]> git.proxmox.com Git - mirror_edk2.git/blame - QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.c
QuarkSocPkg: Add new package for Quark SoC X1000
[mirror_edk2.git] / QuarkSocPkg / QuarkSouthCluster / Usb / Ohci / Dxe / Ohci.c
CommitLineData
9b6bbcdb
MK
1/** @file\r
2This file contains the implementation of Usb Hc Protocol.\r
3\r
4Copyright (c) 2013-2015 Intel Corporation.\r
5\r
6This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16\r
17#include "Ohci.h"\r
18\r
19/**\r
20 Provides software reset for the USB host controller.\r
21\r
22 @param This This EFI_USB_HC_PROTOCOL instance.\r
23 @param Attributes A bit mask of the reset operation to perform.\r
24\r
25 @retval EFI_SUCCESS The reset operation succeeded.\r
26 @retval EFI_INVALID_PARAMETER Attributes is not valid.\r
27 @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is\r
28 not currently supported by the host controller.\r
29 @retval EFI_DEVICE_ERROR Host controller isn't halted to reset.\r
30\r
31**/\r
32EFI_STATUS\r
33EFIAPI\r
34OhciReset (\r
35 IN EFI_USB_HC_PROTOCOL *This,\r
36 IN UINT16 Attributes\r
37 )\r
38{\r
39 EFI_STATUS Status;\r
40 USB_OHCI_HC_DEV *Ohc;\r
41 UINT8 Index;\r
42 UINT8 NumOfPorts;\r
43 UINT32 PowerOnGoodTime;\r
44 UINT32 Data32;\r
45 BOOLEAN Flag = FALSE;\r
46\r
47 if ((Attributes & ~(EFI_USB_HC_RESET_GLOBAL | EFI_USB_HC_RESET_HOST_CONTROLLER)) != 0) {\r
48 return EFI_INVALID_PARAMETER;\r
49 }\r
50\r
51 Status = EFI_SUCCESS;\r
52 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
53\r
54 if ((Attributes & EFI_USB_HC_RESET_HOST_CONTROLLER) != 0) {\r
55 gBS->Stall (50 * 1000);\r
56 Status = OhciSetHcCommandStatus (Ohc, HC_RESET, HC_RESET);\r
57 if (EFI_ERROR (Status)) {\r
58 return EFI_DEVICE_ERROR;\r
59 }\r
60 gBS->Stall (50 * 1000);\r
61 //\r
62 // Wait for host controller reset.\r
63 //\r
64 PowerOnGoodTime = 50;\r
65 do {\r
66 gBS->Stall (1 * 1000);\r
67 Data32 = OhciGetOperationalReg (Ohc->PciIo, HC_COMMAND_STATUS );\r
68 if (EFI_ERROR (Status)) {\r
69 return EFI_DEVICE_ERROR;\r
70 }\r
71 if ((Data32 & HC_RESET) == 0) {\r
72 Flag = TRUE;\r
73 break;\r
74 }\r
75 }while(PowerOnGoodTime--);\r
76 if (!Flag){\r
77 return EFI_DEVICE_ERROR;\r
78 }\r
79 }\r
80 OhciFreeIntTransferMemory (Ohc);\r
81 Status = OhciInitializeInterruptList (Ohc);\r
82 OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf);\r
83 if ((Attributes & EFI_USB_HC_RESET_GLOBAL) != 0) {\r
84 Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_RESET);\r
85 if (EFI_ERROR (Status)) {\r
86 return EFI_DEVICE_ERROR;\r
87 }\r
88 gBS->Stall (50 * 1000);\r
89 }\r
90 //\r
91 // Initialize host controller operational registers\r
92 //\r
93 OhciSetFrameInterval (Ohc, FS_LARGEST_DATA_PACKET, 0x2778);\r
94 OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf);\r
95 OhciSetPeriodicStart (Ohc, 0x2a2f);\r
96 OhciSetHcControl (Ohc, CONTROL_BULK_RATIO, 0x3);\r
97 OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED | BULK_LIST_FILLED, 0);\r
98 OhciSetRootHubDescriptor (Ohc, RH_PSWITCH_MODE, 0);\r
99 OhciSetRootHubDescriptor (Ohc, RH_NO_PSWITCH | RH_NOC_PROT, 1);\r
100 //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NO_PSWITCH, 0);\r
101 //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NOC_PROT, 1);\r
102\r
103 OhciSetRootHubDescriptor (Ohc, RH_DEV_REMOVABLE, 0);\r
104 OhciSetRootHubDescriptor (Ohc, RH_PORT_PWR_CTRL_MASK, 0xffff);\r
105 OhciSetRootHubStatus (Ohc, RH_LOCAL_PSTAT_CHANGE);\r
106 OhciSetRootHubPortStatus (Ohc, 0, RH_SET_PORT_POWER);\r
107 OhciGetRootHubNumOfPorts (This, &NumOfPorts);\r
108 for (Index = 0; Index < NumOfPorts; Index++) {\r
109 if (!EFI_ERROR (OhciSetRootHubPortFeature (This, Index, EfiUsbPortReset))) {\r
110 gBS->Stall (200 * 1000);\r
111 OhciClearRootHubPortFeature (This, Index, EfiUsbPortReset);\r
112 gBS->Stall (1000);\r
113 OhciSetRootHubPortFeature (This, Index, EfiUsbPortEnable);\r
114 gBS->Stall (1000);\r
115 }\r
116 }\r
117 OhciSetMemoryPointer (Ohc, HC_HCCA, Ohc->HccaMemoryBlock);\r
118 OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL);\r
119 OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);\r
120 OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | BULK_ENABLE, 1); /*ISOCHRONOUS_ENABLE*/\r
121 OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_OPERATIONAL);\r
122 gBS->Stall (50*1000);\r
123 //\r
124 // Wait till first SOF occurs, and then clear it\r
125 //\r
126 while (OhciGetHcInterruptStatus (Ohc, START_OF_FRAME) == 0);\r
127 OhciClearInterruptStatus (Ohc, START_OF_FRAME);\r
128 gBS->Stall (1000);\r
129\r
130 return Status;\r
131}\r
132\r
133/**\r
134 Retrieve the current state of the USB host controller.\r
135\r
136 @param This This EFI_USB_HC_PROTOCOL instance.\r
137 @param State Variable to return the current host controller\r
138 state.\r
139\r
140 @retval EFI_SUCCESS Host controller state was returned in State.\r
141 @retval EFI_INVALID_PARAMETER State is NULL.\r
142 @retval EFI_DEVICE_ERROR An error was encountered while attempting to\r
143 retrieve the host controller's current state.\r
144\r
145**/\r
146\r
147EFI_STATUS\r
148EFIAPI\r
149OhciGetState (\r
150 IN EFI_USB_HC_PROTOCOL *This,\r
151 OUT EFI_USB_HC_STATE *State\r
152 )\r
153{\r
154 USB_OHCI_HC_DEV *Ohc;\r
155 UINT32 FuncState;\r
156\r
157 if (State == NULL) {\r
158 return EFI_INVALID_PARAMETER;\r
159 }\r
160\r
161 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
162\r
163 FuncState = OhciGetHcControl (Ohc, HC_FUNCTIONAL_STATE);\r
164\r
165 switch (FuncState) {\r
166 case HC_STATE_RESET:\r
167 case HC_STATE_RESUME:\r
168 *State = EfiUsbHcStateHalt;\r
169 break;\r
170\r
171 case HC_STATE_OPERATIONAL:\r
172 *State = EfiUsbHcStateOperational;\r
173 break;\r
174\r
175 case HC_STATE_SUSPEND:\r
176 *State = EfiUsbHcStateSuspend;\r
177 break;\r
178\r
179 default:\r
180 ASSERT (FALSE);\r
181 }\r
182 return EFI_SUCCESS;\r
183}\r
184\r
185/**\r
186 Sets the USB host controller to a specific state.\r
187\r
188 @param This This EFI_USB_HC_PROTOCOL instance.\r
189 @param State The state of the host controller that will be set.\r
190\r
191 @retval EFI_SUCCESS The USB host controller was successfully placed\r
192 in the state specified by State.\r
193 @retval EFI_INVALID_PARAMETER State is invalid.\r
194 @retval EFI_DEVICE_ERROR Failed to set the state due to device error.\r
195\r
196**/\r
197\r
198EFI_STATUS\r
199EFIAPI\r
200OhciSetState(\r
201 IN EFI_USB_HC_PROTOCOL *This,\r
202 IN EFI_USB_HC_STATE State\r
203 )\r
204{\r
205 EFI_STATUS Status;\r
206 USB_OHCI_HC_DEV *Ohc;\r
207\r
208 Ohc = USB_OHCI_HC_DEV_FROM_THIS(This);\r
209\r
210 switch (State) {\r
211 case EfiUsbHcStateHalt:\r
212 Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_RESET);\r
213 break;\r
214\r
215 case EfiUsbHcStateOperational:\r
216 Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_OPERATIONAL);\r
217 break;\r
218\r
219 case EfiUsbHcStateSuspend:\r
220 Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_SUSPEND);\r
221 break;\r
222\r
223 default:\r
224 Status = EFI_INVALID_PARAMETER;\r
225 }\r
226\r
227 gBS->Stall (1000);\r
228\r
229 return Status;\r
230}\r
231\r
232/**\r
233\r
234 Submits control transfer to a target USB device.\r
235\r
236 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
237 @param DeviceAddress Represents the address of the target device on the USB,\r
238 which is assigned during USB enumeration.\r
239 @param IsSlowDevice Indicates whether the target device is slow device\r
240 or full-speed device.\r
241 @param MaxPaketLength Indicates the maximum packet size that the\r
242 default control transfer endpoint is capable of\r
243 sending or receiving.\r
244 @param Request A pointer to the USB device request that will be sent\r
245 to the USB device.\r
246 @param TransferDirection Specifies the data direction for the transfer.\r
247 There are three values available, DataIn, DataOut\r
248 and NoData.\r
249 @param Data A pointer to the buffer of data that will be transmitted\r
250 to USB device or received from USB device.\r
251 @param DataLength Indicates the size, in bytes, of the data buffer\r
252 specified by Data.\r
253 @param TimeOut Indicates the maximum time, in microseconds,\r
254 which the transfer is allowed to complete.\r
255 @param TransferResult A pointer to the detailed result information generated\r
256 by this control transfer.\r
257\r
258 @retval EFI_SUCCESS The control transfer was completed successfully.\r
259 @retval EFI_OUT_OF_RESOURCES The control transfer could not be completed due to a lack of resources.\r
260 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
261 @retval EFI_TIMEOUT The control transfer failed due to timeout.\r
262 @retval EFI_DEVICE_ERROR The control transfer failed due to host controller or device error.\r
263 Caller should check TranferResult for detailed error information.\r
264\r
265--*/\r
266\r
267\r
268EFI_STATUS\r
269EFIAPI\r
270OhciControlTransfer (\r
271 IN EFI_USB_HC_PROTOCOL *This,\r
272 IN UINT8 DeviceAddress,\r
273 IN BOOLEAN IsSlowDevice,\r
274 IN UINT8 MaxPacketLength,\r
275 IN EFI_USB_DEVICE_REQUEST *Request,\r
276 IN EFI_USB_DATA_DIRECTION TransferDirection,\r
277 IN OUT VOID *Data OPTIONAL,\r
278 IN OUT UINTN *DataLength OPTIONAL,\r
279 IN UINTN TimeOut,\r
280 OUT UINT32 *TransferResult\r
281 )\r
282{\r
283 USB_OHCI_HC_DEV *Ohc;\r
284 ED_DESCRIPTOR *HeadEd;\r
285 ED_DESCRIPTOR *Ed;\r
286 TD_DESCRIPTOR *HeadTd;\r
287 TD_DESCRIPTOR *SetupTd;\r
288 TD_DESCRIPTOR *DataTd;\r
289 TD_DESCRIPTOR *StatusTd;\r
290 TD_DESCRIPTOR *EmptyTd;\r
291 EFI_STATUS Status;\r
292 UINT32 DataPidDir;\r
293 UINT32 StatusPidDir;\r
294 UINTN TimeCount;\r
295 OHCI_ED_RESULT EdResult;\r
296\r
297 EFI_PCI_IO_PROTOCOL_OPERATION MapOp;\r
298\r
299 UINTN ActualSendLength;\r
300 UINTN LeftLength;\r
301 UINT8 DataToggle;\r
302\r
303 VOID *ReqMapping = NULL;\r
304 UINTN ReqMapLength = 0;\r
305 EFI_PHYSICAL_ADDRESS ReqMapPhyAddr = 0;\r
306\r
307 VOID *DataMapping = NULL;\r
308 UINTN DataMapLength = 0;\r
309 EFI_PHYSICAL_ADDRESS DataMapPhyAddr = 0;\r
310\r
311 HeadTd = NULL;\r
312 DataTd = NULL;\r
313\r
314 if ((TransferDirection != EfiUsbDataOut && TransferDirection != EfiUsbDataIn &&\r
315 TransferDirection != EfiUsbNoData) ||\r
316 Request == NULL || DataLength == NULL || TransferResult == NULL ||\r
317 (TransferDirection == EfiUsbNoData && (*DataLength != 0 || Data != NULL)) ||\r
318 (TransferDirection != EfiUsbNoData && (*DataLength == 0 || Data == NULL)) ||\r
319 (IsSlowDevice && MaxPacketLength != 8) ||\r
320 (MaxPacketLength != 8 && MaxPacketLength != 16 &&\r
321 MaxPacketLength != 32 && MaxPacketLength != 64)) {\r
322 return EFI_INVALID_PARAMETER;\r
323 }\r
324\r
325 if (*DataLength > MAX_BYTES_PER_TD) {\r
326 DEBUG ((EFI_D_ERROR, "OhciControlTransfer: Request data size is too large\r\n"));\r
327 return EFI_INVALID_PARAMETER;\r
328 }\r
329\r
330 Ohc = USB_OHCI_HC_DEV_FROM_THIS(This);\r
331\r
332 if (TransferDirection == EfiUsbDataIn) {\r
333 DataPidDir = TD_IN_PID;\r
334 StatusPidDir = TD_OUT_PID;\r
335 } else {\r
336 DataPidDir = TD_OUT_PID;\r
337 StatusPidDir = TD_IN_PID;\r
338 }\r
339\r
340 Status = OhciSetHcControl (Ohc, CONTROL_ENABLE, 0);\r
341 if (EFI_ERROR(Status)) {\r
342 DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable CONTROL_ENABLE\r\n"));\r
343 *TransferResult = EFI_USB_ERR_SYSTEM;\r
344 return EFI_DEVICE_ERROR;\r
345 }\r
346 Status = OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED, 0);\r
347 if (EFI_ERROR(Status)) {\r
348 DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable CONTROL_LIST_FILLED\r\n"));\r
349 *TransferResult = EFI_USB_ERR_SYSTEM;\r
350 return EFI_DEVICE_ERROR;\r
351 }\r
352 gBS->Stall(20 * 1000);\r
353\r
354 OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL);\r
355 Ed = OhciCreateED (Ohc);\r
356 if (Ed == NULL) {\r
357 Status = EFI_OUT_OF_RESOURCES;\r
358 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate ED buffer\r\n"));\r
359 goto CTRL_EXIT;\r
360 }\r
361 OhciSetEDField (Ed, ED_SKIP, 1);\r
362 OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);\r
363 OhciSetEDField (Ed, ED_ENDPT_NUM, 0);\r
364 OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);\r
365 OhciSetEDField (Ed, ED_SPEED, IsSlowDevice);\r
366 OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0);\r
367 OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);\r
368 OhciSetEDField (Ed, ED_PDATA, 0);\r
369 OhciSetEDField (Ed, ED_ZERO, 0);\r
370 OhciSetEDField (Ed, ED_TDHEAD_PTR, 0);\r
371 OhciSetEDField (Ed, ED_TDTAIL_PTR, 0);\r
372 OhciSetEDField (Ed, ED_NEXT_EDPTR, 0);\r
373 HeadEd = OhciAttachEDToList (Ohc, CONTROL_LIST, Ed, NULL);\r
374 //\r
375 // Setup Stage\r
376 //\r
377 if(Request != NULL) {\r
378 ReqMapLength = sizeof(EFI_USB_DEVICE_REQUEST);\r
379 MapOp = EfiPciIoOperationBusMasterRead;\r
380 Status = Ohc->PciIo->Map (Ohc->PciIo, MapOp, (UINT8 *)Request, &ReqMapLength, &ReqMapPhyAddr, &ReqMapping);\r
381 if (EFI_ERROR(Status)) {\r
382 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to Map Request Buffer\r\n"));\r
383 goto FREE_ED_BUFF;\r
384 }\r
385 }\r
386 SetupTd = OhciCreateTD (Ohc);\r
387 if (SetupTd == NULL) {\r
388 Status = EFI_OUT_OF_RESOURCES;\r
389 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Setup TD buffer\r\n"));\r
390 goto UNMAP_SETUP_BUFF;\r
391 }\r
392 HeadTd = SetupTd;\r
393 OhciSetTDField (SetupTd, TD_PDATA, 0);\r
394 OhciSetTDField (SetupTd, TD_BUFFER_ROUND, 1);\r
395 OhciSetTDField (SetupTd, TD_DIR_PID, TD_SETUP_PID);\r
396 OhciSetTDField (SetupTd, TD_DELAY_INT, TD_NO_DELAY);\r
397 OhciSetTDField (SetupTd, TD_DT_TOGGLE, 2);\r
398 OhciSetTDField (SetupTd, TD_ERROR_CNT, 0);\r
399 OhciSetTDField (SetupTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
400 OhciSetTDField (SetupTd, TD_CURR_BUFFER_PTR, (UINT32)ReqMapPhyAddr);\r
401 OhciSetTDField (SetupTd, TD_NEXT_PTR, 0);\r
402 OhciSetTDField (SetupTd, TD_BUFFER_END_PTR, (UINT32)(ReqMapPhyAddr + sizeof (EFI_USB_DEVICE_REQUEST) - 1));\r
403 SetupTd->ActualSendLength = sizeof (EFI_USB_DEVICE_REQUEST);\r
404 SetupTd->DataBuffer = (UINT32)ReqMapPhyAddr;\r
405 SetupTd->NextTDPointer = 0;\r
406\r
407 if (TransferDirection == EfiUsbDataIn) {\r
408 MapOp = EfiPciIoOperationBusMasterWrite;\r
409 } else {\r
410 MapOp = EfiPciIoOperationBusMasterRead;\r
411 }\r
412 DataMapLength = *DataLength;\r
413 if ((Data != NULL) && (DataMapLength != 0)) {\r
414 Status = Ohc->PciIo->Map (Ohc->PciIo, MapOp, Data, &DataMapLength, &DataMapPhyAddr, &DataMapping);\r
415 if (EFI_ERROR(Status)) {\r
416 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail To Map Data Buffer\r\n"));\r
417 goto FREE_TD_BUFF;\r
418 }\r
419 }\r
420 //\r
421 //Data Stage\r
422 //\r
423 LeftLength = DataMapLength;\r
424 ActualSendLength = DataMapLength;\r
425 DataToggle = 1;\r
426 while (LeftLength > 0) {\r
427 ActualSendLength = LeftLength;\r
428 if (LeftLength > MaxPacketLength) {\r
429 ActualSendLength = MaxPacketLength;\r
430 }\r
431 DataTd = OhciCreateTD (Ohc);\r
432 if (DataTd == NULL) {\r
433 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate buffer for Data Stage TD\r\n"));\r
434 Status = EFI_OUT_OF_RESOURCES;\r
435 goto UNMAP_DATA_BUFF;\r
436 }\r
437 OhciSetTDField (DataTd, TD_PDATA, 0);\r
438 OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);\r
439 OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);\r
440 OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);\r
441 OhciSetTDField (DataTd, TD_DT_TOGGLE, DataToggle);\r
442 OhciSetTDField (DataTd, TD_ERROR_CNT, 0);\r
443 OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
444 OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) DataMapPhyAddr);\r
445 OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(DataMapPhyAddr + ActualSendLength - 1));\r
446 OhciSetTDField (DataTd, TD_NEXT_PTR, 0);\r
447 DataTd->ActualSendLength = (UINT32)ActualSendLength;\r
448 DataTd->DataBuffer = (UINT32)DataMapPhyAddr;\r
449 DataTd->NextTDPointer = 0;\r
450 OhciLinkTD (HeadTd, DataTd);\r
451 DataToggle ^= 1;\r
452 DataMapPhyAddr += ActualSendLength;\r
453 LeftLength -= ActualSendLength;\r
454 }\r
455 //\r
456 // Status Stage\r
457 //\r
458 StatusTd = OhciCreateTD (Ohc);\r
459 if (StatusTd == NULL) {\r
460 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate buffer for Status Stage TD\r\n"));\r
461 Status = EFI_OUT_OF_RESOURCES;\r
462 goto UNMAP_DATA_BUFF;\r
463 }\r
464 OhciSetTDField (StatusTd, TD_PDATA, 0);\r
465 OhciSetTDField (StatusTd, TD_BUFFER_ROUND, 1);\r
466 OhciSetTDField (StatusTd, TD_DIR_PID, StatusPidDir);\r
467 OhciSetTDField (StatusTd, TD_DELAY_INT, 7);\r
468 OhciSetTDField (StatusTd, TD_DT_TOGGLE, 3);\r
469 OhciSetTDField (StatusTd, TD_ERROR_CNT, 0);\r
470 OhciSetTDField (StatusTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
471 OhciSetTDField (StatusTd, TD_CURR_BUFFER_PTR, 0);\r
472 OhciSetTDField (StatusTd, TD_NEXT_PTR, 0);\r
473 OhciSetTDField (StatusTd, TD_BUFFER_END_PTR, 0);\r
474 StatusTd->ActualSendLength = 0;\r
475 StatusTd->DataBuffer = 0;\r
476 StatusTd->NextTDPointer = 0;\r
477 OhciLinkTD (HeadTd, StatusTd);\r
478 //\r
479 // Empty Stage\r
480 //\r
481 EmptyTd = OhciCreateTD (Ohc);\r
482 if (EmptyTd == NULL) {\r
483 Status = EFI_OUT_OF_RESOURCES;\r
484 goto UNMAP_DATA_BUFF;\r
485 }\r
486 OhciSetTDField (EmptyTd, TD_PDATA, 0);\r
487 OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0);\r
488 OhciSetTDField (EmptyTd, TD_DIR_PID, 0);\r
489 OhciSetTDField (EmptyTd, TD_DELAY_INT, 0);\r
490 //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle);\r
491 EmptyTd->Word0.DataToggle = 0;\r
492 OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0);\r
493 OhciSetTDField (EmptyTd, TD_COND_CODE, 0);\r
494 OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0);\r
495 OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0);\r
496 OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0);\r
497 EmptyTd->ActualSendLength = 0;\r
498 EmptyTd->DataBuffer = 0;\r
499 EmptyTd->NextTDPointer = 0;\r
500 OhciLinkTD (HeadTd, EmptyTd);\r
501 Ed->TdTailPointer = (UINT32)(UINTN)EmptyTd;\r
502 OhciAttachTDListToED (Ed, HeadTd);\r
503 //\r
504 // For debugging, dump ED & TD buffer befor transferring\r
505 //\r
506 //\r
507 //OhciDumpEdTdInfo (Ohc, Ed, HeadTd, TRUE);\r
508 //\r
509 OhciSetEDField (Ed, ED_SKIP, 0);\r
510 Status = OhciSetHcControl (Ohc, CONTROL_ENABLE, 1);\r
511 if (EFI_ERROR(Status)) {\r
512 DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to enable CONTROL_ENABLE\r\n"));\r
513 *TransferResult = EFI_USB_ERR_SYSTEM;\r
514 Status = EFI_DEVICE_ERROR;\r
515 goto UNMAP_DATA_BUFF;\r
516 }\r
517 Status = OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED, 1);\r
518 if (EFI_ERROR(Status)) {\r
519 DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to enable CONTROL_LIST_FILLED\r\n"));\r
520 *TransferResult = EFI_USB_ERR_SYSTEM;\r
521 Status = EFI_DEVICE_ERROR;\r
522 goto UNMAP_DATA_BUFF;\r
523 }\r
524 gBS->Stall(20 * 1000);\r
525\r
526\r
527 TimeCount = 0;\r
528 Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &EdResult);\r
529\r
530 while (Status == EFI_NOT_READY && TimeCount <= TimeOut) {\r
531 gBS->Stall (1000);\r
532 TimeCount++;\r
533 Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &EdResult);\r
534 }\r
535 //\r
536 // For debugging, dump ED & TD buffer after transferring\r
537 //\r
538 //OhciDumpEdTdInfo (Ohc, Ed, HeadTd, FALSE);\r
539 //\r
540 *TransferResult = ConvertErrorCode (EdResult.ErrorCode);\r
541\r
542 if (EdResult.ErrorCode != TD_NO_ERROR) {\r
543 if (EdResult.ErrorCode == TD_TOBE_PROCESSED) {\r
544 DEBUG ((EFI_D_INFO, "Control pipe timeout, > %d mS\r\n", TimeOut));\r
545 } else {\r
546 DEBUG ((EFI_D_INFO, "Control pipe broken\r\n"));\r
547 }\r
548 *DataLength = 0;\r
549 } else {\r
550 DEBUG ((EFI_D_INFO, "Control transfer successed\r\n"));\r
551 }\r
552\r
553UNMAP_DATA_BUFF:\r
554 OhciSetEDField (Ed, ED_SKIP, 1);\r
555 if (HeadEd == Ed) {\r
556 OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL);\r
557 } else {\r
558 HeadEd->NextED = Ed->NextED;\r
559 }\r
560 if(DataMapping != NULL) {\r
561 Ohc->PciIo->Unmap(Ohc->PciIo, DataMapping);\r
562 }\r
563\r
564FREE_TD_BUFF:\r
565 while (HeadTd) {\r
566 DataTd = HeadTd;\r
567 HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer);\r
568 UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));\r
569 }\r
570\r
571UNMAP_SETUP_BUFF:\r
572 if(ReqMapping != NULL) {\r
573 Ohc->PciIo->Unmap(Ohc->PciIo, ReqMapping);\r
574 }\r
575\r
576FREE_ED_BUFF:\r
577 UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));\r
578\r
579CTRL_EXIT:\r
580 return Status;\r
581}\r
582\r
583/**\r
584\r
585 Submits bulk transfer to a bulk endpoint of a USB device.\r
586\r
587 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
588 @param DeviceAddress Represents the address of the target device on the USB,\r
589 which is assigned during USB enumeration.\r
590 @param EndPointAddress The combination of an endpoint number and an\r
591 endpoint direction of the target USB device.\r
592 Each endpoint address supports data transfer in\r
593 one direction except the control endpoint\r
594 (whose default endpoint address is 0).\r
595 It is the caller's responsibility to make sure that\r
596 the EndPointAddress represents a bulk endpoint.\r
597 @param MaximumPacketLength Indicates the maximum packet size the target endpoint\r
598 is capable of sending or receiving.\r
599 @param Data A pointer to the buffer of data that will be transmitted\r
600 to USB device or received from USB device.\r
601 @param DataLength When input, indicates the size, in bytes, of the data buffer\r
602 specified by Data. When output, indicates the actually\r
603 transferred data size.\r
604 @param DataToggle A pointer to the data toggle value. On input, it indicates\r
605 the initial data toggle value the bulk transfer should adopt;\r
606 on output, it is updated to indicate the data toggle value\r
607 of the subsequent bulk transfer.\r
608 @param TimeOut Indicates the maximum time, in microseconds, which the\r
609 transfer is allowed to complete.\r
610 TransferResult A pointer to the detailed result information of the\r
611 bulk transfer.\r
612\r
613 @retval EFI_SUCCESS The bulk transfer was completed successfully.\r
614 @retval EFI_OUT_OF_RESOURCES The bulk transfer could not be submitted due to lack of resource.\r
615 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
616 @retval EFI_TIMEOUT The bulk transfer failed due to timeout.\r
617 @retval EFI_DEVICE_ERROR The bulk transfer failed due to host controller or device error.\r
618 Caller should check TranferResult for detailed error information.\r
619\r
620**/\r
621\r
622\r
623EFI_STATUS\r
624EFIAPI\r
625OhciBulkTransfer(\r
626 IN EFI_USB_HC_PROTOCOL *This,\r
627 IN UINT8 DeviceAddress,\r
628 IN UINT8 EndPointAddress,\r
629 IN UINT8 MaxPacketLength,\r
630 IN OUT VOID *Data,\r
631 IN OUT UINTN *DataLength,\r
632 IN OUT UINT8 *DataToggle,\r
633 IN UINTN TimeOut,\r
634 OUT UINT32 *TransferResult\r
635 )\r
636{\r
637 USB_OHCI_HC_DEV *Ohc;\r
638 ED_DESCRIPTOR *HeadEd;\r
639 ED_DESCRIPTOR *Ed;\r
640 UINT8 EdDir;\r
641 UINT32 DataPidDir;\r
642 TD_DESCRIPTOR *HeadTd;\r
643 TD_DESCRIPTOR *DataTd;\r
644 TD_DESCRIPTOR *EmptyTd;\r
645 EFI_STATUS Status;\r
646 EFI_USB_DATA_DIRECTION TransferDirection;\r
647 UINT8 EndPointNum;\r
648 UINTN TimeCount;\r
649 OHCI_ED_RESULT EdResult;\r
650\r
651 EFI_PCI_IO_PROTOCOL_OPERATION MapOp;\r
652 VOID *Mapping;\r
653 UINTN MapLength;\r
654 EFI_PHYSICAL_ADDRESS MapPyhAddr;\r
655 UINTN LeftLength;\r
656 UINTN ActualSendLength;\r
657 BOOLEAN FirstTD;\r
658\r
659 Mapping = NULL;\r
660 MapLength = 0;\r
661 MapPyhAddr = 0;\r
662 LeftLength = 0;\r
663 Status = EFI_SUCCESS;\r
664\r
665 if (Data == NULL || DataLength == NULL || DataToggle == NULL || TransferResult == NULL ||\r
666 *DataLength == 0 || (*DataToggle != 0 && *DataToggle != 1) ||\r
667 (MaxPacketLength != 8 && MaxPacketLength != 16 &&\r
668 MaxPacketLength != 32 && MaxPacketLength != 64)) {\r
669 return EFI_INVALID_PARAMETER;\r
670 }\r
671\r
672 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
673\r
674 if ((EndPointAddress & 0x80) != 0) {\r
675 TransferDirection = EfiUsbDataIn;\r
676 EdDir = ED_IN_DIR;\r
677 DataPidDir = TD_IN_PID;\r
678 MapOp = EfiPciIoOperationBusMasterWrite;\r
679 } else {\r
680 TransferDirection = EfiUsbDataOut;\r
681 EdDir = ED_OUT_DIR;\r
682 DataPidDir = TD_OUT_PID;\r
683 MapOp = EfiPciIoOperationBusMasterRead;\r
684 }\r
685\r
686 EndPointNum = (EndPointAddress & 0xF);\r
687 EdResult.NextToggle = *DataToggle;\r
688\r
689 Status = OhciSetHcControl (Ohc, BULK_ENABLE, 0);\r
690 if (EFI_ERROR(Status)) {\r
691 DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable BULK_ENABLE\r\n"));\r
692 *TransferResult = EFI_USB_ERR_SYSTEM;\r
693 return EFI_DEVICE_ERROR;\r
694 }\r
695 Status = OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 0);\r
696 if (EFI_ERROR(Status)) {\r
697 DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable BULK_LIST_FILLED\r\n"));\r
698 *TransferResult = EFI_USB_ERR_SYSTEM;\r
699 return EFI_DEVICE_ERROR;\r
700 }\r
701 gBS->Stall(20 * 1000);\r
702\r
703 OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);\r
704\r
705 Ed = OhciCreateED (Ohc);\r
706 if (Ed == NULL) {\r
707 return EFI_OUT_OF_RESOURCES;\r
708 }\r
709 OhciSetEDField (Ed, ED_SKIP, 1);\r
710 OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);\r
711 OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum);\r
712 OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);\r
713 OhciSetEDField (Ed, ED_SPEED, HI_SPEED);\r
714 OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0);\r
715 OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);\r
716 OhciSetEDField (Ed, ED_PDATA, 0);\r
717 OhciSetEDField (Ed, ED_ZERO, 0);\r
718 OhciSetEDField (Ed, ED_TDHEAD_PTR, 0);\r
719 OhciSetEDField (Ed, ED_TDTAIL_PTR, 0);\r
720 OhciSetEDField (Ed, ED_NEXT_EDPTR, 0);\r
721 HeadEd = OhciAttachEDToList (Ohc, BULK_LIST, Ed, NULL);\r
722\r
723 if(Data != NULL) {\r
724 MapLength = *DataLength;\r
725 Status = Ohc->PciIo->Map (Ohc->PciIo, MapOp, (UINT8 *)Data, &MapLength, &MapPyhAddr, &Mapping);\r
726 if (EFI_ERROR(Status)) {\r
727 DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to Map Data Buffer for Bulk\r\n"));\r
728 goto FREE_ED_BUFF;\r
729 }\r
730 }\r
731 //\r
732 //Data Stage\r
733 //\r
734 LeftLength = MapLength;\r
735 ActualSendLength = MapLength;\r
736 HeadTd = NULL;\r
737 FirstTD = TRUE;\r
738 while (LeftLength > 0) {\r
739 ActualSendLength = LeftLength;\r
740 if (LeftLength > MaxPacketLength) {\r
741 ActualSendLength = MaxPacketLength;\r
742 }\r
743 DataTd = OhciCreateTD (Ohc);\r
744 if (DataTd == NULL) {\r
745 DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to allocate buffer for Data Stage TD\r\n"));\r
746 Status = EFI_OUT_OF_RESOURCES;\r
747 goto FREE_OHCI_TDBUFF;\r
748 }\r
749 OhciSetTDField (DataTd, TD_PDATA, 0);\r
750 OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);\r
751 OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);\r
752 OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);\r
753 OhciSetTDField (DataTd, TD_DT_TOGGLE, *DataToggle);\r
754 OhciSetTDField (DataTd, TD_ERROR_CNT, 0);\r
755 OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
756 OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr);\r
757 OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(MapPyhAddr + ActualSendLength - 1));\r
758 OhciSetTDField (DataTd, TD_NEXT_PTR, 0);\r
759 DataTd->ActualSendLength = (UINT32)ActualSendLength;\r
760 DataTd->DataBuffer = (UINT32)MapPyhAddr;\r
761 DataTd->NextTDPointer = 0;\r
762 if (FirstTD) {\r
763 HeadTd = DataTd;\r
764 FirstTD = FALSE;\r
765 } else {\r
766 OhciLinkTD (HeadTd, DataTd);\r
767 }\r
768 *DataToggle ^= 1;\r
769 MapPyhAddr += ActualSendLength;\r
770 LeftLength -= ActualSendLength;\r
771 }\r
772 //\r
773 // Empty Stage\r
774 //\r
775 EmptyTd = OhciCreateTD (Ohc);\r
776 if (EmptyTd == NULL) {\r
777 Status = EFI_OUT_OF_RESOURCES;\r
778 DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to allocate buffer for Empty TD\r\n"));\r
779 goto FREE_OHCI_TDBUFF;\r
780 }\r
781 OhciSetTDField (EmptyTd, TD_PDATA, 0);\r
782 OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0);\r
783 OhciSetTDField (EmptyTd, TD_DIR_PID, 0);\r
784 OhciSetTDField (EmptyTd, TD_DELAY_INT, 0);\r
785 //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle);\r
786 EmptyTd->Word0.DataToggle = 0;\r
787 OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0);\r
788 OhciSetTDField (EmptyTd, TD_COND_CODE, 0);\r
789 OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0);\r
790 OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0);\r
791 OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0);\r
792 EmptyTd->ActualSendLength = 0;\r
793 EmptyTd->DataBuffer = 0;\r
794 EmptyTd->NextTDPointer = 0;\r
795 OhciLinkTD (HeadTd, EmptyTd);\r
796 Ed->TdTailPointer = (UINT32)(UINTN)EmptyTd;\r
797 OhciAttachTDListToED (Ed, HeadTd);\r
798\r
799 OhciSetEDField (Ed, ED_SKIP, 0);\r
800 Status = OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 1);\r
801 if (EFI_ERROR(Status)) {\r
802 *TransferResult = EFI_USB_ERR_SYSTEM;\r
803 Status = EFI_DEVICE_ERROR;\r
804 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable BULK_LIST_FILLED\r\n"));\r
805 goto FREE_OHCI_TDBUFF;\r
806 }\r
807 Status = OhciSetHcControl (Ohc, BULK_ENABLE, 1);\r
808 if (EFI_ERROR(Status)) {\r
809 *TransferResult = EFI_USB_ERR_SYSTEM;\r
810 Status = EFI_DEVICE_ERROR;\r
811 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable BULK_ENABLE\r\n"));\r
812 goto FREE_OHCI_TDBUFF;\r
813 }\r
814 gBS->Stall(20 * 1000);\r
815\r
816 TimeCount = 0;\r
817 Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &EdResult);\r
818 while (Status == EFI_NOT_READY && TimeCount <= TimeOut) {\r
819 gBS->Stall (1000);\r
820 TimeCount++;\r
821 Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &EdResult);\r
822 }\r
823\r
824 *TransferResult = ConvertErrorCode (EdResult.ErrorCode);\r
825\r
826 if (EdResult.ErrorCode != TD_NO_ERROR) {\r
827 if (EdResult.ErrorCode == TD_TOBE_PROCESSED) {\r
828 DEBUG ((EFI_D_INFO, "Bulk pipe timeout, > %d mS\r\n", TimeOut));\r
829 } else {\r
830 DEBUG ((EFI_D_INFO, "Bulk pipe broken\r\n"));\r
831 *DataToggle = EdResult.NextToggle;\r
832 }\r
833 *DataLength = 0;\r
834 } else {\r
835 DEBUG ((EFI_D_INFO, "Bulk transfer successed\r\n"));\r
836 }\r
837 //*DataToggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE);\r
838\r
839FREE_OHCI_TDBUFF:\r
840 OhciSetEDField (Ed, ED_SKIP, 1);\r
841 if (HeadEd == Ed) {\r
842 OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);\r
843 }else {\r
844 HeadEd->NextED = Ed->NextED;\r
845 }\r
846 while (HeadTd) {\r
847 DataTd = HeadTd;\r
848 HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer);\r
849 UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));\r
850 }\r
851\r
852 if(Mapping != NULL) {\r
853 Ohc->PciIo->Unmap(Ohc->PciIo, Mapping);\r
854 }\r
855\r
856FREE_ED_BUFF:\r
857 UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));\r
858\r
859 return Status;\r
860}\r
861/**\r
862\r
863 Submits an interrupt transfer to an interrupt endpoint of a USB device.\r
864\r
865 @param Ohc Device private data\r
866 @param DeviceAddress Represents the address of the target device on the USB,\r
867 which is assigned during USB enumeration.\r
868 @param EndPointAddress The combination of an endpoint number and an endpoint\r
869 direction of the target USB device. Each endpoint address\r
870 supports data transfer in one direction except the\r
871 control endpoint (whose default endpoint address is 0).\r
872 It is the caller's responsibility to make sure that\r
873 the EndPointAddress represents an interrupt endpoint.\r
874 @param IsSlowDevice Indicates whether the target device is slow device\r
875 or full-speed device.\r
876 @param MaxPacketLength Indicates the maximum packet size the target endpoint\r
877 is capable of sending or receiving.\r
878 @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between\r
879 the host and the target interrupt endpoint.\r
880 If FALSE, the specified asynchronous interrupt pipe\r
881 is canceled.\r
882 @param DataToggle A pointer to the data toggle value. On input, it is valid\r
883 when IsNewTransfer is TRUE, and it indicates the initial\r
884 data toggle value the asynchronous interrupt transfer\r
885 should adopt.\r
886 On output, it is valid when IsNewTransfer is FALSE,\r
887 and it is updated to indicate the data toggle value of\r
888 the subsequent asynchronous interrupt transfer.\r
889 @param PollingInterval Indicates the interval, in milliseconds, that the\r
890 asynchronous interrupt transfer is polled.\r
891 This parameter is required when IsNewTransfer is TRUE.\r
892 @param UCBuffer Uncacheable buffer\r
893 @param DataLength Indicates the length of data to be received at the\r
894 rate specified by PollingInterval from the target\r
895 asynchronous interrupt endpoint. This parameter\r
896 is only required when IsNewTransfer is TRUE.\r
897 @param CallBackFunction The Callback function.This function is called at the\r
898 rate specified by PollingInterval.This parameter is\r
899 only required when IsNewTransfer is TRUE.\r
900 @param Context The context that is passed to the CallBackFunction.\r
901 This is an optional parameter and may be NULL.\r
902 @param IsPeriodic Periodic interrupt or not\r
903 @param OutputED The correspoding ED carried out\r
904 @param OutputTD The correspoding TD carried out\r
905\r
906\r
907 @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully\r
908 submitted or canceled.\r
909 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
910 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
911\r
912**/\r
913\r
914EFI_STATUS\r
915OhciInterruptTransfer (\r
916 IN USB_OHCI_HC_DEV *Ohc,\r
917 IN UINT8 DeviceAddress,\r
918 IN UINT8 EndPointAddress,\r
919 IN BOOLEAN IsSlowDevice,\r
920 IN UINT8 MaxPacketLength,\r
921 IN BOOLEAN IsNewTransfer,\r
922 IN OUT UINT8 *DataToggle OPTIONAL,\r
923 IN UINTN PollingInterval OPTIONAL,\r
924 IN VOID *UCBuffer OPTIONAL,\r
925 IN UINTN DataLength OPTIONAL,\r
926 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL,\r
927 IN VOID *Context OPTIONAL,\r
928 IN BOOLEAN IsPeriodic OPTIONAL,\r
929 OUT ED_DESCRIPTOR **OutputED OPTIONAL,\r
930 OUT TD_DESCRIPTOR **OutputTD OPTIONAL\r
931 )\r
932{\r
933 ED_DESCRIPTOR *Ed;\r
934 UINT8 EdDir;\r
935 ED_DESCRIPTOR *HeadEd;\r
936 TD_DESCRIPTOR *HeadTd;\r
937 TD_DESCRIPTOR *DataTd;\r
938 TD_DESCRIPTOR *EmptTd;\r
939 UINTN Depth;\r
940 UINTN Index;\r
941 EFI_STATUS Status;\r
942 UINT8 EndPointNum;\r
943 UINT32 DataPidDir;\r
944 EFI_USB_DATA_DIRECTION TransferDirection;\r
945 INTERRUPT_CONTEXT_ENTRY *Entry;\r
946 EFI_TPL OldTpl;\r
947 BOOLEAN FirstTD;\r
948\r
949 VOID *Mapping;\r
950 UINTN MapLength;\r
951 EFI_PHYSICAL_ADDRESS MapPyhAddr;\r
952 UINTN LeftLength;\r
953 UINTN ActualSendLength;\r
954\r
955\r
956 if (DataLength > MAX_BYTES_PER_TD) {\r
957 DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Error param\r\n"));\r
958 return EFI_INVALID_PARAMETER;\r
959 }\r
960\r
961 if ((EndPointAddress & 0x80) != 0) {\r
962 TransferDirection = EfiUsbDataIn;\r
963 EdDir = ED_IN_DIR;\r
964 DataPidDir = TD_IN_PID;\r
965 } else {\r
966 TransferDirection = EfiUsbDataOut;\r
967 EdDir = ED_OUT_DIR;\r
968 DataPidDir = TD_OUT_PID;\r
969 }\r
970\r
971 EndPointNum = (EndPointAddress & 0xF);\r
972\r
973 if (!IsNewTransfer) {\r
974 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
975 OhciSetHcControl (Ohc, PERIODIC_ENABLE, 0);\r
976 OhciFreeInterruptContext (Ohc, DeviceAddress, EndPointAddress, DataToggle);\r
977 Status = OhciFreeInterruptEdByAddr (Ohc, DeviceAddress, EndPointNum);\r
978 OhciSetHcControl (Ohc, PERIODIC_ENABLE, 1);\r
979 gBS->RestoreTPL (OldTpl);\r
980 return Status;\r
981 }\r
982 MapLength = DataLength;\r
983 Status = Ohc->PciIo->Map(\r
984 Ohc->PciIo,\r
985 EfiPciIoOperationBusMasterWrite,\r
986 UCBuffer,\r
987 &MapLength,\r
988 &MapPyhAddr,\r
989 &Mapping\r
990 );\r
991 if (EFI_ERROR (Status)) {\r
992 DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Failt to PciIo->Map buffer \r\n"));\r
993 goto EXIT;\r
994 }\r
995 Depth = 5;\r
996 Index = 1;\r
997 while (PollingInterval >= Index * 2 && Depth > 0) {\r
998 Index *= 2;\r
999 Depth--;\r
1000 }\r
1001 //\r
1002 //ED Stage\r
1003 //\r
1004 HeadEd = OhciFindMinInterruptEDList (Ohc, (UINT32)Depth);\r
1005 if ((Ed = OhciFindWorkingEd (HeadEd, DeviceAddress, EndPointNum, EdDir)) != NULL) {\r
1006 OhciSetEDField (Ed, ED_SKIP, 1);\r
1007 } else {\r
1008 Ed = OhciCreateED (Ohc);\r
1009 if (Ed == NULL) {\r
1010 Status = EFI_OUT_OF_RESOURCES;\r
1011 DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for ED\r\n"));\r
1012 goto UNMAP_OHCI_XBUFF;\r
1013 }\r
1014 OhciSetEDField (Ed, ED_SKIP, 1);\r
1015 OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);\r
1016 OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum);\r
1017 OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);\r
1018 OhciSetEDField (Ed, ED_SPEED, IsSlowDevice);\r
1019 OhciSetEDField (Ed, ED_FORMAT, 0);\r
1020 OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);\r
1021 OhciSetEDField (Ed, ED_PDATA | ED_ZERO | ED_HALTED | ED_DTTOGGLE, 0);\r
1022 OhciSetEDField (Ed, ED_TDHEAD_PTR, 0);\r
1023 OhciSetEDField (Ed, ED_TDTAIL_PTR, 0);\r
1024 OhciSetEDField (Ed, ED_NEXT_EDPTR, 0);\r
1025 OhciAttachEDToList (Ohc, INTERRUPT_LIST, Ed, HeadEd);\r
1026 }\r
1027 //\r
1028 //Data Stage\r
1029 //\r
1030 LeftLength = MapLength;\r
1031 ActualSendLength = MapLength;\r
1032 HeadTd = NULL;\r
1033 FirstTD = TRUE;\r
1034 while (LeftLength > 0) {\r
1035 ActualSendLength = LeftLength;\r
1036 if (LeftLength > MaxPacketLength) {\r
1037 ActualSendLength = MaxPacketLength;\r
1038 }\r
1039 DataTd = OhciCreateTD (Ohc);\r
1040 if (DataTd == NULL) {\r
1041 Status = EFI_OUT_OF_RESOURCES;\r
1042 DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for Data Stage TD\r\n"));\r
1043 goto FREE_OHCI_TDBUFF;\r
1044 }\r
1045 OhciSetTDField (DataTd, TD_PDATA, 0);\r
1046 OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);\r
1047 OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);\r
1048 OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);\r
1049 OhciSetTDField (DataTd, TD_DT_TOGGLE, *DataToggle);\r
1050 OhciSetTDField (DataTd, TD_ERROR_CNT, 0);\r
1051 OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
1052 OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr);\r
1053 OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(MapPyhAddr + ActualSendLength - 1));\r
1054 OhciSetTDField (DataTd, TD_NEXT_PTR, 0);\r
1055 DataTd->ActualSendLength = (UINT32)ActualSendLength;\r
1056 DataTd->DataBuffer = (UINT32)MapPyhAddr;\r
1057 DataTd->NextTDPointer = 0;\r
1058 if (FirstTD) {\r
1059 HeadTd = DataTd;\r
1060 FirstTD = FALSE;\r
1061 } else {\r
1062 OhciLinkTD (HeadTd, DataTd);\r
1063 }\r
1064 *DataToggle ^= 1;\r
1065 MapPyhAddr += ActualSendLength;\r
1066 LeftLength -= ActualSendLength;\r
1067 }\r
1068\r
1069 EmptTd = OhciCreateTD (Ohc);\r
1070 if (EmptTd == NULL) {\r
1071 Status = EFI_OUT_OF_RESOURCES;\r
1072 DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for Empty Stage TD\r\n"));\r
1073 goto FREE_OHCI_TDBUFF;\r
1074 }\r
1075 OhciSetTDField (EmptTd, TD_PDATA, 0);\r
1076 OhciSetTDField (EmptTd, TD_BUFFER_ROUND, 0);\r
1077 OhciSetTDField (EmptTd, TD_DIR_PID, 0);\r
1078 OhciSetTDField (EmptTd, TD_DELAY_INT, 0);\r
1079 //OhciSetTDField (EmptTd, TD_DT_TOGGLE, CurrentToggle);\r
1080 EmptTd->Word0.DataToggle = 0;\r
1081 OhciSetTDField (EmptTd, TD_ERROR_CNT, 0);\r
1082 OhciSetTDField (EmptTd, TD_COND_CODE, 0);\r
1083 OhciSetTDField (EmptTd, TD_CURR_BUFFER_PTR, 0);\r
1084 OhciSetTDField (EmptTd, TD_BUFFER_END_PTR, 0);\r
1085 OhciSetTDField (EmptTd, TD_NEXT_PTR, 0);\r
1086 EmptTd->ActualSendLength = 0;\r
1087 EmptTd->DataBuffer = 0;\r
1088 EmptTd->NextTDPointer = 0;\r
1089 OhciLinkTD (HeadTd, EmptTd);\r
1090 Ed->TdTailPointer = (UINT32)(UINTN)EmptTd;\r
1091 OhciAttachTDListToED (Ed, HeadTd);\r
1092\r
1093 if (OutputED != NULL) {\r
1094 *OutputED = Ed;\r
1095 }\r
1096 if (OutputTD != NULL) {\r
1097 *OutputTD = HeadTd;\r
1098 }\r
1099\r
1100 if (CallBackFunction != NULL) {\r
1101 Entry = AllocatePool (sizeof (INTERRUPT_CONTEXT_ENTRY));\r
1102 if (Entry == NULL) {\r
1103 goto FREE_OHCI_TDBUFF;\r
1104 }\r
1105\r
1106 Entry->DeviceAddress = DeviceAddress;\r
1107 Entry->EndPointAddress = EndPointAddress;\r
1108 Entry->Ed = Ed;\r
1109 Entry->DataTd = HeadTd;\r
1110 Entry->IsSlowDevice = IsSlowDevice;\r
1111 Entry->MaxPacketLength = MaxPacketLength;\r
1112 Entry->PollingInterval = PollingInterval;\r
1113 Entry->CallBackFunction = CallBackFunction;\r
1114 Entry->Context = Context;\r
1115 Entry->IsPeriodic = IsPeriodic;\r
1116 Entry->UCBuffer = UCBuffer;\r
1117 Entry->UCBufferMapping = Mapping;\r
1118 Entry->DataLength = DataLength;\r
1119 Entry->Toggle = DataToggle;\r
1120 Entry->NextEntry = NULL;\r
1121 OhciAddInterruptContextEntry (Ohc, Entry);\r
1122 }\r
1123 OhciSetEDField (Ed, ED_SKIP, 0);\r
1124\r
1125 if (OhciGetHcControl (Ohc, PERIODIC_ENABLE) == 0) {\r
1126 Status = OhciSetHcControl (Ohc, PERIODIC_ENABLE, 1);\r
1127 gBS->Stall (1000);\r
1128 }\r
1129\r
1130 return EFI_SUCCESS;\r
1131\r
1132FREE_OHCI_TDBUFF:\r
1133 while (HeadTd) {\r
1134 DataTd = HeadTd;\r
1135 HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer);\r
1136 UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));\r
1137 }\r
1138\r
1139//FREE_OHCI_EDBUFF:\r
1140 if ((HeadEd != Ed) && HeadEd && Ed) {\r
1141 while(HeadEd->NextED != (UINT32)(UINTN)Ed) {\r
1142 HeadEd = (ED_DESCRIPTOR *)(UINTN)(HeadEd->NextED);\r
1143 }\r
1144 HeadEd->NextED = Ed->NextED;\r
1145 UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));\r
1146 }\r
1147\r
1148UNMAP_OHCI_XBUFF:\r
1149 Ohc->PciIo->Unmap(Ohc->PciIo, Mapping);\r
1150\r
1151EXIT:\r
1152 return Status;\r
1153}\r
1154\r
1155/**\r
1156\r
1157 Submits an asynchronous interrupt transfer to an interrupt endpoint of a USB device.\r
1158\r
1159 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
1160 @param DeviceAddress Represents the address of the target device on the USB,\r
1161 which is assigned during USB enumeration.\r
1162 @param EndPointAddress The combination of an endpoint number and an endpoint\r
1163 direction of the target USB device. Each endpoint address\r
1164 supports data transfer in one direction except the\r
1165 control endpoint (whose default endpoint address is 0).\r
1166 It is the caller's responsibility to make sure that\r
1167 the EndPointAddress represents an interrupt endpoint.\r
1168 @param IsSlowDevice Indicates whether the target device is slow device\r
1169 or full-speed device.\r
1170 @param MaxiumPacketLength Indicates the maximum packet size the target endpoint\r
1171 is capable of sending or receiving.\r
1172 @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between\r
1173 the host and the target interrupt endpoint.\r
1174 If FALSE, the specified asynchronous interrupt pipe\r
1175 is canceled.\r
1176 @param DataToggle A pointer to the data toggle value. On input, it is valid\r
1177 when IsNewTransfer is TRUE, and it indicates the initial\r
1178 data toggle value the asynchronous interrupt transfer\r
1179 should adopt.\r
1180 On output, it is valid when IsNewTransfer is FALSE,\r
1181 and it is updated to indicate the data toggle value of\r
1182 the subsequent asynchronous interrupt transfer.\r
1183 @param PollingInterval Indicates the interval, in milliseconds, that the\r
1184 asynchronous interrupt transfer is polled.\r
1185 This parameter is required when IsNewTransfer is TRUE.\r
1186 @param DataLength Indicates the length of data to be received at the\r
1187 rate specified by PollingInterval from the target\r
1188 asynchronous interrupt endpoint. This parameter\r
1189 is only required when IsNewTransfer is TRUE.\r
1190 @param CallBackFunction The Callback function.This function is called at the\r
1191 rate specified by PollingInterval.This parameter is\r
1192 only required when IsNewTransfer is TRUE.\r
1193 @param Context The context that is passed to the CallBackFunction.\r
1194 This is an optional parameter and may be NULL.\r
1195\r
1196 @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully\r
1197 submitted or canceled.\r
1198 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
1199 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
1200\r
1201**/\r
1202\r
1203\r
1204EFI_STATUS\r
1205EFIAPI\r
1206OhciAsyncInterruptTransfer (\r
1207 IN EFI_USB_HC_PROTOCOL *This,\r
1208 IN UINT8 DeviceAddress,\r
1209 IN UINT8 EndPointAddress,\r
1210 IN BOOLEAN IsSlowDevice,\r
1211 IN UINT8 MaxPacketLength,\r
1212 IN BOOLEAN IsNewTransfer,\r
1213 IN OUT UINT8 *DataToggle OPTIONAL,\r
1214 IN UINTN PollingInterval OPTIONAL,\r
1215 IN UINTN DataLength OPTIONAL,\r
1216 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL,\r
1217 IN VOID *Context OPTIONAL\r
1218 )\r
1219{\r
1220 EFI_STATUS Status;\r
1221 USB_OHCI_HC_DEV *Ohc;\r
1222 VOID *UCBuffer;\r
1223\r
1224 if (DataToggle == NULL || (EndPointAddress & 0x80) == 0 ||\r
1225 (IsNewTransfer && (DataLength == 0 ||\r
1226 (*DataToggle != 0 && *DataToggle != 1) || (PollingInterval < 1 || PollingInterval > 255)))) {\r
1227 return EFI_INVALID_PARAMETER;\r
1228 }\r
1229\r
1230 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
1231 if ( IsNewTransfer ) {\r
1232 UCBuffer = AllocatePool(DataLength);\r
1233 if (UCBuffer == NULL) {\r
1234 return EFI_OUT_OF_RESOURCES;\r
1235 }\r
1236 } else {\r
1237 UCBuffer = NULL;\r
1238 }\r
1239 Status = OhciInterruptTransfer (\r
1240 Ohc,\r
1241 DeviceAddress,\r
1242 EndPointAddress,\r
1243 IsSlowDevice,\r
1244 MaxPacketLength,\r
1245 IsNewTransfer,\r
1246 DataToggle,\r
1247 PollingInterval,\r
1248 UCBuffer,\r
1249 DataLength,\r
1250 CallBackFunction,\r
1251 Context,\r
1252 TRUE,\r
1253 NULL,\r
1254 NULL\r
1255 );\r
1256 if ( IsNewTransfer ) {\r
1257 if (EFI_ERROR(Status)) {\r
1258 gBS->FreePool (UCBuffer);\r
1259 }\r
1260 }\r
1261 return Status;\r
1262}\r
1263\r
1264\r
1265/**\r
1266\r
1267 Submits synchronous interrupt transfer to an interrupt endpoint\r
1268 of a USB device.\r
1269\r
1270 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
1271 @param DeviceAddress Represents the address of the target device on the USB,\r
1272 which is assigned during USB enumeration.\r
1273 @param EndPointAddress The combination of an endpoint number and an endpoint\r
1274 direction of the target USB device. Each endpoint\r
1275 address supports data transfer in one direction\r
1276 except the control endpoint (whose default\r
1277 endpoint address is 0). It is the caller's responsibility\r
1278 to make sure that the EndPointAddress represents\r
1279 an interrupt endpoint.\r
1280 @param IsSlowDevice Indicates whether the target device is slow device\r
1281 or full-speed device.\r
1282 @param MaxPacketLength Indicates the maximum packet size the target endpoint\r
1283 is capable of sending or receiving.\r
1284 @param Data A pointer to the buffer of data that will be transmitted\r
1285 to USB device or received from USB device.\r
1286 @param DataLength On input, the size, in bytes, of the data buffer specified\r
1287 by Data. On output, the number of bytes transferred.\r
1288 @param DataToggle A pointer to the data toggle value. On input, it indicates\r
1289 the initial data toggle value the synchronous interrupt\r
1290 transfer should adopt;\r
1291 on output, it is updated to indicate the data toggle value\r
1292 of the subsequent synchronous interrupt transfer.\r
1293 @param TimeOut Indicates the maximum time, in microseconds, which the\r
1294 transfer is allowed to complete.\r
1295 @param TransferResult A pointer to the detailed result information from\r
1296 the synchronous interrupt transfer.\r
1297\r
1298 @retval EFI_UNSUPPORTED This interface not available.\r
1299 @retval EFI_INVALID_PARAMETER Parameters not follow spec\r
1300\r
1301**/\r
1302\r
1303\r
1304EFI_STATUS\r
1305EFIAPI\r
1306OhciSyncInterruptTransfer (\r
1307 IN EFI_USB_HC_PROTOCOL *This,\r
1308 IN UINT8 DeviceAddress,\r
1309 IN UINT8 EndPointAddress,\r
1310 IN BOOLEAN IsSlowDevice,\r
1311 IN UINT8 MaxPacketLength,\r
1312 IN OUT VOID *Data,\r
1313 IN OUT UINTN *DataLength,\r
1314 IN OUT UINT8 *DataToggle,\r
1315 IN UINTN TimeOut,\r
1316 OUT UINT32 *TransferResult\r
1317 )\r
1318{\r
1319 USB_OHCI_HC_DEV *Ohc;\r
1320 EFI_STATUS Status;\r
1321 ED_DESCRIPTOR *Ed;\r
1322 TD_DESCRIPTOR *HeadTd;\r
1323 OHCI_ED_RESULT EdResult;\r
1324 VOID *UCBuffer;\r
1325\r
1326 if ((EndPointAddress & 0x80) == 0 || Data == NULL || DataLength == NULL || *DataLength == 0 ||\r
1327 (IsSlowDevice && MaxPacketLength > 8) || (!IsSlowDevice && MaxPacketLength > 64) ||\r
1328 DataToggle == NULL || (*DataToggle != 0 && *DataToggle != 1) || TransferResult == NULL) {\r
1329 return EFI_INVALID_PARAMETER;\r
1330 }\r
1331\r
1332 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
1333 UCBuffer = AllocatePool (*DataLength);\r
1334 if (UCBuffer == NULL) {\r
1335 return EFI_OUT_OF_RESOURCES;\r
1336 }\r
1337 Status = OhciInterruptTransfer (\r
1338 Ohc,\r
1339 DeviceAddress,\r
1340 EndPointAddress,\r
1341 IsSlowDevice,\r
1342 MaxPacketLength,\r
1343 TRUE,\r
1344 DataToggle,\r
1345 1,\r
1346 UCBuffer,\r
1347 *DataLength,\r
1348 NULL,\r
1349 NULL,\r
1350 FALSE,\r
1351 &Ed,\r
1352 &HeadTd\r
1353 );\r
1354\r
1355 if (!EFI_ERROR (Status)) {\r
1356 Status = CheckIfDone (Ohc, INTERRUPT_LIST, Ed, HeadTd, &EdResult);\r
1357 while (Status == EFI_NOT_READY && TimeOut > 0) {\r
1358 gBS->Stall (1000);\r
1359 TimeOut--;\r
1360 Status = CheckIfDone (Ohc, INTERRUPT_LIST, Ed, HeadTd, &EdResult);\r
1361 }\r
1362\r
1363 *TransferResult = ConvertErrorCode (EdResult.ErrorCode);\r
1364 }\r
1365 CopyMem(Data, UCBuffer, *DataLength);\r
1366 Status = OhciInterruptTransfer (\r
1367 Ohc,\r
1368 DeviceAddress,\r
1369 EndPointAddress,\r
1370 IsSlowDevice,\r
1371 MaxPacketLength,\r
1372 FALSE,\r
1373 DataToggle,\r
1374 0,\r
1375 NULL,\r
1376 0,\r
1377 NULL,\r
1378 NULL,\r
1379 FALSE,\r
1380 NULL,\r
1381 NULL\r
1382 );\r
1383\r
1384 return Status;\r
1385}\r
1386/**\r
1387\r
1388 Submits isochronous transfer to a target USB device.\r
1389\r
1390 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
1391 @param DeviceAddress Represents the address of the target device on the USB,\r
1392 which is assigned during USB enumeration.\r
1393 @param EndPointAddress End point address\r
1394 @param MaximumPacketLength Indicates the maximum packet size that the\r
1395 default control transfer endpoint is capable of\r
1396 sending or receiving.\r
1397 @param Data A pointer to the buffer of data that will be transmitted\r
1398 to USB device or received from USB device.\r
1399 @param DataLength Indicates the size, in bytes, of the data buffer\r
1400 specified by Data.\r
1401 @param TransferResult A pointer to the detailed result information generated\r
1402 by this control transfer.\r
1403\r
1404 @retval EFI_UNSUPPORTED This interface not available\r
1405 @retval EFI_INVALID_PARAMETER Data is NULL or DataLength is 0 or TransferResult is NULL\r
1406\r
1407**/\r
1408\r
1409\r
1410EFI_STATUS\r
1411EFIAPI\r
1412OhciIsochronousTransfer (\r
1413 IN EFI_USB_HC_PROTOCOL *This,\r
1414 IN UINT8 DeviceAddress,\r
1415 IN UINT8 EndPointAddress,\r
1416 IN UINT8 MaximumPacketLength,\r
1417 IN OUT VOID *Data,\r
1418 IN OUT UINTN DataLength,\r
1419 OUT UINT32 *TransferResult\r
1420 )\r
1421{\r
1422 if (Data == NULL || DataLength == 0 || TransferResult == NULL) {\r
1423 return EFI_INVALID_PARAMETER;\r
1424 }\r
1425\r
1426 return EFI_UNSUPPORTED;\r
1427}\r
1428\r
1429/**\r
1430\r
1431 Submits Async isochronous transfer to a target USB device.\r
1432\r
1433 @param his A pointer to the EFI_USB_HC_PROTOCOL instance.\r
1434 @param DeviceAddress Represents the address of the target device on the USB,\r
1435 which is assigned during USB enumeration.\r
1436 @param EndPointAddress End point address\r
1437 @param MaximumPacketLength Indicates the maximum packet size that the\r
1438 default control transfer endpoint is capable of\r
1439 sending or receiving.\r
1440 @param Data A pointer to the buffer of data that will be transmitted\r
1441 to USB device or received from USB device.\r
1442 @param IsochronousCallBack When the transfer complete, the call back function will be called\r
1443 @param Context Pass to the call back function as parameter\r
1444\r
1445 @retval EFI_UNSUPPORTED This interface not available\r
1446 @retval EFI_INVALID_PARAMETER Data is NULL or Datalength is 0\r
1447\r
1448**/\r
1449\r
1450EFI_STATUS\r
1451EFIAPI\r
1452OhciAsyncIsochronousTransfer (\r
1453 IN EFI_USB_HC_PROTOCOL *This,\r
1454 IN UINT8 DeviceAddress,\r
1455 IN UINT8 EndPointAddress,\r
1456 IN UINT8 MaximumPacketLength,\r
1457 IN OUT VOID *Data,\r
1458 IN OUT UINTN DataLength,\r
1459 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,\r
1460 IN VOID *Context OPTIONAL\r
1461 )\r
1462{\r
1463\r
1464 if (Data == NULL || DataLength == 0) {\r
1465 return EFI_INVALID_PARAMETER;\r
1466 }\r
1467\r
1468 return EFI_UNSUPPORTED;\r
1469}\r
1470\r
1471/**\r
1472\r
1473 Retrieves the number of root hub ports.\r
1474\r
1475 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
1476 @param NumOfPorts A pointer to the number of the root hub ports.\r
1477\r
1478 @retval EFI_SUCCESS The port number was retrieved successfully.\r
1479**/\r
1480EFI_STATUS\r
1481EFIAPI\r
1482OhciGetRootHubNumOfPorts (\r
1483 IN EFI_USB_HC_PROTOCOL *This,\r
1484 OUT UINT8 *NumOfPorts\r
1485 )\r
1486{\r
1487 USB_OHCI_HC_DEV *Ohc;\r
1488 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
1489\r
1490 if (NumOfPorts == NULL) {\r
1491 return EFI_INVALID_PARAMETER;\r
1492 }\r
1493\r
1494 *NumOfPorts = (UINT8)OhciGetRootHubDescriptor(Ohc, RH_NUM_DS_PORTS);\r
1495\r
1496 return EFI_SUCCESS;\r
1497}\r
1498/**\r
1499\r
1500 Retrieves the current status of a USB root hub port.\r
1501\r
1502 @param This A pointer to the EFI_USB_HC_PROTOCOL.\r
1503 @param PortNumber Specifies the root hub port from which the status\r
1504 is to be retrieved. This value is zero-based. For example,\r
1505 if a root hub has two ports, then the first port is numbered 0,\r
1506 and the second port is numbered 1.\r
1507 @param PortStatus A pointer to the current port status bits and\r
1508 port status change bits.\r
1509\r
1510 @retval EFI_SUCCESS The status of the USB root hub port specified by PortNumber\r
1511 was returned in PortStatus.\r
1512 @retval EFI_INVALID_PARAMETER Port number not valid\r
1513**/\r
1514\r
1515\r
1516EFI_STATUS\r
1517EFIAPI\r
1518OhciGetRootHubPortStatus (\r
1519 IN EFI_USB_HC_PROTOCOL *This,\r
1520 IN UINT8 PortNumber,\r
1521 OUT EFI_USB_PORT_STATUS *PortStatus\r
1522 )\r
1523{\r
1524 USB_OHCI_HC_DEV *Ohc;\r
1525 UINT8 NumOfPorts;\r
1526\r
1527 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
1528\r
1529 OhciGetRootHubNumOfPorts (This, &NumOfPorts);\r
1530 if (PortNumber >= NumOfPorts) {\r
1531 return EFI_INVALID_PARAMETER;\r
1532 }\r
1533 PortStatus->PortStatus = 0;\r
1534 PortStatus->PortChangeStatus = 0;\r
1535\r
1536 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_CURR_CONNECT_STAT)) {\r
1537 PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;\r
1538 }\r
1539 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_ENABLE_STAT)) {\r
1540 PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;\r
1541 }\r
1542 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_SUSPEND_STAT)) {\r
1543 PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;\r
1544 }\r
1545 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_OC_INDICATOR)) {\r
1546 PortStatus->PortStatus |= USB_PORT_STAT_OVERCURRENT;\r
1547 }\r
1548 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_RESET_STAT)) {\r
1549 PortStatus->PortStatus |= USB_PORT_STAT_RESET;\r
1550 }\r
1551 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_POWER_STAT)) {\r
1552 PortStatus->PortStatus |= USB_PORT_STAT_POWER;\r
1553 }\r
1554 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_LSDEVICE_ATTACHED)) {\r
1555 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
1556 }\r
1557 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE)) {\r
1558 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;\r
1559 }\r
1560 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE)) {\r
1561 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;\r
1562 }\r
1563 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE)) {\r
1564 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_SUSPEND;\r
1565 }\r
1566 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE)) {\r
1567 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_OVERCURRENT;\r
1568 }\r
1569 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE)) {\r
1570 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_RESET;\r
1571 }\r
1572\r
1573 return EFI_SUCCESS;\r
1574}\r
1575/**\r
1576\r
1577 Sets a feature for the specified root hub port.\r
1578\r
1579 @param This A pointer to the EFI_USB_HC_PROTOCOL.\r
1580 @param PortNumber Specifies the root hub port whose feature\r
1581 is requested to be set.\r
1582 @param PortFeature Indicates the feature selector associated\r
1583 with the feature set request.\r
1584\r
1585 @retval EFI_SUCCESS The feature specified by PortFeature was set for the\r
1586 USB root hub port specified by PortNumber.\r
1587 @retval EFI_DEVICE_ERROR Set feature failed because of hardware issue\r
1588 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
1589**/\r
1590EFI_STATUS\r
1591EFIAPI\r
1592OhciSetRootHubPortFeature (\r
1593 IN EFI_USB_HC_PROTOCOL *This,\r
1594 IN UINT8 PortNumber,\r
1595 IN EFI_USB_PORT_FEATURE PortFeature\r
1596 )\r
1597{\r
1598 USB_OHCI_HC_DEV *Ohc;\r
1599 EFI_STATUS Status;\r
1600 UINT8 NumOfPorts;\r
1601 UINTN RetryTimes;\r
1602\r
1603 OhciGetRootHubNumOfPorts (This, &NumOfPorts);\r
1604 if (PortNumber >= NumOfPorts) {\r
1605 return EFI_INVALID_PARAMETER;\r
1606 }\r
1607\r
1608 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
1609\r
1610 Status = EFI_SUCCESS;\r
1611\r
1612\r
1613 switch (PortFeature) {\r
1614 case EfiUsbPortPower:\r
1615 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_POWER);\r
1616\r
1617 //\r
1618 // Verify the state\r
1619 //\r
1620 RetryTimes = 0;\r
1621 do {\r
1622 gBS->Stall (1000);\r
1623 RetryTimes++;\r
1624 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 0 &&\r
1625 RetryTimes < MAX_RETRY_TIMES);\r
1626\r
1627 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1628 return EFI_DEVICE_ERROR;\r
1629 }\r
1630 break;\r
1631\r
1632 case EfiUsbPortReset:\r
1633 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_RESET);\r
1634\r
1635 //\r
1636 // Verify the state\r
1637 //\r
1638 RetryTimes = 0;\r
1639 do {\r
1640 gBS->Stall (1000);\r
1641 RetryTimes++;\r
1642 } while ((OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 0 ||\r
1643 OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT) == 1) &&\r
1644 RetryTimes < MAX_RETRY_TIMES);\r
1645\r
1646 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1647 return EFI_DEVICE_ERROR;\r
1648 }\r
1649\r
1650 OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE);\r
1651 break;\r
1652\r
1653 case EfiUsbPortEnable:\r
1654 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_ENABLE);\r
1655\r
1656 //\r
1657 // Verify the state\r
1658 //\r
1659 RetryTimes = 0;\r
1660 do {\r
1661 gBS->Stall (1000);\r
1662 RetryTimes++;\r
1663 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 0 &&\r
1664 RetryTimes < MAX_RETRY_TIMES);\r
1665\r
1666 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1667 return EFI_DEVICE_ERROR;\r
1668 }\r
1669 break;\r
1670\r
1671\r
1672 case EfiUsbPortSuspend:\r
1673 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_SUSPEND);\r
1674\r
1675 //\r
1676 // Verify the state\r
1677 //\r
1678 RetryTimes = 0;\r
1679 do {\r
1680 gBS->Stall (1000);\r
1681 RetryTimes++;\r
1682 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 0 &&\r
1683 RetryTimes < MAX_RETRY_TIMES);\r
1684\r
1685 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1686 return EFI_DEVICE_ERROR;\r
1687 }\r
1688 break;\r
1689\r
1690 default:\r
1691 return EFI_INVALID_PARAMETER;\r
1692 }\r
1693\r
1694 return Status;\r
1695}\r
1696\r
1697/**\r
1698\r
1699 Clears a feature for the specified root hub port.\r
1700\r
1701 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
1702 @param PortNumber Specifies the root hub port whose feature\r
1703 is requested to be cleared.\r
1704 @param PortFeature Indicates the feature selector associated with the\r
1705 feature clear request.\r
1706\r
1707 @retval EFI_SUCCESS The feature specified by PortFeature was cleared for the\r
1708 USB root hub port specified by PortNumber.\r
1709 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
1710 @retval EFI_DEVICE_ERROR Some error happened when clearing feature\r
1711**/\r
1712EFI_STATUS\r
1713EFIAPI\r
1714OhciClearRootHubPortFeature (\r
1715 IN EFI_USB_HC_PROTOCOL *This,\r
1716 IN UINT8 PortNumber,\r
1717 IN EFI_USB_PORT_FEATURE PortFeature\r
1718 )\r
1719{\r
1720 USB_OHCI_HC_DEV *Ohc;\r
1721 EFI_STATUS Status;\r
1722 UINT8 NumOfPorts;\r
1723 UINTN RetryTimes;\r
1724\r
1725\r
1726 OhciGetRootHubNumOfPorts (This, &NumOfPorts);\r
1727 if (PortNumber >= NumOfPorts) {\r
1728 return EFI_INVALID_PARAMETER;\r
1729 }\r
1730\r
1731 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
1732\r
1733 Status = EFI_SUCCESS;\r
1734\r
1735 switch (PortFeature) {\r
1736 case EfiUsbPortEnable:\r
1737 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_ENABLE);\r
1738\r
1739 //\r
1740 // Verify the state\r
1741 //\r
1742 RetryTimes = 0;\r
1743 do {\r
1744 gBS->Stall (1000);\r
1745 RetryTimes++;\r
1746 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 1 &&\r
1747 RetryTimes < MAX_RETRY_TIMES);\r
1748\r
1749 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1750 return EFI_DEVICE_ERROR;\r
1751 }\r
1752 break;\r
1753\r
1754 case EfiUsbPortSuspend:\r
1755 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_SUSPEND_STATUS);\r
1756\r
1757 //\r
1758 // Verify the state\r
1759 //\r
1760 RetryTimes = 0;\r
1761 do {\r
1762 gBS->Stall (1000);\r
1763 RetryTimes++;\r
1764 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 1 &&\r
1765 RetryTimes < MAX_RETRY_TIMES);\r
1766\r
1767 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1768 return EFI_DEVICE_ERROR;\r
1769 }\r
1770 break;\r
1771\r
1772 case EfiUsbPortReset:\r
1773 break;\r
1774\r
1775 case EfiUsbPortPower:\r
1776 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_POWER);\r
1777\r
1778 //\r
1779 // Verify the state\r
1780 //\r
1781 RetryTimes = 0;\r
1782 do {\r
1783 gBS->Stall (1000);\r
1784 RetryTimes++;\r
1785 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 1 &&\r
1786 RetryTimes < MAX_RETRY_TIMES);\r
1787\r
1788 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1789 return EFI_DEVICE_ERROR;\r
1790 }\r
1791 break;\r
1792\r
1793 case EfiUsbPortConnectChange:\r
1794 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE);\r
1795\r
1796 //\r
1797 // Verify the state\r
1798 //\r
1799 RetryTimes = 0;\r
1800 do {\r
1801 gBS->Stall (1000);\r
1802 RetryTimes++;\r
1803 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE) == 1 &&\r
1804 RetryTimes < MAX_RETRY_TIMES);\r
1805\r
1806 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1807 return EFI_DEVICE_ERROR;\r
1808 }\r
1809 break;\r
1810\r
1811 case EfiUsbPortResetChange:\r
1812 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE);\r
1813\r
1814 //\r
1815 // Verify the state\r
1816 //\r
1817 RetryTimes = 0;\r
1818 do {\r
1819 gBS->Stall (1000);\r
1820 RetryTimes++;\r
1821 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 1 &&\r
1822 RetryTimes < MAX_RETRY_TIMES);\r
1823\r
1824 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1825 return EFI_DEVICE_ERROR;\r
1826 }\r
1827 break;\r
1828\r
1829\r
1830 case EfiUsbPortEnableChange:\r
1831 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE);\r
1832\r
1833 //\r
1834 // Verify the state\r
1835 //\r
1836 RetryTimes = 0;\r
1837 do {\r
1838 gBS->Stall (1000);\r
1839 RetryTimes++;\r
1840 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE) == 1 &&\r
1841 RetryTimes < MAX_RETRY_TIMES);\r
1842\r
1843 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1844 return EFI_DEVICE_ERROR;\r
1845 }\r
1846 break;\r
1847\r
1848 case EfiUsbPortSuspendChange:\r
1849 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE);\r
1850\r
1851 //\r
1852 // Verify the state\r
1853 //\r
1854 RetryTimes = 0;\r
1855 do {\r
1856 gBS->Stall (1000);\r
1857 RetryTimes++;\r
1858 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE) == 1 &&\r
1859 RetryTimes < MAX_RETRY_TIMES);\r
1860\r
1861 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1862 return EFI_DEVICE_ERROR;\r
1863 }\r
1864 break;\r
1865\r
1866 case EfiUsbPortOverCurrentChange:\r
1867 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE);\r
1868\r
1869 //\r
1870 // Verify the state\r
1871 //\r
1872 RetryTimes = 0;\r
1873 do {\r
1874 gBS->Stall (1000);\r
1875 RetryTimes++;\r
1876 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE) == 1 &&\r
1877 RetryTimes < MAX_RETRY_TIMES);\r
1878\r
1879 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1880 return EFI_DEVICE_ERROR;\r
1881 }\r
1882 break;\r
1883\r
1884 default:\r
1885 return EFI_INVALID_PARAMETER;\r
1886 }\r
1887\r
1888 return Status;\r
1889}\r
1890\r
1891EFI_DRIVER_BINDING_PROTOCOL gOhciDriverBinding = {\r
1892 OHCIDriverBindingSupported,\r
1893 OHCIDriverBindingStart,\r
1894 OHCIDriverBindingStop,\r
1895 0x10,\r
1896 NULL,\r
1897 NULL\r
1898};\r
1899\r
1900\r
1901/**\r
1902 Entry point for EFI drivers.\r
1903\r
1904 @param ImageHandle EFI_HANDLE.\r
1905 @param SystemTable EFI_SYSTEM_TABLE.\r
1906\r
1907 @retval EFI_SUCCESS Driver is successfully loaded.\r
1908 @return Others Failed.\r
1909\r
1910**/\r
1911EFI_STATUS\r
1912EFIAPI\r
1913OHCIDriverEntryPoint (\r
1914 IN EFI_HANDLE ImageHandle,\r
1915 IN EFI_SYSTEM_TABLE *SystemTable\r
1916 )\r
1917{\r
1918 return EfiLibInstallDriverBindingComponentName2 (\r
1919 ImageHandle,\r
1920 SystemTable,\r
1921 &gOhciDriverBinding,\r
1922 ImageHandle,\r
1923 &gOhciComponentName,\r
1924 &gOhciComponentName2\r
1925 );\r
1926}\r
1927\r
1928\r
1929/**\r
1930 Test to see if this driver supports ControllerHandle. Any\r
1931 ControllerHandle that has UsbHcProtocol installed will be supported.\r
1932\r
1933 @param This Protocol instance pointer.\r
1934 @param Controller Handle of device to test.\r
1935 @param RemainingDevicePath Not used.\r
1936\r
1937 @return EFI_SUCCESS This driver supports this device.\r
1938 @return EFI_UNSUPPORTED This driver does not support this device.\r
1939\r
1940**/\r
1941EFI_STATUS\r
1942EFIAPI\r
1943OHCIDriverBindingSupported (\r
1944 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1945 IN EFI_HANDLE Controller,\r
1946 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
1947 )\r
1948{\r
1949 EFI_STATUS Status;\r
1950 EFI_PCI_IO_PROTOCOL *PciIo;\r
1951 USB_CLASSC UsbClassCReg;\r
1952 //\r
1953 // Test whether there is PCI IO Protocol attached on the controller handle.\r
1954 //\r
1955 Status = gBS->OpenProtocol (\r
1956 Controller,\r
1957 &gEfiPciIoProtocolGuid,\r
1958 (VOID **) &PciIo,\r
1959 This->DriverBindingHandle,\r
1960 Controller,\r
1961 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1962 );\r
1963\r
1964 if (EFI_ERROR (Status)) {\r
1965 return EFI_UNSUPPORTED;\r
1966 }\r
1967\r
1968 Status = PciIo->Pci.Read (\r
1969 PciIo,\r
1970 EfiPciIoWidthUint8,\r
1971 PCI_CLASSCODE_OFFSET,\r
1972 sizeof (USB_CLASSC) / sizeof (UINT8),\r
1973 &UsbClassCReg\r
1974 );\r
1975\r
1976 if (EFI_ERROR (Status)) {\r
1977 Status = EFI_UNSUPPORTED;\r
1978 goto ON_EXIT;\r
1979 }\r
1980 //\r
1981 // Test whether the controller belongs to OHCI type\r
1982 //\r
1983 if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||\r
1984 (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||\r
1985 (UsbClassCReg.ProgInterface != PCI_IF_OHCI)\r
1986 ) {\r
1987\r
1988 Status = EFI_UNSUPPORTED;\r
1989 }\r
1990ON_EXIT:\r
1991 gBS->CloseProtocol (\r
1992 Controller,\r
1993 &gEfiPciIoProtocolGuid,\r
1994 This->DriverBindingHandle,\r
1995 Controller\r
1996 );\r
1997\r
1998 return Status;\r
1999\r
2000}\r
2001\r
2002/**\r
2003\r
2004 Allocate and initialize the empty OHCI device.\r
2005\r
2006 @param PciIo The PCIIO to use.\r
2007 @param OriginalPciAttributes The original PCI attributes.\r
2008\r
2009 @return Allocated OHCI device If err, return NULL.\r
2010\r
2011**/\r
2012\r
2013USB_OHCI_HC_DEV *\r
2014OhciAllocateDev (\r
2015 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
2016 IN UINT64 OriginalPciAttributes\r
2017 )\r
2018{\r
2019 USB_OHCI_HC_DEV *Ohc;\r
2020 EFI_STATUS Status;\r
2021 VOID *Buf;\r
2022 EFI_PHYSICAL_ADDRESS PhyAddr;\r
2023 VOID *Map;\r
2024 UINTN Pages;\r
2025 UINTN Bytes;\r
2026\r
2027 Ohc = AllocateZeroPool (sizeof (USB_OHCI_HC_DEV));\r
2028 if (Ohc == NULL) {\r
2029 return NULL;\r
2030 }\r
2031\r
2032 Ohc->Signature = USB_OHCI_HC_DEV_SIGNATURE;\r
2033 Ohc->PciIo = PciIo;\r
2034\r
2035 Ohc->UsbHc.Reset = OhciReset;\r
2036 Ohc->UsbHc.GetState = OhciGetState;\r
2037 Ohc->UsbHc.SetState = OhciSetState;\r
2038 Ohc->UsbHc.ControlTransfer = OhciControlTransfer;\r
2039 Ohc->UsbHc.BulkTransfer = OhciBulkTransfer;\r
2040 Ohc->UsbHc.AsyncInterruptTransfer = OhciAsyncInterruptTransfer;\r
2041 Ohc->UsbHc.SyncInterruptTransfer = OhciSyncInterruptTransfer;\r
2042 Ohc->UsbHc.IsochronousTransfer = OhciIsochronousTransfer;\r
2043 Ohc->UsbHc.AsyncIsochronousTransfer = OhciAsyncIsochronousTransfer;\r
2044 Ohc->UsbHc.GetRootHubPortNumber = OhciGetRootHubNumOfPorts;\r
2045 Ohc->UsbHc.GetRootHubPortStatus = OhciGetRootHubPortStatus;\r
2046 Ohc->UsbHc.SetRootHubPortFeature = OhciSetRootHubPortFeature;\r
2047 Ohc->UsbHc.ClearRootHubPortFeature = OhciClearRootHubPortFeature;\r
2048 Ohc->UsbHc.MajorRevision = 0x1;\r
2049 Ohc->UsbHc.MinorRevision = 0x1;\r
2050\r
2051 Ohc->OriginalPciAttributes = OriginalPciAttributes;\r
2052\r
2053 Ohc->HccaMemoryBlock = NULL;\r
2054 Ohc->HccaMemoryMapping = NULL;\r
2055 Ohc->HccaMemoryBuf = NULL;\r
2056 Ohc->HccaMemoryPages = 0;\r
2057 Ohc->InterruptContextList = NULL;\r
2058 Ohc->ControllerNameTable = NULL;\r
2059 Ohc->HouseKeeperTimer = NULL;\r
2060\r
2061 Ohc->MemPool = UsbHcInitMemPool(PciIo, TRUE, 0);\r
2062 if(Ohc->MemPool == NULL) {\r
2063 goto FREE_DEV_BUFFER;\r
2064 }\r
2065\r
2066 Bytes = 4096;\r
2067 Pages = EFI_SIZE_TO_PAGES (Bytes);\r
2068\r
2069 Status = PciIo->AllocateBuffer (\r
2070 PciIo,\r
2071 AllocateAnyPages,\r
2072 EfiBootServicesData,\r
2073 Pages,\r
2074 &Buf,\r
2075 0\r
2076 );\r
2077\r
2078 if (EFI_ERROR (Status)) {\r
2079 goto FREE_MEM_POOL;\r
2080 }\r
2081\r
2082 Status = PciIo->Map (\r
2083 PciIo,\r
2084 EfiPciIoOperationBusMasterCommonBuffer,\r
2085 Buf,\r
2086 &Bytes,\r
2087 &PhyAddr,\r
2088 &Map\r
2089 );\r
2090\r
2091 if (EFI_ERROR (Status) || (Bytes != 4096)) {\r
2092 goto FREE_MEM_PAGE;\r
2093 }\r
2094\r
2095 Ohc->HccaMemoryBlock = (HCCA_MEMORY_BLOCK *)(UINTN)PhyAddr;\r
2096 Ohc->HccaMemoryMapping = Map;\r
2097 Ohc->HccaMemoryBuf = (VOID *)(UINTN)Buf;\r
2098 Ohc->HccaMemoryPages = Pages;\r
2099\r
2100 return Ohc;\r
2101\r
2102FREE_MEM_PAGE:\r
2103 PciIo->FreeBuffer (PciIo, Pages, Buf);\r
2104FREE_MEM_POOL:\r
2105 UsbHcFreeMemPool (Ohc->MemPool);\r
2106FREE_DEV_BUFFER:\r
2107 FreePool(Ohc);\r
2108\r
2109 return NULL;\r
2110}\r
2111/**\r
2112\r
2113 Free the OHCI device and release its associated resources.\r
2114\r
2115 @param Ohc The OHCI device to release.\r
2116\r
2117**/\r
2118VOID\r
2119OhciFreeDev (\r
2120 IN USB_OHCI_HC_DEV *Ohc\r
2121 )\r
2122{\r
2123 OhciFreeFixedIntMemory (Ohc);\r
2124\r
2125 if (Ohc->HouseKeeperTimer != NULL) {\r
2126 gBS->CloseEvent (Ohc->HouseKeeperTimer);\r
2127 }\r
2128\r
2129 if (Ohc->ExitBootServiceEvent != NULL) {\r
2130 gBS->CloseEvent (Ohc->ExitBootServiceEvent);\r
2131 }\r
2132\r
2133 if (Ohc->MemPool != NULL) {\r
2134 UsbHcFreeMemPool (Ohc->MemPool);\r
2135 }\r
2136\r
2137 if (Ohc->HccaMemoryMapping != NULL ) {\r
2138 Ohc->PciIo->FreeBuffer (Ohc->PciIo, Ohc->HccaMemoryPages, Ohc->HccaMemoryBuf);\r
2139 }\r
2140\r
2141 if (Ohc->ControllerNameTable != NULL) {\r
2142 FreeUnicodeStringTable (Ohc->ControllerNameTable);\r
2143 }\r
2144\r
2145 FreePool (Ohc);\r
2146}\r
2147/**\r
2148\r
2149 Uninstall all Ohci Interface.\r
2150\r
2151 @param Controller Controller handle.\r
2152 @param This Protocol instance pointer.\r
2153\r
2154**/\r
2155VOID\r
2156OhciCleanDevUp (\r
2157 IN EFI_HANDLE Controller,\r
2158 IN EFI_USB_HC_PROTOCOL *This\r
2159 )\r
2160{\r
2161 USB_OHCI_HC_DEV *Ohc;\r
2162\r
2163 //\r
2164 // Retrieve private context structure\r
2165 //\r
2166 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
2167\r
2168 //\r
2169 // Uninstall the USB_HC and USB_HC2 protocol\r
2170 //\r
2171 gBS->UninstallProtocolInterface (\r
2172 Controller,\r
2173 &gEfiUsbHcProtocolGuid,\r
2174 &Ohc->UsbHc\r
2175 );\r
2176\r
2177 //\r
2178 // Cancel the timer event\r
2179 //\r
2180 gBS->SetTimer (Ohc->HouseKeeperTimer, TimerCancel, 0);\r
2181\r
2182 //\r
2183 // Stop the host controller\r
2184 //\r
2185 OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | ISOCHRONOUS_ENABLE | BULK_ENABLE, 0);\r
2186 This->Reset (This, EFI_USB_HC_RESET_GLOBAL);\r
2187 This->SetState (This, EfiUsbHcStateHalt);\r
2188\r
2189 //\r
2190 // Free resources\r
2191 //\r
2192 OhciFreeDynamicIntMemory (Ohc);\r
2193\r
2194 //\r
2195 // Restore original PCI attributes\r
2196 //\r
2197 Ohc->PciIo->Attributes (\r
2198 Ohc->PciIo,\r
2199 EfiPciIoAttributeOperationSet,\r
2200 Ohc->OriginalPciAttributes,\r
2201 NULL\r
2202 );\r
2203\r
2204 //\r
2205 // Free the private context structure\r
2206 //\r
2207 OhciFreeDev (Ohc);\r
2208}\r
2209\r
2210/**\r
2211\r
2212 One notified function to stop the Host Controller when gBS->ExitBootServices() called.\r
2213\r
2214 @param Event Pointer to this event\r
2215 @param Context Event hanlder private data\r
2216**/\r
2217VOID\r
2218EFIAPI\r
2219OhcExitBootService (\r
2220 EFI_EVENT Event,\r
2221 VOID *Context\r
2222 )\r
2223{\r
2224 USB_OHCI_HC_DEV *Ohc;\r
2225 EFI_USB_HC_PROTOCOL *UsbHc;\r
2226 Ohc = (USB_OHCI_HC_DEV *) Context;\r
2227\r
2228 UsbHc = &Ohc->UsbHc;\r
2229 //\r
2230 // Stop the Host Controller\r
2231 //\r
2232 //OhciStopHc (Ohc, OHC_GENERIC_TIMEOUT);\r
2233 OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | ISOCHRONOUS_ENABLE | BULK_ENABLE, 0);\r
2234 UsbHc->Reset (UsbHc, EFI_USB_HC_RESET_GLOBAL);\r
2235 UsbHc->SetState (UsbHc, EfiUsbHcStateHalt);\r
2236\r
2237 return;\r
2238}\r
2239\r
2240\r
2241/**\r
2242 Starting the Usb OHCI Driver.\r
2243\r
2244 @param This Protocol instance pointer.\r
2245 @param Controller Handle of device to test.\r
2246 @param RemainingDevicePath Not used.\r
2247\r
2248 @retval EFI_SUCCESS This driver supports this device.\r
2249 @retval EFI_UNSUPPORTED This driver does not support this device.\r
2250 @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.\r
2251 EFI_OUT_OF_RESOURCES- Failed due to resource shortage.\r
2252\r
2253**/\r
2254EFI_STATUS\r
2255EFIAPI\r
2256OHCIDriverBindingStart (\r
2257 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
2258 IN EFI_HANDLE Controller,\r
2259 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
2260 )\r
2261{\r
2262 EFI_STATUS Status;\r
2263 EFI_PCI_IO_PROTOCOL *PciIo;\r
2264 USB_OHCI_HC_DEV *Ohc;\r
2265 UINT64 Supports;\r
2266 UINT64 OriginalPciAttributes;\r
2267 BOOLEAN PciAttributesSaved;\r
2268\r
2269 //\r
2270 // Open PCIIO, then enable the HC device and turn off emulation\r
2271 //\r
2272 Ohc = NULL;\r
2273 Status = gBS->OpenProtocol (\r
2274 Controller,\r
2275 &gEfiPciIoProtocolGuid,\r
2276 (VOID **) &PciIo,\r
2277 This->DriverBindingHandle,\r
2278 Controller,\r
2279 EFI_OPEN_PROTOCOL_BY_DRIVER\r
2280 );\r
2281\r
2282 if (EFI_ERROR (Status)) {\r
2283 return Status;\r
2284 }\r
2285\r
2286 PciAttributesSaved = FALSE;\r
2287 //\r
2288 // Save original PCI attributes\r
2289 //\r
2290 Status = PciIo->Attributes (\r
2291 PciIo,\r
2292 EfiPciIoAttributeOperationGet,\r
2293 0,\r
2294 &OriginalPciAttributes\r
2295 );\r
2296\r
2297 if (EFI_ERROR (Status)) {\r
2298 goto CLOSE_PCIIO;\r
2299 }\r
2300 PciAttributesSaved = TRUE;\r
2301\r
2302 //\r
2303 // Robustnesss improvement such as for UoL\r
2304 // Default is not required.\r
2305 //\r
2306 //if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {\r
2307 // OhciTurnOffUsbEmulation (PciIo);\r
2308 //}\r
2309\r
2310 Status = PciIo->Attributes (\r
2311 PciIo,\r
2312 EfiPciIoAttributeOperationSupported,\r
2313 0,\r
2314 &Supports\r
2315 );\r
2316 if (!EFI_ERROR (Status)) {\r
2317 Supports &= EFI_PCI_DEVICE_ENABLE;\r
2318 Status = PciIo->Attributes (\r
2319 PciIo,\r
2320 EfiPciIoAttributeOperationEnable,\r
2321 Supports,\r
2322 NULL\r
2323 );\r
2324 }\r
2325\r
2326 if (EFI_ERROR (Status)) {\r
2327 goto CLOSE_PCIIO;\r
2328 }\r
2329 //\r
2330 //Allocate memory for OHC private data structure\r
2331 //\r
2332 Ohc = OhciAllocateDev(PciIo, OriginalPciAttributes);\r
2333 if (Ohc == NULL){\r
2334 Status = EFI_OUT_OF_RESOURCES;\r
2335 goto CLOSE_PCIIO;\r
2336 }\r
2337\r
2338 //Status = OhciInitializeInterruptList ( Uhc );\r
2339 //if (EFI_ERROR (Status)) {\r
2340 // goto FREE_OHC;\r
2341 //}\r
2342\r
2343 //\r
2344 // Set 0.01 s timer\r
2345 //\r
2346 Status = gBS->CreateEvent (\r
2347 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
2348 TPL_NOTIFY,\r
2349 OhciHouseKeeper,\r
2350 Ohc,\r
2351 &Ohc->HouseKeeperTimer\r
2352 );\r
2353 if (EFI_ERROR (Status)) {\r
2354 goto FREE_OHC;\r
2355 }\r
2356\r
2357 Status = gBS->SetTimer (Ohc->HouseKeeperTimer, TimerPeriodic, 10 * 1000 * 10);\r
2358 if (EFI_ERROR (Status)) {\r
2359 goto FREE_OHC;\r
2360 }\r
2361\r
2362 //\r
2363 //Install Host Controller Protocol\r
2364 //\r
2365 Status = gBS->InstallProtocolInterface (\r
2366 &Controller,\r
2367 &gEfiUsbHcProtocolGuid,\r
2368 EFI_NATIVE_INTERFACE,\r
2369 &Ohc->UsbHc\r
2370 );\r
2371 if (EFI_ERROR (Status)) {\r
2372 DEBUG ((EFI_D_INFO, "Install protocol error"));\r
2373 goto FREE_OHC;\r
2374 }\r
2375 //\r
2376 // Create event to stop the HC when exit boot service.\r
2377 //\r
2378 Status = gBS->CreateEventEx (\r
2379 EVT_NOTIFY_SIGNAL,\r
2380 TPL_NOTIFY,\r
2381 OhcExitBootService,\r
2382 Ohc,\r
2383 &gEfiEventExitBootServicesGuid,\r
2384 &Ohc->ExitBootServiceEvent\r
2385 );\r
2386 if (EFI_ERROR (Status)) {\r
2387 DEBUG ((EFI_D_INFO, "Create exit boot event error"));\r
2388 goto UNINSTALL_USBHC;\r
2389 }\r
2390 AddUnicodeString2 (\r
2391 "eng",\r
2392 gOhciComponentName.SupportedLanguages,\r
2393 &Ohc->ControllerNameTable,\r
2394 L"Usb Universal Host Controller",\r
2395 TRUE\r
2396 );\r
2397 AddUnicodeString2 (\r
2398 "en",\r
2399 gOhciComponentName2.SupportedLanguages,\r
2400 &Ohc->ControllerNameTable,\r
2401 L"Usb Universal Host Controller",\r
2402 FALSE\r
2403 );\r
2404\r
2405 return EFI_SUCCESS;\r
2406\r
2407UNINSTALL_USBHC:\r
2408 gBS->UninstallMultipleProtocolInterfaces (\r
2409 Controller,\r
2410 &gEfiUsbHcProtocolGuid,\r
2411 &Ohc->UsbHc,\r
2412 NULL\r
2413 );\r
2414\r
2415FREE_OHC:\r
2416 OhciFreeDev (Ohc);\r
2417\r
2418CLOSE_PCIIO:\r
2419 if (PciAttributesSaved) {\r
2420 //\r
2421 // Restore original PCI attributes\r
2422 //\r
2423 PciIo->Attributes (\r
2424 PciIo,\r
2425 EfiPciIoAttributeOperationSet,\r
2426 OriginalPciAttributes,\r
2427 NULL\r
2428 );\r
2429 }\r
2430\r
2431 gBS->CloseProtocol (\r
2432 Controller,\r
2433 &gEfiPciIoProtocolGuid,\r
2434 This->DriverBindingHandle,\r
2435 Controller\r
2436 );\r
2437 return Status;\r
2438}\r
2439\r
2440/**\r
2441 Stop this driver on ControllerHandle. Support stoping any child handles\r
2442 created by this driver.\r
2443\r
2444 @param This Protocol instance pointer.\r
2445 @param Controller Handle of device to stop driver on.\r
2446 @param NumberOfChildren Number of Children in the ChildHandleBuffer.\r
2447 @param ChildHandleBuffer List of handles for the children we need to stop.\r
2448\r
2449 @return EFI_SUCCESS\r
2450 @return others\r
2451\r
2452**/\r
2453EFI_STATUS\r
2454EFIAPI\r
2455OHCIDriverBindingStop (\r
2456 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
2457 IN EFI_HANDLE Controller,\r
2458 IN UINTN NumberOfChildren,\r
2459 IN EFI_HANDLE *ChildHandleBuffer\r
2460 )\r
2461{\r
2462 EFI_STATUS Status;\r
2463 EFI_USB_HC_PROTOCOL *UsbHc;\r
2464\r
2465 Status = gBS->OpenProtocol (\r
2466 Controller,\r
2467 &gEfiUsbHcProtocolGuid,\r
2468 (VOID **)&UsbHc,\r
2469 This->DriverBindingHandle,\r
2470 Controller,\r
2471 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
2472 );\r
2473 if (EFI_ERROR (Status)) {\r
2474 return Status;\r
2475 }\r
2476\r
2477 OhciCleanDevUp(Controller, UsbHc);\r
2478\r
2479 gBS->CloseProtocol (\r
2480 Controller,\r
2481 &gEfiPciIoProtocolGuid,\r
2482 This->DriverBindingHandle,\r
2483 Controller\r
2484 );\r
2485 return EFI_SUCCESS;\r
2486}\r
2487\r
2488\r