Linux下的USB总线驱动(02)——USB框架usb-skeleton.c
发布日期:2021-09-27 14:12:41 浏览次数:4 分类:技术文章

本文共 15688 字,大约阅读时间需要 52 分钟。

原文链接:

USB驱动框架usb-skeleton.c

USB骨架程序可以被看做一个最简单的USB设备驱动的实例。

首先看看USB骨架程序的usb_driver的定义

[cpp] 
  1. static struct usb_driver skel_driver = {  
  2.       .name =          "skeleton",  
  3.       .probe =  skel_probe,             //设备探测  
  4.       .disconnect =  skel_disconnect,  
  5.       .suspend =      skel_suspend,  
  6.       .resume =      skel_resume,  
  7.       .pre_reset =    skel_pre_reset,  
  8.       .post_reset =  skel_post_reset,  
  9.       .id_table =      skel_table,          //设备支持项  
  10.       .supports_autosuspend = 1,  
  11. };  

 

[cpp] 
  1. /* Define these values to match your devices */  
  2. #define USB_SKEL_VENDOR_ID  0xfff0  
  3. #define USB_SKEL_PRODUCT_ID 0xfff0  
  4.   
  5. /* table of devices that work with this driver */  
  6. static const struct usb_device_id skel_table[] = {  
  7.     { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },  
  8.     { }                 /* Terminating entry */  
  9. };  
  10. MODULE_DEVICE_TABLE(usb, skel_table);  

由上面代码可见,通过USB_DEVICE宏定义了设备支持项。

对上面usb_driver的注册和注销发送在USB骨架程序的模块加载和卸载函数中。

[cpp] 
  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;  
  11. }  

一个设备被安装或者有设备插入后,当USB总线上经过match匹配成功,就会调用设备驱动程序中的probe探测函数,向探测函数传递设备的信息,以便确定驱动程序是否支持该设备。

[cpp] 
  1. static int skel_probe(struct usb_interface *interface,  
  2.               const struct usb_device_id *id)  
  3. {  
  4.     struct usb_skel *dev;                       //特定设备结构体  
  5.     struct usb_host_interface *iface_desc;          //设置结构体  
  6.     struct usb_endpoint_descriptor *endpoint;       //端点描述符  
  7.     size_t buffer_size;  
  8.     int i;  
  9.     int retval = -ENOMEM;  
  10.   
  11.     /* allocate memory for our device state and initialize it */  
  12.     dev = kzalloc(sizeof(*dev), GFP_KERNEL);  
  13.     if (!dev) {  
  14.         err("Out of memory");  
  15.         goto error;  
  16.     }  
  17.     kref_init(&dev->kref);                           初始化内核引用计数  
  18.     sema_init(&dev->limit_sem, WRITES_IN_FLIGHT);    //初始化信号量  
  19.     mutex_init(&dev->io_mutex);                  //初始化互斥锁  
  20.     spin_lock_init(&dev->err_lock);                  //初始化自旋锁  
  21.     init_usb_anchor(&dev->submitted);                  
  22.     init_completion(&dev->bulk_in_completion);       //初始化完成量  
  23.   
  24.     dev->udev = usb_get_dev(interface_to_usbdev(interface)); //获取usb_device结构体  
  25.     dev->interface = interface;                              //获取usb_ interface结构体  
  26.   
  27.     /* set up the endpoint information */  
  28.     /* use only the first bulk-in and bulk-out endpoints */  
  29.     iface_desc = interface->cur_altsetting;                      //由接口获取当前设置  
  30.     for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {            //根据端点个数逐一扫描端点  
  31.         endpoint = &iface_desc->endpoint[i].desc;                //由设置获取端点描述符  
  32.   
  33.         if (!dev->bulk_in_endpointAddr &&  
  34.             usb_endpoint_is_bulk_in(endpoint)) {                        //如果端点为批量输入端点  
  35.             /* we found a bulk in endpoint */  
  36.             buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);     //缓冲大小  
  37.             dev->bulk_in_size = buffer_size;  
  38.             dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;   //端点地址  
  39.             dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);      //缓冲区  
  40.             if (!dev->bulk_in_buffer) {  
  41.                 err("Could not allocate bulk_in_buffer");  
  42.                 goto error;  
  43.             }  
  44.             dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL);         //分配URB空间  
  45.             if (!dev->bulk_in_urb) {  
  46.                 err("Could not allocate bulk_in_urb");  
  47.                 goto error;  
  48.             }  
  49.         }  
  50.   
  51.         if (!dev->bulk_out_endpointAddr &&  
  52.             usb_endpoint_is_bulk_out(endpoint)) {                   //如果端点为批量输出端点  
  53.             /* we found a bulk out endpoint */  
  54.             dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;//端点地址  
  55.         }  
  56.     }  
  57.     if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) { //都不是批量端点  
  58.         err("Could not find both bulk-in and bulk-out endpoints");  
  59.         goto error;  
  60.     }  
  61.   
  62.     /* save our data pointer in this interface device */  
  63.     usb_set_intfdata(interface, dev);                   //将特定设备结构体设置为接口的私有数据  
  64.   
  65.     /* we can register the device now, as it is ready */  
  66.     retval = usb_register_dev(interface, &skel_class);  //注册USB设备  
  67.     if (retval) {  
  68.         /* something prevented us from registering this driver */  
  69.         err("Not able to get a minor for this device.");  
  70.         usb_set_intfdata(interface, NULL);  
  71.         goto error;  
  72.     }  
  73.   
  74.     /* let the user know what node this device is now attached to */  
  75.     dev_info(&interface->dev,  
  76.          "USB Skeleton device now attached to USBSkel-%d",  
  77.          interface->minor);  
  78.     return 0;  
  79.   
  80. error:  
  81.     if (dev)  
  82.         /* this frees allocated memory */  
  83.         kref_put(&dev->kref, skel_delete);  
  84.     return retval;  
  85. }  

通过上面分析,我们知道,usb_driver的probe函数中根据usb_interface的成员寻找第一个批量输入和输出的端点,将端点地址、缓冲区等信息存入USB骨架程序定义的usb_skel结构体中,并将usb_skel通过usb_set_intfdata传为USB接口的私有数据,最后注册USB设备。

我们来看看这个USB骨架程序定义的usb_skel结构体

[cpp] 
  1. /* Structure to hold all of our device specific stuff */  
  2. struct usb_skel {  
  3.     struct usb_device   *udev;              /* the usb device for this device */  
  4.     struct usb_interface    *interface;     /* the interface for this device */  
  5.     struct semaphore    limit_sem;          /* limiting the number of writes in progress */  
  6.     struct usb_anchor   submitted;          /* in case we need to retract our submissions */  
  7.     struct urb      *bulk_in_urb;               /* the urb to read data with */  
  8.     unsigned char   *bulk_in_buffer;            /* the buffer to receive data */  
  9.     size_t      bulk_in_size;               /* the size of the receive buffer */  
  10.     size_t      bulk_in_filled;             /* number of bytes in the buffer */  
  11.     size_t      bulk_in_copied;         /* already copied to user space */  
  12.     __u8        bulk_in_endpointAddr;       /* the address of the bulk in endpoint */  
  13.     __u8        bulk_out_endpointAddr;  /* the address of the bulk out endpoint */  
  14.     int         errors;                 /* the last request tanked */  
  15.     int         open_count;             /* count the number of openers */  
  16.     bool            ongoing_read;               /* a read is going on */  
  17.     bool            processed_urb;          /* indicates we haven't processed the urb */  
  18.     spinlock_t      err_lock;               /* lock for errors */  
  19.     struct kref     kref;  
  20.     struct mutex        io_mutex;           /* synchronize I/O with disconnect */  
  21.     struct completion   bulk_in_completion; /* to wait for an ongoing read */  
  22. };  
  23. #define to_skel_dev(d) container_of(d, struct usb_skel, kref)  

 

好了看完了probe,我们再看看disconnect函数

[cpp] 
  1. static void skel_disconnect(struct usb_interface *interface)  
  2. {  
  3.       struct usb_skel *dev;  
  4.       int minor = interface->minor;                  //获得接口的次设备号  
  5.       dev = usb_get_intfdata(interface);            //获取接口的私有数据  
  6.       usb_set_intfdata(interface, NULL);            //设置接口的私有数据为空  
  7.     /* give back our minor */  
  8.       usb_deregister_dev(interface, &skel_class);       //注销USB设备  
  9.       
  10.     /* prevent more I/O from starting */  
  11.       mutex_lock(&dev->io_mutex);  
  12.       dev->interface = NULL;           
  13.       mutex_unlock(&dev->io_mutex);  
  14.       
  15.       usb_kill_anchored_urbs(&dev->submitted);  
  16.     /* decrement our usage count */  
  17.       kref_put(&dev->kref, skel_delete);  
  18.       dev_info(&interface->dev, "USB Skeleton #%d now disconnected", minor);  
  19. }  

我们在skel_probe中最后执行了usb_register_dev(interface, &skel_class)来注册了一个USB设备,我们看看skel_class的定义

[cpp] 
  1. /* 
  2.  * usb class driver info in order to get a minor number from the usb core, 
  3.  * and to have the device registered with the driver core 
  4.  */  
  5. static struct usb_class_driver skel_class = {  
  6.       .name =           "skel%d",  
  7.       .fops =           &skel_fops,  
  8.       .minor_base =     USB_SKEL_MINOR_BASE,  
  9. };  
  10.   
  11. static const struct file_operations skel_fops = {  
  12.     .owner =    THIS_MODULE,  
  13.     .read = skel_read,  
  14.     .write =    skel_write,  
  15.     .open = skel_open,  
  16.     .release =  skel_release,  
  17.     .flush =    skel_flush,  
  18.     .llseek =   noop_llseek,  
  19. };  

 

根据上面代码我们知道,其实我们在probe中注册USB设备的时候使用的skel_class是一个包含file_operations的结构体,而这个结构体正是字符设备文件操作结构体。

我们先来看看这个file_operations中open函数的实现

[cpp] 
  1. static int skel_open(struct inode *inode, struct file *file)  
  2. {  
  3.     struct usb_skel *dev;  
  4.     struct usb_interface *interface;  
  5.     int subminor;  
  6.     int retval = 0;  
  7.   
  8.     subminor = iminor(inode);       //获得次设备号  
  9.     //根据usb_driver和次设备号获取设备的接口  
  10. interface = usb_find_interface(&skel_driver, subminor);  
  11.     if (!interface) {  
  12.         err("%s - error, can't find device for minor %d",  
  13.              __func__, subminor);  
  14.         retval = -ENODEV;  
  15.         goto exit;  
  16.     }  
  17.   
  18.     dev = usb_get_intfdata(interface);          //获取接口的私有数据usb_ske  
  19.     if (!dev) {  
  20.         retval = -ENODEV;  
  21.         goto exit;  
  22.     }  
  23.   
  24.     /* increment our usage count for the device */  
  25.     kref_get(&dev->kref);  
  26.   
  27.     /* lock the device to allow correctly handling errors 
  28.      * in resumption */  
  29.     mutex_lock(&dev->io_mutex);  
  30.   
  31.     if (!dev->open_count++) {  
  32.         retval = usb_autopm_get_interface(interface);  
  33.             if (retval) {  
  34.                 dev->open_count--;  
  35.                 mutex_unlock(&dev->io_mutex);  
  36.                 kref_put(&dev->kref, skel_delete);  
  37.                 goto exit;  
  38.             }  
  39.     } /* else { //uncomment this block if you want exclusive open 
  40.         retval = -EBUSY; 
  41.         dev->open_count--; 
  42.         mutex_unlock(&dev->io_mutex); 
  43.         kref_put(&dev->kref, skel_delete); 
  44.         goto exit; 
  45.     } */  
  46.     /* prevent the device from being autosuspended */  
  47.   
  48.     /* save our object in the file's private structure */  
  49.     file->private_data = dev;            //将usb_skel设置为文件的私有数据  
  50.     mutex_unlock(&dev->io_mutex);  
  51.   
  52. exit:  
  53.     return retval;  
  54. }  

 

这个open函数实现非常简单,它根据usb_driver和次设备号通过usb_find_interface获取USB接口,然后通过usb_get_intfdata获得接口的私有数据并赋值给文件。

好了,我们看看write函数,在write函数中,我们进行了urb的分配、初始化和提交的操作

[cpp] 
  1. static ssize_t skel_write(struct file *file, const char *user_buffer,  
  2.               size_t count, loff_t *ppos)  
  3. {  
  4.     struct usb_skel *dev;  
  5.     int retval = 0;  
  6.     struct urb *urb = NULL;  
  7.     char *buf = NULL;  
  8.     size_t writesize = min(count, (size_t)MAX_TRANSFER);        //待写数据大小  
  9.   
  10.     dev = file->private_data;                                //获取文件的私有数据  
  11.   
  12.     /* verify that we actually have some data to write */  
  13.     if (count == 0)  
  14.         goto exit;  
  15.   
  16.     /* 
  17.      * limit the number of URBs in flight to stop a user from using up all 
  18.      * RAM 
  19.      */  
  20.     if (!(file->f_flags & O_NONBLOCK)) {                 //如果文件采用非阻塞方式  
  21.         if (down_interruptible(&dev->limit_sem)) {           //获取限制读的次数的信号量  
  22.             retval = -ERESTARTSYS;  
  23.             goto exit;  
  24.         }  
  25.     } else {  
  26.         if (down_trylock(&dev->limit_sem)) {  
  27.             retval = -EAGAIN;  
  28.             goto exit;  
  29.         }  
  30.     }  
  31.   
  32.     spin_lock_irq(&dev->err_lock);       //关中断  
  33.     retval = dev->errors;  
  34.     if (retval < 0) {  
  35.         /* any error is reported once */  
  36.         dev->errors = 0;  
  37.         /* to preserve notifications about reset */  
  38.         retval = (retval == -EPIPE) ? retval : -EIO;  
  39.     }  
  40.     spin_unlock_irq(&dev->err_lock);     //开中断  
  41.     if (retval < 0)  
  42.         goto error;  
  43.   
  44.     /* create a urb, and a buffer for it, and copy the data to the urb */  
  45.     urb = usb_alloc_urb(0, GFP_KERNEL); //分配urb  
  46.     if (!urb) {  
  47.         retval = -ENOMEM;  
  48.         goto error;  
  49.     }  
  50.   
  51.     buf = usb_alloc_coherent(dev->udev, writesize, GFP_KERNEL,  
  52.                  &urb->transfer_dma);    //分配写缓冲区  
  53.     if (!buf) {  
  54.         retval = -ENOMEM;  
  55.         goto error;  
  56.     }  
  57.     //将用户空间数据拷贝到缓冲区  
  58.     if (copy_from_user(buf, user_buffer, writesize)) {  
  59.         retval = -EFAULT;  
  60.         goto error;  
  61.     }  
  62.   
  63.     /* this lock makes sure we don't submit URBs to gone devices */  
  64.     mutex_lock(&dev->io_mutex);  
  65.     if (!dev->interface) {       /* disconnect() was called */  
  66.         mutex_unlock(&dev->io_mutex);  
  67.         retval = -ENODEV;  
  68.         goto error;  
  69.     }  
  70.   
  71.     /* initialize the urb properly */  
  72.     usb_fill_bulk_urb(urb, dev->udev,  
  73.               usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),  
  74.               buf, writesize, skel_write_bulk_callback, dev);   //填充urb  
  75.     urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;  //urb->transfer_dma有效  
  76.     usb_anchor_urb(urb, &dev->submitted);  
  77.   
  78.     /* send the data out the bulk port */  
  79.     retval = usb_submit_urb(urb, GFP_KERNEL);               //提交urb  
  80.     mutex_unlock(&dev->io_mutex);  
  81.     if (retval) {  
  82.         err("%s - failed submitting write urb, error %d", __func__,  
  83.             retval);  
  84.         goto error_unanchor;  
  85.     }  
  86.   
  87.     /* 
  88.      * release our reference to this urb, the USB core will eventually free 
  89.      * it entirely 
  90.      */  
  91.     usb_free_urb(urb);  
  92.   
  93.   
  94.     return writesize;  
  95.   
  96. error_unanchor:  
  97.     usb_unanchor_urb(urb);  
  98. error:  
  99.     if (urb) {  
  100.         usb_free_coherent(dev->udev, writesize, buf, urb->transfer_dma);  
  101.         usb_free_urb(urb);  
  102.     }  
  103.     up(&dev->limit_sem);  
  104.   
  105. exit:  
  106.     return retval;  
  107. }  

 

首先说明一个问题,填充urb后,设置了transfer_flags标志,当transfer_flags中的URB_NO_TRANSFER_DMA_MAP被设置,USB核心使用transfer_dma指向的缓冲区而不是使用transfer_buffer 指向的缓冲区,这表明即将传输DMA缓冲区。当transfer_flags中的URB_NO_SETUP_DMA_MAP被设置,如果控制urb有 DMA缓冲区,USB核心将使用setup_dma指向的缓冲区而不是使用setup_packet指向的缓冲区。

另外,通过上面这个write函数我们知道,当写函数发起的urb结束后,其完成函数skel_write_bulk_callback会被调用,我们继续跟踪

[cpp] 
  1. static void skel_write_bulk_callback(struct urb *urb)  
  2. {  
  3.     struct usb_skel *dev;  
  4.   
  5.     dev = urb->context;  
  6.   
  7.     /* sync/async unlink faults aren't errors */  
  8.     if (urb->status) {  
  9.         if (!(urb->status == -ENOENT ||  
  10.             urb->status == -ECONNRESET ||  
  11.             urb->status == -ESHUTDOWN))  
  12.             err("%s - nonzero write bulk status received: %d",  
  13.                 __func__, urb->status);  
  14.   
  15.         spin_lock(&dev->err_lock);  
  16.         dev->errors = urb->status;  
  17.         spin_unlock(&dev->err_lock);  
  18.     }  
  19.   
  20.     /* free up our allocated buffer */  
  21.     usb_free_coherent(urb->dev, urb->transfer_buffer_length,  
  22.               urb->transfer_buffer, urb->transfer_dma);  
  23.     up(&dev->limit_sem);  
  24. }  

很明显,skel_write_bulk_callback主要对urb->status进行判断,根据错误提示显示错误信息,然后释放urb空间。

接着,我们看看USB骨架程序的字符设备的read函数

[cpp] 
  1. static ssize_t skel_read(struct file *file, char *buffer, size_t count,  
  2.              loff_t *ppos)  
  3. {  
  4.     struct usb_skel *dev;  
  5.     int rv;  
  6.     bool ongoing_io;  
  7.   
  8.     dev = file->private_data;                    //获得文件私有数据  
  9.   
  10.     /* if we cannot read at all, return EOF */  
  11.     if (!dev->bulk_in_urb || !count)         //正在写的时候禁止读操作  
  12.         return 0;  
  13.   
  14.     /* no concurrent readers */  
  15.     rv = mutex_lock_interruptible(&dev->io_mutex);  
  16.     if (rv < 0)  
  17.         return rv;  
  18.   
  19.     if (!dev->interface) {       /* disconnect() was called */  
  20.         rv = -ENODEV;  
  21.         goto exit;  
  22.     }  
  23.   
  24.     /* if IO is under way, we must not touch things */  
  25. retry:  
  26.     spin_lock_irq(&dev->err_lock);  
  27.     ongoing_io = dev->ongoing_read;  
  28.     spin_unlock_irq(&dev->err_lock);  
  29.   
  30.     if (ongoing_io) {       //USB core正在读取数据,数据没准备好  
  31.         /* nonblocking IO shall not wait */  
  32.         if (file->f_flags & O_NONBLOCK) {  
  33.             rv = -EAGAIN;  
  34.             goto exit;  
  35.         }  
  36.         /* 
  37.          * IO may take forever 
  38.          * hence wait in an interruptible state 
  39.          */  
  40.         rv = wait_for_completion_interruptible(&dev->bulk_in_completion);  
  41.         if (rv < 0)  
  42.             goto exit;  
  43.         /* 
  44.          * by waiting we also semiprocessed the urb 
  45.          * we must finish now 
  46.          */  
  47.         dev->bulk_in_copied = 0;     //拷贝到用户空间操作已成功  
  48.         dev->processed_urb = 1;      //目前已处理好urb  
  49.     }  
  50.   
  51.     if (!dev->processed_urb) {           //目前还未处理好urb  
  52.         /* 
  53.          * the URB hasn't been processed 
  54.          * do it now 
  55.          */  
  56.         wait_for_completion(&dev->bulk_in_completion);   //等待完成  
  57.         dev->bulk_in_copied = 0;     //拷贝到用户空间操作已成功  
  58.         dev->processed_urb = 1;      //目前已处理好urb  
  59.     }  
  60.   
  61.     /* errors must be reported */  
  62.     rv = dev->errors;  
  63.     if (rv < 0) {  
  64.         /* any error is reported once */  
  65.         dev->errors = 0;  
  66.         /* to preserve notifications about reset */  
  67.         rv = (rv == -EPIPE) ? rv : -EIO;  
  68.         /* no data to deliver */  
  69.         dev->bulk_in_filled = 0;  
  70.         /* report it */  
  71.         goto exit;  
  72.     }  
  73.   
  74.     /* 
  75.      * if the buffer is filled we may satisfy the read 
  76.      * else we need to start IO 
  77.      */  
  78.   
  79.     if (dev->bulk_in_filled) {                   //缓冲区有内容  
  80.         /* we had read data */  
  81.         //可读数据大小为缓冲区内容减去已经拷贝到用户空间的数据大小  
  82.         size_t available = dev->bulk_in_filled - dev->bulk_in_copied;  
  83.         size_t chunk = min(available, count);   //真正读取的数据大小  
  84.   
  85.         if (!available) {  
  86.             /* 
  87.              * all data has been used 
  88.              * actual IO needs to be done 
  89.              */  
  90.             rv = skel_do_read_io(dev, count);  
  91.             if (rv < 0)  
  92.                 goto exit;  
  93.             else  
  94.                 goto retry;  
  95.         }  
  96.         /* 
  97.          * data is available 
  98.          * chunk tells us how much shall be copied 
  99.          */  
  100.         //拷贝缓冲区数据到用户空间  
  101.         if (copy_to_user(buffer,  
  102.                  dev->bulk_in_buffer + dev->bulk_in_copied,  
  103.                  chunk))  
  104.             rv = -EFAULT;  
  105.         else  
  106.             rv = chunk;  
  107.   
  108.         dev->bulk_in_copied += chunk;    //目前拷贝完成的数据大小  
  109.   
  110.         /* 
  111.          * if we are asked for more than we have, 
  112.          * we start IO but don't wait 
  113.          */  
  114.         if (available < count)  
  115.             skel_do_read_io(dev, count - chunk);  
  116.     } else {  
  117.         /* no data in the buffer */  
  118.         rv = skel_do_read_io(dev, count);  
  119.         if (rv < 0)  
  120.             goto exit;  
  121.         else if (!(file->f_flags & O_NONBLOCK))  
  122.             goto retry;  
  123.         rv = -EAGAIN;  
  124.     }  
  125. exit:  
  126.     mutex_unlock(&dev->io_mutex);  
  127.     return rv;  
  128. }  

 

通过上面read函数,我们知道,在读取数据时候,如果发现缓冲区没有数据,或者缓冲区的数据小于用户需要读取的数据量时,则会调用IO操作,也就是skel_do_read_io函数。

[cpp] 
  1. static int skel_do_read_io(struct usb_skel *dev, size_t count)  
  2. {  
  3.       int rv;  
  4.       
  5.     /* prepare a read */  
  6.       usb_fill_bulk_urb(dev->bulk_in_urb,dev->udev,usb_rcvbulkpipe(dev->udev,  
  7.                             dev->bulk_in_endpointAddr),dev->bulk_in_buffer,  
  8.                     min(dev->bulk_in_size, count),skel_read_bulk_callback,dev);  //填充urb  
  9.     /* tell everybody to leave the URB alone */  
  10.       spin_lock_irq(&dev->err_lock);  
  11.       dev->ongoing_read = 1;                                         //标志正在读取数据中  
  12.       spin_unlock_irq(&dev->err_lock);  
  13.       
  14.       rv = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL);             //提交urb  
  15.       if (rv < 0) {  
  16.               err("%s - failed submitting read urb, error %d",  
  17.                     __func__, rv);  
  18.               dev->bulk_in_filled = 0;  
  19.               rv = (rv == -ENOMEM) ? rv : -EIO;  
  20.               spin_lock_irq(&dev->err_lock);  
  21.               dev->ongoing_read = 0;  
  22.               spin_unlock_irq(&dev->err_lock);  
  23.       }  
  24.       return rv;  
  25. }  

 

好了,其实skel_do_read_io只是完成了urb的填充和提交,USB core读取到了数据后,会调用填充urb时设置的回调函数skel_read_bulk_callback。

[cpp] 
  1. static void skel_read_bulk_callback(struct urb *urb)  
  2. {  
  3.     struct usb_skel *dev;  
  4.   
  5.     dev = urb->context;  
  6.   
  7.     spin_lock(&dev->err_lock);  
  8.     /* sync/async unlink faults aren't errors */  
  9.     if (urb->status) {
    //根据返回状态判断是否出错  
  10.         if (!(urb->status == -ENOENT ||  
  11.             urb->status == -ECONNRESET ||  
  12.             urb->status == -ESHUTDOWN))  
  13.             err("%s - nonzero write bulk status received: %d",  
  14.                 __func__, urb->status);  
  15.   
  16.         dev->errors = urb->status;  
  17.     } else {  
  18.         dev->bulk_in_filled = urb->actual_length; //记录缓冲区的大小  
  19.     }  
  20.     dev->ongoing_read = 0;                       //已经读取数据完毕  
  21.     spin_unlock(&dev->err_lock);  
  22.   
  23.     complete(&dev->bulk_in_completion);          //唤醒skel_read函数  
  24. }  

到目前为止,我们已经把USB驱动框架usb-skeleton.c分析完了,总结下,其实很简单,在模块加载里面注册 usb_driver,然后在probe函数里初始化一些参数,最重要的是注册了USB设备,这个USB设备相当于一个字符设备,提供 file_operations接口。然后设计open,close,read,write函数,这个open里基本没做什么事情,在write中,通过分配urb、填充urb和提交urb。注意读的urb的分配在probe里申请空间,写的urb的分配在write里申请空间。在这个驱动程序中,我们重点掌握usb_fill_bulk_urb的设计。

转载于:https://www.cnblogs.com/MMLoveMeMM/articles/4105659.html

转载地址:https://blog.csdn.net/FLY_THINK2012/article/details/101840948 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Android属性之build.prop生成过程分析
下一篇:APP添加jar包在源码下编译

发表评论

最新留言

表示我来过!
[***.240.166.169]2024年03月11日 22时46分20秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

java list 合并 重复的数据_Java ArrayList合并并删除重复数据3种方法 2019-04-21
android volley 上传图片 和参数,android - 使用android中的volley将图像上传到multipart中的服务器 - 堆栈内存溢出... 2019-04-21
android开发的取消清空按钮,Android开发实现带清空按钮的EditText示例 2019-04-21
android gp服务,ArcGIS Runtime SDK for Android开发之调用GP服务(异步调用) 2019-04-21
mysql整体会滚_滚mysql 2019-04-21
向mysql数据库中添加批量数据类型_使用JDBC在MySQL数据库中快速批量插入数据 2019-04-21
最全的mysql 5.7.13_最全的mysql 5.7.13 安装配置方法图文教程(linux) 强烈推荐! 2019-04-21
mssql连接mysql数据库文件_在本地 怎么远程连接MSSQL数据库 2019-04-21
mssql 远程无法连接mysql_解决SQLServer远程连接失败的问题 2019-04-21
linux mysql c++编程_Linux下进行MYSQL的C++编程起步手记 2019-04-21
Maria数据库怎么复制到mysql_MySQL、MariaDB数据库的AB复制配置过程 2019-04-21
mysql5.6 icp mrr bak_【mysql】关于ICP、MRR、BKA等特性 2019-04-21
mysql utf8跟utf8mb4_MySQL utf8 和 utf8mb4 的区别 2019-04-21
docker mysql开机自启动_Docker学习4-学会如何让容器开机自启服务【坑】 2019-04-21
在mysql中删除表正确的是什么_在MySQL中删除表的操作教程 2019-04-21
mysql有3个共同好友_共同好友mysql 2019-04-21
代理查询 mysql_查询数据库代理设置 2019-04-21
mysql dif_mysqldiff实现MySQL数据表比较 2019-04-21
mysql 允许其他主机访问权限_允许其他主机访问本机MySQL 2019-04-21
druid不能close mysql连接_alibaba druid mysql连接问题 2019-04-21