amba-pl010.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 827 行 · 第 1/2 页
C
827 行
}static voidpl010_set_termios(struct uart_port *port, struct termios *termios, struct termios *old){ unsigned int lcr_h, old_cr; unsigned long flags; unsigned int baud, quot; /* * Ask the core to calculate the divisor for us. */ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); quot = uart_get_divisor(port, baud); switch (termios->c_cflag & CSIZE) { case CS5: lcr_h = UART01x_LCRH_WLEN_5; break; case CS6: lcr_h = UART01x_LCRH_WLEN_6; break; case CS7: lcr_h = UART01x_LCRH_WLEN_7; break; default: // CS8 lcr_h = UART01x_LCRH_WLEN_8; break; } if (termios->c_cflag & CSTOPB) lcr_h |= UART01x_LCRH_STP2; if (termios->c_cflag & PARENB) { lcr_h |= UART01x_LCRH_PEN; if (!(termios->c_cflag & PARODD)) lcr_h |= UART01x_LCRH_EPS; } if (port->fifosize > 1) lcr_h |= UART01x_LCRH_FEN; spin_lock_irqsave(&port->lock, flags); /* * Update the per-port timeout. */ uart_update_timeout(port, termios->c_cflag, baud); port->read_status_mask = UART01x_RSR_OE; if (termios->c_iflag & INPCK) port->read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; if (termios->c_iflag & (BRKINT | PARMRK)) port->read_status_mask |= UART01x_RSR_BE; /* * Characters to ignore */ port->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) port->ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; if (termios->c_iflag & IGNBRK) { port->ignore_status_mask |= UART01x_RSR_BE; /* * If we're ignoring parity and break indicators, * ignore overruns too (for real raw support). */ if (termios->c_iflag & IGNPAR) port->ignore_status_mask |= UART01x_RSR_OE; } /* * Ignore all characters if CREAD is not set. */ if ((termios->c_cflag & CREAD) == 0) port->ignore_status_mask |= UART_DUMMY_RSR_RX; /* first, disable everything */ old_cr = UART_GET_CR(port) & ~UART010_CR_MSIE; if (UART_ENABLE_MS(port, termios->c_cflag)) old_cr |= UART010_CR_MSIE; UART_PUT_CR(port, 0); /* Set baud rate */ quot -= 1; UART_PUT_LCRM(port, ((quot & 0xf00) >> 8)); UART_PUT_LCRL(port, (quot & 0xff)); /* * ----------v----------v----------v----------v----- * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L * ----------^----------^----------^----------^----- */ UART_PUT_LCRH(port, lcr_h); UART_PUT_CR(port, old_cr); spin_unlock_irqrestore(&port->lock, flags);}static const char *pl010_type(struct uart_port *port){ return port->type == PORT_AMBA ? "AMBA" : NULL;}/* * Release the memory region(s) being used by 'port' */static void pl010_release_port(struct uart_port *port){ release_mem_region(port->mapbase, UART_PORT_SIZE);}/* * Request the memory region(s) being used by 'port' */static int pl010_request_port(struct uart_port *port){ return request_mem_region(port->mapbase, UART_PORT_SIZE, "uart-pl010") != NULL ? 0 : -EBUSY;}/* * Configure/autoconfigure the port. */static void pl010_config_port(struct uart_port *port, int flags){ if (flags & UART_CONFIG_TYPE) { port->type = PORT_AMBA; pl010_request_port(port); }}/* * verify the new serial_struct (for TIOCSSERIAL). */static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser){ int ret = 0; if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA) ret = -EINVAL; if (ser->irq < 0 || ser->irq >= NR_IRQS) ret = -EINVAL; if (ser->baud_base < 9600) ret = -EINVAL; return ret;}static struct uart_ops amba_pl010_pops = { .tx_empty = pl010_tx_empty, .set_mctrl = pl010_set_mctrl, .get_mctrl = pl010_get_mctrl, .stop_tx = pl010_stop_tx, .start_tx = pl010_start_tx, .stop_rx = pl010_stop_rx, .enable_ms = pl010_enable_ms, .break_ctl = pl010_break_ctl, .startup = pl010_startup, .shutdown = pl010_shutdown, .set_termios = pl010_set_termios, .type = pl010_type, .release_port = pl010_release_port, .request_port = pl010_request_port, .config_port = pl010_config_port, .verify_port = pl010_verify_port,};static struct uart_amba_port amba_ports[UART_NR] = { { .port = { .membase = (void *)IO_ADDRESS(INTEGRATOR_UART0_BASE), .mapbase = INTEGRATOR_UART0_BASE, .iotype = SERIAL_IO_MEM, .irq = IRQ_UARTINT0, .uartclk = 14745600, .fifosize = 16, .ops = &amba_pl010_pops, .flags = ASYNC_BOOT_AUTOCONF, .line = 0, }, .dtr_mask = 1 << 5, .rts_mask = 1 << 4, }, { .port = { .membase = (void *)IO_ADDRESS(INTEGRATOR_UART1_BASE), .mapbase = INTEGRATOR_UART1_BASE, .iotype = SERIAL_IO_MEM, .irq = IRQ_UARTINT1, .uartclk = 14745600, .fifosize = 16, .ops = &amba_pl010_pops, .flags = ASYNC_BOOT_AUTOCONF, .line = 1, }, .dtr_mask = 1 << 7, .rts_mask = 1 << 6, }};#ifdef CONFIG_SERIAL_AMBA_PL010_CONSOLEstatic voidpl010_console_write(struct console *co, const char *s, unsigned int count){ struct uart_port *port = &amba_ports[co->index].port; unsigned int status, old_cr; int i; /* * First save the CR then disable the interrupts */ old_cr = UART_GET_CR(port); UART_PUT_CR(port, UART01x_CR_UARTEN); /* * Now, do each character */ for (i = 0; i < count; i++) { do { status = UART_GET_FR(port); } while (!UART_TX_READY(status)); UART_PUT_CHAR(port, s[i]); if (s[i] == '\n') { do { status = UART_GET_FR(port); } while (!UART_TX_READY(status)); UART_PUT_CHAR(port, '\r'); } } /* * Finally, wait for transmitter to become empty * and restore the TCR */ do { status = UART_GET_FR(port); } while (status & UART01x_FR_BUSY); UART_PUT_CR(port, old_cr);}static void __initpl010_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits){ if (UART_GET_CR(port) & UART01x_CR_UARTEN) { unsigned int lcr_h, quot; lcr_h = UART_GET_LCRH(port); *parity = 'n'; if (lcr_h & UART01x_LCRH_PEN) { if (lcr_h & UART01x_LCRH_EPS) *parity = 'e'; else *parity = 'o'; } if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7) *bits = 7; else *bits = 8; quot = UART_GET_LCRL(port) | UART_GET_LCRM(port) << 8; *baud = port->uartclk / (16 * (quot + 1)); }}static int __init pl010_console_setup(struct console *co, char *options){ struct uart_port *port; int baud = 38400; int bits = 8; int parity = 'n'; int flow = 'n'; /* * Check whether an invalid uart number has been specified, and * if so, search for the first available port that does have * console support. */ if (co->index >= UART_NR) co->index = 0; port = &amba_ports[co->index].port; if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else pl010_console_get_options(port, &baud, &parity, &bits); return uart_set_options(port, co, baud, parity, bits, flow);}extern struct uart_driver amba_reg;static struct console amba_console = { .name = "ttyAM", .write = pl010_console_write, .device = uart_console_device, .setup = pl010_console_setup, .flags = CON_PRINTBUFFER, .index = -1, .data = &amba_reg,};#define AMBA_CONSOLE &amba_console#else#define AMBA_CONSOLE NULL#endifstatic struct uart_driver amba_reg = { .owner = THIS_MODULE, .driver_name = "ttyAM", .dev_name = "ttyAM", .major = SERIAL_AMBA_MAJOR, .minor = SERIAL_AMBA_MINOR, .nr = UART_NR, .cons = AMBA_CONSOLE,};static int pl010_probe(struct amba_device *dev, void *id){ int i; for (i = 0; i < UART_NR; i++) { if (amba_ports[i].port.mapbase != dev->res.start) continue; amba_ports[i].port.dev = &dev->dev; uart_add_one_port(&amba_reg, &amba_ports[i].port); amba_set_drvdata(dev, &amba_ports[i]); break; } return 0;}static int pl010_remove(struct amba_device *dev){ struct uart_amba_port *uap = amba_get_drvdata(dev); if (uap) uart_remove_one_port(&amba_reg, &uap->port); amba_set_drvdata(dev, NULL); return 0;}static int pl010_suspend(struct amba_device *dev, u32 state){ struct uart_amba_port *uap = amba_get_drvdata(dev); if (uap) uart_suspend_port(&amba_reg, &uap->port); return 0;}static int pl010_resume(struct amba_device *dev){ struct uart_amba_port *uap = amba_get_drvdata(dev); if (uap) uart_resume_port(&amba_reg, &uap->port); return 0;}static struct amba_id pl010_ids[] __initdata = { { .id = 0x00041010, .mask = 0x000fffff, }, { 0, 0 },};static struct amba_driver pl010_driver = { .drv = { .name = "uart-pl010", }, .id_table = pl010_ids, .probe = pl010_probe, .remove = pl010_remove, .suspend = pl010_suspend, .resume = pl010_resume,};static int __init pl010_init(void){ int ret; printk(KERN_INFO "Serial: AMBA driver $Revision: 1.41 $\n"); ret = uart_register_driver(&amba_reg); if (ret == 0) { ret = amba_driver_register(&pl010_driver); if (ret) uart_unregister_driver(&amba_reg); } return ret;}static void __exit pl010_exit(void){ amba_driver_unregister(&pl010_driver); uart_unregister_driver(&amba_reg);}module_init(pl010_init);module_exit(pl010_exit);MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");MODULE_DESCRIPTION("ARM AMBA serial port driver $Revision: 1.41 $");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?