X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fserial%2F8250.c;h=54e5cc0dd5f8c323134531f6671c559754d10b5d;hb=33f0f88f1c51ae5c2d593d26960c760ea154c2e2;hp=98820603e75fd2a4a7b27206817744d60c10f833;hpb=b8cbfa692485bf7568eda3d2f37545a76efb7c93;p=pandora-kernel.git diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 98820603e75f..54e5cc0dd5f8 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -54,6 +54,8 @@ */ static unsigned int share_irqs = SERIAL8250_SHARE_IRQS; +static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS; + /* * Debugging. */ @@ -102,7 +104,7 @@ static unsigned int share_irqs = SERIAL8250_SHARE_IRQS; #define SERIAL_PORT_DFNS #endif -static struct old_serial_port old_serial_port[] = { +static const struct old_serial_port old_serial_port[] = { SERIAL_PORT_DFNS /* defined in asm/serial.h */ }; @@ -296,7 +298,7 @@ static inline int map_8250_out_reg(struct uart_8250_port *up, int offset) #endif -static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset) +static unsigned int serial_in(struct uart_8250_port *up, int offset) { offset = map_8250_in_reg(up, offset) << up->port.regshift; @@ -321,7 +323,7 @@ static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset) } } -static _INLINE_ void +static void serial_out(struct uart_8250_port *up, int offset, int value) { offset = map_8250_out_reg(up, offset) << up->port.regshift; @@ -999,7 +1001,10 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) serial_outp(up, UART_MCR, save_mcr); serial8250_clear_fifos(up); (void)serial_in(up, UART_RX); - serial_outp(up, UART_IER, 0); + if (up->capabilities & UART_CAP_UUE) + serial_outp(up, UART_IER, UART_IER_UUE); + else + serial_outp(up, UART_IER, 0); out: spin_unlock_irqrestore(&up->port.lock, flags); @@ -1128,7 +1133,7 @@ static void serial8250_enable_ms(struct uart_port *port) serial_out(up, UART_IER, up->ier); } -static _INLINE_ void +static void receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs) { struct tty_struct *tty = up->port.info->tty; @@ -1137,19 +1142,6 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs) char flag; do { - /* The following is not allowed by the tty layer and - unsafe. It should be fixed ASAP */ - if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) { - if (tty->low_latency) { - spin_unlock(&up->port.lock); - tty_flip_buffer_push(tty); - spin_lock(&up->port.lock); - } - /* - * If this failed then we will throw away the - * bytes but must do so to clear interrupts - */ - } ch = serial_inp(up, UART_RX); flag = TTY_NORMAL; up->port.icount.rx++; @@ -1214,7 +1206,7 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs) *status = lsr; } -static _INLINE_ void transmit_chars(struct uart_8250_port *up) +static void transmit_chars(struct uart_8250_port *up) { struct circ_buf *xmit = &up->port.info->xmit; int count; @@ -1252,25 +1244,24 @@ static _INLINE_ void transmit_chars(struct uart_8250_port *up) __stop_tx(up); } -static _INLINE_ void check_modem_status(struct uart_8250_port *up) +static unsigned int check_modem_status(struct uart_8250_port *up) { - int status; - - status = serial_in(up, UART_MSR); + unsigned int status = serial_in(up, UART_MSR); - if ((status & UART_MSR_ANY_DELTA) == 0) - return; + if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI) { + if (status & UART_MSR_TERI) + up->port.icount.rng++; + if (status & UART_MSR_DDSR) + up->port.icount.dsr++; + if (status & UART_MSR_DDCD) + uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); + if (status & UART_MSR_DCTS) + uart_handle_cts_change(&up->port, status & UART_MSR_CTS); - if (status & UART_MSR_TERI) - up->port.icount.rng++; - if (status & UART_MSR_DDSR) - up->port.icount.dsr++; - if (status & UART_MSR_DDCD) - uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); - if (status & UART_MSR_DCTS) - uart_handle_cts_change(&up->port, status & UART_MSR_CTS); + wake_up_interruptible(&up->port.info->delta_msr_wait); + } - wake_up_interruptible(&up->port.info->delta_msr_wait); + return status; } /* @@ -1279,7 +1270,11 @@ static _INLINE_ void check_modem_status(struct uart_8250_port *up) static inline void serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs) { - unsigned int status = serial_inp(up, UART_LSR); + unsigned int status; + + spin_lock(&up->port.lock); + + status = serial_inp(up, UART_LSR); DEBUG_INTR("status = %x...", status); @@ -1288,6 +1283,8 @@ serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs) check_modem_status(up); if (status & UART_LSR_THRE) transmit_chars(up); + + spin_unlock(&up->port.lock); } /* @@ -1323,9 +1320,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id, struct pt_regs *r iir = serial_in(up, UART_IIR); if (!(iir & UART_IIR_NO_INT)) { - spin_lock(&up->port.lock); serial8250_handle_port(up, regs); - spin_unlock(&up->port.lock); handled = 1; @@ -1424,11 +1419,8 @@ static void serial8250_timeout(unsigned long data) unsigned int iir; iir = serial_in(up, UART_IIR); - if (!(iir & UART_IIR_NO_INT)) { - spin_lock(&up->port.lock); + if (!(iir & UART_IIR_NO_INT)) serial8250_handle_port(up, NULL); - spin_unlock(&up->port.lock); - } timeout = up->port.timeout; timeout = timeout > 6 ? (timeout / 2 - 2) : 1; @@ -1451,10 +1443,10 @@ static unsigned int serial8250_tx_empty(struct uart_port *port) static unsigned int serial8250_get_mctrl(struct uart_port *port) { struct uart_8250_port *up = (struct uart_8250_port *)port; - unsigned char status; + unsigned int status; unsigned int ret; - status = serial_in(up, UART_MSR); + status = check_modem_status(up); ret = 0; if (status & UART_MSR_DCD) @@ -2115,7 +2107,7 @@ static void __init serial8250_isa_init_ports(void) return; first = 0; - for (i = 0; i < UART_NR; i++) { + for (i = 0; i < nr_uarts; i++) { struct uart_8250_port *up = &serial8250_ports[i]; up->port.line = i; @@ -2134,7 +2126,7 @@ static void __init serial8250_isa_init_ports(void) } for (i = 0, up = serial8250_ports; - i < ARRAY_SIZE(old_serial_port) && i < UART_NR; + i < ARRAY_SIZE(old_serial_port) && i < nr_uarts; i++, up++) { up->port.iobase = old_serial_port[i].port; up->port.irq = irq_canonicalize(old_serial_port[i].irq); @@ -2156,7 +2148,7 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev) serial8250_isa_init_ports(); - for (i = 0; i < UART_NR; i++) { + for (i = 0; i < nr_uarts; i++) { struct uart_8250_port *up = &serial8250_ports[i]; up->port.dev = dev; @@ -2259,7 +2251,7 @@ static int serial8250_console_setup(struct console *co, char *options) * if so, search for the first available port that does have * console support. */ - if (co->index >= UART_NR) + if (co->index >= nr_uarts) co->index = 0; port = &serial8250_ports[co->index].port; if (!port->iobase && !port->membase) @@ -2295,11 +2287,9 @@ static int __init find_port(struct uart_port *p) int line; struct uart_port *port; - for (line = 0; line < UART_NR; line++) { + for (line = 0; line < nr_uarts; line++) { port = &serial8250_ports[line].port; - if (p->iotype == port->iotype && - p->iobase == port->iobase && - p->membase == port->membase) + if (uart_match_port(p, port)) return line; } return -ENODEV; @@ -2381,9 +2371,9 @@ void serial8250_resume_port(int line) * list is terminated with a zero flags entry, which means we expect * all entries to have at least UPF_BOOT_AUTOCONF set. */ -static int __devinit serial8250_probe(struct device *dev) +static int __devinit serial8250_probe(struct platform_device *dev) { - struct plat_serial8250_port *p = dev->platform_data; + struct plat_serial8250_port *p = dev->dev.platform_data; struct uart_port port; int ret, i; @@ -2399,12 +2389,12 @@ static int __devinit serial8250_probe(struct device *dev) port.flags = p->flags; port.mapbase = p->mapbase; port.hub6 = p->hub6; - port.dev = dev; + port.dev = &dev->dev; if (share_irqs) port.flags |= UPF_SHARE_IRQ; ret = serial8250_register_port(&port); if (ret < 0) { - dev_err(dev, "unable to register port at index %d " + dev_err(&dev->dev, "unable to register port at index %d " "(IO%lx MEM%lx IRQ%d): %d\n", i, p->iobase, p->mapbase, p->irq, ret); } @@ -2415,54 +2405,55 @@ static int __devinit serial8250_probe(struct device *dev) /* * Remove serial ports registered against a platform device. */ -static int __devexit serial8250_remove(struct device *dev) +static int __devexit serial8250_remove(struct platform_device *dev) { int i; - for (i = 0; i < UART_NR; i++) { + for (i = 0; i < nr_uarts; i++) { struct uart_8250_port *up = &serial8250_ports[i]; - if (up->port.dev == dev) + if (up->port.dev == &dev->dev) serial8250_unregister_port(i); } return 0; } -static int serial8250_suspend(struct device *dev, pm_message_t state) +static int serial8250_suspend(struct platform_device *dev, pm_message_t state) { int i; for (i = 0; i < UART_NR; i++) { struct uart_8250_port *up = &serial8250_ports[i]; - if (up->port.type != PORT_UNKNOWN && up->port.dev == dev) + if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) uart_suspend_port(&serial8250_reg, &up->port); } return 0; } -static int serial8250_resume(struct device *dev) +static int serial8250_resume(struct platform_device *dev) { int i; for (i = 0; i < UART_NR; i++) { struct uart_8250_port *up = &serial8250_ports[i]; - if (up->port.type != PORT_UNKNOWN && up->port.dev == dev) + if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) uart_resume_port(&serial8250_reg, &up->port); } return 0; } -static struct device_driver serial8250_isa_driver = { - .name = "serial8250", - .bus = &platform_bus_type, +static struct platform_driver serial8250_isa_driver = { .probe = serial8250_probe, .remove = __devexit_p(serial8250_remove), .suspend = serial8250_suspend, .resume = serial8250_resume, + .driver = { + .name = "serial8250", + }, }; /* @@ -2485,7 +2476,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port * /* * First, find a port entry which matches. */ - for (i = 0; i < UART_NR; i++) + for (i = 0; i < nr_uarts; i++) if (uart_match_port(&serial8250_ports[i].port, port)) return &serial8250_ports[i]; @@ -2494,7 +2485,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port * * free entry. We look for one which hasn't been previously * used (indicated by zero iobase). */ - for (i = 0; i < UART_NR; i++) + for (i = 0; i < nr_uarts; i++) if (serial8250_ports[i].port.type == PORT_UNKNOWN && serial8250_ports[i].port.iobase == 0) return &serial8250_ports[i]; @@ -2503,7 +2494,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port * * That also failed. Last resort is to find any entry which * doesn't have a real port associated with it. */ - for (i = 0; i < UART_NR; i++) + for (i = 0; i < nr_uarts; i++) if (serial8250_ports[i].port.type == PORT_UNKNOWN) return &serial8250_ports[i]; @@ -2588,8 +2579,11 @@ static int __init serial8250_init(void) { int ret, i; + if (nr_uarts > UART_NR) + nr_uarts = UART_NR; + printk(KERN_INFO "Serial: 8250/16550 driver $Revision: 1.90 $ " - "%d ports, IRQ sharing %sabled\n", (int) UART_NR, + "%d ports, IRQ sharing %sabled\n", nr_uarts, share_irqs ? "en" : "dis"); for (i = 0; i < NR_IRQS; i++) @@ -2608,7 +2602,7 @@ static int __init serial8250_init(void) serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev); - ret = driver_register(&serial8250_isa_driver); + ret = platform_driver_register(&serial8250_isa_driver); if (ret == 0) goto out; @@ -2630,7 +2624,7 @@ static void __exit serial8250_exit(void) */ serial8250_isa_devs = NULL; - driver_unregister(&serial8250_isa_driver); + platform_driver_unregister(&serial8250_isa_driver); platform_device_unregister(isa_dev); uart_unregister_driver(&serial8250_reg); @@ -2649,6 +2643,9 @@ module_param(share_irqs, uint, 0644); MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices" " (unsafe)"); +module_param(nr_uarts, uint, 0644); +MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")"); + #ifdef CONFIG_SERIAL_8250_RSA module_param_array(probe_rsa, ulong, &probe_rsa_count, 0444); MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");