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

📄 8250.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 4 页
字号:
			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 | up->mcr;	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;	up->capabilities = uart_config[up->port.type].flags;	up->mcr = 0;	if (up->port.type == PORT_16C950) {		/* Wake up and initialize UART */		up->acr = 0;		serial_outp(up, UART_LCR, 0xBF);		serial_outp(up, UART_EFR, UART_EFR_ECB);		serial_outp(up, UART_IER, 0);		serial_outp(up, UART_LCR, 0);		serial_icr_write(up, UART_CSR, 0); /* Reset the UART */		serial_outp(up, UART_LCR, 0xBF);		serial_outp(up, UART_EFR, UART_EFR_ECB);		serial_outp(up, UART_LCR, 0);	}#if defined ( CONFIG_ARCH_OMAP) || defined (CONFIG_ARCH_OMAP24XX)       if (up->port.type == PORT_OMAP) {                serial_outp(up, UART_OMAP_MDR1, 0x07); /* disable UART */                serial_outp(up, UART_LCR, 0xBF);       /* select EFR */                serial_outp(up, UART_EFR, UART_EFR_ECB);                serial_outp(up, UART_LCR, UART_LCR_DLAB); /* set DLAB */                serial_outp(up, UART_DLL, 0x00);                serial_outp(up, UART_DLM, 0x00);                serial_outp(up, UART_LCR, 0x00);       /* reset DLAB */                serial_outp(up, UART_OMAP_SCR, 0x08);                serial_outp(up, UART_FCR, 0x00);                serial_outp(up, UART_MCR, 0x40);       /* enable TCR/TLR */                serial_outp(up, UART_OMAP_TCR, 0x0F);                serial_outp(up, UART_OMAP_TLR, 0x00);                serial_outp(up, UART_MCR, 0x00);                serial_outp(up, UART_LCR, 0xBF);       /* select EFR */                serial_outp(up, UART_EFR, 0x00);                serial_outp(up, UART_LCR, 0x00);       /* reset DLAB */#ifdef TI16750_DIV_13                serial_outp(up, UART_OMAP_MDR1, 0x03); /* enable UART */#else  /* use standard DIV_16 */                serial_outp(up, UART_OMAP_MDR1, 0x00); /* enable UART */#endif        }#endif#ifdef CONFIG_SERIAL_8250_RSA	/*	 * If this is an RSA port, see if we can kick it up to the	 * higher speed clock.	 */	enable_rsa(up);#endif	/*	 * Clear the FIFO buffers and disable them.	 * (they will be reeanbled 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);	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 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);	/*	 * 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 (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) {		if (baud < 2400)			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;#ifdef CONFIG_SERIAL_8250_RSA		else if (up->port.type == PORT_RSA)			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;#endif#if defined (CONFIG_ARCH_OMAP) || defined (CONFIG_ARCH_OMAP24XX)		else if (up->port.type == PORT_OMAP)			fcr = UART_FCR_T_TRIGGER_56 | UART_FCR_R_TRIGGER_60 | UART_FCR_ENABLE_FIFO;#endif		else			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;	}	/*	 * TI16C750: hardware flow control and 64 byte FIFOs. 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.	 */	if (up->port.type == PORT_16750) {		up->mcr &= ~UART_MCR_AFE;		if (termios->c_cflag & CRTSCTS)			up->mcr |= UART_MCR_AFE;		fcr |= UART_FCR7_64BYTE;	}	/*	 * 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;	if (up->port.type == PORT_XSCALE)		up->ier |= UART_IER_UUE | UART_IER_RTOIE;	serial_out(up, UART_IER, up->ier);	if (up->capabilities & UART_CAP_EFR) {		serial_outp(up, UART_LCR, 0xBF);		serial_outp(up, UART_EFR,			    termios->c_cflag & CRTSCTS ? UART_EFR_CTS :0);	}#ifdef CONFIG_ARCH_OMAP1510	/* Needed for 1510 only */        if (up->port.type == PORT_OMAP && cpu_is_omap1510()) {		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_outp(up, UART_DLL, quot & 0xff);		/* LS of divisor */	serial_outp(up, UART_DLM, quot >> 8);		/* MS of divisor */	/*	 * 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.  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 UPIO_MEM:		if (up->port.mapbase) {			*res = request_mem_region(up->port.mapbase, size, "serial");			if (!*res)				ret = -EBUSY;		}		break;	case UPIO_HUB6:	case UPIO_PORT:		*res = request_region(up->port.iobase, size, "serial");		if (!*res)			ret = -EBUSY;		break;	}	return ret;}static intserial8250_request_rsa_resource(struct uart_8250_port *up, struct resource **res)

⌨️ 快捷键说明

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