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 + -
显示快捷键?