]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.c
Sync USB modules with main trunk.
[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 > 15)) {
649 gBS->RestoreTPL (OldTpl);
650 return EFI_INVALID_PARAMETER;
651 }
652
653 if (Index >= UsbIf->IfSetting->Desc.NumEndpoints) {
654 gBS->RestoreTPL (OldTpl);
655 return EFI_NOT_FOUND;
656 }
657
658 CopyMem (
659 Descriptor,
660 &(UsbIf->IfSetting->Endpoints[Index]->Desc),
661 sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)
662 );
663
664 gBS->RestoreTPL (OldTpl);
665 return EFI_SUCCESS;
666 }
667
668
669 /**
670 Retrieve the supported language ID table from the device
671
672 @param This The USB IO instance
673 @param LangIDTable The table to return the language IDs
674 @param TableSize The number of supported languanges
675
676 @retval EFI_SUCCESS The language ID is return
677
678 **/
679 STATIC
680 EFI_STATUS
681 EFIAPI
682 UsbIoGetSupportedLanguages (
683 IN EFI_USB_IO_PROTOCOL *This,
684 OUT UINT16 **LangIDTable,
685 OUT UINT16 *TableSize
686 )
687 {
688 USB_DEVICE *Dev;
689 USB_INTERFACE *UsbIf;
690 EFI_TPL OldTpl;
691
692 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
693
694 UsbIf = USB_INTERFACE_FROM_USBIO (This);
695 Dev = UsbIf->Device;
696
697 *LangIDTable = Dev->LangId;
698 *TableSize = Dev->TotalLangId;
699
700 gBS->RestoreTPL (OldTpl);
701 return EFI_SUCCESS;
702 }
703
704
705 /**
706 Retrieve an indexed string in the language of LangID
707
708 @param This The USB IO instance
709 @param LangID The language ID of the string to retrieve
710 @param StringIndex The index of the string
711 @param String The variable to receive the string
712
713 @retval EFI_SUCCESS The string is returned
714 @retval EFI_NOT_FOUND No such string existed
715
716 **/
717 STATIC
718 EFI_STATUS
719 EFIAPI
720 UsbIoGetStringDescriptor (
721 IN EFI_USB_IO_PROTOCOL *This,
722 IN UINT16 LangID,
723 IN UINT8 StringIndex,
724 OUT CHAR16 **String
725 )
726 {
727 USB_DEVICE *Dev;
728 USB_INTERFACE *UsbIf;
729 EFI_USB_STRING_DESCRIPTOR *StrDesc;
730 EFI_TPL OldTpl;
731 UINT8 *Buf;
732 UINT8 Index;
733 EFI_STATUS Status;
734
735 if ((StringIndex == 0) || (LangID == 0)) {
736 return EFI_NOT_FOUND;
737 }
738
739 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
740
741 UsbIf = USB_INTERFACE_FROM_USBIO (This);
742 Dev = UsbIf->Device;
743
744 //
745 // Check whether language ID is supported
746 //
747 Status = EFI_NOT_FOUND;
748
749 for (Index = 0; Index < Dev->TotalLangId; Index++) {
750 if (Dev->LangId[Index] == LangID) {
751 break;
752 }
753 }
754
755 if (Index == Dev->TotalLangId) {
756 goto ON_EXIT;
757 }
758
759 //
760 // Retrieve the string descriptor then allocate a buffer
761 // to hold the string itself.
762 //
763 StrDesc = UsbGetOneString (Dev, StringIndex, LangID);
764
765 if (StrDesc == NULL) {
766 goto ON_EXIT;
767 }
768
769 if (StrDesc->Length <= 2) {
770 goto FREE_STR;
771 }
772
773 Buf = AllocateZeroPool (StrDesc->Length);
774
775 if (Buf == NULL) {
776 Status = EFI_OUT_OF_RESOURCES;
777 goto FREE_STR;
778 }
779
780 CopyMem (Buf, StrDesc->String, StrDesc->Length - 2);
781 *String = (CHAR16 *) Buf;
782 Status = EFI_SUCCESS;
783
784 FREE_STR:
785 gBS->FreePool (StrDesc);
786
787 ON_EXIT:
788 gBS->RestoreTPL (OldTpl);
789 return Status;
790 }
791
792
793 /**
794 Reset the device, then if that succeeds, reconfigure the
795 device with its address and current active configuration.
796
797 @param This The USB IO instance
798
799 @retval EFI_SUCCESS The device is reset and configured
800 @retval Others Failed to reset the device
801
802 **/
803 EFI_STATUS
804 EFIAPI
805 UsbIoPortReset (
806 IN EFI_USB_IO_PROTOCOL *This
807 )
808 {
809 USB_INTERFACE *UsbIf;
810 USB_INTERFACE *HubIf;
811 USB_DEVICE *Dev;
812 UINT8 Address;
813 EFI_TPL OldTpl;
814 EFI_STATUS Status;
815
816 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
817
818 UsbIf = USB_INTERFACE_FROM_USBIO (This);
819 Dev = UsbIf->Device;
820
821 if (UsbIf->IsHub == TRUE) {
822 Status = EFI_INVALID_PARAMETER;
823 goto ON_EXIT;
824 }
825
826 HubIf = Dev->ParentIf;
827 Status = HubIf->HubApi->ResetPort (HubIf, Dev->ParentPort);
828
829 if (EFI_ERROR (Status)) {
830 USB_ERROR (("UsbIoPortReset: failed to reset hub port %d@hub %d, %r \n",
831 Dev->ParentPort, Dev->ParentAddr, Status));
832
833 goto ON_EXIT;
834 }
835
836 //
837 // Reset the device to its current address. The device now has a
838 // address of ZERO, so need to set Dev->Address to zero first for
839 // host to communicate with the device
840 //
841 Address = Dev->Address;
842 Dev->Address = 0;
843 Status = UsbSetAddress (Dev, Address);
844
845 if (EFI_ERROR (Status)) {
846 USB_ERROR (("UsbIoPortReset: failed to set address for device %d - %r\n",
847 Address, Status));
848
849 goto ON_EXIT;
850 }
851
852 Dev->Address = Address;
853
854 //
855 // Reset the current active configure, after this device
856 // is in CONFIGURED state.
857 //
858 if (Dev->ActiveConfig != NULL) {
859 Status = UsbSetConfig (Dev, Dev->ActiveConfig->Desc.ConfigurationValue);
860
861 if (EFI_ERROR (Status)) {
862 USB_ERROR (("UsbIoPortReset: failed to set configure for device %d - %r\n",
863 Address, Status));
864 }
865 }
866
867 ON_EXIT:
868 gBS->RestoreTPL (OldTpl);
869 return Status;
870 }
871
872 EFI_USB_IO_PROTOCOL mUsbIoProtocol = {
873 UsbIoControlTransfer,
874 UsbIoBulkTransfer,
875 UsbIoAsyncInterruptTransfer,
876 UsbIoSyncInterruptTransfer,
877 UsbIoIsochronousTransfer,
878 UsbIoAsyncIsochronousTransfer,
879 UsbIoGetDeviceDescriptor,
880 UsbIoGetActiveConfigDescriptor,
881 UsbIoGetInterfaceDescriptor,
882 UsbIoGetEndpointDescriptor,
883 UsbIoGetStringDescriptor,
884 UsbIoGetSupportedLanguages,
885 UsbIoPortReset
886 };
887
888
889 EFI_STATUS
890 EFIAPI
891 UsbBusDriverEntryPoint (
892 IN EFI_HANDLE ImageHandle,
893 IN EFI_SYSTEM_TABLE *SystemTable
894 )
895 /*++
896
897 Routine Description:
898
899 The USB bus driver entry pointer
900
901 Arguments:
902
903 ImageHandle - The driver image handle
904 SystemTable - The system table
905
906 Returns:
907
908 EFI_SUCCESS - The component name protocol is installed
909 Others - Failed to init the usb driver
910
911 --*/
912 {
913 return EfiLibInstallAllDriverProtocols (
914 ImageHandle,
915 SystemTable,
916 &mUsbBusDriverBinding,
917 ImageHandle,
918 &mUsbBusComponentName,
919 NULL,
920 NULL
921 );
922 }
923
924
925 /**
926 Check whether USB bus driver support this device
927
928 @param This The USB bus driver binding protocol
929 @param Controller The controller handle to test againist
930 @param RemainingDevicePath The remaining device path
931
932 @retval EFI_SUCCESS The bus supports this controller.
933 @retval EFI_UNSUPPORTED This device isn't supported
934
935 **/
936 EFI_STATUS
937 EFIAPI
938 UsbBusControllerDriverSupported (
939 IN EFI_DRIVER_BINDING_PROTOCOL *This,
940 IN EFI_HANDLE Controller,
941 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
942 )
943 {
944 EFI_DEV_PATH_PTR DevicePathNode;
945 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
946 EFI_USB2_HC_PROTOCOL *Usb2Hc;
947 EFI_USB_HC_PROTOCOL *UsbHc;
948 EFI_STATUS Status;
949
950 //
951 // Check whether device path is valid
952 //
953 if (RemainingDevicePath != NULL) {
954 DevicePathNode.DevPath = RemainingDevicePath;
955
956 if ((DevicePathNode.DevPath->Type != MESSAGING_DEVICE_PATH) ||
957 (DevicePathNode.DevPath->SubType != MSG_USB_DP) ||
958 (DevicePathNodeLength (DevicePathNode.DevPath) != sizeof (USB_DEVICE_PATH))) {
959
960 return EFI_UNSUPPORTED;
961 }
962 }
963
964 Status = gBS->OpenProtocol (
965 Controller,
966 &gEfiDevicePathProtocolGuid,
967 (VOID **) &ParentDevicePath,
968 This->DriverBindingHandle,
969 Controller,
970 EFI_OPEN_PROTOCOL_BY_DRIVER
971 );
972
973 if (Status == EFI_ALREADY_STARTED) {
974 return EFI_SUCCESS;
975 }
976
977 if (EFI_ERROR (Status)) {
978 return Status;
979 }
980
981 gBS->CloseProtocol (
982 Controller,
983 &gEfiDevicePathProtocolGuid,
984 This->DriverBindingHandle,
985 Controller
986 );
987
988 //
989 // Check whether USB_HC2 protocol is installed
990 //
991 Status = gBS->OpenProtocol (
992 Controller,
993 &gEfiUsb2HcProtocolGuid,
994 (VOID **) &Usb2Hc,
995 This->DriverBindingHandle,
996 Controller,
997 EFI_OPEN_PROTOCOL_BY_DRIVER
998 );
999
1000 if (Status == EFI_ALREADY_STARTED) {
1001 return EFI_SUCCESS;
1002 }
1003
1004 if (!EFI_ERROR (Status)) {
1005 gBS->CloseProtocol (
1006 Controller,
1007 &gEfiUsb2HcProtocolGuid,
1008 This->DriverBindingHandle,
1009 Controller
1010 );
1011
1012 return EFI_SUCCESS;
1013 }
1014
1015 //
1016 // If failed to open USB_HC2, fall back to USB_HC
1017 //
1018 Status = gBS->OpenProtocol (
1019 Controller,
1020 &gEfiUsbHcProtocolGuid,
1021 (VOID **) &UsbHc,
1022 This->DriverBindingHandle,
1023 Controller,
1024 EFI_OPEN_PROTOCOL_BY_DRIVER
1025 );
1026
1027 if (Status == EFI_ALREADY_STARTED) {
1028 return EFI_SUCCESS;
1029 }
1030
1031 if (!EFI_ERROR (Status)) {
1032 gBS->CloseProtocol (
1033 Controller,
1034 &gEfiUsbHcProtocolGuid,
1035 This->DriverBindingHandle,
1036 Controller
1037 );
1038 }
1039
1040 return Status;
1041 }
1042
1043
1044 /**
1045 Start to process the controller
1046
1047 @param This The USB bus driver binding instance
1048 @param Controller The controller to check
1049 @param RemainingDevicePath The remaining device patch
1050
1051 @retval EFI_SUCCESS The controller is controlled by the usb bus
1052 @retval EFI_ALREADY_STARTED The controller is already controlled by the usb
1053 bus
1054 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources
1055
1056 **/
1057 EFI_STATUS
1058 EFIAPI
1059 UsbBusControllerDriverStart (
1060 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1061 IN EFI_HANDLE Controller,
1062 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1063 )
1064 {
1065 USB_BUS *UsbBus;
1066 USB_DEVICE *RootHub;
1067 USB_INTERFACE *RootIf;
1068 EFI_USB_BUS_PROTOCOL *UsbBusId;
1069 EFI_STATUS Status;
1070 EFI_STATUS Status2;
1071
1072 //
1073 // Locate the USB bus protocol, if it is found, USB bus
1074 // is already started on this controller.
1075 //
1076 Status = gBS->OpenProtocol (
1077 Controller,
1078 &mUsbBusProtocolGuid,
1079 (VOID **) &UsbBusId,
1080 This->DriverBindingHandle,
1081 Controller,
1082 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1083 );
1084
1085 if (!EFI_ERROR (Status)) {
1086 return EFI_ALREADY_STARTED;
1087 }
1088
1089 UsbBus = AllocateZeroPool (sizeof (USB_BUS));
1090
1091 if (UsbBus == NULL) {
1092 return EFI_OUT_OF_RESOURCES;
1093 }
1094
1095 UsbBus->Signature = USB_BUS_SIGNATURE;
1096 UsbBus->HostHandle = Controller;
1097
1098 Status = gBS->OpenProtocol (
1099 Controller,
1100 &gEfiDevicePathProtocolGuid,
1101 (VOID **) &UsbBus->DevicePath,
1102 This->DriverBindingHandle,
1103 Controller,
1104 EFI_OPEN_PROTOCOL_BY_DRIVER
1105 );
1106
1107 if (EFI_ERROR (Status)) {
1108 USB_ERROR (("UsbBusStart: Failed to open device path %r\n", Status));
1109
1110 gBS->FreePool (UsbBus);
1111 return Status;
1112 }
1113
1114 //
1115 // Get USB_HC2/USB_HC host controller protocol (EHCI/UHCI).
1116 // This is for backward compatbility with EFI 1.x. In UEFI
1117 // 2.x, USB_HC2 replaces USB_HC. We will open both USB_HC2
1118 // and USB_HC because EHCI driver will install both protocols
1119 // (for the same reason). If we don't consume both of them,
1120 // the unconsumed one may be opened by others.
1121 //
1122 Status = gBS->OpenProtocol (
1123 Controller,
1124 &gEfiUsb2HcProtocolGuid,
1125 (VOID **) &(UsbBus->Usb2Hc),
1126 This->DriverBindingHandle,
1127 Controller,
1128 EFI_OPEN_PROTOCOL_BY_DRIVER
1129 );
1130
1131 Status2 = gBS->OpenProtocol (
1132 Controller,
1133 &gEfiUsbHcProtocolGuid,
1134 (VOID **) &(UsbBus->UsbHc),
1135 This->DriverBindingHandle,
1136 Controller,
1137 EFI_OPEN_PROTOCOL_BY_DRIVER
1138 );
1139
1140 if (EFI_ERROR (Status) && EFI_ERROR (Status2)) {
1141 USB_ERROR (("UsbBusStart: Failed to open USB_HC/USB2_HC %r\n", Status));
1142
1143 Status = EFI_DEVICE_ERROR;
1144 goto CLOSE_HC;
1145 }
1146
1147 //
1148 // Create a fake usb device for root hub
1149 //
1150 RootHub = AllocateZeroPool (sizeof (USB_DEVICE));
1151
1152 if (RootHub == NULL) {
1153 Status = EFI_OUT_OF_RESOURCES;
1154 goto CLOSE_HC;
1155 }
1156
1157 RootIf = AllocateZeroPool (sizeof (USB_INTERFACE));
1158
1159 if (RootIf == NULL) {
1160 gBS->FreePool (RootHub);
1161 Status = EFI_OUT_OF_RESOURCES;
1162 goto CLOSE_HC;
1163 }
1164
1165 RootHub->Bus = UsbBus;
1166 RootHub->NumOfInterface = 1;
1167 RootHub->Interfaces[0] = RootIf;
1168 RootIf->Signature = USB_INTERFACE_SIGNATURE;
1169 RootIf->Device = RootHub;
1170 RootIf->DevicePath = UsbBus->DevicePath;
1171
1172 Status = mUsbRootHubApi.Init (RootIf);
1173
1174 if (EFI_ERROR (Status)) {
1175 USB_ERROR (("UsbBusStart: Failed to init root hub %r\n", Status));
1176 goto FREE_ROOTHUB;
1177 }
1178
1179 UsbBus->Devices[0] = RootHub;
1180
1181 //
1182 // Install an EFI_USB_BUS_PROTOCOL to host controler to identify it.
1183 //
1184 Status = gBS->InstallProtocolInterface (
1185 &Controller,
1186 &mUsbBusProtocolGuid,
1187 EFI_NATIVE_INTERFACE,
1188 &UsbBus->BusId
1189 );
1190
1191 if (EFI_ERROR (Status)) {
1192 USB_ERROR (("UsbBusStart: Failed to install bus protocol %r\n", Status));
1193
1194 mUsbRootHubApi.Release (RootIf);
1195 goto FREE_ROOTHUB;
1196 }
1197
1198 UsbHcReset (UsbBus, EFI_USB_HC_RESET_GLOBAL);
1199 UsbHcSetState (UsbBus, EfiUsbHcStateOperational);
1200
1201 USB_DEBUG (("UsbBusStart: usb bus started on %x, root hub %x\n", Controller, RootIf));
1202 return EFI_SUCCESS;
1203
1204 FREE_ROOTHUB:
1205 gBS->FreePool (RootIf);
1206 gBS->FreePool (RootHub);
1207
1208 CLOSE_HC:
1209 if (UsbBus->Usb2Hc != NULL) {
1210 gBS->CloseProtocol (
1211 Controller,
1212 &gEfiUsb2HcProtocolGuid,
1213 This->DriverBindingHandle,
1214 Controller
1215 );
1216 }
1217
1218 if (UsbBus->UsbHc != NULL) {
1219 gBS->CloseProtocol (
1220 Controller,
1221 &gEfiUsbHcProtocolGuid,
1222 This->DriverBindingHandle,
1223 Controller
1224 );
1225 }
1226
1227 gBS->CloseProtocol (
1228 Controller,
1229 &gEfiDevicePathProtocolGuid,
1230 This->DriverBindingHandle,
1231 Controller
1232 );
1233
1234 gBS->FreePool (UsbBus);
1235
1236 USB_ERROR (("UsbBusStart: Failed to start bus driver %r\n", Status));
1237 return Status;
1238 }
1239
1240
1241 /**
1242 Stop handle the controller by this USB bus driver
1243
1244 @param This The USB bus driver binding protocol
1245 @param Controller The controller to release
1246 @param NumberOfChildren The child of USB bus that opened controller
1247 BY_CHILD
1248 @param ChildHandleBuffer The array of child handle
1249
1250 @retval EFI_SUCCESS The controller or children are stopped
1251 @retval EFI_DEVICE_ERROR Failed to stop the driver
1252
1253 **/
1254 EFI_STATUS
1255 EFIAPI
1256 UsbBusControllerDriverStop (
1257 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1258 IN EFI_HANDLE Controller,
1259 IN UINTN NumberOfChildren,
1260 IN EFI_HANDLE *ChildHandleBuffer
1261 )
1262 {
1263 USB_BUS *Bus;
1264 USB_DEVICE *RootHub;
1265 USB_DEVICE *UsbDev;
1266 USB_INTERFACE *RootIf;
1267 USB_INTERFACE *UsbIf;
1268 EFI_USB_BUS_PROTOCOL *BusId;
1269 EFI_USB_IO_PROTOCOL *UsbIo;
1270 EFI_TPL OldTpl;
1271 UINTN Index;
1272 EFI_STATUS Status;
1273
1274 Status = EFI_SUCCESS;
1275
1276 if (NumberOfChildren > 0) {
1277 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
1278
1279 for (Index = 0; Index < NumberOfChildren; Index++) {
1280 Status = gBS->OpenProtocol (
1281 ChildHandleBuffer[Index],
1282 &gEfiUsbIoProtocolGuid,
1283 (VOID **) &UsbIo,
1284 This->DriverBindingHandle,
1285 Controller,
1286 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1287 );
1288
1289 if (EFI_ERROR (Status)) {
1290 //
1291 // It is possible that the child has already been released:
1292 // 1. For combo device, free one device will release others.
1293 // 2. If a hub is released, all devices on its down facing
1294 // ports are released also.
1295 //
1296 continue;
1297 }
1298
1299 UsbIf = USB_INTERFACE_FROM_USBIO (UsbIo);
1300 UsbDev = UsbIf->Device;
1301
1302 UsbRemoveDevice (UsbDev);
1303 }
1304
1305 gBS->RestoreTPL (OldTpl);
1306 return EFI_SUCCESS;
1307 }
1308
1309 USB_DEBUG (("UsbBusStop: usb bus stopped on %x\n", Controller));
1310
1311 //
1312 // Locate USB_BUS for the current host controller
1313 //
1314 Status = gBS->OpenProtocol (
1315 Controller,
1316 &mUsbBusProtocolGuid,
1317 (VOID **) &BusId,
1318 This->DriverBindingHandle,
1319 Controller,
1320 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1321 );
1322
1323 if (EFI_ERROR (Status)) {
1324 return Status;
1325 }
1326
1327 Bus = USB_BUS_FROM_THIS (BusId);
1328
1329 //
1330 // Stop the root hub, then free all the devices
1331 //
1332 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
1333 UsbHcSetState (Bus, EfiUsbHcStateHalt);
1334
1335 RootHub = Bus->Devices[0];
1336 RootIf = RootHub->Interfaces[0];
1337
1338 mUsbRootHubApi.Release (RootIf);
1339
1340 for (Index = 1; Index < USB_MAX_DEVICES; Index++) {
1341 if (Bus->Devices[Index] != NULL) {
1342 UsbRemoveDevice (Bus->Devices[Index]);
1343 }
1344 }
1345
1346 gBS->RestoreTPL (OldTpl);
1347
1348 gBS->FreePool (RootIf);
1349 gBS->FreePool (RootHub);
1350
1351 //
1352 // Uninstall the bus identifier and close USB_HC/USB2_HC protocols
1353 //
1354 gBS->UninstallProtocolInterface (Controller, &mUsbBusProtocolGuid, &Bus->BusId);
1355
1356 if (Bus->Usb2Hc != NULL) {
1357 gBS->CloseProtocol (
1358 Controller,
1359 &gEfiUsb2HcProtocolGuid,
1360 This->DriverBindingHandle,
1361 Controller
1362 );
1363 }
1364
1365 if (Bus->UsbHc != NULL) {
1366 gBS->CloseProtocol (
1367 Controller,
1368 &gEfiUsbHcProtocolGuid,
1369 This->DriverBindingHandle,
1370 Controller
1371 );
1372 }
1373
1374 gBS->CloseProtocol (
1375 Controller,
1376 &gEfiDevicePathProtocolGuid,
1377 This->DriverBindingHandle,
1378 Controller
1379 );
1380
1381 gBS->FreePool (Bus);
1382
1383 return Status;
1384 }
1385
1386 EFI_DRIVER_BINDING_PROTOCOL mUsbBusDriverBinding = {
1387 UsbBusControllerDriverSupported,
1388 UsbBusControllerDriverStart,
1389 UsbBusControllerDriverStop,
1390 0xa,
1391 NULL,
1392 NULL
1393 };