/*
 *	Winhal PCImethod via HAL (in driver ctpci) for lspi  
 *
 *	Copyright (c) c't 2010 Andreas Stiller 
 *
 *	Can be freely distributed and used under the terms of the GNU GPL.
 */



#include "internal.h"
#include "contact_ctpci.h" 


static int winhal_detect(struct pci_access *a UNUSED)
{
	return init_directnt();
}

static void winhal_init(struct pci_access *a UNUSED)
{
}

static void winhal_cleanup(struct pci_access *a UNUSED)
{
	cleanup_directnt();
}

static int winhal_read(struct pci_dev *d, int pos, byte *buf, int len)
{
   u32 value;
   u32 res;
   u32 bdf;
   u32 BytesReturned;
   

   bdf=((d->bus & 0xff) << 8) | (PCI_DEVFN(d->dev, d->func)); 
   
  
   res=drvexec (OP_ReadPCIDword,pos,bdf,0,&value,4,&BytesReturned);
   if (res || (BytesReturned==0)) 
   {
	   if ((res== STATUS_NO_DEVICE) || (res==STATUS_NO_BUS)) value=0xFFFFFFFF; 
	   else {
		   cleanup_directnt(); 
		   printf (" error reading from PCI, program break\n");
		   exit(1); 
		   //return 0;
	   }

   }
   //printf ("%4x: %8x ",pos,value);
  value=value >> ((pos & 3)*8);
  switch (len)
    {
    case 1:
      buf[0] = (byte) value & 0xff ;
      break;
    case 2:
      ((u16 *) buf)[0] = (u16) value & 0xffff;
      break;
    case 4:
      ((u32 *) buf)[0] = value;
      break;
    default:
      return pci_generic_block_read(d, pos, buf, len);
    }
   //if (d->dev=16) printf ("w %d %x %d: %d => %8.8x   %d \n",d->bus,d->dev,d->func,pos,value,len); 

  return 1;
}


static int winhal_write(struct pci_dev *d, int pos, byte *buf, int len)
{
#pragma pack(1) // just in case 
	union {
		u32 aslong;
		u16 asword[2];
		 u8 asbyte[4];
	} value;
#pragma pack ()
   u32 res;
   u32 bdf;
   u32 BytesReturned;
 

   bdf=((d->bus & 0xff) << 8) | (PCI_DEVFN(d->dev, d->func)); 
  
  switch (len)
    { 
    case 1:
         res=drvexec (OP_ReadPCIDword,pos,bdf,0,&value,4,&BytesReturned);
		 if (res !=0) return 0;
    	 value.asbyte[pos & 3]=buf[0];
		 res=drvexec (OP_ReadPCIDword,pos,bdf,value.aslong,0,0,&BytesReturned);
         if (res !=0) return 0;
		 return 1;          
      break;
    case 2:
         res=drvexec (OP_ReadPCIDword,pos,bdf,0,&value,4,&BytesReturned);
		 if (res !=0) return 0;
		 value.asword[(pos >>1) & 1]=((u16 *)buf)[0]; 
         res=drvexec (OP_ReadPCIDword,pos&0xfc,bdf,value.aslong,0,0,&BytesReturned);
         if (res !=0) return 0;
		 return 1;               
      break;
    case 4:
		  value.aslong=((u32 *) buf)[0];  
          drvexec (OP_WritePCIDword,pos,bdf,value.aslong,0,0,&BytesReturned);
      break;
    default:
      return pci_generic_block_write(d, pos, buf, len);
    }

  return 1;
}


struct pci_methods pm_winhal = {
  "Win_HAL",
  "Access via HAL-Functions via ctpci.sys",
  NULL,					/* config */
  winhal_detect,
  winhal_init,
  winhal_cleanup,
  pci_generic_scan,     /* scan all buses*/
  pci_generic_fill_info,/* fill info*/
  winhal_read,          /* read  */
  winhal_write,         /* write */  
  NULL,					/* init_dev */
  NULL					/* cleanup_dev */
};