You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
494 lines
12 KiB
494 lines
12 KiB
/***************************************************************************\
|
|
*
|
|
* ************************
|
|
* * MINIPORT SAMPLE CODE *
|
|
* ************************
|
|
*
|
|
* Module Name:
|
|
*
|
|
* i2c.c
|
|
*
|
|
* Abstract:
|
|
*
|
|
* This module contains the code that implements the i2c interface feature
|
|
*
|
|
*
|
|
* Environment:
|
|
*
|
|
* Kernel mode
|
|
*
|
|
*
|
|
* Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved.
|
|
* Copyright (c) 1995-2003 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
#include "perm3.h"
|
|
#include "i2c.h"
|
|
|
|
#if defined(ALLOC_PRAGMA)
|
|
#pragma alloc_text(PAGE,GetCookie)
|
|
#pragma alloc_text(PAGE,I2CBusOpenCRT)
|
|
#pragma alloc_text(PAGE,I2CBusOpenDFP)
|
|
#pragma alloc_text(PAGE,I2CBusOpen)
|
|
#pragma alloc_text(PAGE,I2CBusAccessCRT)
|
|
#pragma alloc_text(PAGE,I2CBusAccessDFP)
|
|
#pragma alloc_text(PAGE,I2CBusAccess)
|
|
#pragma alloc_text(PAGE,I2CNull)
|
|
#pragma alloc_text(PAGE,I2CRead)
|
|
#pragma alloc_text(PAGE,I2CWrite)
|
|
#pragma alloc_text(PAGE,I2CStart)
|
|
#pragma alloc_text(PAGE,I2CStop)
|
|
#pragma alloc_text(PAGE,InterfaceReference)
|
|
#pragma alloc_text(PAGE,InterfaceDereference)
|
|
#pragma alloc_text(PAGE,Perm3QueryInterface)
|
|
#endif
|
|
|
|
VIDEO_I2C_CONTROL
|
|
I2CCallbacksCRT = {
|
|
I2CWriteClock,
|
|
I2CWriteData,
|
|
I2CReadClock,
|
|
I2CReadData,
|
|
0
|
|
};
|
|
|
|
VIDEO_I2C_CONTROL
|
|
I2CCallbacksDFP = {
|
|
I2CWriteClockDFP,
|
|
I2CWriteDataDFP,
|
|
I2CReadClockDFP,
|
|
I2CReadDataDFP,
|
|
0
|
|
};
|
|
|
|
BOOLEAN
|
|
GetCookie(
|
|
PVOID DeviceObject,
|
|
PULONG Cookie
|
|
)
|
|
{
|
|
*Cookie = 0x12345678;
|
|
return TRUE;
|
|
}
|
|
|
|
VP_STATUS
|
|
I2CBusOpenCRT(
|
|
PVOID DeviceObject,
|
|
BOOLEAN bOpen,
|
|
PI2CControl I2CControl
|
|
)
|
|
|
|
{
|
|
return I2CBusOpen(DeviceObject, bOpen, I2CControl, &I2CCallbacksCRT);
|
|
}
|
|
|
|
VP_STATUS
|
|
I2CBusOpenDFP(
|
|
PVOID DeviceObject,
|
|
BOOLEAN bOpen,
|
|
PI2CControl I2CControl
|
|
)
|
|
|
|
{
|
|
return I2CBusOpen(DeviceObject, bOpen, I2CControl, &I2CCallbacksDFP);
|
|
}
|
|
|
|
VP_STATUS
|
|
I2CBusOpen(
|
|
PVOID DeviceObject,
|
|
BOOLEAN bOpen,
|
|
PI2CControl I2CControl,
|
|
PVIDEO_I2C_CONTROL I2CCallbacks
|
|
)
|
|
|
|
{
|
|
PHW_DEVICE_EXTENSION hwDeviceExtension;
|
|
VP_STATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
hwDeviceExtension = VideoPortGetAssociatedDeviceExtension(DeviceObject);
|
|
|
|
VideoPortAcquireDeviceLock(hwDeviceExtension);
|
|
|
|
I2CControl->Status = I2C_STATUS_NOERROR;
|
|
|
|
if (bOpen) {
|
|
|
|
if (I2CControl->ClockRate > MAX_CLOCK_RATE) {
|
|
I2CControl->ClockRate = MAX_CLOCK_RATE;
|
|
}
|
|
|
|
I2CCallbacks->I2CDelay = (MAX_CLOCK_RATE / I2CControl->ClockRate) * 10;
|
|
|
|
if (GetCookie(DeviceObject, &I2CControl->dwCookie)) {
|
|
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
} else {
|
|
|
|
I2CControl->dwCookie = 0;
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
VideoPortReleaseDeviceLock(hwDeviceExtension);
|
|
|
|
return Status;
|
|
}
|
|
|
|
VP_STATUS
|
|
I2CBusAccessCRT(
|
|
PVOID DeviceObject,
|
|
PI2CControl I2CControl
|
|
)
|
|
|
|
{
|
|
return I2CBusAccess(DeviceObject, I2CControl, &I2CCallbacksCRT);
|
|
}
|
|
|
|
VP_STATUS
|
|
I2CBusAccessDFP(
|
|
PVOID DeviceObject,
|
|
PI2CControl I2CControl
|
|
)
|
|
|
|
{
|
|
return I2CBusAccess(DeviceObject, I2CControl, &I2CCallbacksDFP);
|
|
}
|
|
|
|
VP_STATUS
|
|
I2CBusAccess(
|
|
PVOID DeviceObject,
|
|
PI2CControl I2CControl,
|
|
PVIDEO_I2C_CONTROL I2CCallbacks
|
|
)
|
|
|
|
{
|
|
PHW_DEVICE_EXTENSION hwDeviceExtension;
|
|
VP_STATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
hwDeviceExtension = VideoPortGetAssociatedDeviceExtension(DeviceObject);
|
|
|
|
VideoPortAcquireDeviceLock(hwDeviceExtension);
|
|
|
|
I2CControl->Status = I2C_STATUS_NOERROR;
|
|
|
|
if (I2CControl->ClockRate > MAX_CLOCK_RATE) {
|
|
I2CControl->ClockRate = MAX_CLOCK_RATE;
|
|
}
|
|
|
|
I2CCallbacks->I2CDelay = (MAX_CLOCK_RATE / I2CControl->ClockRate) * 10;
|
|
|
|
switch(I2CControl->Command) {
|
|
|
|
case I2C_COMMAND_NULL:
|
|
|
|
I2CNull(I2CControl, I2CCallbacks, hwDeviceExtension);
|
|
break;
|
|
|
|
case I2C_COMMAND_READ:
|
|
|
|
I2CRead(I2CControl, I2CCallbacks, hwDeviceExtension);
|
|
break;
|
|
|
|
case I2C_COMMAND_WRITE:
|
|
|
|
I2CWrite(I2CControl, I2CCallbacks, hwDeviceExtension);
|
|
break;
|
|
|
|
case I2C_COMMAND_RESET:
|
|
|
|
//
|
|
// A reset is just a stop.
|
|
//
|
|
|
|
I2CStop(I2CControl, I2CCallbacks, hwDeviceExtension);
|
|
break;
|
|
|
|
case I2C_COMMAND_STATUS:
|
|
|
|
break;
|
|
|
|
default:
|
|
I2CControl->Status = I2C_STATUS_ERROR;
|
|
}
|
|
|
|
VideoPortReleaseDeviceLock(hwDeviceExtension);
|
|
|
|
return I2CControl->Status;
|
|
}
|
|
|
|
ULONG
|
|
I2CNull(
|
|
PI2CControl I2CControl,
|
|
PVIDEO_I2C_CONTROL I2CCallbacks,
|
|
PHW_DEVICE_EXTENSION hwDeviceExtension
|
|
)
|
|
|
|
{
|
|
I2CControl->Status = I2C_STATUS_NOERROR;
|
|
|
|
if (I2CControl->Flags & I2C_FLAGS_DATACHAINING) {
|
|
hwDeviceExtension->I2CInterface.I2CStop(hwDeviceExtension, I2CCallbacks);
|
|
hwDeviceExtension->I2CInterface.I2CStart(hwDeviceExtension, I2CCallbacks);
|
|
}
|
|
|
|
if (I2CControl->Flags & I2C_FLAGS_START) {
|
|
hwDeviceExtension->I2CInterface.I2CStart(hwDeviceExtension, I2CCallbacks);
|
|
}
|
|
|
|
if (I2CControl->Flags & I2C_FLAGS_STOP) {
|
|
hwDeviceExtension->I2CInterface.I2CStop(hwDeviceExtension, I2CCallbacks);
|
|
}
|
|
|
|
return I2CControl->Status;
|
|
}
|
|
|
|
ULONG
|
|
I2CRead(
|
|
PI2CControl I2CControl,
|
|
PVIDEO_I2C_CONTROL I2CCallbacks,
|
|
PHW_DEVICE_EXTENSION hwDeviceExtension
|
|
)
|
|
|
|
{
|
|
BOOLEAN Result;
|
|
|
|
I2CControl->Status = I2C_STATUS_NOERROR;
|
|
|
|
if (I2CControl->Flags & I2C_FLAGS_DATACHAINING) {
|
|
hwDeviceExtension->I2CInterface.I2CStop(hwDeviceExtension, I2CCallbacks);
|
|
hwDeviceExtension->I2CInterface.I2CStart(hwDeviceExtension, I2CCallbacks);
|
|
}
|
|
|
|
if (I2CControl->Flags & I2C_FLAGS_START) {
|
|
hwDeviceExtension->I2CInterface.I2CStart(hwDeviceExtension, I2CCallbacks);
|
|
}
|
|
|
|
Result = hwDeviceExtension->I2CInterface.I2CRead(
|
|
hwDeviceExtension,
|
|
I2CCallbacks,
|
|
&I2CControl->Data,
|
|
1,
|
|
(I2CControl->Flags & I2C_FLAGS_ACK) ? FALSE : TRUE);
|
|
|
|
if (Result == TRUE) {
|
|
I2CControl->Status = I2C_STATUS_NOERROR;
|
|
} else {
|
|
I2CControl->Status = I2C_STATUS_ERROR;
|
|
}
|
|
|
|
if (I2CControl->Flags & I2C_FLAGS_STOP) {
|
|
hwDeviceExtension->I2CInterface.I2CStop(hwDeviceExtension, I2CCallbacks);
|
|
}
|
|
|
|
return I2CControl->Status;
|
|
}
|
|
|
|
ULONG
|
|
I2CWrite(
|
|
PI2CControl I2CControl,
|
|
PVIDEO_I2C_CONTROL I2CCallbacks,
|
|
PHW_DEVICE_EXTENSION hwDeviceExtension
|
|
)
|
|
|
|
{
|
|
BOOLEAN Result;
|
|
|
|
I2CControl->Status = I2C_STATUS_NOERROR;
|
|
|
|
if (I2CControl->Flags & I2C_FLAGS_DATACHAINING) {
|
|
hwDeviceExtension->I2CInterface.I2CStop(hwDeviceExtension, I2CCallbacks);
|
|
hwDeviceExtension->I2CInterface.I2CStart(hwDeviceExtension, I2CCallbacks);
|
|
}
|
|
|
|
if (I2CControl->Flags & I2C_FLAGS_START) {
|
|
hwDeviceExtension->I2CInterface.I2CStart(hwDeviceExtension, I2CCallbacks);
|
|
}
|
|
|
|
Result = hwDeviceExtension->I2CInterface.I2CWrite(
|
|
hwDeviceExtension,
|
|
I2CCallbacks,
|
|
&I2CControl->Data,
|
|
1);
|
|
|
|
if (Result == TRUE) {
|
|
I2CControl->Status = I2C_STATUS_NOERROR;
|
|
} else {
|
|
I2CControl->Status = I2C_STATUS_ERROR;
|
|
}
|
|
|
|
if (I2CControl->Flags & I2C_FLAGS_STOP) {
|
|
hwDeviceExtension->I2CInterface.I2CStop(hwDeviceExtension, I2CCallbacks);
|
|
}
|
|
|
|
return I2CControl->Status;
|
|
}
|
|
|
|
ULONG
|
|
I2CStop(
|
|
PI2CControl I2CControl,
|
|
PVIDEO_I2C_CONTROL I2CCallbacks,
|
|
PHW_DEVICE_EXTENSION hwDeviceExtension
|
|
)
|
|
|
|
{
|
|
BOOLEAN Result;
|
|
|
|
Result = hwDeviceExtension->I2CInterface.I2CStop(hwDeviceExtension, I2CCallbacks);
|
|
|
|
if (Result == TRUE) {
|
|
I2CControl->Status = I2C_STATUS_NOERROR;
|
|
} else {
|
|
I2CControl->Status = I2C_STATUS_ERROR;
|
|
}
|
|
|
|
return I2CControl->Status;
|
|
}
|
|
|
|
ULONG
|
|
I2CStart(
|
|
PI2CControl I2CControl,
|
|
PVIDEO_I2C_CONTROL I2CCallbacks,
|
|
PHW_DEVICE_EXTENSION hwDeviceExtension
|
|
)
|
|
|
|
{
|
|
BOOLEAN Result;
|
|
|
|
Result = hwDeviceExtension->I2CInterface.I2CStart(hwDeviceExtension, I2CCallbacks);
|
|
|
|
if (Result == TRUE) {
|
|
I2CControl->Status = I2C_STATUS_NOERROR;
|
|
} else {
|
|
I2CControl->Status = I2C_STATUS_ERROR;
|
|
}
|
|
|
|
return I2CControl->Status;
|
|
}
|
|
|
|
VOID
|
|
InterfaceReference(
|
|
IN PVOID pContext
|
|
)
|
|
|
|
{
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
InterfaceDereference(
|
|
IN PVOID pContext
|
|
)
|
|
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
VP_STATUS
|
|
Perm3QueryInterface(
|
|
PVOID HwDeviceExtension,
|
|
PQUERY_INTERFACE pQueryInterface
|
|
)
|
|
|
|
{
|
|
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
|
|
VP_STATUS Status;
|
|
ULONG HwID;
|
|
|
|
if (IsEqualGUID(pQueryInterface->InterfaceType, &GUID_I2C_INTERFACE)) {
|
|
|
|
I2CINTERFACE *Interface = (I2CINTERFACE *)pQueryInterface->Interface;
|
|
|
|
if ((pQueryInterface->Size == sizeof(I2CINTERFACE)) &&
|
|
(pQueryInterface->Version == 2))
|
|
{
|
|
|
|
//
|
|
// Get interface pointers for i2c interface help functions
|
|
//
|
|
|
|
if (hwDeviceExtension->I2CInterfaceAcquired == FALSE) {
|
|
|
|
hwDeviceExtension->I2CInterface.Size = sizeof(VIDEO_PORT_I2C_INTERFACE_2);
|
|
hwDeviceExtension->I2CInterface.Version = VIDEO_PORT_I2C_INTERFACE_VERSION_2;
|
|
|
|
Status = VideoPortQueryServices(
|
|
hwDeviceExtension,
|
|
VideoPortServicesI2C,
|
|
(PINTERFACE)&hwDeviceExtension->I2CInterface);
|
|
|
|
if (Status != NO_ERROR) {
|
|
|
|
VideoDebugPrint((1, "Perm3QueryInterface: Failed to acquire I2C services\n"));
|
|
return Status;
|
|
}
|
|
|
|
hwDeviceExtension->I2CInterfaceAcquired = TRUE;
|
|
}
|
|
|
|
if (((ULONG_PTR)pQueryInterface->InterfaceSpecificData != 0) &&
|
|
((ULONG_PTR)pQueryInterface->InterfaceSpecificData != -1)) {
|
|
|
|
//
|
|
// Get the HwID for the child requesting this interface
|
|
//
|
|
|
|
HwID = VideoPortGetAssociatedDeviceID(
|
|
pQueryInterface->InterfaceSpecificData);
|
|
|
|
} else {
|
|
|
|
if (hwDeviceExtension->Perm3Capabilities & PERM3_DFP_MON_ATTACHED) {
|
|
HwID = PERM3_DFP_MONITOR;
|
|
} else {
|
|
HwID = PERM3_DDC_MONITOR;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Initialize the interface
|
|
//
|
|
|
|
Interface->_vddInterface.Size = sizeof(I2CINTERFACE);
|
|
Interface->_vddInterface.Version = 2;
|
|
Interface->_vddInterface.Context = HwDeviceExtension;
|
|
|
|
Interface->_vddInterface.InterfaceReference = InterfaceReference;
|
|
Interface->_vddInterface.InterfaceDereference = InterfaceDereference;
|
|
|
|
if (HwID == PERM3_DDC_MONITOR) {
|
|
|
|
Interface->i2cOpen = I2CBusOpenCRT;
|
|
Interface->i2cAccess = I2CBusAccessCRT;
|
|
|
|
} else if (HwID == PERM3_DFP_MONITOR) {
|
|
|
|
Interface->i2cOpen = I2CBusOpenDFP;
|
|
Interface->i2cAccess = I2CBusAccessDFP;
|
|
}
|
|
|
|
//
|
|
// Reference the interface before handing it out
|
|
//
|
|
|
|
Interface->_vddInterface.InterfaceReference(Interface->_vddInterface.Context);
|
|
|
|
Status = NO_ERROR;
|
|
|
|
} else {
|
|
|
|
VideoDebugPrint((1, "Perm3QueryInterface: Size or version incorrect\n"));
|
|
Status = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
} else {
|
|
|
|
VideoDebugPrint((1, "Perm3QueryInteface: Unsupported Interface\n"));
|
|
Status = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
VideoDebugPrint((1, "Perm3QueryInterface: Status = 0x%x\n", Status));
|
|
return Status;
|
|
}
|