/***************************************************************************\ * * ************************ * * 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; }