vr41xx_siu.c
来自「linux 内核源代码」· C语言 代码 · 共 963 行 · 第 1/2 页
C
963 行
(void)siu_read(port, UART_IIR); (void)siu_read(port, UART_MSR); return 0;}static void siu_shutdown(struct uart_port *port){ unsigned long flags; uint8_t lcr; siu_write(port, UART_IER, 0); spin_lock_irqsave(&port->lock, flags); port->mctrl &= ~TIOCM_OUT2; siu_set_mctrl(port, port->mctrl); spin_unlock_irqrestore(&port->lock, flags); lcr = siu_read(port, UART_LCR); lcr &= ~UART_LCR_SBC; siu_write(port, UART_LCR, lcr); siu_clear_fifo(port); (void)siu_read(port, UART_RX); if (port->type == PORT_VR41XX_DSIU) vr41xx_disable_dsiuint(DSIUINT_ALL); free_irq(port->irq, port);}static void siu_set_termios(struct uart_port *port, struct ktermios *new, struct ktermios *old){ tcflag_t c_cflag, c_iflag; uint8_t lcr, fcr, ier; unsigned int baud, quot; unsigned long flags; c_cflag = new->c_cflag; switch (c_cflag & CSIZE) { case CS5: lcr = UART_LCR_WLEN5; break; case CS6: lcr = UART_LCR_WLEN6; break; case CS7: lcr = UART_LCR_WLEN7; break; default: lcr = UART_LCR_WLEN8; break; } if (c_cflag & CSTOPB) lcr |= UART_LCR_STOP; if (c_cflag & PARENB) lcr |= UART_LCR_PARITY; if ((c_cflag & PARODD) != PARODD) lcr |= UART_LCR_EPAR; if (c_cflag & CMSPAR) lcr |= UART_LCR_SPAR; baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16); quot = uart_get_divisor(port, baud); fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10; spin_lock_irqsave(&port->lock, flags); uart_update_timeout(port, c_cflag, baud); c_iflag = new->c_iflag; port->read_status_mask = UART_LSR_THRE | UART_LSR_OE | UART_LSR_DR; if (c_iflag & INPCK) port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; if (c_iflag & (BRKINT | PARMRK)) port->read_status_mask |= UART_LSR_BI; port->ignore_status_mask = 0; if (c_iflag & IGNPAR) port->ignore_status_mask |= UART_LSR_FE | UART_LSR_PE; if (c_iflag & IGNBRK) { port->ignore_status_mask |= UART_LSR_BI; if (c_iflag & IGNPAR) port->ignore_status_mask |= UART_LSR_OE; } if ((c_cflag & CREAD) == 0) port->ignore_status_mask |= UART_LSR_DR; ier = siu_read(port, UART_IER); ier &= ~UART_IER_MSI; if (UART_ENABLE_MS(port, c_cflag)) ier |= UART_IER_MSI; siu_write(port, UART_IER, ier); siu_write(port, UART_LCR, lcr | UART_LCR_DLAB); siu_write(port, UART_DLL, (uint8_t)quot); siu_write(port, UART_DLM, (uint8_t)(quot >> 8)); siu_write(port, UART_LCR, lcr); siu_write(port, UART_FCR, fcr); siu_set_mctrl(port, port->mctrl); spin_unlock_irqrestore(&port->lock, flags);}static void siu_pm(struct uart_port *port, unsigned int state, unsigned int oldstate){ switch (state) { case 0: switch (port->type) { case PORT_VR41XX_SIU: vr41xx_supply_clock(SIU_CLOCK); break; case PORT_VR41XX_DSIU: vr41xx_supply_clock(DSIU_CLOCK); break; } break; case 3: switch (port->type) { case PORT_VR41XX_SIU: vr41xx_mask_clock(SIU_CLOCK); break; case PORT_VR41XX_DSIU: vr41xx_mask_clock(DSIU_CLOCK); break; } break; }}static const char *siu_type(struct uart_port *port){ return siu_type_name(port);}static void siu_release_port(struct uart_port *port){ unsigned long size; if (port->flags & UPF_IOREMAP) { iounmap(port->membase); port->membase = NULL; } size = siu_port_size(port); release_mem_region(port->mapbase, size);}static int siu_request_port(struct uart_port *port){ unsigned long size; struct resource *res; size = siu_port_size(port); res = request_mem_region(port->mapbase, size, siu_type_name(port)); if (res == NULL) return -EBUSY; if (port->flags & UPF_IOREMAP) { port->membase = ioremap(port->mapbase, size); if (port->membase == NULL) { release_resource(res); return -ENOMEM; } } return 0;}static void siu_config_port(struct uart_port *port, int flags){ if (flags & UART_CONFIG_TYPE) { port->type = siu_check_type(port); (void)siu_request_port(port); }}static int siu_verify_port(struct uart_port *port, struct serial_struct *serial){ if (port->type != PORT_VR41XX_SIU && port->type != PORT_VR41XX_DSIU) return -EINVAL; if (port->irq != serial->irq) return -EINVAL; if (port->iotype != serial->io_type) return -EINVAL; if (port->mapbase != (unsigned long)serial->iomem_base) return -EINVAL; return 0;}static struct uart_ops siu_uart_ops = { .tx_empty = siu_tx_empty, .set_mctrl = siu_set_mctrl, .get_mctrl = siu_get_mctrl, .stop_tx = siu_stop_tx, .start_tx = siu_start_tx, .stop_rx = siu_stop_rx, .enable_ms = siu_enable_ms, .break_ctl = siu_break_ctl, .startup = siu_startup, .shutdown = siu_shutdown, .set_termios = siu_set_termios, .pm = siu_pm, .type = siu_type, .release_port = siu_release_port, .request_port = siu_request_port, .config_port = siu_config_port, .verify_port = siu_verify_port,};static int siu_init_ports(struct platform_device *pdev){ struct uart_port *port; struct resource *res; int *type = pdev->dev.platform_data; int i; if (!type) return 0; port = siu_uart_ports; for (i = 0; i < SIU_PORTS_MAX; i++) { port->type = type[i]; if (port->type == PORT_UNKNOWN) continue; port->irq = platform_get_irq(pdev, i); port->uartclk = SIU_BAUD_BASE * 16; port->fifosize = 16; port->regshift = 0; port->iotype = UPIO_MEM; port->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; port->line = i; res = platform_get_resource(pdev, IORESOURCE_MEM, i); port->mapbase = res->start; port++; } return i;}#ifdef CONFIG_SERIAL_VR41XX_CONSOLE#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)static void wait_for_xmitr(struct uart_port *port){ int timeout = 10000; uint8_t lsr, msr; do { lsr = siu_read(port, UART_LSR); if (lsr & UART_LSR_BI) lsr_break_flag[port->line] = UART_LSR_BI; if ((lsr & BOTH_EMPTY) == BOTH_EMPTY) break; } while (timeout-- > 0); if (port->flags & UPF_CONS_FLOW) { timeout = 1000000; do { msr = siu_read(port, UART_MSR); if ((msr & UART_MSR_CTS) != 0) break; } while (timeout-- > 0); }}static void siu_console_putchar(struct uart_port *port, int ch){ wait_for_xmitr(port); siu_write(port, UART_TX, ch);}static void siu_console_write(struct console *con, const char *s, unsigned count){ struct uart_port *port; uint8_t ier; port = &siu_uart_ports[con->index]; ier = siu_read(port, UART_IER); siu_write(port, UART_IER, 0); uart_console_write(port, s, count, siu_console_putchar); wait_for_xmitr(port); siu_write(port, UART_IER, ier);}static int __init siu_console_setup(struct console *con, char *options){ struct uart_port *port; int baud = 9600; int parity = 'n'; int bits = 8; int flow = 'n'; if (con->index >= SIU_PORTS_MAX) con->index = 0; port = &siu_uart_ports[con->index]; if (port->membase == NULL) { if (port->mapbase == 0) return -ENODEV; port->membase = ioremap(port->mapbase, siu_port_size(port)); } if (port->type == PORT_VR41XX_SIU) vr41xx_select_siu_interface(SIU_INTERFACE_RS232C); if (options != NULL) uart_parse_options(options, &baud, &parity, &bits, &flow); return uart_set_options(port, con, baud, parity, bits, flow);}static struct uart_driver siu_uart_driver;static struct console siu_console = { .name = "ttyVR", .write = siu_console_write, .device = uart_console_device, .setup = siu_console_setup, .flags = CON_PRINTBUFFER, .index = -1, .data = &siu_uart_driver,};static int __devinit siu_console_init(void){ struct uart_port *port; int i; for (i = 0; i < SIU_PORTS_MAX; i++) { port = &siu_uart_ports[i]; port->ops = &siu_uart_ops; } register_console(&siu_console); return 0;}console_initcall(siu_console_init);#define SERIAL_VR41XX_CONSOLE &siu_console#else#define SERIAL_VR41XX_CONSOLE NULL#endifstatic struct uart_driver siu_uart_driver = { .owner = THIS_MODULE, .driver_name = "SIU", .dev_name = "ttyVR", .major = SIU_MAJOR, .minor = SIU_MINOR_BASE, .cons = SERIAL_VR41XX_CONSOLE,};static int __devinit siu_probe(struct platform_device *dev){ struct uart_port *port; int num, i, retval; num = siu_init_ports(dev); if (num <= 0) return -ENODEV; siu_uart_driver.nr = num; retval = uart_register_driver(&siu_uart_driver); if (retval) return retval; for (i = 0; i < num; i++) { port = &siu_uart_ports[i]; port->ops = &siu_uart_ops; port->dev = &dev->dev; retval = uart_add_one_port(&siu_uart_driver, port); if (retval < 0) { port->dev = NULL; break; } } if (i == 0 && retval < 0) { uart_unregister_driver(&siu_uart_driver); return retval; } return 0;}static int __devexit siu_remove(struct platform_device *dev){ struct uart_port *port; int i; for (i = 0; i < siu_uart_driver.nr; i++) { port = &siu_uart_ports[i]; if (port->dev == &dev->dev) { uart_remove_one_port(&siu_uart_driver, port); port->dev = NULL; } } uart_unregister_driver(&siu_uart_driver); return 0;}static int siu_suspend(struct platform_device *dev, pm_message_t state){ struct uart_port *port; int i; for (i = 0; i < siu_uart_driver.nr; i++) { port = &siu_uart_ports[i]; if ((port->type == PORT_VR41XX_SIU || port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev) uart_suspend_port(&siu_uart_driver, port); } return 0;}static int siu_resume(struct platform_device *dev){ struct uart_port *port; int i; for (i = 0; i < siu_uart_driver.nr; i++) { port = &siu_uart_ports[i]; if ((port->type == PORT_VR41XX_SIU || port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev) uart_resume_port(&siu_uart_driver, port); } return 0;}static struct platform_driver siu_device_driver = { .probe = siu_probe, .remove = __devexit_p(siu_remove), .suspend = siu_suspend, .resume = siu_resume, .driver = { .name = "SIU", .owner = THIS_MODULE, },};static int __init vr41xx_siu_init(void){ return platform_driver_register(&siu_device_driver);}static void __exit vr41xx_siu_exit(void){ platform_driver_unregister(&siu_device_driver);}module_init(vr41xx_siu_init);module_exit(vr41xx_siu_exit);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?