📄 usbohci.c
字号:
*
* ERRNO:
* None.
*
* \NOMANUAL
*/
LOCAL BOOLEAN usbOhciInitializeHostController
(
UINT8 uHostControllerIndex
)
{
/* 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;
UINT32 uTempEndpointDesc = 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) (&uTempEndpointDesc));
pOhciControllerInfo->pDefaultEndpointDescriptor = (PUSB_OHCI_ENDPOINT_DESCRIPTOR)
uTempEndpointDesc;
/*
* 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -