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

📄 moxa.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	}	if (!MoxaPortIsValid(port)) {		tty->driver_data = NULL;		return (-ENODEV);	}	ch = &moxa_ports[port];	ch->count++;	tty->driver_data = ch;	ch->tty = tty;	if (!(ch->asyncflags & ASYNC_INITIALIZED)) {		ch->statusflags = 0;		moxa_set_tty_param(tty);		MoxaPortLineCtrl(ch->port, 1, 1);		MoxaPortEnable(ch->port);		ch->asyncflags |= ASYNC_INITIALIZED;	}	retval = moxa_block_till_ready(tty, filp, ch);	moxa_unthrottle(tty);	if (ch->type == PORT_16550A) {		MoxaSetFifo(ch->port, 1);	} else {		MoxaSetFifo(ch->port, 0);	}	return (retval);}static void moxa_close(struct tty_struct *tty, struct file *filp){	struct moxa_port *ch;	int port;	port = tty->index;	if (port == MAX_PORTS) {		return;	}	if (!MoxaPortIsValid(port)) {		pr_debug("Invalid portno in moxa_close\n");		tty->driver_data = NULL;		return;	}	if (tty->driver_data == NULL) {		return;	}	if (tty_hung_up_p(filp)) {		return;	}	ch = (struct moxa_port *) tty->driver_data;	if ((tty->count == 1) && (ch->count != 1)) {		printk(KERN_WARNING "moxa_close: bad serial port count; "			"tty->count is 1, ch->count is %d\n", ch->count);		ch->count = 1;	}	if (--ch->count < 0) {		printk(KERN_WARNING "moxa_close: bad serial port count, "			"device=%s\n", tty->name);		ch->count = 0;	}	if (ch->count) {		return;	}	ch->asyncflags |= ASYNC_CLOSING;	ch->cflag = tty->termios->c_cflag;	if (ch->asyncflags & ASYNC_INITIALIZED) {		moxa_setup_empty_event(tty);		tty_wait_until_sent(tty, 30 * HZ);	/* 30 seconds timeout */		del_timer_sync(&moxa_ports[ch->port].emptyTimer);	}	moxa_shut_down(ch);	MoxaPortFlushData(port, 2);	if (tty->driver->flush_buffer)		tty->driver->flush_buffer(tty);	tty_ldisc_flush(tty);				tty->closing = 0;	ch->event = 0;	ch->tty = NULL;	if (ch->blocked_open) {		if (ch->close_delay) {			msleep_interruptible(jiffies_to_msecs(ch->close_delay));		}		wake_up_interruptible(&ch->open_wait);	}	ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);	complete_all(&ch->close_wait);}static int moxa_write(struct tty_struct *tty,		      const unsigned char *buf, int count){	struct moxa_port *ch;	int len, port;	unsigned long flags;	ch = (struct moxa_port *) tty->driver_data;	if (ch == NULL)		return (0);	port = ch->port;	spin_lock_irqsave(&moxa_lock, flags);	len = MoxaPortWriteData(port, (unsigned char *) buf, count);	spin_unlock_irqrestore(&moxa_lock, flags);	/*********************************************	if ( !(ch->statusflags & LOWWAIT) &&	     ((len != count) || (MoxaPortTxFree(port) <= 100)) )	************************************************/	ch->statusflags |= LOWWAIT;	return (len);}static int moxa_write_room(struct tty_struct *tty){	struct moxa_port *ch;	if (tty->stopped)		return (0);	ch = (struct moxa_port *) tty->driver_data;	if (ch == NULL)		return (0);	return (MoxaPortTxFree(ch->port));}static void moxa_flush_buffer(struct tty_struct *tty){	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;	if (ch == NULL)		return;	MoxaPortFlushData(ch->port, 1);	tty_wakeup(tty);}static int moxa_chars_in_buffer(struct tty_struct *tty){	int chars;	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;	/*	 * Sigh...I have to check if driver_data is NULL here, because	 * if an open() fails, the TTY subsystem eventually calls	 * tty_wait_until_sent(), which calls the driver's chars_in_buffer()	 * routine.  And since the open() failed, we return 0 here.  TDJ	 */	if (ch == NULL)		return (0);	chars = MoxaPortTxQueue(ch->port);	if (chars) {		/*		 * Make it possible to wakeup anything waiting for output		 * in tty_ioctl.c, etc.		 */		if (!(ch->statusflags & EMPTYWAIT))			moxa_setup_empty_event(tty);	}	return (chars);}static void moxa_flush_chars(struct tty_struct *tty){	/*	 * Don't think I need this, because this is called to empty the TX	 * buffer for the 16450, 16550, etc.	 */}static void moxa_put_char(struct tty_struct *tty, unsigned char c){	struct moxa_port *ch;	int port;	unsigned long flags;	ch = (struct moxa_port *) tty->driver_data;	if (ch == NULL)		return;	port = ch->port;	spin_lock_irqsave(&moxa_lock, flags);	MoxaPortWriteData(port, &c, 1);	spin_unlock_irqrestore(&moxa_lock, flags);	/************************************************	if ( !(ch->statusflags & LOWWAIT) && (MoxaPortTxFree(port) <= 100) )	*************************************************/	ch->statusflags |= LOWWAIT;}static int moxa_tiocmget(struct tty_struct *tty, struct file *file){	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;	int port;	int flag = 0, dtr, rts;	port = tty->index;	if ((port != MAX_PORTS) && (!ch))		return (-EINVAL);	MoxaPortGetLineOut(ch->port, &dtr, &rts);	if (dtr)		flag |= TIOCM_DTR;	if (rts)		flag |= TIOCM_RTS;	dtr = MoxaPortLineStatus(ch->port);	if (dtr & 1)		flag |= TIOCM_CTS;	if (dtr & 2)		flag |= TIOCM_DSR;	if (dtr & 4)		flag |= TIOCM_CD;	return flag;}static int moxa_tiocmset(struct tty_struct *tty, struct file *file,			 unsigned int set, unsigned int clear){	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;	int port;	int dtr, rts;	port = tty->index;	if ((port != MAX_PORTS) && (!ch))		return (-EINVAL);	MoxaPortGetLineOut(ch->port, &dtr, &rts);	if (set & TIOCM_RTS)		rts = 1;	if (set & TIOCM_DTR)		dtr = 1;	if (clear & TIOCM_RTS)		rts = 0;	if (clear & TIOCM_DTR)		dtr = 0;	MoxaPortLineCtrl(ch->port, dtr, rts);	return 0;}static int moxa_ioctl(struct tty_struct *tty, struct file *file,		      unsigned int cmd, unsigned long arg){	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;	register int port;	void __user *argp = (void __user *)arg;	int retval;	port = tty->index;	if ((port != MAX_PORTS) && (!ch))		return (-EINVAL);	switch (cmd) {	case TCSBRK:		/* SVID version: non-zero arg --> no break */		retval = tty_check_change(tty);		if (retval)			return (retval);		moxa_setup_empty_event(tty);		tty_wait_until_sent(tty, 0);		if (!arg)			MoxaPortSendBreak(ch->port, 0);		return (0);	case TCSBRKP:		/* support for POSIX tcsendbreak() */		retval = tty_check_change(tty);		if (retval)			return (retval);		moxa_setup_empty_event(tty);		tty_wait_until_sent(tty, 0);		MoxaPortSendBreak(ch->port, arg);		return (0);	case TIOCGSOFTCAR:		return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) argp);	case TIOCSSOFTCAR:		if(get_user(retval, (unsigned long __user *) argp))			return -EFAULT;		arg = retval;		tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) |					 (arg ? CLOCAL : 0));		if (C_CLOCAL(tty))			ch->asyncflags &= ~ASYNC_CHECK_CD;		else			ch->asyncflags |= ASYNC_CHECK_CD;		return (0);	case TIOCGSERIAL:		return moxa_get_serial_info(ch, argp);	case TIOCSSERIAL:		return moxa_set_serial_info(ch, argp);	default:		retval = MoxaDriverIoctl(cmd, arg, port);	}	return (retval);}static void moxa_throttle(struct tty_struct *tty){	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;	ch->statusflags |= THROTTLE;}static void moxa_unthrottle(struct tty_struct *tty){	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;	ch->statusflags &= ~THROTTLE;}static void moxa_set_termios(struct tty_struct *tty,			     struct ktermios *old_termios){	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;	if (ch == NULL)		return;	moxa_set_tty_param(tty);	if (!(old_termios->c_cflag & CLOCAL) &&	    (tty->termios->c_cflag & CLOCAL))		wake_up_interruptible(&ch->open_wait);}static void moxa_stop(struct tty_struct *tty){	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;	if (ch == NULL)		return;	MoxaPortTxDisable(ch->port);	ch->statusflags |= TXSTOPPED;}static void moxa_start(struct tty_struct *tty){	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;	if (ch == NULL)		return;	if (!(ch->statusflags & TXSTOPPED))		return;	MoxaPortTxEnable(ch->port);	ch->statusflags &= ~TXSTOPPED;}static void moxa_hangup(struct tty_struct *tty){	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;	moxa_flush_buffer(tty);	moxa_shut_down(ch);	ch->event = 0;	ch->count = 0;	ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;	ch->tty = NULL;	wake_up_interruptible(&ch->open_wait);}static void moxa_poll(unsigned long ignored){	register int card;	struct moxa_port *ch;	struct tty_struct *tp;	int i, ports;	del_timer(&moxaTimer);	if (MoxaDriverPoll() < 0) {		mod_timer(&moxaTimer, jiffies + HZ / 50);		return;	}	for (card = 0; card < MAX_BOARDS; card++) {		if ((ports = MoxaPortsOfCard(card)) <= 0)			continue;		ch = &moxa_ports[card * MAX_PORTS_PER_BOARD];		for (i = 0; i < ports; i++, ch++) {			if ((ch->asyncflags & ASYNC_INITIALIZED) == 0)				continue;			if (!(ch->statusflags & THROTTLE) &&			    (MoxaPortRxQueue(ch->port) > 0))				moxa_receive_data(ch);			if ((tp = ch->tty) == 0)				continue;			if (ch->statusflags & LOWWAIT) {				if (MoxaPortTxQueue(ch->port) <= WAKEUP_CHARS) {					if (!tp->stopped) {						ch->statusflags &= ~LOWWAIT;						tty_wakeup(tp);					}				}			}			if (!I_IGNBRK(tp) && (MoxaPortResetBrkCnt(ch->port) > 0)) {				tty_insert_flip_char(tp, 0, TTY_BREAK);				tty_schedule_flip(tp);			}			if (MoxaPortDCDChange(ch->port)) {				if (ch->asyncflags & ASYNC_CHECK_CD) {					if (MoxaPortDCDON(ch->port))						wake_up_interruptible(&ch->open_wait);					else {						tty_hangup(tp);						wake_up_interruptible(&ch->open_wait);						ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;					}				}			}		}	}	mod_timer(&moxaTimer, jiffies + HZ / 50);}/******************************************************************************/static void moxa_set_tty_param(struct tty_struct *tty){	register struct ktermios *ts;	struct moxa_port *ch;	int rts, cts, txflow, rxflow, xany;	ch = (struct moxa_port *) tty->driver_data;	ts = tty->termios;	if (ts->c_cflag & CLOCAL)		ch->asyncflags &= ~ASYNC_CHECK_CD;	else		ch->asyncflags |= ASYNC_CHECK_CD;	rts = cts = txflow = rxflow = xany = 0;	if (ts->c_cflag & CRTSCTS)		rts = cts = 1;	if (ts->c_iflag & IXON)		txflow = 1;	if (ts->c_iflag & IXOFF)		rxflow = 1;	if (ts->c_iflag & IXANY)		xany = 1;	MoxaPortFlowCtrl(ch->port, rts, cts, txflow, rxflow, xany);	MoxaPortSetTermio(ch->port, ts, tty_get_baud_rate(tty));}static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,			    struct moxa_port *ch){	DECLARE_WAITQUEUE(wait,current);	unsigned long flags;	int retval;	int do_clocal = C_CLOCAL(tty);	/*	 * If the device is in the middle of being closed, then block	 * until it's done, and then try again.	 */	if (tty_hung_up_p(filp) || (ch->asyncflags & ASYNC_CLOSING)) {		if (ch->asyncflags & ASYNC_CLOSING)			wait_for_completion_interruptible(&ch->close_wait);#ifdef SERIAL_DO_RESTART		if (ch->asyncflags & ASYNC_HUP_NOTIFY)			return (-EAGAIN);		else			return (-ERESTARTSYS);#else		return (-EAGAIN);#endif	}	/*	 * If non-blocking mode is set, then make the check up front	 * and then exit.	 */	if (filp->f_flags & O_NONBLOCK) {		ch->asyncflags |= ASYNC_NORMAL_ACTIVE;		return (0);	}	/*	 * Block waiting for the carrier detect and the line to become free	 */	retval = 0;	add_wait_queue(&ch->open_wait, &wait);	pr_debug("block_til_ready before block: ttys%d, count = %d\n",		ch->port, ch->count);	spin_lock_irqsave(&moxa_lock, flags);	if (!tty_hung_up_p(filp))		ch->count--;	ch->blocked_open++;	spin_unlock_irqrestore(&moxa_lock, flags);	while (1) {		set_current_state(TASK_INTERRUPTIBLE);		if (tty_hung_up_p(filp) ||		    !(ch->asyncflags & ASYNC_INITIALIZED)) {#ifdef SERIAL_DO_RESTART

⌨️ 快捷键说明

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