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

📄 serial.c

📁 基于16450/16550A的多串口驱动,估计很多人在找吧
💻 C
📖 第 1 页 / 共 5 页
字号:
	save_flags(flags); cli();	if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {		restore_flags(flags);		return;	}	info->xmit_buf[info->xmit_head++] = ch;	info->xmit_head &= SERIAL_XMIT_SIZE-1;	info->xmit_cnt++;	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_cnt <= 0 || 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, total = 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;	    	if (from_user)		down(&tmp_buf_sem);	save_flags(flags);	while (1) {		cli();				c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,				   SERIAL_XMIT_SIZE - info->xmit_head));		if (c <= 0)			break;		if (from_user) {			memcpy_fromfs(tmp_buf, buf, c);			c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,				       SERIAL_XMIT_SIZE - info->xmit_head));			memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);		} else			memcpy(info->xmit_buf + info->xmit_head, buf, c);		info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);		info->xmit_cnt += c;		restore_flags(flags);		buf += c;		count -= c;		total += c;	}	if (from_user)		up(&tmp_buf_sem);	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&	    !(info->IER & UART_IER_THRI)) {		info->IER |= UART_IER_THRI;		serial_out(info, UART_IER, info->IER);	}	restore_flags(flags);	return total;}static int rs_write_room(struct tty_struct *tty){	struct async_struct *info = (struct async_struct *)tty->driver_data;	int	ret;					if (serial_paranoia_check(info, tty->device, "rs_write_room"))		return 0;	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;	if (ret < 0)		ret = 0;	return ret;}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 info->xmit_cnt;}static void rs_flush_buffer(struct tty_struct *tty){	struct async_struct *info = (struct async_struct *)tty->driver_data;					if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))		return;	cli();	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;	sti();	wake_up_interruptible(&tty->write_wait);	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&	    tty->ldisc.write_wakeup)		(tty->ldisc.write_wakeup)(tty);}/* * ------------------------------------------------------------ * 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;#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))		info->x_char = STOP_CHAR(tty);	info->MCR &= ~UART_MCR_RTS;	info->MCR_noint &= ~UART_MCR_RTS;	cli();	serial_out(info, UART_MCR, info->MCR);	sti();}static void rs_unthrottle(struct tty_struct * tty){	struct async_struct *info = (struct async_struct *)tty->driver_data;#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			info->x_char = START_CHAR(tty);	}	info->MCR |= UART_MCR_RTS;	info->MCR_noint |= UART_MCR_RTS;	cli();	serial_out(info, UART_MCR, info->MCR);	sti();}/* * ------------------------------------------------------------ * rs_ioctl() and friends * ------------------------------------------------------------ */static int get_serial_info(struct async_struct * info,			   struct serial_struct * retinfo){	struct serial_struct tmp;  	if (!retinfo)		return -EFAULT;	memset(&tmp, 0, sizeof(tmp));	tmp.type = info->type;	tmp.line = info->line;	tmp.port = info->port;	tmp.irq = info->irq;	tmp.flags = info->flags;	tmp.baud_base = info->baud_base;	tmp.close_delay = info->close_delay;	tmp.closing_wait = info->closing_wait;	tmp.custom_divisor = info->custom_divisor;	tmp.hub6 = info->hub6;	memcpy_tofs(retinfo,&tmp,sizeof(*retinfo));	return 0;}static int set_serial_info(struct async_struct * info,			   struct serial_struct * new_info){	struct serial_struct new_serial;	struct async_struct old_info;	unsigned int		i,change_irq,change_port;	int 			retval = 0;	if (!new_info)		return -EFAULT;	memcpy_fromfs(&new_serial,new_info,sizeof(new_serial));	old_info = *info;	change_irq = new_serial.irq != info->irq;	change_port = (new_serial.port != info->port) || (new_serial.hub6 != info->hub6);	if (!suser()) {		if (change_irq || change_port ||		    (new_serial.baud_base != info->baud_base) ||		    (new_serial.type != info->type) ||		    (new_serial.close_delay != info->close_delay) ||		    ((new_serial.flags & ~ASYNC_USR_MASK) !=		     (info->flags & ~ASYNC_USR_MASK)))			return -EPERM;		info->flags = ((info->flags & ~ASYNC_USR_MASK) |			       (new_serial.flags & ASYNC_USR_MASK));		info->custom_divisor = new_serial.custom_divisor;		goto check_and_exit;	}#ifndef CONFIG_COLDFIRE	if (new_serial.irq == 2)		new_serial.irq = 9;	if ((new_serial.irq > 15) || (new_serial.port > 0xffff) ||	    (new_serial.type < PORT_UNKNOWN) || (new_serial.type > PORT_MAX)) {		return -EINVAL;	}#endif	/* Make sure address is not already in use */	if (new_serial.type) {		for (i = 0 ; i < NR_PORTS; i++)			if ((info != &rs_table[i]) &&			    (rs_table[i].port == new_serial.port) &&			    rs_table[i].type)				return -EADDRINUSE;	}	if ((change_port || change_irq) && (info->count > 1))		return -EBUSY;	/*	 * OK, past this point, all the error checking has been done.	 * At this point, we start making changes.....	 */	info->baud_base = new_serial.baud_base;	info->flags = ((info->flags & ~ASYNC_FLAGS) |			(new_serial.flags & ASYNC_FLAGS));	info->custom_divisor = new_serial.custom_divisor;	info->type = new_serial.type;	info->close_delay = new_serial.close_delay * HZ/100;	info->closing_wait = new_serial.closing_wait * HZ/100;	release_region(info->port,8);	if (change_port || change_irq) {		/*		 * We need to shutdown the serial port at the old		 * port/irq combination.		 */		shutdown(info);		info->irq = new_serial.irq;		info->port = new_serial.port;		info->hub6 = new_serial.hub6;	}	if(info->type != PORT_UNKNOWN)		request_region(info->port,8,"serial(set)");	check_and_exit:	if (!info->port || !info->type)		return 0;	if (info->flags & ASYNC_INITIALIZED) {		if (((old_info.flags & ASYNC_SPD_MASK) !=		     (info->flags & ASYNC_SPD_MASK)) ||		    (old_info.custom_divisor != info->custom_divisor))			change_speed(info);	} else		retval = startup(info);	return retval;}/* * get_lsr_info - get line status register info * * Purpose: Let user call ioctl() to get info when the UART physically * 	    is emptied.  On bus types like RS485, the transmitter must * 	    release the bus after transmitting. This must be done when * 	    the transmit shift register is empty, not be done when the * 	    transmit holding register is empty.  This functionality * 	    allows an RS485 driver to be written in user space.  */static int get_lsr_info(struct async_struct * info, unsigned int *value){	unsigned char status;	unsigned int result;	cli();	status = serial_in(info, UART_LSR);	sti();	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);	put_user(result,value);	return 0;}static int get_modem_info(struct async_struct * info, unsigned int *value){	unsigned char control, status;	unsigned int result;	control = info->MCR;	cli();	status = serial_in(info, UART_MSR);	sti();	result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)		| ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)		| ((status  & UART_MSR_DCD) ? TIOCM_CAR : 0)		| ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)		| ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)		| ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);	put_user(result,value);	return 0;}static int set_modem_info(struct async_struct * info, unsigned int cmd,			  unsigned int *value){	int error;	unsigned int arg;	error = verify_area(VERIFY_READ, value, sizeof(int));	if (error)		return error;	arg = get_user(value);	switch (cmd) {	case TIOCMBIS: 		if (arg & TIOCM_RTS) {			info->MCR |= UART_MCR_RTS;			info->MCR_noint |= UART_MCR_RTS;		}		if (arg & TIOCM_DTR) {			info->MCR |= UART_MCR_DTR;			info->MCR_noint |= UART_MCR_DTR;		}		break;	case TIOCMBIC:		if (arg & TIOCM_RTS) {			info->MCR &= ~UART_MCR_RTS;			info->MCR_noint &= ~UART_MCR_RTS;		}		if (arg & TIOCM_DTR) {			info->MCR &= ~UART_MCR_DTR;			info->MCR_noint &= ~UART_MCR_DTR;		}		break;	case TIOCMSET:		info->MCR = ((info->MCR & ~(UART_MCR_RTS | UART_MCR_DTR))			     | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)			     | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));		info->MCR_noint = ((info->MCR_noint				    & ~(UART_MCR_RTS | UART_MCR_DTR))				   | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)				   | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));		break;	default:		return -EINVAL;	}	cli();	serial_out(info, UART_MCR, info->MCR);	sti();	return 0;}static int do_autoconfig(struct async_struct * info){	int			retval;		if (!suser())		return -EPERM;		if (info->count > 1)		return -EBUSY;		shutdown(info);	cli();	autoconfig(info);	sti();	retval = startup(info);	if (retval)		return retval;	return 0;}/* * rs_break() --- routine which turns the break handling on or off * adapted from 2.1.124 */static void rs_break(struct async_struct * info, int break_state){        unsigned long flags;                if (!info->port)                return;        save_flags(flags);cli();        if (break_state == -1)                serial_out(info, UART_LCR,                           serial_inp(info, UART_LCR) | UART_LCR_SBC);        else                serial_out(info, UART_LCR,                           serial_inp(info, UART_LCR) & ~UART_LCR_SBC);        restore_flags(flags);}/* * This routine sends a break character out the serial port. */static void send_break(	struct async_struct * info, int duration){	if (!info->port)		return;	current->state = TASK_INTERRUPTIBLE;	current->timeout = jiffies + duration;	cli();	serial_out(info, UART_LCR, serial_inp(info, UART_LCR) | UART_LCR_SBC);	schedule();	serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);	sti();}#ifndef CONFIG_COLDFIRE/* * This routine returns a bitfield of "wild interrupts".  Basically, * any unclaimed interrupts which is flapping around. */static int check_wild_interrupts(int doprint){	int	i, mask;	int	wild_interrupts = 0;	int	irq_lines;	unsigned long timeout;	unsigned long flags;		/* Turn on interrupts (they may be off) */	save_flags(flags); sti();	irq_lines = grab_all_interrupts(0);		/*	 * Delay for 0.1 seconds -- we use a busy loop since this may 	 * occur during the bootup sequence	 */	timeout = jiffies+HZ/10;	while (timeout >= jiffies)		;		rs_triggered = 0;	/* Reset after letting things settle */	timeout = jiffies+HZ/10;	while (timeout >= jiffies)		;		for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {		if ((rs_triggered & (1 << i)) &&		    (irq_lines & (1 << i))) {			wild_interrupts |= mask;			if (doprint)				printk("Wild interrupt?  (IRQ %d)\n", i);		}	}	free_all_interrupts(irq_lines);

⌨️ 快捷键说明

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