File:  [Apple Darwin 0.x] / driverkit / libDriver / ppc / IOSmartDisplay.m
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:37:51 2018 UTC (8 years, 3 months ago) by root
Branches: MAIN, Apple
CVS tags: HEAD, Darwin03, Darwin02
Darwin 0.2 Driver Kit

/*
 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
 * Reserved.  This file contains Original Code and/or Modifications of
 * Original Code as defined in and that are subject to the Apple Public
 * Source License Version 1.1 (the "License").  You may not use this file
 * except in compliance with the License.  Please obtain a copy of the
 * License at http://www.apple.com/publicsource and read it before using
 * this file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
/*
 * Copyright (c) 1997 Apple Computer, Inc.
 *
 *
 * HISTORY
 *
 * Simon Douglas  22 Oct 97
 * - first checked in.
 */



#import  <driverkit/ppc/IOMacOSTypes.h>
#import "IOMacOSVideo.h"
#import	<driverkit/ppc/IOSmartDisplay.h>
#import <mach/mach_types.h>
#import <mach/message.h>
#import <bsd/dev/ppc/busses.h>
#import <bsd/dev/ppc/adb.h>

@interface IOSmartDisplay:Object <IOSmartDisplayExported>
{
    // used to query the framebuffer controller
    id			attachedFramebuffer;
    UInt32		attachedRefCon;

@private
    void *		priv;
    
    /* Reserved for future expansion. */
    int _IOSmartDisplay_reserved[2];
}

@end

struct AVDeviceInfo
{
    UInt8		wiggleLADAddr;
    UInt32		numTimings;
    const UInt32    *   timings;
};
typedef struct AVDeviceInfo AVDeviceInfo;

@interface IOSmartADBDisplay:IOSmartDisplay
{
@private
    UInt8		adbAddr;
    UInt8		waitAckValue;
    SInt16		avDisplayID;
    const AVDeviceInfo * deviceInfo;
}

+ probeADBForDisplays;		// strictly temporary!

@end

struct EDID {
    UInt8	header[8];
    UInt8	vendorProduct[10];
    UInt8	version;
    UInt8	revision;
    UInt8	displayParams[5];
    UInt8	colorCharacteristics[10];
    UInt8	establishedTimings[3];
    UInt16	standardTimings[8];
    UInt8	detailedTimings[72];
    UInt8	extension;
    UInt8	checksum;
};
typedef struct EDID EDID;

@interface IOSmartDDCDisplay:IOSmartDisplay
{
@private
    EDID		edid1;

}

@end


static UInt32	smInited = 0;			// why does +initialize get called twice?
static IOSmartADBDisplay * ADB2SmartDisplay[ ADB_DEVICE_COUNT ];

@implementation IOSmartDisplay

+ findForConnection:framebuffer refCon:(UInt32)refCon
{
    IOSmartADBDisplay *	try;
    IOSmartDisplay *	found = nil;
    UInt32		i;

    if( !smInited) {
        smInited = YES;
        [IOSmartADBDisplay probeADBForDisplays];
    }

    if( [framebuffer conformsTo:@protocol( IOFBAppleSense)])
    {
        for (i = 0; (found == nil) && (i < ADB_DEVICE_COUNT); i++ ) {
            try = ADB2SmartDisplay[ i ];
            found = [try attach:framebuffer refCon:refCon];
        }
    }

    if( (found == nil) && [framebuffer conformsTo:@protocol( IOFBHighLevelDDCSense)])
    {
	found = [[[IOSmartDDCDisplay alloc] init] attach:framebuffer refCon:refCon];
    }

    if( found == nil)
	found = [[[IOSmartDisplay alloc] init] attach:framebuffer refCon:refCon];

    return( found);
}

- attach:framebuffer refCon:(UInt32)refCon;
{
    attachedFramebuffer = framebuffer;
    attachedRefCon = refCon;
    return( self);
}

- detach
{
    attachedFramebuffer = nil;
    return( self);
}

- (BOOL) attached
{
    return( attachedFramebuffer != nil);
}

- (IOReturn) getDisplayInfoForMode:(IOFBTimingInformation *)mode flags:(UInt32 *)flags
{
    // Pass the existing flags (from framebuffer) thru
    return( noErr);
}

- (IOReturn)
    getGammaTableByIndex:
	(UInt32 *)channelCount dataCount:(UInt32 *)dataCount
    	dataWidth:(UInt32 *)dataWidth data:(void **)data
{
    return( IO_R_UNSUPPORTED);
}
@end

@implementation IOSmartDDCDisplay

- attach:framebuffer refCon:(UInt32)refCon
{
    IOReturn		err;
    IOByteCount		length;

    do {
	if( NO == [framebuffer hasDDCConnect:refCon])
	    continue;

	length = sizeof( EDID);
	err = [framebuffer getDDCBlock:refCon blockNumber:1 blockType:kIOFBDDCBlockTypeEDID
		options:0 data:(UInt8 *)&edid1 length:&length];
	if( err || (length != sizeof( EDID)))
	    continue;

	kprintf("%s EDID Version %d, Revision %d\n", [framebuffer name],
	    edid1.version, edid1.revision );
	if( edid1.version != 1)
	    continue;
#if 1
    {
	int i;

	kprintf("Est: ");
	for( i=0; i<3; i++)
	    kprintf(" 0x%02x,", edid1.establishedTimings[i] );
	kprintf("\nStd: " );
	for( i=0; i<8; i++)
	    kprintf(" 0x%04x,", edid1.standardTimings[i] );
	kprintf("\n");
    }
#endif

	kprintf("IOSmartDDCDisplay attach on %s\n", [framebuffer name]);
	return( [super attach:framebuffer refCon:refCon]);

    } while( false);

    return([self free]);
}


struct TimingToEDID {
    UInt32	timingID;
    UInt16	standardTiming;
    UInt8	establishedBit;
    UInt8	spare;
};
typedef struct TimingToEDID TimingToEDID;

#define MAKESTD(h,a,r)		( (((h/8)-31)<<8) | (a<<6) | (r-60) )

static const TimingToEDID timingToEDID[] = {
    { timingApple_512x384_60hz,		MAKESTD(  512,1,60), 0xff, 0 },
    { timingApple_640x480_67hz,		MAKESTD(  640,1,67), 0x04, 0 },
    { timingVESA_640x480_60hz,		MAKESTD(  640,1,60), 0x05, 0 },
    { timingVESA_640x480_72hz ,		MAKESTD(  640,1,72), 0x03, 0 },
    { timingVESA_640x480_75hz,		MAKESTD(  640,1,75), 0x02, 0 },
    { timingVESA_640x480_85hz,		MAKESTD(  640,1,85), 0xff, 0 },
    { timingApple_832x624_75hz,		MAKESTD(  832,1,75), 0x0d, 0 },
    { timingVESA_800x600_56hz,		MAKESTD(  800,1,56), 0x01, 0 },
    { timingVESA_800x600_60hz,		MAKESTD(  800,1,60), 0x00, 0 },
    { timingVESA_800x600_72hz,		MAKESTD(  800,1,72), 0x0f, 0 },
    { timingVESA_800x600_75hz,		MAKESTD(  800,1,75), 0x0e, 0 },
    { timingVESA_800x600_85hz,		MAKESTD(  800,1,85), 0xff, 0 },
    { timingVESA_1024x768_60hz,		MAKESTD( 1024,1,60), 0x0b, 0 },
    { timingVESA_1024x768_70hz,		MAKESTD( 1024,1,70), 0x0a, 0 },
    { timingVESA_1024x768_75hz,		MAKESTD( 1024,1,75), 0x09, 0 },
    { timingVESA_1024x768_85hz,		MAKESTD( 1024,1,85), 0xff, 0 },
    { timingApple_1024x768_75hz,	MAKESTD( 1024,1,75), 0x09, 0 },
    { timingApple_1152x870_75hz,	MAKESTD( 0000,0,00), 0x17, 0 },
    { timingVESA_1280x960_75hz,		MAKESTD( 1280,1,75), 0xff, 0 },
    { timingVESA_1280x1024_60hz,	MAKESTD( 1280,2,60), 0xff, 0 },
    { timingVESA_1280x1024_75hz,	MAKESTD( 1280,2,75), 0x08, 0 },
    { timingVESA_1280x1024_85hz,	MAKESTD( 1280,2,85), 0xff, 0 },
    { timingVESA_1600x1200_60hz,	MAKESTD( 1600,1,60), 0xff, 0 },
    { timingVESA_1600x1200_65hz,	MAKESTD( 1600,1,65), 0xff, 0 },
    { timingVESA_1600x1200_70hz,	MAKESTD( 1600,1,70), 0xff, 0 },
    { timingVESA_1600x1200_75hz,	MAKESTD( 1600,1,75), 0xff, 0 },
    { timingVESA_1600x1200_80hz,	MAKESTD( 1600,1,80), 0xff, 0 }
};

- (IOReturn) getDisplayInfoForMode:(IOFBTimingInformation *)mode flags:(UInt32 *)flags
{
    const TimingToEDID	*	lookTiming;
    UInt32			estBit, i;
    enum {			kSetFlags = (kDisplayModeValidFlag | kDisplayModeSafeFlag) };

    lookTiming = timingToEDID;
    while( lookTiming < (timingToEDID + sizeof( timingToEDID) / sizeof( TimingToEDID))) {

	if( lookTiming->timingID == mode->standardTimingID) {
	    estBit = lookTiming->establishedBit;
	    if( estBit != 0xff) {
		if( edid1.establishedTimings[ estBit / 8 ] & (1 << (estBit % 8)))
		    *flags = kSetFlags;
	    }
	    for( i = 0; i < 8; i++ ) {
		if( lookTiming->standardTiming == edid1.standardTimings[ i ]) {
		    *flags = kSetFlags;
		    break;
		}
	    }
	    break;
	}
	lookTiming++;
    }

    // Pass the existing flags (from framebuffer) thru
    return( noErr);
}

@end


#define	kOrgDisplayAddr 		0x7		// Original display ADB address

#define kTelecasterADBHandlerID		0x03
#define kSmartDisplayADBHandlerID	0xc0

#define	kADBReg0			0x0		// Device register zero
#define	kADBReg1			0x1		// Device register one
#define	kADBReg2			0x2		// Device register two
#define	kADBReg3			0x3		// Device register three

#define	kReg2DataRdy			0xFD	// data (to be read) ready
#define	kReg2DataAck			0xFE	// data (just written) OK

#define	kNoDevice		-1
#define	kTelecaster		0
#define	kSousaSoundUnit		1
#define	kHammerhead		2
#define	kOrca			3
#define	kWhaler			4
#define kWarriorEZ		5
#define kManta			6
#define kLastDeviceType		kManta


#define kWiggleLADAddr			0x04	// 0x0f on Telecaster & Sousa?
#define kDisplayLocalRemoteLADAddr	0x02	// lad address used in SetDisplayRemoteMode
#define kAudioKeypadEnableLADAddr	0x7D

#define kUnknown	-1
#define kLocal		0
#define kRemote		1

static const UInt32		orcaTimings[] = {
	timingApple_640x480_67hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag,
	timingVESA_640x480_75hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag,
	timingVESA_640x480_85hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag,
	timingApple_832x624_75hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag,
	timingApple_1024x768_75hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag,
	timingVESA_1024x768_85hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag,
	timingApple_1152x870_75hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag | kDisplayModeDefaultFlag,
	timingVESA_1280x960_75hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag,
	timingVESA_1280x1024_75hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag,
	timingVESA_1280x1024_85hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag,
	timingVESA_1600x1200_60hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag,
	timingVESA_1600x1200_65hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag,
	timingVESA_1600x1200_70hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag,
	timingVESA_1600x1200_75hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag
};

static const UInt32		hammerheadTimings[] = {
	timingApple_640x480_67hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag,
	timingApple_832x624_75hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag,
	timingApple_1024x768_75hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag,
	timingApple_1152x870_75hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag | kDisplayModeDefaultFlag,
	timingVESA_1280x960_75hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag,
	timingVESA_1280x1024_75hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag,
	timingVESA_1600x1200_60hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag,
};

static const UInt32		mantaTimings[] = {
	timingApple_640x480_67hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag,
	timingApple_832x624_75hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag,
	timingApple_1024x768_75hz,	kDisplayModeValidFlag | kDisplayModeSafeFlag | kDisplayModeDefaultFlag,
};


static const AVDeviceInfo	orcaInfo = 
{
	kWiggleLADAddr,
	sizeof( orcaTimings) / sizeof( UInt32) / 2, orcaTimings
};

static const AVDeviceInfo	hammerheadInfo = 
{
	kWiggleLADAddr,
	sizeof( hammerheadTimings) / sizeof( UInt32) / 2, hammerheadTimings
};

static const AVDeviceInfo	mantaInfo = 
{
	kWiggleLADAddr,
	sizeof( mantaTimings) / sizeof( UInt32) / 2, mantaTimings
};

static const AVDeviceInfo *	deviceInfoTable[ kLastDeviceType  + 1 ] = 
{ 
	0, 0, &hammerheadInfo, &orcaInfo, &orcaInfo, &hammerheadInfo, &mantaInfo
};


@implementation IOSmartADBDisplay

- (IOReturn) getDisplayInfoForMode:(IOFBTimingInformation *)mode flags:(UInt32 *)flags
{
    IOReturn		err = noErr;
    UInt32		numTimings;
    const UInt32    *	timings = deviceInfo->timings;

    *flags = 0;
    numTimings = deviceInfo->numTimings;
    while( numTimings--) {
	if( mode->standardTimingID == *(timings++)) {
	    *flags = *timings;
	    break;
	}
	timings++;
    }
    return( err);
}

- (IOReturn) doConnect
{
    IOReturn   	err;
    UInt16 	value;
    UInt32	retries = 9;

    while( retries--) {
	value = 0x6000 | (adbAddr << 8);
	err = adb_writereg( adbAddr, kADBReg3, value);
	if (err != ADB_RET_OK)
            continue;
	IOSleep(10);  
	/* IODelay(1000); */
	err = adb_readreg( adbAddr, kADBReg3, &value);
    	if (err != ADB_RET_OK)
	    continue;

	if( (value & 0xF000) == 0x6000)
	    break;
	else
	    err = ADB_RET_UNEXPECTED_RESULT;
    }

    if( err)
	kprintf( "SMDoConnect %d\n", err);

    return( err);
}


void SMADBHandler( int number, unsigned char *buffer, int count, void * ssp)
{
IOSmartADBDisplay * sm;

    sm = ADB2SmartDisplay[ number ];
    if( sm && count)
	if( *buffer == sm->waitAckValue)
	    sm->waitAckValue = 0;
}

- (IOReturn) writeWithAcknowledge:(UInt8)regNum data:(UInt16)data ackValue:(UInt8)ackValue
{
    IOReturn	err;
    enum { kTimeoutMS = 400 };
    UInt32	timeout;

    waitAckValue = ackValue;

    err = adb_writereg(adbAddr, regNum, data);

    if( !err) {
	timeout = kTimeoutMS / 10;
	while( waitAckValue && timeout--)
	    IOSleep( 10 );

	if( waitAckValue)
	    err = -3;
    }
    waitAckValue = 0;
    return( err);
}


- (IOReturn) setLogicalRegister:(UInt16)address data:(UInt16) data
{
IOReturn	err = -1;
UInt32		reconnects = 3;

    while( err && reconnects--)
    {
	err = [self writeWithAcknowledge:kADBReg1 data:address ackValue:kReg2DataRdy];
	if( err == noErr) {
	    err = [self writeWithAcknowledge:kADBReg2 data:data ackValue:kReg2DataAck];
	}
	if( err)
	    if( [self doConnect])
		break;
    }

    if( err)
	kprintf( "SMSetLogicalRegister %x, %d\n", address, err);

    return( err);
}


- (IOReturn) getLogicalRegister:(UInt16)address data:(UInt16 *) data
{
IOReturn	err = -1;
UInt32		reconnects = 3;
UInt16		value;

    while( err && reconnects--)
    {
	err = [self writeWithAcknowledge:kADBReg1 data:address ackValue:kReg2DataRdy];
	if( err == noErr) {
	    err = adb_readreg( adbAddr, kADBReg2, &value);
	    *data = value & 0xff;			// actually only 8 bit
	}
	if( err)
	    if( [self doConnect])
		break;
    }

    if( err)
	kprintf( "SMGetLogicalRegister %x=%x, %d\n", address, *data, err);

    return( err);
}

- setWiggle:(BOOL) active
{
    IOReturn	err;

    err = [self setLogicalRegister:deviceInfo->wiggleLADAddr data:(active ? 1 : 0)];
    return( self);
}

- initForADB:(UInt8)adbBusAddr
{
    IOReturn	err;
    UInt16	data, deviceType;

    [super init];
    adbAddr = adbBusAddr;

    ADB2SmartDisplay[ adbAddr ] = self;

    do {

	err = [self doConnect];
	if( err)
	    continue;
	adb_register_dev( adbAddr, SMADBHandler);
	err = [self setLogicalRegister:0xff data:0xff];
	if( err)
	    continue;
	err = [self getLogicalRegister:0xff data:&data];
	if( err)
	    continue;
	err = [self getLogicalRegister:0xff data:&deviceType];
	if( err)
	    continue;

	kprintf("Found ADBDisplay@%d, AVType %d\n", adbAddr, deviceType );

	if( (deviceType > kLastDeviceType)
	    || (deviceInfoTable[ deviceType ] == (const AVDeviceInfo *)0) ) {
	    err = -49;
	    continue;
	}

	avDisplayID = deviceType;
	deviceInfo = deviceInfoTable[ deviceType ];
	[self setWiggle:NO];

    } while( false);

    if( err) {
	return( [self free]);
    }
    return( self);
}

- free
{

//  adb_register_dev( adbAddr, 0);	// can't unregister!
    ADB2SmartDisplay[ adbAddr ] = 0;
    return( [super free]);
}

//kprintf( "%s: sense %d, ext sense %d\n", [framebuffer name], info.primarySense, info.extendedSense);

- attach:framebuffer refCon:(UInt32)refCon
{
    IOReturn		err;
    IOFBAppleSenseInfo	info;
    id			attached = nil;

    if( [self attached])
	return( nil);

    do {
	err = [framebuffer getAppleSense:refCon info:&info];
	if( err)
	    continue;
	if( (info.primarySense != kRSCSix) || (info.extendedSense != kESCSixStandard))		// straight-6
	    continue;

	[self setWiggle:YES];
	err = [framebuffer getAppleSense:refCon info:&info];
	[self setWiggle:NO];
	if( err)
	    continue;
	if( (info.primarySense != kRSCFour) || (info.extendedSense != kESCFourNTSC))		// straight-4
	    continue;

 	kprintf("ADBDisplay@%d attached to %s\n", adbAddr, [framebuffer name]);
	attached = [super attach:framebuffer refCon:refCon];

    } while( false);

    return( attached);
}

+ probeADBForDisplays
{
    struct adb_device   *devp;
    int 	i;

    devp = adb_devices;
    for (i = 0; i < ADB_DEVICE_COUNT; i++, devp++) {

        if ((devp->a_flags & ADB_FLAGS_PRESENT) == 0)
            continue;
	// no sense looking for telecaster since its fixed freq
	// && (devp->a_dev_handler != kTelecasterADBHandlerID) )
	if( (devp->a_dev_handler != kSmartDisplayADBHandlerID) )
            continue;

	[[IOSmartADBDisplay alloc] initForADB:i];
    }
    return( self);
}

@end

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.