Newer
Older
Scratch / lockwasher / src / sys / pci / lnc.c
#include <pci/lnc.h>
#include <sys/io.h>
#include <ubixos/types.h>
#include <sys/idt.h>
#include <sys/gdt.h>
#include <lib/kmalloc.h>
#include <sys/video.h>
#include <isa/8259.h>

struct lncInfo *lnc = 0x0;

static char const * const nicIdent[] = {
  "Unknown",
  "BICC",
  "NE2100",
  "DEPCA",
  "CNET98S",      /* PC-98 */
  };

static char const * const icIdent[] = {
  "Unknown",
  "LANCE",
  "C-LANCE",
  "PCnet-ISA",
  "PCnet-ISA+",
  "PCnet-ISA II",
  "PCnet-32 VL-Bus",
  "PCnet-PCI",
  "PCnet-PCI II",
  "PCnet-FAST",
  "PCnet-FAST+",
  "PCnet-Home",
  };  

void writeCsr(struct lncInfo *lnc, uInt16 port, uInt16 val) {
  outportWord(lnc->rap, port);
  outportWord(lnc->rdp, val);
  }

uInt16 readCsr(struct lncInfo *lnc, uInt16 port) {
  outportWord(lnc->rap, port);
  return(inportWord(lnc->rdp));
  }

void writeBcr(struct lncInfo *lnc, uInt16 port, uInt16 val) {
  outportWord(lnc->rap, port);
  outportWord(lnc->bdp, val);
  }

uInt16 readBcr(struct lncInfo *sc, uInt16 port) {
  outportWord(sc->rap, port);
  return (inportWord(sc->bdp));
  }


void initLNC() {
  int            i    = 0x0;
  lnc = kmalloc(sizeof(struct lncInfo),-2);
  
  lnc->rap = 0x1000 + PCNET_RAP;
  lnc->rdp = 0x1000 + PCNET_RDP;
  lnc->bdp = 0x1000 + PCNET_BDP;

  lnc->nic.ic = probe(lnc);
  if ((lnc->nic.ic > 0) && (lnc->nic.ic >= PCnet_32)) {
    lnc->nic.ident = NE2100;
    lnc->nic.memMode = DMA_FIXED;

    lnc->nrdre = NRDRE;
    lnc->ntdre = NTDRE;

    /* Extract MAC address from PROM */
    for (i = 0; i < ETHER_ADDR_LEN; i++) {
      lnc->arpcom.ac_enaddr[i] = inportByte(0x1000 + i);
      kprintf("[0x%X]",lnc->arpcom.ac_enaddr[i]);
      }
    }
  else {
    kprintf("LNC Init Error\n");
    return;
    }
  lncAttach(lnc,0);
  writeCsr(lnc, CSR3, 0);
  writeCsr(lnc, CSR0, INIT);
  for (i = 0; i < 1000; i++)
    if (readCsr(lnc, CSR0) & IDON)
      break;

  if (readCsr(lnc, CSR0) & IDON) {
    writeCsr(lnc, CSR0, STRT | INEA);
    setVector(_lncInt,mVec+9, (dInt + dPresent + dDpl3));
    enableIrq(9);
    //sc->arpcom.ac_if.if_flags |= IFF_RUNNING;
    //sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
    //lnc_start(&sc->arpcom.ac_if);
    }
  else {
    kprintf("LNC init Error\n");
    return;
    }
  return;
  }

int probe(struct lncInfo *lnc) {
  uInt32 chipId = 0x0;
  int    type   = 0x0;

  if ((type = lanceProbe(lnc))) {
    chipId = readCsr(lnc, CSR89);
    chipId <<= 16;
    chipId |= readCsr(lnc, CSR88);
    if (chipId & AMD_MASK) {
      chipId >>= 12;
      switch (chipId & PART_MASK) {
        case Am79C960:
          return(PCnet_ISA);
        case Am79C961:
          return (PCnet_ISAplus);
        case Am79C961A:
          return (PCnet_ISA_II);
        case Am79C965:
          return (PCnet_32);
        case Am79C970:
          return (PCnet_PCI);
        case Am79C970A:
          return (PCnet_PCI_II);
        case Am79C971:
          return (PCnet_FAST);
        case Am79C972:
        case Am79C973:
          return (PCnet_FASTplus);
        case Am79C978:
          return (PCnet_Home);
        default:
          break;
        }
      }
    }
  return (type);
  }

int lanceProbe(struct lncInfo *lnc) {
  writeCsr(lnc, CSR0, STOP);
  if ((inportWord(lnc->rdp) & STOP) && !(readCsr(lnc, CSR3))) {
    writeCsr(lnc, CSR0, INEA);
    if (readCsr(lnc, CSR0) & INEA) {
      return(C_LANCE);
      }
    else {
      return(LANCE);
      }
    }
  else {
    return(UNKNOWN);
    }
  }

void lncInt() {
  uInt16 csr0 = 0x0;
  while ((csr0 = inportWord(lnc->rdp)) & INTR) {
    outportWord(lnc->rdp, csr0);
    kprintf("CSR0: [0x%X]\n",csr0);
    if (csr0 & ERR) {
      kprintf("Error: [0x%X]\n",csr0);
      }
    if (csr0 & RINT) {
      kprintf("RINT\n");
      }
    if (csr0 & TINT) {
      kprintf("TINT\n");
      }
    }
  kprintf("Finished!!!\n");
  outportByte(0x20,0x20);
  return;
  }

asm(
    ".global _lncInt     \n"
    "_lncInt   :         \n"

  "  pusha                \n" /* Save all registers           */
  "  pushw %ds            \n" /* Set up the data segment      */
  "  pushw %es            \n"
  "  pushw %ss            \n" /* Note that ss is always valid */
  "  pushw %ss            \n"
  "  popw %ds             \n"
  "  popw %es             \n"
  "  call lncInt \n"
  "  popw %es             \n"
  "  popw %ds             \n" /* Restore registers            */
  "  popa                 \n"
  "  iret                 \n" /* Exit interrupt               */    
    );

int lncAttach(struct lncInfo *lnc,int unit) {
  int lncMemSize = 0x0;

  lncMemSize = ((NDESC(lnc->nrdre) + NDESC(lnc->ntdre)) * sizeof(struct hostRingEntry));

  if (lnc->nic.memMode != SHMEM)
    lncMemSize += sizeof(struct initBlock) + (sizeof(struct mds) * (NDESC(lnc->nrdre) + NDESC(lnc->ntdre))) + MEM_SLEW;

  if (lnc->nic.memMode == DMA_FIXED)
    lncMemSize += (NDESC(lnc->nrdre) * RECVBUFSIZE) + (NDESC(lnc->ntdre) * TRANSBUFSIZE);

  if (lnc->nic.memMode != SHMEM) {
    if (lnc->nic.ic < PCnet_32) {
      /* ISA based cards */
      kprintf("ISA Board\n");
      //sc->recv_ring = contigmalloc(lnc_mem_size, M_DEVBUF, M_NOWAIT,0ul, 0xfffffful, 4ul, 0x1000000);
      }
    else {
      /*
      * For now it still needs to be below 16MB because the
      * descriptor's can only hold 16 bit addresses.
      */
      //sc->recv_ring = contigmalloc(lnc_mem_size, M_DEVBUF, M_NOWAIT,0ul, 0xfffffful, 4ul, 0x1000000);
      lnc->recvRing = kmalloc(lncMemSize,-2);
      kprintf("PCI Board\n");
      }      
    }

  if (!lnc->recvRing) {
    kprintf("lnc%d: Couldn't allocate memory for NIC\n", unit);
    return (0);
    }

  lnc->nic.mode = NORMAL;

  /* Fill in arpcom structure entries */
  /*
  lnc->arpcom.ac_if.if_softc = sc;
  lnc->arpcom.ac_if.if_name = lncdriver.name;
  lnc->arpcom.ac_if.if_unit = unit;
  lnc->arpcom.ac_if.if_mtu = ETHERMTU;
  lnc->arpcom.ac_if.if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
  lnc->arpcom.ac_if.if_timer = 0;
  lnc->arpcom.ac_if.if_output = ether_output;
  lnc->arpcom.ac_if.if_start = lnc_start;
  lnc->arpcom.ac_if.if_ioctl = lnc_ioctl;
  lnc->arpcom.ac_if.if_watchdog = lnc_watchdog;
  lnc->arpcom.ac_if.if_init = lnc_init;
  lnc->arpcom.ac_if.if_type = IFT_ETHER;
  lnc->arpcom.ac_if.if_addrlen = ETHER_ADDR_LEN;
  lnc->arpcom.ac_if.if_hdrlen = ETHER_HDR_LEN;
  lnc->arpcom.ac_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
  */
  //ether_ifattach(&sc->arpcom.ac_if, ETHER_BPF_SUPPORTED);

  kprintf("lnc%d: ", unit);
  if (lnc->nic.ic == LANCE || lnc->nic.ic == C_LANCE)
    kprintf("%s (%s)",nicIdent[lnc->nic.ident], icIdent[lnc->nic.ic]);
  else
    kprintf("%s", icIdent[lnc->nic.ic]);
  kprintf(" address 0x%X\n", lnc->arpcom.ac_enaddr);   
  return(1);
  }