diff options
Diffstat (limited to 'drivers/tty/tty_port.c')
| -rw-r--r-- | drivers/tty/tty_port.c | 243 |
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); |
