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

📄 vacserial.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
 *  Following two functions were proposed by Pavel Osipenko  *  to make VAC/VIC behaviour more regular. */static void intr_begin(struct async_struct* info) {	serial_outw(info, VAC_UART_INT_MASK, 0);}static void intr_end(struct async_struct* info){	vac_outw(VAC_INT_CTRL_UART_DISABLE(info), VAC_INT_CTRL);	vac_outw(VAC_INT_CTRL_UART_ENABLE,        VAC_INT_CTRL); 	serial_outw(info, VAC_UART_INT_MASK, info->IER);}/* * 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 SERIAL_DEBUG_INTR	baget_printk("rs_interrupt(%d)...", irq);#endif	info = IRQ_ports[irq];	if (!info)		return;	do {	        intr_begin(info);  /* Mark we begin port handling */		if (!info->tty ||		     (serial_inw (info, VAC_UART_INT_STATUS) 		      & VAC_UART_STATUS_INTS) == 0) 		    {			if (!end_mark)				end_mark = info;			goto next;		    }		end_mark = 0;		info->last_active = jiffies;		status = serial_inw(info, VAC_UART_INT_STATUS);#ifdef SERIAL_DEBUG_INTR		baget_printk("status = %x...", status);#endif		if (status & VAC_UART_STATUS_RX_READY) {			receive_chars(info, &status);		}		check_modem_status(info);                if (status & VAC_UART_STATUS_TX_EMPTY)			transmit_chars(info, 0);	next:		intr_end(info);   /* Mark this port handled */		info = info->next_port;		if (!info) {			info = IRQ_ports[irq];			if (pass_counter++ > RS_ISR_PASS_LIMIT) {				break; 	/* Prevent infinite loops */			}			continue;		}	} while (end_mark != info);#ifdef SERIAL_DEBUG_INTR	baget_printk("end.\n");#endif}#endif /* #ifdef CONFIG_SERIAL_SHARE_IRQ *//* The original driver was simplified here:    two functions were joined to reduce code */#define rs_interrupt_single rs_interrupt/* * ------------------------------------------------------------------- * 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);	}}/* * --------------------------------------------------------------- * 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 ? timeout : 1;}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;	page = get_free_page(GFP_KERNEL);	if (!page)		return -ENOMEM;	save_flags(flags); cli();	if (info->flags & ASYNC_INITIALIZED) {		free_page(page);		goto errout;	}	if (!state->port || !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	baget_printk("starting up ttys%d (irq %d)...", info->line, state->irq);#endif	if (uart_config[info->state->type].flags & UART_STARTECH) {		/* Wake up UART */		serial_outp(info, VAC_UART_MODE, 0);		serial_outp(info, VAC_UART_INT_MASK, 0);	}	/*	 * 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, NULL);				handler = rs_interrupt;#else			retval = -EBUSY;			goto errout;#endif /* CONFIG_SERIAL_SHARE_IRQ */		} else 			handler = rs_interrupt_single;		retval = request_irq(state->irq, handler, IRQ_T(state),				     "serial", NULL);		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);	/*	 * Clear the interrupt registers.	 */     /* (void) serial_inw(info, VAC_UART_INT_STATUS); */   /* (see above) */	(void) serial_inw(info, VAC_UART_RX);	/*	 * Now, initialize the UART 	 */	serial_outp(info, VAC_UART_MODE, VAC_UART_MODE_INITIAL); /*reset DLAB*/	/*	 * Finally, enable interrupts	 */	info->IER = VAC_UART_INT_RX_BREAK_CHANGE | VAC_UART_INT_RX_ERRS | \                        VAC_UART_INT_RX_READY;	serial_outp(info, VAC_UART_INT_MASK, info->IER); /*enable interrupts*/		/*	 * And clear the interrupt registers again for luck.	 */	(void)serial_inp(info, VAC_UART_INT_STATUS);	(void)serial_inp(info, VAC_UART_RX);	if (info->tty)		clear_bit(TTY_IO_ERROR, &info->tty->flags);	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;	/*	 * Set up serial timers...	 */	mod_timer(&vacs_timer, jiffies + 2*HZ/100);	/*	 * and set the speed of the serial port	 */	change_speed(info);	info->flags |= ASYNC_INITIALIZED;	restore_flags(flags);	return 0;	errout:	restore_flags(flags);	return retval;}/* * 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){	unsigned long	flags;	struct serial_state *state;	int		retval;	if (!(info->flags & ASYNC_INITIALIZED))		return;	state = info->state;#ifdef SERIAL_DEBUG_OPEN	baget_printk("Shutting down serial port %d (irq %d)....", info->line,	       state->irq);#endif		save_flags(flags); cli(); /* Disable interrupts */	/*	 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq	 * here so the queue might never be waken up	 */	wake_up_interruptible(&info->delta_msr_wait);		/*	 * 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[state->irq] = info->next_port;	figure_IRQ_timeout(state->irq);		/*	 * Free the IRQ, if necessary	 */	if (state->irq && (!IRQ_ports[state->irq] ||			  !IRQ_ports[state->irq]->next_port)) {		if (IRQ_ports[state->irq]) {			free_irq(state->irq, NULL);			retval = request_irq(state->irq, rs_interrupt_single,					     IRQ_T(state), "serial", NULL);						if (retval)				printk("serial shutdown: request_irq: error %d"				       "  Couldn't reacquire IRQ.\n", retval);		} else			free_irq(state->irq, NULL);	}	if (info->xmit_buf) {		free_page((unsigned long) info->xmit_buf);		info->xmit_buf = 0;	}	info->IER = 0;	serial_outp(info, VAC_UART_INT_MASK, 0x00);	/* disable all intrs */		/* disable break condition */	serial_out(info, VAC_UART_MODE, serial_inp(info, VAC_UART_MODE) & \		   ~VAC_UART_MODE_SEND_BREAK);		if (info->tty)		set_bit(TTY_IO_ERROR, &info->tty->flags);	info->flags &= ~ASYNC_INITIALIZED;	restore_flags(flags);}/* *  When we set line mode, we call this function  *  for Baget-specific adjustments. */static inline unsigned short vac_uart_mode_fixup (unsigned short cval){#ifdef QUAD_UART_SPEED	/* 	 *  When we are using 4-x advantage in speed:	 *	 *  Disadvantage : can't support 75, 150 bauds	 *  Advantage    : can support 19200, 38400 bauds	 */	char speed = 7 & (cval >> 10);	cval &= ~(7 << 10);	cval |= VAC_UART_MODE_BAUD(speed-2);#endif	/* 	 *  In general, we have Tx and Rx ON all time	 *  and use int mask flag for their disabling.	 */	cval |= VAC_UART_MODE_RX_ENABLE;	cval |= VAC_UART_MODE_TX_ENABLE;	cval |= VAC_UART_MODE_CHAR_RX_ENABLE;	cval |= VAC_UART_MODE_CHAR_TX_ENABLE;        /* Low 4 bits are not used in UART */		cval &= ~0xf; 	return cval; }/* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */static void change_speed(struct async_struct *info){	unsigned short port;	int	quot = 0, baud_base, baud;	unsigned cflag, cval;	int	bits;	unsigned long	flags;	if (!info->tty || !info->tty->termios)		return;	cflag = info->tty->termios->c_cflag;	if (!(port = info->port))		return;	/* byte size and parity */	switch (cflag & CSIZE) {	      case CS7: cval = 0x0;  bits = 9; break;	      case CS8: cval = VAC_UART_MODE_8BIT_CHAR; bits = 10; break;	      /* Never happens, but GCC is too dumb to figure it out */	      case CS5: 	      case CS6: 	      default:  cval = 0x0; bits = 9; break;	      }	cval &= ~VAC_UART_MODE_PARITY_ENABLE;	if (cflag & PARENB) {		cval |= VAC_UART_MODE_PARITY_ENABLE;		bits++;	}	if (cflag & PARODD)		cval |= VAC_UART_MODE_PARITY_ODD;	/* Determine divisor based on baud rate */	baud = tty_get_baud_rate(info->tty);	if (!baud)		baud = 9600;    /* B0 transition handled in rs_set_termios */	baud_base = info->state->baud_base;	if (baud == 38400 &&	    ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))		quot = info->state->custom_divisor;	else {		if (baud == 134)			/* Special case since 134 is really 134.5 */			quot = (2*baud_base / 269);		else if (baud)			quot = baud_base / baud;	}	/* If the quotient is ever zero, default to 9600 bps */	if (!quot)		quot = baud_base / 9600;	info->quot = quot;	info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base);	info->timeout += HZ/50;		/* Add .02 seconds of slop */	serial_out(info, VAC_UART_INT_MASK, info->IER);	/*	 * Set up parity check flag	 */#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))	info->read_status_mask = VAC_UART_STATUS_RX_ERR_OVERRUN | \                VAC_UART_STATUS_TX_EMPTY | VAC_UART_STATUS_RX_READY;	if (I_INPCK(info->tty))		info->read_status_mask |= VAC_UART_STATUS_RX_ERR_FRAME | \			VAC_UART_STATUS_RX_ERR_PARITY;	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))		info->read_status_mask |= VAC_UART_STATUS_RX_BREAK_CHANGE;		/*	 * Characters to ignore	 */	info->ignore_status_mask = 0;	if (I_IGNPAR(info->tty))		info->ignore_status_mask |= VAC_UART_STATUS_RX_ERR_PARITY | \			VAC_UART_STATUS_RX_ERR_FRAME;	if (I_IGNBRK(info->tty)) {		info->ignore_status_mask |= VAC_UART_STATUS_RX_BREAK_CHANGE;		/*		 * If we're ignore parity and break indicators, ignore 		 * overruns too.  (For real raw support).		 */		if (I_IGNPAR(info->tty))			info->ignore_status_mask |= \				VAC_UART_STATUS_RX_ERR_OVERRUN;	}	/*	 * !!! ignore all characters if CREAD is not set	 */

⌨️ 快捷键说明

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