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

📄 w90n745_uart.c

📁 winbond w90n745串口驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
	}*/	restore_flags(flags);}/* * ---------------------------------------------------------------------- * * Here starts the interrupt handling routines.  All of the following * subroutines are declared as inline and are folded into * rs_interrupt().  They were separated out for readability's sake. * * Note: rs_interrupt() is a "fast" interrupt, which means that it * runs with interrupts turned off.  People who may want to modify * rs_interrupt() should try to keep the interrupt handler as fast as * possible.  After you are done making modifications, it is not a bad * idea to do: *  * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c * * and look at the resulting assemble code in serial.s. * * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93 * ----------------------------------------------------------------------- *//* * This routine is used by the interrupt handler to schedule * processing in the software interrupt portion of the driver. */static _INLINE_ void rs_sched_event(struct async_struct *info,				  int event){	info->event |= 1 << event;	queue_task(&info->tqueue, &tq_serial);	mark_bh(SERIAL_BH);}static _INLINE_ void receive_chars(struct async_struct *info,				 int *status, struct pt_regs * regs){	struct tty_struct *tty = info->tty;	unsigned char ch;	struct	async_icount *icount;	int	max_count = 256;	//int lscr_status;#ifdef CONFIG_LEDMAN	ledman_cmd(LEDMAN_CMD_SET,		(info->line == 0) ? LEDMAN_COM1_RX : LEDMAN_COM2_RX);#endif	*status = serial_inp(info, COM_LSR);	icount = &info->state->icount;	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(info, COM_RX);		*tty->flip.char_buf_ptr = ch;		icount->rx++;		#ifdef SERIAL_DEBUG_INTR		printk("DR%02x:%02x...", ch, *status);#endif		*tty->flip.flag_buf_ptr = 0;		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);				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 defined(CONFIG_SERIAL_WINBOND_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)				if (info->line == sercons.index) {					if (!break_pressed) {						break_pressed = jiffies;						goto ignore_char;					}					break_pressed = 0;				}#endif				if (info->flags & ASYNC_SAK)					do_SAK(tty);			} else if (*status & UART_LSR_PE)				icount->parity++;			else if (*status & UART_LSR_FE)				icount->frame++;			if (*status & UART_LSR_OE)				icount->overrun++;			//			// Mask off conditions which should be ignored.			//			*status &= info->read_status_mask;#ifdef CONFIG_SERIAL_WINBOND_CONSOLE			if (info->line == sercons.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 defined(CONFIG_SERIAL_WINBOND_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)		if (break_pressed && info->line == sercons.index) {			if (ch != 0 &&			    time_before(jiffies, break_pressed + HZ*5)) {				handle_sysrq(ch, regs, NULL, NULL);				break_pressed = 0;				goto ignore_char;			}			break_pressed = 0;		}#endif		if ((*status & info->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.count++;			tty->flip.flag_buf_ptr++;			tty->flip.char_buf_ptr++;		}#if defined(CONFIG_SERIAL_WINBOND_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)	ignore_char:#endif		*status = serial_inp(info, COM_LSR);	} while ((*status & UART_LSR_DR) && (max_count-- > 0));#if (LINUX_VERSION_CODE > 131394) // 2.1.66	tty_flip_buffer_push(tty);#else	queue_task_irq_off(&tty->flip.tqueue, &tq_timer);#endif	}static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done){	int count;#ifdef CONFIG_LEDMAN	ledman_cmd(LEDMAN_CMD_SET,		(info->line == 0) ? LEDMAN_COM1_TX : LEDMAN_COM2_TX);#endif	if (info->x_char) {		serial_outp(info, COM_TX, info->x_char);		info->state->icount.tx++;		info->x_char = 0;		if (intr_done)			*intr_done = 0;		return;	}	if (info->xmit.head == info->xmit.tail	    || info->tty->stopped	    || info->tty->hw_stopped) {/*		info->IER &= ~UART_IER_THRI;		serial_out(info, UART_IER, info->IER);*/		disable_uart_tx_interrupt(info->line);		return;	}		count = info->xmit_fifo_size;	do {		while(!(serial_inp(info, COM_LSR)&UART_LSR_THRE));		serial_out(info, COM_TX, info->xmit.buf[info->xmit.tail]);		info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);		info->state->icount.tx++;		if (info->xmit.head == info->xmit.tail)			break;	} while (--count > 0);	while(!(serial_inp(info, COM_LSR)&UART_LSR_THRE));	if (CIRC_CNT(info->xmit.head,		     info->xmit.tail,		     SERIAL_XMIT_SIZE) < WAKEUP_CHARS)		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);#ifdef SERIAL_DEBUG_INTR	printk("THRE...");#endif	if (intr_done)		*intr_done = 0;	if (info->xmit.head == info->xmit.tail) {/*		info->IER &= ~UART_IER_THRI;		serial_out(info, UART_IER, info->IER);*/		disable_uart_tx_interrupt(info->line);	}}/*static _INLINE_ void check_modem_status(struct async_struct *info){	int	status;	struct	async_icount *icount;		status = serial_in(info, UART_MSR);	if (status & UART_MSR_ANY_DELTA) {		icount = &info->state->icount;		// update input line counters		if (status & UART_MSR_TERI)			icount->rng++;		if (status & UART_MSR_DDSR)			icount->dsr++;		if (status & UART_MSR_DDCD) {			icount->dcd++;#ifdef CONFIG_HARD_PPS			if ((info->flags & ASYNC_HARDPPS_CD) &&			    (status & UART_MSR_DCD))				hardpps();#endif		}		if (status & UART_MSR_DCTS)			icount->cts++;		wake_up_interruptible(&info->delta_msr_wait);	}	if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))		printk("ttys%d CD now %s...", info->line,		       (status & UART_MSR_DCD) ? "on" : "off");#endif				if (status & UART_MSR_DCD)			wake_up_interruptible(&info->open_wait);		else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&			   (info->flags & ASYNC_CALLOUT_NOHUP))) {#ifdef SERIAL_DEBUG_OPEN			printk("doing serial hangup...");#endif			if (info->tty)				tty_hangup(info->tty);		}	}	if (info->flags & ASYNC_CTS_FLOW) {		if (info->tty->hw_stopped) {			if (status & UART_MSR_CTS) {#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))				printk("CTS tx start...");#endif				info->tty->hw_stopped = 0;				info->IER |= UART_IER_THRI;				serial_out(info, UART_IER, info->IER);				rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);				return;			}		} else {			if (!(status & UART_MSR_CTS)) {#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))				printk("CTS tx stop...");#endif				info->tty->hw_stopped = 1;				info->IER &= ~UART_IER_THRI;				serial_out(info, UART_IER, info->IER);			}		}	}}*/#ifdef CONFIG_SERIAL_SHARE_IRQ/* * This is the serial driver's generic interrupt routine *//*static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs){	int status;	struct async_struct * info;	int pass_counter = 0;	struct async_struct *end_mark = 0;#ifdef CONFIG_SERIAL_MULTIPORT		int first_multi = 0;	struct rs_multiport_struct *multi;#endif#ifdef SERIAL_DEBUG_INTR	printk("rs_interrupt(%d)...", irq);#endif	info = IRQ_ports[irq];	if (!info)		return;#ifdef CONFIG_SERIAL_MULTIPORT		multi = &rs_multiport[irq];	if (multi->port_monitor)		first_multi = inb(multi->port_monitor);#endif	do {		if (!info->tty ||		    (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) {			if (!end_mark)				end_mark = info;			goto next;		}#ifdef SERIAL_DEBUG_INTR		printk("IIR = %x...", serial_in(info, UART_IIR));#endif		end_mark = 0;		info->last_active = jiffies;		status = serial_inp(info, 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);	next:		info = info->next_port;		if (!info) {			info = IRQ_ports[irq];			if (pass_counter++ > RS_ISR_PASS_LIMIT) {#if 0				printk("rs loop break\n");#endif				break; 	// Prevent infinite loops			}			continue;		}	} while (end_mark != info);#ifdef CONFIG_SERIAL_MULTIPORT		if (multi->port_monitor)		printk("rs port monitor (normal) irq %d: 0x%x, 0x%x\n",		       info->state->irq, first_multi,		       inb(multi->port_monitor));#endif#ifdef SERIAL_DEBUG_INTR	printk("end.\n");#endif}*/#endif /* #ifdef CONFIG_SERIAL_SHARE_IRQ *//* * 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){	int status;	int pass_counter = 0;	struct async_struct * info;#ifdef CONFIG_SERIAL_MULTIPORT		int first_multi = 0;	struct rs_multiport_struct *multi;#endif	#ifdef SERIAL_DEBUG_INTR	printk("rs_interrupt_single(%d)...", irq);#endif	info = IRQ_ports[irq];	if (!info || !info->tty)		return;#ifdef CONFIG_SERIAL_MULTIPORT		multi = &rs_multiport[irq];	if (multi->port_monitor)		first_multi = inb(multi->port_monitor);#endif	status = serial_inp(info, COM_IIR);	do {		#ifdef SERIAL_DEBUG_INTR		printk("status = %x...", status);#endif#if 1		if (status & UART_IIR_DR)			receive_chars(info, &status, regs);// 1/28/2003 Winbond W90N745 doesn't have modem relate registers//		check_modem_status(info);		if (status & UART_IIR_THRE)			transmit_chars(info, 0);#endif		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, UART_IIR));#endif	} while (((status = serial_inp(info, COM_IIR)) & (UART_IIR_DR | UART_IIR_THRE)));//	} while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT));	info->last_active = jiffies;#ifdef CONFIG_SERIAL_MULTIPORT		if (multi->port_monitor)		printk("rs port monitor (single) irq %d: 0x%x, 0x%x\n",		       info->state->irq, first_multi,		       inb(multi->port_monitor));#endif#ifdef SERIAL_DEBUG_INTR	printk("end.\n");#endif}#ifdef CONFIG_SERIAL_MULTIPORT	/* * This is the serial driver's for multiport boards *//*static void rs_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs){	int status;	struct async_struct * info;	int pass_counter = 0;	int first_multi= 0;	struct rs_multiport_struct *multi;#ifdef SERIAL_DEBUG_INTR	printk("rs_interrupt_multi(%d)...", irq);#endif	info = IRQ_ports[irq];	if (!info)		return;	multi = &rs_multiport[irq];	if (!multi->port1) {		// Should never happen		printk("rs_interrupt_multi: NULL port1!\n");		return;	}	if (multi->port_monitor)		first_multi = inb(multi->port_monitor);		while (1) {		if (!info->tty ||		    (serial_in(info, UART_IIR) & UART_IIR_NO_INT))			goto next;		info->last_active = jiffies;		status = serial_inp(info, 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);	next:		info = info->next_port;		if (info)			continue;		info = IRQ_ports[irq];		//		// 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->state->irq, first_multi,			       inb(multi->port_monitor));		if ((inb(multi->port1) & multi->mask1) != multi->match1)			continue;		if (!multi->port2)

⌨️ 快捷键说明

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