关闭

Linux那些事儿之我是Hub(22)八大重量级函数闪亮登场(六)

标签: linuxdescriptorinterfacestructstringdisk
4125人阅读 评论(4) 收藏 举报
分类:

在调用usb_new_device之前,25552560这一小段,如果说hub已经被撤掉了,那么老规矩,别浪费感情了.否则,udev赋值给hdev->children数组中的对应元素,也正是从此以后,这个设备才算是真正挂上了这棵大树.

Ok,如果status确实为0,(注意,2549刚刚把status赋为了0.)正式调用usb_new_device.

   1275 /**

   1276  * usb_new_device - perform initial device setup (usbcore-internal)

   1277  * @udev: newly addressed device (in ADDRESS state)

   1278  *

   1279  * This is called with devices which have been enumerated, but not yet

   1280  * configured.  The device descriptor is available, but not descriptors

   1281  * for any device configuration.  The caller must have locked either

   1282  * the parent hub (if udev is a normal device) or else the

   1283  * usb_bus_list_lock (if udev is a root hub).  The parent's pointer to

   1284  * udev has already been installed, but udev is not yet visible through

   1285  * sysfs or other filesystem code.

   1286  *

   1287  * It will return if the device is configured properly or not.  Zero if

   1288  * the interface was registered with the driver core; else a negative

   1289  * errno value.

   1290  *

   1291  * This call is synchronous, and may not be used in an interrupt context.

   1292  *

   1293  * Only the hub driver or root-hub registrar should ever call this.

   1294  */

   1295 int usb_new_device(struct usb_device *udev)

   1296 {

   1297         int err;

   1298

   1299         /* Determine quirks */

   1300         usb_detect_quirks(udev);

   1301

   1302         err = usb_get_configuration(udev);

   1303         if (err < 0) {

   1304                 dev_err(&udev->dev, "can't read configurations, error %d/n",

   1305                         err);

   1306                 goto fail;

   1307         }

   1308

   1309         /* read the standard strings and cache them if present */

   1310         udev->product = usb_cache_string(udev, udev->descriptor.iProduct);

   1311         udev->manufacturer = usb_cache_string(udev,

   1312                         udev->descriptor.iManufacturer);

   1313         udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);

   1314

   1315         /* Tell the world! */

   1316         dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "

   1317                         "SerialNumber=%d/n",

   1318                         udev->descriptor.iManufacturer,

   1319                         udev->descriptor.iProduct,

   1320                         udev->descriptor.iSerialNumber);

   1321         show_string(udev, "Product", udev->product);

   1322         show_string(udev, "Manufacturer", udev->manufacturer);

   1323         show_string(udev, "SerialNumber", udev->serial);

   1324

   1325 #ifdef  CONFIG_USB_OTG

   1326         /*

   1327          * OTG-aware devices on OTG-capable root hubs may be able to use SRP,

   1328          * to wake us after we've powered off VBUS; and HNP, switching roles

   1329          * "host" to "peripheral".  The OTG descriptor helps figure this out.

   1330          */

   1331         if (!udev->bus->is_b_host

   1332                         && udev->config

   1333                         && udev->parent == udev->bus->root_hub) {

   1334                 struct usb_otg_descriptor       *desc = 0;

   1335                 struct usb_bus                  *bus = udev->bus;

   1336

   1337                 /* descriptor may appear anywhere in config */

   1338                 if (__usb_get_extra_descriptor (udev->rawdescriptors[0],

   1339                                         le16_to_cpu(udev->config[0].desc.wTotalLength),

   1340                                         USB_DT_OTG, (void **) &desc) == 0) {

   1341                         if (desc->bmAttributes & USB_OTG_HNP) {

   1342                                 unsigned                port1 = udev->portnum;

   1343

   1344                                 dev_info(&udev->dev,

   1345                                         "Dual-Role OTG device on %sHNP port/n",

   1346                                         (port1 == bus->otg_port)

   1347                                                 ? "" : "non-");

   1348

   1349                                 /* enable HNP before suspend, it's simpler */

   1350                                 if (port1 == bus->otg_port)

   1351                                         bus->b_hnp_enable = 1;

   1352                                 err = usb_control_msg(udev,

   1353                                         usb_sndctrlpipe(udev, 0),

   1354                                         USB_REQ_SET_FEATURE, 0,

   1355                                         bus->b_hnp_enable

   1356                                                 ? USB_DEVICE_B_HNP_ENABLE

   1357                                                 : USB_DEVICE_A_ALT_HNP_SUPPORT,

   1358                                         0, NULL, 0, USB_CTRL_SET_TIMEOUT);

   1359                                 if (err < 0) {

   1360                                         /* OTG MESSAGE: report errors here,

   1361                                          * customize to match your product.

   1362                                          */

   1363                                         dev_info(&udev->dev,

   1364                                                 "can't set HNP mode; %d/n",

   1365                                                 err);

   1366                                         bus->b_hnp_enable = 0;

   1367                                 }

   1368                         }

   1369                 }

   1370         }

   1371

   1372         if (!is_targeted(udev)) {

   1373

   1374                 /* Maybe it can talk to us, though we can't talk to it.

   1375                  * (Includes HNP test device.)

   1376                  */

   1377                 if (udev->bus->b_hnp_enable || udev->bus->is_b_host) {

   1378                         err = __usb_port_suspend(udev, udev->bus->otg_port);

   1379                         if (err < 0)

   1380                                 dev_dbg(&udev->dev, "HNP fail, %d/n", err);

   1381                 }

   1382                 err = -ENODEV;

   1383                 goto fail;

   1384         }

   1385 #endif

   1386

   1387         /* export the usbdev device-node for libusb */

   1388         udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,

   1389                         (((udev->bus->busnum-1) * 128) + (udev->devnum-1)));

   1390

   1391         /* Register the device.  The device driver is responsible

   1392          * for adding the device files to sysfs and for configuring

   1393          * the device.

   1394          */

   1395         err = device_add(&udev->dev);

   1396         if (err) {

   1397                 dev_err(&udev->dev, "can't device_add, error %d/n", err);

   1398                 goto fail;

   1399         }

   1400

   1401         /* Increment the parent's count of unsuspended children */

   1402         if (udev->parent)

   1403                 usb_autoresume_device(udev->parent);

   1404

   1405 exit:

   1406         return err;

   1407

   1408 fail:

   1409         usb_set_device_state(udev, USB_STATE_NOTATTACHED);

   1410         goto exit;

   1411 }

这个函数看似很长,实则不然.幸亏咱们前面作了一个厚颜无耻的假设,即假设不打开支持OTG的代码.在这里13251385行就这么被我们华丽丽的飘过了.而剩下的代码就相对来说简单多了,主要就是调用了几个函数.一个一个来看.

usb_detect_quirks().如果不是因为我们讲过了usb-storage,不是因为在usb-storage里面见过那个unusual_devs.h的故事,也许这里我会耐心的给您讲一讲这个关于quirks的故事.实际上这是两个相似的故事,它们共同印证着列夫托尔斯泰在安娜卡列尼娜中的开篇第一句,幸福的家庭都是相似的,不幸的家庭各有各的不幸.好的USB设备都是相似的,大家遵守同样的游戏规则,而不好的USB设备却各有各的毛病,usb-storage里面我们使用了unusual_devs.h,而在整个usb子系统范围内,我们使用另外两个文件,drivers/usb/core/quirks.c以及include/linux/usb/quirks.h. quirk,金山词霸说,怪癖的意思.说白了就是说白里透红,与众不同.

include/linux/usb/quirks.h,我们看到这个文件超级的短,只有两行有意义,其余几行是注释,

      1 /*

      2  * This file holds the definitions of quirks found in USB devices.

      3  * Only quirks that affect the whole device, not an interface,

      4  * belong here.

      5  */

      6

      7 /* device must not be autosuspended */

      8 #define USB_QUIRK_NO_AUTOSUSPEND        0x00000001

      9

     10 /* string descriptors must not be fetched using a 255-byte read */

     11 #define USB_QUIRK_STRING_FETCH_255      0x00000002

这个文件总共就是这么11,而其中定义了两个flag,第一个USB_QUIRK_NO_AUTOSUSPEND表明这个设备不能自动挂起,执行自动挂起会对设备造成伤害,确切的说是设备会被crash.而第二个宏,USB_QUIRK_STRING_FETCH_255,是说该设备在获取字符串描述符的时候会crash.

与此同时,drivers/usb/core/quirks.c中定义了这么一张表,

     18 /* List of quirky USB devices.  Please keep this list ordered by:

     19  *      1) Vendor ID

     20  *      2) Product ID

     21  *      3) Class ID

     22  *

     23  * as we want specific devices to be overridden first, and only after that, any

     24  * class specific quirks.

     25  *

     26  * Right now the logic aborts if it finds a valid device in the table, we might

     27  * want to change that in the future if it turns out that a whole class of

     28  * devices is broken...

     29  */

     30 static const struct usb_device_id usb_quirk_list[] = {

     31         /* HP 5300/5370C scanner */

     32         { USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },

     33         /* Seiko Epson Corp - Perfection 1670 */

     34         { USB_DEVICE(0x04b8, 0x011f), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },

     35         /* Elsa MicroLink 56k (V.250) */

     36         { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },

     37

     38         { }  /* terminating entry must be last */

     39 };

这张表被称作usb黑名单.2.6.22.1的内核中这张表里只记录了3个设备,但之所以创建这张表,目的在于将来可以扩充,比如这个夏天,Oliver同学又往这张表里添加了几个扫描仪,比如明基的S2W 3300U,精工爱普生的Perfection 1200,以及另几家公司的一些产品.所以2.6.23的内核里将会看到这张表的内容比现在丰富.而从原理上来说,这张表和当初我们的那个unusual_devs.h是一样的,usb_detect_quirks()函数就是为了判断一个设备是不是在这张黑名单上,然后如果是的,就判断它具体是属于哪种问题,我们注意到,07年之后的内核中,struct usb_device结构体有一个元素u32 quirks,就是用来做这个检测的,usb_detect_quirks会为在黑名单中找得到的设备的struct usb_device结构体中的quirks赋值,然后接下来相关的代码就会判断一个设备的quirks中的某一位是否设置了,目前quirks里面只有两位可以设置,USB_QUIRKS_STRING_FETCH_255所对应的0x00000002USB_QUIRK_NO_AUTOSUSPEND所对应的0x00000001.而今年4月份,Alan同学又提交了一个patch,增加了另一个标志位,USB_QUIRK_RESET_RESUME,值为0x00000004,以表征一个设备不能正确的resume,而只能通过reset才能让它从挂起状态恢复正常.

所以,usb_detect_quirks()所带给我们的就是这么一个故事.它反映的是这样一种现状,即商家只管赚钱,却不管他们家生产出来的产品是否真的合格,只要它的产品差不多就行了,反正是usb设备,能用即可,基本功能满足,用户也鉴别不出好坏了.就好比我上个月买的雕牌洗衣粉洗了几次总觉得不好,后来仔细一看,包装袋上写着周佳牌洗衣粉.还有一次看路边卖五粮液,觉得便宜就一次性买了好几瓶,回去一喝,感觉完全不对,仔细一看吧,人家瓶子上写的是丑粮液.说了这个我就来气,从上海来北京的时候,火车站买一小说,金庸新著,上了火车我怒了,妈的,作者叫金庸新.

1302,usb_get_configuration(),获得配置描述符,我想你如果清楚了如何获得设备描述符,自然就不难知道如何获得配置描述符,知道了配置描述符,自然就不难知道如何获得接口描述符,然后是端点描述符.usb_get_configuration来自drivers/usb/core/config.c,我们不打算深入去讲这个函数,如果你有兴趣自己去看,那我做一点点解释,我们知道一个手机可以有多种配置,比如可以摄像,可以接在电脑里当做一个U,那么这两种情况就属于不同的配置,在手机里面有相应的选择菜单,你选择了哪种它就按哪种配置进行工作,供你选择的这个就叫做配置.很显然,当你摄像的时候你不可以访问这块U,当你访问这块U盘的时候你不可以摄像,因为你做了选择.第二,既然一个配置代表一种不同的功能,那么很显然,不同的配置可能需要的接口就不一样,我假设你的手机里从硬件上来说一共有5个接口,那么可能当你配置成U盘的时候它只需要用到某一个接口,当你配置成摄像的时候,它可能只需要用到另外两个接口,可能你还有别的配置,然后你可能就会用到剩下那两个接口,那么当你选择好一种配置之后,你给设备发送请求,请求去获得配置描述符的时候,设备返回给你的就绝不仅仅是一个配置描述符,它还必须返回更多的信息.usb spec的说法就是,设备将返回的是除了配置描述符以外,与这种配置相关的接口描述符,以及与这些接口相关的端点描述符,都会一次性返回给你.也正是因为如此,你才会知道足够的信息,从此以后你就可以为所欲为了.

另外一点我需要提示的是,一个接口可以有多种setting,即所谓的alternatesetting,比如在打印机驱动程序里,不同的setting可以表明使用不同的通信协议,又比如在声音设备驱动中setting可以决定不同的音频格式.那么我作为usb设备驱动程序我如何知道这些呢?首先,对于任何一个interface来说,usb spec规定了默认的settingsetting zero,0号设置是默认设置,而如果一个interface可以有多种setting,那么每一个setting将对应一个interface描述符,换言之,即便你只有一个interface,但是由于你可能有两种setting,那么你就有两个interface描述符,而它们对应于同一个interface编号,或者说我们知道接口描述符里面有一个成员,bInterfaceNumber和一个bAlternateSetting,就是对于这种情况,两个interface描述符将具有相同的bInterfaceNumber,而不相同的是bAlternateSetting,另一方面,因为不同的setting完全有可能导致需要不同的端点,所以也将有不同的端点描述符.

而总的来说,在我们的usb设备驱动程序可以正常工作之前,我们需要知道的信息是,接口描述符,Setting,以及端点描述符,从软件的角度来说,我们记得当初我们在usb-storage中的probe函数,我们传递给它的一个重要参数就是struct usb_interface指针,同时所有关于端点的信息也必须在调用storage_probe之前知道,而这一切的一切,都在设备里,我们所需要做的就是发送请求,然后设备就把相关信息返回给我们,然后我们就记录下来,填充好我们自己的数据结构,而这些数据结构,对所有的usb设备都是一样的,因为这些都是usb spec里面规定的,也正是因为如此,写代码的兄弟们才把这部分工作交给usb core来完成,而不是纷纷下放给每一个设备单独去执行,因为那样就太浪费了,大家都得干一些重复的工作,显然是没有必要的.

Ok,关于usb_get_configuration()函数我们就说这么多,我们传递的是struct usb_device结构体指针,即我们这个故事中的udev,从此以后你就会发现udev中的各个成员就有值了,这些值从哪来的?正是从设备里面来.

回到usb_new_device中来,13101323,还记得我们说过那个字符串描述符吧,这里就是去获得字符串描述符,并且保存下来,知道为什么你用lsusb命令可以看到诸如下面的内容了吧,

localhost:/usr/src/linux-2.6.22.1/drivers/usb/core # lsusb

Bus 001 Device 001: ID 0000:0000

Bus 002 Device 003: ID 0624:0294 Avocent Corp.

Bus 002 Device 001: ID 0000:0000

Bus 003 Device 001: ID 0000:0000

Bus 004 Device 003: ID 04b4:6560 Cypress Semiconductor Corp. CY7C65640 USB-2.0 "TetraHub"

Bus 004 Device 001: ID 0000:0000

其中那些字符串,就是这里保存起来的.试想如果不保存起来,那么每次你执行lsusb,都要去向设备发送一次请求,那设备还不被你烦死?usb_cache_string()就是干这个的,它来自drivers/usb/core/message.c,从此udev->product,udev->manufacturer,udev->serial里面就有值了.而下面那几行就是打印出来,show_string其实就是变相的printk语句.1315那句注释尤其搞笑,说什么”Tell the world!”告诉世界自己是一个什么样的设备,我有点怀疑写代码的兄弟是不是活得太压抑了一点,要知道在我们国家,跟一个人说隐私那叫倾诉,跟一群人说隐私那叫变态,跟全国人民说隐私那就叫<<艺术人生>>.

接下来,我们已经说过了,OTG的代码我们只能飘过,然后就到了1388,这里就是传统理论中的那两个主设备号和次设备号了.记得去年在恒隆广场面试赛门铁克的时候就被问到Linux中的设备号是怎么回事,分为主设备号和次设备号.按传统理论来说,主设备号表明了一类设备,一般对应着确定的驱动程序,而次设备号通常是因为一个驱动程序要支持多个设备而为了让驱动程序区分它们而设置的.比如如下,偶的硬盘:

localhost:/usr/src/linux-2.6.22.1/drivers/usb/core # ls -l /dev/sd*

brw-r----- 1 root disk 8,  0 Aug  6 18:19 /dev/sda

brw-r----- 1 root disk 8,  1 Aug  6 18:19 /dev/sda1

brw-r----- 1 root disk 8,  2 Aug  6 18:19 /dev/sda2

brw-r----- 1 root disk 8,  3 Aug  6 18:19 /dev/sda3

brw-r----- 1 root disk 8,  4 Aug  6 18:19 /dev/sda4

brw-r----- 1 root disk 8, 16 Aug  6 18:19 /dev/sdb

brw-r----- 1 root disk 8, 32 Aug  6 18:19 /dev/sdc

brw-r----- 1 root disk 8, 48 Aug  6 18:19 /dev/sdd

brw-r----- 1 root disk 8, 64 Aug  6 18:19 /dev/sde

scsi硬盘主设备号都是8,而不同的盘或者不同的分区都有不同的次设备号.次设备号具体为多少并不重要,不过最大不能超过255.usb子系统里使用以下公式安排次设备号的,minor=((dev->bus->busnum-1)*128)+(dev->devnum-1);USB_DEVICE_MAJOR被定义为189,我们看:

localhost:/usr/src/linux-2.6.22.1/drivers/usb/core # cat /proc/devices

Character devices:

  1 mem

  2 pty

  3 ttyp

  4 /dev/vc/0

  4 tty

  4 ttyS

  5 /dev/tty

  5 /dev/console

  5 /dev/ptmx

  7 vcs

 10 misc

 13 input

 21 sg

 29 fb

128 ptm

136 pts

162 raw

180 usb

189 usb_device

254 megaraid_sas_ioctl

189被称为usb_device,这两行代码是用于与usbfs文件系统相交户的.dev_t记录下了设备的主设备号和次设备号.,dev_t包含两部分,主设备号部分和次设备号部分.12位表征主设备号,20位表示次设备号.

1395,device_add(),Linux 2.6设备模型中最基础的函数之一,这个函数非常了不起.要深入追踪这个函数,足以写一篇专题文章了.这个函数来自drivers/base/core.c,是设备模型那边提供的函数,从作用上来说,这个函数这么一执行,系统里就真正有了咱们这个设备,/sysfs下面也能看到了,而且将会去遍历注册到usb总线上的所有的驱动程序,如果找到合适的,就去调用该驱动的probe函数,对于U盘来说,最终将调用storage_probe()函数,对于hub来说,最终将调用hub_probe()函数,而传递给它们的参数,正是我们此前获得的struct usb_interface指针和一个struct usb_device_id指针.后者我们在usb-storage里面已经非常熟悉了,它正是我们在usb总线上寻找驱动程序的依据,换句话说,每个驱动程序都会usb-storage那样,把自己支持的设备定义在一张表里,表中的每一项就是一个struct usb_device_id,然后当我们获得了一个具体设备,我们就把该设备的实际的信息与这张表去比较,如果找到匹配的了,就认为该驱动支持该设备,从而最终会调用该驱动的probe()函数.而从此,这个设备就被传递到了设备驱动.hub驱动也完成了它最重要的一项工作.

再次回到usb_new_device(),1402,如果该设备不是Root Hub,则调用usb_autoresume_device().这个函数来自drivers/usb/core/driver.c,也是usb core提供的,是电源管理方面的函数,如果设备这时候处于suspended状态,那么这个函数将把它唤醒,因为我们已经要开始用它了,怎么会任凭它睡眠呢.

最后1406,函数终于返回了.正确的话返回值为0.!

返回之后首先判断返回值,如果不为0说明出错了,那么就把hdev->children相应的那位设置为空.要知道我们在调用usb_new_device之前可是把它设置成了udev,怎奈它不思进取,只好放弃把它拉入usb组织的想法.

八大函数只剩下最后一个hub_power_remaining(),这个函数相对来说比较小巧玲珑.这是与电源管理相关的.虽然说刚接入的设备可能已经被设备驱动认领了,但是作为hub驱动,自身的工作还是要处理干净的.

   2364 static unsigned

   2365 hub_power_remaining (struct usb_hub *hub)

   2366 {

   2367         struct usb_device *hdev = hub->hdev;

   2368         int remaining;

   2369         int port1;

   2370

   2371         if (!hub->limited_power)

   2372                 return 0;

   2373

   2374         remaining = hdev->bus_mA - hub->descriptor->bHubContrCurrent;

   2375         for (port1 = 1; port1 <= hdev->maxchild; ++port1) {

   2376                 struct usb_device       *udev = hdev->children[port1 - 1];

   2377                 int                     delta;

   2378

   2379                 if (!udev)

   2380                         continue;

   2381

   2382                 /* Unconfigured devices may not use more than 100mA,

   2383                  * or 8mA for OTG ports */

   2384                 if (udev->actconfig)

   2385                         delta = udev->actconfig->desc.bMaxPower * 2;

   2386                 else if (port1 != udev->bus->otg_port || hdev->parent)

   2387                         delta = 100;

   2388                 else

   2389                         delta = 8;

   2390                 if (delta > hub->mA_per_port)

   2391                         dev_warn(&udev->dev, "%dmA is over %umA budget "

   2392                                         "for port %d!/n",

   2393                                         delta, hub->mA_per_port, port1);

   2394                 remaining -= delta;

   2395         }

   2396         if (remaining < 0) {

   2397                 dev_warn(hub->intfdev, "%dmA over power budget!/n",

   2398                         - remaining);

   2399                 remaining = 0;

   2400         }

   2401         return remaining;

   2402 }

limited_power是咱们当初在hub_configure()中设置的.设置了它说明能源是有限的,希望大家珍惜.所以如果这个变量不为0,我们就要对电源精打细算.要计算出现在还能提供多大电流.即把当前bus_mA减去hub自己需要的电流以及现在连在hub端口上的设备所消耗的电流,求出剩余值来,然后打印出来,告诉世界我们还有多少电流budget.bHubContrCurrent咱们前面在讲hub_configure的时候就已经说过了,Hub控制器本身最大的电流需求,单位是mA,来自hub描述符.

23752395行这段循环,就是上面说的这个思想的具体实现.遍历每个端口进行循环.每个设备的配置描述符中bMaxPower就是该设备从usb总线上消耗的最大的电流.其单位是2mA,所以这里要乘以2.没有配置过的设备是不可能获得超过100mA电流的.

如果deltahub为每个端口提供的平均电流要大,那么至少要警告一下.

然后循环完了,remaining就是如其字面意义一样,还剩下多少电流可供新的设备再接进来.注意到我们从软件的角度来说,是不会强行对设备采取什么措施,我们最多是打印出调试信息,警告警告,而设备如果真的遇到了供电问题,它自然会出现异常,它也许不能工作,这些当然由具体的设备驱动程序去关注,Hub这一层来说,没有必要去干涉人家内部的事情,做到这一步已经是仁至义尽了.

终于我们讲完了这八个函数,可以说到这里为止,我们已经知道了hub驱动是在端口连接有变化的时候如何工作的,并且更重要的是我们知道了hub驱动是如何为子设备驱动服务的.回到hub_port_connect_change之后,一切正常的话我们将会从2579行返回.

剩下的一些行就是错误处理代码.我们就不必再看了.因此我们将返回到hub_events()中来.这个函数还剩下几行,我们下节再看.不过你千万别以为看到这里你就完全明白hub驱动程序了,因为那样无异于你把自己家里的铁锅背在背上就以为自己是忍者神鬼.

别着急,慢慢来,其实懂与不懂,就像黑夜和白天,相隔一瞬间.

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:2433267次
    • 积分:7548
    • 等级:
    • 排名:第3053名
    • 原创:297篇
    • 转载:0篇
    • 译文:0篇
    • 评论:2042条
    博客专栏