diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-02-10 11:35:36 -0800 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-02-10 11:35:36 -0800 |
commit | 4ba24fef3eb3b142197135223b90ced2f319cd53 (patch) | |
tree | a20c125b27740ec7b4c761b11d801108e1b316b2 /drivers/tty | |
parent | 47c1ffb2b6b630894e9a16442611c056ab21c057 (diff) | |
parent | 98a4a59ee31a12105a2b84f5b8b515ac2cb208ef (diff) |
Merge branch 'next' into for-linus
Prepare first round of input updates for 3.20.
Diffstat (limited to 'drivers/tty')
112 files changed, 6771 insertions, 2028 deletions
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 979e7c3ea2cb..d9f85f95eb2a 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1802,7 +1802,6 @@ static struct platform_driver amiga_serial_driver = { .remove = __exit_p(amiga_serial_remove), .driver = { .name = "amiga-serial", - .owner = THIS_MODULE, }, }; diff --git a/drivers/tty/bfin_jtag_comm.c b/drivers/tty/bfin_jtag_comm.c index 8096fcbe2dc1..d7b198c400c7 100644 --- a/drivers/tty/bfin_jtag_comm.c +++ b/drivers/tty/bfin_jtag_comm.c @@ -77,7 +77,6 @@ bfin_jc_emudat_manager(void *arg) pr_debug("waiting for readers\n"); __set_current_state(TASK_UNINTERRUPTIBLE); schedule(); - __set_current_state(TASK_RUNNING); continue; } diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c index 4f485e88f60c..3c60923b0957 100644 --- a/drivers/tty/ehv_bytechan.c +++ b/drivers/tty/ehv_bytechan.c @@ -309,8 +309,8 @@ static int __init ehv_bc_console_init(void) * handle for udbg. */ if (stdout_bc != CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE) - pr_warning("ehv-bc: udbg handle %u is not the stdout handle\n", - CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE); + pr_warn("ehv-bc: udbg handle %u is not the stdout handle\n", + CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE); #endif /* add_preferred_console() must be called before register_console(), @@ -740,7 +740,6 @@ static const struct of_device_id ehv_bc_tty_of_ids[] = { static struct platform_driver ehv_bc_tty_driver = { .driver = { - .owner = THIS_MODULE, .name = "ehv-bc", .of_match_table = ehv_bc_tty_of_ids, }, diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index 09495f515fa9..967b2c2b7cf1 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -155,9 +155,9 @@ static struct tty_driver *goldfish_tty_console_device(struct console *c, static int goldfish_tty_console_setup(struct console *co, char *options) { - if ((unsigned)co->index > goldfish_tty_line_count) + if ((unsigned)co->index >= goldfish_tty_line_count) return -ENODEV; - if (goldfish_ttys[co->index].base == 0) + if (!goldfish_ttys[co->index].base) return -ENODEV; return 0; } @@ -317,7 +317,7 @@ static int goldfish_tty_remove(struct platform_device *pdev) unregister_console(&qtty->console); tty_unregister_device(goldfish_tty_driver, pdev->id); iounmap(qtty->base); - qtty->base = 0; + qtty->base = NULL; free_irq(qtty->irq, pdev); goldfish_tty_current_line_count--; if (goldfish_tty_current_line_count == 0) diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c index a2cc5f834c63..071551bf3e9a 100644 --- a/drivers/tty/hvc/hvc_opal.c +++ b/drivers/tty/hvc/hvc_opal.c @@ -262,7 +262,6 @@ static struct platform_driver hvc_opal_driver = { .remove = hvc_opal_remove, .driver = { .name = hvc_opal_name, - .owner = THIS_MODULE, .of_match_table = hvc_opal_match, } }; diff --git a/drivers/tty/hvc/hvc_tile.c b/drivers/tty/hvc/hvc_tile.c index df374860037c..3f6cd3102db5 100644 --- a/drivers/tty/hvc/hvc_tile.c +++ b/drivers/tty/hvc/hvc_tile.c @@ -178,7 +178,6 @@ static struct platform_driver hvc_tile_driver = { .shutdown = hvc_tile_shutdown, .driver = { .name = "hvc-tile", - .owner = THIS_MODULE, } }; #endif diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c index 5618b5fc7500..f575a9b5ede7 100644 --- a/drivers/tty/hvc/hvc_vio.c +++ b/drivers/tty/hvc/hvc_vio.c @@ -452,7 +452,7 @@ void __init hvc_vio_init_early(void) return; #endif /* Check whether the user has requested a different console. */ - if (!strstr(cmd_line, "console=")) + if (!strstr(boot_command_line, "console=")) add_preferred_console("hvc", 0, NULL); hvc_instantiate(0, 0, ops); } diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index 2dc2831840ca..f1e57425e39f 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -347,8 +347,6 @@ static int xen_console_remove(struct xencons_info *info) } #ifdef CONFIG_HVC_XEN_FRONTEND -static struct xenbus_driver xencons_driver; - static int xencons_remove(struct xenbus_device *dev) { return xen_console_remove(dev_get_drvdata(&dev->dev)); @@ -402,9 +400,6 @@ static int xencons_connect_backend(struct xenbus_device *dev, evtchn); if (ret) goto error_xenbus; - ret = xenbus_printf(xbt, dev->nodename, "type", "ioemu"); - if (ret) - goto error_xenbus; ret = xenbus_transaction_end(xbt, 0); if (ret) { if (ret == -EAGAIN) @@ -502,13 +497,14 @@ static const struct xenbus_device_id xencons_ids[] = { { "" } }; - -static DEFINE_XENBUS_DRIVER(xencons, "xenconsole", +static struct xenbus_driver xencons_driver = { + .name = "xenconsole", + .ids = xencons_ids, .probe = xencons_probe, .remove = xencons_remove, .resume = xencons_resume, .otherend_changed = xencons_backend_changed, -); +}; #endif /* CONFIG_HVC_XEN_FRONTEND */ static int __init xen_hvc_init(void) diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 81e939e90c4c..81ff7e1bfb1a 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -1575,7 +1575,7 @@ static int __init hvcs_module_init(void) */ rc = driver_create_file(&(hvcs_vio_driver.driver), &driver_attr_rescan); if (rc) - pr_warning(KERN_ERR "HVCS: Failed to create rescan file (err %d)\n", rc); + pr_warning("HVCS: Failed to create rescan file (err %d)\n", rc); return 0; } diff --git a/drivers/tty/hvc/hvsi_lib.c b/drivers/tty/hvc/hvsi_lib.c index 7ae6c293e518..a270f04588d7 100644 --- a/drivers/tty/hvc/hvsi_lib.c +++ b/drivers/tty/hvc/hvsi_lib.c @@ -405,8 +405,7 @@ void hvsilib_close(struct hvsi_priv *pv, struct hvc_struct *hp) hvsi_send_close(pv); } - if (pv->tty) - tty_kref_put(pv->tty); + tty_kref_put(pv->tty); pv->tty = NULL; } diff --git a/drivers/tty/ipwireless/hardware.c b/drivers/tty/ipwireless/hardware.c index 2c14842541dd..5c77e1eac4ee 100644 --- a/drivers/tty/ipwireless/hardware.c +++ b/drivers/tty/ipwireless/hardware.c @@ -378,9 +378,9 @@ static void swap_packet_bitfield_to_le(unsigned char *data) /* * transform bits from aa.bbb.ccc to ccc.bbb.aa */ - ret |= tmp & 0xc0 >> 6; - ret |= tmp & 0x38 >> 1; - ret |= tmp & 0x07 << 5; + ret |= (tmp & 0xc0) >> 6; + ret |= (tmp & 0x38) >> 1; + ret |= (tmp & 0x07) << 5; *data = ret & 0xff; #endif } @@ -393,9 +393,9 @@ static void swap_packet_bitfield_from_le(unsigned char *data) /* * transform bits from ccc.bbb.aa to aa.bbb.ccc */ - ret |= tmp & 0xe0 >> 5; - ret |= tmp & 0x1c << 1; - ret |= tmp & 0x03 << 6; + ret |= (tmp & 0xe0) >> 5; + ret |= (tmp & 0x1c) << 1; + ret |= (tmp & 0x03) << 6; *data = ret & 0xff; #endif } diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c index 858291ca889c..59ed783c4bcd 100644 --- a/drivers/tty/isicom.c +++ b/drivers/tty/isicom.c @@ -249,7 +249,7 @@ static int lock_card(struct isi_board *card) spin_unlock_irqrestore(&card->card_lock, card->flags); msleep(10); } - pr_warning("Failed to lock Card (0x%lx)\n", card->base); + pr_warn("Failed to lock Card (0x%lx)\n", card->base); return 0; /* Failed to acquire the card! */ } @@ -378,13 +378,13 @@ static inline int __isicom_paranoia_check(struct isi_port const *port, char *name, const char *routine) { if (!port) { - pr_warning("Warning: bad isicom magic for dev %s in %s.\n", - name, routine); + pr_warn("Warning: bad isicom magic for dev %s in %s\n", + name, routine); return 1; } if (port->magic != ISICOM_MAGIC) { - pr_warning("Warning: NULL isicom port for dev %s in %s.\n", - name, routine); + pr_warn("Warning: NULL isicom port for dev %s in %s\n", + name, routine); return 1; } @@ -546,8 +546,8 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) byte_count = header & 0xff; if (channel + 1 > card->port_count) { - pr_warning("%s(0x%lx): %d(channel) > port_count.\n", - __func__, base, channel+1); + pr_warn("%s(0x%lx): %d(channel) > port_count\n", + __func__, base, channel + 1); outw(0x0000, base+0x04); /* enable interrupts */ spin_unlock(&card->card_lock); return IRQ_HANDLED; diff --git a/drivers/tty/metag_da.c b/drivers/tty/metag_da.c index 7332e2ca4615..3774600741d8 100644 --- a/drivers/tty/metag_da.c +++ b/drivers/tty/metag_da.c @@ -17,6 +17,7 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/kthread.h> +#include <linux/moduleparam.h> #include <linux/mutex.h> #include <linux/sched.h> #include <linux/serial.h> @@ -70,6 +71,15 @@ static struct tty_driver *channel_driver; static struct timer_list put_timer; static struct task_struct *dashtty_thread; +/* + * The console_poll parameter determines whether the console channel should be + * polled for input. + * By default the console channel isn't polled at all, in order to avoid the + * overhead, but that means it isn't possible to have a login on /dev/console. + */ +static bool console_poll; +module_param(console_poll, bool, S_IRUGO); + #define RX_BUF_SIZE 1024 enum { @@ -353,7 +363,7 @@ static int dashtty_port_activate(struct tty_port *port, struct tty_struct *tty) * possible to have a login on /dev/console. * */ - if (dport != &dashtty_ports[CONSOLE_CHANNEL]) + if (console_poll || dport != &dashtty_ports[CONSOLE_CHANNEL]) if (atomic_inc_return(&num_channels_need_poll) == 1) add_poll_timer(&poll_timer); @@ -372,7 +382,7 @@ static void dashtty_port_shutdown(struct tty_port *port) unsigned int count; /* stop reading */ - if (dport != &dashtty_ports[CONSOLE_CHANNEL]) + if (console_poll || dport != &dashtty_ports[CONSOLE_CHANNEL]) if (atomic_dec_and_test(&num_channels_need_poll)) del_timer_sync(&poll_timer); diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index 1deaca4674e4..14c54e041065 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -1096,7 +1096,7 @@ static int __init moxa_init(void) continue; } - printk(KERN_INFO "MOXA isa board found at 0x%.8lu and " + printk(KERN_INFO "MOXA isa board found at 0x%.8lx and " "ready (%u ports, firmware loaded)\n", baseaddr[i], brd->numPorts); diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index f44f1ba762c3..d2b496750d59 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -321,7 +321,8 @@ static void n_tty_check_unthrottle(struct tty_struct *tty) static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata) { - *read_buf_addr(ldata, ldata->read_head++) = c; + *read_buf_addr(ldata, ldata->read_head) = c; + ldata->read_head++; } /** @@ -351,13 +352,13 @@ static void n_tty_packet_mode_flush(struct tty_struct *tty) { unsigned long flags; - spin_lock_irqsave(&tty->ctrl_lock, flags); if (tty->link->packet) { + spin_lock_irqsave(&tty->ctrl_lock, flags); tty->ctrl_status |= TIOCPKT_FLUSHREAD; + spin_unlock_irqrestore(&tty->ctrl_lock, flags); if (waitqueue_active(&tty->link->read_wait)) wake_up_interruptible(&tty->link->read_wait); } - spin_unlock_irqrestore(&tty->ctrl_lock, flags); } /** @@ -1166,7 +1167,7 @@ static void n_tty_receive_break(struct tty_struct *tty) } put_tty_queue('\0', ldata); if (waitqueue_active(&tty->read_wait)) - wake_up_interruptible(&tty->read_wait); + wake_up_interruptible_poll(&tty->read_wait, POLLIN); } /** @@ -1226,7 +1227,7 @@ static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c) } else put_tty_queue(c, ldata); if (waitqueue_active(&tty->read_wait)) - wake_up_interruptible(&tty->read_wait); + wake_up_interruptible_poll(&tty->read_wait, POLLIN); } static void @@ -1378,7 +1379,7 @@ handle_newline: ldata->canon_head = ldata->read_head; kill_fasync(&tty->fasync, SIGIO, POLL_IN); if (waitqueue_active(&tty->read_wait)) - wake_up_interruptible(&tty->read_wait); + wake_up_interruptible_poll(&tty->read_wait, POLLIN); return 0; } } @@ -1679,7 +1680,7 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp, L_EXTPROC(tty)) { kill_fasync(&tty->fasync, SIGIO, POLL_IN); if (waitqueue_active(&tty->read_wait)) - wake_up_interruptible(&tty->read_wait); + wake_up_interruptible_poll(&tty->read_wait, POLLIN); } } @@ -2123,12 +2124,11 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, { struct n_tty_data *ldata = tty->disc_data; unsigned char __user *b = buf; - DECLARE_WAITQUEUE(wait, current); + DEFINE_WAIT_FUNC(wait, woken_wake_function); int c; int minimum, time; ssize_t retval = 0; long timeout; - unsigned long flags; int packet; c = job_control(tty, file); @@ -2174,10 +2174,10 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, unsigned char cs; if (b != buf) break; - spin_lock_irqsave(&tty->link->ctrl_lock, flags); + spin_lock_irq(&tty->link->ctrl_lock); cs = tty->link->ctrl_status; tty->link->ctrl_status = 0; - spin_unlock_irqrestore(&tty->link->ctrl_lock, flags); + spin_unlock_irq(&tty->link->ctrl_lock); if (tty_put_user(tty, cs, b++)) { retval = -EFAULT; b--; @@ -2186,10 +2186,6 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, nr--; break; } - /* This statement must be first before checking for input - so that any interrupt will set the state back to - TASK_RUNNING. */ - set_current_state(TASK_INTERRUPTIBLE); if (((minimum - (b - buf)) < ldata->minimum_to_wake) && ((minimum - (b - buf)) >= 1)) @@ -2197,45 +2193,29 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, if (!input_available_p(tty, 0)) { if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { - up_read(&tty->termios_rwsem); - tty_flush_to_ldisc(tty); - down_read(&tty->termios_rwsem); - if (!input_available_p(tty, 0)) { - retval = -EIO; - break; - } - } else { - if (tty_hung_up_p(file)) - break; - if (!timeout) - break; - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - break; - } - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - n_tty_set_room(tty); - up_read(&tty->termios_rwsem); - - timeout = schedule_timeout(timeout); - - down_read(&tty->termios_rwsem); - continue; + retval = -EIO; + break; } - } - __set_current_state(TASK_RUNNING); - - /* Deal with packet mode. */ - if (packet && b == buf) { - if (tty_put_user(tty, TIOCPKT_DATA, b++)) { - retval = -EFAULT; - b--; + if (tty_hung_up_p(file)) + break; + if (!timeout) + break; + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; break; } - nr--; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + n_tty_set_room(tty); + up_read(&tty->termios_rwsem); + + timeout = wait_woken(&wait, TASK_INTERRUPTIBLE, + timeout); + + down_read(&tty->termios_rwsem); + continue; } if (ldata->icanon && !L_EXTPROC(tty)) { @@ -2247,8 +2227,17 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, break; } else { int uncopied; - /* The copy function takes the read lock and handles - locking internally for this case */ + + /* Deal with packet mode. */ + if (packet && b == buf) { + if (tty_put_user(tty, TIOCPKT_DATA, b++)) { + retval = -EFAULT; + b--; + break; + } + nr--; + } + uncopied = copy_from_read_buf(tty, &b, &nr); uncopied += copy_from_read_buf(tty, &b, &nr); if (uncopied) { @@ -2273,7 +2262,6 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, mutex_unlock(&ldata->atomic_read_lock); - __set_current_state(TASK_RUNNING); if (b - buf) retval = b - buf; @@ -2306,7 +2294,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *buf, size_t nr) { const unsigned char *b = buf; - DECLARE_WAITQUEUE(wait, current); + DEFINE_WAIT_FUNC(wait, woken_wake_function); int c; ssize_t retval = 0; @@ -2324,7 +2312,6 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, add_wait_queue(&tty->write_wait, &wait); while (1) { - set_current_state(TASK_INTERRUPTIBLE); if (signal_pending(current)) { retval = -ERESTARTSYS; break; @@ -2378,12 +2365,11 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, } up_read(&tty->termios_rwsem); - schedule(); + wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); down_read(&tty->termios_rwsem); } break_out: - __set_current_state(TASK_RUNNING); remove_wait_queue(&tty->write_wait, &wait); if (b - buf != nr && tty->fasync) set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); @@ -2413,12 +2399,17 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file, poll_wait(file, &tty->read_wait, wait); poll_wait(file, &tty->write_wait, wait); + if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) + mask |= POLLHUP; if (input_available_p(tty, 1)) mask |= POLLIN | POLLRDNORM; + else if (mask & POLLHUP) { + tty_flush_to_ldisc(tty); + if (input_available_p(tty, 1)) + mask |= POLLIN | POLLRDNORM; + } if (tty->packet && tty->link->ctrl_status) mask |= POLLPRI | POLLIN | POLLRDNORM; - if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) - mask |= POLLHUP; if (tty_hung_up_p(file)) mask |= POLLHUP; if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) { diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index cd0429369557..74885af8c7bd 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -523,7 +523,7 @@ static u32 write_mem32(void __iomem *mem_addr_start, const u32 *buf, } /* Setup pointers to different channels and also setup buffer sizes. */ -static void setup_memory(struct nozomi *dc) +static void nozomi_setup_memory(struct nozomi *dc) { void __iomem *offset = dc->base_addr + dc->config_table.dl_start; /* The length reported is including the length field of 4 bytes, @@ -671,7 +671,7 @@ static int nozomi_read_config_table(struct nozomi *dc) int i; DBG1("Second phase, configuring card"); - setup_memory(dc); + nozomi_setup_memory(dc); dc->port[PORT_MDM].toggle_ul = dc->config_table.toggle.mdm_ul; dc->port[PORT_MDM].toggle_dl = dc->config_table.toggle.mdm_dl; @@ -705,7 +705,7 @@ static int nozomi_read_config_table(struct nozomi *dc) dc->config_table.version); /* Here we should disable all I/O over F32. */ - setup_memory(dc); + nozomi_setup_memory(dc); /* * We should send ALL channel pair tokens back along diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 9bbdb1de12e2..a9d256d6e909 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -24,6 +24,7 @@ #include <linux/devpts_fs.h> #include <linux/slab.h> #include <linux/mutex.h> +#include <linux/poll.h> #ifdef CONFIG_UNIX98_PTYS @@ -46,10 +47,13 @@ static void pty_close(struct tty_struct *tty, struct file *filp) set_bit(TTY_IO_ERROR, &tty->flags); wake_up_interruptible(&tty->read_wait); wake_up_interruptible(&tty->write_wait); + spin_lock_irq(&tty->ctrl_lock); tty->packet = 0; + spin_unlock_irq(&tty->ctrl_lock); /* Review - krefs on tty_link ?? */ if (!tty->link) return; + tty_flush_to_ldisc(tty->link); set_bit(TTY_OTHER_CLOSED, &tty->link->flags); wake_up_interruptible(&tty->link->read_wait); wake_up_interruptible(&tty->link->write_wait); @@ -63,9 +67,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp) mutex_unlock(&devpts_mutex); } #endif - tty_unlock(tty); tty_vhangup(tty->link); - tty_lock(tty); } } @@ -177,21 +179,21 @@ static int pty_get_lock(struct tty_struct *tty, int __user *arg) /* Set the packet mode on a pty */ static int pty_set_pktmode(struct tty_struct *tty, int __user *arg) { - unsigned long flags; int pktmode; if (get_user(pktmode, arg)) return -EFAULT; - spin_lock_irqsave(&tty->ctrl_lock, flags); + spin_lock_irq(&tty->ctrl_lock); if (pktmode) { if (!tty->packet) { - tty->packet = 1; tty->link->ctrl_status = 0; + smp_mb(); + tty->packet = 1; } } else tty->packet = 0; - spin_unlock_irqrestore(&tty->ctrl_lock, flags); + spin_unlock_irq(&tty->ctrl_lock); return 0; } @@ -206,15 +208,12 @@ static int pty_get_pktmode(struct tty_struct *tty, int __user *arg) /* Send a signal to the slave */ static int pty_signal(struct tty_struct *tty, int sig) { - unsigned long flags; struct pid *pgrp; if (tty->link) { - spin_lock_irqsave(&tty->link->ctrl_lock, flags); - pgrp = get_pid(tty->link->pgrp); - spin_unlock_irqrestore(&tty->link->ctrl_lock, flags); - - kill_pgrp(pgrp, sig, 1); + pgrp = tty_get_pgrp(tty->link); + if (pgrp) + kill_pgrp(pgrp, sig, 1); put_pid(pgrp); } return 0; @@ -223,16 +222,15 @@ static int pty_signal(struct tty_struct *tty, int sig) static void pty_flush_buffer(struct tty_struct *tty) { struct tty_struct *to = tty->link; - unsigned long flags; if (!to) return; /* tty_buffer_flush(to); FIXME */ if (to->packet) { - spin_lock_irqsave(&tty->ctrl_lock, flags); + spin_lock_irq(&tty->ctrl_lock); tty->ctrl_status |= TIOCPKT_FLUSHWRITE; wake_up_interruptible(&to->read_wait); - spin_unlock_irqrestore(&tty->ctrl_lock, flags); + spin_unlock_irq(&tty->ctrl_lock); } } @@ -261,6 +259,32 @@ out: static void pty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { + /* 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); + int old_flow = ((old_termios->c_iflag & IXON) && + (old_termios->c_cc[VSTOP] == '\023') && + (old_termios->c_cc[VSTART] == '\021')); + int new_flow = (I_IXON(tty) && + STOP_CHAR(tty) == '\023' && + START_CHAR(tty) == '\021'); + if ((old_flow != new_flow) || extproc) { + spin_lock_irq(&tty->ctrl_lock); + if (old_flow != new_flow) { + tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP); + if (new_flow) + tty->ctrl_status |= TIOCPKT_DOSTOP; + else + tty->ctrl_status |= TIOCPKT_NOSTOP; + } + if (extproc) + tty->ctrl_status |= TIOCPKT_IOCTL; + spin_unlock_irq(&tty->ctrl_lock); + wake_up_interruptible(&tty->link->read_wait); + } + } + tty->termios.c_cflag &= ~(CSIZE | PARENB); tty->termios.c_cflag |= (CS8 | CREAD); } @@ -277,7 +301,6 @@ static void pty_set_termios(struct tty_struct *tty, static int pty_resize(struct tty_struct *tty, struct winsize *ws) { struct pid *pgrp, *rpgrp; - unsigned long flags; struct tty_struct *pty = tty->link; /* For a PTY we need to lock the tty side */ @@ -285,17 +308,9 @@ static int pty_resize(struct tty_struct *tty, struct winsize *ws) if (!memcmp(ws, &tty->winsize, sizeof(*ws))) goto done; - /* Get the PID values and reference them so we can - avoid holding the tty ctrl lock while sending signals. - We need to lock these individually however. */ - - spin_lock_irqsave(&tty->ctrl_lock, flags); - pgrp = get_pid(tty->pgrp); - spin_unlock_irqrestore(&tty->ctrl_lock, flags); - - spin_lock_irqsave(&pty->ctrl_lock, flags); - rpgrp = get_pid(pty->pgrp); - spin_unlock_irqrestore(&pty->ctrl_lock, flags); + /* Signal the foreground process group of both ptys */ + pgrp = tty_get_pgrp(tty); + rpgrp = tty_get_pgrp(pty); if (pgrp) kill_pgrp(pgrp, SIGWINCH, 1); @@ -313,6 +328,42 @@ done: } /** + * pty_start - start() handler + * pty_stop - stop() handler + * @tty: tty being flow-controlled + * + * Propagates the TIOCPKT status to the master pty. + * + * NB: only the master pty can be in packet mode so only the slave + * needs start()/stop() handlers + */ +static void pty_start(struct tty_struct *tty) +{ + unsigned long flags; + + if (tty->link && tty->link->packet) { + spin_lock_irqsave(&tty->ctrl_lock, flags); + tty->ctrl_status &= ~TIOCPKT_STOP; + tty->ctrl_status |= TIOCPKT_START; + spin_unlock_irqrestore(&tty->ctrl_lock, flags); + wake_up_interruptible_poll(&tty->link->read_wait, POLLIN); + } +} + +static void pty_stop(struct tty_struct *tty) +{ + unsigned long flags; + + if (tty->link && tty->link->packet) { + spin_lock_irqsave(&tty->ctrl_lock, flags); + tty->ctrl_status &= ~TIOCPKT_START; + tty->ctrl_status |= TIOCPKT_STOP; + spin_unlock_irqrestore(&tty->ctrl_lock, flags); + wake_up_interruptible_poll(&tty->link->read_wait, POLLIN); + } +} + +/** * pty_common_install - set up the pty pair * @driver: the pty driver * @tty: the tty being instantiated @@ -331,6 +382,10 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, int idx = tty->index; int retval = -ENOMEM; + /* Opening the slave first has always returned -EIO */ + if (driver->subtype != PTY_TYPE_MASTER) + return -EIO; + ports[0] = kmalloc(sizeof **ports, GFP_KERNEL); ports[1] = kmalloc(sizeof **ports, GFP_KERNEL); if (!ports[0] || !ports[1]) @@ -343,6 +398,8 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, if (!o_tty) goto err_put_module; + tty_set_lock_subclass(o_tty); + if (legacy) { /* We always use new tty termios data so we can do this the easy way .. */ @@ -367,8 +424,6 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, * Everything allocated ... set up the o_tty structure. */ 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; @@ -380,6 +435,7 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, tty_driver_kref_get(driver); tty->count++; + o_tty->count++; return 0; err_free_termios: if (legacy) @@ -452,7 +508,6 @@ static const struct tty_operations master_pty_ops_bsd = { .flush_buffer = pty_flush_buffer, .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, - .set_termios = pty_set_termios, .ioctl = pty_bsd_ioctl, .cleanup = pty_cleanup, .resize = pty_resize, @@ -471,6 +526,8 @@ static const struct tty_operations slave_pty_ops_bsd = { .set_termios = pty_set_termios, .cleanup = pty_cleanup, .resize = pty_resize, + .start = pty_start, + .stop = pty_stop, .remove = pty_remove }; @@ -627,7 +684,6 @@ static const struct tty_operations ptm_unix98_ops = { .flush_buffer = pty_flush_buffer, .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, - .set_termios = pty_set_termios, .ioctl = pty_unix98_ioctl, .resize = pty_resize, .shutdown = pty_unix98_shutdown, @@ -646,6 +702,8 @@ static const struct tty_operations pty_unix98_ops = { .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, + .start = pty_start, + .stop = pty_stop, .shutdown = pty_unix98_shutdown, .cleanup = pty_cleanup, }; diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 1b08c918cd51..b00836851061 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -16,13 +16,16 @@ #include <linux/dmaengine.h> struct uart_8250_dma { + int (*tx_dma)(struct uart_8250_port *p); + int (*rx_dma)(struct uart_8250_port *p, unsigned int iir); + + /* Filter function */ dma_filter_fn fn; + + /* Parameter to the filter function */ void *rx_param; void *tx_param; - int rx_chan_id; - int tx_chan_id; - struct dma_slave_config rxconf; struct dma_slave_config txconf; @@ -41,6 +44,8 @@ struct uart_8250_dma { size_t tx_size; unsigned char tx_running:1; + unsigned char tx_err: 1; + unsigned char rx_running:1; }; struct old_serial_port { @@ -51,7 +56,7 @@ struct old_serial_port { unsigned int flags; unsigned char hub6; unsigned char io_type; - unsigned char *iomem_base; + unsigned char __iomem *iomem_base; unsigned short iomem_reg_shift; unsigned long irqflags; }; @@ -72,6 +77,7 @@ struct serial8250_config { #define UART_CAP_UUE (1 << 12) /* UART needs IER bit 6 set (Xscale) */ #define UART_CAP_RTOIE (1 << 13) /* UART needs IER bit 4 set (Xscale, Tegra) */ #define UART_CAP_HFIFO (1 << 14) /* UART has a "hidden" FIFO */ +#define UART_CAP_RPM (1 << 15) /* Runtime PM is active while idle */ #define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */ #define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */ @@ -112,6 +118,10 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value) up->dl_write(up, value); } +struct uart_8250_port *serial8250_get_port(int line); +void serial8250_rpm_get(struct uart_8250_port *p); +void serial8250_rpm_put(struct uart_8250_port *p); + #if defined(__alpha__) && !defined(CONFIG_PCI) /* * Digital did something really horribly wrong with the OUT1 and OUT2 diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 1d42dba6121d..11c66856ba2f 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -37,6 +37,8 @@ #include <linux/nmi.h> #include <linux/mutex.h> #include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/pm_runtime.h> #ifdef CONFIG_SPARC #include <linux/sunserialcore.h> #endif @@ -539,6 +541,55 @@ void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p) } EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos); +void serial8250_rpm_get(struct uart_8250_port *p) +{ + if (!(p->capabilities & UART_CAP_RPM)) + return; + pm_runtime_get_sync(p->port.dev); +} +EXPORT_SYMBOL_GPL(serial8250_rpm_get); + +void serial8250_rpm_put(struct uart_8250_port *p) +{ + if (!(p->capabilities & UART_CAP_RPM)) + return; + pm_runtime_mark_last_busy(p->port.dev); + pm_runtime_put_autosuspend(p->port.dev); +} +EXPORT_SYMBOL_GPL(serial8250_rpm_put); + +/* + * These two wrappers ensure that enable_runtime_pm_tx() can be called more than + * once and disable_runtime_pm_tx() will still disable RPM because the fifo is + * empty and the HW can idle again. + */ +static void serial8250_rpm_get_tx(struct uart_8250_port *p) +{ + unsigned char rpm_active; + + if (!(p->capabilities & UART_CAP_RPM)) + return; + + rpm_active = xchg(&p->rpm_tx_active, 1); + if (rpm_active) + return; + pm_runtime_get_sync(p->port.dev); +} + +static void serial8250_rpm_put_tx(struct uart_8250_port *p) +{ + unsigned char rpm_active; + + if (!(p->capabilities & UART_CAP_RPM)) + return; + + rpm_active = xchg(&p->rpm_tx_active, 0); + if (!rpm_active) + return; + pm_runtime_mark_last_busy(p->port.dev); + pm_runtime_put_autosuspend(p->port.dev); +} + /* * IER sleep support. UARTs which have EFRs need the "extended * capability" bit enabled. Note that on XR16C850s, we need to @@ -546,6 +597,7 @@ EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos); */ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) { + unsigned char lcr = 0, efr = 0; /* * Exar UARTs have a SLEEP register that enables or disables * each UART to enter sleep mode separately. On the XR17V35x the @@ -553,14 +605,17 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) * offset but the UART channel may only write to the corresponding * bit. */ + serial8250_rpm_get(p); if ((p->port.type == PORT_XR17V35X) || (p->port.type == PORT_XR17D15X)) { serial_out(p, UART_EXAR_SLEEP, sleep ? 0xff : 0); - return; + goto out; } if (p->capabilities & UART_CAP_SLEEP) { if (p->capabilities & UART_CAP_EFR) { + lcr = serial_in(p, UART_LCR); + efr = serial_in(p, UART_EFR); serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); serial_out(p, UART_EFR, UART_EFR_ECB); serial_out(p, UART_LCR, 0); @@ -568,10 +623,12 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); if (p->capabilities & UART_CAP_EFR) { serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(p, UART_EFR, 0); - serial_out(p, UART_LCR, 0); + serial_out(p, UART_EFR, efr); + serial_out(p, UART_LCR, lcr); } } +out: + serial8250_rpm_put(p); } #ifdef CONFIG_SERIAL_8250_RSA @@ -1272,6 +1329,7 @@ static inline void __stop_tx(struct uart_8250_port *p) if (p->ier & UART_IER_THRI) { p->ier &= ~UART_IER_THRI; serial_out(p, UART_IER, p->ier); + serial8250_rpm_put_tx(p); } } @@ -1279,6 +1337,7 @@ static void serial8250_stop_tx(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); + serial8250_rpm_get(up); __stop_tx(up); /* @@ -1288,13 +1347,15 @@ static void serial8250_stop_tx(struct uart_port *port) up->acr |= UART_ACR_TXDIS; serial_icr_write(up, UART_ACR, up->acr); } + serial8250_rpm_put(up); } static void serial8250_start_tx(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); - if (up->dma && !serial8250_tx_dma(up)) { + serial8250_rpm_get_tx(up); + if (up->dma && !up->dma->tx_dma(up)) { return; } else if (!(up->ier & UART_IER_THRI)) { up->ier |= UART_IER_THRI; @@ -1318,13 +1379,40 @@ static void serial8250_start_tx(struct uart_port *port) } } +static void serial8250_throttle(struct uart_port *port) +{ + port->throttle(port); +} + +static void serial8250_unthrottle(struct uart_port *port) +{ + port->unthrottle(port); +} + static void serial8250_stop_rx(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); - up->ier &= ~UART_IER_RLSI; + serial8250_rpm_get(up); + + up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); up->port.read_status_mask &= ~UART_LSR_DR; serial_port_out(port, UART_IER, up->ier); + + serial8250_rpm_put(up); +} + +static void serial8250_disable_ms(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + /* no MSR capabilities */ + if (up->bugs & UART_BUG_NOMSR) + return; + + up->ier &= ~UART_IER_MSI; + serial_port_out(port, UART_IER, up->ier); } static void serial8250_enable_ms(struct uart_port *port) @@ -1336,7 +1424,10 @@ static void serial8250_enable_ms(struct uart_port *port) return; up->ier |= UART_IER_MSI; + + serial8250_rpm_get(up); serial_port_out(port, UART_IER, up->ier); + serial8250_rpm_put(up); } /* @@ -1410,7 +1501,7 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) ignore_char: lsr = serial_in(up, UART_LSR); - } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0)); + } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (--max_count > 0)); spin_unlock(&port->lock); tty_flip_buffer_push(&port->state->port); spin_lock(&port->lock); @@ -1458,11 +1549,17 @@ void serial8250_tx_chars(struct uart_8250_port *up) DEBUG_INTR("THRE..."); - if (uart_circ_empty(xmit)) + /* + * With RPM enabled, we have to wait until the FIFO is empty before the + * HW can go idle. So we get here once again with empty FIFO and disable + * the interrupt and RPM in __stop_tx() + */ + if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM)) __stop_tx(up); } EXPORT_SYMBOL_GPL(serial8250_tx_chars); +/* Caller holds uart port lock */ unsigned int serial8250_modem_status(struct uart_8250_port *up) { struct uart_port *port = &up->port; @@ -1509,13 +1606,14 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) if (status & (UART_LSR_DR | UART_LSR_BI)) { if (up->dma) - dma_err = serial8250_rx_dma(up, iir); + dma_err = up->dma->rx_dma(up, iir); if (!up->dma || dma_err) status = serial8250_rx_chars(up, status); } serial8250_modem_status(up); - if (!up->dma && (status & UART_LSR_THRE)) + if ((!up->dma || (up->dma && up->dma->tx_err)) && + (status & UART_LSR_THRE)) serial8250_tx_chars(up); spin_unlock_irqrestore(&port->lock, flags); @@ -1525,9 +1623,17 @@ EXPORT_SYMBOL_GPL(serial8250_handle_irq); static int serial8250_default_handle_irq(struct uart_port *port) { - unsigned int iir = serial_port_in(port, UART_IIR); + struct uart_8250_port *up = up_to_u8250p(port); + unsigned int iir; + int ret; + + serial8250_rpm_get(up); + + iir = serial_port_in(port, UART_IIR); + ret = serial8250_handle_irq(port, iir); - return serial8250_handle_irq(port, iir); + serial8250_rpm_put(up); + return ret; } /* @@ -1784,11 +1890,15 @@ static unsigned int serial8250_tx_empty(struct uart_port *port) unsigned long flags; unsigned int lsr; + serial8250_rpm_get(up); + spin_lock_irqsave(&port->lock, flags); lsr = serial_port_in(port, UART_LSR); up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; spin_unlock_irqrestore(&port->lock, flags); + serial8250_rpm_put(up); + return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0; } @@ -1798,7 +1908,9 @@ static unsigned int serial8250_get_mctrl(struct uart_port *port) unsigned int status; unsigned int ret; + serial8250_rpm_get(up); status = serial8250_modem_status(up); + serial8250_rpm_put(up); ret = 0; if (status & UART_MSR_DCD) @@ -1838,6 +1950,7 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state) struct uart_8250_port *up = up_to_u8250p(port); unsigned long flags; + serial8250_rpm_get(up); spin_lock_irqsave(&port->lock, flags); if (break_state == -1) up->lcr |= UART_LCR_SBC; @@ -1845,6 +1958,7 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state) up->lcr &= ~UART_LCR_SBC; serial_port_out(port, UART_LCR, up->lcr); spin_unlock_irqrestore(&port->lock, flags); + serial8250_rpm_put(up); } /* @@ -1889,12 +2003,23 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits) static int serial8250_get_poll_char(struct uart_port *port) { - unsigned char lsr = serial_port_in(port, UART_LSR); + struct uart_8250_port *up = up_to_u8250p(port); + unsigned char lsr; + int status; + + serial8250_rpm_get(up); - if (!(lsr & UART_LSR_DR)) - return NO_POLL_CHAR; + lsr = serial_port_in(port, UART_LSR); - return serial_port_in(port, UART_RX); + if (!(lsr & UART_LSR_DR)) { + status = NO_POLL_CHAR; + goto out; + } + + status = serial_port_in(port, UART_RX); +out: + serial8250_rpm_put(up); + return status; } @@ -1904,6 +2029,7 @@ static void serial8250_put_poll_char(struct uart_port *port, unsigned int ier; struct uart_8250_port *up = up_to_u8250p(port); + serial8250_rpm_get(up); /* * First save the IER then disable the interrupts */ @@ -1925,11 +2051,12 @@ static void serial8250_put_poll_char(struct uart_port *port, */ wait_for_xmitr(up, BOTH_EMPTY); serial_port_out(port, UART_IER, ier); + serial8250_rpm_put(up); } #endif /* CONFIG_CONSOLE_POLL */ -static int serial8250_startup(struct uart_port *port) +int serial8250_do_startup(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); unsigned long flags; @@ -1950,6 +2077,7 @@ static int serial8250_startup(struct uart_port *port) if (port->iotype != up->cur_iotype) set_io_from_upio(port); + serial8250_rpm_get(up); if (port->type == PORT_16C950) { /* Wake up and initialize UART */ up->acr = 0; @@ -1970,7 +2098,6 @@ static int serial8250_startup(struct uart_port *port) */ enable_rsa(up); #endif - /* * Clear the FIFO buffers and disable them. * (they will be reenabled in set_termios()) @@ -1980,8 +2107,8 @@ static int serial8250_startup(struct uart_port *port) /* * Clear the interrupt registers. */ - serial_port_in(port, UART_LSR); - serial_port_in(port, UART_RX); + if (serial_port_in(port, UART_LSR) & UART_LSR_DR) + serial_port_in(port, UART_RX); serial_port_in(port, UART_IIR); serial_port_in(port, UART_MSR); @@ -1994,7 +2121,8 @@ static int serial8250_startup(struct uart_port *port) (serial_port_in(port, UART_LSR) == 0xff)) { printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n", serial_index(port)); - return -ENODEV; + retval = -ENODEV; + goto out; } /* @@ -2079,7 +2207,7 @@ static int serial8250_startup(struct uart_port *port) } else { retval = serial_link_irq_chain(up); if (retval) - return retval; + goto out; } /* @@ -2141,8 +2269,8 @@ dont_test_tx_en: * saved flags to avoid getting false values from polling * routines or the previous session. */ - serial_port_in(port, UART_LSR); - serial_port_in(port, UART_RX); + if (serial_port_in(port, UART_LSR) & UART_LSR_DR) + serial_port_in(port, UART_RX); serial_port_in(port, UART_IIR); serial_port_in(port, UART_MSR); up->lsr_saved_flags = 0; @@ -2177,15 +2305,26 @@ dont_test_tx_en: outb_p(0x80, icp); inb_p(icp); } + retval = 0; +out: + serial8250_rpm_put(up); + return retval; +} +EXPORT_SYMBOL_GPL(serial8250_do_startup); - return 0; +static int serial8250_startup(struct uart_port *port) +{ + if (port->startup) + return port->startup(port); + return serial8250_do_startup(port); } -static void serial8250_shutdown(struct uart_port *port) +void serial8250_do_shutdown(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); unsigned long flags; + serial8250_rpm_get(up); /* * Disable interrupts from this port */ @@ -2224,13 +2363,24 @@ static void serial8250_shutdown(struct uart_port *port) * Read data port to reset things, and then unlink from * the IRQ chain. */ - serial_port_in(port, UART_RX); + if (serial_port_in(port, UART_LSR) & UART_LSR_DR) + serial_port_in(port, UART_RX); + serial8250_rpm_put(up); del_timer_sync(&up->timer); up->timer.function = serial8250_timeout; if (port->irq) serial_unlink_irq_chain(up); } +EXPORT_SYMBOL_GPL(serial8250_do_shutdown); + +static void serial8250_shutdown(struct uart_port *port) +{ + if (port->shutdown) + port->shutdown(port); + else + serial8250_do_shutdown(port); +} static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud) { @@ -2319,11 +2469,9 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, * the trigger, or the MCR RTS bit is cleared. In the case where * the remote UART is not using CTS auto flow control, we must * have sufficient FIFO entries for the latency of the remote - * UART to respond. IOW, at least 32 bytes of FIFO. Also enable - * AFE if hw flow control is supported + * UART to respond. IOW, at least 32 bytes of FIFO. */ - if ((up->capabilities & UART_CAP_AFE && (port->fifosize >= 32)) || - (port->flags & UPF_HARD_FLOW)) { + if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) { up->mcr &= ~UART_MCR_AFE; if (termios->c_cflag & CRTSCTS) up->mcr |= UART_MCR_AFE; @@ -2333,6 +2481,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, * Ok, we're now changing the port state. Do it with * interrupts disabled. */ + serial8250_rpm_get(up); spin_lock_irqsave(&port->lock, flags); /* @@ -2454,6 +2603,8 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, } serial8250_set_mctrl(port, port->mctrl); spin_unlock_irqrestore(&port->lock, flags); + serial8250_rpm_put(up); + /* Don't rewrite B0 */ if (tty_termios_baud_rate(termios)) tty_termios_encode_baud_rate(termios, baud, baud); @@ -2471,13 +2622,21 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios, } static void -serial8250_set_ldisc(struct uart_port *port, int new) +serial8250_set_ldisc(struct uart_port *port, struct ktermios *termios) { - if (new == N_PPS) { + if (termios->c_line == N_PPS) { port->flags |= UPF_HARDPPS_CD; + spin_lock_irq(&port->lock); serial8250_enable_ms(port); - } else + spin_unlock_irq(&port->lock); + } else { port->flags &= ~UPF_HARDPPS_CD; + if (!UART_ENABLE_MS(port, termios->c_cflag)) { + spin_lock_irq(&port->lock); + serial8250_disable_ms(port); + spin_unlock_irq(&port->lock); + } + } } @@ -2502,8 +2661,11 @@ serial8250_pm(struct uart_port *port, unsigned int state, static unsigned int serial8250_port_size(struct uart_8250_port *pt) { - if (pt->port.iotype == UPIO_AU) + if (pt->port.iotype == UPIO_AU) { + if (pt->port.type == PORT_RT2880) + return 0x100; return 0x1000; + } if (is_omap1_8250(pt)) return 0x16 << pt->port.regshift; @@ -2859,6 +3021,8 @@ static struct uart_ops serial8250_pops = { .get_mctrl = serial8250_get_mctrl, .stop_tx = serial8250_stop_tx, .start_tx = serial8250_start_tx, + .throttle = serial8250_throttle, + .unthrottle = serial8250_unthrottle, .stop_rx = serial8250_stop_rx, .enable_ms = serial8250_enable_ms, .break_ctl = serial8250_break_ctl, @@ -2880,6 +3044,24 @@ static struct uart_ops serial8250_pops = { static struct uart_8250_port serial8250_ports[UART_NR]; +/** + * serial8250_get_port - retrieve struct uart_8250_port + * @line: serial line number + * + * This function retrieves struct uart_8250_port for the specific line. + * This struct *must* *not* be used to perform a 8250 or serial core operation + * which is not accessible otherwise. Its only purpose is to make the struct + * accessible to the runtime-pm callbacks for context suspend/restore. + * The lock assumption made here is none because runtime-pm suspend/resume + * callbacks should not be invoked if there is any operation performed on the + * port. + */ +struct uart_8250_port *serial8250_get_port(int line) +{ + return &serial8250_ports[line]; +} +EXPORT_SYMBOL_GPL(serial8250_get_port); + static void (*serial8250_isa_config)(int port, struct uart_port *up, unsigned short *capabilities); @@ -3007,7 +3189,11 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) touch_nmi_watchdog(); - if (port->sysrq || oops_in_progress) + serial8250_rpm_get(up); + + if (port->sysrq) + locked = 0; + else if (oops_in_progress) locked = spin_trylock_irqsave(&port->lock, flags); else spin_lock_irqsave(&port->lock, flags); @@ -3043,9 +3229,10 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) if (locked) spin_unlock_irqrestore(&port->lock, flags); + serial8250_rpm_put(up); } -static int __init serial8250_console_setup(struct console *co, char *options) +static int serial8250_console_setup(struct console *co, char *options) { struct uart_port *port; int baud = 9600; @@ -3296,7 +3483,6 @@ static struct platform_driver serial8250_isa_driver = { .resume = serial8250_resume, .driver = { .name = "serial8250", - .owner = THIS_MODULE, }, }; @@ -3324,6 +3510,11 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port * if (uart_match_port(&serial8250_ports[i].port, port)) return &serial8250_ports[i]; + /* try line number first if still available */ + i = port->line; + if (i < nr_uarts && serial8250_ports[i].port.type == PORT_UNKNOWN && + serial8250_ports[i].port.iobase == 0) + return &serial8250_ports[i]; /* * We didn't find a matching entry, so look for the first * free entry. We look for one which hasn't been previously @@ -3388,6 +3579,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart->port.fifosize = up->port.fifosize; uart->tx_loadsz = up->tx_loadsz; uart->capabilities = up->capabilities; + uart->port.throttle = up->port.throttle; + uart->port.unthrottle = up->port.unthrottle; + uart->port.rs485_config = up->port.rs485_config; + uart->port.rs485 = up->port.rs485; /* Take tx_loadsz from fifosize if it wasn't set separately */ if (uart->port.fifosize && !uart->tx_loadsz) @@ -3410,6 +3605,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up) /* Possibly override set_termios call */ if (up->port.set_termios) uart->port.set_termios = up->port.set_termios; + if (up->port.startup) + uart->port.startup = up->port.startup; + if (up->port.shutdown) + uart->port.shutdown = up->port.shutdown; if (up->port.pm) uart->port.pm = up->port.pm; if (up->port.handle_break) @@ -3418,8 +3617,13 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart->dl_read = up->dl_read; if (up->dl_write) uart->dl_write = up->dl_write; - if (up->dma) + if (up->dma) { uart->dma = up->dma; + if (!uart->dma->tx_dma) + uart->dma->tx_dma = serial8250_tx_dma; + if (!uart->dma->rx_dma) + uart->dma->rx_dma = serial8250_rx_dma; + } if (serial8250_isa_config != NULL) serial8250_isa_config(0, &uart->port, @@ -3587,7 +3791,7 @@ static void __used s8250_options(void) #ifdef CONFIG_SERIAL_8250_RSA __module_param_call(MODULE_PARAM_PREFIX, probe_rsa, ¶m_array_ops, .arr = &__param_arr_probe_rsa, - 0444, -1); + 0444, -1, 0); #endif } #else diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index 148ffe4c232f..fcd7ac6af2fc 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -21,6 +21,7 @@ static void __dma_tx_complete(void *param) struct uart_8250_dma *dma = p->dma; struct circ_buf *xmit = &p->port.state->xmit; unsigned long flags; + int ret; dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr, UART_XMIT_SIZE, DMA_TO_DEVICE); @@ -36,8 +37,11 @@ static void __dma_tx_complete(void *param) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&p->port); - if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port)) - serial8250_tx_dma(p); + ret = serial8250_tx_dma(p); + if (ret) { + p->ier |= UART_IER_THRI; + serial_port_out(&p->port, UART_IER, p->ier); + } spin_unlock_irqrestore(&p->port.lock, flags); } @@ -53,6 +57,7 @@ static void __dma_rx_complete(void *param) dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr, dma->rx_size, DMA_FROM_DEVICE); + dma->rx_running = 0; dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); dmaengine_terminate_all(dma->rxchan); @@ -69,6 +74,7 @@ int serial8250_tx_dma(struct uart_8250_port *p) struct uart_8250_dma *dma = p->dma; struct circ_buf *xmit = &p->port.state->xmit; struct dma_async_tx_descriptor *desc; + int ret; if (uart_tx_stopped(&p->port) || dma->tx_running || uart_circ_empty(xmit)) @@ -80,11 +86,12 @@ int serial8250_tx_dma(struct uart_8250_port *p) dma->tx_addr + xmit->tail, dma->tx_size, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) - return -EBUSY; + if (!desc) { + ret = -EBUSY; + goto err; + } dma->tx_running = 1; - desc->callback = __dma_tx_complete; desc->callback_param = p; @@ -94,19 +101,23 @@ int serial8250_tx_dma(struct uart_8250_port *p) UART_XMIT_SIZE, DMA_TO_DEVICE); dma_async_issue_pending(dma->txchan); - + if (dma->tx_err) { + dma->tx_err = 0; + if (p->ier & UART_IER_THRI) { + p->ier &= ~UART_IER_THRI; + serial_out(p, UART_IER, p->ier); + } + } return 0; +err: + dma->tx_err = 1; + return ret; } -EXPORT_SYMBOL_GPL(serial8250_tx_dma); int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir) { struct uart_8250_dma *dma = p->dma; struct dma_async_tx_descriptor *desc; - struct dma_tx_state state; - int dma_status; - - dma_status = dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); switch (iir & 0x3f) { case UART_IIR_RLSI: @@ -117,7 +128,7 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir) * If RCVR FIFO trigger level was not reached, complete the * transfer and let 8250_core copy the remaining data. */ - if (dma_status == DMA_IN_PROGRESS) { + if (dma->rx_running) { dmaengine_pause(dma->rxchan); __dma_rx_complete(p); } @@ -126,7 +137,7 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir) break; } - if (dma_status) + if (dma->rx_running) return 0; desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr, @@ -135,6 +146,7 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir) if (!desc) return -EBUSY; + dma->rx_running = 1; desc->callback = __dma_rx_complete; desc->callback_param = p; @@ -147,7 +159,6 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir) return 0; } -EXPORT_SYMBOL_GPL(serial8250_rx_dma); int serial8250_request_dma(struct uart_8250_port *p) { diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 57d9df84ce5d..555de07db593 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -122,12 +122,43 @@ static unsigned int dw8250_serial_in(struct uart_port *p, int offset) return dw8250_modify_msr(p, offset, value); } -/* Read Back (rb) version to ensure register access ording. */ -static void dw8250_serial_out_rb(struct uart_port *p, int offset, int value) +#ifdef CONFIG_64BIT +static unsigned int dw8250_serial_inq(struct uart_port *p, int offset) { - dw8250_serial_out(p, offset, value); - dw8250_serial_in(p, UART_LCR); + unsigned int value; + + value = (u8)__raw_readq(p->membase + (offset << p->regshift)); + + return dw8250_modify_msr(p, offset, value); +} + +static void dw8250_serial_outq(struct uart_port *p, int offset, int value) +{ + struct dw8250_data *d = p->private_data; + + if (offset == UART_MCR) + d->last_mcr = value; + + value &= 0xff; + __raw_writeq(value, p->membase + (offset << p->regshift)); + /* Read back to ensure register write ordering. */ + __raw_readq(p->membase + (UART_LCR << p->regshift)); + + /* Make sure LCR write wasn't ignored */ + if (offset == UART_LCR) { + int tries = 1000; + while (tries--) { + unsigned int lcr = p->serial_in(p, UART_LCR); + if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR)) + return; + dw8250_force_idle(p); + __raw_writeq(value & 0xff, + p->membase + (UART_LCR << p->regshift)); + } + dev_err(p->dev, "Couldn't set LCR to %d\n", value); + } } +#endif /* CONFIG_64BIT */ static void dw8250_serial_out32(struct uart_port *p, int offset, int value) { @@ -216,10 +247,7 @@ out: static bool dw8250_dma_filter(struct dma_chan *chan, void *param) { - struct dw8250_data *data = param; - - return chan->chan_id == data->dma.tx_chan_id || - chan->chan_id == data->dma.rx_chan_id; + return false; } static void dw8250_setup_port(struct uart_8250_port *up) @@ -261,22 +289,19 @@ static int dw8250_probe_of(struct uart_port *p, struct uart_8250_port *up = up_to_u8250p(p); u32 val; bool has_ucv = true; + int id; +#ifdef CONFIG_64BIT if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) { -#ifdef __BIG_ENDIAN - /* - * Low order bits of these 64-bit registers, when - * accessed as a byte, are 7 bytes further down in the - * address space in big endian mode. - */ - p->membase += 7; -#endif - p->serial_out = dw8250_serial_out_rb; + p->serial_in = dw8250_serial_inq; + p->serial_out = dw8250_serial_outq; p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; p->type = PORT_OCTEON; data->usr_reg = 0x27; has_ucv = false; - } else if (!of_property_read_u32(np, "reg-io-width", &val)) { + } else +#endif + if (!of_property_read_u32(np, "reg-io-width", &val)) { switch (val) { case 1: break; @@ -293,9 +318,22 @@ static int dw8250_probe_of(struct uart_port *p, if (has_ucv) dw8250_setup_port(up); + /* if we have a valid fifosize, try hooking up DMA here */ + if (p->fifosize) { + up->dma = &data->dma; + + up->dma->rxconf.src_maxburst = p->fifosize / 4; + up->dma->txconf.dst_maxburst = p->fifosize / 4; + } + if (!of_property_read_u32(np, "reg-shift", &val)) p->regshift = val; + /* get index of serial line, if found in DT aliases */ + id = of_alias_get_id(np, "serial"); + if (id >= 0) + p->line = id; + /* clock got configured through clk api, all done */ if (p->uartclk) return 0; @@ -399,8 +437,6 @@ static int dw8250_probe(struct platform_device *pdev) if (!IS_ERR(data->rst)) reset_control_deassert(data->rst); - data->dma.rx_chan_id = -1; - data->dma.tx_chan_id = -1; data->dma.rx_param = data; data->dma.tx_param = data; data->dma.fn = dw8250_dma_filter; @@ -494,7 +530,7 @@ static int dw8250_resume(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM static int dw8250_runtime_suspend(struct device *dev) { struct dw8250_data *data = dev_get_drvdata(dev); @@ -548,7 +584,6 @@ MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match); static struct platform_driver dw8250_platform_driver = { .driver = { .name = "dw-apb-uart", - .owner = THIS_MODULE, .pm = &dw8250_pm_ops, .of_match_table = dw8250_of_match, .acpi_match_table = ACPI_PTR(dw8250_acpi_match), diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c index 56c87232b6a0..ae5eaed6aa85 100644 --- a/drivers/tty/serial/8250/8250_em.c +++ b/drivers/tty/serial/8250/8250_em.c @@ -102,10 +102,8 @@ static int serial8250_em_probe(struct platform_device *pdev) } priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(&pdev->dev, "unable to allocate private data\n"); + if (!priv) return -ENOMEM; - } priv->sclk = devm_clk_get(&pdev->dev, "sclk"); if (IS_ERR(priv->sclk)) { @@ -161,7 +159,6 @@ static struct platform_driver serial8250_em_platform_driver = { .driver = { .name = "serial8250-em", .of_match_table = serial8250_em_dt_ids, - .owner = THIS_MODULE, }, .probe = serial8250_em_probe, .remove = serial8250_em_remove, diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c new file mode 100644 index 000000000000..1e6899bc9429 --- /dev/null +++ b/drivers/tty/serial/8250/8250_fintek.c @@ -0,0 +1,251 @@ +/* + * Probe for F81216A LPC to 4 UART + * + * Based on drivers/tty/serial/8250_pnp.c, by Russell King, et al + * + * Copyright (C) 2014 Ricardo Ribalda, Qtechnology A/S + * + * + * 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. + */ +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/pnp.h> +#include <linux/kernel.h> +#include <linux/serial_core.h> +#include "8250.h" + +#define ADDR_PORT 0x4E +#define DATA_PORT 0x4F +#define ENTRY_KEY 0x77 +#define EXIT_KEY 0xAA +#define CHIP_ID1 0x20 +#define CHIP_ID1_VAL 0x02 +#define CHIP_ID2 0x21 +#define CHIP_ID2_VAL 0x16 +#define VENDOR_ID1 0x23 +#define VENDOR_ID1_VAL 0x19 +#define VENDOR_ID2 0x24 +#define VENDOR_ID2_VAL 0x34 +#define LDN 0x7 + +#define RS485 0xF0 +#define RTS_INVERT BIT(5) +#define RS485_URA BIT(4) +#define RXW4C_IRA BIT(3) +#define TXW4C_IRA BIT(2) + +#define DRIVER_NAME "8250_fintek" + +static int fintek_8250_enter_key(void){ + + if (!request_muxed_region(ADDR_PORT, 2, DRIVER_NAME)) + return -EBUSY; + + outb(ENTRY_KEY, ADDR_PORT); + outb(ENTRY_KEY, ADDR_PORT); + return 0; +} + +static void fintek_8250_exit_key(void){ + + outb(EXIT_KEY, ADDR_PORT); + release_region(ADDR_PORT, 2); +} + +static int fintek_8250_get_index(resource_size_t base_addr) +{ + resource_size_t base[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8}; + int i; + + for (i = 0; i < ARRAY_SIZE(base); i++) + if (base_addr == base[i]) + return i; + + return -ENODEV; +} + +static int fintek_8250_check_id(void) +{ + + outb(CHIP_ID1, ADDR_PORT); + if (inb(DATA_PORT) != CHIP_ID1_VAL) + return -ENODEV; + + outb(CHIP_ID2, ADDR_PORT); + if (inb(DATA_PORT) != CHIP_ID2_VAL) + return -ENODEV; + + outb(VENDOR_ID1, ADDR_PORT); + if (inb(DATA_PORT) != VENDOR_ID1_VAL) + return -ENODEV; + + outb(VENDOR_ID2, ADDR_PORT); + if (inb(DATA_PORT) != VENDOR_ID2_VAL) + return -ENODEV; + + return 0; +} + +static int fintek_8250_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + uint8_t config = 0; + int index = fintek_8250_get_index(port->iobase); + + if (index < 0) + return -EINVAL; + + if (rs485->flags & SER_RS485_ENABLED) + memset(rs485->padding, 0, sizeof(rs485->padding)); + else + memset(rs485, 0, sizeof(*rs485)); + + rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | + SER_RS485_RTS_AFTER_SEND; + + if (rs485->delay_rts_before_send) { + rs485->delay_rts_before_send = 1; + config |= TXW4C_IRA; + } + + if (rs485->delay_rts_after_send) { + rs485->delay_rts_after_send = 1; + config |= RXW4C_IRA; + } + + if ((!!(rs485->flags & SER_RS485_RTS_ON_SEND)) == + (!!(rs485->flags & SER_RS485_RTS_AFTER_SEND))) + rs485->flags &= SER_RS485_ENABLED; + else + config |= RS485_URA; + + if (rs485->flags & SER_RS485_RTS_ON_SEND) + config |= RTS_INVERT; + + if (fintek_8250_enter_key()) + return -EBUSY; + + outb(LDN, ADDR_PORT); + outb(index, DATA_PORT); + outb(RS485, ADDR_PORT); + outb(config, DATA_PORT); + fintek_8250_exit_key(); + + port->rs485 = *rs485; + + return 0; +} + +static int +fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) +{ + int line; + struct uart_8250_port uart; + int ret; + + if (!pnp_port_valid(dev, 0)) + return -ENODEV; + + if (fintek_8250_get_index(pnp_port_start(dev, 0)) < 0) + return -ENODEV; + + /* Enable configuration registers*/ + if (fintek_8250_enter_key()) + return -EBUSY; + + /*Check ID*/ + ret = fintek_8250_check_id(); + fintek_8250_exit_key(); + if (ret) + return ret; + + memset(&uart, 0, sizeof(uart)); + if (!pnp_irq_valid(dev, 0)) + return -ENODEV; + uart.port.irq = pnp_irq(dev, 0); + uart.port.iobase = pnp_port_start(dev, 0); + uart.port.iotype = UPIO_PORT; + uart.port.rs485_config = fintek_8250_rs485_config; + + uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; + if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE) + uart.port.flags |= UPF_SHARE_IRQ; + uart.port.uartclk = 1843200; + uart.port.dev = &dev->dev; + + line = serial8250_register_8250_port(&uart); + if (line < 0) + return -ENODEV; + + pnp_set_drvdata(dev, (void *)((long)line + 1)); + return 0; +} + +static void fintek_8250_remove(struct pnp_dev *dev) +{ + long line = (long)pnp_get_drvdata(dev); + + if (line) + serial8250_unregister_port(line - 1); +} + +#ifdef CONFIG_PM +static int fintek_8250_suspend(struct pnp_dev *dev, pm_message_t state) +{ + long line = (long)pnp_get_drvdata(dev); + + if (!line) + return -ENODEV; + serial8250_suspend_port(line - 1); + return 0; +} + +static int fintek_8250_resume(struct pnp_dev *dev) +{ + long line = (long)pnp_get_drvdata(dev); + + if (!line) + return -ENODEV; + serial8250_resume_port(line - 1); + return 0; +} +#else +#define fintek_8250_suspend NULL +#define fintek_8250_resume NULL +#endif /* CONFIG_PM */ + +static const struct pnp_device_id fintek_dev_table[] = { + /* Qtechnology Panel PC / IO1000 */ + { "PNP0501"}, + {} +}; + +MODULE_DEVICE_TABLE(pnp, fintek_dev_table); + +static struct pnp_driver fintek_8250_driver = { + .name = DRIVER_NAME, + .probe = fintek_8250_probe, + .remove = fintek_8250_remove, + .suspend = fintek_8250_suspend, + .resume = fintek_8250_resume, + .id_table = fintek_dev_table, +}; + +static int fintek_8250_init(void) +{ + return pnp_register_driver(&fintek_8250_driver); +} +module_init(fintek_8250_init); + +static void fintek_8250_exit(void) +{ + pnp_unregister_driver(&fintek_8250_driver); +} +module_exit(fintek_8250_exit); + +MODULE_DESCRIPTION("Fintek F812164 module"); +MODULE_AUTHOR("Ricardo Ribalda <ricardo.ribalda@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250/8250_hp300.c b/drivers/tty/serial/8250/8250_hp300.c index 5bdaf271d395..b4882082b247 100644 --- a/drivers/tty/serial/8250/8250_hp300.c +++ b/drivers/tty/serial/8250/8250_hp300.c @@ -21,7 +21,7 @@ #include "8250.h" #if !defined(CONFIG_HPDCA) && !defined(CONFIG_HPAPCI) -#warning CONFIG_8250 defined but neither CONFIG_HPDCA nor CONFIG_HPAPCI defined, are you sure? +#warning CONFIG_SERIAL_8250 defined but neither CONFIG_HPDCA nor CONFIG_HPAPCI defined, are you sure? #endif #ifdef CONFIG_HPAPCI @@ -88,10 +88,6 @@ extern int hp300_uart_scode; /* * Parse the bootinfo to find descriptions for headless console and * debug serial ports and register them with the 8250 driver. - * This function should be called before serial_console_init() is called - * to make sure the serial console will be available for use. IA-64 kernel - * calls this function from setup_arch() after the EFI and ACPI tables have - * been parsed. */ int __init hp300_setup_serial_console(void) { diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c new file mode 100644 index 000000000000..7a11fac775c4 --- /dev/null +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -0,0 +1,294 @@ +/* + * Mediatek 8250 driver. + * + * Copyright (c) 2014 MundoReader S.L. + * Author: Matthias Brugger <matthias.bgg@gmail.com> + * + * 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/clk.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/serial_8250.h> +#include <linux/serial_reg.h> + +#include "8250.h" + +#define UART_MTK_HIGHS 0x09 /* Highspeed register */ +#define UART_MTK_SAMPLE_COUNT 0x0a /* Sample count register */ +#define UART_MTK_SAMPLE_POINT 0x0b /* Sample point register */ +#define MTK_UART_RATE_FIX 0x0d /* UART Rate Fix Register */ + +struct mtk8250_data { + int line; + struct clk *uart_clk; +}; + +static void +mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + unsigned long flags; + unsigned int baud, quot; + + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + serial8250_do_set_termios(port, termios, old); + + /* + * Mediatek UARTs use an extra highspeed register (UART_MTK_HIGHS) + * + * We need to recalcualte the quot register, as the claculation depends + * on the vaule in the highspeed register. + * + * Some baudrates are not supported by the chip, so we use the next + * lower rate supported and update termios c_flag. + * + * If highspeed register is set to 3, we need to specify sample count + * and sample point to increase accuracy. If not, we reset the + * registers to their default values. + */ + baud = uart_get_baud_rate(port, termios, old, + port->uartclk / 16 / 0xffff, + port->uartclk / 16); + + if (baud <= 115200) { + serial_port_out(port, UART_MTK_HIGHS, 0x0); + quot = uart_get_divisor(port, baud); + } else if (baud <= 576000) { + serial_port_out(port, UART_MTK_HIGHS, 0x2); + + /* Set to next lower baudrate supported */ + if ((baud == 500000) || (baud == 576000)) + baud = 460800; + quot = DIV_ROUND_UP(port->uartclk, 4 * baud); + } else { + serial_port_out(port, UART_MTK_HIGHS, 0x3); + + /* Set to highest baudrate supported */ + if (baud >= 1152000) + baud = 921600; + quot = DIV_ROUND_UP(port->uartclk, 256 * baud); + } + + /* + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ + spin_lock_irqsave(&port->lock, flags); + + /* set DLAB we have cval saved in up->lcr from the call to the core */ + serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB); + serial_dl_write(up, quot); + + /* reset DLAB */ + serial_port_out(port, UART_LCR, up->lcr); + + if (baud > 460800) { + unsigned int tmp; + + tmp = DIV_ROUND_CLOSEST(port->uartclk, quot * baud); + serial_port_out(port, UART_MTK_SAMPLE_COUNT, tmp - 1); + serial_port_out(port, UART_MTK_SAMPLE_POINT, + (tmp - 2) >> 1); + } else { + serial_port_out(port, UART_MTK_SAMPLE_COUNT, 0x00); + serial_port_out(port, UART_MTK_SAMPLE_POINT, 0xff); + } + + 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 void +mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) +{ + if (!state) + pm_runtime_get_sync(port->dev); + + serial8250_do_pm(port, state, old); + + if (state) + pm_runtime_put_sync_suspend(port->dev); +} + +static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p, + struct mtk8250_data *data) +{ + int err; + struct device_node *np = pdev->dev.of_node; + + data->uart_clk = of_clk_get(np, 0); + if (IS_ERR(data->uart_clk)) { + dev_warn(&pdev->dev, "Can't get timer clock\n"); + return PTR_ERR(data->uart_clk); + } + + err = clk_prepare_enable(data->uart_clk); + if (err) { + dev_warn(&pdev->dev, "Can't prepare clock\n"); + clk_put(data->uart_clk); + return err; + } + p->uartclk = clk_get_rate(data->uart_clk); + + return 0; +} + +static int mtk8250_probe(struct platform_device *pdev) +{ + 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 mtk8250_data *data; + int err; + + if (!regs || !irq) { + dev_err(&pdev->dev, "no registers/irq defined\n"); + return -EINVAL; + } + + uart.port.membase = devm_ioremap(&pdev->dev, regs->start, + resource_size(regs)); + if (!uart.port.membase) + return -ENOMEM; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + if (pdev->dev.of_node) { + err = mtk8250_probe_of(pdev, &uart.port, data); + if (err) + return err; + } else + return -ENODEV; + + spin_lock_init(&uart.port.lock); + uart.port.mapbase = regs->start; + uart.port.irq = irq->start; + uart.port.pm = mtk8250_do_pm; + uart.port.type = PORT_16550; + uart.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT; + uart.port.dev = &pdev->dev; + uart.port.iotype = UPIO_MEM32; + uart.port.regshift = 2; + uart.port.private_data = data; + uart.port.set_termios = mtk8250_set_termios; + + /* Disable Rate Fix function */ + writel(0x0, uart.port.membase + + (MTK_UART_RATE_FIX << uart.port.regshift)); + + data->line = serial8250_register_8250_port(&uart); + if (data->line < 0) + return data->line; + + platform_set_drvdata(pdev, data); + + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + return 0; +} + +static int mtk8250_remove(struct platform_device *pdev) +{ + struct mtk8250_data *data = platform_get_drvdata(pdev); + + pm_runtime_get_sync(&pdev->dev); + + serial8250_unregister_port(data->line); + if (!IS_ERR(data->uart_clk)) { + clk_disable_unprepare(data->uart_clk); + clk_put(data->uart_clk); + } + + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int mtk8250_suspend(struct device *dev) +{ + struct mtk8250_data *data = dev_get_drvdata(dev); + + serial8250_suspend_port(data->line); + + return 0; +} + +static int mtk8250_resume(struct device *dev) +{ + struct mtk8250_data *data = dev_get_drvdata(dev); + + serial8250_resume_port(data->line); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +#ifdef CONFIG_PM +static int mtk8250_runtime_suspend(struct device *dev) +{ + struct mtk8250_data *data = dev_get_drvdata(dev); + + if (!IS_ERR(data->uart_clk)) + clk_disable_unprepare(data->uart_clk); + + return 0; +} + +static int mtk8250_runtime_resume(struct device *dev) +{ + struct mtk8250_data *data = dev_get_drvdata(dev); + + if (!IS_ERR(data->uart_clk)) + clk_prepare_enable(data->uart_clk); + + return 0; +} +#endif + +static const struct dev_pm_ops mtk8250_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(mtk8250_suspend, mtk8250_resume) + SET_RUNTIME_PM_OPS(mtk8250_runtime_suspend, mtk8250_runtime_resume, + NULL) +}; + +static const struct of_device_id mtk8250_of_match[] = { + { .compatible = "mediatek,mt6577-uart" }, + { /* Sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mtk8250_of_match); + +static struct platform_driver mtk8250_platform_driver = { + .driver = { + .name = "mt6577-uart", + .pm = &mtk8250_pm_ops, + .of_match_table = mtk8250_of_match, + }, + .probe = mtk8250_probe, + .remove = mtk8250_remove, +}; +module_platform_driver(mtk8250_platform_driver); + +MODULE_AUTHOR("Matthias Brugger"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Mediatek 8250 serial port driver"); diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c new file mode 100644 index 000000000000..96b69bfd773f --- /dev/null +++ b/drivers/tty/serial/8250/8250_omap.c @@ -0,0 +1,1281 @@ +/* + * 8250-core based driver for the OMAP internal UART + * + * based on omap-serial.c, Copyright (C) 2010 Texas Instruments. + * + * Copyright (C) 2014 Sebastian Andrzej Siewior + * + */ + +#include <linux/device.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/serial_8250.h> +#include <linux/serial_core.h> +#include <linux/serial_reg.h> +#include <linux/tty_flip.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/of_irq.h> +#include <linux/delay.h> +#include <linux/pm_runtime.h> +#include <linux/console.h> +#include <linux/pm_qos.h> +#include <linux/dma-mapping.h> + +#include "8250.h" + +#define DEFAULT_CLK_SPEED 48000000 + +#define UART_ERRATA_i202_MDR1_ACCESS (1 << 0) +#define OMAP_UART_WER_HAS_TX_WAKEUP (1 << 1) +#define OMAP_DMA_TX_KICK (1 << 2) + +#define OMAP_UART_FCR_RX_TRIG 6 +#define OMAP_UART_FCR_TX_TRIG 4 + +/* SCR register bitmasks */ +#define OMAP_UART_SCR_RX_TRIG_GRANU1_MASK (1 << 7) +#define OMAP_UART_SCR_TX_TRIG_GRANU1_MASK (1 << 6) +#define OMAP_UART_SCR_TX_EMPTY (1 << 3) +#define OMAP_UART_SCR_DMAMODE_MASK (3 << 1) +#define OMAP_UART_SCR_DMAMODE_1 (1 << 1) +#define OMAP_UART_SCR_DMAMODE_CTL (1 << 0) + +/* MVR register bitmasks */ +#define OMAP_UART_MVR_SCHEME_SHIFT 30 +#define OMAP_UART_LEGACY_MVR_MAJ_MASK 0xf0 +#define OMAP_UART_LEGACY_MVR_MAJ_SHIFT 4 +#define OMAP_UART_LEGACY_MVR_MIN_MASK 0x0f +#define OMAP_UART_MVR_MAJ_MASK 0x700 +#define OMAP_UART_MVR_MAJ_SHIFT 8 +#define OMAP_UART_MVR_MIN_MASK 0x3f + +#define UART_TI752_TLR_TX 0 +#define UART_TI752_TLR_RX 4 + +#define TRIGGER_TLR_MASK(x) ((x & 0x3c) >> 2) +#define TRIGGER_FCR_MASK(x) (x & 3) + +/* Enable XON/XOFF flow control on output */ +#define OMAP_UART_SW_TX 0x08 +/* Enable XON/XOFF flow control on input */ +#define OMAP_UART_SW_RX 0x02 + +#define OMAP_UART_WER_MOD_WKUP 0x7f +#define OMAP_UART_TX_WAKEUP_EN (1 << 7) + +#define TX_TRIGGER 1 +#define RX_TRIGGER 48 + +#define OMAP_UART_TCR_RESTORE(x) ((x / 4) << 4) +#define OMAP_UART_TCR_HALT(x) ((x / 4) << 0) + +#define UART_BUILD_REVISION(x, y) (((x) << 8) | (y)) + +#define OMAP_UART_REV_46 0x0406 +#define OMAP_UART_REV_52 0x0502 +#define OMAP_UART_REV_63 0x0603 + +struct omap8250_priv { + int line; + u8 habit; + u8 mdr1; + u8 efr; + u8 scr; + u8 wer; + u8 xon; + u8 xoff; + u8 delayed_restore; + u16 quot; + + bool is_suspending; + int wakeirq; + int wakeups_enabled; + u32 latency; + u32 calc_latency; + struct pm_qos_request pm_qos_request; + struct work_struct qos_work; + struct uart_8250_dma omap8250_dma; +}; + +static u32 uart_read(struct uart_8250_port *up, u32 reg) +{ + return readl(up->port.membase + (reg << up->port.regshift)); +} + +/* + * Work Around for Errata i202 (2430, 3430, 3630, 4430 and 4460) + * The access to uart register after MDR1 Access + * causes UART to corrupt data. + * + * Need a delay = + * 5 L4 clock cycles + 5 UART functional clock cycle (@48MHz = ~0.2uS) + * give 10 times as much + */ +static void omap_8250_mdr1_errataset(struct uart_8250_port *up, + struct omap8250_priv *priv) +{ + u8 timeout = 255; + u8 old_mdr1; + + old_mdr1 = serial_in(up, UART_OMAP_MDR1); + if (old_mdr1 == priv->mdr1) + return; + + serial_out(up, UART_OMAP_MDR1, priv->mdr1); + udelay(2); + serial_out(up, UART_FCR, up->fcr | UART_FCR_CLEAR_XMIT | + UART_FCR_CLEAR_RCVR); + /* + * Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and + * TX_FIFO_E bit is 1. + */ + while (UART_LSR_THRE != (serial_in(up, UART_LSR) & + (UART_LSR_THRE | UART_LSR_DR))) { + timeout--; + if (!timeout) { + /* Should *never* happen. we warn and carry on */ + dev_crit(up->port.dev, "Errata i202: timedout %x\n", + serial_in(up, UART_LSR)); + break; + } + udelay(1); + } +} + +static void omap_8250_get_divisor(struct uart_port *port, unsigned int baud, + struct omap8250_priv *priv) +{ + unsigned int uartclk = port->uartclk; + unsigned int div_13, div_16; + unsigned int abs_d13, abs_d16; + + /* + * Old custom speed handling. + */ + if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) { + priv->quot = port->custom_divisor & 0xffff; + /* + * I assume that nobody is using this. But hey, if somebody + * would like to specify the divisor _and_ the mode then the + * driver is ready and waiting for it. + */ + if (port->custom_divisor & (1 << 16)) + priv->mdr1 = UART_OMAP_MDR1_13X_MODE; + else + priv->mdr1 = UART_OMAP_MDR1_16X_MODE; + return; + } + div_13 = DIV_ROUND_CLOSEST(uartclk, 13 * baud); + div_16 = DIV_ROUND_CLOSEST(uartclk, 16 * baud); + + if (!div_13) + div_13 = 1; + if (!div_16) + div_16 = 1; + + abs_d13 = abs(baud - uartclk / 13 / div_13); + abs_d16 = abs(baud - uartclk / 16 / div_16); + + if (abs_d13 >= abs_d16) { + priv->mdr1 = UART_OMAP_MDR1_16X_MODE; + priv->quot = div_16; + } else { + priv->mdr1 = UART_OMAP_MDR1_13X_MODE; + priv->quot = div_13; + } +} + +static void omap8250_update_scr(struct uart_8250_port *up, + struct omap8250_priv *priv) +{ + u8 old_scr; + + old_scr = serial_in(up, UART_OMAP_SCR); + if (old_scr == priv->scr) + return; + + /* + * The manual recommends not to enable the DMA mode selector in the SCR + * (instead of the FCR) register _and_ selecting the DMA mode as one + * register write because this may lead to malfunction. + */ + if (priv->scr & OMAP_UART_SCR_DMAMODE_MASK) + serial_out(up, UART_OMAP_SCR, + priv->scr & ~OMAP_UART_SCR_DMAMODE_MASK); + serial_out(up, UART_OMAP_SCR, priv->scr); +} + +static void omap8250_restore_regs(struct uart_8250_port *up) +{ + struct omap8250_priv *priv = up->port.private_data; + struct uart_8250_dma *dma = up->dma; + + if (dma && dma->tx_running) { + /* + * TCSANOW requests the change to occur immediately however if + * we have a TX-DMA operation in progress then it has been + * observed that it might stall and never complete. Therefore we + * delay DMA completes to prevent this hang from happen. + */ + priv->delayed_restore = 1; + return; + } + + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, UART_EFR_ECB); + + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + serial_out(up, UART_MCR, UART_MCR_TCRTLR); + serial_out(up, UART_FCR, up->fcr); + + omap8250_update_scr(up, priv); + + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + + serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_RESTORE(16) | + OMAP_UART_TCR_HALT(52)); + serial_out(up, UART_TI752_TLR, + TRIGGER_TLR_MASK(TX_TRIGGER) << UART_TI752_TLR_TX | + TRIGGER_TLR_MASK(RX_TRIGGER) << UART_TI752_TLR_RX); + + serial_out(up, UART_LCR, 0); + + /* drop TCR + TLR access, we setup XON/XOFF later */ + serial_out(up, UART_MCR, up->mcr); + serial_out(up, UART_IER, up->ier); + + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_dl_write(up, priv->quot); + + serial_out(up, UART_EFR, priv->efr); + + /* Configure flow control */ + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_XON1, priv->xon); + serial_out(up, UART_XOFF1, priv->xoff); + + serial_out(up, UART_LCR, up->lcr); + /* need mode A for FCR */ + if (priv->habit & UART_ERRATA_i202_MDR1_ACCESS) + omap_8250_mdr1_errataset(up, priv); + else + serial_out(up, UART_OMAP_MDR1, priv->mdr1); + up->port.ops->set_mctrl(&up->port, up->port.mctrl); +} + +/* + * OMAP can use "CLK / (16 or 13) / div" for baud rate. And then we have have + * some differences in how we want to handle flow control. + */ +static void omap_8250_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + struct omap8250_priv *priv = up->port.private_data; + unsigned char cval = 0; + unsigned int baud; + + switch (termios->c_cflag & CSIZE) { + case CS5: + cval = UART_LCR_WLEN5; + break; + case CS6: + cval = UART_LCR_WLEN6; + break; + case CS7: + cval = UART_LCR_WLEN7; + break; + default: + case CS8: + cval = UART_LCR_WLEN8; + break; + } + + if (termios->c_cflag & CSTOPB) + cval |= UART_LCR_STOP; + if (termios->c_cflag & PARENB) + cval |= UART_LCR_PARITY; + if (!(termios->c_cflag & PARODD)) + cval |= UART_LCR_EPAR; + if (termios->c_cflag & CMSPAR) + cval |= UART_LCR_SPAR; + + /* + * Ask the core to calculate the divisor for us. + */ + baud = uart_get_baud_rate(port, termios, old, + port->uartclk / 16 / 0xffff, + port->uartclk / 13); + omap_8250_get_divisor(port, baud, priv); + + /* + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ + pm_runtime_get_sync(port->dev); + spin_lock_irq(&port->lock); + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); + + up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; + if (termios->c_iflag & INPCK) + up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; + if (termios->c_iflag & (IGNBRK | PARMRK)) + up->port.read_status_mask |= UART_LSR_BI; + + /* + * Characters to ignore + */ + up->port.ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + if (termios->c_iflag & IGNBRK) { + up->port.ignore_status_mask |= UART_LSR_BI; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + up->port.ignore_status_mask |= UART_LSR_OE; + } + + /* + * ignore all characters if CREAD is not set + */ + if ((termios->c_cflag & CREAD) == 0) + up->port.ignore_status_mask |= UART_LSR_DR; + + /* + * Modem status interrupts + */ + up->ier &= ~UART_IER_MSI; + if (UART_ENABLE_MS(&up->port, termios->c_cflag)) + up->ier |= UART_IER_MSI; + + up->lcr = cval; + /* Up to here it was mostly serial8250_do_set_termios() */ + + /* + * We enable TRIG_GRANU for RX and TX and additionaly we set + * SCR_TX_EMPTY bit. The result is the following: + * - RX_TRIGGER amount of bytes in the FIFO will cause an interrupt. + * - less than RX_TRIGGER number of bytes will also cause an interrupt + * once the UART decides that there no new bytes arriving. + * - Once THRE is enabled, the interrupt will be fired once the FIFO is + * empty - the trigger level is ignored here. + * + * Once DMA is enabled: + * - UART will assert the TX DMA line once there is room for TX_TRIGGER + * bytes in the TX FIFO. On each assert the DMA engine will move + * TX_TRIGGER bytes into the FIFO. + * - UART will assert the RX DMA line once there are RX_TRIGGER bytes in + * the FIFO and move RX_TRIGGER bytes. + * This is because threshold and trigger values are the same. + */ + up->fcr = UART_FCR_ENABLE_FIFO; + up->fcr |= TRIGGER_FCR_MASK(TX_TRIGGER) << OMAP_UART_FCR_TX_TRIG; + up->fcr |= TRIGGER_FCR_MASK(RX_TRIGGER) << OMAP_UART_FCR_RX_TRIG; + + priv->scr = OMAP_UART_SCR_RX_TRIG_GRANU1_MASK | OMAP_UART_SCR_TX_EMPTY | + OMAP_UART_SCR_TX_TRIG_GRANU1_MASK; + + if (up->dma) + priv->scr |= OMAP_UART_SCR_DMAMODE_1 | + OMAP_UART_SCR_DMAMODE_CTL; + + priv->xon = termios->c_cc[VSTART]; + priv->xoff = termios->c_cc[VSTOP]; + + priv->efr = 0; + up->mcr &= ~(UART_MCR_RTS | UART_MCR_XONANY); + if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) { + /* Enable AUTORTS and AUTOCTS */ + priv->efr |= UART_EFR_CTS | UART_EFR_RTS; + + /* Ensure MCR RTS is asserted */ + up->mcr |= UART_MCR_RTS; + } else if (up->port.flags & UPF_SOFT_FLOW) { + /* + * IXON Flag: + * Enable XON/XOFF flow control on input. + * Receiver compares XON1, XOFF1. + */ + if (termios->c_iflag & IXON) + priv->efr |= OMAP_UART_SW_RX; + + /* + * IXOFF Flag: + * Enable XON/XOFF flow control on output. + * Transmit XON1, XOFF1 + */ + if (termios->c_iflag & IXOFF) + priv->efr |= OMAP_UART_SW_TX; + + /* + * IXANY Flag: + * Enable any character to restart output. + * Operation resumes after receiving any + * character after recognition of the XOFF character + */ + if (termios->c_iflag & IXANY) + up->mcr |= UART_MCR_XONANY; + } + omap8250_restore_regs(up); + + spin_unlock_irq(&up->port.lock); + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); + + /* calculate wakeup latency constraint */ + priv->calc_latency = USEC_PER_SEC * 64 * 8 / baud; + priv->latency = priv->calc_latency; + + schedule_work(&priv->qos_work); + + /* Don't rewrite B0 */ + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); +} + +/* same as 8250 except that we may have extra flow bits set in EFR */ +static void omap_8250_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + struct omap8250_priv *priv = up->port.private_data; + + pm_runtime_get_sync(port->dev); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, priv->efr | UART_EFR_ECB); + serial_out(up, UART_LCR, 0); + + serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, priv->efr); + serial_out(up, UART_LCR, 0); + + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); +} + +static void omap_serial_fill_features_erratas(struct uart_8250_port *up, + struct omap8250_priv *priv) +{ + u32 mvr, scheme; + u16 revision, major, minor; + + mvr = uart_read(up, UART_OMAP_MVER); + + /* Check revision register scheme */ + scheme = mvr >> OMAP_UART_MVR_SCHEME_SHIFT; + + switch (scheme) { + case 0: /* Legacy Scheme: OMAP2/3 */ + /* MINOR_REV[0:4], MAJOR_REV[4:7] */ + major = (mvr & OMAP_UART_LEGACY_MVR_MAJ_MASK) >> + OMAP_UART_LEGACY_MVR_MAJ_SHIFT; + minor = (mvr & OMAP_UART_LEGACY_MVR_MIN_MASK); + break; + case 1: + /* New Scheme: OMAP4+ */ + /* MINOR_REV[0:5], MAJOR_REV[8:10] */ + major = (mvr & OMAP_UART_MVR_MAJ_MASK) >> + OMAP_UART_MVR_MAJ_SHIFT; + minor = (mvr & OMAP_UART_MVR_MIN_MASK); + break; + default: + dev_warn(up->port.dev, + "Unknown revision, defaulting to highest\n"); + /* highest possible revision */ + major = 0xff; + minor = 0xff; + } + /* normalize revision for the driver */ + revision = UART_BUILD_REVISION(major, minor); + + switch (revision) { + case OMAP_UART_REV_46: + priv->habit = UART_ERRATA_i202_MDR1_ACCESS; + break; + case OMAP_UART_REV_52: + priv->habit = UART_ERRATA_i202_MDR1_ACCESS | + OMAP_UART_WER_HAS_TX_WAKEUP; + break; + case OMAP_UART_REV_63: + priv->habit = UART_ERRATA_i202_MDR1_ACCESS | + OMAP_UART_WER_HAS_TX_WAKEUP; + break; + default: + break; + } +} + +static void omap8250_uart_qos_work(struct work_struct *work) +{ + struct omap8250_priv *priv; + + priv = container_of(work, struct omap8250_priv, qos_work); + pm_qos_update_request(&priv->pm_qos_request, priv->latency); +} + +static irqreturn_t omap_wake_irq(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + int ret; + + ret = port->handle_irq(port); + if (ret) + return IRQ_HANDLED; + return IRQ_NONE; +} + +static int omap_8250_startup(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + struct omap8250_priv *priv = port->private_data; + + int ret; + + if (priv->wakeirq) { + ret = request_irq(priv->wakeirq, omap_wake_irq, + port->irqflags, "uart wakeup irq", port); + if (ret) + return ret; + disable_irq(priv->wakeirq); + } + + pm_runtime_get_sync(port->dev); + + ret = serial8250_do_startup(port); + if (ret) + goto err; + +#ifdef CONFIG_PM + up->capabilities |= UART_CAP_RPM; +#endif + + /* Enable module level wake up */ + priv->wer = OMAP_UART_WER_MOD_WKUP; + if (priv->habit & OMAP_UART_WER_HAS_TX_WAKEUP) + priv->wer |= OMAP_UART_TX_WAKEUP_EN; + serial_out(up, UART_OMAP_WER, priv->wer); + + if (up->dma) + up->dma->rx_dma(up, 0); + + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); + return 0; +err: + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); + if (priv->wakeirq) + free_irq(priv->wakeirq, port); + return ret; +} + +static void omap_8250_shutdown(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + struct omap8250_priv *priv = port->private_data; + + flush_work(&priv->qos_work); + if (up->dma) + up->dma->rx_dma(up, UART_IIR_RX_TIMEOUT); + + pm_runtime_get_sync(port->dev); + + serial_out(up, UART_OMAP_WER, 0); + serial8250_do_shutdown(port); + + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); + + if (priv->wakeirq) + free_irq(priv->wakeirq, port); +} + +static void omap_8250_throttle(struct uart_port *port) +{ + unsigned long flags; + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + pm_runtime_get_sync(port->dev); + + spin_lock_irqsave(&port->lock, flags); + up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); + serial_out(up, UART_IER, up->ier); + spin_unlock_irqrestore(&port->lock, flags); + + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); +} + +static void omap_8250_unthrottle(struct uart_port *port) +{ + unsigned long flags; + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + pm_runtime_get_sync(port->dev); + + spin_lock_irqsave(&port->lock, flags); + up->ier |= UART_IER_RLSI | UART_IER_RDI; + serial_out(up, UART_IER, up->ier); + spin_unlock_irqrestore(&port->lock, flags); + + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); +} + +#ifdef CONFIG_SERIAL_8250_DMA +static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir); + +static void __dma_rx_do_complete(struct uart_8250_port *p, bool error) +{ + struct uart_8250_dma *dma = p->dma; + struct tty_port *tty_port = &p->port.state->port; + struct dma_tx_state state; + int count; + + dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr, + dma->rx_size, DMA_FROM_DEVICE); + + dma->rx_running = 0; + dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); + dmaengine_terminate_all(dma->rxchan); + + count = dma->rx_size - state.residue; + + tty_insert_flip_string(tty_port, dma->rx_buf, count); + p->port.icount.rx += count; + if (!error) + omap_8250_rx_dma(p, 0); + + tty_flip_buffer_push(tty_port); +} + +static void __dma_rx_complete(void *param) +{ + __dma_rx_do_complete(param, false); +} + +static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir) +{ + struct uart_8250_dma *dma = p->dma; + struct dma_async_tx_descriptor *desc; + + switch (iir & 0x3f) { + case UART_IIR_RLSI: + /* 8250_core handles errors and break interrupts */ + if (dma->rx_running) { + dmaengine_pause(dma->rxchan); + __dma_rx_do_complete(p, true); + } + return -EIO; + case UART_IIR_RX_TIMEOUT: + /* + * If RCVR FIFO trigger level was not reached, complete the + * transfer and let 8250_core copy the remaining data. + */ + if (dma->rx_running) { + dmaengine_pause(dma->rxchan); + __dma_rx_do_complete(p, true); + } + return -ETIMEDOUT; + case UART_IIR_RDI: + /* + * The OMAP UART is a special BEAST. If we receive RDI we _have_ + * a DMA transfer programmed but it didn't work. One reason is + * that we were too slow and there were too many bytes in the + * FIFO, the UART counted wrong and never kicked the DMA engine + * to do anything. That means once we receive RDI on OMAP then + * the DMA won't do anything soon so we have to cancel the DMA + * transfer and purge the FIFO manually. + */ + if (dma->rx_running) { + dmaengine_pause(dma->rxchan); + __dma_rx_do_complete(p, true); + } + return -ETIMEDOUT; + + default: + break; + } + + if (dma->rx_running) + return 0; + + desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr, + dma->rx_size, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) + return -EBUSY; + + dma->rx_running = 1; + desc->callback = __dma_rx_complete; + desc->callback_param = p; + + dma->rx_cookie = dmaengine_submit(desc); + + dma_sync_single_for_device(dma->rxchan->device->dev, dma->rx_addr, + dma->rx_size, DMA_FROM_DEVICE); + + dma_async_issue_pending(dma->rxchan); + return 0; +} + +static int omap_8250_tx_dma(struct uart_8250_port *p); + +static void omap_8250_dma_tx_complete(void *param) +{ + struct uart_8250_port *p = param; + struct uart_8250_dma *dma = p->dma; + struct circ_buf *xmit = &p->port.state->xmit; + unsigned long flags; + bool en_thri = false; + struct omap8250_priv *priv = p->port.private_data; + + dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr, + UART_XMIT_SIZE, DMA_TO_DEVICE); + + spin_lock_irqsave(&p->port.lock, flags); + + dma->tx_running = 0; + + xmit->tail += dma->tx_size; + xmit->tail &= UART_XMIT_SIZE - 1; + p->port.icount.tx += dma->tx_size; + + if (priv->delayed_restore) { + priv->delayed_restore = 0; + omap8250_restore_regs(p); + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&p->port); + + if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port)) { + int ret; + + ret = omap_8250_tx_dma(p); + if (ret) + en_thri = true; + + } else if (p->capabilities & UART_CAP_RPM) { + en_thri = true; + } + + if (en_thri) { + dma->tx_err = 1; + p->ier |= UART_IER_THRI; + serial_port_out(&p->port, UART_IER, p->ier); + } + + spin_unlock_irqrestore(&p->port.lock, flags); +} + +static int omap_8250_tx_dma(struct uart_8250_port *p) +{ + struct uart_8250_dma *dma = p->dma; + struct omap8250_priv *priv = p->port.private_data; + struct circ_buf *xmit = &p->port.state->xmit; + struct dma_async_tx_descriptor *desc; + unsigned int skip_byte = 0; + int ret; + + if (dma->tx_running) + return 0; + if (uart_tx_stopped(&p->port) || uart_circ_empty(xmit)) { + + /* + * Even if no data, we need to return an error for the two cases + * below so serial8250_tx_chars() is invoked and properly clears + * THRI and/or runtime suspend. + */ + if (dma->tx_err || p->capabilities & UART_CAP_RPM) { + ret = -EBUSY; + goto err; + } + if (p->ier & UART_IER_THRI) { + p->ier &= ~UART_IER_THRI; + serial_out(p, UART_IER, p->ier); + } + return 0; + } + + dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + if (priv->habit & OMAP_DMA_TX_KICK) { + u8 tx_lvl; + + /* + * We need to put the first byte into the FIFO in order to start + * the DMA transfer. For transfers smaller than four bytes we + * don't bother doing DMA at all. It seem not matter if there + * are still bytes in the FIFO from the last transfer (in case + * we got here directly from omap_8250_dma_tx_complete()). Bytes + * leaving the FIFO seem not to trigger the DMA transfer. It is + * really the byte that we put into the FIFO. + * If the FIFO is already full then we most likely got here from + * omap_8250_dma_tx_complete(). And this means the DMA engine + * just completed its work. We don't have to wait the complete + * 86us at 115200,8n1 but around 60us (not to mention lower + * baudrates). So in that case we take the interrupt and try + * again with an empty FIFO. + */ + tx_lvl = serial_in(p, UART_OMAP_TX_LVL); + if (tx_lvl == p->tx_loadsz) { + ret = -EBUSY; + goto err; + } + if (dma->tx_size < 4) { + ret = -EINVAL; + goto err; + } + skip_byte = 1; + } + + desc = dmaengine_prep_slave_single(dma->txchan, + dma->tx_addr + xmit->tail + skip_byte, + dma->tx_size - skip_byte, DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + ret = -EBUSY; + goto err; + } + + dma->tx_running = 1; + + desc->callback = omap_8250_dma_tx_complete; + desc->callback_param = p; + + dma->tx_cookie = dmaengine_submit(desc); + + dma_sync_single_for_device(dma->txchan->device->dev, dma->tx_addr, + UART_XMIT_SIZE, DMA_TO_DEVICE); + + dma_async_issue_pending(dma->txchan); + if (dma->tx_err) + dma->tx_err = 0; + + if (p->ier & UART_IER_THRI) { + p->ier &= ~UART_IER_THRI; + serial_out(p, UART_IER, p->ier); + } + if (skip_byte) + serial_out(p, UART_TX, xmit->buf[xmit->tail]); + return 0; +err: + dma->tx_err = 1; + return ret; +} + +/* + * This is mostly serial8250_handle_irq(). We have a slightly different DMA + * hoook for RX/TX and need different logic for them in the ISR. Therefore we + * use the default routine in the non-DMA case and this one for with DMA. + */ +static int omap_8250_dma_handle_irq(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned char status; + unsigned long flags; + u8 iir; + int dma_err = 0; + + serial8250_rpm_get(up); + + iir = serial_port_in(port, UART_IIR); + if (iir & UART_IIR_NO_INT) { + serial8250_rpm_put(up); + return 0; + } + + spin_lock_irqsave(&port->lock, flags); + + status = serial_port_in(port, UART_LSR); + + if (status & (UART_LSR_DR | UART_LSR_BI)) { + + dma_err = omap_8250_rx_dma(up, iir); + if (dma_err) { + status = serial8250_rx_chars(up, status); + omap_8250_rx_dma(up, 0); + } + } + serial8250_modem_status(up); + if (status & UART_LSR_THRE && up->dma->tx_err) { + if (uart_tx_stopped(&up->port) || + uart_circ_empty(&up->port.state->xmit)) { + up->dma->tx_err = 0; + serial8250_tx_chars(up); + } else { + /* + * try again due to an earlier failer which + * might have been resolved by now. + */ + dma_err = omap_8250_tx_dma(up); + if (dma_err) + serial8250_tx_chars(up); + } + } + + spin_unlock_irqrestore(&port->lock, flags); + serial8250_rpm_put(up); + return 1; +} + +static bool the_no_dma_filter_fn(struct dma_chan *chan, void *param) +{ + return false; +} + +#else + +static inline int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir) +{ + return -EINVAL; +} +#endif + +static int omap8250_probe(struct platform_device *pdev) +{ + struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + struct omap8250_priv *priv; + struct uart_8250_port up; + int ret; + void __iomem *membase; + + if (!regs || !irq) { + dev_err(&pdev->dev, "missing registers or irq\n"); + return -EINVAL; + } + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + membase = devm_ioremap_nocache(&pdev->dev, regs->start, + resource_size(regs)); + if (!membase) + return -ENODEV; + + memset(&up, 0, sizeof(up)); + up.port.dev = &pdev->dev; + up.port.mapbase = regs->start; + up.port.membase = membase; + up.port.irq = irq->start; + /* + * It claims to be 16C750 compatible however it is a little different. + * It has EFR and has no FCR7_64byte bit. The AFE (which it claims to + * have) is enabled via EFR instead of MCR. The type is set here 8250 + * just to get things going. UNKNOWN does not work for a few reasons and + * we don't need our own type since we don't use 8250's set_termios() + * or pm callback. + */ + up.port.type = PORT_8250; + up.port.iotype = UPIO_MEM; + up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SOFT_FLOW | + UPF_HARD_FLOW; + up.port.private_data = priv; + + up.port.regshift = 2; + up.port.fifosize = 64; + up.tx_loadsz = 64; + up.capabilities = UART_CAP_FIFO; +#ifdef CONFIG_PM + /* + * Runtime PM is mostly transparent. However to do it right we need to a + * TX empty interrupt before we can put the device to auto idle. So if + * PM is not enabled we don't add that flag and can spare that one extra + * interrupt in the TX path. + */ + up.capabilities |= UART_CAP_RPM; +#endif + up.port.set_termios = omap_8250_set_termios; + up.port.pm = omap_8250_pm; + up.port.startup = omap_8250_startup; + up.port.shutdown = omap_8250_shutdown; + up.port.throttle = omap_8250_throttle; + up.port.unthrottle = omap_8250_unthrottle; + + if (pdev->dev.of_node) { + ret = of_alias_get_id(pdev->dev.of_node, "serial"); + + of_property_read_u32(pdev->dev.of_node, "clock-frequency", + &up.port.uartclk); + priv->wakeirq = irq_of_parse_and_map(pdev->dev.of_node, 1); + } else { + ret = pdev->id; + } + if (ret < 0) { + dev_err(&pdev->dev, "failed to get alias/pdev id\n"); + return ret; + } + up.port.line = ret; + + if (!up.port.uartclk) { + up.port.uartclk = DEFAULT_CLK_SPEED; + dev_warn(&pdev->dev, + "No clock speed specified: using default: %d\n", + DEFAULT_CLK_SPEED); + } + + priv->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; + priv->calc_latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; + pm_qos_add_request(&priv->pm_qos_request, PM_QOS_CPU_DMA_LATENCY, + priv->latency); + INIT_WORK(&priv->qos_work, omap8250_uart_qos_work); + + device_init_wakeup(&pdev->dev, true); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, -1); + + pm_runtime_irq_safe(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + pm_runtime_get_sync(&pdev->dev); + + omap_serial_fill_features_erratas(&up, priv); +#ifdef CONFIG_SERIAL_8250_DMA + if (pdev->dev.of_node) { + /* + * Oh DMA support. If there are no DMA properties in the DT then + * we will fall back to a generic DMA channel which does not + * really work here. To ensure that we do not get a generic DMA + * channel assigned, we have the the_no_dma_filter_fn() here. + * To avoid "failed to request DMA" messages we check for DMA + * properties in DT. + */ + ret = of_property_count_strings(pdev->dev.of_node, "dma-names"); + if (ret == 2) { + up.dma = &priv->omap8250_dma; + up.port.handle_irq = omap_8250_dma_handle_irq; + priv->omap8250_dma.fn = the_no_dma_filter_fn; + priv->omap8250_dma.tx_dma = omap_8250_tx_dma; + priv->omap8250_dma.rx_dma = omap_8250_rx_dma; + priv->omap8250_dma.rx_size = RX_TRIGGER; + priv->omap8250_dma.rxconf.src_maxburst = RX_TRIGGER; + priv->omap8250_dma.txconf.dst_maxburst = TX_TRIGGER; + + if (of_machine_is_compatible("ti,am33xx")) + priv->habit |= OMAP_DMA_TX_KICK; + } + } +#endif + ret = serial8250_register_8250_port(&up); + if (ret < 0) { + dev_err(&pdev->dev, "unable to register 8250 port\n"); + goto err; + } + priv->line = ret; + platform_set_drvdata(pdev, priv); + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + return 0; +err: + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); + return ret; +} + +static int omap8250_remove(struct platform_device *pdev) +{ + struct omap8250_priv *priv = platform_get_drvdata(pdev); + + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + serial8250_unregister_port(priv->line); + pm_qos_remove_request(&priv->pm_qos_request); + device_init_wakeup(&pdev->dev, false); + return 0; +} + +#ifdef CONFIG_PM + +static inline void omap8250_enable_wakeirq(struct omap8250_priv *priv, + bool enable) +{ + if (!priv->wakeirq) + return; + + if (enable) + enable_irq(priv->wakeirq); + else + disable_irq_nosync(priv->wakeirq); +} + +static void omap8250_enable_wakeup(struct omap8250_priv *priv, + bool enable) +{ + if (enable == priv->wakeups_enabled) + return; + + omap8250_enable_wakeirq(priv, enable); + priv->wakeups_enabled = enable; +} +#endif + +#ifdef CONFIG_PM_SLEEP +static int omap8250_prepare(struct device *dev) +{ + struct omap8250_priv *priv = dev_get_drvdata(dev); + + if (!priv) + return 0; + priv->is_suspending = true; + return 0; +} + +static void omap8250_complete(struct device *dev) +{ + struct omap8250_priv *priv = dev_get_drvdata(dev); + + if (!priv) + return; + priv->is_suspending = false; +} + +static int omap8250_suspend(struct device *dev) +{ + struct omap8250_priv *priv = dev_get_drvdata(dev); + + serial8250_suspend_port(priv->line); + flush_work(&priv->qos_work); + + if (device_may_wakeup(dev)) + omap8250_enable_wakeup(priv, true); + else + omap8250_enable_wakeup(priv, false); + return 0; +} + +static int omap8250_resume(struct device *dev) +{ + struct omap8250_priv *priv = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + omap8250_enable_wakeup(priv, false); + + serial8250_resume_port(priv->line); + return 0; +} +#else +#define omap8250_prepare NULL +#define omap8250_complete NULL +#endif + +#ifdef CONFIG_PM +static int omap8250_lost_context(struct uart_8250_port *up) +{ + u32 val; + + val = serial_in(up, UART_OMAP_MDR1); + /* + * If we lose context, then MDR1 is set to its reset value which is + * UART_OMAP_MDR1_DISABLE. After set_termios() we set it either to 13x + * or 16x but never to disable again. + */ + if (val == UART_OMAP_MDR1_DISABLE) + return 1; + return 0; +} + +static int omap8250_runtime_suspend(struct device *dev) +{ + struct omap8250_priv *priv = dev_get_drvdata(dev); + struct uart_8250_port *up; + + up = serial8250_get_port(priv->line); + /* + * When using 'no_console_suspend', the console UART must not be + * suspended. Since driver suspend is managed by runtime suspend, + * preventing runtime suspend (by returning error) will keep device + * active during suspend. + */ + if (priv->is_suspending && !console_suspend_enabled) { + if (uart_console(&up->port)) + return -EBUSY; + } + + omap8250_enable_wakeup(priv, true); + if (up->dma) + omap_8250_rx_dma(up, UART_IIR_RX_TIMEOUT); + + priv->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; + schedule_work(&priv->qos_work); + + return 0; +} + +static int omap8250_runtime_resume(struct device *dev) +{ + struct omap8250_priv *priv = dev_get_drvdata(dev); + struct uart_8250_port *up; + int loss_cntx; + + /* In case runtime-pm tries this before we are setup */ + if (!priv) + return 0; + + up = serial8250_get_port(priv->line); + omap8250_enable_wakeup(priv, false); + loss_cntx = omap8250_lost_context(up); + + if (loss_cntx) + omap8250_restore_regs(up); + + if (up->dma) + omap_8250_rx_dma(up, 0); + + priv->latency = priv->calc_latency; + schedule_work(&priv->qos_work); + return 0; +} +#endif + +static const struct dev_pm_ops omap8250_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(omap8250_suspend, omap8250_resume) + SET_RUNTIME_PM_OPS(omap8250_runtime_suspend, + omap8250_runtime_resume, NULL) + .prepare = omap8250_prepare, + .complete = omap8250_complete, +}; + +static const struct of_device_id omap8250_dt_ids[] = { + { .compatible = "ti,omap2-uart" }, + { .compatible = "ti,omap3-uart" }, + { .compatible = "ti,omap4-uart" }, + {}, +}; +MODULE_DEVICE_TABLE(of, omap8250_dt_ids); + +static struct platform_driver omap8250_platform_driver = { + .driver = { + .name = "omap8250", + .pm = &omap8250_dev_pm_ops, + .of_match_table = omap8250_dt_ids, + .owner = THIS_MODULE, + }, + .probe = omap8250_probe, + .remove = omap8250_remove, +}; +module_platform_driver(omap8250_platform_driver); + +MODULE_AUTHOR("Sebastian Andrzej Siewior"); +MODULE_DESCRIPTION("OMAP 8250 Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 61830b1792eb..31feeb2d0a66 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -25,6 +25,9 @@ #include <asm/byteorder.h> #include <asm/io.h> +#include <linux/dmaengine.h> +#include <linux/platform_data/dma-dw.h> + #include "8250.h" /* @@ -76,29 +79,24 @@ setup_port(struct serial_private *priv, struct uart_8250_port *port, int bar, int offset, int regshift) { struct pci_dev *dev = priv->dev; - unsigned long base, len; if (bar >= PCI_NUM_BAR_RESOURCES) return -EINVAL; - base = pci_resource_start(dev, bar); - if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) { - len = pci_resource_len(dev, bar); - if (!priv->remapped_bar[bar]) - priv->remapped_bar[bar] = ioremap_nocache(base, len); + priv->remapped_bar[bar] = pci_ioremap_bar(dev, bar); if (!priv->remapped_bar[bar]) return -ENOMEM; port->port.iotype = UPIO_MEM; port->port.iobase = 0; - port->port.mapbase = base + offset; + port->port.mapbase = pci_resource_start(dev, bar) + offset; port->port.membase = priv->remapped_bar[bar] + offset; port->port.regshift = regshift; } else { port->port.iotype = UPIO_PORT; - port->port.iobase = base + offset; + port->port.iobase = pci_resource_start(dev, bar) + offset; port->port.mapbase = 0; port->port.membase = NULL; port->port.regshift = 0; @@ -314,7 +312,6 @@ static void pci_plx9050_exit(struct pci_dev *dev) static void pci_ni8420_exit(struct pci_dev *dev) { void __iomem *p; - unsigned long base, len; unsigned int bar = 0; if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) { @@ -322,9 +319,7 @@ static void pci_ni8420_exit(struct pci_dev *dev) return; } - base = pci_resource_start(dev, bar); - len = pci_resource_len(dev, bar); - p = ioremap_nocache(base, len); + p = pci_ioremap_bar(dev, bar); if (p == NULL) return; @@ -346,7 +341,6 @@ static void pci_ni8420_exit(struct pci_dev *dev) static void pci_ni8430_exit(struct pci_dev *dev) { void __iomem *p; - unsigned long base, len; unsigned int bar = 0; if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) { @@ -354,9 +348,7 @@ static void pci_ni8430_exit(struct pci_dev *dev) return; } - base = pci_resource_start(dev, bar); - len = pci_resource_len(dev, bar); - p = ioremap_nocache(base, len); + p = pci_ioremap_bar(dev, bar); if (p == NULL) return; @@ -679,7 +671,6 @@ static int pci_xircom_init(struct pci_dev *dev) static int pci_ni8420_init(struct pci_dev *dev) { void __iomem *p; - unsigned long base, len; unsigned int bar = 0; if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) { @@ -687,9 +678,7 @@ static int pci_ni8420_init(struct pci_dev *dev) return 0; } - base = pci_resource_start(dev, bar); - len = pci_resource_len(dev, bar); - p = ioremap_nocache(base, len); + p = pci_ioremap_bar(dev, bar); if (p == NULL) return -ENOMEM; @@ -711,7 +700,7 @@ static int pci_ni8420_init(struct pci_dev *dev) static int pci_ni8430_init(struct pci_dev *dev) { void __iomem *p; - unsigned long base, len; + struct pci_bus_region region; u32 device_window; unsigned int bar = 0; @@ -720,14 +709,17 @@ static int pci_ni8430_init(struct pci_dev *dev) return 0; } - base = pci_resource_start(dev, bar); - len = pci_resource_len(dev, bar); - p = ioremap_nocache(base, len); + p = pci_ioremap_bar(dev, bar); if (p == NULL) return -ENOMEM; - /* Set device window address and size in BAR0 */ - device_window = ((base + MITE_IOWBSR1_WIN_OFFSET) & 0xffffff00) + /* + * Set device window address and size in BAR0, while acknowledging that + * the resource structure may contain a translated address that differs + * from the address the device responds to. + */ + pcibios_resource_to_bus(dev->bus, ®ion, &dev->resource[bar]); + device_window = ((region.start + MITE_IOWBSR1_WIN_OFFSET) & 0xffffff00) | MITE_IOWBSR1_WENAB | MITE_IOWBSR1_WSIZE; writel(device_window, p + MITE_IOWBSR1); @@ -754,8 +746,8 @@ pci_ni8430_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { + struct pci_dev *dev = priv->dev; void __iomem *p; - unsigned long base, len; unsigned int bar, offset = board->first_offset; if (idx >= board->num_ports) @@ -764,9 +756,9 @@ pci_ni8430_setup(struct serial_private *priv, bar = FL_GET_BASE(board->flags); offset += idx * board->uart_offset; - base = pci_resource_start(priv->dev, bar); - len = pci_resource_len(priv->dev, bar); - p = ioremap_nocache(base, len); + p = pci_ioremap_bar(dev, bar); + if (!p) + return -ENOMEM; /* enable the transceiver */ writeb(readb(p + offset + NI8430_PORTCON) | NI8430_PORTCON_TXVR_ENABLE, @@ -1000,6 +992,40 @@ static void pci_ite887x_exit(struct pci_dev *dev) } /* + * EndRun Technologies. + * Determine the number of ports available on the device. + */ +#define PCI_VENDOR_ID_ENDRUN 0x7401 +#define PCI_DEVICE_ID_ENDRUN_1588 0xe100 + +static int pci_endrun_init(struct pci_dev *dev) +{ + u8 __iomem *p; + unsigned long deviceID; + unsigned int number_uarts = 0; + + /* EndRun device is all 0xexxx */ + if (dev->vendor == PCI_VENDOR_ID_ENDRUN && + (dev->device & 0xf000) != 0xe000) + return 0; + + p = pci_iomap(dev, 0, 5); + if (p == NULL) + return -ENOMEM; + + deviceID = ioread32(p); + /* EndRun device */ + if (deviceID == 0x07000200) { + number_uarts = ioread8(p + 4); + dev_dbg(&dev->dev, + "%d ports detected on EndRun PCI Express device\n", + number_uarts); + } + pci_iounmap(dev, p); + return number_uarts; +} + +/* * Oxford Semiconductor Inc. * Check that device is part of the Tornado range of devices, then determine * the number of ports available on the device. @@ -1349,15 +1375,15 @@ ce4100_serial_setup(struct serial_private *priv, #define PCI_DEVICE_ID_INTEL_BYT_UART1 0x0f0a #define PCI_DEVICE_ID_INTEL_BYT_UART2 0x0f0c +#define PCI_DEVICE_ID_INTEL_BSW_UART1 0x228a +#define PCI_DEVICE_ID_INTEL_BSW_UART2 0x228c + #define BYT_PRV_CLK 0x800 #define BYT_PRV_CLK_EN (1 << 0) #define BYT_PRV_CLK_M_VAL_SHIFT 1 #define BYT_PRV_CLK_N_VAL_SHIFT 16 #define BYT_PRV_CLK_UPDATE (1 << 31) -#define BYT_GENERAL_REG 0x808 -#define BYT_GENERAL_DIS_RTS_N_OVERRIDE (1 << 3) - #define BYT_TX_OVF_INT 0x820 #define BYT_TX_OVF_INT_MASK (1 << 1) @@ -1412,22 +1438,18 @@ byt_set_termios(struct uart_port *p, struct ktermios *termios, reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE; writel(reg, p->membase + BYT_PRV_CLK); - /* - * If auto-handshake mechanism is not enabled, - * disable rts_n override - */ - reg = readl(p->membase + BYT_GENERAL_REG); - reg &= ~BYT_GENERAL_DIS_RTS_N_OVERRIDE; - if (termios->c_cflag & CRTSCTS) - reg |= BYT_GENERAL_DIS_RTS_N_OVERRIDE; - writel(reg, p->membase + BYT_GENERAL_REG); - serial8250_do_set_termios(p, termios, old); } static bool byt_dma_filter(struct dma_chan *chan, void *param) { - return chan->chan_id == *(int *)param; + struct dw_dma_slave *dws = param; + + if (dws->dma_dev != chan->device->dev) + return false; + + chan->private = dws; + return true; } static int @@ -1435,35 +1457,57 @@ byt_serial_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { + struct pci_dev *pdev = priv->dev; + struct device *dev = port->port.dev; struct uart_8250_dma *dma; + struct dw_dma_slave *tx_param, *rx_param; + struct pci_dev *dma_dev; int ret; - dma = devm_kzalloc(port->port.dev, sizeof(*dma), GFP_KERNEL); + dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); if (!dma) return -ENOMEM; - switch (priv->dev->device) { + tx_param = devm_kzalloc(dev, sizeof(*tx_param), GFP_KERNEL); + if (!tx_param) + return -ENOMEM; + + rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL); + if (!rx_param) + return -ENOMEM; + + switch (pdev->device) { case PCI_DEVICE_ID_INTEL_BYT_UART1: - dma->rx_chan_id = 3; - dma->tx_chan_id = 2; + case PCI_DEVICE_ID_INTEL_BSW_UART1: + rx_param->src_id = 3; + tx_param->dst_id = 2; break; case PCI_DEVICE_ID_INTEL_BYT_UART2: - dma->rx_chan_id = 5; - dma->tx_chan_id = 4; + case PCI_DEVICE_ID_INTEL_BSW_UART2: + rx_param->src_id = 5; + tx_param->dst_id = 4; break; default: return -EINVAL; } - dma->rxconf.slave_id = dma->rx_chan_id; + rx_param->src_master = 1; + rx_param->dst_master = 0; + dma->rxconf.src_maxburst = 16; - dma->txconf.slave_id = dma->tx_chan_id; + tx_param->src_master = 1; + tx_param->dst_master = 0; + dma->txconf.dst_maxburst = 16; + dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), 0)); + rx_param->dma_dev = &dma_dev->dev; + tx_param->dma_dev = &dma_dev->dev; + dma->fn = byt_dma_filter; - dma->rx_param = &dma->rx_chan_id; - dma->tx_param = &dma->tx_chan_id; + dma->rx_param = rx_param; + dma->tx_param = tx_param; ret = pci_default_setup(priv, board, port, idx); port->port.iotype = UPIO_MEM; @@ -1510,25 +1554,48 @@ static int pci_fintek_setup(struct serial_private *priv, unsigned long iobase; unsigned long ciobase = 0; u8 config_base; + u32 bar_data[3]; /* - * We are supposed to be able to read these from the PCI config space, - * but the values there don't seem to match what we need to use, so - * just use these hard-coded values for now, as they are correct. + * Find each UARTs offset in PCI configuraion space */ switch (idx) { - case 0: iobase = 0xe000; config_base = 0x40; break; - case 1: iobase = 0xe008; config_base = 0x48; break; - case 2: iobase = 0xe010; config_base = 0x50; break; - case 3: iobase = 0xe018; config_base = 0x58; break; - case 4: iobase = 0xe020; config_base = 0x60; break; - case 5: iobase = 0xe028; config_base = 0x68; break; - case 6: iobase = 0xe030; config_base = 0x70; break; - case 7: iobase = 0xe038; config_base = 0x78; break; - case 8: iobase = 0xe040; config_base = 0x80; break; - case 9: iobase = 0xe048; config_base = 0x88; break; - case 10: iobase = 0xe050; config_base = 0x90; break; - case 11: iobase = 0xe058; config_base = 0x98; break; + case 0: + config_base = 0x40; + break; + case 1: + config_base = 0x48; + break; + case 2: + config_base = 0x50; + break; + case 3: + config_base = 0x58; + break; + case 4: + config_base = 0x60; + break; + case 5: + config_base = 0x68; + break; + case 6: + config_base = 0x70; + break; + case 7: + config_base = 0x78; + break; + case 8: + config_base = 0x80; + break; + case 9: + config_base = 0x88; + break; + case 10: + config_base = 0x90; + break; + case 11: + config_base = 0x98; + break; default: /* Unknown number of ports, get out of here */ return -EINVAL; @@ -1539,6 +1606,14 @@ static int pci_fintek_setup(struct serial_private *priv, ciobase = (int)(base + (0x8 * idx)); } + /* Get the io address dispatch from the BIOS */ + pci_read_config_dword(pdev, 0x24, &bar_data[0]); + pci_read_config_dword(pdev, 0x20, &bar_data[1]); + pci_read_config_dword(pdev, 0x1c, &bar_data[2]); + + /* Calculate Real IO Port */ + iobase = (bar_data[idx/4] & 0xffffffe0) + (idx % 4) * 8; + dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%lx ciobase=0x%lx config_base=0x%2x\n", __func__, idx, iobase, ciobase, config_base); @@ -1739,6 +1814,16 @@ pci_wch_ch353_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } +static int +pci_wch_ch382_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + port->port.flags |= UPF_FIXED_TYPE; + port->port.type = PORT_16850; + return pci_default_setup(priv, board, port, idx); +} + #define PCI_VENDOR_ID_SBSMODULARIO 0x124B #define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B #define PCI_DEVICE_ID_OCTPRO 0x0001 @@ -1788,10 +1873,13 @@ pci_wch_ch353_setup(struct serial_private *priv, #define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0022 #define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a #define PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800 0x818e +#define PCI_DEVICE_ID_INTEL_QRK_UART 0x0936 #define PCI_VENDOR_ID_SUNIX 0x1fd4 #define PCI_DEVICE_ID_SUNIX_1999 0x1999 +#define PCIE_VENDOR_ID_WCH 0x1c00 +#define PCIE_DEVICE_ID_WCH_CH382_2S1P 0x3250 /* Unknown vendors/cards - this should not be in linux/pci_ids.h */ #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 @@ -1898,6 +1986,27 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .setup = byt_serial_setup, }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_QRK_UART, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_default_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_BSW_UART1, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = byt_serial_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_BSW_UART2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = byt_serial_setup, + }, /* * ITE */ @@ -2303,6 +2412,17 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .setup = pci_netmos_9900_setup, }, /* + * EndRun Technologies + */ + { + .vendor = PCI_VENDOR_ID_ENDRUN, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_endrun_init, + .setup = pci_default_setup, + }, + /* * For Oxford Semiconductor Tornado based devices */ { @@ -2451,6 +2571,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .setup = pci_wch_ch353_setup, }, + /* WCH CH382 2S1P card (16750 clone) */ + { + .vendor = PCIE_VENDOR_ID_WCH, + .device = PCIE_DEVICE_ID_WCH_CH382_2S1P, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_wch_ch382_setup, + }, /* * ASIX devices with FIFO bug */ @@ -2711,6 +2839,7 @@ enum pci_board_num_t { pbn_panacom2, pbn_panacom4, pbn_plx_romulus, + pbn_endrun_2_4000000, pbn_oxsemi, pbn_oxsemi_1_4000000, pbn_oxsemi_2_4000000, @@ -2740,6 +2869,7 @@ enum pci_board_num_t { pbn_ADDIDATA_PCIe_8_3906250, pbn_ce4100_1_115200, pbn_byt, + pbn_qrk, pbn_omegapci, pbn_NETMOS9900_2s_115200, pbn_brcm_trumanage, @@ -3255,6 +3385,20 @@ static struct pciserial_board pci_boards[] = { }, /* + * EndRun Technologies + * Uses the size of PCI Base region 0 to + * signal now many ports are available + * 2 port 952 Uart support + */ + [pbn_endrun_2_4000000] = { + .flags = FL_BASE0, + .num_ports = 2, + .base_baud = 4000000, + .uart_offset = 0x200, + .first_offset = 0x1000, + }, + + /* * This board uses the size of PCI Base region 0 to * signal now many ports are available */ @@ -3490,6 +3634,12 @@ static struct pciserial_board pci_boards[] = { .uart_offset = 0x80, .reg_shift = 2, }, + [pbn_qrk] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 2764800, + .reg_shift = 2, + }, [pbn_omegapci] = { .flags = FL_BASE0, .num_ports = 8, @@ -3536,6 +3686,7 @@ static const struct pci_device_id blacklist[] = { /* multi-io cards handled by parport_serial */ { PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */ { PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */ + { PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */ }; /* @@ -4121,6 +4272,13 @@ static struct pci_device_id serial_pci_tbl[] = { 0x10b5, 0x106a, 0, 0, pbn_plx_romulus }, /* + * EndRun Technologies. PCI express device range. + * EndRun PTP/1588 has 2 Native UARTs. + */ + { PCI_VENDOR_ID_ENDRUN, PCI_DEVICE_ID_ENDRUN_1588, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_endrun_2_4000000 }, + /* * Quatech cards. These actually have configurable clocks but for * now we just use the default. * @@ -5190,8 +5348,22 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000, pbn_byt }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW_UART1, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000, + pbn_byt }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW_UART2, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000, + pbn_byt }, /* + * Intel Quark x1000 + */ + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_UART, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_qrk }, + /* * Cronyx Omega PCI */ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_CRONYX_OMEGA, diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 349ee598b34c..0fcbcd29502f 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -293,8 +293,32 @@ config SERIAL_8250_EM config SERIAL_8250_RT288X bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support" - depends on SERIAL_8250 && (SOC_RT288X || SOC_RT305X || SOC_RT3883) + depends on SERIAL_8250 && (SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620) help If you have a Ralink RT288x/RT305x SoC based board and want to use the serial port, say Y to this option. The driver can handle up to 2 serial ports. If unsure, say N. + +config SERIAL_8250_OMAP + tristate "Support for OMAP internal UART (8250 based driver)" + depends on SERIAL_8250 && ARCH_OMAP2PLUS + help + If you have a machine based on an Texas Instruments OMAP CPU you + can enable its onboard serial ports by enabling this option. + + This driver uses ttyS instead of ttyO. + +config SERIAL_8250_FINTEK + tristate "Support for Fintek F81216A LPC to 4 UART" + depends on SERIAL_8250 && PNP + help + Selecting this option will add support for the Fintek F81216A + LPC to 4 UART. This device has some RS485 functionality not available + through the PNP driver. If unsure, say N. + +config SERIAL_8250_MT6577 + bool "Mediatek serial port support" + depends on SERIAL_8250 && ARCH_MEDIATEK + help + If you have a Mediatek based board and want to use the + serial port, say Y to this option. If unsure, say N. diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index 36d68d054307..31e7cdc6865c 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -20,3 +20,6 @@ obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o +obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o +obj-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o +obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 26cec64dadd7..c79b43cd6014 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -200,10 +200,29 @@ config SERIAL_KS8695_CONSOLE receives all kernel messages and warnings and which allows logins in single user mode). +config SERIAL_MESON + tristate "Meson serial port support" + depends on ARCH_MESON + select SERIAL_CORE + help + This enables the driver for the on-chip UARTs of the Amlogic + MesonX processors. + +config SERIAL_MESON_CONSOLE + bool "Support for console on meson" + depends on SERIAL_MESON=y + select SERIAL_CORE_CONSOLE + help + Say Y here if you wish to use a Amlogic MesonX UART as the + system console (the system console is the device which + receives all kernel messages and warnings and which allows + logins in single user mode) as /dev/ttyAMLx. + config SERIAL_CLPS711X tristate "CLPS711X serial port support" depends on ARCH_CLPS711X || COMPILE_TEST select SERIAL_CORE + select SERIAL_MCTRL_GPIO if GPIOLIB help This enables the driver for the on-chip UARTs of the Cirrus Logic EP711x/EP721x/EP731x processors. @@ -220,7 +239,7 @@ config SERIAL_CLPS711X_CONSOLE config SERIAL_SAMSUNG tristate "Samsung SoC serial support" - depends on PLAT_SAMSUNG + depends on PLAT_SAMSUNG || ARCH_EXYNOS select SERIAL_CORE help Support for the on-chip UARTs on the Samsung S3C24XX series CPUs, @@ -230,14 +249,14 @@ config SERIAL_SAMSUNG config SERIAL_SAMSUNG_UARTS_4 bool - depends on PLAT_SAMSUNG + depends on SERIAL_SAMSUNG default y if !(CPU_S3C2410 || CPU_S3C2412 || CPU_S3C2440 || CPU_S3C2442) help Internal node for the common case of 4 Samsung compatible UARTs config SERIAL_SAMSUNG_UARTS int - depends on PLAT_SAMSUNG + depends on SERIAL_SAMSUNG default 4 if SERIAL_SAMSUNG_UARTS_4 || CPU_S3C2416 default 3 help @@ -682,7 +701,7 @@ config PDC_CONSOLE Saying Y here will enable the software based PDC console to be used as the system console. This is useful for machines in which the hardware based console has not been written yet. The - following steps must be competed to use the PDC console: + following steps must be completed to use the PDC console: 1. create the device entry (mknod /dev/ttyB0 c 11 0) 2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0 @@ -1010,11 +1029,11 @@ config SERIAL_VR41XX_CONSOLE a console on a serial port, say Y. Otherwise, say N. config SERIAL_JSM - tristate "Digi International NEO PCI Support" + tristate "Digi International NEO and Classic PCI Support" depends on PCI select SERIAL_CORE help - This is a driver for Digi International's Neo series + This is a driver for Digi International's Neo and Classic series of cards which provide multiple serial ports. You would need something like this to connect more than two modems to your Linux box, for instance in order to become a dial-in server. This driver @@ -1051,6 +1070,7 @@ config SERIAL_MSM_CONSOLE bool "MSM serial console support" depends on SERIAL_MSM=y select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON config SERIAL_MSM_HS tristate "MSM UART High Speed: Serial Driver" @@ -1261,22 +1281,25 @@ config SERIAL_TIMBERDALE Add support for UART controller on timberdale. config SERIAL_BCM63XX - tristate "bcm63xx serial port support" + tristate "Broadcom BCM63xx/BCM33xx UART support" select SERIAL_CORE - depends on BCM63XX + depends on MIPS || ARM || COMPILE_TEST help - If you have a bcm63xx CPU, you can enable its onboard - serial port by enabling this options. + This enables the driver for the onchip UART core found on + the following chipsets: - To compile this driver as a module, choose M here: the - module will be called bcm963xx_uart. + BCM33xx (cable modem) + BCM63xx/BCM63xxx (DSL) + BCM68xx (PON) + BCM7xxx (STB) - DOCSIS console config SERIAL_BCM63XX_CONSOLE - bool "Console on bcm63xx serial port" + bool "Console on BCM63xx serial port" depends on SERIAL_BCM63XX=y select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON help - If you have enabled the serial port on the bcm63xx CPU + If you have enabled the serial port on the BCM63xx CPU you can make it the console by answering Y to this option. config SERIAL_GRLIB_GAISLER_APBUART @@ -1388,6 +1411,7 @@ config SERIAL_MXS_AUART depends on ARCH_MXS tristate "MXS AUART support" select SERIAL_CORE + select SERIAL_MCTRL_GPIO if GPIOLIB help This driver supports the MXS Application UART (AUART) port. @@ -1410,6 +1434,7 @@ config SERIAL_XILINX_PS_UART_CONSOLE bool "Cadence UART console support" depends on SERIAL_XILINX_PS_UART=y select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON help Enable a Cadence UART port to be the system console. diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 0080cc362e09..9a548acf5fdc 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o obj-$(CONFIG_SERIAL_ICOM) += icom.o obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o obj-$(CONFIG_SERIAL_MPSC) += mpsc.o +obj-$(CONFIG_SERIAL_MESON) += meson_uart.o obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c index d22e3d98ae23..192d0435bb86 100644 --- a/drivers/tty/serial/altera_jtaguart.c +++ b/drivers/tty/serial/altera_jtaguart.c @@ -462,7 +462,7 @@ static int altera_jtaguart_remove(struct platform_device *pdev) } #ifdef CONFIG_OF -static struct of_device_id altera_jtaguart_match[] = { +static const struct of_device_id altera_jtaguart_match[] = { { .compatible = "ALTR,juart-1.0", }, { .compatible = "altr,juart-1.0", }, {}, @@ -475,7 +475,6 @@ static struct platform_driver altera_jtaguart_platform_driver = { .remove = altera_jtaguart_remove, .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(altera_jtaguart_match), }, }; diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 6a243239dbef..eb15a50623cb 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -610,7 +610,7 @@ static int altera_uart_remove(struct platform_device *pdev) } #ifdef CONFIG_OF -static struct of_device_id altera_uart_match[] = { +static const struct of_device_id altera_uart_match[] = { { .compatible = "ALTR,uart-1.0", }, { .compatible = "altr,uart-1.0", }, {}, @@ -623,7 +623,6 @@ static struct platform_driver altera_uart_platform_driver = { .remove = altera_uart_remove, .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(altera_uart_match), }, }; diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index 2064d31d0c8b..5d41d5b92619 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -75,7 +75,8 @@ struct uart_amba_port { static void pl010_stop_tx(struct uart_port *port) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); unsigned int cr; cr = readb(uap->port.membase + UART010_CR); @@ -85,7 +86,8 @@ static void pl010_stop_tx(struct uart_port *port) static void pl010_start_tx(struct uart_port *port) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); unsigned int cr; cr = readb(uap->port.membase + UART010_CR); @@ -95,7 +97,8 @@ static void pl010_start_tx(struct uart_port *port) static void pl010_stop_rx(struct uart_port *port) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); unsigned int cr; cr = readb(uap->port.membase + UART010_CR); @@ -103,12 +106,23 @@ static void pl010_stop_rx(struct uart_port *port) writel(cr, uap->port.membase + UART010_CR); } -static void pl010_enable_ms(struct uart_port *port) +static void pl010_disable_ms(struct uart_port *port) { struct uart_amba_port *uap = (struct uart_amba_port *)port; unsigned int cr; cr = readb(uap->port.membase + UART010_CR); + cr &= ~UART010_CR_MSIE; + writel(cr, uap->port.membase + UART010_CR); +} + +static void pl010_enable_ms(struct uart_port *port) +{ + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); + unsigned int cr; + + cr = readb(uap->port.membase + UART010_CR); cr |= UART010_CR_MSIE; writel(cr, uap->port.membase + UART010_CR); } @@ -259,14 +273,16 @@ static irqreturn_t pl010_int(int irq, void *dev_id) static unsigned int pl010_tx_empty(struct uart_port *port) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); unsigned int status = readb(uap->port.membase + UART01x_FR); return status & UART01x_FR_BUSY ? 0 : TIOCSER_TEMT; } static unsigned int pl010_get_mctrl(struct uart_port *port) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); unsigned int result = 0; unsigned int status; @@ -283,7 +299,8 @@ static unsigned int pl010_get_mctrl(struct uart_port *port) static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); if (uap->data) uap->data->set_mctrl(uap->dev, uap->port.membase, mctrl); @@ -291,7 +308,8 @@ static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl) static void pl010_break_ctl(struct uart_port *port, int break_state) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); unsigned long flags; unsigned int lcr_h; @@ -307,7 +325,8 @@ static void pl010_break_ctl(struct uart_port *port, int break_state) static int pl010_startup(struct uart_port *port) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); int retval; /* @@ -347,7 +366,8 @@ static int pl010_startup(struct uart_port *port) static void pl010_shutdown(struct uart_port *port) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); /* * Free the interrupt @@ -374,7 +394,8 @@ static void pl010_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); unsigned int lcr_h, old_cr; unsigned long flags; unsigned int baud, quot; @@ -468,13 +489,21 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios, spin_unlock_irqrestore(&uap->port.lock, flags); } -static void pl010_set_ldisc(struct uart_port *port, int new) +static void pl010_set_ldisc(struct uart_port *port, struct ktermios *termios) { - if (new == N_PPS) { + if (termios->c_line == N_PPS) { port->flags |= UPF_HARDPPS_CD; + spin_lock_irq(&port->lock); pl010_enable_ms(port); - } else + spin_unlock_irq(&port->lock); + } else { port->flags &= ~UPF_HARDPPS_CD; + if (!UART_ENABLE_MS(port, termios->c_cflag)) { + spin_lock_irq(&port->lock); + pl010_disable_ms(port); + spin_unlock_irq(&port->lock); + } + } } static const char *pl010_type(struct uart_port *port) @@ -551,7 +580,8 @@ static struct uart_amba_port *amba_ports[UART_NR]; static void pl010_console_putchar(struct uart_port *port, int ch) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); unsigned int status; do { diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 8572f2a57fc8..8d94c194f090 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -246,6 +246,7 @@ static int pl011_sgbuf_init(struct dma_chan *chan, struct pl011_sgbuf *sg, sg_set_page(&sg->sg, phys_to_page(dma_addr), PL011_DMA_BUFFER_SIZE, offset_in_page(dma_addr)); sg_dma_address(&sg->sg) = dma_addr; + sg_dma_len(&sg->sg) = PL011_DMA_BUFFER_SIZE; return 0; } @@ -321,10 +322,26 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port * .src_maxburst = uap->fifosize >> 2, .device_fc = false, }; + struct dma_slave_caps caps; + /* + * Some DMA controllers provide information on their capabilities. + * If the controller does, check for suitable residue processing + * otherwise assime all is well. + */ + if (0 == dma_get_slave_caps(chan, &caps)) { + if (caps.residue_granularity == + DMA_RESIDUE_GRANULARITY_DESCRIPTOR) { + dma_release_channel(chan); + dev_info(uap->port.dev, + "RX DMA disabled - no residue processing\n"); + return; + } + } dmaengine_slave_config(chan, &rx_conf); uap->dmarx.chan = chan; + uap->dmarx.auto_poll_rate = false; if (plat && plat->dma_rx_poll_enable) { /* Set poll rate if specified. */ if (plat->dma_rx_poll_rate) { @@ -345,9 +362,24 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port * plat->dma_rx_poll_timeout; else uap->dmarx.poll_timeout = 3000; - } else - uap->dmarx.auto_poll_rate = false; - + } else if (!plat && dev->of_node) { + uap->dmarx.auto_poll_rate = of_property_read_bool( + dev->of_node, "auto-poll"); + if (uap->dmarx.auto_poll_rate) { + u32 x; + + if (0 == of_property_read_u32(dev->of_node, + "poll-rate-ms", &x)) + uap->dmarx.poll_rate = x; + else + uap->dmarx.poll_rate = 100; + if (0 == of_property_read_u32(dev->of_node, + "poll-timeout-ms", &x)) + uap->dmarx.poll_timeout = x; + else + uap->dmarx.poll_timeout = 3000; + } + } dev_info(uap->port.dev, "DMA channel RX %s\n", dma_chan_name(uap->dmarx.chan)); } @@ -501,7 +533,11 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap) memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count); else { size_t first = UART_XMIT_SIZE - xmit->tail; - size_t second = xmit->head; + size_t second; + + if (first > count) + first = count; + second = count - first; memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], first); if (second) @@ -678,7 +714,8 @@ static void pl011_dma_flush_buffer(struct uart_port *port) __releases(&uap->port.lock) __acquires(&uap->port.lock) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); if (!uap->using_tx_dma) return; @@ -987,7 +1024,7 @@ static void pl011_dma_startup(struct uart_amba_port *uap) if (!uap->dmatx.chan) return; - uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL); + uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL | __GFP_DMA); if (!uap->dmatx.buf) { dev_err(uap->port.dev, "no memory for DMA TX buffer\n"); uap->port.fifosize = uap->fifosize; @@ -1163,7 +1200,8 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap) static void pl011_stop_tx(struct uart_port *port) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); uap->im &= ~UART011_TXIM; writew(uap->im, uap->port.membase + UART011_IMSC); @@ -1172,7 +1210,8 @@ static void pl011_stop_tx(struct uart_port *port) static void pl011_start_tx(struct uart_port *port) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); if (!pl011_dma_tx_start(uap)) { uap->im |= UART011_TXIM; @@ -1182,7 +1221,8 @@ static void pl011_start_tx(struct uart_port *port) static void pl011_stop_rx(struct uart_port *port) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM| UART011_PEIM|UART011_BEIM|UART011_OEIM); @@ -1193,7 +1233,8 @@ static void pl011_stop_rx(struct uart_port *port) static void pl011_enable_ms(struct uart_port *port) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM; writew(uap->im, uap->port.membase + UART011_IMSC); @@ -1349,14 +1390,16 @@ static irqreturn_t pl011_int(int irq, void *dev_id) static unsigned int pl011_tx_empty(struct uart_port *port) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, 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 pl011_get_mctrl(struct uart_port *port) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); unsigned int result = 0; unsigned int status = readw(uap->port.membase + UART01x_FR); @@ -1374,7 +1417,8 @@ static unsigned int pl011_get_mctrl(struct uart_port *port) static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); unsigned int cr; cr = readw(uap->port.membase + UART011_CR); @@ -1402,7 +1446,8 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl) static void pl011_break_ctl(struct uart_port *port, int break_state) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); unsigned long flags; unsigned int lcr_h; @@ -1420,7 +1465,8 @@ static void pl011_break_ctl(struct uart_port *port, int break_state) static void pl011_quiesce_irqs(struct uart_port *port) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); unsigned char __iomem *regs = uap->port.membase; writew(readw(regs + UART011_MIS), regs + UART011_ICR); @@ -1442,7 +1488,8 @@ static void pl011_quiesce_irqs(struct uart_port *port) static int pl011_get_poll_char(struct uart_port *port) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); unsigned int status; /* @@ -1461,7 +1508,8 @@ static int pl011_get_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; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) barrier(); @@ -1473,7 +1521,8 @@ static void pl011_put_poll_char(struct uart_port *port, static int pl011_hwinit(struct uart_port *port) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); int retval; /* Optionaly enable pins to be muxed in and configured */ @@ -1526,7 +1575,8 @@ static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h) static int pl011_startup(struct uart_port *port) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); unsigned int cr, lcr_h, fbrd, ibrd; int retval; @@ -1618,7 +1668,8 @@ static void pl011_shutdown_channel(struct uart_amba_port *uap, static void pl011_shutdown(struct uart_port *port) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); unsigned int cr; /* @@ -1674,13 +1725,16 @@ static void pl011_shutdown(struct uart_port *port) plat->exit(); } + if (uap->port.ops->flush_buffer) + uap->port.ops->flush_buffer(port); } static void pl011_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); unsigned int lcr_h, old_cr; unsigned long flags; unsigned int baud, quot, clkdiv; @@ -1822,7 +1876,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, static const char *pl011_type(struct uart_port *port) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); return uap->port.type == PORT_AMBA ? uap->type : NULL; } @@ -1900,7 +1955,8 @@ static struct uart_amba_port *amba_ports[UART_NR]; static void pl011_console_putchar(struct uart_port *port, int ch) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) barrier(); diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c index a34a0cec1685..4f0f95e358e8 100644 --- a/drivers/tty/serial/apbuart.c +++ b/drivers/tty/serial/apbuart.c @@ -585,7 +585,6 @@ static struct of_device_id apbuart_match[] = { static struct platform_driver grlib_apbuart_of_driver = { .probe = apbuart_probe, .driver = { - .owner = THIS_MODULE, .name = "grlib-apbuart", .of_match_table = apbuart_match, }, diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index 0be1c45efd65..77fc9faa74a4 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -119,7 +119,8 @@ static inline void ar933x_uart_putc(struct ar933x_uart_port *up, int ch) static unsigned int ar933x_uart_tx_empty(struct uart_port *port) { - struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + struct ar933x_uart_port *up = + container_of(port, struct ar933x_uart_port, port); unsigned long flags; unsigned int rdata; @@ -141,21 +142,24 @@ static void ar933x_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) static void ar933x_uart_start_tx(struct uart_port *port) { - struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + struct ar933x_uart_port *up = + container_of(port, struct ar933x_uart_port, port); ar933x_uart_start_tx_interrupt(up); } static void ar933x_uart_stop_tx(struct uart_port *port) { - struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + struct ar933x_uart_port *up = + container_of(port, struct ar933x_uart_port, port); ar933x_uart_stop_tx_interrupt(up); } static void ar933x_uart_stop_rx(struct uart_port *port) { - struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + struct ar933x_uart_port *up = + container_of(port, struct ar933x_uart_port, port); up->ier &= ~AR933X_UART_INT_RX_VALID; ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); @@ -163,7 +167,8 @@ static void ar933x_uart_stop_rx(struct uart_port *port) static void ar933x_uart_break_ctl(struct uart_port *port, int break_state) { - struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + struct ar933x_uart_port *up = + container_of(port, struct ar933x_uart_port, port); unsigned long flags; spin_lock_irqsave(&up->port.lock, flags); @@ -231,7 +236,8 @@ static void ar933x_uart_set_termios(struct uart_port *port, struct ktermios *new, struct ktermios *old) { - struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + struct ar933x_uart_port *up = + container_of(port, struct ar933x_uart_port, port); unsigned int cs; unsigned long flags; unsigned int baud, scale, step; @@ -404,7 +410,8 @@ static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id) static int ar933x_uart_startup(struct uart_port *port) { - struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + struct ar933x_uart_port *up = + container_of(port, struct ar933x_uart_port, port); unsigned long flags; int ret; @@ -430,7 +437,8 @@ static int ar933x_uart_startup(struct uart_port *port) static void ar933x_uart_shutdown(struct uart_port *port) { - struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + struct ar933x_uart_port *up = + container_of(port, struct ar933x_uart_port, port); /* Disable all interrupts */ up->ier = 0; @@ -468,7 +476,8 @@ static void ar933x_uart_config_port(struct uart_port *port, int flags) static int ar933x_uart_verify_port(struct uart_port *port, struct serial_struct *ser) { - struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + struct ar933x_uart_port *up = + container_of(port, struct ar933x_uart_port, port); if (ser->type != PORT_UNKNOWN && ser->type != PORT_AR933X) @@ -521,7 +530,8 @@ static void ar933x_uart_wait_xmitr(struct ar933x_uart_port *up) static void ar933x_uart_console_putchar(struct uart_port *port, int ch) { - struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + struct ar933x_uart_port *up = + container_of(port, struct ar933x_uart_port, port); ar933x_uart_wait_xmitr(up); ar933x_uart_putc(up, ch); @@ -734,7 +744,6 @@ static struct platform_driver ar933x_uart_platform_driver = { .remove = ar933x_uart_remove, .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(ar933x_uart_of_ids), }, }; diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index a59d1d77e750..03ebe401fff7 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -653,7 +653,6 @@ static struct platform_driver arc_platform_driver = { .remove = arc_serial_remove, .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, .of_match_table = arc_uart_dt_ids, }, }; diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index d7d4584549a5..4d848a29e223 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -37,6 +37,7 @@ #include <linux/of_device.h> #include <linux/of_gpio.h> #include <linux/dma-mapping.h> +#include <linux/dmaengine.h> #include <linux/atmel_pdc.h> #include <linux/atmel_serial.h> #include <linux/uaccess.h> @@ -166,7 +167,6 @@ struct atmel_uart_port { struct circ_buf rx_ring; - struct serial_rs485 rs485; /* rs485 settings */ struct mctrl_gpios *gpios; int gpio_irq[UART_GPIO_MAX]; unsigned int tx_done_mask; @@ -289,13 +289,11 @@ static unsigned int atmel_get_lines_status(struct uart_port *port) } /* Enable or disable the rs485 support */ -void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) +static int atmel_config_rs485(struct uart_port *port, + struct serial_rs485 *rs485conf) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); unsigned int mode; - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); /* Disable interrupts */ UART_PUT_IDR(port, atmel_port->tx_done_mask); @@ -305,7 +303,7 @@ void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) /* Resetting serial mode to RS232 (0x0) */ mode &= ~ATMEL_US_USMODE; - atmel_port->rs485 = *rs485conf; + port->rs485 = *rs485conf; if (rs485conf->flags & SER_RS485_ENABLED) { dev_dbg(port->dev, "Setting UART to RS485\n"); @@ -326,8 +324,7 @@ void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) /* Enable interrupts */ UART_PUT_IER(port, atmel_port->tx_done_mask); - spin_unlock_irqrestore(&port->lock, flags); - + return 0; } /* @@ -371,11 +368,10 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) /* Resetting serial mode to RS232 (0x0) */ mode &= ~ATMEL_US_USMODE; - if (atmel_port->rs485.flags & SER_RS485_ENABLED) { + if (port->rs485.flags & SER_RS485_ENABLED) { dev_dbg(port->dev, "Setting UART to RS485\n"); - if ((atmel_port->rs485.delay_rts_after_send) > 0) - UART_PUT_TTGR(port, - atmel_port->rs485.delay_rts_after_send); + if ((port->rs485.delay_rts_after_send) > 0) + UART_PUT_TTGR(port, port->rs485.delay_rts_after_send); mode |= ATMEL_US_USMODE_RS485; } else { dev_dbg(port->dev, "Setting UART to RS232\n"); @@ -422,8 +418,8 @@ static void atmel_stop_tx(struct uart_port *port) /* Disable interrupts */ UART_PUT_IDR(port, atmel_port->tx_done_mask); - if ((atmel_port->rs485.flags & SER_RS485_ENABLED) && - !(atmel_port->rs485.flags & SER_RS485_RX_DURING_TX)) + if ((port->rs485.flags & SER_RS485_ENABLED) && + !(port->rs485.flags & SER_RS485_RX_DURING_TX)) atmel_start_rx(port); } @@ -440,8 +436,8 @@ static void atmel_start_tx(struct uart_port *port) really need this.*/ return; - if ((atmel_port->rs485.flags & SER_RS485_ENABLED) && - !(atmel_port->rs485.flags & SER_RS485_RX_DURING_TX)) + if ((port->rs485.flags & SER_RS485_ENABLED) && + !(port->rs485.flags & SER_RS485_RX_DURING_TX)) atmel_stop_rx(port); /* re-enable PDC transmit */ @@ -806,7 +802,7 @@ static void atmel_tx_dma(struct uart_port *port) atmel_port->cookie_tx = dmaengine_submit(desc); } else { - if (atmel_port->rs485.flags & SER_RS485_ENABLED) { + if (port->rs485.flags & SER_RS485_ENABLED) { /* DMA done, stop TX, start RX for RS485 */ atmel_start_rx(port); } @@ -861,9 +857,8 @@ static int atmel_prepare_tx_dma(struct uart_port *port) config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; config.dst_addr = port->mapbase + ATMEL_US_THR; - ret = dmaengine_device_control(atmel_port->chan_tx, - DMA_SLAVE_CONFIG, - (unsigned long)&config); + ret = dmaengine_slave_config(atmel_port->chan_tx, + &config); if (ret) { dev_err(port->dev, "DMA tx slave configuration failed\n"); goto chan_err; @@ -879,32 +874,6 @@ chan_err: return -EINVAL; } -static void atmel_flip_buffer_rx_dma(struct uart_port *port, - char *buf, size_t count) -{ - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - struct tty_port *tport = &port->state->port; - - dma_sync_sg_for_cpu(port->dev, - &atmel_port->sg_rx, - 1, - DMA_DEV_TO_MEM); - - tty_insert_flip_string(tport, buf, count); - - dma_sync_sg_for_device(port->dev, - &atmel_port->sg_rx, - 1, - DMA_DEV_TO_MEM); - /* - * Drop the lock here since it might end up calling - * uart_start(), which takes the lock. - */ - spin_unlock(&port->lock); - tty_flip_buffer_push(tport); - spin_lock(&port->lock); -} - static void atmel_complete_rx_dma(void *arg) { struct uart_port *port = arg; @@ -933,11 +902,12 @@ static void atmel_release_rx_dma(struct uart_port *port) static void atmel_rx_from_dma(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct tty_port *tport = &port->state->port; struct circ_buf *ring = &atmel_port->rx_ring; struct dma_chan *chan = atmel_port->chan_rx; struct dma_tx_state state; enum dma_status dmastat; - size_t pending, count; + size_t count; /* Reset the UART timeout early so that we don't miss one */ @@ -952,27 +922,68 @@ static void atmel_rx_from_dma(struct uart_port *port) tasklet_schedule(&atmel_port->tasklet); return; } - /* current transfer size should no larger than dma buffer */ - pending = sg_dma_len(&atmel_port->sg_rx) - state.residue; - BUG_ON(pending > sg_dma_len(&atmel_port->sg_rx)); + + /* CPU claims ownership of RX DMA buffer */ + dma_sync_sg_for_cpu(port->dev, + &atmel_port->sg_rx, + 1, + DMA_DEV_TO_MEM); /* - * This will take the chars we have so far, - * ring->head will record the transfer size, only new bytes come - * will insert into the framework. + * ring->head points to the end of data already written by the DMA. + * ring->tail points to the beginning of data to be read by the + * framework. + * The current transfer size should not be larger than the dma buffer + * length. */ - if (pending > ring->head) { - count = pending - ring->head; + ring->head = sg_dma_len(&atmel_port->sg_rx) - state.residue; + BUG_ON(ring->head > sg_dma_len(&atmel_port->sg_rx)); + /* + * At this point ring->head may point to the first byte right after the + * last byte of the dma buffer: + * 0 <= ring->head <= sg_dma_len(&atmel_port->sg_rx) + * + * However ring->tail must always points inside the dma buffer: + * 0 <= ring->tail <= sg_dma_len(&atmel_port->sg_rx) - 1 + * + * Since we use a ring buffer, we have to handle the case + * where head is lower than tail. In such a case, we first read from + * tail to the end of the buffer then reset tail. + */ + if (ring->head < ring->tail) { + count = sg_dma_len(&atmel_port->sg_rx) - ring->tail; + + tty_insert_flip_string(tport, ring->buf + ring->tail, count); + ring->tail = 0; + port->icount.rx += count; + } - atmel_flip_buffer_rx_dma(port, ring->buf + ring->head, count); + /* Finally we read data from tail to head */ + if (ring->tail < ring->head) { + count = ring->head - ring->tail; - ring->head += count; - if (ring->head == sg_dma_len(&atmel_port->sg_rx)) + tty_insert_flip_string(tport, ring->buf + ring->tail, count); + /* Wrap ring->head if needed */ + if (ring->head >= sg_dma_len(&atmel_port->sg_rx)) ring->head = 0; - + ring->tail = ring->head; port->icount.rx += count; } + /* USART retreives ownership of RX DMA buffer */ + dma_sync_sg_for_device(port->dev, + &atmel_port->sg_rx, + 1, + DMA_DEV_TO_MEM); + + /* + * Drop the lock here since it might end up calling + * uart_start(), which takes the lock. + */ + spin_unlock(&port->lock); + tty_flip_buffer_push(tport); + spin_lock(&port->lock); + UART_PUT_IER(port, ATMEL_US_TIMEOUT); } @@ -1025,9 +1036,8 @@ static int atmel_prepare_rx_dma(struct uart_port *port) config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; config.src_addr = port->mapbase + ATMEL_US_RHR; - ret = dmaengine_device_control(atmel_port->chan_rx, - DMA_SLAVE_CONFIG, - (unsigned long)&config); + ret = dmaengine_slave_config(atmel_port->chan_rx, + &config); if (ret) { dev_err(port->dev, "DMA rx slave configuration failed\n"); goto chan_err; @@ -1239,8 +1249,8 @@ static void atmel_tx_pdc(struct uart_port *port) /* Enable interrupts */ UART_PUT_IER(port, atmel_port->tx_done_mask); } else { - if ((atmel_port->rs485.flags & SER_RS485_ENABLED) && - !(atmel_port->rs485.flags & SER_RS485_RX_DURING_TX)) { + if ((port->rs485.flags & SER_RS485_ENABLED) && + !(port->rs485.flags & SER_RS485_RX_DURING_TX)) { /* DMA done, stop TX, start RX for RS485 */ atmel_start_rx(port); } @@ -1551,7 +1561,7 @@ static int atmel_init_property(struct atmel_uart_port *atmel_port, return 0; } -static void atmel_init_rs485(struct atmel_uart_port *atmel_port, +static void atmel_init_rs485(struct uart_port *port, struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -1562,7 +1572,7 @@ static void atmel_init_rs485(struct atmel_uart_port *atmel_port, /* rs485 properties */ if (of_property_read_u32_array(np, "rs485-rts-delay", rs485_delay, 2) == 0) { - struct serial_rs485 *rs485conf = &atmel_port->rs485; + struct serial_rs485 *rs485conf = &port->rs485; rs485conf->delay_rts_before_send = rs485_delay[0]; rs485conf->delay_rts_after_send = rs485_delay[1]; @@ -1576,7 +1586,7 @@ static void atmel_init_rs485(struct atmel_uart_port *atmel_port, rs485conf->flags |= SER_RS485_ENABLED; } } else { - atmel_port->rs485 = pdata->rs485; + port->rs485 = pdata->rs485; } } @@ -1801,6 +1811,20 @@ free_irq: } /* + * Flush any TX data submitted for DMA. Called when the TX circular + * buffer is reset. + */ +static void atmel_flush_buffer(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + if (atmel_use_pdc_tx(port)) { + UART_PUT_TCR(port, 0); + atmel_port->pdc_tx.ofs = 0; + } +} + +/* * Disable the port */ static void atmel_shutdown(struct uart_port *port) @@ -1851,20 +1875,8 @@ static void atmel_shutdown(struct uart_port *port) atmel_free_gpio_irq(port); atmel_port->ms_irq_enabled = false; -} -/* - * Flush any TX data submitted for DMA. Called when the TX circular - * buffer is reset. - */ -static void atmel_flush_buffer(struct uart_port *port) -{ - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - - if (atmel_use_pdc_tx(port)) { - UART_PUT_TCR(port, 0); - atmel_port->pdc_tx.ofs = 0; - } + atmel_flush_buffer(port); } /* @@ -1910,7 +1922,6 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, { unsigned long flags; unsigned int mode, imr, quot, baud; - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); /* Get current mode register */ mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL @@ -2012,10 +2023,9 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, /* Resetting serial mode to RS232 (0x0) */ mode &= ~ATMEL_US_USMODE; - if (atmel_port->rs485.flags & SER_RS485_ENABLED) { - if ((atmel_port->rs485.delay_rts_after_send) > 0) - UART_PUT_TTGR(port, - atmel_port->rs485.delay_rts_after_send); + if (port->rs485.flags & SER_RS485_ENABLED) { + if ((port->rs485.delay_rts_after_send) > 0) + UART_PUT_TTGR(port, port->rs485.delay_rts_after_send); mode |= ATMEL_US_USMODE_RS485; } @@ -2039,13 +2049,20 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, spin_unlock_irqrestore(&port->lock, flags); } -static void atmel_set_ldisc(struct uart_port *port, int new) +static void atmel_set_ldisc(struct uart_port *port, struct ktermios *termios) { - if (new == N_PPS) { + if (termios->c_line == N_PPS) { port->flags |= UPF_HARDPPS_CD; + spin_lock_irq(&port->lock); atmel_enable_ms(port); + spin_unlock_irq(&port->lock); } else { port->flags &= ~UPF_HARDPPS_CD; + if (!UART_ENABLE_MS(port, termios->c_cflag)) { + spin_lock_irq(&port->lock); + atmel_disable_ms(port); + spin_unlock_irq(&port->lock); + } } } @@ -2147,35 +2164,6 @@ static void atmel_poll_put_char(struct uart_port *port, unsigned char ch) } #endif -static int -atmel_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg) -{ - struct serial_rs485 rs485conf; - - switch (cmd) { - case TIOCSRS485: - if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg, - sizeof(rs485conf))) - return -EFAULT; - - atmel_config_rs485(port, &rs485conf); - break; - - case TIOCGRS485: - if (copy_to_user((struct serial_rs485 *) arg, - &(to_atmel_uart_port(port)->rs485), - sizeof(rs485conf))) - return -EFAULT; - break; - - default: - return -ENOIOCTLCMD; - } - return 0; -} - - - static struct uart_ops atmel_pops = { .tx_empty = atmel_tx_empty, .set_mctrl = atmel_set_mctrl, @@ -2196,7 +2184,6 @@ static struct uart_ops atmel_pops = { .config_port = atmel_config_port, .verify_port = atmel_verify_port, .pm = atmel_serial_pm, - .ioctl = atmel_ioctl, #ifdef CONFIG_CONSOLE_POLL .poll_get_char = atmel_poll_get_char, .poll_put_char = atmel_poll_put_char, @@ -2216,7 +2203,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, if (!atmel_init_property(atmel_port, pdev)) atmel_set_ops(port); - atmel_init_rs485(atmel_port, pdev); + atmel_init_rs485(port, pdev); port->iotype = UPIO_MEM; port->flags = UPF_BOOT_AUTOCONF; @@ -2225,6 +2212,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, port->dev = &pdev->dev; port->mapbase = pdev->resource[0].start; port->irq = pdev->resource[1].start; + port->rs485_config = atmel_config_rs485; tasklet_init(&atmel_port->tasklet, atmel_tasklet_func, (unsigned long)port); @@ -2259,7 +2247,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, } /* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */ - if (atmel_port->rs485.flags & SER_RS485_ENABLED) + if (port->rs485.flags & SER_RS485_ENABLED) atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; else if (atmel_use_pdc_tx(port)) { port->fifosize = PDC_BUFFER_SIZE; @@ -2540,6 +2528,7 @@ static int atmel_serial_probe(struct platform_device *pdev) struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev); void *data; int ret = -ENODEV; + bool rs485_enabled; BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1)); @@ -2587,6 +2576,8 @@ static int atmel_serial_probe(struct platform_device *pdev) port->rx_ring.buf = data; } + rs485_enabled = port->uart.rs485.flags & SER_RS485_ENABLED; + ret = uart_add_one_port(&atmel_uart, &port->uart); if (ret) goto err_add_port; @@ -2605,7 +2596,7 @@ static int atmel_serial_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); platform_set_drvdata(pdev, port); - if (port->rs485.flags & SER_RS485_ENABLED) { + if (rs485_enabled) { UART_PUT_MR(&port->uart, ATMEL_US_USMODE_NORMAL); UART_PUT_CR(&port->uart, ATMEL_US_RTSEN); } @@ -2659,7 +2650,6 @@ static struct platform_driver atmel_serial_driver = { .resume = atmel_serial_resume, .driver = { .name = "atmel_usart", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(atmel_serial_dt_ids), }, }; diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index 231519022b73..01d83df08e3d 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -588,20 +588,7 @@ static void bcm_uart_set_termios(struct uart_port *port, */ static int bcm_uart_request_port(struct uart_port *port) { - unsigned int size; - - size = UART_REG_SIZE; - if (!request_mem_region(port->mapbase, size, "bcm63xx")) { - dev_err(port->dev, "Memory region busy\n"); - return -EBUSY; - } - - port->membase = ioremap(port->mapbase, size); - if (!port->membase) { - dev_err(port->dev, "Unable to map registers\n"); - release_mem_region(port->mapbase, size); - return -EBUSY; - } + /* UARTs always present */ return 0; } @@ -610,8 +597,7 @@ static int bcm_uart_request_port(struct uart_port *port) */ static void bcm_uart_release_port(struct uart_port *port) { - release_mem_region(port->mapbase, UART_REG_SIZE); - iounmap(port->membase); + /* Nothing to release ... */ } /* @@ -782,6 +768,26 @@ static int __init bcm63xx_console_init(void) console_initcall(bcm63xx_console_init); +static void bcm_early_write(struct console *con, const char *s, unsigned n) +{ + struct earlycon_device *dev = con->data; + + uart_console_write(&dev->port, s, n, bcm_console_putchar); + wait_for_xmitr(&dev->port); +} + +static int __init bcm_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + if (!device->port.membase) + return -ENODEV; + + device->con->write = bcm_early_write; + return 0; +} + +OF_EARLYCON_DECLARE(bcm63xx_uart, "brcm,bcm6345-uart", bcm_early_console_setup); + #define BCM63XX_CONSOLE (&bcm63xx_console) #else #define BCM63XX_CONSOLE NULL @@ -813,25 +819,30 @@ static int bcm_uart_probe(struct platform_device *pdev) if (pdev->id < 0 || pdev->id >= BCM63XX_NR_UARTS) return -EINVAL; - if (ports[pdev->id].membase) + port = &ports[pdev->id]; + if (port->membase) return -EBUSY; + memset(port, 0, sizeof(*port)); res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res_mem) return -ENODEV; + port->mapbase = res_mem->start; + port->membase = devm_ioremap_resource(&pdev->dev, res_mem); + if (IS_ERR(port->membase)) + return PTR_ERR(port->membase); + res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res_irq) return -ENODEV; - clk = clk_get(&pdev->dev, "periph"); + clk = pdev->dev.of_node ? of_clk_get(pdev->dev.of_node, 0) : + clk_get(&pdev->dev, "periph"); if (IS_ERR(clk)) return -ENODEV; - port = &ports[pdev->id]; - memset(port, 0, sizeof(*port)); port->iotype = UPIO_MEM; - port->mapbase = res_mem->start; port->irq = res_irq->start; port->ops = &bcm_uart_ops; port->flags = UPF_BOOT_AUTOCONF; @@ -874,7 +885,6 @@ static struct platform_driver bcm_uart_platform_driver = { .probe = bcm_uart_probe, .remove = bcm_uart_remove, .driver = { - .owner = THIS_MODULE, .name = "bcm63xx_uart", .of_match_table = bcm63xx_of_match, }, @@ -905,5 +915,5 @@ module_init(bcm_uart_init); module_exit(bcm_uart_exit); MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>"); -MODULE_DESCRIPTION("Broadcom 63<xx integrated uart driver"); +MODULE_DESCRIPTION("Broadcom 63xx integrated uart driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/bfin_sport_uart.c b/drivers/tty/serial/bfin_sport_uart.c index 7810aa290edf..984e1c050096 100644 --- a/drivers/tty/serial/bfin_sport_uart.c +++ b/drivers/tty/serial/bfin_sport_uart.c @@ -33,6 +33,7 @@ #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/serial_core.h> +#include <linux/gpio.h> #include <asm/bfin_sport.h> #include <asm/delay.h> @@ -516,14 +517,15 @@ static void sport_set_termios(struct uart_port *port, up->csize = 5; break; default: - pr_warning("requested word length not supported\n"); + pr_warn("requested word length not supported\n"); + break; } if (termios->c_cflag & CSTOPB) { up->stopb = 1; } if (termios->c_cflag & PARENB) { - pr_warning("PAREN bits is not supported yet\n"); + pr_warn("PAREN bit is not supported yet\n"); /* up->parib = 1; */ } diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c index dec0fd725d80..43b3e2c233ff 100644 --- a/drivers/tty/serial/bfin_uart.c +++ b/drivers/tty/serial/bfin_uart.c @@ -108,22 +108,23 @@ static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) static irqreturn_t bfin_serial_mctrl_cts_int(int irq, void *dev_id) { struct bfin_serial_port *uart = dev_id; - unsigned int status = bfin_serial_get_mctrl(&uart->port); + struct uart_port *uport = &uart->port; + unsigned int status = bfin_serial_get_mctrl(uport); #ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS - struct tty_struct *tty = uart->port.state->port.tty; UART_CLEAR_SCTS(uart); - if (tty->hw_stopped) { + if (uport->hw_stopped) { if (status) { - tty->hw_stopped = 0; - uart_write_wakeup(&uart->port); + uport->hw_stopped = 0; + uart_write_wakeup(uport); } } else { if (!status) - tty->hw_stopped = 1; + uport->hw_stopped = 1; } +#else + uart_handle_cts_change(uport, status & TIOCM_CTS); #endif - uart_handle_cts_change(&uart->port, status & TIOCM_CTS); return IRQ_HANDLED; } @@ -943,12 +944,13 @@ bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser) * Enable the IrDA function if tty->ldisc.num is N_IRDA. * In other cases, disable IrDA function. */ -static void bfin_serial_set_ldisc(struct uart_port *port, int ld) +static void bfin_serial_set_ldisc(struct uart_port *port, + struct ktermios *termios) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; unsigned int val; - switch (ld) { + switch (termios->c_line) { case N_IRDA: val = UART_GET_GCTL(uart); val |= (UMOD_IRDA | RPOLC); @@ -1385,7 +1387,6 @@ static struct platform_driver bfin_serial_driver = { .resume = bfin_serial_resume, .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, }, }; diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c index f5b4c3d7e38f..6e11c275f2ab 100644 --- a/drivers/tty/serial/clps711x.c +++ b/drivers/tty/serial/clps711x.c @@ -33,6 +33,8 @@ #include <linux/mfd/syscon.h> #include <linux/mfd/syscon/clps711x.h> +#include "serial_mctrl_gpio.h" + #define UART_CLPS711X_DEVNAME "ttyCL" #define UART_CLPS711X_NR 2 #define UART_CLPS711X_MAJOR 204 @@ -62,7 +64,7 @@ struct clps711x_port { unsigned int tx_enabled; int rx_irq; struct regmap *syscon; - bool use_ms; + struct mctrl_gpios *gpios; }; static struct uart_driver clps711x_uart = { @@ -198,28 +200,17 @@ static unsigned int uart_clps711x_tx_empty(struct uart_port *port) static unsigned int uart_clps711x_get_mctrl(struct uart_port *port) { + unsigned int result = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR; struct clps711x_port *s = dev_get_drvdata(port->dev); - unsigned int result = 0; - - if (s->use_ms) { - u32 sysflg = 0; - - regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg); - if (sysflg & SYSFLG1_DCD) - result |= TIOCM_CAR; - if (sysflg & SYSFLG1_DSR) - result |= TIOCM_DSR; - if (sysflg & SYSFLG1_CTS) - result |= TIOCM_CTS; - } else - result = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR; - return result; + return mctrl_gpio_get(s->gpios, &result); } static void uart_clps711x_set_mctrl(struct uart_port *port, unsigned int mctrl) { - /* Do nothing */ + struct clps711x_port *s = dev_get_drvdata(port->dev); + + mctrl_gpio_set(s->gpios, mctrl); } static void uart_clps711x_break_ctl(struct uart_port *port, int break_state) @@ -234,13 +225,14 @@ static void uart_clps711x_break_ctl(struct uart_port *port, int break_state) writel(ubrlcr, port->membase + UBRLCR_OFFSET); } -static void uart_clps711x_set_ldisc(struct uart_port *port, int ld) +static void uart_clps711x_set_ldisc(struct uart_port *port, + struct ktermios *termios) { if (!port->line) { struct clps711x_port *s = dev_get_drvdata(port->dev); regmap_update_bits(s->syscon, SYSCON_OFFSET, SYSCON1_SIREN, - (ld == N_IRDA) ? SYSCON1_SIREN : 0); + (termios->c_line == N_IRDA) ? SYSCON1_SIREN : 0); } } @@ -490,15 +482,10 @@ static int uart_clps711x_probe(struct platform_device *pdev) s->syscon = syscon_regmap_lookup_by_pdevname(syscon_name); if (IS_ERR(s->syscon)) return PTR_ERR(s->syscon); - - s->use_ms = !index; } else { s->syscon = syscon_regmap_lookup_by_phandle(np, "syscon"); if (IS_ERR(s->syscon)) return PTR_ERR(s->syscon); - - if (!index) - s->use_ms = of_property_read_bool(np, "uart-use-ms"); } s->port.line = index; @@ -513,6 +500,8 @@ static int uart_clps711x_probe(struct platform_device *pdev) platform_set_drvdata(pdev, s); + s->gpios = mctrl_gpio_init(&pdev->dev, 0); + ret = uart_add_one_port(&clps711x_uart, &s->port); if (ret) return ret; @@ -554,7 +543,6 @@ MODULE_DEVICE_TABLE(of, clps711x_uart_dt_ids); static struct platform_driver clps711x_uart_platform = { .driver = { .name = "clps711x-uart", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(clps711x_uart_dt_ids), }, .probe = uart_clps711x_probe, diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c index 533852eb8778..fddb1fd4d9d3 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c @@ -80,7 +80,8 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo); */ static unsigned int cpm_uart_tx_empty(struct uart_port *port) { - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + struct uart_cpm_port *pinfo = + container_of(port, struct uart_cpm_port, port); cbd_t __iomem *bdp = pinfo->tx_bd_base; int ret = 0; @@ -102,7 +103,8 @@ static unsigned int cpm_uart_tx_empty(struct uart_port *port) static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) { - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + struct uart_cpm_port *pinfo = + container_of(port, struct uart_cpm_port, port); if (pinfo->gpios[GPIO_RTS] >= 0) gpio_set_value(pinfo->gpios[GPIO_RTS], !(mctrl & TIOCM_RTS)); @@ -113,7 +115,8 @@ static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) static unsigned int cpm_uart_get_mctrl(struct uart_port *port) { - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + struct uart_cpm_port *pinfo = + container_of(port, struct uart_cpm_port, port); unsigned int mctrl = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; if (pinfo->gpios[GPIO_CTS] >= 0) { @@ -144,7 +147,8 @@ static unsigned int cpm_uart_get_mctrl(struct uart_port *port) */ static void cpm_uart_stop_tx(struct uart_port *port) { - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + struct uart_cpm_port *pinfo = + container_of(port, struct uart_cpm_port, port); smc_t __iomem *smcp = pinfo->smcp; scc_t __iomem *sccp = pinfo->sccp; @@ -161,7 +165,8 @@ static void cpm_uart_stop_tx(struct uart_port *port) */ static void cpm_uart_start_tx(struct uart_port *port) { - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + struct uart_cpm_port *pinfo = + container_of(port, struct uart_cpm_port, port); smc_t __iomem *smcp = pinfo->smcp; scc_t __iomem *sccp = pinfo->sccp; @@ -189,7 +194,8 @@ static void cpm_uart_start_tx(struct uart_port *port) */ static void cpm_uart_stop_rx(struct uart_port *port) { - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + struct uart_cpm_port *pinfo = + container_of(port, struct uart_cpm_port, port); smc_t __iomem *smcp = pinfo->smcp; scc_t __iomem *sccp = pinfo->sccp; @@ -206,7 +212,8 @@ static void cpm_uart_stop_rx(struct uart_port *port) */ static void cpm_uart_break_ctl(struct uart_port *port, int break_state) { - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + struct uart_cpm_port *pinfo = + container_of(port, struct uart_cpm_port, port); pr_debug("CPM uart[%d]:break ctrl, break_state: %d\n", port->line, break_state); @@ -240,7 +247,8 @@ static void cpm_uart_int_rx(struct uart_port *port) unsigned char ch; u8 *cp; struct tty_port *tport = &port->state->port; - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + struct uart_cpm_port *pinfo = + container_of(port, struct uart_cpm_port, port); cbd_t __iomem *bdp; u16 status; unsigned int flg; @@ -397,7 +405,8 @@ static irqreturn_t cpm_uart_int(int irq, void *data) static int cpm_uart_startup(struct uart_port *port) { int retval; - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + struct uart_cpm_port *pinfo = + container_of(port, struct uart_cpm_port, port); pr_debug("CPM uart[%d]:startup\n", port->line); @@ -442,7 +451,8 @@ inline void cpm_uart_wait_until_send(struct uart_cpm_port *pinfo) */ static void cpm_uart_shutdown(struct uart_port *port) { - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + struct uart_cpm_port *pinfo = + container_of(port, struct uart_cpm_port, port); pr_debug("CPM uart[%d]:shutdown\n", port->line); @@ -492,7 +502,8 @@ static void cpm_uart_set_termios(struct uart_port *port, unsigned long flags; u16 cval, scval, prev_mode; int bits, sbits; - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + struct uart_cpm_port *pinfo = + container_of(port, struct uart_cpm_port, port); smc_t __iomem *smcp = pinfo->smcp; scc_t __iomem *sccp = pinfo->sccp; int maxidl; @@ -675,7 +686,8 @@ static int cpm_uart_tx_pump(struct uart_port *port) cbd_t __iomem *bdp; u8 *p; int count; - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + struct uart_cpm_port *pinfo = + container_of(port, struct uart_cpm_port, port); struct circ_buf *xmit = &port->state->xmit; /* Handle xon/xoff */ @@ -906,7 +918,8 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo) */ static int cpm_uart_request_port(struct uart_port *port) { - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + struct uart_cpm_port *pinfo = + container_of(port, struct uart_cpm_port, port); int ret; pr_debug("CPM uart[%d]:request port\n", port->line); @@ -938,7 +951,8 @@ static int cpm_uart_request_port(struct uart_port *port) static void cpm_uart_release_port(struct uart_port *port) { - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + struct uart_cpm_port *pinfo = + container_of(port, struct uart_cpm_port, port); if (!(pinfo->flags & FLAG_CONSOLE)) cpm_uart_freebuf(pinfo); @@ -1082,7 +1096,8 @@ static int poll_wait_key(char *obuf, struct uart_cpm_port *pinfo) static int cpm_get_poll_char(struct uart_port *port) { - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + struct uart_cpm_port *pinfo = + container_of(port, struct uart_cpm_port, port); if (!serial_polled) { serial_polled = 1; @@ -1099,7 +1114,8 @@ static int cpm_get_poll_char(struct uart_port *port) static void cpm_put_poll_char(struct uart_port *port, unsigned char c) { - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + struct uart_cpm_port *pinfo = + container_of(port, struct uart_cpm_port, port); static char ch[2]; ch[0] = (char)c; @@ -1438,7 +1454,6 @@ static struct of_device_id cpm_uart_match[] = { static struct platform_driver cpm_uart_driver = { .driver = { .name = "cpm_uart", - .owner = THIS_MODULE, .of_match_table = cpm_uart_match, }, .probe = cpm_uart_probe, diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 58e6f61a87e4..0c1825b0b41d 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -3676,12 +3676,6 @@ rs_close(struct tty_struct *tty, struct file * filp) } info->port.flags |= ASYNC_CLOSING; /* - * Save the termios structure, since this port may have - * separate termios for callout and dialin. - */ - if (info->port.flags & ASYNC_NORMAL_ACTIVE) - 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. */ @@ -4076,11 +4070,6 @@ rs_open(struct tty_struct *tty, struct file * filp) return retval; } - if ((info->port.count == 1) && (info->port.flags & ASYNC_SPLIT_TERMIOS)) { - tty->termios = info->normal_termios; - change_speed(info); - } - #ifdef SERIAL_DEBUG_OPEN printk("rs_open ttyS%d successful...\n", info->line); #endif @@ -4327,7 +4316,6 @@ static int __init rs_init(void) info->custom_divisor = 0; info->x_char = 0; info->event = 0; - info->normal_termios = driver->init_termios; info->xmit.buf = NULL; info->xmit.tail = info->xmit.head = 0; info->first_recv_buffer = info->last_recv_buffer = NULL; diff --git a/drivers/tty/serial/crisv10.h b/drivers/tty/serial/crisv10.h index 7599014ae03f..15a52ee58251 100644 --- a/drivers/tty/serial/crisv10.h +++ b/drivers/tty/serial/crisv10.h @@ -98,7 +98,6 @@ struct e100_serial { struct work_struct work; struct async_icount icount; /* error-statistics etc.*/ - struct ktermios normal_termios; unsigned long char_time_usec; /* The time for 1 char, in usecs */ unsigned long flush_time_usec; /* How often we should flush */ diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index a514ee6f5406..64fe25a4285c 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -98,7 +98,7 @@ static int __init parse_options(struct earlycon_device *device, strlcpy(device->options, options, length); } - if (mmio || mmio32) + if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM32) pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n", mmio32 ? "32" : "", (unsigned long long)port->mapbase, diff --git a/drivers/tty/serial/efm32-uart.c b/drivers/tty/serial/efm32-uart.c index 55d9c00112cc..195acc868763 100644 --- a/drivers/tty/serial/efm32-uart.c +++ b/drivers/tty/serial/efm32-uart.c @@ -814,7 +814,6 @@ static struct platform_driver efm32_uart_driver = { .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, .of_match_table = efm32_uart_dt_ids, }, }; diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 6dd53af546a3..e7cde3a9566d 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1786,15 +1786,13 @@ static int lpuart_probe(struct platform_device *pdev) } sport->port.line = ret; sport->lpuart32 = of_device_is_compatible(np, "fsl,ls1021a-lpuart"); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - sport->port.mapbase = res->start; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); sport->port.membase = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(sport->port.membase)) return PTR_ERR(sport->port.membase); + sport->port.mapbase = res->start; sport->port.dev = &pdev->dev; sport->port.type = PORT_LPUART; sport->port.iotype = UPIO_MEM; @@ -1862,6 +1860,20 @@ static int lpuart_suspend(struct device *dev) static int lpuart_resume(struct device *dev) { struct lpuart_port *sport = dev_get_drvdata(dev); + unsigned long temp; + + if (sport->lpuart32) { + lpuart32_setup_watermark(sport); + temp = lpuart32_read(sport->port.membase + UARTCTRL); + temp |= (UARTCTRL_RIE | UARTCTRL_TIE | UARTCTRL_RE | + UARTCTRL_TE | UARTCTRL_ILIE); + lpuart32_write(temp, sport->port.membase + UARTCTRL); + } else { + lpuart_setup_watermark(sport); + temp = readb(sport->port.membase + UARTCR2); + temp |= (UARTCR2_RIE | UARTCR2_TIE | UARTCR2_RE | UARTCR2_TE); + writeb(temp, sport->port.membase + UARTCR2); + } uart_resume_port(&lpuart_reg, &sport->port); @@ -1876,7 +1888,6 @@ static struct platform_driver lpuart_driver = { .remove = lpuart_remove, .driver = { .name = "fsl-lpuart", - .owner = THIS_MODULE, .of_match_table = lpuart_dt_ids, .pm = &lpuart_pm_ops, }, @@ -1884,11 +1895,8 @@ static struct platform_driver lpuart_driver = { static int __init lpuart_serial_init(void) { - int ret; - - pr_info("serial: Freescale lpuart driver\n"); + int ret = uart_register_driver(&lpuart_reg); - ret = uart_register_driver(&lpuart_reg); if (ret) return ret; diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c index d4620fe5da2e..45fc323b95e6 100644 --- a/drivers/tty/serial/icom.c +++ b/drivers/tty/serial/icom.c @@ -1550,8 +1550,10 @@ static int icom_probe(struct pci_dev *dev, icom_adapter->base_addr = pci_ioremap_bar(dev, 0); - if (!icom_adapter->base_addr) + if (!icom_adapter->base_addr) { + retval = -ENOMEM; goto probe_exit1; + } /* save off irq and request irq line */ if ( (retval = request_irq(dev->irq, icom_interrupt, diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 044e86d528ae..4c5e9092e2d7 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -80,6 +80,7 @@ #define URXD_FRMERR (1<<12) #define URXD_BRK (1<<11) #define URXD_PRERR (1<<10) +#define URXD_RX_DATA (0xFF<<0) #define UCR1_ADEN (1<<15) /* Auto detect interrupt */ #define UCR1_ADBR (1<<14) /* Auto detect baud rate */ #define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */ @@ -301,7 +302,7 @@ static inline int is_imx6q_uart(struct imx_port *sport) /* * Save and restore functions for UCR1, UCR2 and UCR3 registers */ -#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_IMX_CONSOLE) +#if defined(CONFIG_SERIAL_IMX_CONSOLE) static void imx_port_ucrs_save(struct uart_port *port, struct imx_port_ucrs *ucr) { @@ -435,12 +436,14 @@ static void imx_stop_rx(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; - /* - * We are maybe in the SMP context, so if the DMA TX thread is running - * on other cpu, we have to wait for it to finish. - */ - if (sport->dma_is_enabled && sport->dma_is_rxing) - return; + if (sport->dma_is_enabled && sport->dma_is_rxing) { + if (sport->port.suspended) { + dmaengine_terminate_all(sport->dma_chan_rx); + sport->dma_is_rxing = 0; + } else { + return; + } + } temp = readl(sport->port.membase + UCR2); writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2); @@ -464,9 +467,19 @@ static inline void imx_transmit_buffer(struct imx_port *sport) { struct circ_buf *xmit = &sport->port.state->xmit; + if (sport->port.x_char) { + /* Send next char */ + writel(sport->port.x_char, sport->port.membase + URTX0); + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { + imx_stop_tx(&sport->port); + return; + } + while (!uart_circ_empty(xmit) && - !(readl(sport->port.membase + uts_reg(sport)) - & UTS_TXFULL)) { + !(readl(sport->port.membase + uts_reg(sport)) & UTS_TXFULL)) { /* send xmit->buf[xmit->tail] * out the port here */ writel(xmit->buf[xmit->tail], sport->port.membase + URTX0); @@ -567,9 +580,6 @@ static void imx_start_tx(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; - if (uart_circ_empty(&port->state->xmit)) - return; - if (USE_IRDA(sport)) { /* half duplex in IrDA mode; have to disable receive mode */ temp = readl(sport->port.membase + UCR4); @@ -604,7 +614,10 @@ static void imx_start_tx(struct uart_port *port) } if (sport->dma_is_enabled) { - imx_dma_tx(sport); + /* FIXME: port->x_char must be transmitted if != 0 */ + if (!uart_circ_empty(&port->state->xmit) && + !uart_tx_stopped(port)) + imx_dma_tx(sport); return; } @@ -632,27 +645,10 @@ static irqreturn_t imx_rtsint(int irq, void *dev_id) static irqreturn_t imx_txint(int irq, void *dev_id) { struct imx_port *sport = dev_id; - struct circ_buf *xmit = &sport->port.state->xmit; unsigned long flags; spin_lock_irqsave(&sport->port.lock, flags); - if (sport->port.x_char) { - /* Send next char */ - writel(sport->port.x_char, sport->port.membase + URTX0); - goto out; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { - imx_stop_tx(&sport->port); - goto out; - } - imx_transmit_buffer(sport); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&sport->port); - -out: spin_unlock_irqrestore(&sport->port.lock, flags); return IRQ_HANDLED; } @@ -823,11 +819,9 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; - temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS; - + temp = readl(sport->port.membase + UCR2) & ~(UCR2_CTS | UCR2_CTSC); if (mctrl & TIOCM_RTS) - if (!sport->dma_is_enabled) - temp |= UCR2_CTS; + temp |= UCR2_CTS | UCR2_CTSC; writel(temp, sport->port.membase + UCR2); @@ -997,7 +991,6 @@ static int imx_uart_dma_init(struct imx_port *sport) sport->rx_buf = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!sport->rx_buf) { - dev_err(dev, "cannot alloc DMA buffer.\n"); ret = -ENOMEM; goto err; } @@ -1082,11 +1075,11 @@ static int imx_startup(struct uart_port *port) retval = clk_prepare_enable(sport->clk_per); if (retval) - goto error_out1; + return retval; retval = clk_prepare_enable(sport->clk_ipg); if (retval) { clk_disable_unprepare(sport->clk_per); - goto error_out1; + return retval; } imx_setup_ufcr(sport, 0); @@ -1115,37 +1108,6 @@ static int imx_startup(struct uart_port *port) while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0)) udelay(1); - /* - * Allocate the IRQ(s) i.MX1 has three interrupts whereas later - * chips only have one interrupt. - */ - if (sport->txirq > 0) { - retval = request_irq(sport->rxirq, imx_rxint, 0, - dev_name(port->dev), sport); - if (retval) - goto error_out1; - - retval = request_irq(sport->txirq, imx_txint, 0, - dev_name(port->dev), sport); - if (retval) - goto error_out2; - - /* do not use RTS IRQ on IrDA */ - if (!USE_IRDA(sport)) { - retval = request_irq(sport->rtsirq, imx_rtsint, 0, - dev_name(port->dev), sport); - if (retval) - goto error_out3; - } - } else { - retval = request_irq(sport->port.irq, imx_int, 0, - dev_name(port->dev), sport); - if (retval) { - free_irq(sport->port.irq, sport); - goto error_out1; - } - } - spin_lock_irqsave(&sport->port.lock, flags); /* * Finally, clear and enable interrupts @@ -1207,15 +1169,6 @@ static int imx_startup(struct uart_port *port) } return 0; - -error_out3: - if (sport->txirq) - free_irq(sport->txirq, sport); -error_out2: - if (sport->rxirq) - free_irq(sport->rxirq, sport); -error_out1: - return retval; } static void imx_shutdown(struct uart_port *port) @@ -1225,9 +1178,18 @@ static void imx_shutdown(struct uart_port *port) unsigned long flags; if (sport->dma_is_enabled) { + int ret; + /* We have to wait for the DMA to finish. */ - wait_event(sport->dma_wait, + ret = wait_event_interruptible(sport->dma_wait, !sport->dma_is_rxing && !sport->dma_is_txing); + if (ret != 0) { + sport->dma_is_rxing = 0; + sport->dma_is_txing = 0; + dmaengine_terminate_all(sport->dma_chan_tx); + dmaengine_terminate_all(sport->dma_chan_rx); + } + imx_stop_tx(port); imx_stop_rx(port); imx_disable_dma(sport); imx_uart_dma_exit(sport); @@ -1252,17 +1214,6 @@ static void imx_shutdown(struct uart_port *port) del_timer_sync(&sport->timer); /* - * Free the interrupts - */ - if (sport->txirq > 0) { - if (!USE_IRDA(sport)) - free_irq(sport->rtsirq, sport); - free_irq(sport->txirq, sport); - free_irq(sport->rxirq, sport); - } else - free_irq(sport->port.irq, sport); - - /* * Disable all interrupts, port and break condition. */ @@ -1504,66 +1455,65 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser) } #if defined(CONFIG_CONSOLE_POLL) -static int imx_poll_get_char(struct uart_port *port) + +static int imx_poll_init(struct uart_port *port) { - struct imx_port_ucrs old_ucr; - unsigned int status; - unsigned char c; + struct imx_port *sport = (struct imx_port *)port; + unsigned long flags; + unsigned long temp; + int retval; - /* save control registers */ - imx_port_ucrs_save(port, &old_ucr); + retval = clk_prepare_enable(sport->clk_ipg); + if (retval) + return retval; + retval = clk_prepare_enable(sport->clk_per); + if (retval) + clk_disable_unprepare(sport->clk_ipg); - /* disable interrupts */ - writel(UCR1_UARTEN, port->membase + UCR1); - writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI), - port->membase + UCR2); - writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN), - port->membase + UCR3); + imx_setup_ufcr(sport, 0); - /* poll */ - do { - status = readl(port->membase + USR2); - } while (~status & USR2_RDR); + spin_lock_irqsave(&sport->port.lock, flags); - /* read */ - c = readl(port->membase + URXD0); + temp = readl(sport->port.membase + UCR1); + if (is_imx1_uart(sport)) + temp |= IMX1_UCR1_UARTCLKEN; + temp |= UCR1_UARTEN | UCR1_RRDYEN; + temp &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN); + writel(temp, sport->port.membase + UCR1); - /* restore control registers */ - imx_port_ucrs_restore(port, &old_ucr); + temp = readl(sport->port.membase + UCR2); + temp |= UCR2_RXEN; + writel(temp, sport->port.membase + UCR2); + + spin_unlock_irqrestore(&sport->port.lock, flags); - return c; + return 0; } -static void imx_poll_put_char(struct uart_port *port, unsigned char c) +static int imx_poll_get_char(struct uart_port *port) { - struct imx_port_ucrs old_ucr; - unsigned int status; + if (!(readl_relaxed(port->membase + USR2) & USR2_RDR)) + return NO_POLL_CHAR; - /* save control registers */ - imx_port_ucrs_save(port, &old_ucr); + return readl_relaxed(port->membase + URXD0) & URXD_RX_DATA; +} - /* disable interrupts */ - writel(UCR1_UARTEN, port->membase + UCR1); - writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI), - port->membase + UCR2); - writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN), - port->membase + UCR3); +static void imx_poll_put_char(struct uart_port *port, unsigned char c) +{ + unsigned int status; /* drain */ do { - status = readl(port->membase + USR1); + status = readl_relaxed(port->membase + USR1); } while (~status & USR1_TRDY); /* write */ - writel(c, port->membase + URTX0); + writel_relaxed(c, port->membase + URTX0); /* flush */ do { - status = readl(port->membase + USR2); + status = readl_relaxed(port->membase + USR2); } while (~status & USR2_TXDC); - - /* restore control registers */ - imx_port_ucrs_restore(port, &old_ucr); } #endif @@ -1584,6 +1534,7 @@ static struct uart_ops imx_pops = { .config_port = imx_config_port, .verify_port = imx_verify_port, #if defined(CONFIG_CONSOLE_POLL) + .poll_init = imx_poll_init, .poll_get_char = imx_poll_get_char, .poll_put_char = imx_poll_put_char, #endif @@ -1948,6 +1899,36 @@ static int serial_imx_probe(struct platform_device *pdev) sport->port.uartclk = clk_get_rate(sport->clk_per); + /* + * Allocate the IRQ(s) i.MX1 has three interrupts whereas later + * chips only have one interrupt. + */ + if (sport->txirq > 0) { + ret = devm_request_irq(&pdev->dev, sport->rxirq, imx_rxint, 0, + dev_name(&pdev->dev), sport); + if (ret) + return ret; + + ret = devm_request_irq(&pdev->dev, sport->txirq, imx_txint, 0, + dev_name(&pdev->dev), sport); + if (ret) + return ret; + + /* do not use RTS IRQ on IrDA */ + if (!USE_IRDA(sport)) { + ret = devm_request_irq(&pdev->dev, sport->rtsirq, + imx_rtsint, 0, + dev_name(&pdev->dev), sport); + if (ret) + return ret; + } + } else { + ret = devm_request_irq(&pdev->dev, sport->port.irq, imx_int, 0, + dev_name(&pdev->dev), sport); + if (ret) + return ret; + } + imx_ports[sport->port.line] = sport; platform_set_drvdata(pdev, sport); @@ -1971,18 +1952,14 @@ static struct platform_driver serial_imx_driver = { .id_table = imx_uart_devtype, .driver = { .name = "imx-uart", - .owner = THIS_MODULE, .of_match_table = imx_uart_dt_ids, }, }; static int __init imx_serial_init(void) { - int ret; - - pr_info("Serial: IMX driver\n"); + int ret = uart_register_driver(&imx_reg); - ret = uart_register_driver(&imx_reg); if (ret) return ret; diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c index 99b7b8697861..991e6dce916e 100644 --- a/drivers/tty/serial/ip22zilog.c +++ b/drivers/tty/serial/ip22zilog.c @@ -544,7 +544,8 @@ static unsigned int ip22zilog_get_mctrl(struct uart_port *port) /* The port lock is held and interrupts are disabled. */ static void ip22zilog_set_mctrl(struct uart_port *port, unsigned int mctrl) { - struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port; + struct uart_ip22zilog_port *up = + container_of(port, struct uart_ip22zilog_port, port); struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port); unsigned char set_bits, clear_bits; @@ -568,7 +569,8 @@ static void ip22zilog_set_mctrl(struct uart_port *port, unsigned int mctrl) /* The port lock is held and interrupts are disabled. */ static void ip22zilog_stop_tx(struct uart_port *port) { - struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port; + struct uart_ip22zilog_port *up = + container_of(port, struct uart_ip22zilog_port, port); up->flags |= IP22ZILOG_FLAG_TX_STOPPED; } @@ -576,7 +578,8 @@ static void ip22zilog_stop_tx(struct uart_port *port) /* The port lock is held and interrupts are disabled. */ static void ip22zilog_start_tx(struct uart_port *port) { - struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port; + struct uart_ip22zilog_port *up = + container_of(port, struct uart_ip22zilog_port, port); struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port); unsigned char status; @@ -636,7 +639,8 @@ static void ip22zilog_stop_rx(struct uart_port *port) /* The port lock is held. */ static void ip22zilog_enable_ms(struct uart_port *port) { - struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port; + struct uart_ip22zilog_port *up = + container_of(port, struct uart_ip22zilog_port, port); struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port); unsigned char new_reg; @@ -652,7 +656,8 @@ static void ip22zilog_enable_ms(struct uart_port *port) /* The port lock is not held. */ static void ip22zilog_break_ctl(struct uart_port *port, int break_state) { - struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port; + struct uart_ip22zilog_port *up = + container_of(port, struct uart_ip22zilog_port, port); struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port); unsigned char set_bits, clear_bits, new_reg; unsigned long flags; @@ -873,7 +878,8 @@ static void ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port; + struct uart_ip22zilog_port *up = + container_of(port, struct uart_ip22zilog_port, port); unsigned long flags; int baud, brg; diff --git a/drivers/tty/serial/jsm/Makefile b/drivers/tty/serial/jsm/Makefile index e46b6e0f8b18..705d1ff6fdeb 100644 --- a/drivers/tty/serial/jsm/Makefile +++ b/drivers/tty/serial/jsm/Makefile @@ -4,5 +4,5 @@ obj-$(CONFIG_SERIAL_JSM) += jsm.o -jsm-objs := jsm_driver.o jsm_neo.o jsm_tty.o +jsm-objs := jsm_driver.o jsm_neo.o jsm_tty.o jsm_cls.o diff --git a/drivers/tty/serial/jsm/jsm.h b/drivers/tty/serial/jsm/jsm.h index 844d5e4eb1aa..0b79b87df47d 100644 --- a/drivers/tty/serial/jsm/jsm.h +++ b/drivers/tty/serial/jsm/jsm.h @@ -13,11 +13,6 @@ * 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. - * * Contact Information: * Scott H Kilau <Scott_Kilau@digi.com> * Wendy Xiong <wendyx@us.ibm.com> @@ -67,6 +62,20 @@ do { \ #define MAXPORTS 8 #define MAX_STOPS_SENT 5 +/* Board ids */ +#define PCI_DEVICE_ID_CLASSIC_4 0x0028 +#define PCI_DEVICE_ID_CLASSIC_8 0x0029 +#define PCI_DEVICE_ID_CLASSIC_4_422 0x00D0 +#define PCI_DEVICE_ID_CLASSIC_8_422 0x00D1 +#define PCI_DEVICE_ID_NEO_4 0x00B0 +#define PCI_DEVICE_ID_NEO_1_422 0x00CC +#define PCI_DEVICE_ID_NEO_1_422_485 0x00CD +#define PCI_DEVICE_ID_NEO_2_422_485 0x00CE +#define PCIE_DEVICE_ID_NEO_8 0x00F0 +#define PCIE_DEVICE_ID_NEO_4 0x00F1 +#define PCIE_DEVICE_ID_NEO_4RJ45 0x00F2 +#define PCIE_DEVICE_ID_NEO_8RJ45 0x00F3 + /* Board type definitions */ #define T_NEO 0000 @@ -102,21 +111,21 @@ struct jsm_channel; ************************************************************************/ struct board_ops { irq_handler_t intr; - void (*uart_init) (struct jsm_channel *ch); - void (*uart_off) (struct jsm_channel *ch); - void (*param) (struct jsm_channel *ch); - void (*assert_modem_signals) (struct jsm_channel *ch); - void (*flush_uart_write) (struct jsm_channel *ch); - void (*flush_uart_read) (struct jsm_channel *ch); - void (*disable_receiver) (struct jsm_channel *ch); - void (*enable_receiver) (struct jsm_channel *ch); - void (*send_break) (struct jsm_channel *ch); - void (*clear_break) (struct jsm_channel *ch, int); - void (*send_start_character) (struct jsm_channel *ch); - void (*send_stop_character) (struct jsm_channel *ch); - void (*copy_data_from_queue_to_uart) (struct jsm_channel *ch); - u32 (*get_uart_bytes_left) (struct jsm_channel *ch); - void (*send_immediate_char) (struct jsm_channel *ch, unsigned char); + void (*uart_init)(struct jsm_channel *ch); + void (*uart_off)(struct jsm_channel *ch); + void (*param)(struct jsm_channel *ch); + void (*assert_modem_signals)(struct jsm_channel *ch); + void (*flush_uart_write)(struct jsm_channel *ch); + void (*flush_uart_read)(struct jsm_channel *ch); + void (*disable_receiver)(struct jsm_channel *ch); + void (*enable_receiver)(struct jsm_channel *ch); + void (*send_break)(struct jsm_channel *ch); + void (*clear_break)(struct jsm_channel *ch); + void (*send_start_character)(struct jsm_channel *ch); + void (*send_stop_character)(struct jsm_channel *ch); + void (*copy_data_from_queue_to_uart)(struct jsm_channel *ch); + u32 (*get_uart_bytes_left)(struct jsm_channel *ch); + void (*send_immediate_char)(struct jsm_channel *ch, unsigned char); }; @@ -179,7 +188,7 @@ struct jsm_board #define CH_LOOPBACK 0x2000 /* Channel is in lookback mode */ #define CH_BAUD0 0x08000 /* Used for checking B0 transitions */ -/* Our Read/Error/Write queue sizes */ +/* Our Read/Error queue sizes */ #define RQUEUEMASK 0x1FFF /* 8 K - 1 */ #define EQUEUEMASK 0x1FFF /* 8 K - 1 */ #define RQUEUESIZE (RQUEUEMASK + 1) @@ -212,7 +221,10 @@ struct jsm_channel { u8 ch_mostat; /* FEP output modem status */ u8 ch_mistat; /* FEP input modem status */ - struct neo_uart_struct __iomem *ch_neo_uart; /* Pointer to the "mapped" UART struct */ + /* Pointers to the "mapped" UART structs */ + struct neo_uart_struct __iomem *ch_neo_uart; /* NEO card */ + struct cls_uart_struct __iomem *ch_cls_uart; /* Classic card */ + u8 ch_cached_lsr; /* Cached value of the LSR register */ u8 *ch_rqueue; /* Our read queue buffer - malloc'ed */ @@ -244,6 +256,60 @@ struct jsm_channel { u64 ch_xoff_sends; /* Count of xoffs transmitted */ }; +/************************************************************************ + * Per channel/port Classic UART structures * + ************************************************************************ + * Base Structure Entries Usage Meanings to Host * + * * + * W = read write R = read only * + * U = Unused. * + ************************************************************************/ + +struct cls_uart_struct { + u8 txrx; /* WR RHR/THR - Holding Reg */ + u8 ier; /* WR IER - Interrupt Enable Reg */ + u8 isr_fcr; /* WR ISR/FCR - Interrupt Status Reg/Fifo Control Reg*/ + u8 lcr; /* WR LCR - Line Control Reg */ + u8 mcr; /* WR MCR - Modem Control Reg */ + u8 lsr; /* WR LSR - Line Status Reg */ + u8 msr; /* WR MSR - Modem Status Reg */ + u8 spr; /* WR SPR - Scratch Pad Reg */ +}; + +/* Where to read the interrupt register (8bits) */ +#define UART_CLASSIC_POLL_ADDR_OFFSET 0x40 + +#define UART_EXAR654_ENHANCED_REGISTER_SET 0xBF + +#define UART_16654_FCR_TXTRIGGER_8 0x0 +#define UART_16654_FCR_TXTRIGGER_16 0x10 +#define UART_16654_FCR_TXTRIGGER_32 0x20 +#define UART_16654_FCR_TXTRIGGER_56 0x30 + +#define UART_16654_FCR_RXTRIGGER_8 0x0 +#define UART_16654_FCR_RXTRIGGER_16 0x40 +#define UART_16654_FCR_RXTRIGGER_56 0x80 +#define UART_16654_FCR_RXTRIGGER_60 0xC0 + +#define UART_IIR_CTSRTS 0x20 /* Received CTS/RTS change of state */ +#define UART_IIR_RDI_TIMEOUT 0x0C /* Receiver data TIMEOUT */ + +/* + * These are the EXTENDED definitions for the Exar 654's Interrupt + * Enable Register. + */ +#define UART_EXAR654_EFR_ECB 0x10 /* Enhanced control bit */ +#define UART_EXAR654_EFR_IXON 0x2 /* Receiver compares Xon1/Xoff1 */ +#define UART_EXAR654_EFR_IXOFF 0x8 /* Transmit Xon1/Xoff1 */ +#define UART_EXAR654_EFR_RTSDTR 0x40 /* Auto RTS/DTR Flow Control Enable */ +#define UART_EXAR654_EFR_CTSDSR 0x80 /* Auto CTS/DSR Flow COntrol Enable */ + +#define UART_EXAR654_XOFF_DETECT 0x1 /* Indicates whether chip saw an incoming XOFF char */ +#define UART_EXAR654_XON_DETECT 0x2 /* Indicates whether chip saw an incoming XON char */ + +#define UART_EXAR654_IER_XOFF 0x20 /* Xoff Interrupt Enable */ +#define UART_EXAR654_IER_RTSDTR 0x40 /* Output Interrupt Enable */ +#define UART_EXAR654_IER_CTSDSR 0x80 /* Input Interrupt Enable */ /************************************************************************ * Per channel/port NEO UART structure * @@ -364,6 +430,7 @@ struct neo_uart_struct { */ extern struct uart_driver jsm_uart_driver; extern struct board_ops jsm_neo_ops; +extern struct board_ops jsm_cls_ops; extern int jsm_debug; /************************************************************************* diff --git a/drivers/tty/serial/jsm/jsm_cls.c b/drivers/tty/serial/jsm/jsm_cls.c new file mode 100644 index 000000000000..bfb0681195b6 --- /dev/null +++ b/drivers/tty/serial/jsm/jsm_cls.c @@ -0,0 +1,982 @@ +/* + * Copyright 2003 Digi International (www.digi.com) + * Scott H Kilau <Scott_Kilau at digi dot com> + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE! + * + * This is shared code between Digi's CVS archive and the + * Linux Kernel sources. + * Changing the source just for reformatting needlessly breaks + * our CVS diff history. + * + * Send any bug fixes/changes to: Eng.Linux at digi dot com. + * Thank you. + * + */ + +#include <linux/delay.h> /* For udelay */ +#include <linux/io.h> /* For read[bwl]/write[bwl] */ +#include <linux/serial.h> /* For struct async_serial */ +#include <linux/serial_reg.h> /* For the various UART offsets */ +#include <linux/pci.h> +#include <linux/tty.h> + +#include "jsm.h" /* Driver main header file */ + +static struct { + unsigned int rate; + unsigned int cflag; +} baud_rates[] = { + { 921600, B921600 }, + { 460800, B460800 }, + { 230400, B230400 }, + { 115200, B115200 }, + { 57600, B57600 }, + { 38400, B38400 }, + { 19200, B19200 }, + { 9600, B9600 }, + { 4800, B4800 }, + { 2400, B2400 }, + { 1200, B1200 }, + { 600, B600 }, + { 300, B300 }, + { 200, B200 }, + { 150, B150 }, + { 134, B134 }, + { 110, B110 }, + { 75, B75 }, + { 50, B50 }, +}; + +static void cls_set_cts_flow_control(struct jsm_channel *ch) +{ + u8 lcrb = readb(&ch->ch_cls_uart->lcr); + u8 ier = readb(&ch->ch_cls_uart->ier); + u8 isr_fcr = 0; + + /* + * The Enhanced Register Set may only be accessed when + * the Line Control Register is set to 0xBFh. + */ + writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr); + + isr_fcr = readb(&ch->ch_cls_uart->isr_fcr); + + /* Turn on CTS flow control, turn off IXON flow control */ + isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_CTSDSR); + isr_fcr &= ~(UART_EXAR654_EFR_IXON); + + writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr); + + /* Write old LCR value back out, which turns enhanced access off */ + writeb(lcrb, &ch->ch_cls_uart->lcr); + + /* + * Enable interrupts for CTS flow, turn off interrupts for + * received XOFF chars + */ + ier |= (UART_EXAR654_IER_CTSDSR); + ier &= ~(UART_EXAR654_IER_XOFF); + writeb(ier, &ch->ch_cls_uart->ier); + + /* Set the usual FIFO values */ + writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr); + + writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_56 | + UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR), + &ch->ch_cls_uart->isr_fcr); + + ch->ch_t_tlevel = 16; +} + +static void cls_set_ixon_flow_control(struct jsm_channel *ch) +{ + u8 lcrb = readb(&ch->ch_cls_uart->lcr); + u8 ier = readb(&ch->ch_cls_uart->ier); + u8 isr_fcr = 0; + + /* + * The Enhanced Register Set may only be accessed when + * the Line Control Register is set to 0xBFh. + */ + writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr); + + isr_fcr = readb(&ch->ch_cls_uart->isr_fcr); + + /* Turn on IXON flow control, turn off CTS flow control */ + isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_IXON); + isr_fcr &= ~(UART_EXAR654_EFR_CTSDSR); + + writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr); + + /* Now set our current start/stop chars while in enhanced mode */ + writeb(ch->ch_startc, &ch->ch_cls_uart->mcr); + writeb(0, &ch->ch_cls_uart->lsr); + writeb(ch->ch_stopc, &ch->ch_cls_uart->msr); + writeb(0, &ch->ch_cls_uart->spr); + + /* Write old LCR value back out, which turns enhanced access off */ + writeb(lcrb, &ch->ch_cls_uart->lcr); + + /* + * Disable interrupts for CTS flow, turn on interrupts for + * received XOFF chars + */ + ier &= ~(UART_EXAR654_IER_CTSDSR); + ier |= (UART_EXAR654_IER_XOFF); + writeb(ier, &ch->ch_cls_uart->ier); + + /* Set the usual FIFO values */ + writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr); + + writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 | + UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR), + &ch->ch_cls_uart->isr_fcr); +} + +static void cls_set_no_output_flow_control(struct jsm_channel *ch) +{ + u8 lcrb = readb(&ch->ch_cls_uart->lcr); + u8 ier = readb(&ch->ch_cls_uart->ier); + u8 isr_fcr = 0; + + /* + * The Enhanced Register Set may only be accessed when + * the Line Control Register is set to 0xBFh. + */ + writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr); + + isr_fcr = readb(&ch->ch_cls_uart->isr_fcr); + + /* Turn off IXON flow control, turn off CTS flow control */ + isr_fcr |= (UART_EXAR654_EFR_ECB); + isr_fcr &= ~(UART_EXAR654_EFR_CTSDSR | UART_EXAR654_EFR_IXON); + + writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr); + + /* Write old LCR value back out, which turns enhanced access off */ + writeb(lcrb, &ch->ch_cls_uart->lcr); + + /* + * Disable interrupts for CTS flow, turn off interrupts for + * received XOFF chars + */ + ier &= ~(UART_EXAR654_IER_CTSDSR); + ier &= ~(UART_EXAR654_IER_XOFF); + writeb(ier, &ch->ch_cls_uart->ier); + + /* Set the usual FIFO values */ + writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr); + + writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 | + UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR), + &ch->ch_cls_uart->isr_fcr); + + ch->ch_r_watermark = 0; + ch->ch_t_tlevel = 16; + ch->ch_r_tlevel = 16; +} + +static void cls_set_rts_flow_control(struct jsm_channel *ch) +{ + u8 lcrb = readb(&ch->ch_cls_uart->lcr); + u8 ier = readb(&ch->ch_cls_uart->ier); + u8 isr_fcr = 0; + + /* + * The Enhanced Register Set may only be accessed when + * the Line Control Register is set to 0xBFh. + */ + writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr); + + isr_fcr = readb(&ch->ch_cls_uart->isr_fcr); + + /* Turn on RTS flow control, turn off IXOFF flow control */ + isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_RTSDTR); + isr_fcr &= ~(UART_EXAR654_EFR_IXOFF); + + writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr); + + /* Write old LCR value back out, which turns enhanced access off */ + writeb(lcrb, &ch->ch_cls_uart->lcr); + + /* Enable interrupts for RTS flow */ + ier |= (UART_EXAR654_IER_RTSDTR); + writeb(ier, &ch->ch_cls_uart->ier); + + /* Set the usual FIFO values */ + writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr); + + writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_56 | + UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR), + &ch->ch_cls_uart->isr_fcr); + + ch->ch_r_watermark = 4; + ch->ch_r_tlevel = 8; +} + +static void cls_set_ixoff_flow_control(struct jsm_channel *ch) +{ + u8 lcrb = readb(&ch->ch_cls_uart->lcr); + u8 ier = readb(&ch->ch_cls_uart->ier); + u8 isr_fcr = 0; + + /* + * The Enhanced Register Set may only be accessed when + * the Line Control Register is set to 0xBFh. + */ + writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr); + + isr_fcr = readb(&ch->ch_cls_uart->isr_fcr); + + /* Turn on IXOFF flow control, turn off RTS flow control */ + isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_IXOFF); + isr_fcr &= ~(UART_EXAR654_EFR_RTSDTR); + + writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr); + + /* Now set our current start/stop chars while in enhanced mode */ + writeb(ch->ch_startc, &ch->ch_cls_uart->mcr); + writeb(0, &ch->ch_cls_uart->lsr); + writeb(ch->ch_stopc, &ch->ch_cls_uart->msr); + writeb(0, &ch->ch_cls_uart->spr); + + /* Write old LCR value back out, which turns enhanced access off */ + writeb(lcrb, &ch->ch_cls_uart->lcr); + + /* Disable interrupts for RTS flow */ + ier &= ~(UART_EXAR654_IER_RTSDTR); + writeb(ier, &ch->ch_cls_uart->ier); + + /* Set the usual FIFO values */ + writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr); + + writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 | + UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR), + &ch->ch_cls_uart->isr_fcr); +} + +static void cls_set_no_input_flow_control(struct jsm_channel *ch) +{ + u8 lcrb = readb(&ch->ch_cls_uart->lcr); + u8 ier = readb(&ch->ch_cls_uart->ier); + u8 isr_fcr = 0; + + /* + * The Enhanced Register Set may only be accessed when + * the Line Control Register is set to 0xBFh. + */ + writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr); + + isr_fcr = readb(&ch->ch_cls_uart->isr_fcr); + + /* Turn off IXOFF flow control, turn off RTS flow control */ + isr_fcr |= (UART_EXAR654_EFR_ECB); + isr_fcr &= ~(UART_EXAR654_EFR_RTSDTR | UART_EXAR654_EFR_IXOFF); + + writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr); + + /* Write old LCR value back out, which turns enhanced access off */ + writeb(lcrb, &ch->ch_cls_uart->lcr); + + /* Disable interrupts for RTS flow */ + ier &= ~(UART_EXAR654_IER_RTSDTR); + writeb(ier, &ch->ch_cls_uart->ier); + + /* Set the usual FIFO values */ + writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr); + + writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 | + UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR), + &ch->ch_cls_uart->isr_fcr); + + ch->ch_t_tlevel = 16; + ch->ch_r_tlevel = 16; +} + +/* + * cls_clear_break. + * Determines whether its time to shut off break condition. + * + * No locks are assumed to be held when calling this function. + * channel lock is held and released in this function. + */ +static void cls_clear_break(struct jsm_channel *ch) +{ + unsigned long lock_flags; + + spin_lock_irqsave(&ch->ch_lock, lock_flags); + + /* Turn break off, and unset some variables */ + if (ch->ch_flags & CH_BREAK_SENDING) { + u8 temp = readb(&ch->ch_cls_uart->lcr); + + writeb((temp & ~UART_LCR_SBC), &ch->ch_cls_uart->lcr); + + ch->ch_flags &= ~(CH_BREAK_SENDING); + jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, + "clear break Finishing UART_LCR_SBC! finished: %lx\n", + jiffies); + } + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); +} + +static void cls_disable_receiver(struct jsm_channel *ch) +{ + u8 tmp = readb(&ch->ch_cls_uart->ier); + + tmp &= ~(UART_IER_RDI); + writeb(tmp, &ch->ch_cls_uart->ier); +} + +static void cls_enable_receiver(struct jsm_channel *ch) +{ + u8 tmp = readb(&ch->ch_cls_uart->ier); + + tmp |= (UART_IER_RDI); + writeb(tmp, &ch->ch_cls_uart->ier); +} + +/* Make the UART raise any of the output signals we want up */ +static void cls_assert_modem_signals(struct jsm_channel *ch) +{ + if (!ch) + return; + + writeb(ch->ch_mostat, &ch->ch_cls_uart->mcr); +} + +static void cls_copy_data_from_uart_to_queue(struct jsm_channel *ch) +{ + int qleft = 0; + u8 linestatus = 0; + u8 error_mask = 0; + u16 head; + u16 tail; + unsigned long flags; + + if (!ch) + return; + + spin_lock_irqsave(&ch->ch_lock, flags); + + /* cache head and tail of queue */ + head = ch->ch_r_head & RQUEUEMASK; + tail = ch->ch_r_tail & RQUEUEMASK; + + /* Get our cached LSR */ + linestatus = ch->ch_cached_lsr; + ch->ch_cached_lsr = 0; + + /* Store how much space we have left in the queue */ + qleft = tail - head - 1; + if (qleft < 0) + qleft += RQUEUEMASK + 1; + + /* + * Create a mask to determine whether we should + * insert the character (if any) into our queue. + */ + if (ch->ch_c_iflag & IGNBRK) + error_mask |= UART_LSR_BI; + + while (1) { + /* + * Grab the linestatus register, we need to + * check to see if there is any data to read + */ + linestatus = readb(&ch->ch_cls_uart->lsr); + + /* Break out if there is no data to fetch */ + if (!(linestatus & UART_LSR_DR)) + break; + + /* + * Discard character if we are ignoring the error mask + * which in this case is the break signal. + */ + if (linestatus & error_mask) { + u8 discard; + + linestatus = 0; + discard = readb(&ch->ch_cls_uart->txrx); + continue; + } + + /* + * If our queue is full, we have no choice but to drop some + * data. The assumption is that HWFLOW or SWFLOW should have + * stopped things way way before we got to this point. + * + * I decided that I wanted to ditch the oldest data first, + * I hope thats okay with everyone? Yes? Good. + */ + while (qleft < 1) { + tail = (tail + 1) & RQUEUEMASK; + ch->ch_r_tail = tail; + ch->ch_err_overrun++; + qleft++; + } + + ch->ch_equeue[head] = linestatus & (UART_LSR_BI | UART_LSR_PE + | UART_LSR_FE); + ch->ch_rqueue[head] = readb(&ch->ch_cls_uart->txrx); + + qleft--; + + if (ch->ch_equeue[head] & UART_LSR_PE) + ch->ch_err_parity++; + if (ch->ch_equeue[head] & UART_LSR_BI) + ch->ch_err_break++; + if (ch->ch_equeue[head] & UART_LSR_FE) + ch->ch_err_frame++; + + /* Add to, and flip head if needed */ + head = (head + 1) & RQUEUEMASK; + ch->ch_rxcount++; + } + + /* + * Write new final heads to channel structure. + */ + ch->ch_r_head = head & RQUEUEMASK; + ch->ch_e_head = head & EQUEUEMASK; + + spin_unlock_irqrestore(&ch->ch_lock, flags); +} + +static void cls_copy_data_from_queue_to_uart(struct jsm_channel *ch) +{ + u16 tail; + int n; + int qlen; + u32 len_written = 0; + struct circ_buf *circ; + + if (!ch) + return; + + circ = &ch->uart_port.state->xmit; + + /* No data to write to the UART */ + if (uart_circ_empty(circ)) + return; + + /* If port is "stopped", don't send any data to the UART */ + if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_BREAK_SENDING)) + return; + + /* We have to do it this way, because of the EXAR TXFIFO count bug. */ + if (!(ch->ch_flags & (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM))) + return; + + n = 32; + + /* cache tail of queue */ + tail = circ->tail & (UART_XMIT_SIZE - 1); + qlen = uart_circ_chars_pending(circ); + + /* Find minimum of the FIFO space, versus queue length */ + n = min(n, qlen); + + while (n > 0) { + writeb(circ->buf[tail], &ch->ch_cls_uart->txrx); + tail = (tail + 1) & (UART_XMIT_SIZE - 1); + n--; + ch->ch_txcount++; + len_written++; + } + + /* Update the final tail */ + circ->tail = tail & (UART_XMIT_SIZE - 1); + + if (len_written > ch->ch_t_tlevel) + ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); + + if (uart_circ_empty(circ)) + uart_write_wakeup(&ch->uart_port); +} + +static void cls_parse_modem(struct jsm_channel *ch, u8 signals) +{ + u8 msignals = signals; + + jsm_dbg(MSIGS, &ch->ch_bd->pci_dev, + "neo_parse_modem: port: %d msignals: %x\n", + ch->ch_portnum, msignals); + + /* + * Scrub off lower bits. + * They signify delta's, which I don't care about + * Keep DDCD and DDSR though + */ + msignals &= 0xf8; + + if (msignals & UART_MSR_DDCD) + uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_DCD); + if (msignals & UART_MSR_DDSR) + uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_CTS); + + if (msignals & UART_MSR_DCD) + ch->ch_mistat |= UART_MSR_DCD; + else + ch->ch_mistat &= ~UART_MSR_DCD; + + if (msignals & UART_MSR_DSR) + ch->ch_mistat |= UART_MSR_DSR; + else + ch->ch_mistat &= ~UART_MSR_DSR; + + if (msignals & UART_MSR_RI) + ch->ch_mistat |= UART_MSR_RI; + else + ch->ch_mistat &= ~UART_MSR_RI; + + if (msignals & UART_MSR_CTS) + ch->ch_mistat |= UART_MSR_CTS; + else + ch->ch_mistat &= ~UART_MSR_CTS; + + jsm_dbg(MSIGS, &ch->ch_bd->pci_dev, + "Port: %d DTR: %d RTS: %d CTS: %d DSR: %d " "RI: %d CD: %d\n", + ch->ch_portnum, + !!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_DTR), + !!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_RTS), + !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_CTS), + !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DSR), + !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_RI), + !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DCD)); +} + +/* Parse the ISR register for the specific port */ +static inline void cls_parse_isr(struct jsm_board *brd, uint port) +{ + struct jsm_channel *ch; + u8 isr = 0; + unsigned long flags; + + /* + * No need to verify board pointer, it was already + * verified in the interrupt routine. + */ + + if (port > brd->nasync) + return; + + ch = brd->channels[port]; + if (!ch) + return; + + /* Here we try to figure out what caused the interrupt to happen */ + while (1) { + isr = readb(&ch->ch_cls_uart->isr_fcr); + + /* Bail if no pending interrupt on port */ + if (isr & UART_IIR_NO_INT) + break; + + /* Receive Interrupt pending */ + if (isr & (UART_IIR_RDI | UART_IIR_RDI_TIMEOUT)) { + /* Read data from uart -> queue */ + cls_copy_data_from_uart_to_queue(ch); + jsm_check_queue_flow_control(ch); + } + + /* Transmit Hold register empty pending */ + if (isr & UART_IIR_THRI) { + /* Transfer data (if any) from Write Queue -> UART. */ + spin_lock_irqsave(&ch->ch_lock, flags); + ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); + spin_unlock_irqrestore(&ch->ch_lock, flags); + cls_copy_data_from_queue_to_uart(ch); + } + + /* + * CTS/RTS change of state: + * Don't need to do anything, the cls_parse_modem + * below will grab the updated modem signals. + */ + + /* Parse any modem signal changes */ + cls_parse_modem(ch, readb(&ch->ch_cls_uart->msr)); + } +} + +/* Channel lock MUST be held before calling this function! */ +static void cls_flush_uart_write(struct jsm_channel *ch) +{ + u8 tmp = 0; + u8 i = 0; + + if (!ch) + return; + + writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_XMIT), + &ch->ch_cls_uart->isr_fcr); + + for (i = 0; i < 10; i++) { + /* Check to see if the UART feels it completely flushed FIFO */ + tmp = readb(&ch->ch_cls_uart->isr_fcr); + if (tmp & UART_FCR_CLEAR_XMIT) { + jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, + "Still flushing TX UART... i: %d\n", i); + udelay(10); + } else + break; + } + + ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); +} + +/* Channel lock MUST be held before calling this function! */ +static void cls_flush_uart_read(struct jsm_channel *ch) +{ + if (!ch) + return; + + /* + * For complete POSIX compatibility, we should be purging the + * read FIFO in the UART here. + * + * However, clearing the read FIFO (UART_FCR_CLEAR_RCVR) also + * incorrectly flushes write data as well as just basically trashing the + * FIFO. + * + * Presumably, this is a bug in this UART. + */ + + udelay(10); +} + +static void cls_send_start_character(struct jsm_channel *ch) +{ + if (!ch) + return; + + if (ch->ch_startc != __DISABLED_CHAR) { + ch->ch_xon_sends++; + writeb(ch->ch_startc, &ch->ch_cls_uart->txrx); + } +} + +static void cls_send_stop_character(struct jsm_channel *ch) +{ + if (!ch) + return; + + if (ch->ch_stopc != __DISABLED_CHAR) { + ch->ch_xoff_sends++; + writeb(ch->ch_stopc, &ch->ch_cls_uart->txrx); + } +} + +/* + * cls_param() + * Send any/all changes to the line to the UART. + */ +static void cls_param(struct jsm_channel *ch) +{ + u8 lcr = 0; + u8 uart_lcr = 0; + u8 ier = 0; + u32 baud = 9600; + int quot = 0; + struct jsm_board *bd; + int i; + unsigned int cflag; + + bd = ch->ch_bd; + if (!bd) + return; + + /* + * If baud rate is zero, flush queues, and set mval to drop DTR. + */ + if ((ch->ch_c_cflag & (CBAUD)) == 0) { + ch->ch_r_head = 0; + ch->ch_r_tail = 0; + ch->ch_e_head = 0; + ch->ch_e_tail = 0; + + cls_flush_uart_write(ch); + cls_flush_uart_read(ch); + + /* The baudrate is B0 so all modem lines are to be dropped. */ + ch->ch_flags |= (CH_BAUD0); + ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR); + cls_assert_modem_signals(ch); + return; + } + + cflag = C_BAUD(ch->uart_port.state->port.tty); + baud = 9600; + for (i = 0; i < ARRAY_SIZE(baud_rates); i++) { + if (baud_rates[i].cflag == cflag) { + baud = baud_rates[i].rate; + break; + } + } + + if (ch->ch_flags & CH_BAUD0) + ch->ch_flags &= ~(CH_BAUD0); + + if (ch->ch_c_cflag & PARENB) + lcr |= UART_LCR_PARITY; + + if (!(ch->ch_c_cflag & PARODD)) + lcr |= UART_LCR_EPAR; + + /* + * Not all platforms support mark/space parity, + * so this will hide behind an ifdef. + */ +#ifdef CMSPAR + if (ch->ch_c_cflag & CMSPAR) + lcr |= UART_LCR_SPAR; +#endif + + if (ch->ch_c_cflag & CSTOPB) + lcr |= UART_LCR_STOP; + + switch (ch->ch_c_cflag & CSIZE) { + case CS5: + lcr |= UART_LCR_WLEN5; + break; + case CS6: + lcr |= UART_LCR_WLEN6; + break; + case CS7: + lcr |= UART_LCR_WLEN7; + break; + case CS8: + default: + lcr |= UART_LCR_WLEN8; + break; + } + + ier = readb(&ch->ch_cls_uart->ier); + uart_lcr = readb(&ch->ch_cls_uart->lcr); + + quot = ch->ch_bd->bd_dividend / baud; + + if (quot != 0) { + writeb(UART_LCR_DLAB, &ch->ch_cls_uart->lcr); + writeb((quot & 0xff), &ch->ch_cls_uart->txrx); + writeb((quot >> 8), &ch->ch_cls_uart->ier); + writeb(lcr, &ch->ch_cls_uart->lcr); + } + + if (uart_lcr != lcr) + writeb(lcr, &ch->ch_cls_uart->lcr); + + if (ch->ch_c_cflag & CREAD) + ier |= (UART_IER_RDI | UART_IER_RLSI); + + ier |= (UART_IER_THRI | UART_IER_MSI); + + writeb(ier, &ch->ch_cls_uart->ier); + + if (ch->ch_c_cflag & CRTSCTS) + cls_set_cts_flow_control(ch); + else if (ch->ch_c_iflag & IXON) { + /* + * If start/stop is set to disable, + * then we should disable flow control. + */ + if ((ch->ch_startc == __DISABLED_CHAR) || + (ch->ch_stopc == __DISABLED_CHAR)) + cls_set_no_output_flow_control(ch); + else + cls_set_ixon_flow_control(ch); + } else + cls_set_no_output_flow_control(ch); + + if (ch->ch_c_cflag & CRTSCTS) + cls_set_rts_flow_control(ch); + else if (ch->ch_c_iflag & IXOFF) { + /* + * If start/stop is set to disable, + * then we should disable flow control. + */ + if ((ch->ch_startc == __DISABLED_CHAR) || + (ch->ch_stopc == __DISABLED_CHAR)) + cls_set_no_input_flow_control(ch); + else + cls_set_ixoff_flow_control(ch); + } else + cls_set_no_input_flow_control(ch); + + cls_assert_modem_signals(ch); + + /* get current status of the modem signals now */ + cls_parse_modem(ch, readb(&ch->ch_cls_uart->msr)); +} + +/* + * cls_intr() + * + * Classic specific interrupt handler. + */ +static irqreturn_t cls_intr(int irq, void *voidbrd) +{ + struct jsm_board *brd = voidbrd; + unsigned long lock_flags; + unsigned char uart_poll; + uint i = 0; + + /* Lock out the slow poller from running on this board. */ + spin_lock_irqsave(&brd->bd_intr_lock, lock_flags); + + /* + * Check the board's global interrupt offset to see if we + * acctually do have an interrupt pending on us. + */ + uart_poll = readb(brd->re_map_membase + UART_CLASSIC_POLL_ADDR_OFFSET); + + jsm_dbg(INTR, &brd->pci_dev, "%s:%d uart_poll: %x\n", + __FILE__, __LINE__, uart_poll); + + if (!uart_poll) { + jsm_dbg(INTR, &brd->pci_dev, + "Kernel interrupted to me, but no pending interrupts...\n"); + spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags); + return IRQ_NONE; + } + + /* At this point, we have at least SOMETHING to service, dig further. */ + + /* Parse each port to find out what caused the interrupt */ + for (i = 0; i < brd->nasync; i++) + cls_parse_isr(brd, i); + + spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags); + + return IRQ_HANDLED; +} + +/* Inits UART */ +static void cls_uart_init(struct jsm_channel *ch) +{ + unsigned char lcrb = readb(&ch->ch_cls_uart->lcr); + unsigned char isr_fcr = 0; + + writeb(0, &ch->ch_cls_uart->ier); + + /* + * The Enhanced Register Set may only be accessed when + * the Line Control Register is set to 0xBFh. + */ + writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr); + + isr_fcr = readb(&ch->ch_cls_uart->isr_fcr); + + /* Turn on Enhanced/Extended controls */ + isr_fcr |= (UART_EXAR654_EFR_ECB); + + writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr); + + /* Write old LCR value back out, which turns enhanced access off */ + writeb(lcrb, &ch->ch_cls_uart->lcr); + + /* Clear out UART and FIFO */ + readb(&ch->ch_cls_uart->txrx); + + writeb((UART_FCR_ENABLE_FIFO|UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT), + &ch->ch_cls_uart->isr_fcr); + udelay(10); + + ch->ch_flags |= (CH_FIFO_ENABLED | CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); + + readb(&ch->ch_cls_uart->lsr); + readb(&ch->ch_cls_uart->msr); +} + +/* + * Turns off UART. + */ +static void cls_uart_off(struct jsm_channel *ch) +{ + /* Stop all interrupts from accurring. */ + writeb(0, &ch->ch_cls_uart->ier); +} + +/* + * cls_get_uarts_bytes_left. + * Returns 0 is nothing left in the FIFO, returns 1 otherwise. + * + * The channel lock MUST be held by the calling function. + */ +static u32 cls_get_uart_bytes_left(struct jsm_channel *ch) +{ + u8 left = 0; + u8 lsr = readb(&ch->ch_cls_uart->lsr); + + /* Determine whether the Transmitter is empty or not */ + if (!(lsr & UART_LSR_TEMT)) + left = 1; + else { + ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); + left = 0; + } + + return left; +} + +/* + * cls_send_break. + * Starts sending a break thru the UART. + * + * The channel lock MUST be held by the calling function. + */ +static void cls_send_break(struct jsm_channel *ch) +{ + /* Tell the UART to start sending the break */ + if (!(ch->ch_flags & CH_BREAK_SENDING)) { + u8 temp = readb(&ch->ch_cls_uart->lcr); + + writeb((temp | UART_LCR_SBC), &ch->ch_cls_uart->lcr); + ch->ch_flags |= (CH_BREAK_SENDING); + } +} + +/* + * cls_send_immediate_char. + * Sends a specific character as soon as possible to the UART, + * jumping over any bytes that might be in the write queue. + * + * The channel lock MUST be held by the calling function. + */ +static void cls_send_immediate_char(struct jsm_channel *ch, unsigned char c) +{ + writeb(c, &ch->ch_cls_uart->txrx); +} + +struct board_ops jsm_cls_ops = { + .intr = cls_intr, + .uart_init = cls_uart_init, + .uart_off = cls_uart_off, + .param = cls_param, + .assert_modem_signals = cls_assert_modem_signals, + .flush_uart_write = cls_flush_uart_write, + .flush_uart_read = cls_flush_uart_read, + .disable_receiver = cls_disable_receiver, + .enable_receiver = cls_enable_receiver, + .send_break = cls_send_break, + .clear_break = cls_clear_break, + .send_start_character = cls_send_start_character, + .send_stop_character = cls_send_stop_character, + .copy_data_from_queue_to_uart = cls_copy_data_from_queue_to_uart, + .get_uart_bytes_left = cls_get_uart_bytes_left, + .send_immediate_char = cls_send_immediate_char +}; + diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c index a47d882d6743..efbd87a76656 100644 --- a/drivers/tty/serial/jsm/jsm_driver.c +++ b/drivers/tty/serial/jsm/jsm_driver.c @@ -13,11 +13,6 @@ * 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. - * * Contact Information: * Scott H Kilau <Scott_Kilau@digi.com> * Wendy Xiong <wendyx@us.ibm.com> @@ -31,8 +26,7 @@ #include "jsm.h" MODULE_AUTHOR("Digi International, http://www.digi.com"); -MODULE_DESCRIPTION("Driver for the Digi International " - "Neo PCI based product line"); +MODULE_DESCRIPTION("Driver for the Digi International Neo and Classic PCI based product line"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("jsm"); @@ -50,7 +44,7 @@ struct uart_driver jsm_uart_driver = { }; static pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev, - pci_channel_state_t state); + pci_channel_state_t state); static pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev); static void jsm_io_resume(struct pci_dev *pdev); @@ -68,7 +62,7 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent) { int rc = 0; struct jsm_board *brd; - static int adapter_count = 0; + static int adapter_count; rc = pci_enable_device(pdev); if (rc) { @@ -82,10 +76,8 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_disable_device; } - brd = kzalloc(sizeof(struct jsm_board), GFP_KERNEL); + brd = kzalloc(sizeof(*brd), GFP_KERNEL); if (!brd) { - dev_err(&pdev->dev, - "memory allocation for board structure failed\n"); rc = -ENOMEM; goto out_release_regions; } @@ -93,12 +85,37 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* store the info for the board we've found */ brd->boardnum = adapter_count++; brd->pci_dev = pdev; - if (pdev->device == PCIE_DEVICE_ID_NEO_4_IBM) + + switch (pdev->device) { + case PCI_DEVICE_ID_NEO_2DB9: + case PCI_DEVICE_ID_NEO_2DB9PRI: + case PCI_DEVICE_ID_NEO_2RJ45: + case PCI_DEVICE_ID_NEO_2RJ45PRI: + case PCI_DEVICE_ID_NEO_2_422_485: + brd->maxports = 2; + break; + + case PCI_DEVICE_ID_CLASSIC_4: + case PCI_DEVICE_ID_CLASSIC_4_422: + case PCI_DEVICE_ID_NEO_4: + case PCIE_DEVICE_ID_NEO_4: + case PCIE_DEVICE_ID_NEO_4RJ45: + case PCIE_DEVICE_ID_NEO_4_IBM: brd->maxports = 4; - else if (pdev->device == PCI_DEVICE_ID_DIGI_NEO_8) + break; + + case PCI_DEVICE_ID_CLASSIC_8: + case PCI_DEVICE_ID_CLASSIC_8_422: + case PCI_DEVICE_ID_DIGI_NEO_8: + case PCIE_DEVICE_ID_NEO_8: + case PCIE_DEVICE_ID_NEO_8RJ45: brd->maxports = 8; - else - brd->maxports = 2; + break; + + default: + brd->maxports = 1; + break; + } spin_lock_init(&brd->bd_intr_lock); @@ -107,36 +124,109 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent) brd->irq = pdev->irq; - jsm_dbg(INIT, &brd->pci_dev, "jsm_found_board - NEO adapter\n"); - - /* get the PCI Base Address Registers */ - brd->membase = pci_resource_start(pdev, 0); - brd->membase_end = pci_resource_end(pdev, 0); - - if (brd->membase & 1) - brd->membase &= ~3; - else - brd->membase &= ~15; - - /* Assign the board_ops struct */ - brd->bd_ops = &jsm_neo_ops; + switch (pdev->device) { + case PCI_DEVICE_ID_CLASSIC_4: + case PCI_DEVICE_ID_CLASSIC_4_422: + case PCI_DEVICE_ID_CLASSIC_8: + case PCI_DEVICE_ID_CLASSIC_8_422: + + jsm_dbg(INIT, &brd->pci_dev, + "jsm_found_board - Classic adapter\n"); + + /* + * For PCI ClassicBoards + * PCI Local Address (.i.e. "resource" number) space + * 0 PLX Memory Mapped Config + * 1 PLX I/O Mapped Config + * 2 I/O Mapped UARTs and Status + * 3 Memory Mapped VPD + * 4 Memory Mapped UARTs and Status + */ + + /* Get the PCI Base Address Registers */ + brd->membase = pci_resource_start(pdev, 4); + brd->membase_end = pci_resource_end(pdev, 4); + + if (brd->membase & 0x1) + brd->membase &= ~0x3; + else + brd->membase &= ~0xF; + + brd->iobase = pci_resource_start(pdev, 1); + brd->iobase_end = pci_resource_end(pdev, 1); + brd->iobase = ((unsigned int)(brd->iobase)) & 0xFFFE; + + /* Assign the board_ops struct */ + brd->bd_ops = &jsm_cls_ops; + + brd->bd_uart_offset = 0x8; + brd->bd_dividend = 921600; + + brd->re_map_membase = ioremap(brd->membase, + pci_resource_len(pdev, 4)); + if (!brd->re_map_membase) { + dev_err(&pdev->dev, + "Card has no PCI Memory resources, failing board.\n"); + rc = -ENOMEM; + goto out_kfree_brd; + } - brd->bd_uart_offset = 0x200; - brd->bd_dividend = 921600; + /* + * Enable Local Interrupt 1 (0x1), + * Local Interrupt 1 Polarity Active high (0x2), + * Enable PCI interrupt (0x43) + */ + outb(0x43, brd->iobase + 0x4c); + + break; + + case PCI_DEVICE_ID_NEO_2DB9: + case PCI_DEVICE_ID_NEO_2DB9PRI: + case PCI_DEVICE_ID_NEO_2RJ45: + case PCI_DEVICE_ID_NEO_2RJ45PRI: + case PCI_DEVICE_ID_NEO_2_422_485: + case PCI_DEVICE_ID_NEO_4: + case PCIE_DEVICE_ID_NEO_4: + case PCIE_DEVICE_ID_NEO_4RJ45: + case PCIE_DEVICE_ID_NEO_4_IBM: + case PCI_DEVICE_ID_DIGI_NEO_8: + case PCIE_DEVICE_ID_NEO_8: + case PCIE_DEVICE_ID_NEO_8RJ45: + + jsm_dbg(INIT, &brd->pci_dev, "jsm_found_board - NEO adapter\n"); + + /* get the PCI Base Address Registers */ + brd->membase = pci_resource_start(pdev, 0); + brd->membase_end = pci_resource_end(pdev, 0); + + if (brd->membase & 1) + brd->membase &= ~0x3; + else + brd->membase &= ~0xF; + + /* Assign the board_ops struct */ + brd->bd_ops = &jsm_neo_ops; + + brd->bd_uart_offset = 0x200; + brd->bd_dividend = 921600; + + brd->re_map_membase = ioremap(brd->membase, + pci_resource_len(pdev, 0)); + if (!brd->re_map_membase) { + dev_err(&pdev->dev, + "Card has no PCI Memory resources, failing board.\n"); + rc = -ENOMEM; + goto out_kfree_brd; + } - brd->re_map_membase = ioremap(brd->membase, pci_resource_len(pdev, 0)); - if (!brd->re_map_membase) { - dev_err(&pdev->dev, - "card has no PCI Memory resources, " - "failing board.\n"); - rc = -ENOMEM; - goto out_kfree_brd; + break; + default: + return -ENXIO; } - rc = request_irq(brd->irq, brd->bd_ops->intr, - IRQF_SHARED, "JSM", brd); + rc = request_irq(brd->irq, brd->bd_ops->intr, IRQF_SHARED, "JSM", brd); if (rc) { - printk(KERN_WARNING "Failed to hook IRQ %d\n",brd->irq); + dev_warn(&pdev->dev, "Failed to hook IRQ %d\n", brd->irq); goto out_iounmap; } @@ -156,7 +246,7 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent) } /* Log the information about the board */ - dev_info(&pdev->dev, "board %d: Digi Neo (rev %d), irq %d\n", + dev_info(&pdev->dev, "board %d: Digi Classic/Neo (rev %d), irq %d\n", adapter_count, brd->rev, brd->irq); pci_set_drvdata(pdev, brd); @@ -183,6 +273,18 @@ static void jsm_remove_one(struct pci_dev *pdev) struct jsm_board *brd = pci_get_drvdata(pdev); int i = 0; + switch (pdev->device) { + case PCI_DEVICE_ID_CLASSIC_4: + case PCI_DEVICE_ID_CLASSIC_4_422: + case PCI_DEVICE_ID_CLASSIC_8: + case PCI_DEVICE_ID_CLASSIC_8_422: + /* Tell card not to interrupt anymore. */ + outb(0x0, brd->iobase + 0x4c); + break; + default: + break; + } + jsm_remove_uart_port(brd); free_irq(brd->irq, brd); @@ -209,6 +311,18 @@ static struct pci_device_id jsm_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45PRI), 0, 0, 3 }, { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4_IBM), 0, 0, 4 }, { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_NEO_8), 0, 0, 5 }, + { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_4), 0, 0, 6 }, + { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_1_422), 0, 0, 7 }, + { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_1_422_485), 0, 0, 8 }, + { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2_422_485), 0, 0, 9 }, + { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_8), 0, 0, 10 }, + { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4), 0, 0, 11 }, + { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4RJ45), 0, 0, 12 }, + { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_8RJ45), 0, 0, 13 }, + { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_CLASSIC_4), 0, 0, 14 }, + { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_CLASSIC_4_422), 0, 0, 15 }, + { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_CLASSIC_8), 0, 0, 16 }, + { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_CLASSIC_8_422), 0, 0, 17 }, { 0, } }; MODULE_DEVICE_TABLE(pci, jsm_pci_tbl); diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c index dfaf48826417..7291c2117daa 100644 --- a/drivers/tty/serial/jsm/jsm_neo.c +++ b/drivers/tty/serial/jsm/jsm_neo.c @@ -13,11 +13,6 @@ * 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. - * * Contact Information: * Scott H Kilau <Scott_Kilau@digi.com> * Wendy Xiong <wendyx@us.ibm.com> @@ -649,7 +644,7 @@ static void neo_flush_uart_write(struct jsm_channel *ch) /* Check to see if the UART feels it completely flushed the FIFO. */ tmp = readb(&ch->ch_neo_uart->isr_fcr); - if (tmp & 4) { + if (tmp & UART_FCR_CLEAR_XMIT) { jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, "Still flushing TX UART... i: %d\n", i); udelay(10); @@ -694,7 +689,7 @@ static void neo_flush_uart_read(struct jsm_channel *ch) /* * No locks are assumed to be held when calling this function. */ -static void neo_clear_break(struct jsm_channel *ch, int force) +static void neo_clear_break(struct jsm_channel *ch) { unsigned long lock_flags; @@ -1024,27 +1019,24 @@ static void neo_param(struct jsm_channel *ch) lcr |= UART_LCR_STOP; switch (ch->ch_c_cflag & CSIZE) { - case CS5: - lcr |= UART_LCR_WLEN5; - break; - case CS6: - lcr |= UART_LCR_WLEN6; - break; - case CS7: - lcr |= UART_LCR_WLEN7; - break; - case CS8: - default: - lcr |= UART_LCR_WLEN8; + case CS5: + lcr |= UART_LCR_WLEN5; break; + case CS6: + lcr |= UART_LCR_WLEN6; + break; + case CS7: + lcr |= UART_LCR_WLEN7; + break; + case CS8: + default: + lcr |= UART_LCR_WLEN8; + break; } ier = readb(&ch->ch_neo_uart->ier); uart_lcr = readb(&ch->ch_neo_uart->lcr); - if (baud == 0) - baud = 9600; - quot = ch->ch_bd->bd_dividend / baud; if (quot != 0) { diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c index 3e5c1563afe2..524e86ab3cae 100644 --- a/drivers/tty/serial/jsm/jsm_tty.c +++ b/drivers/tty/serial/jsm/jsm_tty.c @@ -13,11 +13,6 @@ * 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. - * * Contact Information: * Scott H Kilau <Scott_Kilau@digi.com> * Ananda Venkatarman <mansarov@us.ibm.com> @@ -77,7 +72,8 @@ static unsigned int jsm_tty_tx_empty(struct uart_port *port) static unsigned int jsm_tty_get_mctrl(struct uart_port *port) { int result; - struct jsm_channel *channel = (struct jsm_channel *)port; + struct jsm_channel *channel = + container_of(port, struct jsm_channel, uart_port); jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n"); @@ -98,7 +94,8 @@ static unsigned int jsm_tty_get_mctrl(struct uart_port *port) */ static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl) { - struct jsm_channel *channel = (struct jsm_channel *)port; + struct jsm_channel *channel = + container_of(port, struct jsm_channel, uart_port); jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n"); @@ -133,7 +130,8 @@ static void jsm_tty_write(struct uart_port *port) static void jsm_tty_start_tx(struct uart_port *port) { - struct jsm_channel *channel = (struct jsm_channel *)port; + struct jsm_channel *channel = + container_of(port, struct jsm_channel, uart_port); jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n"); @@ -145,7 +143,8 @@ static void jsm_tty_start_tx(struct uart_port *port) static void jsm_tty_stop_tx(struct uart_port *port) { - struct jsm_channel *channel = (struct jsm_channel *)port; + struct jsm_channel *channel = + container_of(port, struct jsm_channel, uart_port); jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n"); @@ -157,7 +156,8 @@ static void jsm_tty_stop_tx(struct uart_port *port) static void jsm_tty_send_xchar(struct uart_port *port, char ch) { unsigned long lock_flags; - struct jsm_channel *channel = (struct jsm_channel *)port; + struct jsm_channel *channel = + container_of(port, struct jsm_channel, uart_port); struct ktermios *termios; spin_lock_irqsave(&port->lock, lock_flags); @@ -172,7 +172,8 @@ static void jsm_tty_send_xchar(struct uart_port *port, char ch) static void jsm_tty_stop_rx(struct uart_port *port) { - struct jsm_channel *channel = (struct jsm_channel *)port; + struct jsm_channel *channel = + container_of(port, struct jsm_channel, uart_port); channel->ch_bd->bd_ops->disable_receiver(channel); } @@ -180,13 +181,14 @@ static void jsm_tty_stop_rx(struct uart_port *port) static void jsm_tty_break(struct uart_port *port, int break_state) { unsigned long lock_flags; - struct jsm_channel *channel = (struct jsm_channel *)port; + struct jsm_channel *channel = + container_of(port, struct jsm_channel, uart_port); spin_lock_irqsave(&port->lock, lock_flags); if (break_state == -1) channel->ch_bd->bd_ops->send_break(channel); else - channel->ch_bd->bd_ops->clear_break(channel, 0); + channel->ch_bd->bd_ops->clear_break(channel); spin_unlock_irqrestore(&port->lock, lock_flags); } @@ -194,7 +196,8 @@ static void jsm_tty_break(struct uart_port *port, int break_state) static int jsm_tty_open(struct uart_port *port) { struct jsm_board *brd; - struct jsm_channel *channel = (struct jsm_channel *)port; + struct jsm_channel *channel = + container_of(port, struct jsm_channel, uart_port); struct ktermios *termios; /* Get board pointer from our array of majors we have allocated */ @@ -273,7 +276,8 @@ static void jsm_tty_close(struct uart_port *port) { struct jsm_board *bd; struct ktermios *ts; - struct jsm_channel *channel = (struct jsm_channel *)port; + struct jsm_channel *channel = + container_of(port, struct jsm_channel, uart_port); jsm_dbg(CLOSE, &channel->ch_bd->pci_dev, "start\n"); @@ -307,7 +311,8 @@ static void jsm_tty_set_termios(struct uart_port *port, struct ktermios *old_termios) { unsigned long lock_flags; - struct jsm_channel *channel = (struct jsm_channel *)port; + struct jsm_channel *channel = + container_of(port, struct jsm_channel, uart_port); spin_lock_irqsave(&port->lock, lock_flags); channel->ch_c_cflag = termios->c_cflag; @@ -415,6 +420,8 @@ int jsm_tty_init(struct jsm_board *brd) if (brd->bd_uart_offset == 0x200) ch->ch_neo_uart = vaddr + (brd->bd_uart_offset * i); + else + ch->ch_cls_uart = vaddr + (brd->bd_uart_offset * i); ch->ch_bd = brd; ch->ch_portnum = i; diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c index 6ec7501b464d..129dc5be6028 100644 --- a/drivers/tty/serial/kgdb_nmi.c +++ b/drivers/tty/serial/kgdb_nmi.c @@ -46,6 +46,8 @@ static atomic_t kgdb_nmi_num_readers = ATOMIC_INIT(0); static int kgdb_nmi_console_setup(struct console *co, char *options) { + arch_kgdb_ops.enable_nmi(1); + /* The NMI console uses the dbg_io_ops to issue console messages. To * avoid duplicate messages during kdb sessions we must inform kdb's * I/O utilities that messages sent to the console will automatically @@ -77,7 +79,7 @@ static struct console kgdb_nmi_console = { .setup = kgdb_nmi_console_setup, .write = kgdb_nmi_console_write, .device = kgdb_nmi_console_device, - .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED, + .flags = CON_PRINTBUFFER | CON_ANYTIME, .index = -1, }; @@ -354,7 +356,6 @@ int kgdb_register_nmi_console(void) } register_console(&kgdb_nmi_console); - arch_kgdb_ops.enable_nmi(1); return 0; err_drv_reg: diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c index 4675fe198d31..4ccc0397664c 100644 --- a/drivers/tty/serial/lantiq.c +++ b/drivers/tty/serial/lantiq.c @@ -497,8 +497,10 @@ lqasc_type(struct uart_port *port) static void lqasc_release_port(struct uart_port *port) { + struct platform_device *pdev = to_platform_device(port->dev); + if (port->flags & UPF_IOREMAP) { - iounmap(port->membase); + devm_iounmap(&pdev->dev, port->membase); port->membase = NULL; } } @@ -743,7 +745,6 @@ MODULE_DEVICE_TABLE(of, ltq_asc_match); static struct platform_driver lqasc_driver = { .driver = { .name = DRVNAME, - .owner = THIS_MODULE, .of_match_table = ltq_asc_match, }, }; diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c index 6f0f89282847..e92d7ebe9e77 100644 --- a/drivers/tty/serial/lpc32xx_hs.c +++ b/drivers/tty/serial/lpc32xx_hs.c @@ -768,7 +768,6 @@ static struct platform_driver serial_hs_lpc32xx_driver = { .resume = serial_hs_lpc32xx_resume, .driver = { .name = MODNAME, - .owner = THIS_MODULE, .of_match_table = serial_hs_lpc32xx_dt_ids, }, }; diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c index 5702828fb62e..8f7f83a14c93 100644 --- a/drivers/tty/serial/m32r_sio.c +++ b/drivers/tty/serial/m32r_sio.c @@ -249,7 +249,8 @@ static void serial_out(struct uart_sio_port *up, int offset, int value) static void m32r_sio_stop_tx(struct uart_port *port) { - struct uart_sio_port *up = (struct uart_sio_port *)port; + struct uart_sio_port *up = + container_of(port, struct uart_sio_port, port); if (up->ier & UART_IER_THRI) { up->ier &= ~UART_IER_THRI; @@ -260,7 +261,8 @@ static void m32r_sio_stop_tx(struct uart_port *port) static void m32r_sio_start_tx(struct uart_port *port) { #ifdef CONFIG_SERIAL_M32R_PLDSIO - struct uart_sio_port *up = (struct uart_sio_port *)port; + struct uart_sio_port *up = + container_of(port, struct uart_sio_port, port); struct circ_buf *xmit = &up->port.state->xmit; if (!(up->ier & UART_IER_THRI)) { @@ -274,7 +276,8 @@ static void m32r_sio_start_tx(struct uart_port *port) } while((serial_in(up, UART_LSR) & UART_EMPTY) != UART_EMPTY); #else - struct uart_sio_port *up = (struct uart_sio_port *)port; + struct uart_sio_port *up = + container_of(port, struct uart_sio_port, port); if (!(up->ier & UART_IER_THRI)) { up->ier |= UART_IER_THRI; @@ -285,7 +288,8 @@ static void m32r_sio_start_tx(struct uart_port *port) static void m32r_sio_stop_rx(struct uart_port *port) { - struct uart_sio_port *up = (struct uart_sio_port *)port; + struct uart_sio_port *up = + container_of(port, struct uart_sio_port, port); up->ier &= ~UART_IER_RLSI; up->port.read_status_mask &= ~UART_LSR_DR; @@ -294,7 +298,8 @@ static void m32r_sio_stop_rx(struct uart_port *port) static void m32r_sio_enable_ms(struct uart_port *port) { - struct uart_sio_port *up = (struct uart_sio_port *)port; + struct uart_sio_port *up = + container_of(port, struct uart_sio_port, port); up->ier |= UART_IER_MSI; serial_out(up, UART_IER, up->ier); @@ -581,7 +586,8 @@ static void m32r_sio_timeout(unsigned long data) static unsigned int m32r_sio_tx_empty(struct uart_port *port) { - struct uart_sio_port *up = (struct uart_sio_port *)port; + struct uart_sio_port *up = + container_of(port, struct uart_sio_port, port); unsigned long flags; unsigned int ret; @@ -609,7 +615,8 @@ static void m32r_sio_break_ctl(struct uart_port *port, int break_state) static int m32r_sio_startup(struct uart_port *port) { - struct uart_sio_port *up = (struct uart_sio_port *)port; + struct uart_sio_port *up = + container_of(port, struct uart_sio_port, port); int retval; sio_init(); @@ -652,7 +659,8 @@ static int m32r_sio_startup(struct uart_port *port) static void m32r_sio_shutdown(struct uart_port *port) { - struct uart_sio_port *up = (struct uart_sio_port *)port; + struct uart_sio_port *up = + container_of(port, struct uart_sio_port, port); /* * Disable interrupts from this port @@ -681,7 +689,8 @@ static unsigned int m32r_sio_get_divisor(struct uart_port *port, static void m32r_sio_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - struct uart_sio_port *up = (struct uart_sio_port *)port; + struct uart_sio_port *up = + container_of(port, struct uart_sio_port, port); unsigned char cval = 0; unsigned long flags; unsigned int baud, quot; @@ -780,7 +789,8 @@ static void m32r_sio_set_termios(struct uart_port *port, static void m32r_sio_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { - struct uart_sio_port *up = (struct uart_sio_port *)port; + struct uart_sio_port *up = + container_of(port, struct uart_sio_port, port); if (up->pm) up->pm(port, state, oldstate); @@ -825,7 +835,8 @@ m32r_sio_request_std_resource(struct uart_sio_port *up, struct resource **res) static void m32r_sio_release_port(struct uart_port *port) { - struct uart_sio_port *up = (struct uart_sio_port *)port; + struct uart_sio_port *up = + container_of(port, struct uart_sio_port, port); unsigned long start, offset = 0, size = 0; size <<= up->port.regshift; @@ -862,7 +873,8 @@ static void m32r_sio_release_port(struct uart_port *port) static int m32r_sio_request_port(struct uart_port *port) { - struct uart_sio_port *up = (struct uart_sio_port *)port; + struct uart_sio_port *up = + container_of(port, struct uart_sio_port, port); struct resource *res = NULL; int ret = 0; @@ -889,7 +901,8 @@ static int m32r_sio_request_port(struct uart_port *port) static void m32r_sio_config_port(struct uart_port *port, int unused) { - struct uart_sio_port *up = (struct uart_sio_port *)port; + struct uart_sio_port *up = + container_of(port, struct uart_sio_port, port); unsigned long flags; spin_lock_irqsave(&up->port.lock, flags); @@ -1000,7 +1013,8 @@ static inline void wait_for_xmitr(struct uart_sio_port *up) static void m32r_sio_console_putchar(struct uart_port *port, int ch) { - struct uart_sio_port *up = (struct uart_sio_port *)port; + struct uart_sio_port *up = + container_of(port, struct uart_sio_port, port); wait_for_xmitr(up); sio_out(up, SIOTXB, ch); diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 82573dc4d8cf..182549f55904 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -346,10 +346,13 @@ static int max3109_detect(struct device *dev) unsigned int val = 0; int ret; - ret = regmap_read(s->regmap, MAX310X_REVID_REG, &val); + ret = regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, + MAX310X_EXTREG_ENBL); if (ret) return ret; + regmap_read(s->regmap, MAX310X_REVID_EXTREG, &val); + regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, MAX310X_EXTREG_DSBL); if (((val & MAX310x_REV_MASK) != MAX3109_REV_ID)) { dev_err(dev, "%s ID 0x%02x does not match\n", s->devtype->name, val); @@ -874,55 +877,37 @@ static void max310x_set_termios(struct uart_port *port, uart_update_timeout(port, termios->c_cflag, baud); } -static int max310x_ioctl(struct uart_port *port, unsigned int cmd, - unsigned long arg) +static int max310x_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) { -#if defined(TIOCSRS485) && defined(TIOCGRS485) - struct serial_rs485 rs485; unsigned int val; - switch (cmd) { - case TIOCSRS485: - if (copy_from_user(&rs485, (void __user *)arg, sizeof(rs485))) - return -EFAULT; - if (rs485.delay_rts_before_send > 0x0f || - rs485.delay_rts_after_send > 0x0f) - return -ERANGE; - val = (rs485.delay_rts_before_send << 4) | - rs485.delay_rts_after_send; - max310x_port_write(port, MAX310X_HDPIXDELAY_REG, val); - if (rs485.flags & SER_RS485_ENABLED) { - max310x_port_update(port, MAX310X_MODE1_REG, - MAX310X_MODE1_TRNSCVCTRL_BIT, - MAX310X_MODE1_TRNSCVCTRL_BIT); - max310x_port_update(port, MAX310X_MODE2_REG, - MAX310X_MODE2_ECHOSUPR_BIT, - MAX310X_MODE2_ECHOSUPR_BIT); - } else { - max310x_port_update(port, MAX310X_MODE1_REG, - MAX310X_MODE1_TRNSCVCTRL_BIT, 0); - max310x_port_update(port, MAX310X_MODE2_REG, - MAX310X_MODE2_ECHOSUPR_BIT, 0); - } - return 0; - case TIOCGRS485: - memset(&rs485, 0, sizeof(rs485)); - val = max310x_port_read(port, MAX310X_MODE1_REG); - rs485.flags = (val & MAX310X_MODE1_TRNSCVCTRL_BIT) ? - SER_RS485_ENABLED : 0; - rs485.flags |= SER_RS485_RTS_ON_SEND; - val = max310x_port_read(port, MAX310X_HDPIXDELAY_REG); - rs485.delay_rts_before_send = val >> 4; - rs485.delay_rts_after_send = val & 0x0f; - if (copy_to_user((void __user *)arg, &rs485, sizeof(rs485))) - return -EFAULT; - return 0; - default: - break; + if (rs485->delay_rts_before_send > 0x0f || + rs485->delay_rts_after_send > 0x0f) + return -ERANGE; + + val = (rs485->delay_rts_before_send << 4) | + rs485->delay_rts_after_send; + max310x_port_write(port, MAX310X_HDPIXDELAY_REG, val); + if (rs485->flags & SER_RS485_ENABLED) { + max310x_port_update(port, MAX310X_MODE1_REG, + MAX310X_MODE1_TRNSCVCTRL_BIT, + MAX310X_MODE1_TRNSCVCTRL_BIT); + max310x_port_update(port, MAX310X_MODE2_REG, + MAX310X_MODE2_ECHOSUPR_BIT, + MAX310X_MODE2_ECHOSUPR_BIT); + } else { + max310x_port_update(port, MAX310X_MODE1_REG, + MAX310X_MODE1_TRNSCVCTRL_BIT, 0); + max310x_port_update(port, MAX310X_MODE2_REG, + MAX310X_MODE2_ECHOSUPR_BIT, 0); } -#endif - return -ENOIOCTLCMD; + rs485->flags &= SER_RS485_RTS_ON_SEND | SER_RS485_ENABLED; + memset(rs485->padding, 0, sizeof(rs485->padding)); + port->rs485 = *rs485; + + return 0; } static int max310x_startup(struct uart_port *port) @@ -1017,7 +1002,6 @@ static const struct uart_ops max310x_ops = { .release_port = max310x_null_void, .config_port = max310x_config_port, .verify_port = max310x_verify_port, - .ioctl = max310x_ioctl, }; static int __maybe_unused max310x_suspend(struct device *dev) @@ -1218,6 +1202,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, s->p[i].port.iobase = i * 0x20; s->p[i].port.membase = (void __iomem *)~0; s->p[i].port.uartclk = uartclk; + s->p[i].port.rs485_config = max310x_rs485_config; s->p[i].port.ops = &max310x_ops; /* Disable all interrupts */ max310x_port_write(&s->p[i].port, MAX310X_IRQEN_REG, 0); @@ -1248,7 +1233,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, mutex_destroy(&s->mutex); #ifdef CONFIG_GPIOLIB - WARN_ON(gpiochip_remove(&s->gpio)); + gpiochip_remove(&s->gpio); out_uart: #endif @@ -1263,12 +1248,10 @@ out_clk: static int max310x_remove(struct device *dev) { struct max310x_port *s = dev_get_drvdata(dev); - int i, ret = 0; + int i; #ifdef CONFIG_GPIOLIB - ret = gpiochip_remove(&s->gpio); - if (ret) - return ret; + gpiochip_remove(&s->gpio); #endif for (i = 0; i < s->uart.nr; i++) { @@ -1282,7 +1265,7 @@ static int max310x_remove(struct device *dev) uart_unregister_driver(&s->uart); clk_disable_unprepare(s->clk); - return ret; + return 0; } static const struct of_device_id __maybe_unused max310x_dt_ids[] = { diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index bc896dc7d2ed..10496672dfdb 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -57,7 +57,6 @@ struct mcf_uart { struct uart_port port; unsigned int sigs; /* Local copy of line sigs */ unsigned char imr; /* Local IMR mirror */ - struct serial_rs485 rs485; /* RS485 settings */ }; /****************************************************************************/ @@ -104,7 +103,7 @@ static void mcf_start_tx(struct uart_port *port) { struct mcf_uart *pp = container_of(port, struct mcf_uart, port); - if (pp->rs485.flags & SER_RS485_ENABLED) { + if (port->rs485.flags & SER_RS485_ENABLED) { /* Enable Transmitter */ writeb(MCFUART_UCR_TXENABLE, port->membase + MCFUART_UCR); /* Manually assert RTS */ @@ -258,12 +257,12 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios, mr2 |= MCFUART_MR2_TXCTS; } - if (pp->rs485.flags & SER_RS485_ENABLED) { + spin_lock_irqsave(&port->lock, flags); + if (port->rs485.flags & SER_RS485_ENABLED) { dev_dbg(port->dev, "Setting UART to RS485\n"); mr2 |= MCFUART_MR2_TXRTS; } - spin_lock_irqsave(&port->lock, flags); uart_update_timeout(port, termios->c_cflag, baud); writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR); writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR); @@ -360,7 +359,7 @@ static void mcf_tx_chars(struct mcf_uart *pp) pp->imr &= ~MCFUART_UIR_TXREADY; writeb(pp->imr, port->membase + MCFUART_UIMR); /* Disable TX to negate RTS automatically */ - if (pp->rs485.flags & SER_RS485_ENABLED) + if (port->rs485.flags & SER_RS485_ENABLED) writeb(MCFUART_UCR_TXDISABLE, port->membase + MCFUART_UCR); } @@ -440,13 +439,11 @@ static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser) /****************************************************************************/ /* Enable or disable the RS485 support */ -static void mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485) +static int mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485) { struct mcf_uart *pp = container_of(port, struct mcf_uart, port); - unsigned long flags; unsigned char mr1, mr2; - spin_lock_irqsave(&port->lock, flags); /* Get mode registers */ mr1 = readb(port->membase + MCFUART_UMR); mr2 = readb(port->membase + MCFUART_UMR); @@ -460,32 +457,8 @@ static void mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485) } writeb(mr1, port->membase + MCFUART_UMR); writeb(mr2, port->membase + MCFUART_UMR); - pp->rs485 = *rs485; - spin_unlock_irqrestore(&port->lock, flags); -} + port->rs485 = *rs485; -static int mcf_ioctl(struct uart_port *port, unsigned int cmd, - unsigned long arg) -{ - switch (cmd) { - case TIOCSRS485: { - struct serial_rs485 rs485; - if (copy_from_user(&rs485, (struct serial_rs485 *)arg, - sizeof(struct serial_rs485))) - return -EFAULT; - mcf_config_rs485(port, &rs485); - break; - } - case TIOCGRS485: { - struct mcf_uart *pp = container_of(port, struct mcf_uart, port); - if (copy_to_user((struct serial_rs485 *)arg, &pp->rs485, - sizeof(struct serial_rs485))) - return -EFAULT; - break; - } - default: - return -ENOIOCTLCMD; - } return 0; } @@ -510,7 +483,6 @@ static const struct uart_ops mcf_uart_ops = { .release_port = mcf_release_port, .config_port = mcf_config_port, .verify_port = mcf_verify_port, - .ioctl = mcf_ioctl, }; static struct mcf_uart mcf_ports[4]; @@ -538,6 +510,7 @@ int __init early_mcf_setup(struct mcf_platform_uart *platp) port->irq = platp[i].irq; port->uartclk = MCF_BUSCLK; port->flags = UPF_BOOT_AUTOCONF; + port->rs485_config = mcf_config_rs485; port->ops = &mcf_uart_ops; } @@ -663,6 +636,7 @@ static int mcf_probe(struct platform_device *pdev) port->uartclk = MCF_BUSCLK; port->ops = &mcf_uart_ops; port->flags = UPF_BOOT_AUTOCONF; + port->rs485_config = mcf_config_rs485; uart_add_one_port(&mcf_driver, port); } @@ -693,7 +667,6 @@ static struct platform_driver mcf_platform_driver = { .remove = mcf_remove, .driver = { .name = "mcfuart", - .owner = THIS_MODULE, }, }; diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c index 30e9e60bc5cd..517cd073dc08 100644 --- a/drivers/tty/serial/men_z135_uart.c +++ b/drivers/tty/serial/men_z135_uart.c @@ -809,6 +809,7 @@ static void men_z135_remove(struct mcb_device *mdev) static const struct mcb_device_id men_z135_ids[] = { { .device = 0x87 }, + { } }; MODULE_DEVICE_TABLE(mcb, men_z135_ids); diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c new file mode 100644 index 000000000000..67c036702629 --- /dev/null +++ b/drivers/tty/serial/meson_uart.c @@ -0,0 +1,633 @@ +/* + * Based on meson_uart.c, by AMLOGIC, INC. + * + * Copyright (C) 2014 Carlo Caione <carlo@caione.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * 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/clk.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/serial.h> +#include <linux/serial_core.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> + +/* Register offsets */ +#define AML_UART_WFIFO 0x00 +#define AML_UART_RFIFO 0x04 +#define AML_UART_CONTROL 0x08 +#define AML_UART_STATUS 0x0c +#define AML_UART_MISC 0x10 +#define AML_UART_REG5 0x14 + +/* AML_UART_CONTROL bits */ +#define AML_UART_TX_EN BIT(12) +#define AML_UART_RX_EN BIT(13) +#define AML_UART_TX_RST BIT(22) +#define AML_UART_RX_RST BIT(23) +#define AML_UART_CLR_ERR BIT(24) +#define AML_UART_RX_INT_EN BIT(27) +#define AML_UART_TX_INT_EN BIT(28) +#define AML_UART_DATA_LEN_MASK (0x03 << 20) +#define AML_UART_DATA_LEN_8BIT (0x00 << 20) +#define AML_UART_DATA_LEN_7BIT (0x01 << 20) +#define AML_UART_DATA_LEN_6BIT (0x02 << 20) +#define AML_UART_DATA_LEN_5BIT (0x03 << 20) + +/* AML_UART_STATUS bits */ +#define AML_UART_PARITY_ERR BIT(16) +#define AML_UART_FRAME_ERR BIT(17) +#define AML_UART_TX_FIFO_WERR BIT(18) +#define AML_UART_RX_EMPTY BIT(20) +#define AML_UART_TX_FULL BIT(21) +#define AML_UART_TX_EMPTY BIT(22) +#define AML_UART_ERR (AML_UART_PARITY_ERR | \ + AML_UART_FRAME_ERR | \ + AML_UART_TX_FIFO_WERR) + +/* AML_UART_CONTROL bits */ +#define AML_UART_TWO_WIRE_EN BIT(15) +#define AML_UART_PARITY_TYPE BIT(18) +#define AML_UART_PARITY_EN BIT(19) +#define AML_UART_CLEAR_ERR BIT(24) +#define AML_UART_STOP_BIN_LEN_MASK (0x03 << 16) +#define AML_UART_STOP_BIN_1SB (0x00 << 16) +#define AML_UART_STOP_BIN_2SB (0x01 << 16) + +/* AML_UART_MISC bits */ +#define AML_UART_XMIT_IRQ(c) (((c) & 0xff) << 8) +#define AML_UART_RECV_IRQ(c) ((c) & 0xff) + +/* AML_UART_REG5 bits */ +#define AML_UART_BAUD_MASK 0x7fffff +#define AML_UART_BAUD_USE BIT(23) + +#define AML_UART_PORT_NUM 6 +#define AML_UART_DEV_NAME "ttyAML" + + +static struct uart_driver meson_uart_driver; + +static struct uart_port *meson_ports[AML_UART_PORT_NUM]; + +static void meson_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +static unsigned int meson_uart_get_mctrl(struct uart_port *port) +{ + return TIOCM_CTS; +} + +static unsigned int meson_uart_tx_empty(struct uart_port *port) +{ + u32 val; + + val = readl(port->membase + AML_UART_STATUS); + return (val & AML_UART_TX_EMPTY) ? TIOCSER_TEMT : 0; +} + +static void meson_uart_stop_tx(struct uart_port *port) +{ + u32 val; + + val = readl(port->membase + AML_UART_CONTROL); + val &= ~AML_UART_TX_EN; + writel(val, port->membase + AML_UART_CONTROL); +} + +static void meson_uart_stop_rx(struct uart_port *port) +{ + u32 val; + + val = readl(port->membase + AML_UART_CONTROL); + val &= ~AML_UART_RX_EN; + writel(val, port->membase + AML_UART_CONTROL); +} + +static void meson_uart_shutdown(struct uart_port *port) +{ + unsigned long flags; + u32 val; + + free_irq(port->irq, port); + + spin_lock_irqsave(&port->lock, flags); + + val = readl(port->membase + AML_UART_CONTROL); + val &= ~(AML_UART_RX_EN | AML_UART_TX_EN); + val &= ~(AML_UART_RX_INT_EN | AML_UART_TX_INT_EN); + writel(val, port->membase + AML_UART_CONTROL); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static void meson_uart_start_tx(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + unsigned int ch; + + if (uart_tx_stopped(port)) { + meson_uart_stop_tx(port); + return; + } + + while (!(readl(port->membase + AML_UART_STATUS) & AML_UART_TX_FULL)) { + if (port->x_char) { + writel(port->x_char, port->membase + AML_UART_WFIFO); + port->icount.tx++; + port->x_char = 0; + continue; + } + + if (uart_circ_empty(xmit)) + break; + + ch = xmit->buf[xmit->tail]; + writel(ch, port->membase + AML_UART_WFIFO); + xmit->tail = (xmit->tail+1) & (SERIAL_XMIT_SIZE - 1); + port->icount.tx++; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); +} + +static void meson_receive_chars(struct uart_port *port) +{ + struct tty_port *tport = &port->state->port; + char flag; + u32 status, ch, mode; + + do { + flag = TTY_NORMAL; + port->icount.rx++; + status = readl(port->membase + AML_UART_STATUS); + + if (status & AML_UART_ERR) { + if (status & AML_UART_TX_FIFO_WERR) + port->icount.overrun++; + else if (status & AML_UART_FRAME_ERR) + port->icount.frame++; + else if (status & AML_UART_PARITY_ERR) + port->icount.frame++; + + mode = readl(port->membase + AML_UART_CONTROL); + mode |= AML_UART_CLEAR_ERR; + writel(mode, port->membase + AML_UART_CONTROL); + + /* It doesn't clear to 0 automatically */ + mode &= ~AML_UART_CLEAR_ERR; + writel(mode, port->membase + AML_UART_CONTROL); + + status &= port->read_status_mask; + if (status & AML_UART_FRAME_ERR) + flag = TTY_FRAME; + else if (status & AML_UART_PARITY_ERR) + flag = TTY_PARITY; + } + + ch = readl(port->membase + AML_UART_RFIFO); + ch &= 0xff; + + if ((status & port->ignore_status_mask) == 0) + tty_insert_flip_char(tport, ch, flag); + + if (status & AML_UART_TX_FIFO_WERR) + tty_insert_flip_char(tport, 0, TTY_OVERRUN); + + } while (!(readl(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY)); + + spin_unlock(&port->lock); + tty_flip_buffer_push(tport); + spin_lock(&port->lock); +} + +static irqreturn_t meson_uart_interrupt(int irq, void *dev_id) +{ + struct uart_port *port = (struct uart_port *)dev_id; + + spin_lock(&port->lock); + + if (!(readl(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY)) + meson_receive_chars(port); + + if (!(readl(port->membase + AML_UART_STATUS) & AML_UART_TX_FULL)) + meson_uart_start_tx(port); + + spin_unlock(&port->lock); + + return IRQ_HANDLED; +} + +static const char *meson_uart_type(struct uart_port *port) +{ + return (port->type == PORT_MESON) ? "meson_uart" : NULL; +} + +static int meson_uart_startup(struct uart_port *port) +{ + u32 val; + int ret = 0; + + val = readl(port->membase + AML_UART_CONTROL); + val |= (AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR); + writel(val, port->membase + AML_UART_CONTROL); + + val &= ~(AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR); + writel(val, port->membase + AML_UART_CONTROL); + + val |= (AML_UART_RX_EN | AML_UART_TX_EN); + writel(val, port->membase + AML_UART_CONTROL); + + val |= (AML_UART_RX_INT_EN | AML_UART_TX_INT_EN); + writel(val, port->membase + AML_UART_CONTROL); + + val = (AML_UART_RECV_IRQ(1) | AML_UART_XMIT_IRQ(port->fifosize / 2)); + writel(val, port->membase + AML_UART_MISC); + + ret = request_irq(port->irq, meson_uart_interrupt, 0, + meson_uart_type(port), port); + + return ret; +} + +static void meson_uart_change_speed(struct uart_port *port, unsigned long baud) +{ + u32 val; + + while (!(readl(port->membase + AML_UART_STATUS) & AML_UART_TX_EMPTY)) + cpu_relax(); + + val = readl(port->membase + AML_UART_REG5); + val &= ~AML_UART_BAUD_MASK; + val = ((port->uartclk * 10 / (baud * 4) + 5) / 10) - 1; + val |= AML_UART_BAUD_USE; + writel(val, port->membase + AML_UART_REG5); +} + +static void meson_uart_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + unsigned int cflags, iflags, baud; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&port->lock, flags); + + cflags = termios->c_cflag; + iflags = termios->c_iflag; + + val = readl(port->membase + AML_UART_CONTROL); + + val &= ~AML_UART_DATA_LEN_MASK; + switch (cflags & CSIZE) { + case CS8: + val |= AML_UART_DATA_LEN_8BIT; + break; + case CS7: + val |= AML_UART_DATA_LEN_7BIT; + break; + case CS6: + val |= AML_UART_DATA_LEN_6BIT; + break; + case CS5: + val |= AML_UART_DATA_LEN_5BIT; + break; + } + + if (cflags & PARENB) + val |= AML_UART_PARITY_EN; + else + val &= ~AML_UART_PARITY_EN; + + if (cflags & PARODD) + val |= AML_UART_PARITY_TYPE; + else + val &= ~AML_UART_PARITY_TYPE; + + val &= ~AML_UART_STOP_BIN_LEN_MASK; + if (cflags & CSTOPB) + val |= AML_UART_STOP_BIN_2SB; + else + val &= ~AML_UART_STOP_BIN_1SB; + + if (cflags & CRTSCTS) + val &= ~AML_UART_TWO_WIRE_EN; + else + val |= AML_UART_TWO_WIRE_EN; + + writel(val, port->membase + AML_UART_CONTROL); + + baud = uart_get_baud_rate(port, termios, old, 9600, 115200); + meson_uart_change_speed(port, baud); + + port->read_status_mask = AML_UART_TX_FIFO_WERR; + if (iflags & INPCK) + port->read_status_mask |= AML_UART_PARITY_ERR | + AML_UART_FRAME_ERR; + + port->ignore_status_mask = 0; + if (iflags & IGNPAR) + port->ignore_status_mask |= AML_UART_PARITY_ERR | + AML_UART_FRAME_ERR; + + uart_update_timeout(port, termios->c_cflag, baud); + spin_unlock_irqrestore(&port->lock, flags); +} + +static int meson_uart_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + int ret = 0; + + if (port->type != PORT_MESON) + ret = -EINVAL; + if (port->irq != ser->irq) + ret = -EINVAL; + if (ser->baud_base < 9600) + ret = -EINVAL; + return ret; +} + +static void meson_uart_release_port(struct uart_port *port) +{ + if (port->flags & UPF_IOREMAP) { + iounmap(port->membase); + port->membase = NULL; + } +} + +static int meson_uart_request_port(struct uart_port *port) +{ + struct platform_device *pdev = to_platform_device(port->dev); + struct resource *res; + int size; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "cannot obtain I/O memory region"); + return -ENODEV; + } + size = resource_size(res); + + if (!devm_request_mem_region(port->dev, port->mapbase, size, + dev_name(port->dev))) { + dev_err(port->dev, "Memory region busy\n"); + return -EBUSY; + } + + if (port->flags & UPF_IOREMAP) { + port->membase = devm_ioremap_nocache(port->dev, + port->mapbase, + size); + if (port->membase == NULL) + return -ENOMEM; + } + + return 0; +} + +static void meson_uart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_MESON; + meson_uart_request_port(port); + } +} + +static struct uart_ops meson_uart_ops = { + .set_mctrl = meson_uart_set_mctrl, + .get_mctrl = meson_uart_get_mctrl, + .tx_empty = meson_uart_tx_empty, + .start_tx = meson_uart_start_tx, + .stop_tx = meson_uart_stop_tx, + .stop_rx = meson_uart_stop_rx, + .startup = meson_uart_startup, + .shutdown = meson_uart_shutdown, + .set_termios = meson_uart_set_termios, + .type = meson_uart_type, + .config_port = meson_uart_config_port, + .request_port = meson_uart_request_port, + .release_port = meson_uart_release_port, + .verify_port = meson_uart_verify_port, +}; + +#ifdef CONFIG_SERIAL_MESON_CONSOLE + +static void meson_console_putchar(struct uart_port *port, int ch) +{ + if (!port->membase) + return; + + while (readl(port->membase + AML_UART_STATUS) & AML_UART_TX_FULL) + cpu_relax(); + writel(ch, port->membase + AML_UART_WFIFO); +} + +static void meson_serial_console_write(struct console *co, const char *s, + u_int count) +{ + struct uart_port *port; + unsigned long flags; + int locked; + + port = meson_ports[co->index]; + if (!port) + return; + + local_irq_save(flags); + if (port->sysrq) { + locked = 0; + } else if (oops_in_progress) { + locked = spin_trylock(&port->lock); + } else { + spin_lock(&port->lock); + locked = 1; + } + + uart_console_write(port, s, count, meson_console_putchar); + + if (locked) + spin_unlock(&port->lock); + local_irq_restore(flags); +} + +static int meson_serial_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 < 0 || co->index >= AML_UART_PORT_NUM) + return -EINVAL; + + port = meson_ports[co->index]; + if (!port || !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 console meson_serial_console = { + .name = AML_UART_DEV_NAME, + .write = meson_serial_console_write, + .device = uart_console_device, + .setup = meson_serial_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &meson_uart_driver, +}; + +static int __init meson_serial_console_init(void) +{ + register_console(&meson_serial_console); + return 0; +} +console_initcall(meson_serial_console_init); + +#define MESON_SERIAL_CONSOLE (&meson_serial_console) +#else +#define MESON_SERIAL_CONSOLE NULL +#endif + +static struct uart_driver meson_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "meson_uart", + .dev_name = AML_UART_DEV_NAME, + .nr = AML_UART_PORT_NUM, + .cons = MESON_SERIAL_CONSOLE, +}; + +static int meson_uart_probe(struct platform_device *pdev) +{ + struct resource *res_mem, *res_irq; + struct uart_port *port; + struct clk *clk; + int ret = 0; + + if (pdev->dev.of_node) + pdev->id = of_alias_get_id(pdev->dev.of_node, "serial"); + + if (pdev->id < 0 || pdev->id >= AML_UART_PORT_NUM) + return -EINVAL; + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res_mem) + return -ENODEV; + + res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res_irq) + return -ENODEV; + + if (meson_ports[pdev->id]) { + dev_err(&pdev->dev, "port %d already allocated\n", pdev->id); + return -EBUSY; + } + + port = devm_kzalloc(&pdev->dev, sizeof(struct uart_port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + port->uartclk = clk_get_rate(clk); + port->iotype = UPIO_MEM; + port->mapbase = res_mem->start; + port->irq = res_irq->start; + port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_LOW_LATENCY; + port->dev = &pdev->dev; + port->line = pdev->id; + port->type = PORT_MESON; + port->x_char = 0; + port->ops = &meson_uart_ops; + port->fifosize = 64; + + meson_ports[pdev->id] = port; + platform_set_drvdata(pdev, port); + + ret = uart_add_one_port(&meson_uart_driver, port); + if (ret) + meson_ports[pdev->id] = NULL; + + return ret; +} + +static int meson_uart_remove(struct platform_device *pdev) +{ + struct uart_port *port; + + port = platform_get_drvdata(pdev); + uart_remove_one_port(&meson_uart_driver, port); + meson_ports[pdev->id] = NULL; + + return 0; +} + + +static const struct of_device_id meson_uart_dt_match[] = { + { .compatible = "amlogic,meson-uart" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, meson_uart_dt_match); + +static struct platform_driver meson_uart_platform_driver = { + .probe = meson_uart_probe, + .remove = meson_uart_remove, + .driver = { + .name = "meson_uart", + .of_match_table = meson_uart_dt_match, + }, +}; + +static int __init meson_uart_init(void) +{ + int ret; + + ret = uart_register_driver(&meson_uart_driver); + if (ret) + return ret; + + ret = platform_driver_register(&meson_uart_platform_driver); + if (ret) + uart_unregister_driver(&meson_uart_driver); + + return ret; +} + +static void __exit meson_uart_exit(void) +{ + platform_driver_unregister(&meson_uart_platform_driver); + uart_unregister_driver(&meson_uart_driver); +} + +module_init(meson_uart_init); +module_exit(meson_uart_exit); + +MODULE_AUTHOR("Carlo Caione <carlo@caione.org>"); +MODULE_DESCRIPTION("Amlogic Meson serial port driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c index 445799dc9846..8fe4501d7565 100644 --- a/drivers/tty/serial/mfd.c +++ b/drivers/tty/serial/mfd.c @@ -1252,12 +1252,7 @@ static int serial_hsu_resume(struct pci_dev *pdev) } return 0; } -#else -#define serial_hsu_suspend NULL -#define serial_hsu_resume NULL -#endif -#ifdef CONFIG_PM_RUNTIME static int serial_hsu_runtime_idle(struct device *dev) { pm_schedule_suspend(dev, 500); @@ -1274,6 +1269,8 @@ static int serial_hsu_runtime_resume(struct device *dev) return 0; } #else +#define serial_hsu_suspend NULL +#define serial_hsu_resume NULL #define serial_hsu_runtime_idle NULL #define serial_hsu_runtime_suspend NULL #define serial_hsu_runtime_resume NULL @@ -1371,7 +1368,7 @@ static void hsu_global_init(void) hsu->iolen = 0x1000; if (!(request_mem_region(hsu->paddr, hsu->iolen, "HSU global"))) - pr_warning("HSU: error in request mem region\n"); + pr_warn("HSU: error in request mem region\n"); hsu->reg = ioremap_nocache((unsigned long)hsu->paddr, hsu->iolen); if (!hsu->reg) { diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index 97888f4900ec..3308ef243dc3 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -1087,22 +1087,6 @@ mpc52xx_uart_start_tx(struct uart_port *port) } static void -mpc52xx_uart_send_xchar(struct uart_port *port, char ch) -{ - unsigned long flags; - spin_lock_irqsave(&port->lock, flags); - - port->x_char = ch; - if (ch) { - /* Make sure tx interrupts are on */ - /* Truly necessary ??? They should be anyway */ - psc_ops->start_tx(port); - } - - spin_unlock_irqrestore(&port->lock, flags); -} - -static void mpc52xx_uart_stop_rx(struct uart_port *port) { /* port->lock taken by caller */ @@ -1361,7 +1345,6 @@ static struct uart_ops mpc52xx_uart_ops = { .get_mctrl = mpc52xx_uart_get_mctrl, .stop_tx = mpc52xx_uart_stop_tx, .start_tx = mpc52xx_uart_start_tx, - .send_xchar = mpc52xx_uart_send_xchar, .stop_rx = mpc52xx_uart_stop_rx, .enable_ms = mpc52xx_uart_enable_ms, .break_ctl = mpc52xx_uart_break_ctl, @@ -1906,7 +1889,6 @@ static struct platform_driver mpc52xx_uart_of_driver = { #endif .driver = { .name = "mpc52xx-psc-uart", - .owner = THIS_MODULE, .of_match_table = mpc52xx_uart_of_match, }, }; diff --git a/drivers/tty/serial/mpsc.c b/drivers/tty/serial/mpsc.c index ae49856ef6c7..856fd5a5fa3c 100644 --- a/drivers/tty/serial/mpsc.c +++ b/drivers/tty/serial/mpsc.c @@ -1246,7 +1246,8 @@ static irqreturn_t mpsc_sdma_intr(int irq, void *dev_id) */ static uint mpsc_tx_empty(struct uart_port *port) { - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + struct mpsc_port_info *pi = + container_of(port, struct mpsc_port_info, port); ulong iflags; uint rc; @@ -1264,7 +1265,8 @@ static void mpsc_set_mctrl(struct uart_port *port, uint mctrl) static uint mpsc_get_mctrl(struct uart_port *port) { - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + struct mpsc_port_info *pi = + container_of(port, struct mpsc_port_info, port); u32 mflags, status; status = (pi->mirror_regs) ? pi->MPSC_CHR_10_m @@ -1281,7 +1283,8 @@ static uint mpsc_get_mctrl(struct uart_port *port) static void mpsc_stop_tx(struct uart_port *port) { - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + struct mpsc_port_info *pi = + container_of(port, struct mpsc_port_info, port); pr_debug("mpsc_stop_tx[%d]\n", port->line); @@ -1290,7 +1293,8 @@ static void mpsc_stop_tx(struct uart_port *port) static void mpsc_start_tx(struct uart_port *port) { - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + struct mpsc_port_info *pi = + container_of(port, struct mpsc_port_info, port); unsigned long iflags; spin_lock_irqsave(&pi->tx_lock, iflags); @@ -1316,7 +1320,8 @@ static void mpsc_start_rx(struct mpsc_port_info *pi) static void mpsc_stop_rx(struct uart_port *port) { - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + struct mpsc_port_info *pi = + container_of(port, struct mpsc_port_info, port); pr_debug("mpsc_stop_rx[%d]: Stopping...\n", port->line); @@ -1338,7 +1343,8 @@ static void mpsc_stop_rx(struct uart_port *port) static void mpsc_break_ctl(struct uart_port *port, int ctl) { - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + struct mpsc_port_info *pi = + container_of(port, struct mpsc_port_info, port); ulong flags; u32 v; @@ -1353,7 +1359,8 @@ static void mpsc_break_ctl(struct uart_port *port, int ctl) static int mpsc_startup(struct uart_port *port) { - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + struct mpsc_port_info *pi = + container_of(port, struct mpsc_port_info, port); u32 flag = 0; int rc; @@ -1383,7 +1390,8 @@ static int mpsc_startup(struct uart_port *port) static void mpsc_shutdown(struct uart_port *port) { - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + struct mpsc_port_info *pi = + container_of(port, struct mpsc_port_info, port); pr_debug("mpsc_shutdown[%d]: Shutting down MPSC\n", port->line); @@ -1394,7 +1402,8 @@ static void mpsc_shutdown(struct uart_port *port) static void mpsc_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + struct mpsc_port_info *pi = + container_of(port, struct mpsc_port_info, port); u32 baud; ulong flags; u32 chr_bits, stop_bits, par; @@ -1498,7 +1507,8 @@ static int mpsc_request_port(struct uart_port *port) static void mpsc_release_port(struct uart_port *port) { - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + struct mpsc_port_info *pi = + container_of(port, struct mpsc_port_info, port); if (pi->ready) { mpsc_uninit_rings(pi); @@ -1513,7 +1523,8 @@ static void mpsc_config_port(struct uart_port *port, int flags) static int mpsc_verify_port(struct uart_port *port, struct serial_struct *ser) { - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + struct mpsc_port_info *pi = + container_of(port, struct mpsc_port_info, port); int rc = 0; pr_debug("mpsc_verify_port[%d]: Verifying port data\n", pi->port.line); @@ -1548,7 +1559,8 @@ static void mpsc_put_poll_char(struct uart_port *port, static int mpsc_get_poll_char(struct uart_port *port) { - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + struct mpsc_port_info *pi = + container_of(port, struct mpsc_port_info, port); struct mpsc_rx_desc *rxre; u32 cmdstat, bytes_in, i; u8 *bp; @@ -1648,7 +1660,8 @@ static int mpsc_get_poll_char(struct uart_port *port) static void mpsc_put_poll_char(struct uart_port *port, unsigned char c) { - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + struct mpsc_port_info *pi = + container_of(port, struct mpsc_port_info, port); u32 data; data = readl(pi->mpsc_base + MPSC_MPCR); @@ -2111,7 +2124,6 @@ static struct platform_driver mpsc_driver = { .remove = mpsc_drv_remove, .driver = { .name = MPSC_CTLR_NAME, - .owner = THIS_MODULE, }, }; diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c index 1504a14ec1a6..77239d5e620d 100644 --- a/drivers/tty/serial/mrst_max3110.c +++ b/drivers/tty/serial/mrst_max3110.c @@ -27,6 +27,8 @@ * interrupt for a low speed UART device */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #ifdef CONFIG_MAGIC_SYSRQ #define SUPPORT_SYSRQ #endif @@ -47,8 +49,6 @@ #include "mrst_max3110.h" -#define PR_FMT "mrst_max3110: " - #define UART_TX_NEEDED 1 #define CON_TX_NEEDED 2 #define BIT_IRQ_PENDING 3 @@ -127,8 +127,8 @@ static int max3110_out(struct uart_max3110 *max, const u16 out) *obuf = out; ret = max3110_write_then_read(max, obuf, ibuf, 2, 1); if (ret) { - pr_warning(PR_FMT "%s(): get err msg %d when sending 0x%x\n", - __func__, ret, out); + pr_warn("%s: get err msg %d when sending 0x%x\n", + __func__, ret, out); goto exit; } @@ -153,10 +153,8 @@ static int max3110_read_multi(struct uart_max3110 *max) blen = M3110_RX_FIFO_DEPTH * sizeof(u16); buf = kzalloc(blen * 2, GFP_KERNEL | GFP_DMA); - if (!buf) { - pr_warning(PR_FMT "%s(): fail to alloc dma buffer\n", __func__); + if (!buf) return 0; - } /* tx/rx always have the same length */ obuf = buf; @@ -212,13 +210,13 @@ serial_m3110_con_setup(struct console *co, char *options) int parity = 'n'; int flow = 'n'; - pr_info(PR_FMT "setting up console\n"); + pr_info("setting up console\n"); if (co->index == -1) co->index = 0; if (!max) { - pr_err(PR_FMT "pmax is NULL, return"); + pr_err("pmax is NULL, return\n"); return -ENODEV; } @@ -296,8 +294,7 @@ static void send_circ_buf(struct uart_max3110 *max, ret = max3110_write_then_read(max, obuf, ibuf, blen, 0); if (ret) - pr_warning(PR_FMT "%s(): get err msg %d\n", - __func__, ret); + pr_warn("%s: get err msg %d\n", __func__, ret); receive_chars(max, ibuf, len); @@ -411,7 +408,7 @@ static int max3110_main_thread(void *_max) int ret = 0; struct circ_buf *xmit = &max->con_xmit; - pr_info(PR_FMT "start main thread\n"); + pr_info("start main thread\n"); do { wait_event_interruptible(*wq, @@ -455,7 +452,7 @@ static int max3110_read_thread(void *_max) { struct uart_max3110 *max = _max; - pr_info(PR_FMT "start read thread\n"); + pr_info("start read thread\n"); do { /* * If can't acquire the mutex, it means the main thread @@ -481,7 +478,7 @@ static int serial_m3110_startup(struct uart_port *port) int ret = 0; if (port->line != 0) { - pr_err(PR_FMT "uart port startup failed\n"); + pr_err("uart port startup failed\n"); return -1; } @@ -504,7 +501,7 @@ static int serial_m3110_startup(struct uart_port *port) if (IS_ERR(max->read_thread)) { ret = PTR_ERR(max->read_thread); max->read_thread = NULL; - pr_err(PR_FMT "Can't create read thread!\n"); + pr_err("Can't create read thread!\n"); return ret; } } diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 0da0b5474e98..c88b522ccd73 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -54,6 +54,7 @@ struct msm_port { unsigned int imr; int is_uartdm; unsigned int old_snap_state; + bool break_detected; }; static inline void wait_for_xmitr(struct uart_port *port) @@ -126,23 +127,38 @@ static void handle_rx_dm(struct uart_port *port, unsigned int misr) while (count > 0) { unsigned char buf[4]; + int sysrq, r_count, i; sr = msm_read(port, UART_SR); if ((sr & UART_SR_RX_READY) == 0) { msm_port->old_snap_state -= count; break; } + ioread32_rep(port->membase + UARTDM_RF, buf, 1); - if (sr & UART_SR_RX_BREAK) { - port->icount.brk++; - if (uart_handle_break(port)) - continue; - } else if (sr & UART_SR_PAR_FRAME_ERR) - port->icount.frame++; + r_count = min_t(int, count, sizeof(buf)); + + for (i = 0; i < r_count; i++) { + char flag = TTY_NORMAL; - /* TODO: handle sysrq */ - tty_insert_flip_string(tport, buf, min(count, 4)); - count -= 4; + if (msm_port->break_detected && buf[i] == 0) { + port->icount.brk++; + flag = TTY_BREAK; + msm_port->break_detected = false; + if (uart_handle_break(port)) + continue; + } + + if (!(port->read_status_mask & UART_SR_RX_BREAK)) + flag = TTY_NORMAL; + + spin_unlock(&port->lock); + sysrq = uart_handle_sysrq_char(port, buf[i]); + spin_lock(&port->lock); + if (!sysrq) + tty_insert_flip_char(tport, buf[i], flag); + } + count -= r_count; } spin_unlock(&port->lock); @@ -174,6 +190,7 @@ static void handle_rx(struct uart_port *port) while ((sr = msm_read(port, UART_SR)) & UART_SR_RX_READY) { unsigned int c; char flag = TTY_NORMAL; + int sysrq; c = msm_read(port, UART_RF); @@ -190,13 +207,15 @@ static void handle_rx(struct uart_port *port) /* Mask conditions we're ignorning. */ sr &= port->read_status_mask; - if (sr & UART_SR_RX_BREAK) { + if (sr & UART_SR_RX_BREAK) flag = TTY_BREAK; - } else if (sr & UART_SR_PAR_FRAME_ERR) { + else if (sr & UART_SR_PAR_FRAME_ERR) flag = TTY_FRAME; - } - if (!uart_handle_sysrq_char(port, c)) + spin_unlock(&port->lock); + sysrq = uart_handle_sysrq_char(port, c); + spin_lock(&port->lock); + if (!sysrq) tty_insert_flip_char(tport, c, flag); } @@ -288,6 +307,11 @@ static irqreturn_t msm_irq(int irq, void *dev_id) misr = msm_read(port, UART_MISR); msm_write(port, 0, UART_IMR); /* disable interrupt */ + if (misr & UART_IMR_RXBREAK_START) { + msm_port->break_detected = true; + msm_write(port, UART_CR_CMD_RESET_RXBREAK_START, UART_CR); + } + if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)) { if (msm_port->is_uartdm) handle_rx_dm(port, misr); @@ -315,7 +339,6 @@ static unsigned int msm_get_mctrl(struct uart_port *port) return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS; } - static void msm_reset(struct uart_port *port) { struct msm_port *msm_port = UART_TO_MSM(port); @@ -336,6 +359,7 @@ static void msm_reset(struct uart_port *port) static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl) { unsigned int mr; + mr = msm_read(port, UART_MR1); if (!(mctrl & TIOCM_RTS)) { @@ -403,9 +427,6 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud) entry = msm_find_best_baud(port, baud); - if (msm_port->is_uartdm) - msm_write(port, UART_CR_CMD_RESET_RX, UART_CR); - msm_write(port, entry->code, UART_CSR); /* RX stale watermark */ @@ -422,6 +443,18 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud) /* set TX watermark */ msm_write(port, 10, UART_TFWR); + msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR); + msm_reset(port); + + /* Enable RX and TX */ + msm_write(port, UART_CR_TX_ENABLE | UART_CR_RX_ENABLE, UART_CR); + + /* turn on RX and CTS interrupts */ + msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE | + UART_IMR_CURRENT_CTS | UART_IMR_RXBREAK_START; + + msm_write(port, msm_port->imr, UART_IMR); + if (msm_port->is_uartdm) { msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); msm_write(port, 0xFFFFFF, UARTDM_DMRX); @@ -431,7 +464,6 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud) return baud; } - static void msm_init_clock(struct uart_port *port) { struct msm_port *msm_port = UART_TO_MSM(port); @@ -469,40 +501,6 @@ static int msm_startup(struct uart_port *port) data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2); data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level; msm_write(port, data, UART_MR1); - - /* make sure that RXSTALE count is non-zero */ - data = msm_read(port, UART_IPR); - if (unlikely(!data)) { - data |= UART_IPR_RXSTALE_LAST; - data |= UART_IPR_STALE_LSB; - msm_write(port, data, UART_IPR); - } - - data = 0; - if (!port->cons || (port->cons && !(port->cons->flags & CON_ENABLED))) { - msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR); - msm_reset(port); - data = UART_CR_TX_ENABLE; - } - - data |= UART_CR_RX_ENABLE; - msm_write(port, data, UART_CR); /* enable TX & RX */ - - /* Make sure IPR is not 0 to start with*/ - if (msm_port->is_uartdm) - msm_write(port, UART_IPR_STALE_LSB, UART_IPR); - - /* turn on RX and CTS interrupts */ - msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE | - UART_IMR_CURRENT_CTS; - - if (msm_port->is_uartdm) { - msm_write(port, 0xFFFFFF, UARTDM_DMRX); - msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); - msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); - } - - msm_write(port, msm_port->imr, UART_IMR); return 0; } @@ -646,6 +644,7 @@ fail_release_port: static void msm_config_port(struct uart_port *port, int flags) { int ret; + if (flags & UART_CONFIG_TYPE) { port->type = PORT_MSM; ret = msm_request_port(port); @@ -678,22 +677,11 @@ static void msm_power(struct uart_port *port, unsigned int state, clk_disable_unprepare(msm_port->pclk); break; default: - printk(KERN_ERR "msm_serial: Unknown PM state %d\n", state); + pr_err("msm_serial: Unknown PM state %d\n", state); } } #ifdef CONFIG_CONSOLE_POLL -static int msm_poll_init(struct uart_port *port) -{ - struct msm_port *msm_port = UART_TO_MSM(port); - - /* Enable single character mode on RX FIFO */ - if (msm_port->is_uartdm >= UARTDM_1P4) - msm_write(port, UARTDM_DMEN_RX_SC_ENABLE, UARTDM_DMEN); - - return 0; -} - static int msm_poll_get_char_single(struct uart_port *port) { struct msm_port *msm_port = UART_TO_MSM(port); @@ -701,11 +689,11 @@ static int msm_poll_get_char_single(struct uart_port *port) if (!(msm_read(port, UART_SR) & UART_SR_RX_READY)) return NO_POLL_CHAR; - else - return msm_read(port, rf_reg) & 0xff; + + return msm_read(port, rf_reg) & 0xff; } -static int msm_poll_get_char_dm_1p3(struct uart_port *port) +static int msm_poll_get_char_dm(struct uart_port *port) { int c; static u32 slop; @@ -729,6 +717,10 @@ static int msm_poll_get_char_dm_1p3(struct uart_port *port) slop = msm_read(port, UARTDM_RF); c = sp[0]; count--; + msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); + msm_write(port, 0xFFFFFF, UARTDM_DMRX); + msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, + UART_CR); } else { c = NO_POLL_CHAR; } @@ -752,8 +744,8 @@ static int msm_poll_get_char(struct uart_port *port) imr = msm_read(port, UART_IMR); msm_write(port, 0, UART_IMR); - if (msm_port->is_uartdm == UARTDM_1P3) - c = msm_poll_get_char_dm_1p3(port); + if (msm_port->is_uartdm) + c = msm_poll_get_char_dm(port); else c = msm_poll_get_char_single(port); @@ -788,8 +780,6 @@ static void msm_poll_put_char(struct uart_port *port, unsigned char c) /* Enable interrupts */ msm_write(port, imr, UART_IMR); - - return; } #endif @@ -812,7 +802,6 @@ static struct uart_ops msm_uart_pops = { .verify_port = msm_verify_port, .pm = msm_power, #ifdef CONFIG_CONSOLE_POLL - .poll_init = msm_poll_init, .poll_get_char = msm_poll_get_char, .poll_put_char = msm_poll_put_char, #endif @@ -856,22 +845,15 @@ static inline struct uart_port *get_port_from_line(unsigned int line) } #ifdef CONFIG_SERIAL_MSM_CONSOLE -static void msm_console_write(struct console *co, const char *s, - unsigned int count) +static void __msm_console_write(struct uart_port *port, const char *s, + unsigned int count, bool is_uartdm) { int i; - struct uart_port *port; - struct msm_port *msm_port; int num_newlines = 0; bool replaced = false; void __iomem *tf; - BUG_ON(co->index < 0 || co->index >= UART_NR); - - port = get_port_from_line(co->index); - msm_port = UART_TO_MSM(port); - - if (msm_port->is_uartdm) + if (is_uartdm) tf = port->membase + UARTDM_TF; else tf = port->membase + UART_TF; @@ -883,7 +865,7 @@ static void msm_console_write(struct console *co, const char *s, count += num_newlines; spin_lock(&port->lock); - if (msm_port->is_uartdm) + if (is_uartdm) reset_dm_count(port, count); i = 0; @@ -892,7 +874,7 @@ static void msm_console_write(struct console *co, const char *s, unsigned int num_chars; char buf[4] = { 0 }; - if (msm_port->is_uartdm) + if (is_uartdm) num_chars = min(count - i, (unsigned int)sizeof(buf)); else num_chars = 1; @@ -921,6 +903,20 @@ static void msm_console_write(struct console *co, const char *s, spin_unlock(&port->lock); } +static void msm_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct uart_port *port; + struct msm_port *msm_port; + + BUG_ON(co->index < 0 || co->index >= UART_NR); + + port = get_port_from_line(co->index); + msm_port = UART_TO_MSM(port); + + __msm_console_write(port, s, count, msm_port->is_uartdm); +} + static int __init msm_console_setup(struct console *co, char *options) { struct uart_port *port; @@ -958,11 +954,54 @@ static int __init msm_console_setup(struct console *co, char *options) msm_write(port, UART_CR_TX_ENABLE, UART_CR); } - printk(KERN_INFO "msm_serial: console setup on port #%d\n", port->line); + pr_info("msm_serial: console setup on port #%d\n", port->line); return uart_set_options(port, co, baud, parity, bits, flow); } +static void +msm_serial_early_write(struct console *con, const char *s, unsigned n) +{ + struct earlycon_device *dev = con->data; + + __msm_console_write(&dev->port, s, n, false); +} + +static int __init +msm_serial_early_console_setup(struct earlycon_device *device, const char *opt) +{ + if (!device->port.membase) + return -ENODEV; + + device->con->write = msm_serial_early_write; + return 0; +} +EARLYCON_DECLARE(msm_serial, msm_serial_early_console_setup); +OF_EARLYCON_DECLARE(msm_serial, "qcom,msm-uart", + msm_serial_early_console_setup); + +static void +msm_serial_early_write_dm(struct console *con, const char *s, unsigned n) +{ + struct earlycon_device *dev = con->data; + + __msm_console_write(&dev->port, s, n, true); +} + +static int __init +msm_serial_early_console_setup_dm(struct earlycon_device *device, + const char *opt) +{ + if (!device->port.membase) + return -ENODEV; + + device->con->write = msm_serial_early_write_dm; + return 0; +} +EARLYCON_DECLARE(msm_serial_dm, msm_serial_early_console_setup_dm); +OF_EARLYCON_DECLARE(msm_serial_dm, "qcom,msm-uartdm", + msm_serial_early_console_setup_dm); + static struct uart_driver msm_uart_driver; static struct console msm_console = { @@ -1005,17 +1044,22 @@ static int msm_serial_probe(struct platform_device *pdev) struct resource *resource; struct uart_port *port; const struct of_device_id *id; - int irq; + int irq, line; - if (pdev->id == -1) - pdev->id = atomic_inc_return(&msm_uart_next_id) - 1; + if (pdev->dev.of_node) + line = of_alias_get_id(pdev->dev.of_node, "serial"); + else + line = pdev->id; + + if (line < 0) + line = atomic_inc_return(&msm_uart_next_id) - 1; - if (unlikely(pdev->id < 0 || pdev->id >= UART_NR)) + if (unlikely(line < 0 || line >= UART_NR)) return -ENXIO; - printk(KERN_INFO "msm_serial: detected port #%d\n", pdev->id); + dev_info(&pdev->dev, "msm_serial: detected port #%d\n", line); - port = get_port_from_line(pdev->id); + port = get_port_from_line(line); port->dev = &pdev->dev; msm_port = UART_TO_MSM(port); @@ -1038,8 +1082,7 @@ static int msm_serial_probe(struct platform_device *pdev) } port->uartclk = clk_get_rate(msm_port->clk); - printk(KERN_INFO "uartclk = %d\n", port->uartclk); - + dev_info(&pdev->dev, "uartclk = %d\n", port->uartclk); resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (unlikely(!resource)) @@ -1076,7 +1119,6 @@ static struct platform_driver msm_platform_driver = { .probe = msm_serial_probe, .driver = { .name = "msm_serial", - .owner = THIS_MODULE, .of_match_table = msm_match_table, }, }; @@ -1093,7 +1135,7 @@ static int __init msm_serial_init(void) if (unlikely(ret)) uart_unregister_driver(&msm_uart_driver); - printk(KERN_INFO "msm_serial: driver initialized\n"); + pr_info("msm_serial: driver initialized\n"); return ret; } diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h index 73d3abe71e79..3e1c7138d8cd 100644 --- a/drivers/tty/serial/msm_serial.h +++ b/drivers/tty/serial/msm_serial.h @@ -65,6 +65,7 @@ #define UART_CR_TX_ENABLE (1 << 2) #define UART_CR_RX_DISABLE (1 << 1) #define UART_CR_RX_ENABLE (1 << 0) +#define UART_CR_CMD_RESET_RXBREAK_START ((1 << 11) | (2 << 4)) #define UART_IMR 0x0014 #define UART_IMR_TXLEV (1 << 0) @@ -72,6 +73,7 @@ #define UART_IMR_RXLEV (1 << 4) #define UART_IMR_DELTA_CTS (1 << 5) #define UART_IMR_CURRENT_CTS (1 << 6) +#define UART_IMR_RXBREAK_START (1 << 10) #define UART_IPR_RXSTALE_LAST 0x20 #define UART_IPR_STALE_LSB 0x1F diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c index 48e94961a9e5..62da8534ba75 100644 --- a/drivers/tty/serial/msm_serial_hs.c +++ b/drivers/tty/serial/msm_serial_hs.c @@ -1792,7 +1792,7 @@ static void __exit msm_serial_hs_exit(void) } module_exit(msm_serial_hs_exit); -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM static int msm_hs_runtime_idle(struct device *dev) { /* @@ -1838,7 +1838,6 @@ static struct platform_driver msm_serial_hs_platform_driver = { .remove = msm_hs_remove, .driver = { .name = "msm_serial_hs", - .owner = THIS_MODULE, .pm = &msm_hs_dev_pm_ops, }, }; diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index b5c329248c81..ec553f8eb218 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -14,6 +14,10 @@ * http://www.gnu.org/copyleft/gpl.html */ +#if defined(CONFIG_SERIAL_MXS_AUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + #include <linux/kernel.h> #include <linux/errno.h> #include <linux/init.h> @@ -38,6 +42,12 @@ #include <asm/cacheflush.h> +#include <linux/gpio.h> +#include <linux/gpio/consumer.h> +#include <linux/err.h> +#include <linux/irq.h> +#include "serial_mctrl_gpio.h" + #define MXS_AUART_PORTS 5 #define MXS_AUART_FIFO_SIZE 16 @@ -139,7 +149,7 @@ struct mxs_auart_port { #define MXS_AUART_DMA_RX_READY 3 /* bit 3 */ #define MXS_AUART_RTSCTS 4 /* bit 4 */ unsigned long flags; - unsigned int ctrl; + unsigned int mctrl_prev; enum mxs_auart_type devtype; unsigned int irq; @@ -155,6 +165,10 @@ struct mxs_auart_port { struct scatterlist rx_sgl; struct dma_chan *rx_dma_chan; void *rx_dma_buf; + + struct mctrl_gpios *gpios; + int gpio_irq[UART_GPIO_MAX]; + bool ms_irq_enabled; }; static struct platform_device_id mxs_auart_devtype[] = { @@ -408,31 +422,108 @@ static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl) ctrl &= ~(AUART_CTRL2_RTSEN | AUART_CTRL2_RTS); if (mctrl & TIOCM_RTS) { - if (tty_port_cts_enabled(&u->state->port)) + if (uart_cts_enabled(u)) ctrl |= AUART_CTRL2_RTSEN; else ctrl |= AUART_CTRL2_RTS; } - s->ctrl = mctrl; writel(ctrl, u->membase + AUART_CTRL2); + + mctrl_gpio_set(s->gpios, mctrl); +} + +#define MCTRL_ANY_DELTA (TIOCM_RI | TIOCM_DSR | TIOCM_CD | TIOCM_CTS) +static u32 mxs_auart_modem_status(struct mxs_auart_port *s, u32 mctrl) +{ + u32 mctrl_diff; + + mctrl_diff = mctrl ^ s->mctrl_prev; + s->mctrl_prev = mctrl; + if (mctrl_diff & MCTRL_ANY_DELTA && s->ms_irq_enabled && + s->port.state != NULL) { + if (mctrl_diff & TIOCM_RI) + s->port.icount.rng++; + if (mctrl_diff & TIOCM_DSR) + s->port.icount.dsr++; + if (mctrl_diff & TIOCM_CD) + uart_handle_dcd_change(&s->port, mctrl & TIOCM_CD); + if (mctrl_diff & TIOCM_CTS) + uart_handle_cts_change(&s->port, mctrl & TIOCM_CTS); + + wake_up_interruptible(&s->port.state->port.delta_msr_wait); + } + return mctrl; } static u32 mxs_auart_get_mctrl(struct uart_port *u) { struct mxs_auart_port *s = to_auart_port(u); u32 stat = readl(u->membase + AUART_STAT); - int ctrl2 = readl(u->membase + AUART_CTRL2); - u32 mctrl = s->ctrl; + u32 mctrl = 0; - mctrl &= ~TIOCM_CTS; if (stat & AUART_STAT_CTS) mctrl |= TIOCM_CTS; - if (ctrl2 & AUART_CTRL2_RTS) - mctrl |= TIOCM_RTS; + return mctrl_gpio_get(s->gpios, &mctrl); +} + +/* + * Enable modem status interrupts + */ +static void mxs_auart_enable_ms(struct uart_port *port) +{ + struct mxs_auart_port *s = to_auart_port(port); - return mctrl; + /* + * Interrupt should not be enabled twice + */ + if (s->ms_irq_enabled) + return; + + s->ms_irq_enabled = true; + + if (s->gpio_irq[UART_GPIO_CTS] >= 0) + enable_irq(s->gpio_irq[UART_GPIO_CTS]); + /* TODO: enable AUART_INTR_CTSMIEN otherwise */ + + if (s->gpio_irq[UART_GPIO_DSR] >= 0) + enable_irq(s->gpio_irq[UART_GPIO_DSR]); + + if (s->gpio_irq[UART_GPIO_RI] >= 0) + enable_irq(s->gpio_irq[UART_GPIO_RI]); + + if (s->gpio_irq[UART_GPIO_DCD] >= 0) + enable_irq(s->gpio_irq[UART_GPIO_DCD]); +} + +/* + * Disable modem status interrupts + */ +static void mxs_auart_disable_ms(struct uart_port *port) +{ + struct mxs_auart_port *s = to_auart_port(port); + + /* + * Interrupt should not be disabled twice + */ + if (!s->ms_irq_enabled) + return; + + s->ms_irq_enabled = false; + + if (s->gpio_irq[UART_GPIO_CTS] >= 0) + disable_irq(s->gpio_irq[UART_GPIO_CTS]); + /* TODO: disable AUART_INTR_CTSMIEN otherwise */ + + if (s->gpio_irq[UART_GPIO_DSR] >= 0) + disable_irq(s->gpio_irq[UART_GPIO_DSR]); + + if (s->gpio_irq[UART_GPIO_RI] >= 0) + disable_irq(s->gpio_irq[UART_GPIO_RI]); + + if (s->gpio_irq[UART_GPIO_DCD] >= 0) + disable_irq(s->gpio_irq[UART_GPIO_DCD]); } static int mxs_auart_dma_prep_rx(struct mxs_auart_port *s); @@ -560,6 +651,10 @@ err_out: } +#define RTS_AT_AUART() IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(s->gpios, \ + UART_GPIO_RTS)) +#define CTS_AT_AUART() IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(s->gpios, \ + UART_GPIO_CTS)) static void mxs_auart_settermios(struct uart_port *u, struct ktermios *termios, struct ktermios *old) @@ -636,6 +731,7 @@ static void mxs_auart_settermios(struct uart_port *u, ctrl |= AUART_LINECTRL_STP2; /* figure out the hardware flow control settings */ + ctrl2 &= ~(AUART_CTRL2_CTSEN | AUART_CTRL2_RTSEN); if (cflag & CRTSCTS) { /* * The DMA has a bug(see errata:2836) in mx23. @@ -650,9 +746,11 @@ static void mxs_auart_settermios(struct uart_port *u, ctrl2 |= AUART_CTRL2_TXDMAE | AUART_CTRL2_RXDMAE | AUART_CTRL2_DMAONERR; } - ctrl2 |= AUART_CTRL2_CTSEN | AUART_CTRL2_RTSEN; - } else { - ctrl2 &= ~(AUART_CTRL2_CTSEN | AUART_CTRL2_RTSEN); + /* Even if RTS is GPIO line RTSEN can be enabled because + * the pinctrl configuration decides about RTS pin function */ + ctrl2 |= AUART_CTRL2_RTSEN; + if (CTS_AT_AUART()) + ctrl2 |= AUART_CTRL2_CTSEN; } /* set baud rate */ @@ -678,12 +776,30 @@ static void mxs_auart_settermios(struct uart_port *u, dev_err(s->dev, "We can not start up the DMA.\n"); } } + + /* CTS flow-control and modem-status interrupts */ + if (UART_ENABLE_MS(u, termios->c_cflag)) + mxs_auart_enable_ms(u); + else + mxs_auart_disable_ms(u); +} + +static void mxs_auart_set_ldisc(struct uart_port *port, + struct ktermios *termios) +{ + if (termios->c_line == N_PPS) { + port->flags |= UPF_HARDPPS_CD; + mxs_auart_enable_ms(port); + } else { + port->flags &= ~UPF_HARDPPS_CD; + } } static irqreturn_t mxs_auart_irq_handle(int irq, void *context) { u32 istat; struct mxs_auart_port *s = context; + u32 mctrl_temp = s->mctrl_prev; u32 stat = readl(s->port.membase + AUART_STAT); istat = readl(s->port.membase + AUART_INTR); @@ -695,8 +811,20 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context) | AUART_INTR_CTSMIS), s->port.membase + AUART_INTR_CLR); + /* + * Dealing with GPIO interrupt + */ + if (irq == s->gpio_irq[UART_GPIO_CTS] || + irq == s->gpio_irq[UART_GPIO_DCD] || + irq == s->gpio_irq[UART_GPIO_DSR] || + irq == s->gpio_irq[UART_GPIO_RI]) + mxs_auart_modem_status(s, + mctrl_gpio_get(s->gpios, &mctrl_temp)); + if (istat & AUART_INTR_CTSMIS) { - uart_handle_cts_change(&s->port, stat & AUART_STAT_CTS); + if (CTS_AT_AUART() && s->ms_irq_enabled) + uart_handle_cts_change(&s->port, + stat & AUART_STAT_CTS); writel(AUART_INTR_CTSMIS, s->port.membase + AUART_INTR_CLR); istat &= ~AUART_INTR_CTSMIS; @@ -757,6 +885,10 @@ static int mxs_auart_startup(struct uart_port *u) */ writel(AUART_LINECTRL_FEN, u->membase + AUART_LINECTRL_SET); + /* get initial status of modem lines */ + mctrl_gpio_get(s->gpios, &s->mctrl_prev); + + s->ms_irq_enabled = false; return 0; } @@ -764,6 +896,8 @@ static void mxs_auart_shutdown(struct uart_port *u) { struct mxs_auart_port *s = to_auart_port(u); + mxs_auart_disable_ms(u); + if (auart_dma_enabled(s)) mxs_auart_dma_exit(s); @@ -779,10 +913,11 @@ static void mxs_auart_shutdown(struct uart_port *u) static unsigned int mxs_auart_tx_empty(struct uart_port *u) { - if (readl(u->membase + AUART_STAT) & AUART_STAT_TXFE) + if ((readl(u->membase + AUART_STAT) & + (AUART_STAT_TXFE | AUART_STAT_BUSY)) == AUART_STAT_TXFE) return TIOCSER_TEMT; - else - return 0; + + return 0; } static void mxs_auart_start_tx(struct uart_port *u) @@ -820,12 +955,14 @@ static struct uart_ops mxs_auart_ops = { .start_tx = mxs_auart_start_tx, .stop_tx = mxs_auart_stop_tx, .stop_rx = mxs_auart_stop_rx, + .enable_ms = mxs_auart_enable_ms, .break_ctl = mxs_auart_break_ctl, .set_mctrl = mxs_auart_set_mctrl, .get_mctrl = mxs_auart_get_mctrl, .startup = mxs_auart_startup, .shutdown = mxs_auart_shutdown, .set_termios = mxs_auart_settermios, + .set_ldisc = mxs_auart_set_ldisc, .type = mxs_auart_type, .release_port = mxs_auart_release_port, .request_port = mxs_auart_request_port, @@ -1020,6 +1157,71 @@ static int serial_mxs_probe_dt(struct mxs_auart_port *s, return 0; } +static bool mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev) +{ + enum mctrl_gpio_idx i; + struct gpio_desc *gpiod; + + s->gpios = mctrl_gpio_init(dev, 0); + if (IS_ERR_OR_NULL(s->gpios)) + return false; + + /* Block (enabled before) DMA option if RTS or CTS is GPIO line */ + if (!RTS_AT_AUART() || !CTS_AT_AUART()) { + if (test_bit(MXS_AUART_RTSCTS, &s->flags)) + dev_warn(dev, + "DMA and flow control via gpio may cause some problems. DMA disabled!\n"); + clear_bit(MXS_AUART_RTSCTS, &s->flags); + } + + for (i = 0; i < UART_GPIO_MAX; i++) { + gpiod = mctrl_gpio_to_gpiod(s->gpios, i); + if (gpiod && (gpiod_get_direction(gpiod) == GPIOF_DIR_IN)) + s->gpio_irq[i] = gpiod_to_irq(gpiod); + else + s->gpio_irq[i] = -EINVAL; + } + + return true; +} + +static void mxs_auart_free_gpio_irq(struct mxs_auart_port *s) +{ + enum mctrl_gpio_idx i; + + for (i = 0; i < UART_GPIO_MAX; i++) + if (s->gpio_irq[i] >= 0) + free_irq(s->gpio_irq[i], s); +} + +static int mxs_auart_request_gpio_irq(struct mxs_auart_port *s) +{ + int *irq = s->gpio_irq; + enum mctrl_gpio_idx i; + int err = 0; + + for (i = 0; (i < UART_GPIO_MAX) && !err; i++) { + if (irq[i] < 0) + continue; + + irq_set_status_flags(irq[i], IRQ_NOAUTOEN); + err = request_irq(irq[i], mxs_auart_irq_handle, + IRQ_TYPE_EDGE_BOTH, dev_name(s->dev), s); + if (err) + dev_err(s->dev, "%s - Can't get %d irq\n", + __func__, irq[i]); + } + + /* + * If something went wrong, rollback. + */ + while (err && (--i >= 0)) + if (irq[i] >= 0) + free_irq(irq[i], s); + + return err; +} + static int mxs_auart_probe(struct platform_device *pdev) { const struct of_device_id *of_id = @@ -1067,7 +1269,7 @@ static int mxs_auart_probe(struct platform_device *pdev) s->port.type = PORT_IMX; s->port.dev = s->dev = &pdev->dev; - s->ctrl = 0; + s->mctrl_prev = 0; s->irq = platform_get_irq(pdev, 0); s->port.irq = s->irq; @@ -1077,13 +1279,24 @@ static int mxs_auart_probe(struct platform_device *pdev) platform_set_drvdata(pdev, s); + if (!mxs_auart_init_gpios(s, &pdev->dev)) + dev_err(&pdev->dev, + "Failed to initialize GPIOs. The serial port may not work as expected\n"); + + /* + * Get the GPIO lines IRQ + */ + ret = mxs_auart_request_gpio_irq(s); + if (ret) + goto out_free_irq; + auart_port[s->port.line] = s; mxs_auart_reset(&s->port); ret = uart_add_one_port(&auart_driver, &s->port); if (ret) - goto out_free_irq; + goto out_free_gpio_irq; version = readl(s->port.membase + AUART_VERSION); dev_info(&pdev->dev, "Found APPUART %d.%d.%d\n", @@ -1092,6 +1305,8 @@ static int mxs_auart_probe(struct platform_device *pdev) return 0; +out_free_gpio_irq: + mxs_auart_free_gpio_irq(s); out_free_irq: auart_port[pdev->id] = NULL; free_irq(s->irq, s); @@ -1111,6 +1326,7 @@ static int mxs_auart_remove(struct platform_device *pdev) auart_port[pdev->id] = NULL; + mxs_auart_free_gpio_irq(s); clk_put(s->clk); free_irq(s->irq, s); kfree(s); @@ -1123,7 +1339,6 @@ static struct platform_driver mxs_auart_driver = { .remove = mxs_auart_remove, .driver = { .name = "mxs-auart", - .owner = THIS_MODULE, .of_match_table = mxs_auart_dt_ids, }, }; diff --git a/drivers/tty/serial/netx-serial.c b/drivers/tty/serial/netx-serial.c index 7a6745601d4e..207a0a032ed1 100644 --- a/drivers/tty/serial/netx-serial.c +++ b/drivers/tty/serial/netx-serial.c @@ -710,7 +710,6 @@ static struct platform_driver serial_netx_driver = { .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, }, }; diff --git a/drivers/tty/serial/nwpserial.c b/drivers/tty/serial/nwpserial.c index c06366b6bc29..5da7622e88c3 100644 --- a/drivers/tty/serial/nwpserial.c +++ b/drivers/tty/serial/nwpserial.c @@ -22,6 +22,7 @@ #include <linux/of_platform.h> #include <linux/of_device.h> #include <linux/nwpserial.h> +#include <linux/delay.h> #include <asm/prom.h> #include <asm/dcr.h> diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index 68d4455f3cf9..64f1bab7e9d7 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -9,6 +9,7 @@ * 2 of the License, or (at your option) any later version. * */ +#include <linux/console.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/delay.h> @@ -129,8 +130,15 @@ static int of_platform_serial_setup(struct platform_device *ofdev, port->dev = &ofdev->dev; - if (type == PORT_TEGRA) + switch (type) { + case PORT_TEGRA: port->handle_break = tegra_serial_handle_break; + break; + + case PORT_RT2880: + port->iotype = UPIO_AU; + break; + } return 0; out: @@ -158,7 +166,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev) if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL)) return -EBUSY; - info = kmalloc(sizeof(*info), GFP_KERNEL); + info = kzalloc(sizeof(*info), GFP_KERNEL); if (info == NULL) return -ENOMEM; @@ -183,10 +191,6 @@ static int of_platform_serial_probe(struct platform_device *ofdev) "auto-flow-control")) port8250.capabilities |= UART_CAP_AFE; - if (of_property_read_bool(ofdev->dev.of_node, - "has-hw-flow-control")) - port8250.port.flags |= UPF_HARD_FLOW; - ret = serial8250_register_8250_port(&port8250); break; } @@ -244,6 +248,70 @@ static int of_platform_serial_remove(struct platform_device *ofdev) return 0; } +#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_SERIAL_8250 +static void of_serial_suspend_8250(struct of_serial_info *info) +{ + struct uart_8250_port *port8250 = serial8250_get_port(info->line); + struct uart_port *port = &port8250->port; + + serial8250_suspend_port(info->line); + if (info->clk && (!uart_console(port) || console_suspend_enabled)) + clk_disable_unprepare(info->clk); +} + +static void of_serial_resume_8250(struct of_serial_info *info) +{ + struct uart_8250_port *port8250 = serial8250_get_port(info->line); + struct uart_port *port = &port8250->port; + + if (info->clk && (!uart_console(port) || console_suspend_enabled)) + clk_prepare_enable(info->clk); + + serial8250_resume_port(info->line); +} +#else +static inline void of_serial_suspend_8250(struct of_serial_info *info) +{ +} + +static inline void of_serial_resume_8250(struct of_serial_info *info) +{ +} +#endif + +static int of_serial_suspend(struct device *dev) +{ + struct of_serial_info *info = dev_get_drvdata(dev); + + switch (info->type) { + case PORT_8250 ... PORT_MAX_8250: + of_serial_suspend_8250(info); + break; + default: + break; + } + + return 0; +} + +static int of_serial_resume(struct device *dev) +{ + struct of_serial_info *info = dev_get_drvdata(dev); + + switch (info->type) { + case PORT_8250 ... PORT_MAX_8250: + of_serial_resume_8250(info); + break; + default: + break; + } + + return 0; +} +#endif +static SIMPLE_DEV_PM_OPS(of_serial_pm_ops, of_serial_suspend, of_serial_resume); + /* * A few common types, add more as needed. */ @@ -256,6 +324,7 @@ static struct of_device_id of_platform_serial_table[] = { { .compatible = "ns16850", .data = (void *)PORT_16850, }, { .compatible = "nvidia,tegra20-uart", .data = (void *)PORT_TEGRA, }, { .compatible = "nxp,lpc3220-uart", .data = (void *)PORT_LPC3220, }, + { .compatible = "ralink,rt2880-uart", .data = (void *)PORT_RT2880, }, { .compatible = "altr,16550-FIFO32", .data = (void *)PORT_ALTR_16550_F32, }, { .compatible = "altr,16550-FIFO64", @@ -273,7 +342,6 @@ static struct of_device_id of_platform_serial_table[] = { static struct platform_driver of_platform_serial_driver = { .driver = { .name = "of_serial", - .owner = THIS_MODULE, .of_match_table = of_platform_serial_table, }, .probe = of_platform_serial_probe, diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index d017cec8a34a..2e1073da6719 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -46,7 +46,7 @@ #include <dt-bindings/gpio/gpio.h> -#define OMAP_MAX_HSUART_PORTS 6 +#define OMAP_MAX_HSUART_PORTS 10 #define UART_BUILD_REVISION(x, y) (((x) << 8) | (y)) @@ -163,7 +163,6 @@ struct uart_omap_port { u8 wakeups_enabled; u32 features; - struct serial_rs485 rs485; int rts_gpio; struct pm_qos_request pm_qos_request; @@ -239,6 +238,26 @@ static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable) } /* + * Calculate the absolute difference between the desired and actual baud + * rate for the given mode. + */ +static inline int calculate_baud_abs_diff(struct uart_port *port, + unsigned int baud, unsigned int mode) +{ + unsigned int n = port->uartclk / (mode * baud); + int abs_diff; + + if (n == 0) + n = 1; + + abs_diff = baud - (port->uartclk / (mode * n)); + if (abs_diff < 0) + abs_diff = -abs_diff; + + return abs_diff; +} + +/* * serial_omap_baud_is_mode16 - check if baud rate is MODE16X * @port: uart port info * @baud: baudrate for which mode needs to be determined @@ -252,16 +271,10 @@ static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable) static bool serial_omap_baud_is_mode16(struct uart_port *port, unsigned int baud) { - unsigned int n13 = port->uartclk / (13 * baud); - unsigned int n16 = port->uartclk / (16 * baud); - int baudAbsDiff13 = baud - (port->uartclk / (13 * n13)); - int baudAbsDiff16 = baud - (port->uartclk / (16 * n16)); - if (baudAbsDiff13 < 0) - baudAbsDiff13 = -baudAbsDiff13; - if (baudAbsDiff16 < 0) - baudAbsDiff16 = -baudAbsDiff16; - - return (baudAbsDiff13 >= baudAbsDiff16); + int abs_diff_13 = calculate_baud_abs_diff(port, baud, 13); + int abs_diff_16 = calculate_baud_abs_diff(port, baud, 16); + + return (abs_diff_13 >= abs_diff_16); } /* @@ -302,7 +315,7 @@ static void serial_omap_stop_tx(struct uart_port *port) pm_runtime_get_sync(up->dev); /* Handle RS-485 */ - if (up->rs485.flags & SER_RS485_ENABLED) { + if (port->rs485.flags & SER_RS485_ENABLED) { if (up->scr & OMAP_UART_SCR_TX_EMPTY) { /* THR interrupt is fired when both TX FIFO and TX * shift register are empty. This means there's nothing @@ -313,10 +326,12 @@ static void serial_omap_stop_tx(struct uart_port *port) */ up->scr &= ~OMAP_UART_SCR_TX_EMPTY; serial_out(up, UART_OMAP_SCR, up->scr); - res = (up->rs485.flags & SER_RS485_RTS_AFTER_SEND) ? 1 : 0; + res = (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) ? + 1 : 0; if (gpio_get_value(up->rts_gpio) != res) { - if (up->rs485.delay_rts_after_send > 0) - mdelay(up->rs485.delay_rts_after_send); + if (port->rs485.delay_rts_after_send > 0) + mdelay( + port->rs485.delay_rts_after_send); gpio_set_value(up->rts_gpio, res); } } else { @@ -339,8 +354,8 @@ static void serial_omap_stop_tx(struct uart_port *port) serial_out(up, UART_IER, up->ier); } - if ((up->rs485.flags & SER_RS485_ENABLED) && - !(up->rs485.flags & SER_RS485_RX_DURING_TX)) { + if ((port->rs485.flags & SER_RS485_ENABLED) && + !(port->rs485.flags & SER_RS485_RX_DURING_TX)) { /* * Empty the RX FIFO, we are not interested in anything * received during the half-duplex transmission. @@ -415,22 +430,22 @@ static void serial_omap_start_tx(struct uart_port *port) pm_runtime_get_sync(up->dev); /* Handle RS-485 */ - if (up->rs485.flags & SER_RS485_ENABLED) { + if (port->rs485.flags & SER_RS485_ENABLED) { /* Fire THR interrupts when FIFO is below trigger level */ up->scr &= ~OMAP_UART_SCR_TX_EMPTY; serial_out(up, UART_OMAP_SCR, up->scr); /* if rts not already enabled */ - res = (up->rs485.flags & SER_RS485_RTS_ON_SEND) ? 1 : 0; + res = (port->rs485.flags & SER_RS485_RTS_ON_SEND) ? 1 : 0; if (gpio_get_value(up->rts_gpio) != res) { gpio_set_value(up->rts_gpio, res); - if (up->rs485.delay_rts_before_send > 0) - mdelay(up->rs485.delay_rts_before_send); + if (port->rs485.delay_rts_before_send > 0) + mdelay(port->rs485.delay_rts_before_send); } } - if ((up->rs485.flags & SER_RS485_ENABLED) && - !(up->rs485.flags & SER_RS485_RX_DURING_TX)) + if ((port->rs485.flags & SER_RS485_ENABLED) && + !(port->rs485.flags & SER_RS485_RX_DURING_TX)) serial_omap_stop_rx(port); serial_omap_enable_ier_thri(up); @@ -1341,16 +1356,14 @@ static inline void serial_omap_add_console_port(struct uart_omap_port *up) #endif /* Enable or disable the rs485 support */ -static void +static int serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) { struct uart_omap_port *up = to_uart_omap_port(port); - unsigned long flags; unsigned int mode; int val; pm_runtime_get_sync(up->dev); - spin_lock_irqsave(&up->port.lock, flags); /* Disable interrupts from this port */ mode = up->ier; @@ -1358,7 +1371,7 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) serial_out(up, UART_IER, 0); /* store new config */ - up->rs485 = *rs485conf; + port->rs485 = *rs485conf; /* * Just as a precaution, only allow rs485 @@ -1366,12 +1379,12 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) */ if (gpio_is_valid(up->rts_gpio)) { /* enable / disable rts */ - val = (up->rs485.flags & SER_RS485_ENABLED) ? + val = (port->rs485.flags & SER_RS485_ENABLED) ? SER_RS485_RTS_AFTER_SEND : SER_RS485_RTS_ON_SEND; - val = (up->rs485.flags & val) ? 1 : 0; + val = (port->rs485.flags & val) ? 1 : 0; gpio_set_value(up->rts_gpio, val); } else - up->rs485.flags &= ~SER_RS485_ENABLED; + port->rs485.flags &= ~SER_RS485_ENABLED; /* Enable interrupts */ up->ier = mode; @@ -1380,45 +1393,18 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) /* If RS-485 is disabled, make sure the THR interrupt is fired when * TX FIFO is below the trigger level. */ - if (!(up->rs485.flags & SER_RS485_ENABLED) && + if (!(port->rs485.flags & SER_RS485_ENABLED) && (up->scr & OMAP_UART_SCR_TX_EMPTY)) { up->scr &= ~OMAP_UART_SCR_TX_EMPTY; serial_out(up, UART_OMAP_SCR, up->scr); } - spin_unlock_irqrestore(&up->port.lock, flags); pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); -} -static int -serial_omap_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg) -{ - struct serial_rs485 rs485conf; - - switch (cmd) { - case TIOCSRS485: - if (copy_from_user(&rs485conf, (void __user *) arg, - sizeof(rs485conf))) - return -EFAULT; - - serial_omap_config_rs485(port, &rs485conf); - break; - - case TIOCGRS485: - if (copy_to_user((void __user *) arg, - &(to_uart_omap_port(port)->rs485), - sizeof(rs485conf))) - return -EFAULT; - break; - - default: - return -ENOIOCTLCMD; - } return 0; } - static struct uart_ops serial_omap_pops = { .tx_empty = serial_omap_tx_empty, .set_mctrl = serial_omap_set_mctrl, @@ -1439,7 +1425,6 @@ static struct uart_ops serial_omap_pops = { .request_port = serial_omap_request_port, .config_port = serial_omap_config_port, .verify_port = serial_omap_verify_port, - .ioctl = serial_omap_ioctl, #ifdef CONFIG_CONSOLE_POLL .poll_put_char = serial_omap_poll_put_char, .poll_get_char = serial_omap_poll_get_char, @@ -1573,7 +1558,7 @@ static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev) static int serial_omap_probe_rs485(struct uart_omap_port *up, struct device_node *np) { - struct serial_rs485 *rs485conf = &up->rs485; + struct serial_rs485 *rs485conf = &up->port.rs485; u32 rs485_delay[2]; enum of_gpio_flags flags; int ret; @@ -1668,14 +1653,21 @@ static int serial_omap_probe(struct platform_device *pdev) up->port.ops = &serial_omap_pops; if (pdev->dev.of_node) - up->port.line = of_alias_get_id(pdev->dev.of_node, "serial"); + ret = of_alias_get_id(pdev->dev.of_node, "serial"); else - up->port.line = pdev->id; + ret = pdev->id; - if (up->port.line < 0) { + if (ret < 0) { dev_err(&pdev->dev, "failed to get alias/pdev id, errno %d\n", - up->port.line); - ret = -ENODEV; + ret); + goto err_port_line; + } + up->port.line = ret; + + if (up->port.line >= OMAP_MAX_HSUART_PORTS) { + dev_err(&pdev->dev, "uart ID %d > MAX %d.\n", up->port.line, + OMAP_MAX_HSUART_PORTS); + ret = -ENXIO; goto err_port_line; } @@ -1688,6 +1680,7 @@ static int serial_omap_probe(struct platform_device *pdev) up->port.membase = base; up->port.flags = omap_up_info->flags; up->port.uartclk = omap_up_info->uartclk; + up->port.rs485_config = serial_omap_config_rs485; if (!up->port.uartclk) { up->port.uartclk = DEFAULT_CLK_SPEED; dev_warn(&pdev->dev, @@ -1733,8 +1726,6 @@ err_add_port: pm_runtime_disable(&pdev->dev); err_rs485: err_port_line: - dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n", - pdev->id, __func__, ret); return ret; } @@ -1785,7 +1776,7 @@ static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1) } } -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM static void serial_omap_restore_context(struct uart_omap_port *up) { if (up->errata & UART_ERRATA_i202_MDR1_ACCESS) diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index abbfedb84901..8f515799c9c1 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -1352,7 +1352,8 @@ static int pmz_verify_port(struct uart_port *port, struct serial_struct *ser) static int pmz_poll_get_char(struct uart_port *port) { - struct uart_pmac_port *uap = (struct uart_pmac_port *)port; + struct uart_pmac_port *uap = + container_of(port, struct uart_pmac_port, port); int tries = 2; while (tries) { @@ -1367,7 +1368,8 @@ static int pmz_poll_get_char(struct uart_port *port) static void pmz_poll_put_char(struct uart_port *port, unsigned char c) { - struct uart_pmac_port *uap = (struct uart_pmac_port *)port; + struct uart_pmac_port *uap = + container_of(port, struct uart_pmac_port, port); /* Wait for the transmit buffer to empty. */ while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0) @@ -1874,7 +1876,6 @@ static struct platform_driver pmz_driver = { .remove = __exit_p(pmz_detach), .driver = { .name = "scc", - .owner = THIS_MODULE, }, }; @@ -1954,7 +1955,8 @@ static void __exit exit_pmz(void) static void pmz_console_putchar(struct uart_port *port, int ch) { - struct uart_pmac_port *uap = (struct uart_pmac_port *)port; + struct uart_pmac_port *uap = + container_of(port, struct uart_pmac_port, port); /* Wait for the transmit buffer to empty. */ while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0) diff --git a/drivers/tty/serial/pnx8xxx_uart.c b/drivers/tty/serial/pnx8xxx_uart.c index 2ba24a45c97f..7a3bb9cf1f2e 100644 --- a/drivers/tty/serial/pnx8xxx_uart.c +++ b/drivers/tty/serial/pnx8xxx_uart.c @@ -126,7 +126,8 @@ static void pnx8xxx_timeout(unsigned long data) */ static void pnx8xxx_stop_tx(struct uart_port *port) { - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + struct pnx8xxx_port *sport = + container_of(port, struct pnx8xxx_port, port); u32 ien; /* Disable TX intr */ @@ -142,7 +143,8 @@ static void pnx8xxx_stop_tx(struct uart_port *port) */ static void pnx8xxx_start_tx(struct uart_port *port) { - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + struct pnx8xxx_port *sport = + container_of(port, struct pnx8xxx_port, port); u32 ien; /* Clear all pending TX intr */ @@ -158,7 +160,8 @@ static void pnx8xxx_start_tx(struct uart_port *port) */ static void pnx8xxx_stop_rx(struct uart_port *port) { - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + struct pnx8xxx_port *sport = + container_of(port, struct pnx8xxx_port, port); u32 ien; /* Disable RX intr */ @@ -174,7 +177,8 @@ static void pnx8xxx_stop_rx(struct uart_port *port) */ static void pnx8xxx_enable_ms(struct uart_port *port) { - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + struct pnx8xxx_port *sport = + container_of(port, struct pnx8xxx_port, port); mod_timer(&sport->timer, jiffies); } @@ -313,14 +317,16 @@ static irqreturn_t pnx8xxx_int(int irq, void *dev_id) */ static unsigned int pnx8xxx_tx_empty(struct uart_port *port) { - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + struct pnx8xxx_port *sport = + container_of(port, struct pnx8xxx_port, port); return serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA ? 0 : TIOCSER_TEMT; } static unsigned int pnx8xxx_get_mctrl(struct uart_port *port) { - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + struct pnx8xxx_port *sport = + container_of(port, struct pnx8xxx_port, port); unsigned int mctrl = TIOCM_DSR; unsigned int msr; @@ -347,7 +353,8 @@ static void pnx8xxx_set_mctrl(struct uart_port *port, unsigned int mctrl) */ static void pnx8xxx_break_ctl(struct uart_port *port, int break_state) { - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + struct pnx8xxx_port *sport = + container_of(port, struct pnx8xxx_port, port); unsigned long flags; unsigned int lcr; @@ -363,7 +370,8 @@ static void pnx8xxx_break_ctl(struct uart_port *port, int break_state) static int pnx8xxx_startup(struct uart_port *port) { - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + struct pnx8xxx_port *sport = + container_of(port, struct pnx8xxx_port, port); int retval; /* @@ -397,7 +405,8 @@ static int pnx8xxx_startup(struct uart_port *port) static void pnx8xxx_shutdown(struct uart_port *port) { - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + struct pnx8xxx_port *sport = + container_of(port, struct pnx8xxx_port, port); int lcr; /* @@ -434,7 +443,8 @@ static void pnx8xxx_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + struct pnx8xxx_port *sport = + container_of(port, struct pnx8xxx_port, port); unsigned long flags; unsigned int lcr_fcr, old_ien, baud, quot; unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; @@ -551,7 +561,8 @@ pnx8xxx_set_termios(struct uart_port *port, struct ktermios *termios, static const char *pnx8xxx_type(struct uart_port *port) { - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + struct pnx8xxx_port *sport = + container_of(port, struct pnx8xxx_port, port); return sport->port.type == PORT_PNX8XXX ? "PNX8XXX" : NULL; } @@ -561,7 +572,8 @@ static const char *pnx8xxx_type(struct uart_port *port) */ static void pnx8xxx_release_port(struct uart_port *port) { - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + struct pnx8xxx_port *sport = + container_of(port, struct pnx8xxx_port, port); release_mem_region(sport->port.mapbase, UART_PORT_SIZE); } @@ -571,7 +583,8 @@ static void pnx8xxx_release_port(struct uart_port *port) */ static int pnx8xxx_request_port(struct uart_port *port) { - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + struct pnx8xxx_port *sport = + container_of(port, struct pnx8xxx_port, port); return request_mem_region(sport->port.mapbase, UART_PORT_SIZE, "pnx8xxx-uart") != NULL ? 0 : -EBUSY; } @@ -581,7 +594,8 @@ static int pnx8xxx_request_port(struct uart_port *port) */ static void pnx8xxx_config_port(struct uart_port *port, int flags) { - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + struct pnx8xxx_port *sport = + container_of(port, struct pnx8xxx_port, port); if (flags & UART_CONFIG_TYPE && pnx8xxx_request_port(&sport->port) == 0) @@ -596,7 +610,8 @@ static void pnx8xxx_config_port(struct uart_port *port, int flags) static int pnx8xxx_verify_port(struct uart_port *port, struct serial_struct *ser) { - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + struct pnx8xxx_port *sport = + container_of(port, struct pnx8xxx_port, port); int ret = 0; if (ser->type != PORT_UNKNOWN && ser->type != PORT_PNX8XXX) @@ -662,7 +677,8 @@ static void __init pnx8xxx_init_ports(void) static void pnx8xxx_console_putchar(struct uart_port *port, int ch) { - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + struct pnx8xxx_port *sport = + container_of(port, struct pnx8xxx_port, port); int status; do { @@ -813,7 +829,6 @@ static int pnx8xxx_serial_remove(struct platform_device *pdev) static struct platform_driver pnx8xxx_serial_driver = { .driver = { .name = "pnx8xxx-uart", - .owner = THIS_MODULE, }, .probe = pnx8xxx_serial_probe, .remove = pnx8xxx_serial_remove, diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index 21b7d8b86493..d5d062694bd3 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -223,6 +223,7 @@ static void serial_pxa_start_tx(struct uart_port *port) } } +/* should hold up->port.lock */ static inline void check_modem_status(struct uart_pxa_port *up) { int status; @@ -255,12 +256,14 @@ static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id) iir = serial_in(up, UART_IIR); if (iir & UART_IIR_NO_INT) return IRQ_NONE; + spin_lock(&up->port.lock); lsr = serial_in(up, UART_LSR); if (lsr & UART_LSR_DR) receive_chars(up, &lsr); check_modem_status(up); if (lsr & UART_LSR_THRE) transmit_chars(up); + spin_unlock(&up->port.lock); return IRQ_HANDLED; } @@ -930,7 +933,6 @@ static struct platform_driver serial_pxa_driver = { .driver = { .name = "pxa2xx-uart", - .owner = THIS_MODULE, #ifdef CONFIG_PM .pm = &serial_pxa_pm_ops, #endif diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c index 753d4525b367..fd3d1329d48c 100644 --- a/drivers/tty/serial/sa1100.c +++ b/drivers/tty/serial/sa1100.c @@ -142,7 +142,8 @@ static void sa1100_timeout(unsigned long data) */ static void sa1100_stop_tx(struct uart_port *port) { - struct sa1100_port *sport = (struct sa1100_port *)port; + struct sa1100_port *sport = + container_of(port, struct sa1100_port, port); u32 utcr3; utcr3 = UART_GET_UTCR3(sport); @@ -155,7 +156,8 @@ static void sa1100_stop_tx(struct uart_port *port) */ static void sa1100_start_tx(struct uart_port *port) { - struct sa1100_port *sport = (struct sa1100_port *)port; + struct sa1100_port *sport = + container_of(port, struct sa1100_port, port); u32 utcr3; utcr3 = UART_GET_UTCR3(sport); @@ -168,7 +170,8 @@ static void sa1100_start_tx(struct uart_port *port) */ static void sa1100_stop_rx(struct uart_port *port) { - struct sa1100_port *sport = (struct sa1100_port *)port; + struct sa1100_port *sport = + container_of(port, struct sa1100_port, port); u32 utcr3; utcr3 = UART_GET_UTCR3(sport); @@ -180,7 +183,8 @@ static void sa1100_stop_rx(struct uart_port *port) */ static void sa1100_enable_ms(struct uart_port *port) { - struct sa1100_port *sport = (struct sa1100_port *)port; + struct sa1100_port *sport = + container_of(port, struct sa1100_port, port); mod_timer(&sport->timer, jiffies); } @@ -323,7 +327,8 @@ static irqreturn_t sa1100_int(int irq, void *dev_id) */ static unsigned int sa1100_tx_empty(struct uart_port *port) { - struct sa1100_port *sport = (struct sa1100_port *)port; + struct sa1100_port *sport = + container_of(port, struct sa1100_port, port); return UART_GET_UTSR1(sport) & UTSR1_TBY ? 0 : TIOCSER_TEMT; } @@ -342,7 +347,8 @@ static void sa1100_set_mctrl(struct uart_port *port, unsigned int mctrl) */ static void sa1100_break_ctl(struct uart_port *port, int break_state) { - struct sa1100_port *sport = (struct sa1100_port *)port; + struct sa1100_port *sport = + container_of(port, struct sa1100_port, port); unsigned long flags; unsigned int utcr3; @@ -358,7 +364,8 @@ static void sa1100_break_ctl(struct uart_port *port, int break_state) static int sa1100_startup(struct uart_port *port) { - struct sa1100_port *sport = (struct sa1100_port *)port; + struct sa1100_port *sport = + container_of(port, struct sa1100_port, port); int retval; /* @@ -387,7 +394,8 @@ static int sa1100_startup(struct uart_port *port) static void sa1100_shutdown(struct uart_port *port) { - struct sa1100_port *sport = (struct sa1100_port *)port; + struct sa1100_port *sport = + container_of(port, struct sa1100_port, port); /* * Stop our timer. @@ -409,7 +417,8 @@ static void sa1100_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - struct sa1100_port *sport = (struct sa1100_port *)port; + struct sa1100_port *sport = + container_of(port, struct sa1100_port, port); unsigned long flags; unsigned int utcr0, old_utcr3, baud, quot; unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; @@ -512,7 +521,8 @@ sa1100_set_termios(struct uart_port *port, struct ktermios *termios, static const char *sa1100_type(struct uart_port *port) { - struct sa1100_port *sport = (struct sa1100_port *)port; + struct sa1100_port *sport = + container_of(port, struct sa1100_port, port); return sport->port.type == PORT_SA1100 ? "SA1100" : NULL; } @@ -522,7 +532,8 @@ static const char *sa1100_type(struct uart_port *port) */ static void sa1100_release_port(struct uart_port *port) { - struct sa1100_port *sport = (struct sa1100_port *)port; + struct sa1100_port *sport = + container_of(port, struct sa1100_port, port); release_mem_region(sport->port.mapbase, UART_PORT_SIZE); } @@ -532,7 +543,8 @@ static void sa1100_release_port(struct uart_port *port) */ static int sa1100_request_port(struct uart_port *port) { - struct sa1100_port *sport = (struct sa1100_port *)port; + struct sa1100_port *sport = + container_of(port, struct sa1100_port, port); return request_mem_region(sport->port.mapbase, UART_PORT_SIZE, "sa11x0-uart") != NULL ? 0 : -EBUSY; @@ -543,7 +555,8 @@ static int sa1100_request_port(struct uart_port *port) */ static void sa1100_config_port(struct uart_port *port, int flags) { - struct sa1100_port *sport = (struct sa1100_port *)port; + struct sa1100_port *sport = + container_of(port, struct sa1100_port, port); if (flags & UART_CONFIG_TYPE && sa1100_request_port(&sport->port) == 0) @@ -558,7 +571,8 @@ static void sa1100_config_port(struct uart_port *port, int flags) static int sa1100_verify_port(struct uart_port *port, struct serial_struct *ser) { - struct sa1100_port *sport = (struct sa1100_port *)port; + struct sa1100_port *sport = + container_of(port, struct sa1100_port, port); int ret = 0; if (ser->type != PORT_UNKNOWN && ser->type != PORT_SA1100) @@ -691,7 +705,8 @@ void __init sa1100_register_uart(int idx, int port) #ifdef CONFIG_SERIAL_SA1100_CONSOLE static void sa1100_console_putchar(struct uart_port *port, int ch) { - struct sa1100_port *sport = (struct sa1100_port *)port; + struct sa1100_port *sport = + container_of(port, struct sa1100_port, port); while (!(UART_GET_UTSR1(sport) & UTSR1_TNF)) barrier(); @@ -883,7 +898,6 @@ static struct platform_driver sa11x0_serial_driver = { .resume = sa1100_serial_resume, .driver = { .name = "sa11x0-uart", - .owner = THIS_MODULE, }, }; diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index c78f43a481ce..19273e31d224 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -199,12 +199,14 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port) } } -static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port) +static inline struct s3c24xx_uart_info + *s3c24xx_port_to_info(struct uart_port *port) { return to_ourport(port)->info; } -static inline struct s3c2410_uartcfg *s3c24xx_port_to_cfg(struct uart_port *port) +static inline struct s3c2410_uartcfg + *s3c24xx_port_to_cfg(struct uart_port *port) { struct s3c24xx_uart_port *ourport; @@ -237,7 +239,7 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id) struct uart_port *port = &ourport->port; unsigned int ufcon, ch, flag, ufstat, uerstat; unsigned long flags; - int max_count = 64; + int max_count = port->fifosize; spin_lock_irqsave(&port->lock, flags); @@ -311,14 +313,14 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id) uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN, ch, flag); - ignore_char: +ignore_char: continue; } spin_unlock_irqrestore(&port->lock, flags); tty_flip_buffer_push(&port->state->port); - out: +out: return IRQ_HANDLED; } @@ -328,7 +330,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) struct uart_port *port = &ourport->port; struct circ_buf *xmit = &port->state->xmit; unsigned long flags; - int count = 256; + int count = port->fifosize; spin_lock_irqsave(&port->lock, flags); @@ -368,7 +370,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) if (uart_circ_empty(xmit)) s3c24xx_serial_stop_tx(port); - out: +out: spin_unlock_irqrestore(&port->lock, flags); return IRQ_HANDLED; } @@ -519,7 +521,7 @@ static int s3c24xx_serial_startup(struct uart_port *port) return ret; - err: +err: s3c24xx_serial_shutdown(port); return ret; } @@ -559,11 +561,15 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, unsigned int old) { struct s3c24xx_uart_port *ourport = to_ourport(port); + int timeout = 10000; ourport->pm_level = level; switch (level) { case 3: + while (--timeout && !s3c24xx_serial_txempty_nofifo(port)) + udelay(100); + if (!IS_ERR(ourport->baudclk)) clk_disable_unprepare(ourport->baudclk); @@ -841,8 +847,8 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, */ port->read_status_mask = S3C2410_UERSTAT_OVERRUN; if (termios->c_iflag & INPCK) - port->read_status_mask |= S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_PARITY; - + port->read_status_mask |= S3C2410_UERSTAT_FRAME | + S3C2410_UERSTAT_PARITY; /* * Which character status flags should we ignore? */ @@ -969,10 +975,13 @@ static struct uart_driver s3c24xx_uart_drv = { .minor = S3C24XX_SERIAL_MINOR, }; -static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = { +#define __PORT_LOCK_UNLOCKED(i) \ + __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[i].port.lock) +static struct s3c24xx_uart_port +s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = { [0] = { .port = { - .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock), + .lock = __PORT_LOCK_UNLOCKED(0), .iotype = UPIO_MEM, .uartclk = 0, .fifosize = 16, @@ -983,7 +992,7 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS }, [1] = { .port = { - .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock), + .lock = __PORT_LOCK_UNLOCKED(1), .iotype = UPIO_MEM, .uartclk = 0, .fifosize = 16, @@ -996,7 +1005,7 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS [2] = { .port = { - .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock), + .lock = __PORT_LOCK_UNLOCKED(2), .iotype = UPIO_MEM, .uartclk = 0, .fifosize = 16, @@ -1009,7 +1018,7 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS #if CONFIG_SERIAL_SAMSUNG_UARTS > 3 [3] = { .port = { - .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock), + .lock = __PORT_LOCK_UNLOCKED(3), .iotype = UPIO_MEM, .uartclk = 0, .fifosize = 16, @@ -1020,6 +1029,7 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS } #endif }; +#undef __PORT_LOCK_UNLOCKED /* s3c24xx_serial_resetport * @@ -1102,11 +1112,12 @@ static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb, s3c24xx_serial_set_termios(uport, termios, NULL); } - exit: +exit: return 0; } -static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port) +static inline int +s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port) { port->freq_transition.notifier_call = s3c24xx_serial_cpufreq_transition; @@ -1114,19 +1125,22 @@ static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port CPUFREQ_TRANSITION_NOTIFIER); } -static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port) +static inline void +s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port) { cpufreq_unregister_notifier(&port->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); } #else -static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port) +static inline int +s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port) { return 0; } -static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port) +static inline void +s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port) { } #endif @@ -1226,24 +1240,6 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, return 0; } -#ifdef CONFIG_SAMSUNG_CLOCK -static ssize_t s3c24xx_serial_show_clksrc(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct uart_port *port = s3c24xx_dev_to_port(dev); - struct s3c24xx_uart_port *ourport = to_ourport(port); - - 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); -#endif - /* Device driver serial port probe */ static const struct of_device_id s3c24xx_uart_dt_match[]; @@ -1296,11 +1292,10 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) of_property_read_u32(np, "samsung,uart-fifosize", &ourport->port.fifosize); - if (!ourport->port.fifosize) { - ourport->port.fifosize = (ourport->info->fifosize) ? - ourport->info->fifosize : - ourport->drv_data->fifosize[index]; - } + if (ourport->drv_data->fifosize[index]) + ourport->port.fifosize = ourport->drv_data->fifosize[index]; + else if (ourport->info->fifosize) + ourport->port.fifosize = ourport->info->fifosize; probe_index++; @@ -1329,12 +1324,6 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) */ clk_disable_unprepare(ourport->clk); -#ifdef CONFIG_SAMSUNG_CLOCK - ret = device_create_file(&pdev->dev, &dev_attr_clock_source); - if (ret < 0) - dev_err(&pdev->dev, "failed to add clock source attr.\n"); -#endif - ret = s3c24xx_serial_cpufreq_register(ourport); if (ret < 0) dev_err(&pdev->dev, "failed to add cpufreq notifier\n"); @@ -1348,9 +1337,6 @@ static int s3c24xx_serial_remove(struct platform_device *dev) if (port) { s3c24xx_serial_cpufreq_deregister(to_ourport(port)); -#ifdef CONFIG_SAMSUNG_CLOCK - device_remove_file(&dev->dev, &dev_attr_clock_source); -#endif uart_remove_one_port(&s3c24xx_uart_drv, port); } @@ -1848,7 +1834,6 @@ static struct platform_driver samsung_serial_driver = { .id_table = s3c24xx_serial_driver_ids, .driver = { .name = "samsung-uart", - .owner = THIS_MODULE, .pm = SERIAL_SAMSUNG_PM_OPS, .of_match_table = of_match_ptr(s3c24xx_uart_dt_match), }, diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 3284c31085a7..df9a384dfbda 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -304,8 +304,6 @@ struct sc16is7xx_one { struct uart_port port; struct work_struct tx_work; struct work_struct md_work; - - struct serial_rs485 rs485; }; struct sc16is7xx_port { @@ -657,15 +655,15 @@ static void sc16is7xx_stop_tx(struct uart_port* port) struct circ_buf *xmit = &one->port.state->xmit; /* handle rs485 */ - if (one->rs485.flags & SER_RS485_ENABLED) { + if (port->rs485.flags & SER_RS485_ENABLED) { /* do nothing if current tx not yet completed */ int lsr = sc16is7xx_port_read(port, SC16IS7XX_LSR_REG); if (!(lsr & SC16IS7XX_LSR_TEMT_BIT)) return; if (uart_circ_empty(xmit) && - (one->rs485.delay_rts_after_send > 0)) - mdelay(one->rs485.delay_rts_after_send); + (port->rs485.delay_rts_after_send > 0)) + mdelay(port->rs485.delay_rts_after_send); } sc16is7xx_port_update(port, SC16IS7XX_IER_REG, @@ -688,9 +686,9 @@ static void sc16is7xx_start_tx(struct uart_port *port) struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); /* handle rs485 */ - if ((one->rs485.flags & SER_RS485_ENABLED) && - (one->rs485.delay_rts_before_send > 0)) { - mdelay(one->rs485.delay_rts_before_send); + if ((port->rs485.flags & SER_RS485_ENABLED) && + (port->rs485.delay_rts_before_send > 0)) { + mdelay(port->rs485.delay_rts_before_send); } if (!work_pending(&one->tx_work)) @@ -830,51 +828,20 @@ static void sc16is7xx_set_termios(struct uart_port *port, uart_update_timeout(port, termios->c_cflag, baud); } -#if defined(TIOCSRS485) && defined(TIOCGRS485) -static void sc16is7xx_config_rs485(struct uart_port *port, +static int sc16is7xx_config_rs485(struct uart_port *port, struct serial_rs485 *rs485) { - struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); - - one->rs485 = *rs485; - - if (one->rs485.flags & SER_RS485_ENABLED) { + if (port->rs485.flags & SER_RS485_ENABLED) sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, SC16IS7XX_EFCR_AUTO_RS485_BIT, SC16IS7XX_EFCR_AUTO_RS485_BIT); - } else { + else sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, SC16IS7XX_EFCR_AUTO_RS485_BIT, 0); - } -} -#endif - -static int sc16is7xx_ioctl(struct uart_port *port, unsigned int cmd, - unsigned long arg) -{ -#if defined(TIOCSRS485) && defined(TIOCGRS485) - struct serial_rs485 rs485; - - switch (cmd) { - case TIOCSRS485: - if (copy_from_user(&rs485, (void __user *)arg, sizeof(rs485))) - return -EFAULT; - - sc16is7xx_config_rs485(port, &rs485); - return 0; - case TIOCGRS485: - if (copy_to_user((void __user *)arg, - &(to_sc16is7xx_one(port, port)->rs485), - sizeof(rs485))) - return -EFAULT; - return 0; - default: - break; - } -#endif + port->rs485 = *rs485; - return -ENOIOCTLCMD; + return 0; } static int sc16is7xx_startup(struct uart_port *port) @@ -1000,7 +967,6 @@ static const struct uart_ops sc16is7xx_ops = { .release_port = sc16is7xx_null_void, .config_port = sc16is7xx_config_port, .verify_port = sc16is7xx_verify_port, - .ioctl = sc16is7xx_ioctl, .pm = sc16is7xx_pm, }; @@ -1130,6 +1096,7 @@ static int sc16is7xx_probe(struct device *dev, s->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY; s->p[i].port.iotype = UPIO_PORT; s->p[i].port.uartclk = freq; + s->p[i].port.rs485_config = sc16is7xx_config_rs485; s->p[i].port.ops = &sc16is7xx_ops; /* Disable all interrupts */ sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_IER_REG, 0); @@ -1157,7 +1124,7 @@ static int sc16is7xx_probe(struct device *dev, #ifdef CONFIG_GPIOLIB if (devtype->nr_gpio) - WARN_ON(gpiochip_remove(&s->gpio)); + gpiochip_remove(&s->gpio); out_uart: #endif @@ -1173,14 +1140,11 @@ out_clk: static int sc16is7xx_remove(struct device *dev) { struct sc16is7xx_port *s = dev_get_drvdata(dev); - int i, ret = 0; + int i; #ifdef CONFIG_GPIOLIB - if (s->devtype->nr_gpio) { - ret = gpiochip_remove(&s->gpio); - if (ret) - return ret; - } + if (s->devtype->nr_gpio) + gpiochip_remove(&s->gpio); #endif for (i = 0; i < s->uart.nr; i++) { @@ -1195,7 +1159,7 @@ static int sc16is7xx_remove(struct device *dev) if (!IS_ERR(s->clk)) clk_disable_unprepare(s->clk); - return ret; + return 0; } static const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = { diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index 75850f70b479..fcf803ffad19 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -1012,7 +1012,6 @@ static int sccnxp_remove(struct platform_device *pdev) static struct platform_driver sccnxp_uart_driver = { .driver = { .name = SCCNXP_NAME, - .owner = THIS_MODULE, }, .probe = sccnxp_probe, .remove = sccnxp_remove, diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index 53d7c31ce098..48e6e41636b2 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -319,16 +319,16 @@ static char tegra_uart_decode_rx_error(struct tegra_uart_port *tup, if (unlikely(lsr & TEGRA_UART_LSR_ANY)) { if (lsr & UART_LSR_OE) { /* Overrrun error */ - flag |= TTY_OVERRUN; + flag = TTY_OVERRUN; tup->uport.icount.overrun++; dev_err(tup->uport.dev, "Got overrun errors\n"); } else if (lsr & UART_LSR_PE) { /* Parity error */ - flag |= TTY_PARITY; + flag = TTY_PARITY; tup->uport.icount.parity++; dev_err(tup->uport.dev, "Got Parity errors\n"); } else if (lsr & UART_LSR_FE) { - flag |= TTY_FRAME; + flag = TTY_FRAME; tup->uport.icount.frame++; dev_err(tup->uport.dev, "Got frame errors\n"); } else if (lsr & UART_LSR_BI) { @@ -1034,6 +1034,20 @@ fail_rx_dma: return ret; } +/* + * Flush any TX data submitted for DMA and PIO. Called when the + * TX circular buffer is reset. + */ +static void tegra_uart_flush_buffer(struct uart_port *u) +{ + struct tegra_uart_port *tup = to_tegra_uport(u); + + tup->tx_bytes = 0; + if (tup->tx_dma_chan) + dmaengine_terminate_all(tup->tx_dma_chan); + return; +} + static void tegra_uart_shutdown(struct uart_port *u) { struct tegra_uart_port *tup = to_tegra_uport(u); @@ -1046,6 +1060,8 @@ static void tegra_uart_shutdown(struct uart_port *u) tegra_uart_dma_channel_free(tup, true); tegra_uart_dma_channel_free(tup, false); free_irq(u->irq, tup); + + tegra_uart_flush_buffer(u); } static void tegra_uart_enable_ms(struct uart_port *u) @@ -1174,20 +1190,6 @@ static void tegra_uart_set_termios(struct uart_port *u, return; } -/* - * Flush any TX data submitted for DMA and PIO. Called when the - * TX circular buffer is reset. - */ -static void tegra_uart_flush_buffer(struct uart_port *u) -{ - struct tegra_uart_port *tup = to_tegra_uport(u); - - tup->tx_bytes = 0; - if (tup->tx_dma_chan) - dmaengine_terminate_all(tup->tx_dma_chan); - return; -} - static const char *tegra_uart_type(struct uart_port *u) { return TEGRA_UART_TYPE; diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 29a7be47389a..57ca61b14670 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -59,6 +59,11 @@ static void uart_change_pm(struct uart_state *state, static void uart_port_shutdown(struct tty_port *port); +static int uart_dcd_enabled(struct uart_port *uport) +{ + return !!(uport->status & UPSTAT_DCD_ENABLE); +} + /* * This routine is used by the interrupt handler to schedule processing in * the software interrupt portion of the driver. @@ -90,7 +95,7 @@ static void __uart_start(struct tty_struct *tty) struct uart_state *state = tty->driver_data; struct uart_port *port = state->uart_port; - if (!tty->stopped && !tty->hw_stopped) + if (!uart_tx_stopped(port)) port->ops->start_tx(port); } @@ -130,7 +135,6 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, int init_hw) { struct uart_port *uport = state->uart_port; - struct tty_port *port = &state->port; unsigned long page; int retval = 0; @@ -175,17 +179,14 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, if (tty->termios.c_cflag & CBAUD) uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR); } - /* - * if hw support flow control without software intervention, - * then skip the below check - */ - if (tty_port_cts_enabled(port) && - !(uport->flags & UPF_HARD_FLOW)) { - spin_lock_irq(&uport->lock); - if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) - tty->hw_stopped = 1; - spin_unlock_irq(&uport->lock); - } + + spin_lock_irq(&uport->lock); + if (uart_cts_enabled(uport) && + !(uport->ops->get_mctrl(uport) & TIOCM_CTS)) + uport->hw_stopped = 1; + else + uport->hw_stopped = 0; + spin_unlock_irq(&uport->lock); } /* @@ -362,7 +363,7 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, * The spd_hi, spd_vhi, spd_shi, spd_warp kludge... * Die! Die! Die! */ - if (baud == 38400) + if (try == 0 && baud == 38400) baud = altbaud; /* @@ -435,11 +436,10 @@ uart_get_divisor(struct uart_port *port, unsigned int baud) EXPORT_SYMBOL(uart_get_divisor); -/* FIXME: Consistent locking policy */ +/* Caller holds port mutex */ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, struct ktermios *old_termios) { - struct tty_port *port = &state->port; struct uart_port *uport = state->uart_port; struct ktermios *termios; @@ -454,17 +454,19 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, uport->ops->set_termios(uport, termios, old_termios); /* - * Set flags based on termios cflag + * Set modem status enables based on termios cflag */ + spin_lock_irq(&uport->lock); if (termios->c_cflag & CRTSCTS) - set_bit(ASYNCB_CTS_FLOW, &port->flags); + uport->status |= UPSTAT_CTS_ENABLE; else - clear_bit(ASYNCB_CTS_FLOW, &port->flags); + uport->status &= ~UPSTAT_CTS_ENABLE; if (termios->c_cflag & CLOCAL) - clear_bit(ASYNCB_CHECK_CD, &port->flags); + uport->status &= ~UPSTAT_DCD_ENABLE; else - set_bit(ASYNCB_CHECK_CD, &port->flags); + uport->status |= UPSTAT_DCD_ENABLE; + spin_unlock_irq(&uport->lock); } static inline int __uart_put_char(struct uart_port *port, @@ -535,9 +537,10 @@ static int uart_write(struct tty_struct *tty, count -= c; ret += c; } + + __uart_start(tty); spin_unlock_irqrestore(&port->lock, flags); - uart_start(tty); return ret; } @@ -604,12 +607,11 @@ static void uart_send_xchar(struct tty_struct *tty, char ch) if (port->ops->send_xchar) port->ops->send_xchar(port, ch); else { + spin_lock_irqsave(&port->lock, flags); port->x_char = ch; - if (ch) { - spin_lock_irqsave(&port->lock, flags); + if (ch) port->ops->start_tx(port); - spin_unlock_irqrestore(&port->lock, flags); - } + spin_unlock_irqrestore(&port->lock, flags); } } @@ -617,7 +619,7 @@ static void uart_throttle(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; struct uart_port *port = state->uart_port; - uint32_t mask = 0; + upf_t mask = 0; if (I_IXOFF(tty)) mask |= UPF_SOFT_FLOW; @@ -640,7 +642,7 @@ static void uart_unthrottle(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; struct uart_port *port = state->uart_port; - uint32_t mask = 0; + upf_t mask = 0; if (I_IXOFF(tty)) mask |= UPF_SOFT_FLOW; @@ -652,12 +654,8 @@ static void uart_unthrottle(struct tty_struct *tty) mask &= ~port->flags; } - if (mask & UPF_SOFT_FLOW) { - if (port->x_char) - port->x_char = 0; - else - uart_send_xchar(tty, START_CHAR(tty)); - } + if (mask & UPF_SOFT_FLOW) + uart_send_xchar(tty, START_CHAR(tty)); if (mask & UPF_HARD_FLOW) uart_set_mctrl(port, TIOCM_RTS); @@ -892,10 +890,11 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, */ if (uport->flags & UPF_SPD_MASK) { char buf[64]; - printk(KERN_NOTICE - "%s sets custom speed on %s. This " - "is deprecated.\n", current->comm, - tty_name(port->tty, buf)); + + dev_notice(uport->dev, + "%s sets custom speed on %s. This is deprecated.\n", + current->comm, + tty_name(port->tty, buf)); } uart_change_speed(tty, state, NULL); } @@ -952,7 +951,7 @@ static int uart_get_lsr_info(struct tty_struct *tty, */ if (uport->x_char || ((uart_circ_chars_pending(&state->xmit) > 0) && - !tty->stopped && !tty->hw_stopped)) + !uart_tx_stopped(uport))) result &= ~TIOCSER_TEMT; return put_user(result, value); @@ -1153,6 +1152,47 @@ static int uart_get_icount(struct tty_struct *tty, return 0; } +static int uart_get_rs485_config(struct uart_port *port, + struct serial_rs485 __user *rs485) +{ + unsigned long flags; + struct serial_rs485 aux; + + spin_lock_irqsave(&port->lock, flags); + aux = port->rs485; + spin_unlock_irqrestore(&port->lock, flags); + + if (copy_to_user(rs485, &aux, sizeof(aux))) + return -EFAULT; + + return 0; +} + +static int uart_set_rs485_config(struct uart_port *port, + struct serial_rs485 __user *rs485_user) +{ + struct serial_rs485 rs485; + int ret; + unsigned long flags; + + if (!port->rs485_config) + return -ENOIOCTLCMD; + + if (copy_from_user(&rs485, rs485_user, sizeof(*rs485_user))) + return -EFAULT; + + spin_lock_irqsave(&port->lock, flags); + ret = port->rs485_config(port, &rs485); + spin_unlock_irqrestore(&port->lock, flags); + if (ret) + return ret; + + if (copy_to_user(rs485_user, &port->rs485, sizeof(port->rs485))) + return -EFAULT; + + return 0; +} + /* * Called via sys_ioctl. We can use spin_lock_irq() here. */ @@ -1175,11 +1215,15 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, break; case TIOCSSERIAL: + down_write(&tty->termios_rwsem); ret = uart_set_info_user(tty, state, uarg); + up_write(&tty->termios_rwsem); break; case TIOCSERCONFIG: + down_write(&tty->termios_rwsem); ret = uart_do_autoconfig(tty, state); + up_write(&tty->termios_rwsem); break; case TIOCSERGWILD: /* obsolete */ @@ -1219,11 +1263,19 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, * All these rely on hardware being present and need to be * protected against the tty being hung up. */ + switch (cmd) { case TIOCSERGETLSR: /* Get line status register */ ret = uart_get_lsr_info(tty, state, uarg); break; + case TIOCGRS485: + ret = uart_get_rs485_config(state->uart_port, uarg); + break; + + case TIOCSRS485: + ret = uart_set_rs485_config(state->uart_port, uarg); + break; default: { struct uart_port *uport = state->uart_port; if (uport->ops->ioctl) @@ -1242,8 +1294,11 @@ static void uart_set_ldisc(struct tty_struct *tty) struct uart_state *state = tty->driver_data; struct uart_port *uport = state->uart_port; - if (uport->ops->set_ldisc) - uport->ops->set_ldisc(uport, tty->termios.c_line); + if (uport->ops->set_ldisc) { + mutex_lock(&state->port.mutex); + uport->ops->set_ldisc(uport, &tty->termios); + mutex_unlock(&state->port.mutex); + } } static void uart_set_termios(struct tty_struct *tty, @@ -1251,7 +1306,6 @@ static void uart_set_termios(struct tty_struct *tty, { struct uart_state *state = tty->driver_data; struct uart_port *uport = state->uart_port; - unsigned long flags; unsigned int cflag = tty->termios.c_cflag; unsigned int iflag_mask = IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK; bool sw_changed = false; @@ -1281,7 +1335,9 @@ static void uart_set_termios(struct tty_struct *tty, return; } + mutex_lock(&state->port.mutex); uart_change_speed(tty, state, old_termios); + mutex_unlock(&state->port.mutex); /* reload cflag from termios; port driver may have overriden flags */ cflag = tty->termios.c_cflag; @@ -1291,34 +1347,33 @@ static void uart_set_termios(struct tty_struct *tty, /* Handle transition away from B0 status */ else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { unsigned int mask = TIOCM_DTR; - if (!(cflag & CRTSCTS) || - !test_bit(TTY_THROTTLED, &tty->flags)) + if (!(cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) mask |= TIOCM_RTS; uart_set_mctrl(uport, mask); } /* * If the port is doing h/w assisted flow control, do nothing. - * We assume that tty->hw_stopped has never been set. + * We assume that port->hw_stopped has never been set. */ if (uport->flags & UPF_HARD_FLOW) return; /* Handle turning off CRTSCTS */ if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) { - spin_lock_irqsave(&uport->lock, flags); - tty->hw_stopped = 0; + spin_lock_irq(&uport->lock); + uport->hw_stopped = 0; __uart_start(tty); - spin_unlock_irqrestore(&uport->lock, flags); + spin_unlock_irq(&uport->lock); } /* Handle turning on CRTSCTS */ else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) { - spin_lock_irqsave(&uport->lock, flags); + spin_lock_irq(&uport->lock); if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) { - tty->hw_stopped = 1; + uport->hw_stopped = 1; uport->ops->stop_tx(uport); } - spin_unlock_irqrestore(&uport->lock, flags); + spin_unlock_irq(&uport->lock); } } @@ -1335,8 +1390,16 @@ static void uart_close(struct tty_struct *tty, struct file *filp) struct uart_port *uport; unsigned long flags; - if (!state) + if (!state) { + struct uart_driver *drv = tty->driver->driver_state; + + state = drv->state + tty->index; + port = &state->port; + spin_lock_irq(&port->lock); + --port->count; + spin_unlock_irq(&port->lock); return; + } uport = state->uart_port; port = &state->port; @@ -1365,10 +1428,6 @@ static void uart_close(struct tty_struct *tty, struct file *filp) mutex_lock(&port->mutex); uart_shutdown(tty, state); - uart_flush_buffer(tty); - - tty_ldisc_flush(tty); - tty_port_tty_set(port, NULL); tty->closing = 0; spin_lock_irqsave(&port->lock, flags); @@ -1376,8 +1435,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp) if (port->blocked_open) { spin_unlock_irqrestore(&port->lock, flags); if (port->close_delay) - msleep_interruptible( - jiffies_to_msecs(port->close_delay)); + msleep_interruptible(jiffies_to_msecs(port->close_delay)); spin_lock_irqsave(&port->lock, flags); } else if (!uart_console(uport)) { spin_unlock_irqrestore(&port->lock, flags); @@ -1395,6 +1453,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp) wake_up_interruptible(&port->close_wait); mutex_unlock(&port->mutex); + + tty_ldisc_flush(tty); } static void uart_wait_until_sent(struct tty_struct *tty, int timeout) @@ -1556,6 +1616,10 @@ static int uart_open(struct tty_struct *tty, struct file *filp) pr_debug("uart_open(%d) called\n", line); + spin_lock_irq(&port->lock); + ++port->count; + spin_unlock_irq(&port->lock); + /* * We take the semaphore here to guarantee that we won't be re-entered * while allocating the state structure, or while we request any IRQs @@ -1568,17 +1632,11 @@ static int uart_open(struct tty_struct *tty, struct file *filp) goto end; } - port->count++; if (!state->uart_port || state->uart_port->flags & UPF_DEAD) { retval = -ENXIO; - goto err_dec_count; + goto err_unlock; } - /* - * Once we set tty->driver_data here, we are guaranteed that - * uart_close() will decrement the driver module use count. - * Any failures from here onwards should not touch the count. - */ tty->driver_data = state; state->uart_port->state = state; state->port.low_latency = @@ -1599,8 +1657,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp) end: return retval; -err_dec_count: - port->count--; +err_unlock: mutex_unlock(&port->mutex); goto end; } @@ -1975,12 +2032,9 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) for (tries = 3; !ops->tx_empty(uport) && tries; tries--) msleep(10); if (!tries) - printk(KERN_ERR "%s%s%s%d: Unable to drain " - "transmitter\n", - uport->dev ? dev_name(uport->dev) : "", - uport->dev ? ": " : "", - drv->dev_name, - drv->tty_driver->name_base + uport->line); + dev_err(uport->dev, "%s%d: Unable to drain transmitter\n", + drv->dev_name, + drv->tty_driver->name_base + uport->line); if (console_suspend_enabled || !uart_console(uport)) ops->shutdown(uport); @@ -2099,6 +2153,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) break; case UPIO_MEM: case UPIO_MEM32: + case UPIO_MEM32BE: case UPIO_AU: case UPIO_TSI: snprintf(address, sizeof(address), @@ -2109,9 +2164,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) break; } - printk(KERN_INFO "%s%s%s%d at %s (irq = %d, base_baud = %d) is a %s\n", - port->dev ? dev_name(port->dev) : "", - port->dev ? ": " : "", + dev_info(port->dev, "%s%d at %s (irq = %d, base_baud = %d) is a %s\n", drv->dev_name, drv->tty_driver->name_base + port->line, address, port->irq, port->uartclk / 16, uart_type(port)); @@ -2348,8 +2401,6 @@ int uart_register_driver(struct uart_driver *drv) tty_port_init(port); port->ops = &uart_port_ops; - port->close_delay = HZ / 2; /* .5 seconds */ - port->closing_wait = 30 * HZ;/* 30 seconds */ } retval = tty_register_driver(normal); @@ -2598,11 +2649,12 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) goto out; } + /* Link the port to the driver state table and vice versa */ state->uart_port = uport; - state->pm_state = UART_PM_STATE_UNDEFINED; + uport->state = state; + state->pm_state = UART_PM_STATE_UNDEFINED; uport->cons = drv->cons; - uport->state = state; /* * If this port is a console, then the spinlock is already @@ -2640,7 +2692,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) if (likely(!IS_ERR(tty_dev))) { device_set_wakeup_capable(tty_dev, 1); } else { - printk(KERN_ERR "Cannot register tty device on line %d\n", + dev_err(uport->dev, "Cannot register tty device on line %d\n", uport->line); } @@ -2675,7 +2727,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) BUG_ON(in_interrupt()); if (state->uart_port != uport) - printk(KERN_ALERT "Removing wrong port: %p != %p\n", + dev_alert(uport->dev, "Removing wrong port: %p != %p\n", state->uart_port, uport); mutex_lock(&port_mutex); @@ -2745,6 +2797,7 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2) (port1->hub6 == port2->hub6); case UPIO_MEM: case UPIO_MEM32: + case UPIO_MEM32BE: case UPIO_AU: case UPIO_TSI: return (port1->mapbase == port2->mapbase); @@ -2757,22 +2810,29 @@ EXPORT_SYMBOL(uart_match_port); * uart_handle_dcd_change - handle a change of carrier detect state * @uport: uart_port structure for the open port * @status: new carrier detect status, nonzero if active + * + * Caller must hold uport->lock */ void uart_handle_dcd_change(struct uart_port *uport, unsigned int status) { struct tty_port *port = &uport->state->port; struct tty_struct *tty = port->tty; - struct tty_ldisc *ld = tty ? tty_ldisc_ref(tty) : NULL; + struct tty_ldisc *ld; + + lockdep_assert_held_once(&uport->lock); - if (ld) { - if (ld->ops->dcd_change) - ld->ops->dcd_change(tty, status); - tty_ldisc_deref(ld); + if (tty) { + ld = tty_ldisc_ref(tty); + if (ld) { + if (ld->ops->dcd_change) + ld->ops->dcd_change(tty, status); + tty_ldisc_deref(ld); + } } uport->icount.dcd++; - if (port->flags & ASYNC_CHECK_CD) { + if (uart_dcd_enabled(uport)) { if (status) wake_up_interruptible(&port->open_wait); else if (tty) @@ -2785,26 +2845,25 @@ EXPORT_SYMBOL_GPL(uart_handle_dcd_change); * uart_handle_cts_change - handle a change of clear-to-send state * @uport: uart_port structure for the open port * @status: new clear to send status, nonzero if active + * + * Caller must hold uport->lock */ void uart_handle_cts_change(struct uart_port *uport, unsigned int status) { - struct tty_port *port = &uport->state->port; - struct tty_struct *tty = port->tty; + lockdep_assert_held_once(&uport->lock); uport->icount.cts++; - /* skip below code if the hw flow control is supported */ - if (tty_port_cts_enabled(port) && - !(uport->flags & UPF_HARD_FLOW)) { - if (tty->hw_stopped) { + if (uart_cts_enabled(uport)) { + if (uport->hw_stopped) { if (status) { - tty->hw_stopped = 0; + uport->hw_stopped = 0; uport->ops->start_tx(uport); uart_write_wakeup(uport); } } else { if (!status) { - tty->hw_stopped = 1; + uport->hw_stopped = 1; uport->ops->stop_tx(uport); } } diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c index bf9560ffe3f4..a38596c5194e 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.c +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -18,7 +18,7 @@ #include <linux/err.h> #include <linux/device.h> #include <linux/gpio/consumer.h> -#include <uapi/asm-generic/termios.h> +#include <linux/termios.h> #include "serial_mctrl_gpio.h" @@ -44,15 +44,21 @@ static const struct { void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) { enum mctrl_gpio_idx i; + struct gpio_desc *desc_array[UART_GPIO_MAX]; + int value_array[UART_GPIO_MAX]; + unsigned int count = 0; if (IS_ERR_OR_NULL(gpios)) return; for (i = 0; i < UART_GPIO_MAX; i++) if (!IS_ERR_OR_NULL(gpios->gpio[i]) && - mctrl_gpios_desc[i].dir_out) - gpiod_set_value(gpios->gpio[i], - !!(mctrl & mctrl_gpios_desc[i].mctrl)); + mctrl_gpios_desc[i].dir_out) { + desc_array[count] = gpios->gpio[i]; + value_array[count] = !!(mctrl & mctrl_gpios_desc[i].mctrl); + count++; + } + gpiod_set_array(count, desc_array, value_array); } EXPORT_SYMBOL_GPL(mctrl_gpio_set); diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c index af115645c51f..f80312eed4fd 100644 --- a/drivers/tty/serial/serial_txx9.c +++ b/drivers/tty/serial/serial_txx9.c @@ -1165,7 +1165,6 @@ static struct platform_driver serial_txx9_plat_driver = { #endif .driver = { .name = "serial_txx9", - .owner = THIS_MODULE, }, }; diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 3081e46085ce..e032963989fc 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1403,7 +1403,7 @@ static void work_fn_rx(struct work_struct *work) unsigned long flags; int count; - chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); + dmaengine_terminate_all(chan); dev_dbg(port->dev, "Read %zu bytes with cookie %d\n", sh_desc->partial, sh_desc->cookie); @@ -1812,9 +1812,6 @@ static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq, err = DIV_ROUND_CLOSEST(freq, ((br + 1) * bps * sr * (1 << (2 * c + 1)) / 1000)) - 1000; - if (err < 0) - continue; - /* Calc recv margin * M: Receive margin (%) * N: Ratio of bit rate to clock (N = sampling rate) @@ -1829,7 +1826,7 @@ static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq, */ recv_margin = abs((500 - DIV_ROUND_CLOSEST(1000, sr << 1)) / 10); - if (min_err > err) { + if (abs(min_err) > abs(err)) { min_err = err; recv_max_margin = recv_margin; } else if ((min_err == err) && @@ -2638,7 +2635,6 @@ static struct platform_driver sci_driver = { .remove = sci_remove, .driver = { .name = "sh-sci", - .owner = THIS_MODULE, .pm = &sci_dev_pm_ops, .of_match_table = of_match_ptr(of_sci_match), }, diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c index 4102192687ee..b269f6bd16d6 100644 --- a/drivers/tty/serial/sirfsoc_uart.c +++ b/drivers/tty/serial/sirfsoc_uart.c @@ -1032,10 +1032,19 @@ static void sirfsoc_uart_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { struct sirfsoc_uart_port *sirfport = to_sirfport(port); - if (!state) + if (!state) { + if (sirfport->is_bt_uart) { + clk_prepare_enable(sirfport->clk_noc); + clk_prepare_enable(sirfport->clk_general); + } clk_prepare_enable(sirfport->clk); - else + } else { clk_disable_unprepare(sirfport->clk); + if (sirfport->is_bt_uart) { + clk_disable_unprepare(sirfport->clk_general); + clk_disable_unprepare(sirfport->clk_noc); + } + } } static int sirfsoc_uart_startup(struct uart_port *port) @@ -1378,12 +1387,26 @@ usp_no_flow_control: } port->irq = res->start; - sirfport->clk = clk_get(&pdev->dev, NULL); + sirfport->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(sirfport->clk)) { ret = PTR_ERR(sirfport->clk); goto err; } port->uartclk = clk_get_rate(sirfport->clk); + if (of_device_is_compatible(pdev->dev.of_node, "sirf,marco-bt-uart")) { + sirfport->clk_general = devm_clk_get(&pdev->dev, "general"); + if (IS_ERR(sirfport->clk_general)) { + ret = PTR_ERR(sirfport->clk_general); + goto err; + } + sirfport->clk_noc = devm_clk_get(&pdev->dev, "noc"); + if (IS_ERR(sirfport->clk_noc)) { + ret = PTR_ERR(sirfport->clk_noc); + goto err; + } + sirfport->is_bt_uart = true; + } else + sirfport->is_bt_uart = false; port->ops = &sirfsoc_uart_ops; spin_lock_init(&port->lock); @@ -1392,7 +1415,7 @@ usp_no_flow_control: ret = uart_add_one_port(&sirfsoc_uart_drv, port); if (ret != 0) { dev_err(&pdev->dev, "Cannot add UART port(%d).\n", pdev->id); - goto port_err; + goto err; } sirfport->rx_dma_chan = dma_request_slave_channel(port->dev, "rx"); @@ -1421,8 +1444,6 @@ alloc_coherent_err: sirfport->rx_dma_items[j].xmit.buf, sirfport->rx_dma_items[j].dma_addr); dma_release_channel(sirfport->rx_dma_chan); -port_err: - clk_put(sirfport->clk); err: return ret; } @@ -1431,7 +1452,6 @@ static int sirfsoc_uart_remove(struct platform_device *pdev) { struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev); struct uart_port *port = &sirfport->port; - clk_put(sirfport->clk); uart_remove_one_port(&sirfsoc_uart_drv, port); if (sirfport->rx_dma_chan) { int i; @@ -1477,7 +1497,6 @@ static struct platform_driver sirfsoc_uart_driver = { .remove = sirfsoc_uart_remove, .driver = { .name = SIRFUART_PORT_NAME, - .owner = THIS_MODULE, .of_match_table = sirfsoc_uart_ids, .pm = &sirfsoc_uart_pm_ops, }, diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h index 6a7ebf7ef130..275d03893990 100644 --- a/drivers/tty/serial/sirfsoc_uart.h +++ b/drivers/tty/serial/sirfsoc_uart.h @@ -417,6 +417,10 @@ struct sirfsoc_uart_port { struct uart_port port; struct clk *clk; + /* UART6 for BT usage in A7DA platform need multi-clock source */ + bool is_bt_uart; + struct clk *clk_general; + struct clk *clk_noc; /* for SiRFmarco, there are SET/CLR for UART_INT_EN */ bool is_marco; struct sirfsoc_uart_register *uart_reg; diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index 8b2d7356611d..712b03a076b8 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -151,12 +151,20 @@ static inline struct asc_port *to_asc_port(struct uart_port *port) static inline u32 asc_in(struct uart_port *port, u32 offset) { +#ifdef readl_relaxed + return readl_relaxed(port->membase + offset); +#else return readl(port->membase + offset); +#endif } static inline void asc_out(struct uart_port *port, u32 offset, u32 value) { +#ifdef writel_relaxed + writel_relaxed(value, port->membase + offset); +#else writel(value, port->membase + offset); +#endif } /* @@ -887,7 +895,6 @@ static struct platform_driver asc_serial_driver = { .driver = { .name = DRIVER_NAME, .pm = &asc_serial_pm_ops, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(asc_match), }, }; diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c index 20521db2189f..534754440fa8 100644 --- a/drivers/tty/serial/sunhv.c +++ b/drivers/tty/serial/sunhv.c @@ -268,6 +268,9 @@ static void sunhv_send_xchar(struct uart_port *port, char ch) unsigned long flags; int limit = 10000; + if (ch == __DISABLED_CHAR) + return; + spin_lock_irqsave(&port->lock, flags); while (limit-- > 0) { @@ -623,7 +626,6 @@ MODULE_DEVICE_TABLE(of, hv_match); static struct platform_driver hv_driver = { .driver = { .name = "hv", - .owner = THIS_MODULE, .of_match_table = hv_match, }, .probe = hv_probe, diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c index b9598b227a45..b5e3195b3697 100644 --- a/drivers/tty/serial/sunsab.c +++ b/drivers/tty/serial/sunsab.c @@ -345,7 +345,8 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id) /* port->lock is not held. */ static unsigned int sunsab_tx_empty(struct uart_port *port) { - struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; + struct uart_sunsab_port *up = + container_of(port, struct uart_sunsab_port, port); int ret; /* Do not need a lock for a state test like this. */ @@ -360,7 +361,8 @@ static unsigned int sunsab_tx_empty(struct uart_port *port) /* port->lock held by caller. */ static void sunsab_set_mctrl(struct uart_port *port, unsigned int mctrl) { - struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; + struct uart_sunsab_port *up = + container_of(port, struct uart_sunsab_port, port); if (mctrl & TIOCM_RTS) { up->cached_mode &= ~SAB82532_MODE_FRTS; @@ -383,7 +385,8 @@ static void sunsab_set_mctrl(struct uart_port *port, unsigned int mctrl) /* port->lock is held by caller and interrupts are disabled. */ static unsigned int sunsab_get_mctrl(struct uart_port *port) { - struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; + struct uart_sunsab_port *up = + container_of(port, struct uart_sunsab_port, port); unsigned char val; unsigned int result; @@ -404,7 +407,8 @@ static unsigned int sunsab_get_mctrl(struct uart_port *port) /* port->lock held by caller. */ static void sunsab_stop_tx(struct uart_port *port) { - struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; + struct uart_sunsab_port *up = + container_of(port, struct uart_sunsab_port, port); up->interrupt_mask1 |= SAB82532_IMR1_XPR; writeb(up->interrupt_mask1, &up->regs->w.imr1); @@ -432,11 +436,12 @@ static void sunsab_tx_idle(struct uart_sunsab_port *up) /* port->lock held by caller. */ static void sunsab_start_tx(struct uart_port *port) { - struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; + struct uart_sunsab_port *up = + container_of(port, struct uart_sunsab_port, port); struct circ_buf *xmit = &up->port.state->xmit; int i; - if (uart_circ_empty(xmit)) + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) return; up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR); @@ -465,9 +470,13 @@ static void sunsab_start_tx(struct uart_port *port) /* port->lock is not held. */ static void sunsab_send_xchar(struct uart_port *port, char ch) { - struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; + struct uart_sunsab_port *up = + container_of(port, struct uart_sunsab_port, port); unsigned long flags; + if (ch == __DISABLED_CHAR) + return; + spin_lock_irqsave(&up->port.lock, flags); sunsab_tec_wait(up); @@ -479,7 +488,8 @@ static void sunsab_send_xchar(struct uart_port *port, char ch) /* port->lock held by caller. */ static void sunsab_stop_rx(struct uart_port *port) { - struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; + struct uart_sunsab_port *up = + container_of(port, struct uart_sunsab_port, port); up->interrupt_mask0 |= SAB82532_IMR0_TCD; writeb(up->interrupt_mask1, &up->regs->w.imr0); @@ -488,7 +498,8 @@ static void sunsab_stop_rx(struct uart_port *port) /* port->lock is not held. */ static void sunsab_break_ctl(struct uart_port *port, int break_state) { - struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; + struct uart_sunsab_port *up = + container_of(port, struct uart_sunsab_port, port); unsigned long flags; unsigned char val; @@ -511,7 +522,8 @@ static void sunsab_break_ctl(struct uart_port *port, int break_state) /* port->lock is not held. */ static int sunsab_startup(struct uart_port *port) { - struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; + struct uart_sunsab_port *up = + container_of(port, struct uart_sunsab_port, port); unsigned long flags; unsigned char tmp; int err = request_irq(up->port.irq, sunsab_interrupt, @@ -582,7 +594,8 @@ static int sunsab_startup(struct uart_port *port) /* port->lock is not held. */ static void sunsab_shutdown(struct uart_port *port) { - struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; + struct uart_sunsab_port *up = + container_of(port, struct uart_sunsab_port, port); unsigned long flags; spin_lock_irqsave(&up->port.lock, flags); @@ -768,7 +781,8 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla static void sunsab_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; + struct uart_sunsab_port *up = + container_of(port, struct uart_sunsab_port, port); unsigned long flags; unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000); unsigned int quot = uart_get_divisor(port, baud); @@ -837,7 +851,8 @@ static struct uart_sunsab_port *sunsab_ports; static void sunsab_console_putchar(struct uart_port *port, int c) { - struct uart_sunsab_port *up = (struct uart_sunsab_port *)port; + struct uart_sunsab_port *up = + container_of(port, struct uart_sunsab_port, port); sunsab_tec_wait(up); writeb(c, &up->regs->w.tic); @@ -1089,7 +1104,6 @@ MODULE_DEVICE_TABLE(of, sab_match); static struct platform_driver sab_driver = { .driver = { .name = "sab", - .owner = THIS_MODULE, .of_match_table = sab_match, }, .probe = sab_probe, diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index 5326ae195e5f..e124d2e88996 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -264,7 +264,8 @@ static inline void __stop_tx(struct uart_sunsu_port *p) static void sunsu_stop_tx(struct uart_port *port) { - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + struct uart_sunsu_port *up = + container_of(port, struct uart_sunsu_port, port); __stop_tx(up); @@ -279,7 +280,8 @@ static void sunsu_stop_tx(struct uart_port *port) static void sunsu_start_tx(struct uart_port *port) { - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + struct uart_sunsu_port *up = + container_of(port, struct uart_sunsu_port, port); if (!(up->ier & UART_IER_THRI)) { up->ier |= UART_IER_THRI; @@ -297,7 +299,8 @@ static void sunsu_start_tx(struct uart_port *port) static void sunsu_stop_rx(struct uart_port *port) { - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + struct uart_sunsu_port *up = + container_of(port, struct uart_sunsu_port, port); up->ier &= ~UART_IER_RLSI; up->port.read_status_mask &= ~UART_LSR_DR; @@ -306,7 +309,8 @@ static void sunsu_stop_rx(struct uart_port *port) static void sunsu_enable_ms(struct uart_port *port) { - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + struct uart_sunsu_port *up = + container_of(port, struct uart_sunsu_port, port); unsigned long flags; spin_lock_irqsave(&up->port.lock, flags); @@ -543,7 +547,8 @@ static irqreturn_t sunsu_kbd_ms_interrupt(int irq, void *dev_id) static unsigned int sunsu_tx_empty(struct uart_port *port) { - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + struct uart_sunsu_port *up = + container_of(port, struct uart_sunsu_port, port); unsigned long flags; unsigned int ret; @@ -556,7 +561,8 @@ static unsigned int sunsu_tx_empty(struct uart_port *port) static unsigned int sunsu_get_mctrl(struct uart_port *port) { - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + struct uart_sunsu_port *up = + container_of(port, struct uart_sunsu_port, port); unsigned char status; unsigned int ret; @@ -576,7 +582,8 @@ static unsigned int sunsu_get_mctrl(struct uart_port *port) static void sunsu_set_mctrl(struct uart_port *port, unsigned int mctrl) { - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + struct uart_sunsu_port *up = + container_of(port, struct uart_sunsu_port, port); unsigned char mcr = 0; if (mctrl & TIOCM_RTS) @@ -595,7 +602,8 @@ static void sunsu_set_mctrl(struct uart_port *port, unsigned int mctrl) static void sunsu_break_ctl(struct uart_port *port, int break_state) { - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + struct uart_sunsu_port *up = + container_of(port, struct uart_sunsu_port, port); unsigned long flags; spin_lock_irqsave(&up->port.lock, flags); @@ -609,7 +617,8 @@ static void sunsu_break_ctl(struct uart_port *port, int break_state) static int sunsu_startup(struct uart_port *port) { - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + struct uart_sunsu_port *up = + container_of(port, struct uart_sunsu_port, port); unsigned long flags; int retval; @@ -719,7 +728,8 @@ static int sunsu_startup(struct uart_port *port) static void sunsu_shutdown(struct uart_port *port) { - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + struct uart_sunsu_port *up = + container_of(port, struct uart_sunsu_port, port); unsigned long flags; /* @@ -767,7 +777,8 @@ static void sunsu_change_speed(struct uart_port *port, unsigned int cflag, unsigned int iflag, unsigned int quot) { - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + struct uart_sunsu_port *up = + container_of(port, struct uart_sunsu_port, port); unsigned char cval, fcr = 0; unsigned long flags; @@ -918,7 +929,8 @@ static int sunsu_request_port(struct uart_port *port) static void sunsu_config_port(struct uart_port *port, int flags) { - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + struct uart_sunsu_port *up = + container_of(port, struct uart_sunsu_port, port); if (flags & UART_CONFIG_TYPE) { /* @@ -1277,7 +1289,8 @@ static __inline__ void wait_for_xmitr(struct uart_sunsu_port *up) static void sunsu_console_putchar(struct uart_port *port, int ch) { - struct uart_sunsu_port *up = (struct uart_sunsu_port *)port; + struct uart_sunsu_port *up = + container_of(port, struct uart_sunsu_port, port); wait_for_xmitr(up); serial_out(up, UART_TX, ch); @@ -1537,7 +1550,6 @@ MODULE_DEVICE_TABLE(of, su_match); static struct platform_driver su_driver = { .driver = { .name = "su", - .owner = THIS_MODULE, .of_match_table = su_match, }, .probe = su_probe, diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index 02df3940b95e..8b6ace341029 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -644,7 +644,8 @@ static unsigned int sunzilog_get_mctrl(struct uart_port *port) /* The port lock is held and interrupts are disabled. */ static void sunzilog_set_mctrl(struct uart_port *port, unsigned int mctrl) { - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + struct uart_sunzilog_port *up = + container_of(port, struct uart_sunzilog_port, port); struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port); unsigned char set_bits, clear_bits; @@ -668,7 +669,8 @@ static void sunzilog_set_mctrl(struct uart_port *port, unsigned int mctrl) /* The port lock is held and interrupts are disabled. */ static void sunzilog_stop_tx(struct uart_port *port) { - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + struct uart_sunzilog_port *up = + container_of(port, struct uart_sunzilog_port, port); up->flags |= SUNZILOG_FLAG_TX_STOPPED; } @@ -676,7 +678,8 @@ static void sunzilog_stop_tx(struct uart_port *port) /* The port lock is held and interrupts are disabled. */ static void sunzilog_start_tx(struct uart_port *port) { - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + struct uart_sunzilog_port *up = + container_of(port, struct uart_sunzilog_port, port); struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port); unsigned char status; @@ -736,7 +739,8 @@ static void sunzilog_stop_rx(struct uart_port *port) /* The port lock is held. */ static void sunzilog_enable_ms(struct uart_port *port) { - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + struct uart_sunzilog_port *up = + container_of(port, struct uart_sunzilog_port, port); struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port); unsigned char new_reg; @@ -752,7 +756,8 @@ static void sunzilog_enable_ms(struct uart_port *port) /* The port lock is not held. */ static void sunzilog_break_ctl(struct uart_port *port, int break_state) { - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + struct uart_sunzilog_port *up = + container_of(port, struct uart_sunzilog_port, port); struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port); unsigned char set_bits, clear_bits, new_reg; unsigned long flags; @@ -938,7 +943,8 @@ static void sunzilog_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + struct uart_sunzilog_port *up = + container_of(port, struct uart_sunzilog_port, port); unsigned long flags; int baud, brg; @@ -998,7 +1004,8 @@ static int sunzilog_verify_port(struct uart_port *port, struct serial_struct *se static int sunzilog_get_poll_char(struct uart_port *port) { unsigned char ch, r1; - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + struct uart_sunzilog_port *up = + container_of(port, struct uart_sunzilog_port, port); struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(&up->port); @@ -1032,7 +1039,8 @@ static int sunzilog_get_poll_char(struct uart_port *port) static void sunzilog_put_poll_char(struct uart_port *port, unsigned char ch) { - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *)port; + struct uart_sunzilog_port *up = + container_of(port, struct uart_sunzilog_port, port); sunzilog_putchar(&up->port, ch); } @@ -1533,7 +1541,6 @@ MODULE_DEVICE_TABLE(of, zs_match); static struct platform_driver zs_driver = { .driver = { .name = "zs", - .owner = THIS_MODULE, .of_match_table = zs_match, }, .probe = zs_probe, diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c index 0d11d5032b93..512c162634a3 100644 --- a/drivers/tty/serial/timbuart.c +++ b/drivers/tty/serial/timbuart.c @@ -273,6 +273,8 @@ static void timbuart_shutdown(struct uart_port *port) dev_dbg(port->dev, "%s\n", __func__); free_irq(port->irq, uart); iowrite32(0, port->membase + TIMBUART_IER); + + timbuart_flush_buffer(port); } static int get_bindex(int baud) @@ -501,7 +503,6 @@ static int timbuart_remove(struct platform_device *dev) static struct platform_driver timbuart_platform_driver = { .driver = { .name = "timb-uart", - .owner = THIS_MODULE, }, .probe = timbuart_probe, .remove = timbuart_remove, diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index 9fc22f40796e..189f52e3111f 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -665,7 +665,6 @@ static struct platform_driver ulite_platform_driver = { .probe = ulite_probe, .remove = ulite_remove, .driver = { - .owner = THIS_MODULE, .name = "uartlite", .of_match_table = of_match_ptr(ulite_of_match), }, diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index c107a0f0e72f..14d10fcfd210 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -1485,7 +1485,6 @@ MODULE_DEVICE_TABLE(of, ucc_uart_match); static struct platform_driver ucc_uart_of_driver = { .driver = { .name = "ucc_uart", - .owner = THIS_MODULE, .of_match_table = ucc_uart_match, }, .probe = ucc_uart_probe, diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c index db0c8a4ab03e..485de53c5d75 100644 --- a/drivers/tty/serial/vr41xx_siu.c +++ b/drivers/tty/serial/vr41xx_siu.c @@ -847,7 +847,6 @@ void __init vr41xx_siu_early_setup(struct uart_port *port) siu_uart_ports[port->line].type = port->type; siu_uart_ports[port->line].uartclk = SIU_BAUD_BASE * 16; siu_uart_ports[port->line].mapbase = port->mapbase; - siu_uart_ports[port->line].mapbase = port->mapbase; siu_uart_ports[port->line].ops = &siu_uart_ops; } @@ -955,7 +954,6 @@ static struct platform_driver siu_device_driver = { .resume = siu_resume, .driver = { .name = "SIU", - .owner = THIS_MODULE, }, }; diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index 15ad6fcda88b..4079ec56f5f9 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c @@ -33,8 +33,8 @@ #include <linux/serial.h> #include <linux/slab.h> #include <linux/clk.h> -#include <linux/platform_device.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/err.h> /* @@ -78,13 +78,40 @@ #define RX_FIFO_INTS (RXFAF | RXFF | RXOVER | PER | FER | RXTOUT) #define TX_FIFO_INTS (TXFAE | TXFE | TXUDR) +/* + * Line control bits + */ + +#define VT8500_TXEN (1 << 0) /* Enable transmit logic */ +#define VT8500_RXEN (1 << 1) /* Enable receive logic */ +#define VT8500_CS8 (1 << 2) /* 8-bit data length (vs. 7-bit) */ +#define VT8500_CSTOPB (1 << 3) /* 2 stop bits (vs. 1) */ +#define VT8500_PARENB (1 << 4) /* Enable parity */ +#define VT8500_PARODD (1 << 5) /* Odd parity (vs. even) */ +#define VT8500_RTS (1 << 6) /* Ready to send */ +#define VT8500_LOOPBK (1 << 7) /* Enable internal loopback */ +#define VT8500_DMA (1 << 8) /* Enable DMA mode (needs FIFO) */ +#define VT8500_BREAK (1 << 9) /* Initiate break signal */ +#define VT8500_PSLVERR (1 << 10) /* APB error upon empty RX FIFO read */ +#define VT8500_SWRTSCTS (1 << 11) /* Software-controlled RTS/CTS */ + +/* + * Capability flags (driver-internal) + */ + +#define VT8500_HAS_SWRTSCTS_SWITCH (1 << 1) + +#define VT8500_RECOMMENDED_CLK 12000000 +#define VT8500_OVERSAMPLING_DIVISOR 13 #define VT8500_MAX_PORTS 6 struct vt8500_port { struct uart_port uart; char name[16]; struct clk *clk; + unsigned int clk_predivisor; unsigned int ier; + unsigned int vt8500_uart_flags; }; /* @@ -267,31 +294,45 @@ static unsigned int vt8500_get_mctrl(struct uart_port *port) static void vt8500_set_mctrl(struct uart_port *port, unsigned int mctrl) { + unsigned int lcr = vt8500_read(port, VT8500_URLCR); + + if (mctrl & TIOCM_RTS) + lcr |= VT8500_RTS; + else + lcr &= ~VT8500_RTS; + + vt8500_write(port, lcr, VT8500_URLCR); } static void vt8500_break_ctl(struct uart_port *port, int break_ctl) { if (break_ctl) - vt8500_write(port, vt8500_read(port, VT8500_URLCR) | (1 << 9), + vt8500_write(port, + vt8500_read(port, VT8500_URLCR) | VT8500_BREAK, VT8500_URLCR); } static int vt8500_set_baud_rate(struct uart_port *port, unsigned int baud) { + struct vt8500_port *vt8500_port = + container_of(port, struct vt8500_port, uart); unsigned long div; unsigned int loops = 1000; - div = vt8500_read(port, VT8500_URDIV) & ~(0x3ff); + div = ((vt8500_port->clk_predivisor - 1) & 0xf) << 16; + div |= (uart_get_divisor(port, baud) - 1) & 0x3ff; - if (unlikely((baud < 900) || (baud > 921600))) - div |= 7; - else - div |= (921600 / baud) - 1; + /* Effective baud rate */ + baud = port->uartclk / 16 / ((div & 0x3ff) + 1); while ((vt8500_read(port, VT8500_URUSR) & (1 << 5)) && --loops) cpu_relax(); + vt8500_write(port, div, VT8500_URDIV); + /* Break signal timing depends on baud rate, update accordingly */ + vt8500_write(port, mult_frac(baud, 4096, 1000000), VT8500_URBKR); + return baud; } @@ -347,31 +388,35 @@ static void vt8500_set_termios(struct uart_port *port, /* calculate parity */ lcr = vt8500_read(&vt8500_port->uart, VT8500_URLCR); - lcr &= ~((1 << 5) | (1 << 4)); + lcr &= ~(VT8500_PARENB | VT8500_PARODD); if (termios->c_cflag & PARENB) { - lcr |= (1 << 4); + lcr |= VT8500_PARENB; termios->c_cflag &= ~CMSPAR; if (termios->c_cflag & PARODD) - lcr |= (1 << 5); + lcr |= VT8500_PARODD; } /* calculate bits per char */ - lcr &= ~(1 << 2); + lcr &= ~VT8500_CS8; switch (termios->c_cflag & CSIZE) { case CS7: break; case CS8: default: - lcr |= (1 << 2); + lcr |= VT8500_CS8; termios->c_cflag &= ~CSIZE; termios->c_cflag |= CS8; break; } /* calculate stop bits */ - lcr &= ~(1 << 3); + lcr &= ~VT8500_CSTOPB; if (termios->c_cflag & CSTOPB) - lcr |= (1 << 3); + lcr |= VT8500_CSTOPB; + + lcr &= ~VT8500_SWRTSCTS; + if (vt8500_port->vt8500_uart_flags & VT8500_HAS_SWRTSCTS_SWITCH) + lcr |= VT8500_SWRTSCTS; /* set parity, bits per char, and stop bit */ vt8500_write(&vt8500_port->uart, lcr, VT8500_URLCR); @@ -521,6 +566,33 @@ static struct console vt8500_console = { #define VT8500_CONSOLE NULL #endif +#ifdef CONFIG_CONSOLE_POLL +static int vt8500_get_poll_char(struct uart_port *port) +{ + unsigned int status = vt8500_read(port, VT8500_URFIDX); + + if (!(status & 0x1f00)) + return NO_POLL_CHAR; + + return vt8500_read(port, VT8500_RXFIFO) & 0xff; +} + +static void vt8500_put_poll_char(struct uart_port *port, unsigned char c) +{ + unsigned int status, tmout = 10000; + + do { + status = vt8500_read(port, VT8500_URFIDX); + + if (--tmout == 0) + break; + udelay(1); + } while (status & 0x10); + + vt8500_write(port, c, VT8500_TXFIFO); +} +#endif + static struct uart_ops vt8500_uart_pops = { .tx_empty = vt8500_tx_empty, .set_mctrl = vt8500_set_mctrl, @@ -538,6 +610,10 @@ static struct uart_ops vt8500_uart_pops = { .request_port = vt8500_request_port, .config_port = vt8500_config_port, .verify_port = vt8500_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = vt8500_get_poll_char, + .poll_put_char = vt8500_put_poll_char, +#endif }; static struct uart_driver vt8500_uart_driver = { @@ -548,14 +624,31 @@ static struct uart_driver vt8500_uart_driver = { .cons = VT8500_CONSOLE, }; +static unsigned int vt8500_flags; /* none required so far */ +static unsigned int wm8880_flags = VT8500_HAS_SWRTSCTS_SWITCH; + +static const struct of_device_id wmt_dt_ids[] = { + { .compatible = "via,vt8500-uart", .data = &vt8500_flags}, + { .compatible = "wm,wm8880-uart", .data = &wm8880_flags}, + {} +}; + static int vt8500_serial_probe(struct platform_device *pdev) { struct vt8500_port *vt8500_port; struct resource *mmres, *irqres; struct device_node *np = pdev->dev.of_node; + const struct of_device_id *match; + const unsigned int *flags; int ret; int port; + match = of_match_device(wmt_dt_ids, &pdev->dev); + if (!match) + return -EINVAL; + + flags = match->data; + mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!mmres || !irqres) @@ -605,6 +698,11 @@ static int vt8500_serial_probe(struct platform_device *pdev) return ret; } + vt8500_port->vt8500_uart_flags = *flags; + vt8500_port->clk_predivisor = DIV_ROUND_CLOSEST( + clk_get_rate(vt8500_port->clk), + VT8500_RECOMMENDED_CLK + ); vt8500_port->uart.type = PORT_VT8500; vt8500_port->uart.iotype = UPIO_MEM; vt8500_port->uart.mapbase = mmres->start; @@ -615,7 +713,10 @@ static int vt8500_serial_probe(struct platform_device *pdev) vt8500_port->uart.dev = &pdev->dev; vt8500_port->uart.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; - vt8500_port->uart.uartclk = clk_get_rate(vt8500_port->clk); + /* Serial core uses the magic "16" everywhere - adjust for it */ + vt8500_port->uart.uartclk = 16 * clk_get_rate(vt8500_port->clk) / + vt8500_port->clk_predivisor / + VT8500_OVERSAMPLING_DIVISOR; snprintf(vt8500_port->name, sizeof(vt8500_port->name), "VT8500 UART%d", pdev->id); @@ -639,17 +740,11 @@ static int vt8500_serial_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id wmt_dt_ids[] = { - { .compatible = "via,vt8500-uart", }, - {} -}; - static struct platform_driver vt8500_platform_driver = { .probe = vt8500_serial_probe, .remove = vt8500_serial_remove, .driver = { .name = "vt8500_serial", - .owner = THIS_MODULE, .of_match_table = wmt_dt_ids, }, }; diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 806e4bcadbd7..542bab37e502 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -133,6 +133,15 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); #define CDNS_UART_IXR_BRK 0x80000000 /* + * Modem Control register: + * The read/write Modem Control register controls the interface with the modem + * or data set, or a peripheral device emulating a modem. + */ +#define CDNS_UART_MODEMCR_FCM 0x00000020 /* Automatic flow control mode */ +#define CDNS_UART_MODEMCR_RTS 0x00000002 /* Request to send output control */ +#define CDNS_UART_MODEMCR_DTR 0x00000001 /* Data Terminal Ready */ + +/* * Channel Status Register: * The channel status register (CSR) is provided to enable the control logic * to monitor the status of bits in the channel interrupt status register, @@ -915,7 +924,18 @@ static unsigned int cdns_uart_get_mctrl(struct uart_port *port) static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) { - /* N/A */ + u32 val; + + val = cdns_uart_readl(CDNS_UART_MODEMCR_OFFSET); + + val &= ~(CDNS_UART_MODEMCR_RTS | CDNS_UART_MODEMCR_DTR); + + if (mctrl & TIOCM_RTS) + val |= CDNS_UART_MODEMCR_RTS; + if (mctrl & TIOCM_DTR) + val |= CDNS_UART_MODEMCR_DTR; + + cdns_uart_writel(val, CDNS_UART_MODEMCR_OFFSET); } #ifdef CONFIG_CONSOLE_POLL @@ -1051,6 +1071,25 @@ static void cdns_uart_console_putchar(struct uart_port *port, int ch) cdns_uart_writel(ch, CDNS_UART_FIFO_OFFSET); } +static void cdns_early_write(struct console *con, const char *s, unsigned n) +{ + struct earlycon_device *dev = con->data; + + uart_console_write(&dev->port, s, n, cdns_uart_console_putchar); +} + +static int __init cdns_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + if (!device->port.membase) + return -ENODEV; + + device->con->write = cdns_early_write; + + return 0; +} +EARLYCON_DECLARE(cdns, cdns_early_console_setup); + /** * cdns_uart_console_write - perform write operation * @co: Console handle @@ -1428,7 +1467,6 @@ static struct platform_driver cdns_uart_platform_driver = { .probe = cdns_uart_probe, .remove = cdns_uart_remove, .driver = { - .owner = THIS_MODULE, .name = CDNS_UART_NAME, .of_match_table = cdns_uart_of_match, .pm = &cdns_uart_dev_pm_ops, diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 143deb62467d..3605103fc1ac 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -202,14 +202,16 @@ static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b) /** * tty_buffer_flush - flush full tty buffers * @tty: tty to flush + * @ld: optional ldisc ptr (must be referenced) * - * flush all the buffers containing receive data. + * flush all the buffers containing receive data. If ld != NULL, + * flush the ldisc input buffer. * * Locking: takes buffer lock to ensure single-threaded flip buffer * 'consumer' */ -void tty_buffer_flush(struct tty_struct *tty) +void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld) { struct tty_port *port = tty->port; struct tty_bufhead *buf = &port->buf; @@ -223,6 +225,10 @@ void tty_buffer_flush(struct tty_struct *tty) buf->head = next; } buf->head->read = buf->head->commit; + + if (ld && ld->ops->flush_buffer) + ld->ops->flush_buffer(tty); + atomic_dec(&buf->priority); mutex_unlock(&buf->lock); } diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 8fbad3410c75..4f35b43e2475 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -153,8 +153,6 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd, static int __tty_fasync(int fd, struct file *filp, int on); static int tty_fasync(int fd, struct file *filp, int on); static void release_tty(struct tty_struct *tty, int idx); -static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty); -static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty); /** * free_tty_struct - free a disused tty @@ -169,8 +167,7 @@ void free_tty_struct(struct tty_struct *tty) { if (!tty) return; - if (tty->dev) - put_device(tty->dev); + put_device(tty->dev); kfree(tty->write_buf); tty->magic = 0xDEADDEAD; kfree(tty); @@ -277,6 +274,7 @@ int tty_paranoia_check(struct tty_struct *tty, struct inode *inode, return 0; } +/* Caller must hold tty_lock */ static int check_tty_count(struct tty_struct *tty, const char *routine) { #ifdef CHECK_TTY_COUNT @@ -492,6 +490,78 @@ static const struct file_operations hung_up_tty_fops = { static DEFINE_SPINLOCK(redirect_lock); static struct file *redirect; + +void proc_clear_tty(struct task_struct *p) +{ + unsigned long flags; + struct tty_struct *tty; + spin_lock_irqsave(&p->sighand->siglock, flags); + tty = p->signal->tty; + p->signal->tty = NULL; + spin_unlock_irqrestore(&p->sighand->siglock, flags); + tty_kref_put(tty); +} + +/** + * proc_set_tty - set the controlling terminal + * + * Only callable by the session leader and only if it does not already have + * a controlling terminal. + * + * Caller must hold: tty_lock() + * a readlock on tasklist_lock + * sighand lock + */ +static void __proc_set_tty(struct tty_struct *tty) +{ + unsigned long flags; + + spin_lock_irqsave(&tty->ctrl_lock, flags); + /* + * The session and fg pgrp references will be non-NULL if + * tiocsctty() is stealing the controlling tty + */ + put_pid(tty->session); + put_pid(tty->pgrp); + tty->pgrp = get_pid(task_pgrp(current)); + spin_unlock_irqrestore(&tty->ctrl_lock, flags); + tty->session = get_pid(task_session(current)); + if (current->signal->tty) { + printk(KERN_DEBUG "tty not NULL!!\n"); + tty_kref_put(current->signal->tty); + } + put_pid(current->signal->tty_old_pgrp); + current->signal->tty = tty_kref_get(tty); + current->signal->tty_old_pgrp = NULL; +} + +static void proc_set_tty(struct tty_struct *tty) +{ + spin_lock_irq(¤t->sighand->siglock); + __proc_set_tty(tty); + spin_unlock_irq(¤t->sighand->siglock); +} + +struct tty_struct *get_current_tty(void) +{ + struct tty_struct *tty; + unsigned long flags; + + spin_lock_irqsave(¤t->sighand->siglock, flags); + tty = tty_kref_get(current->signal->tty); + spin_unlock_irqrestore(¤t->sighand->siglock, flags); + return tty; +} +EXPORT_SYMBOL_GPL(get_current_tty); + +static void session_clear_tty(struct pid *session) +{ + struct task_struct *p; + do_each_pid_task(session, PIDTYPE_SID, p) { + proc_clear_tty(p); + } while_each_pid_task(session, PIDTYPE_SID, p); +} + /** * tty_wakeup - request more data * @tty: terminal @@ -620,9 +690,6 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session) return; } - /* some functions below drop BTM, so we need this bit */ - set_bit(TTY_HUPPING, &tty->flags); - /* inuse_filps is protected by the single tty lock, this really needs to change if we want to flush the workqueue with the lock held */ @@ -647,10 +714,6 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session) while (refs--) tty_kref_put(tty); - /* - * it drops BTM and thus races with reopen - * we protect the race by TTY_HUPPING - */ tty_ldisc_hangup(tty); spin_lock_irq(&tty->ctrl_lock); @@ -682,8 +745,6 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session) * can't yet guarantee all that. */ set_bit(TTY_HUPPED, &tty->flags); - clear_bit(TTY_HUPPING, &tty->flags); - tty_unlock(tty); if (f) @@ -792,14 +853,6 @@ int tty_hung_up_p(struct file *filp) EXPORT_SYMBOL(tty_hung_up_p); -static void session_clear_tty(struct pid *session) -{ - struct task_struct *p; - do_each_pid_task(session, PIDTYPE_SID, p) { - proc_clear_tty(p); - } while_each_pid_task(session, PIDTYPE_SID, p); -} - /** * disassociate_ctty - disconnect controlling tty * @on_exit: true if exiting so need to "hang up" the session @@ -908,8 +961,7 @@ void no_tty(void) * stop_tty - propagate flow control * @tty: tty to stop * - * Perform flow control to the driver. For PTY/TTY pairs we - * must also propagate the TIOCKPKT status. May be called + * Perform flow control to the driver. May be called * on an already stopped device and will not re-call the driver * method. * @@ -919,64 +971,58 @@ void no_tty(void) * but not always. * * Locking: - * Uses the tty control lock internally + * flow_lock */ -void stop_tty(struct tty_struct *tty) +void __stop_tty(struct tty_struct *tty) { - unsigned long flags; - spin_lock_irqsave(&tty->ctrl_lock, flags); - if (tty->stopped) { - spin_unlock_irqrestore(&tty->ctrl_lock, flags); + if (tty->stopped) return; - } tty->stopped = 1; - if (tty->link && tty->link->packet) { - tty->ctrl_status &= ~TIOCPKT_START; - tty->ctrl_status |= TIOCPKT_STOP; - wake_up_interruptible_poll(&tty->link->read_wait, POLLIN); - } - spin_unlock_irqrestore(&tty->ctrl_lock, flags); if (tty->ops->stop) - (tty->ops->stop)(tty); + tty->ops->stop(tty); } +void stop_tty(struct tty_struct *tty) +{ + unsigned long flags; + + spin_lock_irqsave(&tty->flow_lock, flags); + __stop_tty(tty); + spin_unlock_irqrestore(&tty->flow_lock, flags); +} EXPORT_SYMBOL(stop_tty); /** * start_tty - propagate flow control * @tty: tty to start * - * Start a tty that has been stopped if at all possible. Perform - * any necessary wakeups and propagate the TIOCPKT status. If this - * is the tty was previous stopped and is being started then the - * driver start method is invoked and the line discipline woken. + * Start a tty that has been stopped if at all possible. If this + * tty was previous stopped and is now being started, the driver + * start method is invoked and the line discipline woken. * * Locking: - * ctrl_lock + * flow_lock */ -void start_tty(struct tty_struct *tty) +void __start_tty(struct tty_struct *tty) { - unsigned long flags; - spin_lock_irqsave(&tty->ctrl_lock, flags); - if (!tty->stopped || tty->flow_stopped) { - spin_unlock_irqrestore(&tty->ctrl_lock, flags); + if (!tty->stopped || tty->flow_stopped) return; - } tty->stopped = 0; - if (tty->link && tty->link->packet) { - tty->ctrl_status &= ~TIOCPKT_STOP; - tty->ctrl_status |= TIOCPKT_START; - wake_up_interruptible_poll(&tty->link->read_wait, POLLIN); - } - spin_unlock_irqrestore(&tty->ctrl_lock, flags); if (tty->ops->start) - (tty->ops->start)(tty); - /* If we have a running line discipline it may need kicking */ + tty->ops->start(tty); tty_wakeup(tty); } +void start_tty(struct tty_struct *tty) +{ + unsigned long flags; + + spin_lock_irqsave(&tty->flow_lock, flags); + __start_tty(tty); + spin_unlock_irqrestore(&tty->flow_lock, flags); +} EXPORT_SYMBOL(start_tty); /* We limit tty time update visibility to every 8 seconds or so. */ @@ -1019,7 +1065,7 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count, situation */ ld = tty_ldisc_ref_wait(tty); if (ld->ops->read) - i = (ld->ops->read)(tty, file, buf, count); + i = ld->ops->read(tty, file, buf, count); else i = -EIO; tty_ldisc_deref(ld); @@ -1030,15 +1076,13 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count, return i; } -void tty_write_unlock(struct tty_struct *tty) - __releases(&tty->atomic_write_lock) +static void tty_write_unlock(struct tty_struct *tty) { mutex_unlock(&tty->atomic_write_lock); wake_up_interruptible_poll(&tty->write_wait, POLLOUT); } -int tty_write_lock(struct tty_struct *tty, int ndelay) - __acquires(&tty->atomic_write_lock) +static int tty_write_lock(struct tty_struct *tty, int ndelay) { if (!mutex_trylock(&tty->atomic_write_lock)) { if (ndelay) @@ -1153,7 +1197,7 @@ void tty_write_message(struct tty_struct *tty, char *msg) if (tty) { mutex_lock(&tty->atomic_write_lock); tty_lock(tty); - if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) { + if (tty->ops->write && tty->count > 0) { tty_unlock(tty); tty->ops->write(tty, msg, strlen(msg)); } else @@ -1224,6 +1268,35 @@ ssize_t redirected_tty_write(struct file *file, const char __user *buf, return tty_write(file, buf, count, ppos); } +/** + * tty_send_xchar - send priority character + * + * Send a high priority character to the tty even if stopped + * + * Locking: none for xchar method, write ordering for write method. + */ + +int tty_send_xchar(struct tty_struct *tty, char ch) +{ + int was_stopped = tty->stopped; + + if (tty->ops->send_xchar) { + tty->ops->send_xchar(tty, ch); + return 0; + } + + if (tty_write_lock(tty, 0) < 0) + return -ERESTARTSYS; + + if (was_stopped) + start_tty(tty); + tty->ops->write(tty, &ch, 1); + if (was_stopped) + stop_tty(tty); + tty_write_unlock(tty); + return 0; +} + static char ptychar[] = "pqrstuvwxyzabcde"; /** @@ -1271,19 +1344,24 @@ static ssize_t tty_line_name(struct tty_driver *driver, int index, char *p) * @driver: the driver for the tty * @idx: the minor number * - * Return the tty, if found or ERR_PTR() otherwise. + * Return the tty, if found. If not found, return NULL or ERR_PTR() if the + * driver lookup() method returns an error. * - * Locking: tty_mutex must be held. If tty is found, the mutex must - * be held until the 'fast-open' is also done. Will change once we - * have refcounting in the driver and per driver locking + * Locking: tty_mutex must be held. If the tty is found, bump the tty kref. */ static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver, struct inode *inode, int idx) { + struct tty_struct *tty; + if (driver->ops->lookup) - return driver->ops->lookup(driver, inode, idx); + tty = driver->ops->lookup(driver, inode, idx); + else + tty = driver->ttys[idx]; - return driver->ttys[idx]; + if (!IS_ERR(tty)) + tty_kref_get(tty); + return tty; } /** @@ -1371,29 +1449,21 @@ void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct *tty) * @tty - the tty to open * * Return 0 on success, -errno on error. + * Re-opens on master ptys are not allowed and return -EIO. * - * Locking: tty_mutex must be held from the time the tty was found - * till this open completes. + * Locking: Caller must hold tty_lock */ static int tty_reopen(struct tty_struct *tty) { struct tty_driver *driver = tty->driver; - if (test_bit(TTY_CLOSING, &tty->flags) || - test_bit(TTY_HUPPING, &tty->flags)) + if (!tty->count) return -EIO; if (driver->type == TTY_DRIVER_TYPE_PTY && - driver->subtype == PTY_TYPE_MASTER) { - /* - * special case for PTY masters: only one open permitted, - * and the slave side open count is incremented as well. - */ - if (tty->count) - return -EIO; + driver->subtype == PTY_TYPE_MASTER) + return -EIO; - tty->link->count++; - } tty->count++; WARN_ON(!tty->ldisc); @@ -1513,15 +1583,19 @@ void tty_free_termios(struct tty_struct *tty) EXPORT_SYMBOL(tty_free_termios); /** - * tty_flush_works - flush all works of a tty - * @tty: tty device to flush works for + * tty_flush_works - flush all works of a tty/pty pair + * @tty: tty device to flush works for (or either end of a pty pair) * - * Sync flush all works belonging to @tty. + * Sync flush all works belonging to @tty (and the 'other' tty). */ static void tty_flush_works(struct tty_struct *tty) { flush_work(&tty->SAK_work); flush_work(&tty->hangup_work); + if (tty->link) { + flush_work(&tty->link->SAK_work); + flush_work(&tty->link->hangup_work); + } } /** @@ -1544,13 +1618,14 @@ static void release_one_tty(struct work_struct *work) struct tty_struct *tty = container_of(work, struct tty_struct, hangup_work); struct tty_driver *driver = tty->driver; + struct module *owner = driver->owner; if (tty->ops->cleanup) tty->ops->cleanup(tty); tty->magic = 0; tty_driver_kref_put(driver); - module_put(driver->owner); + module_put(owner); spin_lock(&tty_files_lock); list_del_init(&tty->tty_files); @@ -1612,8 +1687,7 @@ static void release_tty(struct tty_struct *tty, int idx) tty->link->port->itty = NULL; cancel_work_sync(&tty->port->buf.work); - if (tty->link) - tty_kref_put(tty->link); + tty_kref_put(tty->link); tty_kref_put(tty); } @@ -1626,8 +1700,7 @@ static void release_tty(struct tty_struct *tty, int idx) * Performs some paranoid checking before true release of the @tty. * This is a no-op unless TTY_PARANOIA_CHECK is defined. */ -static int tty_release_checks(struct tty_struct *tty, struct tty_struct *o_tty, - int idx) +static int tty_release_checks(struct tty_struct *tty, int idx) { #ifdef TTY_PARANOIA_CHECK if (idx < 0 || idx >= tty->driver->num) { @@ -1646,6 +1719,8 @@ static int tty_release_checks(struct tty_struct *tty, struct tty_struct *o_tty, return -1; } if (tty->driver->other) { + struct tty_struct *o_tty = tty->link; + 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); @@ -1682,10 +1757,12 @@ static int tty_release_checks(struct tty_struct *tty, struct tty_struct *o_tty, int tty_release(struct inode *inode, struct file *filp) { struct tty_struct *tty = file_tty(filp); - struct tty_struct *o_tty; - int pty_master, tty_closing, o_tty_closing, do_sleep; + struct tty_struct *o_tty = NULL; + int do_sleep, final; int idx; char buf[64]; + long timeout = 0; + int once = 1; if (tty_paranoia_check(tty, inode, __func__)) return 0; @@ -1696,12 +1773,11 @@ int tty_release(struct inode *inode, struct file *filp) __tty_fasync(-1, filp, 0); idx = tty->index; - pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY && - tty->driver->subtype == PTY_TYPE_MASTER); - /* Review: parallel close */ - o_tty = tty->link; + if (tty->driver->type == TTY_DRIVER_TYPE_PTY && + tty->driver->subtype == PTY_TYPE_MASTER) + o_tty = tty->link; - if (tty_release_checks(tty, o_tty, idx)) { + if (tty_release_checks(tty, idx)) { tty_unlock(tty); return 0; } @@ -1714,7 +1790,9 @@ int tty_release(struct inode *inode, struct file *filp) if (tty->ops->close) tty->ops->close(tty, filp); - tty_unlock(tty); + /* If tty is pty master, lock the slave pty (stable lock order) */ + tty_lock_slave(o_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 @@ -1725,25 +1803,13 @@ int tty_release(struct inode *inode, struct file *filp) * The test for the o_tty closing is necessary, since the master and * slave sides may close in any order. If the slave side closes out * first, its count will be one, since the master side holds an open. - * Thus this test wouldn't be triggered at the time the slave closes, + * Thus this test wouldn't be triggered at the time the slave closed, * so we do it now. - * - * Note that it's possible for the tty to be opened again while we're - * flushing out waiters. By recalculating the closing flags before - * each iteration we avoid any problems. */ while (1) { - /* Guard against races with tty->count changes elsewhere and - opens on /dev/tty */ - - mutex_lock(&tty_mutex); - tty_lock_pair(tty, o_tty); - tty_closing = tty->count <= 1; - o_tty_closing = o_tty && - (o_tty->count <= (pty_master ? 1 : 0)); do_sleep = 0; - if (tty_closing) { + if (tty->count <= 1) { if (waitqueue_active(&tty->read_wait)) { wake_up_poll(&tty->read_wait, POLLIN); do_sleep++; @@ -1753,7 +1819,7 @@ int tty_release(struct inode *inode, struct file *filp) do_sleep++; } } - if (o_tty_closing) { + if (o_tty && o_tty->count <= 1) { if (waitqueue_active(&o_tty->read_wait)) { wake_up_poll(&o_tty->read_wait, POLLIN); do_sleep++; @@ -1766,22 +1832,19 @@ int tty_release(struct inode *inode, struct file *filp) if (!do_sleep) break; - printk(KERN_WARNING "%s: %s: read/write wait queue active!\n", - __func__, tty_name(tty, buf)); - tty_unlock_pair(tty, o_tty); - mutex_unlock(&tty_mutex); - schedule(); + if (once) { + once = 0; + printk(KERN_WARNING "%s: %s: read/write wait queue active!\n", + __func__, tty_name(tty, buf)); + } + schedule_timeout_killable(timeout); + if (timeout < 120 * HZ) + timeout = 2 * timeout + 1; + else + timeout = MAX_SCHEDULE_TIMEOUT; } - /* - * 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) { if (--o_tty->count < 0) { printk(KERN_WARNING "%s: bad pty slave count (%d) for %s\n", __func__, o_tty->count, tty_name(o_tty, buf)); @@ -1808,21 +1871,11 @@ int tty_release(struct inode *inode, struct file *filp) /* * Perform some housekeeping before deciding whether to return. * - * Set the TTY_CLOSING flag if this was the last open. In the - * case of a pty we may have to wait around for the other side - * to close, and TTY_CLOSING makes sure we can't be reopened. - */ - if (tty_closing) - set_bit(TTY_CLOSING, &tty->flags); - if (o_tty_closing) - set_bit(TTY_CLOSING, &o_tty->flags); - - /* * If _either_ side is closing, make sure there aren't any * processes that still think tty or o_tty is their controlling * tty. */ - if (tty_closing || o_tty_closing) { + if (!tty->count) { read_lock(&tasklist_lock); session_clear_tty(tty->session); if (o_tty) @@ -1830,13 +1883,16 @@ int tty_release(struct inode *inode, struct file *filp) read_unlock(&tasklist_lock); } - mutex_unlock(&tty_mutex); - tty_unlock_pair(tty, o_tty); - /* At this point the TTY_CLOSING flag should ensure a dead tty + /* check whether both sides are closing ... */ + final = !tty->count && !(o_tty && o_tty->count); + + tty_unlock_slave(o_tty); + tty_unlock(tty); + + /* At this point, the tty->count == 0 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)) + if (!final) return 0; #ifdef TTY_DEBUG_HANGUP @@ -1845,12 +1901,10 @@ int tty_release(struct inode *inode, struct file *filp) /* * Ask the line discipline code to release its structures */ - tty_ldisc_release(tty, o_tty); + tty_ldisc_release(tty); /* Wait for pending work before tty destruction commmences */ tty_flush_works(tty); - if (o_tty) - tty_flush_works(o_tty); #ifdef TTY_DEBUG_HANGUP printk(KERN_DEBUG "%s: %s: freeing structure...\n", __func__, tty_name(tty, buf)); @@ -1869,20 +1923,20 @@ int tty_release(struct inode *inode, struct file *filp) } /** - * tty_open_current_tty - get tty of current task for open + * tty_open_current_tty - get locked tty of current task * @device: device number * @filp: file pointer to tty - * @return: tty of the current task iff @device is /dev/tty + * @return: locked tty of the current task iff @device is /dev/tty + * + * Performs a re-open of the current task's controlling tty. * * We cannot return driver and index like for the other nodes because * devpts will not work then. It expects inodes to be from devpts FS. - * - * We need to move to returning a refcounted object from all the lookup - * paths including this one. */ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp) { struct tty_struct *tty; + int retval; if (device != MKDEV(TTYAUX_MAJOR, 0)) return NULL; @@ -1893,9 +1947,14 @@ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp) filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */ /* noctty = 1; */ - tty_kref_put(tty); - /* FIXME: we put a reference and return a TTY! */ - /* This is only safe because the caller holds tty_mutex */ + tty_lock(tty); + tty_kref_put(tty); /* safe to drop the kref now */ + + retval = tty_reopen(tty); + if (retval < 0) { + tty_unlock(tty); + tty = ERR_PTR(retval); + } return tty; } @@ -1993,13 +2052,9 @@ retry_open: index = -1; retval = 0; - mutex_lock(&tty_mutex); - /* This is protected by the tty_mutex */ tty = tty_open_current_tty(device, filp); - if (IS_ERR(tty)) { - retval = PTR_ERR(tty); - goto err_unlock; - } else if (!tty) { + if (!tty) { + mutex_lock(&tty_mutex); driver = tty_lookup_driver(device, filp, &noctty, &index); if (IS_ERR(driver)) { retval = PTR_ERR(driver); @@ -2012,21 +2067,25 @@ retry_open: retval = PTR_ERR(tty); goto err_unlock; } - } - if (tty) { - tty_lock(tty); - retval = tty_reopen(tty); - if (retval < 0) { - tty_unlock(tty); - tty = ERR_PTR(retval); + if (tty) { + mutex_unlock(&tty_mutex); + tty_lock(tty); + /* safe to drop the kref from tty_driver_lookup_tty() */ + tty_kref_put(tty); + retval = tty_reopen(tty); + if (retval < 0) { + tty_unlock(tty); + tty = ERR_PTR(retval); + } + } else { /* Returns with the tty_lock held for now */ + tty = tty_init_dev(driver, index); + mutex_unlock(&tty_mutex); } - } 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)) { retval = PTR_ERR(tty); goto err_file; @@ -2068,25 +2127,23 @@ retry_open: /* * Need to reset f_op in case a hangup happened. */ - if (filp->f_op == &hung_up_tty_fops) + if (tty_hung_up_p(filp)) filp->f_op = &tty_fops; goto retry_open; } clear_bit(TTY_HUPPED, &tty->flags); - tty_unlock(tty); - mutex_lock(&tty_mutex); - tty_lock(tty); + read_lock(&tasklist_lock); spin_lock_irq(¤t->sighand->siglock); if (!noctty && current->signal->leader && !current->signal->tty && tty->session == NULL) - __proc_set_tty(current, tty); + __proc_set_tty(tty); spin_unlock_irq(¤t->sighand->siglock); + read_unlock(&tasklist_lock); tty_unlock(tty); - mutex_unlock(&tty_mutex); return 0; err_unlock: mutex_unlock(&tty_mutex); @@ -2123,7 +2180,7 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait) ld = tty_ldisc_ref_wait(tty); if (ld->ops->poll) - ret = (ld->ops->poll)(tty, filp, wait); + ret = ld->ops->poll(tty, filp, wait); tty_ldisc_deref(ld); return ret; } @@ -2163,8 +2220,9 @@ static int __tty_fasync(int fd, struct file *filp, int on) } get_pid(pid); spin_unlock_irqrestore(&tty->ctrl_lock, flags); - retval = __f_setown(filp, pid, type, 0); + __f_setown(filp, pid, type, 0); put_pid(pid); + retval = 0; } out: return retval; @@ -2250,18 +2308,14 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg) int tty_do_resize(struct tty_struct *tty, struct winsize *ws) { struct pid *pgrp; - unsigned long flags; /* Lock the tty */ mutex_lock(&tty->winsize_mutex); if (!memcmp(ws, &tty->winsize, sizeof(*ws))) goto done; - /* Get the PID values and reference them so we can - avoid holding the tty ctrl lock while sending signals */ - spin_lock_irqsave(&tty->ctrl_lock, flags); - pgrp = get_pid(tty->pgrp); - spin_unlock_irqrestore(&tty->ctrl_lock, flags); + /* Signal the foreground process group */ + pgrp = tty_get_pgrp(tty); if (pgrp) kill_pgrp(pgrp, SIGWINCH, 1); put_pid(pgrp); @@ -2370,7 +2424,7 @@ static int fionbio(struct file *file, int __user *p) * leader to set this tty as the controlling tty for the session. * * Locking: - * Takes tty_mutex() to protect tty instance + * Takes tty_lock() to serialize proc_set_tty() for this tty * Takes tasklist_lock internally to walk sessions * Takes ->siglock() when updating signal->tty */ @@ -2378,10 +2432,13 @@ static int fionbio(struct file *file, int __user *p) static int tiocsctty(struct tty_struct *tty, int arg) { int ret = 0; + + tty_lock(tty); + read_lock(&tasklist_lock); + if (current->signal->leader && (task_session(current) == tty->session)) - return ret; + goto unlock; - mutex_lock(&tty_mutex); /* * The process must be a session leader and * not have a controlling tty already. @@ -2400,17 +2457,16 @@ static int tiocsctty(struct tty_struct *tty, int arg) /* * Steal it away */ - read_lock(&tasklist_lock); session_clear_tty(tty->session); - read_unlock(&tasklist_lock); } else { ret = -EPERM; goto unlock; } } - proc_set_tty(current, tty); + proc_set_tty(tty); unlock: - mutex_unlock(&tty_mutex); + read_unlock(&tasklist_lock); + tty_unlock(tty); return ret; } @@ -2435,6 +2491,27 @@ struct pid *tty_get_pgrp(struct tty_struct *tty) } EXPORT_SYMBOL_GPL(tty_get_pgrp); +/* + * This checks not only the pgrp, but falls back on the pid if no + * satisfactory pgrp is found. I dunno - gdb doesn't work correctly + * without this... + * + * The caller must hold rcu lock or the tasklist lock. + */ +static struct pid *session_of_pgrp(struct pid *pgrp) +{ + struct task_struct *p; + struct pid *sid = NULL; + + p = pid_task(pgrp, PIDTYPE_PGID); + if (p == NULL) + p = pid_task(pgrp, PIDTYPE_PID); + if (p != NULL) + sid = task_session(p); + + return sid; +} + /** * tiocgpgrp - get process group * @tty: tty passed by user @@ -2681,23 +2758,35 @@ static int tty_tiocgicount(struct tty_struct *tty, void __user *arg) return 0; } -struct tty_struct *tty_pair_get_tty(struct tty_struct *tty) +static void tty_warn_deprecated_flags(struct serial_struct __user *ss) { - if (tty->driver->type == TTY_DRIVER_TYPE_PTY && - tty->driver->subtype == PTY_TYPE_MASTER) - tty = tty->link; - return tty; + static DEFINE_RATELIMIT_STATE(depr_flags, + DEFAULT_RATELIMIT_INTERVAL, + DEFAULT_RATELIMIT_BURST); + char comm[TASK_COMM_LEN]; + int flags; + + if (get_user(flags, &ss->flags)) + return; + + flags &= ASYNC_DEPRECATED; + + if (flags && __ratelimit(&depr_flags)) + pr_warning("%s: '%s' is using deprecated serial flags (with no effect): %.8x\n", + __func__, get_task_comm(comm, current), flags); } -EXPORT_SYMBOL(tty_pair_get_tty); -struct tty_struct *tty_pair_get_pty(struct tty_struct *tty) +/* + * if pty, return the slave side (real_tty) + * otherwise, return self + */ +static struct tty_struct *tty_pair_get_tty(struct tty_struct *tty) { if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER) - return tty; - return tty->link; + tty = tty->link; + return tty; } -EXPORT_SYMBOL(tty_pair_get_pty); /* * Split this up, as gcc can choke on it otherwise.. @@ -2826,13 +2915,16 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case TCIFLUSH: case TCIOFLUSH: /* flush tty buffer and allow ldisc to process ioctl */ - tty_buffer_flush(tty); + tty_buffer_flush(tty, NULL); break; } break; + case TIOCSSERIAL: + tty_warn_deprecated_flags(p); + break; } if (tty->ops->ioctl) { - retval = (tty->ops->ioctl)(tty, cmd, arg); + retval = tty->ops->ioctl(tty, cmd, arg); if (retval != -ENOIOCTLCMD) return retval; } @@ -2859,7 +2951,7 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd, return -EINVAL; if (tty->ops->compat_ioctl) { - retval = (tty->ops->compat_ioctl)(tty, cmd, arg); + retval = tty->ops->compat_ioctl(tty, cmd, arg); if (retval != -ENOIOCTLCMD) return retval; } @@ -3018,6 +3110,7 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx) INIT_WORK(&tty->hangup_work, do_tty_hangup); mutex_init(&tty->atomic_write_lock); spin_lock_init(&tty->ctrl_lock); + spin_lock_init(&tty->flow_lock); INIT_LIST_HEAD(&tty->tty_files); INIT_WORK(&tty->SAK_work, do_SAK_work); @@ -3409,59 +3502,6 @@ dev_t tty_devnum(struct tty_struct *tty) } EXPORT_SYMBOL(tty_devnum); -void proc_clear_tty(struct task_struct *p) -{ - unsigned long flags; - struct tty_struct *tty; - spin_lock_irqsave(&p->sighand->siglock, flags); - tty = p->signal->tty; - p->signal->tty = NULL; - spin_unlock_irqrestore(&p->sighand->siglock, flags); - tty_kref_put(tty); -} - -/* Called under the sighand lock */ - -static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) -{ - if (tty) { - unsigned long flags; - /* We should not have a session or pgrp to put here but.... */ - spin_lock_irqsave(&tty->ctrl_lock, flags); - put_pid(tty->session); - put_pid(tty->pgrp); - tty->pgrp = get_pid(task_pgrp(tsk)); - spin_unlock_irqrestore(&tty->ctrl_lock, flags); - tty->session = get_pid(task_session(tsk)); - if (tsk->signal->tty) { - printk(KERN_DEBUG "tty not NULL!!\n"); - tty_kref_put(tsk->signal->tty); - } - } - put_pid(tsk->signal->tty_old_pgrp); - tsk->signal->tty = tty_kref_get(tty); - tsk->signal->tty_old_pgrp = NULL; -} - -static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) -{ - spin_lock_irq(&tsk->sighand->siglock); - __proc_set_tty(tsk, tty); - spin_unlock_irq(&tsk->sighand->siglock); -} - -struct tty_struct *get_current_tty(void) -{ - struct tty_struct *tty; - unsigned long flags; - - spin_lock_irqsave(¤t->sighand->siglock, flags); - tty = tty_kref_get(current->signal->tty); - spin_unlock_irqrestore(¤t->sighand->siglock, flags); - return tty; -} -EXPORT_SYMBOL_GPL(get_current_tty); - void tty_default_fops(struct file_operations *fops) { *fops = tty_fops; diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 6fd60fece6b4..1787fa4d9448 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -402,7 +402,7 @@ void tty_termios_encode_baud_rate(struct ktermios *termios, #ifdef BOTHER /* If the user asked for a precise weird speed give a precise weird - answer. If they asked for a Bfoo speed they many have problems + answer. If they asked for a Bfoo speed they may have problems digesting non-exact replies so fuzz a bit */ if ((termios->c_cflag & CBAUD) == BOTHER) @@ -524,9 +524,8 @@ EXPORT_SYMBOL(tty_termios_hw_change); * @tty: tty to update * @new_termios: desired new value * - * Perform updates to the termios values set on this terminal. There - * is a bit of layering violation here with n_tty in terms of the - * internal knowledge of this function. + * Perform updates to the termios values set on this terminal. + * A master pty's termios should never be set. * * Locking: termios_rwsem */ @@ -535,8 +534,9 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios) { struct ktermios old_termios; struct tty_ldisc *ld; - unsigned long flags; + WARN_ON(tty->driver->type == TTY_DRIVER_TYPE_PTY && + tty->driver->subtype == PTY_TYPE_MASTER); /* * Perform the actual termios internal changes under lock. */ @@ -549,41 +549,15 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_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); - int old_flow = ((old_termios.c_iflag & IXON) && - (old_termios.c_cc[VSTOP] == '\023') && - (old_termios.c_cc[VSTART] == '\021')); - int new_flow = (I_IXON(tty) && - STOP_CHAR(tty) == '\023' && - START_CHAR(tty) == '\021'); - if ((old_flow != new_flow) || extproc) { - spin_lock_irqsave(&tty->ctrl_lock, flags); - if (old_flow != new_flow) { - tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP); - if (new_flow) - tty->ctrl_status |= TIOCPKT_DOSTOP; - else - tty->ctrl_status |= TIOCPKT_NOSTOP; - } - if (extproc) - tty->ctrl_status |= TIOCPKT_IOCTL; - spin_unlock_irqrestore(&tty->ctrl_lock, flags); - wake_up_interruptible(&tty->link->read_wait); - } - } - if (tty->ops->set_termios) - (*tty->ops->set_termios)(tty, &old_termios); + tty->ops->set_termios(tty, &old_termios); else tty_termios_copy_hw(&tty->termios, &old_termios); ld = tty_ldisc_ref(tty); if (ld != NULL) { if (ld->ops->set_termios) - (ld->ops->set_termios)(tty, &old_termios); + ld->ops->set_termios(tty, &old_termios); tty_ldisc_deref(ld); } up_write(&tty->termios_rwsem); @@ -912,35 +886,6 @@ static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars) #endif /** - * send_prio_char - send priority character - * - * Send a high priority character to the tty even if stopped - * - * Locking: none for xchar method, write ordering for write method. - */ - -static int send_prio_char(struct tty_struct *tty, char ch) -{ - int was_stopped = tty->stopped; - - if (tty->ops->send_xchar) { - tty->ops->send_xchar(tty, ch); - return 0; - } - - if (tty_write_lock(tty, 0) < 0) - return -ERESTARTSYS; - - if (was_stopped) - start_tty(tty); - tty->ops->write(tty, &ch, 1); - if (was_stopped) - stop_tty(tty); - tty_write_unlock(tty); - return 0; -} - -/** * tty_change_softcar - carrier change ioctl helper * @tty: tty to update * @arg: enable/disable CLOCAL @@ -1177,29 +1122,37 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, return retval; switch (arg) { case TCOOFF: + spin_lock_irq(&tty->flow_lock); if (!tty->flow_stopped) { tty->flow_stopped = 1; - stop_tty(tty); + __stop_tty(tty); } + spin_unlock_irq(&tty->flow_lock); break; case TCOON: + spin_lock_irq(&tty->flow_lock); if (tty->flow_stopped) { tty->flow_stopped = 0; - start_tty(tty); + __start_tty(tty); } + spin_unlock_irq(&tty->flow_lock); break; case TCIOFF: + down_read(&tty->termios_rwsem); if (STOP_CHAR(tty) != __DISABLED_CHAR) - return send_prio_char(tty, STOP_CHAR(tty)); + retval = tty_send_xchar(tty, STOP_CHAR(tty)); + up_read(&tty->termios_rwsem); break; case TCION: + down_read(&tty->termios_rwsem); if (START_CHAR(tty) != __DISABLED_CHAR) - return send_prio_char(tty, START_CHAR(tty)); + retval = tty_send_xchar(tty, START_CHAR(tty)); + up_read(&tty->termios_rwsem); break; default: return -EINVAL; } - return 0; + return retval; case TCFLSH: retval = tty_check_change(tty); if (retval) diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 2d822aa259b2..3737f55272d2 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -308,48 +308,66 @@ EXPORT_SYMBOL_GPL(tty_ldisc_deref); static inline int __lockfunc -tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout) +__tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout) { return ldsem_down_write(&tty->ldisc_sem, timeout); } static inline int __lockfunc -tty_ldisc_lock_nested(struct tty_struct *tty, unsigned long timeout) +__tty_ldisc_lock_nested(struct tty_struct *tty, unsigned long timeout) { return ldsem_down_write_nested(&tty->ldisc_sem, LDISC_SEM_OTHER, timeout); } -static inline void tty_ldisc_unlock(struct tty_struct *tty) +static inline void __tty_ldisc_unlock(struct tty_struct *tty) { return ldsem_up_write(&tty->ldisc_sem); } static int __lockfunc +tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout) +{ + int ret; + + ret = __tty_ldisc_lock(tty, timeout); + if (!ret) + return -EBUSY; + set_bit(TTY_LDISC_HALTED, &tty->flags); + return 0; +} + +static void tty_ldisc_unlock(struct tty_struct *tty) +{ + clear_bit(TTY_LDISC_HALTED, &tty->flags); + __tty_ldisc_unlock(tty); +} + +static int __lockfunc tty_ldisc_lock_pair_timeout(struct tty_struct *tty, struct tty_struct *tty2, unsigned long timeout) { int ret; if (tty < tty2) { - ret = tty_ldisc_lock(tty, timeout); + ret = __tty_ldisc_lock(tty, timeout); if (ret) { - ret = tty_ldisc_lock_nested(tty2, timeout); + ret = __tty_ldisc_lock_nested(tty2, timeout); if (!ret) - tty_ldisc_unlock(tty); + __tty_ldisc_unlock(tty); } } else { /* if this is possible, it has lots of implications */ WARN_ON_ONCE(tty == tty2); if (tty2 && tty != tty2) { - ret = tty_ldisc_lock(tty2, timeout); + ret = __tty_ldisc_lock(tty2, timeout); if (ret) { - ret = tty_ldisc_lock_nested(tty, timeout); + ret = __tty_ldisc_lock_nested(tty, timeout); if (!ret) - tty_ldisc_unlock(tty2); + __tty_ldisc_unlock(tty2); } } else - ret = tty_ldisc_lock(tty, timeout); + ret = __tty_ldisc_lock(tty, timeout); } if (!ret) @@ -370,38 +388,26 @@ tty_ldisc_lock_pair(struct tty_struct *tty, struct tty_struct *tty2) static void __lockfunc tty_ldisc_unlock_pair(struct tty_struct *tty, struct tty_struct *tty2) { - tty_ldisc_unlock(tty); - if (tty2) - tty_ldisc_unlock(tty2); -} - -static void __lockfunc tty_ldisc_enable_pair(struct tty_struct *tty, - struct tty_struct *tty2) -{ - clear_bit(TTY_LDISC_HALTED, &tty->flags); + __tty_ldisc_unlock(tty); if (tty2) - clear_bit(TTY_LDISC_HALTED, &tty2->flags); - - tty_ldisc_unlock_pair(tty, tty2); + __tty_ldisc_unlock(tty2); } /** * tty_ldisc_flush - flush line discipline queue * @tty: tty * - * Flush the line discipline queue (if any) for this tty. If there - * is no line discipline active this is a no-op. + * Flush the line discipline queue (if any) and the tty flip buffers + * for this tty. */ void tty_ldisc_flush(struct tty_struct *tty) { struct tty_ldisc *ld = tty_ldisc_ref(tty); - if (ld) { - if (ld->ops->flush_buffer) - ld->ops->flush_buffer(tty); + + tty_buffer_flush(tty, ld); + if (ld) tty_ldisc_deref(ld); - } - tty_buffer_flush(tty); } EXPORT_SYMBOL_GPL(tty_ldisc_flush); @@ -517,15 +523,16 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) { int retval; struct tty_ldisc *old_ldisc, *new_ldisc; - struct tty_struct *o_tty = tty->link; new_ldisc = tty_ldisc_get(tty, ldisc); if (IS_ERR(new_ldisc)) return PTR_ERR(new_ldisc); - retval = tty_ldisc_lock_pair_timeout(tty, o_tty, 5 * HZ); + tty_lock(tty); + retval = tty_ldisc_lock(tty, 5 * HZ); if (retval) { tty_ldisc_put(new_ldisc); + tty_unlock(tty); return retval; } @@ -534,19 +541,18 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) */ if (tty->ldisc->ops->num == ldisc) { - tty_ldisc_enable_pair(tty, o_tty); + tty_ldisc_unlock(tty); tty_ldisc_put(new_ldisc); + tty_unlock(tty); return 0; } old_ldisc = tty->ldisc; - tty_lock(tty); - if (test_bit(TTY_HUPPING, &tty->flags) || - test_bit(TTY_HUPPED, &tty->flags)) { + if (test_bit(TTY_HUPPED, &tty->flags)) { /* We were raced by the hangup method. It will have stomped the ldisc data and closed the ldisc down */ - tty_ldisc_enable_pair(tty, o_tty); + tty_ldisc_unlock(tty); tty_ldisc_put(new_ldisc); tty_unlock(tty); return -EIO; @@ -566,8 +572,11 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) tty_ldisc_restore(tty, old_ldisc); } - if (tty->ldisc->ops->num != old_ldisc->ops->num && tty->ops->set_ldisc) + if (tty->ldisc->ops->num != old_ldisc->ops->num && tty->ops->set_ldisc) { + down_read(&tty->termios_rwsem); tty->ops->set_ldisc(tty); + up_read(&tty->termios_rwsem); + } /* At this point we hold a reference to the new ldisc and a reference to the old ldisc, or we hold two references to @@ -580,13 +589,11 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) /* * Allow ldisc referencing to occur again */ - tty_ldisc_enable_pair(tty, o_tty); + tty_ldisc_unlock(tty); /* Restart the work queue in case no characters kick it off. Safe if already running */ schedule_work(&tty->port->buf.work); - if (o_tty) - schedule_work(&o_tty->port->buf.work); tty_unlock(tty); return retval; @@ -675,16 +682,13 @@ void tty_ldisc_hangup(struct tty_struct *tty) wake_up_interruptible_poll(&tty->write_wait, POLLOUT); wake_up_interruptible_poll(&tty->read_wait, POLLIN); - tty_unlock(tty); - /* * Shutdown the current line discipline, and reset it to * N_TTY if need be. * * Avoid racing set_ldisc or tty_ldisc_release */ - tty_ldisc_lock_pair(tty, tty->link); - tty_lock(tty); + tty_ldisc_lock(tty, MAX_SCHEDULE_TIMEOUT); if (tty->ldisc) { @@ -706,7 +710,7 @@ void tty_ldisc_hangup(struct tty_struct *tty) WARN_ON(tty_ldisc_open(tty, tty->ldisc)); } } - tty_ldisc_enable_pair(tty, tty->link); + tty_ldisc_unlock(tty); if (reset) tty_reset_termios(tty); @@ -758,16 +762,17 @@ static void tty_ldisc_kill(struct tty_struct *tty) /** * tty_ldisc_release - release line discipline - * @tty: tty being shut down - * @o_tty: pair tty for pty/tty pairs + * @tty: tty being shut down (or one end of pty pair) * - * Called during the final close of a tty/pty pair in order to shut down - * the line discpline layer. On exit the ldisc assigned is N_TTY and the - * ldisc has not been opened. + * Called during the final close of a tty or a pty pair in order to shut + * down the line discpline layer. On exit, each ldisc assigned is N_TTY and + * each ldisc has not been opened. */ -void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) +void tty_ldisc_release(struct tty_struct *tty) { + struct tty_struct *o_tty = tty->link; + /* * Shutdown this line discipline. As this is the final close, * it does not race with the set_ldisc code path. @@ -776,13 +781,9 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc); tty_ldisc_lock_pair(tty, o_tty); - tty_lock_pair(tty, o_tty); - tty_ldisc_kill(tty); if (o_tty) tty_ldisc_kill(o_tty); - - tty_unlock_pair(tty, o_tty); tty_ldisc_unlock_pair(tty, o_tty); /* And the memory resources remaining (buffers, termios) will be diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c index 2e41abebbcba..4486741190c4 100644 --- a/drivers/tty/tty_mutex.c +++ b/drivers/tty/tty_mutex.c @@ -4,19 +4,23 @@ #include <linux/semaphore.h> #include <linux/sched.h> +/* + * Nested tty locks are necessary for releasing pty pairs. + * The stable lock order is master pty first, then slave pty. + */ + /* Legacy tty mutex glue */ enum { TTY_MUTEX_NORMAL, - TTY_MUTEX_NESTED, + TTY_MUTEX_SLAVE, }; /* * Getting the big tty mutex. */ -static void __lockfunc tty_lock_nested(struct tty_struct *tty, - unsigned int subclass) +void __lockfunc tty_lock(struct tty_struct *tty) { if (tty->magic != TTY_MAGIC) { pr_err("L Bad %p\n", tty); @@ -24,12 +28,7 @@ static void __lockfunc tty_lock_nested(struct tty_struct *tty, 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); + mutex_lock(&tty->legacy_mutex); } EXPORT_SYMBOL(tty_lock); @@ -45,29 +44,23 @@ void __lockfunc tty_unlock(struct tty_struct *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) +void __lockfunc tty_lock_slave(struct tty_struct *tty) { - if (tty < tty2) { + if (tty && tty != tty->link) { + WARN_ON(!mutex_is_locked(&tty->link->legacy_mutex) || + !tty->driver->type == TTY_DRIVER_TYPE_PTY || + !tty->driver->type == PTY_TYPE_SLAVE); 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) +void __lockfunc tty_unlock_slave(struct tty_struct *tty) +{ + if (tty && tty != tty->link) + tty_unlock(tty); +} + +void tty_set_lock_subclass(struct tty_struct *tty) { - tty_unlock(tty); - if (tty2 && tty2 != tty) - tty_unlock(tty2); + lockdep_set_subclass(&tty->legacy_mutex, TTY_MUTEX_SLAVE); } -EXPORT_SYMBOL(tty_unlock_pair); diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 1b9335796da4..40b31835f80b 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -193,8 +193,7 @@ void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty) unsigned long flags; spin_lock_irqsave(&port->lock, flags); - if (port->tty) - tty_kref_put(port->tty); + tty_kref_put(port->tty); port->tty = tty_kref_get(tty); spin_unlock_irqrestore(&port->lock, flags); } @@ -473,12 +472,10 @@ int tty_port_close_start(struct tty_port *port, { unsigned long flags; - spin_lock_irqsave(&port->lock, flags); - if (tty_hung_up_p(filp)) { - spin_unlock_irqrestore(&port->lock, flags); + if (tty_hung_up_p(filp)) return 0; - } + spin_lock_irqsave(&port->lock, flags); if (tty->count == 1 && port->count != 1) { printk(KERN_WARNING "tty_port_close_start: tty->count = 1 port count = %d.\n", @@ -522,6 +519,7 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty) { unsigned long flags; + tty_ldisc_flush(tty); tty->closing = 0; spin_lock_irqsave(&port->lock, flags); diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 610b720d3b91..59b25e039968 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -539,6 +539,12 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) /* Save original vc_unipagdir_loc in case we allocate a new one */ p = *vc->vc_uni_pagedir_loc; + + if (!p) { + err = -EINVAL; + + goto out_unlock; + } if (p->refcount > 1) { int j, k; @@ -623,6 +629,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) set_inverse_transl(vc, p, i); /* Update inverse translations */ set_inverse_trans_unicode(vc, p); +out_unlock: console_unlock(); return err; } diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index d0e3a4497707..8a89f6e7715d 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -268,30 +268,30 @@ EXPORT_SYMBOL(kd_mksound); static int kbd_rate_helper(struct input_handle *handle, void *data) { struct input_dev *dev = handle->dev; - struct kbd_repeat *rep = data; + struct kbd_repeat *rpt = data; if (test_bit(EV_REP, dev->evbit)) { - if (rep[0].delay > 0) + if (rpt[0].delay > 0) input_inject_event(handle, - EV_REP, REP_DELAY, rep[0].delay); - if (rep[0].period > 0) + EV_REP, REP_DELAY, rpt[0].delay); + if (rpt[0].period > 0) input_inject_event(handle, - EV_REP, REP_PERIOD, rep[0].period); + EV_REP, REP_PERIOD, rpt[0].period); - rep[1].delay = dev->rep[REP_DELAY]; - rep[1].period = dev->rep[REP_PERIOD]; + rpt[1].delay = dev->rep[REP_DELAY]; + rpt[1].period = dev->rep[REP_PERIOD]; } return 0; } -int kbd_rate(struct kbd_repeat *rep) +int kbd_rate(struct kbd_repeat *rpt) { - struct kbd_repeat data[2] = { *rep }; + struct kbd_repeat data[2] = { *rpt }; input_handler_for_each_handle(&kbd_handler, data, kbd_rate_helper); - *rep = data[1]; /* Copy currently used settings */ + *rpt = data[1]; /* Copy currently used settings */ return 0; } @@ -924,7 +924,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) if (kbd->kbdmode != VC_UNICODE) { if (!up_flag) - pr_warning("keyboard mode must be unicode for braille patterns\n"); + pr_warn("keyboard mode must be unicode for braille patterns\n"); return; } @@ -971,15 +971,15 @@ static unsigned char getledstate(void) return ledstate; } -void setledstate(struct kbd_struct *kbd, unsigned int led) +void setledstate(struct kbd_struct *kb, unsigned int led) { unsigned long flags; spin_lock_irqsave(&led_lock, flags); if (!(led & ~7)) { ledioctl = led; - kbd->ledmode = LED_SHOW_IOCTL; + kb->ledmode = LED_SHOW_IOCTL; } else - kbd->ledmode = LED_SHOW_FLAGS; + kb->ledmode = LED_SHOW_FLAGS; set_leds(); spin_unlock_irqrestore(&led_lock, flags); @@ -987,12 +987,12 @@ void setledstate(struct kbd_struct *kbd, unsigned int led) static inline unsigned char getleds(void) { - struct kbd_struct *kbd = kbd_table + fg_console; + struct kbd_struct *kb = kbd_table + fg_console; - if (kbd->ledmode == LED_SHOW_IOCTL) + if (kb->ledmode == LED_SHOW_IOCTL) return ledioctl; - return kbd->ledflagstate; + return kb->ledflagstate; } static int kbd_update_leds_helper(struct input_handle *handle, void *data) @@ -1018,12 +1018,12 @@ static int kbd_update_leds_helper(struct input_handle *handle, void *data) */ int vt_get_leds(int console, int flag) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; int ret; unsigned long flags; spin_lock_irqsave(&led_lock, flags); - ret = vc_kbd_led(kbd, flag); + ret = vc_kbd_led(kb, flag); spin_unlock_irqrestore(&led_lock, flags); return ret; @@ -1040,8 +1040,8 @@ EXPORT_SYMBOL_GPL(vt_get_leds); */ void vt_set_led_state(int console, int leds) { - struct kbd_struct * kbd = kbd_table + console; - setledstate(kbd, leds); + struct kbd_struct *kb = kbd_table + console; + setledstate(kb, leds); } /** @@ -1059,10 +1059,10 @@ void vt_set_led_state(int console, int leds) */ void vt_kbd_con_start(int console) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; unsigned long flags; spin_lock_irqsave(&led_lock, flags); - clr_vc_kbd_led(kbd, VC_SCROLLOCK); + clr_vc_kbd_led(kb, VC_SCROLLOCK); set_leds(); spin_unlock_irqrestore(&led_lock, flags); } @@ -1076,10 +1076,10 @@ void vt_kbd_con_start(int console) */ void vt_kbd_con_stop(int console) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; unsigned long flags; spin_lock_irqsave(&led_lock, flags); - set_vc_kbd_led(kbd, VC_SCROLLOCK); + set_vc_kbd_led(kb, VC_SCROLLOCK); set_leds(); spin_unlock_irqrestore(&led_lock, flags); } @@ -1253,8 +1253,8 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) if (raw_mode && !hw_raw) if (emulate_raw(vc, keycode, !down << 7)) if (keycode < BTN_MISC && printk_ratelimit()) - pr_warning("can't emulate rawmode for keycode %d\n", - keycode); + pr_warn("can't emulate rawmode for keycode %d\n", + keycode); #ifdef CONFIG_SPARC if (keycode == KEY_A && sparc_l1_a_state) { @@ -1512,15 +1512,14 @@ int __init kbd_init(void) /** * vt_do_diacrit - diacritical table updates * @cmd: ioctl request - * @up: pointer to user data for ioctl + * @udp: pointer to user data for ioctl * @perm: permissions check computed by caller * * Update the diacritical tables atomically and safely. Lock them * against simultaneous keypresses */ -int vt_do_diacrit(unsigned int cmd, void __user *up, int perm) +int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm) { - struct kbdiacrs __user *a = up; unsigned long flags; int asize; int ret = 0; @@ -1528,12 +1527,13 @@ int vt_do_diacrit(unsigned int cmd, void __user *up, int perm) switch (cmd) { case KDGKBDIACR: { - struct kbdiacr *diacr; + struct kbdiacrs __user *a = udp; + struct kbdiacr *dia; int i; - diacr = kmalloc(MAX_DIACR * sizeof(struct kbdiacr), + dia = kmalloc(MAX_DIACR * sizeof(struct kbdiacr), GFP_KERNEL); - if (diacr == NULL) + if (!dia) return -ENOMEM; /* Lock the diacriticals table, make a copy and then @@ -1542,26 +1542,26 @@ int vt_do_diacrit(unsigned int cmd, void __user *up, int perm) asize = accent_table_size; for (i = 0; i < asize; i++) { - diacr[i].diacr = conv_uni_to_8bit( + dia[i].diacr = conv_uni_to_8bit( accent_table[i].diacr); - diacr[i].base = conv_uni_to_8bit( + dia[i].base = conv_uni_to_8bit( accent_table[i].base); - diacr[i].result = conv_uni_to_8bit( + dia[i].result = conv_uni_to_8bit( accent_table[i].result); } spin_unlock_irqrestore(&kbd_event_lock, flags); if (put_user(asize, &a->kb_cnt)) ret = -EFAULT; - else if (copy_to_user(a->kbdiacr, diacr, + else if (copy_to_user(a->kbdiacr, dia, asize * sizeof(struct kbdiacr))) ret = -EFAULT; - kfree(diacr); + kfree(dia); return ret; } case KDGKBDIACRUC: { - struct kbdiacrsuc __user *a = up; + struct kbdiacrsuc __user *a = udp; void *buf; buf = kmalloc(MAX_DIACR * sizeof(struct kbdiacruc), @@ -1589,8 +1589,8 @@ int vt_do_diacrit(unsigned int cmd, void __user *up, int perm) case KDSKBDIACR: { - struct kbdiacrs __user *a = up; - struct kbdiacr *diacr = NULL; + struct kbdiacrs __user *a = udp; + struct kbdiacr *dia = NULL; unsigned int ct; int i; @@ -1602,14 +1602,14 @@ int vt_do_diacrit(unsigned int cmd, void __user *up, int perm) return -EINVAL; if (ct) { - diacr = kmalloc(sizeof(struct kbdiacr) * ct, + dia = kmalloc(sizeof(struct kbdiacr) * ct, GFP_KERNEL); - if (diacr == NULL) + if (!dia) return -ENOMEM; - if (copy_from_user(diacr, a->kbdiacr, + if (copy_from_user(dia, a->kbdiacr, sizeof(struct kbdiacr) * ct)) { - kfree(diacr); + kfree(dia); return -EFAULT; } } @@ -1618,20 +1618,20 @@ int vt_do_diacrit(unsigned int cmd, void __user *up, int perm) accent_table_size = ct; for (i = 0; i < ct; i++) { accent_table[i].diacr = - conv_8bit_to_uni(diacr[i].diacr); + conv_8bit_to_uni(dia[i].diacr); accent_table[i].base = - conv_8bit_to_uni(diacr[i].base); + conv_8bit_to_uni(dia[i].base); accent_table[i].result = - conv_8bit_to_uni(diacr[i].result); + conv_8bit_to_uni(dia[i].result); } spin_unlock_irqrestore(&kbd_event_lock, flags); - kfree(diacr); + kfree(dia); return 0; } case KDSKBDIACRUC: { - struct kbdiacrsuc __user *a = up; + struct kbdiacrsuc __user *a = udp; unsigned int ct; void *buf = NULL; @@ -1679,28 +1679,28 @@ int vt_do_diacrit(unsigned int cmd, void __user *up, int perm) */ int vt_do_kdskbmode(int console, unsigned int arg) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; int ret = 0; unsigned long flags; spin_lock_irqsave(&kbd_event_lock, flags); switch(arg) { case K_RAW: - kbd->kbdmode = VC_RAW; + kb->kbdmode = VC_RAW; break; case K_MEDIUMRAW: - kbd->kbdmode = VC_MEDIUMRAW; + kb->kbdmode = VC_MEDIUMRAW; break; case K_XLATE: - kbd->kbdmode = VC_XLATE; + kb->kbdmode = VC_XLATE; do_compute_shiftstate(); break; case K_UNICODE: - kbd->kbdmode = VC_UNICODE; + kb->kbdmode = VC_UNICODE; do_compute_shiftstate(); break; case K_OFF: - kbd->kbdmode = VC_OFF; + kb->kbdmode = VC_OFF; break; default: ret = -EINVAL; @@ -1719,17 +1719,17 @@ int vt_do_kdskbmode(int console, unsigned int arg) */ int vt_do_kdskbmeta(int console, unsigned int arg) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; int ret = 0; unsigned long flags; spin_lock_irqsave(&kbd_event_lock, flags); switch(arg) { case K_METABIT: - clr_vc_kbd_mode(kbd, VC_META); + clr_vc_kbd_mode(kb, VC_META); break; case K_ESCPREFIX: - set_vc_kbd_mode(kbd, VC_META); + set_vc_kbd_mode(kb, VC_META); break; default: ret = -EINVAL; @@ -1768,7 +1768,7 @@ int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, int console) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; struct kbentry tmp; ushort *key_map, *new_map, val, ov; unsigned long flags; @@ -1786,7 +1786,7 @@ int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, key_map = key_maps[s]; if (key_map) { val = U(key_map[i]); - if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) + if (kb->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) val = K_HOLE; } else val = (i ? K_HOLE : K_NOSUCHMAP); @@ -1814,7 +1814,7 @@ int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, if (KVAL(v) > max_vals[KTYP(v)]) return -EINVAL; } else - if (kbd->kbdmode != VC_UNICODE) + if (kb->kbdmode != VC_UNICODE) return -EINVAL; /* ++Geert: non-PC keyboards may generate keycode zero */ @@ -1985,7 +1985,7 @@ reterr: int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; unsigned long flags; unsigned char ucval; @@ -1994,7 +1994,7 @@ int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm) /* don't use them - they will go away without warning */ case KDGKBLED: spin_lock_irqsave(&kbd_event_lock, flags); - ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4); + ucval = kb->ledflagstate | (kb->default_ledflagstate << 4); spin_unlock_irqrestore(&kbd_event_lock, flags); return put_user(ucval, (char __user *)arg); @@ -2004,8 +2004,8 @@ int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm) if (arg & ~0x77) return -EINVAL; spin_lock_irqsave(&led_lock, flags); - kbd->ledflagstate = (arg & 7); - kbd->default_ledflagstate = ((arg >> 4) & 7); + kb->ledflagstate = (arg & 7); + kb->default_ledflagstate = ((arg >> 4) & 7); set_leds(); spin_unlock_irqrestore(&led_lock, flags); return 0; @@ -2019,7 +2019,7 @@ int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm) case KDSETLED: if (!perm) return -EPERM; - setledstate(kbd, arg); + setledstate(kb, arg); return 0; } return -ENOIOCTLCMD; @@ -2027,9 +2027,9 @@ int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm) int vt_do_kdgkbmode(int console) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; /* This is a spot read so needs no locking */ - switch (kbd->kbdmode) { + switch (kb->kbdmode) { case VC_RAW: return K_RAW; case VC_MEDIUMRAW: @@ -2051,9 +2051,9 @@ int vt_do_kdgkbmode(int console) */ int vt_do_kdgkbmeta(int console) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; /* Again a spot read so no locking */ - return vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT; + return vc_kbd_mode(kb, VC_META) ? K_ESCPREFIX : K_METABIT; } /** @@ -2092,19 +2092,19 @@ int vt_get_shift_state(void) */ void vt_reset_keyboard(int console) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; unsigned long flags; spin_lock_irqsave(&kbd_event_lock, flags); - set_vc_kbd_mode(kbd, VC_REPEAT); - clr_vc_kbd_mode(kbd, VC_CKMODE); - clr_vc_kbd_mode(kbd, VC_APPLIC); - clr_vc_kbd_mode(kbd, VC_CRLF); - kbd->lockstate = 0; - kbd->slockstate = 0; + set_vc_kbd_mode(kb, VC_REPEAT); + clr_vc_kbd_mode(kb, VC_CKMODE); + clr_vc_kbd_mode(kb, VC_APPLIC); + clr_vc_kbd_mode(kb, VC_CRLF); + kb->lockstate = 0; + kb->slockstate = 0; spin_lock(&led_lock); - kbd->ledmode = LED_SHOW_FLAGS; - kbd->ledflagstate = kbd->default_ledflagstate; + kb->ledmode = LED_SHOW_FLAGS; + kb->ledflagstate = kb->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 */ @@ -2122,8 +2122,8 @@ void vt_reset_keyboard(int console) int vt_get_kbd_mode_bit(int console, int bit) { - struct kbd_struct * kbd = kbd_table + console; - return vc_kbd_mode(kbd, bit); + struct kbd_struct *kb = kbd_table + console; + return vc_kbd_mode(kb, bit); } /** @@ -2137,11 +2137,11 @@ int vt_get_kbd_mode_bit(int console, int bit) void vt_set_kbd_mode_bit(int console, int bit) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; unsigned long flags; spin_lock_irqsave(&kbd_event_lock, flags); - set_vc_kbd_mode(kbd, bit); + set_vc_kbd_mode(kb, bit); spin_unlock_irqrestore(&kbd_event_lock, flags); } @@ -2156,10 +2156,10 @@ void vt_set_kbd_mode_bit(int console, int bit) void vt_clr_kbd_mode_bit(int console, int bit) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; unsigned long flags; spin_lock_irqsave(&kbd_event_lock, flags); - clr_vc_kbd_mode(kbd, bit); + clr_vc_kbd_mode(kb, bit); spin_unlock_irqrestore(&kbd_event_lock, flags); } diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index b33b00b386de..f3fbbbca9bde 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -156,6 +156,8 @@ static void console_callback(struct work_struct *ignored); static void blank_screen_t(unsigned long dummy); static void set_palette(struct vc_data *vc); +#define vt_get_kmsg_redirect() vt_kmsg_redirect(-1) + static int printable; /* Is console ready for printing? */ int default_utf8 = true; module_param(default_utf8, int, S_IRUGO | S_IWUSR); @@ -1367,9 +1369,11 @@ static void csi_m(struct vc_data *vc) rgb_from_256(vc->vc_par[i])); } else if (vc->vc_par[i] == 2 && /* 24 bit */ i <= vc->vc_npar + 3) {/* extremely rare */ - struct rgb c = {r:vc->vc_par[i+1], - g:vc->vc_par[i+2], - b:vc->vc_par[i+3]}; + struct rgb c = { + .r = vc->vc_par[i + 1], + .g = vc->vc_par[i + 2], + .b = vc->vc_par[i + 3], + }; rgb_foreground(vc, c); i += 3; } @@ -1388,9 +1392,11 @@ static void csi_m(struct vc_data *vc) rgb_from_256(vc->vc_par[i])); } else if (vc->vc_par[i] == 2 && /* 24 bit */ i <= vc->vc_npar + 3) { - struct rgb c = {r:vc->vc_par[i+1], - g:vc->vc_par[i+2], - b:vc->vc_par[i+3]}; + struct rgb c = { + .r = vc->vc_par[i + 1], + .g = vc->vc_par[i + 2], + .b = vc->vc_par[i + 3], + }; rgb_background(vc, c); i += 3; } @@ -3849,8 +3855,8 @@ void do_unblank_screen(int leaving_gfx) return; if (!vc_cons_allocated(fg_console)) { /* impossible */ - pr_warning("unblank_screen: tty %d not allocated ??\n", - fg_console+1); + pr_warn("unblank_screen: tty %d not allocated ??\n", + fg_console + 1); return; } vc = vc_cons[fg_console].d; |