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