/* * linux/drivers/char/core.c * * Driver core for serial ports * * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. * * Copyright 1999 ARM Limited * Copyright (C) 2000-2001 Deep Blue Solutions Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <linux/module.h>#include <linux/tty.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/console.h>#include <linux/serial_core.h>#include <linux/smp_lock.h>#include <linux/device.h>#include <linux/serial.h> /* for serial_state and serial_icounter_struct */#include <linux/delay.h>#include <linux/mutex.h> #include <asm/irq.h>#include <asm/uaccess.h> #undef DEBUG#ifdef DEBUG#define DPRINTK(x...) printk(x)#else#define DPRINTK(x...) do { } while (0)#endif /* * This is used to lock changes in serial line configuration. */static DEFINE_MUTEX(port_mutex); /* * lockdep: port->lock is initialized in two places, but we * want only one lock-class: */static struct lock_class_key port_lock_key; #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) #define uart_users(state) ((state)->count + ((state)->info ? (state)->info->blocked_open : 0)) #ifdef CONFIG_SERIAL_CORE_CONSOLE#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line)#else#define uart_console(port) (0)#endif static void uart_change_speed(struct uart_state *state, struct ktermios *old_termios);static void uart_wait_until_sent(struct tty_struct *tty, int timeout);static void uart_change_pm(struct uart_state *state, int pm_state); /* * This routine is used by the interrupt handler to schedule processing in * the software interrupt portion of the driver. */void uart_write_wakeup(struct uart_port *port){ struct uart_info *info = port->info; /* * This means you called this function _after_ the port was * closed. No cookie for you. */ BUG_ON(!info); tasklet_schedule(&info->tlet);} static void uart_stop(struct tty_struct *tty){ struct uart_state *state = tty->driver_data; struct uart_port *port = state->port; unsigned long flags; spin_lock_irqsave(&port->lock, flags); port->ops->stop_tx(port); spin_unlock_irqrestore(&port->lock, flags);} static void __uart_start(struct tty_struct *tty){ struct uart_state *state = tty->driver_data; struct uart_port *port = state->port; if (!uart_circ_empty(&state->info->xmit) && state->info->xmit.buf && !tty->stopped && !tty->hw_stopped) port->ops->start_tx(port);} static void uart_start(struct tty_struct *tty){ struct uart_state *state = tty->driver_data; struct uart_port *port = state->port; unsigned long flags; spin_lock_irqsave(&port->lock, flags); __uart_start(tty); spin_unlock_irqrestore(&port->lock, flags);} static void uart_tasklet_action(unsigned long data){ struct uart_state *state = (struct uart_state *)data; tty_wakeup(state->info->tty);} static inline voiduart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear){ unsigned long flags; unsigned int old; spin_lock_irqsave(&port->lock, flags); old = port->mctrl; port->mctrl = (old & ~clear) | set; if (old != port->mctrl) port->ops->set_mctrl(port, port->mctrl); spin_unlock_irqrestore(&port->lock, flags);} #define uart_set_mctrl(port,set) uart_update_mctrl(port,set,0)#define uart_clear_mctrl(port,clear) uart_update_mctrl(port,0,clear) /* * Startup the port. This will be called once per open. All calls * will be serialised by the per-port semaphore. */static int uart_startup(struct uart_state *state, int init_hw){ struct uart_info *info = state->info; struct uart_port *port = state->port; unsigned long page; int retval = 0; if (info->flags & UIF_INITIALIZED) return 0; /* * Set the TTY IO error marker - we will only clear this * once we have successfully opened the port. Also set * up the tty->alt_speed kludge */ set_bit(TTY_IO_ERROR, &info->tty->flags); if (port->type == PORT_UNKNOWN) return 0; /* * Initialise and allocate the transmit and temporary * buffer. */ if (!info->xmit.buf) { page = get_zeroed_page(GFP_KERNEL); if (!page) return -ENOMEM; info->xmit.buf = (unsigned char *) page; uart_circ_clear(&info->xmit); } retval = port->ops->startup(port); if (retval == 0) { if (init_hw) { /* * Initialise the hardware port settings. */ uart_change_speed(state, NULL); /* * Setup the RTS and DTR signals once the * port is open and ready to respond. */ if (info->tty->termios->c_cflag & CBAUD) uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR); } if (info->flags & UIF_CTS_FLOW) { spin_lock_irq(&port->lock); if (!(port->ops->get_mctrl(port) & TIOCM_CTS)) info->tty->hw_stopped = 1; spin_unlock_irq(&port->lock); } info->flags |= UIF_INITIALIZED; clear_bit(TTY_IO_ERROR, &info->tty->flags); } if (retval && capable(CAP_SYS_ADMIN)) retval = 0; return retval;} /* * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. Calls to * uart_shutdown are serialised by the per-port semaphore. */static void uart_shutdown(struct uart_state *state){ struct uart_info *info = state->info; struct uart_port *port = state->port; /* * Set the TTY IO error marker */ if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); if (info->flags & UIF_INITIALIZED) { info->flags &= ~UIF_INITIALIZED; /* * Turn off DTR and RTS early. */ if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); /* * clear delta_msr_wait queue to avoid mem leaks: we may free * the irq here so the queue might never be woken up. Note * that we won't end up waiting on delta_msr_wait again since * any outstanding file descriptors should be pointing at * hung_up_tty_fops now. */ wake_up_interruptible(&info->delta_msr_wait); /* * Free the IRQ and disable the port. */ port->ops->shutdown(port); /* * Ensure that the IRQ handler isn't running on another CPU. */ synchronize_irq(port->irq); } /* * kill off our tasklet */ tasklet_kill(&info->tlet); /* * Free the transmit buffer page. */ if (info->xmit.buf) { free_page((unsigned long)info->xmit.buf); info->xmit.buf = NULL; }} /** * uart_update_timeout - update per-port FIFO timeout. * @port: uart_port structure describing the port * @cflag: termios cflag value * @baud: speed of the port * * Set the port FIFO timeout value. The @cflag value should * reflect the actual hardware settings. */voiduart_update_timeout(struct uart_port *port, unsigned int cflag, unsigned int baud){ unsigned int bits; /* byte size and parity */ switch (cflag & CSIZE) { case CS5: bits = 7; break; case CS6: bits = 8; break; case CS7: bits = 9; break; default: bits = 10; break; // CS8 } if (cflag & CSTOPB) bits++; if (cflag & PARENB) bits++; /* * The total number of bits to be transmitted in the fifo. */ bits = bits * port->fifosize; /* * Figure the timeout to send the above number of bits. * Add .02 seconds of slop */ port->timeout = (HZ * bits) / baud + HZ/50;} EXPORT_SYMBOL(uart_update_timeout); /** * uart_get_baud_rate - return baud rate for a particular port * @port: uart_port structure describing the port in question. * @termios: desired termios settings. * @old: old termios (or NULL) * @min: minimum acceptable baud rate * @max: maximum acceptable baud rate * * Decode the termios structure into a numeric baud rate, * taking account of the magic 38400 baud rate (with spd_* * flags), and mapping the %B0 rate to 9600 baud. * * If the new baud rate is invalid, try the old termios setting. * If it's still invalid, we try 9600 baud. * * Update the @termios structure to reflect the baud rate * we're actually going to be using. */unsigned intuart_get_baud_rate(struct uart_port *port, struct ktermios *termios, struct ktermios *old, unsigned int min, unsigned int max){ unsigned int try, baud, altbaud = 38400; upf_t flags = port->flags & UPF_SPD_MASK; if (flags == UPF_SPD_HI) altbaud = 57600; if (flags == UPF_SPD_VHI) altbaud = 115200; if (flags == UPF_SPD_SHI) altbaud = 230400; if (flags == UPF_SPD_WARP) altbaud = 460800; for (try = 0; try < 2; try++) { baud = tty_termios_baud_rate(termios); /* * The spd_hi, spd_vhi, spd_shi, spd_warp kludge... * Die! Die! Die! */ if (baud == 38400) baud = altbaud; /* * Special case: B0 rate. */ if (baud == 0) baud = 9600; if (baud >= min && baud <= max) return baud; /* * Oops, the quotient was zero. Try again with * the old baud rate if possible. */ termios->c_cflag &= ~CBAUD; if (old) { termios->c_cflag |= old->c_cflag & CBAUD; old = NULL; continue; } /* * As a last resort, if the quotient is zero, * default to 9600 bps */ termios->c_cflag |= B9600; } return 0;} EXPORT_SYMBOL(uart_get_baud_rate); /** * uart_get_divisor - return uart clock divisor * @port: uart_port structure describing the port. * @baud: desired baud rate * * Calculate the uart clock divisor for the port. */unsigned intuart_get_divisor(struct uart_port *port, unsigned int baud){ unsigned int quot; /* * Old custom speed handling. */ if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) quot = port->custom_divisor; else quot = (port->uartclk + (8 * baud)) / (16 * baud); return quot;} EXPORT_SYMBOL(uart_get_divisor); static voiduart_change_speed(struct uart_state *state, struct ktermios *old_termios){ struct tty_struct *tty = state->info->tty; struct uart_port *port = state->port; struct ktermios *termios; /* * If we have no tty, termios, or the port does not exist, * then we can't set the parameters for this port. */ if (!tty || !tty->termios || port->type == PORT_UNKNOWN) return; termios = tty->termios; /* * Set flags based on termios cflag */ if (termios->c_cflag & CRTSCTS) state->info->flags |= UIF_CTS_FLOW; else state->info->flags &= ~UIF_CTS_FLOW; if (termios->c_cflag & CLOCAL) state->info->flags &= ~UIF_CHECK_CD; else state->info->flags |= UIF_CHECK_CD; port->ops->set_termios(port, termios, old_termios);} static inline void__uart_put_char(struct uart_port *port, struct circ_buf *circ, unsigned char c){ unsigned long flags; if (!circ->buf) return; spin_lock_irqsave(&port->lock, flags); if (uart_circ_chars_free(circ) != 0) { circ->buf[circ->head] = c; circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1); } spin_unlock_irqrestore(&port->lock, flags);} static void uart_put_char(struct tty_struct *tty, unsigned char ch){ struct uart_state *state = tty->driver_data; __uart_put_char(state->port, &state->info->xmit, ch);} static void uart_flush_chars(struct tty_struct *tty){ uart_start(tty);} static intuart_write(struct tty_struct *tty, const unsigned char *buf, int count){ struct uart_state *state = tty->driver_data; struct uart_port *port; struct circ_buf *circ; unsigned long flags; int c, ret = 0; /* * This means you called this function _after_ the port was * closed. No cookie for you. */ if (!state || !state->info) { WARN_ON(1); return -EL3HLT; } Lines 1–500 of 2427. Load more
/* * linux/drivers/char/core.c * * Driver core for serial ports * * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. * * Copyright 1999 ARM Limited * Copyright (C) 2000-2001 Deep Blue Solutions Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/module.h> #include <linux/tty.h> #include <linux/slab.h> #include <linux/init.h> #include <linux/console.h> #include <linux/serial_core.h> #include <linux/smp_lock.h> #include <linux/device.h> #include <linux/serial.h> /* for serial_state and serial_icounter_struct */ #include <linux/delay.h> #include <linux/mutex.h> #include <asm/irq.h> #include <asm/uaccess.h> #undef DEBUG #ifdef DEBUG #define DPRINTK(x...) printk(x) #else #define DPRINTK(x...) do { } while (0) #endif /* * This is used to lock changes in serial line configuration. */ static DEFINE_MUTEX(port_mutex); /* * lockdep: port->lock is initialized in two places, but we * want only one lock-class: */ static struct lock_class_key port_lock_key; #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) #define uart_users(state) ((state)->count + ((state)->info ? (state)->info->blocked_open : 0)) #ifdef CONFIG_SERIAL_CORE_CONSOLE #define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line) #else #define uart_console(port) (0) #endif static void uart_change_speed(struct uart_state *state, struct ktermios *old_termios); static void uart_wait_until_sent(struct tty_struct *tty, int timeout); static void uart_change_pm(struct uart_state *state, int pm_state); /* * This routine is used by the interrupt handler to schedule processing in * the software interrupt portion of the driver. */ void uart_write_wakeup(struct uart_port *port) { struct uart_info *info = port->info; /* * This means you called this function _after_ the port was * closed. No cookie for you. */ BUG_ON(!info); tasklet_schedule(&info->tlet); } static void uart_stop(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; struct uart_port *port = state->port; unsigned long flags; spin_lock_irqsave(&port->lock, flags); port->ops->stop_tx(port); spin_unlock_irqrestore(&port->lock, flags); } static void __uart_start(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; struct uart_port *port = state->port; if (!uart_circ_empty(&state->info->xmit) && state->info->xmit.buf && !tty->stopped && !tty->hw_stopped) port->ops->start_tx(port); } static void uart_start(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; struct uart_port *port = state->port; unsigned long flags; spin_lock_irqsave(&port->lock, flags); __uart_start(tty); spin_unlock_irqrestore(&port->lock, flags); } static void uart_tasklet_action(unsigned long data) { struct uart_state *state = (struct uart_state *)data; tty_wakeup(state->info->tty); } static inline void uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear) { unsigned long flags; unsigned int old; spin_lock_irqsave(&port->lock, flags); old = port->mctrl; port->mctrl = (old & ~clear) | set; if (old != port->mctrl) port->ops->set_mctrl(port, port->mctrl); spin_unlock_irqrestore(&port->lock, flags); } #define uart_set_mctrl(port,set) uart_update_mctrl(port,set,0) #define uart_clear_mctrl(port,clear) uart_update_mctrl(port,0,clear) /* * Startup the port. This will be called once per open. All calls * will be serialised by the per-port semaphore. */ static int uart_startup(struct uart_state *state, int init_hw) { struct uart_info *info = state->info; struct uart_port *port = state->port; unsigned long page; int retval = 0; if (info->flags & UIF_INITIALIZED) return 0; /* * Set the TTY IO error marker - we will only clear this * once we have successfully opened the port. Also set * up the tty->alt_speed kludge */ set_bit(TTY_IO_ERROR, &info->tty->flags); if (port->type == PORT_UNKNOWN) return 0; /* * Initialise and allocate the transmit and temporary * buffer. */ if (!info->xmit.buf) { page = get_zeroed_page(GFP_KERNEL); if (!page) return -ENOMEM; info->xmit.buf = (unsigned char *) page; uart_circ_clear(&info->xmit); } retval = port->ops->startup(port); if (retval == 0) { if (init_hw) { /* * Initialise the hardware port settings. */ uart_change_speed(state, NULL); /* * Setup the RTS and DTR signals once the * port is open and ready to respond. */ if (info->tty->termios->c_cflag & CBAUD) uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR); } if (info->flags & UIF_CTS_FLOW) { spin_lock_irq(&port->lock); if (!(port->ops->get_mctrl(port) & TIOCM_CTS)) info->tty->hw_stopped = 1; spin_unlock_irq(&port->lock); } info->flags |= UIF_INITIALIZED; clear_bit(TTY_IO_ERROR, &info->tty->flags); } if (retval && capable(CAP_SYS_ADMIN)) retval = 0; return retval; } /* * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. Calls to * uart_shutdown are serialised by the per-port semaphore. */ static void uart_shutdown(struct uart_state *state) { struct uart_info *info = state->info; struct uart_port *port = state->port; /* * Set the TTY IO error marker */ if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); if (info->flags & UIF_INITIALIZED) { info->flags &= ~UIF_INITIALIZED; /* * Turn off DTR and RTS early. */ if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); /* * clear delta_msr_wait queue to avoid mem leaks: we may free * the irq here so the queue might never be woken up. Note * that we won't end up waiting on delta_msr_wait again since * any outstanding file descriptors should be pointing at * hung_up_tty_fops now. */ wake_up_interruptible(&info->delta_msr_wait); /* * Free the IRQ and disable the port. */ port->ops->shutdown(port); /* * Ensure that the IRQ handler isn't running on another CPU. */ synchronize_irq(port->irq); } /* * kill off our tasklet */ tasklet_kill(&info->tlet); /* * Free the transmit buffer page. */ if (info->xmit.buf) { free_page((unsigned long)info->xmit.buf); info->xmit.buf = NULL; } } /** * uart_update_timeout - update per-port FIFO timeout. * @port: uart_port structure describing the port * @cflag: termios cflag value * @baud: speed of the port * * Set the port FIFO timeout value. The @cflag value should * reflect the actual hardware settings. */ void uart_update_timeout(struct uart_port *port, unsigned int cflag, unsigned int baud) { unsigned int bits; /* byte size and parity */ switch (cflag & CSIZE) { case CS5: bits = 7; break; case CS6: bits = 8; break; case CS7: bits = 9; break; default: bits = 10; break; // CS8 } if (cflag & CSTOPB) bits++; if (cflag & PARENB) bits++; /* * The total number of bits to be transmitted in the fifo. */ bits = bits * port->fifosize; /* * Figure the timeout to send the above number of bits. * Add .02 seconds of slop */ port->timeout = (HZ * bits) / baud + HZ/50; } EXPORT_SYMBOL(uart_update_timeout); /** * uart_get_baud_rate - return baud rate for a particular port * @port: uart_port structure describing the port in question. * @termios: desired termios settings. * @old: old termios (or NULL) * @min: minimum acceptable baud rate * @max: maximum acceptable baud rate * * Decode the termios structure into a numeric baud rate, * taking account of the magic 38400 baud rate (with spd_* * flags), and mapping the %B0 rate to 9600 baud. * * If the new baud rate is invalid, try the old termios setting. * If it's still invalid, we try 9600 baud. * * Update the @termios structure to reflect the baud rate * we're actually going to be using. */ unsigned int uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, struct ktermios *old, unsigned int min, unsigned int max) { unsigned int try, baud, altbaud = 38400; upf_t flags = port->flags & UPF_SPD_MASK; if (flags == UPF_SPD_HI) altbaud = 57600; if (flags == UPF_SPD_VHI) altbaud = 115200; if (flags == UPF_SPD_SHI) altbaud = 230400; if (flags == UPF_SPD_WARP) altbaud = 460800; for (try = 0; try < 2; try++) { baud = tty_termios_baud_rate(termios); /* * The spd_hi, spd_vhi, spd_shi, spd_warp kludge... * Die! Die! Die! */ if (baud == 38400) baud = altbaud; /* * Special case: B0 rate. */ if (baud == 0) baud = 9600; if (baud >= min && baud <= max) return baud; /* * Oops, the quotient was zero. Try again with * the old baud rate if possible. */ termios->c_cflag &= ~CBAUD; if (old) { termios->c_cflag |= old->c_cflag & CBAUD; old = NULL; continue; } /* * As a last resort, if the quotient is zero, * default to 9600 bps */ termios->c_cflag |= B9600; } return 0; } EXPORT_SYMBOL(uart_get_baud_rate); /** * uart_get_divisor - return uart clock divisor * @port: uart_port structure describing the port. * @baud: desired baud rate * * Calculate the uart clock divisor for the port. */ unsigned int uart_get_divisor(struct uart_port *port, unsigned int baud) { unsigned int quot; /* * Old custom speed handling. */ if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) quot = port->custom_divisor; else quot = (port->uartclk + (8 * baud)) / (16 * baud); return quot; } EXPORT_SYMBOL(uart_get_divisor); static void uart_change_speed(struct uart_state *state, struct ktermios *old_termios) { struct tty_struct *tty = state->info->tty; struct uart_port *port = state->port; struct ktermios *termios; /* * If we have no tty, termios, or the port does not exist, * then we can't set the parameters for this port. */ if (!tty || !tty->termios || port->type == PORT_UNKNOWN) return; termios = tty->termios; /* * Set flags based on termios cflag */ if (termios->c_cflag & CRTSCTS) state->info->flags |= UIF_CTS_FLOW; else state->info->flags &= ~UIF_CTS_FLOW; if (termios->c_cflag & CLOCAL) state->info->flags &= ~UIF_CHECK_CD; else state->info->flags |= UIF_CHECK_CD; port->ops->set_termios(port, termios, old_termios); } static inline void __uart_put_char(struct uart_port *port, struct circ_buf *circ, unsigned char c) { unsigned long flags; if (!circ->buf) return; spin_lock_irqsave(&port->lock, flags); if (uart_circ_chars_free(circ) != 0) { circ->buf[circ->head] = c; circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1); } spin_unlock_irqrestore(&port->lock, flags); } static void uart_put_char(struct tty_struct *tty, unsigned char ch) { struct uart_state *state = tty->driver_data; __uart_put_char(state->port, &state->info->xmit, ch); } static void uart_flush_chars(struct tty_struct *tty) { uart_start(tty); } static int uart_write(struct tty_struct *tty, const unsigned char *buf, int count) { struct uart_state *state = tty->driver_data; struct uart_port *port; struct circ_buf *circ; unsigned long flags; int c, ret = 0; /* * This means you called this function _after_ the port was * closed. No cookie for you. */ if (!state || !state->info) { WARN_ON(1); return -EL3HLT; }