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

📄 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 页
字号:
		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)			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}#endif/* * ------------------------------------------------------------------- * Here ends the serial interrupt routines. * ------------------------------------------------------------------- *//* * This routine is used to handle the "bottom half" processing for the * serial driver, known also the "software interrupt" processing. * This processing is done at the kernel interrupt level, after the * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This * is where time-consuming activities which can not be done in the * interrupt driver proper are done; the interrupt driver schedules * them using rs_sched_event(), and they get done here. */static void do_serial_bh(void){	run_task_queue(&tq_serial);}static void do_softint(void *private_){	struct async_struct	*info = (struct async_struct *) private_;	struct tty_struct	*tty;		tty = info->tty;	if (!tty)		return;	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&		    tty->ldisc.write_wakeup)			(tty->ldisc.write_wakeup)(tty);		wake_up_interruptible(&tty->write_wait);#ifdef SERIAL_HAVE_POLL_WAIT		wake_up_interruptible(&tty->poll_wait);#endif	}}/* * This subroutine is called when the RS_TIMER goes off.  It is used * by the serial driver to handle ports that do not have an interrupt * (irq=0).  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 rs_timer(unsigned long dummy){	static unsigned long last_strobe;	struct async_struct *info;	unsigned int	i;	unsigned long flags;	if ((jiffies - last_strobe) >= RS_STROBE_TIME) {		for (i=0; i < NR_IRQS; i++) {			info = IRQ_ports[i];			if (!info)				continue;			save_flags(flags); cli();#ifdef CONFIG_SERIAL_SHARE_IRQ			if (info->next_port) {				do {					serial_out(info, UART_IER, 0);					info->IER |= UART_IER_THRI;					serial_out(info, UART_IER, info->IER);					info = info->next_port;				} while (info);#ifdef CONFIG_SERIAL_MULTIPORT				if (rs_multiport[i].port1)					rs_interrupt_multi(i, NULL, NULL);				else#endif					rs_interrupt(i, NULL, NULL);			} else#endif /* CONFIG_SERIAL_SHARE_IRQ */				rs_interrupt_single(i, NULL, NULL);			restore_flags(flags);		}	}	last_strobe = jiffies;	mod_timer(&serial_timer, jiffies + RS_STROBE_TIME);	if (IRQ_ports[0]) {		save_flags(flags); cli();#ifdef CONFIG_SERIAL_SHARE_IRQ		rs_interrupt(0, NULL, NULL);#else		rs_interrupt_single(0, NULL, NULL);#endif		restore_flags(flags);		mod_timer(&serial_timer, jiffies + IRQ_timeout[0]);	}}/* * --------------------------------------------------------------- * Low level utility subroutines for the serial driver:  routines to * figure out the appropriate timeout for an interrupt chain, routines * to initialize and startup a serial port, and routines to shutdown a * serial port.  Useful stuff like that. * --------------------------------------------------------------- *//* * This routine figures out the correct timeout for a particular IRQ. * It uses the smallest timeout of all of the serial ports in a * particular interrupt chain.  Now only used for IRQ 0.... */static void figure_IRQ_timeout(int irq){	struct	async_struct	*info;	int	timeout = 60*HZ;	/* 60 seconds === a long time :-) */	info = IRQ_ports[irq];	if (!info) {		IRQ_timeout[irq] = 60*HZ;		return;	}	while (info) {		if (info->timeout < timeout)			timeout = info->timeout;		info = info->next_port;	}	if (!irq)		timeout = timeout / 2;	IRQ_timeout[irq] = (timeout > 3) ? timeout-2 : 1;}#ifdef CONFIG_SERIAL_RSA/* Attempts to turn on the RSA FIFO.  Returns zero on failure */static int enable_rsa(struct async_struct *info){	unsigned char mode;	int result;	unsigned long flags;	save_flags(flags); cli();	mode = serial_inp(info, UART_RSA_MSR);	result = mode & UART_RSA_MSR_FIFO;	if (!result) {		serial_outp(info, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);		mode = serial_inp(info, UART_RSA_MSR);		result = mode & UART_RSA_MSR_FIFO;	}	restore_flags(flags);	return result;}/* Attempts to turn off the RSA FIFO.  Returns zero on failure */static int disable_rsa(struct async_struct *info){	unsigned char mode;	int result;	unsigned long flags;	save_flags(flags); cli();	mode = serial_inp(info, UART_RSA_MSR);	result = !(mode & UART_RSA_MSR_FIFO);	if (!result) {		serial_outp(info, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);		mode = serial_inp(info, UART_RSA_MSR);		result = !(mode & UART_RSA_MSR_FIFO);	}	restore_flags(flags);	return result;}#endif /* CONFIG_SERIAL_RSA */static int startup(struct async_struct * info){	unsigned long flags;	int	retval=0;	void (*handler)(int, void *, struct pt_regs *);	struct serial_state *state= info->state;	unsigned long page;#ifdef CONFIG_SERIAL_MANY_PORTS	unsigned short ICP;#endif	page = get_zeroed_page(GFP_KERNEL);	if (!page)		return -ENOMEM;	save_flags(flags); cli();	if (info->flags & ASYNC_INITIALIZED) {		free_page(page);		goto errout;	}	if (!CONFIGURED_SERIAL_PORT(state) || !state->type) {		if (info->tty)			set_bit(TTY_IO_ERROR, &info->tty->flags);		free_page(page);		goto errout;	}	if (info->xmit.buf)		free_page(page);	else		info->xmit.buf = (unsigned char *) page;#ifdef SERIAL_DEBUG_OPEN	printk("starting up ttys%d (irq %d)...", info->line, state->irq);#endif	if (uart_config[state->type].flags & UART_STARTECH) {		/* Wake up UART */		serial_outp(info, UART_LCR, 0xBF);		serial_outp(info, UART_EFR, UART_EFR_ECB);		/*		 * Turn off LCR == 0xBF so we actually set the IER		 * register on the XR16C850		 */		serial_outp(info, UART_LCR, 0);		serial_outp(info, UART_IER, 0);		/*		 * Now reset LCR so we can turn off the ECB bit		 */		serial_outp(info, UART_LCR, 0xBF);		serial_outp(info, UART_EFR, 0);		/*		 * For a XR16C850, we need to set the trigger levels		 */		if (state->type == PORT_16850) {			serial_outp(info, UART_FCTR, UART_FCTR_TRGD |					UART_FCTR_RX);			serial_outp(info, UART_TRG, UART_TRG_96);			serial_outp(info, UART_FCTR, UART_FCTR_TRGD |					UART_FCTR_TX);			serial_outp(info, UART_TRG, UART_TRG_96);		}		serial_outp(info, UART_LCR, 0);	}	if (state->type == PORT_16750) {		/* Wake up UART */		serial_outp(info, UART_IER, 0);	}	if (state->type == PORT_16C950) {		/* Wake up and initialize UART */		info->ACR = 0;		serial_outp(info, UART_LCR, 0xBF);		serial_outp(info, UART_EFR, UART_EFR_ECB);		serial_outp(info, UART_IER, 0);		serial_outp(info, UART_LCR, 0);		serial_icr_write(info, UART_CSR, 0); /* Reset the UART */		serial_outp(info, UART_LCR, 0xBF);		serial_outp(info, UART_EFR, UART_EFR_ECB);		serial_outp(info, 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 (state->type == PORT_RSA) {		if (state->baud_base != SERIAL_RSA_BAUD_BASE &&		    enable_rsa(info))			state->baud_base = SERIAL_RSA_BAUD_BASE;		if (state->baud_base == SERIAL_RSA_BAUD_BASE)			serial_outp(info, UART_RSA_FRR, 0);	}#endif#ifdef CONFIG_ARCH_PXA	if (state->type == PORT_PXA) {		switch ((long)state->iomem_base) {			case (long)&FFUART: CKEN |= CKEN6_FFUART; break;			case (long)&BTUART: CKEN |= CKEN7_BTUART; break;			case (long)&STUART: CKEN |= CKEN5_STUART; break;		}	}#endif	/*	 * Clear the FIFO buffers and disable them	 * (they will be reenabled in change_speed())	 */	if (uart_config[state->type].flags & UART_CLEAR_FIFO) {		serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);		serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |					     UART_FCR_CLEAR_RCVR |					     UART_FCR_CLEAR_XMIT));		serial_outp(info, UART_FCR, 0);	}	/*	 * Clear the interrupt registers.	 */	(void) serial_inp(info, UART_LSR);	(void) serial_inp(info, UART_RX);	(void) serial_inp(info, UART_IIR);	(void) serial_inp(info, 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 (!(info->flags & ASYNC_BUGGY_UART) &&	    (serial_inp(info, UART_LSR) == 0xff)) {		printk("ttyS%d: LSR safety check engaged!\n", state->line);		if (capable(CAP_SYS_ADMIN)) {			if (info->tty)				set_bit(TTY_IO_ERROR, &info->tty->flags);		} else			retval = -ENODEV;		goto errout;	}		/*	 * Allocate the IRQ if necessary	 */	if (state->irq && (!IRQ_ports[state->irq] ||			  !IRQ_ports[state->irq]->next_port)) {		if (IRQ_ports[state->irq]) {#ifdef CONFIG_SERIAL_SHARE_IRQ			free_irq(state->irq, &IRQ_ports[state->irq]);#ifdef CONFIG_SERIAL_MULTIPORT							if (rs_multiport[state->irq].port1)				handler = rs_interrupt_multi;			else#endif				handler = rs_interrupt;#else			retval = -EBUSY;			goto errout;#endif /* CONFIG_SERIAL_SHARE_IRQ */		} else 			handler = rs_interrupt_single;		retval = request_irq(state->irq, handler, SA_SHIRQ,				     "serial", &IRQ_ports[state->irq]);		if (retval) {			if (capable(CAP_SYS_ADMIN)) {				if (info->tty)					set_bit(TTY_IO_ERROR,						&info->tty->flags);				retval = 0;			}			goto errout;		}	}	/*	 * Insert serial port into IRQ chain.	 */	info->prev_port = 0;	info->next_port = IRQ_ports[state->irq];	if (info->next_port)		info->next_port->prev_port = info;	IRQ_ports[state->irq] = info;	figure_IRQ_timeout(state->irq);	/*	 * Now, initialize the UART 	 */	serial_outp(info, UART_LCR, UART_LCR_WLEN8);	/* reset DLAB */	info->MCR = 0;	if (info->tty->termios->c_cflag & CBAUD)		info->MCR = UART_MCR_DTR | UART_MCR_RTS;#ifdef CONFIG_SERIAL_MANY_PORTS	if (info->flags & ASYNC_FOURPORT) {		if (state->irq == 0)			info->MCR |= UART_MCR_OUT1;	} else#endif	{		if (state->irq != 0)			info->MCR |= UART_MCR_OUT2;		if (pxa_buggy_port(state->type) && state->irq != 0)			info->MCR ^= UART_MCR_OUT2;	}	info->MCR |= ALPHA_KLUDGE_MCR; 		/* Don't ask */	serial_outp(info, UART_MCR, info->MCR);		/*	 * Finally, enable interrupts	 */	info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;	if (pxa_port(state->type))		info->IER |= UART_IER_UUE | UART_IER_RTOIE;	serial_outp(info, UART_IER, info->IER);	/* enable interrupts */	#ifdef CONFIG_SERIAL_MANY_PORTS	if (info->flags & ASYNC_FOURPORT) {		/* Enable interrupts on the AST Fourport board */		ICP = (info->port & 0xFE0) | 0x01F;		outb_p(0x80, ICP);		(void) inb_p(ICP);	}#endif	/*	 * And clear the interrupt registers again for luck.	 */	(void)serial_inp(info, UART_LSR);	(void)serial_inp(info, UART_RX);	(void)serial_inp(info, UART_IIR);	(void)serial_inp(info, UART_MSR);	if (info->tty)		clear_bit(TTY_IO_ERROR, &info->tty->flags);	info->xmit.head = info->xmit.tail = 0;	/*	 * Set up serial timers...	 */	mod_timer(&serial_timer, jiffies + 2*HZ/100);	/*	 * Set up the tty->alt_speed kludge	 */#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */	if (info->tty) {		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)			info->tty->alt_speed = 57600;		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)			info->tty->alt_speed = 115200;		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)			info->tty->alt_speed = 230400;		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)			info->tty->alt_speed = 460800;	}#endif		/*	 * and set the speed of the serial port	 */

⌨️ 快捷键说明

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