这个usb_hcd_pci_resume来自drivers/usb/core/hcd-pci.c:
312 /**
313 * usb_hcd_pci_resume - power management resume of a PCI-based HCD
314 * @dev: USB Host Controller being resumed
315 *
316 * Store this function in the HCD's struct pci_driver as resume().
317 */
318 int usb_hcd_pci_resume (struct pci_dev *dev)
319 {
320 struct usb_hcd *hcd;
321 int retval;
322
323 hcd = pci_get_drvdata(dev);
324 if (hcd->state != HC_STATE_SUSPENDED) {
325 dev_dbg (hcd->self.controller,
326 "can't resume, not suspended!/n");
327 return 0;
328 }
329
330 #ifdef CONFIG_PPC_PMAC
331 /* Reenable ASIC clocks for USB */
332 if (machine_is(powermac)) {
333 struct device_node *of_node;
334
335 of_node = pci_device_to_OF_node (dev);
336 if (of_node)
337 pmac_call_feature (PMAC_FTR_USB_ENABLE,
338 of_node, 0, 1);
339 }
340 #endif
341
342 /* NOTE: chip docs cover clean "real suspend" cases (what Linux
343 * calls "standby", "suspend to RAM", and so on). There are also
344 * dirty cases when swsusp fakes a suspend in "shutdown" mode.
345 */
346 if (dev->current_state != PCI_D0) {
347 #ifdef DEBUG
348 int pci_pm;
349 u16 pmcr;
350
351 pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
352 pci_read_config_word(dev, pci_pm + PCI_PM_CTRL, &pmcr);
353 pmcr &= PCI_PM_CTRL_STATE_MASK;
354 if (pmcr) {
355 /* Clean case: power to USB and to HC registers was
356 * maintained; remote wakeup is easy.
357 */
358 dev_dbg(hcd->self.controller, "resume from PCI D%d/n",
359 pmcr);
360 } else {
361 /* Clean: HC lost Vcc power, D0 uninitialized
362 * + Vaux may have preserved port and transceiver
363 * state ... for remote wakeup from D3cold
364 * + or not; HCD must reinit + re-enumerate
365 *
366 * Dirty: D0 semi-initialized cases with swsusp
367 * + after BIOS init
368 * + after Linux init (HCD statically linked)
369 */
370 dev_dbg(hcd->self.controller,
371 "PCI D0, from previous PCI D%d/n",
372 dev->current_state);
373 }
374 #endif
375 /* yes, ignore these results too... */
376 (void) pci_enable_wake (dev, dev->current_state, 0);
377 (void) pci_enable_wake (dev, PCI_D3cold, 0);
378 } else {
379 /* Same basic cases: clean (powered/not), dirty */
380 dev_dbg(hcd->self.controller, "PCI legacy resume/n");
381 }
382
383 /* NOTE: the PCI API itself is asymmetric here. We don't need to
384 * pci_set_power_state(PCI_D0) since that's part of re-enabling;
385 * but that won't re-enable bus mastering. Yet pci_disable_device()
386 * explicitly disables bus mastering...
387 */
388 retval = pci_enable_device (dev);
389 if (retval < 0) {
390 dev_err (hcd->self.controller,
391 "can't re-enable after resume, %d!/n", retval);
392 return retval;
393 }
394 pci_set_master (dev);
395 pci_restore_state (dev);
396
397 dev->dev.power.power_state = PMSG_ON;
398
399 clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
400
401 if (hcd->driver->resume) {
402 retval = hcd->driver->resume(hcd);
403 if (retval) {
404 dev_err (hcd->self.controller,
405 "PCI post-resume error %d!/n", retval);
406 usb_hc_died (hcd);
407 }
408 }
409
410 return retval;
411 }
330行至340行,激动的理由同usb_hcd_pci_suspend.
346行,首先判断,如果是PCI_D0,那么就不存在所谓的resume了.
376行,377行,调用pci_enable_wake,但是传递的第三个参数是0,即这次是关,而上次咱们在usb_hcd_pci_suspend中看到的传递的就不一定是0.这里关闭的是当前状态下的PME#能力,以及PCI_D3cold下的PME#能力,因为这两种状态下没有必要再发送PME#信号了.
388行,pci_enable_device,和前面那个pci_disable_device相对应.其实咱们不是头一次看到这个函数,当初在usb_hcd_pci_probe中就调用了这个函数.
394行,pci_set_master,在设备开始工作之前为设备启用总线控制.其实咱们也不是头一次看到这个函数,当初在usb_hcd_pci_probe中也调用了这个函数.
395行,pci_restore_state,很显然和前面那个pci_save_state相对应.恢复当初保存的PCI设备配置空间.
一切顺利就把power_state设置为PMSG_ON.
399行, HCD_FLAG_SAW_IRQ这个flag意义不大.用Alan Stern的话说就是,这个flag是用来汇报错误的.如果一个urb在这个flag被清掉了以后unlink,这就意味着可能中断号赋错了.就比如现在咱们这里调用clear_bit清掉了这个flag,如果这时候你取unlink一个urb,那么一定是有问题的.当然我个人觉得这个flag的用处不大,如果我是Greg,我肯定把这个flag给删掉.
401行,调用driver->resume,对于uhci,就是uchi_resume函数.来自drivers/usb/host/uhci-hcd.c:
779 static int uhci_resume(struct usb_hcd *hcd)
780 {
781 struct uhci_hcd *uhci = hcd_to_uhci(hcd);
782
783 dev_dbg(uhci_dev(uhci), "%s/n", __FUNCTION__);
784
785 /* Since we aren't in D3 any more, it's safe to set this flag
786 * even if the controller was dead.
787 */
788 set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
789 mb();
790
791 spin_lock_irq(&uhci->lock);
792
793 /* FIXME: Disable non-PME# remote wakeup? */
794
795 /* The firmware or a boot kernel may have changed the controller
796 * settings during a system wakeup. Check it and reconfigure
797 * to avoid problems.
798 */
799 check_and_reset_hc(uhci);
800
801 /* If the controller was dead before, it's back alive now */
802 configure_hc(uhci);
803
804 if (uhci->rh_state == UHCI_RH_RESET) {
805
806 /* The controller had to be reset */
807 usb_root_hub_lost_power(hcd->self.root_hub);
808 suspend_rh(uhci, UHCI_RH_SUSPENDED);
809 }
810
811 spin_unlock_irq(&uhci->lock);
812
813 if (!uhci->working_RD) {
814 /* Suspended root hub needs to be polled */
815 hcd->poll_rh = 1;
816 usb_hcd_poll_rh_status(hcd);
817 }
818 return 0;
819 }
和uhci_suspend所做的事情相反,这里主要就是设置HCD_FLAG_HW_ACCESSIBLE这个flag.
而像check_and_reset_hc和configure_hc这两个函数都是一开始咱们初始化uhci的时候调用过的.resume的时候和init的时候做的事情有时候是很相似的.
而把rh_state设置为UHCI_RH_RESET的地方只有一处,即finish_reset中.这个函数咱们见过不止一次了.而且事实上在刚才说的这个check_and_reset_hc()中就会调用finish_reset().于是我提出一个问题,在咱们这个实验中,finish_reset会不会被调用?让我们再次把check_and_reset_hc()贴出来:
164 /*
165 * Initialize a controller that was newly discovered or has lost power
166 * or otherwise been reset while it was suspended. In none of these cases
167 * can we be sure of its previous state.
168 */
169 static void check_and_reset_hc(struct uhci_hcd *uhci)
170 {
171 if (uhci_check_and_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr))
172 finish_reset(uhci);
173 }
实践表明,uhci_check_and_reset_hc在我们这个实验中返回值一定是0.(在kdb中我们可以使用rd命令来查看寄存器%eax,因为%eax通常就代表着函数的返回值.所以我们可以看到在这个实验中,如果把断点设置在uhci_check_and_reset_hc调用的下一行,那么%eax必然是0.)于是我们来到uhci_check_and_reset_hc中看一下为什么返回值是0.
85 /*
86 * Initialize a controller that was newly discovered or has just been
87 * resumed. In either case we can't be sure of its previous state.
88 *
89 * Returns: 1 if the control