serial_core.c revision 426929f8d3514d7f727b8c464d1eeeaf74b21519
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); 756a3e492b6daaf7ec4dc41e51d87d2aae8ff886f2Jiri Slaby tty_wakeup(state->port.tty); 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 inline void 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear) 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int old; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port->lock, flags); 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds old = port->mctrl; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->mctrl = (old & ~clear) | set; 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (old != port->mctrl) 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->ops->set_mctrl(port, port->mctrl); 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port->lock, flags); 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 124a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox#define uart_set_mctrl(port, set) uart_update_mctrl(port, set, 0) 125a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox#define uart_clear_mctrl(port, clear) uart_update_mctrl(port, 0, clear) 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Startup the port. This will be called once per open. All calls 129df4f4dd429870f435f8d5d9d561db029a29f063bAlan Cox * will be serialised by the per-port mutex. 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 131192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic int uart_startup(struct tty_struct *tty, struct uart_state *state, int init_hw) 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 13446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct tty_port *port = &state->port; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long page; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 138ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (port->flags & ASYNC_INITIALIZED) 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the TTY IO error marker - we will only clear this 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * once we have successfully opened the port. Also set 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * up the tty->alt_speed kludge 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 146192251352f912bccfb942ea35801d2357f11f592Alan Cox set_bit(TTY_IO_ERROR, &tty->flags); 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->type == PORT_UNKNOWN) 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialise and allocate the transmit and temporary 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * buffer. 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 155ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (!state->xmit.buf) { 156df4f4dd429870f435f8d5d9d561db029a29f063bAlan Cox /* This is protected by the per port mutex */ 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds page = get_zeroed_page(GFP_KERNEL); 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!page) 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 161ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox state->xmit.buf = (unsigned char *) page; 162ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox uart_circ_clear(&state->xmit); 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox retval = uport->ops->startup(uport); 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval == 0) { 167c7d7abff40c27f82fe78b1091ab3fad69b2546f9Jiri Slaby if (uart_console(uport) && uport->cons->cflag) { 168c7d7abff40c27f82fe78b1091ab3fad69b2546f9Jiri Slaby tty->termios->c_cflag = uport->cons->cflag; 169c7d7abff40c27f82fe78b1091ab3fad69b2546f9Jiri Slaby uport->cons->cflag = 0; 170c7d7abff40c27f82fe78b1091ab3fad69b2546f9Jiri Slaby } 171c7d7abff40c27f82fe78b1091ab3fad69b2546f9Jiri Slaby /* 172c7d7abff40c27f82fe78b1091ab3fad69b2546f9Jiri Slaby * Initialise the hardware port settings. 173c7d7abff40c27f82fe78b1091ab3fad69b2546f9Jiri Slaby */ 174c7d7abff40c27f82fe78b1091ab3fad69b2546f9Jiri Slaby uart_change_speed(tty, state, NULL); 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 176c7d7abff40c27f82fe78b1091ab3fad69b2546f9Jiri Slaby if (init_hw) { 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Setup the RTS and DTR signals once the 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * port is open and ready to respond. 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 181192251352f912bccfb942ea35801d2357f11f592Alan Cox if (tty->termios->c_cflag & CBAUD) 18246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR); 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 185ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (port->flags & ASYNC_CTS_FLOW) { 18646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_lock_irq(&uport->lock); 18746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) 188192251352f912bccfb942ea35801d2357f11f592Alan Cox tty->hw_stopped = 1; 18946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_unlock_irq(&uport->lock); 1900dd7a1aed7c34a39917c4faf75b4230c169e809bRussell King } 1910dd7a1aed7c34a39917c4faf75b4230c169e809bRussell King 192ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox set_bit(ASYNCB_INITIALIZED, &port->flags); 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 194192251352f912bccfb942ea35801d2357f11f592Alan Cox clear_bit(TTY_IO_ERROR, &tty->flags); 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval && capable(CAP_SYS_ADMIN)) 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine will shutdown a serial port; interrupts are disabled, and 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DTR is dropped if the hangup on close termio flag is on. Calls to 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_shutdown are serialised by the per-port semaphore. 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 208192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic void uart_shutdown(struct tty_struct *tty, struct uart_state *state) 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 210ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct uart_port *uport = state->uart_port; 211bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox struct tty_port *port = &state->port; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 214ee31b337852ca8a65840702544ff5c64d37740f5Russell King * Set the TTY IO error marker 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 216f751928e0ddf54ea4fe5546f35e99efc5b5d9938Alan Cox if (tty) 217f751928e0ddf54ea4fe5546f35e99efc5b5d9938Alan Cox set_bit(TTY_IO_ERROR, &tty->flags); 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 219bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox if (test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) { 220ee31b337852ca8a65840702544ff5c64d37740f5Russell King /* 221ee31b337852ca8a65840702544ff5c64d37740f5Russell King * Turn off DTR and RTS early. 222ee31b337852ca8a65840702544ff5c64d37740f5Russell King */ 223f751928e0ddf54ea4fe5546f35e99efc5b5d9938Alan Cox if (!tty || (tty->termios->c_cflag & HUPCL)) 224ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); 225ee31b337852ca8a65840702544ff5c64d37740f5Russell King 226ee31b337852ca8a65840702544ff5c64d37740f5Russell King /* 227ee31b337852ca8a65840702544ff5c64d37740f5Russell King * clear delta_msr_wait queue to avoid mem leaks: we may free 228ee31b337852ca8a65840702544ff5c64d37740f5Russell King * the irq here so the queue might never be woken up. Note 229ee31b337852ca8a65840702544ff5c64d37740f5Russell King * that we won't end up waiting on delta_msr_wait again since 230ee31b337852ca8a65840702544ff5c64d37740f5Russell King * any outstanding file descriptors should be pointing at 231ee31b337852ca8a65840702544ff5c64d37740f5Russell King * hung_up_tty_fops now. 232ee31b337852ca8a65840702544ff5c64d37740f5Russell King */ 233bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox wake_up_interruptible(&port->delta_msr_wait); 234ee31b337852ca8a65840702544ff5c64d37740f5Russell King 235ee31b337852ca8a65840702544ff5c64d37740f5Russell King /* 236ee31b337852ca8a65840702544ff5c64d37740f5Russell King * Free the IRQ and disable the port. 237ee31b337852ca8a65840702544ff5c64d37740f5Russell King */ 238ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox uport->ops->shutdown(uport); 239ee31b337852ca8a65840702544ff5c64d37740f5Russell King 240ee31b337852ca8a65840702544ff5c64d37740f5Russell King /* 241ee31b337852ca8a65840702544ff5c64d37740f5Russell King * Ensure that the IRQ handler isn't running on another CPU. 242ee31b337852ca8a65840702544ff5c64d37740f5Russell King */ 243ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox synchronize_irq(uport->irq); 244ee31b337852ca8a65840702544ff5c64d37740f5Russell King } 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free the transmit buffer page. 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 249ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (state->xmit.buf) { 250ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox free_page((unsigned long)state->xmit.buf); 251ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox state->xmit.buf = NULL; 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_update_timeout - update per-port FIFO timeout. 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @port: uart_port structure describing the port 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @cflag: termios cflag value 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @baud: speed of the port 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the port FIFO timeout value. The @cflag value should 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reflect the actual hardware settings. 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_update_timeout(struct uart_port *port, unsigned int cflag, 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int baud) 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int bits; 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* byte size and parity */ 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cflag & CSIZE) { 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS5: 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits = 7; 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS6: 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits = 8; 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS7: 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits = 9; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits = 10; 283a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox break; /* CS8 */ 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & CSTOPB) 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits++; 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & PARENB) 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits++; 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The total number of bits to be transmitted in the fifo. 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits = bits * port->fifosize; 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Figure the timeout to send the above number of bits. 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Add .02 seconds of slop 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->timeout = (HZ * bits) / baud + HZ/50; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_update_timeout); 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_get_baud_rate - return baud rate for a particular port 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @port: uart_port structure describing the port in question. 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @termios: desired termios settings. 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @old: old termios (or NULL) 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @min: minimum acceptable baud rate 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @max: maximum acceptable baud rate 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Decode the termios structure into a numeric baud rate, 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * taking account of the magic 38400 baud rate (with spd_* 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * flags), and mapping the %B0 rate to 9600 baud. 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the new baud rate is invalid, try the old termios setting. 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If it's still invalid, we try 9600 baud. 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Update the @termios structure to reflect the baud rate 321eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox * we're actually going to be using. Don't do this for the case 322eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox * where B0 is requested ("hang up"). 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsunsigned int 325606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Coxuart_get_baud_rate(struct uart_port *port, struct ktermios *termios, 326606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox struct ktermios *old, unsigned int min, unsigned int max) 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int try, baud, altbaud = 38400; 329eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox int hung_up = 0; 3300077d45e46fe2af3aaee5813c99268afcd0e7c0eRussell King upf_t flags = port->flags & UPF_SPD_MASK; 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (flags == UPF_SPD_HI) 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds altbaud = 57600; 33482cb7ba10deafe17686bf22ce4a7a303a77a197fAndré Goddard Rosa else if (flags == UPF_SPD_VHI) 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds altbaud = 115200; 33682cb7ba10deafe17686bf22ce4a7a303a77a197fAndré Goddard Rosa else if (flags == UPF_SPD_SHI) 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds altbaud = 230400; 33882cb7ba10deafe17686bf22ce4a7a303a77a197fAndré Goddard Rosa else if (flags == UPF_SPD_WARP) 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds altbaud = 460800; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (try = 0; try < 2; try++) { 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds baud = tty_termios_baud_rate(termios); 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The spd_hi, spd_vhi, spd_shi, spd_warp kludge... 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Die! Die! Die! 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (baud == 38400) 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds baud = altbaud; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Special case: B0 rate. 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 354eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox if (baud == 0) { 355eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox hung_up = 1; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds baud = 9600; 357eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox } 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (baud >= min && baud <= max) 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return baud; 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Oops, the quotient was zero. Try again with 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the old baud rate if possible. 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios->c_cflag &= ~CBAUD; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (old) { 3686d4d67beb963de8865499781b8523e5b683819c3Alan Cox baud = tty_termios_baud_rate(old); 369eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox if (!hung_up) 370eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox tty_termios_encode_baud_rate(termios, 371eb424fd21c0931e998156225f2a0910167c3e16cAlan Cox baud, baud); 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds old = NULL; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 37716ae2a877bf4179737921235e85ceffd7b79354fAlan Cox * As a last resort, if the range cannot be met then clip to 37816ae2a877bf4179737921235e85ceffd7b79354fAlan Cox * the nearest chip supported rate. 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 38016ae2a877bf4179737921235e85ceffd7b79354fAlan Cox if (!hung_up) { 38116ae2a877bf4179737921235e85ceffd7b79354fAlan Cox if (baud <= min) 38216ae2a877bf4179737921235e85ceffd7b79354fAlan Cox tty_termios_encode_baud_rate(termios, 38316ae2a877bf4179737921235e85ceffd7b79354fAlan Cox min + 1, min + 1); 38416ae2a877bf4179737921235e85ceffd7b79354fAlan Cox else 38516ae2a877bf4179737921235e85ceffd7b79354fAlan Cox tty_termios_encode_baud_rate(termios, 38616ae2a877bf4179737921235e85ceffd7b79354fAlan Cox max - 1, max - 1); 38716ae2a877bf4179737921235e85ceffd7b79354fAlan Cox } 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38916ae2a877bf4179737921235e85ceffd7b79354fAlan Cox /* Should never happen */ 39016ae2a877bf4179737921235e85ceffd7b79354fAlan Cox WARN_ON(1); 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_get_baud_rate); 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_get_divisor - return uart clock divisor 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @port: uart_port structure describing the port. 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @baud: desired baud rate 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Calculate the uart clock divisor for the port. 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsunsigned int 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_get_divisor(struct uart_port *port, unsigned int baud) 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int quot; 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Old custom speed handling. 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds quot = port->custom_divisor; 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds quot = (port->uartclk + (8 * baud)) / (16 * baud); 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return quot; 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_get_divisor); 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42123d22cea85ba9114a59a32ca8dfb1e2aef52a278Alan Cox/* FIXME: Consistent locking policy */ 422192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic void uart_change_speed(struct tty_struct *tty, struct uart_state *state, 423192251352f912bccfb942ea35801d2357f11f592Alan Cox struct ktermios *old_termios) 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 425ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct tty_port *port = &state->port; 426ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct uart_port *uport = state->uart_port; 427606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox struct ktermios *termios; 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we have no tty, termios, or the port does not exist, 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * then we can't set the parameters for this port. 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 433ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (!tty || !tty->termios || uport->type == PORT_UNKNOWN) 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios = tty->termios; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set flags based on termios cflag 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (termios->c_cflag & CRTSCTS) 442ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox set_bit(ASYNCB_CTS_FLOW, &port->flags); 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 444ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox clear_bit(ASYNCB_CTS_FLOW, &port->flags); 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (termios->c_cflag & CLOCAL) 447ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox clear_bit(ASYNCB_CHECK_CD, &port->flags); 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 449ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox set_bit(ASYNCB_CHECK_CD, &port->flags); 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 451ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox uport->ops->set_termios(uport, termios, old_termios); 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 454192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic inline int __uart_put_char(struct uart_port *port, 455192251352f912bccfb942ea35801d2357f11f592Alan Cox struct circ_buf *circ, unsigned char c) 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 45823d22cea85ba9114a59a32ca8dfb1e2aef52a278Alan Cox int ret = 0; 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!circ->buf) 46123d22cea85ba9114a59a32ca8dfb1e2aef52a278Alan Cox return 0; 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port->lock, flags); 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (uart_circ_chars_free(circ) != 0) { 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds circ->buf[circ->head] = c; 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1); 46723d22cea85ba9114a59a32ca8dfb1e2aef52a278Alan Cox ret = 1; 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port->lock, flags); 47023d22cea85ba9114a59a32ca8dfb1e2aef52a278Alan Cox return ret; 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47323d22cea85ba9114a59a32ca8dfb1e2aef52a278Alan Coxstatic int uart_put_char(struct tty_struct *tty, unsigned char ch) 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 477ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox return __uart_put_char(state->uart_port, &state->xmit, ch); 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_flush_chars(struct tty_struct *tty) 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_start(tty); 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 485192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic int uart_write(struct tty_struct *tty, 486192251352f912bccfb942ea35801d2357f11f592Alan Cox const unsigned char *buf, int count) 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 489d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek struct uart_port *port; 490d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek struct circ_buf *circ; 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int c, ret = 0; 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 494d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek /* 495d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek * This means you called this function _after_ the port was 496d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek * closed. No cookie for you. 497d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek */ 498f751928e0ddf54ea4fe5546f35e99efc5b5d9938Alan Cox if (!state) { 499d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek WARN_ON(1); 500d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek return -EL3HLT; 501d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek } 502d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek 503ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox port = state->uart_port; 504ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox circ = &state->xmit; 505d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!circ->buf) 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port->lock, flags); 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (1) { 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count < c) 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c = count; 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (c <= 0) 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(circ->buf + circ->head, buf, c); 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1); 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += c; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count -= c; 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret += c; 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port->lock, flags); 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_start(tty); 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int uart_write_room(struct tty_struct *tty) 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 531f34d7a5b7010b82fe97da95496b9971435530062Alan Cox unsigned long flags; 532f34d7a5b7010b82fe97da95496b9971435530062Alan Cox int ret; 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 534ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox spin_lock_irqsave(&state->uart_port->lock, flags); 535ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox ret = uart_circ_chars_free(&state->xmit); 536ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox spin_unlock_irqrestore(&state->uart_port->lock, flags); 537f34d7a5b7010b82fe97da95496b9971435530062Alan Cox return ret; 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int uart_chars_in_buffer(struct tty_struct *tty) 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 543f34d7a5b7010b82fe97da95496b9971435530062Alan Cox unsigned long flags; 544f34d7a5b7010b82fe97da95496b9971435530062Alan Cox int ret; 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 546ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox spin_lock_irqsave(&state->uart_port->lock, flags); 547ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox ret = uart_circ_chars_pending(&state->xmit); 548ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox spin_unlock_irqrestore(&state->uart_port->lock, flags); 549f34d7a5b7010b82fe97da95496b9971435530062Alan Cox return ret; 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_flush_buffer(struct tty_struct *tty) 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 55555d7b68996a5064f011d681bca412b6281d2f711Tetsuo Handa struct uart_port *port; 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 558d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek /* 559d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek * This means you called this function _after_ the port was 560d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek * closed. No cookie for you. 561d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek */ 562f751928e0ddf54ea4fe5546f35e99efc5b5d9938Alan Cox if (!state) { 563d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek WARN_ON(1); 564d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek return; 565d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek } 566d5f735e52fb41e032b0db08aa20c02dbb9cd0db3Pavel Machek 567ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox port = state->uart_port; 568eb3a1e1145ca8f12372c7c96aa0702d86a9002a9Jiri Slaby pr_debug("uart_flush_buffer(%d) called\n", tty->index); 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port->lock, flags); 571ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox uart_circ_clear(&state->xmit); 5726bb0e3a59a089e23eecc0af3b6f6012b2a9affbaHaavard Skinnemoen if (port->ops->flush_buffer) 5736bb0e3a59a089e23eecc0af3b6f6012b2a9affbaHaavard Skinnemoen port->ops->flush_buffer(port); 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port->lock, flags); 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_wakeup(tty); 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function is used to send a high-priority XON/XOFF character to 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the device 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_send_xchar(struct tty_struct *tty, char ch) 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 585ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox struct uart_port *port = state->uart_port; 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->ops->send_xchar) 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->ops->send_xchar(port, ch); 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->x_char = ch; 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ch) { 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port->lock, flags); 594b129a8ccd53f74c43e4c83c8e0031a4990040830Russell King port->ops->start_tx(port); 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port->lock, flags); 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_throttle(struct tty_struct *tty) 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (I_IXOFF(tty)) 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_send_xchar(tty, STOP_CHAR(tty)); 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty->termios->c_cflag & CRTSCTS) 608ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox uart_clear_mctrl(state->uart_port, TIOCM_RTS); 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_unthrottle(struct tty_struct *tty) 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 614ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox struct uart_port *port = state->uart_port; 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (I_IXOFF(tty)) { 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->x_char) 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->x_char = 0; 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_send_xchar(tty, START_CHAR(tty)); 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty->termios->c_cflag & CRTSCTS) 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_set_mctrl(port, TIOCM_RTS); 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int uart_get_info(struct uart_state *state, 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serial_struct __user *retinfo) 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 630a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct uart_port *uport = state->uart_port; 631a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serial_struct tmp; 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(&tmp, 0, sizeof(tmp)); 635f34d7a5b7010b82fe97da95496b9971435530062Alan Cox 636f34d7a5b7010b82fe97da95496b9971435530062Alan Cox /* Ensure the state we copy is consistent and no hardware changes 637f34d7a5b7010b82fe97da95496b9971435530062Alan Cox occur as we go */ 638a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 639f34d7a5b7010b82fe97da95496b9971435530062Alan Cox 640a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.type = uport->type; 641a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.line = uport->line; 642a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.port = uport->iobase; 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (HIGH_BITS_OFFSET) 644a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.port_high = (long) uport->iobase >> HIGH_BITS_OFFSET; 645a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.irq = uport->irq; 646a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.flags = uport->flags; 647a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.xmit_fifo_size = uport->fifosize; 648a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.baud_base = uport->uartclk / 16; 649a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.close_delay = port->close_delay / 10; 650016af53a6de6837e5be3da68901083ea85ebb4daAlan Cox tmp.closing_wait = port->closing_wait == ASYNC_CLOSING_WAIT_NONE ? 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ASYNC_CLOSING_WAIT_NONE : 652a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox port->closing_wait / 10; 653a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.custom_divisor = uport->custom_divisor; 654a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.hub6 = uport->hub6; 655a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.io_type = uport->iotype; 656a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.iomem_reg_shift = uport->regshift; 657a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tmp.iomem_base = (void *)(unsigned long)uport->mapbase; 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 659a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 660f34d7a5b7010b82fe97da95496b9971435530062Alan Cox 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 666192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic int uart_set_info(struct tty_struct *tty, struct uart_state *state, 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serial_struct __user *newinfo) 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serial_struct new_serial; 67046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 67146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct tty_port *port = &state->port; 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long new_port; 6730077d45e46fe2af3aaee5813c99268afcd0e7c0eRussell King unsigned int change_irq, change_port, closing_wait; 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int old_custom_divisor, close_delay; 6750077d45e46fe2af3aaee5813c99268afcd0e7c0eRussell King upf_t old_flags, new_flags; 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_port = new_serial.port; 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (HIGH_BITS_OFFSET) 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_serial.irq = irq_canonicalize(new_serial.irq); 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds close_delay = new_serial.close_delay * 10; 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? 688016af53a6de6837e5be3da68901083ea85ebb4daAlan Cox ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 69191312cdb4fcd832341e425f74f49938e0503c929Alan Cox * This semaphore protects port->count. It is also 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * very useful to prevent opens. Also, take the 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * port configuration semaphore to make sure that a 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * module insertion/removal doesn't change anything 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * under us. 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 697a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 69946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox change_irq = !(uport->flags & UPF_FIXED_PORT) 70046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox && new_serial.irq != uport->irq; 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Since changing the 'type' of the port changes its resource 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * allocations, we should treat type changes the same as 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IO port changes. 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 70746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox change_port = !(uport->flags & UPF_FIXED_PORT) 70846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox && (new_port != uport->iobase || 70946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox (unsigned long)new_serial.iomem_base != uport->mapbase || 71046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox new_serial.hub6 != uport->hub6 || 71146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox new_serial.io_type != uport->iotype || 71246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox new_serial.iomem_reg_shift != uport->regshift || 71346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox new_serial.type != uport->type); 71446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox 71546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_flags = uport->flags; 7160077d45e46fe2af3aaee5813c99268afcd0e7c0eRussell King new_flags = new_serial.flags; 71746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_custom_divisor = uport->custom_divisor; 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!capable(CAP_SYS_ADMIN)) { 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EPERM; 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (change_irq || change_port || 72246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox (new_serial.baud_base != uport->uartclk / 16) || 72346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox (close_delay != port->close_delay) || 72446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox (closing_wait != port->closing_wait) || 725947deee8904b3c2edc7f59ab6e6242499e4dc434Russell King (new_serial.xmit_fifo_size && 72646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox new_serial.xmit_fifo_size != uport->fifosize) || 7270077d45e46fe2af3aaee5813c99268afcd0e7c0eRussell King (((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0)) 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 72946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->flags = ((uport->flags & ~UPF_USR_MASK) | 7300077d45e46fe2af3aaee5813c99268afcd0e7c0eRussell King (new_flags & UPF_USR_MASK)); 73146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->custom_divisor = new_serial.custom_divisor; 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto check_and_exit; 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ask the low level driver to verify the settings. 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 73846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->ops->verify_port) 73946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox retval = uport->ops->verify_port(uport, &new_serial); 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 741a62c41337356989387d15020dc0f0288aaacfa44Yinghai Lu if ((new_serial.irq >= nr_irqs) || (new_serial.irq < 0) || 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (new_serial.baud_base < 9600)) 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EINVAL; 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (change_port || change_irq) { 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EBUSY; 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Make sure that we are the sole user of this port. 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 754b58d13a0216d4e0753668214f23e1d2c24c30f8cAlan Cox if (tty_port_users(port) > 1) 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We need to shutdown the serial port at the old 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * port/type/irq combination. 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 761192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_shutdown(tty, state); 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (change_port) { 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long old_iobase, old_mapbase; 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int old_type, old_iotype, old_hub6, old_shift; 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 76846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_iobase = uport->iobase; 76946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_mapbase = uport->mapbase; 77046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_type = uport->type; 77146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_hub6 = uport->hub6; 77246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_iotype = uport->iotype; 77346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_shift = uport->regshift; 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free and release old regions 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (old_type != PORT_UNKNOWN) 77946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->ops->release_port(uport); 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 78146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->iobase = new_port; 78246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->type = new_serial.type; 78346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->hub6 = new_serial.hub6; 78446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->iotype = new_serial.io_type; 78546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->regshift = new_serial.iomem_reg_shift; 78646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->mapbase = (unsigned long)new_serial.iomem_base; 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Claim and map the new regions 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 79146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->type != PORT_UNKNOWN) { 79246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox retval = uport->ops->request_port(uport); 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Always success - Jean II */ 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we fail to request resources for the 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * new port, try to restore the old settings. 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval && old_type != PORT_UNKNOWN) { 80346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->iobase = old_iobase; 80446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->type = old_type; 80546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->hub6 = old_hub6; 80646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->iotype = old_iotype; 80746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->regshift = old_shift; 80846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->mapbase = old_mapbase; 80946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox retval = uport->ops->request_port(uport); 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we failed to restore the old settings, 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we fail like this. 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 81546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->type = PORT_UNKNOWN; 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We failed anyway. 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EBUSY; 821a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox /* Added to return the correct error -Ram Gupta */ 822a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox goto exit; 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 826abb4a2390737867353ebafc012d45f2b03f3f944David Gibson if (change_irq) 82746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->irq = new_serial.irq; 82846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (!(uport->flags & UPF_FIXED_PORT)) 82946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->uartclk = new_serial.baud_base * 16; 83046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->flags = (uport->flags & ~UPF_CHANGE_MASK) | 8310077d45e46fe2af3aaee5813c99268afcd0e7c0eRussell King (new_flags & UPF_CHANGE_MASK); 83246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->custom_divisor = new_serial.custom_divisor; 83346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox port->close_delay = close_delay; 83446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox port->closing_wait = closing_wait; 835947deee8904b3c2edc7f59ab6e6242499e4dc434Russell King if (new_serial.xmit_fifo_size) 83646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->fifosize = new_serial.xmit_fifo_size; 83746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (port->tty) 83846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox port->tty->low_latency = 83946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox (uport->flags & UPF_LOW_LATENCY) ? 1 : 0; 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds check_and_exit: 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 84346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->type == PORT_UNKNOWN) 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 845ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (port->flags & ASYNC_INITIALIZED) { 84646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (((old_flags ^ uport->flags) & UPF_SPD_MASK) || 84746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox old_custom_divisor != uport->custom_divisor) { 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If they're setting up a custom divisor or speed, 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * instead of clearing it, then bitch about it. No 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * need to rate-limit; it's CAP_SYS_ADMIN only. 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 85346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->flags & UPF_SPD_MASK) { 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char buf[64]; 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_NOTICE 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "%s sets custom speed on %s. This " 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "is deprecated.\n", current->comm, 85846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox tty_name(port->tty, buf)); 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 860192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_change_speed(tty, state, NULL); 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 863192251352f912bccfb942ea35801d2357f11f592Alan Cox retval = uart_startup(tty, state, 1); 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exit: 865a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 869192251352f912bccfb942ea35801d2357f11f592Alan Cox/** 870192251352f912bccfb942ea35801d2357f11f592Alan Cox * uart_get_lsr_info - get line status register info 871192251352f912bccfb942ea35801d2357f11f592Alan Cox * @tty: tty associated with the UART 872192251352f912bccfb942ea35801d2357f11f592Alan Cox * @state: UART being queried 873192251352f912bccfb942ea35801d2357f11f592Alan Cox * @value: returned modem value 874192251352f912bccfb942ea35801d2357f11f592Alan Cox * 875192251352f912bccfb942ea35801d2357f11f592Alan Cox * Note: uart_ioctl protects us against hangups. 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 877192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic int uart_get_lsr_info(struct tty_struct *tty, 878192251352f912bccfb942ea35801d2357f11f592Alan Cox struct uart_state *state, unsigned int __user *value) 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 88046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int result; 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 88346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox result = uport->ops->tx_empty(uport); 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we're about to load something into the transmit 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * register, we'll pretend the transmitter isn't empty to 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * avoid a race condition (depending on when the transmit 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupt happens). 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 89146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->x_char || 892ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox ((uart_circ_chars_pending(&state->xmit) > 0) && 893192251352f912bccfb942ea35801d2357f11f592Alan Cox !tty->stopped && !tty->hw_stopped)) 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result &= ~TIOCSER_TEMT; 895a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return put_user(result, value); 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 89960b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int uart_tiocmget(struct tty_struct *tty) 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 902a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 90346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result = -EIO; 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 906a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 90760b33c133ca0b7c0b6072c87234b63fee6e80558Alan Cox if (!(tty->flags & (1 << TTY_IO_ERROR))) { 90846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox result = uport->mctrl; 90946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_lock_irq(&uport->lock); 91046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox result |= uport->ops->get_mctrl(uport); 91146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_unlock_irq(&uport->lock); 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 913a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 91920b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxuart_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 92246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 923a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = -EIO; 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 926a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 92720b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Cox if (!(tty->flags & (1 << TTY_IO_ERROR))) { 92846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uart_update_mctrl(uport, set, clear); 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 931a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9359e98966c7bb94355689478bc84cc3e0c190f977eAlan Coxstatic int uart_break_ctl(struct tty_struct *tty, int break_state) 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 938a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 93946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 941a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 94346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->type != PORT_UNKNOWN) 94446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->ops->break_ctl(uport, break_state); 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 946a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 9479e98966c7bb94355689478bc84cc3e0c190f977eAlan Cox return 0; 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 950192251352f912bccfb942ea35801d2357f11f592Alan Coxstatic int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state) 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 95246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 953a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int flags, ret; 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!capable(CAP_SYS_ADMIN)) 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Take the per-port semaphore. This prevents count from 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * changing, and hence any extra opens of the port while 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we're auto-configuring. 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 964a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (mutex_lock_interruptible(&port->mutex)) 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ERESTARTSYS; 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EBUSY; 968b58d13a0216d4e0753668214f23e1d2c24c30f8cAlan Cox if (tty_port_users(port) == 1) { 969192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_shutdown(tty, state); 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we already have a port type configured, 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we must release its resources. 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 97546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->type != PORT_UNKNOWN) 97646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->ops->release_port(uport); 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags = UART_CONFIG_TYPE; 97946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->flags & UPF_AUTO_IRQ) 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags |= UART_CONFIG_IRQ; 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This will claim the ports resources if 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a port is found. 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 98646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->ops->config_port(uport, flags); 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 988192251352f912bccfb942ea35801d2357f11f592Alan Cox ret = uart_startup(tty, state, 1); 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 990a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - mask passed in arg for lines of interest 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Caller should use TIOCGICOUNT to see which one it was 999bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox * 1000bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox * FIXME: This wants extracting into a common all driver implementation 1001bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox * of TIOCMWAIT using tty_port. 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_wait_modem_status(struct uart_state *state, unsigned long arg) 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 100646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 1007bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox struct tty_port *port = &state->port; 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DECLARE_WAITQUEUE(wait, current); 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_icount cprev, cnow; 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * note the counters on entry 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 101546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_lock_irq(&uport->lock); 101646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox memcpy(&cprev, &uport->icount, sizeof(struct uart_icount)); 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Force modem status interrupts on 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 102146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->ops->enable_ms(uport); 102246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_unlock_irq(&uport->lock); 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1024bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox add_wait_queue(&port->delta_msr_wait, &wait); 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (;;) { 102646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_lock_irq(&uport->lock); 102746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); 102846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_unlock_irq(&uport->lock); 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_current_state(TASK_INTERRUPTIBLE); 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { 1036a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox ret = 0; 1037a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox break; 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds schedule(); 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* see if a signal did it */ 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) { 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ERESTARTSYS; 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cprev = cnow; 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds current->state = TASK_RUNNING; 1052bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox remove_wait_queue(&port->delta_msr_wait, &wait); 10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return: write counters to the user passed counter struct 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NB: both 1->0 and 0->1 transitions are counted except for 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * RI where only 0->1 is counted. 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1063d281da7ff6f70efca0553c288bb883e8605b3862Alan Coxstatic int uart_get_icount(struct tty_struct *tty, 1064d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox struct serial_icounter_struct *icount) 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1066d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox struct uart_state *state = tty->driver_data; 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_icount cnow; 106846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 107046d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_lock_irq(&uport->lock); 107146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); 107246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox spin_unlock_irq(&uport->lock); 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1074d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox icount->cts = cnow.cts; 1075d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox icount->dsr = cnow.dsr; 1076d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox icount->rng = cnow.rng; 1077d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox icount->dcd = cnow.dcd; 1078d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox icount->rx = cnow.rx; 1079d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox icount->tx = cnow.tx; 1080d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox icount->frame = cnow.frame; 1081d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox icount->overrun = cnow.overrun; 1082d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox icount->parity = cnow.parity; 1083d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox icount->brk = cnow.brk; 1084d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox icount->buf_overrun = cnow.buf_overrun; 1085d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox 1086d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox return 0; 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1090e52384426064bca0669a954736206adca7595d48Alan Cox * Called via sys_ioctl. We can use spin_lock_irq() here. 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 10936caa76b7786891b42b66a0e61e2c2fff2c884620Alan Coxuart_ioctl(struct tty_struct *tty, unsigned int cmd, 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long arg) 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 1097a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __user *uarg = (void __user *)arg; 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = -ENOIOCTLCMD; 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * These ioctls don't rely on the hardware to be present. 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TIOCGSERIAL: 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = uart_get_info(state, uarg); 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TIOCSSERIAL: 1111192251352f912bccfb942ea35801d2357f11f592Alan Cox ret = uart_set_info(tty, state, uarg); 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TIOCSERCONFIG: 1115192251352f912bccfb942ea35801d2357f11f592Alan Cox ret = uart_do_autoconfig(tty, state); 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TIOCSERGWILD: /* obsolete */ 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TIOCSERSWILD: /* obsolete */ 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret != -ENOIOCTLCMD) 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty->flags & (1 << TTY_IO_ERROR)) { 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EIO; 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The following should only be used when hardware is present. 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TIOCMIWAIT: 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = uart_wait_modem_status(state, arg); 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret != -ENOIOCTLCMD) 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1144a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11466caa76b7786891b42b66a0e61e2c2fff2c884620Alan Cox if (tty->flags & (1 << TTY_IO_ERROR)) { 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EIO; 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_up; 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * All these rely on hardware being present and need to be 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * protected against the tty being hung up. 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TIOCSERGETLSR: /* Get line status register */ 1157192251352f912bccfb942ea35801d2357f11f592Alan Cox ret = uart_get_lsr_info(tty, state, uarg); 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: { 116146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 116246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->ops->ioctl) 116346d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox ret = uport->ops->ioctl(uport, cmd, arg); 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1167f34d7a5b7010b82fe97da95496b9971435530062Alan Coxout_up: 1168a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 1169f34d7a5b7010b82fe97da95496b9971435530062Alan Coxout: 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1173edeb280e49d38a5330db25463ef45f5466b0058aLinus Torvaldsstatic void uart_set_ldisc(struct tty_struct *tty) 117464e9159f5d2c4edf5fa6425031e556f8fddaf7e6Alan Cox{ 117564e9159f5d2c4edf5fa6425031e556f8fddaf7e6Alan Cox struct uart_state *state = tty->driver_data; 117646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport = state->uart_port; 117764e9159f5d2c4edf5fa6425031e556f8fddaf7e6Alan Cox 117846d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (uport->ops->set_ldisc) 1179d87d9b7d19f04b16c4406d3c0feeca10090e0adaAlan Cox uport->ops->set_ldisc(uport, tty->termios->c_line); 118064e9159f5d2c4edf5fa6425031e556f8fddaf7e6Alan Cox} 118164e9159f5d2c4edf5fa6425031e556f8fddaf7e6Alan Cox 1182a46c9994242978ab001299cc9c906b9a3eedadccAlan Coxstatic void uart_set_termios(struct tty_struct *tty, 1183a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox struct ktermios *old_termios) 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cflag = tty->termios->c_cflag; 11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * These are the bits that are used to setup various 119220620d688ac6ff8ea01a873e46febf5a6a7909f1David Woodhouse * flags in the low level driver. We can ignore the Bfoo 119320620d688ac6ff8ea01a873e46febf5a6a7909f1David Woodhouse * bits in c_cflag; c_[io]speed will always be set 119420620d688ac6ff8ea01a873e46febf5a6a7909f1David Woodhouse * appropriately by set_termios() in tty_ioctl.c 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((cflag ^ old_termios->c_cflag) == 0 && 119820620d688ac6ff8ea01a873e46febf5a6a7909f1David Woodhouse tty->termios->c_ospeed == old_termios->c_ospeed && 119920620d688ac6ff8ea01a873e46febf5a6a7909f1David Woodhouse tty->termios->c_ispeed == old_termios->c_ispeed && 1200e52384426064bca0669a954736206adca7595d48Alan Cox RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) { 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1202e52384426064bca0669a954736206adca7595d48Alan Cox } 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1204192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_change_speed(tty, state, old_termios); 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Handle transition to B0 status */ 12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) 1208ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox uart_clear_mctrl(state->uart_port, TIOCM_RTS | TIOCM_DTR); 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Handle transition away from B0 status */ 121082cb7ba10deafe17686bf22ce4a7a303a77a197fAndré Goddard Rosa else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { 12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int mask = TIOCM_DTR; 12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(cflag & CRTSCTS) || 12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !test_bit(TTY_THROTTLED, &tty->flags)) 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask |= TIOCM_RTS; 1215ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox uart_set_mctrl(state->uart_port, mask); 12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Handle turning off CRTSCTS */ 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) { 1220ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox spin_lock_irqsave(&state->uart_port->lock, flags); 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->hw_stopped = 0; 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __uart_start(tty); 1223ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox spin_unlock_irqrestore(&state->uart_port->lock, flags); 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12250dd7a1aed7c34a39917c4faf75b4230c169e809bRussell King /* Handle turning on CRTSCTS */ 122682cb7ba10deafe17686bf22ce4a7a303a77a197fAndré Goddard Rosa else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) { 1227ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox spin_lock_irqsave(&state->uart_port->lock, flags); 1228ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (!(state->uart_port->ops->get_mctrl(state->uart_port) & TIOCM_CTS)) { 12290dd7a1aed7c34a39917c4faf75b4230c169e809bRussell King tty->hw_stopped = 1; 1230ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox state->uart_port->ops->stop_tx(state->uart_port); 12310dd7a1aed7c34a39917c4faf75b4230c169e809bRussell King } 1232ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox spin_unlock_irqrestore(&state->uart_port->lock, flags); 12330dd7a1aed7c34a39917c4faf75b4230c169e809bRussell King } 12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In 2.4.5, calls to this will be serialized via the BKL in 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/drivers/char/tty_io.c:tty_release() 12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/drivers/char/tty_io.c:do_tty_handup() 12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_close(struct tty_struct *tty, struct file *filp) 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 124446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct tty_port *port; 124546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct uart_port *uport; 124661cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox unsigned long flags; 1247a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox 1248eea7e17e0eb23729d58368420659f8e7c357d82eLinus Torvalds if (!state) 1249eea7e17e0eb23729d58368420659f8e7c357d82eLinus Torvalds return; 1250eea7e17e0eb23729d58368420659f8e7c357d82eLinus Torvalds 125146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport = state->uart_port; 125246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox port = &state->port; 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 125446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox pr_debug("uart_close(%d) called\n", uport->line); 12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1256a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 125761cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_lock_irqsave(&port->lock, flags); 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 125961cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox if (tty_hung_up_p(filp)) { 126061cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_unlock_irqrestore(&port->lock, flags); 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 126261cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox } 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 126491312cdb4fcd832341e425f74f49938e0503c929Alan Cox if ((tty->count == 1) && (port->count != 1)) { 12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Uh, oh. tty->count is 1, which means that the tty 126791312cdb4fcd832341e425f74f49938e0503c929Alan Cox * structure will be freed. port->count should always 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * be one in these conditions. If it's greater than 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * one, we've got real problems, since it means the 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * serial port won't be shutdown. 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "uart_close: bad serial port count; tty->count is 1, " 127391312cdb4fcd832341e425f74f49938e0503c929Alan Cox "port->count is %d\n", port->count); 127491312cdb4fcd832341e425f74f49938e0503c929Alan Cox port->count = 1; 12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 127691312cdb4fcd832341e425f74f49938e0503c929Alan Cox if (--port->count < 0) { 12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "uart_close: bad serial port count for %s: %d\n", 127891312cdb4fcd832341e425f74f49938e0503c929Alan Cox tty->name, port->count); 127991312cdb4fcd832341e425f74f49938e0503c929Alan Cox port->count = 0; 12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 128161cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox if (port->count) { 128261cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_unlock_irqrestore(&port->lock, flags); 12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 128461cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox } 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Now we wait for the transmit buffer to clear; and we notify 12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the line discipline to only process XON/XOFF characters by 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * setting tty->closing. 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1291426929f8d3514d7f727b8c464d1eeeaf74b21519Jiri Slaby set_bit(ASYNCB_CLOSING, &port->flags); 12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->closing = 1; 129361cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_unlock_irqrestore(&port->lock, flags); 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12951f33a51d9771b34be3cb6f7fb96a325e17bbac7bJiri Slaby if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) 12961f33a51d9771b34be3cb6f7fb96a325e17bbac7bJiri Slaby tty_wait_until_sent(tty, msecs_to_jiffies(port->closing_wait)); 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * At this point, we stop accepting input. To do this, we 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * disable the receive line status interrupts. 13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1302ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (port->flags & ASYNC_INITIALIZED) { 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1304eea7e17e0eb23729d58368420659f8e7c357d82eLinus Torvalds spin_lock_irqsave(&uport->lock, flags); 130546d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox uport->ops->stop_rx(uport); 1306eea7e17e0eb23729d58368420659f8e7c357d82eLinus Torvalds spin_unlock_irqrestore(&uport->lock, flags); 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Before we drop DTR, make sure the UART transmitter 13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * has completely drained; this is especially 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * important if there is a transmit FIFO! 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13121f33a51d9771b34be3cb6f7fb96a325e17bbac7bJiri Slaby uart_wait_until_sent(tty, uport->timeout); 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1315192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_shutdown(tty, state); 13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_flush_buffer(tty); 13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1318a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox tty_ldisc_flush(tty); 1319a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox 13207b01478f97a671c97fad9254aa91892209b018b5Alan Cox tty_port_tty_set(port, NULL); 132161cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_lock_irqsave(&port->lock, flags); 132261cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox tty->closing = 0; 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 132446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (port->blocked_open) { 132561cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_unlock_irqrestore(&port->lock, flags); 132646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox if (port->close_delay) 132746d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox msleep_interruptible(port->close_delay); 132861cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_lock_irqsave(&port->lock, flags); 132946d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox } else if (!uart_console(uport)) { 133061cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_unlock_irqrestore(&port->lock, flags); 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_change_pm(state, 3); 133261cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_lock_irqsave(&port->lock, flags); 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wake up anyone trying to open this port. 13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1338ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); 1339426929f8d3514d7f727b8c464d1eeeaf74b21519Jiri Slaby clear_bit(ASYNCB_CLOSING, &port->flags); 134061cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_unlock_irqrestore(&port->lock, flags); 134146d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox wake_up_interruptible(&port->open_wait); 1342426929f8d3514d7f727b8c464d1eeeaf74b21519Jiri Slaby wake_up_interruptible(&port->close_wait); 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 134446d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Coxdone: 1345a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13481f33a51d9771b34be3cb6f7fb96a325e17bbac7bJiri Slabystatic void uart_wait_until_sent(struct tty_struct *tty, int timeout) 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13501f33a51d9771b34be3cb6f7fb96a325e17bbac7bJiri Slaby struct uart_state *state = tty->driver_data; 13511f33a51d9771b34be3cb6f7fb96a325e17bbac7bJiri Slaby struct uart_port *port = state->uart_port; 13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long char_time, expire; 13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->type == PORT_UNKNOWN || port->fifosize == 0) 13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the check interval to be 1/5 of the estimated time to 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * send a single character, and make it at least 1. The check 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interval should also be less than the timeout. 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note: we have to use pretty tight timings here to satisfy 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the NIST-PCTS. 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char_time = (port->timeout - HZ/50) / port->fifosize; 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char_time = char_time / 5; 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (char_time == 0) 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char_time = 1; 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (timeout && timeout < char_time) 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char_time = timeout; 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the transmitter hasn't cleared in twice the approximate 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * amount of time to send the entire FIFO, it probably won't 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ever clear. This assumes the UART isn't doing flow 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * control, which is currently the case. Hence, if it ever 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * takes longer than port->timeout, this is probably due to a 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * UART bug of some kind. So, we clamp the timeout parameter at 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2*port->timeout. 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (timeout == 0 || timeout > 2 * port->timeout) 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds timeout = 2 * port->timeout; 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds expire = jiffies + timeout; 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1386eb3a1e1145ca8f12372c7c96aa0702d86a9002a9Jiri Slaby pr_debug("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n", 1387a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox port->line, jiffies, expire); 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check whether the transmitter is empty every 'char_time'. 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 'timeout' / 'expire' give us the maximum amount of time 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we wait. 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!port->ops->tx_empty(port)) { 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep_interruptible(jiffies_to_msecs(char_time)); 13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (time_after(jiffies, expire)) 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1401203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmann} 1402203652192634c1fce5e79df0a8ff2fabfaefd3abArnd Bergmann 14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is called with the BKL held in 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/drivers/char/tty_io.c:do_tty_hangup() 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We're called from the eventd thread, so we can sleep for 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a _short_ time only. 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_hangup(struct tty_struct *tty) 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = tty->driver_data; 141246d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox struct tty_port *port = &state->port; 141361cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox unsigned long flags; 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1415ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox pr_debug("uart_hangup(%d)\n", state->uart_port->line); 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1417a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 1418ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (port->flags & ASYNC_NORMAL_ACTIVE) { 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_flush_buffer(tty); 1420192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_shutdown(tty, state); 142161cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_lock_irqsave(&port->lock, flags); 142291312cdb4fcd832341e425f74f49938e0503c929Alan Cox port->count = 0; 1423ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); 142461cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox spin_unlock_irqrestore(&port->lock, flags); 14257b01478f97a671c97fad9254aa91892209b018b5Alan Cox tty_port_tty_set(port, NULL); 142646d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8Alan Cox wake_up_interruptible(&port->open_wait); 1427bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox wake_up_interruptible(&port->delta_msr_wait); 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1429a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1432de0c8cb314cc737c47a00de33cd6246accf94192Alan Coxstatic int uart_carrier_raised(struct tty_port *port) 1433de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox{ 1434de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox struct uart_state *state = container_of(port, struct uart_state, port); 1435de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox struct uart_port *uport = state->uart_port; 1436de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox int mctrl; 1437de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox spin_lock_irq(&uport->lock); 1438de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox uport->ops->enable_ms(uport); 1439de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox mctrl = uport->ops->get_mctrl(uport); 1440de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox spin_unlock_irq(&uport->lock); 1441de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox if (mctrl & TIOCM_CAR) 1442de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox return 1; 1443de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox return 0; 1444de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox} 1445de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox 1446de0c8cb314cc737c47a00de33cd6246accf94192Alan Coxstatic void uart_dtr_rts(struct tty_port *port, int onoff) 1447de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox{ 1448de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox struct uart_state *state = container_of(port, struct uart_state, port); 1449de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox struct uart_port *uport = state->uart_port; 145024fcc7c8cd0fcabcf37d455abe3501b3196fcf64Alan Cox 14516f5c24ad0f7619502199185a026a228174a27e68Jiri Slaby if (onoff) 1452de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS); 1453de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox else 1454de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); 1455de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox} 1456de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct uart_state *uart_get(struct uart_driver *drv, int line) 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state; 1460a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port; 146168ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King int ret = 0; 14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds state = drv->state + line; 1464a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox port = &state->port; 1465a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (mutex_lock_interruptible(&port->mutex)) { 146668ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King ret = -ERESTARTSYS; 146768ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King goto err; 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1470a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox port->count++; 1471ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (!state->uart_port || state->uart_port->flags & UPF_DEAD) { 147268ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King ret = -ENXIO; 147368ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King goto err_unlock; 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return state; 147668ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King 147768ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King err_unlock: 1478a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox port->count--; 1479a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 148068ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King err: 148168ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King return ERR_PTR(ret); 14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1485922f9cfa79b52c85b6002d96cb0eefd13437c58cDenis Cheng * calls to uart_open are serialised by the BKL in 1486922f9cfa79b52c85b6002d96cb0eefd13437c58cDenis Cheng * fs/char_dev.c:chrdev_open() 14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that if this fails, then uart_close() _will_ be called. 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In time, we want to scrap the "opening nonpresent ports" 14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * behaviour and implement an alternative way for setserial 14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to set base addresses/ports/types. This will allow us to 14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * get rid of a certain amount of extra tests. 14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int uart_open(struct tty_struct *tty, struct file *filp) 14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state; 14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state; 149891312cdb4fcd832341e425f74f49938e0503c929Alan Cox struct tty_port *port; 14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval, line = tty->index; 15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1501eb3a1e1145ca8f12372c7c96aa0702d86a9002a9Jiri Slaby pr_debug("uart_open(%d) called\n", line); 15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We take the semaphore inside uart_get to guarantee that we won't 1505ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox * be re-entered while allocating the state structure, or while we 15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * request any IRQs that the driver may need. This also has the nice 15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * side-effect that it delays the action of uart_hangup, so we can 1508ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox * guarantee that state->port.tty will always contain something 1509ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox * reasonable. 15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds state = uart_get(drv, line); 15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(state)) { 15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = PTR_ERR(state); 15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail; 15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 151691312cdb4fcd832341e425f74f49938e0503c929Alan Cox port = &state->port; 15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Once we set tty->driver_data here, we are guaranteed that 15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_close() will decrement the driver module use count. 15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Any failures from here onwards should not touch the count. 15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->driver_data = state; 1524ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox state->uart_port->state = state; 1525ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox tty->low_latency = (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0; 15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->alt_speed = 0; 15277b01478f97a671c97fad9254aa91892209b018b5Alan Cox tty_port_tty_set(port, tty); 15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the port is in the middle of closing, bail out now. 15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty_hung_up_p(filp)) { 15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EAGAIN; 153491312cdb4fcd832341e425f74f49938e0503c929Alan Cox port->count--; 1535a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail; 15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Make sure the device is in D0 state. 15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 154291312cdb4fcd832341e425f74f49938e0503c929Alan Cox if (port->count == 1) 15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_change_pm(state, 0); 15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Start up the serial port. 15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1548192251352f912bccfb942ea35801d2357f11f592Alan Cox retval = uart_startup(tty, state, 0); 15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we succeeded, wait until the port is ready. 15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 155361cd8a21d8a9fb4b11111270cf2d3aa919c20624Alan Cox mutex_unlock(&port->mutex); 15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval == 0) 155574c2107759dc6efaa1b9127014be58a742a1e7acAlan Cox retval = tty_port_block_til_ready(port, tty, filp); 15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1557a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Coxfail: 15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *uart_type(struct uart_port *port) 15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *str = NULL; 15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->ops->type) 15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds str = port->ops->type(port); 15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!str) 15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds str = "unknown"; 15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return str; 15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PROC_FS 15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1576d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyanstatic void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i) 15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = drv->state + i; 1579a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 15803689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis int pm_state; 1581a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct uart_port *uport = state->uart_port; 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char stat_buf[32]; 15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status; 1584d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan int mmio; 15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1586a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (!uport) 1587d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan return; 15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1589a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mmio = uport->iotype >= UPIO_MEM; 1590d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_printf(m, "%d: uart:%s %s%08llX irq:%d", 1591a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->line, uart_type(uport), 15926c6a2334a1e8af7c3eaab992732825fa9ade77cfSergei Shtylyov mmio ? "mmio:0x" : "port:", 1593a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mmio ? (unsigned long long)uport->mapbase 1594a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox : (unsigned long long)uport->iobase, 1595a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->irq); 15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1597a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->type == PORT_UNKNOWN) { 1598d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_putc(m, '\n'); 1599d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan return; 16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1602a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox if (capable(CAP_SYS_ADMIN)) { 1603a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 16043689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis pm_state = state->pm_state; 16053689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis if (pm_state) 16063689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis uart_change_pm(state, 0); 1607a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox spin_lock_irq(&uport->lock); 1608a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox status = uport->ops->get_mctrl(uport); 1609a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox spin_unlock_irq(&uport->lock); 16103689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis if (pm_state) 16113689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis uart_change_pm(state, pm_state); 1612a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1614d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_printf(m, " tx:%d rx:%d", 1615a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->icount.tx, uport->icount.rx); 1616a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->icount.frame) 1617d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_printf(m, " fe:%d", 1618a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->icount.frame); 1619a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->icount.parity) 1620d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_printf(m, " pe:%d", 1621a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->icount.parity); 1622a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->icount.brk) 1623d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_printf(m, " brk:%d", 1624a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->icount.brk); 1625a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->icount.overrun) 1626d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_printf(m, " oe:%d", 1627a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->icount.overrun); 1628a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox 1629a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox#define INFOBIT(bit, str) \ 1630a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->mctrl & (bit)) \ 16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strncat(stat_buf, (str), sizeof(stat_buf) - \ 16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strlen(stat_buf) - 2) 1633a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox#define STATBIT(bit, str) \ 16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & (bit)) \ 16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strncat(stat_buf, (str), sizeof(stat_buf) - \ 16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strlen(stat_buf) - 2) 16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stat_buf[0] = '\0'; 16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stat_buf[1] = '\0'; 16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INFOBIT(TIOCM_RTS, "|RTS"); 16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds STATBIT(TIOCM_CTS, "|CTS"); 16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INFOBIT(TIOCM_DTR, "|DTR"); 16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds STATBIT(TIOCM_DSR, "|DSR"); 16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds STATBIT(TIOCM_CAR, "|CD"); 16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds STATBIT(TIOCM_RNG, "|RI"); 16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (stat_buf[0]) 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stat_buf[0] = ' '; 1648a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox 1649d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_puts(m, stat_buf); 16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1651d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_putc(m, '\n'); 16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef STATBIT 16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef INFOBIT 16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1656d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyanstatic int uart_proc_show(struct seq_file *m, void *v) 16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1658833bb3046b6cb320e775ea2160ddca87d53260d5Alexey Dobriyan struct tty_driver *ttydrv = m->private; 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_driver *drv = ttydrv->driver_state; 1660d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan int i; 16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1662d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n", 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "", "", ""); 1664d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan for (i = 0; i < drv->nr; i++) 1665d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan uart_line_info(m, drv, i); 1666d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan return 0; 16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1668d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan 1669d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyanstatic int uart_proc_open(struct inode *inode, struct file *file) 1670d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan{ 1671d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan return single_open(file, uart_proc_show, PDE(inode)->data); 1672d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan} 1673d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan 1674d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyanstatic const struct file_operations uart_proc_fops = { 1675d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan .owner = THIS_MODULE, 1676d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan .open = uart_proc_open, 1677d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan .read = seq_read, 1678d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan .llseek = seq_lseek, 1679d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan .release = single_release, 1680d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan}; 16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16834a1b5502d426df09b9ba1cbcc74fd09702a74cd8Andrew Morton#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) 16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1685d358788f3f30113e49882187d794832905e42592Russell King * uart_console_write - write a console message to a serial port 1686d358788f3f30113e49882187d794832905e42592Russell King * @port: the port to write the message 1687d358788f3f30113e49882187d794832905e42592Russell King * @s: array of characters 1688d358788f3f30113e49882187d794832905e42592Russell King * @count: number of characters in string to write 1689d358788f3f30113e49882187d794832905e42592Russell King * @write: function to write character to port 1690d358788f3f30113e49882187d794832905e42592Russell King */ 1691d358788f3f30113e49882187d794832905e42592Russell Kingvoid uart_console_write(struct uart_port *port, const char *s, 1692d358788f3f30113e49882187d794832905e42592Russell King unsigned int count, 1693d358788f3f30113e49882187d794832905e42592Russell King void (*putchar)(struct uart_port *, int)) 1694d358788f3f30113e49882187d794832905e42592Russell King{ 1695d358788f3f30113e49882187d794832905e42592Russell King unsigned int i; 1696d358788f3f30113e49882187d794832905e42592Russell King 1697d358788f3f30113e49882187d794832905e42592Russell King for (i = 0; i < count; i++, s++) { 1698d358788f3f30113e49882187d794832905e42592Russell King if (*s == '\n') 1699d358788f3f30113e49882187d794832905e42592Russell King putchar(port, '\r'); 1700d358788f3f30113e49882187d794832905e42592Russell King putchar(port, *s); 1701d358788f3f30113e49882187d794832905e42592Russell King } 1702d358788f3f30113e49882187d794832905e42592Russell King} 1703d358788f3f30113e49882187d794832905e42592Russell KingEXPORT_SYMBOL_GPL(uart_console_write); 1704d358788f3f30113e49882187d794832905e42592Russell King 1705d358788f3f30113e49882187d794832905e42592Russell King/* 17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check whether an invalid uart number has been specified, and 17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if so, search for the first available port that does have 17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * console support. 17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct uart_port * __init 17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_get_console(struct uart_port *ports, int nr, struct console *co) 17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int idx = co->index; 17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (idx < 0 || idx >= nr || (ports[idx].iobase == 0 && 17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ports[idx].membase == NULL)) 17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (idx = 0; idx < nr; idx++) 17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ports[idx].iobase != 0 || 17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ports[idx].membase != NULL) 17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds co->index = idx; 17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ports + idx; 17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_parse_options - Parse serial port baud/parity/bits/flow contro. 17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @options: pointer to option string 17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @baud: pointer to an 'int' variable for the baud rate. 17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @parity: pointer to an 'int' variable for the parity. 17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @bits: pointer to an 'int' variable for the number of data bits. 17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @flow: pointer to an 'int' variable for the flow control character. 17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_parse_options decodes a string containing the serial console 17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * options. The format of the string is <baud><parity><bits><flow>, 17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * eg: 115200n8r 17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1739f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselvoid 17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow) 17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *s = options; 17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *baud = simple_strtoul(s, NULL, 10); 17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (*s >= '0' && *s <= '9') 17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s++; 17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*s) 17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *parity = *s++; 17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*s) 17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *bits = *s++ - '0'; 17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*s) 17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *flow = *s; 17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1754f2d937f3bf00665ccf048b3b6616ef95859b0945Jason WesselEXPORT_SYMBOL_GPL(uart_parse_options); 17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct baud_rates { 17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int rate; 17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cflag; 17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1761cb3592be272d83011051dc49f4326355c01f1e1fArjan van de Venstatic const struct baud_rates baud_rates[] = { 17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 921600, B921600 }, 17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 460800, B460800 }, 17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 230400, B230400 }, 17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 115200, B115200 }, 17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 57600, B57600 }, 17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 38400, B38400 }, 17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 19200, B19200 }, 17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 9600, B9600 }, 17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 4800, B4800 }, 17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 2400, B2400 }, 17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 1200, B1200 }, 17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 0, B38400 } 17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_set_options - setup the serial console parameters 17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @port: pointer to the serial ports uart_port structure 17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @co: console pointer 17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @baud: baud rate 17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @parity: parity character - 'n' (none), 'o' (odd), 'e' (even) 17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @bits: number of data bits 17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @flow: flow control character - 'r' (rts) 17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1785f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselint 17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_set_options(struct uart_port *port, struct console *co, 17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int baud, int parity, int bits, int flow) 17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1789606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox struct ktermios termios; 1790149b36eae2ab6aa6056664f4bc461f3d3affc9c1Alan Cox static struct ktermios dummy; 17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1793976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King /* 1794976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King * Ensure that the serial console lock is initialised 1795976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King * early. 1796976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King */ 1797976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King spin_lock_init(&port->lock); 179813e83599d282ddfd544600df9db5ab343ac4662fIngo Molnar lockdep_set_class(&port->lock, &port_lock_key); 1799976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King 1800606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox memset(&termios, 0, sizeof(struct ktermios)); 18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios.c_cflag = CREAD | HUPCL | CLOCAL; 18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Construct a cflag setting. 18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; baud_rates[i].rate; i++) 18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (baud_rates[i].rate <= baud) 18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios.c_cflag |= baud_rates[i].cflag; 18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bits == 7) 18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios.c_cflag |= CS7; 18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios.c_cflag |= CS8; 18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (parity) { 18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 'o': case 'O': 18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios.c_cflag |= PARODD; 18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*fall through*/ 18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 'e': case 'E': 18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios.c_cflag |= PARENB; 18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (flow == 'r') 18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds termios.c_cflag |= CRTSCTS; 18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 183079492689e40d4f4d3d8a7262781d56fb295b4b86Yinghai Lu /* 183179492689e40d4f4d3d8a7262781d56fb295b4b86Yinghai Lu * some uarts on other side don't support no flow control. 183279492689e40d4f4d3d8a7262781d56fb295b4b86Yinghai Lu * So we set * DTR in host uart to make them happy 183379492689e40d4f4d3d8a7262781d56fb295b4b86Yinghai Lu */ 183479492689e40d4f4d3d8a7262781d56fb295b4b86Yinghai Lu port->mctrl |= TIOCM_DTR; 183579492689e40d4f4d3d8a7262781d56fb295b4b86Yinghai Lu 1836149b36eae2ab6aa6056664f4bc461f3d3affc9c1Alan Cox port->ops->set_termios(port, &termios, &dummy); 1837f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel /* 1838f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel * Allow the setting of the UART parameters with a NULL console 1839f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel * too: 1840f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel */ 1841f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel if (co) 1842f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel co->cflag = termios.c_cflag; 18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1846f2d937f3bf00665ccf048b3b6616ef95859b0945Jason WesselEXPORT_SYMBOL_GPL(uart_set_options); 18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_SERIAL_CORE_CONSOLE */ 18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uart_change_pm(struct uart_state *state, int pm_state) 18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1851ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox struct uart_port *port = state->uart_port; 18521281e36027a9119356bd93b5e7853c72c35dd462Andrew Victor 18531281e36027a9119356bd93b5e7853c72c35dd462Andrew Victor if (state->pm_state != pm_state) { 18541281e36027a9119356bd93b5e7853c72c35dd462Andrew Victor if (port->ops->pm) 18551281e36027a9119356bd93b5e7853c72c35dd462Andrew Victor port->ops->pm(port, pm_state, state->pm_state); 18561281e36027a9119356bd93b5e7853c72c35dd462Andrew Victor state->pm_state = pm_state; 18571281e36027a9119356bd93b5e7853c72c35dd462Andrew Victor } 18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1860b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetskistruct uart_match { 1861b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski struct uart_port *port; 1862b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski struct uart_driver *driver; 1863b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski}; 1864b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski 1865b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetskistatic int serial_match_port(struct device *dev, void *data) 1866b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski{ 1867b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski struct uart_match *match = data; 18687ca796f492a11f9408e661c8f22cd8c4f486b8e5Guennadi Liakhovetski struct tty_driver *tty_drv = match->driver->tty_driver; 18697ca796f492a11f9408e661c8f22cd8c4f486b8e5Guennadi Liakhovetski dev_t devt = MKDEV(tty_drv->major, tty_drv->minor_start) + 18707ca796f492a11f9408e661c8f22cd8c4f486b8e5Guennadi Liakhovetski match->port->line; 1871b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski 1872b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski return dev->devt == devt; /* Actually, only one tty per port */ 1873b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski} 1874b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski 1875ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Coxint uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) 18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1877ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct uart_state *state = drv->state + uport->line; 1878ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct tty_port *port = &state->port; 1879b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski struct device *tty_dev; 1880ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct uart_match match = {uport, drv}; 18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1882a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1884ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox tty_dev = device_find_child(uport->dev, &match, serial_match_port); 1885b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski if (device_may_wakeup(tty_dev)) { 18863f960dbb9dfe29ff283810624c4340c79fde87f5Govindraj.R if (!enable_irq_wake(uport->irq)) 18873f960dbb9dfe29ff283810624c4340c79fde87f5Govindraj.R uport->irq_wake = 1; 1888b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski put_device(tty_dev); 1889a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 1890b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski return 0; 1891b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski } 18924547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec if (console_suspend_enabled || !uart_console(uport)) 18934547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec uport->suspended = 1; 1894b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski 1895ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (port->flags & ASYNC_INITIALIZED) { 1896ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox const struct uart_ops *ops = uport->ops; 1897c8c6bfa39d6bd7347f43937c8767ae145b61bcb4Russell King int tries; 18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18994547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec if (console_suspend_enabled || !uart_console(uport)) { 19004547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec set_bit(ASYNCB_SUSPENDED, &port->flags); 19014547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec clear_bit(ASYNCB_INITIALIZED, &port->flags); 1902a6b93a908508810c5d51dd9b390283345af6f2d9Russell King 19034547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec spin_lock_irq(&uport->lock); 19044547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec ops->stop_tx(uport); 19054547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec ops->set_mctrl(uport, 0); 19064547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec ops->stop_rx(uport); 19074547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec spin_unlock_irq(&uport->lock); 19084547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec } 19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait for the transmitter to empty. 19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1913ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox for (tries = 3; !ops->tx_empty(uport) && tries; tries--) 19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep(10); 1915c8c6bfa39d6bd7347f43937c8767ae145b61bcb4Russell King if (!tries) 1916a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox printk(KERN_ERR "%s%s%s%d: Unable to drain " 1917a46c9994242978ab001299cc9c906b9a3eedadccAlan Cox "transmitter\n", 1918ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox uport->dev ? dev_name(uport->dev) : "", 1919ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox uport->dev ? ": " : "", 19208440838bc5337243917f13bc14ea2445da5e0197David S. Miller drv->dev_name, 1921ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox drv->tty_driver->name_base + uport->line); 19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19234547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec if (console_suspend_enabled || !uart_console(uport)) 19244547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec ops->shutdown(uport); 19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Disable the console device before suspending. 19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19304547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec if (console_suspend_enabled && uart_console(uport)) 1931ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox console_stop(uport->cons); 19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19334547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec if (console_suspend_enabled || !uart_console(uport)) 19344547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec uart_change_pm(state, 3); 19351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1936a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1941ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Coxint uart_resume_port(struct uart_driver *drv, struct uart_port *uport) 19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1943ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct uart_state *state = drv->state + uport->line; 1944ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct tty_port *port = &state->port; 194503a74dcc7eebe6edd778317e82fafdf71e68488cArjan van de Ven struct device *tty_dev; 1946ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox struct uart_match match = {uport, drv}; 1947ba15ab0e8de0d4439a91342ad52d55ca9e313f3dDeepak Saxena struct ktermios termios; 19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1949a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1951ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox tty_dev = device_find_child(uport->dev, &match, serial_match_port); 1952ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (!uport->suspended && device_may_wakeup(tty_dev)) { 19533f960dbb9dfe29ff283810624c4340c79fde87f5Govindraj.R if (uport->irq_wake) { 19543f960dbb9dfe29ff283810624c4340c79fde87f5Govindraj.R disable_irq_wake(uport->irq); 19553f960dbb9dfe29ff283810624c4340c79fde87f5Govindraj.R uport->irq_wake = 0; 19563f960dbb9dfe29ff283810624c4340c79fde87f5Govindraj.R } 1957a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 1958b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski return 0; 1959b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski } 1960ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox uport->suspended = 0; 1961b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski 19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Re-enable the console device after suspending. 19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19655933a161abcb8d83a2c145177f48027c3c0a8995Yin Kangkai if (uart_console(uport)) { 1966891b9dd10764352926e1e107756aa229dfa2c210Jason Wang /* 1967891b9dd10764352926e1e107756aa229dfa2c210Jason Wang * First try to use the console cflag setting. 1968891b9dd10764352926e1e107756aa229dfa2c210Jason Wang */ 1969891b9dd10764352926e1e107756aa229dfa2c210Jason Wang memset(&termios, 0, sizeof(struct ktermios)); 1970891b9dd10764352926e1e107756aa229dfa2c210Jason Wang termios.c_cflag = uport->cons->cflag; 1971891b9dd10764352926e1e107756aa229dfa2c210Jason Wang 1972891b9dd10764352926e1e107756aa229dfa2c210Jason Wang /* 1973891b9dd10764352926e1e107756aa229dfa2c210Jason Wang * If that's unset, use the tty termios setting. 1974891b9dd10764352926e1e107756aa229dfa2c210Jason Wang */ 1975891b9dd10764352926e1e107756aa229dfa2c210Jason Wang if (port->tty && port->tty->termios && termios.c_cflag == 0) 1976891b9dd10764352926e1e107756aa229dfa2c210Jason Wang termios = *(port->tty->termios); 1977891b9dd10764352926e1e107756aa229dfa2c210Jason Wang 1978ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox uport->ops->set_termios(uport, &termios, NULL); 19795933a161abcb8d83a2c145177f48027c3c0a8995Yin Kangkai if (console_suspend_enabled) 19805933a161abcb8d83a2c145177f48027c3c0a8995Yin Kangkai console_start(uport->cons); 19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1983ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox if (port->flags & ASYNC_SUSPENDED) { 1984ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox const struct uart_ops *ops = uport->ops; 1985ee31b337852ca8a65840702544ff5c64d37740f5Russell King int ret; 19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19879d778a69370cc1b643b13648df971c83ff5654efRussell King uart_change_pm(state, 0); 1988ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox spin_lock_irq(&uport->lock); 1989ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox ops->set_mctrl(uport, 0); 1990ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox spin_unlock_irq(&uport->lock); 19914547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec if (console_suspend_enabled || !uart_console(uport)) { 1992192251352f912bccfb942ea35801d2357f11f592Alan Cox /* Protected by port mutex for now */ 1993192251352f912bccfb942ea35801d2357f11f592Alan Cox struct tty_struct *tty = port->tty; 19944547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec ret = ops->startup(uport); 19954547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec if (ret == 0) { 1996192251352f912bccfb942ea35801d2357f11f592Alan Cox if (tty) 1997192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_change_speed(tty, state, NULL); 19984547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec spin_lock_irq(&uport->lock); 19994547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec ops->set_mctrl(uport, uport->mctrl); 20004547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec ops->start_tx(uport); 20014547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec spin_unlock_irq(&uport->lock); 20024547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec set_bit(ASYNCB_INITIALIZED, &port->flags); 20034547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec } else { 20044547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec /* 20054547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec * Failed to resume - maybe hardware went away? 20064547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec * Clear the "initialized" flag so we won't try 20074547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec * to call the low level drivers shutdown method. 20084547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec */ 2009192251352f912bccfb942ea35801d2357f11f592Alan Cox uart_shutdown(tty, state); 20104547be7809a3b775ce750ec7f8b5748954741523Stanislav Brabec } 2011ee31b337852ca8a65840702544ff5c64d37740f5Russell King } 2012a6b93a908508810c5d51dd9b390283345af6f2d9Russell King 2013ccce6debb62d94964e3878f978a56b0f3e32d94fAlan Cox clear_bit(ASYNCB_SUSPENDED, &port->flags); 20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2016a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void 20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_report_port(struct uart_driver *drv, struct uart_port *port) 20231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 202430b7a3bc133c5b4a723163be35157ed709fca91cRussell King char address[64]; 202530b7a3bc133c5b4a723163be35157ed709fca91cRussell King 20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (port->iotype) { 20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case UPIO_PORT: 20289bde10a4b8c54804236d3d6b4b75e98825a921e7Andrew Morton snprintf(address, sizeof(address), "I/O 0x%lx", port->iobase); 20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case UPIO_HUB6: 203130b7a3bc133c5b4a723163be35157ed709fca91cRussell King snprintf(address, sizeof(address), 20329bde10a4b8c54804236d3d6b4b75e98825a921e7Andrew Morton "I/O 0x%lx offset 0x%x", port->iobase, port->hub6); 20331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case UPIO_MEM: 20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case UPIO_MEM32: 203621c614a7899046ab108b3d327d76c33443a8ebf2Pantelis Antoniou case UPIO_AU: 20373be91ec7388bae3cf1bfb4febcee5ab6c65f409fZang Roy-r case UPIO_TSI: 203830b7a3bc133c5b4a723163be35157ed709fca91cRussell King snprintf(address, sizeof(address), 20394f640efb3170dbcf99a37a3cc99060647b95428cJosh Boyer "MMIO 0x%llx", (unsigned long long)port->mapbase); 204030b7a3bc133c5b4a723163be35157ed709fca91cRussell King break; 204130b7a3bc133c5b4a723163be35157ed709fca91cRussell King default: 204230b7a3bc133c5b4a723163be35157ed709fca91cRussell King strlcpy(address, "*unknown*", sizeof(address)); 20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 204530b7a3bc133c5b4a723163be35157ed709fca91cRussell King 20460cf669d5c5d08eb827df9867429df21cf030eba6Russell King printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n", 20474bfe090b0a29258eeeb026a09a96cf5b5838ac63Kay Sievers port->dev ? dev_name(port->dev) : "", 20480cf669d5c5d08eb827df9867429df21cf030eba6Russell King port->dev ? ": " : "", 20498440838bc5337243917f13bc14ea2445da5e0197David S. Miller drv->dev_name, 20508440838bc5337243917f13bc14ea2445da5e0197David S. Miller drv->tty_driver->name_base + port->line, 20518440838bc5337243917f13bc14ea2445da5e0197David S. Miller address, port->irq, uart_type(port)); 20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuart_configure_port(struct uart_driver *drv, struct uart_state *state, 20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_port *port) 20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int flags; 20591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If there isn't a port here, don't do anything further. 20621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!port->iobase && !port->mapbase && !port->membase) 20641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Now do the auto configuration stuff. Note that config_port 20681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is expected to claim the resources and map the port for us. 20691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20708e23fcc89c8091790903927449f8efb9b4e23960David Daney flags = 0; 20711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->flags & UPF_AUTO_IRQ) 20721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags |= UART_CONFIG_IRQ; 20731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->flags & UPF_BOOT_AUTOCONF) { 20748e23fcc89c8091790903927449f8efb9b4e23960David Daney if (!(port->flags & UPF_FIXED_TYPE)) { 20758e23fcc89c8091790903927449f8efb9b4e23960David Daney port->type = PORT_UNKNOWN; 20768e23fcc89c8091790903927449f8efb9b4e23960David Daney flags |= UART_CONFIG_TYPE; 20778e23fcc89c8091790903927449f8efb9b4e23960David Daney } 20781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->ops->config_port(port, flags); 20791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->type != PORT_UNKNOWN) { 20821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 20831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_report_port(drv, port); 20851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20863689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis /* Power up port for set_mctrl() */ 20873689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis uart_change_pm(state, 0); 20883689a0ec60bc8f56cc372c1dfa0d89dab48f7c9cGeorge G. Davis 20891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ensure that the modem control lines are de-activated. 2091c3e4642be734ce3d2c7398246d8cbced3a039f54Yinghai Lu * keep the DTR setting that is set in uart_set_options() 20921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We probably don't need a spinlock around this, but 20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port->lock, flags); 2095c3e4642be734ce3d2c7398246d8cbced3a039f54Yinghai Lu port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR); 20961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port->lock, flags); 20971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 209997d97224ff361e08777fb33e0fd193ca877dac28Russell King * If this driver supports console, and it hasn't been 210097d97224ff361e08777fb33e0fd193ca877dac28Russell King * successfully registered yet, try to re-register it. 210197d97224ff361e08777fb33e0fd193ca877dac28Russell King * It may be that the port was not available. 210297d97224ff361e08777fb33e0fd193ca877dac28Russell King */ 210397d97224ff361e08777fb33e0fd193ca877dac28Russell King if (port->cons && !(port->cons->flags & CON_ENABLED)) 210497d97224ff361e08777fb33e0fd193ca877dac28Russell King register_console(port->cons); 210597d97224ff361e08777fb33e0fd193ca877dac28Russell King 210697d97224ff361e08777fb33e0fd193ca877dac28Russell King /* 21071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Power down all ports by default, except the 21081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * console if we have one. 21091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 21101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!uart_console(port)) 21111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_change_pm(state, 3); 21121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2115f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel#ifdef CONFIG_CONSOLE_POLL 2116f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2117f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic int uart_poll_init(struct tty_driver *driver, int line, char *options) 2118f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel{ 2119f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_driver *drv = driver->driver_state; 2120f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_state *state = drv->state + line; 2121f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_port *port; 2122f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel int baud = 9600; 2123f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel int bits = 8; 2124f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel int parity = 'n'; 2125f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel int flow = 'n'; 2126f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2127ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (!state || !state->uart_port) 2128f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel return -1; 2129f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2130ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox port = state->uart_port; 2131f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel if (!(port->ops->poll_get_char && port->ops->poll_put_char)) 2132f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel return -1; 2133f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2134f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel if (options) { 2135f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel uart_parse_options(options, &baud, &parity, &bits, &flow); 2136f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel return uart_set_options(port, NULL, baud, parity, bits, flow); 2137f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel } 2138f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2139f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel return 0; 2140f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel} 2141f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2142f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic int uart_poll_get_char(struct tty_driver *driver, int line) 2143f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel{ 2144f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_driver *drv = driver->driver_state; 2145f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_state *state = drv->state + line; 2146f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_port *port; 2147f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2148ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (!state || !state->uart_port) 2149f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel return -1; 2150f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2151ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox port = state->uart_port; 2152f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel return port->ops->poll_get_char(port); 2153f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel} 2154f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2155f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wesselstatic void uart_poll_put_char(struct tty_driver *driver, int line, char ch) 2156f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel{ 2157f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_driver *drv = driver->driver_state; 2158f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_state *state = drv->state + line; 2159f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel struct uart_port *port; 2160f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2161ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (!state || !state->uart_port) 2162f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel return; 2163f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2164ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox port = state->uart_port; 2165f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel port->ops->poll_put_char(port, ch); 2166f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel} 2167f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel#endif 2168f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel 2169b68e31d0ebbcc909d1941f9f230c9d062a3a13d3Jeff Dikestatic const struct tty_operations uart_ops = { 21701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = uart_open, 21711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .close = uart_close, 21721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = uart_write, 21731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .put_char = uart_put_char, 21741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .flush_chars = uart_flush_chars, 21751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_room = uart_write_room, 21761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .chars_in_buffer= uart_chars_in_buffer, 21771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .flush_buffer = uart_flush_buffer, 21781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ioctl = uart_ioctl, 21791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .throttle = uart_throttle, 21801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .unthrottle = uart_unthrottle, 21811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .send_xchar = uart_send_xchar, 21821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_termios = uart_set_termios, 218364e9159f5d2c4edf5fa6425031e556f8fddaf7e6Alan Cox .set_ldisc = uart_set_ldisc, 21841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .stop = uart_stop, 21851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .start = uart_start, 21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .hangup = uart_hangup, 21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .break_ctl = uart_break_ctl, 21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .wait_until_sent= uart_wait_until_sent, 21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PROC_FS 2190d196a949ba0fb85121c0dc0720b13380d802dbd6Alexey Dobriyan .proc_fops = &uart_proc_fops, 21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .tiocmget = uart_tiocmget, 21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .tiocmset = uart_tiocmset, 2194d281da7ff6f70efca0553c288bb883e8605b3862Alan Cox .get_icount = uart_get_icount, 2195f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel#ifdef CONFIG_CONSOLE_POLL 2196f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel .poll_init = uart_poll_init, 2197f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel .poll_get_char = uart_poll_get_char, 2198f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel .poll_put_char = uart_poll_put_char, 2199f2d937f3bf00665ccf048b3b6616ef95859b0945Jason Wessel#endif 22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 22011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2202de0c8cb314cc737c47a00de33cd6246accf94192Alan Coxstatic const struct tty_port_operations uart_port_ops = { 2203de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox .carrier_raised = uart_carrier_raised, 2204de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox .dtr_rts = uart_dtr_rts, 2205de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox}; 2206de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox 22071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 22081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_register_driver - register a driver with the uart core layer 22091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @drv: low level driver structure 22101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 22111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Register a uart driver with the core driver. We in turn register 22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with the tty layer, and initialise the core driver per-port state. 22131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 22141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We have a proc file in /proc/tty/driver which is named after the 22151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * normal driver. 22161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 22171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drv->port should be NULL, and the per-port structures should be 22181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * registered using uart_add_one_port after this call has succeeded. 22191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 22201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint uart_register_driver(struct uart_driver *drv) 22211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 22229e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa struct tty_driver *normal; 22231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, retval; 22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(drv->state); 22261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Maybe we should be using a slab cache for this, especially if 22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we have a large number of ports to handle. 22301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 22318f31bb39ec2a5622974666c72257e74c22492602Burman Yan drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL); 22321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!drv->state) 22331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 22341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22359e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa normal = alloc_tty_driver(drv->nr); 22361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!normal) 22379e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa goto out_kfree; 22381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds drv->tty_driver = normal; 22401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->owner = drv->owner; 22421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->driver_name = drv->driver_name; 22431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->name = drv->dev_name; 22441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->major = drv->major; 22451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->minor_start = drv->minor; 22461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->type = TTY_DRIVER_TYPE_SERIAL; 22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->subtype = SERIAL_TYPE_NORMAL; 22481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->init_termios = tty_std_termios; 22491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; 2250606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600; 2251331b831983f9d706f4a40d08a996d5c2c7a6ea7bGreg Kroah-Hartman normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; 22521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal->driver_state = drv; 22531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_set_operations(normal, &uart_ops); 22541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialise the UART state(s). 22571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 22581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < drv->nr; i++) { 22591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state = drv->state + i; 2260a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 22611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2262a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tty_port_init(port); 2263de0c8cb314cc737c47a00de33cd6246accf94192Alan Cox port->ops = &uart_port_ops; 2264a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox port->close_delay = 500; /* .5 seconds */ 2265a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox port->closing_wait = 30000; /* 30 seconds */ 22661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = tty_register_driver(normal); 22699e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa if (retval >= 0) 22709e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa return retval; 22719e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa 22729e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa put_tty_driver(normal); 22739e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosaout_kfree: 22749e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa kfree(drv->state); 22759e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosaout: 22769e845abfc8a8973373821aa05302794fd254514bAndré Goddard Rosa return -ENOMEM; 22771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 22801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_unregister_driver - remove a driver from the uart core layer 22811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @drv: low level driver structure 22821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 22831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Remove all references to a driver from the core driver. The low 22841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * level driver must have removed all its ports via the 22851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_remove_one_port() if it registered them with uart_add_one_port(). 22861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (ie, drv->port == NULL) 22871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 22881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid uart_unregister_driver(struct uart_driver *drv) 22891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tty_driver *p = drv->tty_driver; 22911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_unregister_driver(p); 22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_tty_driver(p); 22931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(drv->state); 22941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds drv->tty_driver = NULL; 22951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct tty_driver *uart_console_device(struct console *co, int *index) 22981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 22991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_driver *p = co->data; 23001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *index = co->index; 23011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return p->tty_driver; 23021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 23051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_add_one_port - attach a driver-defined port structure 23061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @drv: pointer to the uart low level driver structure for this port 23071b9894f342a39601bb0420b7b8c7e445670c1b51Randy Dunlap * @uport: uart port structure to use for this port. 23081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 23091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This allows the driver to register its own uart_port structure 23101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with the core driver. The main purpose is to allow the low 23111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * level uart drivers to expand uart_port, rather than having yet 23121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * more levels of structures. 23131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2314a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Coxint uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) 23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_state *state; 2317a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port; 23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 2319b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski struct device *tty_dev; 23201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(in_interrupt()); 23221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2323a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->line >= drv->nr) 23241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 23251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2326a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox state = drv->state + uport->line; 2327a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox port = &state->port; 23281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2329f392ecfa12de9a2baf72789b00557bac040d6171Arjan van de Ven mutex_lock(&port_mutex); 2330a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 2331ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox if (state->uart_port) { 23321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EINVAL; 23331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 23341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2336a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox state->uart_port = uport; 233797d97224ff361e08777fb33e0fd193ca877dac28Russell King state->pm_state = -1; 23381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2339a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->cons = drv->cons; 2340a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->state = state; 23411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2342976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King /* 2343976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King * If this port is a console, then the spinlock is already 2344976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King * initialised. 2345976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King */ 2346a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) { 2347a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox spin_lock_init(&uport->lock); 2348a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox lockdep_set_class(&uport->lock, &port_lock_key); 234913e83599d282ddfd544600df9db5ab343ac4662fIngo Molnar } 2350976ecd12b8144d066a23fe97c6fbfc1ac8470af7Russell King 2351a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uart_configure_port(drv, state, uport); 23521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 23541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Register the port whether it's detected or not. This allows 23551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * setserial to be used to alter this ports parameters. 23561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2357a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev); 2358b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski if (likely(!IS_ERR(tty_dev))) { 235974081f8667d73ad59961cf63be5f0e9d6a87c8a3Alan Stern device_init_wakeup(tty_dev, 1); 2360b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski device_set_wakeup_enable(tty_dev, 0); 2361b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski } else 2362b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2Guennadi Liakhovetski printk(KERN_ERR "Cannot register tty device on line %d\n", 2363a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->line); 23641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 236668ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King * Ensure UPF_DEAD is not set. 236768ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King */ 2368a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->flags &= ~UPF_DEAD; 236968ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King 23701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: 2371a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 2372f392ecfa12de9a2baf72789b00557bac040d6171Arjan van de Ven mutex_unlock(&port_mutex); 23731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 23751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 23781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * uart_remove_one_port - detach a driver defined port structure 23791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @drv: pointer to the uart low level driver structure for this port 23801b9894f342a39601bb0420b7b8c7e445670c1b51Randy Dunlap * @uport: uart port structure for this port 23811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 23821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This unhooks (and hangs up) the specified port structure from the 23831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * core driver. No further calls will be made to the low-level code 23841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for this port. 23851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2386a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Coxint uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) 23871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2388a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct uart_state *state = drv->state + uport->line; 2389a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox struct tty_port *port = &state->port; 23901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(in_interrupt()); 23921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2393a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (state->uart_port != uport) 23941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ALERT "Removing wrong port: %p != %p\n", 2395a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox state->uart_port, uport); 23961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2397f392ecfa12de9a2baf72789b00557bac040d6171Arjan van de Ven mutex_lock(&port_mutex); 23981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 240068ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King * Mark the port "dead" - this prevents any opens from 240168ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King * succeeding while we shut down the port. 240268ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King */ 2403a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_lock(&port->mutex); 2404a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->flags |= UPF_DEAD; 2405a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox mutex_unlock(&port->mutex); 240668ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King 240768ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King /* 2408aa4148cfc7b3b93eeaf755a7d14f10afaffe9a96Greg Kroah-Hartman * Remove the devices from the tty layer 24091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2410a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tty_unregister_device(drv->tty_driver, uport->line); 24111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2412a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (port->tty) 2413a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox tty_vhangup(port->tty); 241468ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King 241568ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King /* 241668ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King * Free the port IO and memory resources, if any. 241768ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King */ 2418a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox if (uport->type != PORT_UNKNOWN) 2419a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->ops->release_port(uport); 242068ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King 242168ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King /* 242268ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King * Indicate that there isn't a port here anymore. 242368ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King */ 2424a2bceae065ed8c4f552b35c4dde4cc2db05ce9e3Alan Cox uport->type = PORT_UNKNOWN; 242568ac64cd3fd89fdaa091701f6ab98a9065e9b1b5Russell King 2426ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox state->uart_port = NULL; 2427f392ecfa12de9a2baf72789b00557bac040d6171Arjan van de Ven mutex_unlock(&port_mutex); 24281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 24301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 24311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 24331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Are the two ports equivalent? 24341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 24351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint uart_match_port(struct uart_port *port1, struct uart_port *port2) 24361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 24371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port1->iotype != port2->iotype) 24381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 24391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (port1->iotype) { 24411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case UPIO_PORT: 24421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (port1->iobase == port2->iobase); 24431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case UPIO_HUB6: 24441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (port1->iobase == port2->iobase) && 24451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (port1->hub6 == port2->hub6); 24461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case UPIO_MEM: 2447d21b55d30b46c0b43821a2980e4998965fa37e33Sergei Shtylyov case UPIO_MEM32: 2448d21b55d30b46c0b43821a2980e4998965fa37e33Sergei Shtylyov case UPIO_AU: 2449d21b55d30b46c0b43821a2980e4998965fa37e33Sergei Shtylyov case UPIO_TSI: 24501624f003349b49050f42c7d9f5407dfc05efb912Benjamin Herrenschmidt return (port1->mapbase == port2->mapbase); 24511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 24531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 24541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_match_port); 24551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_write_wakeup); 24571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_register_driver); 24581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_unregister_driver); 24591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_suspend_port); 24601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_resume_port); 24611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_add_one_port); 24621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uart_remove_one_port); 24631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Serial driver core"); 24651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 2466