VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/MdePkg/Library/UefiUsbLib/UsbDxeLib.c

Last change on this file was 108794, checked in by vboxsync, 3 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

  • Property svn:eol-style set to native
File size: 37.2 KB
Line 
1/** @file
2
3 The library provides the USB Standard Device Requests defined
4 in Usb specification 9.4 section.
5
6 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
7 Copyright (c) 2024, American Megatrends International LLC. All rights reserved.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9
10**/
11
12#include "UefiUsbLibInternal.h"
13
14static UINT8 *mConfigData = NULL;
15static EFI_USB_DEVICE_DESCRIPTOR mDeviceDescriptor;
16
17/**
18 Get the descriptor of the specified USB device.
19
20 Submit a USB get descriptor request for the USB device specified by UsbIo, Value,
21 and Index, and return the descriptor in the buffer specified by Descriptor.
22 The status of the transfer is returned in Status.
23 If UsbIo is NULL, then ASSERT().
24 If Descriptor is NULL, then ASSERT().
25 If Status is NULL, then ASSERT().
26
27 @param UsbIo A pointer to the USB I/O Protocol instance for the specific USB target.
28 @param Value The device request value.
29 @param Index The device request index.
30 @param DescriptorLength The size, in bytes, of Descriptor.
31 @param Descriptor A pointer to the descriptor buffer to get.
32 @param Status A pointer to the status of the transfer.
33
34 @retval EFI_SUCCESS The request executed successfully.
35 @retval EFI_OUT_OF_RESOURCES The request could not be completed because the
36 buffer specified by DescriptorLength and Descriptor
37 is not large enough to hold the result of the request.
38 @retval EFI_TIMEOUT A timeout occurred executing the request.
39 @retval EFI_DEVICE_ERROR The request failed due to a device error. The transfer
40 status is returned in Status.
41
42**/
43EFI_STATUS
44EFIAPI
45UsbGetDescriptor (
46 IN EFI_USB_IO_PROTOCOL *UsbIo,
47 IN UINT16 Value,
48 IN UINT16 Index,
49 IN UINT16 DescriptorLength,
50 OUT VOID *Descriptor,
51 OUT UINT32 *Status
52 )
53{
54 EFI_USB_DEVICE_REQUEST DevReq;
55
56 ASSERT (UsbIo != NULL);
57 ASSERT (Descriptor != NULL);
58 ASSERT (Status != NULL);
59
60 ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
61
62 DevReq.RequestType = USB_DEV_GET_DESCRIPTOR_REQ_TYPE;
63 DevReq.Request = USB_REQ_GET_DESCRIPTOR;
64 DevReq.Value = Value;
65 DevReq.Index = Index;
66 DevReq.Length = DescriptorLength;
67
68 return UsbIo->UsbControlTransfer (
69 UsbIo,
70 &DevReq,
71 EfiUsbDataIn,
72 PcdGet32 (PcdUsbTransferTimeoutValue),
73 Descriptor,
74 DescriptorLength,
75 Status
76 );
77}
78
79/**
80 Set the descriptor of the specified USB device.
81
82 Submit a USB set descriptor request for the USB device specified by UsbIo,
83 Value, and Index, and set the descriptor using the buffer specified by DesriptorLength
84 and Descriptor. The status of the transfer is returned in Status.
85 If UsbIo is NULL, then ASSERT().
86 If Descriptor is NULL, then ASSERT().
87 If Status is NULL, then ASSERT().
88
89 @param UsbIo A pointer to the USB I/O Protocol instance for the specific USB target.
90 @param Value The device request value.
91 @param Index The device request index.
92 @param DescriptorLength The size, in bytes, of Descriptor.
93 @param Descriptor A pointer to the descriptor buffer to set.
94 @param Status A pointer to the status of the transfer.
95
96 @retval EFI_SUCCESS The request executed successfully.
97 @retval EFI_TIMEOUT A timeout occurred executing the request.
98 @retval EFI_DEVICE_ERROR The request failed due to a device error.
99 The transfer status is returned in Status.
100
101**/
102EFI_STATUS
103EFIAPI
104UsbSetDescriptor (
105 IN EFI_USB_IO_PROTOCOL *UsbIo,
106 IN UINT16 Value,
107 IN UINT16 Index,
108 IN UINT16 DescriptorLength,
109 IN VOID *Descriptor,
110 OUT UINT32 *Status
111 )
112{
113 EFI_USB_DEVICE_REQUEST DevReq;
114
115 ASSERT (UsbIo != NULL);
116 ASSERT (Descriptor != NULL);
117 ASSERT (Status != NULL);
118
119 ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
120
121 DevReq.RequestType = USB_DEV_SET_DESCRIPTOR_REQ_TYPE;
122 DevReq.Request = USB_REQ_SET_DESCRIPTOR;
123 DevReq.Value = Value;
124 DevReq.Index = Index;
125 DevReq.Length = DescriptorLength;
126
127 return UsbIo->UsbControlTransfer (
128 UsbIo,
129 &DevReq,
130 EfiUsbDataOut,
131 PcdGet32 (PcdUsbTransferTimeoutValue),
132 Descriptor,
133 DescriptorLength,
134 Status
135 );
136}
137
138/**
139 Get the interface setting of the specified USB device.
140
141 Submit a USB get interface request for the USB device specified by UsbIo,
142 and Interface, and place the result in the buffer specified by AlternateSetting.
143 The status of the transfer is returned in Status.
144 If UsbIo is NULL, then ASSERT().
145 If AlternateSetting is NULL, then ASSERT().
146 If Status is NULL, then ASSERT().
147
148 @param UsbIo A pointer to the USB I/O Protocol instance for the specific USB target.
149 @param Interface The interface index value.
150 @param AlternateSetting A pointer to the alternate setting to be retrieved.
151 @param Status A pointer to the status of the transfer.
152
153 @retval EFI_SUCCESS The request executed successfully.
154 @retval EFI_TIMEOUT A timeout occurred executing the request.
155 @retval EFI_DEVICE_ERROR The request failed due to a device error.
156 The transfer status is returned in Status.
157
158**/
159EFI_STATUS
160EFIAPI
161UsbGetInterface (
162 IN EFI_USB_IO_PROTOCOL *UsbIo,
163 IN UINT16 Interface,
164 OUT UINT16 *AlternateSetting,
165 OUT UINT32 *Status
166 )
167{
168 EFI_USB_DEVICE_REQUEST DevReq;
169
170 ASSERT (UsbIo != NULL);
171 ASSERT (AlternateSetting != NULL);
172 ASSERT (Status != NULL);
173
174 *AlternateSetting = 0;
175
176 ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
177
178 DevReq.RequestType = USB_DEV_GET_INTERFACE_REQ_TYPE;
179 DevReq.Request = USB_REQ_GET_INTERFACE;
180 DevReq.Index = Interface;
181 DevReq.Length = 1;
182
183 return UsbIo->UsbControlTransfer (
184 UsbIo,
185 &DevReq,
186 EfiUsbDataIn,
187 PcdGet32 (PcdUsbTransferTimeoutValue),
188 AlternateSetting,
189 1,
190 Status
191 );
192}
193
194/**
195 Set the interface setting of the specified USB device.
196
197 Submit a USB set interface request for the USB device specified by UsbIo, and
198 Interface, and set the alternate setting to the value specified by AlternateSetting.
199 The status of the transfer is returned in Status.
200 If UsbIo is NULL, then ASSERT().
201 If Status is NULL, then ASSERT().
202
203 @param UsbIo A pointer to the USB I/O Protocol instance for the specific USB target.
204 @param Interface The interface index value.
205 @param AlternateSetting The alternate setting to be set.
206 @param Status A pointer to the status of the transfer.
207
208 @retval EFI_SUCCESS The request executed successfully.
209 @retval EFI_TIMEOUT A timeout occurred executing the request.
210 @retval EFI_SUCCESS The request failed due to a device error.
211 The transfer status is returned in Status.
212
213**/
214EFI_STATUS
215EFIAPI
216UsbSetInterface (
217 IN EFI_USB_IO_PROTOCOL *UsbIo,
218 IN UINT16 Interface,
219 IN UINT16 AlternateSetting,
220 OUT UINT32 *Status
221 )
222{
223 EFI_USB_DEVICE_REQUEST DevReq;
224
225 ASSERT (UsbIo != NULL);
226 ASSERT (Status != NULL);
227
228 ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
229
230 DevReq.RequestType = USB_DEV_SET_INTERFACE_REQ_TYPE;
231 DevReq.Request = USB_REQ_SET_INTERFACE;
232 DevReq.Value = AlternateSetting;
233 DevReq.Index = Interface;
234
235 return UsbIo->UsbControlTransfer (
236 UsbIo,
237 &DevReq,
238 EfiUsbNoData,
239 PcdGet32 (PcdUsbTransferTimeoutValue),
240 NULL,
241 0,
242 Status
243 );
244}
245
246/**
247 Get the device configuration.
248
249 Submit a USB get configuration request for the USB device specified by UsbIo
250 and place the result in the buffer specified by ConfigurationValue. The status
251 of the transfer is returned in Status.
252 If UsbIo is NULL, then ASSERT().
253 If ConfigurationValue is NULL, then ASSERT().
254 If Status is NULL, then ASSERT().
255
256 @param UsbIo A pointer to the USB I/O Protocol instance for the specific USB target.
257 @param ConfigurationValue A pointer to the device configuration to be retrieved.
258 @param Status A pointer to the status of the transfer.
259
260 @retval EFI_SUCCESS The request executed successfully.
261 @retval EFI_TIMEOUT A timeout occurred executing the request.
262 @retval EFI_DEVICE_ERROR The request failed due to a device error.
263 The transfer status is returned in Status.
264
265**/
266EFI_STATUS
267EFIAPI
268UsbGetConfiguration (
269 IN EFI_USB_IO_PROTOCOL *UsbIo,
270 OUT UINT16 *ConfigurationValue,
271 OUT UINT32 *Status
272 )
273{
274 EFI_USB_DEVICE_REQUEST DevReq;
275
276 ASSERT (UsbIo != NULL);
277 ASSERT (ConfigurationValue != NULL);
278 ASSERT (Status != NULL);
279
280 *ConfigurationValue = 0;
281
282 ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
283
284 DevReq.RequestType = USB_DEV_GET_CONFIGURATION_REQ_TYPE;
285 DevReq.Request = USB_REQ_GET_CONFIG;
286 DevReq.Length = 1;
287
288 return UsbIo->UsbControlTransfer (
289 UsbIo,
290 &DevReq,
291 EfiUsbDataIn,
292 PcdGet32 (PcdUsbTransferTimeoutValue),
293 ConfigurationValue,
294 1,
295 Status
296 );
297}
298
299/**
300 Set the device configuration.
301
302 Submit a USB set configuration request for the USB device specified by UsbIo
303 and set the device configuration to the value specified by ConfigurationValue.
304 The status of the transfer is returned in Status.
305 If UsbIo is NULL, then ASSERT().
306 If Status is NULL, then ASSERT().
307
308 @param UsbIo A pointer to the USB I/O Protocol instance for the specific USB target.
309 @param ConfigurationValue The device configuration value to be set.
310 @param Status A pointer to the status of the transfer.
311
312 @retval EFI_SUCCESS The request executed successfully.
313 @retval EFI_TIMEOUT A timeout occurred executing the request.
314 @retval EFI_DEVICE_ERROR The request failed due to a device error.
315 The transfer status is returned in Status.
316
317**/
318EFI_STATUS
319EFIAPI
320UsbSetConfiguration (
321 IN EFI_USB_IO_PROTOCOL *UsbIo,
322 IN UINT16 ConfigurationValue,
323 OUT UINT32 *Status
324 )
325{
326 EFI_USB_DEVICE_REQUEST DevReq;
327
328 ASSERT (UsbIo != NULL);
329 ASSERT (Status != NULL);
330
331 ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
332
333 DevReq.RequestType = USB_DEV_SET_CONFIGURATION_REQ_TYPE;
334 DevReq.Request = USB_REQ_SET_CONFIG;
335 DevReq.Value = ConfigurationValue;
336
337 return UsbIo->UsbControlTransfer (
338 UsbIo,
339 &DevReq,
340 EfiUsbNoData,
341 PcdGet32 (PcdUsbTransferTimeoutValue),
342 NULL,
343 0,
344 Status
345 );
346}
347
348/**
349 Set the specified feature of the specified device.
350
351 Submit a USB set device feature request for the USB device specified by UsbIo,
352 Recipient, and Target to the value specified by Value. The status of the
353 transfer is returned in Status.
354 If UsbIo is NULL, then ASSERT().
355 If Status is NULL, then ASSERT().
356
357 @param UsbIo A pointer to the USB I/O Protocol instance for the specific USB target.
358 @param Recipient The USB data recipient type (i.e. Device, Interface, Endpoint).
359 Type USB_TYPES_DEFINITION is defined in the MDE Package Industry
360 Standard include file Usb.h.
361 @param Value The value of the feature to be set.
362 @param Target The index of the device to be set.
363 @param Status A pointer to the status of the transfer.
364
365 @retval EFI_SUCCESS The request executed successfully.
366 @retval EFI_TIMEOUT A timeout occurred executing the request.
367 @retval EFI_DEVICE_ERROR The request failed due to a device error.
368 The transfer status is returned in Status.
369
370**/
371EFI_STATUS
372EFIAPI
373UsbSetFeature (
374 IN EFI_USB_IO_PROTOCOL *UsbIo,
375 IN USB_TYPES_DEFINITION Recipient,
376 IN UINT16 Value,
377 IN UINT16 Target,
378 OUT UINT32 *Status
379 )
380{
381 EFI_USB_DEVICE_REQUEST DevReq;
382
383 ASSERT (UsbIo != NULL);
384 ASSERT (Status != NULL);
385
386 ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
387
388 switch (Recipient) {
389 case USB_TARGET_DEVICE:
390 DevReq.RequestType = USB_DEV_SET_FEATURE_REQ_TYPE_D;
391 break;
392
393 case USB_TARGET_INTERFACE:
394 DevReq.RequestType = USB_DEV_SET_FEATURE_REQ_TYPE_I;
395 break;
396
397 case USB_TARGET_ENDPOINT:
398 DevReq.RequestType = USB_DEV_SET_FEATURE_REQ_TYPE_E;
399 break;
400
401 default:
402 break;
403 }
404
405 //
406 // Fill device request, see USB1.1 spec
407 //
408 DevReq.Request = USB_REQ_SET_FEATURE;
409 DevReq.Value = Value;
410 DevReq.Index = Target;
411
412 return UsbIo->UsbControlTransfer (
413 UsbIo,
414 &DevReq,
415 EfiUsbNoData,
416 PcdGet32 (PcdUsbTransferTimeoutValue),
417 NULL,
418 0,
419 Status
420 );
421}
422
423/**
424 Clear the specified feature of the specified device.
425
426 Submit a USB clear device feature request for the USB device specified by UsbIo,
427 Recipient, and Target to the value specified by Value. The status of the transfer
428 is returned in Status.
429 If UsbIo is NULL, then ASSERT().
430 If Status is NULL, then ASSERT().
431
432 @param UsbIo A pointer to the USB I/O Protocol instance for the specific USB target.
433 @param Recipient The USB data recipient type (i.e. Device, Interface, Endpoint).
434 Type USB_TYPES_DEFINITION is defined in the MDE Package Industry Standard
435 include file Usb.h.
436 @param Value The value of the feature to be cleared.
437 @param Target The index of the device to be cleared.
438 @param Status A pointer to the status of the transfer.
439
440 @retval EFI_SUCCESS The request executed successfully.
441 @retval EFI_TIMEOUT A timeout occurred executing the request.
442 @retval EFI_DEVICE_ERROR The request failed due to a device error.
443 The transfer status is returned in Status.
444
445**/
446EFI_STATUS
447EFIAPI
448UsbClearFeature (
449 IN EFI_USB_IO_PROTOCOL *UsbIo,
450 IN USB_TYPES_DEFINITION Recipient,
451 IN UINT16 Value,
452 IN UINT16 Target,
453 OUT UINT32 *Status
454 )
455{
456 EFI_USB_DEVICE_REQUEST DevReq;
457
458 ASSERT (UsbIo != NULL);
459 ASSERT (Status != NULL);
460
461 ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
462
463 switch (Recipient) {
464 case USB_TARGET_DEVICE:
465 DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_D;
466 break;
467
468 case USB_TARGET_INTERFACE:
469 DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_I;
470 break;
471
472 case USB_TARGET_ENDPOINT:
473 DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_E;
474 break;
475
476 default:
477 break;
478 }
479
480 //
481 // Fill device request, see USB1.1 spec
482 //
483 DevReq.Request = USB_REQ_CLEAR_FEATURE;
484 DevReq.Value = Value;
485 DevReq.Index = Target;
486
487 return UsbIo->UsbControlTransfer (
488 UsbIo,
489 &DevReq,
490 EfiUsbNoData,
491 PcdGet32 (PcdUsbTransferTimeoutValue),
492 NULL,
493 0,
494 Status
495 );
496}
497
498/**
499 Get the status of the specified device.
500
501 Submit a USB device get status request for the USB device specified by UsbIo,
502 Recipient, and Target and place the result in the buffer specified by DeviceStatus.
503 The status of the transfer is returned in Status.
504 If UsbIo is NULL, then ASSERT().
505 If DeviceStatus is NULL, then ASSERT().
506 If Status is NULL, then ASSERT().
507
508 @param UsbIo A pointer to the USB I/O Protocol instance for the specific USB target.
509 @param Recipient The USB data recipient type (i.e. Device, Interface, Endpoint).
510 Type USB_TYPES_DEFINITION is defined in the MDE Package Industry Standard
511 include file Usb.h.
512 @param Target The index of the device to be get the status of.
513 @param DeviceStatus A pointer to the device status to be retrieved.
514 @param Status A pointer to the status of the transfer.
515
516 @retval EFI_SUCCESS The request executed successfully.
517 @retval EFI_TIMEOUT A timeout occurred executing the request.
518 @retval EFI_DEVICE_ERROR The request failed due to a device error.
519 The transfer status is returned in Status.
520
521**/
522EFI_STATUS
523EFIAPI
524UsbGetStatus (
525 IN EFI_USB_IO_PROTOCOL *UsbIo,
526 IN USB_TYPES_DEFINITION Recipient,
527 IN UINT16 Target,
528 OUT UINT16 *DeviceStatus,
529 OUT UINT32 *Status
530 )
531{
532 EFI_USB_DEVICE_REQUEST DevReq;
533
534 ASSERT (UsbIo != NULL);
535 ASSERT (DeviceStatus != NULL);
536 ASSERT (Status != NULL);
537
538 ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
539
540 switch (Recipient) {
541 case USB_TARGET_DEVICE:
542 DevReq.RequestType = USB_DEV_GET_STATUS_REQ_TYPE_D;
543 break;
544
545 case USB_TARGET_INTERFACE:
546 DevReq.RequestType = USB_DEV_GET_STATUS_REQ_TYPE_I;
547 break;
548
549 case USB_TARGET_ENDPOINT:
550 DevReq.RequestType = USB_DEV_GET_STATUS_REQ_TYPE_E;
551 break;
552
553 default:
554 break;
555 }
556
557 //
558 // Fill device request, see USB1.1 spec
559 //
560 DevReq.Request = USB_REQ_GET_STATUS;
561 DevReq.Value = 0;
562 DevReq.Index = Target;
563 DevReq.Length = 2;
564
565 return UsbIo->UsbControlTransfer (
566 UsbIo,
567 &DevReq,
568 EfiUsbDataIn,
569 PcdGet32 (PcdUsbTransferTimeoutValue),
570 DeviceStatus,
571 2,
572 Status
573 );
574}
575
576/**
577 Clear halt feature of the specified usb endpoint.
578
579 Retrieve the USB endpoint descriptor specified by UsbIo and EndPoint.
580 If the USB endpoint descriptor can not be retrieved, then return EFI_NOT_FOUND.
581 If the endpoint descriptor is found, then clear the halt feature of this USB endpoint.
582 The status of the transfer is returned in Status.
583 If UsbIo is NULL, then ASSERT().
584 If Status is NULL, then ASSERT().
585
586 @param UsbIo A pointer to the USB I/O Protocol instance for the specific USB target.
587 @param Endpoint The endpoint address.
588 @param Status A pointer to the status of the transfer.
589
590 @retval EFI_SUCCESS The request executed successfully.
591 @retval EFI_TIMEOUT A timeout occurred executing the request.
592 @retval EFI_DEVICE_ERROR The request failed due to a device error.
593 The transfer status is returned in Status.
594 @retval EFI_NOT_FOUND The specified USB endpoint descriptor can not be found
595
596**/
597EFI_STATUS
598EFIAPI
599UsbClearEndpointHalt (
600 IN EFI_USB_IO_PROTOCOL *UsbIo,
601 IN UINT8 Endpoint,
602 OUT UINT32 *Status
603 )
604{
605 EFI_STATUS Result;
606 EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
607 EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
608 UINT8 Index;
609
610 ASSERT (UsbIo != NULL);
611 ASSERT (Status != NULL);
612
613 ZeroMem (&EndpointDescriptor, sizeof (EFI_USB_ENDPOINT_DESCRIPTOR));
614 //
615 // First search the endpoint descriptor for that endpoint addr
616 //
617 Result = UsbIo->UsbGetInterfaceDescriptor (
618 UsbIo,
619 &InterfaceDescriptor
620 );
621 if (EFI_ERROR (Result)) {
622 return Result;
623 }
624
625 for (Index = 0; Index < InterfaceDescriptor.NumEndpoints; Index++) {
626 Result = UsbIo->UsbGetEndpointDescriptor (
627 UsbIo,
628 Index,
629 &EndpointDescriptor
630 );
631 if (EFI_ERROR (Result)) {
632 continue;
633 }
634
635 if (EndpointDescriptor.EndpointAddress == Endpoint) {
636 break;
637 }
638 }
639
640 if (Index == InterfaceDescriptor.NumEndpoints) {
641 //
642 // No such endpoint
643 //
644 return EFI_NOT_FOUND;
645 }
646
647 Result = UsbClearFeature (
648 UsbIo,
649 USB_TARGET_ENDPOINT,
650 USB_FEATURE_ENDPOINT_HALT,
651 EndpointDescriptor.EndpointAddress,
652 Status
653 );
654
655 return Result;
656}
657
658/**
659 Global library data initialization.
660
661 Library public functions' input is the instance of UsbIo protocol. Check if the global
662 data relevant to the UsbIo. If not, read the device and update the global data.
663
664 @param UsbIo The instance of EFI_USB_IO_PROTOCOL.
665
666 @retval EFI_SUCCESS The global data is updated.
667 @retval EFI_NOT_FOUND The UsbIo configuration was not found.
668
669**/
670static
671EFI_STATUS
672InitUsbConfigDescriptorData (
673 EFI_USB_IO_PROTOCOL *UsbIo
674 )
675{
676 EFI_STATUS Status;
677 EFI_USB_DEVICE_DESCRIPTOR DevDesc;
678 EFI_USB_CONFIG_DESCRIPTOR CnfDesc;
679 UINT8 ConfigNum;
680 UINT8 ConfigValue;
681 UINT32 UsbStatus;
682
683 //
684 // Get UsbIo device and configuration descriptors.
685 //
686 Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
687 ASSERT_EFI_ERROR (Status);
688
689 Status = UsbIo->UsbGetConfigDescriptor (UsbIo, &CnfDesc);
690 ASSERT_EFI_ERROR (Status);
691
692 if (mConfigData != NULL) {
693 if ( (CompareMem (&DevDesc, &mDeviceDescriptor, sizeof (EFI_USB_DEVICE_DESCRIPTOR)) == 0)
694 && (CompareMem (&CnfDesc, mConfigData, sizeof (EFI_USB_CONFIG_DESCRIPTOR)) == 0))
695 {
696 return EFI_SUCCESS;
697 }
698
699 gBS->FreePool (mConfigData);
700 mConfigData = NULL;
701 }
702
703 CopyMem (&mDeviceDescriptor, &DevDesc, sizeof (EFI_USB_DEVICE_DESCRIPTOR));
704
705 //
706 // Examine device with multiple configurations: find configuration index of UsbIo config descriptor.
707 //
708 // Use EFI_USB_DEVICE_DESCRIPTOR.NumConfigurations to loop through configuration descriptors, match
709 // EFI_USB_CONFIG_DESCRIPTOR.ConfigurationValue to the configuration value reported by UsbIo->UsbGetConfigDescriptor.
710 // The index of the matched configuration is used in wValue of the following GET_DESCRIPTOR request.
711 //
712 ConfigValue = CnfDesc.ConfigurationValue;
713 for (ConfigNum = 0; ConfigNum < DevDesc.NumConfigurations; ConfigNum++) {
714 Status = UsbGetDescriptor (
715 UsbIo,
716 (USB_DESC_TYPE_CONFIG << 8) | ConfigNum,
717 0,
718 sizeof (EFI_USB_CONFIG_DESCRIPTOR),
719 &CnfDesc,
720 &UsbStatus
721 );
722 ASSERT_EFI_ERROR (Status);
723
724 if (CnfDesc.ConfigurationValue == ConfigValue) {
725 break;
726 }
727 }
728
729 ASSERT (ConfigNum < DevDesc.NumConfigurations);
730 if (ConfigNum == DevDesc.NumConfigurations) {
731 return EFI_NOT_FOUND;
732 }
733
734 //
735 // ConfigNum has zero based index of the configuration that UsbIo belongs to. Use this index to retrieve
736 // full configuration descriptor data.
737 //
738 Status = gBS->AllocatePool (EfiBootServicesData, CnfDesc.TotalLength, (VOID **)&mConfigData);
739 ASSERT_EFI_ERROR (Status);
740
741 Status = UsbGetDescriptor (
742 UsbIo,
743 (USB_DESC_TYPE_CONFIG << 8) | ConfigNum,
744 0,
745 CnfDesc.TotalLength,
746 mConfigData,
747 &UsbStatus
748 );
749 ASSERT_EFI_ERROR (Status);
750
751 return Status;
752}
753
754/**
755 Find descriptor of a given type within data area pointed by mConfigData.
756
757 The following are the assumptions of the configuration descriptor layout:
758 - mConfigData is populated with the configuration data that contains USB interface referenced by UsbIo.
759 - Endpoint may have only one class specific descriptor that immediately follows the endpoint descriptor.
760
761 @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
762 @param[in] DescType Type of descriptor to look for.
763 @param[in] Setting Interface alternate setting.
764 @param[in] Index Index of the descriptor. This descriptor index is used to find a specific
765 descriptor (only for endpoint descriptors and class specific interface descriptors)
766 when several descriptors of the same type are implemented in a device. For other
767 descriptor types, a descriptor index of zero must be used.
768 @param[out] Data A pointer to the caller allocated Descriptor.
769
770 @retval EFI_SUCCESS Output parameters were updated successfully.
771 @retval EFI_UNSUPPORTED Setting is greater than the number of alternate settings in this interface.
772 @retval EFI_NOT_FOUND Index is greater than the number of descriptors of the requested type in this
773 interface.
774**/
775static
776EFI_STATUS
777FindUsbDescriptor (
778 EFI_USB_IO_PROTOCOL *UsbIo,
779 UINT8 DescType,
780 UINT16 Setting,
781 UINTN Index,
782 VOID **Data
783 )
784{
785 EFI_USB_INTERFACE_DESCRIPTOR IntfDesc;
786 EFI_STATUS Status;
787 UINT8 *BufferPtr;
788 UINT8 *BufferEnd;
789 UINT8 *ConfigEnd;
790 UINTN Idx;
791
792 //
793 // Find the interface descriptor referenced by UsbIo in the current configuration
794 //
795 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IntfDesc);
796 ASSERT_EFI_ERROR (Status);
797
798 ConfigEnd = mConfigData + ((EFI_USB_CONFIG_DESCRIPTOR *)mConfigData)->TotalLength;
799
800 for (BufferPtr = mConfigData; BufferPtr < ConfigEnd; BufferPtr += BufferPtr[0]) {
801 if (BufferPtr[1] == USB_DESC_TYPE_INTERFACE) {
802 if ((BufferPtr[2] == IntfDesc.InterfaceNumber) && (BufferPtr[3] == (UINT8)Setting)) {
803 break;
804 }
805 }
806 }
807
808 if (BufferPtr >= ConfigEnd) {
809 return EFI_UNSUPPORTED;
810 }
811
812 //
813 // Found the beginning of the interface, find the ending
814 //
815 for (BufferEnd = BufferPtr + BufferPtr[0]; BufferEnd < ConfigEnd; BufferEnd += BufferEnd[0]) {
816 if (BufferEnd[1] == USB_DESC_TYPE_INTERFACE) {
817 break;
818 }
819 }
820
821 Idx = 0;
822
823 if (DescType == USB_DESC_TYPE_INTERFACE) {
824 *Data = BufferPtr;
825 return EFI_SUCCESS;
826 }
827
828 if ((DescType == USB_DESC_TYPE_ENDPOINT) || (DescType == USB_DESC_TYPE_CS_ENDPOINT)) {
829 while (BufferPtr < BufferEnd) {
830 BufferPtr += BufferPtr[0];
831 if (BufferPtr[1] == USB_DESC_TYPE_ENDPOINT) {
832 if (Idx == Index) {
833 if (DescType == USB_DESC_TYPE_CS_ENDPOINT) {
834 BufferPtr += BufferPtr[0];
835 if (BufferPtr[1] != USB_DESC_TYPE_CS_ENDPOINT) {
836 break;
837 }
838 }
839
840 *Data = BufferPtr;
841 return EFI_SUCCESS;
842 }
843
844 Idx++;
845 }
846 }
847 }
848
849 if (DescType == USB_DESC_TYPE_CS_INTERFACE) {
850 while (BufferPtr < BufferEnd) {
851 BufferPtr += BufferPtr[0];
852 if (BufferPtr[1] == USB_DESC_TYPE_CS_INTERFACE) {
853 if (Idx == Index) {
854 *Data = BufferPtr;
855 return EFI_SUCCESS;
856 }
857
858 Idx++;
859 }
860 }
861 }
862
863 return EFI_NOT_FOUND;
864}
865
866/**
867 Retrieve the number of class specific interface descriptors.
868
869 @param[in] Data A pointer to the USB interface descriptor that may contain class code descriptors.
870
871 @retval UINT8 Number of the class code interface descriptors.
872
873**/
874static
875UINT8
876FindNumberOfCsInterfaces (
877 VOID *Data
878 )
879{
880 UINT8 *Buffer;
881 UINT8 *ConfigEnd;
882 UINT8 Index;
883
884 Buffer = Data;
885 ConfigEnd = mConfigData + ((EFI_USB_CONFIG_DESCRIPTOR *)mConfigData)->TotalLength;
886
887 Index = 0;
888
889 for (Buffer += Buffer[0]; Buffer < ConfigEnd; Buffer += Buffer[0]) {
890 if (Buffer[1] == USB_DESC_TYPE_INTERFACE) {
891 break;
892 }
893
894 if (Buffer[1] == USB_DESC_TYPE_CS_INTERFACE) {
895 Index++;
896 }
897 }
898
899 return Index;
900}
901
902/**
903 Retrieve the interface descriptor details from the interface setting.
904
905 This is an extended version of UsbIo->GetInterfaceDescriptor. It returns the interface
906 descriptor for an alternate setting of the interface without executing SET_INTERFACE
907 transfer. It also returns the number of class specific interfaces.
908 AlternateSetting parameter is the zero-based interface descriptor index that is used in USB
909 interface descriptor as USB_INTERFACE_DESCRIPTOR.AlternateSetting.
910
911
912 @param[in] This A pointer to the EFI_USB_IO_PROTOCOL instance.
913 @param[in] AlternateSetting Interface alternate setting.
914 @param[out] Descriptor The caller allocated buffer to return the contents of the Interface descriptor.
915 @param[out] CsInterfaceNumber Number of class specific interfaces for this interface setting.
916
917 @retval EFI_SUCCESS Output parameters were updated successfully.
918 @retval EFI_INVALID_PARAMETER Descriptor or CsInterfaceNumber is NULL.
919 @retval EFI_UNSUPPORTED AlternateSetting is greater than the number of alternate settings in this interface.
920 @retval EFI_DEVICE_ERROR Error reading device data.
921
922**/
923EFI_STATUS
924EFIAPI
925UsbGetInterfaceDescriptorSetting (
926 IN EFI_USB_IO_PROTOCOL *This,
927 IN UINT16 AlternateSetting,
928 OUT EFI_USB_INTERFACE_DESCRIPTOR *Descriptor,
929 OUT UINTN *CsInterfacesNumber
930 )
931{
932 EFI_STATUS Status;
933 VOID *Data;
934 EFI_TPL OldTpl;
935
936 if ((Descriptor == NULL) || (CsInterfacesNumber == NULL)) {
937 return EFI_INVALID_PARAMETER;
938 }
939
940 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
941
942 Status = InitUsbConfigDescriptorData (This);
943 if (EFI_ERROR (Status)) {
944 Status = EFI_DEVICE_ERROR;
945 goto ON_EXIT;
946 }
947
948 Status = FindUsbDescriptor (This, USB_DESC_TYPE_INTERFACE, AlternateSetting, 0, &Data);
949 if (EFI_ERROR (Status)) {
950 goto ON_EXIT;
951 }
952
953 *CsInterfacesNumber = FindNumberOfCsInterfaces (Data);
954 CopyMem (Descriptor, Data, sizeof (EFI_USB_INTERFACE_DESCRIPTOR));
955
956ON_EXIT:
957 gBS->RestoreTPL (OldTpl);
958 return Status;
959}
960
961/**
962 Retrieve the endpoint descriptor from the interface setting.
963
964 This is an extended version of UsbIo->GetEndpointDescriptor. It returns the endpoint
965 descriptor for an alternate setting of a given interface.
966 AlternateSetting parameter is the zero-based interface descriptor index that is used in USB
967 interface descriptor as USB_INTERFACE_DESCRIPTOR.AlternateSetting.
968
969 Note: The total number of endpoints can be retrieved from the interface descriptor
970 returned by EDKII_USBIO_EXT_GET_INTERFACE_DESCRIPTOR function.
971
972 @param[in] This A pointer to the EFI_USB_IO_PROTOCOL instance.
973 @param[in] AlternateSetting Interface alternate setting.
974 @param[in] Index Index of the endpoint to retrieve. The valid range is 0..15.
975 @param[out] Descriptor A pointer to the caller allocated USB Interface Descriptor.
976
977 @retval EFI_SUCCESS Output parameters were updated successfully.
978 @retval EFI_INVALID_PARAMETER Descriptor is NULL.
979 @retval EFI_UNSUPPORTED AlternateSetting is greater than the number of alternate settings in this interface.
980 @retval EFI_NOT_FOUND Index is greater than the number of endpoints in this interface.
981 @retval EFI_DEVICE_ERROR Error reading device data.
982
983**/
984EFI_STATUS
985EFIAPI
986UsbGetEndpointDescriptorSetting (
987 IN EFI_USB_IO_PROTOCOL *This,
988 IN UINT16 AlternateSetting,
989 IN UINTN Index,
990 OUT EFI_USB_ENDPOINT_DESCRIPTOR *Descriptor
991 )
992{
993 EFI_STATUS Status;
994 VOID *Data;
995 EFI_TPL OldTpl;
996
997 if (Descriptor == NULL) {
998 return EFI_INVALID_PARAMETER;
999 }
1000
1001 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1002
1003 Status = InitUsbConfigDescriptorData (This);
1004 if (EFI_ERROR (Status)) {
1005 Status = EFI_DEVICE_ERROR;
1006 goto ON_EXIT;
1007 }
1008
1009 Status = FindUsbDescriptor (This, USB_DESC_TYPE_ENDPOINT, AlternateSetting, Index, &Data);
1010 if (EFI_ERROR (Status)) {
1011 goto ON_EXIT;
1012 }
1013
1014 CopyMem (Descriptor, Data, sizeof (EFI_USB_ENDPOINT_DESCRIPTOR));
1015
1016ON_EXIT:
1017 gBS->RestoreTPL (OldTpl);
1018 return Status;
1019}
1020
1021/**
1022 Retrieve class specific interface descriptor.
1023
1024 AlternateSetting parameter is the zero-based interface descriptor index that is used in USB
1025 interface descriptor as USB_INTERFACE_DESCRIPTOR.AlternateSetting.
1026
1027 @param[in] This A pointer to the EFI_USB_IO_PROTOCOL instance.
1028 @param[in] AlternateSetting Interface alternate setting.
1029 @param[in] Index Zero-based index of the class specific interface.
1030 @param[in][out] BufferSize On input, the size in bytes of the return Descriptor buffer.
1031 On output the size of data returned in Descriptor.
1032 @param[out] Descriptor The buffer to return the contents of the class specific interface descriptor. May
1033 be NULL with a zero BufferSize in order to determine the size buffer needed.
1034
1035 @retval EFI_SUCCESS Output parameters were updated successfully.
1036 @retval EFI_INVALID_PARAMETER BufferSize is NULL.
1037 Buffer is NULL and *BufferSize is not zero.
1038 @retval EFI_UNSUPPORTED AlternateSetting is greater than the number of alternate settings in this interface.
1039 @retval EFI_NOT_FOUND Index is greater than the number of class specific interfaces.
1040 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small for the result. BufferSize has been updated with the size
1041 needed to complete the request.
1042 @retval EFI_DEVICE_ERROR Error reading device data.
1043
1044**/
1045EFI_STATUS
1046EFIAPI
1047UsbGetCsInterfaceDescriptor (
1048 IN EFI_USB_IO_PROTOCOL *This,
1049 IN UINT16 AlternateSetting,
1050 IN UINTN Index,
1051 IN OUT UINTN *BufferSize,
1052 OUT VOID *Buffer
1053 )
1054{
1055 EFI_STATUS Status;
1056 VOID *Data;
1057 UINT8 DescLength;
1058 EFI_TPL OldTpl;
1059
1060 if ((BufferSize == NULL) || ((Buffer == NULL) && (*BufferSize != 0))) {
1061 return EFI_INVALID_PARAMETER;
1062 }
1063
1064 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1065
1066 Status = InitUsbConfigDescriptorData (This);
1067 if (EFI_ERROR (Status)) {
1068 Status = EFI_DEVICE_ERROR;
1069 goto ON_EXIT;
1070 }
1071
1072 Status = FindUsbDescriptor (This, USB_DESC_TYPE_CS_INTERFACE, AlternateSetting, Index, &Data);
1073 if (EFI_ERROR (Status)) {
1074 goto ON_EXIT;
1075 }
1076
1077 DescLength = ((UINT8 *)Data)[0];
1078
1079 if ((Buffer == NULL) || (DescLength > *BufferSize)) {
1080 *BufferSize = DescLength;
1081 Status = EFI_BUFFER_TOO_SMALL;
1082 goto ON_EXIT;
1083 }
1084
1085 CopyMem (Buffer, Data, DescLength);
1086
1087ON_EXIT:
1088 gBS->RestoreTPL (OldTpl);
1089 return Status;
1090}
1091
1092/**
1093 Retrieve class specific endpoint descriptor.
1094
1095 AlternateSetting parameter is the zero-based interface descriptor index that is used in USB
1096 interface descriptor as USB_INTERFACE_DESCRIPTOR.AlternateSetting.
1097
1098 @param[in] This A pointer to the EFI_USB_IO_PROTOCOL instance.
1099 @param[in] AlternateSetting Interface alternate setting.
1100 @param[in] Index Zero-based index of the non-zero endpoint.
1101 @param[in][out] BufferSize On input, the size in bytes of the return Descriptor buffer.
1102 On output the size of data returned in Descriptor.
1103 @param[out] Descriptor The buffer to return the contents of the class specific endpoint descriptor. May
1104 be NULL with a zero BufferSize in order to determine the size buffer needed.
1105
1106 @retval EFI_SUCCESS Output parameters were updated successfully.
1107 @retval EFI_INVALID_PARAMETER BufferSize is NULL.
1108 Buffer is NULL and *BufferSize is not zero.
1109 @retval EFI_UNSUPPORTED AlternateSetting is greater than the number of alternate settings in this interface.
1110 @retval EFI_NOT_FOUND Index is greater than the number of endpoints in this interface.
1111 Endpoint does not have class specific endpoint descriptor.
1112 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small for the result. BufferSize has been updated with the size
1113 needed to complete the request.
1114 @retval EFI_DEVICE_ERROR Error reading device data.
1115
1116**/
1117EFI_STATUS
1118EFIAPI
1119UsbGetCsEndpointDescriptor (
1120 IN EFI_USB_IO_PROTOCOL *This,
1121 IN UINT16 AlternateSetting,
1122 IN UINTN Index,
1123 IN OUT UINTN *BufferSize,
1124 OUT VOID *Buffer
1125 )
1126{
1127 EFI_STATUS Status;
1128 VOID *Data;
1129 UINT8 DescLength;
1130 EFI_TPL OldTpl;
1131
1132 if ((BufferSize == NULL) || ((Buffer == NULL) && (*BufferSize != 0))) {
1133 return EFI_INVALID_PARAMETER;
1134 }
1135
1136 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1137
1138 Status = InitUsbConfigDescriptorData (This);
1139 if (EFI_ERROR (Status)) {
1140 Status = EFI_DEVICE_ERROR;
1141 goto ON_EXIT;
1142 }
1143
1144 Status = FindUsbDescriptor (This, USB_DESC_TYPE_CS_ENDPOINT, AlternateSetting, Index, &Data);
1145 if (EFI_ERROR (Status)) {
1146 goto ON_EXIT;
1147 }
1148
1149 DescLength = ((UINT8 *)Data)[0];
1150
1151 if ((Buffer == NULL) || (DescLength > *BufferSize)) {
1152 *BufferSize = DescLength;
1153 Status = EFI_BUFFER_TOO_SMALL;
1154 goto ON_EXIT;
1155 }
1156
1157 CopyMem (Buffer, Data, DescLength);
1158
1159ON_EXIT:
1160 gBS->RestoreTPL (OldTpl);
1161 return Status;
1162}
1163
1164/**
1165 Destructor frees memory which was allocated by the library functions.
1166
1167 @param ImageHandle Handle that identifies the image to be unloaded.
1168 @param SystemTable The system table.
1169
1170 @retval EFI_SUCCESS The image has been unloaded.
1171
1172**/
1173EFI_STATUS
1174EFIAPI
1175UefiUsbLibDestructor (
1176 IN EFI_HANDLE ImageHandle,
1177 IN EFI_SYSTEM_TABLE *SystemTable
1178 )
1179{
1180 if (mConfigData != NULL) {
1181 gBS->FreePool (mConfigData);
1182 }
1183
1184 return EFI_SUCCESS;
1185}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette