]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c
MdeModulePkg: Improve formatting of DEBUG messages in UsbBusDxe
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusDxe / UsbDesc.c
CommitLineData
e237e7ae 1/** @file\r
2\r
8616fc4c 3 Manage Usb Descriptor List\r
4\r
d1102dba 5Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
e237e7ae 7\r
e237e7ae 8**/\r
9\r
10#include "UsbBus.h"\r
11\r
e237e7ae 12/**\r
8616fc4c 13 Free the interface setting descriptor.\r
e237e7ae 14\r
8616fc4c 15 @param Setting The descriptor to free.\r
e237e7ae 16\r
e237e7ae 17**/\r
e237e7ae 18VOID\r
19UsbFreeInterfaceDesc (\r
20 IN USB_INTERFACE_SETTING *Setting\r
21 )\r
22{\r
1436aea4
MK
23 USB_ENDPOINT_DESC *Ep;\r
24 UINTN Index;\r
e237e7ae 25\r
26 if (Setting->Endpoints != NULL) {\r
27 //\r
28 // Each interface setting may have several endpoints, free them first.\r
29 //\r
30 for (Index = 0; Index < Setting->Desc.NumEndpoints; Index++) {\r
31 Ep = Setting->Endpoints[Index];\r
32\r
33 if (Ep != NULL) {\r
d17371e8 34 FreePool (Ep);\r
e237e7ae 35 }\r
36 }\r
37\r
efe9186f 38 //\r
39 // Only call FreePool() if NumEndpoints > 0.\r
40 //\r
41 if (Setting->Desc.NumEndpoints > 0) {\r
42 FreePool (Setting->Endpoints);\r
43 }\r
e237e7ae 44 }\r
45\r
d17371e8 46 FreePool (Setting);\r
e237e7ae 47}\r
48\r
e237e7ae 49/**\r
50 Free a configuration descriptor with its interface\r
8616fc4c 51 descriptors. It may be initialized partially.\r
e237e7ae 52\r
8616fc4c 53 @param Config The configuration descriptor to free.\r
e237e7ae 54\r
e237e7ae 55**/\r
e237e7ae 56VOID\r
57UsbFreeConfigDesc (\r
1436aea4 58 IN USB_CONFIG_DESC *Config\r
e237e7ae 59 )\r
60{\r
1436aea4
MK
61 USB_INTERFACE_DESC *Interface;\r
62 UINTN Index;\r
63 UINTN SetIndex;\r
e237e7ae 64\r
65 if (Config->Interfaces != NULL) {\r
66 //\r
67 // A configuration may have several interfaces, free the interface\r
68 //\r
69 for (Index = 0; Index < Config->Desc.NumInterfaces; Index++) {\r
70 Interface = Config->Interfaces[Index];\r
71\r
72 if (Interface == NULL) {\r
73 continue;\r
74 }\r
75\r
76 //\r
77 // Each interface may have several settings, free the settings\r
78 //\r
79 for (SetIndex = 0; SetIndex < Interface->NumOfSetting; SetIndex++) {\r
80 if (Interface->Settings[SetIndex] != NULL) {\r
81 UsbFreeInterfaceDesc (Interface->Settings[SetIndex]);\r
82 }\r
83 }\r
84\r
d17371e8 85 FreePool (Interface);\r
e237e7ae 86 }\r
87\r
d17371e8 88 FreePool (Config->Interfaces);\r
e237e7ae 89 }\r
90\r
d17371e8 91 FreePool (Config);\r
e237e7ae 92}\r
93\r
e237e7ae 94/**\r
8616fc4c 95 Free a device descriptor with its configurations.\r
e237e7ae 96\r
8616fc4c 97 @param DevDesc The device descriptor.\r
e237e7ae 98\r
e237e7ae 99**/\r
100VOID\r
101UsbFreeDevDesc (\r
1436aea4 102 IN USB_DEVICE_DESC *DevDesc\r
e237e7ae 103 )\r
104{\r
1436aea4 105 UINTN Index;\r
e237e7ae 106\r
107 if (DevDesc->Configs != NULL) {\r
108 for (Index = 0; Index < DevDesc->Desc.NumConfigurations; Index++) {\r
109 if (DevDesc->Configs[Index] != NULL) {\r
110 UsbFreeConfigDesc (DevDesc->Configs[Index]);\r
111 }\r
112 }\r
113\r
d17371e8 114 FreePool (DevDesc->Configs);\r
e237e7ae 115 }\r
116\r
d17371e8 117 FreePool (DevDesc);\r
e237e7ae 118}\r
119\r
e237e7ae 120/**\r
8616fc4c 121 Create a descriptor.\r
e237e7ae 122\r
8616fc4c 123 @param DescBuf The buffer of raw descriptor.\r
d17371e8 124 @param Len The length of the raw descriptor buffer.\r
8616fc4c 125 @param Type The type of descriptor to create.\r
126 @param Consumed Number of bytes consumed.\r
e237e7ae 127\r
8616fc4c 128 @return Created descriptor or NULL.\r
e237e7ae 129\r
130**/\r
e237e7ae 131VOID *\r
132UsbCreateDesc (\r
1436aea4
MK
133 IN UINT8 *DescBuf,\r
134 IN UINTN Len,\r
135 IN UINT8 Type,\r
136 OUT UINTN *Consumed\r
e237e7ae 137 )\r
138{\r
1436aea4
MK
139 USB_DESC_HEAD *Head;\r
140 UINTN DescLen;\r
141 UINTN CtrlLen;\r
142 UINTN Offset;\r
143 VOID *Desc;\r
e237e7ae 144\r
145 DescLen = 0;\r
146 CtrlLen = 0;\r
147 *Consumed = 0;\r
148\r
149 switch (Type) {\r
1436aea4
MK
150 case USB_DESC_TYPE_DEVICE:\r
151 DescLen = sizeof (EFI_USB_DEVICE_DESCRIPTOR);\r
152 CtrlLen = sizeof (USB_DEVICE_DESC);\r
153 break;\r
154\r
155 case USB_DESC_TYPE_CONFIG:\r
156 DescLen = sizeof (EFI_USB_CONFIG_DESCRIPTOR);\r
157 CtrlLen = sizeof (USB_CONFIG_DESC);\r
158 break;\r
159\r
160 case USB_DESC_TYPE_INTERFACE:\r
161 DescLen = sizeof (EFI_USB_INTERFACE_DESCRIPTOR);\r
162 CtrlLen = sizeof (USB_INTERFACE_SETTING);\r
163 break;\r
164\r
165 case USB_DESC_TYPE_ENDPOINT:\r
166 DescLen = sizeof (EFI_USB_ENDPOINT_DESCRIPTOR);\r
167 CtrlLen = sizeof (USB_ENDPOINT_DESC);\r
168 break;\r
169\r
170 default:\r
171 ASSERT (FALSE);\r
172 return NULL;\r
4c034bf6
RN
173 }\r
174\r
175 //\r
0bc7448a 176 // Total length is too small that cannot hold the single descriptor header plus data.\r
4c034bf6
RN
177 //\r
178 if (Len <= sizeof (USB_DESC_HEAD)) {\r
179 DEBUG ((DEBUG_ERROR, "UsbCreateDesc: met mal-format descriptor, total length = %d!\n", Len));\r
180 return NULL;\r
e237e7ae 181 }\r
182\r
183 //\r
184 // All the descriptor has a common LTV (Length, Type, Value)\r
185 // format. Skip the descriptor that isn't of this Type\r
186 //\r
187 Offset = 0;\r
4c034bf6
RN
188 Head = (USB_DESC_HEAD *)DescBuf;\r
189 while (Offset < Len - sizeof (USB_DESC_HEAD)) {\r
190 //\r
191 // Above condition make sure Head->Len and Head->Type are safe to access\r
192 //\r
193 Head = (USB_DESC_HEAD *)&DescBuf[Offset];\r
e237e7ae 194\r
4c034bf6
RN
195 if (Head->Len == 0) {\r
196 DEBUG ((DEBUG_ERROR, "UsbCreateDesc: met mal-format descriptor, Head->Len = 0!\n"));\r
4de9d876
FT
197 return NULL;\r
198 }\r
4c034bf6
RN
199\r
200 //\r
201 // Make sure no overflow when adding Head->Len to Offset.\r
202 //\r
203 if (Head->Len > MAX_UINTN - Offset) {\r
204 DEBUG ((DEBUG_ERROR, "UsbCreateDesc: met mal-format descriptor, Head->Len = %d!\n", Head->Len));\r
4de9d876
FT
205 return NULL;\r
206 }\r
4c034bf6
RN
207\r
208 Offset += Head->Len;\r
209\r
210 if (Head->Type == Type) {\r
211 break;\r
212 }\r
213 }\r
214\r
215 //\r
216 // Head->Len is invalid resulting data beyond boundary, or\r
217 // Descriptor cannot be found: No such type.\r
218 //\r
219 if (Len < Offset) {\r
220 DEBUG ((DEBUG_ERROR, "UsbCreateDesc: met mal-format descriptor, Offset/Len = %d/%d!\n", Offset, Len));\r
c87ac38c 221 return NULL;\r
e237e7ae 222 }\r
223\r
4c034bf6
RN
224 if ((Head->Type != Type) || (Head->Len < DescLen)) {\r
225 DEBUG ((DEBUG_ERROR, "UsbCreateDesc: descriptor cannot be found, Header(T/L) = %d/%d!\n", Head->Type, Head->Len));\r
e237e7ae 226 return NULL;\r
227 }\r
228\r
1436aea4 229 Desc = AllocateZeroPool ((UINTN)CtrlLen);\r
e237e7ae 230 if (Desc == NULL) {\r
231 return NULL;\r
232 }\r
efe9186f 233\r
1436aea4 234 CopyMem (Desc, Head, (UINTN)DescLen);\r
efe9186f 235\r
4c034bf6 236 *Consumed = Offset;\r
e237e7ae 237\r
238 return Desc;\r
239}\r
240\r
e237e7ae 241/**\r
d17371e8 242 Parse an interface descriptor and its endpoints.\r
e237e7ae 243\r
8616fc4c 244 @param DescBuf The buffer of raw descriptor.\r
d17371e8 245 @param Len The length of the raw descriptor buffer.\r
8616fc4c 246 @param Consumed The number of raw descriptor consumed.\r
e237e7ae 247\r
8616fc4c 248 @return The create interface setting or NULL if failed.\r
e237e7ae 249\r
250**/\r
e237e7ae 251USB_INTERFACE_SETTING *\r
252UsbParseInterfaceDesc (\r
1436aea4
MK
253 IN UINT8 *DescBuf,\r
254 IN UINTN Len,\r
255 OUT UINTN *Consumed\r
e237e7ae 256 )\r
257{\r
1436aea4
MK
258 USB_INTERFACE_SETTING *Setting;\r
259 USB_ENDPOINT_DESC *Ep;\r
260 UINTN Index;\r
261 UINTN NumEp;\r
262 UINTN Used;\r
263 UINTN Offset;\r
e237e7ae 264\r
265 *Consumed = 0;\r
266 Setting = UsbCreateDesc (DescBuf, Len, USB_DESC_TYPE_INTERFACE, &Used);\r
267\r
268 if (Setting == NULL) {\r
1436aea4 269 DEBUG ((DEBUG_ERROR, "UsbParseInterfaceDesc: failed to create interface descriptor\n"));\r
e237e7ae 270 return NULL;\r
271 }\r
272\r
273 Offset = Used;\r
274\r
275 //\r
d17371e8 276 // Create an array to hold the interface's endpoints\r
e237e7ae 277 //\r
1436aea4 278 NumEp = Setting->Desc.NumEndpoints;\r
e237e7ae 279\r
1436aea4
MK
280 DEBUG ((\r
281 DEBUG_INFO,\r
282 "UsbParseInterfaceDesc: interface %d(setting %d) has %d endpoints\n",\r
283 Setting->Desc.InterfaceNumber,\r
284 Setting->Desc.AlternateSetting,\r
285 (UINT32)NumEp\r
286 ));\r
e237e7ae 287\r
288 if (NumEp == 0) {\r
289 goto ON_EXIT;\r
290 }\r
291\r
1436aea4 292 Setting->Endpoints = AllocateZeroPool (sizeof (USB_ENDPOINT_DESC *) * NumEp);\r
e237e7ae 293\r
294 if (Setting->Endpoints == NULL) {\r
295 goto ON_ERROR;\r
296 }\r
297\r
298 //\r
299 // Create the endpoints for this interface\r
300 //\r
4de9d876 301 for (Index = 0; (Index < NumEp) && (Offset < Len); Index++) {\r
e237e7ae 302 Ep = UsbCreateDesc (DescBuf + Offset, Len - Offset, USB_DESC_TYPE_ENDPOINT, &Used);\r
303\r
304 if (Ep == NULL) {\r
1436aea4 305 DEBUG ((DEBUG_ERROR, "UsbParseInterfaceDesc: failed to create endpoint(index %d)\n", (UINT32)Index));\r
e237e7ae 306 goto ON_ERROR;\r
307 }\r
308\r
1436aea4
MK
309 Setting->Endpoints[Index] = Ep;\r
310 Offset += Used;\r
e237e7ae 311 }\r
312\r
e237e7ae 313ON_EXIT:\r
314 *Consumed = Offset;\r
315 return Setting;\r
316\r
317ON_ERROR:\r
318 UsbFreeInterfaceDesc (Setting);\r
319 return NULL;\r
320}\r
321\r
e237e7ae 322/**\r
323 Parse the configuration descriptor and its interfaces.\r
324\r
8616fc4c 325 @param DescBuf The buffer of raw descriptor.\r
d17371e8 326 @param Len The length of the raw descriptor buffer.\r
e237e7ae 327\r
8616fc4c 328 @return The created configuration descriptor.\r
e237e7ae 329\r
330**/\r
e237e7ae 331USB_CONFIG_DESC *\r
332UsbParseConfigDesc (\r
1436aea4
MK
333 IN UINT8 *DescBuf,\r
334 IN UINTN Len\r
e237e7ae 335 )\r
336{\r
1436aea4
MK
337 USB_CONFIG_DESC *Config;\r
338 USB_INTERFACE_SETTING *Setting;\r
339 USB_INTERFACE_DESC *Interface;\r
340 UINTN Index;\r
341 UINTN NumIf;\r
342 UINTN Consumed;\r
e237e7ae 343\r
344 ASSERT (DescBuf != NULL);\r
345\r
346 Config = UsbCreateDesc (DescBuf, Len, USB_DESC_TYPE_CONFIG, &Consumed);\r
347\r
348 if (Config == NULL) {\r
349 return NULL;\r
350 }\r
351\r
352 //\r
353 // Initialize an array of setting for the configuration's interfaces.\r
354 //\r
1436aea4
MK
355 NumIf = Config->Desc.NumInterfaces;\r
356 Config->Interfaces = AllocateZeroPool (sizeof (USB_INTERFACE_DESC *) * NumIf);\r
e237e7ae 357\r
358 if (Config->Interfaces == NULL) {\r
359 goto ON_ERROR;\r
360 }\r
361\r
1436aea4
MK
362 DEBUG ((\r
363 DEBUG_INFO,\r
364 "UsbParseConfigDesc: config %d has %d interfaces\n",\r
365 Config->Desc.ConfigurationValue,\r
366 (UINT32)NumIf\r
367 ));\r
e237e7ae 368\r
369 for (Index = 0; Index < NumIf; Index++) {\r
370 Interface = AllocateZeroPool (sizeof (USB_INTERFACE_DESC));\r
371\r
372 if (Interface == NULL) {\r
373 goto ON_ERROR;\r
374 }\r
375\r
376 Config->Interfaces[Index] = Interface;\r
377 }\r
378\r
379 //\r
380 // If a configuration has several interfaces, these interfaces are\r
381 // numbered from zero to n. If a interface has several settings,\r
382 // these settings are also number from zero to m. The interface\r
383 // setting must be organized as |interface 0, setting 0|interface 0\r
384 // setting 1|interface 1, setting 0|interface 2, setting 0|. Check\r
385 // USB2.0 spec, page 267.\r
386 //\r
387 DescBuf += Consumed;\r
388 Len -= Consumed;\r
389\r
efe9186f 390 //\r
d1102dba 391 // Make allowances for devices that return extra data at the\r
efe9186f 392 // end of their config descriptors\r
393 //\r
394 while (Len >= sizeof (EFI_USB_INTERFACE_DESCRIPTOR)) {\r
e237e7ae 395 Setting = UsbParseInterfaceDesc (DescBuf, Len, &Consumed);\r
396\r
63e78d52 397 if (Setting == NULL) {\r
1436aea4 398 DEBUG ((DEBUG_ERROR, "UsbParseConfigDesc: warning: failed to get interface setting, stop parsing now.\n"));\r
20bcb757 399 break;\r
e237e7ae 400 } else if (Setting->Desc.InterfaceNumber >= NumIf) {\r
1436aea4 401 DEBUG ((DEBUG_ERROR, "UsbParseConfigDesc: malformatted interface descriptor\n"));\r
e237e7ae 402\r
403 UsbFreeInterfaceDesc (Setting);\r
404 goto ON_ERROR;\r
405 }\r
406\r
407 //\r
408 // Insert the descriptor to the corresponding set.\r
409 //\r
410 Interface = Config->Interfaces[Setting->Desc.InterfaceNumber];\r
411\r
412 if (Interface->NumOfSetting >= USB_MAX_INTERFACE_SETTING) {\r
413 goto ON_ERROR;\r
414 }\r
415\r
416 Interface->Settings[Interface->NumOfSetting] = Setting;\r
417 Interface->NumOfSetting++;\r
418\r
419 DescBuf += Consumed;\r
420 Len -= Consumed;\r
421 }\r
422\r
423 return Config;\r
424\r
425ON_ERROR:\r
426 UsbFreeConfigDesc (Config);\r
427 return NULL;\r
428}\r
429\r
e237e7ae 430/**\r
431 USB standard control transfer support routine. This\r
432 function is used by USB device. It is possible that\r
433 the device's interfaces are still waiting to be\r
434 enumerated.\r
435\r
8616fc4c 436 @param UsbDev The usb device.\r
437 @param Direction The direction of data transfer.\r
438 @param Type Standard / class specific / vendor specific.\r
439 @param Target The receiving target.\r
440 @param Request Which request.\r
441 @param Value The wValue parameter of the request.\r
442 @param Index The wIndex parameter of the request.\r
443 @param Buf The buffer to receive data into / transmit from.\r
444 @param Length The length of the buffer.\r
e237e7ae 445\r
8616fc4c 446 @retval EFI_SUCCESS The control request is executed.\r
447 @retval EFI_DEVICE_ERROR Failed to execute the control transfer.\r
e237e7ae 448\r
449**/\r
450EFI_STATUS\r
451UsbCtrlRequest (\r
1436aea4
MK
452 IN USB_DEVICE *UsbDev,\r
453 IN EFI_USB_DATA_DIRECTION Direction,\r
454 IN UINTN Type,\r
455 IN UINTN Target,\r
456 IN UINTN Request,\r
457 IN UINT16 Value,\r
458 IN UINT16 Index,\r
459 IN OUT VOID *Buf,\r
460 IN UINTN Length\r
e237e7ae 461 )\r
462{\r
463 EFI_USB_DEVICE_REQUEST DevReq;\r
464 EFI_STATUS Status;\r
465 UINT32 Result;\r
466 UINTN Len;\r
467\r
468 ASSERT ((UsbDev != NULL) && (UsbDev->Bus != NULL));\r
469\r
1436aea4
MK
470 DevReq.RequestType = USB_REQUEST_TYPE (Direction, Type, Target);\r
471 DevReq.Request = (UINT8)Request;\r
472 DevReq.Value = Value;\r
473 DevReq.Index = Index;\r
474 DevReq.Length = (UINT16)Length;\r
e237e7ae 475\r
1436aea4 476 Len = Length;\r
e237e7ae 477 Status = UsbHcControlTransfer (\r
478 UsbDev->Bus,\r
479 UsbDev->Address,\r
480 UsbDev->Speed,\r
481 UsbDev->MaxPacket0,\r
482 &DevReq,\r
483 Direction,\r
484 Buf,\r
485 &Len,\r
41e8ff27 486 USB_GENERAL_DEVICE_REQUEST_TIMEOUT,\r
e237e7ae 487 &UsbDev->Translator,\r
488 &Result\r
489 );\r
490\r
491 return Status;\r
492}\r
493\r
e237e7ae 494/**\r
495 Get the standard descriptors.\r
496\r
8616fc4c 497 @param UsbDev The USB device to read descriptor from.\r
498 @param DescType The type of descriptor to read.\r
499 @param DescIndex The index of descriptor to read.\r
e237e7ae 500 @param LangId Language ID, only used to get string, otherwise set\r
8616fc4c 501 it to 0.\r
502 @param Buf The buffer to hold the descriptor read.\r
503 @param Length The length of the buffer.\r
e237e7ae 504\r
8616fc4c 505 @retval EFI_SUCCESS The descriptor is read OK.\r
506 @retval Others Failed to retrieve the descriptor.\r
e237e7ae 507\r
508**/\r
e237e7ae 509EFI_STATUS\r
510UsbCtrlGetDesc (\r
1436aea4
MK
511 IN USB_DEVICE *UsbDev,\r
512 IN UINTN DescType,\r
513 IN UINTN DescIndex,\r
514 IN UINT16 LangId,\r
515 OUT VOID *Buf,\r
516 IN UINTN Length\r
e237e7ae 517 )\r
518{\r
1436aea4 519 EFI_STATUS Status;\r
e237e7ae 520\r
521 Status = UsbCtrlRequest (\r
522 UsbDev,\r
523 EfiUsbDataIn,\r
524 USB_REQ_TYPE_STANDARD,\r
525 USB_TARGET_DEVICE,\r
526 USB_REQ_GET_DESCRIPTOR,\r
1436aea4 527 (UINT16)((DescType << 8) | DescIndex),\r
e237e7ae 528 LangId,\r
529 Buf,\r
530 Length\r
531 );\r
532\r
533 return Status;\r
534}\r
535\r
e237e7ae 536/**\r
537 Return the max packet size for endpoint zero. This function\r
538 is the first function called to get descriptors during bus\r
539 enumeration.\r
540\r
8616fc4c 541 @param UsbDev The usb device.\r
e237e7ae 542\r
8616fc4c 543 @retval EFI_SUCCESS The max packet size of endpoint zero is retrieved.\r
544 @retval EFI_DEVICE_ERROR Failed to retrieve it.\r
e237e7ae 545\r
546**/\r
547EFI_STATUS\r
548UsbGetMaxPacketSize0 (\r
1436aea4 549 IN USB_DEVICE *UsbDev\r
e237e7ae 550 )\r
551{\r
1436aea4
MK
552 EFI_USB_DEVICE_DESCRIPTOR DevDesc;\r
553 EFI_STATUS Status;\r
554 UINTN Index;\r
e237e7ae 555\r
556 //\r
557 // Get the first 8 bytes of the device descriptor which contains\r
558 // max packet size for endpoint 0, which is at least 8.\r
559 //\r
e237e7ae 560 for (Index = 0; Index < 3; Index++) {\r
561 Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_DEVICE, 0, 0, &DevDesc, 8);\r
562\r
563 if (!EFI_ERROR (Status)) {\r
b9953b65 564 if ((DevDesc.BcdUSB >= 0x0300) && (DevDesc.MaxPacketSize0 == 9)) {\r
92870c98 565 UsbDev->MaxPacket0 = 1 << 9;\r
566 return EFI_SUCCESS;\r
567 }\r
1436aea4 568\r
e237e7ae 569 UsbDev->MaxPacket0 = DevDesc.MaxPacketSize0;\r
570 return EFI_SUCCESS;\r
571 }\r
572\r
41e8ff27 573 gBS->Stall (USB_RETRY_MAX_PACK_SIZE_STALL);\r
e237e7ae 574 }\r
575\r
576 return EFI_DEVICE_ERROR;\r
577}\r
578\r
e237e7ae 579/**\r
580 Get the device descriptor for the device.\r
581\r
8616fc4c 582 @param UsbDev The Usb device to retrieve descriptor from.\r
e237e7ae 583\r
8616fc4c 584 @retval EFI_SUCCESS The device descriptor is returned.\r
585 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
e237e7ae 586\r
587**/\r
e237e7ae 588EFI_STATUS\r
589UsbGetDevDesc (\r
1436aea4 590 IN USB_DEVICE *UsbDev\r
e237e7ae 591 )\r
592{\r
1436aea4
MK
593 USB_DEVICE_DESC *DevDesc;\r
594 EFI_STATUS Status;\r
e237e7ae 595\r
596 DevDesc = AllocateZeroPool (sizeof (USB_DEVICE_DESC));\r
597\r
598 if (DevDesc == NULL) {\r
599 return EFI_OUT_OF_RESOURCES;\r
600 }\r
601\r
1436aea4
MK
602 Status = UsbCtrlGetDesc (\r
603 UsbDev,\r
604 USB_DESC_TYPE_DEVICE,\r
605 0,\r
606 0,\r
607 DevDesc,\r
608 sizeof (EFI_USB_DEVICE_DESCRIPTOR)\r
609 );\r
e237e7ae 610\r
611 if (EFI_ERROR (Status)) {\r
612 gBS->FreePool (DevDesc);\r
613 } else {\r
614 UsbDev->DevDesc = DevDesc;\r
615 }\r
616\r
617 return Status;\r
618}\r
619\r
e237e7ae 620/**\r
621 Retrieve the indexed string for the language. It requires two\r
622 steps to get a string, first to get the string's length. Then\r
623 the string itself.\r
624\r
8616fc4c 625 @param UsbDev The usb device.\r
626 @param Index The index the string to retrieve.\r
627 @param LangId Language ID.\r
e237e7ae 628\r
8616fc4c 629 @return The created string descriptor or NULL.\r
e237e7ae 630\r
631**/\r
632EFI_USB_STRING_DESCRIPTOR *\r
633UsbGetOneString (\r
1436aea4
MK
634 IN USB_DEVICE *UsbDev,\r
635 IN UINT8 Index,\r
636 IN UINT16 LangId\r
e237e7ae 637 )\r
638{\r
1436aea4
MK
639 EFI_USB_STRING_DESCRIPTOR Desc;\r
640 EFI_STATUS Status;\r
641 UINT8 *Buf;\r
e237e7ae 642\r
643 //\r
644 // First get two bytes which contains the string length.\r
645 //\r
646 Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_STRING, Index, LangId, &Desc, 2);\r
647\r
b2252bab
RN
648 //\r
649 // Reject if Length even cannot cover itself, or odd because Unicode string byte length should be even.\r
650 //\r
0bc7448a 651 if (EFI_ERROR (Status) ||\r
b2252bab
RN
652 (Desc.Length < OFFSET_OF (EFI_USB_STRING_DESCRIPTOR, Length) + sizeof (Desc.Length)) ||\r
653 (Desc.Length % 2 != 0)\r
1436aea4
MK
654 )\r
655 {\r
e237e7ae 656 return NULL;\r
657 }\r
658\r
659 Buf = AllocateZeroPool (Desc.Length);\r
660\r
661 if (Buf == NULL) {\r
662 return NULL;\r
663 }\r
664\r
665 Status = UsbCtrlGetDesc (\r
666 UsbDev,\r
667 USB_DESC_TYPE_STRING,\r
668 Index,\r
669 LangId,\r
670 Buf,\r
671 Desc.Length\r
672 );\r
673\r
674 if (EFI_ERROR (Status)) {\r
d17371e8 675 FreePool (Buf);\r
e237e7ae 676 return NULL;\r
677 }\r
678\r
1436aea4 679 return (EFI_USB_STRING_DESCRIPTOR *)Buf;\r
e237e7ae 680}\r
681\r
e237e7ae 682/**\r
8616fc4c 683 Build the language ID table for string descriptors.\r
e237e7ae 684\r
8616fc4c 685 @param UsbDev The Usb device.\r
e237e7ae 686\r
8616fc4c 687 @retval EFI_UNSUPPORTED This device doesn't support string table.\r
e237e7ae 688\r
689**/\r
e237e7ae 690EFI_STATUS\r
691UsbBuildLangTable (\r
1436aea4 692 IN USB_DEVICE *UsbDev\r
e237e7ae 693 )\r
694{\r
1436aea4
MK
695 EFI_USB_STRING_DESCRIPTOR *Desc;\r
696 EFI_STATUS Status;\r
697 UINTN Index;\r
698 UINTN Max;\r
699 UINT16 *Point;\r
e237e7ae 700\r
701 //\r
702 // The string of language ID zero returns the supported languages\r
703 //\r
704 Desc = UsbGetOneString (UsbDev, 0, 0);\r
705\r
706 if (Desc == NULL) {\r
707 return EFI_UNSUPPORTED;\r
708 }\r
709\r
710 if (Desc->Length < 4) {\r
711 Status = EFI_UNSUPPORTED;\r
712 goto ON_EXIT;\r
713 }\r
714\r
715 Status = EFI_SUCCESS;\r
716\r
1436aea4
MK
717 Max = (Desc->Length - 2) / 2;\r
718 Max = MIN (Max, USB_MAX_LANG_ID);\r
d1102dba 719\r
e237e7ae 720 Point = Desc->String;\r
721 for (Index = 0; Index < Max; Index++) {\r
722 UsbDev->LangId[Index] = *Point;\r
723 Point++;\r
724 }\r
725\r
726 UsbDev->TotalLangId = (UINT16)Max;\r
727\r
728ON_EXIT:\r
729 gBS->FreePool (Desc);\r
730 return Status;\r
731}\r
732\r
e237e7ae 733/**\r
734 Retrieve the indexed configure for the device. USB device\r
d17371e8 735 returns the configuration together with the interfaces for\r
e237e7ae 736 this configuration. Configuration descriptor is also of\r
8616fc4c 737 variable length.\r
e237e7ae 738\r
8616fc4c 739 @param UsbDev The Usb interface.\r
740 @param Index The index of the configuration.\r
e237e7ae 741\r
8616fc4c 742 @return The created configuration descriptor.\r
e237e7ae 743\r
744**/\r
e237e7ae 745EFI_USB_CONFIG_DESCRIPTOR *\r
746UsbGetOneConfig (\r
1436aea4
MK
747 IN USB_DEVICE *UsbDev,\r
748 IN UINT8 Index\r
e237e7ae 749 )\r
750{\r
1436aea4
MK
751 EFI_USB_CONFIG_DESCRIPTOR Desc;\r
752 EFI_STATUS Status;\r
753 VOID *Buf;\r
e237e7ae 754\r
755 //\r
756 // First get four bytes which contains the total length\r
757 // for this configuration.\r
758 //\r
759 Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_CONFIG, Index, 0, &Desc, 8);\r
760\r
761 if (EFI_ERROR (Status)) {\r
1436aea4
MK
762 DEBUG ((\r
763 DEBUG_ERROR,\r
46f51898 764 "UsbGetOneConfig: failed to get descript length(%d) - %r\n",\r
1436aea4
MK
765 Desc.TotalLength,\r
766 Status\r
767 ));\r
e237e7ae 768\r
769 return NULL;\r
770 }\r
771\r
1436aea4 772 DEBUG ((DEBUG_INFO, "UsbGetOneConfig: total length is %d\n", Desc.TotalLength));\r
e237e7ae 773\r
70c3c237
RN
774 //\r
775 // Reject if TotalLength even cannot cover itself.\r
776 //\r
777 if (Desc.TotalLength < OFFSET_OF (EFI_USB_CONFIG_DESCRIPTOR, TotalLength) + sizeof (Desc.TotalLength)) {\r
778 return NULL;\r
779 }\r
780\r
e237e7ae 781 Buf = AllocateZeroPool (Desc.TotalLength);\r
782\r
783 if (Buf == NULL) {\r
784 return NULL;\r
785 }\r
786\r
787 Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_CONFIG, Index, 0, Buf, Desc.TotalLength);\r
788\r
789 if (EFI_ERROR (Status)) {\r
46f51898 790 DEBUG ((DEBUG_ERROR, "UsbGetOneConfig: failed to get full descript - %r\n", Status));\r
e237e7ae 791\r
d17371e8 792 FreePool (Buf);\r
e237e7ae 793 return NULL;\r
794 }\r
795\r
796 return Buf;\r
797}\r
798\r
e237e7ae 799/**\r
800 Build the whole array of descriptors. This function must\r
801 be called after UsbGetMaxPacketSize0 returns the max packet\r
802 size correctly for endpoint 0.\r
803\r
8616fc4c 804 @param UsbDev The Usb device.\r
e237e7ae 805\r
8616fc4c 806 @retval EFI_SUCCESS The descriptor table is build.\r
807 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the descriptor.\r
e237e7ae 808\r
809**/\r
810EFI_STATUS\r
811UsbBuildDescTable (\r
1436aea4 812 IN USB_DEVICE *UsbDev\r
e237e7ae 813 )\r
814{\r
1436aea4
MK
815 EFI_USB_CONFIG_DESCRIPTOR *Config;\r
816 USB_DEVICE_DESC *DevDesc;\r
817 USB_CONFIG_DESC *ConfigDesc;\r
818 UINT8 NumConfig;\r
819 EFI_STATUS Status;\r
820 UINT8 Index;\r
e237e7ae 821\r
822 //\r
823 // Get the device descriptor, then allocate the configure\r
824 // descriptor pointer array to hold configurations.\r
825 //\r
826 Status = UsbGetDevDesc (UsbDev);\r
827\r
828 if (EFI_ERROR (Status)) {\r
1436aea4 829 DEBUG ((DEBUG_ERROR, "UsbBuildDescTable: failed to get device descriptor - %r\n", Status));\r
e237e7ae 830 return Status;\r
831 }\r
832\r
70eca31b 833 DevDesc = UsbDev->DevDesc;\r
834 NumConfig = DevDesc->Desc.NumConfigurations;\r
835 if (NumConfig == 0) {\r
836 return EFI_DEVICE_ERROR;\r
837 }\r
e237e7ae 838\r
70eca31b 839 DevDesc->Configs = AllocateZeroPool (NumConfig * sizeof (USB_CONFIG_DESC *));\r
e237e7ae 840 if (DevDesc->Configs == NULL) {\r
841 return EFI_OUT_OF_RESOURCES;\r
842 }\r
843\r
1436aea4 844 DEBUG ((DEBUG_INFO, "UsbBuildDescTable: device has %d configures\n", NumConfig));\r
e237e7ae 845\r
846 //\r
847 // Read each configurations, then parse them\r
848 //\r
849 for (Index = 0; Index < NumConfig; Index++) {\r
850 Config = UsbGetOneConfig (UsbDev, Index);\r
851\r
852 if (Config == NULL) {\r
1436aea4 853 DEBUG ((DEBUG_ERROR, "UsbBuildDescTable: failed to get configure (index %d)\n", Index));\r
e237e7ae 854\r
855 //\r
856 // If we can get the default descriptor, it is likely that the\r
857 // device is still operational.\r
858 //\r
859 if (Index == 0) {\r
860 return EFI_DEVICE_ERROR;\r
861 }\r
862\r
863 break;\r
864 }\r
865\r
1436aea4 866 ConfigDesc = UsbParseConfigDesc ((UINT8 *)Config, Config->TotalLength);\r
e237e7ae 867\r
d17371e8 868 FreePool (Config);\r
e237e7ae 869\r
870 if (ConfigDesc == NULL) {\r
1436aea4 871 DEBUG ((DEBUG_ERROR, "UsbBuildDescTable: failed to parse configure (index %d)\n", Index));\r
e237e7ae 872\r
873 //\r
874 // If we can get the default descriptor, it is likely that the\r
875 // device is still operational.\r
876 //\r
877 if (Index == 0) {\r
878 return EFI_DEVICE_ERROR;\r
879 }\r
880\r
881 break;\r
882 }\r
883\r
884 DevDesc->Configs[Index] = ConfigDesc;\r
885 }\r
886\r
887 //\r
888 // Don't return error even this function failed because\r
889 // it is possible for the device to not support strings.\r
890 //\r
891 Status = UsbBuildLangTable (UsbDev);\r
892\r
893 if (EFI_ERROR (Status)) {\r
46f51898 894 DEBUG ((DEBUG_INFO, "UsbBuildDescTable: get language ID table - %r\n", Status));\r
e237e7ae 895 }\r
896\r
897 return EFI_SUCCESS;\r
898}\r
899\r
e237e7ae 900/**\r
901 Set the device's address.\r
902\r
8616fc4c 903 @param UsbDev The device to set address to.\r
904 @param Address The address to set.\r
e237e7ae 905\r
8616fc4c 906 @retval EFI_SUCCESS The device is set to the address.\r
907 @retval Others Failed to set the device address.\r
e237e7ae 908\r
909**/\r
910EFI_STATUS\r
911UsbSetAddress (\r
1436aea4
MK
912 IN USB_DEVICE *UsbDev,\r
913 IN UINT8 Address\r
e237e7ae 914 )\r
915{\r
1436aea4 916 EFI_STATUS Status;\r
e237e7ae 917\r
918 Status = UsbCtrlRequest (\r
919 UsbDev,\r
920 EfiUsbNoData,\r
921 USB_REQ_TYPE_STANDARD,\r
922 USB_TARGET_DEVICE,\r
923 USB_REQ_SET_ADDRESS,\r
924 Address,\r
925 0,\r
926 NULL,\r
927 0\r
928 );\r
929\r
930 return Status;\r
931}\r
932\r
e237e7ae 933/**\r
934 Set the device's configuration. This function changes\r
935 the device's internal state. UsbSelectConfig changes\r
936 the Usb bus's internal state.\r
937\r
8616fc4c 938 @param UsbDev The USB device to set configure to.\r
939 @param ConfigIndex The configure index to set.\r
e237e7ae 940\r
8616fc4c 941 @retval EFI_SUCCESS The device is configured now.\r
942 @retval Others Failed to set the device configure.\r
e237e7ae 943\r
944**/\r
945EFI_STATUS\r
946UsbSetConfig (\r
1436aea4
MK
947 IN USB_DEVICE *UsbDev,\r
948 IN UINT8 ConfigIndex\r
e237e7ae 949 )\r
950{\r
1436aea4 951 EFI_STATUS Status;\r
e237e7ae 952\r
953 Status = UsbCtrlRequest (\r
954 UsbDev,\r
955 EfiUsbNoData,\r
956 USB_REQ_TYPE_STANDARD,\r
957 USB_TARGET_DEVICE,\r
958 USB_REQ_SET_CONFIG,\r
959 ConfigIndex,\r
960 0,\r
961 NULL,\r
962 0\r
1436aea4 963 );\r
e237e7ae 964\r
965 return Status;\r
966}\r
967\r
e237e7ae 968/**\r
969 Usb UsbIo interface to clear the feature. This is should\r
970 only be used by HUB which is considered a device driver\r
971 on top of the UsbIo interface.\r
972\r
8616fc4c 973 @param UsbIo The UsbIo interface.\r
974 @param Target The target of the transfer: endpoint/device.\r
975 @param Feature The feature to clear.\r
976 @param Index The wIndex parameter.\r
e237e7ae 977\r
8616fc4c 978 @retval EFI_SUCCESS The device feature is cleared.\r
979 @retval Others Failed to clear the feature.\r
e237e7ae 980\r
981**/\r
982EFI_STATUS\r
983UsbIoClearFeature (\r
1436aea4
MK
984 IN EFI_USB_IO_PROTOCOL *UsbIo,\r
985 IN UINTN Target,\r
986 IN UINT16 Feature,\r
987 IN UINT16 Index\r
e237e7ae 988 )\r
989{\r
990 EFI_USB_DEVICE_REQUEST DevReq;\r
991 UINT32 UsbResult;\r
992 EFI_STATUS Status;\r
993\r
1436aea4
MK
994 DevReq.RequestType = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, Target);\r
995 DevReq.Request = USB_REQ_CLEAR_FEATURE;\r
996 DevReq.Value = Feature;\r
997 DevReq.Index = Index;\r
998 DevReq.Length = 0;\r
e237e7ae 999\r
1000 Status = UsbIo->UsbControlTransfer (\r
1001 UsbIo,\r
1002 &DevReq,\r
1003 EfiUsbNoData,\r
41e8ff27 1004 USB_CLEAR_FEATURE_REQUEST_TIMEOUT,\r
e237e7ae 1005 NULL,\r
1006 0,\r
1007 &UsbResult\r
1008 );\r
1009\r
1010 return Status;\r
1011}\r