-/* 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 <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "qemu/event_notifier.h"
+#include "qemu/osdep.h"
+#include "qemu/thread.h"
+#include "qemu/sockets.h"
+#include "sysemu/char.h"
+
+#define TYPE_MF624_DEV "mf624"
+
+#define MF624_DEV(obj) \
+ OBJECT_CHECK(mf624_state_t, (obj), TYPE_MF624_DEV)
#define PCI_VENDOR_ID_HUMUSOFT 0x186c
#define PCI_DEVICE_ID_MF624 0x0624
#define INTCSR_off 0x4C
#define GPIOC_off 0x54
-/* BAR2 */
+/* BAR2 */
#define ADDATA_off 0x00
#define ADCTRL_off 0x00
#define ADDATA1_off 0x02
uint16_t DA7;
} BAR2_t;
+/* Not implemented */
typedef struct {
// uint32_t CTR0STATUS;
// uint32_t CTR0MODE;
typedef struct {
PCIDevice dev;
+ MemoryRegion mmio_bar0;
+ MemoryRegion mmio_bar2;
+ MemoryRegion mmio_bar4;
+ qemu_irq irq;
+ QemuThread socket_thread;
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;
s->ADDATA_FIFO_POSITION = 0;
}
+static void
+mf624_reset(void *opaque)
+{
+ mf624_state_t *s = (mf624_state_t *)opaque;
+
+ mf624_init_registers(s);
+}
-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) {
}
}
-
-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;
}
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()");
+ return NULL;
+ }
+ 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, hwaddr addr, uint64_t value, unsigned size)
{
mf624_state_t *s = opaque;
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;
//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 = 0x%" PRIx64 "\n", addr, value);
break;
}
}
-
-uint32_t mf624_BAR0_read32(void *opaque, target_phys_addr_t addr)
+static uint64_t mf624_BAR0_read32(void *opaque, hwaddr addr, unsigned size)
{
mf624_state_t *s = opaque;
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 uint64_t mf624_BAR2_read16(void *opaque, hwaddr addr, unsigned size)
{
int i;
int ADDATA_val = 0xFFFF;
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:
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, hwaddr addr, uint64_t value, unsigned size)
{
mf624_state_t *s = opaque;
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 = 0x%" PRIx64 "\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, hwaddr addr, uint64_t value, unsigned size)
{
- printf("mf624_BAR4_write32(): addr = %d; value = %d\n", addr, value);
+ printf("mf624_BAR4_write32(): addr = " TARGET_FMT_plx
+ "; value = 0x%" PRIx64 "\n", addr, value);
}
-uint32_t mf624_BAR4_read32(void *opaque, target_phys_addr_t addr)
+static uint64_t mf624_BAR4_read32(void *opaque, hwaddr addr, unsigned size)
{
- printf("mf624_BAR4_read32(): addr = %d\n", addr);
+ printf("mf624_BAR4_read32(): addr = " TARGET_FMT_plx "\n", addr);
return 0x0;
}
+//-----------------------------------------------------------------------------
-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 */
- mf624_BAR0_write32,
+static const MemoryRegionOps mf624_BAR0_mmio_ops = {
+ .read = mf624_BAR0_read32,
+ .write = mf624_BAR0_write32,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
};
-static CPUReadMemoryFunc * const mf624_BAR2_read[3] = {
- NULL, /* read8 */
- mf624_BAR2_read16,
- NULL, /* read32 */
-};
-
-static CPUWriteMemoryFunc * const mf624_BAR2_write[3] = {
- NULL, /* write8 */
- mf624_BAR2_write16,
- NULL, /* write32 */
+static const MemoryRegionOps mf624_BAR2_mmio_ops = {
+ .read = mf624_BAR2_read16,
+ .write = mf624_BAR2_write16,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl = {
+ .min_access_size = 2,
+ .max_access_size = 2,
+ },
};
-static CPUReadMemoryFunc * const mf624_BAR4_read[3] = {
- NULL, /* read8 */
- NULL, /* read16 */
- mf624_BAR4_read32,
-};
-
-static CPUWriteMemoryFunc * const mf624_BAR4_write[3] = {
- NULL, /* write8 */
- NULL, /* write16 */
- mf624_BAR4_write32,
+static const MemoryRegionOps mf624_BAR4_mmio_ops = {
+ .read = mf624_BAR4_read32,
+ .write = mf624_BAR4_write32,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
};
-//-----------------------------------------------------------------------------
-
-static void mf624_map(PCIDevice *pci_dev, int region_num,
- pcibus_t addr, pcibus_t size, int type)
+
+#define DEFAULT_PORT 55555
+static int mf624_init(PCIDevice *pci_dev)
{
- mf624_state_t *s = DO_UPCAST(mf624_state_t, dev, pci_dev);
+ mf624_state_t *s = MF624_DEV(pci_dev); //alocation of mf624_state_t
+ uint8_t *pci_conf;
- switch (region_num) {
- case 0:
- //printf("reg%d, addr = %x\n", region_num, addr);
- cpu_register_physical_memory(addr + 0x0, BAR0_size, s->BAR0_mem_table_index);
- break;
- case 2:
- //printf("reg%d, addr = %x\n", region_num, addr);
- cpu_register_physical_memory(addr + 0x0, BAR2_size, s->BAR2_mem_table_index);
- break;
- case 4:
- //printf("reg%d, addr = %x\n", region_num, addr);
- cpu_register_physical_memory(addr + 0x0, BAR4_size, s->BAR4_mem_table_index);
- break;
- default:
- printf("FFFUUU\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);
+
+ pci_conf = pci_dev->config;
+ pci_conf[PCI_INTERRUPT_PIN] = 0x1; // interrupt pin 0
+
+ s->irq = pci_allocate_irq(&s->dev);
+
+ qemu_register_reset(mf624_reset, s);
+
+ memory_region_init_io(&s->mmio_bar0, OBJECT(s), &mf624_BAR0_mmio_ops, s, "mf624_bar0", BAR0_size);
+ memory_region_init_io(&s->mmio_bar2, OBJECT(s), &mf624_BAR2_mmio_ops, s, "mf624_bar2", BAR2_size);
+ memory_region_init_io(&s->mmio_bar4, OBJECT(s), &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);
+
+ //Create thread, which will be blocked on reading from socket (connected to "I/O GUI")
+
+ qemu_thread_create(&s->socket_thread, "mf624_io_thread",
+ init_socket, (void*) s, QEMU_THREAD_JOINABLE);
+ return 0;
}
-static int pci_mf624_init(PCIDevice *pci_dev)
+static void qdev_mf624_reset(DeviceState *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
- //}
-
- //Set all internal registers to default values
- mf624_init_registers(s);
-
- pci_conf = s->dev.config;
- pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_HUMUSOFT);
- pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_MF624);
- pci_config_set_class(pci_conf, PCI_CLASS_SIGNAL_PROCESSING_CONTROLLER);
- pci_conf[PCI_SUBSYSTEM_VENDOR_ID] = PCI_VENDOR_ID_HUMUSOFT & 0xff;
- pci_conf[PCI_SUBSYSTEM_VENDOR_ID + 1] = PCI_VENDOR_ID_HUMUSOFT >> 8;
- pci_conf[PCI_SUBSYSTEM_ID] = PCI_DEVICE_ID_MF624 & 0xff;
- pci_conf[PCI_SUBSYSTEM_ID + 1] = PCI_DEVICE_ID_MF624 >> 8;
-
- pci_conf[PCI_INTERRUPT_PIN] = 0x1; // interrupt pin 0
-
-
- s->BAR0_mem_table_index = cpu_register_io_memory(mf624_BAR0_read,
- mf624_BAR0_write,
- s,
- DEVICE_NATIVE_ENDIAN);
-
- s->BAR2_mem_table_index = cpu_register_io_memory(mf624_BAR2_read,
- mf624_BAR2_write,
- s,
- DEVICE_NATIVE_ENDIAN);
-
- s->BAR4_mem_table_index = cpu_register_io_memory(mf624_BAR4_read,
- mf624_BAR4_write,
- 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);
-
- //Create thread, which will be blocked on reading from socket (connected to "I/O GUI")
- qemu_thread_create(&socket_thread, init_socket, (void*) s);
- return 0;
+ mf624_state_t *s = MF624_DEV(dev);
+ mf624_init_registers(s);
}
-static int pci_mf624_exit(PCIDevice *pci_dev)
+static void mf624_exit(PCIDevice *pci_dev)
{
- mf624_state_t *s = DO_UPCAST(mf624_state_t, dev, pci_dev);
- close(s->socket_srv);
+ mf624_state_t *s = MF624_DEV(pci_dev);
+
+ close(s->socket_srv);
+
+ qemu_thread_join(&s->socket_thread);
+
+ qemu_unregister_reset(mf624_reset, s);
+
+ memory_region_destroy(&s->mmio_bar0);
+ memory_region_destroy(&s->mmio_bar2);
+ memory_region_destroy(&s->mmio_bar4);
- return 0;
+ qemu_free_irq(s->irq);
+}
+
+static const VMStateDescription vmstate_mf624 = {
+ .name = "mf624",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(dev, mf624_state_t),
+ VMSTATE_UINT32(port, mf624_state_t),
+ VMSTATE_END_OF_LIST()
+ }
+
+};
+
+static Property mf624_properties[] = {
+ DEFINE_PROP_UINT32("port", mf624_state_t, port, DEFAULT_PORT),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void mf624_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = mf624_init;
+ k->exit = mf624_exit;
+ k->vendor_id = PCI_VENDOR_ID_HUMUSOFT;
+ k->device_id = PCI_DEVICE_ID_MF624;
+ k->revision = 0x00;
+ k->class_id = PCI_CLASS_SIGNAL_PROCESSING_CONTROLLER;
+ k->subsystem_vendor_id = PCI_VENDOR_ID_HUMUSOFT;
+ k->subsystem_id = PCI_DEVICE_ID_MF624;
+ dc->desc = "Humusoft MF624";
+ dc->props = mf624_properties;
+ dc->vmsd = &vmstate_mf624;
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ dc->reset = qdev_mf624_reset;
}
-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(),
- //}
+static const TypeInfo mf624_info = {
+ .name = TYPE_MF624_DEV,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof( mf624_state_t),
+ .class_init = mf624_class_init,
};
-static void mf624_register_device(void)
+static void mf624_register_types(void)
{
- printf("MF624 Loaded.\n");
- pci_qdev_register(&mf624_info);
+ type_register_static(&mf624_info);
}
-device_init(mf624_register_device)
+type_init(mf624_register_types)