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 */