| 409 | <!-- ==== hw/can-pci.c ==== |
| 410 | |
| 411 | This adds the can-pci device |
| 412 | |
| 413 | Include the simulations for the bus (pci), device type (char), timer functions, and the address-spaces (for memory-mapped io?) |
| 414 | @@ -0,0 +1,193 @@ |
| 415 | +#include "pci/pci.h" |
| 416 | +#include "char/char.h" |
| 417 | +#include "qemu/timer.h" |
| 418 | +#include "exec/address-spaces.h" |
| 419 | |
| 420 | '''TODO:''' look up where these defines are from |
| 421 | +#define PCI_MEM_SIZE 16 |
| 422 | +#define PCI_DEVICE_ID_CANBUS 0xbeef |
| 423 | +#define PCI_REVISION_ID_CANBUS 0x73 |
| 424 | |
| 425 | |
| 426 | +typedef struct CanState { |
| 427 | + /* Some registers ... */ |
| 428 | + qemu_irq irq; |
| 429 | + void *mem_base; |
| 430 | + |
| 431 | + CharDriverState *chr; |
| 432 | + MemoryRegion portio; |
| 433 | + MemoryRegion memio; |
| 434 | +} CanState; |
| 435 | + |
| 436 | +typedef struct PCICanState { |
| 437 | + PCIDevice dev; |
| 438 | + CanState state; |
| 439 | +} PCICanState; |
| 440 | + |
| 441 | +#define DEBUG_CAN |
| 442 | +#ifdef DEBUG_CAN |
| 443 | +#define DPRINTF(fmt, ...) \ |
| 444 | + do { fprintf(stderr, "[mycan]: " fmt , ## __VA_ARGS__); } while (0) |
| 445 | +#else |
| 446 | +#define DPRINTF(fmt, ...) \ |
| 447 | + do {} while (0) |
| 448 | +#endif |
| 449 | + |
| 450 | + |
| 451 | +const uint8_t whatever[] = "ttt"; |
| 452 | +static void can_ioport_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) |
| 453 | +{ |
| 454 | + CanState *s = opaque; |
| 455 | + DPRINTF("write addr=0x%02x val=0x%02x\n", (unsigned int)addr, (unsigned int)val); |
| 456 | + qemu_chr_fe_write(s->chr, whatever, 3); // write to the backends. |
| 457 | +} |
| 458 | + |
| 459 | +static uint64_t can_ioport_read(void *opaque, hwaddr addr, unsigned size) |
| 460 | +{ |
| 461 | + DPRINTF("%s-%s() called\n", __FILE__, __FUNCTION__); |
| 462 | + return 0; |
| 463 | +} |
| 464 | + |
| 465 | +const MemoryRegionOps can_io_ops = { |
| 466 | + .read = can_ioport_read, |
| 467 | + .write = can_ioport_write, |
| 468 | + .endianness = DEVICE_LITTLE_ENDIAN, |
| 469 | + .impl = { |
| 470 | + .min_access_size = 1, |
| 471 | + .max_access_size = 1, |
| 472 | + }, |
| 473 | +}; |
| 474 | + |
| 475 | +static void can_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) |
| 476 | +{ |
| 477 | + CanState *s = opaque; |
| 478 | + void *pci_mem_addr; |
| 479 | + int region_size; |
| 480 | + |
| 481 | + pci_mem_addr = s->mem_base; |
| 482 | + pci_mem_addr = ((char *)pci_mem_addr) + addr; |
| 483 | + region_size = (int)memory_region_size(&s->memio); |
| 484 | + if(addr > region_size) |
| 485 | + return ; |
| 486 | + |
| 487 | + DPRINTF("write 0x%llx to %p\n", val, pci_mem_addr); |
| 488 | + memcpy(pci_mem_addr, (void *)&val, size); |
| 489 | + DPRINTF(" pci_mem_addr 0x%llx\n", *(uint64_t *)pci_mem_addr); |
| 490 | + |
| 491 | + |
| 492 | +} |
| 493 | + |
| 494 | +static uint64_t can_mem_read(void *opaque, hwaddr addr, unsigned size) |
| 495 | +{ |
| 496 | + CanState *s = opaque; |
| 497 | + void *pci_mem_addr; |
| 498 | + int region_size; |
| 499 | + unsigned int temp; |
| 500 | + |
| 501 | + pci_mem_addr = s->mem_base; |
| 502 | + pci_mem_addr = ((char *)pci_mem_addr) + addr; |
| 503 | + region_size = memory_region_size(&s->memio); |
| 504 | + if(addr > region_size) |
| 505 | + return 0; |
| 506 | + |
| 507 | + memcpy(&temp, pci_mem_addr, size); |
| 508 | + DPRINTF("read %d bytes of 0x%x from %p\n", size, temp, pci_mem_addr); |
| 509 | + |
| 510 | + return temp; |
| 511 | +} |
| 512 | + |
| 513 | +static const MemoryRegionOps can_mem_ops = { |
| 514 | + .read = can_mem_read, |
| 515 | + .write = can_mem_write, |
| 516 | + .endianness = DEVICE_LITTLE_ENDIAN, |
| 517 | + .impl = { |
| 518 | + // how many bytes can we read/write every time. |
| 519 | + .min_access_size = 1, |
| 520 | + .max_access_size = 16, |
| 521 | + }, |
| 522 | +}; |
| 523 | + |
| 524 | + |
| 525 | +static int can_pci_init(PCIDevice *dev) |
| 526 | +{ |
| 527 | + // Get the address of PCICanState through PCIDevice. |
| 528 | + PCICanState *pci = DO_UPCAST(PCICanState, dev, dev); |
| 529 | + CanState *s = &pci->state; |
| 530 | + |
| 531 | + DPRINTF("%s-%s() called\n", __FILE__, __FUNCTION__); |
| 532 | + if (!s->chr) { |
| 533 | + fprintf(stderr, "Can't create can device, empty char device\n"); |
| 534 | + exit(1); |
| 535 | + } |
| 536 | + |
| 537 | + s->mem_base = g_malloc0(PCI_MEM_SIZE); |
| 538 | + |
| 539 | + pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; |
| 540 | + s->irq = pci->dev.irq[0]; |
| 541 | + |
| 542 | + |
| 543 | + qemu_irq_lower(s->irq); |
| 544 | + |
| 545 | + memory_region_init_io(&s->portio, &can_io_ops, s, "can", 8); |
| 546 | + memory_region_init_io(&s->memio, &can_mem_ops, s, "can", PCI_MEM_SIZE); |
| 547 | + pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->portio); |
| 548 | + pci_register_bar(&pci->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->memio); |
| 549 | + |
| 550 | +// memory_region_add_subregion(system_io, base, &s->io); |
| 551 | + return 0; |
| 552 | +} |
| 553 | + |
| 554 | +static void can_pci_exit(PCIDevice *dev) |
| 555 | +{ |
| 556 | + PCICanState *pci = DO_UPCAST(PCICanState, dev, dev); |
| 557 | + CanState *s = &pci->state; |
| 558 | + |
| 559 | + g_free(s->mem_base); |
| 560 | + memory_region_destroy(&s->memio); |
| 561 | + memory_region_destroy(&s->portio); |
| 562 | +} |
| 563 | + |
| 564 | + |
| 565 | +static const VMStateDescription vmstate_pci_can = { |
| 566 | + .name = "pci-can", |
| 567 | + .version_id = PCI_REVISION_ID_CANBUS, |
| 568 | + .minimum_version_id = 1, |
| 569 | + .fields = (VMStateField[]) { |
| 570 | + VMSTATE_PCI_DEVICE(dev, PCICanState), |
| 571 | + VMSTATE_END_OF_LIST() |
| 572 | + } |
| 573 | +}; |
| 574 | + |
| 575 | +static Property can_pci_properties[] = { |
| 576 | + DEFINE_PROP_CHR("chardev", PCICanState, state.chr), |
| 577 | + DEFINE_PROP_END_OF_LIST(), |
| 578 | +}; |
| 579 | + |
| 580 | +static void can_pci_class_initfn(ObjectClass *klass, void *data) |
| 581 | +{ |
| 582 | + DeviceClass *dc = DEVICE_CLASS(klass); |
| 583 | + PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); |
| 584 | + |
| 585 | + pc->init = can_pci_init; |
| 586 | + pc->exit = can_pci_exit; |
| 587 | + pc->vendor_id = PCI_VENDOR_ID_REDHAT; // 0x1b36 |
| 588 | + pc->device_id = PCI_DEVICE_ID_CANBUS; |
| 589 | + pc->revision = PCI_REVISION_ID_CANBUS; |
| 590 | + pc->class_id = PCI_CLASS_OTHERS; |
| 591 | + |
| 592 | + dc->desc = "PCI CAN SJA1000"; |
| 593 | + dc->vmsd = &vmstate_pci_can; |
| 594 | + dc->props = can_pci_properties; |
| 595 | +} |
| 596 | + |
| 597 | +static const TypeInfo can_pci_info = { |
| 598 | + .name = "pci-can", |
| 599 | + .parent = TYPE_PCI_DEVICE, |
| 600 | + .instance_size = sizeof(PCICanState), |
| 601 | + .class_init = can_pci_class_initfn, |
| 602 | +}; |
| 603 | + |
| 604 | +static void can_pci_register_types(void) |
| 605 | +{ |
| 606 | + type_register_static(&can_pci_info); |
| 607 | +} |
| 608 | + |
| 609 | +type_init(can_pci_register_types) |
| 610 | --> |