]> rtime.felk.cvut.cz Git - mf6xx.git/blobdiff - src/qemu/hw/mf624.c
Qemu: Coding style.
[mf6xx.git] / src / qemu / hw / mf624.c
old mode 100755 (executable)
new mode 100644 (file)
index 6c2d9d3..8c804d8
@@ -1,19 +1,22 @@
-/* Humusoft MF624 DAQ card implementation
- * 
- * Copyright Rostislav Lisovy (lisovy@gmail.com)
- * 
+/*
+ * Humusoft MF624 DAQ card implementation
+ *
+ * Copyright (C) 2011 Rostislav Lisovy (lisovy@gmail.com)
+ *
  * Licensed under GPLv2 license
  */
 #include "hw.h"
 #include "pci.h"
-#include "../qemu-thread.c"
+#include "qemu-thread.h"
 #include <string.h>
 #include <unistd.h>
-#include <sys/types.h> 
+#include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <sys/socket.h>
 
+/* #define QEMU_VER_ABOVE_015 */
+
 #define PCI_VENDOR_ID_HUMUSOFT         0x186c
 #define PCI_DEVICE_ID_MF624            0x0624
 #define PCI_CLASS_SIGNAL_PROCESSING_CONTROLLER         0x1180
@@ -27,7 +30,7 @@
 #define INTCSR_off                     0x4C
 #define GPIOC_off                      0x54
 
-/* BAR2 */ 
+/* BAR2 */
 #define ADDATA_off                     0x00
 #define ADCTRL_off                     0x00
 #define ADDATA1_off                    0x02
@@ -81,6 +84,7 @@ typedef struct {
        uint16_t DA7;
 } BAR2_t;
 
+/* Not implemented */
 typedef struct {
 //     uint32_t CTR0STATUS;
 //     uint32_t CTR0MODE;
@@ -91,63 +95,76 @@ typedef struct {
 
 typedef struct {
        PCIDevice dev;
+    #ifdef QEMU_VER_ABOVE_015
+       MemoryRegion mmio_bar0;
+       MemoryRegion mmio_bar2;
+       MemoryRegion mmio_bar4;
+    #endif /*QEMU_VER_ABOVE_015*/
 
        int socket_srv;
        int socket_tmp;
-       int port;
+       uint32_t port;
        int addr;
 
-       uint16_t real_world_AD[8]; /* The real voltage which is on inputs od A/D convertors.
-                                       Until new conversion is started, there is old value in 
-                                       ADC registers*/ 
+       /* The real voltage which is on inputs od A/D convertors.
+       Until new conversion is started, there is still old value in ADC registers*/
+       unsigned int real_world_AD0; //Value in "ADC internal" format
+       unsigned int real_world_AD1;
+       unsigned int real_world_AD2;
+       unsigned int real_world_AD3;
+       unsigned int real_world_AD4;
+       unsigned int real_world_AD5;
+       unsigned int real_world_AD6;
+       unsigned int real_world_AD7;
 
        // for cpu_register_physical_memory() function
        unsigned int BAR0_mem_table_index;
        unsigned int BAR2_mem_table_index;
        unsigned int BAR4_mem_table_index;
-       
+
        // Internal registers values
        BAR0_t BAR0;
        BAR2_t BAR2;
        BAR4_t BAR4;
-       
-       unsigned int ADDATA_FIFO_POSITION; //ADDATA is FIFO register; 
-                                       //We need to know, position in this FIFO =
-                                       //Which value will come next
-} mf624_state_t;
 
 
-//FIXME all wrong
-int volts_to_adinternal(int volt)
-{
-       int tmp;
-       
-       tmp = ~volt;
-       tmp += 1;
+       int ADDATA_FIFO[8]; //this array tells us which ADCs are being converted
+       unsigned int ADDATA_FIFO_POSITION; //ADDATA is FIFO register;
+                               //We need to know, position in this FIFO =
+                               //Which value will come next
+} mf624_state_t;
 
-       return tmp;     
-}
+int instance = 0; // Global variable shared between multiple mf624 devices
 
-//FIXME all wrong
-int dacinternal_to_volts(int dacinternal)
+
+static int16_t volts_to_adinternal(double volt)
 {
-       if (dacinternal >= 0x2000) {
-               return -(~(dacinternal & ~(0x2000)))/1000;
+       if (volt > 9.99) {
+               volt = 9.99;
        }
-       else {
-               return (dacinternal - 0x2000)/1000;
+       else if (volt < -10) {
+               volt = -10;
        }
 
+       return ((int16_t) ((volt*0x8000)/10))>>2;
+}
+
+static double dacinternal_to_volts(int16_t dacinternal)
+{
+       return ((((double)dacinternal)/0x4000)*20.0 - 10.0);
 }
+
 //-----------------------------------------------------------------------------
-void mf624_init_registers(mf624_state_t* s)
+
+/* Initialize register values due to MF624 manual */
+static void mf624_init_registers(mf624_state_t* s)
 {
 #define INTCSR_default_value           0x000300
 #define GPIOC_default_value            0x006C0 | (0x10 << 21) | (2 << 25)
 
        //Initialize all registers to default values
        s->BAR0.INTCSR = INTCSR_default_value;
-       s->BAR0.GPIOC = GPIOC_default_value; 
+       s->BAR0.GPIOC = GPIOC_default_value;
        s->BAR2.ADDATA = 0x0;
        s->BAR2.ADCTRL = 0x0;
        s->BAR2.ADDATA1 = 0x0;
@@ -172,12 +189,12 @@ void mf624_init_registers(mf624_state_t* s)
        s->ADDATA_FIFO_POSITION = 0;
 }
 
-
-void socket_write(mf624_state_t *s, const char* reg, unsigned int val)
+/* After some widget's value is changed, new value is send via socket to Qemu */
+static void socket_write(mf624_state_t *s, const char* reg, double val)
 {
        int status;
        char write_buffer[256];
-       snprintf(write_buffer, 255, "%s=%d\n", reg, val);
+       snprintf(write_buffer, 255, "%s=%f\n", reg, val);
 
        status = write(s->socket_tmp, write_buffer, strlen(write_buffer));
        if (status < 0) {
@@ -186,56 +203,90 @@ void socket_write(mf624_state_t *s, const char* reg, unsigned int val)
        }
 }
 
-
-void* socket_accept(void* ptr)
+#define STRING_BUFF_SIZE       256
+static void socket_read(mf624_state_t* dev)
 {
-       struct sockaddr_in addr_client;
-       mf624_state_t* dev = (mf624_state_t*) ptr;
+       // For parsing read instructions
+       char reg[STRING_BUFF_SIZE+1];
+       float val;
+       // For reading from socket
+       char read_buffer[STRING_BUFF_SIZE];
+       int received_length = 0;
+       int status;
+
 
        while(1) {
-               printf("Waiting on port %d for MF624 client to connect\n", dev->port);
-               socklen_t len_client = sizeof(addr_client);
-               dev->socket_tmp = accept(dev->socket_srv, (struct sockaddr*) &addr_client, &len_client);
-               if (dev->socket_tmp == -1) {
-                       perror("accept()");
+               memset(read_buffer, '\0', STRING_BUFF_SIZE);
+               received_length = read(dev->socket_tmp, read_buffer, STRING_BUFF_SIZE-1);
+               if (received_length < 0) {
+                       perror("read()");
+                       return;
+               }
+
+               if (received_length == 0) {
+                       printf("Error while reading from socket. Client disconnected?\n");
+                       return;
+               }
+
+               // REG has "same size +1" as READ_BUFFER to avoid buffer overflow
+               status = sscanf(read_buffer, "%[A-Z0-9]=%f", reg, &val);
+               if (status == 2) {
+                       if(!strcmp(reg, "DIN")) {
+                               dev->BAR2.DIN = val;
+                       }
+                       else if(!strcmp(reg, "ADC0")) {
+                               dev->real_world_AD0 = volts_to_adinternal(val);
+                       }
+                       else if(!strcmp(reg, "ADC1")) {
+                               dev->real_world_AD1 = volts_to_adinternal(val);
+                       }
+                       else if(!strcmp(reg, "ADC2")) {
+                               dev->real_world_AD2 = volts_to_adinternal(val);
+                       }
+                       else if(!strcmp(reg, "ADC3")) {
+                               dev->real_world_AD3 = volts_to_adinternal(val);
+                       }
+                       else if(!strcmp(reg, "ADC4")) {
+                               dev->real_world_AD4 = volts_to_adinternal(val);
+                       }
+                       else if(!strcmp(reg, "ADC5")) {
+                               dev->real_world_AD5 = volts_to_adinternal(val);
+                       }
+                       else if(!strcmp(reg, "ADC6")) {
+                               dev->real_world_AD6 = volts_to_adinternal(val);
+                       }
+                       else if(!strcmp(reg, "ADC7")) {
+                               dev->real_world_AD7 = volts_to_adinternal(val);
+                       }
+                       else {
+                               printf("reg = %s; val = %f\n", reg, val);
+                       }
                }
-               printf("Client connected\n");
        }
 }
 
 
-void* init_socket(void* ptr)
+static void* init_socket(void* ptr)
 {
-#define STRING_BUFF_SIZE       256
-       // Socket stuff
+       struct sockaddr_in addr_client;
        struct sockaddr_in addr_srv;
        int port;
        int yes = 1;
-       // For reading from socket
-       char read_buffer[STRING_BUFF_SIZE];
-       int received_length = 0;
-       // For parsing read instructions
-       char reg[STRING_BUFF_SIZE+1];
-       int val;
-       // ----
-       int status;
-       QemuThread socket_accept_thread;
 
-       
        mf624_state_t* dev = (mf624_state_t*) ptr;
-       // If no client connected, we will know about it
+
        dev->socket_tmp = -1;
        port = dev->port;
 
        dev->socket_srv = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (dev->socket_srv == -1) {
                perror("socket()");
-               goto exit;
+               return NULL;
        }
-       
+
        if (setsockopt(dev->socket_srv, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
                perror("setsockopt()");
-               goto exit;
+               return NULL;
        }
 
 
@@ -246,83 +297,37 @@ void* init_socket(void* ptr)
        addr_srv.sin_port = htons(port);
        if(bind(dev->socket_srv, (struct sockaddr*) &addr_srv, len) == -1) {
                perror("bind()");
-               goto exit;
+               return NULL;
        }
-       
+
        if (listen(dev->socket_srv, 5) == -1) {
                perror("listen()");
-               goto exit;
+               return NULL;
        }
 
 
-       qemu_thread_create(&socket_accept_thread, socket_accept, (void*) ptr);
+       while(1) {
+               printf("Waiting on port %d for MF624 client to connect\n", dev->port);
+               socklen_t len_client = sizeof(addr_client);
+               dev->socket_tmp = accept(dev->socket_srv, (struct sockaddr*) &addr_client, &len_client);
+               if (dev->socket_tmp == -1) {
+                       perror("accept()");
+               }
 
+               printf("Client connected\n");
 
-       memset(read_buffer, '\0', STRING_BUFF_SIZE);
-       while(1) {
-               if (dev->socket_tmp > 0) {
-                       received_length = read(dev->socket_tmp, read_buffer, STRING_BUFF_SIZE-1);
-                       if (received_length < 0) {
-                               perror("read()");
-                               goto exit_close;
-                       }
-                       
-                       if (received_length == 0) {
-                               printf("Error while reading from socket. Client disconnected?\n");
-                               //FIXME For client it is not possible to reconnect
-                               goto exit_close;
-                       }
+               socket_read(dev); // should run forever if everything is OK;
+                               // If error occurs (client disconnected), returns here
 
-                       // REG has "same size +1" as READ_BUFFER to avoid buffer overflow
-                       status = sscanf(read_buffer, "%[A-Z0-9]=%u", reg, &val);
-                       if (status == 2) {
-                               if(!strcmp(reg, "DIN")) {
-                                       dev->BAR2.DIN = val;
-                               }
-                               else if(!strcmp(reg, "ADC0")) {
-                                       dev->real_world_AD[0] = volts_to_adinternal(val);
-                               }
-                               else if(!strcmp(reg, "ADC1")) {
-                                       dev->real_world_AD[1] = volts_to_adinternal(val);
-                               }
-                               else if(!strcmp(reg, "ADC2")) {
-                                       dev->real_world_AD[2] = volts_to_adinternal(val);
-                               }
-                               else if(!strcmp(reg, "ADC3")) {
-                                       dev->real_world_AD[3] = volts_to_adinternal(val);
-                               }
-                               else if(!strcmp(reg, "ADC4")) {
-                                       dev->real_world_AD[4] = volts_to_adinternal(val);
-                               }
-                               else if(!strcmp(reg, "ADC5")) {
-                                       dev->real_world_AD[5] = volts_to_adinternal(val);
-                               }
-                               else if(!strcmp(reg, "ADC6")) {
-                                       dev->real_world_AD[6] = volts_to_adinternal(val);
-                               }
-                               else if(!strcmp(reg, "ADC7")) {
-                                       dev->real_world_AD[7] = volts_to_adinternal(val);
-                               }
-                               else {
-                                       printf("reg = %s; val = %d\n", reg, val);
-                               } 
-                       }
-               }
-               else {
-                       sleep(1);
-               }
+               close(dev->socket_tmp);
        }
 
-
-exit_close:
-       close(dev->socket_tmp);
-exit:
        return NULL;
 }
 
 //-----------------------------------------------------------------------------
 
-void mf624_BAR0_write32(void *opaque, target_phys_addr_t addr, uint32_t value)
+static void mf624_BAR0_write32(void *opaque, target_phys_addr_t addr, uint32_t value)
 {
        mf624_state_t *s = opaque;
 
@@ -331,6 +336,7 @@ void mf624_BAR0_write32(void *opaque, target_phys_addr_t addr, uint32_t value)
                        s->BAR0.INTCSR = (value & 0x7FF) | INTCSR_default_value; // Only first 11 bits are writable
                        socket_write(s, "INTCSR", s->BAR0.INTCSR);
                        break;
+
                case GPIOC_off:
                        //Don't write anywhere else than into these two bits
                        s->BAR0.GPIOC = (value & (GPIOC_LDAC_mask | GPIOC_DACEN_mask)) | GPIOC_default_value;
@@ -339,39 +345,39 @@ void mf624_BAR0_write32(void *opaque, target_phys_addr_t addr, uint32_t value)
                        //Is DAC enabled & Output enabled?
                        if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
                                (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
-                               socket_write(s, "DA0", s->BAR2.DA0);
-                               socket_write(s, "DA1", s->BAR2.DA1);
-                               socket_write(s, "DA2", s->BAR2.DA2);
-                               socket_write(s, "DA3", s->BAR2.DA3);
-                               socket_write(s, "DA4", s->BAR2.DA4);
-                               socket_write(s, "DA5", s->BAR2.DA5);
-                               socket_write(s, "DA6", s->BAR2.DA6);
-                               socket_write(s, "DA7", s->BAR2.DA7);
+                               socket_write(s, "DA0", dacinternal_to_volts(s->BAR2.DA0));
+                               socket_write(s, "DA1", dacinternal_to_volts(s->BAR2.DA1));
+                               socket_write(s, "DA2", dacinternal_to_volts(s->BAR2.DA2));
+                               socket_write(s, "DA3", dacinternal_to_volts(s->BAR2.DA3));
+                               socket_write(s, "DA4", dacinternal_to_volts(s->BAR2.DA4));
+                               socket_write(s, "DA5", dacinternal_to_volts(s->BAR2.DA5));
+                               socket_write(s, "DA6", dacinternal_to_volts(s->BAR2.DA6));
+                               socket_write(s, "DA7", dacinternal_to_volts(s->BAR2.DA7));
                        }
-                       
+
                        //Is output forced to GND?
                        if (!(s->BAR0.GPIOC & GPIOC_DACEN_mask))
                        {
                                #define GND     0
-                               socket_write(s, "DA0", GND);
-                               socket_write(s, "DA1", GND);
-                               socket_write(s, "DA2", GND);
-                               socket_write(s, "DA3", GND);
-                               socket_write(s, "DA4", GND);
-                               socket_write(s, "DA5", GND);
-                               socket_write(s, "DA6", GND);
-                               socket_write(s, "DA7", GND);
+                               socket_write(s, "DA0", dacinternal_to_volts(GND));
+                               socket_write(s, "DA1", dacinternal_to_volts(GND));
+                               socket_write(s, "DA2", dacinternal_to_volts(GND));
+                               socket_write(s, "DA3", dacinternal_to_volts(GND));
+                               socket_write(s, "DA4", dacinternal_to_volts(GND));
+                               socket_write(s, "DA5", dacinternal_to_volts(GND));
+                               socket_write(s, "DA6", dacinternal_to_volts(GND));
+                               socket_write(s, "DA7", dacinternal_to_volts(GND));
                        }
-                               
                        break;
+
                default:
-                       printf("mf624_BAR0_write32(): addr = %d; value = %d\n", addr, value);
+                       printf("mf624_BAR0_write32(): addr = " TARGET_FMT_plx "; value = %d\n", addr, value);
                        break;
        }
 }
 
 
-uint32_t mf624_BAR0_read32(void *opaque, target_phys_addr_t addr)
+static uint32_t mf624_BAR0_read32(void *opaque, target_phys_addr_t addr)
 {
        mf624_state_t *s = opaque;
 
@@ -383,13 +389,13 @@ uint32_t mf624_BAR0_read32(void *opaque, target_phys_addr_t addr)
                        return s->BAR0.GPIOC;
 
                default:
-                       printf("mf624_BAR0_read32(): addr = %d\n", addr);
+                       printf("mf624_BAR0_read32(): addr = " TARGET_FMT_plx "\n", addr);
                        return 0x0;
        }
 }
 
 
-uint32_t mf624_BAR2_read16(void *opaque, target_phys_addr_t addr)
+static uint32_t mf624_BAR2_read16(void *opaque, target_phys_addr_t addr)
 {
        int i;
        int ADDATA_val = 0xFFFF;
@@ -406,6 +412,13 @@ uint32_t mf624_BAR2_read16(void *opaque, target_phys_addr_t addr)
                case ADDATA6_off:
                case ADDATA7_off:
                        if (!(s->BAR0.GPIOC & GPIOC_EOLC_mask)) { //Has the conversion already ended?
+                               #define ADC_CHANNELS    8
+                               for(i = s->ADDATA_FIFO_POSITION; i < ADC_CHANNELS; i ++) {
+                                       if (s->BAR2.ADCTRL & (1 << i)) {
+                                               s->ADDATA_FIFO_POSITION = i; // Move to next AD to be read
+                                       }
+                               }
+
                                switch (s->ADDATA_FIFO_POSITION)
                                {
                                        case 0:
@@ -451,29 +464,32 @@ uint32_t mf624_BAR2_read16(void *opaque, target_phys_addr_t addr)
                case ADSTART_off:
                        s->BAR0.GPIOC |= GPIOC_EOLC_mask; // Conversion in progress
                        s->ADDATA_FIFO_POSITION = 0;
-                       for (i = 0; i < 500000; i++) 
+                       for (i = 0; i < 5000; i++)
                                ; // Small delay simulating real conversion
 
                        // Check before assignement, if particular ADC is enabled
-                       s->BAR2.ADDATA  = (s->BAR2.ADCTRL & (1 << 0)) ? s->real_world_AD[0] : s->BAR2.ADDATA;
-                       s->BAR2.ADDATA1 = (s->BAR2.ADCTRL & (1 << 1)) ? s->real_world_AD[1] : s->BAR2.ADDATA1;
-                       s->BAR2.ADDATA2 = (s->BAR2.ADCTRL & (1 << 2)) ? s->real_world_AD[2] : s->BAR2.ADDATA2;
-                       s->BAR2.ADDATA3 = (s->BAR2.ADCTRL & (1 << 3)) ? s->real_world_AD[3] : s->BAR2.ADDATA3;
-                       s->BAR2.ADDATA4 = (s->BAR2.ADCTRL & (1 << 4)) ? s->real_world_AD[4] : s->BAR2.ADDATA4;
-                       s->BAR2.ADDATA5 = (s->BAR2.ADCTRL & (1 << 5)) ? s->real_world_AD[5] : s->BAR2.ADDATA5;
-                       s->BAR2.ADDATA6 = (s->BAR2.ADCTRL & (1 << 6)) ? s->real_world_AD[6] : s->BAR2.ADDATA6;
-                       s->BAR2.ADDATA7 = (s->BAR2.ADCTRL & (1 << 7)) ? s->real_world_AD[7] : s->BAR2.ADDATA7;
-                       
+                       s->BAR2.ADDATA  = (s->BAR2.ADCTRL & (1 << 0)) ? s->real_world_AD0 : s->BAR2.ADDATA;
+                       s->BAR2.ADDATA1 = (s->BAR2.ADCTRL & (1 << 1)) ? s->real_world_AD1 : s->BAR2.ADDATA1;
+                       s->BAR2.ADDATA2 = (s->BAR2.ADCTRL & (1 << 2)) ? s->real_world_AD2 : s->BAR2.ADDATA2;
+                       s->BAR2.ADDATA3 = (s->BAR2.ADCTRL & (1 << 3)) ? s->real_world_AD3 : s->BAR2.ADDATA3;
+                       s->BAR2.ADDATA4 = (s->BAR2.ADCTRL & (1 << 4)) ? s->real_world_AD4 : s->BAR2.ADDATA4;
+                       s->BAR2.ADDATA5 = (s->BAR2.ADCTRL & (1 << 5)) ? s->real_world_AD5 : s->BAR2.ADDATA5;
+                       s->BAR2.ADDATA6 = (s->BAR2.ADCTRL & (1 << 6)) ? s->real_world_AD6 : s->BAR2.ADDATA6;
+                       s->BAR2.ADDATA7 = (s->BAR2.ADCTRL & (1 << 7)) ? s->real_world_AD7 : s->BAR2.ADDATA7;
+
+                       //All channels converted
+                       s->BAR0.GPIOC &= ~ GPIOC_EOLC_mask;
+
                        return 0xFFFF; // Semirandom value
 
                default:
-                       printf("mf624_BAR2_read16(): addr = %d\n", addr);
+                       printf("mf624_BAR2_read16(): addr = " TARGET_FMT_plx "\n", addr);
                        return 0x0;
        }
 }
 
 
-void mf624_BAR2_write16(void *opaque, target_phys_addr_t addr, uint32_t value)
+static void mf624_BAR2_write16(void *opaque, target_phys_addr_t addr, uint32_t value)
 {
        mf624_state_t *s = opaque;
 
@@ -499,38 +515,138 @@ void mf624_BAR2_write16(void *opaque, target_phys_addr_t addr, uint32_t value)
 
                case DA1_off:
                        s->BAR2.DA1 = value;
-                       if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) && 
+                       if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
                                (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
                                socket_write(s, "DA1", dacinternal_to_volts(s->BAR2.DA1));
                        }
                        break;
 
+               case DA2_off:
+                       s->BAR2.DA2 = value;
+                       if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
+                               (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
+                               socket_write(s, "DA2", dacinternal_to_volts(s->BAR2.DA2));
+                       }
+                       break;
+
+               case DA3_off:
+                       s->BAR2.DA3 = value;
+                       if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
+                               (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
+                               socket_write(s, "DA3", dacinternal_to_volts(s->BAR2.DA3));
+                       }
+                       break;
+
+               case DA4_off:
+                       s->BAR2.DA4 = value;
+                       if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
+                               (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
+                               socket_write(s, "DA4", dacinternal_to_volts(s->BAR2.DA4));
+                       }
+                       break;
+
+               case DA5_off:
+                       s->BAR2.DA5 = value;
+                       if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
+                               (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
+                               socket_write(s, "DA5", dacinternal_to_volts(s->BAR2.DA5));
+                       }
+                       break;
+
+               case DA6_off:
+                       s->BAR2.DA6 = value;
+                       if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
+                               (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
+                               socket_write(s, "DA6", dacinternal_to_volts(s->BAR2.DA6));
+                       }
+                       break;
+
+               case DA7_off:
+                       s->BAR2.DA7 = value;
+                       if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
+                               (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
+                               socket_write(s, "DA7", dacinternal_to_volts(s->BAR2.DA7));
+                       }
+                       break;
+
                default:
-                       printf("mf624_BAR2_write16(): addr = %d; value = %d\n", addr, value);
+                       printf("mf624_BAR2_write16(): addr = " TARGET_FMT_plx "; value = %d\n", addr, value);
                        break;
        }
-
 }
 
 
-void mf624_BAR4_write32(void *opaque, target_phys_addr_t addr, uint32_t value)
+static void mf624_BAR4_write32(void *opaque, target_phys_addr_t addr, uint32_t value)
 {
-       printf("mf624_BAR4_write32(): addr = %d; value = %d\n", addr, value);
+       printf("mf624_BAR4_write32(): addr = " TARGET_FMT_plx "; value = %d\n", addr, value);
 }
 
-uint32_t mf624_BAR4_read32(void *opaque, target_phys_addr_t addr)
+static uint32_t mf624_BAR4_read32(void *opaque, target_phys_addr_t addr)
 {
-       printf("mf624_BAR4_read32(): addr = %d\n", addr);
+       printf("mf624_BAR4_read32(): addr = " TARGET_FMT_plx "\n", addr);
        return 0x0;
 }
 
+//-----------------------------------------------------------------------------
+
+#ifdef QEMU_VER_ABOVE_015
+
+static const MemoryRegionOps mf624_BAR0_mmio_ops = {
+    .old_mmio = {
+        .read = {
+            NULL,
+            NULL,
+            mf624_BAR0_read32,
+        },
+        .write = {
+            NULL,
+            NULL,
+            mf624_BAR0_write32,
+        },
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static const MemoryRegionOps mf624_BAR2_mmio_ops = {
+    .old_mmio = {
+        .read = {
+            NULL,
+            mf624_BAR2_read16,
+            NULL,
+        },
+        .write = {
+            NULL,
+            mf624_BAR2_write16,
+            NULL,
+        },
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static const MemoryRegionOps mf624_BAR4_mmio_ops = {
+    .old_mmio = {
+        .read = {
+            NULL,
+            NULL,
+            mf624_BAR4_read32,
+        },
+        .write = {
+            NULL,
+            NULL,
+            mf624_BAR4_write32,
+        },
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+#else /*QEMU_VER_ABOVE_015*/
 
 static CPUReadMemoryFunc * const mf624_BAR0_read[3] = {
        NULL, /* read8 */
        NULL, /* read16 */
        mf624_BAR0_read32,
 };
+
 static CPUWriteMemoryFunc * const mf624_BAR0_write[3] = {
        NULL, /* write8 */
        NULL, /* write16 */
@@ -542,7 +658,7 @@ static CPUReadMemoryFunc * const mf624_BAR2_read[3] = {
        mf624_BAR2_read16,
        NULL, /* read32 */
 };
+
 static CPUWriteMemoryFunc * const mf624_BAR2_write[3] = {
        NULL, /* write8 */
        mf624_BAR2_write16,
@@ -554,14 +670,16 @@ static CPUReadMemoryFunc * const mf624_BAR4_read[3] = {
        NULL, /* read16 */
        mf624_BAR4_read32,
 };
+
 static CPUWriteMemoryFunc * const mf624_BAR4_write[3] = {
        NULL, /* write8 */
        NULL, /* write16 */
        mf624_BAR4_write32,
 };
+
+
 //-----------------------------------------------------------------------------
-       
+
 static void mf624_map(PCIDevice *pci_dev, int region_num,
                        pcibus_t addr, pcibus_t size, int type)
 {
@@ -586,20 +704,21 @@ static void mf624_map(PCIDevice *pci_dev, int region_num,
 
 }
 
+#endif /*QEMU_VER_ABOVE_015*/
+
+#define DEFAULT_PORT                   55555
 static int pci_mf624_init(PCIDevice *pci_dev)
 {
        mf624_state_t *s = DO_UPCAST(mf624_state_t, dev, pci_dev); //alocation of mf624_state_t
        uint8_t *pci_conf;
        QemuThread socket_thread;
-       //char options_buff[8];
 
-       //Parameters from command line
-       //if (get_param_value(options_buff, sizeof(options_buff), "port", opts)) {
-       //      s->port = atoi(options_buff);
-       //}
-       //else {
-               s->port = 55555; // Default port
-       //}
+       printf("MF624 Loaded.\n");
+
+       if (s->port == DEFAULT_PORT) {
+               s->port += instance; // Each instance of the same device should have another port number
+               instance ++;
+       }
 
        //Set all internal registers to default values
        mf624_init_registers(s);
@@ -615,7 +734,14 @@ static int pci_mf624_init(PCIDevice *pci_dev)
 
        pci_conf[PCI_INTERRUPT_PIN] = 0x1; // interrupt pin 0
 
-
+    #ifdef QEMU_VER_ABOVE_015
+       memory_region_init_io(&s->mmio_bar0, &mf624_BAR0_mmio_ops, s, "mf624_bar0", BAR0_size);
+       memory_region_init_io(&s->mmio_bar2, &mf624_BAR2_mmio_ops, s, "mf624_bar2", BAR2_size);
+       memory_region_init_io(&s->mmio_bar4, &mf624_BAR4_mmio_ops, s, "mf624_bar4", BAR4_size);
+       pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio_bar0);
+       pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio_bar2);
+       pci_register_bar(&s->dev, 4, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio_bar4);
+    #else  /*QEMU_VER_ABOVE_015*/
        s->BAR0_mem_table_index = cpu_register_io_memory(mf624_BAR0_read,
                                                 mf624_BAR0_write,
                                                 s,
@@ -631,13 +757,10 @@ static int pci_mf624_init(PCIDevice *pci_dev)
                                                 s,
                                                 DEVICE_NATIVE_ENDIAN);
 
-       //printf("BAR0: %d\n", s->BAR0_offset);
-       //printf("BAR2: %d\n", s->BAR2_offset);
-       //printf("BAR4: %d\n", s->BAR4_offset);
-
        pci_register_bar(&s->dev, 0, BAR0_size, PCI_BASE_ADDRESS_SPACE_MEMORY, mf624_map);
        pci_register_bar(&s->dev, 2, BAR2_size, PCI_BASE_ADDRESS_SPACE_MEMORY, mf624_map);
        pci_register_bar(&s->dev, 4, BAR4_size, PCI_BASE_ADDRESS_SPACE_MEMORY, mf624_map);
+    #endif  /*QEMU_VER_ABOVE_015*/
 
        //Create thread, which will be blocked on reading from socket (connected to "I/O GUI")
        qemu_thread_create(&socket_thread, init_socket, (void*) s);
@@ -652,20 +775,20 @@ static int pci_mf624_exit(PCIDevice *pci_dev)
        return 0;
 }
 
+
 static PCIDeviceInfo mf624_info = {
        .qdev.name  = "mf624",
        .qdev.size  = sizeof(mf624_state_t),
-       //.qdev.vmsd  = &vmstate_pci_ne2000,
        .init       = pci_mf624_init,
-       .exit       = pci_mf624_exit //,
-       //.qdev.props = (Property[]) {
-       //      DEFINE_PROP_END_OF_LIST(),
-       //}
+       .exit       = pci_mf624_exit,
+       .qdev.props = (Property[]) {
+               DEFINE_PROP_UINT32("port", mf624_state_t, port, DEFAULT_PORT),
+               DEFINE_PROP_END_OF_LIST(),
+       }
 };
 
 static void mf624_register_device(void)
 {
-       printf("MF624 Loaded.\n");
        pci_qdev_register(&mf624_info);
 }