au1x00_uart.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,391 行 · 第 1/3 页

C
1,391
字号
	spin_lock_irq(&i->lock);	if (!list_empty(i->head)) {		if (i->head == &up->list)			i->head = i->head->next;		list_del(&up->list);	} else {		BUG_ON(i->head != &up->list);		i->head = NULL;	}	spin_unlock_irq(&i->lock);}static int serial_link_irq_chain(struct uart_8250_port *up){	struct irq_info *i = irq_lists + up->port.irq;	int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? SA_SHIRQ : 0;	spin_lock_irq(&i->lock);	if (i->head) {		list_add(&up->list, i->head);		spin_unlock_irq(&i->lock);		ret = 0;	} else {		INIT_LIST_HEAD(&up->list);		i->head = &up->list;		spin_unlock_irq(&i->lock);		ret = request_irq(up->port.irq, serial8250_interrupt,				  irq_flags, "serial", i);		if (ret < 0)			serial_do_unlink(i, up);	}	return ret;}static void serial_unlink_irq_chain(struct uart_8250_port *up){	struct irq_info *i = irq_lists + up->port.irq;	BUG_ON(i->head == NULL);	if (list_empty(i->head))		free_irq(up->port.irq, i);	serial_do_unlink(i, up);}/* * This function is used to handle ports that do not have an * interrupt.  This doesn't work very well for 16450's, but gives * barely passable results for a 16550A.  (Although at the expense * of much CPU overhead). */static void serial8250_timeout(unsigned long data){	struct uart_8250_port *up = (struct uart_8250_port *)data;	unsigned int timeout;	unsigned int iir;	iir = serial_in(up, UART_IIR);	if (!(iir & UART_IIR_NO_INT)) {		spin_lock(&up->port.lock);		serial8250_handle_port(up, NULL);		spin_unlock(&up->port.lock);	}	timeout = up->port.timeout;	timeout = timeout > 6 ? (timeout / 2 - 2) : 1;	mod_timer(&up->timer, jiffies + timeout);}static unsigned int serial8250_tx_empty(struct uart_port *port){	struct uart_8250_port *up = (struct uart_8250_port *)port;	unsigned long flags;	unsigned int ret;	spin_lock_irqsave(&up->port.lock, flags);	ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;	spin_unlock_irqrestore(&up->port.lock, flags);	return ret;}static unsigned int serial8250_get_mctrl(struct uart_port *port){	struct uart_8250_port *up = (struct uart_8250_port *)port;	unsigned long flags;	unsigned char status;	unsigned int ret;	spin_lock_irqsave(&up->port.lock, flags);	status = serial_in(up, UART_MSR);	spin_unlock_irqrestore(&up->port.lock, flags);	ret = 0;	if (status & UART_MSR_DCD)		ret |= TIOCM_CAR;	if (status & UART_MSR_RI)		ret |= TIOCM_RNG;	if (status & UART_MSR_DSR)		ret |= TIOCM_DSR;	if (status & UART_MSR_CTS)		ret |= TIOCM_CTS;	return ret;}static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl){	struct uart_8250_port *up = (struct uart_8250_port *)port;	unsigned char mcr = 0;	if (mctrl & TIOCM_RTS)		mcr |= UART_MCR_RTS;	if (mctrl & TIOCM_DTR)		mcr |= UART_MCR_DTR;	if (mctrl & TIOCM_OUT1)		mcr |= UART_MCR_OUT1;	if (mctrl & TIOCM_OUT2)		mcr |= UART_MCR_OUT2;	if (mctrl & TIOCM_LOOP)		mcr |= UART_MCR_LOOP;	mcr = (mcr & up->mcr_mask) | up->mcr_force;	serial_out(up, UART_MCR, mcr);}static void serial8250_break_ctl(struct uart_port *port, int break_state){	struct uart_8250_port *up = (struct uart_8250_port *)port;	unsigned long flags;	spin_lock_irqsave(&up->port.lock, flags);	if (break_state == -1)		up->lcr |= UART_LCR_SBC;	else		up->lcr &= ~UART_LCR_SBC;	serial_out(up, UART_LCR, up->lcr);	spin_unlock_irqrestore(&up->port.lock, flags);}static int serial8250_startup(struct uart_port *port){	struct uart_8250_port *up = (struct uart_8250_port *)port;	unsigned long flags;	int retval;	/*	 * Clear the FIFO buffers and disable them.	 * (they will be reeanbled in set_termios())	 */	if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) {		serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);		serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |				UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);		serial_outp(up, UART_FCR, 0);	}	/*	 * Clear the interrupt registers.	 */	(void) serial_inp(up, UART_LSR);	(void) serial_inp(up, UART_RX);	(void) serial_inp(up, UART_IIR);	(void) serial_inp(up, UART_MSR);	/*	 * At this point, there's no way the LSR could still be 0xff;	 * if it is, then bail out, because there's likely no UART	 * here.	 */	if (!(up->port.flags & UPF_BUGGY_UART) &&	    (serial_inp(up, UART_LSR) == 0xff)) {		printk("ttyS%d: LSR safety check engaged!\n", up->port.line);		return -ENODEV;	}	retval = serial_link_irq_chain(up);		if (retval)			return retval;	/*	 * Now, initialize the UART	 */	serial_outp(up, UART_LCR, UART_LCR_WLEN8);	spin_lock_irqsave(&up->port.lock, flags);	if (up->port.flags & UPF_FOURPORT) {		if (!is_real_interrupt(up->port.irq))			up->port.mctrl |= TIOCM_OUT1;	} else		/*		 * Most PC uarts need OUT2 raised to enable interrupts.		 */		if (is_real_interrupt(up->port.irq))			up->port.mctrl |= TIOCM_OUT2;	serial8250_set_mctrl(&up->port, up->port.mctrl);	spin_unlock_irqrestore(&up->port.lock, flags);	/*	 * Finally, enable interrupts.  Note: Modem status interrupts	 * are set via set_termios(), which will be occurring imminently	 * anyway, so we don't enable them here.	 */	up->ier = UART_IER_RLSI | UART_IER_RDI;	serial_outp(up, UART_IER, up->ier);	if (up->port.flags & UPF_FOURPORT) {		unsigned int icp;		/*		 * Enable interrupts on the AST Fourport board		 */		icp = (up->port.iobase & 0xfe0) | 0x01f;		outb_p(0x80, icp);		(void) inb_p(icp);	}	/*	 * And clear the interrupt registers again for luck.	 */	(void) serial_inp(up, UART_LSR);	(void) serial_inp(up, UART_RX);	(void) serial_inp(up, UART_IIR);	(void) serial_inp(up, UART_MSR);	return 0;}static void serial8250_shutdown(struct uart_port *port){	struct uart_8250_port *up = (struct uart_8250_port *)port;	unsigned long flags;	/*	 * Disable interrupts from this port	 */	up->ier = 0;	serial_outp(up, UART_IER, 0);	spin_lock_irqsave(&up->port.lock, flags);	if (up->port.flags & UPF_FOURPORT) {		/* reset interrupts on the AST Fourport board */		inb((up->port.iobase & 0xfe0) | 0x1f);		up->port.mctrl |= TIOCM_OUT1;	} else		up->port.mctrl &= ~TIOCM_OUT2;	serial8250_set_mctrl(&up->port, up->port.mctrl);	spin_unlock_irqrestore(&up->port.lock, flags);	/*	 * Disable break condition and FIFOs	 */	serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC);	serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |				  UART_FCR_CLEAR_RCVR |				  UART_FCR_CLEAR_XMIT);	serial_outp(up, UART_FCR, 0);	/*	 * Read data port to reset things, and then unlink from	 * the IRQ chain.	 */	(void) serial_in(up, UART_RX);	if (!is_real_interrupt(up->port.irq))		del_timer_sync(&up->timer);	else		serial_unlink_irq_chain(up);}static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud){	unsigned int quot;	/*	 * Handle magic divisors for baud rates above baud_base on	 * SMSC SuperIO chips.	 */	if ((port->flags & UPF_MAGIC_MULTIPLIER) &&	    baud == (port->uartclk/4))		quot = 0x8001;	else if ((port->flags & UPF_MAGIC_MULTIPLIER) &&		 baud == (port->uartclk/8))		quot = 0x8002;	else		quot = uart_get_divisor(port, baud);	return quot;}static voidserial8250_set_termios(struct uart_port *port, struct termios *termios,		       struct termios *old){	struct uart_8250_port *up = (struct uart_8250_port *)port;	unsigned char cval, fcr = 0;	unsigned long flags;	unsigned int baud, quot;	switch (termios->c_cflag & CSIZE) {	case CS5:		cval = 0x00;		break;	case CS6:		cval = 0x01;		break;	case CS7:		cval = 0x02;		break;	default:	case CS8:		cval = 0x03;		break;	}	if (termios->c_cflag & CSTOPB)		cval |= 0x04;	if (termios->c_cflag & PARENB)		cval |= UART_LCR_PARITY;	if (!(termios->c_cflag & PARODD))		cval |= UART_LCR_EPAR;#ifdef CMSPAR	if (termios->c_cflag & CMSPAR)		cval |= UART_LCR_SPAR;#endif	/*	 * Ask the core to calculate the divisor for us.	 */	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 	quot = serial8250_get_divisor(port, baud);	quot = 0x35; /* FIXME */	/*	 * Work around a bug in the Oxford Semiconductor 952 rev B	 * chip which causes it to seriously miscalculate baud rates	 * when DLL is 0.	 */	if ((quot & 0xff) == 0 && up->port.type == PORT_16C950 &&	    up->rev == 0x5201)		quot ++;	if (uart_config[up->port.type].flags & UART_USE_FIFO) {		if (baud < 2400)			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIGGER_1;		else			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIGGER_8;	}	/*	 * 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 = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;	if (termios->c_iflag & INPCK)		up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;	if (termios->c_iflag & (BRKINT | PARMRK))		up->port.read_status_mask |= UART_LSR_BI;	/*	 * Characteres to ignore	 */	up->port.ignore_status_mask = 0;	if (termios->c_iflag & IGNPAR)		up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;	if (termios->c_iflag & IGNBRK) {		up->port.ignore_status_mask |= UART_LSR_BI;		/*		 * 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 |= UART_LSR_OE;	}	/*	 * ignore all characters if CREAD is not set	 */	if ((termios->c_cflag & CREAD) == 0)		up->port.ignore_status_mask |= UART_LSR_DR;	/*	 * CTS flow control flag and modem status interrupts	 */	up->ier &= ~UART_IER_MSI;	if (UART_ENABLE_MS(&up->port, termios->c_cflag))		up->ier |= UART_IER_MSI;	serial_out(up, UART_IER, up->ier);	serial_outp(up, 0x28, quot & 0xffff);	up->lcr = cval;					/* Save LCR */	if (up->port.type != PORT_16750) {		if (fcr & UART_FCR_ENABLE_FIFO) {			/* emulated UARTs (Lucent Venus 167x) need two steps */			serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);		}		serial_outp(up, UART_FCR, fcr);		/* set fcr */	}	spin_unlock_irqrestore(&up->port.lock, flags);}static voidserial8250_pm(struct uart_port *port, unsigned int state,	      unsigned int oldstate){	struct uart_8250_port *up = (struct uart_8250_port *)port;	if (state) {		/* sleep */		if (up->pm)			up->pm(port, state, oldstate);	} else {		/* wake */		if (up->pm)			up->pm(port, state, oldstate);	}}/* * Resource handling.  This is complicated by the fact that resources * depend on the port type.  Maybe we should be claiming the standard * 8250 ports, and then trying to get other resources as necessary? */static intserial8250_request_std_resource(struct uart_8250_port *up, struct resource **res){	unsigned int size = 8 << up->port.regshift;	int ret = 0;	switch (up->port.iotype) {	case SERIAL_IO_MEM:		if (up->port.mapbase) {			*res = request_mem_region(up->port.mapbase, size, "serial");			if (!*res)				ret = -EBUSY;		}		break;	case SERIAL_IO_HUB6:	case SERIAL_IO_PORT:		*res = request_region(up->port.iobase, size, "serial");		if (!*res)			ret = -EBUSY;		break;	}	return ret;}static void serial8250_release_port(struct uart_port *port)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?