Import Usb/UsbBusDxe and Usb/UsbMassStorageDxe into MdeModulePkg.
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Bus / Usb / UsbBusDxe / UsbDesc.c
1 /** @file\r
2 \r
3 Copyright (c) 2007, Intel Corporation\r
4 All rights reserved. This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution.  The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php\r
8 \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT 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
36 STATIC\r
37 VOID\r
38 UsbFreeInterfaceDesc (\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
74 STATIC\r
75 VOID\r
76 UsbFreeConfigDesc (\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
124 VOID\r
125 UsbFreeDevDesc (\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
156 STATIC\r
157 VOID *\r
158 UsbCreateDesc (\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
211     USB_ERROR (("UsbCreateDesc: met mal-format descriptor\n"));\r
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
238 STATIC\r
239 USB_INTERFACE_SETTING *\r
240 UsbParseInterfaceDesc (\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
257     USB_ERROR (("UsbParseInterfaceDesc: failed to create interface descriptor\n"));\r
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
268   USB_DEBUG (("UsbParseInterfaceDesc: interface %d(setting %d) has %d endpoints\n",\r
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
288       USB_ERROR (("UsbParseInterfaceDesc: failed to create endpoint(index %d)\n", Index));\r
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
297 ON_EXIT:\r
298   *Consumed = Offset;\r
299   return Setting;\r
300 \r
301 ON_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
316 STATIC\r
317 USB_CONFIG_DESC *\r
318 UsbParseConfigDesc (\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
348   USB_DEBUG (("UsbParseConfigDesc: config %d has %d interfaces\n",\r
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
376       USB_ERROR (("UsbParseConfigDesc: failed to parse interface setting\n"));\r
377       goto ON_ERROR;\r
378 \r
379     } else if (Setting->Desc.InterfaceNumber >= NumIf) {\r
380       USB_ERROR (("UsbParseConfigDesc: mal-formated interface descriptor\n"));\r
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
404 ON_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
431 EFI_STATUS\r
432 UsbCtrlRequest (\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
467              50 * USB_STALL_1_MS,\r
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
492 STATIC\r
493 EFI_STATUS\r
494 UsbCtrlGetDesc (\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
533 EFI_STATUS\r
534 UsbGetMaxPacketSize0 (\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
557     gBS->Stall (100 * USB_STALL_1_MS);\r
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
574 STATIC\r
575 EFI_STATUS\r
576 UsbGetDevDesc (\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
621 EFI_USB_STRING_DESCRIPTOR *\r
622 UsbGetOneString (\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
674 STATIC\r
675 EFI_STATUS\r
676 UsbBuildLangTable (\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
713 ON_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
732 STATIC\r
733 EFI_USB_CONFIG_DESCRIPTOR *\r
734 UsbGetOneConfig (\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
750     USB_ERROR (("UsbGetOneConfig: failed to get descript length(%d) %r\n",\r
751                 Status, Desc.TotalLength));\r
752 \r
753     return NULL;\r
754   }\r
755 \r
756   USB_DEBUG (("UsbGetOneConfig: total length is %d\n", Desc.TotalLength));\r
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
767     USB_ERROR (("UsbGetOneConfig: failed to get full descript %r\n", Status));\r
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
789 EFI_STATUS\r
790 UsbBuildDescTable (\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
808     USB_ERROR (("UsbBuildDescTable: failed to get device descriptor - %r\n", Status));\r
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
820   USB_DEBUG (("UsbBuildDescTable: device has %d configures\n", NumConfig));\r
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
829       USB_ERROR (("UsbBuildDescTable: failed to get configure (index %d)\n", Index));\r
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
847       USB_ERROR (("UsbBuildDescTable: failed to parse configure (index %d)\n", Index));\r
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
870     USB_DEBUG (("UsbBuildDescTable: get language ID table %r\n", Status));\r
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
887 EFI_STATUS\r
888 UsbSetAddress (\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
923 EFI_STATUS\r
924 UsbSetConfig (\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
962 EFI_STATUS\r
963 UsbIoClearFeature (\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
984                     10 * USB_STALL_1_MS,\r
985                     NULL,\r
986                     0,\r
987                     &UsbResult\r
988                     );\r
989 \r
990   return Status;\r
991 }\r