summaryrefslogtreecommitdiff
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.c243
1 files changed, 101 insertions, 142 deletions
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index a788a6bf487d..fe67c5cb0a3f 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -20,57 +20,51 @@
#include <linux/serdev.h>
#include "tty.h"
-static int tty_port_default_receive_buf(struct tty_port *port,
- const unsigned char *p,
- const unsigned char *f, size_t count)
+static size_t tty_port_default_receive_buf(struct tty_port *port, const u8 *p,
+ const u8 *f, size_t count)
{
- int ret;
struct tty_struct *tty;
- struct tty_ldisc *disc;
+ struct tty_ldisc *ld;
tty = READ_ONCE(port->itty);
if (!tty)
return 0;
- disc = tty_ldisc_ref(tty);
- if (!disc)
+ ld = tty_ldisc_ref(tty);
+ if (!ld)
return 0;
- ret = tty_ldisc_receive_buf(disc, p, (char *)f, count);
+ count = tty_ldisc_receive_buf(ld, p, f, count);
- tty_ldisc_deref(disc);
+ tty_ldisc_deref(ld);
- return ret;
+ return count;
}
-static void tty_port_default_lookahead_buf(struct tty_port *port, const unsigned char *p,
- const unsigned char *f, unsigned int count)
+static void tty_port_default_lookahead_buf(struct tty_port *port, const u8 *p,
+ const u8 *f, size_t count)
{
struct tty_struct *tty;
- struct tty_ldisc *disc;
+ struct tty_ldisc *ld;
tty = READ_ONCE(port->itty);
if (!tty)
return;
- disc = tty_ldisc_ref(tty);
- if (!disc)
+ ld = tty_ldisc_ref(tty);
+ if (!ld)
return;
- if (disc->ops->lookahead_buf)
- disc->ops->lookahead_buf(disc->tty, p, f, count);
+ if (ld->ops->lookahead_buf)
+ ld->ops->lookahead_buf(ld->tty, p, f, count);
- tty_ldisc_deref(disc);
+ tty_ldisc_deref(ld);
}
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);
- }
+ scoped_guard(tty_port_tty, port)
+ tty_wakeup(scoped_tty());
}
const struct tty_port_client_operations tty_port_default_client_ops = {
@@ -81,7 +75,7 @@ const struct tty_port_client_operations tty_port_default_client_ops = {
EXPORT_SYMBOL_GPL(tty_port_default_client_ops);
/**
- * tty_port_init -- initialize tty_port
+ * tty_port_init - initialize tty_port
* @port: tty_port to initialize
*
* Initializes the state of struct tty_port. When a port was initialized using
@@ -173,7 +167,8 @@ EXPORT_SYMBOL_GPL(tty_port_register_device_attr);
* @port: tty_port of the device
* @driver: tty_driver for this device
* @index: index of the tty
- * @device: parent if exists, otherwise NULL
+ * @host: serial port hardware device
+ * @parent: parent if exists, otherwise NULL
* @drvdata: driver data for the device
* @attr_grp: attribute group for the device
*
@@ -182,44 +177,25 @@ EXPORT_SYMBOL_GPL(tty_port_register_device_attr);
*/
struct device *tty_port_register_device_attr_serdev(struct tty_port *port,
struct tty_driver *driver, unsigned index,
- struct device *device, void *drvdata,
+ struct device *host, struct device *parent, 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);
+ dev = serdev_tty_port_register(port, host, parent, 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,
+ return tty_register_device_attr(driver, index, parent, drvdata,
attr_grp);
}
EXPORT_SYMBOL_GPL(tty_port_register_device_attr_serdev);
/**
- * tty_port_register_device_serdev - register tty or serdev device
- * @port: tty_port of the device
- * @driver: tty_driver for this device
- * @index: index of the tty
- * @device: parent if exists, otherwise NULL
- *
- * Register a serdev or tty device depending on if the parent device has any
- * defined serdev clients or not.
- */
-struct device *tty_port_register_device_serdev(struct tty_port *port,
- struct tty_driver *driver, unsigned index,
- struct device *device)
-{
- return tty_port_register_device_attr_serdev(port, driver, index,
- device, NULL, NULL);
-}
-EXPORT_SYMBOL_GPL(tty_port_register_device_serdev);
-
-/**
* tty_port_unregister_device - deregister a tty or serdev device
* @port: tty_port of the device
* @driver: tty_driver for this device
@@ -245,31 +221,32 @@ EXPORT_SYMBOL_GPL(tty_port_unregister_device);
int tty_port_alloc_xmit_buf(struct tty_port *port)
{
/* We may sleep in get_zeroed_page() */
- mutex_lock(&port->buf_mutex);
- if (port->xmit_buf == NULL) {
- port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
- if (port->xmit_buf)
- kfifo_init(&port->xmit_fifo, port->xmit_buf, PAGE_SIZE);
- }
- mutex_unlock(&port->buf_mutex);
+ guard(mutex)(&port->buf_mutex);
+
+ if (port->xmit_buf)
+ return 0;
+
+ port->xmit_buf = (u8 *)get_zeroed_page(GFP_KERNEL);
if (port->xmit_buf == NULL)
return -ENOMEM;
+
+ kfifo_init(&port->xmit_fifo, port->xmit_buf, PAGE_SIZE);
+
return 0;
}
EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
void tty_port_free_xmit_buf(struct tty_port *port)
{
- mutex_lock(&port->buf_mutex);
+ guard(mutex)(&port->buf_mutex);
free_page((unsigned long)port->xmit_buf);
port->xmit_buf = NULL;
INIT_KFIFO(port->xmit_fifo);
- mutex_unlock(&port->buf_mutex);
}
EXPORT_SYMBOL(tty_port_free_xmit_buf);
/**
- * tty_port_destroy -- destroy inited port
+ * tty_port_destroy - destroy inited port
* @port: tty port to be destroyed
*
* When a port was initialized using tty_port_init(), one has to destroy the
@@ -299,7 +276,7 @@ static void tty_port_destructor(struct kref *kref)
}
/**
- * tty_port_put -- drop a reference to tty_port
+ * tty_port_put - drop a reference to tty_port
* @port: port to drop a reference of (can be NULL)
*
* The final put will destroy and free up the @port using
@@ -321,13 +298,8 @@ EXPORT_SYMBOL(tty_port_put);
*/
struct tty_struct *tty_port_tty_get(struct tty_port *port)
{
- unsigned long flags;
- struct tty_struct *tty;
-
- spin_lock_irqsave(&port->lock, flags);
- tty = tty_kref_get(port->tty);
- spin_unlock_irqrestore(&port->lock, flags);
- return tty;
+ guard(spinlock_irqsave)(&port->lock);
+ return tty_kref_get(port->tty);
}
EXPORT_SYMBOL(tty_port_tty_get);
@@ -341,12 +313,9 @@ EXPORT_SYMBOL(tty_port_tty_get);
*/
void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
{
- unsigned long flags;
-
- spin_lock_irqsave(&port->lock, flags);
+ guard(spinlock_irqsave)(&port->lock);
tty_kref_put(port->tty);
port->tty = tty_kref_get(tty);
- spin_unlock_irqrestore(&port->lock, flags);
}
EXPORT_SYMBOL(tty_port_tty_set);
@@ -362,24 +331,24 @@ EXPORT_SYMBOL(tty_port_tty_set);
*/
static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty)
{
- mutex_lock(&port->mutex);
+ guard(mutex)(&port->mutex);
+
if (port->console)
- goto out;
+ return;
- if (tty_port_initialized(port)) {
- tty_port_set_initialized(port, false);
- /*
- * Drop DTR/RTS if HUPCL is set. This causes any attached
- * modem to hang up the line.
- */
- if (tty && C_HUPCL(tty))
- tty_port_lower_dtr_rts(port);
+ if (!tty_port_initialized(port))
+ return;
- if (port->ops->shutdown)
- port->ops->shutdown(port);
- }
-out:
- mutex_unlock(&port->mutex);
+ tty_port_set_initialized(port, false);
+ /*
+ * Drop DTR/RTS if HUPCL is set. This causes any attached
+ * modem to hang up the line.
+ */
+ if (tty && C_HUPCL(tty))
+ tty_port_lower_dtr_rts(port);
+
+ if (port->ops->shutdown)
+ port->ops->shutdown(port);
}
/**
@@ -394,15 +363,15 @@ out:
void tty_port_hangup(struct tty_port *port)
{
struct tty_struct *tty;
- unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
- port->count = 0;
- tty = port->tty;
- if (tty)
- set_bit(TTY_IO_ERROR, &tty->flags);
- port->tty = NULL;
- spin_unlock_irqrestore(&port->lock, flags);
+ scoped_guard(spinlock_irqsave, &port->lock) {
+ port->count = 0;
+ tty = port->tty;
+ if (tty)
+ set_bit(TTY_IO_ERROR, &tty->flags);
+ port->tty = NULL;
+ }
+
tty_port_set_active(port, false);
tty_port_shutdown(port, tty);
tty_kref_put(tty);
@@ -411,20 +380,20 @@ void tty_port_hangup(struct tty_port *port)
}
EXPORT_SYMBOL(tty_port_hangup);
-/**
- * tty_port_tty_hangup - helper to hang up a tty
- * @port: tty port
- * @check_clocal: hang only ttys with %CLOCAL unset?
- */
-void tty_port_tty_hangup(struct tty_port *port, bool check_clocal)
+void __tty_port_tty_hangup(struct tty_port *port, bool check_clocal, bool async)
{
- struct tty_struct *tty = tty_port_tty_get(port);
+ scoped_guard(tty_port_tty, port) {
+ struct tty_struct *tty = scoped_tty();
- if (tty && (!check_clocal || !C_CLOCAL(tty)))
- tty_hangup(tty);
- tty_kref_put(tty);
+ if (!check_clocal || !C_CLOCAL(tty)) {
+ if (async)
+ tty_hangup(tty);
+ else
+ tty_vhangup(tty);
+ }
+ }
}
-EXPORT_SYMBOL_GPL(tty_port_tty_hangup);
+EXPORT_SYMBOL_GPL(__tty_port_tty_hangup);
/**
* tty_port_tty_wakeup - helper to wake up a tty
@@ -511,7 +480,6 @@ int tty_port_block_til_ready(struct tty_port *port,
struct tty_struct *tty, struct file *filp)
{
int do_clocal = 0, retval;
- unsigned long flags;
DEFINE_WAIT(wait);
/* if non-blocking mode is set we can pass directly to open unless
@@ -540,10 +508,10 @@ int tty_port_block_til_ready(struct tty_port *port,
retval = 0;
/* The port lock protects the port counts */
- spin_lock_irqsave(&port->lock, flags);
- port->count--;
- port->blocked_open++;
- spin_unlock_irqrestore(&port->lock, flags);
+ scoped_guard(spinlock_irqsave, &port->lock) {
+ port->count--;
+ port->blocked_open++;
+ }
while (1) {
/* Indicate we are open */
@@ -582,11 +550,11 @@ int tty_port_block_til_ready(struct tty_port *port,
/* Update counts. A parallel hangup will have set count to zero and
* we must not mess that up further.
*/
- spin_lock_irqsave(&port->lock, flags);
- if (!tty_hung_up_p(filp))
- port->count++;
- port->blocked_open--;
- spin_unlock_irqrestore(&port->lock, flags);
+ scoped_guard(spinlock_irqsave, &port->lock) {
+ if (!tty_hung_up_p(filp))
+ port->count++;
+ port->blocked_open--;
+ }
if (retval == 0)
tty_port_set_active(port, true);
return retval;
@@ -625,28 +593,24 @@ static void tty_port_drain_delay(struct tty_port *port, struct tty_struct *tty)
int tty_port_close_start(struct tty_port *port,
struct tty_struct *tty, struct file *filp)
{
- unsigned long flags;
-
if (tty_hung_up_p(filp))
return 0;
- spin_lock_irqsave(&port->lock, flags);
- if (tty->count == 1 && port->count != 1) {
- tty_warn(tty, "%s: tty->count = 1 port count = %d\n", __func__,
- port->count);
- port->count = 1;
- }
- if (--port->count < 0) {
- tty_warn(tty, "%s: bad port count (%d)\n", __func__,
- port->count);
- port->count = 0;
- }
+ scoped_guard(spinlock_irqsave, &port->lock) {
+ if (tty->count == 1 && port->count != 1) {
+ tty_warn(tty, "%s: tty->count = 1 port count = %d\n", __func__,
+ port->count);
+ port->count = 1;
+ }
+ if (--port->count < 0) {
+ tty_warn(tty, "%s: bad port count (%d)\n", __func__,
+ port->count);
+ port->count = 0;
+ }
- if (port->count) {
- spin_unlock_irqrestore(&port->lock, flags);
- return 0;
+ if (port->count)
+ return 0;
}
- spin_unlock_irqrestore(&port->lock, flags);
tty->closing = 1;
@@ -765,9 +729,8 @@ EXPORT_SYMBOL_GPL(tty_port_install);
int tty_port_open(struct tty_port *port, struct tty_struct *tty,
struct file *filp)
{
- spin_lock_irq(&port->lock);
- ++port->count;
- spin_unlock_irq(&port->lock);
+ scoped_guard(spinlock_irq, &port->lock)
+ ++port->count;
tty_port_tty_set(port, tty);
/*
@@ -776,21 +739,17 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty,
* port mutex.
*/
- mutex_lock(&port->mutex);
-
- if (!tty_port_initialized(port)) {
+ scoped_guard(mutex, &port->mutex) {
+ if (tty_port_initialized(port))
+ break;
clear_bit(TTY_IO_ERROR, &tty->flags);
if (port->ops->activate) {
int retval = port->ops->activate(port, tty);
-
- if (retval) {
- mutex_unlock(&port->mutex);
+ if (retval)
return retval;
- }
}
tty_port_set_initialized(port, true);
}
- mutex_unlock(&port->mutex);
return tty_port_block_til_ready(port, tty, filp);
}
EXPORT_SYMBOL(tty_port_open);