1. tty线路设置用户空间接口 可以调用用户空间的termios库函数,改变tty线路设置,或者获取当前线路设置。 用户空间应用程序需引用 termios.h 头文件,该头文件包含了终端设备的I/O接口。
termios结构体 描述了终端设备的操作模式
- typedef unsigned char cc_t;
- typedef unsigned int speed_t;
- typedef unsigned int tcflag_t;
-
- #define NCCS 19
- struct termios {
- tcflag_t c_iflag; /* input mode flags */
- tcflag_t c_oflag; /* output mode flags */
- tcflag_t c_cflag; /* control mode flags */
- tcflag_t c_lflag; /* local mode flags */
- cc_t c_line; /* line discipline */
- cc_t c_cc[NCCS]; /* control characters */
- };
c_cflag --- 控制标志,包含了如下位域信息: CSIZE ---- 字长 CSTOPB ---- 两个停止位 PARENB ---- 奇偶校验位使能 PARODD ---- 奇校验位,当PARENB被使能时。 CREAD ---- 字符接收使能,如果没有使能,仍能从端口接收字符,但这些字符都要被丢弃。 CRTSCTS ---- 如果被置位,CTS 状态改变时将发送报告。 CLOCAL ---- 如果没有置位,调制解调器状态改变时将发送报告。 c_iflag --- 输入标志,包含如下位信息: INPCK ---- 使能帧和奇偶校验错误检查。 BRKINT ---- break 将清除终端输入/输出队列,向终端上前台程序发出 SIGINT 信号。 PARMRK ---- 奇偶校验和帧错误被标记,在INPCK 被设置且IGNPAR未被设置的情况下才有效。 IGNPAR ---- 忽略奇偶校验和帧错误。 IGNBRK ---- 忽略 break 。 2. 用户空间中有如下函数: 2.1 设置和获取终端设备的操作模式: int tcgetattr(int fd, struct termios *termios_p); int tcsetattr(int fd, int optional_actions, struct termios *termios_p ); 2.2 设置和获取输入/输出波特率: speed_t cfgetospeed(struct termios *termios_p); //获得输出波特率 speed_t cfgetispeed(struct termios *termios_p); //获得输入波特率
int cfsetospeed(struct termios *termios_p); //设置输出波特率 int cfsetispeed(struct termios *termios_p); //设置输入波特率
2.3 下面一组函数完成线路控制: int tcdrain(int fd); //等待所有输出都被发送 int tcflush(int fd, int queue_selector); //flush输入输出缓存 int tcflow(int fd, int action); //对输入输出流进行控制 int tcsendback(int fd, int duration); //发送break。
3. tty驱动的set_termios()函数
大部分termios用户空间的函数,被库转换为对驱动节点的ioctl()调用,而tty_ioctl()中的大部分命令会被tty核心转换为对tty驱动的set_termios()成员函数的调用。 set_termios()函数,需要根据用户对termiosde 设置要求, 完成实际的硬件设置。如字长,奇偶校验位,停止位,波特率等。
下面是 set_termios()成员函数的范例:
- static void xxx_set_termios(struct tty_struct *tty, struct termios *old_termios)
- {
- struct xxx_tty *info = (struct cyclades_port *)tty->driver_data;
-
- //新设置=旧设置
- if (tty->termios->c_cflags == old_termios->cflag)
- return;
- ...
- //关闭CRTSCTS硬件流控制
- if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS))
- {
- ...
- }
-
- //打开CRTSCTS 硬件流控制
- if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS))
- {
- ...
- }
-
- //设置字节大小
- switch (tty->termios->c_cflag & CSIZE)
- {
- case CS5:
- ...
- case CS6:
- ...
- case CS7:
- ...
- case CS8:
- ...
- }
-
- //设置奇偶校验位
- if (tty->termios->c_cflag & PARENB)
- if(tty->termios->c_cflag & PARODD) //奇校验
- ...
- else //偶校验
- ...
- }
3.1 tty_register_ldisc() --- 注册线路规程函数
- /**
- * tty_register_ldisc - install a line discipline
- * @disc: ldisc number
- * @new_ldisc: pointer to the ldisc object
- *
- * Installs a new line discipline into the kernel. The discipline
- * is set up as unreferenced and then made available to the kernel
- * from this point onwards.
- *
- * Locking:
- * takes tty_ldisc_lock to guard against ldisc races
- */
- int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
- {
- unsigned long flags;
- int ret = 0;
-
- if (disc < N_TTY || disc >= NR_LDISCS)
- return -EINVAL;
-
- spin_lock_irqsave(&tty_ldisc_lock, flags);
- tty_ldiscs[disc] = new_ldisc;
- new_ldisc->num = disc;
- new_ldisc->refcount = 0;
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-
- return ret;
- }
- EXPORT_SYMBOL(tty_register_ldisc);
3.2 tty_disc_ops --- tty 线路规程操作函数
- struct tty_ldisc_ops tty_ldisc_N_TTY = {
- .magic = TTY_LDISC_MAGIC,
- .name = "n_tty",
- .open = n_tty_open,
- .close = n_tty_close,
- .flush_buffer = n_tty_flush_buffer,
- .chars_in_buffer = n_tty_chars_in_buffer,
- .read = n_tty_read,
- .write = n_tty_write,
- .ioctl = n_tty_ioctl,
- .set_termios = n_tty_set_termios,
- .poll = n_tty_poll,
- .receive_buf = n_tty_receive_buf,
- .write_wakeup = n_tty_write_wakeup
- };
|