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

📄 serial.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 4 页
字号:
			if (recheck_count > 16)				printk("recheck_count = %d\n", recheck_count);#endif		}#ifdef ISR_HACK		serial_outp(info, UART_IER, 0);		serial_out(info, UART_IER, info->IER);#endif				info = info->next_port;		if (!info && !done) {			info = IRQ_ports[irq];			done = 1;			if (pass_number++ > 64)				break; 		/* Prevent infinite loops */		}	}	if ((info = IRQ_ports[irq]) != NULL) {#ifdef 0		do {			serial_outp(info, UART_IER, 0);			serial_out(info, UART_IER, info->IER);			info = info->next_port;		} while (info);#endif					if (irq && !done_work)			IRQ_timer[irq] = jiffies + 1500;		else			IRQ_timer[irq] = jiffies + IRQ_timeout[irq];		IRQ_active |= 1 << irq;	}	figure_RS_timer();}/* * ------------------------------------------------------------------- * Here ends the serial interrupt routines. * ------------------------------------------------------------------- *//* * This routine is called when we receive a break on a serial line. * It is executed out of the software interrupt routine. */static inline void handle_rs_break(struct async_struct *info){	if (info->flags & ASYNC_SAK)		do_SAK(info->tty);			if (!I_IGNBRK(info->tty) && I_BRKINT(info->tty)) {		flush_input(info->tty);		flush_output(info->tty);		if (info->tty->pgrp > 0)			kill_pg(info->tty->pgrp, SIGINT,1);	}}/* * 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_softint(void *unused){	int			i;	struct async_struct	*info;		for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {		if (clear_bit(i, rs_event)) {			if (!info->tty)					continue;			if (clear_bit(RS_EVENT_READ_PROCESS, &info->event)) {				TTY_READ_FLUSH(info->tty);			}			if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {				wake_up_interruptible(&info->tty->write_q.proc_list);			}			if (clear_bit(RS_EVENT_HANGUP, &info->event)) {				tty_hangup(info->tty);				wake_up_interruptible(&info->open_wait);				info->flags &= ~(ASYNC_NORMAL_ACTIVE|						 ASYNC_CALLOUT_ACTIVE);			}			if (clear_bit(RS_EVENT_BREAK, &info->event))				handle_rs_break(info);			if (clear_bit(RS_EVENT_OPEN_WAKEUP, &info->event)) {				wake_up_interruptible(&info->open_wait);			}		}	}}/* * This subroutine is called when the RS_TIMER goes off.  It is used * by the serial driver to run the rs_interrupt routine at certain * intervals, either because a serial interrupt might have been lost, * or because (in the case of IRQ=0) the serial port does not have an * interrupt, and is being checked only via the timer interrupts. */static void rs_timer(void){	int	i, mask;	int	timeout = 0;	for (i = 0, mask = 1; mask <= IRQ_active; i++, mask <<= 1) {		if ((mask & IRQ_active) && (IRQ_timer[i] <= jiffies)) {			IRQ_active &= ~mask;			cli();#ifdef SERIAL_DEBUG_TIMER			printk("rs_timer: rs_interrupt(%d)...", i);#endif			rs_interrupt(i);			sti();		}		if (mask & IRQ_active) {			if (!timeout || (IRQ_timer[i] < timeout))				timeout = IRQ_timer[i];		}	}	if (timeout) {		timer_table[RS_TIMER].expires = timeout;		timer_active |= 1 << RS_TIMER;	}}/* * --------------------------------------------------------------- * 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. * --------------------------------------------------------------- *//* * Grab all interrupts in preparation for doing an automatic irq * detection.  dontgrab is a mask of irq's _not_ to grab.  Returns a * mask of irq's which were grabbed and should therefore be freed * using free_all_interrupts(). */static int grab_all_interrupts(int dontgrab){	int 			irq_lines = 0;	int			i, mask;	struct sigaction 	sa;		sa.sa_handler = rs_probe;	sa.sa_flags = (SA_INTERRUPT);	sa.sa_mask = 0;	sa.sa_restorer = NULL;		for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {		if (!(mask & dontgrab) && !irqaction(i, &sa)) {			irq_lines |= mask;		}	}	return irq_lines;}/* * Release all interrupts grabbed by grab_all_interrupts */static void free_all_interrupts(int irq_lines){	int	i;		for (i = 0; i < 16; i++) {		if (irq_lines & (1 << i))			free_irq(i);	}}/* * 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. */static void figure_IRQ_timeout(int irq){	struct	async_struct	*info;	int	timeout = 6000;	/* 60 seconds === a long time :-) */	info = IRQ_ports[irq];	if (!info) {		IRQ_timeout[irq] = 6000;		return;	}	while (info) {		if (info->timeout < timeout)			timeout = info->timeout;		info = info->next_port;	}	if (!irq)		timeout = timeout / 2;	IRQ_timeout[irq] = timeout ? timeout : 1;}static int startup(struct async_struct * info, int get_irq){	unsigned short ICP;	unsigned long flags;	struct sigaction	sa;	int			retval;	if (info->flags & ASYNC_INITIALIZED)		return 0;	if (!info->port || !info->type) {		if (info->tty)			set_bit(TTY_IO_ERROR, &info->tty->flags);		return 0;	}	save_flags(flags); cli();#ifdef SERIAL_DEBUG_OPEN	printk("starting up ttys%d (irq %d)...", info->line, info->irq);#endif	/*	 * Allocate the IRQ if necessary	 */	if (get_irq && info->irq && !IRQ_ports[info->irq]) {		sa.sa_handler = rs_interrupt;		sa.sa_flags = (SA_INTERRUPT);		sa.sa_mask = 0;		sa.sa_restorer = NULL;		retval = irqaction(info->irq,&sa);		if (retval) {			restore_flags(flags);			return retval;		}	}	/*	 * Clear the FIFO buffers and disable them	 * (they will be reenabled in change_speed())	 */	if (info->type == PORT_16550A) {		serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |					     UART_FCR_CLEAR_XMIT));		info->xmit_fifo_size = 16;	} else		info->xmit_fifo_size = 1;	/*	 * 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);	/*	 * Now, initialize the UART 	 */	serial_outp(info, UART_LCR, UART_LCR_WLEN8);	/* reset DLAB */	if (info->flags & ASYNC_FOURPORT) 		serial_outp(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);	else		serial_outp(info, UART_MCR,			    UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);		/*	 * Finally, enable interrupts	 */#ifdef ISR_HACK	info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;	serial_outp(info, UART_IER, info->IER);	/* enable interrupts */#else	info->IER = (UART_IER_MSI | UART_IER_RLSI |		     UART_IER_THRI | UART_IER_RDI);	serial_outp(info, UART_IER, info->IER);	/* enable all intrs */#endif	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);	}	/*	 * 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);	/*	 * Set up parity check flag	 */	if (info->tty && info->tty->termios && I_INPCK(info->tty))		info->read_status_mask = (UART_LSR_OE | UART_LSR_BI |					  UART_LSR_FE | UART_LSR_PE);	else		info->read_status_mask = (UART_LSR_OE | UART_LSR_BI |					  UART_LSR_FE);	/*	 * Insert serial port into IRQ chain.	 */	info->prev_port = 0;	info->next_port = IRQ_ports[info->irq];	if (info->next_port)		info->next_port->prev_port = info;	IRQ_ports[info->irq] = info;	figure_IRQ_timeout(info->irq);	/*	 * Set up serial timers...	 */	IRQ_active |= 1 << info->irq;	figure_RS_timer();	/*	 * and set the speed of the serial port	 */	change_speed(info->line);	info->flags |= ASYNC_INITIALIZED;	restore_flags(flags);	return 0;}/* * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. */static void shutdown(struct async_struct * info, int do_free_irq){	unsigned long flags;	if (!(info->flags & ASYNC_INITIALIZED))		return;#ifdef SERIAL_DEBUG_OPEN	printk("Shutting down serial port %d (irq %d)....", info->line,	       info->irq);#endif		save_flags(flags); cli(); /* Disable interrupts */		/*	 * First unlink the serial port from the IRQ chain...	 */	if (info->next_port)		info->next_port->prev_port = info->prev_port;	if (info->prev_port)		info->prev_port->next_port = info->next_port;	else		IRQ_ports[info->irq] = info->next_port;	figure_IRQ_timeout(info->irq);		/*	 * Free the IRQ, if necessary	 */	if (do_free_irq && info->irq && !IRQ_ports[info->irq])		free_irq(info->irq);		info->IER = 0;	serial_outp(info, UART_IER, 0x00);	/* disable all intrs */	if (info->flags & ASYNC_FOURPORT) {		/* reset interrupts on the AST Fourport board */		(void) inb((info->port & 0xFE0) | 0x01F);	}	if (info->tty && !(info->tty->termios->c_cflag & HUPCL))		serial_outp(info, UART_MCR, UART_MCR_DTR);	else		/* reset DTR,RTS,OUT_2 */				serial_outp(info, UART_MCR, 0x00);	/* disable FIFO's */		serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |				     UART_FCR_CLEAR_XMIT));	(void)serial_in(info, UART_RX);    /* read data port to reset things */		if (info->tty)		set_bit(TTY_IO_ERROR, &info->tty->flags);		info->flags &= ~ASYNC_INITIALIZED;	restore_flags(flags);}/* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */static void change_speed(unsigned int line){	struct async_struct * info;	unsigned short port;	int	quot = 0;	unsigned cflag,cval,mcr,fcr;	int	i;	if (line >= NR_PORTS)		return;	info = rs_table + line;	if (!info->tty || !info->tty->termios)		return;	cflag = info->tty->termios->c_cflag;	if (!(port = info->port))		return;	i = cflag & CBAUD;	if (i == 15) {		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)			i += 1;		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)			i += 2;		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)			quot = info->custom_divisor;	}	if (quot) {		info->timeout = ((info->xmit_fifo_size*HZ*15*quot) /				 info->baud_base) + 2;	} else if (baud_table[i] == 134) {		quot = (2*info->baud_base / 269);		info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;	} else if (baud_table[i]) {		quot = info->baud_base / baud_table[i];		info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2;	} else {		quot = 0;		info->timeout = 0;	}	cli();	mcr = serial_in(info, UART_MCR);	if (quot) {		serial_out(info, UART_MCR, mcr | UART_MCR_DTR);	} else {		serial_out(info, UART_MCR, mcr & ~UART_MCR_DTR);		sti();		return;	}	sti();	/* byte size and parity */	cval = cflag & (CSIZE | CSTOPB);	cval >>= 4;	if (cflag & PARENB)		cval |= UART_LCR_PARITY;	if (!(cflag & PARODD))		cval |= UART_LCR_EPAR;	if (info->type == PORT_16550A) {		if ((info->baud_base / quot) < 2400)			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;		else			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;	} else		fcr = 0;		cli();	serial_outp(info, UART_LCR, cval | UART_LCR_DLAB);	/* set DLAB */	serial_outp(info, UART_DLL, quot & 0xff);	/* LS of divisor */	serial_outp(info, UART_DLM, quot >> 8);		/* MS of divisor */	serial_outp(info, UART_LCR, cval);		/* reset DLAB */	serial_outp(info, UART_FCR, fcr); 	/* set fcr */	sti();}/* * ------------------------------------------------------------ * rs_write() and friends * ------------------------------------------------------------ *//* * This routine is used by rs_write to restart transmitter interrupts, * which are disabled after we have a transmitter interrupt which went * unacknowledged because we had run out of data to transmit. *  * Note: this subroutine must be called with the interrupts *off* */static inline void restart_port(struct async_struct *info){	struct tty_queue * queue;	int head, tail, count;		if (!info)		return;	if (serial_inp(info, UART_LSR) & UART_LSR_THRE) {		if (info->x_char) {			serial_outp(info, UART_TX, info->x_char);			info->x_char = 0;		} else {			queue = &info->tty->write_q;			head = queue->head;			tail = queue->tail;			count = info->xmit_fifo_size;			while (count--) {				if (tail == head)					break;				serial_outp(info, UART_TX, queue->buf[tail++]);				tail &= TTY_BUF_SIZE-1;			}			queue->tail = tail;		}	}}	/* * This routine gets called when tty_write has put something into * the write_queue.   */void rs_write(struct tty_struct * tty){	struct async_struct *info;	if (!tty || tty->stopped || tty->hw_stopped)		return;	info = rs_table + DEV_TO_SL(tty->line);	cli();

⌨️ 快捷键说明

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