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

📄 sab82532.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
	} else {		info->timeout = 0;		info->tec_timeout = SAB82532_MAX_TEC_TIMEOUT;		info->cec_timeout = SAB82532_MAX_CEC_TIMEOUT;	}	info->timeout += HZ / 50;		/* Add .02 seconds of slop */	/* CTS flow control flags */	if (cflag & CRTSCTS)		info->flags |= ASYNC_CTS_FLOW;	else		info->flags &= ~(ASYNC_CTS_FLOW);	if (cflag & CLOCAL)		info->flags &= ~(ASYNC_CHECK_CD);	else		info->flags |= ASYNC_CHECK_CD;	if (info->tty)		info->tty->hw_stopped = 0;	/*	 * Set up parity check flag	 * XXX: not implemented, yet.	 */#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))	/*	 * Characters to ignore	 * XXX: not implemented, yet.	 */	/*	 * !!! ignore all characters if CREAD is not set	 * XXX: not implemented, yet.	 */	if ((cflag & CREAD) == 0)		info->ignore_status_mask |= SAB82532_ISR0_RPF |					    SAB82532_ISR0_TCD |					    SAB82532_ISR0_TIME;	save_flags(flags); cli();	sab82532_cec_wait(info);	sab82532_tec_wait(info);	writeb(dafo, &info->regs->w.dafo);	writeb(ebrg & 0xff, &info->regs->w.bgr);	writeb(readb(&info->regs->rw.ccr2) & ~(0xc0), &info->regs->rw.ccr2);	writeb(readb(&info->regs->rw.ccr2) | ((ebrg >> 2) & 0xc0), &info->regs->rw.ccr2);	if (info->flags & ASYNC_CTS_FLOW) {		writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_RTS), &info->regs->rw.mode);		writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_FRTS, &info->regs->rw.mode);		writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_FCTS), &info->regs->rw.mode);		info->interrupt_mask1 &= ~(SAB82532_IMR1_CSC);		writeb(info->interrupt_mask1, &info->regs->w.imr1);	} else {		writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RTS, &info->regs->rw.mode);		writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_FRTS), &info->regs->rw.mode);		writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_FCTS, &info->regs->rw.mode);		info->interrupt_mask1 |= SAB82532_IMR1_CSC;		writeb(info->interrupt_mask1, &info->regs->w.imr1);	}	writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RAC, &info->regs->rw.mode);	restore_flags(flags);}static void sab82532_put_char(struct tty_struct *tty, unsigned char ch){	struct sab82532 *info = (struct sab82532 *)tty->driver_data;	unsigned long flags;	if (serial_paranoia_check(info, tty->device, "sab82532_put_char"))		return;	if (!tty || !info->xmit_buf)		return;	save_flags(flags); cli();	if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {		restore_flags(flags);		return;	}	info->xmit_buf[info->xmit_head++] = ch;	info->xmit_head &= SERIAL_XMIT_SIZE-1;	info->xmit_cnt++;	restore_flags(flags);}static void sab82532_flush_chars(struct tty_struct *tty){	struct sab82532 *info = (struct sab82532 *)tty->driver_data;	unsigned long flags;	if (serial_paranoia_check(info, tty->device, "sab82532_flush_chars"))		return;	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||	    !info->xmit_buf)		return;	save_flags(flags); cli();	info->interrupt_mask1 &= ~(SAB82532_IMR1_XPR);	writeb(info->interrupt_mask1, &info->regs->w.imr1);	sab82532_start_tx(info);	restore_flags(flags);}static int sab82532_write(struct tty_struct * tty, int from_user,			  const unsigned char *buf, int count){	int c, ret = 0;	struct sab82532 *info = (struct sab82532 *)tty->driver_data;	unsigned long flags;	if (serial_paranoia_check(info, tty->device, "sab82532_write"))		return 0;	if (!tty || !info->xmit_buf || !tmp_buf)		return 0;	    	if (from_user)		down(&tmp_buf_sem);	save_flags(flags);	while (1) {		cli();				c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,				   SERIAL_XMIT_SIZE - info->xmit_head));		if (c <= 0)			break;		if (from_user) {			c -= copy_from_user(tmp_buf, buf, c);			if (!c) {				if (!ret)					ret = -EFAULT;				break;			}			c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,				       SERIAL_XMIT_SIZE - info->xmit_head));			memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);		} else			memcpy(info->xmit_buf + info->xmit_head, buf, c);		info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);		info->xmit_cnt += c;		restore_flags(flags);		buf += c;		count -= c;		ret += c;	}	if (from_user)		up(&tmp_buf_sem);	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {		info->interrupt_mask1 &= ~(SAB82532_IMR1_XPR);		writeb(info->interrupt_mask1, &info->regs->w.imr1);		sab82532_start_tx(info);	}	restore_flags(flags);	return ret;}static int sab82532_write_room(struct tty_struct *tty){	struct sab82532 *info = (struct sab82532 *)tty->driver_data;	int ret;	if (serial_paranoia_check(info, tty->device, "sab82532_write_room"))		return 0;	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;	if (ret < 0)		ret = 0;	return ret;}static int sab82532_chars_in_buffer(struct tty_struct *tty){	struct sab82532 *info = (struct sab82532 *)tty->driver_data;					if (serial_paranoia_check(info, tty->device, "sab82532_chars_in_buffer"))		return 0;	return info->xmit_cnt;}static void sab82532_flush_buffer(struct tty_struct *tty){	struct sab82532 *info = (struct sab82532 *)tty->driver_data;	if (serial_paranoia_check(info, tty->device, "sab82532_flush_buffer"))		return;	cli();	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;	sti();	wake_up_interruptible(&tty->write_wait);	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&	    tty->ldisc.write_wakeup)		(tty->ldisc.write_wakeup)(tty);}/* * This function is used to send a high-priority XON/XOFF character to * the device */static void sab82532_send_xchar(struct tty_struct *tty, char ch){	struct sab82532 *info = (struct sab82532 *)tty->driver_data;	unsigned long flags;	if (serial_paranoia_check(info, tty->device, "sab82532_send_xchar"))		return;	save_flags(flags); cli();	sab82532_tec_wait(info);	writeb(ch, &info->regs->w.tic);	restore_flags(flags);}/* * ------------------------------------------------------------ * sab82532_throttle() *  * This routine is called by the upper-layer tty layer to signal that * incoming characters should be throttled. * ------------------------------------------------------------ */static void sab82532_throttle(struct tty_struct * tty){	struct sab82532 *info = (struct sab82532 *)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, "sab82532_throttle"))		return;		if (I_IXOFF(tty))		sab82532_send_xchar(tty, STOP_CHAR(tty));}static void sab82532_unthrottle(struct tty_struct * tty){	struct sab82532 *info = (struct sab82532 *)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, "sab82532_unthrottle"))		return;		if (I_IXOFF(tty)) {		if (info->x_char)			info->x_char = 0;		else			sab82532_send_xchar(tty, START_CHAR(tty));	}}/* * ------------------------------------------------------------ * sab82532_ioctl() and friends * ------------------------------------------------------------ */static int get_serial_info(struct sab82532 *info,			   struct serial_struct *retinfo){	struct serial_struct tmp;   	if (!retinfo)		return -EFAULT;	memset(&tmp, 0, sizeof(tmp));	tmp.type = info->type;	tmp.line = info->line;	tmp.port = (unsigned long)info->regs;	tmp.irq = info->irq;	tmp.flags = info->flags;	tmp.xmit_fifo_size = info->xmit_fifo_size;	tmp.baud_base = info->baud_base;	tmp.close_delay = info->close_delay;	tmp.closing_wait = info->closing_wait;	tmp.custom_divisor = info->custom_divisor;	tmp.hub6 = 0;	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))		return -EFAULT;	return 0;}static int set_serial_info(struct sab82532 *info,			   struct serial_struct *new_info){	return 0;}/* * 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 sab82532 * info, unsigned int *value){	unsigned int result;	result = (!info->xmit_buf && info->all_sent) ? TIOCSER_TEMT : 0;	return put_user(result, value);}static int get_modem_info(struct sab82532 * info, unsigned int *value){	unsigned int result;	result =  ((readb(&info->regs->r.mode) & SAB82532_MODE_RTS) ? 		    ((readb(&info->regs->r.mode) & SAB82532_MODE_FRTS) ? 0 : TIOCM_RTS)							    : TIOCM_RTS)		| ((readb(&info->regs->r.pvr) & info->pvr_dtr_bit) ? 0 : TIOCM_DTR)		| ((readb(&info->regs->r.vstr) & SAB82532_VSTR_CD) ? 0 : TIOCM_CAR)		| ((readb(&info->regs->r.pvr) & info->pvr_dsr_bit) ? 0 : TIOCM_DSR)		| ((readb(&info->regs->r.star) & SAB82532_STAR_CTS) ? TIOCM_CTS : 0);	return put_user(result,value);}static int set_modem_info(struct sab82532 * info, unsigned int cmd,			  unsigned int *value){	int error;	unsigned int arg;	error = get_user(arg, value);	if (error)		return error;	switch (cmd) {	case TIOCMBIS: 		if (arg & TIOCM_RTS) {			writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_FRTS), &info->regs->rw.mode);			writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RTS, &info->regs->rw.mode);		}		if (arg & TIOCM_DTR) {			writeb(readb(&info->regs->rw.pvr) & ~(info->pvr_dtr_bit), &info->regs->rw.pvr);		}		break;	case TIOCMBIC:		if (arg & TIOCM_RTS) {			writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_FRTS, &info->regs->rw.mode);			writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RTS, &info->regs->rw.mode);		}		if (arg & TIOCM_DTR) {			writeb(readb(&info->regs->rw.pvr) | info->pvr_dtr_bit, &info->regs->rw.pvr);		}		break;	case TIOCMSET:		if (arg & TIOCM_RTS) {			writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_FRTS), &info->regs->rw.mode);			writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RTS, &info->regs->rw.mode);		} else {			writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_FRTS, &info->regs->rw.mode);			writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RTS, &info->regs->rw.mode);		}		if (arg & TIOCM_DTR) {			writeb(readb(&info->regs->rw.pvr) & ~(info->pvr_dtr_bit), &info->regs->rw.pvr);		} else {			writeb(readb(&info->regs->rw.pvr) | info->pvr_dtr_bit, &info->regs->rw.pvr);		}		break;	default:		return -EINVAL;	}	return 0;}/* * This routine sends a break character out the serial port. */static void sab82532_break(struct tty_struct *tty, int break_state){	struct sab82532 * info = (struct sab82532 *)tty->driver_data;	unsigned long flags;	if (serial_paranoia_check(info, tty->device, "sab82532_break"))		return;	if (!info->regs)		return;#ifdef SERIAL_DEBUG_SEND_BREAK	printk("sab82532_break(%d) jiff=%lu...", break_state, jiffies);#endif	save_flags(flags); cli();	if (break_state == -1)		writeb(readb(&info->regs->rw.dafo) | SAB82532_DAFO_XBRK, &info->regs->rw.dafo);	else		writeb(readb(&info->regs->rw.dafo) & ~(SAB82532_DAFO_XBRK), &info->regs->rw.dafo);	restore_flags(flags);}static int sab82532_ioctl(struct tty_struct *tty, struct file * file,		    unsigned int cmd, unsigned long arg){	int error;	struct sab82532 * info = (struct sab82532 *)tty->driver_data;	struct async_icount cprev, cnow;	/* kernel counter temps */	struct serial_icounter_struct *p_cuser;	/* user space */	if (serial_paranoia_check(info, tty->device, "sab82532_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 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);		case TIOCGSERIAL:			return get_serial_info(info,					       (struct serial_struct *) arg);		case TIOCSSERIAL:			return set_serial_info(info,					       (struct serial_struct *) arg);		case TIOCSERGETLSR: /* Get line status register */			return get_lsr_info(info, (unsigned int *) arg);		case TIOCSERGSTRUCT:			if (copy_to_user((struct sab82532 *) arg,					 info, sizeof(struct sab82532)))				return -EFAULT;			return 0;						/*		 * 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();			/* note the counters on entry */			cprev = info->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->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)

⌨️ 快捷键说明

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