e237e7ae |
1 | /** @file\r |
2 | \r |
8616fc4c |
3 | Usb Bus Driver Binding and Bus IO Protocol.\r |
4 | \r |
84909ad4 |
5 | Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>\r |
cd5ebaa0 |
6 | This program and the accompanying materials\r |
e237e7ae |
7 | are licensed and made available under the terms and conditions of the BSD License\r |
8 | which accompanies this distribution. The full text of the license may be found at\r |
9 | http://opensource.org/licenses/bsd-license.php\r |
10 | \r |
11 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r |
12 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r |
13 | \r |
e237e7ae |
14 | **/\r |
15 | \r |
16 | #include "UsbBus.h"\r |
17 | \r |
18 | //\r |
19 | // USB_BUS_PROTOCOL is only used to locate USB_BUS\r |
20 | //\r |
21 | EFI_GUID mUsbBusProtocolGuid = EFI_USB_BUS_PROTOCOL_GUID;\r |
22 | \r |
aa79b0b3 |
23 | EFI_USB_IO_PROTOCOL mUsbIoProtocol = {\r |
24 | UsbIoControlTransfer,\r |
25 | UsbIoBulkTransfer,\r |
26 | UsbIoAsyncInterruptTransfer,\r |
27 | UsbIoSyncInterruptTransfer,\r |
28 | UsbIoIsochronousTransfer,\r |
29 | UsbIoAsyncIsochronousTransfer,\r |
30 | UsbIoGetDeviceDescriptor,\r |
31 | UsbIoGetActiveConfigDescriptor,\r |
32 | UsbIoGetInterfaceDescriptor,\r |
33 | UsbIoGetEndpointDescriptor,\r |
34 | UsbIoGetStringDescriptor,\r |
35 | UsbIoGetSupportedLanguages,\r |
36 | UsbIoPortReset\r |
37 | };\r |
38 | \r |
39 | EFI_DRIVER_BINDING_PROTOCOL mUsbBusDriverBinding = {\r |
40 | UsbBusControllerDriverSupported,\r |
41 | UsbBusControllerDriverStart,\r |
42 | UsbBusControllerDriverStop,\r |
43 | 0xa,\r |
44 | NULL,\r |
45 | NULL\r |
46 | };\r |
47 | \r |
e237e7ae |
48 | \r |
49 | /**\r |
50 | USB_IO function to execute a control transfer. This\r |
51 | function will execute the USB transfer. If transfer\r |
52 | successes, it will sync the internal state of USB bus\r |
53 | with device state.\r |
54 | \r |
55 | @param This The USB_IO instance\r |
56 | @param Request The control transfer request\r |
57 | @param Direction Direction for data stage\r |
58 | @param Timeout The time to wait before timeout\r |
59 | @param Data The buffer holding the data\r |
60 | @param DataLength Then length of the data\r |
61 | @param UsbStatus USB result\r |
62 | \r |
63 | @retval EFI_INVALID_PARAMETER The parameters are invalid\r |
d17371e8 |
64 | @retval EFI_SUCCESS The control transfer succeeded.\r |
e237e7ae |
65 | @retval Others Failed to execute the transfer\r |
66 | \r |
67 | **/\r |
e237e7ae |
68 | EFI_STATUS\r |
69 | EFIAPI\r |
70 | UsbIoControlTransfer (\r |
71 | IN EFI_USB_IO_PROTOCOL *This,\r |
72 | IN EFI_USB_DEVICE_REQUEST *Request,\r |
73 | IN EFI_USB_DATA_DIRECTION Direction,\r |
74 | IN UINT32 Timeout,\r |
75 | IN OUT VOID *Data, OPTIONAL\r |
76 | IN UINTN DataLength, OPTIONAL\r |
77 | OUT UINT32 *UsbStatus\r |
78 | )\r |
79 | {\r |
80 | USB_DEVICE *Dev;\r |
81 | USB_INTERFACE *UsbIf;\r |
82 | USB_ENDPOINT_DESC *EpDesc;\r |
83 | EFI_TPL OldTpl;\r |
84 | EFI_STATUS Status;\r |
85 | \r |
86 | if (UsbStatus == NULL) {\r |
87 | return EFI_INVALID_PARAMETER;\r |
88 | }\r |
89 | \r |
90 | OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r |
91 | \r |
92 | UsbIf = USB_INTERFACE_FROM_USBIO (This);\r |
93 | Dev = UsbIf->Device;\r |
94 | \r |
95 | Status = UsbHcControlTransfer (\r |
96 | Dev->Bus,\r |
97 | Dev->Address,\r |
98 | Dev->Speed,\r |
99 | Dev->MaxPacket0,\r |
100 | Request,\r |
101 | Direction,\r |
102 | Data,\r |
103 | &DataLength,\r |
104 | (UINTN) Timeout,\r |
105 | &Dev->Translator,\r |
106 | UsbStatus\r |
107 | );\r |
108 | \r |
109 | if (EFI_ERROR (Status) || (*UsbStatus != EFI_USB_NOERROR)) {\r |
110 | //\r |
111 | // Clear TT buffer when CTRL/BULK split transaction failes\r |
112 | // Clear the TRANSLATOR TT buffer, not parent's buffer\r |
113 | //\r |
a1b749d0 |
114 | ASSERT (Dev->Translator.TranslatorHubAddress < USB_MAX_DEVICES);\r |
e237e7ae |
115 | if (Dev->Translator.TranslatorHubAddress != 0) {\r |
116 | UsbHubCtrlClearTTBuffer (\r |
117 | Dev->Bus->Devices[Dev->Translator.TranslatorHubAddress],\r |
118 | Dev->Translator.TranslatorPortNumber,\r |
119 | Dev->Address,\r |
120 | 0,\r |
121 | USB_ENDPOINT_CONTROL\r |
122 | );\r |
123 | }\r |
124 | \r |
125 | goto ON_EXIT;\r |
126 | }\r |
127 | \r |
128 | //\r |
129 | // Some control transfer will change the device's internal\r |
130 | // status, such as Set_Configuration and Set_Interface.\r |
131 | // We must synchronize the bus driver's status with that in\r |
132 | // device. We ignore the Set_Descriptor request because it's\r |
133 | // hardly used by any device, especially in pre-boot environment\r |
134 | //\r |
135 | \r |
136 | //\r |
137 | // Reset the endpoint toggle when endpoint stall is cleared\r |
138 | //\r |
139 | if ((Request->Request == USB_REQ_CLEAR_FEATURE) &&\r |
140 | (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD,\r |
141 | USB_TARGET_ENDPOINT)) &&\r |
142 | (Request->Value == USB_FEATURE_ENDPOINT_HALT)) {\r |
143 | \r |
144 | EpDesc = UsbGetEndpointDesc (UsbIf, (UINT8) Request->Index);\r |
145 | \r |
146 | if (EpDesc != NULL) {\r |
147 | EpDesc->Toggle = 0;\r |
148 | }\r |
149 | }\r |
150 | \r |
151 | //\r |
152 | // Select a new configuration. This is a dangerous action. Upper driver\r |
153 | // should stop use its current UsbIo after calling this driver. The old\r |
154 | // UsbIo will be uninstalled and new UsbIo be installed. We can't use\r |
155 | // ReinstallProtocol since interfaces in different configuration may be\r |
d17371e8 |
156 | // completely irrelevant.\r |
e237e7ae |
157 | //\r |
158 | if ((Request->Request == USB_REQ_SET_CONFIG) &&\r |
159 | (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD,\r |
160 | USB_TARGET_DEVICE))) {\r |
161 | //\r |
162 | // Don't re-create the USB interfaces if configuration isn't changed.\r |
163 | //\r |
164 | if ((Dev->ActiveConfig != NULL) &&\r |
165 | (Request->Value == Dev->ActiveConfig->Desc.ConfigurationValue)) {\r |
166 | \r |
167 | goto ON_EXIT;\r |
168 | }\r |
d2577026 |
169 | DEBUG ((EFI_D_INFO, "UsbIoControlTransfer: configure changed!!! Do NOT use old UsbIo!!!\n"));\r |
e237e7ae |
170 | \r |
171 | if (Dev->ActiveConfig != NULL) {\r |
172 | UsbRemoveConfig (Dev);\r |
173 | }\r |
174 | \r |
175 | if (Request->Value != 0) {\r |
176 | Status = UsbSelectConfig (Dev, (UINT8) Request->Value);\r |
177 | }\r |
178 | \r |
179 | //\r |
180 | // Exit now, Old USB_IO is invalid now\r |
181 | //\r |
182 | goto ON_EXIT;\r |
183 | }\r |
184 | \r |
185 | //\r |
186 | // A new alternative setting is selected for the interface.\r |
187 | // No need to reinstall UsbIo in this case because only\r |
188 | // underlying communication endpoints are changed. Functionality\r |
189 | // should remains the same.\r |
190 | //\r |
191 | if ((Request->Request == USB_REQ_SET_INTERFACE) &&\r |
192 | (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD,\r |
193 | USB_TARGET_INTERFACE)) &&\r |
194 | (Request->Index == UsbIf->IfSetting->Desc.InterfaceNumber)) {\r |
195 | \r |
196 | Status = UsbSelectSetting (UsbIf->IfDesc, (UINT8) Request->Value);\r |
197 | \r |
198 | if (!EFI_ERROR (Status)) {\r |
a1b749d0 |
199 | ASSERT (UsbIf->IfDesc->ActiveIndex < USB_MAX_INTERFACE_SETTING);\r |
e237e7ae |
200 | UsbIf->IfSetting = UsbIf->IfDesc->Settings[UsbIf->IfDesc->ActiveIndex];\r |
201 | }\r |
202 | }\r |
203 | \r |
204 | ON_EXIT:\r |
205 | gBS->RestoreTPL (OldTpl);\r |
206 | return Status;\r |
207 | }\r |
208 | \r |
209 | \r |
210 | /**\r |
8616fc4c |
211 | Execute a bulk transfer to the device endpoint.\r |
e237e7ae |
212 | \r |
8616fc4c |
213 | @param This The USB IO instance.\r |
214 | @param Endpoint The device endpoint.\r |
215 | @param Data The data to transfer.\r |
216 | @param DataLength The length of the data to transfer.\r |
217 | @param Timeout Time to wait before timeout.\r |
218 | @param UsbStatus The result of USB transfer.\r |
e237e7ae |
219 | \r |
8616fc4c |
220 | @retval EFI_SUCCESS The bulk transfer is OK.\r |
221 | @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r |
e237e7ae |
222 | @retval Others Failed to execute transfer, reason returned in\r |
8616fc4c |
223 | UsbStatus.\r |
e237e7ae |
224 | \r |
225 | **/\r |
e237e7ae |
226 | EFI_STATUS\r |
227 | EFIAPI\r |
228 | UsbIoBulkTransfer (\r |
229 | IN EFI_USB_IO_PROTOCOL *This,\r |
230 | IN UINT8 Endpoint,\r |
231 | IN OUT VOID *Data,\r |
232 | IN OUT UINTN *DataLength,\r |
233 | IN UINTN Timeout,\r |
234 | OUT UINT32 *UsbStatus\r |
235 | )\r |
236 | {\r |
237 | USB_DEVICE *Dev;\r |
238 | USB_INTERFACE *UsbIf;\r |
239 | USB_ENDPOINT_DESC *EpDesc;\r |
240 | UINT8 BufNum;\r |
241 | UINT8 Toggle;\r |
242 | EFI_TPL OldTpl;\r |
243 | EFI_STATUS Status;\r |
244 | \r |
245 | if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR(Endpoint) > 15) ||\r |
246 | (UsbStatus == NULL)) {\r |
247 | \r |
248 | return EFI_INVALID_PARAMETER;\r |
249 | }\r |
250 | \r |
251 | OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r |
252 | \r |
253 | UsbIf = USB_INTERFACE_FROM_USBIO (This);\r |
254 | Dev = UsbIf->Device;\r |
255 | \r |
256 | EpDesc = UsbGetEndpointDesc (UsbIf, Endpoint);\r |
257 | \r |
258 | if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_BULK)) {\r |
259 | Status = EFI_INVALID_PARAMETER;\r |
260 | goto ON_EXIT;\r |
261 | }\r |
262 | \r |
263 | BufNum = 1;\r |
264 | Toggle = EpDesc->Toggle;\r |
265 | Status = UsbHcBulkTransfer (\r |
266 | Dev->Bus,\r |
267 | Dev->Address,\r |
268 | Endpoint,\r |
269 | Dev->Speed,\r |
270 | EpDesc->Desc.MaxPacketSize,\r |
271 | BufNum,\r |
272 | &Data,\r |
273 | DataLength,\r |
274 | &Toggle,\r |
275 | Timeout,\r |
276 | &Dev->Translator,\r |
277 | UsbStatus\r |
278 | );\r |
279 | \r |
280 | EpDesc->Toggle = Toggle;\r |
281 | \r |
282 | if (EFI_ERROR (Status) || (*UsbStatus != EFI_USB_NOERROR)) {\r |
283 | //\r |
284 | // Clear TT buffer when CTRL/BULK split transaction failes.\r |
285 | // Clear the TRANSLATOR TT buffer, not parent's buffer\r |
286 | //\r |
a1b749d0 |
287 | ASSERT (Dev->Translator.TranslatorHubAddress < USB_MAX_DEVICES);\r |
e237e7ae |
288 | if (Dev->Translator.TranslatorHubAddress != 0) {\r |
289 | UsbHubCtrlClearTTBuffer (\r |
290 | Dev->Bus->Devices[Dev->Translator.TranslatorHubAddress],\r |
291 | Dev->Translator.TranslatorPortNumber,\r |
292 | Dev->Address,\r |
293 | 0,\r |
294 | USB_ENDPOINT_BULK\r |
295 | );\r |
296 | }\r |
297 | }\r |
298 | \r |
299 | ON_EXIT:\r |
300 | gBS->RestoreTPL (OldTpl);\r |
301 | return Status;\r |
302 | }\r |
303 | \r |
304 | \r |
305 | /**\r |
8616fc4c |
306 | Execute a synchronous interrupt transfer.\r |
e237e7ae |
307 | \r |
8616fc4c |
308 | @param This The USB IO instance.\r |
309 | @param Endpoint The device endpoint.\r |
310 | @param Data The data to transfer.\r |
311 | @param DataLength The length of the data to transfer.\r |
312 | @param Timeout Time to wait before timeout.\r |
313 | @param UsbStatus The result of USB transfer.\r |
e237e7ae |
314 | \r |
8616fc4c |
315 | @retval EFI_SUCCESS The synchronous interrupt transfer is OK.\r |
316 | @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r |
e237e7ae |
317 | @retval Others Failed to execute transfer, reason returned in\r |
8616fc4c |
318 | UsbStatus.\r |
e237e7ae |
319 | \r |
320 | **/\r |
e237e7ae |
321 | EFI_STATUS\r |
322 | EFIAPI\r |
323 | UsbIoSyncInterruptTransfer (\r |
324 | IN EFI_USB_IO_PROTOCOL *This,\r |
325 | IN UINT8 Endpoint,\r |
326 | IN OUT VOID *Data,\r |
327 | IN OUT UINTN *DataLength,\r |
328 | IN UINTN Timeout,\r |
329 | OUT UINT32 *UsbStatus\r |
330 | )\r |
331 | {\r |
332 | USB_DEVICE *Dev;\r |
333 | USB_INTERFACE *UsbIf;\r |
334 | USB_ENDPOINT_DESC *EpDesc;\r |
335 | EFI_TPL OldTpl;\r |
336 | UINT8 Toggle;\r |
337 | EFI_STATUS Status;\r |
338 | \r |
339 | if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR(Endpoint) > 15) ||\r |
340 | (UsbStatus == NULL)) {\r |
341 | \r |
342 | return EFI_INVALID_PARAMETER;\r |
343 | }\r |
344 | \r |
345 | OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r |
346 | \r |
347 | UsbIf = USB_INTERFACE_FROM_USBIO (This);\r |
348 | Dev = UsbIf->Device;\r |
349 | \r |
350 | EpDesc = UsbGetEndpointDesc (UsbIf, Endpoint);\r |
351 | \r |
352 | if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_INTERRUPT)) {\r |
353 | Status = EFI_INVALID_PARAMETER;\r |
354 | goto ON_EXIT;\r |
355 | }\r |
356 | \r |
357 | Toggle = EpDesc->Toggle;\r |
358 | Status = UsbHcSyncInterruptTransfer (\r |
359 | Dev->Bus,\r |
360 | Dev->Address,\r |
361 | Endpoint,\r |
362 | Dev->Speed,\r |
363 | EpDesc->Desc.MaxPacketSize,\r |
364 | Data,\r |
365 | DataLength,\r |
366 | &Toggle,\r |
367 | Timeout,\r |
368 | &Dev->Translator,\r |
369 | UsbStatus\r |
370 | );\r |
371 | \r |
372 | EpDesc->Toggle = Toggle;\r |
373 | \r |
374 | ON_EXIT:\r |
375 | gBS->RestoreTPL (OldTpl);\r |
376 | return Status;\r |
377 | }\r |
378 | \r |
379 | \r |
380 | /**\r |
381 | Queue a new asynchronous interrupt transfer, or remove the old\r |
8616fc4c |
382 | request if (IsNewTransfer == FALSE).\r |
e237e7ae |
383 | \r |
8616fc4c |
384 | @param This The USB_IO instance.\r |
385 | @param Endpoint The device endpoint.\r |
e237e7ae |
386 | @param IsNewTransfer Whether this is a new request, if it's old, remove\r |
8616fc4c |
387 | the request.\r |
388 | @param PollInterval The interval to poll the transfer result, (in ms).\r |
389 | @param DataLength The length of perodic data transfer.\r |
e237e7ae |
390 | @param Callback The function to call periodicaly when transfer is\r |
8616fc4c |
391 | ready.\r |
392 | @param Context The context to the callback.\r |
e237e7ae |
393 | \r |
8616fc4c |
394 | @retval EFI_SUCCESS New transfer is queued or old request is removed.\r |
395 | @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r |
e237e7ae |
396 | @retval Others Failed to queue the new request or remove the old\r |
8616fc4c |
397 | request.\r |
e237e7ae |
398 | \r |
399 | **/\r |
e237e7ae |
400 | EFI_STATUS\r |
401 | EFIAPI\r |
402 | UsbIoAsyncInterruptTransfer (\r |
403 | IN EFI_USB_IO_PROTOCOL *This,\r |
404 | IN UINT8 Endpoint,\r |
405 | IN BOOLEAN IsNewTransfer,\r |
406 | IN UINTN PollInterval, OPTIONAL\r |
407 | IN UINTN DataLength, OPTIONAL\r |
408 | IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback, OPTIONAL\r |
409 | IN VOID *Context OPTIONAL\r |
410 | )\r |
411 | {\r |
412 | USB_DEVICE *Dev;\r |
413 | USB_INTERFACE *UsbIf;\r |
414 | USB_ENDPOINT_DESC *EpDesc;\r |
415 | EFI_TPL OldTpl;\r |
416 | UINT8 Toggle;\r |
417 | EFI_STATUS Status;\r |
418 | \r |
419 | if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR (Endpoint) > 15)) {\r |
420 | return EFI_INVALID_PARAMETER;\r |
421 | }\r |
422 | \r |
423 | OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r |
424 | UsbIf = USB_INTERFACE_FROM_USBIO (This);\r |
425 | Dev = UsbIf->Device;\r |
426 | \r |
427 | EpDesc = UsbGetEndpointDesc (UsbIf, Endpoint);\r |
428 | \r |
429 | if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_INTERRUPT)) {\r |
430 | Status = EFI_INVALID_PARAMETER;\r |
431 | goto ON_EXIT;\r |
432 | }\r |
433 | \r |
434 | Toggle = EpDesc->Toggle;\r |
435 | Status = UsbHcAsyncInterruptTransfer (\r |
436 | Dev->Bus,\r |
437 | Dev->Address,\r |
438 | Endpoint,\r |
439 | Dev->Speed,\r |
440 | EpDesc->Desc.MaxPacketSize,\r |
441 | IsNewTransfer,\r |
442 | &Toggle,\r |
443 | PollInterval,\r |
444 | DataLength,\r |
445 | &Dev->Translator,\r |
446 | Callback,\r |
447 | Context\r |
448 | );\r |
449 | \r |
450 | EpDesc->Toggle = Toggle;\r |
451 | \r |
452 | ON_EXIT:\r |
453 | gBS->RestoreTPL (OldTpl);\r |
454 | return Status;\r |
455 | }\r |
456 | \r |
457 | \r |
458 | /**\r |
8616fc4c |
459 | Execute a synchronous isochronous transfer.\r |
e237e7ae |
460 | \r |
8616fc4c |
461 | @param This The USB IO instance.\r |
462 | @param DeviceEndpoint The device endpoint.\r |
463 | @param Data The data to transfer.\r |
464 | @param DataLength The length of the data to transfer.\r |
465 | @param UsbStatus The result of USB transfer.\r |
e237e7ae |
466 | \r |
8616fc4c |
467 | @retval EFI_UNSUPPORTED Currently isochronous transfer isn't supported.\r |
e237e7ae |
468 | \r |
469 | **/\r |
e237e7ae |
470 | EFI_STATUS\r |
471 | EFIAPI\r |
472 | UsbIoIsochronousTransfer (\r |
473 | IN EFI_USB_IO_PROTOCOL *This,\r |
474 | IN UINT8 DeviceEndpoint,\r |
475 | IN OUT VOID *Data,\r |
476 | IN UINTN DataLength,\r |
477 | OUT UINT32 *Status\r |
478 | )\r |
479 | {\r |
480 | return EFI_UNSUPPORTED;\r |
481 | }\r |
482 | \r |
483 | \r |
484 | /**\r |
8616fc4c |
485 | Queue an asynchronous isochronous transfer.\r |
e237e7ae |
486 | \r |
8616fc4c |
487 | @param This The USB_IO instance.\r |
488 | @param DeviceEndpoint The device endpoint.\r |
489 | @param Data The data to transfer.\r |
490 | @param DataLength The length of perodic data transfer.\r |
e237e7ae |
491 | @param IsochronousCallBack The function to call periodicaly when transfer is\r |
8616fc4c |
492 | ready.\r |
493 | @param Context The context to the callback.\r |
e237e7ae |
494 | \r |
8616fc4c |
495 | @retval EFI_UNSUPPORTED Currently isochronous transfer isn't supported.\r |
e237e7ae |
496 | \r |
497 | **/\r |
e237e7ae |
498 | EFI_STATUS\r |
499 | EFIAPI\r |
500 | UsbIoAsyncIsochronousTransfer (\r |
501 | IN EFI_USB_IO_PROTOCOL *This,\r |
502 | IN UINT8 DeviceEndpoint,\r |
503 | IN OUT VOID *Data,\r |
504 | IN UINTN DataLength,\r |
505 | IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,\r |
506 | IN VOID *Context OPTIONAL\r |
507 | )\r |
508 | {\r |
509 | return EFI_UNSUPPORTED;\r |
510 | }\r |
511 | \r |
512 | \r |
513 | /**\r |
8616fc4c |
514 | Retrieve the device descriptor of the device.\r |
e237e7ae |
515 | \r |
8616fc4c |
516 | @param This The USB IO instance.\r |
517 | @param Descriptor The variable to receive the device descriptor.\r |
e237e7ae |
518 | \r |
8616fc4c |
519 | @retval EFI_SUCCESS The device descriptor is returned.\r |
520 | @retval EFI_INVALID_PARAMETER The parameter is invalid.\r |
e237e7ae |
521 | \r |
522 | **/\r |
e237e7ae |
523 | EFI_STATUS\r |
524 | EFIAPI\r |
525 | UsbIoGetDeviceDescriptor (\r |
526 | IN EFI_USB_IO_PROTOCOL *This,\r |
527 | OUT EFI_USB_DEVICE_DESCRIPTOR *Descriptor\r |
528 | )\r |
529 | {\r |
530 | USB_DEVICE *Dev;\r |
531 | USB_INTERFACE *UsbIf;\r |
532 | EFI_TPL OldTpl;\r |
533 | \r |
534 | if (Descriptor == NULL) {\r |
535 | return EFI_INVALID_PARAMETER;\r |
536 | }\r |
537 | \r |
538 | OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r |
539 | \r |
540 | UsbIf = USB_INTERFACE_FROM_USBIO (This);\r |
541 | Dev = UsbIf->Device;\r |
542 | \r |
543 | CopyMem (Descriptor, &Dev->DevDesc->Desc, sizeof (EFI_USB_DEVICE_DESCRIPTOR));\r |
544 | \r |
545 | gBS->RestoreTPL (OldTpl);\r |
546 | return EFI_SUCCESS;\r |
547 | }\r |
548 | \r |
549 | \r |
550 | /**\r |
8616fc4c |
551 | Return the configuration descriptor of the current active configuration.\r |
e237e7ae |
552 | \r |
8616fc4c |
553 | @param This The USB IO instance.\r |
554 | @param Descriptor The USB configuration descriptor.\r |
e237e7ae |
555 | \r |
8616fc4c |
556 | @retval EFI_SUCCESS The active configuration descriptor is returned.\r |
557 | @retval EFI_INVALID_PARAMETER Some parameter is invalid.\r |
e237e7ae |
558 | @retval EFI_NOT_FOUND Currently no active configuration is selected.\r |
559 | \r |
560 | **/\r |
e237e7ae |
561 | EFI_STATUS\r |
562 | EFIAPI\r |
563 | UsbIoGetActiveConfigDescriptor (\r |
564 | IN EFI_USB_IO_PROTOCOL *This,\r |
565 | OUT EFI_USB_CONFIG_DESCRIPTOR *Descriptor\r |
566 | )\r |
567 | {\r |
568 | USB_DEVICE *Dev;\r |
569 | USB_INTERFACE *UsbIf;\r |
570 | EFI_STATUS Status;\r |
571 | EFI_TPL OldTpl;\r |
572 | \r |
573 | if (Descriptor == NULL) {\r |
574 | return EFI_INVALID_PARAMETER;\r |
575 | }\r |
576 | \r |
577 | Status = EFI_SUCCESS;\r |
578 | OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r |
579 | \r |
580 | UsbIf = USB_INTERFACE_FROM_USBIO (This);\r |
581 | Dev = UsbIf->Device;\r |
582 | \r |
583 | if (Dev->ActiveConfig == NULL) {\r |
584 | Status = EFI_NOT_FOUND;\r |
585 | goto ON_EXIT;\r |
586 | }\r |
587 | \r |
588 | CopyMem (Descriptor, &(Dev->ActiveConfig->Desc), sizeof (EFI_USB_CONFIG_DESCRIPTOR));\r |
589 | \r |
590 | ON_EXIT:\r |
591 | gBS->RestoreTPL (OldTpl);\r |
592 | return Status;\r |
593 | }\r |
594 | \r |
595 | \r |
596 | /**\r |
8616fc4c |
597 | Retrieve the active interface setting descriptor for this USB IO instance.\r |
e237e7ae |
598 | \r |
8616fc4c |
599 | @param This The USB IO instance.\r |
600 | @param Descriptor The variable to receive active interface setting.\r |
e237e7ae |
601 | \r |
8616fc4c |
602 | @retval EFI_SUCCESS The active interface setting is returned.\r |
603 | @retval EFI_INVALID_PARAMETER Some parameter is invalid.\r |
e237e7ae |
604 | \r |
605 | **/\r |
e237e7ae |
606 | EFI_STATUS\r |
607 | EFIAPI\r |
608 | UsbIoGetInterfaceDescriptor (\r |
609 | IN EFI_USB_IO_PROTOCOL *This,\r |
610 | OUT EFI_USB_INTERFACE_DESCRIPTOR *Descriptor\r |
611 | )\r |
612 | {\r |
613 | USB_INTERFACE *UsbIf;\r |
614 | EFI_TPL OldTpl;\r |
615 | \r |
616 | if (Descriptor == NULL) {\r |
617 | return EFI_INVALID_PARAMETER;\r |
618 | }\r |
619 | \r |
620 | OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r |
621 | \r |
622 | UsbIf = USB_INTERFACE_FROM_USBIO (This);\r |
623 | CopyMem (Descriptor, &(UsbIf->IfSetting->Desc), sizeof (EFI_USB_INTERFACE_DESCRIPTOR));\r |
624 | \r |
625 | gBS->RestoreTPL (OldTpl);\r |
626 | return EFI_SUCCESS;\r |
627 | }\r |
628 | \r |
629 | \r |
630 | /**\r |
8616fc4c |
631 | Retrieve the endpoint descriptor from this interface setting.\r |
e237e7ae |
632 | \r |
8616fc4c |
633 | @param This The USB IO instance.\r |
e237e7ae |
634 | @param Index The index (start from zero) of the endpoint to\r |
8616fc4c |
635 | retrieve.\r |
636 | @param Descriptor The variable to receive the descriptor.\r |
e237e7ae |
637 | \r |
8616fc4c |
638 | @retval EFI_SUCCESS The endpoint descriptor is returned.\r |
639 | @retval EFI_INVALID_PARAMETER Some parameter is invalid.\r |
e237e7ae |
640 | \r |
641 | **/\r |
e237e7ae |
642 | EFI_STATUS\r |
643 | EFIAPI\r |
644 | UsbIoGetEndpointDescriptor (\r |
645 | IN EFI_USB_IO_PROTOCOL *This,\r |
646 | IN UINT8 Index,\r |
647 | OUT EFI_USB_ENDPOINT_DESCRIPTOR *Descriptor\r |
648 | )\r |
649 | {\r |
650 | USB_INTERFACE *UsbIf;\r |
651 | EFI_TPL OldTpl;\r |
652 | \r |
653 | OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r |
654 | \r |
655 | UsbIf = USB_INTERFACE_FROM_USBIO (This);\r |
656 | \r |
50fa1b3a |
657 | if ((Descriptor == NULL) || (Index > 15)) {\r |
e237e7ae |
658 | gBS->RestoreTPL (OldTpl);\r |
659 | return EFI_INVALID_PARAMETER;\r |
660 | }\r |
661 | \r |
50fa1b3a |
662 | if (Index >= UsbIf->IfSetting->Desc.NumEndpoints) {\r |
663 | gBS->RestoreTPL (OldTpl);\r |
664 | return EFI_NOT_FOUND;\r |
665 | }\r |
666 | \r |
e237e7ae |
667 | CopyMem (\r |
668 | Descriptor,\r |
669 | &(UsbIf->IfSetting->Endpoints[Index]->Desc),\r |
670 | sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)\r |
671 | );\r |
672 | \r |
673 | gBS->RestoreTPL (OldTpl);\r |
674 | return EFI_SUCCESS;\r |
675 | }\r |
676 | \r |
677 | \r |
678 | /**\r |
8616fc4c |
679 | Retrieve the supported language ID table from the device.\r |
e237e7ae |
680 | \r |
8616fc4c |
681 | @param This The USB IO instance.\r |
682 | @param LangIDTable The table to return the language IDs.\r |
84909ad4 |
683 | @param TableSize The size, in bytes, of the table LangIDTable.\r |
e237e7ae |
684 | \r |
8616fc4c |
685 | @retval EFI_SUCCESS The language ID is return.\r |
e237e7ae |
686 | \r |
687 | **/\r |
e237e7ae |
688 | EFI_STATUS\r |
689 | EFIAPI\r |
690 | UsbIoGetSupportedLanguages (\r |
691 | IN EFI_USB_IO_PROTOCOL *This,\r |
692 | OUT UINT16 **LangIDTable,\r |
693 | OUT UINT16 *TableSize\r |
694 | )\r |
695 | {\r |
696 | USB_DEVICE *Dev;\r |
697 | USB_INTERFACE *UsbIf;\r |
698 | EFI_TPL OldTpl;\r |
699 | \r |
700 | OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r |
701 | \r |
702 | UsbIf = USB_INTERFACE_FROM_USBIO (This);\r |
703 | Dev = UsbIf->Device;\r |
704 | \r |
705 | *LangIDTable = Dev->LangId;\r |
84909ad4 |
706 | *TableSize = (UINT16) (Dev->TotalLangId * sizeof (UINT16));\r |
e237e7ae |
707 | \r |
708 | gBS->RestoreTPL (OldTpl);\r |
709 | return EFI_SUCCESS;\r |
710 | }\r |
711 | \r |
712 | \r |
713 | /**\r |
8616fc4c |
714 | Retrieve an indexed string in the language of LangID.\r |
e237e7ae |
715 | \r |
8616fc4c |
716 | @param This The USB IO instance.\r |
717 | @param LangID The language ID of the string to retrieve.\r |
718 | @param StringIndex The index of the string.\r |
719 | @param String The variable to receive the string.\r |
e237e7ae |
720 | \r |
8616fc4c |
721 | @retval EFI_SUCCESS The string is returned.\r |
722 | @retval EFI_NOT_FOUND No such string existed.\r |
e237e7ae |
723 | \r |
724 | **/\r |
e237e7ae |
725 | EFI_STATUS\r |
726 | EFIAPI\r |
727 | UsbIoGetStringDescriptor (\r |
728 | IN EFI_USB_IO_PROTOCOL *This,\r |
729 | IN UINT16 LangID,\r |
730 | IN UINT8 StringIndex,\r |
731 | OUT CHAR16 **String\r |
732 | )\r |
733 | {\r |
734 | USB_DEVICE *Dev;\r |
735 | USB_INTERFACE *UsbIf;\r |
736 | EFI_USB_STRING_DESCRIPTOR *StrDesc;\r |
737 | EFI_TPL OldTpl;\r |
738 | UINT8 *Buf;\r |
739 | UINT8 Index;\r |
740 | EFI_STATUS Status;\r |
741 | \r |
742 | if ((StringIndex == 0) || (LangID == 0)) {\r |
743 | return EFI_NOT_FOUND;\r |
744 | }\r |
745 | \r |
746 | OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r |
747 | \r |
748 | UsbIf = USB_INTERFACE_FROM_USBIO (This);\r |
749 | Dev = UsbIf->Device;\r |
750 | \r |
751 | //\r |
752 | // Check whether language ID is supported\r |
753 | //\r |
754 | Status = EFI_NOT_FOUND;\r |
755 | \r |
756 | for (Index = 0; Index < Dev->TotalLangId; Index++) {\r |
a1b749d0 |
757 | ASSERT (Index < USB_MAX_LANG_ID);\r |
e237e7ae |
758 | if (Dev->LangId[Index] == LangID) {\r |
759 | break;\r |
760 | }\r |
761 | }\r |
762 | \r |
763 | if (Index == Dev->TotalLangId) {\r |
764 | goto ON_EXIT;\r |
765 | }\r |
766 | \r |
767 | //\r |
768 | // Retrieve the string descriptor then allocate a buffer\r |
769 | // to hold the string itself.\r |
770 | //\r |
771 | StrDesc = UsbGetOneString (Dev, StringIndex, LangID);\r |
772 | \r |
773 | if (StrDesc == NULL) {\r |
774 | goto ON_EXIT;\r |
775 | }\r |
776 | \r |
777 | if (StrDesc->Length <= 2) {\r |
778 | goto FREE_STR;\r |
779 | }\r |
780 | \r |
781 | Buf = AllocateZeroPool (StrDesc->Length);\r |
782 | \r |
783 | if (Buf == NULL) {\r |
784 | Status = EFI_OUT_OF_RESOURCES;\r |
785 | goto FREE_STR;\r |
786 | }\r |
787 | \r |
788 | CopyMem (Buf, StrDesc->String, StrDesc->Length - 2);\r |
789 | *String = (CHAR16 *) Buf;\r |
790 | Status = EFI_SUCCESS;\r |
791 | \r |
792 | FREE_STR:\r |
793 | gBS->FreePool (StrDesc);\r |
794 | \r |
795 | ON_EXIT:\r |
796 | gBS->RestoreTPL (OldTpl);\r |
797 | return Status;\r |
798 | }\r |
799 | \r |
800 | \r |
801 | /**\r |
802 | Reset the device, then if that succeeds, reconfigure the\r |
803 | device with its address and current active configuration.\r |
804 | \r |
8616fc4c |
805 | @param This The USB IO instance.\r |
e237e7ae |
806 | \r |
8616fc4c |
807 | @retval EFI_SUCCESS The device is reset and configured.\r |
808 | @retval Others Failed to reset the device.\r |
e237e7ae |
809 | \r |
810 | **/\r |
811 | EFI_STATUS\r |
812 | EFIAPI\r |
813 | UsbIoPortReset (\r |
814 | IN EFI_USB_IO_PROTOCOL *This\r |
815 | )\r |
816 | {\r |
817 | USB_INTERFACE *UsbIf;\r |
818 | USB_INTERFACE *HubIf;\r |
819 | USB_DEVICE *Dev;\r |
820 | UINT8 Address;\r |
821 | EFI_TPL OldTpl;\r |
822 | EFI_STATUS Status;\r |
823 | \r |
824 | OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r |
825 | \r |
826 | UsbIf = USB_INTERFACE_FROM_USBIO (This);\r |
827 | Dev = UsbIf->Device;\r |
828 | \r |
a92d4e8a |
829 | if (UsbIf->IsHub) {\r |
50fa1b3a |
830 | Status = EFI_INVALID_PARAMETER;\r |
831 | goto ON_EXIT;\r |
832 | }\r |
833 | \r |
e237e7ae |
834 | HubIf = Dev->ParentIf;\r |
835 | Status = HubIf->HubApi->ResetPort (HubIf, Dev->ParentPort);\r |
836 | \r |
837 | if (EFI_ERROR (Status)) {\r |
d2577026 |
838 | DEBUG (( EFI_D_ERROR, "UsbIoPortReset: failed to reset hub port %d@hub %d, %r \n",\r |
e237e7ae |
839 | Dev->ParentPort, Dev->ParentAddr, Status));\r |
840 | \r |
841 | goto ON_EXIT;\r |
842 | }\r |
843 | \r |
844 | //\r |
845 | // Reset the device to its current address. The device now has a\r |
846 | // address of ZERO, so need to set Dev->Address to zero first for\r |
847 | // host to communicate with the device\r |
848 | //\r |
849 | Address = Dev->Address;\r |
850 | Dev->Address = 0;\r |
851 | Status = UsbSetAddress (Dev, Address);\r |
efe9186f |
852 | \r |
853 | gBS->Stall (USB_SET_DEVICE_ADDRESS_STALL);\r |
7e388f85 |
854 | \r |
e237e7ae |
855 | if (EFI_ERROR (Status)) {\r |
d2577026 |
856 | DEBUG (( EFI_D_ERROR, "UsbIoPortReset: failed to set address for device %d - %r\n",\r |
e237e7ae |
857 | Address, Status));\r |
858 | \r |
859 | goto ON_EXIT;\r |
860 | }\r |
861 | \r |
efe9186f |
862 | Dev->Address = Address;\r |
e237e7ae |
863 | \r |
7e388f85 |
864 | DEBUG (( EFI_D_INFO, "UsbIoPortReset: device is now ADDRESSED at %d\n", Address));\r |
865 | \r |
e237e7ae |
866 | //\r |
867 | // Reset the current active configure, after this device\r |
868 | // is in CONFIGURED state.\r |
869 | //\r |
870 | if (Dev->ActiveConfig != NULL) {\r |
871 | Status = UsbSetConfig (Dev, Dev->ActiveConfig->Desc.ConfigurationValue);\r |
872 | \r |
873 | if (EFI_ERROR (Status)) {\r |
d2577026 |
874 | DEBUG (( EFI_D_ERROR, "UsbIoPortReset: failed to set configure for device %d - %r\n",\r |
e237e7ae |
875 | Address, Status));\r |
876 | }\r |
877 | }\r |
878 | \r |
879 | ON_EXIT:\r |
880 | gBS->RestoreTPL (OldTpl);\r |
881 | return Status;\r |
882 | }\r |
883 | \r |
ecb575d9 |
884 | \r |
885 | /**\r |
8616fc4c |
886 | Install Usb Bus Protocol on host controller, and start the Usb bus.\r |
ecb575d9 |
887 | \r |
8616fc4c |
888 | @param This The USB bus driver binding instance.\r |
889 | @param Controller The controller to check.\r |
890 | @param RemainingDevicePath The remaining device patch.\r |
ecb575d9 |
891 | \r |
8616fc4c |
892 | @retval EFI_SUCCESS The controller is controlled by the usb bus.\r |
893 | @retval EFI_ALREADY_STARTED The controller is already controlled by the usb bus.\r |
894 | @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.\r |
ecb575d9 |
895 | \r |
896 | **/\r |
897 | EFI_STATUS\r |
898 | EFIAPI\r |
899 | UsbBusBuildProtocol (\r |
900 | IN EFI_DRIVER_BINDING_PROTOCOL *This,\r |
901 | IN EFI_HANDLE Controller,\r |
902 | IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r |
903 | )\r |
904 | {\r |
905 | USB_BUS *UsbBus;\r |
906 | USB_DEVICE *RootHub;\r |
907 | USB_INTERFACE *RootIf;\r |
908 | EFI_STATUS Status;\r |
909 | EFI_STATUS Status2;\r |
910 | \r |
911 | UsbBus = AllocateZeroPool (sizeof (USB_BUS));\r |
912 | \r |
913 | if (UsbBus == NULL) {\r |
914 | return EFI_OUT_OF_RESOURCES;\r |
915 | }\r |
916 | \r |
917 | UsbBus->Signature = USB_BUS_SIGNATURE;\r |
918 | UsbBus->HostHandle = Controller;\r |
919 | \r |
920 | Status = gBS->OpenProtocol (\r |
921 | Controller,\r |
922 | &gEfiDevicePathProtocolGuid,\r |
923 | (VOID **) &UsbBus->DevicePath,\r |
924 | This->DriverBindingHandle,\r |
925 | Controller,\r |
926 | EFI_OPEN_PROTOCOL_BY_DRIVER\r |
927 | );\r |
928 | \r |
929 | if (EFI_ERROR (Status)) {\r |
930 | DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to open device path %r\n", Status));\r |
931 | \r |
d17371e8 |
932 | FreePool (UsbBus);\r |
ecb575d9 |
933 | return Status;\r |
934 | }\r |
935 | \r |
936 | //\r |
937 | // Get USB_HC2/USB_HC host controller protocol (EHCI/UHCI).\r |
d17371e8 |
938 | // This is for backward compatibility with EFI 1.x. In UEFI\r |
ecb575d9 |
939 | // 2.x, USB_HC2 replaces USB_HC. We will open both USB_HC2\r |
940 | // and USB_HC because EHCI driver will install both protocols\r |
941 | // (for the same reason). If we don't consume both of them,\r |
942 | // the unconsumed one may be opened by others.\r |
943 | //\r |
944 | Status = gBS->OpenProtocol (\r |
945 | Controller,\r |
946 | &gEfiUsb2HcProtocolGuid,\r |
947 | (VOID **) &(UsbBus->Usb2Hc),\r |
948 | This->DriverBindingHandle,\r |
949 | Controller,\r |
950 | EFI_OPEN_PROTOCOL_BY_DRIVER\r |
951 | );\r |
952 | \r |
953 | Status2 = gBS->OpenProtocol (\r |
954 | Controller,\r |
955 | &gEfiUsbHcProtocolGuid,\r |
956 | (VOID **) &(UsbBus->UsbHc),\r |
957 | This->DriverBindingHandle,\r |
958 | Controller,\r |
959 | EFI_OPEN_PROTOCOL_BY_DRIVER\r |
960 | );\r |
961 | \r |
962 | if (EFI_ERROR (Status) && EFI_ERROR (Status2)) {\r |
963 | DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to open USB_HC/USB2_HC %r\n", Status));\r |
964 | \r |
965 | Status = EFI_DEVICE_ERROR;\r |
966 | goto CLOSE_HC;\r |
967 | }\r |
968 | \r |
969 | UsbHcReset (UsbBus, EFI_USB_HC_RESET_GLOBAL);\r |
970 | UsbHcSetState (UsbBus, EfiUsbHcStateOperational);\r |
971 | \r |
972 | //\r |
d17371e8 |
973 | // Install an EFI_USB_BUS_PROTOCOL to host controller to identify it.\r |
ecb575d9 |
974 | //\r |
975 | Status = gBS->InstallProtocolInterface (\r |
976 | &Controller,\r |
977 | &mUsbBusProtocolGuid,\r |
978 | EFI_NATIVE_INTERFACE,\r |
979 | &UsbBus->BusId\r |
980 | );\r |
981 | \r |
982 | if (EFI_ERROR (Status)) {\r |
983 | DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to install bus protocol %r\n", Status));\r |
984 | goto CLOSE_HC;\r |
985 | }\r |
986 | \r |
987 | //\r |
988 | // Initial the wanted child device path list, and add first RemainingDevicePath\r |
989 | //\r |
990 | InitializeListHead (&UsbBus->WantedUsbIoDPList);\r |
991 | Status = UsbBusAddWantedUsbIoDP (&UsbBus->BusId, RemainingDevicePath);\r |
992 | ASSERT (!EFI_ERROR (Status));\r |
993 | //\r |
994 | // Create a fake usb device for root hub\r |
995 | //\r |
996 | RootHub = AllocateZeroPool (sizeof (USB_DEVICE));\r |
997 | \r |
998 | if (RootHub == NULL) {\r |
999 | Status = EFI_OUT_OF_RESOURCES;\r |
1000 | goto UNINSTALL_USBBUS;\r |
1001 | }\r |
1002 | \r |
1003 | RootIf = AllocateZeroPool (sizeof (USB_INTERFACE));\r |
1004 | \r |
1005 | if (RootIf == NULL) {\r |
d17371e8 |
1006 | FreePool (RootHub);\r |
ecb575d9 |
1007 | Status = EFI_OUT_OF_RESOURCES;\r |
1008 | goto FREE_ROOTHUB;\r |
1009 | }\r |
1010 | \r |
1011 | RootHub->Bus = UsbBus;\r |
1012 | RootHub->NumOfInterface = 1;\r |
1013 | RootHub->Interfaces[0] = RootIf;\r |
1014 | RootIf->Signature = USB_INTERFACE_SIGNATURE;\r |
1015 | RootIf->Device = RootHub;\r |
1016 | RootIf->DevicePath = UsbBus->DevicePath;\r |
1017 | \r |
1018 | Status = mUsbRootHubApi.Init (RootIf);\r |
1019 | \r |
1020 | if (EFI_ERROR (Status)) {\r |
1021 | DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to init root hub %r\n", Status));\r |
1022 | goto FREE_ROOTHUB;\r |
1023 | }\r |
1024 | \r |
1025 | UsbBus->Devices[0] = RootHub;\r |
1026 | \r |
0e549d5b |
1027 | DEBUG ((EFI_D_INFO, "UsbBusStart: usb bus started on %p, root hub %p\n", Controller, RootIf));\r |
ecb575d9 |
1028 | return EFI_SUCCESS;\r |
1029 | \r |
1030 | FREE_ROOTHUB:\r |
1031 | if (RootIf != NULL) {\r |
d17371e8 |
1032 | FreePool (RootIf);\r |
ecb575d9 |
1033 | }\r |
1034 | if (RootHub != NULL) {\r |
d17371e8 |
1035 | FreePool (RootHub);\r |
ecb575d9 |
1036 | }\r |
1037 | \r |
1038 | UNINSTALL_USBBUS:\r |
1039 | gBS->UninstallProtocolInterface (Controller, &mUsbBusProtocolGuid, &UsbBus->BusId);\r |
1040 | \r |
1041 | CLOSE_HC:\r |
1042 | if (UsbBus->Usb2Hc != NULL) {\r |
1043 | gBS->CloseProtocol (\r |
1044 | Controller,\r |
1045 | &gEfiUsb2HcProtocolGuid,\r |
1046 | This->DriverBindingHandle,\r |
1047 | Controller\r |
1048 | );\r |
1049 | }\r |
1050 | if (UsbBus->UsbHc != NULL) {\r |
1051 | gBS->CloseProtocol (\r |
1052 | Controller,\r |
1053 | &gEfiUsbHcProtocolGuid,\r |
1054 | This->DriverBindingHandle,\r |
1055 | Controller\r |
1056 | );\r |
1057 | }\r |
1058 | gBS->CloseProtocol (\r |
1059 | Controller,\r |
1060 | &gEfiDevicePathProtocolGuid,\r |
1061 | This->DriverBindingHandle,\r |
1062 | Controller\r |
1063 | );\r |
d17371e8 |
1064 | FreePool (UsbBus);\r |
ecb575d9 |
1065 | \r |
1066 | DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to start bus driver %r\n", Status));\r |
1067 | return Status;\r |
1068 | }\r |
1069 | \r |
e237e7ae |
1070 | \r |
8616fc4c |
1071 | /**\r |
1072 | The USB bus driver entry pointer.\r |
1073 | \r |
1074 | @param ImageHandle The driver image handle.\r |
1075 | @param SystemTable The system table.\r |
1076 | \r |
1077 | @return EFI_SUCCESS The component name protocol is installed.\r |
1078 | @return Others Failed to init the usb driver.\r |
1079 | \r |
1080 | **/\r |
e237e7ae |
1081 | EFI_STATUS\r |
1082 | EFIAPI\r |
1083 | UsbBusDriverEntryPoint (\r |
1084 | IN EFI_HANDLE ImageHandle,\r |
1085 | IN EFI_SYSTEM_TABLE *SystemTable\r |
1086 | )\r |
e237e7ae |
1087 | {\r |
62b9bb55 |
1088 | return EfiLibInstallDriverBindingComponentName2 (\r |
e237e7ae |
1089 | ImageHandle,\r |
1090 | SystemTable,\r |
1091 | &mUsbBusDriverBinding,\r |
1092 | ImageHandle,\r |
1093 | &mUsbBusComponentName,\r |
62b9bb55 |
1094 | &mUsbBusComponentName2\r |
e237e7ae |
1095 | );\r |
1096 | }\r |
1097 | \r |
1098 | \r |
1099 | /**\r |
8616fc4c |
1100 | Check whether USB bus driver support this device.\r |
e237e7ae |
1101 | \r |
8616fc4c |
1102 | @param This The USB bus driver binding protocol.\r |
34a0bac4 |
1103 | @param Controller The controller handle to check.\r |
8616fc4c |
1104 | @param RemainingDevicePath The remaining device path.\r |
e237e7ae |
1105 | \r |
1106 | @retval EFI_SUCCESS The bus supports this controller.\r |
8616fc4c |
1107 | @retval EFI_UNSUPPORTED This device isn't supported.\r |
e237e7ae |
1108 | \r |
1109 | **/\r |
1110 | EFI_STATUS\r |
1111 | EFIAPI\r |
1112 | UsbBusControllerDriverSupported (\r |
1113 | IN EFI_DRIVER_BINDING_PROTOCOL *This,\r |
1114 | IN EFI_HANDLE Controller,\r |
1115 | IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r |
1116 | )\r |
1117 | {\r |
1118 | EFI_DEV_PATH_PTR DevicePathNode;\r |
1119 | EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r |
1120 | EFI_USB2_HC_PROTOCOL *Usb2Hc;\r |
1121 | EFI_USB_HC_PROTOCOL *UsbHc;\r |
1122 | EFI_STATUS Status;\r |
1123 | \r |
1124 | //\r |
1125 | // Check whether device path is valid\r |
1126 | //\r |
1127 | if (RemainingDevicePath != NULL) {\r |
af4a6385 |
1128 | //\r |
1129 | // Check if RemainingDevicePath is the End of Device Path Node, \r |
1130 | // if yes, go on checking other conditions\r |
1131 | //\r |
1132 | if (!IsDevicePathEnd (RemainingDevicePath)) {\r |
1133 | //\r |
1134 | // If RemainingDevicePath isn't the End of Device Path Node,\r |
1135 | // check its validation\r |
1136 | //\r |
1137 | DevicePathNode.DevPath = RemainingDevicePath;\r |
1138 | \r |
1139 | if ((DevicePathNode.DevPath->Type != MESSAGING_DEVICE_PATH) ||\r |
1140 | (DevicePathNode.DevPath->SubType != MSG_USB_DP &&\r |
1141 | DevicePathNode.DevPath->SubType != MSG_USB_CLASS_DP\r |
1142 | && DevicePathNode.DevPath->SubType != MSG_USB_WWID_DP\r |
1143 | )) {\r |
1144 | \r |
1145 | return EFI_UNSUPPORTED;\r |
1146 | }\r |
e237e7ae |
1147 | }\r |
1148 | }\r |
1149 | \r |
e237e7ae |
1150 | //\r |
1151 | // Check whether USB_HC2 protocol is installed\r |
1152 | //\r |
1153 | Status = gBS->OpenProtocol (\r |
1154 | Controller,\r |
1155 | &gEfiUsb2HcProtocolGuid,\r |
1156 | (VOID **) &Usb2Hc,\r |
1157 | This->DriverBindingHandle,\r |
1158 | Controller,\r |
1159 | EFI_OPEN_PROTOCOL_BY_DRIVER\r |
1160 | );\r |
e237e7ae |
1161 | if (Status == EFI_ALREADY_STARTED) {\r |
1162 | return EFI_SUCCESS;\r |
1163 | }\r |
1164 | \r |
af4a6385 |
1165 | if (EFI_ERROR (Status)) {\r |
1166 | //\r |
1167 | // If failed to open USB_HC2, fall back to USB_HC\r |
1168 | //\r |
1169 | Status = gBS->OpenProtocol (\r |
1170 | Controller,\r |
1171 | &gEfiUsbHcProtocolGuid,\r |
1172 | (VOID **) &UsbHc,\r |
1173 | This->DriverBindingHandle,\r |
1174 | Controller,\r |
1175 | EFI_OPEN_PROTOCOL_BY_DRIVER\r |
1176 | );\r |
1177 | if (Status == EFI_ALREADY_STARTED) {\r |
1178 | return EFI_SUCCESS;\r |
1179 | }\r |
1180 | \r |
1181 | if (EFI_ERROR (Status)) {\r |
1182 | return Status;\r |
1183 | }\r |
1184 | \r |
1185 | //\r |
1186 | // Close the USB_HC used to perform the supported test\r |
1187 | //\r |
e237e7ae |
1188 | gBS->CloseProtocol (\r |
1189 | Controller,\r |
af4a6385 |
1190 | &gEfiUsbHcProtocolGuid,\r |
e237e7ae |
1191 | This->DriverBindingHandle,\r |
1192 | Controller\r |
1193 | );\r |
1194 | \r |
af4a6385 |
1195 | } else {\r |
e237e7ae |
1196 | \r |
af4a6385 |
1197 | //\r |
1198 | // Close the USB_HC2 used to perform the supported test\r |
1199 | //\r |
1200 | gBS->CloseProtocol (\r |
1201 | Controller,\r |
1202 | &gEfiUsb2HcProtocolGuid,\r |
1203 | This->DriverBindingHandle,\r |
1204 | Controller\r |
1205 | );\r |
1206 | }\r |
1207 | \r |
e237e7ae |
1208 | //\r |
af4a6385 |
1209 | // Open the EFI Device Path protocol needed to perform the supported test\r |
e237e7ae |
1210 | //\r |
1211 | Status = gBS->OpenProtocol (\r |
1212 | Controller,\r |
af4a6385 |
1213 | &gEfiDevicePathProtocolGuid,\r |
1214 | (VOID **) &ParentDevicePath,\r |
e237e7ae |
1215 | This->DriverBindingHandle,\r |
1216 | Controller,\r |
1217 | EFI_OPEN_PROTOCOL_BY_DRIVER\r |
1218 | );\r |
e237e7ae |
1219 | if (Status == EFI_ALREADY_STARTED) {\r |
1220 | return EFI_SUCCESS;\r |
1221 | }\r |
1222 | \r |
1223 | if (!EFI_ERROR (Status)) {\r |
af4a6385 |
1224 | //\r |
1225 | // Close protocol, don't use device path protocol in the Support() function\r |
1226 | //\r |
e237e7ae |
1227 | gBS->CloseProtocol (\r |
1228 | Controller,\r |
af4a6385 |
1229 | &gEfiDevicePathProtocolGuid,\r |
e237e7ae |
1230 | This->DriverBindingHandle,\r |
1231 | Controller\r |
1232 | );\r |
af4a6385 |
1233 | \r |
1234 | return EFI_SUCCESS;\r |
e237e7ae |
1235 | }\r |
1236 | \r |
1237 | return Status;\r |
1238 | }\r |
1239 | \r |
1240 | \r |
1241 | /**\r |
8616fc4c |
1242 | Start to process the controller.\r |
e237e7ae |
1243 | \r |
8616fc4c |
1244 | @param This The USB bus driver binding instance.\r |
1245 | @param Controller The controller to check.\r |
1246 | @param RemainingDevicePath The remaining device patch.\r |
e237e7ae |
1247 | \r |
8616fc4c |
1248 | @retval EFI_SUCCESS The controller is controlled by the usb bus.\r |
e237e7ae |
1249 | @retval EFI_ALREADY_STARTED The controller is already controlled by the usb\r |
8616fc4c |
1250 | bus.\r |
1251 | @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.\r |
e237e7ae |
1252 | \r |
1253 | **/\r |
1254 | EFI_STATUS\r |
1255 | EFIAPI\r |
1256 | UsbBusControllerDriverStart (\r |
1257 | IN EFI_DRIVER_BINDING_PROTOCOL *This,\r |
1258 | IN EFI_HANDLE Controller,\r |
1259 | IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r |
1260 | )\r |
1261 | {\r |
ecb575d9 |
1262 | EFI_USB_BUS_PROTOCOL *UsbBusId;\r |
1263 | EFI_STATUS Status;\r |
e237e7ae |
1264 | \r |
1265 | //\r |
1266 | // Locate the USB bus protocol, if it is found, USB bus\r |
1267 | // is already started on this controller.\r |
1268 | //\r |
1269 | Status = gBS->OpenProtocol (\r |
1270 | Controller,\r |
1271 | &mUsbBusProtocolGuid,\r |
1272 | (VOID **) &UsbBusId,\r |
1273 | This->DriverBindingHandle,\r |
1274 | Controller,\r |
1275 | EFI_OPEN_PROTOCOL_GET_PROTOCOL\r |
1276 | );\r |
1277 | \r |
e237e7ae |
1278 | if (EFI_ERROR (Status)) {\r |
ecb575d9 |
1279 | //\r |
d17371e8 |
1280 | // If first start, build the bus execute environment and install bus protocol\r |
ecb575d9 |
1281 | //\r |
1282 | Status = UsbBusBuildProtocol (This, Controller, RemainingDevicePath);\r |
1283 | if (EFI_ERROR (Status)) {\r |
1284 | return Status;\r |
1285 | }\r |
1286 | //\r |
1287 | // Try get the Usb Bus protocol interface again\r |
1288 | //\r |
1289 | Status = gBS->OpenProtocol (\r |
1290 | Controller,\r |
1291 | &mUsbBusProtocolGuid,\r |
1292 | (VOID **) &UsbBusId,\r |
1293 | This->DriverBindingHandle,\r |
1294 | Controller,\r |
1295 | EFI_OPEN_PROTOCOL_GET_PROTOCOL\r |
1296 | );\r |
1297 | ASSERT (!EFI_ERROR (Status));\r |
1298 | } else {\r |
1299 | //\r |
1300 | // USB Bus driver need to control the recursive connect policy of the bus, only those wanted\r |
1301 | // usb child device will be recursively connected.\r |
1302 | // The RemainingDevicePath indicate the child usb device which user want to fully recursively connecte this time.\r |
1303 | // All wanted usb child devices will be remembered by the usb bus driver itself.\r |
1304 | // If RemainingDevicePath == NULL, all the usb child devices in the usb bus are wanted devices.\r |
1305 | //\r |
1306 | // Save the passed in RemainingDevicePath this time\r |
1307 | //\r |
af4a6385 |
1308 | if (RemainingDevicePath != NULL) {\r |
1309 | if (IsDevicePathEnd (RemainingDevicePath)) {\r |
1310 | //\r |
1311 | // If RemainingDevicePath is the End of Device Path Node,\r |
1312 | // skip enumerate any device and return EFI_SUCESSS\r |
1313 | // \r |
1314 | return EFI_SUCCESS;\r |
1315 | }\r |
1316 | }\r |
1317 | \r |
ecb575d9 |
1318 | Status = UsbBusAddWantedUsbIoDP (UsbBusId, RemainingDevicePath);\r |
1319 | ASSERT (!EFI_ERROR (Status));\r |
1320 | //\r |
1321 | // Ensure all wanted child usb devices are fully recursively connected\r |
1322 | //\r |
1323 | Status = UsbBusRecursivelyConnectWantedUsbIo (UsbBusId);\r |
1324 | ASSERT (!EFI_ERROR (Status));\r |
e237e7ae |
1325 | }\r |
1326 | \r |
e237e7ae |
1327 | \r |
e237e7ae |
1328 | return EFI_SUCCESS;\r |
e237e7ae |
1329 | }\r |
1330 | \r |
1331 | \r |
1332 | /**\r |
8616fc4c |
1333 | Stop handle the controller by this USB bus driver.\r |
e237e7ae |
1334 | \r |
8616fc4c |
1335 | @param This The USB bus driver binding protocol.\r |
1336 | @param Controller The controller to release.\r |
e237e7ae |
1337 | @param NumberOfChildren The child of USB bus that opened controller\r |
8616fc4c |
1338 | BY_CHILD.\r |
1339 | @param ChildHandleBuffer The array of child handle.\r |
e237e7ae |
1340 | \r |
8616fc4c |
1341 | @retval EFI_SUCCESS The controller or children are stopped.\r |
1342 | @retval EFI_DEVICE_ERROR Failed to stop the driver.\r |
e237e7ae |
1343 | \r |
1344 | **/\r |
1345 | EFI_STATUS\r |
1346 | EFIAPI\r |
1347 | UsbBusControllerDriverStop (\r |
1348 | IN EFI_DRIVER_BINDING_PROTOCOL *This,\r |
1349 | IN EFI_HANDLE Controller,\r |
1350 | IN UINTN NumberOfChildren,\r |
1351 | IN EFI_HANDLE *ChildHandleBuffer\r |
1352 | )\r |
1353 | {\r |
1354 | USB_BUS *Bus;\r |
1355 | USB_DEVICE *RootHub;\r |
1356 | USB_DEVICE *UsbDev;\r |
1357 | USB_INTERFACE *RootIf;\r |
1358 | USB_INTERFACE *UsbIf;\r |
1359 | EFI_USB_BUS_PROTOCOL *BusId;\r |
1360 | EFI_USB_IO_PROTOCOL *UsbIo;\r |
1361 | EFI_TPL OldTpl;\r |
1362 | UINTN Index;\r |
1363 | EFI_STATUS Status;\r |
1364 | \r |
1365 | Status = EFI_SUCCESS;\r |
1366 | \r |
1367 | if (NumberOfChildren > 0) {\r |
ecb575d9 |
1368 | //\r |
1369 | // BugBug: Raise TPL to callback level instead of USB_BUS_TPL to avoid TPL conflict\r |
1370 | //\r |
1371 | OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r |
e237e7ae |
1372 | \r |
1373 | for (Index = 0; Index < NumberOfChildren; Index++) {\r |
1374 | Status = gBS->OpenProtocol (\r |
1375 | ChildHandleBuffer[Index],\r |
1376 | &gEfiUsbIoProtocolGuid,\r |
1377 | (VOID **) &UsbIo,\r |
1378 | This->DriverBindingHandle,\r |
1379 | Controller,\r |
1380 | EFI_OPEN_PROTOCOL_GET_PROTOCOL\r |
1381 | );\r |
1382 | \r |
1383 | if (EFI_ERROR (Status)) {\r |
1384 | //\r |
1385 | // It is possible that the child has already been released:\r |
1386 | // 1. For combo device, free one device will release others.\r |
1387 | // 2. If a hub is released, all devices on its down facing\r |
1388 | // ports are released also.\r |
1389 | //\r |
1390 | continue;\r |
1391 | }\r |
1392 | \r |
1393 | UsbIf = USB_INTERFACE_FROM_USBIO (UsbIo);\r |
1394 | UsbDev = UsbIf->Device;\r |
1395 | \r |
1396 | UsbRemoveDevice (UsbDev);\r |
1397 | }\r |
1398 | \r |
1399 | gBS->RestoreTPL (OldTpl);\r |
1400 | return EFI_SUCCESS;\r |
1401 | }\r |
1402 | \r |
0e549d5b |
1403 | DEBUG (( EFI_D_INFO, "UsbBusStop: usb bus stopped on %p\n", Controller));\r |
e237e7ae |
1404 | \r |
1405 | //\r |
1406 | // Locate USB_BUS for the current host controller\r |
1407 | //\r |
1408 | Status = gBS->OpenProtocol (\r |
1409 | Controller,\r |
1410 | &mUsbBusProtocolGuid,\r |
1411 | (VOID **) &BusId,\r |
1412 | This->DriverBindingHandle,\r |
1413 | Controller,\r |
1414 | EFI_OPEN_PROTOCOL_GET_PROTOCOL\r |
1415 | );\r |
1416 | \r |
1417 | if (EFI_ERROR (Status)) {\r |
1418 | return Status;\r |
1419 | }\r |
1420 | \r |
1421 | Bus = USB_BUS_FROM_THIS (BusId);\r |
1422 | \r |
1423 | //\r |
1424 | // Stop the root hub, then free all the devices\r |
1425 | //\r |
ecb575d9 |
1426 | // BugBug: Raise TPL to callback level instead of USB_BUS_TPL to avoid TPL conflict\r |
1427 | //\r |
1428 | OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r |
e237e7ae |
1429 | UsbHcSetState (Bus, EfiUsbHcStateHalt);\r |
1430 | \r |
1431 | RootHub = Bus->Devices[0];\r |
1432 | RootIf = RootHub->Interfaces[0];\r |
1433 | \r |
1434 | mUsbRootHubApi.Release (RootIf);\r |
1435 | \r |
1436 | for (Index = 1; Index < USB_MAX_DEVICES; Index++) {\r |
1437 | if (Bus->Devices[Index] != NULL) {\r |
1438 | UsbRemoveDevice (Bus->Devices[Index]);\r |
1439 | }\r |
1440 | }\r |
1441 | \r |
1442 | gBS->RestoreTPL (OldTpl);\r |
1443 | \r |
1444 | gBS->FreePool (RootIf);\r |
1445 | gBS->FreePool (RootHub);\r |
ecb575d9 |
1446 | Status = UsbBusFreeUsbDPList (&Bus->WantedUsbIoDPList);\r |
1447 | ASSERT (!EFI_ERROR (Status));\r |
e237e7ae |
1448 | \r |
1449 | //\r |
1450 | // Uninstall the bus identifier and close USB_HC/USB2_HC protocols\r |
1451 | //\r |
1452 | gBS->UninstallProtocolInterface (Controller, &mUsbBusProtocolGuid, &Bus->BusId);\r |
1453 | \r |
1454 | if (Bus->Usb2Hc != NULL) {\r |
1455 | gBS->CloseProtocol (\r |
1456 | Controller,\r |
1457 | &gEfiUsb2HcProtocolGuid,\r |
1458 | This->DriverBindingHandle,\r |
1459 | Controller\r |
1460 | );\r |
1461 | }\r |
1462 | \r |
1463 | if (Bus->UsbHc != NULL) {\r |
1464 | gBS->CloseProtocol (\r |
1465 | Controller,\r |
1466 | &gEfiUsbHcProtocolGuid,\r |
1467 | This->DriverBindingHandle,\r |
1468 | Controller\r |
1469 | );\r |
1470 | }\r |
1471 | \r |
1472 | gBS->CloseProtocol (\r |
1473 | Controller,\r |
1474 | &gEfiDevicePathProtocolGuid,\r |
1475 | This->DriverBindingHandle,\r |
1476 | Controller\r |
1477 | );\r |
1478 | \r |
1479 | gBS->FreePool (Bus);\r |
1480 | \r |
1481 | return Status;\r |
1482 | }\r |