diff options
Diffstat (limited to 'drivers/tty/hvc')
-rw-r--r-- | drivers/tty/hvc/hvc_console.c | 11 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_console.h | 3 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_iucv.c | 64 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_xen.c | 6 |
4 files changed, 67 insertions, 17 deletions
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index eb255e807c06..9eba119bcdd3 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c | |||
@@ -361,7 +361,12 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) | |||
361 | tty->driver_data = NULL; | 361 | tty->driver_data = NULL; |
362 | tty_port_put(&hp->port); | 362 | tty_port_put(&hp->port); |
363 | printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc); | 363 | printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc); |
364 | } | 364 | } else |
365 | /* We are ready... raise DTR/RTS */ | ||
366 | if (C_BAUD(tty)) | ||
367 | if (hp->ops->dtr_rts) | ||
368 | hp->ops->dtr_rts(hp, 1); | ||
369 | |||
365 | /* Force wakeup of the polling thread */ | 370 | /* Force wakeup of the polling thread */ |
366 | hvc_kick(); | 371 | hvc_kick(); |
367 | 372 | ||
@@ -393,6 +398,10 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) | |||
393 | /* We are done with the tty pointer now. */ | 398 | /* We are done with the tty pointer now. */ |
394 | tty_port_tty_set(&hp->port, NULL); | 399 | tty_port_tty_set(&hp->port, NULL); |
395 | 400 | ||
401 | if (C_HUPCL(tty)) | ||
402 | if (hp->ops->dtr_rts) | ||
403 | hp->ops->dtr_rts(hp, 0); | ||
404 | |||
396 | if (hp->ops->notifier_del) | 405 | if (hp->ops->notifier_del) |
397 | hp->ops->notifier_del(hp, hp->data); | 406 | hp->ops->notifier_del(hp, hp->data); |
398 | 407 | ||
diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h index 674d23cb919a..913101980827 100644 --- a/drivers/tty/hvc/hvc_console.h +++ b/drivers/tty/hvc/hvc_console.h | |||
@@ -75,6 +75,9 @@ struct hv_ops { | |||
75 | /* tiocmget/set implementation */ | 75 | /* tiocmget/set implementation */ |
76 | int (*tiocmget)(struct hvc_struct *hp); | 76 | int (*tiocmget)(struct hvc_struct *hp); |
77 | int (*tiocmset)(struct hvc_struct *hp, unsigned int set, unsigned int clear); | 77 | int (*tiocmset)(struct hvc_struct *hp, unsigned int set, unsigned int clear); |
78 | |||
79 | /* Callbacks to handle tty ports */ | ||
80 | void (*dtr_rts)(struct hvc_struct *hp, int raise); | ||
78 | }; | 81 | }; |
79 | 82 | ||
80 | /* Register a vterm and a slot index for use as a console (console_init) */ | 83 | /* 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 9d47f50c2755..fd17a9b804b8 100644 --- a/drivers/tty/hvc/hvc_iucv.c +++ b/drivers/tty/hvc/hvc_iucv.c | |||
@@ -656,21 +656,64 @@ static void hvc_iucv_notifier_hangup(struct hvc_struct *hp, int id) | |||
656 | } | 656 | } |
657 | 657 | ||
658 | /** | 658 | /** |
659 | * hvc_iucv_dtr_rts() - HVC notifier for handling DTR/RTS | ||
660 | * @hp: Pointer the HVC device (struct hvc_struct) | ||
661 | * @raise: Non-zero to raise or zero to lower DTR/RTS lines | ||
662 | * | ||
663 | * This routine notifies the HVC back-end to raise or lower DTR/RTS | ||
664 | * lines. Raising DTR/RTS is ignored. Lowering DTR/RTS indicates to | ||
665 | * drop the IUCV connection (similar to hang up the modem). | ||
666 | */ | ||
667 | static void hvc_iucv_dtr_rts(struct hvc_struct *hp, int raise) | ||
668 | { | ||
669 | struct hvc_iucv_private *priv; | ||
670 | struct iucv_path *path; | ||
671 | |||
672 | /* Raising the DTR/RTS is ignored as IUCV connections can be | ||
673 | * established at any times. | ||
674 | */ | ||
675 | if (raise) | ||
676 | return; | ||
677 | |||
678 | priv = hvc_iucv_get_private(hp->vtermno); | ||
679 | if (!priv) | ||
680 | return; | ||
681 | |||
682 | /* Lowering the DTR/RTS lines disconnects an established IUCV | ||
683 | * connection. | ||
684 | */ | ||
685 | flush_sndbuf_sync(priv); | ||
686 | |||
687 | spin_lock_bh(&priv->lock); | ||
688 | path = priv->path; /* save reference to IUCV path */ | ||
689 | priv->path = NULL; | ||
690 | priv->iucv_state = IUCV_DISCONN; | ||
691 | spin_unlock_bh(&priv->lock); | ||
692 | |||
693 | /* Sever IUCV path outside of priv->lock due to lock ordering of: | ||
694 | * priv->lock <--> iucv_table_lock */ | ||
695 | if (path) { | ||
696 | iucv_path_sever(path, NULL); | ||
697 | iucv_path_free(path); | ||
698 | } | ||
699 | } | ||
700 | |||
701 | /** | ||
659 | * hvc_iucv_notifier_del() - HVC notifier for closing a TTY for the last time. | 702 | * hvc_iucv_notifier_del() - HVC notifier for closing a TTY for the last time. |
660 | * @hp: Pointer to the HVC device (struct hvc_struct) | 703 | * @hp: Pointer to the HVC device (struct hvc_struct) |
661 | * @id: Additional data (originally passed to hvc_alloc): | 704 | * @id: Additional data (originally passed to hvc_alloc): |
662 | * the index of an struct hvc_iucv_private instance. | 705 | * the index of an struct hvc_iucv_private instance. |
663 | * | 706 | * |
664 | * This routine notifies the HVC back-end that the last tty device fd has been | 707 | * This routine notifies the HVC back-end that the last tty device fd has been |
665 | * closed. The function calls hvc_iucv_cleanup() to clean up the struct | 708 | * closed. The function cleans up tty resources. The clean-up of the IUCV |
666 | * hvc_iucv_private instance. | 709 | * connection is done in hvc_iucv_dtr_rts() and depends on the HUPCL termios |
710 | * control setting. | ||
667 | * | 711 | * |
668 | * Locking: struct hvc_iucv_private->lock | 712 | * Locking: struct hvc_iucv_private->lock |
669 | */ | 713 | */ |
670 | static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id) | 714 | static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id) |
671 | { | 715 | { |
672 | struct hvc_iucv_private *priv; | 716 | struct hvc_iucv_private *priv; |
673 | struct iucv_path *path; | ||
674 | 717 | ||
675 | priv = hvc_iucv_get_private(id); | 718 | priv = hvc_iucv_get_private(id); |
676 | if (!priv) | 719 | if (!priv) |
@@ -679,17 +722,11 @@ static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id) | |||
679 | flush_sndbuf_sync(priv); | 722 | flush_sndbuf_sync(priv); |
680 | 723 | ||
681 | spin_lock_bh(&priv->lock); | 724 | spin_lock_bh(&priv->lock); |
682 | path = priv->path; /* save reference to IUCV path */ | 725 | destroy_tty_buffer_list(&priv->tty_outqueue); |
683 | priv->path = NULL; | 726 | destroy_tty_buffer_list(&priv->tty_inqueue); |
684 | hvc_iucv_cleanup(priv); | 727 | priv->tty_state = TTY_CLOSED; |
728 | priv->sndbuf_len = 0; | ||
685 | spin_unlock_bh(&priv->lock); | 729 | spin_unlock_bh(&priv->lock); |
686 | |||
687 | /* sever IUCV path outside of priv->lock due to lock ordering of: | ||
688 | * priv->lock <--> iucv_table_lock */ | ||
689 | if (path) { | ||
690 | iucv_path_sever(path, NULL); | ||
691 | iucv_path_free(path); | ||
692 | } | ||
693 | } | 730 | } |
694 | 731 | ||
695 | /** | 732 | /** |
@@ -931,6 +968,7 @@ static const struct hv_ops hvc_iucv_ops = { | |||
931 | .notifier_add = hvc_iucv_notifier_add, | 968 | .notifier_add = hvc_iucv_notifier_add, |
932 | .notifier_del = hvc_iucv_notifier_del, | 969 | .notifier_del = hvc_iucv_notifier_del, |
933 | .notifier_hangup = hvc_iucv_notifier_hangup, | 970 | .notifier_hangup = hvc_iucv_notifier_hangup, |
971 | .dtr_rts = hvc_iucv_dtr_rts, | ||
934 | }; | 972 | }; |
935 | 973 | ||
936 | /* Suspend / resume device operations */ | 974 | /* Suspend / resume device operations */ |
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index 682210d778bd..e61c36cbb866 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c | |||
@@ -208,7 +208,7 @@ static int xen_hvm_console_init(void) | |||
208 | 208 | ||
209 | info = vtermno_to_xencons(HVC_COOKIE); | 209 | info = vtermno_to_xencons(HVC_COOKIE); |
210 | if (!info) { | 210 | if (!info) { |
211 | info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO); | 211 | info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL); |
212 | if (!info) | 212 | if (!info) |
213 | return -ENOMEM; | 213 | return -ENOMEM; |
214 | } else if (info->intf != NULL) { | 214 | } else if (info->intf != NULL) { |
@@ -257,7 +257,7 @@ static int xen_pv_console_init(void) | |||
257 | 257 | ||
258 | info = vtermno_to_xencons(HVC_COOKIE); | 258 | info = vtermno_to_xencons(HVC_COOKIE); |
259 | if (!info) { | 259 | if (!info) { |
260 | info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO); | 260 | info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL); |
261 | if (!info) | 261 | if (!info) |
262 | return -ENOMEM; | 262 | return -ENOMEM; |
263 | } else if (info->intf != NULL) { | 263 | } else if (info->intf != NULL) { |
@@ -284,7 +284,7 @@ static int xen_initial_domain_console_init(void) | |||
284 | 284 | ||
285 | info = vtermno_to_xencons(HVC_COOKIE); | 285 | info = vtermno_to_xencons(HVC_COOKIE); |
286 | if (!info) { | 286 | if (!info) { |
287 | info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO); | 287 | info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL); |
288 | if (!info) | 288 | if (!info) |
289 | return -ENOMEM; | 289 | return -ENOMEM; |
290 | } | 290 | } |