天天看點

Linux那些事兒之我是UHCI(18)Root Hub的控制傳輸(二)

醫生,請把孩子取出來之後,順便給我吸吸脂.

——廣州一婦女在剖腹産手術前對醫生說.

對于控制傳輸,rh_call_control會被調用.我也特别希望能有人給這個函數吸吸脂,我們的上下文是為了擷取裝置描述符,即當初那個usb_get_device_descriptor領着我們來到了這個函數,為了完成這件事情,實際上隻需要很少的代碼,但是rh_call_control這個函數涉及了所有的Root Hub相關的控制傳輸,以至于我們除了把孩子取出來之外,還不得不順便看看其它的代碼.當然了,既然是順便,那麼我們也就不會詳細的去講解每一行.這個函數定義于drivers/usb/core/hcd.c:

    343

    344 static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)

    345 {

    346         struct usb_ctrlrequest *cmd;

    347         u16             typeReq, wValue, wIndex, wLength;

    348         u8              *ubuf = urb->transfer_buffer;

    349         u8              tbuf [sizeof (struct usb_hub_descriptor)]

    350                 __attribute__((aligned(4)));

    351         const u8        *bufp = tbuf;

    352         int             len = 0;

    353         int             patch_wakeup = 0;

    354         unsigned long   flags;

    355         int             status = 0;

    356         int             n;

    357

    358         cmd = (struct usb_ctrlrequest *) urb->setup_packet;

    359         typeReq  = (cmd->bRequestType << 8) | cmd->bRequest;

    360         wValue   = le16_to_cpu (cmd->wValue);

    361         wIndex   = le16_to_cpu (cmd->wIndex);

    362         wLength  = le16_to_cpu (cmd->wLength);

    363

    364         if (wLength > urb->transfer_buffer_length)

    365                 goto error;

    366

    367         urb->actual_length = 0;

    368         switch (typeReq) {

    369

    370        

    371

    372        

    387

    388         case DeviceRequest | USB_REQ_GET_STATUS:

    389                 tbuf [0] = (device_may_wakeup(&hcd->self.root_hub->dev)

    390                                         << USB_DEVICE_REMOTE_WAKEUP)

    391                                 | (1 << USB_DEVICE_SELF_POWERED);

    392                 tbuf [1] = 0;

    393                 len = 2;

    394                 break;

    395         case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:

    396                 if (wValue == USB_DEVICE_REMOTE_WAKEUP)

    397                         device_set_wakeup_enable(&hcd->self.root_hub->dev, 0);

    398                 else

    399                         goto error;

    400                 break;

    401         case DeviceOutRequest | USB_REQ_SET_FEATURE:

    402                 if (device_can_wakeup(&hcd->self.root_hub->dev)

    403                                 && wValue == USB_DEVICE_REMOTE_WAKEUP)

    404                         device_set_wakeup_enable(&hcd->self.root_hub->dev, 1);

    405                 else

    406                         goto error;

    407                 break;

    408         case DeviceRequest | USB_REQ_GET_CONFIGURATION:

    409                 tbuf [0] = 1;

    410                 len = 1;

    411                        

    412         case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:

    413                 break;

    414         case DeviceRequest | USB_REQ_GET_DESCRIPTOR:

    415                 switch (wValue & 0xff00) {

    416                 case USB_DT_DEVICE << 8:

    417                         if (hcd->driver->flags & HCD_USB2)

    418                                 bufp = usb2_rh_dev_descriptor;

    419                         else if (hcd->driver->flags & HCD_USB11)

    420                                 bufp = usb11_rh_dev_descriptor;

    421                         else

    422                                 goto error;

    423                         len = 18;

    424                         break;

425                 case USB_DT_CONFIG << 8:

    426                         if (hcd->driver->flags & HCD_USB2) {

    427                                 bufp = hs_rh_config_descriptor;

    428                                 len = sizeof hs_rh_config_descriptor;

    429                         } else {

    430                                 bufp = fs_rh_config_descriptor;

    431                                 len = sizeof fs_rh_config_descriptor;

    432                         }

    433                         if (device_can_wakeup(&hcd->self.root_hub->dev))

    434                                 patch_wakeup = 1;

    435                         break;

    436                 case USB_DT_STRING << 8:

    437                         n = rh_string (wValue & 0xff, hcd, ubuf, wLength);

    438                         if (n < 0)

    439                                 goto error;

    440                         urb->actual_length = n;

    441                         break;

    442                 default:

    443                         goto error;

    444                 }

    445                 break;

    446         case DeviceRequest | USB_REQ_GET_INTERFACE:

    447                 tbuf [0] = 0;

    448                 len = 1;

    449                        

    450         case DeviceOutRequest | USB_REQ_SET_INTERFACE:

    451                 break;

    452         case DeviceOutRequest | USB_REQ_SET_ADDRESS:

    453                 // wValue == urb->dev->devaddr

    454                 dev_dbg (hcd->self.controller, "root hub device address %d/n",

    455                         wValue);

    456                 break;

    457

    458        

    459

    460        

    461

    462         case EndpointRequest | USB_REQ_GET_STATUS:

    463                 // ENDPOINT_HALT flag

    464                 tbuf [0] = 0;

    465                 tbuf [1] = 0;

466                 len = 2;

    467                        

    468         case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:

    469         case EndpointOutRequest | USB_REQ_SET_FEATURE:

    470                 dev_dbg (hcd->self.controller, "no endpoint features yet/n");

    471                 break;

    472

    473        

    474

    475         default:

    476                

    477                 switch (typeReq) {

    478                 case GetHubStatus:

    479                 case GetPortStatus:

    480                         len = 4;

    481                         break;

    482                 case GetHubDescriptor:

    483                         len = sizeof (struct usb_hub_descriptor);

    484                         break;

    485                 }

    486                 status = hcd->driver->hub_control (hcd,

    487                         typeReq, wValue, wIndex,

    488                         tbuf, wLength);

    489                 break;

    490 error:

    491                

    492                 status = -EPIPE;

    493         }

    494

    495         if (status) {

    496                 len = 0;

    497                 if (status != -EPIPE) {

    498                         dev_dbg (hcd->self.controller,

    499                                 "CTRL: TypeReq=0x%x val=0x%x "

    500                                 "idx=0x%x len=%d ==> %d/n",

    501                                 typeReq, wValue, wIndex,

    502                                 wLength, status);

    503                 }

    504         }

    505         if (len) {

    506                 if (urb->transfer_buffer_length < len)

    507                         len = urb->transfer_buffer_length;

508                 urb->actual_length = len;

    509                 // always USB_DIR_IN, toward host

    510                 memcpy (ubuf, bufp, len);

    511

    512                

    513                 if (patch_wakeup &&

    514                                 len > offsetof (struct usb_config_descriptor,

    515                                                 bmAttributes))

    516                         ((struct usb_config_descriptor *)ubuf)->bmAttributes

    517                                 |= USB_CONFIG_ATT_WAKEUP;

    518         }

    519

    520        

    521         local_irq_save (flags);

    522         spin_lock (&urb->lock);

    523         if (urb->status == -EINPROGRESS)

    524                 urb->status = status;

    525         spin_unlock (&urb->lock);

    526         usb_hcd_giveback_urb (hcd, urb);

    527         local_irq_restore (flags);

    528         return 0;

    529 }

看到這樣近200行的函數,真是有一種叫天天不靈叫地地不應的感覺.不幸中的萬幸,這個函數的結構還是很清晰的.自上而下的看過來就可以了.

對于控制傳輸,首先要獲得它的setup_packet,來自urb結構體,正如我們當初在usb-storage中看到的那樣.這裡把這個setup_packet賦給cmd指針.然後把其中的各個成員都給取出來,分别放在臨時變量typeReq,wValue,wIndex,wLength中,然後來判斷這個typeReq.

如果是裝置請求并且方向是IN,而且是USB_REQ_GET_STATUS,則,設定len為2.

如果是裝置請求并且方向是OUT,而且是USB_REQ_CLEAR_FEATURE,則如何如何.

如果是裝置請求并且方向是OUT,而且是USB_REQ_SET_FEATURE,則如何如何.

如果是裝置請求并且方向是IN,而且是USB_REQ_GET_CONFIGURATION,則設定len為1.

如果是裝置請求并且方向是OUT,而且是USB_REQ_SET_CONFIGURATION,則啥也不做.

如果是裝置請求并且方向是IN,而且是USB_REQ_GET_DESCRIPTOR,則繼續判斷,wValue到底是什麼來決定究竟是要獲得什麼描述符.如果是USB_DT_DEVICE,則說明要獲得的是裝置描述符,這正是咱們的上下文,而整個這段函數中其它的内容就隻相當于順便看看.(咱們傳遞給usb_get_descriptor的第二個參數就是USB_DT_DEVICE,傳遞給usb_control_msg的第三個參數正是USB_REQ_GET_DESCRIPTOR.)如果是USB_DT_CONFIG,則說明要獲得的是配置描述符,如果是USB_DT_STRING,則說明要獲得的是字元串描述符.實際上,對于Root Hub來說,這些東西都是一樣的,咱們在drivers/usb/core/hcd.c中都預先定義好了,usb2_rh_dev_descriptor是針對usb 2.0的,而usb11_rh_dev_descriptor是針對usb 1.1的,咱們的uhci driver裡面設定了flags的HCD_USB11.

    108

    109

    110

    113

    114

    115

    116 #define KERNEL_REL      ((LINUX_VERSION_CODE >> 16) & 0x0ff)

    117 #define KERNEL_VER      ((LINUX_VERSION_CODE >> 8) & 0x0ff)

    118

    119

    120 static const u8 usb2_rh_dev_descriptor [18] = {

    121         0x12,      

    122         0x01,      

    123         0x00, 0x02,

    124

    125         0x09,      

    126         0x00,      

    127         0x01,      

    128         0x40,      

    129

    130         0x00, 0x00,

    131         0x00, 0x00,

    132         KERNEL_VER, KERNEL_REL,

    133

    134         0x03,      

    135         0x02,      

    136         0x01,      

    137         0x01       

    138 };

    139

    140

    141

    142

    143 static const u8 usb11_rh_dev_descriptor [18] = {

    144         0x12,      

    145         0x01,      

    146         0x10, 0x01,

    147

    148         0x09,      

    149         0x00,      

    150         0x00,      

    151         0x40,      

    152

    153         0x00, 0x00,

    154         0x00, 0x00,

    155         KERNEL_VER, KERNEL_REL,

    156

    157         0x03,      

    158         0x02,      

159         0x01,      

    160         0x01       

    161 };

    162

    163

    164

    165

    166

    167

    168 static const u8 fs_rh_config_descriptor [] = {

    169

    170        

    171         0x09,      

    172         0x02,      

    173         0x19, 0x00,

    174         0x01,      

    175         0x01,      

    176         0x00,      

    177         0xc0,      

    182         0x00,       

    183

    184        

    194

    195         

    196         0x09,      

    197         0x04,      

    198         0x00,      

    199         0x00,      

200         0x01,      

    201         0x09,      

    202         0x00,      

    203         0x00,      

    204         0x00,      

    205

    206        

    207         0x07,      

    208         0x05,      

    209         0x81,      

    210         0x03,      

    211         0x02, 0x00,

    212         0xff       

    213 };

    214

    215 static const u8 hs_rh_config_descriptor [] = {

    216

    217        

    218         0x09,      

    219         0x02,      

    220         0x19, 0x00,

    221         0x01,      

    222         0x01,      

    223         0x00,      

    224         0xc0,      

    229         0x00,      

    230

    231        

    241

    242        

243         0x09,      

    244         0x04,      

    245         0x00,      

    246         0x00,      

    247         0x01,      

    248         0x09,      

    249         0x00,      

    250         0x00,      

    251         0x00,      

    252

    253        

    254         0x07,      

    255         0x05,      

    256         0x81,      

    257         0x03,      

    258                    

    260         (USB_MAXCHILDREN + 1 + 7) / 8, 0x00,

    261         0x0c       

    262 };

如果是裝置請求且方向為IN,而且是USB_REQ_GET_INTERFACE,則設定len為1

如果是裝置請求且方向為OUT,而且是USB_REQ_SET_INTERFACE,則如何如何.

如果是裝置請求且方向為OUT,而且是USB_REQ_SET_ADDRESS,則如何如何.

如果是端點請求且方向為IN,而且是USB_REQ_GET_STATUS,則如何如何.

如果是端點請求且方向為OUT,而且是USB_REQ_CLEAR_FEATURE或者USB_REQ_SET_FEATURE,則如何如何.

以上這些設定,統統是和usb spec中規定的東西相比對的.

如果是Hub特定的類請求,而且是GetHubStatus或者是GetPortStatus,則設定len為4.

如果是Hub特定的類請求,而且是GetHubDescriptor,則設定len為usb_hub_descriptor結構體的大小.

最後對于Hub特定的類請求需要調用主機控制器驅動程式的hub_control函數,對于uhci_driver來說,這個指針被指派為uhci_hub_control,來自drivers/usb/host/uhci-hub.c:

    238

    239 static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,

    240                         u16 wIndex, char *buf, u16 wLength)

    241 {

    242         struct uhci_hcd *uhci = hcd_to_uhci(hcd);

    243         int status, lstatus, retval = 0, len = 0;

    244         unsigned int port = wIndex - 1;

    245         unsigned long port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;

    246         u16 wPortChange, wPortStatus;

    247         unsigned long flags;

    248

    249         if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead)

    250                 return -ETIMEDOUT;

    251

    252         spin_lock_irqsave(&uhci->lock, flags);

    253         switch (typeReq) {

    254

    255         case GetHubStatus:

    256                 *(__le32 *)buf = cpu_to_le32(0);

    257                 OK(4);         

    258         case GetPortStatus:

    259                 if (port >= uhci->rh_numports)

    260                         goto err;

    261

    262                 uhci_check_ports(uhci);

    263                 status = inw(port_addr);

    264

    265                

    269                 if (to_pci_dev(hcd->self.controller)->vendor ==

    270                                 PCI_VENDOR_ID_VIA)

    271                         status ^= USBPORTSC_OC;

    272

    273                

    274                 wPortChange = lstatus = 0;

    275                 if (status & USBPORTSC_CSC)

    276                         wPortChange |= USB_PORT_STAT_C_CONNECTION;

277                 if (status & USBPORTSC_PEC)

    278                         wPortChange |= USB_PORT_STAT_C_ENABLE;

    279                 if ((status & USBPORTSC_OCC) && !ignore_oc)

    280                         wPortChange |= USB_PORT_STAT_C_OVERCURRENT;

    281

    282                 if (test_bit(port, &uhci->port_c_suspend)) {

    283                         wPortChange |= USB_PORT_STAT_C_SUSPEND;

    284                         lstatus |= 1;

    285                 }

    286                 if (test_bit(port, &uhci->resuming_ports))

    287                         lstatus |= 4;

    288

    289                

    290                 wPortStatus = USB_PORT_STAT_POWER;

    291                 if (status & USBPORTSC_CCS)

    292                         wPortStatus |= USB_PORT_STAT_CONNECTION;

    293                 if (status & USBPORTSC_PE) {

    294                         wPortStatus |= USB_PORT_STAT_ENABLE;

    295                         if (status & SUSPEND_BITS)

    296                                 wPortStatus |= USB_PORT_STAT_SUSPEND;

    297                 }

    298                 if (status & USBPORTSC_OC)

    299                         wPortStatus |= USB_PORT_STAT_OVERCURRENT;

    300                 if (status & USBPORTSC_PR)

    301                         wPortStatus |= USB_PORT_STAT_RESET;

    302                 if (status & USBPORTSC_LSDA)

    303                         wPortStatus |= USB_PORT_STAT_LOW_SPEED;

    304

    305                 if (wPortChange)

    306                         dev_dbg(uhci_dev(uhci), "port %d portsc %04x,%02x/n",

    307                                         wIndex, status, lstatus);

    308

    309                 *(__le16 *)buf = cpu_to_le16(wPortStatus);

    310                 *(__le16 *)(buf + 2) = cpu_to_le16(wPortChange);

    311                 OK(4);

    312         case SetHubFeature:            

    313         case ClearHubFeature:

    314                 switch (wValue) {

    315                 case C_HUB_OVER_CURRENT:

    316                 case C_HUB_LOCAL_POWER:

    317                         OK(0);

    318                 default:

319                         goto err;

    320                 }

    321                 break;

    322         case SetPortFeature:

    323                 if (port >= uhci->rh_numports)

    324                         goto err;

    325

    326                 switch (wValue) {

    327                 case USB_PORT_FEAT_SUSPEND:

    328                         SET_RH_PORTSTAT(USBPORTSC_SUSP);

    329                         OK(0);

    330                 case USB_PORT_FEAT_RESET:

    331                         SET_RH_PORTSTAT(USBPORTSC_PR);

    332

    333                        

    334                         uhci_finish_suspend(uhci, port, port_addr);

    335

    336                         

    337                         uhci->ports_timeout = jiffies + msecs_to_jiffies(50);

    338                         OK(0);

    339                 case USB_PORT_FEAT_POWER:

    340                        

    341                         OK(0);

    342                 default:

    343                         goto err;

    344                 }

    345                 break;

    346         case ClearPortFeature:

    347                 if (port >= uhci->rh_numports)

    348                         goto err;

    349

    350                 switch (wValue) {

    351                 case USB_PORT_FEAT_ENABLE:

    352                         CLR_RH_PORTSTAT(USBPORTSC_PE);

    353

    354                         

    355                         uhci_finish_suspend(uhci, port, port_addr);

    356                         OK(0);

357                 case USB_PORT_FEAT_C_ENABLE:

    358                         CLR_RH_PORTSTAT(USBPORTSC_PEC);

    359                         OK(0);

    360                 case USB_PORT_FEAT_SUSPEND:

    361                         if (!(inw(port_addr) & USBPORTSC_SUSP)) {

    362

    363                                

    364                                 uhci_finish_suspend(uhci, port, port_addr);

    365                         } else if (!test_and_set_bit(port,

    366                                                 &uhci->resuming_ports)) {

    367                                 SET_RH_PORTSTAT(USBPORTSC_RD);

    368

    369                                

    373                                 if (!(inw(port_addr) & USBPORTSC_RD))

    374                                         uhci_finish_suspend(uhci, port,

    375                                                         port_addr);

    376                                 else

    377                                        

    378                                         uhci->ports_timeout = jiffies +

    379                                                 msecs_to_jiffies(20);

    380                         }

    381                         OK(0);

    382                 case USB_PORT_FEAT_C_SUSPEND:

    383                         clear_bit(port, &uhci->port_c_suspend);

    384                         OK(0);

    385                 case USB_PORT_FEAT_POWER:

    386                        

    387                         goto err;

    388                 case USB_PORT_FEAT_C_CONNECTION:

    389                         CLR_RH_PORTSTAT(USBPORTSC_CSC);

    390                         OK(0);

    391                 case USB_PORT_FEAT_C_OVER_CURRENT:

    392                         CLR_RH_PORTSTAT(USBPORTSC_OCC);

    393                         OK(0);

    394                 case USB_PORT_FEAT_C_RESET:

    395                        

    396                         OK(0);

    397                 default:

398                         goto err;

    399                 }

    400                 break;

    401         case GetHubDescriptor:

    402                 len = min_t(unsigned int, sizeof(root_hub_hub_des), wLength);

    403                 memcpy(buf, root_hub_hub_des, len);

    404                 if (len > 2)

    405                         buf[2] = uhci->rh_numports;

    406                 OK(len);

    407         default:

    408 err:

    409                 retval = -EPIPE;

    410         }

    411         spin_unlock_irqrestore(&uhci->lock, flags);

    412

    413         return retval;

    414 }

服了,徹底服了,變态的函數一個接着一個.莫非這群混蛋寫一個200行的函數就跟我寫一個20行的函數一樣随便?

249行,struct usb_hcd結構體的成員unsigned long flags,咱們當初在usb_add_hcd中調用set_bit函數設定了這麼一個flag,HCD_FLAG_HW_ACCESSIBLE,基本上這個flag在咱們的故事中是被設定了的.另外,struct uhci_hcd結構體有一個成員unsigned int dead,它如果為1就表明控制器挂了.

然後用一個switch來處理hub特定的類請求.OK居然也是一個宏,定義于drivers/usb/host/uhci-hub.c:

     78 #define OK(x)                   len = (x); break

是以如果請求是GetHubStatus,則設定len為4.

如果請求是GetPortStatus,則調用uhci_check_ports.然後讀端口寄存器.USBPORTSC_CSC表示端口連接配接有變化,USBPORTSC_PEC表示Port Enable有變化.USBPORTSC_OCC表示Over Current有變化,struct uhci_hcd的兩個成員,port_c_suspend和resuming_ports都是電源管理相關的.

但無論如何,以上所做的這些都是為了獲得兩個東西,wPortStatus和wPortChange.以此來響應GetPortStatus這個請求.

接下來,SetHubFeature和ClearHubFeature咱們沒啥好說的,不需要做什麼.

但是SetPortFeature就有事情要做了.wValue表明具體是什麼特征.

SET_RH_PORTSTAT這個宏就是專門用于設定Root Hub的端口特征的.

     80 #define CLR_RH_PORTSTAT(x) /

     81         status = inw(port_addr); /

     82         status &= ~(RWC_BITS|WZ_BITS); /

     83         status &= ~(x); /

     84         status |= RWC_BITS & (x); /

     85         outw(status, port_addr)

     86

     87 #define SET_RH_PORTSTAT(x) /

     88         status = inw(port_addr); /

     89         status |= (x); /

     90         status &= ~(RWC_BITS|WZ_BITS); /

     91         outw(status, port_addr)

對于USB_PORT_FEAT_RESET,還需要調用uhci_finish_suspend.

如果是USB_PORT_FEAT_POWER,則什麼也不做,因為UHCI不吃這一套.

如果請求是ClearPortFeature,基本上也是一樣的做法.除了調用的宏變成了CLR_RH_PORTSTAT.

如果請求是GetHubDescriptor,那就滿足它呗.root_hub_hub_des是早就在drivers/usb/host/uhci-hub.c中定義好的:

     15 static __u8 root_hub_hub_des[] =

     16 {

     17         0x09,                  

     18         0x29,                  

     19         0x02,                  

     20         0x0a,                  

     21         0x00,                  

     22         0x01,                  

     23         0x00,                  

     24         0x00,                  

     25         0xff                   

     26 };

回到rh_call_control,switch結束了,下面是判斷status和len.

然後調用usb_hcd_giveback_urb().來自drivers/usb/core/hcd.c:

   1373

   1385 void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)

   1386 {

   1387         int at_root_hub;

   1388

   1389         at_root_hub = (urb->dev == hcd->self.root_hub);

   1390         urb_unlink (urb);

   1391

   1392        

   1394         if (hcd->self.uses_dma && !at_root_hub) {

   1395                 if (usb_pipecontrol (urb->pipe)

   1396                         && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))

   1397                         dma_unmap_single (hcd->self.controller, urb->setup_dma,

   1398                                         sizeof (struct usb_ctrlrequest),

   1399                                         DMA_TO_DEVICE);

   1400                 if (urb->transfer_buffer_length != 0

   1401                         && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))

   1402                         dma_unmap_single (hcd->self.controller,

   1403                                         urb->transfer_dma,

   1404                                         urb->transfer_buffer_length,

   1405                                         usb_pipein (urb->pipe)

   1406                                             ? DMA_FROM_DEVICE

   1407                                             : DMA_TO_DEVICE);

   1408         }

   1409

   1410         usbmon_urb_complete (&hcd->self, urb);

   1411        

   1412         urb->complete (urb);

   1413         atomic_dec (&urb->use_count);

   1414         if (unlikely (urb->reject))

   1415                 wake_up (&usb_kill_urb_queue);

   1416         usb_put_urb (urb);

   1417 }

   1418 EXPORT_SYMBOL (usb_hcd_giveback_urb);

這裡最重要最有意義的一行當然就是1412行,調用urb的complete函數,這正是我們在usb-storage裡期待的那個函數.從此rh_call_control函數也該傳回了,以後裝置驅動又獲得了控制權.事實上令人欣喜的是對于Root Hub,1394行開始的這一段if是不會被執行的,因為at_root_hub顯然是為真.不過就算這段要執行也沒什麼可怕的,無非就是把之前為這個urb建立的dma映射給取消掉.而另一方面,對于Root Hub來說,complete函數基本上是什麼也不做,隻不過是讓咱們再次回到usb_start_wait_urb去,而控制傳輸需要的資料也已經copy到了urb->transfer_buffer中去了. 至此,Root Hub的控制傳輸就算結束了,即我們的usb_get_device_descriptor函數取得了空前絕後的圓滿成功.

繼續閱讀