File:  [NeXTSTEP 3.3 examples] / Examples / DriverKit / QVision / QVision_reloc.tproj / QVisionSetMode.m
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:49:00 2018 UTC (8 years, 1 month ago) by root
Branches: NeXT, MAIN
CVS tags: NeXTSTEP33, HEAD
Sample Programs from NeXSTEP 3.3

/* Copyright (c) 1993 by NeXT Computer, Inc as an unpublished work.
 * All rights reserved.
 *
 * QVisionSetMode.m -- Mode support for the QVision.
 *
 * NOTE: view this file with tabs set to 4 spaces
 *
 * Author:  Derek B Clegg	21 May 1993
 *	Based on work by Joe Pasqua.
 * Tue Aug 16 16:53:03 PDT 1994 James C. Lee
 *	Add 3.3 bus support & 8-bit color support.
 * Thu Sep 22 16:39:18 PDT 1994 James C. Lee
 *	Use the new PCI API that returns IOReturn instead of BOOL.
 */
#import <string.h>
#import <driverkit/generalFuncs.h>
#import <driverkit/i386/ioPorts.h>
#import <driverkit/i386/directDevice.h>
#import <driverkit/i386/IOPCIDeviceDescription.h>
#import <driverkit/i386/IOPCIDirectDevice.h>
#import <string.h>
#import <stdio.h>
//#import <stdlib.h>

#import "QVision.h"


/* private interfaces for SetMode category of QVision */
/*@interface QVision (SetMode_Private)
- (ConfigBusType) determineConfigBusType;
- (QVAdapterType) determineVLCardType;
- (QVAdapterType) determinePCICardType;
- (QVAdapterType) determineEISACardType;
@end
*/
/* The `SetMode' category of `QVision'. */

@implementation QVision (SetMode)

- (ConfigBusType) determineConfigBusType
{
	const char		*busTypeName;
	IOConfigTable	*configTable;
	
	configTable = [[self deviceDescription] configTable];
	busTypeName = [configTable valueForStringKey:"Bus Type"];
	if (strcmp(busTypeName, "PCI")==0) {
		busType = BusPCI;
	} else if (strcmp(busTypeName, "EISA")==0) {
		busType = BusEISA;
	} else {
		/* default to ISA or VL */
		busType = BusISAorVL;
	}
	return busType;
}

/* assume dac type is determined already. This method is called by
 * determineConfiguration only */
- (QVAdapterType) determineVLCardType
{
	QVAdapterType adapterType;
	
	adapterType = UnknownAdapter;
	switch (dac) {
		case Bt484:
			adapterType = OrionAdapter;
			break;
		case Bt485:
		case Bt485A:
		case ATT20C505:
			adapterType = Orion12Adapter;
			break;
		default:
			break;
	}
	return adapterType;
}

/* TODO: clean up error handling, i.e. return something meaningful rather
 * than returning [super free]; */
- (QVAdapterType) determinePCICardType
{
    unsigned int		physicalAddress;
	int					numRanges;
	IOPCIConfigSpace	configSpace;
	unsigned char		devNum, funcNum, busNum;
	unsigned long		vendorDeviceID;
	unsigned short		vendorID, deviceID;
	char				idString[11];
	id					deviceDescription;
	QVAdapterType 		adapterType;
	IOConfigTable		*configTable;
	IORange				*oldRange, newRange[3];

	adapterType = UnknownAdapter;
	if (![self isPCIPresent]) {
		IOLog ("%s: No PCI card found.\n", [self name]);
		return UnknownAdapter;
	}
	deviceDescription = [self deviceDescription]; 
	[deviceDescription getPCIdevice:&devNum function:&funcNum bus:&busNum];
	IOLog_dbg(("%s: PCI Dev:%d Func:%d Bus:%d\n", [self name], devNum,
		funcNum, busNum));
	[self getPCIConfigData:&vendorDeviceID atRegister:0x00];
	vendorID = (unsigned short) vendorDeviceID;
	deviceID = (unsigned short) (vendorDeviceID >> 16);
	IOLog("%s: vendorID=%04x deviceID=%04x\n", [self name], vendorID,
		deviceID);

	/* go through "Auto Detect IDs" and make sure we are okay */
	configTable = [[self deviceDescription] configTable];
	sprintf(idString, "%08lx", vendorDeviceID);
	if (strstr([configTable valueForStringKey:"Auto Detect IDs"], idString)
		== NULL)
	{
		IOLog("%s: VenderDeviceID %08lx not found in instance table.\n",
			[self name], vendorDeviceID);
		return UnknownAdapter;
	} else {
		/* add more card types here if there are PCI cards other than 1280P
		 * actually, if there are more than one PCI cards, we should determine
		 * which PCI card here */
		adapterType = QVision1280P;
	}

	/* need to do set framebuffer address for PCI */
	[self getPCIConfigSpace:&configSpace];
	physicalAddress = configSpace.BaseAddress[0];
	physicalAddress &= 0xfffffff0;	/* mask out lower 4 bits */

	if (physicalAddress) {
		IOLog_dbg(("%s: try to set physical address to 0x%08x\n",
			[self name], physicalAddress));
		/* PCI does report where the frame buffer address is */
		oldRange = [deviceDescription memoryRangeList];
		numRanges = [deviceDescription numMemoryRanges];
		if (numRanges==3) {
			int	ret;
			int	i;

			/* replace the address */
			for (i=0; i<numRanges; i++) {
				newRange[i] = oldRange[i];
			}
			newRange[0].start = physicalAddress;
			ret = [deviceDescription setMemoryRangeList:newRange num:3];
			if (ret) {
				/* can't set to new memory range */
				IOLog("%s: Can't set memory range, using default.\n",
				[self name]);
				for (i=0; i<numRanges; i++) {
					newRange[i] = oldRange[i];
				}
				physicalAddress = newRange[0].start;
				ret = [deviceDescription setMemoryRangeList:newRange
					num:3];
				if (ret) {
					/* can't set to old range-->major problem! */
					IOLog("%s: Can't set to default range either!\n",
						[self name]);
					return UnknownAdapter;
				}
			}
		} else {
			IOLog("%s: Incorrect number of address ranges: %d.\n",
				[self name], numRanges);
			return UnknownAdapter;
		}
	} else {
		IOLog_dbg(("%s: PCI doesn't tell us the physical address.\n",
			[self name]));
		physicalAddress = [deviceDescription memoryRangeList] -> start;
		configSpace.BaseAddress[0] = physicalAddress;
		[self setPCIConfigSpace:&configSpace];
	}
	return adapterType;
}


/* helper method to -determineEISACardType */
- (QVAdapterType)adapterTypeFromEISAID:(unsigned int)cardID
{
	QVAdapterType 	adapterType;

	adapterType = UnknownAdapter;
	IOLog_dbg(("%s: adapterTypeFromEISAID cardID=0x%08x\n", [self name],
		cardID));
	switch (cardID) {
		case QVISION_EISA_ID:
			adapterType = QVisionAdapter;
			break;
		case ORION_EISA_ID:
			adapterType = OrionAdapter;
			break;
		case ORION12_EISA_ID:
			adapterType = Orion12Adapter;
			break;
		case QVISION_ISA_ID:
		case ORION_ISA_ID:
		case ORION12_ISA_ID:
			IOLog("%s: Sorry, ISA cards are not supported (id=0x%08x).\n",
				[self name], cardID);
			break;
		default:
			/* We found some other EISA card.  Just ignore it. */
			break;
	}
	return adapterType;
}

/* helper method to -determineEISACardType */
- (QVAdapterType)autoScanEISAForCardType
{
	int				slot;
	QVAdapterType 	adapterType;
	unsigned int	cardID;

	IOLog_dbg(("%s: doing auto-scan on EISA bus.\n", [self name]));
		
	adapterType = UnknownAdapter;
	for (slot=1; slot<16; slot++) {
		if ([self getEISAId:&cardID forSlot:slot]) {
			adapterType = [self adapterTypeFromEISAID:cardID];
		}
		if (adapterType != UnknownAdapter) {
			IOLog_dbg(("%s: found card in slot %d.\n", [self name], slot));
			return adapterType;
		}
	}
	return UnknownAdapter;
}

/* can't use atoi() nor sscanf() */
- (int) getFirstNumber:(char *)s
{
	char	*cptr;
	int		n;
	
	cptr = s;
	n = -1;
	while(*cptr && ((*cptr<'0') || (*cptr>'9'))) cptr++;
	while(*cptr && ((*cptr>='0') && (*cptr<='9'))) {
		if (n==-1) n = 0;
		n = n*10 + (*cptr - '0');
		cptr++;
	}
	return n;
}

/* TODO: clean up error handling, i.e. return something meaningful rather
 * than returning [super free]; */
- (QVAdapterType) determineEISACardType
{
	QVAdapterType 	adapterType;
	int				mySlot;
	id				deviceDescription;
	const char		*slotValue;
	IOConfigTable	*configTable;
	unsigned int	cardID;
	
	adapterType = UnknownAdapter;
	if (![self isEISAPresent]) {
		IOLog ("%s: Not an EISA system.\n", [self name]);
		return UnknownAdapter;
	}
	deviceDescription = [self deviceDescription]; 
	configTable = [[self deviceDescription] configTable];

	/* see what slot we're supposed be in */
	slotValue = [configTable valueForStringKey:"Location"];
	if (strstr(slotValue, "Slot")) {
		mySlot = [self getFirstNumber:(char *)slotValue];
		IOLog_dbg(("%s: we should be in slot %d\n", [self name], mySlot));
	} else {
		/* instance table doesn't tell us what slot we're in */
		return [self autoScanEISAForCardType];
	}
	
	/* TODO: need to check for auto detect id's */
	if (mySlot > 0) {
		if ([self getEISAId:&cardID forSlot:mySlot]) {
			adapterType = [self adapterTypeFromEISAID:cardID];
		} else {
			/* can't find card in the specified slot, do auto-scan */
			adapterType = [self autoScanEISAForCardType];
		}
	} else {
		/* slot not specified, do auto-scan */
		adapterType = [self autoScanEISAForCardType];
	}
	return adapterType;
}

- (void)reportConfiguration
{
	const char *adapterString, *dacString;

	switch (adapter) {
		case QVisionAdapter: adapterString = "QVision"; break;
		case OrionAdapter: adapterString = "Orion"; break;
		case Orion12Adapter: adapterString = "Orion12"; break;
		case QVision1280P: adapterString = "QVision1280P"; break;
		default: adapterString = "unknown"; break;
	}

	switch (dac) {
		case Bt484: dacString = "Brooktree 484"; break;
		case Bt485: dacString = "Brooktree 485"; break;
		case Bt485A: dacString = "Brooktree 485A"; break;
		case ATT20C505: dacString = "AT&T 20C505"; break;
		default: dacString = "unknown"; break;
	}

	IOLog("%s: %s adapter; %s DAC.\n", [self name], adapterString, dacString);
}

- determineConfiguration
{
	adapter = UnknownAdapter;

	[self determineConfigBusType];
	[self determineDACType];
	switch(busType) {
		case BusISAorVL:
			adapter = [self determineVLCardType];
			break;
		case BusPCI:
			adapter = [self determinePCICardType];
			break;
		case BusEISA:
			adapter = [self determineEISACardType];
			break;
	}
	[self reportConfiguration];
	if (adapter==UnknownAdapter || dac==UnknownDAC) return nil;
	return self;
}

- selectMode
{
	int k, mode;
	const QVisionMode *qvMode;
	BOOL validModes[QVisionModeTableCount];

	for (k = 0; k < QVisionModeTableCount; k++) {
		qvMode = QVisionModeTable[k].parameters;
		validModes[k] = (qvMode->adapter <= adapter);
	}

	mode = [self selectMode:QVisionModeTable count:QVisionModeTableCount
	valid:validModes];

	if (mode < 0) {
		IOLog("%s: Sorry, cannot use requested display mode.\n", [self name]);
		switch (adapter) {
			case Orion12Adapter:
				mode = DEFAULT_ORION12_MODE;
				break;
			case OrionAdapter:
				mode = DEFAULT_ORION_MODE;
				break;
			case QVision1280P:
				mode = DEFAULT_1280P_MODE;
				break;
			case QVisionAdapter:
			default:
				mode = DEFAULT_QVISION_MODE;
				break;
		}
	}
	*[self displayInfo] = QVisionModeTable[mode];
	return self;
}

- initializeMode
{
	unsigned int i;
	const QVisionMode *mode;
	const IODisplayInfo *displayInfo;

	displayInfo = [self displayInfo];
	mode = displayInfo->parameters;

	/* Turn off video while setting all of the registers. */
	inb(VGA_INPUT_STATUS_1);
	outb(VGA_ATTR_INDEX, 0x00);
	
	/* Set the sequencer registers. */
	for (i = 0; i < VGA_SEQ_COUNT; i++) {
	outb(VGA_SEQ_INDEX, i);
	outb(VGA_SEQ_DATA, mode->vgaData.seqx[i]);
	}
	outb(VGA_SEQ_INDEX, 0x00);
	outb(VGA_SEQ_DATA, 0x03);	/* Restart the sequencer. */
	
	/* Unlock extended graphics registers. */
	outw(VGA_GRFX_INDEX, 0x050f);

	/* Unlock more extended registers. */
	outb(VGA_GRFX_INDEX, 0x10);
	outb(VGA_GRFX_DATA, 0x08);

	/* Set Advanced VGA mode (set bit 0 of Ctrl Reg 0). */
	outb(VGA_GRFX_INDEX, 0x40);
	outb(VGA_GRFX_DATA, 0x01);
	
	/* Fix sequencer pixel mask for 8 bits. */
	outb(VGA_SEQ_INDEX, SEQ_PIXEL_WR_MSK);
	outb(VGA_SEQ_DATA, 0xff);
	
	outb(CTRL_REG_1, mode->ctrlReg1);
	if (mode->adapter >= OrionAdapter) {
	/* Set access level & enable high address map. */
	outb(QVGA_CTL_2, 0x14);
	/* Select 2 Meg mode. */
	outb(QVGA_CTL_3, 0x05);
	}
	
	/* Set miscellaneous output register. */
	outb(VGA_MISC_OUTPUT, mode->vgaData.miscOutput);
	
	[self programDAC];

	/* Load CRTC registers. */
	outb(VGA_CRTC_INDEX, 0x11);		/* Unlock CRTC regs 0-7. */
	outb(VGA_CRTC_DATA, 0x00);
	for (i = 0; i < VGA_CRTC_COUNT; i++) {
	outb(VGA_CRTC_INDEX, i);
	outb(VGA_CRTC_DATA, mode->vgaData.crtc[i]);
	}

	/* Load overflow registers. */
	outb(VGA_GRFX_INDEX, 0x42);
	outb(VGA_GRFX_DATA, mode->overflow1);
	outb(VGA_GRFX_INDEX, 0x51);
	outb(VGA_GRFX_DATA, mode->overflow2);
	
	/* Load attribute registers. */

	inb(VGA_INPUT_STATUS_1);	/* Reset latch. */
	for (i = 0; i < VGA_ATTR_COUNT; i++) {
	outb(VGA_ATTR_INDEX, i);
	outb(VGA_ATTR_DATA, mode->vgaData.attr[i]);
	}
	
	/* Load graphics registers. */
	for (i = 0; i < VGA_GRFX_COUNT; i++) {
	outb(VGA_GRFX_INDEX, i);
	outb(VGA_GRFX_DATA, mode->vgaData.grfx[i]);
	}
	
	[self setGammaTable];
	
	/* Re-enable video display. */
	inb(VGA_INPUT_STATUS_1);
	outb(VGA_ATTR_INDEX, 0x20);

	return self;
}

- enableLinearFrameBuffer
{
	const IODisplayInfo *displayInfo;
	unsigned char tmp;
	
	/* Override the high address map disable, thus allowing access to
	 * the high address map of the current board, even when the board
	 * is disabled. */

	outb(VGA_GRFX_INDEX, HI_ADDR_MAP+1);
	tmp = inb(VGA_GRFX_DATA);
	outb(VGA_GRFX_DATA, tmp | 0x80);

	/* Map VRAM.  Tell the adapter where to decode the framebuffer. */

	/* Set low 8 bits */
	outb(VGA_GRFX_INDEX, HI_ADDR_MAP);
	outb(VGA_GRFX_DATA, (videoRamAddress >> 20) & 0xFF);

	/* Set upper 4 bits */
	outb(VGA_GRFX_INDEX, HI_ADDR_MAP + 1);
	outb(VGA_GRFX_DATA, (videoRamAddress >> 28) & 0x0F);

	/* Leave them with a nice clear screen. */

	displayInfo = [self displayInfo];
	memset(displayInfo->frameBuffer, 0, 
	   displayInfo->rowBytes * displayInfo->height);

	return self;
}

- resetVGA
{
	const IODisplayInfo *displayInfo;
	const QVisionMode *mode;

	displayInfo = [self displayInfo];
	mode = displayInfo->parameters;

	/* Clear the QVision extended mode bit. This is bit 0 of CTRL_REG_1. */

	outb(CTRL_REG_1, inb(CTRL_REG_1) & 0xFE);

	if (mode != 0 && mode->adapter >= OrionAdapter) {
	/* Select 1 meg mode. */
	outb(QVGA_CTL_3, 0x00);
	/* Reset access level & disable high address map. */
	outb(QVGA_CTL_2, 0x00);
	}
	
	/* Clear the extended 256 color bit. This is bit 0 of 3CF.40. */
	outb(VGA_GRFX_INDEX, 0x40);
	outb(VGA_GRFX_DATA, (inb(VGA_GRFX_DATA) & 0xFE));
	
	/* Clear the page registers - 3CF.45 and 3CF.46. */
	outb(VGA_GRFX_INDEX, PAGE_REG_0);
	outb(VGA_GRFX_DATA, 0x00);
	outb(VGA_GRFX_INDEX, PAGE_REG_1);
	outb(VGA_GRFX_DATA, 0x00);
	
	[self resetDAC];

	/* Clear the overflow registers. */
	outb(VGA_GRFX_INDEX, 0x42);
	outb(VGA_GRFX_DATA, 0x00);
	outb(VGA_GRFX_INDEX, 0x51);
	outb(VGA_GRFX_DATA, 0x00);

	VGASetMode(0x03);

	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.