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