Linux那些事儿 之 戏说USB(30)驱动的生命线(二)
生活随笔
收集整理的這篇文章主要介紹了
Linux那些事儿 之 戏说USB(30)驱动的生命线(二)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
core配置設備使用的是message.c里的usb_set_configuration函數
先看第一階段,9行,configuration是前邊兒choose_configuration()那里返回回來的,找到合意的配置的話,就返回那個配置的bConfigurationValue值,沒有找到稱心的配置的話,就返回-1,所以這里的configuration值就可能有兩種情況,或者為-1,或者為配置的bConfigurationValue值。當configuration為-1時這里為啥又要把它改為0捏?要知道configuration這個值是要在后面的階段里發送SET_CONFIGURATION請求時用的,關于SET_CONFIGURATION請求,spec里說,這個值必須為0或者與配置描述符的bConfigurationValue一致,如果為0,則設備收到SET_CONFIGURATION請求后,仍然會待在Address狀態。這里當configuration為-1也就是沒有發現滿意的配置時,設備不能進入Configured,所以要把configuration的值改為0,以便滿足SET_CONFIGURATION請求的要求。
那接下來的問題就出來了,在沒有找到合適配置的時候直接給configuration這個參數傳個0,也就是讓choose_configuration()返回個0不就得了,干嗎還這么麻煩先返回個-1再把它改成0,不是脫褲子放屁多此一舉么?你別憤怒,這歸根結底還是那句話,林子大了什么鳥都有,有些設備就是有拿0當配置bConfigurationValue值的毛病,你又不能不讓它用。usb世界里出現幾個有毛病的設備也沒啥大不了的,這里妥協一下就是了,想讓設備回到Address狀態時,usb_set_configuration()就別傳遞0了,傳遞個-1,里邊兒去處理一下。如果configuration值為0或大于0的值,就從設備struct usb_device結構體的config數組里將相應配置的描述信息,也就是struct usb_host_config結構體給取出來。
20行,如果沒有拿到配置的內容,configuration值就必須為0了,讓設備待在Address那兒別動。這也很好理解,配置的內容都找不到了,還配置個什么勁兒。當然,如果拿到了配置的內容,但同時configuration為0,這就是對應了上面說的那種有毛病的設備的情況,就提出一下警告,告訴你不正常現象出現了。
33行,過了這個if,第一階段就告結束了。如果配置是實實在在存在的,就為它使用的那些接口都準備一個struct usb_interface結構體。new_interfaces是開頭兒就定義好的一個struct usb_interface結構體指針數組,數組的每一項都指向了一個struct usb_interface結構體,所以這里申請內存也要分兩步走,先申請指針數組的,再申請每一項的。
int usb_set_configuration(struct usb_device *dev, int configuration)
{int i, ret;struct usb_host_config *cp = NULL;struct usb_interface **new_interfaces = NULL;struct usb_hcd *hcd = bus_to_hcd(dev->bus);int n, nintf;if (dev->authorized == 0 || configuration == -1)configuration = 0;else {for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {if (dev->config[i].desc.bConfigurationValue ==configuration) {cp = &dev->config[i];break;}}}if ((!cp && configuration != 0))return -EINVAL;/* The USB spec says configuration 0 means unconfigured.* But if a device includes a configuration numbered 0,* we will accept it as a correctly configured state.* Use -1 if you really want to unconfigure the device.*/if (cp && configuration == 0)dev_warn(&dev->dev, "config 0 descriptor??\n");/* Allocate memory for new interfaces before doing anything else,* so that if we run out then nothing will have changed. */n = nintf = 0;if (cp) {nintf = cp->desc.bNumInterfaces;new_interfaces = kmalloc(nintf * sizeof(*new_interfaces),GFP_NOIO);if (!new_interfaces) {dev_err(&dev->dev, "Out of memory\n");return -ENOMEM;}for (; n < nintf; ++n) {new_interfaces[n] = kzalloc(sizeof(struct usb_interface),GFP_NOIO);if (!new_interfaces[n]) {dev_err(&dev->dev, "Out of memory\n");ret = -ENOMEM;
free_interfaces:while (--n >= 0)kfree(new_interfaces[n]);kfree(new_interfaces);return ret;}}i = dev->bus_mA - usb_get_max_power(dev, cp);if (i < 0)dev_warn(&dev->dev, "new config #%d exceeds power ""limit by %dmA\n",configuration, -i);}/* Wake up the device so we can send it the Set-Config request */ret = usb_autoresume_device(dev);if (ret)goto free_interfaces;/* if it's already configured, clear out old state first.* getting rid of old interfaces means unbinding their drivers.*/if (dev->state != USB_STATE_ADDRESS)usb_disable_device(dev, 1); /* Skip ep0 *//* Get rid of pending async Set-Config requests for this device */cancel_async_set_config(dev);/* Make sure we have bandwidth (and available HCD resources) for this* configuration. Remove endpoints from the schedule if we're dropping* this configuration to set configuration 0. After this point, the* host controller will not allow submissions to dropped endpoints. If* this call fails, the device state is unchanged.*/mutex_lock(hcd->bandwidth_mutex);/* Disable LPM, and re-enable it once the new configuration is* installed, so that the xHCI driver can recalculate the U1/U2* timeouts.*/if (dev->actconfig && usb_disable_lpm(dev)) {dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__);mutex_unlock(hcd->bandwidth_mutex);ret = -ENOMEM;goto free_interfaces;}ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);if (ret < 0) {if (dev->actconfig)usb_enable_lpm(dev);mutex_unlock(hcd->bandwidth_mutex);usb_autosuspend_device(dev);goto free_interfaces;}/** Initialize the new interface structures and the* hc/hcd/usbcore interface/endpoint state.*/for (i = 0; i < nintf; ++i) {struct usb_interface_cache *intfc;struct usb_interface *intf;struct usb_host_interface *alt;cp->interface[i] = intf = new_interfaces[i];intfc = cp->intf_cache[i];intf->altsetting = intfc->altsetting;intf->num_altsetting = intfc->num_altsetting;kref_get(&intfc->ref);alt = usb_altnum_to_altsetting(intf, 0);/* No altsetting 0? We'll assume the first altsetting.* We could use a GetInterface call, but if a device is* so non-compliant that it doesn't have altsetting 0* then I wouldn't trust its reply anyway.*/if (!alt)alt = &intf->altsetting[0];intf->intf_assoc =find_iad(dev, cp, alt->desc.bInterfaceNumber);intf->cur_altsetting = alt;usb_enable_interface(dev, intf, true);intf->dev.parent = &dev->dev;intf->dev.driver = NULL;intf->dev.bus = &usb_bus_type;intf->dev.type = &usb_if_device_type;intf->dev.groups = usb_interface_groups;intf->dev.dma_mask = dev->dev.dma_mask;INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);intf->minor = -1;device_initialize(&intf->dev);pm_runtime_no_callbacks(&intf->dev);dev_set_name(&intf->dev, "%d-%s:%d.%d",dev->bus->busnum, dev->devpath,configuration, alt->desc.bInterfaceNumber);}kfree(new_interfaces);ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),USB_REQ_SET_CONFIGURATION, 0, configuration, 0,NULL, 0, USB_CTRL_SET_TIMEOUT);if (ret < 0 && cp) {/** All the old state is gone, so what else can we do?* The device is probably useless now anyway.*/usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);for (i = 0; i < nintf; ++i) {usb_disable_interface(dev, cp->interface[i], true);put_device(&cp->interface[i]->dev);cp->interface[i] = NULL;}cp = NULL;}dev->actconfig = cp;mutex_unlock(hcd->bandwidth_mutex);if (!cp) {usb_set_device_state(dev, USB_STATE_ADDRESS);/* Leave LPM disabled while the device is unconfigured. */usb_autosuspend_device(dev);return ret;}usb_set_device_state(dev, USB_STATE_CONFIGURED);if (cp->string == NULL &&!(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))cp->string = usb_cache_string(dev, cp->desc.iConfiguration);/* Now that the interfaces are installed, re-enable LPM. */usb_unlocked_enable_lpm(dev);/* Enable LTM if it was turned off by usb_disable_device. */usb_enable_ltm(dev);/* Now that all the interfaces are set up, register them* to trigger binding of drivers to interfaces. probe()* routines may install different altsettings and may* claim() any interfaces not yet bound. Many class drivers* need that: CDC, audio, video, etc.*/for (i = 0; i < nintf; ++i) {struct usb_interface *intf = cp->interface[i];dev_dbg(&dev->dev,"adding %s (config #%d, interface %d)\n",dev_name(&intf->dev), configuration,intf->cur_altsetting->desc.bInterfaceNumber);device_enable_async_suspend(&intf->dev);ret = device_add(&intf->dev);if (ret != 0) {dev_err(&dev->dev, "device_add(%s) --> %d\n",dev_name(&intf->dev), ret);continue;}create_intf_ep_devs(intf);}usb_autosuspend_device(dev);return 0;
}說代碼前咱們再聊點這個函數背后的人生哲學,你設備不是和usb_generic_driver這個大美女配對成功了么,可是要想保持和她的這種親密關系,你就得準備著讓她去配置,準備著她想讓你什么樣你就什么樣。這個函數就可以涇渭分明的分成三個部分三個階段,從3到63的這幾十行是準備階段,做做常規檢查啊,申請申請內存什么的。70到177這部分可是重頭戲,就是在這里設備從Address發展到了Configured,可算是高潮階段。194到209這階段也挺重要的,主要就是充實充實設備的每個接口并提交給設備模型,為它們尋找命中注定的接口驅動,usb_generic_driver也就徹底從你設備那兒得到滿足了,generic_probe的歷史使命也就完成了。
先看第一階段,9行,configuration是前邊兒choose_configuration()那里返回回來的,找到合意的配置的話,就返回那個配置的bConfigurationValue值,沒有找到稱心的配置的話,就返回-1,所以這里的configuration值就可能有兩種情況,或者為-1,或者為配置的bConfigurationValue值。當configuration為-1時這里為啥又要把它改為0捏?要知道configuration這個值是要在后面的階段里發送SET_CONFIGURATION請求時用的,關于SET_CONFIGURATION請求,spec里說,這個值必須為0或者與配置描述符的bConfigurationValue一致,如果為0,則設備收到SET_CONFIGURATION請求后,仍然會待在Address狀態。這里當configuration為-1也就是沒有發現滿意的配置時,設備不能進入Configured,所以要把configuration的值改為0,以便滿足SET_CONFIGURATION請求的要求。
那接下來的問題就出來了,在沒有找到合適配置的時候直接給configuration這個參數傳個0,也就是讓choose_configuration()返回個0不就得了,干嗎還這么麻煩先返回個-1再把它改成0,不是脫褲子放屁多此一舉么?你別憤怒,這歸根結底還是那句話,林子大了什么鳥都有,有些設備就是有拿0當配置bConfigurationValue值的毛病,你又不能不讓它用。usb世界里出現幾個有毛病的設備也沒啥大不了的,這里妥協一下就是了,想讓設備回到Address狀態時,usb_set_configuration()就別傳遞0了,傳遞個-1,里邊兒去處理一下。如果configuration值為0或大于0的值,就從設備struct usb_device結構體的config數組里將相應配置的描述信息,也就是struct usb_host_config結構體給取出來。
20行,如果沒有拿到配置的內容,configuration值就必須為0了,讓設備待在Address那兒別動。這也很好理解,配置的內容都找不到了,還配置個什么勁兒。當然,如果拿到了配置的內容,但同時configuration為0,這就是對應了上面說的那種有毛病的設備的情況,就提出一下警告,告訴你不正常現象出現了。
33行,過了這個if,第一階段就告結束了。如果配置是實實在在存在的,就為它使用的那些接口都準備一個struct usb_interface結構體。new_interfaces是開頭兒就定義好的一個struct usb_interface結構體指針數組,數組的每一項都指向了一個struct usb_interface結構體,所以這里申請內存也要分兩步走,先申請指針數組的,再申請每一項的。
總結
以上是生活随笔為你收集整理的Linux那些事儿 之 戏说USB(30)驱动的生命线(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux那些事儿 之 戏说USB(29
- 下一篇: Linux那些事儿 之 戏说USB(31