rocket.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,368 行 · 第 1/5 页
C
2,368 行
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, i; unsigned int xmitmask; 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 interupt 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 = kmalloc(sizeof (struct r_port), GFP_KERNEL); if (!info) { printk(KERN_INFO "Couldn't allocate info struct for line #%d\n", line); return; } memset(info, 0, sizeof (struct r_port)); 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_waitqueue_head(&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); sema_init(&info->write_sem, 1); rp_table[line] = info; if (pci_dev) tty_register_device(rocket_driver, line, &pci_dev->dev);}/* * 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 termios *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) { interruptible_sleep_on(&info->close_wait); 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; break; } if (!(info->flags & ROCKET_CLOSING) && (do_clocal || (sGetChanStatusLo(&info->channel) & CD_ACT))) break; if (signal_pending(current)) { retval = -ERESTARTSYS; break; }#ifdef ROCKET_DEBUG_OPEN printk(KERN_INFO "block_til_ready blocking: ttyR%d, count = %d, flags=0x%0x\n", info->line, info->count, info->flags);#endif schedule(); /* Don't hold spinlock here, will hang PC */ } current->state = TASK_RUNNING; remove_wait_queue(&info->open_wait, &wait); spin_lock_irqsave(&info->slock, flags); if (extra_count) info->count++; info->blocked_open--; spin_unlock_irqrestore(&info->slock, flags);#ifdef ROCKET_DEBUG_OPEN printk(KERN_INFO "block_til_ready after blocking: ttyR%d, count = %d\n", info->line, info->count);#endif if (retval) return retval; info->flags |= ROCKET_NORMAL_ACTIVE; return 0;}/* * Exception handler that opens a serial port. Creates xmit_buf storage, fills in * port's r_port struct. Initializes the port hardware. */static int rp_open(struct tty_struct *tty, struct file *filp){ struct r_port *info; int line = 0, retval; CHANNEL_t *cp; unsigned long page; line = TTY_GET_LINE(tty); if ((line < 0) || (line >= MAX_RP_PORTS) || ((info = rp_table[line]) == NULL)) return -ENXIO; page = __get_free_page(GFP_KERNEL); if (!page) return -ENOMEM; if (info->flags & ROCKET_CLOSING) { interruptible_sleep_on(&info->close_wait); free_page(page); return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); } /* * We must not sleep from here until the port is marked fully in use. */ if (info->xmit_buf) free_page(page); else info->xmit_buf = (unsigned char *) page; tty->driver_data = info; info->tty = tty; if (info->count++ == 0) { atomic_inc(&rp_num_ports_open);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?