rocket.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,368 行 · 第 1/5 页
C
2,368 行
#ifdef ROCKET_DEBUG_OPEN printk(KERN_INFO "rocket mod++ = %d...", atomic_read(&rp_num_ports_open));#endif }#ifdef ROCKET_DEBUG_OPEN printk(KERN_INFO "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->signal->session; info->pgrp = process_group(current); if ((info->flags & ROCKET_INITIALIZED) == 0) { 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; /* * 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; configure_r_port(info, NULL); if (tty->termios->c_cflag & CBAUD) { sSetDTR(cp); sSetRTS(cp); } } /* Starts (or resets) the maint polling loop */ mod_timer(&rocket_timer, jiffies + POLL_PERIOD); retval = block_til_ready(tty, filp, info); if (retval) {#ifdef ROCKET_DEBUG_OPEN printk(KERN_INFO "rp_open returning after block_til_ready with %d\n", retval);#endif return retval; } return 0;}/* * Exception handler that closes a serial port. info->count is considered critical. */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, "rp_close")) return;#ifdef ROCKET_DEBUG_OPEN printk(KERN_INFO "rp_close ttyR%d, count = %d\n", info->line, info->count);#endif if (tty_hung_up_p(filp)) return; spin_lock_irqsave(&info->slock, flags); 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(KERN_INFO "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(KERN_INFO "rp_close: bad serial port count for ttyR%d: %d\n", info->line, info->count); info->count = 0; } if (info->count) { spin_unlock_irqrestore(&info->slock, flags); return; } info->flags |= ROCKET_CLOSING; spin_unlock_irqrestore(&info->slock, flags); 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 (tty->flow_stopped) rp_flush_buffer(tty); /* * 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); clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); 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_EXISTS(tty)) TTY_DRIVER_FLUSH_BUFFER(tty); tty_ldisc_flush(tty); clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); 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 = NULL; } } info->flags &= ~(ROCKET_INITIALIZED | ROCKET_CLOSING | ROCKET_NORMAL_ACTIVE); tty->closing = 0; wake_up_interruptible(&info->close_wait); atomic_dec(&rp_num_ports_open);#ifdef ROCKET_DEBUG_OPEN printk(KERN_INFO "rocket mod-- = %d...", atomic_read(&rp_num_ports_open)); printk(KERN_INFO "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, "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, old_termios); 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); }}static 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, "rp_break")) return; spin_lock_irqsave(&info->slock, flags); if (break_state == -1) sSendBreak(&info->channel); else sClrBreak(&info->channel); spin_unlock_irqrestore(&info->slock, flags);}/* * sGetChanRI used to be a macro in rocket_int.h. When the functionality for * the UPCI boards was added, it was decided to make this a function because * the macro was getting too complicated. All cases except the first one * (UPCIRingInd) are taken directly from the original macro. */static int sGetChanRI(CHANNEL_T * ChP){ CONTROLLER_t *CtlP = ChP->CtlP; int ChanNum = ChP->ChanNum; int RingInd = 0; if (CtlP->UPCIRingInd) RingInd = !(sInB(CtlP->UPCIRingInd) & sBitMapSetTbl[ChanNum]); else if (CtlP->AltChanRingIndicator) RingInd = sInB((ByteIO_t) (ChP->ChanStat + 8)) & DSR_ACT; else if (CtlP->boardType == ROCKET_TYPE_PC104) RingInd = !(sInB(CtlP->AiopIO[3]) & sBitMapSetTbl[ChanNum]); return RingInd;}/********************************************************************************************//* Here are the routines used by rp_ioctl. These are all called from exception handlers. *//* * Returns the state of the serial modem control lines. These next 2 functions * are the way kernel versions > 2.5 handle modem control lines rather than IOCTLs. */static int rp_tiocmget(struct tty_struct *tty, struct file *file){ struct r_port *info = (struct r_port *)tty->driver_data; 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) | (sGetChanRI(&info->channel) ? TIOCM_RNG : 0) | ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0) | ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0); return result;}/* * Sets the modem control lines */static int rp_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear){ struct r_port *info = (struct r_port *)tty->driver_data; if (set & TIOCM_RTS) info->channel.TxControl[3] |= SET_RTS; if (set & TIOCM_DTR) info->channel.TxControl[3] |= SET_DTR; if (clear & TIOCM_RTS) info->channel.TxControl[3] &= ~SET_RTS; if (clear & TIOCM_DTR) info->channel.TxControl[3] &= ~SET_DTR; sOutDW(info->channel.IndexAddr, *(DWord_t *) & (info->channel.TxControl[0])); return 0;}static int get_config(struct r_port *info, struct rocket_config __user *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 __user *new_info){ struct rocket_config new_serial; if (copy_from_user(&new_serial, new_info, sizeof (new_serial))) return -EFAULT; if (!capable(CAP_SYS_ADMIN)) { 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, NULL); 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 ((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; configure_r_port(info, NULL); return 0;}/* * This function fills in a rocket_ports struct with information * about what boards/ports are in the system. This info is passed * to user space. See setrocket.c where the info is used to create * the /dev/ttyRx ports. */static int get_ports(struct r_port *info, struct rocket_ports __user *retports){ struct rocket_ports tmp; int board; if (!retports) return -EFAULT; memset(&tmp, 0, sizeof (tmp)); tmp.tty_major = rocket_driver->major; for (board = 0; board < 4; board++) { tmp.rocketModel[board].model = rocketModel[board].model; strcpy(tmp.rocketModel[board].modelString, rocketModel[board].modelString); tmp.rocketModel[board].numPorts = rocketModel[board].numPorts; tmp.rocketModel[board].loadrm2 = rocketModel[board].loadrm2; tmp.rocketModel[board].startingPortNumber = rocketModel[board].startingPortNumber; } if (copy_to_user(retports, &tmp, sizeof (*retports))) return -EFAULT; return 0;}static int reset_rm2(struct r_port *info, void __user *arg){ int reset; if (copy_from_user(&reset, arg, sizeof (int))) return -EFAULT; if (reset) reset = 1; if (rcktpt_type[info->board] != ROCKET_TYPE_MODEMII && rcktpt_type[info->board] != ROCKET_TYPE_MODEMIII) return -EINVAL; if (info->ctlp->BusType == isISA) sModemReset(info->ctlp, info->chan, reset); else sPCIModemReset(info->ctlp, info->chan, reset); return 0;}static int get_version(struct r_port *info, struct rocket_version __user *retvers){ if (copy_to_user(retvers, &driver_version, sizeof (*retvers))) return -EFAULT; return 0;}/* IOCTL call handler into the driver */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; void __user *argp = (void __user *)arg; if (cmd != RCKP_GET_PORTS && rocket_paranoia_check(info, "rp_ioctl")) return -ENXIO; switch (cmd) { case RCKP_GET_STRUCT: if (copy_to_user(argp, info, sizeof (struct r_port))) return -EFAULT; return 0; case RCKP_GET_CONFIG: return get_config(info, argp); case RCKP_SET_CONFIG: return set_config(info, argp); case RCKP_GET_PORTS: return get_ports(info, argp); case RCKP_RESET_RM2: return reset_rm2(info, argp); case RCKP_GET_VERSION: return get_version(info, argp); default: return -ENOIOCTLCMD; } return 0;}static 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, "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;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?