/*
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

/*
 * Mac specific includes
 */
#include <NameRegistry.h>
#include <Pci.h>
#include <Gestalt.h>
#include <Timer.h>
#include <DriverServices.h>

/*
 * macraigor systems PCI card registers
 */
typedef struct pciRegs {
	unsigned char  cmdStat;			/* Command / Status Register */
	unsigned char  ___0;
	unsigned char  gpOut;			/* GP Output Register */
	unsigned char  ___1;
	unsigned char  IOLow;			/* Holding Register 0-7, input shift register */
	unsigned short TMSReg;			/* TMS Register */
	unsigned short ___2;
	unsigned short ___3;
	unsigned short ___4;
	unsigned char  IOHi;			/* Holding Register 8-15 */
} pciRegs;

void findPCICard(char *name);
void Jtag_OSDelay(int waitTime);	/* miliseconds */
void usDelay(int waitTime);
unsigned long swapEndian(unsigned long val);
void readConfigEE(unsigned long adr);

volatile pciRegs *regPtr = 0;
int jtagError = 0;
char *failedRoutineName;

unsigned long		aaplAdrs[8];
RegPropertyValueSize	adrSize = sizeof(aaplAdrs);
char					slotName[32];
RegPropertyValueSize	nameSize = sizeof(slotName);
unsigned long		assignedAdrs[8][5];
RegPropertyValueSize	assignedAdrsSize = sizeof(assignedAdrs);
unsigned long		regAdrs[8][5];
RegPropertyValueSize	regAdrsSize = sizeof(regAdrs);

char	*CardNames[]  = {   "pci1c1c,1",		/* winbond (really broken IDE)*/
							"pci907f,2015", 	/* ATronics 2015 (sort of broken IDE)*/
							"pci10ad,105",		/* Cujo (bus master IDE) */
							"pci10b5,9050",		/* PLX Eval board */
							"pci131f,1034",		/* SIIG 2S 1P */
							"pci121f,1020",		/* SIIG 1P (plx9052) */
							"pcid84d,6811",		/* Dolphin 1P */
							"pcifde5,7", 		/* Frontier Designs (PLX9050if) */
							"pci152c,1",		/* Macgraigor PCI JTAG card */
							"pci10b5,1",		/* MCT-P1P-E */
							""
						};

unsigned char stateChg[12] = {	0b0000, 0b1000, 0b0000, 0b0100, 0b0000, 0b0000,
								0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b1000 };


volatile unsigned char * LPT0Adr;

#define LPD	LPT0Adr
#define LPS LPT0Adr+1
#define LPC LPT0Adr+2

/* LPS */
#define ASYN	0x08

/* LPC */
#define PSYN	0x01


#define NBLOCK (1+2+8+256)
short block[NBLOCK];

void outport(volatile unsigned char *adr, unsigned char data);
unsigned char inport(volatile unsigned char *adr);
void getblock();
void getinsync();
int getword();


void main(void)
{
	 int i;
	 int bno;
	

	 unsigned long configAdr;
	 
	 unsigned clkCnt = 0;
	 unsigned char clkShadow = 0;
	 FILE *fp;
	 
	for(i=0; CardNames[i][0] != '\0'; i++){
	 findPCICard(CardNames[i]);
	 if(!jtagError) goto foundOne;
	}
	printf("didn't find a known card\n");
	exit(1);
	
foundOne:
	 printf("%s = %s\n",slotName, CardNames[i]);
	 
	 printf("Slot %s, adrs %x %x %x %x %x %x\n", slotName, aaplAdrs[0], aaplAdrs[1], aaplAdrs[2], aaplAdrs[3], aaplAdrs[4], aaplAdrs[5]);
	for(i=0; i<8; i++)
		 printf("reg %d  %08x,%08x,%08x,%08x,%08x\n", i, regAdrs[i][0],regAdrs[i][1],regAdrs[i][2],regAdrs[i][3],regAdrs[i][4]);
	for(i=0; i<8; i++)
		 printf("assigned adrs %d %08x,%08x,%08x,%08x,%08x\n", i, assignedAdrs[i][0],assignedAdrs[i][1],assignedAdrs[i][2],assignedAdrs[i][3],assignedAdrs[i][4]);
/*
	for(j=0; j<8; j++){
		printf("Adr space %d: 0x%08x\n",j ,aaplAdrs[j]);
		for(i=0, p = (unsigned char *)aaplAdrs[0]; i<16; i++)
		 printf("%02x ", *p++);
		printf("\n");
	}
*/
	/*
	 * find memory mapped config space
	 */
	 configAdr  = 0;
	 for(i=0; i<8; i++){
	  if((assignedAdrs[i][0] & 0xff0000ff) == 0x82000010){
	   configAdr = aaplAdrs[i];
	   break;
	  }
	 }
	 printf("Config Adr = %08x\n", configAdr);
	 
	 if(configAdr){
		readConfigEE(configAdr);
	 }

	 LPT0Adr = 0;
	 for(i=0; i<8; i++){
	  if((assignedAdrs[i][0] & 0xff0000ff) == 0x81000020){	/* IO Mapped Parallel Port */
	   LPT0Adr = (volatile unsigned char *)aaplAdrs[i];
	   break;
	  }
	 }
	 printf("LPT0 Adr = %08x\n", LPT0Adr);
	 
	 if(!LPT0Adr) exit(1);

/*
 * force parallel port to input mode
 */
 	
 	outport(LPC, 0x20 | PSYN);

	fp = fopen("alto.dsk", "wb");
	if (fp == 0) { printf("Can't open alto.dsk\n"); exit(1); }
	printf("Calling getinsync()\n"); fflush(stdout);
	
	getinsync();
	for (bno = 0; bno < 4872; ++bno) {
		printf("Block %d ...\n", bno); fflush(stdout);
		getblock();
		if (block[0] != bno) {
			printf("Wrong block, gto %d\n", bno);
			exit(1);
		}
		if (fwrite((char *)block, sizeof(short), NBLOCK, fp) != NBLOCK) {
			printf("Write error\n");
			exit(1);
		}
	}
	fclose(fp);
	
}

void outport(volatile unsigned char *adr, unsigned char data)
{
	*adr = data;
}

unsigned char inport(volatile unsigned char *adr)
{
	return(*adr);
}


void getblock()
{
	int	s;
	int	d;
	int	i;

	d = getword();
	if (d != 20000) {
		printf("Bad seal, got %04x %d\n", d, d);
		exit(1);
	}
	s = d;
	for (i=0; i<NBLOCK; ++i) {
		d = getword();
		block[i] = d;
		s += d;
	}
	s &= 0xffff;
	
	d = getword();
	if (d != s) {
		printf("Bad checksum, %04x %04x\n", s, d);
		exit(1);
	}
}

void getinsync()
{
	outport(LPC, 0x20 | PSYN);
	while ((inport(LPS) & ASYN) == 0)		// wait for negation of -stb
		;
}

int getword()
{
	unsigned char d;
	unsigned char invalue;

// first byte
	while ((inport(LPS) & ASYN) != ASYN);	// wait for -stb
	invalue = inport(LPD);					// read data
	d = invalue;
	outport(LPC, PSYN | 0x20);						// assert -ack
	while ((inport(LPS) & ASYN) == ASYN);	// wait for negation of -stb
	outport(LPC,  0x20);				// negate -ack

// second byte
	while ((inport(LPS) & ASYN) != ASYN);
	invalue = inport(LPD);
	d |= invalue << 8;
	outport(LPC, PSYN | 0x20);						// assert -ack
	while ((inport(LPS) & ASYN) == ASYN);
	outport(LPC, 0x20);

	return (d);
}



unsigned short eeBuffer[256];

#define D0 0x4
#define CS 0x2
#define CK 0x1

unsigned char	readCmd[] = {

		CS, 		CS, 	D0|CS,
		D0|CS|CK,	D0|CS,	D0|CS, 
		CS|CK, 		CS,		CS,
		CS|CK, 		CS,		CS,
		CS|CK, 		CS,		CS,
		CS|CK, 		CS,		CS,
		CS|CK, 		CS,		CS,
		CS|CK, 		CS,		CS,
		CS|CK, 		CS,		CS,
		CS|CK, 		CS,		CS,
		CS|CK,		CS,		CS,
		CS|CK, 		CS,		CS
};


void readConfigEE(unsigned long adr)
{
	volatile char *p = (volatile char *)(adr + 0x53);			/* point to ee access reg */
	int i, j;
	unsigned short inp = 0;

	for(i=0; i<33; i++){
	 asm(eieio);
	 *p = readCmd[i];
	}
	 
	for(i=0; i<64; i++){
		for(j=0; j<16; j++){
			*p = CS;										/* lower ck */
			asm(eieio);
			inp = (inp << 1) | ((*p & 0x8) >> 3);			/* read a bit */
			asm(eieio);
			*p = CS|CK;										/* raise ck */
			asm(eieio);
			*p = CS|CK;										/* raise ck */
			asm(eieio);
			*p = CS;										/* lower ck */
			asm(eieio);
			*p = CS;										/* two ticks */
			asm(eieio);
		}
		printf("%04x ", inp);
		if(((i+1) % 16) == 0) printf("\n"); 
		eeBuffer[i] = inp;
	}
	*p = 0x20;												/* negate CS and clock */
}

unsigned long swapEndian(unsigned long val)
{
	return __lwbrx( &val, 0 );

}

/*
 * try to find the PCI JTAG card, and return the register base
 * adr
 */

void findPCICard(char *name)
{

	OSErr					err;
	long 					result;
	RegEntryID				entry;
	RegEntryIter			iter;
	Boolean 				done = false;
	RegEntryIterationOp		iterOp = kRegIterDescendants;
	int						i,j;
	unsigned long			val, sav;

	/*
	 * Check that this is a PCI Mac
	 */
	if(Gestalt( gestaltNameRegistryVersion, &result) != noErr) goto fail;

	RegistryEntryIDInit(&entry);
	if(RegistryEntryIterateCreate( &iter ) != noErr) goto fail;

	/*
	 * search the name registry for a PCI card with the correct vendor ID
	 */

	err = RegistryEntrySearch(&iter, iterOp, &entry, &done, "name", name, strlen(name)+1);
	
	if(err != noErr) goto fail;
	RegistryEntryIterateDispose(&iter);

	err = RegistryPropertyGet(&entry, "assigned-addresses", (void *)&assignedAdrs, &assignedAdrsSize);
	if(err != noErr) goto fail;
	err = RegistryPropertyGet(&entry, "reg", (void *)&regAdrs, &regAdrsSize);
	if(err != noErr) goto fail;
	err = RegistryPropertyGet(&entry, "AAPL,address", (void *)&aaplAdrs, &adrSize);
	if(err != noErr) goto fail;
	err = RegistryPropertyGet(&entry, "AAPL,slot-name", (void *)&slotName, &nameSize);
	if(err != noErr) goto fail;
	/*
	 * card was found, enable I/O and memory space access in PCI config reg at offset 4
	 */
	err = ExpMgrConfigReadLong(&entry, (LogicalAddress)4, &val);
	val |= 3;
	err = ExpMgrConfigWriteWord(&entry, (LogicalAddress)4, val);
	if(err != noErr) goto fail;

	printf("Config Space\n");
	for(j=0; j<128; j+=4){
	 		err = ExpMgrConfigReadLong(&entry, (void *)j, &val);
			if((j % 16) == 0) printf("\n");
	 		printf("%08x ", val); fflush(stdout);
	}
	printf("\n\n");

printf("--\n");
	 for(i=0; i<6; i++){
	  err = ExpMgrConfigReadLong(&entry, (void *)((i*4)+0x10), &sav);
	  err = ExpMgrConfigWriteLong(&entry, (void *)((i*4)+0x10), 0xffffffff);
	  err = ExpMgrConfigReadLong(&entry, (void *)((i*4)+0x10), &val);
	  err = ExpMgrConfigWriteLong(&entry, (void *)((i*4)+0x10), sav);
	  printf("%08x = %08x\n",((i*4)+0x10), val); fflush(stdout);
	 }


	  err = ExpMgrConfigReadLong(&entry, (void *)(0x30), &sav);
	  err = ExpMgrConfigWriteLong(&entry, (void *)(0x30), 0xffffffff);
	  err = ExpMgrConfigReadLong(&entry, (void *)(0x30), &val);
	  err = ExpMgrConfigWriteLong(&entry, (void *)(0x30), sav);
	  printf("%08x = %08x (config)\n",0x30, val);

printf("--\n");
	
	jtagError = 0;
	return;

fail:
	jtagError = 1;
	return;
}

static long long
primeTimeoutTime(int timeout)
{
	UnsignedWide currentTime;
	long long theTime;

	Microseconds(&currentTime);
	theTime = ((currentTime.hi  << 32) | currentTime.lo) + timeout;
	return theTime;
}

static long long
currentTime(void)
{
	UnsignedWide currentTime;
	Microseconds(&currentTime);
	return((currentTime.hi << 32) | currentTime.lo);
}

static void
csrTimeout(char *rtn)
{
	failedRoutineName = rtn;
	jtagError = 1;
}
/*
 * Macintosh specific delay() routine
 */
 
void Jtag_OSDelay( int waitTime ) {
	AbsoluteTime	startTime, currentDelta;
	Duration		delta;
	
	/* get the start time */
	startTime = UpTime();
	
	do {
		/* get the delta absolute time from the start time */
		currentDelta = SubAbsoluteFromAbsolute( UpTime(), startTime );
		
		/* convert the delta into micro/milli seconds */
		delta = AbsoluteToDuration( currentDelta );
		
		/* if we got microseconds, convert to milliseconds */
		if ( delta < 0 )
			delta /= -1000;
				
	} while( delta < waitTime );
}

void usDelay( int waitTime )
{
	AbsoluteTime	startTime, currentDelta;
	Duration		delta;
	
	/* get the start time */
	startTime = UpTime();
	
	do {
		/* get the delta absolute time from the start time */
		currentDelta = SubAbsoluteFromAbsolute( UpTime(), startTime );
		
		/* convert the delta into micro/milli seconds */
		delta = AbsoluteToDuration( currentDelta );
		
		/* at this rate we shouldnt get microseconds, but we'll check for them anyways */
		if ( delta > 0 )
			delta *= 1000;
		else
			delta = -delta;
				
	} while( delta < waitTime );
}
