Linux那些事儿之我是Hub(8)While You Were Sleeping(一) – fudan

最近看了热播的电视剧<<奋斗>>,赵宝刚导演的转型之作.里面李小璐和文章演的那对小夫妻甚是搞笑.这部片子其实号称励志篇但实际上一点也不励志,就是搞笑,像我这种严肃的人向来不喜欢这些搞笑,不过里面李小璐扮演的杨晓芸对文章演的那个向南的一番对话倒是让我觉得颇为感慨.杨晓芸一心希望向南能够有理想有目标,而向南却非常满足于现状,而这种矛盾间接导致了杨晓芸对丈夫的失望并且最终两个人走向了离婚.其实我就是一个没有目标的人,整天混日子,从前进复旦的时候是一个字,混,后来离开复旦的时候是两个字,混混.

看了这部片子之后,我决定做一个有目标的人,首先我的目标不是像其他男人那样庸俗,什么农妇山泉有点田,作为复旦大学高材生,我有一个更为宏伟的目标,就是一鼓作气,跟踪hub_probe,直到找到那句唤醒hub_thread()的代码为止.(画外音:我汗…这也叫宏伟?)

继续沿着hub_probe()往下走,937至941行,937行我们在usb-storage里已然见过了,usb_set_intfdata(intf,hub)的作用就是让intf和hub关联起来,从此以后,我们知道struct usb_interface *intf,就可以追溯到与之关联的struct usb_hub指针.这种思想是很纯朴的,很简单的,但也是很重要的,这就好比在网络时代的我们,应该熟练掌握以google为代表的搜索引擎的使用方法,要学会如何从一根狗毛追溯到狗的主人曾经得过什么病.

938行,设置intf的need_remote_wakeup为1.

940行,如果这个设备,确切地说是这个hub是高速设备,那么让highspeed_hubs加一.highspeed_hubs是hub一个drivers/usb/core/hub.c中的全局变量,确切地说应该还是局部变量,其定义是这样的,

848 static unsigned highspeed_hubs;

static,静态变量.其实就是hub.c这个文件里的全局.至于这几个变量是干嘛用的,您暂时甭管,用到了再说.

943到947行,结束了这几行的话,hub_probe就算完了.我们先不用细看每个函数,很显然,hub_configure这个函数是用来配置hub的,返回值小于0就算出错了,这里的做法是,没出错那么hub_probe就返回0,否则,那就执行hub_disconnect(),断开,并且返回错误代码-ENODEV.hub_disconnect其实就是和hub_probe()对应的函数,其暧昧关系就像当初storage_probe()和storage_disconnect的关系一样.我们先来看hub_configure().这个函数简直是帅呆了,又是一个300来行的函数.同样还是来自drivers/usb/core/hub.c:

595 static int hub_configure(struct usb_hub *hub,

596 struct usb_endpoint_descriptor *endpoint)

597 {

598 struct usb_device *hdev = hub->hdev;

599 struct device *hub_dev = hub->intfdev;

600 u16 hubstatus, hubchange;

601 u16 wHubCharacteristics;

602 unsigned int pipe;

603 int maxp, ret;

604 char *message;

605

606 hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL,

607 &hub->buffer_dma);

608 if (!hub->buffer) {

609 message = "can’t allocate hub irq buffer";

610 ret = -ENOMEM;

611 goto fail;

612 }

613

614 hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);

615 if (!hub->status) {

616 message = "can’t kmalloc hub status buffer";

617 ret = -ENOMEM;

618 goto fail;

619 }

620 mutex_init(&hub->status_mutex);

621

622 hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);

623 if (!hub->descriptor) {

624 message = "can’t kmalloc hub descriptor";

625 ret = -ENOMEM;

626 goto fail;

627 }

628

629 /* Request the entire hub descriptor.

630 * hub->descriptor can handle USB_MAXCHILDREN ports,

631 * but the hub can/will return fewer bytes here.

632 */

633 ret = get_hub_descriptor(hdev, hub->descriptor,

634 sizeof(*hub->descriptor));

635 if (ret < 0) {

636 message = "can’t read hub descriptor";

637 goto fail;

638 } else if (hub->descriptor->bNbrPorts > USB_MAXCHILDREN) {

639 message = "hub has too many ports!";

640 ret = -ENODEV;

641 goto fail;

642 }

643

644 hdev->maxchild = hub->descriptor->bNbrPorts;

645 dev_info (hub_dev, "%d port%s detected/n", hdev->maxchild,

646 (hdev->maxchild == 1) ? "" : "s");

647

648 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);

649

650 if (wHubCharacteristics & HUB_CHAR_COMPOUND) {

651 int i;

652 char portstr [USB_MAXCHILDREN + 1];

653

654 for (i = 0; i < hdev->maxchild; i++)

655 portstr[i] = hub->descriptor->DeviceRemovable

656 [((i + 1) / 8)] & (1 << ((i + 1) % 8))

657 ? ‘F’ : ‘R’;

658 portstr[hdev->maxchild] = 0;

659 dev_dbg(hub_dev, "compound device; port removable status: %s/n", portstr);

660 } else

661 dev_dbg(hub_dev, "standalone hub/n");

662

663 switch (wHubCharacteristics & HUB_CHAR_LPSM) {

664 case 0x00:

665 dev_dbg(hub_dev, "ganged power switching/n");

666 break;

667 case 0x01:

668 dev_dbg(hub_dev, "individual port power switching/n");

669 break;

670 case 0x02:

671 case 0x03:

672 dev_dbg(hub_dev, "no power switching (usb 1.0)/n");

673 break;

674 }

675

676 switch (wHubCharacteristics & HUB_CHAR_OCPM) {

677 case 0x00:

678 dev_dbg(hub_dev, "global over-current protection/n");

679 break;

680 case 0x08:

681 dev_dbg(hub_dev, "individual port over-current protection/n");

682 break;

683 case 0x10:

684 case 0x18:

685 dev_dbg(hub_dev, "no over-current protection/n");

686 break;

687 }

688

689 spin_lock_init (&hub->tt.lock);

690 INIT_LIST_HEAD (&hub->tt.clear_list);

691 INIT_WORK (&hub->tt.kevent, hub_tt_kevent);

692 switch (hdev->descriptor.bDeviceProtocol) {

693 case 0:

694 break;

695 case 1:

696 dev_dbg(hub_dev, "Single TT/n");

697 hub->tt.hub = hdev;

698 break;

699 case 2:

700 ret = usb_set_interface(hdev, 0, 1);

701 if (ret == 0) {

702 dev_dbg(hub_dev, "TT per port/n");

703 hub->tt.multi = 1;

704 } else

705 dev_err(hub_dev, "Using single TT (err %d)/n",

706 ret);

707 hub->tt.hub = hdev;

708 break;

709 default:

710 dev_dbg(hub_dev, "Unrecognized hub protocol %d/n",

711 hdev->descriptor.bDeviceProtocol);

712 break;

713 }

714

715 /* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */

716 switch (wHubCharacteristics & HUB_CHAR_TTTT) {

717 case HUB_TTTT_8_BITS:

718 if (hdev->descriptor.bDeviceProtocol != 0) {

719 hub->tt.think_time = 666;

720 dev_dbg(hub_dev, "TT requires at most %d "

721 "FS bit times (%d ns)/n",

722 8, hub->tt.think_time);

723 }

724 break;

725 case HUB_TTTT_16_BITS:

726 hub->tt.think_time = 666 * 2;

727 dev_dbg(hub_dev, "TT requires at most %d "

728 "FS bit times (%d ns)/n",

729 16, hub->tt.think_time);

730 break;

731 case HUB_TTTT_24_BITS:

732 hub->tt.think_time = 666 * 3;

733 dev_dbg(hub_dev, "TT requires at most %d "

734 "FS bit times (%d ns)/n",

735 24, hub->tt.think_time);

736 break;

737 case HUB_TTTT_32_BITS:

738 hub->tt.think_time = 666 * 4;

739 dev_dbg(hub_dev, "TT requires at most %d "

740 "FS bit times (%d ns)/n",

741 32, hub->tt.think_time);

742 break;

743 }

744

745 /* probe() zeroes hub->indicator[] */

746 if (wHubCharacteristics & HUB_CHAR_PORTIND) {

747 hub->has_indicators = 1;

748 dev_dbg(hub_dev, "Port indicators are supported/n");

749 }

750

751 dev_dbg(hub_dev, "power on to power good time: %dms/n",

752 hub->descriptor->bPwrOn2PwrGood * 2);

753

754 /* power budgeting mostly matters with bus-powered hubs,

755 * and battery-powered root hubs (may provide just 8 mA).

756 */

757 ret = usb_get_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus);

758 if (ret < 2) {

759 message = "can’t get hub status";

760 goto fail;

761 }

762 le16_to_cpus(&hubstatus);

763 if (hdev == hdev->bus->root_hub) {

764 if (hdev->bus_mA == 0 || hdev->bus_mA >= 500)

765 hub->mA_per_port = 500;

766 else {

767 hub->mA_per_port = hdev->bus_mA;

768 hub->limited_power = 1;

769 }

770 } else if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) {

771 dev_dbg(hub_dev, "hub controller current requirement: %dmA/n",

772 hub->descriptor->bHubContrCurrent);

773 hub->limited_power = 1;

774 if (hdev->maxchild > 0) {

775 int remaining = hdev->bus_mA –

776 hub->descriptor->bHubContrCurrent;

777

778 if (remaining < hdev->maxchild * 100)

779 dev_warn(hub_dev,

780 "insufficient power available "

781 "to use all downstream ports/n");

782 hub->mA_per_port = 100; /* 7.2.1.1 */

783 }

784 } else { /* Self-powered external hub */

785 /* FIXME: What about battery-powered external hubs that

786 * provide less current per port? */

787 hub->mA_per_port = 500;

788 }

789 if (hub->mA_per_port < 500)

790 dev_dbg(hub_dev, "%umA bus power budget for each child/n",

791 hub->mA_per_port);

792

793 ret = hub_hub_status(hub, &hubstatus, &hubchange);

794 if (ret < 0) {

795 message = "can’t get hub status";

796 goto fail;

797 }

798

799 /* local power status reports aren’t always correct */

800 if (hdev->actconfig->desc.bmAttributes & USB_CONFIG_ATT_SELFPOWER)

801 dev_dbg(hub_dev, "local power source is %s/n",

802 (hubstatus & HUB_STATUS_LOCAL_POWER)

803 ? "lost (inactive)" : "good");

804

805 if ((wHubCharacteristics & HUB_CHAR_OCPM) == 0)

806 dev_dbg(hub_dev, "%sover-current condition exists/n",

807 (hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");

808

809 /* set up the interrupt endpoint

810 * We use the EP’s maxpacket size instead of (PORTS+1+7)/8

811 * bytes as USB2.0[11.12.3] says because some hubs are known

812 * to send more data (and thus cause overflow). For root hubs,

813 * maxpktsize is defined in hcd.c’s fake endpoint descriptors

814 * to be big enough for at least USB_MAXCHILDREN ports. */

815 pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress);

816 maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe));

817

818 if (maxp > sizeof(*hub->buffer))

819 maxp = sizeof(*hub->buffer);

820

821 hub->urb = usb_alloc_urb(0, GFP_KERNEL);

822 if (!hub->urb) {

823 message = "couldn’t allocate interrupt urb";

824 ret = -ENOMEM;

825 goto fail;

826 }

827

828 usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,

829 hub, endpoint->bInterval);

830 hub->urb->transfer_dma = hub->buffer_dma;

831 hub->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

832

833 /* maybe cycle the hub leds */

834 if (hub->has_indicators && blinkenlights)

835 hub->indicator [0] = INDICATOR_CYCLE;

836

837 hub_power_on(hub);

838 hub_activate(hub);

839 return 0;

840

841 fail:

842 dev_err (hub_dev, "config failed, %s (err %d)/n",

843 message, ret);

844 /* hub_disconnect() frees urb and descriptor */

845 return ret;

846 }

不过这个函数虽然长,但是逻辑非常简单,无非就是对hub进行必要的配置,然后就启动hub.这个函数的关键就是调用了另外几个经典的函数.我们一点点来看.穿越茫茫人海,寻找属于我们的那一份宁静。

Linux那些事儿之我是Hub(8)While You Were Sleeping(一) – fudan

相关文章:

你感兴趣的文章:

标签云: