rocket.c
来自「linux 内核源代码」· C语言 代码 · 共 2,326 行 · 第 1/5 页
C
2,326 行
printk(KERN_INFO "tx %d chars...", c);#endif } if (info->xmit_cnt == 0) clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); if (info->xmit_cnt < WAKEUP_CHARS) { tty_wakeup(tty);#ifdef ROCKETPORT_HAVE_POLL_WAIT wake_up_interruptible(&tty->poll_wait);#endif } spin_unlock_irqrestore(&info->slock, flags);#ifdef ROCKET_DEBUG_INTR printk(KERN_INFO "(%d,%d,%d,%d)...", info->xmit_cnt, info->xmit_head, info->xmit_tail, info->xmit_fifo_room);#endif}/* * Called when a serial port signals it has read data in it's RX FIFO. * It checks what interrupts are pending and services them, including * receiving serial data. */static void rp_handle_port(struct r_port *info){ CHANNEL_t *cp; struct tty_struct *tty; unsigned int IntMask, ChanStatus; if (!info) return; if ((info->flags & ROCKET_INITIALIZED) == 0) { printk(KERN_INFO "rp: WARNING: rp_handle_port called with info->flags & NOT_INIT\n"); return; } if (!info->tty) { printk(KERN_INFO "rp: WARNING: rp_handle_port called with info->tty==NULL\n"); return; } cp = &info->channel; tty = info->tty; IntMask = sGetChanIntID(cp) & info->intmask;#ifdef ROCKET_DEBUG_INTR printk(KERN_INFO "rp_interrupt %02x...", IntMask);#endif ChanStatus = sGetChanStatus(cp); if (IntMask & RXF_TRIG) { /* Rx FIFO trigger level */ rp_do_receive(info, tty, cp, ChanStatus); } if (IntMask & DELTA_CD) { /* CD change */#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_INTR) || defined(ROCKET_DEBUG_HANGUP)) printk(KERN_INFO "ttyR%d CD now %s...", info->line, (ChanStatus & CD_ACT) ? "on" : "off");#endif if (!(ChanStatus & CD_ACT) && info->cd_status) {#ifdef ROCKET_DEBUG_HANGUP printk(KERN_INFO "CD drop, calling hangup.\n");#endif tty_hangup(tty); } info->cd_status = (ChanStatus & CD_ACT) ? 1 : 0; wake_up_interruptible(&info->open_wait); }#ifdef ROCKET_DEBUG_INTR if (IntMask & DELTA_CTS) { /* CTS change */ printk(KERN_INFO "CTS change...\n"); } if (IntMask & DELTA_DSR) { /* DSR change */ printk(KERN_INFO "DSR change...\n"); }#endif}/* * The top level polling routine. Repeats every 1/100 HZ (10ms). */static void rp_do_poll(unsigned long dummy){ CONTROLLER_t *ctlp; int ctrl, aiop, ch, line; unsigned int xmitmask, i; unsigned int CtlMask; unsigned char AiopMask; Word_t bit; /* Walk through all the boards (ctrl's) */ for (ctrl = 0; ctrl < max_board; ctrl++) { if (rcktpt_io_addr[ctrl] <= 0) continue; /* Get a ptr to the board's control struct */ ctlp = sCtlNumToCtlPtr(ctrl); /* Get the interrupt status from the board */#ifdef CONFIG_PCI if (ctlp->BusType == isPCI) CtlMask = sPCIGetControllerIntStatus(ctlp); else#endif CtlMask = sGetControllerIntStatus(ctlp); /* Check if any AIOP read bits are set */ for (aiop = 0; CtlMask; aiop++) { bit = ctlp->AiopIntrBits[aiop]; if (CtlMask & bit) { CtlMask &= ~bit; AiopMask = sGetAiopIntStatus(ctlp, aiop); /* Check if any port read bits are set */ for (ch = 0; AiopMask; AiopMask >>= 1, ch++) { if (AiopMask & 1) { /* Get the line number (/dev/ttyRx number). */ /* Read the data from the port. */ line = GetLineNumber(ctrl, aiop, ch); rp_handle_port(rp_table[line]); } } } } xmitmask = xmit_flags[ctrl]; /* * xmit_flags contains bit-significant flags, indicating there is data * to xmit on the port. Bit 0 is port 0 on this board, bit 1 is port * 1, ... (32 total possible). The variable i has the aiop and ch * numbers encoded in it (port 0-7 are aiop0, 8-15 are aiop1, etc). */ if (xmitmask) { for (i = 0; i < rocketModel[ctrl].numPorts; i++) { if (xmitmask & (1 << i)) { aiop = (i & 0x18) >> 3; ch = i & 0x07; line = GetLineNumber(ctrl, aiop, ch); rp_do_transmit(rp_table[line]); } } } } /* * Reset the timer so we get called at the next clock tick (10ms). */ if (atomic_read(&rp_num_ports_open)) mod_timer(&rocket_timer, jiffies + POLL_PERIOD);}/* * Initializes the r_port structure for a port, as well as enabling the port on * the board. * Inputs: board, aiop, chan numbers */static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev){ unsigned rocketMode; struct r_port *info; int line; CONTROLLER_T *ctlp; /* Get the next available line number */ line = SetLineNumber(board, aiop, chan); ctlp = sCtlNumToCtlPtr(board); /* Get a r_port struct for the port, fill it in and save it globally, indexed by line number */ info = kzalloc(sizeof (struct r_port), GFP_KERNEL); if (!info) { printk(KERN_INFO "Couldn't allocate info struct for line #%d\n", line); return; } info->magic = RPORT_MAGIC; info->line = line; info->ctlp = ctlp; info->board = board; info->aiop = aiop; info->chan = chan; info->closing_wait = 3000; info->close_delay = 50; init_waitqueue_head(&info->open_wait); init_completion(&info->close_wait); info->flags &= ~ROCKET_MODE_MASK; switch (pc104[board][line]) { case 422: info->flags |= ROCKET_MODE_RS422; break; case 485: info->flags |= ROCKET_MODE_RS485; break; case 232: default: info->flags |= ROCKET_MODE_RS232; break; } info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR; if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) { printk(KERN_INFO "RocketPort sInitChan(%d, %d, %d) failed!\n", board, aiop, chan); kfree(info); return; } rocketMode = info->flags & ROCKET_MODE_MASK; if ((info->flags & ROCKET_RTS_TOGGLE) || (rocketMode == ROCKET_MODE_RS485)) sEnRTSToggle(&info->channel); else sDisRTSToggle(&info->channel); if (ctlp->boardType == ROCKET_TYPE_PC104) { switch (rocketMode) { case ROCKET_MODE_RS485: sSetInterfaceMode(&info->channel, InterfaceModeRS485); break; case ROCKET_MODE_RS422: sSetInterfaceMode(&info->channel, InterfaceModeRS422); break; case ROCKET_MODE_RS232: default: if (info->flags & ROCKET_RTS_TOGGLE) sSetInterfaceMode(&info->channel, InterfaceModeRS232T); else sSetInterfaceMode(&info->channel, InterfaceModeRS232); break; } } spin_lock_init(&info->slock); mutex_init(&info->write_mtx); rp_table[line] = info; tty_register_device(rocket_driver, line, pci_dev ? &pci_dev->dev : NULL);}/* * Configures a rocketport port according to its termio settings. Called from * user mode into the driver (exception handler). *info CD manipulation is spinlock protected. */static void configure_r_port(struct r_port *info, struct ktermios *old_termios){ unsigned cflag; unsigned long flags; unsigned rocketMode; int bits, baud, divisor; CHANNEL_t *cp; if (!info->tty || !info->tty->termios) return; cp = &info->channel; cflag = info->tty->termios->c_cflag; /* Byte size and parity */ if ((cflag & CSIZE) == CS8) { sSetData8(cp); bits = 10; } else { sSetData7(cp); bits = 9; } if (cflag & CSTOPB) { sSetStop2(cp); bits++; } else { sSetStop1(cp); } if (cflag & PARENB) { sEnParity(cp); bits++; if (cflag & PARODD) { sSetOddParity(cp); } else { sSetEvenParity(cp); } } else { sDisParity(cp); } /* baud rate */ baud = tty_get_baud_rate(info->tty); if (!baud) baud = 9600; divisor = ((rp_baud_base[info->board] + (baud >> 1)) / baud) - 1; if ((divisor >= 8192 || divisor < 0) && old_termios) { info->tty->termios->c_cflag &= ~CBAUD; info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); baud = tty_get_baud_rate(info->tty); if (!baud) baud = 9600; divisor = (rp_baud_base[info->board] / baud) - 1; } if (divisor >= 8192 || divisor < 0) { baud = 9600; divisor = (rp_baud_base[info->board] / baud) - 1; } info->cps = baud / bits; sSetBaud(cp, divisor); if (cflag & CRTSCTS) { info->intmask |= DELTA_CTS; sEnCTSFlowCtl(cp); } else { info->intmask &= ~DELTA_CTS; sDisCTSFlowCtl(cp); } if (cflag & CLOCAL) { info->intmask &= ~DELTA_CD; } else { spin_lock_irqsave(&info->slock, flags); if (sGetChanStatus(cp) & CD_ACT) info->cd_status = 1; else info->cd_status = 0; info->intmask |= DELTA_CD; spin_unlock_irqrestore(&info->slock, flags); } /* * Handle software flow control in the board */#ifdef ROCKET_SOFT_FLOW if (I_IXON(info->tty)) { sEnTxSoftFlowCtl(cp); if (I_IXANY(info->tty)) { sEnIXANY(cp); } else { sDisIXANY(cp); } sSetTxXONChar(cp, START_CHAR(info->tty)); sSetTxXOFFChar(cp, STOP_CHAR(info->tty)); } else { sDisTxSoftFlowCtl(cp); sDisIXANY(cp); sClrTxXOFF(cp); }#endif /* * Set up ignore/read mask words */ info->read_status_mask = STMRCVROVRH | 0xFF; if (I_INPCK(info->tty)) info->read_status_mask |= STMFRAMEH | STMPARITYH; if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) info->read_status_mask |= STMBREAKH; /* * Characters to ignore */ info->ignore_status_mask = 0; if (I_IGNPAR(info->tty)) info->ignore_status_mask |= STMFRAMEH | STMPARITYH; if (I_IGNBRK(info->tty)) { info->ignore_status_mask |= STMBREAKH; /* * If we're ignoring parity and break indicators, * ignore overruns too. (For real raw support). */ if (I_IGNPAR(info->tty)) info->ignore_status_mask |= STMRCVROVRH; } rocketMode = info->flags & ROCKET_MODE_MASK; if ((info->flags & ROCKET_RTS_TOGGLE) || (rocketMode == ROCKET_MODE_RS485)) sEnRTSToggle(cp); else sDisRTSToggle(cp); sSetRTS(&info->channel); if (cp->CtlP->boardType == ROCKET_TYPE_PC104) { switch (rocketMode) { case ROCKET_MODE_RS485: sSetInterfaceMode(cp, InterfaceModeRS485); break; case ROCKET_MODE_RS422: sSetInterfaceMode(cp, InterfaceModeRS422); break; case ROCKET_MODE_RS232: default: if (info->flags & ROCKET_RTS_TOGGLE) sSetInterfaceMode(cp, InterfaceModeRS232T); else sSetInterfaceMode(cp, InterfaceModeRS232); break; } }}/* info->count is considered critical, protected by spinlocks. */static int block_til_ready(struct tty_struct *tty, struct file *filp, struct r_port *info){ DECLARE_WAITQUEUE(wait, current); int retval; int do_clocal = 0, extra_count = 0; unsigned long flags; /* * 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)) return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); if (info->flags & ROCKET_CLOSING) { if (wait_for_completion_interruptible(&info->close_wait)) return -ERESTARTSYS; return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); } /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { info->flags |= ROCKET_NORMAL_ACTIVE; return 0; } if (tty->termios->c_cflag & CLOCAL) do_clocal = 1; /* * Block waiting for the carrier detect and the line to become free. While we are in * this loop, info->count is dropped by one, so that rp_close() knows when to free things. * We restore it upon exit, either normal or abnormal. */ retval = 0; add_wait_queue(&info->open_wait, &wait);#ifdef ROCKET_DEBUG_OPEN printk(KERN_INFO "block_til_ready before block: ttyR%d, count = %d\n", info->line, info->count);#endif spin_lock_irqsave(&info->slock, flags);#ifdef ROCKET_DISABLE_SIMUSAGE info->flags |= ROCKET_NORMAL_ACTIVE;#else if (!tty_hung_up_p(filp)) { extra_count = 1; info->count--; }#endif info->blocked_open++; spin_unlock_irqrestore(&info->slock, flags); while (1) { if (tty->termios->c_cflag & CBAUD) { sSetDTR(&info->channel); sSetRTS(&info->channel); } set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ROCKET_INITIALIZED)) { if (info->flags & ROCKET_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?