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