From: James S. <jsi...@us...> - 2001-12-13 04:46:55
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/serial In directory usw-pr-cvs1:/tmp/cvs-serv2658/drivers/serial Modified Files: serial_21285.c serial_8250.c serial_8250.h serial_8250_pci.c serial_8250_pnp.c serial_amba.c serial_anakin.c serial_clps711x.c serial_core.c serial_sa1100.c serial_uart00.c Log Message: More serial driver updates. Index: serial_21285.c =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/serial/serial_21285.c,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- serial_21285.c 2001/11/01 21:38:35 1.6 +++ serial_21285.c 2001/12/13 04:46:52 1.7 @@ -23,6 +23,7 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/console.h> +#include <linux/serial_core.h> #include <asm/io.h> #include <asm/irq.h> @@ -39,378 +40,325 @@ #define SERIAL_21285_AUXNAME "cuafb" #define SERIAL_21285_AUXMAJOR 205 #define SERIAL_21285_AUXMINOR 4 - -#ifdef CONFIG_SERIAL_21285_OLD -#include <asm/mach-types.h> -/* - * Compatability with a mistake made a long time ago. - * Note - the use of "ttyI", "/dev/ttyS0" and major/minor 5,64 - * is HIGHLY DEPRECIATED, and will be removed in the 2.5 - * kernel series. - * -- rmk 15/04/2000 - */ -#define SERIAL_21285_OLD_NAME "ttyI" -#define SERIAL_21285_OLD_MAJOR TTY_MAJOR -#define SERIAL_21285_OLD_MINOR 64 -static struct tty_driver rs285_old_driver; -#endif +#define RXSTAT_DUMMY_READ 0x80000000 +#define RXSTAT_FRAME (1 << 0) +#define RXSTAT_PARITY (1 << 1) +#define RXSTAT_OVERRUN (1 << 2) +#define RXSTAT_ANYERR (RXSTAT_FRAME|RXSTAT_PARITY|RXSTAT_OVERRUN) -static struct tty_driver rs285_driver, callout_driver; -static int rs285_refcount; -static struct tty_struct *rs285_table[1]; +#define H_UBRLCR_BREAK (1 << 0) +#define H_UBRLCR_PARENB (1 << 1) +#define H_UBRLCR_PAREVN (1 << 2) +#define H_UBRLCR_STOPB (1 << 3) +#define H_UBRLCR_FIFO (1 << 4) -static struct termios *rs285_termios[1]; -static struct termios *rs285_termios_locked[1]; +static struct tty_driver normal, callout; +static struct tty_struct *serial21285_table[1]; +static struct termios *serial21285_termios[1]; +static struct termios *serial21285_termios_locked[1]; +static const char serial21285_name[] = "Footbridge UART"; -static char wbuf[1000], *putp = wbuf, *getp = wbuf, x_char; -static struct tty_struct *rs285_tty; -static int rs285_use_count; +/* + * The documented expression for selecting the divisor is: + * BAUD_BASE / baud - 1 + * However, typically BAUD_BASE is not divisible by baud, so + * we want to select the divisor that gives us the minimum + * error. Therefore, we want: + * int(BAUD_BASE / baud - 0.5) -> + * int(BAUD_BASE / baud - (baud >> 1) / baud) -> + * int((BAUD_BASE - (baud >> 1)) / baud) + */ -static int rs285_write_room(struct tty_struct *tty) +static void serial21285_stop_tx(struct uart_port *port, u_int from_tty) { - return putp >= getp ? (sizeof(wbuf) - (long) putp + (long) getp) : ((long) getp - (long) putp - 1); + disable_irq(IRQ_CONTX); } -static void rs285_rx_int(int irq, void *dev_id, struct pt_regs *regs) +static void serial21285_start_tx(struct uart_port *port, u_int nonempty, u_int from_tty) { - if (!rs285_tty) { - disable_irq(IRQ_CONRX); - return; - } - while (!(*CSR_UARTFLG & 0x10)) { - int ch, flag; - ch = *CSR_UARTDR; - flag = *CSR_RXSTAT; - if (flag & 4) - tty_insert_flip_char(rs285_tty, 0, TTY_OVERRUN); - if (flag & 2) - flag = TTY_PARITY; - else if (flag & 1) - flag = TTY_FRAME; - tty_insert_flip_char(rs285_tty, ch, flag); - } - tty_flip_buffer_push(rs285_tty); + if (nonempty) + enable_irq(IRQ_CONTX); } -static void rs285_send_xchar(struct tty_struct *tty, char ch) +static void serial21285_stop_rx(struct uart_port *port) { - x_char = ch; - enable_irq(IRQ_CONTX); + disable_irq(IRQ_CONRX); } -static void rs285_throttle(struct tty_struct *tty) +static void serial21285_enable_ms(struct uart_port *port) { - if (I_IXOFF(tty)) - rs285_send_xchar(tty, STOP_CHAR(tty)); } -static void rs285_unthrottle(struct tty_struct *tty) +static void serial21285_rx_chars(int irq, void *dev_id, struct pt_regs *regs) { - if (I_IXOFF(tty)) { - if (x_char) - x_char = 0; - else - rs285_send_xchar(tty, START_CHAR(tty)); - } -} + struct uart_info *info = dev_id; + struct uart_port *port = info->port; + struct tty_struct *tty = info->tty; + unsigned int status, ch, rxs, max_count = 256; -static void rs285_tx_int(int irq, void *dev_id, struct pt_regs *regs) -{ - while (!(*CSR_UARTFLG & 0x20)) { - if (x_char) { - *CSR_UARTDR = x_char; - x_char = 0; - continue; + status = *CSR_UARTFLG; + while (status & 0x10 && max_count--) { + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty->flip.tqueue.routine((void *)tty); + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + printk(KERN_WARNING "TTY_DONT_FLIP set\n"); + return; + } } - if (putp == getp) { - disable_irq(IRQ_CONTX); - break; + + ch = *CSR_UARTDR; + + *tty->flip.char_buf_ptr = ch; + *tty->flip.flag_buf_ptr = TTY_NORMAL; + port->icount.rx++; + + rxs = *CSR_RXSTAT | RXSTAT_DUMMY_READ; + if (rxs & RXSTAT_ANYERR) { + if (rxs & RXSTAT_PARITY) + port->icount.parity++; + else if (rxs & RXSTAT_FRAME) + port->icount.frame++; + if (rxs & RXSTAT_OVERRUN) + port->icount.overrun++; + + rxs &= port->read_status_mask; + + if (rxs & RXSTAT_PARITY) + *tty->flip.flag_buf_ptr = TTY_PARITY; + else if (rxs & RXSTAT_FRAME) + *tty->flip.flag_buf_ptr = TTY_FRAME; } - *CSR_UARTDR = *getp; - if (++getp >= wbuf + sizeof(wbuf)) - getp = wbuf; + + if ((rxs & port->ignore_status_mask) == 0) { + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + } + if ((rxs & RXSTAT_OVERRUN) && + tty->flip.count < TTY_FLIPBUF_SIZE) { + /* + * Overrun is special, since it's reported + * immediately, and doesn't affect the current + * character. + */ + *tty->flip.char_buf_ptr++ = 0; + *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; + tty->flip.count++; + } + status = *CSR_UARTFLG; } - if (rs285_tty) - wake_up_interruptible(&rs285_tty->write_wait); + tty_flip_buffer_push(tty); } -static inline int rs285_xmit(int ch) +static void serial21285_tx_chars(int irq, void *dev_id, struct pt_regs *regs) { - if (putp + 1 == getp || (putp + 1 == wbuf + sizeof(wbuf) && getp == wbuf)) - return 0; - *putp = ch; - if (++putp >= wbuf + sizeof(wbuf)) - putp = wbuf; - enable_irq(IRQ_CONTX); - return 1; + struct uart_info *info = dev_id; + struct uart_port *port = info->port; + int count = 256; + + if (port->x_char) { + *CSR_UARTDR = port->x_char; + port->icount.tx++; + port->x_char = 0; + return; + } + if (info->xmit.head == info->xmit.tail + || info->tty->stopped + || info->tty->hw_stopped) { + serial21285_stop_tx(port, 0); + return; + } + + do { + *CSR_UARTDR = info->xmit.buf[info->xmit.tail]; + info->xmit.tail = (info->xmit.tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (info->xmit.head == info->xmit.tail) + break; + } while (--count > 0 && !(*CSR_UARTFLG & 0x20)); + + if (CIRC_CNT(info->xmit.head, info->xmit.tail, UART_XMIT_SIZE) < + WAKEUP_CHARS) + uart_event(info, EVT_WRITE_WAKEUP); + + if (info->xmit.head == info->xmit.tail) + serial21285_stop_tx(port, 0); } -static int rs285_write(struct tty_struct *tty, int from_user, - const u_char * buf, int count) +static u_int serial21285_tx_empty(struct uart_port *port) { - int i; + return (*CSR_UARTFLG & 8) ? 0 : TIOCSER_TEMT; +} - if (from_user && verify_area(VERIFY_READ, buf, count)) - return -EINVAL; +/* no modem control lines */ +static u_int serial21285_get_mctrl(struct uart_port *port) +{ + return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; +} - for (i = 0; i < count; i++) { - char ch; - if (from_user) - __get_user(ch, buf + i); - else - ch = buf[i]; - if (!rs285_xmit(ch)) - break; - } - return i; +static void serial21285_set_mctrl(struct uart_port *port, u_int mctrl) +{ } -static void rs285_put_char(struct tty_struct *tty, u_char ch) +static void serial21285_break_ctl(struct uart_port *port, int break_state) { - rs285_xmit(ch); + u_int h_lcr; + + h_lcr = *CSR_H_UBRLCR; + if (break_state) + h_lcr |= H_UBRLCR_BREAK; + else + h_lcr &= ~H_UBRLCR_BREAK; + *CSR_H_UBRLCR = h_lcr; } -static int rs285_chars_in_buffer(struct tty_struct *tty) +static int serial21285_startup(struct uart_port *port, struct uart_info *info) { - return sizeof(wbuf) - rs285_write_room(tty); + int ret; + + ret = request_irq(IRQ_CONRX, serial21285_rx_chars, 0, + serial21285_name, info); + if (ret == 0) { + ret = request_irq(IRQ_CONTX, serial21285_tx_chars, 0, + serial21285_name, info); + if (ret) + free_irq(IRQ_CONRX, info); + } + return ret; } -static void rs285_flush_buffer(struct tty_struct *tty) +static void serial21285_shutdown(struct uart_port *port, struct uart_info *info) { - disable_irq(IRQ_CONTX); - putp = getp = wbuf; - if (x_char) - enable_irq(IRQ_CONTX); + free_irq(IRQ_CONTX, info); + free_irq(IRQ_CONRX, info); } -static inline void rs285_set_cflag(int cflag) +static void +serial21285_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot) { - int h_lcr, baud, quot; + u_int h_lcr; switch (cflag & CSIZE) { - case CS5: - h_lcr = 0x10; - break; - case CS6: - h_lcr = 0x30; - break; - case CS7: - h_lcr = 0x50; - break; - default: /* CS8 */ - h_lcr = 0x70; - break; - + case CS5: h_lcr = 0x00; break; + case CS6: h_lcr = 0x20; break; + case CS7: h_lcr = 0x40; break; + default: /* CS8 */ h_lcr = 0x60; break; } - if (cflag & CSTOPB) - h_lcr |= 0x08; - if (cflag & PARENB) - h_lcr |= 0x02; - if (!(cflag & PARODD)) - h_lcr |= 0x04; - switch (cflag & CBAUD) { - case B200: baud = 200; break; - case B300: baud = 300; break; - case B1200: baud = 1200; break; - case B1800: baud = 1800; break; - case B2400: baud = 2400; break; - case B4800: baud = 4800; break; - default: - case B9600: baud = 9600; break; - case B19200: baud = 19200; break; - case B38400: baud = 38400; break; - case B57600: baud = 57600; break; - case B115200: baud = 115200; break; + if (cflag & CSTOPB) + h_lcr |= H_UBRLCR_STOPB; + if (cflag & PARENB) { + h_lcr |= H_UBRLCR_PARENB; + if (!(cflag & PARODD)) + h_lcr |= H_UBRLCR_PAREVN; } + if (port->fifosize) + h_lcr |= H_UBRLCR_FIFO; + + port->read_status_mask = RXSTAT_OVERRUN; + if (iflag & INPCK) + port->read_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY; + /* - * The documented expression for selecting the divisor is: - * BAUD_BASE / baud - 1 - * However, typically BAUD_BASE is not divisible by baud, so - * we want to select the divisor that gives us the minimum - * error. Therefore, we want: - * int(BAUD_BASE / baud - 0.5) -> - * int(BAUD_BASE / baud - (baud >> 1) / baud) -> - * int((BAUD_BASE - (baud >> 1)) / baud) + * Characters to ignore */ - quot = (BAUD_BASE - (baud >> 1)) / baud; + port->ignore_status_mask = 0; + if (iflag & IGNPAR) + port->ignore_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY; + if (iflag & IGNBRK && iflag & IGNPAR) + port->ignore_status_mask |= RXSTAT_OVERRUN; + /* + * Ignore all characters if CREAD is not set. + */ + if ((cflag & CREAD) == 0) + port->ignore_status_mask |= RXSTAT_DUMMY_READ; + *CSR_UARTCON = 0; *CSR_L_UBRLCR = quot & 0xff; *CSR_M_UBRLCR = (quot >> 8) & 0x0f; *CSR_H_UBRLCR = h_lcr; *CSR_UARTCON = 1; } - -static void rs285_set_termios(struct tty_struct *tty, struct termios *old) -{ - if (old && tty->termios->c_cflag == old->c_cflag) - return; - rs285_set_cflag(tty->termios->c_cflag); -} - -static void rs285_stop(struct tty_struct *tty) +static const char *serial21285_type(struct uart_port *port) { - disable_irq(IRQ_CONTX); + return port->type == PORT_21285 ? "DC21285" : NULL; } -static void rs285_start(struct tty_struct *tty) +static void serial21285_release_port(struct uart_port *port) { - enable_irq(IRQ_CONTX); + release_mem_region(port->mapbase, 32); } -static void rs285_wait_until_sent(struct tty_struct *tty, int timeout) +static int serial21285_request_port(struct uart_port *port) { - int orig_jiffies = jiffies; - while (*CSR_UARTFLG & 8) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - if (signal_pending(current)) - break; - if (timeout && time_after(jiffies, orig_jiffies + timeout)) - break; - } - set_current_state(TASK_RUNNING); + return request_mem_region(port->mapbase, 32, serial21285_name) + != NULL ? 0 : -EBUSY; } -static int rs285_open(struct tty_struct *tty, struct file *filp) +static void serial21285_config_port(struct uart_port *port, int flags) { - int line; - - MOD_INC_USE_COUNT; - line = MINOR(tty->device) - tty->driver.minor_start; - if (line) { - MOD_DEC_USE_COUNT; - return -ENODEV; - } - - tty->driver_data = NULL; - if (!rs285_tty) - rs285_tty = tty; - - enable_irq(IRQ_CONRX); - rs285_use_count++; - return 0; + if (flags & UART_CONFIG_TYPE && serial21285_request_port(port) == 0) + port->type = PORT_21285; } -static void rs285_close(struct tty_struct *tty, struct file *filp) +/* + * verify the new serial_struct (for TIOCSSERIAL). + */ +static int serial21285_verify_port(struct uart_port *port, struct serial_struct *ser) { - if (!--rs285_use_count) { - rs285_wait_until_sent(tty, 0); - disable_irq(IRQ_CONRX); - disable_irq(IRQ_CONTX); - rs285_tty = NULL; - } - MOD_DEC_USE_COUNT; + int ret = 0; + if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285) + ret = -EINVAL; + if (ser->irq != NO_IRQ) + ret = -EINVAL; + if (ser->baud_base != port->uartclk / 16) + ret = -EINVAL; + return ret; } - -static int __init rs285_init(void) -{ - int baud = B9600; - if (machine_is_personal_server()) - baud = B57600; - - rs285_driver.magic = TTY_DRIVER_MAGIC; - rs285_driver.driver_name = "serial_21285"; - rs285_driver.name = SERIAL_21285_NAME; - rs285_driver.major = SERIAL_21285_MAJOR; - rs285_driver.minor_start = SERIAL_21285_MINOR; - rs285_driver.num = 1; - rs285_driver.type = TTY_DRIVER_TYPE_SERIAL; - rs285_driver.subtype = SERIAL_TYPE_NORMAL; - rs285_driver.init_termios = tty_std_termios; - rs285_driver.init_termios.c_cflag = baud | CS8 | CREAD | HUPCL | CLOCAL; - rs285_driver.flags = TTY_DRIVER_REAL_RAW; - rs285_driver.refcount = &rs285_refcount; - rs285_driver.table = rs285_table; - rs285_driver.termios = rs285_termios; - rs285_driver.termios_locked = rs285_termios_locked; - - rs285_driver.open = rs285_open; - rs285_driver.close = rs285_close; - rs285_driver.write = rs285_write; - rs285_driver.put_char = rs285_put_char; - rs285_driver.write_room = rs285_write_room; - rs285_driver.chars_in_buffer = rs285_chars_in_buffer; - rs285_driver.flush_buffer = rs285_flush_buffer; - rs285_driver.throttle = rs285_throttle; - rs285_driver.unthrottle = rs285_unthrottle; - rs285_driver.send_xchar = rs285_send_xchar; - rs285_driver.set_termios = rs285_set_termios; - rs285_driver.stop = rs285_stop; - rs285_driver.start = rs285_start; - rs285_driver.wait_until_sent = rs285_wait_until_sent; - - callout_driver = rs285_driver; - callout_driver.name = SERIAL_21285_AUXNAME; - callout_driver.major = SERIAL_21285_AUXMAJOR; - callout_driver.subtype = SERIAL_TYPE_CALLOUT; - - if (request_irq(IRQ_CONRX, rs285_rx_int, 0, "rs285", NULL)) - panic("Couldn't get rx irq for rs285"); - - if (request_irq(IRQ_CONTX, rs285_tx_int, 0, "rs285", NULL)) - panic("Couldn't get tx irq for rs285"); - -#ifdef CONFIG_SERIAL_21285_OLD - if (!machine_is_ebsa285() && !machine_is_netwinder()) { - rs285_old_driver = rs285_driver; - rs285_old_driver.name = SERIAL_21285_OLD_NAME; - rs285_old_driver.major = SERIAL_21285_OLD_MAJOR; - rs285_old_driver.minor_start = SERIAL_21285_OLD_MINOR; - - if (tty_register_driver(&rs285_old_driver)) - printk(KERN_ERR "Couldn't register old 21285 serial driver\n"); - } -#endif - - if (tty_register_driver(&rs285_driver)) - printk(KERN_ERR "Couldn't register 21285 serial driver\n"); - if (tty_register_driver(&callout_driver)) - printk(KERN_ERR "Couldn't register 21285 callout driver\n"); +static struct uart_ops serial21285_ops = { + tx_empty: serial21285_tx_empty, + get_mctrl: serial21285_get_mctrl, + set_mctrl: serial21285_set_mctrl, + stop_tx: serial21285_stop_tx, + start_tx: serial21285_start_tx, + stop_rx: serial21285_stop_rx, + enable_ms: serial21285_enable_ms, + break_ctl: serial21285_break_ctl, + startup: serial21285_startup, + shutdown: serial21285_shutdown, + change_speed: serial21285_change_speed, + type: serial21285_type, + release_port: serial21285_release_port, + request_port: serial21285_request_port, + config_port: serial21285_config_port, + verify_port: serial21285_verify_port, +}; - return 0; -} +static struct uart_port serial21285_port = { + membase: 0, + mapbase: 0x42000160, + iotype: SERIAL_IO_MEM, + irq: NO_IRQ, + uartclk: 0, + fifosize: 16, + ops: &serial21285_ops, + flags: ASYNC_BOOT_AUTOCONF, +}; -static void __exit rs285_fini(void) +static void serial21285_setup_ports(void) { - unsigned long flags; - int ret; - - save_flags(flags); - cli(); - ret = tty_unregister_driver(&callout_driver); - if (ret) - printk(KERN_ERR "Unable to unregister 21285 callout driver " - "(%d)\n", ret); - ret = tty_unregister_driver(&rs285_driver); - if (ret) - printk(KERN_ERR "Unable to unregister 21285 driver (%d)\n", - ret); -#ifdef CONFIG_SERIAL_21285_OLD - if (!machine_is_ebsa285() && !machine_is_netwinder()) { - ret = tty_unregister_driver(&rs285_old_driver); - if (ret) - printk(KERN_ERR "Unable to unregister old 21285 " - "driver (%d)\n", ret); - } -#endif - free_irq(IRQ_CONTX, NULL); - free_irq(IRQ_CONRX, NULL); - restore_flags(flags); + serial21285_port.uartclk = mem_fclk_21285 / 16; } -module_init(rs285_init); -module_exit(rs285_fini); - #ifdef CONFIG_SERIAL_21285_CONSOLE /************** console driver *****************/ -static void rs285_console_write(struct console *co, const char *s, u_int count) +static void serial21285_console_write(struct console *co, const char *s, u_int count) { int i; @@ -426,8 +374,13 @@ enable_irq(IRQ_CONTX); } -static int rs285_console_wait_key(struct console *co) +static kdev_t serial21285_console_device(struct console *c) { + return MKDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR); +} + +static int serial21285_console_wait_key(struct console *co) +{ int c; disable_irq(IRQ_CONRX); @@ -437,104 +390,45 @@ return c; } -static kdev_t rs285_console_device(struct console *c) +static void __init +serial21285_get_options(struct uart_port *port, int *baud, int *parity, int *bits) { - return MKDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR); } -static int __init rs285_console_setup(struct console *co, char *options) +static int __init serial21285_console_setup(struct console *co, char *options) { + struct uart_port *port = &serial21285_port; int baud = 9600; int bits = 8; int parity = 'n'; - int cflag = CREAD | HUPCL | CLOCAL; + int flow = 'n'; if (machine_is_personal_server()) baud = 57600; - if (options) { - char *s = options; - baud = simple_strtoul(options, NULL, 10); - while (*s >= '0' && *s <= '9') - s++; - if (*s) - parity = *s++; - if (*s) - bits = *s - '0'; - } - /* - * Now construct a cflag setting. + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. */ - switch (baud) { - case 1200: - cflag |= B1200; - break; - case 2400: - cflag |= B2400; - break; - case 4800: - cflag |= B4800; - break; - case 9600: - cflag |= B9600; - break; - case 19200: - cflag |= B19200; - break; - case 38400: - cflag |= B38400; - break; - case 57600: - cflag |= B57600; - break; - case 115200: - cflag |= B115200; - break; - default: - cflag |= B9600; - break; - } - switch (bits) { - case 7: - cflag |= CS7; - break; - default: - cflag |= CS8; - break; - } - switch (parity) { - case 'o': - case 'O': - cflag |= PARODD; - break; - case 'e': - case 'E': - cflag |= PARENB; - break; - } - co->cflag = cflag; - rs285_set_cflag(cflag); - rs285_console_write(NULL, "\e[2J\e[Hboot ", 12); if (options) - rs285_console_write(NULL, options, strlen(options)); + uart_parse_options(options, &baud, &parity, &bits, &flow); else - rs285_console_write(NULL, "no options", 10); - rs285_console_write(NULL, "\n", 1); + serial21285_get_options(port, &baud, &parity, &bits); - return 0; + return uart_set_options(port, co, baud, parity, bits, flow); } #ifdef CONFIG_SERIAL_21285_OLD -static struct console rs285_old_cons = +static struct console serial21285_old_cons = { SERIAL_21285_OLD_NAME, - rs285_console_write, + serial21285_console_write, NULL, - rs285_console_device, - rs285_console_wait_key, + serial21285_console_device, + serial21285_console_wait_key, NULL, - rs285_console_setup, + serial21285_console_setup, CON_PRINTBUFFER, -1, 0, @@ -542,27 +436,63 @@ }; #endif -static struct console rs285_cons = +static struct console serial21285_console = { name: SERIAL_21285_NAME, - write: rs285_console_write, - device: rs285_console_device, - wait_key: rs285_console_wait_key, - setup: rs285_console_setup, + write: serial21285_console_write, + device: serial21285_console_device, + wait_key: serial21285_console_wait_key, + setup: serial21285_console_setup, flags: CON_PRINTBUFFER, index: -1, }; void __init rs285_console_init(void) { -#ifdef CONFIG_SERIAL_21285_OLD - if (!machine_is_ebsa285() && !machine_is_netwinder()) - register_console(&rs285_old_cons); + serial21285_setup_ports(); + register_console(&serial21285_console); +} + +#define SERIAL_21285_CONSOLE &serial21285_console +#else +#define SERIAL_21285_CONSOLE NULL #endif - register_console(&rs285_cons); + +static struct uart_driver serial21285_reg = { + owner: THIS_MODULE, + normal_major: SERIAL_21285_MAJOR, +#ifdef CONFIG_DEVFS_FS + normal_name: "ttyFB%d", + callout_name: "cuafb%d", +#else + normal_name: "ttyFB", + callout_name: "cuafb", +#endif + normal_driver: &normal, + callout_major: SERIAL_21285_AUXMAJOR, + callout_driver: &callout, + table: serial21285_table, + termios: serial21285_termios, + termios_locked: serial21285_termios_locked, + minor: SERIAL_21285_MINOR, + nr: 1, + port: &serial21285_port, + cons: SERIAL_21285_CONSOLE, +}; + +static int __init serial21285_init(void) +{ + serial21285_setup_ports(); + return uart_register_driver(&serial21285_reg); } -#endif /* CONFIG_SERIAL_21285_CONSOLE */ +static void __exit serial21285_exit(void) +{ + uart_unregister_driver(&serial21285_reg); +} + +module_init(serial21285_init); +module_exit(serial21285_exit); EXPORT_NO_SYMBOLS; Index: serial_8250.c =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/serial/serial_8250.c,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- serial_8250.c 2001/11/23 01:44:33 1.10 +++ serial_8250.c 2001/12/13 04:46:52 1.11 @@ -102,7 +102,7 @@ /* * Here we define the default xmit fifo size used for each type of UART. */ -static struct serial_uart_config uart_config[PORT_MAX_8250+1] = { +static const struct serial_uart_config uart_config[PORT_MAX_8250+1] = { { "unknown", 1, 0 }, { "8250", 1, 0 }, { "16450", 1, 0 }, @@ -857,6 +857,8 @@ #endif do { + spin_lock(&info->lock); + if (!info->tty || (serial_in(info->port, UART_IIR) & UART_IIR_NO_INT)) { if (!end_mark) @@ -871,6 +873,8 @@ serial8250_handle_port(info, regs); next: + spin_unlock(&info->lock); + info = info->next_info; if (info) continue; @@ -918,6 +922,8 @@ first_multi = inb(port_monitor); #endif + spin_lock(&info->lock); + do { serial8250_handle_port(info, regs); if (pass_counter++ > RS_ISR_PASS_LIMIT) { @@ -930,6 +936,9 @@ printk("IIR = %x...", serial_in(info->port, UART_IIR)); #endif } while (!(serial_in(info->port, UART_IIR) & UART_IIR_NO_INT)); + + spin_unlock(&info->lock); + #ifdef CONFIG_SERIAL_8250_MULTIPORT if (port_monitor) printk("rs port monitor (single) irq %d: 0x%x, 0x%x\n", @@ -968,6 +977,7 @@ first_multi = inb(multi->port_monitor); while (1) { + spin_lock(info->lock); if (!info->tty || (serial_in(info->port, UART_IIR) & UART_IIR_NO_INT)) goto next; @@ -975,6 +985,7 @@ serial8250_handle_port(info, regs); next: + spin_unlock(info->lock); info = info->next; if (info) continue; @@ -1613,6 +1624,16 @@ return 0; } +static const char * +serial8250_type(struct uart_port *port) +{ + int type = port->type; + + if (type >= PORT_MAX_8250) + type = 0; + return uart_config[type].name; +} + static struct uart_ops serial8250_pops = { tx_empty: serial8250_tx_empty, set_mctrl: serial8250_set_mctrl, @@ -1626,6 +1647,7 @@ shutdown: serial8250_shutdown, change_speed: serial8250_change_speed, pm: serial8250_pm, + type: serial8250_type, release_port: serial8250_release_port, request_port: serial8250_request_port, config_port: serial8250_config_port, Index: serial_8250.h =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/serial/serial_8250.h,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 Index: serial_8250_pci.c =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/serial/serial_8250_pci.c,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- serial_8250_pci.c 2001/12/02 07:03:59 1.11 +++ serial_8250_pci.c 2001/12/13 04:46:52 1.12 @@ -1078,4 +1078,4 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Generic 8250/16x50 PCI serial probe module"); -//MODULE_GENERIC_TABLE(pci, serial_pci_tbl); +MODULE_GENERIC_TABLE(pci, serial_pci_tbl); Index: serial_8250_pnp.c =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/serial/serial_8250_pnp.c,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- serial_8250_pnp.c 2001/12/02 07:03:59 1.6 +++ serial_8250_pnp.c 2001/12/13 04:46:52 1.7 @@ -549,5 +549,5 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Generic 8250/16x50 PNPBIOS serial probe module"); -//MODULE_GENERIC_TABLE(pnp, pnp_dev_table); +MODULE_GENERIC_TABLE(pnp, pnp_dev_table); Index: serial_amba.c =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/serial/serial_amba.c,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- serial_amba.c 2001/11/23 01:44:33 1.9 +++ serial_amba.c 2001/12/13 04:46:52 1.10 @@ -511,6 +511,11 @@ restore_flags(flags); } +static const char *ambauart_type(struct uart_port *port) +{ + return port->type == PORT_AMBA ? "AMBA" : NULL; +} + /* * Release the memory region(s) being used by 'port' */ @@ -566,6 +571,7 @@ startup: ambauart_startup, shutdown: ambauart_shutdown, change_speed: ambauart_change_speed, + type: ambauart_type, release_port: ambauart_release_port, request_port: ambauart_request_port, config_port: ambauart_config_port, Index: serial_anakin.c =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/serial/serial_anakin.c,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- serial_anakin.c 2001/11/23 01:44:33 1.2 +++ serial_anakin.c 2001/12/13 04:46:52 1.3 @@ -337,6 +337,11 @@ restore_flags(flags); } +static const char *anakin_type(struct port *port) +{ + return port->type == PORT_ANAKIN ? "ANAKIN" : NULL; +} + static struct uart_ops anakin_pops = { tx_empty: anakin_tx_empty, set_mctrl: anakin_set_mctrl, @@ -349,6 +354,7 @@ startup: anakin_startup, shutdown: anakin_shutdown, change_speed: anakin_change_speed, + type: anakin_type, }; static struct uart_port anakin_ports[UART_NR] = { Index: serial_clps711x.c =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/serial/serial_clps711x.c,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- serial_clps711x.c 2001/11/23 01:44:33 1.9 +++ serial_clps711x.c 2001/12/13 04:46:52 1.10 @@ -406,6 +406,11 @@ restore_flags(flags); } +static const char *clps711xuart_type(struct uart_port *port) +{ + return port->type == PORT_CLPS711X ? "CLPS711x" : NULL; +} + /* * Configure/autoconfigure the port. */ @@ -436,6 +441,7 @@ startup: clps711xuart_startup, shutdown: clps711xuart_shutdown, change_speed: clps711xuart_change_speed, + type: clps711xuart_type, config_port: clps711xuart_config_port, release_port: clps711xuart_release_port, request_port: clps711xuart_request_port, Index: serial_core.c =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/serial/serial_core.c,v retrieving revision 1.16 retrieving revision 1.17 diff -u -d -r1.16 -r1.17 --- serial_core.c 2001/11/23 01:44:33 1.16 +++ serial_core.c 2001/12/13 04:46:52 1.17 @@ -1506,7 +1506,15 @@ static const char *uart_type(struct uart_port *port) { - return ""; + const char *str = NULL; + + if (port->ops->type) + str = port->ops->type(port); + + if (!str) + str = "unknown"; + + return str; } static int uart_line_info(char *buf, struct uart_driver *drv, int i) @@ -1705,6 +1713,7 @@ extern void rs285_console_init(void); extern void sa1100_rs_console_init(void); extern void serial8250_console_init(void); +extern void uart00_console_init(void); /* * Central "initialise all serial consoles" container. Needs to be killed. @@ -1745,60 +1754,105 @@ * We don't actually save any state; the serial driver has enough * state held internally to re-setup the port when we come out of D3. */ -static int uart_pm(struct pm_dev *dev, pm_request_t rqst, void *data) +static int uart_pm_set_state(struct uart_state *state, int pm_state, int oldstate) { - if (rqst == PM_SUSPEND || rqst == PM_RESUME) { - struct uart_state *state = dev->data; - struct uart_port *port = state->port; - struct uart_ops *ops = port->ops; - int pm_state = (int)data; - int running = state->info && - state->info->flags & ASYNC_INITIALIZED; + struct uart_port *port = state->port; + struct uart_ops *ops = port->ops; + int running = state->info && + state->info->flags & ASYNC_INITIALIZED; - if (port->type == PORT_UNKNOWN) - return 0; + if (port->type == PORT_UNKNOWN) + return 0; //printk("pm: %08x: %d -> %d, %srunning\n", port->iobase, dev->state, pm_state, running ? "" : "not "); - if (pm_state == 0) { - if (ops->pm) - ops->pm(port, pm_state, dev->state); - if (running) { - ops->set_mctrl(port, 0); - ops->startup(port, state->info); - uart_change_speed(state->info, NULL); - ops->set_mctrl(port, state->info->mctrl); - ops->start_tx(port, 1, 0); - } + if (pm_state == 0) { + if (ops->pm) + ops->pm(port, pm_state, oldstate); + if (running) { + ops->set_mctrl(port, 0); + ops->startup(port, state->info); + uart_change_speed(state->info, NULL); + ops->set_mctrl(port, state->info->mctrl); + ops->start_tx(port, 1, 0); + } - /* - * Re-enable the console device after suspending. - */ - if (state->cons && state->cons->index == port->line) - state->cons->flags |= CON_ENABLED; - } else if (pm_state == 1) { - if (ops->pm) - ops->pm(port, pm_state, dev->state); - } else { - /* - * Disable the console device before suspending. - */ - if (state->cons && state->cons->index == port->line) - state->cons->flags &= ~CON_ENABLED; + /* + * Re-enable the console device after suspending. + */ + if (state->cons && state->cons->index == port->line) + state->cons->flags |= CON_ENABLED; + } else if (pm_state == 1) { + if (ops->pm) + ops->pm(port, pm_state, oldstate); + } else { + /* + * Disable the console device before suspending. + */ + if (state->cons && state->cons->index == port->line) + state->cons->flags &= ~CON_ENABLED; - if (running) { - ops->stop_tx(port, 0); - ops->set_mctrl(port, 0); - ops->stop_rx(port); - ops->shutdown(port, state->info); - } - if (ops->pm) - ops->pm(port, pm_state, dev->state); + if (running) { + ops->stop_tx(port, 0); + ops->set_mctrl(port, 0); + ops->stop_rx(port); + ops->shutdown(port, state->info); } + if (ops->pm) + ops->pm(port, pm_state, oldstate); } return 0; } + +/* + * Wakeup support. + */ +static int uart_pm_set_wakeup(struct uart_state *state, int data) +{ + int err = 0; + + if (state->port->ops->set_wake) + err = state->port->ops->set_wake(state->port, data); + + return err; +} + +static int uart_pm(struct pm_dev *dev, pm_request_t rqst, void *data) +{ + struct uart_state *state = dev->data; + int err = 0; + + switch (rqst) { + case PM_SUSPEND: + case PM_RESUME: + err = uart_pm_set_state(state, (int)data, dev->state); + break; + + case PM_SET_WAKEUP: + err = uart_pm_set_wakeup(state, (int)data); + break; + } + return err; +} #endif +static inline void +uart_report_port(struct uart_driver *drv, struct uart_port *port) +{ + printk("%s%d at ", drv->normal_name, port->line); + switch (port->iotype) { + case SERIAL_IO_PORT: + printk("I/O 0x%x", port->iobase); + break; + case SERIAL_IO_HUB6: + printk("I/O 0x%x offset 0x%x", port->iobase, port->hub6); + break; + case SERIAL_IO_MEM: + printk("MEM 0x%x", port->mapbase); + break; + } + printk(" (irq = %d) is a %s\n", port->irq, uart_type(port)); +} + static void uart_setup_port(struct uart_driver *drv, struct uart_state *state) { @@ -1842,6 +1896,7 @@ state->port->line); tty_register_devfs(drv->callout_driver, 0, drv->minor + state->port->line); + uart_report_port(drv, port); } #ifdef CONFIG_PM @@ -2091,7 +2146,7 @@ #if 0 //def CONFIG_PM /* we have already registered the power management handlers */ - state->pm = pm_register(PM_SYS_DEV, PM_SYS_CON, uart_pm); + state->pm = pm_register(PM_SYS_DEV, PM_SYS_COM, uart_pm); if (state->pm) { state->pm->data = state; @@ -2113,6 +2168,9 @@ state->port->line); tty_register_devfs(drv->callout_driver, 0, drv->minor + state->port->line); + + uart_report_port(drv, state->port); + up(&state->count_sem); return i; } Index: serial_sa1100.c =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/serial/serial_sa1100.c,v retrieving revision 1.14 retrieving revision 1.15 diff -u -d -r1.14 -r1.15 --- serial_sa1100.c 2001/11/23 01:44:33 1.14 +++ serial_sa1100.c 2001/12/13 04:46:52 1.15 @@ -271,6 +271,7 @@ unsigned int status, pass_counter = 0; status = UART_GET_UTSR0(port); + status &= (SM_TO_UTSR0(port->read_status_mask) | ~UTSR0_TFS); do { if (status & (UTSR0_RFS | UTSR0_RID)) { /* Clear the receiver idle bit, if set */ @@ -294,12 +295,12 @@ } #endif } - status &= SM_TO_UTSR0(port->read_status_mask); if (status & UTSR0_TFS) sa1100_tx_chars(info); if (pass_counter++ > SA1100_ISR_PASS_LIMIT) break; status = UART_GET_UTSR0(port); + status &= (SM_TO_UTSR0(port->read_status_mask) | ~UTSR0_TFS); } while (status & (UTSR0_TFS | UTSR0_RFS | UTSR0_RID)); } @@ -451,6 +452,11 @@ UART_PUT_UTCR3(port, old_utcr3); } +static const char *sa1100_type(struct uart_port *port) +{ + return port->type == PORT_SA1100 ? "SA1100" : NULL; +} + /* * Release the memory region(s) being used by 'port'. */ @@ -514,6 +520,7 @@ startup: sa1100_startup, shutdown: sa1100_shutdown, change_speed: sa1100_change_speed, + type: sa1100_type, release_port: sa1100_release_port, request_port: sa1100_request_port, config_port: sa1100_config_port, @@ -565,9 +572,10 @@ sa1100_pops.get_mctrl = fns->get_mctrl; if (fns->set_mctrl) sa1100_pops.set_mctrl = fns->set_mctrl; - sa1100_open = fns->open; - sa1100_close = fns->close; - sa1100_pops.pm = fns->pm; + sa1100_open = fns->open; + sa1100_close = fns->close; + sa1100_pops.pm = fns->pm; + sa1100_pops.set_wake = fns->set_wake; } void __init sa1100_register_uart(int idx, int port) Index: serial_uart00.c =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/serial/serial_uart00.c,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- serial_uart00.c 2001/11/23 01:44:33 1.2 +++ serial_uart00.c 2001/12/13 04:46:52 1.3 @@ -530,6 +530,11 @@ UART_PUT_MCR(port, UART_GET_MCR(port) &~UART_MCR_BR_MSK); } +static const char *uart00_type(struct uart_port *port) +{ + return port->type == PORT_UART00 ? "UART00" : NULL; +} + /* * Release the memory region(s) being used by 'port' */ @@ -585,6 +590,7 @@ startup: uart00_startup, shutdown: uart00_shutdown, change_speed: uart00_change_speed, + type: uart00_type, release_port: uart00_release_port, request_port: uart00_request_port, config_port: uart00_config_port, |