MdeModulePkg UsbBusPei: Fix wrong buffer length used to read hub desc
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusPei / HubPeim.c
1 /** @file
2 Usb Hub Request Support In PEI Phase
3
4 Copyright (c) 2006 - 2018, 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 "HubPeim.h"
19 #include "PeiUsbLib.h"
20
21 /**
22 Get a given hub port status.
23
24 @param PeiServices General-purpose services that are available to every PEIM.
25 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
26 @param Port Usb hub port number (starting from 1).
27 @param PortStatus Current Hub port status and change status.
28
29 @retval EFI_SUCCESS Port status is obtained successfully.
30 @retval EFI_DEVICE_ERROR Cannot get the port status due to a hardware error.
31 @retval Others Other failure occurs.
32
33 **/
34 EFI_STATUS
35 PeiHubGetPortStatus (
36 IN EFI_PEI_SERVICES **PeiServices,
37 IN PEI_USB_IO_PPI *UsbIoPpi,
38 IN UINT8 Port,
39 OUT UINT32 *PortStatus
40 )
41 {
42 EFI_USB_DEVICE_REQUEST DeviceRequest;
43
44 ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
45
46 //
47 // Fill Device request packet
48 //
49 DeviceRequest.RequestType = USB_HUB_GET_PORT_STATUS_REQ_TYPE;
50 DeviceRequest.Request = USB_HUB_GET_PORT_STATUS;
51 DeviceRequest.Index = Port;
52 DeviceRequest.Length = (UINT16) sizeof (UINT32);
53
54
55 return UsbIoPpi->UsbControlTransfer (
56 PeiServices,
57 UsbIoPpi,
58 &DeviceRequest,
59 EfiUsbDataIn,
60 PcdGet32 (PcdUsbTransferTimeoutValue),
61 PortStatus,
62 sizeof (UINT32)
63 );
64
65 }
66
67 /**
68 Set specified feature to a given hub port.
69
70 @param PeiServices General-purpose services that are available to every PEIM.
71 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
72 @param Port Usb hub port number (starting from 1).
73 @param Value New feature value.
74
75 @retval EFI_SUCCESS Port feature is set successfully.
76 @retval EFI_DEVICE_ERROR Cannot set the port feature due to a hardware error.
77 @retval Others Other failure occurs.
78
79 **/
80 EFI_STATUS
81 PeiHubSetPortFeature (
82 IN EFI_PEI_SERVICES **PeiServices,
83 IN PEI_USB_IO_PPI *UsbIoPpi,
84 IN UINT8 Port,
85 IN UINT8 Value
86 )
87 {
88 EFI_USB_DEVICE_REQUEST DeviceRequest;
89
90 ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
91
92 //
93 // Fill Device request packet
94 //
95 DeviceRequest.RequestType = USB_HUB_SET_PORT_FEATURE_REQ_TYPE;
96 DeviceRequest.Request = USB_HUB_SET_PORT_FEATURE;
97 DeviceRequest.Value = Value;
98 DeviceRequest.Index = Port;
99
100 return UsbIoPpi->UsbControlTransfer (
101 PeiServices,
102 UsbIoPpi,
103 &DeviceRequest,
104 EfiUsbNoData,
105 PcdGet32 (PcdUsbTransferTimeoutValue),
106 NULL,
107 0
108 );
109 }
110
111 /**
112 Clear specified feature on a given hub port.
113
114 @param PeiServices General-purpose services that are available to every PEIM.
115 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
116 @param Port Usb hub port number (starting from 1).
117 @param Value Feature value that will be cleared from the hub port.
118
119 @retval EFI_SUCCESS Port feature is cleared successfully.
120 @retval EFI_DEVICE_ERROR Cannot clear the port feature due to a hardware error.
121 @retval Others Other failure occurs.
122
123 **/
124 EFI_STATUS
125 PeiHubClearPortFeature (
126 IN EFI_PEI_SERVICES **PeiServices,
127 IN PEI_USB_IO_PPI *UsbIoPpi,
128 IN UINT8 Port,
129 IN UINT8 Value
130 )
131 {
132 EFI_USB_DEVICE_REQUEST DeviceRequest;
133
134 ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
135
136 //
137 // Fill Device request packet
138 //
139 DeviceRequest.RequestType = USB_HUB_CLEAR_FEATURE_PORT_REQ_TYPE;
140 DeviceRequest.Request = USB_HUB_CLEAR_FEATURE_PORT;
141 DeviceRequest.Value = Value;
142 DeviceRequest.Index = Port;
143
144 return UsbIoPpi->UsbControlTransfer (
145 PeiServices,
146 UsbIoPpi,
147 &DeviceRequest,
148 EfiUsbNoData,
149 PcdGet32 (PcdUsbTransferTimeoutValue),
150 NULL,
151 0
152 );
153 }
154
155 /**
156 Get a given hub status.
157
158 @param PeiServices General-purpose services that are available to every PEIM.
159 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
160 @param HubStatus Current Hub status and change status.
161
162 @retval EFI_SUCCESS Hub status is obtained successfully.
163 @retval EFI_DEVICE_ERROR Cannot get the hub status due to a hardware error.
164 @retval Others Other failure occurs.
165
166 **/
167 EFI_STATUS
168 PeiHubGetHubStatus (
169 IN EFI_PEI_SERVICES **PeiServices,
170 IN PEI_USB_IO_PPI *UsbIoPpi,
171 OUT UINT32 *HubStatus
172 )
173 {
174 EFI_USB_DEVICE_REQUEST DeviceRequest;
175
176 ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
177
178 //
179 // Fill Device request packet
180 //
181 DeviceRequest.RequestType = USB_HUB_GET_HUB_STATUS_REQ_TYPE;
182 DeviceRequest.Request = USB_HUB_GET_HUB_STATUS;
183 DeviceRequest.Length = (UINT16) sizeof (UINT32);
184
185 return UsbIoPpi->UsbControlTransfer (
186 PeiServices,
187 UsbIoPpi,
188 &DeviceRequest,
189 EfiUsbDataIn,
190 PcdGet32 (PcdUsbTransferTimeoutValue),
191 HubStatus,
192 sizeof (UINT32)
193 );
194 }
195
196 /**
197 Set specified feature to a given hub.
198
199 @param PeiServices General-purpose services that are available to every PEIM.
200 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
201 @param Value New feature value.
202
203 @retval EFI_SUCCESS Port feature is set successfully.
204 @retval EFI_DEVICE_ERROR Cannot set the port feature due to a hardware error.
205 @retval Others Other failure occurs.
206
207 **/
208 EFI_STATUS
209 PeiHubSetHubFeature (
210 IN EFI_PEI_SERVICES **PeiServices,
211 IN PEI_USB_IO_PPI *UsbIoPpi,
212 IN UINT8 Value
213 )
214 {
215 EFI_USB_DEVICE_REQUEST DeviceRequest;
216
217 ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
218
219 //
220 // Fill Device request packet
221 //
222 DeviceRequest.RequestType = USB_HUB_SET_HUB_FEATURE_REQ_TYPE;
223 DeviceRequest.Request = USB_HUB_SET_HUB_FEATURE;
224 DeviceRequest.Value = Value;
225
226 return UsbIoPpi->UsbControlTransfer (
227 PeiServices,
228 UsbIoPpi,
229 &DeviceRequest,
230 EfiUsbNoData,
231 PcdGet32 (PcdUsbTransferTimeoutValue),
232 NULL,
233 0
234 );
235 }
236
237 /**
238 Clear specified feature on a given hub.
239
240 @param PeiServices General-purpose services that are available to every PEIM.
241 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
242 @param Value Feature value that will be cleared from the hub port.
243
244 @retval EFI_SUCCESS Hub feature is cleared successfully.
245 @retval EFI_DEVICE_ERROR Cannot clear the hub feature due to a hardware error.
246 @retval Others Other failure occurs.
247
248 **/
249 EFI_STATUS
250 PeiHubClearHubFeature (
251 IN EFI_PEI_SERVICES **PeiServices,
252 IN PEI_USB_IO_PPI *UsbIoPpi,
253 IN UINT8 Value
254 )
255 {
256 EFI_USB_DEVICE_REQUEST DeviceRequest;
257
258 ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
259
260 //
261 // Fill Device request packet
262 //
263 DeviceRequest.RequestType = USB_HUB_CLEAR_FEATURE_REQ_TYPE;
264 DeviceRequest.Request = USB_HUB_CLEAR_FEATURE;
265 DeviceRequest.Value = Value;
266
267 return UsbIoPpi->UsbControlTransfer (
268 PeiServices,
269 UsbIoPpi,
270 &DeviceRequest,
271 EfiUsbNoData,
272 PcdGet32 (PcdUsbTransferTimeoutValue),
273 NULL,
274 0
275 );
276 }
277
278 /**
279 Get a given (SuperSpeed) hub descriptor.
280
281 @param PeiServices General-purpose services that are available to every PEIM.
282 @param PeiUsbDevice Indicates the hub controller device.
283 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
284 @param DescriptorSize The length of Hub Descriptor buffer.
285 @param HubDescriptor Caller allocated buffer to store the hub descriptor if
286 successfully returned.
287
288 @retval EFI_SUCCESS Hub descriptor is obtained successfully.
289 @retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error.
290 @retval Others Other failure occurs.
291
292 **/
293 EFI_STATUS
294 PeiGetHubDescriptor (
295 IN EFI_PEI_SERVICES **PeiServices,
296 IN PEI_USB_DEVICE *PeiUsbDevice,
297 IN PEI_USB_IO_PPI *UsbIoPpi,
298 IN UINTN DescriptorSize,
299 OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor
300 )
301 {
302 EFI_USB_DEVICE_REQUEST DevReq;
303 UINT8 DescType;
304
305 ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
306
307 DescType = (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) ?
308 USB_DT_SUPERSPEED_HUB :
309 USB_DT_HUB;
310
311 //
312 // Fill Device request packet
313 //
314 DevReq.RequestType = USB_RT_HUB | 0x80;
315 DevReq.Request = USB_HUB_GET_DESCRIPTOR;
316 DevReq.Value = (UINT16) (DescType << 8);
317 DevReq.Length = (UINT16) DescriptorSize;
318
319 return UsbIoPpi->UsbControlTransfer (
320 PeiServices,
321 UsbIoPpi,
322 &DevReq,
323 EfiUsbDataIn,
324 PcdGet32 (PcdUsbTransferTimeoutValue),
325 HubDescriptor,
326 (UINT16)DescriptorSize
327 );
328 }
329
330 /**
331 Read the whole usb hub descriptor. It is necessary
332 to do it in two steps because hub descriptor is of
333 variable length.
334
335 @param PeiServices General-purpose services that are available to every PEIM.
336 @param PeiUsbDevice Indicates the hub controller device.
337 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
338 @param HubDescriptor Caller allocated buffer to store the hub descriptor if
339 successfully returned.
340
341 @retval EFI_SUCCESS Hub descriptor is obtained successfully.
342 @retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error.
343 @retval Others Other failure occurs.
344
345 **/
346 EFI_STATUS
347 PeiUsbHubReadDesc (
348 IN EFI_PEI_SERVICES **PeiServices,
349 IN PEI_USB_DEVICE *PeiUsbDevice,
350 IN PEI_USB_IO_PPI *UsbIoPpi,
351 OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor
352 )
353 {
354 EFI_STATUS Status;
355
356 //
357 // First get the hub descriptor length
358 //
359 Status = PeiGetHubDescriptor (PeiServices, PeiUsbDevice, UsbIoPpi, 2, HubDescriptor);
360
361 if (EFI_ERROR (Status)) {
362 return Status;
363 }
364
365 //
366 // Get the whole hub descriptor
367 //
368 return PeiGetHubDescriptor (PeiServices, PeiUsbDevice, UsbIoPpi, HubDescriptor->Length, HubDescriptor);
369 }
370
371 /**
372 USB hub control transfer to set the hub depth.
373
374 @param PeiServices General-purpose services that are available to every PEIM.
375 @param PeiUsbDevice Indicates the hub controller device.
376 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
377
378 @retval EFI_SUCCESS Depth of the hub is set.
379 @retval Others Failed to set the depth.
380
381 **/
382 EFI_STATUS
383 PeiUsbHubCtrlSetHubDepth (
384 IN EFI_PEI_SERVICES **PeiServices,
385 IN PEI_USB_DEVICE *PeiUsbDevice,
386 IN PEI_USB_IO_PPI *UsbIoPpi
387 )
388 {
389 EFI_USB_DEVICE_REQUEST DevReq;
390 ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
391
392 //
393 // Fill Device request packet
394 //
395 DevReq.RequestType = USB_RT_HUB;
396 DevReq.Request = USB_HUB_REQ_SET_DEPTH;
397 DevReq.Value = PeiUsbDevice->Tier;
398 DevReq.Length = 0;
399
400 return UsbIoPpi->UsbControlTransfer (
401 PeiServices,
402 UsbIoPpi,
403 &DevReq,
404 EfiUsbNoData,
405 PcdGet32 (PcdUsbTransferTimeoutValue),
406 NULL,
407 0
408 );
409 }
410
411 /**
412 Configure a given hub.
413
414 @param PeiServices General-purpose services that are available to every PEIM.
415 @param PeiUsbDevice Indicating the hub controller device that will be configured
416
417 @retval EFI_SUCCESS Hub configuration is done successfully.
418 @retval EFI_DEVICE_ERROR Cannot configure the hub due to a hardware error.
419
420 **/
421 EFI_STATUS
422 PeiDoHubConfig (
423 IN EFI_PEI_SERVICES **PeiServices,
424 IN PEI_USB_DEVICE *PeiUsbDevice
425 )
426 {
427 UINT8 HubDescBuffer[256];
428 EFI_USB_HUB_DESCRIPTOR *HubDescriptor;
429 EFI_STATUS Status;
430 EFI_USB_HUB_STATUS HubStatus;
431 UINTN Index;
432 PEI_USB_IO_PPI *UsbIoPpi;
433
434 UsbIoPpi = &PeiUsbDevice->UsbIoPpi;
435
436 //
437 // The length field of descriptor is UINT8 type, so the buffer
438 // with 256 bytes is enough to hold the descriptor data.
439 //
440 HubDescriptor = (EFI_USB_HUB_DESCRIPTOR *) HubDescBuffer;
441
442 //
443 // Get the hub descriptor
444 //
445 Status = PeiUsbHubReadDesc (
446 PeiServices,
447 PeiUsbDevice,
448 UsbIoPpi,
449 HubDescriptor
450 );
451 if (EFI_ERROR (Status)) {
452 return EFI_DEVICE_ERROR;
453 }
454
455 PeiUsbDevice->DownStreamPortNo = HubDescriptor->NbrPorts;
456
457 if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) {
458 DEBUG ((EFI_D_INFO, "PeiDoHubConfig: Set Hub Depth as 0x%x\n", PeiUsbDevice->Tier));
459 PeiUsbHubCtrlSetHubDepth (
460 PeiServices,
461 PeiUsbDevice,
462 UsbIoPpi
463 );
464 } else {
465 //
466 // Power all the hub ports
467 //
468 for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {
469 Status = PeiHubSetPortFeature (
470 PeiServices,
471 UsbIoPpi,
472 (UINT8) (Index + 1),
473 EfiUsbPortPower
474 );
475 if (EFI_ERROR (Status)) {
476 DEBUG (( EFI_D_ERROR, "PeiDoHubConfig: PeiHubSetPortFeature EfiUsbPortPower failed %x\n", Index));
477 continue;
478 }
479 }
480
481 DEBUG (( EFI_D_INFO, "PeiDoHubConfig: HubDescriptor.PwrOn2PwrGood: 0x%x\n", HubDescriptor->PwrOn2PwrGood));
482 if (HubDescriptor->PwrOn2PwrGood > 0) {
483 MicroSecondDelay (HubDescriptor->PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);
484 }
485
486 //
487 // Clear Hub Status Change
488 //
489 Status = PeiHubGetHubStatus (
490 PeiServices,
491 UsbIoPpi,
492 (UINT32 *) &HubStatus
493 );
494 if (EFI_ERROR (Status)) {
495 return EFI_DEVICE_ERROR;
496 } else {
497 //
498 // Hub power supply change happens
499 //
500 if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) {
501 PeiHubClearHubFeature (
502 PeiServices,
503 UsbIoPpi,
504 C_HUB_LOCAL_POWER
505 );
506 }
507 //
508 // Hub change overcurrent happens
509 //
510 if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) {
511 PeiHubClearHubFeature (
512 PeiServices,
513 UsbIoPpi,
514 C_HUB_OVER_CURRENT
515 );
516 }
517 }
518 }
519
520 return EFI_SUCCESS;
521 }
522
523 /**
524 Send reset signal over the given root hub port.
525
526 @param PeiServices General-purpose services that are available to every PEIM.
527 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
528 @param PortNum Usb hub port number (starting from 1).
529
530 **/
531 VOID
532 PeiResetHubPort (
533 IN EFI_PEI_SERVICES **PeiServices,
534 IN PEI_USB_IO_PPI *UsbIoPpi,
535 IN UINT8 PortNum
536 )
537 {
538 EFI_STATUS Status;
539 UINTN Index;
540 EFI_USB_PORT_STATUS HubPortStatus;
541
542 MicroSecondDelay (100 * 1000);
543
544 //
545 // reset root port
546 //
547 PeiHubSetPortFeature (
548 PeiServices,
549 UsbIoPpi,
550 PortNum,
551 EfiUsbPortReset
552 );
553
554 //
555 // Drive the reset signal for worst 20ms. Check USB 2.0 Spec
556 // section 7.1.7.5 for timing requirements.
557 //
558 MicroSecondDelay (USB_SET_PORT_RESET_STALL);
559
560 //
561 // Check USB_PORT_STAT_C_RESET bit to see if the resetting state is done.
562 //
563 ZeroMem (&HubPortStatus, sizeof (EFI_USB_PORT_STATUS));
564
565 for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
566 Status = PeiHubGetPortStatus (
567 PeiServices,
568 UsbIoPpi,
569 PortNum,
570 (UINT32 *) &HubPortStatus
571 );
572
573 if (EFI_ERROR (Status)) {
574 return;
575 }
576
577 if (USB_BIT_IS_SET (HubPortStatus.PortChangeStatus, USB_PORT_STAT_C_RESET)) {
578 break;
579 }
580
581 MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);
582 }
583
584 if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
585 DEBUG ((EFI_D_ERROR, "PeiResetHubPort: reset not finished in time on port %d\n", PortNum));
586 return;
587 }
588
589 //
590 // clear reset change root port
591 //
592 PeiHubClearPortFeature (
593 PeiServices,
594 UsbIoPpi,
595 PortNum,
596 EfiUsbPortResetChange
597 );
598
599 MicroSecondDelay (1 * 1000);
600
601 PeiHubClearPortFeature (
602 PeiServices,
603 UsbIoPpi,
604 PortNum,
605 EfiUsbPortConnectChange
606 );
607
608 //
609 // Set port enable
610 //
611 PeiHubSetPortFeature (
612 PeiServices,
613 UsbIoPpi,
614 PortNum,
615 EfiUsbPortEnable
616 );
617
618 //
619 // Clear any change status
620 //
621
622 PeiHubClearPortFeature (
623 PeiServices,
624 UsbIoPpi,
625 PortNum,
626 EfiUsbPortEnableChange
627 );
628
629 MicroSecondDelay (10 * 1000);
630
631 return;
632 }