Logo Search packages:      
Sourcecode: faumachine version File versions  Download package

chip_gen_8390.c

/* $Id: chip_gen_8390.c,v 1.1 2009-01-30 10:54:02 vrsieh Exp $ 
 *
 * Copyright (C) 2007-2009 FAUmachine Team <info@faumachine.org>.
 *
 * chip_gen_8390_crc taken from the bochs project, originally licensed
 * as LGPL-2+, but we relicensed it here under GPL-2+ according to 
 * section 3 of the LGPL, version 2.
 *
 * Copyright (C) 2002 MandrakeSoft S.A.
 *
 *    MandrakeSoft S.A.
 *    43, rue d'Aboukir
 *    75002 Paris - France
 *    http://www.linux-mandrake.com/
 *    http://www.mandrakesoft.com/
 *
 * 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.
 */

#include "config.h"

#include <assert.h>
#include <stdio.h>
#include <string.h>

#include "glue-main.h"
#include "glue-shm.h"

#include "chip_gen_8390.h"

#define CHIP_(x) chip_gen_8390_ ## x
#define CHIP "chip_gen_8390"

struct cpssp {
      /*
       * Signals
       */
      unsigned int state_power;
      struct sig_isa_bus_main *port_bus;
      struct sig_isa_bus_dma *port_dma;
      struct sig_boolean_or *port_irq;
      struct sig_eth *port_eth;

      /*
       * State
       */
      uint8_t fifo[0x10000];

      uint8_t bnry;     /* Boundary */
      uint16_t clda;    /* Current Local DMA Address */
      uint8_t cntr0;    /* Tally Counter 0 (Frame Alignment Errors) */
      uint8_t cntr1;    /* Tally Counter 1 (CRC Errors) */
      uint8_t cntr2;    /* Tally Counter 2 (Missed Packet Errors) */
      uint8_t cr; /* Command */
      uint8_t cr_ps;    /* Command: Page Select */
      uint8_t curr;     /* Current Page */
      uint8_t dcr;      /* Data Configuration */
      uint8_t imr;      /* Interrupt Mask */
      uint8_t isr;      /* Interrupt Status */
      uint8_t mar[8];   /* Multicast Address */
      uint8_t ncr;      /* Number of Collisions */
      uint8_t par[6];   /* Physical Address */
      uint8_t pstart;   /* Page Start */
      uint8_t pstop;    /* Page Stop */
      uint16_t rbcr;    /* Remove Byte Count */
      uint8_t rcr;      /* Receive Configuration */
      uint16_t rsar;    /* Remote Start Address */
      uint8_t rsr;      /* Receiver Status */
      uint16_t tbcr;    /* Transmit Byte Count */
      uint8_t tcr;      /* Transmit Configuration */
      uint8_t tpsr;     /* Transmit Page Start */
      uint8_t tsr;      /* Transmit Status */
};

/* Some generic ethernet register configurations. */
#define SHORTPKT    0x02 /* Accept packets with length fewer than 64 byts */
#define BROADCAST   0x04 /* Accept broadcast packets */
#define MULTICAST   0x08 /* Accept mutlcast packets */
#define PROMISCUOUS 0x10 /* Accept all physical. that is not multi/broad cast */

/*  Register accessed at CMD, the 8390 base addr.  */
#define E8390_STOP      0x01    /* Stop and reset the chip */
#define E8390_START     0x02    /* Start the chip, clear reset */
#define E8390_TRANS     0x04    /* Transmit a frame */
#define E8390_RREAD     0x08    /* Remote read */
#define E8390_RWRITE    0x10    /* Remote write  */
#define E8390_NODMA     0x20    /* Remote DMA */

/* Bits in ISR - Interrupt status register */
#define ENISR_RX        0x01    /* Receiver, no error */
#define ENISR_TX        0x02    /* Transmitter, no error */
#define ENISR_RX_ERR    0x04    /* Receiver, with error */
#define ENISR_TX_ERR    0x08    /* Transmitter, with error */
#define ENISR_OVER      0x10    /* Receiver overwrote the ring */
#define ENISR_COUNTERS  0x20    /* Counters need emptying */
#define ENISR_RDC       0x40    /* remote dma complete */
#define ENISR_RESET     0x80    /* Reset completed */
#define ENISR_ALL       0x3f    /* Interrupts we will enable */

/* Bits in received packet status byte and RSR */
#define ENRSR_RXOK      0x01    /* Received a good packet */
#define ENRSR_CRC       0x02    /* CRC error */
#define ENRSR_FAE       0x04    /* frame alignment error */
#define ENRSR_FO        0x08    /* FIFO overrun */
#define ENRSR_MPA       0x10    /* missed pkt */
#define ENRSR_PHY       0x20    /* physical/multicast address */
#define ENRSR_DIS       0x40    /* receiver disable. set in monitor mode */
#define ENRSR_DEF       0x80    /* deferring */

/* Transmitted packet status, TSR. */
#define ENTSR_PTX 0x01  /* Packet transmitted without error */
#define ENTSR_ND  0x02  /* The transmit wasn't deferred. */
#define ENTSR_COL 0x04  /* The transmit collided at least once. */
#define ENTSR_ABT 0x08  /* The transmit collided 16 times, and was deferred. */
#define ENTSR_CRS 0x10  /* The carrier sense was lost. */
#define ENTSR_FU  0x20  /* A "FIFO underrun" occurred during transmit. */
#define ENTSR_CDH 0x40  /* The collision detect "heartbeat" signal was lost. */
#define ENTSR_OWC 0x80  /* There was an out-of-window collision. */

struct isa_ne2000_e8390_pkt_hdr {
      unsigned char  status;
      unsigned char  next;
      unsigned short count;
};

static uint8_t
CHIP_(mem_readb)(struct cpssp *cpssp, uint16_t addr)
{
      uint8_t val;

      sig_isa_bus_readb(cpssp->port_bus, cpssp, addr, &val);

      return val;
}

static void
CHIP_(mem_writeb)(struct cpssp *cpssp, uint16_t addr, uint8_t val)
{
      sig_isa_bus_writeb(cpssp->port_bus, cpssp, addr, val);
}

/*
 * The Interrupt Status Regoster (ISR) is accessed by the host processor to
 * determine the cause of an interrupt. Any interrupt can be masked in the
 * Interrupt Mask Register (IMR). Individual interrupt bits are cleared by
 * writing a ``1'' into the corresponding bit of the ISR. The INT signal is
 * active as long as any unmasked signal is set, and will not go low until all
 * unmasked bits in this register have been cleared. The ISR must be cleared
 * after power up by writing it with all 1's. So the following functions gets
 * called when IMR or ISR is touched. 
 * The IMR is used to mask interrupts. Each interrupt mask bit corresponds to a
 * bit in the Interrupt Status Register (ISR). If an interrupt mask bit is set
 * an interrupt will be issued whenever the corresponding bit in the ISR is
 * set. If any bit in the IMR is set low, an interrupt will not occur when the
 * bit in the ISR is set. The IMR powers up all zeroes.
 */
static void
CHIP_(handle_irq)(struct cpssp *cpssp)
{
      /*
       * bit 7 in ISR is mereley a status bit and *not* an interrupt
       * reaons. So even if this bit gets ONE, it won't raise an interrupt.
       * Same for the interrupt mask register: bit 7 is reserved and as such
       * has no effect.
       */
      if (cpssp->isr & 0x7F & cpssp->imr) { 
            sig_boolean_or_set(cpssp->port_irq, cpssp, 1);
      } else {
            sig_boolean_or_set(cpssp->port_irq, cpssp, 0);
      }
}

/*
 * mcast_index() - return the 6-bit index into the multicast
 * table. Stolen unashamedly from Bochs
 */
static unsigned char
CHIP_(crc)(unsigned char *dst)
{
#define POLYNOMIAL 0x04c11db6
      unsigned long crc = 0xffffffffL;
      int carry, i, j;
      unsigned char b;

      for (i = 6; --i >= 0;) {
            b = *dst++;
            for (j = 8; --j >= 0;) {
                  carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
                  crc <<= 1;
                  b >>= 1;
                  if (carry)
                        crc = ((crc ^ POLYNOMIAL) | carry);
            }
      }
      return (crc >> 26);
#undef POLYNOMIAL
}

/*
 * This function decides whatever this packet should be dropped or given to the
 * kernel. First it checks if it is a BROADCAST address and if BROADCAST
 * packets should be received. Second it checks if the packet is MULTICAST
 * packet, if MULTICAST packets should be received and if they match the hash
 * algorithm / filter. Third it checks if packet is for my MAC address. After
 * that is has a look if the PROMISCIOUS mode is enabled. This is *not& a bug!
 * If you really want to receive all packets you have to turn on BROADCAST,
 * MULTICAST, PROMISCIOUS and set the MULTICAST filter bits to all 1. See Note:
 * 8390 pdf page 25.
 */
static unsigned char
CHIP_(packet_for_me)(struct cpssp *cpssp, unsigned char *buf)
{
      static const unsigned char broadcast[6] = {
            0xff, 0xff, 0xff, 0xff, 0xff, 0xff
      };

      if (memcmp(buf, &broadcast, sizeof(broadcast)) == 0) {
            return (cpssp->rcr & BROADCAST);
      }

      if (buf[0] & 0x1) {
            if (! (cpssp->rcr & MULTICAST)) {
                  return 0;

            } else {
                  /* adapted from bochs */
                  unsigned int idx = CHIP_(crc)(buf);
                  assert(/* 0 <= (idx >> 3) && */ (idx >> 3) <= 7);
                  return (cpssp->mar[idx >> 3] & (1 << (idx & 0x7)));
            }
      }

      if (memcmp(buf, cpssp->par, 6) == 0) {
            return 1;
      }

      return (cpssp->rcr & PROMISCUOUS);

}

/*
 * This functions takes packages from the bridge and stores them in the
 * ringbuffer, if possible.
 */
static void
CHIP_(recv)(void *_cpssp, const void *_buf, unsigned int buflen)
{
      struct cpssp *cpssp = _cpssp;
      const uint8_t *buf = _buf;
      uint8_t pkt_recv[2048]; /* tmp  buffer ethernet frame 3*256 +
                                + some bytes for ne2000 headers */
      char *pkt;
      int i;
      unsigned short starting_index;

      if (! cpssp->state_power) {
            /* Power-off */
            return;
      }

      if (cpssp->cr & E8390_STOP) {
            /* Receiver disabled. */
            return;
      }

      if (buflen < 60
       && ! (cpssp->rcr & SHORTPKT)) {
            /* Short packet. */
            return;
      }

      assert(buflen <= sizeof(pkt_recv)
                  - sizeof(struct isa_ne2000_e8390_pkt_hdr));
      memcpy(pkt_recv + sizeof(struct isa_ne2000_e8390_pkt_hdr),
                  buf, buflen);

      pkt = pkt_recv + sizeof(struct isa_ne2000_e8390_pkt_hdr);
      if (! CHIP_(packet_for_me)(cpssp, pkt)) {
            /* Packet not for us. */
            return;
      }

      /* clear ne2000 header */

      pkt = (char *) pkt_recv;
      pkt[0] = 0;
      pkt[1] = 0;
      pkt[2] = 0;
      pkt[3] = 0;

      /* remember start of packet in NE2000 buffer */

      starting_index = (cpssp->curr << 8);

      /* copy incoming packet with heading header into NE2000 buffer */

      buflen += sizeof(struct isa_ne2000_e8390_pkt_hdr);
      i = buflen;
      while (0 < i) {
            unsigned short dst;
            unsigned short j;

            if (cpssp->curr == cpssp->bnry) {
                  /* FIXME: overrun */
                  fprintf(stderr, "NE2000 overrun, dropping packet\n");
                  cpssp->curr = starting_index >> 8;
                  return;
            }
            dst = (cpssp->curr << 8) & 0x7fff;
            for (j = 0; j < 256; j++) {
                  CHIP_(mem_writeb)(cpssp, dst + j, pkt[j]);
            }
            pkt += 256;
            i -= 256;
            cpssp->curr++;
            if (cpssp->curr == cpssp->pstop) {
                  cpssp->curr = cpssp->pstart;
            }
      }

      /* Status */
      CHIP_(mem_writeb)(cpssp, starting_index + 0, ENRSR_RXOK);
      /* Next Pointer */
      CHIP_(mem_writeb)(cpssp, starting_index + 1, cpssp->curr);
      /* Count */
      CHIP_(mem_writeb)(cpssp, starting_index + 2, (buflen >> 0) & 0xff);
      CHIP_(mem_writeb)(cpssp, starting_index + 3, (buflen >> 8) & 0xff);

      cpssp->isr |= ENISR_RX;
      cpssp->rsr = ENRSR_RXOK; /* no errors */

      CHIP_(handle_irq)(cpssp);
}

static void
CHIP_(send)(struct cpssp *cpssp)
{
      unsigned int i;

      if (cpssp->tbcr == 0) {
            /* Nothing to send. */
            return;
      }

      /*
       * Move bytes to FIFO.
       */
      for (i = 0; i < cpssp->tbcr; i++) {
            cpssp->fifo[i] = CHIP_(mem_readb)(cpssp,
                        (cpssp->tpsr << 8) + i);
      }

      cpssp->isr |= ENISR_TX;  /* intr reason xmit packet w.o. error */
      cpssp->tsr  = ENTSR_PTX; /* Packet transmitted without error */
      CHIP_(handle_irq)(cpssp);

      sig_eth_send(cpssp->port_eth, cpssp, cpssp->fifo, cpssp->tbcr);
}

static int
CHIP_(inb)(void *_cpssp, uint8_t *valp, uint16_t port)
{
      struct cpssp *cpssp = _cpssp;
      uint8_t value;

      switch ((cpssp->cr_ps << 8) | port) {
      case (0 << 8) | 0x00:
      case (1 << 8) | 0x00:
      case (2 << 8) | 0x00:
      case (3 << 8) | 0x00:
            /* Command Register */
            value = (cpssp->cr_ps << 6)
                  | cpssp->cr;
            break;

      /* Page 0 */
      case (0 << 8) | 0x01:
            /* Current Local DMA Address 0 */
            value = (cpssp->clda >> 0) & 0xff;
            break;
      case (0 << 8) | 0x02:
            /* Current Local DMA Address 1 */
            value = (cpssp->clda >> 8) & 0xff;
            break;
      case (0 << 8) | 0x03:
            /* Boundary Pointer */
            value = cpssp->bnry;
            break;
      case (0 << 8) | 0x04:
            /* Transmit status reg RD */
            value = cpssp->tsr;
            break;
      case (0 << 8) | 0x05:
            /* Number of Collisions */
            value = cpssp->ncr;
            break;
      case (0 << 8) | 0x06:
            /* FIFO */
            value = 0; /* FIXME */
            break;
      case (0 << 8) | 0x07:
            /* Interrupt Status Register */
            value = cpssp->isr;
            break;
      case (0 << 8) | 0x08:
            /* Current Remote DMA Address 0 */
            value = cpssp->rsar & 0xff;
            break;
      case (0 << 8) | 0x09:
            /* Current Remote DMA Address 1 */
            value = cpssp->rsar >> 8;
            break;
      case (0 << 8) | 0x0a:
            /* Reserved */
            value = 0; /* FIXME */
            break;
      case (0 << 8) | 0x0b:
            /* Reserved */
            value = 0; /* FIXME */
            break;
      case (0 << 8) | 0x0c:
            /* Receiver Status Register */
            value = cpssp->rsr;
            break;
      case (0 << 8) | 0x0d:
            /* Tally Counter 0 (Frame Alignment Errors) */
            value = cpssp->cntr0;
            cpssp->cntr0 = 0;
            break;
      case (0 << 8) | 0x0e:
            /* Tally Counter 1 (CRC Errors) */
            value = cpssp->cntr1;
            cpssp->cntr1 = 0;
            break;
      case (0 << 8) | 0x0f:
            /* Tally Counter 2 (Missed Packet Errors) */
            value = cpssp->cntr2;
            cpssp->cntr2 = 0;
            break;

      /* Page 1 */
      case (1 << 8) | 0x01:
            /* Physical Address 0 */
            value = cpssp->par[0];
            break;
      case (1 << 8) | 0x02:
            /* Physical Address 1 */
            value = cpssp->par[1];
            break;
      case (1 << 8) | 0x03:
            /* Physical Address 2 */
            value = cpssp->par[2];
            break;
      case (1 << 8) | 0x04:
            /* Physical Address 3 */
            value = cpssp->par[3];
            break;
      case (1 << 8) | 0x05:
            /* Physical Address 4 */
            value = cpssp->par[4];
            break;
      case (1 << 8) | 0x06:
            /* Physical Address 5 */
            value = cpssp->par[5];
            break;
      case (1 << 8) | 0x07:
            /* Current Page Register */
            value = cpssp->curr;
            break;
      case (1 << 8) | 0x08:
            /* Multicast Address 0 */
            value = cpssp->mar[0];
            break;
      case (1 << 8) | 0x09:
            /* Multicast Address 1 */
            value = cpssp->mar[1];
            break;
      case (1 << 8) | 0x0a:
            /* Multicast Address 2 */
            value = cpssp->mar[2];
            break;
      case (1 << 8) | 0x0b:
            /* Multicast Address 3 */
            value = cpssp->mar[3];
            break;
      case (1 << 8) | 0x0c:
            /* Multicast Address 4 */
            value = cpssp->mar[4];
            break;
      case (1 << 8) | 0x0d:
            /* Multicast Address 5 */
            value = cpssp->mar[5];
            break;
      case (1 << 8) | 0x0e:
            /* Multicast Address 6 */
            value = cpssp->mar[6];
            break;
      case (1 << 8) | 0x0f:
            /* Multicast Address 7 */
            value = cpssp->mar[7];
            break;

      /* Page 2 */
      case (2 << 8) | 0x01:
            /* Page Start Register */
            value = cpssp->pstart;
            break;
      case (2 << 8) | 0x02:
            /* Page Stop Register */
            value = cpssp->pstop;
            break;
      case (2 << 8) | 0x03:
            /* Remote Next Packet Pointer */
            value = 0; /* FIXME */
            break;
      case (2 << 8) | 0x04:
            /* Transmit Page Start Address */
            value = cpssp->tpsr;
            break;
      case (2 << 8) | 0x05:
            /* Local Next Packet Pointer */
            value = 0; /* FIXME */
            break;
      case (2 << 8) | 0x06:
            /* Address Counter (Upper) */
            value = 0; /* FIXME */
            break;
      case (2 << 8) | 0x07:
            /* Address Counter (Lower) */
            value = 0; /* FIXME */
            break;
      case (2 << 8) | 0x08:
      case (2 << 8) | 0x09:
      case (2 << 8) | 0x0a:
      case (2 << 8) | 0x0b:
            /* Reserved */
            value = 0; /* FIXME */
            break;
      case (2 << 8) | 0x0c:
            /* Receive Configuration */
            value = cpssp->rcr;
            break;
      case (2 << 8) | 0x0d:
            /* Transmit Configuration */
            value = cpssp->tcr;
            break;
      case (2 << 8) | 0x0e:
            /* Data Configuration */
            value = cpssp->dcr;
            break;
      case (2 << 8) | 0x0f:
            /* Interrupt Mask */
            value = cpssp->imr;
            break;

      /* Page 3 */
      case (3 << 8) | 0x01:
      case (3 << 8) | 0x02:
      case (3 << 8) | 0x03:
      case (3 << 8) | 0x04:
      case (3 << 8) | 0x05:
      case (3 << 8) | 0x06:
      case (3 << 8) | 0x07:
      case (3 << 8) | 0x08:
      case (3 << 8) | 0x09:
      case (3 << 8) | 0x0a:
      case (3 << 8) | 0x0b:
      case (3 << 8) | 0x0c:
      case (3 << 8) | 0x0d:
      case (3 << 8) | 0x0e:
      case (3 << 8) | 0x0f:
            value = 0; /* FIXME */
            break;

      default:
            assert(0); /* Cannot happen. */
      }

      *valp = value;
      return 0;
}

static int
CHIP_(outb)(void *_cpssp, uint8_t value, uint16_t port)
{
      struct cpssp *cpssp = _cpssp;

      switch ((cpssp->cr_ps << 8) | port) {
      case (0 << 8) | 0x00:
      case (1 << 8) | 0x00:
      case (2 << 8) | 0x00:
      case (3 << 8) | 0x00:
            /* Command Register */
            cpssp->cr = value & 0x3f;
            cpssp->cr_ps = (value >> 6) & 0x3;

            if (value & E8390_STOP) {
                  cpssp->isr |= ENISR_RESET;
                  cpssp->rsr = 0;

            } else if (value & E8390_START) {
                  cpssp->isr &= ~ENISR_RESET;
                  if (value & E8390_RREAD) {
                        if (! cpssp->rbcr) {
                              cpssp->isr |= ENISR_RDC;
                              CHIP_(handle_irq)(cpssp);
                        }
                  }
                  if (value & E8390_TRANS) {
                        CHIP_(send)(cpssp);
                  }
            }
            break;

      /* Page 0 */
      case (0 << 8) | 0x01:
            /* Page Start Register */
            cpssp->pstart = value;
            break;
      case (0 << 8) | 0x02:
            /* Page Stop Register */
            cpssp->pstop = value;
            break;
      case (0 << 8) | 0x03:
            /* Boundary Register */
            cpssp->bnry = value;
            break;
      case (0 << 8) | 0x04:
            /* Transmit Page Start Address */
            cpssp->tpsr = value;
            break;
      case (0 << 8) | 0x05:
            /* Transmit Byte Count 0 */
            cpssp->tbcr = (cpssp->tbcr & 0xff00) | value;
            break;
      case (0 << 8) | 0x06:
            /* Transmit Byte Count 1 */
            cpssp->tbcr = (value << 8) | (cpssp->tbcr & 0xff);
            break;
      case (0 << 8) | 0x07:
            /* Interrupt Status Register */
            cpssp->isr &= ~(value & 0x7F); /* Don't clr RST that way */
            CHIP_(handle_irq)(cpssp);
            break;
      case (0 << 8) | 0x08:
            /* Remote Start Address Register 0 */
            cpssp->rsar = (cpssp->rsar & 0xff00) | value;
            break;
      case (0 << 8) | 0x09:
            /* Remote Start Address Register 1 */
            cpssp->rsar = (value << 8) | (cpssp->rsar & 0xff);
            break;
      case (0 << 8) | 0x0a:
            /* Remote Byte Count Register 0 */
            cpssp->rbcr = (cpssp->rbcr & 0xff00) | value;
            break;
      case (0 << 8) | 0x0b:
            /* Remote Byte Count Register 1 */
            cpssp->rbcr = (value << 8) | (cpssp->rbcr & 0xff);
            break;
      case (0 << 8) | 0x0c:
            /* Receive Configuration Register */
            cpssp->rcr = value;
            break;
      case (0 << 8) | 0x0d:
            /* Transmit Configuration Register */
            cpssp->tcr = value;
            break;
      case (0 << 8) | 0x0e:
            /* Data Configuration Register */
            cpssp->dcr = value;
            break;
      case (0 << 8) | 0x0f:
            /* Interrupt Mask Register */
            /* Bit 7 is reserved and has absolut no effect. */
            cpssp->imr = value & 0x7f;
            CHIP_(handle_irq)(cpssp);
            break;

      /* Page 1 */
      case (1 << 8) | 0x01:
            /* Physical Address Register 0 */
            cpssp->par[0] = value;
            break;
      case (1 << 8) | 0x02:
            /* Physical Address Register 1 */
            cpssp->par[1] = value;
            break;
      case (1 << 8) | 0x03:
            /* Physical Address Register 2 */
            cpssp->par[2] = value;
            break;
      case (1 << 8) | 0x04:
            /* Physical Address Register 3 */
            cpssp->par[3] = value;
            break;
      case (1 << 8) | 0x05:
            /* Physical Address Register 4 */
            cpssp->par[4] = value;
            break;
      case (1 << 8) | 0x06:
            /* Physical Address Register 5 */
            cpssp->par[5] = value;
            break;
      case (1 << 8) | 0x07:
            /* Current Page Register */
            cpssp->curr = value;
            break;
      case (1 << 8) | 0x08:
            /* Multicast Address Register 0 */
            cpssp->mar[0] = value;
            break;
      case (1 << 8) | 0x09:
            /* Multicast Address Register 1 */
            cpssp->mar[1] = value;
            break;
      case (1 << 8) | 0x0a:
            /* Multicast Address Register 2 */
            cpssp->mar[2] = value;
            break;
      case (1 << 8) | 0x0b:
            /* Multicast Address Register 3 */
            cpssp->mar[3] = value;
            break;
      case (1 << 8) | 0x0c:
            /* Multicast Address Register 4 */
            cpssp->mar[4] = value;
            break;
      case (1 << 8) | 0x0d:
            /* Multicast Address Register 5 */
            cpssp->mar[5] = value;
            break;
      case (1 << 8) | 0x0e:
            /* Multicast Address Register 6 */
            cpssp->mar[6] = value;
            break;
      case (1 << 8) | 0x0f:
            /* Multicast Address Register 7 */
            cpssp->mar[7] = value;
            break;

      /* Page 2 */
      case (2 << 8) | 0x01:
            /* Current Local DMA Address */
            cpssp->clda &= 0xff00;
            cpssp->clda |= value << 0;
            break;
      case (2 << 8) | 0x02:
            /* Current Local DMA Address */
            cpssp->clda &= 0x00ff;
            cpssp->clda |= value << 8;
            break;
      case (2 << 8) | 0x03:
            /* Remote Next Packet Pointer */
            /* FIXME */
            break;
      case (2 << 8) | 0x04:
            /* Reserved */
            /* FIXME */
            break;
      case (2 << 8) | 0x05:
            /* Local Next Packet Pointer */
            /* FIXME */
            break;
      case (2 << 8) | 0x06:
            /* Address Counter (Upper) */
            /* FIXME */
            break;
      case (2 << 8) | 0x07:
            /* Address Counter (Lower) */
            /* FIXME */
            break;
      case (2 << 8) | 0x08:
      case (2 << 8) | 0x09:
      case (2 << 8) | 0x0a:
      case (2 << 8) | 0x0b:
      case (2 << 8) | 0x0c:
      case (2 << 8) | 0x0d:
      case (2 << 8) | 0x0e:
      case (2 << 8) | 0x0f:
            /* Reserved */
            /* FIXME */
            break;

      /* Page 3 */
      case (3 << 8) | 0x01:
      case (3 << 8) | 0x02:
      case (3 << 8) | 0x03:
      case (3 << 8) | 0x04:
      case (3 << 8) | 0x05:
      case (3 << 8) | 0x06:
      case (3 << 8) | 0x07:
      case (3 << 8) | 0x08:
      case (3 << 8) | 0x09:
      case (3 << 8) | 0x0a:
      case (3 << 8) | 0x0b:
      case (3 << 8) | 0x0c:
      case (3 << 8) | 0x0d:
      case (3 << 8) | 0x0e:
      case (3 << 8) | 0x0f:
            /* Reserved */
            /* FIXME */
            break;

      default:
            assert(0); /* Cannot happen. */
      }

      return 0;
}

static int
CHIP_(ack_outb)(void *_cpssp, unsigned int tc, uint8_t value)
{
      struct cpssp *cpssp = _cpssp;

      if (cpssp->rbcr == 0) {
            fprintf(stderr, "write access to NE2000 buffer, but not in DMA mode\n");
            return -1;
      }

      CHIP_(mem_writeb)(cpssp, cpssp->rsar, value);

      cpssp->rsar++;
      if (cpssp->rsar == (cpssp->pstop << 8)) {
            cpssp->rsar = cpssp->pstart << 8;
      }
      cpssp->rbcr--;

      if (! cpssp->rbcr) { 
            /* FIXME check for interrupt or kick all RDC intr */
            cpssp->isr |= ENISR_RDC; /* remote dma complete */
            CHIP_(handle_irq)(cpssp);
      }

      return 0;
}

static int
CHIP_(ack_inb)(void *_cpssp, unsigned int tc, uint8_t *valp)
{
      struct cpssp *cpssp = _cpssp;

      if (cpssp->rbcr == 0) {
            fprintf(stderr, "read access to NE2000 buffer, but not in DMA mode\n");
            return 0xff;
      }

      *valp = CHIP_(mem_readb)(cpssp, cpssp->rsar);

      cpssp->rsar++;
      if (cpssp->rsar == cpssp->pstop << 8) {
            cpssp->rsar = cpssp->pstart << 8;
      }
      cpssp->rbcr--;

      if (cpssp->rbcr == 0) {
            cpssp->isr |= ENISR_RDC;
            CHIP_(handle_irq)(cpssp);
      }

      return 0;
}

static void
CHIP_(power_set)(void *_cpssp, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;

      cpssp->state_power = val;

      if (val) {
            /* Power On Event */
            /* Nothing to do (yet). */

      } else {
            /* Power Off Event */
            /* Nothing to do (yet). */
      }
}

static void
CHIP_(reset_set)(void *_cpssp, unsigned int val)
{
      struct cpssp *cpssp = _cpssp;

      if (! val) {
            cpssp->isr |= ENISR_RESET;
      }
}

void
CHIP_(init)(
      unsigned int nr,
      struct sig_boolean *port_power,
      struct sig_boolean *port_reset_hash_,
      struct sig_isa_bus_main *port_bus,
      struct sig_isa_bus_dma *port_dma,
      struct sig_boolean_or *port_irq,
      struct sig_eth *port_eth
)
{
      static const struct sig_boolean_funcs power_funcs = {
            .set = CHIP_(power_set),
      };
      static const struct sig_boolean_funcs reset_funcs = {
            .set = CHIP_(reset_set),
      };
      static const struct sig_isa_bus_main_funcs bus_funcs = {
            .inb = CHIP_(inb),
            .outb = CHIP_(outb),
      };
      static const struct sig_isa_bus_dma_funcs dma_funcs = {
            .ack_inb = CHIP_(ack_inb),
            .ack_outb = CHIP_(ack_outb),
      };
      static const struct sig_eth_funcs eth_funcs = {
            .recv = CHIP_(recv),
      };
      struct cpssp *cpssp;

      cpssp = shm_map(CHIP, nr, sizeof(*cpssp), 0);

      /* Call */
      cpssp->port_bus = port_bus;
      sig_isa_bus_main_connect(port_bus, cpssp, &bus_funcs);
      sig_isa_bus_dma_connect(port_dma, cpssp, &dma_funcs);
      cpssp->port_eth = port_eth;
      sig_eth_connect(cpssp->port_eth, cpssp, &eth_funcs);

      /* Out */
      cpssp->port_irq = port_irq;
      sig_boolean_or_connect_out(cpssp->port_irq, cpssp, 0);

      /* In */
      sig_boolean_connect_in(port_power, cpssp, &power_funcs);
      sig_boolean_connect_in(port_reset_hash_, cpssp, &reset_funcs);
}

unsigned int
CHIP_(create)(void)
{
      static unsigned int nr = 0;
      struct cpssp *cpssp;

      shm_create(CHIP, nr, sizeof(*cpssp));
      cpssp = shm_map(CHIP, nr, sizeof(*cpssp), 0);

      shm_unmap(cpssp, sizeof(*cpssp));

      return nr++;
}

void
CHIP_(destroy)(unsigned int nr)
{
      struct cpssp *cpssp;

      cpssp = shm_map(CHIP, nr, sizeof(*cpssp), 0);

      shm_unmap(cpssp, sizeof(*cpssp));
      shm_destroy(CHIP, nr);
}

Generated by  Doxygen 1.6.0   Back to index