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