|
@@ -655,6 +655,49 @@ static void hvc_iucv_notifier_hangup(struct hvc_struct *hp, int id)
|
|
|
spin_unlock_bh(&priv->lock);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * 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)
|
|
@@ -662,15 +705,15 @@ static void hvc_iucv_notifier_hangup(struct hvc_struct *hp, int id)
|
|
|
* 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 */
|