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