summaryrefslogtreecommitdiffstats
path: root/drivers/tty/tty_port.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/tty_port.c')
-rw-r--r--drivers/tty/tty_port.c67
1 files changed, 56 insertions, 11 deletions
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index c3f9d93ba227..1d21a9c1d33e 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -11,11 +11,50 @@
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/slab.h>
-#include <linux/sched.h>
+#include <linux/sched/signal.h>
#include <linux/wait.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/module.h>
+#include <linux/serdev.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)
{
@@ -28,6 +67,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);
@@ -67,8 +107,7 @@ struct device *tty_port_register_device(struct tty_port *port,
struct tty_driver *driver, unsigned index,
struct device *device)
{
- tty_port_link_device(port, driver, index);
- return tty_register_device(driver, index, device);
+ return tty_port_register_device_attr(port, driver, index, device, NULL, NULL);
}
EXPORT_SYMBOL_GPL(tty_port_register_device);
@@ -90,7 +129,15 @@ struct device *tty_port_register_device_attr(struct tty_port *port,
struct device *device, void *drvdata,
const struct attribute_group **attr_grp)
{
+ struct device *dev;
+
tty_port_link_device(port, driver, index);
+
+ dev = serdev_tty_port_register(port, device, driver, index);
+ if (PTR_ERR(dev) != -ENODEV)
+ /* Skip creating cdev if we registered a serdev device */
+ return dev;
+
return tty_register_device_attr(driver, index, device, drvdata,
attr_grp);
}
@@ -142,6 +189,9 @@ static void tty_port_destructor(struct kref *kref)
/* check if last port ref was dropped before tty release */
if (WARN_ON(port->itty))
return;
+
+ serdev_tty_port_unregister(port);
+
if (port->xmit_buf)
free_page((unsigned long)port->xmit_buf);
tty_port_destroy(port);
@@ -273,12 +323,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);
@@ -335,7 +380,7 @@ EXPORT_SYMBOL(tty_port_lower_dtr_rts);
* tty_port_block_til_ready - Waiting logic for tty open
* @port: the tty port being opened
* @tty: the tty device being bound
- * @filp: the file pointer of the opener
+ * @filp: the file pointer of the opener or NULL
*
* Implement the core POSIX/SuS tty behaviour when opening a tty device.
* Handles:
@@ -369,7 +414,7 @@ int tty_port_block_til_ready(struct tty_port *port,
tty_port_set_active(port, 1);
return 0;
}
- if (filp->f_flags & O_NONBLOCK) {
+ if (filp == NULL || (filp->f_flags & O_NONBLOCK)) {
/* Indicate we are open */
if (C_BAUD(tty))
tty_port_raise_dtr_rts(port);