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

📄 serial.c

📁 arm平台上的uclinux系统全部源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		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;}/* * 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();}/* * 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);	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[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[info->irq])		return -EINVAL;	multi = &rs_multiport[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[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;}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 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);		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;		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);		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);			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;					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);		/*		 * 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)) {

⌨️ 快捷键说明

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