#include <hw/pci.h>
#include <hw/pci_devices.h>
#include <stdio.h>
#include <stdlib.h>
#include<sys/mman.h>
#include<signal.h>
#include<sys/neutrino.h>

#define MAX_BARS 6

static void Log_pci_dev_info( const struct pci_dev_info *pinfo )
{
	int	i;
	
	printf( "Dev: 0x%04x, Ven: 0x%04x, Sub: 0x%04x, SubVen: 0x%04x.\n",
		pinfo->DeviceId, pinfo->VendorId, pinfo->SubsystemId, pinfo->SubsystemVendorId );
	printf( "Bus: %hu, DevFunc: %hu, Rev: %hu, Class: 0x%x, Irq: 0x%x.\n",
		pinfo->BusNumber, pinfo->DevFunc, pinfo->Revision, pinfo->Class, pinfo->Irq );
	printf( "CpuIoTr: 0x%llx, CpuMemTr: 0x%llx, CpuBmstrTr: 0x%llx.\n",
		pinfo->CpuIoTranslation, pinfo->CpuMemTranslation, pinfo->CpuBmstrTranslation );

	for ( i = 0; i < MAX_BARS; i++ )
	{
		printf( "base %hu: Pci: 0x%llx, Cpu: 0x%llx, size: 0x%x.\n", 
			i, pinfo->PciBaseAddress[i], pinfo->CpuBaseAddress[i], pinfo->BaseAddressSize[i] );
	}
}
 
static void TestReadWrite( int ibar, void *p )
{
	uint32_t		*pdw = (uint32_t *)p;
	int i;
	char buf[32]="hellohellohello";
	printf( "r/w bar mapping %d\n", ibar );
	for(i=0;i<32;i++)
		pdw[i] = 0x00000001+i;
		

   for(i=0;i<32;i++)
	printf( "read: 0x%x\n", pdw[i] );    // gives 0xffffffff for bar 0
	//printf( "read1: 0x%x\n", *(pdw+1) );

}
uint32_t		*pdw;
const struct sigevent* intr_handler(void *arg,int id)
{
  *pdw = 0x05060708;        
}
void int_thread( void* arg );

main()
{
   int id;
   printf("rthis dfdgdsf\n");
    
id = pthread_create (NULL, NULL, int_thread, NULL);
//    pthread_join(id,NULL);
}

void int_thread( void* arg )
{
    int pidx,i;
    void* hdl,*areal;
    char *buf;
    int phdl;
    struct pci_dev_info inf;
    struct sigevent event;
    int	iret = 0,id;
    void	*base_ptr[MAX_BARS];
    printf("dgfdfgdfgdf\n");
    /* Connect to the PCI server */
    phdl = pci_attach( 0 );
    printf("phdl:%x",phdl);
    printf("HI\n");
    if( phdl == -1 ) {
       printf("PCI Attach failed\n");
        fprintf( stderr, "Unable to initialize PCI\n" );

        return EXIT_FAILURE;
    }

    printf("connected\n");
    /* Initialize the pci_dev_info structure */
    memset( &inf, 0, sizeof( inf ) );
    pidx = 0;
     inf.VendorId = 0x10ee;
    inf.DeviceId = 0x9;

    hdl = pci_attach_device( NULL, PCI_INIT_ALL, pidx, &inf );
    printf("handler:%x",hdl);
    pci_read_config32(2,0,0x04,10,&buf);
    for(i=0;i<10;i++)
    printf("cmd=%x\n",buf);
    
  //  pci_read_config(hdl,0x04,10,4,&buf);
   
    if( hdl == NULL ) {
        fprintf( stderr, "Unable to locate adapter\n" );
    } else {
        /* Do something to the adapter */
        printf("bus num %d\n",inf.BusNumber);
        printf("Irq num %d\n",inf.Irq);
        printf("Dev func %d\n",inf.DevFunc);
        	Log_pci_dev_info(&inf);
        		for ( i = 0; i < MAX_BARS; i++ )
			{
				uint64_t	baddr, baddr_mem;
				uint32_t	bsize;

				base_ptr[i] = MAP_FAILED;

				baddr = inf.CpuBaseAddress[i];
				bsize =  inf.BaseAddressSize[i];
				if ( bsize > 0 && PCI_IS_MEM( baddr ) )
				{
					baddr_mem = PCI_MEM_ADDR( baddr );
					printf( "map bar %d (baddr: %llx, baddr_mem: %llx)\n", i, baddr, baddr_mem );
					base_ptr[i] = mmap_device_memory( NULL, bsize, 
						/*PROT_NOCACHE|*/PROT_READ|PROT_WRITE | PROT_NOCACHE  , 0 , baddr_mem );

					printf( "map bar %d returns: %p\n", i, base_ptr[i] );				
				}
			}
			
#if 0
					/* try to read/write in mapped bars */
			for ( i = 0; i < MAX_BARS; i++ )
			{
				//printf("MAP_FAILED %d\n",MAP_FAILED);
				//printf("base_ptr[%d]=%d\n",i,base_ptr[i]);  
				if ( base_ptr[i] != MAP_FAILED )
				{
					TestReadWrite( i, base_ptr[i] );
				}
			}
#endif			
          pdw = base_ptr[0];
          *pdw = 0x01020304;
	//		interruptenable(void); 
           if( ThreadCtl(_NTO_TCTL_IO,0)==-1)
           {
             printf("can't get I/O permissions ");
             return -1;
           }
			id=InterruptAttach(10,intr_handler,0,0,_NTO_INTR_FLAGS_PROCESS);	
			while(1)
			{
//			    interruptwait(0,0);
			    if(InterruptWait(0,0)==-1)
			    {
			      printf("Error occured");
			      break;
			    }
			    printf("Interrupt");
			}	
			
			if(id==-1)
			{
		     	 printf("Error exit");	
		     	 exit(1);
		    }
						
			for ( i = 0; i < MAX_BARS; i++ )
			{
				if ( base_ptr[i] != MAP_FAILED )
				{
					printf( "unmap bar %d (%p)\n", i, base_ptr[i] );
					iret = munmap_device_memory( base_ptr[i], inf.BaseAddressSize[i] );
					printf( "unmap bar %d returns %d\n", i, iret );
				}
			}
			
		InterruptDetach(id);
 
                pci_detach_device( hdl );
    }

    /* Disconnect from the PCI server */
    pci_detach( phdl );
    
    return EXIT_SUCCESS;
}

