X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fserial%2Fserial_core.c;h=16c227d30016b7bc1981866bc74a3d3324cbe20a;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=1ac6c9d8144cdf047c87bc98d8e07315cea16204;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 1ac6c9d81..16c227d30 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -32,6 +32,7 @@ #include #include #include /* for serial_state and serial_icounter_struct */ +#include #include #include @@ -162,8 +163,6 @@ static int uart_startup(struct uart_state *state, int init_hw) return -ENOMEM; info->xmit.buf = (unsigned char *) page; - info->tmpbuf = info->xmit.buf + UART_XMIT_SIZE; - init_MUTEX(&info->tmpbuf_sem); uart_circ_clear(&info->xmit); } @@ -238,7 +237,6 @@ static void uart_shutdown(struct uart_state *state) if (info->xmit.buf) { free_page((unsigned long)info->xmit.buf); info->xmit.buf = NULL; - info->tmpbuf = NULL; } /* @@ -450,53 +448,30 @@ __uart_put_char(struct uart_port *port, struct circ_buf *circ, unsigned char c) spin_unlock_irqrestore(&port->lock, flags); } -static inline int -__uart_user_write(struct uart_port *port, struct circ_buf *circ, - const unsigned char __user *buf, int count) +static void uart_put_char(struct tty_struct *tty, unsigned char ch) { - unsigned long flags; - int c, ret = 0; - - if (down_interruptible(&port->info->tmpbuf_sem)) - return -EINTR; - - while (1) { - int c1; - c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); - if (count < c) - c = count; - if (c <= 0) - break; + struct uart_state *state = tty->driver_data; - c -= copy_from_user(port->info->tmpbuf, buf, c); - if (!c) { - if (!ret) - ret = -EFAULT; - break; - } - spin_lock_irqsave(&port->lock, flags); - c1 = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); - if (c1 < c) - c = c1; - memcpy(circ->buf + circ->head, port->info->tmpbuf, c); - circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1); - spin_unlock_irqrestore(&port->lock, flags); - buf += c; - count -= c; - ret += c; - } - up(&port->info->tmpbuf_sem); + __uart_put_char(state->port, &state->info->xmit, ch); +} - return ret; +static void uart_flush_chars(struct tty_struct *tty) +{ + uart_start(tty); } -static inline int -__uart_kern_write(struct uart_port *port, struct circ_buf *circ, - const unsigned char *buf, int count) +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 = state->port; + struct circ_buf *circ = &state->info->xmit; unsigned long flags; int c, ret = 0; + if (!circ->buf) + return 0; + spin_lock_irqsave(&port->lock, flags); while (1) { c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); @@ -512,38 +487,6 @@ __uart_kern_write(struct uart_port *port, struct circ_buf *circ, } spin_unlock_irqrestore(&port->lock, flags); - return ret; -} - -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, int from_user, const unsigned char * buf, - int count) -{ - struct uart_state *state = tty->driver_data; - int ret; - - if (!state->info->xmit.buf) - return 0; - - if (from_user) - ret = __uart_user_write(state->port, &state->info->xmit, - (const unsigned char __user *)buf, count); - else - ret = __uart_kern_write(state->port, &state->info->xmit, - buf, count); - uart_start(tty); return ret; } @@ -641,8 +584,10 @@ static int uart_get_info(struct uart_state *state, tmp.flags = port->flags; tmp.xmit_fifo_size = port->fifosize; tmp.baud_base = port->uartclk / 16; - tmp.close_delay = state->close_delay; - tmp.closing_wait = state->closing_wait; + 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; tmp.custom_divisor = port->custom_divisor; tmp.hub6 = port->hub6; tmp.io_type = port->iotype; @@ -660,8 +605,8 @@ static int uart_set_info(struct uart_state *state, struct serial_struct new_serial; struct uart_port *port = state->port; unsigned long new_port; - unsigned int change_irq, change_port, old_flags; - unsigned int old_custom_divisor; + unsigned int change_irq, change_port, old_flags, closing_wait; + unsigned int old_custom_divisor, close_delay; int retval = 0; if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) @@ -672,6 +617,9 @@ static int uart_set_info(struct uart_state *state, new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; new_serial.irq = irq_canonicalize(new_serial.irq); + close_delay = new_serial.close_delay * 10; + closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? + USF_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; /* * This semaphore protects state->count. It is also @@ -703,8 +651,8 @@ static int uart_set_info(struct uart_state *state, retval = -EPERM; if (change_irq || change_port || (new_serial.baud_base != port->uartclk / 16) || - (new_serial.close_delay != state->close_delay) || - (new_serial.closing_wait != state->closing_wait) || + (close_delay != state->close_delay) || + (closing_wait != state->closing_wait) || (new_serial.xmit_fifo_size != port->fifosize) || (((new_serial.flags ^ old_flags) & ~UPF_USR_MASK) != 0)) goto exit; @@ -808,8 +756,8 @@ static int uart_set_info(struct uart_state *state, port->flags = (port->flags & ~UPF_CHANGE_MASK) | (new_serial.flags & UPF_CHANGE_MASK); port->custom_divisor = new_serial.custom_divisor; - state->close_delay = new_serial.close_delay * HZ / 100; - state->closing_wait = new_serial.closing_wait * HZ / 100; + state->close_delay = close_delay; + state->closing_wait = closing_wait; port->fifosize = new_serial.xmit_fifo_size; if (state->info->tty) state->info->tty->low_latency = @@ -1248,7 +1196,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp) tty->closing = 1; if (state->closing_wait != USF_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, state->closing_wait); + tty_wait_until_sent(tty, msecs_to_jiffies(state->closing_wait)); /* * At this point, we stop accepting input. To do this, we @@ -1276,10 +1224,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp) state->info->tty = NULL; if (state->info->blocked_open) { - if (state->close_delay) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(state->close_delay); - } + if (state->close_delay) + msleep_interruptible(state->close_delay); } else if (!uart_console(port)) { uart_change_pm(state, 3); } @@ -1343,8 +1289,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout) * we wait. */ while (!port->ops->tx_empty(port)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(char_time); + msleep_interruptible(jiffies_to_msecs(char_time)); if (signal_pending(current)) break; if (time_after(jiffies, expire)) @@ -1901,10 +1846,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) * Wait for the transmitter to empty. */ while (!ops->tx_empty(port)) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(10*HZ/1000); + msleep(10); } - set_current_state(TASK_RUNNING); ops->shutdown(port); } @@ -1934,7 +1877,21 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) * Re-enable the console device after suspending. */ if (uart_console(port)) { - uart_change_speed(state, NULL); + struct termios termios; + + /* + * First try to use the console cflag setting. + */ + memset(&termios, 0, sizeof(struct termios)); + termios.c_cflag = port->cons->cflag; + + /* + * If that's unset, use the tty termios setting. + */ + if (state->info && state->info->tty && termios.c_cflag == 0) + termios = *state->info->tty->termios; + + port->ops->set_termios(port, &termios, NULL); console_start(port->cons); } @@ -2143,8 +2100,8 @@ int uart_register_driver(struct uart_driver *drv) for (i = 0; i < drv->nr; i++) { struct uart_state *state = drv->state + i; - state->close_delay = 5 * HZ / 10; - state->closing_wait = 30 * HZ; + state->close_delay = 500; /* .5 seconds */ + state->closing_wait = 30000; /* 30 seconds */ init_MUTEX(&state->sem); } @@ -2225,6 +2182,15 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) */ 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); + out: up(&port_sem);