+/*
+ File: DDCPowerOnOffUtils.c <CS3>
+*/
+
+enum{
+ kVCPSendSize = 8,
+ kVCPReplySize = 64,
+ kI2CDisplayWriteAddress = 0x6E,
+ kI2CDisplayReadAddress = 0x6F,
+ // Messed up specification says checksum should be calculated with ACCESS.bus value of 50.
+ kI2CDisplayReadHostCheckSumAddress = 0x50,
+ // Messed up specification says checksum should be calculated with ACCESS.bus value of 50.
+ kI2CDisplayReadHostAddress = 0x51,
+
+ kI2CVCPGetCode = 0x01,
+ kI2CVCPGetLength = 0x82,
+ kI2CVCPGetMessageSize = 0x05,
+
+ kI2CVCPReplyLength = 0x88,
+ kI2CNullReplyLength = 0x80,
+ kI2CNullReplyCheckSum = 0xBE,
+
+ kI2CVCPSetCode = 0x03,
+ kI2CVCPSetLength = 0x84,
+ kI2CVCPReplyCode = 0x02,
+
+ kDDCPowerOn = 0x01,
+ kDDCPowerOff = 0x04
+};
+enum {
+ kBasicI2CCommTransactionsMask = ( (1<<kVideoNoTransactionType) | (1<<kVideoSimpleI2CType)
+ | (1<<kVideoDDCciReplyType) )
+};
+
+void IONDRVFramebuffer::displayI2CPower( bool enable )
+{
+ VDCommunicationRec i2CRecord;
+ VDCommunicationInfoRec i2cInfoRecord;
+ Byte sendBuffer[8];
+ Byte replyBuffer[kVCPReplySize];
+ UInt32 supportedCommFlags = 0;
+ // Don't do it if we're told it's not supported
+ bool setThisDisplay = true;
+
+ //
+ // Some displays (like Fiji) do not support the reading
+ // of the current power state. Others (like Mitsubishi
+ // Diamond Pro 710) report that they do not support
+ // power management calls.
+ //
+ // I'll avoid sending the power command only in the
+ // case that I get a valid reply that does says
+ // it does not support the power selector.
+ //
+
+ bzero( &i2cInfoRecord, sizeof(i2cInfoRecord) );
+ if( noErr != doStatus( cscGetCommunicationInfo, &i2cInfoRecord))
+ return;
+ if( kBasicI2CCommTransactionsMask != (i2cInfoRecord.csSupportedTypes & kBasicI2CCommTransactionsMask))
+ return;
+ if( !shouldDoI2CPower)
+ return;
+
+ supportedCommFlags = i2cInfoRecord.csSupportedCommFlags;
+ bzero( &i2CRecord, sizeof(i2CRecord) );
+ bzero( &sendBuffer, sizeof(sendBuffer) );
+ bzero( &replyBuffer, sizeof(replyBuffer) );
+
+ sendBuffer[0] = kI2CDisplayReadHostAddress;
+ sendBuffer[1] = kI2CVCPGetLength;
+ sendBuffer[2] = kI2CVCPGetCode; // GetVCP command
+ sendBuffer[3] = 0xD6;
+ sendBuffer[4] = kI2CDisplayWriteAddress ^
+ sendBuffer[0] ^ sendBuffer[1] ^
+ sendBuffer[2] ^ sendBuffer[3];
+
+ i2CRecord.csBusID = kVideoDefaultBus;
+ i2CRecord.csSendType = kVideoSimpleI2CType;
+ i2CRecord.csSendAddress = kI2CDisplayWriteAddress;
+ i2CRecord.csSendBuffer = &sendBuffer;
+ i2CRecord.csSendSize = 7;
+ i2CRecord.csReplyType = kVideoDDCciReplyType;
+ i2CRecord.csReplyAddress = kI2CDisplayReadAddress;
+ i2CRecord.csReplyBuffer = &replyBuffer;
+ i2CRecord.csReplySize = kVCPReplySize;
+
+ if( supportedCommFlags & kVideoReplyMicroSecDelayMask )
+ {
+ // We know some displays are slow, this is an important call to get right
+ i2CRecord.csCommFlags |= kVideoReplyMicroSecDelayMask;
+ // 50 milliseconds should be enough time for the display to respond.
+ i2CRecord.csMinReplyDelay = 50 * 1000;
+ }
+
+ if( (noErr == doControl( cscDoCommunication, &i2CRecord))
+ && (kI2CDisplayWriteAddress == replyBuffer[0])
+ && (kI2CVCPReplyLength == replyBuffer[1])
+ && (kI2CVCPReplyCode == replyBuffer[2])) {
+ Byte checkSum = kI2CDisplayReadHostCheckSumAddress ^ // host address
+ replyBuffer[0] ^ // source address
+ replyBuffer[1] ^ // message length (0x88)
+ replyBuffer[2] ^ // VCP type code
+ replyBuffer[3] ^ // result code
+ replyBuffer[4] ^ // VCP op code
+ replyBuffer[5] ^ // VCP type code
+ replyBuffer[6] ^ // Max value MSB
+ replyBuffer[7] ^ // Max value LSB
+ replyBuffer[8] ^ // Current value MSB
+ replyBuffer[9]; // Current value LSB
+
+ if( (checkSum == replyBuffer[10]) && // Did the check sum match AND
+ (0 != replyBuffer[3])) // Are we not supposed to support this feature?
+ setThisDisplay = false; // Don't do it if we're told it's not supported
+ }
+
+ if( setThisDisplay) {
+
+ bzero( &i2CRecord, sizeof(i2CRecord) );
+ bzero( &sendBuffer, sizeof(sendBuffer) );
+ bzero( &replyBuffer, sizeof(replyBuffer) );
+
+ sendBuffer[0] = kI2CDisplayReadHostAddress;
+ sendBuffer[1] = kI2CVCPSetLength;
+ sendBuffer[2] = kI2CVCPSetCode; // SetVCP command
+ sendBuffer[3] = 0xD6;
+ sendBuffer[4] = 0; // MSB
+ sendBuffer[5] = enable ? kDDCPowerOn : kDDCPowerOff; // LSB
+ sendBuffer[6] = kI2CDisplayWriteAddress ^
+ sendBuffer[0] ^ sendBuffer[1] ^
+ sendBuffer[2] ^ sendBuffer[3] ^
+ sendBuffer[4] ^ sendBuffer[5];
+
+ i2CRecord.csBusID = kVideoDefaultBus;
+ i2CRecord.csSendAddress = kI2CDisplayWriteAddress;
+ i2CRecord.csSendType = kVideoSimpleI2CType;
+ i2CRecord.csSendBuffer = &sendBuffer;
+ i2CRecord.csSendSize = 7;
+ i2CRecord.csReplyType = kVideoNoTransactionType;
+ i2CRecord.csReplyAddress = 0;
+ i2CRecord.csReplyBuffer = 0;
+ i2CRecord.csReplySize = 0;
+
+ if( supportedCommFlags & kVideoReplyMicroSecDelayMask) {
+ // We know some displays are slow, this is an important call to get right
+ i2CRecord.csCommFlags |= kVideoReplyMicroSecDelayMask;
+ // 50 milliseconds should be enough time for the display to respond.
+ i2CRecord.csMinReplyDelay = 50 * 1000;
+ }
+
+ doControl( cscDoCommunication, &i2CRecord);
+ }
+}