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驱动,



原创粉丝点击