--- trunk/src/devices/bus_pci.c 2007/10/08 16:19:56 24 +++ trunk/src/devices/bus_pci.c 2007/10/08 16:20:40 30 @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: bus_pci.c,v 1.65 2006/05/10 03:32:32 debug Exp $ + * $Id: bus_pci.c,v 1.70 2006/08/12 19:38:24 debug Exp $ * * Generic PCI bus framework. This is not a normal "device", but is used by * individual PCI controllers and devices. @@ -57,6 +57,8 @@ #include "memory.h" #include "misc.h" +#include "wdc.h" + extern int verbose; @@ -147,15 +149,27 @@ pci_data->last_was_write_ffffffff = 1; return; } - /* Writes are not really supported yet: */ - if (idata != x) { + + if (dev->cfg_reg_write != NULL) { + dev->cfg_reg_write(dev, pci_data->cur_reg, *data); + } else { + /* Print a warning for unhandled writes: */ debug("[ bus_pci: write to PCI DATA: data = 0x%08llx" - " differs from current value 0x%08llx; NOT YET" + " (current value = 0x%08llx); NOT YET" " SUPPORTED. bus %i, device %i, function %i (%s)" " register 0x%02x ]\n", (long long)idata, (long long)x, pci_data->cur_bus, pci_data->cur_device, pci_data->cur_func, dev->name, pci_data->cur_reg); + + /* Special warning, to detect if NetBSD's special + detection of PCI devices fails: */ + if (pci_data->cur_reg == PCI_COMMAND_STATUS_REG + && !((*data) & PCI_COMMAND_IO_ENABLE)) { + fatal("\n[ NetBSD PCI detection stuff not" + " yet implemented for device '%s' ]\n", + dev->name); + } } return; } @@ -420,15 +434,16 @@ /* - * Integraphics Systems "igsfb" Framebuffer (graphics) card. - * - * TODO + * Integraphics Systems "igsfb" Framebuffer (graphics) card, used in at + * least the NetWinder. */ #define PCI_VENDOR_INTEGRAPHICS 0x10ea PCIINIT(igsfb) { + char tmpstr[200]; + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_INTEGRAPHICS, 0x2010)); @@ -439,8 +454,9 @@ /* TODO */ PCI_SET_DATA(0x10, 0x08000000); - dev_vga_init(machine, mem, pd->pcibus->isa_membase + 0xa0000, - 0x88800000 + 0x3c0, machine->machine_name); + snprintf(tmpstr, sizeof(tmpstr), "igsfb addr=0x%llx", + (long long)(pd->pcibus->isa_membase + 0x08000000)); + device_add(machine, tmpstr); } @@ -627,6 +643,47 @@ /* + * AMD PCnet Ethernet card. + * + * "Am79c970A PCnet-PCI II rev 0" or similar. + */ + +#define PCI_VENDOR_AMD 0x1022 /* Advanced Micro Devices */ +#define PCI_PRODUCT_AMD_PCNET_PCI 0x2000 /* PCnet-PCI Ethernet */ + +PCIINIT(pcn) +{ + int irq; + + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_AMD, + PCI_PRODUCT_AMD_PCNET_PCI)); + + PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_NETWORK, + PCI_SUBCLASS_NETWORK_ETHERNET, 0) + 0x00); /* Revision 0 */ + + switch (machine->machine_type) { + + case MACHINE_EVBMIPS: + irq = (1 << 8) + 10; /* TODO */ + break; + + default:fatal("pcn in non-implemented machine type %i\n", + machine->machine_type); + exit(1); + } + + PCI_SET_DATA(PCI_INTERRUPT_REG, 0x01100000 | irq); + + /* + * TODO: Add the pcn device here. The pcn device will need to work as + * a wrapper for dev_le + all the DMA magic and whatever is required. + * It's too much to implement right now. + */ +} + + + +/* * Intel 31244 Serial ATA Controller * Intel 82371SB PIIX3 PCI-ISA bridge * Intel 82371AB PIIX4 PCI-ISA bridge @@ -721,6 +778,31 @@ PCI_SET_DATA(0x60, 0x0f0e0b0a); } +struct piix_ide_extra { + void *wdc0; + void *wdc1; +}; + +int piix_ide_cfg_reg_write(struct pci_device *pd, int reg, uint32_t value) +{ + void *wdc0 = ((struct piix_ide_extra *)pd->extra)->wdc0; + void *wdc1 = ((struct piix_ide_extra *)pd->extra)->wdc1; + int enabled = 0; + + switch (reg) { + case PCI_COMMAND_STATUS_REG: + if (value & PCI_COMMAND_IO_ENABLE) + enabled = 1; + if (wdc0 != NULL) + wdc_set_io_enabled(wdc0, enabled); + if (wdc1 != NULL) + wdc_set_io_enabled(wdc1, enabled); + return 1; + } + + return 0; +} + PCIINIT(piix3_ide) { char tmpstr[100]; @@ -736,12 +818,21 @@ /* channel 0 and 1 enabled as IDE */ PCI_SET_DATA(0x40, 0x80008000); + pd->extra = malloc(sizeof(struct piix_ide_extra)); + if (pd->extra == NULL) { + fatal("Out of memory.\n"); + exit(1); + } + ((struct piix_ide_extra *)pd->extra)->wdc0 = NULL; + ((struct piix_ide_extra *)pd->extra)->wdc1 = NULL; + if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || diskimage_exist(machine, 1, DISKIMAGE_IDE)) { snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%i", (long long)(pd->pcibus->isa_portbase + 0x1f0), pd->pcibus->isa_irqbase + 14); - device_add(machine, tmpstr); + ((struct piix_ide_extra *)pd->extra)->wdc0 = + device_add(machine, tmpstr); } if (diskimage_exist(machine, 2, DISKIMAGE_IDE) || @@ -749,8 +840,11 @@ snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%i", (long long)(pd->pcibus->isa_portbase + 0x170), pd->pcibus->isa_irqbase + 15); - device_add(machine, tmpstr); + ((struct piix_ide_extra *)pd->extra)->wdc1 = + device_add(machine, tmpstr); } + + pd->cfg_reg_write = piix_ide_cfg_reg_write; } PCIINIT(piix4_ide) @@ -768,12 +862,21 @@ /* channel 0 and 1 enabled as IDE */ PCI_SET_DATA(0x40, 0x80008000); + pd->extra = malloc(sizeof(struct piix_ide_extra)); + if (pd->extra == NULL) { + fatal("Out of memory.\n"); + exit(1); + } + ((struct piix_ide_extra *)pd->extra)->wdc0 = NULL; + ((struct piix_ide_extra *)pd->extra)->wdc1 = NULL; + if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || diskimage_exist(machine, 1, DISKIMAGE_IDE)) { snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%i", (long long)(pd->pcibus->isa_portbase + 0x1f0), pd->pcibus->isa_irqbase + 14); - device_add(machine, tmpstr); + ((struct piix_ide_extra *)pd->extra)->wdc0 = + device_add(machine, tmpstr); } if (diskimage_exist(machine, 2, DISKIMAGE_IDE) || @@ -781,8 +884,11 @@ snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%i", (long long)(pd->pcibus->isa_portbase + 0x170), pd->pcibus->isa_irqbase + 15); - device_add(machine, tmpstr); + ((struct piix_ide_extra *)pd->extra)->wdc1 = + device_add(machine, tmpstr); } + + pd->cfg_reg_write = piix_ide_cfg_reg_write; } @@ -856,6 +962,31 @@ PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0)); } +struct vt82c586_ide_extra { + void *wdc0; + void *wdc1; +}; + +int vt82c586_ide_cfg_reg_write(struct pci_device *pd, int reg, uint32_t value) +{ + void *wdc0 = ((struct vt82c586_ide_extra *)pd->extra)->wdc0; + void *wdc1 = ((struct vt82c586_ide_extra *)pd->extra)->wdc1; + int enabled = 0; + + switch (reg) { + case PCI_COMMAND_STATUS_REG: + if (value & PCI_COMMAND_IO_ENABLE) + enabled = 1; + if (wdc0 != NULL) + wdc_set_io_enabled(wdc0, enabled); + if (wdc1 != NULL) + wdc_set_io_enabled(wdc1, enabled); + return 1; + } + + return 0; +} + PCIINIT(vt82c586_ide) { char tmpstr[100]; @@ -871,12 +1002,21 @@ /* channel 0 and 1 enabled */ PCI_SET_DATA(0x40, 0x00000003); + pd->extra = malloc(sizeof(struct vt82c586_ide_extra)); + if (pd->extra == NULL) { + fatal("Out of memory.\n"); + exit(1); + } + ((struct vt82c586_ide_extra *)pd->extra)->wdc0 = NULL; + ((struct vt82c586_ide_extra *)pd->extra)->wdc1 = NULL; + if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || diskimage_exist(machine, 1, DISKIMAGE_IDE)) { snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%i", (long long)(pd->pcibus->isa_portbase + 0x1f0), pd->pcibus->isa_irqbase + 14); - device_add(machine, tmpstr); + ((struct vt82c586_ide_extra *)pd->extra)->wdc0 = + device_add(machine, tmpstr); } if (diskimage_exist(machine, 2, DISKIMAGE_IDE) || @@ -884,8 +1024,11 @@ snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%i", (long long)(pd->pcibus->isa_portbase + 0x170), pd->pcibus->isa_irqbase + 15); - device_add(machine, tmpstr); + ((struct vt82c586_ide_extra *)pd->extra)->wdc1 = + device_add(machine, tmpstr); } + + pd->cfg_reg_write = vt82c586_ide_cfg_reg_write; }