diff options
Diffstat (limited to 'drivers/tty/hvc')
-rw-r--r-- | drivers/tty/hvc/hvc_console.c | 4 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_console.h | 2 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_iucv.c | 6 | ||||
-rw-r--r-- | drivers/tty/hvc/hvcs.c | 91 |
4 files changed, 40 insertions, 63 deletions
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index a683e21df19c..10c10cfdf92a 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -376,7 +376,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) /* We are ready... raise DTR/RTS */ if (C_BAUD(tty)) if (hp->ops->dtr_rts) - hp->ops->dtr_rts(hp, 1); + hp->ops->dtr_rts(hp, true); tty_port_set_initialized(&hp->port, true); } @@ -406,7 +406,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) if (C_HUPCL(tty)) if (hp->ops->dtr_rts) - hp->ops->dtr_rts(hp, 0); + hp->ops->dtr_rts(hp, false); if (hp->ops->notifier_del) hp->ops->notifier_del(hp, hp->data); diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h index 18d005814e4b..9668f821db01 100644 --- a/drivers/tty/hvc/hvc_console.h +++ b/drivers/tty/hvc/hvc_console.h @@ -66,7 +66,7 @@ struct hv_ops { int (*tiocmset)(struct hvc_struct *hp, unsigned int set, unsigned int clear); /* Callbacks to handle tty ports */ - void (*dtr_rts)(struct hvc_struct *hp, int raise); + void (*dtr_rts)(struct hvc_struct *hp, bool active); }; /* Register a vterm and a slot index for use as a console (console_init) */ diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c index 7d49a872de48..543f35ddf523 100644 --- a/drivers/tty/hvc/hvc_iucv.c +++ b/drivers/tty/hvc/hvc_iucv.c @@ -658,13 +658,13 @@ static void hvc_iucv_notifier_hangup(struct hvc_struct *hp, int id) /** * hvc_iucv_dtr_rts() - HVC notifier for handling DTR/RTS * @hp: Pointer the HVC device (struct hvc_struct) - * @raise: Non-zero to raise or zero to lower DTR/RTS lines + * @active: True to raise or false to lower DTR/RTS lines * * This routine notifies the HVC back-end to raise or lower DTR/RTS * lines. Raising DTR/RTS is ignored. Lowering DTR/RTS indicates to * drop the IUCV connection (similar to hang up the modem). */ -static void hvc_iucv_dtr_rts(struct hvc_struct *hp, int raise) +static void hvc_iucv_dtr_rts(struct hvc_struct *hp, bool active) { struct hvc_iucv_private *priv; struct iucv_path *path; @@ -672,7 +672,7 @@ static void hvc_iucv_dtr_rts(struct hvc_struct *hp, int raise) /* Raising the DTR/RTS is ignored as IUCV connections can be * established at any times. */ - if (raise) + if (active) return; priv = hvc_iucv_get_private(hp->vtermno); diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 4ba24963685e..1de1a09bf82d 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -52,6 +52,7 @@ #include <linux/device.h> #include <linux/init.h> +#include <linux/completion.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/kref.h> @@ -285,6 +286,7 @@ struct hvcs_struct { char p_location_code[HVCS_CLC_LENGTH + 1]; /* CLC + Null Term */ struct list_head next; /* list management */ struct vio_dev *vdev; + struct completion *destroyed; }; static LIST_HEAD(hvcs_structs); @@ -432,7 +434,7 @@ static ssize_t hvcs_index_show(struct device *dev, struct device_attribute *attr static DEVICE_ATTR(index, S_IRUGO, hvcs_index_show, NULL); -static struct attribute *hvcs_attrs[] = { +static struct attribute *hvcs_dev_attrs[] = { &dev_attr_partner_vtys.attr, &dev_attr_partner_clcs.attr, &dev_attr_current_vty.attr, @@ -441,9 +443,7 @@ static struct attribute *hvcs_attrs[] = { NULL, }; -static struct attribute_group hvcs_attr_group = { - .attrs = hvcs_attrs, -}; +ATTRIBUTE_GROUPS(hvcs_dev); static ssize_t rescan_show(struct device_driver *ddp, char *buf) { @@ -468,6 +468,13 @@ static ssize_t rescan_store(struct device_driver *ddp, const char * buf, static DRIVER_ATTR_RW(rescan); +static struct attribute *hvcs_attrs[] = { + &driver_attr_rescan.attr, + NULL, +}; + +ATTRIBUTE_GROUPS(hvcs); + static void hvcs_kick(void) { hvcs_kicked = 1; @@ -658,11 +665,13 @@ static void hvcs_destruct_port(struct tty_port *p) { struct hvcs_struct *hvcsd = container_of(p, struct hvcs_struct, port); struct vio_dev *vdev; + struct completion *comp; unsigned long flags; spin_lock(&hvcs_structs_lock); spin_lock_irqsave(&hvcsd->lock, flags); + comp = hvcsd->destroyed; /* the list_del poisons the pointers */ list_del(&(hvcsd->next)); @@ -682,15 +691,16 @@ static void hvcs_destruct_port(struct tty_port *p) hvcsd->p_unit_address = 0; hvcsd->p_partition_ID = 0; + hvcsd->destroyed = NULL; hvcs_return_index(hvcsd->index); memset(&hvcsd->p_location_code[0], 0x00, HVCS_CLC_LENGTH + 1); spin_unlock_irqrestore(&hvcsd->lock, flags); spin_unlock(&hvcs_structs_lock); - sysfs_remove_group(&vdev->dev.kobj, &hvcs_attr_group); - kfree(hvcsd); + if (comp) + complete(comp); } static const struct tty_port_operations hvcs_port_ops = { @@ -721,7 +731,6 @@ static int hvcs_probe( { struct hvcs_struct *hvcsd; int index, rc; - int retval; if (!dev || !id) { printk(KERN_ERR "HVCS: probed with invalid parameter.\n"); @@ -778,13 +787,6 @@ static int hvcs_probe( list_add_tail(&(hvcsd->next), &hvcs_structs); spin_unlock(&hvcs_structs_lock); - retval = sysfs_create_group(&dev->dev.kobj, &hvcs_attr_group); - if (retval) { - printk(KERN_ERR "HVCS: Can't create sysfs attrs for vty-server@%X\n", - hvcsd->vdev->unit_address); - return retval; - } - printk(KERN_INFO "HVCS: vty-server@%X added to the vio bus.\n", dev->unit_address); /* @@ -797,6 +799,7 @@ static int hvcs_probe( static void hvcs_remove(struct vio_dev *dev) { struct hvcs_struct *hvcsd = dev_get_drvdata(&dev->dev); + DECLARE_COMPLETION_ONSTACK(comp); unsigned long flags; struct tty_struct *tty; @@ -804,24 +807,22 @@ static void hvcs_remove(struct vio_dev *dev) spin_lock_irqsave(&hvcsd->lock, flags); - tty = hvcsd->port.tty; + hvcsd->destroyed = ∁ + tty = tty_port_tty_get(&hvcsd->port); spin_unlock_irqrestore(&hvcsd->lock, flags); /* - * Let the last holder of this object cause it to be removed, which - * would probably be tty_hangup below. - */ - tty_port_put(&hvcsd->port); - - /* - * The hangup is a scheduled function which will auto chain call - * hvcs_hangup. The tty should always be valid at this time unless a + * The tty should always be valid at this time unless a * simultaneous tty close already cleaned up the hvcs_struct. */ - if (tty) - tty_hangup(tty); + if (tty) { + tty_vhangup(tty); + tty_kref_put(tty); + } + tty_port_put(&hvcsd->port); + wait_for_completion(&comp); printk(KERN_INFO "HVCS: vty-server@%X removed from the" " vio bus.\n", dev->unit_address); }; @@ -831,6 +832,10 @@ static struct vio_driver hvcs_vio_driver = { .probe = hvcs_probe, .remove = hvcs_remove, .name = hvcs_driver_name, + .driver = { + .groups = hvcs_groups, + .dev_groups = hvcs_dev_groups, + }, }; /* Only called from hvcs_get_pi please */ @@ -1171,7 +1176,10 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) hvcsd = tty->driver_data; spin_lock_irqsave(&hvcsd->lock, flags); - if (--hvcsd->port.count == 0) { + if (hvcsd->port.count == 0) { + spin_unlock_irqrestore(&hvcsd->lock, flags); + return; + } else if (--hvcsd->port.count == 0) { vio_disable_interrupts(hvcsd->vdev); @@ -1215,12 +1223,9 @@ static void hvcs_hangup(struct tty_struct * tty) { struct hvcs_struct *hvcsd = tty->driver_data; unsigned long flags; - int temp_open_count; int irq; spin_lock_irqsave(&hvcsd->lock, flags); - /* Preserve this so that we know how many kref refs to put */ - temp_open_count = hvcsd->port.count; /* * Don't kref put inside the spinlock because the destruction @@ -1230,11 +1235,7 @@ static void hvcs_hangup(struct tty_struct * tty) vio_disable_interrupts(hvcsd->vdev); hvcsd->todo_mask = 0; - - /* I don't think the tty needs the hvcs_struct pointer after a hangup */ - tty->driver_data = NULL; hvcsd->port.tty = NULL; - hvcsd->port.count = 0; /* This will drop any buffered data on the floor which is OK in a hangup @@ -1247,21 +1248,6 @@ static void hvcs_hangup(struct tty_struct * tty) spin_unlock_irqrestore(&hvcsd->lock, flags); free_irq(irq, hvcsd); - - /* - * We need to kref_put() for every open_count we have since the - * tty_hangup() function doesn't invoke a close per open connection on a - * non-console device. - */ - while(temp_open_count) { - --temp_open_count; - /* - * The final put will trigger destruction of the hvcs_struct. - * NOTE: If this hangup was signaled from user space then the - * final put will never happen. - */ - tty_port_put(&hvcsd->port); - } } /* @@ -1525,13 +1511,6 @@ static int __init hvcs_module_init(void) pr_info("HVCS: Driver registered.\n"); - /* This needs to be done AFTER the vio_register_driver() call or else - * the kobjects won't be initialized properly. - */ - rc = driver_create_file(&(hvcs_vio_driver.driver), &driver_attr_rescan); - if (rc) - pr_warn("HVCS: Failed to create rescan file (err %d)\n", rc); - return 0; } @@ -1556,8 +1535,6 @@ static void __exit hvcs_module_exit(void) hvcs_pi_buff = NULL; spin_unlock(&hvcs_pi_lock); - driver_remove_file(&hvcs_vio_driver.driver, &driver_attr_rescan); - tty_unregister_driver(hvcs_tty_driver); hvcs_free_index_list(); |