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