
const struct sigevent *irq_handler(void *arg, int id)
{
	printf("\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n");
    printf("\nDEV_MIL_DRV_UDx: irq_handler(): begin.\n");
    fflush(stdout);

	uint32_t ri, mi, mci, rci;
    DEVICE_MIL *dm;
    int eu = 0;
    dm = (DEVICE_MIL *)arg;

    struct sigevent event;
    int i = 0,err = 0;

    //максируем прерывание
    InterruptMask(dm->irq_num,id);
	
	////////////////////////////////////
	!!!code!!!
	/////////////////////////////////////
	
	InterruptUnmask(dm->irq_num,id);
    return 0;
	
}

static __inline__ int pci_detect_card(void)
{	unsigned int minor = 0, devfunc, bus;
	int status;
	int i;

	uint32_t addr_dma_lo, addr_dma_hi;

	// создаем поток для драйвера(должны быть root права)
	ThreadCtl( _NTO_TCTL_IO, 0 );

	printf("\nDEV_MIL_DRV_UDx: try attach to pci-server..");

	// подключение к pci серверу
	pci_hndl = pci_attach(0);

	if (pci_hndl == -1)	{
		printf("\nDEV_MIL_DRV_UDx: error unable to attach pci");
		perror("\npci_attach:");
		printf("\nDEV_MIL_DRV_UDx: DEVICE DON'T CREATE");
		return - 1;
	}

	printf("\nDEV_MIL_DRV_UDx: pci_attach good");

	plata_cnt = 0;

	do{
		// проверяем, что слишком много устройств найдено
		if(plata_cnt >= MINOR_CNT){
			printf("\nDEV_MIL_DRV_UDx: find MAX device(%d) -> exit find device",MINOR_CNT);
			return 0;
		}
		//заполняем структуру для поиска
		memset( &device_mil[minor].pci_info, 0, sizeof( device_mil[minor].pci_info ) );
		device_mil[minor].pci_info.VendorId = VENDOR_ID;
		device_mil[minor].pci_info.DeviceId = DEVICE_ID_UDx;

		// начинаем поиск устройства на шине pci
		status=pci_find_device(device_mil[minor].pci_info.DeviceId,device_mil[minor].pci_info.VendorId,minor,&bus,&devfunc );
		if (status!=PCI_SUCCESS){
			device_mil[minor].pci_info.DeviceId = DEVICE_ID_mPCIe;
			status=pci_find_device(device_mil[minor].pci_info.DeviceId,device_mil[minor].pci_info.VendorId,minor,&bus,&devfunc );
			if (status!=PCI_SUCCESS){
				if(minor == 0) // если нет ни одного устройства на шине
				{	printf("\nDEV_MIL_DRV_UDx: don't find device");
					goto err1;
				}
				else{
					printf("\nDEV_MIL_DRV_UDx: find %d device",plata_cnt);
					return 0;
				}
			}
		}

		// запоминаем индекс устройства
		device_mil[minor].minor = minor;
		plata_cnt++; // увеличиваем общее количество устройств

		printf("\nDEV_MIL_DRV_UDx: pci_find_device good");
		printf("\nDEV_MIL_DRV_UDx: Find device(Vendor_ID = %x, Device_ID = %x, Minor = %d)",device_mil[minor].pci_info.DeviceId,device_mil[minor].pci_info.VendorId, minor);
		device_mil[minor].vendor_id = device_mil[minor].pci_info.VendorId;
		device_mil[minor].device_id = device_mil[minor].pci_info.DeviceId;

		// подключение к pci устройству
		device_mil[minor].pci_dev_hndl = pci_attach_device(NULL,( PCI_SHARE | PCI_SEARCH_VENDEV | PCI_INIT_ALL | PCI_INIT_IRQ | PCI_MASTER_ENABLE | PCI_USE_MSI),minor,&device_mil[minor].pci_info);
		if(device_mil[minor].pci_dev_hndl == NULL){
			printf("\nDEV_MIL_DRV_UDx: error attach device");
			perror("\npci_attach_device:");
			goto err2;
		}

		printf("\nDEV_MIL_DRV_UDx: pci_attach_device good");

		printf("\nDEV_MIL_DRV_UDx: SUMMARY INFO DEVICE");
		printf("\nDEV_MIL_DRV_UDx: Device_ID = 0x%x",device_mil[minor].pci_info.DeviceId);
		printf("\nDEV_MIL_DRV_UDx: Vendor_ID = 0x%x",device_mil[minor].pci_info.VendorId);
		printf("\nDEV_MIL_DRV_UDx: Bus Number = 0x%x",device_mil[minor].pci_info.BusNumber);
		printf("\nDEV_MIL_DRV_UDx: Device Function = 0x%x",device_mil[minor].pci_info.DevFunc);
		printf("\nDEV_MIL_DRV_UDx: Device Class = 0x%x",device_mil[minor].pci_info.Class);
		printf("\nDEV_MIL_DRV_UDx: Device IRQ = 0x%x(%d)",device_mil[minor].pci_info.Irq,device_mil[minor].pci_info.Irq);
		printf("\nDEV_MIL_DRV_UDx: MSI REG = 0x%x",device_mil[minor].pci_info.msi);
	
		device_mil[minor].bars = 0;
		for(i =0; i < 6; i++){
			printf("\nDEV_MIL_DRV_UDx: BAR%d Address = 0x%x, Size = 0x%x",i,(uint32_t)(device_mil[minor].pci_info.CpuBaseAddress[i]),(uint32_t)(device_mil[minor].pci_info.BaseAddressSize[i]));
			// смотрим, что за бар у нас
			if ((PCI_IS_MEM(device_mil[minor].pci_info.CpuBaseAddress[i])) && (device_mil[minor].pci_info.CpuBaseAddress[i]!=0x00000000)){
				printf("\nDEV_MIL_DRV_UDx: BAR%d is Memory",i);
				device_mil[minor].bars++;
			}
			else if((PCI_IS_IO(device_mil[minor].pci_info.CpuBaseAddress[i])) && (device_mil[minor].pci_info.CpuBaseAddress[i]!=0x00000000)){
				printf("\nDEV_MIL_DRV_UDx: BAR%d is I/O",i);
				device_mil[minor].bars++;
			}
		}
		// инициализаци bar0
		if ((PCI_IS_MEM(device_mil[minor].pci_info.CpuBaseAddress[0])) && (device_mil[minor].pci_info.CpuBaseAddress[0]!=0x00000000)){
			printf("\nDEV_MIL_DRV_UDx: BAR0 is Memory");
			printf("\nDEV_MIL_DRV_UDx: BAR0 Address = 0x%x, Size = 0x%x",(uint32_t)(device_mil[minor].pci_info.CpuBaseAddress[0]),(uint32_t)(device_mil[minor].pci_info.BaseAddressSize[0]));
			// физический адрес
			device_mil[minor].base_addr0 = PCI_MEM_ADDR(device_mil[minor].pci_info.CpuBaseAddress[0]);
			printf("\nDEV_MIL_DRV_UDx: PCI_MEM_ADDR BAR0 Address = 0x%lx",(unsigned long int)device_mil[minor].base_addr0);
			// виртуальный адрес
			device_mil[minor].base_addr = mmap_device_memory(NULL, device_mil[minor].pci_info.BaseAddressSize[0], PROT_NOCACHE | PROT_READ | PROT_WRITE, 0, device_mil[minor].base_addr0);
			printf("\nDEV_MIL_DRV_UDx: mmap_device_memory base_addr0 = 0x%lx,base_addr = 0x%lx",(unsigned long int)device_mil[minor].base_addr0,(unsigned long int)device_mil[minor].base_addr);
			if ( device_mil[minor].base_addr == MAP_FAILED ) {
				printf("\nDEV_MIL_DRV_UDx: mmap device memory failed");
			    perror( "\nmmap_device_memory for physical address failed" );
			    goto err2;
			}
		}
		else {
			printf("\nDEV_MIL_DRV_UDx: BAR0 is BAD");
			goto err2;
		}

		printf("\nDEV_MIL_DRV_UDx: allocate BAR0");

		// выделяем память под dma
		device_mil[minor].addr_dma = mmap(0,SIZE_DMA,(PROT_READ | PROT_WRITE | PROT_NOCACHE), MAP_ANON | MAP_PHYS  ,NOFD,0);
		if(device_mil[minor].addr_dma == MAP_FAILED){
			printf("\nDEV_MIL_DRV_UDx: dma mmap failed");
			perror("\nmmap:");
			goto err3;
		}
		
		if( mem_offset64(device_mil[minor].addr_dma,NOFD,SIZE_DMA,(off64_t *)&device_mil[minor].addr_dma_1,0) != 0){
			printf("\nDEV_MIL_DRV_UDx: don't get physical address");
			perror("\nmem_offset:");
			goto err4;
		}

		printf("\nDEV_MIL_DRV_UDx: DMA addr_dma1 = 0x%lx,addr_dma = 0x%lx",(unsigned long int)device_mil[minor].addr_dma_1,(unsigned long int)device_mil[minor].addr_dma);
		//memset(device_mil[minor].addr_dma, 0x12, SIZE_DMA);        // clear DMA
		addr_dma_lo = (device_mil[minor].addr_dma_1 & 0xffffffff);	// low part address DMA
		addr_dma_hi = (device_mil[minor].addr_dma_1 >> 32) & 0xffffffff;	// hi part address DMA
		*(uint32_t*)(device_mil[minor].base_addr + DMA_DATA_BASE) = addr_dma_lo;
		*(uint32_t*)(device_mil[minor].base_addr + DMA_DATA_BASE_HI) = addr_dma_hi;
		printf("\nDEV_MIL_DRV_UDx: to address = 0x%lx was written 0x%x", (long unsigned int)(device_mil[minor].base_addr + DMA_DATA_BASE),(unsigned int) addr_dma_lo);
		printf("\nDEV_MIL_DRV_UDx: to address = 0x%lx was written 0x%x", (long unsigned int)(device_mil[minor].base_addr + DMA_DATA_BASE_HI), (unsigned int)addr_dma_hi);
		printf("\nDEV_MIL_DRV_UDx: allocate DMA");

		//записываем номер MSI прерывания
		device_mil[minor].irq_num = device_mil[minor].pci_info.Irq;
		if(device_mil[minor].pci_info.msi)	printf("\nDEV_MIL_DRV_UDx: MSI enable, MSI irq is %d",device_mil[minor].irq_num);
		else printf("\nDEV_MIL_DRV_UDx: !!! MSI DON'T ENABLE, YOU MUST DON'T USE INTERRUPT FOR WORK WITH MODULE!!!");

		//регистрируем обработчик прерывания
		device_mil[minor].di.int_id = InterruptAttach(device_mil[minor].irq_num,irq_handler,&device_mil[minor],sizeof(device_mil[minor]),_NTO_INTR_FLAGS_END | _NTO_INTR_FLAGS_TRK_MSK);
		if(device_mil[minor].di.int_id == -1)
		{	printf("\nDEV_MIL_DRV_UDx: error interrupt attach");
			perror("\nInterruptAttach:");
			goto err4;
		}

		// определяем тип и преобразуем его
		device_mil[minor].dev_type = ((*(uint32_t*)(device_mil[minor].base_addr + 0x1034)) >> 24) & 0xFF;
		printf("\nDEV_MIL_DRV_UDx: DEVICE TYPE = 0x%x", device_mil[minor].dev_type);
		switch (device_mil[minor].dev_type){
			case 0x03:
				device_mil[minor].dev_type = PCIe_1553UD;
			break;
			case 0x23:
				device_mil[minor].dev_type = PCIe_1553UD2;
			break;
			case 0x43:
				device_mil[minor].dev_type = PCIe_1553UD4;
			break;
			default:
				printf("\nDEV_MIL_DRV_UDx: error device type");
				goto err5;
			break;
		}

		sprintf((char *)&device_mil[minor].dev_name, "/dev/%s_%d",MIL1553UDx_DRIVER_MASKNAME,minor);
		printf("\nDEV_MIL_DRV_UDx: device path with name is %s",device_mil[minor].dev_name);
		status = pthread_mutex_init(&device_mil[minor].mutex_dma,NULL);
		if(status != EOK)
		{	printf("\nDEV_MIL_DRV_UDx: error pthread mutex init %d",status);
			perror("\npthread_mutex_init:");
			goto err5;
		}
		printf("\nDEV_MIL_DRV_UDx: DEVICE CREATE GOOD");
		fflush(stdout);
		minor++;
	}while(1);

// подчищаем текущее устройство
err5: for(minor = 0; minor < plata_cnt; minor++) InterruptDetach(device_mil[minor].di.int_id);
err4: for(minor = 0; minor < plata_cnt; minor++) munmap(device_mil[minor].addr_dma, SIZE_DMA);
err3: for(minor = 0; minor < plata_cnt; minor++) munmap_device_memory(device_mil[minor].base_addr, device_mil[minor].pci_info.BaseAddressSize[0]);
err2: for(minor = 0; minor < plata_cnt; minor++) pci_detach_device(device_mil[minor].pci_dev_hndl);
err1: pci_detach(pci_hndl);

	printf("\nDEV_MIL_DRV_UDx: DEVICE DON'T CREATE");
	return -1;
}