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

时间:2022-11-21 15:57:22

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


看了这部片子之后,我决定做一个有目标的人,首先我的目标不是像其他男人那样庸俗,什么农妇山泉有点田,作为复旦大学高材生,我有一个更为宏伟的目标,就是一鼓作气,跟踪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.这个函数的关键就是调用了另外几个经典的函数.我们一点点来看.