diff options
Diffstat (limited to 'drivers/tty/serial/serial_core.c')
-rw-r--r-- | drivers/tty/serial/serial_core.c | 186 |
1 files changed, 171 insertions, 15 deletions
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 098bb99..2c7230a 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -657,10 +657,10 @@ static void uart_unthrottle(struct tty_struct *tty) uart_set_mctrl(port, TIOCM_RTS); } -static void uart_get_info(struct tty_port *port, - struct uart_state *state, +static void do_uart_get_info(struct tty_port *port, struct serial_struct *retinfo) { + struct uart_state *state = container_of(port, struct uart_state, port); struct uart_port *uport = state->uart_port; memset(retinfo, 0, sizeof(*retinfo)); @@ -685,17 +685,21 @@ static void uart_get_info(struct tty_port *port, retinfo->iomem_base = (void *)(unsigned long)uport->mapbase; } -static int uart_get_info_user(struct uart_state *state, - struct serial_struct __user *retinfo) +static void uart_get_info(struct tty_port *port, + struct serial_struct *retinfo) { - struct tty_port *port = &state->port; - struct serial_struct tmp; - /* Ensure the state we copy is consistent and no hardware changes occur as we go */ mutex_lock(&port->mutex); - uart_get_info(port, state, &tmp); + do_uart_get_info(port, retinfo); mutex_unlock(&port->mutex); +} + +static int uart_get_info_user(struct tty_port *port, + struct serial_struct __user *retinfo) +{ + struct serial_struct tmp; + uart_get_info(port, &tmp); if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) return -EFAULT; @@ -1154,7 +1158,7 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, */ switch (cmd) { case TIOCGSERIAL: - ret = uart_get_info_user(state, uarg); + ret = uart_get_info_user(port, uarg); break; case TIOCSSERIAL: @@ -2336,6 +2340,8 @@ int uart_register_driver(struct uart_driver *drv) if (retval >= 0) return retval; + for (i = 0; i < drv->nr; i++) + tty_port_destroy(&drv->state[i].port); put_tty_driver(normal); out_kfree: kfree(drv->state); @@ -2355,8 +2361,12 @@ out: void uart_unregister_driver(struct uart_driver *drv) { struct tty_driver *p = drv->tty_driver; + unsigned int i; + tty_unregister_driver(p); put_tty_driver(p); + for (i = 0; i < drv->nr; i++) + tty_port_destroy(&drv->state[i].port); kfree(drv->state); drv->state = NULL; drv->tty_driver = NULL; @@ -2372,21 +2382,166 @@ struct tty_driver *uart_console_device(struct console *co, int *index) static ssize_t uart_get_attr_uartclk(struct device *dev, struct device_attribute *attr, char *buf) { - int ret; + struct serial_struct tmp; struct tty_port *port = dev_get_drvdata(dev); - struct uart_state *state = container_of(port, struct uart_state, port); - mutex_lock(&state->port.mutex); - ret = snprintf(buf, PAGE_SIZE, "%d\n", state->uart_port->uartclk); - mutex_unlock(&state->port.mutex); + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "%d\n", tmp.baud_base * 16); +} - return ret; +static ssize_t uart_get_attr_type(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "%d\n", tmp.type); +} +static ssize_t uart_get_attr_line(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "%d\n", tmp.line); +} + +static ssize_t uart_get_attr_port(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + unsigned long ioaddr; + + uart_get_info(port, &tmp); + ioaddr = tmp.port; + if (HIGH_BITS_OFFSET) + ioaddr |= (unsigned long)tmp.port_high << HIGH_BITS_OFFSET; + return snprintf(buf, PAGE_SIZE, "0x%lX\n", ioaddr); } +static ssize_t uart_get_attr_irq(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "%d\n", tmp.irq); +} + +static ssize_t uart_get_attr_flags(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "0x%X\n", tmp.flags); +} + +static ssize_t uart_get_attr_xmit_fifo_size(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "%d\n", tmp.xmit_fifo_size); +} + + +static ssize_t uart_get_attr_close_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "%d\n", tmp.close_delay); +} + + +static ssize_t uart_get_attr_closing_wait(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "%d\n", tmp.closing_wait); +} + +static ssize_t uart_get_attr_custom_divisor(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "%d\n", tmp.custom_divisor); +} + +static ssize_t uart_get_attr_io_type(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "%d\n", tmp.io_type); +} + +static ssize_t uart_get_attr_iomem_base(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "0x%lX\n", (unsigned long)tmp.iomem_base); +} + +static ssize_t uart_get_attr_iomem_reg_shift(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "%d\n", tmp.iomem_reg_shift); +} + +static DEVICE_ATTR(type, S_IRUSR | S_IRGRP, uart_get_attr_type, NULL); +static DEVICE_ATTR(line, S_IRUSR | S_IRGRP, uart_get_attr_line, NULL); +static DEVICE_ATTR(port, S_IRUSR | S_IRGRP, uart_get_attr_port, NULL); +static DEVICE_ATTR(irq, S_IRUSR | S_IRGRP, uart_get_attr_irq, NULL); +static DEVICE_ATTR(flags, S_IRUSR | S_IRGRP, uart_get_attr_flags, NULL); +static DEVICE_ATTR(xmit_fifo_size, S_IRUSR | S_IRGRP, uart_get_attr_xmit_fifo_size, NULL); static DEVICE_ATTR(uartclk, S_IRUSR | S_IRGRP, uart_get_attr_uartclk, NULL); +static DEVICE_ATTR(close_delay, S_IRUSR | S_IRGRP, uart_get_attr_close_delay, NULL); +static DEVICE_ATTR(closing_wait, S_IRUSR | S_IRGRP, uart_get_attr_closing_wait, NULL); +static DEVICE_ATTR(custom_divisor, S_IRUSR | S_IRGRP, uart_get_attr_custom_divisor, NULL); +static DEVICE_ATTR(io_type, S_IRUSR | S_IRGRP, uart_get_attr_io_type, NULL); +static DEVICE_ATTR(iomem_base, S_IRUSR | S_IRGRP, uart_get_attr_iomem_base, NULL); +static DEVICE_ATTR(iomem_reg_shift, S_IRUSR | S_IRGRP, uart_get_attr_iomem_reg_shift, NULL); static struct attribute *tty_dev_attrs[] = { + &dev_attr_type.attr, + &dev_attr_line.attr, + &dev_attr_port.attr, + &dev_attr_irq.attr, + &dev_attr_flags.attr, + &dev_attr_xmit_fifo_size.attr, &dev_attr_uartclk.attr, + &dev_attr_close_delay.attr, + &dev_attr_closing_wait.attr, + &dev_attr_custom_divisor.attr, + &dev_attr_io_type.attr, + &dev_attr_iomem_base.attr, + &dev_attr_iomem_reg_shift.attr, NULL, }; @@ -2399,6 +2554,7 @@ static const struct attribute_group *tty_dev_attr_groups[] = { NULL }; + /** * uart_add_one_port - attach a driver-defined port structure * @drv: pointer to the uart low level driver structure for this port |