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

📄 serial.c

📁 In the ffuart.tar.gz it has one file. The serial.c is the source codes of the FFUART as a console
💻 C
📖 第 1 页 / 共 5 页
字号:
	serial_icr_write(info, UART_ACR, info->ACR | UART_ACR_ICRRD);	serial_out(info, UART_SCR, offset);	value = serial_in(info, UART_ICR);	serial_icr_write(info, UART_ACR, info->ACR);	return value;}/* * ------------------------------------------------------------ * rs_stop() and rs_start() * * This routines are called before setting or resetting tty->stopped. * They enable or disable transmitter interrupts, as necessary. * ------------------------------------------------------------ */static void rs_stop(struct tty_struct *tty){	struct async_struct *info = (struct async_struct *)tty->driver_data;	unsigned long flags;	if (serial_paranoia_check(info, tty->device, "rs_stop"))		return;		save_flags(flags); cli();	if (info->IER & UART_IER_THRI) {		info->IER &= ~UART_IER_THRI;		serial_out(info, UART_IER, info->IER);	}	if (info->state->type == PORT_16C950) {		info->ACR |= UART_ACR_TXDIS;		serial_icr_write(info, UART_ACR, info->ACR);	}	restore_flags(flags);}static void rs_start(struct tty_struct *tty){	struct async_struct *info = (struct async_struct *)tty->driver_data;	unsigned long flags;		if (serial_paranoia_check(info, tty->device, "rs_start"))		return;		save_flags(flags); cli();	if (info->xmit.head != info->xmit.tail	    && info->xmit.buf	    && !(info->IER & UART_IER_THRI)) {		info->IER |= UART_IER_THRI;		serial_out(info, UART_IER, info->IER);	}	if (info->state->type == PORT_16C950) {		info->ACR &= ~UART_ACR_TXDIS;		serial_icr_write(info, UART_ACR, info->ACR);	}	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;	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, UART_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_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_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_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_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)	ignore_char:#endif		*status = serial_inp(info, UART_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;	if (info->x_char) {		serial_outp(info, UART_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);		return;	}		count = info->xmit_fifo_size;	do {		serial_out(info, UART_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);		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);	}}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	do {		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);		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 (!(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;

⌨️ 快捷键说明

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