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