From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1MOtH2-0002JW-M0 for qemu-devel@nongnu.org; Thu, 09 Jul 2009 09:02:52 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1MOtGx-0002Es-JW for qemu-devel@nongnu.org; Thu, 09 Jul 2009 09:02:51 -0400 Received: from [199.232.76.173] (port=42395 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MOtGx-0002Ei-FB for qemu-devel@nongnu.org; Thu, 09 Jul 2009 09:02:47 -0400 Received: from mx2.redhat.com ([66.187.237.31]:54512) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1MOtGw-0002Eb-J8 for qemu-devel@nongnu.org; Thu, 09 Jul 2009 09:02:46 -0400 Received: from int-mx2.corp.redhat.com (int-mx2.corp.redhat.com [172.16.27.26]) by mx2.redhat.com (8.13.8/8.13.8) with ESMTP id n69D2k2H016293 for ; Thu, 9 Jul 2009 09:02:46 -0400 From: Gerd Hoffmann Date: Thu, 9 Jul 2009 15:02:37 +0200 Message-Id: <1247144560-9014-2-git-send-email-kraxel@redhat.com> In-Reply-To: <1247144560-9014-1-git-send-email-kraxel@redhat.com> References: <1247144560-9014-1-git-send-email-kraxel@redhat.com> Subject: [Qemu-devel] [PATCH 1/4] qdev/isa: add isa bus support to qdev. List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Gerd Hoffmann The implementation tries to cover both the pc-ish ioport case and the mmio-based isa port access found in other architectures. The common code in isa-bus.c handles mmio internally, so the separate init path for mmio present in many drivers can go away once all users are switched over to qdev. Signed-off-by: Gerd Hoffmann --- Makefile.target | 8 +- hw/isa-bus.c | 216 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/isa.h | 31 ++++++++ 3 files changed, 251 insertions(+), 4 deletions(-) create mode 100644 hw/isa-bus.c diff --git a/Makefile.target b/Makefile.target index a593503..1a865fa 100644 --- a/Makefile.target +++ b/Makefile.target @@ -562,7 +562,7 @@ obj-y += wdt_ib700.o wdt_i6300esb.o ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support -obj-y += ide.o pckbd.o vga.o $(sound-obj-y) dma.o +obj-y += ide.o pckbd.o vga.o $(sound-obj-y) dma.o isa-bus.o obj-y += fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o obj-y += cirrus_vga.o apic.o ioapic.o parallel.o acpi.o piix_pci.o obj-y += usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o @@ -572,7 +572,7 @@ endif ifeq ($(TARGET_BASE_ARCH), ppc) CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE # shared objects -obj-y += ppc.o ide.o vga.o $(sound-obj-y) dma.o openpic.o +obj-y += ppc.o ide.o vga.o $(sound-obj-y) dma.o isa-bus.o openpic.o # PREP target obj-y += pckbd.o serial.o i8259.o i8254.o fdc.o mc146818rtc.o obj-y += prep_pci.o ppc_prep.o @@ -598,7 +598,7 @@ obj-y += mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o obj-y += mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o rc4030.o obj-y += g364fb.o jazz_led.o dp8393x.o obj-y += ide.o gt64xxx.o pckbd.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o -obj-y += piix_pci.o parallel.o cirrus_vga.o pcspk.o $(sound-obj-y) +obj-y += piix_pci.o parallel.o cirrus_vga.o isa-bus.o pcspk.o $(sound-obj-y) obj-y += mipsnet.o obj-y += pflash_cfi01.o obj-y += vmware_vga.o @@ -634,7 +634,7 @@ obj-y += pflash_cfi02.o endif ifeq ($(TARGET_BASE_ARCH), sparc) ifeq ($(TARGET_ARCH), sparc64) -obj-y += sun4u.o ide.o pckbd.o vga.o apb_pci.o +obj-y += sun4u.o ide.o isa-bus.o pckbd.o vga.o apb_pci.o obj-y += fdc.o mc146818rtc.o serial.o obj-y += cirrus_vga.o parallel.o else diff --git a/hw/isa-bus.c b/hw/isa-bus.c new file mode 100644 index 0000000..96f95a9 --- /dev/null +++ b/hw/isa-bus.c @@ -0,0 +1,216 @@ +#include "hw.h" +#include "sysemu.h" +#include "isa.h" + +typedef struct ISAMMIO { + ISADevice *dev; + ISADeviceInfo *info; + int region; + int io_memory; +} ISAMMIO; + +struct ISABus { + BusState qbus; + int mmio; + int it_shift; +}; +static ISABus *isabus; + +static struct BusInfo isa_bus_info = { + .name = "ISA", + .size = sizeof(ISABus), + .props = (Property[]) { + { + .name = "iobase", + .info = &qdev_prop_hex32, + .offset = offsetof(ISADevice, iobase[0]), + .defval = (uint32_t[]) { -1 }, + },{ + .name = "iobase2", + .info = &qdev_prop_hex32, + .offset = offsetof(ISADevice, iobase[1]), + .defval = (uint32_t[]) { -1 }, + }, + {/* end of list */} + } +}; + +ISABus *isa_bus_new(DeviceState *dev, int mmio, int it_shift) +{ + if (isabus) { + fprintf(stderr, "Can't create a second ISA bus\n"); + return NULL; + } + + isabus = FROM_QBUS(ISABus, qbus_create(&isa_bus_info, dev, "isa")); + isabus->mmio = mmio; + isabus->it_shift = it_shift; + return isabus; +} + +void isa_connect_irq(ISADevice *dev, int n, qemu_irq irq) +{ + assert(n >= 0 && n < dev->nirqs); + if (dev->irqs[n]) + *dev->irqs[n] = irq; +} + +void isa_init_irq(ISADevice *dev, qemu_irq *p) +{ + assert(dev->nirqs < ARRAY_SIZE(dev->irqs)); + dev->irqs[dev->nirqs] = p; + dev->nirqs++; +} + +static uint32_t isa_mm_readb(void *opaque, target_phys_addr_t addr) +{ + ISAMMIO *mm = opaque; + IOPortReadFunc *ioread = mm->info->io[mm->region].read; + + return ioread(mm->dev, addr >> isabus->it_shift) & 0xFF; +} + +static void isa_mm_writeb(void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + ISAMMIO *mm = opaque; + IOPortWriteFunc *iowrite = mm->info->io[mm->region].write; + + iowrite(mm->dev, addr >> isabus->it_shift, value & 0xFF); +} + +static uint32_t isa_mm_readw(void *opaque, target_phys_addr_t addr) +{ + ISAMMIO *mm = opaque; + IOPortReadFunc *ioread = mm->info->io[mm->region].read; + uint32_t value; + + value = ioread(mm->dev, addr >> isabus->it_shift) & 0xFFFF; +#ifdef TARGET_WORDS_BIGENDIAN + value = bswap16(value); +#endif + return value; +} + +static void isa_mm_writew(void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + ISAMMIO *mm = opaque; + IOPortWriteFunc *iowrite = mm->info->io[mm->region].write; + +#ifdef TARGET_WORDS_BIGENDIAN + value = bswap16(value); +#endif + iowrite(mm->dev, addr >> isabus->it_shift, value & 0xFFFF); +} + +static uint32_t isa_mm_readl(void *opaque, target_phys_addr_t addr) +{ + ISAMMIO *mm = opaque; + IOPortReadFunc *ioread = mm->info->io[mm->region].read; + uint32_t value; + + value = ioread(mm->dev, addr >> isabus->it_shift); +#ifdef TARGET_WORDS_BIGENDIAN + value = bswap32(value); +#endif + return value; +} + +static void isa_mm_writel(void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + ISAMMIO *mm = opaque; + IOPortWriteFunc *iowrite = mm->info->io[mm->region].write; + +#ifdef TARGET_WORDS_BIGENDIAN + value = bswap32(value); +#endif + iowrite(mm->dev, addr >> isabus->it_shift, value & 0xFFFF); +} + +static CPUReadMemoryFunc *isa_mm_read[] = { + &isa_mm_readb, + &isa_mm_readw, + &isa_mm_readl, +}; + +static CPUWriteMemoryFunc *isa_mm_write[] = { + &isa_mm_writeb, + &isa_mm_writew, + &isa_mm_writel, +}; + +static void isa_setup_ioport(ISADevice *dev, ISADeviceInfo *info) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dev->iobase); i++) { + if (!dev->iobase[i]) + continue; + if (info->io[i].read) + register_ioport_read(dev->iobase[i], info->io[i].length, 1, + info->io[i].read, dev); + if (info->io[i].write) + register_ioport_write(dev->iobase[i], info->io[i].length, 1, + info->io[i].write, dev); + fprintf(stderr, "%s: ioport 0x%x (+%d) %c%c for %s\n", __FUNCTION__, + dev->iobase[i], info->io[i].length, + info->io[i].read ? 'r' : '-', + info->io[i].write ? 'w' : '-', + info->qdev.name); + } +} + +static void isa_setup_mmio(ISADevice *dev, ISADeviceInfo *info) +{ + struct ISAMMIO *mm; + int i; + + for (i = 0; i < ARRAY_SIZE(dev->iobase); i++) { + if (!dev->iobase[i]) + continue; + mm = qemu_mallocz(sizeof(*mm)); + mm->dev = dev; + mm->info = info; + mm->region = i; + mm->io_memory = cpu_register_io_memory(isa_mm_read, isa_mm_write, mm); + cpu_register_physical_memory(dev->iobase[i], info->io[i].length, mm->io_memory); + } +} + +static void isa_qdev_init(DeviceState *qdev, DeviceInfo *base) +{ + ISADevice *dev = DO_UPCAST(ISADevice, qdev, qdev); + ISADeviceInfo *info = DO_UPCAST(ISADeviceInfo, qdev, base); + + if (isabus->mmio) { + isa_setup_mmio(dev, info); + } else { + isa_setup_ioport(dev, info); + } + + info->init(dev); +} + +void isa_qdev_register(ISADeviceInfo *info) +{ + info->qdev.init = isa_qdev_init; + info->qdev.bus_info = &isa_bus_info; + qdev_register(&info->qdev); +} + +ISADevice *isa_create_simple(const char *name, uint32_t iobase, uint32_t iobase2) +{ + DeviceState *dev; + ISADevice *isa; + + if (!isabus) + return NULL; + dev = qdev_create(&isabus->qbus, name); + isa = DO_UPCAST(ISADevice, qdev, dev); + isa->iobase[0] = iobase; + isa->iobase[1] = iobase2; + qdev_init(dev); + return isa; +} diff --git a/hw/isa.h b/hw/isa.h index a8c1a56..941bfe3 100644 --- a/hw/isa.h +++ b/hw/isa.h @@ -1,7 +1,38 @@ #ifndef HW_ISA_H #define HW_ISA_H + /* ISA bus */ +#include "qdev.h" + +typedef struct ISABus ISABus; +typedef struct ISADevice ISADevice; +typedef struct ISADeviceInfo ISADeviceInfo; + +struct ISADevice { + DeviceState qdev; + uint32_t iobase[2]; + qemu_irq *irqs[2]; + int nirqs; +}; + +typedef void (*isa_qdev_initfn)(ISADevice *dev); +struct ISADeviceInfo { + DeviceInfo qdev; + isa_qdev_initfn init; + struct { + IOPortReadFunc *read; + IOPortWriteFunc *write; + uint32_t length; + } io[2]; +}; + +ISABus *isa_bus_new(DeviceState *dev, int mmio, int it_shift); +void isa_connect_irq(ISADevice *dev, int n, qemu_irq irq); +void isa_init_irq(ISADevice *dev, qemu_irq *p); +void isa_qdev_register(ISADeviceInfo *info); +ISADevice *isa_create_simple(const char *name, uint32_t iobase, uint32_t iobase2); + extern target_phys_addr_t isa_mem_base; int register_ioport_read(int start, int length, int size, -- 1.6.2.5