📄 at91_serial.c
字号:
/* parity */ if (cflag & PARENB) { if (cflag & CMSPAR) { /* Mark or Space parity */ if (cflag & PARODD) mode |= AT91C_US_PAR_MARK; else mode |= AT91C_US_PAR_SPACE; } else if (cflag & PARODD) mode |= AT91C_US_PAR_ODD; else mode |= AT91C_US_PAR_EVEN; } else mode |= AT91C_US_PAR_NONE; port->read_status_mask |= AT91C_US_OVRE; if (iflag & INPCK) port->read_status_mask |= AT91C_US_FRAME | AT91C_US_PARE; if (iflag & (BRKINT | PARMRK)) port->read_status_mask |= AT91C_US_RXBRK; /* * Characters to ignore */ port->ignore_status_mask = 0; if (iflag & IGNPAR) port->ignore_status_mask |= (AT91C_US_FRAME | AT91C_US_PARE); if (iflag & IGNBRK) { port->ignore_status_mask |= AT91C_US_RXBRK; /* * If we're ignoring parity and break indicators, * ignore overruns too (for real raw support). */ if (iflag & IGNPAR) port->ignore_status_mask |= AT91C_US_OVRE; } // TODO: Ignore all characters if CREAD is set. /* first, disable interrupts and drain transmitter */ local_irq_save(flags); imr = UART_GET_IMR(port); /* get interrupt mask */ UART_PUT_IDR(port, -1); /* disable all interrupts */ local_irq_restore(flags); while (!(UART_GET_CSR(port) & AT91C_US_TXEMPTY)) { barrier(); } /* disable receiver and transmitter */ UART_PUT_CR(port, AT91C_US_TXDIS | AT91C_US_RXDIS); /* set the parity, stop bits and data size */ UART_PUT_MR(port, mode); /* set the baud rate */ UART_PUT_BRGR(port, quot); UART_PUT_CR(port, AT91C_US_TXEN | AT91C_US_RXEN); /* restore interrupts */ UART_PUT_IER(port, imr); /* CTS flow-control and modem-status interrupts */ if (UART_ENABLE_MS(port, cflag)) at91_pops.enable_ms(port);}/* * Return string describing the specified port */static const char *at91_type(struct uart_port *port){ return port->type == PORT_AT91RM9200 ? "AT91_SERIAL" : NULL;}/* * Release the memory region(s) being used by 'port'. */static void at91_release_port(struct uart_port *port){ release_mem_region(port->mapbase, port->mapbase == AT91C_VA_BASE_DBGU ? 512 : SZ_16K);}/* * Request the memory region(s) being used by 'port'. */static int at91_request_port(struct uart_port *port){ return request_mem_region(port->mapbase, port->mapbase == AT91C_VA_BASE_DBGU ? 512 : SZ_16K, "at91_serial") != NULL ? 0 : -EBUSY;}/* * Configure/autoconfigure the port. */static void at91_config_port(struct uart_port *port, int flags){ if (flags & UART_CONFIG_TYPE) { port->type = PORT_AT91RM9200; at91_request_port(port); }}/* * Verify the new serial_struct (for TIOCSSERIAL). */static int at91_verify_port(struct uart_port *port, struct serial_struct *ser){ int ret = 0; if (ser->type != PORT_UNKNOWN && ser->type != PORT_AT91RM9200) ret = -EINVAL; if (port->irq != ser->irq) ret = -EINVAL; if (ser->io_type != SERIAL_IO_MEM) ret = -EINVAL; if (port->uartclk / 16 != ser->baud_base) ret = -EINVAL; if ((void *)port->mapbase != ser->iomem_base) ret = -EINVAL; if (port->iobase != ser->port) ret = -EINVAL; if (ser->hub6 != 0) ret = -EINVAL; return ret;}//added by wujh@hyesco.comstatic int at91_port_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg){ unsigned long flags; unsigned int mode,imr; int ret = -ENOIOCTLCMD; unsigned int control = 0; switch (cmd) { case UART_RS485_CONFIG: if(port->line) { /* Get current mode register */ mode = UART_GET_MR(port) & ~(AT91C_US_USMODE); mode |= AT91C_US_USMODE_RS485 ; local_irq_save(flags); imr = UART_GET_IMR(port); /* get interrupt mask */ UART_PUT_IDR(port, -1); /* disable all interrupts */ local_irq_restore(flags); while (!(UART_GET_CSR(port) & AT91C_US_TXEMPTY)) { barrier(); } /* disable receiver and transmitter */ UART_PUT_CR(port, AT91C_US_TXDIS | AT91C_US_RXDIS); /* set the rs485 mode */ UART_PUT_MR(port, mode); UART_PUT_CR(port, AT91C_US_TXEN | AT91C_US_RXEN); /* restore interrupts */ UART_PUT_IER(port, imr); printk("\n\r config mode succeed! \r\n"); } break; case UART_RS485_READ: if (port->mapbase == AT91C_VA_BASE_US0) { AT91_SYS->PIOA_CODR = AT91C_PA21_RTS0; } else if (port->mapbase == AT91C_VA_BASE_US3) { AT91_SYS->PIOB_CODR = AT91C_PB0_RTS3; } break; case UART_RS485_WRITE: if (port->mapbase == AT91C_VA_BASE_US0) { AT91_SYS->PIOA_SODR = AT91C_PA21_RTS0; } else if (port->mapbase == AT91C_VA_BASE_US3) { AT91_SYS->PIOB_SODR = AT91C_PB0_RTS3; } break; default: break; } return ret;}static struct uart_ops at91_pops = { tx_empty: at91_tx_empty, set_mctrl: at91_set_mctrl, get_mctrl: at91_get_mctrl, stop_tx: at91_stop_tx, start_tx: at91_start_tx, stop_rx: at91_stop_rx, enable_ms: at91_enable_ms, break_ctl: at91_break_ctl, startup: at91_startup, shutdown: at91_shutdown, change_speed: at91_change_speed, type: at91_type, release_port: at91_release_port, request_port: at91_request_port, config_port: at91_config_port, verify_port: at91_verify_port, ioctl: at91_port_ioctl, //added by wujh@hyesco.com};static struct uart_port at91_ports[AT91C_NR_UART];void __init at91_init_ports(void){ static int first = 1; int i; if (!first) return; first = 0; for (i = 0; i < AT91C_NR_UART; i++) { at91_ports[i].iotype = SERIAL_IO_MEM; at91_ports[i].flags = ASYNC_BOOT_AUTOCONF; at91_ports[i].uartclk = AT91C_MASTER_CLOCK; at91_ports[i].ops = &at91_pops; at91_ports[i].fifosize = 1; at91_ports[i].line = i; }}void __init at91_register_uart_fns(struct at91rm9200_port_fns *fns){ if (fns->enable_ms) at91_pops.enable_ms = fns->enable_ms; if (fns->get_mctrl) at91_pops.get_mctrl = fns->get_mctrl; if (fns->set_mctrl) at91_pops.set_mctrl = fns->set_mctrl; at91_open = fns->open; at91_close = fns->close; at91_pops.pm = fns->pm; at91_pops.set_wake = fns->set_wake;}/* * Setup ports. */void __init at91_register_uart(int idx, int port){ if ((idx < 0) || (idx >= AT91C_NR_UART)) { printk(KERN_ERR __FUNCTION__ ": bad index number %d\n", idx); return; } switch (port) { case 0: at91_ports[idx].membase = (void *) AT91C_VA_BASE_US0; at91_ports[idx].mapbase = AT91C_VA_BASE_US0; at91_ports[idx].irq = AT91C_ID_US0; AT91_CfgPIO_USART0(); break; case 1: at91_ports[idx].membase = (void *) AT91C_VA_BASE_US1; at91_ports[idx].mapbase = AT91C_VA_BASE_US1; at91_ports[idx].irq = AT91C_ID_US1; AT91_CfgPIO_USART1(); break; case 2: at91_ports[idx].membase = (void *) AT91C_VA_BASE_US2; at91_ports[idx].mapbase = AT91C_VA_BASE_US2; at91_ports[idx].irq = AT91C_ID_US2; AT91_CfgPIO_USART2(); break; case 3: at91_ports[idx].membase = (void *) AT91C_VA_BASE_US3; at91_ports[idx].mapbase = AT91C_VA_BASE_US3; at91_ports[idx].irq = AT91C_ID_US3; AT91_CfgPIO_USART3(); break; case 4: at91_ports[idx].membase = (void *) AT91C_VA_BASE_DBGU; at91_ports[idx].mapbase = AT91C_VA_BASE_DBGU; at91_ports[idx].irq = AT91C_ID_SYS; AT91_CfgPIO_DBGU(); break; default: printk(KERN_ERR __FUNCTION__ ": bad port number %d\n", port); }}#ifdef CONFIG_SERIAL_AT91_CONSOLE/* * Interrupts are disabled on entering */static void at91_console_write(struct console *co, const char *s, u_int count){ struct uart_port *port = at91_ports + co->index; unsigned int status, i, imr; /* * First, save IMR and then disable interrupts */ imr = UART_GET_IMR(port); /* get interrupt mask */ UART_PUT_IDR(port, AT91C_US_RXRDY | AT91C_US_TXRDY); /* * Now, do each character */ for (i = 0; i < count; i++) { do { status = UART_GET_CSR(port); } while (!(status & AT91C_US_TXRDY)); UART_PUT_CHAR(port, s[i]); if (s[i] == '\n') { do { status = UART_GET_CSR(port); } while (!(status & AT91C_US_TXRDY)); UART_PUT_CHAR(port, '\r'); } } /* * Finally, wait for transmitter to become empty * and restore IMR */ do { status = UART_GET_CSR(port); } while (!(status & AT91C_US_TXRDY)); UART_PUT_IER(port, imr); /* set interrupts back the way they were */}static kdev_t at91_console_device(struct console *co){ return MKDEV(SERIAL_AT91_MAJOR, MINOR_START + co->index);}/* * If the port was already initialised (eg, by a boot loader), try to determine * the current setup. */static void __init at91_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits){ unsigned int mr, quot;// TODO: CR is a write-only register// unsigned int cr;//// cr = UART_GET_CR(port) & (AT91C_US_RXEN | AT91C_US_TXEN);// if (cr == (AT91C_US_RXEN | AT91C_US_TXEN)) {// /* ok, the port was enabled *///// mr = UART_GET_MR(port) & AT91C_US_PAR;//// *parity = 'n';// if (mr == AT91C_US_PAR_EVEN)// *parity = 'e';// else if (mr == AT91C_US_PAR_ODD)// *parity = 'o';// } mr = UART_GET_MR(port) & AT91C_US_CHRL; if (mr == AT91C_US_CHRL_8_BITS) *bits = 8; else *bits = 7; quot = UART_GET_BRGR(port); *baud = port->uartclk / (16 * (quot));}static int __init at91_console_setup(struct console *co, char *options){ struct uart_port *port; int baud = AT91C_CONSOLE_DEFAULT_BAUDRATE; 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. */ port = uart_get_console(at91_ports, AT91C_NR_UART, co); // TODO: The console port should be initialized, and clock enabled if // we're not relying on the bootloader to do it. if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else at91_console_get_options(port, &baud, &parity, &bits); return uart_set_options(port, co, baud, parity, bits, flow);}static struct console at91_console = { name: "ttyS", write: at91_console_write, device: at91_console_device, setup: at91_console_setup, flags: CON_PRINTBUFFER, index: AT91C_CONSOLE,};#define AT91_CONSOLE_DEVICE &at91_consolevoid __init at91_console_init(void){ at91_init_ports(); register_console(&at91_console);}#else#define AT91_CONSOLE_DEVICE NULL#endifstruct uart_driver at91_reg = { owner: THIS_MODULE, normal_major: SERIAL_AT91_MAJOR,#ifdef CONFIG_DEVFS_FS normal_name: "ttyS%d", callout_name: "cua%d",#else normal_name: "ttyS", callout_name: "cua",#endif normal_driver: &normal, callout_major: CALLOUT_AT91_MAJOR, callout_driver: &callout, table: at91_table, termios: at91_termios, termios_locked: at91_termios_locked, minor: MINOR_START,//added by wujh@hyesco.com#ifdef SUPPORT_TL16C554 nr: AT91C_NR_UART+4,#else nr: AT91C_NR_UART,#endif cons: AT91_CONSOLE_DEVICE,};static int __init at91_serial_init(void){ int ret, i; at91_init_ports(); ret = uart_register_driver(&at91_reg); if (ret) return ret; for (i = 0; i < AT91C_NR_UART; i++) { if (at91_serialmap[i] >= 0) uart_add_one_port(&at91_reg, &at91_ports[i]); } return 0;}static void __exit at91_serial_exit(void){ int i; for (i = 0; i < AT91C_NR_UART; i++) { if (at91_serialmap[i] >= 0) uart_remove_one_port(&at91_reg, &at91_ports[i]); } uart_unregister_driver(&at91_reg);}//added by wujh@hyesco.comEXPORT_SYMBOL(at91_reg);module_init(at91_serial_init);module_exit(at91_serial_exit);MODULE_AUTHOR("Rick Bronson");MODULE_DESCRIPTION("AT91 generic serial port driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -