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

📄 mxser.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
		ret = 0;	return (ret);}static int mxser_chars_in_buffer(struct tty_struct *tty){	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;	return (info->xmit_cnt);}static void mxser_flush_buffer(struct tty_struct *tty){	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;	unsigned long flags;	save_flags(flags);	cli();	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;	restore_flags(flags);	wake_up_interruptible(&tty->write_wait);	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&	    tty->ldisc.write_wakeup)		(tty->ldisc.write_wakeup) (tty);}static int mxser_ioctl(struct tty_struct *tty, struct file *file,		       unsigned int cmd, unsigned long arg){	unsigned long flags;	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;	int retval;	struct async_icount cprev, cnow;	/* kernel counter temps */	struct serial_icounter_struct *p_cuser;		/* user space */	unsigned long templ;	if (PORTNO(tty) == MXSER_PORTS)		return (mxser_ioctl_special(cmd, arg));	if ((cmd != TIOCGSERIAL) && (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)			mxser_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);		mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4);		return (0);	case TIOCGSOFTCAR:		return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg);	case TIOCSSOFTCAR:		if(get_user(templ, (unsigned long *) arg))			return -EFAULT;		arg = templ;		tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) |					 (arg ? CLOCAL : 0));		return (0);	case TIOCMGET:		return (mxser_get_modem_info(info, (unsigned int *) arg));	case TIOCMBIS:	case TIOCMBIC:	case TIOCMSET:		return (mxser_set_modem_info(info, cmd, (unsigned int *) arg));	case TIOCGSERIAL:		return (mxser_get_serial_info(info, (struct serial_struct *) arg));	case TIOCSSERIAL:		return (mxser_set_serial_info(info, (struct serial_struct *) arg));	case TIOCSERGETLSR:	/* Get line status register */		return (mxser_get_lsr_info(info, (unsigned int *) 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:		save_flags(flags);		cli();		cprev = info->icount;	/* note the counters on entry */		restore_flags(flags);		while (1) {			interruptible_sleep_on(&info->delta_msr_wait);			/* see if a signal did it */			if (signal_pending(current))				return (-ERESTARTSYS);			save_flags(flags);			cli();			cnow = info->icount;	/* atomic copy */			restore_flags(flags);			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:		save_flags(flags);		cli();		cnow = info->icount;		restore_flags(flags);		p_cuser = (struct serial_icounter_struct *) arg;		if(put_user(cnow.cts, &p_cuser->cts))			return -EFAULT;		if(put_user(cnow.dsr, &p_cuser->dsr))			return -EFAULT;		if(put_user(cnow.rng, &p_cuser->rng))			return -EFAULT;		return put_user(cnow.dcd, &p_cuser->dcd);	case MOXA_HighSpeedOn:		return put_user(info->baud_base != 115200 ? 1 : 0, (int *) arg);	default:		return (-ENOIOCTLCMD);	}	return (0);}static int mxser_ioctl_special(unsigned int cmd, unsigned long arg){	int i, result, status;	switch (cmd) {	case MOXA_GET_CONF:		if(copy_to_user((struct mxser_hwconf *) arg, mxsercfg,			     sizeof(struct mxser_hwconf) * 4))			     	return -EFAULT;		return 0;	case MOXA_GET_MAJOR:		if(copy_to_user((int *) arg, &ttymajor, sizeof(int)))			return -EFAULT;		return 0;	case MOXA_GET_CUMAJOR:		if(copy_to_user((int *) arg, &calloutmajor, sizeof(int)))			return -EFAULT;		return 0;	case MOXA_CHKPORTENABLE:		result = 0;		for (i = 0; i < MXSER_PORTS; i++) {			if (mxvar_table[i].base)				result |= (1 << i);		}		return put_user(result, (unsigned long *) arg);	case MOXA_GETDATACOUNT:		if(copy_to_user((struct mxser_log *) arg, &mxvar_log, sizeof(mxvar_log)))			return -EFAULT;		return (0);	case MOXA_GETMSTATUS:		for (i = 0; i < MXSER_PORTS; i++) {			GMStatus[i].ri = 0;			if (!mxvar_table[i].base) {				GMStatus[i].dcd = 0;				GMStatus[i].dsr = 0;				GMStatus[i].cts = 0;				continue;			}			if (!mxvar_table[i].tty || !mxvar_table[i].tty->termios)				GMStatus[i].cflag = mxvar_table[i].normal_termios.c_cflag;			else				GMStatus[i].cflag = mxvar_table[i].tty->termios->c_cflag;			status = inb(mxvar_table[i].base + UART_MSR);			if (status & 0x80 /*UART_MSR_DCD */ )				GMStatus[i].dcd = 1;			else				GMStatus[i].dcd = 0;			if (status & 0x20 /*UART_MSR_DSR */ )				GMStatus[i].dsr = 1;			else				GMStatus[i].dsr = 0;			if (status & 0x10 /*UART_MSR_CTS */ )				GMStatus[i].cts = 1;			else				GMStatus[i].cts = 0;		}		if(copy_to_user((struct mxser_mstatus *) arg, GMStatus,			     sizeof(struct mxser_mstatus) * MXSER_PORTS))			return -EFAULT;		return 0;	default:		return (-ENOIOCTLCMD);	}	return (0);}/* * This routine is called by the upper-layer tty layer to signal that * incoming characters should be throttled. */static void mxser_throttle(struct tty_struct *tty){	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;	unsigned long flags;	if (I_IXOFF(tty)) {		info->x_char = STOP_CHAR(tty);		save_flags(flags);		cli();		outb(info->IER, 0);		info->IER |= UART_IER_THRI;		outb(info->IER, info->base + UART_IER);		/* force Tx interrupt */		restore_flags(flags);	}	if (info->tty->termios->c_cflag & CRTSCTS) {		info->MCR &= ~UART_MCR_RTS;		save_flags(flags);		cli();		outb(info->MCR, info->base + UART_MCR);		restore_flags(flags);	}}static void mxser_unthrottle(struct tty_struct *tty){	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;	unsigned long flags;	if (I_IXOFF(tty)) {		if (info->x_char)			info->x_char = 0;		else {			info->x_char = START_CHAR(tty);			save_flags(flags);			cli();			outb(info->IER, 0);			info->IER |= UART_IER_THRI;	/* force Tx interrupt */			outb(info->IER, info->base + UART_IER);			restore_flags(flags);		}	}	if (info->tty->termios->c_cflag & CRTSCTS) {		info->MCR |= UART_MCR_RTS;		save_flags(flags);		cli();		outb(info->MCR, info->base + UART_MCR);		restore_flags(flags);	}}static void mxser_set_termios(struct tty_struct *tty,			      struct termios *old_termios){	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;/* 8-2-99 by William   if ( (tty->termios->c_cflag == old_termios->c_cflag) &&   (RELEVANT_IFLAG(tty->termios->c_iflag) ==   RELEVANT_IFLAG(old_termios->c_iflag)) )   return;   mxser_change_speed(info, old_termios);   if ( (old_termios->c_cflag & CRTSCTS) &&   !(tty->termios->c_cflag & CRTSCTS) ) {   tty->hw_stopped = 0;   mxser_start(tty);   } */	if ((tty->termios->c_cflag != old_termios->c_cflag) ||	    (RELEVANT_IFLAG(tty->termios->c_iflag) !=	     RELEVANT_IFLAG(old_termios->c_iflag))) {		mxser_change_speed(info, old_termios);		if ((old_termios->c_cflag & CRTSCTS) &&		    !(tty->termios->c_cflag & CRTSCTS)) {			tty->hw_stopped = 0;			mxser_start(tty);		}	}/* Handle sw stopped */	if ((old_termios->c_iflag & IXON) &&	    !(tty->termios->c_iflag & IXON)) {		tty->stopped = 0;		mxser_start(tty);	}}/* * mxser_stop() and mxser_start() * * This routines are called before setting or resetting tty->stopped. * They enable or disable transmitter interrupts, as necessary. */static void mxser_stop(struct tty_struct *tty){	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;	unsigned long flags;	save_flags(flags);	cli();	if (info->IER & UART_IER_THRI) {		info->IER &= ~UART_IER_THRI;		outb(info->IER, info->base + UART_IER);	}	restore_flags(flags);}static void mxser_start(struct tty_struct *tty){	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;	unsigned long flags;	save_flags(flags);	cli();	if (info->xmit_cnt && info->xmit_buf &&	    !(info->IER & UART_IER_THRI)) {		info->IER |= UART_IER_THRI;		outb(info->IER, info->base + UART_IER);	}	restore_flags(flags);}/* * This routine is called by tty_hangup() when a hangup is signaled. */void mxser_hangup(struct tty_struct *tty){	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;	mxser_flush_buffer(tty);	mxser_shutdown(info);	info->event = 0;	info->count = 0;	info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);	info->tty = 0;	wake_up_interruptible(&info->open_wait);}/* * This is the serial driver's generic interrupt routine */static void mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs){	int status, i;	struct mxser_struct *info;	struct mxser_struct *port;	int max, irqbits, bits, msr;	int pass_counter = 0;	port = 0;	for (i = 0; i < MXSER_BOARDS; i++) {		if (dev_id == &(mxvar_table[i * MXSER_PORTS_PER_BOARD])) {			port = dev_id;			break;		}	}	if (i == MXSER_BOARDS)		return;	if (port == 0)		return;	max = mxser_numports[mxsercfg[i].board_type - 1];	while (1) {		irqbits = inb(port->vector) & port->vectormask;		if (irqbits == port->vectormask)			break;		for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) {			if (irqbits == port->vectormask)				break;			if (bits & irqbits)				continue;			info = port + i;			if (!info->tty ||			  (inb(info->base + UART_IIR) & UART_IIR_NO_INT))				continue;			status = inb(info->base + UART_LSR) & info->read_status_mask;			if (status & UART_LSR_DR)				mxser_receive_chars(info, &status);			msr = inb(info->base + UART_MSR);			if (msr & UART_MSR_ANY_DELTA)				mxser_check_modem_status(info, msr);			if (status & UART_LSR_THRE) {/* 8-2-99 by William   if ( info->x_char || (info->xmit_cnt > 0) ) */				mxser_transmit_chars(info);			}		}		if (pass_counter++ > MXSER_ISR_PASS_LIMIT) {#if 0			printk("MOXA Smartio/Indusrtio family driver interrupt loop break\n");#endif			break;	/* Prevent infinite loops */		}	}}static inline void mxser_receive_chars(struct mxser_struct *info,					 int *status){	struct tty_struct *tty = info->tty;	unsigned char ch;	int ignored = 0;	int cnt = 0;	do {		ch = inb(info->base + UART_RX);		if (*status & info->ignore_status_mask) {			if (++ignored > 100)				break;		} else {			if (tty->flip.count >= TTY_FLIPBUF_SIZE)				break;			tty->flip.count++;			if (*status & UART_LSR_SPECIAL) {				if (*status & UART_LSR_BI) {					*tty->flip.flag_buf_ptr++ = TTY_BREAK;					if (info->flags & ASYNC_SAK)						do_SAK(tty);				} else if (*status & UART_LSR_PE) {					*tty->flip.flag_buf_ptr++ = TTY_PARITY;				} else if (*status & UART_LSR_FE) {					*tty->flip.flag_buf_ptr++ = TTY_FRAME;				} else if (*status & UART_LSR_OE) {					*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;				} else					*tty->flip.flag_buf_ptr++ = 0;			} else				*tty->flip.flag_buf_ptr++ = 0;			*tty->flip.char_buf_ptr++ = ch;			cnt++;		}		*status = inb(info->base + UART_LSR) & info->read_status_mask;	} while (*status & UART_LSR_DR);	mxvar_log.rxcnt[info->port] += cnt;	queue_task(&tty->flip.tqueue, &tq_timer);}static inline void mxser_transmit_chars(struct mxser_struct *info){	int count, cnt;	if (info->x_char) {		outb(info->x_char, info->base + UART_TX);		info->x_char = 0;		mxvar_log.txcnt[info->port]++;		return;	}	if ((info->xmit_cnt <= 0) || info->tty->stopped ||	    info->tty->hw_stopped) {		info->IER &= ~UART_IER_THRI;		outb(info->IER, info->base + UART_IER);		return;	}	cnt = info->xmit_cnt;	count = info->xmit_fifo_size;	do {		outb(info->xmit_buf[info->xmit_tail++], info->base + UART_TX);		info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE - 1);		if (--info->xmit_cnt <= 0)			break;	} while (--count > 0);	mxvar_log.txcnt[info->port] += (cnt - info->xmit_cnt);	if (info->xmit_cnt < WAKEUP_CHARS) {		set_bit(MXSER_EVENT_TXLOW, &info->event);		schedule_task(&info->tqueue);	}

⌨️ 快捷键说明

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