📄 moxa.c
字号:
ch = (struct moxa_str *) tty->driver_data; if (ch == NULL) return (0); port = ch->port; save_flags(flags); cli(); if (from_user) { copy_from_user(moxaXmitBuff, buf, count); temp = moxaXmitBuff; } else temp = (unsigned char *) buf; len = MoxaPortWriteData(port, temp, count); restore_flags(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_str *ch; if (tty->stopped) return (0); ch = (struct moxa_str *) tty->driver_data; if (ch == NULL) return (0); return (MoxaPortTxFree(ch->port));}static void moxa_flush_buffer(struct tty_struct *tty){ struct moxa_str *ch = (struct moxa_str *) tty->driver_data; if (ch == NULL) return; MoxaPortFlushData2(ch->port, 1); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup) (tty); wake_up_interruptible(&tty->write_wait);}static int moxa_chars_in_buffer(struct tty_struct *tty){ int chars; struct moxa_str *ch = (struct moxa_str *) 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)) 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_str *ch; int port; unsigned long flags; ch = (struct moxa_str *) tty->driver_data; if (ch == NULL) return; port = ch->port; save_flags(flags); cli(); moxaXmitBuff[0] = c; MoxaPortWriteData(port, moxaXmitBuff, 1); restore_flags(flags); /************************************************ if ( !(ch->statusflags & LOWWAIT) && (MoxaPortTxFree(port) <= 100) ) *************************************************/ ch->statusflags |= LOWWAIT;}static int moxa_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg){ struct moxa_str *ch = (struct moxa_str *)tty->driver_data; register int port; int retval, dtr, rts; unsigned long flag; port = PORTNO(tty); 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); 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); setup_empty_event(tty); tty_wait_until_sent(tty, 0); MoxaPortSendBreak(ch->port, arg); return(0); case TIOCGSOFTCAR: retval = verify_area(VERIFY_WRITE, (void *)arg, sizeof(long)); if ( retval ) return(retval); put_to_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg); return(0); case TIOCSSOFTCAR: retval = verify_area(VERIFY_READ, (void *)arg, sizeof(long)); if ( retval ) return(retval); get_from_user(retval,(unsigned long *)arg); 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 TIOCMGET: retval = verify_area(VERIFY_WRITE, (void *)arg, sizeof(long)); if ( retval ) return(retval); flag = 0; 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; put_to_user(flag, (unsigned long *)arg); return(0); case TIOCMBIS: retval = verify_area(VERIFY_READ, (void *)arg, sizeof(long)); if ( retval ) return(retval); get_from_user(retval,(unsigned long *)arg); MoxaPortGetLineOut(ch->port, &dtr, &rts); if ( retval & TIOCM_RTS ) rts = 1; if ( retval & TIOCM_DTR ) dtr = 1; MoxaPortLineCtrl(ch->port, dtr, rts); return(0); case TIOCMBIC: retval = verify_area(VERIFY_READ, (void *)arg, sizeof(long)); if ( retval ) return(retval); get_from_user(retval,(unsigned long *)arg); MoxaPortGetLineOut(ch->port, &dtr, &rts); if ( retval & TIOCM_RTS ) rts = 0; if ( retval & TIOCM_DTR ) dtr = 0; MoxaPortLineCtrl(ch->port, dtr, rts); return(0); case TIOCMSET: retval = verify_area(VERIFY_READ, (void *)arg, sizeof(long)); if ( retval ) return(retval); get_from_user(retval,(unsigned long *)arg); dtr = rts = 0; if ( retval & TIOCM_RTS ) rts = 1; if ( retval & TIOCM_DTR ) dtr = 1; MoxaPortLineCtrl(ch->port, dtr, rts); return(0); case TIOCGSERIAL: retval = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct serial_struct)); if ( retval ) return(retval); return(moxa_get_serial_info(ch, (struct serial_struct *)arg)); case TIOCSSERIAL: retval = verify_area(VERIFY_READ, (void *)arg, sizeof(struct serial_struct)); if ( retval ) return(retval); return(moxa_set_serial_info(ch, (struct serial_struct *)arg)); default: retval = MoxaDriverIoctl(cmd, arg, port); } return(retval);}static void moxa_throttle(struct tty_struct * tty){ struct moxa_str *ch = (struct moxa_str *)tty->driver_data; ch->statusflags |= THROTTLE;}static void moxa_unthrottle(struct tty_struct * tty){ struct moxa_str *ch = (struct moxa_str *)tty->driver_data; ch->statusflags &= ~THROTTLE;}static void moxa_set_termios(struct tty_struct *tty, struct termios *old_termios){ struct moxa_str *ch = (struct moxa_str *) tty->driver_data; if (ch == NULL) return; 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_str *ch = (struct moxa_str *) tty->driver_data; if (ch == NULL) return; MoxaPortTxDisable(ch->port); ch->statusflags |= TXSTOPPED;}static void moxa_start(struct tty_struct *tty){ struct moxa_str *ch = (struct moxa_str *) 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_str *ch = (struct moxa_str *) tty->driver_data; moxa_flush_buffer(tty); shut_down(ch); ch->event = 0; ch->count = 0; ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); ch->tty = 0; wake_up_interruptible(&ch->open_wait);}static void moxa_poll(unsigned long ignored){ register int card; struct moxa_str *ch; struct tty_struct *tp; int i, ports; moxaTimer_on = 0; del_timer(&moxaTimer); if (MoxaDriverPoll() < 0) { moxaTimer.function = moxa_poll; moxaTimer.expires = jiffies + (HZ / 50); moxaTimer_on = 1; add_timer(&moxaTimer); return; } for ( card=0; card<MAX_BOARDS; card++ ) { if ( (ports = MoxaPortsOfCard(card)) <= 0 ) continue; ch = &moxaChannels[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) ) 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; if ( (tp->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tp->ldisc.write_wakeup ) (tp->ldisc.write_wakeup)(tp); wake_up_interruptible(&tp->write_wait); } } } 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 { set_bit(MOXA_EVENT_HANGUP,&ch->event); MOD_DEC_USE_COUNT;#if (LINUX_VERSION_CODE >= VERSION_CODE(2,4,0)) if (schedule_task(&ch->tqueue) == 0) MOD_INC_USE_COUNT;#else# if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)) queue_task(&ch->tqueue, &tq_scheduler);# else queue_task_irq_off(&ch->tqueue,&tq_scheduler);# endif#endif } } } } } moxaTimer.function = moxa_poll; moxaTimer.expires = jiffies + (HZ/50); moxaTimer_on = 1; add_timer(&moxaTimer);}/******************************************************************************/static void set_tty_param(struct tty_struct *tty){ register struct termios *ts; struct moxa_str *ch; int rts, cts, txflow, rxflow, xany; ch = (struct moxa_str *) 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);}static int block_till_ready(struct tty_struct *tty, struct file *filp, struct moxa_str *ch){#if (LINUX_VERSION_CODE >= VERSION_CODE(2,4,0)) DECLARE_WAITQUEUE(wait,current); #else struct wait_queue wait = {current, NULL};#endif 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) interruptible_sleep_on(&ch->close_wait);#ifdef SERIAL_DO_RESTART if (ch->asyncflags & ASYNC_HUP_NOTIFY) return (-EAGAIN); else return (-ERESTARTSYS);#else return (-EAGAIN);#endif } /* * If this is a callout device, then just make sure the normal * device isn't being used. */ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { if (ch->asyncflags & ASYNC_NORMAL_ACTIVE) return (-EBUSY); if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) && (ch->asyncflags & ASYNC_SESSION_LOCKOUT) && (ch->session != current->session)) return (-EBUSY); if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) && (ch->asyncflags & ASYNC_PGRP_LOCKOUT) && (ch->pgrp != current->pgrp)) return (-EBUSY); ch->asyncflags |= ASYNC_CALLOUT_ACTIVE; return (0); } /* * If non-blocking mode is set, then make the check up front * and then exit. */ if (filp->f_flags & O_NONBLOCK) { if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE) return (-EBUSY); 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);#ifdef SERIAL_DEBUG_OPEN printk("block_til_ready before block: ttys%d, count = %d\n", ch->line, ch->count);#endif save_flags(flags); cli(); if (!tty_hung_up_p(filp)) ch->count--; restore_flags(flags); ch->blocked_open++; while (1) { current->state = TASK_INTERRUPTIBLE; if (tty_hung_up_p(filp) || !(ch->asyncflags & ASYNC_INITIALIZED)) {#ifdef SERIAL_DO_RESTART if (ch->asyncflags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -