/*
该函数做了一下事情 :
1 : 分配tty_driver 并且注册它
2 : 注册usb转串口总线
*/
static int __init usb_serial_init(void)
{
/*
这里分配一个tty_driver
下面要给他赋值,接着要注册它
分配 -->赋值 --> 注册 又耍这套手段,万变不离其宗 !
该模块上来第一任务就要注册tty_driver,usb转虚拟串口中 uart面向用户,usb深藏幕后默默工作
该函数的参数很有意思, 它是表示次设备的数量
有什么依据吗 ?
alloc_tty_driver(unsigned int lines)
{
tty_alloc_driver(lines, 0);
{
__tty_alloc_driver(lines, THIS_MODULE, flags);
{
....
/*
看,下面注册字符设备的时候 会使用到这个driver->num
下面有分析
*/
driver->num = lines;
}
}
}
*/
usb_serial_tty_driver = alloc_tty_driver(USB_SERIAL_TTY_MINORS);
if (!usb_serial_tty_driver)
return -ENOMEM;
/**
注册usb转串口总线.
该总线提供了probe()函数,类似的还有IIC总线, 但是USB总线,平台总线 却没有提供probe()函数
IIC总线的probe()函数调用了driver的 probe()函数,但是该总线也这样做了, 看下面
具体该总线的probe()方法做了那些事情,下面有说明
struct bus_type usb_serial_bus_type = {
.name = "usb-serial",
.match = usb_serial_device_match,
.probe = usb_serial_device_probe,
{
if (type->probe) //如果该driver提供了 probe函数
{
....
}
}
.....
};
iic总线 probe :
http://blog.csdn.net/leesagacious/article/details/50488949
*/
result = bus_register(&usb_serial_bus_type);
if (result) {
pr_err("%s - registering bus driver failed\n", __func__);
goto exit_bus;
}
/*
一块堆内存,已经赋值了,在这里再次 做 “整容手术”
主设备号 : 118 188看错了
具体赋值的是什么含义,用到再说吧
*/
usb_serial_tty_driver->driver_name = "usbserial";
usb_serial_tty_driver->name = "ttyUSB";
usb_serial_tty_driver->major = USB_SERIAL_TTY_MAJOR; //118
usb_serial_tty_driver->minor_start = 0;
usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
usb_serial_tty_driver->init_termios = tty_std_termios;
usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
usb_serial_tty_driver->init_termios.c_ispeed = 9600;
usb_serial_tty_driver->init_termios.c_ospeed = 9600;
}
/*
好了,收发流程的入口来了
操作设备文件,最终会调用serial_ops集合中对应的函数
“一切皆文件” 底层是VFS机制的贡献, Linux Kernel的精华所在!
它仿佛是一个黑洞,signal, socket 也逃脱不了! 也不知道当初是谁创造出来这么优秀的机制
但是通过设备文件沟通kernel space 与 user space 收发数据, netlink,signal实现的更优雅
*/
tty_set_operations(usb_serial_tty_driver, &serial_ops);
/**
开始要注册了
1 :看看上面说到的那个次设备号的个数,driver->num
int tty_register_driver(struct tty_driver *driver)
{
if (!driver->major) {
.....
} else {
register_chrdev_region(dev, driver->num, driver->name);
}
}
2 : 将该driver挂接到全局链表 tty_drivers 上
usb gadget 最低层的udc 也是挂接到全局链表上
这样的做法当然是为了以后遍历查找了,
3 : 注册 tty device
for (i = 0; i < device->num; i++) {
tty_register_device(driver, i, NULL);
}
*/
result = tty_register_driver(usb_serial_tty_driver);
if (result) {
pr_err("%s - tty_register_driver failed\n", __func__);
goto exit_reg_driver;
}
/*
usb_serial_probe()函数将会被调用
这是设备驱动模型的内容了,Linux Kernel driver 的基石所在 !
详细 :
http://blog.csdn.net/leesagacious/article/details/50488949 匹配流程图
在这个probe函数中最多生成 8 个ttyUSB 设备文件,ttyUSB%d
这个 8 数字在Kernel USB 中 很有有意思,且 超过了这个数字都是强制为 8
比如 : 看获取配置描述符中的实现
#define USB_MAXCOFIG : 8
int usb_get_configuration(struct usb_device *dev)
{
....
int ncfg = dev->descriptor.bNumConfigurations;
....
if (ncfg > USB_MAXCONFIG) {
......
}
}
7 ↑ 8 ↓ 哈哈 !
在一个init函数中做了这么多的注册操作! 下面还有注册.
不是常说 : 雨常有,天不常蹋吗 ? 哈哈 作者究竟要未雨绸缪什么 ?
*/
result = usb_register(&usb_serial_driver);
if (result < 0) {
pr_err("%s - usb_register failed\n", __func__);
goto exit_tty;
}
Usb + Serial + Net --- Linux Kernel 实现欣赏
猜你喜欢
转载自blog.csdn.net/leesagacious/article/details/79189901
今日推荐
周排行