2010-12-25 13:01:41 +08:00
|
|
|
/*
|
|
|
|
* QEMU Intel i82378 emulation (PCI to ISA bridge)
|
|
|
|
*
|
|
|
|
* Copyright (c) 2010-2011 Hervé Poussineau
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2016-01-27 02:17:30 +08:00
|
|
|
#include "qemu/osdep.h"
|
2013-02-04 22:40:22 +08:00
|
|
|
#include "hw/pci/pci.h"
|
2013-02-06 00:06:20 +08:00
|
|
|
#include "hw/i386/pc.h"
|
2019-08-12 13:23:42 +08:00
|
|
|
#include "hw/irq.h"
|
2013-02-06 00:06:20 +08:00
|
|
|
#include "hw/timer/i8254.h"
|
|
|
|
#include "hw/audio/pcspk.h"
|
2010-12-25 13:01:41 +08:00
|
|
|
|
2013-07-24 05:16:46 +08:00
|
|
|
#define TYPE_I82378 "i82378"
|
|
|
|
#define I82378(obj) \
|
|
|
|
OBJECT_CHECK(I82378State, (obj), TYPE_I82378)
|
2010-12-25 13:01:41 +08:00
|
|
|
|
|
|
|
typedef struct I82378State {
|
2013-07-24 05:16:46 +08:00
|
|
|
PCIDevice parent_obj;
|
|
|
|
|
2010-12-25 13:01:41 +08:00
|
|
|
qemu_irq out[2];
|
|
|
|
qemu_irq *i8259;
|
|
|
|
MemoryRegion io;
|
|
|
|
} I82378State;
|
|
|
|
|
2013-07-24 05:16:46 +08:00
|
|
|
static const VMStateDescription vmstate_i82378 = {
|
2010-12-25 13:01:41 +08:00
|
|
|
.name = "pci-i82378",
|
|
|
|
.version_id = 0,
|
|
|
|
.minimum_version_id = 0,
|
|
|
|
.fields = (VMStateField[]) {
|
2013-07-24 05:16:46 +08:00
|
|
|
VMSTATE_PCI_DEVICE(parent_obj, I82378State),
|
2010-12-25 13:01:41 +08:00
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static void i82378_request_out0_irq(void *opaque, int irq, int level)
|
|
|
|
{
|
|
|
|
I82378State *s = opaque;
|
|
|
|
qemu_set_irq(s->out[0], level);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i82378_request_pic_irq(void *opaque, int irq, int level)
|
|
|
|
{
|
|
|
|
DeviceState *dev = opaque;
|
2013-07-24 05:16:46 +08:00
|
|
|
I82378State *s = I82378(dev);
|
2010-12-25 13:01:41 +08:00
|
|
|
|
2013-07-24 05:16:46 +08:00
|
|
|
qemu_set_irq(s->i8259[irq], level);
|
2010-12-25 13:01:41 +08:00
|
|
|
}
|
|
|
|
|
2015-01-19 22:52:30 +08:00
|
|
|
static void i82378_realize(PCIDevice *pci, Error **errp)
|
2010-12-25 13:01:41 +08:00
|
|
|
{
|
2013-07-24 05:16:46 +08:00
|
|
|
DeviceState *dev = DEVICE(pci);
|
|
|
|
I82378State *s = I82378(dev);
|
|
|
|
uint8_t *pci_conf;
|
|
|
|
ISABus *isabus;
|
2012-03-17 22:39:41 +08:00
|
|
|
ISADevice *isa;
|
2010-12-25 13:01:41 +08:00
|
|
|
|
2013-07-24 05:16:46 +08:00
|
|
|
pci_conf = pci->config;
|
|
|
|
pci_set_word(pci_conf + PCI_COMMAND,
|
|
|
|
PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
|
|
|
|
pci_set_word(pci_conf + PCI_STATUS,
|
|
|
|
PCI_STATUS_DEVSEL_MEDIUM);
|
|
|
|
|
|
|
|
pci_config_set_interrupt_pin(pci_conf, 1); /* interrupt pin 0 */
|
|
|
|
|
2015-02-01 16:12:50 +08:00
|
|
|
isabus = isa_bus_new(dev, get_system_memory(),
|
isa: Clean up error handling around isa_bus_new()
We can have at most one ISA bus. If you try to create another one,
isa_bus_new() complains to stderr and returns null.
isa_bus_new() is called in two contexts, machine's init() and device's
realize() methods. Since complaining to stderr is not proper in the
latter context, convert isa_bus_new() to Error.
Machine's init():
* mips_jazz_init(), called from the init() methods of machines
"magnum" and "pica"
* mips_r4k_init(), the init() method of machine "mips"
* pc_init1() called from the init() methods of non-q35 PC machines
* typhoon_init(), called from clipper_init(), the init() method of
machine "clipper"
These callers always create the first ISA bus, hence isa_bus_new()
can't fail. Simply pass &error_abort.
Device's realize():
* i82378_realize(), of PCI device "i82378"
* ich9_lpc_realize(), of PCI device "ICH9-LPC"
* pci_ebus_realize(), of PCI device "ebus"
* piix3_realize(), of PCI device "pci-piix3", abstract parent of
"PIIX3" and "PIIX3-xen"
* piix4_realize(), of PCI device "PIIX4"
* vt82c686b_realize(), of PCI device "VT82C686B"
Propagate the error. Note that these devices are typically created
only by machine init() methods with qdev_init_nofail() or similar. If
we screwed up and created an ISA bus before that call, we now give up
right away. Before, we'd hobble on, and typically die in
isa_bus_irqs(). Similar if someone finds a way to hot-plug one of
these critters.
Cc: Richard Henderson <rth@twiddle.net>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: "Hervé Poussineau" <hpoussin@reactos.org>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
Reviewed-by: Marcel Apfelbaum <marcel@redhat.com>
Reviewed-by: Hervé Poussineau <hpoussin@reactos.org>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Message-Id: <1450370121-5768-11-git-send-email-armbru@redhat.com>
2015-12-18 00:35:18 +08:00
|
|
|
pci_address_space_io(pci), errp);
|
|
|
|
if (!isabus) {
|
|
|
|
return;
|
|
|
|
}
|
2013-07-24 05:16:46 +08:00
|
|
|
|
2010-12-25 13:01:41 +08:00
|
|
|
/* This device has:
|
|
|
|
2 82C59 (irq)
|
|
|
|
1 82C54 (pit)
|
|
|
|
2 82C37 (dma)
|
|
|
|
NMI
|
|
|
|
Utility Bus Support Registers
|
|
|
|
|
|
|
|
All devices accept byte access only, except timer
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* 2 82C59 (irq) */
|
2015-05-29 13:27:01 +08:00
|
|
|
s->i8259 = i8259_init(isabus,
|
|
|
|
qemu_allocate_irq(i82378_request_out0_irq, s, 0));
|
2010-12-25 13:01:41 +08:00
|
|
|
isa_bus_irqs(isabus, s->i8259);
|
|
|
|
|
|
|
|
/* 1 82C54 (pit) */
|
2017-10-18 00:44:15 +08:00
|
|
|
isa = i8254_pit_init(isabus, 0x40, 0, NULL);
|
2010-12-25 13:01:41 +08:00
|
|
|
|
|
|
|
/* speaker */
|
2013-07-24 05:16:46 +08:00
|
|
|
pcspk_init(isabus, isa);
|
2010-12-25 13:01:41 +08:00
|
|
|
|
|
|
|
/* 2 82C37 (dma) */
|
2012-03-17 22:39:41 +08:00
|
|
|
isa = isa_create_simple(isabus, "i82374");
|
2010-12-25 13:01:41 +08:00
|
|
|
}
|
|
|
|
|
2013-07-24 05:16:46 +08:00
|
|
|
static void i82378_init(Object *obj)
|
2010-12-25 13:01:41 +08:00
|
|
|
{
|
2013-07-24 05:16:46 +08:00
|
|
|
DeviceState *dev = DEVICE(obj);
|
|
|
|
I82378State *s = I82378(obj);
|
2010-12-25 13:01:41 +08:00
|
|
|
|
2015-02-16 21:13:11 +08:00
|
|
|
qdev_init_gpio_out(dev, s->out, 1);
|
2013-07-24 05:16:46 +08:00
|
|
|
qdev_init_gpio_in(dev, i82378_request_pic_irq, 16);
|
2010-12-25 13:01:41 +08:00
|
|
|
}
|
|
|
|
|
2013-07-24 05:16:46 +08:00
|
|
|
static void i82378_class_init(ObjectClass *klass, void *data)
|
2011-12-05 02:22:06 +08:00
|
|
|
{
|
|
|
|
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
2011-12-08 11:34:16 +08:00
|
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
2011-12-05 02:22:06 +08:00
|
|
|
|
2015-01-19 22:52:30 +08:00
|
|
|
k->realize = i82378_realize;
|
2011-12-05 02:22:06 +08:00
|
|
|
k->vendor_id = PCI_VENDOR_ID_INTEL;
|
|
|
|
k->device_id = PCI_DEVICE_ID_INTEL_82378;
|
|
|
|
k->revision = 0x03;
|
|
|
|
k->class_id = PCI_CLASS_BRIDGE_ISA;
|
2013-07-24 05:16:46 +08:00
|
|
|
dc->vmsd = &vmstate_i82378;
|
2013-07-29 22:17:45 +08:00
|
|
|
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
|
2011-12-05 02:22:06 +08:00
|
|
|
}
|
|
|
|
|
2013-07-24 05:16:46 +08:00
|
|
|
static const TypeInfo i82378_type_info = {
|
|
|
|
.name = TYPE_I82378,
|
2011-12-08 11:34:16 +08:00
|
|
|
.parent = TYPE_PCI_DEVICE,
|
2013-07-24 05:16:46 +08:00
|
|
|
.instance_size = sizeof(I82378State),
|
|
|
|
.instance_init = i82378_init,
|
|
|
|
.class_init = i82378_class_init,
|
2017-09-28 03:56:34 +08:00
|
|
|
.interfaces = (InterfaceInfo[]) {
|
|
|
|
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
|
|
|
|
{ },
|
|
|
|
},
|
2010-12-25 13:01:41 +08:00
|
|
|
};
|
|
|
|
|
2012-02-09 22:20:55 +08:00
|
|
|
static void i82378_register_types(void)
|
2010-12-25 13:01:41 +08:00
|
|
|
{
|
2013-07-24 05:16:46 +08:00
|
|
|
type_register_static(&i82378_type_info);
|
2010-12-25 13:01:41 +08:00
|
|
|
}
|
|
|
|
|
2012-02-09 22:20:55 +08:00
|
|
|
type_init(i82378_register_types)
|