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

📄 serial_amba.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
					info->tty->hw_stopped = 0;					ambauart_enable_tx_interrupt(info);					ambauart_event(info, EVT_WRITE_WAKEUP);				}			} else {				if (!status) {					info->tty->hw_stopped = 1;					ambauart_disable_tx_interrupt(info);				}			}		}	}	wake_up_interruptible(&info->delta_msr_wait);}static void ambauart_int(int irq, void *dev_id, struct pt_regs *regs){	struct amba_info *info = dev_id;	unsigned int status, pass_counter = 0;#if DEBUG_LEDS	// tell the world	set_leds(get_leds() | RED_LED);#endif	status = UART_GET_INT_STATUS(info->port);	do {		/*		 * FIXME: what about clearing the interrupts?		 */		if (status & (AMBA_UARTIIR_RTIS | AMBA_UARTIIR_RIS))#ifdef SUPPORT_SYSRQ			ambauart_rx_chars(info, regs);#else			ambauart_rx_chars(info);#endif		if (status & AMBA_UARTIIR_TIS)			ambauart_tx_chars(info);		if (status & AMBA_UARTIIR_MIS)			ambauart_modem_status(info);		if (pass_counter++ > AMBA_ISR_PASS_LIMIT)			break;		status = UART_GET_INT_STATUS(info->port);	} while (status & (AMBA_UARTIIR_RTIS | AMBA_UARTIIR_RIS | AMBA_UARTIIR_TIS));#if DEBUG_LEDS	// tell the world	set_leds(get_leds() & ~RED_LED);#endif}static void ambauart_tasklet_action(unsigned long data){	struct amba_info *info = (struct amba_info *)data;	struct tty_struct *tty;	tty = info->tty;	if (!tty || !test_and_clear_bit(EVT_WRITE_WAKEUP, &info->event))		return;	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&	    tty->ldisc.write_wakeup)		(tty->ldisc.write_wakeup)(tty);	wake_up_interruptible(&tty->write_wait);}static int ambauart_startup(struct amba_info *info){	unsigned long flags;	unsigned long page;	int retval = 0;	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 (info->xmit.buf)		free_page(page);	else		info->xmit.buf = (unsigned char *) page;	/*	 * Allocate the IRQ	 */	retval = request_irq(info->port->irq, ambauart_int, 0, "amba", info);	if (retval) {		if (capable(CAP_SYS_ADMIN)) {			if (info->tty)				set_bit(TTY_IO_ERROR, &info->tty->flags);			retval = 0;		}		goto errout;	}	info->mctrl = 0;	if (info->tty->termios->c_cflag & CBAUD)		info->mctrl = TIOCM_RTS | TIOCM_DTR;	info->port->set_mctrl(info->port, info->mctrl);	/*	 * initialise the old status of the modem signals	 */	info->old_status = UART_GET_FR(info->port) & AMBA_UARTFR_MODEM_ANY;	/*	 * Finally, enable interrupts	 */	ambauart_enable_rx_interrupt(info);	if (info->tty)		clear_bit(TTY_IO_ERROR, &info->tty->flags);	info->xmit.head = info->xmit.tail = 0;	/*	 * Set up the tty->alt_speed kludge	 */	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;	}	/*	 * and set the speed of the serial port	 */	ambauart_change_speed(info, 0);	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 ambauart_shutdown(struct amba_info *info){	unsigned long flags;	if (!(info->flags & ASYNC_INITIALIZED))		return;	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 woken up	 */	wake_up_interruptible(&info->delta_msr_wait);	/*	 * Free the IRQ	 */	free_irq(info->port->irq, info);	if (info->xmit.buf) {		unsigned long pg = (unsigned long) info->xmit.buf;		info->xmit.buf = NULL;		free_page(pg);	}	/*	 * disable all interrupts, disable the port	 */	UART_PUT_CR(info->port, 0);	/* disable break condition and fifos */	UART_PUT_LCRH(info->port, UART_GET_LCRH(info->port) &		~(AMBA_UARTLCR_H_BRK | AMBA_UARTLCR_H_FEN));	if (!info->tty || (info->tty->termios->c_cflag & HUPCL))		info->mctrl &= ~(TIOCM_DTR|TIOCM_RTS);	info->port->set_mctrl(info->port, info->mctrl);	/* kill off our tasklet */	tasklet_kill(&info->tlet);	if (info->tty)		set_bit(TTY_IO_ERROR, &info->tty->flags);	info->flags &= ~ASYNC_INITIALIZED;	restore_flags(flags);}static void ambauart_change_speed(struct amba_info *info, struct termios *old_termios){	unsigned int lcr_h, baud, quot, cflag, old_cr, bits;	unsigned long flags;	if (!info->tty || !info->tty->termios)		return;	cflag = info->tty->termios->c_cflag;#if DEBUG	printk("ambauart_set_cflag(0x%x) called\n", cflag);#endif	/* byte size and parity */	switch (cflag & CSIZE) {	case CS5: lcr_h = AMBA_UARTLCR_H_WLEN_5; bits = 7;  break;	case CS6: lcr_h = AMBA_UARTLCR_H_WLEN_6; bits = 8;  break;	case CS7: lcr_h = AMBA_UARTLCR_H_WLEN_7; bits = 9;  break;	default:  lcr_h = AMBA_UARTLCR_H_WLEN_8; bits = 10; break; // CS8	}	if (cflag & CSTOPB) {		lcr_h |= AMBA_UARTLCR_H_STP2;		bits ++;	}	if (cflag & PARENB) {		lcr_h |= AMBA_UARTLCR_H_PEN;		bits++;		if (!(cflag & PARODD))			lcr_h |= AMBA_UARTLCR_H_EPS;	}	if (info->port->fifosize > 1)		lcr_h |= AMBA_UARTLCR_H_FEN;	do {		/* Determine divisor based on baud rate */		baud = tty_get_baud_rate(info->tty);		if (!baud)			baud = 9600;		if (baud == 38400 &&		    ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))			quot = info->state->custom_divisor;		else			quot = (info->port->uartclk / (16 * baud)) - 1;		if (!quot && old_termios) {			info->tty->termios->c_cflag &= ~CBAUD;			info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);			old_termios = NULL;		}	} while (quot == 0 && old_termios);	/* As a last resort, if the quotient is zero, default to 9600 bps */	if (!quot)		quot = (info->port->uartclk / (16 * 9600)) - 1;			info->timeout = (info->port->fifosize * HZ * bits * quot) /			 (info->port->uartclk / 16);	info->timeout += HZ/50;		/* Add .02 seconds of slop */	if (cflag & CRTSCTS)		info->flags |= ASYNC_CTS_FLOW;	else		info->flags &= ~ASYNC_CTS_FLOW;	if (cflag & CLOCAL)		info->flags &= ~ASYNC_CHECK_CD;	else		info->flags |= ASYNC_CHECK_CD;	/*	 * Set up parity check flag	 */#define RELEVENT_IFLAG(iflag)	((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))	info->read_status_mask = AMBA_UARTRSR_OE;	if (I_INPCK(info->tty))		info->read_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE;	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))		info->read_status_mask |= AMBA_UARTRSR_BE;	/*	 * Characters to ignore	 */	info->ignore_status_mask = 0;	if (I_IGNPAR(info->tty))		info->ignore_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE;	if (I_IGNBRK(info->tty)) {		info->ignore_status_mask |= AMBA_UARTRSR_BE;		/*		 * If we're ignoring parity and break indicators,		 * ignore overruns to (for real raw support).		 */		if (I_IGNPAR(info->tty))			info->ignore_status_mask |= AMBA_UARTRSR_OE;	}	/* first, disable everything */	save_flags(flags); cli();	old_cr = UART_GET_CR(info->port) &= ~AMBA_UARTCR_MSIE;	if ((info->flags & ASYNC_HARDPPS_CD) ||	    (cflag & CRTSCTS) ||	    !(cflag & CLOCAL))		old_cr |= AMBA_UARTCR_MSIE;	UART_PUT_CR(info->port, 0);	restore_flags(flags);	/* Set baud rate */	UART_PUT_LCRM(info->port, ((quot & 0xf00) >> 8));	UART_PUT_LCRL(info->port, (quot & 0xff));	/*	 * ----------v----------v----------v----------v-----	 * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L	 * ----------^----------^----------^----------^-----	 */	UART_PUT_LCRH(info->port, lcr_h);	UART_PUT_CR(info->port, old_cr);}static void ambauart_put_char(struct tty_struct *tty, u_char ch){	struct amba_info *info = tty->driver_data;	unsigned long flags;	if (!tty || !info->xmit.buf)		return;	save_flags(flags); cli();	if (CIRC_SPACE(info->xmit.head, info->xmit.tail, AMBA_XMIT_SIZE) != 0) {		info->xmit.buf[info->xmit.head] = ch;		info->xmit.head = (info->xmit.head + 1) & (AMBA_XMIT_SIZE - 1);	}	restore_flags(flags);}static void ambauart_flush_chars(struct tty_struct *tty){	struct amba_info *info = tty->driver_data;	unsigned long flags;	if (info->xmit.head == info->xmit.tail	    || tty->stopped	    || tty->hw_stopped	    || !info->xmit.buf)		return;	save_flags(flags); cli();	ambauart_enable_tx_interrupt(info);	restore_flags(flags);}static int ambauart_write(struct tty_struct *tty, int from_user,			  const u_char * buf, int count){	struct amba_info *info = tty->driver_data;	unsigned long flags;	int c, ret = 0;	if (!tty || !info->xmit.buf || !tmp_buf)		return 0;	save_flags(flags);	if (from_user) {		down(&tmp_buf_sem);		while (1) {			int c1;			c = CIRC_SPACE_TO_END(info->xmit.head,					      info->xmit.tail,					      AMBA_XMIT_SIZE);			if (count < c)				c = count;			if (c <= 0)				break;			c -= copy_from_user(tmp_buf, buf, c);			if (!c) {				if (!ret)					ret = -EFAULT;				break;			}			cli();			c1 = CIRC_SPACE_TO_END(info->xmit.head,					       info->xmit.tail,					       AMBA_XMIT_SIZE);			if (c1 < c)				c = c1;			memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);			info->xmit.head = (info->xmit.head + c) &					  (AMBA_XMIT_SIZE - 1);			restore_flags(flags);			buf += c;			count -= c;			ret += c;		}		up(&tmp_buf_sem);	} else {		cli();		while (1) {			c = CIRC_SPACE_TO_END(info->xmit.head,					      info->xmit.tail,					      AMBA_XMIT_SIZE);			if (count < c)				c = count;			if (c <= 0)				break;			memcpy(info->xmit.buf + info->xmit.head, buf, c);			info->xmit.head = (info->xmit.head + c) &					  (AMBA_XMIT_SIZE - 1);			buf += c;			count -= c;			ret += c;		}		restore_flags(flags);	}	if (info->xmit.head != info->xmit.tail	    && !tty->stopped	    && !tty->hw_stopped)		ambauart_enable_tx_interrupt(info);	return ret;}static int ambauart_write_room(struct tty_struct *tty){	struct amba_info *info = tty->driver_data;	return CIRC_SPACE(info->xmit.head, info->xmit.tail, AMBA_XMIT_SIZE);}static int ambauart_chars_in_buffer(struct tty_struct *tty){	struct amba_info *info = tty->driver_data;	return CIRC_CNT(info->xmit.head, info->xmit.tail, AMBA_XMIT_SIZE);}static void ambauart_flush_buffer(struct tty_struct *tty){	struct amba_info *info = tty->driver_data;	unsigned long flags;#if DEBUG	printk("ambauart_flush_buffer(%d) called\n",	       MINOR(tty->device) - tty->driver.minor_start);#endif	save_flags(flags); cli();	info->xmit.head = info->xmit.tail = 0;	restore_flags(flags);	wake_up_interruptible(&tty->write_wait);	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&	    tty->ldisc.write_wakeup)		(tty->ldisc.write_wakeup)(tty);}/* * This function is used to send a high-priority XON/XOFF character to * the device */static void ambauart_send_xchar(struct tty_struct *tty, char ch){	struct amba_info *info = tty->driver_data;	info->x_char = ch;	if (ch)		ambauart_enable_tx_interrupt(info);}static void ambauart_throttle(struct tty_struct *tty){	struct amba_info *info = tty->driver_data;	unsigned long flags;	if (I_IXOFF(tty))		ambauart_send_xchar(tty, STOP_CHAR(tty));	if (tty->termios->c_cflag & CRTSCTS) {		save_flags(flags); cli();		info->mctrl &= ~TIOCM_RTS;		info->port->set_mctrl(info->port, info->mctrl);		restore_flags(flags);	}}static void ambauart_unthrottle(struct tty_struct *tty){	struct amba_info *info = (struct amba_info *) tty->driver_data;	unsigned long flags;	if (I_IXOFF(tty)) {		if (info->x_char)			info->x_char = 0;		else			ambauart_send_xchar(tty, START_CHAR(tty));	}	if (tty->termios->c_cflag & CRTSCTS) {		save_flags(flags); cli();		info->mctrl |= TIOCM_RTS;		info->port->set_mctrl(info->port, info->mctrl);		restore_flags(flags);	}}static int get_serial_info(struct amba_info *info, struct serial_struct *retinfo)

⌨️ 快捷键说明

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