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

📄 8250.c

📁 IXP425 平台下嵌入式LINUX的串口的驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
#ifdef SERIAL_DEBUG_INTR	printk("rs_interrupt_multi(%d)...", irq);#endif	info = *(struct uart_info **)dev_id;	if (!info)		return;	if (!multi->port1) {		/* should never happen */		printk("rs_interrupt_multi: port1 NULL!\n");		return;	}	if (multi->port_monitor)		first_multi = inb(multi->port_monitor);	while (1) {		if (!info->tty ||		    (serial_in(info->port, UART_IIR) & UART_IIR_NO_INT))			goto next;		serial8250_handle_port(info, regs);	next:		info = info->next;		if (info)			continue;		info = *(struct uart_info **)dev_id;		/*		 * The user was a bonehead, and misconfigured their		 * multiport info.  Rather than lock up the kernel		 * in an infinite loop, if we loop too many times,		 * print a message and break out of the loop.		 */		if (pass_counter++ > RS_ISR_PASS_LIMIT) {			printk("Misconfigured multiport serial info "			       "for irq %d.  Breaking out irq loop\n", irq);			break;		}		if (multi->port_monitor)			printk("rs port monitor irq %d: 0x%x, 0x%x\n",				info->port->irq, first_multi,				inb(multi->port_monitor));		if ((inb(multi->port1) & multi->mask1) != multi->match1)			continue;		if (!multi->port2)			break;		if ((inb(multi->port2) & multi->mask2) != multi->match2)			continue;		if (!multi->port3)			break;		if ((inb(multi->port3) & multi->mask3) != multi->match3)			continue;		if (!multi->port4)			break;		if ((inb(multi->port4) & multi->mask4) != multi->match4)			continue;		break;	}#ifdef SERIAL_DEBUG_INTR	printk("end.\n");#endif}#endifstatic u_int serial8250_tx_empty(struct uart_port *port){	return serial_in(port, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;}static u_int serial8250_get_mctrl(struct uart_port *port){	unsigned long flags;	unsigned char status;	unsigned int ret;	save_flags(flags); cli();	status = serial_in(port, UART_MSR);	restore_flags(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, u_int mctrl){	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;	serial_out(port, UART_MCR, mcr);}static void serial8250_break_ctl(struct uart_port *port, int break_state){	if (break_state == -1)		port->port_lcr |= UART_LCR_SBC;	else		port->port_lcr &= ~UART_LCR_SBC;	serial_out(port, UART_LCR, port->port_lcr);}static int serial8250_startup(struct uart_port *port, struct uart_info *info){	void (*handler)(int, void *, struct pt_regs *);	int retval;	if (port->type == PORT_16C950) {		/* Wake up and initialize UART */		port->port_acr = 0;		serial_outp(port, UART_LCR, 0xBF);		serial_outp(port, UART_EFR, UART_EFR_ECB);		serial_outp(port, UART_IER, 0);		serial_outp(port, UART_LCR, 0);		serial_icr_write(port, UART_CSR, 0); /* Reset the UART */		serial_outp(port, UART_LCR, 0xBF);		serial_outp(port, UART_EFR, UART_EFR_ECB);		serial_outp(port, UART_LCR, 0);	}#ifdef CONFIG_SERIAL_RSA	/*	 * If this is an RSA port, see if we can kick it up to the	 * higher speed clock.	 */	if (port->type == PORT_RSA) {		if (port->uartclk != SERIAL_RSA_BAUD_BASE * 16 &&		    enable_rsa(port))			port->uartclk = SERIAL_RSA_BAUD_BASE * 16;		if (port->uartclk == SERIAL_RSA_BAUD_BASE * 16)			serial_outp(port, UART_RSA_FRR, 0);	}#endif	/*	 * Clear the FIFO buffers and disable them.	 * (they will be reeanbled in change_speed())	 */	if (uart_config[port->type].flags & UART_CLEAR_FIFO) {		serial_outp(port, UART_FCR, UART_FCR_ENABLE_FIFO);		serial_outp(port, UART_FCR, UART_FCR_ENABLE_FIFO |				UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);		serial_outp(port, UART_FCR, 0);	}	/*	 * Clear the interrupt registers.	 */	(void) serial_inp(port, UART_LSR);	(void) serial_inp(port, UART_RX);	(void) serial_inp(port, UART_IIR);	(void) serial_inp(port, 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 (!(port->flags & ASYNC_BUGGY_UART) &&	    (serial_inp(port, UART_LSR) == 0xff)) {		printk("ttyS%d: LSR safety check engaged!\n", port->line);		return -ENODEV;	}	/*	 * Allocate the IRQ if necessary	 */	if (port->irq && (!IRQ_ports[port->irq] ||			  !IRQ_ports[port->irq]->next_info)) {		handler = rs_interrupt_single;		if (IRQ_ports[port->irq]) {#ifdef CONFIG_SERIAL_8250_SHARE_IRQ			handler = rs_interrupt;			free_irq(port->irq, &IRQ_ports[port->irq]);#ifdef CONFIG_SERIAL_8250_MULTIPORT			if (rs_multiport[port->irq].port1)				handler = serial8250_interrupt_multi;#endif#else			return -EBUSY;#endif /* CONFIG_SERIAL_8250_SHARE_IRQ */		}		retval = request_irq(port->irq, handler, SA_SHIRQ,				     "serial", &IRQ_ports[port->irq]);		if (retval)			return retval;	}	/*	 * Insert serial port into IRQ chain.	 */	info->next_info = IRQ_ports[port->irq];	IRQ_ports[port->irq] = info;	/*	 * Now, initialize the UART	 */	serial_outp(port, UART_LCR, UART_LCR_WLEN8);#ifdef CONFIG_SERIAL_MANY_PORTS	if (port->flags & ASYNC_FOURPORT) {		if (port->irq == 0)			info->mctrl |= TIOCM_OUT1;	} else#endif		/*		 * Most PC uarts need OUT2 raised to enable interrupts.		 */		if (port->irq != 0)			info->mctrl |= TIOCM_OUT2;	/* FIXME: ALPHA_KLUDGE_MCR; */	serial8250_set_mctrl(port, info->mctrl);	/*	 * Finally, enable interrupts.  Note: Modem status interrupts	 * are set via change_speed(), which will be occuring imminently	 * anyway, so we don't enable them here.	 */	port->port_ier = UART_IER_RLSI | UART_IER_RDI;	serial_outp(port, UART_IER, port->port_ier);#ifdef CONFIG_SERIAL_MANY_PORTS	if (port->flags & ASYNC_FOURPORT) {		unsigned int ICP;		/*		 * Enable interrupts on the AST Fourport board		 */		ICP = (port->iobase & 0xfe0) | 0x01f;		outb_p(0x80, ICP);		(void) inb_p(ICP);	}#endif	/*	 * And clear the interrupt registers again for luck.	 */	(void) serial_inp(port, UART_LSR);	(void) serial_inp(port, UART_RX);	(void) serial_inp(port, UART_IIR);	(void) serial_inp(port, UART_MSR);	return 0;}static void serial8250_shutdown(struct uart_port *port, struct uart_info *info){	struct uart_info **infop;	int retval;	/*	 * First, disable all intrs from the port.	 */	port->port_ier = 0;	serial_outp(port, UART_IER, 0);	synchronize_irq();	/*	 * unlink the serial port from the IRQ chain...	 */	for (infop = &IRQ_ports[port->irq]; *infop; infop = &(*infop)->next_info)		if (*infop == info)			break;	if (*infop == info)		*infop = info->next_info;	/*	 * Free the IRQ, if necessary	 */	if (port->irq && (!IRQ_ports[port->irq] ||			  !IRQ_ports[port->irq]->next_info)) {		free_irq(port->irq, &IRQ_ports[port->irq]);		if (IRQ_ports[port->irq]) {			retval = request_irq(port->irq, rs_interrupt_single,					     SA_SHIRQ, "serial", &IRQ_ports[port->irq]);			if (retval)				printk("serial shutdown: request_irq: error %d"				       " couldn't reacquire IRQ.\n", retval);		}	}#ifdef CONFIG_SERIAL_MANY_PORTS	if (port->flags & ASYNC_FOURPORT) {		/* reset interrupts on the AST Fourport board */		inb((port->iobase & 0xfe0) | 0x1f);		info->mctrl |= TIOCM_OUT1;	} else#endif		info->mctrl &= ~TIOCM_OUT2;	/* FIXME: ALPHA_KLUDGE_MCR; */	serial8250_set_mctrl(port, info->mctrl);	/*	 * Disable break condition and FIFOs	 */	serial_out(port, UART_LCR, serial_inp(port, UART_LCR) & ~UART_LCR_SBC);	serial_outp(port, UART_FCR, UART_FCR_ENABLE_FIFO |				    UART_FCR_CLEAR_RCVR |				    UART_FCR_CLEAR_XMIT);	serial_outp(port, UART_FCR, 0);#ifdef CONFIG_SERIAL_RSA	/*	 * Reset the RSA board back to 115kbps compat mode.	 */	if (port->type == PORT_RSA &&	    port->uartclk == SERIAL_RSA_BAUD_BASE * 16 &&	    disable_rsa(port))		port->uartclk = SERIAL_RSA_BAUD_BASE_LO * 16;#endif	/*	 * Read data port to reset things	 */	(void) serial_in(port, UART_RX);}static void serial8250_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot){	unsigned char cval, fcr = 0;	unsigned long flags;	switch (cflag & CSIZE) {	case CS5:	cval = 0x00;	break;	case CS6:	cval = 0x01;	break;	case CS7:	cval = 0x02;	break;	default:	case CS8:	cval = 0x03;	break;	}	if (cflag & CSTOPB)		cval |= 0x04;	if (cflag & PARENB)		cval |= UART_LCR_PARITY;	if (!(cflag & PARODD))		cval |= UART_LCR_EPAR;#ifdef CMSPAR	if (cflag & CMSPAR)		cval |= UART_LCR_SPAR;#endif	/*	 * 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 && port->type == PORT_16C950 &&	    port->port_rev == 0x5201)		quot ++;	if (uart_config[port->type].flags & UART_USE_FIFO) {		if ((port->uartclk / quot) < (2400 * 16))			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;#ifdef CONFIG_SERIAL_RSA		else if (port->type == PORT_RSA)			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;#endif		else			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;	}	if (port->type == PORT_16750)		fcr |= UART_FCR7_64BYTE;	port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;	if (iflag & IGNPAR)		port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;	if (iflag & (BRKINT | PARMRK))		port->read_status_mask |= UART_LSR_BI;	/*	 * Characteres to ignore	 */	port->ignore_status_mask = 0;	if (iflag & IGNPAR)		port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;	if (iflag & IGNBRK) {		port->ignore_status_mask |= UART_LSR_BI;		/*		 * If we're ignoring parity and break indicators,		 * ignore overruns too (for real raw support).		 */		if (iflag & IGNPAR)			port->ignore_status_mask |= UART_LSR_OE;	}	/*	 * ignore all characters if CREAD is not set	 */	if ((cflag & CREAD) == 0)		port->ignore_status_mask |= UART_LSR_DR;	/*	 * CTS flow control flag and modem status interrupts	 */	port->port_ier &= ~UART_IER_MSI;	if (port->flags & ASYNC_HARDPPS_CD || cflag & CRTSCTS ||	    !(cflag & CLOCAL))		port->port_ier |= UART_IER_MSI;	/*	 * Ok, we're now changing the port state.  Do it with	 * interrupts disabled.	 */	save_flags(flags); cli();	serial_out(port, UART_IER, port->port_ier);	if (uart_config[port->type].flags & UART_STARTECH) {		serial_outp(port, UART_LCR, 0xBF);		serial_outp(port, UART_EFR, cflag & CRTSCTS ? UART_EFR_CTS :0);	}	serial_outp(port, UART_LCR, cval | UART_LCR_DLAB);	/* set DLAB */	serial_outp(port, UART_DLL, quot & 0xff);	/* LS of divisor */	serial_outp(port, UART_DLM, quot >> 8);		/* MS of divisor */	if (port->type == PORT_16750)		serial_outp(port, UART_FCR, fcr);	/* set fcr */	serial_outp(port, UART_LCR, cval);		/* reset DLAB */	port->port_lcr = cval;				/* Save LCR */	if (port->type != PORT_16750) {		if (fcr & UART_FCR_ENABLE_FIFO) {			/* emulated UARTs (Lucent Venus 167x) need two steps */			serial_outp(port, UART_FCR, UART_FCR_ENABLE_FIFO);		}		serial_outp(port, UART_FCR, fcr);	/* set fcr */	}	restore_flags(flags);}static void serial8250_pm(struct uart_port *port, u_int state, u_int oldstate){	if (state) {		/* sleep */		if (uart_config[port->type].flags & UART_STARTECH) {			/* Arrange to enter sleep mode */			serial_outp(port, UART_LCR, 0xBF);			serial_outp(port, UART_EFR, UART_EFR_ECB);			serial_outp(port, UART_LCR, 0);			serial_outp(port, UART_IER, UART_IERX_SLEEP);			serial_outp(port, UART_LCR, 0xBF);			serial_outp(port, UART_EFR, 0);			serial_outp(port, UART_LCR, 0);		}		if (port->type == PORT_16750) {			/* Arrange to enter sleep mode */			serial_outp(port, UART_IER, UART_IERX_SLEEP);		}	} else {		/* wake */		if (uart_config[port->type].flags & UART_STARTECH) {			/* Wake up UART */			serial_outp(port, UART_LCR, 0xBF);			serial_outp(port, UART_EFR, UART_EFR_ECB);			/*			 * Turn off LCR == 0xBF so we actually set the IER			 * register on the XR16C850			 */			serial_outp(port, UART_LCR, 0);			serial_outp(port, UART_IER, 0);			/*			 * Now reset LCR so we can turn off the ECB bit

⌨️ 快捷键说明

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