serial_txx9.c
来自「linux 内核源代码」· C语言 代码 · 共 1,269 行 · 第 1/3 页
C
1,269 行
return ret;}static unsigned int serial_txx9_get_mctrl(struct uart_port *port){ struct uart_txx9_port *up = (struct uart_txx9_port *)port; unsigned int ret; /* no modem control lines */ ret = TIOCM_CAR | TIOCM_DSR; ret |= (sio_in(up, TXX9_SIFLCR) & TXX9_SIFLCR_RTSSC) ? 0 : TIOCM_RTS; ret |= (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS) ? 0 : TIOCM_CTS; return ret;}static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl){ struct uart_txx9_port *up = (struct uart_txx9_port *)port; if (mctrl & TIOCM_RTS) sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC); else sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);}static void serial_txx9_break_ctl(struct uart_port *port, int break_state){ struct uart_txx9_port *up = (struct uart_txx9_port *)port; unsigned long flags; spin_lock_irqsave(&up->port.lock, flags); if (break_state == -1) sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK); else sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK); spin_unlock_irqrestore(&up->port.lock, flags);}static int serial_txx9_startup(struct uart_port *port){ struct uart_txx9_port *up = (struct uart_txx9_port *)port; unsigned long flags; int retval; /* * Clear the FIFO buffers and disable them. * (they will be reenabled in set_termios()) */ sio_set(up, TXX9_SIFCR, TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE); /* clear reset */ sio_mask(up, TXX9_SIFCR, TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE); sio_out(up, TXX9_SIDICR, 0); /* * Clear the interrupt registers. */ sio_out(up, TXX9_SIDISR, 0); retval = request_irq(up->port.irq, serial_txx9_interrupt, IRQF_SHARED, "serial_txx9", up); if (retval) return retval; /* * Now, initialize the UART */ spin_lock_irqsave(&up->port.lock, flags); serial_txx9_set_mctrl(&up->port, up->port.mctrl); spin_unlock_irqrestore(&up->port.lock, flags); /* Enable RX/TX */ sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RSDE | TXX9_SIFLCR_TSDE); /* * Finally, enable interrupts. */ sio_set(up, TXX9_SIDICR, TXX9_SIDICR_RIE); return 0;}static void serial_txx9_shutdown(struct uart_port *port){ struct uart_txx9_port *up = (struct uart_txx9_port *)port; unsigned long flags; /* * Disable interrupts from this port */ sio_out(up, TXX9_SIDICR, 0); /* disable all intrs */ spin_lock_irqsave(&up->port.lock, flags); serial_txx9_set_mctrl(&up->port, up->port.mctrl); spin_unlock_irqrestore(&up->port.lock, flags); /* * Disable break condition */ sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK);#ifdef CONFIG_SERIAL_TXX9_CONSOLE if (up->port.cons && up->port.line == up->port.cons->index) { free_irq(up->port.irq, up); return; }#endif /* reset FIFOs */ sio_set(up, TXX9_SIFCR, TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE); /* clear reset */ sio_mask(up, TXX9_SIFCR, TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE); /* Disable RX/TX */ sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RSDE | TXX9_SIFLCR_TSDE); free_irq(up->port.irq, up);}static voidserial_txx9_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old){ struct uart_txx9_port *up = (struct uart_txx9_port *)port; unsigned int cval, fcr = 0; unsigned long flags; unsigned int baud, quot; /* * We don't support modem control lines. */ termios->c_cflag &= ~(HUPCL | CMSPAR); termios->c_cflag |= CLOCAL; cval = sio_in(up, TXX9_SILCR); /* byte size and parity */ cval &= ~TXX9_SILCR_UMODE_MASK; switch (termios->c_cflag & CSIZE) { case CS7: cval |= TXX9_SILCR_UMODE_7BIT; break; default: case CS5: /* not supported */ case CS6: /* not supported */ case CS8: cval |= TXX9_SILCR_UMODE_8BIT; break; } cval &= ~TXX9_SILCR_USBL_MASK; if (termios->c_cflag & CSTOPB) cval |= TXX9_SILCR_USBL_2BIT; else cval |= TXX9_SILCR_USBL_1BIT; cval &= ~(TXX9_SILCR_UPEN | TXX9_SILCR_UEPS); if (termios->c_cflag & PARENB) cval |= TXX9_SILCR_UPEN; if (!(termios->c_cflag & PARODD)) cval |= TXX9_SILCR_UEPS; /* * Ask the core to calculate the divisor for us. */ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16/2); quot = uart_get_divisor(port, baud); /* Set up FIFOs */ /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */ fcr = TXX9_SIFCR_TDIL_MAX | TXX9_SIFCR_RDIL_1; /* * Ok, we're now changing the port state. Do it with * interrupts disabled. */ spin_lock_irqsave(&up->port.lock, flags); /* * Update the per-port timeout. */ uart_update_timeout(port, termios->c_cflag, baud); up->port.read_status_mask = TXX9_SIDISR_UOER | TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS; if (termios->c_iflag & INPCK) up->port.read_status_mask |= TXX9_SIDISR_UFER | TXX9_SIDISR_UPER; if (termios->c_iflag & (BRKINT | PARMRK)) up->port.read_status_mask |= TXX9_SIDISR_UBRK; /* * Characteres to ignore */ up->port.ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) up->port.ignore_status_mask |= TXX9_SIDISR_UPER | TXX9_SIDISR_UFER; if (termios->c_iflag & IGNBRK) { up->port.ignore_status_mask |= TXX9_SIDISR_UBRK; /* * If we're ignoring parity and break indicators, * ignore overruns too (for real raw support). */ if (termios->c_iflag & IGNPAR) up->port.ignore_status_mask |= TXX9_SIDISR_UOER; } /* * ignore all characters if CREAD is not set */ if ((termios->c_cflag & CREAD) == 0) up->port.ignore_status_mask |= TXX9_SIDISR_RDIS; /* CTS flow control flag */ if ((termios->c_cflag & CRTSCTS) && (up->port.flags & UPF_TXX9_HAVE_CTS_LINE)) { sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RCS | TXX9_SIFLCR_TES); } else { sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RCS | TXX9_SIFLCR_TES); } sio_out(up, TXX9_SILCR, cval); sio_quot_set(up, quot); sio_out(up, TXX9_SIFCR, fcr); serial_txx9_set_mctrl(&up->port, up->port.mctrl); spin_unlock_irqrestore(&up->port.lock, flags);}static voidserial_txx9_pm(struct uart_port *port, unsigned int state, unsigned int oldstate){ /* * If oldstate was -1 this is called from * uart_configure_port(). In this case do not initialize the * port now, because the port was already initialized (for * non-console port) or should not be initialized here (for * console port). If we initialized the port here we lose * serial console settings. */ if (state == 0 && oldstate != -1) serial_txx9_initialize(port);}static int serial_txx9_request_resource(struct uart_txx9_port *up){ unsigned int size = TXX9_REGION_SIZE; int ret = 0; switch (up->port.iotype) { default: if (!up->port.mapbase) break; if (!request_mem_region(up->port.mapbase, size, "serial_txx9")) { ret = -EBUSY; break; } if (up->port.flags & UPF_IOREMAP) { up->port.membase = ioremap(up->port.mapbase, size); if (!up->port.membase) { release_mem_region(up->port.mapbase, size); ret = -ENOMEM; } } break; case UPIO_PORT: if (!request_region(up->port.iobase, size, "serial_txx9")) ret = -EBUSY; break; } return ret;}static void serial_txx9_release_resource(struct uart_txx9_port *up){ unsigned int size = TXX9_REGION_SIZE; switch (up->port.iotype) { default: if (!up->port.mapbase) break; if (up->port.flags & UPF_IOREMAP) { iounmap(up->port.membase); up->port.membase = NULL; } release_mem_region(up->port.mapbase, size); break; case UPIO_PORT: release_region(up->port.iobase, size); break; }}static void serial_txx9_release_port(struct uart_port *port){ struct uart_txx9_port *up = (struct uart_txx9_port *)port; serial_txx9_release_resource(up);}static int serial_txx9_request_port(struct uart_port *port){ struct uart_txx9_port *up = (struct uart_txx9_port *)port; return serial_txx9_request_resource(up);}static void serial_txx9_config_port(struct uart_port *port, int uflags){ struct uart_txx9_port *up = (struct uart_txx9_port *)port; int ret; /* * Find the region that we can probe for. This in turn * tells us whether we can probe for the type of port. */ ret = serial_txx9_request_resource(up); if (ret < 0) return; port->type = PORT_TXX9; up->port.fifosize = TXX9_SIO_TX_FIFO;#ifdef CONFIG_SERIAL_TXX9_CONSOLE if (up->port.line == up->port.cons->index) return;#endif serial_txx9_initialize(port);}static const char *serial_txx9_type(struct uart_port *port){ return "txx9";}static struct uart_ops serial_txx9_pops = { .tx_empty = serial_txx9_tx_empty, .set_mctrl = serial_txx9_set_mctrl, .get_mctrl = serial_txx9_get_mctrl, .stop_tx = serial_txx9_stop_tx, .start_tx = serial_txx9_start_tx, .stop_rx = serial_txx9_stop_rx, .enable_ms = serial_txx9_enable_ms, .break_ctl = serial_txx9_break_ctl, .startup = serial_txx9_startup, .shutdown = serial_txx9_shutdown, .set_termios = serial_txx9_set_termios, .pm = serial_txx9_pm, .type = serial_txx9_type, .release_port = serial_txx9_release_port, .request_port = serial_txx9_request_port, .config_port = serial_txx9_config_port,};static struct uart_txx9_port serial_txx9_ports[UART_NR];static void __init serial_txx9_register_ports(struct uart_driver *drv, struct device *dev){ int i; for (i = 0; i < UART_NR; i++) { struct uart_txx9_port *up = &serial_txx9_ports[i]; up->port.line = i; up->port.ops = &serial_txx9_pops; up->port.dev = dev; if (up->port.iobase || up->port.mapbase) uart_add_one_port(drv, &up->port); }}#ifdef CONFIG_SERIAL_TXX9_CONSOLE/* * Wait for transmitter & holding register to empty */static inline void wait_for_xmitr(struct uart_txx9_port *up){ unsigned int tmout = 10000; /* Wait up to 10ms for the character(s) to be sent. */ while (--tmout && !(sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS)) udelay(1); /* Wait up to 1s for flow control if necessary */ if (up->port.flags & UPF_CONS_FLOW) { tmout = 1000000; while (--tmout && (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS)) udelay(1); }}static void serial_txx9_console_putchar(struct uart_port *port, int ch){ struct uart_txx9_port *up = (struct uart_txx9_port *)port; wait_for_xmitr(up); sio_out(up, TXX9_SITFIFO, ch);}/* * Print a string to the serial port trying not to disturb * any possible real use of the port... * * The console_lock must be held when we get here. */static voidserial_txx9_console_write(struct console *co, const char *s, unsigned int count){ struct uart_txx9_port *up = &serial_txx9_ports[co->index]; unsigned int ier, flcr;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?