Linux那些事儿 之 戏说USB(29)驱动的生命线(一)
現在開始就沿著usb_generic_driver的成名之路走一走,設備的生命線你可以想當然的認為是從你的usb設備連接到hub的某個端口時開始,驅動的生命線就必須得回溯到usb子系統的初始化函數usb_init了。
drivers/usb/core/usb.c
retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);if (!retval)goto out;
在usb子系統初始化的時候就調用driver.c里的usb_register_device_driver函數將usb_generic_driver注冊給系統了,現在看看usb_register_device_driver函數。
drivers/usb/core/driver.c
int usb_register_device_driver(struct usb_device_driver *new_udriver,struct module *owner)
{int retval = 0;if (usb_disabled())return -ENODEV;new_udriver->drvwrap.for_devices = 1;new_udriver->drvwrap.driver.name = new_udriver->name;new_udriver->drvwrap.driver.bus = &usb_bus_type;new_udriver->drvwrap.driver.probe = usb_probe_device;new_udriver->drvwrap.driver.remove = usb_unbind_device;new_udriver->drvwrap.driver.owner = owner;retval = driver_register(&new_udriver->drvwrap.driver);if (!retval)pr_info("%s: registered new device driver %s\n",usbcore_name, new_udriver->name);elseprintk(KERN_ERR "%s: error %d registering device "" driver %s\n",usbcore_name, retval, new_udriver->name);return retval;
}
6行,判斷一下usb子系統是不是在你啟動內核的時候就被禁止了,一般來說,你不至于無聊到那種地步和她過不去吧。usb_disabled在usb.c里定義
drivers/usb/core/usb.c
int usb_disabled(void)
{return nousb;
}如果你不是存心和我過不去的話,是應該知道nosub表示什么意思的。
9行,看到沒,for_devices就是在這兒被初始化為1的,有了它,match里的那個is_usb_device_driver把門兒的才有章可循有憑可依。
下面就是充實了下usb_generic_driver里嵌入的那個struct device_driver結構體,usb_generic_driver就是通過它和設備模型搭上關系的。name就是usb_generic_driver的名字,即usb,所屬的總線類型同樣被設置為usb_bus_type,然后是指定probe函數和remove函數。
16行,調用設備模型的函數driver_register將usb_generic_driver添加到usb總線的那條驅動鏈表里,然后它就可以接受usb設備的討好、獻殷勤、表白。
usb_generic_driver和usb設備匹配成功后,就會調用12行指定的probe函數usb_probe_device(),現在看看driver.c里定義的這個函數
drivers/usb/core/driver.c
static int usb_probe_device(struct device *dev)
{struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);struct usb_device *udev = to_usb_device(dev);int error = 0;dev_dbg(dev, "%s\n", __func__);/* TODO: Add real matching code *//* The device should always appear to be in use* unless the driver supports autosuspend.*/if (!udriver->supports_autosuspend)error = usb_autoresume_device(udev);if (!error)error = udriver->probe(udev);return error;
}
3行,to_usb_device_driver是include/linux/usb.h里定義的一個宏,和前面遇到的那個to_usb_device有異曲同工之妙,
include/linux/usb.h
#define to_usb_device_driver(d) container_of(d, struct usb_device_driver, \drvwrap.driver)4行,說曹操曹操就到,前面剛提到to_usb_device它這就來了。
14行,supports_autosuspend這兩個前面都提到過那么一下,現在將那兩個片斷給回顧一下。每個struct usb_driver或struct usb_device_driver里都有一個supports_autosuspend。提到supports_autosuspend時說如果它為0就不再允許綁定到這個驅動的接口autosuspend。
所有的usb設備都是綁定到usb_generic_driver上面的,usb_generic_driver的supports_autosuspend字段又是為1的,也就是說允許設備autosuspend。
18行,飄過了上面有關電源管理的那行之后,這里要調用usb_generic_driver自己私有的probe函數generic_probe()對你的設備進行進一步的審查,它在generic.c里定義
static int generic_probe(struct usb_device *udev)
{int err, c;/* Choose and set the configuration. This registers the interfaces* with the driver core and lets interface drivers bind to them.*/if (udev->authorized == 0)dev_err(&udev->dev, "Device is not authorized for usage\n");else {c = usb_choose_configuration(udev);if (c >= 0) {err = usb_set_configuration(udev, c);if (err && err != -ENODEV) {dev_err(&udev->dev, "can't set config #%d, error %d\n",c, err);/* This need not be fatal. The user can try to* set other configurations. */}}}/* USB device state == configured ... usable */usb_notify_add_device(udev);return 0;
}這函數說簡單也簡單,說復雜也復雜,簡單的是外表,復雜的是內心。用一句話去概括它的中心思想,就是從設備可能的眾多配置中選擇一個合適的,然后去配置設備,從而讓設備進入期待已久的Configured狀態。概括了中心思想,再去看看細節。先看看是怎么選擇一個配置的,調用的是generic.c里的usb_choose_configuration函數。
int usb_choose_configuration(struct usb_device *udev)
{int i;int num_configs;int insufficient_power = 0;struct usb_host_config *c, *best;if (usb_device_is_owned(udev))return 0;best = NULL;c = udev->config;num_configs = udev->descriptor.bNumConfigurations;for (i = 0; i < num_configs; (i++, c++)) {struct usb_interface_descriptor *desc = NULL;/* It's possible that a config has no interfaces! */if (c->desc.bNumInterfaces > 0)desc = &c->intf_cache[0]->altsetting->desc;/** HP's USB bus-powered keyboard has only one configuration* and it claims to be self-powered; other devices may have* similar errors in their descriptors. If the next test* were allowed to execute, such configurations would always* be rejected and the devices would not work as expected.* In the meantime, we run the risk of selecting a config* that requires external power at a time when that power* isn't available. It seems to be the lesser of two evils.** Bugzilla #6448 reports a device that appears to crash* when it receives a GET_DEVICE_STATUS request! We don't* have any other way to tell whether a device is self-powered,* but since we don't use that information anywhere but here,* the call has been removed.** Maybe the GET_DEVICE_STATUS call and the test below can* be reinstated when device firmwares become more reliable.* Don't hold your breath.*/
#if 0/* Rule out self-powered configs for a bus-powered device */if (bus_powered && (c->desc.bmAttributes &USB_CONFIG_ATT_SELFPOWER))continue;
#endif/** The next test may not be as effective as it should be.* Some hubs have errors in their descriptor, claiming* to be self-powered when they are really bus-powered.* We will overestimate the amount of current such hubs* make available for each port.** This is a fairly benign sort of failure. It won't* cause us to reject configurations that we should have* accepted.*//* Rule out configs that draw too much bus current */if (usb_get_max_power(udev, c) > udev->bus_mA) {insufficient_power++;continue;}/* When the first config's first interface is one of Microsoft's* pet nonstandard Ethernet-over-USB protocols, ignore it unless* this kernel has enabled the necessary host side driver.* But: Don't ignore it if it's the only config.*/if (i == 0 && num_configs > 1 && desc &&(is_rndis(desc) || is_activesync(desc))) {
#if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)continue;
#elsebest = c;
#endif}/* From the remaining configs, choose the first one whose* first interface is for a non-vendor-specific class.* Reason: Linux is more likely to have a class driver* than a vendor-specific driver. */else if (udev->descriptor.bDeviceClass !=USB_CLASS_VENDOR_SPEC &&(desc && desc->bInterfaceClass !=USB_CLASS_VENDOR_SPEC)) {best = c;break;}/* If all the remaining configs are vendor-specific,* choose the first one. */else if (!best)best = c;}if (insufficient_power > 0)dev_info(&udev->dev, "rejected %d configuration%s ""due to insufficient available bus power\n",insufficient_power, plural(insufficient_power));if (best) {i = best->desc.bConfigurationValue;dev_dbg(&udev->dev,"configuration #%d chosen from %d choice%s\n",i, num_configs, plural(num_configs));} else {i = -1;dev_warn(&udev->dev,"no configuration chosen from %d choice%s\n",num_configs, plural(num_configs));}return i;
}設備各個配置的詳細信息在設備自身的漫漫人生旅途中就已經獲取存放在相關的幾個成員里了,怎么從中挑選一個讓人滿意的?顯然誰都會說去一個一個的瀏覽每個配置,看看有沒有稱心如意的,于是就有了14行的for循環。
剛看到這個for循環就有點傻眼了,有點不大相信,居然注釋要遠遠多于代碼!。
這么一個for循環,咱們把它分成三大段,21~46這一大段你什么都可以不看,就是不能不看那個#if 0,因為它就意味著你可以華麗麗的飄過這么一大段了。
第二段是60~64行,這一段牽扯到人世間最讓人無可奈何的一對矛盾,索取與給予。一個配置索取的電流比hub所能給予的還要大,顯然它不會是一個讓人滿意的配置。
第三段是71~96行,關于這段只說一個原則,linux更care那些標準的東西,比如USB_CLASS_VIDEO、USB_CLASS_AUDIO等等這樣子的設備和接口就更討人喜歡一些,所以就會優先選擇非USB_CLASS_VENDOR_SPEC的接口。
for循環之后,殘余的那些部分都是調試用的,輸出一些調試信息,不需要去關心,不過里面出現了個有趣的函數plural,它是一個在generic.c開頭兒定義的內聯函數
static inline const char *plural(int n)
{return (n == 1 ? "" : "s");
}參數n為1返回一個空字符串,否則返回一個‘s’,瞄一下使用了這個函數的那幾個打印語句,就明白它是用來打印一個英語名詞的單復數的,復數的話就加上個s。呵呵,那些不規律的名詞單復數形式咋辦?涼拌!
不管你疑惑也好,滿意也好,choose_configuration就是這樣按照自己的標準挑選了一個比較合自己心意的配置,接下來當然就是要用這個配置去配置設備以便讓它邁進Configured狀態了。
總結
以上是生活随笔為你收集整理的Linux那些事儿 之 戏说USB(29)驱动的生命线(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux那些事儿 之 戏说USB(28
- 下一篇: Linux那些事儿 之 戏说USB(30