X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fserial%2Fsunzilog.c;h=2c7a66af4f5289047395cca207dedbd3a311cac2;hb=2a2a5660f10a468016fed594ab09d77ef0bb6079;hp=15b6e1cb040be54994ea9cbeea68bce51a61e2bf;hpb=9977e390dd25751fc40e01850da88b37d3c81109;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 15b6e1c..2c7a66a 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -9,7 +9,7 @@ * C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their * work there. * - * Copyright (C) 2002, 2006 David S. Miller (davem@davemloft.net) + * Copyright (C) 2002, 2006, 2007 David S. Miller (davem@davemloft.net) */ #include @@ -32,11 +32,11 @@ #include #endif #include +#include #include #include #include -#include #if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ @@ -63,10 +63,6 @@ readb(&((__channel)->control)) #endif -static int num_sunzilog; -#define NUM_SUNZILOG num_sunzilog -#define NUM_CHANNELS (NUM_SUNZILOG * 2) - #define ZS_CLOCK 4915200 /* Zilog input clock rate. */ #define ZS_CLOCK_DIVISOR 16 /* Divisor this driver uses. */ @@ -332,9 +328,9 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up, unsigned char ch, r1, flag; tty = NULL; - if (up->port.info != NULL && /* Unopened serial console */ - up->port.info->tty != NULL) /* Keyboard || mouse */ - tty = up->port.info->tty; + if (up->port.state != NULL && /* Unopened serial console */ + up->port.state->port.tty != NULL) /* Keyboard || mouse */ + tty = up->port.state->port.tty; for (;;) { @@ -455,7 +451,7 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up, uart_handle_cts_change(&up->port, (status & CTS)); - wake_up_interruptible(&up->port.info->delta_msr_wait); + wake_up_interruptible(&up->port.state->port.delta_msr_wait); } up->prev_status = status; @@ -505,9 +501,9 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up, return; } - if (up->port.info == NULL) + if (up->port.state == NULL) goto ack_tx_int; - xmit = &up->port.info->xmit; + xmit = &up->port.state->xmit; if (uart_circ_empty(xmit)) goto ack_tx_int; @@ -709,7 +705,7 @@ static void sunzilog_start_tx(struct uart_port *port) port->icount.tx++; port->x_char = 0; } else { - struct circ_buf *xmit = &port->info->xmit; + struct circ_buf *xmit = &port->state->xmit; writeb(xmit->buf[xmit->tail], &channel->data); ZSDELAY(); @@ -1019,6 +1015,7 @@ static struct uart_ops sunzilog_pops = { .verify_port = sunzilog_verify_port, }; +static int uart_chip_count; static struct uart_sunzilog_port *sunzilog_port_table; static struct zilog_layout __iomem **sunzilog_chip_regs; @@ -1026,23 +1023,24 @@ static struct uart_sunzilog_port *sunzilog_irq_chain; static struct uart_driver sunzilog_reg = { .owner = THIS_MODULE, - .driver_name = "ttyS", + .driver_name = "sunzilog", .dev_name = "ttyS", .major = TTY_MAJOR, }; -static int __init sunzilog_alloc_tables(void) +static int __init sunzilog_alloc_tables(int num_sunzilog) { struct uart_sunzilog_port *up; unsigned long size; + int num_channels = num_sunzilog * 2; int i; - size = NUM_CHANNELS * sizeof(struct uart_sunzilog_port); + size = num_channels * sizeof(struct uart_sunzilog_port); sunzilog_port_table = kzalloc(size, GFP_KERNEL); if (!sunzilog_port_table) return -ENOMEM; - for (i = 0; i < NUM_CHANNELS; i++) { + for (i = 0; i < num_channels; i++) { up = &sunzilog_port_table[i]; spin_lock_init(&up->port.lock); @@ -1050,13 +1048,13 @@ static int __init sunzilog_alloc_tables(void) if (i == 0) sunzilog_irq_chain = up; - if (i < NUM_CHANNELS - 1) + if (i < num_channels - 1) up->next = up + 1; else up->next = NULL; } - size = NUM_SUNZILOG * sizeof(struct zilog_layout __iomem *); + size = num_sunzilog * sizeof(struct zilog_layout __iomem *); sunzilog_chip_regs = kzalloc(size, GFP_KERNEL); if (!sunzilog_chip_regs) { kfree(sunzilog_port_table); @@ -1151,11 +1149,22 @@ sunzilog_console_write(struct console *con, const char *s, unsigned int count) { struct uart_sunzilog_port *up = &sunzilog_port_table[con->index]; unsigned long flags; + int locked = 1; + + local_irq_save(flags); + if (up->port.sysrq) { + locked = 0; + } else if (oops_in_progress) { + locked = spin_trylock(&up->port.lock); + } else + spin_lock(&up->port.lock); - spin_lock_irqsave(&up->port.lock, flags); uart_console_write(&up->port, s, count, sunzilog_putchar); udelay(2); - spin_unlock_irqrestore(&up->port.lock, flags); + + if (locked) + spin_unlock(&up->port.lock); + local_irq_restore(flags); } static int __init sunzilog_console_setup(struct console *con, char *options) @@ -1171,7 +1180,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options) (sunzilog_reg.minor - 64) + con->index, con->index); /* Get firmware console settings. */ - sunserial_console_termios(con); + sunserial_console_termios(con, to_of_device(up->port.dev)->node); /* Firmware console speed is limited to 150-->38400 baud so * this hackish cflag thing is OK. @@ -1215,23 +1224,6 @@ static struct console sunzilog_console_ops = { static inline struct console *SUNZILOG_CONSOLE(void) { - int i; - - if (con_is_present()) - return NULL; - - for (i = 0; i < NUM_CHANNELS; i++) { - int this_minor = sunzilog_reg.minor + i; - - if ((this_minor - 64) == (serial_console - 1)) - break; - } - if (i == NUM_CHANNELS) - return NULL; - - sunzilog_console_ops.index = i; - sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS; - return &sunzilog_console_ops; } @@ -1239,7 +1231,7 @@ static inline struct console *SUNZILOG_CONSOLE(void) #define SUNZILOG_CONSOLE() (NULL) #endif -static void __devinit sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channel) +static void __devinit sunzilog_init_kbdms(struct uart_sunzilog_port *up) { int baud, brg; @@ -1313,7 +1305,7 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up) up->curregs[R7] = 0x7E; /* SDLC Flag */ up->curregs[R9] = NV; up->curregs[R7p] = 0x00; - sunzilog_init_kbdms(up, up->port.line); + sunzilog_init_kbdms(up); /* Only enable interrupts if an ISR handler available */ if (up->flags & SUNZILOG_FLAG_ISR_HANDLER) up->curregs[R9] |= MIE; @@ -1359,16 +1351,22 @@ static int zilog_irq = -1; static int __devinit zs_probe(struct of_device *op, const struct of_device_id *match) { - static int inst; + static int kbm_inst, uart_inst; + int inst; struct uart_sunzilog_port *up; struct zilog_layout __iomem *rp; - int keyboard_mouse; + int keyboard_mouse = 0; int err; - keyboard_mouse = 0; if (of_find_property(op->node, "keyboard", NULL)) keyboard_mouse = 1; + /* uarts must come before keyboards/mice */ + if (keyboard_mouse) + inst = uart_chip_count + kbm_inst; + else + inst = uart_inst; + sunzilog_chip_regs[inst] = of_ioremap(&op->resource[0], 0, sizeof(struct zilog_layout), "zs"); @@ -1417,12 +1415,20 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m sunzilog_init_hw(&up[1]); if (!keyboard_mouse) { + if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node, + &sunzilog_reg, up[0].port.line, + false)) + up->flags |= SUNZILOG_FLAG_IS_CONS; err = uart_add_one_port(&sunzilog_reg, &up[0].port); if (err) { of_iounmap(&op->resource[0], rp, sizeof(struct zilog_layout)); return err; } + if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node, + &sunzilog_reg, up[1].port.line, + false)) + up->flags |= SUNZILOG_FLAG_IS_CONS; err = uart_add_one_port(&sunzilog_reg, &up[1].port); if (err) { uart_remove_one_port(&sunzilog_reg, &up[0].port); @@ -1430,21 +1436,23 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m rp, sizeof(struct zilog_layout)); return err; } + uart_inst++; } else { - printk(KERN_INFO "%s: Keyboard at MMIO 0x%lx (irq = %d) " + printk(KERN_INFO "%s: Keyboard at MMIO 0x%llx (irq = %d) " "is a %s\n", - op->dev.bus_id, up[0].port.mapbase, op->irqs[0], - sunzilog_type (&up[0].port)); - printk(KERN_INFO "%s: Mouse at MMIO 0x%lx (irq = %d) " + dev_name(&op->dev), + (unsigned long long) up[0].port.mapbase, + op->irqs[0], sunzilog_type(&up[0].port)); + printk(KERN_INFO "%s: Mouse at MMIO 0x%llx (irq = %d) " "is a %s\n", - op->dev.bus_id, up[1].port.mapbase, op->irqs[0], - sunzilog_type (&up[1].port)); + dev_name(&op->dev), + (unsigned long long) up[1].port.mapbase, + op->irqs[0], sunzilog_type(&up[1].port)); + kbm_inst++; } dev_set_drvdata(&op->dev, &up[0]); - inst++; - return 0; } @@ -1474,7 +1482,7 @@ static int __devexit zs_remove(struct of_device *op) return 0; } -static struct of_device_id zs_match[] = { +static const struct of_device_id zs_match[] = { { .name = "zs", }, @@ -1492,37 +1500,27 @@ static struct of_platform_driver zs_driver = { static int __init sunzilog_init(void) { struct device_node *dp; - int err, uart_count; - int num_keybms; + int err; + int num_keybms = 0; + int num_sunzilog = 0; - NUM_SUNZILOG = 0; - num_keybms = 0; for_each_node_by_name(dp, "zs") { - NUM_SUNZILOG++; + num_sunzilog++; if (of_find_property(dp, "keyboard", NULL)) num_keybms++; } - uart_count = 0; - if (NUM_SUNZILOG) { - int uart_count; - - err = sunzilog_alloc_tables(); + if (num_sunzilog) { + err = sunzilog_alloc_tables(num_sunzilog); if (err) goto out; - uart_count = (NUM_SUNZILOG * 2) - (2 * num_keybms); + uart_chip_count = num_sunzilog - num_keybms; - sunzilog_reg.nr = uart_count; - sunzilog_reg.minor = sunserial_current_minor; - err = uart_register_driver(&sunzilog_reg); + err = sunserial_register_minors(&sunzilog_reg, + uart_chip_count * 2); if (err) goto out_free_tables; - - sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64; - sunzilog_reg.cons = SUNZILOG_CONSOLE(); - - sunserial_current_minor += uart_count; } err = of_register_driver(&zs_driver, &of_bus_type); @@ -1556,8 +1554,8 @@ out_unregister_driver: of_unregister_driver(&zs_driver); out_unregister_uart: - if (NUM_SUNZILOG) { - uart_unregister_driver(&sunzilog_reg); + if (num_sunzilog) { + sunserial_unregister_minors(&sunzilog_reg, num_sunzilog); sunzilog_reg.cons = NULL; } @@ -1589,8 +1587,8 @@ static void __exit sunzilog_exit(void) zilog_irq = -1; } - if (NUM_SUNZILOG) { - uart_unregister_driver(&sunzilog_reg); + if (sunzilog_reg.nr) { + sunserial_unregister_minors(&sunzilog_reg, sunzilog_reg.nr); sunzilog_free_tables(); } }