免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1645 | 回复: 0
打印 上一主题 下一主题

Linux USB驱动框架分析(四) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-08-03 11:04 |只看该作者 |倒序浏览

probe是usb子系统自动调用的一个函数,有USB设备接到硬件集线器时,usb子系统
会根据production ID和vendor
ID的组合或者设备的class、subclass跟protocol的组合来识别设备调用相应驱动程序的probe(探测)函数,对于skeleton
来说,就是skel_probe。系统会传递给探测函数一个usb_interface *跟一个struct usb_device_id
*作为参数。他们分别是该USB设备的接口描述(一般会是该设备的第0号接口,该接口的默认设置也是第0号设置)跟它的设备ID描述(包括Vendor
ID、Production ID等)。Probe函数比较长,我们分段来分析这个函数:
     dev->udev = usb_get_dev(interface_to_usbdev(interface));
     dev->interface = interface;
在初始化了一些资源之后,我们可以看到第一个关键的函数调用——
interface_to_usbdev。他同uo一个usb_interface来得到该接口所在设备的设备描述结构。本来,要得到一个
usb_device只要用interface_to_usbdev就够了,但因为要增加对该usb_device的引用计数,我们应该在做一个
usb_get_dev的操作,来增加引用计数,并在释放设备时用usb_put_dev来减少引用计数。这里要解释的是,该引用计数值是对该
usb_device的计数,并不是对本模块的计数,本模块的计数要由kref来维护。所以,probe一开始就有初始化kref。事实
上,kref_init操作不单只初始化kref,还将其置设成1。所以在出错处理代码中有kref_put,它把kref的计数减1,如果kref计数
已经为0,那么kref会被释放。Kref_put的第二个参数是一个函数指针,指向一个清理函数。注意,该指针不能位空,或者kfree。该函数会在最
后一个对kref的引用释放时被调用(如果我的理解不准确,请指正)。下面是内核源码中的一段注释及代码:
/**
* kref_put - decrement refcount for object.
* @kref: object.
* @release: pointer to the function that will clean up the object when the
*        last reference to the object is released.
*        This pointer is required, and it is not acceptable to pass kfree
*        in as this function.
*
* Decrement the refcount, and if 0, call release().
* Return 1 if the object was removed, otherwise return 0.  Beware, if this
* function returns 0, you still can not count on the kref from remaining in
* memory.  Only use the return value if you want to see if the kref is now
* gone, not present.
*/
int kref_put(struct kref *kref, void (*release)(struct kref *kref))
{
     WARN_ON(release == NULL);
     WARN_ON(release == (void (*)(struct kref *))kfree);

     /*
      * if current count is one, we are the last user and can release object
      * right now, avoiding an atomic operation on 'refcount'
      */
     if ((atomic_read(&kref->refcount) == 1) ||
         (atomic_dec_and_test(&kref->refcount))) {
         release(kref);
         return 1;
     }
     return 0;
}
当我们执行打开操作时,我们要增加kref的计数,我们可以用kref_get,来完成。所有对struct kref的操作都有内核代码确保其原子性。
得到了该usb_device之后,我们要对我们自定义的usb_skel各个状态跟资源作
初始化。这部分工作的任务主要是向usb_skel注册该usb设备的端点。这里可能要补充以下一些关于
usb_interface_descriptor的知识,但因为内核源码对该结构体的注释不多,所以只能靠个人猜测。在一个
usb_host_interface结构里面有一个usb_interface_descriptor叫做desc的成员,他应该是用于描述该
interface的一些属性,其中bNubEndpoints一个8位(b for
byte)的数字,他代表了该接口的端点数。Probe然后遍历所有的端点,检查他们的类型跟方向,注册到usb_skel中。
     /* set up the endpoint information */
     /* use only the first bulk-in and bulk-out endpoints */
     iface_desc = interface->cur_altsetting;
     for (i = 0; i desc.bNumEndpoints; ++i) {
         endpoint = &iface_desc->endpoint.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;
     }
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/17928/showart_2016079.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP