diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-22 19:59:04 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-22 19:59:04 -0700 |
commit | 73ecf3a6e3f0206bf56a0fefe3b3eda042fb7034 (patch) | |
tree | 866f0ebb2b148479e93b5ac955097b1cc94ceb4e /drivers/char/tty_io.c | |
parent | b9da0571050c09863e59f94d0b8594a290d61b88 (diff) | |
parent | cd3ecad19aea8debae9a48b53de2ec7a571f24e9 (diff) | |
download | op-kernel-dev-73ecf3a6e3f0206bf56a0fefe3b3eda042fb7034.zip op-kernel-dev-73ecf3a6e3f0206bf56a0fefe3b3eda042fb7034.tar.gz |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6: (49 commits)
serial8250: ratelimit "too much work" error
serial: bfin_sport_uart: speed up sport RX sample rate to be 3% faster
serial: abstraction for 8250 legacy ports
serial/imx: check that the buffer is non-empty before sending it out
serial: mfd: add more baud rates support
jsm: Remove the uart port on errors
Alchemy: Add UART PM methods.
8250: allow platforms to override PM hook.
altera_uart: Don't use plain integer as NULL pointer
altera_uart: Fix missing prototype for registering an early console
altera_uart: Fixup type usage of port flags
altera_uart: Make it possible to use Altera UART and 8250 ports together
altera_uart: Add support for different address strides
altera_uart: Add support for getting mapbase and IRQ from resources
altera_uart: Add support for polling mode (IRQ-less)
serial: Factor out uart_poll_timeout() from 8250 driver
serial: mark the 8250 driver as maintained
serial: 8250: Don't delay after transmitter is ready.
tty: MAINTAINERS: add drivers/serial/jsm/ as maintained driver
vcs: invoke the vt update callback when /dev/vcs* is written to
...
Diffstat (limited to 'drivers/char/tty_io.c')
-rw-r--r-- | drivers/char/tty_io.c | 77 |
1 files changed, 71 insertions, 6 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 613c852..c05c5af 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -96,6 +96,7 @@ #include <linux/bitops.h> #include <linux/delay.h> #include <linux/seq_file.h> +#include <linux/serial.h> #include <linux/uaccess.h> #include <asm/system.h> @@ -183,6 +184,8 @@ struct tty_struct *alloc_tty_struct(void) void free_tty_struct(struct tty_struct *tty) { + if (tty->dev) + put_device(tty->dev); kfree(tty->write_buf); tty_buffer_free_all(tty); kfree(tty); @@ -194,12 +197,13 @@ static inline struct tty_struct *file_tty(struct file *file) } /* Associate a new file with the tty structure */ -void tty_add_file(struct tty_struct *tty, struct file *file) +int tty_add_file(struct tty_struct *tty, struct file *file) { struct tty_file_private *priv; - /* XXX: must implement proper error handling in callers */ - priv = kmalloc(sizeof(*priv), GFP_KERNEL|__GFP_NOFAIL); + priv = kmalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; priv->tty = tty; priv->file = file; @@ -208,6 +212,8 @@ void tty_add_file(struct tty_struct *tty, struct file *file) spin_lock(&tty_files_lock); list_add(&priv->list, &tty->tty_files); spin_unlock(&tty_files_lock); + + return 0; } /* Delete file from its tty */ @@ -1875,7 +1881,11 @@ got_driver: return PTR_ERR(tty); } - tty_add_file(tty, filp); + retval = tty_add_file(tty, filp); + if (retval) { + tty_unlock(); + return retval; + } check_tty_count(tty, "tty_open"); if (tty->driver->type == TTY_DRIVER_TYPE_PTY && @@ -2502,6 +2512,20 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int return tty->ops->tiocmset(tty, file, set, clear); } +static int tty_tiocgicount(struct tty_struct *tty, void __user *arg) +{ + int retval = -EINVAL; + struct serial_icounter_struct icount; + memset(&icount, 0, sizeof(icount)); + if (tty->ops->get_icount) + retval = tty->ops->get_icount(tty, &icount); + if (retval != 0) + return retval; + if (copy_to_user(arg, &icount, sizeof(icount))) + return -EFAULT; + return 0; +} + struct tty_struct *tty_pair_get_tty(struct tty_struct *tty) { if (tty->driver->type == TTY_DRIVER_TYPE_PTY && @@ -2622,6 +2646,12 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case TIOCMBIC: case TIOCMBIS: return tty_tiocmset(tty, file, cmd, p); + case TIOCGICOUNT: + retval = tty_tiocgicount(tty, p); + /* For the moment allow fall through to the old method */ + if (retval != -EINVAL) + return retval; + break; case TCFLSH: switch (arg) { case TCIFLUSH: @@ -2783,6 +2813,20 @@ void do_SAK(struct tty_struct *tty) EXPORT_SYMBOL(do_SAK); +static int dev_match_devt(struct device *dev, void *data) +{ + dev_t *devt = data; + return dev->devt == *devt; +} + +/* Must put_device() after it's unused! */ +static struct device *tty_get_device(struct tty_struct *tty) +{ + dev_t devt = tty_devnum(tty); + return class_find_device(tty_class, NULL, &devt, dev_match_devt); +} + + /** * initialize_tty_struct * @tty: tty to initialize @@ -2823,6 +2867,7 @@ void initialize_tty_struct(struct tty_struct *tty, tty->ops = driver->ops; tty->index = idx; tty_line_name(driver, idx, tty->name); + tty->dev = tty_get_device(tty); } /** @@ -2980,6 +3025,7 @@ int tty_register_driver(struct tty_driver *driver) int i; dev_t dev; void **p = NULL; + struct device *d; if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) { p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL); @@ -3027,12 +3073,31 @@ int tty_register_driver(struct tty_driver *driver) mutex_unlock(&tty_mutex); if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) { - for (i = 0; i < driver->num; i++) - tty_register_device(driver, i, NULL); + for (i = 0; i < driver->num; i++) { + d = tty_register_device(driver, i, NULL); + if (IS_ERR(d)) { + error = PTR_ERR(d); + goto err; + } + } } proc_tty_register_driver(driver); driver->flags |= TTY_DRIVER_INSTALLED; return 0; + +err: + for (i--; i >= 0; i--) + tty_unregister_device(driver, i); + + mutex_lock(&tty_mutex); + list_del(&driver->tty_drivers); + mutex_unlock(&tty_mutex); + + unregister_chrdev_region(dev, driver->num); + driver->ttys = NULL; + driver->termios = NULL; + kfree(p); + return error; } EXPORT_SYMBOL(tty_register_driver); |