Logo Search packages:      
Sourcecode: baycomepp version File versions

fpgatests.c

/*****************************************************************************/

/*
 *      fpgatests.c  -- HDLC packet radio modem for EPP using FPGA utility library.
 *
 *      Copyright (C) 1998  Thomas Sailer (sailer@ife.ee.ethz.ch)
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  Please note that the GPL allows you to use the driver, NOT the radio.
 *  In order to use the radio, you need a license from the communications
 *  authority of your country.
 *
 */

/*****************************************************************************/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <math.h>
#include <unistd.h>
#include <stdarg.h>

#include "parport.h"
#include "fpga.h"
#include "util.h"

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

/*
 *The doubly scrambled BERR tests 
 * (once in software, once in the modem)
 * exercise the data exchange between modem and PC
 */

/* note: this is the reverse direction */

#if 0
#define SCRAM_TAP1  0x00001  /* X^17 */
#define SCRAM_TAPN  0x21000  /* X^0+X^5 */

#define DESCRAM_TAPSH1  0
#define DESCRAM_TAPSH2  5
#define DESCRAM_TAPSH3  17
#endif

#define DESCRAM_TAPSH1  0
#define DESCRAM_TAPSH2  7
#define DESCRAM_TAPSH3  10

#define SCRAM_TAP1  1
#define SCRAM_TAPN  ((1<<DESCRAM_TAPSH3)|(1<<(DESCRAM_TAPSH3-DESCRAM_TAPSH2)))

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

#include "epp_fpga.h"

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

static unsigned readboundaryword(const unsigned char *b, const unsigned *x, unsigned num)
{
      unsigned mask = 1, ret = 0;

        for (; num > 0; num--, x++, mask <<= 1)
            if (readboundary(b, *x))
                  ret |= mask;
      return ret;
}

static void writeboundaryword(unsigned char *b, const unsigned *x, unsigned num, unsigned v)
{
      unsigned sh = 0;

        for (; num > 0; num--, x++, sh++)
            writeboundary(b, *x, (v >> sh) & 1);
}

/* ========= BOUNDARY SCAN ONLY TESTS =================================== */

/*
 * RAM-Test
 */

static const unsigned int ram_addr_o[15] = 
{
      FPGA_PIN_RAMA0_O,
      FPGA_PIN_RAMA1_O,
      FPGA_PIN_RAMA2_O,
      FPGA_PIN_RAMA3_O,
      FPGA_PIN_RAMA4_O,
      FPGA_PIN_RAMA5_O,
      FPGA_PIN_RAMA6_O,
      FPGA_PIN_RAMA7_O,
      FPGA_PIN_RAMA8_O,
      FPGA_PIN_RAMA9_O,
      FPGA_PIN_RAMA10_O,
      FPGA_PIN_RAMA11_O,
      FPGA_PIN_RAMA12_O,
      FPGA_PIN_RAMA13_O,
      FPGA_PIN_RAMA14_O
};

static const unsigned int ram_addr_t[15] = 
{
      FPGA_PIN_RAMA0_T,
      FPGA_PIN_RAMA1_T,
      FPGA_PIN_RAMA2_T,
      FPGA_PIN_RAMA3_T,
      FPGA_PIN_RAMA4_T,
      FPGA_PIN_RAMA5_T,
      FPGA_PIN_RAMA6_T,
      FPGA_PIN_RAMA7_T,
      FPGA_PIN_RAMA8_T,
      FPGA_PIN_RAMA9_T,
      FPGA_PIN_RAMA10_T,
      FPGA_PIN_RAMA11_T,
      FPGA_PIN_RAMA12_T,
      FPGA_PIN_RAMA13_T,
      FPGA_PIN_RAMA14_T
};

static const unsigned int ram_data_t[8] = 
{
      FPGA_PIN_RAMD0_T,
      FPGA_PIN_RAMD1_T,
      FPGA_PIN_RAMD2_T,
      FPGA_PIN_RAMD3_T,
      FPGA_PIN_RAMD4_T,
      FPGA_PIN_RAMD5_T,
      FPGA_PIN_RAMD6_T,
      FPGA_PIN_RAMD7_T
};

static const unsigned int ram_data_o[8] = 
{
      FPGA_PIN_RAMD0_O,
      FPGA_PIN_RAMD1_O,
      FPGA_PIN_RAMD2_O,
      FPGA_PIN_RAMD3_O,
      FPGA_PIN_RAMD4_O,
      FPGA_PIN_RAMD5_O,
      FPGA_PIN_RAMD6_O,
      FPGA_PIN_RAMD7_O
};

static const unsigned int ram_data_i[8] = 
{
      FPGA_PIN_RAMD0_I,
      FPGA_PIN_RAMD1_I,
      FPGA_PIN_RAMD2_I,
      FPGA_PIN_RAMD3_I,
      FPGA_PIN_RAMD4_I,
      FPGA_PIN_RAMD5_I,
      FPGA_PIN_RAMD6_I,
      FPGA_PIN_RAMD7_I
};

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

static unsigned int ramaccess(unsigned addr, unsigned data, unsigned write)
{
      unsigned char bd1[FPGA_BOUNDSIZE], bd2[FPGA_BOUNDSIZE];

      memcpy(bd1, fpga_safebound, FPGA_BOUNDSIZE);
      writeboundaryword(bd1, ram_addr_t, 15, 0);
      writeboundaryword(bd1, ram_addr_o, 15, addr);
      writeboundary(bd1, FPGA_PIN_RAMCE_T, 0);
      writeboundary(bd1, FPGA_PIN_RAMOE_T, 0);
      writeboundary(bd1, FPGA_PIN_RAMWR_T, 0);
      writeboundary(bd1, FPGA_PIN_RAMCE_O, 0);
      writeboundary(bd1, FPGA_PIN_RAMOE_O, (write) & 1);
      writeboundary(bd1, FPGA_PIN_RAMWR_O, (!write) & 1);
      if (write) {
            writeboundaryword(bd1, ram_data_t, 8, 0);
            writeboundaryword(bd1, ram_data_o, 8, data);
      }
      boundary(FPGA_BOUND, bd1, bd2, 0);
      writeboundary(bd1, FPGA_PIN_RAMCE_O, 1);
      writeboundary(bd1, FPGA_PIN_RAMOE_O, 1);
      writeboundary(bd1, FPGA_PIN_RAMWR_O, 1);  
      boundary(FPGA_BOUND, bd1, bd2, 0);
      if (write)
            return 0;
      return readboundaryword(bd2, ram_data_i, 8);
}

static unsigned char *to_bin(unsigned char *buf, unsigned val, unsigned num)
{
      unsigned int i;

      for (i = 0; i < num; i++, val <<= 1)
            buf[i] = ((val >> (num-1)) & 1) + '0';
      buf[num] = 0;
      return buf;
}

static unsigned ramtestdata(unsigned data)
{
      unsigned val;
      unsigned char s[10];

      ramaccess(0, data, 1);
      val = ramaccess(0, 0, 0);
      tprintf("Testing data pattern 0x%02x read 0x%02x  failure mask %8s\n",
             data, val, to_bin(s, val ^ data, 8));
      idle_callback(0);
      return val ^ data;
}

static unsigned ramtestaddr(void)
{
      unsigned char ramd[32768];
      unsigned int i, j, k, l, mask = 0;
      unsigned char s[16];

      for (i = 0; i < 32768; i++) {
            if (!(i & 0xff)) {
                  tprintf("Writing RAM address 0x%04x...\r", i);
                  if (idle_callback(0))
                        return mask;
            }
            ramd[i] = random();
            ramaccess(i, ramd[i], 1);
      }
      for (i = 0; i < 32768; i++) {
            if (!(i & 0xff)) {
                  tprintf("Reading RAM address 0x%04x...\r", i);
                  if (idle_callback(0))
                        return mask;
            }
            j = ramaccess(i, 0, 0);
            if (j == ramd[i])
                  continue;
            l = 0xffff;
            for (k = 0; k < 32768; k++) {
                  if (ramd[k] != j)
                        continue;
                  if (hweight32(l) > hweight32(k ^ i))
                        l = k ^ i;
            }
            mask |= k;
            tprintf("RAM address error at 0x%04x minimum error mask %15s\n", 
                   i, to_bin(s, k, 15));
            if (idle_callback(0))
                  return mask;
      }
      return mask;
}

static int ramtest(struct adapter_config *cfg)
{
      unsigned mask;
      unsigned char s[16];
      int i;

      if ((i = adapter_start_no_firmware()))
            return i;
      tprintf("Performing RAM test...\n");
      mask = ramtestdata(0xff);
      mask |= ramtestdata(0x00);
      mask |= ramtestdata(0x55);
      mask |= ramtestdata(0xaa);
      mask |= ramtestdata(0xcc);
      mask |= ramtestdata(0x33);
      if (mask) {
            tprintf("RAM data error mask %s\nRAM data test failed, exiting\n", 
                   to_bin(s, mask, 8));
            reset_modem();
            return -4;
      }
      if ((mask = ramtestaddr())) {
            tprintf("RAM address error mask %s\nRAM address test failed, exiting\n", 
                  to_bin(s, mask, 15));
            reset_modem();
            return -5;
      }
      if (!idle_callback(0))
            tprintf("\nRAM test passed\n");
      reset_modem();
      return 0;
}

/* ---------------------------------------------------------------------- */
/*
 * LED test
 */

static int ledtest(struct adapter_config *cfg)
{
      unsigned led = 0;
      unsigned char bd1[FPGA_BOUNDSIZE], bd2[FPGA_BOUNDSIZE];
      int i;

      if ((i = adapter_start_no_firmware()))
            return i;
      memcpy(bd1, fpga_safebound, FPGA_BOUNDSIZE);
      tprintf("LED test, DISCONNECT PTT!!\n");
      for (;;) {
            led = (++led) & 3;
            writeboundary(bd1, FPGA_PIN_LEDSTA_O, led != 0);
            writeboundary(bd1, FPGA_PIN_LEDCON_O, led != 1);
            writeboundary(bd1, FPGA_PIN_LEDDCD_O, led != 2);
            writeboundary(bd1, FPGA_PIN_LEDPTT_O, led == 3);
            writeboundary(bd1, FPGA_PIN_LEDCON_T, 0);
            writeboundary(bd1, FPGA_PIN_LEDSTA_T, 0);
            writeboundary(bd1, FPGA_PIN_LEDDCD_T, 0);
            writeboundary(bd1, FPGA_PIN_LEDPTT_T, 0);
            boundary(FPGA_BOUND, bd1, bd2, 0);
            tprintf("Lighting LED %s\r", ((const char *[4]){ "STA", "CON", "DCD", "PTT"})[led]);
            if (idle_callback(500000)) {
                  reset_modem();
                  return 0;
            }
      }
}

/* ---------------------------------------------------------------------- */
/*
 * DAC test
 */

static const unsigned int dac_t[7] = 
{
      FPGA_PIN_DAC0_T,
      FPGA_PIN_DAC1_T,
      FPGA_PIN_DAC2_T,
      FPGA_PIN_DAC3_T,
      FPGA_PIN_DAC4_T,
      FPGA_PIN_DAC5_T,
      FPGA_PIN_DAC6_T
};

static const unsigned int dac_o[7] = 
{
      FPGA_PIN_DAC0_O,
      FPGA_PIN_DAC1_O,
      FPGA_PIN_DAC2_O,
      FPGA_PIN_DAC3_O,
      FPGA_PIN_DAC4_O,
      FPGA_PIN_DAC5_O,
      FPGA_PIN_DAC6_O
};


static int dactest(struct adapter_config *cfg)
{
      unsigned phase = 0, data, rot = 0;
      unsigned char bd1[FPGA_BOUNDSIZE], bd2[FPGA_BOUNDSIZE];
      int i;

      if ((i = adapter_start_no_firmware()))
            return i;
      memcpy(bd1, fpga_safebound, FPGA_BOUNDSIZE);
      tprintf("DAC test\n");
      for (;;) {
            data = 64 + 63 * sin(M_PI / 128 * phase);
            writeboundaryword(bd1, dac_t, 7, 0);
            writeboundaryword(bd1, dac_o, 7, data);
            boundary(FPGA_BOUND, bd1, bd2, 0);
            phase = (phase + 1) & 0xff;
            if (phase)
                  continue;
            rot = (rot + 1) & 3;
            tprintf("%c\r", "|\\-/"[rot]);
            if (idle_callback(0)) {
                  reset_modem();
                  return 0;
            }
      }
}

/* ---------------------------------------------------------------------- */
/*
 * Parport Signal Tests
 */

static const unsigned int ppinsig[] = {
      FPGA_PIN_EPPNWRITE_I,    /* strobe */
      FPGA_PIN_EPPNDATASTB_I,  /* nAutoFD */
      FPGA_PIN_EPPNRESET_I,    /* nInit */
      FPGA_PIN_EPPNADDRSTB_I,  /* SlctIn */
      FPGA_PIN_EPPDATA3_I,
      FPGA_PIN_EPPDATA4_I,
      FPGA_PIN_EPPDATA5_I,
      FPGA_PIN_EPPDATA6_I,
      FPGA_PIN_EPPDATA7_I
};

static const unsigned int ppoutsig[] = {
      FPGA_PIN_EPPNERR_O,
      FPGA_PIN_SPPPE_O
};

static const unsigned int ppoutsigt[] = {
      FPGA_PIN_EPPNERR_T,
      FPGA_PIN_SPPPE_T
};

static const char *ppsigstr[] = {
      "nError (15)", "PE (12)", 
      "nWrite/Strobe (1)", "nDataStb/nAutoFD (14)", "nReset/nInit (16)", "nAddrStb/nSlctIn (17)", 
      "D3 (5)", "D4 (6)", "D5 (7)", "D6 (8)", "D7 (9)"
};

static unsigned ppsigcheckone(unsigned val)
{
      unsigned char bd1[FPGA_BOUNDSIZE], bd2[FPGA_BOUNDSIZE];
      unsigned v;

      memcpy(bd1, fpga_safebound, FPGA_BOUNDSIZE);
      writeboundaryword(bd1, ppoutsigt, 2, 0);
      writeboundaryword(bd1, ppoutsig, 2, val);
      parport_write_control(((val >> 2) & 0xf) ^ (LPTCTRL_WRITE|LPTCTRL_ADDRSTB|LPTCTRL_DATASTB));
      boundary(FPGA_BOUND, bd1, bd2, val >> 3);
      v = parport_read_status();
      v = ((v >> 3) & 1) | ((v >> 4) & 2);
      boundary(FPGA_BOUND, bd1, bd2, val >> 3);
        parport_write_control(LPTCTRL_PROGRAM);
      return v | ((readboundaryword(bd2, ppinsig, 9) << 2) & 0x7fc);
}

static int ppsigtest(struct adapter_config *cfg)
{
      unsigned val, v2, err[11];
      int i, ret = 0;

      if ((i = adapter_start_no_firmware()))
            return i;
      for (i = 0; i < 11; i++)
            err[i] = 0;
      tprintf("Checking parallel port signals...\n");
      for (val = 0; val < 0x800; val++) {
            /* make sure the FPGA is not reset */
            if (!(val & ((LPTCTRL_ADDRSTB|LPTCTRL_PROGRAM)<<2)))
                  continue;
            if (idle_callback(0)) {
                  reset_modem();
                  return 0;
            }
            v2 = ppsigcheckone(val);
#if 0
            tprintf("check: 0x%03x  ret: 0x%03x  diff: 0x%03x\n", val, v2, v2 ^ val);
#endif
            v2 ^= val;
            if (val & 0x400)
                  v2 &= 0x7fc;
            if (!v2)
                  continue;
            ret = -1;
            for (i = 0; i < 11; i++)
                  err[i] += ((v2 >> i) & 1);
      }
      tprintf("Parport Signal Errors:\n");
      for (i = 0; i < 11; i++)
            tprintf("%-22s  %5d\n", ppsigstr[i], err[i]);
      reset_modem();
      return ret;
}

/* ========= EPP CHECK FIRMWARE TESTS =================================== */

static int chkcountertest(struct adapter_config *cfg)
{
      struct timeval time1, time2;
      unsigned int cnt0 = 0, cnt1 = 0, cnt2 = 0, cnt3 = 0, 
            prevcnt0 = 0, prevcnt1 = 0, prevcnt2 = 0, prevcnt3 = 0,
            freq0 = 0, freq1 = 0, freq2 = 0, freq3 = 0, usec;
      int i;
      unsigned char eio[3];
      
      if ((i = adapter_start_eppchk()))
            return i;
      /* reset counters */
      eio[0] = 0;
      if (parport_epp_write_addr(eio, 1) != 1)
            goto errret;
      tprintf("Frequency counter\n"
             "Counter value                Frequency (Hz)\n"
             "fclk__ clk___ RxC___ TxC___  fclk____ clk_____ RxC_____ TxC_____\n");
      if (gettime(&time1)) {
            reset_modem();
            return -6;
      }
      for (;;) {
            /* read counters */
            eio[0] = 4;
            if (parport_epp_write_addr(eio, 1) != 1)
                  goto errret;
            if (parport_epp_read_data(eio, 3) != 3)
                  goto errret;
            cnt0 = eio[0] | (((unsigned int)eio[1]) << 8) | (((unsigned int)eio[2]) << 16);
            eio[0] = 5;
            if (parport_epp_write_addr(eio, 1) != 1)
                  goto errret;
            if (parport_epp_read_data(eio, 3) != 3)
                  goto errret;
            cnt1 = eio[0] | (((unsigned int)eio[1]) << 8) | (((unsigned int)eio[2]) << 16);
            eio[0] = 6;
            if (parport_epp_write_addr(eio, 1) != 1)
                  goto errret;
            if (parport_epp_read_data(eio, 3) != 3)
                  goto errret;
            cnt2 = eio[0] | (((unsigned int)eio[1]) << 8) | (((unsigned int)eio[2]) << 16);
            eio[0] = 7;
            if (parport_epp_write_addr(eio, 1) != 1)
                  goto errret;
            if (parport_epp_read_data(eio, 3) != 3)
                  goto errret;
            cnt3 = eio[0] | (((unsigned int)eio[1]) << 8) | (((unsigned int)eio[2]) << 16);
            if (gettime(&time2)) {
                  reset_modem();
                  return -6;
            }
            usec = ((time2.tv_sec - time1.tv_sec) % 60 * 1000000)
                  + time2.tv_usec - time1.tv_usec;
            if (usec >= 1000000) {
                  time1 = time2;
                  freq0 = ((cnt0 - prevcnt0) & 0xffffff) * 1000000.0 / usec;
                  prevcnt0 = cnt0;
                  freq1 = ((cnt1 - prevcnt1) & 0xffffff) * 8000000.0 / usec;
                  prevcnt1 = cnt1;
                  freq2 = ((cnt2 - prevcnt2) & 0xffffff) * 1000000.0 / usec;
                  prevcnt2 = cnt2;
                  freq3 = ((cnt3 - prevcnt3) & 0xffffff) * 1000000.0 / usec;
                  prevcnt3 = cnt3;
            }
            tprintf("%06x %06x %06x %06x  %8d %8d %8d %8d\r", 
                   cnt0, cnt1, cnt2, cnt3, freq0, freq1, freq2, freq3);
            if (idle_callback(200000)) {
                  reset_modem();
                  return 0;
            }
      }
      return 0;

errret:
      lprintf(0, "EPP timeout\n");
      return -1;
}

/* ---------------------------------------------------------------------- */
/*
 * LED test
 */

static int chkledtest(struct adapter_config *cfg)
{
      unsigned led = 0;
      int i;
      unsigned char eio;
      
      if ((i = adapter_start_eppchk()))
            return i;
      tprintf("LED test, DISCONNECT PTT!!\n");
      eio = 1;
      if (parport_epp_write_addr(&eio, 1) != 1)
            goto errret;
      for (;;) {
            led = (++led) & 3;
            eio = 1 << led;
            if (parport_epp_write_data(&eio, 1) != 1)
                  goto errret;
            tprintf("Lighting LED %s\r", ((const char *[4]){ "DCD", "CON", "STA", "PTT"})[led]);
            if (idle_callback(500000)) {
                  reset_modem();
                  return 0;
            }
      }
      return 0;

errret:
      lprintf(0, "EPP timeout\n");
      return -1;
}

/* ---------------------------------------------------------------------- */
/*
 * DAC test
 */

static int chkdactest(struct adapter_config *cfg)
{
      unsigned phase = 0, rot = 0;
      unsigned char eio;
      int i;
      
      if ((i = adapter_start_eppchk()))
            return i;
      tprintf("DAC test\n");
      eio = 2;
      if (parport_epp_write_addr(&eio, 1) != 1)
            goto errret;
      for (;;) {
            eio = 128 + 127 * sin(M_PI / 128 * phase);
            if (parport_epp_write_data(&eio, 1) != 1)
                  goto errret;
            phase = (phase + 1) & 0xff;
            if (phase)
                  continue;
            rot = (rot + 1) & 3;
            tprintf("%c\r", "|\\-/"[rot]);
            if (idle_callback(0)) {
                  reset_modem();
                  return 0;
            }
      }
      return 0;

errret:
      lprintf(0, "EPP timeout\n");
      return -1;
}

/* ---------------------------------------------------------------------- */
/*
 * Register test
 */

static int chkregtest(struct adapter_config *cfg)
{
      unsigned data, read, cnt = 0, err = 0;
      unsigned char eio[5];
      int i;
      
      if ((i = adapter_start_eppchk()))
            return i;
      tprintf("Checking LED register\n");
      eio[0] = 1;
      if (parport_epp_write_addr(eio, 1) != 1)
            goto errret;
      for (data = 0; data < 0x100; data += 0x40) {
            eio[0] = data;
            if (parport_epp_write_data(eio, 1) != 1)
                  goto errret;
            read = parport_read_status();
            tprintf("LED register: 0x%02x  LPT port status: 0x%02x  %sOK\n", data, read, 
                   (((data ^ (read << 4)) & 0x80) | ((data ^ (read << 1)) & 0x40)) ? "NOT " : "");
      }
      tprintf("EPP register read/write test\n");
      for (;;) {
            eio[0] = data;
            if (parport_epp_write_addr(eio, 1) != 1)
                  goto errret;
            if (parport_epp_read_addr(eio, 5) != 5)
                  goto errret;
            if ((data ^ eio[0]) & 0xff)
                  err++;
            cnt++;
            data++;
            tprintf("Count: %6d  Errors: %6d\r", cnt, err);
            if (idle_callback(0)) {
                  reset_modem();
                  return 0;
            }
      }
      return 0;

errret:
      lprintf(0, "EPP timeout\n");
      return -1;
}

/* ---------------------------------------------------------------------- */
/*
 * RAM-Test
 */

static int chkramaccess(unsigned addr, unsigned data, unsigned write)
{
      unsigned char rd;
      unsigned char eio[3];

      eio[0] = 8;
      if (parport_epp_write_addr(eio, 1) != 1)
            return -1;
      eio[0] = addr & 0xff;
      if (parport_epp_write_data(eio, 1) != 1)
            return -1;
      eio[0] = 9;
      if (parport_epp_write_addr(eio, 1) != 1)
            return -1;
      eio[0] = addr >> 8;
      if (parport_epp_write_data(eio, 1) != 1)
            return -1;
      if (write) {
            eio[0] = 11;
            if (parport_epp_write_addr(eio, 1) != 1)
                  return -1;
            eio[0] = data;
            if (parport_epp_write_data(eio, 1) != 1)
                  return -1;
            eio[0] = 8;
            eio[1] = 10;
            eio[2] = 8;
            if (parport_epp_write_addr(eio, 3) != 3)
                  return -1;
            return 0;
      }
      eio[0] = 11;
      if (parport_epp_write_addr(eio, 1) != 1)
            return -1;
      if (parport_epp_read_data(eio, 1) != 1)
            return -1;
      rd = eio[0];
      eio[0] = 8;
      if (parport_epp_write_addr(eio, 1) != 1)
            return -1;
      return rd;
}

static int chkramtestdata(unsigned data)
{
      int val;
      unsigned char s[10];

      if (chkramaccess(0, data, 1))
            return -1;
      val = chkramaccess(0, 0, 0);
      if (val == -1)
            return -1;
      tprintf("Testing data pattern 0x%02x read 0x%02x  failure mask %8s\n",
             data, val, to_bin(s, val ^ data, 8));
      idle_callback(0);
      return val ^ data;
}

static int chkramtestaddr(void)
{
      unsigned char ramd[32768];
      unsigned int i, j, k, l, mask = 0;
      unsigned char s[16];

      for (i = 0; i < 32768; i++) {
            if (!(i & 0xff)) {
                  tprintf("Writing RAM address 0x%04x...\r", i);
                  if (idle_callback(0))
                        return mask;
            }
            ramd[i] = random();
            if (chkramaccess(i, ramd[i], 1))
                  return -1;
      }
      for (i = 0; i < 32768; i++) {
            if (!(i & 0xff)) {
                  tprintf("Reading RAM address 0x%04x...\r", i);
                  if (idle_callback(0))
                        return mask;
            }
            j = chkramaccess(i, 0, 0);
            if (j == -1)
                  return -1;
            if (j == ramd[i])
                  continue;
            l = 0xffff;
            for (k = 0; k < 32768; k++) {
                  if (ramd[k] != j)
                        continue;
                  if (hweight32(l) > hweight32(k ^ i))
                        l = k ^ i;
            }
            mask |= k;
            tprintf("RAM address error at 0x%04x minimum error mask %15s\n", 
                   i, to_bin(s, k, 15));
            if (idle_callback(0))
                  return mask;
      }
      return mask;
}

static int chkramtest(struct adapter_config *cfg)
{
      int mask, val;
      unsigned char s[16];
      int i;
      
      if ((i = adapter_start_eppchk()))
            return i;
      tprintf("Performing RAM test...\n");
      if ((mask = chkramtestdata(0xff)) == -1)
            goto errret;
      if ((val = chkramtestdata(0x00)) == -1)
            goto errret;
      mask |= val;
      if ((val = chkramtestdata(0x55)) == -1)
            goto errret;
      mask |= val;
      if ((val = chkramtestdata(0xaa)) == -1)
            goto errret;
      mask |= val;
      if ((val = chkramtestdata(0xcc)) == -1)
            goto errret;
      mask |= val;
      if ((val = chkramtestdata(0x33)) == -1)
            goto errret;
      mask |= val;
      if (mask) {
            tprintf("RAM data error mask %s\nRAM data test failed, exiting\n", 
                   to_bin(s, mask, 8));
            reset_modem();
            return -4;
      }
      if ((mask = chkramtestaddr()) == -1)
            goto errret;
      if (mask) {
            tprintf("RAM address error mask %s\nRAM address test failed, exiting\n", 
                  to_bin(s, mask, 15));
            reset_modem();
            return -5;
      }
      if (!idle_callback(0))
            tprintf("\nRAM test passed\n");
      reset_modem();
      return 0;

errret:
      lprintf(0, "EPP timeout\n");
      return -1;
}

/* ---------------------------------------------------------------------- */
/*
 * Sigma Delta A/D converter
 */

static int chkadctest(struct adapter_config *cfg)
{
      unsigned char eio;
      int i;

      if ((i = adapter_start_eppchk()))
            return i;
      tprintf("Performing SigmaDelta A/D converter test...\n");
      tprintf("ADC signal is now routed to DAC...\n");
      i = 19666660 / 9600;
      eio = 0x1e;
      if (parport_epp_write_addr(&eio, 1) != 1)
            goto errret;
      eio = i;
      if (parport_epp_write_data(&eio, 1) != 1)
            goto errret;
      eio = 0x1f;
      if (parport_epp_write_addr(&eio, 1) != 1)
            goto errret;
      eio = i >> 8;
      if (parport_epp_write_data(&eio, 1) != 1)
            goto errret;
      eio = 0x10;
      if (parport_epp_write_addr(&eio, 1) != 1)
            goto errret;
      for (;;) {
            if (idle_callback(100000))
                  break;
      }
      reset_modem();
      return 0;

errret:
      lprintf(0, "EPP timeout\n");
      return -1;
}

/* ========= EPP FIRMWARE TESTS ========================================= */

/*
 * EPP LED test
 */

static int eppledtest(struct adapter_config *cfg)
{
      unsigned led = 0;
      unsigned char eio;
      int i;
      
      if ((i = adapter_start_epp(cfg)))
            return i;
      tprintf("EPP port LED test\n");
      for (;;) {
            led = !led;
            eio = led ? EPP_LED_STA : EPP_LED_CON;
            if (parport_epp_write_addr(&eio, 1) != 1)
                  goto errret;
            tprintf("Lighting LED %s\r", ((const char *[2]){ "CON", "STA" })[led]);
            if (idle_callback(500000)) {
                  reset_modem();
                  return 0;
            }
      }
      return 0;

errret:
      lprintf(0, "EPP timeout\n");
      return -1;
}

static int eppledtest2(struct adapter_config *cfg)
{
      unsigned led = 0;
      unsigned char eio;
      int i;
      
      if ((i = adapter_start_epp(cfg)))
            return i;
      tprintf("EPP port LED test (fast)\n");
      for (;;) {
            led = !led;
            eio = led ? EPP_LED_STA : EPP_LED_CON;
            if (parport_epp_write_addr(&eio, 1) != 1)
                  goto errret;
            if (idle_callback(0)) {
                  reset_modem();
                  return 0;
            }
      }
      return 0;

errret:
      lprintf(0, "EPP timeout\n");
      return -1;
}

/* ---------------------------------------------------------------------- */
/*
 * EPP modem test
 */

static int eppmodemtest(struct adapter_config *cfg, unsigned int flags)
{
      unsigned int enc_state = 0x100;
      unsigned int dec_state = 0;
      unsigned int mask1, mask2;
      unsigned char stat;
        int cnt, cntx, i, j, icnt, ocnt, icntx, ocntx;
      unsigned int berr = 0;
#if 0
      unsigned int pcnt = 0;
#endif
      unsigned char eio[2048];
      
      if ((i = adapter_start_epp(cfg)))
            return i;
      /* reset modem */
      eio[0] = 0;
      eio[1] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE;
      if (parport_epp_write_addr(eio, 2) != 2)
            goto errret;
      for (;;) {
            if (parport_epp_read_addr(&stat, 1) != 1)
                  goto errret;
            /* determine TX fifo size from status bits */
            switch (stat & (EPP_NTAEF|EPP_NTHF)) {
            case EPP_NTHF:
                  ocntx = 2048 - 256;
                  break;

            case EPP_NTAEF:
                  ocntx = 2048 - 1793;
                  break;

            case 0:
                  ocntx = 0;
                  break;

            default:
                  ocntx = 2048 - 1025;
                  break;
            }
            /* determine RX fifo size from status bits */
            switch (stat & (EPP_NRAEF|EPP_NRHF)) {
            case EPP_NRHF:
                  icntx = 0;
                  break;
                
            case EPP_NRAEF:
                  icntx = 1025;
                  break;
                
            case 0:
                  icntx = 1793;
                  break;
                
            default:
                  icntx = 256;
                  break;
            }
            ocnt = ocntx;
            icnt = icntx;
            /* try to determine the FIFO count if in extended mode */
            if (cfg->extstat) {
                  eio[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|1;
                  if (parport_epp_write_addr(eio, 1) != 1)
                        goto errret;
getpid();
                  if (parport_epp_read_addr(eio, 2) != 2)
                        goto errret;
getpid();
                  icnt = eio[0] | (((unsigned int)eio[1]) << 8);
                  eio[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|2;
                  if (parport_epp_write_addr(eio, 1) != 1)
                        goto errret;
getpid();
                  if (parport_epp_read_addr(eio, 2) != 2)
                        goto errret;
getpid();
                  ocnt = eio[0] | (((unsigned int)eio[1]) << 8);
                  eio[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE;
                  if (parport_epp_write_addr(eio, 1) != 1)
                        goto errret;
                  ocnt = 16384 - (ocnt & 0x7fff);
                  icnt &= 0x7fff;
#if 0
                  {
                        unsigned ocnt2, icnt2;
                        eio[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|1;
                        if (parport_epp_write_addr(eio, 1) != 1)
                              goto errret;
                        if (parport_epp_read_addr(eio, 2) != 2)
                              goto errret;
                        icnt2 = eio[0] | (((unsigned int)eio[1]) << 8);
                        eio[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|2;
                        if (parport_epp_write_addr(eio, 1) != 1)
                              goto errret;
                        if (parport_epp_read_addr(eio, 2) != 2)
                              goto errret;
                        ocnt2 = eio[0] | (((unsigned int)eio[1]) << 8);
                        eio[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE;
                        if (parport_epp_write_addr(eio, 1) != 1)
                              goto errret;
                        ocnt2 = 16384 - (ocnt2 & 0x7fff);
                        icnt2 &= 0x7fff;

                        if (icnt != icnt2 || ocnt != ocnt2) {
                              printf("\nCOUNT ERROR!! icnt 0x%x icnt2 0x%x ocnt 0x%x ocnt2 0x%x\n",
                                     icnt, icnt2, ocnt, ocnt2);
                        }
                  }
#endif

            }
            /* try to tx */
            for (cntx = ocnt; cntx > 0; cntx -= cnt) {
                  cnt = cntx;
                  if (cnt > sizeof(eio))
                        cnt = sizeof(eio);
                  if (flags & 2) {
                        for (j = 0; j < cnt; j++) {
                              enc_state >>= 8;
                              for (i = 0, mask1 = SCRAM_TAP1, mask2 = SCRAM_TAPN; 
                                   i < 8; i++, mask1 <<= 1, mask2 <<= 1)
                                    if (enc_state & mask1)
                                          enc_state ^= mask2;
                              eio[j] = enc_state;
                        }
                  } else
                        memset(eio, 0, cnt);
                  if (parport_epp_write_data(eio, cnt) != cnt)
                        goto errret;
            }
            if (icnt <= 0) {
                  if (idle_callback(10000)) {
                        reset_modem();
                        return 0;
                  }
            } else {
                  for (cntx = icnt; cntx > 0; cntx -= cnt) {
                        cnt = cntx;
                        if (cnt > sizeof(eio))
                              cnt = sizeof(eio);
                        if (parport_epp_read_data(eio, cnt) != cnt)
                              goto errret;
                        if (flags & 2) {
                              for (j = 0; j < cnt; j++) {
                                    dec_state = (dec_state >> 8) | (((unsigned int)eio[j]) << DESCRAM_TAPSH3);
                                    eio[j] = ((dec_state >> DESCRAM_TAPSH1) ^ 
                                            (dec_state >> DESCRAM_TAPSH2) ^
                                            (dec_state >> DESCRAM_TAPSH3)) & 0xff;
                              }
                        }
                        for (j = 0; j < cnt; j++) {
                              if (eio[j])
                                    berr += hweight8(eio[j]);
                              if (flags & 1)
                                    for (i = 0; i < 8; i++)
                                          fputc('0' + ((eio[j] >> i) & 1), stdout);
                        }
                  }
                  if (flags & 1)
                        fputc('\n', stdout);
            }
#if 0
            pcnt = (++pcnt) & 0x3f;
            if (pcnt)
                  continue;
#endif
            /* DCD has inverse logic */
            tprintf("BERR: %8d  DCD:%c  stat: %02x   icnt %5d icntx %5d ocnt %5d ocntx %5d\r", 
                   berr, (stat & EPP_DCDBIT) ? '-' : 'D', stat, icnt, icntx, ocnt, ocntx);
            if (idle_callback(0)) {
                  reset_modem();
                  return 0;
            }
      }
      return 0;

errret:
      lprintf(0, "EPP timeout\n");
      return -1;
}

static int eppmodemtest1(struct adapter_config *cfg)
{
      return eppmodemtest(cfg, 0);
}

static int eppmodemtest2(struct adapter_config *cfg)
{
      return eppmodemtest(cfg, 1);
}

static int eppmodemtest3(struct adapter_config *cfg)
{
      return eppmodemtest(cfg, 2);
}

static int eppmodemtest4(struct adapter_config *cfg)
{
      return eppmodemtest(cfg, 3);
}

/* ========= ECP FIRMWARE TESTS ========================================= */

/*
 * ECP LED test
 */

static int ecpledtest(struct adapter_config *cfg)
{
      unsigned led = 0;
      unsigned char eio;
      int i;
      
      if ((i = adapter_start_ecp(cfg)))
            return i;
      tprintf("ECP port LED test\n");
      for (;;) {
            led = !led;
            eio = 0xb0 | (led + 1);
            if (parport_ecp_write_addr(&eio, 1) != 1)
                  goto errret;
            tprintf("Lighting LED %s\r", ((const char *[2]){ "CON", "STA" })[led]);
            if (idle_callback(500000)) {
                  reset_modem();
                  return 0;
            }
      }
      return 0;

errret:
      lprintf(0, "ECP timeout\n");
      return -1;
}

static int ecpledtest2(struct adapter_config *cfg)
{
      unsigned led = 0;
      unsigned char eio;
      int i;
      
      if ((i = adapter_start_ecp(cfg)))
            return i;
      tprintf("ECP port LED test (fast)\n");
      for (;;) {
            led = !led;
            eio = 0xb0 | (led + 1);
            if (parport_ecp_write_addr(&eio, 1) != 1)
                  goto errret;
            if (idle_callback(0)) {
                  reset_modem();
                  return 0;
            }
      }
      return 0;

errret:
      lprintf(0, "ECP timeout\n");
      return -1;
}

/* ---------------------------------------------------------------------- */
/*
 * ECP modem test
 */

static int ecpmodemtest(struct adapter_config *cfg, unsigned int flags)
{
      unsigned int enc_state = 0x100;
      unsigned int dec_state = 0;
      unsigned int mask1, mask2;
      unsigned char stat[6];
      unsigned char data[4096];
        int cnt, cntx, i, j, icnt, ocnt;
      unsigned int berr = 0;
#if 0
      unsigned int pcnt = 0;
#endif

      if ((i = adapter_start_ecp(cfg)))
            return i;
      data[0] = 0xaf;  /* reset register: all reset */
      data[1] = 0xa0;  /* reset register: terminate reset */
      data[2] = 0xb0;
      if (parport_ecp_write_addr(data, 3) != 3)
            goto errret;
      for (;;) {
            data[0] = 0x81;
            if (parport_ecp_write_addr(data, 1) != 1)
                  goto errret;
            if (parport_ecp_read_data(stat, 6) != 6)
                  goto errret;
            data[0] = 0x80;
            if (parport_ecp_write_addr(data, 1) != 1)
                  goto errret;
            icnt = ((unsigned int)stat[2] << 8) | stat[1];
            ocnt = ((unsigned int)stat[4] << 8) | stat[3];
            /* read */
            if (icnt > 0) {
                  for (cntx = icnt; cntx > 0; cntx -= cnt) {
                        cnt = cntx;
                        if (cnt > sizeof(data))
                              cnt = sizeof(data);
                        if (cnt > 0xfff)
                              cnt = 0xfff;
                        data[0] = 0xc0 | (cnt & 0xf);
                        data[1] = 0xd0 | ((cnt >> 4) & 0xf);
                        data[2] = 0xe0 | ((cnt >> 8) & 0xf);
                        if (parport_ecp_write_addr(data, 3) != 3)
                              goto errret;
                        if (parport_ecp_read_data(data, cnt) != cnt)
                              goto errret;
                        /* if doubly scrambled do it in place */
                        if (flags & 2) {
                              for (i = 0; i < cnt; i++) {
                                    dec_state = (dec_state >> 8) | (((unsigned)data[i]) << DESCRAM_TAPSH3);
                                    data[i] = (dec_state >> DESCRAM_TAPSH1) ^ 
                                          (dec_state >> DESCRAM_TAPSH2) ^
                                          (dec_state >> DESCRAM_TAPSH3);
                              }
                        }
                        for (i = 0; i < cnt; i++) {
                              if (data[i])
                                    berr += hweight8(data[i]);
                              if (flags & 1)
                                    for (i = 0; i < 8; i++)
                                          fputc('0' + ((data[i] >> i) & 1), stdout);
                        }
                  }
                  if (flags & 1)
                        fputc('\n', stdout);
            } else {
                  if (idle_callback(10000)) {
                        reset_modem();
                        return 0;
                  }
            }
            /* write */
            for (cntx = 16384 - ocnt; cntx > 0; cntx -= cnt) {
                  cnt = cntx;
                  if (cnt > sizeof(data))
                        cnt = sizeof(data);
                  if (flags & 2) {
                        for (i = 0; i < cnt; i++) {
                              enc_state >>= 8;
                              for (j = 0, mask1 = SCRAM_TAP1, mask2 = SCRAM_TAPN;
                                   j < 8; j++, mask1 <<= 1, mask2 <<= 1)
                                    if (enc_state & mask1)
                                          enc_state ^= mask2;
                              data[i] = enc_state;
                        }
                  } else
                        memset(data, 0, cnt);
                  if (parport_ecp_write_data(data, cnt) != cnt)
                        goto errret;
            }
#if 0
            pcnt = (++pcnt) & 0x3f;
            if (pcnt)
                  continue;
#endif
            /* DCD has inverse logic */
            tprintf("BERR: %8d  DCD:%c  stat: %02x   icnt %5d ocnt %5d\r", 
                   berr, (stat[0] & EPP_DCDBIT) ? '-' : 'D', stat[0], icnt, ocnt);
            if (idle_callback(0)) {
                  reset_modem();
                  return 0;
            }
      }
      return 0;

errret:
      lprintf(0, "ECP timeout\n");
      return -1;
}

static int ecpmodemtest1(struct adapter_config *cfg)
{
      return ecpmodemtest(cfg, 0);
}

static int ecpmodemtest2(struct adapter_config *cfg)
{
      return ecpmodemtest(cfg, 1);
}

static int ecpmodemtest3(struct adapter_config *cfg)
{
      return ecpmodemtest(cfg, 2);
}

static int ecpmodemtest4(struct adapter_config *cfg)
{
      return ecpmodemtest(cfg, 3);
}

/* ========= EPPAFSK FIRMWARE TESTS ===================================== */

/*
 * EPP AFSK LED test
 */

static int eppafskledtest(struct adapter_config *cfg)
{
      unsigned led = 0;
      unsigned char eio;
      int i;
      
      cfg->bitrate = 1200;
      if ((i = adapter_start_eppafsk(cfg)))
            return i;
      tprintf("EPPAFSK port LED test\n");
      for (;;) {
            led = !led;
            eio = led ? EPP_LED_STA : EPP_LED_CON;
            if (parport_epp_write_addr(&eio, 1) != 1)
                  goto errret;
            tprintf("Lighting LED %s\r", ((const char *[2]){ "CON", "STA" })[led]);
            if (idle_callback(500000)) {
                  reset_modem();
                  return 0;
            }
      }
      return 0;

errret:
      lprintf(0, "EPP timeout\n");
      return -1;
}

static int eppafskledtest2(struct adapter_config *cfg)
{
      unsigned led = 0;
      unsigned char eio;
      int i;
      
      cfg->bitrate = 1200;
      if ((i = adapter_start_eppafsk(cfg)))
            return i;
      tprintf("EPPAFSK port LED test (fast)\n");
      for (;;) {
            led = !led;
            eio = led ? EPP_LED_STA : EPP_LED_CON;
            if (parport_epp_write_addr(&eio, 1) != 1)
                  goto errret;
            if (idle_callback(0)) {
                  reset_modem();
                  return 0;
            }
      }
      return 0;

errret:
      lprintf(0, "EPP timeout\n");
      return -1;
}

/* ---------------------------------------------------------------------- */
/*
 * EPP AFSK modem test
 */

static int eppafskmodemtest(struct adapter_config *cfg, unsigned int flags)
{
      unsigned int enc_state = 0x100;
      unsigned int dec_state = 0;
      unsigned int mask1, mask2;
      unsigned char stat, txbyte;
        int i, j, icnt, ocnt;
      unsigned int berr = 0;
#if 0
      unsigned int pcnt = 0;
#endif
      unsigned char eio[32];

      cfg->bitrate = 1200;
      if ((i = adapter_start_eppafsk(cfg)))
            return i;
      txbyte = -((flags >> 1) & 1);
      /* reset modem */
      eio[0] = 0x00;
      eio[1] = 0x18;
      if (parport_epp_write_addr(eio, 2) != 2)
            goto errret;
      for (;;) {
            if (parport_epp_read_addr(&stat, 1) != 1)
                  goto errret;
            /* determine the FIFO count */
            eio[0] = 0x19;
            if (parport_epp_write_addr(eio, 1) != 1)
                  goto errret;
            if (parport_epp_read_addr(eio, 1) != 1)
                  goto errret;
            ocnt = 0x10 - (eio[0] & 0x1f);
            eio[0] = 0x1a;
            if (parport_epp_write_addr(eio, 1) != 1)
                  goto errret;
            if (parport_epp_read_addr(eio, 1) != 1)
                  goto errret;
            icnt = eio[0] & 0x1f;
            eio[0] = 0x18;
            if (parport_epp_write_addr(eio, 1) != 1)
                  goto errret;
            /* try to tx */
            if (ocnt > 0) {
                  if (flags & 2) {
                        for (j = 0; j < ocnt; j++) {
                              enc_state >>= 8;
                              for (i = 0, mask1 = SCRAM_TAP1, mask2 = SCRAM_TAPN; 
                                   i < 8; i++, mask1 <<= 1, mask2 <<= 1)
                                    if (enc_state & mask1)
                                          enc_state ^= mask2;
                              eio[j] = enc_state;
                        }
                  } else
                        memset(eio, 0, ocnt);
                  if (parport_epp_write_data(eio, ocnt) != ocnt)
                        goto errret;
            }
            if (icnt <= 0) {
                  if (idle_callback(1000)) {
                        reset_modem();
                        return 0;
                  }
            }
            else {
                  if (parport_epp_read_data(eio, icnt) != icnt)
                        goto errret;
                  if (flags & 2) {
                        for (j = 0; j < icnt; j++) {
                              dec_state = (dec_state >> 8) | (((unsigned int)eio[j]) << DESCRAM_TAPSH3);
                              eio[j] = ((dec_state >> DESCRAM_TAPSH1) ^ 
                                      (dec_state >> DESCRAM_TAPSH2) ^
                                      (dec_state >> DESCRAM_TAPSH3)) & 0xff;
                        }
                  }
                  for (j = 0; j < icnt; j++) {
                        if (eio[j])
                              berr += hweight8(eio[j]);
                        if (flags & 1)
                              for (i = 0; i < 8; i++)
                                    fputc('0' + ((eio[j] >> i) & 1), stdout);
                  }
                  if (flags & 1)
                        fputc('\n', stdout);
            }
#if 0
            pcnt = (++pcnt) & 0x3f;
            if (pcnt)
                  continue;
#endif
            /* DCD has inverse logic */
            tprintf("BERR: %8d  DCD:%c PTT:%c  stat: %02x   icnt %5d ocnt %5d\r", 
                   berr, (stat & 0x80) ? '-' : 'D', (stat & 0x40) ? '-' : 'P', stat, icnt, ocnt);
            if (idle_callback(0)) {
                  reset_modem();
                  return 0;
            }
      }
      return 0;

errret:
      lprintf(0, "EPP timeout\n");
      return -1;
}

static int eppafskmodemtest1(struct adapter_config *cfg)
{
      return eppafskmodemtest(cfg, 0);
}

static int eppafskmodemtest2(struct adapter_config *cfg)
{
      return eppafskmodemtest(cfg, 1);
}

static int eppafskmodemtest3(struct adapter_config *cfg)
{
      return eppafskmodemtest(cfg, 2);
}

static int eppafskmodemtest4(struct adapter_config *cfg)
{
      return eppafskmodemtest(cfg, 3);
}

static int eppafskmodemtest5(struct adapter_config *cfg)
{
      return eppafskmodemtest(cfg, 4);
}

static int eppafskmodemtest6(struct adapter_config *cfg)
{
      return eppafskmodemtest(cfg, 6);
}

/* ========= SPPAFSK FIRMWARE TESTS ===================================== */

/*
 * SPP AFSK LED test
 */

static int sppafskledtest(struct adapter_config *cfg)
{
      unsigned led = 0;
      int i;
      
      cfg->bitrate = 1200;
      if ((i = adapter_start_sppafsk(cfg)))
            return i;
      tprintf("SPPAFSK port LED test\n");
      for (;;) {
            led = !led;
            sppafsk_wrcmd(led ? EPP_LED_STA : EPP_LED_CON);
            tprintf("Lighting LED %s\r", ((const char *[2]){ "CON", "STA" })[led]);
            if (idle_callback(500000)) {
                  reset_modem();
                  return 0;
            }
      }
      return 0;
}

static int sppafskledtest2(struct adapter_config *cfg)
{
      unsigned led = 0;
      int i;
      
      cfg->bitrate = 1200;
      if ((i = adapter_start_eppafsk(cfg)))
            return i;
      tprintf("SPPAFSK port LED test (fast)\n");
      for (;;) {
            led = !led;
            sppafsk_wrcmd(led ? EPP_LED_STA : EPP_LED_CON);
            if (idle_callback(0)) {
                  reset_modem();
                  return 0;
            }
      }
      return 0;
}

/* ---------------------------------------------------------------------- */
/*
 * SPP AFSK modem test
 */

static int sppafskmodemtest(struct adapter_config *cfg, unsigned int flags)
{
      unsigned int enc_state = 0x100;
      unsigned int dec_state = 0;
      unsigned int mask1, mask2;
      unsigned char stat, txbyte;
        int i, j, icnt, ocnt;
      unsigned int berr = 0;
#if 0
      unsigned int pcnt = 0;
#endif
      unsigned char currx;

      cfg->bitrate = 1200;
      if ((i = adapter_start_sppafsk(cfg)))
            return i;
      txbyte = -((flags >> 1) & 1);
      /* reset modem */
      sppafsk_wrcmd(0x00);
      sppafsk_wrcmd(0x18);
      for (;;) {
            stat = sppafsk_rdcmd();
            /* determine the FIFO count */
            sppafsk_wrcmd(0x19);
            ocnt = sppafsk_rdcmd();
            sppafsk_wrcmd(0x1a);
            icnt = sppafsk_rdcmd();
            sppafsk_wrcmd(0x18);
            if (icnt > 0x10 || ocnt > 0x10)
                  goto errret;
            ocnt = 0x10 - ocnt;
            /* try to tx */
            if (ocnt > 0) {
                  if (flags & 2) {
                        for (j = 0; j < ocnt; j++) {
                              enc_state >>= 8;
                              for (i = 0, mask1 = SCRAM_TAP1, mask2 = SCRAM_TAPN; 
                                   i < 8; i++, mask1 <<= 1, mask2 <<= 1)
                                    if (enc_state & mask1)
                                          enc_state ^= mask2;
                              sppafsk_wrdata(enc_state);
                        }
                  } else {
                        for (j = 0; j < ocnt; j++) 
                              sppafsk_wrdata(0);
                  }
            }
            if (icnt <= 0) {
                  if (idle_callback(1000)) {
                        reset_modem();
                        return 0;
                  }
            }
            else {
                  for (j = 0; j < icnt; j++) {
                        currx = sppafsk_rddata();
                        if (flags & 2) {
                              dec_state = (dec_state >> 8) | (((unsigned int)currx) << DESCRAM_TAPSH3);
                              currx = ((dec_state >> DESCRAM_TAPSH1) ^ 
                                     (dec_state >> DESCRAM_TAPSH2) ^
                                     (dec_state >> DESCRAM_TAPSH3)) & 0xff;
                        }
                        if (currx)
                              berr += hweight8(currx);
                        if (flags & 1)
                              for (i = 0; i < 8; i++)
                                    fputc('0' + ((currx >> i) & 1), stdout);
                  }
                  if (flags & 1)
                        fputc('\n', stdout);
            }
#if 0
            pcnt = (++pcnt) & 0x3f;
            if (pcnt)
                  continue;
#endif
            /* DCD has inverse logic */
            tprintf("BERR: %8d  DCD:%c PTT:%c  stat: %02x   icnt %5d ocnt %5d\r", 
                   berr, (stat & 0x80) ? '-' : 'D', (stat & 0x40) ? '-' : 'P', stat, icnt, ocnt);
            if (idle_callback(0)) {
                  reset_modem();
                  return 0;
            }
      }
      return 0;

errret:
      lprintf(0, "SPP bogus values read\n");
      return -1;
}

static int sppafskmodemtest1(struct adapter_config *cfg)
{
      return sppafskmodemtest(cfg, 0);
}

static int sppafskmodemtest2(struct adapter_config *cfg)
{
      return sppafskmodemtest(cfg, 1);
}

static int sppafskmodemtest3(struct adapter_config *cfg)
{
      return sppafskmodemtest(cfg, 2);
}

static int sppafskmodemtest4(struct adapter_config *cfg)
{
      return sppafskmodemtest(cfg, 3);
}

static int sppafskmodemtest5(struct adapter_config *cfg)
{
      return sppafskmodemtest(cfg, 4);
}

static int sppafskmodemtest6(struct adapter_config *cfg)
{
      return sppafskmodemtest(cfg, 6);
}

/* ---------------------------------------------------------------------- */
/*
 * HDLC receive tests
 */

static void tprintpkt(const unsigned char *pkt, unsigned len)
{
        unsigned char v1=1,cmd=0;
        unsigned char i,j;

        if (!pkt || len < 8)
                return;
        if (pkt[1] & 1) {
                /*
                 * FlexNet Header Compression
                 */
                v1 = 0;
                cmd = (pkt[1] & 2) != 0;
                tprintf("fm ? to ");
                i = (pkt[2] >> 2) & 0x3f;
                if (i)
                        tprintf("%c",i+0x20);
                i = ((pkt[2] << 4) | ((pkt[3] >> 4) & 0xf)) & 0x3f;
                if (i)
                        tprintf("%c", i+0x20);
                i = ((pkt[3] << 2) | ((pkt[4] >> 6) & 3)) & 0x3f;
                if (i)
                        tprintf("%c", i+0x20);
                i = pkt[4] & 0x3f;
                if (i)
                        tprintf("%c", i+0x20);
                i = (pkt[5] >> 2) & 0x3f;
                if (i)
                        tprintf("%c", i+0x20);
                i = ((pkt[5] << 4) | ((pkt[6] >> 4) & 0xf)) & 0x3f;
                if (i)
                        tprintf("%c", i+0x20);
                tprintf("-%u QSO Nr %u", pkt[6] & 0xf, (pkt[0] << 6) | (pkt[1] >> 2));
                pkt += 7;
                len -= 7;
        } else {
                /*
                 * normal header
                 */
                if (len < 15)
                        return;
                if ((pkt[6] & 0x80) != (pkt[13] & 0x80)) {
                        v1 = 0;
                        cmd = (pkt[6] & 0x80);
                }
                tprintf("fm ");
                for(i = 7; i < 13; i++) 
                        if ((pkt[i] &0xfe) != 0x40)
                                tprintf("%c", pkt[i] >> 1);
                tprintf("-%u to ", (pkt[13] >> 1) & 0xf);
                for(i = 0; i < 6; i++) 
                        if ((pkt[i] &0xfe) != 0x40)
                                tprintf("%c", pkt[i] >> 1);
                tprintf("-%u", (pkt[6] >> 1) & 0xf);
                pkt += 14;
                len -= 14;
                if ((!(pkt[-1] & 1)) && (len >= 7))
                        tprintf(" via ");
                while ((!(pkt[-1] & 1)) && (len >= 7)) {
                        for(i = 0; i < 6; i++) 
                                if ((pkt[i] &0xfe) != 0x40)
                                        tprintf("%c", pkt[i] >> 1);
                        tprintf("-%u", (pkt[6] >> 1) & 0xf);
                        pkt += 7;
                        len -= 7;
                        if ((!(pkt[-1] & 1)) && (len >= 7))
                                tprintf(",");
                }
        }
        if(!len) 
                return;
        i = *pkt++;
        len--;
        j = v1 ? ((i & 0x10) ? '!' : ' ') : 
                ((i & 0x10) ? (cmd ? '+' : '-') : (cmd ? '^' : 'v'));
        if (!(i & 1)) {
                /*
                 * Info frame
                 */
                tprintf(" I%u%u%c", (i >> 5) & 7, (i >> 1) & 7, j);
        } else if (i & 2) {
                /*
                 * U frame
                 */
                switch (i & (~0x10)) {
                case 0x03:
                        tprintf(" UI%c", j);
                        break;
                case 0x2f:
                        tprintf(" SABM%c", j);
                        break;
                case 0x43:
                        tprintf(" DISC%c", j);
                        break;
                case 0x0f:
                        tprintf(" DM%c", j);
                        break;
                case 0x63:
                        tprintf(" UA%c", j);
                        break;
                case 0x87:
                        tprintf(" FRMR%c", j);
                        break;
                default:
                        tprintf(" unknown U (0x%x)%c", i & (~0x10), j);
                        break;
                }
        } else {
                /*
                 * supervisory
                 */
                switch (i & 0xf) {
                case 0x1:
                        tprintf(" RR%u%c", (i >> 5) & 7, j);
                        break;
                case 0x5:
                        tprintf(" RNR%u%c", (i >> 5) & 7, j);
                        break;
                case 0x9:
                        tprintf(" REJ%u%c", (i >> 5) & 7, j);
                        break;
                default:
                        tprintf(" unknown S (0x%x)%u%c", i & 0xf, (i >> 5) & 7, j);
                        break;
                }
        }
        if (!len) {
                tprintf("\n");
                return;
        }
        tprintf(" pid=%02X\n", *pkt++);
        len--;
        j = 0;
        while (len) {
                i = *pkt++;
            if ((i >= 32) && (i < 128))
                  tprintf("%c", i);
            else if (i == 13) {
                        if (j)
                                tprintf("\n");
                        j = 0;
                } else
                        tprintf(".");
                if (i >= 32) 
                        j = 1;
                len--;
        }
        if (j)
                tprintf("\n");
}

/* ---------------------------------------------------------------------- */
/*
 * the CRC routines are stolen from WAMPES
 * by Dieter Deyke
 */

static const u_int16_t crc_ccitt_table[0x100] = {
        0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
        0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
        0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
        0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
        0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
        0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
        0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
        0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
        0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
        0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
        0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
        0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
        0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
        0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
        0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
        0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
        0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
        0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
        0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
        0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
        0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
        0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
        0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
        0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
        0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
        0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
        0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
        0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
        0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
        0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
        0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
        0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};

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

extern inline u_int16_t calc_crc_ccitt(const u_int8_t *buffer, int len)
{
        u_int16_t crc = 0xffff;

        for (;len>0;len--)
                crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buffer++) & 0xff];
        crc ^= 0xffff;
      return crc;
}

extern inline void append_crc_ccitt(u_int8_t *buffer, int len)
{
        u_int16_t crc = calc_crc_ccitt(buffer, len);
        *buffer++ = crc;
        *buffer++ = crc >> 8;
}

extern inline int check_crc_ccitt(const u_int8_t *buffer, int len)
{
        u_int16_t crc = calc_crc_ccitt(buffer, len);
        return (crc & 0xffff) == 0x0f47;
}

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

#define MAXFLEN           512
#define RXBUFFER_SIZE     ((MAXFLEN*6/5)+8)

struct hdlc_receiver {
        unsigned int bitbuf, bitstream, numbits, state;
        unsigned char *bufptr;
        int bufcnt;
        unsigned char buf[RXBUFFER_SIZE];
};

extern inline void hdlc_initrx(struct hdlc_receiver *h)
{       
        memset(h, 0, sizeof(struct hdlc_receiver));
        h->bufptr = h->buf;
}

static void do_rxpacket(struct hdlc_receiver *h)
{
      if (h->bufcnt < 4) 
            return;
      if (!check_crc_ccitt(h->buf, h->bufcnt)) 
            return;
      tprintf("                                                              \r");
      tprintpkt(h->buf, h->bufcnt-2);
}

#define DECODEITERA(j)                                                        \
{                                                                             \
        if (!(notbitstream & (0x0fc << j)))              /* flag or abort */  \
                goto flgabrt##j;                                              \
        if ((bitstream & (0x1f8 << j)) == (0xf8 << j))   /* stuffed bit */    \
                goto stuff##j;                                                \
}                                                                             \
  enditer##j:

#define DECODEITERB(j)                                                                 \
({                                                                                     \
  flgabrt##j:                                                                          \
        if (!(notbitstream & (0x1fc << j))) {              /* abort received */        \
                state = 0;                                                             \
                goto enditer##j;                                                       \
        }                                                                              \
        if ((bitstream & (0x1fe << j)) != (0x0fc << j))   /* flag received */          \
                goto enditer##j;                                                       \
        if (state)                                                                     \
                do_rxpacket(h);                                                        \
        h->bufcnt = 0;                                                                 \
        h->bufptr = h->buf;                                                            \
        state = 1;                                                                     \
        numbits = 7-j;                                                                 \
        goto enditer##j;                                                               \
  stuff##j:                                                                            \
        numbits--;                                                                     \
        bitbuf = (bitbuf & ((~0xff) << j)) | ((bitbuf & ~((~0xff) << j)) << 1);        \
        goto enditer##j;                                                               \
})
        
/* ---------------------------------------------------------------------- */

static void hdlc_receive(struct hdlc_receiver *h, u_int8_t *bits, int cnt)
{
        unsigned int bitbuf, notbitstream, bitstream, numbits, state;
        u_int8_t ch;

        numbits = h->numbits;
        state = h->state;
        bitstream = h->bitstream;
        bitbuf = h->bitbuf;
        for (; cnt > 0; cnt--) {
                ch = *bits++;
                bitstream >>= 8;
                bitstream |= ch << 8;
                bitbuf >>= 8;
                bitbuf |= ch << 8;
                numbits += 8;
                notbitstream = ~bitstream;
                DECODEITERA(0);
                DECODEITERA(1);
                DECODEITERA(2);
                DECODEITERA(3);
                DECODEITERA(4);
                DECODEITERA(5);
                DECODEITERA(6);
                DECODEITERA(7);
                goto enddec;
                DECODEITERB(0);
                DECODEITERB(1);
                DECODEITERB(2);
                DECODEITERB(3);
                DECODEITERB(4);
                DECODEITERB(5);
                DECODEITERB(6);
                DECODEITERB(7);
          enddec:
                while (state && numbits >= 8) {
                        if (h->bufcnt >= RXBUFFER_SIZE) {
                                state = 0;
                        } else {
                                *(h->bufptr)++ = bitbuf >> (16-numbits);
                                h->bufcnt++;
                                numbits -= 8;
                        }
                }
        }
        h->numbits = numbits;
        h->state = state;
        h->bitstream = bitstream;
        h->bitbuf = bitbuf;
}

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

static int epprx(struct adapter_config *cfg)
{
      u_int8_t stat;
        int cnt, cntx, i, icnt, ocnt, icntx, ocntx;
#if 0
      unsigned int pcnt = 0;
#endif
      struct hdlc_receiver hdlcrx;
      unsigned char eio[1024];

      hdlc_initrx(&hdlcrx);
      if ((i = adapter_start_epp(cfg)))
            return i;
      /* reset modem */
      eio[0] = 0;
      eio[1] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE;
      if (parport_epp_write_addr(eio, 2) != 2)
            goto errret;
      for (;;) {
            if (parport_epp_read_addr(&stat, 1) != 1)
                  goto errret;
            /* determine TX fifo size from status bits */
            switch (stat & (EPP_NTAEF|EPP_NTHF)) {
            case EPP_NTHF:
                  ocntx = 2048 - 256;
                  break;

            case EPP_NTAEF:
                  ocntx = 2048 - 1793;
                  break;

            case 0:
                  ocntx = 0;
                  break;

            default:
                  ocntx = 2048 - 1025;
                  break;
            }
            /* determine RX fifo size from status bits */
            switch (stat & (EPP_NRAEF|EPP_NRHF)) {
            case EPP_NRHF:
                  icntx = 0;
                  break;
                
            case EPP_NRAEF:
                  icntx = 1025;
                  break;
                
            case 0:
                  icntx = 1793;
                  break;
                
            default:
                  icntx = 256;
                  break;
            }
            ocnt = ocntx;
            icnt = icntx;
            /* try to determine the FIFO count if in extended mode */
            if (cfg->extstat) {
                  eio[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|1;
                  if (parport_epp_write_addr(eio, 1) != 1)
                        goto errret;
                  if (parport_epp_read_addr(eio, 2) != 2)
                        goto errret;
                  icnt = eio[0] | (((unsigned int)eio[1]) << 8);
                  eio[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|2;
                  if (parport_epp_write_addr(eio, 1) != 1)
                        goto errret;
                  if (parport_epp_read_addr(eio, 2) != 2)
                        goto errret;
                  ocnt = eio[0] | (((unsigned int)eio[1]) << 8);
                  eio[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE;
                  if (parport_epp_write_addr(eio, 1) != 1)
                        goto errret;
                  ocnt = 16384 - (ocnt & 0x7fff);
                  icnt &= 0x7fff;
            }
            /* try to tx */
#if 0
            if (ocnt > 0) {
            }
#endif
            if (icnt > 0) {
                  for (cntx = icnt; cntx > 0; cntx -= cnt) {
                        cnt = cntx;
                        if (cnt > sizeof(eio))
                              cnt = sizeof(eio);
                        if (parport_epp_read_data(eio, cnt) != cnt)
                              goto errret;
                        hdlc_receive(&hdlcrx, eio, cnt);
                  }
            } else {
                  if (idle_callback(10000)) {
                        reset_modem();
                        return 0;
                  }
            }
#if 0
            pcnt = (++pcnt) & 0x3f;
            if (pcnt)
                  continue;
#endif
            /* DCD has inverse logic */
            tprintf("DCD:%c  stat: %02x   icnt %5d icntx %5d ocnt %5d ocntx %5d\r", 
                   (stat & EPP_DCDBIT) ? '-' : 'D', stat, icnt, icntx, ocnt, ocntx);
            if (idle_callback(0)) {
                  reset_modem();
                  return 0;
            }
      }
      return 0;

errret:
      lprintf(0, "EPP timeout\n");
      return -1;
}

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

static int ecprx(struct adapter_config *cfg)
{
      u_int8_t stat[6];
        int cnt, cntx, i, icnt, ocnt;
#if 0
      unsigned int pcnt = 0;
#endif
      unsigned char data[4096];
      struct hdlc_receiver hdlcrx;

      hdlc_initrx(&hdlcrx);
      if ((i = adapter_start_ecp(cfg)))
            return i;
      data[0] = 0xaf;  /* reset register: all reset */
      data[1] = 0xa0;  /* reset register: terminate reset */
      data[2] = 0xb0;
      if (parport_ecp_write_addr(data, 3) != 3)
            goto errret;
      for (;;) {
            data[0] = 0x81;
            if (parport_ecp_write_addr(data, 1) != 1)
                  goto errret;
            if (parport_ecp_read_data(stat, 6) != 6)
                  goto errret;
            data[0] = 0x80;
            if (parport_ecp_write_addr(data, 1) != 1)
                  goto errret;
            icnt = ((unsigned)stat[2] << 8) | stat[1];
            ocnt = ((unsigned)stat[4] << 8) | stat[3];
            /* read */
            if (icnt > 0) {
                  for (cntx = icnt; cntx > 0; cntx -= cnt) {
                        cnt = cntx;
                        if (cnt > sizeof(data))
                              cnt = sizeof(data);
                        if (cnt > 0xfff)
                              cnt = 0xfff;
                        data[0] = 0xc0 | (cnt & 0xf);
                        data[1] = 0xd0 | ((cnt >> 4) & 0xf);
                        data[2] = 0xe0 | ((cnt >> 8) & 0xf);
                        if (parport_ecp_write_addr(data, 3) != 3)
                              goto errret;
                        if (parport_ecp_read_data(data, cnt) != cnt)
                              goto errret;
                        hdlc_receive(&hdlcrx, data, cnt);
                  }
            } else {
                  if (idle_callback(10000)) {
                        reset_modem();
                        return 0;
                  }
            }
            /* write */
#if 0
            if (ocnt < 8192) { /* fixme */
                  cnt = 8192 - ocnt;
                  if (cnt > sizeof(data))
                        cnt = sizeof(data);
            }
#endif
#if 0
            pcnt = (++pcnt) & 0x3f;
            if (pcnt)
                  continue;
#endif
            /* DCD has inverse logic */
            tprintf("DCD:%c  stat: %02x   icnt %5d ocnt %5d\r", 
                  (stat[0] & EPP_DCDBIT) ? '-' : 'D', stat[0], icnt, ocnt);
            if (idle_callback(0)) {
                  reset_modem();
                  return 0;
            }
      }
      return 0;

errret:
      lprintf(0, "ECP timeout\n");
      return -1;
}

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

static int eppafskrx(struct adapter_config *cfg)
{
      u_int8_t stat;
        int i, icnt, ocnt;
#if 0
      int j;
      unsigned int pcnt = 0;
#endif
      unsigned char eio[32];
      struct hdlc_receiver hdlcrx;

      hdlc_initrx(&hdlcrx);
      cfg->bitrate = 1200;
      if ((i = adapter_start_eppafsk(cfg)))
            return i;
      /* reset modem */
      eio[0] = 0x00;
      eio[1] = 0x18;
      if (parport_epp_write_addr(eio, 2) != 2)
            goto errret;
      for (;;) {
            if (parport_epp_read_addr(&stat, 1) != 1)
                  goto errret;
            /* determine the FIFO count */
            eio[0] = 0x19;
            if (parport_epp_write_addr(eio, 1) != 1)
                  goto errret;
            if (parport_epp_read_addr(eio, 1) != 1)
                  goto errret;
            ocnt = 0x10 - (eio[0] & 0x1f);
            eio[0] = 0x1a;
            if (parport_epp_write_addr(eio, 1) != 1)
                  goto errret;
            if (parport_epp_read_addr(eio, 1) != 1)
                  goto errret;
            icnt = eio[0] & 0x1f;
            eio[0] = 0x18;
            if (parport_epp_write_addr(eio, 1) != 1)
                  goto errret;
            /* try to tx */
#if 0
            if (ocnt > 0) {
            }
#endif
            if (icnt > 0) {
                  if (parport_epp_read_data(eio, icnt) != icnt)
                        goto errret;
#if 0
                  for (i = 0; i < icnt; i++)
                        for (j = 0; j < 8; j++)
                              putc('0' + ((eio[i] >> j) & 1), stdout);
                  fflush(stdout);
#endif
                  hdlc_receive(&hdlcrx, eio, icnt);
            } else {
                  if (idle_callback(10000)) {
                        reset_modem();
                        return 0;
                  }
            }
#if 0
            pcnt = (++pcnt) & 0x3f;
            if (pcnt)
                  continue;
#endif
            /* DCD has inverse logic */
#if 1
            tprintf("DCD:%c  stat: %02x   icnt %5d ocnt %5d\r", 
                   (stat & EPP_DCDBIT) ? '-' : 'D', stat, icnt, ocnt);
#endif
            if (idle_callback(0)) {
                  reset_modem();
                  return 0;
            }
      }
      return 0;

errret:
      lprintf(0, "EPP timeout\n");
      return -1;
}

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

static int sppafskrx(struct adapter_config *cfg)
{
      u_int8_t stat;
        int i, icnt, ocnt;
#if 0
      unsigned int pcnt = 0;
#endif
      unsigned char eio[32];
      struct hdlc_receiver hdlcrx;

      hdlc_initrx(&hdlcrx);
      cfg->bitrate = 1200;
      if ((i = adapter_start_sppafsk(cfg)))
            return i;
      /* reset modem */
      sppafsk_wrcmd(0x00);
      sppafsk_wrcmd(0x18);
      for (;;) {
            stat = sppafsk_rdcmd();
            /* determine the FIFO count */
            sppafsk_wrcmd(0x19);
            ocnt = sppafsk_rdcmd();
            sppafsk_wrcmd(0x1a);
            icnt = sppafsk_rdcmd();
            sppafsk_wrcmd(0x18);
            if (icnt > 0x10 || ocnt > 0x10)
                  goto errret;
            ocnt = 0x10 - ocnt;
            /* try to tx */
#if 0
            if (ocnt > 0) {
            }
#endif
            if (icnt > 0) {
                  for (i = 0; i < icnt; i++)
                        eio[i] = sppafsk_rddata();
                  hdlc_receive(&hdlcrx, eio, icnt);
            } else {
                  if (idle_callback(10000)) {
                        reset_modem();
                        return 0;
                  }
            }
#if 0
            pcnt = (++pcnt) & 0x3f;
            if (pcnt)
                  continue;
#endif
            /* DCD has inverse logic */
            tprintf("DCD:%c  stat: %02x   icnt %5d ocnt %5d\r", 
                   (stat & EPP_DCDBIT) ? '-' : 'D', stat, icnt, ocnt);
            if (idle_callback(0)) {
                  reset_modem();
                  return 0;
            }
      }
      return 0;

errret:
      lprintf(0, "SPP bogus values read\n");
      return -1;
}

/* ---------------------------------------------------------------------- */
/*
 * Sample IO Firmware Tests
 */

static int sine1k(struct adapter_config *cfg)
{
#if 0
      static const char scdisp[] = "                                                               *\n";
#endif
      signed char sine[128];
      unsigned char eio[1024];
      unsigned char ctrl = 0;
      unsigned phase = 0, ledcnt = 0;
      int i, icnt, ocnt, cnt, cntx;

      cfg->bitrate = 8000;
      if ((i = adapter_start_eppsamp(cfg)))
            return i;
      for (i = 0; i < sizeof(sine); i++)
            sine[i] = 127 * sin((2.0 * M_PI / sizeof(sine)) * i);
      tprintf("Sine 1k Test\n");
      eio[0] = 7;
      eio[1] = 0;
      if (parport_epp_write_addr(eio, 2) != 2)
            goto errret;
      for (;;) {
            /* determine the FIFO count */
            eio[0] = ctrl | 1;
            if (parport_epp_write_addr(eio, 1) != 1)
                  goto errret;
            if (parport_epp_read_addr(eio, 2) != 2)
                  goto errret;
            icnt = eio[0] | (((unsigned int)eio[1]) << 8);
            eio[0] = ctrl | 2;
            if (parport_epp_write_addr(eio, 1) != 1)
                  goto errret;
            if (parport_epp_read_addr(eio, 2) != 2)
                  goto errret;
            ocnt = eio[0] | (((unsigned int)eio[1]) << 8);
            eio[0] = ctrl;
            if (parport_epp_write_addr(eio, 1) != 1)
                  goto errret;
            ocnt = 16384 - (ocnt & 0x7fff);
            icnt &= 0x7fff;
            /* try to tx */
            if (ocnt > 0) {
                  for (cntx = ocnt; cntx > 0; cntx -= cnt) {
                        cnt = cntx;
                        if (cnt > sizeof(eio))
                              cnt = sizeof(eio);
                        for (i = 0; i < cnt; i++) {
                              eio[i] = sine[(phase >> 9) & 0x7f];
                              phase += 0x1789;  /* pretty arbitrary */
                        }
                        if (parport_epp_write_data(eio, cnt) != cnt)
                              goto errret;
                  }
            }
            if (icnt > 0) {
                  for (cntx = icnt; cntx > 0; cntx -= cnt) {
                        cnt = cntx;
                        if (cnt > sizeof(eio))
                              cnt = sizeof(eio);
                        if (parport_epp_read_data(eio, cnt) != cnt)
                              goto errret;
                        for (i = 0; i < cnt; i++) {
#if 0
                              tprintf(scdisp + (((eio[i] + 128) & 0xff) / 4));
#elif 1
                              if (i < 64)
                                    tprintf("%4d\n", ((signed char)eio[i]));
                              else if (i == 64)
                                    tprintf("--\n");
#endif
                              if ((++ledcnt) >= 4000) {
                                    ledcnt = 0;
                                    ctrl += 0x40;
                              }
                        }
                  }
            } else {
                  if (idle_callback(10000)) {
                        reset_modem();
                        return 0;
                  }
            }
      }

errret:
      lprintf(0, "EPP timeout\n");
      return -1;
}

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

#ifdef HAVE_LINUX_SOUNDCARD_H

#include <linux/soundcard.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

#define SNDLATENCY 4000   /* approx 1/2 seconds */
#define PHASEFRAC  12
#define PHASEMASK  ((1<<PHASEFRAC)-1)
#define SINEOVERLAY

static int saudio(struct adapter_config *cfg)
{
      unsigned char bufu[8192];   /* must be significantly bigger than SNDLATENCY! */
      signed char bufs[8192];     /* must be significantly bigger than SNDLATENCY! */
      audio_buf_info aboinfo, abiinfo;
      int fddsp, apar;
      unsigned srate;
      unsigned char ctrl = 0;
      unsigned phinceppdsp, phincdspepp, pheppdsp = 0, phdspepp = 0;
      unsigned ledcnt = 0;
      int i, icnt, ocnt, cnt, ocnts, omax;
#ifdef SINEOVERLAY
      signed char sine[128];
      unsigned phase = 0;
#endif

#ifdef SINEOVERLAY
      for (i = 0; i < sizeof(sine); i++)
            sine[i] = 63 * sin((2.0 * M_PI / sizeof(sine)) * i);
#endif
      cfg->bitrate = 8000;
      if ((i = adapter_start_eppsamp(cfg)))
            return i;
      if ((fddsp = open("/dev/dsp", O_RDWR | O_NONBLOCK)) == -1) {
            lprintf(0, "cannot open /dev/dsp (%s)\n", strerror(errno));
            return -1;
      }
      fcntl(fddsp, F_SETFL, fcntl(fddsp, F_GETFL, 0) | O_NONBLOCK);
      if (ioctl(fddsp, SNDCTL_DSP_NONBLOCK, 0) == -1) {
            lprintf(0, "ioctl SNDCTL_DSP_NONBLOCK failed (%s)\n", strerror(errno));
            goto errsnd;
      }
      if (ioctl(fddsp, SNDCTL_DSP_GETCAPS, &apar) == -1) {
            lprintf(0, "ioctl SNDCTL_DSP_GETCAPS failed (%s)\n", strerror(errno));
            goto errsnd;
      }
      if (!(apar & DSP_CAP_DUPLEX)) {
            lprintf(0, "full duplex soundcard required\n");
            goto errsnd;
      }
      if (!(apar & DSP_CAP_TRIGGER)) {
            lprintf(0, "soundcard does not support trigger\n");
            goto errsnd;
      }
      if (ioctl(fddsp, SNDCTL_DSP_SETDUPLEX, 0) == -1) {
            lprintf(0, "ioctl SNDCTL_DSP_SETDUPLEX failed (%s)\n", strerror(errno));
            goto errsnd;
      }
      apar = AFMT_U8;
      if (ioctl(fddsp, SNDCTL_DSP_SETFMT, &apar) == -1) {
            lprintf(0, "ioctl SNDCTL_DSP_SETFMT failed (%s), U8 not supported??\n", strerror(errno));
            goto errsnd;
      }
      apar = 0;
      if (ioctl(fddsp, SNDCTL_DSP_STEREO, &apar) == -1) {
            lprintf(0, "ioctl SNDCTL_DSP_STEREO failed (%s), mono not supported??\n", strerror(errno));
            goto errsnd;
      }
      srate = cfg->bitrate;
      if (ioctl(fddsp, SNDCTL_DSP_SPEED, &srate) == -1) {
            lprintf(0, "ioctl SNDCTL_DSP_SPEED failed (%s), samplingrate %u not supported??\n", 
                  strerror(errno), cfg->bitrate);
            goto errsnd;
      }
      lprintf(1, "epp adapter sampling rate %u, soundcard sampling rate %u\n", cfg->bitrate, srate);
      if (abs(cfg->bitrate - srate) > cfg->bitrate / 2) {
            lprintf(0, "sampling rates (%u,%u) too different\n", cfg->bitrate, srate);
            goto errsnd;
      }
      phinceppdsp = ((1 << PHASEFRAC) * cfg->bitrate + srate / 2) / srate;
      phincdspepp = ((1 << PHASEFRAC) * srate + cfg->bitrate / 2) / cfg->bitrate;
      lprintf(1, "epp->dsp phase inc: 0x%05x  dsp->epp phase inc: 0x%05x\n", phinceppdsp, phincdspepp);
      if (ioctl(fddsp, SNDCTL_DSP_GETOSPACE, &aboinfo) == -1) {
            lprintf(0, "ioctl SNDCTL_DSP_GETOSPACE failed (%s)\n", strerror(errno));
            goto errsnd;
      }
      if (ioctl(fddsp, SNDCTL_DSP_GETISPACE, &abiinfo) == -1) {
            lprintf(0, "ioctl SNDCTL_DSP_GETISPACE failed (%s)\n", strerror(errno));
            goto errsnd;
      }
      if (aboinfo.fragstotal * aboinfo.fragsize < 2*SNDLATENCY ||
          abiinfo.fragstotal * abiinfo.fragsize < 2*SNDLATENCY) {
            lprintf(0, "soundcard buffers too small (%u,%u)\n", 
                  aboinfo.fragstotal * aboinfo.fragsize, 
                  abiinfo.fragstotal * abiinfo.fragsize);
            goto errsnd;
      }
      tprintf("Audio IO to Linux Soundcard\n");
      /* reset the EPP adapter */
      bufu[0] = 7;
      bufu[1] = 0;
      if (parport_epp_write_addr(bufu, 2) != 2)
            goto errret;
      /* prefill EPP adapter to nominal queue size */
      memset(bufs, 0, SNDLATENCY);
      if (parport_epp_write_data(bufs, SNDLATENCY) != SNDLATENCY)
            goto errret;
      /* prefill to nominal queue size and stard soundcard */
      memset(bufu, 0x80, SNDLATENCY);
      if ((i = write(fddsp, bufu, SNDLATENCY)) != SNDLATENCY) {
            lprintf(0, "write(%d) failed %i (%s)\n", SNDLATENCY, i, strerror(errno));
            goto errsnd;
      }
      apar = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT;
      if (ioctl(fddsp, SNDCTL_DSP_SETTRIGGER, &apar) == -1) {
            lprintf(0, "ioctl SNDCTL_DSP_SETTRIGGER failed (%s)\n", strerror(errno));
            goto errsnd;
      }
      /* start the whole thing */
      for (;;) {
            /* first do the epp->dsp direction */
            /* get FIFO count */
            bufu[0] = ctrl | 1;
            if (parport_epp_write_addr(bufu, 1) != 1)
                  goto errret;
            if (parport_epp_read_addr(bufu, 2) != 2)
                  goto errret;
            icnt = bufu[0] | (((unsigned int)bufu[1]) << 8);
            bufu[0] = ctrl;
            if (parport_epp_write_addr(bufu, 1) != 1)
                  goto errret;
            icnt &= 0x7fff;
            if (icnt > 0) {
                  if (icnt > sizeof(bufs)/2)
                        icnt = sizeof(bufs)/2;
                  if (parport_epp_read_data(bufs, icnt) != icnt)
                        goto errret;
                  pheppdsp &= PHASEMASK;
                  cnt = 0;
                  while (pheppdsp < (icnt << PHASEFRAC)) {
                        bufu[cnt] = bufs[pheppdsp >> PHASEFRAC] + 128;
                        pheppdsp += phinceppdsp;
                        cnt++;
                  }
                  if ((i = write(fddsp, bufu, cnt)) != cnt) {
                        lprintf(0, "write(%d) failed %i (%s)\n", cnt, i, strerror(errno));
                        goto errsnd;
                  }
                  if (ioctl(fddsp, SNDCTL_DSP_GETODELAY, &apar) == -1) {
                        lprintf(0, "ioctl SNDCTL_DSP_GETODELAY failed (%s)\n", strerror(errno));
                        goto errsnd;
                  }
                  /* adjust speed */
                  lprintf(4, "icnt %d cnt %d odel %d\n", icnt, cnt, apar);
                  if (apar > SNDLATENCY)
                        phinceppdsp++;
                  else if (apar < SNDLATENCY)
                        phinceppdsp--;
                  if (phinceppdsp < (0x9 << (PHASEFRAC-4)) || phinceppdsp > (0x1f << (PHASEFRAC-4))) {
                        lprintf(0, "phinceppdsp (0x%05x) out of range\n", phinceppdsp);
                        goto errsnd;
                  }
                  /* play games with the LEDS */
                  ledcnt += icnt;
                  if (ledcnt >= 4000) {
                        ledcnt %= 4000;
                        ctrl += 0x40;
                  }
            }
            /* next do the dsp->epp direction */
            /* get FIFO count */
            bufu[0] = ctrl | 2;
            if (parport_epp_write_addr(bufu, 1) != 1)
                  goto errret;
            if (parport_epp_read_addr(bufu, 2) != 2)
                  goto errret;
            ocnt = bufu[0] | (((unsigned int)bufu[1]) << 8);
            bufu[0] = ctrl;
            if (parport_epp_write_addr(bufu, 1) != 1)
                  goto errret;
            ocnt &= 0x7fff;
            omax = 16384 - ocnt;
            /* read sound */
            ocnts = read(fddsp, bufu, sizeof(bufu)/2);
            if (ocnts == -1 && errno == EAGAIN)
                  ocnts = 0;
            if (ocnts < 0) {
                  lprintf(0, "read(%d) failed %i (%s)\n", sizeof(bufu)/2, ocnts, strerror(errno));
                  goto errsnd;
            }
            if (ocnts > 0) {
                  phdspepp &= PHASEMASK;
                  cnt = 0;
                  while (phdspepp < (ocnts << PHASEFRAC)) {
                        bufs[cnt] = bufu[phdspepp >> PHASEFRAC] - 128;
                        phdspepp += phincdspepp;
                        cnt++;
                  }
                  if (cnt > omax) {
                        lprintf(0, "epp adapter output overrun (%d, %d)\n", cnt, omax);
                        goto errsnd;
                  }
#ifdef SINEOVERLAY
                  for (i = 0; i < cnt; i++) {
                        bufs[i] += sine[(phase >> 9) & 0x7f];
                        phase += 0x1789;  /* pretty arbitrary */
                  }
#endif
                  if (parport_epp_write_data(bufs, cnt) != cnt)
                        goto errret;
                  /* reget the FIFO count */
                  bufu[0] = ctrl | 2;
                  if (parport_epp_write_addr(bufu, 1) != 1)
                        goto errret;
                  if (parport_epp_read_addr(bufu, 2) != 2)
                        goto errret;
                  ocnt = bufu[0] | (((unsigned int)bufu[1]) << 8);
                  bufu[0] = ctrl;
                  if (parport_epp_write_addr(bufu, 1) != 1)
                        goto errret;
                  ocnt &= 0x7fff;
                  /* adjust speed */
                  lprintf(4, "ocnts %d cnt %d ocnt %d\n", ocnts, cnt, ocnt);
                  if (ocnt > SNDLATENCY)
                        phincdspepp++;
                  else if (ocnt < SNDLATENCY)
                        phincdspepp--;
                  if (phincdspepp < (0x9 << (PHASEFRAC-4)) || phincdspepp > (0x1f << (PHASEFRAC-4))) {
                        lprintf(0, "phincdspepp (0x%05x) out of range\n", phincdspepp);
                        goto errsnd;
                  }
            }
            /* wait a bit */
            if (idle_callback(50000)) {
                  reset_modem();
                  return 0;
            }
            lprintf(1, "phase increments: 0x%05x 0x%05x\n", phinceppdsp, phincdspepp);
      }

errret:
      lprintf(0, "EPP timeout\n");
errsnd:
      close(fddsp);
      return -1;
}

#endif /* HAVE_LINUX_SOUNDCARD_H */

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

#ifdef HAVE_DIRECTX

#include <directx.h>

#define SNDLATENCY 4000   /* approx 1/2 seconds */
#define PHASEFRAC  12
#define PHASEMASK  ((1<<PHASEFRAC)-1)
#define SINEOVERLAY

static BOOL CALLBACK DSEnumProc(LPGUID guid, LPCSTR lpszDesc, LPCSTR lpszDrvName, LPVOID lpcontext)
{
        lprintf(1, "has %sGUID, desc %s drvname %s\n", guid ? "" : "no ", lpszDesc, lpszDrvName);
        return TRUE;
}

static LRESULT CALLBACK MyWndProc(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam)
{
      switch (umsg) {
            /* Add cases such as WM_CREATE, WM_COMMAND, WM_PAINT if you don't 
                want to pass these messages along for default processing. */
      case WM_CLOSE:
            DestroyWindow (hwnd);
            return 0;

      case WM_DESTROY:
            PostQuitMessage (0);
            return 0;
      }
      return DefWindowProc (hwnd, umsg, wParam, lParam);
}

static int saudio(struct adapter_config *cfg)
{
      LPDIRECTSOUND dsplay = NULL;
      LPDIRECTSOUNDCAPTURE dsrec = NULL;
      LPDIRECTSOUNDBUFFER playbuf = NULL;
      LPDIRECTSOUNDCAPTUREBUFFER recbuf = NULL;
      WNDCLASS wndclass;
      HRESULT res;
        WAVEFORMATEX waveformat;
        DSBUFFERDESC bdesc;
        DSCBUFFERDESC cbdesc;
      HANDLE hinst;
      HWND hwnd;
      DWORD playbufsz, recbufsz, playptr = 0, recptr = 0;
      DWORD lockbytes, lockbytes2, delay;
      unsigned char *uptr;
      unsigned char *uptr2;
      unsigned char *uptr3;
      int retval = -1;
      unsigned char bufu[8];
      signed char bufs[8192];     /* must be significantly bigger than SNDLATENCY! */
      unsigned char ctrl = 0;
      unsigned phinceppdsp, phincdspepp, pheppdsp = 0, phdspepp = 0;
      unsigned ledcnt = 0;
      int i, icnt, ocnt, cnt, ocnts, omax;
#ifdef SINEOVERLAY
      signed char sine[128];
      unsigned phase = 0;
#endif

#ifdef SINEOVERLAY
      for (i = 0; i < sizeof(sine); i++)
            sine[i] = 63 * sin((2.0 * M_PI / sizeof(sine)) * i);
#endif
        lprintf(1, "DirectSound drivers\n");
        DirectSoundEnumerateA(DSEnumProc, NULL);
        lprintf(1, "DirectSoundCapture drivers\n");
        DirectSoundCaptureEnumerateA(DSEnumProc, NULL);
      hinst = GetModuleHandleA(0);
      wndclass.style = CS_HREDRAW | CS_VREDRAW;
      wndclass.lpfnWndProc = (WNDPROC)MyWndProc;
      wndclass.cbClsExtra = 0;
      wndclass.cbWndExtra = 0;
      wndclass.hIcon = NULL;
      wndclass.hInstance = hinst;
      wndclass.hCursor = NULL;
      wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
      wndclass.lpszMenuName = NULL;
      wndclass.lpszClassName = "MyClass";
      if (!RegisterClass(&wndclass)) {
            lprintf(0, "RegisterClass error, %d\n", GetLastError());
            return -1;
      }
      hwnd = CreateWindowEx(WS_EX_APPWINDOW, "MyClass", "eppfpga", WS_DISABLED | WS_POPUP,
                        0, 0, 0, 0, NULL, NULL, hinst, NULL);
      if (!hwnd) {
            lprintf(0, "CreateWindowEx error, %d\n", GetLastError());
            goto errcreatewin;
      }
        if (FAILED(res = DirectSoundCreate(NULL, &dsplay, NULL))) {
                lprintf(0, "DirectSoundCreate error %lu\n", res);
                goto errdscreate;
        }
        if (FAILED(res = IDirectSound_SetCooperativeLevel(dsplay, hwnd, DSSCL_NORMAL))) {
                lprintf(0, "SetCooperativeLevel error %lu\n", res);
                goto errdscreate1;
        }
        if (FAILED(res = DirectSoundCaptureCreate(NULL, &dsrec, NULL))) {
                lprintf(0, "DirectSoundCaptureCreate error %lu\n", res);
                goto errdscreate1;
        }
        memset(&waveformat, 0, sizeof(waveformat));
        waveformat.wFormatTag = WAVE_FORMAT_PCM;
        waveformat.wBitsPerSample = 8;
        waveformat.nChannels = 1;
        waveformat.nSamplesPerSec = 8000;
        waveformat.nBlockAlign = waveformat.nChannels * waveformat.wBitsPerSample / 8;
        waveformat.nAvgBytesPerSec = waveformat.nSamplesPerSec * waveformat.nBlockAlign;
        memset(&cbdesc, 0, sizeof(cbdesc));
        cbdesc.dwSize = sizeof(cbdesc);
        cbdesc.dwFlags = /* DSCBCAPS_WAVEMAPPED */ 0;
        recbufsz = cbdesc.dwBufferBytes = waveformat.nAvgBytesPerSec;
        cbdesc.lpwfxFormat = &waveformat;
        if (FAILED(res = IDirectSoundCapture_CreateCaptureBuffer(dsrec, &cbdesc, &recbuf, NULL))) {
                lprintf(0, "CreateSoundCaptureBuffer error %lu\n", res);
                goto errdscreate2;
        }
        memset(&waveformat, 0, sizeof(waveformat));
        waveformat.wFormatTag = WAVE_FORMAT_PCM;
        waveformat.wBitsPerSample = 8;
        waveformat.nChannels = 1;
        waveformat.nSamplesPerSec = 8000;
        waveformat.nBlockAlign = waveformat.nChannels * waveformat.wBitsPerSample / 8;
        waveformat.nAvgBytesPerSec = waveformat.nSamplesPerSec * waveformat.nBlockAlign;
        memset(&bdesc, 0, sizeof(bdesc));
        bdesc.dwSize = sizeof(bdesc);
        bdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPAN;
        playbufsz = bdesc.dwBufferBytes = waveformat.nAvgBytesPerSec;
        bdesc.lpwfxFormat = &waveformat;
        if (FAILED(res = IDirectSound_CreateSoundBuffer(dsplay, &bdesc, &playbuf, NULL))) {
                lprintf(0, "CreateSoundBuffer error %lu\n", res);
                goto errdscreate3;
        }
      cfg->bitrate = 8000;
      if ((i = adapter_start_eppsamp(cfg))) {
            retval = i;
            goto errdscreate4;
      }
      phinceppdsp = ((1 << PHASEFRAC) * cfg->bitrate + 8000 / 2) / 8000;
      phincdspepp = ((1 << PHASEFRAC) * 8000 + cfg->bitrate / 2) / cfg->bitrate;
      lprintf(1, "epp->dsp phase inc: 0x%05x  dsp->epp phase inc: 0x%05x\n", phinceppdsp, phincdspepp);
      tprintf("Audio IO to DirectX\n");
      /* reset the EPP adapter */
      bufu[0] = 7;
      bufu[1] = 0;
      if (parport_epp_write_addr(bufu, 2) != 2)
            goto errret;
      /* prefill EPP adapter to nominal queue size */
      memset(bufs, 0, SNDLATENCY);
      if (parport_epp_write_data(bufs, SNDLATENCY) != SNDLATENCY)
            goto errret;
      /* prefill to nominal queue size and stard soundcard */
      if (FAILED(res = IDirectSoundBuffer_Lock(playbuf, 0, SNDLATENCY, (LPVOID)&uptr, &lockbytes, NULL, NULL, 0))) {
                lprintf(0, "IDirectSoundBuffer_Lock error %lu\n", res);
                goto errresmodem;
        }
      memset(uptr, 0x80, SNDLATENCY);
      if (FAILED(res = IDirectSoundBuffer_Unlock(playbuf, uptr, lockbytes, NULL, 0))) {
                lprintf(0, "IDirectSoundBuffer_Unlock error %lu\n", res);
                goto errresmodem;
        }
      playptr = SNDLATENCY;
      if (FAILED(res = IDirectSoundBuffer_Play(playbuf, 0, 0, DSBPLAY_LOOPING))) {
                lprintf(0, "IDirectSoundBuffer_Play error %lu\n", res);
                goto errresmodem;
        }
      if (FAILED(res = IDirectSoundCaptureBuffer_Start(recbuf, DSCBSTART_LOOPING))) {
                lprintf(0, "IDirectSoundCaptureBuffer_Start error %lu\n", res);
                goto errresmodem;
        }
      /* start the whole thing */
      for (;;) {
            /* first do the epp->dsp direction */
            /* get FIFO count */
            bufu[0] = ctrl | 1;
            if (parport_epp_write_addr(bufu, 1) != 1)
                  goto errret;
            if (parport_epp_read_addr(bufu, 2) != 2)
                  goto errret;
            icnt = bufu[0] | (((unsigned int)bufu[1]) << 8);
            bufu[0] = ctrl;
            if (parport_epp_write_addr(bufu, 1) != 1)
                  goto errret;
            icnt &= 0x7fff;
            if (icnt > 0) {
                  if (icnt > sizeof(bufs)/2)
                        icnt = sizeof(bufs)/2;
                  if (parport_epp_read_data(bufs, icnt) != icnt)
                        goto errret;
                  pheppdsp &= PHASEMASK;
                  /* write to direct sound and convert */
                  if (FAILED(res = IDirectSoundBuffer_Lock(playbuf, playptr, SNDLATENCY, (LPVOID)&uptr, &lockbytes,
                                                 (LPVOID)&uptr2, &lockbytes2, 0))) {
                        lprintf(0, "IDirectSoundBuffer_Lock error %lu\n", res);
                        goto errresmodem;
                  }
                  uptr3 = uptr;
                  while (pheppdsp < (icnt << PHASEFRAC)) {
                        *uptr3++ = bufs[pheppdsp >> PHASEFRAC] + 128;
                        pheppdsp += phinceppdsp;
                        playptr++;
                        if (playptr >= playbufsz) {
                              playptr = 0;
                              uptr3 = uptr2;
                        }
                  }
                  if (FAILED(res = IDirectSoundBuffer_Unlock(playbuf, uptr, lockbytes, uptr2, lockbytes2))) {
                        lprintf(0, "IDirectSoundBuffer_Unlock error %lu\n", res);
                        goto errresmodem;
                  }
                  /* get output delay */
                  if (FAILED(res = IDirectSoundBuffer_GetCurrentPosition(playbuf, &delay, NULL))) {
                        lprintf(0, "IDirectSoundBuffer_GetCurrentPosition error %lu\n", res);
                        goto errresmodem;
                  }
                  delay = (playbufsz + playptr - delay) % playbufsz;
                  /* adjust speed */
                  lprintf(4, "icnt %d cnt %d odel %u\n", icnt, cnt, delay);
                  if (delay > SNDLATENCY)
                        phinceppdsp++;
                  else if (delay < SNDLATENCY)
                        phinceppdsp--;
                  if (phinceppdsp < (0x9 << (PHASEFRAC-4)) || phinceppdsp > (0x1f << (PHASEFRAC-4))) {
                        lprintf(0, "phinceppdsp (0x%05x) out of range\n", phinceppdsp);
                        goto errresmodem;
                  }
                  /* play games with the LEDS */
                  ledcnt += icnt;
                  if (ledcnt >= 4000) {
                        ledcnt %= 4000;
                        ctrl += 0x40;
                  }
            }
            /* next do the dsp->epp direction */
            /* get FIFO count */
            bufu[0] = ctrl | 2;
            if (parport_epp_write_addr(bufu, 1) != 1)
                  goto errret;
            if (parport_epp_read_addr(bufu, 2) != 2)
                  goto errret;
            ocnt = bufu[0] | (((unsigned int)bufu[1]) << 8);
            bufu[0] = ctrl;
            if (parport_epp_write_addr(bufu, 1) != 1)
                  goto errret;
            ocnt &= 0x7fff;
            omax = 16384 - ocnt;
            /* read sound */
            if (FAILED(res = IDirectSoundCaptureBuffer_GetCurrentPosition(recbuf, &delay, NULL))) {
                  lprintf(0, "IDirectSoundCaptureBuffer_GetCurrentPosition error %lu\n", res);
                  goto errresmodem;
            }
            ocnts = (recbufsz + delay - recptr) % recbufsz;
            if (ocnts > 0) {
                  if (FAILED(res = IDirectSoundCaptureBuffer_Lock(recbuf, recptr, SNDLATENCY, (LPVOID)&uptr, &lockbytes,
                                                      (LPVOID)&uptr2, &lockbytes2, 0))) {
                        lprintf(0, "IDirectSoundCaptureBuffer_Lock error %lu\n", res);
                        goto errresmodem;
                  }
                  uptr3 = uptr;
                  phdspepp &= PHASEMASK;
                  cnt = 0;
                  while (phdspepp < (ocnts << PHASEFRAC)) {
                        if (phdspepp >= ((recbufsz - recptr) << PHASEFRAC)) {
                              uptr3 = uptr2;
                              phdspepp -= (recbufsz - recptr) << PHASEFRAC;
                              recptr = 0;
                        }
                        bufs[cnt] = uptr3[phdspepp >> PHASEFRAC] - 128;
                        phdspepp += phincdspepp;
                        cnt++;
                  }
                  recptr = (recptr + (phdspepp >> PHASEFRAC)) % recbufsz;
                  if (FAILED(res = IDirectSoundCaptureBuffer_Unlock(recbuf, uptr, lockbytes, uptr2, lockbytes2))) {
                        lprintf(0, "IDirectSoundCaptureBuffer_Unlock error %lu\n", res);
                        goto errresmodem;
                  }
                  if (cnt > omax) {
                        lprintf(0, "epp adapter output overrun (%d, %d)\n", cnt, omax);
                        goto errresmodem;
                  }
#ifdef SINEOVERLAY
                  for (i = 0; i < cnt; i++) {
                        bufs[i] += sine[(phase >> 9) & 0x7f];
                        phase += 0x1789;  /* pretty arbitrary */
                  }
#endif
                  if (parport_epp_write_data(bufs, cnt) != cnt)
                        goto errret;
                  /* reget the FIFO count */
                  bufu[0] = ctrl | 2;
                  if (parport_epp_write_addr(bufu, 1) != 1)
                        goto errret;
                  if (parport_epp_read_addr(bufu, 2) != 2)
                        goto errret;
                  ocnt = bufu[0] | (((unsigned int)bufu[1]) << 8);
                  bufu[0] = ctrl;
                  if (parport_epp_write_addr(bufu, 1) != 1)
                        goto errret;
                  ocnt &= 0x7fff;
                  /* adjust speed */
                  lprintf(4, "ocnts %d cnt %d ocnt %d\n", ocnts, cnt, ocnt);
                  if (ocnt > SNDLATENCY)
                        phincdspepp++;
                  else if (ocnt < SNDLATENCY)
                        phincdspepp--;
                  if (phincdspepp < (0x9 << (PHASEFRAC-4)) || phincdspepp > (0x1f << (PHASEFRAC-4))) {
                        lprintf(0, "phincdspepp (0x%05x) out of range\n", phincdspepp);
                        goto errresmodem;
                  }
            }
            /* wait a bit */
            if (idle_callback(50000)) {
                  reset_modem();
                  retval = 0;
                  goto errresmodem;
            }
            lprintf(1, "phase increments: 0x%05x 0x%05x\n", phinceppdsp, phincdspepp);
      }

errret:
      lprintf(0, "EPP timeout\n");
errresmodem:
      IDirectSoundBuffer_Stop(playbuf);
      IDirectSoundCaptureBuffer_Stop(recbuf);
      reset_modem();
errdscreate4:
      IDirectSoundBuffer_Release(playbuf);
errdscreate3:
      IDirectSoundCaptureBuffer_Release(recbuf);
errdscreate2:
      IDirectSoundCapture_Release(dsrec);
errdscreate1:
      IDirectSound_Release(dsplay);
errdscreate:
      DestroyWindow(hwnd);
errcreatewin:
      UnregisterClass("MyClass", hinst);
      return -1;
}

#endif /* HAVE_DIRECTX */

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

const struct eppfpgatests eppfpgatests[] = {
      { "ram", "tests the on board SRAM", ramtest },
      { "bled", "tests the on board LED's using boundary scan", ledtest },
      { "dac", "tests the on board DAC", dactest },
      { "ppsig", "tests the parallel port signals using boundary scan", ppsigtest },
      { "led", "tests the CON and STA leds using EPP address write", eppledtest },
      { "ledfast", "tests the CON and STA leds using fast EPP address write", eppledtest2 },
      { "berr", "tests the complete adapter", eppmodemtest1 },
      { "berrv", "tests the complete adapter (verbose)", eppmodemtest2 },
      { "berrd", "tests the complete adapter (exercises data transfer)", eppmodemtest3 },
      { "berrdv", "tests the complete adapter (exercises data transfer, verbose)", eppmodemtest4 },
      { "ccnt", "frequency counter using the check firmware", chkcountertest },
      { "cdac", "fast DAC test using the check firmware", chkdactest },
      { "creg", "EPP register read/write test using the check firmware", chkregtest },
      { "cram", "fast RAM test using the check firmware", chkramtest },
      { "cled", "LED test using the check firmware", chkledtest },
      { "cadc", "tests the sigma delta A/D converter", chkadctest },
      { "ecpled", "tests the CON and STA leds using ECP write", ecpledtest },
      { "ecpledfast", "tests the CON and STA leds using fast ECP write", ecpledtest2 },
      { "ecpberr", "tests the complete adapter in ECP mode", ecpmodemtest1 },
      { "ecpberrv", "tests the complete adapter in ECP mode (verbose)", ecpmodemtest2 },
      { "ecpberrd", "tests the complete adapter in ECP mode (exercises data transfer)", ecpmodemtest3 },
      { "ecpberrdv", "tests the complete adapter in ECP mode (exercises data transfer, verbose)", ecpmodemtest4 },
      { "eppafskled", "tests the CON and STA leds using EPP address write", eppafskledtest },
      { "eppafskledfast", "tests the CON and STA leds using fast EPP address write", eppafskledtest2 },
      { "eppafskberr", "tests the complete adapter", eppafskmodemtest1 },
      { "eppafskberrv", "tests the complete adapter (verbose)", eppafskmodemtest2 },
      { "eppafskberrd", "tests the complete adapter (exercises data transfer)", eppafskmodemtest3 },
      { "eppafskberrdv", "tests the complete adapter (exercises data transfer, verbose)", eppafskmodemtest4 },
      { "eppafsktx0", "transmit AFSK 0 constantly", eppafskmodemtest5 },
      { "eppafsktx1", "transmit AFSK 1 constantly", eppafskmodemtest6 },
      { "sppafskled", "tests the CON and STA leds using EPP address write", sppafskledtest },
      { "sppafskledfast", "tests the CON and STA leds using fast EPP address write", sppafskledtest2 },
      { "sppafskberr", "tests the complete adapter", sppafskmodemtest1 },
      { "sppafskberrv", "tests the complete adapter (verbose)", sppafskmodemtest2 },
      { "sppafskberrd", "tests the complete adapter (exercises data transfer)", sppafskmodemtest3 },
      { "sppafskberrdv", "tests the complete adapter (exercises data transfer, verbose)", sppafskmodemtest4 },
      { "sppafsktx0", "transmit AFSK 0 constantly", sppafskmodemtest5 },
      { "sppafsktx1", "transmit AFSK 1 constantly", sppafskmodemtest6 },
      { "epprx", "decodes received packets using EPP mode", epprx },
      { "ecprx", "decodes received packets using ECP mode", ecprx },
      { "eppafskrx", "decodes received packets using EPP AFSK mode", eppafskrx },
      { "sppafskrx", "decodes received packets using SPP AFSK mode", sppafskrx },
      { "sine1k", "generate approx 1k sine using the sample IO firmware", sine1k },
#if defined(HAVE_LINUX_SOUNDCARD_H) || defined(HAVE_DIRECTX)
      { "saudio", "generate approx 1k sine using the sample IO firmware", saudio },
#endif /* HAVE_LINUX_SOUNDCARD_H */
      { NULL, NULL, NULL }
};

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

Generated by  Doxygen 1.6.0   Back to index