📄 hostctrl.c
字号:
/*-----------------------------------------------------------------------------
$File: //hodad/usblink/3.4/source/hostctrl/otg242/hostctrl.c $
$DateTime: 2003/11/21 14:48:39 $
$Revision: #3 $
Purpose: OTG242 host controller operations.
CONFIDENTIAL AND PROPRIETARY INFORMATION OF SOFTCONNEX TECHNOLOGIES, INC.
THIS NOTICE IS NOT TO BE DELETED, MODIFIED, MOVED OR CHANGED IN ANY WAY.
Copyright (c) 1999 - 2003 by SoftConnex Technologies, Inc.
This software is protected by copyright laws and international copyright
treaties, as well as other intellectual property laws and treaties. This
software is a CONFIDENTIAL, unpublished work of authorship, and with portions
constituting TRADE SECRETS of SoftConnex Technologies, Inc., a Delaware USA
corporation. Any unauthorized use, disclosure, and/or reproduction of this
software, or any part of this software; or distribution of this software in any
form or by any means; or storage of this software in any database or retrieval
system, without the express written consent of, and license from, SoftConnex
Technologies, Inc. is strictly prohibited. This software is protected under the
copyright and/or trade secret laws in other countries in addition to USA. All
Rights Reserved. Failure to abide by the use, disclosure and/or reproduction
restrictions may result in civil and /or criminal penalties, and will be
prosecuted to the maximum extent of the law.
-----------------------------------------------------------------------------*/
#include "usblink.h"
#include "top.h"
/******************************************************************************
Private Definitions
******************************************************************************/
#define HC_NEW_HCD_MEM 1
/* otg242 report 3 ports while only has 2 ports */
#define OTG242HC_NUM_PORT_FIX 1
#define HC_MASS_STORAGE_NEW 1
static U32 OTG242HC_PortStatusChange[OTG242HC_RH_PORT_MAX];
/******************************************************************************
Private Functions
******************************************************************************/
/* End private functions */
SctStatus OTG242HC_Create(Otg242Hc *hc, struct _Otg242 *otg)
{
U32 Read;
hc->otg = otg;
hc->regBase = otg->regBase;
hc->hcca = NULL;
/* Initialize OHCI register maps */
OS_MemSet(hc->ohciRegMap, 0, 256);
hc->ohciReg = (U32 *)(((U32)(hc->ohciRegMap) + 0x7F) & ~0x7F);
hc->ohciReg[OTG242HC_HC_BASE / sizeof(U32)] = (U32)hc;
hc->bulkMemorySize = 64;
hc->freeEtdCount = OTG242ETD_MAX;
OTG242ETD_Create(hc->etdBank, hc);
/* turn on HOST clk */
Read = OTG242HC_ReadReg(hc, OTG242_CLOCK_CONTROL);
OTG242HC_WriteReg(hc, OTG242_CLOCK_CONTROL,
Read | OTG242_HSTCLK );
OTG242HC_WriteReg(hc, OTG242HC_INTR_STATUS,
OTG242HC_INTR_SCHEDULE_OVERRUN |
OTG242HC_INTR_WRITE_DONE_HEAD |
OTG242HC_INTR_START_OF_FRAME |
OTG242HC_INTR_RESUME_DETECT |
OTG242HC_INTR_UNRECOVERABLE_ERROR |
OTG242HC_INTR_FRAME_NO_OVERFLOW |
OTG242HC_INTR_ROOT_HUB_STATUS_CHANGE
);
/* clear any XY interrupt */
Read = OTG242HC_ReadReg(hc, OTG242HC_XBUFFERINTERRUPTSTATUS);
OTG242HC_WriteReg(hc, OTG242HC_XBUFFERINTERRUPTSTATUS, Read);
Read = OTG242HC_ReadReg(hc, OTG242HC_YBUFFERINTERRUPTSTATUS);
OTG242HC_WriteReg(hc, OTG242HC_YBUFFERINTERRUPTSTATUS, Read);
/* disable all etd interrupt */
OTG242HC_WriteReg(hc, OTG242HC_XYINTERRUPTENABLES, 0);
hc->ohciReg[OHCI_HC_REVISION / sizeof(U32)] = 0x10;
hc->ohciReg[OHCI_HC_LS_THRESHOLD / sizeof(U32)] = 0x0628;
hc->regLock = OS_SemaphoreCreate();
OS_SemaphoreSignal(hc->regLock);
if (hc->regLock == NULL)
{
return SCC_FALSE;
}
return SCC_TRUE;
}
SctStatus OTG242HC_Initialize(Otg242Hc *hc)
{
U32 Read;
Read = 0;
/* Start of Frame interrupt and root hub change status bits
* should be enabled all the time */
hc->intrEnable |= OTG242HC_INTR_START_OF_FRAME |
OTG242HC_INTR_ROOT_HUB_STATUS_CHANGE;
hc->previousFrameNo = 0xFFFFFFFF;
return SCC_TRUE;
}
void OTG242HC_Delete(Otg242Hc *hc)
{
OS_SemaphoreDelete(hc->regLock);
}
U32 Ohci_ReadRegister(unsigned long* reg)
{
U32 index;
Otg242Hc* hc;
U32 val;
val = (U32)reg;
index = val & 0x7F;
val = (val & ~0x7F) + OTG242HC_HC_BASE;
hc = (Otg242Hc*)(*((U32*)val));
if (OTG242_IsInISR(hc->otg) != SCC_TRUE)
{
OS_SemaphoreWait(hc->regLock, SCC_SEMA_WAIT_FOREVER);
OS_DisableInterrupts(OTG242_GetIntrNumber(hc->otg));
}
switch (index)
{
case OHCI_HC_REVISION:
case OHCI_HC_CTRL:
val = *reg;
break;
case OHCI_HC_CMD_STATUS:
val = OTG242HC_ReadReg(hc, OTG242HC_CTRL);
*reg &= ~(OHCI_HC_CMD_STATUS_HCR | OHCI_HC_CMD_STATUS_SOC);
*reg |= OTG242HC_CMD_STATUS_HCR_TO_OHCI(val) | OTG242HC_CMD_STATUS_SOC_TO_OHCI(val);
val = *reg;
break;
case OHCI_HC_INTR_STATUS:
val = *reg;
break;
case OHCI_HC_INTR_ENABLE:
case OHCI_HC_INTR_DISABLE:
val = hc->ohciReg[OHCI_HC_INTR_ENABLE / sizeof(U32)];
break;
case OHCI_HC_HCCA:
case OHCI_HC_PERIOD_CURRENT_ED:
case OHCI_HC_CTRL_HEAD_ED:
case OHCI_HC_CTRL_CURRENT_ED:
case OHCI_HC_BULK_HEAD_ED:
case OHCI_HC_BULK_CURRENT_ED:
case OHCI_HC_DONE_HEAD:
val = *reg;
break;
case OHCI_HC_FM_INTERVAL:
val = OTG242HC_ReadReg(hc, OTG242_FRAMEINTERVAL);
break;
case OHCI_HC_FM_REMAINING:
val = OTG242HC_ReadReg(hc, OTG242_FRAMEREMAINING);
val = (val & OHCI_HC_FM_REMAINING_FR) | (OTG242HC_FRAME_REMAINING_FRT_TO_OHCI(val));
break;
case OHCI_HC_FM_NUMBER:
val = OTG242HC_ReadReg(hc, OTG242HC_FRAME_NUMBER);
break;
case OHCI_HC_PERIODIC_START:
val = *reg;
break;
case OHCI_HC_LS_THRESHOLD:
val = OTG242HC_ReadReg(hc, OTG242HC_LS_THRESHOLD);
break;
case OHCI_HC_RH_DESCRIPTOR_A:
val = OTG242HC_ReadReg(hc, OTG242HC_RH_DESCRIPTOR_A);
#if OTG242HC_NUM_PORT_FIX
/* otg242 has one less port specify */
val--;
#endif
if (val & OHCI_HC_RH_DESCRIPTOR_A_PSM)
{
if (0 == (val & OHCI_HC_RH_DESCRIPTOR_A_NPS))
{
val &= ~OHCI_HC_RH_DESCRIPTOR_A_PSM;
val |= OHCI_HC_RH_DESCRIPTOR_A_NPS;
}
}
else
{
if (val & OHCI_HC_RH_DESCRIPTOR_A_NPS)
{
val &= ~OHCI_HC_RH_DESCRIPTOR_A_NPS;
val |= OHCI_HC_RH_DESCRIPTOR_A_PSM;
}
}
break;
case OHCI_HC_RH_DESCRIPTOR_B:
val = OTG242HC_ReadReg(hc, OTG242HC_RH_DESCRIPTOR_B);
break;
case OHCI_HC_RH_STATUS:
val = OTG242HC_ReadReg(hc, OTG242HC_RH_STATUS);
break;
case OHCI_HC_RH_PORT_STATUS(1):
val = OTG242HC_ReadReg(hc, OTG242HC_RH_PORT_STATUS(1));
val |= OTG242HC_PortStatusChange[0];
break;
case OHCI_HC_RH_PORT_STATUS(2):
val = OTG242HC_ReadReg(hc, OTG242HC_RH_PORT_STATUS(2));
val |= OTG242HC_PortStatusChange[1];
break;
case OHCI_HC_RH_PORT_STATUS(3):
val = 0;
break;
default:
OS_DEBUG_MSG2(OS_ZONE_ERR, "Unknown OHCI register 0x%0x\r\n", index);
break;
}
if (OTG242_IsInISR(hc->otg) != SCC_TRUE)
{
OS_EnableInterrupts(OTG242_GetIntrNumber(hc->otg));
OS_SemaphoreSignal(hc->regLock);
}
return val;
}
void Ohci_WriteRegister(unsigned long* reg, U32 val)
{
U32 index;
Otg242Hc *hc;
U32 tmp;
tmp = (U32)reg;
index = tmp & 0x7F;
tmp = (tmp & ~0x7F) + OTG242HC_HC_BASE;
hc = (Otg242Hc*)(*((U32*)tmp));
if (OTG242_IsInISR(hc->otg) != SCC_TRUE)
{
OS_SemaphoreWait(hc->regLock, SCC_SEMA_WAIT_FOREVER);
OS_DisableInterrupts(OTG242_GetIntrNumber(hc->otg));
}
switch (index)
{
case OHCI_HC_REVISION:
break;
case OHCI_HC_CTRL:
*reg = val;
OTG242HC_WriteReg
(
hc,
OTG242HC_CTRL,
OTG242HC_CTRL_HCFS_FROM_OHCI(val) | OTG242HC_CTRL_RWE_FROM_OHCI(val)
);
if ((val & OHCI_HC_CTRL_HCFS) == OHCI_HC_CTRL_HCFS_OPERATIONAL)
{
OTG242HC_Operational(hc);
}
break;
case OHCI_HC_CMD_STATUS:
OTG242HC_CommandStatusWrite(hc, (U32*)reg, val);
break;
case OHCI_HC_INTR_STATUS:
*reg &= ~val;
break;
case OHCI_HC_INTR_ENABLE:
*reg |= val;
hc->intrEnable |= val & ~(OHCI_HC_INTR_STATUS_OC | OHCI_HC_INTR_STATUS_MIE);
OTG242HC_WriteReg( hc, OTG242HC_INTR_ENABLE, hc->intrEnable);
break;
case OHCI_HC_INTR_DISABLE:
hc->ohciReg[OHCI_HC_INTR_ENABLE / sizeof(U32)] &= ~val;
hc->intrEnable &= ~val;
/* SOF and Port Status Change interrupts should remain on */
hc->intrEnable |= OTG242HC_INTR_START_OF_FRAME |
OTG242HC_INTR_ROOT_HUB_STATUS_CHANGE;
OTG242HC_WriteReg( hc, OTG242HC_INTR_ENABLE, hc->intrEnable);
break;
case OHCI_HC_HCCA:
#if HC_MASS_STORAGE_NEW
hc->hcca = (U32 *)OS_PhysicalToVirtual((void*)val);
#else
hc->hcca = (U32 *)OS_PhysicalToVirtual(val);
#endif
*reg = val;
break;
case OHCI_HC_PERIOD_CURRENT_ED:
break;
case OHCI_HC_CTRL_HEAD_ED:
*reg = val;
break;
case OHCI_HC_CTRL_CURRENT_ED:
if (!(hc->ohciReg[OHCI_HC_CTRL / sizeof(U32)] & OHCI_HC_CTRL_CLE))
{
*reg = val;
}
break;
case OHCI_HC_BULK_HEAD_ED:
*reg = val;
break;
case OHCI_HC_BULK_CURRENT_ED:
if (!(hc->ohciReg[OHCI_HC_CTRL / sizeof(U32)] & OHCI_HC_CTRL_BLE))
{
*reg = val;
}
break;
case OHCI_HC_DONE_HEAD:
break;
case OHCI_HC_FM_INTERVAL:
OTG242HC_WriteReg(hc, OTG242_FRAMEINTERVAL, val);
break;
case OHCI_HC_FM_REMAINING:
break;
case OHCI_HC_FM_NUMBER:
break;
case OHCI_HC_PERIODIC_START:
*reg = val;
break;
case OHCI_HC_LS_THRESHOLD:
OTG242HC_WriteReg(hc, OTG242HC_LS_THRESHOLD, val);
break;
case OHCI_HC_RH_DESCRIPTOR_A:
if (val & OHCI_HC_RH_DESCRIPTOR_A_PSM)
{
if (0 == (val & OHCI_HC_RH_DESCRIPTOR_A_NPS))
{
val &= ~OHCI_HC_RH_DESCRIPTOR_A_PSM;
val |= OHCI_HC_RH_DESCRIPTOR_A_NPS;
}
}
else
{
if (val & OHCI_HC_RH_DESCRIPTOR_A_NPS)
{
val &= ~OHCI_HC_RH_DESCRIPTOR_A_NPS;
val |= OHCI_HC_RH_DESCRIPTOR_A_PSM;
}
}
*reg = val;
OTG242HC_WriteReg(hc, OTG242HC_RH_DESCRIPTOR_A, val);
break;
case OHCI_HC_RH_DESCRIPTOR_B:
*reg = val;
OTG242HC_WriteReg(hc, OTG242HC_RH_DESCRIPTOR_B, val);
break;
case OHCI_HC_RH_STATUS:
OTG242HC_RhStatusWrite(hc, val);
break;
case OHCI_HC_RH_PORT_STATUS(1):
OTG242HC_PortStatusChange[0] &= ~(OTG242HC_RH_PORT_STATUS_CHANGE&val);
val &= ~OTG242HC_RH_PORT_STATUS_CHANGE;
OTG242HC_WriteReg(hc, OTG242HC_RH_PORT_STATUS(1), val);
break;
case OHCI_HC_RH_PORT_STATUS(2):
OTG242HC_PortStatusChange[1] &= ~(OTG242HC_RH_PORT_STATUS_CHANGE&val);
val &= ~OTG242HC_RH_PORT_STATUS_CHANGE;
OTG242HC_WriteReg(hc, OTG242HC_RH_PORT_STATUS(2), val);
break;
case OHCI_HC_RH_PORT_STATUS(3):
break;
default:
OS_DEBUG_MSG3(OS_ZONE_ERR, "Write to Unknown OHCI register 0x%0x with 0x%0x\r\n", index, val);
break;
}
if (OTG242_IsInISR(hc->otg) != SCC_TRUE)
{
OS_EnableInterrupts(OTG242_GetIntrNumber(hc->otg));
OS_SemaphoreSignal(hc->regLock);
}
}
U32 Ohci_PM_ReadRegister(unsigned long* reg)
{
U32 index;
Otg242Hc* hc;
U32 val;
val = (U32)reg;
index = val & 0x7F;
val = (val & ~0x7F) + OTG242HC_HC_BASE;
hc = (Otg242Hc*)(*((U32*)val));
switch (index)
{
case OHCI_HC_REVISION:
case OHCI_HC_CTRL:
val = *reg;
break;
case OHCI_HC_CMD_STATUS:
val = OTG242HC_ReadReg(hc, OTG242HC_CTRL);
*reg &= ~(OHCI_HC_CMD_STATUS_HCR | OHCI_HC_CMD_STATUS_SOC);
*reg |= OTG242HC_CMD_STATUS_HCR_TO_OHCI(val) | OTG242HC_CMD_STATUS_SOC_TO_OHCI(val);
val = *reg;
break;
case OHCI_HC_INTR_STATUS:
val = *reg;
break;
case OHCI_HC_INTR_ENABLE:
case OHCI_HC_INTR_DISABLE:
val = hc->ohciReg[OHCI_HC_INTR_ENABLE / sizeof(U32)];
break;
case OHCI_HC_HCCA:
case OHCI_HC_PERIOD_CURRENT_ED:
case OHCI_HC_CTRL_HEAD_ED:
case OHCI_HC_CTRL_CURRENT_ED:
case OHCI_HC_BULK_HEAD_ED:
case OHCI_HC_BULK_CURRENT_ED:
case OHCI_HC_DONE_HEAD:
val = *reg;
break;
case OHCI_HC_FM_INTERVAL:
val = OTG242HC_ReadReg(hc, OTG242_FRAMEINTERVAL);
break;
case OHCI_HC_FM_REMAINING:
val = OTG242HC_ReadReg(hc, OTG242_FRAMEREMAINING);
val = (val & OHCI_HC_FM_REMAINING_FR) | (OTG242HC_FRAME_REMAINING_FRT_TO_OHCI(val));
break;
case OHCI_HC_FM_NUMBER:
val = OTG242HC_ReadReg(hc, OTG242HC_FRAME_NUMBER);
break;
case OHCI_HC_PERIODIC_START:
val = *reg;
break;
case OHCI_HC_LS_THRESHOLD:
val = OTG242HC_ReadReg(hc, OTG242HC_LS_THRESHOLD);
break;
case OHCI_HC_RH_DESCRIPTOR_A:
val = OTG242HC_ReadReg(hc, OTG242HC_RH_DESCRIPTOR_A);
#if OTG242HC_NUM_PORT_FIX
/* otg242 has one less port specify */
val--;
#endif
if (val & OHCI_HC_RH_DESCRIPTOR_A_PSM)
{
if (0 == (val & OHCI_HC_RH_DESCRIPTOR_A_NPS))
{
val &= ~OHCI_HC_RH_DESCRIPTOR_A_PSM;
val |= OHCI_HC_RH_DESCRIPTOR_A_NPS;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -