📄 rocket.c
字号:
printk("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("CTS change...\n"); } if (IntMask & DELTA_DSR) { /* DSR change */ printk("DSR change...\n"); }#endif}/* * The top level polling routine. */static void rp_do_poll(void){ CONTROLLER_t *ctlp; int ctrl, aiop, ch, line; unsigned int xmitmask; unsigned char CtlMask, AiopMask;#ifdef TIME_STAT unsigned long low=0, high=0, loop_time; unsigned long long time_stat_tmp=0, time_stat_tmp2=0; __asm__(".byte 0x0f,0x31" :"=a" (low), "=d" (high)); time_stat_tmp = high; time_stat_tmp <<= 32; time_stat_tmp += low;#endif /* TIME_STAT */ for (ctrl=0; ctrl < max_board; ctrl++) { if (rcktpt_io_addr[ctrl] <= 0) continue; ctlp= sCtlNumToCtlPtr(ctrl);#ifdef ENABLE_PCI if(ctlp->BusType == isPCI) CtlMask= sPCIGetControllerIntStatus(ctlp); else#endif CtlMask= sGetControllerIntStatus(ctlp); for (aiop=0; CtlMask; CtlMask >>= 1, aiop++) { if (CtlMask & 1) { AiopMask= sGetAiopIntStatus(ctlp, aiop); for (ch=0; AiopMask; AiopMask >>= 1, ch++) { if (AiopMask & 1) { line = (ctrl << 5) | (aiop << 3) | ch; rp_handle_port(rp_table[line]); } } } } xmitmask = xmit_flags[ctrl]; for (line = ctrl << 5; xmitmask; xmitmask >>= 1, line++) { if (xmitmask & 1) rp_do_transmit(rp_table[line]); } } /* * Reset the timer so we get called at the next clock tick. */ if (rp_num_ports_open) { timer_active |= 1 << COMTROL_TIMER; }#ifdef TIME_STAT __asm__(".byte 0x0f,0x31" :"=a" (low), "=d" (high)); time_stat_tmp2 = high; time_stat_tmp2 <<= 32; time_stat_tmp2 += low; time_stat_tmp2 -= time_stat_tmp; time_stat += time_stat_tmp2; if (time_counter == 0) time_stat_short = time_stat_long = time_stat_tmp2; else { if ( time_stat_tmp2 < time_stat_short ) time_stat_short = time_stat_tmp2; else if ( time_stat_tmp2 > time_stat_long ) time_stat_long = time_stat_tmp2; } if ( ++time_counter == TIME_COUNTER ) { loop_time = (unsigned long) ( ((unsigned long)(time_stat >> 32) * ( (unsigned long)(0xffffffff)/(TIME_STAT_CPU * TIME_COUNTER) ) ) + ((unsigned long)time_stat/(TIME_STAT_CPU*TIME_COUNTER)));#ifdef TIME_STAT_VERBOSE printk("rp_do_poll: Interrupt Timings\n"); printk(" %5ld iterations; %ld us min,\n", (long)TIME_COUNTER, (time_stat_short/TIME_STAT_CPU)); printk(" %5ld us max, %ld us average per iteration.\n", (time_stat_long/TIME_STAT_CPU), loop_time); printk("We want to use < 5,000 us for an iteration.\n");#else /* TIME_STAT_VERBOSE */ printk("rp: %ld loops: %ld min, %ld max, %ld us/loop.\n", (long)TIME_COUNTER, (time_stat_short/TIME_STAT_CPU), (time_stat_long/TIME_STAT_CPU), loop_time);#endif /* TIME_STAT_VERBOSE */ time_counter = time_stat = 0; time_stat_short = time_stat_long = 0; }#endif /* TIME_STAT */}/* * Here ends the interrupt/polling routine. *//* * This function initializes the r_port structure, as well as enabling * the port on the RocketPort board. */static void init_r_port(int board, int aiop, int chan){ struct r_port *info; int line; CONTROLLER_T *ctlp; CHANNEL_t *cp; line = (board << 5) | (aiop << 3) | chan; ctlp= sCtlNumToCtlPtr(board); info = kmalloc(sizeof(struct r_port), GFP_KERNEL); if (!info) { printk("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; info->callout_termios =callout_driver.init_termios; info->normal_termios = rocket_driver.init_termios; info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR; if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) { printk("Rocketport sInitChan(%d, %d, %d) failed!\n", board, aiop, chan); kfree(info); return; } cp = &info->channel; rp_table[line] = info;}#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */static int baud_table[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };#endif/* * This routine configures a rocketport port so according to its * termio settings. */static void configure_r_port(struct r_port *info){ unsigned cflag; unsigned long flags; int bits, baud;#if (LINUX_VERSION_CODE < 131393) /* Linux 2.1.65 */ int i;#endif 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 */#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ i = cflag & CBAUD; if (i & CBAUDEX) { i &= ~CBAUDEX; if (i < 1 || i > 4) info->tty->termios->c_cflag &= ~CBAUDEX; else i += 15; } if (i == 15) { if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI) i += 1; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI) i += 2; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI) i += 3; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP) i += 4; } baud = baud_table[i] ? baud_table[i] : 9600;#else baud = tty_get_baud_rate(info->tty); if (!baud) baud = 9600;#endif info->cps = baud / bits; sSetBaud(cp, (rp_baud_base/baud) - 1); if (cflag & CRTSCTS) { info->intmask |= DELTA_CTS; sEnCTSFlowCtl(cp); } else { info->intmask &= ~DELTA_CTS; sDisCTSFlowCtl(cp); } sSetRTS(&info->channel); if (cflag & CLOCAL) info->intmask &= ~DELTA_CD; else { save_flags(flags); cli(); if (sGetChanStatus(cp) & CD_ACT) info->cd_status = 1; else info->cd_status = 0; info->intmask |= DELTA_CD; restore_flags(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; }}static int block_til_ready(struct tty_struct *tty, struct file * filp, struct r_port *info){ struct wait_queue wait = { current, NULL }; 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 this is a callout device, then just make sure the normal * device isn't being used. */ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { if (info->flags & ROCKET_NORMAL_ACTIVE) return -EBUSY; if ((info->flags & ROCKET_CALLOUT_ACTIVE) && (info->flags & ROCKET_SESSION_LOCKOUT) && (info->session != current->session)) return -EBUSY; if ((info->flags & ROCKET_CALLOUT_ACTIVE) && (info->flags & ROCKET_PGRP_LOCKOUT) && (info->pgrp != current->pgrp)) return -EBUSY; info->flags |= ROCKET_CALLOUT_ACTIVE; return 0; } /* * 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))) { if (info->flags & ROCKET_CALLOUT_ACTIVE) return -EBUSY; info->flags |= ROCKET_NORMAL_ACTIVE; return 0; } if (info->flags & ROCKET_CALLOUT_ACTIVE) { if (info->normal_termios.c_cflag & CLOCAL) do_clocal = 1; } else { if (tty->termios->c_cflag & CLOCAL) do_clocal = 1; } /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). 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("block_til_ready before block: ttyR%d, count = %d\n", info->line, info->count);#endif save_flags(flags); cli(); if (!tty_hung_up_p(filp)) { extra_count = 1; info->count--; } restore_flags(flags); info->blocked_open++; while (1) { if (!(info->flags & ROCKET_CALLOUT_ACTIVE) && (tty->termios->c_cflag & CBAUD)) { sSetDTR(&info->channel); sSetRTS(&info->channel); } 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_CALLOUT_ACTIVE) && !(info->flags & ROCKET_CLOSING) && (do_clocal || (sGetChanStatusLo(&info->channel) & CD_ACT))) break; if (signal_pending(current)) { retval = -ERESTARTSYS; break; }#ifdef ROCKET_DEBUG_OPEN printk("block_til_ready blocking: ttyR%d, count = %d, flags=0x%0x\n", info->line, info->count, info->flags);#endif schedule(); } current->state = TASK_RUNNING; remove_wait_queue(&info->open_wait, &wait); cli(); if (extra_count) info->count++; restore_flags(flags); info->blocked_open--;#ifdef ROCKET_DEBUG_OPEN printk("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;} /* * This routine is called whenever a rocketport board is opened. */static int rp_open(struct tty_struct *tty, struct file * filp){ struct r_port *info; int line, retval; CHANNEL_t *cp; unsigned long page; line = MINOR(tty->device) - tty->driver.minor_start; if ((line < 0) || (line >= MAX_RP_PORTS)) return -ENODEV; if (!tmp_buf) { page = get_free_page(GFP_KERNEL); if (!page) return -ENOMEM; if (tmp_buf) free_page(page); else tmp_buf = (unsigned char *) page; } page = get_free_page(GFP_KERNEL); if (!page) return -ENOMEM; tty->driver_data = info = rp_table[line]; 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 (rp_table[line] == NULL) { tty->flags = (1 << TTY_IO_ERROR); free_page(page); return 0; } if (!info) { printk("rp_open: rp_table[%d] is NULL!\n", line); free_page(page); return -EIO; } if (info->xmit_buf) free_page(page); else info->xmit_buf = (unsigned char *) page; info->tty = tty; if (info->flags & ROCKET_CLOSING) { interruptible_sleep_on(&info->close_wait); return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); } if (info->count++ == 0) {#ifdef MODULE MOD_INC_USE_COUNT;#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -