Import Usb/UsbBusDxe and Usb/UsbMassStorageDxe into MdeModulePkg.
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Bus / Usb / UsbBusDxe / usbbus.c
1 /** @file\r
2 \r
3 Copyright (c) 2004 - 2007, Intel Corporation\r
4 All rights reserved. This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution.  The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php\r
8 \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11 \r
12   Module Name:\r
13 \r
14     UsbBus.c\r
15 \r
16   Abstract:\r
17 \r
18     Usb Bus Driver Binding and Bus IO Protocol\r
19 \r
20   Revision History\r
21 \r
22 \r
23 **/\r
24 \r
25 #include "UsbBus.h"\r
26 \r
27 //\r
28 // USB_BUS_PROTOCOL is only used to locate USB_BUS\r
29 //\r
30 EFI_GUID  mUsbBusProtocolGuid = EFI_USB_BUS_PROTOCOL_GUID;\r
31 \r
32 \r
33 /**\r
34   USB_IO function to execute a control transfer. This\r
35   function will execute the USB transfer. If transfer\r
36   successes, it will sync the internal state of USB bus\r
37   with device state.\r
38 \r
39   @param  This                   The USB_IO instance\r
40   @param  Request                The control transfer request\r
41   @param  Direction              Direction for data stage\r
42   @param  Timeout                The time to wait before timeout\r
43   @param  Data                   The buffer holding the data\r
44   @param  DataLength             Then length of the data\r
45   @param  UsbStatus              USB result\r
46 \r
47   @retval EFI_INVALID_PARAMETER  The parameters are invalid\r
48   @retval EFI_SUCCESS            The control transfer succeded.\r
49   @retval Others                 Failed to execute the transfer\r
50 \r
51 **/\r
52 STATIC\r
53 EFI_STATUS\r
54 EFIAPI\r
55 UsbIoControlTransfer (\r
56   IN  EFI_USB_IO_PROTOCOL     *This,\r
57   IN  EFI_USB_DEVICE_REQUEST  *Request,\r
58   IN  EFI_USB_DATA_DIRECTION  Direction,\r
59   IN  UINT32                  Timeout,\r
60   IN  OUT VOID                *Data,      OPTIONAL\r
61   IN  UINTN                   DataLength, OPTIONAL\r
62   OUT UINT32                  *UsbStatus\r
63   )\r
64 {\r
65   USB_DEVICE              *Dev;\r
66   USB_INTERFACE           *UsbIf;\r
67   USB_ENDPOINT_DESC       *EpDesc;\r
68   EFI_TPL                 OldTpl;\r
69   EFI_STATUS              Status;\r
70 \r
71   if (UsbStatus == NULL) {\r
72     return EFI_INVALID_PARAMETER;\r
73   }\r
74 \r
75   OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
76 \r
77   UsbIf  = USB_INTERFACE_FROM_USBIO (This);\r
78   Dev    = UsbIf->Device;\r
79 \r
80   Status = UsbHcControlTransfer (\r
81              Dev->Bus,\r
82              Dev->Address,\r
83              Dev->Speed,\r
84              Dev->MaxPacket0,\r
85              Request,\r
86              Direction,\r
87              Data,\r
88              &DataLength,\r
89              (UINTN) Timeout,\r
90              &Dev->Translator,\r
91              UsbStatus\r
92              );\r
93 \r
94   if (EFI_ERROR (Status) || (*UsbStatus != EFI_USB_NOERROR)) {\r
95     //\r
96     // Clear TT buffer when CTRL/BULK split transaction failes\r
97     // Clear the TRANSLATOR TT buffer, not parent's buffer\r
98     //\r
99     if (Dev->Translator.TranslatorHubAddress != 0) {\r
100       UsbHubCtrlClearTTBuffer (\r
101         Dev->Bus->Devices[Dev->Translator.TranslatorHubAddress],\r
102         Dev->Translator.TranslatorPortNumber,\r
103         Dev->Address,\r
104         0,\r
105         USB_ENDPOINT_CONTROL\r
106         );\r
107     }\r
108 \r
109     goto ON_EXIT;\r
110   }\r
111 \r
112   //\r
113   // Some control transfer will change the device's internal\r
114   // status, such as Set_Configuration and Set_Interface.\r
115   // We must synchronize the bus driver's status with that in\r
116   // device. We ignore the Set_Descriptor request because it's\r
117   // hardly used by any device, especially in pre-boot environment\r
118   //\r
119 \r
120   //\r
121   // Reset the endpoint toggle when endpoint stall is cleared\r
122   //\r
123   if ((Request->Request     == USB_REQ_CLEAR_FEATURE) &&\r
124       (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD,\r
125                                                  USB_TARGET_ENDPOINT)) &&\r
126       (Request->Value       == USB_FEATURE_ENDPOINT_HALT)) {\r
127 \r
128     EpDesc = UsbGetEndpointDesc (UsbIf, (UINT8) Request->Index);\r
129 \r
130     if (EpDesc != NULL) {\r
131       EpDesc->Toggle = 0;\r
132     }\r
133   }\r
134 \r
135   //\r
136   // Select a new configuration. This is a dangerous action. Upper driver\r
137   // should stop use its current UsbIo after calling this driver. The old\r
138   // UsbIo will be uninstalled and new UsbIo be installed. We can't use\r
139   // ReinstallProtocol since interfaces in different configuration may be\r
140   // completely irrellvant.\r
141   //\r
142   if ((Request->Request == USB_REQ_SET_CONFIG) &&\r
143       (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD,\r
144                                                  USB_TARGET_DEVICE))) {\r
145     //\r
146     // Don't re-create the USB interfaces if configuration isn't changed.\r
147     //\r
148     if ((Dev->ActiveConfig != NULL) &&\r
149         (Request->Value == Dev->ActiveConfig->Desc.ConfigurationValue)) {\r
150 \r
151       goto ON_EXIT;\r
152     }\r
153 \r
154     USB_DEBUG (("UsbIoControlTransfer: configure changed!!! Do NOT use old UsbIo!!!\n"));\r
155 \r
156     if (Dev->ActiveConfig != NULL) {\r
157       UsbRemoveConfig (Dev);\r
158     }\r
159 \r
160     if (Request->Value != 0) {\r
161       Status = UsbSelectConfig (Dev, (UINT8) Request->Value);\r
162     }\r
163 \r
164     //\r
165     // Exit now, Old USB_IO is invalid now\r
166     //\r
167     goto ON_EXIT;\r
168   }\r
169 \r
170   //\r
171   // A new alternative setting is selected for the interface.\r
172   // No need to reinstall UsbIo in this case because only\r
173   // underlying communication endpoints are changed. Functionality\r
174   // should remains the same.\r
175   //\r
176   if ((Request->Request     == USB_REQ_SET_INTERFACE) &&\r
177       (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD,\r
178                                                  USB_TARGET_INTERFACE)) &&\r
179       (Request->Index       == UsbIf->IfSetting->Desc.InterfaceNumber)) {\r
180 \r
181     Status = UsbSelectSetting (UsbIf->IfDesc, (UINT8) Request->Value);\r
182 \r
183     if (!EFI_ERROR (Status)) {\r
184       UsbIf->IfSetting = UsbIf->IfDesc->Settings[UsbIf->IfDesc->ActiveIndex];\r
185     }\r
186   }\r
187 \r
188 ON_EXIT:\r
189   gBS->RestoreTPL (OldTpl);\r
190   return Status;\r
191 }\r
192 \r
193 \r
194 /**\r
195   Execute a bulk transfer to the device endpoint\r
196 \r
197   @param  This                   The USB IO instance\r
198   @param  Endpoint               The device endpoint\r
199   @param  Data                   The data to transfer\r
200   @param  DataLength             The length of the data to transfer\r
201   @param  Timeout                Time to wait before timeout\r
202   @param  UsbStatus              The result of USB transfer\r
203 \r
204   @retval EFI_SUCCESS            The bulk transfer is OK\r
205   @retval EFI_INVALID_PARAMETER  Some parameters are invalid\r
206   @retval Others                 Failed to execute transfer, reason returned in\r
207                                  UsbStatus\r
208 \r
209 **/\r
210 STATIC\r
211 EFI_STATUS\r
212 EFIAPI\r
213 UsbIoBulkTransfer (\r
214   IN  EFI_USB_IO_PROTOCOL *This,\r
215   IN  UINT8               Endpoint,\r
216   IN  OUT VOID            *Data,\r
217   IN  OUT UINTN           *DataLength,\r
218   IN  UINTN               Timeout,\r
219   OUT UINT32              *UsbStatus\r
220   )\r
221 {\r
222   USB_DEVICE              *Dev;\r
223   USB_INTERFACE           *UsbIf;\r
224   USB_ENDPOINT_DESC       *EpDesc;\r
225   UINT8                   BufNum;\r
226   UINT8                   Toggle;\r
227   EFI_TPL                 OldTpl;\r
228   EFI_STATUS              Status;\r
229 \r
230   if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR(Endpoint) > 15) ||\r
231       (UsbStatus == NULL)) {\r
232 \r
233     return EFI_INVALID_PARAMETER;\r
234   }\r
235 \r
236   OldTpl  = gBS->RaiseTPL (USB_BUS_TPL);\r
237 \r
238   UsbIf   = USB_INTERFACE_FROM_USBIO (This);\r
239   Dev     = UsbIf->Device;\r
240 \r
241   EpDesc  = UsbGetEndpointDesc (UsbIf, Endpoint);\r
242 \r
243   if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_BULK)) {\r
244     Status = EFI_INVALID_PARAMETER;\r
245     goto ON_EXIT;\r
246   }\r
247 \r
248   BufNum  = 1;\r
249   Toggle  = EpDesc->Toggle;\r
250   Status  = UsbHcBulkTransfer (\r
251               Dev->Bus,\r
252               Dev->Address,\r
253               Endpoint,\r
254               Dev->Speed,\r
255               EpDesc->Desc.MaxPacketSize,\r
256               BufNum,\r
257               &Data,\r
258               DataLength,\r
259               &Toggle,\r
260               Timeout,\r
261               &Dev->Translator,\r
262               UsbStatus\r
263               );\r
264 \r
265   EpDesc->Toggle = Toggle;\r
266 \r
267   if (EFI_ERROR (Status) || (*UsbStatus != EFI_USB_NOERROR)) {\r
268     //\r
269     // Clear TT buffer when CTRL/BULK split transaction failes.\r
270     // Clear the TRANSLATOR TT buffer, not parent's buffer\r
271     //\r
272     if (Dev->Translator.TranslatorHubAddress != 0) {\r
273       UsbHubCtrlClearTTBuffer (\r
274         Dev->Bus->Devices[Dev->Translator.TranslatorHubAddress],\r
275         Dev->Translator.TranslatorPortNumber,\r
276         Dev->Address,\r
277         0,\r
278         USB_ENDPOINT_BULK\r
279         );\r
280     }\r
281   }\r
282 \r
283 ON_EXIT:\r
284   gBS->RestoreTPL (OldTpl);\r
285   return Status;\r
286 }\r
287 \r
288 \r
289 /**\r
290   Execute a synchronous interrupt transfer\r
291 \r
292   @param  This                   The USB IO instance\r
293   @param  Endpoint               The device endpoint\r
294   @param  Data                   The data to transfer\r
295   @param  DataLength             The length of the data to transfer\r
296   @param  Timeout                Time to wait before timeout\r
297   @param  UsbStatus              The result of USB transfer\r
298 \r
299   @retval EFI_SUCCESS            The synchronous interrupt transfer is OK\r
300   @retval EFI_INVALID_PARAMETER  Some parameters are invalid\r
301   @retval Others                 Failed to execute transfer, reason returned in\r
302                                  UsbStatus\r
303 \r
304 **/\r
305 STATIC\r
306 EFI_STATUS\r
307 EFIAPI\r
308 UsbIoSyncInterruptTransfer (\r
309   IN  EFI_USB_IO_PROTOCOL *This,\r
310   IN  UINT8               Endpoint,\r
311   IN  OUT VOID            *Data,\r
312   IN  OUT UINTN           *DataLength,\r
313   IN  UINTN               Timeout,\r
314   OUT UINT32              *UsbStatus\r
315   )\r
316 {\r
317   USB_DEVICE              *Dev;\r
318   USB_INTERFACE           *UsbIf;\r
319   USB_ENDPOINT_DESC       *EpDesc;\r
320   EFI_TPL                 OldTpl;\r
321   UINT8                   Toggle;\r
322   EFI_STATUS              Status;\r
323 \r
324   if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR(Endpoint) > 15) ||\r
325       (UsbStatus == NULL)) {\r
326 \r
327     return EFI_INVALID_PARAMETER;\r
328   }\r
329 \r
330   OldTpl  = gBS->RaiseTPL (USB_BUS_TPL);\r
331 \r
332   UsbIf   = USB_INTERFACE_FROM_USBIO (This);\r
333   Dev     = UsbIf->Device;\r
334 \r
335   EpDesc  = UsbGetEndpointDesc (UsbIf, Endpoint);\r
336 \r
337   if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_INTERRUPT)) {\r
338     Status = EFI_INVALID_PARAMETER;\r
339     goto ON_EXIT;\r
340   }\r
341 \r
342   Toggle = EpDesc->Toggle;\r
343   Status = UsbHcSyncInterruptTransfer (\r
344              Dev->Bus,\r
345              Dev->Address,\r
346              Endpoint,\r
347              Dev->Speed,\r
348              EpDesc->Desc.MaxPacketSize,\r
349              Data,\r
350              DataLength,\r
351              &Toggle,\r
352              Timeout,\r
353              &Dev->Translator,\r
354              UsbStatus\r
355              );\r
356 \r
357   EpDesc->Toggle = Toggle;\r
358 \r
359 ON_EXIT:\r
360   gBS->RestoreTPL (OldTpl);\r
361   return Status;\r
362 }\r
363 \r
364 \r
365 /**\r
366   Queue a new asynchronous interrupt transfer, or remove the old\r
367   request if (IsNewTransfer == FALSE)\r
368 \r
369   @param  This                   The USB_IO instance\r
370   @param  Endpoint               The device endpoint\r
371   @param  IsNewTransfer          Whether this is a new request, if it's old, remove\r
372                                  the request\r
373   @param  PollInterval           The interval to poll the transfer result, (in ms)\r
374   @param  DataLength             The length of perodic data transfer\r
375   @param  Callback               The function to call periodicaly when transfer is\r
376                                  ready\r
377   @param  Context                The context to the callback\r
378 \r
379   @retval EFI_SUCCESS            New transfer is queued or old request is removed\r
380   @retval EFI_INVALID_PARAMETER  Some parameters are invalid\r
381   @retval Others                 Failed to queue the new request or remove the old\r
382                                  request\r
383 \r
384 **/\r
385 STATIC\r
386 EFI_STATUS\r
387 EFIAPI\r
388 UsbIoAsyncInterruptTransfer (\r
389   IN EFI_USB_IO_PROTOCOL              *This,\r
390   IN UINT8                            Endpoint,\r
391   IN BOOLEAN                          IsNewTransfer,\r
392   IN UINTN                            PollInterval,       OPTIONAL\r
393   IN UINTN                            DataLength,         OPTIONAL\r
394   IN EFI_ASYNC_USB_TRANSFER_CALLBACK  Callback,           OPTIONAL\r
395   IN VOID                             *Context            OPTIONAL\r
396   )\r
397 {\r
398   USB_DEVICE              *Dev;\r
399   USB_INTERFACE           *UsbIf;\r
400   USB_ENDPOINT_DESC       *EpDesc;\r
401   EFI_TPL                 OldTpl;\r
402   UINT8                   Toggle;\r
403   EFI_STATUS              Status;\r
404 \r
405   if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR (Endpoint) > 15)) {\r
406     return EFI_INVALID_PARAMETER;\r
407   }\r
408 \r
409   OldTpl  = gBS->RaiseTPL (USB_BUS_TPL);\r
410   UsbIf   = USB_INTERFACE_FROM_USBIO (This);\r
411   Dev     = UsbIf->Device;\r
412 \r
413   EpDesc  = UsbGetEndpointDesc (UsbIf, Endpoint);\r
414 \r
415   if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_INTERRUPT)) {\r
416     Status = EFI_INVALID_PARAMETER;\r
417     goto ON_EXIT;\r
418   }\r
419 \r
420   Toggle  = EpDesc->Toggle;\r
421   Status  = UsbHcAsyncInterruptTransfer (\r
422               Dev->Bus,\r
423               Dev->Address,\r
424               Endpoint,\r
425               Dev->Speed,\r
426               EpDesc->Desc.MaxPacketSize,\r
427               IsNewTransfer,\r
428               &Toggle,\r
429               PollInterval,\r
430               DataLength,\r
431               &Dev->Translator,\r
432               Callback,\r
433               Context\r
434               );\r
435 \r
436   EpDesc->Toggle = Toggle;\r
437 \r
438 ON_EXIT:\r
439   gBS->RestoreTPL (OldTpl);\r
440   return Status;\r
441 }\r
442 \r
443 \r
444 /**\r
445   Execute a synchronous isochronous transfer\r
446 \r
447   @param  This                   The USB IO instance\r
448   @param  DeviceEndpoint         The device endpoint\r
449   @param  Data                   The data to transfer\r
450   @param  DataLength             The length of the data to transfer\r
451   @param  UsbStatus              The result of USB transfer\r
452 \r
453   @retval EFI_UNSUPPORTED        Currently isochronous transfer isn't supported\r
454 \r
455 **/\r
456 STATIC\r
457 EFI_STATUS\r
458 EFIAPI\r
459 UsbIoIsochronousTransfer (\r
460   IN  EFI_USB_IO_PROTOCOL *This,\r
461   IN  UINT8               DeviceEndpoint,\r
462   IN  OUT VOID            *Data,\r
463   IN  UINTN               DataLength,\r
464   OUT UINT32              *Status\r
465   )\r
466 {\r
467   return EFI_UNSUPPORTED;\r
468 }\r
469 \r
470 \r
471 /**\r
472   Queue an asynchronous isochronous transfer\r
473 \r
474   @param  This                   The USB_IO instance\r
475   @param  DeviceEndpoint         The device endpoint\r
476   @param  DataLength             The length of perodic data transfer\r
477   @param  IsochronousCallBack    The function to call periodicaly when transfer is\r
478                                  ready\r
479   @param  Context                The context to the callback\r
480 \r
481   @retval EFI_UNSUPPORTED        Currently isochronous transfer isn't supported\r
482 \r
483 **/\r
484 STATIC\r
485 EFI_STATUS\r
486 EFIAPI\r
487 UsbIoAsyncIsochronousTransfer (\r
488   IN EFI_USB_IO_PROTOCOL              *This,\r
489   IN UINT8                            DeviceEndpoint,\r
490   IN OUT VOID                         *Data,\r
491   IN UINTN                            DataLength,\r
492   IN EFI_ASYNC_USB_TRANSFER_CALLBACK  IsochronousCallBack,\r
493   IN VOID                             *Context              OPTIONAL\r
494   )\r
495 {\r
496   return EFI_UNSUPPORTED;\r
497 }\r
498 \r
499 \r
500 /**\r
501   Retrieve the device descriptor of the device\r
502 \r
503   @param  This                   The USB IO instance\r
504   @param  Descriptor             The variable to receive the device descriptor\r
505 \r
506   @retval EFI_SUCCESS            The device descriptor is returned\r
507   @retval EFI_INVALID_PARAMETER  The parameter is invalid\r
508 \r
509 **/\r
510 STATIC\r
511 EFI_STATUS\r
512 EFIAPI\r
513 UsbIoGetDeviceDescriptor (\r
514   IN  EFI_USB_IO_PROTOCOL       *This,\r
515   OUT EFI_USB_DEVICE_DESCRIPTOR *Descriptor\r
516   )\r
517 {\r
518   USB_DEVICE              *Dev;\r
519   USB_INTERFACE           *UsbIf;\r
520   EFI_TPL                 OldTpl;\r
521 \r
522   if (Descriptor == NULL) {\r
523     return EFI_INVALID_PARAMETER;\r
524   }\r
525 \r
526   OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
527 \r
528   UsbIf  = USB_INTERFACE_FROM_USBIO (This);\r
529   Dev    = UsbIf->Device;\r
530 \r
531   CopyMem (Descriptor, &Dev->DevDesc->Desc, sizeof (EFI_USB_DEVICE_DESCRIPTOR));\r
532 \r
533   gBS->RestoreTPL (OldTpl);\r
534   return EFI_SUCCESS;\r
535 }\r
536 \r
537 \r
538 /**\r
539   Return the configuration descriptor of the current active configuration\r
540 \r
541   @param  This                   The USB IO instance\r
542   @param  Descriptor             The USB configuration descriptor\r
543 \r
544   @retval EFI_SUCCESS            The active configuration descriptor is returned\r
545   @retval EFI_INVALID_PARAMETER  Some parameter is invalid\r
546   @retval EFI_NOT_FOUND          Currently no active configuration is selected.\r
547 \r
548 **/\r
549 STATIC\r
550 EFI_STATUS\r
551 EFIAPI\r
552 UsbIoGetActiveConfigDescriptor (\r
553   IN  EFI_USB_IO_PROTOCOL       *This,\r
554   OUT EFI_USB_CONFIG_DESCRIPTOR *Descriptor\r
555   )\r
556 {\r
557   USB_DEVICE              *Dev;\r
558   USB_INTERFACE           *UsbIf;\r
559   EFI_STATUS              Status;\r
560   EFI_TPL                 OldTpl;\r
561 \r
562   if (Descriptor == NULL) {\r
563     return EFI_INVALID_PARAMETER;\r
564   }\r
565 \r
566   Status = EFI_SUCCESS;\r
567   OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
568 \r
569   UsbIf  = USB_INTERFACE_FROM_USBIO (This);\r
570   Dev    = UsbIf->Device;\r
571 \r
572   if (Dev->ActiveConfig == NULL) {\r
573     Status = EFI_NOT_FOUND;\r
574     goto ON_EXIT;\r
575   }\r
576 \r
577   CopyMem (Descriptor, &(Dev->ActiveConfig->Desc), sizeof (EFI_USB_CONFIG_DESCRIPTOR));\r
578 \r
579 ON_EXIT:\r
580   gBS->RestoreTPL (OldTpl);\r
581   return Status;\r
582 }\r
583 \r
584 \r
585 /**\r
586   Retrieve the active interface setting descriptor for this USB IO instance\r
587 \r
588   @param  This                   The USB IO instance\r
589   @param  Descriptor             The variable to receive active interface setting\r
590 \r
591   @retval EFI_SUCCESS            The active interface setting is returned\r
592   @retval EFI_INVALID_PARAMETER  Some parameter is invalid\r
593 \r
594 **/\r
595 STATIC\r
596 EFI_STATUS\r
597 EFIAPI\r
598 UsbIoGetInterfaceDescriptor (\r
599   IN  EFI_USB_IO_PROTOCOL           *This,\r
600   OUT EFI_USB_INTERFACE_DESCRIPTOR  *Descriptor\r
601   )\r
602 {\r
603   USB_INTERFACE           *UsbIf;\r
604   EFI_TPL                 OldTpl;\r
605 \r
606   if (Descriptor == NULL) {\r
607     return EFI_INVALID_PARAMETER;\r
608   }\r
609 \r
610   OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
611 \r
612   UsbIf  = USB_INTERFACE_FROM_USBIO (This);\r
613   CopyMem (Descriptor, &(UsbIf->IfSetting->Desc), sizeof (EFI_USB_INTERFACE_DESCRIPTOR));\r
614 \r
615   gBS->RestoreTPL (OldTpl);\r
616   return EFI_SUCCESS;\r
617 }\r
618 \r
619 \r
620 /**\r
621   Retrieve the endpoint descriptor from this interface setting\r
622 \r
623   @param  This                   The USB IO instance\r
624   @param  Index                  The index (start from zero) of the endpoint to\r
625                                  retrieve\r
626   @param  Descriptor             The variable to receive the descriptor\r
627 \r
628   @retval EFI_SUCCESS            The endpoint descriptor is returned\r
629   @retval EFI_INVALID_PARAMETER  Some parameter is invalid\r
630 \r
631 **/\r
632 STATIC\r
633 EFI_STATUS\r
634 EFIAPI\r
635 UsbIoGetEndpointDescriptor (\r
636   IN  EFI_USB_IO_PROTOCOL         *This,\r
637   IN  UINT8                       Index,\r
638   OUT EFI_USB_ENDPOINT_DESCRIPTOR *Descriptor\r
639   )\r
640 {\r
641   USB_INTERFACE           *UsbIf;\r
642   EFI_TPL                 OldTpl;\r
643 \r
644   OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
645 \r
646   UsbIf  = USB_INTERFACE_FROM_USBIO (This);\r
647 \r
648   if ((Descriptor == NULL) || (Index >= UsbIf->IfSetting->Desc.NumEndpoints)) {\r
649     gBS->RestoreTPL (OldTpl);\r
650     return EFI_INVALID_PARAMETER;\r
651   }\r
652 \r
653   CopyMem (\r
654     Descriptor,\r
655     &(UsbIf->IfSetting->Endpoints[Index]->Desc),\r
656     sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)\r
657     );\r
658 \r
659   gBS->RestoreTPL (OldTpl);\r
660   return EFI_SUCCESS;\r
661 }\r
662 \r
663 \r
664 /**\r
665   Retrieve the supported language ID table from the device\r
666 \r
667   @param  This                   The USB IO instance\r
668   @param  LangIDTable            The table to return the language IDs\r
669   @param  TableSize              The number of supported languanges\r
670 \r
671   @retval EFI_SUCCESS            The language ID is return\r
672 \r
673 **/\r
674 STATIC\r
675 EFI_STATUS\r
676 EFIAPI\r
677 UsbIoGetSupportedLanguages (\r
678   IN  EFI_USB_IO_PROTOCOL *This,\r
679   OUT UINT16              **LangIDTable,\r
680   OUT UINT16              *TableSize\r
681   )\r
682 {\r
683   USB_DEVICE              *Dev;\r
684   USB_INTERFACE           *UsbIf;\r
685   EFI_TPL                 OldTpl;\r
686 \r
687   OldTpl        = gBS->RaiseTPL (USB_BUS_TPL);\r
688 \r
689   UsbIf         = USB_INTERFACE_FROM_USBIO (This);\r
690   Dev           = UsbIf->Device;\r
691 \r
692   *LangIDTable  = Dev->LangId;\r
693   *TableSize    = Dev->TotalLangId;\r
694 \r
695   gBS->RestoreTPL (OldTpl);\r
696   return EFI_SUCCESS;\r
697 }\r
698 \r
699 \r
700 /**\r
701   Retrieve an indexed string in the language of LangID\r
702 \r
703   @param  This                   The USB IO instance\r
704   @param  LangID                 The language ID of the string to retrieve\r
705   @param  StringIndex            The index of the string\r
706   @param  String                 The variable to receive the string\r
707 \r
708   @retval EFI_SUCCESS            The string is returned\r
709   @retval EFI_NOT_FOUND          No such string existed\r
710 \r
711 **/\r
712 STATIC\r
713 EFI_STATUS\r
714 EFIAPI\r
715 UsbIoGetStringDescriptor (\r
716   IN  EFI_USB_IO_PROTOCOL   *This,\r
717   IN  UINT16                LangID,\r
718   IN  UINT8                 StringIndex,\r
719   OUT CHAR16                **String\r
720   )\r
721 {\r
722   USB_DEVICE                *Dev;\r
723   USB_INTERFACE             *UsbIf;\r
724   EFI_USB_STRING_DESCRIPTOR *StrDesc;\r
725   EFI_TPL                   OldTpl;\r
726   UINT8                     *Buf;\r
727   UINT8                     Index;\r
728   EFI_STATUS                Status;\r
729 \r
730   if ((StringIndex == 0) || (LangID == 0)) {\r
731     return EFI_NOT_FOUND;\r
732   }\r
733 \r
734   OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
735 \r
736   UsbIf  = USB_INTERFACE_FROM_USBIO (This);\r
737   Dev    = UsbIf->Device;\r
738 \r
739   //\r
740   // Check whether language ID is supported\r
741   //\r
742   Status = EFI_NOT_FOUND;\r
743 \r
744   for (Index = 0; Index < Dev->TotalLangId; Index++) {\r
745     if (Dev->LangId[Index] == LangID) {\r
746       break;\r
747     }\r
748   }\r
749 \r
750   if (Index == Dev->TotalLangId) {\r
751     goto ON_EXIT;\r
752   }\r
753 \r
754   //\r
755   // Retrieve the string descriptor then allocate a buffer\r
756   // to hold the string itself.\r
757   //\r
758   StrDesc = UsbGetOneString (Dev, StringIndex, LangID);\r
759 \r
760   if (StrDesc == NULL) {\r
761     goto ON_EXIT;\r
762   }\r
763 \r
764   if (StrDesc->Length <= 2) {\r
765     goto FREE_STR;\r
766   }\r
767 \r
768   Buf = AllocateZeroPool (StrDesc->Length);\r
769 \r
770   if (Buf == NULL) {\r
771     Status = EFI_OUT_OF_RESOURCES;\r
772     goto FREE_STR;\r
773   }\r
774 \r
775   CopyMem (Buf, StrDesc->String, StrDesc->Length - 2);\r
776   *String = (CHAR16 *) Buf;\r
777   Status  = EFI_SUCCESS;\r
778 \r
779 FREE_STR:\r
780   gBS->FreePool (StrDesc);\r
781 \r
782 ON_EXIT:\r
783   gBS->RestoreTPL (OldTpl);\r
784   return Status;\r
785 }\r
786 \r
787 \r
788 /**\r
789   Reset the device, then if that succeeds, reconfigure the\r
790   device with its address and current active configuration.\r
791 \r
792   @param  This                   The USB IO instance\r
793 \r
794   @retval EFI_SUCCESS            The device is reset and configured\r
795   @retval Others                 Failed to reset the device\r
796 \r
797 **/\r
798 EFI_STATUS\r
799 EFIAPI\r
800 UsbIoPortReset (\r
801   IN EFI_USB_IO_PROTOCOL  *This\r
802   )\r
803 {\r
804   USB_INTERFACE           *UsbIf;\r
805   USB_INTERFACE           *HubIf;\r
806   USB_DEVICE              *Dev;\r
807   UINT8                   Address;\r
808   EFI_TPL                 OldTpl;\r
809   EFI_STATUS              Status;\r
810 \r
811   OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
812 \r
813   UsbIf  = USB_INTERFACE_FROM_USBIO (This);\r
814   Dev    = UsbIf->Device;\r
815 \r
816   HubIf  = Dev->ParentIf;\r
817   Status = HubIf->HubApi->ResetPort (HubIf, Dev->ParentPort);\r
818 \r
819   if (EFI_ERROR (Status)) {\r
820     USB_ERROR (("UsbIoPortReset: failed to reset hub port %d@hub  %d, %r \n",\r
821                 Dev->ParentPort, Dev->ParentAddr, Status));\r
822 \r
823     goto ON_EXIT;\r
824   }\r
825 \r
826   //\r
827   // Reset the device to its current address. The device now has a\r
828   // address of ZERO, so need to set Dev->Address to zero first for\r
829   // host to communicate with the device\r
830   //\r
831   Address       = Dev->Address;\r
832   Dev->Address  = 0;\r
833   Status        = UsbSetAddress (Dev, Address);\r
834 \r
835   if (EFI_ERROR (Status)) {\r
836     USB_ERROR (("UsbIoPortReset: failed to set address for device %d - %r\n",\r
837                 Address, Status));\r
838 \r
839     goto ON_EXIT;\r
840   }\r
841 \r
842   Dev->Address  = Address;\r
843 \r
844   //\r
845   // Reset the current active configure, after this device\r
846   // is in CONFIGURED state.\r
847   //\r
848   if (Dev->ActiveConfig != NULL) {\r
849     Status = UsbSetConfig (Dev, Dev->ActiveConfig->Desc.ConfigurationValue);\r
850 \r
851     if (EFI_ERROR (Status)) {\r
852       USB_ERROR (("UsbIoPortReset: failed to set configure for device %d - %r\n",\r
853                   Address, Status));\r
854     }\r
855   }\r
856 \r
857 ON_EXIT:\r
858   gBS->RestoreTPL (OldTpl);\r
859   return Status;\r
860 }\r
861 \r
862 EFI_USB_IO_PROTOCOL mUsbIoProtocol = {\r
863   UsbIoControlTransfer,\r
864   UsbIoBulkTransfer,\r
865   UsbIoAsyncInterruptTransfer,\r
866   UsbIoSyncInterruptTransfer,\r
867   UsbIoIsochronousTransfer,\r
868   UsbIoAsyncIsochronousTransfer,\r
869   UsbIoGetDeviceDescriptor,\r
870   UsbIoGetActiveConfigDescriptor,\r
871   UsbIoGetInterfaceDescriptor,\r
872   UsbIoGetEndpointDescriptor,\r
873   UsbIoGetStringDescriptor,\r
874   UsbIoGetSupportedLanguages,\r
875   UsbIoPortReset\r
876 };\r
877 \r
878 //@MT: EFI_DRIVER_ENTRY_POINT (UsbBusDriverEntryPoint)\r
879 \r
880 EFI_STATUS\r
881 EFIAPI\r
882 UsbBusDriverEntryPoint (\r
883   IN EFI_HANDLE           ImageHandle,\r
884   IN EFI_SYSTEM_TABLE     *SystemTable\r
885   )\r
886 /*++\r
887 \r
888 Routine Description:\r
889 \r
890   The USB bus driver entry pointer\r
891 \r
892 Arguments:\r
893 \r
894   ImageHandle - The driver image handle\r
895   SystemTable - The system table\r
896 \r
897 Returns:\r
898 \r
899   EFI_SUCCESS - The component name protocol is installed\r
900   Others      - Failed to init the usb driver\r
901 \r
902 --*/\r
903 {\r
904   return EfiLibInstallAllDriverProtocols (\r
905            ImageHandle,\r
906            SystemTable,\r
907            &mUsbBusDriverBinding,\r
908            ImageHandle,\r
909            &mUsbBusComponentName,\r
910            NULL,\r
911            NULL\r
912            );\r
913 }\r
914 \r
915 \r
916 /**\r
917   Check whether USB bus driver support this device\r
918 \r
919   @param  This                   The USB bus driver binding protocol\r
920   @param  Controller             The controller handle to test againist\r
921   @param  RemainingDevicePath    The remaining device path\r
922 \r
923   @retval EFI_SUCCESS            The bus supports this controller.\r
924   @retval EFI_UNSUPPORTED        This device isn't supported\r
925 \r
926 **/\r
927 EFI_STATUS\r
928 EFIAPI\r
929 UsbBusControllerDriverSupported (\r
930   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
931   IN EFI_HANDLE                   Controller,\r
932   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
933   )\r
934 {\r
935   EFI_DEV_PATH_PTR          DevicePathNode;\r
936   EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;\r
937   EFI_USB2_HC_PROTOCOL      *Usb2Hc;\r
938   EFI_USB_HC_PROTOCOL       *UsbHc;\r
939   EFI_STATUS                Status;\r
940 \r
941   //\r
942   // Check whether device path is valid\r
943   //\r
944   if (RemainingDevicePath != NULL) {\r
945     DevicePathNode.DevPath = RemainingDevicePath;\r
946 \r
947     if ((DevicePathNode.DevPath->Type    != MESSAGING_DEVICE_PATH) ||\r
948         (DevicePathNode.DevPath->SubType != MSG_USB_DP) ||\r
949         (DevicePathNodeLength (DevicePathNode.DevPath) != sizeof (USB_DEVICE_PATH))) {\r
950 \r
951       return EFI_UNSUPPORTED;\r
952     }\r
953   }\r
954 \r
955   Status = gBS->OpenProtocol (\r
956                   Controller,\r
957                   &gEfiDevicePathProtocolGuid,\r
958                   (VOID **) &ParentDevicePath,\r
959                   This->DriverBindingHandle,\r
960                   Controller,\r
961                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
962                   );\r
963 \r
964   if (Status == EFI_ALREADY_STARTED) {\r
965     return EFI_SUCCESS;\r
966   }\r
967 \r
968   if (EFI_ERROR (Status)) {\r
969     return Status;\r
970   }\r
971 \r
972   gBS->CloseProtocol (\r
973          Controller,\r
974          &gEfiDevicePathProtocolGuid,\r
975          This->DriverBindingHandle,\r
976          Controller\r
977          );\r
978 \r
979   //\r
980   // Check whether USB_HC2 protocol is installed\r
981   //\r
982   Status = gBS->OpenProtocol (\r
983                   Controller,\r
984                   &gEfiUsb2HcProtocolGuid,\r
985                   (VOID **) &Usb2Hc,\r
986                   This->DriverBindingHandle,\r
987                   Controller,\r
988                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
989                   );\r
990 \r
991   if (Status == EFI_ALREADY_STARTED) {\r
992     return EFI_SUCCESS;\r
993   }\r
994 \r
995   if (!EFI_ERROR (Status)) {\r
996     gBS->CloseProtocol (\r
997           Controller,\r
998           &gEfiUsb2HcProtocolGuid,\r
999           This->DriverBindingHandle,\r
1000           Controller\r
1001           );\r
1002 \r
1003     return EFI_SUCCESS;\r
1004   }\r
1005 \r
1006   //\r
1007   // If failed to open USB_HC2, fall back to USB_HC\r
1008   //\r
1009   Status = gBS->OpenProtocol (\r
1010                   Controller,\r
1011                   &gEfiUsbHcProtocolGuid,\r
1012                   (VOID **) &UsbHc,\r
1013                   This->DriverBindingHandle,\r
1014                   Controller,\r
1015                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
1016                   );\r
1017 \r
1018   if (Status == EFI_ALREADY_STARTED) {\r
1019     return EFI_SUCCESS;\r
1020   }\r
1021 \r
1022   if (!EFI_ERROR (Status)) {\r
1023     gBS->CloseProtocol (\r
1024           Controller,\r
1025           &gEfiUsbHcProtocolGuid,\r
1026           This->DriverBindingHandle,\r
1027           Controller\r
1028           );\r
1029   }\r
1030 \r
1031   return Status;\r
1032 }\r
1033 \r
1034 \r
1035 /**\r
1036   Start to process the controller\r
1037 \r
1038   @param  This                   The USB bus driver binding instance\r
1039   @param  Controller             The controller to check\r
1040   @param  RemainingDevicePath    The remaining device patch\r
1041 \r
1042   @retval EFI_SUCCESS            The controller is controlled by the usb bus\r
1043   @retval EFI_ALREADY_STARTED    The controller is already controlled by the usb\r
1044                                  bus\r
1045   @retval EFI_OUT_OF_RESOURCES   Failed to allocate resources\r
1046 \r
1047 **/\r
1048 EFI_STATUS\r
1049 EFIAPI\r
1050 UsbBusControllerDriverStart (\r
1051   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
1052   IN EFI_HANDLE                   Controller,\r
1053   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
1054   )\r
1055 {\r
1056   USB_BUS                 *UsbBus;\r
1057   USB_DEVICE              *RootHub;\r
1058   USB_INTERFACE           *RootIf;\r
1059   EFI_USB_BUS_PROTOCOL    *UsbBusId;\r
1060   EFI_STATUS              Status;\r
1061   EFI_STATUS              Status2;\r
1062 \r
1063   //\r
1064   // Locate the USB bus protocol, if it is found, USB bus\r
1065   // is already started on this controller.\r
1066   //\r
1067   Status = gBS->OpenProtocol (\r
1068                   Controller,\r
1069                   &mUsbBusProtocolGuid,\r
1070                   (VOID **) &UsbBusId,\r
1071                   This->DriverBindingHandle,\r
1072                   Controller,\r
1073                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1074                   );\r
1075 \r
1076   if (!EFI_ERROR (Status)) {\r
1077     return EFI_ALREADY_STARTED;\r
1078   }\r
1079 \r
1080   UsbBus = AllocateZeroPool (sizeof (USB_BUS));\r
1081 \r
1082   if (UsbBus == NULL) {\r
1083     return EFI_OUT_OF_RESOURCES;\r
1084   }\r
1085 \r
1086   UsbBus->Signature   = USB_BUS_SIGNATURE;\r
1087   UsbBus->HostHandle  = Controller;\r
1088 \r
1089   Status = gBS->OpenProtocol (\r
1090                   Controller,\r
1091                   &gEfiDevicePathProtocolGuid,\r
1092                   (VOID **) &UsbBus->DevicePath,\r
1093                   This->DriverBindingHandle,\r
1094                   Controller,\r
1095                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
1096                   );\r
1097 \r
1098   if (EFI_ERROR (Status)) {\r
1099     USB_ERROR (("UsbBusStart: Failed to open device path %r\n", Status));\r
1100 \r
1101     gBS->FreePool (UsbBus);\r
1102     return Status;\r
1103   }\r
1104 \r
1105   //\r
1106   // Get USB_HC2/USB_HC host controller protocol (EHCI/UHCI).\r
1107   // This is for backward compatbility with EFI 1.x. In UEFI\r
1108   // 2.x, USB_HC2 replaces USB_HC. We will open both USB_HC2\r
1109   // and USB_HC because EHCI driver will install both protocols\r
1110   // (for the same reason). If we don't consume both of them,\r
1111   // the unconsumed one may be opened by others.\r
1112   //\r
1113   Status = gBS->OpenProtocol (\r
1114                   Controller,\r
1115                   &gEfiUsb2HcProtocolGuid,\r
1116                   (VOID **) &(UsbBus->Usb2Hc),\r
1117                   This->DriverBindingHandle,\r
1118                   Controller,\r
1119                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
1120                   );\r
1121 \r
1122   Status2 = gBS->OpenProtocol (\r
1123                    Controller,\r
1124                    &gEfiUsbHcProtocolGuid,\r
1125                    (VOID **) &(UsbBus->UsbHc),\r
1126                    This->DriverBindingHandle,\r
1127                    Controller,\r
1128                    EFI_OPEN_PROTOCOL_BY_DRIVER\r
1129                    );\r
1130 \r
1131   if (EFI_ERROR (Status) && EFI_ERROR (Status2)) {\r
1132     USB_ERROR (("UsbBusStart: Failed to open USB_HC/USB2_HC %r\n", Status));\r
1133 \r
1134     Status = EFI_DEVICE_ERROR;\r
1135     goto CLOSE_HC;\r
1136   }\r
1137 \r
1138   //\r
1139   // Create a fake usb device for root hub\r
1140   //\r
1141   RootHub = AllocateZeroPool (sizeof (USB_DEVICE));\r
1142 \r
1143   if (RootHub == NULL) {\r
1144     Status = EFI_OUT_OF_RESOURCES;\r
1145     goto CLOSE_HC;\r
1146   }\r
1147 \r
1148   RootIf = AllocateZeroPool (sizeof (USB_INTERFACE));\r
1149 \r
1150   if (RootIf == NULL) {\r
1151     gBS->FreePool (RootHub);\r
1152     Status = EFI_OUT_OF_RESOURCES;\r
1153     goto CLOSE_HC;\r
1154   }\r
1155 \r
1156   RootHub->Bus            = UsbBus;\r
1157   RootHub->NumOfInterface = 1;\r
1158   RootHub->Interfaces[0]  = RootIf;\r
1159   RootIf->Signature       = USB_INTERFACE_SIGNATURE;\r
1160   RootIf->Device          = RootHub;\r
1161   RootIf->DevicePath      = UsbBus->DevicePath;\r
1162 \r
1163   Status                  = mUsbRootHubApi.Init (RootIf);\r
1164 \r
1165   if (EFI_ERROR (Status)) {\r
1166     USB_ERROR (("UsbBusStart: Failed to init root hub %r\n", Status));\r
1167     goto FREE_ROOTHUB;\r
1168   }\r
1169 \r
1170   UsbBus->Devices[0] = RootHub;\r
1171 \r
1172   //\r
1173   // Install an EFI_USB_BUS_PROTOCOL to host controler to identify it.\r
1174   //\r
1175   Status = gBS->InstallProtocolInterface (\r
1176                   &Controller,\r
1177                   &mUsbBusProtocolGuid,\r
1178                   EFI_NATIVE_INTERFACE,\r
1179                   &UsbBus->BusId\r
1180                   );\r
1181 \r
1182   if (EFI_ERROR (Status)) {\r
1183     USB_ERROR (("UsbBusStart: Failed to install bus protocol %r\n", Status));\r
1184 \r
1185     mUsbRootHubApi.Release (RootIf);\r
1186     goto FREE_ROOTHUB;\r
1187   }\r
1188 \r
1189   UsbHcReset (UsbBus, EFI_USB_HC_RESET_GLOBAL);\r
1190   UsbHcSetState (UsbBus, EfiUsbHcStateOperational);\r
1191 \r
1192   USB_DEBUG (("UsbBusStart: usb bus started on %x, root hub %x\n", Controller, RootIf));\r
1193   return EFI_SUCCESS;\r
1194 \r
1195 FREE_ROOTHUB:\r
1196   gBS->FreePool (RootIf);\r
1197   gBS->FreePool (RootHub);\r
1198 \r
1199 CLOSE_HC:\r
1200   if (UsbBus->Usb2Hc != NULL) {\r
1201     gBS->CloseProtocol (\r
1202           Controller,\r
1203           &gEfiUsb2HcProtocolGuid,\r
1204           This->DriverBindingHandle,\r
1205           Controller\r
1206           );\r
1207   }\r
1208 \r
1209   if (UsbBus->UsbHc != NULL) {\r
1210     gBS->CloseProtocol (\r
1211           Controller,\r
1212           &gEfiUsbHcProtocolGuid,\r
1213           This->DriverBindingHandle,\r
1214           Controller\r
1215           );\r
1216   }\r
1217 \r
1218   gBS->CloseProtocol (\r
1219          Controller,\r
1220          &gEfiDevicePathProtocolGuid,\r
1221          This->DriverBindingHandle,\r
1222          Controller\r
1223          );\r
1224 \r
1225   gBS->FreePool (UsbBus);\r
1226 \r
1227   USB_ERROR (("UsbBusStart: Failed to start bus driver %r\n", Status));\r
1228   return Status;\r
1229 }\r
1230 \r
1231 \r
1232 /**\r
1233   Stop handle the controller by this USB bus driver\r
1234 \r
1235   @param  This                   The USB bus driver binding protocol\r
1236   @param  Controller             The controller to release\r
1237   @param  NumberOfChildren       The child of USB bus that opened controller\r
1238                                  BY_CHILD\r
1239   @param  ChildHandleBuffer      The array of child handle\r
1240 \r
1241   @retval EFI_SUCCESS            The controller or children are stopped\r
1242   @retval EFI_DEVICE_ERROR       Failed to stop the driver\r
1243 \r
1244 **/\r
1245 EFI_STATUS\r
1246 EFIAPI\r
1247 UsbBusControllerDriverStop (\r
1248   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
1249   IN EFI_HANDLE                   Controller,\r
1250   IN UINTN                        NumberOfChildren,\r
1251   IN EFI_HANDLE                   *ChildHandleBuffer\r
1252   )\r
1253 {\r
1254   USB_BUS               *Bus;\r
1255   USB_DEVICE            *RootHub;\r
1256   USB_DEVICE            *UsbDev;\r
1257   USB_INTERFACE         *RootIf;\r
1258   USB_INTERFACE         *UsbIf;\r
1259   EFI_USB_BUS_PROTOCOL  *BusId;\r
1260   EFI_USB_IO_PROTOCOL   *UsbIo;\r
1261   EFI_TPL               OldTpl;\r
1262   UINTN                 Index;\r
1263   EFI_STATUS            Status;\r
1264 \r
1265   Status  = EFI_SUCCESS;\r
1266 \r
1267   if (NumberOfChildren > 0) {\r
1268     OldTpl   = gBS->RaiseTPL (USB_BUS_TPL);\r
1269 \r
1270     for (Index = 0; Index < NumberOfChildren; Index++) {\r
1271       Status = gBS->OpenProtocol (\r
1272                       ChildHandleBuffer[Index],\r
1273                       &gEfiUsbIoProtocolGuid,\r
1274                       (VOID **) &UsbIo,\r
1275                       This->DriverBindingHandle,\r
1276                       Controller,\r
1277                       EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1278                       );\r
1279 \r
1280       if (EFI_ERROR (Status)) {\r
1281         //\r
1282         // It is possible that the child has already been released:\r
1283         // 1. For combo device, free one device will release others.\r
1284         // 2. If a hub is released, all devices on its down facing\r
1285         //    ports are released also.\r
1286         //\r
1287         continue;\r
1288       }\r
1289 \r
1290       UsbIf   = USB_INTERFACE_FROM_USBIO (UsbIo);\r
1291       UsbDev  = UsbIf->Device;\r
1292 \r
1293       UsbRemoveDevice (UsbDev);\r
1294     }\r
1295 \r
1296     gBS->RestoreTPL (OldTpl);\r
1297     return EFI_SUCCESS;\r
1298   }\r
1299 \r
1300   USB_DEBUG (("UsbBusStop: usb bus stopped on %x\n", Controller));\r
1301 \r
1302   //\r
1303   // Locate USB_BUS for the current host controller\r
1304   //\r
1305   Status = gBS->OpenProtocol (\r
1306                   Controller,\r
1307                   &mUsbBusProtocolGuid,\r
1308                   (VOID **) &BusId,\r
1309                   This->DriverBindingHandle,\r
1310                   Controller,\r
1311                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1312                   );\r
1313 \r
1314   if (EFI_ERROR (Status)) {\r
1315     return Status;\r
1316   }\r
1317 \r
1318   Bus = USB_BUS_FROM_THIS (BusId);\r
1319 \r
1320   //\r
1321   // Stop the root hub, then free all the devices\r
1322   //\r
1323   OldTpl  = gBS->RaiseTPL (USB_BUS_TPL);\r
1324   UsbHcSetState (Bus, EfiUsbHcStateHalt);\r
1325 \r
1326   RootHub = Bus->Devices[0];\r
1327   RootIf  = RootHub->Interfaces[0];\r
1328 \r
1329   mUsbRootHubApi.Release (RootIf);\r
1330 \r
1331   for (Index = 1; Index < USB_MAX_DEVICES; Index++) {\r
1332     if (Bus->Devices[Index] != NULL) {\r
1333       UsbRemoveDevice (Bus->Devices[Index]);\r
1334     }\r
1335   }\r
1336 \r
1337   gBS->RestoreTPL (OldTpl);\r
1338 \r
1339   gBS->FreePool   (RootIf);\r
1340   gBS->FreePool   (RootHub);\r
1341 \r
1342   //\r
1343   // Uninstall the bus identifier and close USB_HC/USB2_HC protocols\r
1344   //\r
1345   gBS->UninstallProtocolInterface (Controller, &mUsbBusProtocolGuid, &Bus->BusId);\r
1346 \r
1347   if (Bus->Usb2Hc != NULL) {\r
1348     gBS->CloseProtocol (\r
1349            Controller,\r
1350            &gEfiUsb2HcProtocolGuid,\r
1351            This->DriverBindingHandle,\r
1352            Controller\r
1353            );\r
1354   }\r
1355 \r
1356   if (Bus->UsbHc != NULL) {\r
1357     gBS->CloseProtocol (\r
1358            Controller,\r
1359            &gEfiUsbHcProtocolGuid,\r
1360            This->DriverBindingHandle,\r
1361            Controller\r
1362            );\r
1363   }\r
1364 \r
1365   gBS->CloseProtocol (\r
1366          Controller,\r
1367          &gEfiDevicePathProtocolGuid,\r
1368          This->DriverBindingHandle,\r
1369          Controller\r
1370          );\r
1371 \r
1372   gBS->FreePool (Bus);\r
1373 \r
1374   return Status;\r
1375 }\r
1376 \r
1377 EFI_DRIVER_BINDING_PROTOCOL mUsbBusDriverBinding = {\r
1378   UsbBusControllerDriverSupported,\r
1379   UsbBusControllerDriverStart,\r
1380   UsbBusControllerDriverStop,\r
1381   0xa,\r
1382   NULL,\r
1383   NULL\r
1384 };\r