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