1 /** @file
2 The module is used to implement Usb Io PPI interfaces.
3 
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved. <BR>
5 
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 #include "UsbPeim.h"
11 #include "PeiUsbLib.h"
12 
13 /**
14   Submits control transfer to a target USB device.
15 
16   @param  PeiServices            The pointer of EFI_PEI_SERVICES.
17   @param  This                   The pointer of PEI_USB_IO_PPI.
18   @param  Request                USB device request to send.
19   @param  Direction              Specifies the data direction for the data stage.
20   @param  Timeout                Indicates the maximum timeout, in millisecond. If Timeout
21                                  is 0, then the caller must wait for the function to be
22                                  completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
23   @param  Data                   Data buffer to be transmitted or received from USB device.
24   @param  DataLength             The size (in bytes) of the data buffer.
25 
26   @retval EFI_SUCCESS            Transfer was completed successfully.
27   @retval EFI_OUT_OF_RESOURCES   The transfer failed due to lack of resources.
28   @retval EFI_INVALID_PARAMETER  Some parameters are invalid.
29   @retval EFI_TIMEOUT            Transfer failed due to timeout.
30   @retval EFI_DEVICE_ERROR       Transfer failed due to host controller or device error.
31 
32 **/
33 EFI_STATUS
34 EFIAPI
PeiUsbControlTransfer(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_IO_PPI * This,IN EFI_USB_DEVICE_REQUEST * Request,IN EFI_USB_DATA_DIRECTION Direction,IN UINT32 Timeout,IN OUT VOID * Data,OPTIONAL IN UINTN DataLength OPTIONAL)35 PeiUsbControlTransfer (
36   IN     EFI_PEI_SERVICES          **PeiServices,
37   IN     PEI_USB_IO_PPI            *This,
38   IN     EFI_USB_DEVICE_REQUEST    *Request,
39   IN     EFI_USB_DATA_DIRECTION    Direction,
40   IN     UINT32                    Timeout,
41   IN OUT VOID                      *Data,      OPTIONAL
42   IN     UINTN                     DataLength  OPTIONAL
43   )
44 {
45   EFI_STATUS                  Status;
46   PEI_USB_DEVICE              *PeiUsbDev;
47   UINT32                      TransferResult;
48   EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor;
49   UINT8                       EndpointIndex;
50 
51   PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This);
52 
53   EndpointDescriptor = NULL;
54   EndpointIndex = 0;
55 
56   if ((Request->Request     == USB_REQ_CLEAR_FEATURE) &&
57       (Request->RequestType == USB_DEV_CLEAR_FEATURE_REQ_TYPE_E) &&
58       (Request->Value       == USB_FEATURE_ENDPOINT_HALT)) {
59     //
60     // Request->Index is the Endpoint Address, use it to get the Endpoint Index.
61     //
62     while (EndpointIndex < MAX_ENDPOINT) {
63       Status = PeiUsbGetEndpointDescriptor (PeiServices, This, EndpointIndex, &EndpointDescriptor);
64       if (EFI_ERROR (Status)) {
65         return EFI_INVALID_PARAMETER;
66       }
67 
68       if (EndpointDescriptor->EndpointAddress == Request->Index) {
69         break;
70       }
71 
72       EndpointIndex++;
73     }
74 
75     if (EndpointIndex == MAX_ENDPOINT) {
76       return EFI_INVALID_PARAMETER;
77     }
78   }
79 
80   if (PeiUsbDev->Usb2HcPpi != NULL) {
81     Status = PeiUsbDev->Usb2HcPpi->ControlTransfer (
82                         PeiServices,
83                         PeiUsbDev->Usb2HcPpi,
84                         PeiUsbDev->DeviceAddress,
85                         PeiUsbDev->DeviceSpeed,
86                         PeiUsbDev->MaxPacketSize0,
87                         Request,
88                         Direction,
89                         Data,
90                         &DataLength,
91                         Timeout,
92                         &(PeiUsbDev->Translator),
93                         &TransferResult
94                         );
95   } else {
96     Status = PeiUsbDev->UsbHcPpi->ControlTransfer (
97                         PeiServices,
98                         PeiUsbDev->UsbHcPpi,
99                         PeiUsbDev->DeviceAddress,
100                         PeiUsbDev->DeviceSpeed,
101                         (UINT8) PeiUsbDev->MaxPacketSize0,
102                         Request,
103                         Direction,
104                         Data,
105                         &DataLength,
106                         Timeout,
107                         &TransferResult
108                         );
109   }
110 
111   //
112   // Reset the endpoint toggle when endpoint stall is cleared
113   //
114   if ((Request->Request     == USB_REQ_CLEAR_FEATURE) &&
115       (Request->RequestType == USB_DEV_CLEAR_FEATURE_REQ_TYPE_E) &&
116       (Request->Value       == USB_FEATURE_ENDPOINT_HALT)) {
117     if ((PeiUsbDev->DataToggle & (1 << EndpointIndex)) != 0) {
118       PeiUsbDev->DataToggle = (UINT16) (PeiUsbDev->DataToggle ^ (1 << EndpointIndex));
119     }
120   }
121 
122   DEBUG ((EFI_D_INFO, "PeiUsbControlTransfer: %r\n", Status));
123   return Status;
124 }
125 
126 /**
127   Submits bulk transfer to a bulk endpoint of a USB device.
128 
129   @param  PeiServices           The pointer of EFI_PEI_SERVICES.
130   @param  This                  The pointer of PEI_USB_IO_PPI.
131   @param  DeviceEndpoint        Endpoint number and its direction in bit 7.
132   @param  Data                  A pointer to the buffer of data to transmit
133                                 from or receive into.
134   @param  DataLength            The lenght of the data buffer.
135   @param  Timeout               Indicates the maximum time, in millisecond, which the
136                                 transfer is allowed to complete. If Timeout is 0, then
137                                 the caller must wait for the function to be completed
138                                 until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
139 
140   @retval EFI_SUCCESS           The transfer was completed successfully.
141   @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.
142   @retval EFI_INVALID_PARAMETER Parameters are invalid.
143   @retval EFI_TIMEOUT           The transfer failed due to timeout.
144   @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.
145 
146 **/
147 EFI_STATUS
148 EFIAPI
PeiUsbBulkTransfer(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_IO_PPI * This,IN UINT8 DeviceEndpoint,IN OUT VOID * Data,IN OUT UINTN * DataLength,IN UINTN Timeout)149 PeiUsbBulkTransfer (
150   IN     EFI_PEI_SERVICES    **PeiServices,
151   IN     PEI_USB_IO_PPI      *This,
152   IN     UINT8               DeviceEndpoint,
153   IN OUT VOID                *Data,
154   IN OUT UINTN               *DataLength,
155   IN     UINTN               Timeout
156   )
157 {
158   EFI_STATUS                  Status;
159   PEI_USB_DEVICE              *PeiUsbDev;
160   UINT32                      TransferResult;
161   UINTN                       MaxPacketLength;
162   UINT8                       DataToggle;
163   UINT8                       OldToggle;
164   EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor;
165   UINT8                       EndpointIndex;
166   VOID                        *Data2[EFI_USB_MAX_BULK_BUFFER_NUM];
167 
168   PeiUsbDev     = PEI_USB_DEVICE_FROM_THIS (This);
169 
170   EndpointDescriptor = NULL;
171   EndpointIndex = 0;
172   Data2[0] = Data;
173   Data2[1] = NULL;
174 
175   while (EndpointIndex < MAX_ENDPOINT) {
176     Status = PeiUsbGetEndpointDescriptor (PeiServices, This, EndpointIndex, &EndpointDescriptor);
177     if (EFI_ERROR (Status)) {
178       return EFI_INVALID_PARAMETER;
179     }
180 
181     if (EndpointDescriptor->EndpointAddress == DeviceEndpoint) {
182       break;
183     }
184 
185     EndpointIndex++;
186   }
187 
188   if (EndpointIndex == MAX_ENDPOINT) {
189     return EFI_INVALID_PARAMETER;
190   }
191 
192   MaxPacketLength = PeiUsbDev->EndpointDesc[EndpointIndex]->MaxPacketSize;
193   if ((PeiUsbDev->DataToggle & (1 << EndpointIndex)) != 0) {
194     DataToggle = 1;
195   } else {
196     DataToggle = 0;
197   }
198 
199   OldToggle = DataToggle;
200 
201   if (PeiUsbDev->Usb2HcPpi != NULL) {
202     Status = PeiUsbDev->Usb2HcPpi->BulkTransfer (
203                         PeiServices,
204                         PeiUsbDev->Usb2HcPpi,
205                         PeiUsbDev->DeviceAddress,
206                         DeviceEndpoint,
207                         PeiUsbDev->DeviceSpeed,
208                         MaxPacketLength,
209                         Data2,
210                         DataLength,
211                         &DataToggle,
212                         Timeout,
213                         &(PeiUsbDev->Translator),
214                         &TransferResult
215                         );
216   } else {
217     Status = PeiUsbDev->UsbHcPpi->BulkTransfer (
218                         PeiServices,
219                         PeiUsbDev->UsbHcPpi,
220                         PeiUsbDev->DeviceAddress,
221                         DeviceEndpoint,
222                         (UINT8) MaxPacketLength,
223                         Data,
224                         DataLength,
225                         &DataToggle,
226                         Timeout,
227                         &TransferResult
228                         );
229   }
230 
231   if (OldToggle != DataToggle) {
232     PeiUsbDev->DataToggle = (UINT16) (PeiUsbDev->DataToggle ^ (1 << EndpointIndex));
233   }
234 
235   DEBUG ((EFI_D_INFO, "PeiUsbBulkTransfer: %r\n", Status));
236   return Status;
237 }
238 
239 /**
240   Get the usb interface descriptor.
241 
242   @param  PeiServices          General-purpose services that are available to every PEIM.
243   @param  This                 Indicates the PEI_USB_IO_PPI instance.
244   @param  InterfaceDescriptor  Request interface descriptor.
245 
246 
247   @retval EFI_SUCCESS          Usb interface descriptor is obtained successfully.
248 
249 **/
250 EFI_STATUS
251 EFIAPI
PeiUsbGetInterfaceDescriptor(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_IO_PPI * This,OUT EFI_USB_INTERFACE_DESCRIPTOR ** InterfaceDescriptor)252 PeiUsbGetInterfaceDescriptor (
253   IN  EFI_PEI_SERVICES               **PeiServices,
254   IN  PEI_USB_IO_PPI                 *This,
255   OUT EFI_USB_INTERFACE_DESCRIPTOR   **InterfaceDescriptor
256   )
257 {
258   PEI_USB_DEVICE  *PeiUsbDev;
259   PeiUsbDev             = PEI_USB_DEVICE_FROM_THIS (This);
260   *InterfaceDescriptor  = PeiUsbDev->InterfaceDesc;
261   return EFI_SUCCESS;
262 }
263 
264 /**
265   Get the usb endpoint descriptor.
266 
267   @param  PeiServices          General-purpose services that are available to every PEIM.
268   @param  This                 Indicates the PEI_USB_IO_PPI instance.
269   @param  EndpointIndex        The valid index of the specified endpoint.
270   @param  EndpointDescriptor   Request endpoint descriptor.
271 
272   @retval EFI_SUCCESS       Usb endpoint descriptor is obtained successfully.
273   @retval EFI_NOT_FOUND     Usb endpoint descriptor is NOT found.
274 
275 **/
276 EFI_STATUS
277 EFIAPI
PeiUsbGetEndpointDescriptor(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_IO_PPI * This,IN UINT8 EndpointIndex,OUT EFI_USB_ENDPOINT_DESCRIPTOR ** EndpointDescriptor)278 PeiUsbGetEndpointDescriptor (
279   IN  EFI_PEI_SERVICES               **PeiServices,
280   IN  PEI_USB_IO_PPI                 *This,
281   IN  UINT8                          EndpointIndex,
282   OUT EFI_USB_ENDPOINT_DESCRIPTOR    **EndpointDescriptor
283   )
284 {
285   PEI_USB_DEVICE  *PeiUsbDev;
286 
287   PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This);
288 
289   ASSERT (EndpointDescriptor != NULL);
290 
291   //
292   // The valid range of EndpointIndex is 0..15
293   // If EndpointIndex is lesser than 15 but larger than the number of interfaces,
294   // a EFI_NOT_FOUND should be returned
295   //
296   ASSERT (EndpointIndex <= 15);
297 
298   if (EndpointIndex >= PeiUsbDev->InterfaceDesc->NumEndpoints) {
299     return EFI_NOT_FOUND;
300   }
301 
302   *EndpointDescriptor = PeiUsbDev->EndpointDesc[EndpointIndex];
303 
304   return EFI_SUCCESS;
305 }
306 
307 /**
308   Reset the port and re-configure the usb device.
309 
310   @param  PeiServices    General-purpose services that are available to every PEIM.
311   @param  This           Indicates the PEI_USB_IO_PPI instance.
312 
313   @retval EFI_SUCCESS    Usb device is reset and configured successfully.
314   @retval Others         Other failure occurs.
315 
316 **/
317 EFI_STATUS
318 EFIAPI
PeiUsbPortReset(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_IO_PPI * This)319 PeiUsbPortReset (
320   IN EFI_PEI_SERVICES               **PeiServices,
321   IN PEI_USB_IO_PPI                 *This
322   )
323 {
324   PEI_USB_DEVICE  *PeiUsbDev;
325   EFI_STATUS      Status;
326   UINT8           Address;
327 
328   PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This);
329 
330   ResetRootPort (
331     PeiServices,
332     PeiUsbDev->UsbHcPpi,
333     PeiUsbDev->Usb2HcPpi,
334     PeiUsbDev->DeviceAddress,
335     0
336     );
337 
338   //
339   // Set address
340   //
341   Address                   = PeiUsbDev->DeviceAddress;
342   PeiUsbDev->DeviceAddress  = 0;
343 
344   Status = PeiUsbSetDeviceAddress (
345             PeiServices,
346             This,
347             Address
348             );
349 
350   if (EFI_ERROR (Status)) {
351     return Status;
352   }
353 
354   PeiUsbDev->DeviceAddress = Address;
355 
356   //
357   // Set default configuration
358   //
359   Status = PeiUsbSetConfiguration (
360             PeiServices,
361             This
362             );
363 
364   return Status;
365 }
366