summaryrefslogtreecommitdiff
path: root/drivers/tty/hvc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/hvc')
-rw-r--r--drivers/tty/hvc/hvc_console.c11
-rw-r--r--drivers/tty/hvc/hvc_console.h3
-rw-r--r--drivers/tty/hvc/hvc_iucv.c64
-rw-r--r--drivers/tty/hvc/hvc_xen.c6
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)
tty->driver_data = NULL;
tty_port_put(&hp->port);
printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
- }
+ } else
+ /* We are ready... raise DTR/RTS */
+ if (C_BAUD(tty))
+ if (hp->ops->dtr_rts)
+ hp->ops->dtr_rts(hp, 1);
+
/* Force wakeup of the polling thread */
hvc_kick();
@@ -393,6 +398,10 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
/* We are done with the tty pointer now. */
tty_port_tty_set(&hp->port, NULL);
+ if (C_HUPCL(tty))
+ if (hp->ops->dtr_rts)
+ hp->ops->dtr_rts(hp, 0);
+
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 674d23cb919a..913101980827 100644
--- a/drivers/tty/hvc/hvc_console.h
+++ b/drivers/tty/hvc/hvc_console.h
@@ -75,6 +75,9 @@ struct hv_ops {
/* tiocmget/set implementation */
int (*tiocmget)(struct hvc_struct *hp);
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);
};
/* 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)
}
/**
+ * 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
+ *
+ * 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)
+{
+ struct hvc_iucv_private *priv;
+ struct iucv_path *path;
+
+ /* Raising the DTR/RTS is ignored as IUCV connections can be
+ * established at any times.
+ */
+ if (raise)
+ return;
+
+ priv = hvc_iucv_get_private(hp->vtermno);
+ if (!priv)
+ return;
+
+ /* Lowering the DTR/RTS lines disconnects an established IUCV
+ * connection.
+ */
+ flush_sndbuf_sync(priv);
+
+ spin_lock_bh(&priv->lock);
+ path = priv->path; /* save reference to IUCV path */
+ priv->path = NULL;
+ priv->iucv_state = IUCV_DISCONN;
+ spin_unlock_bh(&priv->lock);
+
+ /* Sever IUCV path outside of priv->lock due to lock ordering of:
+ * priv->lock <--> iucv_table_lock */
+ if (path) {
+ iucv_path_sever(path, NULL);
+ iucv_path_free(path);
+ }
+}
+
+/**
* hvc_iucv_notifier_del() - HVC notifier for closing a TTY for the last time.
* @hp: Pointer to the HVC device (struct hvc_struct)
* @id: Additional data (originally passed to hvc_alloc):
* the index of an struct hvc_iucv_private instance.
*
* This routine notifies the HVC back-end that the last tty device fd has been
- * closed. The function calls hvc_iucv_cleanup() to clean up the struct
- * hvc_iucv_private instance.
+ * closed. The function cleans up tty resources. The clean-up of the IUCV
+ * connection is done in hvc_iucv_dtr_rts() and depends on the HUPCL termios
+ * control setting.
*
* Locking: struct hvc_iucv_private->lock
*/
static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id)
{
struct hvc_iucv_private *priv;
- struct iucv_path *path;
priv = hvc_iucv_get_private(id);
if (!priv)
@@ -679,17 +722,11 @@ static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id)
flush_sndbuf_sync(priv);
spin_lock_bh(&priv->lock);
- path = priv->path; /* save reference to IUCV path */
- priv->path = NULL;
- hvc_iucv_cleanup(priv);
+ destroy_tty_buffer_list(&priv->tty_outqueue);
+ destroy_tty_buffer_list(&priv->tty_inqueue);
+ priv->tty_state = TTY_CLOSED;
+ priv->sndbuf_len = 0;
spin_unlock_bh(&priv->lock);
-
- /* sever IUCV path outside of priv->lock due to lock ordering of:
- * priv->lock <--> iucv_table_lock */
- if (path) {
- iucv_path_sever(path, NULL);
- iucv_path_free(path);
- }
}
/**
@@ -931,6 +968,7 @@ static const struct hv_ops hvc_iucv_ops = {
.notifier_add = hvc_iucv_notifier_add,
.notifier_del = hvc_iucv_notifier_del,
.notifier_hangup = hvc_iucv_notifier_hangup,
+ .dtr_rts = hvc_iucv_dtr_rts,
};
/* 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)
info = vtermno_to_xencons(HVC_COOKIE);
if (!info) {
- info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
+ info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
} else if (info->intf != NULL) {
@@ -257,7 +257,7 @@ static int xen_pv_console_init(void)
info = vtermno_to_xencons(HVC_COOKIE);
if (!info) {
- info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
+ info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
} else if (info->intf != NULL) {
@@ -284,7 +284,7 @@ static int xen_initial_domain_console_init(void)
info = vtermno_to_xencons(HVC_COOKIE);
if (!info) {
- info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
+ info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
}