////////////////////////////////////////////////////////////////
// File - INT_IO.C
//
// This is a skeleton driver for an ISA card. The driver implemets
// IO port access and interrupt handler installtion.
// 
////////////////////////////////////////////////////////////////

#include <windows.h>
#include <winioctl.h>
#include "../../include/windrvr.h"
#include <stdio.h>

// put your IO range here (this example 0x378-0x37a)
enum {MY_IO_BASE = 0x378};
enum {MY_IO_SIZE = 0x3};
// put your IRQ number to install here (this example IRQ 5)
enum {MY_IRQ = 5};

// global WinDriver handle
HANDLE hWD;

// interrupt structure
WD_INTERRUPT Intrp;

// this is equal to assember "inp" command
BYTE IO_ReadByte(DWORD dwIOAddr)
{
    WD_TRANSFER trns;
    trns.cmdTrans = RP_BYTE; // R-Read P-Port BYTE
    trns.dwPort = dwIOAddr;
    WD_Transfer( hWD, &trns); // Perform read
    return trns.Data.Byte;
}

// this is equal to assember "outp" command
void IO_WriteByte(DWORD dwIOAddr, BYTE bData)
{
    WD_TRANSFER trns;
    trns.cmdTrans = WP_BYTE; // R-Write P-Port BYTE
    trns.dwPort = dwIOAddr;
    trns.Data.Byte = bData;
    WD_Transfer( hWD, &trns); // Perform write
}

void IO_ReadByteString(DWORD dwIOAddr, PBYTE pBuf, DWORD dwBytes)
{
    WD_TRANSFER trns;
    trns.cmdTrans = RP_SBYTE; // R-Read, P-Port, S-String BYTE
    trns.dwPort = dwIOAddr;
    trns.dwBytes = dwBytes;
    trns.fAutoinc = FALSE;
    trns.dwOptions = 0;
    trns.Data.pBuffer = pBuf;
    WD_Transfer( hWD, &trns); // Perform read
}

void IO_WriteByteString(DWORD dwIOAddr, PBYTE pBuf, DWORD dwBytes)
{
    WD_TRANSFER trns;
    trns.cmdTrans = WP_SBYTE; // W-Write, P-Port, S-String BYTE
    trns.dwPort = dwIOAddr;
    trns.dwBytes = dwBytes;
    trns.fAutoinc = FALSE;
    trns.dwOptions = 0;
    trns.Data.pBuffer = pBuf;
    WD_Transfer( hWD, &trns); // Perform write
}

DWORD WINAPI wait_interrupt (PVOID pData)
{
  printf ("Waiting for interrupt");
  for (;;)
  {
    WD_IntWait (hWD, &Intrp);
    if (Intrp.fStopped)
      break;
    else
    {
      // do your interrupt routine here 
      printf ("Got interrupt %d\n", Intrp.dwCounter);
    }
  }
  return 0;
}

int main()
{
    WD_CARD_REGISTER cardReg;
    WD_VERSION verBuf;

    hWD = WD_Open();
    if (hWD==INVALID_HANDLE_VALUE)
    {
        printf ("error opening WINDRVR\n");
        return 0;
    }

    WD_Version (hWD, &verBuf);
    printf ("WinDriver version - %s\n", verBuf.cVer);
    if (verBuf.dwVer<WD_VER)
    {
        printf ("error incorrect WINDRVR version. needs ver %d\n",WD_VER);
        return 0;
    }

    cardReg.Card.dwItems = 2;
    cardReg.Card.Item[0].item = ITEM_INTERRUPT;
    cardReg.Card.Item[0].fNotSharable = TRUE;
    cardReg.Card.Item[0].I.Int.dwInterrupt = MY_IRQ;
    cardReg.Card.Item[0].I.Int.dwOptions = 0;
    cardReg.Card.Item[1].item = ITEM_IO;
    cardReg.Card.Item[1].fNotSharable = TRUE;
    cardReg.Card.Item[1].I.IO.dwAddr = MY_IO_BASE;
    cardReg.Card.Item[1].I.IO.dwBytes = MY_IO_SIZE;
    cardReg.fCheckLockOnly = FALSE;
    WD_CardRegister (hWD, &cardReg);
    if (cardReg.hCard==0)
      printf ("could not lock device - already in use");
    else
    {
        HANDLE thread_handle;
        DWORD thread_id;
    
        Intrp.hInterrupt = cardReg.Card.Item[0].I.Int.hInterrupt;
        Intrp.Cmd = NULL;
        Intrp.dwCmds = 0;
        Intrp.dwOptions = 0;
        WD_IntEnable(hWD, &Intrp);
    
        printf ("starting interrupt thread\n");
        thread_handle = CreateThread (0, 0x1000, 
            wait_interrupt, NULL, 0, &thread_id);
    
        // call your driver code here 
    
        WD_IntDisable (hWD, &Intrp);    
        WD_CardUnregister(hWD, &cardReg);
    }

    WD_Close(hWD);
    return 0;
}