]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
tty_port: Add port client functions
authorRob Herring <robh@kernel.org>
Thu, 2 Feb 2017 19:48:05 +0000 (13:48 -0600)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 3 Feb 2017 09:17:02 +0000 (10:17 +0100)
Introduce a client (upward direction) operations struct for tty_port
clients. Initially supported operations are for receiving data and write
wake-up. This will allow for having clients other than an ldisc.

Convert the calls to the ldisc to use the client ops as the default
operations.

Signed-off-by: Rob Herring <robh@kernel.org>
Reviewed-By: Sebastian Reichel <sre@kernel.org>
Tested-By: Sebastian Reichel <sre@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/tty_buffer.c
drivers/tty/tty_port.c
include/linux/tty.h

index f4dc3e296dd52dfd0270a890edcea817a5153bcd..4e7a4e9dcf4d3740b7c4655c37ec54d9ff93b76c 100644 (file)
@@ -437,7 +437,7 @@ int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p,
 EXPORT_SYMBOL_GPL(tty_ldisc_receive_buf);
 
 static int
-receive_buf(struct tty_ldisc *ld, struct tty_buffer *head, int count)
+receive_buf(struct tty_port *port, struct tty_buffer *head, int count)
 {
        unsigned char *p = char_buf_ptr(head, head->read);
        char          *f = NULL;
@@ -445,7 +445,7 @@ receive_buf(struct tty_ldisc *ld, struct tty_buffer *head, int count)
        if (~head->flags & TTYB_NORMAL)
                f = flag_buf_ptr(head, head->read);
 
-       return tty_ldisc_receive_buf(ld, p, f, count);
+       return port->client_ops->receive_buf(port, p, f, count);
 }
 
 /**
@@ -465,16 +465,6 @@ static void flush_to_ldisc(struct work_struct *work)
 {
        struct tty_port *port = container_of(work, struct tty_port, buf.work);
        struct tty_bufhead *buf = &port->buf;
-       struct tty_struct *tty;
-       struct tty_ldisc *disc;
-
-       tty = READ_ONCE(port->itty);
-       if (tty == NULL)
-               return;
-
-       disc = tty_ldisc_ref(tty);
-       if (disc == NULL)
-               return;
 
        mutex_lock(&buf->lock);
 
@@ -504,7 +494,7 @@ static void flush_to_ldisc(struct work_struct *work)
                        continue;
                }
 
-               count = receive_buf(disc, head, count);
+               count = receive_buf(port, head, count);
                if (!count)
                        break;
                head->read += count;
@@ -512,7 +502,6 @@ static void flush_to_ldisc(struct work_struct *work)
 
        mutex_unlock(&buf->lock);
 
-       tty_ldisc_deref(disc);
 }
 
 /**
index 1d8804843103edb0166c1f4ea7303ff30a8c3360..8d9886b060379356b671e9feeb9626da3d114a86 100644 (file)
 #include <linux/delay.h>
 #include <linux/module.h>
 
+static int tty_port_default_receive_buf(struct tty_port *port,
+                                       const unsigned char *p,
+                                       const unsigned char *f, size_t count)
+{
+       int ret;
+       struct tty_struct *tty;
+       struct tty_ldisc *disc;
+
+       tty = READ_ONCE(port->itty);
+       if (!tty)
+               return 0;
+
+       disc = tty_ldisc_ref(tty);
+       if (!disc)
+               return 0;
+
+       ret = tty_ldisc_receive_buf(disc, p, (char *)f, count);
+
+       tty_ldisc_deref(disc);
+
+       return ret;
+}
+
+static void tty_port_default_wakeup(struct tty_port *port)
+{
+       struct tty_struct *tty = tty_port_tty_get(port);
+
+       if (tty) {
+               tty_wakeup(tty);
+               tty_kref_put(tty);
+       }
+}
+
+static const struct tty_port_client_operations default_client_ops = {
+       .receive_buf = tty_port_default_receive_buf,
+       .write_wakeup = tty_port_default_wakeup,
+};
+
 void tty_port_init(struct tty_port *port)
 {
        memset(port, 0, sizeof(*port));
@@ -28,6 +66,7 @@ void tty_port_init(struct tty_port *port)
        spin_lock_init(&port->lock);
        port->close_delay = (50 * HZ) / 100;
        port->closing_wait = (3000 * HZ) / 100;
+       port->client_ops = &default_client_ops;
        kref_init(&port->kref);
 }
 EXPORT_SYMBOL(tty_port_init);
@@ -272,12 +311,7 @@ EXPORT_SYMBOL_GPL(tty_port_tty_hangup);
  */
 void tty_port_tty_wakeup(struct tty_port *port)
 {
-       struct tty_struct *tty = tty_port_tty_get(port);
-
-       if (tty) {
-               tty_wakeup(tty);
-               tty_kref_put(tty);
-       }
+       port->client_ops->write_wakeup(port);
 }
 EXPORT_SYMBOL_GPL(tty_port_tty_wakeup);
 
index 21c0fabfed60114ffb8b73482da951b9d0008f73..1017e904c0a3f90507183570b0897199b4ace563 100644 (file)
@@ -217,12 +217,18 @@ struct tty_port_operations {
        /* Called on the final put of a port */
        void (*destruct)(struct tty_port *port);
 };
-       
+
+struct tty_port_client_operations {
+       int (*receive_buf)(struct tty_port *port, const unsigned char *, const unsigned char *, size_t);
+       void (*write_wakeup)(struct tty_port *port);
+};
+
 struct tty_port {
        struct tty_bufhead      buf;            /* Locked internally */
        struct tty_struct       *tty;           /* Back pointer */
        struct tty_struct       *itty;          /* internal back ptr */
        const struct tty_port_operations *ops;  /* Port operations */
+       const struct tty_port_client_operations *client_ops; /* Port client operations */
        spinlock_t              lock;           /* Lock protecting tty field */
        int                     blocked_open;   /* Waiting to open */
        int                     count;          /* Usage count */
@@ -241,6 +247,7 @@ struct tty_port {
                                                   based drain is needed else
                                                   set to size of fifo */
        struct kref             kref;           /* Ref counter */
+       void                    *client_data;
 };
 
 /* tty_port::iflags bits -- use atomic bit ops */