]> git.proxmox.com Git - mirror_edk2.git/blame - QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.c
QuarkSocPkg: Fix typos in comments
[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
MK
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
9b6bbcdb
MK
640 UINT32 DataPidDir;\r
641 TD_DESCRIPTOR *HeadTd;\r
642 TD_DESCRIPTOR *DataTd;\r
643 TD_DESCRIPTOR *EmptyTd;\r
644 EFI_STATUS Status;\r
9b6bbcdb
MK
645 UINT8 EndPointNum;\r
646 UINTN TimeCount;\r
647 OHCI_ED_RESULT EdResult;\r
648\r
649 EFI_PCI_IO_PROTOCOL_OPERATION MapOp;\r
650 VOID *Mapping;\r
651 UINTN MapLength;\r
652 EFI_PHYSICAL_ADDRESS MapPyhAddr;\r
653 UINTN LeftLength;\r
654 UINTN ActualSendLength;\r
655 BOOLEAN FirstTD;\r
656\r
657 Mapping = NULL;\r
658 MapLength = 0;\r
659 MapPyhAddr = 0;\r
660 LeftLength = 0;\r
661 Status = EFI_SUCCESS;\r
662\r
663 if (Data == NULL || DataLength == NULL || DataToggle == NULL || TransferResult == NULL ||\r
664 *DataLength == 0 || (*DataToggle != 0 && *DataToggle != 1) ||\r
665 (MaxPacketLength != 8 && MaxPacketLength != 16 &&\r
666 MaxPacketLength != 32 && MaxPacketLength != 64)) {\r
667 return EFI_INVALID_PARAMETER;\r
668 }\r
669\r
670 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
671\r
672 if ((EndPointAddress & 0x80) != 0) {\r
9b6bbcdb
MK
673 DataPidDir = TD_IN_PID;\r
674 MapOp = EfiPciIoOperationBusMasterWrite;\r
675 } else {\r
9b6bbcdb
MK
676 DataPidDir = TD_OUT_PID;\r
677 MapOp = EfiPciIoOperationBusMasterRead;\r
678 }\r
679\r
680 EndPointNum = (EndPointAddress & 0xF);\r
681 EdResult.NextToggle = *DataToggle;\r
682\r
683 Status = OhciSetHcControl (Ohc, BULK_ENABLE, 0);\r
684 if (EFI_ERROR(Status)) {\r
685 DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable BULK_ENABLE\r\n"));\r
686 *TransferResult = EFI_USB_ERR_SYSTEM;\r
687 return EFI_DEVICE_ERROR;\r
688 }\r
689 Status = OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 0);\r
690 if (EFI_ERROR(Status)) {\r
691 DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable BULK_LIST_FILLED\r\n"));\r
692 *TransferResult = EFI_USB_ERR_SYSTEM;\r
693 return EFI_DEVICE_ERROR;\r
694 }\r
695 gBS->Stall(20 * 1000);\r
696\r
697 OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);\r
698\r
699 Ed = OhciCreateED (Ohc);\r
700 if (Ed == NULL) {\r
701 return EFI_OUT_OF_RESOURCES;\r
702 }\r
703 OhciSetEDField (Ed, ED_SKIP, 1);\r
704 OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);\r
705 OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum);\r
706 OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);\r
707 OhciSetEDField (Ed, ED_SPEED, HI_SPEED);\r
708 OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0);\r
709 OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);\r
710 OhciSetEDField (Ed, ED_PDATA, 0);\r
711 OhciSetEDField (Ed, ED_ZERO, 0);\r
712 OhciSetEDField (Ed, ED_TDHEAD_PTR, 0);\r
713 OhciSetEDField (Ed, ED_TDTAIL_PTR, 0);\r
714 OhciSetEDField (Ed, ED_NEXT_EDPTR, 0);\r
715 HeadEd = OhciAttachEDToList (Ohc, BULK_LIST, Ed, NULL);\r
716\r
717 if(Data != NULL) {\r
718 MapLength = *DataLength;\r
719 Status = Ohc->PciIo->Map (Ohc->PciIo, MapOp, (UINT8 *)Data, &MapLength, &MapPyhAddr, &Mapping);\r
720 if (EFI_ERROR(Status)) {\r
721 DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to Map Data Buffer for Bulk\r\n"));\r
722 goto FREE_ED_BUFF;\r
723 }\r
724 }\r
725 //\r
726 //Data Stage\r
727 //\r
728 LeftLength = MapLength;\r
729 ActualSendLength = MapLength;\r
730 HeadTd = NULL;\r
731 FirstTD = TRUE;\r
732 while (LeftLength > 0) {\r
733 ActualSendLength = LeftLength;\r
734 if (LeftLength > MaxPacketLength) {\r
735 ActualSendLength = MaxPacketLength;\r
736 }\r
737 DataTd = OhciCreateTD (Ohc);\r
738 if (DataTd == NULL) {\r
739 DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to allocate buffer for Data Stage TD\r\n"));\r
740 Status = EFI_OUT_OF_RESOURCES;\r
741 goto FREE_OHCI_TDBUFF;\r
742 }\r
743 OhciSetTDField (DataTd, TD_PDATA, 0);\r
744 OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);\r
745 OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);\r
746 OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);\r
747 OhciSetTDField (DataTd, TD_DT_TOGGLE, *DataToggle);\r
748 OhciSetTDField (DataTd, TD_ERROR_CNT, 0);\r
749 OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
750 OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr);\r
751 OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(MapPyhAddr + ActualSendLength - 1));\r
752 OhciSetTDField (DataTd, TD_NEXT_PTR, 0);\r
753 DataTd->ActualSendLength = (UINT32)ActualSendLength;\r
754 DataTd->DataBuffer = (UINT32)MapPyhAddr;\r
755 DataTd->NextTDPointer = 0;\r
756 if (FirstTD) {\r
757 HeadTd = DataTd;\r
758 FirstTD = FALSE;\r
759 } else {\r
760 OhciLinkTD (HeadTd, DataTd);\r
761 }\r
762 *DataToggle ^= 1;\r
763 MapPyhAddr += ActualSendLength;\r
764 LeftLength -= ActualSendLength;\r
765 }\r
766 //\r
767 // Empty Stage\r
768 //\r
769 EmptyTd = OhciCreateTD (Ohc);\r
770 if (EmptyTd == NULL) {\r
771 Status = EFI_OUT_OF_RESOURCES;\r
772 DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to allocate buffer for Empty TD\r\n"));\r
773 goto FREE_OHCI_TDBUFF;\r
774 }\r
775 OhciSetTDField (EmptyTd, TD_PDATA, 0);\r
776 OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0);\r
777 OhciSetTDField (EmptyTd, TD_DIR_PID, 0);\r
778 OhciSetTDField (EmptyTd, TD_DELAY_INT, 0);\r
779 //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle);\r
780 EmptyTd->Word0.DataToggle = 0;\r
781 OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0);\r
782 OhciSetTDField (EmptyTd, TD_COND_CODE, 0);\r
783 OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0);\r
784 OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0);\r
785 OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0);\r
786 EmptyTd->ActualSendLength = 0;\r
787 EmptyTd->DataBuffer = 0;\r
788 EmptyTd->NextTDPointer = 0;\r
789 OhciLinkTD (HeadTd, EmptyTd);\r
790 Ed->TdTailPointer = (UINT32)(UINTN)EmptyTd;\r
791 OhciAttachTDListToED (Ed, HeadTd);\r
792\r
793 OhciSetEDField (Ed, ED_SKIP, 0);\r
794 Status = OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 1);\r
795 if (EFI_ERROR(Status)) {\r
796 *TransferResult = EFI_USB_ERR_SYSTEM;\r
797 Status = EFI_DEVICE_ERROR;\r
798 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable BULK_LIST_FILLED\r\n"));\r
799 goto FREE_OHCI_TDBUFF;\r
800 }\r
801 Status = OhciSetHcControl (Ohc, BULK_ENABLE, 1);\r
802 if (EFI_ERROR(Status)) {\r
803 *TransferResult = EFI_USB_ERR_SYSTEM;\r
804 Status = EFI_DEVICE_ERROR;\r
805 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable BULK_ENABLE\r\n"));\r
806 goto FREE_OHCI_TDBUFF;\r
807 }\r
808 gBS->Stall(20 * 1000);\r
809\r
810 TimeCount = 0;\r
811 Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &EdResult);\r
812 while (Status == EFI_NOT_READY && TimeCount <= TimeOut) {\r
813 gBS->Stall (1000);\r
814 TimeCount++;\r
815 Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &EdResult);\r
816 }\r
817\r
818 *TransferResult = ConvertErrorCode (EdResult.ErrorCode);\r
819\r
820 if (EdResult.ErrorCode != TD_NO_ERROR) {\r
821 if (EdResult.ErrorCode == TD_TOBE_PROCESSED) {\r
822 DEBUG ((EFI_D_INFO, "Bulk pipe timeout, > %d mS\r\n", TimeOut));\r
823 } else {\r
824 DEBUG ((EFI_D_INFO, "Bulk pipe broken\r\n"));\r
825 *DataToggle = EdResult.NextToggle;\r
826 }\r
827 *DataLength = 0;\r
828 } else {\r
829 DEBUG ((EFI_D_INFO, "Bulk transfer successed\r\n"));\r
830 }\r
831 //*DataToggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE);\r
832\r
833FREE_OHCI_TDBUFF:\r
834 OhciSetEDField (Ed, ED_SKIP, 1);\r
835 if (HeadEd == Ed) {\r
836 OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);\r
837 }else {\r
838 HeadEd->NextED = Ed->NextED;\r
839 }\r
840 while (HeadTd) {\r
841 DataTd = HeadTd;\r
842 HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer);\r
843 UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));\r
844 }\r
845\r
846 if(Mapping != NULL) {\r
847 Ohc->PciIo->Unmap(Ohc->PciIo, Mapping);\r
848 }\r
849\r
850FREE_ED_BUFF:\r
851 UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));\r
852\r
853 return Status;\r
854}\r
855/**\r
856\r
857 Submits an interrupt transfer to an interrupt endpoint of a USB device.\r
858\r
859 @param Ohc Device private data\r
860 @param DeviceAddress Represents the address of the target device on the USB,\r
861 which is assigned during USB enumeration.\r
862 @param EndPointAddress The combination of an endpoint number and an endpoint\r
863 direction of the target USB device. Each endpoint address\r
864 supports data transfer in one direction except the\r
865 control endpoint (whose default endpoint address is 0).\r
866 It is the caller's responsibility to make sure that\r
867 the EndPointAddress represents an interrupt endpoint.\r
868 @param IsSlowDevice Indicates whether the target device is slow device\r
869 or full-speed device.\r
870 @param MaxPacketLength Indicates the maximum packet size the target endpoint\r
871 is capable of sending or receiving.\r
872 @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between\r
873 the host and the target interrupt endpoint.\r
874 If FALSE, the specified asynchronous interrupt pipe\r
875 is canceled.\r
876 @param DataToggle A pointer to the data toggle value. On input, it is valid\r
877 when IsNewTransfer is TRUE, and it indicates the initial\r
878 data toggle value the asynchronous interrupt transfer\r
879 should adopt.\r
880 On output, it is valid when IsNewTransfer is FALSE,\r
881 and it is updated to indicate the data toggle value of\r
882 the subsequent asynchronous interrupt transfer.\r
883 @param PollingInterval Indicates the interval, in milliseconds, that the\r
884 asynchronous interrupt transfer is polled.\r
885 This parameter is required when IsNewTransfer is TRUE.\r
886 @param UCBuffer Uncacheable buffer\r
887 @param DataLength Indicates the length of data to be received at the\r
888 rate specified by PollingInterval from the target\r
889 asynchronous interrupt endpoint. This parameter\r
890 is only required when IsNewTransfer is TRUE.\r
891 @param CallBackFunction The Callback function.This function is called at the\r
892 rate specified by PollingInterval.This parameter is\r
893 only required when IsNewTransfer is TRUE.\r
894 @param Context The context that is passed to the CallBackFunction.\r
895 This is an optional parameter and may be NULL.\r
896 @param IsPeriodic Periodic interrupt or not\r
897 @param OutputED The correspoding ED carried out\r
898 @param OutputTD The correspoding TD carried out\r
899\r
900\r
901 @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully\r
902 submitted or canceled.\r
903 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
904 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
905\r
906**/\r
907\r
908EFI_STATUS\r
909OhciInterruptTransfer (\r
910 IN USB_OHCI_HC_DEV *Ohc,\r
911 IN UINT8 DeviceAddress,\r
912 IN UINT8 EndPointAddress,\r
913 IN BOOLEAN IsSlowDevice,\r
914 IN UINT8 MaxPacketLength,\r
915 IN BOOLEAN IsNewTransfer,\r
916 IN OUT UINT8 *DataToggle OPTIONAL,\r
917 IN UINTN PollingInterval OPTIONAL,\r
918 IN VOID *UCBuffer OPTIONAL,\r
919 IN UINTN DataLength OPTIONAL,\r
920 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL,\r
921 IN VOID *Context OPTIONAL,\r
922 IN BOOLEAN IsPeriodic OPTIONAL,\r
923 OUT ED_DESCRIPTOR **OutputED OPTIONAL,\r
924 OUT TD_DESCRIPTOR **OutputTD OPTIONAL\r
925 )\r
926{\r
927 ED_DESCRIPTOR *Ed;\r
928 UINT8 EdDir;\r
929 ED_DESCRIPTOR *HeadEd;\r
930 TD_DESCRIPTOR *HeadTd;\r
931 TD_DESCRIPTOR *DataTd;\r
932 TD_DESCRIPTOR *EmptTd;\r
933 UINTN Depth;\r
934 UINTN Index;\r
935 EFI_STATUS Status;\r
936 UINT8 EndPointNum;\r
937 UINT32 DataPidDir;\r
9b6bbcdb
MK
938 INTERRUPT_CONTEXT_ENTRY *Entry;\r
939 EFI_TPL OldTpl;\r
940 BOOLEAN FirstTD;\r
941\r
942 VOID *Mapping;\r
943 UINTN MapLength;\r
944 EFI_PHYSICAL_ADDRESS MapPyhAddr;\r
945 UINTN LeftLength;\r
946 UINTN ActualSendLength;\r
947\r
948\r
949 if (DataLength > MAX_BYTES_PER_TD) {\r
950 DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Error param\r\n"));\r
951 return EFI_INVALID_PARAMETER;\r
952 }\r
953\r
954 if ((EndPointAddress & 0x80) != 0) {\r
9b6bbcdb
MK
955 EdDir = ED_IN_DIR;\r
956 DataPidDir = TD_IN_PID;\r
957 } else {\r
9b6bbcdb
MK
958 EdDir = ED_OUT_DIR;\r
959 DataPidDir = TD_OUT_PID;\r
960 }\r
961\r
962 EndPointNum = (EndPointAddress & 0xF);\r
963\r
964 if (!IsNewTransfer) {\r
965 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
966 OhciSetHcControl (Ohc, PERIODIC_ENABLE, 0);\r
967 OhciFreeInterruptContext (Ohc, DeviceAddress, EndPointAddress, DataToggle);\r
968 Status = OhciFreeInterruptEdByAddr (Ohc, DeviceAddress, EndPointNum);\r
969 OhciSetHcControl (Ohc, PERIODIC_ENABLE, 1);\r
970 gBS->RestoreTPL (OldTpl);\r
971 return Status;\r
972 }\r
973 MapLength = DataLength;\r
974 Status = Ohc->PciIo->Map(\r
975 Ohc->PciIo,\r
976 EfiPciIoOperationBusMasterWrite,\r
977 UCBuffer,\r
978 &MapLength,\r
979 &MapPyhAddr,\r
980 &Mapping\r
981 );\r
982 if (EFI_ERROR (Status)) {\r
983 DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Failt to PciIo->Map buffer \r\n"));\r
984 goto EXIT;\r
985 }\r
986 Depth = 5;\r
987 Index = 1;\r
988 while (PollingInterval >= Index * 2 && Depth > 0) {\r
989 Index *= 2;\r
990 Depth--;\r
991 }\r
992 //\r
993 //ED Stage\r
994 //\r
995 HeadEd = OhciFindMinInterruptEDList (Ohc, (UINT32)Depth);\r
996 if ((Ed = OhciFindWorkingEd (HeadEd, DeviceAddress, EndPointNum, EdDir)) != NULL) {\r
997 OhciSetEDField (Ed, ED_SKIP, 1);\r
998 } else {\r
999 Ed = OhciCreateED (Ohc);\r
1000 if (Ed == NULL) {\r
1001 Status = EFI_OUT_OF_RESOURCES;\r
1002 DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for ED\r\n"));\r
1003 goto UNMAP_OHCI_XBUFF;\r
1004 }\r
1005 OhciSetEDField (Ed, ED_SKIP, 1);\r
1006 OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);\r
1007 OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum);\r
1008 OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);\r
1009 OhciSetEDField (Ed, ED_SPEED, IsSlowDevice);\r
1010 OhciSetEDField (Ed, ED_FORMAT, 0);\r
1011 OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);\r
1012 OhciSetEDField (Ed, ED_PDATA | ED_ZERO | ED_HALTED | ED_DTTOGGLE, 0);\r
1013 OhciSetEDField (Ed, ED_TDHEAD_PTR, 0);\r
1014 OhciSetEDField (Ed, ED_TDTAIL_PTR, 0);\r
1015 OhciSetEDField (Ed, ED_NEXT_EDPTR, 0);\r
1016 OhciAttachEDToList (Ohc, INTERRUPT_LIST, Ed, HeadEd);\r
1017 }\r
1018 //\r
1019 //Data Stage\r
1020 //\r
1021 LeftLength = MapLength;\r
1022 ActualSendLength = MapLength;\r
1023 HeadTd = NULL;\r
1024 FirstTD = TRUE;\r
1025 while (LeftLength > 0) {\r
1026 ActualSendLength = LeftLength;\r
1027 if (LeftLength > MaxPacketLength) {\r
1028 ActualSendLength = MaxPacketLength;\r
1029 }\r
1030 DataTd = OhciCreateTD (Ohc);\r
1031 if (DataTd == NULL) {\r
1032 Status = EFI_OUT_OF_RESOURCES;\r
1033 DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for Data Stage TD\r\n"));\r
1034 goto FREE_OHCI_TDBUFF;\r
1035 }\r
1036 OhciSetTDField (DataTd, TD_PDATA, 0);\r
1037 OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);\r
1038 OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);\r
1039 OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);\r
1040 OhciSetTDField (DataTd, TD_DT_TOGGLE, *DataToggle);\r
1041 OhciSetTDField (DataTd, TD_ERROR_CNT, 0);\r
1042 OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
1043 OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr);\r
1044 OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(MapPyhAddr + ActualSendLength - 1));\r
1045 OhciSetTDField (DataTd, TD_NEXT_PTR, 0);\r
1046 DataTd->ActualSendLength = (UINT32)ActualSendLength;\r
1047 DataTd->DataBuffer = (UINT32)MapPyhAddr;\r
1048 DataTd->NextTDPointer = 0;\r
1049 if (FirstTD) {\r
1050 HeadTd = DataTd;\r
1051 FirstTD = FALSE;\r
1052 } else {\r
1053 OhciLinkTD (HeadTd, DataTd);\r
1054 }\r
1055 *DataToggle ^= 1;\r
1056 MapPyhAddr += ActualSendLength;\r
1057 LeftLength -= ActualSendLength;\r
1058 }\r
1059\r
1060 EmptTd = OhciCreateTD (Ohc);\r
1061 if (EmptTd == NULL) {\r
1062 Status = EFI_OUT_OF_RESOURCES;\r
1063 DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for Empty Stage TD\r\n"));\r
1064 goto FREE_OHCI_TDBUFF;\r
1065 }\r
1066 OhciSetTDField (EmptTd, TD_PDATA, 0);\r
1067 OhciSetTDField (EmptTd, TD_BUFFER_ROUND, 0);\r
1068 OhciSetTDField (EmptTd, TD_DIR_PID, 0);\r
1069 OhciSetTDField (EmptTd, TD_DELAY_INT, 0);\r
1070 //OhciSetTDField (EmptTd, TD_DT_TOGGLE, CurrentToggle);\r
1071 EmptTd->Word0.DataToggle = 0;\r
1072 OhciSetTDField (EmptTd, TD_ERROR_CNT, 0);\r
1073 OhciSetTDField (EmptTd, TD_COND_CODE, 0);\r
1074 OhciSetTDField (EmptTd, TD_CURR_BUFFER_PTR, 0);\r
1075 OhciSetTDField (EmptTd, TD_BUFFER_END_PTR, 0);\r
1076 OhciSetTDField (EmptTd, TD_NEXT_PTR, 0);\r
1077 EmptTd->ActualSendLength = 0;\r
1078 EmptTd->DataBuffer = 0;\r
1079 EmptTd->NextTDPointer = 0;\r
1080 OhciLinkTD (HeadTd, EmptTd);\r
1081 Ed->TdTailPointer = (UINT32)(UINTN)EmptTd;\r
1082 OhciAttachTDListToED (Ed, HeadTd);\r
1083\r
1084 if (OutputED != NULL) {\r
1085 *OutputED = Ed;\r
1086 }\r
1087 if (OutputTD != NULL) {\r
1088 *OutputTD = HeadTd;\r
1089 }\r
1090\r
1091 if (CallBackFunction != NULL) {\r
1092 Entry = AllocatePool (sizeof (INTERRUPT_CONTEXT_ENTRY));\r
1093 if (Entry == NULL) {\r
1094 goto FREE_OHCI_TDBUFF;\r
1095 }\r
1096\r
1097 Entry->DeviceAddress = DeviceAddress;\r
1098 Entry->EndPointAddress = EndPointAddress;\r
1099 Entry->Ed = Ed;\r
1100 Entry->DataTd = HeadTd;\r
1101 Entry->IsSlowDevice = IsSlowDevice;\r
1102 Entry->MaxPacketLength = MaxPacketLength;\r
1103 Entry->PollingInterval = PollingInterval;\r
1104 Entry->CallBackFunction = CallBackFunction;\r
1105 Entry->Context = Context;\r
1106 Entry->IsPeriodic = IsPeriodic;\r
1107 Entry->UCBuffer = UCBuffer;\r
1108 Entry->UCBufferMapping = Mapping;\r
1109 Entry->DataLength = DataLength;\r
1110 Entry->Toggle = DataToggle;\r
1111 Entry->NextEntry = NULL;\r
1112 OhciAddInterruptContextEntry (Ohc, Entry);\r
1113 }\r
1114 OhciSetEDField (Ed, ED_SKIP, 0);\r
1115\r
1116 if (OhciGetHcControl (Ohc, PERIODIC_ENABLE) == 0) {\r
1117 Status = OhciSetHcControl (Ohc, PERIODIC_ENABLE, 1);\r
1118 gBS->Stall (1000);\r
1119 }\r
1120\r
1121 return EFI_SUCCESS;\r
1122\r
1123FREE_OHCI_TDBUFF:\r
1124 while (HeadTd) {\r
1125 DataTd = HeadTd;\r
1126 HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer);\r
1127 UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));\r
1128 }\r
1129\r
1130//FREE_OHCI_EDBUFF:\r
1131 if ((HeadEd != Ed) && HeadEd && Ed) {\r
1132 while(HeadEd->NextED != (UINT32)(UINTN)Ed) {\r
1133 HeadEd = (ED_DESCRIPTOR *)(UINTN)(HeadEd->NextED);\r
1134 }\r
1135 HeadEd->NextED = Ed->NextED;\r
1136 UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));\r
1137 }\r
1138\r
1139UNMAP_OHCI_XBUFF:\r
1140 Ohc->PciIo->Unmap(Ohc->PciIo, Mapping);\r
1141\r
1142EXIT:\r
1143 return Status;\r
1144}\r
1145\r
1146/**\r
1147\r
1148 Submits an asynchronous interrupt transfer to an interrupt endpoint of a USB device.\r
1149\r
1150 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
1151 @param DeviceAddress Represents the address of the target device on the USB,\r
1152 which is assigned during USB enumeration.\r
1153 @param EndPointAddress The combination of an endpoint number and an endpoint\r
1154 direction of the target USB device. Each endpoint address\r
1155 supports data transfer in one direction except the\r
1156 control endpoint (whose default endpoint address is 0).\r
1157 It is the caller's responsibility to make sure that\r
1158 the EndPointAddress represents an interrupt endpoint.\r
1159 @param IsSlowDevice Indicates whether the target device is slow device\r
1160 or full-speed device.\r
1161 @param MaxiumPacketLength Indicates the maximum packet size the target endpoint\r
1162 is capable of sending or receiving.\r
1163 @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between\r
1164 the host and the target interrupt endpoint.\r
1165 If FALSE, the specified asynchronous interrupt pipe\r
1166 is canceled.\r
1167 @param DataToggle A pointer to the data toggle value. On input, it is valid\r
1168 when IsNewTransfer is TRUE, and it indicates the initial\r
1169 data toggle value the asynchronous interrupt transfer\r
1170 should adopt.\r
1171 On output, it is valid when IsNewTransfer is FALSE,\r
1172 and it is updated to indicate the data toggle value of\r
1173 the subsequent asynchronous interrupt transfer.\r
1174 @param PollingInterval Indicates the interval, in milliseconds, that the\r
1175 asynchronous interrupt transfer is polled.\r
1176 This parameter is required when IsNewTransfer is TRUE.\r
1177 @param DataLength Indicates the length of data to be received at the\r
1178 rate specified by PollingInterval from the target\r
1179 asynchronous interrupt endpoint. This parameter\r
1180 is only required when IsNewTransfer is TRUE.\r
1181 @param CallBackFunction The Callback function.This function is called at the\r
1182 rate specified by PollingInterval.This parameter is\r
1183 only required when IsNewTransfer is TRUE.\r
1184 @param Context The context that is passed to the CallBackFunction.\r
1185 This is an optional parameter and may be NULL.\r
1186\r
1187 @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully\r
1188 submitted or canceled.\r
1189 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
1190 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
1191\r
1192**/\r
1193\r
1194\r
1195EFI_STATUS\r
1196EFIAPI\r
1197OhciAsyncInterruptTransfer (\r
1198 IN EFI_USB_HC_PROTOCOL *This,\r
1199 IN UINT8 DeviceAddress,\r
1200 IN UINT8 EndPointAddress,\r
1201 IN BOOLEAN IsSlowDevice,\r
1202 IN UINT8 MaxPacketLength,\r
1203 IN BOOLEAN IsNewTransfer,\r
1204 IN OUT UINT8 *DataToggle OPTIONAL,\r
1205 IN UINTN PollingInterval OPTIONAL,\r
1206 IN UINTN DataLength OPTIONAL,\r
1207 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL,\r
1208 IN VOID *Context OPTIONAL\r
1209 )\r
1210{\r
1211 EFI_STATUS Status;\r
1212 USB_OHCI_HC_DEV *Ohc;\r
1213 VOID *UCBuffer;\r
1214\r
1215 if (DataToggle == NULL || (EndPointAddress & 0x80) == 0 ||\r
1216 (IsNewTransfer && (DataLength == 0 ||\r
1217 (*DataToggle != 0 && *DataToggle != 1) || (PollingInterval < 1 || PollingInterval > 255)))) {\r
1218 return EFI_INVALID_PARAMETER;\r
1219 }\r
1220\r
1221 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
1222 if ( IsNewTransfer ) {\r
1223 UCBuffer = AllocatePool(DataLength);\r
1224 if (UCBuffer == NULL) {\r
1225 return EFI_OUT_OF_RESOURCES;\r
1226 }\r
1227 } else {\r
1228 UCBuffer = NULL;\r
1229 }\r
1230 Status = OhciInterruptTransfer (\r
1231 Ohc,\r
1232 DeviceAddress,\r
1233 EndPointAddress,\r
1234 IsSlowDevice,\r
1235 MaxPacketLength,\r
1236 IsNewTransfer,\r
1237 DataToggle,\r
1238 PollingInterval,\r
1239 UCBuffer,\r
1240 DataLength,\r
1241 CallBackFunction,\r
1242 Context,\r
1243 TRUE,\r
1244 NULL,\r
1245 NULL\r
1246 );\r
1247 if ( IsNewTransfer ) {\r
1248 if (EFI_ERROR(Status)) {\r
1249 gBS->FreePool (UCBuffer);\r
1250 }\r
1251 }\r
1252 return Status;\r
1253}\r
1254\r
1255\r
1256/**\r
1257\r
1258 Submits synchronous interrupt transfer to an interrupt endpoint\r
1259 of a USB device.\r
1260\r
1261 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
1262 @param DeviceAddress Represents the address of the target device on the USB,\r
1263 which is assigned during USB enumeration.\r
1264 @param EndPointAddress The combination of an endpoint number and an endpoint\r
1265 direction of the target USB device. Each endpoint\r
1266 address supports data transfer in one direction\r
1267 except the control endpoint (whose default\r
1268 endpoint address is 0). It is the caller's responsibility\r
1269 to make sure that the EndPointAddress represents\r
1270 an interrupt endpoint.\r
1271 @param IsSlowDevice Indicates whether the target device is slow device\r
1272 or full-speed device.\r
1273 @param MaxPacketLength Indicates the maximum packet size the target endpoint\r
1274 is capable of sending or receiving.\r
1275 @param Data A pointer to the buffer of data that will be transmitted\r
1276 to USB device or received from USB device.\r
1277 @param DataLength On input, the size, in bytes, of the data buffer specified\r
1278 by Data. On output, the number of bytes transferred.\r
1279 @param DataToggle A pointer to the data toggle value. On input, it indicates\r
1280 the initial data toggle value the synchronous interrupt\r
1281 transfer should adopt;\r
1282 on output, it is updated to indicate the data toggle value\r
1283 of the subsequent synchronous interrupt transfer.\r
1284 @param TimeOut Indicates the maximum time, in microseconds, which the\r
1285 transfer is allowed to complete.\r
1286 @param TransferResult A pointer to the detailed result information from\r
1287 the synchronous interrupt transfer.\r
1288\r
1289 @retval EFI_UNSUPPORTED This interface not available.\r
1290 @retval EFI_INVALID_PARAMETER Parameters not follow spec\r
1291\r
1292**/\r
1293\r
1294\r
1295EFI_STATUS\r
1296EFIAPI\r
1297OhciSyncInterruptTransfer (\r
1298 IN EFI_USB_HC_PROTOCOL *This,\r
1299 IN UINT8 DeviceAddress,\r
1300 IN UINT8 EndPointAddress,\r
1301 IN BOOLEAN IsSlowDevice,\r
1302 IN UINT8 MaxPacketLength,\r
1303 IN OUT VOID *Data,\r
1304 IN OUT UINTN *DataLength,\r
1305 IN OUT UINT8 *DataToggle,\r
1306 IN UINTN TimeOut,\r
1307 OUT UINT32 *TransferResult\r
1308 )\r
1309{\r
1310 USB_OHCI_HC_DEV *Ohc;\r
1311 EFI_STATUS Status;\r
1312 ED_DESCRIPTOR *Ed;\r
1313 TD_DESCRIPTOR *HeadTd;\r
1314 OHCI_ED_RESULT EdResult;\r
1315 VOID *UCBuffer;\r
1316\r
1317 if ((EndPointAddress & 0x80) == 0 || Data == NULL || DataLength == NULL || *DataLength == 0 ||\r
1318 (IsSlowDevice && MaxPacketLength > 8) || (!IsSlowDevice && MaxPacketLength > 64) ||\r
1319 DataToggle == NULL || (*DataToggle != 0 && *DataToggle != 1) || TransferResult == NULL) {\r
1320 return EFI_INVALID_PARAMETER;\r
1321 }\r
1322\r
1323 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
1324 UCBuffer = AllocatePool (*DataLength);\r
1325 if (UCBuffer == NULL) {\r
1326 return EFI_OUT_OF_RESOURCES;\r
1327 }\r
1328 Status = OhciInterruptTransfer (\r
1329 Ohc,\r
1330 DeviceAddress,\r
1331 EndPointAddress,\r
1332 IsSlowDevice,\r
1333 MaxPacketLength,\r
1334 TRUE,\r
1335 DataToggle,\r
1336 1,\r
1337 UCBuffer,\r
1338 *DataLength,\r
1339 NULL,\r
1340 NULL,\r
1341 FALSE,\r
1342 &Ed,\r
1343 &HeadTd\r
1344 );\r
1345\r
1346 if (!EFI_ERROR (Status)) {\r
1347 Status = CheckIfDone (Ohc, INTERRUPT_LIST, Ed, HeadTd, &EdResult);\r
1348 while (Status == EFI_NOT_READY && TimeOut > 0) {\r
1349 gBS->Stall (1000);\r
1350 TimeOut--;\r
1351 Status = CheckIfDone (Ohc, INTERRUPT_LIST, Ed, HeadTd, &EdResult);\r
1352 }\r
1353\r
1354 *TransferResult = ConvertErrorCode (EdResult.ErrorCode);\r
1355 }\r
1356 CopyMem(Data, UCBuffer, *DataLength);\r
1357 Status = OhciInterruptTransfer (\r
1358 Ohc,\r
1359 DeviceAddress,\r
1360 EndPointAddress,\r
1361 IsSlowDevice,\r
1362 MaxPacketLength,\r
1363 FALSE,\r
1364 DataToggle,\r
1365 0,\r
1366 NULL,\r
1367 0,\r
1368 NULL,\r
1369 NULL,\r
1370 FALSE,\r
1371 NULL,\r
1372 NULL\r
1373 );\r
1374\r
1375 return Status;\r
1376}\r
1377/**\r
1378\r
1379 Submits isochronous transfer to a target USB device.\r
1380\r
1381 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
1382 @param DeviceAddress Represents the address of the target device on the USB,\r
1383 which is assigned during USB enumeration.\r
1384 @param EndPointAddress End point address\r
1385 @param MaximumPacketLength Indicates the maximum packet size that the\r
1386 default control transfer endpoint is capable of\r
1387 sending or receiving.\r
1388 @param Data A pointer to the buffer of data that will be transmitted\r
1389 to USB device or received from USB device.\r
1390 @param DataLength Indicates the size, in bytes, of the data buffer\r
1391 specified by Data.\r
1392 @param TransferResult A pointer to the detailed result information generated\r
1393 by this control transfer.\r
1394\r
1395 @retval EFI_UNSUPPORTED This interface not available\r
1396 @retval EFI_INVALID_PARAMETER Data is NULL or DataLength is 0 or TransferResult is NULL\r
1397\r
1398**/\r
1399\r
1400\r
1401EFI_STATUS\r
1402EFIAPI\r
1403OhciIsochronousTransfer (\r
1404 IN EFI_USB_HC_PROTOCOL *This,\r
1405 IN UINT8 DeviceAddress,\r
1406 IN UINT8 EndPointAddress,\r
1407 IN UINT8 MaximumPacketLength,\r
1408 IN OUT VOID *Data,\r
1409 IN OUT UINTN DataLength,\r
1410 OUT UINT32 *TransferResult\r
1411 )\r
1412{\r
1413 if (Data == NULL || DataLength == 0 || TransferResult == NULL) {\r
1414 return EFI_INVALID_PARAMETER;\r
1415 }\r
1416\r
1417 return EFI_UNSUPPORTED;\r
1418}\r
1419\r
1420/**\r
1421\r
1422 Submits Async isochronous transfer to a target USB device.\r
1423\r
1424 @param his A pointer to the EFI_USB_HC_PROTOCOL instance.\r
1425 @param DeviceAddress Represents the address of the target device on the USB,\r
1426 which is assigned during USB enumeration.\r
1427 @param EndPointAddress End point address\r
1428 @param MaximumPacketLength Indicates the maximum packet size that the\r
1429 default control transfer endpoint is capable of\r
1430 sending or receiving.\r
1431 @param Data A pointer to the buffer of data that will be transmitted\r
1432 to USB device or received from USB device.\r
1433 @param IsochronousCallBack When the transfer complete, the call back function will be called\r
1434 @param Context Pass to the call back function as parameter\r
1435\r
1436 @retval EFI_UNSUPPORTED This interface not available\r
1437 @retval EFI_INVALID_PARAMETER Data is NULL or Datalength is 0\r
1438\r
1439**/\r
1440\r
1441EFI_STATUS\r
1442EFIAPI\r
1443OhciAsyncIsochronousTransfer (\r
1444 IN EFI_USB_HC_PROTOCOL *This,\r
1445 IN UINT8 DeviceAddress,\r
1446 IN UINT8 EndPointAddress,\r
1447 IN UINT8 MaximumPacketLength,\r
1448 IN OUT VOID *Data,\r
1449 IN OUT UINTN DataLength,\r
1450 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,\r
1451 IN VOID *Context OPTIONAL\r
1452 )\r
1453{\r
1454\r
1455 if (Data == NULL || DataLength == 0) {\r
1456 return EFI_INVALID_PARAMETER;\r
1457 }\r
1458\r
1459 return EFI_UNSUPPORTED;\r
1460}\r
1461\r
1462/**\r
1463\r
1464 Retrieves the number of root hub ports.\r
1465\r
1466 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
1467 @param NumOfPorts A pointer to the number of the root hub ports.\r
1468\r
1469 @retval EFI_SUCCESS The port number was retrieved successfully.\r
1470**/\r
1471EFI_STATUS\r
1472EFIAPI\r
1473OhciGetRootHubNumOfPorts (\r
1474 IN EFI_USB_HC_PROTOCOL *This,\r
1475 OUT UINT8 *NumOfPorts\r
1476 )\r
1477{\r
1478 USB_OHCI_HC_DEV *Ohc;\r
1479 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
1480\r
1481 if (NumOfPorts == NULL) {\r
1482 return EFI_INVALID_PARAMETER;\r
1483 }\r
1484\r
1485 *NumOfPorts = (UINT8)OhciGetRootHubDescriptor(Ohc, RH_NUM_DS_PORTS);\r
1486\r
1487 return EFI_SUCCESS;\r
1488}\r
1489/**\r
1490\r
1491 Retrieves the current status of a USB root hub port.\r
1492\r
1493 @param This A pointer to the EFI_USB_HC_PROTOCOL.\r
1494 @param PortNumber Specifies the root hub port from which the status\r
1495 is to be retrieved. This value is zero-based. For example,\r
1496 if a root hub has two ports, then the first port is numbered 0,\r
1497 and the second port is numbered 1.\r
1498 @param PortStatus A pointer to the current port status bits and\r
1499 port status change bits.\r
1500\r
1501 @retval EFI_SUCCESS The status of the USB root hub port specified by PortNumber\r
1502 was returned in PortStatus.\r
1503 @retval EFI_INVALID_PARAMETER Port number not valid\r
1504**/\r
1505\r
1506\r
1507EFI_STATUS\r
1508EFIAPI\r
1509OhciGetRootHubPortStatus (\r
1510 IN EFI_USB_HC_PROTOCOL *This,\r
1511 IN UINT8 PortNumber,\r
1512 OUT EFI_USB_PORT_STATUS *PortStatus\r
1513 )\r
1514{\r
1515 USB_OHCI_HC_DEV *Ohc;\r
1516 UINT8 NumOfPorts;\r
1517\r
1518 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
1519\r
1520 OhciGetRootHubNumOfPorts (This, &NumOfPorts);\r
1521 if (PortNumber >= NumOfPorts) {\r
1522 return EFI_INVALID_PARAMETER;\r
1523 }\r
1524 PortStatus->PortStatus = 0;\r
1525 PortStatus->PortChangeStatus = 0;\r
1526\r
1527 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_CURR_CONNECT_STAT)) {\r
1528 PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;\r
1529 }\r
1530 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_ENABLE_STAT)) {\r
1531 PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;\r
1532 }\r
1533 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_SUSPEND_STAT)) {\r
1534 PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;\r
1535 }\r
1536 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_OC_INDICATOR)) {\r
1537 PortStatus->PortStatus |= USB_PORT_STAT_OVERCURRENT;\r
1538 }\r
1539 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_RESET_STAT)) {\r
1540 PortStatus->PortStatus |= USB_PORT_STAT_RESET;\r
1541 }\r
1542 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_POWER_STAT)) {\r
1543 PortStatus->PortStatus |= USB_PORT_STAT_POWER;\r
1544 }\r
1545 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_LSDEVICE_ATTACHED)) {\r
1546 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
1547 }\r
1548 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE)) {\r
1549 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;\r
1550 }\r
1551 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE)) {\r
1552 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;\r
1553 }\r
1554 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE)) {\r
1555 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_SUSPEND;\r
1556 }\r
1557 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE)) {\r
1558 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_OVERCURRENT;\r
1559 }\r
1560 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE)) {\r
1561 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_RESET;\r
1562 }\r
1563\r
1564 return EFI_SUCCESS;\r
1565}\r
1566/**\r
1567\r
1568 Sets a feature for the specified root hub port.\r
1569\r
1570 @param This A pointer to the EFI_USB_HC_PROTOCOL.\r
1571 @param PortNumber Specifies the root hub port whose feature\r
1572 is requested to be set.\r
1573 @param PortFeature Indicates the feature selector associated\r
1574 with the feature set request.\r
1575\r
1576 @retval EFI_SUCCESS The feature specified by PortFeature was set for the\r
1577 USB root hub port specified by PortNumber.\r
1578 @retval EFI_DEVICE_ERROR Set feature failed because of hardware issue\r
1579 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
1580**/\r
1581EFI_STATUS\r
1582EFIAPI\r
1583OhciSetRootHubPortFeature (\r
1584 IN EFI_USB_HC_PROTOCOL *This,\r
1585 IN UINT8 PortNumber,\r
1586 IN EFI_USB_PORT_FEATURE PortFeature\r
1587 )\r
1588{\r
1589 USB_OHCI_HC_DEV *Ohc;\r
1590 EFI_STATUS Status;\r
1591 UINT8 NumOfPorts;\r
1592 UINTN RetryTimes;\r
1593\r
1594 OhciGetRootHubNumOfPorts (This, &NumOfPorts);\r
1595 if (PortNumber >= NumOfPorts) {\r
1596 return EFI_INVALID_PARAMETER;\r
1597 }\r
1598\r
1599 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
1600\r
1601 Status = EFI_SUCCESS;\r
1602\r
1603\r
1604 switch (PortFeature) {\r
1605 case EfiUsbPortPower:\r
1606 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_POWER);\r
1607\r
1608 //\r
1609 // Verify the state\r
1610 //\r
1611 RetryTimes = 0;\r
1612 do {\r
1613 gBS->Stall (1000);\r
1614 RetryTimes++;\r
1615 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 0 &&\r
1616 RetryTimes < MAX_RETRY_TIMES);\r
1617\r
1618 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1619 return EFI_DEVICE_ERROR;\r
1620 }\r
1621 break;\r
1622\r
1623 case EfiUsbPortReset:\r
1624 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_RESET);\r
1625\r
1626 //\r
1627 // Verify the state\r
1628 //\r
1629 RetryTimes = 0;\r
1630 do {\r
1631 gBS->Stall (1000);\r
1632 RetryTimes++;\r
1633 } while ((OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 0 ||\r
1634 OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT) == 1) &&\r
1635 RetryTimes < MAX_RETRY_TIMES);\r
1636\r
1637 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1638 return EFI_DEVICE_ERROR;\r
1639 }\r
1640\r
1641 OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE);\r
1642 break;\r
1643\r
1644 case EfiUsbPortEnable:\r
1645 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_ENABLE);\r
1646\r
1647 //\r
1648 // Verify the state\r
1649 //\r
1650 RetryTimes = 0;\r
1651 do {\r
1652 gBS->Stall (1000);\r
1653 RetryTimes++;\r
1654 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 0 &&\r
1655 RetryTimes < MAX_RETRY_TIMES);\r
1656\r
1657 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1658 return EFI_DEVICE_ERROR;\r
1659 }\r
1660 break;\r
1661\r
1662\r
1663 case EfiUsbPortSuspend:\r
1664 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_SUSPEND);\r
1665\r
1666 //\r
1667 // Verify the state\r
1668 //\r
1669 RetryTimes = 0;\r
1670 do {\r
1671 gBS->Stall (1000);\r
1672 RetryTimes++;\r
1673 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 0 &&\r
1674 RetryTimes < MAX_RETRY_TIMES);\r
1675\r
1676 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1677 return EFI_DEVICE_ERROR;\r
1678 }\r
1679 break;\r
1680\r
1681 default:\r
1682 return EFI_INVALID_PARAMETER;\r
1683 }\r
1684\r
1685 return Status;\r
1686}\r
1687\r
1688/**\r
1689\r
1690 Clears a feature for the specified root hub port.\r
1691\r
1692 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
1693 @param PortNumber Specifies the root hub port whose feature\r
1694 is requested to be cleared.\r
1695 @param PortFeature Indicates the feature selector associated with the\r
1696 feature clear request.\r
1697\r
1698 @retval EFI_SUCCESS The feature specified by PortFeature was cleared for the\r
1699 USB root hub port specified by PortNumber.\r
1700 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
1701 @retval EFI_DEVICE_ERROR Some error happened when clearing feature\r
1702**/\r
1703EFI_STATUS\r
1704EFIAPI\r
1705OhciClearRootHubPortFeature (\r
1706 IN EFI_USB_HC_PROTOCOL *This,\r
1707 IN UINT8 PortNumber,\r
1708 IN EFI_USB_PORT_FEATURE PortFeature\r
1709 )\r
1710{\r
1711 USB_OHCI_HC_DEV *Ohc;\r
1712 EFI_STATUS Status;\r
1713 UINT8 NumOfPorts;\r
1714 UINTN RetryTimes;\r
1715\r
1716\r
1717 OhciGetRootHubNumOfPorts (This, &NumOfPorts);\r
1718 if (PortNumber >= NumOfPorts) {\r
1719 return EFI_INVALID_PARAMETER;\r
1720 }\r
1721\r
1722 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
1723\r
1724 Status = EFI_SUCCESS;\r
1725\r
1726 switch (PortFeature) {\r
1727 case EfiUsbPortEnable:\r
1728 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_ENABLE);\r
1729\r
1730 //\r
1731 // Verify the state\r
1732 //\r
1733 RetryTimes = 0;\r
1734 do {\r
1735 gBS->Stall (1000);\r
1736 RetryTimes++;\r
1737 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 1 &&\r
1738 RetryTimes < MAX_RETRY_TIMES);\r
1739\r
1740 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1741 return EFI_DEVICE_ERROR;\r
1742 }\r
1743 break;\r
1744\r
1745 case EfiUsbPortSuspend:\r
1746 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_SUSPEND_STATUS);\r
1747\r
1748 //\r
1749 // Verify the state\r
1750 //\r
1751 RetryTimes = 0;\r
1752 do {\r
1753 gBS->Stall (1000);\r
1754 RetryTimes++;\r
1755 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 1 &&\r
1756 RetryTimes < MAX_RETRY_TIMES);\r
1757\r
1758 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1759 return EFI_DEVICE_ERROR;\r
1760 }\r
1761 break;\r
1762\r
1763 case EfiUsbPortReset:\r
1764 break;\r
1765\r
1766 case EfiUsbPortPower:\r
1767 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_POWER);\r
1768\r
1769 //\r
1770 // Verify the state\r
1771 //\r
1772 RetryTimes = 0;\r
1773 do {\r
1774 gBS->Stall (1000);\r
1775 RetryTimes++;\r
1776 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 1 &&\r
1777 RetryTimes < MAX_RETRY_TIMES);\r
1778\r
1779 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1780 return EFI_DEVICE_ERROR;\r
1781 }\r
1782 break;\r
1783\r
1784 case EfiUsbPortConnectChange:\r
1785 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE);\r
1786\r
1787 //\r
1788 // Verify the state\r
1789 //\r
1790 RetryTimes = 0;\r
1791 do {\r
1792 gBS->Stall (1000);\r
1793 RetryTimes++;\r
1794 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE) == 1 &&\r
1795 RetryTimes < MAX_RETRY_TIMES);\r
1796\r
1797 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1798 return EFI_DEVICE_ERROR;\r
1799 }\r
1800 break;\r
1801\r
1802 case EfiUsbPortResetChange:\r
1803 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE);\r
1804\r
1805 //\r
1806 // Verify the state\r
1807 //\r
1808 RetryTimes = 0;\r
1809 do {\r
1810 gBS->Stall (1000);\r
1811 RetryTimes++;\r
1812 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 1 &&\r
1813 RetryTimes < MAX_RETRY_TIMES);\r
1814\r
1815 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1816 return EFI_DEVICE_ERROR;\r
1817 }\r
1818 break;\r
1819\r
1820\r
1821 case EfiUsbPortEnableChange:\r
1822 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE);\r
1823\r
1824 //\r
1825 // Verify the state\r
1826 //\r
1827 RetryTimes = 0;\r
1828 do {\r
1829 gBS->Stall (1000);\r
1830 RetryTimes++;\r
1831 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE) == 1 &&\r
1832 RetryTimes < MAX_RETRY_TIMES);\r
1833\r
1834 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1835 return EFI_DEVICE_ERROR;\r
1836 }\r
1837 break;\r
1838\r
1839 case EfiUsbPortSuspendChange:\r
1840 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE);\r
1841\r
1842 //\r
1843 // Verify the state\r
1844 //\r
1845 RetryTimes = 0;\r
1846 do {\r
1847 gBS->Stall (1000);\r
1848 RetryTimes++;\r
1849 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE) == 1 &&\r
1850 RetryTimes < MAX_RETRY_TIMES);\r
1851\r
1852 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1853 return EFI_DEVICE_ERROR;\r
1854 }\r
1855 break;\r
1856\r
1857 case EfiUsbPortOverCurrentChange:\r
1858 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE);\r
1859\r
1860 //\r
1861 // Verify the state\r
1862 //\r
1863 RetryTimes = 0;\r
1864 do {\r
1865 gBS->Stall (1000);\r
1866 RetryTimes++;\r
1867 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE) == 1 &&\r
1868 RetryTimes < MAX_RETRY_TIMES);\r
1869\r
1870 if (RetryTimes >= MAX_RETRY_TIMES) {\r
1871 return EFI_DEVICE_ERROR;\r
1872 }\r
1873 break;\r
1874\r
1875 default:\r
1876 return EFI_INVALID_PARAMETER;\r
1877 }\r
1878\r
1879 return Status;\r
1880}\r
1881\r
1882EFI_DRIVER_BINDING_PROTOCOL gOhciDriverBinding = {\r
1883 OHCIDriverBindingSupported,\r
1884 OHCIDriverBindingStart,\r
1885 OHCIDriverBindingStop,\r
1886 0x10,\r
1887 NULL,\r
1888 NULL\r
1889};\r
1890\r
1891\r
1892/**\r
1893 Entry point for EFI drivers.\r
1894\r
1895 @param ImageHandle EFI_HANDLE.\r
1896 @param SystemTable EFI_SYSTEM_TABLE.\r
1897\r
1898 @retval EFI_SUCCESS Driver is successfully loaded.\r
1899 @return Others Failed.\r
1900\r
1901**/\r
1902EFI_STATUS\r
1903EFIAPI\r
1904OHCIDriverEntryPoint (\r
1905 IN EFI_HANDLE ImageHandle,\r
1906 IN EFI_SYSTEM_TABLE *SystemTable\r
1907 )\r
1908{\r
1909 return EfiLibInstallDriverBindingComponentName2 (\r
1910 ImageHandle,\r
1911 SystemTable,\r
1912 &gOhciDriverBinding,\r
1913 ImageHandle,\r
1914 &gOhciComponentName,\r
1915 &gOhciComponentName2\r
1916 );\r
1917}\r
1918\r
1919\r
1920/**\r
1921 Test to see if this driver supports ControllerHandle. Any\r
1922 ControllerHandle that has UsbHcProtocol installed will be supported.\r
1923\r
1924 @param This Protocol instance pointer.\r
1925 @param Controller Handle of device to test.\r
1926 @param RemainingDevicePath Not used.\r
1927\r
1928 @return EFI_SUCCESS This driver supports this device.\r
1929 @return EFI_UNSUPPORTED This driver does not support this device.\r
1930\r
1931**/\r
1932EFI_STATUS\r
1933EFIAPI\r
1934OHCIDriverBindingSupported (\r
1935 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1936 IN EFI_HANDLE Controller,\r
1937 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
1938 )\r
1939{\r
1940 EFI_STATUS Status;\r
1941 EFI_PCI_IO_PROTOCOL *PciIo;\r
1942 USB_CLASSC UsbClassCReg;\r
1943 //\r
1944 // Test whether there is PCI IO Protocol attached on the controller handle.\r
1945 //\r
1946 Status = gBS->OpenProtocol (\r
1947 Controller,\r
1948 &gEfiPciIoProtocolGuid,\r
1949 (VOID **) &PciIo,\r
1950 This->DriverBindingHandle,\r
1951 Controller,\r
1952 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1953 );\r
1954\r
1955 if (EFI_ERROR (Status)) {\r
1956 return EFI_UNSUPPORTED;\r
1957 }\r
1958\r
1959 Status = PciIo->Pci.Read (\r
1960 PciIo,\r
1961 EfiPciIoWidthUint8,\r
1962 PCI_CLASSCODE_OFFSET,\r
1963 sizeof (USB_CLASSC) / sizeof (UINT8),\r
1964 &UsbClassCReg\r
1965 );\r
1966\r
1967 if (EFI_ERROR (Status)) {\r
1968 Status = EFI_UNSUPPORTED;\r
1969 goto ON_EXIT;\r
1970 }\r
1971 //\r
1972 // Test whether the controller belongs to OHCI type\r
1973 //\r
1974 if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||\r
1975 (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||\r
1976 (UsbClassCReg.ProgInterface != PCI_IF_OHCI)\r
1977 ) {\r
1978\r
1979 Status = EFI_UNSUPPORTED;\r
1980 }\r
1981ON_EXIT:\r
1982 gBS->CloseProtocol (\r
1983 Controller,\r
1984 &gEfiPciIoProtocolGuid,\r
1985 This->DriverBindingHandle,\r
1986 Controller\r
1987 );\r
1988\r
1989 return Status;\r
1990\r
1991}\r
1992\r
1993/**\r
1994\r
1995 Allocate and initialize the empty OHCI device.\r
1996\r
1997 @param PciIo The PCIIO to use.\r
1998 @param OriginalPciAttributes The original PCI attributes.\r
1999\r
2000 @return Allocated OHCI device If err, return NULL.\r
2001\r
2002**/\r
2003\r
2004USB_OHCI_HC_DEV *\r
2005OhciAllocateDev (\r
2006 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
2007 IN UINT64 OriginalPciAttributes\r
2008 )\r
2009{\r
2010 USB_OHCI_HC_DEV *Ohc;\r
2011 EFI_STATUS Status;\r
2012 VOID *Buf;\r
2013 EFI_PHYSICAL_ADDRESS PhyAddr;\r
2014 VOID *Map;\r
2015 UINTN Pages;\r
2016 UINTN Bytes;\r
2017\r
2018 Ohc = AllocateZeroPool (sizeof (USB_OHCI_HC_DEV));\r
2019 if (Ohc == NULL) {\r
2020 return NULL;\r
2021 }\r
2022\r
2023 Ohc->Signature = USB_OHCI_HC_DEV_SIGNATURE;\r
2024 Ohc->PciIo = PciIo;\r
2025\r
2026 Ohc->UsbHc.Reset = OhciReset;\r
2027 Ohc->UsbHc.GetState = OhciGetState;\r
2028 Ohc->UsbHc.SetState = OhciSetState;\r
2029 Ohc->UsbHc.ControlTransfer = OhciControlTransfer;\r
2030 Ohc->UsbHc.BulkTransfer = OhciBulkTransfer;\r
2031 Ohc->UsbHc.AsyncInterruptTransfer = OhciAsyncInterruptTransfer;\r
2032 Ohc->UsbHc.SyncInterruptTransfer = OhciSyncInterruptTransfer;\r
2033 Ohc->UsbHc.IsochronousTransfer = OhciIsochronousTransfer;\r
2034 Ohc->UsbHc.AsyncIsochronousTransfer = OhciAsyncIsochronousTransfer;\r
2035 Ohc->UsbHc.GetRootHubPortNumber = OhciGetRootHubNumOfPorts;\r
2036 Ohc->UsbHc.GetRootHubPortStatus = OhciGetRootHubPortStatus;\r
2037 Ohc->UsbHc.SetRootHubPortFeature = OhciSetRootHubPortFeature;\r
2038 Ohc->UsbHc.ClearRootHubPortFeature = OhciClearRootHubPortFeature;\r
2039 Ohc->UsbHc.MajorRevision = 0x1;\r
2040 Ohc->UsbHc.MinorRevision = 0x1;\r
2041\r
2042 Ohc->OriginalPciAttributes = OriginalPciAttributes;\r
2043\r
2044 Ohc->HccaMemoryBlock = NULL;\r
2045 Ohc->HccaMemoryMapping = NULL;\r
2046 Ohc->HccaMemoryBuf = NULL;\r
2047 Ohc->HccaMemoryPages = 0;\r
2048 Ohc->InterruptContextList = NULL;\r
2049 Ohc->ControllerNameTable = NULL;\r
2050 Ohc->HouseKeeperTimer = NULL;\r
2051\r
2052 Ohc->MemPool = UsbHcInitMemPool(PciIo, TRUE, 0);\r
2053 if(Ohc->MemPool == NULL) {\r
2054 goto FREE_DEV_BUFFER;\r
2055 }\r
2056\r
2057 Bytes = 4096;\r
2058 Pages = EFI_SIZE_TO_PAGES (Bytes);\r
2059\r
2060 Status = PciIo->AllocateBuffer (\r
2061 PciIo,\r
2062 AllocateAnyPages,\r
2063 EfiBootServicesData,\r
2064 Pages,\r
2065 &Buf,\r
2066 0\r
2067 );\r
2068\r
2069 if (EFI_ERROR (Status)) {\r
2070 goto FREE_MEM_POOL;\r
2071 }\r
2072\r
2073 Status = PciIo->Map (\r
2074 PciIo,\r
2075 EfiPciIoOperationBusMasterCommonBuffer,\r
2076 Buf,\r
2077 &Bytes,\r
2078 &PhyAddr,\r
2079 &Map\r
2080 );\r
2081\r
2082 if (EFI_ERROR (Status) || (Bytes != 4096)) {\r
2083 goto FREE_MEM_PAGE;\r
2084 }\r
2085\r
2086 Ohc->HccaMemoryBlock = (HCCA_MEMORY_BLOCK *)(UINTN)PhyAddr;\r
2087 Ohc->HccaMemoryMapping = Map;\r
2088 Ohc->HccaMemoryBuf = (VOID *)(UINTN)Buf;\r
2089 Ohc->HccaMemoryPages = Pages;\r
2090\r
2091 return Ohc;\r
2092\r
2093FREE_MEM_PAGE:\r
2094 PciIo->FreeBuffer (PciIo, Pages, Buf);\r
2095FREE_MEM_POOL:\r
2096 UsbHcFreeMemPool (Ohc->MemPool);\r
2097FREE_DEV_BUFFER:\r
2098 FreePool(Ohc);\r
2099\r
2100 return NULL;\r
2101}\r
2102/**\r
2103\r
2104 Free the OHCI device and release its associated resources.\r
2105\r
2106 @param Ohc The OHCI device to release.\r
2107\r
2108**/\r
2109VOID\r
2110OhciFreeDev (\r
2111 IN USB_OHCI_HC_DEV *Ohc\r
2112 )\r
2113{\r
2114 OhciFreeFixedIntMemory (Ohc);\r
2115\r
2116 if (Ohc->HouseKeeperTimer != NULL) {\r
2117 gBS->CloseEvent (Ohc->HouseKeeperTimer);\r
2118 }\r
2119\r
2120 if (Ohc->ExitBootServiceEvent != NULL) {\r
2121 gBS->CloseEvent (Ohc->ExitBootServiceEvent);\r
2122 }\r
2123\r
2124 if (Ohc->MemPool != NULL) {\r
2125 UsbHcFreeMemPool (Ohc->MemPool);\r
2126 }\r
2127\r
2128 if (Ohc->HccaMemoryMapping != NULL ) {\r
2129 Ohc->PciIo->FreeBuffer (Ohc->PciIo, Ohc->HccaMemoryPages, Ohc->HccaMemoryBuf);\r
2130 }\r
2131\r
2132 if (Ohc->ControllerNameTable != NULL) {\r
2133 FreeUnicodeStringTable (Ohc->ControllerNameTable);\r
2134 }\r
2135\r
2136 FreePool (Ohc);\r
2137}\r
2138/**\r
2139\r
2140 Uninstall all Ohci Interface.\r
2141\r
2142 @param Controller Controller handle.\r
2143 @param This Protocol instance pointer.\r
2144\r
2145**/\r
2146VOID\r
2147OhciCleanDevUp (\r
2148 IN EFI_HANDLE Controller,\r
2149 IN EFI_USB_HC_PROTOCOL *This\r
2150 )\r
2151{\r
2152 USB_OHCI_HC_DEV *Ohc;\r
2153\r
2154 //\r
2155 // Retrieve private context structure\r
2156 //\r
2157 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
2158\r
2159 //\r
2160 // Uninstall the USB_HC and USB_HC2 protocol\r
2161 //\r
2162 gBS->UninstallProtocolInterface (\r
2163 Controller,\r
2164 &gEfiUsbHcProtocolGuid,\r
2165 &Ohc->UsbHc\r
2166 );\r
2167\r
2168 //\r
2169 // Cancel the timer event\r
2170 //\r
2171 gBS->SetTimer (Ohc->HouseKeeperTimer, TimerCancel, 0);\r
2172\r
2173 //\r
2174 // Stop the host controller\r
2175 //\r
2176 OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | ISOCHRONOUS_ENABLE | BULK_ENABLE, 0);\r
2177 This->Reset (This, EFI_USB_HC_RESET_GLOBAL);\r
2178 This->SetState (This, EfiUsbHcStateHalt);\r
2179\r
2180 //\r
2181 // Free resources\r
2182 //\r
2183 OhciFreeDynamicIntMemory (Ohc);\r
2184\r
2185 //\r
2186 // Restore original PCI attributes\r
2187 //\r
2188 Ohc->PciIo->Attributes (\r
2189 Ohc->PciIo,\r
2190 EfiPciIoAttributeOperationSet,\r
2191 Ohc->OriginalPciAttributes,\r
2192 NULL\r
2193 );\r
2194\r
2195 //\r
2196 // Free the private context structure\r
2197 //\r
2198 OhciFreeDev (Ohc);\r
2199}\r
2200\r
2201/**\r
2202\r
2203 One notified function to stop the Host Controller when gBS->ExitBootServices() called.\r
2204\r
2205 @param Event Pointer to this event\r
74c6a103 2206 @param Context Event handler private data\r
9b6bbcdb
MK
2207**/\r
2208VOID\r
2209EFIAPI\r
2210OhcExitBootService (\r
2211 EFI_EVENT Event,\r
2212 VOID *Context\r
2213 )\r
2214{\r
2215 USB_OHCI_HC_DEV *Ohc;\r
2216 EFI_USB_HC_PROTOCOL *UsbHc;\r
2217 Ohc = (USB_OHCI_HC_DEV *) Context;\r
2218\r
2219 UsbHc = &Ohc->UsbHc;\r
2220 //\r
2221 // Stop the Host Controller\r
2222 //\r
2223 //OhciStopHc (Ohc, OHC_GENERIC_TIMEOUT);\r
2224 OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | ISOCHRONOUS_ENABLE | BULK_ENABLE, 0);\r
2225 UsbHc->Reset (UsbHc, EFI_USB_HC_RESET_GLOBAL);\r
2226 UsbHc->SetState (UsbHc, EfiUsbHcStateHalt);\r
2227\r
2228 return;\r
2229}\r
2230\r
2231\r
2232/**\r
2233 Starting the Usb OHCI Driver.\r
2234\r
2235 @param This Protocol instance pointer.\r
2236 @param Controller Handle of device to test.\r
2237 @param RemainingDevicePath Not used.\r
2238\r
2239 @retval EFI_SUCCESS This driver supports this device.\r
2240 @retval EFI_UNSUPPORTED This driver does not support this device.\r
2241 @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.\r
2242 EFI_OUT_OF_RESOURCES- Failed due to resource shortage.\r
2243\r
2244**/\r
2245EFI_STATUS\r
2246EFIAPI\r
2247OHCIDriverBindingStart (\r
2248 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
2249 IN EFI_HANDLE Controller,\r
2250 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
2251 )\r
2252{\r
2253 EFI_STATUS Status;\r
2254 EFI_PCI_IO_PROTOCOL *PciIo;\r
2255 USB_OHCI_HC_DEV *Ohc;\r
2256 UINT64 Supports;\r
2257 UINT64 OriginalPciAttributes;\r
2258 BOOLEAN PciAttributesSaved;\r
2259\r
2260 //\r
2261 // Open PCIIO, then enable the HC device and turn off emulation\r
2262 //\r
2263 Ohc = NULL;\r
2264 Status = gBS->OpenProtocol (\r
2265 Controller,\r
2266 &gEfiPciIoProtocolGuid,\r
2267 (VOID **) &PciIo,\r
2268 This->DriverBindingHandle,\r
2269 Controller,\r
2270 EFI_OPEN_PROTOCOL_BY_DRIVER\r
2271 );\r
2272\r
2273 if (EFI_ERROR (Status)) {\r
2274 return Status;\r
2275 }\r
2276\r
2277 PciAttributesSaved = FALSE;\r
2278 //\r
2279 // Save original PCI attributes\r
2280 //\r
2281 Status = PciIo->Attributes (\r
2282 PciIo,\r
2283 EfiPciIoAttributeOperationGet,\r
2284 0,\r
2285 &OriginalPciAttributes\r
2286 );\r
2287\r
2288 if (EFI_ERROR (Status)) {\r
2289 goto CLOSE_PCIIO;\r
2290 }\r
2291 PciAttributesSaved = TRUE;\r
2292\r
2293 //\r
2294 // Robustnesss improvement such as for UoL\r
2295 // Default is not required.\r
2296 //\r
2297 //if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {\r
2298 // OhciTurnOffUsbEmulation (PciIo);\r
2299 //}\r
2300\r
2301 Status = PciIo->Attributes (\r
2302 PciIo,\r
2303 EfiPciIoAttributeOperationSupported,\r
2304 0,\r
2305 &Supports\r
2306 );\r
2307 if (!EFI_ERROR (Status)) {\r
2308 Supports &= EFI_PCI_DEVICE_ENABLE;\r
2309 Status = PciIo->Attributes (\r
2310 PciIo,\r
2311 EfiPciIoAttributeOperationEnable,\r
2312 Supports,\r
2313 NULL\r
2314 );\r
2315 }\r
2316\r
2317 if (EFI_ERROR (Status)) {\r
2318 goto CLOSE_PCIIO;\r
2319 }\r
2320 //\r
2321 //Allocate memory for OHC private data structure\r
2322 //\r
2323 Ohc = OhciAllocateDev(PciIo, OriginalPciAttributes);\r
2324 if (Ohc == NULL){\r
2325 Status = EFI_OUT_OF_RESOURCES;\r
2326 goto CLOSE_PCIIO;\r
2327 }\r
2328\r
2329 //Status = OhciInitializeInterruptList ( Uhc );\r
2330 //if (EFI_ERROR (Status)) {\r
2331 // goto FREE_OHC;\r
2332 //}\r
2333\r
2334 //\r
2335 // Set 0.01 s timer\r
2336 //\r
2337 Status = gBS->CreateEvent (\r
2338 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
2339 TPL_NOTIFY,\r
2340 OhciHouseKeeper,\r
2341 Ohc,\r
2342 &Ohc->HouseKeeperTimer\r
2343 );\r
2344 if (EFI_ERROR (Status)) {\r
2345 goto FREE_OHC;\r
2346 }\r
2347\r
2348 Status = gBS->SetTimer (Ohc->HouseKeeperTimer, TimerPeriodic, 10 * 1000 * 10);\r
2349 if (EFI_ERROR (Status)) {\r
2350 goto FREE_OHC;\r
2351 }\r
2352\r
2353 //\r
2354 //Install Host Controller Protocol\r
2355 //\r
2356 Status = gBS->InstallProtocolInterface (\r
2357 &Controller,\r
2358 &gEfiUsbHcProtocolGuid,\r
2359 EFI_NATIVE_INTERFACE,\r
2360 &Ohc->UsbHc\r
2361 );\r
2362 if (EFI_ERROR (Status)) {\r
2363 DEBUG ((EFI_D_INFO, "Install protocol error"));\r
2364 goto FREE_OHC;\r
2365 }\r
2366 //\r
2367 // Create event to stop the HC when exit boot service.\r
2368 //\r
2369 Status = gBS->CreateEventEx (\r
2370 EVT_NOTIFY_SIGNAL,\r
2371 TPL_NOTIFY,\r
2372 OhcExitBootService,\r
2373 Ohc,\r
2374 &gEfiEventExitBootServicesGuid,\r
2375 &Ohc->ExitBootServiceEvent\r
2376 );\r
2377 if (EFI_ERROR (Status)) {\r
2378 DEBUG ((EFI_D_INFO, "Create exit boot event error"));\r
2379 goto UNINSTALL_USBHC;\r
2380 }\r
2381 AddUnicodeString2 (\r
2382 "eng",\r
2383 gOhciComponentName.SupportedLanguages,\r
2384 &Ohc->ControllerNameTable,\r
2385 L"Usb Universal Host Controller",\r
2386 TRUE\r
2387 );\r
2388 AddUnicodeString2 (\r
2389 "en",\r
2390 gOhciComponentName2.SupportedLanguages,\r
2391 &Ohc->ControllerNameTable,\r
2392 L"Usb Universal Host Controller",\r
2393 FALSE\r
2394 );\r
2395\r
2396 return EFI_SUCCESS;\r
2397\r
2398UNINSTALL_USBHC:\r
2399 gBS->UninstallMultipleProtocolInterfaces (\r
2400 Controller,\r
2401 &gEfiUsbHcProtocolGuid,\r
2402 &Ohc->UsbHc,\r
2403 NULL\r
2404 );\r
2405\r
2406FREE_OHC:\r
2407 OhciFreeDev (Ohc);\r
2408\r
2409CLOSE_PCIIO:\r
2410 if (PciAttributesSaved) {\r
2411 //\r
2412 // Restore original PCI attributes\r
2413 //\r
2414 PciIo->Attributes (\r
2415 PciIo,\r
2416 EfiPciIoAttributeOperationSet,\r
2417 OriginalPciAttributes,\r
2418 NULL\r
2419 );\r
2420 }\r
2421\r
2422 gBS->CloseProtocol (\r
2423 Controller,\r
2424 &gEfiPciIoProtocolGuid,\r
2425 This->DriverBindingHandle,\r
2426 Controller\r
2427 );\r
2428 return Status;\r
2429}\r
2430\r
2431/**\r
74c6a103 2432 Stop this driver on ControllerHandle. Support stopping any child handles\r
9b6bbcdb
MK
2433 created by this driver.\r
2434\r
2435 @param This Protocol instance pointer.\r
2436 @param Controller Handle of device to stop driver on.\r
2437 @param NumberOfChildren Number of Children in the ChildHandleBuffer.\r
2438 @param ChildHandleBuffer List of handles for the children we need to stop.\r
2439\r
2440 @return EFI_SUCCESS\r
2441 @return others\r
2442\r
2443**/\r
2444EFI_STATUS\r
2445EFIAPI\r
2446OHCIDriverBindingStop (\r
2447 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
2448 IN EFI_HANDLE Controller,\r
2449 IN UINTN NumberOfChildren,\r
2450 IN EFI_HANDLE *ChildHandleBuffer\r
2451 )\r
2452{\r
2453 EFI_STATUS Status;\r
2454 EFI_USB_HC_PROTOCOL *UsbHc;\r
2455\r
2456 Status = gBS->OpenProtocol (\r
2457 Controller,\r
2458 &gEfiUsbHcProtocolGuid,\r
2459 (VOID **)&UsbHc,\r
2460 This->DriverBindingHandle,\r
2461 Controller,\r
2462 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
2463 );\r
2464 if (EFI_ERROR (Status)) {\r
2465 return Status;\r
2466 }\r
2467\r
2468 OhciCleanDevUp(Controller, UsbHc);\r
2469\r
2470 gBS->CloseProtocol (\r
2471 Controller,\r
2472 &gEfiPciIoProtocolGuid,\r
2473 This->DriverBindingHandle,\r
2474 Controller\r
2475 );\r
2476 return EFI_SUCCESS;\r
2477}\r
2478\r
2479\r