📄 s3c2410.c
字号:
serial_s3c2410_request_port(port) == 0) port->type = PORT_S3C2410;}/* * verify the new serial_struct (for TIOCSSERIAL). */static intserial_s3c2410_verify_port(struct uart_port *port, struct serial_struct *ser){ int ret = 0; if (ser->type != PORT_UNKNOWN && ser->type != PORT_S3C2410) ret = -EINVAL; return ret;}static struct uart_ops serial_s3c2410_ops = { .tx_empty = serial_s3c2410_tx_empty, .get_mctrl = serial_s3c2410_get_mctrl, .set_mctrl = serial_s3c2410_set_mctrl, .stop_tx = serial_s3c2410_stop_tx, .start_tx = serial_s3c2410_start_tx, .stop_rx = serial_s3c2410_stop_rx, .enable_ms = serial_s3c2410_enable_ms, .break_ctl = serial_s3c2410_break_ctl, .startup = serial_s3c2410_startup, .shutdown = serial_s3c2410_shutdown, .set_termios = serial_s3c2410_set_termios, .type = serial_s3c2410_type, .release_port = serial_s3c2410_release_port, .request_port = serial_s3c2410_request_port, .config_port = serial_s3c2410_config_port, .verify_port = serial_s3c2410_verify_port,};static struct uart_port serial_s3c2410_ports[NR_PORTS] = { { .membase = 0, .mapbase = 0, .iotype = UPIO_MEM, .irq = IRQ_S3CUART_RX0, .uartclk = 0, .fifosize = 16, .ops = &serial_s3c2410_ops, .flags = UPF_BOOT_AUTOCONF, .line = 0, }, { .membase = 0, .mapbase = 0, .iotype = UPIO_MEM, .irq = IRQ_S3CUART_RX1, .uartclk = 0, .fifosize = 16, .ops = &serial_s3c2410_ops, .flags = UPF_BOOT_AUTOCONF, .line = 1, }#if NR_PORTS > 2 , { .membase = 0, .mapbase = 0, .iotype = UPIO_MEM, .irq = IRQ_S3CUART_RX2, .uartclk = 0, .fifosize = 16, .ops = &serial_s3c2410_ops, .flags = UPF_BOOT_AUTOCONF, .line = 2, }#endif};static intserial_s3c2410_resetport(struct uart_port *port, struct s3c2410_uartcfg *cfg){ /* ensure registers are setup */ dbg("serial_s3c2410_resetport: port=%p (%08x), cfg=%p\n", port, port->mapbase, cfg); wr_regl(port, S3C2410_UCON, cfg->ucon); wr_regl(port, S3C2410_ULCON, cfg->ulcon); /* reset both fifos */ wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); wr_regl(port, S3C2410_UFCON, cfg->ufcon); return 0;}/* serial_s3c2410_init_ports * * initialise the serial ports from the machine provided initialisation * data.*/static int serial_s3c2410_init_ports(void){ struct uart_port *ptr = serial_s3c2410_ports; struct s3c2410_uartcfg *cfg = s3c2410_uartcfgs; static int inited = 0; int i; if (inited) return 0; inited = 1; dbg("serial_s3c2410_init_ports: initialising ports...\n"); for (i = 0; i < NR_PORTS; i++, ptr++, cfg++) { if (cfg->hwport > 3) continue; dbg("serial_s3c2410_init_ports: port %d (hw %d)...\n", i, cfg->hwport); if (cfg->clock != NULL) ptr->uartclk = *cfg->clock; switch (cfg->hwport) { case 0: ptr->mapbase = S3C2410_PA_UART0; ptr->membase = (char *)S3C2410_VA_UART0; ptr->irq = IRQ_S3CUART_RX0; break; case 1: ptr->mapbase = S3C2410_PA_UART1; ptr->membase = (char *)S3C2410_VA_UART1; ptr->irq = IRQ_S3CUART_RX1; break; case 2: ptr->mapbase = S3C2410_PA_UART2; ptr->membase = (char *)S3C2410_VA_UART2; ptr->irq = IRQ_S3CUART_RX2; break; } if (ptr->mapbase == 0) continue; /* reset the fifos (and setup the uart */ serial_s3c2410_resetport(ptr, cfg); } return 0;}#ifdef CONFIG_SERIAL_S3C2410_CONSOLEstatic struct uart_port *cons_uart;static intserial_s3c2410_console_txrdy(struct uart_port *port, unsigned int ufcon){ unsigned long ufstat, utrstat; if (ufcon & S3C2410_UFCON_FIFOMODE) { /* fifo mode - check ammount of data in fifo registers... */ ufstat = rd_regl(port, S3C2410_UFSTAT); return S3C2410_UFCON_TXC(ufstat) < 12; } /* in non-fifo mode, we go and use the tx buffer empty */ utrstat = rd_regl(port, S3C2410_UTRSTAT); return (utrstat & S3C2410_UTRSTAT_TXFE) ? 1 : 0;}static voidserial_s3c2410_console_write(struct console *co, const char *s, unsigned int count){ int i; unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON); for (i = 0; i < count; i++) { while (!serial_s3c2410_console_txrdy(cons_uart, ufcon)) barrier(); wr_regb(cons_uart, S3C2410_UTXH, s[i]); if (s[i] == '\n') { while (!serial_s3c2410_console_txrdy(cons_uart, ufcon)) barrier(); wr_regb(cons_uart, S3C2410_UTXH, '\r'); } }}static void __initserial_s3c2410_get_options(struct uart_port *port, int *baud, int *parity, int *bits){ unsigned int ulcon, ucon, ubrdiv; ulcon = rd_regl(port, S3C2410_ULCON); ucon = rd_regl(port, S3C2410_UCON); ubrdiv = rd_regl(port, S3C2410_UBRDIV); dbg("serial_s3c2410_get_options: port=%p\n" "registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n", port, ulcon, ucon, ubrdiv); if ((ucon & 0xf) != 0) { /* consider the serial port configured if the tx/rx mode set */ switch (ulcon & S3C2410_LCON_CSMASK) { case S3C2410_LCON_CS5: *bits = 5; break; case S3C2410_LCON_CS6: *bits = 6; break; case S3C2410_LCON_CS7: *bits = 7; break; default: case S3C2410_LCON_CS8: *bits = 8; break; } switch (ulcon & S3C2410_LCON_PMASK) { case S3C2410_LCON_PEVEN: *parity = 'e'; break; case S3C2410_LCON_PODD: *parity = 'o'; break; default: case S3C2410_LCON_PNONE: *parity = 'n'; } /* now calculate the baud rate */ *baud = port->uartclk / ( 16 * (ubrdiv + 1)); dbg("calculated baud %d\n", *baud); }}static int __initserial_s3c2410_console_setup(struct console *co, char *options){ struct uart_port *port; int baud = 9600; int bits = 8; int parity = 'n'; int flow = 'n'; /* is this a valid port */ if (co->index == -1 || co->index >= NR_PORTS) co->index = 0; port = &serial_s3c2410_ports[co->index]; /* is the port configured? */ if (port->mapbase == 0x0) { co->index = 0; port = &serial_s3c2410_ports[co->index]; } cons_uart = port; dbg("serial_s3c2410_console_setup: port=%p (%d)\n", port, co->index); /* * Check whether an invalid uart number has been specified, and * if so, search for the first available port that does have * console support. */ if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else serial_s3c2410_get_options(port, &baud, &parity, &bits); return uart_set_options(port, co, baud, parity, bits, flow);}static struct uart_driver s3c2410_uart_drv;static struct console serial_s3c2410_console ={ .name = SERIAL_S3C2410_NAME, .write = serial_s3c2410_console_write, .device = uart_console_device, .setup = serial_s3c2410_console_setup, .flags = CON_PRINTBUFFER, .index = -1, .data = &s3c2410_uart_drv,};static int __init s3c2410_console_init(void){ dbg("s3c2410_console_init:\n"); serial_s3c2410_init_ports(); register_console(&serial_s3c2410_console); return 0;}console_initcall(s3c2410_console_init);#define SERIAL_S3C2410_CONSOLE &serial_s3c2410_console#else#define SERIAL_S3C2410_CONSOLE NULL#endifstatic struct uart_driver s3c2410_uart_drv = { .owner = THIS_MODULE, .driver_name = SERIAL_S3C2410_NAME, .dev_name = SERIAL_S3C2410_NAME, .major = SERIAL_S3C2410_MAJOR, .minor = SERIAL_S3C2410_MINOR, .nr = 3, .cons = SERIAL_S3C2410_CONSOLE,};/* device driver */static int s3c2410_serial_probe(struct device *_dev);static int s3c2410_serial_remove(struct device *_dev);static struct device_driver s3c2410_serial_drv = { .name = "s3c2410-uart", .bus = &platform_bus_type, .probe = s3c2410_serial_probe, .remove = s3c2410_serial_remove, .suspend = NULL, .resume = NULL,};#define s3c2410_dev_to_port(__dev) (struct uart_port *)dev_get_drvdata(__dev)static int s3c2410_serial_probe(struct device *_dev){ struct platform_device *dev = to_platform_device(_dev); struct resource *res = dev->resource; int i; dbg("s3c2410_serial_probe: dev=%p, _dev=%p, res=%p\n", _dev, dev, res); for (i = 0; i < dev->num_resources; i++, res++) if (res->flags & IORESOURCE_MEM) break; if (i < dev->num_resources) { struct uart_port *ptr = serial_s3c2410_ports; for (i = 0; i < NR_PORTS; i++, ptr++) { dbg("s3c2410_serial_probe: ptr=%p (%08x, %08x)\n", ptr, ptr->mapbase, ptr->membase); if (ptr->mapbase != res->start) continue; dbg("s3c2410_serial_probe: got device %p: port=%p\n", _dev, ptr); uart_add_one_port(&s3c2410_uart_drv, ptr); dev_set_drvdata(_dev, ptr); break; } } return 0;}static int s3c2410_serial_remove(struct device *_dev){ struct uart_port *port = s3c2410_dev_to_port(_dev); if (port) uart_remove_one_port(&s3c2410_uart_drv, port); return 0;}static int __init serial_s3c2410_init(void){ int ret; printk(KERN_INFO "S3C2410X Serial, (c) 2003 Simtec Electronics\n"); ret = uart_register_driver(&s3c2410_uart_drv); if (ret != 0) return ret; ret = driver_register(&s3c2410_serial_drv); if (ret) { uart_unregister_driver(&s3c2410_uart_drv); } return ret;}static void __exit serial_s3c2410_exit(void){ driver_unregister(&s3c2410_serial_drv); uart_unregister_driver(&s3c2410_uart_drv);}module_init(serial_s3c2410_init);module_exit(serial_s3c2410_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");MODULE_DESCRIPTION("Samsung S3C2410X (S3C2410) Serial driver");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -