aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHendrik Brueckner <brueckner@linux.vnet.ibm.com>2013-07-02 11:07:15 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-07-24 18:21:13 -0400
commit74b3b4cd80f43b094b5cb78e73bf612383d80749 (patch)
treefece662e88308182bc1cd1cfc57722ed7f6c9e98
parent33e745a192c272130b02b86d5dea5b577a291ed7 (diff)
tty/hvc_iucv: Disconnect IUCV connection when lowering DTR
Implement the dtr_rts() hvc console callback to improve control when to disconnect the IUCV connection. Previously, the IUCV connection was disconnected during the notifier_del() callback, i.e., when the last file descriptor to the hvc terminal device was closed. Recent changes in login programs caused undesired disconnects during the login phase. To prevent these kind of disconnects, implement the dtr_rts callback to implicitly handle the HUPCL termios control via the hvc_console driver. Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/hvc/hvc_iucv.c64
1 files changed, 51 insertions, 13 deletions
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 */
667static 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 */
670static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id) 714static 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 */