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

📄 serial.c

📁 基于16450/16550A的多串口驱动,估计很多人在找吧
💻 C
📖 第 1 页 / 共 5 页
字号:
	restore_flags(flags);	return wild_interrupts;}static int get_multiport_struct(struct async_struct * info,				struct serial_multiport_struct *retinfo){	struct serial_multiport_struct ret;	struct rs_multiport_struct *multi;		multi = &rs_multiport[IRQMASK(info->irq)];	ret.port_monitor = multi->port_monitor;		ret.port1 = multi->port1;	ret.mask1 = multi->mask1;	ret.match1 = multi->match1;		ret.port2 = multi->port2;	ret.mask2 = multi->mask2;	ret.match2 = multi->match2;		ret.port3 = multi->port3;	ret.mask3 = multi->mask3;	ret.match3 = multi->match3;		ret.port4 = multi->port4;	ret.mask4 = multi->mask4;	ret.match4 = multi->match4;	ret.irq = info->irq;	memcpy_tofs(retinfo,&ret,sizeof(*retinfo));	return 0;	}static int set_multiport_struct(struct async_struct * info,				struct serial_multiport_struct *in_multi){	struct serial_multiport_struct new_multi;	struct rs_multiport_struct *multi;	int	was_multi, now_multi;	int	retval;	void (*handler)(int, void *, struct pt_regs *);	if (!suser())		return -EPERM;	if (!in_multi)		return -EFAULT;	memcpy_fromfs(&new_multi, in_multi,		      sizeof(struct serial_multiport_struct));	if (new_multi.irq != info->irq || info->irq == 0 ||	    !IRQ_ports[IRQMASK(info->irq)])		return -EINVAL;	multi = &rs_multiport[IRQMASK(info->irq)];	was_multi = (multi->port1 != 0);		multi->port_monitor = new_multi.port_monitor;		if (multi->port1)		release_region(multi->port1,1);	multi->port1 = new_multi.port1;	multi->mask1 = new_multi.mask1;	multi->match1 = new_multi.match1;	if (multi->port1)		request_region(multi->port1,1,"serial(multiport1)");	if (multi->port2)		release_region(multi->port2,1);	multi->port2 = new_multi.port2;	multi->mask2 = new_multi.mask2;	multi->match2 = new_multi.match2;	if (multi->port2)		request_region(multi->port2,1,"serial(multiport2)");	if (multi->port3)		release_region(multi->port3,1);	multi->port3 = new_multi.port3;	multi->mask3 = new_multi.mask3;	multi->match3 = new_multi.match3;	if (multi->port3)		request_region(multi->port3,1,"serial(multiport3)");	if (multi->port4)		release_region(multi->port4,1);	multi->port4 = new_multi.port4;	multi->mask4 = new_multi.mask4;	multi->match4 = new_multi.match4;	if (multi->port4)		request_region(multi->port4,1,"serial(multiport4)");	now_multi = (multi->port1 != 0);		if (IRQ_ports[IRQMASK(info->irq)]->next_port &&	    (was_multi != now_multi)) {		free_irq(info->irq, NULL);		if (now_multi)			handler = rs_interrupt_multi;		else			handler = rs_interrupt;		retval = request_irq(info->irq, handler, IRQ_T(info),				     "serial", NULL);		if (retval) {			printk("Couldn't reallocate serial interrupt "			       "driver!!\n");		}	}	return 0;}#endif /* CONFIG_COLDFIRE */static int rs_ioctl(struct tty_struct *tty, struct file * file,		    unsigned int cmd, unsigned long arg){	int error;	struct async_struct * info = (struct async_struct *)tty->driver_data;	int retval;	struct async_icount cprev, cnow;	/* kernel counter temps */	struct serial_icounter_struct *p_cuser;	/* user space */	if (serial_paranoia_check(info, tty->device, "rs_ioctl"))		return -ENODEV;	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&	    (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT) &&	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {		if (tty->flags & (1 << TTY_IO_ERROR))		    return -EIO;	}		switch (cmd) {                case TIOCSBRK:  /* Turn break on, unconditionally */			retval = tty_check_change(tty);			if (retval)				return retval;			tty_wait_until_sent(tty, 0);			rs_break(info,-1);			return 0;                case TIOCCBRK:  /* Turn break off, unconditionally */			retval = tty_check_change(tty);			if (retval)				return retval;			tty_wait_until_sent(tty, 0);			rs_break(info,0);			return 0;		case TCSBRK:	/* SVID version: non-zero arg --> no break */			retval = tty_check_change(tty);			if (retval)				return retval;			tty_wait_until_sent(tty, 0);			if (!arg)				send_break(info, HZ/4);	/* 1/4 second */			return 0;		case TCSBRKP:	/* support for POSIX tcsendbreak() */			retval = tty_check_change(tty);			if (retval)				return retval;			tty_wait_until_sent(tty, 0);			send_break(info, arg ? arg*(HZ/10) : HZ/4);			return 0;		case TIOCGSOFTCAR:			error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));			if (error)				return error;			put_fs_long(C_CLOCAL(tty) ? 1 : 0,				    (unsigned long *) arg);			return 0;		case TIOCSSOFTCAR:			error = verify_area(VERIFY_READ, (void *) arg,sizeof(long));			if (error)				return error;			arg = get_fs_long((unsigned long *) arg);			tty->termios->c_cflag =				((tty->termios->c_cflag & ~CLOCAL) |				 (arg ? CLOCAL : 0));			return 0;		case TIOCMGET:			error = verify_area(VERIFY_WRITE, (void *) arg,				sizeof(unsigned int));			if (error)				return error;			return get_modem_info(info, (unsigned int *) arg);		case TIOCMBIS:		case TIOCMBIC:		case TIOCMSET:			return set_modem_info(info, cmd, (unsigned int *) arg);		case TIOCGSERIAL:			error = verify_area(VERIFY_WRITE, (void *) arg,						sizeof(struct serial_struct));			if (error)				return error;			return get_serial_info(info,					       (struct serial_struct *) arg);		case TIOCSSERIAL:			error = verify_area(VERIFY_READ, (void *) arg,						sizeof(struct serial_struct));			if (error)				return error;			return set_serial_info(info,					       (struct serial_struct *) arg);		case TIOCSERCONFIG:			return do_autoconfig(info);#ifndef CONFIG_COLDFIRE		case TIOCSERGWILD:			error = verify_area(VERIFY_WRITE, (void *) arg,					    sizeof(int));			if (error)				return error;			put_fs_long(rs_wild_int_mask, (unsigned long *) arg);			return 0;#endif /* CONFIG_COLDFIRE */		case TIOCSERGETLSR: /* Get line status register */			error = verify_area(VERIFY_WRITE, (void *) arg,				sizeof(unsigned int));			if (error)				return error;			else			    return get_lsr_info(info, (unsigned int *) arg);#ifndef CONFIG_COLDFIRE		case TIOCSERSWILD:			if (!suser())				return -EPERM;			error = verify_area(VERIFY_READ, (void *) arg,sizeof(long));			if (error)				return error;			rs_wild_int_mask = get_fs_long((unsigned long *) arg);			if (rs_wild_int_mask < 0)				rs_wild_int_mask = check_wild_interrupts(0);#endif /* CONFIG_COLDFIRE */			return 0;		case TIOCSERGSTRUCT:			error = verify_area(VERIFY_WRITE, (void *) arg,						sizeof(struct async_struct));			if (error)				return error;			memcpy_tofs((struct async_struct *) arg,				    info, sizeof(struct async_struct));			return 0;			#ifndef CONFIG_COLDFIRE		case TIOCSERGETMULTI:			error = verify_area(VERIFY_WRITE, (void *) arg,				    sizeof(struct serial_multiport_struct));			if (error)				return error;			return get_multiport_struct(info,				       (struct serial_multiport_struct *) arg);		case TIOCSERSETMULTI:			error = verify_area(VERIFY_READ, (void *) arg,				    sizeof(struct serial_multiport_struct));			if (error)				return error;			return set_multiport_struct(info,				       (struct serial_multiport_struct *) arg);#endif /* CONFIG_COLDFIRE */		/*		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change		 * - mask passed in arg for lines of interest 		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)		 * Caller should use TIOCGICOUNT to see which one it was		 */		 case TIOCMIWAIT:			cli();			cprev = info->icount;	/* note the counters on entry */			sti();			while (1) {				interruptible_sleep_on(&info->delta_msr_wait);				/* see if a signal did it */				if (current->signal & ~current->blocked)					return -ERESTARTSYS;				cli();				cnow = info->icount;	/* atomic copy */				sti();				if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 				    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)					return -EIO; /* no change => error */				if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||				     ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||				     ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||				     ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {					return 0;				}				cprev = cnow;			}			/* NOTREACHED */		/* 		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)		 * Return: write counters to the user passed counter struct		 * NB: both 1->0 and 0->1 transitions are counted except for		 *     RI where only 0->1 is counted.		 */		case TIOCGICOUNT:			error = verify_area(VERIFY_WRITE, (void *) arg,				sizeof(struct serial_icounter_struct));			if (error)				return error;			cli();			cnow = info->icount;			sti();			p_cuser = (struct serial_icounter_struct *) arg;			put_user(cnow.cts, &p_cuser->cts);			put_user(cnow.dsr, &p_cuser->dsr);			put_user(cnow.rng, &p_cuser->rng);			put_user(cnow.dcd, &p_cuser->dcd);			return 0;		default:			return -ENOIOCTLCMD;		}	return 0;}static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios){	struct async_struct *info = (struct async_struct *)tty->driver_data;	if (   (tty->termios->c_cflag == old_termios->c_cflag)	    && (   RELEVANT_IFLAG(tty->termios->c_iflag) 		== RELEVANT_IFLAG(old_termios->c_iflag)))	  return;	change_speed(info);	if ((old_termios->c_cflag & CRTSCTS) &&	    !(tty->termios->c_cflag & CRTSCTS)) {		tty->hw_stopped = 0;		rs_start(tty);	}#if 0	/*	 * No need to wake up processes in open wait, since they	 * sample the CLOCAL flag once, and don't recheck it.	 * XXX  It's not clear whether the current behavior is correct	 * or not.  Hence, this may change.....	 */	if (!(old_termios->c_cflag & CLOCAL) &&	    (tty->termios->c_cflag & CLOCAL))		wake_up_interruptible(&info->open_wait);#endif}/* * ------------------------------------------------------------ * rs_close() *  * This routine is called when the serial port gets closed.  First, we * wait for the last remaining data to be sent.  Then, we unlink its * async structure from the interrupt chain if necessary, and we free * that IRQ if nothing is left in the chain. * ------------------------------------------------------------ */static void rs_close(struct tty_struct *tty, struct file * filp){	struct async_struct * info = (struct async_struct *)tty->driver_data;	unsigned long flags;	unsigned long timeout;	if (!info || serial_paranoia_check(info, tty->device, "rs_close"))		return;		save_flags(flags); cli();		if (tty_hung_up_p(filp)) {		DBG_CNT("before DEC-hung");		MOD_DEC_USE_COUNT;		restore_flags(flags);		return;	}	#ifdef SERIAL_DEBUG_OPEN	printk("rs_close ttys%d, count = %d\n", info->line, info->count);#endif	if ((tty->count == 1) && (info->count != 1)) {		/*		 * Uh, oh.  tty->count is 1, which means that the tty		 * structure will be freed.  Info->count should always		 * be one in these conditions.  If it's greater than		 * one, we've got real problems, since it means the		 * serial port won't be shutdown.		 */		printk("rs_close: bad serial port count; tty->count is 1, "		       "info->count is %d\n", info->count);		info->count = 1;	}	if (--info->count < 0) {		printk("rs_close: bad serial port count for ttys%d: %d\n",		       info->line, info->count);		info->count = 0;	}	if (info->count) {		DBG_CNT("before DEC-2");		MOD_DEC_USE_COUNT;		restore_flags(flags);		return;	}	info->flags |= ASYNC_CLOSING;	/*	 * Save the termios structure, since this port may have	 * separate termios for callout and dialin.	 */	if (info->flags & ASYNC_NORMAL_ACTIVE)		info->normal_termios = *tty->termios;	if (info->flags & ASYNC_CALLOUT_ACTIVE)		info->callout_termios = *tty->termios;	/*	 * Now we wait for the transmit buffer to clear; and we notify 	 * the line discipline to only process XON/XOFF characters.	 */	tty->closing = 1;	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)		tty_wait_until_sent(tty, info->closing_wait);	/*	 * At this point we stop accepting input.  To do this, we	 * disable the receive line status interrupts, and tell the	 * interrupt driver to stop checking the data ready bit in the	 * line status register.	 */	info->IER &= ~UART_IER_RLSI;	info->read_status_mask &= ~UART_LSR_DR;	if (info->flags & ASYNC_INITIALIZED) {		serial_out(info, UART_IER, info->IER);		/*		 * Before we drop DTR, make sure the UART transmitter		 * has completely drained; this is especially		 * important if there is a transmit FIFO!		 */		timeout = jiffies+HZ;		while (!(serial_inp(info, UART_LSR) & UART_LSR_TEMT)) {			current->state = TASK_INTERRUPTIBLE;			current->timeout = jiffies + info->timeout;			schedule();			if (jiffies > timeout)				break;		}	}	shutdown(info);	if (tty->driver.flush_buffer)		tty->driver.flush_buffer(tty);	if (tty->ldisc.flush_buffer)		tty->ldisc.flush_buffer(tty);	tty->closing = 0;	info->event = 0;	info->tty = 0;	if (info->blocked_open) {		if (info->close_delay) {			current->state = TASK_INTERRUPTIBLE;			current->timeout = jiffies + info->close_delay;			schedule();		}		wake_up_interruptible(&info->open_wait);	}	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|			 ASYNC_CLOSING);	wake_up_interruptible(&info->close_wait);	MOD_DEC_USE_COUNT;	restore_flags(flags);}/* * rs_hangup() --- called by tty_hangup() when a hangup is signaled. */void rs_hangup(struct tty_struct *tty){	struct async_struct * info = (struct async_struct *)tty->driver_data;		if (serial_paranoia_check(info, tty->device, "rs_hangup"))		return;		rs_flush_buffer(tty);	shutdown(info);	info->event = 0;	info->count = 0;	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);	info->tty = 0;	wake_up_interruptible(&info->open_wa

⌨️ 快捷键说明

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