* Re: [Qemu-devel] ISA PnP support
2004-06-04 16:34 ` Fabrice Bellard
2004-06-04 17:04 ` Gianni Tedesco
@ 2004-06-05 15:25 ` Antony T Curtis
2004-06-05 17:04 ` Karel Gardas
1 sibling, 1 reply; 8+ messages in thread
From: Antony T Curtis @ 2004-06-05 15:25 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 448 bytes --]
On Fri, 2004-06-04 at 17:34, Fabrice Bellard wrote:
> Hi,
>
> I am not really interested by ISA PnP as PCI will be the default config
> as soon as it works for NT. But I can still look at the patch.
IMO, the ISAPnP makes sense for the NE2000 implementation... makes it
easier to install/run other target OS.
<snip>
The diff is against the current CVS + my qemu-cirrus.patch (in other
email).
--
Antony T Curtis <antony.t.curtis@ntlworld.com>
[-- Attachment #2: qemu-isapnp.diff --]
[-- Type: text/x-patch, Size: 33656 bytes --]
diff -burN --exclude=*.bck qemu/Makefile.target qemu-pnp/Makefile.target
--- qemu/Makefile.target Sat Jun 5 13:25:07 2004
+++ qemu-pnp/Makefile.target Sat Jun 5 15:52:41 2004
@@ -238,7 +238,7 @@
# Hardware support
VL_OBJS+= ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o
VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o
-VL_OBJS+= cirrus_vga.o
+VL_OBJS+= cirrus_vga.o pnp.o
endif
ifeq ($(TARGET_ARCH), ppc)
# Generic PPC support
@@ -246,7 +246,7 @@
# PREP hardware support
VL_OBJS+= ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o
VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
-VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o
+VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o pnp.o
endif
ifdef CONFIG_GDBSTUB
VL_OBJS+=gdbstub.o
diff -burN --exclude=*.bck qemu/hw/ne2000.c qemu-pnp/hw/ne2000.c
--- qemu/hw/ne2000.c Sat May 22 17:52:29 2004
+++ qemu-pnp/hw/ne2000.c Sat Jun 5 17:13:14 2004
@@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
#include "vl.h"
+#include "pnpreg.h"
/* debug NE2000 card */
//#define DEBUG_NE2000
@@ -583,6 +584,146 @@
ne2000_reset(s);
qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s);
+}
+
+/***********************************************************/
+/* PNP NE2000 definitions */
+
+typedef struct PNPNE2000State {
+ PNPDevice dev;
+ NE2000State ne2000;
+ int nv_base, nv_irq;
+ int base;
+ int activated;
+ uint8_t config[128];
+} PNPNE2000State;
+
+static int pnp_ne2000_activate(PNPDevice *dev, enum PNPActivate activate)
+{
+ PNPNE2000State *d = (PNPNE2000State *)dev;
+ NE2000State *s = &d->ne2000;
+
+ if (activate == PNP_ACTIVATE_ENABLE) {
+ int irq = dev->resource[0x3f & PNP_IRQ_LEVEL(0)];
+ int base = dev->resource[0x3f & PNP_IO_BASE_HIGH(0)];
+ base <<= 8; base |= dev->resource[0x3f & PNP_IO_BASE_LOW(0)];
+
+ if (d->activated) {
+ if (d->base == base)
+ return 1;
+ isa_unassign_ioport(d->base, 32);
+ }
+
+ d->base = base;
+ s->irq = irq;
+
+#ifdef DEBUG_NE2000
+ printf("%s: activate addr=0x%04x irq=%d\n", dev->name, d->base, irq);
+#endif
+
+ register_ioport_write(base, 16, 1, ne2000_ioport_write, s);
+ register_ioport_read(base, 16, 1, ne2000_ioport_read, s);
+
+ register_ioport_write(base + 0x10, 1, 1, ne2000_asic_ioport_write, s);
+ register_ioport_read(base + 0x10, 1, 1, ne2000_asic_ioport_read, s);
+ register_ioport_write(base + 0x10, 2, 2, ne2000_asic_ioport_write, s);
+ register_ioport_read(base + 0x10, 2, 2, ne2000_asic_ioport_read, s);
+
+ register_ioport_write(base + 0x1f, 1, 1, ne2000_reset_ioport_write, s);
+ register_ioport_read(base + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
+
+ d->activated = 1;
+ } else
+ if (d->activated && activate == PNP_ACTIVATE_DISABLE)
+ {
+#ifdef DEBUG_NE2000
+ printf("%s: deactivated\n", dev->name);
+#endif
+ isa_unassign_ioport(d->base, 32);
+ d->activated = 0;
+ } else
+ if (activate == PNP_ACTIVATE_RESET)
+ {
+ /* reset the default */
+ d->dev.resource[0x3f & PNP_IRQ_LEVEL(0)] = d->nv_irq;
+ d->dev.resource[0x3f & PNP_IO_BASE_HIGH(0)] = d->nv_base >> 8;
+ d->dev.resource[0x3f & PNP_IO_BASE_LOW(0)] = d->nv_base & 0xff;
+
+ pnp_ne2000_activate(dev, PNP_ACTIVATE_ENABLE);
+
+ ne2000_reset(s);
+ }
+
+ return d->activated;
+}
+
+void pnp_ne2000_init(int base, int irq, NetDriverState *nd)
+{
+ PNPNE2000State *d;
+ NE2000State *s;
+ uint8_t *pnp_conf;
+ int i;
+
+ d = (PNPNE2000State *)
+ pnp_register_device(nd->ifname, sizeof(PNPNE2000State),
+ pnp_ne2000_activate,
+ NULL, NULL);
+
+ d->nv_base = base;
+ d->nv_irq = irq;
+
+ pnp_conf = d->dev.config = d->config;
+
+#if 0
+ *(uint32_t *)&pnp_conf[0] = cpu_to_le32(0x19808c4a); // RTL8019
+#else
+ *(uint32_t *)&pnp_conf[0] = cpu_to_le32(0xd680d041); // PNP80D6
+#endif
+ *(uint32_t *)&pnp_conf[4] = *(uint32_t *)nd->macaddr+2;
+ pnp_conf += 9;
+
+ *(pnp_conf++) = 0x0a; /* small item, PnP version */
+ *(pnp_conf++) = 0x10; /* Version 1.0 */
+ *(pnp_conf++) = 0x00; /* vendor version */
+
+ *(pnp_conf++) = 0x82; /* Large item, type id string */
+ i = sprintf(pnp_conf+2,
+ "QEMU NE2000 Compatible Device (%s)", nd->ifname);
+ *(uint16_t *)pnp_conf = cpu_to_le16(i);
+ pnp_conf += 2 + i;
+
+ /* logical device */
+ *(pnp_conf++) = 0x15; /* small item, logical device */
+ *(uint32_t *)pnp_conf = *(uint32_t *)d->config; pnp_conf+=4;
+ *(pnp_conf++) = 0x01; /* logical device flags[0] */
+
+ /* io port descriptor */
+ *(pnp_conf++) = 0x47; /* small iten, io port */
+ *(pnp_conf++) = 0x01; /* 16bit decode */
+ *(uint16_t *)pnp_conf = cpu_to_le16(0x280); pnp_conf+=2;
+ *(uint16_t *)pnp_conf = cpu_to_le16(0x380); pnp_conf+=2;
+ *(pnp_conf++) = 0x20; /* alignment */
+ *(pnp_conf++) = 0x20; /* ports */
+
+
+ /* irq format */
+ *(pnp_conf++) = 0x23; /* small item, irq */
+ *(pnp_conf++) = 0x80; /* irq 0-7 */
+ *(pnp_conf++) = 0x3c; /* irq 8-15 */
+ *(pnp_conf++) = 0x01;
+
+ /* end tag */
+ isa_pnp_config_checksum(&d->dev, pnp_conf);
+
+ s = &d->ne2000;
+#if 0
+ s->pnp_dev = (PNPDevice *)d;
+#endif
+ s->nd = nd;
+
+ pnp_ne2000_activate(&d->dev, PNP_ACTIVATE_RESET);
+
+ qemu_add_read_packet(s->nd, ne2000_can_receive, ne2000_receive, s);
}
/***********************************************************/
diff -burN --exclude=*.bck qemu/hw/pc.c qemu-pnp/hw/pc.c
--- qemu/hw/pc.c Sat Jun 5 14:38:11 2004
+++ qemu-pnp/hw/pc.c Sat Jun 5 16:17:03 2004
@@ -386,6 +386,10 @@
stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x210, 0x01);
}
+ if (pnp_enabled) {
+ isa_pnp_init();
+ }
+
if (pci_enabled) {
i440fx_init();
piix3_init();
@@ -431,6 +435,9 @@
if (nb_nics1 > NE2000_NB_MAX)
nb_nics1 = NE2000_NB_MAX;
for(i = 0; i < nb_nics1; i++) {
+ if (pnp_enabled)
+ pnp_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]);
+ else
isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]);
}
diff -burN --exclude=*.bck qemu/hw/pnp.c qemu-pnp/hw/pnp.c
--- qemu/hw/pnp.c Thu Jan 1 01:00:00 1970
+++ qemu-pnp/hw/pnp.c Sat Jun 5 17:13:21 2004
@@ -0,0 +1,414 @@
+/*
+ * QEMU PnP emulation
+ *
+ * Copyright (c) 2004 Antony T Curtis
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+
+//#define PNP_DEBUG
+
+#include "pnpreg.h"
+
+#define REGISTER_IOPORT_WRITE(A, B, C, D, E) do { \
+ int _i; \
+ for (_i = 0; _i < 16; _i++) \
+ register_ioport_write((_i<<12)|(A),(B),(C),(D),(E)); \
+} while (0);
+
+#define REGISTER_IOPORT_READ(A, B, C, D, E) do { \
+ int _i; \
+ for (_i = 0; _i < 16; _i++) \
+ register_ioport_read((_i<<12)|(A),(B),(C),(D),(E)); \
+} while (0);
+
+#define ISA_UNASSIGN_IOPORT(A, B) do { \
+ int _i; \
+ for (_i = 0; _i < 16; _i++) \
+ isa_unassign_ioport((_i<<12)|(A),(B)); \
+} while (0);
+
+static int pnp_enable, pnp_rd_port;
+static int pnp_isolate_index, pnp_config_index;
+static uint8_t pnp_address;
+
+static struct PNPDevice **pnp_devices;
+
+static int isa_ioport_isfree(int start, int length)
+{
+ int i, result = 1;
+ for (i = 0; result && i < 16; i++)
+ result &= !isa_assigned_ioport((i<<12)|start,length);
+ return result;
+}
+
+static uint32_t pnp_isolation_read()
+{
+ uint8_t result = -1;
+ if (pnp_isolate_index < 144)
+ {
+ int i = pnp_isolate_index >> 1, j;
+ int mask = 0x1 << (i & 7);
+
+ for (j = 0; j < 256; j++)
+ if (pnp_devices[j] != NULL &&
+ pnp_devices[j]->mode == PNP_ISOLATION &&
+ (pnp_devices[j]->config[i/8] & mask))
+ result &= pnp_isolate_index & 1 ? 0xaa : 0x55;
+
+ for (j = 0; j < 256; j++)
+ if (pnp_devices[j] != NULL &&
+ pnp_devices[j]->mode == PNP_ISOLATION) {
+ if (pnp_devices[j]->config[i/8] & mask)
+ continue;
+ if (result != (pnp_isolate_index & 1 ? 0xaa : 0x55))
+ continue;
+ pnp_devices[j]->mode = PNP_SLEEP;
+ }
+
+ pnp_isolate_index++;
+ }
+ return result;
+}
+
+static uint32_t pnp_readdata_read(void *opaque, uint32_t addr)
+{
+ uint32_t result = -1;
+ int i;
+
+ switch (pnp_address)
+ {
+ case PNP_SERIAL_ISOLATION:
+ result = pnp_isolation_read();
+ break;
+ case PNP_STATUS:
+ result = 1;
+ for (i = 0; i<256; i++)
+ if (pnp_devices[i] != NULL) {
+ if (pnp_devices[i]->mode == PNP_CONFIG)
+ result &= pnp_config_index < pnp_devices[i]->config_size;
+ }
+ printf("pnp: resource status read [0x%02x] result=0x%02x\n",
+ pnp_config_index, result);
+ break;
+ case PNP_RESOURCE_DATA:
+ for (i = 0; i<256; i++)
+ if (pnp_devices[i] != NULL) {
+ if (pnp_devices[i]->mode == PNP_CONFIG &&
+ pnp_config_index < pnp_devices[i]->config_size) {
+ result &= pnp_devices[i]->config[pnp_config_index];
+ }
+ }
+ printf("pnp: resource read [0x%02x] result=0x%02x\n",
+ pnp_config_index, result);
+ pnp_config_index++;
+ break;
+ case PNP_ACTIVATE:
+ for (i = 0; i<256; i++)
+ if (pnp_devices[i] != NULL) {
+ if (pnp_devices[i]->mode == PNP_CONFIG)
+ result &= pnp_devices[i]->
+ pnp_card_activate(pnp_devices[i], PNP_ACTIVATE_INQUIRE);
+ }
+ break;
+ case PNP_SET_CSN:
+ for (i = 0; i < 256; i++)
+ if (pnp_devices[i] != NULL &&
+ pnp_devices[i]->mode == PNP_CONFIG) {
+ result &= pnp_devices[i]->csn;
+ }
+ break;
+ case PNP_SET_LDN:
+ case PNP_IO_RANGE_CHECK:
+ result = 0;
+ break;
+ default:
+ if (pnp_address >= 0x40 && pnp_address < 0x80) {
+ for (i = 0; i<256; i++)
+ if (pnp_devices[i] != NULL) {
+ if (pnp_devices[i]->mode == PNP_CONFIG)
+ result &= pnp_devices[i]->pnp_config_read(pnp_devices[i], pnp_address);
+ }
+ } else
+ printf("pnp: unhandled pnp_readdata adr=0x%02x\n",pnp_address);
+ }
+ /*printf("pnp: address_read [0x%02x] result=0x%02x\n", pnp_address, result);*/
+ return result;
+}
+
+static void pnp_set_rd_port(uint32_t port)
+{
+ if (port < 0x203 || port > 0x3ff)
+ port = -1;
+ if (pnp_rd_port != port) {
+ if (pnp_rd_port != -1) {
+ ISA_UNASSIGN_IOPORT(port,1);
+ pnp_rd_port = -1;
+ }
+ if (port != -1) {
+ if (!isa_ioport_isfree(port,1)) {
+#ifdef PNP_DEBUG
+ printf("pnp: pnp read port in use\n");
+#endif
+ port = -1;
+ } else
+ REGISTER_IOPORT_READ(port, 1, 1, pnp_readdata_read, NULL);
+ pnp_rd_port = port;
+ }
+ }
+}
+
+static void pnp_writedata_write(void *opaque, uint32_t addr, uint32_t val)
+{
+ int i;
+#ifdef PNP_DEBUG
+ printf("pnp: write data [0x%02x] = 0x%02x\n", pnp_address, val);
+#endif
+ switch (pnp_address)
+ {
+ case PNP_CONFIG_CONTROL:
+ for (i = 0; i < 256; i++)
+ if (pnp_devices[i] != NULL) {
+ if (pnp_devices[i]->mode != PNP_WAITFORKEY) {
+ if (val & PNP_CONFIG_CONTROL_RESET_CSN)
+ pnp_devices[i]->
+ pnp_card_activate(pnp_devices[i],PNP_ACTIVATE_RESET);
+ if (val & PNP_CONFIG_CONTROL_RESET_CSN)
+ pnp_devices[i]->csn = 0;
+ }
+ if (val & PNP_CONFIG_CONTROL_WAIT_FOR_KEY)
+ pnp_devices[i]->mode = PNP_WAITFORKEY;
+ }
+ break;
+ case PNP_ACTIVATE:
+ for (i = 0; i<256; i++)
+ if (pnp_devices[i] != NULL) {
+ if (pnp_devices[i]->mode == PNP_CONFIG) {
+ pnp_devices[i]->
+ pnp_card_activate(pnp_devices[i], (val & 1)
+ ? PNP_ACTIVATE_ENABLE : PNP_ACTIVATE_DISABLE);
+ if (val == 0)
+ pnp_devices[i]->mode = PNP_WAITFORKEY;
+ }
+ }
+ break;
+ case PNP_WAKE:
+ for (i = 0; i<256; i++)
+ if (pnp_devices[i] != NULL) {
+ if ((pnp_devices[i]->mode == PNP_ISOLATION ||
+ pnp_devices[i]->mode == PNP_CONFIG) &&
+ (pnp_devices[i]->csn != val))
+ pnp_devices[i]->mode = PNP_SLEEP;
+ if ((pnp_devices[i]->mode == PNP_SLEEP) &&
+ (pnp_devices[i]->csn == val)) {
+ pnp_devices[i]->mode = val ? PNP_CONFIG : PNP_ISOLATION;
+ pnp_isolate_index = 0;
+ pnp_config_index = 9;
+ }
+ }
+ break;
+ case PNP_SET_RD_DATA:
+ pnp_set_rd_port((val << 2) | 3);
+ break;
+ case PNP_SET_CSN:
+ if (val == 0)
+ break;
+ for (i = 0; i < 256; i++)
+ if (pnp_devices[i] != NULL &&
+ pnp_devices[i]->mode == PNP_ISOLATION) {
+ pnp_devices[i]->mode = PNP_CONFIG;
+ pnp_devices[i]->csn = val;
+#ifdef PNP_DEBUG
+ printf("pnp: Device[%s]: CSN=%d\n", pnp_devices[i]->name, val);
+#endif
+ }
+ break;
+ case PNP_SET_LDN:
+ break;
+ default:
+ if (pnp_address >= 0x40 && pnp_address < 0x80) {
+ for (i = 0; i<256; i++)
+ if (pnp_devices[i] != NULL) {
+ if (pnp_devices[i]->mode == PNP_CONFIG)
+ pnp_devices[i]->pnp_config_write(pnp_devices[i], pnp_address,val);
+ }
+ } else
+ printf("pnp: unhandled pnp_writedata adr=0x%02x value=0x%02x\n",pnp_address,val);
+ }
+}
+
+static void pnp_address_write(void *opaque, uint32_t addr, uint32_t val)
+{
+ static int pnp_wait_for_key = 0;
+ static uint8_t pnp_lfsr = -1;
+ int i;
+
+ if ((pnp_address == 0) && (val == 0))
+ {
+ pnp_lfsr = 0x6a;
+ pnp_wait_for_key = 1;
+#ifdef PNP_DEBUG
+ printf("pnp: KEY LFSR INIT\n");
+#endif
+ } else
+ if (pnp_wait_for_key) {
+ if (val == pnp_lfsr) {
+ if (pnp_wait_for_key == 32) {
+#ifdef PNP_DEBUG
+ printf("pnp: KEY DECODED\n");
+#endif
+ pnp_wait_for_key = 0;
+ for (i = 0; i<256; i++)
+ if (pnp_devices[i] != NULL) {
+ if (pnp_devices[i]->mode == PNP_WAITFORKEY)
+ pnp_devices[i]->mode = PNP_SLEEP;
+ }
+ if (!pnp_enable) {
+ REGISTER_IOPORT_WRITE(_PNP_WRITE_DATA, 1, 1,
+ pnp_writedata_write, NULL);
+ pnp_enable = 1;
+ }
+ } else {
+ pnp_lfsr = (pnp_lfsr >> 1) |
+ (((pnp_lfsr ^ (pnp_lfsr >> 1)) << 7) & 0xff);
+ pnp_wait_for_key++;
+ }
+ } else {
+#ifdef PNP_DEBUG
+ printf("pnp: KEY DECODE FAILED at %d\n", pnp_wait_for_key);
+#endif
+ pnp_wait_for_key = 0;
+ pnp_lfsr = -1;
+ }
+ return;
+ }
+
+#ifdef PNP_DEBUG
+ if (0) printf("pnp: address_write = 0x%02x\n", val);
+#endif
+
+ switch (pnp_address) {
+ case PNP_SERIAL_ISOLATION:
+ pnp_isolate_index = 0;
+ break;
+ }
+ pnp_address = val;
+}
+
+void isa_pnp_init()
+{
+ pnp_enable = 0;
+ pnp_address = -1;
+ pnp_rd_port = -1;
+
+ pnp_isolate_index = -1;
+ pnp_config_index = 65536;
+
+ pnp_devices = qemu_mallocz(256 * sizeof(PNPDevice *));
+ REGISTER_IOPORT_WRITE(_PNP_ADDRESS, 1, 1, pnp_address_write, NULL);
+}
+
+void isa_pnp_config_checksum(PNPDevice *device, uint8_t *end)
+{
+ uint8_t *config = device->config;
+ uint8_t csum = 0x6a;
+ int i;
+
+ /* fixup pnp serial */
+ for (i = 0; i < 64; i++) {
+ int bit = (config[i/8] & (1<<(i&7))) != 0;
+ csum = (csum >> 1) | (((csum ^ (csum >> 1) ^ bit) << 7) & 0xff);
+ }
+ config[8] = csum;
+
+ /* Add end tag */
+ *(end++) = 0x78;
+ csum = 0;
+ while (config != end) {
+ csum += *(config++);
+ }
+ *(end++) = -csum;
+ device->config_size = end - device->config;
+#ifdef PNP_DEBUG
+ printf("%s: config size = %d\n",device->name, device->config_size);
+#endif
+}
+
+static int pnp_default_card_activate(PNPDevice *dev, enum PNPActivate value)
+{
+#ifdef PNP_DEBUG
+ printf("%s: pnp card activate, enable=%d\n",dev->name, value);
+#endif
+ return 1;
+}
+
+void pnp_default_config_write(PNPDevice *dev, uint8_t addr, uint8_t data)
+{
+ dev->resource[addr & 0x3f] = data;
+#ifdef PNP_DEBUG
+ printf("%s: pnp config write, reg[0x%02x] = 0x%02x\n",
+ dev->name, addr, data);
+#endif
+}
+
+uint8_t pnp_default_config_read(PNPDevice *dev, uint8_t addr)
+{
+ uint8_t result = dev->resource[addr & 0x3f];
+#ifdef PNP_DEBUG
+ printf("%s: pnp config read, reg[0x%02x] = 0x%02x\n",
+ dev->name, addr, result);
+#endif
+ return result;
+}
+
+PNPDevice *pnp_register_device(const char *name, int instance_size,
+ PNPCardActivateFunc *card_activate,
+ PNPConfigWriteFunc *config_write,
+ PNPConfigReadFunc *config_read)
+{
+ int i;
+ PNPDevice *dev;
+
+ dev = qemu_mallocz(instance_size);
+ if (!dev)
+ return NULL;
+ pstrcpy(dev->name, sizeof(dev->name), name);
+
+ if (!card_activate)
+ card_activate = pnp_default_card_activate;
+
+ if (!config_write)
+ config_write = pnp_default_config_write;
+
+ if (!config_read)
+ config_read = pnp_default_config_read;
+
+ dev->pnp_card_activate = card_activate;
+ dev->pnp_config_write = config_write;
+ dev->pnp_config_read = config_read;
+
+ for (i = 0; i < 256; i++)
+ if (pnp_devices[i] == NULL) {
+ pnp_devices[i] = dev;
+ break;
+ }
+
+ return dev;
+}
diff -burN --exclude=*.bck qemu/hw/pnpreg.h qemu-pnp/hw/pnpreg.h
--- qemu/hw/pnpreg.h Thu Jan 1 01:00:00 1970
+++ qemu-pnp/hw/pnpreg.h Sat Jun 5 15:46:26 2004
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 1996, Sujal M. Patel
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Sujal M. Patel
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/isa/pnpreg.h,v 1.5 2002/04/09 11:18:40 phk Exp $
+ * from: pnp.h,v 1.7 1998/09/13 22:15:44 eivind Exp
+ */
+
+#ifndef _ISA_PNPREG_H_
+#define _ISA_PNPREG_H_
+
+/* Maximum Number of PnP Devices. 8 should be plenty */
+#define PNP_MAX_CARDS 8
+
+/* Static ports to access PnP state machine */
+#ifdef PC98
+#define _PNP_ADDRESS 0x259
+#define _PNP_WRITE_DATA 0xa59
+#else
+#define _PNP_ADDRESS 0x279
+#define _PNP_WRITE_DATA 0xa79
+#endif
+
+/* PnP Registers. Write to ADDRESS and then use WRITE/READ_DATA */
+#define PNP_SET_RD_DATA 0x00
+ /***
+ Writing to this location modifies the address of the port used for
+ reading from the Plug and Play ISA cards. Bits[7:0] become I/O
+ read port address bits[9:2]. Reads from this register are ignored.
+ ***/
+
+#define PNP_SERIAL_ISOLATION 0x01
+ /***
+ A read to this register causes a Plug and Play cards in the Isolation
+ state to compare one bit of the boards ID.
+ This register is read only.
+ ***/
+
+#define PNP_CONFIG_CONTROL 0x02
+#define PNP_CONFIG_CONTROL_RESET_CSN 0x04
+#define PNP_CONFIG_CONTROL_WAIT_FOR_KEY 0x02
+#define PNP_CONFIG_CONTROL_RESET 0x01
+ /***
+ Bit[2] Reset CSN to 0
+ Bit[1] Return to the Wait for Key state
+ Bit[0] Reset all logical devices and restore configuration
+ registers to their power-up values.
+
+ A write to bit[0] of this register performs a reset function on
+ all logical devices. This resets the contents of configuration
+ registers to their default state. All card's logical devices
+ enter their default state and the CSN is preserved.
+
+ A write to bit[1] of this register causes all cards to enter the
+ Wait for Key state but all CSNs are preserved and logical devices
+ are not affected.
+
+ A write to bit[2] of this register causes all cards to reset their
+ CSN to zero .
+
+ This register is write-only. The values are not sticky, that is,
+ hardware will automatically clear them and there is no need for
+ software to clear the bits.
+ ***/
+
+#define PNP_WAKE 0x03
+ /***
+ A write to this port will cause all cards that have a CSN that
+ matches the write data[7:0] to go from the Sleep state to the either
+ the Isolation state if the write data for this command is zero or
+ the Config state if the write data is not zero. Additionally, the
+ pointer to the byte-serial device is reset. This register is
+ writeonly.
+ ***/
+
+#define PNP_RESOURCE_DATA 0x04
+ /***
+ A read from this address reads the next byte of resource information.
+ The Status register must be polled until bit[0] is set before this
+ register may be read. This register is read only.
+ ***/
+
+#define PNP_STATUS 0x05
+ /***
+ Bit[0] when set indicates it is okay to read the next data byte
+ from the Resource Data register. This register is readonly.
+ ***/
+
+#define PNP_SET_CSN 0x06
+ /***
+ A write to this port sets a card's CSN. The CSN is a value uniquely
+ assigned to each ISA card after the serial identification process
+ so that each card may be individually selected during a Wake[CSN]
+ command. This register is read/write.
+ ***/
+
+#define PNP_SET_LDN 0x07
+ /***
+ Selects the current logical device. All reads and writes of memory,
+ I/O, interrupt and DMA configuration information access the registers
+ of the logical device written here. In addition, the I/O Range
+ Check and Activate commands operate only on the selected logical
+ device. This register is read/write. If a card has only 1 logical
+ device, this location should be a read-only value of 0x00.
+ ***/
+
+/*** addresses 0x08 - 0x1F Card Level Reserved for future use ***/
+/*** addresses 0x20 - 0x2F Card Level, Vendor Defined ***/
+
+#define PNP_ACTIVATE 0x30
+ /***
+ For each logical device there is one activate register that controls
+ whether or not the logical device is active on the ISA bus. Bit[0],
+ if set, activates the logical device. Bits[7:1] are reserved and
+ must return 0 on reads. This is a read/write register. Before a
+ logical device is activated, I/O range check must be disabled.
+ ***/
+
+#define PNP_IO_RANGE_CHECK 0x31
+#define PNP_IO_RANGE_CHECK_ENABLE 0x02
+#define PNP_IO_RANGE_CHECK_READ_AS_55 0x01
+ /***
+ This register is used to perform a conflict check on the I/O port
+ range programmed for use by a logical device.
+
+ Bit[7:2] Reserved and must return 0 on reads
+ Bit[1] Enable I/O Range check, if set then I/O Range Check
+ is enabled. I/O range check is only valid when the logical
+ device is inactive.
+
+ Bit[0], if set, forces the logical device to respond to I/O reads
+ of the logical device's assigned I/O range with a 0x55 when I/O
+ range check is in operation. If clear, the logical device drives
+ 0xAA. This register is read/write.
+ ***/
+
+/*** addr 0x32 - 0x37 Logical Device Control Reserved for future use ***/
+/*** addr 0x38 - 0x3F Logical Device Control Vendor Define ***/
+
+#define PNP_MEM_BASE_HIGH(i) (0x40 + 8*(i))
+#define PNP_MEM_BASE_LOW(i) (0x41 + 8*(i))
+#define PNP_MEM_CONTROL(i) (0x42 * 8*(i))
+#define PNP_MEM_CONTROL_16BIT 0x2
+#define PNP_MEM_CONTROL_LIMIT 0x1
+#define PNP_MEM_RANGE_HIGH(i) (0x43 + 8*(i))
+#define PNP_MEM_RANGE_LOW(i) (0x44 + 8*(i))
+ /***
+ Four memory resource registers per range, four ranges.
+ Fill with 0 if no ranges are enabled.
+
+ Offset 0: RW Memory base address bits[23:16]
+ Offset 1: RW Memory base address bits[15:8]
+ Offset 2: Memory control
+ Bit[1] specifies 8/16-bit control. This bit is set to indicate
+ 16-bit memory, and cleared to indicate 8-bit memory.
+ Bit[0], if cleared, indicates the next field can be used as a range
+ length for decode (implies range length and base alignment of memory
+ descriptor are equal).
+ Bit[0], if set, indicates the next field is the upper limit for
+ the address. - - Bit[0] is read-only.
+ Offset 3: RW upper limit or range len, bits[23:16]
+ Offset 4: RW upper limit or range len, bits[15:8]
+ Offset 5-Offset 7: filler, unused.
+ ***/
+
+#define PNP_IO_BASE_HIGH(i) (0x60 + 2*(i))
+#define PNP_IO_BASE_LOW(i) (0x61 + 2*(i))
+ /***
+ Eight ranges, two bytes per range.
+ Offset 0: I/O port base address bits[15:8]
+ Offset 1: I/O port base address bits[7:0]
+ ***/
+
+#define PNP_IRQ_LEVEL(i) (0x70 + 2*(i))
+#define PNP_IRQ_TYPE(i) (0x71 + 2*(i))
+ /***
+ Two entries, two bytes per entry.
+ Offset 0: RW interrupt level (1..15, 0=unused).
+ Offset 1: Bit[1]: level(1:hi, 0:low),
+ Bit[0]: type (1:level, 0:edge)
+ byte 1 can be readonly if 1 type of int is used.
+ ***/
+
+#define PNP_DMA_CHANNEL(i) (0x74 + 1*(i))
+ /***
+ Two entries, one byte per entry. Bits[2:0] select
+ which DMA channel is in use for DMA 0. Zero selects DMA channel
+ 0, seven selects DMA channel 7. DMA channel 4, the cascade channel
+ is used to indicate no DMA channel is active.
+ ***/
+
+/*** 32-bit memory accesses are at 0x76 ***/
+
+/* Macros to parse Resource IDs */
+#define PNP_RES_TYPE(a) (a >> 7)
+#define PNP_SRES_NUM(a) (a >> 3)
+#define PNP_SRES_LEN(a) (a & 0x07)
+#define PNP_LRES_NUM(a) (a & 0x7f)
+
+/* Small Resource Item names */
+#define PNP_TAG_VERSION 0x1
+#define PNP_TAG_LOGICAL_DEVICE 0x2
+#define PNP_TAG_COMPAT_DEVICE 0x3
+#define PNP_TAG_IRQ_FORMAT 0x4
+#define PNP_TAG_DMA_FORMAT 0x5
+#define PNP_TAG_START_DEPENDANT 0x6
+#define PNP_TAG_END_DEPENDANT 0x7
+#define PNP_TAG_IO_RANGE 0x8
+#define PNP_TAG_IO_FIXED 0x9
+#define PNP_TAG_RESERVED 0xa-0xd
+#define PNP_TAG_VENDOR 0xe
+#define PNP_TAG_END 0xf
+
+/* Large Resource Item names */
+#define PNP_TAG_MEMORY_RANGE 0x1
+#define PNP_TAG_ID_ANSI 0x2
+#define PNP_TAG_ID_UNICODE 0x3
+#define PNP_TAG_LARGE_VENDOR 0x4
+#define PNP_TAG_MEMORY32_RANGE 0x5
+#define PNP_TAG_MEMORY32_FIXED 0x6
+#define PNP_TAG_LARGE_RESERVED 0x7-0x7f
+
+#endif /* !_ISA_PNPREG_H_ */
diff -burN --exclude=*.bck qemu/vl.c qemu-pnp/vl.c
--- qemu/vl.c Sat Jun 5 13:50:36 2004
+++ qemu-pnp/vl.c Sat Jun 5 16:48:30 2004
@@ -128,6 +128,7 @@
QEMUTimer *gui_timer;
int vm_running;
int audio_enabled = 0;
+int pnp_enabled = 0;
int pci_enabled = 0;
int prep_enabled = 0;
int rtc_utc = 1;
@@ -260,9 +261,26 @@
ioport_write_table[0][i] = default_ioport_writeb;
ioport_write_table[1][i] = default_ioport_writew;
ioport_write_table[2][i] = default_ioport_writel;
+ ioport_opaque[i] = NULL;
}
}
+int isa_assigned_ioport(int start, int length)
+{
+ int i, result = 1;
+
+ for(i = start; result && i < start + length; i++) {
+ result &= ioport_read_table[0][i] == default_ioport_readb;
+ result &= ioport_read_table[1][i] == default_ioport_readw;
+ result &= ioport_read_table[2][i] == default_ioport_readl;
+
+ result &= ioport_write_table[0][i] == default_ioport_writeb;
+ result &= ioport_write_table[1][i] == default_ioport_writew;
+ result &= ioport_write_table[2][i] == default_ioport_writel;
+ }
+ return result == 0;
+}
+
void pstrcpy(char *buf, int buf_size, const char *str)
{
int c;
@@ -2079,6 +2097,7 @@
QEMU_OPTION_L,
QEMU_OPTION_no_code_copy,
QEMU_OPTION_pci,
+ QEMU_OPTION_pnp,
QEMU_OPTION_prep,
QEMU_OPTION_localtime,
};
@@ -2128,6 +2147,7 @@
/* temporary options */
{ "pci", 0, QEMU_OPTION_pci },
+ { "pnp", 0, QEMU_OPTION_pnp },
#ifdef TARGET_PPC
{ "prep", 0, QEMU_OPTION_prep },
#endif
@@ -2404,6 +2424,9 @@
break;
case QEMU_OPTION_pci:
pci_enabled = 1;
+ break;
+ case QEMU_OPTION_pnp:
+ pnp_enabled = 1;
break;
case QEMU_OPTION_prep:
prep_enabled = 1;
diff -burN --exclude=*.bck qemu/vl.h qemu-pnp/vl.h
--- qemu/vl.h Sat Jun 5 13:25:07 2004
+++ qemu-pnp/vl.h Sat Jun 5 16:35:40 2004
@@ -379,6 +379,60 @@
int register_ioport_write(int start, int length, int size,
IOPortWriteFunc *func, void *opaque);
void isa_unassign_ioport(int start, int length);
+int isa_assigned_ioport(int start, int length);
+
+/* PNP devices */
+
+extern int pnp_enabled;
+
+enum PNPActivate {
+ PNP_ACTIVATE_INQUIRE=-1,
+ PNP_ACTIVATE_DISABLE=0,
+ PNP_ACTIVATE_ENABLE=1,
+ PNP_ACTIVATE_RESET=2
+};
+
+typedef struct PNPDevice PNPDevice;
+
+typedef int PNPCardActivateFunc(PNPDevice *pci_dev, enum PNPActivate value);
+
+typedef void PNPConfigWriteFunc(PNPDevice *pci_dev,
+ uint8_t address, uint8_t data);
+
+typedef uint8_t PNPConfigReadFunc(PNPDevice *pci_dev,
+ uint8_t address);
+
+
+struct PNPDevice {
+ /* PNP config space */
+ uint8_t *config;
+ uint8_t resource[0x40];
+ enum {
+ PNP_WAITFORKEY=0,
+ PNP_SLEEP,
+ PNP_ISOLATION,
+ PNP_CONFIG
+ } mode;
+ char name[64];
+ int config_size;
+ uint8_t csn;
+
+ PNPCardActivateFunc *pnp_card_activate;
+ PNPConfigWriteFunc *pnp_config_write;
+ PNPConfigReadFunc *pnp_config_read;
+};
+
+PNPDevice *pnp_register_device(const char *name, int instance_size,
+ PNPCardActivateFunc *activate,
+ PNPConfigWriteFunc *config_write,
+ PNPConfigReadFunc *config_read);
+
+void isa_pnp_init();
+
+void isa_pnp_config_checksum(PNPDevice *device, uint8_t *end);
+
+void pnp_default_config_write(PNPDevice *dev, uint8_t addr, uint8_t data);
+uint8_t pnp_default_config_read(PNPDevice *dev, uint8_t addr);
/* PCI bus */
@@ -548,6 +602,7 @@
/* ne2000.c */
void isa_ne2000_init(int base, int irq, NetDriverState *nd);
+void pnp_ne2000_init(int base, int irq, NetDriverState *nd);
void pci_ne2000_init(NetDriverState *nd);
/* pckbd.c */
^ permalink raw reply [flat|nested] 8+ messages in thread