2 * Humusoft MF624 DAQ card implementation
4 * Copyright (C) 2011 Rostislav Lisovy (lisovy@gmail.com)
6 * Licensed under GPLv2 license
10 #include "qemu-thread.h"
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <netinet/in.h>
16 #include <sys/socket.h>
18 /* #define QEMU_VER_ABOVE_015 */
20 #define PCI_VENDOR_ID_HUMUSOFT 0x186c
21 #define PCI_DEVICE_ID_MF624 0x0624
22 #define PCI_CLASS_SIGNAL_PROCESSING_CONTROLLER 0x1180
30 #define INTCSR_off 0x4C
31 #define GPIOC_off 0x54
34 #define ADDATA_off 0x00
35 #define ADCTRL_off 0x00
36 #define ADDATA1_off 0x02
37 #define ADDATA2_off 0x04
38 #define ADDATA3_off 0x06
39 #define ADDATA4_off 0x08
40 #define ADDATA5_off 0x0A
41 #define ADDATA6_off 0x0C
42 #define ADDATA7_off 0x0E
45 #define ADSTART_off 0x20
55 #define GPIOC_EOLC_mask (1 << 17)
56 #define GPIOC_LDAC_mask (1 << 23)
57 #define GPIOC_DACEN_mask (1 << 26)
89 // uint32_t CTR0STATUS;
98 #ifdef QEMU_VER_ABOVE_015
99 MemoryRegion mmio_bar0;
100 MemoryRegion mmio_bar2;
101 MemoryRegion mmio_bar4;
102 #endif /*QEMU_VER_ABOVE_015*/
109 /* The real voltage which is on inputs od A/D convertors.
110 Until new conversion is started, there is still old value in ADC registers*/
111 unsigned int real_world_AD0; //Value in "ADC internal" format
112 unsigned int real_world_AD1;
113 unsigned int real_world_AD2;
114 unsigned int real_world_AD3;
115 unsigned int real_world_AD4;
116 unsigned int real_world_AD5;
117 unsigned int real_world_AD6;
118 unsigned int real_world_AD7;
120 // for cpu_register_physical_memory() function
121 unsigned int BAR0_mem_table_index;
122 unsigned int BAR2_mem_table_index;
123 unsigned int BAR4_mem_table_index;
125 // Internal registers values
131 int ADDATA_FIFO[8]; //this array tells us which ADCs are being converted
132 unsigned int ADDATA_FIFO_POSITION; //ADDATA is FIFO register;
133 //We need to know, position in this FIFO =
134 //Which value will come next
137 int instance = 0; // Global variable shared between multiple mf624 devices
140 static int16_t volts_to_adinternal(double volt)
145 else if (volt < -10) {
149 return ((int16_t) ((volt*0x8000)/10))>>2;
152 static double dacinternal_to_volts(int16_t dacinternal)
154 return ((((double)dacinternal)/0x4000)*20.0 - 10.0);
157 //-----------------------------------------------------------------------------
159 /* Initialize register values due to MF624 manual */
160 static void mf624_init_registers(mf624_state_t* s)
162 #define INTCSR_default_value 0x000300
163 #define GPIOC_default_value 0x006C0 | (0x10 << 21) | (2 << 25)
165 //Initialize all registers to default values
166 s->BAR0.INTCSR = INTCSR_default_value;
167 s->BAR0.GPIOC = GPIOC_default_value;
168 s->BAR2.ADDATA = 0x0;
169 s->BAR2.ADCTRL = 0x0;
170 s->BAR2.ADDATA1 = 0x0;
171 s->BAR2.ADDATA2 = 0x0;
172 s->BAR2.ADDATA3 = 0x0;
173 s->BAR2.ADDATA4 = 0x0;
174 s->BAR2.ADDATA5 = 0x0;
175 s->BAR2.ADDATA6 = 0x0;
176 s->BAR2.ADDATA7 = 0x0;
180 s->BAR2.DA0 = 0x3FFF;
181 s->BAR2.DA1 = 0x3FFF;
182 s->BAR2.DA2 = 0x3FFF;
183 s->BAR2.DA3 = 0x3FFF;
184 s->BAR2.DA4 = 0x3FFF;
185 s->BAR2.DA5 = 0x3FFF;
186 s->BAR2.DA6 = 0x3FFF;
187 s->BAR2.DA7 = 0x3FFF;
189 s->ADDATA_FIFO_POSITION = 0;
192 /* After some widget's value is changed, new value is send via socket to Qemu */
193 static void socket_write(mf624_state_t *s, const char* reg, double val)
196 char write_buffer[256];
197 snprintf(write_buffer, 255, "%s=%f\n", reg, val);
199 status = write(s->socket_tmp, write_buffer, strlen(write_buffer));
202 printf("Error writing into socket. Is there no client connected?\n");
206 #define STRING_BUFF_SIZE 256
207 static void socket_read(mf624_state_t* dev)
209 // For parsing read instructions
210 char reg[STRING_BUFF_SIZE+1];
212 // For reading from socket
213 char read_buffer[STRING_BUFF_SIZE];
214 int received_length = 0;
219 memset(read_buffer, '\0', STRING_BUFF_SIZE);
220 received_length = read(dev->socket_tmp, read_buffer, STRING_BUFF_SIZE-1);
221 if (received_length < 0) {
226 if (received_length == 0) {
227 printf("Error while reading from socket. Client disconnected?\n");
231 // REG has "same size +1" as READ_BUFFER to avoid buffer overflow
232 status = sscanf(read_buffer, "%[A-Z0-9]=%f", reg, &val);
234 if(!strcmp(reg, "DIN")) {
237 else if(!strcmp(reg, "ADC0")) {
238 dev->real_world_AD0 = volts_to_adinternal(val);
240 else if(!strcmp(reg, "ADC1")) {
241 dev->real_world_AD1 = volts_to_adinternal(val);
243 else if(!strcmp(reg, "ADC2")) {
244 dev->real_world_AD2 = volts_to_adinternal(val);
246 else if(!strcmp(reg, "ADC3")) {
247 dev->real_world_AD3 = volts_to_adinternal(val);
249 else if(!strcmp(reg, "ADC4")) {
250 dev->real_world_AD4 = volts_to_adinternal(val);
252 else if(!strcmp(reg, "ADC5")) {
253 dev->real_world_AD5 = volts_to_adinternal(val);
255 else if(!strcmp(reg, "ADC6")) {
256 dev->real_world_AD6 = volts_to_adinternal(val);
258 else if(!strcmp(reg, "ADC7")) {
259 dev->real_world_AD7 = volts_to_adinternal(val);
262 printf("reg = %s; val = %f\n", reg, val);
269 static void* init_socket(void* ptr)
271 struct sockaddr_in addr_client;
272 struct sockaddr_in addr_srv;
276 mf624_state_t* dev = (mf624_state_t*) ptr;
278 dev->socket_tmp = -1;
281 dev->socket_srv = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
282 if (dev->socket_srv == -1) {
287 if (setsockopt(dev->socket_srv, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
288 perror("setsockopt()");
293 socklen_t len = sizeof(addr_srv);
294 memset(&addr_srv, 0, len);
295 addr_srv.sin_family = AF_INET;
296 addr_srv.sin_addr.s_addr = htonl(INADDR_ANY);
297 addr_srv.sin_port = htons(port);
298 if(bind(dev->socket_srv, (struct sockaddr*) &addr_srv, len) == -1) {
303 if (listen(dev->socket_srv, 5) == -1) {
310 printf("Waiting on port %d for MF624 client to connect\n", dev->port);
311 socklen_t len_client = sizeof(addr_client);
312 dev->socket_tmp = accept(dev->socket_srv, (struct sockaddr*) &addr_client, &len_client);
313 if (dev->socket_tmp == -1) {
317 printf("Client connected\n");
319 socket_read(dev); // should run forever if everything is OK;
320 // If error occurs (client disconnected), returns here
322 close(dev->socket_tmp);
328 //-----------------------------------------------------------------------------
330 static void mf624_BAR0_write32(void *opaque, target_phys_addr_t addr, uint32_t value)
332 mf624_state_t *s = opaque;
334 switch (addr % BAR0_size) {
336 s->BAR0.INTCSR = (value & 0x7FF) | INTCSR_default_value; // Only first 11 bits are writable
337 socket_write(s, "INTCSR", s->BAR0.INTCSR);
341 //Don't write anywhere else than into these two bits
342 s->BAR0.GPIOC = (value & (GPIOC_LDAC_mask | GPIOC_DACEN_mask)) | GPIOC_default_value;
343 socket_write(s, "GPIOC", s->BAR0.GPIOC);
345 //Is DAC enabled & Output enabled?
346 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
347 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
348 socket_write(s, "DA0", dacinternal_to_volts(s->BAR2.DA0));
349 socket_write(s, "DA1", dacinternal_to_volts(s->BAR2.DA1));
350 socket_write(s, "DA2", dacinternal_to_volts(s->BAR2.DA2));
351 socket_write(s, "DA3", dacinternal_to_volts(s->BAR2.DA3));
352 socket_write(s, "DA4", dacinternal_to_volts(s->BAR2.DA4));
353 socket_write(s, "DA5", dacinternal_to_volts(s->BAR2.DA5));
354 socket_write(s, "DA6", dacinternal_to_volts(s->BAR2.DA6));
355 socket_write(s, "DA7", dacinternal_to_volts(s->BAR2.DA7));
358 //Is output forced to GND?
359 if (!(s->BAR0.GPIOC & GPIOC_DACEN_mask))
362 socket_write(s, "DA0", dacinternal_to_volts(GND));
363 socket_write(s, "DA1", dacinternal_to_volts(GND));
364 socket_write(s, "DA2", dacinternal_to_volts(GND));
365 socket_write(s, "DA3", dacinternal_to_volts(GND));
366 socket_write(s, "DA4", dacinternal_to_volts(GND));
367 socket_write(s, "DA5", dacinternal_to_volts(GND));
368 socket_write(s, "DA6", dacinternal_to_volts(GND));
369 socket_write(s, "DA7", dacinternal_to_volts(GND));
374 printf("mf624_BAR0_write32(): addr = " TARGET_FMT_plx "; value = %d\n", addr, value);
380 static uint32_t mf624_BAR0_read32(void *opaque, target_phys_addr_t addr)
382 mf624_state_t *s = opaque;
384 switch (addr % BAR0_size) {
386 return s->BAR0.INTCSR;
389 return s->BAR0.GPIOC;
392 printf("mf624_BAR0_read32(): addr = " TARGET_FMT_plx "\n", addr);
398 static uint32_t mf624_BAR2_read16(void *opaque, target_phys_addr_t addr)
401 int ADDATA_val = 0xFFFF;
402 mf624_state_t *s = opaque;
404 switch (addr % BAR2_size) {
405 /* Reading from ADDATA FIFO register */
407 case ADDATA1_off: // Mirrored registers
414 if (!(s->BAR0.GPIOC & GPIOC_EOLC_mask)) { //Has the conversion already ended?
415 #define ADC_CHANNELS 8
416 for(i = s->ADDATA_FIFO_POSITION; i < ADC_CHANNELS; i ++) {
417 if (s->BAR2.ADCTRL & (1 << i)) {
418 s->ADDATA_FIFO_POSITION = i; // Move to next AD to be read
422 switch (s->ADDATA_FIFO_POSITION)
425 ADDATA_val = s->BAR2.ADDATA;
428 ADDATA_val = s->BAR2.ADDATA1;
431 ADDATA_val = s->BAR2.ADDATA2;
434 ADDATA_val = s->BAR2.ADDATA3;
437 ADDATA_val = s->BAR2.ADDATA4;
440 ADDATA_val = s->BAR2.ADDATA5;
443 ADDATA_val = s->BAR2.ADDATA6;
446 ADDATA_val = s->BAR2.ADDATA7;
448 default: // restart counter
449 s->ADDATA_FIFO_POSITION = 0;
450 ADDATA_val = s->BAR2.ADDATA;
453 s->ADDATA_FIFO_POSITION ++;
456 return 0xFFFF; // Semirandom value
462 /* A/D Conversion Start. Reading this register triggers A/D
463 conversion for all channels selected in ADCTRL. */
465 s->BAR0.GPIOC |= GPIOC_EOLC_mask; // Conversion in progress
466 s->ADDATA_FIFO_POSITION = 0;
467 for (i = 0; i < 5000; i++)
468 ; // Small delay simulating real conversion
470 // Check before assignement, if particular ADC is enabled
471 s->BAR2.ADDATA = (s->BAR2.ADCTRL & (1 << 0)) ? s->real_world_AD0 : s->BAR2.ADDATA;
472 s->BAR2.ADDATA1 = (s->BAR2.ADCTRL & (1 << 1)) ? s->real_world_AD1 : s->BAR2.ADDATA1;
473 s->BAR2.ADDATA2 = (s->BAR2.ADCTRL & (1 << 2)) ? s->real_world_AD2 : s->BAR2.ADDATA2;
474 s->BAR2.ADDATA3 = (s->BAR2.ADCTRL & (1 << 3)) ? s->real_world_AD3 : s->BAR2.ADDATA3;
475 s->BAR2.ADDATA4 = (s->BAR2.ADCTRL & (1 << 4)) ? s->real_world_AD4 : s->BAR2.ADDATA4;
476 s->BAR2.ADDATA5 = (s->BAR2.ADCTRL & (1 << 5)) ? s->real_world_AD5 : s->BAR2.ADDATA5;
477 s->BAR2.ADDATA6 = (s->BAR2.ADCTRL & (1 << 6)) ? s->real_world_AD6 : s->BAR2.ADDATA6;
478 s->BAR2.ADDATA7 = (s->BAR2.ADCTRL & (1 << 7)) ? s->real_world_AD7 : s->BAR2.ADDATA7;
480 //All channels converted
481 s->BAR0.GPIOC &= ~ GPIOC_EOLC_mask;
483 return 0xFFFF; // Semirandom value
486 printf("mf624_BAR2_read16(): addr = " TARGET_FMT_plx "\n", addr);
492 static void mf624_BAR2_write16(void *opaque, target_phys_addr_t addr, uint32_t value)
494 mf624_state_t *s = opaque;
496 switch (addr % BAR2_size) {
498 s->BAR2.ADCTRL = value;
499 socket_write(s, "ADCTRL", s->BAR2.ADCTRL);
503 s->BAR2.DOUT = value;
504 socket_write(s, "DOUT", s->BAR2.DOUT);
509 //Is DAC enabled & Output enabled?
510 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
511 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
512 socket_write(s, "DA0", dacinternal_to_volts(s->BAR2.DA0));
518 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
519 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
520 socket_write(s, "DA1", dacinternal_to_volts(s->BAR2.DA1));
526 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
527 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
528 socket_write(s, "DA2", dacinternal_to_volts(s->BAR2.DA2));
534 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
535 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
536 socket_write(s, "DA3", dacinternal_to_volts(s->BAR2.DA3));
542 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
543 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
544 socket_write(s, "DA4", dacinternal_to_volts(s->BAR2.DA4));
550 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
551 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
552 socket_write(s, "DA5", dacinternal_to_volts(s->BAR2.DA5));
558 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
559 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
560 socket_write(s, "DA6", dacinternal_to_volts(s->BAR2.DA6));
566 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
567 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
568 socket_write(s, "DA7", dacinternal_to_volts(s->BAR2.DA7));
573 printf("mf624_BAR2_write16(): addr = " TARGET_FMT_plx "; value = %d\n", addr, value);
579 static void mf624_BAR4_write32(void *opaque, target_phys_addr_t addr, uint32_t value)
581 printf("mf624_BAR4_write32(): addr = " TARGET_FMT_plx "; value = %d\n", addr, value);
584 static uint32_t mf624_BAR4_read32(void *opaque, target_phys_addr_t addr)
586 printf("mf624_BAR4_read32(): addr = " TARGET_FMT_plx "\n", addr);
590 //-----------------------------------------------------------------------------
592 #ifdef QEMU_VER_ABOVE_015
594 static const MemoryRegionOps mf624_BAR0_mmio_ops = {
607 .endianness = DEVICE_LITTLE_ENDIAN,
610 static const MemoryRegionOps mf624_BAR2_mmio_ops = {
623 .endianness = DEVICE_LITTLE_ENDIAN,
626 static const MemoryRegionOps mf624_BAR4_mmio_ops = {
639 .endianness = DEVICE_LITTLE_ENDIAN,
642 #else /*QEMU_VER_ABOVE_015*/
644 static CPUReadMemoryFunc * const mf624_BAR0_read[3] = {
650 static CPUWriteMemoryFunc * const mf624_BAR0_write[3] = {
656 static CPUReadMemoryFunc * const mf624_BAR2_read[3] = {
662 static CPUWriteMemoryFunc * const mf624_BAR2_write[3] = {
668 static CPUReadMemoryFunc * const mf624_BAR4_read[3] = {
674 static CPUWriteMemoryFunc * const mf624_BAR4_write[3] = {
681 //-----------------------------------------------------------------------------
683 static void mf624_map(PCIDevice *pci_dev, int region_num,
684 pcibus_t addr, pcibus_t size, int type)
686 mf624_state_t *s = DO_UPCAST(mf624_state_t, dev, pci_dev);
688 switch (region_num) {
690 //printf("reg%d, addr = %x\n", region_num, addr);
691 cpu_register_physical_memory(addr + 0x0, BAR0_size, s->BAR0_mem_table_index);
694 //printf("reg%d, addr = %x\n", region_num, addr);
695 cpu_register_physical_memory(addr + 0x0, BAR2_size, s->BAR2_mem_table_index);
698 //printf("reg%d, addr = %x\n", region_num, addr);
699 cpu_register_physical_memory(addr + 0x0, BAR4_size, s->BAR4_mem_table_index);
707 #endif /*QEMU_VER_ABOVE_015*/
709 #define DEFAULT_PORT 55555
710 static int pci_mf624_init(PCIDevice *pci_dev)
712 mf624_state_t *s = DO_UPCAST(mf624_state_t, dev, pci_dev); //alocation of mf624_state_t
714 QemuThread socket_thread;
716 printf("MF624 Loaded.\n");
718 if (s->port == DEFAULT_PORT) {
719 s->port += instance; // Each instance of the same device should have another port number
723 //Set all internal registers to default values
724 mf624_init_registers(s);
726 pci_conf = s->dev.config;
727 pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_HUMUSOFT);
728 pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_MF624);
729 pci_config_set_class(pci_conf, PCI_CLASS_SIGNAL_PROCESSING_CONTROLLER);
730 pci_conf[PCI_SUBSYSTEM_VENDOR_ID] = PCI_VENDOR_ID_HUMUSOFT & 0xff;
731 pci_conf[PCI_SUBSYSTEM_VENDOR_ID + 1] = PCI_VENDOR_ID_HUMUSOFT >> 8;
732 pci_conf[PCI_SUBSYSTEM_ID] = PCI_DEVICE_ID_MF624 & 0xff;
733 pci_conf[PCI_SUBSYSTEM_ID + 1] = PCI_DEVICE_ID_MF624 >> 8;
735 pci_conf[PCI_INTERRUPT_PIN] = 0x1; // interrupt pin 0
737 #ifdef QEMU_VER_ABOVE_015
738 memory_region_init_io(&s->mmio_bar0, &mf624_BAR0_mmio_ops, s, "mf624_bar0", BAR0_size);
739 memory_region_init_io(&s->mmio_bar2, &mf624_BAR2_mmio_ops, s, "mf624_bar2", BAR2_size);
740 memory_region_init_io(&s->mmio_bar4, &mf624_BAR4_mmio_ops, s, "mf624_bar4", BAR4_size);
741 pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio_bar0);
742 pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio_bar2);
743 pci_register_bar(&s->dev, 4, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio_bar4);
744 #else QEMU_VER_ABOVE_015
745 s->BAR0_mem_table_index = cpu_register_io_memory(mf624_BAR0_read,
748 DEVICE_NATIVE_ENDIAN);
750 s->BAR2_mem_table_index = cpu_register_io_memory(mf624_BAR2_read,
753 DEVICE_NATIVE_ENDIAN);
755 s->BAR4_mem_table_index = cpu_register_io_memory(mf624_BAR4_read,
758 DEVICE_NATIVE_ENDIAN);
760 pci_register_bar(&s->dev, 0, BAR0_size, PCI_BASE_ADDRESS_SPACE_MEMORY, mf624_map);
761 pci_register_bar(&s->dev, 2, BAR2_size, PCI_BASE_ADDRESS_SPACE_MEMORY, mf624_map);
762 pci_register_bar(&s->dev, 4, BAR4_size, PCI_BASE_ADDRESS_SPACE_MEMORY, mf624_map);
763 #endif QEMU_VER_ABOVE_015
765 //Create thread, which will be blocked on reading from socket (connected to "I/O GUI")
766 qemu_thread_create(&socket_thread, init_socket, (void*) s);
770 static int pci_mf624_exit(PCIDevice *pci_dev)
772 mf624_state_t *s = DO_UPCAST(mf624_state_t, dev, pci_dev);
773 close(s->socket_srv);
779 static PCIDeviceInfo mf624_info = {
780 .qdev.name = "mf624",
781 .qdev.size = sizeof(mf624_state_t),
782 .init = pci_mf624_init,
783 .exit = pci_mf624_exit,
784 .qdev.props = (Property[]) {
785 DEFINE_PROP_UINT32("port", mf624_state_t, port, DEFAULT_PORT),
786 DEFINE_PROP_END_OF_LIST(),
790 static void mf624_register_device(void)
792 pci_qdev_register(&mf624_info);
795 device_init(mf624_register_device)