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