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