📄 triton.c
字号:
L"IOCTL_DDK_GET_DRIVER_IFC can be called only from "
L"device process (caller process id 0x%08x)\r\n",
GetCallerProcess()
));
SetLastError(ERROR_ACCESS_DENIED);
break;
}
// Check input parameters
if ((pInBuffer == NULL) || (inSize < sizeof(GUID)))
{
SetLastError(ERROR_INVALID_PARAMETER);
break;
}
if (IsEqualGUID(pInBuffer, &DEVICE_IFC_TWL_GUID))
{
if (pOutSize != NULL) *pOutSize = sizeof(DEVICE_IFC_TWL);
if (pOutBuffer == NULL || outSize < sizeof(DEVICE_IFC_TWL))
{
SetLastError(ERROR_INVALID_PARAMETER);
break;
}
ifc.context = context;
ifc.pfnReadRegs = TWL_ReadRegs;
ifc.pfnWriteRegs = TWL_WriteRegs;
ifc.pfnSetIntrEvent = TWL_SetIntrEvent;
ifc.pfnIntrEnable = TWL_IntrEnable;
ifc.pfnIntrDisable = TWL_IntrDisable;
if (!CeSafeCopyMemory(pOutBuffer, &ifc, sizeof(DEVICE_IFC_TWL)))
{
SetLastError(ERROR_INVALID_PARAMETER);
break;
}
rc = TRUE;
break;
}
SetLastError(ERROR_INVALID_PARAMETER);
break;
case IOCTL_TWL_READREGS:
if ((pInBuffer == NULL) ||
(inSize < sizeof(IOCTL_TWL_READREGS_IN)))
{
SetLastError(ERROR_INVALID_PARAMETER);
break;
}
address = ((IOCTL_TWL_READREGS_IN*)pInBuffer)->address;
size = ((IOCTL_TWL_READREGS_IN*)pInBuffer)->size;
if (pOutSize != NULL) *pOutSize = size;
if ((pOutBuffer == NULL) || (outSize < size))
{
SetLastError(ERROR_INVALID_PARAMETER);
break;
}
rc = ReadRegs(pDevice, address, pOutBuffer, size);
break;
case IOCTL_TWL_WRITEREGS:
if ((pInBuffer == NULL) ||
(inSize < sizeof(IOCTL_TWL_WRITEREGS_IN)))
{
SetLastError(ERROR_INVALID_PARAMETER);
break;
}
address = ((IOCTL_TWL_WRITEREGS_IN*)pInBuffer)->address;
size = ((IOCTL_TWL_WRITEREGS_IN*)pInBuffer)->size;
if (inSize < (sizeof(IOCTL_TWL_WRITEREGS_IN) + size))
{
SetLastError(ERROR_INVALID_PARAMETER);
break;
}
((IOCTL_TWL_WRITEREGS_IN*)pInBuffer)++;
rc = WriteRegs(pDevice, address, pInBuffer, size);
break;
}
cleanUp:
DEBUGMSG(ZONE_FUNCTION, (L"-TWL_IOControl(rc = %d)\r\n", rc));
return rc;
}
//------------------------------------------------------------------------------
//
// Function: TWL_InterruptThread
//
// This function acts as the IST for the external irq.
//
DWORD
TWL_IntrThread(
VOID *pContext
)
{
Device_t *pDevice = (Device_t*)pContext;
DWORD id;
UINT16 status;
UINT16 currMask;
// Loop until we are stopped...
while (!pDevice->intrThreadExit) {
// Wait for event
WaitForSingleObject(pDevice->hIntrEvent, INFINITE);
if (pDevice->intrThreadExit) break;
// Get interrupt status register
if (GetTritonIrqStatus(pDevice, &status) && GetTritonIrqMask(pDevice, &currMask)) {
// Diable all interrupts
SetTritonIrqMask(pDevice, status);
// Process each unmasked interrupt
status &= ~currMask;
id = 0;
while (status != 0) {
if ((status & 0x0001) != 0) {
if (pDevice->hSetIntrEvent[id] != NULL) {
SetEvent(pDevice->hSetIntrEvent[id]);
}
// If this is a RTC alarm interrupt, let oal handle the interrupt.
if (id == TWL_INTR_RTCALM) {
KernelIoControl(IOCTL_HAL_RTC_ALARM, NULL, 0, NULL, 0, NULL);
}
}
status >>= 1;
id++;
}
}
// Set fake interrupt event
if (pDevice->hSetIntrEvent[16] != NULL) {
// Use pulse event there in case that event is already
// signaled as associated with some interrupt...
PulseEvent(pDevice->hSetIntrEvent[16]);
}
InterruptDone(pDevice->sysIntr);
}
return ERROR_SUCCESS;
}
//------------------------------------------------------------------------------
//
static
BOOL
TWL_ReadRegs(
DWORD context,
DWORD address,
UCHAR *pBuffer,
DWORD size
)
{
BOOL rc = FALSE;
Device_t *pDevice = (Device_t*)context;
// Check if we get correct context
if ((pDevice == NULL) || (pDevice->cookie != TWL_DEVICE_COOKIE))
{
DEBUGMSG(ZONE_ERROR, (L"ERROR: TWL_ReadRegs: "
L"Incorrect context parameter\r\n"
));
goto cleanUp;
}
rc = ReadRegs(pDevice, address, pBuffer, size);
cleanUp:
return rc;
}
//------------------------------------------------------------------------------
static
BOOL
TWL_WriteRegs(
DWORD context,
DWORD address,
const UCHAR *pBuffer,
DWORD size
)
{
BOOL rc = FALSE;
Device_t *pDevice = (Device_t*)context;
// Check if we get correct context
if ((pDevice == NULL) || (pDevice->cookie != TWL_DEVICE_COOKIE))
{
DEBUGMSG(ZONE_ERROR, (L"ERROR: TWL_WriteRegs: "
L"Incorrect context parameter\r\n"
));
goto cleanUp;
}
rc = WriteRegs(pDevice, address, pBuffer, size);
cleanUp:
return rc;
}
//------------------------------------------------------------------------------
// This function allows child drivers to register event to triton driver.
// When interrupt happends, triton driver will trigger the related event.
//
static
BOOL
TWL_SetIntrEvent(
DWORD context,
DWORD intrId,
HANDLE hEvent
)
{
BOOL rc = FALSE;
Device_t *pDevice = (Device_t*)context;
// Check if we get correct context
if ((pDevice == NULL) || (pDevice->cookie != TWL_DEVICE_COOKIE)) {
DEBUGMSG(ZONE_ERROR, (L"ERROR: TWL_SetIntrEvent: "
L"Incorrect context parameter\r\n"
));
goto cleanUp;
}
if ((intrId > 16) && (intrId != (-1))) {
DEBUGMSG(ZONE_ERROR, (L"ERROR: TWL_SetIntrEvent: "
L"Incorrect interrupt Id %d\r\n", intrId
));
goto cleanUp;
}
// Common interrupt is stored in last position
if (intrId == (-1)) intrId = 16;
// If handle isn't NULL we set new association,
// otherwise we delete it....
if (hEvent != NULL) {
if (pDevice->hSetIntrEvent[intrId] != NULL) {
DEBUGMSG(ZONE_ERROR, (L"ERROR: TWL_SetIntrEvent: "
L"Interrupt Id %d already associated with event\r\n"
));
goto cleanUp;
}
rc = DuplicateHandle(
GetCurrentProcess(), hEvent, GetCurrentProcess(),
&pDevice->hSetIntrEvent[intrId], 0, FALSE, DUPLICATE_SAME_ACCESS
);
if (!rc) {
DEBUGMSG(ZONE_ERROR, (L"ERROR: TWL_SetIntrEvent: "
L"Event handler duplication failed\r\n"
));
goto cleanUp;
}
}
else {
if (pDevice->hSetIntrEvent[intrId] == NULL) {
DEBUGMSG(ZONE_ERROR, (L"ERROR: TWL_SetIntrEvent: "
L"Interrupt Id %d isn't associated with event\r\n"
));
goto cleanUp;
}
rc = CloseHandle(pDevice->hSetIntrEvent[intrId]);
pDevice->hSetIntrEvent[intrId] = NULL;
}
cleanUp:
return rc;
}
//------------------------------------------------------------------------------
// Child driver can call this function to enable the sub interrupt.
//
static
BOOL
TWL_IntrEnable(
DWORD context,
DWORD intrId
)
{
BOOL rc = FALSE;
Device_t *pDevice = (Device_t*)context;
BYTE mask;
BYTE offset;
// Check if we get correct context
if ((pDevice == NULL) || (pDevice->cookie != TWL_DEVICE_COOKIE)) {
DEBUGMSG(ZONE_ERROR, (L"ERROR: TWL_IntrEnable: "
L"Incorrect context parameter\r\n"
));
goto cleanUp;
}
if (intrId > 16)
{
DEBUGMSG(ZONE_ERROR, (L"ERROR: TWL_IntrEnable: "
L"Incorrect interrupt Id %d\r\n", intrId
));
goto cleanUp;
}
// We have take critical section there to avoid concurrent
// enable register modification
if (intrId < 8) {
offset = MENELAUS_INTMASK1_OFFSET;
}
else {
offset = MENELAUS_INTMASK2_OFFSET;
intrId -= 8;
}
EnterCriticalSection(&pDevice->cs);
// Get actual mask
if (!ReadRegs(pDevice, offset, &mask, sizeof(mask))) {
goto cleanUp;
}
// Enable interrupt
mask &= ~(1 << intrId);
// Write it back
if (!WriteRegs(pDevice, offset, &mask, sizeof(mask))) {
goto cleanUp;
}
rc = TRUE;
cleanUp:
LeaveCriticalSection(&pDevice->cs);
return rc;
}
//------------------------------------------------------------------------------
// Child driver can call this fucntion to disable the sub interrupt.
//
static
BOOL
TWL_IntrDisable(
DWORD context,
DWORD intrId
)
{
BOOL rc = FALSE;
Device_t *pDevice = (Device_t*)context;
BYTE mask;
BYTE offset;
// Check if we get correct context
if ((pDevice == NULL) || (pDevice->cookie != TWL_DEVICE_COOKIE)) {
DEBUGMSG(ZONE_ERROR, (L"ERROR: TWL_IntrDisable: "
L"Incorrect context parameter\r\n"
));
goto cleanUp;
}
if (intrId > 16)
{
DEBUGMSG(ZONE_ERROR, (L"ERROR: TWL_IntrDisable: "
L"Incorrect interrupt Id %d\r\n", intrId
));
goto cleanUp;
}
if (intrId < 8)
{
offset = MENELAUS_INTMASK1_OFFSET;
}
else
{
offset = MENELAUS_INTMASK2_OFFSET;
intrId -= 8;
}
// We have take critical section there to avoid concurrent
// enable register modification
EnterCriticalSection(&pDevice->cs);
// Get actual mask
if (!ReadRegs(pDevice, offset, &mask, sizeof(mask))) {
goto cleanUp;
}
// Disable interrupt
mask |= (1 << intrId);
// Write it back
if (!WriteRegs(pDevice, offset, &mask, sizeof(mask))) {
goto cleanUp;
}
rc = TRUE;
cleanUp:
LeaveCriticalSection(&pDevice->cs);
return rc;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOL
ReadRegs(
Device_t *pDevice,
DWORD address,
UCHAR *pBuffer,
DWORD size
)
{
I2CTRANS trans;
ZeroMemory(&trans,sizeof(trans));
trans.mClk_HL_Divisor = I2C_CLOCK_100Khz;
/* first write register address */
trans.mOpCode[0] = I2C_OPCODE_WRITE;
trans.mBufferOffset[0] = 0;
trans.mTransLen[0] = 1;
trans.mBuffer[0] = (BYTE)address;
/* then read back data from that address */
trans.mOpCode[1] = I2C_OPCODE_READ;
trans.mBufferOffset[1] = 0;
trans.mTransLen[1] = 1;
I2CTransact(pDevice->hI2C, &trans);
*pBuffer = trans.mBuffer[0];
return (trans.mErrorCode == 0);
}
//------------------------------------------------------------------------------
BOOL
WriteRegs(
Device_t *pDevice,
DWORD address,
const UCHAR *pBuffer,
DWORD size
)
{
I2CTRANS trans;
ZeroMemory(&trans,sizeof(trans));
trans.mClk_HL_Divisor = I2C_CLOCK_100Khz;
/* just write the register # then the data in one shot */
trans.mOpCode[0] = I2C_OPCODE_WRITE;
trans.mBufferOffset[0] = 0;
trans.mTransLen[0] = 2;
trans.mBuffer[0] = (BYTE)address;
trans.mBuffer[1] = ((UCHAR*)pBuffer)[0];
I2CTransact(pDevice->hI2C, &trans);
return (trans.mErrorCode == 0);
}
//------------------------------------------------------------------------------
//
// Function: DllMain
//
// Standard Windows DLL entry point.
//
BOOL
__stdcall
DllMain(
HANDLE hDLL,
DWORD reason,
VOID *pReserved
)
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
DEBUGREGISTER(hDLL);
DisableThreadLibraryCalls((HMODULE)hDLL);
break;
}
return TRUE;
}
//------------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -