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