serial_core.c revision 60b33c133ca0b7c0b6072c87234b63fee6e80558
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/drivers/char/core.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver core for serial ports 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 1999 ARM Limited 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2000-2001 Deep Blue Solutions Ltd. 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version. 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details. 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/console.h> 30d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan#include <linux/proc_fs.h> 31d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan#include <linux/seq_file.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h> /* for serial_state and serial_icounter_struct */ 34ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox#include <linux/serial_core.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 36f392ecfa12de9a2baf72789b00557bac040d6171Arjan van de Ven#include <linux/mutex.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is used to lock changes in serial line configuration. 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 44f392ecfa12de9a2baf72789b00557bac040d6171Arjan van de Venstatic DEFINE_MUTEX(port_mutex); 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4613e83599d282ddfd544600df9db5ab343ac4662fIngo Molnar/* 4713e83599d282ddfd544600df9db5ab343ac4662fIngo Molnar * lockdep: port->lock is initialized in two places, but we 4813e83599d282ddfd544600df9db5ab343ac4662fIngo Molnar * want only one lock-class: 4913e83599d282ddfd544600df9db5ab343ac4662fIngo Molnar */ 5013e83599d282ddfd544600df9db5ab343ac4662fIngo Molnarstatic struct lock_class_key port_lock_key; 5113e83599d282ddfd544600df9db5ab343ac4662fIngo Molnar 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SERIAL_CORE_CONSOLE 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line) 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define uart_console(port) (0) 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 60192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic void uart_change_speed(struct tty_struct *tty, struct uart_state *state, 61a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox struct ktermios *old_termios); 62203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmannstatic void __uart_wait_until_sent(struct uart_port *port, int timeout); 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_change_pm(struct uart_state *state, int pm_state); 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine is used by the interrupt handler to schedule processing in 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the software interrupt portion of the driver. 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid uart_write_wakeup(struct uart_port *port) 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 71ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox struct uart_state *state = port->state; 72d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek /* 73d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek * This means you called this function _after_ the port was 74d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek * closed. No cookie for you. 75d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek */ 76ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox BUG_ON(!state); 77ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox tasklet_schedule(&state->tlet); 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_stop(struct tty_struct *tty) 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 83ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox struct uart_port *port = state->uart_port; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port->lock, flags); 87b129a8ccd53f74c43e4c83c8e0031a4990040830Russell King port->ops->stop_tx(port); 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port->lock, flags); 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __uart_start(struct tty_struct *tty) 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 94ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox struct uart_port *port = state->uart_port; 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 96ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (!uart_circ_empty(&state->xmit) && state->xmit.buf && 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !tty->stopped && !tty->hw_stopped) 98b129a8ccd53f74c43e4c83c8e0031a4990040830Russell King port->ops->start_tx(port); 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_start(struct tty_struct *tty) 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 104ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox struct uart_port *port = state->uart_port; 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port->lock, flags); 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __uart_start(tty); 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port->lock, flags); 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_tasklet_action(unsigned long data) 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = (struct uart_state *)data; 115ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox tty_wakeup(state->port.tty); 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear) 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int old; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port->lock, flags); 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds old = port->mctrl; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->mctrl = (old & ~clear) | set; 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (old != port->mctrl) 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->ops->set_mctrl(port, port->mctrl); 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port->lock, flags); 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 132a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox#define uart_set_mctrl(port, set) uart_update_mctrl(port, set, 0) 133a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox#define uart_clear_mctrl(port, clear) uart_update_mctrl(port, 0, clear) 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Startup the port. This will be called once per open. All calls 137df4f4dd429870f435f8d5d9d561db029a29f063bAlan Cox * will be serialised by the per-port mutex. 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 139192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic int uart_startup(struct tty_struct *tty, struct uart_state *state, int init_hw) 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 14246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct tty_port *port = &state->port; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long page; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 146ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (port->flags & ASYNC_INITIALIZED) 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the TTY IO error marker - we will only clear this 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * once we have successfully opened the port. Also set 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * up the tty->alt_speed kludge 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 154192251352f912bccfb942ea35801d2357f11f592Alan Cox set_bit(TTY_IO_ERROR, &tty->flags); 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->type == PORT_UNKNOWN) 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialise and allocate the transmit and temporary 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * buffer. 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 163ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (!state->xmit.buf) { 164df4f4dd429870f435f8d5d9d561db029a29f063bAlan Cox /* This is protected by the per port mutex */ 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds page = get_zeroed_page(GFP_KERNEL); 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!page) 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 169ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox state->xmit.buf = (unsigned char *) page; 170ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox uart_circ_clear(&state->xmit); 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox retval = uport->ops->startup(uport); 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval == 0) { 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (init_hw) { 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialise the hardware port settings. 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 179192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_change_speed(tty, state, NULL); 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Setup the RTS and DTR signals once the 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * port is open and ready to respond. 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 185192251352f912bccfb942ea35801d2357f11f592Alan Cox if (tty->termios->c_cflag & CBAUD) 18646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR); 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 189ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (port->flags & ASYNC_CTS_FLOW) { 19046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_lock_irq(&uport->lock); 19146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) 192192251352f912bccfb942ea35801d2357f11f592Alan Cox tty->hw_stopped = 1; 19346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_unlock_irq(&uport->lock); 1940dd7a1aed7c34a39917c4faf75b4230c169e809bRussell King } 1950dd7a1aed7c34a39917c4faf75b4230c169e809bRussell King 196ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox set_bit(ASYNCB_INITIALIZED, &port->flags); 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 198192251352f912bccfb942ea35801d2357f11f592Alan Cox clear_bit(TTY_IO_ERROR, &tty->flags); 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval && capable(CAP_SYS_ADMIN)) 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine will shutdown a serial port; interrupts are disabled, and 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DTR is dropped if the hangup on close termio flag is on. Calls to 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_shutdown are serialised by the per-port semaphore. 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 212192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic void uart_shutdown(struct tty_struct *tty, struct uart_state *state) 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 214ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct uart_port *uport = state->uart_port; 215bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox struct tty_port *port = &state->port; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 218ee31b337852ca8a65840702544ff5c64d37740f5Russell King * Set the TTY IO error marker 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 220f751928e0ddf54ea4fe5546f35e99efc5b5d9938Alan Cox if (tty) 221f751928e0ddf54ea4fe5546f35e99efc5b5d9938Alan Cox set_bit(TTY_IO_ERROR, &tty->flags); 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 223bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox if (test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) { 224ee31b337852ca8a65840702544ff5c64d37740f5Russell King /* 225ee31b337852ca8a65840702544ff5c64d37740f5Russell King * Turn off DTR and RTS early. 226ee31b337852ca8a65840702544ff5c64d37740f5Russell King */ 227f751928e0ddf54ea4fe5546f35e99efc5b5d9938Alan Cox if (!tty || (tty->termios->c_cflag & HUPCL)) 228ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); 229ee31b337852ca8a65840702544ff5c64d37740f5Russell King 230ee31b337852ca8a65840702544ff5c64d37740f5Russell King /* 231ee31b337852ca8a65840702544ff5c64d37740f5Russell King * clear delta_msr_wait queue to avoid mem leaks: we may free 232ee31b337852ca8a65840702544ff5c64d37740f5Russell King * the irq here so the queue might never be woken up. Note 233ee31b337852ca8a65840702544ff5c64d37740f5Russell King * that we won't end up waiting on delta_msr_wait again since 234ee31b337852ca8a65840702544ff5c64d37740f5Russell King * any outstanding file descriptors should be pointing at 235ee31b337852ca8a65840702544ff5c64d37740f5Russell King * hung_up_tty_fops now. 236ee31b337852ca8a65840702544ff5c64d37740f5Russell King */ 237bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox wake_up_interruptible(&port->delta_msr_wait); 238ee31b337852ca8a65840702544ff5c64d37740f5Russell King 239ee31b337852ca8a65840702544ff5c64d37740f5Russell King /* 240ee31b337852ca8a65840702544ff5c64d37740f5Russell King * Free the IRQ and disable the port. 241ee31b337852ca8a65840702544ff5c64d37740f5Russell King */ 242ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox uport->ops->shutdown(uport); 243ee31b337852ca8a65840702544ff5c64d37740f5Russell King 244ee31b337852ca8a65840702544ff5c64d37740f5Russell King /* 245ee31b337852ca8a65840702544ff5c64d37740f5Russell King * Ensure that the IRQ handler isn't running on another CPU. 246ee31b337852ca8a65840702544ff5c64d37740f5Russell King */ 247ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox synchronize_irq(uport->irq); 248ee31b337852ca8a65840702544ff5c64d37740f5Russell King } 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 251ee31b337852ca8a65840702544ff5c64d37740f5Russell King * kill off our tasklet 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 253ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox tasklet_kill(&state->tlet); 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free the transmit buffer page. 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 258ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (state->xmit.buf) { 259ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox free_page((unsigned long)state->xmit.buf); 260ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox state->xmit.buf = NULL; 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_update_timeout - update per-port FIFO timeout. 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @port: uart_port structure describing the port 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @cflag: termios cflag value 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @baud: speed of the port 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the port FIFO timeout value. The @cflag value should 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reflect the actual hardware settings. 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_update_timeout(struct uart_port *port, unsigned int cflag, 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int baud) 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int bits; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* byte size and parity */ 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cflag & CSIZE) { 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS5: 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits = 7; 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS6: 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits = 8; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS7: 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits = 9; 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits = 10; 292a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox break; /* CS8 */ 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & CSTOPB) 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits++; 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & PARENB) 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits++; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The total number of bits to be transmitted in the fifo. 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits = bits * port->fifosize; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Figure the timeout to send the above number of bits. 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Add .02 seconds of slop 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->timeout = (HZ * bits) / baud + HZ/50; 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_update_timeout); 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_get_baud_rate - return baud rate for a particular port 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @port: uart_port structure describing the port in question. 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @termios: desired termios settings. 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @old: old termios (or NULL) 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @min: minimum acceptable baud rate 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @max: maximum acceptable baud rate 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Decode the termios structure into a numeric baud rate, 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * taking account of the magic 38400 baud rate (with spd_* 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * flags), and mapping the %B0 rate to 9600 baud. 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the new baud rate is invalid, try the old termios setting. 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If it's still invalid, we try 9600 baud. 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Update the @termios structure to reflect the baud rate 330eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox * we're actually going to be using. Don't do this for the case 331eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox * where B0 is requested ("hang up"). 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsunsigned int 334606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Coxuart_get_baud_rate(struct uart_port *port, struct ktermios *termios, 335606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox struct ktermios *old, unsigned int min, unsigned int max) 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int try, baud, altbaud = 38400; 338eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox int hung_up = 0; 3390077d45e46fe2af3aaee5813c99268afcd0e7c0eRussell King upf_t flags = port->flags & UPF_SPD_MASK; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (flags == UPF_SPD_HI) 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds altbaud = 57600; 34382cb7ba10deafe17686bf22ce4a7a303a77a197fAndré Goddard Rosa else if (flags == UPF_SPD_VHI) 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds altbaud = 115200; 34582cb7ba10deafe17686bf22ce4a7a303a77a197fAndré Goddard Rosa else if (flags == UPF_SPD_SHI) 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds altbaud = 230400; 34782cb7ba10deafe17686bf22ce4a7a303a77a197fAndré Goddard Rosa else if (flags == UPF_SPD_WARP) 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds altbaud = 460800; 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (try = 0; try < 2; try++) { 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds baud = tty_termios_baud_rate(termios); 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The spd_hi, spd_vhi, spd_shi, spd_warp kludge... 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Die! Die! Die! 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (baud == 38400) 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds baud = altbaud; 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Special case: B0 rate. 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 363eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox if (baud == 0) { 364eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox hung_up = 1; 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds baud = 9600; 366eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox } 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (baud >= min && baud <= max) 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return baud; 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Oops, the quotient was zero. Try again with 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the old baud rate if possible. 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios->c_cflag &= ~CBAUD; 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (old) { 3776d4d67beb963de8865499781b8523e5b683819c3Alan Cox baud = tty_termios_baud_rate(old); 378eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox if (!hung_up) 379eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox tty_termios_encode_baud_rate(termios, 380eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox baud, baud); 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds old = NULL; 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 38616ae2a877bf4179737921235e85ceffd7b79354fAlan Cox * As a last resort, if the range cannot be met then clip to 38716ae2a877bf4179737921235e85ceffd7b79354fAlan Cox * the nearest chip supported rate. 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 38916ae2a877bf4179737921235e85ceffd7b79354fAlan Cox if (!hung_up) { 39016ae2a877bf4179737921235e85ceffd7b79354fAlan Cox if (baud <= min) 39116ae2a877bf4179737921235e85ceffd7b79354fAlan Cox tty_termios_encode_baud_rate(termios, 39216ae2a877bf4179737921235e85ceffd7b79354fAlan Cox min + 1, min + 1); 39316ae2a877bf4179737921235e85ceffd7b79354fAlan Cox else 39416ae2a877bf4179737921235e85ceffd7b79354fAlan Cox tty_termios_encode_baud_rate(termios, 39516ae2a877bf4179737921235e85ceffd7b79354fAlan Cox max - 1, max - 1); 39616ae2a877bf4179737921235e85ceffd7b79354fAlan Cox } 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39816ae2a877bf4179737921235e85ceffd7b79354fAlan Cox /* Should never happen */ 39916ae2a877bf4179737921235e85ceffd7b79354fAlan Cox WARN_ON(1); 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_get_baud_rate); 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_get_divisor - return uart clock divisor 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @port: uart_port structure describing the port. 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @baud: desired baud rate 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Calculate the uart clock divisor for the port. 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsunsigned int 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_get_divisor(struct uart_port *port, unsigned int baud) 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int quot; 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Old custom speed handling. 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds quot = port->custom_divisor; 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds quot = (port->uartclk + (8 * baud)) / (16 * baud); 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return quot; 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_get_divisor); 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43023d22cea85ba9114a59a32ca8dfb1e2aef52a278Alan Cox/* FIXME: Consistent locking policy */ 431192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic void uart_change_speed(struct tty_struct *tty, struct uart_state *state, 432192251352f912bccfb942ea35801d2357f11f592Alan Cox struct ktermios *old_termios) 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 434ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct tty_port *port = &state->port; 435ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct uart_port *uport = state->uart_port; 436606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox struct ktermios *termios; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we have no tty, termios, or the port does not exist, 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * then we can't set the parameters for this port. 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 442ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (!tty || !tty->termios || uport->type == PORT_UNKNOWN) 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios = tty->termios; 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set flags based on termios cflag 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (termios->c_cflag & CRTSCTS) 451ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox set_bit(ASYNCB_CTS_FLOW, &port->flags); 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 453ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox clear_bit(ASYNCB_CTS_FLOW, &port->flags); 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (termios->c_cflag & CLOCAL) 456ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox clear_bit(ASYNCB_CHECK_CD, &port->flags); 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 458ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox set_bit(ASYNCB_CHECK_CD, &port->flags); 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 460ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox uport->ops->set_termios(uport, termios, old_termios); 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 463192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic inline int __uart_put_char(struct uart_port *port, 464192251352f912bccfb942ea35801d2357f11f592Alan Cox struct circ_buf *circ, unsigned char c) 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 46723d22cea85ba9114a59a32ca8dfb1e2aef52a278Alan Cox int ret = 0; 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!circ->buf) 47023d22cea85ba9114a59a32ca8dfb1e2aef52a278Alan Cox return 0; 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port->lock, flags); 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (uart_circ_chars_free(circ) != 0) { 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds circ->buf[circ->head] = c; 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1); 47623d22cea85ba9114a59a32ca8dfb1e2aef52a278Alan Cox ret = 1; 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port->lock, flags); 47923d22cea85ba9114a59a32ca8dfb1e2aef52a278Alan Cox return ret; 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48223d22cea85ba9114a59a32ca8dfb1e2aef52a278Alan Coxstatic int uart_put_char(struct tty_struct *tty, unsigned char ch) 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 486ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox return __uart_put_char(state->uart_port, &state->xmit, ch); 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_flush_chars(struct tty_struct *tty) 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_start(tty); 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 494192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic int uart_write(struct tty_struct *tty, 495192251352f912bccfb942ea35801d2357f11f592Alan Cox const unsigned char *buf, int count) 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 498d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek struct uart_port *port; 499d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek struct circ_buf *circ; 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int c, ret = 0; 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 503d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek /* 504d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek * This means you called this function _after_ the port was 505d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek * closed. No cookie for you. 506d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek */ 507f751928e0ddf54ea4fe5546f35e99efc5b5d9938Alan Cox if (!state) { 508d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek WARN_ON(1); 509d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek return -EL3HLT; 510d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek } 511d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek 512ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox port = state->uart_port; 513ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox circ = &state->xmit; 514d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!circ->buf) 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port->lock, flags); 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (1) { 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count < c) 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c = count; 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (c <= 0) 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(circ->buf + circ->head, buf, c); 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1); 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += c; 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count -= c; 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret += c; 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port->lock, flags); 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_start(tty); 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int uart_write_room(struct tty_struct *tty) 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 540f34d7a5b7010b82fe97da95496b9971435530062Alan Cox unsigned long flags; 541f34d7a5b7010b82fe97da95496b9971435530062Alan Cox int ret; 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 543ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox spin_lock_irqsave(&state->uart_port->lock, flags); 544ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox ret = uart_circ_chars_free(&state->xmit); 545ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox spin_unlock_irqrestore(&state->uart_port->lock, flags); 546f34d7a5b7010b82fe97da95496b9971435530062Alan Cox return ret; 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int uart_chars_in_buffer(struct tty_struct *tty) 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 552f34d7a5b7010b82fe97da95496b9971435530062Alan Cox unsigned long flags; 553f34d7a5b7010b82fe97da95496b9971435530062Alan Cox int ret; 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 555ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox spin_lock_irqsave(&state->uart_port->lock, flags); 556ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox ret = uart_circ_chars_pending(&state->xmit); 557ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox spin_unlock_irqrestore(&state->uart_port->lock, flags); 558f34d7a5b7010b82fe97da95496b9971435530062Alan Cox return ret; 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_flush_buffer(struct tty_struct *tty) 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 56455d7b68996a5064f011d681bca412b6281d2f711Tetsuo Handa struct uart_port *port; 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 567d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek /* 568d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek * This means you called this function _after_ the port was 569d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek * closed. No cookie for you. 570d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek */ 571f751928e0ddf54ea4fe5546f35e99efc5b5d9938Alan Cox if (!state) { 572d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek WARN_ON(1); 573d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek return; 574d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek } 575d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek 576ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox port = state->uart_port; 577eb3a1e1145ca8f12372c7c96aa0702d86a9002a9Jiri Slaby pr_debug("uart_flush_buffer(%d) called\n", tty->index); 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port->lock, flags); 580ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox uart_circ_clear(&state->xmit); 5816bb0e3a59a089e23eecc0af3b6f6012b2a9affbaHaavard Skinnemoen if (port->ops->flush_buffer) 5826bb0e3a59a089e23eecc0af3b6f6012b2a9affbaHaavard Skinnemoen port->ops->flush_buffer(port); 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port->lock, flags); 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_wakeup(tty); 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function is used to send a high-priority XON/XOFF character to 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the device 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_send_xchar(struct tty_struct *tty, char ch) 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 594ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox struct uart_port *port = state->uart_port; 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->ops->send_xchar) 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->ops->send_xchar(port, ch); 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->x_char = ch; 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ch) { 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port->lock, flags); 603b129a8ccd53f74c43e4c83c8e0031a4990040830Russell King port->ops->start_tx(port); 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port->lock, flags); 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_throttle(struct tty_struct *tty) 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (I_IXOFF(tty)) 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_send_xchar(tty, STOP_CHAR(tty)); 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty->termios->c_cflag & CRTSCTS) 617ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox uart_clear_mctrl(state->uart_port, TIOCM_RTS); 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_unthrottle(struct tty_struct *tty) 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 623ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox struct uart_port *port = state->uart_port; 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (I_IXOFF(tty)) { 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->x_char) 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->x_char = 0; 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_send_xchar(tty, START_CHAR(tty)); 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty->termios->c_cflag & CRTSCTS) 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_set_mctrl(port, TIOCM_RTS); 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int uart_get_info(struct uart_state *state, 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serial_struct __user *retinfo) 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 639a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct uart_port *uport = state->uart_port; 640a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serial_struct tmp; 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(&tmp, 0, sizeof(tmp)); 644f34d7a5b7010b82fe97da95496b9971435530062Alan Cox 645f34d7a5b7010b82fe97da95496b9971435530062Alan Cox /* Ensure the state we copy is consistent and no hardware changes 646f34d7a5b7010b82fe97da95496b9971435530062Alan Cox occur as we go */ 647a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 648f34d7a5b7010b82fe97da95496b9971435530062Alan Cox 649a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.type = uport->type; 650a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.line = uport->line; 651a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.port = uport->iobase; 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (HIGH_BITS_OFFSET) 653a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.port_high = (long) uport->iobase >> HIGH_BITS_OFFSET; 654a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.irq = uport->irq; 655a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.flags = uport->flags; 656a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.xmit_fifo_size = uport->fifosize; 657a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.baud_base = uport->uartclk / 16; 658a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.close_delay = port->close_delay / 10; 659016af53a6de6837e5be3da68901083ea85ebb4daAlan Cox tmp.closing_wait = port->closing_wait == ASYNC_CLOSING_WAIT_NONE ? 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ASYNC_CLOSING_WAIT_NONE : 661a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox port->closing_wait / 10; 662a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.custom_divisor = uport->custom_divisor; 663a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.hub6 = uport->hub6; 664a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.io_type = uport->iotype; 665a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.iomem_reg_shift = uport->regshift; 666a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.iomem_base = (void *)(unsigned long)uport->mapbase; 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 668a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 669f34d7a5b7010b82fe97da95496b9971435530062Alan Cox 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 675192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic int uart_set_info(struct tty_struct *tty, struct uart_state *state, 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serial_struct __user *newinfo) 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serial_struct new_serial; 67946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 68046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct tty_port *port = &state->port; 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long new_port; 6820077d45e46fe2af3aaee5813c99268afcd0e7c0eRussell King unsigned int change_irq, change_port, closing_wait; 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int old_custom_divisor, close_delay; 6840077d45e46fe2af3aaee5813c99268afcd0e7c0eRussell King upf_t old_flags, new_flags; 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_port = new_serial.port; 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (HIGH_BITS_OFFSET) 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_serial.irq = irq_canonicalize(new_serial.irq); 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds close_delay = new_serial.close_delay * 10; 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? 697016af53a6de6837e5be3da68901083ea85ebb4daAlan Cox ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 70091312cdb4fcd832341e425f74f49938e0503c929Alan Cox * This semaphore protects port->count. It is also 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * very useful to prevent opens. Also, take the 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * port configuration semaphore to make sure that a 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * module insertion/removal doesn't change anything 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * under us. 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 706a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 70846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox change_irq = !(uport->flags & UPF_FIXED_PORT) 70946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox && new_serial.irq != uport->irq; 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Since changing the 'type' of the port changes its resource 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * allocations, we should treat type changes the same as 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IO port changes. 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 71646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox change_port = !(uport->flags & UPF_FIXED_PORT) 71746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox && (new_port != uport->iobase || 71846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox (unsigned long)new_serial.iomem_base != uport->mapbase || 71946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox new_serial.hub6 != uport->hub6 || 72046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox new_serial.io_type != uport->iotype || 72146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox new_serial.iomem_reg_shift != uport->regshift || 72246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox new_serial.type != uport->type); 72346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox 72446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_flags = uport->flags; 7250077d45e46fe2af3aaee5813c99268afcd0e7c0eRussell King new_flags = new_serial.flags; 72646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_custom_divisor = uport->custom_divisor; 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!capable(CAP_SYS_ADMIN)) { 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EPERM; 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (change_irq || change_port || 73146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox (new_serial.baud_base != uport->uartclk / 16) || 73246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox (close_delay != port->close_delay) || 73346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox (closing_wait != port->closing_wait) || 734947deee8904b3c2edc7f59ab6e6242499e4dc434Russell King (new_serial.xmit_fifo_size && 73546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox new_serial.xmit_fifo_size != uport->fifosize) || 7360077d45e46fe2af3aaee5813c99268afcd0e7c0eRussell King (((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0)) 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 73846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->flags = ((uport->flags & ~UPF_USR_MASK) | 7390077d45e46fe2af3aaee5813c99268afcd0e7c0eRussell King (new_flags & UPF_USR_MASK)); 74046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->custom_divisor = new_serial.custom_divisor; 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto check_and_exit; 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ask the low level driver to verify the settings. 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 74746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->ops->verify_port) 74846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox retval = uport->ops->verify_port(uport, &new_serial); 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 750a62c41337356989387d15020dc0f0288aaacfa44Yinghai Lu if ((new_serial.irq >= nr_irqs) || (new_serial.irq < 0) || 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (new_serial.baud_base < 9600)) 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EINVAL; 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (change_port || change_irq) { 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EBUSY; 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Make sure that we are the sole user of this port. 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 763b58d13a0216d4e0753668214f23e1d2c24c30f8cAlan Cox if (tty_port_users(port) > 1) 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We need to shutdown the serial port at the old 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * port/type/irq combination. 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 770192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_shutdown(tty, state); 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (change_port) { 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long old_iobase, old_mapbase; 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int old_type, old_iotype, old_hub6, old_shift; 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 77746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_iobase = uport->iobase; 77846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_mapbase = uport->mapbase; 77946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_type = uport->type; 78046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_hub6 = uport->hub6; 78146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_iotype = uport->iotype; 78246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_shift = uport->regshift; 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free and release old regions 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (old_type != PORT_UNKNOWN) 78846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->ops->release_port(uport); 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 79046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->iobase = new_port; 79146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->type = new_serial.type; 79246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->hub6 = new_serial.hub6; 79346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->iotype = new_serial.io_type; 79446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->regshift = new_serial.iomem_reg_shift; 79546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->mapbase = (unsigned long)new_serial.iomem_base; 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Claim and map the new regions 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 80046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->type != PORT_UNKNOWN) { 80146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox retval = uport->ops->request_port(uport); 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Always success - Jean II */ 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we fail to request resources for the 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * new port, try to restore the old settings. 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval && old_type != PORT_UNKNOWN) { 81246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->iobase = old_iobase; 81346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->type = old_type; 81446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->hub6 = old_hub6; 81546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->iotype = old_iotype; 81646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->regshift = old_shift; 81746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->mapbase = old_mapbase; 81846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox retval = uport->ops->request_port(uport); 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we failed to restore the old settings, 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we fail like this. 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 82446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->type = PORT_UNKNOWN; 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We failed anyway. 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EBUSY; 830a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox /* Added to return the correct error -Ram Gupta */ 831a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox goto exit; 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 835abb4a2390737867353ebafc012d45f2b03f3f944David Gibson if (change_irq) 83646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->irq = new_serial.irq; 83746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (!(uport->flags & UPF_FIXED_PORT)) 83846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->uartclk = new_serial.baud_base * 16; 83946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->flags = (uport->flags & ~UPF_CHANGE_MASK) | 8400077d45e46fe2af3aaee5813c99268afcd0e7c0eRussell King (new_flags & UPF_CHANGE_MASK); 84146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->custom_divisor = new_serial.custom_divisor; 84246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox port->close_delay = close_delay; 84346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox port->closing_wait = closing_wait; 844947deee8904b3c2edc7f59ab6e6242499e4dc434Russell King if (new_serial.xmit_fifo_size) 84546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->fifosize = new_serial.xmit_fifo_size; 84646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (port->tty) 84746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox port->tty->low_latency = 84846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox (uport->flags & UPF_LOW_LATENCY) ? 1 : 0; 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds check_and_exit: 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 85246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->type == PORT_UNKNOWN) 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 854ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (port->flags & ASYNC_INITIALIZED) { 85546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (((old_flags ^ uport->flags) & UPF_SPD_MASK) || 85646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_custom_divisor != uport->custom_divisor) { 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If they're setting up a custom divisor or speed, 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * instead of clearing it, then bitch about it. No 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * need to rate-limit; it's CAP_SYS_ADMIN only. 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 86246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->flags & UPF_SPD_MASK) { 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char buf[64]; 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_NOTICE 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "%s sets custom speed on %s. This " 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "is deprecated.\n", current->comm, 86746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox tty_name(port->tty, buf)); 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 869192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_change_speed(tty, state, NULL); 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 872192251352f912bccfb942ea35801d2357f11f592Alan Cox retval = uart_startup(tty, state, 1); 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exit: 874a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 878192251352f912bccfb942ea35801d2357f11f592Alan Cox/** 879192251352f912bccfb942ea35801d2357f11f592Alan Cox * uart_get_lsr_info - get line status register info 880192251352f912bccfb942ea35801d2357f11f592Alan Cox * @tty: tty associated with the UART 881192251352f912bccfb942ea35801d2357f11f592Alan Cox * @state: UART being queried 882192251352f912bccfb942ea35801d2357f11f592Alan Cox * @value: returned modem value 883192251352f912bccfb942ea35801d2357f11f592Alan Cox * 884192251352f912bccfb942ea35801d2357f11f592Alan Cox * Note: uart_ioctl protects us against hangups. 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 886192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic int uart_get_lsr_info(struct tty_struct *tty, 887192251352f912bccfb942ea35801d2357f11f592Alan Cox struct uart_state *state, unsigned int __user *value) 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 88946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int result; 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 89246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox result = uport->ops->tx_empty(uport); 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we're about to load something into the transmit 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * register, we'll pretend the transmitter isn't empty to 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * avoid a race condition (depending on when the transmit 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupt happens). 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 90046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->x_char || 901ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox ((uart_circ_chars_pending(&state->xmit) > 0) && 902192251352f912bccfb942ea35801d2357f11f592Alan Cox !tty->stopped && !tty->hw_stopped)) 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result &= ~TIOCSER_TEMT; 904a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return put_user(result, value); 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 90860b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int uart_tiocmget(struct tty_struct *tty) 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 911a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 91246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result = -EIO; 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 915a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 91660b33c133ca0b7c0b6072c87234b63fee6e80558Alan Cox if (!(tty->flags & (1 << TTY_IO_ERROR))) { 91746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox result = uport->mctrl; 91846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_lock_irq(&uport->lock); 91946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox result |= uport->ops->get_mctrl(uport); 92046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_unlock_irq(&uport->lock); 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 922a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_tiocmset(struct tty_struct *tty, struct file *file, 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int set, unsigned int clear) 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 93246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 933a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = -EIO; 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 936a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((!file || !tty_hung_up_p(file)) && 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !(tty->flags & (1 << TTY_IO_ERROR))) { 93946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uart_update_mctrl(uport, set, clear); 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 942a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9469e98966c7bb94355689478bc84cc3e0c190f977eAlan Coxstatic int uart_break_ctl(struct tty_struct *tty, int break_state) 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 949a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 95046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 952a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->type != PORT_UNKNOWN) 95546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->ops->break_ctl(uport, break_state); 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 957a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 9589e98966c7bb94355689478bc84cc3e0c190f977eAlan Cox return 0; 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 961192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state) 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 96346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 964a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int flags, ret; 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!capable(CAP_SYS_ADMIN)) 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Take the per-port semaphore. This prevents count from 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * changing, and hence any extra opens of the port while 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we're auto-configuring. 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 975a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (mutex_lock_interruptible(&port->mutex)) 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ERESTARTSYS; 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EBUSY; 979b58d13a0216d4e0753668214f23e1d2c24c30f8cAlan Cox if (tty_port_users(port) == 1) { 980192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_shutdown(tty, state); 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we already have a port type configured, 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we must release its resources. 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 98646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->type != PORT_UNKNOWN) 98746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->ops->release_port(uport); 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags = UART_CONFIG_TYPE; 99046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->flags & UPF_AUTO_IRQ) 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags |= UART_CONFIG_IRQ; 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This will claim the ports resources if 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a port is found. 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 99746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->ops->config_port(uport, flags); 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 999192251352f912bccfb942ea35801d2357f11f592Alan Cox ret = uart_startup(tty, state, 1); 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1001a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - mask passed in arg for lines of interest 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Caller should use TIOCGICOUNT to see which one it was 1010bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox * 1011bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox * FIXME: This wants extracting into a common all driver implementation 1012bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox * of TIOCMWAIT using tty_port. 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_wait_modem_status(struct uart_state *state, unsigned long arg) 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 101746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 1018bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox struct tty_port *port = &state->port; 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DECLARE_WAITQUEUE(wait, current); 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_icount cprev, cnow; 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * note the counters on entry 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 102646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_lock_irq(&uport->lock); 102746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox memcpy(&cprev, &uport->icount, sizeof(struct uart_icount)); 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Force modem status interrupts on 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 103246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->ops->enable_ms(uport); 103346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_unlock_irq(&uport->lock); 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1035bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox add_wait_queue(&port->delta_msr_wait, &wait); 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (;;) { 103746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_lock_irq(&uport->lock); 103846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); 103946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_unlock_irq(&uport->lock); 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_current_state(TASK_INTERRUPTIBLE); 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { 1047a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox ret = 0; 1048a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox break; 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds schedule(); 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* see if a signal did it */ 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) { 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ERESTARTSYS; 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cprev = cnow; 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds current->state = TASK_RUNNING; 1063bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox remove_wait_queue(&port->delta_msr_wait, &wait); 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return: write counters to the user passed counter struct 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NB: both 1->0 and 0->1 transitions are counted except for 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * RI where only 0->1 is counted. 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1074d281da7ff6f70efca0553c288bb883e8605b3862Alan Coxstatic int uart_get_icount(struct tty_struct *tty, 1075d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox struct serial_icounter_struct *icount) 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1077d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox struct uart_state *state = tty->driver_data; 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_icount cnow; 107946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 108146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_lock_irq(&uport->lock); 108246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); 108346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_unlock_irq(&uport->lock); 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1085d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox icount->cts = cnow.cts; 1086d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox icount->dsr = cnow.dsr; 1087d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox icount->rng = cnow.rng; 1088d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox icount->dcd = cnow.dcd; 1089d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox icount->rx = cnow.rx; 1090d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox icount->tx = cnow.tx; 1091d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox icount->frame = cnow.frame; 1092d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox icount->overrun = cnow.overrun; 1093d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox icount->parity = cnow.parity; 1094d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox icount->brk = cnow.brk; 1095d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox icount->buf_overrun = cnow.buf_overrun; 1096d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox 1097d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox return 0; 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1101e52384426064bca0669a954736206adca7595d48Alan Cox * Called via sys_ioctl. We can use spin_lock_irq() here. 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long arg) 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 1108a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __user *uarg = (void __user *)arg; 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = -ENOIOCTLCMD; 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * These ioctls don't rely on the hardware to be present. 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TIOCGSERIAL: 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = uart_get_info(state, uarg); 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TIOCSSERIAL: 1122192251352f912bccfb942ea35801d2357f11f592Alan Cox ret = uart_set_info(tty, state, uarg); 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TIOCSERCONFIG: 1126192251352f912bccfb942ea35801d2357f11f592Alan Cox ret = uart_do_autoconfig(tty, state); 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TIOCSERGWILD: /* obsolete */ 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TIOCSERSWILD: /* obsolete */ 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret != -ENOIOCTLCMD) 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty->flags & (1 << TTY_IO_ERROR)) { 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EIO; 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The following should only be used when hardware is present. 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TIOCMIWAIT: 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = uart_wait_modem_status(state, arg); 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret != -ENOIOCTLCMD) 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1155a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty_hung_up_p(filp)) { 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EIO; 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_up; 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * All these rely on hardware being present and need to be 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * protected against the tty being hung up. 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TIOCSERGETLSR: /* Get line status register */ 1168192251352f912bccfb942ea35801d2357f11f592Alan Cox ret = uart_get_lsr_info(tty, state, uarg); 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: { 117246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 117346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->ops->ioctl) 117446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox ret = uport->ops->ioctl(uport, cmd, arg); 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1178f34d7a5b7010b82fe97da95496b9971435530062Alan Coxout_up: 1179a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 1180f34d7a5b7010b82fe97da95496b9971435530062Alan Coxout: 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1184edeb280e49d38a5330db25463ef45f5466b0058aLinus Torvaldsstatic void uart_set_ldisc(struct tty_struct *tty) 118564e9159f5d2c4edf5fa6425031e556f8fddaf7e6Alan Cox{ 118664e9159f5d2c4edf5fa6425031e556f8fddaf7e6Alan Cox struct uart_state *state = tty->driver_data; 118746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 118864e9159f5d2c4edf5fa6425031e556f8fddaf7e6Alan Cox 118946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->ops->set_ldisc) 1190d87d9b7d19f04b16c4406d3c0feeca10090e0adaAlan Cox uport->ops->set_ldisc(uport, tty->termios->c_line); 119164e9159f5d2c4edf5fa6425031e556f8fddaf7e6Alan Cox} 119264e9159f5d2c4edf5fa6425031e556f8fddaf7e6Alan Cox 1193a46c9994242978ab001299cc9c906b9a3eedadccAlan Coxstatic void uart_set_termios(struct tty_struct *tty, 1194a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox struct ktermios *old_termios) 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cflag = tty->termios->c_cflag; 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * These are the bits that are used to setup various 120320620d688ac6ff8ea01a873e46febf5a6a7909f1David Woodhouse * flags in the low level driver. We can ignore the Bfoo 120420620d688ac6ff8ea01a873e46febf5a6a7909f1David Woodhouse * bits in c_cflag; c_[io]speed will always be set 120520620d688ac6ff8ea01a873e46febf5a6a7909f1David Woodhouse * appropriately by set_termios() in tty_ioctl.c 12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) 12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((cflag ^ old_termios->c_cflag) == 0 && 120920620d688ac6ff8ea01a873e46febf5a6a7909f1David Woodhouse tty->termios->c_ospeed == old_termios->c_ospeed && 121020620d688ac6ff8ea01a873e46febf5a6a7909f1David Woodhouse tty->termios->c_ispeed == old_termios->c_ispeed && 1211e52384426064bca0669a954736206adca7595d48Alan Cox RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) { 12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1213e52384426064bca0669a954736206adca7595d48Alan Cox } 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1215192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_change_speed(tty, state, old_termios); 12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Handle transition to B0 status */ 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) 1219ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox uart_clear_mctrl(state->uart_port, TIOCM_RTS | TIOCM_DTR); 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Handle transition away from B0 status */ 122182cb7ba10deafe17686bf22ce4a7a303a77a197fAndré Goddard Rosa else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int mask = TIOCM_DTR; 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(cflag & CRTSCTS) || 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !test_bit(TTY_THROTTLED, &tty->flags)) 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask |= TIOCM_RTS; 1226ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox uart_set_mctrl(state->uart_port, mask); 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Handle turning off CRTSCTS */ 12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) { 1231ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox spin_lock_irqsave(&state->uart_port->lock, flags); 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->hw_stopped = 0; 12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __uart_start(tty); 1234ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox spin_unlock_irqrestore(&state->uart_port->lock, flags); 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12360dd7a1aed7c34a39917c4faf75b4230c169e809bRussell King /* Handle turning on CRTSCTS */ 123782cb7ba10deafe17686bf22ce4a7a303a77a197fAndré Goddard Rosa else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) { 1238ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox spin_lock_irqsave(&state->uart_port->lock, flags); 1239ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (!(state->uart_port->ops->get_mctrl(state->uart_port) & TIOCM_CTS)) { 12400dd7a1aed7c34a39917c4faf75b4230c169e809bRussell King tty->hw_stopped = 1; 1241ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox state->uart_port->ops->stop_tx(state->uart_port); 12420dd7a1aed7c34a39917c4faf75b4230c169e809bRussell King } 1243ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox spin_unlock_irqrestore(&state->uart_port->lock, flags); 12440dd7a1aed7c34a39917c4faf75b4230c169e809bRussell King } 12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * No need to wake up processes in open wait, since they 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sample the CLOCAL flag once, and don't recheck it. 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * XXX It's not clear whether the current behavior is correct 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or not. Hence, this may change..... 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(old_termios->c_cflag & CLOCAL) && 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (tty->termios->c_cflag & CLOCAL)) 1254ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox wake_up_interruptible(&state->uart_port.open_wait); 12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In 2.4.5, calls to this will be serialized via the BKL in 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/drivers/char/tty_io.c:tty_release() 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/drivers/char/tty_io.c:do_tty_handup() 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_close(struct tty_struct *tty, struct file *filp) 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 126646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct tty_port *port; 126746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport; 126861cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox unsigned long flags; 1269a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox 1270ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann BUG_ON(!tty_locked()); 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1272eea7e17e0eb23729d58368420659f8e7c357d82eLinus Torvalds if (!state) 1273eea7e17e0eb23729d58368420659f8e7c357d82eLinus Torvalds return; 1274eea7e17e0eb23729d58368420659f8e7c357d82eLinus Torvalds 127546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport = state->uart_port; 127646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox port = &state->port; 12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 127846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox pr_debug("uart_close(%d) called\n", uport->line); 12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1280a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 128161cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_lock_irqsave(&port->lock, flags); 12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 128361cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox if (tty_hung_up_p(filp)) { 128461cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_unlock_irqrestore(&port->lock, flags); 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 128661cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox } 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 128891312cdb4fcd832341e425f74f49938e0503c929Alan Cox if ((tty->count == 1) && (port->count != 1)) { 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Uh, oh. tty->count is 1, which means that the tty 129191312cdb4fcd832341e425f74f49938e0503c929Alan Cox * structure will be freed. port->count should always 12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * be one in these conditions. If it's greater than 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * one, we've got real problems, since it means the 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * serial port won't be shutdown. 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "uart_close: bad serial port count; tty->count is 1, " 129791312cdb4fcd832341e425f74f49938e0503c929Alan Cox "port->count is %d\n", port->count); 129891312cdb4fcd832341e425f74f49938e0503c929Alan Cox port->count = 1; 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 130091312cdb4fcd832341e425f74f49938e0503c929Alan Cox if (--port->count < 0) { 13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "uart_close: bad serial port count for %s: %d\n", 130291312cdb4fcd832341e425f74f49938e0503c929Alan Cox tty->name, port->count); 130391312cdb4fcd832341e425f74f49938e0503c929Alan Cox port->count = 0; 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 130561cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox if (port->count) { 130661cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_unlock_irqrestore(&port->lock, flags); 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 130861cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox } 13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Now we wait for the transmit buffer to clear; and we notify 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the line discipline to only process XON/XOFF characters by 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * setting tty->closing. 13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->closing = 1; 131661cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_unlock_irqrestore(&port->lock, flags); 13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1318203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmann if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) { 1319203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmann /* 1320203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmann * hack: open-coded tty_wait_until_sent to avoid 1321203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmann * recursive tty_lock 1322203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmann */ 1323203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmann long timeout = msecs_to_jiffies(port->closing_wait); 1324203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmann if (wait_event_interruptible_timeout(tty->write_wait, 1325203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmann !tty_chars_in_buffer(tty), timeout) >= 0) 1326203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmann __uart_wait_until_sent(uport, timeout); 1327203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmann } 13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * At this point, we stop accepting input. To do this, we 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * disable the receive line status interrupts. 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1333ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (port->flags & ASYNC_INITIALIZED) { 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1335eea7e17e0eb23729d58368420659f8e7c357d82eLinus Torvalds spin_lock_irqsave(&uport->lock, flags); 133646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->ops->stop_rx(uport); 1337eea7e17e0eb23729d58368420659f8e7c357d82eLinus Torvalds spin_unlock_irqrestore(&uport->lock, flags); 13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Before we drop DTR, make sure the UART transmitter 13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * has completely drained; this is especially 13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * important if there is a transmit FIFO! 13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1343203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmann __uart_wait_until_sent(uport, uport->timeout); 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1346192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_shutdown(tty, state); 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_flush_buffer(tty); 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1349a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox tty_ldisc_flush(tty); 1350a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox 13517b01478f97a671c97fad9254aa91892209b018b5Alan Cox tty_port_tty_set(port, NULL); 135261cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_lock_irqsave(&port->lock, flags); 135361cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox tty->closing = 0; 13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 135546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (port->blocked_open) { 135661cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_unlock_irqrestore(&port->lock, flags); 135746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (port->close_delay) 135846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox msleep_interruptible(port->close_delay); 135961cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_lock_irqsave(&port->lock, flags); 136046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox } else if (!uart_console(uport)) { 136161cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_unlock_irqrestore(&port->lock, flags); 13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_change_pm(state, 3); 136361cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_lock_irqsave(&port->lock, flags); 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wake up anyone trying to open this port. 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1369ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); 137061cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_unlock_irqrestore(&port->lock, flags); 137146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox wake_up_interruptible(&port->open_wait); 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 137346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Coxdone: 1374a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1377203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmannstatic void __uart_wait_until_sent(struct uart_port *port, int timeout) 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long char_time, expire; 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->type == PORT_UNKNOWN || port->fifosize == 0) 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the check interval to be 1/5 of the estimated time to 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * send a single character, and make it at least 1. The check 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interval should also be less than the timeout. 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note: we have to use pretty tight timings here to satisfy 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the NIST-PCTS. 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char_time = (port->timeout - HZ/50) / port->fifosize; 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char_time = char_time / 5; 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (char_time == 0) 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char_time = 1; 13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (timeout && timeout < char_time) 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char_time = timeout; 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the transmitter hasn't cleared in twice the approximate 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * amount of time to send the entire FIFO, it probably won't 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ever clear. This assumes the UART isn't doing flow 14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * control, which is currently the case. Hence, if it ever 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * takes longer than port->timeout, this is probably due to a 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * UART bug of some kind. So, we clamp the timeout parameter at 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2*port->timeout. 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (timeout == 0 || timeout > 2 * port->timeout) 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds timeout = 2 * port->timeout; 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds expire = jiffies + timeout; 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1413eb3a1e1145ca8f12372c7c96aa0702d86a9002a9Jiri Slaby pr_debug("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n", 1414a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox port->line, jiffies, expire); 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check whether the transmitter is empty every 'char_time'. 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 'timeout' / 'expire' give us the maximum amount of time 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we wait. 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!port->ops->tx_empty(port)) { 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep_interruptible(jiffies_to_msecs(char_time)); 14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (time_after(jiffies, expire)) 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_current_state(TASK_RUNNING); /* might not be needed */ 1429203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmann} 1430203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmann 1431203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmannstatic void uart_wait_until_sent(struct tty_struct *tty, int timeout) 1432203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmann{ 1433203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmann struct uart_state *state = tty->driver_data; 1434203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmann struct uart_port *port = state->uart_port; 1435203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmann 1436203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmann tty_lock(); 1437203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmann __uart_wait_until_sent(port, timeout); 1438ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann tty_unlock(); 14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is called with the BKL held in 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/drivers/char/tty_io.c:do_tty_hangup() 14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We're called from the eventd thread, so we can sleep for 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a _short_ time only. 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_hangup(struct tty_struct *tty) 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 145046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct tty_port *port = &state->port; 145161cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox unsigned long flags; 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1453ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann BUG_ON(!tty_locked()); 1454ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox pr_debug("uart_hangup(%d)\n", state->uart_port->line); 14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1456a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 1457ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (port->flags & ASYNC_NORMAL_ACTIVE) { 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_flush_buffer(tty); 1459192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_shutdown(tty, state); 146061cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_lock_irqsave(&port->lock, flags); 146191312cdb4fcd832341e425f74f49938e0503c929Alan Cox port->count = 0; 1462ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); 146361cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_unlock_irqrestore(&port->lock, flags); 14647b01478f97a671c97fad9254aa91892209b018b5Alan Cox tty_port_tty_set(port, NULL); 146546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox wake_up_interruptible(&port->open_wait); 1466bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox wake_up_interruptible(&port->delta_msr_wait); 14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1468a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1471192251352f912bccfb942ea35801d2357f11f592Alan Cox/** 1472192251352f912bccfb942ea35801d2357f11f592Alan Cox * uart_update_termios - update the terminal hw settings 1473192251352f912bccfb942ea35801d2357f11f592Alan Cox * @tty: tty associated with UART 1474192251352f912bccfb942ea35801d2357f11f592Alan Cox * @state: UART to update 1475192251352f912bccfb942ea35801d2357f11f592Alan Cox * 1476192251352f912bccfb942ea35801d2357f11f592Alan Cox * Copy across the serial console cflag setting into the termios settings 1477192251352f912bccfb942ea35801d2357f11f592Alan Cox * for the initial open of the port. This allows continuity between the 1478192251352f912bccfb942ea35801d2357f11f592Alan Cox * kernel settings, and the settings init adopts when it opens the port 1479192251352f912bccfb942ea35801d2357f11f592Alan Cox * for the first time. 14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1481192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic void uart_update_termios(struct tty_struct *tty, 1482192251352f912bccfb942ea35801d2357f11f592Alan Cox struct uart_state *state) 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1484ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox struct uart_port *port = state->uart_port; 14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (uart_console(port) && port->cons->cflag) { 14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->termios->c_cflag = port->cons->cflag; 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->cons->cflag = 0; 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the device failed to grab its irq resources, 14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or some other error occurred, don't try to talk 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to the port hardware. 14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(tty->flags & (1 << TTY_IO_ERROR))) { 14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Make termios settings take effect. 14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1500192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_change_speed(tty, state, NULL); 15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * And finally enable the RTS and DTR signals. 15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty->termios->c_cflag & CBAUD) 15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS); 15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1510de0c8cb314cc737c47a00de33cd6246accf94192Alan Coxstatic int uart_carrier_raised(struct tty_port *port) 1511de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox{ 1512de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox struct uart_state *state = container_of(port, struct uart_state, port); 1513de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox struct uart_port *uport = state->uart_port; 1514de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox int mctrl; 1515de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox spin_lock_irq(&uport->lock); 1516de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox uport->ops->enable_ms(uport); 1517de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox mctrl = uport->ops->get_mctrl(uport); 1518de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox spin_unlock_irq(&uport->lock); 1519de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox if (mctrl & TIOCM_CAR) 1520de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox return 1; 1521de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox return 0; 1522de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox} 1523de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox 1524de0c8cb314cc737c47a00de33cd6246accf94192Alan Coxstatic void uart_dtr_rts(struct tty_port *port, int onoff) 1525de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox{ 1526de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox struct uart_state *state = container_of(port, struct uart_state, port); 1527de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox struct uart_port *uport = state->uart_port; 152824fcc7c8cd0fcabcf37d455abe3501b3196fcf64Alan Cox 15293f582b8c11014e4ce310d9839fb335164195333fArnd Bergmann if (onoff) { 1530de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS); 15313f582b8c11014e4ce310d9839fb335164195333fArnd Bergmann 15323f582b8c11014e4ce310d9839fb335164195333fArnd Bergmann /* 15333f582b8c11014e4ce310d9839fb335164195333fArnd Bergmann * If this is the first open to succeed, 15343f582b8c11014e4ce310d9839fb335164195333fArnd Bergmann * adjust things to suit. 15353f582b8c11014e4ce310d9839fb335164195333fArnd Bergmann */ 15363f582b8c11014e4ce310d9839fb335164195333fArnd Bergmann if (!test_and_set_bit(ASYNCB_NORMAL_ACTIVE, &port->flags)) 15373f582b8c11014e4ce310d9839fb335164195333fArnd Bergmann uart_update_termios(port->tty, state); 15383f582b8c11014e4ce310d9839fb335164195333fArnd Bergmann } 1539de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox else 1540de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); 1541de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox} 1542de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox 15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct uart_state *uart_get(struct uart_driver *drv, int line) 15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state; 1546a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port; 154768ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King int ret = 0; 15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds state = drv->state + line; 1550a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox port = &state->port; 1551a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (mutex_lock_interruptible(&port->mutex)) { 155268ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King ret = -ERESTARTSYS; 155368ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King goto err; 15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1556a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox port->count++; 1557ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (!state->uart_port || state->uart_port->flags & UPF_DEAD) { 155868ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King ret = -ENXIO; 155968ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King goto err_unlock; 15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return state; 156268ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King 156368ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King err_unlock: 1564a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox port->count--; 1565a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 156668ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King err: 156768ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King return ERR_PTR(ret); 15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1571922f9cfa79b52c85b6002d96cb0eefd13437c58cDenis Cheng * calls to uart_open are serialised by the BKL in 1572922f9cfa79b52c85b6002d96cb0eefd13437c58cDenis Cheng * fs/char_dev.c:chrdev_open() 15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that if this fails, then uart_close() _will_ be called. 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In time, we want to scrap the "opening nonpresent ports" 15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * behaviour and implement an alternative way for setserial 15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to set base addresses/ports/types. This will allow us to 15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * get rid of a certain amount of extra tests. 15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int uart_open(struct tty_struct *tty, struct file *filp) 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state; 15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state; 158491312cdb4fcd832341e425f74f49938e0503c929Alan Cox struct tty_port *port; 15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval, line = tty->index; 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1587ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann BUG_ON(!tty_locked()); 1588eb3a1e1145ca8f12372c7c96aa0702d86a9002a9Jiri Slaby pr_debug("uart_open(%d) called\n", line); 15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tty->driver->num won't change, so we won't fail here with 15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tty->driver_data set to something non-NULL (and therefore 15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we won't get caught by uart_close()). 15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ENODEV; 15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (line >= tty->driver->num) 15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail; 15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We take the semaphore inside uart_get to guarantee that we won't 1601ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox * be re-entered while allocating the state structure, or while we 16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * request any IRQs that the driver may need. This also has the nice 16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * side-effect that it delays the action of uart_hangup, so we can 1604ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox * guarantee that state->port.tty will always contain something 1605ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox * reasonable. 16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds state = uart_get(drv, line); 16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(state)) { 16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = PTR_ERR(state); 16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail; 16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 161291312cdb4fcd832341e425f74f49938e0503c929Alan Cox port = &state->port; 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Once we set tty->driver_data here, we are guaranteed that 16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_close() will decrement the driver module use count. 16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Any failures from here onwards should not touch the count. 16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->driver_data = state; 1620ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox state->uart_port->state = state; 1621ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox tty->low_latency = (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0; 16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->alt_speed = 0; 16237b01478f97a671c97fad9254aa91892209b018b5Alan Cox tty_port_tty_set(port, tty); 16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the port is in the middle of closing, bail out now. 16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty_hung_up_p(filp)) { 16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EAGAIN; 163091312cdb4fcd832341e425f74f49938e0503c929Alan Cox port->count--; 1631a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail; 16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Make sure the device is in D0 state. 16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 163891312cdb4fcd832341e425f74f49938e0503c929Alan Cox if (port->count == 1) 16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_change_pm(state, 0); 16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Start up the serial port. 16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1644192251352f912bccfb942ea35801d2357f11f592Alan Cox retval = uart_startup(tty, state, 0); 16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we succeeded, wait until the port is ready. 16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 164961cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox mutex_unlock(&port->mutex); 16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval == 0) 165174c2107759dc6efaa1b9127014be58a742a1e7acAlan Cox retval = tty_port_block_til_ready(port, tty, filp); 16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1653a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Coxfail: 16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *uart_type(struct uart_port *port) 16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *str = NULL; 16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->ops->type) 16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds str = port->ops->type(port); 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!str) 16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds str = "unknown"; 16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return str; 16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PROC_FS 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1672d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyanstatic void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i) 16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = drv->state + i; 1675a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 16763689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis int pm_state; 1677a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct uart_port *uport = state->uart_port; 16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char stat_buf[32]; 16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status; 1680d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan int mmio; 16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1682a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (!uport) 1683d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan return; 16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1685a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mmio = uport->iotype >= UPIO_MEM; 1686d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_printf(m, "%d: uart:%s %s%08llX irq:%d", 1687a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->line, uart_type(uport), 16886c6a2334a1e8af7c3eaab992732825fa9ade77cfSergei Shtylyov mmio ? "mmio:0x" : "port:", 1689a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mmio ? (unsigned long long)uport->mapbase 1690a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox : (unsigned long long)uport->iobase, 1691a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->irq); 16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1693a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->type == PORT_UNKNOWN) { 1694d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_putc(m, '\n'); 1695d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan return; 16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1698a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox if (capable(CAP_SYS_ADMIN)) { 1699a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 17003689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis pm_state = state->pm_state; 17013689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis if (pm_state) 17023689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis uart_change_pm(state, 0); 1703a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox spin_lock_irq(&uport->lock); 1704a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox status = uport->ops->get_mctrl(uport); 1705a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox spin_unlock_irq(&uport->lock); 17063689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis if (pm_state) 17073689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis uart_change_pm(state, pm_state); 1708a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1710d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_printf(m, " tx:%d rx:%d", 1711a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->icount.tx, uport->icount.rx); 1712a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->icount.frame) 1713d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_printf(m, " fe:%d", 1714a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->icount.frame); 1715a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->icount.parity) 1716d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_printf(m, " pe:%d", 1717a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->icount.parity); 1718a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->icount.brk) 1719d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_printf(m, " brk:%d", 1720a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->icount.brk); 1721a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->icount.overrun) 1722d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_printf(m, " oe:%d", 1723a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->icount.overrun); 1724a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox 1725a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox#define INFOBIT(bit, str) \ 1726a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->mctrl & (bit)) \ 17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strncat(stat_buf, (str), sizeof(stat_buf) - \ 17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strlen(stat_buf) - 2) 1729a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox#define STATBIT(bit, str) \ 17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & (bit)) \ 17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strncat(stat_buf, (str), sizeof(stat_buf) - \ 17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strlen(stat_buf) - 2) 17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stat_buf[0] = '\0'; 17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stat_buf[1] = '\0'; 17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INFOBIT(TIOCM_RTS, "|RTS"); 17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds STATBIT(TIOCM_CTS, "|CTS"); 17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INFOBIT(TIOCM_DTR, "|DTR"); 17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds STATBIT(TIOCM_DSR, "|DSR"); 17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds STATBIT(TIOCM_CAR, "|CD"); 17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds STATBIT(TIOCM_RNG, "|RI"); 17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (stat_buf[0]) 17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stat_buf[0] = ' '; 1744a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox 1745d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_puts(m, stat_buf); 17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1747d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_putc(m, '\n'); 17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef STATBIT 17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef INFOBIT 17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1752d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyanstatic int uart_proc_show(struct seq_file *m, void *v) 17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1754833bb3046b6cb320e775ea2160ddca87d53260d5Alexey Dobriyan struct tty_driver *ttydrv = m->private; 17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_driver *drv = ttydrv->driver_state; 1756d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan int i; 17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1758d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n", 17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "", "", ""); 1760d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan for (i = 0; i < drv->nr; i++) 1761d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan uart_line_info(m, drv, i); 1762d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan return 0; 17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1764d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan 1765d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyanstatic int uart_proc_open(struct inode *inode, struct file *file) 1766d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan{ 1767d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan return single_open(file, uart_proc_show, PDE(inode)->data); 1768d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan} 1769d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan 1770d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyanstatic const struct file_operations uart_proc_fops = { 1771d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan .owner = THIS_MODULE, 1772d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan .open = uart_proc_open, 1773d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan .read = seq_read, 1774d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan .llseek = seq_lseek, 1775d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan .release = single_release, 1776d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan}; 17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17794a1b5502d426df09b9ba1cbcc74fd09702a74cd8Andrew Morton#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) 17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1781d358788f3f30113e49882187d794832905e42592Russell King * uart_console_write - write a console message to a serial port 1782d358788f3f30113e49882187d794832905e42592Russell King * @port: the port to write the message 1783d358788f3f30113e49882187d794832905e42592Russell King * @s: array of characters 1784d358788f3f30113e49882187d794832905e42592Russell King * @count: number of characters in string to write 1785d358788f3f30113e49882187d794832905e42592Russell King * @write: function to write character to port 1786d358788f3f30113e49882187d794832905e42592Russell King */ 1787d358788f3f30113e49882187d794832905e42592Russell Kingvoid uart_console_write(struct uart_port *port, const char *s, 1788d358788f3f30113e49882187d794832905e42592Russell King unsigned int count, 1789d358788f3f30113e49882187d794832905e42592Russell King void (*putchar)(struct uart_port *, int)) 1790d358788f3f30113e49882187d794832905e42592Russell King{ 1791d358788f3f30113e49882187d794832905e42592Russell King unsigned int i; 1792d358788f3f30113e49882187d794832905e42592Russell King 1793d358788f3f30113e49882187d794832905e42592Russell King for (i = 0; i < count; i++, s++) { 1794d358788f3f30113e49882187d794832905e42592Russell King if (*s == '\n') 1795d358788f3f30113e49882187d794832905e42592Russell King putchar(port, '\r'); 1796d358788f3f30113e49882187d794832905e42592Russell King putchar(port, *s); 1797d358788f3f30113e49882187d794832905e42592Russell King } 1798d358788f3f30113e49882187d794832905e42592Russell King} 1799d358788f3f30113e49882187d794832905e42592Russell KingEXPORT_SYMBOL_GPL(uart_console_write); 1800d358788f3f30113e49882187d794832905e42592Russell King 1801d358788f3f30113e49882187d794832905e42592Russell King/* 18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check whether an invalid uart number has been specified, and 18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if so, search for the first available port that does have 18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * console support. 18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct uart_port * __init 18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_get_console(struct uart_port *ports, int nr, struct console *co) 18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int idx = co->index; 18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (idx < 0 || idx >= nr || (ports[idx].iobase == 0 && 18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ports[idx].membase == NULL)) 18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (idx = 0; idx < nr; idx++) 18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ports[idx].iobase != 0 || 18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ports[idx].membase != NULL) 18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds co->index = idx; 18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ports + idx; 18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_parse_options - Parse serial port baud/parity/bits/flow contro. 18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @options: pointer to option string 18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @baud: pointer to an 'int' variable for the baud rate. 18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @parity: pointer to an 'int' variable for the parity. 18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @bits: pointer to an 'int' variable for the number of data bits. 18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @flow: pointer to an 'int' variable for the flow control character. 18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_parse_options decodes a string containing the serial console 18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * options. The format of the string is <baud><parity><bits><flow>, 18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * eg: 115200n8r 18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1835f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselvoid 18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow) 18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *s = options; 18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *baud = simple_strtoul(s, NULL, 10); 18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (*s >= '0' && *s <= '9') 18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s++; 18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*s) 18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *parity = *s++; 18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*s) 18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *bits = *s++ - '0'; 18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*s) 18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *flow = *s; 18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1850f2d937f3bf00665ccf048b3b6616ef95859b0945Jason WesselEXPORT_SYMBOL_GPL(uart_parse_options); 18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct baud_rates { 18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int rate; 18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cflag; 18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1857cb3592be272d83011051dc49f4326355c01f1e1fArjan van de Venstatic const struct baud_rates baud_rates[] = { 18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 921600, B921600 }, 18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 460800, B460800 }, 18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 230400, B230400 }, 18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 115200, B115200 }, 18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 57600, B57600 }, 18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 38400, B38400 }, 18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 19200, B19200 }, 18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 9600, B9600 }, 18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 4800, B4800 }, 18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 2400, B2400 }, 18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 1200, B1200 }, 18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 0, B38400 } 18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_set_options - setup the serial console parameters 18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @port: pointer to the serial ports uart_port structure 18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @co: console pointer 18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @baud: baud rate 18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @parity: parity character - 'n' (none), 'o' (odd), 'e' (even) 18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @bits: number of data bits 18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @flow: flow control character - 'r' (rts) 18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1881f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselint 18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_set_options(struct uart_port *port, struct console *co, 18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int baud, int parity, int bits, int flow) 18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1885606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox struct ktermios termios; 1886149b36eae2ab6aa6056664f4bc461f3d3affc9c1Alan Cox static struct ktermios dummy; 18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1889976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King /* 1890976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King * Ensure that the serial console lock is initialised 1891976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King * early. 1892976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King */ 1893976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King spin_lock_init(&port->lock); 189413e83599d282ddfd544600df9db5ab343ac4662fIngo Molnar lockdep_set_class(&port->lock, &port_lock_key); 1895976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King 1896606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox memset(&termios, 0, sizeof(struct ktermios)); 18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios.c_cflag = CREAD | HUPCL | CLOCAL; 18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Construct a cflag setting. 19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; baud_rates[i].rate; i++) 19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (baud_rates[i].rate <= baud) 19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios.c_cflag |= baud_rates[i].cflag; 19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bits == 7) 19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios.c_cflag |= CS7; 19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios.c_cflag |= CS8; 19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (parity) { 19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 'o': case 'O': 19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios.c_cflag |= PARODD; 19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*fall through*/ 19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 'e': case 'E': 19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios.c_cflag |= PARENB; 19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (flow == 'r') 19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios.c_cflag |= CRTSCTS; 19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 192679492689e40d4f4d3d8a7262781d56fb295b4b86Yinghai Lu /* 192779492689e40d4f4d3d8a7262781d56fb295b4b86Yinghai Lu * some uarts on other side don't support no flow control. 192879492689e40d4f4d3d8a7262781d56fb295b4b86Yinghai Lu * So we set * DTR in host uart to make them happy 192979492689e40d4f4d3d8a7262781d56fb295b4b86Yinghai Lu */ 193079492689e40d4f4d3d8a7262781d56fb295b4b86Yinghai Lu port->mctrl |= TIOCM_DTR; 193179492689e40d4f4d3d8a7262781d56fb295b4b86Yinghai Lu 1932149b36eae2ab6aa6056664f4bc461f3d3affc9c1Alan Cox port->ops->set_termios(port, &termios, &dummy); 1933f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel /* 1934f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel * Allow the setting of the UART parameters with a NULL console 1935f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel * too: 1936f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel */ 1937f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel if (co) 1938f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel co->cflag = termios.c_cflag; 19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1942f2d937f3bf00665ccf048b3b6616ef95859b0945Jason WesselEXPORT_SYMBOL_GPL(uart_set_options); 19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_SERIAL_CORE_CONSOLE */ 19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_change_pm(struct uart_state *state, int pm_state) 19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1947ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox struct uart_port *port = state->uart_port; 19481281e36027a9119356bd93b5e7853c72c35dd462Andrew Victor 19491281e36027a9119356bd93b5e7853c72c35dd462Andrew Victor if (state->pm_state != pm_state) { 19501281e36027a9119356bd93b5e7853c72c35dd462Andrew Victor if (port->ops->pm) 19511281e36027a9119356bd93b5e7853c72c35dd462Andrew Victor port->ops->pm(port, pm_state, state->pm_state); 19521281e36027a9119356bd93b5e7853c72c35dd462Andrew Victor state->pm_state = pm_state; 19531281e36027a9119356bd93b5e7853c72c35dd462Andrew Victor } 19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1956b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetskistruct uart_match { 1957b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski struct uart_port *port; 1958b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski struct uart_driver *driver; 1959b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski}; 1960b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski 1961b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetskistatic int serial_match_port(struct device *dev, void *data) 1962b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski{ 1963b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski struct uart_match *match = data; 19647ca796f492a11f9408e661c8f22cd8c4f486b8e5Guennadi Liakhovetski struct tty_driver *tty_drv = match->driver->tty_driver; 19657ca796f492a11f9408e661c8f22cd8c4f486b8e5Guennadi Liakhovetski dev_t devt = MKDEV(tty_drv->major, tty_drv->minor_start) + 19667ca796f492a11f9408e661c8f22cd8c4f486b8e5Guennadi Liakhovetski match->port->line; 1967b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski 1968b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski return dev->devt == devt; /* Actually, only one tty per port */ 1969b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski} 1970b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski 1971ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Coxint uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) 19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1973ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct uart_state *state = drv->state + uport->line; 1974ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct tty_port *port = &state->port; 1975b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski struct device *tty_dev; 1976ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct uart_match match = {uport, drv}; 1977192251352f912bccfb942ea35801d2357f11f592Alan Cox struct tty_struct *tty; 19781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1979a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1981192251352f912bccfb942ea35801d2357f11f592Alan Cox /* Must be inside the mutex lock until we convert to tty_port */ 1982192251352f912bccfb942ea35801d2357f11f592Alan Cox tty = port->tty; 1983192251352f912bccfb942ea35801d2357f11f592Alan Cox 1984ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox tty_dev = device_find_child(uport->dev, &match, serial_match_port); 1985b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski if (device_may_wakeup(tty_dev)) { 19863f960dbb9dfe29ff283810624c4340c79fde87f5Govindraj.R if (!enable_irq_wake(uport->irq)) 19873f960dbb9dfe29ff283810624c4340c79fde87f5Govindraj.R uport->irq_wake = 1; 1988b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski put_device(tty_dev); 1989a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 1990b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski return 0; 1991b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski } 19924547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec if (console_suspend_enabled || !uart_console(uport)) 19934547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec uport->suspended = 1; 1994b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski 1995ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (port->flags & ASYNC_INITIALIZED) { 1996ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox const struct uart_ops *ops = uport->ops; 1997c8c6bfa39d6bd7347f43937c8767ae145b61bcb4Russell King int tries; 19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19994547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec if (console_suspend_enabled || !uart_console(uport)) { 20004547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec set_bit(ASYNCB_SUSPENDED, &port->flags); 20014547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec clear_bit(ASYNCB_INITIALIZED, &port->flags); 2002a6b93a908508810c5d51dd9b390283345af6f2d9Russell King 20034547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec spin_lock_irq(&uport->lock); 20044547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec ops->stop_tx(uport); 20054547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec ops->set_mctrl(uport, 0); 20064547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec ops->stop_rx(uport); 20074547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec spin_unlock_irq(&uport->lock); 20084547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec } 20091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait for the transmitter to empty. 20121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2013ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox for (tries = 3; !ops->tx_empty(uport) && tries; tries--) 20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep(10); 2015c8c6bfa39d6bd7347f43937c8767ae145b61bcb4Russell King if (!tries) 2016a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox printk(KERN_ERR "%s%s%s%d: Unable to drain " 2017a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox "transmitter\n", 2018ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox uport->dev ? dev_name(uport->dev) : "", 2019ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox uport->dev ? ": " : "", 20208440838bc5337243917f13bc14ea2445da5e0197David S. Miller drv->dev_name, 2021ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox drv->tty_driver->name_base + uport->line); 20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20234547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec if (console_suspend_enabled || !uart_console(uport)) 20244547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec ops->shutdown(uport); 20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Disable the console device before suspending. 20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20304547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec if (console_suspend_enabled && uart_console(uport)) 2031ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox console_stop(uport->cons); 20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20334547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec if (console_suspend_enabled || !uart_console(uport)) 20344547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec uart_change_pm(state, 3); 20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2036a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2041ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Coxint uart_resume_port(struct uart_driver *drv, struct uart_port *uport) 20421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2043ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct uart_state *state = drv->state + uport->line; 2044ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct tty_port *port = &state->port; 204503a74dcc7eebe6edd778317e82fafdf71e68488cArjan van de Ven struct device *tty_dev; 2046ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct uart_match match = {uport, drv}; 2047ba15ab0e8de0d4439a91342ad52d55ca9e313f3dDeepak Saxena struct ktermios termios; 20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2049a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2051ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox tty_dev = device_find_child(uport->dev, &match, serial_match_port); 2052ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (!uport->suspended && device_may_wakeup(tty_dev)) { 20533f960dbb9dfe29ff283810624c4340c79fde87f5Govindraj.R if (uport->irq_wake) { 20543f960dbb9dfe29ff283810624c4340c79fde87f5Govindraj.R disable_irq_wake(uport->irq); 20553f960dbb9dfe29ff283810624c4340c79fde87f5Govindraj.R uport->irq_wake = 0; 20563f960dbb9dfe29ff283810624c4340c79fde87f5Govindraj.R } 2057a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 2058b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski return 0; 2059b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski } 2060ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox uport->suspended = 0; 2061b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski 20621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Re-enable the console device after suspending. 20641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20655933a161abcb8d83a2c145177f48027c3c0a8995Yin Kangkai if (uart_console(uport)) { 2066891b9dd10764352926e1e107756aa229dfa2c210Jason Wang /* 2067891b9dd10764352926e1e107756aa229dfa2c210Jason Wang * First try to use the console cflag setting. 2068891b9dd10764352926e1e107756aa229dfa2c210Jason Wang */ 2069891b9dd10764352926e1e107756aa229dfa2c210Jason Wang memset(&termios, 0, sizeof(struct ktermios)); 2070891b9dd10764352926e1e107756aa229dfa2c210Jason Wang termios.c_cflag = uport->cons->cflag; 2071891b9dd10764352926e1e107756aa229dfa2c210Jason Wang 2072891b9dd10764352926e1e107756aa229dfa2c210Jason Wang /* 2073891b9dd10764352926e1e107756aa229dfa2c210Jason Wang * If that's unset, use the tty termios setting. 2074891b9dd10764352926e1e107756aa229dfa2c210Jason Wang */ 2075891b9dd10764352926e1e107756aa229dfa2c210Jason Wang if (port->tty && port->tty->termios && termios.c_cflag == 0) 2076891b9dd10764352926e1e107756aa229dfa2c210Jason Wang termios = *(port->tty->termios); 2077891b9dd10764352926e1e107756aa229dfa2c210Jason Wang 2078ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox uport->ops->set_termios(uport, &termios, NULL); 20795933a161abcb8d83a2c145177f48027c3c0a8995Yin Kangkai if (console_suspend_enabled) 20805933a161abcb8d83a2c145177f48027c3c0a8995Yin Kangkai console_start(uport->cons); 20811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2083ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (port->flags & ASYNC_SUSPENDED) { 2084ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox const struct uart_ops *ops = uport->ops; 2085ee31b337852ca8a65840702544ff5c64d37740f5Russell King int ret; 20861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20879d778a69370cc1b643b13648df971c83ff5654efRussell King uart_change_pm(state, 0); 2088ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox spin_lock_irq(&uport->lock); 2089ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox ops->set_mctrl(uport, 0); 2090ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox spin_unlock_irq(&uport->lock); 20914547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec if (console_suspend_enabled || !uart_console(uport)) { 2092192251352f912bccfb942ea35801d2357f11f592Alan Cox /* Protected by port mutex for now */ 2093192251352f912bccfb942ea35801d2357f11f592Alan Cox struct tty_struct *tty = port->tty; 20944547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec ret = ops->startup(uport); 20954547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec if (ret == 0) { 2096192251352f912bccfb942ea35801d2357f11f592Alan Cox if (tty) 2097192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_change_speed(tty, state, NULL); 20984547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec spin_lock_irq(&uport->lock); 20994547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec ops->set_mctrl(uport, uport->mctrl); 21004547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec ops->start_tx(uport); 21014547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec spin_unlock_irq(&uport->lock); 21024547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec set_bit(ASYNCB_INITIALIZED, &port->flags); 21034547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec } else { 21044547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec /* 21054547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec * Failed to resume - maybe hardware went away? 21064547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec * Clear the "initialized" flag so we won't try 21074547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec * to call the low level drivers shutdown method. 21084547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec */ 2109192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_shutdown(tty, state); 21104547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec } 2111ee31b337852ca8a65840702544ff5c64d37740f5Russell King } 2112a6b93a908508810c5d51dd9b390283345af6f2d9Russell King 2113ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox clear_bit(ASYNCB_SUSPENDED, &port->flags); 21141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2116a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 21171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 21191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void 21221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_report_port(struct uart_driver *drv, struct uart_port *port) 21231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 212430b7a3bc133c5b4a723163be35157ed709fca91cRussell King char address[64]; 212530b7a3bc133c5b4a723163be35157ed709fca91cRussell King 21261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (port->iotype) { 21271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case UPIO_PORT: 21289bde10a4b8c54804236d3d6b4b75e98825a921e7Andrew Morton snprintf(address, sizeof(address), "I/O 0x%lx", port->iobase); 21291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case UPIO_HUB6: 213130b7a3bc133c5b4a723163be35157ed709fca91cRussell King snprintf(address, sizeof(address), 21329bde10a4b8c54804236d3d6b4b75e98825a921e7Andrew Morton "I/O 0x%lx offset 0x%x", port->iobase, port->hub6); 21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case UPIO_MEM: 21351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case UPIO_MEM32: 213621c614a7899046ab108b3d327d76c33443a8ebf2Pantelis Antoniou case UPIO_AU: 21373be91ec7388bae3cf1bfb4febcee5ab6c65f409fZang Roy-r case UPIO_TSI: 2138beab697ab4b2962e3d741b476abe443baad0933dMarc St-Jean case UPIO_DWAPB: 2139a3ae0fc34f58e7163b7724feb3d77aa4603f0dc3Jamie Iles case UPIO_DWAPB32: 214030b7a3bc133c5b4a723163be35157ed709fca91cRussell King snprintf(address, sizeof(address), 21414f640efb3170dbcf99a37a3cc99060647b95428cJosh Boyer "MMIO 0x%llx", (unsigned long long)port->mapbase); 214230b7a3bc133c5b4a723163be35157ed709fca91cRussell King break; 214330b7a3bc133c5b4a723163be35157ed709fca91cRussell King default: 214430b7a3bc133c5b4a723163be35157ed709fca91cRussell King strlcpy(address, "*unknown*", sizeof(address)); 21451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 21461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 214730b7a3bc133c5b4a723163be35157ed709fca91cRussell King 21480cf669d5c5d08eb827df9867429df21cf030eba6Russell King printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n", 21494bfe090b0a29258eeeb026a09a96cf5b5838ac63Kay Sievers port->dev ? dev_name(port->dev) : "", 21500cf669d5c5d08eb827df9867429df21cf030eba6Russell King port->dev ? ": " : "", 21518440838bc5337243917f13bc14ea2445da5e0197David S. Miller drv->dev_name, 21528440838bc5337243917f13bc14ea2445da5e0197David S. Miller drv->tty_driver->name_base + port->line, 21538440838bc5337243917f13bc14ea2445da5e0197David S. Miller address, port->irq, uart_type(port)); 21541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_configure_port(struct uart_driver *drv, struct uart_state *state, 21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_port *port) 21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 21601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int flags; 21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 21631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If there isn't a port here, don't do anything further. 21641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 21651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!port->iobase && !port->mapbase && !port->membase) 21661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 21671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 21691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Now do the auto configuration stuff. Note that config_port 21701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is expected to claim the resources and map the port for us. 21711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 21728e23fcc89c8091790903927449f8efb9b4e23960David Daney flags = 0; 21731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->flags & UPF_AUTO_IRQ) 21741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags |= UART_CONFIG_IRQ; 21751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->flags & UPF_BOOT_AUTOCONF) { 21768e23fcc89c8091790903927449f8efb9b4e23960David Daney if (!(port->flags & UPF_FIXED_TYPE)) { 21778e23fcc89c8091790903927449f8efb9b4e23960David Daney port->type = PORT_UNKNOWN; 21788e23fcc89c8091790903927449f8efb9b4e23960David Daney flags |= UART_CONFIG_TYPE; 21798e23fcc89c8091790903927449f8efb9b4e23960David Daney } 21801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->ops->config_port(port, flags); 21811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->type != PORT_UNKNOWN) { 21841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 21851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_report_port(drv, port); 21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21883689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis /* Power up port for set_mctrl() */ 21893689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis uart_change_pm(state, 0); 21903689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis 21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ensure that the modem control lines are de-activated. 2193c3e4642be734ce3d2c7398246d8cbced3a039f54Yinghai Lu * keep the DTR setting that is set in uart_set_options() 21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We probably don't need a spinlock around this, but 21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port->lock, flags); 2197c3e4642be734ce3d2c7398246d8cbced3a039f54Yinghai Lu port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR); 21981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port->lock, flags); 21991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 220197d97224ff361e08777fb33e0fd193ca877dac28Russell King * If this driver supports console, and it hasn't been 220297d97224ff361e08777fb33e0fd193ca877dac28Russell King * successfully registered yet, try to re-register it. 220397d97224ff361e08777fb33e0fd193ca877dac28Russell King * It may be that the port was not available. 220497d97224ff361e08777fb33e0fd193ca877dac28Russell King */ 220597d97224ff361e08777fb33e0fd193ca877dac28Russell King if (port->cons && !(port->cons->flags & CON_ENABLED)) 220697d97224ff361e08777fb33e0fd193ca877dac28Russell King register_console(port->cons); 220797d97224ff361e08777fb33e0fd193ca877dac28Russell King 220897d97224ff361e08777fb33e0fd193ca877dac28Russell King /* 22091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Power down all ports by default, except the 22101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * console if we have one. 22111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!uart_console(port)) 22131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_change_pm(state, 3); 22141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2217f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel#ifdef CONFIG_CONSOLE_POLL 2218f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2219f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic int uart_poll_init(struct tty_driver *driver, int line, char *options) 2220f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel{ 2221f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_driver *drv = driver->driver_state; 2222f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_state *state = drv->state + line; 2223f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_port *port; 2224f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel int baud = 9600; 2225f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel int bits = 8; 2226f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel int parity = 'n'; 2227f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel int flow = 'n'; 2228f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2229ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (!state || !state->uart_port) 2230f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel return -1; 2231f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2232ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox port = state->uart_port; 2233f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel if (!(port->ops->poll_get_char && port->ops->poll_put_char)) 2234f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel return -1; 2235f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2236f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel if (options) { 2237f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel uart_parse_options(options, &baud, &parity, &bits, &flow); 2238f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel return uart_set_options(port, NULL, baud, parity, bits, flow); 2239f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel } 2240f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2241f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel return 0; 2242f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel} 2243f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2244f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic int uart_poll_get_char(struct tty_driver *driver, int line) 2245f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel{ 2246f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_driver *drv = driver->driver_state; 2247f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_state *state = drv->state + line; 2248f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_port *port; 2249f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2250ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (!state || !state->uart_port) 2251f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel return -1; 2252f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2253ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox port = state->uart_port; 2254f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel return port->ops->poll_get_char(port); 2255f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel} 2256f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2257f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic void uart_poll_put_char(struct tty_driver *driver, int line, char ch) 2258f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel{ 2259f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_driver *drv = driver->driver_state; 2260f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_state *state = drv->state + line; 2261f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_port *port; 2262f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2263ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (!state || !state->uart_port) 2264f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel return; 2265f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2266ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox port = state->uart_port; 2267f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel port->ops->poll_put_char(port, ch); 2268f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel} 2269f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel#endif 2270f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2271b68e31d0ebbcc909d1941f9f230c9d062a3a13d3Jeff Dikestatic const struct tty_operations uart_ops = { 22721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = uart_open, 22731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .close = uart_close, 22741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = uart_write, 22751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .put_char = uart_put_char, 22761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .flush_chars = uart_flush_chars, 22771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_room = uart_write_room, 22781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .chars_in_buffer= uart_chars_in_buffer, 22791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .flush_buffer = uart_flush_buffer, 22801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ioctl = uart_ioctl, 22811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .throttle = uart_throttle, 22821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .unthrottle = uart_unthrottle, 22831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .send_xchar = uart_send_xchar, 22841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_termios = uart_set_termios, 228564e9159f5d2c4edf5fa6425031e556f8fddaf7e6Alan Cox .set_ldisc = uart_set_ldisc, 22861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .stop = uart_stop, 22871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .start = uart_start, 22881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .hangup = uart_hangup, 22891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .break_ctl = uart_break_ctl, 22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .wait_until_sent= uart_wait_until_sent, 22911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PROC_FS 2292d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan .proc_fops = &uart_proc_fops, 22931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 22941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .tiocmget = uart_tiocmget, 22951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .tiocmset = uart_tiocmset, 2296d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox .get_icount = uart_get_icount, 2297f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel#ifdef CONFIG_CONSOLE_POLL 2298f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel .poll_init = uart_poll_init, 2299f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel .poll_get_char = uart_poll_get_char, 2300f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel .poll_put_char = uart_poll_put_char, 2301f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel#endif 23021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 23031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2304de0c8cb314cc737c47a00de33cd6246accf94192Alan Coxstatic const struct tty_port_operations uart_port_ops = { 2305de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox .carrier_raised = uart_carrier_raised, 2306de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox .dtr_rts = uart_dtr_rts, 2307de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox}; 2308de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox 23091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 23101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_register_driver - register a driver with the uart core layer 23111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @drv: low level driver structure 23121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 23131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Register a uart driver with the core driver. We in turn register 23141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with the tty layer, and initialise the core driver per-port state. 23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 23161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We have a proc file in /proc/tty/driver which is named after the 23171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * normal driver. 23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 23191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drv->port should be NULL, and the per-port structures should be 23201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * registered using uart_add_one_port after this call has succeeded. 23211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint uart_register_driver(struct uart_driver *drv) 23231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23249e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa struct tty_driver *normal; 23251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, retval; 23261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(drv->state); 23281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 23301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Maybe we should be using a slab cache for this, especially if 23311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we have a large number of ports to handle. 23321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23338f31bb39ec2a5622974666c72257e74c22492602Burman Yan drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL); 23341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!drv->state) 23351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 23361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23379e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa normal = alloc_tty_driver(drv->nr); 23381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!normal) 23399e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa goto out_kfree; 23401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds drv->tty_driver = normal; 23421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->owner = drv->owner; 23441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->driver_name = drv->driver_name; 23451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->name = drv->dev_name; 23461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->major = drv->major; 23471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->minor_start = drv->minor; 23481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->type = TTY_DRIVER_TYPE_SERIAL; 23491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->subtype = SERIAL_TYPE_NORMAL; 23501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->init_termios = tty_std_termios; 23511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; 2352606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600; 2353331b831983f9d706f4a40d08a996d5c2c7a6ea7bGreg Kroah-Hartman normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; 23541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->driver_state = drv; 23551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_set_operations(normal, &uart_ops); 23561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 23581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialise the UART state(s). 23591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < drv->nr; i++) { 23611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = drv->state + i; 2362a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 23631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2364a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tty_port_init(port); 2365de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox port->ops = &uart_port_ops; 2366a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox port->close_delay = 500; /* .5 seconds */ 2367a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox port->closing_wait = 30000; /* 30 seconds */ 2368ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox tasklet_init(&state->tlet, uart_tasklet_action, 2369f751928e0ddf54ea4fe5546f35e99efc5b5d9938Alan Cox (unsigned long)state); 23701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = tty_register_driver(normal); 23739e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa if (retval >= 0) 23749e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa return retval; 23759e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa 23769e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa put_tty_driver(normal); 23779e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosaout_kfree: 23789e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa kfree(drv->state); 23799e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosaout: 23809e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa return -ENOMEM; 23811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 23841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_unregister_driver - remove a driver from the uart core layer 23851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @drv: low level driver structure 23861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 23871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Remove all references to a driver from the core driver. The low 23881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * level driver must have removed all its ports via the 23891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_remove_one_port() if it registered them with uart_add_one_port(). 23901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (ie, drv->port == NULL) 23911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid uart_unregister_driver(struct uart_driver *drv) 23931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tty_driver *p = drv->tty_driver; 23951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_unregister_driver(p); 23961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_tty_driver(p); 23971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(drv->state); 23981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds drv->tty_driver = NULL; 23991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 24001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct tty_driver *uart_console_device(struct console *co, int *index) 24021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 24031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_driver *p = co->data; 24041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *index = co->index; 24051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return p->tty_driver; 24061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 24071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 24091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_add_one_port - attach a driver-defined port structure 24101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @drv: pointer to the uart low level driver structure for this port 24111b9894f342a39601bb0420b7b8c7e445670c1b51Randy Dunlap * @uport: uart port structure to use for this port. 24121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 24131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This allows the driver to register its own uart_port structure 24141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with the core driver. The main purpose is to allow the low 24151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * level uart drivers to expand uart_port, rather than having yet 24161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * more levels of structures. 24171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2418a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Coxint uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) 24191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 24201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state; 2421a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port; 24221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 2423b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski struct device *tty_dev; 24241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(in_interrupt()); 24261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2427a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->line >= drv->nr) 24281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 24291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2430a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox state = drv->state + uport->line; 2431a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox port = &state->port; 24321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2433f392ecfa12de9a2baf72789b00557bac040d6171Arjan van de Ven mutex_lock(&port_mutex); 2434a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 2435ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (state->uart_port) { 24361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EINVAL; 24371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 24381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2440a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox state->uart_port = uport; 244197d97224ff361e08777fb33e0fd193ca877dac28Russell King state->pm_state = -1; 24421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2443a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->cons = drv->cons; 2444a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->state = state; 24451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2446976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King /* 2447976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King * If this port is a console, then the spinlock is already 2448976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King * initialised. 2449976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King */ 2450a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) { 2451a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox spin_lock_init(&uport->lock); 2452a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox lockdep_set_class(&uport->lock, &port_lock_key); 245313e83599d282ddfd544600df9db5ab343ac4662fIngo Molnar } 2454976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King 2455a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uart_configure_port(drv, state, uport); 24561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 24581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Register the port whether it's detected or not. This allows 24591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * setserial to be used to alter this ports parameters. 24601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2461a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev); 2462b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski if (likely(!IS_ERR(tty_dev))) { 246374081f8667d73ad59961cf63be5f0e9d6a87c8a3Alan Stern device_init_wakeup(tty_dev, 1); 2464b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski device_set_wakeup_enable(tty_dev, 0); 2465b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski } else 2466b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski printk(KERN_ERR "Cannot register tty device on line %d\n", 2467a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->line); 24681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 247068ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King * Ensure UPF_DEAD is not set. 247168ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King */ 2472a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->flags &= ~UPF_DEAD; 247368ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King 24741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: 2475a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 2476f392ecfa12de9a2baf72789b00557bac040d6171Arjan van de Ven mutex_unlock(&port_mutex); 24771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 24791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 24801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 24821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_remove_one_port - detach a driver defined port structure 24831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @drv: pointer to the uart low level driver structure for this port 24841b9894f342a39601bb0420b7b8c7e445670c1b51Randy Dunlap * @uport: uart port structure for this port 24851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 24861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This unhooks (and hangs up) the specified port structure from the 24871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * core driver. No further calls will be made to the low-level code 24881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for this port. 24891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2490a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Coxint uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) 24911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2492a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct uart_state *state = drv->state + uport->line; 2493a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 24941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(in_interrupt()); 24961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2497a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (state->uart_port != uport) 24981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ALERT "Removing wrong port: %p != %p\n", 2499a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox state->uart_port, uport); 25001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2501f392ecfa12de9a2baf72789b00557bac040d6171Arjan van de Ven mutex_lock(&port_mutex); 25021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 250468ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King * Mark the port "dead" - this prevents any opens from 250568ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King * succeeding while we shut down the port. 250668ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King */ 2507a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 2508a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->flags |= UPF_DEAD; 2509a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 251068ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King 251168ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King /* 2512aa4148cfc7b3b93eeaf755a7d14f10afaffe9a96Greg Kroah-Hartman * Remove the devices from the tty layer 25131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2514a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tty_unregister_device(drv->tty_driver, uport->line); 25151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2516a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (port->tty) 2517a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tty_vhangup(port->tty); 251868ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King 251968ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King /* 252068ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King * Free the port IO and memory resources, if any. 252168ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King */ 2522a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->type != PORT_UNKNOWN) 2523a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->ops->release_port(uport); 252468ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King 252568ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King /* 252668ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King * Indicate that there isn't a port here anymore. 252768ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King */ 2528a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->type = PORT_UNKNOWN; 252968ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King 253068ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King /* 253168ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King * Kill the tasklet, and free resources. 253268ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King */ 2533ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox tasklet_kill(&state->tlet); 253468ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King 2535ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox state->uart_port = NULL; 2536f392ecfa12de9a2baf72789b00557bac040d6171Arjan van de Ven mutex_unlock(&port_mutex); 25371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 25391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 25401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 25421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Are the two ports equivalent? 25431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 25441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint uart_match_port(struct uart_port *port1, struct uart_port *port2) 25451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 25461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port1->iotype != port2->iotype) 25471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 25481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (port1->iotype) { 25501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case UPIO_PORT: 25511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (port1->iobase == port2->iobase); 25521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case UPIO_HUB6: 25531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (port1->iobase == port2->iobase) && 25541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (port1->hub6 == port2->hub6); 25551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case UPIO_MEM: 2556d21b55d30b46c0b43821a2980e4998965fa37e33Sergei Shtylyov case UPIO_MEM32: 2557d21b55d30b46c0b43821a2980e4998965fa37e33Sergei Shtylyov case UPIO_AU: 2558d21b55d30b46c0b43821a2980e4998965fa37e33Sergei Shtylyov case UPIO_TSI: 2559beab697ab4b2962e3d741b476abe443baad0933dMarc St-Jean case UPIO_DWAPB: 2560a3ae0fc34f58e7163b7724feb3d77aa4603f0dc3Jamie Iles case UPIO_DWAPB32: 25611624f003349b49050f42c7d9f5407dfc05efb912Benjamin Herrenschmidt return (port1->mapbase == port2->mapbase); 25621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 25641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 25651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_match_port); 25661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_write_wakeup); 25681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_register_driver); 25691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_unregister_driver); 25701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_suspend_port); 25711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_resume_port); 25721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_add_one_port); 25731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_remove_one_port); 25741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Serial driver core"); 25761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 2577