]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[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
d1102dba 5Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
e237e7ae 7\r
e237e7ae 8**/\r
9\r
10#include "UsbBus.h"\r
11\r
12\r
13/**\r
8616fc4c 14 Free the interface setting descriptor.\r
e237e7ae 15\r
8616fc4c 16 @param Setting The descriptor to free.\r
e237e7ae 17\r
e237e7ae 18**/\r
e237e7ae 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
d17371e8 35 FreePool (Ep);\r
e237e7ae 36 }\r
37 }\r
38\r
efe9186f 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
e237e7ae 45 }\r
46\r
d17371e8 47 FreePool (Setting);\r
e237e7ae 48}\r
49\r
50\r
e237e7ae 51/**\r
52 Free a configuration descriptor with its interface\r
8616fc4c 53 descriptors. It may be initialized partially.\r
e237e7ae 54\r
8616fc4c 55 @param Config The configuration descriptor to free.\r
e237e7ae 56\r
e237e7ae 57**/\r
e237e7ae 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
d17371e8 87 FreePool (Interface);\r
e237e7ae 88 }\r
89\r
d17371e8 90 FreePool (Config->Interfaces);\r
e237e7ae 91 }\r
92\r
d17371e8 93 FreePool (Config);\r
e237e7ae 94\r
95}\r
96\r
97\r
e237e7ae 98/**\r
8616fc4c 99 Free a device descriptor with its configurations.\r
e237e7ae 100\r
8616fc4c 101 @param DevDesc The device descriptor.\r
e237e7ae 102\r
e237e7ae 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
d17371e8 118 FreePool (DevDesc->Configs);\r
e237e7ae 119 }\r
120\r
d17371e8 121 FreePool (DevDesc);\r
e237e7ae 122}\r
123\r
124\r
125/**\r
8616fc4c 126 Create a descriptor.\r
e237e7ae 127\r
8616fc4c 128 @param DescBuf The buffer of raw descriptor.\r
d17371e8 129 @param Len The length of the raw descriptor buffer.\r
8616fc4c 130 @param Type The type of descriptor to create.\r
131 @param Consumed Number of bytes consumed.\r
e237e7ae 132\r
8616fc4c 133 @return Created descriptor or NULL.\r
e237e7ae 134\r
135**/\r
e237e7ae 136VOID *\r
137UsbCreateDesc (\r
138 IN UINT8 *DescBuf,\r
4de9d876 139 IN UINTN Len,\r
e237e7ae 140 IN UINT8 Type,\r
4de9d876 141 OUT UINTN *Consumed\r
e237e7ae 142 )\r
143{\r
144 USB_DESC_HEAD *Head;\r
4de9d876
FT
145 UINTN DescLen;\r
146 UINTN CtrlLen;\r
147 UINTN Offset;\r
e237e7ae 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
4c034bf6
RN
174\r
175 default:\r
176 ASSERT (FALSE);\r
177 return NULL;\r
178 }\r
179\r
180 //\r
0bc7448a 181 // Total length is too small that cannot hold the single descriptor header plus data.\r
4c034bf6
RN
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
e237e7ae 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
4c034bf6
RN
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
e237e7ae 199\r
4c034bf6
RN
200 if (Head->Len == 0) {\r
201 DEBUG ((DEBUG_ERROR, "UsbCreateDesc: met mal-format descriptor, Head->Len = 0!\n"));\r
4de9d876
FT
202 return NULL;\r
203 }\r
4c034bf6
RN
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
4de9d876
FT
210 return NULL;\r
211 }\r
4c034bf6
RN
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
c87ac38c 226 return NULL;\r
e237e7ae 227 }\r
228\r
4c034bf6
RN
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
e237e7ae 231 return NULL;\r
232 }\r
233\r
cd7bfc2c 234 Desc = AllocateZeroPool ((UINTN) CtrlLen);\r
e237e7ae 235 if (Desc == NULL) {\r
236 return NULL;\r
237 }\r
efe9186f 238\r
cd7bfc2c 239 CopyMem (Desc, Head, (UINTN) DescLen);\r
efe9186f 240\r
4c034bf6 241 *Consumed = Offset;\r
e237e7ae 242\r
243 return Desc;\r
244}\r
245\r
246\r
247/**\r
d17371e8 248 Parse an interface descriptor and its endpoints.\r
e237e7ae 249\r
8616fc4c 250 @param DescBuf The buffer of raw descriptor.\r
d17371e8 251 @param Len The length of the raw descriptor buffer.\r
8616fc4c 252 @param Consumed The number of raw descriptor consumed.\r
e237e7ae 253\r
8616fc4c 254 @return The create interface setting or NULL if failed.\r
e237e7ae 255\r
256**/\r
e237e7ae 257USB_INTERFACE_SETTING *\r
258UsbParseInterfaceDesc (\r
259 IN UINT8 *DescBuf,\r
4de9d876
FT
260 IN UINTN Len,\r
261 OUT UINTN *Consumed\r
e237e7ae 262 )\r
263{\r
264 USB_INTERFACE_SETTING *Setting;\r
265 USB_ENDPOINT_DESC *Ep;\r
266 UINTN Index;\r
267 UINTN NumEp;\r
4de9d876
FT
268 UINTN Used;\r
269 UINTN Offset;\r
e237e7ae 270\r
271 *Consumed = 0;\r
272 Setting = UsbCreateDesc (DescBuf, Len, USB_DESC_TYPE_INTERFACE, &Used);\r
273\r
274 if (Setting == NULL) {\r
d2577026 275 DEBUG (( EFI_D_ERROR, "UsbParseInterfaceDesc: failed to create interface descriptor\n"));\r
e237e7ae 276 return NULL;\r
277 }\r
278\r
279 Offset = Used;\r
280\r
281 //\r
d17371e8 282 // Create an array to hold the interface's endpoints\r
e237e7ae 283 //\r
284 NumEp = Setting->Desc.NumEndpoints;\r
285\r
d2577026 286 DEBUG (( EFI_D_INFO, "UsbParseInterfaceDesc: interface %d(setting %d) has %d endpoints\n",\r
7df7393f 287 Setting->Desc.InterfaceNumber, Setting->Desc.AlternateSetting, (UINT32)NumEp));\r
e237e7ae 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
4de9d876 302 for (Index = 0; (Index < NumEp) && (Offset < Len); Index++) {\r
e237e7ae 303 Ep = UsbCreateDesc (DescBuf + Offset, Len - Offset, USB_DESC_TYPE_ENDPOINT, &Used);\r
304\r
305 if (Ep == NULL) {\r
7df7393f 306 DEBUG (( EFI_D_ERROR, "UsbParseInterfaceDesc: failed to create endpoint(index %d)\n", (UINT32)Index));\r
e237e7ae 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
8616fc4c 328 @param DescBuf The buffer of raw descriptor.\r
d17371e8 329 @param Len The length of the raw descriptor buffer.\r
e237e7ae 330\r
8616fc4c 331 @return The created configuration descriptor.\r
e237e7ae 332\r
333**/\r
e237e7ae 334USB_CONFIG_DESC *\r
335UsbParseConfigDesc (\r
336 IN UINT8 *DescBuf,\r
4de9d876 337 IN UINTN Len\r
e237e7ae 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
4de9d876 345 UINTN Consumed;\r
e237e7ae 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
d2577026 365 DEBUG (( EFI_D_INFO, "UsbParseConfigDesc: config %d has %d interfaces\n",\r
7df7393f 366 Config->Desc.ConfigurationValue, (UINT32)NumIf));\r
e237e7ae 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
efe9186f 389 //\r
d1102dba 390 // Make allowances for devices that return extra data at the\r
efe9186f 391 // end of their config descriptors\r
392 //\r
393 while (Len >= sizeof (EFI_USB_INTERFACE_DESCRIPTOR)) {\r
e237e7ae 394 Setting = UsbParseInterfaceDesc (DescBuf, Len, &Consumed);\r
395\r
63e78d52 396 if (Setting == NULL) {\r
20bcb757 397 DEBUG (( EFI_D_ERROR, "UsbParseConfigDesc: warning: failed to get interface setting, stop parsing now.\n"));\r
398 break;\r
e237e7ae 399\r
400 } else if (Setting->Desc.InterfaceNumber >= NumIf) {\r
d2577026 401 DEBUG (( EFI_D_ERROR, "UsbParseConfigDesc: mal-formated interface descriptor\n"));\r
e237e7ae 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
e237e7ae 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
8616fc4c 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
e237e7ae 446\r
8616fc4c 447 @retval EFI_SUCCESS The control request is executed.\r
448 @retval EFI_DEVICE_ERROR Failed to execute the control transfer.\r
e237e7ae 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
41e8ff27 487 USB_GENERAL_DEVICE_REQUEST_TIMEOUT,\r
e237e7ae 488 &UsbDev->Translator,\r
489 &Result\r
490 );\r
491\r
492 return Status;\r
493}\r
494\r
495\r
e237e7ae 496/**\r
497 Get the standard descriptors.\r
498\r
8616fc4c 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
e237e7ae 502 @param LangId Language ID, only used to get string, otherwise set\r
8616fc4c 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
e237e7ae 506\r
8616fc4c 507 @retval EFI_SUCCESS The descriptor is read OK.\r
508 @retval Others Failed to retrieve the descriptor.\r
e237e7ae 509\r
510**/\r
e237e7ae 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
e237e7ae 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
8616fc4c 544 @param UsbDev The usb device.\r
e237e7ae 545\r
8616fc4c 546 @retval EFI_SUCCESS The max packet size of endpoint zero is retrieved.\r
547 @retval EFI_DEVICE_ERROR Failed to retrieve it.\r
e237e7ae 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
e237e7ae 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
b9953b65 568 if ((DevDesc.BcdUSB >= 0x0300) && (DevDesc.MaxPacketSize0 == 9)) {\r
92870c98 569 UsbDev->MaxPacket0 = 1 << 9;\r
570 return EFI_SUCCESS;\r
571 }\r
e237e7ae 572 UsbDev->MaxPacket0 = DevDesc.MaxPacketSize0;\r
573 return EFI_SUCCESS;\r
574 }\r
575\r
41e8ff27 576 gBS->Stall (USB_RETRY_MAX_PACK_SIZE_STALL);\r
e237e7ae 577 }\r
578\r
579 return EFI_DEVICE_ERROR;\r
580}\r
581\r
582\r
e237e7ae 583/**\r
584 Get the device descriptor for the device.\r
585\r
8616fc4c 586 @param UsbDev The Usb device to retrieve descriptor from.\r
e237e7ae 587\r
8616fc4c 588 @retval EFI_SUCCESS The device descriptor is returned.\r
589 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
e237e7ae 590\r
591**/\r
e237e7ae 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
e237e7ae 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
8616fc4c 630 @param UsbDev The usb device.\r
631 @param Index The index the string to retrieve.\r
632 @param LangId Language ID.\r
e237e7ae 633\r
8616fc4c 634 @return The created string descriptor or NULL.\r
e237e7ae 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
b2252bab
RN
653 //\r
654 // Reject if Length even cannot cover itself, or odd because Unicode string byte length should be even.\r
655 //\r
0bc7448a 656 if (EFI_ERROR (Status) ||\r
b2252bab
RN
657 (Desc.Length < OFFSET_OF (EFI_USB_STRING_DESCRIPTOR, Length) + sizeof (Desc.Length)) ||\r
658 (Desc.Length % 2 != 0)\r
659 ) {\r
e237e7ae 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
d17371e8 679 FreePool (Buf);\r
e237e7ae 680 return NULL;\r
681 }\r
682\r
683 return (EFI_USB_STRING_DESCRIPTOR *) Buf;\r
684}\r
685\r
686\r
e237e7ae 687/**\r
8616fc4c 688 Build the language ID table for string descriptors.\r
e237e7ae 689\r
8616fc4c 690 @param UsbDev The Usb device.\r
e237e7ae 691\r
8616fc4c 692 @retval EFI_UNSUPPORTED This device doesn't support string table.\r
e237e7ae 693\r
694**/\r
e237e7ae 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
d17371e8 723 Max = MIN(Max, USB_MAX_LANG_ID);\r
d1102dba 724\r
e237e7ae 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
e237e7ae 739/**\r
740 Retrieve the indexed configure for the device. USB device\r
d17371e8 741 returns the configuration together with the interfaces for\r
e237e7ae 742 this configuration. Configuration descriptor is also of\r
8616fc4c 743 variable length.\r
e237e7ae 744\r
8616fc4c 745 @param UsbDev The Usb interface.\r
746 @param Index The index of the configuration.\r
e237e7ae 747\r
8616fc4c 748 @return The created configuration descriptor.\r
e237e7ae 749\r
750**/\r
e237e7ae 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
d2577026 768 DEBUG (( EFI_D_ERROR, "UsbGetOneConfig: failed to get descript length(%d) %r\n",\r
7df7393f 769 Desc.TotalLength, Status));\r
e237e7ae 770\r
771 return NULL;\r
772 }\r
773\r
d2577026 774 DEBUG (( EFI_D_INFO, "UsbGetOneConfig: total length is %d\n", Desc.TotalLength));\r
e237e7ae 775\r
70c3c237
RN
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
e237e7ae 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
d2577026 792 DEBUG (( EFI_D_ERROR, "UsbGetOneConfig: failed to get full descript %r\n", Status));\r
e237e7ae 793\r
d17371e8 794 FreePool (Buf);\r
e237e7ae 795 return NULL;\r
796 }\r
797\r
798 return Buf;\r
799}\r
800\r
801\r
e237e7ae 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
8616fc4c 807 @param UsbDev The Usb device.\r
e237e7ae 808\r
8616fc4c 809 @retval EFI_SUCCESS The descriptor table is build.\r
810 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the descriptor.\r
e237e7ae 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
d2577026 832 DEBUG (( EFI_D_ERROR, "UsbBuildDescTable: failed to get device descriptor - %r\n", Status));\r
e237e7ae 833 return Status;\r
834 }\r
835\r
70eca31b 836 DevDesc = UsbDev->DevDesc;\r
837 NumConfig = DevDesc->Desc.NumConfigurations;\r
838 if (NumConfig == 0) {\r
839 return EFI_DEVICE_ERROR;\r
840 }\r
e237e7ae 841\r
70eca31b 842 DevDesc->Configs = AllocateZeroPool (NumConfig * sizeof (USB_CONFIG_DESC *));\r
e237e7ae 843 if (DevDesc->Configs == NULL) {\r
844 return EFI_OUT_OF_RESOURCES;\r
845 }\r
846\r
d2577026 847 DEBUG (( EFI_D_INFO, "UsbBuildDescTable: device has %d configures\n", NumConfig));\r
e237e7ae 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
d2577026 856 DEBUG (( EFI_D_ERROR, "UsbBuildDescTable: failed to get configure (index %d)\n", Index));\r
e237e7ae 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
d17371e8 871 FreePool (Config);\r
e237e7ae 872\r
873 if (ConfigDesc == NULL) {\r
d2577026 874 DEBUG (( EFI_D_ERROR, "UsbBuildDescTable: failed to parse configure (index %d)\n", Index));\r
e237e7ae 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
9a95972e 897 DEBUG (( EFI_D_INFO, "UsbBuildDescTable: get language ID table %r\n", Status));\r
e237e7ae 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
8616fc4c 907 @param UsbDev The device to set address to.\r
908 @param Address The address to set.\r
e237e7ae 909\r
8616fc4c 910 @retval EFI_SUCCESS The device is set to the address.\r
911 @retval Others Failed to set the device address.\r
e237e7ae 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
8616fc4c 943 @param UsbDev The USB device to set configure to.\r
944 @param ConfigIndex The configure index to set.\r
e237e7ae 945\r
8616fc4c 946 @retval EFI_SUCCESS The device is configured now.\r
947 @retval Others Failed to set the device configure.\r
e237e7ae 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
e237e7ae 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
8616fc4c 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
e237e7ae 983\r
8616fc4c 984 @retval EFI_SUCCESS The device feature is cleared.\r
985 @retval Others Failed to clear the feature.\r
e237e7ae 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
41e8ff27 1010 USB_CLEAR_FEATURE_REQUEST_TIMEOUT,\r
e237e7ae 1011 NULL,\r
1012 0,\r
1013 &UsbResult\r
1014 );\r
1015\r
1016 return Status;\r
1017}\r