#include <linux/slab.h>
#include <linux/init.h>
#include <linux/console.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/serial_core.h>
#include <linux/smp_lock.h>
#include <linux/device.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.
*/
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
-#define uart_users(state) ((state)->count + ((state)->info ? (state)->info->blocked_open : 0))
+#define uart_users(state) ((state)->count + (state)->info.port.blocked_open)
#ifdef CONFIG_SERIAL_CORE_CONSOLE
#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line)
#define uart_console(port) (0)
#endif
-static void uart_change_speed(struct uart_state *state, struct ktermios *old_termios);
+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);
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->port;
- if (!uart_circ_empty(&state->info->xmit) && state->info->xmit.buf &&
+ if (!uart_circ_empty(&state->info.xmit) && state->info.xmit.buf &&
!tty->stopped && !tty->hw_stopped)
port->ops->start_tx(port);
}
static void uart_tasklet_action(unsigned long data)
{
struct uart_state *state = (struct uart_state *)data;
- tty_wakeup(state->info->tty);
+ tty_wakeup(state->info.port.tty);
}
static inline void
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)
+#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.
+ * will be serialised by the per-port mutex.
*/
static int uart_startup(struct uart_state *state, int init_hw)
{
- struct uart_info *info = state->info;
+ struct uart_info *info = &state->info;
struct uart_port *port = state->port;
unsigned long page;
int retval = 0;
* once we have successfully opened the port. Also set
* up the tty->alt_speed kludge
*/
- set_bit(TTY_IO_ERROR, &info->tty->flags);
+ set_bit(TTY_IO_ERROR, &info->port.tty->flags);
if (port->type == PORT_UNKNOWN)
return 0;
* buffer.
*/
if (!info->xmit.buf) {
+ /* This is protected by the per port mutex */
page = get_zeroed_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
* Setup the RTS and DTR signals once the
* port is open and ready to respond.
*/
- if (info->tty->termios->c_cflag & CBAUD)
+ if (info->port.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;
+ info->port.tty->hw_stopped = 1;
spin_unlock_irq(&port->lock);
}
info->flags |= UIF_INITIALIZED;
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
}
if (retval && capable(CAP_SYS_ADMIN))
*/
static void uart_shutdown(struct uart_state *state)
{
- struct uart_info *info = state->info;
+ struct uart_info *info = &state->info;
struct uart_port *port = state->port;
+ struct tty_struct *tty = info->port.tty;
/*
* Set the TTY IO error marker
*/
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
+ if (tty)
+ set_bit(TTY_IO_ERROR, &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))
+ if (!tty || (tty->termios->c_cflag & HUPCL))
uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
/*
break;
default:
bits = 10;
- break; // CS8
+ break; /* CS8 */
}
if (cflag & CSTOPB)
* 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.
+ * we're actually going to be using. Don't do this for the case
+ * where B0 is requested ("hang up").
*/
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;
+ int hung_up = 0;
upf_t flags = port->flags & UPF_SPD_MASK;
if (flags == UPF_SPD_HI)
/*
* Special case: B0 rate.
*/
- if (baud == 0)
+ if (baud == 0) {
+ hung_up = 1;
baud = 9600;
+ }
if (baud >= min && baud <= max)
return baud;
*/
termios->c_cflag &= ~CBAUD;
if (old) {
- termios->c_cflag |= old->c_cflag & CBAUD;
+ baud = tty_termios_baud_rate(old);
+ if (!hung_up)
+ tty_termios_encode_baud_rate(termios,
+ baud, baud);
old = NULL;
continue;
}
* As a last resort, if the quotient is zero,
* default to 9600 bps
*/
- termios->c_cflag |= B9600;
+ if (!hung_up)
+ tty_termios_encode_baud_rate(termios, 9600, 9600);
}
return 0;
EXPORT_SYMBOL(uart_get_divisor);
+/* FIXME: Consistent locking policy */
static void
uart_change_speed(struct uart_state *state, struct ktermios *old_termios)
{
- struct tty_struct *tty = state->info->tty;
+ struct tty_struct *tty = state->info.port.tty;
struct uart_port *port = state->port;
struct ktermios *termios;
* Set flags based on termios cflag
*/
if (termios->c_cflag & CRTSCTS)
- state->info->flags |= UIF_CTS_FLOW;
+ state->info.flags |= UIF_CTS_FLOW;
else
- state->info->flags &= ~UIF_CTS_FLOW;
+ state->info.flags &= ~UIF_CTS_FLOW;
if (termios->c_cflag & CLOCAL)
- state->info->flags &= ~UIF_CHECK_CD;
+ state->info.flags &= ~UIF_CHECK_CD;
else
- state->info->flags |= UIF_CHECK_CD;
+ state->info.flags |= UIF_CHECK_CD;
port->ops->set_termios(port, termios, old_termios);
}
-static inline void
+static inline int
__uart_put_char(struct uart_port *port, struct circ_buf *circ, unsigned char c)
{
unsigned long flags;
+ int ret = 0;
if (!circ->buf)
- return;
+ return 0;
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);
+ ret = 1;
}
spin_unlock_irqrestore(&port->lock, flags);
+ return ret;
}
-static void uart_put_char(struct tty_struct *tty, unsigned char ch)
+static int 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);
+ return __uart_put_char(state->port, &state->info.xmit, ch);
}
static void uart_flush_chars(struct tty_struct *tty)
* This means you called this function _after_ the port was
* closed. No cookie for you.
*/
- if (!state || !state->info) {
+ if (!state) {
WARN_ON(1);
return -EL3HLT;
}
port = state->port;
- circ = &state->info->xmit;
+ circ = &state->info.xmit;
if (!circ->buf)
return 0;
static int uart_write_room(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
+ unsigned long flags;
+ int ret;
- return uart_circ_chars_free(&state->info->xmit);
+ spin_lock_irqsave(&state->port->lock, flags);
+ ret = uart_circ_chars_free(&state->info.xmit);
+ spin_unlock_irqrestore(&state->port->lock, flags);
+ return ret;
}
static int uart_chars_in_buffer(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
+ unsigned long flags;
+ int ret;
- return uart_circ_chars_pending(&state->info->xmit);
+ spin_lock_irqsave(&state->port->lock, flags);
+ ret = uart_circ_chars_pending(&state->info.xmit);
+ spin_unlock_irqrestore(&state->port->lock, flags);
+ return ret;
}
static void uart_flush_buffer(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
- struct uart_port *port = state->port;
+ struct uart_port *port;
unsigned long flags;
/*
* This means you called this function _after_ the port was
* closed. No cookie for you.
*/
- if (!state || !state->info) {
+ if (!state) {
WARN_ON(1);
return;
}
- DPRINTK("uart_flush_buffer(%d) called\n", tty->index);
+ port = state->port;
+ pr_debug("uart_flush_buffer(%d) called\n", tty->index);
spin_lock_irqsave(&port->lock, flags);
- uart_circ_clear(&state->info->xmit);
+ uart_circ_clear(&state->info.xmit);
+ if (port->ops->flush_buffer)
+ port->ops->flush_buffer(port);
spin_unlock_irqrestore(&port->lock, flags);
tty_wakeup(tty);
}
struct serial_struct tmp;
memset(&tmp, 0, sizeof(tmp));
+
+ /* Ensure the state we copy is consistent and no hardware changes
+ occur as we go */
+ mutex_lock(&state->mutex);
+
tmp.type = port->type;
tmp.line = port->line;
tmp.port = port->iobase;
tmp.close_delay = state->close_delay / 10;
tmp.closing_wait = state->closing_wait == USF_CLOSING_WAIT_NONE ?
ASYNC_CLOSING_WAIT_NONE :
- state->closing_wait / 10;
+ state->closing_wait / 10;
tmp.custom_divisor = port->custom_divisor;
tmp.hub6 = port->hub6;
tmp.io_type = port->iotype;
tmp.iomem_reg_shift = port->regshift;
- tmp.iomem_base = (void *)port->mapbase;
+ tmp.iomem_base = (void *)(unsigned long)port->mapbase;
+
+ mutex_unlock(&state->mutex);
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT;
*/
mutex_lock(&state->mutex);
- change_irq = new_serial.irq != port->irq;
+ change_irq = !(port->flags & UPF_FIXED_PORT)
+ && new_serial.irq != port->irq;
/*
* Since changing the 'type' of the port changes its resource
* allocations, we should treat type changes the same as
* IO port changes.
*/
- change_port = new_port != port->iobase ||
- (unsigned long)new_serial.iomem_base != port->mapbase ||
- new_serial.hub6 != port->hub6 ||
- new_serial.io_type != port->iotype ||
- new_serial.iomem_reg_shift != port->regshift ||
- new_serial.type != port->type;
+ change_port = !(port->flags & UPF_FIXED_PORT)
+ && (new_port != port->iobase ||
+ (unsigned long)new_serial.iomem_base != port->mapbase ||
+ new_serial.hub6 != port->hub6 ||
+ new_serial.io_type != port->iotype ||
+ new_serial.iomem_reg_shift != port->regshift ||
+ new_serial.type != port->type);
old_flags = port->flags;
new_flags = new_serial.flags;
if (port->ops->verify_port)
retval = port->ops->verify_port(port, &new_serial);
- if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) ||
+ if ((new_serial.irq >= nr_irqs) || (new_serial.irq < 0) ||
(new_serial.baud_base < 9600))
retval = -EINVAL;
* We failed anyway.
*/
retval = -EBUSY;
- goto exit; // Added to return the correct error -Ram Gupta
+ /* Added to return the correct error -Ram Gupta */
+ goto exit;
}
}
- port->irq = new_serial.irq;
- port->uartclk = new_serial.baud_base * 16;
+ if (change_irq)
+ port->irq = new_serial.irq;
+ if (!(port->flags & UPF_FIXED_PORT))
+ port->uartclk = new_serial.baud_base * 16;
port->flags = (port->flags & ~UPF_CHANGE_MASK) |
(new_flags & UPF_CHANGE_MASK);
port->custom_divisor = new_serial.custom_divisor;
state->closing_wait = closing_wait;
if (new_serial.xmit_fifo_size)
port->fifosize = new_serial.xmit_fifo_size;
- if (state->info->tty)
- state->info->tty->low_latency =
+ if (state->info.port.tty)
+ state->info.port.tty->low_latency =
(port->flags & UPF_LOW_LATENCY) ? 1 : 0;
check_and_exit:
retval = 0;
if (port->type == PORT_UNKNOWN)
goto exit;
- if (state->info->flags & UIF_INITIALIZED) {
+ if (state->info.flags & UIF_INITIALIZED) {
if (((old_flags ^ port->flags) & UPF_SPD_MASK) ||
old_custom_divisor != port->custom_divisor) {
/*
printk(KERN_NOTICE
"%s sets custom speed on %s. This "
"is deprecated.\n", current->comm,
- tty_name(state->info->tty, buf));
+ tty_name(state->info.port.tty, buf));
}
uart_change_speed(state, NULL);
}
* interrupt happens).
*/
if (port->x_char ||
- ((uart_circ_chars_pending(&state->info->xmit) > 0) &&
- !state->info->tty->stopped && !state->info->tty->hw_stopped))
+ ((uart_circ_chars_pending(&state->info.xmit) > 0) &&
+ !state->info.port.tty->stopped && !state->info.port.tty->hw_stopped))
result &= ~TIOCSER_TEMT;
-
+
return put_user(result, value);
}
return ret;
}
-static void uart_break_ctl(struct tty_struct *tty, int break_state)
+static int uart_break_ctl(struct tty_struct *tty, int break_state)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->port;
- BUG_ON(!kernel_locked());
-
mutex_lock(&state->mutex);
if (port->type != PORT_UNKNOWN)
port->ops->break_ctl(port, break_state);
mutex_unlock(&state->mutex);
+ return 0;
}
static int uart_do_autoconfig(struct uart_state *state)
port->ops->enable_ms(port);
spin_unlock_irq(&port->lock);
- add_wait_queue(&state->info->delta_msr_wait, &wait);
+ add_wait_queue(&state->info.delta_msr_wait, &wait);
for (;;) {
spin_lock_irq(&port->lock);
memcpy(&cnow, &port->icount, sizeof(struct uart_icount));
((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
- ret = 0;
- break;
+ ret = 0;
+ break;
}
schedule();
}
current->state = TASK_RUNNING;
- remove_wait_queue(&state->info->delta_msr_wait, &wait);
+ remove_wait_queue(&state->info.delta_msr_wait, &wait);
return ret;
}
}
/*
- * Called via sys_ioctl under the BKL. We can use spin_lock_irq() here.
+ * Called via sys_ioctl. We can use spin_lock_irq() here.
*/
static int
uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
void __user *uarg = (void __user *)arg;
int ret = -ENOIOCTLCMD;
- BUG_ON(!kernel_locked());
/*
* These ioctls don't rely on the hardware to be present.
break;
}
}
- out_up:
+out_up:
mutex_unlock(&state->mutex);
- out:
+out:
return ret;
}
-static void uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+static void uart_set_ldisc(struct tty_struct *tty)
+{
+ struct uart_state *state = tty->driver_data;
+ struct uart_port *port = state->port;
+
+ if (port->ops->set_ldisc)
+ port->ops->set_ldisc(port);
+}
+
+static void uart_set_termios(struct tty_struct *tty,
+ struct ktermios *old_termios)
{
struct uart_state *state = tty->driver_data;
unsigned long flags;
unsigned int cflag = tty->termios->c_cflag;
- BUG_ON(!kernel_locked());
/*
* These are the bits that are used to setup various
- * flags in the low level driver.
+ * flags in the low level driver. We can ignore the Bfoo
+ * bits in c_cflag; c_[io]speed will always be set
+ * appropriately by set_termios() in tty_ioctl.c
*/
#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
if ((cflag ^ old_termios->c_cflag) == 0 &&
- RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0)
+ tty->termios->c_ospeed == old_termios->c_ospeed &&
+ tty->termios->c_ispeed == old_termios->c_ispeed &&
+ RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) {
return;
+ }
uart_change_speed(state, old_termios);
}
spin_unlock_irqrestore(&state->port->lock, flags);
}
-
#if 0
/*
* No need to wake up processes in open wait, since they
*/
if (!(old_termios->c_cflag & CLOCAL) &&
(tty->termios->c_cflag & CLOCAL))
- wake_up_interruptible(&state->info->open_wait);
+ wake_up_interruptible(&info->port.open_wait);
#endif
}
{
struct uart_state *state = tty->driver_data;
struct uart_port *port;
-
+
BUG_ON(!kernel_locked());
if (!state || !state->port)
port = state->port;
- DPRINTK("uart_close(%d) called\n", port->line);
+ pr_debug("uart_close(%d) called\n", port->line);
mutex_lock(&state->mutex);
* At this point, we stop accepting input. To do this, we
* disable the receive line status interrupts.
*/
- if (state->info->flags & UIF_INITIALIZED) {
+ if (state->info.flags & UIF_INITIALIZED) {
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
port->ops->stop_rx(port);
uart_shutdown(state);
uart_flush_buffer(tty);
- tty_ldisc_flush(tty);
-
+ tty_ldisc_flush(tty);
+
tty->closing = 0;
- state->info->tty = NULL;
+ state->info.port.tty = NULL;
- if (state->info->blocked_open) {
+ if (state->info.port.blocked_open) {
if (state->close_delay)
msleep_interruptible(state->close_delay);
} else if (!uart_console(port)) {
/*
* Wake up anyone trying to open this port.
*/
- state->info->flags &= ~UIF_NORMAL_ACTIVE;
- wake_up_interruptible(&state->info->open_wait);
+ state->info.flags &= ~UIF_NORMAL_ACTIVE;
+ wake_up_interruptible(&state->info.port.open_wait);
done:
mutex_unlock(&state->mutex);
struct uart_port *port = state->port;
unsigned long char_time, expire;
- BUG_ON(!kernel_locked());
-
if (port->type == PORT_UNKNOWN || port->fifosize == 0)
return;
+ lock_kernel();
+
/*
* Set the check interval to be 1/5 of the estimated time to
* send a single character, and make it at least 1. The check
expire = jiffies + timeout;
- DPRINTK("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n",
- port->line, jiffies, expire);
+ pr_debug("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n",
+ port->line, jiffies, expire);
/*
* Check whether the transmitter is empty every 'char_time'.
break;
}
set_current_state(TASK_RUNNING); /* might not be needed */
+ unlock_kernel();
}
/*
static void uart_hangup(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
+ struct uart_info *info = &state->info;
BUG_ON(!kernel_locked());
- DPRINTK("uart_hangup(%d)\n", state->port->line);
+ pr_debug("uart_hangup(%d)\n", state->port->line);
mutex_lock(&state->mutex);
- if (state->info && state->info->flags & UIF_NORMAL_ACTIVE) {
+ if (info->flags & UIF_NORMAL_ACTIVE) {
uart_flush_buffer(tty);
uart_shutdown(state);
state->count = 0;
- state->info->flags &= ~UIF_NORMAL_ACTIVE;
- state->info->tty = NULL;
- wake_up_interruptible(&state->info->open_wait);
- wake_up_interruptible(&state->info->delta_msr_wait);
+ info->flags &= ~UIF_NORMAL_ACTIVE;
+ info->port.tty = NULL;
+ wake_up_interruptible(&info->port.open_wait);
+ wake_up_interruptible(&info->delta_msr_wait);
}
mutex_unlock(&state->mutex);
}
*/
static void uart_update_termios(struct uart_state *state)
{
- struct tty_struct *tty = state->info->tty;
+ struct tty_struct *tty = state->info.port.tty;
struct uart_port *port = state->port;
if (uart_console(port) && port->cons->cflag) {
uart_block_til_ready(struct file *filp, struct uart_state *state)
{
DECLARE_WAITQUEUE(wait, current);
- struct uart_info *info = state->info;
+ struct uart_info *info = &state->info;
struct uart_port *port = state->port;
unsigned int mctrl;
- info->blocked_open++;
+ info->port.blocked_open++;
state->count--;
- add_wait_queue(&info->open_wait, &wait);
+ add_wait_queue(&info->port.open_wait, &wait);
while (1) {
set_current_state(TASK_INTERRUPTIBLE);
/*
* If we have been hung up, tell userspace/restart open.
*/
- if (tty_hung_up_p(filp) || info->tty == NULL)
+ if (tty_hung_up_p(filp) || info->port.tty == NULL)
break;
/*
* have set TTY_IO_ERROR for a non-existant port.
*/
if ((filp->f_flags & O_NONBLOCK) ||
- (info->tty->termios->c_cflag & CLOCAL) ||
- (info->tty->flags & (1 << TTY_IO_ERROR))) {
+ (info->port.tty->termios->c_cflag & CLOCAL) ||
+ (info->port.tty->flags & (1 << TTY_IO_ERROR)))
break;
- }
/*
* Set DTR to allow modem to know we're waiting. Do
* not set RTS here - we want to make sure we catch
* the data from the modem.
*/
- if (info->tty->termios->c_cflag & CBAUD)
+ if (info->port.tty->termios->c_cflag & CBAUD)
uart_set_mctrl(port, TIOCM_DTR);
/*
break;
}
set_current_state(TASK_RUNNING);
- remove_wait_queue(&info->open_wait, &wait);
+ remove_wait_queue(&info->port.open_wait, &wait);
state->count++;
- info->blocked_open--;
+ info->port.blocked_open--;
if (signal_pending(current))
return -ERESTARTSYS;
- if (!info->tty || tty_hung_up_p(filp))
+ if (!info->port.tty || tty_hung_up_p(filp))
return -EAGAIN;
return 0;
ret = -ENXIO;
goto err_unlock;
}
-
- if (!state->info) {
- state->info = kzalloc(sizeof(struct uart_info), GFP_KERNEL);
- if (state->info) {
- init_waitqueue_head(&state->info->open_wait);
- init_waitqueue_head(&state->info->delta_msr_wait);
-
- /*
- * Link the info into the other structures.
- */
- state->port->info = state->info;
-
- tasklet_init(&state->info->tlet, uart_tasklet_action,
- (unsigned long)state);
- } else {
- ret = -ENOMEM;
- goto err_unlock;
- }
- }
return state;
err_unlock:
}
/*
- * In 2.4.5, calls to uart_open are serialised by the BKL in
- * linux/fs/devices.c:chrdev_open()
+ * calls to uart_open are serialised by the BKL in
+ * fs/char_dev.c:chrdev_open()
* Note that if this fails, then uart_close() _will_ be called.
*
* In time, we want to scrap the "opening nonpresent ports"
int retval, line = tty->index;
BUG_ON(!kernel_locked());
- DPRINTK("uart_open(%d) called\n", line);
+ pr_debug("uart_open(%d) called\n", line);
/*
* tty->driver->num won't change, so we won't fail here with
* be re-entered while allocating the info structure, or while we
* request any IRQs that the driver may need. This also has the nice
* side-effect that it delays the action of uart_hangup, so we can
- * guarantee that info->tty will always contain something reasonable.
+ * guarantee that info->port.tty will always contain something reasonable.
*/
state = uart_get(drv, line);
if (IS_ERR(state)) {
* Any failures from here onwards should not touch the count.
*/
tty->driver_data = state;
+ state->port->info = &state->info;
tty->low_latency = (state->port->flags & UPF_LOW_LATENCY) ? 1 : 0;
tty->alt_speed = 0;
- state->info->tty = tty;
+ state->info.port.tty = tty;
/*
* If the port is in the middle of closing, bail out now.
/*
* If this is the first open to succeed, adjust things to suit.
*/
- if (retval == 0 && !(state->info->flags & UIF_NORMAL_ACTIVE)) {
- state->info->flags |= UIF_NORMAL_ACTIVE;
+ if (retval == 0 && !(state->info.flags & UIF_NORMAL_ACTIVE)) {
+ state->info.flags |= UIF_NORMAL_ACTIVE;
uart_update_termios(state);
}
#ifdef CONFIG_PROC_FS
-static int uart_line_info(char *buf, struct uart_driver *drv, int i)
+static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
{
struct uart_state *state = drv->state + i;
int pm_state;
struct uart_port *port = state->port;
char stat_buf[32];
unsigned int status;
- int mmio, ret;
+ int mmio;
if (!port)
- return 0;
+ return;
mmio = port->iotype >= UPIO_MEM;
- ret = sprintf(buf, "%d: uart:%s %s%08lX irq:%d",
+ seq_printf(m, "%d: uart:%s %s%08llX irq:%d",
port->line, uart_type(port),
mmio ? "mmio:0x" : "port:",
- mmio ? port->mapbase : (unsigned long) port->iobase,
+ mmio ? (unsigned long long)port->mapbase
+ : (unsigned long long) port->iobase,
port->irq);
if (port->type == PORT_UNKNOWN) {
- strcat(buf, "\n");
- return ret + 1;
+ seq_putc(m, '\n');
+ return;
}
- if(capable(CAP_SYS_ADMIN))
- {
+ if (capable(CAP_SYS_ADMIN)) {
mutex_lock(&state->mutex);
pm_state = state->pm_state;
if (pm_state)
uart_change_pm(state, pm_state);
mutex_unlock(&state->mutex);
- ret += sprintf(buf + ret, " tx:%d rx:%d",
+ seq_printf(m, " tx:%d rx:%d",
port->icount.tx, port->icount.rx);
if (port->icount.frame)
- ret += sprintf(buf + ret, " fe:%d",
+ seq_printf(m, " fe:%d",
port->icount.frame);
if (port->icount.parity)
- ret += sprintf(buf + ret, " pe:%d",
+ seq_printf(m, " pe:%d",
port->icount.parity);
if (port->icount.brk)
- ret += sprintf(buf + ret, " brk:%d",
+ seq_printf(m, " brk:%d",
port->icount.brk);
if (port->icount.overrun)
- ret += sprintf(buf + ret, " oe:%d",
+ seq_printf(m, " oe:%d",
port->icount.overrun);
-
-#define INFOBIT(bit,str) \
+
+#define INFOBIT(bit, str) \
if (port->mctrl & (bit)) \
strncat(stat_buf, (str), sizeof(stat_buf) - \
strlen(stat_buf) - 2)
-#define STATBIT(bit,str) \
+#define STATBIT(bit, str) \
if (status & (bit)) \
strncat(stat_buf, (str), sizeof(stat_buf) - \
strlen(stat_buf) - 2)
STATBIT(TIOCM_RNG, "|RI");
if (stat_buf[0])
stat_buf[0] = ' ';
- strcat(stat_buf, "\n");
-
- ret += sprintf(buf + ret, stat_buf);
- } else {
- strcat(buf, "\n");
- ret++;
+
+ seq_puts(m, stat_buf);
}
+ seq_putc(m, '\n');
#undef STATBIT
#undef INFOBIT
- return ret;
}
-static int uart_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int uart_proc_show(struct seq_file *m, void *v)
{
- struct tty_driver *ttydrv = data;
+ struct tty_driver *ttydrv = m->private;
struct uart_driver *drv = ttydrv->driver_state;
- int i, len = 0, l;
- off_t begin = 0;
+ int i;
- len += sprintf(page, "serinfo:1.0 driver%s%s revision:%s\n",
+ seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n",
"", "", "");
- for (i = 0; i < drv->nr && len < PAGE_SIZE - 96; i++) {
- l = uart_line_info(page + len, drv, i);
- len += l;
- if (len + begin > off + count)
- goto done;
- if (len + begin < off) {
- begin += len;
- len = 0;
- }
- }
- *eof = 1;
- done:
- if (off >= len + begin)
- return 0;
- *start = page + (off - begin);
- return (count < begin + len - off) ? count : (begin + len - off);
+ for (i = 0; i < drv->nr; i++)
+ uart_line_info(m, drv, i);
+ return 0;
+}
+
+static int uart_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, uart_proc_show, PDE(inode)->data);
}
+
+static const struct file_operations uart_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = uart_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
#endif
-#ifdef CONFIG_SERIAL_CORE_CONSOLE
+#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
/*
* uart_console_write - write a console message to a serial port
* @port: the port to write the message
* options. The format of the string is <baud><parity><bits><flow>,
* eg: 115200n8r
*/
-void __init
+void
uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow)
{
char *s = options;
if (*s)
*flow = *s;
}
+EXPORT_SYMBOL_GPL(uart_parse_options);
struct baud_rates {
unsigned int rate;
* @bits: number of data bits
* @flow: flow control character - 'r' (rts)
*/
-int __init
+int
uart_set_options(struct uart_port *port, struct console *co,
int baud, int parity, int bits, int flow)
{
struct ktermios termios;
+ static struct ktermios dummy;
int i;
/*
if (flow == 'r')
termios.c_cflag |= CRTSCTS;
- port->ops->set_termios(port, &termios, NULL);
- co->cflag = termios.c_cflag;
+ /*
+ * some uarts on other side don't support no flow control.
+ * So we set * DTR in host uart to make them happy
+ */
+ port->mctrl |= TIOCM_DTR;
+
+ port->ops->set_termios(port, &termios, &dummy);
+ /*
+ * Allow the setting of the UART parameters with a NULL console
+ * too:
+ */
+ if (co)
+ co->cflag = termios.c_cflag;
return 0;
}
+EXPORT_SYMBOL_GPL(uart_set_options);
#endif /* CONFIG_SERIAL_CORE_CONSOLE */
static void uart_change_pm(struct uart_state *state, int pm_state)
}
}
+struct uart_match {
+ struct uart_port *port;
+ struct uart_driver *driver;
+};
+
+static int serial_match_port(struct device *dev, void *data)
+{
+ struct uart_match *match = data;
+ struct tty_driver *tty_drv = match->driver->tty_driver;
+ dev_t devt = MKDEV(tty_drv->major, tty_drv->minor_start) +
+ match->port->line;
+
+ return dev->devt == devt; /* Actually, only one tty per port */
+}
+
int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
{
struct uart_state *state = drv->state + port->line;
+ struct device *tty_dev;
+ struct uart_match match = {port, drv};
mutex_lock(&state->mutex);
-#ifdef CONFIG_DISABLE_CONSOLE_SUSPEND
- if (uart_console(port)) {
+ if (!console_suspend_enabled && uart_console(port)) {
+ /* we're going to avoid suspending serial console */
mutex_unlock(&state->mutex);
return 0;
}
-#endif
- if (state->info && state->info->flags & UIF_INITIALIZED) {
+ tty_dev = device_find_child(port->dev, &match, serial_match_port);
+ if (device_may_wakeup(tty_dev)) {
+ enable_irq_wake(port->irq);
+ put_device(tty_dev);
+ mutex_unlock(&state->mutex);
+ return 0;
+ }
+ port->suspended = 1;
+
+ if (state->info.flags & UIF_INITIALIZED) {
const struct uart_ops *ops = port->ops;
+ int tries;
- state->info->flags = (state->info->flags & ~UIF_INITIALIZED)
+ state->info.flags = (state->info.flags & ~UIF_INITIALIZED)
| UIF_SUSPENDED;
spin_lock_irq(&port->lock);
/*
* Wait for the transmitter to empty.
*/
- while (!ops->tx_empty(port)) {
+ for (tries = 3; !ops->tx_empty(port) && tries; tries--)
msleep(10);
- }
+ if (!tries)
+ printk(KERN_ERR "%s%s%s%d: Unable to drain "
+ "transmitter\n",
+ port->dev ? dev_name(port->dev) : "",
+ port->dev ? ": " : "",
+ drv->dev_name,
+ drv->tty_driver->name_base + port->line);
ops->shutdown(port);
}
int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
{
struct uart_state *state = drv->state + port->line;
+ struct device *tty_dev;
+ struct uart_match match = {port, drv};
mutex_lock(&state->mutex);
-#ifdef CONFIG_DISABLE_CONSOLE_SUSPEND
- if (uart_console(port)) {
+ if (!console_suspend_enabled && uart_console(port)) {
+ /* no need to resume serial console, it wasn't suspended */
mutex_unlock(&state->mutex);
return 0;
}
-#endif
- uart_change_pm(state, 0);
+ tty_dev = device_find_child(port->dev, &match, serial_match_port);
+ if (!port->suspended && device_may_wakeup(tty_dev)) {
+ disable_irq_wake(port->irq);
+ mutex_unlock(&state->mutex);
+ return 0;
+ }
+ port->suspended = 0;
/*
* Re-enable the console device after suspending.
/*
* If that's unset, use the tty termios setting.
*/
- if (state->info && state->info->tty && termios.c_cflag == 0)
- termios = *state->info->tty->termios;
+ if (state->info.port.tty && termios.c_cflag == 0)
+ termios = *state->info.port.tty->termios;
+ uart_change_pm(state, 0);
port->ops->set_termios(port, &termios, NULL);
console_start(port->cons);
}
- if (state->info && state->info->flags & UIF_SUSPENDED) {
+ if (state->info.flags & UIF_SUSPENDED) {
const struct uart_ops *ops = port->ops;
int ret;
+ uart_change_pm(state, 0);
+ spin_lock_irq(&port->lock);
ops->set_mctrl(port, 0);
+ spin_unlock_irq(&port->lock);
ret = ops->startup(port);
if (ret == 0) {
uart_change_speed(state, NULL);
ops->set_mctrl(port, port->mctrl);
ops->start_tx(port);
spin_unlock_irq(&port->lock);
- state->info->flags |= UIF_INITIALIZED;
+ state->info.flags |= UIF_INITIALIZED;
} else {
/*
* Failed to resume - maybe hardware went away?
uart_shutdown(state);
}
- state->info->flags &= ~UIF_SUSPENDED;
+ state->info.flags &= ~UIF_SUSPENDED;
}
mutex_unlock(&state->mutex);
switch (port->iotype) {
case UPIO_PORT:
- snprintf(address, sizeof(address),
- "I/O 0x%x", port->iobase);
+ snprintf(address, sizeof(address), "I/O 0x%lx", port->iobase);
break;
case UPIO_HUB6:
snprintf(address, sizeof(address),
- "I/O 0x%x offset 0x%x", port->iobase, port->hub6);
+ "I/O 0x%lx offset 0x%x", port->iobase, port->hub6);
break;
case UPIO_MEM:
case UPIO_MEM32:
case UPIO_AU:
case UPIO_TSI:
+ case UPIO_DWAPB:
snprintf(address, sizeof(address),
- "MMIO 0x%lx", port->mapbase);
+ "MMIO 0x%llx", (unsigned long long)port->mapbase);
break;
default:
strlcpy(address, "*unknown*", sizeof(address));
}
printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n",
- port->dev ? port->dev->bus_id : "",
+ port->dev ? dev_name(port->dev) : "",
port->dev ? ": " : "",
- drv->dev_name, port->line, address, port->irq, uart_type(port));
+ drv->dev_name,
+ drv->tty_driver->name_base + port->line,
+ address, port->irq, uart_type(port));
}
static void
* Now do the auto configuration stuff. Note that config_port
* is expected to claim the resources and map the port for us.
*/
- flags = UART_CONFIG_TYPE;
+ flags = 0;
if (port->flags & UPF_AUTO_IRQ)
flags |= UART_CONFIG_IRQ;
if (port->flags & UPF_BOOT_AUTOCONF) {
- port->type = PORT_UNKNOWN;
+ if (!(port->flags & UPF_FIXED_TYPE)) {
+ port->type = PORT_UNKNOWN;
+ flags |= UART_CONFIG_TYPE;
+ }
port->ops->config_port(port, flags);
}
/*
* Ensure that the modem control lines are de-activated.
+ * keep the DTR setting that is set in uart_set_options()
* We probably don't need a spinlock around this, but
*/
spin_lock_irqsave(&port->lock, flags);
- port->ops->set_mctrl(port, 0);
+ port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR);
spin_unlock_irqrestore(&port->lock, flags);
/*
+ * If this driver supports console, and it hasn't been
+ * successfully registered yet, try to re-register it.
+ * It may be that the port was not available.
+ */
+ if (port->cons && !(port->cons->flags & CON_ENABLED))
+ register_console(port->cons);
+
+ /*
* Power down all ports by default, except the
* console if we have one.
*/
}
}
+#ifdef CONFIG_CONSOLE_POLL
+
+static int uart_poll_init(struct tty_driver *driver, int line, char *options)
+{
+ struct uart_driver *drv = driver->driver_state;
+ struct uart_state *state = drv->state + line;
+ struct uart_port *port;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (!state || !state->port)
+ return -1;
+
+ port = state->port;
+ if (!(port->ops->poll_get_char && port->ops->poll_put_char))
+ return -1;
+
+ if (options) {
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ return uart_set_options(port, NULL, baud, parity, bits, flow);
+ }
+
+ return 0;
+}
+
+static int uart_poll_get_char(struct tty_driver *driver, int line)
+{
+ struct uart_driver *drv = driver->driver_state;
+ struct uart_state *state = drv->state + line;
+ struct uart_port *port;
+
+ if (!state || !state->port)
+ return -1;
+
+ port = state->port;
+ return port->ops->poll_get_char(port);
+}
+
+static void uart_poll_put_char(struct tty_driver *driver, int line, char ch)
+{
+ struct uart_driver *drv = driver->driver_state;
+ struct uart_state *state = drv->state + line;
+ struct uart_port *port;
+
+ if (!state || !state->port)
+ return;
+
+ port = state->port;
+ port->ops->poll_put_char(port, ch);
+}
+#endif
+
static const struct tty_operations uart_ops = {
.open = uart_open,
.close = uart_close,
.unthrottle = uart_unthrottle,
.send_xchar = uart_send_xchar,
.set_termios = uart_set_termios,
+ .set_ldisc = uart_set_ldisc,
.stop = uart_stop,
.start = uart_start,
.hangup = uart_hangup,
.break_ctl = uart_break_ctl,
.wait_until_sent= uart_wait_until_sent,
#ifdef CONFIG_PROC_FS
- .read_proc = uart_read_proc,
+ .proc_fops = &uart_proc_fops,
#endif
.tiocmget = uart_tiocmget,
.tiocmset = uart_tiocmset,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_init = uart_poll_init,
+ .poll_get_char = uart_poll_get_char,
+ .poll_put_char = uart_poll_put_char,
+#endif
};
/**
state->close_delay = 500; /* .5 seconds */
state->closing_wait = 30000; /* 30 seconds */
-
mutex_init(&state->mutex);
+
+ tty_port_init(&state->info.port);
+ init_waitqueue_head(&state->info.delta_msr_wait);
+ tasklet_init(&state->info.tlet, uart_tasklet_action,
+ (unsigned long)state);
}
retval = tty_register_driver(normal);
{
struct uart_state *state;
int ret = 0;
+ struct device *tty_dev;
BUG_ON(in_interrupt());
}
state->port = port;
+ state->pm_state = -1;
port->cons = drv->cons;
- port->info = state->info;
+ port->info = &state->info;
/*
* If this port is a console, then the spinlock is already
* Register the port whether it's detected or not. This allows
* setserial to be used to alter this ports parameters.
*/
- tty_register_device(drv->tty_driver, port->line, port->dev);
-
- /*
- * If this driver supports console, and it hasn't been
- * successfully registered yet, try to re-register it.
- * It may be that the port was not available.
- */
- if (port->type != PORT_UNKNOWN &&
- port->cons && !(port->cons->flags & CON_ENABLED))
- register_console(port->cons);
+ tty_dev = tty_register_device(drv->tty_driver, port->line, port->dev);
+ if (likely(!IS_ERR(tty_dev))) {
+ device_init_wakeup(tty_dev, 1);
+ device_set_wakeup_enable(tty_dev, 0);
+ } else
+ printk(KERN_ERR "Cannot register tty device on line %d\n",
+ port->line);
/*
* Ensure UPF_DEAD is not set.
*/
tty_unregister_device(drv->tty_driver, port->line);
- info = state->info;
- if (info && info->tty)
- tty_vhangup(info->tty);
-
- /*
- * All users of this port should now be disconnected from
- * this driver, and the port shut down. We should be the
- * only thread fiddling with this port from now on.
- */
- state->info = NULL;
+ info = &state->info;
+ if (info && info->port.tty)
+ tty_vhangup(info->port.tty);
/*
* Free the port IO and memory resources, if any.
/*
* Kill the tasklet, and free resources.
*/
- if (info) {
+ if (info)
tasklet_kill(&info->tlet);
- kfree(info);
- }
state->port = NULL;
mutex_unlock(&port_mutex);
case UPIO_MEM32:
case UPIO_AU:
case UPIO_TSI:
+ case UPIO_DWAPB:
return (port1->mapbase == port2->mapbase);
}
return 0;