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

📄 8250.c

📁 linux 2.6内核下8250串口设备驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
	else		serial_outp(up, UART_IER, 0); out:		spin_unlock_irqrestore(&up->port.lock, flags);//	restore_flags(flags);	DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name);}static void autoconfig_irq(struct uart_8250_port *up){	unsigned char save_mcr, save_ier;	unsigned char save_ICP = 0;	unsigned int ICP = 0;	unsigned long irqs;	int irq;	if (up->port.flags & UPF_FOURPORT) {		ICP = (up->port.iobase & 0xfe0) | 0x1f;		save_ICP = inb_p(ICP);		outb_p(0x80, ICP);		(void) inb_p(ICP);	}	/* forget possible initially masked and pending IRQ */	probe_irq_off(probe_irq_on());	save_mcr = serial_inp(up, UART_MCR);	save_ier = serial_inp(up, UART_IER);	serial_outp(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);		irqs = probe_irq_on();	serial_outp(up, UART_MCR, 0);	udelay (10);	if (up->port.flags & UPF_FOURPORT)  {		serial_outp(up, UART_MCR,			    UART_MCR_DTR | UART_MCR_RTS);	} else {		serial_outp(up, UART_MCR,			    UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);	}	serial_outp(up, UART_IER, 0x0f);	/* enable all intrs */	(void)serial_inp(up, UART_LSR);	(void)serial_inp(up, UART_RX);	(void)serial_inp(up, UART_IIR);	(void)serial_inp(up, UART_MSR);	serial_outp(up, UART_TX, 0xFF);	udelay (20);	irq = probe_irq_off(irqs);	serial_outp(up, UART_MCR, save_mcr);	serial_outp(up, UART_IER, save_ier);	if (up->port.flags & UPF_FOURPORT)		outb_p(save_ICP, ICP);	up->port.irq = (irq > 0) ? irq : 0;}static inline void __stop_tx(struct uart_8250_port *p){	if (p->ier & UART_IER_THRI) {		p->ier &= ~UART_IER_THRI;		serial_out(p, UART_IER, p->ier);	}}static void serial8250_stop_tx(struct uart_port *port){	struct uart_8250_port *up = (struct uart_8250_port *)port;	__stop_tx(up);	/*	 * We really want to stop the transmitter from sending.	 */	if (up->port.type == PORT_16C950) {		up->acr |= UART_ACR_TXDIS;		serial_icr_write(up, UART_ACR, up->acr);	}}static void transmit_chars(struct uart_8250_port *up);static void serial8250_start_tx(struct uart_port *port){	struct uart_8250_port *up = (struct uart_8250_port *)port;	if (!(up->ier & UART_IER_THRI)) {		up->ier |= UART_IER_THRI;		serial_out(up, UART_IER, up->ier);		if (up->bugs & UART_BUG_TXEN) {			unsigned char lsr, iir;			lsr = serial_in(up, UART_LSR);			iir = serial_in(up, UART_IIR);			if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT)				transmit_chars(up);		}	}	/*	 * Re-enable the transmitter if we disabled it.	 */	if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) {		up->acr &= ~UART_ACR_TXDIS;		serial_icr_write(up, UART_ACR, up->acr);	}}static void serial8250_stop_rx(struct uart_port *port){	struct uart_8250_port *up = (struct uart_8250_port *)port;	up->ier &= ~UART_IER_RLSI;	up->port.read_status_mask &= ~UART_LSR_DR;	serial_out(up, UART_IER, up->ier);}static void serial8250_enable_ms(struct uart_port *port){	struct uart_8250_port *up = (struct uart_8250_port *)port;	/* no MSR capabilities */	if (up->bugs & UART_BUG_NOMSR)		return;	up->ier |= UART_IER_MSI;	serial_out(up, UART_IER, up->ier);}static voidreceive_chars(struct uart_8250_port *up, int *status){	struct tty_struct *tty = up->port.info->tty;	unsigned char ch, lsr = *status;	int max_count = 256;	char flag;	do {		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 ignored.			 */			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))			goto ignore_char;		uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);	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 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_tx_stopped(&up->port)) {		serial8250_stop_tx(&up->port);		return;	}	if (uart_circ_empty(xmit)) {		__stop_tx(up);		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))		__stop_tx(up);}static unsigned int check_modem_status(struct uart_8250_port *up){	unsigned int status = serial_in(up, UART_MSR);	if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI) {		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);	}	return status;}/* * This handles the interrupt from one port. */static inline voidserial8250_handle_port(struct uart_8250_port *up){	unsigned int status;	spin_lock(&up->port.lock);	status = serial_inp(up, UART_LSR);	DEBUG_INTR("status = %x...", status);	if (status & UART_LSR_DR)		receive_chars(up, &status);	check_modem_status(up);	if (status & UART_LSR_THRE)		transmit_chars(up);	spin_unlock(&up->port.lock);}/* * 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 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);		iir = serial_in(up, UART_IIR);		if (!(iir & UART_IIR_NO_INT)) {			serial8250_handle_port(up);			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);}/* * 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);}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 ? IRQF_SHARED : 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))		serial8250_handle_port(up);	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 int status;	unsigned int ret;	status = check_modem_status(up);	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;	unsigned char lsr, iir;	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);	}#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

⌨️ 快捷键说明

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