目录
在之前笔记1中有提到tty设备初始化时注册串口数据的读写等操作的结构体ft260_uart_ops。
static const struct tty_operations ft260_uart_ops = {
.open = ft260_uart_open,
.close = ft260_uart_close,
.write = ft260_uart_write,
.write_room = ft260_uart_write_room,
.chars_in_buffer = ft260_uart_chars_in_buffer,
.set_termios = ft260_uart_set_termios,
.hangup = ft260_uart_hangup,
.install = ft260_uart_install,
.cleanup = ft260_uart_cleanup,
.proc_show = ft260_uart_proc_show,
.get_icount = ft260_uart_get_icount,
};
通过这个结构体,不同的硬件设备可以实现相同的串口操作接口。
1. install
在driver的内部表中安装一个新的tty,一般是在设备被打开时调用。
static int ft260_uart_install(struct tty_driver *driver, struct tty_struct *tty)
{
int idx = tty->index;
struct ft260_device *port = ft260_uart_port_get(idx);
int ret = tty_standard_install(driver, tty);
if (ret == 0)
/* This is the ref ft260_uart_port get provided */
tty->driver_data = port;
else
ft260_uart_port_put(port);
return ret;
}
该函数用于安装FT260 UART设备的驱动程序。它接收一个tty_driver
结构体和一个tty_struct
结构体作为参数。函数首先根据tty
的索引获取相应的ft260_device
结构体,即从ft260_uart_device_list中取出FT260对应的设备。
然后调用tty_standard_install
函数进行标准的驱动程序安装。如果安装成功,将port
赋值给tty->driver_data
;否则,释放port
所占用的资源。最后返回安装的返回值。
2. cleanup
用于挂断tty设备。这通常涉及关闭设备、释放资源等。
3. open
打开tty设备
4. close
关闭tty设备
5. hangup
挂断tty设备
6. proc_show
在/proc/tty/driver/<Driver_name>中显示其他信息。在该目录下查看这个文件内容,如下:
$ sudo cat /proc/tty/driver/ft260_ser
ft260 info:1.0 driver revision:
0: uart:FT260 tx:0 rx:0
7. get_icount
icount包含了UART的中断计数信息,如接收错误、接收字符、发送字符等的计数。在ft260_uart_proc_show里面就是显示这些数据。这部分数据保存在设备结构体中。
8. write
内核调用此函数以向tty设备写入字符串。字符串可能来自用户空间或内核空间。此例程将返回实际接受写入的字符数。在特殊情况下可能同时发生。因为这包括恐慌(panic)路径,所以驱动通常不应该尝试在这里进行太复杂的锁。
函数首先使用kfifo_in_spinlocked
将cnt
个字节从buf
拷贝到设备的发送FIFO中,并返回实际拷贝的字节数len
。
然后,它调用ft260_uart_transmit_chars
来发送FIFO中的数据。如果发送失败,函数返回0。如果发送成功,函数返回实际拷贝的字节数len
。如果发送后FIFO中仍有剩余数据,函数计算未发送的字节数diff
并返回该值。
9. write_room
该函数用于获取FT260 UART的发送缓冲区可用空间大小。
10. chars_in_buffer
该函数用于获取FT260 UART缓冲区中的字符数量。
11. set_termios
该函数用于设置FT260 UART的终端属性。
12. UART读的实现
从上面的结构体初始化来看,并没有UART读部分的实现。这部分实现是在hid_driver的raw_event完成的。
static struct hid_driver ft260_driver = {
.name = "ft260",
.id_table = ft260_devices,
.probe = ft260_probe,
.remove = ft260_remove,
.raw_event = ft260_raw_event,
};
在函数ft260_raw_event中以下这段代码是uart部分的处理
FT260_UART_REPORT_MIN = 0xF0,
FT260_UART_REPORT_MAX = 0xFE,
else if (xfer->report >= FT260_UART_REPORT_MIN
&& xfer->report <= FT260_UART_REPORT_MAX) {
return ft260_uart_receive_chars(dev, xfer->data, xfer->length);
}
其对应的说明在FT260的AN394的4.6.3 UART Input Report中。
函数ft260_uart_receive_chars
的主要功能是处理从FT260设备的UART接口接收到的数据,并确保这些数据被正确地存入与设备相关的TTY缓冲区中以便进一步处理。下面是该函数的详细步骤说明:
参数说明:
struct ft260_device *port
: 指向ft260_device
结构体的指针,包含了关于FT260设备的信息,包括其TTY端口。u8 *data
: 指向缓冲区的指针,该缓冲区存储了从UART接收到的原始数据字符。u8 length
: 无符号8位整型变量,表示data
缓冲区中有效数据的字节长度。
数据插入翻转缓冲区:
- 调用
tty_insert_flip_string
函数尝试将data
中的length
个字符插入到port->port
关联的TTY翻转缓冲区中。这个缓冲区设计用来高效地管理输入输出数据流,支持“翻转”操作以准备数据供上层读取。 - 函数返回值
ret
表示实际成功插入缓冲区的字符数量。
错误处理:
- 如果插入的字符数
ret
不等于期望的长度length
,则通过调用ft260_dbg
调试日志函数报告未成功插入的字符数量。这有助于诊断潜在的数据丢失问题。
更新接收计数器:
- 更新
port->icount.rx
字段,累加实际接收到的字符数ret
。此字段通常用于跟踪设备的接收统计信息。
缓冲区推送:
- 当至少有一个字符被成功插入缓冲区时(即
ret > 0
),调用tty_flip_buffer_push
来“推送”或提交翻转缓冲区的更改。这一操作告知TTY子系统数据已准备好被读取,可能触发读事件通知上层应用程序。
返回值:
- 函数最终返回实际插入到缓冲区的字符数
ret
,这可以用于外部调用者确认操作结果。