usb_serial部分分析3

来源:互联网 发布:zara淘宝没有了 编辑:程序博客网 时间:2024/06/04 00:45

转自http://blog.csdn.net/aaronychen/article/details/3555885

generic.c:

static int generic_probe(struct usb_interface *interface,

                            const struct usb_device_id *id)

{

       const struct usb_device_id *id_pattern;

 

       id_pattern = usb_match_id(interface,  generic_device_ids);  //设备匹

       if (id_pattern != NULL)

              return usb_serial_probe(interface, id);  //进一步匹配

       return -ENODEV;

}

如果接入系统的设备的vendor和product与我们驱动支持的设备列表匹配则调用usb_serial_probe来进一步匹配.

usb_serial_probe函数比较长, 我们一段段的来看

usb-serial.c:

int usb_serial_probe(struct usb_interface *interface,

                            const struct usb_device_id *id)

{

       struct usb_device *dev = interface_to_usbdev (interface);

       struct usb_serial *serial = NULL;

       struct usb_serial_port *port;

       struct usb_host_interface *iface_desc;

       struct usb_endpoint_descriptor *endpoint;

       struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];

       struct usb_endpoint_descriptor *interrupt_out_endpoint[MAX_NUM_PORTS];

       struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];

       struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];

       struct usb_serial_driver *type = NULL;

       int retval;

       int minor;

       int buffer_size;

       int i;

       int num_interrupt_in = 0;

       int num_interrupt_out = 0;

       int num_bulk_in = 0;

       int num_bulk_out = 0;

       int num_ports = 0;

       int max_endpoints;

 

       type = search_serial_device(interface);  //获取该设备匹配的驱动

       if (!type) {

              dbg("none matched");

              return -ENODEV;

       }

......

}

首先是找到合适的驱动程序.

usb-serial.c:

static struct usb_serial_driver *search_serial_device(struct usb_interface *iface)

{

       struct list_head *p;

       const struct usb_device_id *id;

       struct usb_serial_driver *t;

 

       /* Check if the usb id matches a known device */

       list_for_each(p, &usb_serial_driver_list) {

              t = list_entry(p, struct usb_serial_driver, driver_list);

              id = usb_match_id(iface, t->id_table);   //看设备列表是否匹配

              if (id != NULL) {

                     dbg("descriptor matches");

                     return t;   //返回匹配的驱动

              }

       }

 

       return NULL;

}

实际上这边的匹配和generic_probe里的匹配重复了, 因为他们的匹配的设备列表是同一个,  这边主要是为了得到匹配的驱动程序, 根据上面的代码分析我们可以知道这里匹配的驱动是usb_serial_generic_device.

接着看usb_serial_probe()

usb-serial.c:

....

       serial = create_serial (dev, interface, type);   //为该设备创建一个usb_serial对象

       if (!serial) {

              dev_err(&interface->dev, "%s - out of memory/n", __FUNCTION__);

              return -ENOMEM;

       }

 

       /* if this device type has a probe function, call it */

       if (type->probe) {   //从上面分析的代码可知这里的probe函数没有赋值

              const struct usb_device_id *id;

 

              if (!try_module_get(type->driver.owner)) {

                     dev_err(&interface->dev, "module get failed, exiting/n");

                     kfree (serial);

                     return -EIO;

              }

 

              id = usb_match_id(interface, type->id_table);

              retval = type->probe(serial, id);

              module_put(type->driver.owner);

 

              if (retval) {

                     dbg ("sub driver rejected device");

                     kfree (serial);

                     return retval;

              }

       }

....

这段代码可知, 主要是创建一个usb_serial的对象, 用于保存该设备的详细信息, 一般的驱动程序都会为自己匹配的设备创建一个描用于描述该设备的对象. 在以后的所有操作中如读写等都会直接从这个对象里获取相应的信息.

usb-serial.c:

static struct usb_serial * create_serial (struct usb_device *dev,

                                     struct usb_interface *interface,

                                     struct usb_serial_driver *driver)

{

       struct usb_serial *serial;

 

       serial = kmalloc (sizeof (*serial), GFP_KERNEL);  //创造该对象

       if (!serial) {

              dev_err(&dev->dev, "%s - out of memory/n", __FUNCTION__);

              return NULL;

       }

    //初始化该对象

       memset (serial, 0, sizeof(*serial));

       serial->dev = usb_get_dev(dev);   //增加dev的引用计数

       serial->type = driver;  

       serial->interface = interface; 

       kref_init(&serial->kref);

 

       return serial;

}

这个函数就是用来创建usb_serial对象的,并把相关信息保存在里面.

继续看usb_serial_probe()

usb-serial.c:

....

       /* descriptor matches, let's find the endpoints needed */

       /* check out the endpoints */

    //查找该设备使用的endpoint的描述符, 并检查是否正确

       iface_desc = interface->cur_altsetting;   //接口描述符

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

              endpoint =& iface_desc->endpoint[i].desc;  //端点描述符

             

              if ((endpoint->bEndpointAddress& 0x80) &&

                  ((endpoint->bmAttributes & 3) == 0x02)) {

                     /* we found a bulk in endpoint */   //bulk in 的端点

                     dbg("found bulk in on endpoint %d", i);

                     bulk_in_endpoint[num_bulk_in] = endpoint;

                     ++num_bulk_in;

              }

 

              if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&

                  ((endpoint->bmAttributes & 3) == 0x02)) {

                     /* we found a bulk out endpoint */   //bulk out的端点

                     dbg("found bulk out on endpoint %d", i);

                     bulk_out_endpoint[num_bulk_out] = endpoint;

                     ++num_bulk_out;

              }

             

              if ((endpoint->bEndpointAddress& 0x80) &&

                  ((endpoint->bmAttributes & 3) == 0x03)) {

                     /* we found a interrupt in endpoint */    //中断 in 端点

                     dbg("found interrupt in on endpoint %d", i);

                     interrupt_in_endpoint[num_interrupt_in] = endpoint;

                     ++num_interrupt_in;

              }

 

              if (((endpoint->bEndpointAddress& 0x80) == 0x00) &&

                  ((endpoint->bmAttributes & 3) == 0x03)) {

                     /* we found an interrupt out endpoint */ //中断 out 端点

                     dbg("found interrupt out on endpoint %d", i);

                     interrupt_out_endpoint[num_interrupt_out] = endpoint;

                     ++num_interrupt_out;

              }

       }

.....

该段代码主要是获取该设备使用的各个类型及方向的端点描述府, 并保存起来, 关于端点的类型与方向可以参考USB的规范.

继续看usb_serial_probe()

usb-serial.c:

....

#if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE)

       /* BEGIN HORRIBLE HACK FOR PL2303 */

       /* this is needed due to the looney way its endpoints are set up */

       if (((le16_to_cpu(dev->descriptor.idVendor) == PL2303_VENDOR_ID) &&

            (le16_to_cpu(dev->descriptor.idProduct) == PL2303_PRODUCT_ID)) ||

           ((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) &&

            (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID))) {

              if (interface != dev->actconfig->interface[0]) {

                     /* check out the endpoints of the other interface*/

                     iface_desc = dev->actconfig->interface[0]->cur_altsetting;

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

                            endpoint = &iface_desc->endpoint[i].desc;

                            if ((endpoint->bEndpointAddress & 0x80) &&

                                ((endpoint->bmAttributes & 3) == 0x03)) {

                                   /* we found a interrupt in endpoint */

                                   dbg("found interrupt in for Prolific device on separate interface");

                                   interrupt_in_endpoint[num_interrupt_in] = endpoint;

                                   ++num_interrupt_in;

                            }

                     }

              }

 

              /* Now make sure the PL-2303 is configured correctly.

               * If not, give up now and hope this hack will work

               * properly during a later invocation of usb_serial_probe

               */

              if (num_bulk_in == 0 || num_bulk_out == 0) {

                     dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not/n");

                     kfree (serial);

                     return -ENODEV;

              }

       }

       /* END HORRIBLE HACK FOR PL2303 */

#endif

上面这段代码主要是用于特定类型设备的(PL2303), 这里我们不用管他.


原创粉丝点击