#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <math.h>
#include <sys/time.h>
#include <sys/utsname.h>
#include <sys/vfs.h>
#include <asm/io.h>

#define BASEADDR 0x300

/* Bit 0 = Data out (read from EEPROM)
   Bit 1 = Data in  (write to EEPROM)
   Bit 2 = Clock
   Bit 3 = Chip Select
   Bit 7 = ~50 kHz clock for defined delays */


void dlink_put_eeprom(unsigned char value, unsigned int addr)
{
	int z;
	unsigned char v1, v2;

	/* write the value to the NIC EEPROM register */

	outb(value, addr + 0x1e);

	/* now wait the clock line to toggle twice.  Effectively, we are
	   waiting (at least) for one clock cycle */

	for (z = 0; z < 2; z++) {
		do {
			v1 = inb(addr + 0x1e);
			v2 = inb(addr + 0x1e);
		}
		while (!((v1 ^ v2) & 0x80));
	}
}

void dlink_send_eeprom_bit(unsigned int bit, unsigned int addr)
{
	/* shift data bit into correct position */

	bit = bit << 1;

	/* write value, keep clock line high for two cycles */

	dlink_put_eeprom(0x09 | bit, addr);
	dlink_put_eeprom(0x0d | bit, addr);
	dlink_put_eeprom(0x0d | bit, addr);
	dlink_put_eeprom(0x09 | bit, addr);
}

void dlink_send_eeprom_word(unsigned int value, unsigned int len, unsigned int addr)
{
	int z;

	/* adjust bits so that they are left-aligned in a 16-bit-word */

	value = value << (16 - len);

	/* shift bits out to the EEPROM */

	for (z = 0; z < len; z++) {
		dlink_send_eeprom_bit((value & 0x8000) >> 15, addr);
		value = value << 1;
	}
}

unsigned int dlink_get_eeprom(unsigned int eeaddr, unsigned int addr)
{
	int z;
	unsigned int value = 0;
 
	/* pull the CS line low for a moment.  This resets the EEPROM-
	   internal logic, and makes it ready for a new command. */

	dlink_put_eeprom(0x01, addr);
	dlink_put_eeprom(0x09, addr);

	/* send one start bit, read command (1 - 0), plus the address to
           the EEPROM */

	dlink_send_eeprom_word(0x0180 | (eeaddr & 0x3f), 9, addr);

	/* get the data word.  We clock by sending 0s to the EEPROM, which
	   get ignored during the read process */

	for (z = 0; z < 16; z++) {
		dlink_send_eeprom_bit(0, addr);
		value = (value << 1) | (inb(addr + 0x1e) & 0x01);
	}

	return value;
}

int main(int argc, char **argv)
{
  int z;
  
  if (ioperm(BASEADDR, 0x20, 1) == -1) 
  { 
    fprintf(stderr, "couldn't get access rights for I/O");
    return 2;
  }

  for (z = 0; z < 64; z++)
  {
    if ((z & 7) == 0)
      printf("%02x:", z);
    printf(" %04x", dlink_get_eeprom(z, BASEADDR));
    if ((z & 7) == 7)
      printf("\n");
  }

  return 0;
}
