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

📄 serial.c

📁 上传linux-jx2410的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	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(struct async_struct *info,			 struct termios *old_termios){	int	quot = 0, baud_base, baud;	unsigned cflag, cval, fcr = 0;	int	bits;	unsigned long	flags;	if (!info->tty || !info->tty->termios)		return;	cflag = info->tty->termios->c_cflag;	if (!CONFIGURED_SERIAL_PORT(info))		return;	/* byte size and parity */	switch (cflag & CSIZE) {	      case CS5: cval = 0x00; bits = 7; break;	      case CS6: cval = 0x01; bits = 8; break;	      case CS7: cval = 0x02; bits = 9; break;	      case CS8: cval = 0x03; bits = 10; break;	      /* Never happens, but GCC is too dumb to figure it out */	      default:  cval = 0x00; bits = 7; break;	      }	if (cflag & CSTOPB) {		cval |= 0x04;		bits++;	}	if (cflag & PARENB) {		cval |= UART_LCR_PARITY;		bits++;	}	if (!(cflag & PARODD))		cval |= UART_LCR_EPAR;#ifdef CMSPAR	if (cflag & CMSPAR)		cval |= UART_LCR_SPAR;#endif	/* 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 &&	if (((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 zero refuse the change */	if (!quot && old_termios) {		info->tty->termios->c_cflag &= ~CBAUD;		info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);		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 {			if (baud == 134)				/* Special case since 134 is really 134.5 */				quot = (2*baud_base / 269);			else if (baud)				quot = baud_base / baud;		}	}	/* As a last resort, if the quotient is 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 */	/* Set up FIFO's */	if (uart_config[info->state->type].flags & UART_USE_FIFO) {		if ((info->state->baud_base / quot) < 2400)			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIGGER_1;		else			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIGGER_8;	}		/* CTS flow control flag and modem status interrupts */	info->IER &= ~UART_IER_MSI;	if (info->flags & ASYNC_HARDPPS_CD)		info->IER |= UART_IER_MSI;	if (cflag & CRTSCTS) {		info->flags |= ASYNC_CTS_FLOW;		info->IER |= UART_IER_MSI;	} else		info->flags &= ~ASYNC_CTS_FLOW;	if (cflag & CLOCAL)		info->flags &= ~ASYNC_CHECK_CD;	else {		info->flags |= ASYNC_CHECK_CD;		info->IER |= UART_IER_MSI;	}	serial_out(info, UART_IER, info->IER);	/*	 * Set up parity check flag	 */#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))	info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;	if (I_INPCK(info->tty))		info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))		info->read_status_mask |= UART_LSR_BI;		/*	 * Characters to ignore	 */	info->ignore_status_mask = 0;	if (I_IGNPAR(info->tty))		info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;	if (I_IGNBRK(info->tty)) {		info->ignore_status_mask |= UART_LSR_BI;		/*		 * If we're ignore parity and break indicators, ignore 		 * overruns too.  (For real raw support).		 */		if (I_IGNPAR(info->tty))			info->ignore_status_mask |= UART_LSR_OE;	}	/*	 * !!! ignore all characters if CREAD is not set	 */	if ((cflag & CREAD) == 0)		info->ignore_status_mask |= UART_LSR_DR;	save_flags(flags); cli();	serial_outp(info, UART_CLK, quot & 0xffff);	serial_outp(info, UART_LCR, cval);	info->LCR = cval;				/* Save LCR */	restore_flags(flags);}static void rs_put_char(struct tty_struct *tty, unsigned char ch){	struct async_struct *info = (struct async_struct *)tty->driver_data;	unsigned long flags;	if (serial_paranoia_check(info, tty->device, "rs_put_char"))		return;	if (!tty || !info->xmit.buf)		return;	save_flags(flags); cli();	if (CIRC_SPACE(info->xmit.head,		       info->xmit.tail,		       SERIAL_XMIT_SIZE) == 0) {		restore_flags(flags);		return;	}	info->xmit.buf[info->xmit.head] = ch;	info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1);	restore_flags(flags);}static void rs_flush_chars(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_flush_chars"))		return;	if (info->xmit.head == info->xmit.tail	    || tty->stopped	    || tty->hw_stopped	    || !info->xmit.buf)		return;	save_flags(flags); cli();	info->IER |= UART_IER_THRI;	serial_out(info, UART_IER, info->IER);	restore_flags(flags);}static int rs_write(struct tty_struct * tty, int from_user,		    const unsigned char *buf, int count){	int	c, ret = 0;	struct async_struct *info = (struct async_struct *)tty->driver_data;	unsigned long flags;					if (serial_paranoia_check(info, tty->device, "rs_write"))		return 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,					      SERIAL_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,					       SERIAL_XMIT_SIZE);			if (c1 < c)				c = c1;			memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);			info->xmit.head = ((info->xmit.head + c) &					   (SERIAL_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,					      SERIAL_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) &					   (SERIAL_XMIT_SIZE-1));			buf += c;			count -= c;			ret += c;		}		restore_flags(flags);	}	if (info->xmit.head != info->xmit.tail	    && !tty->stopped	    && !tty->hw_stopped	    && !(info->IER & UART_IER_THRI)) {		info->IER |= UART_IER_THRI;		serial_out(info, UART_IER, info->IER);	}	return ret;}static int rs_write_room(struct tty_struct *tty){	struct async_struct *info = (struct async_struct *)tty->driver_data;	if (serial_paranoia_check(info, tty->device, "rs_write_room"))		return 0;	return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);}static int rs_chars_in_buffer(struct tty_struct *tty){	struct async_struct *info = (struct async_struct *)tty->driver_data;					if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))		return 0;	return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);}static void rs_flush_buffer(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_flush_buffer"))		return;	save_flags(flags); cli();	info->xmit.head = info->xmit.tail = 0;	restore_flags(flags);	wake_up_interruptible(&tty->write_wait);#ifdef SERIAL_HAVE_POLL_WAIT	wake_up_interruptible(&tty->poll_wait);#endif	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 rs_send_xchar(struct tty_struct *tty, char ch){	struct async_struct *info = (struct async_struct *)tty->driver_data;	if (serial_paranoia_check(info, tty->device, "rs_send_char"))		return;	info->x_char = ch;	if (ch) {		/* Make sure transmit interrupts are on */		info->IER |= UART_IER_THRI;		serial_out(info, UART_IER, info->IER);	}}/* * ------------------------------------------------------------ * rs_throttle() *  * This routine is called by the upper-layer tty layer to signal that * incoming characters should be throttled. * ------------------------------------------------------------ */static void rs_throttle(struct tty_struct * tty){	struct async_struct *info = (struct async_struct *)tty->driver_data;	unsigned long flags;#ifdef SERIAL_DEBUG_THROTTLE	char	buf[64];		printk("throttle %s: %d....\n", tty_name(tty, buf),	       tty->ldisc.chars_in_buffer(tty));#endif	if (serial_paranoia_check(info, tty->device, "rs_throttle"))		return;		if (I_IXOFF(tty))		rs_send_xchar(tty, STOP_CHAR(tty));	if (tty->termios->c_cflag & CRTSCTS)		info->MCR &= ~UART_MCR_RTS;	save_flags(flags); cli();	serial_out(info, UART_MCR, info->MCR);	restore_flags(flags);}static void rs_unthrottle(struct tty_struct * tty){	struct async_struct *info = (struct async_struct *)tty->driver_data;	unsigned long flags;#ifdef SERIAL_DEBUG_THROTTLE	char	buf[64];		printk("unthrottle %s: %d....\n", tty_name(tty, buf),	       tty->ldisc.chars_in_buffer(tty));#endif	if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))		return;		if (I_IXOFF(tty)) {		if (info->x_char)			info->x_char = 0;		else			rs_send_xchar(tty, START_CHAR(tty));	}	if (tty->termios->c_cflag & CRTSCTS)		info->MCR |= UART_MCR_RTS;	save_flags(flags); cli();	serial_out(info, UART_MCR, info->MCR);	restore_flags(flags);}/* * ------------------------------------------------------------ * rs_ioctl() and friends * ------------------------------------------------------------ */static int get_serial_info(struct async_struct * info,			   struct serial_struct * retinfo){	struct serial_struct tmp;	struct serial_state *state = info->state;   	if (!retinfo)		return -EFAULT;	memset(&tmp, 0, sizeof(tmp));	tmp.type = state->type;	tmp.line = state->line;	tmp.port = state->port;	if (HIGH_BITS_OFFSET)		tmp.port_high = state->port >> HIGH_BITS_OFFSET;	else		tmp.port_high = 0;	tmp.irq = state->irq;	tmp.flags = state->flags;	tmp.xmit_fifo_size = state->xmit_fifo_size;	tmp.baud_base = state->baud_base;	tmp.close_delay = state->close_delay;	tmp.closing_wait = state->closing_wait;	tmp.custom_divisor = state->custom_divisor;	tmp.hub6 = state->hub6;	tmp.io_type = state->io_type;	if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))		return -EFAULT;	return 0;}static int set_serial_info(struct async_struct * info,			   struct serial_struct * new_info){	struct serial_struct new_serial; 	struct serial_state old_state, *state;	unsigned int		i,change_irq,change_port;	int 			retval = 0;	unsigned long		new_port;	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))		return -EFAULT;	state = info->state;	old_state = *state;	new_port = new_serial.port;	if (HIGH_BITS_OFFSET)		new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;	change_irq = new_serial.irq != state->irq;	change_port = (new_port != ((int) state->port)) ||		(new_serial.hub6 != state->hub6);  	if (!capable(CAP_SYS_ADMIN)) {		if (change_irq || change_port ||		    (new_serial.baud_base != state->baud_base) ||		    (new_serial.type != state->type) ||		    (new_serial.close_delay != state->close_delay) ||		    (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||		    ((new_serial.flags & ~ASYNC_USR_MASK) !=		     (state->flags & ~ASYNC_USR_MASK)))			return -EPERM;		state->flags = ((state->flags & ~ASYNC_USR_MASK) |			       (new_serial.flags & ASYNC_USR_MASK));		info->flags = ((info->flags & ~ASYNC_USR_MASK) |			       (new_serial.flags & ASYNC_USR_MASK));		state->custom_divisor = new_serial.custom_divisor;		goto check_and_exit;	}	new_serial.irq = irq_cannonicalize(new_serial.irq);	if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) || 	    (new_serial.baud_base < 9600)|| (new_serial.type < PORT_UNKNOWN) ||	    (new_serial.type > PORT_MAX) || (new_serial.type == PORT_CIRRUS) ||	    (new_serial.type == PORT_STARTECH)) {		return -EINVAL;	}	if ((new_serial.type != state->type) ||	    (new_serial.xmit_fifo_size <= 0))		new_serial.xmit_fifo_size =			uart_config[new_serial.type].dfl_xmit_fifo_size;	/* Make sure address is not already in use */	if (new_serial.type) {		for (i = 0 ; i < NR_PORTS; i++)			if ((state != &rs_table[i]) &&			    (rs_table[i].port == new_port) &&			    rs_table[i].type)				return -EADDRINUSE;	}	if ((change_port || change_irq) && (state->count > 1))		return -EBUSY;

⌨️ 快捷键说明

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