usb_serial部分分析2
来源:互联网 发布:电信移动网络如何连接 编辑:程序博客网 时间:2024/06/08 05:32
转自http://blog.csdn.net/aaronychen/article/details/3555885
好了,是时候分析usbserial模块了.
我们知道当把一个模块加载进系统时会调用这个模块里的一个由module_init()声明的一个初始化函数. usbserial当然也不另外,
usb-serial.c:
module_init(usb_serial_init);
module_exit(usb_serial_exit);
没错加载时调用的就是: usb_serial_init().
usb-serial.c:
struct tty_driver *usb_serial_tty_driver;
static int __init usb_serial_init(void)
{int i;
int result;
//创建一个tty_driver对象,对应的就是tty设备的驱动.
usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);
if (!usb_serial_tty_driver)
return -ENOMEM;
/* Initialize our global data */
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
serial_table[i] = NULL; //该模块共支持SERIAL_TTY_MINORS个该类型设备.
}
result = bus_register(&usb_serial_bus_type); //注册这条serial bus.
if (result) {
err("%s - registering bus driver failed", __FUNCTION__);
goto exit_bus;
}
//初始化tty_driver对象
usb_serial_tty_driver->owner = THIS_MODULE;
usb_serial_tty_driver->driver_name = "usbserial";
usb_serial_tty_driver->devfs_name = "usb/tts/";
usb_serial_tty_driver->name = "ttyUSB"; //tty设备文件名以这个开头,后加0,1,2,3,....
usb_serial_tty_driver->major = SERIAL_TTY_MAJOR; //主设备号
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_NO_DEVFS;
usb_serial_tty_driver->init_termios = tty_std_termios;
usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
//赋值tty设备的操作集合,即应用层调用open时最终会调到serial_ops->open里面
tty_set_operations(usb_serial_tty_driver,& serial_ops);
result = tty_register_driver(usb_serial_tty_driver); //注册这个tty驱动
if (result) {
err("%s - tty_register_driver failed", __FUNCTION__);
goto exit_reg_driver;
}
/* register the USB driver */
result = usb_register(&usb_serial_driver); //注册一个usb驱动
if (result < 0) {
err("%s - usb_register failed", __FUNCTION__);
goto exit_tty;
}
/* register the generic driver, if we should */
result = usb_serial_generic_register(debug); //注册generic驱动程序
if (result < 0) {
err("%s - registering generic driver failed", __FUNCTION__);
goto exit_generic;
}
info(DRIVER_DESC);
return result;
//失败时候的一些反向操作
exit_generic:
usb_deregister(&usb_serial_driver);
exit_tty:
tty_unregister_driver(usb_serial_tty_driver);
exit_reg_driver:
bus_unregister(&usb_serial_bus_type);
exit_bus:
err ("%s - returning with error %d", __FUNCTION__, result);
put_tty_driver(usb_serial_tty_driver);
return result;
}
该函数先创建并初始化好了一个tty_driver的对象,并把该对象注册进系统, 该对象就是tty设备的驱动程序,后面我们会看到他是如何与具体tty设备绑定在一起的.
usb_serial.c:
static struct tty_operations serial_ops = {
.open = serial_open,
.close = serial_close,
.write = serial_write,
.write_room = serial_write_room,
.ioctl = serial_ioctl,
.set_termios = serial_set_termios,
.throttle = serial_throttle,
.unthrottle = serial_unthrottle,
.break_ctl = serial_break,
.chars_in_buffer = serial_chars_in_buffer,
.read_proc = serial_read_proc,
.tiocmget = serial_tiocmget,
.tiocmset = serial_tiocmset,
};
这个就是tty设备文件对应的操作方法集合,例如, 应用层调用open函数来打开该设备文件时将最终会走到serial_open里面.
usb_serial_init()还注册了一条总线: usb_serial_bus_type,这样当有设备连上系统时, 该总线上的驱动就有机会去匹配这个设备.后面我们会看到generic的驱动就是注册在该总线上的.
bus.c:
struct bus_type usb_serial_bus_type = {
.name = "usb-serial",
.match = usb_serial_device_match, //在设备匹配时会调用
.probe = usb_serial_device_probe,
.remove = usb_serial_device_remove,
};
关于设备匹配过程(probe)可以参考我的另一篇文章.
usb_serial_init()在最后usb_serial_generic_register(debug)来注册generic驱动.
generic.c:
int usb_serial_generic_register (int _debug)
{
int retval = 0;
debug = _debug;
#ifdef CONFIG_USB_SERIAL_GENERIC
generic_device_ids[0].idVendor = vendor; //保存厂商ID
generic_device_ids[0].idProduct = product; //保存产品ID
generic_device_ids[0].match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT; //匹配类型
/* register our generic driver with ourselves */
retval = usb_serial_register (&usb_serial_generic_device); //注册驱动
if (retval)
goto exit;
retval = usb_register(&generic_driver); //注册驱动
if (retval)
usb_serial_deregister(&usb_serial_generic_device);
exit:
#endif
return retval;
}
该函数首先保存了命令通过命令行设备的vendor,product用于以后设备匹配, 由此我们知道该驱动可以动态支持设备匹配.接着该函数注册了usb_serial_generic_device驱动.
generic.c:
struct usb_serial_driver usb_serial_generic_device = {
.driver = {
.owner = THIS_MODULE,
.name = "generic",
},
.id_table = generic_device_ids, //匹配用的设备列表,支持动态匹配
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
.shutdown = usb_serial_generic_shutdown,
};
Usb-serial.c:
int usb_serial_register(struct usb_serial_driver *driver)
{
int retval;
fixup_generic(driver); //为driver赋上默认的操作函数
if (!driver->description)
driver->description = driver->driver.name;
/* Add this device to our list of devices */
list_add(&driver->driver_list,& usb_serial_driver_list); //加入驱动列表
retval = usb_serial_bus_register(driver); //把该驱动注册进usb serial bus下
if (retval) {
err("problem %d when registering driver %s", retval, driver->description);
list_del(&driver->driver_list);
}
else
info("USB Serial support registered for %s", driver->description);
return retval;
}
其中的fixup_generic()函数仅仅是为driver赋上默认的操作函数.
Usb-serial.c:
#define set_to_generic_if_null(type, function) /
do { /
if (!type->function) { /
type->function = usb_serial_generic_##function; /
dbg("Had to override the " #function /
" usb serial operation with the generic one.");/
} /
} while (0)
static void fixup_generic(struct usb_serial_driver *device)
{
set_to_generic_if_null(device, open);
set_to_generic_if_null(device, write);
set_to_generic_if_null(device, close);
set_to_generic_if_null(device, write_room);
set_to_generic_if_null(device, chars_in_buffer);
set_to_generic_if_null(device, read_bulk_callback);
set_to_generic_if_null(device, write_bulk_callback);
set_to_generic_if_null(device, shutdown);
}
即通过上面的usb_serial_register()函数后usb_serial_generic_device的函数集为:
usb_serial_generic_device.open = usb_serial_generic_open;
usb_serial_generic_device.close = usb_serial_generic_close
......
驱动usb_serial_generic_device将是以后操作tty设备的主要函数.我们会在后面分析.
bus.c:
int usb_serial_bus_register(struct usb_serial_driver *driver)
{
int retval;
driver->driver.bus =& usb_serial_bus_type; //注册到该bus下
retval = driver_register(&driver->driver);
return retval;
}
最后usb_serial_generic_register()函数注册了一个generic_driver驱动.
generic.c:
static struct usb_driver generic_driver = {
.name = "usbserial_generic",
.probe = generic_probe, //匹配函数
.disconnect = usb_serial_disconnect,
.id_table = generic_serial_ids, //匹配用的设备列表
.no_dynamic_id = 1, //不支持动态匹配
};
整个初始化过程,乍一看一下子注册了几个驱动程序, 几个驱动列表, 有的支持动态匹配有的不支持,感觉很复杂, 其实注册generic_driver驱动主要是为了注册一个generic_probe函数,而该函数将会在设备连上系统后被调用以来匹配设备.除此之外该驱动没什么用, 而在这个初始化函数中把vendor,product都保存在了generic_device_ids里,因此可以肯定以后的匹配将用这个设备列表,而不是generic_serial_ids,说的更直白些generic_serial_ids其实根本也没什么用. 真正有用的是usb_serial_generic_device驱动,
- usb_serial部分分析2
- usb_serial部分分析3
- usb_serial部分分析4
- usb_serial部分分析5
- usb_serial之repllog.exe不能自启动
- read-atleap-Hibernate部分分析2-CreateNews
- 第 2 部分 设计模式分析
- cocos2dx 音频模块分析(2): 音效部分
- icesword 驱动部分分析
- Icesword驱动部分分析
- Icesword 驱动部分分析
- icesword 驱动部分分析
- 第三部分 需求分析
- lighting sensor 部分分析
- 吃豆人部分代码分析
- listview 部分代码分析
- apache网络部分分析
- spring部分源码分析
- Appium的安装教程
- android interpolator 插值器
- C++__类与对象
- Java经典面试套路讲解:Java Killer系列
- spring使用aop时需要设置proxy-target-class="true" 否则无法依赖注入
- usb_serial部分分析2
- QT5.7下载安装
- jsp学习3-自定义标签
- hdu 1999
- 回文数
- POP默认支持三种动画 但同时也支持自定义动画
- 关于二叉树
- mysql高可用方案对比
- 科技公司都变成了数据公司:但你真的了解什么是“数据工程师”吗?