25.2.4 USB驱动程序框架

2019-07-13 01:58发布

http://book.51cto.com/art/200912/169140.htm
《ARM嵌入式Linux系统开发详解》第25章USB驱动开发,本章讲解了Linux内核USB驱动体系结构、USB设备驱动结构等知识,并在最后给出了两个USB设备驱动开发实例。本节为大家介绍USB驱动程序框架。 AD:2014WOT全球软件技术峰会北京站 课程视频发布 25.2.4  USB驱动程序框架 Linux内核代码driver/usb/usb-skeleton.c文件是一个标准的USB设备驱动程序。编写一个USB设备的驱动可以参考usb-skeleton.c文件,实际上,可以直接修改该文件驱动新的USB设备。下面以usb-skeleton.c文件为例分析usb-skel设备驱动框架。 1.基本数据结构 usb-skel设备使用自定义结构usb_skel记录设备驱动用到的所有描述符,该结构定义如下:
  1. struct usb_skel {  
  2.     struct usb_device * udev;           /* the usb device for 
    this device */                                                
    // USB设备描述符  
  3.     struct usb_interface *  interface;      /* the 
    interface for this device 
     
  4.     */                                             
    // USB接口描述符  
  5.     struct semaphore    limit_sem;      /* limiting 
    the number of writes in   
  6.     progress */                                    
    // 互斥信号量  
  7.     unsigned char *     bulk_in_buffer;     /* the 
    buffer to receive data */

    // 数据接收缓冲区  
  8.     size_t          bulk_in_size;       /* the size 
    of the receive buffer */

    // 数据接收缓冲区大小  
  9.     __u8            bulk_in_endpointAddr;   /* the 
    address of the bulk in   
  10.     endpoint */                                    
    // 入端点地址  
  11.     __u8            bulk_out_endpointAddr;  /* the 
    address of the bulk out  endpoint */                       
    // 出端点地址  
  12.     struct kref     kref;  
  13. }; 
usb-skel设备驱动把usb_skel结构存放在了urb结构的context指针里。通过urb,设备的所有操作函数都可以访问到usb_skel结构。其中,limit_sem成员是一个信号量,当多个usb-skel类型的设备存在于系统中的时候,需要控制设备之间的数据同步。 2.驱动程序初始化和注销 与其他所有的Linux设备驱动程序一样,usb-skel驱动使用module_init()宏设置初始化函数,使用module_exit()宏设置注销函数。usb-skel驱动的初始化函数是usb_skel_init()函数,定义如下:
  1. static int __init usb_skel_init(void)  
  2. {  
  3.        int result;  
  4.  
  5.        /* register this driver with the USB subsystem */  
  6.        result = usb_register(&skel_driver);     // 注册USB设备驱动  
  7.        if (result)  
  8.               err("usb_register failed. Error number %d", result);  
  9.  
  10.        return result;  
usb_skel_init()函数调用内核提供的usb_register()函数注册了一个usb_driver类型的结构变量,该变量定义如下:
  1. static struct usb_driver skel_driver = {  
  2.        .name =      "skeleton",             // USB设备名称  
  3.        .probe = skel_probe,                 // USB设备初始化函数  
  4.        .disconnect =    skel_disconnect,    // USB设备注销函数  
  5.        .id_table =  skel_table,             // USB设备ID映射表  
  6. }; 
skel_driver结构变量中,定义了usb-skel设备的名、设备初始化函数、设备注销函数和USB ID映射表。其中usb-skel设备的USB ID映射表定义如下:
  1. static struct usb_device_id skel_table [] = {  
  2.        { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },  
  3.        { }                  /* Terminating entry */  
  4. }; 
skel_table中只有一项,定义了一个默认的usb-skel设备的ID。其中,USB_SKEL_VENDOR_ID是USB设备的厂商ID,USB_SKEL_PRODUCT_ID是USB设备ID。 注销函数的操作比较简单,调用usb_deregister()函数注销usb-skel设备驱动,函数定义如下:
  1. static void __exit usb_skel_exit(void)  
  2. {  
  3.        /* deregister this driver with the USB subsystem */  
  4.        usb_deregister(&skel_driver);    // 注销USB设备  
3.设备初始化 从skel_driver结构可以知道usb-skel设备的初始化函数是skel_probe()函数。设备初始化主要是探测设备类型,分配USB设备用到的urb资源,注册USB设备操作函数等。skel_class结构变量记录了usb-skel设备信息,定义如下:
  1. static struct usb_class_driver skel_class = {  
  2.        .name =      "skel%d",       // 设备名称  
  3.        .fops =      &skel_fops,     // 设备操作函数  
  4.        .minor_base =    USB_SKEL_MINOR_BASE,  
  5. }; 
name变量使用%d通配符表示一个整型变量,当一个usb-skel类型的设备连接到USB总线后会按照子设备编号自动设置设备名称。fops是设备操作函数结构变量,定义如下:
  1. static struct file_operations skel_fops = {  
  2.        .owner = THIS_MODULE,  
  3.        .read =      skel_read,      // 读操作  
  4.        .write = skel_write,         // 写操作  
  5.        .open =      skel_open,      // 打开操作  
  6.        .release =   skel_release,   // 关闭操作  
  7. }; 
skel_ops定义了usb-skel设备的操作函数。当在usb-skel设备上发生相关事件时,USB文件系统会调用对应的函数处理。 4.设备注销 skel_disconnect()函数在注销设备的时候被调用,定义如下:
  1. static void skel_disconnect(struct usb_interface *interface)  
  2. {  
  3.        struct usb_skel *dev;  
  4.        int minor = interface->minor;  
  5.  
  6.        /* prevent skel_open() from racing skel_disconnect() */  
  7.        lock_kernel();                       // 在操作之前加锁  
  8.  
  9.        dev = usb_get_intfdata(interface);   // 获得USB设备接口描述  
  10.        usb_set_intfdata(interface, NULL);   // 设置USB设备接口描述无效  
  11.  
  12.        /* give back our minor */  
  13.        usb_deregister_dev(interface, &skel_class);  // 注销USB设备操作描述  
  14.  
  15.        unlock_kernel();                     // 操作完毕解锁  
  16.  
  17.        /* decrement our usage count */  
  18.        kref_put(&dev->kref, skel_delete);           // 减小引用计数  
  19.  
  20.        info("USB Skeleton #%d now disconnected", minor);  
skel_disconnect()函数释放usb-skel设备用到的资源。首先获取USB设备接口描述,之后设置为无效;然后调用usb_deregister_dev()函数注销USB设备的操作描述符,注销操作本身需要加锁;注销设备描述符后,更新内核对usb-skel设备的引用计数。