📄 synclink_gt.c
字号:
* Note: use tight timings here to satisfy the NIST-PCTS. */ if (info->params.data_rate) { char_time = info->timeout/(32 * 5); if (!char_time) char_time++; } else char_time = 1; if (timeout) char_time = min_t(unsigned long, char_time, timeout); while (info->tx_active) { msleep_interruptible(jiffies_to_msecs(char_time)); if (signal_pending(current)) break; if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; }exit: DBGINFO(("%s wait_until_sent exit\n", info->device_name));}static int write_room(struct tty_struct *tty){ struct slgt_info *info = tty->driver_data; int ret; if (sanity_check(info, tty->name, "write_room")) return 0; ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE; DBGINFO(("%s write_room=%d\n", info->device_name, ret)); return ret;}static void flush_chars(struct tty_struct *tty){ struct slgt_info *info = tty->driver_data; unsigned long flags; if (sanity_check(info, tty->name, "flush_chars")) return; DBGINFO(("%s flush_chars entry tx_count=%d\n", info->device_name, info->tx_count)); if (info->tx_count <= 0 || tty->stopped || tty->hw_stopped || !info->tx_buf) return; DBGINFO(("%s flush_chars start transmit\n", info->device_name)); spin_lock_irqsave(&info->lock,flags); if (!info->tx_active && info->tx_count) { tx_load(info, info->tx_buf,info->tx_count); tx_start(info); } spin_unlock_irqrestore(&info->lock,flags);}static void flush_buffer(struct tty_struct *tty){ struct slgt_info *info = tty->driver_data; unsigned long flags; if (sanity_check(info, tty->name, "flush_buffer")) return; DBGINFO(("%s flush_buffer\n", info->device_name)); spin_lock_irqsave(&info->lock,flags); if (!info->tx_active) info->tx_count = 0; spin_unlock_irqrestore(&info->lock,flags); tty_wakeup(tty);}/* * throttle (stop) transmitter */static void tx_hold(struct tty_struct *tty){ struct slgt_info *info = tty->driver_data; unsigned long flags; if (sanity_check(info, tty->name, "tx_hold")) return; DBGINFO(("%s tx_hold\n", info->device_name)); spin_lock_irqsave(&info->lock,flags); if (info->tx_enabled && info->params.mode == MGSL_MODE_ASYNC) tx_stop(info); spin_unlock_irqrestore(&info->lock,flags);}/* * release (start) transmitter */static void tx_release(struct tty_struct *tty){ struct slgt_info *info = tty->driver_data; unsigned long flags; if (sanity_check(info, tty->name, "tx_release")) return; DBGINFO(("%s tx_release\n", info->device_name)); spin_lock_irqsave(&info->lock,flags); if (!info->tx_active && info->tx_count) { tx_load(info, info->tx_buf, info->tx_count); tx_start(info); } spin_unlock_irqrestore(&info->lock,flags);}/* * Service an IOCTL request * * Arguments * * tty pointer to tty instance data * file pointer to associated file object for device * cmd IOCTL command code * arg command argument/context * * Return 0 if success, otherwise error code */static int ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg){ struct slgt_info *info = tty->driver_data; struct mgsl_icount cnow; /* kernel counter temps */ struct serial_icounter_struct __user *p_cuser; /* user space */ unsigned long flags; void __user *argp = (void __user *)arg; if (sanity_check(info, tty->name, "ioctl")) return -ENODEV; DBGINFO(("%s ioctl() cmd=%08X\n", info->device_name, cmd)); if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; } switch (cmd) { case MGSL_IOCGPARAMS: return get_params(info, argp); case MGSL_IOCSPARAMS: return set_params(info, argp); case MGSL_IOCGTXIDLE: return get_txidle(info, argp); case MGSL_IOCSTXIDLE: return set_txidle(info, (int)arg); case MGSL_IOCTXENABLE: return tx_enable(info, (int)arg); case MGSL_IOCRXENABLE: return rx_enable(info, (int)arg); case MGSL_IOCTXABORT: return tx_abort(info); case MGSL_IOCGSTATS: return get_stats(info, argp); case MGSL_IOCWAITEVENT: return wait_mgsl_event(info, argp); case TIOCMIWAIT: return modem_input_wait(info,(int)arg); case MGSL_IOCGIF: return get_interface(info, argp); case MGSL_IOCSIF: return set_interface(info,(int)arg); case MGSL_IOCSGPIO: return set_gpio(info, argp); case MGSL_IOCGGPIO: return get_gpio(info, argp); case MGSL_IOCWAITGPIO: return wait_gpio(info, argp); case TIOCGICOUNT: spin_lock_irqsave(&info->lock,flags); cnow = info->icount; spin_unlock_irqrestore(&info->lock,flags); p_cuser = argp; if (put_user(cnow.cts, &p_cuser->cts) || put_user(cnow.dsr, &p_cuser->dsr) || put_user(cnow.rng, &p_cuser->rng) || put_user(cnow.dcd, &p_cuser->dcd) || put_user(cnow.rx, &p_cuser->rx) || put_user(cnow.tx, &p_cuser->tx) || put_user(cnow.frame, &p_cuser->frame) || put_user(cnow.overrun, &p_cuser->overrun) || put_user(cnow.parity, &p_cuser->parity) || put_user(cnow.brk, &p_cuser->brk) || put_user(cnow.buf_overrun, &p_cuser->buf_overrun)) return -EFAULT; return 0; default: return -ENOIOCTLCMD; } return 0;}/* * support for 32 bit ioctl calls on 64 bit systems */#ifdef CONFIG_COMPATstatic long get_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *user_params){ struct MGSL_PARAMS32 tmp_params; DBGINFO(("%s get_params32\n", info->device_name)); tmp_params.mode = (compat_ulong_t)info->params.mode; tmp_params.loopback = info->params.loopback; tmp_params.flags = info->params.flags; tmp_params.encoding = info->params.encoding; tmp_params.clock_speed = (compat_ulong_t)info->params.clock_speed; tmp_params.addr_filter = info->params.addr_filter; tmp_params.crc_type = info->params.crc_type; tmp_params.preamble_length = info->params.preamble_length; tmp_params.preamble = info->params.preamble; tmp_params.data_rate = (compat_ulong_t)info->params.data_rate; tmp_params.data_bits = info->params.data_bits; tmp_params.stop_bits = info->params.stop_bits; tmp_params.parity = info->params.parity; if (copy_to_user(user_params, &tmp_params, sizeof(struct MGSL_PARAMS32))) return -EFAULT; return 0;}static long set_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *new_params){ struct MGSL_PARAMS32 tmp_params; DBGINFO(("%s set_params32\n", info->device_name)); if (copy_from_user(&tmp_params, new_params, sizeof(struct MGSL_PARAMS32))) return -EFAULT; spin_lock(&info->lock); info->params.mode = tmp_params.mode; info->params.loopback = tmp_params.loopback; info->params.flags = tmp_params.flags; info->params.encoding = tmp_params.encoding; info->params.clock_speed = tmp_params.clock_speed; info->params.addr_filter = tmp_params.addr_filter; info->params.crc_type = tmp_params.crc_type; info->params.preamble_length = tmp_params.preamble_length; info->params.preamble = tmp_params.preamble; info->params.data_rate = tmp_params.data_rate; info->params.data_bits = tmp_params.data_bits; info->params.stop_bits = tmp_params.stop_bits; info->params.parity = tmp_params.parity; spin_unlock(&info->lock); change_params(info); return 0;}static long slgt_compat_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg){ struct slgt_info *info = tty->driver_data; int rc = -ENOIOCTLCMD; if (sanity_check(info, tty->name, "compat_ioctl")) return -ENODEV; DBGINFO(("%s compat_ioctl() cmd=%08X\n", info->device_name, cmd)); switch (cmd) { case MGSL_IOCSPARAMS32: rc = set_params32(info, compat_ptr(arg)); break; case MGSL_IOCGPARAMS32: rc = get_params32(info, compat_ptr(arg)); break; case MGSL_IOCGPARAMS: case MGSL_IOCSPARAMS: case MGSL_IOCGTXIDLE: case MGSL_IOCGSTATS: case MGSL_IOCWAITEVENT: case MGSL_IOCGIF: case MGSL_IOCSGPIO: case MGSL_IOCGGPIO: case MGSL_IOCWAITGPIO: case TIOCGICOUNT: rc = ioctl(tty, file, cmd, (unsigned long)(compat_ptr(arg))); break; case MGSL_IOCSTXIDLE: case MGSL_IOCTXENABLE: case MGSL_IOCRXENABLE: case MGSL_IOCTXABORT: case TIOCMIWAIT: case MGSL_IOCSIF: rc = ioctl(tty, file, cmd, arg); break; } DBGINFO(("%s compat_ioctl() cmd=%08X rc=%d\n", info->device_name, cmd, rc)); return rc;}#else#define slgt_compat_ioctl NULL#endif /* ifdef CONFIG_COMPAT *//* * proc fs support */static inline int line_info(char *buf, struct slgt_info *info){ char stat_buf[30]; int ret; unsigned long flags; ret = sprintf(buf, "%s: IO=%08X IRQ=%d MaxFrameSize=%u\n", info->device_name, info->phys_reg_addr, info->irq_level, info->max_frame_size); /* output current serial signal states */ spin_lock_irqsave(&info->lock,flags); get_signals(info); spin_unlock_irqrestore(&info->lock,flags); stat_buf[0] = 0; stat_buf[1] = 0; if (info->signals & SerialSignal_RTS) strcat(stat_buf, "|RTS"); if (info->signals & SerialSignal_CTS) strcat(stat_buf, "|CTS"); if (info->signals & SerialSignal_DTR) strcat(stat_buf, "|DTR"); if (info->signals & SerialSignal_DSR) strcat(stat_buf, "|DSR"); if (info->signals & SerialSignal_DCD) strcat(stat_buf, "|CD"); if (info->signals & SerialSignal_RI) strcat(stat_buf, "|RI"); if (info->params.mode != MGSL_MODE_ASYNC) { ret += sprintf(buf+ret, "\tHDLC txok:%d rxok:%d", info->icount.txok, info->icount.rxok); if (info->icount.txunder) ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder); if (info->icount.txabort) ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort); if (info->icount.rxshort) ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort); if (info->icount.rxlong) ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong); if (info->icount.rxover) ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover); if (info->icount.rxcrc) ret += sprintf(buf+ret, " rxcrc:%d", info->icount.rxcrc); } else { ret += sprintf(buf+ret, "\tASYNC tx:%d rx:%d", info->icount.tx, info->icount.rx); if (info->icount.frame) ret += sprintf(buf+ret, " fe:%d", info->icount.frame); if (info->icount.parity) ret += sprintf(buf+ret, " pe:%d", info->icount.parity); if (info->icount.brk) ret += sprintf(buf+ret, " brk:%d", info->icount.brk); if (info->icount.overrun) ret += sprintf(buf+ret, " oe:%d", info->icount.overrun); } /* Append serial signal status to end */ ret += sprintf(buf+ret, " %s\n", stat_buf+1); ret += sprintf(buf+ret, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n", info->tx_active,info->bh_requested,info->bh_running, info->pending_bh); return ret;}/* Called to print information about devices */static int read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ int len = 0, l; off_t begin = 0; struct slgt_info *info; len += sprintf(page, "synclink_gt driver:%s\n", driver_version); info = slgt_device_list; while( info ) { l = line_info(page + len, info); len += l; if (len+begin > off+count) goto done; if (len+begin < off) { begin += len; len = 0; } info = info->next_device; } *eof = 1;done: if (off >= len+begin) return 0; *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off);}/* * return count of bytes in transmit buffer */static int chars_in_buffer(struct tty_struct *tty){ struct slgt_info *info = tty->driver_data; if (sanity_check(info, tty->name, "chars_in_buffer")) return 0; DBGINFO(("%s chars_in_buffer()=%d\n", info->device_name, info->tx_count)); return info->tx_count;}/* * signal remote device to throttle send data (our receive data) */static void throttle(struct tty_struct * tty){ struct slgt_info *info = tty->driver_data; unsigned long flags; if (sanity_check(info, tty->name, "throttle")) return; DBGINFO(("%s throttle\n", info->device_name)); if (I_IXOFF(tty)) send_xchar(tty, STOP_CHAR(tty)); if (tty->termios->c_cflag & CRTSCTS) { spin_lock_irqsave(&info->lock,flags); info->signals &= ~SerialSignal_RTS; set_signals(info); spin_unlock_irqrestore(&info->lock,flags); }}/* * signal remote device to stop throttling send data (our receive data) */static void unthrottle(struct tty_struct * tty){ struct slgt_info *info = tty->driver_data; unsigned long flags; if (sanity_check(info, tty->name, "unthrottle")) return; DBGINFO(("%s unthrottle\n", info->device_name)); if (I_IXOFF(tty)) { if (info->x_char) info->x_char = 0; else send_xchar(tty, START_CHAR(tty)); } if (tty->termios->c_cflag & CRTSCTS) { spin_lock_irqsave(&info->lock,flags); info->signals |= SerialSignal_RTS; set_signals(info); spin_unlock_irqrestore(&info->lock,flags); }}/* * set or clear transmit break condition * break_state -1=set break condition, 0=clear */static void set_break(struct tty_struct *tty, int break_state){ struct slgt_info *info = tty->driver_data; unsigned short value; unsigned long flags; if (sanity_check(info, tty->name, "set_break")) return; DBGINFO(("%s set_break(%d)\n", info->device_name, break_state)); spin_lock_irqsave(&info->lock,flags); value = rd_reg16(info, TCR); if (break_state == -1) value |= BIT6;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -