⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 8250.c

📁 linux 2.6内核下8250串口设备驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
	/*	 * Clear the FIFO buffers and disable them.	 * (they will be reenabled in set_termios())	 */	serial8250_clear_fifos(up);	/*	 * 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;	}	/*	 * For a XR16C850, we need to set the trigger levels	 */	if (up->port.type == PORT_16850) {		unsigned char fctr;		serial_outp(up, UART_LCR, 0xbf);		fctr = serial_inp(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX);		serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_RX);		serial_outp(up, UART_TRG, UART_TRG_96);		serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_TX);		serial_outp(up, UART_TRG, UART_TRG_96);		serial_outp(up, UART_LCR, 0);	}	/*	 * If the "interrupt" for this port doesn't correspond with any	 * hardware interrupt, we use a timer-based system.  The original	 * driver used to do this with IRQ0.	 */	if (!is_real_interrupt(up->port.irq)) {		unsigned int timeout = up->port.timeout;		timeout = timeout > 6 ? (timeout / 2 - 2) : 1;		up->timer.data = (unsigned long)up;		mod_timer(&up->timer, jiffies + timeout);	} else {		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);	/*	 * Do a quick test to see if we receive an	 * interrupt when we enable the TX irq.	 */	serial_outp(up, UART_IER, UART_IER_THRI);	lsr = serial_in(up, UART_LSR);	iir = serial_in(up, UART_IIR);	serial_outp(up, UART_IER, 0);	if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {		if (!(up->bugs & UART_BUG_TXEN)) {			up->bugs |= UART_BUG_TXEN;			pr_debug("ttyS%d - enabling bad tx status workarounds\n",				 port->line);		}	} else {		up->bugs &= ~UART_BUG_TXEN;	}	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);	serial8250_clear_fifos(up);#ifdef CONFIG_SERIAL_8250_RSA	/*	 * Reset the RSA board back to 115kbps compat mode.	 */	disable_rsa(up);#endif	/*	 * 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 ktermios *termios,		       struct ktermios *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 = UART_LCR_WLEN5;		break;	case CS6:		cval = UART_LCR_WLEN6;		break;	case CS7:		cval = UART_LCR_WLEN7;		break;	default:	case CS8:		cval = UART_LCR_WLEN8;		break;	}	if (termios->c_cflag & CSTOPB)		cval |= UART_LCR_STOP;	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);	/*	 * Oxford Semi 952 rev B workaround	 */	if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0)		quot ++;	if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) {		if (baud < 2400)			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;		else			fcr = uart_config[up->port.type].fcr;	}	/*	 * MCR-based auto flow control.  When AFE is enabled, RTS will be	 * deasserted when the receive FIFO contains more characters than	 * the trigger, or the MCR RTS bit is cleared.  In the case where	 * the remote UART is not using CTS auto flow control, we must	 * have sufficient FIFO entries for the latency of the remote	 * UART to respond.  IOW, at least 32 bytes of FIFO.	 */	if (up->capabilities & UART_CAP_AFE && up->port.fifosize >= 32) {		up->mcr &= ~UART_MCR_AFE;		if (termios->c_cflag & CRTSCTS)			up->mcr |= UART_MCR_AFE;	}	/*	 * 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 (!(up->bugs & UART_BUG_NOMSR) &&			UART_ENABLE_MS(&up->port, termios->c_cflag))		up->ier |= UART_IER_MSI;	if (up->capabilities & UART_CAP_UUE)		up->ier |= UART_IER_UUE | UART_IER_RTOIE;	serial_out(up, UART_IER, up->ier);	if (up->capabilities & UART_CAP_EFR) {		unsigned char efr = 0;		/*		 * TI16C752/Startech hardware flow control.  FIXME:		 * - TI16C752 requires control thresholds to be set.		 * - UART_MCR_RTS is ineffective if auto-RTS mode is enabled.		 */		if (termios->c_cflag & CRTSCTS)			efr |= UART_EFR_CTS;		serial_outp(up, UART_LCR, 0xBF);		serial_outp(up, UART_EFR, efr);	}#ifdef CONFIG_ARCH_OMAP15XX	/* Workaround to enable 115200 baud on OMAP1510 internal ports */	if (cpu_is_omap1510() && is_omap_port((unsigned int)up->port.membase)) {		if (baud == 115200) {			quot = 1;			serial_out(up, UART_OMAP_OSC_12M_SEL, 1);		} else			serial_out(up, UART_OMAP_OSC_12M_SEL, 0);	}#endif	if (up->capabilities & UART_NATSEMI) {		/* Switch to bank 2 not bank 1, to avoid resetting EXCR2 */		serial_outp(up, UART_LCR, 0xe0);	} else {		serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */	}	serial_dl_write(up, quot);	/*	 * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR	 * is written without DLAB set, this mode will be disabled.	 */	if (up->port.type == PORT_16750)		serial_outp(up, UART_FCR, fcr);	serial_outp(up, UART_LCR, cval);		/* reset DLAB */	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 */	}	serial8250_set_mctrl(&up->port, up->port.mctrl);	spin_unlock_irqrestore(&up->port.lock, flags);}static voidserial8250_pm(struct uart_port *port, unsigned int state,	      unsigned int oldstate){	struct uart_8250_port *p = (struct uart_8250_port *)port;	serial8250_set_sleep(p, state != 0);	if (p->pm)		p->pm(port, state, oldstate);}/* * Resource handling. */static int serial8250_request_std_resource(struct uart_8250_port *up){	unsigned int size = 8 << up->port.regshift;	int ret = 0;	switch (up->port.iotype) {	case UPIO_AU:		size = 0x100000;		/* fall thru */	case UPIO_TSI:	case UPIO_MEM32:	case UPIO_MEM:		if (!up->port.mapbase)			break;		if (!request_mem_region(up->port.mapbase, size, "serial")) {			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_HUB6:	case UPIO_PORT:		if (!request_region(up->port.iobase, size, "serial"))			ret = -EBUSY;		break;	}	return ret;}static void serial8250_release_std_resource(struct uart_8250_port *up){	unsigned int size = 8 << up->port.regshift;	switch (up->port.iotype) {	case UPIO_AU:		size = 0x100000;		/* fall thru */	case UPIO_TSI:	case UPIO_MEM32:	case UPIO_MEM:		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_HUB6:	case UPIO_PORT:		release_region(up->port.iobase, size);		break;	}}static int serial8250_request_rsa_resource(struct uart_8250_port *up){	unsigned long start = UART_RSA_BASE << up->port.regshift;	unsigned int size = 8 << up->port.regshift;	int ret = -EINVAL;	switch (up->port.iotype) {	case UPIO_HUB6:	case UPIO_PORT:		start += up->port.iobase;		if (request_region(start, size, "serial-rsa"))			ret = 0;		else			ret = -EBUSY;		break;	}	return ret;}static void serial8250_release_rsa_resource(struct uart_8250_port *up){	unsigned long offset = UART_RSA_BASE << up->port.regshift;	unsigned int size = 8 << up->port.regshift;	switch (up->port.iotype) {	case UPIO_HUB6:	case UPIO_PORT:		release_region(up->port.iobase + offset, size);		break;	}}static void serial8250_release_port(struct uart_port *port){	struct uart_8250_port *up = (struct uart_8250_port *)port;	serial8250_release_std_resource(up);	if (up->port.type == PORT_RSA)		serial8250_release_rsa_resource(up);}static int serial8250_request_port(struct uart_port *port){	struct uart_8250_port *up = (struct uart_8250_port *)port;	int ret = 0;	ret = serial8250_request_std_resource(up);	if (ret == 0 && up->port.type == PORT_RSA) {		ret = serial8250_request_rsa_resource(up);		if (ret < 0)			serial8250_release_std_resource(up);	}	return ret;}static void serial8250_config_port(struct uart_port *port, int flags){	struct uart_8250_port *up = (struct uart_8250_port *)port;	int probeflags = PROBE_ANY;	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 = serial8250_request_std_resource(up);	if (ret < 0)		return;	ret = serial8250_request_rsa_resource(up);

⌨️ 快捷键说明

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