📄 rocket.c
字号:
return get_config(info, (struct rocket_config *) arg); case RCKP_SET_CONFIG: return set_config(info, (struct rocket_config *) arg); case RCKP_GET_PORTS: return get_ports(info, (struct rocket_ports *) arg); default: return -ENOIOCTLCMD; } return 0;}#if (defined(ROCKET_DEBUG_FLOW) || defined(ROCKET_DEBUG_THROTTLE))static char *rp_tty_name(struct tty_struct *tty, char *buf){ if (tty) sprintf(buf, "%s%d", tty->driver.name, MINOR(tty->device) - tty->driver.minor_start + tty->driver.name_base); else strcpy(buf, "NULL tty"); return buf;}#endifstatic void rp_send_xchar(struct tty_struct *tty, char ch){ struct r_port *info = (struct r_port *)tty->driver_data; CHANNEL_t *cp; if (rocket_paranoia_check(info, tty->device, "rp_send_xchar")) return; cp = &info->channel; if (sGetTxCnt(cp)) sWriteTxPrioByte(cp, ch); else sWriteTxByte(sGetTxRxDataIO(cp), ch);}static void rp_throttle(struct tty_struct * tty){ struct r_port *info = (struct r_port *)tty->driver_data; CHANNEL_t *cp;#ifdef ROCKET_DEBUG_THROTTLE char buf[64]; printk("throttle %s: %d....\n", rp_tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty));#endif if (rocket_paranoia_check(info, tty->device, "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 char buf[64]; printk("unthrottle %s: %d....\n", rp_tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty));#endif if (rocket_paranoia_check(info, tty->device, "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 char buf[64]; printk("stop %s: %d %d....\n", rp_tty_name(tty, buf), info->xmit_cnt, info->xmit_fifo_room);#endif if (rocket_paranoia_check(info, tty->device, "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 char buf[64]; printk("start %s: %d %d....\n", rp_tty_name(tty, buf), info->xmit_cnt, info->xmit_fifo_room);#endif if (rocket_paranoia_check(info, tty->device, "rp_stop")) return; sEnTransmit(&info->channel); xmit_flags[info->line >> 5] |= (1 << (info->line & 0x1f));}/* * 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, tty->device, "rp_wait_until_sent")) return; cp = &info->channel; orig_jiffies = jiffies;#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT printk("In RP_wait_until_sent(%d) (jiff=%lu)...", timeout, jiffies); printk("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("txcnt = %d (jiff=%lu,check=%d)...", txcnt, jiffies, check_time);#endif current->state = TASK_INTERRUPTIBLE; current->counter = 0; /* make us low-priority */ schedule_timeout(check_time); if (signal_pending(current)) break; } current->state = TASK_RUNNING;#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT printk("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, tty->device, "rp_hangup")) return;#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_HANGUP)) printk("rp_hangup of ttyR%d...", info->line);#endif /* * If the port is in the process of being closed, just force * the transmit buffer to be empty, and let rp_close handle * the clean up. */ if (info->flags & ROCKET_CLOSING) { cli(); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; sti(); wake_up_interruptible(&tty->write_wait); return; } if (info->count) {#ifdef MODULE MOD_DEC_USE_COUNT;#endif rp_num_ports_open--; } xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f)); info->count = 0; info->flags &= ~(ROCKET_NORMAL_ACTIVE|ROCKET_CALLOUT_ACTIVE); info->tty = 0; 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);}/* * The Rocketport write routines. 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. * * This gets a little tricky, but I'm pretty sure I got it all right. */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; if (rocket_paranoia_check(info, tty->device, "rp_put_char")) return;#ifdef ROCKET_DEBUG_WRITE printk("rp_put_char %c...", ch);#endif 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++; xmit_flags[info->line >> 5] |= (1 << (info->line & 0x1f)); } else { sOutB(sGetTxRxDataIO(cp), ch); info->xmit_fifo_room--; }}#if (LINUX_VERSION_CODE > 66304)static int rp_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count)#elsestatic int rp_write(struct tty_struct * tty, int from_user, unsigned char *buf, int count)#endif { 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, tty->device, "rp_write")) return 0;#ifdef ROCKET_DEBUG_WRITE printk("rp_write %d chars...", count);#endif 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_cnt == 0 && info->xmit_fifo_room >= 0) { c = MIN(count, info->xmit_fifo_room); b = buf; if (from_user) { down(&tmp_buf_sem); c -= copy_from_user(tmp_buf, buf, c); b = tmp_buf; up(&tmp_buf_sem); /* In case we got pre-empted */ if (!c) { retval = -EFAULT; goto end; } if (info->tty == 0) goto end; c = MIN(c, info->xmit_fifo_room); } sOutStrW(sGetTxRxDataIO(cp), b, c/2); if (c & 1) sOutB(sGetTxRxDataIO(cp), b[c-1]); retval += c; buf += c; count -= c; info->xmit_fifo_room -= c; } if (!count) goto end; save_flags(flags); while (1) { if (info->tty == 0) { restore_flags(flags); 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) { down(&tmp_buf_sem); c -= copy_from_user(tmp_buf, buf, c); b = tmp_buf; up(&tmp_buf_sem); if (!c) { if (retval == 0) retval = -EFAULT; goto end_intr; } /* In case we got pre-empted */ if (info->tty == 0) goto end_intr; } cli(); c = MIN(c, MIN(XMIT_BUF_SIZE - info->xmit_cnt - 1, XMIT_BUF_SIZE - info->xmit_head)); memcpy(info->xmit_buf + info->xmit_head, b, c); info->xmit_head = (info->xmit_head + c) & (XMIT_BUF_SIZE-1); info->xmit_cnt += c; restore_flags(flags); buf += c; count -= c; retval += c; }end_intr: if ((retval > 0) && !tty->stopped && !tty->hw_stopped) xmit_flags[info->line >> 5] |= (1 << (info->line & 0x1f)); restore_flags(flags);end: if (info->xmit_cnt < WAKEUP_CHARS) { if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait); } 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, tty->device, "rp_write_room")) return 0; ret = XMIT_BUF_SIZE - info->xmit_cnt - 1; if (ret < 0) ret = 0;#ifdef ROCKET_DEBUG_WRITE printk("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, tty->device, "rp_chars_in_buffer")) return 0; cp = &info->channel;#ifdef ROCKET_DEBUG_WRITE printk("rp_chars_in_buffer returns %d...", info->xmit_cnt);#endif return info->xmit_cnt;}static void rp_flush_buffer(struct tty_struct *tty){ struct r_port * info = (struct r_port *)tty->driver_data; CHANNEL_t *cp; if (rocket_paranoia_check(info, tty->device, "rp_flush_buffer")) return; cli(); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; sti(); wake_up_interruptible(&tty->write_wait); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); cp = &info->channel; sFlushTxFIFO(cp);}#ifdef ENABLE_PCI#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 *//* For compatibility */static struct pci_dev *pci_find_slot(unsigned char bus, unsigned char device_fn){ unsigned short vendor_id, device_id; int ret, error; static struct pci_dev ret_struct; error = pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID, &vendor_id); ret = pcibios_read_config_word(bus, device_fn, PCI_DEVICE_ID, &device_id); if (error == 0) error = ret; if (error) { printk("PCI RocketPort error: %s not initializing due to error" "reading configuration space\n", pcibios_strerror(error)); return(0); } memset(&ret_struct, 0, sizeof(ret_struct)); ret_struct.device = device_id; return &ret_struct;}#endif __initfunc(int register_PCI(int i, unsigned int bus, unsigned int device_fn)){ int num_aiops, aiop, max_num_aiops, num_chan, chan; unsigned int aiopio[MAX_AIOPS_PER_BOARD]; char *str; CONTROLLER_t *ctlp; struct pci_dev *dev = pci_find_slot(bus, device_fn);#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */ int ret; unsigned int port;#endif if (!dev) return 0;#if (LINUX_VERSION_CODE >= 0x020163) /* 2.1.99 */ rcktpt_io_addr[i] = dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;#else ret = pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0, &port); if (ret) return 0; rcktpt_io_addr[i] = port & PCI_BASE_ADDRESS_IO_MASK;#endif switch(dev->device) { case PCI_DEVICE_ID_RP4QUAD: str = "Quadcable"; max_num_aiops = 1; break; case PCI_DEVICE_ID_RP8OCTA: str = "Octacable"; max_num_aiops = 1; break; case PCI_DEVICE_ID_RP8INTF: str = "8";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -