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