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

/* 
 * This file replaces tv_i2c.c with two purposes: a) track I2C access;
 * and b) emulate it in a test environment.
 *
 */

#include "local.h" /* before everything else */

#include "xf86i2c.h"

#include "tester.h"
#include "test_record.h"

/* ======================================== */

RecordDevicePtr TestFindDev (char *name, I2CSlaveAddr addr)
{
  RecordDevicePtr *r;

  for (r = config->devices; *r; r++) {
    if (strcmp ((*r)->bus, name) == 0 && (*r)->dev == addr) return (*r);
  }
  return NULL;
}

int TestAccessCH1 (RecordDevice *this, int subaddr)
{
  int result;

  if (subaddr != -1) this->current = subaddr;
  if (this->current == -1) return -1;
  result = this->current & 0x3f;
  if (this->current & 0x40) {
    this->current = (this->current & 0xc0) | ((this->current + 1) & 0x3f);
  }
  return result;
}

int TestAccessCH2 (RecordDevice *this, int subaddr)
{
  if (subaddr != -1) this->current = subaddr;
  if (this->current == -1) return -1;
  return this->current & 0x7f;
}

int TestStatusCH (RecordDevice *this)
{
  return -1;
}

int TestAccessPH (RecordDevice *this, int subaddr)
{
  return subaddr; // FIXME
}

int TestStatusPH (RecordDevice *this)
{
  return -1; // FIXME DAC
}

int TestAccessCX1 (RecordDevice *this, int subaddr)
{
  int result;

  if (subaddr != -1) this->current = subaddr;
  if (this->current & 1) return -1;
  result = this->current;
  this->current = (this->current + 2) & 0xff;
  return result; 
}

int TestAccessCX2 (RecordDevice *this, int subaddr)
{
  int result;

  if (subaddr != -1) this->current = subaddr;
  result = this->current & ~1;
  this->current = (this->current + 2) & 0xff;
  return result; 
}

int TestStatusCX (RecordDevice *this)
{
  return (recordReadDirect (this->zone, 0xc4, BIT8) >> 5) & 0x6;
}

/* -------- -------- */

/* On TV0 for I810 ?? */					    
RecordDevice TestDeviceCH1 = {
  bus:"TV0", dev:0xea, zone: ZONE_CH1, current:0, 
  access:TestAccessCH1, status:TestStatusCH};

/* On TV1 for I830 ?? */					    
RecordDevice TestDeviceCH2 = {
  bus:"TV1", dev:0xea, zone: ZONE_CH2, current:0,
  access:TestAccessCH2, status:TestStatusCH};

/* Must be on TV0 for TDFX */
RecordDevice TestDeviceCX1 = {
  bus:"TV0", dev:0x8a, zone: ZONE_CX1, current:0,
  access:TestAccessCX1, status:TestStatusCX};

RecordDevice TestDeviceCX2 = {
  bus:"TV1", dev:0x8a, zone: ZONE_CX2, current:0,
  access:TestAccessCX2, status:TestStatusCX};

RecordDevice TestDevicePH1 = {
  bus:"TV0", dev:0x88, zone: ZONE_PH1, current:0,
  access:TestAccessPH, status:TestStatusPH};
					    
RecordDevice TestDevicePH2 = {
  bus:"TV1", dev:0x88, zone: ZONE_PH2, current:0,
  access:TestAccessPH, status:TestStatusPH};
					    
/* -------- -------- */

Bool tvBusOk = TRUE;

/* -------- I2C bus access -------- */

Bool TVProbeBus (I2CBusPtr bus, I2CSlaveAddr addr)
{
  Bool result;

  if (testopt_snoop) {
    result = xf86I2CProbeAddress (bus, addr);
  } else {
    result = (TestFindDev (bus->BusName, addr) != NULL);
  }
  return result;
}

void TVWriteBus (I2CDevPtr d, I2CByte subaddr, I2CByte data)
{
  RecordDevicePtr r = TestFindDev (d->pI2CBus->BusName, d->SlaveAddr);

  if (testopt_snoop) {
    if (!xf86I2CWriteByte (d, subaddr, data)) tvBusOk = FALSE;
  } else {
    if (!r) tvBusOk = FALSE; 
    else if (r->access (r, subaddr) == -1) {
      tvBusOk = FALSE; 
      return;
    }
  }
  if (!r) return;
  recordWrite (r->zone, r->access (r, subaddr), data, BIT8, "out");
}

void TVWriteSeqBus (I2CDevPtr d, I2CByte subaddr, I2CByte *buf, int len)
{
  RecordDevicePtr r = TestFindDev (d->pI2CBus->BusName, d->SlaveAddr);

  if (testopt_snoop) {
    if (!xf86I2CWriteBytes (d, subaddr, buf, len)) tvBusOk = FALSE;
  } else {
    if (!r) tvBusOk = FALSE; 
    else if (r->access (r, subaddr) == -1) {
      tvBusOk = FALSE; 
      return;
    }
  }
  if (!r) return;
  recordWrite (r->zone, r->access (r, subaddr), *buf++, BIT8, "out");
  for (len--; len > 0; len--)
    recordWrite (r->zone, r->access (r, -1), *buf++, BIT8, "out");
}

void TVReadBus (I2CDevPtr d, I2CByte subaddr, I2CByte *data)
{
  RecordDevicePtr r = TestFindDev (d->pI2CBus->BusName, d->SlaveAddr);

  if (testopt_snoop) {
    if (!xf86I2CReadByte (d, subaddr, data)) tvBusOk = FALSE;
    if (!r || !tvBusOk) return;
    recordWrite (r->zone, r->access (r, subaddr), *data, BIT8, "in ");
  } else {
    if (!r) { tvBusOk = FALSE; return; }
    if (r->access (r, subaddr) == -1) { tvBusOk = FALSE; return; }
    *data = recordRead (r->zone, r->access (r, subaddr), BIT8, "in ");
  }
}

void TVReadSeqBus (I2CDevPtr d, I2CByte subaddr, I2CByte *buf, int len)
{
  RecordDevicePtr r = TestFindDev (d->pI2CBus->BusName, d->SlaveAddr);

  if (testopt_snoop) {
    if (!xf86I2CWriteRead (d, &subaddr, 1, buf, len)) tvBusOk = FALSE;
    if (!r || !tvBusOk) return;
    recordWrite (r->zone, r->access (r, subaddr), *buf++, BIT8, "in ");
    for (len--; len > 0; len--)
      recordWrite (r->zone, r->access (r, -1), *buf++, BIT8, "in ");
  } else {
    if (!r) { tvBusOk = FALSE; return; }
    if (r->access (r, subaddr) == -1) { tvBusOk = FALSE; return; }
    *buf++ = recordRead (r->zone, r->access (r, subaddr), BIT8, "in ");
    for (len--; len > 0; len--)
      *buf++ = recordRead (r->zone, r->access (r, -1), BIT8, "in ");
  }
}

void TVStatusBus (I2CDevPtr d, I2CByte *data)
{
  RecordDevicePtr r = TestFindDev (d->pI2CBus->BusName, d->SlaveAddr);

  if (testopt_snoop) {
    if (!xf86I2CReadStatus(d, data)) tvBusOk = FALSE;
    if (!r || !tvBusOk) return;
    recordWrite (r->zone, r->status (r), *data, BIT8, "st ");
  } else {
    if (!r) tvBusOk = FALSE; 
    *data = recordRead (r->zone, r->status (r), BIT8, "st ");
  }
}

void TVStatusSeqBus (I2CDevPtr d, I2CByte *buf, int len)
{
  RecordDevicePtr r = TestFindDev (d->pI2CBus->BusName, d->SlaveAddr);

  if (testopt_snoop) {
    if (!xf86I2CWriteRead (d, NULL, 0, buf, len)) tvBusOk = FALSE;
    if (!r || !tvBusOk) return;
    recordWrite (r->zone, r->status (r), *buf++, BIT8, "st ");
    for (len--; len > 0; len--)
      recordWrite (r->zone, r->status (r), *buf++, BIT8, "st ");
  } else {
    if (!r) { tvBusOk = FALSE; return; }
    *buf++ = recordRead (r->zone, r->status (r), BIT8, "st ");
    for (len--; len > 0; len--)
      *buf++ = recordRead (r->zone, r->status (r), BIT8, "st ");
  }
}

/* -------- -------- */

I2CBusPtr TestHookBus (I2CBusPtr I2CPtr)
{
  return I2CPtr;
}



syntax highlighted by Code2HTML, v. 0.9.1