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

📄 uart.c

📁 microwindows移植到S3C44B0的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	}	/*	 * !!! ignore all characters if CREAD is not set	 */	if ((cflag & CREAD) == 0)	 info->read_status_mask &= ~BD_SC_EMPTY;	 save_flags(flags); cli();	 /* Start bit has not been added (so don't, because we would just	  * subtract it later), and we need to add one for the number of	  * stops bits (there is always at least one).	  */	 bits++;	 idx = PORT_NUM(state->smc_scc_num);	 if (state->smc_scc_num & NUM_IS_SCC) {         sccp = &pquicc->scc_regs[idx];         sccp->scc_psmr = (sbits << 12) | scval;     } else {         smcp = &pquicc->smc_regs[idx];		/* Set the mode register.  We want to keep a copy of the		 * enables, because we want to put them back if they were		 * present.		 */		prev_mode = smcp->smc_smcmr;		smcp->smc_smcmr = smcr_mk_clen(bits) | cval |  SMCMR_SM_UART;		smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN));	}	m360_cpm_setbrg((state - rs_table), baud_rate);	restore_flags(flags);}static void rs_360_put_char(struct tty_struct *tty, unsigned char ch){	ser_info_t *info = (ser_info_t *)tty->driver_data;	volatile QUICC_BD	*bdp;	if (serial_paranoia_check(info, tty->device, "rs_put_char"))		return;	if (!tty)		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;}static int rs_360_write(struct tty_struct * tty, int from_user,		    const unsigned char *buf, int count){	int	c, ret = 0;	ser_info_t *info = (ser_info_t *)tty->driver_data;	volatile QUICC_BD *bdp;#ifdef CONFIG_KGDB	/* Try to let stub handle output. Returns true if it did. */ 	if (kgdb_output_string(buf, count))		return ret;#endif	if (serial_paranoia_check(info, tty->device, "rs_write"))		return 0;	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;		}		if (from_user) {			if (copy_from_user((void *)bdp->buf, buf, c)) {				if (!ret)					ret = -EFAULT;				break;			}		} else {			/* 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->device, "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->device, "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->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_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->device, "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->device, "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;	cli();	serial_out(info, UART_MCR, info->MCR);	sti();#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->device, "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;	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); */	put_user(result,value);	return (0);}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 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, 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_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->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); */			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;		case TIOCMGET:			return get_modem_info(info, (unsigned int *) arg);		case TIOCMBIS:

⌨️ 快捷键说明

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