Linux USB驱动框架分析(三)

嵌入式技术

1372人已加入

描述


    下面分析一下usb-skeleton的源码。这个范例程序可以在linux-2.6.17/drivers/usb下找到,其他版本的内核程序源码可能有所不同,但相差不大。大家可以先找到源码看一看,先有个整体印象。

    之前已经提到,模块先要向内核注册初始化跟销毁函数:

static int __init usb_skel_init(void)

{

     int result;

     /* register this driver with the USB subsystem */

     result = usb_register(&skel_driver);

     if (result)

         err("usb_register failed. Error number %d", result);

     return result;

}

static void __exit usb_skel_exit(void)

{

     /* deregister this driver with the USB subsystem */

     usb_deregister(&skel_driver);

}

module_init (usb_skel_init);

module_exit (usb_skel_exit);

MODULE_LICENSE("GPL");

    从代码开来,这个initexit函数的作用只是用来注册驱动程序,这个描述驱动程序的结构体是系统定义的标准结构struct usb_driver,注册和注销的方法很简单,usb_registerstruct *usb_driver, usb_deregisterstruct *usb_driver。那这个结构体需要做些什么呢?他要向系统提供几个函数入口,跟驱动的名字:

static struct usb_driver skel_driver = {

     .name =      "skeleton",

     .probe =     skel_probe,

     .disconnect = skel_disconnect,

     .id_table =    skel_table,

};

    从代码看来,usb_driver需要初始化四个东西:模块的名字skeletonprobe函数skel_probe,disconnect函数skel_disconnect,以及id_table

    在解释skel_driver各个成员之前,我们先来看看另外一个结构体。这个结构体的名字有开发人员自定义,它描述的是该驱动拥有的所有资源及状态:

struct usb_skel {

     struct usb_device *      udev;                 /* the usb device for this device */

     struct usb_interface *   interface;            /* the interface for this device */

     struct semaphore       limit_sem;         /* limiting the number of writes in progress */

     unsigned char *         bulk_in_buffer;     /* the buffer to receive data */

     size_t         bulk_in_size;                  /* the size of the receive buffer */

     __u8          bulk_in_endpointAddr;        /* the address of the bulk in endpoint */

     __u8          bulk_out_endpointAddr;      /* the address of the bulk out endpoint */

     struct kref   kref;

};

    我们先来对这个usb_skel作个简单分析,他拥有一个描述usb设备的结构体udev,一个接口interface,用于并发访问控制的semaphore(信号量) limit_sem,用于接收数据的缓冲bulk_in_buffer及其尺寸bulk_in_size,然后是批量输入输出端口地址bulk_in_endpointAddrbulk_out_endpointAddr,最后是一个内核使用的引用计数器。他们的作用我们将在后面的代码中看到。

    我们再回过头来看看skel_driver

    name用来告诉内核模块的名字是什么,这个注册之后有系统来使用,跟我们关系不大。

    id_table用来告诉内核该模块支持的设备。usb子系统通过设备的production IDvendor ID的组合或者设备的classsubclassprotocol的组合来识别设备,并调用相关的驱动程序作处理。我们可以看看这个id_table到底是什么东西:

/* Define these values to match your devices */

#define USB_SKEL_VENDOR_ID  0xfff0

#define USB_SKEL_PRODUCT_ID 0xfff0

/* table of devices that work with this driver */

static struct usb_device_id skel_table [] = {

     { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },

     { }                    /* Terminating entry */

};

MODULE_DEVICE_TABLE (usb, skel_table); 

    MODULE_DEVICE_TABLE的第一个参数是设备的类型,如果是USB设备,那自然是usb(如果是PCI设备,那将是pci,这两个子系统用同一个宏来注册所支持的设备。这涉及PCI设备的驱动了,在此先不深究)。后面一个参数是设备表,这个设备表的最后一个元素是空的,用于标识结束。代码定义了USB_SKEL_VENDOR_ID0xfff0USB_SKEL_PRODUCT_ID0xfff0,也就是说,当有一个设备接到集线器时,usb子系统就会检查这个设备的vendor IDproduct ID,如果它们的值是0xfff0时,那么子系统就会调用这个skeleton模块作为设备的驱动。



打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 相关推荐

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分