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

📄 uart.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
		return 0;	if ((info->tx_cur->cbd_sc & BD_SC_READY) == 0) {		info->flags &= ~TX_WAKEUP;		ret = TX_BUF_SIZE;	}	else {		info->flags |= TX_WAKEUP;		ret = 0;	}	return ret;}/* I could track this with transmit counters....maybe later.*/static int rs_8xx_chars_in_buffer(struct tty_struct *tty){	ser_info_t *info = (ser_info_t *)tty->driver_data;					if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))		return 0;	return 0;}static void rs_8xx_flush_buffer(struct tty_struct *tty){	ser_info_t *info = (ser_info_t *)tty->driver_data;					if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))		return;	/* There is nothing to "flush", whatever we gave the CPM	 * is on its way out.	 */	wake_up_interruptible(&tty->write_wait);	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&	    tty->ldisc.write_wakeup)		(tty->ldisc.write_wakeup)(tty);	info->flags &= ~TX_WAKEUP;}/* * This function is used to send a high-priority XON/XOFF character to * the device */static void rs_8xx_send_xchar(struct tty_struct *tty, char ch){	volatile cbd_t	*bdp;	ser_info_t *info = (ser_info_t *)tty->driver_data;	if (serial_paranoia_check(info, tty->device, "rs_send_char"))		return;	bdp = info->tx_cur;	while (bdp->cbd_sc & BD_SC_READY);	*((char *)__va(bdp->cbd_bufaddr)) = ch;	bdp->cbd_datlen = 1;	bdp->cbd_sc |= BD_SC_READY;	/* Get next BD.	*/	if (bdp->cbd_sc & BD_SC_WRAP)		bdp = info->tx_bd_base;	else		bdp++;	info->tx_cur = (cbd_t *)bdp;}/* * ------------------------------------------------------------ * rs_throttle() *  * This routine is called by the upper-layer tty layer to signal that * incoming characters should be throttled. * ------------------------------------------------------------ */static void rs_8xx_throttle(struct tty_struct * tty){	ser_info_t *info = (ser_info_t *)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))		rs_8xx_send_xchar(tty, STOP_CHAR(tty));#ifdef modem_control	if (tty->termios->c_cflag & CRTSCTS)		info->MCR &= ~UART_MCR_RTS;	cli();	serial_out(info, UART_MCR, info->MCR);	sti();#endif}static void rs_8xx_unthrottle(struct tty_struct * tty){	ser_info_t *info = (ser_info_t *)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			rs_8xx_send_xchar(tty, START_CHAR(tty));	}#ifdef modem_control	if (tty->termios->c_cflag & CRTSCTS)		info->MCR |= UART_MCR_RTS;	cli();	serial_out(info, UART_MCR, info->MCR);	sti();#endif}/* * ------------------------------------------------------------ * rs_ioctl() and friends * ------------------------------------------------------------ */#ifdef maybe/* * 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);	return put_user(result,value);}#endifstatic int get_modem_info(ser_info_t *info, unsigned int *value){	unsigned int result = 0;#ifdef modem_control	unsigned char control, status;	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)#ifdef TIOCM_OUT1		| ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0)		| ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0)#endif		| ((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);#endif	return put_user(result,value);}static int set_modem_info(ser_info_t *info, unsigned int cmd,			  unsigned int *value){	int error;	unsigned int arg;	error = get_user(arg, value);	if (error)		return error;#ifdef modem_control	switch (cmd) {	case TIOCMBIS: 		if (arg & TIOCM_RTS)			info->MCR |= UART_MCR_RTS;		if (arg & TIOCM_DTR)			info->MCR |= UART_MCR_DTR;#ifdef TIOCM_OUT1		if (arg & TIOCM_OUT1)			info->MCR |= UART_MCR_OUT1;		if (arg & TIOCM_OUT2)			info->MCR |= UART_MCR_OUT2;#endif		break;	case TIOCMBIC:		if (arg & TIOCM_RTS)			info->MCR &= ~UART_MCR_RTS;		if (arg & TIOCM_DTR)			info->MCR &= ~UART_MCR_DTR;#ifdef TIOCM_OUT1		if (arg & TIOCM_OUT1)			info->MCR &= ~UART_MCR_OUT1;		if (arg & TIOCM_OUT2)			info->MCR &= ~UART_MCR_OUT2;#endif		break;	case TIOCMSET:		info->MCR = ((info->MCR & ~(UART_MCR_RTS |#ifdef TIOCM_OUT1					    UART_MCR_OUT1 |					    UART_MCR_OUT2 |#endif					    UART_MCR_DTR))			     | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)#ifdef TIOCM_OUT1			     | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0)			     | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0)#endif			     | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));		break;	default:		return -EINVAL;	}	cli();	serial_out(info, UART_MCR, info->MCR);	sti();#endif	return 0;}/* Sending a break is a two step process on the SMC/SCC.  It is accomplished * by sending a STOP TRANSMIT command followed by a RESTART TRANSMIT * command.  We take advantage of the begin/end functions to make this * happen. */static void begin_break(ser_info_t *info){	volatile cpm8260_t *cp;	uint	page, sblock;	ushort	num;	cp = cpmp;	if ((num = info->state->smc_scc_num) < SCC_NUM_BASE) {		if (num == 0) {			page = CPM_CR_SMC1_PAGE;			sblock = CPM_CR_SMC1_SBLOCK;		}		else {			page = CPM_CR_SMC2_PAGE;			sblock = CPM_CR_SMC2_SBLOCK;		}	}	else {		num -= SCC_NUM_BASE;		switch (num) {		case 0:			page = CPM_CR_SCC1_PAGE;			sblock = CPM_CR_SCC1_SBLOCK;			break;		case 1:			page = CPM_CR_SCC2_PAGE;			sblock = CPM_CR_SCC2_SBLOCK;			break;		case 2:			page = CPM_CR_SCC3_PAGE;			sblock = CPM_CR_SCC3_SBLOCK;			break;		case 3:			page = CPM_CR_SCC4_PAGE;			sblock = CPM_CR_SCC4_SBLOCK;			break;		default: return;		}	}	cp->cp_cpcr = mk_cr_cmd(page, sblock, 0, CPM_CR_STOP_TX) | CPM_CR_FLG;	while (cp->cp_cpcr & CPM_CR_FLG);}static void end_break(ser_info_t *info){	volatile cpm8260_t *cp;	uint	page, sblock;	ushort	num;	cp = cpmp;	if ((num = info->state->smc_scc_num) < SCC_NUM_BASE) {		if (num == 0) {			page = CPM_CR_SMC1_PAGE;			sblock = CPM_CR_SMC1_SBLOCK;		}		else {			page = CPM_CR_SMC2_PAGE;			sblock = CPM_CR_SMC2_SBLOCK;		}	}	else {		num -= SCC_NUM_BASE;		switch (num) {		case 0:			page = CPM_CR_SCC1_PAGE;			sblock = CPM_CR_SCC1_SBLOCK;			break;		case 1:			page = CPM_CR_SCC2_PAGE;			sblock = CPM_CR_SCC2_SBLOCK;			break;		case 2:			page = CPM_CR_SCC3_PAGE;			sblock = CPM_CR_SCC3_SBLOCK;			break;		case 3:			page = CPM_CR_SCC4_PAGE;			sblock = CPM_CR_SCC4_SBLOCK;			break;		default: return;		}	}	cp->cp_cpcr = mk_cr_cmd(page, sblock, 0, CPM_CR_RESTART_TX) | CPM_CR_FLG;	while (cp->cp_cpcr & CPM_CR_FLG);}/* * This routine sends a break character out the serial port. */static void send_break(ser_info_t *info, int duration){	current->state = TASK_INTERRUPTIBLE;#ifdef SERIAL_DEBUG_SEND_BREAK	printk("rs_send_break(%d) jiff=%lu...", duration, jiffies);#endif	begin_break(info);	schedule_timeout(duration);	end_break(info);#ifdef SERIAL_DEBUG_SEND_BREAK	printk("done jiffies=%lu\n", jiffies);#endif}static int rs_8xx_ioctl(struct tty_struct *tty, struct file * file,		    unsigned int cmd, unsigned long arg){	int error;	ser_info_t *info = (ser_info_t *)tty->driver_data;	int retval;	struct async_icount 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 != 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 (signal_pending(current))				return -EINTR;			if (!arg) {				send_break(info, HZ/4);	/* 1/4 second */				if (signal_pending(current))					return -EINTR;			}			return 0;		case TCSBRKP:	/* support for POSIX tcsendbreak() */			retval = tty_check_change(tty);			if (retval)				return retval;			tty_wait_until_sent(tty, 0);			if (signal_pending(current))				return -EINTR;			send_break(info, arg ? arg*(HZ/10) : HZ/4);			if (signal_pending(current))				return -EINTR;			return 0;		case TIOCSBRK:			retval = tty_check_change(tty);			if (retval)				return retval;			tty_wait_until_sent(tty, 0);			begin_break(info);			return 0;		case TIOCCBRK:			retval = tty_check_change(tty);			if (retval)				return retval;			end_break(info);			return 0;		case TIOCGSOFTCAR:			return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg);		case TIOCSSOFTCAR:			error = get_user(arg, (unsigned int *) arg);			if (error)				return error;			tty->termios->c_cflag =				((tty->termios->c_cflag & ~CLOCAL) |				 (arg ? CLOCAL : 0));			return 0;		case TIOCMGET:			return get_modem_info(info, (unsigned int *) arg);		case TIOCMBIS:		case TIOCMBIC:		case TIOCMSET:			return set_modem_info(info, cmd, (unsigned int *) arg);#ifdef maybe		case TIOCSERGETLSR: /* Get line status register */			return get_lsr_info(info, (unsigned int *) arg);#endif		/*		 * 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:#ifdef modem_control			cli();			/* note the counters on entry */			cprev = info->state->icount;			sti();			while (1) {				interruptible_sleep_on(&info->delta_msr_wait);				/* see if a signal did it */				if (signal_pending(current))					return -ERESTARTSYS;				cli();				cnow = info->state->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 */#else			return 0;#endif		/* 		 * 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:			cli();			cnow = info->state->icount;			sti();			p_cuser = (struct serial_icounter_struct *) arg;			error = put_user(cnow.cts, &p_cuser->cts);			if (error) return error;			error = put_user(cnow.dsr, &p_cuser->dsr);			if (error) return error;			error = put_user(cnow.rng, &p_cuser->rng);			if (error) return error;			error = put_user(cnow.dcd, &p_cuser->dcd);			if (error) return error;			return 0;		default:			return -ENOIOCTLCMD;		}	return 0;}/* FIX UP modem control here someday......*/static void rs_8xx_set_termios(struct tty_struct *tty, struct termios *old_termios){	ser_info_t *info = (ser_info_t *)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;

⌨️ 快捷键说明

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