Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1048941
  • 博文数量: 326
  • 博客积分: 10135
  • 博客等级: 上将
  • 技术积分: 2490
  • 用 户 组: 普通用户
  • 注册时间: 2006-04-22 23:53
文章分类

全部博文(326)

文章存档

2014年(1)

2012年(4)

2011年(1)

2010年(4)

2009年(41)

2008年(44)

2007年(63)

2006年(168)

我的朋友

分类: LINUX

2009-08-03 11:04:08

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 < 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;

     }

阅读(777) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~