📄 isdn_tty.c
字号:
if (i < 1 || i > 2) info->tty->termios->c_cflag &= ~CBAUDEX; else i += 15; } if (quot) { info->mcr |= UART_MCR_DTR; isdn_tty_modem_ncarrier(info); } else { info->mcr &= ~UART_MCR_DTR; if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {#ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup in changespeed\n");#endif if (info->online) info->ncarrier = 1; isdn_tty_modem_reset_regs(info, 0); isdn_tty_modem_hup(info, 1); } return; } /* byte size and parity */ cval = cflag & (CSIZE | CSTOPB); cval >>= 4; if (cflag & PARENB) cval |= UART_LCR_PARITY; if (!(cflag & PARODD)) cval |= UART_LCR_EPAR; fcr = 0; /* CTS flow control flag and modem status interrupts */ if (cflag & CRTSCTS) { info->flags |= ISDN_ASYNC_CTS_FLOW; } else info->flags &= ~ISDN_ASYNC_CTS_FLOW; if (cflag & CLOCAL) info->flags &= ~ISDN_ASYNC_CHECK_CD; else { info->flags |= ISDN_ASYNC_CHECK_CD; }}static intisdn_tty_startup(modem_info * info){ if (info->flags & ISDN_ASYNC_INITIALIZED) return 0; isdn_lock_drivers();#ifdef ISDN_DEBUG_MODEM_OPEN printk(KERN_DEBUG "starting up ttyi%d ...\n", info->line);#endif /* * Now, initialize the UART */ info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); /* * and set the speed of the serial port */ isdn_tty_change_speed(info); info->flags |= ISDN_ASYNC_INITIALIZED; info->msr |= (UART_MSR_DSR | UART_MSR_CTS); info->send_outstanding = 0; return 0;}/* * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. */static voidisdn_tty_shutdown(modem_info * info){ if (!(info->flags & ISDN_ASYNC_INITIALIZED)) return;#ifdef ISDN_DEBUG_MODEM_OPEN printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line);#endif isdn_unlock_drivers(); info->msr &= ~UART_MSR_RI; if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS); if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) { isdn_tty_modem_reset_regs(info, 0);#ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n");#endif isdn_tty_modem_hup(info, 1); } } if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); info->flags &= ~ISDN_ASYNC_INITIALIZED;}/* isdn_tty_write() is the main send-routine. It is called from the upper * levels within the kernel to perform sending data. Depending on the * online-flag it either directs output to the at-command-interpreter or * to the lower level. Additional tasks done here: * - If online, check for escape-sequence (+++) * - If sending audio-data, call isdn_tty_DLEdown() to parse DLE-codes. * - If receiving audio-data, call isdn_tty_end_vrx() to abort if needed. * - If dialing, abort dial. */static intisdn_tty_write(struct tty_struct *tty, const u_char * buf, int count){ int c; int total = 0; modem_info *info = (modem_info *) tty->driver_data; atemu *m = &info->emu; if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_write")) return 0; /* See isdn_tty_senddown() */ atomic_inc(&info->xmit_lock); while (1) { c = count; if (c > info->xmit_size - info->xmit_count) c = info->xmit_size - info->xmit_count; if (info->isdn_driver >= 0 && c > dev->drv[info->isdn_driver]->maxbufsize) c = dev->drv[info->isdn_driver]->maxbufsize; if (c <= 0) break; if ((info->online > 1)#ifdef CONFIG_ISDN_AUDIO || (info->vonline & 3)#endif ) {#ifdef CONFIG_ISDN_AUDIO if (!info->vonline)#endif isdn_tty_check_esc(buf, m->mdmreg[REG_ESC], c, &(m->pluscount), &(m->lastplus)); memcpy(&(info->xmit_buf[info->xmit_count]), buf, c);#ifdef CONFIG_ISDN_AUDIO if (info->vonline) { int cc = isdn_tty_handleDLEdown(info, m, c); if (info->vonline & 2) { if (!cc) { /* If DLE decoding results in zero-transmit, but * c originally was non-zero, do a wakeup. */ tty_wakeup(tty); info->msr |= UART_MSR_CTS; info->lsr |= UART_LSR_TEMT; } info->xmit_count += cc; } if ((info->vonline & 3) == 1) { /* Do NOT handle Ctrl-Q or Ctrl-S * when in full-duplex audio mode. */ if (isdn_tty_end_vrx(buf, c)) { info->vonline &= ~1;#ifdef ISDN_DEBUG_MODEM_VOICE printk(KERN_DEBUG "got !^Q/^S, send DLE-ETX,VCON on ttyI%d\n", info->line);#endif isdn_tty_at_cout("\020\003\r\nVCON\r\n", info); } } } else if (TTY_IS_FCLASS1(info)) { int cc = isdn_tty_handleDLEdown(info, m, c); if (info->vonline & 4) { /* ETX seen */ isdn_ctrl c; c.command = ISDN_CMD_FAXCMD; c.driver = info->isdn_driver; c.arg = info->isdn_channel; c.parm.aux.cmd = ISDN_FAX_CLASS1_CTRL; c.parm.aux.subcmd = ETX; isdn_command(&c); } info->vonline = 0;#ifdef ISDN_DEBUG_MODEM_VOICE printk(KERN_DEBUG "fax dle cc/c %d/%d\n", cc, c);#endif info->xmit_count += cc; } else#endif info->xmit_count += c; } else { info->msr |= UART_MSR_CTS; info->lsr |= UART_LSR_TEMT; if (info->dialing) { info->dialing = 0;#ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup in isdn_tty_write\n");#endif isdn_tty_modem_result(RESULT_NO_CARRIER, info); isdn_tty_modem_hup(info, 1); } else c = isdn_tty_edit_at(buf, c, info); } buf += c; count -= c; total += c; } atomic_dec(&info->xmit_lock); if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue)) { if (m->mdmreg[REG_DXMT] & BIT_DXMT) { isdn_tty_senddown(info); isdn_tty_tint(info); } isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1); } return total;}static intisdn_tty_write_room(struct tty_struct *tty){ modem_info *info = (modem_info *) tty->driver_data; int ret; if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_write_room")) return 0; if (!info->online) return info->xmit_size; ret = info->xmit_size - info->xmit_count; return (ret < 0) ? 0 : ret;}static intisdn_tty_chars_in_buffer(struct tty_struct *tty){ modem_info *info = (modem_info *) tty->driver_data; if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_chars_in_buffer")) return 0; if (!info->online) return 0; return (info->xmit_count);}static voidisdn_tty_flush_buffer(struct tty_struct *tty){ modem_info *info; if (!tty) { return; } info = (modem_info *) tty->driver_data; if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_buffer")) { return; } isdn_tty_cleanup_xmit(info); info->xmit_count = 0; wake_up_interruptible(&tty->write_wait); tty_wakeup(tty);}static voidisdn_tty_flush_chars(struct tty_struct *tty){ modem_info *info = (modem_info *) tty->driver_data; if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_chars")) return; if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue)) isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);}/* * ------------------------------------------------------------ * isdn_tty_throttle() * * This routine is called by the upper-layer tty layer to signal that * incoming characters should be throttled. * ------------------------------------------------------------ */static voidisdn_tty_throttle(struct tty_struct *tty){ modem_info *info = (modem_info *) tty->driver_data; if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_throttle")) return; if (I_IXOFF(tty)) info->x_char = STOP_CHAR(tty); info->mcr &= ~UART_MCR_RTS;}static voidisdn_tty_unthrottle(struct tty_struct *tty){ modem_info *info = (modem_info *) tty->driver_data; if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_unthrottle")) return; if (I_IXOFF(tty)) { if (info->x_char) info->x_char = 0; else info->x_char = START_CHAR(tty); } info->mcr |= UART_MCR_RTS;}/* * ------------------------------------------------------------ * isdn_tty_ioctl() and friends * ------------------------------------------------------------ *//* * isdn_tty_get_lsr_info - get line status register info * * Purpose: Let user call ioctl() to get info when the UART physically * is emptied. On bus types like RS485, the transmitter must * release the bus after transmitting. This must be done when * the transmit shift register is empty, not be done when the * transmit holding register is empty. This functionality * allows RS485 driver to be written in user space. */static intisdn_tty_get_lsr_info(modem_info * info, uint __user * value){ u_char status; uint result; status = info->lsr; result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); return put_user(result, value);}static intisdn_tty_tiocmget(struct tty_struct *tty, struct file *file){ modem_info *info = (modem_info *) tty->driver_data; u_char control, status; if (isdn_tty_paranoia_check(info, tty->name, __FUNCTION__)) return -ENODEV; if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO;#ifdef ISDN_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line);#endif control = info->mcr; status = info->msr; return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);}static intisdn_tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear){ modem_info *info = (modem_info *) tty->driver_data; if (isdn_tty_paranoia_check(info, tty->name, __FUNCTION__)) return -ENODEV; if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO;#ifdef ISDN_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "ttyI%d ioctl TIOCMxxx: %x %x\n", info->line, set, clear);#endif if (set & TIOCM_RTS) info->mcr |= UART_MCR_RTS; if (set & TIOCM_DTR) { info->mcr |= UART_MCR_DTR; isdn_tty_modem_ncarrier(info); } if (clear & TIOCM_RTS) info->mcr &= ~UART_MCR_RTS; if (clear & TIOCM_DTR) { info->mcr &= ~UART_MCR_DTR; if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) { isdn_tty_modem_reset_regs(info, 0);#ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup in TIOCMSET\n");#endif if (info->online) info->ncarrier = 1; isdn_tty_modem_hup(info, 1); } } return 0;}static intisdn_tty_ioctl(struct tty_struct *tty, struct file *file, uint cmd, ulong arg){ modem_info *info = (modem_info *) tty->driver_data; int retval; if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_ioctl")) return -ENODEV; if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; switch (cmd) { case TCSBRK: /* SVID version: non-zero arg --> no break */#ifdef ISDN_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "ttyI%d ioctl TCSBRK\n", info->line);#endif retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); return 0; case TCSBRKP: /* support for POSIX tcsendbreak() */#ifdef ISDN_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "ttyI%d ioctl TCSBRKP\n", info->line);#endif retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); return 0; case TIOCGSOFTCAR:#ifdef ISDN_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "ttyI%d ioctl TIOCGSOFTCAR\n", info->line);#endif return put_user(C_CLOCAL(tty) ? 1 : 0, (ulong __user *) arg); case TIOCSSOFTCAR:#ifdef ISDN_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "ttyI%d ioctl TIOCSSOFTCAR\n", info->line);#endif if (get_user(arg, (ulong __user *) arg)) return -EFAULT; tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); return 0; case TIOCSERGETLSR: /* Get line status register */#ifdef ISDN_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line);#endif return isdn_tty_get_lsr_info(info, (uint __user *) arg); default:#ifdef ISDN_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line);#endif return -ENOIOCTLCMD; } return 0;}static voidisdn_tty_set_termios(struct tty_struct *tty, struct termios *old_termios){ modem_info *info = (modem_info *) tty->driver_data; if (!old_termios) isdn_tty_change_speed(info); else { if (tty->termios->c_cflag == old_termios->c_cflag) return; isdn_tty_change_speed(info); if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { tty->hw_stopped = 0; } }}/* * ------------------------------------------------------------ * isdn_tty_open() and friends * ------------------------------------------------------------ */static intisdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info * info){ DECLARE_WAITQUEUE(wait, NULL); int do_clocal = 0; int retval; /* * 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) || (info->flags & ISDN_ASYNC_CLOSING)) { if (info->flags & ISDN_ASYNC_CLOSING) interruptible_sleep_on(&info->close_wait);#ifdef MODEM_DO_RESTART if (info->flags & ISDN_ASYNC_HUP_NOTIFY) return -EAGAIN; else return -ERESTARTSYS;#else return -EAGAIN;#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -