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 mf624_instance; /* Global variable shared between multiple mf624 devices */
141 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;
193 mf624_reset(void *opaque)
195 mf624_state_t *s = (mf624_state_t *)opaque;
197 mf624_init_registers(s);
200 /* After some widget's value is changed, new value is send via socket to QEMU */
201 static void socket_write(mf624_state_t *s, const char* reg, double val)
204 char write_buffer[256];
205 snprintf(write_buffer, 255, "%s=%f\n", reg, val);
207 status = write(s->socket_tmp, write_buffer, strlen(write_buffer));
209 /* perror("write()"); */
210 printf("Error writing into socket. Is there no client connected?\n");
214 #define STRING_BUFF_SIZE 256
215 static void socket_read(mf624_state_t *dev)
217 /* For parsing read instructions */
218 char reg[STRING_BUFF_SIZE+1];
220 /* For reading from socket */
221 char read_buffer[STRING_BUFF_SIZE];
222 int received_length = 0;
227 memset(read_buffer, '\0', STRING_BUFF_SIZE);
229 received_length = read(dev->socket_tmp, read_buffer,
232 if (received_length < 0) {
237 if (received_length == 0) {
238 printf("Error while reading from socket. Client disconnected?\n");
242 /* REG has "same size +1" as READ_BUFFER to avoid buffer overflow */
243 status = sscanf(read_buffer, "%[A-Z0-9]=%f", reg, &val);
245 if (!strcmp(reg, "DIN")) {
247 } else if (!strcmp(reg, "ADC0")) {
248 dev->real_world_AD0 = volts_to_adinternal(val);
249 } else if (!strcmp(reg, "ADC1")) {
250 dev->real_world_AD1 = volts_to_adinternal(val);
251 } else if (!strcmp(reg, "ADC2")) {
252 dev->real_world_AD2 = volts_to_adinternal(val);
253 } else if (!strcmp(reg, "ADC3")) {
254 dev->real_world_AD3 = volts_to_adinternal(val);
255 } else if (!strcmp(reg, "ADC4")) {
256 dev->real_world_AD4 = volts_to_adinternal(val);
257 } else if (!strcmp(reg, "ADC5")) {
258 dev->real_world_AD5 = volts_to_adinternal(val);
259 } else if (!strcmp(reg, "ADC6")) {
260 dev->real_world_AD6 = volts_to_adinternal(val);
261 } else if (!strcmp(reg, "ADC7")) {
262 dev->real_world_AD7 = volts_to_adinternal(val);
264 printf("reg = %s; val = %f\n", reg, val);
271 static void *init_socket(void * ptr)
273 struct sockaddr_in addr_client;
274 struct sockaddr_in addr_srv;
278 mf624_state_t *dev = (mf624_state_t *) ptr;
280 dev->socket_tmp = -1;
283 dev->socket_srv = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
284 if (dev->socket_srv == -1) {
289 if (setsockopt(dev->socket_srv,
290 SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
291 perror("setsockopt()");
296 socklen_t len = sizeof(addr_srv);
297 memset(&addr_srv, 0, len);
298 addr_srv.sin_family = AF_INET;
299 addr_srv.sin_addr.s_addr = htonl(INADDR_ANY);
300 addr_srv.sin_port = htons(port);
301 if (bind(dev->socket_srv, (struct sockaddr *) &addr_srv, len) == -1) {
306 if (listen(dev->socket_srv, 5) == -1) {
313 printf("Waiting on port %d for MF624 client to connect\n", dev->port);
314 socklen_t len_client = sizeof(addr_client);
315 dev->socket_tmp = accept(dev->socket_srv,
316 (struct sockaddr *) &addr_client, &len_client);
317 if (dev->socket_tmp == -1) {
322 printf("Client connected\n");
324 socket_read(dev); /* should run forever if everything is OK; */
325 /* If error occurs (client disconnected), returns here */
327 close(dev->socket_tmp);
333 /*----------------------------------------------------------------------------*/
335 static void mf624_BAR0_write32(void *opaque, hwaddr addr, uint64_t value, unsigned size)
337 mf624_state_t *s = opaque;
339 switch (addr % BAR0_size) {
341 s->BAR0.INTCSR = (value & 0x7FF) | INTCSR_default_value; /* Only first 11 bits are writable */
342 socket_write(s, "INTCSR", s->BAR0.INTCSR);
346 /* Don't write anywhere else than into these two bits */
347 s->BAR0.GPIOC = (value & (GPIOC_LDAC_mask | GPIOC_DACEN_mask)) |
350 socket_write(s, "GPIOC", s->BAR0.GPIOC);
352 /* Is DAC enabled & Output enabled? */
353 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
354 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
355 socket_write(s, "DA0", dacinternal_to_volts(s->BAR2.DA0));
356 socket_write(s, "DA1", dacinternal_to_volts(s->BAR2.DA1));
357 socket_write(s, "DA2", dacinternal_to_volts(s->BAR2.DA2));
358 socket_write(s, "DA3", dacinternal_to_volts(s->BAR2.DA3));
359 socket_write(s, "DA4", dacinternal_to_volts(s->BAR2.DA4));
360 socket_write(s, "DA5", dacinternal_to_volts(s->BAR2.DA5));
361 socket_write(s, "DA6", dacinternal_to_volts(s->BAR2.DA6));
362 socket_write(s, "DA7", dacinternal_to_volts(s->BAR2.DA7));
365 /* Is output forced to GND? */
366 if (!(s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
368 socket_write(s, "DA0", dacinternal_to_volts(GND));
369 socket_write(s, "DA1", dacinternal_to_volts(GND));
370 socket_write(s, "DA2", dacinternal_to_volts(GND));
371 socket_write(s, "DA3", dacinternal_to_volts(GND));
372 socket_write(s, "DA4", dacinternal_to_volts(GND));
373 socket_write(s, "DA5", dacinternal_to_volts(GND));
374 socket_write(s, "DA6", dacinternal_to_volts(GND));
375 socket_write(s, "DA7", dacinternal_to_volts(GND));
380 printf("mf624_BAR0_write32(): addr = " TARGET_FMT_plx
381 "; value = 0x%" PRIx64 "\n", addr, value);
386 static uint64_t mf624_BAR0_read32(void *opaque, hwaddr addr, unsigned size)
388 mf624_state_t *s = opaque;
390 switch (addr % BAR0_size) {
392 return s->BAR0.INTCSR;
395 return s->BAR0.GPIOC;
398 printf("mf624_BAR0_read32(): addr = "
399 TARGET_FMT_plx "\n", addr);
404 static uint64_t mf624_BAR2_read16(void *opaque, hwaddr addr, unsigned size)
407 int ADDATA_val = 0xFFFF;
408 mf624_state_t *s = opaque;
410 switch (addr % BAR2_size) {
411 /* Reading from ADDATA FIFO register */
413 case ADDATA1_off: /* Mirrored registers */
420 if (!(s->BAR0.GPIOC & GPIOC_EOLC_mask)) { /* Has the conversion already ended? */
421 #define ADC_CHANNELS 8
422 for (i = s->ADDATA_FIFO_POSITION; i < ADC_CHANNELS; i++) {
423 if (s->BAR2.ADCTRL & (1 << i)) {
424 s->ADDATA_FIFO_POSITION = i; /* Move to next AD to be read */
428 switch (s->ADDATA_FIFO_POSITION) {
430 ADDATA_val = s->BAR2.ADDATA;
433 ADDATA_val = s->BAR2.ADDATA1;
436 ADDATA_val = s->BAR2.ADDATA2;
439 ADDATA_val = s->BAR2.ADDATA3;
442 ADDATA_val = s->BAR2.ADDATA4;
445 ADDATA_val = s->BAR2.ADDATA5;
448 ADDATA_val = s->BAR2.ADDATA6;
451 ADDATA_val = s->BAR2.ADDATA7;
453 default: /* restart counter */
454 s->ADDATA_FIFO_POSITION = 0;
455 ADDATA_val = s->BAR2.ADDATA;
458 s->ADDATA_FIFO_POSITION++;
461 return 0xFFFF; /* Semirandom value */
467 /* A/D Conversion Start. Reading this register triggers A/D
468 conversion for all channels selected in ADCTRL. */
470 s->BAR0.GPIOC |= GPIOC_EOLC_mask; /* Conversion in progress */
471 s->ADDATA_FIFO_POSITION = 0;
473 /* Simulation of the time delay of real conversion should be implemented there */
475 /* Check before assignement, if particular ADC is enabled */
476 s->BAR2.ADDATA = (s->BAR2.ADCTRL & (1 << 0)) ?
477 s->real_world_AD0 : s->BAR2.ADDATA;
478 s->BAR2.ADDATA1 = (s->BAR2.ADCTRL & (1 << 1)) ?
479 s->real_world_AD1 : s->BAR2.ADDATA1;
480 s->BAR2.ADDATA2 = (s->BAR2.ADCTRL & (1 << 2)) ?
481 s->real_world_AD2 : s->BAR2.ADDATA2;
482 s->BAR2.ADDATA3 = (s->BAR2.ADCTRL & (1 << 3)) ?
483 s->real_world_AD3 : s->BAR2.ADDATA3;
484 s->BAR2.ADDATA4 = (s->BAR2.ADCTRL & (1 << 4)) ?
485 s->real_world_AD4 : s->BAR2.ADDATA4;
486 s->BAR2.ADDATA5 = (s->BAR2.ADCTRL & (1 << 5)) ?
487 s->real_world_AD5 : s->BAR2.ADDATA5;
488 s->BAR2.ADDATA6 = (s->BAR2.ADCTRL & (1 << 6)) ?
489 s->real_world_AD6 : s->BAR2.ADDATA6;
490 s->BAR2.ADDATA7 = (s->BAR2.ADCTRL & (1 << 7)) ?
491 s->real_world_AD7 : s->BAR2.ADDATA7;
493 /* All channels converted */
494 s->BAR0.GPIOC &= ~GPIOC_EOLC_mask;
496 return 0xFFFF; /* Semirandom value */
499 printf("mf624_BAR2_read16(): addr = "
500 TARGET_FMT_plx "\n", addr);
505 static void mf624_BAR2_write16(void *opaque, hwaddr addr, uint64_t value, unsigned size)
507 mf624_state_t *s = opaque;
509 switch (addr % BAR2_size) {
511 s->BAR2.ADCTRL = value;
512 socket_write(s, "ADCTRL", s->BAR2.ADCTRL);
516 s->BAR2.DOUT = value;
517 socket_write(s, "DOUT", s->BAR2.DOUT);
522 /* Is DAC enabled & Output enabled? */
523 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
524 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
525 socket_write(s, "DA0", dacinternal_to_volts(s->BAR2.DA0));
531 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
532 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
533 socket_write(s, "DA1", dacinternal_to_volts(s->BAR2.DA1));
539 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
540 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
541 socket_write(s, "DA2", dacinternal_to_volts(s->BAR2.DA2));
547 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
548 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
549 socket_write(s, "DA3", dacinternal_to_volts(s->BAR2.DA3));
555 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
556 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
557 socket_write(s, "DA4", dacinternal_to_volts(s->BAR2.DA4));
563 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
564 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
565 socket_write(s, "DA5", dacinternal_to_volts(s->BAR2.DA5));
571 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
572 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
573 socket_write(s, "DA6", dacinternal_to_volts(s->BAR2.DA6));
579 if (!(s->BAR0.GPIOC & GPIOC_LDAC_mask) &&
580 (s->BAR0.GPIOC & GPIOC_DACEN_mask)) {
581 socket_write(s, "DA7", dacinternal_to_volts(s->BAR2.DA7));
586 printf("mf624_BAR2_write16(): addr = " TARGET_FMT_plx
587 "; value = 0x%" PRIx64 "\n", addr, value);
592 static void mf624_BAR4_write32(void *opaque, hwaddr addr, uint64_t value, unsigned size)
594 printf("mf624_BAR4_write32(): addr = " TARGET_FMT_plx
595 "; value = 0x%" PRIx64 "\n", addr, value);
598 static uint64_t mf624_BAR4_read32(void *opaque, hwaddr addr, unsigned size)
600 printf("mf624_BAR4_read32(): addr = " TARGET_FMT_plx "\n", addr);
604 /*----------------------------------------------------------------------------*/
606 static const MemoryRegionOps mf624_BAR0_mmio_ops = {
607 .read = mf624_BAR0_read32,
608 .write = mf624_BAR0_write32,
609 .endianness = DEVICE_LITTLE_ENDIAN,
611 .min_access_size = 4,
612 .max_access_size = 4,
616 static const MemoryRegionOps mf624_BAR2_mmio_ops = {
617 .read = mf624_BAR2_read16,
618 .write = mf624_BAR2_write16,
619 .endianness = DEVICE_LITTLE_ENDIAN,
621 .min_access_size = 2,
622 .max_access_size = 2,
626 static const MemoryRegionOps mf624_BAR4_mmio_ops = {
627 .read = mf624_BAR4_read32,
628 .write = mf624_BAR4_write32,
629 .endianness = DEVICE_LITTLE_ENDIAN,
631 .min_access_size = 4,
632 .max_access_size = 4,
636 #define DEFAULT_PORT 55555
637 static int mf624_init(PCIDevice *pci_dev)
639 mf624_state_t *s = MF624_DEV(pci_dev); /* alocation of mf624_state_t */
642 if (s->port == DEFAULT_PORT) {
643 s->port += mf624_instance; /* Each instance of the same device should have another port number */
647 /* Set all internal registers to default values */
648 mf624_init_registers(s);
650 pci_conf = pci_dev->config;
651 pci_conf[PCI_INTERRUPT_PIN] = 0x1; /* interrupt pin 0 */
653 s->irq = pci_allocate_irq(&s->dev);
655 qemu_register_reset(mf624_reset, s);
657 memory_region_init_io(&s->mmio_bar0, OBJECT(s), &mf624_BAR0_mmio_ops, s, "mf624_bar0", BAR0_size);
658 memory_region_init_io(&s->mmio_bar2, OBJECT(s), &mf624_BAR2_mmio_ops, s, "mf624_bar2", BAR2_size);
659 memory_region_init_io(&s->mmio_bar4, OBJECT(s), &mf624_BAR4_mmio_ops, s, "mf624_bar4", BAR4_size);
660 pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio_bar0);
661 pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio_bar2);
662 pci_register_bar(&s->dev, 4, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio_bar4);
664 /* Create thread, which will be blocked on reading from socket (connected to "I/O GUI") */
666 qemu_thread_create(&s->socket_thread, "mf624_io_thread",
667 init_socket, (void *) s, QEMU_THREAD_JOINABLE);
671 static void qdev_mf624_reset(DeviceState *dev)
673 mf624_state_t *s = MF624_DEV(dev);
674 mf624_init_registers(s);
677 static void mf624_exit(PCIDevice *pci_dev)
679 mf624_state_t *s = MF624_DEV(pci_dev);
681 close(s->socket_srv);
683 qemu_thread_join(&s->socket_thread);
685 qemu_unregister_reset(mf624_reset, s);
687 memory_region_destroy(&s->mmio_bar0);
688 memory_region_destroy(&s->mmio_bar2);
689 memory_region_destroy(&s->mmio_bar4);
691 qemu_free_irq(s->irq);
694 static const VMStateDescription vmstate_mf624 = {
697 .minimum_version_id = 1,
698 .minimum_version_id_old = 1,
700 .fields = (VMStateField[]) {
701 VMSTATE_PCI_DEVICE(dev, mf624_state_t),
702 VMSTATE_UINT32(port, mf624_state_t),
703 VMSTATE_END_OF_LIST()
708 static Property mf624_properties[] = {
709 DEFINE_PROP_UINT32("port", mf624_state_t, port, DEFAULT_PORT),
710 DEFINE_PROP_END_OF_LIST(),
713 static void mf624_class_init(ObjectClass *klass, void *data)
715 DeviceClass *dc = DEVICE_CLASS(klass);
716 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
718 k->init = mf624_init;
719 k->exit = mf624_exit;
720 k->vendor_id = PCI_VENDOR_ID_HUMUSOFT;
721 k->device_id = PCI_DEVICE_ID_MF624;
723 k->class_id = PCI_CLASS_SIGNAL_PROCESSING_CONTROLLER;
724 k->subsystem_vendor_id = PCI_VENDOR_ID_HUMUSOFT;
725 k->subsystem_id = PCI_DEVICE_ID_MF624;
726 dc->desc = "Humusoft MF624";
727 dc->props = mf624_properties;
728 dc->vmsd = &vmstate_mf624;
729 set_bit(DEVICE_CATEGORY_MISC, dc->categories);
730 dc->reset = qdev_mf624_reset;
733 static const TypeInfo mf624_info = {
734 .name = TYPE_MF624_DEV,
735 .parent = TYPE_PCI_DEVICE,
736 .instance_size = sizeof(mf624_state_t),
737 .class_init = mf624_class_init,
740 static void mf624_register_types(void)
742 type_register_static(&mf624_info);
745 type_init(mf624_register_types)