]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c
Fixed potential issues to release resources when error occurs.
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / EhciDxe / Ehci.c
... / ...
CommitLineData
1/** @file\r
2\r
3Copyright (c) 2006 - 2007, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13\r
14 Ehci.c\r
15\r
16Abstract:\r
17\r
18\r
19Revision History\r
20\r
21**/\r
22\r
23\r
24#include "Ehci.h"\r
25\r
26//\r
27// Two arrays used to translate the EHCI port state (change)\r
28// to the UEFI protocol's port state (change).\r
29//\r
30USB_PORT_STATE_MAP mUsbPortStateMap[] = {\r
31 {PORTSC_CONN, USB_PORT_STAT_CONNECTION},\r
32 {PORTSC_ENABLED, USB_PORT_STAT_ENABLE},\r
33 {PORTSC_SUSPEND, USB_PORT_STAT_SUSPEND},\r
34 {PORTSC_OVERCUR, USB_PORT_STAT_OVERCURRENT},\r
35 {PORTSC_RESET, USB_PORT_STAT_RESET},\r
36 {PORTSC_POWER, USB_PORT_STAT_POWER},\r
37 {PORTSC_OWNER, USB_PORT_STAT_OWNER}\r
38};\r
39\r
40USB_PORT_STATE_MAP mUsbPortChangeMap[] = {\r
41 {PORTSC_CONN_CHANGE, USB_PORT_STAT_C_CONNECTION},\r
42 {PORTSC_ENABLE_CHANGE, USB_PORT_STAT_C_ENABLE},\r
43 {PORTSC_OVERCUR_CHANGE, USB_PORT_STAT_C_OVERCURRENT}\r
44};\r
45\r
46\r
47/**\r
48 Retrieves the capablility of root hub ports.\r
49\r
50 @param This This EFI_USB_HC_PROTOCOL instance.\r
51 @param MaxSpeed Max speed supported by the controller\r
52 @param PortNumber Number of the root hub ports.\r
53 @param Is64BitCapable Whether the controller supports 64-bit memory\r
54 addressing.\r
55\r
56 @return EFI_SUCCESS : host controller capability were retrieved successfully.\r
57 @return EFI_INVALID_PARAMETER : Either of the three capability pointer is NULL\r
58\r
59**/\r
60STATIC\r
61EFI_STATUS\r
62EFIAPI\r
63EhcGetCapability (\r
64 IN EFI_USB2_HC_PROTOCOL *This,\r
65 OUT UINT8 *MaxSpeed,\r
66 OUT UINT8 *PortNumber,\r
67 OUT UINT8 *Is64BitCapable\r
68 )\r
69{\r
70 USB2_HC_DEV *Ehc;\r
71 EFI_TPL OldTpl;\r
72\r
73 if ((MaxSpeed == NULL) || (PortNumber == NULL) || (Is64BitCapable == NULL)) {\r
74 return EFI_INVALID_PARAMETER;\r
75 }\r
76\r
77 OldTpl = gBS->RaiseTPL (EHC_TPL);\r
78 Ehc = EHC_FROM_THIS (This);\r
79\r
80 *MaxSpeed = EFI_USB_SPEED_HIGH;\r
81 *PortNumber = (UINT8) (Ehc->HcStructParams & HCSP_NPORTS);\r
82 *Is64BitCapable = (UINT8) (Ehc->HcCapParams & HCCP_64BIT);\r
83\r
84 EHC_DEBUG (("EhcGetCapability: %d ports, 64 bit %d\n", *PortNumber, *Is64BitCapable));\r
85\r
86 gBS->RestoreTPL (OldTpl);\r
87 return EFI_SUCCESS;\r
88}\r
89\r
90\r
91/**\r
92 Provides software reset for the USB host controller.\r
93\r
94 @param This This EFI_USB2_HC_PROTOCOL instance.\r
95 @param Attributes A bit mask of the reset operation to perform.\r
96\r
97 @return EFI_SUCCESS : The reset operation succeeded.\r
98 @return EFI_INVALID_PARAMETER : Attributes is not valid.\r
99 @return EFI_UNSUPPOURTED : The type of reset specified by Attributes is\r
100 @return not currently supported by the host controller.\r
101 @return EFI_DEVICE_ERROR : Host controller isn't halted to reset.\r
102\r
103**/\r
104STATIC\r
105EFI_STATUS\r
106EFIAPI\r
107EhcReset (\r
108 IN EFI_USB2_HC_PROTOCOL *This,\r
109 IN UINT16 Attributes\r
110 )\r
111{\r
112 USB2_HC_DEV *Ehc;\r
113 EFI_TPL OldTpl;\r
114 EFI_STATUS Status;\r
115\r
116 OldTpl = gBS->RaiseTPL (EHC_TPL);\r
117 Ehc = EHC_FROM_THIS (This);\r
118\r
119 switch (Attributes) {\r
120 case EFI_USB_HC_RESET_GLOBAL:\r
121 //\r
122 // Flow through, same behavior as Host Controller Reset\r
123 //\r
124 case EFI_USB_HC_RESET_HOST_CONTROLLER:\r
125 //\r
126 // Host Controller must be Halt when Reset it\r
127 //\r
128 if (!EhcIsHalt (Ehc)) {\r
129 Status = EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);\r
130\r
131 if (EFI_ERROR (Status)) {\r
132 Status = EFI_DEVICE_ERROR;\r
133 goto ON_EXIT;\r
134 }\r
135 }\r
136\r
137 //\r
138 // Clean up the asynchronous transfers, currently only\r
139 // interrupt supports asynchronous operation.\r
140 //\r
141 EhciDelAllAsyncIntTransfers (Ehc);\r
142 EhcAckAllInterrupt (Ehc);\r
143 EhcFreeSched (Ehc);\r
144\r
145 Status = EhcResetHC (Ehc, EHC_RESET_TIMEOUT);\r
146\r
147 if (EFI_ERROR (Status)) {\r
148 goto ON_EXIT;\r
149 }\r
150\r
151 Status = EhcInitHC (Ehc);\r
152 break;\r
153\r
154 case EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG:\r
155 case EFI_USB_HC_RESET_HOST_WITH_DEBUG:\r
156 Status = EFI_UNSUPPORTED;\r
157 break;\r
158\r
159 default:\r
160 Status = EFI_INVALID_PARAMETER;\r
161 }\r
162\r
163ON_EXIT:\r
164 EHC_DEBUG (("EhcReset: exit status %r\n", Status));\r
165 gBS->RestoreTPL (OldTpl);\r
166 return Status;\r
167}\r
168\r
169\r
170/**\r
171 Retrieve the current state of the USB host controller.\r
172\r
173 @param This This EFI_USB2_HC_PROTOCOL instance.\r
174 @param State Variable to return the current host controller\r
175 state.\r
176\r
177 @return EFI_SUCCESS : Host controller state was returned in State.\r
178 @return EFI_INVALID_PARAMETER : State is NULL.\r
179 @return EFI_DEVICE_ERROR : An error was encountered while attempting to\r
180 @return retrieve the host controller's current state.\r
181\r
182**/\r
183STATIC\r
184EFI_STATUS\r
185EFIAPI\r
186EhcGetState (\r
187 IN CONST EFI_USB2_HC_PROTOCOL *This,\r
188 OUT EFI_USB_HC_STATE *State\r
189 )\r
190{\r
191 EFI_TPL OldTpl;\r
192 USB2_HC_DEV *Ehc;\r
193\r
194 if (State == NULL) {\r
195 return EFI_INVALID_PARAMETER;\r
196 }\r
197\r
198 OldTpl = gBS->RaiseTPL (EHC_TPL);\r
199 Ehc = EHC_FROM_THIS (This);\r
200\r
201 if (EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {\r
202 *State = EfiUsbHcStateHalt;\r
203 } else {\r
204 *State = EfiUsbHcStateOperational;\r
205 }\r
206\r
207 gBS->RestoreTPL (OldTpl);\r
208\r
209 EHC_DEBUG (("EhcGetState: current state %d\n", *State));\r
210 return EFI_SUCCESS;\r
211}\r
212\r
213\r
214/**\r
215 Sets the USB host controller to a specific state.\r
216\r
217 @param This This EFI_USB2_HC_PROTOCOL instance.\r
218 @param State The state of the host controller that will be set.\r
219\r
220 @return EFI_SUCCESS : The USB host controller was successfully placed\r
221 @return in the state specified by State.\r
222 @return EFI_INVALID_PARAMETER : State is invalid.\r
223 @return EFI_DEVICE_ERROR : Failed to set the state due to device error.\r
224\r
225**/\r
226STATIC\r
227EFI_STATUS\r
228EFIAPI\r
229EhcSetState (\r
230 IN EFI_USB2_HC_PROTOCOL *This,\r
231 IN EFI_USB_HC_STATE State\r
232 )\r
233{\r
234 USB2_HC_DEV *Ehc;\r
235 EFI_TPL OldTpl;\r
236 EFI_STATUS Status;\r
237 EFI_USB_HC_STATE CurState;\r
238\r
239 Status = EhcGetState (This, &CurState);\r
240\r
241 if (EFI_ERROR (Status)) {\r
242 return EFI_DEVICE_ERROR;\r
243 }\r
244\r
245 if (CurState == State) {\r
246 return EFI_SUCCESS;\r
247 }\r
248\r
249 OldTpl = gBS->RaiseTPL (EHC_TPL);\r
250 Ehc = EHC_FROM_THIS (This);\r
251\r
252 switch (State) {\r
253 case EfiUsbHcStateHalt:\r
254 Status = EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);\r
255 break;\r
256\r
257 case EfiUsbHcStateOperational:\r
258 if (EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_SYS_ERROR)) {\r
259 Status = EFI_DEVICE_ERROR;\r
260 break;\r
261 }\r
262\r
263 //\r
264 // Software must not write a one to this field unless the host controller\r
265 // is in the Halted state. Doing so will yield undefined results.\r
266 // refers to Spec[EHCI1.0-2.3.1]\r
267 //\r
268 if (!EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {\r
269 Status = EFI_DEVICE_ERROR;\r
270 break;\r
271 }\r
272\r
273 Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT);\r
274 break;\r
275\r
276 case EfiUsbHcStateSuspend:\r
277 Status = EFI_UNSUPPORTED;\r
278 break;\r
279\r
280 default:\r
281 Status = EFI_INVALID_PARAMETER;\r
282 }\r
283\r
284 EHC_DEBUG (("EhcSetState: exit status %r\n", Status));\r
285 gBS->RestoreTPL (OldTpl);\r
286 return Status;\r
287}\r
288\r
289\r
290/**\r
291 Retrieves the current status of a USB root hub port.\r
292\r
293 @param This This EFI_USB2_HC_PROTOCOL instance.\r
294 @param PortNumber The root hub port to retrieve the state from. This\r
295 value is zero-based.\r
296 @param PortStatus Variable to receive the port state\r
297\r
298 @return EFI_SUCCESS : The status of the USB root hub port specified\r
299 @return by PortNumber was returned in PortStatus.\r
300 @return EFI_INVALID_PARAMETER : PortNumber is invalid.\r
301 @return EFI_DEVICE_ERROR : Can't read register\r
302\r
303**/\r
304STATIC\r
305EFI_STATUS\r
306EFIAPI\r
307EhcGetRootHubPortStatus (\r
308 IN CONST EFI_USB2_HC_PROTOCOL *This,\r
309 IN CONST UINT8 PortNumber,\r
310 OUT EFI_USB_PORT_STATUS *PortStatus\r
311 )\r
312{\r
313 USB2_HC_DEV *Ehc;\r
314 EFI_TPL OldTpl;\r
315 UINT32 Offset;\r
316 UINT32 State;\r
317 UINT32 TotalPort;\r
318 UINTN Index;\r
319 UINTN MapSize;\r
320 EFI_STATUS Status;\r
321\r
322 if (PortStatus == NULL) {\r
323 return EFI_INVALID_PARAMETER;\r
324 }\r
325\r
326 OldTpl = gBS->RaiseTPL (EHC_TPL);\r
327\r
328 Ehc = EHC_FROM_THIS (This);\r
329 Status = EFI_SUCCESS;\r
330\r
331 TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);\r
332\r
333 if (PortNumber >= TotalPort) {\r
334 Status = EFI_INVALID_PARAMETER;\r
335 goto ON_EXIT;\r
336 }\r
337\r
338 Offset = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber));\r
339 PortStatus->PortStatus = 0;\r
340 PortStatus->PortChangeStatus = 0;\r
341\r
342 State = EhcReadOpReg (Ehc, Offset);\r
343\r
344 //\r
345 // Identify device speed. If in K state, it is low speed.\r
346 // If the port is enabled after reset, the device is of\r
347 // high speed. The USB bus driver should retrieve the actual\r
348 // port speed after reset.\r
349 //\r
350 if (EHC_BIT_IS_SET (State, PORTSC_LINESTATE_K)) {\r
351 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
352\r
353 } else if (EHC_BIT_IS_SET (State, PORTSC_ENABLED)) {\r
354 PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;\r
355 }\r
356\r
357 //\r
358 // Convert the EHCI port/port change state to UEFI status\r
359 //\r
360 MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);\r
361\r
362 for (Index = 0; Index < MapSize; Index++) {\r
363 if (EHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {\r
364 PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);\r
365 }\r
366 }\r
367\r
368 MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);\r
369\r
370 for (Index = 0; Index < MapSize; Index++) {\r
371 if (EHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {\r
372 PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);\r
373 }\r
374 }\r
375\r
376ON_EXIT:\r
377 gBS->RestoreTPL (OldTpl);\r
378 return Status;\r
379}\r
380\r
381\r
382/**\r
383 Sets a feature for the specified root hub port.\r
384\r
385 @param This This EFI_USB2_HC_PROTOCOL instance.\r
386 @param PortNumber Root hub port to set.\r
387 @param PortFeature Feature to set\r
388\r
389 @return EFI_SUCCESS : The feature specified by PortFeature was set\r
390 @return EFI_INVALID_PARAMETER : PortNumber is invalid or PortFeature is invalid.\r
391 @return EFI_DEVICE_ERROR : Can't read register\r
392\r
393**/\r
394STATIC\r
395EFI_STATUS\r
396EFIAPI\r
397EhcSetRootHubPortFeature (\r
398 IN EFI_USB2_HC_PROTOCOL *This,\r
399 IN UINT8 PortNumber,\r
400 IN EFI_USB_PORT_FEATURE PortFeature\r
401 )\r
402{\r
403 USB2_HC_DEV *Ehc;\r
404 EFI_TPL OldTpl;\r
405 UINT32 Offset;\r
406 UINT32 State;\r
407 UINT32 TotalPort;\r
408 EFI_STATUS Status;\r
409\r
410 OldTpl = gBS->RaiseTPL (EHC_TPL);\r
411 Ehc = EHC_FROM_THIS (This);\r
412 Status = EFI_SUCCESS;\r
413\r
414 TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);\r
415\r
416 if (PortNumber >= TotalPort) {\r
417 Status = EFI_INVALID_PARAMETER;\r
418 goto ON_EXIT;\r
419 }\r
420\r
421 Offset = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber));\r
422 State = EhcReadOpReg (Ehc, Offset);\r
423\r
424 //\r
425 // Mask off the port status change bits, these bits are\r
426 // write clean bit\r
427 //\r
428 State &= ~PORTSC_CHANGE_MASK;\r
429\r
430 switch (PortFeature) {\r
431 case EfiUsbPortEnable:\r
432 //\r
433 // Sofeware can't set this bit, Port can only be enable by\r
434 // EHCI as a part of the reset and enable\r
435 //\r
436 State |= PORTSC_ENABLED;\r
437 EhcWriteOpReg (Ehc, Offset, State);\r
438 break;\r
439\r
440 case EfiUsbPortSuspend:\r
441 State |= PORTSC_SUSPEND;\r
442 EhcWriteOpReg (Ehc, Offset, State);\r
443 break;\r
444\r
445 case EfiUsbPortReset:\r
446 //\r
447 // Make sure Host Controller not halt before reset it\r
448 //\r
449 if (EhcIsHalt (Ehc)) {\r
450 Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT);\r
451\r
452 if (EFI_ERROR (Status)) {\r
453 EHC_DEBUG (("EhcSetRootHubPortFeature :failed to start HC - %r\n", Status));\r
454 break;\r
455 }\r
456 }\r
457\r
458 //\r
459 // Set one to PortReset bit must also set zero to PortEnable bit\r
460 //\r
461 State |= PORTSC_RESET;\r
462 State &= ~PORTSC_ENABLED;\r
463 EhcWriteOpReg (Ehc, Offset, State);\r
464 break;\r
465\r
466 case EfiUsbPortPower:\r
467 //\r
468 // Not supported, ignore the operation\r
469 //\r
470 Status = EFI_SUCCESS;\r
471 break;\r
472\r
473 case EfiUsbPortOwner:\r
474 State |= PORTSC_OWNER;\r
475 EhcWriteOpReg (Ehc, Offset, State);\r
476 break;\r
477\r
478 default:\r
479 Status = EFI_INVALID_PARAMETER;\r
480 }\r
481\r
482ON_EXIT:\r
483 EHC_DEBUG (("EhcSetRootHubPortFeature: exit status %r\n", Status));\r
484\r
485 gBS->RestoreTPL (OldTpl);\r
486 return Status;\r
487}\r
488\r
489\r
490/**\r
491 Clears a feature for the specified root hub port.\r
492\r
493 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
494 @param PortNumber Specifies the root hub port whose feature is\r
495 requested to be cleared.\r
496 @param PortFeature Indicates the feature selector associated with the\r
497 feature clear request.\r
498\r
499 @return EFI_SUCCESS : The feature specified by PortFeature was cleared\r
500 @return for the USB root hub port specified by PortNumber.\r
501 @return EFI_INVALID_PARAMETER : PortNumber is invalid or PortFeature is invalid.\r
502 @return EFI_DEVICE_ERROR : Can't read register\r
503\r
504**/\r
505STATIC\r
506EFI_STATUS\r
507EFIAPI\r
508EhcClearRootHubPortFeature (\r
509 IN EFI_USB2_HC_PROTOCOL *This,\r
510 IN UINT8 PortNumber,\r
511 IN EFI_USB_PORT_FEATURE PortFeature\r
512 )\r
513{\r
514 USB2_HC_DEV *Ehc;\r
515 EFI_TPL OldTpl;\r
516 UINT32 Offset;\r
517 UINT32 State;\r
518 UINT32 TotalPort;\r
519 EFI_STATUS Status;\r
520\r
521 OldTpl = gBS->RaiseTPL (EHC_TPL);\r
522 Ehc = EHC_FROM_THIS (This);\r
523 Status = EFI_SUCCESS;\r
524\r
525 TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);\r
526\r
527 if (PortNumber >= TotalPort) {\r
528 Status = EFI_INVALID_PARAMETER;\r
529 goto ON_EXIT;\r
530 }\r
531\r
532 Offset = EHC_PORT_STAT_OFFSET + (4 * PortNumber);\r
533 State = EhcReadOpReg (Ehc, Offset);\r
534 State &= ~PORTSC_CHANGE_MASK;\r
535\r
536 switch (PortFeature) {\r
537 case EfiUsbPortEnable:\r
538 //\r
539 // Clear PORT_ENABLE feature means disable port.\r
540 //\r
541 State &= ~PORTSC_ENABLED;\r
542 EhcWriteOpReg (Ehc, Offset, State);\r
543 break;\r
544\r
545 case EfiUsbPortSuspend:\r
546 //\r
547 // A write of zero to this bit is ignored by the host\r
548 // controller. The host controller will unconditionally\r
549 // set this bit to a zero when:\r
550 // 1. software sets the Forct Port Resume bit to a zero from a one.\r
551 // 2. software sets the Port Reset bit to a one frome a zero.\r
552 //\r
553 State &= ~PORSTSC_RESUME;\r
554 EhcWriteOpReg (Ehc, Offset, State);\r
555 break;\r
556\r
557 case EfiUsbPortReset:\r
558 //\r
559 // Clear PORT_RESET means clear the reset signal.\r
560 //\r
561 State &= ~PORTSC_RESET;\r
562 EhcWriteOpReg (Ehc, Offset, State);\r
563 break;\r
564\r
565 case EfiUsbPortOwner:\r
566 //\r
567 // Clear port owner means this port owned by EHC\r
568 //\r
569 State &= ~PORTSC_OWNER;\r
570 EhcWriteOpReg (Ehc, Offset, State);\r
571 break;\r
572\r
573 case EfiUsbPortConnectChange:\r
574 //\r
575 // Clear connect status change\r
576 //\r
577 State |= PORTSC_CONN_CHANGE;\r
578 EhcWriteOpReg (Ehc, Offset, State);\r
579 break;\r
580\r
581 case EfiUsbPortEnableChange:\r
582 //\r
583 // Clear enable status change\r
584 //\r
585 State |= PORTSC_ENABLE_CHANGE;\r
586 EhcWriteOpReg (Ehc, Offset, State);\r
587 break;\r
588\r
589 case EfiUsbPortOverCurrentChange:\r
590 //\r
591 // Clear PortOverCurrent change\r
592 //\r
593 State |= PORTSC_OVERCUR_CHANGE;\r
594 EhcWriteOpReg (Ehc, Offset, State);\r
595 break;\r
596\r
597 case EfiUsbPortPower:\r
598 case EfiUsbPortSuspendChange:\r
599 case EfiUsbPortResetChange:\r
600 //\r
601 // Not supported or not related operation\r
602 //\r
603 break;\r
604\r
605 default:\r
606 Status = EFI_INVALID_PARAMETER;\r
607 break;\r
608 }\r
609\r
610ON_EXIT:\r
611 EHC_DEBUG (("EhcClearRootHubPortFeature: exit status %r\n", Status));\r
612 gBS->RestoreTPL (OldTpl);\r
613 return Status;\r
614}\r
615\r
616\r
617/**\r
618 Submits control transfer to a target USB device.\r
619\r
620 @param This This EFI_USB2_HC_PROTOCOL instance.\r
621 @param DeviceAddress The target device address\r
622 @param DeviceSpeed Target device speed.\r
623 @param MaximumPacketLength Maximum packet size the default control transfer\r
624 endpoint is capable of sending or receiving.\r
625 @param Request USB device request to send\r
626 @param TransferDirection Specifies the data direction for the data stage\r
627 @param Data Data buffer to be transmitted or received from USB\r
628 device.\r
629 @param DataLength The size (in bytes) of the data buffer\r
630 @param TimeOut Indicates the maximum timeout, in millisecond,\r
631 @param Translator Transaction translator to be used by this device.\r
632 @param TransferResult Return the result of this control transfer.\r
633\r
634 @return EFI_SUCCESS : Transfer was completed successfully.\r
635 @return EFI_OUT_OF_RESOURCES : The transfer failed due to lack of resources.\r
636 @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
637 @return EFI_TIMEOUT : Transfer failed due to timeout.\r
638 @return EFI_DEVICE_ERROR : Transfer failed due to host controller or device error.\r
639\r
640**/\r
641STATIC\r
642EFI_STATUS\r
643EFIAPI\r
644EhcControlTransfer (\r
645 IN EFI_USB2_HC_PROTOCOL *This,\r
646 IN UINT8 DeviceAddress,\r
647 IN UINT8 DeviceSpeed,\r
648 IN UINTN MaximumPacketLength,\r
649 IN EFI_USB_DEVICE_REQUEST *Request,\r
650 IN EFI_USB_DATA_DIRECTION TransferDirection,\r
651 IN OUT VOID *Data,\r
652 IN OUT UINTN *DataLength,\r
653 IN UINTN TimeOut,\r
654 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
655 OUT UINT32 *TransferResult\r
656 )\r
657{\r
658 USB2_HC_DEV *Ehc;\r
659 URB *Urb;\r
660 EFI_TPL OldTpl;\r
661 UINT8 Endpoint;\r
662 EFI_STATUS Status;\r
663\r
664 //\r
665 // Validate parameters\r
666 //\r
667 if ((Request == NULL) || (TransferResult == NULL)) {\r
668 return EFI_INVALID_PARAMETER;\r
669 }\r
670\r
671 if ((TransferDirection != EfiUsbDataIn) &&\r
672 (TransferDirection != EfiUsbDataOut) &&\r
673 (TransferDirection != EfiUsbNoData)) {\r
674 return EFI_INVALID_PARAMETER;\r
675 }\r
676\r
677 if ((TransferDirection == EfiUsbNoData) &&\r
678 ((Data != NULL) || (*DataLength != 0))) {\r
679 return EFI_INVALID_PARAMETER;\r
680 }\r
681\r
682 if ((TransferDirection != EfiUsbNoData) &&\r
683 ((Data == NULL) || (*DataLength == 0))) {\r
684 return EFI_INVALID_PARAMETER;\r
685 }\r
686\r
687 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&\r
688 (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {\r
689 return EFI_INVALID_PARAMETER;\r
690 }\r
691\r
692 if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {\r
693 return EFI_INVALID_PARAMETER;\r
694 }\r
695\r
696 OldTpl = gBS->RaiseTPL (EHC_TPL);\r
697 Ehc = EHC_FROM_THIS (This);\r
698\r
699 Status = EFI_DEVICE_ERROR;\r
700 *TransferResult = EFI_USB_ERR_SYSTEM;\r
701\r
702 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
703 EHC_ERROR (("EhcControlTransfer: HC halted at entrance\n"));\r
704\r
705 EhcAckAllInterrupt (Ehc);\r
706 goto ON_EXIT;\r
707 }\r
708\r
709 EhcAckAllInterrupt (Ehc);\r
710\r
711 //\r
712 // Create a new URB, insert it into the asynchronous\r
713 // schedule list, then poll the execution status.\r
714 //\r
715 //\r
716 // Encode the direction in address, although default control\r
717 // endpoint is bidirectional. EhcCreateUrb expects this\r
718 // combination of Ep addr and its direction.\r
719 //\r
720 Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));\r
721 Urb = EhcCreateUrb (\r
722 Ehc,\r
723 DeviceAddress,\r
724 Endpoint,\r
725 DeviceSpeed,\r
726 0,\r
727 MaximumPacketLength,\r
728 Translator,\r
729 EHC_CTRL_TRANSFER,\r
730 Request,\r
731 Data,\r
732 *DataLength,\r
733 NULL,\r
734 NULL,\r
735 1\r
736 );\r
737\r
738 if (Urb == NULL) {\r
739 EHC_ERROR (("EhcControlTransfer: failed to create URB"));\r
740\r
741 Status = EFI_OUT_OF_RESOURCES;\r
742 goto ON_EXIT;\r
743 }\r
744\r
745 EhcLinkQhToAsync (Ehc, Urb->Qh);\r
746 Status = EhcExecTransfer (Ehc, Urb, TimeOut);\r
747 EhcUnlinkQhFromAsync (Ehc, Urb->Qh);\r
748\r
749 //\r
750 // Get the status from URB. The result is updated in EhcCheckUrbResult\r
751 // which is called by EhcExecTransfer\r
752 //\r
753 *TransferResult = Urb->Result;\r
754 *DataLength = Urb->Completed;\r
755\r
756 if (*TransferResult == EFI_USB_NOERROR) {\r
757 Status = EFI_SUCCESS;\r
758 }\r
759\r
760 EhcAckAllInterrupt (Ehc);\r
761 EhcFreeUrb (Ehc, Urb);\r
762\r
763ON_EXIT:\r
764 Ehc->PciIo->Flush (Ehc->PciIo);\r
765 gBS->RestoreTPL (OldTpl);\r
766\r
767 if (EFI_ERROR (Status)) {\r
768 EHC_ERROR (("EhcControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
769 }\r
770\r
771 return Status;\r
772}\r
773\r
774\r
775/**\r
776 Submits bulk transfer to a bulk endpoint of a USB device.\r
777\r
778 @param This This EFI_USB2_HC_PROTOCOL instance.\r
779 @param DeviceAddress Target device address\r
780 @param EndPointAddress Endpoint number and its direction in bit 7. .\r
781 @param DeviceSpeed Device speed, Low speed device doesn't support bulk\r
782 transfer.\r
783 @param MaximumPacketLength Maximum packet size the endpoint is capable of\r
784 sending or receiving.\r
785 @param DataBuffersNumber Number of data buffers prepared for the transfer.\r
786 @param Data Array of pointers to the buffers of data to transmit\r
787 from or receive into.\r
788 @param DataLength The lenght of the data buffer\r
789 @param DataToggle On input, the initial data toggle for the transfer;\r
790 On output, it is updated to to next data toggle to\r
791 use of the subsequent bulk\r
792 transfer.\r
793 @param Translator A pointr to the transaction translator data.\r
794 @param TimeOut Indicates the maximum time, in millisecond, which\r
795 the transfer is allowed to complete.\r
796 @param TransferResult A pointer to the detailed result information of the\r
797 bulk transfer.\r
798\r
799 @return EFI_SUCCESS : The transfer was completed successfully.\r
800 @return EFI_OUT_OF_RESOURCES : The transfer failed due to lack of resource.\r
801 @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
802 @return EFI_TIMEOUT : The transfer failed due to timeout.\r
803 @return EFI_DEVICE_ERROR : The transfer failed due to host controller error.\r
804\r
805**/\r
806STATIC\r
807EFI_STATUS\r
808EFIAPI\r
809EhcBulkTransfer (\r
810 IN EFI_USB2_HC_PROTOCOL *This,\r
811 IN UINT8 DeviceAddress,\r
812 IN UINT8 EndPointAddress,\r
813 IN UINT8 DeviceSpeed,\r
814 IN UINTN MaximumPacketLength,\r
815 IN UINT8 DataBuffersNumber,\r
816 IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],\r
817 IN OUT UINTN *DataLength,\r
818 IN OUT UINT8 *DataToggle,\r
819 IN UINTN TimeOut,\r
820 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
821 OUT UINT32 *TransferResult\r
822 )\r
823{\r
824 USB2_HC_DEV *Ehc;\r
825 URB *Urb;\r
826 EFI_TPL OldTpl;\r
827 EFI_STATUS Status;\r
828\r
829 //\r
830 // Validate the parameters\r
831 //\r
832 if ((DataLength == NULL) || (*DataLength == 0) ||\r
833 (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {\r
834 return EFI_INVALID_PARAMETER;\r
835 }\r
836\r
837 if ((*DataToggle != 0) && (*DataToggle != 1)) {\r
838 return EFI_INVALID_PARAMETER;\r
839 }\r
840\r
841 if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||\r
842 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||\r
843 ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512))) {\r
844 return EFI_INVALID_PARAMETER;\r
845 }\r
846\r
847 OldTpl = gBS->RaiseTPL (EHC_TPL);\r
848 Ehc = EHC_FROM_THIS (This);\r
849\r
850 *TransferResult = EFI_USB_ERR_SYSTEM;\r
851 Status = EFI_DEVICE_ERROR;\r
852\r
853 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
854 EHC_ERROR (("EhcBulkTransfer: HC is halted\n"));\r
855\r
856 EhcAckAllInterrupt (Ehc);\r
857 goto ON_EXIT;\r
858 }\r
859\r
860 EhcAckAllInterrupt (Ehc);\r
861\r
862 //\r
863 // Create a new URB, insert it into the asynchronous\r
864 // schedule list, then poll the execution status.\r
865 //\r
866 Urb = EhcCreateUrb (\r
867 Ehc,\r
868 DeviceAddress,\r
869 EndPointAddress,\r
870 DeviceSpeed,\r
871 *DataToggle,\r
872 MaximumPacketLength,\r
873 Translator,\r
874 EHC_BULK_TRANSFER,\r
875 NULL,\r
876 Data[0],\r
877 *DataLength,\r
878 NULL,\r
879 NULL,\r
880 1\r
881 );\r
882\r
883 if (Urb == NULL) {\r
884 EHC_ERROR (("EhcBulkTransfer: failed to create URB\n"));\r
885\r
886 Status = EFI_OUT_OF_RESOURCES;\r
887 goto ON_EXIT;\r
888 }\r
889\r
890 EhcLinkQhToAsync (Ehc, Urb->Qh);\r
891 Status = EhcExecTransfer (Ehc, Urb, TimeOut);\r
892 EhcUnlinkQhFromAsync (Ehc, Urb->Qh);\r
893\r
894 *TransferResult = Urb->Result;\r
895 *DataLength = Urb->Completed;\r
896 *DataToggle = Urb->DataToggle;\r
897\r
898 if (*TransferResult == EFI_USB_NOERROR) {\r
899 Status = EFI_SUCCESS;\r
900 }\r
901\r
902 EhcAckAllInterrupt (Ehc);\r
903 EhcFreeUrb (Ehc, Urb);\r
904\r
905ON_EXIT:\r
906 Ehc->PciIo->Flush (Ehc->PciIo);\r
907 gBS->RestoreTPL (OldTpl);\r
908\r
909 if (EFI_ERROR (Status)) {\r
910 EHC_ERROR (("EhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
911 }\r
912\r
913 return Status;\r
914}\r
915\r
916\r
917/**\r
918 Submits an asynchronous interrupt transfer to an\r
919 interrupt endpoint of a USB device.\r
920\r
921 @param This This EFI_USB2_HC_PROTOCOL instance.\r
922 @param DeviceAddress Target device address\r
923 @param EndPointAddress Endpoint number and its direction encoded in bit 7\r
924 @param DeviceSpeed Indicates device speed.\r
925 @param MaximumPacketLength Maximum packet size the target endpoint is capable\r
926 @param IsNewTransfer If TRUE, to submit an new asynchronous interrupt\r
927 transfer If FALSE, to remove the specified\r
928 asynchronous interrupt\r
929 @param DataToggle On input, the initial data toggle to use; on output,\r
930 it is updated to indicate the next data toggle\r
931 @param PollingInterval The he interval, in milliseconds, that the transfer\r
932 is polled.\r
933 @param DataLength The length of data to receive at the rate specified\r
934 by PollingInterval.\r
935 @param Translator Transaction translator to use.\r
936 @param CallBackFunction Function to call at the rate specified by\r
937 PollingInterval\r
938 @param Context Context to CallBackFunction.\r
939\r
940 @return EFI_SUCCESS : The request has been successfully submitted or canceled.\r
941 @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
942 @return EFI_OUT_OF_RESOURCES : The request failed due to a lack of resources.\r
943 @return EFI_DEVICE_ERROR : The transfer failed due to host controller error.\r
944\r
945**/\r
946STATIC\r
947EFI_STATUS\r
948EFIAPI\r
949EhcAsyncInterruptTransfer (\r
950 IN EFI_USB2_HC_PROTOCOL * This,\r
951 IN UINT8 DeviceAddress,\r
952 IN UINT8 EndPointAddress,\r
953 IN UINT8 DeviceSpeed,\r
954 IN UINTN MaximumPacketLength,\r
955 IN BOOLEAN IsNewTransfer,\r
956 IN OUT UINT8 *DataToggle,\r
957 IN UINTN PollingInterval,\r
958 IN UINTN DataLength,\r
959 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR * Translator,\r
960 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,\r
961 IN VOID *Context OPTIONAL\r
962 )\r
963{\r
964 USB2_HC_DEV *Ehc;\r
965 URB *Urb;\r
966 EFI_TPL OldTpl;\r
967 EFI_STATUS Status;\r
968 UINT8 *Data;\r
969\r
970 //\r
971 // Validate parameters\r
972 //\r
973 if (!EHCI_IS_DATAIN (EndPointAddress)) {\r
974 return EFI_INVALID_PARAMETER;\r
975 }\r
976\r
977 if (IsNewTransfer) {\r
978 if (DataLength == 0) {\r
979 return EFI_INVALID_PARAMETER;\r
980 }\r
981\r
982 if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
983 return EFI_INVALID_PARAMETER;\r
984 }\r
985\r
986 if ((PollingInterval > 255) || (PollingInterval < 1)) {\r
987 return EFI_INVALID_PARAMETER;\r
988 }\r
989 }\r
990\r
991 OldTpl = gBS->RaiseTPL (EHC_TPL);\r
992 Ehc = EHC_FROM_THIS (This);\r
993\r
994 //\r
995 // Delete Async interrupt transfer request. DataToggle will return\r
996 // the next data toggle to use.\r
997 //\r
998 if (!IsNewTransfer) {\r
999 Status = EhciDelAsyncIntTransfer (Ehc, DeviceAddress, EndPointAddress, DataToggle);\r
1000\r
1001 EHC_DEBUG (("EhcAsyncInterruptTransfer: remove old transfer - %r\n", Status));\r
1002 goto ON_EXIT;\r
1003 }\r
1004\r
1005 Status = EFI_SUCCESS;\r
1006\r
1007 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
1008 EHC_ERROR (("EhcAsyncInterruptTransfer: HC is halt\n"));\r
1009 EhcAckAllInterrupt (Ehc);\r
1010\r
1011 Status = EFI_DEVICE_ERROR;\r
1012 goto ON_EXIT;\r
1013 }\r
1014\r
1015 EhcAckAllInterrupt (Ehc);\r
1016\r
1017 Data = AllocatePool (DataLength);\r
1018\r
1019 if (Data == NULL) {\r
1020 EHC_ERROR (("EhcAsyncInterruptTransfer: failed to allocate buffer\n"));\r
1021\r
1022 Status = EFI_OUT_OF_RESOURCES;\r
1023 goto ON_EXIT;\r
1024 }\r
1025\r
1026 Urb = EhcCreateUrb (\r
1027 Ehc,\r
1028 DeviceAddress,\r
1029 EndPointAddress,\r
1030 DeviceSpeed,\r
1031 *DataToggle,\r
1032 MaximumPacketLength,\r
1033 Translator,\r
1034 EHC_INT_TRANSFER_ASYNC,\r
1035 NULL,\r
1036 Data,\r
1037 DataLength,\r
1038 CallBackFunction,\r
1039 Context,\r
1040 PollingInterval\r
1041 );\r
1042\r
1043 if (Urb == NULL) {\r
1044 EHC_ERROR (("EhcAsyncInterruptTransfer: failed to create URB\n"));\r
1045\r
1046 gBS->FreePool (Data);\r
1047 Status = EFI_OUT_OF_RESOURCES;\r
1048 goto ON_EXIT;\r
1049 }\r
1050\r
1051 //\r
1052 // New asynchronous transfer must inserted to the head.\r
1053 // Check the comments in EhcMoniteAsyncRequests\r
1054 //\r
1055 EhcLinkQhToPeriod (Ehc, Urb->Qh);\r
1056 InsertHeadList (&Ehc->AsyncIntTransfers, &Urb->UrbList);\r
1057\r
1058ON_EXIT:\r
1059 Ehc->PciIo->Flush (Ehc->PciIo);\r
1060 gBS->RestoreTPL (OldTpl);\r
1061\r
1062 return Status;\r
1063}\r
1064\r
1065\r
1066/**\r
1067 Submits synchronous interrupt transfer to an interrupt endpoint\r
1068 of a USB device.\r
1069\r
1070 @param This This EFI_USB2_HC_PROTOCOL instance.\r
1071 @param DeviceAddress Target device address\r
1072 @param EndPointAddress Endpoint number and its direction encoded in bit 7\r
1073 @param DeviceSpeed Indicates device speed.\r
1074 @param MaximumPacketLength Maximum packet size the target endpoint is capable\r
1075 of sending or receiving.\r
1076 @param Data Buffer of data that will be transmitted to USB\r
1077 device or received from USB device.\r
1078 @param DataLength On input, the size, in bytes, of the data buffer; On\r
1079 output, the number of bytes transferred.\r
1080 @param DataToggle On input, the initial data toggle to use; on output,\r
1081 it is updated to indicate the next data toggle\r
1082 @param TimeOut Maximum time, in second, to complete\r
1083 @param Translator Transaction translator to use.\r
1084 @param TransferResult Variable to receive the transfer result\r
1085\r
1086 @return EFI_SUCCESS : The transfer was completed successfully.\r
1087 @return EFI_OUT_OF_RESOURCES : The transfer failed due to lack of resource.\r
1088 @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
1089 @return EFI_TIMEOUT : The transfer failed due to timeout.\r
1090 @return EFI_DEVICE_ERROR : The failed due to host controller or device error\r
1091\r
1092**/\r
1093STATIC\r
1094EFI_STATUS\r
1095EFIAPI\r
1096EhcSyncInterruptTransfer (\r
1097 IN EFI_USB2_HC_PROTOCOL *This,\r
1098 IN UINT8 DeviceAddress,\r
1099 IN UINT8 EndPointAddress,\r
1100 IN UINT8 DeviceSpeed,\r
1101 IN UINTN MaximumPacketLength,\r
1102 IN OUT VOID *Data,\r
1103 IN OUT UINTN *DataLength,\r
1104 IN OUT UINT8 *DataToggle,\r
1105 IN UINTN TimeOut,\r
1106 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
1107 OUT UINT32 *TransferResult\r
1108 )\r
1109{\r
1110 USB2_HC_DEV *Ehc;\r
1111 EFI_TPL OldTpl;\r
1112 URB *Urb;\r
1113 EFI_STATUS Status;\r
1114\r
1115 //\r
1116 // Validates parameters\r
1117 //\r
1118 if ((DataLength == NULL) || (*DataLength == 0) ||\r
1119 (Data == NULL) || (TransferResult == NULL)) {\r
1120 return EFI_INVALID_PARAMETER;\r
1121 }\r
1122\r
1123 if (!EHCI_IS_DATAIN (EndPointAddress)) {\r
1124 return EFI_INVALID_PARAMETER;\r
1125 }\r
1126\r
1127 if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
1128 return EFI_INVALID_PARAMETER;\r
1129 }\r
1130\r
1131 if (((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) ||\r
1132 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||\r
1133 ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 3072))) {\r
1134 return EFI_INVALID_PARAMETER;\r
1135 }\r
1136\r
1137 OldTpl = gBS->RaiseTPL (EHC_TPL);\r
1138 Ehc = EHC_FROM_THIS (This);\r
1139\r
1140 *TransferResult = EFI_USB_ERR_SYSTEM;\r
1141 Status = EFI_DEVICE_ERROR;\r
1142\r
1143 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
1144 EHC_ERROR (("EhcSyncInterruptTransfer: HC is halt\n"));\r
1145\r
1146 EhcAckAllInterrupt (Ehc);\r
1147 goto ON_EXIT;\r
1148 }\r
1149\r
1150 EhcAckAllInterrupt (Ehc);\r
1151\r
1152 Urb = EhcCreateUrb (\r
1153 Ehc,\r
1154 DeviceAddress,\r
1155 EndPointAddress,\r
1156 DeviceSpeed,\r
1157 *DataToggle,\r
1158 MaximumPacketLength,\r
1159 Translator,\r
1160 EHC_INT_TRANSFER_SYNC,\r
1161 NULL,\r
1162 Data,\r
1163 *DataLength,\r
1164 NULL,\r
1165 NULL,\r
1166 1\r
1167 );\r
1168\r
1169 if (Urb == NULL) {\r
1170 EHC_ERROR (("EhcSyncInterruptTransfer: failed to create URB\n"));\r
1171\r
1172 Status = EFI_OUT_OF_RESOURCES;\r
1173 goto ON_EXIT;\r
1174 }\r
1175\r
1176 EhcLinkQhToPeriod (Ehc, Urb->Qh);\r
1177 Status = EhcExecTransfer (Ehc, Urb, TimeOut);\r
1178 EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);\r
1179\r
1180 *TransferResult = Urb->Result;\r
1181 *DataLength = Urb->Completed;\r
1182 *DataToggle = Urb->DataToggle;\r
1183\r
1184 if (*TransferResult == EFI_USB_NOERROR) {\r
1185 Status = EFI_SUCCESS;\r
1186 }\r
1187\r
1188ON_EXIT:\r
1189 Ehc->PciIo->Flush (Ehc->PciIo);\r
1190 gBS->RestoreTPL (OldTpl);\r
1191\r
1192 if (EFI_ERROR (Status)) {\r
1193 EHC_ERROR (("EhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
1194 }\r
1195\r
1196 return Status;\r
1197}\r
1198\r
1199\r
1200/**\r
1201 Submits isochronous transfer to a target USB device.\r
1202\r
1203 @param This This EFI_USB2_HC_PROTOCOL instance.\r
1204 @param DeviceAddress Target device address\r
1205 @param EndPointAddress End point address with its direction\r
1206 @param DeviceSpeed Device speed, Low speed device doesn't support this\r
1207 type.\r
1208 @param MaximumPacketLength Maximum packet size that the endpoint is capable of\r
1209 sending or receiving.\r
1210 @param DataBuffersNumber Number of data buffers prepared for the transfer.\r
1211 @param Data Array of pointers to the buffers of data that will\r
1212 be transmitted to USB device or received from USB\r
1213 device.\r
1214 @param DataLength The size, in bytes, of the data buffer\r
1215 @param Translator Transaction translator to use.\r
1216 @param TransferResult Variable to receive the transfer result\r
1217\r
1218 @return EFI_UNSUPPORTED : Isochronous transfer is unsupported.\r
1219\r
1220**/\r
1221STATIC\r
1222EFI_STATUS\r
1223EFIAPI\r
1224EhcIsochronousTransfer (\r
1225 IN EFI_USB2_HC_PROTOCOL *This,\r
1226 IN UINT8 DeviceAddress,\r
1227 IN UINT8 EndPointAddress,\r
1228 IN UINT8 DeviceSpeed,\r
1229 IN UINTN MaximumPacketLength,\r
1230 IN UINT8 DataBuffersNumber,\r
1231 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
1232 IN UINTN DataLength,\r
1233 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
1234 OUT UINT32 *TransferResult\r
1235 )\r
1236{\r
1237 return EFI_UNSUPPORTED;\r
1238}\r
1239\r
1240\r
1241/**\r
1242 Submits Async isochronous transfer to a target USB device.\r
1243\r
1244 @param This This EFI_USB2_HC_PROTOCOL instance.\r
1245 @param DeviceAddress Target device address\r
1246 @param EndPointAddress End point address with its direction\r
1247 @param DeviceSpeed Device speed, Low speed device doesn't support this\r
1248 type.\r
1249 @param MaximumPacketLength Maximum packet size that the endpoint is capable of\r
1250 sending or receiving.\r
1251 @param DataBuffersNumber Number of data buffers prepared for the transfer.\r
1252 @param Data Array of pointers to the buffers of data that will\r
1253 be transmitted to USB device or received from USB\r
1254 device.\r
1255 @param DataLength The size, in bytes, of the data buffer\r
1256 @param Translator Transaction translator to use.\r
1257 @param IsochronousCallBack Function to be called when the transfer complete\r
1258 @param Context Context passed to the call back function as\r
1259 parameter\r
1260\r
1261 @return EFI_UNSUPPORTED : Isochronous transfer isn't supported\r
1262\r
1263**/\r
1264STATIC\r
1265EFI_STATUS\r
1266EFIAPI\r
1267EhcAsyncIsochronousTransfer (\r
1268 IN EFI_USB2_HC_PROTOCOL *This,\r
1269 IN UINT8 DeviceAddress,\r
1270 IN UINT8 EndPointAddress,\r
1271 IN UINT8 DeviceSpeed,\r
1272 IN UINTN MaximumPacketLength,\r
1273 IN UINT8 DataBuffersNumber,\r
1274 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
1275 IN UINTN DataLength,\r
1276 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
1277 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,\r
1278 IN VOID *Context\r
1279 )\r
1280{\r
1281 return EFI_UNSUPPORTED;\r
1282}\r
1283\r
1284EFI_STATUS\r
1285EFIAPI\r
1286EhcDriverEntryPoint (\r
1287 IN EFI_HANDLE ImageHandle,\r
1288 IN EFI_SYSTEM_TABLE *SystemTable\r
1289 )\r
1290/*++\r
1291\r
1292Routine Description:\r
1293\r
1294 Entry point for EFI drivers.\r
1295\r
1296Arguments:\r
1297\r
1298 ImageHandle - EFI_HANDLE\r
1299 SystemTable - EFI_SYSTEM_TABLE\r
1300\r
1301Returns:\r
1302\r
1303 EFI_SUCCESS Success\r
1304 EFI_DEVICE_ERROR Fail\r
1305\r
1306--*/\r
1307{\r
1308 return EfiLibInstallDriverBindingComponentName2 (\r
1309 ImageHandle,\r
1310 SystemTable,\r
1311 &gEhciDriverBinding,\r
1312 ImageHandle,\r
1313 &gEhciComponentName,\r
1314 &gEhciComponentName2\r
1315 );\r
1316}\r
1317\r
1318\r
1319/**\r
1320 Test to see if this driver supports ControllerHandle. Any\r
1321 ControllerHandle that has Usb2HcProtocol installed will\r
1322 be supported.\r
1323\r
1324 @param This Protocol instance pointer.\r
1325 @param Controlle Handle of device to test\r
1326 @param RemainingDevicePath Not used\r
1327\r
1328 @return EFI_SUCCESS : This driver supports this device.\r
1329 @return EFI_UNSUPPORTED : This driver does not support this device.\r
1330\r
1331**/\r
1332EFI_STATUS\r
1333EFIAPI\r
1334EhcDriverBindingSupported (\r
1335 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1336 IN EFI_HANDLE Controller,\r
1337 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
1338 )\r
1339{\r
1340 EFI_STATUS Status;\r
1341 EFI_PCI_IO_PROTOCOL *PciIo;\r
1342 USB_CLASSC UsbClassCReg;\r
1343\r
1344 //\r
1345 // Test whether there is PCI IO Protocol attached on the controller handle.\r
1346 //\r
1347 Status = gBS->OpenProtocol (\r
1348 Controller,\r
1349 &gEfiPciIoProtocolGuid,\r
1350 (VOID **) &PciIo,\r
1351 This->DriverBindingHandle,\r
1352 Controller,\r
1353 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1354 );\r
1355\r
1356 if (EFI_ERROR (Status)) {\r
1357 return EFI_UNSUPPORTED;\r
1358 }\r
1359\r
1360 Status = PciIo->Pci.Read (\r
1361 PciIo,\r
1362 EfiPciIoWidthUint8,\r
1363 EHC_PCI_CLASSC,\r
1364 sizeof (USB_CLASSC) / sizeof (UINT8),\r
1365 &UsbClassCReg\r
1366 );\r
1367\r
1368 if (EFI_ERROR (Status)) {\r
1369 Status = EFI_UNSUPPORTED;\r
1370 goto ON_EXIT;\r
1371 }\r
1372\r
1373 //\r
1374 // Test whether the controller belongs to Ehci type\r
1375 //\r
1376 if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||\r
1377 (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||\r
1378 (UsbClassCReg.PI != EHC_PCI_CLASSC_PI)) {\r
1379\r
1380 Status = EFI_UNSUPPORTED;\r
1381 }\r
1382\r
1383ON_EXIT:\r
1384 gBS->CloseProtocol (\r
1385 Controller,\r
1386 &gEfiPciIoProtocolGuid,\r
1387 This->DriverBindingHandle,\r
1388 Controller\r
1389 );\r
1390\r
1391 return Status;\r
1392}\r
1393\r
1394\r
1395/**\r
1396 Create and initialize a USB2_HC_DEV\r
1397\r
1398 @param PciIo The PciIo on this device\r
1399 @param OriginalPciAttributes Original PCI attributes\r
1400\r
1401 @return The allocated and initialized USB2_HC_DEV structure\r
1402 @return if created, otherwise NULL.\r
1403\r
1404**/\r
1405STATIC\r
1406USB2_HC_DEV *\r
1407EhcCreateUsb2Hc (\r
1408 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1409 IN UINT64 OriginalPciAttributes\r
1410 )\r
1411{\r
1412 USB2_HC_DEV *Ehc;\r
1413 EFI_STATUS Status;\r
1414\r
1415 Ehc = AllocateZeroPool (sizeof (USB2_HC_DEV));\r
1416\r
1417 if (Ehc == NULL) {\r
1418 return NULL;\r
1419 }\r
1420\r
1421 //\r
1422 // Init EFI_USB2_HC_PROTOCOL interface and private data structure\r
1423 //\r
1424 Ehc->Signature = USB2_HC_DEV_SIGNATURE;\r
1425\r
1426 Ehc->Usb2Hc.GetCapability = EhcGetCapability;\r
1427 Ehc->Usb2Hc.Reset = EhcReset;\r
1428 Ehc->Usb2Hc.GetState = EhcGetState;\r
1429 Ehc->Usb2Hc.SetState = EhcSetState;\r
1430 Ehc->Usb2Hc.ControlTransfer = EhcControlTransfer;\r
1431 Ehc->Usb2Hc.BulkTransfer = EhcBulkTransfer;\r
1432 Ehc->Usb2Hc.AsyncInterruptTransfer = EhcAsyncInterruptTransfer;\r
1433 Ehc->Usb2Hc.SyncInterruptTransfer = EhcSyncInterruptTransfer;\r
1434 Ehc->Usb2Hc.IsochronousTransfer = EhcIsochronousTransfer;\r
1435 Ehc->Usb2Hc.AsyncIsochronousTransfer = EhcAsyncIsochronousTransfer;\r
1436 Ehc->Usb2Hc.GetRootHubPortStatus = EhcGetRootHubPortStatus;\r
1437 Ehc->Usb2Hc.SetRootHubPortFeature = EhcSetRootHubPortFeature;\r
1438 Ehc->Usb2Hc.ClearRootHubPortFeature = EhcClearRootHubPortFeature;\r
1439 Ehc->Usb2Hc.MajorRevision = 0x1;\r
1440 Ehc->Usb2Hc.MinorRevision = 0x1;\r
1441\r
1442 Ehc->PciIo = PciIo;\r
1443 Ehc->OriginalPciAttributes = OriginalPciAttributes;\r
1444\r
1445 InitializeListHead (&Ehc->AsyncIntTransfers);\r
1446\r
1447 Ehc->HcStructParams = EhcReadCapRegister (Ehc, EHC_HCSPARAMS_OFFSET);\r
1448 Ehc->HcCapParams = EhcReadCapRegister (Ehc, EHC_HCCPARAMS_OFFSET);\r
1449 Ehc->CapLen = EhcReadCapRegister (Ehc, EHC_CAPLENGTH_OFFSET) & 0x0FF;\r
1450\r
1451 EHC_DEBUG (("EhcCreateUsb2Hc: capability length %d\n", Ehc->CapLen));\r
1452\r
1453 //\r
1454 // Create AsyncRequest Polling Timer\r
1455 //\r
1456 Status = gBS->CreateEvent (\r
1457 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
1458 TPL_CALLBACK,\r
1459 EhcMoniteAsyncRequests,\r
1460 Ehc,\r
1461 &Ehc->PollTimer\r
1462 );\r
1463\r
1464 if (EFI_ERROR (Status)) {\r
1465 gBS->FreePool (Ehc);\r
1466 return NULL;\r
1467 }\r
1468\r
1469 return Ehc;\r
1470}\r
1471\r
1472\r
1473/**\r
1474 Starting the Usb EHCI Driver\r
1475\r
1476 @param This Protocol instance pointer.\r
1477 @param Controller Handle of device to test\r
1478 @param RemainingDevicePath Not used\r
1479\r
1480 @return EFI_SUCCESS : supports this device.\r
1481 @return EFI_UNSUPPORTED : do not support this device.\r
1482 @return EFI_DEVICE_ERROR : cannot be started due to device Error\r
1483 @return EFI_OUT_OF_RESOURCES : cannot allocate resources\r
1484\r
1485**/\r
1486EFI_STATUS\r
1487EFIAPI\r
1488EhcDriverBindingStart (\r
1489 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1490 IN EFI_HANDLE Controller,\r
1491 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
1492 )\r
1493{\r
1494 EFI_STATUS Status;\r
1495 USB2_HC_DEV *Ehc;\r
1496 EFI_PCI_IO_PROTOCOL *PciIo;\r
1497 UINT64 Supports;\r
1498 UINT64 OriginalPciAttributes;\r
1499 BOOLEAN PciAttributesSaved;\r
1500\r
1501 //\r
1502 // Open the PciIo Protocol, then enable the USB host controller\r
1503 //\r
1504 Status = gBS->OpenProtocol (\r
1505 Controller,\r
1506 &gEfiPciIoProtocolGuid,\r
1507 (VOID **) &PciIo,\r
1508 This->DriverBindingHandle,\r
1509 Controller,\r
1510 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1511 );\r
1512\r
1513 if (EFI_ERROR (Status)) {\r
1514 EHC_ERROR (("EhcDriverBindingStart: failed to open PCI_IO\n"));\r
1515 return EFI_DEVICE_ERROR;\r
1516 }\r
1517\r
1518 PciAttributesSaved = FALSE;\r
1519 //\r
1520 // Save original PCI attributes\r
1521 //\r
1522 Status = PciIo->Attributes (\r
1523 PciIo,\r
1524 EfiPciIoAttributeOperationGet,\r
1525 0,\r
1526 &OriginalPciAttributes\r
1527 );\r
1528\r
1529 if (EFI_ERROR (Status)) {\r
1530 goto CLOSE_PCIIO;\r
1531 }\r
1532 PciAttributesSaved = TRUE;\r
1533\r
1534 Status = PciIo->Attributes (\r
1535 PciIo,\r
1536 EfiPciIoAttributeOperationSupported,\r
1537 0,\r
1538 &Supports\r
1539 );\r
1540 if (!EFI_ERROR (Status)) {\r
1541 Supports &= EFI_PCI_DEVICE_ENABLE;\r
1542 Status = PciIo->Attributes (\r
1543 PciIo,\r
1544 EfiPciIoAttributeOperationEnable,\r
1545 Supports,\r
1546 NULL\r
1547 );\r
1548 }\r
1549\r
1550 if (EFI_ERROR (Status)) {\r
1551 EHC_ERROR (("EhcDriverBindingStart: failed to enable controller\n"));\r
1552 goto CLOSE_PCIIO;\r
1553 }\r
1554\r
1555 //\r
1556 // Create then install USB2_HC_PROTOCOL\r
1557 //\r
1558 Ehc = EhcCreateUsb2Hc (PciIo, OriginalPciAttributes);\r
1559\r
1560 if (Ehc == NULL) {\r
1561 EHC_ERROR (("EhcDriverBindingStart: failed to create USB2_HC\n"));\r
1562\r
1563 Status = EFI_OUT_OF_RESOURCES;\r
1564 goto CLOSE_PCIIO;\r
1565 }\r
1566\r
1567 Status = gBS->InstallProtocolInterface (\r
1568 &Controller,\r
1569 &gEfiUsb2HcProtocolGuid,\r
1570 EFI_NATIVE_INTERFACE,\r
1571 &Ehc->Usb2Hc\r
1572 );\r
1573\r
1574 if (EFI_ERROR (Status)) {\r
1575 EHC_ERROR (("EhcDriverBindingStart: failed to install USB2_HC Protocol\n"));\r
1576 goto FREE_POOL;\r
1577 }\r
1578\r
1579 //\r
1580 // Robustnesss improvement such as for UoL\r
1581 //\r
1582 EhcClearLegacySupport (Ehc);\r
1583 EhcResetHC (Ehc, EHC_RESET_TIMEOUT);\r
1584\r
1585 Status = EhcInitHC (Ehc);\r
1586\r
1587 if (EFI_ERROR (Status)) {\r
1588 EHC_ERROR (("EhcDriverBindingStart: failed to init host controller\n"));\r
1589 goto UNINSTALL_USBHC;\r
1590 }\r
1591\r
1592 //\r
1593 // Start the asynchronous interrupt monitor\r
1594 //\r
1595 Status = gBS->SetTimer (Ehc->PollTimer, TimerPeriodic, EHC_ASYNC_POLL_INTERVAL);\r
1596\r
1597 if (EFI_ERROR (Status)) {\r
1598 EHC_ERROR (("EhcDriverBindingStart: failed to start async interrupt monitor\n"));\r
1599\r
1600 EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);\r
1601 goto UNINSTALL_USBHC;\r
1602 }\r
1603\r
1604 //\r
1605 // Install the component name protocol, don't fail the start\r
1606 // because of something for display.\r
1607 //\r
1608 AddUnicodeString2 (\r
1609 "eng",\r
1610 gEhciComponentName.SupportedLanguages,\r
1611 &Ehc->ControllerNameTable,\r
1612 L"Enhanced Host Controller (USB 2.0)",\r
1613 TRUE\r
1614 );\r
1615 AddUnicodeString2 (\r
1616 "en",\r
1617 gEhciComponentName2.SupportedLanguages,\r
1618 &Ehc->ControllerNameTable,\r
1619 L"Enhanced Host Controller (USB 2.0)",\r
1620 FALSE\r
1621 );\r
1622\r
1623\r
1624 EHC_DEBUG (("EhcDriverBindingStart: EHCI started for controller @ %x\n", Controller));\r
1625 return EFI_SUCCESS;\r
1626\r
1627UNINSTALL_USBHC:\r
1628 gBS->UninstallProtocolInterface (\r
1629 Controller,\r
1630 &gEfiUsb2HcProtocolGuid,\r
1631 &Ehc->Usb2Hc\r
1632 );\r
1633\r
1634FREE_POOL:\r
1635 EhcFreeSched (Ehc);\r
1636 gBS->CloseEvent (Ehc->PollTimer);\r
1637 gBS->FreePool (Ehc);\r
1638\r
1639CLOSE_PCIIO:\r
1640 if (PciAttributesSaved == TRUE) {\r
1641 //\r
1642 // Restore original PCI attributes\r
1643 //\r
1644 PciIo->Attributes (\r
1645 PciIo,\r
1646 EfiPciIoAttributeOperationSet,\r
1647 OriginalPciAttributes,\r
1648 NULL\r
1649 );\r
1650 }\r
1651\r
1652 gBS->CloseProtocol (\r
1653 Controller,\r
1654 &gEfiPciIoProtocolGuid,\r
1655 This->DriverBindingHandle,\r
1656 Controller\r
1657 );\r
1658\r
1659 return Status;\r
1660}\r
1661\r
1662\r
1663/**\r
1664 Stop this driver on ControllerHandle. Support stoping any child handles\r
1665 created by this driver.\r
1666\r
1667 @param This Protocol instance pointer.\r
1668 @param Controller Handle of device to stop driver on\r
1669 @param NumberOfChildren Number of Children in the ChildHandleBuffer\r
1670 @param ChildHandleBuffer List of handles for the children we need to stop.\r
1671\r
1672 @return EFI_SUCCESS Success\r
1673 @return EFI_DEVICE_ERROR Fail\r
1674\r
1675**/\r
1676EFI_STATUS\r
1677EFIAPI\r
1678EhcDriverBindingStop (\r
1679 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1680 IN EFI_HANDLE Controller,\r
1681 IN UINTN NumberOfChildren,\r
1682 IN EFI_HANDLE *ChildHandleBuffer\r
1683 )\r
1684{\r
1685 EFI_STATUS Status;\r
1686 EFI_USB2_HC_PROTOCOL *Usb2Hc;\r
1687 EFI_PCI_IO_PROTOCOL *PciIo;\r
1688 USB2_HC_DEV *Ehc;\r
1689\r
1690 //\r
1691 // Test whether the Controller handler passed in is a valid\r
1692 // Usb controller handle that should be supported, if not,\r
1693 // return the error status directly\r
1694 //\r
1695 Status = gBS->OpenProtocol (\r
1696 Controller,\r
1697 &gEfiUsb2HcProtocolGuid,\r
1698 (VOID **) &Usb2Hc,\r
1699 This->DriverBindingHandle,\r
1700 Controller,\r
1701 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1702 );\r
1703\r
1704 if (EFI_ERROR (Status)) {\r
1705 return Status;\r
1706 }\r
1707\r
1708 Ehc = EHC_FROM_THIS (Usb2Hc);\r
1709 PciIo = Ehc->PciIo;\r
1710\r
1711 //\r
1712 // Stop AsyncRequest Polling timer then stop the EHCI driver\r
1713 // and uninstall the EHCI protocl.\r
1714 //\r
1715 gBS->SetTimer (Ehc->PollTimer, TimerCancel, EHC_ASYNC_POLL_INTERVAL);\r
1716 EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);\r
1717\r
1718 Status = gBS->UninstallProtocolInterface (\r
1719 Controller,\r
1720 &gEfiUsb2HcProtocolGuid,\r
1721 Usb2Hc\r
1722 );\r
1723\r
1724 if (EFI_ERROR (Status)) {\r
1725 return Status;\r
1726 }\r
1727\r
1728 if (Ehc->PollTimer != NULL) {\r
1729 gBS->CloseEvent (Ehc->PollTimer);\r
1730 }\r
1731\r
1732 EhcFreeSched (Ehc);\r
1733\r
1734 if (Ehc->ControllerNameTable) {\r
1735 FreeUnicodeStringTable (Ehc->ControllerNameTable);\r
1736 }\r
1737\r
1738 //\r
1739 // Restore original PCI attributes\r
1740 //\r
1741 PciIo->Attributes (\r
1742 PciIo,\r
1743 EfiPciIoAttributeOperationSet,\r
1744 Ehc->OriginalPciAttributes,\r
1745 NULL\r
1746 );\r
1747\r
1748 gBS->CloseProtocol (\r
1749 Controller,\r
1750 &gEfiPciIoProtocolGuid,\r
1751 This->DriverBindingHandle,\r
1752 Controller\r
1753 );\r
1754\r
1755 FreePool (Ehc);\r
1756\r
1757 return EFI_SUCCESS;\r
1758}\r
1759\r
1760EFI_DRIVER_BINDING_PROTOCOL\r
1761gEhciDriverBinding = {\r
1762 EhcDriverBindingSupported,\r
1763 EhcDriverBindingStart,\r
1764 EhcDriverBindingStop,\r
1765 0x10,\r
1766 NULL,\r
1767 NULL\r
1768};\r