2 * Humusoft MF624 DAQ card implementation
4 * Copyright (C) 2011 Rostislav Lisovy (lisovy@gmail.com)
6 * Licensed under GPLv2 license
9 #include "hw/pci/pci.h"
10 #include "qemu/event_notifier.h"
11 #include "qemu/osdep.h"
12 #include "qemu/thread.h"
13 #include "qemu/sockets.h"
14 #include "sysemu/char.h"
16 #define TYPE_MF624_DEV "mf624"
18 #define MF624_DEV(obj) \
19 OBJECT_CHECK(mf624_state_t, (obj), TYPE_MF624_DEV)
21 #define PCI_VENDOR_ID_HUMUSOFT 0x186c
22 #define PCI_DEVICE_ID_MF624 0x0624
23 #define PCI_CLASS_SIGNAL_PROCESSING_CONTROLLER 0x1180
31 #define INTCSR_off 0x4C
32 #define GPIOC_off 0x54
35 #define ADDATA_off 0x00
36 #define ADCTRL_off 0x00
37 #define ADDATA1_off 0x02
38 #define ADDATA2_off 0x04
39 #define ADDATA3_off 0x06
40 #define ADDATA4_off 0x08
41 #define ADDATA5_off 0x0A
42 #define ADDATA6_off 0x0C
43 #define ADDATA7_off 0x0E
46 #define ADSTART_off 0x20
56 #define GPIOC_EOLC_mask (1 << 17)
57 #define GPIOC_LDAC_mask (1 << 23)
58 #define GPIOC_DACEN_mask (1 << 26)
90 // uint32_t CTR0STATUS;
99 MemoryRegion mmio_bar0;
100 MemoryRegion mmio_bar2;
101 MemoryRegion mmio_bar4;
104 QemuThread socket_thread;
110 /* The real voltage which is on inputs od A/D convertors.
111 Until new conversion is started, there is still old value in ADC registers*/
112 unsigned int real_world_AD0; //Value in "ADC internal" format
113 unsigned int real_world_AD1;
114 unsigned int real_world_AD2;
115 unsigned int real_world_AD3;
116 unsigned int real_world_AD4;
117 unsigned int real_world_AD5;
118 unsigned int real_world_AD6;
119 unsigned int real_world_AD7;
121 // for cpu_register_physical_memory() function
122 unsigned int BAR0_mem_table_index;
123 unsigned int BAR2_mem_table_index;
124 unsigned int BAR4_mem_table_index;
126 // Internal registers values
132 int ADDATA_FIFO[8]; //this array tells us which ADCs are being converted
133 unsigned int ADDATA_FIFO_POSITION; //ADDATA is FIFO register;
134 //We need to know, position in this FIFO =
135 //Which value will come next
138 int instance = 0; // Global variable shared between multiple mf624 devices
141 static int16_t volts_to_adinternal(double volt)
146 else if (volt < -10) {
150 return ((int16_t) ((volt*0x8000)/10))>>2;
153 static double dacinternal_to_volts(int16_t dacinternal)
155 return ((((double)dacinternal)/0x4000)*20.0 - 10.0);
158 //-----------------------------------------------------------------------------
160 /* Initialize register values due to MF624 manual */
161 static void mf624_init_registers(mf624_state_t* s)
163 #define INTCSR_default_value 0x000300
164 #define GPIOC_default_value 0x006C0 | (0x10 << 21) | (2 << 25)
166 //Initialize all registers to default values
167 s->BAR0.INTCSR = INTCSR_default_value;
168 s->BAR0.GPIOC = GPIOC_default_value;
169 s->BAR2.ADDATA = 0x0;
170 s->BAR2.ADCTRL = 0x0;
171 s->BAR2.ADDATA1 = 0x0;
172 s->BAR2.ADDATA2 = 0x0;
173 s->BAR2.ADDATA3 = 0x0;
174 s->BAR2.ADDATA4 = 0x0;
175 s->BAR2.ADDATA5 = 0x0;
176 s->BAR2.ADDATA6 = 0x0;
177 s->BAR2.ADDATA7 = 0x0;
181 s->BAR2.DA0 = 0x3FFF;
182 s->BAR2.DA1 = 0x3FFF;
183 s->BAR2.DA2 = 0x3FFF;
184 s->BAR2.DA3 = 0x3FFF;
185 s->BAR2.DA4 = 0x3FFF;
186 s->BAR2.DA5 = 0x3FFF;
187 s->BAR2.DA6 = 0x3FFF;
188 s->BAR2.DA7 = 0x3FFF;
190 s->ADDATA_FIFO_POSITION = 0;
194 mf624_reset(void *opaque)
196 mf624_state_t *s = (mf624_state_t *)opaque;
198 mf624_init_registers(s);
201 /* After some widget's value is changed, new value is send via socket to Qemu */
202 static void socket_write(mf624_state_t *s, const char* reg, double val)
205 char write_buffer[256];
206 snprintf(write_buffer, 255, "%s=%f\n", reg, val);
208 status = write(s->socket_tmp, write_buffer, strlen(write_buffer));
211 printf("Error writing into socket. Is there no client connected?\n");
215 #define STRING_BUFF_SIZE 256
216 static void socket_read(mf624_state_t* dev)
218 // For parsing read instructions
219 char reg[STRING_BUFF_SIZE+1];
221 // For reading from socket
222 char read_buffer[STRING_BUFF_SIZE];
223 int received_length = 0;
228 memset(read_buffer, '\0', STRING_BUFF_SIZE);
229 received_length = read(dev->socket_tmp, read_buffer, STRING_BUFF_SIZE-1);
230 if (received_length < 0) {
235 if (received_length == 0) {
236 printf("Error while reading from socket. Client disconnected?\n");
240 // REG has "same size +1" as READ_BUFFER to avoid buffer overflow
241 status = sscanf(read_buffer, "%[A-Z0-9]=%f", reg, &val);
243 if(!strcmp(reg, "DIN")) {
246 else if(!strcmp(reg, "ADC0")) {
247 dev->real_world_AD0 = volts_to_adinternal(val);
249 else if(!strcmp(reg, "ADC1")) {
250 dev->real_world_AD1 = volts_to_adinternal(val);
252 else if(!strcmp(reg, "ADC2")) {
253 dev->real_world_AD2 = volts_to_adinternal(val);
255 else if(!strcmp(reg, "ADC3")) {
256 dev->real_world_AD3 = volts_to_adinternal(val);
258 else if(!strcmp(reg, "ADC4")) {
259 dev->real_world_AD4 = volts_to_adinternal(val);
261 else if(!strcmp(reg, "ADC5")) {
262 dev->real_world_AD5 = volts_to_adinternal(val);
264 else if(!strcmp(reg, "ADC6")) {
265 dev->real_world_AD6 = volts_to_adinternal(val);
267 else if(!strcmp(reg, "ADC7")) {
268 dev->real_world_AD7 = volts_to_adinternal(val);
271 printf("reg = %s; val = %f\n", reg, val);
278 static void* init_socket(void* ptr)
280 struct sockaddr_in addr_client;
281 struct sockaddr_in addr_srv;
285 mf624_state_t* dev = (mf624_state_t*) ptr;
287 dev->socket_tmp = -1;
290 dev->socket_srv = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
291 if (dev->socket_srv == -1) {
296 if (setsockopt(dev->socket_srv, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
297 perror("setsockopt()");
302 socklen_t len = sizeof(addr_srv);
303 memset(&addr_srv, 0, len);
304 addr_srv.sin_family = AF_INET;
305 addr_srv.sin_addr.s_addr = htonl(INADDR_ANY);
306 addr_srv.sin_port = htons(port);
307 if(bind(dev->socket_srv, (struct sockaddr*) &addr_srv, len) == -1) {
312 if (listen(dev->socket_srv, 5) == -1) {
319 printf("Waiting on port %d for MF624 client to connect\n", dev->port);
320 socklen_t len_client = sizeof(addr_client);
321 dev->socket_tmp = accept(dev->socket_srv, (struct sockaddr*) &addr_client, &len_client);
322 if (dev->socket_tmp == -1) {
327 printf("Client connected\n");
329 socket_read(dev); // should run forever if everything is OK;
330 // If error occurs (client disconnected), returns here
332 close(dev->socket_tmp);
338 //-----------------------------------------------------------------------------
340 static void mf624_BAR0_write32(void *opaque, hwaddr addr, uint64_t value, unsigned size)
342 mf624_state_t *s = opaque;
344 switch (addr % BAR0_size) {
346 s->BAR0.INTCSR = (value & 0x7FF) | INTCSR_default_value; // Only first 11 bits are writable
347 socket_write(s, "INTCSR", s->BAR0.INTCSR);
351 //Don't write anywhere else than into these two bits
352 s->BAR0.GPIOC = (value & (GPIOC_LDAC_mask | GPIOC_DACEN_mask)) | GPIOC_default_value;
353 socket_write(s, "GPIOC", s->BAR0.GPIOC);
355 //Is DAC enabled & Output enabled?
356 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
357 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
358 socket_write(s, "DA0", dacinternal_to_volts(s->BAR2.DA0));
359 socket_write(s, "DA1", dacinternal_to_volts(s->BAR2.DA1));
360 socket_write(s, "DA2", dacinternal_to_volts(s->BAR2.DA2));
361 socket_write(s, "DA3", dacinternal_to_volts(s->BAR2.DA3));
362 socket_write(s, "DA4", dacinternal_to_volts(s->BAR2.DA4));
363 socket_write(s, "DA5", dacinternal_to_volts(s->BAR2.DA5));
364 socket_write(s, "DA6", dacinternal_to_volts(s->BAR2.DA6));
365 socket_write(s, "DA7", dacinternal_to_volts(s->BAR2.DA7));
368 //Is output forced to GND?
369 if (!(s->BAR0.GPIOC & GPIOC_DACEN_mask))
372 socket_write(s, "DA0", dacinternal_to_volts(GND));
373 socket_write(s, "DA1", dacinternal_to_volts(GND));
374 socket_write(s, "DA2", dacinternal_to_volts(GND));
375 socket_write(s, "DA3", dacinternal_to_volts(GND));
376 socket_write(s, "DA4", dacinternal_to_volts(GND));
377 socket_write(s, "DA5", dacinternal_to_volts(GND));
378 socket_write(s, "DA6", dacinternal_to_volts(GND));
379 socket_write(s, "DA7", dacinternal_to_volts(GND));
384 printf("mf624_BAR0_write32(): addr = " TARGET_FMT_plx
385 "; value = 0x%" PRIx64 "\n", addr, value);
390 static uint64_t mf624_BAR0_read32(void *opaque, hwaddr addr, unsigned size)
392 mf624_state_t *s = opaque;
394 switch (addr % BAR0_size) {
396 return s->BAR0.INTCSR;
399 return s->BAR0.GPIOC;
402 printf("mf624_BAR0_read32(): addr = "
403 TARGET_FMT_plx "\n", addr);
408 static uint64_t mf624_BAR2_read16(void *opaque, hwaddr addr, unsigned size)
411 int ADDATA_val = 0xFFFF;
412 mf624_state_t *s = opaque;
414 switch (addr % BAR2_size) {
415 /* Reading from ADDATA FIFO register */
417 case ADDATA1_off: // Mirrored registers
424 if (!(s->BAR0.GPIOC & GPIOC_EOLC_mask)) { //Has the conversion already ended?
425 #define ADC_CHANNELS 8
426 for(i = s->ADDATA_FIFO_POSITION; i < ADC_CHANNELS; i ++) {
427 if (s->BAR2.ADCTRL & (1 << i)) {
428 s->ADDATA_FIFO_POSITION = i; // Move to next AD to be read
432 switch (s->ADDATA_FIFO_POSITION)
435 ADDATA_val = s->BAR2.ADDATA;
438 ADDATA_val = s->BAR2.ADDATA1;
441 ADDATA_val = s->BAR2.ADDATA2;
444 ADDATA_val = s->BAR2.ADDATA3;
447 ADDATA_val = s->BAR2.ADDATA4;
450 ADDATA_val = s->BAR2.ADDATA5;
453 ADDATA_val = s->BAR2.ADDATA6;
456 ADDATA_val = s->BAR2.ADDATA7;
458 default: // restart counter
459 s->ADDATA_FIFO_POSITION = 0;
460 ADDATA_val = s->BAR2.ADDATA;
463 s->ADDATA_FIFO_POSITION ++;
466 return 0xFFFF; // Semirandom value
472 /* A/D Conversion Start. Reading this register triggers A/D
473 conversion for all channels selected in ADCTRL. */
475 s->BAR0.GPIOC |= GPIOC_EOLC_mask; // Conversion in progress
476 s->ADDATA_FIFO_POSITION = 0;
477 for (i = 0; i < 5000; i++)
478 ; // Small delay simulating real conversion
480 // Check before assignement, if particular ADC is enabled
481 s->BAR2.ADDATA = (s->BAR2.ADCTRL & (1 << 0)) ? s->real_world_AD0 : s->BAR2.ADDATA;
482 s->BAR2.ADDATA1 = (s->BAR2.ADCTRL & (1 << 1)) ? s->real_world_AD1 : s->BAR2.ADDATA1;
483 s->BAR2.ADDATA2 = (s->BAR2.ADCTRL & (1 << 2)) ? s->real_world_AD2 : s->BAR2.ADDATA2;
484 s->BAR2.ADDATA3 = (s->BAR2.ADCTRL & (1 << 3)) ? s->real_world_AD3 : s->BAR2.ADDATA3;
485 s->BAR2.ADDATA4 = (s->BAR2.ADCTRL & (1 << 4)) ? s->real_world_AD4 : s->BAR2.ADDATA4;
486 s->BAR2.ADDATA5 = (s->BAR2.ADCTRL & (1 << 5)) ? s->real_world_AD5 : s->BAR2.ADDATA5;
487 s->BAR2.ADDATA6 = (s->BAR2.ADCTRL & (1 << 6)) ? s->real_world_AD6 : s->BAR2.ADDATA6;
488 s->BAR2.ADDATA7 = (s->BAR2.ADCTRL & (1 << 7)) ? s->real_world_AD7 : s->BAR2.ADDATA7;
490 //All channels converted
491 s->BAR0.GPIOC &= ~ GPIOC_EOLC_mask;
493 return 0xFFFF; // Semirandom value
496 printf("mf624_BAR2_read16(): addr = "
497 TARGET_FMT_plx "\n", addr);
502 static void mf624_BAR2_write16(void *opaque, hwaddr addr, uint64_t value, unsigned size)
504 mf624_state_t *s = opaque;
506 switch (addr % BAR2_size) {
508 s->BAR2.ADCTRL = value;
509 socket_write(s, "ADCTRL", s->BAR2.ADCTRL);
513 s->BAR2.DOUT = value;
514 socket_write(s, "DOUT", s->BAR2.DOUT);
519 //Is DAC enabled & Output enabled?
520 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
521 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
522 socket_write(s, "DA0", dacinternal_to_volts(s->BAR2.DA0));
528 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
529 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
530 socket_write(s, "DA1", dacinternal_to_volts(s->BAR2.DA1));
536 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
537 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
538 socket_write(s, "DA2", dacinternal_to_volts(s->BAR2.DA2));
544 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
545 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
546 socket_write(s, "DA3", dacinternal_to_volts(s->BAR2.DA3));
552 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
553 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
554 socket_write(s, "DA4", dacinternal_to_volts(s->BAR2.DA4));
560 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
561 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
562 socket_write(s, "DA5", dacinternal_to_volts(s->BAR2.DA5));
568 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
569 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
570 socket_write(s, "DA6", dacinternal_to_volts(s->BAR2.DA6));
576 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
577 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
578 socket_write(s, "DA7", dacinternal_to_volts(s->BAR2.DA7));
583 printf("mf624_BAR2_write16(): addr = " TARGET_FMT_plx
584 "; value = 0x%" PRIx64 "\n", addr, value);
589 static void mf624_BAR4_write32(void *opaque, hwaddr addr, uint64_t value, unsigned size)
591 printf("mf624_BAR4_write32(): addr = " TARGET_FMT_plx
592 "; value = 0x%" PRIx64 "\n", addr, value);
595 static uint64_t mf624_BAR4_read32(void *opaque, hwaddr addr, unsigned size)
597 printf("mf624_BAR4_read32(): addr = " TARGET_FMT_plx "\n", addr);
601 //-----------------------------------------------------------------------------
603 static const MemoryRegionOps mf624_BAR0_mmio_ops = {
604 .read = mf624_BAR0_read32,
605 .write = mf624_BAR0_write32,
606 .endianness = DEVICE_LITTLE_ENDIAN,
608 .min_access_size = 4,
609 .max_access_size = 4,
613 static const MemoryRegionOps mf624_BAR2_mmio_ops = {
614 .read = mf624_BAR2_read16,
615 .write = mf624_BAR2_write16,
616 .endianness = DEVICE_LITTLE_ENDIAN,
618 .min_access_size = 2,
619 .max_access_size = 2,
623 static const MemoryRegionOps mf624_BAR4_mmio_ops = {
624 .read = mf624_BAR4_read32,
625 .write = mf624_BAR4_write32,
626 .endianness = DEVICE_LITTLE_ENDIAN,
628 .min_access_size = 4,
629 .max_access_size = 4,
633 #define DEFAULT_PORT 55555
634 static int mf624_init(PCIDevice *pci_dev)
636 mf624_state_t *s = MF624_DEV(pci_dev); //alocation of mf624_state_t
639 if (s->port == DEFAULT_PORT) {
640 s->port += instance; // Each instance of the same device should have another port number
644 //Set all internal registers to default values
645 mf624_init_registers(s);
647 pci_conf = pci_dev->config;
648 pci_conf[PCI_INTERRUPT_PIN] = 0x1; // interrupt pin 0
650 s->irq = pci_allocate_irq(&s->dev);
652 qemu_register_reset(mf624_reset, s);
654 memory_region_init_io(&s->mmio_bar0, OBJECT(s), &mf624_BAR0_mmio_ops, s, "mf624_bar0", BAR0_size);
655 memory_region_init_io(&s->mmio_bar2, OBJECT(s), &mf624_BAR2_mmio_ops, s, "mf624_bar2", BAR2_size);
656 memory_region_init_io(&s->mmio_bar4, OBJECT(s), &mf624_BAR4_mmio_ops, s, "mf624_bar4", BAR4_size);
657 pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio_bar0);
658 pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio_bar2);
659 pci_register_bar(&s->dev, 4, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio_bar4);
661 //Create thread, which will be blocked on reading from socket (connected to "I/O GUI")
663 qemu_thread_create(&s->socket_thread, "mf624_io_thread",
664 init_socket, (void*) s, QEMU_THREAD_JOINABLE);
668 static void qdev_mf624_reset(DeviceState *dev)
670 mf624_state_t *s = MF624_DEV(dev);
671 mf624_init_registers(s);
674 static void mf624_exit(PCIDevice *pci_dev)
676 mf624_state_t *s = MF624_DEV(pci_dev);
678 close(s->socket_srv);
680 qemu_thread_join(&s->socket_thread);
682 qemu_unregister_reset(mf624_reset, s);
684 memory_region_destroy(&s->mmio_bar0);
685 memory_region_destroy(&s->mmio_bar2);
686 memory_region_destroy(&s->mmio_bar4);
688 qemu_free_irq(s->irq);
691 static const VMStateDescription vmstate_mf624 = {
694 .minimum_version_id = 1,
695 .minimum_version_id_old = 1,
697 .fields = (VMStateField[]) {
698 VMSTATE_PCI_DEVICE(dev, mf624_state_t),
699 VMSTATE_UINT32(port, mf624_state_t),
700 VMSTATE_END_OF_LIST()
705 static Property mf624_properties[] = {
706 DEFINE_PROP_UINT32("port", mf624_state_t, port, DEFAULT_PORT),
707 DEFINE_PROP_END_OF_LIST(),
710 static void mf624_class_init(ObjectClass *klass, void *data)
712 DeviceClass *dc = DEVICE_CLASS(klass);
713 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
715 k->init = mf624_init;
716 k->exit = mf624_exit;
717 k->vendor_id = PCI_VENDOR_ID_HUMUSOFT;
718 k->device_id = PCI_DEVICE_ID_MF624;
720 k->class_id = PCI_CLASS_SIGNAL_PROCESSING_CONTROLLER;
721 k->subsystem_vendor_id = PCI_VENDOR_ID_HUMUSOFT;
722 k->subsystem_id = PCI_DEVICE_ID_MF624;
723 dc->desc = "Humusoft MF624";
724 dc->props = mf624_properties;
725 dc->vmsd = &vmstate_mf624;
726 set_bit(DEVICE_CATEGORY_MISC, dc->categories);
727 dc->reset = qdev_mf624_reset;
730 static const TypeInfo mf624_info = {
731 .name = TYPE_MF624_DEV,
732 .parent = TYPE_PCI_DEVICE,
733 .instance_size = sizeof( mf624_state_t),
734 .class_init = mf624_class_init,
737 static void mf624_register_types(void)
739 type_register_static(&mf624_info);
742 type_init(mf624_register_types)