/src/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c
Line | Count | Source |
1 | | /** @file |
2 | | The module to produce Usb Bus PPI. |
3 | | |
4 | | Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved.<BR> |
5 | | Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> |
6 | | |
7 | | SPDX-License-Identifier: BSD-2-Clause-Patent |
8 | | |
9 | | **/ |
10 | | |
11 | | #include "UsbPeim.h" |
12 | | #include "HubPeim.h" |
13 | | #include "PeiUsbLib.h" |
14 | | |
15 | | // |
16 | | // UsbIo PPI interface function |
17 | | // |
18 | | PEI_USB_IO_PPI mUsbIoPpi = { |
19 | | PeiUsbControlTransfer, |
20 | | PeiUsbBulkTransfer, |
21 | | PeiUsbGetInterfaceDescriptor, |
22 | | PeiUsbGetEndpointDescriptor, |
23 | | PeiUsbPortReset |
24 | | }; |
25 | | |
26 | | EFI_PEI_PPI_DESCRIPTOR mUsbIoPpiList = { |
27 | | (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), |
28 | | &gPeiUsbIoPpiGuid, |
29 | | NULL |
30 | | }; |
31 | | |
32 | | /** |
33 | | The enumeration routine to detect device change. |
34 | | |
35 | | @param PeiServices Describes the list of possible PEI Services. |
36 | | @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance. |
37 | | |
38 | | @retval EFI_SUCCESS The usb is enumerated successfully. |
39 | | @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. |
40 | | @retval Others Other failure occurs. |
41 | | |
42 | | **/ |
43 | | EFI_STATUS |
44 | | PeiUsbEnumeration ( |
45 | | IN EFI_PEI_SERVICES **PeiServices, |
46 | | IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi |
47 | | ); |
48 | | |
49 | | /** |
50 | | Configure new detected usb device. |
51 | | |
52 | | @param PeiServices Describes the list of possible PEI Services. |
53 | | @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance. |
54 | | @param Port The port to be configured. |
55 | | @param DeviceAddress The device address to be configured. |
56 | | |
57 | | @retval EFI_SUCCESS The new detected usb device is configured successfully. |
58 | | @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. |
59 | | @retval Others Other failure occurs. |
60 | | |
61 | | **/ |
62 | | EFI_STATUS |
63 | | PeiConfigureUsbDevice ( |
64 | | IN EFI_PEI_SERVICES **PeiServices, |
65 | | IN PEI_USB_DEVICE *PeiUsbDevice, |
66 | | IN UINT8 Port, |
67 | | IN OUT UINT8 *DeviceAddress |
68 | | ); |
69 | | |
70 | | /** |
71 | | Get all configurations from a detected usb device. |
72 | | |
73 | | @param PeiServices Describes the list of possible PEI Services. |
74 | | @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance. |
75 | | |
76 | | @retval EFI_SUCCESS The new detected usb device is configured successfully. |
77 | | @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. |
78 | | @retval Others Other failure occurs. |
79 | | |
80 | | **/ |
81 | | EFI_STATUS |
82 | | PeiUsbGetAllConfiguration ( |
83 | | IN EFI_PEI_SERVICES **PeiServices, |
84 | | IN PEI_USB_DEVICE *PeiUsbDevice |
85 | | ); |
86 | | |
87 | | /** |
88 | | Get the start position of next wanted descriptor. |
89 | | |
90 | | @param Buffer Buffer containing data to parse. |
91 | | @param Length Buffer length. |
92 | | @param DescType Descriptor type. |
93 | | @param DescLength Descriptor length. |
94 | | @param ParsedBytes Bytes has been parsed. |
95 | | |
96 | | @retval EFI_SUCCESS Get wanted descriptor successfully. |
97 | | @retval EFI_DEVICE_ERROR Error occurred. |
98 | | |
99 | | **/ |
100 | | EFI_STATUS |
101 | | GetExpectedDescriptor ( |
102 | | IN UINT8 *Buffer, |
103 | | IN UINTN Length, |
104 | | IN UINT8 DescType, |
105 | | IN UINT8 DescLength, |
106 | | OUT UINTN *ParsedBytes |
107 | | ); |
108 | | |
109 | | /** |
110 | | The entrypoint of the module, it will enumerate all HCs. |
111 | | |
112 | | @param FileHandle Handle of the file being invoked. |
113 | | @param PeiServices Describes the list of possible PEI Services. |
114 | | |
115 | | @retval EFI_SUCCESS Usb initialization is done successfully. |
116 | | @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. |
117 | | @retval EFI_UNSUPPORTED Can't find required PPI. |
118 | | |
119 | | **/ |
120 | | EFI_STATUS |
121 | | EFIAPI |
122 | | PeimInitializeUsb ( |
123 | | IN EFI_PEI_FILE_HANDLE FileHandle, |
124 | | IN CONST EFI_PEI_SERVICES **PeiServices |
125 | | ) |
126 | 0 | { |
127 | 0 | EFI_STATUS Status; |
128 | 0 | UINTN Index; |
129 | 0 | PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi; |
130 | |
|
131 | 0 | if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) { |
132 | 0 | return EFI_SUCCESS; |
133 | 0 | } |
134 | | |
135 | 0 | Index = 0; |
136 | 0 | while (TRUE) { |
137 | 0 | Status = PeiServicesLocatePpi ( |
138 | 0 | &gPeiUsb2HostControllerPpiGuid, |
139 | 0 | Index, |
140 | 0 | NULL, |
141 | 0 | (VOID **)&Usb2HcPpi |
142 | 0 | ); |
143 | 0 | if (EFI_ERROR (Status)) { |
144 | | // |
145 | | // No more host controller, break out |
146 | | // |
147 | 0 | break; |
148 | 0 | } |
149 | | |
150 | 0 | PeiUsbEnumeration ((EFI_PEI_SERVICES **)PeiServices, Usb2HcPpi); |
151 | 0 | Index++; |
152 | 0 | } |
153 | |
|
154 | 0 | if (Index == 0) { |
155 | 0 | return EFI_UNSUPPORTED; |
156 | 0 | } |
157 | | |
158 | 0 | return EFI_SUCCESS; |
159 | 0 | } |
160 | | |
161 | | /** |
162 | | The Hub Enumeration just scans the hub ports one time. It also |
163 | | doesn't support hot-plug. |
164 | | |
165 | | @param PeiServices Describes the list of possible PEI Services. |
166 | | @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance. |
167 | | @param CurrentAddress The DeviceAddress of usb device. |
168 | | |
169 | | @retval EFI_SUCCESS The usb hub is enumerated successfully. |
170 | | @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. |
171 | | @retval Others Other failure occurs. |
172 | | |
173 | | **/ |
174 | | EFI_STATUS |
175 | | PeiHubEnumeration ( |
176 | | IN EFI_PEI_SERVICES **PeiServices, |
177 | | IN PEI_USB_DEVICE *PeiUsbDevice, |
178 | | IN UINT8 *CurrentAddress |
179 | | ) |
180 | 0 | { |
181 | 0 | UINTN Index; |
182 | 0 | EFI_STATUS Status; |
183 | 0 | PEI_USB_IO_PPI *UsbIoPpi; |
184 | 0 | EFI_USB_PORT_STATUS PortStatus; |
185 | 0 | UINTN MemPages; |
186 | 0 | EFI_PHYSICAL_ADDRESS AllocateAddress; |
187 | 0 | PEI_USB_DEVICE *NewPeiUsbDevice; |
188 | 0 | UINTN InterfaceIndex; |
189 | 0 | UINTN EndpointIndex; |
190 | |
|
191 | 0 | UsbIoPpi = &PeiUsbDevice->UsbIoPpi; |
192 | |
|
193 | 0 | DEBUG ((DEBUG_INFO, "PeiHubEnumeration: DownStreamPortNo: %x\n", PeiUsbDevice->DownStreamPortNo)); |
194 | |
|
195 | 0 | for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) { |
196 | 0 | Status = PeiHubGetPortStatus ( |
197 | 0 | PeiServices, |
198 | 0 | UsbIoPpi, |
199 | 0 | (UINT8)(Index + 1), |
200 | 0 | (UINT32 *)&PortStatus |
201 | 0 | ); |
202 | |
|
203 | 0 | if (EFI_ERROR (Status)) { |
204 | 0 | continue; |
205 | 0 | } |
206 | | |
207 | 0 | DEBUG ((DEBUG_INFO, "USB Status --- Port: %x ConnectChange[%04x] Status[%04x]\n", Index, PortStatus.PortChangeStatus, PortStatus.PortStatus)); |
208 | | // |
209 | | // Only handle connection/enable/overcurrent/reset change. |
210 | | // |
211 | 0 | if ((PortStatus.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) { |
212 | 0 | continue; |
213 | 0 | } else { |
214 | 0 | if (IsPortConnect (PortStatus.PortStatus)) { |
215 | | // |
216 | | // Begin to deal with the new device |
217 | | // |
218 | 0 | MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1; |
219 | 0 | Status = PeiServicesAllocatePages ( |
220 | 0 | EfiBootServicesCode, |
221 | 0 | MemPages, |
222 | 0 | &AllocateAddress |
223 | 0 | ); |
224 | 0 | if (EFI_ERROR (Status)) { |
225 | 0 | return EFI_OUT_OF_RESOURCES; |
226 | 0 | } |
227 | | |
228 | 0 | NewPeiUsbDevice = (PEI_USB_DEVICE *)((UINTN)AllocateAddress); |
229 | 0 | ZeroMem (NewPeiUsbDevice, sizeof (PEI_USB_DEVICE)); |
230 | |
|
231 | 0 | NewPeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE; |
232 | 0 | NewPeiUsbDevice->DeviceAddress = 0; |
233 | 0 | NewPeiUsbDevice->MaxPacketSize0 = 8; |
234 | 0 | NewPeiUsbDevice->DataToggle = 0; |
235 | 0 | CopyMem ( |
236 | 0 | &(NewPeiUsbDevice->UsbIoPpi), |
237 | 0 | &mUsbIoPpi, |
238 | 0 | sizeof (PEI_USB_IO_PPI) |
239 | 0 | ); |
240 | 0 | CopyMem ( |
241 | 0 | &(NewPeiUsbDevice->UsbIoPpiList), |
242 | 0 | &mUsbIoPpiList, |
243 | 0 | sizeof (EFI_PEI_PPI_DESCRIPTOR) |
244 | 0 | ); |
245 | 0 | NewPeiUsbDevice->UsbIoPpiList.Ppi = &NewPeiUsbDevice->UsbIoPpi; |
246 | 0 | NewPeiUsbDevice->AllocateAddress = (UINTN)AllocateAddress; |
247 | 0 | NewPeiUsbDevice->Usb2HcPpi = PeiUsbDevice->Usb2HcPpi; |
248 | 0 | NewPeiUsbDevice->Tier = (UINT8)(PeiUsbDevice->Tier + 1); |
249 | 0 | NewPeiUsbDevice->IsHub = 0x0; |
250 | 0 | NewPeiUsbDevice->DownStreamPortNo = 0x0; |
251 | |
|
252 | 0 | if (((PortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0) || |
253 | 0 | ((PortStatus.PortStatus & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == 0)) |
254 | 0 | { |
255 | | // |
256 | | // If the port already has reset change flag and is connected and enabled, skip the port reset logic. |
257 | | // |
258 | 0 | PeiResetHubPort (PeiServices, UsbIoPpi, (UINT8)(Index + 1)); |
259 | |
|
260 | 0 | PeiHubGetPortStatus ( |
261 | 0 | PeiServices, |
262 | 0 | UsbIoPpi, |
263 | 0 | (UINT8)(Index + 1), |
264 | 0 | (UINT32 *)&PortStatus |
265 | 0 | ); |
266 | 0 | } else { |
267 | 0 | PeiHubClearPortFeature ( |
268 | 0 | PeiServices, |
269 | 0 | UsbIoPpi, |
270 | 0 | (UINT8)(Index + 1), |
271 | 0 | EfiUsbPortResetChange |
272 | 0 | ); |
273 | 0 | } |
274 | |
|
275 | 0 | NewPeiUsbDevice->DeviceSpeed = (UINT8)PeiUsbGetDeviceSpeed (PortStatus.PortStatus); |
276 | 0 | DEBUG ((DEBUG_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed)); |
277 | |
|
278 | 0 | if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_SUPER_SPEED)) { |
279 | 0 | NewPeiUsbDevice->MaxPacketSize0 = 512; |
280 | 0 | } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_HIGH_SPEED)) { |
281 | 0 | NewPeiUsbDevice->MaxPacketSize0 = 64; |
282 | 0 | } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_LOW_SPEED)) { |
283 | 0 | NewPeiUsbDevice->MaxPacketSize0 = 8; |
284 | 0 | } else { |
285 | 0 | NewPeiUsbDevice->MaxPacketSize0 = 8; |
286 | 0 | } |
287 | |
|
288 | 0 | if (NewPeiUsbDevice->DeviceSpeed != EFI_USB_SPEED_HIGH) { |
289 | 0 | if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_HIGH) { |
290 | 0 | NewPeiUsbDevice->Translator.TranslatorPortNumber = (UINT8)Index; |
291 | 0 | NewPeiUsbDevice->Translator.TranslatorHubAddress = *CurrentAddress; |
292 | 0 | } else { |
293 | 0 | CopyMem (&(NewPeiUsbDevice->Translator), &(PeiUsbDevice->Translator), sizeof (EFI_USB2_HC_TRANSACTION_TRANSLATOR)); |
294 | 0 | } |
295 | 0 | } |
296 | | |
297 | | // |
298 | | // Configure that Usb Device |
299 | | // |
300 | 0 | Status = PeiConfigureUsbDevice ( |
301 | 0 | PeiServices, |
302 | 0 | NewPeiUsbDevice, |
303 | 0 | (UINT8)(Index + 1), |
304 | 0 | CurrentAddress |
305 | 0 | ); |
306 | |
|
307 | 0 | if (EFI_ERROR (Status)) { |
308 | 0 | continue; |
309 | 0 | } |
310 | | |
311 | 0 | DEBUG ((DEBUG_INFO, "PeiHubEnumeration: PeiConfigureUsbDevice Success\n")); |
312 | |
|
313 | 0 | Status = PeiServicesInstallPpi (&NewPeiUsbDevice->UsbIoPpiList); |
314 | |
|
315 | 0 | if (NewPeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) { |
316 | 0 | NewPeiUsbDevice->IsHub = 0x1; |
317 | |
|
318 | 0 | Status = PeiDoHubConfig (PeiServices, NewPeiUsbDevice); |
319 | 0 | if (EFI_ERROR (Status)) { |
320 | 0 | return Status; |
321 | 0 | } |
322 | | |
323 | 0 | PeiHubEnumeration (PeiServices, NewPeiUsbDevice, CurrentAddress); |
324 | 0 | } |
325 | | |
326 | 0 | for (InterfaceIndex = 1; InterfaceIndex < NewPeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) { |
327 | | // |
328 | | // Begin to deal with the new device |
329 | | // |
330 | 0 | MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1; |
331 | 0 | Status = PeiServicesAllocatePages ( |
332 | 0 | EfiBootServicesCode, |
333 | 0 | MemPages, |
334 | 0 | &AllocateAddress |
335 | 0 | ); |
336 | 0 | if (EFI_ERROR (Status)) { |
337 | 0 | return EFI_OUT_OF_RESOURCES; |
338 | 0 | } |
339 | | |
340 | 0 | CopyMem ((VOID *)(UINTN)AllocateAddress, NewPeiUsbDevice, sizeof (PEI_USB_DEVICE)); |
341 | 0 | NewPeiUsbDevice = (PEI_USB_DEVICE *)((UINTN)AllocateAddress); |
342 | 0 | NewPeiUsbDevice->AllocateAddress = (UINTN)AllocateAddress; |
343 | 0 | NewPeiUsbDevice->UsbIoPpiList.Ppi = &NewPeiUsbDevice->UsbIoPpi; |
344 | 0 | NewPeiUsbDevice->InterfaceDesc = NewPeiUsbDevice->InterfaceDescList[InterfaceIndex]; |
345 | 0 | for (EndpointIndex = 0; EndpointIndex < NewPeiUsbDevice->InterfaceDesc->NumEndpoints; EndpointIndex++) { |
346 | 0 | NewPeiUsbDevice->EndpointDesc[EndpointIndex] = NewPeiUsbDevice->EndpointDescList[InterfaceIndex][EndpointIndex]; |
347 | 0 | } |
348 | |
|
349 | 0 | Status = PeiServicesInstallPpi (&NewPeiUsbDevice->UsbIoPpiList); |
350 | |
|
351 | 0 | if (NewPeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) { |
352 | 0 | NewPeiUsbDevice->IsHub = 0x1; |
353 | |
|
354 | 0 | Status = PeiDoHubConfig (PeiServices, NewPeiUsbDevice); |
355 | 0 | if (EFI_ERROR (Status)) { |
356 | 0 | return Status; |
357 | 0 | } |
358 | | |
359 | 0 | PeiHubEnumeration (PeiServices, NewPeiUsbDevice, CurrentAddress); |
360 | 0 | } |
361 | 0 | } |
362 | 0 | } |
363 | 0 | } |
364 | 0 | } |
365 | | |
366 | 0 | return EFI_SUCCESS; |
367 | 0 | } |
368 | | |
369 | | /** |
370 | | The enumeration routine to detect device change. |
371 | | |
372 | | @param PeiServices Describes the list of possible PEI Services. |
373 | | @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance. |
374 | | |
375 | | @retval EFI_SUCCESS The usb is enumerated successfully. |
376 | | @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. |
377 | | @retval Others Other failure occurs. |
378 | | |
379 | | **/ |
380 | | EFI_STATUS |
381 | | PeiUsbEnumeration ( |
382 | | IN EFI_PEI_SERVICES **PeiServices, |
383 | | IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi |
384 | | ) |
385 | 0 | { |
386 | 0 | UINT8 NumOfRootPort; |
387 | 0 | EFI_STATUS Status; |
388 | 0 | UINT8 Index; |
389 | 0 | EFI_USB_PORT_STATUS PortStatus; |
390 | 0 | PEI_USB_DEVICE *PeiUsbDevice; |
391 | 0 | UINTN MemPages; |
392 | 0 | EFI_PHYSICAL_ADDRESS AllocateAddress; |
393 | 0 | UINT8 CurrentAddress; |
394 | 0 | UINTN InterfaceIndex; |
395 | 0 | UINTN EndpointIndex; |
396 | 0 | UINT8 UsbEnumLoop; |
397 | |
|
398 | 0 | CurrentAddress = 0; |
399 | 0 | if (Usb2HcPpi != NULL) { |
400 | 0 | Usb2HcPpi->GetRootHubPortNumber ( |
401 | 0 | PeiServices, |
402 | 0 | Usb2HcPpi, |
403 | 0 | (UINT8 *)&NumOfRootPort |
404 | 0 | ); |
405 | 0 | } else { |
406 | 0 | ASSERT (FALSE); |
407 | 0 | return EFI_INVALID_PARAMETER; |
408 | 0 | } |
409 | | |
410 | 0 | DEBUG ((DEBUG_INFO, "PeiUsbEnumeration: NumOfRootPort: %x\n", NumOfRootPort)); |
411 | | |
412 | | // |
413 | | // USB3.x devices initially appear in USB2.0 ports. When the USB2.0 port is reset, the USB3.x device disappears |
414 | | // from the USB2.0 port and appears on the USB3.0 port. The USB3.x device won't be enumerated if the USB2.0 port |
415 | | // number is greater than the USB3.0 port number. Re-enumerate USB to make sure USB3.x devices in this case. |
416 | | // |
417 | 0 | for (UsbEnumLoop = 0; UsbEnumLoop < 2; UsbEnumLoop++) { |
418 | 0 | for (Index = 0; Index < NumOfRootPort; Index++) { |
419 | | // |
420 | | // First get root port status to detect changes happen |
421 | | // |
422 | 0 | Usb2HcPpi->GetRootHubPortStatus ( |
423 | 0 | PeiServices, |
424 | 0 | Usb2HcPpi, |
425 | 0 | (UINT8)Index, |
426 | 0 | &PortStatus |
427 | 0 | ); |
428 | |
|
429 | 0 | DEBUG ((DEBUG_INFO, "USB Status --- Port: %x ConnectChange[%04x] Status[%04x]\n", Index, PortStatus.PortChangeStatus, PortStatus.PortStatus)); |
430 | | // |
431 | | // Only handle connection/enable/overcurrent/reset change. |
432 | | // |
433 | 0 | if ((PortStatus.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) { |
434 | 0 | continue; |
435 | 0 | } else { |
436 | 0 | if (IsPortConnect (PortStatus.PortStatus)) { |
437 | 0 | MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1; |
438 | 0 | Status = PeiServicesAllocatePages ( |
439 | 0 | EfiBootServicesCode, |
440 | 0 | MemPages, |
441 | 0 | &AllocateAddress |
442 | 0 | ); |
443 | 0 | if (EFI_ERROR (Status)) { |
444 | 0 | return EFI_OUT_OF_RESOURCES; |
445 | 0 | } |
446 | | |
447 | 0 | PeiUsbDevice = (PEI_USB_DEVICE *)((UINTN)AllocateAddress); |
448 | 0 | ZeroMem (PeiUsbDevice, sizeof (PEI_USB_DEVICE)); |
449 | |
|
450 | 0 | PeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE; |
451 | 0 | PeiUsbDevice->DeviceAddress = 0; |
452 | 0 | PeiUsbDevice->MaxPacketSize0 = 8; |
453 | 0 | PeiUsbDevice->DataToggle = 0; |
454 | 0 | CopyMem ( |
455 | 0 | &(PeiUsbDevice->UsbIoPpi), |
456 | 0 | &mUsbIoPpi, |
457 | 0 | sizeof (PEI_USB_IO_PPI) |
458 | 0 | ); |
459 | 0 | CopyMem ( |
460 | 0 | &(PeiUsbDevice->UsbIoPpiList), |
461 | 0 | &mUsbIoPpiList, |
462 | 0 | sizeof (EFI_PEI_PPI_DESCRIPTOR) |
463 | 0 | ); |
464 | 0 | PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi; |
465 | 0 | PeiUsbDevice->AllocateAddress = (UINTN)AllocateAddress; |
466 | 0 | PeiUsbDevice->Usb2HcPpi = Usb2HcPpi; |
467 | 0 | PeiUsbDevice->IsHub = 0x0; |
468 | 0 | PeiUsbDevice->DownStreamPortNo = 0x0; |
469 | |
|
470 | 0 | if (((PortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0) || |
471 | 0 | ((PortStatus.PortStatus & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == 0)) |
472 | 0 | { |
473 | | // |
474 | | // If the port already has reset change flag and is connected and enabled, skip the port reset logic. |
475 | | // |
476 | 0 | ResetRootPort ( |
477 | 0 | PeiServices, |
478 | 0 | PeiUsbDevice->Usb2HcPpi, |
479 | 0 | Index, |
480 | 0 | 0 |
481 | 0 | ); |
482 | |
|
483 | 0 | Usb2HcPpi->GetRootHubPortStatus ( |
484 | 0 | PeiServices, |
485 | 0 | Usb2HcPpi, |
486 | 0 | (UINT8)Index, |
487 | 0 | &PortStatus |
488 | 0 | ); |
489 | 0 | } else { |
490 | 0 | Usb2HcPpi->ClearRootHubPortFeature ( |
491 | 0 | PeiServices, |
492 | 0 | Usb2HcPpi, |
493 | 0 | (UINT8)Index, |
494 | 0 | EfiUsbPortResetChange |
495 | 0 | ); |
496 | 0 | } |
497 | |
|
498 | 0 | PeiUsbDevice->DeviceSpeed = (UINT8)PeiUsbGetDeviceSpeed (PortStatus.PortStatus); |
499 | 0 | DEBUG ((DEBUG_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed)); |
500 | |
|
501 | 0 | if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_SUPER_SPEED)) { |
502 | 0 | PeiUsbDevice->MaxPacketSize0 = 512; |
503 | 0 | } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_HIGH_SPEED)) { |
504 | 0 | PeiUsbDevice->MaxPacketSize0 = 64; |
505 | 0 | } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_LOW_SPEED)) { |
506 | 0 | PeiUsbDevice->MaxPacketSize0 = 8; |
507 | 0 | } else { |
508 | 0 | PeiUsbDevice->MaxPacketSize0 = 8; |
509 | 0 | } |
510 | | |
511 | | // |
512 | | // Configure that Usb Device |
513 | | // |
514 | 0 | Status = PeiConfigureUsbDevice ( |
515 | 0 | PeiServices, |
516 | 0 | PeiUsbDevice, |
517 | 0 | Index, |
518 | 0 | &CurrentAddress |
519 | 0 | ); |
520 | |
|
521 | 0 | if (EFI_ERROR (Status)) { |
522 | 0 | continue; |
523 | 0 | } |
524 | | |
525 | 0 | DEBUG ((DEBUG_INFO, "PeiUsbEnumeration: PeiConfigureUsbDevice Success\n")); |
526 | |
|
527 | 0 | Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList); |
528 | |
|
529 | 0 | if (PeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) { |
530 | 0 | PeiUsbDevice->IsHub = 0x1; |
531 | |
|
532 | 0 | Status = PeiDoHubConfig (PeiServices, PeiUsbDevice); |
533 | 0 | if (EFI_ERROR (Status)) { |
534 | 0 | return Status; |
535 | 0 | } |
536 | | |
537 | 0 | PeiHubEnumeration (PeiServices, PeiUsbDevice, &CurrentAddress); |
538 | 0 | } |
539 | | |
540 | 0 | for (InterfaceIndex = 1; InterfaceIndex < PeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) { |
541 | | // |
542 | | // Begin to deal with the new device |
543 | | // |
544 | 0 | MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1; |
545 | 0 | Status = PeiServicesAllocatePages ( |
546 | 0 | EfiBootServicesCode, |
547 | 0 | MemPages, |
548 | 0 | &AllocateAddress |
549 | 0 | ); |
550 | 0 | if (EFI_ERROR (Status)) { |
551 | 0 | return EFI_OUT_OF_RESOURCES; |
552 | 0 | } |
553 | | |
554 | 0 | CopyMem ((VOID *)(UINTN)AllocateAddress, PeiUsbDevice, sizeof (PEI_USB_DEVICE)); |
555 | 0 | PeiUsbDevice = (PEI_USB_DEVICE *)((UINTN)AllocateAddress); |
556 | 0 | PeiUsbDevice->AllocateAddress = (UINTN)AllocateAddress; |
557 | 0 | PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi; |
558 | 0 | PeiUsbDevice->InterfaceDesc = PeiUsbDevice->InterfaceDescList[InterfaceIndex]; |
559 | 0 | for (EndpointIndex = 0; EndpointIndex < PeiUsbDevice->InterfaceDesc->NumEndpoints; EndpointIndex++) { |
560 | 0 | PeiUsbDevice->EndpointDesc[EndpointIndex] = PeiUsbDevice->EndpointDescList[InterfaceIndex][EndpointIndex]; |
561 | 0 | } |
562 | |
|
563 | 0 | Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList); |
564 | |
|
565 | 0 | if (PeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) { |
566 | 0 | PeiUsbDevice->IsHub = 0x1; |
567 | |
|
568 | 0 | Status = PeiDoHubConfig (PeiServices, PeiUsbDevice); |
569 | 0 | if (EFI_ERROR (Status)) { |
570 | 0 | return Status; |
571 | 0 | } |
572 | | |
573 | 0 | PeiHubEnumeration (PeiServices, PeiUsbDevice, &CurrentAddress); |
574 | 0 | } |
575 | 0 | } |
576 | 0 | } else { |
577 | | // |
578 | | // Disconnect change happen, currently we don't support |
579 | | // |
580 | 0 | } |
581 | 0 | } |
582 | 0 | } |
583 | 0 | } |
584 | | |
585 | 0 | return EFI_SUCCESS; |
586 | 0 | } |
587 | | |
588 | | /** |
589 | | Configure new detected usb device. |
590 | | |
591 | | @param PeiServices Describes the list of possible PEI Services. |
592 | | @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance. |
593 | | @param Port The port to be configured. |
594 | | @param DeviceAddress The device address to be configured. |
595 | | |
596 | | @retval EFI_SUCCESS The new detected usb device is configured successfully. |
597 | | @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. |
598 | | @retval Others Other failure occurs. |
599 | | |
600 | | **/ |
601 | | EFI_STATUS |
602 | | PeiConfigureUsbDevice ( |
603 | | IN EFI_PEI_SERVICES **PeiServices, |
604 | | IN PEI_USB_DEVICE *PeiUsbDevice, |
605 | | IN UINT8 Port, |
606 | | IN OUT UINT8 *DeviceAddress |
607 | | ) |
608 | 0 | { |
609 | 0 | EFI_USB_DEVICE_DESCRIPTOR DeviceDescriptor; |
610 | 0 | EFI_STATUS Status; |
611 | 0 | PEI_USB_IO_PPI *UsbIoPpi; |
612 | 0 | UINT8 Retry; |
613 | |
|
614 | 0 | UsbIoPpi = &PeiUsbDevice->UsbIoPpi; |
615 | 0 | Status = EFI_SUCCESS; |
616 | 0 | ZeroMem (&DeviceDescriptor, sizeof (EFI_USB_DEVICE_DESCRIPTOR)); |
617 | | // |
618 | | // Get USB device descriptor |
619 | | // |
620 | |
|
621 | 0 | for (Retry = 0; Retry < 3; Retry++) { |
622 | 0 | Status = PeiUsbGetDescriptor ( |
623 | 0 | PeiServices, |
624 | 0 | UsbIoPpi, |
625 | 0 | (USB_DT_DEVICE << 8), |
626 | 0 | 0, |
627 | 0 | 8, |
628 | 0 | &DeviceDescriptor |
629 | 0 | ); |
630 | |
|
631 | 0 | if (!EFI_ERROR (Status)) { |
632 | 0 | DEBUG ((DEBUG_INFO, "PeiUsbGet Device Descriptor the %d time Success\n", Retry)); |
633 | 0 | break; |
634 | 0 | } |
635 | 0 | } |
636 | |
|
637 | 0 | if (Retry == 3) { |
638 | 0 | DEBUG ((DEBUG_ERROR, "PeiUsbGet Device Descriptor fail: %x %r\n", Retry, Status)); |
639 | 0 | return Status; |
640 | 0 | } |
641 | | |
642 | 0 | if ((DeviceDescriptor.BcdUSB >= 0x0300) && (DeviceDescriptor.MaxPacketSize0 == 9)) { |
643 | 0 | PeiUsbDevice->MaxPacketSize0 = 1 << 9; |
644 | 0 | } else { |
645 | 0 | PeiUsbDevice->MaxPacketSize0 = DeviceDescriptor.MaxPacketSize0; |
646 | 0 | } |
647 | |
|
648 | 0 | (*DeviceAddress)++; |
649 | |
|
650 | 0 | Status = PeiUsbSetDeviceAddress ( |
651 | 0 | PeiServices, |
652 | 0 | UsbIoPpi, |
653 | 0 | *DeviceAddress |
654 | 0 | ); |
655 | |
|
656 | 0 | if (EFI_ERROR (Status)) { |
657 | 0 | DEBUG ((DEBUG_ERROR, "PeiUsbSetDeviceAddress Failed: %r\n", Status)); |
658 | 0 | return Status; |
659 | 0 | } |
660 | | |
661 | 0 | MicroSecondDelay (USB_SET_DEVICE_ADDRESS_STALL); |
662 | |
|
663 | 0 | PeiUsbDevice->DeviceAddress = *DeviceAddress; |
664 | | |
665 | | // |
666 | | // Get whole USB device descriptor |
667 | | // |
668 | 0 | Status = PeiUsbGetDescriptor ( |
669 | 0 | PeiServices, |
670 | 0 | UsbIoPpi, |
671 | 0 | (USB_DT_DEVICE << 8), |
672 | 0 | 0, |
673 | 0 | (UINT16)sizeof (EFI_USB_DEVICE_DESCRIPTOR), |
674 | 0 | &DeviceDescriptor |
675 | 0 | ); |
676 | |
|
677 | 0 | if (EFI_ERROR (Status)) { |
678 | 0 | DEBUG ((DEBUG_ERROR, "PeiUsbGetDescriptor First Failed\n")); |
679 | 0 | return Status; |
680 | 0 | } |
681 | | |
682 | | // |
683 | | // Get its default configuration and its first interface |
684 | | // |
685 | 0 | Status = PeiUsbGetAllConfiguration ( |
686 | 0 | PeiServices, |
687 | 0 | PeiUsbDevice |
688 | 0 | ); |
689 | 0 | if (EFI_ERROR (Status)) { |
690 | 0 | return Status; |
691 | 0 | } |
692 | | |
693 | 0 | MicroSecondDelay (USB_GET_CONFIG_DESCRIPTOR_STALL); |
694 | |
|
695 | 0 | Status = PeiUsbSetConfiguration ( |
696 | 0 | PeiServices, |
697 | 0 | UsbIoPpi |
698 | 0 | ); |
699 | |
|
700 | 0 | if (EFI_ERROR (Status)) { |
701 | 0 | return Status; |
702 | 0 | } |
703 | | |
704 | 0 | return EFI_SUCCESS; |
705 | 0 | } |
706 | | |
707 | | /** |
708 | | Get all configurations from a detected usb device. |
709 | | |
710 | | @param PeiServices Describes the list of possible PEI Services. |
711 | | @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance. |
712 | | |
713 | | @retval EFI_SUCCESS The new detected usb device is configured successfully. |
714 | | @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. |
715 | | @retval Others Other failure occurs. |
716 | | |
717 | | **/ |
718 | | EFI_STATUS |
719 | | PeiUsbGetAllConfiguration ( |
720 | | IN EFI_PEI_SERVICES **PeiServices, |
721 | | IN PEI_USB_DEVICE *PeiUsbDevice |
722 | | ) |
723 | 42 | { |
724 | 42 | EFI_STATUS Status; |
725 | 42 | EFI_USB_CONFIG_DESCRIPTOR *ConfigDesc; |
726 | 42 | PEI_USB_IO_PPI *UsbIoPpi; |
727 | 42 | UINT16 ConfigDescLength; |
728 | 42 | UINT8 *Ptr; |
729 | 42 | UINTN SkipBytes; |
730 | 42 | UINTN LengthLeft; |
731 | 42 | UINTN InterfaceIndex; |
732 | 42 | UINTN Index; |
733 | 42 | UINTN NumOfEndpoint; |
734 | | |
735 | 42 | UsbIoPpi = &PeiUsbDevice->UsbIoPpi; |
736 | | |
737 | | // |
738 | | // First get its 4-byte configuration descriptor |
739 | | // |
740 | 42 | Status = PeiUsbGetDescriptor ( |
741 | 42 | PeiServices, |
742 | 42 | UsbIoPpi, |
743 | 42 | (USB_DT_CONFIG << 8), // Value |
744 | 42 | 0, // Index |
745 | 42 | 4, // Length |
746 | 42 | PeiUsbDevice->ConfigurationData |
747 | 42 | ); |
748 | | |
749 | 42 | if (EFI_ERROR (Status)) { |
750 | 0 | DEBUG ((DEBUG_ERROR, "PeiUsbGet Config Descriptor First Failed\n")); |
751 | 0 | return Status; |
752 | 0 | } |
753 | | |
754 | 42 | MicroSecondDelay (USB_GET_CONFIG_DESCRIPTOR_STALL); |
755 | | |
756 | 42 | ConfigDesc = (EFI_USB_CONFIG_DESCRIPTOR *)PeiUsbDevice->ConfigurationData; |
757 | 42 | ConfigDescLength = ConfigDesc->TotalLength; |
758 | | |
759 | | // |
760 | | // Reject if TotalLength even cannot cover itself. |
761 | | // |
762 | 42 | if (ConfigDescLength < OFFSET_OF (EFI_USB_CONFIG_DESCRIPTOR, TotalLength) + sizeof (ConfigDesc->TotalLength)) { |
763 | 4 | return EFI_DEVICE_ERROR; |
764 | 4 | } |
765 | | |
766 | | // |
767 | | // Reject if TotalLength exceeds the PeiUsbDevice->ConfigurationData. |
768 | | // |
769 | 38 | if (ConfigDescLength > sizeof (PeiUsbDevice->ConfigurationData)) { |
770 | 9 | return EFI_DEVICE_ERROR; |
771 | 9 | } |
772 | | |
773 | | // |
774 | | // Then we get the total descriptors for this configuration |
775 | | // |
776 | 29 | Status = PeiUsbGetDescriptor ( |
777 | 29 | PeiServices, |
778 | 29 | UsbIoPpi, |
779 | 29 | (USB_DT_CONFIG << 8), |
780 | 29 | 0, |
781 | 29 | ConfigDescLength, |
782 | 29 | PeiUsbDevice->ConfigurationData |
783 | 29 | ); |
784 | | |
785 | 29 | if (EFI_ERROR (Status)) { |
786 | 0 | DEBUG ((DEBUG_ERROR, "PeiUsbGet Config Descriptor all Failed\n")); |
787 | 0 | return Status; |
788 | 0 | } |
789 | | |
790 | | // |
791 | | // Parse this configuration descriptor |
792 | | // First get the current config descriptor; |
793 | | // |
794 | 29 | Status = GetExpectedDescriptor ( |
795 | 29 | PeiUsbDevice->ConfigurationData, |
796 | 29 | ConfigDescLength, |
797 | 29 | USB_DT_CONFIG, |
798 | 29 | (UINT8)sizeof (EFI_USB_CONFIG_DESCRIPTOR), |
799 | 29 | &SkipBytes |
800 | 29 | ); |
801 | | |
802 | 29 | if (EFI_ERROR (Status)) { |
803 | 12 | return Status; |
804 | 12 | } |
805 | | |
806 | 17 | Ptr = PeiUsbDevice->ConfigurationData + SkipBytes; |
807 | 17 | PeiUsbDevice->ConfigDesc = (EFI_USB_CONFIG_DESCRIPTOR *)Ptr; |
808 | | |
809 | 17 | Ptr += sizeof (EFI_USB_CONFIG_DESCRIPTOR); |
810 | 17 | LengthLeft = ConfigDescLength - SkipBytes - sizeof (EFI_USB_CONFIG_DESCRIPTOR); |
811 | | |
812 | 17 | if (PeiUsbDevice->ConfigDesc->NumInterfaces > MAX_INTERFACE) { |
813 | 0 | DEBUG ((DEBUG_ERROR, "PeiUsbGet Number of interfaces in the configuration exceeds maximum allowed")); |
814 | 0 | return EFI_DEVICE_ERROR; |
815 | 0 | } |
816 | | |
817 | 28 | for (InterfaceIndex = 0; InterfaceIndex < PeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) { |
818 | | // |
819 | | // Get the interface descriptor |
820 | | // |
821 | 27 | Status = GetExpectedDescriptor ( |
822 | 27 | Ptr, |
823 | 27 | LengthLeft, |
824 | 27 | USB_DT_INTERFACE, |
825 | 27 | (UINT8)sizeof (EFI_USB_INTERFACE_DESCRIPTOR), |
826 | 27 | &SkipBytes |
827 | 27 | ); |
828 | | |
829 | 27 | if (EFI_ERROR (Status)) { |
830 | 10 | return Status; |
831 | 10 | } |
832 | | |
833 | 17 | Ptr += SkipBytes; |
834 | 17 | if (InterfaceIndex == 0) { |
835 | 9 | PeiUsbDevice->InterfaceDesc = (EFI_USB_INTERFACE_DESCRIPTOR *)Ptr; |
836 | 9 | } |
837 | | |
838 | 17 | PeiUsbDevice->InterfaceDescList[InterfaceIndex] = (EFI_USB_INTERFACE_DESCRIPTOR *)Ptr; |
839 | | |
840 | 17 | Ptr += sizeof (EFI_USB_INTERFACE_DESCRIPTOR); |
841 | 17 | LengthLeft -= SkipBytes; |
842 | 17 | LengthLeft -= sizeof (EFI_USB_INTERFACE_DESCRIPTOR); |
843 | | |
844 | | // |
845 | | // Parse all the endpoint descriptor within this interface |
846 | | // |
847 | 17 | NumOfEndpoint = PeiUsbDevice->InterfaceDescList[InterfaceIndex]->NumEndpoints; |
848 | 17 | if (NumOfEndpoint > MAX_ENDPOINT) { |
849 | 1 | DEBUG ((DEBUG_ERROR, "PeiUsbGet Number of endpoints in interface configuration exceeds maximum allowed")); |
850 | 1 | return EFI_DEVICE_ERROR; |
851 | 1 | } |
852 | | |
853 | 75 | for (Index = 0; Index < NumOfEndpoint; Index++) { |
854 | | // |
855 | | // Get the endpoint descriptor |
856 | | // |
857 | 64 | Status = GetExpectedDescriptor ( |
858 | 64 | Ptr, |
859 | 64 | LengthLeft, |
860 | 64 | USB_DT_ENDPOINT, |
861 | 64 | (UINT8)sizeof (EFI_USB_ENDPOINT_DESCRIPTOR), |
862 | 64 | &SkipBytes |
863 | 64 | ); |
864 | | |
865 | 64 | if (EFI_ERROR (Status)) { |
866 | 5 | return Status; |
867 | 5 | } |
868 | | |
869 | 59 | Ptr += SkipBytes; |
870 | 59 | if (InterfaceIndex == 0) { |
871 | 41 | PeiUsbDevice->EndpointDesc[Index] = (EFI_USB_ENDPOINT_DESCRIPTOR *)Ptr; |
872 | 41 | } |
873 | | |
874 | 59 | PeiUsbDevice->EndpointDescList[InterfaceIndex][Index] = (EFI_USB_ENDPOINT_DESCRIPTOR *)Ptr; |
875 | | |
876 | 59 | Ptr += sizeof (EFI_USB_ENDPOINT_DESCRIPTOR); |
877 | 59 | LengthLeft -= SkipBytes; |
878 | 59 | LengthLeft -= sizeof (EFI_USB_ENDPOINT_DESCRIPTOR); |
879 | 59 | } |
880 | 16 | } |
881 | | |
882 | 1 | return EFI_SUCCESS; |
883 | 17 | } |
884 | | |
885 | | /** |
886 | | Get the start position of next wanted descriptor. |
887 | | |
888 | | @param Buffer Buffer containing data to parse. |
889 | | @param Length Buffer length. |
890 | | @param DescType Descriptor type. |
891 | | @param DescLength Descriptor length. |
892 | | @param ParsedBytes Bytes has been parsed. |
893 | | |
894 | | @retval EFI_SUCCESS Get wanted descriptor successfully. |
895 | | @retval EFI_DEVICE_ERROR Error occurred. |
896 | | |
897 | | **/ |
898 | | EFI_STATUS |
899 | | GetExpectedDescriptor ( |
900 | | IN UINT8 *Buffer, |
901 | | IN UINTN Length, |
902 | | IN UINT8 DescType, |
903 | | IN UINT8 DescLength, |
904 | | OUT UINTN *ParsedBytes |
905 | | ) |
906 | 120 | { |
907 | 120 | USB_DESC_HEAD *Head; |
908 | 120 | UINTN Offset; |
909 | | |
910 | | // |
911 | | // Total length is too small that cannot hold the single descriptor header plus data. |
912 | | // |
913 | 120 | if (Length <= sizeof (USB_DESC_HEAD)) { |
914 | 0 | DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: met mal-format descriptor, total length = %d!\n", Length)); |
915 | 0 | return EFI_DEVICE_ERROR; |
916 | 0 | } |
917 | | |
918 | | // |
919 | | // All the descriptor has a common LTV (Length, Type, Value) |
920 | | // format. Skip the descriptor that isn't of this Type |
921 | | // |
922 | 120 | Offset = 0; |
923 | 120 | Head = (USB_DESC_HEAD *)Buffer; |
924 | 600 | while (Offset < Length - sizeof (USB_DESC_HEAD)) { |
925 | | // |
926 | | // Above condition make sure Head->Len and Head->Type are safe to access |
927 | | // |
928 | 586 | Head = (USB_DESC_HEAD *)&Buffer[Offset]; |
929 | | |
930 | 586 | if (Head->Len == 0) { |
931 | 13 | DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: met mal-format descriptor, Head->Len = 0!\n")); |
932 | 13 | return EFI_DEVICE_ERROR; |
933 | 13 | } |
934 | | |
935 | | // |
936 | | // Make sure no overflow when adding Head->Len to Offset. |
937 | | // |
938 | 573 | if (Head->Len > MAX_UINTN - Offset) { |
939 | 0 | DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: met mal-format descriptor, Head->Len = %d!\n", Head->Len)); |
940 | 0 | return EFI_DEVICE_ERROR; |
941 | 0 | } |
942 | | |
943 | 573 | if (Head->Type == DescType) { |
944 | 93 | break; |
945 | 93 | } |
946 | | |
947 | 480 | Offset += Head->Len; |
948 | 480 | } |
949 | | |
950 | | // |
951 | | // Head->Len is invalid resulting data beyond boundary, or |
952 | | // Descriptor cannot be found: No such type. |
953 | | // |
954 | 107 | if (Length < Offset) { |
955 | 14 | DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: met mal-format descriptor, Offset/Len = %d/%d!\n", Offset, Length)); |
956 | 14 | return EFI_DEVICE_ERROR; |
957 | 14 | } |
958 | | |
959 | 93 | if ((Head->Type != DescType) || (Head->Len < DescLength)) { |
960 | 0 | DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: descriptor cannot be found, Header(T/L) = %d/%d!\n", Head->Type, Head->Len)); |
961 | 0 | return EFI_DEVICE_ERROR; |
962 | 0 | } |
963 | | |
964 | 93 | *ParsedBytes = Offset; |
965 | 93 | return EFI_SUCCESS; |
966 | 93 | } |
967 | | |
968 | | /** |
969 | | Send reset signal over the given root hub port. |
970 | | |
971 | | @param PeiServices Describes the list of possible PEI Services. |
972 | | @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance. |
973 | | @param PortNum The port to be reset. |
974 | | @param RetryIndex The retry times. |
975 | | |
976 | | **/ |
977 | | VOID |
978 | | ResetRootPort ( |
979 | | IN EFI_PEI_SERVICES **PeiServices, |
980 | | IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi, |
981 | | IN UINT8 PortNum, |
982 | | IN UINT8 RetryIndex |
983 | | ) |
984 | 0 | { |
985 | 0 | EFI_STATUS Status; |
986 | 0 | UINTN Index; |
987 | 0 | EFI_USB_PORT_STATUS PortStatus; |
988 | |
|
989 | 0 | MicroSecondDelay (200 * 1000); |
990 | | |
991 | | // |
992 | | // reset root port |
993 | | // |
994 | 0 | Status = Usb2HcPpi->SetRootHubPortFeature ( |
995 | 0 | PeiServices, |
996 | 0 | Usb2HcPpi, |
997 | 0 | PortNum, |
998 | 0 | EfiUsbPortReset |
999 | 0 | ); |
1000 | |
|
1001 | 0 | if (EFI_ERROR (Status)) { |
1002 | 0 | DEBUG ((DEBUG_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n")); |
1003 | 0 | return; |
1004 | 0 | } |
1005 | | |
1006 | | // |
1007 | | // Drive the reset signal for at least 50ms. Check USB 2.0 Spec |
1008 | | // section 7.1.7.5 for timing requirements. |
1009 | | // |
1010 | 0 | MicroSecondDelay (USB_SET_ROOT_PORT_RESET_STALL); |
1011 | | |
1012 | | // |
1013 | | // clear reset root port |
1014 | | // |
1015 | 0 | Status = Usb2HcPpi->ClearRootHubPortFeature ( |
1016 | 0 | PeiServices, |
1017 | 0 | Usb2HcPpi, |
1018 | 0 | PortNum, |
1019 | 0 | EfiUsbPortReset |
1020 | 0 | ); |
1021 | |
|
1022 | 0 | if (EFI_ERROR (Status)) { |
1023 | 0 | DEBUG ((DEBUG_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n")); |
1024 | 0 | return; |
1025 | 0 | } |
1026 | | |
1027 | 0 | MicroSecondDelay (USB_CLR_ROOT_PORT_RESET_STALL); |
1028 | | |
1029 | | // |
1030 | | // USB host controller won't clear the RESET bit until |
1031 | | // reset is actually finished. |
1032 | | // |
1033 | 0 | ZeroMem (&PortStatus, sizeof (EFI_USB_PORT_STATUS)); |
1034 | |
|
1035 | 0 | for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) { |
1036 | 0 | Status = Usb2HcPpi->GetRootHubPortStatus ( |
1037 | 0 | PeiServices, |
1038 | 0 | Usb2HcPpi, |
1039 | 0 | PortNum, |
1040 | 0 | &PortStatus |
1041 | 0 | ); |
1042 | 0 | if (EFI_ERROR (Status)) { |
1043 | 0 | return; |
1044 | 0 | } |
1045 | | |
1046 | 0 | if (!USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_RESET)) { |
1047 | 0 | break; |
1048 | 0 | } |
1049 | | |
1050 | 0 | MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL); |
1051 | 0 | } |
1052 | | |
1053 | 0 | if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) { |
1054 | 0 | DEBUG ((DEBUG_ERROR, "ResetRootPort: reset not finished in time on port %d\n", PortNum)); |
1055 | 0 | return; |
1056 | 0 | } |
1057 | | |
1058 | 0 | Usb2HcPpi->ClearRootHubPortFeature ( |
1059 | 0 | PeiServices, |
1060 | 0 | Usb2HcPpi, |
1061 | 0 | PortNum, |
1062 | 0 | EfiUsbPortResetChange |
1063 | 0 | ); |
1064 | |
|
1065 | 0 | Usb2HcPpi->ClearRootHubPortFeature ( |
1066 | 0 | PeiServices, |
1067 | 0 | Usb2HcPpi, |
1068 | 0 | PortNum, |
1069 | 0 | EfiUsbPortConnectChange |
1070 | 0 | ); |
1071 | | |
1072 | | // |
1073 | | // Set port enable |
1074 | | // |
1075 | 0 | Usb2HcPpi->SetRootHubPortFeature ( |
1076 | 0 | PeiServices, |
1077 | 0 | Usb2HcPpi, |
1078 | 0 | PortNum, |
1079 | 0 | EfiUsbPortEnable |
1080 | 0 | ); |
1081 | |
|
1082 | 0 | Usb2HcPpi->ClearRootHubPortFeature ( |
1083 | 0 | PeiServices, |
1084 | 0 | Usb2HcPpi, |
1085 | 0 | PortNum, |
1086 | 0 | EfiUsbPortEnableChange |
1087 | 0 | ); |
1088 | |
|
1089 | 0 | MicroSecondDelay ((RetryIndex + 1) * 50 * 1000); |
1090 | 0 | } |