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