现在开始就沿着usb_generic_driver的生命线继续往下走。设备的生命线你可以为是从你的usb设备连接到hub的某个端口时开始,而驱动的生命线就必须得回溯到usb子系统的初始化函数usb_init了。

if (retval)

goto hub_init_failed;

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世界里的一个超级大美女诞生了。现在先看看带她来到这个世界上的usb_register_device_driver函数。

/**

* usb_register_device_driver - register a USB device (not interface) driver

* @new_udriver: USB operations for the device driver

* @owner: module owner of this driver.

*

* Registers a USB device driver with the USB core. The list of

* unattached devices will be rescanned whenever a new driver is

* added, allowing the new driver to attach to any recognized devices.

* Returns a negative error code on failure and 0 on success.

*/

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 = (char *) 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);

usbfs_update_special();

} else {

printk(KERN_ERR "%s: error %d registering device "

" driver %s\n",

usbcore_name, retval, new_udriver->name);

}

return retval;

}

usb_disabled函数判断一下usb子系统是不是在你启动内核的时候就被禁止了,如果是的话,这个超级大美女的生命也就太短暂了。

看到没,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函数。

然后调用设备模型的函数driver_register将usb_generic_driver添加到usb总线的那条驱动链表里。

usb_generic_driver和usb设备匹配成功后,就会调用指定的probe函数usb_probe_device(),现在看看driver.c里定义的这个函数。

/* called from driver core with dev locked */

static int usb_probe_device(struct device *dev)

{

struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);

struct usb_device *udev;

int error = -ENODEV;

dev_dbg(dev, "%s\n", __FUNCTION__);

if (!is_usb_device(dev)) /* Sanity check */

return error;

udev = to_usb_device(dev);

/* TODO: Add real matching code */

/* The device should always appear to be in use

* unless the driver suports autosuspend.

*/

udev->pm_usage_cnt = !(udriver->supports_autosuspend);

error = udriver->probe(udev);

return error;

}

首先to_usb_device_driver是include/linux/usb.h里定义的一个宏,和前面遇到的那个to_usb_device有异曲同工之妙,

然后is_usb_device表示 usb_generic_driver是match成功了,但是还需要获得usb_device结构体,所以to_usb_device它这就来了。

pm_usage_cnt和supports_autosuspend两个变量,前面都提到过那么一下,现在将那两个片断给回顾一下。每个struct usb_interface或struct usb_device里都有一个pm_usage_cnt,每个struct usb_driver或struct usb_device_driver里都有一个supports_autosuspend。提到pm_usage_cnt时说只有它为0时才会允许接口autosuspend,提到supports_autosuspend时说如果它为0就不再允许绑定到这个驱动的接口autosuspend。接口乎?设备乎?有些时候需要那么难得糊涂一下。需要的时候,群众的眼睛是雪亮的,接口是接口设备是设备,不需要的时候,群众是不明真相的,接口设备一个样。这里就是不需要的时候,所以将上面的话里的接口换成设备套一下就是:pm_usage_cnt为0时才会允许设备autosuspend,supports_autosuspend为0就不再允许绑定到这个驱动的设备autosuspend。

所有的usb设备都是绑定到usb_generic_driver上面的,usb_generic_driver的supports_autosuspend字段又是为1的,所以这行就是将设备struct usb_device结构体的pm_usage_cnt置为了0,也就是说允许设备autosuspend。但是不是说这里将pm_usage_cnt轻轻松松置为0,设备就能够autosuspend了,什么事都是说起来简单,做起来就不是那么回事儿,驱动必须得实现一对儿suspend/resume函数供PM子系统那块驱使,usb_generic_driver里的这对函数就是generic_suspend/generic_resume,就不多说它们了。

最后调用usb_generic_driver自己私有的probe函数generic_probe()对你的设备进行进一步的审查。

static int generic_probe(struct usb_device *udev)

{

int err, c;

/* put device-specific files into sysfs */

usb_create_sysfs_dev_files(udev);

/* Choose and set the configuration. This registers the interfaces

* with the driver core and lets interface drivers bind to them.

*/

c = choose_configuration(udev);

if (c >= 0) {

err = usb_set_configuration(udev, c);

if (err) {

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里的choose_configuration函数。注释很详细就不说了。看一下另一个设备配置usb_set_configuration函数。

/*

* usb_set_configuration - Makes a particular device setting be current

* @dev: the device whose configuration is being updated

* @configuration: the configuration being chosen.

* Context: !in_interrupt(), caller owns the device lock

*

* This is used to enable non-default device modes. Not all devices

* use this kind of configurability; many devices only have one

* configuration.

*

* @configuration is the value of the configuration to be installed.

* According to the USB spec (e.g. section 9.1.1.5), configuration values

* must be non-zero; a value of zero indicates that the device in

* unconfigured. However some devices erroneously use 0 as one of their

* configuration values. To help manage such devices, this routine will

* accept @configuration = -1 as indicating the device should be put in

* an unconfigured state.

*

* USB device configurations may affect Linux interoperability,

* power consumption and the functionality available. For example,

* the default configuration is limited to using 100mA of bus power,

* so that when certain device functionality requires more power,

* and the device is bus powered, that functionality should be in some

* non-default device configuration. Other device modes may also be

* reflected as configuration options, such as whether two ISDN

* channels are available independently; and choosing between open

* standard device protocols (like CDC) or proprietary ones.

*

* Note that USB has an additional level of device configurability,

* associated with interfaces. That configurability is accessed using

* usb_set_interface().

*

* This call is synchronous. The calling context must be able to sleep,

* must own the device lock, and must not hold the driver model's USB

* bus mutex; usb device driver probe() methods cannot use this routine.

*

* Returns zero on success, or else the status code returned by the

* underlying call that failed. On successful completion, each interface

* in the original device configuration has been destroyed, and each one

* in the new configuration has been probed by all relevant usb device

* drivers currently known to the kernel.

*/

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;

int n, nintf;

if (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_KERNEL);

if (!new_interfaces) {

dev_err(&dev->dev, "Out of memory");

return -ENOMEM;

}

for (; n < nintf; ++n) {

new_interfaces[n] = kzalloc(

sizeof(struct usb_interface),

GFP_KERNEL);

if (!new_interfaces[n]) {

dev_err(&dev->dev, "Out of memory");

ret = -ENOMEM;

free_interfaces:

while (--n >= 0)

kfree(new_interfaces[n]);

kfree(new_interfaces);

return ret;

}

}

i = dev->bus_mA - cp->desc.bMaxPower * 2;

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

if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),

USB_REQ_SET_CONFIGURATION, 0, configuration, 0,

NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) {

/* All the old state is gone, so what else can we do?

* The device is probably useless now anyway.

*/

cp = NULL;

}

dev->actconfig = cp;

if (!cp) {

usb_set_device_state(dev, USB_STATE_ADDRESS);

usb_autosuspend_device(dev);

goto free_interfaces;

}

usb_set_device_state(dev, USB_STATE_CONFIGURED);

/* 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->cur_altsetting = alt;

usb_enable_interface(dev, intf);

intf->dev.parent = &dev->dev;

intf->dev.driver = NULL;

intf->dev.bus = &usb_bus_type;

intf->dev.type = &usb_if_device_type;

intf->dev.dma_mask = dev->dev.dma_mask;

device_initialize (&intf->dev);

mark_quiesced(intf);

sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",

dev->bus->busnum, dev->devpath,

configuration, alt->desc.bInterfaceNumber);

}

kfree(new_interfaces);

if (cp->string == NULL)

cp->string = usb_cache_string(dev, cp->desc.iConfiguration);

/* 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",

intf->dev.bus_id, configuration,

intf->cur_altsetting->desc.bInterfaceNumber);

ret = device_add (&intf->dev);

if (ret != 0) {

dev_err(&dev->dev, "device_add(%s) --> %d\n",

intf->dev.bus_id, ret);

continue;

}

usb_create_sysfs_intf_files (intf);

}

usb_autosuspend_device(dev);

return 0;

}

遇到很长的代码,我们总是想说点函数背后的理论,或者聊聊函数背后的人生哲学。走到这里,设备已经和usb_generic_driver这个大美女配对成功了,这并不意味着你可以高枕无忧了,要想保持和她的这种亲密关系,你得想办法让她得到满足,你就要准备着让她去配置,准备着她想让你什么样你就什么样。你要明白,吸引住男人的办法就是让他一直得不到,吸引住女人的办法正好相反,就是让她一直满足。从这个角度看,这个函数就可以泾渭分明的分成三个部分三个阶段。一是准备阶段,做做常规检查啊,申请申请内存啊,搞点前戏什么的。二是设备从Address发展到了Configured,可算是高潮阶段,别看它短,这是事物发展的规律,也是每个男人女人的规律,充实充实设备的每个接口并提交给设备模型,为它们寻找命中注定的接口驱动。最后温存温存,过了这个后戏阶段,usb_generic_driver也就彻底从你设备那儿得到满足了,generic_probe的历史使命也就完成了。事物的发展大体上就脱离不了这三个阶段,再比如股票,买、卖、回味。

先看第一阶段,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值的毛病,你又不能不让它用,这里妥协一下就是了,想让设备回到Address状态时,usb_set_configuration()就别传递0了,传递个-1,里边儿去处理一下。如果configuration值为0或大于0的值,就从设备struct usb_device结构体的config数组里将相应配置的描述信息,也就是struct usb_host_config结构体给取出来。如果没有拿到配置的内容,configuration值就必须为0了,让设备待在Address那儿别动。这也很好理解,配置的内容都找不到了,还配置个什么劲儿。当然,如果拿到了配置的内容,但同时configuration为0,这就是对应了上面说的那种有毛病的设备的情况,就提出一下警告,告诉你不正常现象出现了。接下来的if判断如果配置是实实在在存在的,就为它使用的那些接口都准备一个struct usb_interface结构体。new_interfaces是开头儿就定义好的一个struct usb_interface结构体指针数组,数组的每一项都指向了一个struct usb_interface结构体,所以这里申请内存也要分两步走,先申请指针数组的,再申请每一项的。

下面的高潮部分,还是抽两支烟的功夫后再看吧。

usb驱动开发21之驱动生命线的更多相关文章

  1. Linux 设备驱动开发 —— platform设备驱动应用实例解析

    前面我们已经学习了platform设备的理论知识Linux 设备驱动开发 —— platform 设备驱动 ,下面将通过一个实例来深入我们的学习. 一.platform 驱动的工作过程 platfor ...

  2. usb驱动开发22之驱动生命线

    我们总是很喜欢高潮,不是吗?那就好好对待她哦.我们来看一下linux中的高潮部分设备是怎么从Address进入Configured的. usb_set_configuration函数的代码就不贴了,可 ...

  3. usb驱动开发13之设备生命线

    上一节勉勉强强把struct urb这个中心给说完,接着看那三个基本点. 第一个基本点,usb_alloc_urb函数,创建urb的专用函数,为一个urb申请内存并做初始化,在drviers/usb/ ...

  4. usb驱动开发12之设备生命线

    函数usb_control_msg完成一些初始化后调用了usb_internal_control_msg之后就free urb.剩下的活,全部留给usb_internal_control_msg去做了 ...

  5. usb驱动开发18之设备生命线

    现在已经使用GET_DESCRIPTOR请求取到了包含一个配置里所有相关描述符内容的一堆数据,这些数据是raw的,即原始的,所有数据不管是配置描述符.接口描述符还是端点描述符都挤在一起,所以得想办法将 ...

  6. usb驱动开发17之设备生命线

    拜会完了山头的几位大哥,还记得我们从哪里来要到哪里去吗?时刻不能忘记自身的使命啊.我们是从usb_submit_urb()最后的那个遗留问题usb_hcd_submit_urb()函数一路走来,现在就 ...

  7. usb驱动开发16之设备生命线

    回到struct usb_hcd,继续努力的往下看. kref,usb主机控制器的引用计数.struct usb_hcd也有自己专用的引用计数函数,看hcd.c文件. static void hcd_ ...

  8. usb驱动开发14之设备生命线

    直接看代码吧. /*-------------------------------------------------------------------*/ /** * usb_submit_urb ...

  9. usb驱动开发15之设备生命线

    总算是进入了HCD的片儿区,既然来到一个片区,怎么都要去拜会一下山头几个大哥吧.,先回忆一些我们怎么到这里的?给你列举一个调用函数过程usb_control_msg->usb_internal_ ...

随机推荐

  1. 【代码笔记】iOS-提醒时间的选择

    一,效果图. 二,工程图. 三,代码. RootViewController.h #import <UIKit/UIKit.h> @interface RootViewController ...

  2. iOS-UIScrollView和UIPageControl的综合实力,滚动图,轮播图

    本代码主要实现图片之间的切换 目录结构 代码 ViewController.m文件 #import "ViewController.h" @interface ViewContro ...

  3. iOS中的过期方法和新的替代方法

    关于iOS中的过期方法和新的替代方法 1.获取某些类的UINavigationBar的统一外观并设置UINavigationbar的背景 注:方法名改了但是基本使用方法不变 + (instancety ...

  4. Visio作图

    1.Microsoft Visio介绍 Visio是一款便于IT和商务专业人员就复杂信息.系统和流程进行可视化处理.分析和交流的软件,也是Microsoft Office办公软件家族中的一个绘图工具软 ...

  5. Java基础知识学习(七)

    线程(续) 线程同步 当两个或两个以上的线程需要共享资源,它们需要某种方法来确定资源在某一刻仅被一个线程占用.达到此目的的过程叫做同步(synchronization) 可以用两种方法同步化代码.两者 ...

  6. react学习笔记1

    # 1.hello world 学习一个语言,最好的方式,我们需要去官网去查看文档(https://facebook.github.io/react),通过JSFiddle,便可以看到最简单的demo ...

  7. jquery中attr和prop的区别、 什么时候用 attr 什么时候用 prop (转自 芈老头 )

    jquery中attr和prop的区别. 什么时候用 attr 什么时候用 prop   在高版本的jquery引入prop方法后,什么时候该用prop?什么时候用attr?它们两个之间有什么区别?这 ...

  8. js日期校验

    当查询条件含有日期时,如"2012-3-4",查询前校验输入的日期字符串是否为有效的日期 var snapshot_createTime_begin=$(selector+&quo ...

  9. node.js表单——formidable

    node处理表单请求,需要用到formidable包.安装formidable包的命令如下: npm install formidable 安装package的路径分为两种,一种是本地目录,一种是全局 ...

  10. ELK日志解决方案安装配置与使用

    官方网站:https://www.elastic.co/products/elasticsearch logstash,elasticsearch,kibana作用如下: logstash:分布在每一 ...