`
dato0123
  • 浏览: 910563 次
文章分类
社区版块
存档分类
最新评论

Linux那些事儿之我是Hub(15)一个都不能少

 
阅读更多

烟波江声里,何处是江南.一晃神,一转眼,我们就这样垂垂老去.可是我们直到现在还根本就没有看明白hub驱动究竟是怎么工作的.但我相信,红莲即将绽放,双星终会汇聚,命运的轮转已经开始,我们只需耐心的等待.

2686,苦苦追寻之后,终于发现从这里开始针对端口进行分析了,有几个端口就对几个端口进行分析,分析每一个端口的状态变化,一个都不能少,很显然,这就是我们期待看到的代码,马上我们就可以知道,当我们把一个usb设备插入usb端口之后究竟会发生什么,知道usb设备提供的那些接口函数究竟是如何被调用的,特别是那个probe函数.这一刻,红领巾迎着太阳,阳光洒在海面上,水中鱼儿望着我们,悄悄的听我们愉快的歌唱,小船儿轻轻飘荡在水中,迎面吹来了凉爽的风!

bNbrports是前面我们获得的hub descriptor的一个成员,表征这个hub有几个端口.很显然,月可无光,星可无语,usb设备却不可以没有描述符.这里就是遍历每一个端口.busy_bitsstruct usb_hub的一个成员,unsigned long busy_bits[1],接下来的event_bits也是,change_bits也是,unsigned long event_bits[1],unsigned long change_bits[1],test_bit()我们太熟悉了,usb-storage里面到处都是,只不过当时我们测试的是us->flags里面的某个flag是否设置了,而这里我们要测试的有三个东东,首先测试busy_bits,这个flag实际上只有在resetresume的函数内部才会设置,所以这里我们先不用管,而这里的意思是,如果眼下这个端口正在执行reset或者resume操作,那么咱们就跳过去,不予理睬.

2689,测试change_bits.结合2690,2691,2692行一起看.如果这个端口对应的change_bits没有设置,event_bits没有设置过,hub->activating也为0,那么这里就执行continue,不过我们想都不用想,因为我们就是从hub_activate进来的.我们来的时候activating就是设置成了1,所以这里的continue我们是不用执行的.换言之,我们继续往下走.

2694,hub_port_status(),portstatusportchange是我们在hub_events()伊始定义的两个变量,u16 portstatus,u16 portchange,即两个都是16.尽管说了N遍了,但是我还是得说第N+1,这个函数仍然是来自drivers/usb/core/hub.c:

1413 static int hub_port_status(struct usb_hub *hub, int port1,

1414 u16 *status, u16 *change)

1415 {

1416 int ret;

1417

1418 mutex_lock(&hub->status_mutex);

1419 ret = get_port_status(hub->hdev, port1, &hub->status->port);

1420 if (ret < 4) {

1421 dev_err (hub->intfdev,

1422 "%s failed (err = %d)/n", __FUNCTION__, ret);

1423 if (ret >= 0)

1424 ret = -EIO;

1425 } else {

1426 *status = le16_to_cpu(hub->status->port.wPortStatus);

1427 *change = le16_to_cpu(hub->status->port.wPortChange);

1428 ret = 0;

1429 }

1430 mutex_unlock(&hub->status_mutex);

1431 return ret;

1432 }

重要的是其中的那个get_port_status()函数.

300 /*

301 * USB 2.0 spec Section 11.24.2.7

302 */

303 static int get_port_status(struct usb_device *hdev, int port1,

304 struct usb_port_status *data)

305 {

306 int i, status = -ETIMEDOUT;

307

308 for (i = 0; i < USB_STS_RETRIES && status == -ETIMEDOUT; i++) {

309 status = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),

310 USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port1,

311 data, sizeof(*data), USB_STS_TIMEOUT);

312 }

313 return status;

314 }

一路从泥泞走到美景,我们再也不会对usb_control_msg()函数陌生了,这个函数做什么勾当我们完全是一目了然.Get Port StatusHub的一个标准请求,对我们来说就是一次控制传输就可以搞定.这个请求的格式如下图所示:

<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 415.5pt; HEIGHT: 78pt" type="#_x0000_t75"><imagedata o:title="" src="file:///C:/DOCUME~1/JASON_~1/LOCALS~1/Temp/msohtml1/01/clip_image001.emz"></imagedata></shape>

其中这个GET_STATUS的对应具体的数值可以在下面这张表中对比得到,

<shape id="_x0000_i1027" style="WIDTH: 365.25pt; HEIGHT: 395.25pt" type="#_x0000_t75"><imagedata o:title="" src="file:///C:/DOCUME~1/JASON_~1/LOCALS~1/Temp/msohtml1/01/clip_image003.emz"></imagedata></shape>

而关于各种请求,咱们在include/linux/usb/ch9.h中也定义了相应的宏,

72 /*

73 * Standard requests, for the bRequest field of a SETUP packet.

74 *

75 * These are qualified by the bRequestType field, so that for example

76 * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved

77 * by a GET_STATUS request.

78 */

79 #define USB_REQ_GET_STATUS 0x00

80 #define USB_REQ_CLEAR_FEATURE 0x01

81 #define USB_REQ_SET_FEATURE 0x03

82 #define USB_REQ_SET_ADDRESS 0x05

83 #define USB_REQ_GET_DESCRIPTOR 0x06

84 #define USB_REQ_SET_DESCRIPTOR 0x07

85 #define USB_REQ_GET_CONFIGURATION 0x08

86 #define USB_REQ_SET_CONFIGURATION 0x09

87 #define USB_REQ_GET_INTERFACE 0x0A

88 #define USB_REQ_SET_INTERFACE 0x0B

89 #define USB_REQ_SYNCH_FRAME 0x0C

90

91 #define USB_REQ_SET_ENCRYPTION 0x0D /* Wireless USB */

92 #define USB_REQ_GET_ENCRYPTION 0x0E

93 #define USB_REQ_RPIPE_ABORT 0x0E

94 #define USB_REQ_SET_HANDSHAKE 0x0F

95 #define USB_REQ_RPIPE_RESET 0x0F

96 #define USB_REQ_GET_HANDSHAKE 0x10

97 #define USB_REQ_SET_CONNECTION 0x11

98 #define USB_REQ_SET_SECURITY_DATA 0x12

99 #define USB_REQ_GET_SECURITY_DATA 0x13

100 #define USB_REQ_SET_WUSB_DATA 0x14

101 #define USB_REQ_LOOPBACK_DATA_WRITE 0x15

102 #define USB_REQ_LOOPBACK_DATA_READ 0x16

103 #define USB_REQ_SET_INTERFACE_DS 0x17

比如这里咱们传递给usb_control_msgrequest就是USB_REQ_GET_STATUS,它的值为0,usb spec中定义的GET_STATUS的值是对应的.这个请求返回两个咚咚,一个称为Port Status,一个称为Port Change Status.usb_control_msg()的调用注定了返回值将保存在struct usb_port_status *data里面,这个结构体定义与drivers/usb/core/hub.h:

58 /*

59 * Hub Status and Hub Change results

60 * See USB 2.0 spec Table 11-19 and Table 11-20

61 */

62 struct usb_port_status {

63 __le16 wPortStatus;

64 __le16 wPortChange;

65 } __attribute__ ((packed));

很显然这个格式是和实际的spec规范对应的,我们给get_port_status()传递的实参是&hub->status->port,port也是一个struct usb_port_status结构体变量,所以在hub_port_status()里面,14261427两行我们就得到了Status BitsStatus Change Bits.get_port_status()返回值就是GET PORT STATUS请求的返回数据的长度,它至少应该能够保存wPortStatuswPortChange,所以至少不能小于4,所以1420行有这么一个错误判断.这样,hub_port_status()就返回了,statuschange这两个指针也算是满载而归了,正常的话返回值就是0.

继续往下走,2699,children[i-1],这么一个冬冬我们从没有见过,但是我想白痴都知道,正是像parentchildren这样的指针才能把USB树给建立起来,而我们才刚上路,肯定还没有设置children,所以对我们来说,至少目前children数组肯定为空,而我们又知道hub->activating这时候肯定为1,所以就看第三个条件了,portstatus&USB_PORT_STAT_CONNECTION,这是啥意思?稍有悟性的人就能看出来,这表明这个端口连了设备,没错,USB_PORT_STAT_CONNECTION这个宏定义于drivers/usb/core/hub.h:

67 /*

68 * wPortStatus bit field

69 * See USB 2.0 spec Table 11-21

70 */

71 #define USB_PORT_STAT_CONNECTION 0x0001

72 #define USB_PORT_STAT_ENABLE 0x0002

73 #define USB_PORT_STAT_SUSPEND 0x0004

74 #define USB_PORT_STAT_OVERCURRENT 0x0008

75 #define USB_PORT_STAT_RESET 0x0010

76 /* bits 5 to 7 are reserved */

77 #define USB_PORT_STAT_POWER 0x0100

78 #define USB_PORT_STAT_LOW_SPEED 0x0200

79 #define USB_PORT_STAT_HIGH_SPEED 0x0400

80 #define USB_PORT_STAT_TEST 0x0800

81 #define USB_PORT_STAT_INDICATOR 0x1000

82 /* bits 13 to 15 are reserved */

83

84 /*

85 * wPortChange bit field

86 * See USB 2.0 spec Table 11-22

87 * Bits 0 to 4 shown, bits 5 to 15 are reserved

88 */

89 #define USB_PORT_STAT_C_CONNECTION 0x0001

90 #define USB_PORT_STAT_C_ENABLE 0x0002

91 #define USB_PORT_STAT_C_SUSPEND 0x0004

92 #define USB_PORT_STAT_C_OVERCURRENT 0x0008

93 #define USB_PORT_STAT_C_RESET 0x0010

这都是这两个变量对应的宏,usb 2.0spec里面对这些宏的意义说得很清楚,USB_PORT_STAT_CONNECTION的意思的确是表征是否有设备连接在这个端口上,我们不妨假设有,那么portstatus和它相与的结果就是1,usb spec里面,这一位叫做Current Connect Status,于是这里我们会看到connect_change被设置成了1.而接下来,USB_PORT_STAT_C_CONNECTION则是表征这个端口的Current Connect Status位是否有变化,如果有变化,那么portchangeUSB_PORT_STAT_C_CONNECTION相与的结果就是1,对于这种情况,我们需要发送另一个请求以清除这个flag,并且将connect_change也设置为1.这个请求叫做Clear Port Feature.这个请求也是Hub的标准请求,

<shape id="_x0000_i1028" style="WIDTH: 415.5pt; HEIGHT: 67.5pt" type="#_x0000_t75"><imagedata o:title="" src="file:///C:/DOCUME~1/JASON_~1/LOCALS~1/Temp/msohtml1/01/clip_image005.emz"></imagedata></shape>

它的作用就是reset hub端口的某种feature.clear_port_feature()定义于drivers/usb/core/hub.c:

162 /*

163 * USB 2.0 spec Section 11.24.2.2

164 */

165 static int clear_port_feature(struct usb_device *hdev, int port1, int feature)

166 {

167 return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),

168 USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port1,

169 NULL, 0, 1000);

170 }

对比上面贴出来的定义可知,USB_REQ_CLEAR_FEATUREusb spec中的CLEAR_FEATURE这个请求是对应的,那么一共有些什么Feature?drivers/usb/core/hub.h中是这样定义的,

38 /*

39 * Port feature numbers

40 * See USB 2.0 spec Table 11-17

41 */

42 #define USB_PORT_FEAT_CONNECTION 0

43 #define USB_PORT_FEAT_ENABLE 1

44 #define USB_PORT_FEAT_SUSPEND 2

45 #define USB_PORT_FEAT_OVER_CURRENT 3

46 #define USB_PORT_FEAT_RESET 4

47 #define USB_PORT_FEAT_POWER 8

48 #define USB_PORT_FEAT_LOWSPEED 9

49 #define USB_PORT_FEAT_HIGHSPEED 10

50 #define USB_PORT_FEAT_C_CONNECTION 16

51 #define USB_PORT_FEAT_C_ENABLE 17

52 #define USB_PORT_FEAT_C_SUSPEND 18

53 #define USB_PORT_FEAT_C_OVER_CURRENT 19

54 #define USB_PORT_FEAT_C_RESET 20

55 #define USB_PORT_FEAT_TEST 21

56 #define USB_PORT_FEAT_INDICATOR 22

而在usb spec,有一张与之相对应的表格,定义了许多的feature,如图所示:

<shape id="_x0000_i1029" style="WIDTH: 414.75pt; HEIGHT: 231.75pt" type="#_x0000_t75"><imagedata o:title="" src="file:///C:/DOCUME~1/JASON_~1/LOCALS~1/Temp/msohtml1/01/clip_image007.emz"></imagedata></shape>

<shape id="_x0000_i1026" style="WIDTH: 414.75pt; HEIGHT: 276pt" type="#_x0000_t75"><imagedata o:title="" src="file:///C:/DOCUME~1/JASON_~1/LOCALS~1/Temp/msohtml1/01/clip_image009.emz"></imagedata></shape>

所以,我们清除的是C_PORT_CONNECTION这一个feature.spec里面说了,清除一个状态改变的feature就等于承认这么一个feature.(clearing that status change acknowledges the change)理由很简单,每次你检测到一个flag被设置之后,你都应该清除掉它,以便下次人家一设你就知道是人家设了,否则你不清你下次判断你就不知道是不是又有人设了.同理,接下来的每个与portchange相关的判断语句都要这么做.所以如果portchange与上USB_PORT_STAT_C_CONNECTION确实为1,那么我们就要清除这个feature.同时我们当然也要记录connect_change1.

继续,每个端口都有一个开关,这叫做enable或者disable一个端口.portchangeUSB_PORT_STAT_C_ENABLE相与如果为1的话,说明端口开关有变化.和刚才一样,首先我们要做的是,清除掉这个变化的feature.但是这里需要注意,spec里对这个feature是这样规定的,如果portchangeUSB_PORT_STAT_C_ENABLE1,说明这个port是从enable状态进入了disable状态.为什么呢?因为在spec规定了,Hub的端口是不可以直接设置成enable.通常让Hub端口enable的方法是reset hub port.spec的话说,这叫做发送另一个request,名为SET_FEATURE.SET_FEATURECLEAR_FEATURE是对应的,一个设置一个清除. 对于PORT_ENABLE这一位,spec里的话说,This bit may be set only as a result of a SetPortFeature(PORT_RESET) request,PORT_RESET是为hub定义的众多feature中的一种.最后提醒一点,27112715这段if语句仅仅是为了打印调试信息的,就是说如果port enable改变了,但是端口连接没有改变,那么打印出信息来通知调试者,不要把clear_port_feature这一行也纳入到if语句里去了.因为port enable的改变有多种可能,其中一种可能就是由于检测到了disconnection,但是对于这种情况,我们下面要处理的,所以甭急.

下面这段代码就比较帅了,电磁干扰都给扯进来了.EMI,就是电磁干扰.就是说有的时候hub portenable变成disable有可能是由于电磁干扰造成的,这个if条件判断的是,端口被disable,但是连接没有变化,并且hdev->children[i]还有值,这就说明明明有子设备连在端口上,可是端口却被disable,基本上这种情况就是电磁干扰造成的,否则hub端口不会有这种抽风的举动.那么这种情况就设置connect_change1.因为接下来我们会看到对于connect_change1的情况,我们会专门进行处理,而更犀利更一针见血的说法就是,hub_events()其实最重要的任务就是对于端口连接有变化的情况进行处理,或者说进行响应.

再往下,portchangeUSB_PORT_STAT_C_SUSPEND相与如果为1,表明连在该端口的设备的suspend状态有变化,并且是从suspended状态出来,也就是说resume完成.(别问我为什么,spec就这么规定的,没什么理由,一定要问理由那你问郑源去,他不是唱那什么如果你真的需要什么理由,一万个够不够吗.)那么首先我们就调用clear_port_feature清掉这个feature.接下来这个if牵扯到的东西比较高深,涉及到电源管理中很华丽的部分,我们只能先跳过.否则深陷其中难免会走火入魔欲罢不能.总之这里做的就是对于该端口连了子设备的情况就把子设备唤醒,否则如果端口没有连子设备,那么就把端口disable.

2754,portchange如果和USB_PORT_STAT_C_OVERCURRENT相与结果为1的话,说明这个端口可能曾经存在电流过大的情况,而现在这种情况不存在了,或者本来不存在而现在存在了.对此我们能做的就是首先清除这个feature.有一种比较特别的情况是,如果其它的端口电流过大,那么将会导致本端口断电,hub上一个端口出现over-current条件将有可能引起hub上其它端口陷入powered off的状态.不管怎么说,对于over-current的情况我们都把hub重新上电,执行hub_power_on().

2763,portchange如果和USB_PORT_STAT_C_RESET相与为1的话,这叫做一个端口从Resetting状态进入到Enabled状态.

2771,connect_change如果为1,就执行hub_port_connect_change(),啥也不说了,这是每一个看hub驱动的人最期待的函数,因为这正是我们的原始动机,即当一个usb设备插入usb接口之后究竟会发生什么,usb设备驱动程序提供那个probe函数究竟是如何被调用的.这些疑问统统会在这个函数里得到答案.来自drivers/usb/core/hub.c:

2404 /* Handle physical or logical connection change events.

2405 * This routine is called when:

2406 * a port connection-change occurs;

2407 * a port enable-change occurs (often caused by EMI);

2408 * usb_reset_device() encounters changed descriptors (as from

2409 * a firmware download)

2410 * caller already locked the hub

2411 */

2412 static void hub_port_connect_change(struct usb_hub *hub, int port1,

2413 u16 portstatus, u16 portchange)

2414 {

2415 struct usb_device *hdev = hub->hdev;

2416 struct device *hub_dev = hub->intfdev;

2417 u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);

2418 int status, i;

2419

2420 dev_dbg (hub_dev,

2421 "port %d, status %04x, change %04x, %s/n",

2422 port1, portstatus, portchange, portspeed (portstatus));

2423

2424 if (hub->has_indicators) {

2425 set_port_led(hub, port1, HUB_LED_AUTO);

2426 hub->indicator[port1-1] = INDICATOR_AUTO;

2427 }

2428

2429 /* Disconnect any existing devices under this port */

2430 if (hdev->children[port1-1])

2431 usb_disconnect(&hdev->children[port1-1]);

2432 clear_bit(port1, hub->change_bits);

2433

2434 #ifdef CONFIG_USB_OTG

2435 /* during HNP, don't repeat the debounce */

2436 if (hdev->bus->is_b_host)

2437 portchange &= ~USB_PORT_STAT_C_CONNECTION;

2438 #endif

2439

2440 if (portchange & USB_PORT_STAT_C_CONNECTION) {

2441 status = hub_port_debounce(hub, port1);

2442 if (status < 0) {

2443 if (printk_ratelimit())

2444 dev_err (hub_dev, "connect-debounce failed, "

2445 "port %d disabled/n", port1);

2446 goto done;

2447 }

2448 portstatus = status;

2449 }

2450

2451 /* Return now if nothing is connected */

2452 if (!(portstatus & USB_PORT_STAT_CONNECTION)) {

2453

2454 /* maybe switch power back on (e.g. root hub was reset) */

2455 if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2

2456 && !(portstatus & (1 << USB_PORT_FEAT_POWER)))

2457 set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);

2458

2459 if (portstatus & USB_PORT_STAT_ENABLE)

2460 goto done;

2461 return;

2462 }

2463

2464 #ifdef CONFIG_USB_SUSPEND

2465 /* If something is connected, but the port is suspended, wake it up. */

2466 if (portstatus & USB_PORT_STAT_SUSPEND) {

2467 status = hub_port_resume(hub, port1, NULL);

2468 if (status < 0) {

2469 dev_dbg(hub_dev,

2470 "can't clear suspend on port %d; %d/n",

2471 port1, status);

2472 goto done;

2473 }

2474 }

2475 #endif

2476

2477 for (i = 0; i < SET_CONFIG_TRIES; i++) {

2478 struct usb_device *udev;

2479

2480 /* reallocate for each attempt, since references

2481 * to the previous one can escape in various ways

2482 */

2483 udev = usb_alloc_dev(hdev, hdev->bus, port1);

2484 if (!udev) {

2485 dev_err (hub_dev,

2486 "couldn't allocate port %d usb_device/n",

2487 port1);

2488 goto done;

2489 }

2490

2491 usb_set_device_state(udev, USB_STATE_POWERED);

2492 udev->speed = USB_SPEED_UNKNOWN;

2493 udev->bus_mA = hub->mA_per_port;

2494 udev->level = hdev->level + 1;

2495

2496 /* set the address */

2497 choose_address(udev);

2498 if (udev->devnum <= 0) {

2499 status = -ENOTCONN; /* Don't retry */

2500 goto loop;

2501 }

2502

2503 /* reset and get descriptor */

2504 status = hub_port_init(hub, udev, port1, i);

2505 if (status < 0)

2506 goto loop;

2507

2508 /* consecutive bus-powered hubs aren't reliable; they can

2509 * violate the voltage drop budget. if the new child has

2510 * a "powered" LED, users should notice we didn't enable it

2511 * (without reading syslog), even without per-port LEDs

2512 * on the parent.

2513 */

2514 if (udev->descriptor.bDeviceClass == USB_CLASS_HUB

2515 && udev->bus_mA <= 100) {

2516 u16 devstat;

2517

2518 status = usb_get_status(udev, USB_RECIP_DEVICE, 0,

2519 &devstat);

2520 if (status < 2) {

2521 dev_dbg(&udev->dev, "get status %d ?/n", status);

2522 goto loop_disable;

2523 }

2524 le16_to_cpus(&devstat);

2525 if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {

2526 dev_err(&udev->dev,

2527 "can't connect bus-powered hub "

2528 "to this port/n");

2529 if (hub->has_indicators) {

2530 hub->indicator[port1-1] =

2531 INDICATOR_AMBER_BLINK;

2532 schedule_delayed_work (&hub->leds, 0);

2533 }

2534 status = -ENOTCONN; /* Don't retry */

2535 goto loop_disable;

2536 }

2537 }

2538

2539 /* check for devices running slower than they could */

2540 if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200

2541 && udev->speed == USB_SPEED_FULL

2542 && highspeed_hubs != 0)

2543 check_highspeed (hub, udev, port1);

2544

2545 /* Store the parent's children[] pointer. At this point

2546 * udev becomes globally accessible, although presumably

2547 * no one will look at it until hdev is unlocked.

2548 */

2549 status = 0;

2550

2551 /* We mustn't add new devices if the parent hub has

2552 * been disconnected; we would race with the

2553 * recursively_mark_NOTATTACHED() routine.

2554 */

2555 spin_lock_irq(&device_state_lock);

2556 if (hdev->state == USB_STATE_NOTATTACHED)

2557 status = -ENOTCONN;

2558 else

2559 hdev->children[port1-1] = udev;

2560 spin_unlock_irq(&device_state_lock);

2561

2562 /* Run it through the hoops (find a driver, etc) */

2563 if (!status) {

2564 status = usb_new_device(udev);

2565 if (status) {

2566 spin_lock_irq(&device_state_lock);

2567 hdev->children[port1-1] = NULL;

2568 spin_unlock_irq(&device_state_lock);

2569 }

2570 }

2571

2572 if (status)

2573 goto loop_disable;

2574

2575 status = hub_power_remaining(hub);

2576 if (status)

2577 dev_dbg(hub_dev, "%dmA power budget left/n", status);

2578

2579 return;

2580

2581 loop_disable:

2582 hub_port_disable(hub, port1, 1);

2583 loop:

2584 ep0_reinit(udev);

2585 release_address(udev);

2586 usb_put_dev(udev);

2587 if (status == -ENOTCONN)

2588 break;

2589 }

2590

2591 done:

2592 hub_port_disable(hub, port1, 1);

2593 }

到今天我算是看明白了,内核里面这些函数,没有最变态只有更变态,变态哪都有,可是开源社区尤其多!你们他妈的不是我的冤家派来故意玩我的吧?面对这个函数,我真的想吐血!我打算不像过去那样一行一行讲了,我必须先来个提纲挈领,必须先开门见山把这个函数的哲学思想讲清楚,否则一行一行往下讲肯定晕菜.
分享到:
评论

相关推荐

    Linux那些事儿之我是Hub

    Linux那些事儿之我是Hub,是前面Linux那些事之我是U盘,usb等的姐妹篇

    Linux那些事儿之我是HUB.pdf

    非常不错的一本书,LinuxLinuxLinuxLinuxLinuxLinuxLinuxLinuxLinuxLinuxLinuxLinuxLinuxLinux

    Linux那些事儿

    Linux那些事儿之我是Hub Linux那些事儿之我是USB Core Linux那些事儿之我是UHCI Linux那些事儿之我是EHCI控制器 Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Block层 Linux那些事儿之我...

    Linux那些事儿1-9合集

    读过《linux那些事儿之我是U盘》的人,都知道其风格,我就不多说了。 导读: linux那些事儿之我是U盘 linux那些事儿之我是HUB linux那些事儿之我是USB Core linux那些事儿之我是UHCI Linux那些事儿之我是EHCI主机控制...

    Linux那些事儿之我是USB(第2版)

    Linux那些事儿第二版我是Hub一章,比较第一版修正了一些错误,增加了电源管理部分的分析,推荐阅读

    Linux那些事儿之全集

    导读.doc Linux那些事儿之我是Block层.pdf Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是Hub.pdf Linux那些事儿之我是USB_core.pdf Linux那些事儿之我是U盘.pdf等等 Linux那些事儿系列全在这里了

    Linux那些事儿系列.rar

    》包括《Linux那些事儿之我是Hub》、《Linux那些事儿之我是Sysfs》《Linux那些事儿之我是UHCI》、《Linux那些事儿之我是USB core》、《Linux那些事儿之我是U盘》,令人叹为观止的一个linux系列书籍。只能说,江山代...

    linux那些事儿之我是USB(包括第一版和第二版完整文字)

    本文件包括第一第二完成...本次改版修改了第1版中出现的错误,增加了一个附录,主要内容是关于Linux内核的学习方法,是作者的经验总结,值得一读。 本书使用幽默诙谐的笔调对Linux内核中的USB子系统源代码进行了分析。

    Linux那些事儿之我是USB(第2版).pdf

    本次改版修改了第1版中出现的错误,增加了一个附录,主要内容是关于Linux内核的学习方法,是作者的经验总结,值得一读。 本书使用幽默诙谐的笔调对Linux内核中的USB子系统源代码进行了分析,形象且详尽地介绍了USB在...

    linux的那些事儿全集

    Linux那些事儿之我是Block层 ...Linux那些事儿之我是Hub Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Sysfs Linux那些事儿之我是UHCI Linux那些事儿之我是USB core Linux那些事儿之我是U盘

    linux那些事儿(EHCI Block SCSI Sysfs PCI USB U 盘 UHCI Hub)

    Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是Block层.pdf Linux那些事儿之我是SCSI硬盘.pdf Linux那些事儿之我是Sysfs.pdf ...Linux那些事儿之我是Hub.pdf Linux那些事儿之我是UHCI.pdf

    linux那些事全集

    Linux那些事儿之我是U盘 Linux那些事儿之我是USB_core Linux那些事儿之我是UHCI Linux那些事儿之我是Sysfs ...Linux那些事儿之我是Hub Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是Block层

    Linux那些事儿系列

    本人整理的fudan_abc的专栏中以完结的文章,在此向原作者表示感谢,给...内容包括:linux那些事儿之我是U盘,linux那些事儿之我是USB,linux那些事儿之我是HUB,linux那些事儿之我是UHCI,linux那些事儿之我是Sysfs。

    Linux那些事儿之我是XXX全集.rar

    Linux那些事儿之我是XXX全集 包含USB core U盘 UHCI PCI SCSI硬盘 Block Hub EHCI 。 想学驱动的童鞋,不妨看看。该书主要是进行源代码的分析

    Linux那些事儿 系列之2 Block+EHCI+PCI+SCSI

    Linux那些事儿之我是Block层.pdf Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是PCI.pdf Linux那些事儿之我是SCSI硬盘.pdf 注: 之前有人已经上传了《Linux那些事儿 系列》,其已经包含了:hub,sysfs...

    linux那些事儿之我是USB.zip

    里面包含Linux那些事的九个文档,Block层,ECHI主机控制,HUB,PCI,SCSI硬盘,Sysfs,UHCI,USB+core,U盘等九个文档,内容详细,而且全面都有书签,适合系统学习!

    Linux那些事儿.rar

    包括:Linux那些Linux那些事儿之我是SCSI硬盘,Linux那些事儿之我是Block层,Linux那些事儿之我是EHCI主机控制器,Linux那些事儿之我是HUB,Linux那些事儿之我是PCI,Linux那些事儿之我是Sysfs,Linux那些事儿之我是...

    Linux那些事系列

    Linux那些事儿之我是Hub Linux那些事儿之我是Sysfs Linux那些事儿之我是UHCI Linux那些事儿之我是USB core Linux那些事儿之我是U盘 Linux那些事之我是HUB1

Global site tag (gtag.js) - Google Analytics