rocket.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,368 行 · 第 1/5 页
C
2,368 行
#ifdef ROCKET_DEBUG_THROTTLE printk(KERN_INFO "throttle %s: %d....\n", tty->name, tty->ldisc.chars_in_buffer(tty));#endif if (rocket_paranoia_check(info, "rp_throttle")) return; cp = &info->channel; if (I_IXOFF(tty)) rp_send_xchar(tty, STOP_CHAR(tty)); sClrRTS(&info->channel);}static void rp_unthrottle(struct tty_struct *tty){ struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp;#ifdef ROCKET_DEBUG_THROTTLE printk(KERN_INFO "unthrottle %s: %d....\n", tty->name, tty->ldisc.chars_in_buffer(tty));#endif if (rocket_paranoia_check(info, "rp_throttle")) return; cp = &info->channel; if (I_IXOFF(tty)) rp_send_xchar(tty, START_CHAR(tty)); sSetRTS(&info->channel);}/* * ------------------------------------------------------------ * rp_stop() and rp_start() * * This routines are called before setting or resetting tty->stopped. * They enable or disable transmitter interrupts, as necessary. * ------------------------------------------------------------ */static void rp_stop(struct tty_struct *tty){ struct r_port *info = (struct r_port *) tty->driver_data;#ifdef ROCKET_DEBUG_FLOW printk(KERN_INFO "stop %s: %d %d....\n", tty->name, info->xmit_cnt, info->xmit_fifo_room);#endif if (rocket_paranoia_check(info, "rp_stop")) return; if (sGetTxCnt(&info->channel)) sDisTransmit(&info->channel);}static void rp_start(struct tty_struct *tty){ struct r_port *info = (struct r_port *) tty->driver_data;#ifdef ROCKET_DEBUG_FLOW printk(KERN_INFO "start %s: %d %d....\n", tty->name, info->xmit_cnt, info->xmit_fifo_room);#endif if (rocket_paranoia_check(info, "rp_stop")) return; sEnTransmit(&info->channel); set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);}/* * rp_wait_until_sent() --- wait until the transmitter is empty */static void rp_wait_until_sent(struct tty_struct *tty, int timeout){ struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; unsigned long orig_jiffies; int check_time, exit_time; int txcnt; if (rocket_paranoia_check(info, "rp_wait_until_sent")) return; cp = &info->channel; orig_jiffies = jiffies;#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT printk(KERN_INFO "In RP_wait_until_sent(%d) (jiff=%lu)...", timeout, jiffies); printk(KERN_INFO "cps=%d...", info->cps);#endif while (1) { txcnt = sGetTxCnt(cp); if (!txcnt) { if (sGetChanStatusLo(cp) & TXSHRMT) break; check_time = (HZ / info->cps) / 5; } else { check_time = HZ * txcnt / info->cps; } if (timeout) { exit_time = orig_jiffies + timeout - jiffies; if (exit_time <= 0) break; if (exit_time < check_time) check_time = exit_time; } if (check_time == 0) check_time = 1;#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT printk(KERN_INFO "txcnt = %d (jiff=%lu,check=%d)...", txcnt, jiffies, check_time);#endif current->state = TASK_INTERRUPTIBLE; schedule_timeout(check_time); if (signal_pending(current)) break; } current->state = TASK_RUNNING;#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies);#endif}/* * rp_hangup() --- called by tty_hangup() when a hangup is signaled. */static void rp_hangup(struct tty_struct *tty){ CHANNEL_t *cp; struct r_port *info = (struct r_port *) tty->driver_data; if (rocket_paranoia_check(info, "rp_hangup")) return;#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_HANGUP)) printk(KERN_INFO "rp_hangup of ttyR%d...", info->line);#endif rp_flush_buffer(tty); if (info->flags & ROCKET_CLOSING) return; if (info->count) atomic_dec(&rp_num_ports_open); clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); info->count = 0; info->flags &= ~ROCKET_NORMAL_ACTIVE; info->tty = NULL; cp = &info->channel; sDisRxFIFO(cp); sDisTransmit(cp); sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN)); sDisCTSFlowCtl(cp); sDisTxSoftFlowCtl(cp); sClrTxXOFF(cp); info->flags &= ~ROCKET_INITIALIZED; wake_up_interruptible(&info->open_wait);}/* * Exception handler - write char routine. The RocketPort driver uses a * double-buffering strategy, with the twist that if the in-memory CPU * buffer is empty, and there's space in the transmit FIFO, the * writing routines will write directly to transmit FIFO. * Write buffer and counters protected by spinlocks */static void rp_put_char(struct tty_struct *tty, unsigned char ch){ struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; unsigned long flags; if (rocket_paranoia_check(info, "rp_put_char")) return; /* Grab the port write semaphore, locking out other processes that try to write to this port */ down(&info->write_sem);#ifdef ROCKET_DEBUG_WRITE printk(KERN_INFO "rp_put_char %c...", ch);#endif spin_lock_irqsave(&info->slock, flags); cp = &info->channel; if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room == 0) info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); if (tty->stopped || tty->hw_stopped || info->xmit_fifo_room == 0 || info->xmit_cnt != 0) { info->xmit_buf[info->xmit_head++] = ch; info->xmit_head &= XMIT_BUF_SIZE - 1; info->xmit_cnt++; set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); } else { sOutB(sGetTxRxDataIO(cp), ch); info->xmit_fifo_room--; } spin_unlock_irqrestore(&info->slock, flags); up(&info->write_sem);}/* * Exception handler - write routine, called when user app writes to the device. * A per port write semaphore is used to protect from another process writing to * this port at the same time. This other process could be running on the other CPU * or get control of the CPU if the copy_from_user() blocks due to a page fault (swapped out). * Spinlocks protect the info xmit members. */static int rp_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count){ struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; const unsigned char *b; int c, retval = 0; unsigned long flags; if (count <= 0 || rocket_paranoia_check(info, "rp_write")) return 0; down_interruptible(&info->write_sem);#ifdef ROCKET_DEBUG_WRITE printk(KERN_INFO "rp_write %d chars...", count);#endif cp = &info->channel; if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room < count) info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); /* * If the write queue for the port is empty, and there is FIFO space, stuff bytes * into FIFO. Use the write queue for temp storage. */ if (!tty->stopped && !tty->hw_stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) { c = min(count, info->xmit_fifo_room); b = buf; if (from_user) { if (copy_from_user(info->xmit_buf, buf, c)) { retval = -EFAULT; goto end; } if (info->tty == 0) goto end; b = info->xmit_buf; c = min(c, info->xmit_fifo_room); } /* Push data into FIFO, 2 bytes at a time */ sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) b, c / 2); /* If there is a byte remaining, write it */ if (c & 1) sOutB(sGetTxRxDataIO(cp), b[c - 1]); retval += c; buf += c; count -= c; spin_lock_irqsave(&info->slock, flags); info->xmit_fifo_room -= c; spin_unlock_irqrestore(&info->slock, flags); } /* If count is zero, we wrote it all and are done */ if (!count) goto end; /* Write remaining data into the port's xmit_buf */ while (1) { if (info->tty == 0) /* Seemingly obligatory check... */ goto end; c = min(count, min(XMIT_BUF_SIZE - info->xmit_cnt - 1, XMIT_BUF_SIZE - info->xmit_head)); if (c <= 0) break; b = buf; if (from_user) { if (copy_from_user(info->xmit_buf + info->xmit_head, b, c)) { retval = -EFAULT; goto end_intr; } else { memcpy(info->xmit_buf + info->xmit_head, b, c); } } spin_lock_irqsave(&info->slock, flags); info->xmit_head = (info->xmit_head + c) & (XMIT_BUF_SIZE - 1); info->xmit_cnt += c; spin_unlock_irqrestore(&info->slock, flags); buf += c; count -= c; retval += c; }end_intr: if ((retval > 0) && !tty->stopped && !tty->hw_stopped) set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); end: if (info->xmit_cnt < WAKEUP_CHARS) { tty_wakeup(tty); wake_up_interruptible(&tty->write_wait);#ifdef ROCKETPORT_HAVE_POLL_WAIT wake_up_interruptible(&tty->poll_wait);#endif } up(&info->write_sem); return retval;}/* * Return the number of characters that can be sent. We estimate * only using the in-memory transmit buffer only, and ignore the * potential space in the transmit FIFO. */static int rp_write_room(struct tty_struct *tty){ struct r_port *info = (struct r_port *) tty->driver_data; int ret; if (rocket_paranoia_check(info, "rp_write_room")) return 0; ret = XMIT_BUF_SIZE - info->xmit_cnt - 1; if (ret < 0) ret = 0;#ifdef ROCKET_DEBUG_WRITE printk(KERN_INFO "rp_write_room returns %d...", ret);#endif return ret;}/* * Return the number of characters in the buffer. Again, this only * counts those characters in the in-memory transmit buffer. */static int rp_chars_in_buffer(struct tty_struct *tty){ struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; if (rocket_paranoia_check(info, "rp_chars_in_buffer")) return 0; cp = &info->channel;#ifdef ROCKET_DEBUG_WRITE printk(KERN_INFO "rp_chars_in_buffer returns %d...", info->xmit_cnt);#endif return info->xmit_cnt;}/* * Flushes the TX fifo for a port, deletes data in the xmit_buf stored in the * r_port struct for the port. Note that spinlock are used to protect info members, * do not call this function if the spinlock is already held. */static void rp_flush_buffer(struct tty_struct *tty){ struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; unsigned long flags; if (rocket_paranoia_check(info, "rp_flush_buffer")) return; spin_lock_irqsave(&info->slock, flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; spin_unlock_irqrestore(&info->slock, flags); wake_up_interruptible(&tty->write_wait);#ifdef ROCKETPORT_HAVE_POLL_WAIT wake_up_interruptible(&tty->poll_wait);#endif tty_wakeup(tty); cp = &info->channel; sFlushTxFIFO(cp);}#ifdef CONFIG_PCI/* * Called when a PCI card is found. Retrieves and stores model information, * init's aiopic and serial port hardware. * Inputs: i is the board number (0-n) */__init int register_PCI(int i, struct pci_dev *dev){ int num_aiops, aiop, max_num_aiops, num_chan, chan; unsigned int aiopio[MAX_AIOPS_PER_BOARD]; char *str, *board_type; CONTROLLER_t *ctlp; int fast_clock = 0; int altChanRingIndicator = 0; int ports_per_aiop = 8; int ret; unsigned int class_rev; WordIO_t ConfigIO = 0; ByteIO_t UPCIRingInd = 0; if (!dev || pci_enable_device(dev)) return 0; rcktpt_io_addr[i] = pci_resource_start(dev, 0); ret = pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); if (ret) { printk(KERN_INFO " Error during register_PCI(), unable to read config dword \n"); return 0; } rcktpt_type[i] = ROCKET_TYPE_NORMAL; rocketModel[i].loadrm2 = 0; rocketModel[i].startingPortNumber = nextLineNumber; /* Depending on the model, set up some config variables */ switch (dev->device) { case PCI_DEVICE_ID_RP4QUAD: str = "Quadcable"; max_num_aiops = 1; ports_per_aiop = 4; rocketModel[i].model = MODEL_RP4QUAD; strcpy(rocketModel[i].modelString, "RocketPort 4 port w/quad cable"); rocketModel[i].numPorts = 4; break; case PCI_DEVICE_ID_RP8OCTA: str = "Octacable"; max_num_aiops = 1; rocketModel[i].model = MODEL_RP8OCTA; strcpy(rocketModel[i].modelString, "RocketPort 8 port w/octa cable"); rocketModel[i].numPorts = 8; break; case PCI_DEVICE_ID_URP8OCTA: str = "Octacable"; max_num_aiops = 1; rocketModel[i].model = MODEL_UPCI_RP8OCTA; strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/octa cable"); rocketModel[i].numPorts = 8; break; case PCI_DEVICE_ID_RP8INTF: str = "8"; max_num_aiops = 1; rocketModel[i].model = MODEL_RP8INTF; strcpy(rocketModel[i].modelString, "RocketPort 8 port w/external I/F"); rocketModel[i].numPorts = 8; break; case PCI_DEVICE_ID_URP8INTF: str = "8"; max_num_aiops = 1; rocketModel[i].model = MODEL_UPCI_RP8INTF; strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/external I/F"); rocketModel[i].numPorts = 8; break; case PCI_DEVICE_ID_RP8J: str = "8J"; max_num_aiops = 1; rocketModel[i].model = MODEL_RP8J; strcpy(rocketModel[i].modelString, "RocketPort 8 port w/RJ11 connectors"); rocketModel[i].numPorts = 8; break; case PCI_DEVICE_ID_RP4J:
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?