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   SPDX-License-Identifier: BSD-2-Clause-Patent
8 
9 **/
10 
11 #include "UefiUsbLibInternal.h"
12 
13 
14 /**
15   Get the descriptor of the specified USB device.
16 
17   Submit a USB get descriptor request for the USB device specified by UsbIo, Value,
18   and Index, and return the descriptor in the buffer specified by Descriptor.
19   The status of the transfer is returned in Status.
20   If UsbIo is NULL, then ASSERT().
21   If Descriptor is NULL, then ASSERT().
22   If Status is NULL, then ASSERT().
23 
24   @param  UsbIo             A pointer to the USB I/O Protocol instance for the specific USB target.
25   @param  Value             The device request value.
26   @param  Index             The device request index.
27   @param  DescriptorLength  The size, in bytes, of Descriptor.
28   @param  Descriptor        A pointer to the descriptor buffer to get.
29   @param  Status            A pointer to the status of the transfer.
30 
31   @retval EFI_SUCCESS           The request executed successfully.
32   @retval EFI_OUT_OF_RESOURCES  The request could not be completed because the
33                                 buffer specified by DescriptorLength and Descriptor
34                                 is not large enough to hold the result of the request.
35   @retval EFI_TIMEOUT           A timeout occurred executing the request.
36   @retval EFI_DEVICE_ERROR      The request failed due to a device error. The transfer
37                                 status is returned in Status.
38 
39 **/
40 EFI_STATUS
41 EFIAPI
UsbGetDescriptor(IN EFI_USB_IO_PROTOCOL * UsbIo,IN UINT16 Value,IN UINT16 Index,IN UINT16 DescriptorLength,OUT VOID * Descriptor,OUT UINT32 * Status)42 UsbGetDescriptor (
43   IN  EFI_USB_IO_PROTOCOL     *UsbIo,
44   IN  UINT16                  Value,
45   IN  UINT16                  Index,
46   IN  UINT16                  DescriptorLength,
47   OUT VOID                    *Descriptor,
48   OUT UINT32                  *Status
49   )
50 {
51   EFI_USB_DEVICE_REQUEST  DevReq;
52 
53   ASSERT (UsbIo != NULL);
54   ASSERT (Descriptor != NULL);
55   ASSERT (Status != NULL);
56 
57   ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
58 
59   DevReq.RequestType  = USB_DEV_GET_DESCRIPTOR_REQ_TYPE;
60   DevReq.Request      = USB_REQ_GET_DESCRIPTOR;
61   DevReq.Value        = Value;
62   DevReq.Index        = Index;
63   DevReq.Length       = DescriptorLength;
64 
65   return UsbIo->UsbControlTransfer (
66                   UsbIo,
67                   &DevReq,
68                   EfiUsbDataIn,
69                   PcdGet32 (PcdUsbTransferTimeoutValue),
70                   Descriptor,
71                   DescriptorLength,
72                   Status
73                   );
74 }
75 
76 
77 /**
78   Set the descriptor of the specified USB device.
79 
80   Submit a USB set descriptor request for the USB device specified by UsbIo,
81   Value, and Index, and set the descriptor using the buffer specified by DesriptorLength
82   and Descriptor.  The status of the transfer is returned in Status.
83   If UsbIo is NULL, then ASSERT().
84   If Descriptor is NULL, then ASSERT().
85   If Status is NULL, then ASSERT().
86 
87   @param  UsbIo             A pointer to the USB I/O Protocol instance for the specific USB target.
88   @param  Value             The device request value.
89   @param  Index             The device request index.
90   @param  DescriptorLength  The size, in bytes, of Descriptor.
91   @param  Descriptor        A pointer to the descriptor buffer to set.
92   @param  Status            A pointer to the status of the transfer.
93 
94   @retval  EFI_SUCCESS       The request executed successfully.
95   @retval  EFI_TIMEOUT       A timeout occurred executing the request.
96   @retval  EFI_DEVICE_ERROR  The request failed due to a device error.
97                              The transfer status is returned in Status.
98 
99 **/
100 EFI_STATUS
101 EFIAPI
UsbSetDescriptor(IN EFI_USB_IO_PROTOCOL * UsbIo,IN UINT16 Value,IN UINT16 Index,IN UINT16 DescriptorLength,IN VOID * Descriptor,OUT UINT32 * Status)102 UsbSetDescriptor (
103   IN  EFI_USB_IO_PROTOCOL     *UsbIo,
104   IN  UINT16                  Value,
105   IN  UINT16                  Index,
106   IN  UINT16                  DescriptorLength,
107   IN  VOID                    *Descriptor,
108   OUT UINT32                  *Status
109   )
110 {
111   EFI_USB_DEVICE_REQUEST  DevReq;
112 
113   ASSERT (UsbIo != NULL);
114   ASSERT (Descriptor != NULL);
115   ASSERT (Status != NULL);
116 
117   ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
118 
119   DevReq.RequestType  = USB_DEV_SET_DESCRIPTOR_REQ_TYPE;
120   DevReq.Request      = USB_REQ_SET_DESCRIPTOR;
121   DevReq.Value        = Value;
122   DevReq.Index        = Index;
123   DevReq.Length       = DescriptorLength;
124 
125   return UsbIo->UsbControlTransfer (
126                   UsbIo,
127                   &DevReq,
128                   EfiUsbDataOut,
129                   PcdGet32 (PcdUsbTransferTimeoutValue),
130                   Descriptor,
131                   DescriptorLength,
132                   Status
133                   );
134 }
135 
136 
137 /**
138   Get the interface setting of the specified USB device.
139 
140   Submit a USB get interface request for the USB device specified by UsbIo,
141   and Interface, and place the result in the buffer specified by AlternateSetting.
142   The status of the transfer is returned in Status.
143   If UsbIo is NULL, then ASSERT().
144   If AlternateSetting is NULL, then ASSERT().
145   If Status is NULL, then ASSERT().
146 
147   @param  UsbIo             A pointer to the USB I/O Protocol instance for the specific USB target.
148   @param  Interface         The interface index value.
149   @param  AlternateSetting  A pointer to the alternate setting to be retrieved.
150   @param  Status            A pointer to the status of the transfer.
151 
152   @retval EFI_SUCCESS       The request executed successfully.
153   @retval EFI_TIMEOUT       A timeout occurred executing the request.
154   @retval EFI_DEVICE_ERROR  The request failed due to a device error.
155                             The transfer status is returned in Status.
156 
157 **/
158 EFI_STATUS
159 EFIAPI
UsbGetInterface(IN EFI_USB_IO_PROTOCOL * UsbIo,IN UINT16 Interface,OUT UINT16 * AlternateSetting,OUT UINT32 * Status)160 UsbGetInterface (
161   IN  EFI_USB_IO_PROTOCOL     *UsbIo,
162   IN  UINT16                  Interface,
163   OUT UINT16                  *AlternateSetting,
164   OUT UINT32                  *Status
165   )
166 {
167   EFI_USB_DEVICE_REQUEST  DevReq;
168 
169   ASSERT (UsbIo != NULL);
170   ASSERT (AlternateSetting != NULL);
171   ASSERT (Status != NULL);
172 
173   *AlternateSetting = 0;
174 
175   ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
176 
177   DevReq.RequestType  = USB_DEV_GET_INTERFACE_REQ_TYPE;
178   DevReq.Request      = USB_REQ_GET_INTERFACE;
179   DevReq.Index        = Interface;
180   DevReq.Length       = 1;
181 
182   return UsbIo->UsbControlTransfer (
183                   UsbIo,
184                   &DevReq,
185                   EfiUsbDataIn,
186                   PcdGet32 (PcdUsbTransferTimeoutValue),
187                   AlternateSetting,
188                   1,
189                   Status
190                   );
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 **/
214 EFI_STATUS
215 EFIAPI
UsbSetInterface(IN EFI_USB_IO_PROTOCOL * UsbIo,IN UINT16 Interface,IN UINT16 AlternateSetting,OUT UINT32 * Status)216 UsbSetInterface (
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 /**
248   Get the device configuration.
249 
250   Submit a USB get configuration request for the USB device specified by UsbIo
251   and place the result in the buffer specified by ConfigurationValue. The status
252   of the transfer is returned in Status.
253   If UsbIo is NULL, then ASSERT().
254   If ConfigurationValue is NULL, then ASSERT().
255   If Status is NULL, then ASSERT().
256 
257   @param  UsbIo               A pointer to the USB I/O Protocol instance for the specific USB target.
258   @param  ConfigurationValue  A pointer to the device configuration to be retrieved.
259   @param  Status              A pointer to the status of the transfer.
260 
261   @retval EFI_SUCCESS        The request executed successfully.
262   @retval EFI_TIMEOUT        A timeout occurred executing the request.
263   @retval EFI_DEVICE_ERROR   The request failed due to a device error.
264                              The transfer status is returned in Status.
265 
266 **/
267 EFI_STATUS
268 EFIAPI
UsbGetConfiguration(IN EFI_USB_IO_PROTOCOL * UsbIo,OUT UINT16 * ConfigurationValue,OUT UINT32 * Status)269 UsbGetConfiguration (
270   IN  EFI_USB_IO_PROTOCOL     *UsbIo,
271   OUT UINT16                  *ConfigurationValue,
272   OUT UINT32                  *Status
273   )
274 {
275   EFI_USB_DEVICE_REQUEST  DevReq;
276 
277   ASSERT (UsbIo != NULL);
278   ASSERT (ConfigurationValue != NULL);
279   ASSERT (Status != NULL);
280 
281   *ConfigurationValue = 0;
282 
283   ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
284 
285   DevReq.RequestType  = USB_DEV_GET_CONFIGURATION_REQ_TYPE;
286   DevReq.Request      = USB_REQ_GET_CONFIG;
287   DevReq.Length       = 1;
288 
289   return UsbIo->UsbControlTransfer (
290                   UsbIo,
291                   &DevReq,
292                   EfiUsbDataIn,
293                   PcdGet32 (PcdUsbTransferTimeoutValue),
294                   ConfigurationValue,
295                   1,
296                   Status
297                   );
298 }
299 
300 
301 /**
302   Set the device configuration.
303 
304   Submit a USB set configuration request for the USB device specified by UsbIo
305   and set the device configuration to the value specified by ConfigurationValue.
306   The status of the transfer is returned in Status.
307   If UsbIo is NULL, then ASSERT().
308   If Status is NULL, then ASSERT().
309 
310   @param  UsbIo               A pointer to the USB I/O Protocol instance for the specific USB target.
311   @param  ConfigurationValue  The device configuration value to be set.
312   @param  Status              A pointer to the status of the transfer.
313 
314   @retval EFI_SUCCESS       The request executed successfully.
315   @retval EFI_TIMEOUT       A timeout occurred executing the request.
316   @retval EFI_DEVICE_ERROR  The request failed due to a device error.
317                             The transfer status is returned in Status.
318 
319 **/
320 EFI_STATUS
321 EFIAPI
UsbSetConfiguration(IN EFI_USB_IO_PROTOCOL * UsbIo,IN UINT16 ConfigurationValue,OUT UINT32 * Status)322 UsbSetConfiguration (
323   IN  EFI_USB_IO_PROTOCOL     *UsbIo,
324   IN  UINT16                  ConfigurationValue,
325   OUT UINT32                  *Status
326   )
327 {
328   EFI_USB_DEVICE_REQUEST  DevReq;
329 
330   ASSERT (UsbIo != NULL);
331   ASSERT (Status != NULL);
332 
333   ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
334 
335   DevReq.RequestType  = USB_DEV_SET_CONFIGURATION_REQ_TYPE;
336   DevReq.Request      = USB_REQ_SET_CONFIG;
337   DevReq.Value        = ConfigurationValue;
338 
339   return UsbIo->UsbControlTransfer (
340                   UsbIo,
341                   &DevReq,
342                   EfiUsbNoData,
343                   PcdGet32 (PcdUsbTransferTimeoutValue),
344                   NULL,
345                   0,
346                   Status
347                   );
348 }
349 
350 
351 /**
352   Set the specified feature of the specified device.
353 
354   Submit a USB set device feature request for the USB device specified by UsbIo,
355   Recipient, and Target to the value specified by Value.  The status of the
356   transfer is returned in Status.
357   If UsbIo is NULL, then ASSERT().
358   If Status is NULL, then ASSERT().
359 
360   @param  UsbIo      A pointer to the USB I/O Protocol instance for the specific USB target.
361   @param  Recipient  The USB data recipient type (i.e. Device, Interface, Endpoint).
362                      Type USB_TYPES_DEFINITION is defined in the MDE Package Industry
363                      Standard include file Usb.h.
364   @param  Value      The value of the feature to be set.
365   @param  Target     The index of the device to be set.
366   @param  Status     A pointer to the status of the transfer.
367 
368   @retval EFI_SUCCESS       The request executed successfully.
369   @retval EFI_TIMEOUT       A timeout occurred executing the request.
370   @retval EFI_DEVICE_ERROR  The request failed due to a device error.
371                             The transfer status is returned in Status.
372 
373 **/
374 EFI_STATUS
375 EFIAPI
UsbSetFeature(IN EFI_USB_IO_PROTOCOL * UsbIo,IN USB_TYPES_DEFINITION Recipient,IN UINT16 Value,IN UINT16 Target,OUT UINT32 * Status)376 UsbSetFeature (
377   IN  EFI_USB_IO_PROTOCOL     *UsbIo,
378   IN  USB_TYPES_DEFINITION    Recipient,
379   IN  UINT16                  Value,
380   IN  UINT16                  Target,
381   OUT UINT32                  *Status
382   )
383 {
384   EFI_USB_DEVICE_REQUEST  DevReq;
385 
386   ASSERT (UsbIo != NULL);
387   ASSERT (Status != NULL);
388 
389   ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
390 
391   switch (Recipient) {
392 
393   case USB_TARGET_DEVICE:
394     DevReq.RequestType = USB_DEV_SET_FEATURE_REQ_TYPE_D;
395     break;
396 
397   case USB_TARGET_INTERFACE:
398     DevReq.RequestType = USB_DEV_SET_FEATURE_REQ_TYPE_I;
399     break;
400 
401   case USB_TARGET_ENDPOINT:
402     DevReq.RequestType = USB_DEV_SET_FEATURE_REQ_TYPE_E;
403     break;
404 
405   default:
406     break;
407   }
408   //
409   // Fill device request, see USB1.1 spec
410   //
411   DevReq.Request  = USB_REQ_SET_FEATURE;
412   DevReq.Value    = Value;
413   DevReq.Index    = Target;
414 
415 
416   return UsbIo->UsbControlTransfer (
417                   UsbIo,
418                   &DevReq,
419                   EfiUsbNoData,
420                   PcdGet32 (PcdUsbTransferTimeoutValue),
421                   NULL,
422                   0,
423                   Status
424                   );
425 }
426 
427 
428 /**
429   Clear the specified feature of the specified device.
430 
431   Submit a USB clear device feature request for the USB device specified by UsbIo,
432   Recipient, and Target to the value specified by Value.  The status of the transfer
433   is returned in Status.
434   If UsbIo is NULL, then ASSERT().
435   If Status is NULL, then ASSERT().
436 
437   @param  UsbIo      A pointer to the USB I/O Protocol instance for the specific USB target.
438   @param  Recipient  The USB data recipient type (i.e. Device, Interface, Endpoint).
439                      Type USB_TYPES_DEFINITION is defined in the MDE Package Industry Standard
440                      include file Usb.h.
441   @param  Value      The value of the feature to be cleared.
442   @param  Target     The index of the device to be cleared.
443   @param  Status     A pointer to the status of the transfer.
444 
445   @retval EFI_SUCCESS       The request executed successfully.
446   @retval EFI_TIMEOUT       A timeout occurred executing the request.
447   @retval EFI_DEVICE_ERROR  The request failed due to a device error.
448                             The transfer status is returned in Status.
449 
450 **/
451 EFI_STATUS
452 EFIAPI
UsbClearFeature(IN EFI_USB_IO_PROTOCOL * UsbIo,IN USB_TYPES_DEFINITION Recipient,IN UINT16 Value,IN UINT16 Target,OUT UINT32 * Status)453 UsbClearFeature (
454   IN  EFI_USB_IO_PROTOCOL     *UsbIo,
455   IN  USB_TYPES_DEFINITION    Recipient,
456   IN  UINT16                  Value,
457   IN  UINT16                  Target,
458   OUT UINT32                  *Status
459   )
460 {
461   EFI_USB_DEVICE_REQUEST  DevReq;
462 
463   ASSERT (UsbIo != NULL);
464   ASSERT (Status != NULL);
465 
466 
467   ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
468 
469   switch (Recipient) {
470 
471   case USB_TARGET_DEVICE:
472     DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_D;
473     break;
474 
475   case USB_TARGET_INTERFACE:
476     DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_I;
477     break;
478 
479   case USB_TARGET_ENDPOINT:
480     DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_E;
481     break;
482 
483   default:
484     break;
485   }
486   //
487   // Fill device request, see USB1.1 spec
488   //
489   DevReq.Request  = USB_REQ_CLEAR_FEATURE;
490   DevReq.Value    = Value;
491   DevReq.Index    = Target;
492 
493 
494   return UsbIo->UsbControlTransfer (
495                   UsbIo,
496                   &DevReq,
497                   EfiUsbNoData,
498                   PcdGet32 (PcdUsbTransferTimeoutValue),
499                   NULL,
500                   0,
501                   Status
502                   );
503 }
504 
505 
506 /**
507   Get the status of the specified device.
508 
509   Submit a USB device get status request for the USB device specified by UsbIo,
510   Recipient, and Target and place the result in the buffer specified by DeviceStatus.
511   The status of the transfer is returned in Status.
512   If UsbIo is NULL, then ASSERT().
513   If DeviceStatus is NULL, then ASSERT().
514   If Status is NULL, then ASSERT().
515 
516   @param  UsbIo         A pointer to the USB I/O Protocol instance for the specific USB target.
517   @param  Recipient     The USB data recipient type (i.e. Device, Interface, Endpoint).
518                         Type USB_TYPES_DEFINITION is defined in the MDE Package Industry Standard
519                         include file Usb.h.
520   @param  Target        The index of the device to be get the status of.
521   @param  DeviceStatus  A pointer to the device status to be retrieved.
522   @param  Status        A pointer to the status of the transfer.
523 
524   @retval EFI_SUCCESS       The request executed successfully.
525   @retval EFI_TIMEOUT       A timeout occurred executing the request.
526   @retval EFI_DEVICE_ERROR  The request failed due to a device error.
527                             The transfer status is returned in Status.
528 
529 **/
530 EFI_STATUS
531 EFIAPI
UsbGetStatus(IN EFI_USB_IO_PROTOCOL * UsbIo,IN USB_TYPES_DEFINITION Recipient,IN UINT16 Target,OUT UINT16 * DeviceStatus,OUT UINT32 * Status)532 UsbGetStatus (
533   IN  EFI_USB_IO_PROTOCOL     *UsbIo,
534   IN  USB_TYPES_DEFINITION    Recipient,
535   IN  UINT16                  Target,
536   OUT UINT16                  *DeviceStatus,
537   OUT UINT32                  *Status
538   )
539 {
540   EFI_USB_DEVICE_REQUEST  DevReq;
541 
542   ASSERT (UsbIo != NULL);
543   ASSERT (DeviceStatus != NULL);
544   ASSERT (Status != NULL);
545 
546   ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
547 
548   switch (Recipient) {
549 
550   case USB_TARGET_DEVICE:
551     DevReq.RequestType = USB_DEV_GET_STATUS_REQ_TYPE_D;
552     break;
553 
554   case USB_TARGET_INTERFACE:
555     DevReq.RequestType = USB_DEV_GET_STATUS_REQ_TYPE_I;
556     break;
557 
558   case USB_TARGET_ENDPOINT:
559     DevReq.RequestType = USB_DEV_GET_STATUS_REQ_TYPE_E;
560     break;
561 
562   default:
563     break;
564   }
565   //
566   // Fill device request, see USB1.1 spec
567   //
568   DevReq.Request  = USB_REQ_GET_STATUS;
569   DevReq.Value    = 0;
570   DevReq.Index    = Target;
571   DevReq.Length   = 2;
572 
573   return UsbIo->UsbControlTransfer (
574                   UsbIo,
575                   &DevReq,
576                   EfiUsbDataIn,
577                   PcdGet32 (PcdUsbTransferTimeoutValue),
578                   DeviceStatus,
579                   2,
580                   Status
581                   );
582 }
583 
584 
585 /**
586   Clear halt feature of the specified usb endpoint.
587 
588   Retrieve the USB endpoint descriptor specified by UsbIo and EndPoint.
589   If the USB endpoint descriptor can not be retrieved, then return EFI_NOT_FOUND.
590   If the endpoint descriptor is found, then clear the halt feature of this USB endpoint.
591   The status of the transfer is returned in Status.
592   If UsbIo is NULL, then ASSERT().
593   If Status is NULL, then ASSERT().
594 
595   @param  UsbIo     A pointer to the USB I/O Protocol instance for the specific USB target.
596   @param  Endpoint  The endpoint address.
597   @param  Status    A pointer to the status of the transfer.
598 
599   @retval EFI_SUCCESS       The request executed successfully.
600   @retval EFI_TIMEOUT       A timeout occurred executing the request.
601   @retval EFI_DEVICE_ERROR  The request failed due to a device error.
602                             The transfer status is returned in Status.
603   @retval EFI_NOT_FOUND     The specified USB endpoint descriptor can not be found
604 
605 **/
606 EFI_STATUS
607 EFIAPI
UsbClearEndpointHalt(IN EFI_USB_IO_PROTOCOL * UsbIo,IN UINT8 Endpoint,OUT UINT32 * Status)608 UsbClearEndpointHalt (
609   IN  EFI_USB_IO_PROTOCOL     *UsbIo,
610   IN  UINT8                   Endpoint,
611   OUT UINT32                  *Status
612   )
613 {
614   EFI_STATUS                    Result;
615   EFI_USB_ENDPOINT_DESCRIPTOR   EndpointDescriptor;
616   EFI_USB_INTERFACE_DESCRIPTOR  InterfaceDescriptor;
617   UINT8                         Index;
618 
619   ASSERT (UsbIo != NULL);
620   ASSERT (Status != NULL);
621 
622   ZeroMem (&EndpointDescriptor, sizeof (EFI_USB_ENDPOINT_DESCRIPTOR));
623   //
624   // First search the endpoint descriptor for that endpoint addr
625   //
626   Result = UsbIo->UsbGetInterfaceDescriptor (
627                     UsbIo,
628                     &InterfaceDescriptor
629                     );
630   if (EFI_ERROR (Result)) {
631     return Result;
632   }
633 
634   for (Index = 0; Index < InterfaceDescriptor.NumEndpoints; Index++) {
635     Result = UsbIo->UsbGetEndpointDescriptor (
636                       UsbIo,
637                       Index,
638                       &EndpointDescriptor
639                       );
640     if (EFI_ERROR (Result)) {
641       continue;
642     }
643 
644     if (EndpointDescriptor.EndpointAddress == Endpoint) {
645       break;
646     }
647   }
648 
649   if (Index == InterfaceDescriptor.NumEndpoints) {
650     //
651     // No such endpoint
652     //
653     return EFI_NOT_FOUND;
654   }
655 
656   Result = UsbClearFeature (
657             UsbIo,
658             USB_TARGET_ENDPOINT,
659             USB_FEATURE_ENDPOINT_HALT,
660             EndpointDescriptor.EndpointAddress,
661             Status
662             );
663 
664   return Result;
665 }
666