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

📄 8250.c

📁 the attached file is the driver of Uart
💻 C
📖 第 1 页 / 共 5 页
字号:
	struct tty_struct *tty = up->port.info->tty;	unsigned char ch, lsr = *status;	int max_count = 256;	char flag;	do {		/* The following is not allowed by the tty layer and		   unsafe. It should be fixed ASAP */		if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {			if (tty->low_latency) {				spin_unlock(&up->port.lock);				tty_flip_buffer_push(tty);				spin_lock(&up->port.lock);			}			/* If this failed then we will throw away the			   bytes but must do so to clear interrupts */		}		ch = serial_inp(up, UART_RX);		flag = TTY_NORMAL;		up->port.icount.rx++;#ifdef CONFIG_SERIAL_8250_CONSOLE		/*		 * Recover the break flag from console xmit		 */		if (up->port.line == up->port.cons->index) {			lsr |= up->lsr_break_flag;			up->lsr_break_flag = 0;		}#endif		if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE |				    UART_LSR_FE | UART_LSR_OE))) {			/*			 * For statistics only			 */			if (lsr & UART_LSR_BI) {				lsr &= ~(UART_LSR_FE | UART_LSR_PE);				up->port.icount.brk++;				/*				 * We do the SysRQ and SAK checking				 * here because otherwise the break				 * may get masked by ignore_status_mask				 * or read_status_mask.				 */				if (uart_handle_break(&up->port))					goto ignore_char;			} else if (lsr & UART_LSR_PE)				up->port.icount.parity++;			else if (lsr & UART_LSR_FE)				up->port.icount.frame++;			if (lsr & UART_LSR_OE)				up->port.icount.overrun++;			/*			 * Mask off conditions which should be ingored.			 */			lsr &= up->port.read_status_mask;			if (lsr & UART_LSR_BI) {				DEBUG_INTR("handling break....");				flag = TTY_BREAK;			} else if (lsr & UART_LSR_PE)				flag = TTY_PARITY;			else if (lsr & UART_LSR_FE)				flag = TTY_FRAME;		}		if (uart_handle_sysrq_char(&up->port, ch, regs))			goto ignore_char;		if ((lsr & up->port.ignore_status_mask) == 0) {			tty_insert_flip_char(tty, ch, flag);		}		if ((lsr & UART_LSR_OE) &&		    tty->flip.count < TTY_FLIPBUF_SIZE) {			/*			 * Overrun is special, since it's reported			 * immediately, and doesn't affect the current			 * character.			 */			tty_insert_flip_char(tty, 0, TTY_OVERRUN);		}	ignore_char:		lsr = serial_inp(up, UART_LSR);	} while ((lsr & UART_LSR_DR) && (max_count-- > 0));	spin_unlock(&up->port.lock);	tty_flip_buffer_push(tty);	spin_lock(&up->port.lock);	*status = lsr;}static _INLINE_ void transmit_chars(struct uart_8250_port *up){	struct circ_buf *xmit = &up->port.info->xmit;	int count;	if (up->port.x_char) {		serial_outp(up, UART_TX, up->port.x_char);		up->port.icount.tx++;		up->port.x_char = 0;		return;	}	if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {		serial8250_stop_tx(&up->port, 0);		return;	}	count = up->tx_loadsz;	do {		serial_out(up, UART_TX, xmit->buf[xmit->tail]);		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);		up->port.icount.tx++;		if (uart_circ_empty(xmit))			break;	} while (--count > 0);	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)		uart_write_wakeup(&up->port);	DEBUG_INTR("THRE...");	if (uart_circ_empty(xmit))		serial8250_stop_tx(&up->port, 0);}static _INLINE_ void check_modem_status(struct uart_8250_port *up){	int status;	status = serial_in(up, UART_MSR);	if ((status & UART_MSR_ANY_DELTA) == 0)		return;	if (status & UART_MSR_TERI)		up->port.icount.rng++;	if (status & UART_MSR_DDSR)		up->port.icount.dsr++;	if (status & UART_MSR_DDCD)		uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);	if (status & UART_MSR_DCTS)		uart_handle_cts_change(&up->port, status & UART_MSR_CTS);	wake_up_interruptible(&up->port.info->delta_msr_wait);}/* * This handles the interrupt from one port. */static inline voidserial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs){	unsigned int status = serial_inp(up, UART_LSR);	DEBUG_INTR("status = %x...", status);	if (status & UART_LSR_DR)		receive_chars(up, &status, regs);	check_modem_status(up);	if (status & UART_LSR_THRE)		transmit_chars(up);}/*! * This is the 16C652 serial driver's interrupt routine modified for MXC. This * function is modified to handle interrupt pin connectivity requirements. *  * @param   irq      The Interrupt number * @param   dev_id   Driver private data * @param   regs     Holds a snapshot of the processors context before the *                   processor entered the interrupt code * * @result    This function returns \b IRQ_HANDLED.  *            \b IRQ_HANDLED is defined in include/linux/interrupt.h. * *//* * This is the serial driver's interrupt routine. * * Arjan thinks the old way was overly complex, so it got simplified. * Alan disagrees, saying that need the complexity to handle the weird * nature of ISA shared interrupts.  (This is a special exception.) * * In order to handle ISA shared interrupts properly, we need to check * that all ports have been serviced, and therefore the ISA interrupt * line has been de-asserted. * * This means we need to loop through all ports. checking that they * don't have an interrupt pending. */static irqreturn_t serial8250_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct irq_info *i = dev_id;	struct list_head *l, *end = NULL;	int pass_counter = 0, handled = 0;	DEBUG_INTR("serial8250_interrupt(%d)...", irq);	spin_lock(&i->lock);	l = i->head;	do {		struct uart_8250_port *up;		unsigned int iir;		up = list_entry(l, struct uart_8250_port, list);#if defined(CONFIG_ARCH_ARGONPLUS) || \    defined(CONFIG_ARCH_SCMA11) || \    defined(CONFIG_ARCH_MX3) || \    defined(CONFIG_MACH_ZEUSEVB)		/*		 * Make sure INTA-B are active in the MCR, otherwise the DUART will		 * tri-state the INT lines		 */		serial_out(up, UART_MCR, serial_inp(up, UART_MCR) | UART_MCR_OUT2);		/*		 * Get the EDIO interrupt, clear if set.		 */		extuart_intr_clear(up->port.line);#endif		iir = serial_in(up, UART_IIR);		if (!(iir & UART_IIR_NO_INT)) {			spin_lock(&up->port.lock);			serial8250_handle_port(up, regs);			spin_unlock(&up->port.lock);			handled = 1;			end = NULL;		} else if (end == NULL)			end = l;		l = l->next;		if (l == i->head && pass_counter++ > PASS_LIMIT) {			/* If we hit this, we're dead. */			printk(KERN_ERR "serial8250: too much work for "				"irq%d\n", irq);			break;		}	} while (l != end);	spin_unlock(&i->lock);	DEBUG_INTR("end.\n");	//return IRQ_RETVAL(handled);	return IRQ_HANDLED;	/* FIXME: iir status not ready on 1510 */}/* * To support ISA shared interrupts, we need to have one interrupt * handler that ensures that the IRQ line has been deasserted * before returning.  Failing to do this will result in the IRQ * line being stuck active, and, since ISA irqs are edge triggered, * no more IRQs will be seen. */static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up){	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);}/*! * This function registers UART interrupt service routine, if not already * registered. If Interrupt type flags contains UPF_SHARE_IRQ, interrupt * sharing is enabled. This function inserts irq info into irq_lists. This * function handles interrupt pin configurations required for MXC boards. *  * @param   up   the 8250 UART port structure  * * @result   This function returns zero if irq_lists is already initialized *           or the return value from request_irq().  */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);#if defined(CONFIG_ARCH_SCMA11) || \    defined(CONFIG_ARCH_MX3) || \    defined(CONFIG_ARCH_ARGONPLUS)		ret = extuart_intr_setup(up->port.line);		/*                 * Register the ISR with the GPIO driver,                 * return after registering                 */		if (ret == 1) {			ret = gpio_request_irq(2, 30, GPIO_HIGH_PRIO,					       serial8250_interrupt,					       irq_flags, "serial", i);			if (ret != 0) {				gpio_free_irq(2, 30, GPIO_HIGH_PRIO);				serial_do_unlink(i, up);			}			return ret;		}#endif#if defined(CONFIG_MACH_ZEUSEVB)		ret = extuart_intr_setup(up->port.line, up->port.irq, serial8250_interrupt,					 irq_flags, "serial", i);#else		ret = request_irq(up->port.irq, serial8250_interrupt,				  irq_flags, "serial", i);#endif		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 defined(CONFIG_ARCH_ARGONPLUS) || \    defined(CONFIG_ARCH_SCMA11) || \    defined(CONFIG_ARCH_MX3)	if (list_empty(i->head)) {		if (extuart_intr_cleanup(up->port.line)) {			gpio_free_irq(2, 30, GPIO_HIGH_PRIO);		} else {			free_irq(up->port.irq, i);		}		serial_do_unlink(i, up);		return;	}#endif	if (list_empty(i->head))#if defined(CONFIG_MACH_ZEUSEVB)		extuart_intr_cleanup(up->port.line, up->port.irq, i);#else		free_irq(up->port.irq, i);#endif	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;	if (up->port.line == kgdb8250_ttyS)		return -EBUSY;	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);	}#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.	 */

⌨️ 快捷键说明

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