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