diff options
author | Paul Walmsley <paul@pwsan.com> | 2012-09-23 17:15:44 -0600 |
---|---|---|
committer | Paul Walmsley <paul@pwsan.com> | 2012-09-23 17:15:44 -0600 |
commit | 291852e8791a596195edc3ced96481bfd105f35b (patch) | |
tree | 5ac0d7f65cc21943863301fc50e62a616b168e8d /drivers | |
parent | 2910f14584eddf2bc0db4baec3c6950ef357b52c (diff) | |
parent | de6ca33a96a6bf61fcb91d3d399703e19ead9d1e (diff) | |
download | linux-291852e8791a596195edc3ced96481bfd105f35b.tar.bz2 |
Merge tag 'cleanup-fixes-for-v3.7' into test_v3.6-rc6_ocb3.7_cff3.7_odaf3.7
These fixes are needed to fix non-omap build breakage for
twl-core driver and to fix omap1_defconfig compile when
led driver changes and omap sparse IRQ changes are merged
together. Also fix warnings for omaps not using pinctrl
framework yet.
Diffstat (limited to 'drivers')
146 files changed, 6016 insertions, 4083 deletions
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c index 12172a6a95c4..0bc8a6a6a148 100644 --- a/drivers/bluetooth/hci_ath.c +++ b/drivers/bluetooth/hci_ath.c @@ -58,7 +58,7 @@ static int ath_wakeup_ar3k(struct tty_struct *tty) return status; /* Disable Automatic RTSCTS */ - memcpy(&ktermios, tty->termios, sizeof(ktermios)); + ktermios = tty->termios; ktermios.c_cflag &= ~CRTSCTS; tty_set_termios(tty, &ktermios); diff --git a/drivers/char/mwave/mwavedd.c b/drivers/char/mwave/mwavedd.c index 1d82d5838f0c..164544afd680 100644 --- a/drivers/char/mwave/mwavedd.c +++ b/drivers/char/mwave/mwavedd.c @@ -430,7 +430,7 @@ static ssize_t mwave_write(struct file *file, const char __user *buf, static int register_serial_portandirq(unsigned int port, int irq) { - struct uart_port uart; + struct uart_8250_port uart; switch ( port ) { case 0x3f8: @@ -462,14 +462,14 @@ static int register_serial_portandirq(unsigned int port, int irq) } /* switch */ /* irq is okay */ - memset(&uart, 0, sizeof(struct uart_port)); + memset(&uart, 0, sizeof(uart)); - uart.uartclk = 1843200; - uart.iobase = port; - uart.irq = irq; - uart.iotype = UPIO_PORT; - uart.flags = UPF_SHARE_IRQ; - return serial8250_register_port(&uart); + uart.port.uartclk = 1843200; + uart.port.iobase = port; + uart.port.irq = irq; + uart.port.iotype = UPIO_PORT; + uart.port.flags = UPF_SHARE_IRQ; + return serial8250_register_8250_port(&uart); } diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 0a484b4a1b02..3f57d5de3957 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -1050,7 +1050,7 @@ static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty) wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); - if (info->port.flags & ASYNC_CTS_FLOW) { + if (tty_port_cts_enabled(&info->port)) { if (tty->hw_stopped) { if (info->serial_signals & SerialSignal_CTS) { if (debug_level >= DEBUG_LEVEL_ISR) @@ -1344,7 +1344,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty) /* TODO:disable interrupts instead of reset to preserve signal states */ reset_device(info); - if (!tty || tty->termios->c_cflag & HUPCL) { + if (!tty || tty->termios.c_cflag & HUPCL) { info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS); set_signals(info); } @@ -1385,7 +1385,7 @@ static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty) port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI); get_signals(info); - if (info->netcount || (tty && (tty->termios->c_cflag & CREAD))) + if (info->netcount || (tty && (tty->termios.c_cflag & CREAD))) rx_start(info); spin_unlock_irqrestore(&info->lock,flags); @@ -1398,14 +1398,14 @@ static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty) unsigned cflag; int bits_per_char; - if (!tty || !tty->termios) + if (!tty) return; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgslpc_change_params(%s)\n", __FILE__,__LINE__, info->device_name ); - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; /* if B0 rate (hangup) specified then negate DTR and RTS */ /* otherwise assert DTR and RTS */ @@ -1728,7 +1728,7 @@ static void mgslpc_throttle(struct tty_struct * tty) if (I_IXOFF(tty)) mgslpc_send_xchar(tty, STOP_CHAR(tty)); - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { spin_lock_irqsave(&info->lock,flags); info->serial_signals &= ~SerialSignal_RTS; set_signals(info); @@ -1757,7 +1757,7 @@ static void mgslpc_unthrottle(struct tty_struct * tty) mgslpc_send_xchar(tty, START_CHAR(tty)); } - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { spin_lock_irqsave(&info->lock,flags); info->serial_signals |= SerialSignal_RTS; set_signals(info); @@ -2293,8 +2293,8 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term tty->driver->name ); /* just return if nothing has changed */ - if ((tty->termios->c_cflag == old_termios->c_cflag) - && (RELEVANT_IFLAG(tty->termios->c_iflag) + if ((tty->termios.c_cflag == old_termios->c_cflag) + && (RELEVANT_IFLAG(tty->termios.c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) return; @@ -2302,7 +2302,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term /* Handle transition to B0 status */ if (old_termios->c_cflag & CBAUD && - !(tty->termios->c_cflag & CBAUD)) { + !(tty->termios.c_cflag & CBAUD)) { info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); spin_lock_irqsave(&info->lock,flags); set_signals(info); @@ -2311,9 +2311,9 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && - tty->termios->c_cflag & CBAUD) { + tty->termios.c_cflag & CBAUD) { info->serial_signals |= SerialSignal_DTR; - if (!(tty->termios->c_cflag & CRTSCTS) || + if (!(tty->termios.c_cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) { info->serial_signals |= SerialSignal_RTS; } @@ -2324,7 +2324,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term /* Handle turning off CRTSCTS */ if (old_termios->c_cflag & CRTSCTS && - !(tty->termios->c_cflag & CRTSCTS)) { + !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; tx_release(tty); } @@ -2731,6 +2731,8 @@ static void mgslpc_add_device(MGSLPC_INFO *info) #if SYNCLINK_GENERIC_HDLC hdlcdev_init(info); #endif + tty_port_register_device(&info->port, serial_driver, info->line, + &info->p_dev->dev); } static void mgslpc_remove_device(MGSLPC_INFO *remove_info) @@ -2744,6 +2746,7 @@ static void mgslpc_remove_device(MGSLPC_INFO *remove_info) last->next_device = info->next_device; else mgslpc_device_list = info->next_device; + tty_unregister_device(serial_driver, info->line); #if SYNCLINK_GENERIC_HDLC hdlcdev_exit(info); #endif @@ -2798,77 +2801,63 @@ static const struct tty_operations mgslpc_ops = { .proc_fops = &mgslpc_proc_fops, }; -static void synclink_cs_cleanup(void) +static int __init synclink_cs_init(void) { int rc; - while(mgslpc_device_list) - mgslpc_remove_device(mgslpc_device_list); - - if (serial_driver) { - if ((rc = tty_unregister_driver(serial_driver))) - printk("%s(%d) failed to unregister tty driver err=%d\n", - __FILE__,__LINE__,rc); - put_tty_driver(serial_driver); + if (break_on_load) { + mgslpc_get_text_ptr(); + BREAKPOINT(); } - pcmcia_unregister_driver(&mgslpc_driver); -} - -static int __init synclink_cs_init(void) -{ - int rc; - - if (break_on_load) { - mgslpc_get_text_ptr(); - BREAKPOINT(); - } - - if ((rc = pcmcia_register_driver(&mgslpc_driver)) < 0) - return rc; - - serial_driver = alloc_tty_driver(MAX_DEVICE_COUNT); - if (!serial_driver) { - rc = -ENOMEM; - goto error; - } + serial_driver = tty_alloc_driver(MAX_DEVICE_COUNT, + TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV); + if (IS_ERR(serial_driver)) { + rc = PTR_ERR(serial_driver); + goto err; + } - /* Initialize the tty_driver structure */ - - serial_driver->driver_name = "synclink_cs"; - serial_driver->name = "ttySLP"; - serial_driver->major = ttymajor; - serial_driver->minor_start = 64; - serial_driver->type = TTY_DRIVER_TYPE_SERIAL; - serial_driver->subtype = SERIAL_TYPE_NORMAL; - serial_driver->init_termios = tty_std_termios; - serial_driver->init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - serial_driver->flags = TTY_DRIVER_REAL_RAW; - tty_set_operations(serial_driver, &mgslpc_ops); - - if ((rc = tty_register_driver(serial_driver)) < 0) { - printk("%s(%d):Couldn't register serial driver\n", - __FILE__,__LINE__); - put_tty_driver(serial_driver); - serial_driver = NULL; - goto error; - } + /* Initialize the tty_driver structure */ + serial_driver->driver_name = "synclink_cs"; + serial_driver->name = "ttySLP"; + serial_driver->major = ttymajor; + serial_driver->minor_start = 64; + serial_driver->type = TTY_DRIVER_TYPE_SERIAL; + serial_driver->subtype = SERIAL_TYPE_NORMAL; + serial_driver->init_termios = tty_std_termios; + serial_driver->init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + tty_set_operations(serial_driver, &mgslpc_ops); + + rc = tty_register_driver(serial_driver); + if (rc < 0) { + printk(KERN_ERR "%s(%d):Couldn't register serial driver\n", + __FILE__, __LINE__); + goto err_put_tty; + } - printk("%s %s, tty major#%d\n", - driver_name, driver_version, - serial_driver->major); + rc = pcmcia_register_driver(&mgslpc_driver); + if (rc < 0) + goto err_unreg_tty; - return 0; + printk(KERN_INFO "%s %s, tty major#%d\n", driver_name, driver_version, + serial_driver->major); -error: - synclink_cs_cleanup(); - return rc; + return 0; +err_unreg_tty: + tty_unregister_driver(serial_driver); +err_put_tty: + put_tty_driver(serial_driver); +err: + return rc; } static void __exit synclink_cs_exit(void) { - synclink_cs_cleanup(); + pcmcia_unregister_driver(&mgslpc_driver); + tty_unregister_driver(serial_driver); + put_tty_driver(serial_driver); } module_init(synclink_cs_init); diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index 46b77ede84c0..af98f6d6509b 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -67,7 +67,7 @@ static int tpk_printk(const unsigned char *buf, int count) tmp[tpk_curr + 1] = '\0'; printk(KERN_INFO "%s%s", tpk_tag, tmp); tpk_curr = 0; - if (buf[i + 1] == '\n') + if ((i + 1) < count && buf[i + 1] == '\n') i++; break; case '\n': @@ -178,11 +178,17 @@ static struct tty_driver *ttyprintk_driver; static int __init ttyprintk_init(void) { int ret = -ENOMEM; - void *rp; - ttyprintk_driver = alloc_tty_driver(1); - if (!ttyprintk_driver) - return ret; + tty_port_init(&tpk_port.port); + tpk_port.port.ops = &null_ops; + mutex_init(&tpk_port.port_write_mutex); + + ttyprintk_driver = tty_alloc_driver(1, + TTY_DRIVER_RESET_TERMIOS | + TTY_DRIVER_REAL_RAW | + TTY_DRIVER_UNNUMBERED_NODE); + if (IS_ERR(ttyprintk_driver)) + return PTR_ERR(ttyprintk_driver); ttyprintk_driver->driver_name = "ttyprintk"; ttyprintk_driver->name = "ttyprintk"; @@ -191,9 +197,8 @@ static int __init ttyprintk_init(void) ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE; ttyprintk_driver->init_termios = tty_std_termios; ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET; - ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS | - TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_set_operations(ttyprintk_driver, &ttyprintk_ops); + tty_port_link_device(&tpk_port.port, ttyprintk_driver, 0); ret = tty_register_driver(ttyprintk_driver); if (ret < 0) { @@ -201,22 +206,10 @@ static int __init ttyprintk_init(void) goto error; } - /* create our unnumbered device */ - rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL, - ttyprintk_driver->name); - if (IS_ERR(rp)) { - printk(KERN_ERR "Couldn't create ttyprintk device\n"); - ret = PTR_ERR(rp); - goto error; - } - - tty_port_init(&tpk_port.port); - tpk_port.port.ops = &null_ops; - mutex_init(&tpk_port.port_write_mutex); - return 0; error: + tty_unregister_driver(ttyprintk_driver); put_tty_driver(ttyprintk_driver); ttyprintk_driver = NULL; return ret; diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c index ae0561826137..2e1662777661 100644 --- a/drivers/dma/omap-dma.c +++ b/drivers/dma/omap-dma.c @@ -18,6 +18,8 @@ #include <linux/spinlock.h> #include "virt-dma.h" + +#include <plat/cpu.h> #include <plat/dma.h> struct omap_dmadev { diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index e6efd77668f0..64fbce30c502 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -25,11 +25,9 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/irqdomain.h> +#include <linux/gpio.h> +#include <linux/platform_data/gpio-omap.h> -#include <mach/hardware.h> -#include <asm/irq.h> -#include <mach/irqs.h> -#include <asm/gpio.h> #include <asm/mach/irq.h> #define OFF_MODE 1 @@ -385,13 +383,16 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, static int gpio_irq_type(struct irq_data *d, unsigned type) { struct gpio_bank *bank = irq_data_get_irq_chip_data(d); - unsigned gpio; + unsigned gpio = 0; int retval; unsigned long flags; - if (!cpu_class_is_omap2() && d->irq > IH_MPUIO_BASE) +#ifdef CONFIG_ARCH_OMAP1 + if (d->irq > IH_MPUIO_BASE) gpio = OMAP_MPUIO(d->irq - IH_MPUIO_BASE); - else +#endif + + if (!gpio) gpio = irq_to_gpio(bank, d->irq); if (type & ~IRQ_TYPE_SENSE_MASK) diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 94256fe7bf36..f030880bc9bb 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -51,6 +51,7 @@ static struct gpio_chip twl_gpiochip; +static int twl4030_gpio_base; static int twl4030_gpio_irq_base; /* genirq interfaces are not available to modules */ @@ -428,8 +429,6 @@ no_irqs: twl_gpiochip.dev = &pdev->dev; if (pdata) { - twl_gpiochip.base = pdata->gpio_base; - /* * NOTE: boards may waste power if they don't set pullups * and pulldowns correctly ... default for non-ULPI pins is @@ -461,15 +460,21 @@ no_irqs: dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret); twl_gpiochip.ngpio = 0; gpio_twl4030_remove(pdev); - } else if (pdata && pdata->setup) { + goto out; + } + + twl4030_gpio_base = twl_gpiochip.base; + + if (pdata && pdata->setup) { int status; status = pdata->setup(&pdev->dev, - pdata->gpio_base, TWL4030_GPIO_MAX); + twl4030_gpio_base, TWL4030_GPIO_MAX); if (status) dev_dbg(&pdev->dev, "setup --> %d\n", status); } +out: return ret; } @@ -481,7 +486,7 @@ static int gpio_twl4030_remove(struct platform_device *pdev) if (pdata && pdata->teardown) { status = pdata->teardown(&pdev->dev, - pdata->gpio_base, TWL4030_GPIO_MAX); + twl4030_gpio_base, TWL4030_GPIO_MAX); if (status) { dev_dbg(&pdev->dev, "teardown --> %d\n", status); return status; diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index c50fa75416f8..b4b65af8612a 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -533,7 +533,7 @@ config KEYBOARD_DAVINCI config KEYBOARD_OMAP tristate "TI OMAP keypad support" - depends on (ARCH_OMAP1 || ARCH_OMAP2) + depends on ARCH_OMAP1 select INPUT_MATRIXKMAP help Say Y here if you want to use the OMAP keypad. diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c index a0222db4dc86..2bda5f0b9c6e 100644 --- a/drivers/input/keyboard/omap-keypad.c +++ b/drivers/input/keyboard/omap-keypad.c @@ -35,13 +35,9 @@ #include <linux/mutex.h> #include <linux/errno.h> #include <linux/slab.h> -#include <asm/gpio.h> +#include <linux/gpio.h> +#include <linux/platform_data/gpio-omap.h> #include <plat/keypad.h> -#include <plat/menelaus.h> -#include <asm/irq.h> -#include <mach/hardware.h> -#include <asm/io.h> -#include <plat/mux.h> #undef NEW_BOARD_LEARNING_MODE @@ -96,28 +92,8 @@ static u8 get_row_gpio_val(struct omap_kp *omap_kp) static irqreturn_t omap_kp_interrupt(int irq, void *dev_id) { - struct omap_kp *omap_kp = dev_id; - /* disable keyboard interrupt and schedule for handling */ - if (cpu_is_omap24xx()) { - int i; - - for (i = 0; i < omap_kp->rows; i++) { - int gpio_irq = gpio_to_irq(row_gpios[i]); - /* - * The interrupt which we're currently handling should - * be disabled _nosync() to avoid deadlocks waiting - * for this handler to complete. All others should - * be disabled the regular way for SMP safety. - */ - if (gpio_irq == irq) - disable_irq_nosync(gpio_irq); - else - disable_irq(gpio_irq); - } - } else - /* disable keyboard interrupt and schedule for handling */ - omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); + omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); tasklet_schedule(&kp_tasklet); @@ -133,33 +109,22 @@ static void omap_kp_scan_keypad(struct omap_kp *omap_kp, unsigned char *state) { int col = 0; - /* read the keypad status */ - if (cpu_is_omap24xx()) { - /* read the keypad status */ - for (col = 0; col < omap_kp->cols; col++) { - set_col_gpio_val(omap_kp, ~(1 << col)); - state[col] = ~(get_row_gpio_val(omap_kp)) & 0xff; - } - set_col_gpio_val(omap_kp, 0); - - } else { - /* disable keyboard interrupt and schedule for handling */ - omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); + /* disable keyboard interrupt and schedule for handling */ + omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); - /* read the keypad status */ - omap_writew(0xff, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC); - for (col = 0; col < omap_kp->cols; col++) { - omap_writew(~(1 << col) & 0xff, - OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC); + /* read the keypad status */ + omap_writew(0xff, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC); + for (col = 0; col < omap_kp->cols; col++) { + omap_writew(~(1 << col) & 0xff, + OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC); - udelay(omap_kp->delay); + udelay(omap_kp->delay); - state[col] = ~omap_readw(OMAP1_MPUIO_BASE + - OMAP_MPUIO_KBR_LATCH) & 0xff; - } - omap_writew(0x00, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC); - udelay(2); + state[col] = ~omap_readw(OMAP1_MPUIO_BASE + + OMAP_MPUIO_KBR_LATCH) & 0xff; } + omap_writew(0x00, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC); + udelay(2); } static void omap_kp_tasklet(unsigned long data) @@ -222,14 +187,8 @@ static void omap_kp_tasklet(unsigned long data) mod_timer(&omap_kp_data->timer, jiffies + delay); } else { /* enable interrupts */ - if (cpu_is_omap24xx()) { - int i; - for (i = 0; i < omap_kp_data->rows; i++) - enable_irq(gpio_to_irq(row_gpios[i])); - } else { - omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); - kp_cur_group = -1; - } + omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); + kp_cur_group = -1; } } @@ -242,6 +201,7 @@ static ssize_t omap_kp_enable_show(struct device *dev, static ssize_t omap_kp_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct omap_kp *omap_kp = dev_get_drvdata(dev); int state; if (sscanf(buf, "%u", &state) != 1) @@ -253,9 +213,9 @@ static ssize_t omap_kp_enable_store(struct device *dev, struct device_attribute mutex_lock(&kp_enable_mutex); if (state != kp_enable) { if (state) - enable_irq(INT_KEYBOARD); + enable_irq(omap_kp->irq); else - disable_irq(INT_KEYBOARD); + disable_irq(omap_kp->irq); kp_enable = state; } mutex_unlock(&kp_enable_mutex); @@ -289,7 +249,7 @@ static int __devinit omap_kp_probe(struct platform_device *pdev) struct omap_kp *omap_kp; struct input_dev *input_dev; struct omap_kp_platform_data *pdata = pdev->dev.platform_data; - int i, col_idx, row_idx, irq_idx, ret; + int i, col_idx, row_idx, ret; unsigned int row_shift, keycodemax; if (!pdata->rows || !pdata->cols || !pdata->keymap_data) { @@ -314,8 +274,7 @@ static int __devinit omap_kp_probe(struct platform_device *pdev) omap_kp->input = input_dev; /* Disable the interrupt for the MPUIO keyboard */ - if (!cpu_is_omap24xx()) - omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); + omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); if (pdata->delay) omap_kp->delay = pdata->delay; @@ -328,31 +287,8 @@ static int __devinit omap_kp_probe(struct platform_device *pdev) omap_kp->rows = pdata->rows; omap_kp->cols = pdata->cols; - if (cpu_is_omap24xx()) { - /* Cols: outputs */ - for (col_idx = 0; col_idx < omap_kp->cols; col_idx++) { - if (gpio_request(col_gpios[col_idx], "omap_kp_col") < 0) { - printk(KERN_ERR "Failed to request" - "GPIO%d for keypad\n", - col_gpios[col_idx]); - goto err1; - } - gpio_direction_output(col_gpios[col_idx], 0); - } - /* Rows: inputs */ - for (row_idx = 0; row_idx < omap_kp->rows; row_idx++) { - if (gpio_request(row_gpios[row_idx], "omap_kp_row") < 0) { - printk(KERN_ERR "Failed to request" - "GPIO%d for keypad\n", - row_gpios[row_idx]); - goto err2; - } - gpio_direction_input(row_gpios[row_idx]); - } - } else { - col_idx = 0; - row_idx = 0; - } + col_idx = 0; + row_idx = 0; setup_timer(&omap_kp->timer, omap_kp_timer, (unsigned long)omap_kp); @@ -394,27 +330,16 @@ static int __devinit omap_kp_probe(struct platform_device *pdev) /* scan current status and enable interrupt */ omap_kp_scan_keypad(omap_kp, keypad_state); - if (!cpu_is_omap24xx()) { - omap_kp->irq = platform_get_irq(pdev, 0); - if (omap_kp->irq >= 0) { - if (request_irq(omap_kp->irq, omap_kp_interrupt, 0, - "omap-keypad", omap_kp) < 0) - goto err4; - } - omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); - } else { - for (irq_idx = 0; irq_idx < omap_kp->rows; irq_idx++) { - if (request_irq(gpio_to_irq(row_gpios[irq_idx]), - omap_kp_interrupt, - IRQF_TRIGGER_FALLING, - "omap-keypad", omap_kp) < 0) - goto err5; - } + omap_kp->irq = platform_get_irq(pdev, 0); + if (omap_kp->irq >= 0) { + if (request_irq(omap_kp->irq, omap_kp_interrupt, 0, + "omap-keypad", omap_kp) < 0) + goto err4; } + omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); + return 0; -err5: - for (i = irq_idx - 1; i >=0; i--) - free_irq(row_gpios[i], omap_kp); + err4: input_unregister_device(omap_kp->input); input_dev = NULL; @@ -423,7 +348,6 @@ err3: err2: for (i = row_idx - 1; i >=0; i--) gpio_free(row_gpios[i]); -err1: for (i = col_idx - 1; i >=0; i--) gpio_free(col_gpios[i]); @@ -439,18 +363,8 @@ static int __devexit omap_kp_remove(struct platform_device *pdev) /* disable keypad interrupt handling */ tasklet_disable(&kp_tasklet); - if (cpu_is_omap24xx()) { - int i; - for (i = 0; i < omap_kp->cols; i++) - gpio_free(col_gpios[i]); - for (i = 0; i < omap_kp->rows; i++) { - gpio_free(row_gpios[i]); - free_irq(gpio_to_irq(row_gpios[i]), omap_kp); - } - } else { - omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); - free_irq(omap_kp->irq, omap_kp); - } + omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); + free_irq(omap_kp->irq, omap_kp); del_timer_sync(&omap_kp->timer); tasklet_kill(&kp_tasklet); diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 38c4bd87b2c9..c679867c2ccd 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -234,7 +234,8 @@ static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci) mp->minor = minor; - dev = tty_register_device(capinc_tty_driver, minor, NULL); + dev = tty_port_register_device(&mp->port, capinc_tty_driver, minor, + NULL); if (IS_ERR(dev)) goto err_out2; diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index a6d9fd2858f7..67abf3ff45e8 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -446,8 +446,8 @@ static void if_set_termios(struct tty_struct *tty, struct ktermios *old) goto out; } - iflag = tty->termios->c_iflag; - cflag = tty->termios->c_cflag; + iflag = tty->termios.c_iflag; + cflag = tty->termios.c_cflag; old_cflag = old ? old->c_cflag : cflag; gig_dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x", cs->minor_index, iflag, cflag, old_cflag); @@ -524,7 +524,8 @@ void gigaset_if_init(struct cardstate *cs) tasklet_init(&cs->if_wake_tasklet, if_wake, (unsigned long) cs); mutex_lock(&cs->mutex); - cs->tty_dev = tty_register_device(drv->tty, cs->minor_index, NULL); + cs->tty_dev = tty_port_register_device(&cs->port, drv->tty, + cs->minor_index, NULL); if (!IS_ERR(cs->tty_dev)) dev_set_drvdata(cs->tty_dev, cs); diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 7bc50670d7d9..b817809f763c 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1009,15 +1009,15 @@ isdn_tty_change_speed(modem_info *info) quot; int i; - if (!port->tty || !port->tty->termios) + if (!port->tty) return; - cflag = port->tty->termios->c_cflag; + cflag = port->tty->termios.c_cflag; quot = i = cflag & CBAUD; if (i & CBAUDEX) { i &= ~CBAUDEX; if (i < 1 || i > 2) - port->tty->termios->c_cflag &= ~CBAUDEX; + port->tty->termios.c_cflag &= ~CBAUDEX; else i += 15; } @@ -1097,7 +1097,7 @@ isdn_tty_shutdown(modem_info *info) #endif isdn_unlock_drivers(); info->msr &= ~UART_MSR_RI; - if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) { + if (!info->port.tty || (info->port.tty->termios.c_cflag & HUPCL)) { info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS); if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) { isdn_tty_modem_reset_regs(info, 0); @@ -1469,13 +1469,13 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) if (!old_termios) isdn_tty_change_speed(info); else { - if (tty->termios->c_cflag == old_termios->c_cflag && - tty->termios->c_ispeed == old_termios->c_ispeed && - tty->termios->c_ospeed == old_termios->c_ospeed) + if (tty->termios.c_cflag == old_termios->c_cflag && + tty->termios.c_ispeed == old_termios->c_ispeed && + tty->termios.c_ospeed == old_termios->c_ospeed) return; isdn_tty_change_speed(info); if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) + !(tty->termios.c_cflag & CRTSCTS)) tty->hw_stopped = 0; } } @@ -1486,6 +1486,18 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) * ------------------------------------------------------------ */ +static int isdn_tty_install(struct tty_driver *driver, struct tty_struct *tty) +{ + modem_info *info = &dev->mdm.info[tty->index]; + + if (isdn_tty_paranoia_check(info, tty->name, __func__)) + return -ENODEV; + + tty->driver_data = info; + + return tty_port_install(&info->port, driver, tty); +} + /* * This routine is called whenever a serial port is opened. It * enables interrupts for a serial port, linking in its async structure into @@ -1495,22 +1507,16 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) static int isdn_tty_open(struct tty_struct *tty, struct file *filp) { - struct tty_port *port; - modem_info *info; + modem_info *info = tty->driver_data; + struct tty_port *port = &info->port; int retval; - info = &dev->mdm.info[tty->index]; - if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open")) - return -ENODEV; - port = &info->port; #ifdef ISDN_DEBUG_MODEM_OPEN printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name, port->count); #endif port->count++; - tty->driver_data = info; port->tty = tty; - tty->port = port; /* * Start up serial port */ @@ -1738,6 +1744,7 @@ modem_write_profile(atemu *m) } static const struct tty_operations modem_ops = { + .install = isdn_tty_install, .open = isdn_tty_open, .close = isdn_tty_close, .write = isdn_tty_write, @@ -1782,7 +1789,7 @@ isdn_tty_modem_init(void) m->tty_modem->subtype = SERIAL_TYPE_NORMAL; m->tty_modem->init_termios = tty_std_termios; m->tty_modem->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - m->tty_modem->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + m->tty_modem->flags = TTY_DRIVER_REAL_RAW; m->tty_modem->driver_name = "isdn_tty"; tty_set_operations(m->tty_modem, &modem_ops); retval = tty_register_driver(m->tty_modem); diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index 88cf9d952631..409da0f8e5cf 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c @@ -44,6 +44,7 @@ #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> +#include <plat/cpu.h> #include <plat/dma.h> #include <plat/vrfb.h> #include <video/omapdss.h> diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index 1c347633e663..43e61fe5df50 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -70,6 +70,8 @@ #include <media/v4l2-common.h> #include <media/v4l2-device.h> +#include <plat/cpu.h> + #include "isp.h" #include "ispreg.h" #include "ispccdc.h" diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 1c32afed28aa..9d3a0bc1a65f 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -1132,12 +1132,7 @@ static void clocks_init(struct device *dev, u32 rate; u8 ctrl = HFCLK_FREQ_26_MHZ; -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) - if (cpu_is_omap2430()) - osc = clk_get(dev, "osc_ck"); - else - osc = clk_get(dev, "osc_sys_ck"); - + osc = clk_get(dev, "fck"); if (IS_ERR(osc)) { printk(KERN_WARNING "Skipping twl internal clock init and " "using bootloader value (unknown osc rate)\n"); @@ -1147,18 +1142,6 @@ static void clocks_init(struct device *dev, rate = clk_get_rate(osc); clk_put(osc); -#else - /* REVISIT for non-OMAP systems, pass the clock rate from - * board init code, using platform_data. - */ - osc = ERR_PTR(-EIO); - - printk(KERN_WARNING "Skipping twl internal clock init and " - "using bootloader value (unknown osc rate)\n"); - - return; -#endif - switch (rate) { case 19200000: ctrl = HFCLK_FREQ_19p2_MHZ; @@ -1220,10 +1203,23 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct twl4030_platform_data *pdata = client->dev.platform_data; struct device_node *node = client->dev.of_node; + struct platform_device *pdev; int irq_base = 0; int status; unsigned i, num_slaves; + pdev = platform_device_alloc(DRIVER_NAME, -1); + if (!pdev) { + dev_err(&client->dev, "can't alloc pdev\n"); + return -ENOMEM; + } + + status = platform_device_add(pdev); + if (status) { + platform_device_put(pdev); + return status; + } + if (node && !pdata) { /* * XXX: Temporary pdata until the information is correctly @@ -1232,23 +1228,30 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) pdata = devm_kzalloc(&client->dev, sizeof(struct twl4030_platform_data), GFP_KERNEL); - if (!pdata) - return -ENOMEM; + if (!pdata) { + status = -ENOMEM; + goto free; + } } if (!pdata) { dev_dbg(&client->dev, "no platform data?\n"); - return -EINVAL; + status = -EINVAL; + goto free; } + platform_set_drvdata(pdev, pdata); + if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) { dev_dbg(&client->dev, "can't talk I2C?\n"); - return -EIO; + status = -EIO; + goto free; } if (inuse) { dev_dbg(&client->dev, "driver is already in use\n"); - return -EBUSY; + status = -EBUSY; + goto free; } if ((id->driver_data) & TWL6030_CLASS) { @@ -1283,7 +1286,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) inuse = true; /* setup clock framework */ - clocks_init(&client->dev, pdata->clock); + clocks_init(&pdev->dev, pdata->clock); /* read TWL IDCODE Register */ if (twl_id == TWL4030_CLASS_ID) { @@ -1333,6 +1336,9 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) fail: if (status < 0) twl_remove(client); +free: + if (status < 0) + platform_device_unregister(pdev); return status; } diff --git a/drivers/misc/ibmasm/uart.c b/drivers/misc/ibmasm/uart.c index 1dcb9ae1905a..01e2b0d7e590 100644 --- a/drivers/misc/ibmasm/uart.c +++ b/drivers/misc/ibmasm/uart.c @@ -33,7 +33,7 @@ void ibmasm_register_uart(struct service_processor *sp) { - struct uart_port uport; + struct uart_8250_port uart; void __iomem *iomem_base; iomem_base = sp->base_address + SCOUT_COM_B_BASE; @@ -47,14 +47,14 @@ void ibmasm_register_uart(struct service_processor *sp) return; } - memset(&uport, 0, sizeof(struct uart_port)); - uport.irq = sp->irq; - uport.uartclk = 3686400; - uport.flags = UPF_SHARE_IRQ; - uport.iotype = UPIO_MEM; - uport.membase = iomem_base; + memset(&uart, 0, sizeof(uart)); + uart.port.irq = sp->irq; + uart.port.uartclk = 3686400; + uart.port.flags = UPF_SHARE_IRQ; + uart.port.iotype = UPIO_MEM; + uart.port.membase = iomem_base; - sp->serial_line = serial8250_register_port(&uport); + sp->serial_line = serial8250_register_8250_port(&uart); if (sp->serial_line < 0) { dev_err(sp->dev, "Failed to register serial port\n"); return; diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index b7eb545394b1..4999b34b7a60 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c @@ -60,7 +60,7 @@ struct pti_tty { }; struct pti_dev { - struct tty_port port; + struct tty_port port[PTITTY_MINOR_NUM]; unsigned long pti_addr; unsigned long aperture_base; void __iomem *pti_ioaddr; @@ -76,7 +76,7 @@ struct pti_dev { */ static DEFINE_MUTEX(alloclock); -static struct pci_device_id pci_ids[] __devinitconst = { +static const struct pci_device_id pci_ids[] __devinitconst = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x82B)}, {0} }; @@ -393,25 +393,6 @@ void pti_writedata(struct pti_masterchannel *mc, u8 *buf, int count) } EXPORT_SYMBOL_GPL(pti_writedata); -/** - * pti_pci_remove()- Driver exit method to remove PTI from - * PCI bus. - * @pdev: variable containing pci info of PTI. - */ -static void __devexit pti_pci_remove(struct pci_dev *pdev) -{ - struct pti_dev *drv_data; - - drv_data = pci_get_drvdata(pdev); - if (drv_data != NULL) { - pci_iounmap(pdev, drv_data->pti_ioaddr); - pci_set_drvdata(pdev, NULL); - kfree(drv_data); - pci_release_region(pdev, 1); - pci_disable_device(pdev); - } -} - /* * for the tty_driver_*() basic function descriptions, see tty_driver.h. * Specific header comments made for PTI-related specifics. @@ -446,7 +427,7 @@ static int pti_tty_driver_open(struct tty_struct *tty, struct file *filp) * also removes a locking requirement for the actual write * procedure. */ - return tty_port_open(&drv_data->port, tty, filp); + return tty_port_open(tty->port, tty, filp); } /** @@ -462,7 +443,7 @@ static int pti_tty_driver_open(struct tty_struct *tty, struct file *filp) */ static void pti_tty_driver_close(struct tty_struct *tty, struct file *filp) { - tty_port_close(&drv_data->port, tty, filp); + tty_port_close(tty->port, tty, filp); } /** @@ -818,6 +799,7 @@ static const struct tty_port_operations tty_port_ops = { static int __devinit pti_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { + unsigned int a; int retval = -EINVAL; int pci_bar = 1; @@ -830,7 +812,7 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev, __func__, __LINE__); pr_err("%s(%d): Error value returned: %d\n", __func__, __LINE__, retval); - return retval; + goto err; } retval = pci_enable_device(pdev); @@ -838,17 +820,16 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev, dev_err(&pdev->dev, "%s: pci_enable_device() returned error %d\n", __func__, retval); - return retval; + goto err_unreg_misc; } drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL); - if (drv_data == NULL) { retval = -ENOMEM; dev_err(&pdev->dev, "%s(%d): kmalloc() returned NULL memory.\n", __func__, __LINE__); - return retval; + goto err_disable_pci; } drv_data->pti_addr = pci_resource_start(pdev, pci_bar); @@ -857,33 +838,65 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev, dev_err(&pdev->dev, "%s(%d): pci_request_region() returned error %d\n", __func__, __LINE__, retval); - kfree(drv_data); - return retval; + goto err_free_dd; } drv_data->aperture_base = drv_data->pti_addr+APERTURE_14; drv_data->pti_ioaddr = ioremap_nocache((u32)drv_data->aperture_base, APERTURE_LEN); if (!drv_data->pti_ioaddr) { - pci_release_region(pdev, pci_bar); retval = -ENOMEM; - kfree(drv_data); - return retval; + goto err_rel_reg; } pci_set_drvdata(pdev, drv_data); - tty_port_init(&drv_data->port); - drv_data->port.ops = &tty_port_ops; + for (a = 0; a < PTITTY_MINOR_NUM; a++) { + struct tty_port *port = &drv_data->port[a]; + tty_port_init(port); + port->ops = &tty_port_ops; - tty_register_device(pti_tty_driver, 0, &pdev->dev); - tty_register_device(pti_tty_driver, 1, &pdev->dev); + tty_port_register_device(port, pti_tty_driver, a, &pdev->dev); + } register_console(&pti_console); + return 0; +err_rel_reg: + pci_release_region(pdev, pci_bar); +err_free_dd: + kfree(drv_data); +err_disable_pci: + pci_disable_device(pdev); +err_unreg_misc: + misc_deregister(&pti_char_driver); +err: return retval; } +/** + * pti_pci_remove()- Driver exit method to remove PTI from + * PCI bus. + * @pdev: variable containing pci info of PTI. + */ +static void __devexit pti_pci_remove(struct pci_dev *pdev) +{ + struct pti_dev *drv_data = pci_get_drvdata(pdev); + + unregister_console(&pti_console); + + tty_unregister_device(pti_tty_driver, 0); + tty_unregister_device(pti_tty_driver, 1); + + iounmap(drv_data->pti_ioaddr); + pci_set_drvdata(pdev, NULL); + kfree(drv_data); + pci_release_region(pdev, 1); + pci_disable_device(pdev); + + misc_deregister(&pti_char_driver); +} + static struct pci_driver pti_pci_driver = { .name = PCINAME, .id_table = pci_ids, @@ -933,25 +946,24 @@ static int __init pti_init(void) pr_err("%s(%d): Error value returned: %d\n", __func__, __LINE__, retval); - pti_tty_driver = NULL; - return retval; + goto put_tty; } retval = pci_register_driver(&pti_pci_driver); - if (retval) { pr_err("%s(%d): PCI registration failed of pti driver\n", __func__, __LINE__); pr_err("%s(%d): Error value returned: %d\n", __func__, __LINE__, retval); - - tty_unregister_driver(pti_tty_driver); - pr_err("%s(%d): Unregistering TTY part of pti driver\n", - __func__, __LINE__); - pti_tty_driver = NULL; - return retval; + goto unreg_tty; } + return 0; +unreg_tty: + tty_unregister_driver(pti_tty_driver); +put_tty: + put_tty_driver(pti_tty_driver); + pti_tty_driver = NULL; return retval; } @@ -960,31 +972,9 @@ static int __init pti_init(void) */ static void __exit pti_exit(void) { - int retval; - - tty_unregister_device(pti_tty_driver, 0); - tty_unregister_device(pti_tty_driver, 1); - - retval = tty_unregister_driver(pti_tty_driver); - if (retval) { - pr_err("%s(%d): TTY unregistration failed of pti driver\n", - __func__, __LINE__); - pr_err("%s(%d): Error value returned: %d\n", - __func__, __LINE__, retval); - } - + tty_unregister_driver(pti_tty_driver); pci_unregister_driver(&pti_pci_driver); - - retval = misc_deregister(&pti_char_driver); - if (retval) { - pr_err("%s(%d): CHAR unregistration failed of pti driver\n", - __func__, __LINE__); - pr_err("%s(%d): Error value returned: %d\n", - __func__, __LINE__, retval); - } - - unregister_console(&pti_console); - return; + put_tty_driver(pti_tty_driver); } module_init(pti_init); diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index 5a2cbfac66d2..d2339ea37815 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c @@ -518,7 +518,7 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port) if (status & UART_MSR_DCTS) { port->icount.cts++; tty = tty_port_tty_get(&port->port); - if (tty && (tty->termios->c_cflag & CRTSCTS)) { + if (tty && (tty->termios.c_cflag & CRTSCTS)) { int cts = (status & UART_MSR_CTS); if (tty->hw_stopped) { if (cts) { @@ -671,12 +671,12 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty) port->ier = UART_IER_RLSI|UART_IER_RDI|UART_IER_RTOIE|UART_IER_UUE; port->mctrl = TIOCM_OUT2; - sdio_uart_change_speed(port, tty->termios, NULL); + sdio_uart_change_speed(port, &tty->termios, NULL); - if (tty->termios->c_cflag & CBAUD) + if (tty->termios.c_cflag & CBAUD) sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR); - if (tty->termios->c_cflag & CRTSCTS) + if (tty->termios.c_cflag & CRTSCTS) if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS)) tty->hw_stopped = 1; @@ -850,7 +850,7 @@ static void sdio_uart_throttle(struct tty_struct *tty) { struct sdio_uart_port *port = tty->driver_data; - if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS)) + if (!I_IXOFF(tty) && !(tty->termios.c_cflag & CRTSCTS)) return; if (sdio_uart_claim_func(port) != 0) @@ -861,7 +861,7 @@ static void sdio_uart_throttle(struct tty_struct *tty) sdio_uart_start_tx(port); } - if (tty->termios->c_cflag & CRTSCTS) + if (tty->termios.c_cflag & CRTSCTS) sdio_uart_clear_mctrl(port, TIOCM_RTS); sdio_uart_irq(port->func); @@ -872,7 +872,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty) { struct sdio_uart_port *port = tty->driver_data; - if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS)) + if (!I_IXOFF(tty) && !(tty->termios.c_cflag & CRTSCTS)) return; if (sdio_uart_claim_func(port) != 0) @@ -887,7 +887,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty) } } - if (tty->termios->c_cflag & CRTSCTS) + if (tty->termios.c_cflag & CRTSCTS) sdio_uart_set_mctrl(port, TIOCM_RTS); sdio_uart_irq(port->func); @@ -898,12 +898,12 @@ static void sdio_uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct sdio_uart_port *port = tty->driver_data; - unsigned int cflag = tty->termios->c_cflag; + unsigned int cflag = tty->termios.c_cflag; if (sdio_uart_claim_func(port) != 0) return; - sdio_uart_change_speed(port, tty->termios, old_termios); + sdio_uart_change_speed(port, &tty->termios, old_termios); /* Handle transition to B0 status */ if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) @@ -1132,8 +1132,8 @@ static int sdio_uart_probe(struct sdio_func *func, kfree(port); } else { struct device *dev; - dev = tty_register_device(sdio_uart_tty_driver, - port->index, &func->dev); + dev = tty_port_register_device(&port->port, + sdio_uart_tty_driver, port->index, &func->dev); if (IS_ERR(dev)) { sdio_uart_port_remove(port); ret = PTR_ERR(dev); diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index a5999a74496a..87c0293a1eef 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -33,7 +33,6 @@ #include <asm/io.h> #include <asm/irq.h> -#include <plat/board.h> #include <plat/mmc.h> #include <asm/gpio.h> #include <plat/dma.h> diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 3a09f93cc3b6..f871b31ece5a 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -40,7 +40,6 @@ #include <linux/regulator/consumer.h> #include <linux/pm_runtime.h> #include <mach/hardware.h> -#include <plat/board.h> #include <plat/mmc.h> #include <plat/cpu.h> diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c index 861ca8f7e47d..78a524b49357 100644 --- a/drivers/mtd/nand/ams-delta.c +++ b/drivers/mtd/nand/ams-delta.c @@ -23,12 +23,16 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> +#include <linux/gpio.h> +#include <linux/platform_data/gpio-omap.h> + #include <asm/io.h> -#include <mach/hardware.h> #include <asm/sizes.h> -#include <linux/gpio.h> + #include <plat/board-ams-delta.h> +#include <mach/hardware.h> + /* * MTD structure for E3 (Delta) */ diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index ac4fd756eda3..27293e328517 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -101,6 +101,16 @@ #define P4e_s(a) (TF(a & NAND_Ecc_P4e) << 0) #define P4o_s(a) (TF(a & NAND_Ecc_P4o) << 1) +#define PREFETCH_CONFIG1_CS_SHIFT 24 +#define ECC_CONFIG_CS_SHIFT 1 +#define CS_MASK 0x7 +#define ENABLE_PREFETCH (0x1 << 7) +#define DMA_MPU_MODE_SHIFT 2 +#define ECCSIZE1_SHIFT 22 +#define ECC1RESULTSIZE 0x1 +#define ECCCLEAR 0x100 +#define ECC1 0x1 + /* oob info generated runtime depending on ecc algorithm and layout selected */ static struct nand_ecclayout omap_oobinfo; /* Define some generic bad / good block scan pattern which are used @@ -124,15 +134,18 @@ struct omap_nand_info { int gpmc_cs; unsigned long phys_base; + unsigned long mem_size; struct completion comp; struct dma_chan *dma; - int gpmc_irq; + int gpmc_irq_fifo; + int gpmc_irq_count; enum { OMAP_NAND_IO_READ = 0, /* read */ OMAP_NAND_IO_WRITE, /* write */ } iomode; u_char *buf; int buf_len; + struct gpmc_nand_regs reg; #ifdef CONFIG_MTD_NAND_OMAP_BCH struct bch_control *bch; @@ -141,6 +154,63 @@ struct omap_nand_info { }; /** + * omap_prefetch_enable - configures and starts prefetch transfer + * @cs: cs (chip select) number + * @fifo_th: fifo threshold to be used for read/ write + * @dma_mode: dma mode enable (1) or disable (0) + * @u32_count: number of bytes to be transferred + * @is_write: prefetch read(0) or write post(1) mode + */ +static int omap_prefetch_enable(int cs, int fifo_th, int dma_mode, + unsigned int u32_count, int is_write, struct omap_nand_info *info) +{ + u32 val; + + if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX) + return -1; + + if (readl(info->reg.gpmc_prefetch_control)) + return -EBUSY; + + /* Set the amount of bytes to be prefetched */ + writel(u32_count, info->reg.gpmc_prefetch_config2); + + /* Set dma/mpu mode, the prefetch read / post write and + * enable the engine. Set which cs is has requested for. + */ + val = ((cs << PREFETCH_CONFIG1_CS_SHIFT) | + PREFETCH_FIFOTHRESHOLD(fifo_th) | ENABLE_PREFETCH | + (dma_mode << DMA_MPU_MODE_SHIFT) | (0x1 & is_write)); + writel(val, info->reg.gpmc_prefetch_config1); + + /* Start the prefetch engine */ + writel(0x1, info->reg.gpmc_prefetch_control); + + return 0; +} + +/** + * omap_prefetch_reset - disables and stops the prefetch engine + */ +static int omap_prefetch_reset(int cs, struct omap_nand_info *info) +{ + u32 config1; + + /* check if the same module/cs is trying to reset */ + config1 = readl(info->reg.gpmc_prefetch_config1); + if (((config1 >> PREFETCH_CONFIG1_CS_SHIFT) & CS_MASK) != cs) + return -EINVAL; + + /* Stop the PFPW engine */ + writel(0x0, info->reg.gpmc_prefetch_control); + + /* Reset/disable the PFPW engine */ + writel(0x0, info->reg.gpmc_prefetch_config1); + + return 0; +} + +/** * omap_hwcontrol - hardware specific access to control-lines * @mtd: MTD device structure * @cmd: command to device @@ -158,13 +228,13 @@ static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) if (cmd != NAND_CMD_NONE) { if (ctrl & NAND_CLE) - gpmc_nand_write(info->gpmc_cs, GPMC_NAND_COMMAND, cmd); + writeb(cmd, info->reg.gpmc_nand_command); else if (ctrl & NAND_ALE) - gpmc_nand_write(info->gpmc_cs, GPMC_NAND_ADDRESS, cmd); + writeb(cmd, info->reg.gpmc_nand_address); else /* NAND_NCE */ - gpmc_nand_write(info->gpmc_cs, GPMC_NAND_DATA, cmd); + writeb(cmd, info->reg.gpmc_nand_data); } } @@ -198,7 +268,8 @@ static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len) iowrite8(*p++, info->nand.IO_ADDR_W); /* wait until buffer is available for write */ do { - status = gpmc_read_status(GPMC_STATUS_BUFFER); + status = readl(info->reg.gpmc_status) & + GPMC_STATUS_BUFF_EMPTY; } while (!status); } } @@ -235,7 +306,8 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len) iowrite16(*p++, info->nand.IO_ADDR_W); /* wait until buffer is available for write */ do { - status = gpmc_read_status(GPMC_STATUS_BUFFER); + status = readl(info->reg.gpmc_status) & + GPMC_STATUS_BUFF_EMPTY; } while (!status); } } @@ -265,8 +337,8 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len) } /* configure and start prefetch transfer */ - ret = gpmc_prefetch_enable(info->gpmc_cs, - PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x0); + ret = omap_prefetch_enable(info->gpmc_cs, + PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x0, info); if (ret) { /* PFPW engine is busy, use cpu copy method */ if (info->nand.options & NAND_BUSWIDTH_16) @@ -275,14 +347,15 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len) omap_read_buf8(mtd, (u_char *)p, len); } else { do { - r_count = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT); + r_count = readl(info->reg.gpmc_prefetch_status); + r_count = GPMC_PREFETCH_STATUS_FIFO_CNT(r_count); r_count = r_count >> 2; ioread32_rep(info->nand.IO_ADDR_R, p, r_count); p += r_count; len -= r_count << 2; } while (len); /* disable and stop the PFPW engine */ - gpmc_prefetch_reset(info->gpmc_cs); + omap_prefetch_reset(info->gpmc_cs, info); } } @@ -301,6 +374,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd, int i = 0, ret = 0; u16 *p = (u16 *)buf; unsigned long tim, limit; + u32 val; /* take care of subpage writes */ if (len % 2 != 0) { @@ -310,8 +384,8 @@ static void omap_write_buf_pref(struct mtd_info *mtd, } /* configure and start prefetch transfer */ - ret = gpmc_prefetch_enable(info->gpmc_cs, - PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x1); + ret = omap_prefetch_enable(info->gpmc_cs, + PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x1, info); if (ret) { /* PFPW engine is busy, use cpu copy method */ if (info->nand.options & NAND_BUSWIDTH_16) @@ -320,7 +394,8 @@ static void omap_write_buf_pref(struct mtd_info *mtd, omap_write_buf8(mtd, (u_char *)p, len); } else { while (len) { - w_count = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT); + w_count = readl(info->reg.gpmc_prefetch_status); + w_count = GPMC_PREFETCH_STATUS_FIFO_CNT(w_count); w_count = w_count >> 1; for (i = 0; (i < w_count) && len; i++, len -= 2) iowrite16(*p++, info->nand.IO_ADDR_W); @@ -329,11 +404,14 @@ static void omap_write_buf_pref(struct mtd_info *mtd, tim = 0; limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS)); - while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit)) + do { cpu_relax(); + val = readl(info->reg.gpmc_prefetch_status); + val = GPMC_PREFETCH_STATUS_COUNT(val); + } while (val && (tim++ < limit)); /* disable and stop the PFPW engine */ - gpmc_prefetch_reset(info->gpmc_cs); + omap_prefetch_reset(info->gpmc_cs, info); } } @@ -365,6 +443,7 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, unsigned long tim, limit; unsigned n; int ret; + u32 val; if (addr >= high_memory) { struct page *p1; @@ -396,9 +475,9 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, tx->callback_param = &info->comp; dmaengine_submit(tx); - /* configure and start prefetch transfer */ - ret = gpmc_prefetch_enable(info->gpmc_cs, - PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write); + /* configure and start prefetch transfer */ + ret = omap_prefetch_enable(info->gpmc_cs, + PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write, info); if (ret) /* PFPW engine is busy, use cpu copy method */ goto out_copy_unmap; @@ -410,11 +489,15 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, wait_for_completion(&info->comp); tim = 0; limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS)); - while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit)) + + do { cpu_relax(); + val = readl(info->reg.gpmc_prefetch_status); + val = GPMC_PREFETCH_STATUS_COUNT(val); + } while (val && (tim++ < limit)); /* disable and stop the PFPW engine */ - gpmc_prefetch_reset(info->gpmc_cs); + omap_prefetch_reset(info->gpmc_cs, info); dma_unmap_sg(info->dma->device->dev, &sg, 1, dir); return 0; @@ -471,13 +554,12 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev) { struct omap_nand_info *info = (struct omap_nand_info *) dev; u32 bytes; - u32 irq_stat; - irq_stat = gpmc_read_status(GPMC_GET_IRQ_STATUS); - bytes = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT); + bytes = readl(info->reg.gpmc_prefetch_status); + bytes = GPMC_PREFETCH_STATUS_FIFO_CNT(bytes); bytes = bytes & 0xFFFC; /* io in multiple of 4 bytes */ if (info->iomode == OMAP_NAND_IO_WRITE) { /* checks for write io */ - if (irq_stat & 0x2) + if (this_irq == info->gpmc_irq_count) goto done; if (info->buf_len && (info->buf_len < bytes)) @@ -494,20 +576,17 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev) (u32 *)info->buf, bytes >> 2); info->buf = info->buf + bytes; - if (irq_stat & 0x2) + if (this_irq == info->gpmc_irq_count) goto done; } - gpmc_cs_configure(info->gpmc_cs, GPMC_SET_IRQ_STATUS, irq_stat); return IRQ_HANDLED; done: complete(&info->comp); - /* disable irq */ - gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ, 0); - /* clear status */ - gpmc_cs_configure(info->gpmc_cs, GPMC_SET_IRQ_STATUS, irq_stat); + disable_irq_nosync(info->gpmc_irq_fifo); + disable_irq_nosync(info->gpmc_irq_count); return IRQ_HANDLED; } @@ -534,22 +613,22 @@ static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len) init_completion(&info->comp); /* configure and start prefetch transfer */ - ret = gpmc_prefetch_enable(info->gpmc_cs, - PREFETCH_FIFOTHRESHOLD_MAX/2, 0x0, len, 0x0); + ret = omap_prefetch_enable(info->gpmc_cs, + PREFETCH_FIFOTHRESHOLD_MAX/2, 0x0, len, 0x0, info); if (ret) /* PFPW engine is busy, use cpu copy method */ goto out_copy; info->buf_len = len; - /* enable irq */ - gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ, - (GPMC_IRQ_FIFOEVENTENABLE | GPMC_IRQ_COUNT_EVENT)); + + enable_irq(info->gpmc_irq_count); + enable_irq(info->gpmc_irq_fifo); /* waiting for read to complete */ wait_for_completion(&info->comp); /* disable and stop the PFPW engine */ - gpmc_prefetch_reset(info->gpmc_cs); + omap_prefetch_reset(info->gpmc_cs, info); return; out_copy: @@ -572,6 +651,7 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd, struct omap_nand_info, mtd); int ret = 0; unsigned long tim, limit; + u32 val; if (len <= mtd->oobsize) { omap_write_buf_pref(mtd, buf, len); @@ -583,27 +663,31 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd, init_completion(&info->comp); /* configure and start prefetch transfer : size=24 */ - ret = gpmc_prefetch_enable(info->gpmc_cs, - (PREFETCH_FIFOTHRESHOLD_MAX * 3) / 8, 0x0, len, 0x1); + ret = omap_prefetch_enable(info->gpmc_cs, + (PREFETCH_FIFOTHRESHOLD_MAX * 3) / 8, 0x0, len, 0x1, info); if (ret) /* PFPW engine is busy, use cpu copy method */ goto out_copy; info->buf_len = len; - /* enable irq */ - gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ, - (GPMC_IRQ_FIFOEVENTENABLE | GPMC_IRQ_COUNT_EVENT)); + + enable_irq(info->gpmc_irq_count); + enable_irq(info->gpmc_irq_fifo); /* waiting for write to complete */ wait_for_completion(&info->comp); + /* wait for data to flushed-out before reset the prefetch */ tim = 0; limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS)); - while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit)) + do { + val = readl(info->reg.gpmc_prefetch_status); + val = GPMC_PREFETCH_STATUS_COUNT(val); cpu_relax(); + } while (val && (tim++ < limit)); /* disable and stop the PFPW engine */ - gpmc_prefetch_reset(info->gpmc_cs); + omap_prefetch_reset(info->gpmc_cs, info); return; out_copy: @@ -843,7 +927,20 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat, { struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); - return gpmc_calculate_ecc(info->gpmc_cs, dat, ecc_code); + u32 val; + + val = readl(info->reg.gpmc_ecc_config); + if (((val >> ECC_CONFIG_CS_SHIFT) & ~CS_MASK) != info->gpmc_cs) + return -EINVAL; + + /* read ecc result */ + val = readl(info->reg.gpmc_ecc1_result); + *ecc_code++ = val; /* P128e, ..., P1e */ + *ecc_code++ = val >> 16; /* P128o, ..., P1o */ + /* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */ + *ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0); + + return 0; } /** @@ -857,8 +954,34 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode) mtd); struct nand_chip *chip = mtd->priv; unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0; + u32 val; + + /* clear ecc and enable bits */ + val = ECCCLEAR | ECC1; + writel(val, info->reg.gpmc_ecc_control); + + /* program ecc and result sizes */ + val = ((((info->nand.ecc.size >> 1) - 1) << ECCSIZE1_SHIFT) | + ECC1RESULTSIZE); + writel(val, info->reg.gpmc_ecc_size_config); - gpmc_enable_hwecc(info->gpmc_cs, mode, dev_width, info->nand.ecc.size); + switch (mode) { + case NAND_ECC_READ: + case NAND_ECC_WRITE: + writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control); + break; + case NAND_ECC_READSYN: + writel(ECCCLEAR, info->reg.gpmc_ecc_control); + break; + default: + dev_info(&info->pdev->dev, + "error: unrecognized Mode[%d]!\n", mode); + break; + } + + /* (ECC 16 or 8 bit col) | ( CS ) | ECC Enable */ + val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1); + writel(val, info->reg.gpmc_ecc_config); } /** @@ -886,10 +1009,9 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip) else timeo += (HZ * 20) / 1000; - gpmc_nand_write(info->gpmc_cs, - GPMC_NAND_COMMAND, (NAND_CMD_STATUS & 0xFF)); + writeb(NAND_CMD_STATUS & 0xFF, info->reg.gpmc_nand_command); while (time_before(jiffies, timeo)) { - status = gpmc_nand_read(info->gpmc_cs, GPMC_NAND_DATA); + status = readb(info->reg.gpmc_nand_data); if (status & NAND_STATUS_READY) break; cond_resched(); @@ -909,22 +1031,13 @@ static int omap_dev_ready(struct mtd_info *mtd) struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); - val = gpmc_read_status(GPMC_GET_IRQ_STATUS); + val = readl(info->reg.gpmc_status); + if ((val & 0x100) == 0x100) { - /* Clear IRQ Interrupt */ - val |= 0x100; - val &= ~(0x0); - gpmc_cs_configure(info->gpmc_cs, GPMC_SET_IRQ_STATUS, val); + return 1; } else { - unsigned int cnt = 0; - while (cnt++ < 0x1FF) { - if ((val & 0x100) == 0x100) - return 0; - val = gpmc_read_status(GPMC_GET_IRQ_STATUS); - } + return 0; } - - return 1; } #ifdef CONFIG_MTD_NAND_OMAP_BCH @@ -1155,6 +1268,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) int i, offset; dma_cap_mask_t mask; unsigned sig; + struct resource *res; pdata = pdev->dev.platform_data; if (pdata == NULL) { @@ -1174,7 +1288,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) info->pdev = pdev; info->gpmc_cs = pdata->cs; - info->phys_base = pdata->phys_base; + info->reg = pdata->reg; info->mtd.priv = &info->nand; info->mtd.name = dev_name(&pdev->dev); @@ -1183,16 +1297,23 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) info->nand.options = pdata->devsize; info->nand.options |= NAND_SKIP_BBTSCAN; - /* NAND write protect off */ - gpmc_cs_configure(info->gpmc_cs, GPMC_CONFIG_WP, 0); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + err = -EINVAL; + dev_err(&pdev->dev, "error getting memory resource\n"); + goto out_free_info; + } + + info->phys_base = res->start; + info->mem_size = resource_size(res); - if (!request_mem_region(info->phys_base, NAND_IO_SIZE, + if (!request_mem_region(info->phys_base, info->mem_size, pdev->dev.driver->name)) { err = -EBUSY; goto out_free_info; } - info->nand.IO_ADDR_R = ioremap(info->phys_base, NAND_IO_SIZE); + info->nand.IO_ADDR_R = ioremap(info->phys_base, info->mem_size); if (!info->nand.IO_ADDR_R) { err = -ENOMEM; goto out_release_mem_region; @@ -1265,17 +1386,39 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) break; case NAND_OMAP_PREFETCH_IRQ: - err = request_irq(pdata->gpmc_irq, - omap_nand_irq, IRQF_SHARED, "gpmc-nand", info); + info->gpmc_irq_fifo = platform_get_irq(pdev, 0); + if (info->gpmc_irq_fifo <= 0) { + dev_err(&pdev->dev, "error getting fifo irq\n"); + err = -ENODEV; + goto out_release_mem_region; + } + err = request_irq(info->gpmc_irq_fifo, omap_nand_irq, + IRQF_SHARED, "gpmc-nand-fifo", info); if (err) { dev_err(&pdev->dev, "requesting irq(%d) error:%d", - pdata->gpmc_irq, err); + info->gpmc_irq_fifo, err); + info->gpmc_irq_fifo = 0; + goto out_release_mem_region; + } + + info->gpmc_irq_count = platform_get_irq(pdev, 1); + if (info->gpmc_irq_count <= 0) { + dev_err(&pdev->dev, "error getting count irq\n"); + err = -ENODEV; + goto out_release_mem_region; + } + err = request_irq(info->gpmc_irq_count, omap_nand_irq, + IRQF_SHARED, "gpmc-nand-count", info); + if (err) { + dev_err(&pdev->dev, "requesting irq(%d) error:%d", + info->gpmc_irq_count, err); + info->gpmc_irq_count = 0; goto out_release_mem_region; - } else { - info->gpmc_irq = pdata->gpmc_irq; - info->nand.read_buf = omap_read_buf_irq_pref; - info->nand.write_buf = omap_write_buf_irq_pref; } + + info->nand.read_buf = omap_read_buf_irq_pref; + info->nand.write_buf = omap_write_buf_irq_pref; + break; default: @@ -1363,7 +1506,11 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) out_release_mem_region: if (info->dma) dma_release_channel(info->dma); - release_mem_region(info->phys_base, NAND_IO_SIZE); + if (info->gpmc_irq_count > 0) + free_irq(info->gpmc_irq_count, info); + if (info->gpmc_irq_fifo > 0) + free_irq(info->gpmc_irq_fifo, info); + release_mem_region(info->phys_base, info->mem_size); out_free_info: kfree(info); @@ -1381,8 +1528,10 @@ static int omap_nand_remove(struct platform_device *pdev) if (info->dma) dma_release_channel(info->dma); - if (info->gpmc_irq) - free_irq(info->gpmc_irq, info); + if (info->gpmc_irq_count > 0) + free_irq(info->gpmc_irq_count, info); + if (info->gpmc_irq_fifo > 0) + free_irq(info->gpmc_irq_fifo, info); /* Release NAND device, its internal structures and partitions */ nand_release(&info->mtd); diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index 398a82783848..9d49b1f4ff53 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -43,18 +43,17 @@ #include <asm/gpio.h> #include <plat/dma.h> - -#include <plat/board.h> +#include <plat/cpu.h> #define DRIVER_NAME "omap2-onenand" -#define ONENAND_IO_SIZE SZ_128K #define ONENAND_BUFRAM_SIZE (1024 * 5) struct omap2_onenand { struct platform_device *pdev; int gpmc_cs; unsigned long phys_base; + unsigned int mem_size; int gpio_irq; struct mtd_info mtd; struct onenand_chip onenand; @@ -626,6 +625,7 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) struct omap2_onenand *c; struct onenand_chip *this; int r; + struct resource *res; pdata = pdev->dev.platform_data; if (pdata == NULL) { @@ -647,20 +647,24 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) c->gpio_irq = 0; } - r = gpmc_cs_request(c->gpmc_cs, ONENAND_IO_SIZE, &c->phys_base); - if (r < 0) { - dev_err(&pdev->dev, "Cannot request GPMC CS\n"); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + r = -EINVAL; + dev_err(&pdev->dev, "error getting memory resource\n"); goto err_kfree; } - if (request_mem_region(c->phys_base, ONENAND_IO_SIZE, + c->phys_base = res->start; + c->mem_size = resource_size(res); + + if (request_mem_region(c->phys_base, c->mem_size, pdev->dev.driver->name) == NULL) { - dev_err(&pdev->dev, "Cannot reserve memory region at 0x%08lx, " - "size: 0x%x\n", c->phys_base, ONENAND_IO_SIZE); + dev_err(&pdev->dev, "Cannot reserve memory region at 0x%08lx, size: 0x%x\n", + c->phys_base, c->mem_size); r = -EBUSY; - goto err_free_cs; + goto err_kfree; } - c->onenand.base = ioremap(c->phys_base, ONENAND_IO_SIZE); + c->onenand.base = ioremap(c->phys_base, c->mem_size); if (c->onenand.base == NULL) { r = -ENOMEM; goto err_release_mem_region; @@ -776,9 +780,7 @@ err_release_gpio: err_iounmap: iounmap(c->onenand.base); err_release_mem_region: - release_mem_region(c->phys_base, ONENAND_IO_SIZE); -err_free_cs: - gpmc_cs_free(c->gpmc_cs); + release_mem_region(c->phys_base, c->mem_size); err_kfree: kfree(c); @@ -800,7 +802,7 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev) gpio_free(c->gpio_irq); } iounmap(c->onenand.base); - release_mem_region(c->phys_base, ONENAND_IO_SIZE); + release_mem_region(c->phys_base, c->mem_size); gpmc_cs_free(c->gpmc_cs); kfree(c); diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c index b5ba3084c7fc..3e5519a0acc7 100644 --- a/drivers/net/ethernet/sgi/ioc3-eth.c +++ b/drivers/net/ethernet/sgi/ioc3-eth.c @@ -1147,15 +1147,17 @@ static void __devinit ioc3_8250_register(struct ioc3_uartregs __iomem *uart) { #define COSMISC_CONSTANT 6 - struct uart_port port = { - .irq = 0, - .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, - .iotype = UPIO_MEM, - .regshift = 0, - .uartclk = (22000000 << 1) / COSMISC_CONSTANT, - - .membase = (unsigned char __iomem *) uart, - .mapbase = (unsigned long) uart, + struct uart_8250_port port = { + .port = { + .irq = 0, + .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, + .iotype = UPIO_MEM, + .regshift = 0, + .uartclk = (22000000 << 1) / COSMISC_CONSTANT, + + .membase = (unsigned char __iomem *) uart, + .mapbase = (unsigned long) uart, + } }; unsigned char lcr; @@ -1164,7 +1166,7 @@ static void __devinit ioc3_8250_register(struct ioc3_uartregs __iomem *uart) uart->iu_scr = COSMISC_CONSTANT, uart->iu_lcr = lcr; uart->iu_lcr; - serial8250_register_port(&port); + serial8250_register_8250_port(&port); } static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3) diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c index 3352b2443e58..30087ca23a0f 100644 --- a/drivers/net/irda/irtty-sir.c +++ b/drivers/net/irda/irtty-sir.c @@ -124,8 +124,8 @@ static int irtty_change_speed(struct sir_dev *dev, unsigned speed) tty = priv->tty; mutex_lock(&tty->termios_mutex); - old_termios = *(tty->termios); - cflag = tty->termios->c_cflag; + old_termios = tty->termios; + cflag = tty->termios.c_cflag; tty_encode_baud_rate(tty, speed, speed); if (tty->ops->set_termios) tty->ops->set_termios(tty, &old_termios); @@ -281,15 +281,15 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop) int cflag; mutex_lock(&tty->termios_mutex); - old_termios = *(tty->termios); - cflag = tty->termios->c_cflag; + old_termios = tty->termios; + cflag = tty->termios.c_cflag; if (stop) cflag &= ~CREAD; else cflag |= CREAD; - tty->termios->c_cflag = cflag; + tty->termios.c_cflag = cflag; if (tty->ops->set_termios) tty->ops->set_termios(tty, &old_termios); mutex_unlock(&tty->termios_mutex); diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 62f30b46fa42..605a4baa9b7b 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -1107,7 +1107,6 @@ static void _hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) { struct hso_serial *serial = tty->driver_data; - struct ktermios *termios; if (!serial) { printk(KERN_ERR "%s: no tty structures", __func__); @@ -1119,16 +1118,15 @@ static void _hso_serial_set_termios(struct tty_struct *tty, /* * Fix up unsupported bits */ - termios = tty->termios; - termios->c_iflag &= ~IXON; /* disable enable XON/XOFF flow control */ + tty->termios.c_iflag &= ~IXON; /* disable enable XON/XOFF flow control */ - termios->c_cflag &= + tty->termios.c_cflag &= ~(CSIZE /* no size */ | PARENB /* disable parity bit */ | CBAUD /* clear current baud rate */ | CBAUDEX); /* clear current buad rate */ - termios->c_cflag |= CS8; /* character size 8 bits */ + tty->termios.c_cflag |= CS8; /* character size 8 bits */ /* baud rate 115200 */ tty_encode_baud_rate(tty, 115200, 115200); @@ -1425,14 +1423,14 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) if (old) D5("Termios called with: cflags new[%d] - old[%d]", - tty->termios->c_cflag, old->c_cflag); + tty->termios.c_cflag, old->c_cflag); /* the actual setup */ spin_lock_irqsave(&serial->serial_lock, flags); if (serial->port.count) _hso_serial_set_termios(tty, old); else - tty->termios = old; + tty->termios = *old; spin_unlock_irqrestore(&serial->serial_lock, flags); /* done */ @@ -2289,9 +2287,11 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs, if (minor < 0) goto exit; + tty_port_init(&serial->port); + /* register our minor number */ - serial->parent->dev = tty_register_device(tty_drv, minor, - &serial->parent->interface->dev); + serial->parent->dev = tty_port_register_device(&serial->port, tty_drv, + minor, &serial->parent->interface->dev); dev = serial->parent->dev; dev_set_drvdata(dev, serial->parent); i = device_create_file(dev, &dev_attr_hsotype); @@ -2300,7 +2300,6 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs, serial->minor = minor; serial->magic = HSO_SERIAL_MAGIC; spin_lock_init(&serial->serial_lock); - tty_port_init(&serial->port); serial->num_rx_urbs = num_urbs; /* RX, allocate urb and initialize */ diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c index 5d6de380e42b..352f96180bc7 100644 --- a/drivers/parport/parport_gsc.c +++ b/drivers/parport/parport_gsc.c @@ -271,6 +271,7 @@ struct parport *__devinit parport_gsc_probe_port (unsigned long base, if (!parport_SPP_supported (p)) { /* No port. */ kfree (priv); + kfree(ops); return NULL; } parport_PS2_supported (p); diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c index e9c32274df3f..1631eeaf440e 100644 --- a/drivers/parport/parport_serial.c +++ b/drivers/parport/parport_serial.c @@ -62,6 +62,7 @@ enum parport_pc_pci_cards { timedia_9079a, timedia_9079b, timedia_9079c, + wch_ch353_2s1p, }; /* each element directly indexed from enum list, above */ @@ -145,6 +146,7 @@ static struct parport_pc_pci cards[] __devinitdata = { /* timedia_9079a */ { 1, { { 2, 3 }, } }, /* timedia_9079b */ { 1, { { 2, 3 }, } }, /* timedia_9079c */ { 1, { { 2, 3 }, } }, + /* wch_ch353_2s1p*/ { 1, { { 2, -1}, } }, }; static struct pci_device_id parport_serial_pci_tbl[] = { @@ -243,7 +245,8 @@ static struct pci_device_id parport_serial_pci_tbl[] = { { 0x1409, 0x7168, 0x1409, 0xb079, 0, 0, timedia_9079a }, { 0x1409, 0x7168, 0x1409, 0xc079, 0, 0, timedia_9079b }, { 0x1409, 0x7168, 0x1409, 0xd079, 0, 0, timedia_9079c }, - + /* WCH CARDS */ + { 0x4348, 0x7053, 0x4348, 0x3253, 0, 0, wch_ch353_2s1p}, { 0, } /* terminate list */ }; MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl); @@ -460,6 +463,12 @@ static struct pciserial_board pci_parport_serial_boards[] __devinitdata = { .base_baud = 921600, .uart_offset = 8, }, + [wch_ch353_2s1p] = { + .flags = FL_BASE0|FL_BASE_BARS, + .num_ports = 2, + .base_baud = 115200, + .uart_offset = 8, + }, }; struct parport_serial_private { diff --git a/drivers/power/avs/smartreflex.c b/drivers/power/avs/smartreflex.c index 44efc6e202af..d4957b4edb62 100644 --- a/drivers/power/avs/smartreflex.c +++ b/drivers/power/avs/smartreflex.c @@ -27,6 +27,8 @@ #include <linux/pm_runtime.h> #include <linux/power/smartreflex.h> +#include <plat/cpu.h> + #define SMARTREFLEX_NAME_LEN 16 #define NVALUE_NAME_LEN 40 #define SR_DISABLE_TIMEOUT 200 diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 6c0116d48c74..9ffb6d5f17aa 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -716,10 +716,17 @@ static int raw3215_probe (struct ccw_device *cdev) static void raw3215_remove (struct ccw_device *cdev) { struct raw3215_info *raw; + unsigned int line; ccw_device_set_offline(cdev); raw = dev_get_drvdata(&cdev->dev); if (raw) { + spin_lock(&raw3215_device_lock); + for (line = 0; line < NR_3215; line++) + if (raw3215[line] == raw) + break; + raw3215[line] = NULL; + spin_unlock(&raw3215_device_lock); dev_set_drvdata(&cdev->dev, NULL); raw3215_free_info(raw); } @@ -935,6 +942,19 @@ static int __init con3215_init(void) console_initcall(con3215_init); #endif +static int tty3215_install(struct tty_driver *driver, struct tty_struct *tty) +{ + struct raw3215_info *raw; + + raw = raw3215[tty->index]; + if (raw == NULL) + return -ENODEV; + + tty->driver_data = raw; + + return tty_port_install(&raw->port, driver, tty); +} + /* * tty3215_open * @@ -942,14 +962,9 @@ console_initcall(con3215_init); */ static int tty3215_open(struct tty_struct *tty, struct file * filp) { - struct raw3215_info *raw; + struct raw3215_info *raw = tty->driver_data; int retval; - raw = raw3215[tty->index]; - if (raw == NULL) - return -ENODEV; - - tty->driver_data = raw; tty_port_tty_set(&raw->port, tty); tty->low_latency = 0; /* don't use bottom half for pushing chars */ @@ -1110,6 +1125,7 @@ static void tty3215_start(struct tty_struct *tty) } static const struct tty_operations tty3215_ops = { + .install = tty3215_install, .open = tty3215_open, .close = tty3215_close, .write = tty3215_write, diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index 0792c85baafe..30ec09e3d037 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -567,6 +567,7 @@ sclp_tty_init(void) driver->init_termios.c_lflag = ISIG | ECHO; driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(driver, &sclp_ops); + tty_port_link_device(&sclp_port, driver, 0); rc = tty_register_driver(driver); if (rc) { put_tty_driver(driver); diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index edfc0fd73dc6..7e60f3d2f3f9 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -691,6 +691,7 @@ static int __init sclp_vt220_tty_init(void) driver->init_termios = tty_std_termios; driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(driver, &sclp_vt220_ops); + tty_port_link_device(&sclp_vt220_port, driver, 0); rc = tty_register_driver(driver); if (rc) diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 1928f3458d10..482ee028f842 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -842,17 +842,14 @@ static struct raw3270_fn tty3270_fn = { }; /* - * This routine is called whenever a 3270 tty is opened. + * This routine is called whenever a 3270 tty is opened first time. */ -static int -tty3270_open(struct tty_struct *tty, struct file * filp) +static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty) { struct raw3270_view *view; struct tty3270 *tp; int i, rc; - if (tty->count > 1) - return 0; /* Check if the tty3270 is already there. */ view = raw3270_find_view(&tty3270_fn, tty->index + RAW3270_FIRSTMINOR); @@ -865,7 +862,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp) /* why to reassign? */ tty_port_tty_set(&tp->port, tty); tp->inattr = TF_INPUT; - return 0; + return tty_port_install(&tp->port, driver, tty); } if (tty3270_max_index < tty->index + 1) tty3270_max_index = tty->index + 1; @@ -895,7 +892,6 @@ tty3270_open(struct tty_struct *tty, struct file * filp) tty_port_tty_set(&tp->port, tty); tty->low_latency = 0; - tty->driver_data = tp; tty->winsize.ws_row = tp->view.rows - 2; tty->winsize.ws_col = tp->view.cols; @@ -915,6 +911,15 @@ tty3270_open(struct tty_struct *tty, struct file * filp) kbd_ascebc(tp->kbd, tp->view.ascebc); raw3270_activate_view(&tp->view); + + rc = tty_port_install(&tp->port, driver, tty); + if (rc) { + raw3270_put_view(&tp->view); + return rc; + } + + tty->driver_data = tp; + return 0; } @@ -932,10 +937,17 @@ tty3270_close(struct tty_struct *tty, struct file * filp) if (tp) { tty->driver_data = NULL; tty_port_tty_set(&tp->port, NULL); - raw3270_put_view(&tp->view); } } +static void tty3270_cleanup(struct tty_struct *tty) +{ + struct tty3270 *tp = tty->driver_data; + + if (tp) + raw3270_put_view(&tp->view); +} + /* * We always have room. */ @@ -1737,7 +1749,8 @@ static long tty3270_compat_ioctl(struct tty_struct *tty, #endif static const struct tty_operations tty3270_ops = { - .open = tty3270_open, + .install = tty3270_install, + .cleanup = tty3270_cleanup, .close = tty3270_close, .write = tty3270_write, .put_char = tty3270_put_char, @@ -1781,7 +1794,7 @@ static int __init tty3270_init(void) driver->type = TTY_DRIVER_TYPE_SYSTEM; driver->subtype = SYSTEM_TYPE_TTY; driver->init_termios = tty_std_termios; - driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_DYNAMIC_DEV; + driver->flags = TTY_DRIVER_RESET_TERMIOS; tty_set_operations(driver, &tty3270_ops); ret = tty_register_driver(driver); if (ret) { @@ -1800,6 +1813,7 @@ tty3270_exit(void) driver = tty3270_driver; tty3270_driver = NULL; tty_unregister_driver(driver); + put_tty_driver(driver); tty3270_del_views(); } diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c index 9b0d71696039..a3996a1c6345 100644 --- a/drivers/spi/spi-omap-uwire.c +++ b/drivers/spi/spi-omap-uwire.c @@ -53,7 +53,8 @@ #include <asm/mach-types.h> #include <plat/mux.h> -#include <plat/omap7xx.h> /* OMAP7XX_IO_CONF registers */ + +#include <mach/omap7xx.h> /* OMAP7XX_IO_CONF registers */ /* FIXME address is now a platform device resource, diff --git a/drivers/staging/ipack/devices/ipoctal.c b/drivers/staging/ipack/devices/ipoctal.c index fd0e30132ca2..a68d981c259f 100644 --- a/drivers/staging/ipack/devices/ipoctal.c +++ b/drivers/staging/ipack/devices/ipoctal.c @@ -502,7 +502,7 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr, ipoctal->pointer_read[i] = 0; ipoctal->pointer_write[i] = 0; ipoctal->nb_bytes[i] = 0; - tty_register_device(tty, i, NULL); + tty_port_register_device(&ipoctal->tty_port[i], tty, i, NULL); /* * Enable again the RX. TX will be enabled when @@ -617,7 +617,7 @@ static void ipoctal_set_termios(struct tty_struct *tty, struct ipoctal *ipoctal = tty->driver_data; speed_t baud; - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; /* Disable and reset everything before change the setup */ ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, @@ -643,7 +643,7 @@ static void ipoctal_set_termios(struct tty_struct *tty, default: mr1 |= MR1_CHRL_8_BITS; /* By default, select CS8 */ - tty->termios->c_cflag = (cflag & ~CSIZE) | CS8; + tty->termios.c_cflag = (cflag & ~CSIZE) | CS8; break; } @@ -657,7 +657,7 @@ static void ipoctal_set_termios(struct tty_struct *tty, mr1 |= MR1_PARITY_OFF; /* Mark or space parity is not supported */ - tty->termios->c_cflag &= ~CMSPAR; + tty->termios.c_cflag &= ~CMSPAR; /* Set stop bits */ if (cflag & CSTOPB) @@ -690,10 +690,10 @@ static void ipoctal_set_termios(struct tty_struct *tty, } baud = tty_get_baud_rate(tty); - tty_termios_encode_baud_rate(tty->termios, baud, baud); + tty_termios_encode_baud_rate(&tty->termios, baud, baud); /* Set baud rate */ - switch (tty->termios->c_ospeed) { + switch (baud) { case 75: csr |= TX_CLK_75 | RX_CLK_75; break; @@ -734,7 +734,7 @@ static void ipoctal_set_termios(struct tty_struct *tty, default: csr |= TX_CLK_38400 | RX_CLK_38400; /* In case of default, we establish 38400 bps */ - tty_termios_encode_baud_rate(tty->termios, 38400, 38400); + tty_termios_encode_baud_rate(&tty->termios, 38400, 38400); break; } diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c index 8a362f7af379..c90de969be8f 100644 --- a/drivers/staging/serqt_usb2/serqt_usb2.c +++ b/drivers/staging/serqt_usb2/serqt_usb2.c @@ -315,10 +315,8 @@ static void qt_read_bulk_callback(struct urb *urb) } tty = tty_port_tty_get(&port->port); - if (!tty) { - dbg("%s - bad tty pointer - exiting", __func__); + if (!tty) return; - } data = urb->transfer_buffer; @@ -364,7 +362,7 @@ static void qt_read_bulk_callback(struct urb *urb) goto exit; } - if (tty && RxCount) { + if (RxCount) { flag_data = 0; for (i = 0; i < RxCount; ++i) { /* Look ahead code here */ @@ -428,7 +426,7 @@ static void qt_read_bulk_callback(struct urb *urb) dbg("%s - failed resubmitting read urb, error %d", __func__, result); else { - if (tty && RxCount) { + if (RxCount) { tty_flip_buffer_push(tty); tty_schedule_flip(tty); } @@ -897,8 +895,6 @@ static int qt_open(struct tty_struct *tty, * Put this here to make it responsive to stty and defaults set by * the tty layer */ - /* FIXME: is this needed? */ - /* qt_set_termios(tty, port, NULL); */ /* Check to see if we've set up our endpoint info yet */ if (port0->open_ports == 1) { @@ -1195,7 +1191,7 @@ static void qt_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; unsigned char new_LCR = 0; unsigned int cflag = termios->c_cflag; unsigned int index; @@ -1204,7 +1200,7 @@ static void qt_set_termios(struct tty_struct *tty, index = tty->index - port->serial->minor; - switch (cflag) { + switch (cflag & CSIZE) { case CS5: new_LCR |= SERIAL_5_DATA; break; @@ -1215,6 +1211,8 @@ static void qt_set_termios(struct tty_struct *tty, new_LCR |= SERIAL_7_DATA; break; default: + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= CS8; case CS8: new_LCR |= SERIAL_8_DATA; break; @@ -1301,7 +1299,7 @@ static void qt_set_termios(struct tty_struct *tty, dbg(__FILE__ "BoxSetSW_FlowCtrl (diabling) failed\n"); } - tty->termios->c_cflag &= ~CMSPAR; + termios->c_cflag &= ~CMSPAR; /* FIXME: Error cases should be returning the actual bits changed only */ } diff --git a/drivers/staging/speakup/serialio.h b/drivers/staging/speakup/serialio.h index 614271f9b99f..55d68b5ad165 100644 --- a/drivers/staging/speakup/serialio.h +++ b/drivers/staging/speakup/serialio.h @@ -1,8 +1,7 @@ #ifndef _SPEAKUP_SERIAL_H #define _SPEAKUP_SERIAL_H -#include <linux/serial.h> /* for rs_table, serial constants & - serial_uart_config */ +#include <linux/serial.h> /* for rs_table, serial constants */ #include <linux/serial_reg.h> /* for more serial constants */ #ifndef __sparc__ #include <asm/serial.h> diff --git a/drivers/staging/tidspbridge/core/wdt.c b/drivers/staging/tidspbridge/core/wdt.c index 870f934f4f3b..453ef748bf45 100644 --- a/drivers/staging/tidspbridge/core/wdt.c +++ b/drivers/staging/tidspbridge/core/wdt.c @@ -25,7 +25,7 @@ #include <dspbridge/host_os.h> -#define OMAP34XX_WDT3_BASE (L4_PER_34XX_BASE + 0x30000) +#define INT_34XX_WDT3_IRQ (36 + NR_IRQS) static struct dsp_wdt_setting dsp_wdt; diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 6cc4358f68c1..42d0a2581a87 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -420,7 +420,7 @@ static void check_modem_status(struct serial_state *info) tty_hangup(port->tty); } } - if (port->flags & ASYNC_CTS_FLOW) { + if (tty_port_cts_enabled(port)) { if (port->tty->hw_stopped) { if (!(status & SER_CTS)) { #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) @@ -646,7 +646,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info) custom.adkcon = AC_UARTBRK; mb(); - if (tty->termios->c_cflag & HUPCL) + if (tty->termios.c_cflag & HUPCL) info->MCR &= ~(SER_DTR|SER_RTS); rtsdtr_ctrl(info->MCR); @@ -670,7 +670,7 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info, int bits; unsigned long flags; - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; /* Byte size is always 8 bits plus parity bit if requested */ @@ -707,8 +707,8 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info, /* If the quotient is zero refuse the change */ if (!quot && old_termios) { /* FIXME: Will need updating for new tty in the end */ - tty->termios->c_cflag &= ~CBAUD; - tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); + tty->termios.c_cflag &= ~CBAUD; + tty->termios.c_cflag |= (old_termios->c_cflag & CBAUD); baud = tty_get_baud_rate(tty); if (!baud) baud = 9600; @@ -984,7 +984,7 @@ static void rs_throttle(struct tty_struct * tty) if (I_IXOFF(tty)) rs_send_xchar(tty, STOP_CHAR(tty)); - if (tty->termios->c_cflag & CRTSCTS) + if (tty->termios.c_cflag & CRTSCTS) info->MCR &= ~SER_RTS; local_irq_save(flags); @@ -1012,7 +1012,7 @@ static void rs_unthrottle(struct tty_struct * tty) else rs_send_xchar(tty, START_CHAR(tty)); } - if (tty->termios->c_cflag & CRTSCTS) + if (tty->termios.c_cflag & CRTSCTS) info->MCR |= SER_RTS; local_irq_save(flags); rtsdtr_ctrl(info->MCR); @@ -1033,7 +1033,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state, if (!retinfo) return -EFAULT; memset(&tmp, 0, sizeof(tmp)); - tty_lock(); + tty_lock(tty); tmp.line = tty->index; tmp.port = state->port; tmp.flags = state->tport.flags; @@ -1042,7 +1042,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state, tmp.close_delay = state->tport.close_delay; tmp.closing_wait = state->tport.closing_wait; tmp.custom_divisor = state->custom_divisor; - tty_unlock(); + tty_unlock(tty); if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) return -EFAULT; return 0; @@ -1059,12 +1059,12 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) return -EFAULT; - tty_lock(); + tty_lock(tty); change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) || new_serial.custom_divisor != state->custom_divisor; if (new_serial.irq || new_serial.port != state->port || new_serial.xmit_fifo_size != state->xmit_fifo_size) { - tty_unlock(); + tty_unlock(tty); return -EINVAL; } @@ -1074,7 +1074,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, (new_serial.xmit_fifo_size != state->xmit_fifo_size) || ((new_serial.flags & ~ASYNC_USR_MASK) != (port->flags & ~ASYNC_USR_MASK))) { - tty_unlock(); + tty_unlock(tty); return -EPERM; } port->flags = ((port->flags & ~ASYNC_USR_MASK) | @@ -1084,7 +1084,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, } if (new_serial.baud_base < 9600) { - tty_unlock(); + tty_unlock(tty); return -EINVAL; } @@ -1116,7 +1116,7 @@ check_and_exit: } } else retval = startup(tty, state); - tty_unlock(); + tty_unlock(tty); return retval; } @@ -1330,7 +1330,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct serial_state *info = tty->driver_data; unsigned long flags; - unsigned int cflag = tty->termios->c_cflag; + unsigned int cflag = tty->termios.c_cflag; change_speed(tty, info, old_termios); @@ -1347,7 +1347,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { info->MCR |= SER_DTR; - if (!(tty->termios->c_cflag & CRTSCTS) || + if (!(tty->termios.c_cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) { info->MCR |= SER_RTS; } @@ -1358,7 +1358,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) /* Handle turning off CRTSCTS */ if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { + !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; rs_start(tty); } @@ -1371,7 +1371,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) * or not. Hence, this may change..... */ if (!(old_termios->c_cflag & CLOCAL) && - (tty->termios->c_cflag & CLOCAL)) + (tty->termios.c_cflag & CLOCAL)) wake_up_interruptible(&info->open_wait); #endif } @@ -1710,10 +1710,6 @@ static int __init amiga_serial_probe(struct platform_device *pdev) serial_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(serial_driver, &serial_ops); - error = tty_register_driver(serial_driver); - if (error) - goto fail_put_tty_driver; - state = rs_table; state->port = (int)&custom.serdatr; /* Just to give it a value */ state->custom_divisor = 0; @@ -1724,6 +1720,11 @@ static int __init amiga_serial_probe(struct platform_device *pdev) state->icount.overrun = state->icount.brk = 0; tty_port_init(&state->tport); state->tport.ops = &amiga_port_ops; + tty_port_link_device(&state->tport, serial_driver, 0); + + error = tty_register_driver(serial_driver); + if (error) + goto fail_put_tty_driver; printk(KERN_INFO "ttyS0 is the amiga builtin serial port\n"); diff --git a/drivers/tty/bfin_jtag_comm.c b/drivers/tty/bfin_jtag_comm.c index 61fc74fe1747..02b7d3a09696 100644 --- a/drivers/tty/bfin_jtag_comm.c +++ b/drivers/tty/bfin_jtag_comm.c @@ -263,6 +263,7 @@ static int __init bfin_jc_init(void) bfin_jc_driver->subtype = SERIAL_TYPE_NORMAL; bfin_jc_driver->init_termios = tty_std_termios; tty_set_operations(bfin_jc_driver, &bfin_jc_ops); + tty_port_link_device(&port, bfin_jc_driver, 0); ret = tty_register_driver(bfin_jc_driver); if (ret) diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index e61cabdd69df..0a6a0bc1b598 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -727,7 +727,7 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip, else tty_hangup(tty); } - if ((mdm_change & CyCTS) && (info->port.flags & ASYNC_CTS_FLOW)) { + if ((mdm_change & CyCTS) && tty_port_cts_enabled(&info->port)) { if (tty->hw_stopped) { if (mdm_status & CyCTS) { /* cy_start isn't used @@ -1459,7 +1459,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty) info->port.xmit_buf = NULL; free_page((unsigned long)temp); } - if (tty->termios->c_cflag & HUPCL) + if (tty->termios.c_cflag & HUPCL) cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR); cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR); @@ -1488,7 +1488,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty) free_page((unsigned long)temp); } - if (tty->termios->c_cflag & HUPCL) + if (tty->termios.c_cflag & HUPCL) tty_port_lower_dtr_rts(&info->port); set_bit(TTY_IO_ERROR, &tty->flags); @@ -1599,7 +1599,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp) * If the port is the middle of closing, bail out now */ if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) { - wait_event_interruptible_tty(info->port.close_wait, + wait_event_interruptible_tty(tty, info->port.close_wait, !(info->port.flags & ASYNC_CLOSING)); return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS; } @@ -1999,14 +1999,11 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty) int baud, baud_rate = 0; int i; - if (!tty->termios) /* XXX can this happen at all? */ - return; - if (info->line == -1) return; - cflag = tty->termios->c_cflag; - iflag = tty->termios->c_iflag; + cflag = tty->termios.c_cflag; + iflag = tty->termios.c_iflag; /* * Set up the tty->alt_speed kludge @@ -2825,7 +2822,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios) cy_set_line_char(info, tty); if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { + !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; cy_start(tty); } @@ -2837,7 +2834,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios) * or not. Hence, this may change..... */ if (!(old_termios->c_cflag & CLOCAL) && - (tty->termios->c_cflag & CLOCAL)) + (tty->termios.c_cflag & CLOCAL)) wake_up_interruptible(&info->port.open_wait); #endif } /* cy_set_termios */ @@ -2899,7 +2896,7 @@ static void cy_throttle(struct tty_struct *tty) info->throttle = 1; } - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { if (!cy_is_Z(card)) { spin_lock_irqsave(&card->card_lock, flags); cyy_change_rts_dtr(info, 0, TIOCM_RTS); @@ -2938,7 +2935,7 @@ static void cy_unthrottle(struct tty_struct *tty) cy_send_xchar(tty, START_CHAR(tty)); } - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { card = info->card; if (!cy_is_Z(card)) { spin_lock_irqsave(&card->card_lock, flags); @@ -3289,9 +3286,10 @@ static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr, static int __init cy_detect_isa(void) { #ifdef CONFIG_ISA + struct cyclades_card *card; unsigned short cy_isa_irq, nboard; void __iomem *cy_isa_address; - unsigned short i, j, cy_isa_nchan; + unsigned short i, j, k, cy_isa_nchan; int isparam = 0; nboard = 0; @@ -3349,7 +3347,8 @@ static int __init cy_detect_isa(void) } /* fill the next cy_card structure available */ for (j = 0; j < NR_CARDS; j++) { - if (cy_card[j].base_addr == NULL) + card = &cy_card[j]; + if (card->base_addr == NULL) break; } if (j == NR_CARDS) { /* no more cy_cards available */ @@ -3363,7 +3362,7 @@ static int __init cy_detect_isa(void) /* allocate IRQ */ if (request_irq(cy_isa_irq, cyy_interrupt, - 0, "Cyclom-Y", &cy_card[j])) { + 0, "Cyclom-Y", card)) { printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but " "could not allocate IRQ#%d.\n", (unsigned long)cy_isa_address, cy_isa_irq); @@ -3372,16 +3371,16 @@ static int __init cy_detect_isa(void) } /* set cy_card */ - cy_card[j].base_addr = cy_isa_address; - cy_card[j].ctl_addr.p9050 = NULL; - cy_card[j].irq = (int)cy_isa_irq; - cy_card[j].bus_index = 0; - cy_card[j].first_line = cy_next_channel; - cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP; - cy_card[j].nports = cy_isa_nchan; - if (cy_init_card(&cy_card[j])) { - cy_card[j].base_addr = NULL; - free_irq(cy_isa_irq, &cy_card[j]); + card->base_addr = cy_isa_address; + card->ctl_addr.p9050 = NULL; + card->irq = (int)cy_isa_irq; + card->bus_index = 0; + card->first_line = cy_next_channel; + card->num_chips = cy_isa_nchan / CyPORTS_PER_CHIP; + card->nports = cy_isa_nchan; + if (cy_init_card(card)) { + card->base_addr = NULL; + free_irq(cy_isa_irq, card); iounmap(cy_isa_address); continue; } @@ -3393,9 +3392,10 @@ static int __init cy_detect_isa(void) (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)), cy_isa_irq, cy_isa_nchan, cy_next_channel); - for (j = cy_next_channel; - j < cy_next_channel + cy_isa_nchan; j++) - tty_register_device(cy_serial_driver, j, NULL); + for (k = 0, j = cy_next_channel; + j < cy_next_channel + cy_isa_nchan; j++, k++) + tty_port_register_device(&card->ports[k].port, + cy_serial_driver, j, NULL); cy_next_channel += cy_isa_nchan; } return nboard; @@ -3695,10 +3695,11 @@ err: static int __devinit cy_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { + struct cyclades_card *card; void __iomem *addr0 = NULL, *addr2 = NULL; char *card_name = NULL; u32 uninitialized_var(mailbox); - unsigned int device_id, nchan = 0, card_no, i; + unsigned int device_id, nchan = 0, card_no, i, j; unsigned char plx_ver; int retval, irq; @@ -3829,7 +3830,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, } /* fill the next cy_card structure available */ for (card_no = 0; card_no < NR_CARDS; card_no++) { - if (cy_card[card_no].base_addr == NULL) + card = &cy_card[card_no]; + if (card->base_addr == NULL) break; } if (card_no == NR_CARDS) { /* no more cy_cards available */ @@ -3843,27 +3845,26 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { /* allocate IRQ */ retval = request_irq(irq, cyy_interrupt, - IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]); + IRQF_SHARED, "Cyclom-Y", card); if (retval) { dev_err(&pdev->dev, "could not allocate IRQ\n"); goto err_unmap; } - cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP; + card->num_chips = nchan / CyPORTS_PER_CHIP; } else { struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS; struct ZFW_CTRL __iomem *zfw_ctrl; zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff); - cy_card[card_no].hw_ver = mailbox; - cy_card[card_no].num_chips = (unsigned int)-1; - cy_card[card_no].board_ctrl = &zfw_ctrl->board_ctrl; + card->hw_ver = mailbox; + card->num_chips = (unsigned int)-1; + card->board_ctrl = &zfw_ctrl->board_ctrl; #ifdef CONFIG_CYZ_INTR /* allocate IRQ only if board has an IRQ */ if (irq != 0 && irq != 255) { retval = request_irq(irq, cyz_interrupt, - IRQF_SHARED, "Cyclades-Z", - &cy_card[card_no]); + IRQF_SHARED, "Cyclades-Z", card); if (retval) { dev_err(&pdev->dev, "could not allocate IRQ\n"); goto err_unmap; @@ -3873,17 +3874,17 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, } /* set cy_card */ - cy_card[card_no].base_addr = addr2; - cy_card[card_no].ctl_addr.p9050 = addr0; - cy_card[card_no].irq = irq; - cy_card[card_no].bus_index = 1; - cy_card[card_no].first_line = cy_next_channel; - cy_card[card_no].nports = nchan; - retval = cy_init_card(&cy_card[card_no]); + card->base_addr = addr2; + card->ctl_addr.p9050 = addr0; + card->irq = irq; + card->bus_index = 1; + card->first_line = cy_next_channel; + card->nports = nchan; + retval = cy_init_card(card); if (retval) goto err_null; - pci_set_drvdata(pdev, &cy_card[card_no]); + pci_set_drvdata(pdev, card); if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo || device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { @@ -3909,14 +3910,15 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from " "port %d.\n", card_name, card_no + 1, nchan, cy_next_channel); - for (i = cy_next_channel; i < cy_next_channel + nchan; i++) - tty_register_device(cy_serial_driver, i, &pdev->dev); + for (j = 0, i = cy_next_channel; i < cy_next_channel + nchan; i++, j++) + tty_port_register_device(&card->ports[j].port, + cy_serial_driver, i, &pdev->dev); cy_next_channel += nchan; return 0; err_null: - cy_card[card_no].base_addr = NULL; - free_irq(irq, &cy_card[card_no]); + card->base_addr = NULL; + free_irq(irq, card); err_unmap: iounmap(addr0); if (addr2) diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c index 4813684cb634..4ab936b7aac6 100644 --- a/drivers/tty/ehv_bytechan.c +++ b/drivers/tty/ehv_bytechan.c @@ -738,16 +738,17 @@ static int __devinit ehv_bc_tty_probe(struct platform_device *pdev) goto error; } - bc->dev = tty_register_device(ehv_bc_driver, i, &pdev->dev); + tty_port_init(&bc->port); + bc->port.ops = &ehv_bc_tty_port_ops; + + bc->dev = tty_port_register_device(&bc->port, ehv_bc_driver, i, + &pdev->dev); if (IS_ERR(bc->dev)) { ret = PTR_ERR(bc->dev); dev_err(&pdev->dev, "could not register tty (ret=%i)\n", ret); goto error; } - tty_port_init(&bc->port); - bc->port.ops = &ehv_bc_tty_port_ops; - dev_set_drvdata(&pdev->dev, bc); dev_info(&pdev->dev, "registered /dev/%s%u for byte channel %u\n", diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 2d691eb7c40a..7f80f15681cd 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -299,20 +299,33 @@ static void hvc_unthrottle(struct tty_struct *tty) hvc_kick(); } +static int hvc_install(struct tty_driver *driver, struct tty_struct *tty) +{ + struct hvc_struct *hp; + int rc; + + /* Auto increments kref reference if found. */ + if (!(hp = hvc_get_by_index(tty->index))) + return -ENODEV; + + tty->driver_data = hp; + + rc = tty_port_install(&hp->port, driver, tty); + if (rc) + tty_port_put(&hp->port); + return rc; +} + /* * The TTY interface won't be used until after the vio layer has exposed the vty * adapter to the kernel. */ static int hvc_open(struct tty_struct *tty, struct file * filp) { - struct hvc_struct *hp; + struct hvc_struct *hp = tty->driver_data; unsigned long flags; int rc = 0; - /* Auto increments kref reference if found. */ - if (!(hp = hvc_get_by_index(tty->index))) - return -ENODEV; - spin_lock_irqsave(&hp->port.lock, flags); /* Check and then increment for fast path open. */ if (hp->port.count++ > 0) { @@ -322,7 +335,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) } /* else count == 0 */ spin_unlock_irqrestore(&hp->port.lock, flags); - tty->driver_data = hp; tty_port_tty_set(&hp->port, tty); if (hp->ops->notifier_add) @@ -389,6 +401,11 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) hp->vtermno, hp->port.count); spin_unlock_irqrestore(&hp->port.lock, flags); } +} + +static void hvc_cleanup(struct tty_struct *tty) +{ + struct hvc_struct *hp = tty->driver_data; tty_port_put(&hp->port); } @@ -792,8 +809,10 @@ static void hvc_poll_put_char(struct tty_driver *driver, int line, char ch) #endif static const struct tty_operations hvc_ops = { + .install = hvc_install, .open = hvc_open, .close = hvc_close, + .cleanup = hvc_cleanup, .write = hvc_write, .hangup = hvc_hangup, .unthrottle = hvc_unthrottle, diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index d56788c83974..cab5c7adf8e8 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -1102,27 +1102,20 @@ static struct hvcs_struct *hvcs_get_by_index(int index) return NULL; } -/* - * This is invoked via the tty_open interface when a user app connects to the - * /dev node. - */ -static int hvcs_open(struct tty_struct *tty, struct file *filp) +static int hvcs_install(struct tty_driver *driver, struct tty_struct *tty) { struct hvcs_struct *hvcsd; - int rc, retval = 0; - unsigned long flags; - unsigned int irq; struct vio_dev *vdev; - unsigned long unit_address; - - if (tty->driver_data) - goto fast_open; + unsigned long unit_address, flags; + unsigned int irq; + int retval; /* * Is there a vty-server that shares the same index? * This function increments the kref index. */ - if (!(hvcsd = hvcs_get_by_index(tty->index))) { + hvcsd = hvcs_get_by_index(tty->index); + if (!hvcsd) { printk(KERN_WARNING "HVCS: open failed, no device associated" " with tty->index %d.\n", tty->index); return -ENODEV; @@ -1130,11 +1123,16 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) spin_lock_irqsave(&hvcsd->lock, flags); - if (hvcsd->connected == 0) - if ((retval = hvcs_partner_connect(hvcsd))) - goto error_release; + if (hvcsd->connected == 0) { + retval = hvcs_partner_connect(hvcsd); + if (retval) { + spin_unlock_irqrestore(&hvcsd->lock, flags); + printk(KERN_WARNING "HVCS: partner connect failed.\n"); + goto err_put; + } + } - hvcsd->port.count = 1; + hvcsd->port.count = 0; hvcsd->port.tty = tty; tty->driver_data = hvcsd; @@ -1155,37 +1153,48 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) * This must be done outside of the spinlock because it requests irqs * and will grab the spinlock and free the connection if it fails. */ - if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) { - tty_port_put(&hvcsd->port); + retval = hvcs_enable_device(hvcsd, unit_address, irq, vdev); + if (retval) { printk(KERN_WARNING "HVCS: enable device failed.\n"); - return rc; + goto err_put; } - goto open_success; + retval = tty_port_install(&hvcsd->port, driver, tty); + if (retval) + goto err_irq; -fast_open: - hvcsd = tty->driver_data; + return 0; +err_irq: + spin_lock_irqsave(&hvcsd->lock, flags); + vio_disable_interrupts(hvcsd->vdev); + spin_unlock_irqrestore(&hvcsd->lock, flags); + free_irq(irq, hvcsd); +err_put: + tty_port_put(&hvcsd->port); + + return retval; +} + +/* + * This is invoked via the tty_open interface when a user app connects to the + * /dev node. + */ +static int hvcs_open(struct tty_struct *tty, struct file *filp) +{ + struct hvcs_struct *hvcsd = tty->driver_data; + unsigned long flags; spin_lock_irqsave(&hvcsd->lock, flags); - tty_port_get(&hvcsd->port); hvcsd->port.count++; hvcsd->todo_mask |= HVCS_SCHED_READ; spin_unlock_irqrestore(&hvcsd->lock, flags); -open_success: hvcs_kick(); printk(KERN_INFO "HVCS: vty-server@%X connection opened.\n", hvcsd->vdev->unit_address ); return 0; - -error_release: - spin_unlock_irqrestore(&hvcsd->lock, flags); - tty_port_put(&hvcsd->port); - - printk(KERN_WARNING "HVCS: partner connect failed.\n"); - return retval; } static void hvcs_close(struct tty_struct *tty, struct file *filp) @@ -1236,7 +1245,6 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) tty->driver_data = NULL; free_irq(irq, hvcsd); - tty_port_put(&hvcsd->port); return; } else if (hvcsd->port.count < 0) { printk(KERN_ERR "HVCS: vty-server@%X open_count: %d" @@ -1245,6 +1253,12 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) } spin_unlock_irqrestore(&hvcsd->lock, flags); +} + +static void hvcs_cleanup(struct tty_struct * tty) +{ + struct hvcs_struct *hvcsd = tty->driver_data; + tty_port_put(&hvcsd->port); } @@ -1431,8 +1445,10 @@ static int hvcs_chars_in_buffer(struct tty_struct *tty) } static const struct tty_operations hvcs_ops = { + .install = hvcs_install, .open = hvcs_open, .close = hvcs_close, + .cleanup = hvcs_cleanup, .hangup = hvcs_hangup, .write = hvcs_write, .write_room = hvcs_write_room, diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c index 6f5bc49c441f..0083bc1f63f4 100644 --- a/drivers/tty/hvc/hvsi.c +++ b/drivers/tty/hvc/hvsi.c @@ -1080,6 +1080,8 @@ static int __init hvsi_init(void) struct hvsi_struct *hp = &hvsi_ports[i]; int ret = 1; + tty_port_link_device(&hp->port, hvsi_driver, i); + ret = request_irq(hp->virq, hvsi_interrupt, 0, "hvsi", hp); if (ret) printk(KERN_ERR "HVSI: couldn't reserve irq 0x%x (error %i)\n", diff --git a/drivers/tty/hvc/hvsi_lib.c b/drivers/tty/hvc/hvsi_lib.c index 59c135dd5d20..3396eb9d57a3 100644 --- a/drivers/tty/hvc/hvsi_lib.c +++ b/drivers/tty/hvc/hvsi_lib.c @@ -400,7 +400,7 @@ void hvsilib_close(struct hvsi_priv *pv, struct hvc_struct *hp) spin_unlock_irqrestore(&hp->lock, flags); /* Clear our own DTR */ - if (!pv->tty || (pv->tty->termios->c_cflag & HUPCL)) + if (!pv->tty || (pv->tty->termios.c_cflag & HUPCL)) hvsilib_write_mctrl(pv, 0); /* Tear down the connection */ diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index f8b5fa0093a3..160f0ad9589d 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -476,7 +476,7 @@ static int add_tty(int j, mutex_init(&ttys[j]->ipw_tty_mutex); tty_port_init(&ttys[j]->port); - tty_register_device(ipw_tty_driver, j, NULL); + tty_port_register_device(&ttys[j]->port, ipw_tty_driver, j, NULL); ipwireless_associate_network_tty(network, channel_idx, ttys[j]); if (secondary_channel_idx != -1) diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c index e1235accab74..d7492e183607 100644 --- a/drivers/tty/isicom.c +++ b/drivers/tty/isicom.c @@ -600,7 +600,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) port->status &= ~ISI_DCD; } - if (port->port.flags & ASYNC_CTS_FLOW) { + if (tty_port_cts_enabled(&port->port)) { if (tty->hw_stopped) { if (header & ISI_CTS) { port->port.tty->hw_stopped = 0; @@ -702,7 +702,7 @@ static void isicom_config_port(struct tty_struct *tty) /* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */ if (baud < 1 || baud > 4) - tty->termios->c_cflag &= ~CBAUDEX; + tty->termios.c_cflag &= ~CBAUDEX; else baud += 15; } @@ -1196,8 +1196,8 @@ static void isicom_set_termios(struct tty_struct *tty, if (isicom_paranoia_check(port, tty->name, "isicom_set_termios")) return; - if (tty->termios->c_cflag == old_termios->c_cflag && - tty->termios->c_iflag == old_termios->c_iflag) + if (tty->termios.c_cflag == old_termios->c_cflag && + tty->termios.c_iflag == old_termios->c_iflag) return; spin_lock_irqsave(&port->card->card_lock, flags); @@ -1205,7 +1205,7 @@ static void isicom_set_termios(struct tty_struct *tty, spin_unlock_irqrestore(&port->card->card_lock, flags); if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { + !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; isicom_start(tty); } @@ -1611,7 +1611,8 @@ static int __devinit isicom_probe(struct pci_dev *pdev, goto errunri; for (index = 0; index < board->port_count; index++) - tty_register_device(isicom_normal, board->index * 16 + index, + tty_port_register_device(&board->ports[index].port, + isicom_normal, board->index * 16 + index, &pdev->dev); return 0; diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index 324467d28a54..56e616b9109a 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -169,6 +169,7 @@ static DEFINE_SPINLOCK(moxa_lock); static unsigned long baseaddr[MAX_BOARDS]; static unsigned int type[MAX_BOARDS]; static unsigned int numports[MAX_BOARDS]; +static struct tty_port moxa_service_port; MODULE_AUTHOR("William Chen"); MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver"); @@ -367,10 +368,10 @@ static int moxa_ioctl(struct tty_struct *tty, tmp.dcd = 1; ttyp = tty_port_tty_get(&p->port); - if (!ttyp || !ttyp->termios) + if (!ttyp) tmp.cflag = p->cflag; else - tmp.cflag = ttyp->termios->c_cflag; + tmp.cflag = ttyp->termios.c_cflag; tty_kref_put(ttyp); copy: if (copy_to_user(argm, &tmp, sizeof(tmp))) @@ -834,7 +835,7 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev) const struct firmware *fw; const char *file; struct moxa_port *p; - unsigned int i; + unsigned int i, first_idx; int ret; brd->ports = kcalloc(MAX_PORTS_PER_BOARD, sizeof(*brd->ports), @@ -887,6 +888,11 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev) mod_timer(&moxaTimer, jiffies + HZ / 50); spin_unlock_bh(&moxa_lock); + first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD; + for (i = 0; i < brd->numPorts; i++) + tty_port_register_device(&brd->ports[i].port, moxaDriver, + first_idx + i, dev); + return 0; err_free: kfree(brd->ports); @@ -896,7 +902,7 @@ err: static void moxa_board_deinit(struct moxa_board_conf *brd) { - unsigned int a, opened; + unsigned int a, opened, first_idx; mutex_lock(&moxa_openlock); spin_lock_bh(&moxa_lock); @@ -925,6 +931,10 @@ static void moxa_board_deinit(struct moxa_board_conf *brd) mutex_lock(&moxa_openlock); } + first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD; + for (a = 0; a < brd->numPorts; a++) + tty_unregister_device(moxaDriver, first_idx + a); + iounmap(brd->basemem); brd->basemem = NULL; kfree(brd->ports); @@ -967,6 +977,7 @@ static int __devinit moxa_pci_probe(struct pci_dev *pdev, board->basemem = ioremap_nocache(pci_resource_start(pdev, 2), 0x4000); if (board->basemem == NULL) { dev_err(&pdev->dev, "can't remap io space 2\n"); + retval = -ENOMEM; goto err_reg; } @@ -1031,9 +1042,14 @@ static int __init moxa_init(void) printk(KERN_INFO "MOXA Intellio family driver version %s\n", MOXA_VERSION); - moxaDriver = alloc_tty_driver(MAX_PORTS + 1); - if (!moxaDriver) - return -ENOMEM; + + tty_port_init(&moxa_service_port); + + moxaDriver = tty_alloc_driver(MAX_PORTS + 1, + TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV); + if (IS_ERR(moxaDriver)) + return PTR_ERR(moxaDriver); moxaDriver->name = "ttyMX"; moxaDriver->major = ttymajor; @@ -1044,8 +1060,9 @@ static int __init moxa_init(void) moxaDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; moxaDriver->init_termios.c_ispeed = 9600; moxaDriver->init_termios.c_ospeed = 9600; - moxaDriver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(moxaDriver, &moxa_ops); + /* Having one more port only for ioctls is ugly */ + tty_port_link_device(&moxa_service_port, moxaDriver, MAX_PORTS); if (tty_register_driver(moxaDriver)) { printk(KERN_ERR "can't register MOXA Smartio tty driver!\n"); @@ -1178,7 +1195,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp) mutex_lock(&ch->port.mutex); if (!(ch->port.flags & ASYNC_INITIALIZED)) { ch->statusflags = 0; - moxa_set_tty_param(tty, tty->termios); + moxa_set_tty_param(tty, &tty->termios); MoxaPortLineCtrl(ch, 1, 1); MoxaPortEnable(ch); MoxaSetFifo(ch, ch->type == PORT_16550A); @@ -1193,7 +1210,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp) static void moxa_close(struct tty_struct *tty, struct file *filp) { struct moxa_port *ch = tty->driver_data; - ch->cflag = tty->termios->c_cflag; + ch->cflag = tty->termios.c_cflag; tty_port_close(&ch->port, tty, filp); } @@ -1464,7 +1481,7 @@ static void moxa_poll(unsigned long ignored) static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_termios) { - register struct ktermios *ts = tty->termios; + register struct ktermios *ts = &tty->termios; struct moxa_port *ch = tty->driver_data; int rts, cts, txflow, rxflow, xany, baud; diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 90cc680c4f0e..cfda47dabd28 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -643,7 +643,7 @@ static int mxser_change_speed(struct tty_struct *tty, int ret = 0; unsigned char status; - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; if (!info->ioaddr) return ret; @@ -830,7 +830,7 @@ static void mxser_check_modem_status(struct tty_struct *tty, wake_up_interruptible(&port->port.open_wait); } - if (port->port.flags & ASYNC_CTS_FLOW) { + if (tty_port_cts_enabled(&port->port)) { if (tty->hw_stopped) { if (status & UART_MSR_CTS) { tty->hw_stopped = 0; @@ -1520,10 +1520,10 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) tty = tty_port_tty_get(port); - if (!tty || !tty->termios) + if (!tty) ms.cflag = ip->normal_termios.c_cflag; else - ms.cflag = tty->termios->c_cflag; + ms.cflag = tty->termios.c_cflag; tty_kref_put(tty); spin_lock_irq(&ip->slock); status = inb(ip->ioaddr + UART_MSR); @@ -1589,13 +1589,13 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) tty = tty_port_tty_get(&ip->port); - if (!tty || !tty->termios) { + if (!tty) { cflag = ip->normal_termios.c_cflag; iflag = ip->normal_termios.c_iflag; me->baudrate[p] = tty_termios_baud_rate(&ip->normal_termios); } else { - cflag = tty->termios->c_cflag; - iflag = tty->termios->c_iflag; + cflag = tty->termios.c_cflag; + iflag = tty->termios.c_iflag; me->baudrate[p] = tty_get_baud_rate(tty); } tty_kref_put(tty); @@ -1853,7 +1853,7 @@ static void mxser_stoprx(struct tty_struct *tty) } } - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { info->MCR &= ~UART_MCR_RTS; outb(info->MCR, info->ioaddr + UART_MCR); } @@ -1890,7 +1890,7 @@ static void mxser_unthrottle(struct tty_struct *tty) } } - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { info->MCR |= UART_MCR_RTS; outb(info->MCR, info->ioaddr + UART_MCR); } @@ -1939,14 +1939,14 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi spin_unlock_irqrestore(&info->slock, flags); if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { + !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; mxser_start(tty); } /* Handle sw stopped */ if ((old_termios->c_iflag & IXON) && - !(tty->termios->c_iflag & IXON)) { + !(tty->termios.c_iflag & IXON)) { tty->stopped = 0; if (info->board->chip_flag) { @@ -2337,11 +2337,36 @@ static struct tty_port_operations mxser_port_ops = { * The MOXA Smartio/Industio serial driver boot-time initialization code! */ +static bool allow_overlapping_vector; +module_param(allow_overlapping_vector, bool, S_IRUGO); +MODULE_PARM_DESC(allow_overlapping_vector, "whether we allow ISA cards to be configured such that vector overlabs IO ports (default=no)"); + +static bool mxser_overlapping_vector(struct mxser_board *brd) +{ + return allow_overlapping_vector && + brd->vector >= brd->ports[0].ioaddr && + brd->vector < brd->ports[0].ioaddr + 8 * brd->info->nports; +} + +static int mxser_request_vector(struct mxser_board *brd) +{ + if (mxser_overlapping_vector(brd)) + return 0; + return request_region(brd->vector, 1, "mxser(vector)") ? 0 : -EIO; +} + +static void mxser_release_vector(struct mxser_board *brd) +{ + if (mxser_overlapping_vector(brd)) + return; + release_region(brd->vector, 1); +} + static void mxser_release_ISA_res(struct mxser_board *brd) { free_irq(brd->irq, brd); release_region(brd->ports[0].ioaddr, 8 * brd->info->nports); - release_region(brd->vector, 1); + mxser_release_vector(brd); } static int __devinit mxser_initbrd(struct mxser_board *brd, @@ -2396,7 +2421,7 @@ static int __devinit mxser_initbrd(struct mxser_board *brd, static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd) { - int id, i, bits; + int id, i, bits, ret; unsigned short regs[16], irq; unsigned char scratch, scratch2; @@ -2492,13 +2517,15 @@ static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd) 8 * brd->info->nports - 1); return -EIO; } - if (!request_region(brd->vector, 1, "mxser(vector)")) { + + ret = mxser_request_vector(brd); + if (ret) { release_region(brd->ports[0].ioaddr, 8 * brd->info->nports); printk(KERN_ERR "mxser: can't request interrupt vector region: " "0x%.8lx-0x%.8lx\n", brd->ports[0].ioaddr, brd->ports[0].ioaddr + 8 * brd->info->nports - 1); - return -EIO; + return ret; } return brd->info->nports; @@ -2598,7 +2625,8 @@ static int __devinit mxser_probe(struct pci_dev *pdev, goto err_rel3; for (i = 0; i < brd->info->nports; i++) - tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev); + tty_port_register_device(&brd->ports[i].port, mxvar_sdriver, + brd->idx + i, &pdev->dev); pci_set_drvdata(pdev, brd); @@ -2695,7 +2723,8 @@ static int __init mxser_module_init(void) brd->idx = m * MXSER_PORTS_PER_BOARD; for (i = 0; i < brd->info->nports; i++) - tty_register_device(mxvar_sdriver, brd->idx + i, NULL); + tty_port_register_device(&brd->ports[i].port, + mxvar_sdriver, brd->idx + i, NULL); m++; } diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index c43b683b6eb8..3e210a430fb3 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -108,7 +108,7 @@ struct gsm_mux_net { */ struct gsm_msg { - struct gsm_msg *next; + struct list_head list; u8 addr; /* DLCI address + flags */ u8 ctrl; /* Control byte + flags */ unsigned int len; /* Length of data block (can be zero) */ @@ -245,8 +245,7 @@ struct gsm_mux { unsigned int tx_bytes; /* TX data outstanding */ #define TX_THRESH_HI 8192 #define TX_THRESH_LO 2048 - struct gsm_msg *tx_head; /* Pending data packets */ - struct gsm_msg *tx_tail; + struct list_head tx_list; /* Pending data packets */ /* Control messages */ struct timer_list t2_timer; /* Retransmit timer for commands */ @@ -663,7 +662,7 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len, m->len = len; m->addr = addr; m->ctrl = ctrl; - m->next = NULL; + INIT_LIST_HEAD(&m->list); return m; } @@ -673,22 +672,21 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len, * * The tty device has called us to indicate that room has appeared in * the transmit queue. Ram more data into the pipe if we have any + * If we have been flow-stopped by a CMD_FCOFF, then we can only + * send messages on DLCI0 until CMD_FCON * * FIXME: lock against link layer control transmissions */ static void gsm_data_kick(struct gsm_mux *gsm) { - struct gsm_msg *msg = gsm->tx_head; + struct gsm_msg *msg, *nmsg; int len; int skip_sof = 0; - /* FIXME: We need to apply this solely to data messages */ - if (gsm->constipated) - return; - - while (gsm->tx_head != NULL) { - msg = gsm->tx_head; + list_for_each_entry_safe(msg, nmsg, &gsm->tx_list, list) { + if (gsm->constipated && msg->addr) + continue; if (gsm->encoding != 0) { gsm->txframe[0] = GSM1_SOF; len = gsm_stuff_frame(msg->data, @@ -711,14 +709,13 @@ static void gsm_data_kick(struct gsm_mux *gsm) len - skip_sof) < 0) break; /* FIXME: Can eliminate one SOF in many more cases */ - gsm->tx_head = msg->next; - if (gsm->tx_head == NULL) - gsm->tx_tail = NULL; gsm->tx_bytes -= msg->len; - kfree(msg); /* For a burst of frames skip the extra SOF within the burst */ skip_sof = 1; + + list_del(&msg->list); + kfree(msg); } } @@ -768,11 +765,7 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg) msg->data = dp; /* Add to the actual output queue */ - if (gsm->tx_tail) - gsm->tx_tail->next = msg; - else - gsm->tx_head = msg; - gsm->tx_tail = msg; + list_add_tail(&msg->list, &gsm->tx_list); gsm->tx_bytes += msg->len; gsm_data_kick(gsm); } @@ -875,7 +868,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm, /* dlci->skb is locked by tx_lock */ if (dlci->skb == NULL) { - dlci->skb = skb_dequeue(&dlci->skb_list); + dlci->skb = skb_dequeue_tail(&dlci->skb_list); if (dlci->skb == NULL) return 0; first = 1; @@ -886,7 +879,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm, if (len > gsm->mtu) { if (dlci->adaption == 3) { /* Over long frame, bin it */ - kfree_skb(dlci->skb); + dev_kfree_skb_any(dlci->skb); dlci->skb = NULL; return 0; } @@ -899,8 +892,11 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm, /* FIXME: need a timer or something to kick this so it can't get stuck with no work outstanding and no buffer free */ - if (msg == NULL) + if (msg == NULL) { + skb_queue_tail(&dlci->skb_list, dlci->skb); + dlci->skb = NULL; return -ENOMEM; + } dp = msg->data; if (dlci->adaption == 4) { /* Interruptible framed (Packetised Data) */ @@ -912,7 +908,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm, skb_pull(dlci->skb, len); __gsm_data_queue(dlci, msg); if (last) { - kfree_skb(dlci->skb); + dev_kfree_skb_any(dlci->skb); dlci->skb = NULL; } return size; @@ -971,16 +967,22 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm) static void gsm_dlci_data_kick(struct gsm_dlci *dlci) { unsigned long flags; + int sweep; + + if (dlci->constipated) + return; spin_lock_irqsave(&dlci->gsm->tx_lock, flags); /* If we have nothing running then we need to fire up */ + sweep = (dlci->gsm->tx_bytes < TX_THRESH_LO); if (dlci->gsm->tx_bytes == 0) { if (dlci->net) gsm_dlci_data_output_framed(dlci->gsm, dlci); else gsm_dlci_data_output(dlci->gsm, dlci); - } else if (dlci->gsm->tx_bytes < TX_THRESH_LO) - gsm_dlci_data_sweep(dlci->gsm); + } + if (sweep) + gsm_dlci_data_sweep(dlci->gsm); spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags); } @@ -1027,6 +1029,7 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci, { int mlines = 0; u8 brk = 0; + int fc; /* The modem status command can either contain one octet (v.24 signals) or two octets (v.24 signals + break signals). The length field will @@ -1038,19 +1041,21 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci, else { brk = modem & 0x7f; modem = (modem >> 7) & 0x7f; - }; + } /* Flow control/ready to communicate */ - if (modem & MDM_FC) { + fc = (modem & MDM_FC) || !(modem & MDM_RTR); + if (fc && !dlci->constipated) { /* Need to throttle our output on this device */ dlci->constipated = 1; - } - if (modem & MDM_RTC) { - mlines |= TIOCM_DSR | TIOCM_DTR; + } else if (!fc && dlci->constipated) { dlci->constipated = 0; gsm_dlci_data_kick(dlci); } + /* Map modem bits */ + if (modem & MDM_RTC) + mlines |= TIOCM_DSR | TIOCM_DTR; if (modem & MDM_RTR) mlines |= TIOCM_RTS | TIOCM_CTS; if (modem & MDM_IC) @@ -1061,7 +1066,7 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci, /* Carrier drop -> hangup */ if (tty) { if ((mlines & TIOCM_CD) == 0 && (dlci->modem_rx & TIOCM_CD)) - if (!(tty->termios->c_cflag & CLOCAL)) + if (!(tty->termios.c_cflag & CLOCAL)) tty_hangup(tty); if (brk & 0x01) tty_insert_flip_char(tty, 0, TTY_BREAK); @@ -1190,6 +1195,8 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, u8 *data, int clen) { u8 buf[1]; + unsigned long flags; + switch (command) { case CMD_CLD: { struct gsm_dlci *dlci = gsm->dlci[0]; @@ -1206,16 +1213,18 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, gsm_control_reply(gsm, CMD_TEST, data, clen); break; case CMD_FCON: - /* Modem wants us to STFU */ - gsm->constipated = 1; - gsm_control_reply(gsm, CMD_FCON, NULL, 0); - break; - case CMD_FCOFF: /* Modem can accept data again */ gsm->constipated = 0; - gsm_control_reply(gsm, CMD_FCOFF, NULL, 0); + gsm_control_reply(gsm, CMD_FCON, NULL, 0); /* Kick the link in case it is idling */ + spin_lock_irqsave(&gsm->tx_lock, flags); gsm_data_kick(gsm); + spin_unlock_irqrestore(&gsm->tx_lock, flags); + break; + case CMD_FCOFF: + /* Modem wants us to STFU */ + gsm->constipated = 1; + gsm_control_reply(gsm, CMD_FCOFF, NULL, 0); break; case CMD_MSC: /* Out of band modem line change indicator for a DLCI */ @@ -1668,7 +1677,7 @@ static void gsm_dlci_free(struct kref *ref) dlci->gsm->dlci[dlci->addr] = NULL; kfifo_free(dlci->fifo); while ((dlci->skb = skb_dequeue(&dlci->skb_list))) - kfree_skb(dlci->skb); + dev_kfree_skb(dlci->skb); kfree(dlci); } @@ -2007,7 +2016,7 @@ void gsm_cleanup_mux(struct gsm_mux *gsm) { int i; struct gsm_dlci *dlci = gsm->dlci[0]; - struct gsm_msg *txq; + struct gsm_msg *txq, *ntxq; struct gsm_control *gc; gsm->dead = 1; @@ -2042,11 +2051,9 @@ void gsm_cleanup_mux(struct gsm_mux *gsm) if (gsm->dlci[i]) gsm_dlci_release(gsm->dlci[i]); /* Now wipe the queues */ - for (txq = gsm->tx_head; txq != NULL; txq = gsm->tx_head) { - gsm->tx_head = txq->next; + list_for_each_entry_safe(txq, ntxq, &gsm->tx_list, list) kfree(txq); - } - gsm->tx_tail = NULL; + INIT_LIST_HEAD(&gsm->tx_list); } EXPORT_SYMBOL_GPL(gsm_cleanup_mux); @@ -2157,6 +2164,7 @@ struct gsm_mux *gsm_alloc_mux(void) } spin_lock_init(&gsm->lock); kref_init(&gsm->ref); + INIT_LIST_HEAD(&gsm->tx_list); gsm->t1 = T1; gsm->t2 = T2; @@ -2273,7 +2281,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp, gsm->error(gsm, *dp, flags); break; default: - WARN_ONCE("%s: unknown flag %d\n", + WARN_ONCE(1, "%s: unknown flag %d\n", tty_name(tty, buf), flags); break; } @@ -2377,12 +2385,12 @@ static void gsmld_write_wakeup(struct tty_struct *tty) /* Queue poll */ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + spin_lock_irqsave(&gsm->tx_lock, flags); gsm_data_kick(gsm); if (gsm->tx_bytes < TX_THRESH_LO) { - spin_lock_irqsave(&gsm->tx_lock, flags); gsm_dlci_data_sweep(gsm); - spin_unlock_irqrestore(&gsm->tx_lock, flags); } + spin_unlock_irqrestore(&gsm->tx_lock, flags); } /** @@ -2868,14 +2876,14 @@ static const struct tty_port_operations gsm_port_ops = { .dtr_rts = gsm_dtr_rts, }; - -static int gsmtty_open(struct tty_struct *tty, struct file *filp) +static int gsmtty_install(struct tty_driver *driver, struct tty_struct *tty) { struct gsm_mux *gsm; struct gsm_dlci *dlci; - struct tty_port *port; unsigned int line = tty->index; unsigned int mux = line >> 6; + bool alloc = false; + int ret; line = line & 0x3F; @@ -2889,14 +2897,35 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp) gsm = gsm_mux[mux]; if (gsm->dead) return -EL2HLT; + /* If DLCI 0 is not yet fully open return an error. This is ok from a locking + perspective as we don't have to worry about this if DLCI0 is lost */ + if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN) + return -EL2NSYNC; dlci = gsm->dlci[line]; - if (dlci == NULL) + if (dlci == NULL) { + alloc = true; dlci = gsm_dlci_alloc(gsm, line); + } if (dlci == NULL) return -ENOMEM; - port = &dlci->port; - port->count++; + ret = tty_port_install(&dlci->port, driver, tty); + if (ret) { + if (alloc) + dlci_put(dlci); + return ret; + } + tty->driver_data = dlci; + + return 0; +} + +static int gsmtty_open(struct tty_struct *tty, struct file *filp) +{ + struct gsm_dlci *dlci = tty->driver_data; + struct tty_port *port = &dlci->port; + + port->count++; dlci_get(dlci); dlci_get(dlci->gsm->dlci[0]); mux_get(dlci->gsm); @@ -3043,13 +3072,13 @@ static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old) the RPN control message. This however rapidly gets nasty as we then have to remap modem signals each way according to whether our virtual cable is null modem etc .. */ - tty_termios_copy_hw(tty->termios, old); + tty_termios_copy_hw(&tty->termios, old); } static void gsmtty_throttle(struct tty_struct *tty) { struct gsm_dlci *dlci = tty->driver_data; - if (tty->termios->c_cflag & CRTSCTS) + if (tty->termios.c_cflag & CRTSCTS) dlci->modem_tx &= ~TIOCM_DTR; dlci->throttled = 1; /* Send an MSC with DTR cleared */ @@ -3059,7 +3088,7 @@ static void gsmtty_throttle(struct tty_struct *tty) static void gsmtty_unthrottle(struct tty_struct *tty) { struct gsm_dlci *dlci = tty->driver_data; - if (tty->termios->c_cflag & CRTSCTS) + if (tty->termios.c_cflag & CRTSCTS) dlci->modem_tx |= TIOCM_DTR; dlci->throttled = 0; /* Send an MSC with DTR set */ @@ -3085,6 +3114,7 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state) /* Virtual ttys for the demux */ static const struct tty_operations gsmtty_ops = { + .install = gsmtty_install, .open = gsmtty_open, .close = gsmtty_close, .write = gsmtty_write, diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c index 5c6c31459a2f..1e6405070ce6 100644 --- a/drivers/tty/n_r3964.c +++ b/drivers/tty/n_r3964.c @@ -1065,7 +1065,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, TRACE_L("read()"); - tty_lock(); + tty_lock(tty); pClient = findClient(pInfo, task_pid(current)); if (pClient) { @@ -1077,7 +1077,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, goto unlock; } /* block until there is a message: */ - wait_event_interruptible_tty(pInfo->read_wait, + wait_event_interruptible_tty(tty, pInfo->read_wait, (pMsg = remove_msg(pInfo, pClient))); } @@ -1107,7 +1107,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, } ret = -EPERM; unlock: - tty_unlock(); + tty_unlock(tty); return ret; } @@ -1156,7 +1156,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, pHeader->locks = 0; pHeader->owner = NULL; - tty_lock(); + tty_lock(tty); pClient = findClient(pInfo, task_pid(current)); if (pClient) { @@ -1175,7 +1175,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, add_tx_queue(pInfo, pHeader); trigger_transmit(pInfo); - tty_unlock(); + tty_unlock(tty); return 0; } diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index ee1c268f5f9d..8c0b7b42319c 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -92,10 +92,18 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x, static void n_tty_set_room(struct tty_struct *tty) { - /* tty->read_cnt is not read locked ? */ - int left = N_TTY_BUF_SIZE - tty->read_cnt - 1; + int left; int old_left; + /* tty->read_cnt is not read locked ? */ + if (I_PARMRK(tty)) { + /* Multiply read_cnt by 3, since each byte might take up to + * three times as many spaces when PARMRK is set (depending on + * its flags, e.g. parity error). */ + left = N_TTY_BUF_SIZE - tty->read_cnt * 3 - 1; + } else + left = N_TTY_BUF_SIZE - tty->read_cnt - 1; + /* * If we are doing input canonicalization, and there are no * pending newlines, let characters through without limit, so @@ -1432,6 +1440,12 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, */ if (tty->receive_room < TTY_THRESHOLD_THROTTLE) tty_throttle(tty); + + /* FIXME: there is a tiny race here if the receive room check runs + before the other work executes and empties the buffer (upping + the receiving room and unthrottling. We then throttle and get + stuck. This has been observed and traced down by Vincent Pillet/ + We need to address this when we sort out out the rx path locking */ } int is_ignored(int sig) @@ -1460,7 +1474,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) BUG_ON(!tty); if (old) - canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON; + canon_change = (old->c_lflag ^ tty->termios.c_lflag) & ICANON; if (canon_change) { memset(&tty->read_flags, 0, sizeof tty->read_flags); tty->canon_head = tty->read_tail; @@ -1728,7 +1742,8 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, do_it_again: - BUG_ON(!tty->read_buf); + if (WARN_ON(!tty->read_buf)) + return -EAGAIN; c = job_control(tty, file); if (c < 0) @@ -1832,13 +1847,13 @@ do_it_again: if (tty->icanon && !L_EXTPROC(tty)) { /* N.B. avoid overrun if nr == 0 */ + spin_lock_irqsave(&tty->read_lock, flags); while (nr && tty->read_cnt) { int eol; eol = test_and_clear_bit(tty->read_tail, tty->read_flags); c = tty->read_buf[tty->read_tail]; - spin_lock_irqsave(&tty->read_lock, flags); tty->read_tail = ((tty->read_tail+1) & (N_TTY_BUF_SIZE-1)); tty->read_cnt--; @@ -1856,15 +1871,19 @@ do_it_again: if (tty_put_user(tty, c, b++)) { retval = -EFAULT; b--; + spin_lock_irqsave(&tty->read_lock, flags); break; } nr--; } if (eol) { tty_audit_push(tty); + spin_lock_irqsave(&tty->read_lock, flags); break; } + spin_lock_irqsave(&tty->read_lock, flags); } + spin_unlock_irqrestore(&tty->read_lock, flags); if (retval) break; } else { diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index e7592f9037da..b917c9424954 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -1473,8 +1473,8 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev, port->dc = dc; tty_port_init(&port->port); port->port.ops = &noz_tty_port_ops; - tty_dev = tty_register_device(ntty_driver, dc->index_start + i, - &pdev->dev); + tty_dev = tty_port_register_device(&port->port, ntty_driver, + dc->index_start + i, &pdev->dev); if (IS_ERR(tty_dev)) { ret = PTR_ERR(tty_dev); diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 5505ffc91da4..2bace847eb39 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -47,6 +47,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp) wake_up_interruptible(&tty->read_wait); wake_up_interruptible(&tty->write_wait); tty->packet = 0; + /* Review - krefs on tty_link ?? */ if (!tty->link) return; tty->link->packet = 0; @@ -62,9 +63,9 @@ static void pty_close(struct tty_struct *tty, struct file *filp) mutex_unlock(&devpts_mutex); } #endif - tty_unlock(); + tty_unlock(tty); tty_vhangup(tty->link); - tty_lock(); + tty_lock(tty); } } @@ -231,8 +232,8 @@ out: static void pty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { - tty->termios->c_cflag &= ~(CSIZE | PARENB); - tty->termios->c_cflag |= (CS8 | CREAD); + tty->termios.c_cflag &= ~(CSIZE | PARENB); + tty->termios.c_cflag |= (CS8 | CREAD); } /** @@ -282,60 +283,110 @@ done: return 0; } -/* Traditional BSD devices */ -#ifdef CONFIG_LEGACY_PTYS - -static int pty_install(struct tty_driver *driver, struct tty_struct *tty) +/** + * pty_common_install - set up the pty pair + * @driver: the pty driver + * @tty: the tty being instantiated + * @bool: legacy, true if this is BSD style + * + * Perform the initial set up for the tty/pty pair. Called from the + * tty layer when the port is first opened. + * + * Locking: the caller must hold the tty_mutex + */ +static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, + bool legacy) { struct tty_struct *o_tty; + struct tty_port *ports[2]; int idx = tty->index; - int retval; + int retval = -ENOMEM; o_tty = alloc_tty_struct(); if (!o_tty) - return -ENOMEM; + goto err; + ports[0] = kmalloc(sizeof **ports, GFP_KERNEL); + ports[1] = kmalloc(sizeof **ports, GFP_KERNEL); + if (!ports[0] || !ports[1]) + goto err_free_tty; if (!try_module_get(driver->other->owner)) { /* This cannot in fact currently happen */ - retval = -ENOMEM; goto err_free_tty; } initialize_tty_struct(o_tty, driver->other, idx); - /* We always use new tty termios data so we can do this - the easy way .. */ - retval = tty_init_termios(tty); - if (retval) - goto err_deinit_tty; - - retval = tty_init_termios(o_tty); - if (retval) - goto err_free_termios; + if (legacy) { + /* We always use new tty termios data so we can do this + the easy way .. */ + retval = tty_init_termios(tty); + if (retval) + goto err_deinit_tty; + + retval = tty_init_termios(o_tty); + if (retval) + goto err_free_termios; + + driver->other->ttys[idx] = o_tty; + driver->ttys[idx] = tty; + } else { + memset(&tty->termios_locked, 0, sizeof(tty->termios_locked)); + tty->termios = driver->init_termios; + memset(&o_tty->termios_locked, 0, sizeof(tty->termios_locked)); + o_tty->termios = driver->other->init_termios; + } /* * Everything allocated ... set up the o_tty structure. */ - driver->other->ttys[idx] = o_tty; tty_driver_kref_get(driver->other); if (driver->subtype == PTY_TYPE_MASTER) o_tty->count++; /* Establish the links in both directions */ tty->link = o_tty; o_tty->link = tty; + tty_port_init(ports[0]); + tty_port_init(ports[1]); + o_tty->port = ports[0]; + tty->port = ports[1]; tty_driver_kref_get(driver); tty->count++; - driver->ttys[idx] = tty; return 0; err_free_termios: - tty_free_termios(tty); + if (legacy) + tty_free_termios(tty); err_deinit_tty: deinitialize_tty_struct(o_tty); module_put(o_tty->driver->owner); err_free_tty: + kfree(ports[0]); + kfree(ports[1]); free_tty_struct(o_tty); +err: return retval; } +static void pty_cleanup(struct tty_struct *tty) +{ + kfree(tty->port); +} + +/* Traditional BSD devices */ +#ifdef CONFIG_LEGACY_PTYS + +static int pty_install(struct tty_driver *driver, struct tty_struct *tty) +{ + return pty_common_install(driver, tty, true); +} + +static void pty_remove(struct tty_driver *driver, struct tty_struct *tty) +{ + struct tty_struct *pair = tty->link; + driver->ttys[tty->index] = NULL; + if (pair) + pair->driver->ttys[pair->index] = NULL; +} + static int pty_bsd_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { @@ -366,7 +417,9 @@ static const struct tty_operations master_pty_ops_bsd = { .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, .ioctl = pty_bsd_ioctl, - .resize = pty_resize + .cleanup = pty_cleanup, + .resize = pty_resize, + .remove = pty_remove }; static const struct tty_operations slave_pty_ops_bsd = { @@ -379,7 +432,9 @@ static const struct tty_operations slave_pty_ops_bsd = { .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, - .resize = pty_resize + .cleanup = pty_cleanup, + .resize = pty_resize, + .remove = pty_remove }; static void __init legacy_pty_init(void) @@ -389,12 +444,18 @@ static void __init legacy_pty_init(void) if (legacy_count <= 0) return; - pty_driver = alloc_tty_driver(legacy_count); - if (!pty_driver) + pty_driver = tty_alloc_driver(legacy_count, + TTY_DRIVER_RESET_TERMIOS | + TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_ALLOC); + if (IS_ERR(pty_driver)) panic("Couldn't allocate pty driver"); - pty_slave_driver = alloc_tty_driver(legacy_count); - if (!pty_slave_driver) + pty_slave_driver = tty_alloc_driver(legacy_count, + TTY_DRIVER_RESET_TERMIOS | + TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_ALLOC); + if (IS_ERR(pty_slave_driver)) panic("Couldn't allocate pty slave driver"); pty_driver->driver_name = "pty_master"; @@ -410,7 +471,6 @@ static void __init legacy_pty_init(void) pty_driver->init_termios.c_lflag = 0; pty_driver->init_termios.c_ispeed = 38400; pty_driver->init_termios.c_ospeed = 38400; - pty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW; pty_driver->other = pty_slave_driver; tty_set_operations(pty_driver, &master_pty_ops_bsd); @@ -424,8 +484,6 @@ static void __init legacy_pty_init(void) pty_slave_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; pty_slave_driver->init_termios.c_ispeed = 38400; pty_slave_driver->init_termios.c_ospeed = 38400; - pty_slave_driver->flags = TTY_DRIVER_RESET_TERMIOS | - TTY_DRIVER_REAL_RAW; pty_slave_driver->other = pty_driver; tty_set_operations(pty_slave_driver, &slave_pty_ops_bsd); @@ -497,78 +555,22 @@ static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver, return tty; } -static void pty_unix98_shutdown(struct tty_struct *tty) -{ - tty_driver_remove_tty(tty->driver, tty); - /* We have our own method as we don't use the tty index */ - kfree(tty->termios); -} - /* We have no need to install and remove our tty objects as devpts does all the work for us */ static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty) { - struct tty_struct *o_tty; - int idx = tty->index; - - o_tty = alloc_tty_struct(); - if (!o_tty) - return -ENOMEM; - if (!try_module_get(driver->other->owner)) { - /* This cannot in fact currently happen */ - goto err_free_tty; - } - initialize_tty_struct(o_tty, driver->other, idx); - - tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL); - if (tty->termios == NULL) - goto err_free_mem; - *tty->termios = driver->init_termios; - tty->termios_locked = tty->termios + 1; - - o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL); - if (o_tty->termios == NULL) - goto err_free_mem; - *o_tty->termios = driver->other->init_termios; - o_tty->termios_locked = o_tty->termios + 1; - - tty_driver_kref_get(driver->other); - if (driver->subtype == PTY_TYPE_MASTER) - o_tty->count++; - /* Establish the links in both directions */ - tty->link = o_tty; - o_tty->link = tty; - /* - * All structures have been allocated, so now we install them. - * Failures after this point use release_tty to clean up, so - * there's no need to null out the local pointers. - */ - tty_driver_kref_get(driver); - tty->count++; - return 0; -err_free_mem: - deinitialize_tty_struct(o_tty); - kfree(o_tty->termios); - kfree(tty->termios); - module_put(o_tty->driver->owner); -err_free_tty: - free_tty_struct(o_tty); - return -ENOMEM; -} - -static void ptm_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) -{ + return pty_common_install(driver, tty, false); } -static void pts_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) +static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) { } static const struct tty_operations ptm_unix98_ops = { .lookup = ptm_unix98_lookup, .install = pty_unix98_install, - .remove = ptm_unix98_remove, + .remove = pty_unix98_remove, .open = pty_open, .close = pty_close, .write = pty_write, @@ -578,14 +580,14 @@ static const struct tty_operations ptm_unix98_ops = { .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, .ioctl = pty_unix98_ioctl, - .shutdown = pty_unix98_shutdown, - .resize = pty_resize + .resize = pty_resize, + .cleanup = pty_cleanup }; static const struct tty_operations pty_unix98_ops = { .lookup = pts_unix98_lookup, .install = pty_unix98_install, - .remove = pts_unix98_remove, + .remove = pty_unix98_remove, .open = pty_open, .close = pty_close, .write = pty_write, @@ -594,7 +596,7 @@ static const struct tty_operations pty_unix98_ops = { .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, - .shutdown = pty_unix98_shutdown + .cleanup = pty_cleanup, }; /** @@ -622,26 +624,27 @@ static int ptmx_open(struct inode *inode, struct file *filp) return retval; /* find a device that is not in use. */ - tty_lock(); + mutex_lock(&devpts_mutex); index = devpts_new_index(inode); - tty_unlock(); if (index < 0) { retval = index; goto err_file; } + mutex_unlock(&devpts_mutex); + mutex_lock(&tty_mutex); - mutex_lock(&devpts_mutex); tty = tty_init_dev(ptm_driver, index); - mutex_unlock(&devpts_mutex); - tty_lock(); - mutex_unlock(&tty_mutex); if (IS_ERR(tty)) { retval = PTR_ERR(tty); goto out; } + /* The tty returned here is locked so we can safely + drop the mutex */ + mutex_unlock(&tty_mutex); + set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ tty_add_file(tty, filp); @@ -654,16 +657,17 @@ static int ptmx_open(struct inode *inode, struct file *filp) if (retval) goto err_release; - tty_unlock(); + tty_unlock(tty); return 0; err_release: - tty_unlock(); + tty_unlock(tty); tty_release(inode, filp); return retval; out: + mutex_unlock(&tty_mutex); devpts_kill_index(inode, index); - tty_unlock(); err_file: + mutex_unlock(&devpts_mutex); tty_free_file(filp); return retval; } @@ -672,11 +676,21 @@ static struct file_operations ptmx_fops; static void __init unix98_pty_init(void) { - ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX); - if (!ptm_driver) + ptm_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX, + TTY_DRIVER_RESET_TERMIOS | + TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV | + TTY_DRIVER_DEVPTS_MEM | + TTY_DRIVER_DYNAMIC_ALLOC); + if (IS_ERR(ptm_driver)) panic("Couldn't allocate Unix98 ptm driver"); - pts_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX); - if (!pts_driver) + pts_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX, + TTY_DRIVER_RESET_TERMIOS | + TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV | + TTY_DRIVER_DEVPTS_MEM | + TTY_DRIVER_DYNAMIC_ALLOC); + if (IS_ERR(pts_driver)) panic("Couldn't allocate Unix98 pts driver"); ptm_driver->driver_name = "pty_master"; @@ -692,8 +706,6 @@ static void __init unix98_pty_init(void) ptm_driver->init_termios.c_lflag = 0; ptm_driver->init_termios.c_ispeed = 38400; ptm_driver->init_termios.c_ospeed = 38400; - ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM; ptm_driver->other = pts_driver; tty_set_operations(ptm_driver, &ptm_unix98_ops); @@ -707,8 +719,6 @@ static void __init unix98_pty_init(void) pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; pts_driver->init_termios.c_ispeed = 38400; pts_driver->init_termios.c_ospeed = 38400; - pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM; pts_driver->other = ptm_driver; tty_set_operations(pts_driver, &pty_unix98_ops); diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index 777d5f9cf6cc..9700d34b20a3 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -704,8 +704,8 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev) spin_lock_init(&info->slock); mutex_init(&info->write_mtx); rp_table[line] = info; - tty_register_device(rocket_driver, line, pci_dev ? &pci_dev->dev : - NULL); + tty_port_register_device(&info->port, rocket_driver, line, + pci_dev ? &pci_dev->dev : NULL); } /* @@ -720,7 +720,7 @@ static void configure_r_port(struct tty_struct *tty, struct r_port *info, unsigned rocketMode; int bits, baud, divisor; CHANNEL_t *cp; - struct ktermios *t = tty->termios; + struct ktermios *t = &tty->termios; cp = &info->channel; cflag = t->c_cflag; @@ -978,7 +978,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp) tty->alt_speed = 460800; configure_r_port(tty, info, NULL); - if (tty->termios->c_cflag & CBAUD) { + if (tty->termios.c_cflag & CBAUD) { sSetDTR(cp); sSetRTS(cp); } @@ -1089,35 +1089,35 @@ static void rp_set_termios(struct tty_struct *tty, if (rocket_paranoia_check(info, "rp_set_termios")) return; - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; /* * This driver doesn't support CS5 or CS6 */ if (((cflag & CSIZE) == CS5) || ((cflag & CSIZE) == CS6)) - tty->termios->c_cflag = + tty->termios.c_cflag = ((cflag & ~CSIZE) | (old_termios->c_cflag & CSIZE)); /* Or CMSPAR */ - tty->termios->c_cflag &= ~CMSPAR; + tty->termios.c_cflag &= ~CMSPAR; configure_r_port(tty, info, old_termios); cp = &info->channel; /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && !(tty->termios->c_cflag & CBAUD)) { + if ((old_termios->c_cflag & CBAUD) && !(tty->termios.c_cflag & CBAUD)) { sClrDTR(cp); sClrRTS(cp); } /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && (tty->termios->c_cflag & CBAUD)) { - if (!tty->hw_stopped || !(tty->termios->c_cflag & CRTSCTS)) + if (!(old_termios->c_cflag & CBAUD) && (tty->termios.c_cflag & CBAUD)) { + if (!tty->hw_stopped || !(tty->termios.c_cflag & CRTSCTS)) sSetRTS(cp); sSetDTR(cp); } - if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { + if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; rp_start(tty); } diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index 3ed20e435e59..66c38a3f74ce 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -515,7 +515,7 @@ static void change_speed(struct m68k_serial *info, struct tty_struct *tty) unsigned cflag; int i; - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; if (!(port = info->port)) return; @@ -617,7 +617,7 @@ static void rs_set_ldisc(struct tty_struct *tty) if (serial_paranoia_check(info, tty->name, "rs_set_ldisc")) return; - info->is_cons = (tty->termios->c_line == N_TTY); + info->is_cons = (tty->termios.c_line == N_TTY); printk("ttyS%d console mode %s\n", info->line, info->is_cons ? "on" : "off"); } @@ -985,7 +985,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) change_speed(info, tty); if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { + !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; rs_start(tty); } @@ -1070,7 +1070,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) if (tty->ldisc.close) (tty->ldisc.close)(tty); tty->ldisc = ldiscs[N_TTY]; - tty->termios->c_line = N_TTY; + tty->termios.c_line = N_TTY; if (tty->ldisc.open) (tty->ldisc.open)(tty); } @@ -1189,12 +1189,6 @@ rs68328_init(void) serial_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(serial_driver, &rs_ops); - if (tty_register_driver(serial_driver)) { - put_tty_driver(serial_driver); - printk(KERN_ERR "Couldn't register serial driver\n"); - return -ENOMEM; - } - local_irq_save(flags); for(i=0;i<NR_PORTS;i++) { @@ -1224,8 +1218,17 @@ rs68328_init(void) 0, "M68328_UART", info)) panic("Unable to attach 68328 serial interrupt\n"); + + tty_port_link_device(&info->tport, serial_driver, i); } local_irq_restore(flags); + + if (tty_register_driver(serial_driver)) { + put_tty_driver(serial_driver); + printk(KERN_ERR "Couldn't register serial driver\n"); + return -ENOMEM; + } + return 0; } diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index 8123f784bcda..d4e0b07cb130 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c @@ -2202,6 +2202,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, unsigned char cval, fcr = 0; unsigned long flags; unsigned int baud, quot; + int fifo_bug = 0; switch (termios->c_cflag & CSIZE) { case CS5: @@ -2221,8 +2222,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, if (termios->c_cflag & CSTOPB) cval |= UART_LCR_STOP; - if (termios->c_cflag & PARENB) + if (termios->c_cflag & PARENB) { cval |= UART_LCR_PARITY; + if (up->bugs & UART_BUG_PARITY) + fifo_bug = 1; + } if (!(termios->c_cflag & PARODD)) cval |= UART_LCR_EPAR; #ifdef CMSPAR @@ -2246,7 +2250,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) { fcr = uart_config[port->type].fcr; - if (baud < 2400) { + if (baud < 2400 || fifo_bug) { fcr &= ~UART_FCR_TRIGGER_MASK; fcr |= UART_FCR_TRIGGER_1; } @@ -2336,7 +2340,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, serial_port_out(port, UART_EFR, efr); } -#ifdef CONFIG_ARCH_OMAP +#ifdef CONFIG_ARCH_OMAP1 /* Workaround to enable 115200 baud on OMAP1510 internal ports */ if (cpu_is_omap1510() && is_omap_port(up)) { if (baud == 115200) { @@ -2426,7 +2430,7 @@ static unsigned int serial8250_port_size(struct uart_8250_port *pt) { if (pt->port.iotype == UPIO_AU) return 0x1000; -#ifdef CONFIG_ARCH_OMAP +#ifdef CONFIG_ARCH_OMAP1 if (is_omap_port(pt)) return 0x16 << pt->port.regshift; #endif @@ -2979,36 +2983,36 @@ void serial8250_resume_port(int line) static int __devinit serial8250_probe(struct platform_device *dev) { struct plat_serial8250_port *p = dev->dev.platform_data; - struct uart_port port; + struct uart_8250_port uart; int ret, i, irqflag = 0; - memset(&port, 0, sizeof(struct uart_port)); + memset(&uart, 0, sizeof(uart)); if (share_irqs) irqflag = IRQF_SHARED; for (i = 0; p && p->flags != 0; p++, i++) { - port.iobase = p->iobase; - port.membase = p->membase; - port.irq = p->irq; - port.irqflags = p->irqflags; - port.uartclk = p->uartclk; - port.regshift = p->regshift; - port.iotype = p->iotype; - port.flags = p->flags; - port.mapbase = p->mapbase; - port.hub6 = p->hub6; - port.private_data = p->private_data; - port.type = p->type; - port.serial_in = p->serial_in; - port.serial_out = p->serial_out; - port.handle_irq = p->handle_irq; - port.handle_break = p->handle_break; - port.set_termios = p->set_termios; - port.pm = p->pm; - port.dev = &dev->dev; - port.irqflags |= irqflag; - ret = serial8250_register_port(&port); + uart.port.iobase = p->iobase; + uart.port.membase = p->membase; + uart.port.irq = p->irq; + uart.port.irqflags = p->irqflags; + uart.port.uartclk = p->uartclk; + uart.port.regshift = p->regshift; + uart.port.iotype = p->iotype; + uart.port.flags = p->flags; + uart.port.mapbase = p->mapbase; + uart.port.hub6 = p->hub6; + uart.port.private_data = p->private_data; + uart.port.type = p->type; + uart.port.serial_in = p->serial_in; + uart.port.serial_out = p->serial_out; + uart.port.handle_irq = p->handle_irq; + uart.port.handle_break = p->handle_break; + uart.port.set_termios = p->set_termios; + uart.port.pm = p->pm; + uart.port.dev = &dev->dev; + uart.port.irqflags |= irqflag; + ret = serial8250_register_8250_port(&uart); if (ret < 0) { dev_err(&dev->dev, "unable to register port at index %d " "(IO%lx MEM%llx IRQ%d): %d\n", i, @@ -3081,7 +3085,7 @@ static struct platform_driver serial8250_isa_driver = { static struct platform_device *serial8250_isa_devs; /* - * serial8250_register_port and serial8250_unregister_port allows for + * serial8250_register_8250_port and serial8250_unregister_port allows for * 16x50 serial ports to be configured at run-time, to support PCMCIA * modems and PCI multiport cards. */ @@ -3155,6 +3159,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart->port.regshift = up->port.regshift; uart->port.iotype = up->port.iotype; uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF; + uart->bugs = up->bugs; uart->port.mapbase = up->port.mapbase; uart->port.private_data = up->port.private_data; if (up->port.dev) @@ -3198,29 +3203,6 @@ int serial8250_register_8250_port(struct uart_8250_port *up) EXPORT_SYMBOL(serial8250_register_8250_port); /** - * serial8250_register_port - register a serial port - * @port: serial port template - * - * Configure the serial port specified by the request. If the - * port exists and is in use, it is hung up and unregistered - * first. - * - * The port is then probed and if necessary the IRQ is autodetected - * If this fails an error is returned. - * - * On success the port is ready to use and the line number is returned. - */ -int serial8250_register_port(struct uart_port *port) -{ - struct uart_8250_port up; - - memset(&up, 0, sizeof(up)); - memcpy(&up.port, port, sizeof(*port)); - return serial8250_register_8250_port(&up); -} -EXPORT_SYMBOL(serial8250_register_port); - -/** * serial8250_unregister_port - remove a 16x50 serial port at runtime * @line: serial line number * diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index f9719d167c8d..0c5e908df0b5 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -13,36 +13,6 @@ #include <linux/serial_8250.h> -struct uart_8250_port { - struct uart_port port; - struct timer_list timer; /* "no irq" timer */ - struct list_head list; /* ports on this IRQ */ - unsigned short capabilities; /* port capabilities */ - unsigned short bugs; /* port bugs */ - unsigned int tx_loadsz; /* transmit fifo load size */ - unsigned char acr; - unsigned char ier; - unsigned char lcr; - unsigned char mcr; - unsigned char mcr_mask; /* mask of user bits */ - unsigned char mcr_force; /* mask of forced bits */ - unsigned char cur_iotype; /* Running I/O type */ - - /* - * Some bits in registers are cleared on a read, so they must - * be saved whenever the register is read but the bits will not - * be immediately processed. - */ -#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS - unsigned char lsr_saved_flags; -#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA - unsigned char msr_saved_flags; - - /* 8250 specific callbacks */ - int (*dl_read)(struct uart_8250_port *); - void (*dl_write)(struct uart_8250_port *, int); -}; - struct old_serial_port { unsigned int uart; unsigned int baud_base; @@ -56,9 +26,6 @@ struct old_serial_port { unsigned long irqflags; }; -/* - * This replaces serial_uart_config in include/linux/serial.h - */ struct serial8250_config { const char *name; unsigned short fifo_size; @@ -78,6 +45,7 @@ struct serial8250_config { #define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */ #define UART_BUG_NOMSR (1 << 2) /* UART has buggy MSR status bits (Au1x00) */ #define UART_BUG_THRE (1 << 3) /* UART has buggy THRE reassertion */ +#define UART_BUG_PARITY (1 << 4) /* UART mishandles parity if FIFO enabled */ #define PROBE_RSA (1 << 0) #define PROBE_ANY (~0) diff --git a/drivers/tty/serial/8250/8250_acorn.c b/drivers/tty/serial/8250/8250_acorn.c index b0ce8c56f1a4..857498312a9a 100644 --- a/drivers/tty/serial/8250/8250_acorn.c +++ b/drivers/tty/serial/8250/8250_acorn.c @@ -43,7 +43,7 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id) { struct serial_card_info *info; struct serial_card_type *type = id->data; - struct uart_port port; + struct uart_8250_port uart; unsigned long bus_addr; unsigned int i; @@ -62,19 +62,19 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id) ecard_set_drvdata(ec, info); - memset(&port, 0, sizeof(struct uart_port)); - port.irq = ec->irq; - port.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; - port.uartclk = type->uartclk; - port.iotype = UPIO_MEM; - port.regshift = 2; - port.dev = &ec->dev; + memset(&uart, 0, sizeof(struct uart_8250_port)); + uart.port.irq = ec->irq; + uart.port.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; + uart.port.uartclk = type->uartclk; + uart.port.iotype = UPIO_MEM; + uart.port.regshift = 2; + uart.port.dev = &ec->dev; for (i = 0; i < info->num_ports; i ++) { - port.membase = info->vaddr + type->offset[i]; - port.mapbase = bus_addr + type->offset[i]; + uart.port.membase = info->vaddr + type->offset[i]; + uart.port.mapbase = bus_addr + type->offset[i]; - info->ports[i] = serial8250_register_port(&port); + info->ports[i] = serial8250_register_8250_port(&uart); } return 0; diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index f574eef3075f..c3b2ec0c8c0b 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -89,7 +89,7 @@ static int dw8250_handle_irq(struct uart_port *p) static int __devinit dw8250_probe(struct platform_device *pdev) { - struct uart_port port = {}; + struct uart_8250_port uart = {}; struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); struct device_node *np = pdev->dev.of_node; @@ -104,28 +104,28 @@ static int __devinit dw8250_probe(struct platform_device *pdev) data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - port.private_data = data; - - spin_lock_init(&port.lock); - port.mapbase = regs->start; - port.irq = irq->start; - port.handle_irq = dw8250_handle_irq; - port.type = PORT_8250; - port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP | + uart.port.private_data = data; + + spin_lock_init(&uart.port.lock); + uart.port.mapbase = regs->start; + uart.port.irq = irq->start; + uart.port.handle_irq = dw8250_handle_irq; + uart.port.type = PORT_8250; + uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE; - port.dev = &pdev->dev; + uart.port.dev = &pdev->dev; - port.iotype = UPIO_MEM; - port.serial_in = dw8250_serial_in; - port.serial_out = dw8250_serial_out; + uart.port.iotype = UPIO_MEM; + uart.port.serial_in = dw8250_serial_in; + uart.port.serial_out = dw8250_serial_out; if (!of_property_read_u32(np, "reg-io-width", &val)) { switch (val) { case 1: break; case 4: - port.iotype = UPIO_MEM32; - port.serial_in = dw8250_serial_in32; - port.serial_out = dw8250_serial_out32; + uart.port.iotype = UPIO_MEM32; + uart.port.serial_in = dw8250_serial_in32; + uart.port.serial_out = dw8250_serial_out32; break; default: dev_err(&pdev->dev, "unsupported reg-io-width (%u)\n", @@ -135,15 +135,15 @@ static int __devinit dw8250_probe(struct platform_device *pdev) } if (!of_property_read_u32(np, "reg-shift", &val)) - port.regshift = val; + uart.port.regshift = val; if (of_property_read_u32(np, "clock-frequency", &val)) { dev_err(&pdev->dev, "no clock-frequency property set\n"); return -EINVAL; } - port.uartclk = val; + uart.port.uartclk = val; - data->line = serial8250_register_port(&port); + data->line = serial8250_register_8250_port(&uart); if (data->line < 0) return data->line; diff --git a/drivers/tty/serial/8250/8250_gsc.c b/drivers/tty/serial/8250/8250_gsc.c index d8c0ffbfa6e3..097dff9c08ad 100644 --- a/drivers/tty/serial/8250/8250_gsc.c +++ b/drivers/tty/serial/8250/8250_gsc.c @@ -26,7 +26,7 @@ static int __init serial_init_chip(struct parisc_device *dev) { - struct uart_port port; + struct uart_8250_port uart; unsigned long address; int err; @@ -48,21 +48,21 @@ static int __init serial_init_chip(struct parisc_device *dev) if (dev->id.sversion != 0x8d) address += 0x800; - memset(&port, 0, sizeof(port)); - port.iotype = UPIO_MEM; + memset(&uart, 0, sizeof(uart)); + uart.port.iotype = UPIO_MEM; /* 7.272727MHz on Lasi. Assumed the same for Dino, Wax and Timi. */ - port.uartclk = 7272727; - port.mapbase = address; - port.membase = ioremap_nocache(address, 16); - port.irq = dev->irq; - port.flags = UPF_BOOT_AUTOCONF; - port.dev = &dev->dev; - - err = serial8250_register_port(&port); + uart.port.uartclk = 7272727; + uart.port.mapbase = address; + uart.port.membase = ioremap_nocache(address, 16); + uart.port.irq = dev->irq; + uart.port.flags = UPF_BOOT_AUTOCONF; + uart.port.dev = &dev->dev; + + err = serial8250_register_8250_port(&uart); if (err < 0) { printk(KERN_WARNING - "serial8250_register_port returned error %d\n", err); - iounmap(port.membase); + "serial8250_register_8250_port returned error %d\n", err); + iounmap(uart.port.membase); return err; } diff --git a/drivers/tty/serial/8250/8250_hp300.c b/drivers/tty/serial/8250/8250_hp300.c index c13438c93012..8f1dd2cc00a8 100644 --- a/drivers/tty/serial/8250/8250_hp300.c +++ b/drivers/tty/serial/8250/8250_hp300.c @@ -171,7 +171,7 @@ static int __devinit hpdca_init_one(struct dio_dev *d, return 0; } #endif - memset(&port, 0, sizeof(struct uart_port)); + memset(&uart, 0, sizeof(uart)); /* Memory mapped I/O */ port.iotype = UPIO_MEM; @@ -182,7 +182,7 @@ static int __devinit hpdca_init_one(struct dio_dev *d, port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE); port.regshift = 1; port.dev = &d->dev; - line = serial8250_register_port(&port); + line = serial8250_register_8250_port(&uart); if (line < 0) { printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d" @@ -210,7 +210,7 @@ static int __init hp300_8250_init(void) #ifdef CONFIG_HPAPCI int line; unsigned long base; - struct uart_port uport; + struct uart_8250_port uart; struct hp300_port *port; int i; #endif @@ -248,26 +248,26 @@ static int __init hp300_8250_init(void) if (!port) return -ENOMEM; - memset(&uport, 0, sizeof(struct uart_port)); + memset(&uart, 0, sizeof(uart)); base = (FRODO_BASE + FRODO_APCI_OFFSET(i)); /* Memory mapped I/O */ - uport.iotype = UPIO_MEM; - uport.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \ + uart.port.iotype = UPIO_MEM; + uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \ | UPF_BOOT_AUTOCONF; /* XXX - no interrupt support yet */ - uport.irq = 0; - uport.uartclk = HPAPCI_BAUD_BASE * 16; - uport.mapbase = base; - uport.membase = (char *)(base + DIO_VIRADDRBASE); - uport.regshift = 2; + uart.port.irq = 0; + uart.port.uartclk = HPAPCI_BAUD_BASE * 16; + uart.port.mapbase = base; + uart.port.membase = (char *)(base + DIO_VIRADDRBASE); + uart.port.regshift = 2; - line = serial8250_register_port(&uport); + line = serial8250_register_8250_port(&uart); if (line < 0) { printk(KERN_NOTICE "8250_hp300: register_serial() APCI" - " %d irq %d failed\n", i, uport.irq); + " %d irq %d failed\n", i, uart.port.irq); kfree(port); continue; } diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 28e7c7cce893..fdab80a4e063 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -44,7 +44,7 @@ struct pci_serial_quirk { int (*init)(struct pci_dev *dev); int (*setup)(struct serial_private *, const struct pciserial_board *, - struct uart_port *, int); + struct uart_8250_port *, int); void (*exit)(struct pci_dev *dev); }; @@ -59,7 +59,7 @@ struct serial_private { }; static int pci_default_setup(struct serial_private*, - const struct pciserial_board*, struct uart_port*, int); + const struct pciserial_board*, struct uart_8250_port *, int); static void moan_device(const char *str, struct pci_dev *dev) { @@ -74,7 +74,7 @@ static void moan_device(const char *str, struct pci_dev *dev) } static int -setup_port(struct serial_private *priv, struct uart_port *port, +setup_port(struct serial_private *priv, struct uart_8250_port *port, int bar, int offset, int regshift) { struct pci_dev *dev = priv->dev; @@ -93,17 +93,17 @@ setup_port(struct serial_private *priv, struct uart_port *port, if (!priv->remapped_bar[bar]) return -ENOMEM; - port->iotype = UPIO_MEM; - port->iobase = 0; - port->mapbase = base + offset; - port->membase = priv->remapped_bar[bar] + offset; - port->regshift = regshift; + port->port.iotype = UPIO_MEM; + port->port.iobase = 0; + port->port.mapbase = base + offset; + port->port.membase = priv->remapped_bar[bar] + offset; + port->port.regshift = regshift; } else { - port->iotype = UPIO_PORT; - port->iobase = base + offset; - port->mapbase = 0; - port->membase = NULL; - port->regshift = 0; + port->port.iotype = UPIO_PORT; + port->port.iobase = base + offset; + port->port.mapbase = 0; + port->port.membase = NULL; + port->port.regshift = 0; } return 0; } @@ -113,7 +113,7 @@ setup_port(struct serial_private *priv, struct uart_port *port, */ static int addidata_apci7800_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { unsigned int bar = 0, offset = board->first_offset; bar = FL_GET_BASE(board->flags); @@ -140,7 +140,7 @@ static int addidata_apci7800_setup(struct serial_private *priv, */ static int afavlab_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { unsigned int bar, offset = board->first_offset; @@ -195,7 +195,7 @@ static int pci_hp_diva_init(struct pci_dev *dev) static int pci_hp_diva_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { unsigned int offset = board->first_offset; unsigned int bar = FL_GET_BASE(board->flags); @@ -370,7 +370,7 @@ static void __devexit pci_ni8430_exit(struct pci_dev *dev) /* SBS Technologies Inc. PMC-OCTPRO and P-OCTAL cards */ static int sbs_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { unsigned int bar, offset = board->first_offset; @@ -525,7 +525,7 @@ static int pci_siig_init(struct pci_dev *dev) static int pci_siig_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { unsigned int bar = FL_GET_BASE(board->flags) + idx, offset = 0; @@ -619,7 +619,7 @@ static int pci_timedia_init(struct pci_dev *dev) static int pci_timedia_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { unsigned int bar = 0, offset = board->first_offset; @@ -653,7 +653,7 @@ pci_timedia_setup(struct serial_private *priv, static int titan_400l_800l_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { unsigned int bar, offset = board->first_offset; @@ -754,7 +754,7 @@ static int pci_ni8430_init(struct pci_dev *dev) static int pci_ni8430_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { void __iomem *p; unsigned long base, len; @@ -781,7 +781,7 @@ pci_ni8430_setup(struct serial_private *priv, static int pci_netmos_9900_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { unsigned int bar; @@ -1032,10 +1032,17 @@ static int pci_oxsemi_tornado_init(struct pci_dev *dev) return number_uarts; } -static int -pci_default_setup(struct serial_private *priv, +static int pci_asix_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) +{ + port->bugs |= UART_BUG_PARITY; + return pci_default_setup(priv, board, port, idx); +} + +static int pci_default_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) { unsigned int bar, offset = board->first_offset, maxnr; @@ -1057,15 +1064,15 @@ pci_default_setup(struct serial_private *priv, static int ce4100_serial_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { int ret; ret = setup_port(priv, port, 0, 0, board->reg_shift); - port->iotype = UPIO_MEM32; - port->type = PORT_XSCALE; - port->flags = (port->flags | UPF_FIXED_PORT | UPF_FIXED_TYPE); - port->regshift = 2; + port->port.iotype = UPIO_MEM32; + port->port.type = PORT_XSCALE; + port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE); + port->port.regshift = 2; return ret; } @@ -1073,16 +1080,16 @@ ce4100_serial_setup(struct serial_private *priv, static int pci_omegapci_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { return setup_port(priv, port, 2, idx * 8, 0); } static int skip_tx_en_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { - port->flags |= UPF_NO_TXEN_TEST; + port->port.flags |= UPF_NO_TXEN_TEST; printk(KERN_DEBUG "serial8250: skipping TxEn test for device " "[%04x:%04x] subsystem [%04x:%04x]\n", priv->dev->vendor, @@ -1131,11 +1138,11 @@ static unsigned int kt_serial_in(struct uart_port *p, int offset) static int kt_serial_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { - port->flags |= UPF_BUG_THRE; - port->serial_in = kt_serial_in; - port->handle_break = kt_handle_break; + port->port.flags |= UPF_BUG_THRE; + port->port.serial_in = kt_serial_in; + port->port.handle_break = kt_handle_break; return skip_tx_en_setup(priv, board, port, idx); } @@ -1151,9 +1158,19 @@ static int pci_eg20t_init(struct pci_dev *dev) static int pci_xr17c154_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) +{ + port->port.flags |= UPF_EXAR_EFR; + return pci_default_setup(priv, board, port, idx); +} + +static int +pci_wch_ch353_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) { - port->flags |= UPF_EXAR_EFR; + port->port.flags |= UPF_FIXED_TYPE; + port->port.type = PORT_16550A; return pci_default_setup(priv, board, port, idx); } @@ -1187,6 +1204,13 @@ pci_xr17c154_setup(struct serial_private *priv, #define PCIE_DEVICE_ID_NEO_2_OX_IBM 0x00F6 #define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001 #define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d +#define PCI_VENDOR_ID_WCH 0x4348 +#define PCI_DEVICE_ID_WCH_CH353_4S 0x3453 +#define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046 +#define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053 +#define PCI_VENDOR_ID_AGESTAR 0x5372 +#define PCI_DEVICE_ID_AGESTAR_9375 0x6872 +#define PCI_VENDOR_ID_ASIX 0x9710 /* Unknown vendors/cards - this should not be in linux/pci_ids.h */ #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 @@ -1726,7 +1750,41 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = pci_omegapci_setup, - }, + }, + /* WCH CH353 2S1P card (16550 clone) */ + { + .vendor = PCI_VENDOR_ID_WCH, + .device = PCI_DEVICE_ID_WCH_CH353_2S1P, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_wch_ch353_setup, + }, + /* WCH CH353 4S card (16550 clone) */ + { + .vendor = PCI_VENDOR_ID_WCH, + .device = PCI_DEVICE_ID_WCH_CH353_4S, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_wch_ch353_setup, + }, + /* WCH CH353 2S1PF card (16550 clone) */ + { + .vendor = PCI_VENDOR_ID_WCH, + .device = PCI_DEVICE_ID_WCH_CH353_2S1PF, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_wch_ch353_setup, + }, + /* + * ASIX devices with FIFO bug + */ + { + .vendor = PCI_VENDOR_ID_ASIX, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_asix_setup, + }, /* * Default "match everything" terminator entry */ @@ -1887,7 +1945,6 @@ enum pci_board_num_t { pbn_panacom, pbn_panacom2, pbn_panacom4, - pbn_exsys_4055, pbn_plx_romulus, pbn_oxsemi, pbn_oxsemi_1_4000000, @@ -2393,13 +2450,6 @@ static struct pciserial_board pci_boards[] __devinitdata = { .reg_shift = 7, }, - [pbn_exsys_4055] = { - .flags = FL_BASE2, - .num_ports = 4, - .base_baud = 115200, - .uart_offset = 8, - }, - /* I think this entry is broken - the first_offset looks wrong --rmk */ [pbn_plx_romulus] = { .flags = FL_BASE2, @@ -2624,10 +2674,14 @@ static struct pciserial_board pci_boards[] __devinitdata = { }, }; -static const struct pci_device_id softmodem_blacklist[] = { +static const struct pci_device_id blacklist[] = { + /* softmodems */ { PCI_VDEVICE(AL, 0x5457), }, /* ALi Corporation M5457 AC'97 Modem */ { PCI_VDEVICE(MOTOROLA, 0x3052), }, /* Motorola Si3052-based modem */ { PCI_DEVICE(0x1543, 0x3052), }, /* Si3052-based modem, default IDs */ + + /* multi-io cards handled by parport_serial */ + { PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */ }; /* @@ -2638,7 +2692,7 @@ static const struct pci_device_id softmodem_blacklist[] = { static int __devinit serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board) { - const struct pci_device_id *blacklist; + const struct pci_device_id *bldev; int num_iomem, num_port, first_port = -1, i; /* @@ -2655,13 +2709,13 @@ serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board) /* * Do not access blacklisted devices that are known not to - * feature serial ports. + * feature serial ports or are handled by other modules. */ - for (blacklist = softmodem_blacklist; - blacklist < softmodem_blacklist + ARRAY_SIZE(softmodem_blacklist); - blacklist++) { - if (dev->vendor == blacklist->vendor && - dev->device == blacklist->device) + for (bldev = blacklist; + bldev < blacklist + ARRAY_SIZE(blacklist); + bldev++) { + if (dev->vendor == bldev->vendor && + dev->device == bldev->device) return -ENODEV; } @@ -2728,7 +2782,7 @@ serial_pci_matches(const struct pciserial_board *board, struct serial_private * pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) { - struct uart_port serial_port; + struct uart_8250_port uart; struct serial_private *priv; struct pci_serial_quirk *quirk; int rc, nr_ports, i; @@ -2768,22 +2822,22 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) priv->dev = dev; priv->quirk = quirk; - memset(&serial_port, 0, sizeof(struct uart_port)); - serial_port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; - serial_port.uartclk = board->base_baud * 16; - serial_port.irq = get_pci_irq(dev, board); - serial_port.dev = &dev->dev; + memset(&uart, 0, sizeof(uart)); + uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; + uart.port.uartclk = board->base_baud * 16; + uart.port.irq = get_pci_irq(dev, board); + uart.port.dev = &dev->dev; for (i = 0; i < nr_ports; i++) { - if (quirk->setup(priv, board, &serial_port, i)) + if (quirk->setup(priv, board, &uart, i)) break; #ifdef SERIAL_DEBUG_PCI printk(KERN_DEBUG "Setup PCI port: port %lx, irq %d, type %d\n", - serial_port.iobase, serial_port.irq, serial_port.iotype); + uart.port.iobase, uart.port.irq, uart.port.iotype); #endif - priv->line[i] = serial8250_register_port(&serial_port); + priv->line[i] = serial8250_register_8250_port(&uart); if (priv->line[i] < 0) { printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), priv->line[i]); break; @@ -3193,7 +3247,7 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_EXSYS, PCI_SUBDEVICE_ID_EXSYS_4055, 0, 0, - pbn_exsys_4055 }, + pbn_b2_4_115200 }, /* * Megawolf Romulus PCI Serial Card, from Mike Hudson * (Exoray@isys.ca) @@ -4179,6 +4233,25 @@ static struct pci_device_id serial_pci_tbl[] = { pbn_omegapci }, /* + * AgeStar as-prs2-009 + */ + { PCI_VENDOR_ID_AGESTAR, PCI_DEVICE_ID_AGESTAR_9375, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, pbn_b0_bt_2_115200 }, + + /* + * WCH CH353 series devices: The 2S1P is handled by parport_serial + * so not listed here. + */ + { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH353_4S, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, pbn_b0_bt_4_115200 }, + + { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH353_2S1PF, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, pbn_b0_bt_2_115200 }, + + /* * These entries match devices with class COMMUNICATION_SERIAL, * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL */ diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c index a2f236510ff1..fde5aa60d51e 100644 --- a/drivers/tty/serial/8250/8250_pnp.c +++ b/drivers/tty/serial/8250/8250_pnp.c @@ -424,7 +424,7 @@ static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags) static int __devinit serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) { - struct uart_port port; + struct uart_8250_port uart; int ret, line, flags = dev_id->driver_data; if (flags & UNKNOWN_DEV) { @@ -433,32 +433,32 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) return ret; } - memset(&port, 0, sizeof(struct uart_port)); + memset(&uart, 0, sizeof(uart)); if (pnp_irq_valid(dev, 0)) - port.irq = pnp_irq(dev, 0); + uart.port.irq = pnp_irq(dev, 0); if (pnp_port_valid(dev, 0)) { - port.iobase = pnp_port_start(dev, 0); - port.iotype = UPIO_PORT; + uart.port.iobase = pnp_port_start(dev, 0); + uart.port.iotype = UPIO_PORT; } else if (pnp_mem_valid(dev, 0)) { - port.mapbase = pnp_mem_start(dev, 0); - port.iotype = UPIO_MEM; - port.flags = UPF_IOREMAP; + uart.port.mapbase = pnp_mem_start(dev, 0); + uart.port.iotype = UPIO_MEM; + uart.port.flags = UPF_IOREMAP; } else return -ENODEV; #ifdef SERIAL_DEBUG_PNP printk(KERN_DEBUG "Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n", - port.iobase, port.mapbase, port.irq, port.iotype); + uart.port.iobase, uart.port.mapbase, uart.port.irq, uart.port.iotype); #endif - port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; + uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE) - port.flags |= UPF_SHARE_IRQ; - port.uartclk = 1843200; - port.dev = &dev->dev; + uart.port.flags |= UPF_SHARE_IRQ; + uart.port.uartclk = 1843200; + uart.port.dev = &dev->dev; - line = serial8250_register_port(&port); + line = serial8250_register_8250_port(&uart); if (line < 0) return -ENODEV; diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c index 29b695d041ec..b7d48b346393 100644 --- a/drivers/tty/serial/8250/serial_cs.c +++ b/drivers/tty/serial/8250/serial_cs.c @@ -73,7 +73,7 @@ struct serial_quirk { unsigned int prodid; int multi; /* 1 = multifunction, > 1 = # ports */ void (*config)(struct pcmcia_device *); - void (*setup)(struct pcmcia_device *, struct uart_port *); + void (*setup)(struct pcmcia_device *, struct uart_8250_port *); void (*wakeup)(struct pcmcia_device *); int (*post)(struct pcmcia_device *); }; @@ -105,9 +105,9 @@ struct serial_cfg_mem { * Elan VPU16551 UART with 14.7456MHz oscillator * manfid 0x015D, 0x4C45 */ -static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_port *port) +static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_8250_port *uart) { - port->uartclk = 14745600; + uart->port.uartclk = 14745600; } static int quirk_post_ibm(struct pcmcia_device *link) @@ -343,25 +343,25 @@ static void serial_detach(struct pcmcia_device *link) static int setup_serial(struct pcmcia_device *handle, struct serial_info * info, unsigned int iobase, int irq) { - struct uart_port port; + struct uart_8250_port uart; int line; - memset(&port, 0, sizeof (struct uart_port)); - port.iobase = iobase; - port.irq = irq; - port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ; - port.uartclk = 1843200; - port.dev = &handle->dev; + memset(&uart, 0, sizeof(uart)); + uart.port.iobase = iobase; + uart.port.irq = irq; + uart.port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ; + uart.port.uartclk = 1843200; + uart.port.dev = &handle->dev; if (buggy_uart) - port.flags |= UPF_BUGGY_UART; + uart.port.flags |= UPF_BUGGY_UART; if (info->quirk && info->quirk->setup) - info->quirk->setup(handle, &port); + info->quirk->setup(handle, &uart); - line = serial8250_register_port(&port); + line = serial8250_register_8250_port(&uart); if (line < 0) { - printk(KERN_NOTICE "serial_cs: serial8250_register_port() at " - "0x%04lx, irq %d failed\n", (u_long)iobase, irq); + pr_err("serial_cs: serial8250_register_8250_port() at 0x%04lx, irq %d failed\n", + (unsigned long)iobase, irq); return -EINVAL; } diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 4720b4ba096a..26907cf25744 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -257,12 +257,19 @@ config SERIAL_MAX3100 help MAX3100 chip support -config SERIAL_MAX3107 - tristate "MAX3107 support" +config SERIAL_MAX310X + bool "MAX310X support" depends on SPI select SERIAL_CORE + select REGMAP_SPI if SPI + default n help - MAX3107 chip support + This selects support for an advanced UART from Maxim (Dallas). + Supported ICs are MAX3107, MAX3108. + Each IC contains 128 words each of receive and transmit FIFO + that can be controlled through I2C or high-speed SPI. + + Say Y here if you want to support this ICs. config SERIAL_DZ bool "DECstation DZ serial driver" @@ -704,6 +711,25 @@ config SERIAL_PNX8XXX_CONSOLE If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330 and you want to use serial console, say Y. Otherwise, say N. +config SERIAL_HS_LPC32XX + tristate "LPC32XX high speed serial port support" + depends on ARCH_LPC32XX && OF + select SERIAL_CORE + help + Support for the LPC32XX high speed serial ports (up to 900kbps). + Those are UARTs completely different from the Standard UARTs on the + LPC32XX SoC. + Choose M or Y here to build this driver. + +config SERIAL_HS_LPC32XX_CONSOLE + bool "Enable LPC32XX high speed UART serial console" + depends on SERIAL_HS_LPC32XX + select SERIAL_CORE_CONSOLE + help + If you would like to be able to use one of the high speed serial + ports on the LPC32XX as the console, you can do so by answering + Y to this option. + config SERIAL_CORE tristate @@ -1104,6 +1130,24 @@ config SERIAL_SC26XX_CONSOLE help Support for Console on SC2681/SC2692 serial ports. +config SERIAL_SCCNXP + bool "SCCNXP serial port support" + depends on !SERIAL_SC26XX + select SERIAL_CORE + default n + help + This selects support for an advanced UART from NXP (Philips). + Supported ICs are SCC2681, SCC2691, SCC2692, SC28L91, SC28L92, + SC28L202, SCC68681 and SCC68692. + Positioned as a replacement for the driver SC26XX. + +config SERIAL_SCCNXP_CONSOLE + bool "Console on SCCNXP serial port" + depends on SERIAL_SCCNXP + select SERIAL_CORE_CONSOLE + help + Support for console on SCCNXP serial ports. + config SERIAL_BFIN_SPORT tristate "Blackfin SPORT emulate UART" depends on BLACKFIN diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 7257c5d898ae..ce88667cfd17 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -28,12 +28,13 @@ obj-$(CONFIG_SERIAL_BFIN) += bfin_uart.o obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o obj-$(CONFIG_SERIAL_MAX3100) += max3100.o -obj-$(CONFIG_SERIAL_MAX3107) += max3107.o +obj-$(CONFIG_SERIAL_MAX310X) += max310x.o obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o obj-$(CONFIG_SERIAL_MUX) += mux.o obj-$(CONFIG_SERIAL_68328) += 68328serial.o obj-$(CONFIG_SERIAL_MCF) += mcf.o obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o +obj-$(CONFIG_SERIAL_HS_LPC32XX) += lpc32xx_hs.o obj-$(CONFIG_SERIAL_DZ) += dz.o obj-$(CONFIG_SERIAL_ZS) += zs.o obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o @@ -47,6 +48,7 @@ obj-$(CONFIG_SERIAL_MPSC) += mpsc.o obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o obj-$(CONFIG_SERIAL_SC26XX) += sc26xx.o +obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o obj-$(CONFIG_SERIAL_JSM) += jsm/ obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 1f0330915d5a..15d80b9fb303 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -591,7 +591,7 @@ static int __devinit altera_uart_probe(struct platform_device *pdev) port->ops = &altera_uart_ops; port->flags = UPF_BOOT_AUTOCONF; - dev_set_drvdata(&pdev->dev, port); + platform_set_drvdata(pdev, port); uart_add_one_port(&altera_uart_driver, port); @@ -600,11 +600,11 @@ static int __devinit altera_uart_probe(struct platform_device *pdev) static int __devexit altera_uart_remove(struct platform_device *pdev) { - struct uart_port *port = dev_get_drvdata(&pdev->dev); + struct uart_port *port = platform_get_drvdata(pdev); if (port) { uart_remove_one_port(&altera_uart_driver, port); - dev_set_drvdata(&pdev->dev, NULL); + platform_set_drvdata(pdev, NULL); port->mapbase = 0; } diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index 0d91a540bf11..22317dd16474 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -312,16 +312,12 @@ static int pl010_startup(struct uart_port *port) struct uart_amba_port *uap = (struct uart_amba_port *)port; int retval; - retval = clk_prepare(uap->clk); - if (retval) - goto out; - /* * Try to enable the clock producer. */ - retval = clk_enable(uap->clk); + retval = clk_prepare_enable(uap->clk); if (retval) - goto clk_unprep; + goto out; uap->port.uartclk = clk_get_rate(uap->clk); @@ -346,9 +342,7 @@ static int pl010_startup(struct uart_port *port) return 0; clk_dis: - clk_disable(uap->clk); - clk_unprep: - clk_unprepare(uap->clk); + clk_disable_unprepare(uap->clk); out: return retval; } @@ -375,8 +369,7 @@ static void pl010_shutdown(struct uart_port *port) /* * Shut down the clock producer */ - clk_disable(uap->clk); - clk_unprepare(uap->clk); + clk_disable_unprepare(uap->clk); } static void diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index d3553b5d3fca..cede93876649 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -52,6 +52,8 @@ #include <linux/scatterlist.h> #include <linux/delay.h> #include <linux/types.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/pinctrl/consumer.h> #include <linux/sizes.h> @@ -75,7 +77,6 @@ struct vendor_data { unsigned int lcrh_tx; unsigned int lcrh_rx; bool oversampling; - bool interrupt_may_hang; /* vendor-specific */ bool dma_threshold; bool cts_event_workaround; }; @@ -96,7 +97,6 @@ static struct vendor_data vendor_st = { .lcrh_tx = ST_UART011_LCRH_TX, .lcrh_rx = ST_UART011_LCRH_RX, .oversampling = true, - .interrupt_may_hang = true, .dma_threshold = true, .cts_event_workaround = true, }; @@ -147,7 +147,6 @@ struct uart_amba_port { unsigned int old_cr; /* state during shutdown */ bool autorts; char type[12]; - bool interrupt_may_hang; /* vendor-specific */ #ifdef CONFIG_DMA_ENGINE /* DMA stuff */ bool using_tx_dma; @@ -1215,14 +1214,14 @@ static irqreturn_t pl011_int(int irq, void *dev_id) return IRQ_RETVAL(handled); } -static unsigned int pl01x_tx_empty(struct uart_port *port) +static unsigned int pl011_tx_empty(struct uart_port *port) { struct uart_amba_port *uap = (struct uart_amba_port *)port; unsigned int status = readw(uap->port.membase + UART01x_FR); return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT; } -static unsigned int pl01x_get_mctrl(struct uart_port *port) +static unsigned int pl011_get_mctrl(struct uart_port *port) { struct uart_amba_port *uap = (struct uart_amba_port *)port; unsigned int result = 0; @@ -1285,7 +1284,7 @@ static void pl011_break_ctl(struct uart_port *port, int break_state) } #ifdef CONFIG_CONSOLE_POLL -static int pl010_get_poll_char(struct uart_port *port) +static int pl011_get_poll_char(struct uart_port *port) { struct uart_amba_port *uap = (struct uart_amba_port *)port; unsigned int status; @@ -1297,7 +1296,7 @@ static int pl010_get_poll_char(struct uart_port *port) return readw(uap->port.membase + UART01x_DR); } -static void pl010_put_poll_char(struct uart_port *port, +static void pl011_put_poll_char(struct uart_port *port, unsigned char ch) { struct uart_amba_port *uap = (struct uart_amba_port *)port; @@ -1324,16 +1323,12 @@ static int pl011_startup(struct uart_port *port) "could not set default pins\n"); } - retval = clk_prepare(uap->clk); - if (retval) - goto out; - /* * Try to enable the clock producer. */ - retval = clk_enable(uap->clk); + retval = clk_prepare_enable(uap->clk); if (retval) - goto clk_unprep; + goto out; uap->port.uartclk = clk_get_rate(uap->clk); @@ -1411,9 +1406,7 @@ static int pl011_startup(struct uart_port *port) return 0; clk_dis: - clk_disable(uap->clk); - clk_unprep: - clk_unprepare(uap->clk); + clk_disable_unprepare(uap->clk); out: return retval; } @@ -1473,8 +1466,7 @@ static void pl011_shutdown(struct uart_port *port) /* * Shut down the clock producer */ - clk_disable(uap->clk); - clk_unprepare(uap->clk); + clk_disable_unprepare(uap->clk); /* Optionally let pins go into sleep states */ if (!IS_ERR(uap->pins_sleep)) { retval = pinctrl_select_state(uap->pinctrl, uap->pins_sleep); @@ -1637,7 +1629,7 @@ static const char *pl011_type(struct uart_port *port) /* * Release the memory region(s) being used by 'port' */ -static void pl010_release_port(struct uart_port *port) +static void pl011_release_port(struct uart_port *port) { release_mem_region(port->mapbase, SZ_4K); } @@ -1645,7 +1637,7 @@ static void pl010_release_port(struct uart_port *port) /* * Request the memory region(s) being used by 'port' */ -static int pl010_request_port(struct uart_port *port) +static int pl011_request_port(struct uart_port *port) { return request_mem_region(port->mapbase, SZ_4K, "uart-pl011") != NULL ? 0 : -EBUSY; @@ -1654,18 +1646,18 @@ static int pl010_request_port(struct uart_port *port) /* * Configure/autoconfigure the port. */ -static void pl010_config_port(struct uart_port *port, int flags) +static void pl011_config_port(struct uart_port *port, int flags) { if (flags & UART_CONFIG_TYPE) { port->type = PORT_AMBA; - pl010_request_port(port); + pl011_request_port(port); } } /* * verify the new serial_struct (for TIOCSSERIAL). */ -static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser) +static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser) { int ret = 0; if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA) @@ -1678,9 +1670,9 @@ static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser) } static struct uart_ops amba_pl011_pops = { - .tx_empty = pl01x_tx_empty, + .tx_empty = pl011_tx_empty, .set_mctrl = pl011_set_mctrl, - .get_mctrl = pl01x_get_mctrl, + .get_mctrl = pl011_get_mctrl, .stop_tx = pl011_stop_tx, .start_tx = pl011_start_tx, .stop_rx = pl011_stop_rx, @@ -1691,13 +1683,13 @@ static struct uart_ops amba_pl011_pops = { .flush_buffer = pl011_dma_flush_buffer, .set_termios = pl011_set_termios, .type = pl011_type, - .release_port = pl010_release_port, - .request_port = pl010_request_port, - .config_port = pl010_config_port, - .verify_port = pl010_verify_port, + .release_port = pl011_release_port, + .request_port = pl011_request_port, + .config_port = pl011_config_port, + .verify_port = pl011_verify_port, #ifdef CONFIG_CONSOLE_POLL - .poll_get_char = pl010_get_poll_char, - .poll_put_char = pl010_put_poll_char, + .poll_get_char = pl011_get_poll_char, + .poll_put_char = pl011_put_poll_char, #endif }; @@ -1869,6 +1861,38 @@ static struct uart_driver amba_reg = { .cons = AMBA_CONSOLE, }; +static int pl011_probe_dt_alias(int index, struct device *dev) +{ + struct device_node *np; + static bool seen_dev_with_alias = false; + static bool seen_dev_without_alias = false; + int ret = index; + + if (!IS_ENABLED(CONFIG_OF)) + return ret; + + np = dev->of_node; + if (!np) + return ret; + + ret = of_alias_get_id(np, "serial"); + if (IS_ERR_VALUE(ret)) { + seen_dev_without_alias = true; + ret = index; + } else { + seen_dev_with_alias = true; + if (ret >= ARRAY_SIZE(amba_ports) || amba_ports[ret] != NULL) { + dev_warn(dev, "requested serial port %d not available.\n", ret); + ret = index; + } + } + + if (seen_dev_with_alias && seen_dev_without_alias) + dev_warn(dev, "aliased and non-aliased serial devices found in device tree. Serial port enumeration may be unpredictable.\n"); + + return ret; +} + static int pl011_probe(struct amba_device *dev, const struct amba_id *id) { struct uart_amba_port *uap; @@ -1891,6 +1915,8 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) goto out; } + i = pl011_probe_dt_alias(i, &dev->dev); + base = ioremap(dev->res.start, resource_size(&dev->res)); if (!base) { ret = -ENOMEM; @@ -1923,7 +1949,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) uap->lcrh_tx = vendor->lcrh_tx; uap->old_cr = 0; uap->fifosize = vendor->fifosize; - uap->interrupt_may_hang = vendor->interrupt_may_hang; uap->port.dev = &dev->dev; uap->port.mapbase = dev->res.start; uap->port.membase = base; diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c index bd97db23985b..9242d56ba267 100644 --- a/drivers/tty/serial/bfin_uart.c +++ b/drivers/tty/serial/bfin_uart.c @@ -182,7 +182,7 @@ static void bfin_serial_start_tx(struct uart_port *port) * To avoid losting RX interrupt, we reset IR function * before sending data. */ - if (tty->termios->c_line == N_IRDA) + if (tty->termios.c_line == N_IRDA) bfin_serial_reset_irda(port); #ifdef CONFIG_SERIAL_BFIN_DMA diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 80b6b1b1f725..35ee6a2c6877 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -955,7 +955,7 @@ static const struct control_pins e100_modem_pins[NR_PORTS] = /* Calculate the chartime depending on baudrate, numbor of bits etc. */ static void update_char_time(struct e100_serial * info) { - tcflag_t cflags = info->port.tty->termios->c_cflag; + tcflag_t cflags = info->port.tty->termios.c_cflag; int bits; /* calc. number of bits / data byte */ @@ -1473,7 +1473,7 @@ rs_stop(struct tty_struct *tty) xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->port.tty)); xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop); - if (tty->termios->c_iflag & IXON ) { + if (tty->termios.c_iflag & IXON ) { xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); } @@ -1496,7 +1496,7 @@ rs_start(struct tty_struct *tty) info->xmit.tail,SERIAL_XMIT_SIZE))); xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty)); xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable); - if (tty->termios->c_iflag & IXON ) { + if (tty->termios.c_iflag & IXON ) { xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); } @@ -2929,7 +2929,7 @@ shutdown(struct e100_serial * info) descr[i].buf = 0; } - if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) { + if (!info->port.tty || (info->port.tty->termios.c_cflag & HUPCL)) { /* hang up DTR and RTS if HUPCL is enabled */ e100_dtr(info, 0); e100_rts(info, 0); /* could check CRTSCTS before doing this */ @@ -2953,12 +2953,12 @@ change_speed(struct e100_serial *info) unsigned long flags; /* first some safety checks */ - if (!info->port.tty || !info->port.tty->termios) + if (!info->port.tty) return; if (!info->ioport) return; - cflag = info->port.tty->termios->c_cflag; + cflag = info->port.tty->termios.c_cflag; /* possibly, the tx/rx should be disabled first to do this safely */ @@ -3088,7 +3088,7 @@ change_speed(struct e100_serial *info) info->ioport[REG_REC_CTRL] = info->rx_ctrl; xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->port.tty)); xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable); - if (info->port.tty->termios->c_iflag & IXON ) { + if (info->port.tty->termios.c_iflag & IXON ) { DFLOW(DEBUG_LOG(info->line, "FLOW XOFF enabled 0x%02X\n", STOP_CHAR(info->port.tty))); xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); @@ -3355,7 +3355,7 @@ rs_throttle(struct tty_struct * tty) DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty))); /* Do RTS before XOFF since XOFF might take some time */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { /* Turn off RTS line */ e100_rts(info, 0); } @@ -3377,7 +3377,7 @@ rs_unthrottle(struct tty_struct * tty) DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty))); DFLOW(DEBUG_LOG(info->line,"rs_unthrottle flip.count: %i\n", tty->flip.count)); /* Do RTS before XOFF since XOFF might take some time */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { /* Assert RTS line */ e100_rts(info, 1); } @@ -3748,7 +3748,7 @@ rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) /* Handle turning off CRTSCTS */ if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { + !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; rs_start(tty); } @@ -3815,7 +3815,7 @@ rs_close(struct tty_struct *tty, struct file * filp) * separate termios for callout and dialin. */ if (info->flags & ASYNC_NORMAL_ACTIVE) - info->normal_termios = *tty->termios; + info->normal_termios = tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -3976,7 +3976,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, */ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { - wait_event_interruptible_tty(info->close_wait, + wait_event_interruptible_tty(tty, info->close_wait, !(info->flags & ASYNC_CLOSING)); #ifdef SERIAL_DO_RESTART if (info->flags & ASYNC_HUP_NOTIFY) @@ -3998,7 +3998,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, return 0; } - if (tty->termios->c_cflag & CLOCAL) { + if (tty->termios.c_cflag & CLOCAL) { do_clocal = 1; } @@ -4052,9 +4052,9 @@ block_til_ready(struct tty_struct *tty, struct file * filp, printk("block_til_ready blocking: ttyS%d, count = %d\n", info->line, info->count); #endif - tty_unlock(); + tty_unlock(tty); schedule(); - tty_lock(); + tty_lock(tty); } set_current_state(TASK_RUNNING); remove_wait_queue(&info->open_wait, &wait); @@ -4115,7 +4115,7 @@ rs_open(struct tty_struct *tty, struct file * filp) */ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { - wait_event_interruptible_tty(info->close_wait, + wait_event_interruptible_tty(tty, info->close_wait, !(info->flags & ASYNC_CLOSING)); #ifdef SERIAL_DO_RESTART return ((info->flags & ASYNC_HUP_NOTIFY) ? @@ -4219,7 +4219,7 @@ rs_open(struct tty_struct *tty, struct file * filp) } if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { - *tty->termios = info->normal_termios; + tty->termios = info->normal_termios; change_speed(info); } @@ -4443,14 +4443,12 @@ static int __init rs_init(void) B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */ driver->init_termios.c_ispeed = 115200; driver->init_termios.c_ospeed = 115200; - driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(driver, &rs_ops); serial_driver = driver; - if (tty_register_driver(driver)) - panic("Couldn't register serial driver\n"); - /* do some initializing for the separate ports */ + /* do some initializing for the separate ports */ for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) { if (info->enabled) { if (cris_request_io_interface(info->io_if, @@ -4502,7 +4500,12 @@ static int __init rs_init(void) printk(KERN_INFO "%s%d at %p is a builtin UART with DMA\n", serial_driver->name, info->line, info->ioport); } + tty_port_link_device(&info->port, driver, i); } + + if (tty_register_driver(driver)) + panic("Couldn't register serial driver\n"); + #ifdef CONFIG_ETRAX_FAST_TIMER #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER memset(fast_timers, 0, sizeof(fast_timers)); diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c index 3ad079ffd049..5b9bc19ed134 100644 --- a/drivers/tty/serial/ifx6x60.c +++ b/drivers/tty/serial/ifx6x60.c @@ -800,8 +800,8 @@ static int ifx_spi_create_port(struct ifx_spi_device *ifx_dev) tty_port_init(pport); pport->ops = &ifx_tty_port_ops; ifx_dev->minor = IFX_SPI_TTY_ID; - ifx_dev->tty_dev = tty_register_device(tty_drv, ifx_dev->minor, - &ifx_dev->spi_dev->dev); + ifx_dev->tty_dev = tty_port_register_device(pport, tty_drv, + ifx_dev->minor, &ifx_dev->spi_dev->dev); if (IS_ERR(ifx_dev->tty_dev)) { dev_dbg(&ifx_dev->spi_dev->dev, "%s: registering tty device failed", __func__); diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index e309e8b0aaba..5952b25c288e 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -207,7 +207,7 @@ struct imx_port { unsigned short trcv_delay; /* transceiver delay */ struct clk *clk_ipg; struct clk *clk_per; - struct imx_uart_data *devdata; + const struct imx_uart_data *devdata; }; struct imx_port_ucrs { @@ -1505,18 +1505,21 @@ static int serial_imx_probe(struct platform_device *pdev) pinctrl = devm_pinctrl_get_select_default(&pdev->dev); if (IS_ERR(pinctrl)) { ret = PTR_ERR(pinctrl); + dev_err(&pdev->dev, "failed to get default pinctrl: %d\n", ret); goto unmap; } sport->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(sport->clk_ipg)) { ret = PTR_ERR(sport->clk_ipg); + dev_err(&pdev->dev, "failed to get ipg clk: %d\n", ret); goto unmap; } sport->clk_per = devm_clk_get(&pdev->dev, "per"); if (IS_ERR(sport->clk_per)) { ret = PTR_ERR(sport->clk_per); + dev_err(&pdev->dev, "failed to get per clk: %d\n", ret); goto unmap; } diff --git a/drivers/tty/serial/ioc3_serial.c b/drivers/tty/serial/ioc3_serial.c index 758ff310f7f8..5ac52898a0bb 100644 --- a/drivers/tty/serial/ioc3_serial.c +++ b/drivers/tty/serial/ioc3_serial.c @@ -1120,13 +1120,14 @@ static inline int do_read(struct uart_port *the_port, char *buf, int len) struct ioc3_port *port = get_ioc3_port(the_port); struct ring *inring; struct ring_entry *entry; - struct port_hooks *hooks = port->ip_hooks; + struct port_hooks *hooks; int byte_num; char *sc; int loop_counter; BUG_ON(!(len >= 0)); BUG_ON(!port); + hooks = port->ip_hooks; /* There is a nasty timing issue in the IOC3. When the rx_timer * expires or the rx_high condition arises, we take an interrupt. diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c index e16894fb2ca3..3e7da10cebba 100644 --- a/drivers/tty/serial/ioc4_serial.c +++ b/drivers/tty/serial/ioc4_serial.c @@ -1803,7 +1803,7 @@ static inline int ic4_startup_local(struct uart_port *the_port) ioc4_set_proto(port, the_port->mapbase); /* set the speed of the serial port */ - ioc4_change_speed(the_port, state->port.tty->termios, + ioc4_change_speed(the_port, &state->port.tty->termios, (struct ktermios *)0); return 0; @@ -2069,13 +2069,14 @@ static inline int do_read(struct uart_port *the_port, unsigned char *buf, struct ioc4_port *port = get_ioc4_port(the_port, 0); struct ring *inring; struct ring_entry *entry; - struct hooks *hooks = port->ip_hooks; + struct hooks *hooks; int byte_num; char *sc; int loop_counter; BUG_ON(!(len >= 0)); BUG_ON(!port); + hooks = port->ip_hooks; /* There is a nasty timing issue in the IOC4. When the rx_timer * expires or the rx_high condition arises, we take an interrupt. diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c index 434bd881fcae..71397961773c 100644 --- a/drivers/tty/serial/jsm/jsm_tty.c +++ b/drivers/tty/serial/jsm/jsm_tty.c @@ -161,7 +161,7 @@ static void jsm_tty_send_xchar(struct uart_port *port, char ch) struct ktermios *termios; spin_lock_irqsave(&port->lock, lock_flags); - termios = port->state->port.tty->termios; + termios = &port->state->port.tty->termios; if (ch == termios->c_cc[VSTART]) channel->ch_bd->bd_ops->send_start_character(channel); @@ -250,7 +250,7 @@ static int jsm_tty_open(struct uart_port *port) channel->ch_cached_lsr = 0; channel->ch_stops_sent = 0; - termios = port->state->port.tty->termios; + termios = &port->state->port.tty->termios; channel->ch_c_cflag = termios->c_cflag; channel->ch_c_iflag = termios->c_iflag; channel->ch_c_oflag = termios->c_oflag; @@ -283,7 +283,7 @@ static void jsm_tty_close(struct uart_port *port) jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n"); bd = channel->ch_bd; - ts = port->state->port.tty->termios; + ts = &port->state->port.tty->termios; channel->ch_flags &= ~(CH_STOPI); @@ -567,7 +567,7 @@ void jsm_input(struct jsm_channel *ch) *input data and return immediately. */ if (!tp || - !(tp->termios->c_cflag & CREAD) ) { + !(tp->termios.c_cflag & CREAD) ) { jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "input. dropping %d bytes on port %d...\n", data_len, ch->ch_portnum); diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c new file mode 100644 index 000000000000..ba3af3bf6d43 --- /dev/null +++ b/drivers/tty/serial/lpc32xx_hs.c @@ -0,0 +1,823 @@ +/* + * High Speed Serial Ports on NXP LPC32xx SoC + * + * Authors: Kevin Wells <kevin.wells@nxp.com> + * Roland Stigge <stigge@antcom.de> + * + * Copyright (C) 2010 NXP Semiconductors + * Copyright (C) 2012 Roland Stigge + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/console.h> +#include <linux/sysrq.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/serial_core.h> +#include <linux/serial.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/nmi.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/of.h> +#include <mach/platform.h> +#include <mach/hardware.h> + +/* + * High Speed UART register offsets + */ +#define LPC32XX_HSUART_FIFO(x) ((x) + 0x00) +#define LPC32XX_HSUART_LEVEL(x) ((x) + 0x04) +#define LPC32XX_HSUART_IIR(x) ((x) + 0x08) +#define LPC32XX_HSUART_CTRL(x) ((x) + 0x0C) +#define LPC32XX_HSUART_RATE(x) ((x) + 0x10) + +#define LPC32XX_HSU_BREAK_DATA (1 << 10) +#define LPC32XX_HSU_ERROR_DATA (1 << 9) +#define LPC32XX_HSU_RX_EMPTY (1 << 8) + +#define LPC32XX_HSU_TX_LEV(n) (((n) >> 8) & 0xFF) +#define LPC32XX_HSU_RX_LEV(n) ((n) & 0xFF) + +#define LPC32XX_HSU_TX_INT_SET (1 << 6) +#define LPC32XX_HSU_RX_OE_INT (1 << 5) +#define LPC32XX_HSU_BRK_INT (1 << 4) +#define LPC32XX_HSU_FE_INT (1 << 3) +#define LPC32XX_HSU_RX_TIMEOUT_INT (1 << 2) +#define LPC32XX_HSU_RX_TRIG_INT (1 << 1) +#define LPC32XX_HSU_TX_INT (1 << 0) + +#define LPC32XX_HSU_HRTS_INV (1 << 21) +#define LPC32XX_HSU_HRTS_TRIG_8B (0x0 << 19) +#define LPC32XX_HSU_HRTS_TRIG_16B (0x1 << 19) +#define LPC32XX_HSU_HRTS_TRIG_32B (0x2 << 19) +#define LPC32XX_HSU_HRTS_TRIG_48B (0x3 << 19) +#define LPC32XX_HSU_HRTS_EN (1 << 18) +#define LPC32XX_HSU_TMO_DISABLED (0x0 << 16) +#define LPC32XX_HSU_TMO_INACT_4B (0x1 << 16) +#define LPC32XX_HSU_TMO_INACT_8B (0x2 << 16) +#define LPC32XX_HSU_TMO_INACT_16B (0x3 << 16) +#define LPC32XX_HSU_HCTS_INV (1 << 15) +#define LPC32XX_HSU_HCTS_EN (1 << 14) +#define LPC32XX_HSU_OFFSET(n) ((n) << 9) +#define LPC32XX_HSU_BREAK (1 << 8) +#define LPC32XX_HSU_ERR_INT_EN (1 << 7) +#define LPC32XX_HSU_RX_INT_EN (1 << 6) +#define LPC32XX_HSU_TX_INT_EN (1 << 5) +#define LPC32XX_HSU_RX_TL1B (0x0 << 2) +#define LPC32XX_HSU_RX_TL4B (0x1 << 2) +#define LPC32XX_HSU_RX_TL8B (0x2 << 2) +#define LPC32XX_HSU_RX_TL16B (0x3 << 2) +#define LPC32XX_HSU_RX_TL32B (0x4 << 2) +#define LPC32XX_HSU_RX_TL48B (0x5 << 2) +#define LPC32XX_HSU_TX_TLEMPTY (0x0 << 0) +#define LPC32XX_HSU_TX_TL0B (0x0 << 0) +#define LPC32XX_HSU_TX_TL4B (0x1 << 0) +#define LPC32XX_HSU_TX_TL8B (0x2 << 0) +#define LPC32XX_HSU_TX_TL16B (0x3 << 0) + +#define MODNAME "lpc32xx_hsuart" + +struct lpc32xx_hsuart_port { + struct uart_port port; +}; + +#define FIFO_READ_LIMIT 128 +#define MAX_PORTS 3 +#define LPC32XX_TTY_NAME "ttyTX" +static struct lpc32xx_hsuart_port lpc32xx_hs_ports[MAX_PORTS]; + +#ifdef CONFIG_SERIAL_HS_LPC32XX_CONSOLE +static void wait_for_xmit_empty(struct uart_port *port) +{ + unsigned int timeout = 10000; + + do { + if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL( + port->membase))) == 0) + break; + if (--timeout == 0) + break; + udelay(1); + } while (1); +} + +static void wait_for_xmit_ready(struct uart_port *port) +{ + unsigned int timeout = 10000; + + while (1) { + if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL( + port->membase))) < 32) + break; + if (--timeout == 0) + break; + udelay(1); + } +} + +static void lpc32xx_hsuart_console_putchar(struct uart_port *port, int ch) +{ + wait_for_xmit_ready(port); + writel((u32)ch, LPC32XX_HSUART_FIFO(port->membase)); +} + +static void lpc32xx_hsuart_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct lpc32xx_hsuart_port *up = &lpc32xx_hs_ports[co->index]; + unsigned long flags; + int locked = 1; + + touch_nmi_watchdog(); + local_irq_save(flags); + if (up->port.sysrq) + locked = 0; + else if (oops_in_progress) + locked = spin_trylock(&up->port.lock); + else + spin_lock(&up->port.lock); + + uart_console_write(&up->port, s, count, lpc32xx_hsuart_console_putchar); + wait_for_xmit_empty(&up->port); + + if (locked) + spin_unlock(&up->port.lock); + local_irq_restore(flags); +} + +static int __init lpc32xx_hsuart_console_setup(struct console *co, + char *options) +{ + struct uart_port *port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index >= MAX_PORTS) + co->index = 0; + + port = &lpc32xx_hs_ports[co->index].port; + if (!port->membase) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct uart_driver lpc32xx_hsuart_reg; +static struct console lpc32xx_hsuart_console = { + .name = LPC32XX_TTY_NAME, + .write = lpc32xx_hsuart_console_write, + .device = uart_console_device, + .setup = lpc32xx_hsuart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &lpc32xx_hsuart_reg, +}; + +static int __init lpc32xx_hsuart_console_init(void) +{ + register_console(&lpc32xx_hsuart_console); + return 0; +} +console_initcall(lpc32xx_hsuart_console_init); + +#define LPC32XX_HSUART_CONSOLE (&lpc32xx_hsuart_console) +#else +#define LPC32XX_HSUART_CONSOLE NULL +#endif + +static struct uart_driver lpc32xx_hs_reg = { + .owner = THIS_MODULE, + .driver_name = MODNAME, + .dev_name = LPC32XX_TTY_NAME, + .nr = MAX_PORTS, + .cons = LPC32XX_HSUART_CONSOLE, +}; +static int uarts_registered; + +static unsigned int __serial_get_clock_div(unsigned long uartclk, + unsigned long rate) +{ + u32 div, goodrate, hsu_rate, l_hsu_rate, comprate; + u32 rate_diff; + + /* Find the closest divider to get the desired clock rate */ + div = uartclk / rate; + goodrate = hsu_rate = (div / 14) - 1; + if (hsu_rate != 0) + hsu_rate--; + + /* Tweak divider */ + l_hsu_rate = hsu_rate + 3; + rate_diff = 0xFFFFFFFF; + + while (hsu_rate < l_hsu_rate) { + comprate = uartclk / ((hsu_rate + 1) * 14); + if (abs(comprate - rate) < rate_diff) { + goodrate = hsu_rate; + rate_diff = abs(comprate - rate); + } + + hsu_rate++; + } + if (hsu_rate > 0xFF) + hsu_rate = 0xFF; + + return goodrate; +} + +static void __serial_uart_flush(struct uart_port *port) +{ + u32 tmp; + int cnt = 0; + + while ((readl(LPC32XX_HSUART_LEVEL(port->membase)) > 0) && + (cnt++ < FIFO_READ_LIMIT)) + tmp = readl(LPC32XX_HSUART_FIFO(port->membase)); +} + +static void __serial_lpc32xx_rx(struct uart_port *port) +{ + unsigned int tmp, flag; + struct tty_struct *tty = tty_port_tty_get(&port->state->port); + + if (!tty) { + /* Discard data: no tty available */ + while (!(readl(LPC32XX_HSUART_FIFO(port->membase)) & + LPC32XX_HSU_RX_EMPTY)) + ; + + return; + } + + /* Read data from FIFO and push into terminal */ + tmp = readl(LPC32XX_HSUART_FIFO(port->membase)); + while (!(tmp & LPC32XX_HSU_RX_EMPTY)) { + flag = TTY_NORMAL; + port->icount.rx++; + + if (tmp & LPC32XX_HSU_ERROR_DATA) { + /* Framing error */ + writel(LPC32XX_HSU_FE_INT, + LPC32XX_HSUART_IIR(port->membase)); + port->icount.frame++; + flag = TTY_FRAME; + tty_insert_flip_char(tty, 0, TTY_FRAME); + } + + tty_insert_flip_char(tty, (tmp & 0xFF), flag); + + tmp = readl(LPC32XX_HSUART_FIFO(port->membase)); + } + tty_flip_buffer_push(tty); + tty_kref_put(tty); +} + +static void __serial_lpc32xx_tx(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + unsigned int tmp; + + if (port->x_char) { + writel((u32)port->x_char, LPC32XX_HSUART_FIFO(port->membase)); + port->icount.tx++; + port->x_char = 0; + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + goto exit_tx; + + /* Transfer data */ + while (LPC32XX_HSU_TX_LEV(readl( + LPC32XX_HSUART_LEVEL(port->membase))) < 64) { + writel((u32) xmit->buf[xmit->tail], + LPC32XX_HSUART_FIFO(port->membase)); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + +exit_tx: + if (uart_circ_empty(xmit)) { + tmp = readl(LPC32XX_HSUART_CTRL(port->membase)); + tmp &= ~LPC32XX_HSU_TX_INT_EN; + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); + } +} + +static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + struct tty_struct *tty = tty_port_tty_get(&port->state->port); + u32 status; + + spin_lock(&port->lock); + + /* Read UART status and clear latched interrupts */ + status = readl(LPC32XX_HSUART_IIR(port->membase)); + + if (status & LPC32XX_HSU_BRK_INT) { + /* Break received */ + writel(LPC32XX_HSU_BRK_INT, LPC32XX_HSUART_IIR(port->membase)); + port->icount.brk++; + uart_handle_break(port); + } + + /* Framing error */ + if (status & LPC32XX_HSU_FE_INT) + writel(LPC32XX_HSU_FE_INT, LPC32XX_HSUART_IIR(port->membase)); + + if (status & LPC32XX_HSU_RX_OE_INT) { + /* Receive FIFO overrun */ + writel(LPC32XX_HSU_RX_OE_INT, + LPC32XX_HSUART_IIR(port->membase)); + port->icount.overrun++; + if (tty) { + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_schedule_flip(tty); + } + } + + /* Data received? */ + if (status & (LPC32XX_HSU_RX_TIMEOUT_INT | LPC32XX_HSU_RX_TRIG_INT)) { + __serial_lpc32xx_rx(port); + if (tty) + tty_flip_buffer_push(tty); + } + + /* Transmit data request? */ + if ((status & LPC32XX_HSU_TX_INT) && (!uart_tx_stopped(port))) { + writel(LPC32XX_HSU_TX_INT, LPC32XX_HSUART_IIR(port->membase)); + __serial_lpc32xx_tx(port); + } + + spin_unlock(&port->lock); + tty_kref_put(tty); + + return IRQ_HANDLED; +} + +/* port->lock is not held. */ +static unsigned int serial_lpc32xx_tx_empty(struct uart_port *port) +{ + unsigned int ret = 0; + + if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(port->membase))) == 0) + ret = TIOCSER_TEMT; + + return ret; +} + +/* port->lock held by caller. */ +static void serial_lpc32xx_set_mctrl(struct uart_port *port, + unsigned int mctrl) +{ + /* No signals are supported on HS UARTs */ +} + +/* port->lock is held by caller and interrupts are disabled. */ +static unsigned int serial_lpc32xx_get_mctrl(struct uart_port *port) +{ + /* No signals are supported on HS UARTs */ + return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; +} + +/* port->lock held by caller. */ +static void serial_lpc32xx_stop_tx(struct uart_port *port) +{ + u32 tmp; + + tmp = readl(LPC32XX_HSUART_CTRL(port->membase)); + tmp &= ~LPC32XX_HSU_TX_INT_EN; + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); +} + +/* port->lock held by caller. */ +static void serial_lpc32xx_start_tx(struct uart_port *port) +{ + u32 tmp; + + __serial_lpc32xx_tx(port); + tmp = readl(LPC32XX_HSUART_CTRL(port->membase)); + tmp |= LPC32XX_HSU_TX_INT_EN; + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); +} + +/* port->lock held by caller. */ +static void serial_lpc32xx_stop_rx(struct uart_port *port) +{ + u32 tmp; + + tmp = readl(LPC32XX_HSUART_CTRL(port->membase)); + tmp &= ~(LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN); + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); + + writel((LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT | + LPC32XX_HSU_FE_INT), LPC32XX_HSUART_IIR(port->membase)); +} + +/* port->lock held by caller. */ +static void serial_lpc32xx_enable_ms(struct uart_port *port) +{ + /* Modem status is not supported */ +} + +/* port->lock is not held. */ +static void serial_lpc32xx_break_ctl(struct uart_port *port, + int break_state) +{ + unsigned long flags; + u32 tmp; + + spin_lock_irqsave(&port->lock, flags); + tmp = readl(LPC32XX_HSUART_CTRL(port->membase)); + if (break_state != 0) + tmp |= LPC32XX_HSU_BREAK; + else + tmp &= ~LPC32XX_HSU_BREAK; + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); + spin_unlock_irqrestore(&port->lock, flags); +} + +/* LPC3250 Errata HSUART.1: Hang workaround via loopback mode on inactivity */ +static void lpc32xx_loopback_set(resource_size_t mapbase, int state) +{ + int bit; + u32 tmp; + + switch (mapbase) { + case LPC32XX_HS_UART1_BASE: + bit = 0; + break; + case LPC32XX_HS_UART2_BASE: + bit = 1; + break; + case LPC32XX_HS_UART7_BASE: + bit = 6; + break; + default: + WARN(1, "lpc32xx_hs: Warning: Unknown port at %08x\n", mapbase); + return; + } + + tmp = readl(LPC32XX_UARTCTL_CLOOP); + if (state) + tmp |= (1 << bit); + else + tmp &= ~(1 << bit); + writel(tmp, LPC32XX_UARTCTL_CLOOP); +} + +/* port->lock is not held. */ +static int serial_lpc32xx_startup(struct uart_port *port) +{ + int retval; + unsigned long flags; + u32 tmp; + + spin_lock_irqsave(&port->lock, flags); + + __serial_uart_flush(port); + + writel((LPC32XX_HSU_TX_INT | LPC32XX_HSU_FE_INT | + LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT), + LPC32XX_HSUART_IIR(port->membase)); + + writel(0xFF, LPC32XX_HSUART_RATE(port->membase)); + + /* + * Set receiver timeout, HSU offset of 20, no break, no interrupts, + * and default FIFO trigger levels + */ + tmp = LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B | + LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B; + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); + + lpc32xx_loopback_set(port->mapbase, 0); /* get out of loopback mode */ + + spin_unlock_irqrestore(&port->lock, flags); + + retval = request_irq(port->irq, serial_lpc32xx_interrupt, + 0, MODNAME, port); + if (!retval) + writel((tmp | LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN), + LPC32XX_HSUART_CTRL(port->membase)); + + return retval; +} + +/* port->lock is not held. */ +static void serial_lpc32xx_shutdown(struct uart_port *port) +{ + u32 tmp; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + tmp = LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B | + LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B; + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); + + lpc32xx_loopback_set(port->mapbase, 1); /* go to loopback mode */ + + spin_unlock_irqrestore(&port->lock, flags); + + free_irq(port->irq, port); +} + +/* port->lock is not held. */ +static void serial_lpc32xx_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + unsigned long flags; + unsigned int baud, quot; + u32 tmp; + + /* Always 8-bit, no parity, 1 stop bit */ + termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD); + termios->c_cflag |= CS8; + + termios->c_cflag &= ~(HUPCL | CMSPAR | CLOCAL | CRTSCTS); + + baud = uart_get_baud_rate(port, termios, old, 0, + port->uartclk / 14); + + quot = __serial_get_clock_div(port->uartclk, baud); + + spin_lock_irqsave(&port->lock, flags); + + /* Ignore characters? */ + tmp = readl(LPC32XX_HSUART_CTRL(port->membase)); + if ((termios->c_cflag & CREAD) == 0) + tmp &= ~(LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN); + else + tmp |= LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN; + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); + + writel(quot, LPC32XX_HSUART_RATE(port->membase)); + + uart_update_timeout(port, termios->c_cflag, baud); + + spin_unlock_irqrestore(&port->lock, flags); + + /* Don't rewrite B0 */ + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); +} + +static const char *serial_lpc32xx_type(struct uart_port *port) +{ + return MODNAME; +} + +static void serial_lpc32xx_release_port(struct uart_port *port) +{ + if ((port->iotype == UPIO_MEM32) && (port->mapbase)) { + if (port->flags & UPF_IOREMAP) { + iounmap(port->membase); + port->membase = NULL; + } + + release_mem_region(port->mapbase, SZ_4K); + } +} + +static int serial_lpc32xx_request_port(struct uart_port *port) +{ + int ret = -ENODEV; + + if ((port->iotype == UPIO_MEM32) && (port->mapbase)) { + ret = 0; + + if (!request_mem_region(port->mapbase, SZ_4K, MODNAME)) + ret = -EBUSY; + else if (port->flags & UPF_IOREMAP) { + port->membase = ioremap(port->mapbase, SZ_4K); + if (!port->membase) { + release_mem_region(port->mapbase, SZ_4K); + ret = -ENOMEM; + } + } + } + + return ret; +} + +static void serial_lpc32xx_config_port(struct uart_port *port, int uflags) +{ + int ret; + + ret = serial_lpc32xx_request_port(port); + if (ret < 0) + return; + port->type = PORT_UART00; + port->fifosize = 64; + + __serial_uart_flush(port); + + writel((LPC32XX_HSU_TX_INT | LPC32XX_HSU_FE_INT | + LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT), + LPC32XX_HSUART_IIR(port->membase)); + + writel(0xFF, LPC32XX_HSUART_RATE(port->membase)); + + /* Set receiver timeout, HSU offset of 20, no break, no interrupts, + and default FIFO trigger levels */ + writel(LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B | + LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B, + LPC32XX_HSUART_CTRL(port->membase)); +} + +static int serial_lpc32xx_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + int ret = 0; + + if (ser->type != PORT_UART00) + ret = -EINVAL; + + return ret; +} + +static struct uart_ops serial_lpc32xx_pops = { + .tx_empty = serial_lpc32xx_tx_empty, + .set_mctrl = serial_lpc32xx_set_mctrl, + .get_mctrl = serial_lpc32xx_get_mctrl, + .stop_tx = serial_lpc32xx_stop_tx, + .start_tx = serial_lpc32xx_start_tx, + .stop_rx = serial_lpc32xx_stop_rx, + .enable_ms = serial_lpc32xx_enable_ms, + .break_ctl = serial_lpc32xx_break_ctl, + .startup = serial_lpc32xx_startup, + .shutdown = serial_lpc32xx_shutdown, + .set_termios = serial_lpc32xx_set_termios, + .type = serial_lpc32xx_type, + .release_port = serial_lpc32xx_release_port, + .request_port = serial_lpc32xx_request_port, + .config_port = serial_lpc32xx_config_port, + .verify_port = serial_lpc32xx_verify_port, +}; + +/* + * Register a set of serial devices attached to a platform device + */ +static int __devinit serial_hs_lpc32xx_probe(struct platform_device *pdev) +{ + struct lpc32xx_hsuart_port *p = &lpc32xx_hs_ports[uarts_registered]; + int ret = 0; + struct resource *res; + + if (uarts_registered >= MAX_PORTS) { + dev_err(&pdev->dev, + "Error: Number of possible ports exceeded (%d)!\n", + uarts_registered + 1); + return -ENXIO; + } + + memset(p, 0, sizeof(*p)); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, + "Error getting mem resource for HS UART port %d\n", + uarts_registered); + return -ENXIO; + } + p->port.mapbase = res->start; + p->port.membase = NULL; + + p->port.irq = platform_get_irq(pdev, 0); + if (p->port.irq < 0) { + dev_err(&pdev->dev, "Error getting irq for HS UART port %d\n", + uarts_registered); + return p->port.irq; + } + + p->port.iotype = UPIO_MEM32; + p->port.uartclk = LPC32XX_MAIN_OSC_FREQ; + p->port.regshift = 2; + p->port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP; + p->port.dev = &pdev->dev; + p->port.ops = &serial_lpc32xx_pops; + p->port.line = uarts_registered++; + spin_lock_init(&p->port.lock); + + /* send port to loopback mode by default */ + lpc32xx_loopback_set(p->port.mapbase, 1); + + ret = uart_add_one_port(&lpc32xx_hs_reg, &p->port); + + platform_set_drvdata(pdev, p); + + return ret; +} + +/* + * Remove serial ports registered against a platform device. + */ +static int __devexit serial_hs_lpc32xx_remove(struct platform_device *pdev) +{ + struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev); + + uart_remove_one_port(&lpc32xx_hs_reg, &p->port); + + return 0; +} + + +#ifdef CONFIG_PM +static int serial_hs_lpc32xx_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev); + + uart_suspend_port(&lpc32xx_hs_reg, &p->port); + + return 0; +} + +static int serial_hs_lpc32xx_resume(struct platform_device *pdev) +{ + struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev); + + uart_resume_port(&lpc32xx_hs_reg, &p->port); + + return 0; +} +#else +#define serial_hs_lpc32xx_suspend NULL +#define serial_hs_lpc32xx_resume NULL +#endif + +static const struct of_device_id serial_hs_lpc32xx_dt_ids[] = { + { .compatible = "nxp,lpc3220-hsuart" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, serial_hs_lpc32xx_dt_ids); + +static struct platform_driver serial_hs_lpc32xx_driver = { + .probe = serial_hs_lpc32xx_probe, + .remove = __devexit_p(serial_hs_lpc32xx_remove), + .suspend = serial_hs_lpc32xx_suspend, + .resume = serial_hs_lpc32xx_resume, + .driver = { + .name = MODNAME, + .owner = THIS_MODULE, + .of_match_table = serial_hs_lpc32xx_dt_ids, + }, +}; + +static int __init lpc32xx_hsuart_init(void) +{ + int ret; + + ret = uart_register_driver(&lpc32xx_hs_reg); + if (ret) + return ret; + + ret = platform_driver_register(&serial_hs_lpc32xx_driver); + if (ret) + uart_unregister_driver(&lpc32xx_hs_reg); + + return ret; +} + +static void __exit lpc32xx_hsuart_exit(void) +{ + platform_driver_unregister(&serial_hs_lpc32xx_driver); + uart_unregister_driver(&lpc32xx_hs_reg); +} + +module_init(lpc32xx_hsuart_init); +module_exit(lpc32xx_hsuart_exit); + +MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>"); +MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>"); +MODULE_DESCRIPTION("NXP LPC32XX High Speed UART driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c index a0703624d5e5..b13949ad3408 100644 --- a/drivers/tty/serial/m32r_sio.c +++ b/drivers/tty/serial/m32r_sio.c @@ -44,8 +44,6 @@ #include <asm/io.h> #include <asm/irq.h> -#define PORT_M32R_BASE PORT_M32R_SIO -#define PORT_INDEX(x) (x - PORT_M32R_BASE + 1) #define BAUD_RATE 115200 #include <linux/serial_core.h> @@ -132,22 +130,6 @@ struct irq_info { static struct irq_info irq_lists[NR_IRQS]; -/* - * Here we define the default xmit fifo size used for each type of UART. - */ -static const struct serial_uart_config uart_config[] = { - [PORT_UNKNOWN] = { - .name = "unknown", - .dfl_xmit_fifo_size = 1, - .flags = 0, - }, - [PORT_INDEX(PORT_M32R_SIO)] = { - .name = "M32RSIO", - .dfl_xmit_fifo_size = 1, - .flags = 0, - }, -}; - #ifdef CONFIG_SERIAL_M32R_PLDSIO #define __sio_in(x) inw((unsigned long)(x)) @@ -907,8 +889,7 @@ static void m32r_sio_config_port(struct uart_port *port, int unused) spin_lock_irqsave(&up->port.lock, flags); - up->port.type = (PORT_M32R_SIO - PORT_M32R_BASE + 1); - up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size; + up->port.fifosize = 1; spin_unlock_irqrestore(&up->port.lock, flags); } @@ -916,23 +897,11 @@ static void m32r_sio_config_port(struct uart_port *port, int unused) static int m32r_sio_verify_port(struct uart_port *port, struct serial_struct *ser) { - if (ser->irq >= nr_irqs || ser->irq < 0 || - ser->baud_base < 9600 || ser->type < PORT_UNKNOWN || - ser->type >= ARRAY_SIZE(uart_config)) + if (ser->irq >= nr_irqs || ser->irq < 0 || ser->baud_base < 9600) return -EINVAL; return 0; } -static const char * -m32r_sio_type(struct uart_port *port) -{ - int type = port->type; - - if (type >= ARRAY_SIZE(uart_config)) - type = 0; - return uart_config[type].name; -} - static struct uart_ops m32r_sio_pops = { .tx_empty = m32r_sio_tx_empty, .set_mctrl = m32r_sio_set_mctrl, @@ -946,7 +915,6 @@ static struct uart_ops m32r_sio_pops = { .shutdown = m32r_sio_shutdown, .set_termios = m32r_sio_set_termios, .pm = m32r_sio_pm, - .type = m32r_sio_type, .release_port = m32r_sio_release_port, .request_port = m32r_sio_request_port, .config_port = m32r_sio_config_port, diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index b4902b99cfd2..46043c2521ce 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -910,17 +910,7 @@ static struct spi_driver max3100_driver = { .resume = max3100_resume, }; -static int __init max3100_init(void) -{ - return spi_register_driver(&max3100_driver); -} -module_init(max3100_init); - -static void __exit max3100_exit(void) -{ - spi_unregister_driver(&max3100_driver); -} -module_exit(max3100_exit); +module_spi_driver(max3100_driver); MODULE_DESCRIPTION("MAX3100 driver"); MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>"); diff --git a/drivers/tty/serial/max3107.c b/drivers/tty/serial/max3107.c deleted file mode 100644 index 17c7ba805d98..000000000000 --- a/drivers/tty/serial/max3107.c +++ /dev/null @@ -1,1215 +0,0 @@ -/* - * max3107.c - spi uart protocol driver for Maxim 3107 - * Based on max3100.c - * by Christian Pellegrin <chripell@evolware.org> - * and max3110.c - * by Feng Tang <feng.tang@intel.com> - * - * Copyright (C) Aavamobile 2009 - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - */ - -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/serial_core.h> -#include <linux/serial.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/gpio.h> -#include <linux/spi/spi.h> -#include <linux/freezer.h> -#include <linux/module.h> -#include "max3107.h" - -static const struct baud_table brg26_ext[] = { - { 300, MAX3107_BRG26_B300 }, - { 600, MAX3107_BRG26_B600 }, - { 1200, MAX3107_BRG26_B1200 }, - { 2400, MAX3107_BRG26_B2400 }, - { 4800, MAX3107_BRG26_B4800 }, - { 9600, MAX3107_BRG26_B9600 }, - { 19200, MAX3107_BRG26_B19200 }, - { 57600, MAX3107_BRG26_B57600 }, - { 115200, MAX3107_BRG26_B115200 }, - { 230400, MAX3107_BRG26_B230400 }, - { 460800, MAX3107_BRG26_B460800 }, - { 921600, MAX3107_BRG26_B921600 }, - { 0, 0 } -}; - -static const struct baud_table brg13_int[] = { - { 300, MAX3107_BRG13_IB300 }, - { 600, MAX3107_BRG13_IB600 }, - { 1200, MAX3107_BRG13_IB1200 }, - { 2400, MAX3107_BRG13_IB2400 }, - { 4800, MAX3107_BRG13_IB4800 }, - { 9600, MAX3107_BRG13_IB9600 }, - { 19200, MAX3107_BRG13_IB19200 }, - { 57600, MAX3107_BRG13_IB57600 }, - { 115200, MAX3107_BRG13_IB115200 }, - { 230400, MAX3107_BRG13_IB230400 }, - { 460800, MAX3107_BRG13_IB460800 }, - { 921600, MAX3107_BRG13_IB921600 }, - { 0, 0 } -}; - -static u32 get_new_brg(int baud, struct max3107_port *s) -{ - int i; - const struct baud_table *baud_tbl = s->baud_tbl; - - for (i = 0; i < 13; i++) { - if (baud == baud_tbl[i].baud) - return baud_tbl[i].new_brg; - } - - return 0; -} - -/* Perform SPI transfer for write/read of device register(s) */ -int max3107_rw(struct max3107_port *s, u8 *tx, u8 *rx, int len) -{ - struct spi_message spi_msg; - struct spi_transfer spi_xfer; - - /* Initialize SPI ,message */ - spi_message_init(&spi_msg); - - /* Initialize SPI transfer */ - memset(&spi_xfer, 0, sizeof spi_xfer); - spi_xfer.len = len; - spi_xfer.tx_buf = tx; - spi_xfer.rx_buf = rx; - spi_xfer.speed_hz = MAX3107_SPI_SPEED; - - /* Add SPI transfer to SPI message */ - spi_message_add_tail(&spi_xfer, &spi_msg); - -#ifdef DBG_TRACE_SPI_DATA - { - int i; - pr_info("tx len %d:\n", spi_xfer.len); - for (i = 0 ; i < spi_xfer.len && i < 32 ; i++) - pr_info(" %x", ((u8 *)spi_xfer.tx_buf)[i]); - pr_info("\n"); - } -#endif - - /* Perform synchronous SPI transfer */ - if (spi_sync(s->spi, &spi_msg)) { - dev_err(&s->spi->dev, "spi_sync failure\n"); - return -EIO; - } - -#ifdef DBG_TRACE_SPI_DATA - if (spi_xfer.rx_buf) { - int i; - pr_info("rx len %d:\n", spi_xfer.len); - for (i = 0 ; i < spi_xfer.len && i < 32 ; i++) - pr_info(" %x", ((u8 *)spi_xfer.rx_buf)[i]); - pr_info("\n"); - } -#endif - return 0; -} -EXPORT_SYMBOL_GPL(max3107_rw); - -/* Puts received data to circular buffer */ -static void put_data_to_circ_buf(struct max3107_port *s, unsigned char *data, - int len) -{ - struct uart_port *port = &s->port; - struct tty_struct *tty; - - if (!port->state) - return; - - tty = port->state->port.tty; - if (!tty) - return; - - /* Insert received data */ - tty_insert_flip_string(tty, data, len); - /* Update RX counter */ - port->icount.rx += len; -} - -/* Handle data receiving */ -static void max3107_handlerx(struct max3107_port *s, u16 rxlvl) -{ - int i; - int j; - int len; /* SPI transfer buffer length */ - u16 *buf; - u8 *valid_str; - - if (!s->rx_enabled) - /* RX is disabled */ - return; - - if (rxlvl == 0) { - /* RX fifo is empty */ - return; - } else if (rxlvl >= MAX3107_RX_FIFO_SIZE) { - dev_warn(&s->spi->dev, "Possible RX FIFO overrun %d\n", rxlvl); - /* Ensure sanity of RX level */ - rxlvl = MAX3107_RX_FIFO_SIZE; - } - if ((s->rxbuf == 0) || (s->rxstr == 0)) { - dev_warn(&s->spi->dev, "Rx buffer/str isn't ready\n"); - return; - } - buf = s->rxbuf; - valid_str = s->rxstr; - while (rxlvl) { - pr_debug("rxlvl %d\n", rxlvl); - /* Clear buffer */ - memset(buf, 0, sizeof(u16) * (MAX3107_RX_FIFO_SIZE + 2)); - len = 0; - if (s->irqen_reg & MAX3107_IRQ_RXFIFO_BIT) { - /* First disable RX FIFO interrupt */ - pr_debug("Disabling RX INT\n"); - buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG); - s->irqen_reg &= ~MAX3107_IRQ_RXFIFO_BIT; - buf[0] |= s->irqen_reg; - len++; - } - /* Just increase the length by amount of words in FIFO since - * buffer was zeroed and SPI transfer of 0x0000 means reading - * from RX FIFO - */ - len += rxlvl; - /* Append RX level query */ - buf[len] = MAX3107_RXFIFOLVL_REG; - len++; - - /* Perform the SPI transfer */ - if (max3107_rw(s, (u8 *)buf, (u8 *)buf, len * 2)) { - dev_err(&s->spi->dev, "SPI transfer for RX h failed\n"); - return; - } - - /* Skip RX FIFO interrupt disabling word if it was added */ - j = ((len - 1) - rxlvl); - /* Read received words */ - for (i = 0; i < rxlvl; i++, j++) - valid_str[i] = (u8)buf[j]; - put_data_to_circ_buf(s, valid_str, rxlvl); - /* Get new RX level */ - rxlvl = (buf[len - 1] & MAX3107_SPI_RX_DATA_MASK); - } - - if (s->rx_enabled) { - /* RX still enabled, re-enable RX FIFO interrupt */ - pr_debug("Enabling RX INT\n"); - buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG); - s->irqen_reg |= MAX3107_IRQ_RXFIFO_BIT; - buf[0] |= s->irqen_reg; - if (max3107_rw(s, (u8 *)buf, NULL, 2)) - dev_err(&s->spi->dev, "RX FIFO INT enabling failed\n"); - } - - /* Push the received data to receivers */ - if (s->port.state->port.tty) - tty_flip_buffer_push(s->port.state->port.tty); -} - - -/* Handle data sending */ -static void max3107_handletx(struct max3107_port *s) -{ - struct circ_buf *xmit = &s->port.state->xmit; - int i; - unsigned long flags; - int len; /* SPI transfer buffer length */ - u16 *buf; - - if (!s->tx_fifo_empty) - /* Don't send more data before previous data is sent */ - return; - - if (uart_circ_empty(xmit) || uart_tx_stopped(&s->port)) - /* No data to send or TX is stopped */ - return; - - if (!s->txbuf) { - dev_warn(&s->spi->dev, "Txbuf isn't ready\n"); - return; - } - buf = s->txbuf; - /* Get length of data pending in circular buffer */ - len = uart_circ_chars_pending(xmit); - if (len) { - /* Limit to size of TX FIFO */ - if (len > MAX3107_TX_FIFO_SIZE) - len = MAX3107_TX_FIFO_SIZE; - - pr_debug("txlen %d\n", len); - - /* Update TX counter */ - s->port.icount.tx += len; - - /* TX FIFO will no longer be empty */ - s->tx_fifo_empty = 0; - - i = 0; - if (s->irqen_reg & MAX3107_IRQ_TXEMPTY_BIT) { - /* First disable TX empty interrupt */ - pr_debug("Disabling TE INT\n"); - buf[i] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG); - s->irqen_reg &= ~MAX3107_IRQ_TXEMPTY_BIT; - buf[i] |= s->irqen_reg; - i++; - len++; - } - /* Add data to send */ - spin_lock_irqsave(&s->port.lock, flags); - for ( ; i < len ; i++) { - buf[i] = (MAX3107_WRITE_BIT | MAX3107_THR_REG); - buf[i] |= ((u16)xmit->buf[xmit->tail] & - MAX3107_SPI_TX_DATA_MASK); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - } - spin_unlock_irqrestore(&s->port.lock, flags); - if (!(s->irqen_reg & MAX3107_IRQ_TXEMPTY_BIT)) { - /* Enable TX empty interrupt */ - pr_debug("Enabling TE INT\n"); - buf[i] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG); - s->irqen_reg |= MAX3107_IRQ_TXEMPTY_BIT; - buf[i] |= s->irqen_reg; - i++; - len++; - } - if (!s->tx_enabled) { - /* Enable TX */ - pr_debug("Enable TX\n"); - buf[i] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG); - spin_lock_irqsave(&s->data_lock, flags); - s->mode1_reg &= ~MAX3107_MODE1_TXDIS_BIT; - buf[i] |= s->mode1_reg; - spin_unlock_irqrestore(&s->data_lock, flags); - s->tx_enabled = 1; - i++; - len++; - } - - /* Perform the SPI transfer */ - if (max3107_rw(s, (u8 *)buf, NULL, len*2)) { - dev_err(&s->spi->dev, - "SPI transfer TX handling failed\n"); - return; - } - } - - /* Indicate wake up if circular buffer is getting low on data */ - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&s->port); - -} - -/* Handle interrupts - * Also reads and returns current RX FIFO level - */ -static u16 handle_interrupt(struct max3107_port *s) -{ - u16 buf[4]; /* Buffer for SPI transfers */ - u8 irq_status; - u16 rx_level; - unsigned long flags; - - /* Read IRQ status register */ - buf[0] = MAX3107_IRQSTS_REG; - /* Read status IRQ status register */ - buf[1] = MAX3107_STS_IRQSTS_REG; - /* Read LSR IRQ status register */ - buf[2] = MAX3107_LSR_IRQSTS_REG; - /* Query RX level */ - buf[3] = MAX3107_RXFIFOLVL_REG; - - if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 8)) { - dev_err(&s->spi->dev, - "SPI transfer for INTR handling failed\n"); - return 0; - } - - irq_status = (u8)buf[0]; - pr_debug("IRQSTS %x\n", irq_status); - rx_level = (buf[3] & MAX3107_SPI_RX_DATA_MASK); - - if (irq_status & MAX3107_IRQ_LSR_BIT) { - /* LSR interrupt */ - if (buf[2] & MAX3107_LSR_RXTO_BIT) - /* RX timeout interrupt, - * handled by normal RX handling - */ - pr_debug("RX TO INT\n"); - } - - if (irq_status & MAX3107_IRQ_TXEMPTY_BIT) { - /* Tx empty interrupt, - * disable TX and set tx_fifo_empty flag - */ - pr_debug("TE INT, disabling TX\n"); - buf[0] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG); - spin_lock_irqsave(&s->data_lock, flags); - s->mode1_reg |= MAX3107_MODE1_TXDIS_BIT; - buf[0] |= s->mode1_reg; - spin_unlock_irqrestore(&s->data_lock, flags); - if (max3107_rw(s, (u8 *)buf, NULL, 2)) - dev_err(&s->spi->dev, "SPI transfer TX dis failed\n"); - s->tx_enabled = 0; - s->tx_fifo_empty = 1; - } - - if (irq_status & MAX3107_IRQ_RXFIFO_BIT) - /* RX FIFO interrupt, - * handled by normal RX handling - */ - pr_debug("RFIFO INT\n"); - - /* Return RX level */ - return rx_level; -} - -/* Trigger work thread*/ -static void max3107_dowork(struct max3107_port *s) -{ - if (!work_pending(&s->work) && !freezing(current) && !s->suspended) - queue_work(s->workqueue, &s->work); - else - dev_warn(&s->spi->dev, "interrup isn't serviced normally!\n"); -} - -/* Work thread */ -static void max3107_work(struct work_struct *w) -{ - struct max3107_port *s = container_of(w, struct max3107_port, work); - u16 rxlvl = 0; - int len; /* SPI transfer buffer length */ - u16 buf[5]; /* Buffer for SPI transfers */ - unsigned long flags; - - /* Start by reading current RX FIFO level */ - buf[0] = MAX3107_RXFIFOLVL_REG; - if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) { - dev_err(&s->spi->dev, "SPI transfer RX lev failed\n"); - rxlvl = 0; - } else { - rxlvl = (buf[0] & MAX3107_SPI_RX_DATA_MASK); - } - - do { - pr_debug("rxlvl %d\n", rxlvl); - - /* Handle RX */ - max3107_handlerx(s, rxlvl); - rxlvl = 0; - - if (s->handle_irq) { - /* Handle pending interrupts - * We also get new RX FIFO level since new data may - * have been received while pushing received data to - * receivers - */ - s->handle_irq = 0; - rxlvl = handle_interrupt(s); - } - - /* Handle TX */ - max3107_handletx(s); - - /* Handle configuration changes */ - len = 0; - spin_lock_irqsave(&s->data_lock, flags); - if (s->mode1_commit) { - pr_debug("mode1_commit\n"); - buf[len] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG); - buf[len++] |= s->mode1_reg; - s->mode1_commit = 0; - } - if (s->lcr_commit) { - pr_debug("lcr_commit\n"); - buf[len] = (MAX3107_WRITE_BIT | MAX3107_LCR_REG); - buf[len++] |= s->lcr_reg; - s->lcr_commit = 0; - } - if (s->brg_commit) { - pr_debug("brg_commit\n"); - buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG); - buf[len++] |= ((s->brg_cfg >> 16) & - MAX3107_SPI_TX_DATA_MASK); - buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG); - buf[len++] |= ((s->brg_cfg >> 8) & - MAX3107_SPI_TX_DATA_MASK); - buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGCFG_REG); - buf[len++] |= ((s->brg_cfg) & 0xff); - s->brg_commit = 0; - } - spin_unlock_irqrestore(&s->data_lock, flags); - - if (len > 0) { - if (max3107_rw(s, (u8 *)buf, NULL, len * 2)) - dev_err(&s->spi->dev, - "SPI transfer config failed\n"); - } - - /* Reloop if interrupt handling indicated data in RX FIFO */ - } while (rxlvl); - -} - -/* Set sleep mode */ -static void max3107_set_sleep(struct max3107_port *s, int mode) -{ - u16 buf[1]; /* Buffer for SPI transfer */ - unsigned long flags; - pr_debug("enter, mode %d\n", mode); - - buf[0] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG); - spin_lock_irqsave(&s->data_lock, flags); - switch (mode) { - case MAX3107_DISABLE_FORCED_SLEEP: - s->mode1_reg &= ~MAX3107_MODE1_FORCESLEEP_BIT; - break; - case MAX3107_ENABLE_FORCED_SLEEP: - s->mode1_reg |= MAX3107_MODE1_FORCESLEEP_BIT; - break; - case MAX3107_DISABLE_AUTOSLEEP: - s->mode1_reg &= ~MAX3107_MODE1_AUTOSLEEP_BIT; - break; - case MAX3107_ENABLE_AUTOSLEEP: - s->mode1_reg |= MAX3107_MODE1_AUTOSLEEP_BIT; - break; - default: - spin_unlock_irqrestore(&s->data_lock, flags); - dev_warn(&s->spi->dev, "invalid sleep mode\n"); - return; - } - buf[0] |= s->mode1_reg; - spin_unlock_irqrestore(&s->data_lock, flags); - - if (max3107_rw(s, (u8 *)buf, NULL, 2)) - dev_err(&s->spi->dev, "SPI transfer sleep mode failed\n"); - - if (mode == MAX3107_DISABLE_AUTOSLEEP || - mode == MAX3107_DISABLE_FORCED_SLEEP) - msleep(MAX3107_WAKEUP_DELAY); -} - -/* Perform full register initialization */ -static void max3107_register_init(struct max3107_port *s) -{ - u16 buf[11]; /* Buffer for SPI transfers */ - - /* 1. Configure baud rate, 9600 as default */ - s->baud = 9600; - /* the below is default*/ - if (s->ext_clk) { - s->brg_cfg = MAX3107_BRG26_B9600; - s->baud_tbl = (struct baud_table *)brg26_ext; - } else { - s->brg_cfg = MAX3107_BRG13_IB9600; - s->baud_tbl = (struct baud_table *)brg13_int; - } - - if (s->pdata->init) - s->pdata->init(s); - - buf[0] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG) - | ((s->brg_cfg >> 16) & MAX3107_SPI_TX_DATA_MASK); - buf[1] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG) - | ((s->brg_cfg >> 8) & MAX3107_SPI_TX_DATA_MASK); - buf[2] = (MAX3107_WRITE_BIT | MAX3107_BRGCFG_REG) - | ((s->brg_cfg) & 0xff); - - /* 2. Configure LCR register, 8N1 mode by default */ - s->lcr_reg = MAX3107_LCR_WORD_LEN_8; - buf[3] = (MAX3107_WRITE_BIT | MAX3107_LCR_REG) - | s->lcr_reg; - - /* 3. Configure MODE 1 register */ - s->mode1_reg = 0; - /* Enable IRQ pin */ - s->mode1_reg |= MAX3107_MODE1_IRQSEL_BIT; - /* Disable TX */ - s->mode1_reg |= MAX3107_MODE1_TXDIS_BIT; - s->tx_enabled = 0; - /* RX is enabled */ - s->rx_enabled = 1; - buf[4] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG) - | s->mode1_reg; - - /* 4. Configure MODE 2 register */ - buf[5] = (MAX3107_WRITE_BIT | MAX3107_MODE2_REG); - if (s->loopback) { - /* Enable loopback */ - buf[5] |= MAX3107_MODE2_LOOPBACK_BIT; - } - /* Reset FIFOs */ - buf[5] |= MAX3107_MODE2_FIFORST_BIT; - s->tx_fifo_empty = 1; - - /* 5. Configure FIFO trigger level register */ - buf[6] = (MAX3107_WRITE_BIT | MAX3107_FIFOTRIGLVL_REG); - /* RX FIFO trigger for 16 words, TX FIFO trigger not used */ - buf[6] |= (MAX3107_FIFOTRIGLVL_RX(16) | MAX3107_FIFOTRIGLVL_TX(0)); - - /* 6. Configure flow control levels */ - buf[7] = (MAX3107_WRITE_BIT | MAX3107_FLOWLVL_REG); - /* Flow control halt level 96, resume level 48 */ - buf[7] |= (MAX3107_FLOWLVL_RES(48) | MAX3107_FLOWLVL_HALT(96)); - - /* 7. Configure flow control */ - buf[8] = (MAX3107_WRITE_BIT | MAX3107_FLOWCTRL_REG); - /* Enable auto CTS and auto RTS flow control */ - buf[8] |= (MAX3107_FLOWCTRL_AUTOCTS_BIT | MAX3107_FLOWCTRL_AUTORTS_BIT); - - /* 8. Configure RX timeout register */ - buf[9] = (MAX3107_WRITE_BIT | MAX3107_RXTO_REG); - /* Timeout after 48 character intervals */ - buf[9] |= 0x0030; - - /* 9. Configure LSR interrupt enable register */ - buf[10] = (MAX3107_WRITE_BIT | MAX3107_LSR_IRQEN_REG); - /* Enable RX timeout interrupt */ - buf[10] |= MAX3107_LSR_RXTO_BIT; - - /* Perform SPI transfer */ - if (max3107_rw(s, (u8 *)buf, NULL, 22)) - dev_err(&s->spi->dev, "SPI transfer for init failed\n"); - - /* 10. Clear IRQ status register by reading it */ - buf[0] = MAX3107_IRQSTS_REG; - - /* 11. Configure interrupt enable register */ - /* Enable LSR interrupt */ - s->irqen_reg = MAX3107_IRQ_LSR_BIT; - /* Enable RX FIFO interrupt */ - s->irqen_reg |= MAX3107_IRQ_RXFIFO_BIT; - buf[1] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG) - | s->irqen_reg; - - /* 12. Clear FIFO reset that was set in step 6 */ - buf[2] = (MAX3107_WRITE_BIT | MAX3107_MODE2_REG); - if (s->loopback) { - /* Keep loopback enabled */ - buf[2] |= MAX3107_MODE2_LOOPBACK_BIT; - } - - /* Perform SPI transfer */ - if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 6)) - dev_err(&s->spi->dev, "SPI transfer for init failed\n"); - -} - -/* IRQ handler */ -static irqreturn_t max3107_irq(int irqno, void *dev_id) -{ - struct max3107_port *s = dev_id; - - if (irqno != s->spi->irq) { - /* Unexpected IRQ */ - return IRQ_NONE; - } - - /* Indicate irq */ - s->handle_irq = 1; - - /* Trigger work thread */ - max3107_dowork(s); - - return IRQ_HANDLED; -} - -/* HW suspension function - * - * Currently autosleep is used to decrease current consumption, alternative - * approach would be to set the chip to reset mode if UART is not being - * used but that would mess the GPIOs - * - */ -void max3107_hw_susp(struct max3107_port *s, int suspend) -{ - pr_debug("enter, suspend %d\n", suspend); - - if (suspend) { - /* Suspend requested, - * enable autosleep to decrease current consumption - */ - s->suspended = 1; - max3107_set_sleep(s, MAX3107_ENABLE_AUTOSLEEP); - } else { - /* Resume requested, - * disable autosleep - */ - s->suspended = 0; - max3107_set_sleep(s, MAX3107_DISABLE_AUTOSLEEP); - } -} -EXPORT_SYMBOL_GPL(max3107_hw_susp); - -/* Modem status IRQ enabling */ -static void max3107_enable_ms(struct uart_port *port) -{ - /* Modem status not supported */ -} - -/* Data send function */ -static void max3107_start_tx(struct uart_port *port) -{ - struct max3107_port *s = container_of(port, struct max3107_port, port); - - /* Trigger work thread for sending data */ - max3107_dowork(s); -} - -/* Function for checking that there is no pending transfers */ -static unsigned int max3107_tx_empty(struct uart_port *port) -{ - struct max3107_port *s = container_of(port, struct max3107_port, port); - - pr_debug("returning %d\n", - (s->tx_fifo_empty && uart_circ_empty(&s->port.state->xmit))); - return s->tx_fifo_empty && uart_circ_empty(&s->port.state->xmit); -} - -/* Function for stopping RX */ -static void max3107_stop_rx(struct uart_port *port) -{ - struct max3107_port *s = container_of(port, struct max3107_port, port); - unsigned long flags; - - /* Set RX disabled in MODE 1 register */ - spin_lock_irqsave(&s->data_lock, flags); - s->mode1_reg |= MAX3107_MODE1_RXDIS_BIT; - s->mode1_commit = 1; - spin_unlock_irqrestore(&s->data_lock, flags); - /* Set RX disabled */ - s->rx_enabled = 0; - /* Trigger work thread for doing the actual configuration change */ - max3107_dowork(s); -} - -/* Function for returning control pin states */ -static unsigned int max3107_get_mctrl(struct uart_port *port) -{ - /* DCD and DSR are not wired and CTS/RTS is handled automatically - * so just indicate DSR and CAR asserted - */ - return TIOCM_DSR | TIOCM_CAR; -} - -/* Function for setting control pin states */ -static void max3107_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - /* DCD and DSR are not wired and CTS/RTS is hadnled automatically - * so do nothing - */ -} - -/* Function for configuring UART parameters */ -static void max3107_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old) -{ - struct max3107_port *s = container_of(port, struct max3107_port, port); - struct tty_struct *tty; - int baud; - u16 new_lcr = 0; - u32 new_brg = 0; - unsigned long flags; - - if (!port->state) - return; - - tty = port->state->port.tty; - if (!tty) - return; - - /* Get new LCR register values */ - /* Word size */ - if ((termios->c_cflag & CSIZE) == CS7) - new_lcr |= MAX3107_LCR_WORD_LEN_7; - else - new_lcr |= MAX3107_LCR_WORD_LEN_8; - - /* Parity */ - if (termios->c_cflag & PARENB) { - new_lcr |= MAX3107_LCR_PARITY_BIT; - if (!(termios->c_cflag & PARODD)) - new_lcr |= MAX3107_LCR_EVENPARITY_BIT; - } - - /* Stop bits */ - if (termios->c_cflag & CSTOPB) { - /* 2 stop bits */ - new_lcr |= MAX3107_LCR_STOPLEN_BIT; - } - - /* Mask termios capabilities we don't support */ - termios->c_cflag &= ~CMSPAR; - - /* Set status ignore mask */ - s->port.ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - s->port.ignore_status_mask |= MAX3107_ALL_ERRORS; - - /* Set low latency to immediately handle pushed data */ - s->port.state->port.tty->low_latency = 1; - - /* Get new baud rate generator configuration */ - baud = tty_get_baud_rate(tty); - - spin_lock_irqsave(&s->data_lock, flags); - new_brg = get_new_brg(baud, s); - /* if can't find the corrent config, use previous */ - if (!new_brg) { - baud = s->baud; - new_brg = s->brg_cfg; - } - spin_unlock_irqrestore(&s->data_lock, flags); - tty_termios_encode_baud_rate(termios, baud, baud); - s->baud = baud; - - /* Update timeout according to new baud rate */ - uart_update_timeout(port, termios->c_cflag, baud); - - spin_lock_irqsave(&s->data_lock, flags); - if (s->lcr_reg != new_lcr) { - s->lcr_reg = new_lcr; - s->lcr_commit = 1; - } - if (s->brg_cfg != new_brg) { - s->brg_cfg = new_brg; - s->brg_commit = 1; - } - spin_unlock_irqrestore(&s->data_lock, flags); - - /* Trigger work thread for doing the actual configuration change */ - max3107_dowork(s); -} - -/* Port shutdown function */ -static void max3107_shutdown(struct uart_port *port) -{ - struct max3107_port *s = container_of(port, struct max3107_port, port); - - if (s->suspended && s->pdata->hw_suspend) - s->pdata->hw_suspend(s, 0); - - /* Free the interrupt */ - free_irq(s->spi->irq, s); - - if (s->workqueue) { - /* Flush and destroy work queue */ - flush_workqueue(s->workqueue); - destroy_workqueue(s->workqueue); - s->workqueue = NULL; - } - - /* Suspend HW */ - if (s->pdata->hw_suspend) - s->pdata->hw_suspend(s, 1); -} - -/* Port startup function */ -static int max3107_startup(struct uart_port *port) -{ - struct max3107_port *s = container_of(port, struct max3107_port, port); - - /* Initialize work queue */ - s->workqueue = create_freezable_workqueue("max3107"); - if (!s->workqueue) { - dev_err(&s->spi->dev, "Workqueue creation failed\n"); - return -EBUSY; - } - INIT_WORK(&s->work, max3107_work); - - /* Setup IRQ */ - if (request_irq(s->spi->irq, max3107_irq, IRQF_TRIGGER_FALLING, - "max3107", s)) { - dev_err(&s->spi->dev, "IRQ reguest failed\n"); - destroy_workqueue(s->workqueue); - s->workqueue = NULL; - return -EBUSY; - } - - /* Resume HW */ - if (s->pdata->hw_suspend) - s->pdata->hw_suspend(s, 0); - - /* Init registers */ - max3107_register_init(s); - - return 0; -} - -/* Port type function */ -static const char *max3107_type(struct uart_port *port) -{ - struct max3107_port *s = container_of(port, struct max3107_port, port); - return s->spi->modalias; -} - -/* Port release function */ -static void max3107_release_port(struct uart_port *port) -{ - /* Do nothing */ -} - -/* Port request function */ -static int max3107_request_port(struct uart_port *port) -{ - /* Do nothing */ - return 0; -} - -/* Port config function */ -static void max3107_config_port(struct uart_port *port, int flags) -{ - struct max3107_port *s = container_of(port, struct max3107_port, port); - s->port.type = PORT_MAX3107; -} - -/* Port verify function */ -static int max3107_verify_port(struct uart_port *port, - struct serial_struct *ser) -{ - if (ser->type == PORT_UNKNOWN || ser->type == PORT_MAX3107) - return 0; - - return -EINVAL; -} - -/* Port stop TX function */ -static void max3107_stop_tx(struct uart_port *port) -{ - /* Do nothing */ -} - -/* Port break control function */ -static void max3107_break_ctl(struct uart_port *port, int break_state) -{ - /* We don't support break control, do nothing */ -} - - -/* Port functions */ -static struct uart_ops max3107_ops = { - .tx_empty = max3107_tx_empty, - .set_mctrl = max3107_set_mctrl, - .get_mctrl = max3107_get_mctrl, - .stop_tx = max3107_stop_tx, - .start_tx = max3107_start_tx, - .stop_rx = max3107_stop_rx, - .enable_ms = max3107_enable_ms, - .break_ctl = max3107_break_ctl, - .startup = max3107_startup, - .shutdown = max3107_shutdown, - .set_termios = max3107_set_termios, - .type = max3107_type, - .release_port = max3107_release_port, - .request_port = max3107_request_port, - .config_port = max3107_config_port, - .verify_port = max3107_verify_port, -}; - -/* UART driver data */ -static struct uart_driver max3107_uart_driver = { - .owner = THIS_MODULE, - .driver_name = "ttyMAX", - .dev_name = "ttyMAX", - .nr = 1, -}; - -static int driver_registered = 0; - - - -/* 'Generic' platform data */ -static struct max3107_plat generic_plat_data = { - .loopback = 0, - .ext_clk = 1, - .hw_suspend = max3107_hw_susp, - .polled_mode = 0, - .poll_time = 0, -}; - - -/*******************************************************************/ - -/** - * max3107_probe - SPI bus probe entry point - * @spi: the spi device - * - * SPI wants us to probe this device and if appropriate claim it. - * Perform any platform specific requirements and then initialise - * the device. - */ - -int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata) -{ - struct max3107_port *s; - u16 buf[2]; /* Buffer for SPI transfers */ - int retval; - - pr_info("enter max3107 probe\n"); - - /* Allocate port structure */ - s = kzalloc(sizeof(*s), GFP_KERNEL); - if (!s) { - pr_err("Allocating port structure failed\n"); - return -ENOMEM; - } - - s->pdata = pdata; - - /* SPI Rx buffer - * +2 for RX FIFO interrupt - * disabling and RX level query - */ - s->rxbuf = kzalloc(sizeof(u16) * (MAX3107_RX_FIFO_SIZE+2), GFP_KERNEL); - if (!s->rxbuf) { - pr_err("Allocating RX buffer failed\n"); - retval = -ENOMEM; - goto err_free4; - } - s->rxstr = kzalloc(sizeof(u8) * MAX3107_RX_FIFO_SIZE, GFP_KERNEL); - if (!s->rxstr) { - pr_err("Allocating RX buffer failed\n"); - retval = -ENOMEM; - goto err_free3; - } - /* SPI Tx buffer - * SPI transfer buffer - * +3 for TX FIFO empty - * interrupt disabling and - * enabling and TX enabling - */ - s->txbuf = kzalloc(sizeof(u16) * MAX3107_TX_FIFO_SIZE + 3, GFP_KERNEL); - if (!s->txbuf) { - pr_err("Allocating TX buffer failed\n"); - retval = -ENOMEM; - goto err_free2; - } - /* Initialize shared data lock */ - spin_lock_init(&s->data_lock); - - /* SPI intializations */ - dev_set_drvdata(&spi->dev, s); - spi->mode = SPI_MODE_0; - spi->dev.platform_data = pdata; - spi->bits_per_word = 16; - s->ext_clk = pdata->ext_clk; - s->loopback = pdata->loopback; - spi_setup(spi); - s->spi = spi; - - /* Check REV ID to ensure we are talking to what we expect */ - buf[0] = MAX3107_REVID_REG; - if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) { - dev_err(&s->spi->dev, "SPI transfer for REVID read failed\n"); - retval = -EIO; - goto err_free1; - } - if ((buf[0] & MAX3107_SPI_RX_DATA_MASK) != MAX3107_REVID1 && - (buf[0] & MAX3107_SPI_RX_DATA_MASK) != MAX3107_REVID2) { - dev_err(&s->spi->dev, "REVID %x does not match\n", - (buf[0] & MAX3107_SPI_RX_DATA_MASK)); - retval = -ENODEV; - goto err_free1; - } - - /* Disable all interrupts */ - buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG | 0x0000); - buf[0] |= 0x0000; - - /* Configure clock source */ - buf[1] = (MAX3107_WRITE_BIT | MAX3107_CLKSRC_REG); - if (s->ext_clk) { - /* External clock */ - buf[1] |= MAX3107_CLKSRC_EXTCLK_BIT; - } - - /* PLL bypass ON */ - buf[1] |= MAX3107_CLKSRC_PLLBYP_BIT; - - /* Perform SPI transfer */ - if (max3107_rw(s, (u8 *)buf, NULL, 4)) { - dev_err(&s->spi->dev, "SPI transfer for init failed\n"); - retval = -EIO; - goto err_free1; - } - - /* Register UART driver */ - if (!driver_registered) { - retval = uart_register_driver(&max3107_uart_driver); - if (retval) { - dev_err(&s->spi->dev, "Registering UART driver failed\n"); - goto err_free1; - } - driver_registered = 1; - } - - /* Initialize UART port data */ - s->port.fifosize = 128; - s->port.ops = &max3107_ops; - s->port.line = 0; - s->port.dev = &spi->dev; - s->port.uartclk = 9600; - s->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; - s->port.irq = s->spi->irq; - s->port.type = PORT_MAX3107; - - /* Add UART port */ - retval = uart_add_one_port(&max3107_uart_driver, &s->port); - if (retval < 0) { - dev_err(&s->spi->dev, "Adding UART port failed\n"); - goto err_free1; - } - - if (pdata->configure) { - retval = pdata->configure(s); - if (retval < 0) - goto err_free1; - } - - /* Go to suspend mode */ - if (pdata->hw_suspend) - pdata->hw_suspend(s, 1); - - return 0; - -err_free1: - kfree(s->txbuf); -err_free2: - kfree(s->rxstr); -err_free3: - kfree(s->rxbuf); -err_free4: - kfree(s); - return retval; -} -EXPORT_SYMBOL_GPL(max3107_probe); - -/* Driver remove function */ -int max3107_remove(struct spi_device *spi) -{ - struct max3107_port *s = dev_get_drvdata(&spi->dev); - - pr_info("enter max3107 remove\n"); - - /* Remove port */ - if (uart_remove_one_port(&max3107_uart_driver, &s->port)) - dev_warn(&s->spi->dev, "Removing UART port failed\n"); - - - /* Free TxRx buffer */ - kfree(s->rxbuf); - kfree(s->rxstr); - kfree(s->txbuf); - - /* Free port structure */ - kfree(s); - - return 0; -} -EXPORT_SYMBOL_GPL(max3107_remove); - -/* Driver suspend function */ -int max3107_suspend(struct spi_device *spi, pm_message_t state) -{ -#ifdef CONFIG_PM - struct max3107_port *s = dev_get_drvdata(&spi->dev); - - pr_debug("enter suspend\n"); - - /* Suspend UART port */ - uart_suspend_port(&max3107_uart_driver, &s->port); - - /* Go to suspend mode */ - if (s->pdata->hw_suspend) - s->pdata->hw_suspend(s, 1); -#endif /* CONFIG_PM */ - return 0; -} -EXPORT_SYMBOL_GPL(max3107_suspend); - -/* Driver resume function */ -int max3107_resume(struct spi_device *spi) -{ -#ifdef CONFIG_PM - struct max3107_port *s = dev_get_drvdata(&spi->dev); - - pr_debug("enter resume\n"); - - /* Resume from suspend */ - if (s->pdata->hw_suspend) - s->pdata->hw_suspend(s, 0); - - /* Resume UART port */ - uart_resume_port(&max3107_uart_driver, &s->port); -#endif /* CONFIG_PM */ - return 0; -} -EXPORT_SYMBOL_GPL(max3107_resume); - -static int max3107_probe_generic(struct spi_device *spi) -{ - return max3107_probe(spi, &generic_plat_data); -} - -/* Spi driver data */ -static struct spi_driver max3107_driver = { - .driver = { - .name = "max3107", - .owner = THIS_MODULE, - }, - .probe = max3107_probe_generic, - .remove = __devexit_p(max3107_remove), - .suspend = max3107_suspend, - .resume = max3107_resume, -}; - -/* Driver init function */ -static int __init max3107_init(void) -{ - pr_info("enter max3107 init\n"); - return spi_register_driver(&max3107_driver); -} - -/* Driver exit function */ -static void __exit max3107_exit(void) -{ - pr_info("enter max3107 exit\n"); - /* Unregister UART driver */ - if (driver_registered) - uart_unregister_driver(&max3107_uart_driver); - spi_unregister_driver(&max3107_driver); -} - -module_init(max3107_init); -module_exit(max3107_exit); - -MODULE_DESCRIPTION("MAX3107 driver"); -MODULE_AUTHOR("Aavamobile"); -MODULE_ALIAS("spi:max3107"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/max3107.h b/drivers/tty/serial/max3107.h deleted file mode 100644 index 8415fc723b96..000000000000 --- a/drivers/tty/serial/max3107.h +++ /dev/null @@ -1,441 +0,0 @@ -/* - * max3107.h - spi uart protocol driver header for Maxim 3107 - * - * Copyright (C) Aavamobile 2009 - * Based on serial_max3100.h by Christian Pellegrin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef _MAX3107_H -#define _MAX3107_H - -/* Serial error status definitions */ -#define MAX3107_PARITY_ERROR 1 -#define MAX3107_FRAME_ERROR 2 -#define MAX3107_OVERRUN_ERROR 4 -#define MAX3107_ALL_ERRORS (MAX3107_PARITY_ERROR | \ - MAX3107_FRAME_ERROR | \ - MAX3107_OVERRUN_ERROR) - -/* GPIO definitions */ -#define MAX3107_GPIO_BASE 88 -#define MAX3107_GPIO_COUNT 4 - - -/* GPIO connected to chip's reset pin */ -#define MAX3107_RESET_GPIO 87 - - -/* Chip reset delay */ -#define MAX3107_RESET_DELAY 10 - -/* Chip wakeup delay */ -#define MAX3107_WAKEUP_DELAY 50 - - -/* Sleep mode definitions */ -#define MAX3107_DISABLE_FORCED_SLEEP 0 -#define MAX3107_ENABLE_FORCED_SLEEP 1 -#define MAX3107_DISABLE_AUTOSLEEP 2 -#define MAX3107_ENABLE_AUTOSLEEP 3 - - -/* Definitions for register access with SPI transfers - * - * SPI transfer format: - * - * Master to slave bits xzzzzzzzyyyyyyyy - * Slave to master bits aaaaaaaabbbbbbbb - * - * where: - * x = 0 for reads, 1 for writes - * z = register address - * y = new register value if write, 0 if read - * a = unspecified - * b = register value if read, unspecified if write - */ - -/* SPI speed */ -#define MAX3107_SPI_SPEED (3125000 * 2) - -/* Write bit */ -#define MAX3107_WRITE_BIT (1 << 15) - -/* SPI TX data mask */ -#define MAX3107_SPI_RX_DATA_MASK (0x00ff) - -/* SPI RX data mask */ -#define MAX3107_SPI_TX_DATA_MASK (0x00ff) - -/* Register access masks */ -#define MAX3107_RHR_REG (0x0000) /* RX FIFO */ -#define MAX3107_THR_REG (0x0000) /* TX FIFO */ -#define MAX3107_IRQEN_REG (0x0100) /* IRQ enable */ -#define MAX3107_IRQSTS_REG (0x0200) /* IRQ status */ -#define MAX3107_LSR_IRQEN_REG (0x0300) /* LSR IRQ enable */ -#define MAX3107_LSR_IRQSTS_REG (0x0400) /* LSR IRQ status */ -#define MAX3107_SPCHR_IRQEN_REG (0x0500) /* Special char IRQ enable */ -#define MAX3107_SPCHR_IRQSTS_REG (0x0600) /* Special char IRQ status */ -#define MAX3107_STS_IRQEN_REG (0x0700) /* Status IRQ enable */ -#define MAX3107_STS_IRQSTS_REG (0x0800) /* Status IRQ status */ -#define MAX3107_MODE1_REG (0x0900) /* MODE1 */ -#define MAX3107_MODE2_REG (0x0a00) /* MODE2 */ -#define MAX3107_LCR_REG (0x0b00) /* LCR */ -#define MAX3107_RXTO_REG (0x0c00) /* RX timeout */ -#define MAX3107_HDPIXDELAY_REG (0x0d00) /* Auto transceiver delays */ -#define MAX3107_IRDA_REG (0x0e00) /* IRDA settings */ -#define MAX3107_FLOWLVL_REG (0x0f00) /* Flow control levels */ -#define MAX3107_FIFOTRIGLVL_REG (0x1000) /* FIFO IRQ trigger levels */ -#define MAX3107_TXFIFOLVL_REG (0x1100) /* TX FIFO level */ -#define MAX3107_RXFIFOLVL_REG (0x1200) /* RX FIFO level */ -#define MAX3107_FLOWCTRL_REG (0x1300) /* Flow control */ -#define MAX3107_XON1_REG (0x1400) /* XON1 character */ -#define MAX3107_XON2_REG (0x1500) /* XON2 character */ -#define MAX3107_XOFF1_REG (0x1600) /* XOFF1 character */ -#define MAX3107_XOFF2_REG (0x1700) /* XOFF2 character */ -#define MAX3107_GPIOCFG_REG (0x1800) /* GPIO config */ -#define MAX3107_GPIODATA_REG (0x1900) /* GPIO data */ -#define MAX3107_PLLCFG_REG (0x1a00) /* PLL config */ -#define MAX3107_BRGCFG_REG (0x1b00) /* Baud rate generator conf */ -#define MAX3107_BRGDIVLSB_REG (0x1c00) /* Baud rate divisor LSB */ -#define MAX3107_BRGDIVMSB_REG (0x1d00) /* Baud rate divisor MSB */ -#define MAX3107_CLKSRC_REG (0x1e00) /* Clock source */ -#define MAX3107_REVID_REG (0x1f00) /* Revision identification */ - -/* IRQ register bits */ -#define MAX3107_IRQ_LSR_BIT (1 << 0) /* LSR interrupt */ -#define MAX3107_IRQ_SPCHR_BIT (1 << 1) /* Special char interrupt */ -#define MAX3107_IRQ_STS_BIT (1 << 2) /* Status interrupt */ -#define MAX3107_IRQ_RXFIFO_BIT (1 << 3) /* RX FIFO interrupt */ -#define MAX3107_IRQ_TXFIFO_BIT (1 << 4) /* TX FIFO interrupt */ -#define MAX3107_IRQ_TXEMPTY_BIT (1 << 5) /* TX FIFO empty interrupt */ -#define MAX3107_IRQ_RXEMPTY_BIT (1 << 6) /* RX FIFO empty interrupt */ -#define MAX3107_IRQ_CTS_BIT (1 << 7) /* CTS interrupt */ - -/* LSR register bits */ -#define MAX3107_LSR_RXTO_BIT (1 << 0) /* RX timeout */ -#define MAX3107_LSR_RXOVR_BIT (1 << 1) /* RX overrun */ -#define MAX3107_LSR_RXPAR_BIT (1 << 2) /* RX parity error */ -#define MAX3107_LSR_FRERR_BIT (1 << 3) /* Frame error */ -#define MAX3107_LSR_RXBRK_BIT (1 << 4) /* RX break */ -#define MAX3107_LSR_RXNOISE_BIT (1 << 5) /* RX noise */ -#define MAX3107_LSR_UNDEF6_BIT (1 << 6) /* Undefined/not used */ -#define MAX3107_LSR_CTS_BIT (1 << 7) /* CTS pin state */ - -/* Special character register bits */ -#define MAX3107_SPCHR_XON1_BIT (1 << 0) /* XON1 character */ -#define MAX3107_SPCHR_XON2_BIT (1 << 1) /* XON2 character */ -#define MAX3107_SPCHR_XOFF1_BIT (1 << 2) /* XOFF1 character */ -#define MAX3107_SPCHR_XOFF2_BIT (1 << 3) /* XOFF2 character */ -#define MAX3107_SPCHR_BREAK_BIT (1 << 4) /* RX break */ -#define MAX3107_SPCHR_MULTIDROP_BIT (1 << 5) /* 9-bit multidrop addr char */ -#define MAX3107_SPCHR_UNDEF6_BIT (1 << 6) /* Undefined/not used */ -#define MAX3107_SPCHR_UNDEF7_BIT (1 << 7) /* Undefined/not used */ - -/* Status register bits */ -#define MAX3107_STS_GPIO0_BIT (1 << 0) /* GPIO 0 interrupt */ -#define MAX3107_STS_GPIO1_BIT (1 << 1) /* GPIO 1 interrupt */ -#define MAX3107_STS_GPIO2_BIT (1 << 2) /* GPIO 2 interrupt */ -#define MAX3107_STS_GPIO3_BIT (1 << 3) /* GPIO 3 interrupt */ -#define MAX3107_STS_UNDEF4_BIT (1 << 4) /* Undefined/not used */ -#define MAX3107_STS_CLKREADY_BIT (1 << 5) /* Clock ready */ -#define MAX3107_STS_SLEEP_BIT (1 << 6) /* Sleep interrupt */ -#define MAX3107_STS_UNDEF7_BIT (1 << 7) /* Undefined/not used */ - -/* MODE1 register bits */ -#define MAX3107_MODE1_RXDIS_BIT (1 << 0) /* RX disable */ -#define MAX3107_MODE1_TXDIS_BIT (1 << 1) /* TX disable */ -#define MAX3107_MODE1_TXHIZ_BIT (1 << 2) /* TX pin three-state */ -#define MAX3107_MODE1_RTSHIZ_BIT (1 << 3) /* RTS pin three-state */ -#define MAX3107_MODE1_TRNSCVCTRL_BIT (1 << 4) /* Transceiver ctrl enable */ -#define MAX3107_MODE1_FORCESLEEP_BIT (1 << 5) /* Force sleep mode */ -#define MAX3107_MODE1_AUTOSLEEP_BIT (1 << 6) /* Auto sleep enable */ -#define MAX3107_MODE1_IRQSEL_BIT (1 << 7) /* IRQ pin enable */ - -/* MODE2 register bits */ -#define MAX3107_MODE2_RST_BIT (1 << 0) /* Chip reset */ -#define MAX3107_MODE2_FIFORST_BIT (1 << 1) /* FIFO reset */ -#define MAX3107_MODE2_RXTRIGINV_BIT (1 << 2) /* RX FIFO INT invert */ -#define MAX3107_MODE2_RXEMPTINV_BIT (1 << 3) /* RX FIFO empty INT invert */ -#define MAX3107_MODE2_SPCHR_BIT (1 << 4) /* Special chr detect enable */ -#define MAX3107_MODE2_LOOPBACK_BIT (1 << 5) /* Internal loopback enable */ -#define MAX3107_MODE2_MULTIDROP_BIT (1 << 6) /* 9-bit multidrop enable */ -#define MAX3107_MODE2_ECHOSUPR_BIT (1 << 7) /* ECHO suppression enable */ - -/* LCR register bits */ -#define MAX3107_LCR_LENGTH0_BIT (1 << 0) /* Word length bit 0 */ -#define MAX3107_LCR_LENGTH1_BIT (1 << 1) /* Word length bit 1 - * - * Word length bits table: - * 00 -> 5 bit words - * 01 -> 6 bit words - * 10 -> 7 bit words - * 11 -> 8 bit words - */ -#define MAX3107_LCR_STOPLEN_BIT (1 << 2) /* STOP length bit - * - * STOP length bit table: - * 0 -> 1 stop bit - * 1 -> 1-1.5 stop bits if - * word length is 5, - * 2 stop bits otherwise - */ -#define MAX3107_LCR_PARITY_BIT (1 << 3) /* Parity bit enable */ -#define MAX3107_LCR_EVENPARITY_BIT (1 << 4) /* Even parity bit enable */ -#define MAX3107_LCR_FORCEPARITY_BIT (1 << 5) /* 9-bit multidrop parity */ -#define MAX3107_LCR_TXBREAK_BIT (1 << 6) /* TX break enable */ -#define MAX3107_LCR_RTS_BIT (1 << 7) /* RTS pin control */ -#define MAX3107_LCR_WORD_LEN_5 (0x0000) -#define MAX3107_LCR_WORD_LEN_6 (0x0001) -#define MAX3107_LCR_WORD_LEN_7 (0x0002) -#define MAX3107_LCR_WORD_LEN_8 (0x0003) - - -/* IRDA register bits */ -#define MAX3107_IRDA_IRDAEN_BIT (1 << 0) /* IRDA mode enable */ -#define MAX3107_IRDA_SIR_BIT (1 << 1) /* SIR mode enable */ -#define MAX3107_IRDA_SHORTIR_BIT (1 << 2) /* Short SIR mode enable */ -#define MAX3107_IRDA_MIR_BIT (1 << 3) /* MIR mode enable */ -#define MAX3107_IRDA_RXINV_BIT (1 << 4) /* RX logic inversion enable */ -#define MAX3107_IRDA_TXINV_BIT (1 << 5) /* TX logic inversion enable */ -#define MAX3107_IRDA_UNDEF6_BIT (1 << 6) /* Undefined/not used */ -#define MAX3107_IRDA_UNDEF7_BIT (1 << 7) /* Undefined/not used */ - -/* Flow control trigger level register masks */ -#define MAX3107_FLOWLVL_HALT_MASK (0x000f) /* Flow control halt level */ -#define MAX3107_FLOWLVL_RES_MASK (0x00f0) /* Flow control resume level */ -#define MAX3107_FLOWLVL_HALT(words) ((words/8) & 0x000f) -#define MAX3107_FLOWLVL_RES(words) (((words/8) & 0x000f) << 4) - -/* FIFO interrupt trigger level register masks */ -#define MAX3107_FIFOTRIGLVL_TX_MASK (0x000f) /* TX FIFO trigger level */ -#define MAX3107_FIFOTRIGLVL_RX_MASK (0x00f0) /* RX FIFO trigger level */ -#define MAX3107_FIFOTRIGLVL_TX(words) ((words/8) & 0x000f) -#define MAX3107_FIFOTRIGLVL_RX(words) (((words/8) & 0x000f) << 4) - -/* Flow control register bits */ -#define MAX3107_FLOWCTRL_AUTORTS_BIT (1 << 0) /* Auto RTS flow ctrl enable */ -#define MAX3107_FLOWCTRL_AUTOCTS_BIT (1 << 1) /* Auto CTS flow ctrl enable */ -#define MAX3107_FLOWCTRL_GPIADDR_BIT (1 << 2) /* Enables that GPIO inputs - * are used in conjunction with - * XOFF2 for definition of - * special character */ -#define MAX3107_FLOWCTRL_SWFLOWEN_BIT (1 << 3) /* Auto SW flow ctrl enable */ -#define MAX3107_FLOWCTRL_SWFLOW0_BIT (1 << 4) /* SWFLOW bit 0 */ -#define MAX3107_FLOWCTRL_SWFLOW1_BIT (1 << 5) /* SWFLOW bit 1 - * - * SWFLOW bits 1 & 0 table: - * 00 -> no transmitter flow - * control - * 01 -> receiver compares - * XON2 and XOFF2 - * and controls - * transmitter - * 10 -> receiver compares - * XON1 and XOFF1 - * and controls - * transmitter - * 11 -> receiver compares - * XON1, XON2, XOFF1 and - * XOFF2 and controls - * transmitter - */ -#define MAX3107_FLOWCTRL_SWFLOW2_BIT (1 << 6) /* SWFLOW bit 2 */ -#define MAX3107_FLOWCTRL_SWFLOW3_BIT (1 << 7) /* SWFLOW bit 3 - * - * SWFLOW bits 3 & 2 table: - * 00 -> no received flow - * control - * 01 -> transmitter generates - * XON2 and XOFF2 - * 10 -> transmitter generates - * XON1 and XOFF1 - * 11 -> transmitter generates - * XON1, XON2, XOFF1 and - * XOFF2 - */ - -/* GPIO configuration register bits */ -#define MAX3107_GPIOCFG_GP0OUT_BIT (1 << 0) /* GPIO 0 output enable */ -#define MAX3107_GPIOCFG_GP1OUT_BIT (1 << 1) /* GPIO 1 output enable */ -#define MAX3107_GPIOCFG_GP2OUT_BIT (1 << 2) /* GPIO 2 output enable */ -#define MAX3107_GPIOCFG_GP3OUT_BIT (1 << 3) /* GPIO 3 output enable */ -#define MAX3107_GPIOCFG_GP0OD_BIT (1 << 4) /* GPIO 0 open-drain enable */ -#define MAX3107_GPIOCFG_GP1OD_BIT (1 << 5) /* GPIO 1 open-drain enable */ -#define MAX3107_GPIOCFG_GP2OD_BIT (1 << 6) /* GPIO 2 open-drain enable */ -#define MAX3107_GPIOCFG_GP3OD_BIT (1 << 7) /* GPIO 3 open-drain enable */ - -/* GPIO DATA register bits */ -#define MAX3107_GPIODATA_GP0OUT_BIT (1 << 0) /* GPIO 0 output value */ -#define MAX3107_GPIODATA_GP1OUT_BIT (1 << 1) /* GPIO 1 output value */ -#define MAX3107_GPIODATA_GP2OUT_BIT (1 << 2) /* GPIO 2 output value */ -#define MAX3107_GPIODATA_GP3OUT_BIT (1 << 3) /* GPIO 3 output value */ -#define MAX3107_GPIODATA_GP0IN_BIT (1 << 4) /* GPIO 0 input value */ -#define MAX3107_GPIODATA_GP1IN_BIT (1 << 5) /* GPIO 1 input value */ -#define MAX3107_GPIODATA_GP2IN_BIT (1 << 6) /* GPIO 2 input value */ -#define MAX3107_GPIODATA_GP3IN_BIT (1 << 7) /* GPIO 3 input value */ - -/* PLL configuration register masks */ -#define MAX3107_PLLCFG_PREDIV_MASK (0x003f) /* PLL predivision value */ -#define MAX3107_PLLCFG_PLLFACTOR_MASK (0x00c0) /* PLL multiplication factor */ - -/* Baud rate generator configuration register masks and bits */ -#define MAX3107_BRGCFG_FRACT_MASK (0x000f) /* Fractional portion of - * Baud rate generator divisor - */ -#define MAX3107_BRGCFG_2XMODE_BIT (1 << 4) /* Double baud rate */ -#define MAX3107_BRGCFG_4XMODE_BIT (1 << 5) /* Quadruple baud rate */ -#define MAX3107_BRGCFG_UNDEF6_BIT (1 << 6) /* Undefined/not used */ -#define MAX3107_BRGCFG_UNDEF7_BIT (1 << 7) /* Undefined/not used */ - -/* Clock source register bits */ -#define MAX3107_CLKSRC_INTOSC_BIT (1 << 0) /* Internal osc enable */ -#define MAX3107_CLKSRC_CRYST_BIT (1 << 1) /* Crystal osc enable */ -#define MAX3107_CLKSRC_PLL_BIT (1 << 2) /* PLL enable */ -#define MAX3107_CLKSRC_PLLBYP_BIT (1 << 3) /* PLL bypass */ -#define MAX3107_CLKSRC_EXTCLK_BIT (1 << 4) /* External clock enable */ -#define MAX3107_CLKSRC_UNDEF5_BIT (1 << 5) /* Undefined/not used */ -#define MAX3107_CLKSRC_UNDEF6_BIT (1 << 6) /* Undefined/not used */ -#define MAX3107_CLKSRC_CLK2RTS_BIT (1 << 7) /* Baud clk to RTS pin */ - - -/* HW definitions */ -#define MAX3107_RX_FIFO_SIZE 128 -#define MAX3107_TX_FIFO_SIZE 128 -#define MAX3107_REVID1 0x00a0 -#define MAX3107_REVID2 0x00a1 - - -/* Baud rate generator configuration values for external clock 13MHz */ -#define MAX3107_BRG13_B300 (0x0A9400 | 0x05) -#define MAX3107_BRG13_B600 (0x054A00 | 0x03) -#define MAX3107_BRG13_B1200 (0x02A500 | 0x01) -#define MAX3107_BRG13_B2400 (0x015200 | 0x09) -#define MAX3107_BRG13_B4800 (0x00A900 | 0x04) -#define MAX3107_BRG13_B9600 (0x005400 | 0x0A) -#define MAX3107_BRG13_B19200 (0x002A00 | 0x05) -#define MAX3107_BRG13_B38400 (0x001500 | 0x03) -#define MAX3107_BRG13_B57600 (0x000E00 | 0x02) -#define MAX3107_BRG13_B115200 (0x000700 | 0x01) -#define MAX3107_BRG13_B230400 (0x000300 | 0x08) -#define MAX3107_BRG13_B460800 (0x000100 | 0x0c) -#define MAX3107_BRG13_B921600 (0x000100 | 0x1c) - -/* Baud rate generator configuration values for external clock 26MHz */ -#define MAX3107_BRG26_B300 (0x152800 | 0x0A) -#define MAX3107_BRG26_B600 (0x0A9400 | 0x05) -#define MAX3107_BRG26_B1200 (0x054A00 | 0x03) -#define MAX3107_BRG26_B2400 (0x02A500 | 0x01) -#define MAX3107_BRG26_B4800 (0x015200 | 0x09) -#define MAX3107_BRG26_B9600 (0x00A900 | 0x04) -#define MAX3107_BRG26_B19200 (0x005400 | 0x0A) -#define MAX3107_BRG26_B38400 (0x002A00 | 0x05) -#define MAX3107_BRG26_B57600 (0x001C00 | 0x03) -#define MAX3107_BRG26_B115200 (0x000E00 | 0x02) -#define MAX3107_BRG26_B230400 (0x000700 | 0x01) -#define MAX3107_BRG26_B460800 (0x000300 | 0x08) -#define MAX3107_BRG26_B921600 (0x000100 | 0x0C) - -/* Baud rate generator configuration values for internal clock */ -#define MAX3107_BRG13_IB300 (0x008000 | 0x00) -#define MAX3107_BRG13_IB600 (0x004000 | 0x00) -#define MAX3107_BRG13_IB1200 (0x002000 | 0x00) -#define MAX3107_BRG13_IB2400 (0x001000 | 0x00) -#define MAX3107_BRG13_IB4800 (0x000800 | 0x00) -#define MAX3107_BRG13_IB9600 (0x000400 | 0x00) -#define MAX3107_BRG13_IB19200 (0x000200 | 0x00) -#define MAX3107_BRG13_IB38400 (0x000100 | 0x00) -#define MAX3107_BRG13_IB57600 (0x000000 | 0x0B) -#define MAX3107_BRG13_IB115200 (0x000000 | 0x05) -#define MAX3107_BRG13_IB230400 (0x000000 | 0x03) -#define MAX3107_BRG13_IB460800 (0x000000 | 0x00) -#define MAX3107_BRG13_IB921600 (0x000000 | 0x00) - - -struct baud_table { - int baud; - u32 new_brg; -}; - -struct max3107_port { - /* UART port structure */ - struct uart_port port; - - /* SPI device structure */ - struct spi_device *spi; - -#if defined(CONFIG_GPIOLIB) - /* GPIO chip structure */ - struct gpio_chip chip; -#endif - - /* Workqueue that does all the magic */ - struct workqueue_struct *workqueue; - struct work_struct work; - - /* Lock for shared data */ - spinlock_t data_lock; - - /* Device configuration */ - int ext_clk; /* 1 if external clock used */ - int loopback; /* Current loopback mode state */ - int baud; /* Current baud rate */ - - /* State flags */ - int suspended; /* Indicates suspend mode */ - int tx_fifo_empty; /* Flag for TX FIFO state */ - int rx_enabled; /* Flag for receiver state */ - int tx_enabled; /* Flag for transmitter state */ - - u16 irqen_reg; /* Current IRQ enable register value */ - /* Shared data */ - u16 mode1_reg; /* Current mode1 register value*/ - int mode1_commit; /* Flag for setting new mode1 register value */ - u16 lcr_reg; /* Current LCR register value */ - int lcr_commit; /* Flag for setting new LCR register value */ - u32 brg_cfg; /* Current Baud rate generator config */ - int brg_commit; /* Flag for setting new baud rate generator - * config - */ - struct baud_table *baud_tbl; - int handle_irq; /* Indicates that IRQ should be handled */ - - /* Rx buffer and str*/ - u16 *rxbuf; - u8 *rxstr; - /* Tx buffer*/ - u16 *txbuf; - - struct max3107_plat *pdata; /* Platform data */ -}; - -/* Platform data structure */ -struct max3107_plat { - /* Loopback mode enable */ - int loopback; - /* External clock enable */ - int ext_clk; - /* Called during the register initialisation */ - void (*init)(struct max3107_port *s); - /* Called when the port is found and configured */ - int (*configure)(struct max3107_port *s); - /* HW suspend function */ - void (*hw_suspend) (struct max3107_port *s, int suspend); - /* Polling mode enable */ - int polled_mode; - /* Polling period if polling mode enabled */ - int poll_time; -}; - -extern int max3107_rw(struct max3107_port *s, u8 *tx, u8 *rx, int len); -extern void max3107_hw_susp(struct max3107_port *s, int suspend); -extern int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata); -extern int max3107_remove(struct spi_device *spi); -extern int max3107_suspend(struct spi_device *spi, pm_message_t state); -extern int max3107_resume(struct spi_device *spi); - -#endif /* _LINUX_SERIAL_MAX3107_H */ diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c new file mode 100644 index 000000000000..2bc28a59d385 --- /dev/null +++ b/drivers/tty/serial/max310x.c @@ -0,0 +1,1260 @@ +/* + * Maxim (Dallas) MAX3107/8 serial driver + * + * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru> + * + * Based on max3100.c, by Christian Pellegrin <chripell@evolware.org> + * Based on max3110.c, by Feng Tang <feng.tang@intel.com> + * Based on max3107.c, by Aavamobile + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +/* TODO: MAX3109 support (Dual) */ +/* TODO: MAX14830 support (Quad) */ + +#include <linux/module.h> +#include <linux/device.h> +#include <linux/serial_core.h> +#include <linux/serial.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/regmap.h> +#include <linux/gpio.h> +#include <linux/spi/spi.h> +#include <linux/platform_data/max310x.h> + +#define MAX310X_MAJOR 204 +#define MAX310X_MINOR 209 + +/* MAX310X register definitions */ +#define MAX310X_RHR_REG (0x00) /* RX FIFO */ +#define MAX310X_THR_REG (0x00) /* TX FIFO */ +#define MAX310X_IRQEN_REG (0x01) /* IRQ enable */ +#define MAX310X_IRQSTS_REG (0x02) /* IRQ status */ +#define MAX310X_LSR_IRQEN_REG (0x03) /* LSR IRQ enable */ +#define MAX310X_LSR_IRQSTS_REG (0x04) /* LSR IRQ status */ +#define MAX310X_SPCHR_IRQEN_REG (0x05) /* Special char IRQ enable */ +#define MAX310X_SPCHR_IRQSTS_REG (0x06) /* Special char IRQ status */ +#define MAX310X_STS_IRQEN_REG (0x07) /* Status IRQ enable */ +#define MAX310X_STS_IRQSTS_REG (0x08) /* Status IRQ status */ +#define MAX310X_MODE1_REG (0x09) /* MODE1 */ +#define MAX310X_MODE2_REG (0x0a) /* MODE2 */ +#define MAX310X_LCR_REG (0x0b) /* LCR */ +#define MAX310X_RXTO_REG (0x0c) /* RX timeout */ +#define MAX310X_HDPIXDELAY_REG (0x0d) /* Auto transceiver delays */ +#define MAX310X_IRDA_REG (0x0e) /* IRDA settings */ +#define MAX310X_FLOWLVL_REG (0x0f) /* Flow control levels */ +#define MAX310X_FIFOTRIGLVL_REG (0x10) /* FIFO IRQ trigger levels */ +#define MAX310X_TXFIFOLVL_REG (0x11) /* TX FIFO level */ +#define MAX310X_RXFIFOLVL_REG (0x12) /* RX FIFO level */ +#define MAX310X_FLOWCTRL_REG (0x13) /* Flow control */ +#define MAX310X_XON1_REG (0x14) /* XON1 character */ +#define MAX310X_XON2_REG (0x15) /* XON2 character */ +#define MAX310X_XOFF1_REG (0x16) /* XOFF1 character */ +#define MAX310X_XOFF2_REG (0x17) /* XOFF2 character */ +#define MAX310X_GPIOCFG_REG (0x18) /* GPIO config */ +#define MAX310X_GPIODATA_REG (0x19) /* GPIO data */ +#define MAX310X_PLLCFG_REG (0x1a) /* PLL config */ +#define MAX310X_BRGCFG_REG (0x1b) /* Baud rate generator conf */ +#define MAX310X_BRGDIVLSB_REG (0x1c) /* Baud rate divisor LSB */ +#define MAX310X_BRGDIVMSB_REG (0x1d) /* Baud rate divisor MSB */ +#define MAX310X_CLKSRC_REG (0x1e) /* Clock source */ +/* Only present in MAX3107 */ +#define MAX3107_REVID_REG (0x1f) /* Revision identification */ + +/* IRQ register bits */ +#define MAX310X_IRQ_LSR_BIT (1 << 0) /* LSR interrupt */ +#define MAX310X_IRQ_SPCHR_BIT (1 << 1) /* Special char interrupt */ +#define MAX310X_IRQ_STS_BIT (1 << 2) /* Status interrupt */ +#define MAX310X_IRQ_RXFIFO_BIT (1 << 3) /* RX FIFO interrupt */ +#define MAX310X_IRQ_TXFIFO_BIT (1 << 4) /* TX FIFO interrupt */ +#define MAX310X_IRQ_TXEMPTY_BIT (1 << 5) /* TX FIFO empty interrupt */ +#define MAX310X_IRQ_RXEMPTY_BIT (1 << 6) /* RX FIFO empty interrupt */ +#define MAX310X_IRQ_CTS_BIT (1 << 7) /* CTS interrupt */ + +/* LSR register bits */ +#define MAX310X_LSR_RXTO_BIT (1 << 0) /* RX timeout */ +#define MAX310X_LSR_RXOVR_BIT (1 << 1) /* RX overrun */ +#define MAX310X_LSR_RXPAR_BIT (1 << 2) /* RX parity error */ +#define MAX310X_LSR_FRERR_BIT (1 << 3) /* Frame error */ +#define MAX310X_LSR_RXBRK_BIT (1 << 4) /* RX break */ +#define MAX310X_LSR_RXNOISE_BIT (1 << 5) /* RX noise */ +#define MAX310X_LSR_CTS_BIT (1 << 7) /* CTS pin state */ + +/* Special character register bits */ +#define MAX310X_SPCHR_XON1_BIT (1 << 0) /* XON1 character */ +#define MAX310X_SPCHR_XON2_BIT (1 << 1) /* XON2 character */ +#define MAX310X_SPCHR_XOFF1_BIT (1 << 2) /* XOFF1 character */ +#define MAX310X_SPCHR_XOFF2_BIT (1 << 3) /* XOFF2 character */ +#define MAX310X_SPCHR_BREAK_BIT (1 << 4) /* RX break */ +#define MAX310X_SPCHR_MULTIDROP_BIT (1 << 5) /* 9-bit multidrop addr char */ + +/* Status register bits */ +#define MAX310X_STS_GPIO0_BIT (1 << 0) /* GPIO 0 interrupt */ +#define MAX310X_STS_GPIO1_BIT (1 << 1) /* GPIO 1 interrupt */ +#define MAX310X_STS_GPIO2_BIT (1 << 2) /* GPIO 2 interrupt */ +#define MAX310X_STS_GPIO3_BIT (1 << 3) /* GPIO 3 interrupt */ +#define MAX310X_STS_CLKREADY_BIT (1 << 5) /* Clock ready */ +#define MAX310X_STS_SLEEP_BIT (1 << 6) /* Sleep interrupt */ + +/* MODE1 register bits */ +#define MAX310X_MODE1_RXDIS_BIT (1 << 0) /* RX disable */ +#define MAX310X_MODE1_TXDIS_BIT (1 << 1) /* TX disable */ +#define MAX310X_MODE1_TXHIZ_BIT (1 << 2) /* TX pin three-state */ +#define MAX310X_MODE1_RTSHIZ_BIT (1 << 3) /* RTS pin three-state */ +#define MAX310X_MODE1_TRNSCVCTRL_BIT (1 << 4) /* Transceiver ctrl enable */ +#define MAX310X_MODE1_FORCESLEEP_BIT (1 << 5) /* Force sleep mode */ +#define MAX310X_MODE1_AUTOSLEEP_BIT (1 << 6) /* Auto sleep enable */ +#define MAX310X_MODE1_IRQSEL_BIT (1 << 7) /* IRQ pin enable */ + +/* MODE2 register bits */ +#define MAX310X_MODE2_RST_BIT (1 << 0) /* Chip reset */ +#define MAX310X_MODE2_FIFORST_BIT (1 << 1) /* FIFO reset */ +#define MAX310X_MODE2_RXTRIGINV_BIT (1 << 2) /* RX FIFO INT invert */ +#define MAX310X_MODE2_RXEMPTINV_BIT (1 << 3) /* RX FIFO empty INT invert */ +#define MAX310X_MODE2_SPCHR_BIT (1 << 4) /* Special chr detect enable */ +#define MAX310X_MODE2_LOOPBACK_BIT (1 << 5) /* Internal loopback enable */ +#define MAX310X_MODE2_MULTIDROP_BIT (1 << 6) /* 9-bit multidrop enable */ +#define MAX310X_MODE2_ECHOSUPR_BIT (1 << 7) /* ECHO suppression enable */ + +/* LCR register bits */ +#define MAX310X_LCR_LENGTH0_BIT (1 << 0) /* Word length bit 0 */ +#define MAX310X_LCR_LENGTH1_BIT (1 << 1) /* Word length bit 1 + * + * Word length bits table: + * 00 -> 5 bit words + * 01 -> 6 bit words + * 10 -> 7 bit words + * 11 -> 8 bit words + */ +#define MAX310X_LCR_STOPLEN_BIT (1 << 2) /* STOP length bit + * + * STOP length bit table: + * 0 -> 1 stop bit + * 1 -> 1-1.5 stop bits if + * word length is 5, + * 2 stop bits otherwise + */ +#define MAX310X_LCR_PARITY_BIT (1 << 3) /* Parity bit enable */ +#define MAX310X_LCR_EVENPARITY_BIT (1 << 4) /* Even parity bit enable */ +#define MAX310X_LCR_FORCEPARITY_BIT (1 << 5) /* 9-bit multidrop parity */ +#define MAX310X_LCR_TXBREAK_BIT (1 << 6) /* TX break enable */ +#define MAX310X_LCR_RTS_BIT (1 << 7) /* RTS pin control */ +#define MAX310X_LCR_WORD_LEN_5 (0x00) +#define MAX310X_LCR_WORD_LEN_6 (0x01) +#define MAX310X_LCR_WORD_LEN_7 (0x02) +#define MAX310X_LCR_WORD_LEN_8 (0x03) + +/* IRDA register bits */ +#define MAX310X_IRDA_IRDAEN_BIT (1 << 0) /* IRDA mode enable */ +#define MAX310X_IRDA_SIR_BIT (1 << 1) /* SIR mode enable */ +#define MAX310X_IRDA_SHORTIR_BIT (1 << 2) /* Short SIR mode enable */ +#define MAX310X_IRDA_MIR_BIT (1 << 3) /* MIR mode enable */ +#define MAX310X_IRDA_RXINV_BIT (1 << 4) /* RX logic inversion enable */ +#define MAX310X_IRDA_TXINV_BIT (1 << 5) /* TX logic inversion enable */ + +/* Flow control trigger level register masks */ +#define MAX310X_FLOWLVL_HALT_MASK (0x000f) /* Flow control halt level */ +#define MAX310X_FLOWLVL_RES_MASK (0x00f0) /* Flow control resume level */ +#define MAX310X_FLOWLVL_HALT(words) ((words / 8) & 0x0f) +#define MAX310X_FLOWLVL_RES(words) (((words / 8) & 0x0f) << 4) + +/* FIFO interrupt trigger level register masks */ +#define MAX310X_FIFOTRIGLVL_TX_MASK (0x0f) /* TX FIFO trigger level */ +#define MAX310X_FIFOTRIGLVL_RX_MASK (0xf0) /* RX FIFO trigger level */ +#define MAX310X_FIFOTRIGLVL_TX(words) ((words / 8) & 0x0f) +#define MAX310X_FIFOTRIGLVL_RX(words) (((words / 8) & 0x0f) << 4) + +/* Flow control register bits */ +#define MAX310X_FLOWCTRL_AUTORTS_BIT (1 << 0) /* Auto RTS flow ctrl enable */ +#define MAX310X_FLOWCTRL_AUTOCTS_BIT (1 << 1) /* Auto CTS flow ctrl enable */ +#define MAX310X_FLOWCTRL_GPIADDR_BIT (1 << 2) /* Enables that GPIO inputs + * are used in conjunction with + * XOFF2 for definition of + * special character */ +#define MAX310X_FLOWCTRL_SWFLOWEN_BIT (1 << 3) /* Auto SW flow ctrl enable */ +#define MAX310X_FLOWCTRL_SWFLOW0_BIT (1 << 4) /* SWFLOW bit 0 */ +#define MAX310X_FLOWCTRL_SWFLOW1_BIT (1 << 5) /* SWFLOW bit 1 + * + * SWFLOW bits 1 & 0 table: + * 00 -> no transmitter flow + * control + * 01 -> receiver compares + * XON2 and XOFF2 + * and controls + * transmitter + * 10 -> receiver compares + * XON1 and XOFF1 + * and controls + * transmitter + * 11 -> receiver compares + * XON1, XON2, XOFF1 and + * XOFF2 and controls + * transmitter + */ +#define MAX310X_FLOWCTRL_SWFLOW2_BIT (1 << 6) /* SWFLOW bit 2 */ +#define MAX310X_FLOWCTRL_SWFLOW3_BIT (1 << 7) /* SWFLOW bit 3 + * + * SWFLOW bits 3 & 2 table: + * 00 -> no received flow + * control + * 01 -> transmitter generates + * XON2 and XOFF2 + * 10 -> transmitter generates + * XON1 and XOFF1 + * 11 -> transmitter generates + * XON1, XON2, XOFF1 and + * XOFF2 + */ + +/* GPIO configuration register bits */ +#define MAX310X_GPIOCFG_GP0OUT_BIT (1 << 0) /* GPIO 0 output enable */ +#define MAX310X_GPIOCFG_GP1OUT_BIT (1 << 1) /* GPIO 1 output enable */ +#define MAX310X_GPIOCFG_GP2OUT_BIT (1 << 2) /* GPIO 2 output enable */ +#define MAX310X_GPIOCFG_GP3OUT_BIT (1 << 3) /* GPIO 3 output enable */ +#define MAX310X_GPIOCFG_GP0OD_BIT (1 << 4) /* GPIO 0 open-drain enable */ +#define MAX310X_GPIOCFG_GP1OD_BIT (1 << 5) /* GPIO 1 open-drain enable */ +#define MAX310X_GPIOCFG_GP2OD_BIT (1 << 6) /* GPIO 2 open-drain enable */ +#define MAX310X_GPIOCFG_GP3OD_BIT (1 << 7) /* GPIO 3 open-drain enable */ + +/* GPIO DATA register bits */ +#define MAX310X_GPIODATA_GP0OUT_BIT (1 << 0) /* GPIO 0 output value */ +#define MAX310X_GPIODATA_GP1OUT_BIT (1 << 1) /* GPIO 1 output value */ +#define MAX310X_GPIODATA_GP2OUT_BIT (1 << 2) /* GPIO 2 output value */ +#define MAX310X_GPIODATA_GP3OUT_BIT (1 << 3) /* GPIO 3 output value */ +#define MAX310X_GPIODATA_GP0IN_BIT (1 << 4) /* GPIO 0 input value */ +#define MAX310X_GPIODATA_GP1IN_BIT (1 << 5) /* GPIO 1 input value */ +#define MAX310X_GPIODATA_GP2IN_BIT (1 << 6) /* GPIO 2 input value */ +#define MAX310X_GPIODATA_GP3IN_BIT (1 << 7) /* GPIO 3 input value */ + +/* PLL configuration register masks */ +#define MAX310X_PLLCFG_PREDIV_MASK (0x3f) /* PLL predivision value */ +#define MAX310X_PLLCFG_PLLFACTOR_MASK (0xc0) /* PLL multiplication factor */ + +/* Baud rate generator configuration register bits */ +#define MAX310X_BRGCFG_2XMODE_BIT (1 << 4) /* Double baud rate */ +#define MAX310X_BRGCFG_4XMODE_BIT (1 << 5) /* Quadruple baud rate */ + +/* Clock source register bits */ +#define MAX310X_CLKSRC_CRYST_BIT (1 << 1) /* Crystal osc enable */ +#define MAX310X_CLKSRC_PLL_BIT (1 << 2) /* PLL enable */ +#define MAX310X_CLKSRC_PLLBYP_BIT (1 << 3) /* PLL bypass */ +#define MAX310X_CLKSRC_EXTCLK_BIT (1 << 4) /* External clock enable */ +#define MAX310X_CLKSRC_CLK2RTS_BIT (1 << 7) /* Baud clk to RTS pin */ + +/* Misc definitions */ +#define MAX310X_FIFO_SIZE (128) + +/* MAX3107 specific */ +#define MAX3107_REV_ID (0xa0) +#define MAX3107_REV_MASK (0xfe) + +/* IRQ status bits definitions */ +#define MAX310X_IRQ_TX (MAX310X_IRQ_TXFIFO_BIT | \ + MAX310X_IRQ_TXEMPTY_BIT) +#define MAX310X_IRQ_RX (MAX310X_IRQ_RXFIFO_BIT | \ + MAX310X_IRQ_RXEMPTY_BIT) + +/* Supported chip types */ +enum { + MAX310X_TYPE_MAX3107 = 3107, + MAX310X_TYPE_MAX3108 = 3108, +}; + +struct max310x_port { + struct uart_driver uart; + struct uart_port port; + + const char *name; + int uartclk; + + unsigned int nr_gpio; +#ifdef CONFIG_GPIOLIB + struct gpio_chip gpio; +#endif + + struct regmap *regmap; + struct regmap_config regcfg; + + struct workqueue_struct *wq; + struct work_struct tx_work; + + struct mutex max310x_mutex; + + struct max310x_pdata *pdata; +}; + +static bool max3107_8_reg_writeable(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX310X_IRQSTS_REG: + case MAX310X_LSR_IRQSTS_REG: + case MAX310X_SPCHR_IRQSTS_REG: + case MAX310X_STS_IRQSTS_REG: + case MAX310X_TXFIFOLVL_REG: + case MAX310X_RXFIFOLVL_REG: + case MAX3107_REVID_REG: /* Only available on MAX3107 */ + return false; + default: + break; + } + + return true; +} + +static bool max310x_reg_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX310X_RHR_REG: + case MAX310X_IRQSTS_REG: + case MAX310X_LSR_IRQSTS_REG: + case MAX310X_SPCHR_IRQSTS_REG: + case MAX310X_STS_IRQSTS_REG: + case MAX310X_TXFIFOLVL_REG: + case MAX310X_RXFIFOLVL_REG: + case MAX310X_GPIODATA_REG: + return true; + default: + break; + } + + return false; +} + +static bool max310x_reg_precious(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX310X_RHR_REG: + case MAX310X_IRQSTS_REG: + case MAX310X_SPCHR_IRQSTS_REG: + case MAX310X_STS_IRQSTS_REG: + return true; + default: + break; + } + + return false; +} + +static void max310x_set_baud(struct max310x_port *s, int baud) +{ + unsigned int mode = 0, div = s->uartclk / baud; + + if (!(div / 16)) { + /* Mode x2 */ + mode = MAX310X_BRGCFG_2XMODE_BIT; + div = (s->uartclk * 2) / baud; + } + + if (!(div / 16)) { + /* Mode x4 */ + mode = MAX310X_BRGCFG_4XMODE_BIT; + div = (s->uartclk * 4) / baud; + } + + regmap_write(s->regmap, MAX310X_BRGDIVMSB_REG, + ((div / 16) >> 8) & 0xff); + regmap_write(s->regmap, MAX310X_BRGDIVLSB_REG, (div / 16) & 0xff); + regmap_write(s->regmap, MAX310X_BRGCFG_REG, (div % 16) | mode); +} + +static void max310x_wait_pll(struct max310x_port *s) +{ + int tryes = 1000; + + /* Wait for PLL only if crystal is used */ + if (!(s->pdata->driver_flags & MAX310X_EXT_CLK)) { + unsigned int sts = 0; + + while (tryes--) { + regmap_read(s->regmap, MAX310X_STS_IRQSTS_REG, &sts); + if (sts & MAX310X_STS_CLKREADY_BIT) + break; + } + } +} + +static int __devinit max310x_update_best_err(unsigned long f, long *besterr) +{ + /* Use baudrate 115200 for calculate error */ + long err = f % (115200 * 16); + + if ((*besterr < 0) || (*besterr > err)) { + *besterr = err; + return 0; + } + + return 1; +} + +static int __devinit max310x_set_ref_clk(struct max310x_port *s) +{ + unsigned int div, clksrc, pllcfg = 0; + long besterr = -1; + unsigned long fdiv, fmul, bestfreq = s->pdata->frequency; + + /* First, update error without PLL */ + max310x_update_best_err(s->pdata->frequency, &besterr); + + /* Try all possible PLL dividers */ + for (div = 1; (div <= 63) && besterr; div++) { + fdiv = DIV_ROUND_CLOSEST(s->pdata->frequency, div); + + /* Try multiplier 6 */ + fmul = fdiv * 6; + if ((fdiv >= 500000) && (fdiv <= 800000)) + if (!max310x_update_best_err(fmul, &besterr)) { + pllcfg = (0 << 6) | div; + bestfreq = fmul; + } + /* Try multiplier 48 */ + fmul = fdiv * 48; + if ((fdiv >= 850000) && (fdiv <= 1200000)) + if (!max310x_update_best_err(fmul, &besterr)) { + pllcfg = (1 << 6) | div; + bestfreq = fmul; + } + /* Try multiplier 96 */ + fmul = fdiv * 96; + if ((fdiv >= 425000) && (fdiv <= 1000000)) + if (!max310x_update_best_err(fmul, &besterr)) { + pllcfg = (2 << 6) | div; + bestfreq = fmul; + } + /* Try multiplier 144 */ + fmul = fdiv * 144; + if ((fdiv >= 390000) && (fdiv <= 667000)) + if (!max310x_update_best_err(fmul, &besterr)) { + pllcfg = (3 << 6) | div; + bestfreq = fmul; + } + } + + /* Configure clock source */ + if (s->pdata->driver_flags & MAX310X_EXT_CLK) + clksrc = MAX310X_CLKSRC_EXTCLK_BIT; + else + clksrc = MAX310X_CLKSRC_CRYST_BIT; + + /* Configure PLL */ + if (pllcfg) { + clksrc |= MAX310X_CLKSRC_PLL_BIT; + regmap_write(s->regmap, MAX310X_PLLCFG_REG, pllcfg); + } else + clksrc |= MAX310X_CLKSRC_PLLBYP_BIT; + + regmap_write(s->regmap, MAX310X_CLKSRC_REG, clksrc); + + if (pllcfg) + max310x_wait_pll(s); + + dev_dbg(s->port.dev, "Reference clock set to %lu Hz\n", bestfreq); + + return (int)bestfreq; +} + +static void max310x_handle_rx(struct max310x_port *s, unsigned int rxlen) +{ + unsigned int sts = 0, ch = 0, flag; + struct tty_struct *tty = tty_port_tty_get(&s->port.state->port); + + if (!tty) + return; + + if (unlikely(rxlen >= MAX310X_FIFO_SIZE)) { + dev_warn(s->port.dev, "Possible RX FIFO overrun %d\n", rxlen); + /* Ensure sanity of RX level */ + rxlen = MAX310X_FIFO_SIZE; + } + + dev_dbg(s->port.dev, "RX Len = %u\n", rxlen); + + while (rxlen--) { + regmap_read(s->regmap, MAX310X_RHR_REG, &ch); + regmap_read(s->regmap, MAX310X_LSR_IRQSTS_REG, &sts); + + sts &= MAX310X_LSR_RXPAR_BIT | MAX310X_LSR_FRERR_BIT | + MAX310X_LSR_RXOVR_BIT | MAX310X_LSR_RXBRK_BIT; + + s->port.icount.rx++; + flag = TTY_NORMAL; + + if (unlikely(sts)) { + if (sts & MAX310X_LSR_RXBRK_BIT) { + s->port.icount.brk++; + if (uart_handle_break(&s->port)) + continue; + } else if (sts & MAX310X_LSR_RXPAR_BIT) + s->port.icount.parity++; + else if (sts & MAX310X_LSR_FRERR_BIT) + s->port.icount.frame++; + else if (sts & MAX310X_LSR_RXOVR_BIT) + s->port.icount.overrun++; + + sts &= s->port.read_status_mask; + if (sts & MAX310X_LSR_RXBRK_BIT) + flag = TTY_BREAK; + else if (sts & MAX310X_LSR_RXPAR_BIT) + flag = TTY_PARITY; + else if (sts & MAX310X_LSR_FRERR_BIT) + flag = TTY_FRAME; + else if (sts & MAX310X_LSR_RXOVR_BIT) + flag = TTY_OVERRUN; + } + + if (uart_handle_sysrq_char(s->port, ch)) + continue; + + if (sts & s->port.ignore_status_mask) + continue; + + uart_insert_char(&s->port, sts, MAX310X_LSR_RXOVR_BIT, + ch, flag); + } + + tty_flip_buffer_push(tty); + + tty_kref_put(tty); +} + +static void max310x_handle_tx(struct max310x_port *s) +{ + struct circ_buf *xmit = &s->port.state->xmit; + unsigned int txlen = 0, to_send; + + if (unlikely(s->port.x_char)) { + regmap_write(s->regmap, MAX310X_THR_REG, s->port.x_char); + s->port.icount.tx++; + s->port.x_char = 0; + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(&s->port)) + return; + + /* Get length of data pending in circular buffer */ + to_send = uart_circ_chars_pending(xmit); + if (likely(to_send)) { + /* Limit to size of TX FIFO */ + regmap_read(s->regmap, MAX310X_TXFIFOLVL_REG, &txlen); + txlen = MAX310X_FIFO_SIZE - txlen; + to_send = (to_send > txlen) ? txlen : to_send; + + dev_dbg(s->port.dev, "TX Len = %u\n", to_send); + + /* Add data to send */ + s->port.icount.tx += to_send; + while (to_send--) { + regmap_write(s->regmap, MAX310X_THR_REG, + xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + }; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&s->port); +} + +static irqreturn_t max310x_ist(int irq, void *dev_id) +{ + struct max310x_port *s = (struct max310x_port *)dev_id; + unsigned int ists = 0, lsr = 0, rxlen = 0; + + mutex_lock(&s->max310x_mutex); + + for (;;) { + /* Read IRQ status & RX FIFO level */ + regmap_read(s->regmap, MAX310X_IRQSTS_REG, &ists); + regmap_read(s->regmap, MAX310X_LSR_IRQSTS_REG, &lsr); + regmap_read(s->regmap, MAX310X_RXFIFOLVL_REG, &rxlen); + if (!ists && !(lsr & MAX310X_LSR_RXTO_BIT) && !rxlen) + break; + + dev_dbg(s->port.dev, "IRQ status: 0x%02x\n", ists); + + if (rxlen) + max310x_handle_rx(s, rxlen); + if (ists & MAX310X_IRQ_TX) + max310x_handle_tx(s); + if (ists & MAX310X_IRQ_CTS_BIT) + uart_handle_cts_change(&s->port, + !!(lsr & MAX310X_LSR_CTS_BIT)); + } + + mutex_unlock(&s->max310x_mutex); + + return IRQ_HANDLED; +} + +static void max310x_wq_proc(struct work_struct *ws) +{ + struct max310x_port *s = container_of(ws, struct max310x_port, tx_work); + + mutex_lock(&s->max310x_mutex); + max310x_handle_tx(s); + mutex_unlock(&s->max310x_mutex); +} + +static void max310x_start_tx(struct uart_port *port) +{ + struct max310x_port *s = container_of(port, struct max310x_port, port); + + queue_work(s->wq, &s->tx_work); +} + +static void max310x_stop_tx(struct uart_port *port) +{ + /* Do nothing */ +} + +static void max310x_stop_rx(struct uart_port *port) +{ + /* Do nothing */ +} + +static unsigned int max310x_tx_empty(struct uart_port *port) +{ + unsigned int val = 0; + struct max310x_port *s = container_of(port, struct max310x_port, port); + + mutex_lock(&s->max310x_mutex); + regmap_read(s->regmap, MAX310X_TXFIFOLVL_REG, &val); + mutex_unlock(&s->max310x_mutex); + + return val ? 0 : TIOCSER_TEMT; +} + +static void max310x_enable_ms(struct uart_port *port) +{ + /* Modem status not supported */ +} + +static unsigned int max310x_get_mctrl(struct uart_port *port) +{ + /* DCD and DSR are not wired and CTS/RTS is handled automatically + * so just indicate DSR and CAR asserted + */ + return TIOCM_DSR | TIOCM_CAR; +} + +static void max310x_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + /* DCD and DSR are not wired and CTS/RTS is hadnled automatically + * so do nothing + */ +} + +static void max310x_break_ctl(struct uart_port *port, int break_state) +{ + struct max310x_port *s = container_of(port, struct max310x_port, port); + + mutex_lock(&s->max310x_mutex); + regmap_update_bits(s->regmap, MAX310X_LCR_REG, + MAX310X_LCR_TXBREAK_BIT, + break_state ? MAX310X_LCR_TXBREAK_BIT : 0); + mutex_unlock(&s->max310x_mutex); +} + +static void max310x_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + struct max310x_port *s = container_of(port, struct max310x_port, port); + unsigned int lcr, flow = 0; + int baud; + + mutex_lock(&s->max310x_mutex); + + /* Mask termios capabilities we don't support */ + termios->c_cflag &= ~CMSPAR; + termios->c_iflag &= ~IXANY; + + /* Word size */ + switch (termios->c_cflag & CSIZE) { + case CS5: + lcr = MAX310X_LCR_WORD_LEN_5; + break; + case CS6: + lcr = MAX310X_LCR_WORD_LEN_6; + break; + case CS7: + lcr = MAX310X_LCR_WORD_LEN_7; + break; + case CS8: + default: + lcr = MAX310X_LCR_WORD_LEN_8; + break; + } + + /* Parity */ + if (termios->c_cflag & PARENB) { + lcr |= MAX310X_LCR_PARITY_BIT; + if (!(termios->c_cflag & PARODD)) + lcr |= MAX310X_LCR_EVENPARITY_BIT; + } + + /* Stop bits */ + if (termios->c_cflag & CSTOPB) + lcr |= MAX310X_LCR_STOPLEN_BIT; /* 2 stops */ + + /* Update LCR register */ + regmap_write(s->regmap, MAX310X_LCR_REG, lcr); + + /* Set read status mask */ + port->read_status_mask = MAX310X_LSR_RXOVR_BIT; + if (termios->c_iflag & INPCK) + port->read_status_mask |= MAX310X_LSR_RXPAR_BIT | + MAX310X_LSR_FRERR_BIT; + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= MAX310X_LSR_RXBRK_BIT; + + /* Set status ignore mask */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNBRK) + port->ignore_status_mask |= MAX310X_LSR_RXBRK_BIT; + if (!(termios->c_cflag & CREAD)) + port->ignore_status_mask |= MAX310X_LSR_RXPAR_BIT | + MAX310X_LSR_RXOVR_BIT | + MAX310X_LSR_FRERR_BIT | + MAX310X_LSR_RXBRK_BIT; + + /* Configure flow control */ + regmap_write(s->regmap, MAX310X_XON1_REG, termios->c_cc[VSTART]); + regmap_write(s->regmap, MAX310X_XOFF1_REG, termios->c_cc[VSTOP]); + if (termios->c_cflag & CRTSCTS) + flow |= MAX310X_FLOWCTRL_AUTOCTS_BIT | + MAX310X_FLOWCTRL_AUTORTS_BIT; + if (termios->c_iflag & IXON) + flow |= MAX310X_FLOWCTRL_SWFLOW3_BIT | + MAX310X_FLOWCTRL_SWFLOWEN_BIT; + if (termios->c_iflag & IXOFF) + flow |= MAX310X_FLOWCTRL_SWFLOW1_BIT | + MAX310X_FLOWCTRL_SWFLOWEN_BIT; + regmap_write(s->regmap, MAX310X_FLOWCTRL_REG, flow); + + /* Get baud rate generator configuration */ + baud = uart_get_baud_rate(port, termios, old, + port->uartclk / 16 / 0xffff, + port->uartclk / 4); + + /* Setup baudrate generator */ + max310x_set_baud(s, baud); + + /* Update timeout according to new baud rate */ + uart_update_timeout(port, termios->c_cflag, baud); + + mutex_unlock(&s->max310x_mutex); +} + +static int max310x_startup(struct uart_port *port) +{ + unsigned int val, line = port->line; + struct max310x_port *s = container_of(port, struct max310x_port, port); + + if (s->pdata->suspend) + s->pdata->suspend(0); + + mutex_lock(&s->max310x_mutex); + + /* Configure baud rate, 9600 as default */ + max310x_set_baud(s, 9600); + + /* Configure LCR register, 8N1 mode by default */ + val = MAX310X_LCR_WORD_LEN_8; + regmap_write(s->regmap, MAX310X_LCR_REG, val); + + /* Configure MODE1 register */ + regmap_update_bits(s->regmap, MAX310X_MODE1_REG, + MAX310X_MODE1_TRNSCVCTRL_BIT, + (s->pdata->uart_flags[line] & MAX310X_AUTO_DIR_CTRL) + ? MAX310X_MODE1_TRNSCVCTRL_BIT : 0); + + /* Configure MODE2 register */ + val = MAX310X_MODE2_RXEMPTINV_BIT; + if (s->pdata->uart_flags[line] & MAX310X_LOOPBACK) + val |= MAX310X_MODE2_LOOPBACK_BIT; + if (s->pdata->uart_flags[line] & MAX310X_ECHO_SUPRESS) + val |= MAX310X_MODE2_ECHOSUPR_BIT; + + /* Reset FIFOs */ + val |= MAX310X_MODE2_FIFORST_BIT; + regmap_write(s->regmap, MAX310X_MODE2_REG, val); + + /* Configure FIFO trigger level register */ + /* RX FIFO trigger for 16 words, TX FIFO trigger for 64 words */ + val = MAX310X_FIFOTRIGLVL_RX(16) | MAX310X_FIFOTRIGLVL_TX(64); + regmap_write(s->regmap, MAX310X_FIFOTRIGLVL_REG, val); + + /* Configure flow control levels */ + /* Flow control halt level 96, resume level 48 */ + val = MAX310X_FLOWLVL_RES(48) | MAX310X_FLOWLVL_HALT(96); + regmap_write(s->regmap, MAX310X_FLOWLVL_REG, val); + + /* Clear timeout register */ + regmap_write(s->regmap, MAX310X_RXTO_REG, 0); + + /* Configure LSR interrupt enable register */ + /* Enable RX timeout interrupt */ + val = MAX310X_LSR_RXTO_BIT; + regmap_write(s->regmap, MAX310X_LSR_IRQEN_REG, val); + + /* Clear FIFO reset */ + regmap_update_bits(s->regmap, MAX310X_MODE2_REG, + MAX310X_MODE2_FIFORST_BIT, 0); + + /* Clear IRQ status register by reading it */ + regmap_read(s->regmap, MAX310X_IRQSTS_REG, &val); + + /* Configure interrupt enable register */ + /* Enable CTS change interrupt */ + val = MAX310X_IRQ_CTS_BIT; + /* Enable RX, TX interrupts */ + val |= MAX310X_IRQ_RX | MAX310X_IRQ_TX; + regmap_write(s->regmap, MAX310X_IRQEN_REG, val); + + mutex_unlock(&s->max310x_mutex); + + return 0; +} + +static void max310x_shutdown(struct uart_port *port) +{ + struct max310x_port *s = container_of(port, struct max310x_port, port); + + /* Disable all interrupts */ + mutex_lock(&s->max310x_mutex); + regmap_write(s->regmap, MAX310X_IRQEN_REG, 0); + mutex_unlock(&s->max310x_mutex); + + if (s->pdata->suspend) + s->pdata->suspend(1); +} + +static const char *max310x_type(struct uart_port *port) +{ + struct max310x_port *s = container_of(port, struct max310x_port, port); + + return (port->type == PORT_MAX310X) ? s->name : NULL; +} + +static int max310x_request_port(struct uart_port *port) +{ + /* Do nothing */ + return 0; +} + +static void max310x_release_port(struct uart_port *port) +{ + /* Do nothing */ +} + +static void max310x_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) + port->type = PORT_MAX310X; +} + +static int max310x_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + if ((ser->type == PORT_UNKNOWN) || (ser->type == PORT_MAX310X)) + return 0; + if (ser->irq == port->irq) + return 0; + + return -EINVAL; +} + +static struct uart_ops max310x_ops = { + .tx_empty = max310x_tx_empty, + .set_mctrl = max310x_set_mctrl, + .get_mctrl = max310x_get_mctrl, + .stop_tx = max310x_stop_tx, + .start_tx = max310x_start_tx, + .stop_rx = max310x_stop_rx, + .enable_ms = max310x_enable_ms, + .break_ctl = max310x_break_ctl, + .startup = max310x_startup, + .shutdown = max310x_shutdown, + .set_termios = max310x_set_termios, + .type = max310x_type, + .request_port = max310x_request_port, + .release_port = max310x_release_port, + .config_port = max310x_config_port, + .verify_port = max310x_verify_port, +}; + +static int max310x_suspend(struct spi_device *spi, pm_message_t state) +{ + int ret; + struct max310x_port *s = dev_get_drvdata(&spi->dev); + + dev_dbg(&spi->dev, "Suspend\n"); + + ret = uart_suspend_port(&s->uart, &s->port); + + mutex_lock(&s->max310x_mutex); + + /* Enable sleep mode */ + regmap_update_bits(s->regmap, MAX310X_MODE1_REG, + MAX310X_MODE1_FORCESLEEP_BIT, + MAX310X_MODE1_FORCESLEEP_BIT); + + mutex_unlock(&s->max310x_mutex); + + if (s->pdata->suspend) + s->pdata->suspend(1); + + return ret; +} + +static int max310x_resume(struct spi_device *spi) +{ + struct max310x_port *s = dev_get_drvdata(&spi->dev); + + dev_dbg(&spi->dev, "Resume\n"); + + if (s->pdata->suspend) + s->pdata->suspend(0); + + mutex_lock(&s->max310x_mutex); + + /* Disable sleep mode */ + regmap_update_bits(s->regmap, MAX310X_MODE1_REG, + MAX310X_MODE1_FORCESLEEP_BIT, + 0); + + max310x_wait_pll(s); + + mutex_unlock(&s->max310x_mutex); + + return uart_resume_port(&s->uart, &s->port); +} + +#ifdef CONFIG_GPIOLIB +static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + unsigned int val = 0; + struct max310x_port *s = container_of(chip, struct max310x_port, gpio); + + mutex_lock(&s->max310x_mutex); + regmap_read(s->regmap, MAX310X_GPIODATA_REG, &val); + mutex_unlock(&s->max310x_mutex); + + return !!((val >> 4) & (1 << offset)); +} + +static void max310x_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct max310x_port *s = container_of(chip, struct max310x_port, gpio); + + mutex_lock(&s->max310x_mutex); + regmap_update_bits(s->regmap, MAX310X_GPIODATA_REG, 1 << offset, value ? + 1 << offset : 0); + mutex_unlock(&s->max310x_mutex); +} + +static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct max310x_port *s = container_of(chip, struct max310x_port, gpio); + + mutex_lock(&s->max310x_mutex); + + regmap_update_bits(s->regmap, MAX310X_GPIOCFG_REG, 1 << offset, 0); + + mutex_unlock(&s->max310x_mutex); + + return 0; +} + +static int max310x_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct max310x_port *s = container_of(chip, struct max310x_port, gpio); + + mutex_lock(&s->max310x_mutex); + + regmap_update_bits(s->regmap, MAX310X_GPIOCFG_REG, 1 << offset, + 1 << offset); + regmap_update_bits(s->regmap, MAX310X_GPIODATA_REG, 1 << offset, value ? + 1 << offset : 0); + + mutex_unlock(&s->max310x_mutex); + + return 0; +} +#endif + +/* Generic platform data */ +static struct max310x_pdata generic_plat_data = { + .driver_flags = MAX310X_EXT_CLK, + .uart_flags[0] = MAX310X_ECHO_SUPRESS, + .frequency = 26000000, +}; + +static int __devinit max310x_probe(struct spi_device *spi) +{ + struct max310x_port *s; + struct device *dev = &spi->dev; + int chiptype = spi_get_device_id(spi)->driver_data; + struct max310x_pdata *pdata = dev->platform_data; + unsigned int val = 0; + int ret; + + /* Check for IRQ */ + if (spi->irq <= 0) { + dev_err(dev, "No IRQ specified\n"); + return -ENOTSUPP; + } + + /* Alloc port structure */ + s = devm_kzalloc(dev, sizeof(struct max310x_port), GFP_KERNEL); + if (!s) { + dev_err(dev, "Error allocating port structure\n"); + return -ENOMEM; + } + dev_set_drvdata(dev, s); + + if (!pdata) { + dev_warn(dev, "No platform data supplied, using defaults\n"); + pdata = &generic_plat_data; + } + s->pdata = pdata; + + /* Individual chip settings */ + switch (chiptype) { + case MAX310X_TYPE_MAX3107: + s->name = "MAX3107"; + s->nr_gpio = 4; + s->uart.nr = 1; + s->regcfg.max_register = 0x1f; + break; + case MAX310X_TYPE_MAX3108: + s->name = "MAX3108"; + s->nr_gpio = 4; + s->uart.nr = 1; + s->regcfg.max_register = 0x1e; + break; + default: + dev_err(dev, "Unsupported chip type %i\n", chiptype); + return -ENOTSUPP; + } + + /* Check input frequency */ + if ((pdata->driver_flags & MAX310X_EXT_CLK) && + ((pdata->frequency < 500000) || (pdata->frequency > 35000000))) + goto err_freq; + /* Check frequency for quartz */ + if (!(pdata->driver_flags & MAX310X_EXT_CLK) && + ((pdata->frequency < 1000000) || (pdata->frequency > 4000000))) + goto err_freq; + + mutex_init(&s->max310x_mutex); + + /* Setup SPI bus */ + spi->mode = SPI_MODE_0; + spi->bits_per_word = 8; + spi->max_speed_hz = 26000000; + spi_setup(spi); + + /* Setup regmap */ + s->regcfg.reg_bits = 8; + s->regcfg.val_bits = 8; + s->regcfg.read_flag_mask = 0x00; + s->regcfg.write_flag_mask = 0x80; + s->regcfg.cache_type = REGCACHE_RBTREE; + s->regcfg.writeable_reg = max3107_8_reg_writeable; + s->regcfg.volatile_reg = max310x_reg_volatile; + s->regcfg.precious_reg = max310x_reg_precious; + s->regmap = devm_regmap_init_spi(spi, &s->regcfg); + if (IS_ERR(s->regmap)) { + ret = PTR_ERR(s->regmap); + dev_err(dev, "Failed to initialize register map\n"); + goto err_out; + } + + /* Reset chip & check SPI function */ + ret = regmap_write(s->regmap, MAX310X_MODE2_REG, MAX310X_MODE2_RST_BIT); + if (ret) { + dev_err(dev, "SPI transfer failed\n"); + goto err_out; + } + /* Clear chip reset */ + regmap_write(s->regmap, MAX310X_MODE2_REG, 0); + + switch (chiptype) { + case MAX310X_TYPE_MAX3107: + /* Check REV ID to ensure we are talking to what we expect */ + regmap_read(s->regmap, MAX3107_REVID_REG, &val); + if (((val & MAX3107_REV_MASK) != MAX3107_REV_ID)) { + dev_err(dev, "%s ID 0x%02x does not match\n", + s->name, val); + ret = -ENODEV; + goto err_out; + } + break; + case MAX310X_TYPE_MAX3108: + /* MAX3108 have not REV ID register, we just check default value + * from clocksource register to make sure everything works. + */ + regmap_read(s->regmap, MAX310X_CLKSRC_REG, &val); + if (val != (MAX310X_CLKSRC_EXTCLK_BIT | + MAX310X_CLKSRC_PLLBYP_BIT)) { + dev_err(dev, "%s not present\n", s->name); + ret = -ENODEV; + goto err_out; + } + break; + } + + /* Board specific configure */ + if (pdata->init) + pdata->init(); + if (pdata->suspend) + pdata->suspend(0); + + /* Calculate referecne clock */ + s->uartclk = max310x_set_ref_clk(s); + + /* Disable all interrupts */ + regmap_write(s->regmap, MAX310X_IRQEN_REG, 0); + + /* Setup MODE1 register */ + val = MAX310X_MODE1_IRQSEL_BIT; /* Enable IRQ pin */ + if (pdata->driver_flags & MAX310X_AUTOSLEEP) + val = MAX310X_MODE1_AUTOSLEEP_BIT; + regmap_write(s->regmap, MAX310X_MODE1_REG, val); + + /* Setup interrupt */ + ret = devm_request_threaded_irq(dev, spi->irq, NULL, max310x_ist, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + dev_name(dev), s); + if (ret) { + dev_err(dev, "Unable to reguest IRQ %i\n", spi->irq); + goto err_out; + } + + /* Register UART driver */ + s->uart.owner = THIS_MODULE; + s->uart.driver_name = dev_name(dev); + s->uart.dev_name = "ttyMAX"; + s->uart.major = MAX310X_MAJOR; + s->uart.minor = MAX310X_MINOR; + ret = uart_register_driver(&s->uart); + if (ret) { + dev_err(dev, "Registering UART driver failed\n"); + goto err_out; + } + + /* Initialize workqueue for start TX */ + s->wq = create_freezable_workqueue(dev_name(dev)); + INIT_WORK(&s->tx_work, max310x_wq_proc); + + /* Initialize UART port data */ + s->port.line = 0; + s->port.dev = dev; + s->port.irq = spi->irq; + s->port.type = PORT_MAX310X; + s->port.fifosize = MAX310X_FIFO_SIZE; + s->port.flags = UPF_SKIP_TEST | UPF_FIXED_TYPE; + s->port.iotype = UPIO_PORT; + s->port.membase = (void __iomem *)0xffffffff; /* Bogus value */ + s->port.uartclk = s->uartclk; + s->port.ops = &max310x_ops; + uart_add_one_port(&s->uart, &s->port); + +#ifdef CONFIG_GPIOLIB + /* Setup GPIO cotroller */ + if (pdata->gpio_base) { + s->gpio.owner = THIS_MODULE; + s->gpio.dev = dev; + s->gpio.label = dev_name(dev); + s->gpio.direction_input = max310x_gpio_direction_input; + s->gpio.get = max310x_gpio_get; + s->gpio.direction_output= max310x_gpio_direction_output; + s->gpio.set = max310x_gpio_set; + s->gpio.base = pdata->gpio_base; + s->gpio.ngpio = s->nr_gpio; + if (gpiochip_add(&s->gpio)) { + /* Indicate that we should not call gpiochip_remove */ + s->gpio.base = 0; + } + } else + dev_info(dev, "GPIO support not enabled\n"); +#endif + + /* Go to suspend mode */ + if (pdata->suspend) + pdata->suspend(1); + + return 0; + +err_freq: + dev_err(dev, "Frequency parameter incorrect\n"); + ret = -EINVAL; + +err_out: + dev_set_drvdata(dev, NULL); + + return ret; +} + +static int __devexit max310x_remove(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct max310x_port *s = dev_get_drvdata(dev); + int ret = 0; + + dev_dbg(dev, "Removing port\n"); + + devm_free_irq(dev, s->port.irq, s); + + destroy_workqueue(s->wq); + + uart_remove_one_port(&s->uart, &s->port); + + uart_unregister_driver(&s->uart); + +#ifdef CONFIG_GPIOLIB + if (s->pdata->gpio_base) { + ret = gpiochip_remove(&s->gpio); + if (ret) + dev_err(dev, "Failed to remove gpio chip: %d\n", ret); + } +#endif + + dev_set_drvdata(dev, NULL); + + if (s->pdata->suspend) + s->pdata->suspend(1); + if (s->pdata->exit) + s->pdata->exit(); + + return ret; +} + +static const struct spi_device_id max310x_id_table[] = { + { "max3107", MAX310X_TYPE_MAX3107 }, + { "max3108", MAX310X_TYPE_MAX3108 }, +}; +MODULE_DEVICE_TABLE(spi, max310x_id_table); + +static struct spi_driver max310x_driver = { + .driver = { + .name = "max310x", + .owner = THIS_MODULE, + }, + .probe = max310x_probe, + .remove = __devexit_p(max310x_remove), + .suspend = max310x_suspend, + .resume = max310x_resume, + .id_table = max310x_id_table, +}; +module_spi_driver(max310x_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); +MODULE_DESCRIPTION("MAX310X serial driver"); diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index bedac0d4c9ce..f19d04ed8586 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -775,11 +775,15 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, } if (new->c_cflag & PARENB) { + if (new->c_cflag & CMSPAR) + mr1 |= MPC52xx_PSC_MODE_PARFORCE; + + /* With CMSPAR, PARODD also means high parity (same as termios) */ mr1 |= (new->c_cflag & PARODD) ? MPC52xx_PSC_MODE_PARODD : MPC52xx_PSC_MODE_PAREVEN; - } else + } else { mr1 |= MPC52xx_PSC_MODE_PARNONE; - + } mr2 = 0; diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 8131e2c28015..033e0bc9ebab 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -896,7 +896,7 @@ static int __init msm_serial_probe(struct platform_device *pdev) return PTR_ERR(msm_port->clk); if (msm_port->is_uartdm) - clk_set_rate(msm_port->clk, 7372800); + clk_set_rate(msm_port->clk, 1843200); port->uartclk = clk_get_rate(msm_port->clk); printk(KERN_INFO "uartclk = %d\n", port->uartclk); diff --git a/drivers/tty/serial/msm_smd_tty.c b/drivers/tty/serial/msm_smd_tty.c index b25e6ee71443..925d1fa153db 100644 --- a/drivers/tty/serial/msm_smd_tty.c +++ b/drivers/tty/serial/msm_smd_tty.c @@ -223,9 +223,11 @@ static int __init smd_tty_init(void) return ret; for (i = 0; i < smd_tty_channels_len; i++) { - tty_port_init(&smd_tty[smd_tty_channels[i].id].port); - smd_tty[smd_tty_channels[i].id].port.ops = &smd_tty_port_ops; - tty_register_device(smd_tty_driver, smd_tty_channels[i].id, 0); + struct tty_port *port = &smd_tty[smd_tty_channels[i].id].port; + tty_port_init(port); + port->ops = &smd_tty_port_ops; + tty_port_register_device(port, smd_tty_driver, + smd_tty_channels[i].id, NULL); } return 0; diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 3a667eed63d6..68984136bfb1 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -262,7 +262,7 @@ static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl) ctrl &= ~AUART_CTRL2_RTSEN; if (mctrl & TIOCM_RTS) { - if (u->state->port.flags & ASYNC_CTS_FLOW) + if (tty_port_cts_enabled(&u->state->port)) ctrl |= AUART_CTRL2_RTSEN; } @@ -457,11 +457,11 @@ static void mxs_auart_shutdown(struct uart_port *u) writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_CLR); - writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_SET); - writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN, u->membase + AUART_INTR_CLR); + writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_SET); + clk_disable_unprepare(s->clk); } @@ -796,6 +796,7 @@ static int __devexit mxs_auart_remove(struct platform_device *pdev) auart_port[pdev->id] = NULL; + put_device(s->dev); clk_put(s->clk); free_irq(s->irq, s); kfree(s); diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index 34e71874a892..df443b908ca3 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -105,6 +105,10 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev, port->uartclk = clk; port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE; + + if (of_find_property(np, "no-loopback-test", NULL)) + port->flags |= UPF_SKIP_TEST; + port->dev = &ofdev->dev; if (type == PORT_TEGRA) @@ -144,8 +148,15 @@ static int __devinit of_platform_serial_probe(struct platform_device *ofdev) switch (port_type) { #ifdef CONFIG_SERIAL_8250 case PORT_8250 ... PORT_MAX_8250: - ret = serial8250_register_port(&port); + { + /* For now the of bindings don't support the extra + 8250 specific bits */ + struct uart_8250_port port8250; + memset(&port8250, 0, sizeof(port8250)); + port8250.port = port; + ret = serial8250_register_8250_port(&port8250); break; + } #endif #ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL case PORT_NWPSERIAL: diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index d3cda0cb2df0..f175385bb304 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -32,16 +32,16 @@ #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_flip.h> +#include <linux/platform_device.h> #include <linux/io.h> -#include <linux/dma-mapping.h> #include <linux/clk.h> #include <linux/serial_core.h> #include <linux/irq.h> #include <linux/pm_runtime.h> #include <linux/of.h> +#include <linux/gpio.h> +#include <linux/pinctrl/consumer.h> -#include <plat/dma.h> -#include <plat/dmtimer.h> #include <plat/omap-serial.h> #define UART_BUILD_REVISION(x, y) (((x) << 8) | (y)) @@ -57,8 +57,8 @@ #define OMAP_UART_SCR_RX_TRIG_GRANU1_MASK (1 << 7) /* FCR register bitmasks */ -#define OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT 6 #define OMAP_UART_FCR_RX_FIFO_TRIG_MASK (0x3 << 6) +#define OMAP_UART_FCR_TX_FIFO_TRIG_MASK (0x3 << 4) /* MVR register bitmasks */ #define OMAP_UART_MVR_SCHEME_SHIFT 30 @@ -71,12 +71,52 @@ #define OMAP_UART_MVR_MAJ_SHIFT 8 #define OMAP_UART_MVR_MIN_MASK 0x3f +struct uart_omap_port { + struct uart_port port; + struct uart_omap_dma uart_dma; + struct device *dev; + + unsigned char ier; + unsigned char lcr; + unsigned char mcr; + unsigned char fcr; + unsigned char efr; + unsigned char dll; + unsigned char dlh; + unsigned char mdr1; + unsigned char scr; + + int use_dma; + /* + * Some bits in registers are cleared on a read, so they must + * be saved whenever the register is read but the bits will not + * be immediately processed. + */ + unsigned int lsr_break_flag; + unsigned char msr_saved_flags; + char name[20]; + unsigned long port_activity; + u32 context_loss_cnt; + u32 errata; + u8 wakeups_enabled; + unsigned int irq_pending:1; + + int DTR_gpio; + int DTR_inverted; + int DTR_active; + + struct pm_qos_request pm_qos_request; + u32 latency; + u32 calc_latency; + struct work_struct qos_work; + struct pinctrl *pins; +}; + +#define to_uart_omap_port(p) ((container_of((p), struct uart_omap_port, port))) + static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS]; /* Forward declaration of functions */ -static void uart_tx_dma_callback(int lch, u16 ch_status, void *data); -static void serial_omap_rxdma_poll(unsigned long uart_no); -static int serial_omap_start_rxdma(struct uart_omap_port *up); static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1); static struct workqueue_struct *serial_omap_uart_wq; @@ -101,6 +141,46 @@ static inline void serial_omap_clear_fifos(struct uart_omap_port *up) serial_out(up, UART_FCR, 0); } +static int serial_omap_get_context_loss_count(struct uart_omap_port *up) +{ + struct omap_uart_port_info *pdata = up->dev->platform_data; + + if (!pdata || !pdata->get_context_loss_count) + return 0; + + return pdata->get_context_loss_count(up->dev); +} + +static void serial_omap_set_forceidle(struct uart_omap_port *up) +{ + struct omap_uart_port_info *pdata = up->dev->platform_data; + + if (!pdata || !pdata->set_forceidle) + return; + + pdata->set_forceidle(up->dev); +} + +static void serial_omap_set_noidle(struct uart_omap_port *up) +{ + struct omap_uart_port_info *pdata = up->dev->platform_data; + + if (!pdata || !pdata->set_noidle) + return; + + pdata->set_noidle(up->dev); +} + +static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable) +{ + struct omap_uart_port_info *pdata = up->dev->platform_data; + + if (!pdata || !pdata->enable_wakeup) + return; + + pdata->enable_wakeup(up->dev, enable); +} + /* * serial_omap_get_divisor - calculate divisor value * @port: uart port info @@ -126,151 +206,55 @@ serial_omap_get_divisor(struct uart_port *port, unsigned int baud) return port->uartclk/(baud * divisor); } -static void serial_omap_stop_rxdma(struct uart_omap_port *up) -{ - if (up->uart_dma.rx_dma_used) { - del_timer(&up->uart_dma.rx_timer); - omap_stop_dma(up->uart_dma.rx_dma_channel); - omap_free_dma(up->uart_dma.rx_dma_channel); - up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE; - up->uart_dma.rx_dma_used = false; - pm_runtime_mark_last_busy(&up->pdev->dev); - pm_runtime_put_autosuspend(&up->pdev->dev); - } -} - static void serial_omap_enable_ms(struct uart_port *port) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); dev_dbg(up->port.dev, "serial_omap_enable_ms+%d\n", up->port.line); - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); up->ier |= UART_IER_MSI; serial_out(up, UART_IER, up->ier); - pm_runtime_put(&up->pdev->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); } static void serial_omap_stop_tx(struct uart_port *port) { - struct uart_omap_port *up = (struct uart_omap_port *)port; - struct omap_uart_port_info *pdata = up->pdev->dev.platform_data; + struct uart_omap_port *up = to_uart_omap_port(port); - if (up->use_dma && - up->uart_dma.tx_dma_channel != OMAP_UART_DMA_CH_FREE) { - /* - * Check if dma is still active. If yes do nothing, - * return. Else stop dma - */ - if (omap_get_dma_active_status(up->uart_dma.tx_dma_channel)) - return; - omap_stop_dma(up->uart_dma.tx_dma_channel); - omap_free_dma(up->uart_dma.tx_dma_channel); - up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE; - pm_runtime_mark_last_busy(&up->pdev->dev); - pm_runtime_put_autosuspend(&up->pdev->dev); - } - - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); if (up->ier & UART_IER_THRI) { up->ier &= ~UART_IER_THRI; serial_out(up, UART_IER, up->ier); } - if (!up->use_dma && pdata && pdata->set_forceidle) - pdata->set_forceidle(up->pdev); + serial_omap_set_forceidle(up); - pm_runtime_mark_last_busy(&up->pdev->dev); - pm_runtime_put_autosuspend(&up->pdev->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); } static void serial_omap_stop_rx(struct uart_port *port) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); - pm_runtime_get_sync(&up->pdev->dev); - if (up->use_dma) - serial_omap_stop_rxdma(up); + pm_runtime_get_sync(up->dev); up->ier &= ~UART_IER_RLSI; up->port.read_status_mask &= ~UART_LSR_DR; serial_out(up, UART_IER, up->ier); - pm_runtime_mark_last_busy(&up->pdev->dev); - pm_runtime_put_autosuspend(&up->pdev->dev); -} - -static inline void receive_chars(struct uart_omap_port *up, - unsigned int *status) -{ - struct tty_struct *tty = up->port.state->port.tty; - unsigned int flag, lsr = *status; - unsigned char ch = 0; - int max_count = 256; - - do { - if (likely(lsr & UART_LSR_DR)) - ch = serial_in(up, UART_RX); - flag = TTY_NORMAL; - up->port.icount.rx++; - - if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) { - /* - * For statistics only - */ - if (lsr & UART_LSR_BI) { - lsr &= ~(UART_LSR_FE | UART_LSR_PE); - up->port.icount.brk++; - /* - * We do the SysRQ and SAK checking - * here because otherwise the break - * may get masked by ignore_status_mask - * or read_status_mask. - */ - if (uart_handle_break(&up->port)) - goto ignore_char; - } else if (lsr & UART_LSR_PE) { - up->port.icount.parity++; - } else if (lsr & UART_LSR_FE) { - up->port.icount.frame++; - } - - if (lsr & UART_LSR_OE) - up->port.icount.overrun++; - - /* - * Mask off conditions which should be ignored. - */ - lsr &= up->port.read_status_mask; - -#ifdef CONFIG_SERIAL_OMAP_CONSOLE - if (up->port.line == up->port.cons->index) { - /* Recover the break flag from console xmit */ - lsr |= up->lsr_break_flag; - } -#endif - if (lsr & UART_LSR_BI) - flag = TTY_BREAK; - else if (lsr & UART_LSR_PE) - flag = TTY_PARITY; - else if (lsr & UART_LSR_FE) - flag = TTY_FRAME; - } - - if (uart_handle_sysrq_char(&up->port, ch)) - goto ignore_char; - uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag); -ignore_char: - lsr = serial_in(up, UART_LSR); - } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0)); - spin_unlock(&up->port.lock); - tty_flip_buffer_push(tty); - spin_lock(&up->port.lock); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); } -static void transmit_chars(struct uart_omap_port *up) +static void transmit_chars(struct uart_omap_port *up, unsigned int lsr) { struct circ_buf *xmit = &up->port.state->xmit; int count; + if (!(lsr & UART_LSR_THRE)) + return; + if (up->port.x_char) { serial_out(up, UART_TX, up->port.x_char); up->port.icount.tx++; @@ -290,8 +274,11 @@ static void transmit_chars(struct uart_omap_port *up) break; } while (--count > 0); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) { + spin_unlock(&up->port.lock); uart_write_wakeup(&up->port); + spin_lock(&up->port.lock); + } if (uart_circ_empty(xmit)) serial_omap_stop_tx(&up->port); @@ -307,70 +294,13 @@ static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up) static void serial_omap_start_tx(struct uart_port *port) { - struct uart_omap_port *up = (struct uart_omap_port *)port; - struct omap_uart_port_info *pdata = up->pdev->dev.platform_data; - struct circ_buf *xmit; - unsigned int start; - int ret = 0; - - if (!up->use_dma) { - pm_runtime_get_sync(&up->pdev->dev); - serial_omap_enable_ier_thri(up); - if (pdata && pdata->set_noidle) - pdata->set_noidle(up->pdev); - pm_runtime_mark_last_busy(&up->pdev->dev); - pm_runtime_put_autosuspend(&up->pdev->dev); - return; - } - - if (up->uart_dma.tx_dma_used) - return; - - xmit = &up->port.state->xmit; - - if (up->uart_dma.tx_dma_channel == OMAP_UART_DMA_CH_FREE) { - pm_runtime_get_sync(&up->pdev->dev); - ret = omap_request_dma(up->uart_dma.uart_dma_tx, - "UART Tx DMA", - (void *)uart_tx_dma_callback, up, - &(up->uart_dma.tx_dma_channel)); + struct uart_omap_port *up = to_uart_omap_port(port); - if (ret < 0) { - serial_omap_enable_ier_thri(up); - return; - } - } - spin_lock(&(up->uart_dma.tx_lock)); - up->uart_dma.tx_dma_used = true; - spin_unlock(&(up->uart_dma.tx_lock)); - - start = up->uart_dma.tx_buf_dma_phys + - (xmit->tail & (UART_XMIT_SIZE - 1)); - - up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit); - /* - * It is a circular buffer. See if the buffer has wounded back. - * If yes it will have to be transferred in two separate dma - * transfers - */ - if (start + up->uart_dma.tx_buf_size >= - up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) - up->uart_dma.tx_buf_size = - (up->uart_dma.tx_buf_dma_phys + - UART_XMIT_SIZE) - start; - - omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0, - OMAP_DMA_AMODE_CONSTANT, - up->uart_dma.uart_base, 0, 0); - omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0, - OMAP_DMA_AMODE_POST_INC, start, 0, 0); - omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel, - OMAP_DMA_DATA_TYPE_S8, - up->uart_dma.tx_buf_size, 1, - OMAP_DMA_SYNC_ELEMENT, - up->uart_dma.uart_dma_tx, 0); - /* FIXME: Cache maintenance needed here? */ - omap_start_dma(up->uart_dma.tx_dma_channel); + pm_runtime_get_sync(up->dev); + serial_omap_enable_ier_thri(up); + serial_omap_set_noidle(up); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); } static unsigned int check_modem_status(struct uart_omap_port *up) @@ -401,76 +331,158 @@ static unsigned int check_modem_status(struct uart_omap_port *up) return status; } +static void serial_omap_rlsi(struct uart_omap_port *up, unsigned int lsr) +{ + unsigned int flag; + + up->port.icount.rx++; + flag = TTY_NORMAL; + + if (lsr & UART_LSR_BI) { + flag = TTY_BREAK; + lsr &= ~(UART_LSR_FE | UART_LSR_PE); + up->port.icount.brk++; + /* + * We do the SysRQ and SAK checking + * here because otherwise the break + * may get masked by ignore_status_mask + * or read_status_mask. + */ + if (uart_handle_break(&up->port)) + return; + + } + + if (lsr & UART_LSR_PE) { + flag = TTY_PARITY; + up->port.icount.parity++; + } + + if (lsr & UART_LSR_FE) { + flag = TTY_FRAME; + up->port.icount.frame++; + } + + if (lsr & UART_LSR_OE) + up->port.icount.overrun++; + +#ifdef CONFIG_SERIAL_OMAP_CONSOLE + if (up->port.line == up->port.cons->index) { + /* Recover the break flag from console xmit */ + lsr |= up->lsr_break_flag; + } +#endif + uart_insert_char(&up->port, lsr, UART_LSR_OE, 0, flag); +} + +static void serial_omap_rdi(struct uart_omap_port *up, unsigned int lsr) +{ + unsigned char ch = 0; + unsigned int flag; + + if (!(lsr & UART_LSR_DR)) + return; + + ch = serial_in(up, UART_RX); + flag = TTY_NORMAL; + up->port.icount.rx++; + + if (uart_handle_sysrq_char(&up->port, ch)) + return; + + uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag); +} + /** * serial_omap_irq() - This handles the interrupt from one port * @irq: uart port irq number * @dev_id: uart port info */ -static inline irqreturn_t serial_omap_irq(int irq, void *dev_id) +static irqreturn_t serial_omap_irq(int irq, void *dev_id) { struct uart_omap_port *up = dev_id; + struct tty_struct *tty = up->port.state->port.tty; unsigned int iir, lsr; - unsigned long flags; + unsigned int type; + irqreturn_t ret = IRQ_NONE; + int max_count = 256; - pm_runtime_get_sync(&up->pdev->dev); - iir = serial_in(up, UART_IIR); - if (iir & UART_IIR_NO_INT) { - pm_runtime_mark_last_busy(&up->pdev->dev); - pm_runtime_put_autosuspend(&up->pdev->dev); - return IRQ_NONE; - } + spin_lock(&up->port.lock); + pm_runtime_get_sync(up->dev); - spin_lock_irqsave(&up->port.lock, flags); - lsr = serial_in(up, UART_LSR); - if (iir & UART_IIR_RLSI) { - if (!up->use_dma) { - if (lsr & UART_LSR_DR) - receive_chars(up, &lsr); - } else { - up->ier &= ~(UART_IER_RDI | UART_IER_RLSI); - serial_out(up, UART_IER, up->ier); - if ((serial_omap_start_rxdma(up) != 0) && - (lsr & UART_LSR_DR)) - receive_chars(up, &lsr); + do { + iir = serial_in(up, UART_IIR); + if (iir & UART_IIR_NO_INT) + break; + + ret = IRQ_HANDLED; + lsr = serial_in(up, UART_LSR); + + /* extract IRQ type from IIR register */ + type = iir & 0x3e; + + switch (type) { + case UART_IIR_MSI: + check_modem_status(up); + break; + case UART_IIR_THRI: + transmit_chars(up, lsr); + break; + case UART_IIR_RX_TIMEOUT: + /* FALLTHROUGH */ + case UART_IIR_RDI: + serial_omap_rdi(up, lsr); + break; + case UART_IIR_RLSI: + serial_omap_rlsi(up, lsr); + break; + case UART_IIR_CTS_RTS_DSR: + /* simply try again */ + break; + case UART_IIR_XOFF: + /* FALLTHROUGH */ + default: + break; } - } + } while (!(iir & UART_IIR_NO_INT) && max_count--); - check_modem_status(up); - if ((lsr & UART_LSR_THRE) && (iir & UART_IIR_THRI)) - transmit_chars(up); + spin_unlock(&up->port.lock); - spin_unlock_irqrestore(&up->port.lock, flags); - pm_runtime_mark_last_busy(&up->pdev->dev); - pm_runtime_put_autosuspend(&up->pdev->dev); + tty_flip_buffer_push(tty); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); up->port_activity = jiffies; - return IRQ_HANDLED; + + return ret; } static unsigned int serial_omap_tx_empty(struct uart_port *port) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); unsigned long flags = 0; unsigned int ret = 0; - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->port.line); spin_lock_irqsave(&up->port.lock, flags); ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; spin_unlock_irqrestore(&up->port.lock, flags); - pm_runtime_put(&up->pdev->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); return ret; } static unsigned int serial_omap_get_mctrl(struct uart_port *port) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); unsigned int status; unsigned int ret = 0; - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); status = check_modem_status(up); - pm_runtime_put(&up->pdev->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->port.line); @@ -487,7 +499,7 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port) static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); unsigned char mcr = 0; dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->port.line); @@ -502,20 +514,31 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) if (mctrl & TIOCM_LOOP) mcr |= UART_MCR_LOOP; - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); up->mcr = serial_in(up, UART_MCR); up->mcr |= mcr; serial_out(up, UART_MCR, up->mcr); - pm_runtime_put(&up->pdev->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); + + if (gpio_is_valid(up->DTR_gpio) && + !!(mctrl & TIOCM_DTR) != up->DTR_active) { + up->DTR_active = !up->DTR_active; + if (gpio_cansleep(up->DTR_gpio)) + schedule_work(&up->qos_work); + else + gpio_set_value(up->DTR_gpio, + up->DTR_active != up->DTR_inverted); + } } static void serial_omap_break_ctl(struct uart_port *port, int break_state) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); unsigned long flags = 0; dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->port.line); - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); spin_lock_irqsave(&up->port.lock, flags); if (break_state == -1) up->lcr |= UART_LCR_SBC; @@ -523,12 +546,13 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state) up->lcr &= ~UART_LCR_SBC; serial_out(up, UART_LCR, up->lcr); spin_unlock_irqrestore(&up->port.lock, flags); - pm_runtime_put(&up->pdev->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); } static int serial_omap_startup(struct uart_port *port) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); unsigned long flags = 0; int retval; @@ -542,7 +566,7 @@ static int serial_omap_startup(struct uart_port *port) dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line); - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); /* * Clear the FIFO buffers and disable them. * (they will be reenabled in set_termios()) @@ -573,20 +597,6 @@ static int serial_omap_startup(struct uart_port *port) spin_unlock_irqrestore(&up->port.lock, flags); up->msr_saved_flags = 0; - if (up->use_dma) { - free_page((unsigned long)up->port.state->xmit.buf); - up->port.state->xmit.buf = dma_alloc_coherent(NULL, - UART_XMIT_SIZE, - (dma_addr_t *)&(up->uart_dma.tx_buf_dma_phys), - 0); - init_timer(&(up->uart_dma.rx_timer)); - up->uart_dma.rx_timer.function = serial_omap_rxdma_poll; - up->uart_dma.rx_timer.data = up->port.line; - /* Currently the buffer size is 4KB. Can increase it */ - up->uart_dma.rx_buf = dma_alloc_coherent(NULL, - up->uart_dma.rx_buf_size, - (dma_addr_t *)&(up->uart_dma.rx_buf_dma_phys), 0); - } /* * Finally, enable interrupts. Note: Modem status interrupts * are set via set_termios(), which will be occurring imminently @@ -598,20 +608,20 @@ static int serial_omap_startup(struct uart_port *port) /* Enable module level wake up */ serial_out(up, UART_OMAP_WER, OMAP_UART_WER_MOD_WKUP); - pm_runtime_mark_last_busy(&up->pdev->dev); - pm_runtime_put_autosuspend(&up->pdev->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); up->port_activity = jiffies; return 0; } static void serial_omap_shutdown(struct uart_port *port) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); unsigned long flags = 0; dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->port.line); - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); /* * Disable interrupts from this port */ @@ -634,19 +644,9 @@ static void serial_omap_shutdown(struct uart_port *port) */ if (serial_in(up, UART_LSR) & UART_LSR_DR) (void) serial_in(up, UART_RX); - if (up->use_dma) { - dma_free_coherent(up->port.dev, - UART_XMIT_SIZE, up->port.state->xmit.buf, - up->uart_dma.tx_buf_dma_phys); - up->port.state->xmit.buf = NULL; - serial_omap_stop_rx(port); - dma_free_coherent(up->port.dev, - up->uart_dma.rx_buf_size, up->uart_dma.rx_buf, - up->uart_dma.rx_buf_dma_phys); - up->uart_dma.rx_buf = NULL; - } - pm_runtime_put(&up->pdev->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); free_irq(up->port.irq, up); } @@ -667,19 +667,19 @@ serial_omap_configure_xonxoff /* * IXON Flag: - * Enable XON/XOFF flow control on output. - * Transmit XON1, XOFF1 + * Flow control for OMAP.TX + * OMAP.RX should listen for XON/XOFF */ if (termios->c_iflag & IXON) - up->efr |= OMAP_UART_SW_TX; + up->efr |= OMAP_UART_SW_RX; /* * IXOFF Flag: - * Enable XON/XOFF flow control on input. - * Receiver compares XON1, XOFF1. + * Flow control for OMAP.RX + * OMAP.TX should send XON/XOFF */ if (termios->c_iflag & IXOFF) - up->efr |= OMAP_UART_SW_RX; + up->efr |= OMAP_UART_SW_TX; serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); @@ -715,13 +715,16 @@ static void serial_omap_uart_qos_work(struct work_struct *work) qos_work); pm_qos_update_request(&up->pm_qos_request, up->latency); + if (gpio_is_valid(up->DTR_gpio)) + gpio_set_value_cansleep(up->DTR_gpio, + up->DTR_active != up->DTR_inverted); } static void serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); unsigned char cval = 0; unsigned char efr = 0; unsigned long flags = 0; @@ -768,14 +771,12 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, up->fcr = UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_01 | UART_FCR_ENABLE_FIFO; - if (up->use_dma) - up->fcr |= UART_FCR_DMA_SELECT; /* * Ok, we're now changing the port state. Do it with * interrupts disabled. */ - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); spin_lock_irqsave(&up->port.lock, flags); /* @@ -845,14 +846,13 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, up->scr |= OMAP_UART_SCR_RX_TRIG_GRANU1_MASK; - if (up->use_dma) { - serial_out(up, UART_TI752_TLR, 0); - up->scr |= UART_FCR_TRIGGER_4; - } else { - /* Set receive FIFO threshold to 1 byte */ - up->fcr &= ~OMAP_UART_FCR_RX_FIFO_TRIG_MASK; - up->fcr |= (0x1 << OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT); - } + /* Set receive FIFO threshold to 16 characters and + * transmit FIFO threshold to 16 spaces + */ + up->fcr &= ~OMAP_UART_FCR_RX_FIFO_TRIG_MASK; + up->fcr &= ~OMAP_UART_FCR_TX_FIFO_TRIG_MASK; + up->fcr |= UART_FCR6_R_TRIGGER_16 | UART_FCR6_T_TRIGGER_24 | + UART_FCR_ENABLE_FIFO; serial_out(up, UART_FCR, up->fcr); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); @@ -924,20 +924,30 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, serial_omap_configure_xonxoff(up, termios); spin_unlock_irqrestore(&up->port.lock, flags); - pm_runtime_put(&up->pdev->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->port.line); } +static int serial_omap_set_wake(struct uart_port *port, unsigned int state) +{ + struct uart_omap_port *up = to_uart_omap_port(port); + + serial_omap_enable_wakeup(up, state); + + return 0; +} + static void serial_omap_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); unsigned char efr; dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->port.line); - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); efr = serial_in(up, UART_EFR); serial_out(up, UART_EFR, efr | UART_EFR_ECB); @@ -948,14 +958,15 @@ serial_omap_pm(struct uart_port *port, unsigned int state, serial_out(up, UART_EFR, efr); serial_out(up, UART_LCR, 0); - if (!device_may_wakeup(&up->pdev->dev)) { + if (!device_may_wakeup(up->dev)) { if (!state) - pm_runtime_forbid(&up->pdev->dev); + pm_runtime_forbid(up->dev); else - pm_runtime_allow(&up->pdev->dev); + pm_runtime_allow(up->dev); } - pm_runtime_put(&up->pdev->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); } static void serial_omap_release_port(struct uart_port *port) @@ -971,7 +982,7 @@ static int serial_omap_request_port(struct uart_port *port) static void serial_omap_config_port(struct uart_port *port, int flags) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); dev_dbg(up->port.dev, "serial_omap_config_port+%d\n", up->port.line); @@ -989,7 +1000,7 @@ serial_omap_verify_port(struct uart_port *port, struct serial_struct *ser) static const char * serial_omap_type(struct uart_port *port) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); dev_dbg(up->port.dev, "serial_omap_type+%d\n", up->port.line); return up->name; @@ -1032,26 +1043,33 @@ static inline void wait_for_xmitr(struct uart_omap_port *up) static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); wait_for_xmitr(up); serial_out(up, UART_TX, ch); - pm_runtime_put(&up->pdev->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); } static int serial_omap_poll_get_char(struct uart_port *port) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); unsigned int status; - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); status = serial_in(up, UART_LSR); - if (!(status & UART_LSR_DR)) - return NO_POLL_CHAR; + if (!(status & UART_LSR_DR)) { + status = NO_POLL_CHAR; + goto out; + } status = serial_in(up, UART_RX); - pm_runtime_put(&up->pdev->dev); + +out: + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); + return status; } @@ -1065,7 +1083,7 @@ static struct uart_driver serial_omap_reg; static void serial_omap_console_putchar(struct uart_port *port, int ch) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); wait_for_xmitr(up); serial_out(up, UART_TX, ch); @@ -1080,7 +1098,7 @@ serial_omap_console_write(struct console *co, const char *s, unsigned int ier; int locked = 1; - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); local_irq_save(flags); if (up->port.sysrq) @@ -1114,8 +1132,8 @@ serial_omap_console_write(struct console *co, const char *s, if (up->msr_saved_flags) check_modem_status(up); - pm_runtime_mark_last_busy(&up->pdev->dev); - pm_runtime_put_autosuspend(&up->pdev->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); if (locked) spin_unlock(&up->port.lock); local_irq_restore(flags); @@ -1179,6 +1197,7 @@ static struct uart_ops serial_omap_pops = { .shutdown = serial_omap_shutdown, .set_termios = serial_omap_set_termios, .pm = serial_omap_pm, + .set_wake = serial_omap_set_wake, .type = serial_omap_type, .release_port = serial_omap_release_port, .request_port = serial_omap_request_port, @@ -1221,150 +1240,7 @@ static int serial_omap_resume(struct device *dev) } #endif -static void serial_omap_rxdma_poll(unsigned long uart_no) -{ - struct uart_omap_port *up = ui[uart_no]; - unsigned int curr_dma_pos, curr_transmitted_size; - int ret = 0; - - curr_dma_pos = omap_get_dma_dst_pos(up->uart_dma.rx_dma_channel); - if ((curr_dma_pos == up->uart_dma.prev_rx_dma_pos) || - (curr_dma_pos == 0)) { - if (jiffies_to_msecs(jiffies - up->port_activity) < - up->uart_dma.rx_timeout) { - mod_timer(&up->uart_dma.rx_timer, jiffies + - usecs_to_jiffies(up->uart_dma.rx_poll_rate)); - } else { - serial_omap_stop_rxdma(up); - up->ier |= (UART_IER_RDI | UART_IER_RLSI); - serial_out(up, UART_IER, up->ier); - } - return; - } - - curr_transmitted_size = curr_dma_pos - - up->uart_dma.prev_rx_dma_pos; - up->port.icount.rx += curr_transmitted_size; - tty_insert_flip_string(up->port.state->port.tty, - up->uart_dma.rx_buf + - (up->uart_dma.prev_rx_dma_pos - - up->uart_dma.rx_buf_dma_phys), - curr_transmitted_size); - tty_flip_buffer_push(up->port.state->port.tty); - up->uart_dma.prev_rx_dma_pos = curr_dma_pos; - if (up->uart_dma.rx_buf_size + - up->uart_dma.rx_buf_dma_phys == curr_dma_pos) { - ret = serial_omap_start_rxdma(up); - if (ret < 0) { - serial_omap_stop_rxdma(up); - up->ier |= (UART_IER_RDI | UART_IER_RLSI); - serial_out(up, UART_IER, up->ier); - } - } else { - mod_timer(&up->uart_dma.rx_timer, jiffies + - usecs_to_jiffies(up->uart_dma.rx_poll_rate)); - } - up->port_activity = jiffies; -} - -static void uart_rx_dma_callback(int lch, u16 ch_status, void *data) -{ - return; -} - -static int serial_omap_start_rxdma(struct uart_omap_port *up) -{ - int ret = 0; - - if (up->uart_dma.rx_dma_channel == -1) { - pm_runtime_get_sync(&up->pdev->dev); - ret = omap_request_dma(up->uart_dma.uart_dma_rx, - "UART Rx DMA", - (void *)uart_rx_dma_callback, up, - &(up->uart_dma.rx_dma_channel)); - if (ret < 0) - return ret; - - omap_set_dma_src_params(up->uart_dma.rx_dma_channel, 0, - OMAP_DMA_AMODE_CONSTANT, - up->uart_dma.uart_base, 0, 0); - omap_set_dma_dest_params(up->uart_dma.rx_dma_channel, 0, - OMAP_DMA_AMODE_POST_INC, - up->uart_dma.rx_buf_dma_phys, 0, 0); - omap_set_dma_transfer_params(up->uart_dma.rx_dma_channel, - OMAP_DMA_DATA_TYPE_S8, - up->uart_dma.rx_buf_size, 1, - OMAP_DMA_SYNC_ELEMENT, - up->uart_dma.uart_dma_rx, 0); - } - up->uart_dma.prev_rx_dma_pos = up->uart_dma.rx_buf_dma_phys; - /* FIXME: Cache maintenance needed here? */ - omap_start_dma(up->uart_dma.rx_dma_channel); - mod_timer(&up->uart_dma.rx_timer, jiffies + - usecs_to_jiffies(up->uart_dma.rx_poll_rate)); - up->uart_dma.rx_dma_used = true; - return ret; -} - -static void serial_omap_continue_tx(struct uart_omap_port *up) -{ - struct circ_buf *xmit = &up->port.state->xmit; - unsigned int start = up->uart_dma.tx_buf_dma_phys - + (xmit->tail & (UART_XMIT_SIZE - 1)); - - if (uart_circ_empty(xmit)) - return; - - up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit); - /* - * It is a circular buffer. See if the buffer has wounded back. - * If yes it will have to be transferred in two separate dma - * transfers - */ - if (start + up->uart_dma.tx_buf_size >= - up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) - up->uart_dma.tx_buf_size = - (up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) - start; - omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0, - OMAP_DMA_AMODE_CONSTANT, - up->uart_dma.uart_base, 0, 0); - omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0, - OMAP_DMA_AMODE_POST_INC, start, 0, 0); - omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel, - OMAP_DMA_DATA_TYPE_S8, - up->uart_dma.tx_buf_size, 1, - OMAP_DMA_SYNC_ELEMENT, - up->uart_dma.uart_dma_tx, 0); - /* FIXME: Cache maintenance needed here? */ - omap_start_dma(up->uart_dma.tx_dma_channel); -} - -static void uart_tx_dma_callback(int lch, u16 ch_status, void *data) -{ - struct uart_omap_port *up = (struct uart_omap_port *)data; - struct circ_buf *xmit = &up->port.state->xmit; - - xmit->tail = (xmit->tail + up->uart_dma.tx_buf_size) & \ - (UART_XMIT_SIZE - 1); - up->port.icount.tx += up->uart_dma.tx_buf_size; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); - - if (uart_circ_empty(xmit)) { - spin_lock(&(up->uart_dma.tx_lock)); - serial_omap_stop_tx(&up->port); - up->uart_dma.tx_dma_used = false; - spin_unlock(&(up->uart_dma.tx_lock)); - } else { - omap_stop_dma(up->uart_dma.tx_dma_channel); - serial_omap_continue_tx(up); - } - up->port_activity = jiffies; - return; -} - -static void omap_serial_fill_features_erratas(struct uart_omap_port *up) +static void __devinit omap_serial_fill_features_erratas(struct uart_omap_port *up) { u32 mvr, scheme; u16 revision, major, minor; @@ -1389,7 +1265,7 @@ static void omap_serial_fill_features_erratas(struct uart_omap_port *up) minor = (mvr & OMAP_UART_MVR_MIN_MASK); break; default: - dev_warn(&up->pdev->dev, + dev_warn(up->dev, "Unknown %s revision, defaulting to highest\n", up->name); /* highest possible revision */ @@ -1417,7 +1293,7 @@ static void omap_serial_fill_features_erratas(struct uart_omap_port *up) } } -static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev) +static __devinit struct omap_uart_port_info *of_get_uart_port_info(struct device *dev) { struct omap_uart_port_info *omap_up_info; @@ -1430,12 +1306,12 @@ static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev) return omap_up_info; } -static int serial_omap_probe(struct platform_device *pdev) +static int __devinit serial_omap_probe(struct platform_device *pdev) { struct uart_omap_port *up; - struct resource *mem, *irq, *dma_tx, *dma_rx; + struct resource *mem, *irq; struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data; - int ret = -ENOSPC; + int ret; if (pdev->dev.of_node) omap_up_info = of_get_uart_port_info(&pdev->dev); @@ -1458,19 +1334,30 @@ static int serial_omap_probe(struct platform_device *pdev) return -EBUSY; } - dma_rx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); - if (!dma_rx) - return -ENXIO; - - dma_tx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); - if (!dma_tx) - return -ENXIO; + if (gpio_is_valid(omap_up_info->DTR_gpio) && + omap_up_info->DTR_present) { + ret = gpio_request(omap_up_info->DTR_gpio, "omap-serial"); + if (ret < 0) + return ret; + ret = gpio_direction_output(omap_up_info->DTR_gpio, + omap_up_info->DTR_inverted); + if (ret < 0) + return ret; + } up = devm_kzalloc(&pdev->dev, sizeof(*up), GFP_KERNEL); if (!up) return -ENOMEM; - up->pdev = pdev; + if (gpio_is_valid(omap_up_info->DTR_gpio) && + omap_up_info->DTR_present) { + up->DTR_gpio = omap_up_info->DTR_gpio; + up->DTR_inverted = omap_up_info->DTR_inverted; + } else + up->DTR_gpio = -EINVAL; + up->DTR_active = 0; + + up->dev = &pdev->dev; up->port.dev = &pdev->dev; up->port.type = PORT_OMAP; up->port.iotype = UPIO_MEM; @@ -1492,6 +1379,13 @@ static int serial_omap_probe(struct platform_device *pdev) goto err_port_line; } + up->pins = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(up->pins)) { + dev_warn(&pdev->dev, "did not get pins for uart%i error: %li\n", + up->port.line, PTR_ERR(up->pins)); + up->pins = NULL; + } + sprintf(up->name, "OMAP UART%d", up->port.line); up->port.mapbase = mem->start; up->port.membase = devm_ioremap(&pdev->dev, mem->start, @@ -1509,20 +1403,6 @@ static int serial_omap_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "No clock speed specified: using default:" "%d\n", DEFAULT_CLK_SPEED); } - up->uart_dma.uart_base = mem->start; - - if (omap_up_info->dma_enabled) { - up->uart_dma.uart_dma_tx = dma_tx->start; - up->uart_dma.uart_dma_rx = dma_rx->start; - up->use_dma = 1; - up->uart_dma.rx_buf_size = omap_up_info->dma_rx_buf_size; - up->uart_dma.rx_timeout = omap_up_info->dma_rx_timeout; - up->uart_dma.rx_poll_rate = omap_up_info->dma_rx_poll_rate; - spin_lock_init(&(up->uart_dma.tx_lock)); - spin_lock_init(&(up->uart_dma.rx_lock)); - up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE; - up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE; - } up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; up->calc_latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; @@ -1531,12 +1411,13 @@ static int serial_omap_probe(struct platform_device *pdev) serial_omap_uart_wq = create_singlethread_workqueue(up->name); INIT_WORK(&up->qos_work, serial_omap_uart_qos_work); + platform_set_drvdata(pdev, up); + pm_runtime_enable(&pdev->dev); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, omap_up_info->autosuspend_timeout); pm_runtime_irq_safe(&pdev->dev); - pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); omap_serial_fill_features_erratas(up); @@ -1548,8 +1429,8 @@ static int serial_omap_probe(struct platform_device *pdev) if (ret != 0) goto err_add_port; - pm_runtime_put(&pdev->dev); - platform_set_drvdata(pdev, up); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); return 0; err_add_port: @@ -1562,17 +1443,15 @@ err_port_line: return ret; } -static int serial_omap_remove(struct platform_device *dev) +static int __devexit serial_omap_remove(struct platform_device *dev) { struct uart_omap_port *up = platform_get_drvdata(dev); - if (up) { - pm_runtime_disable(&up->pdev->dev); - uart_remove_one_port(&serial_omap_reg, &up->port); - pm_qos_remove_request(&up->pm_qos_request); - } + pm_runtime_put_sync(up->dev); + pm_runtime_disable(up->dev); + uart_remove_one_port(&serial_omap_reg, &up->port); + pm_qos_remove_request(&up->pm_qos_request); - platform_set_drvdata(dev, NULL); return 0; } @@ -1602,7 +1481,7 @@ static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1) timeout--; if (!timeout) { /* Should *never* happen. we warn and carry on */ - dev_crit(&up->pdev->dev, "Errata i202: timedout %x\n", + dev_crit(up->dev, "Errata i202: timedout %x\n", serial_in(up, UART_LSR)); break; } @@ -1648,29 +1527,23 @@ static int serial_omap_runtime_suspend(struct device *dev) if (!up) return -EINVAL; - if (!pdata || !pdata->enable_wakeup) + if (!pdata) return 0; - if (pdata->get_context_loss_count) - up->context_loss_cnt = pdata->get_context_loss_count(dev); + up->context_loss_cnt = serial_omap_get_context_loss_count(up); if (device_may_wakeup(dev)) { if (!up->wakeups_enabled) { - pdata->enable_wakeup(up->pdev, true); + serial_omap_enable_wakeup(up, true); up->wakeups_enabled = true; } } else { if (up->wakeups_enabled) { - pdata->enable_wakeup(up->pdev, false); + serial_omap_enable_wakeup(up, false); up->wakeups_enabled = false; } } - /* Errata i291 */ - if (up->use_dma && pdata->set_forceidle && - (up->errata & UART_ERRATA_i291_DMA_FORCEIDLE)) - pdata->set_forceidle(up->pdev); - up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; schedule_work(&up->qos_work); @@ -1683,17 +1556,10 @@ static int serial_omap_runtime_resume(struct device *dev) struct omap_uart_port_info *pdata = dev->platform_data; if (up && pdata) { - if (pdata->get_context_loss_count) { - u32 loss_cnt = pdata->get_context_loss_count(dev); + u32 loss_cnt = serial_omap_get_context_loss_count(up); if (up->context_loss_cnt != loss_cnt) serial_omap_restore_context(up); - } - - /* Errata i291 */ - if (up->use_dma && pdata->set_noidle && - (up->errata & UART_ERRATA_i291_DMA_FORCEIDLE)) - pdata->set_noidle(up->pdev); up->latency = up->calc_latency; schedule_work(&up->qos_work); @@ -1721,7 +1587,7 @@ MODULE_DEVICE_TABLE(of, omap_serial_of_match); static struct platform_driver serial_omap_driver = { .probe = serial_omap_probe, - .remove = serial_omap_remove, + .remove = __devexit_p(serial_omap_remove), .driver = { .name = DRIVER_NAME, .pm = &serial_omap_dev_pm_ops, diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 558ce8509a9a..4cd6c2381528 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -979,6 +979,10 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv) priv->tx_dma_use = 1; priv->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC); + if (!priv->sg_tx_p) { + dev_err(priv->port.dev, "%s:kzalloc Failed\n", __func__); + return 0; + } sg_init_table(priv->sg_tx_p, num); /* Initialize SG table */ sg = priv->sg_tx_p; diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index 5847a4b855f7..9033fc6e0e4e 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -670,9 +670,19 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count) { struct uart_pxa_port *up = serial_pxa_ports[co->index]; unsigned int ier; + unsigned long flags; + int locked = 1; clk_prepare_enable(up->clk); + local_irq_save(flags); + if (up->port.sysrq) + locked = 0; + else if (oops_in_progress) + locked = spin_trylock(&up->port.lock); + else + spin_lock(&up->port.lock); + /* * First save the IER then disable the interrupts */ @@ -688,6 +698,10 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count) wait_for_xmitr(up); serial_out(up, UART_IER, ier); + if (locked) + spin_unlock(&up->port.lock); + local_irq_restore(flags); + clk_disable_unprepare(up->clk); } diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 02d07bfcfa8a..bdaa06f3ab69 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -82,7 +82,7 @@ static inline const char *s3c24xx_serial_portname(struct uart_port *port) static int s3c24xx_serial_txempty_nofifo(struct uart_port *port) { - return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE); + return rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE; } /* @@ -268,7 +268,7 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id) dbg("break!\n"); port->icount.brk++; if (uart_handle_break(port)) - goto ignore_char; + goto ignore_char; } if (uerstat & S3C2410_UERSTAT_FRAME) @@ -459,7 +459,7 @@ static int s3c24xx_serial_startup(struct uart_port *port) s3c24xx_serial_portname(port), ourport); if (ret != 0) { - printk(KERN_ERR "cannot get irq %d\n", ourport->rx_irq); + dev_err(port->dev, "cannot get irq %d\n", ourport->rx_irq); return ret; } @@ -473,7 +473,7 @@ static int s3c24xx_serial_startup(struct uart_port *port) s3c24xx_serial_portname(port), ourport); if (ret) { - printk(KERN_ERR "cannot get irq %d\n", ourport->tx_irq); + dev_err(port->dev, "cannot get irq %d\n", ourport->tx_irq); goto err; } @@ -502,7 +502,7 @@ static int s3c64xx_serial_startup(struct uart_port *port) ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED, s3c24xx_serial_portname(port), ourport); if (ret) { - printk(KERN_ERR "cannot get irq %d\n", port->irq); + dev_err(port->dev, "cannot get irq %d\n", port->irq); return ret; } @@ -529,7 +529,7 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, switch (level) { case 3: - if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL) + if (!IS_ERR(ourport->baudclk)) clk_disable(ourport->baudclk); clk_disable(ourport->clk); @@ -538,12 +538,12 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, case 0: clk_enable(ourport->clk); - if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL) + if (!IS_ERR(ourport->baudclk)) clk_enable(ourport->baudclk); break; default: - printk(KERN_ERR "s3c24xx_serial: unknown pm %d\n", level); + dev_err(port->dev, "s3c24xx_serial: unknown pm %d\n", level); } } @@ -604,7 +604,6 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport, char clkname[MAX_CLK_NAME_LENGTH]; int calc_deviation, deviation = (1 << 30) - 1; - *best_clk = NULL; clk_sel = (ourport->cfg->clk_sel) ? ourport->cfg->clk_sel : ourport->info->def_clk_sel; for (cnt = 0; cnt < info->num_clks; cnt++) { @@ -613,7 +612,7 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport, sprintf(clkname, "clk_uart_baud%d", cnt); clk = clk_get(ourport->port.dev, clkname); - if (IS_ERR_OR_NULL(clk)) + if (IS_ERR(clk)) continue; rate = clk_get_rate(clk); @@ -684,7 +683,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, { struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port); struct s3c24xx_uart_port *ourport = to_ourport(port); - struct clk *clk = NULL; + struct clk *clk = ERR_PTR(-EINVAL); unsigned long flags; unsigned int baud, quot, clk_sel = 0; unsigned int ulcon; @@ -705,7 +704,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, quot = s3c24xx_serial_getclk(ourport, baud, &clk, &clk_sel); if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) quot = port->custom_divisor; - if (!clk) + if (IS_ERR(clk)) return; /* check to see if we need to change clock source */ @@ -713,9 +712,9 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, if (ourport->baudclk != clk) { s3c24xx_serial_setsource(port, clk_sel); - if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) { + if (!IS_ERR(ourport->baudclk)) { clk_disable(ourport->baudclk); - ourport->baudclk = NULL; + ourport->baudclk = ERR_PTR(-EINVAL); } clk_enable(clk); @@ -1036,10 +1035,10 @@ static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb, if (tty == NULL) goto exit; - termios = tty->termios; + termios = &tty->termios; if (termios == NULL) { - printk(KERN_WARNING "%s: no termios?\n", __func__); + dev_warn(uport->dev, "%s: no termios?\n", __func__); goto exit; } @@ -1114,7 +1113,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, res = platform_get_resource(platdev, IORESOURCE_MEM, 0); if (res == NULL) { - printk(KERN_ERR "failed to find memory resource for uart\n"); + dev_err(port->dev, "failed to find memory resource for uart\n"); return -EINVAL; } @@ -1130,7 +1129,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, ourport->rx_irq = ret; ourport->tx_irq = ret + 1; } - + ret = platform_get_irq(platdev, 1); if (ret > 0) ourport->tx_irq = ret; @@ -1160,7 +1159,11 @@ static ssize_t s3c24xx_serial_show_clksrc(struct device *dev, struct uart_port *port = s3c24xx_dev_to_port(dev); struct s3c24xx_uart_port *ourport = to_ourport(port); - return snprintf(buf, PAGE_SIZE, "* %s\n", ourport->baudclk->name); + if (IS_ERR(ourport->baudclk)) + return -EINVAL; + + return snprintf(buf, PAGE_SIZE, "* %s\n", + ourport->baudclk->name ?: "(null)"); } static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL); @@ -1200,6 +1203,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) return -ENODEV; } + ourport->baudclk = ERR_PTR(-EINVAL); ourport->info = ourport->drv_data->info; ourport->cfg = (pdev->dev.platform_data) ? (struct s3c2410_uartcfg *)pdev->dev.platform_data : @@ -1387,7 +1391,7 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud, sprintf(clk_name, "clk_uart_baud%d", clk_sel); clk = clk_get(port->dev, clk_name); - if (!IS_ERR(clk) && clk != NULL) + if (!IS_ERR(clk)) rate = clk_get_rate(clk); else rate = 1; @@ -1679,7 +1683,7 @@ static int __init s3c24xx_serial_modinit(void) ret = uart_register_driver(&s3c24xx_uart_drv); if (ret < 0) { - printk(KERN_ERR "failed to register UART driver\n"); + pr_err("Failed to register Samsung UART driver\n"); return -1; } diff --git a/drivers/tty/serial/sc26xx.c b/drivers/tty/serial/sc26xx.c index e0b4b0a30a5a..9d664242b312 100644 --- a/drivers/tty/serial/sc26xx.c +++ b/drivers/tty/serial/sc26xx.c @@ -20,6 +20,10 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/irq.h> +#include <linux/io.h> + +#warning "Please try migrate to use new driver SCCNXP and report the status" \ + "in the linux-serial mailing list." #if defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c new file mode 100644 index 000000000000..05d767cf82a7 --- /dev/null +++ b/drivers/tty/serial/sccnxp.c @@ -0,0 +1,985 @@ +/* + * NXP (Philips) SCC+++(SCN+++) serial driver + * + * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru> + * + * Based on sc26xx.c, by Thomas Bogendörfer (tsbogend@alpha.franken.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#if defined(CONFIG_SERIAL_SCCNXP_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include <linux/module.h> +#include <linux/device.h> +#include <linux/console.h> +#include <linux/serial_core.h> +#include <linux/serial.h> +#include <linux/io.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/platform_device.h> +#include <linux/platform_data/sccnxp.h> + +#define SCCNXP_NAME "uart-sccnxp" +#define SCCNXP_MAJOR 204 +#define SCCNXP_MINOR 205 + +#define SCCNXP_MR_REG (0x00) +# define MR0_BAUD_NORMAL (0 << 0) +# define MR0_BAUD_EXT1 (1 << 0) +# define MR0_BAUD_EXT2 (5 << 0) +# define MR0_FIFO (1 << 3) +# define MR0_TXLVL (1 << 4) +# define MR1_BITS_5 (0 << 0) +# define MR1_BITS_6 (1 << 0) +# define MR1_BITS_7 (2 << 0) +# define MR1_BITS_8 (3 << 0) +# define MR1_PAR_EVN (0 << 2) +# define MR1_PAR_ODD (1 << 2) +# define MR1_PAR_NO (4 << 2) +# define MR2_STOP1 (7 << 0) +# define MR2_STOP2 (0xf << 0) +#define SCCNXP_SR_REG (0x01) +#define SCCNXP_CSR_REG SCCNXP_SR_REG +# define SR_RXRDY (1 << 0) +# define SR_FULL (1 << 1) +# define SR_TXRDY (1 << 2) +# define SR_TXEMT (1 << 3) +# define SR_OVR (1 << 4) +# define SR_PE (1 << 5) +# define SR_FE (1 << 6) +# define SR_BRK (1 << 7) +#define SCCNXP_CR_REG (0x02) +# define CR_RX_ENABLE (1 << 0) +# define CR_RX_DISABLE (1 << 1) +# define CR_TX_ENABLE (1 << 2) +# define CR_TX_DISABLE (1 << 3) +# define CR_CMD_MRPTR1 (0x01 << 4) +# define CR_CMD_RX_RESET (0x02 << 4) +# define CR_CMD_TX_RESET (0x03 << 4) +# define CR_CMD_STATUS_RESET (0x04 << 4) +# define CR_CMD_BREAK_RESET (0x05 << 4) +# define CR_CMD_START_BREAK (0x06 << 4) +# define CR_CMD_STOP_BREAK (0x07 << 4) +# define CR_CMD_MRPTR0 (0x0b << 4) +#define SCCNXP_RHR_REG (0x03) +#define SCCNXP_THR_REG SCCNXP_RHR_REG +#define SCCNXP_IPCR_REG (0x04) +#define SCCNXP_ACR_REG SCCNXP_IPCR_REG +# define ACR_BAUD0 (0 << 7) +# define ACR_BAUD1 (1 << 7) +# define ACR_TIMER_MODE (6 << 4) +#define SCCNXP_ISR_REG (0x05) +#define SCCNXP_IMR_REG SCCNXP_ISR_REG +# define IMR_TXRDY (1 << 0) +# define IMR_RXRDY (1 << 1) +# define ISR_TXRDY(x) (1 << ((x * 4) + 0)) +# define ISR_RXRDY(x) (1 << ((x * 4) + 1)) +#define SCCNXP_IPR_REG (0x0d) +#define SCCNXP_OPCR_REG SCCNXP_IPR_REG +#define SCCNXP_SOP_REG (0x0e) +#define SCCNXP_ROP_REG (0x0f) + +/* Route helpers */ +#define MCTRL_MASK(sig) (0xf << (sig)) +#define MCTRL_IBIT(cfg, sig) ((((cfg) >> (sig)) & 0xf) - LINE_IP0) +#define MCTRL_OBIT(cfg, sig) ((((cfg) >> (sig)) & 0xf) - LINE_OP0) + +/* Supported chip types */ +enum { + SCCNXP_TYPE_SC2681 = 2681, + SCCNXP_TYPE_SC2691 = 2691, + SCCNXP_TYPE_SC2692 = 2692, + SCCNXP_TYPE_SC2891 = 2891, + SCCNXP_TYPE_SC2892 = 2892, + SCCNXP_TYPE_SC28202 = 28202, + SCCNXP_TYPE_SC68681 = 68681, + SCCNXP_TYPE_SC68692 = 68692, +}; + +struct sccnxp_port { + struct uart_driver uart; + struct uart_port port[SCCNXP_MAX_UARTS]; + + const char *name; + int irq; + + u8 imr; + u8 addr_mask; + int freq_std; + + int flags; +#define SCCNXP_HAVE_IO 0x00000001 +#define SCCNXP_HAVE_MR0 0x00000002 + +#ifdef CONFIG_SERIAL_SCCNXP_CONSOLE + struct console console; +#endif + + struct mutex sccnxp_mutex; + + struct sccnxp_pdata pdata; +}; + +static inline u8 sccnxp_raw_read(void __iomem *base, u8 reg, u8 shift) +{ + return readb(base + (reg << shift)); +} + +static inline void sccnxp_raw_write(void __iomem *base, u8 reg, u8 shift, u8 v) +{ + writeb(v, base + (reg << shift)); +} + +static inline u8 sccnxp_read(struct uart_port *port, u8 reg) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + return sccnxp_raw_read(port->membase, reg & s->addr_mask, + port->regshift); +} + +static inline void sccnxp_write(struct uart_port *port, u8 reg, u8 v) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + sccnxp_raw_write(port->membase, reg & s->addr_mask, port->regshift, v); +} + +static inline u8 sccnxp_port_read(struct uart_port *port, u8 reg) +{ + return sccnxp_read(port, (port->line << 3) + reg); +} + +static inline void sccnxp_port_write(struct uart_port *port, u8 reg, u8 v) +{ + sccnxp_write(port, (port->line << 3) + reg, v); +} + +static int sccnxp_update_best_err(int a, int b, int *besterr) +{ + int err = abs(a - b); + + if ((*besterr < 0) || (*besterr > err)) { + *besterr = err; + return 0; + } + + return 1; +} + +struct baud_table { + u8 csr; + u8 acr; + u8 mr0; + int baud; +}; + +const struct baud_table baud_std[] = { + { 0, ACR_BAUD0, MR0_BAUD_NORMAL, 50, }, + { 0, ACR_BAUD1, MR0_BAUD_NORMAL, 75, }, + { 1, ACR_BAUD0, MR0_BAUD_NORMAL, 110, }, + { 2, ACR_BAUD0, MR0_BAUD_NORMAL, 134, }, + { 3, ACR_BAUD1, MR0_BAUD_NORMAL, 150, }, + { 3, ACR_BAUD0, MR0_BAUD_NORMAL, 200, }, + { 4, ACR_BAUD0, MR0_BAUD_NORMAL, 300, }, + { 0, ACR_BAUD1, MR0_BAUD_EXT1, 450, }, + { 1, ACR_BAUD0, MR0_BAUD_EXT2, 880, }, + { 3, ACR_BAUD1, MR0_BAUD_EXT1, 900, }, + { 5, ACR_BAUD0, MR0_BAUD_NORMAL, 600, }, + { 7, ACR_BAUD0, MR0_BAUD_NORMAL, 1050, }, + { 2, ACR_BAUD0, MR0_BAUD_EXT2, 1076, }, + { 6, ACR_BAUD0, MR0_BAUD_NORMAL, 1200, }, + { 10, ACR_BAUD1, MR0_BAUD_NORMAL, 1800, }, + { 7, ACR_BAUD1, MR0_BAUD_NORMAL, 2000, }, + { 8, ACR_BAUD0, MR0_BAUD_NORMAL, 2400, }, + { 5, ACR_BAUD1, MR0_BAUD_EXT1, 3600, }, + { 9, ACR_BAUD0, MR0_BAUD_NORMAL, 4800, }, + { 10, ACR_BAUD0, MR0_BAUD_NORMAL, 7200, }, + { 11, ACR_BAUD0, MR0_BAUD_NORMAL, 9600, }, + { 8, ACR_BAUD0, MR0_BAUD_EXT1, 14400, }, + { 12, ACR_BAUD1, MR0_BAUD_NORMAL, 19200, }, + { 9, ACR_BAUD0, MR0_BAUD_EXT1, 28800, }, + { 12, ACR_BAUD0, MR0_BAUD_NORMAL, 38400, }, + { 11, ACR_BAUD0, MR0_BAUD_EXT1, 57600, }, + { 12, ACR_BAUD1, MR0_BAUD_EXT1, 115200, }, + { 12, ACR_BAUD0, MR0_BAUD_EXT1, 230400, }, + { 0, 0, 0, 0 } +}; + +static void sccnxp_set_baud(struct uart_port *port, int baud) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + int div_std, tmp_baud, bestbaud = baud, besterr = -1; + u8 i, acr = 0, csr = 0, mr0 = 0; + + /* Find best baud from table */ + for (i = 0; baud_std[i].baud && besterr; i++) { + if (baud_std[i].mr0 && !(s->flags & SCCNXP_HAVE_MR0)) + continue; + div_std = DIV_ROUND_CLOSEST(s->freq_std, baud_std[i].baud); + tmp_baud = DIV_ROUND_CLOSEST(port->uartclk, div_std); + if (!sccnxp_update_best_err(baud, tmp_baud, &besterr)) { + acr = baud_std[i].acr; + csr = baud_std[i].csr; + mr0 = baud_std[i].mr0; + bestbaud = tmp_baud; + } + } + + if (s->flags & SCCNXP_HAVE_MR0) { + /* Enable FIFO, set half level for TX */ + mr0 |= MR0_FIFO | MR0_TXLVL; + /* Update MR0 */ + sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_MRPTR0); + sccnxp_port_write(port, SCCNXP_MR_REG, mr0); + } + + sccnxp_port_write(port, SCCNXP_ACR_REG, acr | ACR_TIMER_MODE); + sccnxp_port_write(port, SCCNXP_CSR_REG, (csr << 4) | csr); + + dev_dbg(port->dev, "Baudrate desired: %i, calculated: %i\n", + baud, bestbaud); +} + +static void sccnxp_enable_irq(struct uart_port *port, int mask) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + s->imr |= mask << (port->line * 4); + sccnxp_write(port, SCCNXP_IMR_REG, s->imr); +} + +static void sccnxp_disable_irq(struct uart_port *port, int mask) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + s->imr &= ~(mask << (port->line * 4)); + sccnxp_write(port, SCCNXP_IMR_REG, s->imr); +} + +static void sccnxp_set_bit(struct uart_port *port, int sig, int state) +{ + u8 bitmask; + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(sig)) { + bitmask = 1 << MCTRL_OBIT(s->pdata.mctrl_cfg[port->line], sig); + if (state) + sccnxp_write(port, SCCNXP_SOP_REG, bitmask); + else + sccnxp_write(port, SCCNXP_ROP_REG, bitmask); + } +} + +static void sccnxp_handle_rx(struct uart_port *port) +{ + u8 sr; + unsigned int ch, flag; + struct tty_struct *tty = tty_port_tty_get(&port->state->port); + + if (!tty) + return; + + for (;;) { + sr = sccnxp_port_read(port, SCCNXP_SR_REG); + if (!(sr & SR_RXRDY)) + break; + sr &= SR_PE | SR_FE | SR_OVR | SR_BRK; + + ch = sccnxp_port_read(port, SCCNXP_RHR_REG); + + port->icount.rx++; + flag = TTY_NORMAL; + + if (unlikely(sr)) { + if (sr & SR_BRK) { + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } else if (sr & SR_PE) + port->icount.parity++; + else if (sr & SR_FE) + port->icount.frame++; + else if (sr & SR_OVR) + port->icount.overrun++; + + sr &= port->read_status_mask; + if (sr & SR_BRK) + flag = TTY_BREAK; + else if (sr & SR_PE) + flag = TTY_PARITY; + else if (sr & SR_FE) + flag = TTY_FRAME; + else if (sr & SR_OVR) + flag = TTY_OVERRUN; + } + + if (uart_handle_sysrq_char(port, ch)) + continue; + + if (sr & port->ignore_status_mask) + continue; + + uart_insert_char(port, sr, SR_OVR, ch, flag); + } + + tty_flip_buffer_push(tty); + + tty_kref_put(tty); +} + +static void sccnxp_handle_tx(struct uart_port *port) +{ + u8 sr; + struct circ_buf *xmit = &port->state->xmit; + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + if (unlikely(port->x_char)) { + sccnxp_port_write(port, SCCNXP_THR_REG, port->x_char); + port->icount.tx++; + port->x_char = 0; + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + /* Disable TX if FIFO is empty */ + if (sccnxp_port_read(port, SCCNXP_SR_REG) & SR_TXEMT) { + sccnxp_disable_irq(port, IMR_TXRDY); + + /* Set direction to input */ + if (s->flags & SCCNXP_HAVE_IO) + sccnxp_set_bit(port, DIR_OP, 0); + } + return; + } + + while (!uart_circ_empty(xmit)) { + sr = sccnxp_port_read(port, SCCNXP_SR_REG); + if (!(sr & SR_TXRDY)) + break; + + sccnxp_port_write(port, SCCNXP_THR_REG, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); +} + +static irqreturn_t sccnxp_ist(int irq, void *dev_id) +{ + int i; + u8 isr; + struct sccnxp_port *s = (struct sccnxp_port *)dev_id; + + mutex_lock(&s->sccnxp_mutex); + + for (;;) { + isr = sccnxp_read(&s->port[0], SCCNXP_ISR_REG); + isr &= s->imr; + if (!isr) + break; + + dev_dbg(s->port[0].dev, "IRQ status: 0x%02x\n", isr); + + for (i = 0; i < s->uart.nr; i++) { + if (isr & ISR_RXRDY(i)) + sccnxp_handle_rx(&s->port[i]); + if (isr & ISR_TXRDY(i)) + sccnxp_handle_tx(&s->port[i]); + } + } + + mutex_unlock(&s->sccnxp_mutex); + + return IRQ_HANDLED; +} + +static void sccnxp_start_tx(struct uart_port *port) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + mutex_lock(&s->sccnxp_mutex); + + /* Set direction to output */ + if (s->flags & SCCNXP_HAVE_IO) + sccnxp_set_bit(port, DIR_OP, 1); + + sccnxp_enable_irq(port, IMR_TXRDY); + + mutex_unlock(&s->sccnxp_mutex); +} + +static void sccnxp_stop_tx(struct uart_port *port) +{ + /* Do nothing */ +} + +static void sccnxp_stop_rx(struct uart_port *port) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + mutex_lock(&s->sccnxp_mutex); + sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_DISABLE); + mutex_unlock(&s->sccnxp_mutex); +} + +static unsigned int sccnxp_tx_empty(struct uart_port *port) +{ + u8 val; + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + mutex_lock(&s->sccnxp_mutex); + val = sccnxp_port_read(port, SCCNXP_SR_REG); + mutex_unlock(&s->sccnxp_mutex); + + return (val & SR_TXEMT) ? TIOCSER_TEMT : 0; +} + +static void sccnxp_enable_ms(struct uart_port *port) +{ + /* Do nothing */ +} + +static void sccnxp_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + if (!(s->flags & SCCNXP_HAVE_IO)) + return; + + mutex_lock(&s->sccnxp_mutex); + + sccnxp_set_bit(port, DTR_OP, mctrl & TIOCM_DTR); + sccnxp_set_bit(port, RTS_OP, mctrl & TIOCM_RTS); + + mutex_unlock(&s->sccnxp_mutex); +} + +static unsigned int sccnxp_get_mctrl(struct uart_port *port) +{ + u8 bitmask, ipr; + struct sccnxp_port *s = dev_get_drvdata(port->dev); + unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR; + + if (!(s->flags & SCCNXP_HAVE_IO)) + return mctrl; + + mutex_lock(&s->sccnxp_mutex); + + ipr = ~sccnxp_read(port, SCCNXP_IPCR_REG); + + if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(DSR_IP)) { + bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line], + DSR_IP); + mctrl &= ~TIOCM_DSR; + mctrl |= (ipr & bitmask) ? TIOCM_DSR : 0; + } + if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(CTS_IP)) { + bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line], + CTS_IP); + mctrl &= ~TIOCM_CTS; + mctrl |= (ipr & bitmask) ? TIOCM_CTS : 0; + } + if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(DCD_IP)) { + bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line], + DCD_IP); + mctrl &= ~TIOCM_CAR; + mctrl |= (ipr & bitmask) ? TIOCM_CAR : 0; + } + if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(RNG_IP)) { + bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line], + RNG_IP); + mctrl &= ~TIOCM_RNG; + mctrl |= (ipr & bitmask) ? TIOCM_RNG : 0; + } + + mutex_unlock(&s->sccnxp_mutex); + + return mctrl; +} + +static void sccnxp_break_ctl(struct uart_port *port, int break_state) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + mutex_lock(&s->sccnxp_mutex); + sccnxp_port_write(port, SCCNXP_CR_REG, break_state ? + CR_CMD_START_BREAK : CR_CMD_STOP_BREAK); + mutex_unlock(&s->sccnxp_mutex); +} + +static void sccnxp_set_termios(struct uart_port *port, + struct ktermios *termios, struct ktermios *old) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + u8 mr1, mr2; + int baud; + + mutex_lock(&s->sccnxp_mutex); + + /* Mask termios capabilities we don't support */ + termios->c_cflag &= ~CMSPAR; + termios->c_iflag &= ~(IXON | IXOFF | IXANY); + + /* Disable RX & TX, reset break condition, status and FIFOs */ + sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_RX_RESET | + CR_RX_DISABLE | CR_TX_DISABLE); + sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_TX_RESET); + sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_STATUS_RESET); + sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_BREAK_RESET); + + /* Word size */ + switch (termios->c_cflag & CSIZE) { + case CS5: + mr1 = MR1_BITS_5; + break; + case CS6: + mr1 = MR1_BITS_6; + break; + case CS7: + mr1 = MR1_BITS_7; + break; + default: + case CS8: + mr1 = MR1_BITS_8; + break; + } + + /* Parity */ + if (termios->c_cflag & PARENB) { + if (termios->c_cflag & PARODD) + mr1 |= MR1_PAR_ODD; + } else + mr1 |= MR1_PAR_NO; + + /* Stop bits */ + mr2 = (termios->c_cflag & CSTOPB) ? MR2_STOP2 : MR2_STOP1; + + /* Update desired format */ + sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_MRPTR1); + sccnxp_port_write(port, SCCNXP_MR_REG, mr1); + sccnxp_port_write(port, SCCNXP_MR_REG, mr2); + + /* Set read status mask */ + port->read_status_mask = SR_OVR; + if (termios->c_iflag & INPCK) + port->read_status_mask |= SR_PE | SR_FE; + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= SR_BRK; + + /* Set status ignore mask */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNBRK) + port->ignore_status_mask |= SR_BRK; + if (!(termios->c_cflag & CREAD)) + port->ignore_status_mask |= SR_PE | SR_OVR | SR_FE | SR_BRK; + + /* Setup baudrate */ + baud = uart_get_baud_rate(port, termios, old, 50, + (s->flags & SCCNXP_HAVE_MR0) ? + 230400 : 38400); + sccnxp_set_baud(port, baud); + + /* Update timeout according to new baud rate */ + uart_update_timeout(port, termios->c_cflag, baud); + + /* Enable RX & TX */ + sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_ENABLE | CR_TX_ENABLE); + + mutex_unlock(&s->sccnxp_mutex); +} + +static int sccnxp_startup(struct uart_port *port) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + mutex_lock(&s->sccnxp_mutex); + + if (s->flags & SCCNXP_HAVE_IO) { + /* Outputs are controlled manually */ + sccnxp_write(port, SCCNXP_OPCR_REG, 0); + } + + /* Reset break condition, status and FIFOs */ + sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_RX_RESET); + sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_TX_RESET); + sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_STATUS_RESET); + sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_BREAK_RESET); + + /* Enable RX & TX */ + sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_ENABLE | CR_TX_ENABLE); + + /* Enable RX interrupt */ + sccnxp_enable_irq(port, IMR_RXRDY); + + mutex_unlock(&s->sccnxp_mutex); + + return 0; +} + +static void sccnxp_shutdown(struct uart_port *port) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + mutex_lock(&s->sccnxp_mutex); + + /* Disable interrupts */ + sccnxp_disable_irq(port, IMR_TXRDY | IMR_RXRDY); + + /* Disable TX & RX */ + sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_DISABLE | CR_TX_DISABLE); + + /* Leave direction to input */ + if (s->flags & SCCNXP_HAVE_IO) + sccnxp_set_bit(port, DIR_OP, 0); + + mutex_unlock(&s->sccnxp_mutex); +} + +static const char *sccnxp_type(struct uart_port *port) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + return (port->type == PORT_SC26XX) ? s->name : NULL; +} + +static void sccnxp_release_port(struct uart_port *port) +{ + /* Do nothing */ +} + +static int sccnxp_request_port(struct uart_port *port) +{ + /* Do nothing */ + return 0; +} + +static void sccnxp_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) + port->type = PORT_SC26XX; +} + +static int sccnxp_verify_port(struct uart_port *port, struct serial_struct *s) +{ + if ((s->type == PORT_UNKNOWN) || (s->type == PORT_SC26XX)) + return 0; + if (s->irq == port->irq) + return 0; + + return -EINVAL; +} + +static const struct uart_ops sccnxp_ops = { + .tx_empty = sccnxp_tx_empty, + .set_mctrl = sccnxp_set_mctrl, + .get_mctrl = sccnxp_get_mctrl, + .stop_tx = sccnxp_stop_tx, + .start_tx = sccnxp_start_tx, + .stop_rx = sccnxp_stop_rx, + .enable_ms = sccnxp_enable_ms, + .break_ctl = sccnxp_break_ctl, + .startup = sccnxp_startup, + .shutdown = sccnxp_shutdown, + .set_termios = sccnxp_set_termios, + .type = sccnxp_type, + .release_port = sccnxp_release_port, + .request_port = sccnxp_request_port, + .config_port = sccnxp_config_port, + .verify_port = sccnxp_verify_port, +}; + +#ifdef CONFIG_SERIAL_SCCNXP_CONSOLE +static void sccnxp_console_putchar(struct uart_port *port, int c) +{ + int tryes = 100000; + + while (tryes--) { + if (sccnxp_port_read(port, SCCNXP_SR_REG) & SR_TXRDY) { + sccnxp_port_write(port, SCCNXP_THR_REG, c); + break; + } + barrier(); + } +} + +static void sccnxp_console_write(struct console *co, const char *c, unsigned n) +{ + struct sccnxp_port *s = (struct sccnxp_port *)co->data; + struct uart_port *port = &s->port[co->index]; + + mutex_lock(&s->sccnxp_mutex); + uart_console_write(port, c, n, sccnxp_console_putchar); + mutex_unlock(&s->sccnxp_mutex); +} + +static int sccnxp_console_setup(struct console *co, char *options) +{ + struct sccnxp_port *s = (struct sccnxp_port *)co->data; + struct uart_port *port = &s->port[(co->index > 0) ? co->index : 0]; + int baud = 9600, bits = 8, parity = 'n', flow = 'n'; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} +#endif + +static int __devinit sccnxp_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + int chiptype = pdev->id_entry->driver_data; + struct sccnxp_pdata *pdata = dev_get_platdata(&pdev->dev); + int i, ret, fifosize, freq_min, freq_max; + struct sccnxp_port *s; + void __iomem *membase; + + if (!res) { + dev_err(&pdev->dev, "Missing memory resource data\n"); + return -EADDRNOTAVAIL; + } + + dev_set_name(&pdev->dev, SCCNXP_NAME); + + s = devm_kzalloc(&pdev->dev, sizeof(struct sccnxp_port), GFP_KERNEL); + if (!s) { + dev_err(&pdev->dev, "Error allocating port structure\n"); + return -ENOMEM; + } + platform_set_drvdata(pdev, s); + + mutex_init(&s->sccnxp_mutex); + + /* Individual chip settings */ + switch (chiptype) { + case SCCNXP_TYPE_SC2681: + s->name = "SC2681"; + s->uart.nr = 2; + s->freq_std = 3686400; + s->addr_mask = 0x0f; + s->flags = SCCNXP_HAVE_IO; + fifosize = 3; + freq_min = 1000000; + freq_max = 4000000; + break; + case SCCNXP_TYPE_SC2691: + s->name = "SC2691"; + s->uart.nr = 1; + s->freq_std = 3686400; + s->addr_mask = 0x07; + s->flags = 0; + fifosize = 3; + freq_min = 1000000; + freq_max = 4000000; + break; + case SCCNXP_TYPE_SC2692: + s->name = "SC2692"; + s->uart.nr = 2; + s->freq_std = 3686400; + s->addr_mask = 0x0f; + s->flags = SCCNXP_HAVE_IO; + fifosize = 3; + freq_min = 1000000; + freq_max = 4000000; + break; + case SCCNXP_TYPE_SC2891: + s->name = "SC2891"; + s->uart.nr = 1; + s->freq_std = 3686400; + s->addr_mask = 0x0f; + s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0; + fifosize = 16; + freq_min = 100000; + freq_max = 8000000; + break; + case SCCNXP_TYPE_SC2892: + s->name = "SC2892"; + s->uart.nr = 2; + s->freq_std = 3686400; + s->addr_mask = 0x0f; + s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0; + fifosize = 16; + freq_min = 100000; + freq_max = 8000000; + break; + case SCCNXP_TYPE_SC28202: + s->name = "SC28202"; + s->uart.nr = 2; + s->freq_std = 14745600; + s->addr_mask = 0x7f; + s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0; + fifosize = 256; + freq_min = 1000000; + freq_max = 50000000; + break; + case SCCNXP_TYPE_SC68681: + s->name = "SC68681"; + s->uart.nr = 2; + s->freq_std = 3686400; + s->addr_mask = 0x0f; + s->flags = SCCNXP_HAVE_IO; + fifosize = 3; + freq_min = 1000000; + freq_max = 4000000; + break; + case SCCNXP_TYPE_SC68692: + s->name = "SC68692"; + s->uart.nr = 2; + s->freq_std = 3686400; + s->addr_mask = 0x0f; + s->flags = SCCNXP_HAVE_IO; + fifosize = 3; + freq_min = 1000000; + freq_max = 4000000; + break; + default: + dev_err(&pdev->dev, "Unsupported chip type %i\n", chiptype); + ret = -ENOTSUPP; + goto err_out; + } + + if (!pdata) { + dev_warn(&pdev->dev, + "No platform data supplied, using defaults\n"); + s->pdata.frequency = s->freq_std; + } else + memcpy(&s->pdata, pdata, sizeof(struct sccnxp_pdata)); + + s->irq = platform_get_irq(pdev, 0); + if (s->irq <= 0) { + dev_err(&pdev->dev, "Missing irq resource data\n"); + ret = -ENXIO; + goto err_out; + } + + /* Check input frequency */ + if ((s->pdata.frequency < freq_min) || + (s->pdata.frequency > freq_max)) { + dev_err(&pdev->dev, "Frequency out of bounds\n"); + ret = -EINVAL; + goto err_out; + } + + membase = devm_request_and_ioremap(&pdev->dev, res); + if (!membase) { + dev_err(&pdev->dev, "Failed to ioremap\n"); + ret = -EIO; + goto err_out; + } + + s->uart.owner = THIS_MODULE; + s->uart.dev_name = "ttySC"; + s->uart.major = SCCNXP_MAJOR; + s->uart.minor = SCCNXP_MINOR; +#ifdef CONFIG_SERIAL_SCCNXP_CONSOLE + s->uart.cons = &s->console; + s->uart.cons->device = uart_console_device; + s->uart.cons->write = sccnxp_console_write; + s->uart.cons->setup = sccnxp_console_setup; + s->uart.cons->flags = CON_PRINTBUFFER; + s->uart.cons->index = -1; + s->uart.cons->data = s; + strcpy(s->uart.cons->name, "ttySC"); +#endif + ret = uart_register_driver(&s->uart); + if (ret) { + dev_err(&pdev->dev, "Registering UART driver failed\n"); + goto err_out; + } + + for (i = 0; i < s->uart.nr; i++) { + s->port[i].line = i; + s->port[i].dev = &pdev->dev; + s->port[i].irq = s->irq; + s->port[i].type = PORT_SC26XX; + s->port[i].fifosize = fifosize; + s->port[i].flags = UPF_SKIP_TEST | UPF_FIXED_TYPE; + s->port[i].iotype = UPIO_MEM; + s->port[i].mapbase = res->start; + s->port[i].membase = membase; + s->port[i].regshift = s->pdata.reg_shift; + s->port[i].uartclk = s->pdata.frequency; + s->port[i].ops = &sccnxp_ops; + uart_add_one_port(&s->uart, &s->port[i]); + /* Set direction to input */ + if (s->flags & SCCNXP_HAVE_IO) + sccnxp_set_bit(&s->port[i], DIR_OP, 0); + } + + /* Disable interrupts */ + s->imr = 0; + sccnxp_write(&s->port[0], SCCNXP_IMR_REG, 0); + + /* Board specific configure */ + if (s->pdata.init) + s->pdata.init(); + + ret = devm_request_threaded_irq(&pdev->dev, s->irq, NULL, sccnxp_ist, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + dev_name(&pdev->dev), s); + if (!ret) + return 0; + + dev_err(&pdev->dev, "Unable to reguest IRQ %i\n", s->irq); + +err_out: + platform_set_drvdata(pdev, NULL); + + return ret; +} + +static int __devexit sccnxp_remove(struct platform_device *pdev) +{ + int i; + struct sccnxp_port *s = platform_get_drvdata(pdev); + + devm_free_irq(&pdev->dev, s->irq, s); + + for (i = 0; i < s->uart.nr; i++) + uart_remove_one_port(&s->uart, &s->port[i]); + + uart_unregister_driver(&s->uart); + platform_set_drvdata(pdev, NULL); + + if (s->pdata.exit) + s->pdata.exit(); + + return 0; +} + +static const struct platform_device_id sccnxp_id_table[] = { + { "sc2681", SCCNXP_TYPE_SC2681 }, + { "sc2691", SCCNXP_TYPE_SC2691 }, + { "sc2692", SCCNXP_TYPE_SC2692 }, + { "sc2891", SCCNXP_TYPE_SC2891 }, + { "sc2892", SCCNXP_TYPE_SC2892 }, + { "sc28202", SCCNXP_TYPE_SC28202 }, + { "sc68681", SCCNXP_TYPE_SC68681 }, + { "sc68692", SCCNXP_TYPE_SC68692 }, +}; +MODULE_DEVICE_TABLE(platform, sccnxp_id_table); + +static struct platform_driver sccnxp_uart_driver = { + .driver = { + .name = SCCNXP_NAME, + .owner = THIS_MODULE, + }, + .probe = sccnxp_probe, + .remove = __devexit_p(sccnxp_remove), + .id_table = sccnxp_id_table, +}; +module_platform_driver(sccnxp_uart_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); +MODULE_DESCRIPTION("SCCNXP serial driver"); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index a21dc8e3b7c0..046279ce3e8d 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -159,7 +159,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, retval = uport->ops->startup(uport); if (retval == 0) { if (uart_console(uport) && uport->cons->cflag) { - tty->termios->c_cflag = uport->cons->cflag; + tty->termios.c_cflag = uport->cons->cflag; uport->cons->cflag = 0; } /* @@ -172,11 +172,11 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, * Setup the RTS and DTR signals once the * port is open and ready to respond. */ - if (tty->termios->c_cflag & CBAUD) + if (tty->termios.c_cflag & CBAUD) uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR); } - if (port->flags & ASYNC_CTS_FLOW) { + if (tty_port_cts_enabled(port)) { spin_lock_irq(&uport->lock); if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) tty->hw_stopped = 1; @@ -240,7 +240,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) /* * Turn off DTR and RTS early. */ - if (!tty || (tty->termios->c_cflag & HUPCL)) + if (!tty || (tty->termios.c_cflag & HUPCL)) uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); uart_port_shutdown(port); @@ -440,10 +440,10 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, * If we have no tty, termios, or the port does not exist, * then we can't set the parameters for this port. */ - if (!tty || !tty->termios || uport->type == PORT_UNKNOWN) + if (!tty || uport->type == PORT_UNKNOWN) return; - termios = tty->termios; + termios = &tty->termios; /* * Set flags based on termios cflag @@ -614,7 +614,7 @@ static void uart_throttle(struct tty_struct *tty) if (I_IXOFF(tty)) uart_send_xchar(tty, STOP_CHAR(tty)); - if (tty->termios->c_cflag & CRTSCTS) + if (tty->termios.c_cflag & CRTSCTS) uart_clear_mctrl(state->uart_port, TIOCM_RTS); } @@ -630,42 +630,48 @@ static void uart_unthrottle(struct tty_struct *tty) uart_send_xchar(tty, START_CHAR(tty)); } - if (tty->termios->c_cflag & CRTSCTS) + if (tty->termios.c_cflag & CRTSCTS) uart_set_mctrl(port, TIOCM_RTS); } -static int uart_get_info(struct uart_state *state, - struct serial_struct __user *retinfo) +static void uart_get_info(struct tty_port *port, + struct uart_state *state, + struct serial_struct *retinfo) { struct uart_port *uport = state->uart_port; - struct tty_port *port = &state->port; - struct serial_struct tmp; - - memset(&tmp, 0, sizeof(tmp)); - /* Ensure the state we copy is consistent and no hardware changes - occur as we go */ - mutex_lock(&port->mutex); + memset(retinfo, 0, sizeof(*retinfo)); - tmp.type = uport->type; - tmp.line = uport->line; - tmp.port = uport->iobase; + retinfo->type = uport->type; + retinfo->line = uport->line; + retinfo->port = uport->iobase; if (HIGH_BITS_OFFSET) - tmp.port_high = (long) uport->iobase >> HIGH_BITS_OFFSET; - tmp.irq = uport->irq; - tmp.flags = uport->flags; - tmp.xmit_fifo_size = uport->fifosize; - tmp.baud_base = uport->uartclk / 16; - tmp.close_delay = jiffies_to_msecs(port->close_delay) / 10; - tmp.closing_wait = port->closing_wait == ASYNC_CLOSING_WAIT_NONE ? + retinfo->port_high = (long) uport->iobase >> HIGH_BITS_OFFSET; + retinfo->irq = uport->irq; + retinfo->flags = uport->flags; + retinfo->xmit_fifo_size = uport->fifosize; + retinfo->baud_base = uport->uartclk / 16; + retinfo->close_delay = jiffies_to_msecs(port->close_delay) / 10; + retinfo->closing_wait = port->closing_wait == ASYNC_CLOSING_WAIT_NONE ? ASYNC_CLOSING_WAIT_NONE : jiffies_to_msecs(port->closing_wait) / 10; - tmp.custom_divisor = uport->custom_divisor; - tmp.hub6 = uport->hub6; - tmp.io_type = uport->iotype; - tmp.iomem_reg_shift = uport->regshift; - tmp.iomem_base = (void *)(unsigned long)uport->mapbase; + retinfo->custom_divisor = uport->custom_divisor; + retinfo->hub6 = uport->hub6; + retinfo->io_type = uport->iotype; + retinfo->iomem_reg_shift = uport->regshift; + retinfo->iomem_base = (void *)(unsigned long)uport->mapbase; +} +static int uart_get_info_user(struct uart_state *state, + struct serial_struct __user *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); mutex_unlock(&port->mutex); if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) @@ -673,42 +679,30 @@ static int uart_get_info(struct uart_state *state, return 0; } -static int uart_set_info(struct tty_struct *tty, struct uart_state *state, - struct serial_struct __user *newinfo) +static int uart_set_info(struct tty_struct *tty, struct tty_port *port, + struct uart_state *state, + struct serial_struct *new_info) { - struct serial_struct new_serial; struct uart_port *uport = state->uart_port; - struct tty_port *port = &state->port; unsigned long new_port; unsigned int change_irq, change_port, closing_wait; unsigned int old_custom_divisor, close_delay; upf_t old_flags, new_flags; int retval = 0; - if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) - return -EFAULT; - - new_port = new_serial.port; + new_port = new_info->port; if (HIGH_BITS_OFFSET) - new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; + new_port += (unsigned long) new_info->port_high << HIGH_BITS_OFFSET; - new_serial.irq = irq_canonicalize(new_serial.irq); - close_delay = msecs_to_jiffies(new_serial.close_delay * 10); - closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? + new_info->irq = irq_canonicalize(new_info->irq); + close_delay = msecs_to_jiffies(new_info->close_delay * 10); + closing_wait = new_info->closing_wait == ASYNC_CLOSING_WAIT_NONE ? ASYNC_CLOSING_WAIT_NONE : - msecs_to_jiffies(new_serial.closing_wait * 10); + msecs_to_jiffies(new_info->closing_wait * 10); - /* - * This semaphore protects port->count. It is also - * very useful to prevent opens. Also, take the - * port configuration semaphore to make sure that a - * module insertion/removal doesn't change anything - * under us. - */ - mutex_lock(&port->mutex); change_irq = !(uport->flags & UPF_FIXED_PORT) - && new_serial.irq != uport->irq; + && new_info->irq != uport->irq; /* * Since changing the 'type' of the port changes its resource @@ -717,29 +711,29 @@ static int uart_set_info(struct tty_struct *tty, struct uart_state *state, */ change_port = !(uport->flags & UPF_FIXED_PORT) && (new_port != uport->iobase || - (unsigned long)new_serial.iomem_base != uport->mapbase || - new_serial.hub6 != uport->hub6 || - new_serial.io_type != uport->iotype || - new_serial.iomem_reg_shift != uport->regshift || - new_serial.type != uport->type); + (unsigned long)new_info->iomem_base != uport->mapbase || + new_info->hub6 != uport->hub6 || + new_info->io_type != uport->iotype || + new_info->iomem_reg_shift != uport->regshift || + new_info->type != uport->type); old_flags = uport->flags; - new_flags = new_serial.flags; + new_flags = new_info->flags; old_custom_divisor = uport->custom_divisor; if (!capable(CAP_SYS_ADMIN)) { retval = -EPERM; if (change_irq || change_port || - (new_serial.baud_base != uport->uartclk / 16) || + (new_info->baud_base != uport->uartclk / 16) || (close_delay != port->close_delay) || (closing_wait != port->closing_wait) || - (new_serial.xmit_fifo_size && - new_serial.xmit_fifo_size != uport->fifosize) || + (new_info->xmit_fifo_size && + new_info->xmit_fifo_size != uport->fifosize) || (((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0)) goto exit; uport->flags = ((uport->flags & ~UPF_USR_MASK) | (new_flags & UPF_USR_MASK)); - uport->custom_divisor = new_serial.custom_divisor; + uport->custom_divisor = new_info->custom_divisor; goto check_and_exit; } @@ -747,10 +741,10 @@ static int uart_set_info(struct tty_struct *tty, struct uart_state *state, * Ask the low level driver to verify the settings. */ if (uport->ops->verify_port) - retval = uport->ops->verify_port(uport, &new_serial); + retval = uport->ops->verify_port(uport, new_info); - if ((new_serial.irq >= nr_irqs) || (new_serial.irq < 0) || - (new_serial.baud_base < 9600)) + if ((new_info->irq >= nr_irqs) || (new_info->irq < 0) || + (new_info->baud_base < 9600)) retval = -EINVAL; if (retval) @@ -790,11 +784,11 @@ static int uart_set_info(struct tty_struct *tty, struct uart_state *state, uport->ops->release_port(uport); uport->iobase = new_port; - uport->type = new_serial.type; - uport->hub6 = new_serial.hub6; - uport->iotype = new_serial.io_type; - uport->regshift = new_serial.iomem_reg_shift; - uport->mapbase = (unsigned long)new_serial.iomem_base; + uport->type = new_info->type; + uport->hub6 = new_info->hub6; + uport->iotype = new_info->io_type; + uport->regshift = new_info->iomem_reg_shift; + uport->mapbase = (unsigned long)new_info->iomem_base; /* * Claim and map the new regions @@ -835,16 +829,16 @@ static int uart_set_info(struct tty_struct *tty, struct uart_state *state, } if (change_irq) - uport->irq = new_serial.irq; + uport->irq = new_info->irq; if (!(uport->flags & UPF_FIXED_PORT)) - uport->uartclk = new_serial.baud_base * 16; + uport->uartclk = new_info->baud_base * 16; uport->flags = (uport->flags & ~UPF_CHANGE_MASK) | (new_flags & UPF_CHANGE_MASK); - uport->custom_divisor = new_serial.custom_divisor; + uport->custom_divisor = new_info->custom_divisor; port->close_delay = close_delay; port->closing_wait = closing_wait; - if (new_serial.xmit_fifo_size) - uport->fifosize = new_serial.xmit_fifo_size; + if (new_info->xmit_fifo_size) + uport->fifosize = new_info->xmit_fifo_size; if (port->tty) port->tty->low_latency = (uport->flags & UPF_LOW_LATENCY) ? 1 : 0; @@ -873,6 +867,28 @@ static int uart_set_info(struct tty_struct *tty, struct uart_state *state, } else retval = uart_startup(tty, state, 1); exit: + return retval; +} + +static int uart_set_info_user(struct tty_struct *tty, struct uart_state *state, + struct serial_struct __user *newinfo) +{ + struct serial_struct new_serial; + struct tty_port *port = &state->port; + int retval; + + if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) + return -EFAULT; + + /* + * This semaphore protects port->count. It is also + * very useful to prevent opens. Also, take the + * port configuration semaphore to make sure that a + * module insertion/removal doesn't change anything + * under us. + */ + mutex_lock(&port->mutex); + retval = uart_set_info(tty, port, state, &new_serial); mutex_unlock(&port->mutex); return retval; } @@ -1115,11 +1131,11 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, */ switch (cmd) { case TIOCGSERIAL: - ret = uart_get_info(state, uarg); + ret = uart_get_info_user(state, uarg); break; case TIOCSSERIAL: - ret = uart_set_info(tty, state, uarg); + ret = uart_set_info_user(tty, state, uarg); break; case TIOCSERCONFIG: @@ -1187,7 +1203,7 @@ static void uart_set_ldisc(struct tty_struct *tty) struct uart_port *uport = state->uart_port; if (uport->ops->set_ldisc) - uport->ops->set_ldisc(uport, tty->termios->c_line); + uport->ops->set_ldisc(uport, tty->termios.c_line); } static void uart_set_termios(struct tty_struct *tty, @@ -1195,7 +1211,7 @@ static void uart_set_termios(struct tty_struct *tty, { struct uart_state *state = tty->driver_data; unsigned long flags; - unsigned int cflag = tty->termios->c_cflag; + unsigned int cflag = tty->termios.c_cflag; /* @@ -1206,9 +1222,9 @@ static void uart_set_termios(struct tty_struct *tty, */ #define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) if ((cflag ^ old_termios->c_cflag) == 0 && - tty->termios->c_ospeed == old_termios->c_ospeed && - tty->termios->c_ispeed == old_termios->c_ispeed && - RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) { + tty->termios.c_ospeed == old_termios->c_ospeed && + tty->termios.c_ispeed == old_termios->c_ispeed && + RELEVANT_IFLAG(tty->termios.c_iflag ^ old_termios->c_iflag) == 0) { return; } @@ -1960,8 +1976,8 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) /* * If that's unset, use the tty termios setting. */ - if (port->tty && port->tty->termios && termios.c_cflag == 0) - termios = *(port->tty->termios); + if (port->tty && termios.c_cflag == 0) + termios = port->tty->termios; if (console_suspend_enabled) uart_change_pm(state, 0); @@ -2293,6 +2309,36 @@ struct tty_driver *uart_console_device(struct console *co, int *index) return p->tty_driver; } +static ssize_t uart_get_attr_uartclk(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + 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); + + return ret; +} + +static DEVICE_ATTR(uartclk, S_IRUSR | S_IRGRP, uart_get_attr_uartclk, NULL); + +static struct attribute *tty_dev_attrs[] = { + &dev_attr_uartclk.attr, + NULL, + }; + +static const struct attribute_group tty_dev_attr_group = { + .attrs = tty_dev_attrs, + }; + +static const struct attribute_group *tty_dev_attr_groups[] = { + &tty_dev_attr_group, + NULL + }; + /** * uart_add_one_port - attach a driver-defined port structure * @drv: pointer to the uart low level driver structure for this port @@ -2346,7 +2392,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) * Register the port whether it's detected or not. This allows * setserial to be used to alter this ports parameters. */ - tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev); + tty_dev = tty_port_register_device_attr(port, drv->tty_driver, + uport->line, uport->dev, port, tty_dev_attr_groups); if (likely(!IS_ERR(tty_dev))) { device_set_wakeup_capable(tty_dev, 1); } else { @@ -2492,7 +2539,7 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status) uport->icount.cts++; - if (port->flags & ASYNC_CTS_FLOW) { + if (tty_port_cts_enabled(port)) { if (tty->hw_stopped) { if (status) { tty->hw_stopped = 0; diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c index 5b3eda2024fe..a9e2bd1ab534 100644 --- a/drivers/tty/serial/sirfsoc_uart.c +++ b/drivers/tty/serial/sirfsoc_uart.c @@ -668,7 +668,7 @@ int sirfsoc_uart_probe(struct platform_device *pdev) if (res == NULL) { dev_err(&pdev->dev, "Insufficient resources.\n"); ret = -EFAULT; - goto irq_err; + goto err; } port->irq = res->start; @@ -676,7 +676,7 @@ int sirfsoc_uart_probe(struct platform_device *pdev) sirfport->p = pinctrl_get_select_default(&pdev->dev); ret = IS_ERR(sirfport->p); if (ret) - goto pin_err; + goto err; } port->ops = &sirfsoc_uart_ops; @@ -695,9 +695,6 @@ port_err: platform_set_drvdata(pdev, NULL); if (sirfport->hw_flow_ctrl) pinctrl_put(sirfport->p); -pin_err: -irq_err: - devm_iounmap(&pdev->dev, port->membase); err: return ret; } @@ -709,7 +706,6 @@ static int sirfsoc_uart_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); if (sirfport->hw_flow_ctrl) pinctrl_put(sirfport->p); - devm_iounmap(&pdev->dev, port->membase); uart_remove_one_port(&sirfsoc_uart_drv, port); return 0; } diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index 675303b8ed84..b97913dcdbff 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -58,10 +58,16 @@ enum su_type { SU_PORT_NONE, SU_PORT_MS, SU_PORT_KBD, SU_PORT_PORT }; static char *su_typev[] = { "su(???)", "su(mouse)", "su(kbd)", "su(serial)" }; +struct serial_uart_config { + char *name; + int dfl_xmit_fifo_size; + int flags; +}; + /* * Here we define the default xmit fifo size used for each type of UART. */ -static const struct serial_uart_config uart_config[PORT_MAX_8250+1] = { +static const struct serial_uart_config uart_config[] = { { "unknown", 1, 0 }, { "8250", 1, 0 }, { "16450", 1, 0 }, diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index 593d40ad0a6b..70e3a525bc82 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -1359,7 +1359,7 @@ static void mgsl_isr_io_pin( struct mgsl_struct *info ) } } - if ( (info->port.flags & ASYNC_CTS_FLOW) && + if (tty_port_cts_enabled(&info->port) && (status & MISCSTATUS_CTS_LATCHED) ) { if (info->port.tty->hw_stopped) { if (status & MISCSTATUS_CTS) { @@ -1840,22 +1840,22 @@ static void shutdown(struct mgsl_struct * info) usc_DisableInterrupts(info,RECEIVE_DATA + RECEIVE_STATUS + TRANSMIT_DATA + TRANSMIT_STATUS + IO_PIN + MISC ); usc_DisableDmaInterrupts(info,DICR_MASTER + DICR_TRANSMIT + DICR_RECEIVE); - + /* Disable DMAEN (Port 7, Bit 14) */ /* This disconnects the DMA request signal from the ISA bus */ /* on the ISA adapter. This has no effect for the PCI adapter */ usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT15) | BIT14)); - + /* Disable INTEN (Port 6, Bit12) */ /* This disconnects the IRQ request signal to the ISA bus */ /* on the ISA adapter. This has no effect for the PCI adapter */ usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) | BIT12)); - - if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) { + + if (!info->port.tty || info->port.tty->termios.c_cflag & HUPCL) { info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS); usc_set_serial_signals(info); } - + spin_unlock_irqrestore(&info->irq_spinlock,flags); mgsl_release_resources(info); @@ -1895,7 +1895,7 @@ static void mgsl_program_hw(struct mgsl_struct *info) usc_EnableInterrupts(info, IO_PIN); usc_get_serial_signals(info); - if (info->netcount || info->port.tty->termios->c_cflag & CREAD) + if (info->netcount || info->port.tty->termios.c_cflag & CREAD) usc_start_receiver(info); spin_unlock_irqrestore(&info->irq_spinlock,flags); @@ -1908,14 +1908,14 @@ static void mgsl_change_params(struct mgsl_struct *info) unsigned cflag; int bits_per_char; - if (!info->port.tty || !info->port.tty->termios) + if (!info->port.tty) return; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_change_params(%s)\n", __FILE__,__LINE__, info->device_name ); - cflag = info->port.tty->termios->c_cflag; + cflag = info->port.tty->termios.c_cflag; /* if B0 rate (hangup) specified then negate DTR and RTS */ /* otherwise assert DTR and RTS */ @@ -2367,8 +2367,8 @@ static void mgsl_throttle(struct tty_struct * tty) if (I_IXOFF(tty)) mgsl_send_xchar(tty, STOP_CHAR(tty)); - - if (tty->termios->c_cflag & CRTSCTS) { + + if (tty->termios.c_cflag & CRTSCTS) { spin_lock_irqsave(&info->irq_spinlock,flags); info->serial_signals &= ~SerialSignal_RTS; usc_set_serial_signals(info); @@ -2401,8 +2401,8 @@ static void mgsl_unthrottle(struct tty_struct * tty) else mgsl_send_xchar(tty, START_CHAR(tty)); } - - if (tty->termios->c_cflag & CRTSCTS) { + + if (tty->termios.c_cflag & CRTSCTS) { spin_lock_irqsave(&info->irq_spinlock,flags); info->serial_signals |= SerialSignal_RTS; usc_set_serial_signals(info); @@ -3045,7 +3045,7 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio /* Handle transition to B0 status */ if (old_termios->c_cflag & CBAUD && - !(tty->termios->c_cflag & CBAUD)) { + !(tty->termios.c_cflag & CBAUD)) { info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); spin_lock_irqsave(&info->irq_spinlock,flags); usc_set_serial_signals(info); @@ -3054,9 +3054,9 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && - tty->termios->c_cflag & CBAUD) { + tty->termios.c_cflag & CBAUD) { info->serial_signals |= SerialSignal_DTR; - if (!(tty->termios->c_cflag & CRTSCTS) || + if (!(tty->termios.c_cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) { info->serial_signals |= SerialSignal_RTS; } @@ -3067,7 +3067,7 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio /* Handle turning off CRTSCTS */ if (old_termios->c_cflag & CRTSCTS && - !(tty->termios->c_cflag & CRTSCTS)) { + !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; mgsl_start(tty); } @@ -3287,7 +3287,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, return 0; } - if (tty->termios->c_cflag & CLOCAL) + if (tty->termios.c_cflag & CLOCAL) do_clocal = true; /* Wait for carrier detect and the line to become @@ -3313,7 +3313,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, port->blocked_open++; while (1) { - if (tty->termios->c_cflag & CBAUD) + if (tty->termios.c_cflag & CBAUD) tty_port_raise_dtr_rts(port); set_current_state(TASK_INTERRUPTIBLE); @@ -3338,9 +3338,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, printk("%s(%d):block_til_ready blocking on %s count=%d\n", __FILE__,__LINE__, tty->driver->name, port->count ); - tty_unlock(); + tty_unlock(tty); schedule(); - tty_lock(); + tty_lock(tty); } set_current_state(TASK_RUNNING); @@ -3362,6 +3362,29 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, } /* end of block_til_ready() */ +static int mgsl_install(struct tty_driver *driver, struct tty_struct *tty) +{ + struct mgsl_struct *info; + int line = tty->index; + + /* verify range of specified line number */ + if (line >= mgsl_device_count) { + printk("%s(%d):mgsl_open with invalid line #%d.\n", + __FILE__, __LINE__, line); + return -ENODEV; + } + + /* find the info structure for the specified line */ + info = mgsl_device_list; + while (info && info->line != line) + info = info->next_device; + if (mgsl_paranoia_check(info, tty->name, "mgsl_open")) + return -ENODEV; + tty->driver_data = info; + + return tty_port_install(&info->port, driver, tty); +} + /* mgsl_open() * * Called when a port is opened. Init and enable port. @@ -3374,26 +3397,10 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, */ static int mgsl_open(struct tty_struct *tty, struct file * filp) { - struct mgsl_struct *info; - int retval, line; + struct mgsl_struct *info = tty->driver_data; unsigned long flags; + int retval; - /* verify range of specified line number */ - line = tty->index; - if (line >= mgsl_device_count) { - printk("%s(%d):mgsl_open with invalid line #%d.\n", - __FILE__,__LINE__,line); - return -ENODEV; - } - - /* find the info structure for the specified line */ - info = mgsl_device_list; - while(info && info->line != line) - info = info->next_device; - if (mgsl_paranoia_check(info, tty->name, "mgsl_open")) - return -ENODEV; - - tty->driver_data = info; info->port.tty = tty; if (debug_level >= DEBUG_LEVEL_INFO) @@ -4297,6 +4304,7 @@ static struct mgsl_struct* mgsl_allocate_device(void) } /* end of mgsl_allocate_device()*/ static const struct tty_operations mgsl_ops = { + .install = mgsl_install, .open = mgsl_open, .close = mgsl_close, .write = mgsl_write, diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index aa1debf97cc7..b38e954eedd3 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -785,7 +785,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) /* Handle transition to B0 status */ if (old_termios->c_cflag & CBAUD && - !(tty->termios->c_cflag & CBAUD)) { + !(tty->termios.c_cflag & CBAUD)) { info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR); spin_lock_irqsave(&info->lock,flags); set_signals(info); @@ -794,9 +794,9 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && - tty->termios->c_cflag & CBAUD) { + tty->termios.c_cflag & CBAUD) { info->signals |= SerialSignal_DTR; - if (!(tty->termios->c_cflag & CRTSCTS) || + if (!(tty->termios.c_cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) { info->signals |= SerialSignal_RTS; } @@ -807,7 +807,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) /* Handle turning off CRTSCTS */ if (old_termios->c_cflag & CRTSCTS && - !(tty->termios->c_cflag & CRTSCTS)) { + !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; tx_release(tty); } @@ -1372,7 +1372,7 @@ static void throttle(struct tty_struct * tty) DBGINFO(("%s throttle\n", info->device_name)); if (I_IXOFF(tty)) send_xchar(tty, STOP_CHAR(tty)); - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { spin_lock_irqsave(&info->lock,flags); info->signals &= ~SerialSignal_RTS; set_signals(info); @@ -1397,7 +1397,7 @@ static void unthrottle(struct tty_struct * tty) else send_xchar(tty, START_CHAR(tty)); } - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { spin_lock_irqsave(&info->lock,flags); info->signals |= SerialSignal_RTS; set_signals(info); @@ -2053,7 +2053,7 @@ static void cts_change(struct slgt_info *info, unsigned short status) wake_up_interruptible(&info->event_wait_q); info->pending_bh |= BH_STATUS; - if (info->port.flags & ASYNC_CTS_FLOW) { + if (tty_port_cts_enabled(&info->port)) { if (info->port.tty) { if (info->port.tty->hw_stopped) { if (info->signals & SerialSignal_CTS) { @@ -2493,7 +2493,7 @@ static void shutdown(struct slgt_info *info) slgt_irq_off(info, IRQ_ALL | IRQ_MASTER); - if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) { + if (!info->port.tty || info->port.tty->termios.c_cflag & HUPCL) { info->signals &= ~(SerialSignal_DTR + SerialSignal_RTS); set_signals(info); } @@ -2534,7 +2534,7 @@ static void program_hw(struct slgt_info *info) get_signals(info); if (info->netcount || - (info->port.tty && info->port.tty->termios->c_cflag & CREAD)) + (info->port.tty && info->port.tty->termios.c_cflag & CREAD)) rx_start(info); spin_unlock_irqrestore(&info->lock,flags); @@ -2548,11 +2548,11 @@ static void change_params(struct slgt_info *info) unsigned cflag; int bits_per_char; - if (!info->port.tty || !info->port.tty->termios) + if (!info->port.tty) return; DBGINFO(("%s change_params\n", info->device_name)); - cflag = info->port.tty->termios->c_cflag; + cflag = info->port.tty->termios.c_cflag; /* if B0 rate (hangup) specified then negate DTR and RTS */ /* otherwise assert DTR and RTS */ @@ -3292,7 +3292,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, return 0; } - if (tty->termios->c_cflag & CLOCAL) + if (tty->termios.c_cflag & CLOCAL) do_clocal = true; /* Wait for carrier detect and the line to become @@ -3314,7 +3314,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, port->blocked_open++; while (1) { - if ((tty->termios->c_cflag & CBAUD)) + if ((tty->termios.c_cflag & CBAUD)) tty_port_raise_dtr_rts(port); set_current_state(TASK_INTERRUPTIBLE); @@ -3336,9 +3336,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, } DBGINFO(("%s block_til_ready wait\n", tty->driver->name)); - tty_unlock(); + tty_unlock(tty); schedule(); - tty_lock(); + tty_lock(tty); } set_current_state(TASK_RUNNING); @@ -3689,8 +3689,11 @@ static void device_init(int adapter_num, struct pci_dev *pdev) } } - for (i=0; i < port_count; ++i) - tty_register_device(serial_driver, port_array[i]->line, &(port_array[i]->pdev->dev)); + for (i = 0; i < port_count; ++i) { + struct slgt_info *info = port_array[i]; + tty_port_register_device(&info->port, serial_driver, info->line, + &info->pdev->dev); + } } static int __devinit init_one(struct pci_dev *dev, diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index a3dddc12d2fe..f17d9f3d84a2 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -711,15 +711,11 @@ static void ldisc_receive_buf(struct tty_struct *tty, /* tty callbacks */ -/* Called when a port is opened. Init and enable port. - */ -static int open(struct tty_struct *tty, struct file *filp) +static int install(struct tty_driver *driver, struct tty_struct *tty) { SLMP_INFO *info; - int retval, line; - unsigned long flags; + int line = tty->index; - line = tty->index; if (line >= synclinkmp_device_count) { printk("%s(%d): open with invalid line #%d.\n", __FILE__,__LINE__,line); @@ -727,17 +723,30 @@ static int open(struct tty_struct *tty, struct file *filp) } info = synclinkmp_device_list; - while(info && info->line != line) + while (info && info->line != line) info = info->next_device; if (sanity_check(info, tty->name, "open")) return -ENODEV; - if ( info->init_error ) { + if (info->init_error) { printk("%s(%d):%s device is not allocated, init error=%d\n", - __FILE__,__LINE__,info->device_name,info->init_error); + __FILE__, __LINE__, info->device_name, + info->init_error); return -ENODEV; } tty->driver_data = info; + + return tty_port_install(&info->port, driver, tty); +} + +/* Called when a port is opened. Init and enable port. + */ +static int open(struct tty_struct *tty, struct file *filp) +{ + SLMP_INFO *info = tty->driver_data; + unsigned long flags; + int retval; + info->port.tty = tty; if (debug_level >= DEBUG_LEVEL_INFO) @@ -873,7 +882,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) /* Handle transition to B0 status */ if (old_termios->c_cflag & CBAUD && - !(tty->termios->c_cflag & CBAUD)) { + !(tty->termios.c_cflag & CBAUD)) { info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); spin_lock_irqsave(&info->lock,flags); set_signals(info); @@ -882,9 +891,9 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && - tty->termios->c_cflag & CBAUD) { + tty->termios.c_cflag & CBAUD) { info->serial_signals |= SerialSignal_DTR; - if (!(tty->termios->c_cflag & CRTSCTS) || + if (!(tty->termios.c_cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) { info->serial_signals |= SerialSignal_RTS; } @@ -895,7 +904,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) /* Handle turning off CRTSCTS */ if (old_termios->c_cflag & CRTSCTS && - !(tty->termios->c_cflag & CRTSCTS)) { + !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; tx_release(tty); } @@ -1473,7 +1482,7 @@ static void throttle(struct tty_struct * tty) if (I_IXOFF(tty)) send_xchar(tty, STOP_CHAR(tty)); - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { spin_lock_irqsave(&info->lock,flags); info->serial_signals &= ~SerialSignal_RTS; set_signals(info); @@ -1502,7 +1511,7 @@ static void unthrottle(struct tty_struct * tty) send_xchar(tty, START_CHAR(tty)); } - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { spin_lock_irqsave(&info->lock,flags); info->serial_signals |= SerialSignal_RTS; set_signals(info); @@ -2491,7 +2500,7 @@ static void isr_io_pin( SLMP_INFO *info, u16 status ) } } - if ( (info->port.flags & ASYNC_CTS_FLOW) && + if (tty_port_cts_enabled(&info->port) && (status & MISCSTATUS_CTS_LATCHED) ) { if ( info->port.tty ) { if (info->port.tty->hw_stopped) { @@ -2708,7 +2717,7 @@ static void shutdown(SLMP_INFO * info) reset_port(info); - if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) { + if (!info->port.tty || info->port.tty->termios.c_cflag & HUPCL) { info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS); set_signals(info); } @@ -2749,7 +2758,7 @@ static void program_hw(SLMP_INFO *info) get_signals(info); - if (info->netcount || (info->port.tty && info->port.tty->termios->c_cflag & CREAD) ) + if (info->netcount || (info->port.tty && info->port.tty->termios.c_cflag & CREAD) ) rx_start(info); spin_unlock_irqrestore(&info->lock,flags); @@ -2762,14 +2771,14 @@ static void change_params(SLMP_INFO *info) unsigned cflag; int bits_per_char; - if (!info->port.tty || !info->port.tty->termios) + if (!info->port.tty) return; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s change_params()\n", __FILE__,__LINE__, info->device_name ); - cflag = info->port.tty->termios->c_cflag; + cflag = info->port.tty->termios.c_cflag; /* if B0 rate (hangup) specified then negate DTR and RTS */ /* otherwise assert DTR and RTS */ @@ -3306,7 +3315,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, return 0; } - if (tty->termios->c_cflag & CLOCAL) + if (tty->termios.c_cflag & CLOCAL) do_clocal = true; /* Wait for carrier detect and the line to become @@ -3332,7 +3341,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, port->blocked_open++; while (1) { - if (tty->termios->c_cflag & CBAUD) + if (tty->termios.c_cflag & CBAUD) tty_port_raise_dtr_rts(port); set_current_state(TASK_INTERRUPTIBLE); @@ -3357,9 +3366,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, printk("%s(%d):%s block_til_ready() count=%d\n", __FILE__,__LINE__, tty->driver->name, port->count ); - tty_unlock(); + tty_unlock(tty); schedule(); - tty_lock(); + tty_lock(tty); } set_current_state(TASK_RUNNING); @@ -3881,6 +3890,7 @@ static void device_init(int adapter_num, struct pci_dev *pdev) } static const struct tty_operations ops = { + .install = install, .open = open, .close = close, .write = write, diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index b425c79675ad..8a5a8b064616 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -181,10 +181,13 @@ struct tty_struct *alloc_tty_struct(void) void free_tty_struct(struct tty_struct *tty) { + if (!tty) + return; if (tty->dev) put_device(tty->dev); kfree(tty->write_buf); tty_buffer_free_all(tty); + tty->magic = 0xDEADDEAD; kfree(tty); } @@ -573,7 +576,7 @@ void __tty_hangup(struct tty_struct *tty) } spin_unlock(&redirect_lock); - tty_lock(); + tty_lock(tty); /* some functions below drop BTM, so we need this bit */ set_bit(TTY_HUPPING, &tty->flags); @@ -666,7 +669,7 @@ void __tty_hangup(struct tty_struct *tty) clear_bit(TTY_HUPPING, &tty->flags); tty_ldisc_enable(tty); - tty_unlock(); + tty_unlock(tty); if (f) fput(f); @@ -1103,12 +1106,12 @@ void tty_write_message(struct tty_struct *tty, char *msg) { if (tty) { mutex_lock(&tty->atomic_write_lock); - tty_lock(); + tty_lock(tty); if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) { - tty_unlock(); + tty_unlock(tty); tty->ops->write(tty, msg, strlen(msg)); } else - tty_unlock(); + tty_unlock(tty); tty_write_unlock(tty); } return; @@ -1213,7 +1216,10 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p) */ static void tty_line_name(struct tty_driver *driver, int index, char *p) { - sprintf(p, "%s%d", driver->name, index + driver->name_base); + if (driver->flags & TTY_DRIVER_UNNUMBERED_NODE) + strcpy(p, driver->name); + else + sprintf(p, "%s%d", driver->name, index + driver->name_base); } /** @@ -1249,21 +1255,19 @@ int tty_init_termios(struct tty_struct *tty) struct ktermios *tp; int idx = tty->index; - tp = tty->driver->termios[idx]; - if (tp == NULL) { - tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL); - if (tp == NULL) - return -ENOMEM; - memcpy(tp, &tty->driver->init_termios, - sizeof(struct ktermios)); - tty->driver->termios[idx] = tp; + if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) + tty->termios = tty->driver->init_termios; + else { + /* Check for lazy saved data */ + tp = tty->driver->termios[idx]; + if (tp != NULL) + tty->termios = *tp; + else + tty->termios = tty->driver->init_termios; } - tty->termios = tp; - tty->termios_locked = tp + 1; - /* Compatibility until drivers always set this */ - tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios); - tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios); + tty->termios.c_ispeed = tty_termios_input_baud_rate(&tty->termios); + tty->termios.c_ospeed = tty_termios_baud_rate(&tty->termios); return 0; } EXPORT_SYMBOL_GPL(tty_init_termios); @@ -1403,10 +1407,18 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) } initialize_tty_struct(tty, driver, idx); + tty_lock(tty); retval = tty_driver_install_tty(driver, tty); if (retval < 0) goto err_deinit_tty; + if (!tty->port) + tty->port = driver->ports[idx]; + + WARN_RATELIMIT(!tty->port, + "%s: %s driver does not set tty->port. This will crash the kernel later. Fix the driver!\n", + __func__, tty->driver->name); + /* * Structures all installed ... call the ldisc open routines. * If we fail here just call release_tty to clean up. No need @@ -1415,9 +1427,11 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) retval = tty_ldisc_setup(tty, tty->link); if (retval) goto err_release_tty; + /* Return the tty locked so that it cannot vanish under the caller */ return tty; err_deinit_tty: + tty_unlock(tty); deinitialize_tty_struct(tty); free_tty_struct(tty); err_module_put: @@ -1426,6 +1440,7 @@ err_module_put: /* call the tty release_tty routine to clean out this slot */ err_release_tty: + tty_unlock(tty); printk_ratelimited(KERN_INFO "tty_init_dev: ldisc open failed, " "clearing slot %d\n", idx); release_tty(tty, idx); @@ -1436,22 +1451,25 @@ void tty_free_termios(struct tty_struct *tty) { struct ktermios *tp; int idx = tty->index; - /* Kill this flag and push into drivers for locking etc */ - if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { - /* FIXME: Locking on ->termios array */ - tp = tty->termios; - tty->driver->termios[idx] = NULL; - kfree(tp); + + /* If the port is going to reset then it has no termios to save */ + if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) + return; + + /* Stash the termios data */ + tp = tty->driver->termios[idx]; + if (tp == NULL) { + tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL); + if (tp == NULL) { + pr_warn("tty: no memory to save termios state.\n"); + return; + } + tty->driver->termios[idx] = tp; } + *tp = tty->termios; } EXPORT_SYMBOL(tty_free_termios); -void tty_shutdown(struct tty_struct *tty) -{ - tty_driver_remove_tty(tty->driver, tty); - tty_free_termios(tty); -} -EXPORT_SYMBOL(tty_shutdown); /** * release_one_tty - release tty structure memory @@ -1462,7 +1480,6 @@ EXPORT_SYMBOL(tty_shutdown); * in use. It also gets called when setup of a device fails. * * Locking: - * tty_mutex - sometimes only * takes the file list lock internally when working on the list * of ttys that the driver keeps. * @@ -1495,11 +1512,6 @@ static void queue_release_one_tty(struct kref *kref) { struct tty_struct *tty = container_of(kref, struct tty_struct, kref); - if (tty->ops->shutdown) - tty->ops->shutdown(tty); - else - tty_shutdown(tty); - /* The hangup queue is now free so we can reuse it rather than waste a chunk of memory for each port */ INIT_WORK(&tty->hangup_work, release_one_tty); @@ -1528,16 +1540,20 @@ EXPORT_SYMBOL(tty_kref_put); * and decrement the refcount of the backing module. * * Locking: - * tty_mutex - sometimes only + * tty_mutex * takes the file list lock internally when working on the list * of ttys that the driver keeps. - * FIXME: should we require tty_mutex is held here ?? * */ static void release_tty(struct tty_struct *tty, int idx) { /* This should always be true but check for the moment */ WARN_ON(tty->index != idx); + WARN_ON(!mutex_is_locked(&tty_mutex)); + if (tty->ops->shutdown) + tty->ops->shutdown(tty); + tty_free_termios(tty); + tty_driver_remove_tty(tty->driver, tty); if (tty->link) tty_kref_put(tty->link); @@ -1572,22 +1588,12 @@ static int tty_release_checks(struct tty_struct *tty, struct tty_struct *o_tty, __func__, idx, tty->name); return -1; } - if (tty->termios != tty->driver->termios[idx]) { - printk(KERN_DEBUG "%s: driver.termios[%d] not termios for (%s)\n", - __func__, idx, tty->name); - return -1; - } if (tty->driver->other) { if (o_tty != tty->driver->other->ttys[idx]) { printk(KERN_DEBUG "%s: other->table[%d] not o_tty for (%s)\n", __func__, idx, tty->name); return -1; } - if (o_tty->termios != tty->driver->other->termios[idx]) { - printk(KERN_DEBUG "%s: other->termios[%d] not o_termios for (%s)\n", - __func__, idx, tty->name); - return -1; - } if (o_tty->link != tty) { printk(KERN_DEBUG "%s: bad pty pointers\n", __func__); return -1; @@ -1628,7 +1634,7 @@ int tty_release(struct inode *inode, struct file *filp) if (tty_paranoia_check(tty, inode, __func__)) return 0; - tty_lock(); + tty_lock(tty); check_tty_count(tty, __func__); __tty_fasync(-1, filp, 0); @@ -1637,10 +1643,11 @@ int tty_release(struct inode *inode, struct file *filp) pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER); devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0; + /* Review: parallel close */ o_tty = tty->link; if (tty_release_checks(tty, o_tty, idx)) { - tty_unlock(); + tty_unlock(tty); return 0; } @@ -1652,7 +1659,7 @@ int tty_release(struct inode *inode, struct file *filp) if (tty->ops->close) tty->ops->close(tty, filp); - tty_unlock(); + tty_unlock(tty); /* * Sanity check: if tty->count is going to zero, there shouldn't be * any waiters on tty->read_wait or tty->write_wait. We test the @@ -1675,7 +1682,7 @@ int tty_release(struct inode *inode, struct file *filp) opens on /dev/tty */ mutex_lock(&tty_mutex); - tty_lock(); + tty_lock_pair(tty, o_tty); tty_closing = tty->count <= 1; o_tty_closing = o_tty && (o_tty->count <= (pty_master ? 1 : 0)); @@ -1706,7 +1713,7 @@ int tty_release(struct inode *inode, struct file *filp) printk(KERN_WARNING "%s: %s: read/write wait queue active!\n", __func__, tty_name(tty, buf)); - tty_unlock(); + tty_unlock_pair(tty, o_tty); mutex_unlock(&tty_mutex); schedule(); } @@ -1715,6 +1722,9 @@ int tty_release(struct inode *inode, struct file *filp) * The closing flags are now consistent with the open counts on * both sides, and we've completed the last operation that could * block, so it's safe to proceed with closing. + * + * We must *not* drop the tty_mutex until we ensure that a further + * entry into tty_open can not pick up this tty. */ if (pty_master) { if (--o_tty->count < 0) { @@ -1766,12 +1776,13 @@ int tty_release(struct inode *inode, struct file *filp) } mutex_unlock(&tty_mutex); + tty_unlock_pair(tty, o_tty); + /* At this point the TTY_CLOSING flag should ensure a dead tty + cannot be re-opened by a racing opener */ /* check whether both sides are closing ... */ - if (!tty_closing || (o_tty && !o_tty_closing)) { - tty_unlock(); + if (!tty_closing || (o_tty && !o_tty_closing)) return 0; - } #ifdef TTY_DEBUG_HANGUP printk(KERN_DEBUG "%s: freeing tty structure...\n", __func__); @@ -1782,14 +1793,17 @@ int tty_release(struct inode *inode, struct file *filp) tty_ldisc_release(tty, o_tty); /* * The release_tty function takes care of the details of clearing - * the slots and preserving the termios structure. + * the slots and preserving the termios structure. The tty_unlock_pair + * should be safe as we keep a kref while the tty is locked (so the + * unlock never unlocks a freed tty). */ + mutex_lock(&tty_mutex); release_tty(tty, idx); + mutex_unlock(&tty_mutex); /* Make this pty number available for reallocation */ if (devpts) devpts_kill_index(inode, idx); - tty_unlock(); return 0; } @@ -1893,6 +1907,9 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp, * Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev. * tty->count should protect the rest. * ->siglock protects ->signal/->sighand + * + * Note: the tty_unlock/lock cases without a ref are only safe due to + * tty_mutex */ static int tty_open(struct inode *inode, struct file *filp) @@ -1916,8 +1933,7 @@ retry_open: retval = 0; mutex_lock(&tty_mutex); - tty_lock(); - + /* This is protected by the tty_mutex */ tty = tty_open_current_tty(device, filp); if (IS_ERR(tty)) { retval = PTR_ERR(tty); @@ -1938,17 +1954,19 @@ retry_open: } if (tty) { + tty_lock(tty); retval = tty_reopen(tty); - if (retval) + if (retval < 0) { + tty_unlock(tty); tty = ERR_PTR(retval); - } else + } + } else /* Returns with the tty_lock held for now */ tty = tty_init_dev(driver, index); mutex_unlock(&tty_mutex); if (driver) tty_driver_kref_put(driver); if (IS_ERR(tty)) { - tty_unlock(); retval = PTR_ERR(tty); goto err_file; } @@ -1977,7 +1995,7 @@ retry_open: printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__, retval, tty->name); #endif - tty_unlock(); /* need to call tty_release without BTM */ + tty_unlock(tty); /* need to call tty_release without BTM */ tty_release(inode, filp); if (retval != -ERESTARTSYS) return retval; @@ -1989,17 +2007,15 @@ retry_open: /* * Need to reset f_op in case a hangup happened. */ - tty_lock(); if (filp->f_op == &hung_up_tty_fops) filp->f_op = &tty_fops; - tty_unlock(); goto retry_open; } - tty_unlock(); + tty_unlock(tty); mutex_lock(&tty_mutex); - tty_lock(); + tty_lock(tty); spin_lock_irq(¤t->sighand->siglock); if (!noctty && current->signal->leader && @@ -2007,11 +2023,10 @@ retry_open: tty->session == NULL) __proc_set_tty(current, tty); spin_unlock_irq(¤t->sighand->siglock); - tty_unlock(); + tty_unlock(tty); mutex_unlock(&tty_mutex); return 0; err_unlock: - tty_unlock(); mutex_unlock(&tty_mutex); /* after locks to avoid deadlock */ if (!IS_ERR_OR_NULL(driver)) @@ -2094,10 +2109,13 @@ out: static int tty_fasync(int fd, struct file *filp, int on) { + struct tty_struct *tty = file_tty(filp); int retval; - tty_lock(); + + tty_lock(tty); retval = __tty_fasync(fd, filp, on); - tty_unlock(); + tty_unlock(tty); + return retval; } @@ -2756,7 +2774,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (ld->ops->ioctl) { retval = ld->ops->ioctl(tty, file, cmd, arg); if (retval == -ENOIOCTLCMD) - retval = -EINVAL; + retval = -ENOTTY; } tty_ldisc_deref(ld); return retval; @@ -2934,6 +2952,7 @@ void initialize_tty_struct(struct tty_struct *tty, tty->pgrp = NULL; tty->overrun_time = jiffies; tty_buffer_init(tty); + mutex_init(&tty->legacy_mutex); mutex_init(&tty->termios_mutex); mutex_init(&tty->ldisc_mutex); init_waitqueue_head(&tty->write_wait); @@ -2991,6 +3010,15 @@ EXPORT_SYMBOL_GPL(tty_put_char); struct class *tty_class; +static int tty_cdev_add(struct tty_driver *driver, dev_t dev, + unsigned int index, unsigned int count) +{ + /* init here, since reused cdevs cause crashes */ + cdev_init(&driver->cdevs[index], &tty_fops); + driver->cdevs[index].owner = driver->owner; + return cdev_add(&driver->cdevs[index], dev, count); +} + /** * tty_register_device - register a tty device * @driver: the tty driver that describes the tty device @@ -3013,8 +3041,46 @@ struct class *tty_class; struct device *tty_register_device(struct tty_driver *driver, unsigned index, struct device *device) { + return tty_register_device_attr(driver, index, device, NULL, NULL); +} +EXPORT_SYMBOL(tty_register_device); + +static void tty_device_create_release(struct device *dev) +{ + pr_debug("device: '%s': %s\n", dev_name(dev), __func__); + kfree(dev); +} + +/** + * tty_register_device_attr - register a tty device + * @driver: the tty driver that describes the tty device + * @index: the index in the tty driver for this tty device + * @device: a struct device that is associated with this tty device. + * This field is optional, if there is no known struct device + * for this tty device it can be set to NULL safely. + * @drvdata: Driver data to be set to device. + * @attr_grp: Attribute group to be set on device. + * + * Returns a pointer to the struct device for this tty device + * (or ERR_PTR(-EFOO) on error). + * + * This call is required to be made to register an individual tty device + * if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set. If + * that bit is not set, this function should not be called by a tty + * driver. + * + * Locking: ?? + */ +struct device *tty_register_device_attr(struct tty_driver *driver, + unsigned index, struct device *device, + void *drvdata, + const struct attribute_group **attr_grp) +{ char name[64]; - dev_t dev = MKDEV(driver->major, driver->minor_start) + index; + dev_t devt = MKDEV(driver->major, driver->minor_start) + index; + struct device *dev = NULL; + int retval = -ENODEV; + bool cdev = false; if (index >= driver->num) { printk(KERN_ERR "Attempt to register invalid tty line number " @@ -3027,9 +3093,40 @@ struct device *tty_register_device(struct tty_driver *driver, unsigned index, else tty_line_name(driver, index, name); - return device_create(tty_class, device, dev, NULL, name); + if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) { + retval = tty_cdev_add(driver, devt, index, 1); + if (retval) + goto error; + cdev = true; + } + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + retval = -ENOMEM; + goto error; + } + + dev->devt = devt; + dev->class = tty_class; + dev->parent = device; + dev->release = tty_device_create_release; + dev_set_name(dev, "%s", name); + dev->groups = attr_grp; + dev_set_drvdata(dev, drvdata); + + retval = device_register(dev); + if (retval) + goto error; + + return dev; + +error: + put_device(dev); + if (cdev) + cdev_del(&driver->cdevs[index]); + return ERR_PTR(retval); } -EXPORT_SYMBOL(tty_register_device); +EXPORT_SYMBOL_GPL(tty_register_device_attr); /** * tty_unregister_device - unregister a tty device @@ -3046,31 +3143,82 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index) { device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); + if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) + cdev_del(&driver->cdevs[index]); } EXPORT_SYMBOL(tty_unregister_device); -struct tty_driver *__alloc_tty_driver(int lines, struct module *owner) +/** + * __tty_alloc_driver -- allocate tty driver + * @lines: count of lines this driver can handle at most + * @owner: module which is repsonsible for this driver + * @flags: some of TTY_DRIVER_* flags, will be set in driver->flags + * + * This should not be called directly, some of the provided macros should be + * used instead. Use IS_ERR and friends on @retval. + */ +struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner, + unsigned long flags) { struct tty_driver *driver; + unsigned int cdevs = 1; + int err; + + if (!lines || (flags & TTY_DRIVER_UNNUMBERED_NODE && lines > 1)) + return ERR_PTR(-EINVAL); driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL); - if (driver) { - kref_init(&driver->kref); - driver->magic = TTY_DRIVER_MAGIC; - driver->num = lines; - driver->owner = owner; - /* later we'll move allocation of tables here */ + if (!driver) + return ERR_PTR(-ENOMEM); + + kref_init(&driver->kref); + driver->magic = TTY_DRIVER_MAGIC; + driver->num = lines; + driver->owner = owner; + driver->flags = flags; + + if (!(flags & TTY_DRIVER_DEVPTS_MEM)) { + driver->ttys = kcalloc(lines, sizeof(*driver->ttys), + GFP_KERNEL); + driver->termios = kcalloc(lines, sizeof(*driver->termios), + GFP_KERNEL); + if (!driver->ttys || !driver->termios) { + err = -ENOMEM; + goto err_free_all; + } } + + if (!(flags & TTY_DRIVER_DYNAMIC_ALLOC)) { + driver->ports = kcalloc(lines, sizeof(*driver->ports), + GFP_KERNEL); + if (!driver->ports) { + err = -ENOMEM; + goto err_free_all; + } + cdevs = lines; + } + + driver->cdevs = kcalloc(cdevs, sizeof(*driver->cdevs), GFP_KERNEL); + if (!driver->cdevs) { + err = -ENOMEM; + goto err_free_all; + } + return driver; +err_free_all: + kfree(driver->ports); + kfree(driver->ttys); + kfree(driver->termios); + kfree(driver); + return ERR_PTR(err); } -EXPORT_SYMBOL(__alloc_tty_driver); +EXPORT_SYMBOL(__tty_alloc_driver); static void destruct_tty_driver(struct kref *kref) { struct tty_driver *driver = container_of(kref, struct tty_driver, kref); int i; struct ktermios *tp; - void *p; if (driver->flags & TTY_DRIVER_INSTALLED) { /* @@ -3087,13 +3235,14 @@ static void destruct_tty_driver(struct kref *kref) if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) tty_unregister_device(driver, i); } - p = driver->ttys; proc_tty_unregister_driver(driver); - driver->ttys = NULL; - driver->termios = NULL; - kfree(p); - cdev_del(&driver->cdev); + if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC) + cdev_del(&driver->cdevs[0]); } + kfree(driver->cdevs); + kfree(driver->ports); + kfree(driver->termios); + kfree(driver->ttys); kfree(driver); } @@ -3124,15 +3273,8 @@ int tty_register_driver(struct tty_driver *driver) int error; 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); - if (!p) - return -ENOMEM; - } - if (!driver->major) { error = alloc_chrdev_region(&dev, driver->minor_start, driver->num, driver->name); @@ -3144,28 +3286,13 @@ int tty_register_driver(struct tty_driver *driver) dev = MKDEV(driver->major, driver->minor_start); error = register_chrdev_region(dev, driver->num, driver->name); } - if (error < 0) { - kfree(p); - return error; - } + if (error < 0) + goto err; - if (p) { - driver->ttys = (struct tty_struct **)p; - driver->termios = (struct ktermios **)(p + driver->num); - } else { - driver->ttys = NULL; - driver->termios = NULL; - } - - cdev_init(&driver->cdev, &tty_fops); - driver->cdev.owner = driver->owner; - error = cdev_add(&driver->cdev, dev, driver->num); - if (error) { - unregister_chrdev_region(dev, driver->num); - driver->ttys = NULL; - driver->termios = NULL; - kfree(p); - return error; + if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC) { + error = tty_cdev_add(driver, dev, 0, driver->num); + if (error) + goto err_unreg_char; } mutex_lock(&tty_mutex); @@ -3177,7 +3304,7 @@ int tty_register_driver(struct tty_driver *driver) d = tty_register_device(driver, i, NULL); if (IS_ERR(d)) { error = PTR_ERR(d); - goto err; + goto err_unreg_devs; } } } @@ -3185,7 +3312,7 @@ int tty_register_driver(struct tty_driver *driver) driver->flags |= TTY_DRIVER_INSTALLED; return 0; -err: +err_unreg_devs: for (i--; i >= 0; i--) tty_unregister_device(driver, i); @@ -3193,13 +3320,11 @@ err: list_del(&driver->tty_drivers); mutex_unlock(&tty_mutex); +err_unreg_char: unregister_chrdev_region(dev, driver->num); - driver->ttys = NULL; - driver->termios = NULL; - kfree(p); +err: return error; } - EXPORT_SYMBOL(tty_register_driver); /* diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index a1b9a2f68567..12b1fa0f4f86 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -410,7 +410,7 @@ EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate); void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud) { - tty_termios_encode_baud_rate(tty->termios, ibaud, obaud); + tty_termios_encode_baud_rate(&tty->termios, ibaud, obaud); } EXPORT_SYMBOL_GPL(tty_encode_baud_rate); @@ -427,7 +427,7 @@ EXPORT_SYMBOL_GPL(tty_encode_baud_rate); speed_t tty_get_baud_rate(struct tty_struct *tty) { - speed_t baud = tty_termios_baud_rate(tty->termios); + speed_t baud = tty_termios_baud_rate(&tty->termios); if (baud == 38400 && tty->alt_speed) { if (!tty->warned) { @@ -509,14 +509,14 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios) /* FIXME: we need to decide on some locking/ordering semantics for the set_termios notification eventually */ mutex_lock(&tty->termios_mutex); - old_termios = *tty->termios; - *tty->termios = *new_termios; - unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); + old_termios = tty->termios; + tty->termios = *new_termios; + unset_locked_termios(&tty->termios, &old_termios, &tty->termios_locked); /* See if packet mode change of state. */ if (tty->link && tty->link->packet) { int extproc = (old_termios.c_lflag & EXTPROC) | - (tty->termios->c_lflag & EXTPROC); + (tty->termios.c_lflag & EXTPROC); int old_flow = ((old_termios.c_iflag & IXON) && (old_termios.c_cc[VSTOP] == '\023') && (old_termios.c_cc[VSTART] == '\021')); @@ -542,7 +542,7 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios) if (tty->ops->set_termios) (*tty->ops->set_termios)(tty, &old_termios); else - tty_termios_copy_hw(tty->termios, &old_termios); + tty_termios_copy_hw(&tty->termios, &old_termios); ld = tty_ldisc_ref(tty); if (ld != NULL) { @@ -578,7 +578,7 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt) return retval; mutex_lock(&tty->termios_mutex); - memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios)); + tmp_termios = tty->termios; mutex_unlock(&tty->termios_mutex); if (opt & TERMIOS_TERMIO) { @@ -632,14 +632,14 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt) static void copy_termios(struct tty_struct *tty, struct ktermios *kterm) { mutex_lock(&tty->termios_mutex); - memcpy(kterm, tty->termios, sizeof(struct ktermios)); + *kterm = tty->termios; mutex_unlock(&tty->termios_mutex); } static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm) { mutex_lock(&tty->termios_mutex); - memcpy(kterm, tty->termios_locked, sizeof(struct ktermios)); + *kterm = tty->termios_locked; mutex_unlock(&tty->termios_mutex); } @@ -707,16 +707,16 @@ static int get_sgflags(struct tty_struct *tty) { int flags = 0; - if (!(tty->termios->c_lflag & ICANON)) { - if (tty->termios->c_lflag & ISIG) + if (!(tty->termios.c_lflag & ICANON)) { + if (tty->termios.c_lflag & ISIG) flags |= 0x02; /* cbreak */ else flags |= 0x20; /* raw */ } - if (tty->termios->c_lflag & ECHO) + if (tty->termios.c_lflag & ECHO) flags |= 0x08; /* echo */ - if (tty->termios->c_oflag & OPOST) - if (tty->termios->c_oflag & ONLCR) + if (tty->termios.c_oflag & OPOST) + if (tty->termios.c_oflag & ONLCR) flags |= 0x10; /* crmod */ return flags; } @@ -726,10 +726,10 @@ static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb) struct sgttyb tmp; mutex_lock(&tty->termios_mutex); - tmp.sg_ispeed = tty->termios->c_ispeed; - tmp.sg_ospeed = tty->termios->c_ospeed; - tmp.sg_erase = tty->termios->c_cc[VERASE]; - tmp.sg_kill = tty->termios->c_cc[VKILL]; + tmp.sg_ispeed = tty->termios.c_ispeed; + tmp.sg_ospeed = tty->termios.c_ospeed; + tmp.sg_erase = tty->termios.c_cc[VERASE]; + tmp.sg_kill = tty->termios.c_cc[VKILL]; tmp.sg_flags = get_sgflags(tty); mutex_unlock(&tty->termios_mutex); @@ -787,7 +787,7 @@ static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb) return -EFAULT; mutex_lock(&tty->termios_mutex); - termios = *tty->termios; + termios = tty->termios; termios.c_cc[VERASE] = tmp.sg_erase; termios.c_cc[VKILL] = tmp.sg_kill; set_sgflags(&termios, tmp.sg_flags); @@ -808,12 +808,12 @@ static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars) struct tchars tmp; mutex_lock(&tty->termios_mutex); - tmp.t_intrc = tty->termios->c_cc[VINTR]; - tmp.t_quitc = tty->termios->c_cc[VQUIT]; - tmp.t_startc = tty->termios->c_cc[VSTART]; - tmp.t_stopc = tty->termios->c_cc[VSTOP]; - tmp.t_eofc = tty->termios->c_cc[VEOF]; - tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */ + tmp.t_intrc = tty->termios.c_cc[VINTR]; + tmp.t_quitc = tty->termios.c_cc[VQUIT]; + tmp.t_startc = tty->termios.c_cc[VSTART]; + tmp.t_stopc = tty->termios.c_cc[VSTOP]; + tmp.t_eofc = tty->termios.c_cc[VEOF]; + tmp.t_brkc = tty->termios.c_cc[VEOL2]; /* what is brkc anyway? */ mutex_unlock(&tty->termios_mutex); return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0; } @@ -825,12 +825,12 @@ static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars) if (copy_from_user(&tmp, tchars, sizeof(tmp))) return -EFAULT; mutex_lock(&tty->termios_mutex); - tty->termios->c_cc[VINTR] = tmp.t_intrc; - tty->termios->c_cc[VQUIT] = tmp.t_quitc; - tty->termios->c_cc[VSTART] = tmp.t_startc; - tty->termios->c_cc[VSTOP] = tmp.t_stopc; - tty->termios->c_cc[VEOF] = tmp.t_eofc; - tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */ + tty->termios.c_cc[VINTR] = tmp.t_intrc; + tty->termios.c_cc[VQUIT] = tmp.t_quitc; + tty->termios.c_cc[VSTART] = tmp.t_startc; + tty->termios.c_cc[VSTOP] = tmp.t_stopc; + tty->termios.c_cc[VEOF] = tmp.t_eofc; + tty->termios.c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */ mutex_unlock(&tty->termios_mutex); return 0; } @@ -842,14 +842,14 @@ static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars) struct ltchars tmp; mutex_lock(&tty->termios_mutex); - tmp.t_suspc = tty->termios->c_cc[VSUSP]; + tmp.t_suspc = tty->termios.c_cc[VSUSP]; /* what is dsuspc anyway? */ - tmp.t_dsuspc = tty->termios->c_cc[VSUSP]; - tmp.t_rprntc = tty->termios->c_cc[VREPRINT]; + tmp.t_dsuspc = tty->termios.c_cc[VSUSP]; + tmp.t_rprntc = tty->termios.c_cc[VREPRINT]; /* what is flushc anyway? */ - tmp.t_flushc = tty->termios->c_cc[VEOL2]; - tmp.t_werasc = tty->termios->c_cc[VWERASE]; - tmp.t_lnextc = tty->termios->c_cc[VLNEXT]; + tmp.t_flushc = tty->termios.c_cc[VEOL2]; + tmp.t_werasc = tty->termios.c_cc[VWERASE]; + tmp.t_lnextc = tty->termios.c_cc[VLNEXT]; mutex_unlock(&tty->termios_mutex); return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0; } @@ -862,14 +862,14 @@ static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars) return -EFAULT; mutex_lock(&tty->termios_mutex); - tty->termios->c_cc[VSUSP] = tmp.t_suspc; + tty->termios.c_cc[VSUSP] = tmp.t_suspc; /* what is dsuspc anyway? */ - tty->termios->c_cc[VEOL2] = tmp.t_dsuspc; - tty->termios->c_cc[VREPRINT] = tmp.t_rprntc; + tty->termios.c_cc[VEOL2] = tmp.t_dsuspc; + tty->termios.c_cc[VREPRINT] = tmp.t_rprntc; /* what is flushc anyway? */ - tty->termios->c_cc[VEOL2] = tmp.t_flushc; - tty->termios->c_cc[VWERASE] = tmp.t_werasc; - tty->termios->c_cc[VLNEXT] = tmp.t_lnextc; + tty->termios.c_cc[VEOL2] = tmp.t_flushc; + tty->termios.c_cc[VWERASE] = tmp.t_werasc; + tty->termios.c_cc[VLNEXT] = tmp.t_lnextc; mutex_unlock(&tty->termios_mutex); return 0; } @@ -920,12 +920,12 @@ static int tty_change_softcar(struct tty_struct *tty, int arg) struct ktermios old; mutex_lock(&tty->termios_mutex); - old = *tty->termios; - tty->termios->c_cflag &= ~CLOCAL; - tty->termios->c_cflag |= bit; + old = tty->termios; + tty->termios.c_cflag &= ~CLOCAL; + tty->termios.c_cflag |= bit; if (tty->ops->set_termios) tty->ops->set_termios(tty, &old); - if ((tty->termios->c_cflag & CLOCAL) != bit) + if ((tty->termios.c_cflag & CLOCAL) != bit) ret = -EINVAL; mutex_unlock(&tty->termios_mutex); return ret; @@ -1031,7 +1031,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, (struct termios __user *) arg)) return -EFAULT; mutex_lock(&real_tty->termios_mutex); - memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios)); + real_tty->termios_locked = kterm; mutex_unlock(&real_tty->termios_mutex); return 0; #else @@ -1048,7 +1048,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, (struct termios __user *) arg)) return -EFAULT; mutex_lock(&real_tty->termios_mutex); - memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios)); + real_tty->termios_locked = kterm; mutex_unlock(&real_tty->termios_mutex); return ret; #endif diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 6f99c9959f0c..4d7b56268c79 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -413,7 +413,7 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush); static void tty_set_termios_ldisc(struct tty_struct *tty, int num) { mutex_lock(&tty->termios_mutex); - tty->termios->c_line = num; + tty->termios.c_line = num; mutex_unlock(&tty->termios_mutex); } @@ -568,7 +568,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) if (IS_ERR(new_ldisc)) return PTR_ERR(new_ldisc); - tty_lock(); + tty_lock(tty); /* * We need to look at the tty locking here for pty/tty pairs * when both sides try to change in parallel. @@ -582,12 +582,12 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) */ if (tty->ldisc->ops->num == ldisc) { - tty_unlock(); + tty_unlock(tty); tty_ldisc_put(new_ldisc); return 0; } - tty_unlock(); + tty_unlock(tty); /* * Problem: What do we do if this blocks ? * We could deadlock here @@ -595,7 +595,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) tty_wait_until_sent(tty, 0); - tty_lock(); + tty_lock(tty); mutex_lock(&tty->ldisc_mutex); /* @@ -605,10 +605,10 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { mutex_unlock(&tty->ldisc_mutex); - tty_unlock(); + tty_unlock(tty); wait_event(tty_ldisc_wait, test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0); - tty_lock(); + tty_lock(tty); mutex_lock(&tty->ldisc_mutex); } @@ -623,7 +623,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) o_ldisc = tty->ldisc; - tty_unlock(); + tty_unlock(tty); /* * Make sure we don't change while someone holds a * reference to the line discipline. The TTY_LDISC bit @@ -650,7 +650,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) retval = tty_ldisc_wait_idle(tty, 5 * HZ); - tty_lock(); + tty_lock(tty); mutex_lock(&tty->ldisc_mutex); /* handle wait idle failure locked */ @@ -665,7 +665,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) clear_bit(TTY_LDISC_CHANGING, &tty->flags); mutex_unlock(&tty->ldisc_mutex); tty_ldisc_put(new_ldisc); - tty_unlock(); + tty_unlock(tty); return -EIO; } @@ -708,7 +708,7 @@ enable: if (o_work) schedule_work(&o_tty->buf.work); mutex_unlock(&tty->ldisc_mutex); - tty_unlock(); + tty_unlock(tty); return retval; } @@ -722,9 +722,9 @@ enable: static void tty_reset_termios(struct tty_struct *tty) { mutex_lock(&tty->termios_mutex); - *tty->termios = tty->driver->init_termios; - tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios); - tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios); + tty->termios = tty->driver->init_termios; + tty->termios.c_ispeed = tty_termios_input_baud_rate(&tty->termios); + tty->termios.c_ospeed = tty_termios_baud_rate(&tty->termios); mutex_unlock(&tty->termios_mutex); } @@ -816,11 +816,11 @@ void tty_ldisc_hangup(struct tty_struct *tty) * need to wait for another function taking the BTM */ clear_bit(TTY_LDISC, &tty->flags); - tty_unlock(); + tty_unlock(tty); cancel_work_sync(&tty->buf.work); mutex_unlock(&tty->ldisc_mutex); retry: - tty_lock(); + tty_lock(tty); mutex_lock(&tty->ldisc_mutex); /* At this point we have a closed ldisc and we want to @@ -831,7 +831,7 @@ retry: if (atomic_read(&tty->ldisc->users) != 1) { char cur_n[TASK_COMM_LEN], tty_n[64]; long timeout = 3 * HZ; - tty_unlock(); + tty_unlock(tty); while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) { timeout = MAX_SCHEDULE_TIMEOUT; @@ -846,7 +846,7 @@ retry: if (reset == 0) { - if (!tty_ldisc_reinit(tty, tty->termios->c_line)) + if (!tty_ldisc_reinit(tty, tty->termios.c_line)) err = tty_ldisc_open(tty, tty->ldisc); else err = 1; @@ -894,6 +894,23 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) tty_ldisc_enable(tty); return 0; } + +static void tty_ldisc_kill(struct tty_struct *tty) +{ + mutex_lock(&tty->ldisc_mutex); + /* + * Now kill off the ldisc + */ + tty_ldisc_close(tty, tty->ldisc); + tty_ldisc_put(tty->ldisc); + /* Force an oops if we mess this up */ + tty->ldisc = NULL; + + /* Ensure the next open requests the N_TTY ldisc */ + tty_set_termios_ldisc(tty, N_TTY); + mutex_unlock(&tty->ldisc_mutex); +} + /** * tty_ldisc_release - release line discipline * @tty: tty being shut down @@ -912,28 +929,21 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) * race with the set_ldisc code path. */ - tty_unlock(); + tty_lock_pair(tty, o_tty); tty_ldisc_halt(tty); tty_ldisc_flush_works(tty); - tty_lock(); - - mutex_lock(&tty->ldisc_mutex); - /* - * Now kill off the ldisc - */ - tty_ldisc_close(tty, tty->ldisc); - tty_ldisc_put(tty->ldisc); - /* Force an oops if we mess this up */ - tty->ldisc = NULL; - - /* Ensure the next open requests the N_TTY ldisc */ - tty_set_termios_ldisc(tty, N_TTY); - mutex_unlock(&tty->ldisc_mutex); + if (o_tty) { + tty_ldisc_halt(o_tty); + tty_ldisc_flush_works(o_tty); + } /* This will need doing differently if we need to lock */ + tty_ldisc_kill(tty); + if (o_tty) - tty_ldisc_release(o_tty, NULL); + tty_ldisc_kill(o_tty); + tty_unlock_pair(tty, o_tty); /* And the memory resources remaining (buffers, termios) will be disposed of when the kref hits zero */ } diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c index 9ff986c32a21..67feac9e6ebb 100644 --- a/drivers/tty/tty_mutex.c +++ b/drivers/tty/tty_mutex.c @@ -4,29 +4,70 @@ #include <linux/semaphore.h> #include <linux/sched.h> -/* - * The 'big tty mutex' - * - * This mutex is taken and released by tty_lock() and tty_unlock(), - * replacing the older big kernel lock. - * It can no longer be taken recursively, and does not get - * released implicitly while sleeping. - * - * Don't use in new code. - */ -static DEFINE_MUTEX(big_tty_mutex); +/* Legacy tty mutex glue */ + +enum { + TTY_MUTEX_NORMAL, + TTY_MUTEX_NESTED, +}; /* * Getting the big tty mutex. */ -void __lockfunc tty_lock(void) + +static void __lockfunc tty_lock_nested(struct tty_struct *tty, + unsigned int subclass) { - mutex_lock(&big_tty_mutex); + if (tty->magic != TTY_MAGIC) { + printk(KERN_ERR "L Bad %p\n", tty); + WARN_ON(1); + return; + } + tty_kref_get(tty); + mutex_lock_nested(&tty->legacy_mutex, subclass); +} + +void __lockfunc tty_lock(struct tty_struct *tty) +{ + return tty_lock_nested(tty, TTY_MUTEX_NORMAL); } EXPORT_SYMBOL(tty_lock); -void __lockfunc tty_unlock(void) +void __lockfunc tty_unlock(struct tty_struct *tty) { - mutex_unlock(&big_tty_mutex); + if (tty->magic != TTY_MAGIC) { + printk(KERN_ERR "U Bad %p\n", tty); + WARN_ON(1); + return; + } + mutex_unlock(&tty->legacy_mutex); + tty_kref_put(tty); } EXPORT_SYMBOL(tty_unlock); + +/* + * Getting the big tty mutex for a pair of ttys with lock ordering + * On a non pty/tty pair tty2 can be NULL which is just fine. + */ +void __lockfunc tty_lock_pair(struct tty_struct *tty, + struct tty_struct *tty2) +{ + if (tty < tty2) { + tty_lock(tty); + tty_lock_nested(tty2, TTY_MUTEX_NESTED); + } else { + if (tty2 && tty2 != tty) + tty_lock(tty2); + tty_lock_nested(tty, TTY_MUTEX_NESTED); + } +} +EXPORT_SYMBOL(tty_lock_pair); + +void __lockfunc tty_unlock_pair(struct tty_struct *tty, + struct tty_struct *tty2) +{ + tty_unlock(tty); + if (tty2 && tty2 != tty) + tty_unlock(tty2); +} +EXPORT_SYMBOL(tty_unlock_pair); diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index bf6e238146ae..d7bdd8d0c23f 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -33,6 +33,70 @@ void tty_port_init(struct tty_port *port) } EXPORT_SYMBOL(tty_port_init); +/** + * tty_port_link_device - link tty and tty_port + * @port: tty_port of the device + * @driver: tty_driver for this device + * @index: index of the tty + * + * Provide the tty layer wit ha link from a tty (specified by @index) to a + * tty_port (@port). Use this only if neither tty_port_register_device nor + * tty_port_install is used in the driver. If used, this has to be called before + * tty_register_driver. + */ +void tty_port_link_device(struct tty_port *port, + struct tty_driver *driver, unsigned index) +{ + if (WARN_ON(index >= driver->num)) + return; + driver->ports[index] = port; +} +EXPORT_SYMBOL_GPL(tty_port_link_device); + +/** + * tty_port_register_device - register tty device + * @port: tty_port of the device + * @driver: tty_driver for this device + * @index: index of the tty + * @device: parent if exists, otherwise NULL + * + * It is the same as tty_register_device except the provided @port is linked to + * a concrete tty specified by @index. Use this or tty_port_install (or both). + * Call tty_port_link_device as a last resort. + */ +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); +} +EXPORT_SYMBOL_GPL(tty_port_register_device); + +/** + * tty_port_register_device_attr - register tty device + * @port: tty_port of the device + * @driver: tty_driver for this device + * @index: index of the tty + * @device: parent if exists, otherwise NULL + * @drvdata: Driver data to be set to device. + * @attr_grp: Attribute group to be set on device. + * + * It is the same as tty_register_device_attr except the provided @port is + * linked to a concrete tty specified by @index. Use this or tty_port_install + * (or both). Call tty_port_link_device as a last resort. + */ +struct device *tty_port_register_device_attr(struct tty_port *port, + struct tty_driver *driver, unsigned index, + struct device *device, void *drvdata, + const struct attribute_group **attr_grp) +{ + tty_port_link_device(port, driver, index); + return tty_register_device_attr(driver, index, device, drvdata, + attr_grp); +} +EXPORT_SYMBOL_GPL(tty_port_register_device_attr); + int tty_port_alloc_xmit_buf(struct tty_port *port) { /* We may sleep in get_zeroed_page() */ @@ -230,7 +294,7 @@ int tty_port_block_til_ready(struct tty_port *port, /* block if port is in the process of being closed */ if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { - wait_event_interruptible_tty(port->close_wait, + wait_event_interruptible_tty(tty, port->close_wait, !(port->flags & ASYNC_CLOSING)); if (port->flags & ASYNC_HUP_NOTIFY) return -EAGAIN; @@ -246,7 +310,7 @@ int tty_port_block_til_ready(struct tty_port *port, } if (filp->f_flags & O_NONBLOCK) { /* Indicate we are open */ - if (tty->termios->c_cflag & CBAUD) + if (tty->termios.c_cflag & CBAUD) tty_port_raise_dtr_rts(port); port->flags |= ASYNC_NORMAL_ACTIVE; return 0; @@ -270,7 +334,7 @@ int tty_port_block_til_ready(struct tty_port *port, while (1) { /* Indicate we are open */ - if (tty->termios->c_cflag & CBAUD) + if (tty->termios.c_cflag & CBAUD) tty_port_raise_dtr_rts(port); prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE); @@ -296,9 +360,9 @@ int tty_port_block_til_ready(struct tty_port *port, retval = -ERESTARTSYS; break; } - tty_unlock(); + tty_unlock(tty); schedule(); - tty_lock(); + tty_lock(tty); } finish_wait(&port->open_wait, &wait); @@ -369,7 +433,7 @@ int tty_port_close_start(struct tty_port *port, /* Drop DTR/RTS if HUPCL is set. This causes any attached modem to hang up the line */ - if (tty->termios->c_cflag & HUPCL) + if (tty->termios.c_cflag & HUPCL) tty_port_lower_dtr_rts(port); /* Don't call port->drop for the last reference. Callers will want @@ -413,6 +477,24 @@ void tty_port_close(struct tty_port *port, struct tty_struct *tty, } EXPORT_SYMBOL(tty_port_close); +/** + * tty_port_install - generic tty->ops->install handler + * @port: tty_port of the device + * @driver: tty_driver for this device + * @tty: tty to be installed + * + * It is the same as tty_standard_install except the provided @port is linked + * to a concrete tty specified by @tty. Use this or tty_port_register_device + * (or both). Call tty_port_link_device as a last resort. + */ +int tty_port_install(struct tty_port *port, struct tty_driver *driver, + struct tty_struct *tty) +{ + tty->port = port; + return tty_standard_install(driver, tty); +} +EXPORT_SYMBOL_GPL(tty_port_install); + int tty_port_open(struct tty_port *port, struct tty_struct *tty, struct file *filp) { diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 48cc6f25cfd3..681765baef69 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -119,6 +119,7 @@ static const int NR_TYPES = ARRAY_SIZE(max_vals); static struct input_handler kbd_handler; static DEFINE_SPINLOCK(kbd_event_lock); +static DEFINE_SPINLOCK(led_lock); static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */ static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ static bool dead_key_next; @@ -310,7 +311,7 @@ static void put_queue(struct vc_data *vc, int ch) if (tty) { tty_insert_flip_char(tty, ch, 0); - con_schedule_flip(tty); + tty_schedule_flip(tty); } } @@ -325,7 +326,7 @@ static void puts_queue(struct vc_data *vc, char *cp) tty_insert_flip_char(tty, *cp, 0); cp++; } - con_schedule_flip(tty); + tty_schedule_flip(tty); } static void applkey(struct vc_data *vc, int key, char mode) @@ -586,7 +587,7 @@ static void fn_send_intr(struct vc_data *vc) if (!tty) return; tty_insert_flip_char(tty, 0, TTY_BREAK); - con_schedule_flip(tty); + tty_schedule_flip(tty); } static void fn_scroll_forw(struct vc_data *vc) @@ -984,7 +985,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) * or (ii) whatever pattern of lights people want to show using KDSETLED, * or (iii) specified bits of specified words in kernel memory. */ -unsigned char getledstate(void) +static unsigned char getledstate(void) { return ledstate; } @@ -992,7 +993,7 @@ unsigned char getledstate(void) void setledstate(struct kbd_struct *kbd, unsigned int led) { unsigned long flags; - spin_lock_irqsave(&kbd_event_lock, flags); + spin_lock_irqsave(&led_lock, flags); if (!(led & ~7)) { ledioctl = led; kbd->ledmode = LED_SHOW_IOCTL; @@ -1000,7 +1001,7 @@ void setledstate(struct kbd_struct *kbd, unsigned int led) kbd->ledmode = LED_SHOW_FLAGS; set_leds(); - spin_unlock_irqrestore(&kbd_event_lock, flags); + spin_unlock_irqrestore(&led_lock, flags); } static inline unsigned char getleds(void) @@ -1049,13 +1050,13 @@ static int kbd_update_leds_helper(struct input_handle *handle, void *data) */ int vt_get_leds(int console, int flag) { - unsigned long flags; struct kbd_struct * kbd = kbd_table + console; int ret; + unsigned long flags; - spin_lock_irqsave(&kbd_event_lock, flags); + spin_lock_irqsave(&led_lock, flags); ret = vc_kbd_led(kbd, flag); - spin_unlock_irqrestore(&kbd_event_lock, flags); + spin_unlock_irqrestore(&led_lock, flags); return ret; } @@ -1091,11 +1092,11 @@ void vt_set_led_state(int console, int leds) void vt_kbd_con_start(int console) { struct kbd_struct * kbd = kbd_table + console; -/* unsigned long flags; */ -/* spin_lock_irqsave(&kbd_event_lock, flags); */ + unsigned long flags; + spin_lock_irqsave(&led_lock, flags); clr_vc_kbd_led(kbd, VC_SCROLLOCK); set_leds(); -/* spin_unlock_irqrestore(&kbd_event_lock, flags); */ + spin_unlock_irqrestore(&led_lock, flags); } /** @@ -1104,21 +1105,15 @@ void vt_kbd_con_start(int console) * * Handle console stop. This is a wrapper for the VT layer * so that we can keep kbd knowledge internal - * - * FIXME: We eventually need to hold the kbd lock here to protect - * the LED updating. We can't do it yet because fn_hold calls stop_tty - * and start_tty under the kbd_event_lock, while normal tty paths - * don't hold the lock. We probably need to split out an LED lock - * but not during an -rc release! */ void vt_kbd_con_stop(int console) { struct kbd_struct * kbd = kbd_table + console; -/* unsigned long flags; */ -/* spin_lock_irqsave(&kbd_event_lock, flags); */ + unsigned long flags; + spin_lock_irqsave(&led_lock, flags); set_vc_kbd_led(kbd, VC_SCROLLOCK); set_leds(); -/* spin_unlock_irqrestore(&kbd_event_lock, flags); */ + spin_unlock_irqrestore(&led_lock, flags); } /* @@ -1130,7 +1125,12 @@ void vt_kbd_con_stop(int console) */ static void kbd_bh(unsigned long dummy) { - unsigned char leds = getleds(); + unsigned char leds; + unsigned long flags; + + spin_lock_irqsave(&led_lock, flags); + leds = getleds(); + spin_unlock_irqrestore(&led_lock, flags); if (leds != ledstate) { input_handler_for_each_handle(&kbd_handler, &leds, @@ -2035,11 +2035,11 @@ int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm) return -EPERM; if (arg & ~0x77) return -EINVAL; - spin_lock_irqsave(&kbd_event_lock, flags); + spin_lock_irqsave(&led_lock, flags); kbd->ledflagstate = (arg & 7); kbd->default_ledflagstate = ((arg >> 4) & 7); set_leds(); - spin_unlock_irqrestore(&kbd_event_lock, flags); + spin_unlock_irqrestore(&led_lock, flags); return 0; /* the ioctls below only set the lights, not the functions */ @@ -2134,8 +2134,10 @@ void vt_reset_keyboard(int console) clr_vc_kbd_mode(kbd, VC_CRLF); kbd->lockstate = 0; kbd->slockstate = 0; + spin_lock(&led_lock); kbd->ledmode = LED_SHOW_FLAGS; kbd->ledflagstate = kbd->default_ledflagstate; + spin_unlock(&led_lock); /* do not do set_leds here because this causes an endless tasklet loop when the keyboard hasn't been initialized yet */ spin_unlock_irqrestore(&kbd_event_lock, flags); diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 84cbf298c094..999ca63afdef 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -537,45 +537,27 @@ void complement_pos(struct vc_data *vc, int offset) static void insert_char(struct vc_data *vc, unsigned int nr) { - unsigned short *p, *q = (unsigned short *)vc->vc_pos; + unsigned short *p = (unsigned short *) vc->vc_pos; - p = q + vc->vc_cols - nr - vc->vc_x; - while (--p >= q) - scr_writew(scr_readw(p), p + nr); - scr_memsetw(q, vc->vc_video_erase_char, nr * 2); + scr_memmovew(p + nr, p, vc->vc_cols - vc->vc_x); + scr_memsetw(p, vc->vc_video_erase_char, nr * 2); vc->vc_need_wrap = 0; - if (DO_UPDATE(vc)) { - unsigned short oldattr = vc->vc_attr; - vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x, vc->vc_y, vc->vc_x + nr, 1, - vc->vc_cols - vc->vc_x - nr); - vc->vc_attr = vc->vc_video_erase_char >> 8; - while (nr--) - vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, vc->vc_x + nr); - vc->vc_attr = oldattr; - } + if (DO_UPDATE(vc)) + do_update_region(vc, (unsigned long) p, + (vc->vc_cols - vc->vc_x) / 2 + 1); } static void delete_char(struct vc_data *vc, unsigned int nr) { - unsigned int i = vc->vc_x; - unsigned short *p = (unsigned short *)vc->vc_pos; + unsigned short *p = (unsigned short *) vc->vc_pos; - while (++i <= vc->vc_cols - nr) { - scr_writew(scr_readw(p+nr), p); - p++; - } - scr_memsetw(p, vc->vc_video_erase_char, nr * 2); + scr_memcpyw(p, p + nr, vc->vc_cols - vc->vc_x - nr); + scr_memsetw(p + vc->vc_cols - vc->vc_x - nr, vc->vc_video_erase_char, + nr * 2); vc->vc_need_wrap = 0; - if (DO_UPDATE(vc)) { - unsigned short oldattr = vc->vc_attr; - vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x + nr, vc->vc_y, vc->vc_x, 1, - vc->vc_cols - vc->vc_x - nr); - vc->vc_attr = vc->vc_video_erase_char >> 8; - while (nr--) - vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, - vc->vc_cols - 1 - nr); - vc->vc_attr = oldattr; - } + if (DO_UPDATE(vc)) + do_update_region(vc, (unsigned long) p, + (vc->vc_cols - vc->vc_x) / 2); } static int softcursor_original; @@ -1172,45 +1154,26 @@ static void csi_J(struct vc_data *vc, int vpar) case 0: /* erase from cursor to end of display */ count = (vc->vc_scr_end - vc->vc_pos) >> 1; start = (unsigned short *)vc->vc_pos; - if (DO_UPDATE(vc)) { - /* do in two stages */ - vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, - vc->vc_cols - vc->vc_x); - vc->vc_sw->con_clear(vc, vc->vc_y + 1, 0, - vc->vc_rows - vc->vc_y - 1, - vc->vc_cols); - } break; case 1: /* erase from start to cursor */ count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1; start = (unsigned short *)vc->vc_origin; - if (DO_UPDATE(vc)) { - /* do in two stages */ - vc->vc_sw->con_clear(vc, 0, 0, vc->vc_y, - vc->vc_cols); - vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1, - vc->vc_x + 1); - } break; case 3: /* erase scroll-back buffer (and whole display) */ scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char, vc->vc_screenbuf_size >> 1); set_origin(vc); - if (CON_IS_VISIBLE(vc)) - update_screen(vc); /* fall through */ case 2: /* erase whole display */ count = vc->vc_cols * vc->vc_rows; start = (unsigned short *)vc->vc_origin; - if (DO_UPDATE(vc)) - vc->vc_sw->con_clear(vc, 0, 0, - vc->vc_rows, - vc->vc_cols); break; default: return; } scr_memsetw(start, vc->vc_video_erase_char, 2 * count); + if (DO_UPDATE(vc)) + do_update_region(vc, (unsigned long) start, count); vc->vc_need_wrap = 0; } @@ -1223,29 +1186,22 @@ static void csi_K(struct vc_data *vc, int vpar) case 0: /* erase from cursor to end of line */ count = vc->vc_cols - vc->vc_x; start = (unsigned short *)vc->vc_pos; - if (DO_UPDATE(vc)) - vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, - vc->vc_cols - vc->vc_x); break; case 1: /* erase from start of line to cursor */ start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1)); count = vc->vc_x + 1; - if (DO_UPDATE(vc)) - vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1, - vc->vc_x + 1); break; case 2: /* erase whole line */ start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1)); count = vc->vc_cols; - if (DO_UPDATE(vc)) - vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1, - vc->vc_cols); break; default: return; } scr_memsetw(start, vc->vc_video_erase_char, 2 * count); vc->vc_need_wrap = 0; + if (DO_UPDATE(vc)) + do_update_region(vc, (unsigned long) start, count); } static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar positions */ @@ -1380,7 +1336,7 @@ static void respond_string(const char *p, struct tty_struct *tty) tty_insert_flip_char(tty, *p, 0); p++; } - con_schedule_flip(tty); + tty_schedule_flip(tty); } static void cursor_report(struct vc_data *vc, struct tty_struct *tty) @@ -2792,41 +2748,52 @@ static void con_flush_chars(struct tty_struct *tty) /* * Allocate the console screen memory. */ -static int con_open(struct tty_struct *tty, struct file *filp) +static int con_install(struct tty_driver *driver, struct tty_struct *tty) { unsigned int currcons = tty->index; - int ret = 0; + struct vc_data *vc; + int ret; console_lock(); - if (tty->driver_data == NULL) { - ret = vc_allocate(currcons); - if (ret == 0) { - struct vc_data *vc = vc_cons[currcons].d; + ret = vc_allocate(currcons); + if (ret) + goto unlock; - /* Still being freed */ - if (vc->port.tty) { - console_unlock(); - return -ERESTARTSYS; - } - tty->driver_data = vc; - vc->port.tty = tty; + vc = vc_cons[currcons].d; - if (!tty->winsize.ws_row && !tty->winsize.ws_col) { - tty->winsize.ws_row = vc_cons[currcons].d->vc_rows; - tty->winsize.ws_col = vc_cons[currcons].d->vc_cols; - } - if (vc->vc_utf) - tty->termios->c_iflag |= IUTF8; - else - tty->termios->c_iflag &= ~IUTF8; - console_unlock(); - return ret; - } + /* Still being freed */ + if (vc->port.tty) { + ret = -ERESTARTSYS; + goto unlock; } + + ret = tty_port_install(&vc->port, driver, tty); + if (ret) + goto unlock; + + tty->driver_data = vc; + vc->port.tty = tty; + + if (!tty->winsize.ws_row && !tty->winsize.ws_col) { + tty->winsize.ws_row = vc_cons[currcons].d->vc_rows; + tty->winsize.ws_col = vc_cons[currcons].d->vc_cols; + } + if (vc->vc_utf) + tty->termios.c_iflag |= IUTF8; + else + tty->termios.c_iflag &= ~IUTF8; +unlock: console_unlock(); return ret; } +static int con_open(struct tty_struct *tty, struct file *filp) +{ + /* everything done in install */ + return 0; +} + + static void con_close(struct tty_struct *tty, struct file *filp) { /* Nothing to do - we defer to shutdown */ @@ -2839,7 +2806,6 @@ static void con_shutdown(struct tty_struct *tty) console_lock(); vc->port.tty = NULL; console_unlock(); - tty_shutdown(tty); } static int default_italic_color = 2; // green (ASCII) @@ -2947,6 +2913,7 @@ static int __init con_init(void) console_initcall(con_init); static const struct tty_operations con_ops = { + .install = con_install, .open = con_open, .close = con_close, .write = con_write, diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index f763ed7ba91e..ff7b5a8d501c 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -826,7 +826,7 @@ static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old) { struct acm *acm = tty->driver_data; - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; struct usb_cdc_line_coding newline; int newctrl = acm->ctrlout; @@ -1299,7 +1299,8 @@ skip_countries: usb_set_intfdata(data_interface, acm); usb_get_intf(control_interface); - tty_register_device(acm_tty_driver, minor, &control_interface->dev); + tty_port_register_device(&acm->port, acm_tty_driver, minor, + &control_interface->dev); return 0; alloc_fail7: diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index da6d479ff9a6..f1739526820f 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -1133,7 +1133,8 @@ int gserial_setup(struct usb_gadget *g, unsigned count) for (i = 0; i < count; i++) { struct device *tty_dev; - tty_dev = tty_register_device(gs_tty_driver, i, &g->dev); + tty_dev = tty_port_register_device(&ports[i].port->port, + gs_tty_driver, i, &g->dev); if (IS_ERR(tty_dev)) pr_warning("%s: no classdev for port %d, err %ld\n", __func__, i, PTR_ERR(tty_dev)); diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index f8ce97d8b0ad..3b98fb733362 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -215,7 +215,7 @@ static void ark3116_release(struct usb_serial *serial) static void ark3116_init_termios(struct tty_struct *tty) { - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; *termios = tty_std_termios; termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; @@ -229,7 +229,7 @@ static void ark3116_set_termios(struct tty_struct *tty, { struct usb_serial *serial = port->serial; struct ark3116_private *priv = usb_get_serial_port_data(port); - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; unsigned int cflag = termios->c_cflag; int bps = tty_get_baud_rate(tty); int quot; diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index 6b7365632951..a46df73ee96e 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -307,7 +307,7 @@ static void belkin_sa_set_termios(struct tty_struct *tty, unsigned long control_state; int bad_flow_control; speed_t baud; - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; iflag = termios->c_iflag; cflag = termios->c_cflag; diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index b9cca6dcde07..9a564286bfd7 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -165,8 +165,8 @@ static int usb_console_setup(struct console *co, char *options) } if (serial->type->set_termios) { - tty->termios->c_cflag = cflag; - tty_termios_encode_baud_rate(tty->termios, baud, baud); + tty->termios.c_cflag = cflag; + tty_termios_encode_baud_rate(&tty->termios, baud, baud); memset(&dummy, 0, sizeof(struct ktermios)); serial->type->set_termios(tty, port, &dummy); diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 1e71079ce33b..ba5e07e188a0 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -469,7 +469,7 @@ static void cp210x_get_termios(struct tty_struct *tty, if (tty) { cp210x_get_termios_port(tty->driver_data, - &tty->termios->c_cflag, &baud); + &tty->termios.c_cflag, &baud); tty_encode_baud_rate(tty, baud, baud); } @@ -631,7 +631,7 @@ static void cp210x_change_speed(struct tty_struct *tty, { u32 baud; - baud = tty->termios->c_ospeed; + baud = tty->termios.c_ospeed; /* This maps the requested rate to a rate valid on cp2102 or cp2103, * or to an arbitrary rate in [1M,2M]. @@ -665,10 +665,10 @@ static void cp210x_set_termios(struct tty_struct *tty, if (!tty) return; - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; old_cflag = old_termios->c_cflag; - if (tty->termios->c_ospeed != old_termios->c_ospeed) + if (tty->termios.c_ospeed != old_termios->c_ospeed) cp210x_change_speed(tty, port, old_termios); /* If the number of data bits is to be updated */ diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index b78c34eb5d3f..be34f153e566 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -922,38 +922,38 @@ static void cypress_set_termios(struct tty_struct *tty, early enough */ if (!priv->termios_initialized) { if (priv->chiptype == CT_EARTHMATE) { - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = B4800 | CS8 | CREAD | HUPCL | + tty->termios = tty_std_termios; + tty->termios.c_cflag = B4800 | CS8 | CREAD | HUPCL | CLOCAL; - tty->termios->c_ispeed = 4800; - tty->termios->c_ospeed = 4800; + tty->termios.c_ispeed = 4800; + tty->termios.c_ospeed = 4800; } else if (priv->chiptype == CT_CYPHIDCOM) { - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | + tty->termios = tty_std_termios; + tty->termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - tty->termios->c_ispeed = 9600; - tty->termios->c_ospeed = 9600; + tty->termios.c_ispeed = 9600; + tty->termios.c_ospeed = 9600; } else if (priv->chiptype == CT_CA42V2) { - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | + tty->termios = tty_std_termios; + tty->termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - tty->termios->c_ispeed = 9600; - tty->termios->c_ospeed = 9600; + tty->termios.c_ispeed = 9600; + tty->termios.c_ospeed = 9600; } priv->termios_initialized = 1; } spin_unlock_irqrestore(&priv->lock, flags); /* Unsupported features need clearing */ - tty->termios->c_cflag &= ~(CMSPAR|CRTSCTS); + tty->termios.c_cflag &= ~(CMSPAR|CRTSCTS); - cflag = tty->termios->c_cflag; - iflag = tty->termios->c_iflag; + cflag = tty->termios.c_cflag; + iflag = tty->termios.c_iflag; /* check if there are new settings */ if (old_termios) { spin_lock_irqsave(&priv->lock, flags); - priv->tmp_termios = *(tty->termios); + priv->tmp_termios = tty->termios; spin_unlock_irqrestore(&priv->lock, flags); } @@ -1021,7 +1021,7 @@ static void cypress_set_termios(struct tty_struct *tty, "4800bps."); /* define custom termios settings for NMEA protocol */ - tty->termios->c_iflag /* input modes - */ + tty->termios.c_iflag /* input modes - */ &= ~(IGNBRK /* disable ignore break */ | BRKINT /* disable break causes interrupt */ | PARMRK /* disable mark parity errors */ @@ -1031,10 +1031,10 @@ static void cypress_set_termios(struct tty_struct *tty, | ICRNL /* disable translate CR to NL */ | IXON); /* disable enable XON/XOFF flow control */ - tty->termios->c_oflag /* output modes */ + tty->termios.c_oflag /* output modes */ &= ~OPOST; /* disable postprocess output char */ - tty->termios->c_lflag /* line discipline modes */ + tty->termios.c_lflag /* line discipline modes */ &= ~(ECHO /* disable echo input characters */ | ECHONL /* disable echo new line */ | ICANON /* disable erase, kill, werase, and rprnt @@ -1200,7 +1200,7 @@ static void cypress_read_int_callback(struct urb *urb) /* hangup, as defined in acm.c... this might be a bad place for it * though */ - if (tty && !(tty->termios->c_cflag & CLOCAL) && + if (tty && !(tty->termios.c_cflag & CLOCAL) && !(priv->current_status & UART_CD)) { dbg("%s - calling hangup", __func__); tty_hangup(tty); diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index b5cd838093ef..afd9d2ec577b 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -687,8 +687,8 @@ static void digi_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { struct digi_port *priv = usb_get_serial_port_data(port); - unsigned int iflag = tty->termios->c_iflag; - unsigned int cflag = tty->termios->c_cflag; + unsigned int iflag = tty->termios.c_iflag; + unsigned int cflag = tty->termios.c_cflag; unsigned int old_iflag = old_termios->c_iflag; unsigned int old_cflag = old_termios->c_cflag; unsigned char buf[32]; @@ -709,7 +709,7 @@ static void digi_set_termios(struct tty_struct *tty, /* don't set RTS if using hardware flow control */ /* and throttling input */ modem_signals = TIOCM_DTR; - if (!(tty->termios->c_cflag & CRTSCTS) || + if (!(tty->termios.c_cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) modem_signals |= TIOCM_RTS; digi_set_modem_signals(port, modem_signals, 1); @@ -748,7 +748,7 @@ static void digi_set_termios(struct tty_struct *tty, } } /* set parity */ - tty->termios->c_cflag &= ~CMSPAR; + tty->termios.c_cflag &= ~CMSPAR; if ((cflag&(PARENB|PARODD)) != (old_cflag&(PARENB|PARODD))) { if (cflag&PARENB) { @@ -1124,8 +1124,8 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port) /* set termios settings */ if (tty) { - not_termios.c_cflag = ~tty->termios->c_cflag; - not_termios.c_iflag = ~tty->termios->c_iflag; + not_termios.c_cflag = ~tty->termios.c_cflag; + not_termios.c_iflag = ~tty->termios.c_iflag; digi_set_termios(tty, port, ¬_termios); } return 0; @@ -1500,7 +1500,7 @@ static int digi_read_oob_callback(struct urb *urb) rts = 0; if (tty) - rts = tty->termios->c_cflag & CRTSCTS; + rts = tty->termios.c_cflag & CRTSCTS; if (tty && opcode == DIGI_CMD_READ_INPUT_SIGNALS) { spin_lock(&priv->dp_port_lock); diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index cdf61dd07318..34e86383090a 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -87,7 +87,7 @@ static int empeg_startup(struct usb_serial *serial) static void empeg_init_termios(struct tty_struct *tty) { - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; /* * The empeg-car player wants these particular tty settings. diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index 499b15fd82f1..79451ee12ca0 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -173,10 +173,11 @@ static void f81232_set_termios(struct tty_struct *tty, /* FIXME - Stubbed out for now */ /* Don't change anything if nothing has changed */ - if (!tty_termios_hw_change(tty->termios, old_termios)) + if (!tty_termios_hw_change(&tty->termios, old_termios)) return; /* Do the real work here... */ + tty_termios_copy_hw(&tty->termios, old_termios); } static int f81232_tiocmget(struct tty_struct *tty) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index f906b3aec217..0c8d1c226273 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -2102,7 +2102,7 @@ static void ftdi_set_termios(struct tty_struct *tty, { struct usb_device *dev = port->serial->dev; struct ftdi_private *priv = usb_get_serial_port_data(port); - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; unsigned int cflag = termios->c_cflag; __u16 urb_value; /* will hold the new flags */ diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index e1f5ccd1e8f8..f435575c4e6e 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -1458,7 +1458,7 @@ static void edge_throttle(struct tty_struct *tty) } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { edge_port->shadowMCR &= ~MCR_RTS; status = send_cmd_write_uart_register(edge_port, MCR, edge_port->shadowMCR); @@ -1497,7 +1497,7 @@ static void edge_unthrottle(struct tty_struct *tty) return; } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { edge_port->shadowMCR |= MCR_RTS; send_cmd_write_uart_register(edge_port, MCR, edge_port->shadowMCR); @@ -1516,9 +1516,9 @@ static void edge_set_termios(struct tty_struct *tty, struct edgeport_port *edge_port = usb_get_serial_port_data(port); unsigned int cflag; - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; dbg("%s - clfag %08x iflag %08x", __func__, - tty->termios->c_cflag, tty->termios->c_iflag); + tty->termios.c_cflag, tty->termios.c_iflag); dbg("%s - old clfag %08x old iflag %08x", __func__, old_termios->c_cflag, old_termios->c_iflag); @@ -1987,7 +1987,7 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, tty = tty_port_tty_get(&edge_port->port->port); if (tty) { change_port_settings(tty, - edge_port, tty->termios); + edge_port, &tty->termios); tty_kref_put(tty); } @@ -2570,7 +2570,7 @@ static void change_port_settings(struct tty_struct *tty, return; } - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; switch (cflag & CSIZE) { case CS5: diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 3936904c6419..765978ae752e 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -1870,7 +1870,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) /* set up the port settings */ if (tty) - edge_set_termios(tty, port, tty->termios); + edge_set_termios(tty, port, &tty->termios); /* open up the port */ @@ -2272,13 +2272,13 @@ static void change_port_settings(struct tty_struct *tty, config = kmalloc (sizeof (*config), GFP_KERNEL); if (!config) { - *tty->termios = *old_termios; + tty->termios = *old_termios; dev_err(&edge_port->port->dev, "%s - out of memory\n", __func__); return; } - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; config->wFlags = 0; @@ -2362,7 +2362,7 @@ static void change_port_settings(struct tty_struct *tty, } else dbg("%s - OUTBOUND XON/XOFF is disabled", __func__); - tty->termios->c_cflag &= ~CMSPAR; + tty->termios.c_cflag &= ~CMSPAR; /* Round the baud rate */ baud = tty_get_baud_rate(tty); @@ -2408,10 +2408,10 @@ static void edge_set_termios(struct tty_struct *tty, struct edgeport_port *edge_port = usb_get_serial_port_data(port); unsigned int cflag; - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; dbg("%s - clfag %08x iflag %08x", __func__, - tty->termios->c_cflag, tty->termios->c_iflag); + tty->termios.c_cflag, tty->termios.c_iflag); dbg("%s - old clfag %08x old iflag %08x", __func__, old_termios->c_cflag, old_termios->c_iflag); dbg("%s - port %d", __func__, port->number); diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index fc09414c960f..5a96692b12a2 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -381,7 +381,7 @@ static void ir_set_termios(struct tty_struct *tty, ir_xbof = ir_xbof_change(xbof) ; /* Only speed changes are supported */ - tty_termios_copy_hw(tty->termios, old_termios); + tty_termios_copy_hw(&tty->termios, old_termios); tty_encode_baud_rate(tty, baud, baud); /* diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index 22b1eb5040b7..bf3864045c18 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -921,7 +921,7 @@ static void iuu_set_termios(struct tty_struct *tty, { const u32 supported_mask = CMSPAR|PARENB|PARODD; struct iuu_private *priv = usb_get_serial_port_data(port); - unsigned int cflag = tty->termios->c_cflag; + unsigned int cflag = tty->termios.c_cflag; int status; u32 actual; u32 parity; @@ -930,7 +930,7 @@ static void iuu_set_termios(struct tty_struct *tty, u32 newval = cflag & supported_mask; /* Just use the ospeed. ispeed should be the same. */ - baud = tty->termios->c_ospeed; + baud = tty->termios.c_ospeed; dbg("%s - enter c_ospeed or baud=%d", __func__, baud); @@ -961,13 +961,13 @@ static void iuu_set_termios(struct tty_struct *tty, * settings back over and then adjust them */ if (old_termios) - tty_termios_copy_hw(tty->termios, old_termios); + tty_termios_copy_hw(&tty->termios, old_termios); if (status != 0) /* Set failed - return old bits */ return; /* Re-encode speed, parity and csize */ tty_encode_baud_rate(tty, baud, baud); - tty->termios->c_cflag &= ~(supported_mask|CSIZE); - tty->termios->c_cflag |= newval | csize; + tty->termios.c_cflag &= ~(supported_mask|CSIZE); + tty->termios.c_cflag |= newval | csize; } static void iuu_close(struct usb_serial_port *port) @@ -993,14 +993,14 @@ static void iuu_close(struct usb_serial_port *port) static void iuu_init_termios(struct tty_struct *tty) { - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600 + tty->termios = tty_std_termios; + tty->termios.c_cflag = CLOCAL | CREAD | CS8 | B9600 | TIOCM_CTS | CSTOPB | PARENB; - tty->termios->c_ispeed = 9600; - tty->termios->c_ospeed = 9600; - tty->termios->c_lflag = 0; - tty->termios->c_oflag = 0; - tty->termios->c_iflag = 0; + tty->termios.c_ispeed = 9600; + tty->termios.c_ospeed = 9600; + tty->termios.c_lflag = 0; + tty->termios.c_oflag = 0; + tty->termios.c_iflag = 0; } static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) @@ -1012,8 +1012,8 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) u32 actual; struct iuu_private *priv = usb_get_serial_port_data(port); - baud = tty->termios->c_ospeed; - tty->termios->c_ispeed = baud; + baud = tty->termios.c_ospeed; + tty->termios.c_ispeed = baud; /* Re-encode speed */ tty_encode_baud_rate(tty, baud, baud); diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index af0b70eaf032..7bcbb47e1449 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -158,7 +158,7 @@ static void keyspan_set_termios(struct tty_struct *tty, p_priv = usb_get_serial_port_data(port); d_details = p_priv->device_details; - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; device_port = port->number - port->serial->minor; /* Baud rate calculation takes baud rate as an integer @@ -179,7 +179,7 @@ static void keyspan_set_termios(struct tty_struct *tty, p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none; /* Mark/Space not supported */ - tty->termios->c_cflag &= ~CMSPAR; + tty->termios.c_cflag &= ~CMSPAR; keyspan_send_setup(port, 0); } @@ -1086,7 +1086,7 @@ static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port) device_port = port->number - port->serial->minor; if (tty) { - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; /* Baud rate calculation takes baud rate as an integer so other rates can be generated if desired. */ baud_rate = tty_get_baud_rate(tty); diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index a4ac3cfeffc4..dcada8615fcf 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -338,7 +338,7 @@ static void keyspan_pda_set_termios(struct tty_struct *tty, 7[EOMS]1: 10 bit, b0/b7 is parity 7[EOMS]2: 11 bit, b0/b7 is parity, extra bit always (mark?) - HW flow control is dictated by the tty->termios->c_cflags & CRTSCTS + HW flow control is dictated by the tty->termios.c_cflags & CRTSCTS bit. For now, just do baud. */ @@ -353,7 +353,7 @@ static void keyspan_pda_set_termios(struct tty_struct *tty, } /* Only speed can change so copy the old h/w parameters then encode the new speed */ - tty_termios_copy_hw(tty->termios, old_termios); + tty_termios_copy_hw(&tty->termios, old_termios); tty_encode_baud_rate(tty, speed, speed); } diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 5bed59cd5776..def9ad258715 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -311,12 +311,12 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) /* set up termios structure */ spin_lock_irqsave(&priv->lock, flags); - priv->termios.c_iflag = tty->termios->c_iflag; - priv->termios.c_oflag = tty->termios->c_oflag; - priv->termios.c_cflag = tty->termios->c_cflag; - priv->termios.c_lflag = tty->termios->c_lflag; + priv->termios.c_iflag = tty->termios.c_iflag; + priv->termios.c_oflag = tty->termios.c_oflag; + priv->termios.c_cflag = tty->termios.c_cflag; + priv->termios.c_lflag = tty->termios.c_lflag; for (i = 0; i < NCCS; i++) - priv->termios.c_cc[i] = tty->termios->c_cc[i]; + priv->termios.c_cc[i] = tty->termios.c_cc[i]; priv->cfg.pktlen = cfg->pktlen; priv->cfg.baudrate = cfg->baudrate; priv->cfg.databits = cfg->databits; @@ -445,9 +445,9 @@ static void klsi_105_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct klsi_105_private *priv = usb_get_serial_port_data(port); - unsigned int iflag = tty->termios->c_iflag; + unsigned int iflag = tty->termios.c_iflag; unsigned int old_iflag = old_termios->c_iflag; - unsigned int cflag = tty->termios->c_cflag; + unsigned int cflag = tty->termios.c_cflag; unsigned int old_cflag = old_termios->c_cflag; struct klsi_105_port_settings *cfg; unsigned long flags; @@ -560,7 +560,7 @@ static void klsi_105_set_termios(struct tty_struct *tty, if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD)) || (cflag & CSTOPB) != (old_cflag & CSTOPB)) { /* Not currently supported */ - tty->termios->c_cflag &= ~(PARENB|PARODD|CSTOPB); + tty->termios.c_cflag &= ~(PARENB|PARODD|CSTOPB); #if 0 priv->last_lcr = 0; @@ -587,7 +587,7 @@ static void klsi_105_set_termios(struct tty_struct *tty, || (iflag & IXON) != (old_iflag & IXON) || (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) { /* Not currently supported */ - tty->termios->c_cflag &= ~CRTSCTS; + tty->termios.c_cflag &= ~CRTSCTS; /* Drop DTR/RTS if no flow control otherwise assert */ #if 0 if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS)) diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index fafeabb64c55..bf5c74965d34 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -191,11 +191,11 @@ static void kobil_release(struct usb_serial *serial) static void kobil_init_termios(struct tty_struct *tty) { /* Default to echo off and other sane device settings */ - tty->termios->c_lflag = 0; - tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE); - tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF; + tty->termios.c_lflag = 0; + tty->termios.c_iflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE); + tty->termios.c_iflag |= IGNBRK | IGNPAR | IXOFF; /* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */ - tty->termios->c_oflag &= ~ONLCR; + tty->termios.c_oflag &= ~ONLCR; } static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) @@ -581,14 +581,14 @@ static void kobil_set_termios(struct tty_struct *tty, struct kobil_private *priv; int result; unsigned short urb_val = 0; - int c_cflag = tty->termios->c_cflag; + int c_cflag = tty->termios.c_cflag; speed_t speed; priv = usb_get_serial_port_data(port); if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) { /* This device doesn't support ioctl calls */ - *tty->termios = *old; + tty_termios_copy_hw(&tty->termios, old); return; } @@ -612,7 +612,7 @@ static void kobil_set_termios(struct tty_struct *tty, urb_val |= SUSBCR_SPASB_EvenParity; } else urb_val |= SUSBCR_SPASB_NoParity; - tty->termios->c_cflag &= ~CMSPAR; + tty->termios.c_cflag &= ~CMSPAR; tty_encode_baud_rate(tty, speed, speed); result = usb_control_msg(port->serial->dev, diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index a71fa0aa0406..df98cffdba65 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -454,7 +454,7 @@ static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port) * either. */ spin_lock_irqsave(&priv->lock, flags); - if (tty && (tty->termios->c_cflag & CBAUD)) + if (tty && (tty->termios.c_cflag & CBAUD)) priv->control_state = TIOCM_DTR | TIOCM_RTS; else priv->control_state = 0; @@ -634,7 +634,7 @@ static void mct_u232_set_termios(struct tty_struct *tty, { struct usb_serial *serial = port->serial; struct mct_u232_private *priv = usb_get_serial_port_data(port); - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; unsigned int cflag = termios->c_cflag; unsigned int old_cflag = old_termios->c_cflag; unsigned long flags; diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c index d47eb06fe463..2b0627b5fe2c 100644 --- a/drivers/usb/serial/metro-usb.c +++ b/drivers/usb/serial/metro-usb.c @@ -130,12 +130,6 @@ static void metrousb_read_int_callback(struct urb *urb) /* Set the data read from the usb port into the serial port buffer. */ tty = tty_port_tty_get(&port->port); - if (!tty) { - dev_err(&port->dev, "%s - bad tty pointer - exiting\n", - __func__); - return; - } - if (tty && urb->actual_length) { /* Loop through the data copying each byte to the tty layer. */ tty_insert_flip_string(tty, data, urb->actual_length); diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index a07dd3c8cfef..012f67b2e4cc 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1349,7 +1349,7 @@ static void mos7720_throttle(struct tty_struct *tty) } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { mos7720_port->shadowMCR &= ~UART_MCR_RTS; write_mos_reg(port->serial, port->number - port->serial->minor, MCR, mos7720_port->shadowMCR); @@ -1383,7 +1383,7 @@ static void mos7720_unthrottle(struct tty_struct *tty) } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { mos7720_port->shadowMCR |= UART_MCR_RTS; write_mos_reg(port->serial, port->number - port->serial->minor, MCR, mos7720_port->shadowMCR); @@ -1604,8 +1604,8 @@ static void change_port_settings(struct tty_struct *tty, lStop = 0x00; /* 1 stop bit */ lParity = 0x00; /* No parity */ - cflag = tty->termios->c_cflag; - iflag = tty->termios->c_iflag; + cflag = tty->termios.c_cflag; + iflag = tty->termios.c_iflag; /* Change the number of bits */ switch (cflag & CSIZE) { @@ -1753,11 +1753,11 @@ static void mos7720_set_termios(struct tty_struct *tty, dbg("%s\n", "setting termios - ASPIRE"); - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; dbg("%s - cflag %08x iflag %08x", __func__, - tty->termios->c_cflag, - RELEVANT_IFLAG(tty->termios->c_iflag)); + tty->termios.c_cflag, + RELEVANT_IFLAG(tty->termios.c_iflag)); dbg("%s - old cflag %08x old iflag %08x", __func__, old_termios->c_cflag, diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 2f6da1e89bfa..402c32d7accb 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1651,7 +1651,7 @@ static void mos7840_throttle(struct tty_struct *tty) return; } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { mos7840_port->shadowMCR &= ~MCR_RTS; status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mos7840_port->shadowMCR); @@ -1694,7 +1694,7 @@ static void mos7840_unthrottle(struct tty_struct *tty) } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { mos7840_port->shadowMCR |= MCR_RTS; status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mos7840_port->shadowMCR); @@ -2000,8 +2000,8 @@ static void mos7840_change_port_settings(struct tty_struct *tty, lStop = LCR_STOP_1; lParity = LCR_PAR_NONE; - cflag = tty->termios->c_cflag; - iflag = tty->termios->c_iflag; + cflag = tty->termios.c_cflag; + iflag = tty->termios.c_iflag; /* Change the number of bits */ if (cflag & CSIZE) { @@ -2161,10 +2161,10 @@ static void mos7840_set_termios(struct tty_struct *tty, dbg("%s", "setting termios - "); - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; dbg("%s - clfag %08x iflag %08x", __func__, - tty->termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag)); + tty->termios.c_cflag, RELEVANT_IFLAG(tty->termios.c_iflag)); dbg("%s - old clfag %08x old iflag %08x", __func__, old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag)); dbg("%s - port %d", __func__, port->number); diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index 5976b65ab6ee..9f555560bfbf 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -404,10 +404,10 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty) static void oti6858_init_termios(struct tty_struct *tty) { - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL; - tty->termios->c_ispeed = 38400; - tty->termios->c_ospeed = 38400; + tty->termios = tty_std_termios; + tty->termios.c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL; + tty->termios.c_ispeed = 38400; + tty->termios.c_ospeed = 38400; } static void oti6858_set_termios(struct tty_struct *tty, @@ -425,7 +425,7 @@ static void oti6858_set_termios(struct tty_struct *tty, return; } - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; spin_lock_irqsave(&priv->lock, flags); divisor = priv->pending_setup.divisor; diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 13b8dd6481f5..2b9108a8ea64 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -260,16 +260,16 @@ static void pl2303_set_termios(struct tty_struct *tty, serial settings even to the same values as before. Thus we actually need to filter in this specific case */ - if (!tty_termios_hw_change(tty->termios, old_termios)) + if (!tty_termios_hw_change(&tty->termios, old_termios)) return; - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; buf = kzalloc(7, GFP_KERNEL); if (!buf) { dev_err(&port->dev, "%s - out of memory.\n", __func__); /* Report back no change occurred */ - *tty->termios = *old_termios; + tty->termios = *old_termios; return; } diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 151670b6b72a..7df9cdb053ed 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -275,7 +275,7 @@ static void qt2_set_termios(struct tty_struct *tty, { struct usb_device *dev = port->serial->dev; struct qt2_port_private *port_priv; - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; u16 baud; unsigned int cflag = termios->c_cflag; u16 new_lcr = 0; @@ -406,7 +406,7 @@ static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port) port_priv->device_port = (u8) device_port; if (tty) - qt2_set_termios(tty, port, tty->termios); + qt2_set_termios(tty, port, &tty->termios); return 0; diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 0274710cced5..b14ebbd73567 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -382,7 +382,7 @@ static int sierra_send_setup(struct usb_serial_port *port) static void sierra_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { - tty_termios_copy_hw(tty->termios, old_termios); + tty_termios_copy_hw(&tty->termios, old_termios); sierra_send_setup(port); } diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index cad608984710..ab68a4d74d61 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -316,10 +316,10 @@ static void spcp8x5_dtr_rts(struct usb_serial_port *port, int on) static void spcp8x5_init_termios(struct tty_struct *tty) { /* for the 1st time call this function */ - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; - tty->termios->c_ispeed = 115200; - tty->termios->c_ospeed = 115200; + tty->termios = tty_std_termios; + tty->termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; + tty->termios.c_ispeed = 115200; + tty->termios.c_ospeed = 115200; } /* set the serial param for transfer. we should check if we really need to @@ -330,7 +330,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty, struct usb_serial *serial = port->serial; struct spcp8x5_private *priv = usb_get_serial_port_data(port); unsigned long flags; - unsigned int cflag = tty->termios->c_cflag; + unsigned int cflag = tty->termios.c_cflag; unsigned int old_cflag = old_termios->c_cflag; unsigned short uartdata; unsigned char buf[2] = {0, 0}; @@ -340,7 +340,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty, /* check that they really want us to change something */ - if (!tty_termios_hw_change(tty->termios, old_termios)) + if (!tty_termios_hw_change(&tty->termios, old_termios)) return; /* set DTR/RTS active */ diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 3fee23bf0c14..cf2d30cf7588 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -216,7 +216,7 @@ static void ssu100_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct usb_device *dev = port->serial->dev; - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; u16 baud, divisor, remainder; unsigned int cflag = termios->c_cflag; u16 urb_value = 0; /* will hold the new flags */ @@ -322,7 +322,7 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) dbg("%s - set uart failed", __func__); if (tty) - ssu100_set_termios(tty, port, tty->termios); + ssu100_set_termios(tty, port, &tty->termios); return usb_serial_generic_open(tty, port); } diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index a4404f5ad68e..f502a16aac21 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -520,7 +520,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) } if (tty) - ti_set_termios(tty, port, tty->termios); + ti_set_termios(tty, port, &tty->termios); dbg("%s - sending TI_OPEN_PORT", __func__); status = ti_command_out_sync(tdev, TI_OPEN_PORT, @@ -562,7 +562,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) usb_clear_halt(dev, port->read_urb->pipe); if (tty) - ti_set_termios(tty, port, tty->termios); + ti_set_termios(tty, port, &tty->termios); dbg("%s - sending TI_OPEN_PORT (2)", __func__); status = ti_command_out_sync(tdev, TI_OPEN_PORT, @@ -831,8 +831,8 @@ static void ti_set_termios(struct tty_struct *tty, int port_number = port->number - port->serial->minor; unsigned int mcr; - cflag = tty->termios->c_cflag; - iflag = tty->termios->c_iflag; + cflag = tty->termios.c_cflag; + iflag = tty->termios.c_iflag; dbg("%s - cflag %08x, iflag %08x", __func__, cflag, iflag); dbg("%s - old clfag %08x, old iflag %08x", __func__, @@ -871,7 +871,7 @@ static void ti_set_termios(struct tty_struct *tty, } /* CMSPAR isn't supported by this driver */ - tty->termios->c_cflag &= ~CMSPAR; + tty->termios.c_cflag &= ~CMSPAR; if (cflag & PARENB) { if (cflag & PARODD) { diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 27483f91a4a3..aa4b0d775992 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -207,7 +207,7 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty) if (retval) goto error_get_interface; - retval = tty_standard_install(driver, tty); + retval = tty_port_install(&port->port, driver, tty); if (retval) goto error_init_termios; @@ -305,8 +305,7 @@ static void serial_close(struct tty_struct *tty, struct file *filp) * Do the resource freeing and refcount dropping for the port. * Avoid freeing the console. * - * Called asynchronously after the last tty kref is dropped, - * and the tty layer has already done the tty_shutdown(tty); + * Called asynchronously after the last tty kref is dropped. */ static void serial_cleanup(struct tty_struct *tty) { @@ -423,7 +422,7 @@ static void serial_set_termios(struct tty_struct *tty, struct ktermios *old) if (port->serial->type->set_termios) port->serial->type->set_termios(tty, port, old); else - tty_termios_copy_hw(tty->termios, old); + tty_termios_copy_hw(&tty->termios, old); } static int serial_break(struct tty_struct *tty, int break_state) diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index 6855d5ed0331..72b678d90831 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -67,7 +67,7 @@ void usb_wwan_set_termios(struct tty_struct *tty, struct usb_wwan_intf_private *intfdata = port->serial->private; /* Doesn't support option setting */ - tty_termios_copy_hw(tty->termios, old_termios); + tty_termios_copy_hw(&tty->termios, old_termios); if (intfdata->send_setup) intfdata->send_setup(port); diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 473635e7f5db..b36077de72b9 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -724,7 +724,7 @@ static void firm_setup_port(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct whiteheat_port_settings port_settings; - unsigned int cflag = tty->termios->c_cflag; + unsigned int cflag = tty->termios.c_cflag; port_settings.port = port->number + 1; diff --git a/drivers/video/backlight/omap1_bl.c b/drivers/video/backlight/omap1_bl.c index bfdc5fbeaa11..92257ef19403 100644 --- a/drivers/video/backlight/omap1_bl.c +++ b/drivers/video/backlight/omap1_bl.c @@ -27,9 +27,9 @@ #include <linux/fb.h> #include <linux/backlight.h> #include <linux/slab.h> +#include <linux/platform_data/omap1_bl.h> #include <mach/hardware.h> -#include <plat/board.h> #include <plat/mux.h> #define OMAPBL_MAX_INTENSITY 0xff diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 5b289c5f695b..ee9e29639dcc 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -37,6 +37,7 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <plat/cpu.h> #include <plat/clock.h> #include <video/omapdss.h> diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index fc671d3d8004..3c39aa8de928 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -31,6 +31,7 @@ #include <linux/omapfb.h> #include <video/omapdss.h> +#include <plat/cpu.h> #include <plat/vram.h> #include <plat/vrfb.h> diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c index 4b0fcf3c2d03..fee195a76941 100644 --- a/drivers/w1/masters/omap_hdq.c +++ b/drivers/w1/masters/omap_hdq.c @@ -19,7 +19,6 @@ #include <linux/pm_runtime.h> #include <asm/irq.h> -#include <mach/hardware.h> #include "../w1.h" #include "../w1_int.h" @@ -644,7 +643,7 @@ static int omap_hdq_remove(struct platform_device *pdev) /* remove module dependency */ pm_runtime_disable(&pdev->dev); - free_irq(INT_24XX_HDQ_IRQ, hdq_data); + free_irq(platform_get_irq(pdev, 0), hdq_data); platform_set_drvdata(pdev, NULL); iounmap(hdq_data->hdq_base); kfree(hdq_data); diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c index fceec4f4eb7e..f5db18dbc0f9 100644 --- a/drivers/watchdog/omap_wdt.c +++ b/drivers/watchdog/omap_wdt.c @@ -46,6 +46,7 @@ #include <linux/slab.h> #include <linux/pm_runtime.h> #include <mach/hardware.h> +#include <plat/cpu.h> #include <plat/prcm.h> #include "omap_wdt.h" @@ -218,12 +219,16 @@ static long omap_wdt_ioctl(struct file *file, unsigned int cmd, case WDIOC_GETSTATUS: return put_user(0, (int __user *)arg); case WDIOC_GETBOOTSTATUS: +#ifdef CONFIG_ARCH_OMAP1 if (cpu_is_omap16xx()) return put_user(__raw_readw(ARM_SYSST), (int __user *)arg); +#endif +#ifdef CONFIG_ARCH_OMAP2PLUS if (cpu_is_omap24xx()) return put_user(omap_prcm_get_reset_sources(), (int __user *)arg); +#endif return put_user(0, (int __user *)arg); case WDIOC_KEEPALIVE: spin_lock(&wdt_lock); |