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