精华内容
下载资源
问答
  • linuxusb驱动
    万次阅读 多人点赞
    2016-03-26 15:10:13

        前面学习了USB驱动的一些基础概念与重要的数据结构,那么究竟如何编写一个USB 驱动程序呢?编写与一个USB设备驱动程序的方法和其他总线驱动方式类似,驱动程序把驱动程序对象注册到USB子系统中,稍后再使用制造商和设备标识来判断是否安装了硬件。当然,这些制造商和设备标识需要我们编写进USB 驱动程序中。

      USB 驱动程序依然遵循设备模型 —— 总线、设备、驱动。和I2C 总线设备驱动编写一样,所有的USB驱动程序都必须创建的主要结构体是 struct usb_driver,它们向USB 核心代码描述了USB 驱动程序。但这是个外壳,只是实现设备和总线的挂接,具体的USB 设备是什么样的,如何实现的,比如一个字符设备,我们还需填写相应的文件操作接口 ,下面我们从外到里进行剖析,学习如何搭建这样的一个USB驱动外壳框架:


    一、注册USB驱动程序

      Linux的设备驱动,特别是这种hotplug的USB设备驱动,会被编译成模块,然后在需要时挂在到内核。所以USB驱动和注册与正常的模块注册、卸载是一样的,下面是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");

          USB设备驱动的模块加载函数通用的方法是在I2C设备驱动的模块加载函数中使用usb_register(struct *usb_driver)函数添加usb_driver的工作,而在模块卸载函数中利用usb_deregister(struct *usb_driver)做相反的工作。 对比I2C设备驱动中的 i2c_add_driver(&i2c_driver)i2c_del_driver(&i2c_driver)

        struct usb_driver是USB设备驱动,我们需要实现其成员函数:

    static struct usb_driver skel_driver = {   
         .owner = THIS_MODULE,    
         .name = "skeleton",  
         .id_table = skel_table,       
         .probe = skel_probe,     
         .disconnect = skel_disconnect,     
    };    
    从代码看来,usb_driver需要初始化五个字段:

    模块的所有者 THIS_MODULE
    模块的名字  skeleton
    probe函数   skel_probe
    disconnect函数skel_disconnect

    id_table

        最重要的当然是probe函数与disconnect函数,这个在后面详细介绍,先谈一下id_table:

        id_table 是struct usb_device_id 类型,包含了一列该驱动程序可以支持的所有不同类型的USB设备。如果没有设置该变量,USB驱动程序中的探测回调该函数将不会被调用。对比I2C中struct i2c_device_id *id_table,一个驱动程序可以对应多个设备,i2c 示例:

    static const struct i2c_device_id mpu6050_id[] = {    
        { "mpu6050", 0},    
        {}    
    };  

        usb子系统通过设备的production ID和vendor ID的组合或者设备的class、subclass跟protocol的组合来识别设备,并调用相关的驱动程序作处理。我们可以看看这个id_table到底是什么东西:

    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。后面一个参数是 设备表这个设备表的最后一个元素是空的,用于标识结束。代码定义了USB_SKEL_VENDOR_ID是0xfff0,USB_SKEL_PRODUCT_ID是0xfff0,也就是说,当有一个设备接到集线器时,usb子系统就会检查这个设备的vendor ID和product ID,如果它们的值是0xfff0时,那么子系统就会调用这个skeleton模块作为设备的驱动。

       当USB设备接到USB控制器接口时,usb_core就检测该设备的一些信息,例如生产厂商ID和产品的ID,或者是设备所属的class、subclass跟protocol,以便确定应该调用哪一个驱动处理该设备
      
     

         我们下面所要做的就是对probe函数与disconnect函数的填充了,但是在对probe函数与disconnect函数填充之前,有必要先学习三个重要的数据结构,这在我们后面probe函数与disconnect函数中有很大的作用:

    二、USB驱动程序中重要数据结构

    1、usb-skeleton

           usb-skeleton 是一个局部结构体,用于与端点进行通信。下面先看一下Linux内核源码中的一个usb-skeleton(就是usb驱动的骨架咯),其定义的设备结构体就叫做usb-skel:

    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设备的结构体udev
    一个接口interface
    用于并发访问控制的semaphore(信号量) limit_sem
    用于接收数据的缓冲bulk_in_buffer
    用于接收数据的缓冲尺寸bulk_in_size
    批量输入端口地址bulk_in_endpointAddr
    批量输出端口地址bulk_out_endpointAddr

    内核使用的引用计数器


         从开发人员的角度看,每一个usb设备有若干个配置(configuration)组成,每个配置又可以有多个接口(interface)(我理解就是USB设备的一项功能),每个接口又有多个设置,而接口本身可能没有端点或者多个端点(end point)

    2、USB 接口数据结构 struct usb_interface

    struct usb_interface  
    {           
             struct usb_host_interface *altsetting;   
             struct usb_host_interface *cur_altsetting;        
             unsigned num_altsetting;           
             int minor;                        
             enum usb_interface_condition condition;           
             unsigned is_active:1;             
             unsigned needs_remote_wakeup:1;    
             struct device dev;                
             struct device *usb_dev;           
             int pm_usage_cnt;                 
    };  

           在逻辑上,一个USB设备的功能划分是通过接口来完成的。比如说一个USB扬声器,可能会包括有两个接口:一个用于键盘控制,另外一个用于音频流传输。而事实上,这种设备需要用到不同的两个驱动程序来操作,一个控制键盘,一个控制音频流。但也有例外,比如蓝牙设备,要求有两个接口,第一用于ACL跟EVENT的传输,另外一个用于SCO链路,但两者通过一个驱动控制。在Linux上,接口使用struct usb_interface来描述,以下是该结构体中比较重要的字段:

    a -- struct usb_host_interface *altsetting(注意不是usb_interface)

           其实据我理解,他应该是每个接口的设置,虽然名字上有点奇怪。该字段是一个设置的数组(一个接口可以有多个设置),每个usb_host_interface都包含一套由struct usb_host_endpoint定义的端点配置。但这些配置次序是不定的。

    b -- struct usb_host_interface *cur_altsetting

           当前活动的设置,指向altsetting数组中的一个

    struct usb_host_interface数据结构:

    struct usb_host_interface   
    {  
             struct usb_interface_descriptor desc;//usb描述符,主要有四种usb描述符,设备描述符,配置描述符,接口描述符和端点描述符,协议里规定一个usb设备是必须支持这四大描述符的。  
                                     //usb描述符放在usb设备的eeprom里边  
             /* array of desc.bNumEndpoint endpoints associated with this 
              * interface setting. these will be in no particular order. 
              */  
             struct usb_host_endpoint *endpoint;//这个设置所使用的端点  
      
             char *string;           /* iInterface string, if present */  
             unsigned char *extra;   /* Extra descriptors */关于额外描述符  
             int extralen;  
    };  

    c -- unsigned num_altstting

          可选设置的数量,即altsetting所指数组的元素个数

    d -- int minor

         当捆绑到该接口的USB驱动程序使用USB主设备号时,USB core分配的次设备号。仅在成功调用usb_register_dev之后才有效。  


    3、USB 端点 struct usb_host_endpoint

          Linux中用struct usb_host_endpoint 来描述USB端点

    struct usb_host_endpoint   
    {  
             struct usb_endpoint_descriptor desc;  
             struct list_head                urb_list;//端点要处理的urb队列.urb是usb通信的主角,设备中的每个端点都可以处理一个urb队列.要想和你的usb通信,就得创建一个urb,并且为它赋好值,  
                                       //交给咱们的usb core,它会找到合适的host controller,从而进行具体的数据传输  
             void                            *hcpriv;//这是提供给HCD(host controller driver)用的  
             struct ep_device                *ep_dev;        /* For sysfs info */  
      
             unsigned char *extra;   /* Extra descriptors */  
             int extralen;  
    };  

         每个usb_host_endpoint中包含一个struct usb_endpoint_descriptor结构体,当中包含该端点的信息以及设备自定义的各种信息,这些信息包括:

    a -- bEndpointAddress(b for byte)

           8位端点地址,其地址还隐藏了端点方向的信息(之前说过,端点是单向的),可以用掩码USB_DIR_OUT和USB_DIR_IN来确定。

    b -- bmAttributes

           端点的类型,结合USB_ENDPOINT_XFERTYPE_MASK可以确定端点是USB_ENDPOINT_XFER_ISOC(等时)、USB_ENDPOINT_XFER_BULK(批量)还是USB_ENDPOINT_XFER_INT(中断)。

    c -- wMaxPacketSize

           端点一次处理的最大字节数。发送的BULK包可以大于这个数值,但会被分割传送。

    d -- bInterval

           如果端点是中断类型,该值是端点的间隔设置,以毫秒为单位


    三、探测和断开函数分析

            USB驱动程序指定了两个USB核心在适当时间调用的函数。

    1、探测函数

            当一个设备被安装而USB核心认为该驱动程序应该处理时,探测函数被调用;

            探测函数应该检查传递给他的设备信息确定驱动程序是否真的适合该设备。当驱动程序因为某种原因不应控制设备时,断开函数被调用,它可以做一些清洁的工作。

          系统会传递给探测函数的信息是什么呢?一个usb_interface * 跟一个struct usb_device_id *作为参数。他们分别是该USB设备的接口描述(一般会是该设备的第0号接口,该接口的默认设置也是第0号设置)跟它的设备ID描述(包括Vendor ID、Production ID等)。

           USB驱动程序应该初始化任何可能用于控制USB设备的局部结构体,它还应该把所需的任何设备相关信息保存到局部结构体中。例如,USB驱动程序通常需要探测设备对的端点地址和缓冲区大小,因为需要他们才能和端点通信

           下面具体分析探测函数做了哪些事情:

    a -- 探测设备的端点地址、缓冲区大小,初始化任何可能用于控制USB设备的数据结构

           下面是一个实例代码,他们探测批量类型的IN和OUT端点,把相关信息保存到一个局部设备结构体中

    /* set up the endpoint information */   
         /* use only the first bulk-in and bulk-out endpoints */   
         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 &&   
                    ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) = = USB_DIR_IN) &&   
                 ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) = = USB_ENDPOINT_XFER_BULK)) {   
                 /* we found a bulk in endpoint */   
                  buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);   
                  dev->bulk_in_size = buffer_size;   
                  dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;   
                  dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);   
                  if (!dev->bulk_in_buffer) {   
                      err("Could not allocate bulk_in_buffer");   
                       goto error;                 
                  }
             }   
      
             if (!dev->bulk_out_endpointAddr &&   
                ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)= =USB_DIR_OUT) &&   
                   ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)= = USB_ENDPOINT_XFER_BULK)) {   
                  /* we found a bulk out endpoint */   
                  dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;   
             }   
         }   
      
         if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {   
             err("Could not find both bulk-in and bulk-out endpoints");   
             goto error;   
         }  

    具体流程如下:   

         该代码块首先循环访问该接口中存在的每一个端点,赋予该端点结构体的局部指针以使稍后的访问更加容易

    for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {   
             endpoint = &iface_desc->endpoint[i].desc; 

             然后,我们有了一个端点,而还没有发现批量IN类型的端点时,查看该端点的方向是否为IN。这可以通过检查位掩码 USB_DIR_IN 是否包含在bEndpointAddress 端点变量中来确定。如果是的话,我们测定该端点类型是否批量,这首先通过USB_ENDPOINT_XFERTYPE_MASK 位掩码来取bmAttributes变量的值,然后检查它是否和USB_ENDPOINT_XFER_BULK 的值匹配来完成

     if ( !dev->bulk_in_endpointAddr &&   
                    ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) = = USB_DIR_IN) &&   
                 ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) = = USB_ENDPOINT_XFER_BULK)) {   

           如果这些都通过了,驱动程序就知道它已经发现了正确的端点类型,可以把该端点相关的信息保存到一个局部结构体中,就是我们前面的usb_skel ,以便稍后使用它和端点进行通信

    /* we found a bulk in endpoint */   
                  buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);   
                  dev->bulk_in_size = buffer_size;   
                  dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;   
                  dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);   
                  if (!dev->bulk_in_buffer) {   
                      err("Could not allocate bulk_in_buffer");   
                       goto error;               
    	      }   


    b -- 把已经初始化数据结构的指针保存到接口设备中

          接下来的工作是向系统注册一些以后会用的的信息。首先我们来说明一下usb_set_intfdata()他向内核注册一个data,这个data的结构可以是任意的,这段程序向内核注册了一个usb_skel结构,就是我们刚刚看到的被初始化的那个,这个data可以在以后用usb_get_intfdata来得到

    usb_set_intfdata(interface, dev);


    c -- 注册USB设备

           如果USB驱动程序没有和处理设备与用户交互(例如输入、tty、视频等)的另一种类型的子系统相关联,驱动程序可以使用USB主设备号,以便在用户空间使用传统的字符驱动程序接口。如果要这样做,USB驱动程序必须在探测函数中调用 usb_resgister_dev 函数来把设备注册到USB核心。只要该函数被调用,就要确保设备和驱动陈旭都处于可以处理用户访问设备的要求的恰当状态

    retval = usb_register_dev(interface, &skel_class);

    skel_class结构。这个结构又是什么?我们就来看看这到底是个什么东西:

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

        它其实是一个系统定义的结构,里面包含了一名字、一个文件操作结构体还有一个次设备号的基准值。事实上它才是定义真正完成对设备IO操作的函数。所以他的核心内容应该是skel_fops。

       因为usb设备可以有多个interface,每个interface所定义的IO操作可能不一样,所以向系统注册的usb_class_driver要求注册到某一个interface,而不是device,因此,usb_register_dev的第一个参数才是interface,而第二个参数就是某一个usb_class_driver。

       通常情况下,linux系统用主设备号来识别某类设备的驱动程序,用次设备号管理识别具体的设备,驱动程序可以依照次设备号来区分不同的设备,所以,这里的次设备好其实是用来管理不同的interface的,但由于这个范例只有一个interface,在代码上无法求证这个猜想。

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


    2、断开函数

          当设备被拔出集线器时,usb子系统会自动地调用disconnect,他做的事情不多,最重要的是注销class_driver(交还次设备号)和interface的data:

    dev = usb_get_intfdata(interface);  
    usb_set_intfdata(interface, NULL);  
      
    /* give back our minor */  
    usb_deregister_dev(interface, &skel_class);  


    四、USB请求块

           USB 设备驱动代码通过urb和所有的 USB 设备通讯。urb用 struct urb 结构描述(include/linux/usb.h )。

           urb 以一种异步的方式同一个特定USB设备的特定端点发送或接受数据。一个 USB 设备驱动可根据驱动的需要,分配多个 urb 给一个端点或重用单个 urb 给多个不同的端点。设备中的每个端点都处理一个 urb 队列, 所以多个 urb 可在队列清空之前被发送到相同的端点。

     一个 urb 的典型生命循环如下:

     (1)被创建;
     (2)被分配给一个特定 USB 设备的特定端点;
     (3)被提交给 USB 核心;
     (4)被 USB 核心提交给特定设备的特定 USB 主机控制器驱动;
     (5)被 USB 主机控制器驱动处理, 并传送到设备;
     (6)以上操作完成后,USB主机控制器驱动通知 USB 设备驱动。

     
       urb 也可被提交它的驱动在任何时间取消;如果设备被移除,urb 可以被USB核心取消。urb 被动态创建并包含一个内部引用计数,使它们可以在最后一个用户释放它们时被自动释放。

    struct urb
    {
    	/* 私有的:只能由usb核心和主机控制器访问的字段 */
    	struct kref kref; /*urb引用计数 */
    	spinlock_t lock; /* urb锁 */
    	void *hcpriv; /* 主机控制器私有数据 */
    	int bandwidth; /* int/iso请求的带宽 */
    	atomic_t use_count; /* 并发传输计数 */
    	u8 reject; /* 传输将失败*/
    	
    	/* 公共的: 可以被驱动使用的字段 */
    	struct list_head urb_list; /* 链表头*/
    	struct usb_device *dev; /* 关联的usb设备 */
    	unsigned int pipe; /* 管道信息 */
    	int status; /* urb的当前状态 */
    	unsigned int transfer_flags; /* urb_short_not_ok | ...*/
    	void *transfer_buffer; /* 发送数据到设备或从设备接收数据的缓冲区 */
    	dma_addr_t transfer_dma; /*用来以dma方式向设备传输数据的缓冲区 */
    	int transfer_buffer_length;/*transfer_buffer或transfer_dma 指向缓冲区的大小 */
    	                     
    	int actual_length; /* urb结束后,发送或接收数据的实际长度 */
    	unsigned char *setup_packet; /* 指向控制urb的设置数据包的指针*/
    	dma_addr_t setup_dma; /*控制urb的设置数据包的dma缓冲区*/
    	int start_frame; /*等时传输中用于设置或返回初始帧*/
    	int number_of_packets; /*等时传输中等时缓冲区数据 */
    	int interval; /* urb被轮询到的时间间隔(对中断和等时urb有效) */
    	int error_count;  /* 等时传输错误数量 */
    	void *context; /* completion函数上下文 */
    	usb_complete_t complete; /* 当urb被完全传输或发生错误时,被调用 */
    	struct usb_iso_packet_descriptor iso_frame_desc[0];
    	/*单个urb一次可定义多个等时传输时,描述各个等时传输 */
    };


    1、创建和注销 urb

          struct urb 结构不能静态创建,必须使用 usb_alloc_urb 函数创建. 函数原型:

    struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags);
    //int iso_packets : urb 包含等时数据包的数目。如果不使用等时urb,则为0
    //gfp_t mem_flags : 与传递给 kmalloc 函数调用来从内核分配内存的标志类型相同

    //返回值          : 如果成功分配足够内存给 urb , 返回值为指向 urb 的指针. 如果返回值是 NULL, 则在 USB 核心中发生了错误, 且驱动需要进行适当清理


    如果驱动已经对 urb 使用完毕, 必须调用 usb_free_urb 函数,释放urb。函数原型:

    void usb_free_urb(struct urb *urb);
    //struct urb *urb : 要释放的 struct urb 指针


    2、初始化 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);
    
    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);
    
    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);
    
    
    //struct urb *urb :指向要被初始化的 urb 的指针
    //struct usb_device *dev :指向 urb 要发送到的 USB 设备.
    //unsigned int pipe : urb 要被发送到的 USB 设备的特定端点. 必须使用前面提过的 usb_******pipe 函数创建
    //void *transfer_buffer :指向外发数据或接收数据的缓冲区的指针.注意:不能是静态缓冲,必须使用 kmalloc 来创建.
    //int buffer_length :transfer_buffer 指针指向的缓冲区的大小
    //usb_complete_t complete :指向 urb 结束处理例程函数指针
    //void *context :指向一个小数据块的指针, 被添加到 urb 结构中,以便被结束处理例程函数获取使用.
    //int interval :中断 urb 被调度的间隔.
    //函数不设置 urb 中的 transfer_flags 变量, 因此对这个成员的修改必须由驱动手动完成
    
    /*等时 urb 没有初始化函数,必须手动初始化,以下为一个例子*/
    urb->dev = dev;
    urb->context = uvd;
    urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp-1);
    urb->interval = 1;
    urb->transfer_flags = URB_ISO_ASAP;
    urb->transfer_buffer = cam->sts_buf[i];
    urb->complete = konicawc_isoc_irq;
    urb->number_of_packets = FRAMES_PER_DESC;
    urb->transfer_buffer_length = FRAMES_PER_DESC;
    for (j=0; j < FRAMES_PER_DESC; j++) {
            urb->iso_frame_desc[j].offset = j;
            urb->iso_frame_desc[j].length = 1;
    }


    3、提交 urb

          一旦 urb 被正确地创建并初始化, 它就可以提交给 USB 核心以发送出到 USB 设备. 这通过调用函数 usb_submit_urb 实现:

    int usb_submit_urb(struct urb *urb, gfp_t mem_flags);
    //struct urb *urb :指向被提交的 urb 的指针 
    //gfp_t mem_flags :使用传递给 kmalloc 调用同样的参数, 用来告诉 USB 核心如何及时分配内存缓冲

    /*因为函数 usb_submit_urb 可被在任何时候被调用(包括从一个中断上下文), mem_flags 变量必须正确设置. 根据 usb_submit_urb 被调用的时间,只有 3 个有效值可用:
    GFP_ATOMIC 
    只要满足以下条件,就应当使用此值:
    1.调用者处于一个 urb 结束处理例程,中断处理例程,底半部,tasklet或者一个定时器回调函数.
    2.调用者持有自旋锁或者读写锁. 注意如果正持有一个信号量, 这个值不必要.
    3.current->state 不是 TASK_RUNNING. 除非驱动已自己改变 current 状态,否则状态应该一直是 TASK_RUNNING .

    GFP_NOIO 
    驱动处于块 I/O 处理过程中. 它还应当用在所有的存储类型的错误处理过程中.

    GFP_KERNEL 
    所有不属于之前提到的其他情况
    */


    在 urb 被成功提交给 USB 核心之后, 直到结束处理例程函数被调用前,都不能访问 urb 结构的任何成员.


    4、urb结束处理例程

          如果 usb_submit_urb 被成功调用, 并把对 urb 的控制权传递给 USB 核心, 函数返回 0; 否则返回一个负的错误代码. 如果函数调用成功, 当 urb 被结束的时候结束处理例程会被调用一次.当这个函数被调用时, USB 核心就完成了这个urb, 并将它的控制权返回给设备驱动.

    只有 3 种结束urb并调用结束处理例程的情况:

    (1)urb 被成功发送给设备, 且设备返回正确的确认.如果这样, urb 中的status变量被设置为 0.
    (2)发生错误, 错误值记录在 urb 结构中的 status 变量.
    (3)urb 从 USB 核心unlink. 这发生在要么当驱动通过调用 usb_unlink_urb 或者 usb_kill_urb告知 USB 核心取消一个已提交的 urb,或者在一个 urb 已经被提交给它时设备从系统中去除.

    5、取消 urb

    使用以下函数停止一个已经提交给 USB 核心的 urb:

    void usb_kill_urb(struct urb *urb)
    int usb_unlink_urb(struct urb *urb);

    如果调用usb_kill_urb函数,则 urb 的生命周期将被终止. 这通常在设备从系统移除时,在断开回调函数(disconnect callback)中调用.

    对一些驱动, 应当调用 usb_unlink_urb 函数来使 USB 核心停止 urb. 这个函数不会等待 urb 完全停止才返回. 这对于在中断处理例程中或者持有一个自旋锁时去停止 urb 是很有用的, 因为等待一个 urb 完全停止需要 USB 核心有使调用进程休眠的能力(wait_event()函数).



    更多相关内容
  • Linux USB驱动框架分析

    2021-01-20 14:54:58
    Linux USB驱动框架分析(一)  初次接触与OS相关的设备驱动编写,感觉还挺有意思的,为了不至于忘掉看过的东西,笔记跟总结当然不可缺,更何况我决定为嵌入式卖命了。好,言归正传,我说一说这段时间的收获,跟...
  • linux usb驱动

    2009-07-20 16:16:36
    usb驱动 linux驱动 usb驱动入门,很好的linux驱动入门资料!
  • linux驱动开发中文版,包括中断,DMA,PCI,USB,串并口,显示等
  • drivers/usb目录下面,host目录包括了host驱动代码,core目录包含了主要的api接口代码,而其他目录则主要是device驱动代码。 2、device驱动怎么看 device驱动大多数和上层协议有关,不涉及到具体的寄存器读写。示例...
  • SIM7600 USB驱动 linux

    2020-07-28 10:01:51
    开发环境 操作系统:OpenWrt(linux) 客户机:MT7688 拨号方式:NDIS------>wwan0
  • linux usb驱动详解

    千次阅读 2019-10-21 10:25:42
    如上图所示,从主机侧视角去看,在linux驱动中,usb驱动处于最上层,主要表现为usb主机侧的功能具体实现(比如U盘,鼠标,usb camer等),其下为usb核心层,主要完成usb驱动管理以及协议处理,再下为usb...

    一、USB驱动层次

    usb采用树形拓扑结构,可分为主机侧与设备侧,每一条USB总线上只有一个主机控制器,负责协调主机与设备之间的通讯,设备不能主动的向主机发送任何消息,如下图所示
    在这里插入图片描述
    如上图所示,从主机侧视角去看,在linux驱动中,usb驱动处于最上层,主要表现为usb主机侧的功能具体实现(比如U盘,鼠标,usb camer等),其下为usb核心层,主要完成usb驱动管理以及协议处理,再下为usb主机控制器,主要提供usb控制器的API,维护整个usb系统,完成设备的热插拔,总线传输控制等,最下为具体的USB硬件实现。
    从从机侧看,linux的usb分为3个层次,udc,gadget api与gadget驱动,udc为直接访问硬件,控制usb与主机之间的底层通讯,上下层提供硬件相关的操作接口,gadget api主要完成对udc层的一些封装,适配于上层的gadget 驱动层的需求,最上层为gadget驱动层,主要完成设备的运用表现(网络打印,usb mass storage)等特性,gadget的存在主要是为了gadget将运用于底层的硬件操作进行隔离,是的gadget驱动层不需要关系udc层的具体实现。

    二:usb的枚举过程

    还是口头叙述吧,懒得画图了,挺麻烦的 ~~ 哈哈哈 ~~~~~~
    当主机检测到usb设备插入后,

    1、主机发起读设备参数的请求,设备也设备描述配置符的方式回应。

    在这里插入图片描述
    上庙的设备描述符中,我们主要关心vid,pid,配置数目这三个参数,vid与pid在usb的driver中会进行table的对比,当匹配当table中有相对应的VID与PID参数后,才会执行driver->probe进行参数的相关处理。

    2、主机再次发起配置描述请求,从机以配置描述符的协议进行回应、

    在这里插入图片描述
    这里主要关心接口的个数,在同一个配置下,可能存在很多的接口设备,所有这里的配置根据其下的接口描述符的个数进行修改。

    3、主机最后发起接口描述符请求,从机回应接口描述符的配置描述、

    在这里插入图片描述
    这里主要关心端点数,接口类型,一个接口下可能会有多个端点,不同的断电对应不同的类型(短点0主要用于usb控制,所以我们的功能定制需要从短点1开始,比如端点1用于hid设备的out端口,端点2用于hid的in端口,端点3用于mass storage的out 端点,断点4用于mass storage的in端点,。。。),

    4、最后到具体断点描述符,从机会将当前设备的端点描述符返回给主机、

    在这里插入图片描述
    自此,usb的枚举以及完成,主机会将usb的信息存储到driver->private数据接口,获取到的数据都存储到struct usb_interface中,在probe函数中将相关的信息提出出来,进行usb的core相关即可完成usb的枚举过程。

    三、usb主机侧驱动

    usb主控制器有三种规格,OHCI(open host controller interface),UHCI(universal host controller interface)和EHCI(enhanced host controller interface)。
    嵌入式中常用的是OHCI,在主机侧,用hub_hcd来描述主机相关的相关信息,
    在这里插入图片描述
    usb_hcd主要描述了主机控制器的相关信息,同时usb_driver为控制usb主机的钩子函数(回调函数)。
    在这里插入图片描述

    四、usb从机侧驱动

    usb从机可大概分为如下几个设备类、
    1、音频设备类
    2、通讯设备类
    3、HID设备类
    4、mass storage类
    5、集线器设备类
    usb的从机侧使用usb_Driver来描述一个从机usb设备驱动,数据结构如下、
    在这里插入图片描述
    在编写usb从机侧驱动时候,主要完成probe与diconnect函数,
    probe函数的被调用如上枚举所言,只要当枚举到的VID与PID与我们驱动中的id_table成员中的相同,才会被执行,usb设备拔出后disconnect函数在设备被拔出时才会被执行。

    五、urb

    urb(usb request block)为usb输出传输的载体,用于描述usb传输数据包的基本信息,结构体如下、
    在这里插入图片描述
    transfer_flags表示当前usb的状态,只有当该状态处于idle时,数据才能被submit到usb的ENDPOINT的queue中。

    5.1 urb的处理流程

    5.1.1、分配urb

    使用struct urb *usb_alloc_urb(int iso_pockets,int men_flags)来动态的分配一个urb资源。
    iso_pockets表示分配的urb个数,为0则表示分配的urb是非实时性的,
    usb_free_urb(struct urb *urb) 表示将分配的资源进行释放。

    5.1.2、初始化urb

    使用void usb_fill_int_urb(struct urb *urb,struct usb_device *dev,unsigned int pipe,void *transfer_buf,int buffer_length,usb_complete complete,void *context,int interval)来初始化中断urb,
    urb表示需要初始化的urb的指针,dev表示需要发送这个urb的usb设备,pipe表示urb需要发送到的usb指定的端口(一般情况下使用usb_sndintpipe()或者usb_rcvintpipe()创建),transfer_buf是指向发送数据或者接受数据的缓冲区,buffer_len表示数据长度,complete表示传输完成之后需要执行的处理回调函数,xontext字面上是上下文(咱不理解),interval表示这个urb被调度的间隔。

    5.1.3、提交urb

    使用int usb_submit_urb(struct urb *urb,int mem_flag)将urb的数据提交到usb的core层,注意,在complete没有没调用之前,不要再次submit urb

    建议:关于usb的相关,内核中已经提供了一个很好的usb框架文件在drivers/usb/usb-skeleton.c

    举个栗子:见下一篇 usb emulate camera device。

    **~~~~~~~~~~~~~~~~~~~~~废话太多了,再见 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**

    展开全文
  • Linux USB驱动详解

    万次阅读 2019-04-13 09:56:35
            ...原文地址:http://blog.csdn.net/chenjin_zhong/article/details/63293161.Linux usb设备驱动框架USB是通用串行总线的总称,Linux内核几乎...

    首先给大家分享一个巨牛巨牛的人工智能教程,是我无意中发现的。教程不仅零基础,通俗易懂,而且非常风趣幽默,还时不时有内涵段子,像看小说一样,哈哈~我正在学习中,觉得太牛了,所以分享给大家!点这里可以跳转到教程

                   

     

    原文地址:http://blog.csdn.net/chenjin_zhong/article/details/6329316

    1.Linux usb设备驱动框架

    USB是通用串行总线的总称,Linux内核几乎支持所有的usb设备,包括键盘,鼠标,打印机,modem,扫描仪。Linux的usb驱动分为主机驱动与gadget驱动。前者是设备连接到计算机上,通过主机驱动扫描usb设备,控制所连接的设备。而gadget驱动一般用于嵌入式设备,gadget驱动用于控制嵌入式设备。Linux的usb驱动两种类型图如下:

      

    左侧是usb的主机驱动,右侧是gadget驱动。下面着重介绍一下usb的主机驱动:

    (1)usb主机控制器-直接与硬件设备交互。

    (2)usb core-向usb设备驱动提供API以及usb主机控制器驱动的程序。使用usb core所提供的函数,宏来完成数据处理的功能。

    (3)usb设备驱动,即usb接口驱动,一般所说的usb驱动指的是usb接口驱动

      

    2.usb系统的组成部分

    usb系统一般由三个部分组成,主机,一个或多个usb hub,以及与之些hub连接的usb设备。

    (1)主机

    在任何的usb系统中仅有一个主机,主机系统中的usb接口即上图中的主机控制器,主机控制器可由硬件,软件或固件组成。主机主要负责:

    a.检测usb设备的连接与拆除

    b.管理主机与usb设备之间的控制流

    c.管理主机与usb设备之间的数据流

    d.收集状态和活动的统计

    e.为连接的usb设备提供电源

     

     

    (2)usb设备

    所有的usb设备都是通过地址来存取的,这个地址在连接或枚举时分配。usb设备对usb系统来说是端点的集合,一组端点实现一个接口。设备端点是usb设备中唯一可寻址的部分。它是主机与设备之间通信流的结束点。一系列的相互独立的端点构成了usb逻辑设备。每个端点支持流进设备或者是流出设备。

    主机与设备端点上的usb数据传输是通过管道的方式。

     

    (3)hub

    所有的usb device都连接在hub端口上。

     

     

     

    3. usb传输模式

     

    (1)控制传输模式(Control)

    控制传输模式支持双向传输,用来处理从usb主机端口到usb设备端口的数据传输,用于控制指令,设备状态查询以及确认命令。

     

    (2)等时传输方式(lsochronous)

    等时传输是一种周期性的连续性的意向传输模式,通常用于对时间有着密切关系的信息的传输,对准确性要求不高,但对时间要求极为敏感的设备,如视频,音频的传输。

     

    (3)中断传输模式(Interrupt)

    中断传输模式用于非周期性的,自然发生的,数据量小的传输,数据传输的方向是从设备到主机。如usb键盘和鼠标

     

    (4)批量传输模式(bulk)

    批量传输模式是一种单向的,用于大量数据传输的模式,该方式用来传输正确无误的数据。通常打印机,扫描仪,数码相机以这种方式与主机连接

     

     

    4. usb设备组成

    (1)一个usb设备由可以有一个或多个配置

    (2)一个配置通常可以有一个或多个接口

    (3)一个接口通常可以有一个或多个端点

    通常所尽的usb设备驱动是指接口驱动,即一个接口对应一个驱动。

    所以Linux usb设备有四大描述符,分别为设备描述符,配置描述符,接口描述符,端点描述符。下面看一个这几个描述符的相关数据结构:

     

     

    struct usb_device_descriptor

    {
          _u8 bLength;  //此描述符的字节数
          _u8  bDescriptorType; //描述符的种类为设备
          _u16 bcdUSB;  //此设备与描述符兼容的usb设备说明版本号(BCD码)
          _u8   bDeviceClass; //设备类码
          _u8   bDeviceSubClass; //设备子类码
          _u8   bDeviceProtocol; //协议码
          _u8   bMaxPacketSize0; //端点0的最大包大小
          _u16 idVendor; //厂商标志
          _u16  idProduct; //产品标志
          _u16 bcdDevice; //设备发行号
          _u8   iManufacturer; //描述厂商的字串索引

          _u8   iProduct; //描述产品信息的字串索引

          _u8  iSerialNumber; //描述设备序列号信息的字串索引
          _u8  bNumConfigurations;//此设备支持的配置数

      }_attribute_ ((packed));

     

    设备类码的典型值如下:

     

    #define USB_CLASS_PER_INTERFACE 0

    #define USB_CLAS_AUDIO 1     //声音设备

    #define USB_CLASS_COMM 2   // 调制解调器,网卡,ISDN连接

    #define USB_CLASS_HID  3    //HID设备,如鼠标,键盘

    #define USB_CLASS_PHYSICAL 5 //物理设备

    #define USB_CLASS_STILL_IMAGE 6 //静止图像捕捉设备

    #define USB_CLASS_PRINTER 7//打印机

    #define USB_CLASS_MASS_STORAGE //8 批量存储设备

    #define USB_CLASS_HUB 9   //USB HUBS

    #define USB_CLASS_CSCID 0x0B  //智能卡

    #define USB_CLASS_VIDEO 0X0E //视频设备,如网络摄像头

    #define USB_CLASS_VENDOR_SPEC 0xFF //厂商自定义的设备

     

      struct usb_config_descriptor{

     

     _u8 bLength ;//此描述符的字节数

    _u8 bDescriptorType; //配置描述符类型

    _u16 wTotalLength; //此配置信息的总长(包括配置,接口,端点和设备类型及厂商定义的描述符)

    _u8 bNumInterfaces; //此配置所支持的接口数

    _u8 bConfigurationValue ;//在setConfiguration()请求中用作参数来选定此配置

    _u8 iConfiguration; //描述此配置的字串描述符索引

    _u8 bmAttributes; //电源配置特性

    _u8 bMaxpowe;r //此配置下的总线电源耗电量

    }_attribute_ ((packed));

     

     

    配置描述符给出了usb设备配置信息,以及此配置下的接口数。每个接口可能的独立操作。

     

     

     

    struct usb_interface_descriptor{

     

    _u8 bLength ;//此描述符的字节数

    _u8 bDescriptorType;//接口描述符类

    _u8 bInterfacNumber;//接口号,当前配置所支持的接口数组索引,从0开始

    _u8 bNumEndpoints ;//此接口用的端点数量,如果是0,说明此接口只有缺省控制通道

    _u8 bAlernateSetting;//可选设备的索引值

    _u8 bInterfaceClass;// 类值,0值作为将来保留使用如果是0FFH,此接口由厂商说明

    _u8 bInterfaceSubClass;//子类码

    _u8 bInterfaceProtocol;//协议码

    _u8 iInterface;//描述此接口的字串描述符索引

     

    }_attribute_ ((packed));

     

    struct usb_endpoint_descriptor{

    _u8 bLength ;//此描述符的字节数

    _u8 bDescriptorType;//端点描述符类

    _u8 bEndpointAddress;此描述符所描述的端点的地址

    _u8 bmAtrributes;//所指定的端点的特性,如果是00=控制传送,01=等时传送,10=批传送,11=中断传送

    _u8 wMaxPacketSize;//当前配置下端点能够发送与接收的最大数据包大小

    _u8 bInterval;//轮询数据传送端点的时间间隙

    _u8 bRefresh

    _u8 bSynchAddress

    }_attribute_ ((packed));

     

    以上给出了usb中的设备描述符,配置描述符,接口描述符和端点描述符。

     

     

    5. usb设备驱动的几个重要的数据结构

     

    usb_driver,usb_device,usb_bus.

     

     

    /**
    788* stru ctusb_driver - identifiesU SB interface driver tou sbcore
    789* @name: The driver name shou ld beu niqu e amongU SB drivers,
    790*      and shou ld normally be the same as the modu le name.
    791* @probe: Called to see if the driver is willing to manage a particu lar
    792*      interface on a device.  If it is, probe retu rns zero andu ses
    793*     u sb_set_intfdata() to associate driver-specific data with the
    794*      interface.  It may alsou seu sb_set_interface() to specify the
    795*      appropriate altsetting.  Ifu nwilling to manage the interface,
    796*      retu rn -ENODEV, if genu ine IO errors occu red, an appropriate
    797*      negative errno valu e.
    798* @disconnect: Called when the interface is no longer accessible,u su ally
    799*      becau se its device has been (or is being) disconnected or the
    800*      driver modu le is beingu nloaded.
    801* @u nlocked_ioctl:U sed for drivers that want to talk tou serspace throu gh
    802*      the "u sbfs" filesystem.  This lets devices provide ways to
    803*      expose information tou ser space regardless of where they
    804*      do (or don't) showu p otherwise in the filesystem.
    805* @su spend: Called when the device is going to be su spended by the system.
    806* @resu me: Called when the device is being resu med by the system.
    807* @reset_resu me: Called when the su spended device has been reset instead
    808*      of being resu med.
    809* @pre_reset: Called byu sb_reset_device() when the device
    810*      is abou t to be reset.
    811* @post_reset: Called byu sb_reset_device() after the device
    812*      has been reset
    813* @id_table:U SB driversu se ID table to su pport hotplu gging.
    814*      Export this with MODU LE_DEVICE_TABLE(u sb,...).  This mu st be set
    815*      or you r driver's probe fu nction will never get called.
    816* @dynids:u sed internally to hold the list of dynamically added device
    817*      ids for this driver.
    818* @drvwrap: Driver-model core stru ctu re wrapper.
    819* @no_dynamic_id: if set to 1, theU SB core will not allow dynamic ids to be
    820*      added to this driver by preventing the sysfs file from being created.
    821* @su pports_au tosu spend: if set to 0, theU SB core will not allow au tosu spend
    822*      for interfaces bou nd to this driver.
    823* @soft_u nbind: if set to 1, theU SB core will not killU RBs and disable
    824*      endpoints before calling the driver's disconnect method.
    825*
    826*U SB interface drivers mu st provide a name, probe() and disconnect()
    827* methods, and an id_table.  Other driver fields are optional.
    828*
    829* The id_table isu sed in hotplu gging.  It holds a set of descriptors,
    830* and specialized data may be associated with each entry.  That table
    831* isu sed by bothu ser and kernel mode hotplu gging su pport.
    832*
    833* The probe() and disconnect() methods are called in a context where
    834* they can sleep, bu t they shou ld avoid abu sing the privilege.  Most
    835* work to connect to a device shou ld be done when the device is opened,
    836* andu ndone at the last close.  The disconnect code needs to address
    837* concu rrency issu es with respect to open() and close() methods, as
    838* well as forcing all pending I/O requ ests to complete (byu nlinking
    839* them as necessary, and blockingu ntil theu nlinks complete).
    840*/
    841stru ctusb_driver{
    842         const char *name;
    843
    844         int (*probe) (stru ct u sb_interface*intf,
    845                       const stru ctu sb_device_id*id);
    846
    847         void (*disconnect) (stru ct u sb_interface*intf);
    848
    849         int (*u nlocked_ioctl) (stru ctu sb_interface*intf,u nsigned intcode,
    850                         void *bu f);
    851
    852         int (*su spend) (stru ct u sb_interface *intf,pm_message_tmessage);
    853         int (*resu me) (stru ct u sb_interface *intf);
    854         int (*reset_resu me)(stru ctu sb_interface*intf);
    855
    856         int (*pre_reset)(stru ct u sb_interface*intf);
    857         int (*post_reset)(stru ctu sb_interface*intf);
    858
    859         const stru ctu sb_device_id*id_table;
    860
    861         stru ctu sb_dynidsdynids;
    862         stru ctu sbdrv_wrapdrvwrap;
    863        u nsigned int no_dynamic_id:1;
    864        u nsigned int su pports_au tosu spend:1;
    865        u nsigned int soft_u nbind:1;
    866};

     

    usb_driver中的probe函数扫描连接到主机上的usb设备,并且注册usb接口驱动。

     

    disconnect函数是当usb设备移除时调用。

     

     

    /*
    310* Allocated per bu s (tree of devices) we have:
    311*/
    312stru ctu sb_bu s {
    313         stru ctdevice *controller ;     /* host/master side hardware */
    314         int bu snu m;                    /* Bu s nu mber (in order of reg) */
    315         const char *bu s_name;          /* stable id (PCI slot_name etc) */
    316        u 8u ses_dma;                   /* Does the host controlleru se DMA? */
    317        u 8u ses_pio_for_control;       /*
    318                                         * Does the host controlleru se PIO
    319                                         * for control transfers?
    320                                         */
    321        u 8 otg_port;                   /* 0, or nu mber of OTG/HNP port */
    322        u nsigned is_b_host:1;          /* tru e du ring some HNP roleswitches */
    323        u nsigned b_hnp_enable:1;       /* OTG: did A-Host enable HNP? */
    324        u nsignedsg_tablesize ;         /* 0 or largest nu mber of sg list entries */
    325
    326         int devnu m_next;               /* Next open device nu mber in
    327                                         * rou nd-robin allocation */
    328
    329         stru ctu sb_devmap  devmap;      /* device address allocation map */
    330         stru ctusb_device * root_hu b;   /* Root hu b */
    331         stru ctu sb_bu s *hs_companion;  /* Companion EHCI bu s, if any */
    332         stru ctlist_head bu s_list;     /* list of bu sses */
    333
    334         int bandwidth_allocated;       /* on this bu s: how mu ch of the time
    335                                         * reserved for periodic (intr/iso)
    336                                         * requ ests isu sed, on average?
    337                                         *U nits: microseconds/frame.
    338                                         * Limits: Fu ll/low speed reserve 90%,
    339                                         * while high speed reserves 80%.
    340                                         */
    341         int bandwidth_int_reqs;        /* nu mber of Interru pt requ ests */
    342         int bandwidth_isoc_reqs;       /* nu mber of Isoc. requ ests */
    343
    344#ifdef CONFIG_USB_DEVICE FS
    345         stru ctdentry *u sbfs_dentry;   /*u sbfs dentry entry for the bu s */
    346#endif
    347
    348#ifdefined (CONFIG_U SB_MON) ||defined(CONFIG_U SB_MON_MODU LE)
    349         stru ctmon_bu s *mon_bu s ;       /* non-nu ll when associated */
    350         int monitored;                 /* non-zero when monitored */
    351#endif
    352};
    353

     

     

    **
    370* stru ctusb_device - kernel's representation of aU SB device
    371* @devnu m: device nu mber; address on aU SB bu s
    372* @devpath: device ID string foru se in messages (e.g., /port/...)
    373* @rou te: tree topology hex string foru se with xHCI
    374* @state: device state: configu red, not attached, etc.
    375* @speed: device speed: high/fu ll/low (or error)
    376* @tt: Transaction Translator info;u sed with low/fu ll speed dev, highspeed hu b
    377* @ttport: device port on that tt hu b
    378* @toggle: one bit for each endpoint, with ([0] = IN, [1] = OU T) endpoints
    379* @parent: ou r hu b,u nless we're the root
    380* @bu s: bu s we're part of
    381* @ep0: endpoint 0 data (defau lt control pipe)
    382* @dev: generic device interface
    383* @descriptor:U SB device descriptor
    384* @config: all of the device's configs
    385* @actconfig: the active configu ration
    386* @ep_in: array of IN endpoints
    387* @ep_ou t: array of OU T endpoints
    388* @rawdescriptors: raw descriptors for each config
    389* @bu s_mA: Cu rrent available from the bu s
    390* @portnu m: parent port nu mber (origin 1)
    391* @level: nu mber ofU SB hu b ancestors
    392* @can_su bmit:U RBs may be su bmitted
    393* @persist_enabled: U SB_PERSIST enabled for this device
    394* @have_langid: whether string_langid is valid
    395* @au thorized: policy has said we canu se it;
    396*      (u ser space) policy determines if we au thorize this device to be
    397*     u sed or not. By defau lt, wiredU SB devices are au thorized.
    398*      WU SB devices are not,u ntil we au thorize them fromu ser space.
    399*      FIXME -- complete doc
    400* @au thenticated: Crypto au thentication passed
    401* @wu sb: device is WirelessU SB
    402* @string_langid: langu age ID for strings
    403* @produ ct: iProdu ct string, if present (static)
    404* @manu factu rer: iManu factu rer string, if present (static)
    405* @serial: iSerialNu mber string, if present (static)
    406* @filelist:u sbfs files that are open to this device
    407* @u sb_classdev:U SB class device that was created foru sbfs device
    408*      access fromu serspace
    409* @u sbfs_dentry:u sbfs dentry entry for the device
    410* @maxchild: nu mber of ports if hu b
    411* @children: child devices -U SB devices that are attached to this hu b
    412* @qu irks: qu irks of the whole device
    413* @u rbnu m: nu mber ofU RBs su bmitted for the whole device
    414* @active_du ration: total time device is not su spended
    415* @connect_time: time device was first connected
    416* @do_remote_wakeu p:  remote wakeu p shou ld be enabled
    417* @reset_resu me: needs reset instead of resu me
    418* @wu sb_dev: if this is a WirelessU SB device, link to the WU SB
    419*      specific data for the device.
    420* @slot_id: Slot ID assigned by xHCI
    421*
    422* Notes:
    423*U sbcore drivers shou ld not setu sbdev->state directly.  Insteadu se
    424*u sb_set_device_state().
    425*/
    426stru ctusb_device{
    427         int             devnu m;
    428         char            devpath[16];
    429        u 32             rou te;
    430         enu musb_device _state  state;
    431         enu musb_device _speed  speed;
    432
    433         stru ctu sb_tt   *tt;
    434         int             ttport;
    435
    436        u nsigned inttoggle[2];
    437
    438         stru ctusb_device*parent;
    439         stru ctu sb_bu s*bu s;
    440         stru ctu sb_host_endpointep0;
    441
    442         stru ctdevicedev;
    443
    444         stru ctusb_device _descriptordescriptor;
    445         stru ctu sb_host_config*config;
    446
    447         stru ctu sb_host_config*actconfig;
    448         stru ctu sb_host_endpoint*ep_in[16];
    449         stru ctu sb_host_endpoint*ep_ou t[16];
    450
    451         char **rawdescriptors;
    452
    453        u nsigned short bu s_mA;
    454        u 8portnu m;
    455        u 8level;
    456
    457        u nsigned can_su bmit:1;
    458        u nsigned persist_enabled:1;
    459        u nsigned have_langid:1;
    460        u nsigned au thorized:1;
    461        u nsigned au thenticated:1;
    462        u nsigned wu sb:1;
    463         int string_langid;
    464
    465        /* static strings from the device */
    466         char *produ ct;
    467         char *manu factu rer;
    468         char *serial;
    469
    470         stru ctlist_headfilelist;
    471#ifdef CONFIG_USB_DEVICE _CLASS
    472         stru ctdevice*u sb_classdev;
    473#endif
    474#ifdef CONFIG_USB_DEVICE FS
    475         stru ctdentry*u sbfs_dentry;
    476#endif
    477
    478         int maxchild;
    479         stru ctusb_device*children[U SB_MAXCHILDREN];
    480
    481        u 32qu irks;
    482        atomic_tu rbnu m;
    483
    484        u nsigned long active_du ration;
    485
    486#ifdefCONFIG_PM
    487        u nsigned long connect_time;
    488
    489        u nsigned do_remote_wakeu p:1;
    490        u nsigned reset_resu me:1;
    491#endif
    492         stru ctwu sb_dev*wu sb_dev;
    493         int slot_id;
    494};
    495#defineto_usb_device(d)container_of(d, stru ctusb_device,dev)
    496
    497static inline stru ctusb_device*interface_to_u sbdev(stru ctu sb_interface*intf)
    498{
    499         retu rnto_usb_device(intf->dev.parent);
    500}
    501

     

    以上三个结构体分别是usb_driver,usb_bus,usb_device设备结构体。

     

     

     

    usb_interface结构体:

     

    struct usb_interface{
    160        /* array of alternate settings for this interface,
    161         * stored in no particular order */
    162         structusb_host_interface*altsetting;
    163
    164         structusb_host_interface*cur_altsetting;     /* the currently
    165                                         * active alternate setting */
    166         unsigned num_altsetting;       /* number of alternate settings */
    167
    168        /* If there is an interface association descriptor then it will list
    169         * the associated interfaces */
    170         structusb_interface_assoc_descriptor*intf_assoc;
    171
    172         intminor;                     /* minor number this interface is
    173                                         * bound to */
    174         enumusb_interface_conditioncondition;        /* state of binding */
    175         unsigned sysfs_files_created:1;/* the sysfs attributes exist */
    176         unsigned ep_devs_created:1;    /* endpoint "devices" exist */
    177         unsigned unregistering:1;      /* unregistration is in progress */
    178         unsigned needs_remote_wakeup:1;/* driver requires remote wakeup */
    179         unsigned needs_altsetting0:1;  /* switch to altsetting 0 is pending */
    180         unsigned needs_binding:1;      /* needs delayed unbind/rebind */
    181         unsigned reset_running:1;
    182         unsigned resetting_device:1;   /* true: bandwidth alloc after reset */
    183
    184         structdevicedev;             /* interface specific device info */
    185         structdevice*usb_dev;
    186        atomic_tpm_usage_cnt;         /* usage counter for autosuspend */
    187         structwork_structreset_ws;   /* for resets in atomic context */
    188};

     struct usb_host_interface *altsetting包含了usb interface的所有可选设置。

     struct usb_host _interface *cur_altsetting是usb interface的当前可选设置。

     

    下面看一个struct usb_host_interface

     

     

    /* host-side wrapper for one interface setting's parsed descriptors */

    展开全文
  • LinuxUSB驱动框架分析.doc
  • LinuxUSB驱动框架分析.pdf
  • 基于FT245的Linux USB驱动的设计.pdf
  • 设备驱动程序是操作系统内核和机器硬件之间的接口,由一组函数和一些私有数据组成,是应用程序和硬件设备之间的桥梁。在应用程序看来,硬件设备只是一个设备文件,应用程序可以像操作普通文件一样对硬件设备进行操作...

           设备驱动程序是操作系统内核和机器硬件之间的接口,由一组函数和一些私有数据组成,是应用程序和硬件设备之间的桥梁。在应用程序看来,硬件设备只是一个设备文件,应用程序可以像操作普通文件一样对硬件设备进行操作。

          设备驱动程序是内核的一部分,主要完成以下功能:对设备的初始化和释放把数据从内核传送到硬件设备和从硬件设备读取数据读取应用程序数据传送给设备文件和回送应用程序请求的数据检测和处理硬件设备出现的错误


    一、 Linux USB子系统分析

            在Linux系统中,USB主机驱动程序由3部分组成:USB主机控制器驱动(HCD)USB核心驱动(USBD)不同种类的USB设备类驱动,如下所示。其中HCD和USBD被称为协议软件或者协议栈,这两部分共同处理与协议相关的操作。

           USB设备类驱动可以包含多个,不同的功能接口对应不同的驱动程序,它们不直接与USB设备硬件打交道,而是通过协议软件的抽象处理来完成与设备的不同功能接口之间的通信

           在Linux USB子系统中,HCD是直接和硬件进行交互的软件模块是USB协议栈的最底层部分是USB主机控制器硬件和数据传输的一种抽象

          HCD向上仅对USB总线驱动程序服务,HCD提供了一个软件接口,即HCDI,使得各种USB主机控制器的硬件特性都被软件化,并受USB总线驱动程序的调用和管理。HCD向下则直接管理和检测主控制器硬件的各种行为。HCD提供的功能主要有:主机控制器硬件初始化;为USBD层提供相应的接口函数;提供根HUB(ROOT HUB)设备配置、控制功能;完成4种类型的数据传输等。

          USBD部分是整个USB主机驱动的核心,主要实现的功能有:USB总线管理;USB总线设备管理、USB总线带宽管理、USB的4种类型数据传输、USB HUB驱动、为USB设备驱动提供相关接口、提供应用程序访问USB系统的文件接口等。其中USB HUB作为一类特殊的USB设备,其驱动程序被包含在USBD层。

         在嵌入式Linux系统中,已经包含HCD模块和USB核心驱动USBD,不需要用户重新编写,用户仅仅需要完成USB设备类驱动即可。


    二、Linux系统中USB子系统的主要数据结构

            Linux系统中,USBD通过定义一组宏、数据结构和函数来抽象出所有硬件或是设备具有依赖关系的部分。

    USBD中主要有四个数据结构,分别是:

    1.usb_device保存一个USB设备的信息,包括设备地址,设备描述符,配置描述符等。

    2.usb_bus保存一个USB总线系统的信息,包括总线上设备地址信息,根集线器,带宽使用情况等。一个USB总线系统至少有一个主机控制器一个根集线器,Linux系统支持多USB总线系统。

    3.usb_driver保存客户驱动信息,包括驱动名称,以及驱动提供给USB内核使用的函数指针等。

    4.URB(Universal Request Block)是进行USB通信的数据结构,USBD通过URB在USB设备类驱动和USBD、USBD和HCD间进行数据传输。


    三、Linux系统中USB设备的加载与卸载

           当把一个USB设备插入到一个USB HUB的某个端口时,集中器就会检测到设备的接入,从而在下一次受到主机通过中断交互查询时就会向其报告。集中器的端口在没有设备接入时都处于关闭状态,插入设备之后也不会自动打开,必须由主机通过控制交互发出命令予以打开。所以,在得到集中器的报告之后,主机的USB驱动程序就会为新插入的设备调度若干个控制交互,并向集中器发出打开这个端口的命令,这样新插入的设备就会出现在USB总线上了,并为该设备分配唯一的地址

           HUB驱动程序调用函数usb_connect(struct usb_device *dev)usb_new_device(struct usb_device *dev)解析设备的各种描述符信息,分配资源,并与相应的设备驱动程序建立联系。

    函数usb_new_device主要完成以下工作:

    1.调用usb_set_address把新分配的设备地址传送给设备。

    2.调用usb_get_descriptor获得设备的设备描述符,得到设备端点的包的最大长度,接下来的控制传输按这个数据包最大长度进行。

    3.调用usb_get_configuration得到设备的所有配置描述符、接口描述符和端点描述符信息。

    4.调用usb_set_configuration激活当前的配置作为默认工作配置。

    5.在目录“proc/bus/usb”中为设备创建节点。

    6.在USB子系统中,通过函数usb_find_driversusb_find_interface_driver为设备的每一个接口寻找相应的驱动程序,驱动程序对接口进行配置并为它们分配所需的资源。当每个接口被成功驱动后,此设备就能正常工作了。

          设备拔下时,与之相联的集线器首先检测到设备的拔下信号,通过中断传输将信息传送给集线器的驱动,集线器的驱动先验证设备是否被拔下,如果是则调用usb_disconnect(struct usb_device **pdev)进行处理。设备断开后,USB系统找到设备当前活动配置的每个接口的驱动程序,调用它们提供的disconnect接口函数,中断它们与各个接口的数据传输操作,释放它们为每个接口分配的资源。如果此设备是集线器,则递归调用usb_disconnect来处理它的子设备,释放设备地址,通过usbdevfs_remove_device函数释放给设备创建的文件节点,通过usb_free_dev释放USBD给设备分配的资源。


    四、编写USB驱动程序步骤

    1、所有usb驱动都必须创建主要结构体struct usb_driver

    struct usb_driver

    ->struct module *owner

       (有他可正确对该驱动程序引用计数,应为THIS_MODULE)

    ->const char *name

       (驱动名字,运行时可在查看 /sys/bus/usb/drivers/)

    ->const struct usb_device_id *id_table

       (包含该驱动可支持的所有不同类型的驱动设备,没添探测回调函数不会被调用)

    ->int (*probe)(struct usb_interface *intf,const struct usb_device_id *id)

       (usb驱动探测函数,确认后struct usb_interface 应恰当初始化,然后返0,如果出错则返负值)

    ->void(*disconnect)(struct usb_interface *intf)

       (当struct usb_interface 被从系统中移除或驱动正从usb核心中卸载时,usb核心将调用此函数)

    代码实例:

    1. static struct usb_driver skel_driver={
    2. .owner = THIS_MODULE,
    3. .name = "skeleton",
    4. .id_table = skel_table,
    5. .probe = skel_probe,
    6. .disconnect = skel_disconnect,
    7. };

    2、usb_register()注册将struct usb_driver 注册到usb核心,传统是在usb驱动程序模块初始化代码中完成该工作的

    1. static int __ init usb_skel_init(void)
    2. {
    3. ...
    4. usb_register(&skel_driver);
    5. ...
    6. }

    3、struct usb_device_id usb核心用该表判断哪个设备该使用哪个驱动程序,热插拔脚本使用它来确定当一个特定的设备插入到系统时该自动装载哪个驱动程序

    ->__u16 match_flags(确定设备和结构体中下列字段中哪一个相匹配)
    ->__u16 idVendor(设备的usb制造商id)
    ->__u16 idProduct(设备的usb产品id) 


    4、USB骨架程序的关键几点如下:

    a -- USB驱动的注册和注销 

       Usb驱动程序在注册时会发送一个命令给usb_register,通常在驱动程序的初始化函数里。

       当要从系统卸载驱动程序时,需要注销usb子系统。即需要usb_unregister 函数处理。

    b -- 当usb设备插入时,为了使linux-hotplug(Linux中PCI、USB等设备热插拔支持)系统自动装载驱动程序,你需要创建一个MODULE_DEVICE_TABLE

    代码如下(这个模块仅支持某一特定设备):

    1. static struct usb_device_id skel_table [] = {
    2. { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
    3. { } /* Terminating entry */};
    4. MODULE_DEVICE_TABLE (usb, skel_table);

     USB_DEVICE宏利用厂商ID和产品ID为我们提供了一个设备的唯一标识。当系统插入一个ID匹配的USB设备到USB总线时,驱动会在USB core中注册。驱动程序中probe 函数也就会被调用。usb_device 结构指针、接口号和接口ID都会被传递到函数中。

    c -- static void * skel_probe(struct usb_device *dev,unsigned int ifnum, const struct usb_device_id *id)

           驱动程序需要确认插入的设备是否可以被接受,如果不接受,或者在初始化的过程中发生任何错误,probe函数返回一个NULL值。否则返回一个含有设备驱动程序状态的指针。通过这个指针,就可以访问所有结构中的回调函数。

    d -- 在骨架驱动程序里,最后一点是我们要注册devfs

          我们创建一个缓冲用来保存那些被发送给usb设备的数据和那些从设备上接受的数据,同时USB urb 被初始化,并且我们在devfs子系统中注册设备,允许devfs用户访问我们的设备。注册过程如下:

    1. /* initialize the devfs node for this device and register it */
    2. sprintf(name, "skel%d", skel->;minor);
    3. skel->devfs = devfs_register (usb_devfs_handle, name,DEVFS_FL_DEFAULT, USB_MAJOR,USB_SKEL_MINOR_BASE + skel->minor,
    4. S_IFCHR | S_IRUSR | S_IWUSR |S_IRGRP | S_IWGRP | S_IROTH, &skel_fops, NULL);
    如果devfs_register函数失败,不用担心,devfs子系统会将此情况报告给用户。

    当然最后,如果设备从usb总线拔掉,设备指针会调用disconnect 函数。驱动程序就需要清除那些被分配了的所有私有数据、关闭urbs,并且从devfs上注销调自己。
      /* remove our devfs node */devfs_unregister(skel->;devfs);


    5、其他

    a -- struct usb_host_endpoint(描述usb端点)

    →(包含)struct usb_endpoint_descriptor(含真正端点信息,数据格式,是真正驱动关心的字段)

     端点描述符:

    bEndpointAddress = 81(in)(第8位为1是输入设备)(usb的端点地址,包含端点方向)
    bmAttibutes = 03(interrupt)(端点类型,为中断传输)
    wMaxPacketSize = 0008(每次传8个字节)(端点每次可处理最大字节长度)
    bInterval = 08(8ms)(如端点为中断,该值为轮询间隔)

    b -- usb端点捆绑为接口,usb接口只处理一种usb逻辑连接,如鼠标键盘等

       一个usb设备可有多接口,usb扬声器:一个usb键盘用于按键,一个usb音频流,则需两个不同的驱动程序。

       usb驱动 通常将struct usb_interface 转成 struct usb_device 用函数 interface_to_usbdev转 

    c -- struct usb_interface 描述usb接口

       →struct usb_host_interface * altsetting(接口结构体数组,包含所有可能用于该接口的可选设置)
        →struct usb_host_endpoint
       →unsigned num_altsetting(可选设置的数量)
       →struct usb_host_interface * cur_altsetting(接口当前活动设置)
       →int minor(usb核心分配给接口的次设备号,成功调用usb_register_dev有效) 

    d -- usb设备非常复杂,由许多不同逻辑单元组成,简单关系如下:

       设备通常有一个以上的配置
       配置经常有一个以上接口
       接口通常有一个以上设置
       接口通常有一个以上端点
       设备描述-》配置描述-》接口描述-》端点描述 

    e -- usb sysfs设备命名方案

       根集线器-集线器端口号:配置。接口
       对于usb hub树中层次更高的字树命名方案
       根集线器-集线器端口号-集线器端口号:配置。接口 

    f --  linux内核的代码通过一个成为urb(usb请求块)和所有usb设备通信.  

     用struct urb描述(include/linux/usb.h中定义) 

       ->urb用异步同usb设备特定usb端点发送/接收数据,使用类似网络代码中的struct skbuff
       -> urb 被动态创建,随时可被驱动程序或usb核心取消,内部有引用计数,可被多次调用,使他们可在最后一个使用者释放他们时自动地销毁
       -> urb使得流处理或其他复杂的重叠的通信成为可能,获得高数据传输速度。 
       ->usb_alloc_urb() 创建urb包 usb_free_urb() 释放urb包 
       ->usb_fill_int_urb()正确初始化将发送到usb设备的中断端点urb
         usb_fill_bulk_urb() .. .. .. ... 批量传输端点urb
         usb_fill_control_urb() .. .. .. ... 控制端点urb
         等时urb在提交给核心时必须手动初始化(很不幸,没函数)
       ->usb_submit_urb()urb被usb驱动正确创建和初始化后,就可提交到usb核心,发送到usb设备上了,如果调用成功,函数返0,urb控制权转给usb核心
       ->usb_kill_urb() or usb_unlink_urb()取消已经被提交给核心的urb 


    五、USB驱动开发简单示例

    1、嵌入式Linux系统中USB摄像头驱动程序实现

         通常USB设备类驱动程序需要提供两个数据结构接口,一个针对USBD层,一个针对文件系统。USB摄像头驱动程序需要做的第一件事情就是在USB子系统里注册,并提供一些相关信息,包括该驱动程序支持哪些设备,当被支持的设备从总线插入或拔出时,会有哪些动作等,所有这些信息通过usb_driver的形式传送到USBD中,具体实现如下:

    1. static struct usb_driver cam_driver = {
    2. .name: "cam_video",
    3. .probe: cam_probe,
    4. .disconnect: cam_disconnect,
    5. .id_table: cam_ids,
    6. };

    其中

    cam_video是客户端驱动程序的字符串名称,用于避免驱动程序的重复安装和卸载;

    cam_probe则指向USB驱动程序的探测函数指针,提供给USB内核的函数用于判断驱动程序是否能对设备的某个接口进行驱动

    cam_disconnect指向USB驱动程序中的断开函数的指针,当从系统中被移除或者驱动程序正在从USB核心中卸载时,USB核心将调用该函数;

    cam_ids列表包含了一系列该驱动程序可以支持的所有不同类型的USB设备,如没有设置该列表,则该驱动程序中的探测回调函数不会被调用。

           当一个摄像头连接到USB总线上时,USB内核通过调用camDrive.c中的cam_probe函数判断是否支持该设备,如果支持,为该设备创建设备文件节点,以后应用程序就可以通过标准POSIX函数,把该设备当成普通文件来访问。摄像头驱动程序定义的文件系统接口如下:

    1. struct file_operations cam_fops = {
    2. .owner = THIS_MODULE,
    3. .open = cam_v 4l2_open,
    4. .release = cam_v4l2_release,
    5. .ioctl = cam_v4l2_ioctl,
    6. .llseek = no_llseek,
    7. .read = cam_v4l2_read,
    8. .mmap = cam_v4l2_mmap,
    9. .poll = cam_v4l2_poll,
    10. };
         在USB摄像头驱动程序的初始化函数中,通过usb_register进行设备注册;当从系统卸载驱动程序时,需要通过usb_deregister进行卸载。当驱动程序向USB子系统注册后,插入一个新的USB设备后总是要调用cam_probe函数进行设备驱动程序的查找,以确定新的USB设备硬件中的生产厂商ID和产品自定义ID是否与驱动程序相符,从而确定是否使用该驱动程序。


     2、USB摄像头驱动程序测试

           在嵌入式Linux系统中,USB摄像头被注册为一个标准的视频设备/dev/video,通过影像设备API接口Video4Linux来获取视频和音频数据。

    现有的Video4Linux有两个版本:v4l和v4l2。通过v4l2 API接口获取视频图像的主要操作步骤如下:

    a -- 打开视频设备

    在Linux系统中,摄像头的设备文件为/dev/video0,调用系统函数open打开该设备。

    fd = open (dev_name, O_RDWR);

    b -- 获取视频设备所支持的V4L2特性

          所有的V4L2设备驱动都需要支持VIDIOC_QUERYCAP_ioctl的系统调用。通过该调用,确定该驱动程序是否与V4L2规范相兼容,同时获取该设备所支持的V4L2特性。在摄像头应用程序的开发过程中,需要判定该设备是否支持视频捕获。

    ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);

    c -- 获取视频设备支持的各种特性

          接着,利用ioctl(fd,VIDIOC_QUERYCAP,&cap)函数读取struct v4l2_capability中有关摄像头的信息。该函数成功返回后,这些信息从内核空间拷贝到用户程序空间capability各成员分量中。

    ioctl(device_fd, VIDIOCGCAP, &vidcap);

    d -- 设置视频捕获的图像格式

    memset(&fmt, 0, sizeof(struct v4l2_format));
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.width = vd->width;
    fmt.fmt.pix.height = vd->height;
    fmt.fmt.pix.pixelformat = vd->formatIn;
    ret = ioctl(fd, VIDIOC_S_FMT, &fmt);

    e -- 视频数据帧捕获

    ioctl (fd, VIDIOC_DQBUF, &buf);

    获取到视频数据之后,放到buf缓冲区中,通过QT桌面应用开发系统,显示到LCD显示屏上,通过触摸屏进行交互控制。

    展开全文
  • LinuxUSB驱动框架分析[参照].pdf
  • Linux驱动开发: USB驱动开发

    千次阅读 多人点赞 2021-08-24 22:03:05
    一、USB简介 1.1 什么是USB? USB是连接计算机系统与外部设备的一种串口总线标准,也是一种输入输出接口的技术规范,被广泛地应用于个人电脑和移动设备等信息通讯产品,USB就是简写,中文叫通用串行总线。最早出现...
  • Linux驱动开发|USB驱动

    千次阅读 2022-01-14 16:13:01
    USB驱动
  • 编写与一个USB设备驱动程序的方法和其他总线驱动方式类似,驱动程序把驱动程序对象注册到USB子系统中,稍后再使用制造商和...总线设备驱动编写一样,所有的USB驱动程序都必须创建的主要结构体是 struct usb_driver,
  • 摘要:本文主要介绍了Linux平台的USB设备驱动开发的一般步骤方法和技巧,通过详细介绍USB的相关概念和Linux中USB设备驱动程序的数据结构,框架和步骤,并通过设计和实现一个驱动的实例,总结了USB驱动的一般方法和...
  • linux下4g模块的usb驱动

    2020-12-08 09:05:40
    解压tar zxvf openssh-4.6p1.tar.gz,进入目录,官方源码,没有修改。./configure -host=arm-linux-with-libs -with-zlib=
  • LINUXUSB驱动.pdf

    2021-10-08 16:08:55
    LINUXUSB驱动.pdf
  • linuxusb 驱动

    千次阅读 2021-06-02 11:18:54
    今天我们来简单地把USBLinux里的结构框架大致整理下,其中重点解析下USB Core和Hub。 0. 预备理论 说实话,读USB协议还是蛮痛苦的,它仅仅是一个协议,一个在USB世界里制定的游戏规则,就像法律条文一样,它并不...
  • linuxUSB驱动移植

    2020-10-19 16:38:22
    linuxUSB驱动移植,一、代码修改在这里把include前面的#给删了,希望有帮助/*addbylfc*/#include<asm/arch/regs-clock.h>#include<asm/arch/usb-control.h>#include<linux/device.h>#include...
  • 嵌入式LinuxUSB驱动设计.pdf
  • 参考2.6.14版本中的driver/usb/input/usbmouse.c。鼠标驱动可分为几个部分:驱动加载...一、驱动加载部分static int __init usb_mouse_init(void) { int retval = usb_register(&usb_mouse_driver);//注册鼠标驱动
  • linux usb驱动教程

    2008-08-27 14:04:36
    linux usb驱动教程,从模块设计到数据调用,描述得比较完善
  • linux安装usb驱动命令

    2021-05-09 07:51:17
    有时我们会用到usb设备,这时我们就要学会如何在linux系统下安装usb驱动了。下面由学习啦小编为大家整理了linux安装usb驱动命令的相关知识,希望大家喜欢!linux安装usb驱动命令安装方法及步骤:一、准备工作2、到...
  • 嵌入式linux上的USB设备驱动源代码和Makefile编译驱动文件源代码
  • 嵌入式LinuxUSB摄像头驱动实现.pdf

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 85,286
精华内容 34,114
关键字:

linuxusb驱动

友情链接: MINIWEB.rar