}
//处理有数据流控制情况
if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
spin_lock_irqsave(&state->uart_port->lock, flags);
if (!(state->uart_port->ops->get_mctrl(state->uart_port) & TIOCM_CTS)) {
tty->hw_stopped = 1;
state->uart_port->ops->stop_tx(state->uart_port);
}
spin_unlock_irqrestore(&state->uart_port->lock, flags);
}
}
好了我们已经讲解了write,set_termiox,下面我们讲讲tiocmget和tiocmset。Tiocmget()函数用于获取tty设备的线路设置,对应的tiocmset()用于设置tty设备的线路设置。
static int uart_tiocmget(struct tty_struct *tty, struct file *file)
{
struct uart_state *state = tty->driver_data;
struct tty_port *port = &state->port;
struct uart_port *uport = state->uart_port;
int result = -EIO;
mutex_lock(&port->mutex); //获取对tty_port操作的锁
if ((!file || !tty_hung_up_p(file)) &&
!(tty->flags & (1 < TTY_IO_ERROR))) {
result = uport->mctrl;
spin_lock_irq(&uport->lock);
result |= uport->ops->get_mctrl(uport); //调用UART层get_mctrl获取modem控制
spin_unlock_irq(&uport->lock);
}
mutex_unlock(&port->mutex); //释放对tty_port操作的锁
return result;
}
static int uart_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
struct uart_state *state = tty->driver_data;
struct uart_port *uport = state->uart_port;
struct tty_port *port = &state->port;
int ret = -EIO;
mutex_lock(&port->mutex); //获取对tty_port操作的锁
if ((!file || !tty_hung_up_p(file)) &&
!(tty->flags & (1 < TTY_IO_ERROR))) {
uart_update_mctrl(uport, set, clear); //获取modem控制
ret = 0;
}
mutex_unlock(&port->mutex); //释放对tty_port操作的锁
return ret;
}
上面uart_tiocmset中调用了uart_update_mctrl(uport, set, clear)函数,它最终是通过调用port->ops->set_mctrl(port, port->mctrl)完成,而set_mctrl在UART层的uart_ops实现了。
综上,TTY层的ops中的uart_tiocmget和uart_tiocmset其实最终是调用UART层uart_ops中的get_mctrl和set_mctrl实现的。
当用户在tty设备节点上进行ioctl调用时,tty_operations中的ioctl()函数会被tty核心调用。我们接下来看看struct tty_operations uart_ops下的.ioctl也就是uart_ioctl。
static int uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
unsigned long arg)
{
struct uart_state *state = tty->driver_data;
struct tty_port *port = &state->port;
void __user *uarg = (void __user *)arg;
int ret = -ENOIOCTLCMD;
switch (cmd) { //这些ioctl不依赖硬件
case TIOCGSERIAL: //获得串口线信息
ret = uart_get_info(state, uarg);
break;
case TIOCSSERIAL: //设置串口线信息
ret = uart_set_info(state, uarg);
break;
case TIOCSERCONFIG: //自动配置
ret = uart_do_autoconfig(state);
break;
case TIOCSERGWILD:
case TIOCSERSWILD:
ret = 0;
break;
}
if (ret != -ENOIOCTLCMD)
goto out;
if (tty->flags & (1 < TTY_IO_ERROR)) {
ret = -EIO;
goto out;
}
switch (cmd) { //这些ioctl依赖硬件
case TIOCMIWAIT: //等待MSR改变
ret = uart_wait_modem_status(state, arg);
break;
case TIOCGICOUNT: //获得中断计数
ret = uart_get_count(state, uarg);
break;
}
if (ret != -ENOIOCTLCMD)
goto out;
mutex_lock(&port->mutex);
if (tty_hung_up_p(filp)) {
ret = -EIO;
goto out_up;
}
switch (cmd) { //这些ioctl依赖硬件,并且需要保护,房子tty被挂起
case TIOCSERGETLSR: //获得这个tty设备的线路状态寄存器LSR的值
ret = uart_get_lsr_info(state, uarg);
break;
default: {
struct uart_port *uport = state->uart_port;
if (uport->ops->ioctl)
ret = uport->ops->ioctl(uport, cmd, arg);
break;
}
}
out_up:
mutex_unlock(&port->mutex);
out:
return ret;
}
当TTY核心想知道由TTY驱动程序提供的可用写入缓冲区的大小时,就会调用write_room。在清空写缓冲区,或者调用write函数向缓冲区添加数据时,该值是变化的。接下来我们看看TTY层ops中write_room,也就是uart_write_room。跟踪发现其实这个函数实现主要是把缓冲区头尾相减得到剩余空间大小。
除