serial_core.c revision 1f33a51d9771b34be3cb6f7fb96a325e17bbac7b
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver core for serial ports 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 1999 ARM Limited 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2000-2001 Deep Blue Solutions Ltd. 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version. 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details. 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/console.h> 28d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan#include <linux/proc_fs.h> 29d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan#include <linux/seq_file.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h> /* for serial_state and serial_icounter_struct */ 32ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox#include <linux/serial_core.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 34f392ecfa12de9a2baf72789b00557bac040d6171Arjan van de Ven#include <linux/mutex.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is used to lock changes in serial line configuration. 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 42f392ecfa12de9a2baf72789b00557bac040d6171Arjan van de Venstatic DEFINE_MUTEX(port_mutex); 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4413e83599d282ddfd544600df9db5ab343ac4662fIngo Molnar/* 4513e83599d282ddfd544600df9db5ab343ac4662fIngo Molnar * lockdep: port->lock is initialized in two places, but we 4613e83599d282ddfd544600df9db5ab343ac4662fIngo Molnar * want only one lock-class: 4713e83599d282ddfd544600df9db5ab343ac4662fIngo Molnar */ 4813e83599d282ddfd544600df9db5ab343ac4662fIngo Molnarstatic struct lock_class_key port_lock_key; 4913e83599d282ddfd544600df9db5ab343ac4662fIngo Molnar 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SERIAL_CORE_CONSOLE 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line) 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define uart_console(port) (0) 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic void uart_change_speed(struct tty_struct *tty, struct uart_state *state, 59a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox struct ktermios *old_termios); 601f33a51d9771b34be3cb6f7fb96a325e17bbac7bJiri Slabystatic void uart_wait_until_sent(struct tty_struct *tty, int timeout); 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_change_pm(struct uart_state *state, int pm_state); 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine is used by the interrupt handler to schedule processing in 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the software interrupt portion of the driver. 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid uart_write_wakeup(struct uart_port *port) 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 69ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox struct uart_state *state = port->state; 70d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek /* 71d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek * This means you called this function _after_ the port was 72d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek * closed. No cookie for you. 73d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek */ 74ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox BUG_ON(!state); 75ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox tasklet_schedule(&state->tlet); 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_stop(struct tty_struct *tty) 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 81ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox struct uart_port *port = state->uart_port; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port->lock, flags); 85b129a8ccd53f74c43e4c83c8e0031a4990040830Russell King port->ops->stop_tx(port); 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port->lock, flags); 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __uart_start(struct tty_struct *tty) 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 92ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox struct uart_port *port = state->uart_port; 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 94ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (!uart_circ_empty(&state->xmit) && state->xmit.buf && 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !tty->stopped && !tty->hw_stopped) 96b129a8ccd53f74c43e4c83c8e0031a4990040830Russell King port->ops->start_tx(port); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_start(struct tty_struct *tty) 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 102ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox struct uart_port *port = state->uart_port; 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port->lock, flags); 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __uart_start(tty); 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port->lock, flags); 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_tasklet_action(unsigned long data) 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = (struct uart_state *)data; 113ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox tty_wakeup(state->port.tty); 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear) 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int old; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port->lock, flags); 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds old = port->mctrl; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->mctrl = (old & ~clear) | set; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (old != port->mctrl) 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->ops->set_mctrl(port, port->mctrl); 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port->lock, flags); 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 130a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox#define uart_set_mctrl(port, set) uart_update_mctrl(port, set, 0) 131a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox#define uart_clear_mctrl(port, clear) uart_update_mctrl(port, 0, clear) 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Startup the port. This will be called once per open. All calls 135df4f4dd429870f435f8d5d9d561db029a29f063bAlan Cox * will be serialised by the per-port mutex. 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 137192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic int uart_startup(struct tty_struct *tty, struct uart_state *state, int init_hw) 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 14046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct tty_port *port = &state->port; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long page; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 144ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (port->flags & ASYNC_INITIALIZED) 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the TTY IO error marker - we will only clear this 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * once we have successfully opened the port. Also set 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * up the tty->alt_speed kludge 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 152192251352f912bccfb942ea35801d2357f11f592Alan Cox set_bit(TTY_IO_ERROR, &tty->flags); 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->type == PORT_UNKNOWN) 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialise and allocate the transmit and temporary 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * buffer. 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 161ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (!state->xmit.buf) { 162df4f4dd429870f435f8d5d9d561db029a29f063bAlan Cox /* This is protected by the per port mutex */ 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds page = get_zeroed_page(GFP_KERNEL); 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!page) 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 167ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox state->xmit.buf = (unsigned char *) page; 168ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox uart_circ_clear(&state->xmit); 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox retval = uport->ops->startup(uport); 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval == 0) { 173c7d7abff40c27f82fe78b1091ab3fad69b2546f9Jiri Slaby if (uart_console(uport) && uport->cons->cflag) { 174c7d7abff40c27f82fe78b1091ab3fad69b2546f9Jiri Slaby tty->termios->c_cflag = uport->cons->cflag; 175c7d7abff40c27f82fe78b1091ab3fad69b2546f9Jiri Slaby uport->cons->cflag = 0; 176c7d7abff40c27f82fe78b1091ab3fad69b2546f9Jiri Slaby } 177c7d7abff40c27f82fe78b1091ab3fad69b2546f9Jiri Slaby /* 178c7d7abff40c27f82fe78b1091ab3fad69b2546f9Jiri Slaby * Initialise the hardware port settings. 179c7d7abff40c27f82fe78b1091ab3fad69b2546f9Jiri Slaby */ 180c7d7abff40c27f82fe78b1091ab3fad69b2546f9Jiri Slaby uart_change_speed(tty, state, NULL); 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 182c7d7abff40c27f82fe78b1091ab3fad69b2546f9Jiri Slaby if (init_hw) { 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Setup the RTS and DTR signals once the 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * port is open and ready to respond. 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 187192251352f912bccfb942ea35801d2357f11f592Alan Cox if (tty->termios->c_cflag & CBAUD) 18846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR); 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 191ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (port->flags & ASYNC_CTS_FLOW) { 19246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_lock_irq(&uport->lock); 19346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) 194192251352f912bccfb942ea35801d2357f11f592Alan Cox tty->hw_stopped = 1; 19546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_unlock_irq(&uport->lock); 1960dd7a1aed7c34a39917c4faf75b4230c169e809bRussell King } 1970dd7a1aed7c34a39917c4faf75b4230c169e809bRussell King 198ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox set_bit(ASYNCB_INITIALIZED, &port->flags); 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 200192251352f912bccfb942ea35801d2357f11f592Alan Cox clear_bit(TTY_IO_ERROR, &tty->flags); 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval && capable(CAP_SYS_ADMIN)) 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine will shutdown a serial port; interrupts are disabled, and 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DTR is dropped if the hangup on close termio flag is on. Calls to 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_shutdown are serialised by the per-port semaphore. 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 214192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic void uart_shutdown(struct tty_struct *tty, struct uart_state *state) 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 216ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct uart_port *uport = state->uart_port; 217bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox struct tty_port *port = &state->port; 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 220ee31b337852ca8a65840702544ff5c64d37740f5Russell King * Set the TTY IO error marker 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 222f751928e0ddf54ea4fe5546f35e99efc5b5d9938Alan Cox if (tty) 223f751928e0ddf54ea4fe5546f35e99efc5b5d9938Alan Cox set_bit(TTY_IO_ERROR, &tty->flags); 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 225bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox if (test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) { 226ee31b337852ca8a65840702544ff5c64d37740f5Russell King /* 227ee31b337852ca8a65840702544ff5c64d37740f5Russell King * Turn off DTR and RTS early. 228ee31b337852ca8a65840702544ff5c64d37740f5Russell King */ 229f751928e0ddf54ea4fe5546f35e99efc5b5d9938Alan Cox if (!tty || (tty->termios->c_cflag & HUPCL)) 230ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); 231ee31b337852ca8a65840702544ff5c64d37740f5Russell King 232ee31b337852ca8a65840702544ff5c64d37740f5Russell King /* 233ee31b337852ca8a65840702544ff5c64d37740f5Russell King * clear delta_msr_wait queue to avoid mem leaks: we may free 234ee31b337852ca8a65840702544ff5c64d37740f5Russell King * the irq here so the queue might never be woken up. Note 235ee31b337852ca8a65840702544ff5c64d37740f5Russell King * that we won't end up waiting on delta_msr_wait again since 236ee31b337852ca8a65840702544ff5c64d37740f5Russell King * any outstanding file descriptors should be pointing at 237ee31b337852ca8a65840702544ff5c64d37740f5Russell King * hung_up_tty_fops now. 238ee31b337852ca8a65840702544ff5c64d37740f5Russell King */ 239bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox wake_up_interruptible(&port->delta_msr_wait); 240ee31b337852ca8a65840702544ff5c64d37740f5Russell King 241ee31b337852ca8a65840702544ff5c64d37740f5Russell King /* 242ee31b337852ca8a65840702544ff5c64d37740f5Russell King * Free the IRQ and disable the port. 243ee31b337852ca8a65840702544ff5c64d37740f5Russell King */ 244ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox uport->ops->shutdown(uport); 245ee31b337852ca8a65840702544ff5c64d37740f5Russell King 246ee31b337852ca8a65840702544ff5c64d37740f5Russell King /* 247ee31b337852ca8a65840702544ff5c64d37740f5Russell King * Ensure that the IRQ handler isn't running on another CPU. 248ee31b337852ca8a65840702544ff5c64d37740f5Russell King */ 249ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox synchronize_irq(uport->irq); 250ee31b337852ca8a65840702544ff5c64d37740f5Russell King } 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 253ee31b337852ca8a65840702544ff5c64d37740f5Russell King * kill off our tasklet 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 255ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox tasklet_kill(&state->tlet); 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free the transmit buffer page. 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 260ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (state->xmit.buf) { 261ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox free_page((unsigned long)state->xmit.buf); 262ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox state->xmit.buf = NULL; 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_update_timeout - update per-port FIFO timeout. 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @port: uart_port structure describing the port 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @cflag: termios cflag value 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @baud: speed of the port 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the port FIFO timeout value. The @cflag value should 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reflect the actual hardware settings. 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_update_timeout(struct uart_port *port, unsigned int cflag, 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int baud) 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int bits; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* byte size and parity */ 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cflag & CSIZE) { 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS5: 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits = 7; 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS6: 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits = 8; 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS7: 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits = 9; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits = 10; 294a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox break; /* CS8 */ 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & CSTOPB) 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits++; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & PARENB) 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits++; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The total number of bits to be transmitted in the fifo. 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits = bits * port->fifosize; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Figure the timeout to send the above number of bits. 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Add .02 seconds of slop 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->timeout = (HZ * bits) / baud + HZ/50; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_update_timeout); 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_get_baud_rate - return baud rate for a particular port 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @port: uart_port structure describing the port in question. 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @termios: desired termios settings. 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @old: old termios (or NULL) 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @min: minimum acceptable baud rate 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @max: maximum acceptable baud rate 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Decode the termios structure into a numeric baud rate, 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * taking account of the magic 38400 baud rate (with spd_* 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * flags), and mapping the %B0 rate to 9600 baud. 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the new baud rate is invalid, try the old termios setting. 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If it's still invalid, we try 9600 baud. 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Update the @termios structure to reflect the baud rate 332eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox * we're actually going to be using. Don't do this for the case 333eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox * where B0 is requested ("hang up"). 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsunsigned int 336606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Coxuart_get_baud_rate(struct uart_port *port, struct ktermios *termios, 337606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox struct ktermios *old, unsigned int min, unsigned int max) 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int try, baud, altbaud = 38400; 340eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox int hung_up = 0; 3410077d45e46fe2af3aaee5813c99268afcd0e7c0eRussell King upf_t flags = port->flags & UPF_SPD_MASK; 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (flags == UPF_SPD_HI) 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds altbaud = 57600; 34582cb7ba10deafe17686bf22ce4a7a303a77a197fAndré Goddard Rosa else if (flags == UPF_SPD_VHI) 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds altbaud = 115200; 34782cb7ba10deafe17686bf22ce4a7a303a77a197fAndré Goddard Rosa else if (flags == UPF_SPD_SHI) 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds altbaud = 230400; 34982cb7ba10deafe17686bf22ce4a7a303a77a197fAndré Goddard Rosa else if (flags == UPF_SPD_WARP) 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds altbaud = 460800; 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (try = 0; try < 2; try++) { 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds baud = tty_termios_baud_rate(termios); 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The spd_hi, spd_vhi, spd_shi, spd_warp kludge... 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Die! Die! Die! 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (baud == 38400) 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds baud = altbaud; 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Special case: B0 rate. 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 365eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox if (baud == 0) { 366eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox hung_up = 1; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds baud = 9600; 368eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox } 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (baud >= min && baud <= max) 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return baud; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Oops, the quotient was zero. Try again with 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the old baud rate if possible. 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios->c_cflag &= ~CBAUD; 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (old) { 3796d4d67beb963de8865499781b8523e5b683819c3Alan Cox baud = tty_termios_baud_rate(old); 380eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox if (!hung_up) 381eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox tty_termios_encode_baud_rate(termios, 382eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox baud, baud); 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds old = NULL; 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 38816ae2a877bf4179737921235e85ceffd7b79354fAlan Cox * As a last resort, if the range cannot be met then clip to 38916ae2a877bf4179737921235e85ceffd7b79354fAlan Cox * the nearest chip supported rate. 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 39116ae2a877bf4179737921235e85ceffd7b79354fAlan Cox if (!hung_up) { 39216ae2a877bf4179737921235e85ceffd7b79354fAlan Cox if (baud <= min) 39316ae2a877bf4179737921235e85ceffd7b79354fAlan Cox tty_termios_encode_baud_rate(termios, 39416ae2a877bf4179737921235e85ceffd7b79354fAlan Cox min + 1, min + 1); 39516ae2a877bf4179737921235e85ceffd7b79354fAlan Cox else 39616ae2a877bf4179737921235e85ceffd7b79354fAlan Cox tty_termios_encode_baud_rate(termios, 39716ae2a877bf4179737921235e85ceffd7b79354fAlan Cox max - 1, max - 1); 39816ae2a877bf4179737921235e85ceffd7b79354fAlan Cox } 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 40016ae2a877bf4179737921235e85ceffd7b79354fAlan Cox /* Should never happen */ 40116ae2a877bf4179737921235e85ceffd7b79354fAlan Cox WARN_ON(1); 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_get_baud_rate); 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_get_divisor - return uart clock divisor 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @port: uart_port structure describing the port. 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @baud: desired baud rate 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Calculate the uart clock divisor for the port. 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsunsigned int 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_get_divisor(struct uart_port *port, unsigned int baud) 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int quot; 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Old custom speed handling. 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds quot = port->custom_divisor; 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds quot = (port->uartclk + (8 * baud)) / (16 * baud); 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return quot; 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_get_divisor); 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43223d22cea85ba9114a59a32ca8dfb1e2aef52a278Alan Cox/* FIXME: Consistent locking policy */ 433192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic void uart_change_speed(struct tty_struct *tty, struct uart_state *state, 434192251352f912bccfb942ea35801d2357f11f592Alan Cox struct ktermios *old_termios) 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 436ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct tty_port *port = &state->port; 437ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct uart_port *uport = state->uart_port; 438606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox struct ktermios *termios; 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we have no tty, termios, or the port does not exist, 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * then we can't set the parameters for this port. 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 444ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (!tty || !tty->termios || uport->type == PORT_UNKNOWN) 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios = tty->termios; 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set flags based on termios cflag 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (termios->c_cflag & CRTSCTS) 453ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox set_bit(ASYNCB_CTS_FLOW, &port->flags); 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 455ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox clear_bit(ASYNCB_CTS_FLOW, &port->flags); 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (termios->c_cflag & CLOCAL) 458ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox clear_bit(ASYNCB_CHECK_CD, &port->flags); 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 460ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox set_bit(ASYNCB_CHECK_CD, &port->flags); 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 462ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox uport->ops->set_termios(uport, termios, old_termios); 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 465192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic inline int __uart_put_char(struct uart_port *port, 466192251352f912bccfb942ea35801d2357f11f592Alan Cox struct circ_buf *circ, unsigned char c) 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 46923d22cea85ba9114a59a32ca8dfb1e2aef52a278Alan Cox int ret = 0; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!circ->buf) 47223d22cea85ba9114a59a32ca8dfb1e2aef52a278Alan Cox return 0; 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port->lock, flags); 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (uart_circ_chars_free(circ) != 0) { 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds circ->buf[circ->head] = c; 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1); 47823d22cea85ba9114a59a32ca8dfb1e2aef52a278Alan Cox ret = 1; 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port->lock, flags); 48123d22cea85ba9114a59a32ca8dfb1e2aef52a278Alan Cox return ret; 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48423d22cea85ba9114a59a32ca8dfb1e2aef52a278Alan Coxstatic int uart_put_char(struct tty_struct *tty, unsigned char ch) 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 488ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox return __uart_put_char(state->uart_port, &state->xmit, ch); 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_flush_chars(struct tty_struct *tty) 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_start(tty); 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 496192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic int uart_write(struct tty_struct *tty, 497192251352f912bccfb942ea35801d2357f11f592Alan Cox const unsigned char *buf, int count) 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 500d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek struct uart_port *port; 501d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek struct circ_buf *circ; 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int c, ret = 0; 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 505d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek /* 506d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek * This means you called this function _after_ the port was 507d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek * closed. No cookie for you. 508d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek */ 509f751928e0ddf54ea4fe5546f35e99efc5b5d9938Alan Cox if (!state) { 510d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek WARN_ON(1); 511d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek return -EL3HLT; 512d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek } 513d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek 514ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox port = state->uart_port; 515ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox circ = &state->xmit; 516d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!circ->buf) 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port->lock, flags); 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (1) { 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count < c) 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c = count; 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (c <= 0) 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(circ->buf + circ->head, buf, c); 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1); 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += c; 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count -= c; 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret += c; 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port->lock, flags); 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_start(tty); 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int uart_write_room(struct tty_struct *tty) 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 542f34d7a5b7010b82fe97da95496b9971435530062Alan Cox unsigned long flags; 543f34d7a5b7010b82fe97da95496b9971435530062Alan Cox int ret; 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 545ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox spin_lock_irqsave(&state->uart_port->lock, flags); 546ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox ret = uart_circ_chars_free(&state->xmit); 547ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox spin_unlock_irqrestore(&state->uart_port->lock, flags); 548f34d7a5b7010b82fe97da95496b9971435530062Alan Cox return ret; 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int uart_chars_in_buffer(struct tty_struct *tty) 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 554f34d7a5b7010b82fe97da95496b9971435530062Alan Cox unsigned long flags; 555f34d7a5b7010b82fe97da95496b9971435530062Alan Cox int ret; 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 557ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox spin_lock_irqsave(&state->uart_port->lock, flags); 558ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox ret = uart_circ_chars_pending(&state->xmit); 559ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox spin_unlock_irqrestore(&state->uart_port->lock, flags); 560f34d7a5b7010b82fe97da95496b9971435530062Alan Cox return ret; 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_flush_buffer(struct tty_struct *tty) 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 56655d7b68996a5064f011d681bca412b6281d2f711Tetsuo Handa struct uart_port *port; 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 569d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek /* 570d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek * This means you called this function _after_ the port was 571d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek * closed. No cookie for you. 572d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek */ 573f751928e0ddf54ea4fe5546f35e99efc5b5d9938Alan Cox if (!state) { 574d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek WARN_ON(1); 575d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek return; 576d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek } 577d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek 578ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox port = state->uart_port; 579eb3a1e1145ca8f12372c7c96aa0702d86a9002a9Jiri Slaby pr_debug("uart_flush_buffer(%d) called\n", tty->index); 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port->lock, flags); 582ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox uart_circ_clear(&state->xmit); 5836bb0e3a59a089e23eecc0af3b6f6012b2a9affbaHaavard Skinnemoen if (port->ops->flush_buffer) 5846bb0e3a59a089e23eecc0af3b6f6012b2a9affbaHaavard Skinnemoen port->ops->flush_buffer(port); 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port->lock, flags); 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_wakeup(tty); 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function is used to send a high-priority XON/XOFF character to 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the device 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_send_xchar(struct tty_struct *tty, char ch) 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 596ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox struct uart_port *port = state->uart_port; 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->ops->send_xchar) 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->ops->send_xchar(port, ch); 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->x_char = ch; 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ch) { 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port->lock, flags); 605b129a8ccd53f74c43e4c83c8e0031a4990040830Russell King port->ops->start_tx(port); 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port->lock, flags); 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_throttle(struct tty_struct *tty) 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (I_IXOFF(tty)) 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_send_xchar(tty, STOP_CHAR(tty)); 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty->termios->c_cflag & CRTSCTS) 619ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox uart_clear_mctrl(state->uart_port, TIOCM_RTS); 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_unthrottle(struct tty_struct *tty) 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 625ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox struct uart_port *port = state->uart_port; 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (I_IXOFF(tty)) { 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->x_char) 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->x_char = 0; 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_send_xchar(tty, START_CHAR(tty)); 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty->termios->c_cflag & CRTSCTS) 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_set_mctrl(port, TIOCM_RTS); 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int uart_get_info(struct uart_state *state, 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serial_struct __user *retinfo) 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 641a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct uart_port *uport = state->uart_port; 642a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serial_struct tmp; 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(&tmp, 0, sizeof(tmp)); 646f34d7a5b7010b82fe97da95496b9971435530062Alan Cox 647f34d7a5b7010b82fe97da95496b9971435530062Alan Cox /* Ensure the state we copy is consistent and no hardware changes 648f34d7a5b7010b82fe97da95496b9971435530062Alan Cox occur as we go */ 649a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 650f34d7a5b7010b82fe97da95496b9971435530062Alan Cox 651a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.type = uport->type; 652a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.line = uport->line; 653a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.port = uport->iobase; 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (HIGH_BITS_OFFSET) 655a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.port_high = (long) uport->iobase >> HIGH_BITS_OFFSET; 656a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.irq = uport->irq; 657a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.flags = uport->flags; 658a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.xmit_fifo_size = uport->fifosize; 659a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.baud_base = uport->uartclk / 16; 660a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.close_delay = port->close_delay / 10; 661016af53a6de6837e5be3da68901083ea85ebb4daAlan Cox tmp.closing_wait = port->closing_wait == ASYNC_CLOSING_WAIT_NONE ? 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ASYNC_CLOSING_WAIT_NONE : 663a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox port->closing_wait / 10; 664a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.custom_divisor = uport->custom_divisor; 665a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.hub6 = uport->hub6; 666a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.io_type = uport->iotype; 667a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.iomem_reg_shift = uport->regshift; 668a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.iomem_base = (void *)(unsigned long)uport->mapbase; 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 670a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 671f34d7a5b7010b82fe97da95496b9971435530062Alan Cox 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 677192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic int uart_set_info(struct tty_struct *tty, struct uart_state *state, 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serial_struct __user *newinfo) 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serial_struct new_serial; 68146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 68246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct tty_port *port = &state->port; 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long new_port; 6840077d45e46fe2af3aaee5813c99268afcd0e7c0eRussell King unsigned int change_irq, change_port, closing_wait; 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int old_custom_divisor, close_delay; 6860077d45e46fe2af3aaee5813c99268afcd0e7c0eRussell King upf_t old_flags, new_flags; 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_port = new_serial.port; 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (HIGH_BITS_OFFSET) 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_serial.irq = irq_canonicalize(new_serial.irq); 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds close_delay = new_serial.close_delay * 10; 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? 699016af53a6de6837e5be3da68901083ea85ebb4daAlan Cox ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 70291312cdb4fcd832341e425f74f49938e0503c929Alan Cox * This semaphore protects port->count. It is also 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * very useful to prevent opens. Also, take the 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * port configuration semaphore to make sure that a 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * module insertion/removal doesn't change anything 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * under us. 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 708a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox change_irq = !(uport->flags & UPF_FIXED_PORT) 71146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox && new_serial.irq != uport->irq; 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Since changing the 'type' of the port changes its resource 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * allocations, we should treat type changes the same as 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IO port changes. 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 71846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox change_port = !(uport->flags & UPF_FIXED_PORT) 71946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox && (new_port != uport->iobase || 72046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox (unsigned long)new_serial.iomem_base != uport->mapbase || 72146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox new_serial.hub6 != uport->hub6 || 72246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox new_serial.io_type != uport->iotype || 72346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox new_serial.iomem_reg_shift != uport->regshift || 72446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox new_serial.type != uport->type); 72546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox 72646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_flags = uport->flags; 7270077d45e46fe2af3aaee5813c99268afcd0e7c0eRussell King new_flags = new_serial.flags; 72846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_custom_divisor = uport->custom_divisor; 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!capable(CAP_SYS_ADMIN)) { 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EPERM; 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (change_irq || change_port || 73346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox (new_serial.baud_base != uport->uartclk / 16) || 73446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox (close_delay != port->close_delay) || 73546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox (closing_wait != port->closing_wait) || 736947deee8904b3c2edc7f59ab6e6242499e4dc434Russell King (new_serial.xmit_fifo_size && 73746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox new_serial.xmit_fifo_size != uport->fifosize) || 7380077d45e46fe2af3aaee5813c99268afcd0e7c0eRussell King (((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0)) 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 74046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->flags = ((uport->flags & ~UPF_USR_MASK) | 7410077d45e46fe2af3aaee5813c99268afcd0e7c0eRussell King (new_flags & UPF_USR_MASK)); 74246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->custom_divisor = new_serial.custom_divisor; 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto check_and_exit; 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ask the low level driver to verify the settings. 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 74946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->ops->verify_port) 75046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox retval = uport->ops->verify_port(uport, &new_serial); 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 752a62c41337356989387d15020dc0f0288aaacfa44Yinghai Lu if ((new_serial.irq >= nr_irqs) || (new_serial.irq < 0) || 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (new_serial.baud_base < 9600)) 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EINVAL; 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (change_port || change_irq) { 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EBUSY; 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Make sure that we are the sole user of this port. 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 765b58d13a0216d4e0753668214f23e1d2c24c30f8cAlan Cox if (tty_port_users(port) > 1) 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We need to shutdown the serial port at the old 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * port/type/irq combination. 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 772192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_shutdown(tty, state); 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (change_port) { 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long old_iobase, old_mapbase; 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int old_type, old_iotype, old_hub6, old_shift; 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 77946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_iobase = uport->iobase; 78046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_mapbase = uport->mapbase; 78146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_type = uport->type; 78246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_hub6 = uport->hub6; 78346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_iotype = uport->iotype; 78446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_shift = uport->regshift; 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free and release old regions 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (old_type != PORT_UNKNOWN) 79046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->ops->release_port(uport); 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 79246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->iobase = new_port; 79346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->type = new_serial.type; 79446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->hub6 = new_serial.hub6; 79546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->iotype = new_serial.io_type; 79646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->regshift = new_serial.iomem_reg_shift; 79746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->mapbase = (unsigned long)new_serial.iomem_base; 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Claim and map the new regions 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 80246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->type != PORT_UNKNOWN) { 80346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox retval = uport->ops->request_port(uport); 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Always success - Jean II */ 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we fail to request resources for the 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * new port, try to restore the old settings. 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval && old_type != PORT_UNKNOWN) { 81446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->iobase = old_iobase; 81546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->type = old_type; 81646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->hub6 = old_hub6; 81746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->iotype = old_iotype; 81846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->regshift = old_shift; 81946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->mapbase = old_mapbase; 82046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox retval = uport->ops->request_port(uport); 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we failed to restore the old settings, 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we fail like this. 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 82646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->type = PORT_UNKNOWN; 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We failed anyway. 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EBUSY; 832a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox /* Added to return the correct error -Ram Gupta */ 833a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox goto exit; 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 837abb4a2390737867353ebafc012d45f2b03f3f944David Gibson if (change_irq) 83846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->irq = new_serial.irq; 83946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (!(uport->flags & UPF_FIXED_PORT)) 84046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->uartclk = new_serial.baud_base * 16; 84146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->flags = (uport->flags & ~UPF_CHANGE_MASK) | 8420077d45e46fe2af3aaee5813c99268afcd0e7c0eRussell King (new_flags & UPF_CHANGE_MASK); 84346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->custom_divisor = new_serial.custom_divisor; 84446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox port->close_delay = close_delay; 84546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox port->closing_wait = closing_wait; 846947deee8904b3c2edc7f59ab6e6242499e4dc434Russell King if (new_serial.xmit_fifo_size) 84746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->fifosize = new_serial.xmit_fifo_size; 84846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (port->tty) 84946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox port->tty->low_latency = 85046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox (uport->flags & UPF_LOW_LATENCY) ? 1 : 0; 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds check_and_exit: 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 85446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->type == PORT_UNKNOWN) 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 856ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (port->flags & ASYNC_INITIALIZED) { 85746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (((old_flags ^ uport->flags) & UPF_SPD_MASK) || 85846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_custom_divisor != uport->custom_divisor) { 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If they're setting up a custom divisor or speed, 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * instead of clearing it, then bitch about it. No 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * need to rate-limit; it's CAP_SYS_ADMIN only. 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 86446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->flags & UPF_SPD_MASK) { 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char buf[64]; 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_NOTICE 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "%s sets custom speed on %s. This " 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "is deprecated.\n", current->comm, 86946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox tty_name(port->tty, buf)); 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 871192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_change_speed(tty, state, NULL); 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 874192251352f912bccfb942ea35801d2357f11f592Alan Cox retval = uart_startup(tty, state, 1); 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exit: 876a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 880192251352f912bccfb942ea35801d2357f11f592Alan Cox/** 881192251352f912bccfb942ea35801d2357f11f592Alan Cox * uart_get_lsr_info - get line status register info 882192251352f912bccfb942ea35801d2357f11f592Alan Cox * @tty: tty associated with the UART 883192251352f912bccfb942ea35801d2357f11f592Alan Cox * @state: UART being queried 884192251352f912bccfb942ea35801d2357f11f592Alan Cox * @value: returned modem value 885192251352f912bccfb942ea35801d2357f11f592Alan Cox * 886192251352f912bccfb942ea35801d2357f11f592Alan Cox * Note: uart_ioctl protects us against hangups. 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 888192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic int uart_get_lsr_info(struct tty_struct *tty, 889192251352f912bccfb942ea35801d2357f11f592Alan Cox struct uart_state *state, unsigned int __user *value) 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 89146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int result; 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 89446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox result = uport->ops->tx_empty(uport); 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we're about to load something into the transmit 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * register, we'll pretend the transmitter isn't empty to 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * avoid a race condition (depending on when the transmit 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupt happens). 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 90246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->x_char || 903ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox ((uart_circ_chars_pending(&state->xmit) > 0) && 904192251352f912bccfb942ea35801d2357f11f592Alan Cox !tty->stopped && !tty->hw_stopped)) 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result &= ~TIOCSER_TEMT; 906a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return put_user(result, value); 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 91060b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int uart_tiocmget(struct tty_struct *tty) 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 913a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 91446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result = -EIO; 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 917a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 91860b33c133ca0b7c0b6072c87234b63fee6e80558Alan Cox if (!(tty->flags & (1 << TTY_IO_ERROR))) { 91946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox result = uport->mctrl; 92046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_lock_irq(&uport->lock); 92146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox result |= uport->ops->get_mctrl(uport); 92246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_unlock_irq(&uport->lock); 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 924a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 93020b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxuart_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 93346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 934a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = -EIO; 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 937a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 93820b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Cox if (!(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 11046caa76b7786891b42b66a0e61e2c2fff2c884620Alan Coxuart_ioctl(struct tty_struct *tty, 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 11576caa76b7786891b42b66a0e61e2c2fff2c884620Alan Cox if (tty->flags & (1 << TTY_IO_ERROR)) { 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} 12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In 2.4.5, calls to this will be serialized via the BKL in 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/drivers/char/tty_io.c:tty_release() 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/drivers/char/tty_io.c:do_tty_handup() 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_close(struct tty_struct *tty, struct file *filp) 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 125546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct tty_port *port; 125646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport; 125761cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox unsigned long flags; 1258a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox 1259ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann BUG_ON(!tty_locked()); 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1261eea7e17e0eb23729d58368420659f8e7c357d82eLinus Torvalds if (!state) 1262eea7e17e0eb23729d58368420659f8e7c357d82eLinus Torvalds return; 1263eea7e17e0eb23729d58368420659f8e7c357d82eLinus Torvalds 126446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport = state->uart_port; 126546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox port = &state->port; 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 126746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox pr_debug("uart_close(%d) called\n", uport->line); 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1269a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 127061cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_lock_irqsave(&port->lock, flags); 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 127261cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox if (tty_hung_up_p(filp)) { 127361cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_unlock_irqrestore(&port->lock, flags); 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 127561cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox } 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 127791312cdb4fcd832341e425f74f49938e0503c929Alan Cox if ((tty->count == 1) && (port->count != 1)) { 12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Uh, oh. tty->count is 1, which means that the tty 128091312cdb4fcd832341e425f74f49938e0503c929Alan Cox * structure will be freed. port->count should always 12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * be one in these conditions. If it's greater than 12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * one, we've got real problems, since it means the 12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * serial port won't be shutdown. 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "uart_close: bad serial port count; tty->count is 1, " 128691312cdb4fcd832341e425f74f49938e0503c929Alan Cox "port->count is %d\n", port->count); 128791312cdb4fcd832341e425f74f49938e0503c929Alan Cox port->count = 1; 12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 128991312cdb4fcd832341e425f74f49938e0503c929Alan Cox if (--port->count < 0) { 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "uart_close: bad serial port count for %s: %d\n", 129191312cdb4fcd832341e425f74f49938e0503c929Alan Cox tty->name, port->count); 129291312cdb4fcd832341e425f74f49938e0503c929Alan Cox port->count = 0; 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 129461cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox if (port->count) { 129561cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_unlock_irqrestore(&port->lock, flags); 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 129761cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox } 12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Now we wait for the transmit buffer to clear; and we notify 13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the line discipline to only process XON/XOFF characters by 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * setting tty->closing. 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->closing = 1; 130561cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_unlock_irqrestore(&port->lock, flags); 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13071f33a51d9771b34be3cb6f7fb96a325e17bbac7bJiri Slaby if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) 13081f33a51d9771b34be3cb6f7fb96a325e17bbac7bJiri Slaby tty_wait_until_sent(tty, msecs_to_jiffies(port->closing_wait)); 13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * At this point, we stop accepting input. To do this, we 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * disable the receive line status interrupts. 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1314ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (port->flags & ASYNC_INITIALIZED) { 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1316eea7e17e0eb23729d58368420659f8e7c357d82eLinus Torvalds spin_lock_irqsave(&uport->lock, flags); 131746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->ops->stop_rx(uport); 1318eea7e17e0eb23729d58368420659f8e7c357d82eLinus Torvalds spin_unlock_irqrestore(&uport->lock, flags); 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Before we drop DTR, make sure the UART transmitter 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * has completely drained; this is especially 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * important if there is a transmit FIFO! 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13241f33a51d9771b34be3cb6f7fb96a325e17bbac7bJiri Slaby uart_wait_until_sent(tty, uport->timeout); 13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1327192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_shutdown(tty, state); 13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_flush_buffer(tty); 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1330a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox tty_ldisc_flush(tty); 1331a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox 13327b01478f97a671c97fad9254aa91892209b018b5Alan Cox tty_port_tty_set(port, NULL); 133361cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_lock_irqsave(&port->lock, flags); 133461cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox tty->closing = 0; 13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 133646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (port->blocked_open) { 133761cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_unlock_irqrestore(&port->lock, flags); 133846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (port->close_delay) 133946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox msleep_interruptible(port->close_delay); 134061cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_lock_irqsave(&port->lock, flags); 134146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox } else if (!uart_console(uport)) { 134261cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_unlock_irqrestore(&port->lock, flags); 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_change_pm(state, 3); 134461cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_lock_irqsave(&port->lock, flags); 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wake up anyone trying to open this port. 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1350ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); 135161cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_unlock_irqrestore(&port->lock, flags); 135246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox wake_up_interruptible(&port->open_wait); 13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 135446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Coxdone: 1355a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13581f33a51d9771b34be3cb6f7fb96a325e17bbac7bJiri Slabystatic void uart_wait_until_sent(struct tty_struct *tty, int timeout) 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13601f33a51d9771b34be3cb6f7fb96a325e17bbac7bJiri Slaby struct uart_state *state = tty->driver_data; 13611f33a51d9771b34be3cb6f7fb96a325e17bbac7bJiri Slaby struct uart_port *port = state->uart_port; 13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long char_time, expire; 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->type == PORT_UNKNOWN || port->fifosize == 0) 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the check interval to be 1/5 of the estimated time to 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * send a single character, and make it at least 1. The check 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interval should also be less than the timeout. 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note: we have to use pretty tight timings here to satisfy 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the NIST-PCTS. 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char_time = (port->timeout - HZ/50) / port->fifosize; 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char_time = char_time / 5; 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (char_time == 0) 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char_time = 1; 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (timeout && timeout < char_time) 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char_time = timeout; 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the transmitter hasn't cleared in twice the approximate 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * amount of time to send the entire FIFO, it probably won't 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ever clear. This assumes the UART isn't doing flow 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * control, which is currently the case. Hence, if it ever 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * takes longer than port->timeout, this is probably due to a 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * UART bug of some kind. So, we clamp the timeout parameter at 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2*port->timeout. 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (timeout == 0 || timeout > 2 * port->timeout) 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds timeout = 2 * port->timeout; 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds expire = jiffies + timeout; 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1396eb3a1e1145ca8f12372c7c96aa0702d86a9002a9Jiri Slaby pr_debug("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n", 1397a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox port->line, jiffies, expire); 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check whether the transmitter is empty every 'char_time'. 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 'timeout' / 'expire' give us the maximum amount of time 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we wait. 14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!port->ops->tx_empty(port)) { 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep_interruptible(jiffies_to_msecs(char_time)); 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (time_after(jiffies, expire)) 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1411203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmann} 1412203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmann 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is called with the BKL held in 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/drivers/char/tty_io.c:do_tty_hangup() 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We're called from the eventd thread, so we can sleep for 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a _short_ time only. 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_hangup(struct tty_struct *tty) 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 142246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct tty_port *port = &state->port; 142361cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox unsigned long flags; 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1425ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann BUG_ON(!tty_locked()); 1426ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox pr_debug("uart_hangup(%d)\n", state->uart_port->line); 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1428a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 1429ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (port->flags & ASYNC_NORMAL_ACTIVE) { 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_flush_buffer(tty); 1431192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_shutdown(tty, state); 143261cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_lock_irqsave(&port->lock, flags); 143391312cdb4fcd832341e425f74f49938e0503c929Alan Cox port->count = 0; 1434ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); 143561cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_unlock_irqrestore(&port->lock, flags); 14367b01478f97a671c97fad9254aa91892209b018b5Alan Cox tty_port_tty_set(port, NULL); 143746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox wake_up_interruptible(&port->open_wait); 1438bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox wake_up_interruptible(&port->delta_msr_wait); 14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1440a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1443de0c8cb314cc737c47a00de33cd6246accf94192Alan Coxstatic int uart_carrier_raised(struct tty_port *port) 1444de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox{ 1445de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox struct uart_state *state = container_of(port, struct uart_state, port); 1446de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox struct uart_port *uport = state->uart_port; 1447de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox int mctrl; 1448de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox spin_lock_irq(&uport->lock); 1449de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox uport->ops->enable_ms(uport); 1450de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox mctrl = uport->ops->get_mctrl(uport); 1451de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox spin_unlock_irq(&uport->lock); 1452de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox if (mctrl & TIOCM_CAR) 1453de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox return 1; 1454de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox return 0; 1455de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox} 1456de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox 1457de0c8cb314cc737c47a00de33cd6246accf94192Alan Coxstatic void uart_dtr_rts(struct tty_port *port, int onoff) 1458de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox{ 1459de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox struct uart_state *state = container_of(port, struct uart_state, port); 1460de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox struct uart_port *uport = state->uart_port; 146124fcc7c8cd0fcabcf37d455abe3501b3196fcf64Alan Cox 14626f5c24ad0f7619502199185a026a228174a27e68Jiri Slaby if (onoff) 1463de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS); 1464de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox else 1465de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); 1466de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox} 1467de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct uart_state *uart_get(struct uart_driver *drv, int line) 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state; 1471a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port; 147268ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King int ret = 0; 14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds state = drv->state + line; 1475a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox port = &state->port; 1476a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (mutex_lock_interruptible(&port->mutex)) { 147768ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King ret = -ERESTARTSYS; 147868ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King goto err; 14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1481a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox port->count++; 1482ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (!state->uart_port || state->uart_port->flags & UPF_DEAD) { 148368ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King ret = -ENXIO; 148468ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King goto err_unlock; 14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return state; 148768ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King 148868ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King err_unlock: 1489a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox port->count--; 1490a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 149168ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King err: 149268ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King return ERR_PTR(ret); 14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1496922f9cfa79b52c85b6002d96cb0eefd13437c58cDenis Cheng * calls to uart_open are serialised by the BKL in 1497922f9cfa79b52c85b6002d96cb0eefd13437c58cDenis Cheng * fs/char_dev.c:chrdev_open() 14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that if this fails, then uart_close() _will_ be called. 14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In time, we want to scrap the "opening nonpresent ports" 15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * behaviour and implement an alternative way for setserial 15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to set base addresses/ports/types. This will allow us to 15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * get rid of a certain amount of extra tests. 15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int uart_open(struct tty_struct *tty, struct file *filp) 15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state; 15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state; 150991312cdb4fcd832341e425f74f49938e0503c929Alan Cox struct tty_port *port; 15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval, line = tty->index; 15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1512ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann BUG_ON(!tty_locked()); 1513eb3a1e1145ca8f12372c7c96aa0702d86a9002a9Jiri Slaby pr_debug("uart_open(%d) called\n", line); 15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We take the semaphore inside uart_get to guarantee that we won't 1517ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox * be re-entered while allocating the state structure, or while we 15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * request any IRQs that the driver may need. This also has the nice 15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * side-effect that it delays the action of uart_hangup, so we can 1520ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox * guarantee that state->port.tty will always contain something 1521ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox * reasonable. 15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds state = uart_get(drv, line); 15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(state)) { 15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = PTR_ERR(state); 15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail; 15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 152891312cdb4fcd832341e425f74f49938e0503c929Alan Cox port = &state->port; 15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Once we set tty->driver_data here, we are guaranteed that 15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_close() will decrement the driver module use count. 15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Any failures from here onwards should not touch the count. 15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->driver_data = state; 1536ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox state->uart_port->state = state; 1537ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox tty->low_latency = (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0; 15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->alt_speed = 0; 15397b01478f97a671c97fad9254aa91892209b018b5Alan Cox tty_port_tty_set(port, tty); 15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the port is in the middle of closing, bail out now. 15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty_hung_up_p(filp)) { 15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EAGAIN; 154691312cdb4fcd832341e425f74f49938e0503c929Alan Cox port->count--; 1547a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail; 15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Make sure the device is in D0 state. 15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 155491312cdb4fcd832341e425f74f49938e0503c929Alan Cox if (port->count == 1) 15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_change_pm(state, 0); 15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Start up the serial port. 15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1560192251352f912bccfb942ea35801d2357f11f592Alan Cox retval = uart_startup(tty, state, 0); 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we succeeded, wait until the port is ready. 15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 156561cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox mutex_unlock(&port->mutex); 15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval == 0) 156774c2107759dc6efaa1b9127014be58a742a1e7acAlan Cox retval = tty_port_block_til_ready(port, tty, filp); 15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1569a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Coxfail: 15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *uart_type(struct uart_port *port) 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *str = NULL; 15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->ops->type) 15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds str = port->ops->type(port); 15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!str) 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds str = "unknown"; 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return str; 15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PROC_FS 15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1588d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyanstatic void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i) 15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = drv->state + i; 1591a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 15923689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis int pm_state; 1593a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct uart_port *uport = state->uart_port; 15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char stat_buf[32]; 15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status; 1596d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan int mmio; 15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1598a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (!uport) 1599d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan return; 16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1601a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mmio = uport->iotype >= UPIO_MEM; 1602d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_printf(m, "%d: uart:%s %s%08llX irq:%d", 1603a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->line, uart_type(uport), 16046c6a2334a1e8af7c3eaab992732825fa9ade77cfSergei Shtylyov mmio ? "mmio:0x" : "port:", 1605a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mmio ? (unsigned long long)uport->mapbase 1606a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox : (unsigned long long)uport->iobase, 1607a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->irq); 16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1609a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->type == PORT_UNKNOWN) { 1610d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_putc(m, '\n'); 1611d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan return; 16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1614a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox if (capable(CAP_SYS_ADMIN)) { 1615a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 16163689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis pm_state = state->pm_state; 16173689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis if (pm_state) 16183689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis uart_change_pm(state, 0); 1619a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox spin_lock_irq(&uport->lock); 1620a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox status = uport->ops->get_mctrl(uport); 1621a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox spin_unlock_irq(&uport->lock); 16223689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis if (pm_state) 16233689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis uart_change_pm(state, pm_state); 1624a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1626d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_printf(m, " tx:%d rx:%d", 1627a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->icount.tx, uport->icount.rx); 1628a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->icount.frame) 1629d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_printf(m, " fe:%d", 1630a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->icount.frame); 1631a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->icount.parity) 1632d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_printf(m, " pe:%d", 1633a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->icount.parity); 1634a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->icount.brk) 1635d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_printf(m, " brk:%d", 1636a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->icount.brk); 1637a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->icount.overrun) 1638d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_printf(m, " oe:%d", 1639a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->icount.overrun); 1640a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox 1641a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox#define INFOBIT(bit, str) \ 1642a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->mctrl & (bit)) \ 16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strncat(stat_buf, (str), sizeof(stat_buf) - \ 16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strlen(stat_buf) - 2) 1645a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox#define STATBIT(bit, str) \ 16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & (bit)) \ 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strncat(stat_buf, (str), sizeof(stat_buf) - \ 16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strlen(stat_buf) - 2) 16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stat_buf[0] = '\0'; 16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stat_buf[1] = '\0'; 16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INFOBIT(TIOCM_RTS, "|RTS"); 16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds STATBIT(TIOCM_CTS, "|CTS"); 16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INFOBIT(TIOCM_DTR, "|DTR"); 16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds STATBIT(TIOCM_DSR, "|DSR"); 16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds STATBIT(TIOCM_CAR, "|CD"); 16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds STATBIT(TIOCM_RNG, "|RI"); 16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (stat_buf[0]) 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stat_buf[0] = ' '; 1660a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox 1661d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_puts(m, stat_buf); 16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1663d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_putc(m, '\n'); 16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef STATBIT 16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef INFOBIT 16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1668d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyanstatic int uart_proc_show(struct seq_file *m, void *v) 16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1670833bb3046b6cb320e775ea2160ddca87d53260d5Alexey Dobriyan struct tty_driver *ttydrv = m->private; 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_driver *drv = ttydrv->driver_state; 1672d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan int i; 16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1674d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n", 16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "", "", ""); 1676d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan for (i = 0; i < drv->nr; i++) 1677d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan uart_line_info(m, drv, i); 1678d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan return 0; 16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1680d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan 1681d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyanstatic int uart_proc_open(struct inode *inode, struct file *file) 1682d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan{ 1683d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan return single_open(file, uart_proc_show, PDE(inode)->data); 1684d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan} 1685d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan 1686d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyanstatic const struct file_operations uart_proc_fops = { 1687d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan .owner = THIS_MODULE, 1688d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan .open = uart_proc_open, 1689d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan .read = seq_read, 1690d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan .llseek = seq_lseek, 1691d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan .release = single_release, 1692d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan}; 16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16954a1b5502d426df09b9ba1cbcc74fd09702a74cd8Andrew Morton#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) 16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1697d358788f3f30113e49882187d794832905e42592Russell King * uart_console_write - write a console message to a serial port 1698d358788f3f30113e49882187d794832905e42592Russell King * @port: the port to write the message 1699d358788f3f30113e49882187d794832905e42592Russell King * @s: array of characters 1700d358788f3f30113e49882187d794832905e42592Russell King * @count: number of characters in string to write 1701d358788f3f30113e49882187d794832905e42592Russell King * @write: function to write character to port 1702d358788f3f30113e49882187d794832905e42592Russell King */ 1703d358788f3f30113e49882187d794832905e42592Russell Kingvoid uart_console_write(struct uart_port *port, const char *s, 1704d358788f3f30113e49882187d794832905e42592Russell King unsigned int count, 1705d358788f3f30113e49882187d794832905e42592Russell King void (*putchar)(struct uart_port *, int)) 1706d358788f3f30113e49882187d794832905e42592Russell King{ 1707d358788f3f30113e49882187d794832905e42592Russell King unsigned int i; 1708d358788f3f30113e49882187d794832905e42592Russell King 1709d358788f3f30113e49882187d794832905e42592Russell King for (i = 0; i < count; i++, s++) { 1710d358788f3f30113e49882187d794832905e42592Russell King if (*s == '\n') 1711d358788f3f30113e49882187d794832905e42592Russell King putchar(port, '\r'); 1712d358788f3f30113e49882187d794832905e42592Russell King putchar(port, *s); 1713d358788f3f30113e49882187d794832905e42592Russell King } 1714d358788f3f30113e49882187d794832905e42592Russell King} 1715d358788f3f30113e49882187d794832905e42592Russell KingEXPORT_SYMBOL_GPL(uart_console_write); 1716d358788f3f30113e49882187d794832905e42592Russell King 1717d358788f3f30113e49882187d794832905e42592Russell King/* 17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check whether an invalid uart number has been specified, and 17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if so, search for the first available port that does have 17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * console support. 17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct uart_port * __init 17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_get_console(struct uart_port *ports, int nr, struct console *co) 17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int idx = co->index; 17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (idx < 0 || idx >= nr || (ports[idx].iobase == 0 && 17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ports[idx].membase == NULL)) 17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (idx = 0; idx < nr; idx++) 17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ports[idx].iobase != 0 || 17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ports[idx].membase != NULL) 17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds co->index = idx; 17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ports + idx; 17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_parse_options - Parse serial port baud/parity/bits/flow contro. 17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @options: pointer to option string 17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @baud: pointer to an 'int' variable for the baud rate. 17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @parity: pointer to an 'int' variable for the parity. 17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @bits: pointer to an 'int' variable for the number of data bits. 17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @flow: pointer to an 'int' variable for the flow control character. 17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_parse_options decodes a string containing the serial console 17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * options. The format of the string is <baud><parity><bits><flow>, 17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * eg: 115200n8r 17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1751f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselvoid 17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow) 17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *s = options; 17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *baud = simple_strtoul(s, NULL, 10); 17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (*s >= '0' && *s <= '9') 17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s++; 17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*s) 17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *parity = *s++; 17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*s) 17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *bits = *s++ - '0'; 17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*s) 17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *flow = *s; 17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1766f2d937f3bf00665ccf048b3b6616ef95859b0945Jason WesselEXPORT_SYMBOL_GPL(uart_parse_options); 17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct baud_rates { 17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int rate; 17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cflag; 17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1773cb3592be272d83011051dc49f4326355c01f1e1fArjan van de Venstatic const struct baud_rates baud_rates[] = { 17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 921600, B921600 }, 17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 460800, B460800 }, 17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 230400, B230400 }, 17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 115200, B115200 }, 17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 57600, B57600 }, 17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 38400, B38400 }, 17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 19200, B19200 }, 17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 9600, B9600 }, 17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 4800, B4800 }, 17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 2400, B2400 }, 17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 1200, B1200 }, 17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 0, B38400 } 17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_set_options - setup the serial console parameters 17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @port: pointer to the serial ports uart_port structure 17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @co: console pointer 17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @baud: baud rate 17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @parity: parity character - 'n' (none), 'o' (odd), 'e' (even) 17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @bits: number of data bits 17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @flow: flow control character - 'r' (rts) 17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1797f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselint 17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_set_options(struct uart_port *port, struct console *co, 17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int baud, int parity, int bits, int flow) 18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1801606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox struct ktermios termios; 1802149b36eae2ab6aa6056664f4bc461f3d3affc9c1Alan Cox static struct ktermios dummy; 18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1805976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King /* 1806976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King * Ensure that the serial console lock is initialised 1807976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King * early. 1808976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King */ 1809976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King spin_lock_init(&port->lock); 181013e83599d282ddfd544600df9db5ab343ac4662fIngo Molnar lockdep_set_class(&port->lock, &port_lock_key); 1811976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King 1812606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox memset(&termios, 0, sizeof(struct ktermios)); 18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios.c_cflag = CREAD | HUPCL | CLOCAL; 18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Construct a cflag setting. 18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; baud_rates[i].rate; i++) 18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (baud_rates[i].rate <= baud) 18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios.c_cflag |= baud_rates[i].cflag; 18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bits == 7) 18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios.c_cflag |= CS7; 18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios.c_cflag |= CS8; 18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (parity) { 18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 'o': case 'O': 18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios.c_cflag |= PARODD; 18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*fall through*/ 18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 'e': case 'E': 18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios.c_cflag |= PARENB; 18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (flow == 'r') 18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios.c_cflag |= CRTSCTS; 18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 184279492689e40d4f4d3d8a7262781d56fb295b4b86Yinghai Lu /* 184379492689e40d4f4d3d8a7262781d56fb295b4b86Yinghai Lu * some uarts on other side don't support no flow control. 184479492689e40d4f4d3d8a7262781d56fb295b4b86Yinghai Lu * So we set * DTR in host uart to make them happy 184579492689e40d4f4d3d8a7262781d56fb295b4b86Yinghai Lu */ 184679492689e40d4f4d3d8a7262781d56fb295b4b86Yinghai Lu port->mctrl |= TIOCM_DTR; 184779492689e40d4f4d3d8a7262781d56fb295b4b86Yinghai Lu 1848149b36eae2ab6aa6056664f4bc461f3d3affc9c1Alan Cox port->ops->set_termios(port, &termios, &dummy); 1849f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel /* 1850f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel * Allow the setting of the UART parameters with a NULL console 1851f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel * too: 1852f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel */ 1853f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel if (co) 1854f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel co->cflag = termios.c_cflag; 18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1858f2d937f3bf00665ccf048b3b6616ef95859b0945Jason WesselEXPORT_SYMBOL_GPL(uart_set_options); 18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_SERIAL_CORE_CONSOLE */ 18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_change_pm(struct uart_state *state, int pm_state) 18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1863ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox struct uart_port *port = state->uart_port; 18641281e36027a9119356bd93b5e7853c72c35dd462Andrew Victor 18651281e36027a9119356bd93b5e7853c72c35dd462Andrew Victor if (state->pm_state != pm_state) { 18661281e36027a9119356bd93b5e7853c72c35dd462Andrew Victor if (port->ops->pm) 18671281e36027a9119356bd93b5e7853c72c35dd462Andrew Victor port->ops->pm(port, pm_state, state->pm_state); 18681281e36027a9119356bd93b5e7853c72c35dd462Andrew Victor state->pm_state = pm_state; 18691281e36027a9119356bd93b5e7853c72c35dd462Andrew Victor } 18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1872b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetskistruct uart_match { 1873b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski struct uart_port *port; 1874b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski struct uart_driver *driver; 1875b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski}; 1876b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski 1877b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetskistatic int serial_match_port(struct device *dev, void *data) 1878b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski{ 1879b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski struct uart_match *match = data; 18807ca796f492a11f9408e661c8f22cd8c4f486b8e5Guennadi Liakhovetski struct tty_driver *tty_drv = match->driver->tty_driver; 18817ca796f492a11f9408e661c8f22cd8c4f486b8e5Guennadi Liakhovetski dev_t devt = MKDEV(tty_drv->major, tty_drv->minor_start) + 18827ca796f492a11f9408e661c8f22cd8c4f486b8e5Guennadi Liakhovetski match->port->line; 1883b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski 1884b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski return dev->devt == devt; /* Actually, only one tty per port */ 1885b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski} 1886b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski 1887ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Coxint uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) 18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1889ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct uart_state *state = drv->state + uport->line; 1890ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct tty_port *port = &state->port; 1891b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski struct device *tty_dev; 1892ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct uart_match match = {uport, drv}; 18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1894a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1896ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox tty_dev = device_find_child(uport->dev, &match, serial_match_port); 1897b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski if (device_may_wakeup(tty_dev)) { 18983f960dbb9dfe29ff283810624c4340c79fde87f5Govindraj.R if (!enable_irq_wake(uport->irq)) 18993f960dbb9dfe29ff283810624c4340c79fde87f5Govindraj.R uport->irq_wake = 1; 1900b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski put_device(tty_dev); 1901a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 1902b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski return 0; 1903b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski } 19044547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec if (console_suspend_enabled || !uart_console(uport)) 19054547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec uport->suspended = 1; 1906b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski 1907ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (port->flags & ASYNC_INITIALIZED) { 1908ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox const struct uart_ops *ops = uport->ops; 1909c8c6bfa39d6bd7347f43937c8767ae145b61bcb4Russell King int tries; 19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19114547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec if (console_suspend_enabled || !uart_console(uport)) { 19124547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec set_bit(ASYNCB_SUSPENDED, &port->flags); 19134547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec clear_bit(ASYNCB_INITIALIZED, &port->flags); 1914a6b93a908508810c5d51dd9b390283345af6f2d9Russell King 19154547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec spin_lock_irq(&uport->lock); 19164547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec ops->stop_tx(uport); 19174547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec ops->set_mctrl(uport, 0); 19184547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec ops->stop_rx(uport); 19194547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec spin_unlock_irq(&uport->lock); 19204547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec } 19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait for the transmitter to empty. 19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1925ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox for (tries = 3; !ops->tx_empty(uport) && tries; tries--) 19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep(10); 1927c8c6bfa39d6bd7347f43937c8767ae145b61bcb4Russell King if (!tries) 1928a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox printk(KERN_ERR "%s%s%s%d: Unable to drain " 1929a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox "transmitter\n", 1930ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox uport->dev ? dev_name(uport->dev) : "", 1931ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox uport->dev ? ": " : "", 19328440838bc5337243917f13bc14ea2445da5e0197David S. Miller drv->dev_name, 1933ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox drv->tty_driver->name_base + uport->line); 19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19354547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec if (console_suspend_enabled || !uart_console(uport)) 19364547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec ops->shutdown(uport); 19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Disable the console device before suspending. 19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19424547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec if (console_suspend_enabled && uart_console(uport)) 1943ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox console_stop(uport->cons); 19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19454547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec if (console_suspend_enabled || !uart_console(uport)) 19464547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec uart_change_pm(state, 3); 19471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1948a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1953ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Coxint uart_resume_port(struct uart_driver *drv, struct uart_port *uport) 19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1955ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct uart_state *state = drv->state + uport->line; 1956ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct tty_port *port = &state->port; 195703a74dcc7eebe6edd778317e82fafdf71e68488cArjan van de Ven struct device *tty_dev; 1958ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct uart_match match = {uport, drv}; 1959ba15ab0e8de0d4439a91342ad52d55ca9e313f3dDeepak Saxena struct ktermios termios; 19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1961a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1963ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox tty_dev = device_find_child(uport->dev, &match, serial_match_port); 1964ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (!uport->suspended && device_may_wakeup(tty_dev)) { 19653f960dbb9dfe29ff283810624c4340c79fde87f5Govindraj.R if (uport->irq_wake) { 19663f960dbb9dfe29ff283810624c4340c79fde87f5Govindraj.R disable_irq_wake(uport->irq); 19673f960dbb9dfe29ff283810624c4340c79fde87f5Govindraj.R uport->irq_wake = 0; 19683f960dbb9dfe29ff283810624c4340c79fde87f5Govindraj.R } 1969a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 1970b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski return 0; 1971b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski } 1972ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox uport->suspended = 0; 1973b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski 19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Re-enable the console device after suspending. 19761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19775933a161abcb8d83a2c145177f48027c3c0a8995Yin Kangkai if (uart_console(uport)) { 1978891b9dd10764352926e1e107756aa229dfa2c210Jason Wang /* 1979891b9dd10764352926e1e107756aa229dfa2c210Jason Wang * First try to use the console cflag setting. 1980891b9dd10764352926e1e107756aa229dfa2c210Jason Wang */ 1981891b9dd10764352926e1e107756aa229dfa2c210Jason Wang memset(&termios, 0, sizeof(struct ktermios)); 1982891b9dd10764352926e1e107756aa229dfa2c210Jason Wang termios.c_cflag = uport->cons->cflag; 1983891b9dd10764352926e1e107756aa229dfa2c210Jason Wang 1984891b9dd10764352926e1e107756aa229dfa2c210Jason Wang /* 1985891b9dd10764352926e1e107756aa229dfa2c210Jason Wang * If that's unset, use the tty termios setting. 1986891b9dd10764352926e1e107756aa229dfa2c210Jason Wang */ 1987891b9dd10764352926e1e107756aa229dfa2c210Jason Wang if (port->tty && port->tty->termios && termios.c_cflag == 0) 1988891b9dd10764352926e1e107756aa229dfa2c210Jason Wang termios = *(port->tty->termios); 1989891b9dd10764352926e1e107756aa229dfa2c210Jason Wang 1990ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox uport->ops->set_termios(uport, &termios, NULL); 19915933a161abcb8d83a2c145177f48027c3c0a8995Yin Kangkai if (console_suspend_enabled) 19925933a161abcb8d83a2c145177f48027c3c0a8995Yin Kangkai console_start(uport->cons); 19931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1995ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (port->flags & ASYNC_SUSPENDED) { 1996ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox const struct uart_ops *ops = uport->ops; 1997ee31b337852ca8a65840702544ff5c64d37740f5Russell King int ret; 19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19999d778a69370cc1b643b13648df971c83ff5654efRussell King uart_change_pm(state, 0); 2000ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox spin_lock_irq(&uport->lock); 2001ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox ops->set_mctrl(uport, 0); 2002ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox spin_unlock_irq(&uport->lock); 20034547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec if (console_suspend_enabled || !uart_console(uport)) { 2004192251352f912bccfb942ea35801d2357f11f592Alan Cox /* Protected by port mutex for now */ 2005192251352f912bccfb942ea35801d2357f11f592Alan Cox struct tty_struct *tty = port->tty; 20064547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec ret = ops->startup(uport); 20074547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec if (ret == 0) { 2008192251352f912bccfb942ea35801d2357f11f592Alan Cox if (tty) 2009192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_change_speed(tty, state, NULL); 20104547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec spin_lock_irq(&uport->lock); 20114547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec ops->set_mctrl(uport, uport->mctrl); 20124547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec ops->start_tx(uport); 20134547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec spin_unlock_irq(&uport->lock); 20144547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec set_bit(ASYNCB_INITIALIZED, &port->flags); 20154547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec } else { 20164547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec /* 20174547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec * Failed to resume - maybe hardware went away? 20184547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec * Clear the "initialized" flag so we won't try 20194547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec * to call the low level drivers shutdown method. 20204547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec */ 2021192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_shutdown(tty, state); 20224547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec } 2023ee31b337852ca8a65840702544ff5c64d37740f5Russell King } 2024a6b93a908508810c5d51dd9b390283345af6f2d9Russell King 2025ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox clear_bit(ASYNCB_SUSPENDED, &port->flags); 20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2028a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void 20341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_report_port(struct uart_driver *drv, struct uart_port *port) 20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 203630b7a3bc133c5b4a723163be35157ed709fca91cRussell King char address[64]; 203730b7a3bc133c5b4a723163be35157ed709fca91cRussell King 20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (port->iotype) { 20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case UPIO_PORT: 20409bde10a4b8c54804236d3d6b4b75e98825a921e7Andrew Morton snprintf(address, sizeof(address), "I/O 0x%lx", port->iobase); 20411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case UPIO_HUB6: 204330b7a3bc133c5b4a723163be35157ed709fca91cRussell King snprintf(address, sizeof(address), 20449bde10a4b8c54804236d3d6b4b75e98825a921e7Andrew Morton "I/O 0x%lx offset 0x%x", port->iobase, port->hub6); 20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case UPIO_MEM: 20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case UPIO_MEM32: 204821c614a7899046ab108b3d327d76c33443a8ebf2Pantelis Antoniou case UPIO_AU: 20493be91ec7388bae3cf1bfb4febcee5ab6c65f409fZang Roy-r case UPIO_TSI: 2050beab697ab4b2962e3d741b476abe443baad0933dMarc St-Jean case UPIO_DWAPB: 2051a3ae0fc34f58e7163b7724feb3d77aa4603f0dc3Jamie Iles case UPIO_DWAPB32: 205230b7a3bc133c5b4a723163be35157ed709fca91cRussell King snprintf(address, sizeof(address), 20534f640efb3170dbcf99a37a3cc99060647b95428cJosh Boyer "MMIO 0x%llx", (unsigned long long)port->mapbase); 205430b7a3bc133c5b4a723163be35157ed709fca91cRussell King break; 205530b7a3bc133c5b4a723163be35157ed709fca91cRussell King default: 205630b7a3bc133c5b4a723163be35157ed709fca91cRussell King strlcpy(address, "*unknown*", sizeof(address)); 20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 205930b7a3bc133c5b4a723163be35157ed709fca91cRussell King 20600cf669d5c5d08eb827df9867429df21cf030eba6Russell King printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n", 20614bfe090b0a29258eeeb026a09a96cf5b5838ac63Kay Sievers port->dev ? dev_name(port->dev) : "", 20620cf669d5c5d08eb827df9867429df21cf030eba6Russell King port->dev ? ": " : "", 20638440838bc5337243917f13bc14ea2445da5e0197David S. Miller drv->dev_name, 20648440838bc5337243917f13bc14ea2445da5e0197David S. Miller drv->tty_driver->name_base + port->line, 20658440838bc5337243917f13bc14ea2445da5e0197David S. Miller address, port->irq, uart_type(port)); 20661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 20691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_configure_port(struct uart_driver *drv, struct uart_state *state, 20701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_port *port) 20711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int flags; 20731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If there isn't a port here, don't do anything further. 20761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!port->iobase && !port->mapbase && !port->membase) 20781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 20791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Now do the auto configuration stuff. Note that config_port 20821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is expected to claim the resources and map the port for us. 20831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20848e23fcc89c8091790903927449f8efb9b4e23960David Daney flags = 0; 20851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->flags & UPF_AUTO_IRQ) 20861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags |= UART_CONFIG_IRQ; 20871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->flags & UPF_BOOT_AUTOCONF) { 20888e23fcc89c8091790903927449f8efb9b4e23960David Daney if (!(port->flags & UPF_FIXED_TYPE)) { 20898e23fcc89c8091790903927449f8efb9b4e23960David Daney port->type = PORT_UNKNOWN; 20908e23fcc89c8091790903927449f8efb9b4e23960David Daney flags |= UART_CONFIG_TYPE; 20918e23fcc89c8091790903927449f8efb9b4e23960David Daney } 20921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->ops->config_port(port, flags); 20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->type != PORT_UNKNOWN) { 20961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 20971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_report_port(drv, port); 20991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21003689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis /* Power up port for set_mctrl() */ 21013689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis uart_change_pm(state, 0); 21023689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis 21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ensure that the modem control lines are de-activated. 2105c3e4642be734ce3d2c7398246d8cbced3a039f54Yinghai Lu * keep the DTR setting that is set in uart_set_options() 21061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We probably don't need a spinlock around this, but 21071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 21081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port->lock, flags); 2109c3e4642be734ce3d2c7398246d8cbced3a039f54Yinghai Lu port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR); 21101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port->lock, flags); 21111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 211397d97224ff361e08777fb33e0fd193ca877dac28Russell King * If this driver supports console, and it hasn't been 211497d97224ff361e08777fb33e0fd193ca877dac28Russell King * successfully registered yet, try to re-register it. 211597d97224ff361e08777fb33e0fd193ca877dac28Russell King * It may be that the port was not available. 211697d97224ff361e08777fb33e0fd193ca877dac28Russell King */ 211797d97224ff361e08777fb33e0fd193ca877dac28Russell King if (port->cons && !(port->cons->flags & CON_ENABLED)) 211897d97224ff361e08777fb33e0fd193ca877dac28Russell King register_console(port->cons); 211997d97224ff361e08777fb33e0fd193ca877dac28Russell King 212097d97224ff361e08777fb33e0fd193ca877dac28Russell King /* 21211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Power down all ports by default, except the 21221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * console if we have one. 21231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 21241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!uart_console(port)) 21251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_change_pm(state, 3); 21261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2129f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel#ifdef CONFIG_CONSOLE_POLL 2130f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2131f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic int uart_poll_init(struct tty_driver *driver, int line, char *options) 2132f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel{ 2133f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_driver *drv = driver->driver_state; 2134f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_state *state = drv->state + line; 2135f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_port *port; 2136f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel int baud = 9600; 2137f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel int bits = 8; 2138f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel int parity = 'n'; 2139f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel int flow = 'n'; 2140f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2141ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (!state || !state->uart_port) 2142f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel return -1; 2143f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2144ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox port = state->uart_port; 2145f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel if (!(port->ops->poll_get_char && port->ops->poll_put_char)) 2146f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel return -1; 2147f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2148f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel if (options) { 2149f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel uart_parse_options(options, &baud, &parity, &bits, &flow); 2150f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel return uart_set_options(port, NULL, baud, parity, bits, flow); 2151f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel } 2152f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2153f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel return 0; 2154f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel} 2155f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2156f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic int uart_poll_get_char(struct tty_driver *driver, int line) 2157f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel{ 2158f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_driver *drv = driver->driver_state; 2159f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_state *state = drv->state + line; 2160f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_port *port; 2161f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2162ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (!state || !state->uart_port) 2163f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel return -1; 2164f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2165ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox port = state->uart_port; 2166f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel return port->ops->poll_get_char(port); 2167f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel} 2168f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2169f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic void uart_poll_put_char(struct tty_driver *driver, int line, char ch) 2170f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel{ 2171f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_driver *drv = driver->driver_state; 2172f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_state *state = drv->state + line; 2173f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_port *port; 2174f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2175ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (!state || !state->uart_port) 2176f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel return; 2177f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2178ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox port = state->uart_port; 2179f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel port->ops->poll_put_char(port, ch); 2180f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel} 2181f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel#endif 2182f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2183b68e31d0ebbcc909d1941f9f230c9d062a3a13d3Jeff Dikestatic const struct tty_operations uart_ops = { 21841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = uart_open, 21851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .close = uart_close, 21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = uart_write, 21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .put_char = uart_put_char, 21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .flush_chars = uart_flush_chars, 21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_room = uart_write_room, 21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .chars_in_buffer= uart_chars_in_buffer, 21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .flush_buffer = uart_flush_buffer, 21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ioctl = uart_ioctl, 21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .throttle = uart_throttle, 21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .unthrottle = uart_unthrottle, 21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .send_xchar = uart_send_xchar, 21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_termios = uart_set_termios, 219764e9159f5d2c4edf5fa6425031e556f8fddaf7e6Alan Cox .set_ldisc = uart_set_ldisc, 21981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .stop = uart_stop, 21991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .start = uart_start, 22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .hangup = uart_hangup, 22011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .break_ctl = uart_break_ctl, 22021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .wait_until_sent= uart_wait_until_sent, 22031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PROC_FS 2204d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan .proc_fops = &uart_proc_fops, 22051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 22061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .tiocmget = uart_tiocmget, 22071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .tiocmset = uart_tiocmset, 2208d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox .get_icount = uart_get_icount, 2209f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel#ifdef CONFIG_CONSOLE_POLL 2210f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel .poll_init = uart_poll_init, 2211f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel .poll_get_char = uart_poll_get_char, 2212f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel .poll_put_char = uart_poll_put_char, 2213f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel#endif 22141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 22151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2216de0c8cb314cc737c47a00de33cd6246accf94192Alan Coxstatic const struct tty_port_operations uart_port_ops = { 2217de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox .carrier_raised = uart_carrier_raised, 2218de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox .dtr_rts = uart_dtr_rts, 2219de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox}; 2220de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox 22211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 22221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_register_driver - register a driver with the uart core layer 22231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @drv: low level driver structure 22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Register a uart driver with the core driver. We in turn register 22261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with the tty layer, and initialise the core driver per-port state. 22271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We have a proc file in /proc/tty/driver which is named after the 22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * normal driver. 22301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drv->port should be NULL, and the per-port structures should be 22321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * registered using uart_add_one_port after this call has succeeded. 22331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 22341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint uart_register_driver(struct uart_driver *drv) 22351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 22369e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa struct tty_driver *normal; 22371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, retval; 22381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(drv->state); 22401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 22421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Maybe we should be using a slab cache for this, especially if 22431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we have a large number of ports to handle. 22441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 22458f31bb39ec2a5622974666c72257e74c22492602Burman Yan drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL); 22461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!drv->state) 22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 22481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22499e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa normal = alloc_tty_driver(drv->nr); 22501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!normal) 22519e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa goto out_kfree; 22521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds drv->tty_driver = normal; 22541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->owner = drv->owner; 22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->driver_name = drv->driver_name; 22571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->name = drv->dev_name; 22581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->major = drv->major; 22591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->minor_start = drv->minor; 22601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->type = TTY_DRIVER_TYPE_SERIAL; 22611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->subtype = SERIAL_TYPE_NORMAL; 22621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->init_termios = tty_std_termios; 22631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; 2264606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600; 2265331b831983f9d706f4a40d08a996d5c2c7a6ea7bGreg Kroah-Hartman normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; 22661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->driver_state = drv; 22671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_set_operations(normal, &uart_ops); 22681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 22701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialise the UART state(s). 22711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 22721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < drv->nr; i++) { 22731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = drv->state + i; 2274a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 22751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2276a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tty_port_init(port); 2277de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox port->ops = &uart_port_ops; 2278a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox port->close_delay = 500; /* .5 seconds */ 2279a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox port->closing_wait = 30000; /* 30 seconds */ 2280ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox tasklet_init(&state->tlet, uart_tasklet_action, 2281f751928e0ddf54ea4fe5546f35e99efc5b5d9938Alan Cox (unsigned long)state); 22821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = tty_register_driver(normal); 22859e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa if (retval >= 0) 22869e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa return retval; 22879e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa 22889e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa put_tty_driver(normal); 22899e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosaout_kfree: 22909e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa kfree(drv->state); 22919e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosaout: 22929e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa return -ENOMEM; 22931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 22961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_unregister_driver - remove a driver from the uart core layer 22971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @drv: low level driver structure 22981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 22991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Remove all references to a driver from the core driver. The low 23001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * level driver must have removed all its ports via the 23011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_remove_one_port() if it registered them with uart_add_one_port(). 23021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (ie, drv->port == NULL) 23031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid uart_unregister_driver(struct uart_driver *drv) 23051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tty_driver *p = drv->tty_driver; 23071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_unregister_driver(p); 23081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_tty_driver(p); 23091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(drv->state); 23101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds drv->tty_driver = NULL; 23111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct tty_driver *uart_console_device(struct console *co, int *index) 23141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_driver *p = co->data; 23161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *index = co->index; 23171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return p->tty_driver; 23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 23211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_add_one_port - attach a driver-defined port structure 23221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @drv: pointer to the uart low level driver structure for this port 23231b9894f342a39601bb0420b7b8c7e445670c1b51Randy Dunlap * @uport: uart port structure to use for this port. 23241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 23251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This allows the driver to register its own uart_port structure 23261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with the core driver. The main purpose is to allow the low 23271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * level uart drivers to expand uart_port, rather than having yet 23281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * more levels of structures. 23291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2330a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Coxint uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) 23311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state; 2333a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port; 23341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 2335b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski struct device *tty_dev; 23361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(in_interrupt()); 23381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2339a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->line >= drv->nr) 23401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 23411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2342a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox state = drv->state + uport->line; 2343a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox port = &state->port; 23441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2345f392ecfa12de9a2baf72789b00557bac040d6171Arjan van de Ven mutex_lock(&port_mutex); 2346a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 2347ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (state->uart_port) { 23481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EINVAL; 23491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 23501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2352a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox state->uart_port = uport; 235397d97224ff361e08777fb33e0fd193ca877dac28Russell King state->pm_state = -1; 23541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2355a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->cons = drv->cons; 2356a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->state = state; 23571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2358976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King /* 2359976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King * If this port is a console, then the spinlock is already 2360976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King * initialised. 2361976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King */ 2362a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) { 2363a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox spin_lock_init(&uport->lock); 2364a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox lockdep_set_class(&uport->lock, &port_lock_key); 236513e83599d282ddfd544600df9db5ab343ac4662fIngo Molnar } 2366976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King 2367a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uart_configure_port(drv, state, uport); 23681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 23701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Register the port whether it's detected or not. This allows 23711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * setserial to be used to alter this ports parameters. 23721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2373a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev); 2374b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski if (likely(!IS_ERR(tty_dev))) { 237574081f8667d73ad59961cf63be5f0e9d6a87c8a3Alan Stern device_init_wakeup(tty_dev, 1); 2376b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski device_set_wakeup_enable(tty_dev, 0); 2377b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski } else 2378b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski printk(KERN_ERR "Cannot register tty device on line %d\n", 2379a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->line); 23801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 238268ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King * Ensure UPF_DEAD is not set. 238368ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King */ 2384a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->flags &= ~UPF_DEAD; 238568ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King 23861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: 2387a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 2388f392ecfa12de9a2baf72789b00557bac040d6171Arjan van de Ven mutex_unlock(&port_mutex); 23891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 23911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 23941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_remove_one_port - detach a driver defined port structure 23951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @drv: pointer to the uart low level driver structure for this port 23961b9894f342a39601bb0420b7b8c7e445670c1b51Randy Dunlap * @uport: uart port structure for this port 23971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 23981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This unhooks (and hangs up) the specified port structure from the 23991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * core driver. No further calls will be made to the low-level code 24001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for this port. 24011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2402a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Coxint uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) 24031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2404a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct uart_state *state = drv->state + uport->line; 2405a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 24061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(in_interrupt()); 24081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2409a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (state->uart_port != uport) 24101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ALERT "Removing wrong port: %p != %p\n", 2411a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox state->uart_port, uport); 24121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2413f392ecfa12de9a2baf72789b00557bac040d6171Arjan van de Ven mutex_lock(&port_mutex); 24141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 241668ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King * Mark the port "dead" - this prevents any opens from 241768ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King * succeeding while we shut down the port. 241868ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King */ 2419a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 2420a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->flags |= UPF_DEAD; 2421a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 242268ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King 242368ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King /* 2424aa4148cfc7b3b93eeaf755a7d14f10afaffe9a96Greg Kroah-Hartman * Remove the devices from the tty layer 24251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2426a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tty_unregister_device(drv->tty_driver, uport->line); 24271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2428a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (port->tty) 2429a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tty_vhangup(port->tty); 243068ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King 243168ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King /* 243268ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King * Free the port IO and memory resources, if any. 243368ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King */ 2434a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->type != PORT_UNKNOWN) 2435a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->ops->release_port(uport); 243668ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King 243768ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King /* 243868ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King * Indicate that there isn't a port here anymore. 243968ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King */ 2440a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->type = PORT_UNKNOWN; 244168ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King 244268ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King /* 244368ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King * Kill the tasklet, and free resources. 244468ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King */ 2445ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox tasklet_kill(&state->tlet); 244668ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King 2447ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox state->uart_port = NULL; 2448f392ecfa12de9a2baf72789b00557bac040d6171Arjan van de Ven mutex_unlock(&port_mutex); 24491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 24511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 24521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 24541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Are the two ports equivalent? 24551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 24561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint uart_match_port(struct uart_port *port1, struct uart_port *port2) 24571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 24581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port1->iotype != port2->iotype) 24591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 24601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (port1->iotype) { 24621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case UPIO_PORT: 24631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (port1->iobase == port2->iobase); 24641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case UPIO_HUB6: 24651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (port1->iobase == port2->iobase) && 24661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (port1->hub6 == port2->hub6); 24671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case UPIO_MEM: 2468d21b55d30b46c0b43821a2980e4998965fa37e33Sergei Shtylyov case UPIO_MEM32: 2469d21b55d30b46c0b43821a2980e4998965fa37e33Sergei Shtylyov case UPIO_AU: 2470d21b55d30b46c0b43821a2980e4998965fa37e33Sergei Shtylyov case UPIO_TSI: 2471beab697ab4b2962e3d741b476abe443baad0933dMarc St-Jean case UPIO_DWAPB: 2472a3ae0fc34f58e7163b7724feb3d77aa4603f0dc3Jamie Iles case UPIO_DWAPB32: 24731624f003349b49050f42c7d9f5407dfc05efb912Benjamin Herrenschmidt return (port1->mapbase == port2->mapbase); 24741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 24761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 24771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_match_port); 24781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_write_wakeup); 24801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_register_driver); 24811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_unregister_driver); 24821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_suspend_port); 24831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_resume_port); 24841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_add_one_port); 24851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_remove_one_port); 24861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Serial driver core"); 24881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 2489