linux ------ USB设备驱动

来源:互联网 发布:淘宝店铺提升信誉 编辑:程序博客网 时间:2024/05/01 11:52

     USB是通用串行接口,具有USB接口的设备很多,比如U盘,MP3,PC CAMERA等。USB分主机端与设备端,在LINUX系统里面,在USB主机端集成了一个根HUB和主控制器,系统启动的时候会对根HUB与主控制器进行牧举并加载驱动,然后会启动一个守护进程专门监视控制器总线上的变化,如果有新的设备接入,该守护进程就会被调用并对设备进行枚举,然后会产生一个热插拔的事件。LINUX内核已经写好USB HUB与主控制器的代码,不需驱动程序员进行修改,驱动程序员只需理解设备端的程序与架构,写USB设备驱动程序。

    一. USB设备架构简单描述

         在USB传输过程中,总线上流动的数据是按照包来解释的,各种包又由协议所定义的基本域构成,不同的包构成传输事务,一个或多个事务可以完成用户所需要的传输。

         USB协议定义的一些基本单位包括:域,包,事务,数据传输类型,USB中描述符,USB数据流模型等。

         域:USB协议定义了一系列有统一解释的二进制序列,这些序列称为域。分为:同步域、标识域、地址域、端点域、帧号域、数据域、校验域。

         包:包是USB的基本数据单元,由一系列的域组成。USB中的包类型有:令牌包、数据包、握手包、特殊包。

         事务:事务是某种传输类型的一次实例,多次事务完成用户指定的传输。USB的事务有:IN事务、OUT事务、SETUP事务。

         数据传输类型:USB协议寇义了四种数据传输类型,即控制传输、中断传输、批量传输和同步传输。

        描述符:USB作为一种总线本身只是一种传输通道,并不能完成特殊的功能,它需要集成到设备上。而USB设备的接入不需要人工来于预,所以必须事先规定若干描述
符来标识设备的功能和配置,这样在主机端枚举并配置完设备后才能匹配适当的主机端驱动程序。USB的描述符号有:设备描述符、配置描述符、接口描述符、端点描述符号、字符串描述符。

        数据流模型:USB的数据流模型摘述了USB总线上的数据包是如何在主机和设备之间传递的。数据流模型涉及两个概念:端口和管道。

        在PC上设备驱动程序通过调用USBD,发出输入输出请求包URB,USB驱动程序接到请求后,调用主控制驱动程序接口HCD,将URB转换为USB的传输。根据数据量的大小,一个URB可以包含一个或多个USB传输,然后主控制器驱动程序将USBB传输分解为总线事务,主控制器以包的形式把数据传给设备。

        讲了这个USB相关的基本元素,有点抽象,可以简单概括一下,USB系统架构实际就是包括USB主控制器,USB HUB总线,USB 设备3部分,而域、包、事务、传输类型、描述符与数据流模型把它们联系组成一个整体,保证它们之间的正常运作。可以把USB通信系统比喻为一个物流系统,USB控制器就是需要快递服务的买家,USB HUB总线是物流的高速公路,USB设备就是快递派送的目的地。域、包是物流快递的具体物体,包好比就是一个包裹,域是包裹上的标签信息,比如收件人名字、地址等。事务就是一次快递的执行,比如发快递,收快递,或快递打包。传输类型可以比喻为快递派送中的具体派送方式,控制、中断传输就好比是用电动车或面包车短途内把包裹送过去,批量、同步传输就是用大卡车或火车把大量的包裹运到目的地。描述符可以比喻为物流快递过程中某个环节的描述,设备描述符可以比喻为“快递公司顺丰需要把顾客A的物品N送到目的地D"等。数据流模型URB可以为快递员+快递工具,比如快递员A与他的电动车,或大卡车与派送司机。

    二. 相关数据结构

        1. USB端点描述符usb_endpoint_descriptor

             struct usb_endpoint_descriptor{
                      __u8  bLength;                                    //描述符长度
                      __u8  bDescriptorType;                     //描述符类型
                      __u8  bEndpointAddress;                 //端点地址,包含端点方向的信息
                      __u8  bmAttributes;                           //端点类型,中断、控制、批量或同步中的一种
                      __le16 wMaxPacketSize;//端点一次处理的最大字节数。发送的BULK 包能大于这个数值,但会被分割传送。
                      __u8  bInterval;      //如果端点是中断类型,该值是端点的间隔设置,以毫秒为单位。
                      /* NOTE:  these two are _only_ in audio endpoints. */
                      /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
                      __u8  bRefresh;
                      __u8  bSynchAddress;
               } __attribute__ ((packed));     //这行表示取消字节对齐的优化,用该结构实际的字节数。

        2. USB接口描述符usb_interface

             struct usb_interface{
                     struct usb_host_interface *altsetting;             //接口设置数组指针,一个接口有多个设置
                     struct usb_host_interface *cur_altsetting; /* the currently active alternate setting */ //当前活动的设置
                     unsigned num_altsetting; /* number of alternate settings *///接口设置总数
                     struct usb_interface_assoc_descriptor *intf_assoc; 
                     int minor;   /* minor number this interface is bound to */     //次设备号
                     enum usb_interface_condition condition;  /* state of binding */
                     unsigned sysfs_files_created:1; /* the sysfs attributes exist */
                     unsigned ep_devs_created:1; /* endpoint "devices" exist */
                     unsigned unregistering:1; /* unregistration is in progress */
                     unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */
                     unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */
                     unsigned needs_binding:1; /* needs delayed unbind/rebind */
                     unsigned reset_running:1;
                     unsigned resetting_device:1; /* true: bandwidth alloc after reset */
                     struct device dev;  /* interface specific device info */   //接口相关的设备信息
                     struct device *usb_dev;     //相关的USB设备
                     atomic_t pm_usage_cnt;  /* usage counter for autosuspend */
                     struct work_struct reset_ws; /* for resets in atomic context */
             };

        3. USB设备描述符usb_device

            struct usb_device {
                   int  devnum;               //USB设备在总线上的编号
                   char  devpath[16];     //设备信息
                   u32  route;
                   enum usb_device_state state;       //设备状态
                   enum usb_device_speed speed;  //设备速度
                   struct usb_tt *tt;
                   int  ttport;
                   unsigned int toggle[2];
                   struct usb_device *parent;          //父设备
                   struct usb_bus *bus;                   //总线指针
                   struct usb_host_endpoint ep0;  //端点0
                   struct device dev;    //设备对象
                   struct usb_device_descriptor descriptor;
                   struct usb_host_bos *bos;
                   struct usb_host_config *config;    //拥有的所有配置
                   struct usb_host_config *actconfig;  //当前活动的配置
                   struct usb_host_endpoint *ep_in[16];  //最多支持15个端点
                   struct usb_host_endpoint *ep_out[16];
                   char **rawdescriptors;
                   unsigned short bus_mA;
                   u8 portnum;
                   u8 level;
                   unsigned can_submit:1;
                   unsigned persist_enabled:1;
                   unsigned have_langid:1;
                   unsigned authorized:1;
                   unsigned authenticated:1;
                   unsigned wusb:1;
                   unsigned lpm_capable:1;
                   unsigned usb2_hw_lpm_capable:1;
                   unsigned usb2_hw_lpm_enabled:1;
                   int string_langid;
                   char *product;
                   char *manufacturer;
                   char *serial;
                   struct list_head filelist;
                   #ifdef CONFIG_USB_DEVICE_CLASS
                            struct device *usb_classdev;
                   #endif
                   #ifdef CONFIG_USB_DEVICEFS
                            struct dentry *usbfs_dentry;
                   #endif
                   #if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
                            u8 otgdevice;    /*device is otg type */
                            u8 otgstate;
                            void *otgpriv;
                            void (*otg_notif) (void *otg_priv, unsigned long notif, unsigned long data);
                            void *hcd_priv;
                            void (*hcd_suspend) (void *hcd_priv);
                   #endif
                   int maxchild;
                   struct usb_device **children;
                   u32 quirks;
                   atomic_t urbnum;
                   unsigned long active_duration;
                   #ifdef CONFIG_PM
                            unsigned long connect_time;
                            unsigned do_remote_wakeup:1;
                            unsigned reset_resume:1;
                   #endif
                   struct wusb_dev *wusb_dev;
                   int slot_id;
                   enum usb_device_removable removable;
             };

        4. USB驱动usb_driver

             struct usb_driver {
                     const char *name;            //USB驱动名称
                     int (*probe) (struct usb_interface *intf, const struct usb_device_id *id); //USB探测函数,USB子系统会根据PID/UID的组合来区别设备进而调用这个函数
                     void (*disconnect) (struct usb_interface *intf);//断开连接的处理,当设备从HUB上拔出时,USB子系统调用这个函数
                     int (*unlocked_ioctl) (struct usb_interface *intf, unsigned int code, void *buf);
                     int (*suspend) (struct usb_interface *intf, pm_message_t message);
                     int (*resume) (struct usb_interface *intf);
                     int (*reset_resume)(struct usb_interface *intf);
                     int (*pre_reset)(struct usb_interface *intf);
                     int (*post_reset)(struct usb_interface *intf);
                     const struct usb_device_id *id_table;     //设备ID表,由PID/VID组成
                     struct usb_dynids dynids;
                     struct usbdrv_wrap drvwrap;
                     unsigned int no_dynamic_id:1;
                     unsigned int supports_autosuspend:1;
                     unsigned int soft_unbind:1;
             };

        5. USB class驱动usb_class_driver

             struct usb_class_driver{
                     char *name;        //class 驱动名称
                     char *(*devnode)(struct device *dev, umode_t *mode);  
                     const struct file_operations *fops;   //文件操作集
                     int minor_base;   //次设备号基准值
             };

        6. URB数据结构

             struct urb {
                    struct kref kref;  /* reference count of the URB */    //URB引用计数
                    void *hcpriv;   /* private data for host controller */ //host控制器私有数据
                    atomic_t use_count;  /* concurrent submissions counter *///当前提交计数
                    atomic_t reject;  /* submissions will fail */ //提交失败计数
                    int unlinked;   /* unlink error code */  //连接失败代码
                    struct list_head urb_list; /* list head for use by the urb's current owner *///URB链表
                    struct list_head anchor_list; /* the URB may be anchored */
                    struct usb_anchor *anchor;
                    struct usb_device *dev;  /* (in) pointer to associated device *///指向这个urb要发送的目标设备的指针,这个变量必须在urb被发送到USB核心之前被初始化
                    struct usb_host_endpoint *ep; /* (internal) pointer to endpoint *///端点指针
                    unsigned int pipe;  /* (in) pipe information */  //管道号码,该管道记录了目标设备的端点及管道的类型。
                    unsigned int stream_id;  /* (in) stream ID */
                    int status;   /* (return) non-ISO status */ //记录数据传输的有关状态,传送成功和否,成功的话会是0。
                    unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*///传输设置
                    void *transfer_buffer;  /* (in) associated data buffer */ //传输数据缓存区,为了主机控制器驱动正确访问这个缓冲, 使用 kmalloc 调用来创建。
                    dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */ //DMA传输数据缓存区
                    struct scatterlist *sg;  /* (in) scatter gather buffer list */
                    int num_mapped_sgs;  /* (internal) mapped sg entries */
                    int num_sgs;   /* (in) number of entries in the sg list */
                    u32 transfer_buffer_length; /* (in) data buffer length */   //传输数据长度
                    u32 actual_length;  /* (return) actual transfer length */   //实际传输的长度
                    unsigned char *setup_packet; /* (in) setup packet (control only) */ //指向控制urb的设置数据包指针
                    dma_addr_t setup_dma;  /* (in) dma addr for setup_packet */ //控制 urb 用于设置数据包的 DMA 缓冲区地址
                    int start_frame;  /* (modify) start frame (ISO) */ //设置或返回初始的帧数量
                    int number_of_packets;  /* (in) number of ISO packets */
                    int interval;   /* (modify) transfer interval(INT/ISO) */
                    int error_count;  /* (return) number of ISO errors */ //等时urb的错误计数,由USB核心设置
                    void *context;   /* (in) context for completion *///指向一个可以被USB驱动模块设置的数据块. 当 urb 被返回到驱动时,可在结束处理例程中使用
                    usb_complete_t complete; /* (in) completion routine *///结束处理例程函数指针, 当 urb 被完全传送或发生错误,它将被 USB 核心调用. 
                    struct usb_iso_packet_descriptor iso_frame_desc[0]; /* (in) ISO ONLY */
             };

    三. USB设备处理函数

          1. 创建URB,usb_alloc_urb

               struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
               {
                      struct urb *urb;
                      urb = kmalloc(sizeof(struct urb) + iso_packets * sizeof(struct usb_iso_packet_descriptor), mem_flags);
                      if (!urb) {
                            printk(KERN_ERR "alloc_urb: kmalloc failed\n");
                            return NULL;
                      }
                      usb_init_urb(urb);
                      return urb;
               }

               iso_packets: urb 所包含的等时数据包的个数,若不是等时传输,则为0.

           mem_flags: 内存分配标识, 如GFP_KERNEL。

          2. 初始化URB

               (1). 中断URB

                      static inline void usb_fill_int_urb(struct urb *urb,
                                 struct usb_device *dev,
                                 unsigned int pipe,
                                 void *transfer_buffer,
                                 int buffer_length,
                                 usb_complete_t complete_fn,
                                 void *context,
                                 int interval)
                     {
                             urb->dev = dev;
                             urb->pipe = pipe;
                             urb->transfer_buffer = transfer_buffer;
                             urb->transfer_buffer_length = buffer_length;
                             urb->complete = complete_fn;
                             urb->context = context;
                             if (dev->speed == USB_SPEED_HIGH || dev->speed == USB_SPEED_SUPER)
                                    urb->interval = 1 << (interval - 1);
                             else
                                    urb->interval = interval;
                             urb->start_frame = -1;
                      }

               (2). 批量URB

                      static inline void usb_fill_bulk_urb(struct urb *urb,
                                  struct usb_device *dev,
                                  unsigned int pipe,
                                  void *transfer_buffer,
                                  int buffer_length,
                                  usb_complete_t complete_fn,
                                  void *context)
                      {
                              urb->dev = dev;
                              urb->pipe = pipe;
                              urb->transfer_buffer = transfer_buffer;
                              urb->transfer_buffer_length = buffer_length;
                              urb->complete = complete_fn;
                              urb->context = context;
                      }

               (3). 控制URB

                      static inline void usb_fill_control_urb(struct urb *urb,
                                  struct usb_device *dev,
                                  unsigned int pipe,
                                  unsigned char *setup_packet,
                                  void *transfer_buffer,
                                  int buffer_length,
                                  usb_complete_t complete_fn,
                                  void *context)
                     {
                              urb->dev = dev;
                              urb->pipe = pipe;
                              urb->setup_packet = setup_packet;
                              urb->transfer_buffer = transfer_buffer;
                              urb->transfer_buffer_length = buffer_length;
                              urb->complete = complete_fn;
                              urb->context = context;
                     }

          3. 提交URB

               int usb_submit_urb(struct urb *urb, gfp_t mem_flags);

          4. 释放URB

               void usb_free_urb(struct urb *urb)
               {
                      if (urb)
                      kref_put(&urb->kref, urb_destroy);
               }

          5. 注册USB class

               int usb_register_dev(struct usb_interface *intf, struct usb_class_driver *class_driver);

          6. 注销USB class

               void usb_deregister_dev(struct usb_interface *intf, struct usb_class_driver *class_driver)
               {
                      if (intf->minor == -1)
                             return;
                      dbg ("removing %d minor", intf->minor);
                      down_write(&minor_rwsem);
                      usb_minors[intf->minor] = NULL;
                      up_write(&minor_rwsem);
                      device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
                      intf->usb_dev = NULL;
                      intf->minor = -1;
                      destroy_usb_class();
               }

    四. USB设备驱动编写流程及简单例子描述 

          1. 包含头文件

               #include <linux/kref.h>

               #include <linux/usb.h>

          2. 定义及初始化USB设备私有数据结构

              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 */
                       struct usb_anchor submitted;  /* in case we need to retract our submissions */
                       struct urb  *bulk_in_urb;  /* the urb to read data with */
                       unsigned char           *bulk_in_buffer; /* the buffer to receive data */
                       size_t   bulk_in_size;  /* the size of the receive buffer */
                       size_t   bulk_in_filled;  /* number of bytes in the buffer */
                       size_t   bulk_in_copied;  /* already copied to user space */
                       __u8   bulk_in_endpointAddr; /* the address of the bulk in endpoint */
                       __u8   bulk_out_endpointAddr; /* the address of the bulk out endpoint */
                       int   errors;   /* the last request tanked */
                       bool   ongoing_read;  /* a read is going on */
                       bool   processed_urb;  /* indicates we haven't processed the urb */
                       spinlock_t  err_lock;  /* lock for errors */
                       struct kref  kref;
                       struct mutex  io_mutex;  /* synchronize I/O with disconnect */
                       struct completion bulk_in_completion; /* to wait for an ongoing read */
                 };
                #define to_skel_dev(d) container_of(d, struct usb_skel, kref)

          3. 定义file_operations操作集并显示成员函数

               static const struct file_operations skel_fops= {
                       .owner = THIS_MODULE,
                       .read =  skel_read,
                       .write = skel_write,
                       .open =  skel_open,
                       .release = skel_release,
                       .flush = skel_flush,
                       .llseek = noop_llseek,
               };

               static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
               {

               }

               static ssize_t skel_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos)
               {

                     ......

                     /* create a urb, and a buffer for it, and copy the data to the urb */
                     urb = usb_alloc_urb(0, GFP_KERNEL);
                     if (!urb) {
                           retval = -ENOMEM;
                           goto error;
                     }
                     buf = usb_alloc_coherent(dev->udev, writesize, GFP_KERNEL,urb->transfer_dma);
                     if (!buf) {
                           retval = -ENOMEM;
                           goto error;
                     }
                     if (copy_from_user(buf, user_buffer, writesize)) {
                            retval = -EFAULT;
                            goto error;
                      }

                      /* initialize the urb properly */
                      usb_fill_bulk_urb(urb, dev->udev,
                                  usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
                                  buf, writesize, skel_write_bulk_callback, dev);
                      urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
                      usb_anchor_urb(urb, &dev->submitted);
                      retval = usb_submit_urb(urb, GFP_KERNEL);
                      usb_free_urb(urb);
              error:
                      if (urb) {
                               usb_free_coherent(dev->udev, writesize, buf, urb->transfer_dma);
                               usb_free_urb(urb);
                      }

               }

               static int skel_open(struct inode *inode, struct file *file)
               {
                      struct usb_skel *dev;
                      struct usb_interface *interface;
                      int subminor;
                      int retval = 0;
                      subminor = iminor(inode);
                      interface = usb_find_interface(&skel_driver, subminor);
                      if (!interface) {
                             retval = -ENODEV;
                             goto exit;
                      }
                      dev = usb_get_intfdata(interface);
                      if (!dev) {
                             retval = -ENODEV;
                             goto exit;
                      }
                      kref_get(&dev->kref);
                      mutex_lock(&dev->io_mutex);
                      retval = usb_autopm_get_interface(interface);
                      if (retval)
                           goto out_err;
                      file->private_data = dev;
                      mutex_unlock(&dev->io_mutex);
                exit:
                      return retval;
                }

                static int skel_release(struct inode *inode, struct file *file)
                {
                       struct usb_skel *dev;
                       dev = file->private_data;
                       if (dev == NULL)
                              return -ENODEV;
                       mutex_lock(&dev->io_mutex);
                       if (dev->interface)
                             usb_autopm_put_interface(dev->interface);
                       mutex_unlock(&dev->io_mutex);
                       kref_put(&dev->kref, skel_delete);
                       return 0;
                }

                static int skel_flush(struct file *file, fl_owner_t id)
                {
                       struct usb_skel *dev;
                       int res;
                       dev = file->private_data;
                       if (dev == NULL)
                             return -ENODEV;
                       mutex_lock(&dev->io_mutex);
                       skel_draw_down(dev);
                       spin_lock_irq(&dev->err_lock);
                       res = dev->errors ? (dev->errors == -EPIPE ? -EPIPE : -EIO) : 0;
                       dev->errors = 0;
                       spin_unlock_irq(&dev->err_lock);
                       mutex_unlock(&dev->io_mutex);
                       return res;
                }

          4. 定义usb_class_driver并初始化结构

              static struct usb_class_driverskel_class= {
                     .name =  "skel%d",
                     .fops =  &skel_fops,
                     .minor_base = USB_SKEL_MINOR_BASE,
               };

          5. 定义usb_driver结构并实现具体的成员函数

              static struct usb_driver skel_driver= {
                     .name =  "skeleton",
                     .probe = skel_probe,
                     .disconnect = skel_disconnect,
                     .suspend = skel_suspend,
                     .resume = skel_resume,
                     .pre_reset = skel_pre_reset,
                     .post_reset = skel_post_reset,
                     .id_table = skel_table,
                     .supports_autosuspend = 1,
                };

                static int skel_probe(struct usb_interface *interface, const struct usb_device_id *id)
                {
                        struct usb_skel *dev;
                        struct usb_host_interface *iface_desc;
                        struct usb_endpoint_descriptor *endpoint;
                        size_t buffer_size;
                        int i;
                        int retval = -ENOMEM;
                        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
                        kref_init(&dev->kref);
                        sema_init(&dev->limit_sem, WRITES_IN_FLIGHT);
                        mutex_init(&dev->io_mutex);
                        spin_lock_init(&dev->err_lock);
                        init_usb_anchor(&dev->submitted);
                        init_completion(&dev->bulk_in_completion);
                        dev->udev = usb_get_dev(interface_to_usbdev(interface));
                        dev->interface = interface;
                        iface_desc = interface->cur_altsetting;
                        for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
                                endpoint = &iface_desc->endpoint[i].desc;
                                if (!dev->bulk_in_endpointAddr && usb_endpoint_is_bulk_in(endpoint)) {
                                       buffer_size = usb_endpoint_maxp(endpoint);
                                       dev->bulk_in_size = buffer_size;
                                       dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
                                       dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
                                       dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL);
                                }
                                if (!dev->bulk_out_endpointAddr && usb_endpoint_is_bulk_out(endpoint)) {
                                       dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
                                }
                         }
                         if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
                                goto error;
                         }
                         usb_set_intfdata(interface, dev);
                         retval = usb_register_dev(interface, &skel_class);
                         if (retval) {
                                 usb_set_intfdata(interface, NULL);
                                 goto error;
                         }
                         dev_info(&interface->dev,
                                          "USB Skeleton device now attached to USBSkel-%d",
                                           interface->minor);
                         return 0;
                  error:
                         if (dev)
                                kref_put(&dev->kref, skel_delete);
                         return retval;
                  }

                  static void skel_disconnect(struct usb_interface *interface)
                  {
                          struct usb_skel *dev;
                          int minor = interface->minor;
                          dev = usb_get_intfdata(interface);
                          usb_set_intfdata(interface, NULL);
                          usb_deregister_dev(interface, &skel_class);
                          mutex_lock(&dev->io_mutex);
                          dev->interface = NULL;
                          mutex_unlock(&dev->io_mutex);
                          usb_kill_anchored_urbs(&dev->submitted);
                          kref_put(&dev->kref, skel_delete);
                          dev_info(&interface->dev, "USB Skeleton #%d now disconnected", minor);
                  }

                  static int skel_suspend(struct usb_interface *intf, pm_message_t message)
                  {
                          struct usb_skel *dev = usb_get_intfdata(intf);
                          if (!dev)
                                return 0;
                          skel_draw_down(dev);
                          return 0;
                  }

                  static int skel_resume(struct usb_interface *intf)
                  {
                          return 0;
                  }

                  static int skel_pre_reset(struct usb_interface *intf)
                  {
                          struct usb_skel *dev = usb_get_intfdata(intf);
                          mutex_lock(&dev->io_mutex);
                          skel_draw_down(dev);
                          return 0;
                 }

                 static int skel_post_reset(struct usb_interface *intf)
                 {
                          struct usb_skel *dev = usb_get_intfdata(intf);
                          dev->errors = -EPIPE;
                          mutex_unlock(&dev->io_mutex);
                          return 0;
                 }

                 static const struct usb_device_id skel_table[] = {
                        { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
                        { }
                 };

          6. 在probe函数中调用usb_register_dev注册USB class

               retval = usb_register_dev(interface, &skel_class);

          7. 调用module_usb_driver注册usb driver

               module_usb_driver(skel_driver);

0 0
原创粉丝点击