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

📄 68360serial.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (!tty) 		return 0;	bdp = info->tx_cur;	while (1) {		c = min(count, TX_BUF_SIZE);		if (c <= 0)			break;		if (bdp->status & BD_SC_READY) {			info->flags |= TX_WAKEUP;			break;		}		/* memcpy(__va(bdp->buf), buf, c); */		memcpy((void *)bdp->buf, buf, c);		bdp->length = c;		bdp->status |= BD_SC_READY;		buf += c;		count -= c;		ret += c;		/* Get next BD.		*/		if (bdp->status & BD_SC_WRAP)			bdp = info->tx_bd_base;		else			bdp++;		info->tx_cur = (QUICC_BD *)bdp;	}	return ret;}static int rs_360_write_room(struct tty_struct *tty){	ser_info_t *info = (ser_info_t *)tty->driver_data;	int	ret;	if (serial_paranoia_check(info, tty->name, "rs_write_room"))		return 0;	if ((info->tx_cur->status & 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_360_chars_in_buffer(struct tty_struct *tty){	ser_info_t *info = (ser_info_t *)tty->driver_data;					if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))		return 0;	return 0;}static void rs_360_flush_buffer(struct tty_struct *tty){	ser_info_t *info = (ser_info_t *)tty->driver_data;					if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))		return;	/* There is nothing to "flush", whatever we gave the CPM	 * is on its way out.	 */	tty_wakeup(tty);	info->flags &= ~TX_WAKEUP;}/* * This function is used to send a high-priority XON/XOFF character to * the device */static void rs_360_send_xchar(struct tty_struct *tty, char ch){	volatile QUICC_BD	*bdp;	ser_info_t *info = (ser_info_t *)tty->driver_data;	if (serial_paranoia_check(info, tty->name, "rs_send_char"))		return;	bdp = info->tx_cur;	while (bdp->status & BD_SC_READY);	/* *((char *)__va(bdp->buf)) = ch; */	*((char *)bdp->buf) = ch;	bdp->length = 1;	bdp->status |= BD_SC_READY;	/* Get next BD.	*/	if (bdp->status & BD_SC_WRAP)		bdp = info->tx_bd_base;	else		bdp++;	info->tx_cur = (QUICC_BD *)bdp;}/* * ------------------------------------------------------------ * rs_throttle() *  * This routine is called by the upper-layer tty layer to signal that * incoming characters should be throttled. * ------------------------------------------------------------ */static void rs_360_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->name, "rs_throttle"))		return;		if (I_IXOFF(tty))		rs_360_send_xchar(tty, STOP_CHAR(tty));#ifdef modem_control	if (tty->termios->c_cflag & CRTSCTS)		info->MCR &= ~UART_MCR_RTS;	local_irq_disable();	serial_out(info, UART_MCR, info->MCR);	local_irq_enable();#endif}static void rs_360_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->name, "rs_unthrottle"))		return;		if (I_IXOFF(tty)) {		if (info->x_char)			info->x_char = 0;		else			rs_360_send_xchar(tty, START_CHAR(tty));	}#ifdef modem_control	if (tty->termios->c_cflag & CRTSCTS)		info->MCR |= UART_MCR_RTS;	local_irq_disable();	serial_out(info, UART_MCR, info->MCR);	local_irq_enable();#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;	local_irq_disable();	status = serial_in(info, UART_LSR);	local_irq_enable();	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);	return put_user(result,value);}#endifstatic int rs_360_tiocmget(struct tty_struct *tty, struct file *file){	ser_info_t *info = (ser_info_t *)tty->driver_data;	unsigned int result = 0;#ifdef modem_control	unsigned char control, status;	if (serial_paranoia_check(info, tty->name, __FUNCTION__))		return -ENODEV;	if (tty->flags & (1 << TTY_IO_ERROR))		return -EIO;	control = info->MCR;	local_irq_disable();	status = serial_in(info, UART_MSR);	local_irq_enable();	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 result;}static int rs_360_tiocmset(struct tty_struct *tty, struct file *file,			   unsigned int set, unsigned int clear){#ifdef modem_control	ser_info_t *info = (ser_info_t *)tty->driver_data; 	unsigned int arg;	if (serial_paranoia_check(info, tty->name, __FUNCTION__))		return -ENODEV;	if (tty->flags & (1 << TTY_IO_ERROR))		return -EIO; 	if (set & TIOCM_RTS) 		info->mcr |= UART_MCR_RTS; 	if (set & TIOCM_DTR) 		info->mcr |= UART_MCR_DTR;	if (clear & TIOCM_RTS)		info->MCR &= ~UART_MCR_RTS;	if (clear & TIOCM_DTR)		info->MCR &= ~UART_MCR_DTR;#ifdef TIOCM_OUT1	if (set & TIOCM_OUT1)		info->MCR |= UART_MCR_OUT1;	if (set & TIOCM_OUT2)		info->MCR |= UART_MCR_OUT2;	if (clear & TIOCM_OUT1)		info->MCR &= ~UART_MCR_OUT1;	if (clear & TIOCM_OUT2)		info->MCR &= ~UART_MCR_OUT2;#endif	local_irq_disable();	serial_out(info, UART_MCR, info->MCR);	local_irq_enable();#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 ushort	smc_chan_map[] = {	CPM_CR_CH_SMC1,	CPM_CR_CH_SMC2};static ushort	scc_chan_map[] = {	CPM_CR_CH_SCC1,	CPM_CR_CH_SCC2,	CPM_CR_CH_SCC3,	CPM_CR_CH_SCC4};static void begin_break(ser_info_t *info){	volatile QUICC *cp;	ushort	chan;	int     idx;	cp = pquicc;	idx = PORT_NUM(info->state->smc_scc_num);	if (info->state->smc_scc_num & NUM_IS_SCC)		chan = scc_chan_map[idx];	else		chan = smc_chan_map[idx];	cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG;	while (cp->cp_cr & CPM_CR_FLG);}static void end_break(ser_info_t *info){	volatile QUICC *cp;	ushort	chan;	int idx;	cp = pquicc;	idx = PORT_NUM(info->state->smc_scc_num);	if (info->state->smc_scc_num & NUM_IS_SCC)		chan = scc_chan_map[idx];	else		chan = smc_chan_map[idx];	cp->cp_cr = mk_cr_cmd(chan, CPM_CR_RESTART_TX) | CPM_CR_FLG;	while (cp->cp_cr & CPM_CR_FLG);}/* * This routine sends a break character out the serial port. */static void send_break(ser_info_t *info, unsigned int duration){#ifdef SERIAL_DEBUG_SEND_BREAK	printk("rs_send_break(%d) jiff=%lu...", duration, jiffies);#endif	begin_break(info);	msleep_interruptible(duration);	end_break(info);#ifdef SERIAL_DEBUG_SEND_BREAK	printk("done jiffies=%lu\n", jiffies);#endif}static int rs_360_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; 	/* struct async_icount_24 cnow;*/ 	/* kernel counter temps */	struct serial_icounter_struct *p_cuser;	/* user space */	if (serial_paranoia_check(info, tty->name, "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, 250);	/* 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*100 : 250);			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); */			put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg);			return 0;		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;#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			local_irq_disable();			/* note the counters on entry */			cprev = info->state->icount;			local_irq_enable();			while (1) {				interruptible_sleep_on(&info->delta_msr_wait);				/* see if a signal did it */				if (signal_pending(current))					return -ERESTARTSYS;				local_irq_disable();				cnow = info->state->icount; /* atomic copy */				local_irq_enable();				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:			local_irq_disable();			cnow = info->state->icount;			local_irq_enable();			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; */			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;}/* FIX UP modem control here someday......*/static void rs_360_set_termios(struct tty_struct *tty, struct ktermios *old_termios){	ser_info_t *info = (ser_info_t *)tty->driver_data;	change_speed(info);#ifdef modem_control	/* Handle transition to B0 status */	if ((old_termios->c_cflag & CBAUD) &&	    !(tty->termios->c_cflag & CBAUD)) {		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);		local_irq_disable();		serial_out(info, UART_MCR, info->MCR);		local_irq_enable();	}		/* Handle transition away from B0 status */	if (!(old_termios->c_cflag & CBAUD) &&	    (tty->termios->c_cflag & CBAUD)) {		info->MCR |= UART_MCR_DTR;		if (!tty->hw_stopped ||		    !(tty->termios->c_cflag & CRTSCTS)) {			info->MCR |= UART_MCR_RTS;		}		local_irq_disable();		serial_out(info, UART_MCR, info->MCR);		local_irq_enable();	}		/* Handle turning off CRTSCTS */	if ((old_termios->c_cflag & CRTSCTS) &&

⌨️ 快捷键说明

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