📄 usbohci.c
字号:
{ /* To hold the state of the OHCI Controller after reset */ UINT32 uOhciControllerState = 0; /* To hold the value read from the registers */ UINT32 uRegisterValue = 0; /* To hold the status of the operation */ BUS_OPERATION_STATUS uStatus = BUS_OPERATION_SUCCESS; /* To hold the status of initializing the root hub emulation module */ USBHST_STATUS nRootHubEmulationInit = FALSE; /* To hold the value of the HcFmInterval register */ UINT32 uHcFmInterval = 0; /* To hold the temporary data */ UINT32 uTemp = 0; /* To hold the default control endpoint descriptor */ USB_ENDPOINT_DESCRIPTOR controlEndpointDescriptor = { 7, /* bLength */ USB_OHCI_ENDPOINT_DESCRIPTOR_TYPE, /* Endpoint Descritpor Type */ 0x00, /* Endpoint Address */ USB_OHCI_CONTROL_TRANSFER, /* bmAttributes */ USB_DEFAULT_DEVICE_MAXIMUM_PACKET_SIZE, /* wMaxPacketSize */ 0 /* bInterval */ }; /* To hold the pointer to the host controller information */ PUSB_OHCI_INFORMATION pOhciControllerInfo = NULL; /* Obtain the pointer to the host controller information */ pOhciControllerInfo = &usbOhciControllerInfo[uHostControllerIndex]; pOhciControllerInfo->uIrqNumber = pOhciBusInfo[uHostControllerIndex]->irq; pOhciControllerInfo->uBaseAddress = (UINT32)pOhciBusInfo[uHostControllerIndex]->pBaseAddress; /* Initialize the OHCI Controller (BEGIN) */ /* * The following initization steps should be followed to initialize * the OHCI Host Controller: * * a) Save the contents of the HcFmInterval register. * b) Issue a software reset to the host controller. It takes 1 micro * second to complete the software reset. * c) Restore the contents of the HcFmInterval register. * d) Initialize the device data HCCA block to match the current * device data state. * e) Initialize the Operational Registers to match the current device * data state. * f) Program the HcHCCA register with the physical address of the * HCCA block. * g) Set HcInterruptEnable to have all interrupt enabled except SOF * detect. * h) Set HcControl to have "all queues on". * i) Set HcPeriodicStart to a value that is 90% of the value in * FrameInterval field of HcFmInterval register. * j) Put the host control in Operation State. */ OS_LOG_MESSAGE_LOW( OHCD, "Entering the function: usbOhciInitializeHostController().\n", 0, 0, 0, 0); /* Create the endpoint list access event */ pOhciControllerInfo->endpointListAccessEvent = OS_CREATE_EVENT (OS_EVENT_SIGNALED); /* Check whether the event was created successfully */ if (pOhciControllerInfo->endpointListAccessEvent == OS_INVALID_EVENT_ID) { return FALSE; } /* * Allocate memory for the Host Controller Communication Area. * * NOTE: This memory should be aligned to 256 bytes boundary. */ pOhciControllerInfo->pHcca = (PUSB_OHCI_HCCA) OS_MALLOC (sizeof(USB_OHCI_HCCA) + 256); /* Check whether memory was allocated successfully */ if (pOhciControllerInfo->pHcca == NULL) { return FALSE; } /* Reset the Host Controller Communication Area */ OS_MEMSET ((PUCHAR) pOhciControllerInfo->pHcca, 0, sizeof(USB_OHCI_HCCA) + 256); /* * Check whether the Host Controller Communication Area is aligned to * 256 bytes boundary. */ uTemp = (UINT32) pOhciControllerInfo->pHcca; if ((uTemp % 256) != 0) { /* * Align the Host Controller Communication Area to 256 bytes * boundary */ pOhciControllerInfo->pHccaAligned = (PUSB_OHCI_HCCA) ((uTemp & (~0xFF)) + 256); } else { /* Initialize the Host Controller Communication Area pointer */ pOhciControllerInfo->pHccaAligned = pOhciControllerInfo->pHcca; } /* Create the pipe for the default control endpoint */ uStatus = usbOhciCreatePipe ( uHostControllerIndex, USB_DEFAULT_DEVICE_ADDRESS, USB_DEFAULT_DEVICE_SPEED, (PUCHAR) (&controlEndpointDescriptor), (UINT16) 0, (PUINT32) (&pOhciControllerInfo->pDefaultEndpointDescriptor)); /* * Check whether the pipe for default control endpoint was created * successfully */ if (uStatus != USBHST_SUCCESS) { /* Return from the function */ return FALSE; } /* Read the contents of the HcFmInterval register */ uHcFmInterval = USB_OHCI_REG_READ (uHostControllerIndex, (pOhciControllerInfo->uBaseAddress + USB_OHCI_FM_INTERVAL_REGISTER_OFFSET)); /* Reset the OHCI Controller */ USB_OHCI_REG_WRITE (uHostControllerIndex, (pOhciControllerInfo->uBaseAddress + USB_OHCI_COMMAND_STATUS_REGISTER_OFFSET), USB_OHCI_COMMAND_STATUS_HCR); /* * Wait for the reset operation to complete. The reset operation should * be completed in 1 micro second. However, a delay of 1 milli second * is provided. * * NOTE: This extra delay will not create any performance issues. * Since the host controller is being enabled, this delay is * acceptable. */ OS_DELAY_MS (USB_OHCI_WAIT_FOR_HOST_CONTROLLER_RESET_COMPLETION); /* Wait for the reset to be complete */ while ((USB_OHCI_REG_READ (uHostControllerIndex, (pOhciControllerInfo->uBaseAddress + USB_OHCI_COMMAND_STATUS_REGISTER_OFFSET)) & USB_OHCI_COMMAND_STATUS_HCR) != 0) { OS_DELAY_MS(1); } /* Check the status of the OHCI Controller */ uOhciControllerState = USB_OHCI_REG_READ (uHostControllerIndex, (pOhciControllerInfo->uBaseAddress + USB_OHCI_CONTROL_REGISTER_OFFSET)); /* Check whether the OHCI Controller is in SUSPEND state */ if ((uOhciControllerState & USB_OHCI_CONTROL_HCFS_USB_SUSPEND) != USB_OHCI_CONTROL_HCFS_USB_SUSPEND) { /* Failed to reset the OHCI Controller */ OS_LOG_MESSAGE_HIGH ( OHCD, "Failed to reset the host controller ..... \n", 0, 0, 0, 0); return FALSE; } /* * Update the maximum packet size that can be transmitted by the host * controller without causing a schedule overrun. (BEGIN) */ /* Update the largets packet size that can be transmitted in a frame */ /* PENDING: Give proper explanation for this value */ uHcFmInterval = uHcFmInterval | (0x2781 << 16); /* * Update the maximum packet size that can be transmitted by the host * controller without causing a schedule overrun. (END) */ /* Restore the contents of the HcFmInterval register */ USB_OHCI_REG_WRITE (uHostControllerIndex, (pOhciControllerInfo->uBaseAddress + USB_OHCI_FM_INTERVAL_REGISTER_OFFSET), uHcFmInterval); /* Flush the contents of the cache to the RAM */ DMA_FLUSH(pOhciControllerInfo->pHccaAligned, sizeof(USB_OHCI_HCCA)); /* Invalidate the cache */ DMA_INVALIDATE(pOhciControllerInfo->pHccaAligned, sizeof(USB_OHCI_HCCA)); /* * Program the Host Controller Communication Area into the HcHCCA * Register */ USB_OHCI_REG_WRITE (uHostControllerIndex, (pOhciControllerInfo->uBaseAddress + USB_OHCI_HCCA_REGISTER_OFFSET), (USB_OHCD_CONVERT_TO_BUS_MEM (uHostControllerIndex, pOhciControllerInfo->pHccaAligned))); /* * Initialize the Host Controller Communication Area for interrupt and * isochronous transfers. * * NOTE: No initialization is required. The transfers will be queued * based on the need. */ /* * Initialize the head pointer for bulk transfers. * * NOTE: No initailization is required. The transfers will be queued * based on the need. */ /* Initialize the head pointer for control transfers (BEGIN) */ /* Program the HcControlHeadED register */ USB_OHCI_REG_WRITE (uHostControllerIndex, (pOhciControllerInfo->uBaseAddress + USB_OHCI_CONTROL_HEAD_ED_REGISTER_OFFSET), (USB_OHCD_CONVERT_TO_BUS_MEM (uHostControllerIndex, pOhciControllerInfo->pDefaultEndpointDescriptor))); /* Initialize the head pointer for control transfers (END) */ /* * Enable the data transfers lists in the HcControl Register (BEGIN) * * The following lists are initialized. * * a) Control List Enable * b) Bulk List Enable * c) Periodic List Enable (Interrupt Only) * d) Isochronous List Enable */ /* Read the contents of the HcControl register */ uTemp = USB_OHCI_REG_READ (uHostControllerIndex, pOhciControllerInfo->uBaseAddress + USB_OHCI_CONTROL_REGISTER_OFFSET); /* Enable the processing of the endpoint descriptor list */ uTemp |= (USB_OHCI_CONTROL_CLE | USB_OHCI_CONTROL_BLE | USB_OHCI_CONTROL_PLE | USB_OHCI_CONTROL_IE); /* Update the contents of the HcControl register */ USB_OHCI_REG_WRITE (uHostControllerIndex, (pOhciControllerInfo->uBaseAddress + USB_OHCI_CONTROL_REGISTER_OFFSET), uTemp); /* Enable the control list in the HcControl Register (END) */ /* Update the HcPeriodicStart Register (BEGIN) */ /* Read the contents of the HcFmInterval register */ uTemp = USB_OHCI_REG_READ (uHostControllerIndex, pOhciControllerInfo->uBaseAddress + USB_OHCI_FM_INTERVAL_REGISTER_OFFSET); /* Obtain the contents of the HcFmInterval::FrameInterval field */ uRegisterValue = uTemp & 0x00003FFF; /* Compute the frame interval for starting the periodic transfers */ uRegisterValue = (uRegisterValue * USB_OHCI_PERCENTAGE_BANDWIDTH_FOR_PERIODIC_TRANSFERS); uRegisterValue = (uRegisterValue & 0x00003FFF); /* * Program the HcPeriodicStart register with the frame interval for * starting the periodic transfers. */ USB_OHCI_REG_WRITE (uHostControllerIndex, (pOhciControllerInfo->uBaseAddress + USB_OHCI_PERIODIC_START_REGISTER_OFFSET), uRegisterValue); /* Update the HcPeriodicStart Register (END) */ /* * Update the maximum periodic bandwidth available on this OHCI host * controller. */ pOhciControllerInfo->uMaximumBandwidthAvailable = (UINT32) (USB_OHCI_MAXIMUM_USB11_BANDWIDTH * USB_OHCI_PERCENTAGE_BANDWIDTH_FOR_PERIODIC_TRANSFERS); /* Set the OHCI Controller to operational state (BEGIN) */ /* * NOTE: After host controller reset, the host controller enters the * USB_SUSPEND state. The host controller should not remain in * this state for more than 2 ms. If not, the host controller * will enter USB_RESUME state and the host controller should * remain in this state for the minimum duration specified in * the USB specification (i.e. 5 ms). */ /* Read the contents of the HC Control Register */ uRegisterValue = USB_OHCI_REG_READ (uHostControllerIndex, pOhciControllerInfo->uBaseAddress + USB_OHCI_CONTROL_REGISTER_OFFSET); /* Clear the previous state */ uRegisterValue &= (~USB_OHCI_CONTROL_HCFS_MASK); /* Set the OHCI Controller in operational state */ uRegisterValue |= USB_OHCI_CONTROL_HCFS_USB_OPERATIONAL; /* Program the HC Control Register */ USB_OHCI_REG_WRITE (uHostControllerIndex, (pOhciControllerInfo->uBaseAddress + USB_OHCI_CONTROL_REGISTER_OFFSET), uRegisterValue); /* Set the OHCI Controller to operational state (END) */ /* * Update the frame interval register (BEGIN) * * NOTE: It is observed that some controllers like Opti OHCI card * do not allow the HcFmInterval register to be updated when the * controller is in USB_SUSPEND state. Hence, the HcFmInterval * register is updated after the host controller is in * USB_OPERATIONAL state. */ OS_DELAY_MS(2); /* Update the contents of the HcFmInterval register */ USB_OHCI_REG_WRITE (uHostControllerIndex, (pOhciControllerInfo->uBaseAddress + USB_OHCI_FM_INTERVAL_REGISTER_OFFSET), uHcFmInterval); /* Update the frame interval register (END) */ /* Initialize the root hub emulation module */ nRootHubEmulationInit = usbOhciRootHubEmulationInit (uHostControllerIndex); /* * Check whether the root hub emulation module was initialize * successfully */ if (nRootHubEmulationInit != USBHST_SUCCESS) { /* Failed to initialize the root hub emulation module */ OS_LOG_MESSAGE_HIGH ( OHCD, "Failed to initialize the root hub emulation module ..... \n", 0, 0, 0, 0); return FALSE; } /* Read the contents of the HcRhDescriptorA Register */ uRegisterValue = USB_OHCI_REG_READ (uHostControllerIndex, (pOhciControllerInfo->uBaseAddress + USB_OHCI_RH_DESCRIPTOR_A_REGISTER_OFFSET)); uRegisterValue &= ~0x300; /* * Set the bit which indicates that the ports are to be powered on * a per-port basis */ uRegisterValue |= 0x100; USB_OHCI_REG_WRITE (uHostControllerIndex, (pOhciControllerInfo->uBaseAddress + USB_OHCI_RH_DESCRIPTOR_A_REGISTER_OFFSET),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -