📄 rocket.c
字号:
rp_num_ports_open++;#ifdef ROCKET_DEBUG_OPEN printk("rocket mod++ = %d...", rp_num_ports_open);#endif }#ifdef ROCKET_DEBUG_OPEN printk("rp_open ttyR%d, count=%d\n", info->line, info->count);#endif /* * Info->count is now 1; so it's safe to sleep now. */ info->session = current->session; info->pgrp = current->pgrp; cp = &info->channel; sSetRxTrigger(cp, TRIG_1); if (sGetChanStatus(cp) & CD_ACT) info->cd_status = 1; else info->cd_status = 0; sDisRxStatusMode(cp); sFlushRxFIFO(cp); sFlushTxFIFO(cp); sEnInterrupts(cp, (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN)); sSetRxTrigger(cp, TRIG_1); sGetChanStatus(cp); sDisRxStatusMode(cp); sClrTxXOFF(cp); sDisCTSFlowCtl(cp); sDisTxSoftFlowCtl(cp); sEnRxFIFO(cp); sEnTransmit(cp); info->flags |= ROCKET_INITIALIZED;#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ /* * Set up the tty->alt_speed kludge */ if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI) info->tty->alt_speed = 57600; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI) info->tty->alt_speed = 115200; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI) info->tty->alt_speed = 230400; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP) info->tty->alt_speed = 460800;#endif configure_r_port(info); if (tty->termios->c_cflag & CBAUD) { sSetDTR(cp); sSetRTS(cp); } timer_active |= 1 << COMTROL_TIMER; retval = block_til_ready(tty, filp, info); if (retval) {#ifdef ROCKET_DEBUG_OPEN printk("rp_open returning after block_til_ready with %d\n", retval);#endif return retval; } if ((info->count == 1) && (info->flags & ROCKET_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) *tty->termios = info->normal_termios; else *tty->termios = info->callout_termios; configure_r_port(info); } return 0;}static void rp_close(struct tty_struct *tty, struct file * filp){ struct r_port * info = (struct r_port *)tty->driver_data; unsigned long flags; int timeout; CHANNEL_t *cp; if (rocket_paranoia_check(info, tty->device, "rp_close")) return;#ifdef ROCKET_DEBUG_OPEN printk("rp_close ttyR%d, count = %d\n", info->line, info->count);#endif save_flags(flags); cli(); if (tty_hung_up_p(filp)) { restore_flags(flags); return; } if ((tty->count == 1) && (info->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. Info->count should always * be one in these conditions. If it's greater than * one, we've got real problems, since it means the * serial port won't be shutdown. */ printk("rp_close: bad serial port count; tty->count is 1, " "info->count is %d\n", info->count); info->count = 1; } if (--info->count < 0) { printk("rp_close: bad serial port count for ttyR%d: %d\n", info->line, info->count); info->count = 0; } if (info->count) { restore_flags(flags); return; } info->flags |= ROCKET_CLOSING; /* * Save the termios structure, since this port may have * separate termios for callout and dialin. */ if (info->flags & ROCKET_NORMAL_ACTIVE) info->normal_termios = *tty->termios; if (info->flags & ROCKET_CALLOUT_ACTIVE) info->callout_termios = *tty->termios; cp = &info->channel; /* * Notify the line discpline to only process XON/XOFF characters */ tty->closing = 1; /* * If transmission was throttled by the application request, * just flush the xmit buffer. */#if (LINUX_VERSION_CODE >= 131343) if (tty->flow_stopped) rp_flush_buffer(tty);#endif /* * Wait for the transmit buffer to clear */ if (info->closing_wait != ROCKET_CLOSING_WAIT_NONE) tty_wait_until_sent(tty, info->closing_wait); /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially * important if there is a transmit FIFO! */ timeout = (sGetTxCnt(cp)+1) * HZ / info->cps; if (timeout == 0) timeout = 1; rp_wait_until_sent(tty, timeout); xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f)); sDisTransmit(cp); sDisInterrupts(cp, (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN)); sDisCTSFlowCtl(cp); sDisTxSoftFlowCtl(cp); sClrTxXOFF(cp); sFlushRxFIFO(cp); sFlushTxFIFO(cp); sClrRTS(cp); if (C_HUPCL(tty)) { sClrDTR(cp); } if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f)); if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); } else { if (info->xmit_buf) { free_page((unsigned long) info->xmit_buf); info->xmit_buf = 0; } } info->flags &= ~(ROCKET_INITIALIZED | ROCKET_CLOSING | ROCKET_CALLOUT_ACTIVE | ROCKET_NORMAL_ACTIVE); tty->closing = 0; wake_up_interruptible(&info->close_wait); #ifdef MODULE MOD_DEC_USE_COUNT;#endif rp_num_ports_open--;#ifdef ROCKET_DEBUG_OPEN printk("rocket mod-- = %d...", rp_num_ports_open);#endif restore_flags(flags); #ifdef ROCKET_DEBUG_OPEN printk("rp_close ttyR%d complete shutdown\n", info->line);#endif }static void rp_set_termios(struct tty_struct *tty, struct termios *old_termios){ struct r_port * info = (struct r_port *)tty->driver_data; CHANNEL_t *cp; unsigned cflag; if (rocket_paranoia_check(info, tty->device, "rp_set_termios")) return; cflag = tty->termios->c_cflag; if (cflag == old_termios->c_cflag) return; /* * This driver doesn't support CS5 or CS6 */ if (((cflag & CSIZE) == CS5) || ((cflag & CSIZE) == CS6)) tty->termios->c_cflag = ((cflag & ~CSIZE) | (old_termios->c_cflag & CSIZE)); configure_r_port(info); cp = &info->channel; /* Handle transition to B0 status */ if ((old_termios->c_cflag & CBAUD) && !(tty->termios->c_cflag & CBAUD)) { sClrDTR(cp); sClrRTS(cp); } /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && (tty->termios->c_cflag & CBAUD)) { if (!tty->hw_stopped || !(tty->termios->c_cflag & CRTSCTS)) { sSetRTS(cp); } sSetDTR(cp); } if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { tty->hw_stopped = 0; rp_start(tty); }}/* * Here are the routines used by rp_ioctl */#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */static void send_break( struct r_port * info, int duration){ current->state = TASK_INTERRUPTIBLE; cli(); sSendBreak(&info->channel); schedule_timeout(duration); sClrBreak(&info->channel); sti();}#elsestatic void rp_break(struct tty_struct *tty, int break_state){ struct r_port * info = (struct r_port *)tty->driver_data; unsigned long flags; if (rocket_paranoia_check(info, tty->device, "rp_break")) return; save_flags(flags); cli(); if (break_state == -1) { sSendBreak(&info->channel); } else { sClrBreak(&info->channel); } restore_flags(flags);}#endifstatic int get_modem_info(struct r_port * info, unsigned int *value){ unsigned int control, result, ChanStatus; ChanStatus = sGetChanStatusLo(&info->channel); control = info->channel.TxControl[3]; result = ((control & SET_RTS) ? TIOCM_RTS : 0) | ((control & SET_DTR) ? TIOCM_DTR : 0) | ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0) /* TIOCM_RNG not supported */ | ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0) | ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0); if (copy_to_user(value, &result, sizeof(int))) return -EFAULT; return 0;}static int set_modem_info(struct r_port * info, unsigned int cmd, unsigned int *value){ unsigned int arg; if (copy_from_user(&arg, value, sizeof(int))) return -EFAULT; switch (cmd) { case TIOCMBIS: if (arg & TIOCM_RTS) info->channel.TxControl[3] |= SET_RTS; if (arg & TIOCM_DTR) info->channel.TxControl[3] |= SET_DTR; break; case TIOCMBIC: if (arg & TIOCM_RTS) info->channel.TxControl[3] &= ~SET_RTS; if (arg & TIOCM_DTR) info->channel.TxControl[3] &= ~SET_DTR; break; case TIOCMSET: info->channel.TxControl[3] = ((info->channel.TxControl[3] & ~(SET_RTS | SET_DTR)) | ((arg & TIOCM_RTS) ? SET_RTS : 0) | ((arg & TIOCM_DTR) ? SET_DTR : 0)); break; default: return -EINVAL; } sOutDW(info->channel.IndexAddr, *(DWord_t *) &(info->channel.TxControl[0])); return 0;}static int get_config(struct r_port * info, struct rocket_config * retinfo){ struct rocket_config tmp; if (!retinfo) return -EFAULT; memset(&tmp, 0, sizeof(tmp)); tmp.line = info->line; tmp.flags = info->flags; tmp.close_delay = info->close_delay; tmp.closing_wait = info->closing_wait; tmp.port = rcktpt_io_addr[(info->line >> 5) & 3]; if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) return -EFAULT; return 0;}static int set_config(struct r_port * info, struct rocket_config * new_info){ struct rocket_config new_serial; if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) return -EFAULT;#ifdef CAP_SYS_ADMIN if (!capable(CAP_SYS_ADMIN))#else if (!suser())#endif { if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK)) return -EPERM; info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK)); configure_r_port(info); return 0; } info->flags = ((info->flags & ~ROCKET_FLAGS) | (new_serial.flags & ROCKET_FLAGS)); info->close_delay = new_serial.close_delay; info->closing_wait = new_serial.closing_wait;#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI) info->tty->alt_speed = 57600; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI) info->tty->alt_speed = 115200; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI) info->tty->alt_speed = 230400; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP) info->tty->alt_speed = 460800;#endif configure_r_port(info); return 0;}static int get_ports(struct r_port * info, struct rocket_ports * retports){ struct rocket_ports tmp; int board, port, index; if (!retports) return -EFAULT; memset(&tmp, 0, sizeof(tmp)); tmp.tty_major = rocket_driver.major; tmp.callout_major = callout_driver.major; for (board = 0; board < 4; board++) { index = board << 5; for (port = 0; port < 32; port++, index++) { if (rp_table[index]) tmp.port_bitmap[board] |= 1 << port; } } if (copy_to_user(retports,&tmp,sizeof(*retports))) return -EFAULT; return 0;}static int rp_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg){ struct r_port * info = (struct r_port *)tty->driver_data;#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ int retval, tmp;#endif if (cmd != RCKP_GET_PORTS && rocket_paranoia_check(info, tty->device, "rp_ioctl")) return -ENODEV; switch (cmd) {#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ case TCSBRK: /* SVID version: non-zero arg --> no break */ retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); if (signal_pending(current)) return -EINTR; if (!arg) { send_break(info, HZ/4); /* 1/4 second */ if (signal_pending(current)) return -EINTR; } return 0; case TCSBRKP: /* support for POSIX tcsendbreak() */ retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); if (signal_pending(current)) return -EINTR; send_break(info, arg ? arg*(HZ/10) : HZ/4); if (signal_pending(current)) return -EINTR; return 0; case TIOCGSOFTCAR: tmp = C_CLOCAL(tty) ? 1 : 0; if (copy_to_user((void *)arg, &tmp, sizeof(int))) return -EFAULT; return 0; case TIOCSSOFTCAR: if (copy_from_user(&tmp, (void *)arg, sizeof(int))) return -EFAULT; tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (tmp ? CLOCAL : 0)); return 0;#endif case TIOCMGET: return get_modem_info(info, (unsigned int *) arg); case TIOCMBIS: case TIOCMBIC: case TIOCMSET: return set_modem_info(info, cmd, (unsigned int *) arg); case RCKP_GET_STRUCT: if (copy_to_user((void *) arg, info, sizeof(struct r_port))) return -EFAULT; return 0; case RCKP_GET_CONFIG:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -