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

📄 8250.c

📁 IXP425 平台下嵌入式LINUX的串口的驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
		serial_outp(port, UART_LCR, UART_LCR_DLAB);		if (serial_in(port, UART_EFR) == 0) {			port->type = PORT_16650;		} else {			serial_outp(port, UART_LCR, 0xBF);			if (serial_in(port, UART_EFR) == 0)				autoconfig_startech_uarts(port);		}	}	if (port->type == PORT_16550A) {		/* Check for TI 16750 */		serial_outp(port, UART_LCR, save_lcr | UART_LCR_DLAB);		serial_outp(port, UART_FCR,			    UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);		scratch = serial_in(port, UART_IIR) >> 5;		if (scratch == 7) {			/*			 * If this is a 16750, and not a cheap UART			 * clone, then it should only go into 64 byte			 * mode if the UART_FCR7_64BYTE bit was set			 * while UART_LCR_DLAB was latched.			 */ 			serial_outp(port, UART_FCR, UART_FCR_ENABLE_FIFO);			serial_outp(port, UART_LCR, 0);			serial_outp(port, UART_FCR,				    UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);			scratch = serial_in(port, UART_IIR) >> 5;			if (scratch == 6)				port->type = PORT_16750;		}		serial_outp(port, UART_FCR, UART_FCR_ENABLE_FIFO);	}#if defined(CONFIG_SERIAL_RSA) && defined(MODULE)	/*	 * Only probe for RSA ports if we got the region.	 */	if (port->type == PORT_16550A && probeflags & PROBE_RSA) {		int i;		for (i = 0 ; i < PORT_RSA_MAX ; ++i) {			if (!probe_rsa[i] && !force_rsa[i])				break;			if (((probe_rsa[i] != port->iobase) ||			     check_region(port->iobase + UART_RSA_BASE, 16)) &&			    (force_rsa[i] != port->iobase))				continue;			if (!enable_rsa(port))				continue;			port->type = PORT_RSA;			port->uartclk = SERIAL_RSA_BAUD_BASE * 16;			break;		}	}#endif	serial_outp(port, UART_LCR, save_lcr);	if (port->type == PORT_16450) {		scratch = serial_in(port, UART_SCR);		serial_outp(port, UART_SCR, 0xa5);		status1 = serial_in(port, UART_SCR);		serial_outp(port, UART_SCR, 0x5a);		status2 = serial_in(port, UART_SCR);		serial_outp(port, UART_SCR, scratch);		if ((status1 != 0xa5) || (status2 != 0x5a))			port->type = PORT_8250;	}	port->fifosize = uart_config[port->type].dfl_xmit_fifo_size;	if (port->type == PORT_UNKNOWN) {		restore_flags(flags);		return;	}#ifdef CONFIG_SERIAL_RSA	if (port->iobase && port->type == PORT_RSA) {		release_region(port->iobase, 8);		request_region(port->iobase + UART_RSA_BASE, 16,			       "serial_rsa");	}#endif	/*	 * Reset the UART.	 */#ifdef CONFIG_SERIAL_RSA	if (port->type == PORT_RSA)		serial_outp(port, UART_RSA_FRR, 0);#endif	serial_outp(port, UART_MCR, save_mcr);	serial_outp(port, UART_FCR, (UART_FCR_ENABLE_FIFO |				     UART_FCR_CLEAR_RCVR |				     UART_FCR_CLEAR_XMIT));	serial_outp(port, UART_FCR, 0);	(void)serial_in(port, UART_RX);	serial_outp(port, UART_IER, 0);		restore_flags(flags);}static void autoconfig_irq(struct uart_port *port){	unsigned char save_mcr, save_ier;	unsigned long irqs;	int irq;#ifdef CONFIG_SERIAL_MANY_PORTS	unsigned char save_ICP = 0;	unsigned short ICP = 0;	if (port->flags & ASYNC_FOURPORT) {		ICP = (port->iobase & 0xfe0) | 0x1f;		save_ICP = inb_p(ICP);		outb_p(0x80, ICP);		(void) inb_p(ICP);	}#endif	/* forget possible initially masked and pending IRQ */	probe_irq_off(probe_irq_on());	save_mcr = serial_inp(port, UART_MCR);	save_ier = serial_inp(port, UART_IER);	serial_outp(port, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);		irqs = probe_irq_on();	serial_outp(port, UART_MCR, 0);	udelay (10);	if (port->flags & ASYNC_FOURPORT)  {		serial_outp(port, UART_MCR,			    UART_MCR_DTR | UART_MCR_RTS);	} else {		serial_outp(port, UART_MCR,			    UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);	}	serial_outp(port, UART_IER, 0x0f);	/* enable all intrs */	(void)serial_inp(port, UART_LSR);	(void)serial_inp(port, UART_RX);	(void)serial_inp(port, UART_IIR);	(void)serial_inp(port, UART_MSR);	serial_outp(port, UART_TX, 0xFF);	udelay (20);	irq = probe_irq_off(irqs);	serial_outp(port, UART_MCR, save_mcr);	serial_outp(port, UART_IER, save_ier);#ifdef CONFIG_SERIAL_MANY_PORTS	if (port->flags & ASYNC_FOURPORT)		outb_p(save_ICP, ICP);#endif	port->irq = (irq > 0)? irq : 0;}static void serial8250_stop_tx(struct uart_port *port, u_int from_tty){	if (port->port_ier & UART_IER_THRI) {		port->port_ier &= ~UART_IER_THRI;		serial_out(port, UART_IER, port->port_ier);	}	if (port->type == PORT_16C950) {		port->port_acr |= UART_ACR_TXDIS;		serial_icr_write(port, UART_ACR, port->port_acr);	}}static void serial8250_start_tx(struct uart_port *port, u_int nonempty, u_int from_tty){	if (nonempty && !(port->port_ier & UART_IER_THRI)) {		port->port_ier |= UART_IER_THRI;		serial_out(port, UART_IER, port->port_ier);	}	/*	 * We only do this from uart_start	 */	if (from_tty && port->type == PORT_16C950) {		port->port_acr &= ~UART_ACR_TXDIS;		serial_icr_write(port, UART_ACR, port->port_acr);	}}static void serial8250_stop_rx(struct uart_port *port){	port->port_ier &= ~UART_IER_RLSI;	port->read_status_mask &= ~UART_LSR_DR;	serial_out(port, UART_IER, port->port_ier);}static void serial8250_enable_ms(struct uart_port *port){	port->port_ier |= UART_IER_MSI;	serial_out(port, UART_IER, port->port_ier);}static _INLINE_ voidreceive_chars(struct uart_info *info, int *status, struct pt_regs *regs){	struct tty_struct *tty = info->tty;	struct uart_port *port = info->port;	unsigned char ch;	int max_count = 256;	do {		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {			tty->flip.tqueue.routine((void *)tty);			if (tty->flip.count >= TTY_FLIPBUF_SIZE)				return; // if TTY_DONT_FLIP is set		}		ch = serial_inp(port, UART_RX);		*tty->flip.char_buf_ptr = ch;		*tty->flip.flag_buf_ptr = TTY_NORMAL;		port->icount.rx++;		if (*status & (UART_LSR_BI | UART_LSR_PE |			       UART_LSR_FE | UART_LSR_OE)) {			/*			 * For statistics only			 */			if (*status & UART_LSR_BI) {				*status &= ~(UART_LSR_FE | UART_LSR_PE);				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.				 */				uart_handle_break(info, &serial8250_console);			} else if (*status & UART_LSR_PE)				port->icount.parity++;			else if (*status & UART_LSR_FE)				port->icount.frame++;			if (*status & UART_LSR_OE)				port->icount.overrun++;			/*			 * Mask off conditions which should be ingored.			 */			*status &= port->read_status_mask;#ifdef CONFIG_SERIAL_8250_CONSOLE			if (port->line == serial8250_console.index) {				/* Recover the break flag from console xmit */				*status |= lsr_break_flag;				lsr_break_flag = 0;			}#endif			if (*status & UART_LSR_BI) {#ifdef SERIAL_DEBUG_INTR				printk("handling break....");#endif				*tty->flip.flag_buf_ptr = TTY_BREAK;			} else if (*status & UART_LSR_PE)				*tty->flip.flag_buf_ptr = TTY_PARITY;			else if (*status & UART_LSR_FE)				*tty->flip.flag_buf_ptr = TTY_FRAME;		}		if (uart_handle_sysrq_char(info, ch, regs))			goto ignore_char;		if ((*status & port->ignore_status_mask) == 0) {			tty->flip.flag_buf_ptr++;			tty->flip.char_buf_ptr++;			tty->flip.count++;		}		if ((*status & 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->flip.flag_buf_ptr = TTY_OVERRUN;			tty->flip.flag_buf_ptr++;			tty->flip.char_buf_ptr++;			tty->flip.count++;		}	ignore_char:		*status = serial_inp(port, UART_LSR);	} while ((*status & UART_LSR_DR) && (max_count-- > 0));	tty_flip_buffer_push(tty);}static _INLINE_ void transmit_chars(struct uart_info *info, int *intr_done){	struct uart_port *port = info->port;	int count;	if (port->x_char) {		serial_outp(port, UART_TX, port->x_char);		port->icount.tx++;		port->x_char = 0;		if (intr_done)			*intr_done = 0;		return;	}	if (info->xmit.head == info->xmit.tail	    || info->tty->stopped	    || info->tty->hw_stopped) {		serial8250_stop_tx(port, 0);		return;	}	count = port->fifosize;	do {		serial_out(port, UART_TX, info->xmit.buf[info->xmit.tail]);		info->xmit.tail = (info->xmit.tail + 1) & (UART_XMIT_SIZE - 1);		port->icount.tx++;		if (info->xmit.head == info->xmit.tail)			break;	} while (--count > 0);	if (CIRC_CNT(info->xmit.head, info->xmit.tail, UART_XMIT_SIZE) <			WAKEUP_CHARS)		uart_event(info, EVT_WRITE_WAKEUP);#ifdef SERIAL_DEBUG_INTR	printk("THRE...");#endif	if (intr_done)		*intr_done = 0;	if (info->xmit.head == info->xmit.tail)		serial8250_stop_tx(info->port, 0);}static _INLINE_ void check_modem_status(struct uart_info *info){	struct uart_port *port = info->port;	int status;	status = serial_in(port, UART_MSR);	if (status & UART_MSR_ANY_DELTA) {		if (status & UART_MSR_TERI)			port->icount.rng++;		if (status & UART_MSR_DDSR)			port->icount.dsr++;		if (status & UART_MSR_DDCD)			uart_handle_dcd_change(info, status & UART_MSR_DCD);		if (status & UART_MSR_DCTS)			uart_handle_cts_change(info, status & UART_MSR_CTS);		wake_up_interruptible(&info->delta_msr_wait);	}}/* * This handles the interrupt from one port. */static inline voidserial8250_handle_port(struct uart_info *info, struct pt_regs *regs){	int status = serial_inp(info->port, UART_LSR);#ifdef SERIAL_DEBUG_INTR	printk("status = %x...", status);#endif	if (status & UART_LSR_DR)		receive_chars(info, &status, regs);	check_modem_status(info);	if (status & UART_LSR_THRE)		transmit_chars(info, 0);}#ifdef CONFIG_SERIAL_8250_SHARE_IRQ/* * This is the serial driver's generic interrupt routine */static void rs_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct uart_info *info, *end_mark = NULL;	int pass_counter = 0;#ifdef CONFIG_SERIAL_8250_MULTIPORT	int first_multi = 0;	unsigned long port_monitor = rs_multiport[irq].port_monitor;#endif#ifdef SERIAL_DEBUG_INTR	printk("rs_interrupt(%d)...", irq);#endif	info = *(struct uart_info **)dev_id;	if (!info)		return;#ifdef CONFIG_SERIAL_8250_MULTIPORT	if (port_monitor)		first_multi = inb(port_monitor);#endif	do {		if (!info->tty ||		    (serial_in(info->port, UART_IIR) & UART_IIR_NO_INT)) {		    	if (!end_mark)		    		end_mark = info;			goto next;		}#ifdef SERIAL_DEBUG_INTR		printk("IIR = %x...", serial_in(info->port, UART_IIR));#endif		end_mark = NULL;		serial8250_handle_port(info, regs);	next:		info = info->next_info;		if (info)			continue;		info = *(struct uart_info **)dev_id;		if (pass_counter++ > RS_ISR_PASS_LIMIT) {#if 0			printk("rs loop break\n");#endif			break; /* Prevent infinite loops */		}	} while (end_mark != info);#ifdef CONFIG_SERIAL_8250_MULTIPORT	if (port_monitor)		printk("rs port monitor (normal) irq %d: 0x%x, 0x%x\n",			info->port->irq, first_multi, inb(port_monitor));#endif#ifdef SERIAL_DEBUG_INTR	printk("end.\n");#endif}#endif/* * This is the serial driver's interrupt routine for a single port */static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs *regs){	struct uart_info *info;	int pass_counter = 0;#ifdef CONFIG_SERIAL_8250_MULTIPORT	int first_multi = 0;	unsigned long port_monitor = rs_multiport[irq].port_monitor;#endif#ifdef SERIAL_DEBUG_INTR	printk("rs_interrupt_single(%d)...", irq);#endif	info = *(struct uart_info **)dev_id;	if (!info || !info->tty)		return;#ifdef CONFIG_SERIAL_8250_MULTIPORT	if (port_monitor)		first_multi = inb(port_monitor);#endif	do {		serial8250_handle_port(info, regs);		if (pass_counter++ > RS_ISR_PASS_LIMIT) {#if 0			printk("rs_single loop break.\n");#endif			break;		}#ifdef SERIAL_DEBUG_INTR		printk("IIR = %x...", serial_in(info->port, UART_IIR));#endif	} while (!(serial_in(info->port, UART_IIR) & UART_IIR_NO_INT));#ifdef CONFIG_SERIAL_8250_MULTIPORT	if (port_monitor)		printk("rs port monitor (single) irq %d: 0x%x, 0x%x\n",			info->port->irq, first_multi, inb(port_monitor));#endif#ifdef SERIAL_DEBUG_INTR	printk("end.\n");#endif}#ifdef CONFIG_SERIAL_8250_MULTIPORT/* * This is the serial driver's interrupt routine for multiport boards */static void rs_interrupt_multi(int irq, void *dev_id, struct pt_regs *regs){	struct uart_info *info;	int pass_counter = 0;	struct rs_multiport_struct *multi = &rs_multiport[irq];	int first_multi = 0;

⌨️ 快捷键说明

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