X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fserial%2Fserial_core.c;h=16c227d30016b7bc1981866bc74a3d3324cbe20a;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=66bb3cfb22f06f800add7e251258170fbe3413be;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 66bb3cfb2..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 @@ -107,15 +108,7 @@ static void uart_start(struct tty_struct *tty) static void uart_tasklet_action(unsigned long data) { struct uart_state *state = (struct uart_state *)data; - struct tty_struct *tty; - - tty = state->info->tty; - if (tty) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - tty->ldisc.write_wakeup(tty); - wake_up_interruptible(&tty->write_wait); - } + tty_wakeup(state->info->tty); } static inline void @@ -170,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); } @@ -246,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; } /* @@ -403,7 +393,7 @@ uart_get_divisor(struct uart_port *port, unsigned int baud) if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) quot = port->custom_divisor; else - quot = port->uartclk / (16 * baud); + quot = (port->uartclk + (8 * baud)) / (16 * baud); return quot; } @@ -458,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 *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); @@ -520,36 +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, buf, count); - else - ret = __uart_kern_write(state->port, &state->info->xmit, buf, count); - uart_start(tty); return ret; } @@ -579,10 +516,7 @@ static void uart_flush_buffer(struct tty_struct *tty) spin_lock_irqsave(&port->lock, flags); uart_circ_clear(&state->info->xmit); spin_unlock_irqrestore(&port->lock, flags); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* @@ -634,7 +568,8 @@ static void uart_unthrottle(struct tty_struct *tty) uart_set_mctrl(port, TIOCM_RTS); } -static int uart_get_info(struct uart_state *state, struct serial_struct *retinfo) +static int uart_get_info(struct uart_state *state, + struct serial_struct __user *retinfo) { struct uart_port *port = state->port; struct serial_struct tmp; @@ -649,8 +584,10 @@ static int uart_get_info(struct uart_state *state, struct serial_struct *retinfo 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; @@ -662,14 +599,14 @@ static int uart_get_info(struct uart_state *state, struct serial_struct *retinfo return 0; } -static int -uart_set_info(struct uart_state *state, struct serial_struct *newinfo) +static int uart_set_info(struct uart_state *state, + struct serial_struct __user *newinfo) { 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))) @@ -680,6 +617,9 @@ uart_set_info(struct uart_state *state, struct serial_struct *newinfo) 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 @@ -711,8 +651,8 @@ uart_set_info(struct uart_state *state, struct serial_struct *newinfo) 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; @@ -816,8 +756,8 @@ uart_set_info(struct uart_state *state, struct serial_struct *newinfo) 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 = @@ -856,7 +796,8 @@ uart_set_info(struct uart_state *state, struct serial_struct *newinfo) * uart_get_lsr_info - get line status register info. * Note: uart_ioctl protects us against hangups. */ -static int uart_get_lsr_info(struct uart_state *state, unsigned int *value) +static int uart_get_lsr_info(struct uart_state *state, + unsigned int __user *value) { struct uart_port *port = state->port; unsigned int result; @@ -1035,8 +976,8 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg) * NB: both 1->0 and 0->1 transitions are counted except for * RI where only 0->1 is counted. */ -static int -uart_get_count(struct uart_state *state, struct serial_icounter_struct *icnt) +static int uart_get_count(struct uart_state *state, + struct serial_icounter_struct __user *icnt) { struct serial_icounter_struct icount; struct uart_icount cnow; @@ -1069,6 +1010,7 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg) { struct uart_state *state = tty->driver_data; + void __user *uarg = (void __user *)arg; int ret = -ENOIOCTLCMD; BUG_ON(!kernel_locked()); @@ -1078,11 +1020,11 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, */ switch (cmd) { case TIOCGSERIAL: - ret = uart_get_info(state, (struct serial_struct *)arg); + ret = uart_get_info(state, uarg); break; case TIOCSSERIAL: - ret = uart_set_info(state, (struct serial_struct *)arg); + ret = uart_set_info(state, uarg); break; case TIOCSERCONFIG: @@ -1112,7 +1054,7 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, break; case TIOCGICOUNT: - ret = uart_get_count(state, (struct serial_icounter_struct *)arg); + ret = uart_get_count(state, uarg); break; } @@ -1132,7 +1074,7 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, */ switch (cmd) { case TIOCSERGETLSR: /* Get line status register */ - ret = uart_get_lsr_info(state, (unsigned int *)arg); + ret = uart_get_lsr_info(state, uarg); break; default: { @@ -1211,7 +1153,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp) { struct uart_state *state = tty->driver_data; struct uart_port *port; - + BUG_ON(!kernel_locked()); if (!state || !state->port) @@ -1234,12 +1176,12 @@ static void uart_close(struct tty_struct *tty, struct file *filp) * one, we've got real problems, since it means the * serial port won't be shutdown. */ - printk("uart_close: bad serial port count; tty->count is 1, " + printk(KERN_ERR "uart_close: bad serial port count; tty->count is 1, " "state->count is %d\n", state->count); state->count = 1; } if (--state->count < 0) { - printk("rs_close: bad serial port count for %s: %d\n", + printk(KERN_ERR "uart_close: bad serial port count for %s: %d\n", tty->name, state->count); state->count = 0; } @@ -1254,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 @@ -1275,16 +1217,15 @@ static void uart_close(struct tty_struct *tty, struct file *filp) uart_shutdown(state); uart_flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + + tty_ldisc_flush(tty); + tty->closing = 0; 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); } @@ -1348,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)) @@ -1906,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); } @@ -1918,7 +1856,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) * Disable the console device before suspending. */ if (uart_console(port)) - port->cons->flags &= ~CON_ENABLED; + console_stop(port->cons); uart_change_pm(state, 3); @@ -1939,8 +1877,22 @@ 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); - port->cons->flags |= CON_ENABLED; + 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); } if (state->info && state->info->flags & UIF_INITIALIZED) { @@ -1973,6 +1925,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) printk("I/O 0x%x offset 0x%x", port->iobase, port->hub6); break; case UPIO_MEM: + case UPIO_MEM32: printk("MMIO 0x%lx", port->mapbase); break; } @@ -2147,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); } @@ -2229,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);