#ifdef __PUREC__
   #include <tos.h>
#else
   #include <osbind.h>
   #ifdef __LATTICE__
      #include <dos.h>
   #endif
#endif

#include <stdio.h>


#define SCRATCH_REG0            0x0080  /* Dword offset 20 */

#define reg_w(register_base,offset,value) \
		*((volatile unsigned long *)(register_base + offset)) = value, 0
#define reg_w_b(register_base,offset,value) \
		*((volatile char *)(register_base + offset)) = value, 0
#define reg_r(register_base,offset) \
		*(volatile unsigned long *)(register_base + offset)

#define Reg_w(a,v) reg_w(reg_base,a,v)
#define xReg_w(a,v) reg_w(wreg_base,a,v)
#define Reg_w_b(a,v) reg_w_b(wreg_base,a,v)
#define Reg_r(a) reg_r(reg_base,a)


extern long pci_bios_call(long pci_bios_struct, long offset, long d0, long d1, void *a1, long super);


static long
tests[] = {9, 0x00000000L, 0xffffffffL, 0x55555555L,
              0xaaaaaaaaL, 0x55550000L, 0x00005555L,
              0x55005500L, 0x00555500L, 0x00550055L,
           1, 0x55000000L,
           0,
           1, 0xaa000000L};


/*
 * Returns the value of a cookie, or -1
 */
long get_cookie(const unsigned char *cname, long super)
{
   long oldstack, *ptr, value, name;

   name = 0;
   while(*cname)
      name = (name << 8) | (long)*cname++;

   if (!super)
      oldstack = (long)Super(0L);
   ptr = (long *)*(long *)0x5a0;

   value = -1;
   if (ptr) {
      while ((*ptr != 0) && (*ptr != name))
         ptr += 2;
      if (*ptr == name)
         value = ptr[1];
   }

   if (!super)
      Super((void *)oldstack);
   return value;
}


int scratch(unsigned long reg_base, int eclipse)
{
	unsigned long wreg_base;
	long *scratches;
	int i, j, n;
	long v, r;
	int error;

	wreg_base = reg_base;
	if (eclipse)
		wreg_base = reg_base - 0x10000000L;

	error = 0;

	scratches = tests;
	n = *scratches++;
	for(i = 0; i <= 4; i += 4) {
		printf("Testing scratch register %d\n", i / 4);
		for(j = 0; j < n; j++) {
			v = *scratches++;
			printf("Writing %08x     ", v);
			Reg_w(SCRATCH_REG0 + i, v);
			r = Reg_r(SCRATCH_REG0 + i);
			printf("Read back %08x\n", r);
			if (r != v) {
				error = 1;
			}
		}
		n = *scratches++;
		if (n) {
			v = *scratches++;
			for(j = 0; j < 4; j++) {
				printf("Writing %08x     ", v);
				Reg_w(SCRATCH_REG0 + i, v);
				r = Reg_r(SCRATCH_REG0 + i);
				printf("Read back %08x\n", r);
				if (r != v) {
					error = 1;
				}
				v = (v >> 8) & 0x00ffffffL;
			}
		}
		Reg_w(SCRATCH_REG0 + i, 0);
	}

	if (error) {
		printf("Scratch register test failed!\n");
	} else {
		printf("Scratch register test successful!\n");
	}

	return !error;
}


int main(int argc, char **argv)
{
	int card, pci_bios_struct, reg_base, fb_base, tmp, hostid, id;
	int super;
	int error;
	struct {
		int cpu_addr;
		int size;
	} map;
	int eclipse;

	super = argc < 2;

	printf("\nPCI BIOS ATI card check");
	if (super)
		printf(" (Calling in supervisor mode)");
	printf("\n\n");

	if ((pci_bios_struct = get_cookie("_PCI", 0)) != -1) {
		hostid = pci_bios_call(pci_bios_struct, 0x9c, 0, 0, 0, super);
		eclipse = 0;
		switch ((hostid >> 24) & 0xff) {
		case 0:
			printf("Medusa/Hades: $%06x\n", hostid & 0xffffff);
			break;
		case 1:
			printf("Milan: $%06x\n", hostid & 0xffffff);
			break;
		case 2:
			printf("PAK/Panther2: $%06x\n", hostid & 0xffffff);
			break;
		default:
			printf("Unknown computer, probably a Falcon030/Eclipse ($%06x)\n", hostid & 0xffffff);
			eclipse = 1;
			break;
		}

#if 0
		card = pci_bios_call(pci_bios_struct, 0x08, 0x19690311L, 0, 0, super);
		if (card <= 0)
			printf("Attempt to find non-existing card yielded an error return of $%08x\n", ati_card);
		else
			printf("Attempt to find non-existing card did not report an error ($%08x)!\n", ati_card);
		printf("\n");
#endif

		card = pci_bios_call(pci_bios_struct, 0x08, 0x47561002L, 0, 0, super);
		if (card < 0) {
			card = pci_bios_call(pci_bios_struct, 0x08, 0x47551002L, 0, 0, super);
		}
		if (card < 0)
			printf("No recognized ATI card was found\n");
		else {
			int ati_card = card;
			printf("One of the two recognized ATI cards was found ($%x)\n", ati_card);

			error = pci_bios_call(pci_bios_struct, 0x18, ati_card, 0x18, &reg_base, super);
			if (error < 0)
				printf("An error ($%08x) was reported when trying to read configuration space\n", error);
			reg_base &= 0xfffffff0L;
			error = pci_bios_call(pci_bios_struct, 0x18, ati_card, 0x10, &fb_base, super);
			fb_base &= 0xfffffff0L;
			printf("PCI addresses:   Registers at $%x   Frame buffer at $%x\n", reg_base, fb_base);

#if 0
			tmp = pci_bios_call(pci_bios_struct, 168, ati_card, reg_base, 0, super);
			if (tmp != -2) {
				reg_base = tmp;
				fb_base = pci_bios_call(pci_bios_struct, 168, ati_card, fb_base, 0, super);
				printf("Mapped addresses:   Registers at $%x   Frame buffer at $%x\n", reg_base, fb_base);
			} else {
				printf("Mapping not possible with this PCI BIOS\n");
			}
#else
			error = pci_bios_call(pci_bios_struct, 0xa8, ati_card, reg_base, &map, super);
			if ((error & 0xfffffff0) != 0xfffffff0) {
				reg_base = map.cpu_addr;
				error = pci_bios_call(pci_bios_struct, 0xa8, ati_card, fb_base, &map, super);
				fb_base = map.cpu_addr;
				printf("Mapped addresses:   Registers at $%x   Frame buffer at $%x\n", reg_base, fb_base);
				reg_base += 1024;	/* Actual registers */
			} else {
				printf("Mapping not possible with this PCI BIOS\n");
				if (eclipse) {
					reg_base += 0xf0000000L + 1024;	/* Long word (Was PCIMACH64) */
					fb_base  += 0xe0000000L;		/* Word (Was PCISCREEN) */
				} else if (((hostid >> 24) & 0xff) == 1) {			/* Milan? */
					reg_base += 0x40000000L + 1024;
					fb_base  += 0x40000000L;
				} else {
					reg_base += 1024;				/* Assume the rest correct for Hades etc */
				}
			}
#endif
		}

#if 1
		card = 0;
		for(id = 0; id < 256; id++) {
			int i, value;
			card = pci_bios_call(pci_bios_struct, 0x08, 0x0000ffffL, id, 0, super);
			if (card == 0xfffffffc)
				break;
			printf("Card found: $%x\n", card);
			for(i = 0; i < 0x40; i += 4) {
				error = pci_bios_call(pci_bios_struct, 0x18, card, i, &value, super);
				if (error >= 0)
					printf("$%08x  ", value);
				else
					printf(".........  ");
				if ((i + 4) % 16 == 0)
					printf("\n");
			}
			scratch(reg_base, eclipse);
		}
#endif

	} else {
		printf("PCI BIOS not found!\n");
	}

	printf("\nPress enter to exit\n");
	getchar();

	return 0;
}

