ip22zilog.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,308 行 · 第 1/3 页
C
1,308 行
ip22zilog_set_termios(struct uart_port *port, struct termios *termios, struct termios *old){ struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port; unsigned long flags; int baud, brg; baud = uart_get_baud_rate(port, termios, old, 1200, 76800); spin_lock_irqsave(&up->port.lock, flags); brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); ip22zilog_convert_to_zs(up, termios->c_cflag, termios->c_iflag, brg); if (UART_ENABLE_MS(&up->port, termios->c_cflag)) up->flags |= IP22ZILOG_FLAG_MODEM_STATUS; else up->flags &= ~IP22ZILOG_FLAG_MODEM_STATUS; up->cflag = termios->c_cflag; ip22zilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port)); spin_unlock_irqrestore(&up->port.lock, flags);}static const char *ip22zilog_type(struct uart_port *port){ return "IP22-Zilog";}/* We do not request/release mappings of the registers here, this * happens at early serial probe time. */static void ip22zilog_release_port(struct uart_port *port){}static int ip22zilog_request_port(struct uart_port *port){ return 0;}/* These do not need to do anything interesting either. */static void ip22zilog_config_port(struct uart_port *port, int flags){}/* We do not support letting the user mess with the divisor, IRQ, etc. */static int ip22zilog_verify_port(struct uart_port *port, struct serial_struct *ser){ return -EINVAL;}static struct uart_ops ip22zilog_pops = { .tx_empty = ip22zilog_tx_empty, .set_mctrl = ip22zilog_set_mctrl, .get_mctrl = ip22zilog_get_mctrl, .stop_tx = ip22zilog_stop_tx, .start_tx = ip22zilog_start_tx, .stop_rx = ip22zilog_stop_rx, .enable_ms = ip22zilog_enable_ms, .break_ctl = ip22zilog_break_ctl, .startup = ip22zilog_startup, .shutdown = ip22zilog_shutdown, .set_termios = ip22zilog_set_termios, .type = ip22zilog_type, .release_port = ip22zilog_release_port, .request_port = ip22zilog_request_port, .config_port = ip22zilog_config_port, .verify_port = ip22zilog_verify_port,};static struct uart_ip22zilog_port *ip22zilog_port_table;static struct zilog_layout **ip22zilog_chip_regs;static struct uart_ip22zilog_port *ip22zilog_irq_chain;static int zilog_irq = -1;static struct uart_driver ip22zilog_reg = { .owner = THIS_MODULE, .driver_name = "ttyS", .devfs_name = "tty/", .major = TTY_MAJOR,};static void * __init alloc_one_table(unsigned long size){ void *ret; ret = kmalloc(size, GFP_KERNEL); if (ret != NULL) memset(ret, 0, size); return ret;}static void __init ip22zilog_alloc_tables(void){ ip22zilog_port_table = (struct uart_ip22zilog_port *) alloc_one_table(NUM_CHANNELS * sizeof(struct uart_ip22zilog_port)); ip22zilog_chip_regs = (struct zilog_layout **) alloc_one_table(NUM_IP22ZILOG * sizeof(struct zilog_layout *)); if (ip22zilog_port_table == NULL || ip22zilog_chip_regs == NULL) { panic("IP22-Zilog: Cannot allocate IP22-Zilog tables."); }}/* Get the address of the registers for IP22-Zilog instance CHIP. */static struct zilog_layout * __init get_zs(int chip){ unsigned long base; if (chip < 0 || chip >= NUM_IP22ZILOG) { panic("IP22-Zilog: Illegal chip number %d in get_zs.", chip); } /* Not probe-able, hard code it. */ base = (unsigned long) &sgioc->serport; zilog_irq = SGI_SERIAL_IRQ; request_mem_region(base, 8, "IP22-Zilog"); return (struct zilog_layout *) base;}#define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */#ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLEstatic void ip22zilog_put_char(struct zilog_channel *channel, unsigned char ch){ int loops = ZS_PUT_CHAR_MAX_DELAY; /* This is a timed polling loop so do not switch the explicit * udelay with ZSDELAY as that is a NOP on some platforms. -DaveM */ do { unsigned char val = readb(&channel->control); if (val & Tx_BUF_EMP) { ZSDELAY(); break; } udelay(5); } while (--loops); writeb(ch, &channel->data); ZSDELAY(); ZS_WSYNC(channel);}static voidip22zilog_console_write(struct console *con, const char *s, unsigned int count){ struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index]; struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(&up->port); unsigned long flags; int i; spin_lock_irqsave(&up->port.lock, flags); for (i = 0; i < count; i++, s++) { ip22zilog_put_char(channel, *s); if (*s == 10) ip22zilog_put_char(channel, 13); } udelay(2); spin_unlock_irqrestore(&up->port.lock, flags);}voidip22serial_console_termios(struct console *con, char *options){ int baud = 9600, bits = 8, cflag; int parity = 'n'; int flow = 'n'; if (!serial_console) return; if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); cflag = CREAD | HUPCL | CLOCAL; switch (baud) { case 150: cflag |= B150; break; case 300: cflag |= B300; break; case 600: cflag |= B600; break; 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; default: baud = 9600; cflag |= B9600; break; } con->cflag = cflag | CS8; /* 8N1 */}static int __init ip22zilog_console_setup(struct console *con, char *options){ struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index]; unsigned long flags; int baud, brg; printk("Console: ttyS%d (IP22-Zilog)\n", (ip22zilog_reg.minor - 64) + con->index); /* Get firmware console settings. */ ip22serial_console_termios(con, options); /* Firmware console speed is limited to 150-->38400 baud so * this hackish cflag thing is OK. */ switch (con->cflag & CBAUD) { case B150: baud = 150; break; case B300: baud = 300; break; case B600: baud = 600; break; case B1200: baud = 1200; 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; }; brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); spin_lock_irqsave(&up->port.lock, flags); up->curregs[R15] = BRKIE; ip22zilog_convert_to_zs(up, con->cflag, 0, brg); __ip22zilog_startup(up); spin_unlock_irqrestore(&up->port.lock, flags); return 0;}static struct console ip22zilog_console = { .name = "ttyS", .write = ip22zilog_console_write, .device = uart_console_device, .setup = ip22zilog_console_setup, .flags = CON_PRINTBUFFER, .index = -1, .data = &ip22zilog_reg,};#define IP22ZILOG_CONSOLE (&ip22zilog_console)static int __init ip22zilog_console_init(void){ int i; if (con_is_present()) return 0; for (i = 0; i < NUM_CHANNELS; i++) { int this_minor = ip22zilog_reg.minor + i; if ((this_minor - 64) == (serial_console - 1)) break; } if (i == NUM_CHANNELS) return 0; ip22zilog_console.index = i; register_console(&ip22zilog_console); return 0;}#else /* CONFIG_SERIAL_IP22_ZILOG_CONSOLE */#define IP22ZILOG_CONSOLE (NULL)#define ip22zilog_console_init() do { } while (0)#endifstatic void __init ip22zilog_prepare(void){ struct uart_ip22zilog_port *up; struct zilog_layout *rp; int channel, chip; /* * Temporary fix. */ for (channel = 0; channel < NUM_CHANNELS; channel++) spin_lock_init(&ip22zilog_port_table[channel].port.lock); ip22zilog_irq_chain = up = &ip22zilog_port_table[0]; for (channel = 0; channel < NUM_CHANNELS - 1; channel++) up[channel].next = &up[channel + 1]; up[channel].next = NULL; for (chip = 0; chip < NUM_IP22ZILOG; chip++) { if (!ip22zilog_chip_regs[chip]) { ip22zilog_chip_regs[chip] = rp = get_zs(chip); up[(chip * 2) + 0].port.membase = (char *) &rp->channelA; up[(chip * 2) + 1].port.membase = (char *) &rp->channelB; } /* Channel A */ up[(chip * 2) + 0].port.iotype = UPIO_MEM; up[(chip * 2) + 0].port.irq = zilog_irq; up[(chip * 2) + 0].port.uartclk = ZS_CLOCK; up[(chip * 2) + 0].port.fifosize = 1; up[(chip * 2) + 0].port.ops = &ip22zilog_pops; up[(chip * 2) + 0].port.type = PORT_IP22ZILOG; up[(chip * 2) + 0].port.flags = 0; up[(chip * 2) + 0].port.line = (chip * 2) + 0; up[(chip * 2) + 0].flags |= IP22ZILOG_FLAG_IS_CHANNEL_A; /* Channel B */ up[(chip * 2) + 1].port.iotype = UPIO_MEM; up[(chip * 2) + 1].port.irq = zilog_irq; up[(chip * 2) + 1].port.uartclk = ZS_CLOCK; up[(chip * 2) + 1].port.fifosize = 1; up[(chip * 2) + 1].port.ops = &ip22zilog_pops; up[(chip * 2) + 1].port.type = PORT_IP22ZILOG; up[(chip * 2) + 1].port.flags = 0; up[(chip * 2) + 1].port.line = (chip * 2) + 1; up[(chip * 2) + 1].flags |= 0; }}static void __init ip22zilog_init_hw(void){ int i; for (i = 0; i < NUM_CHANNELS; i++) { struct uart_ip22zilog_port *up = &ip22zilog_port_table[i]; struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(&up->port); unsigned long flags; int baud, brg; spin_lock_irqsave(&up->port.lock, flags); if (ZS_IS_CHANNEL_A(up)) { write_zsreg(channel, R9, FHWRES); ZSDELAY_LONG(); (void) read_zsreg(channel, R0); } /* Normal serial TTY. */ up->parity_mask = 0xff; up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; up->curregs[R4] = PAR_EVEN | X16CLK | SB1; up->curregs[R3] = RxENAB | Rx8; up->curregs[R5] = TxENAB | Tx8; up->curregs[R9] = NV | MIE; up->curregs[R10] = NRZ; up->curregs[R11] = TCBR | RCBR; baud = 9600; brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); up->curregs[R12] = (brg & 0xff); up->curregs[R13] = (brg >> 8) & 0xff; up->curregs[R14] = BRSRC | BRENAB; __load_zsregs(channel, up->curregs); spin_unlock_irqrestore(&up->port.lock, flags); }}static int __init ip22zilog_ports_init(void){ int ret; printk(KERN_INFO "Serial: IP22 Zilog driver (%d chips).\n", NUM_IP22ZILOG); ip22zilog_prepare(); if (request_irq(zilog_irq, ip22zilog_interrupt, 0, "IP22-Zilog", ip22zilog_irq_chain)) { panic("IP22-Zilog: Unable to register zs interrupt handler.\n"); } ip22zilog_init_hw(); /* We can only init this once we have probed the Zilogs * in the system. */ ip22zilog_reg.nr = NUM_CHANNELS; ip22zilog_reg.cons = IP22ZILOG_CONSOLE; ip22zilog_reg.minor = ip22serial_current_minor; ip22serial_current_minor += NUM_CHANNELS; ret = uart_register_driver(&ip22zilog_reg); if (ret == 0) { int i; for (i = 0; i < NUM_CHANNELS; i++) { struct uart_ip22zilog_port *up = &ip22zilog_port_table[i]; uart_add_one_port(&ip22zilog_reg, &up->port); } } return ret;}static int __init ip22zilog_init(void){ /* IP22 Zilog setup is hard coded, no probing to do. */ ip22zilog_alloc_tables(); ip22zilog_ports_init(); ip22zilog_console_init(); return 0;}static void __exit ip22zilog_exit(void){ int i; for (i = 0; i < NUM_CHANNELS; i++) { struct uart_ip22zilog_port *up = &ip22zilog_port_table[i]; uart_remove_one_port(&ip22zilog_reg, &up->port); } uart_unregister_driver(&ip22zilog_reg);}module_init(ip22zilog_init);module_exit(ip22zilog_exit);/* David wrote it but I'm to blame for the bugs ... */MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");MODULE_DESCRIPTION("SGI Zilog serial port driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?