--- trunk/src/devices/bus_pci.c 2007/10/08 16:19:28 21 +++ trunk/src/devices/bus_pci.c 2007/10/08 16:19:37 22 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2005 Anders Gavare. All rights reserved. + * Copyright (C) 2004-2006 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: bus_pci.c,v 1.40 2005/11/25 03:59:58 debug Exp $ + * $Id: bus_pci.c,v 1.62 2006/02/18 21:03:12 debug Exp $ * * Generic PCI bus framework. This is not a normal "device", but is used by * individual PCI controllers and devices. @@ -60,88 +60,88 @@ extern int verbose; -/* #define debug fatal */ +/* #define debug fatal */ -static void reverse(uint64_t *p, int len) +/* + * bus_pci_decompose_1(): + * + * Helper function for decomposing Mechanism 1 tags. + */ +void bus_pci_decompose_1(uint32_t t, int *bus, int *dev, int *func, int *reg) { - uint64_t x = *p, y = 0; - int i; - for (i=0; i> (8*i)) & 0xff); - } - *p = y; + *bus = (t >> 16) & 0xff; + *dev = (t >> 11) & 0x1f; + *func = (t >> 8) & 0x7; + *reg = t & 0xff; + + /* Warn about unaligned register access: */ + if (t & 3) + fatal("[ bus_pci_decompose_1: WARNING: reg = 0x%02x ]\n", + t & 0xff); } /* * bus_pci_data_access(): * - * Reads from and writes to the PCI configuration registers of a device. + * Reads from or writes to the PCI configuration registers of a device. */ -void bus_pci_data_access(struct cpu *cpu, struct memory *mem, - uint64_t *data, int len, int writeflag, struct pci_data *pci_data) +void bus_pci_data_access(struct cpu *cpu, struct pci_data *pci_data, + uint64_t *data, int len, int writeflag) { struct pci_device *dev; - int bus, device, function, registernr; unsigned char *cfg_base; uint64_t x, idata = *data; - - if (cpu->byte_order == EMUL_BIG_ENDIAN) - reverse(&idata, len); - - /* Get the bus, device, and function numbers from the address: */ - bus = (pci_data->pci_addr >> 16) & 0xff; - device = (pci_data->pci_addr >> 11) & 0x1f; - function = (pci_data->pci_addr >> 8) & 0x7; - registernr = (pci_data->pci_addr) & 0xff; + int i; /* Scan through the list of pci_device entries. */ dev = pci_data->first_device; while (dev != NULL) { - if (dev->bus == bus && dev->function == function && - dev->device == device) + if (dev->bus == pci_data->cur_bus && + dev->function == pci_data->cur_func && + dev->device == pci_data->cur_device) break; dev = dev->next; } /* No device? Then return emptiness. */ if (dev == NULL) { - if ((pci_data->pci_addr & 0xff) == 0) - *data = 0xffffffff; - else - *data = 0; + if (writeflag == MEM_READ) { + if (pci_data->cur_reg == 0) + *data = -1; + else + *data = 0; + } else { + fatal("[ bus_pci_data_access(): write to non-existant" + " device? ]\n"); + } return; } /* Return normal config data, or length data? */ if (pci_data->last_was_write_ffffffff && - registernr >= PCI_MAPREG_START && registernr <= PCI_MAPREG_END - 4) + pci_data->cur_reg >= PCI_MAPREG_START && + pci_data->cur_reg <= PCI_MAPREG_END - 4) cfg_base = dev->cfg_mem_size; else cfg_base = dev->cfg_mem; /* Read data as little-endian: */ x = 0; - if (registernr + len - 1 < PCI_CFG_MEM_SIZE) { - x = cfg_base[registernr]; - if (len > 1) - x |= (cfg_base[registernr+1] << 8); - if (len > 2) - x |= (cfg_base[registernr+2] << 16); - if (len > 3) - x |= ((uint64_t)cfg_base[registernr+3] << 24); - if (len > 4) - fatal("TODO: more than 32-bit PCI access?\n"); + for (i=len-1; i>=0; i--) { + int ofs = pci_data->cur_reg + i; + x <<= 8; + x |= cfg_base[ofs & (PCI_CFG_MEM_SIZE - 1)]; } /* Register write: */ if (writeflag == MEM_WRITE) { - debug("[ bus_pci: write to PCI DATA: data = 0x%016llx ]\n", + debug("[ bus_pci: write to PCI DATA: data = 0x%08llx ]\n", (long long)idata); - if (idata == 0xffffffffULL && registernr >= PCI_MAPREG_START - && registernr <= PCI_MAPREG_END - 4) { + if (idata == 0xffffffffULL && + pci_data->cur_reg >= PCI_MAPREG_START && + pci_data->cur_reg <= PCI_MAPREG_END - 4) { pci_data->last_was_write_ffffffff = 1; return; } @@ -151,89 +151,42 @@ " differs from current value 0x%08llx; NOT YET" " SUPPORTED. bus %i, device %i, function %i (%s)" " register 0x%02x ]\n", (long long)idata, - (long long)x, bus, device, function, dev->name, - registernr); + (long long)x, pci_data->cur_bus, + pci_data->cur_device, pci_data->cur_func, + dev->name, pci_data->cur_reg); } return; } /* Register read: */ - if (cpu->byte_order == EMUL_BIG_ENDIAN) - reverse(&x, len); *data = x; pci_data->last_was_write_ffffffff = 0; - debug("[ bus_pci: read from PCI DATA, addr = 0x%08lx (bus %i, device " - "%i, function %i (%s) register 0x%02x): 0x%08lx ]\n", (long) - pci_data->pci_addr, bus, device, function, dev->name, - registernr, (long)*data); + debug("[ bus_pci: read from PCI DATA, bus %i, device " + "%i, function %i (%s) register 0x%02x: 0x%08lx ]\n", (long) + pci_data->cur_bus, pci_data->cur_device, + pci_data->cur_func, dev->name, pci_data->cur_reg, (long)*data); } /* - * bus_pci_access(): - * - * relative_addr should be either BUS_PCI_ADDR or BUS_PCI_DATA. The uint64_t - * pointed to by data should contain the word to be written to the pci bus, - * or a placeholder for information read from the bus. + * bus_pci_setaddr(): * - * Returns 1 if ok, 0 on error. + * Sets the address in preparation for a PCI register transfer. */ -int bus_pci_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, - uint64_t *data, int len, int writeflag, struct pci_data *pci_data) +void bus_pci_setaddr(struct cpu *cpu, struct pci_data *pci_data, + int bus, int device, int function, int reg) { - if (writeflag == MEM_READ) - *data = 0; - - switch (relative_addr) { - - case BUS_PCI_ADDR: - if (writeflag == MEM_WRITE) { - debug("[ bus_pci: write to PCI ADDR: data = 0x%016llx" - " ]\n", (long long)*data); - pci_data->pci_addr = *data; - - /* - * Big-endian systems (e.g. PowerPC) seem to access - * PCI config data using little-endian accesses. - */ - if (cpu->byte_order == EMUL_BIG_ENDIAN) { - uint32_t t = pci_data->pci_addr; - pci_data->pci_addr = ((t >> 24) & 255) - | ((t >> 8) & 0xff00) - | ((t << 8) & 0xff0000) - | ((t << 24) & 0xff000000); - } - - /* Linux seems to use type 0 even when it does - type 1 detection. Hm. This is commented for now. */ - /* if (pci_data->pci_addr & 1) - fatal("[ bus_pci: WARNING! pci type 0 not" - " yet implemented! ]\n"); */ - } else { - debug("[ bus_pci: read from PCI ADDR (data = " - "0x%016llx) ]\n", (long long)pci_data->pci_addr); - *data = pci_data->pci_addr; - } - break; - - case BUS_PCI_DATA: - bus_pci_data_access(cpu, mem, data, len, writeflag, pci_data); - break; - - default:if (writeflag == MEM_READ) { - debug("[ bus_pci: read from unimplemented addr " - "0x%x ]\n", (int)relative_addr); - *data = 0; - } else { - debug("[ bus_pci: write to unimplemented addr " - "0x%x: 0x%llx ]\n", (int)relative_addr, - (long long)*data); - } + if (cpu == NULL || pci_data == NULL) { + fatal("bus_pci_setaddr(): NULL ptr\n"); + exit(1); } - return 1; + pci_data->cur_bus = bus; + pci_data->cur_device = device; + pci_data->cur_func = function; + pci_data->cur_reg = reg; } @@ -244,7 +197,7 @@ */ void bus_pci_add(struct machine *machine, struct pci_data *pci_data, struct memory *mem, int bus, int device, int function, - char *name) + const char *name) { struct pci_device *pd; int ofs; @@ -291,14 +244,13 @@ /* * Initialize with some default values: * - * TODO: The command status register is best to set up per device, - * just enabling all bits like this is not really good. - * The size registers should also be set up on a per-device - * basis. + * TODO: The command status register is best to set up per device. + * The size registers should also be set up on a per-device basis. */ - PCI_SET_DATA(PCI_COMMAND_STATUS_REG, 0x00ffffffULL); + PCI_SET_DATA(PCI_COMMAND_STATUS_REG, + PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE); for (ofs = PCI_MAPREG_START; ofs < PCI_MAPREG_END; ofs += 4) - PCI_SET_DATA_SIZE(ofs, 0x00400000 - 1); + PCI_SET_DATA_SIZE(ofs, 0x00100000 - 1); if (init == NULL) { fatal("No init function for PCI device \"%s\"?\n", name); @@ -331,8 +283,11 @@ if (portsize != 0) { port = ((port - 1) | (portsize - 1)) + 1; pd->pcibus->cur_pci_portbase = port; - PCI_SET_DATA(PCI_MAPREG_START, port | PCI_MAPREG_TYPE_IO); - PCI_SET_DATA_SIZE(PCI_MAPREG_START, portsize - 1); + PCI_SET_DATA(PCI_MAPREG_START + pd->cur_mapreg_offset, + port | PCI_MAPREG_TYPE_IO); + PCI_SET_DATA_SIZE(PCI_MAPREG_START + pd->cur_mapreg_offset, + portsize - 1); + pd->cur_mapreg_offset += sizeof(uint32_t); } /* Calculate an aligned starting memory location: */ @@ -340,8 +295,10 @@ if (memsize != 0) { mem = ((mem - 1) | (memsize - 1)) + 1; pd->pcibus->cur_pci_membase = mem; - PCI_SET_DATA(PCI_MAPREG_START + 0x04, mem); - PCI_SET_DATA_SIZE(PCI_MAPREG_START + 0x04, memsize - 1); + PCI_SET_DATA(PCI_MAPREG_START + pd->cur_mapreg_offset, mem); + PCI_SET_DATA_SIZE(PCI_MAPREG_START + pd->cur_mapreg_offset, + memsize - 1); + pd->cur_mapreg_offset += sizeof(uint32_t); } *portp = port + pd->pcibus->pci_actual_io_offset; @@ -365,11 +322,43 @@ } +static void bus_pci_debug_dump__2(struct pci_device *pd) +{ + if (pd == NULL) + return; + bus_pci_debug_dump__2(pd->next); + debug("bus %3i, dev %2i, func %i: %s\n", + pd->bus, pd->device, pd->function, pd->name); +} + + +/* + * bus_pci_debug_dump(): + * + * Lists the attached PCI devices (in reverse). + */ +void bus_pci_debug_dump(void *extra) +{ + struct pci_data *d = (struct pci_data *) extra; + int iadd = DEBUG_INDENTATION; + + debug("pci:\n"); + debug_indentation(iadd); + + if (d->first_device == NULL) + debug("no devices!\n"); + else + bus_pci_debug_dump__2(d->first_device); + + debug_indentation(-iadd); +} + + /* * bus_pci_init(): * * This doesn't register a device, but instead returns a pointer to a struct - * which should be passed to bus_pci_access() when accessing the PCI bus. + * which should be passed to other bus_pci functions when accessing the bus. * * irq_nr is the (optional) IRQ nr that this PCI bus interrupts at. * @@ -382,7 +371,7 @@ * isa_portbase, isa_membase, and isa_irqbase are the port, memory, and * interrupt bases for legacy ISA devices. */ -struct pci_data *bus_pci_init(int irq_nr, +struct pci_data *bus_pci_init(struct machine *machine, int irq_nr, uint64_t pci_actual_io_offset, uint64_t pci_actual_mem_offset, uint64_t pci_portbase, uint64_t pci_membase, int pci_irqbase, uint64_t isa_portbase, uint64_t isa_membase, int isa_irqbase) @@ -405,6 +394,9 @@ d->isa_membase = isa_membase; d->isa_irqbase = isa_irqbase; + /* Register the bus: */ + machine_bus_register(machine, "pci", bus_pci_debug_dump, d); + /* Assume that the first 64KB could be used by legacy ISA devices: */ d->cur_pci_portbase = d->pci_portbase + 0x10000; d->cur_pci_membase = d->pci_membase + 0x10000; @@ -415,12 +407,12 @@ /****************************************************************************** - * - * The following is glue code for PCI controllers and devices. The glue code - * does the minimal stuff necessary to get an emulated OS to detect the - * device (i.e. set up PCI configuration registers), and then if necessary - * add a "normal" device. - * + * * + * The following is glue code for PCI controllers and devices. The glue * + * code does the minimal stuff necessary to get an emulated OS to detect * + * the device (i.e. set up PCI configuration registers), and then if * + * necessary adds a "normal" device. * + * * ******************************************************************************/ @@ -443,9 +435,10 @@ PCI_SUBCLASS_DISPLAY_VGA, 0) + 0x01); /* TODO */ - PCI_SET_DATA(0x10, 0xb0000000); + PCI_SET_DATA(0x10, 0x08000000); - /* TODO: This is just a dummy so far. */ + dev_vga_init(machine, mem, pd->pcibus->isa_membase + 0xa0000, + 0x88800000 + 0x3c0, machine->machine_name); } @@ -594,14 +587,14 @@ #define PCI_VENDOR_GALILEO 0x11ab /* Galileo Technology */ #define PCI_PRODUCT_GALILEO_GT64011 0x4146 /* GT-64011 System Controller */ #define PCI_PRODUCT_GALILEO_GT64120 0x4620 /* GT-64120 */ +#define PCI_PRODUCT_GALILEO_GT64260 0x6430 /* GT-64260 */ PCIINIT(gt64011) { PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_GALILEO, PCI_PRODUCT_GALILEO_GT64011)); - PCI_SET_DATA(PCI_CLASS_REG, - PCI_CLASS_CODE(PCI_CLASS_BRIDGE, + PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_HOST, 0) + 0x01); /* Revision 1 */ } @@ -620,19 +613,82 @@ } } +PCIINIT(gt64260) +{ + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_GALILEO, + PCI_PRODUCT_GALILEO_GT64260)); + + PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE, + PCI_SUBCLASS_BRIDGE_HOST, 0) + 0x01); /* Revision 1? */ +} + /* - * Intel 82371AB PIIX4 PCI-ISA bridge and IDE controller - * and 82378ZB System I/O controller. + * Intel 31244 Serial ATA Controller + * Intel 82371SB PIIX3 PCI-ISA bridge + * Intel 82371AB PIIX4 PCI-ISA bridge + * Intel 82371SB IDE controller + * Intel 82371AB IDE controller + * Intel 82378ZB System I/O controller. */ #define PCI_VENDOR_INTEL 0x8086 +#define PCI_PRODUCT_INTEL_31244 0x3200 +#define PCI_PRODUCT_INTEL_82371SB_ISA 0x7000 +#define PCI_PRODUCT_INTEL_82371SB_IDE 0x7010 #define PCI_PRODUCT_INTEL_82371AB_ISA 0x7110 #define PCI_PRODUCT_INTEL_82371AB_IDE 0x7111 #define PCI_PRODUCT_INTEL_SIO 0x0484 -PCIINIT(i82371ab_isa) +PCIINIT(i31244) +{ + uint64_t port, memaddr; + + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_INTEL, + PCI_PRODUCT_INTEL_31244)); + + PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_MASS_STORAGE, + PCI_SUBCLASS_MASS_STORAGE_IDE, 0x33) + 0x00); + + switch (machine->machine_type) { + case MACHINE_IQ80321: + /* S-PCI-X slot uses PCI IRQ A */ + break; + default:fatal("i31244 in non-implemented machine type %i\n", + machine->machine_type); + exit(1); + } + + PCI_SET_DATA(PCI_INTERRUPT_REG, 0x28140100); + + allocate_device_space(pd, 0x400, 0, &port, &memaddr); + allocate_device_space(pd, 0x400, 0, &port, &memaddr); + + /* PCI IDE using dev_wdc: */ + if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || + diskimage_exist(machine, 1, DISKIMAGE_IDE)) { + char tmpstr[150]; + snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%i", + (long long)(pd->pcibus->pci_actual_io_offset + 0), + pd->pcibus->pci_irqbase + 0); + device_add(machine, tmpstr); + } +} + +PCIINIT(piix3_isa) +{ + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_INTEL, + PCI_PRODUCT_INTEL_82371SB_ISA)); + + PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE, + PCI_SUBCLASS_BRIDGE_ISA, 0) + 0x01); /* Rev 1 */ + + PCI_SET_DATA(PCI_BHLC_REG, + PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0)); +} + +PCIINIT(piix4_isa) { PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371AB_ISA)); @@ -654,9 +710,46 @@ PCI_SET_DATA(PCI_BHLC_REG, PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0)); + + PCI_SET_DATA(0x40, 0x20); + + /* PIRQ[0]=10 PIRQ[1]=11 PIRQ[2]=14 PIRQ[3]=15 */ + PCI_SET_DATA(0x60, 0x0f0e0b0a); } -PCIINIT(i82371ab_ide) +PCIINIT(piix3_ide) +{ + char tmpstr[100]; + + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_INTEL, + PCI_PRODUCT_INTEL_82371SB_IDE)); + + /* Possibly not correct: */ + PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_MASS_STORAGE, + PCI_SUBCLASS_MASS_STORAGE_IDE, 0x00) + 0x00); + + /* PIIX_IDETIM (see NetBSD's pciide_piix_reg.h) */ + /* channel 0 and 1 enabled as IDE */ + PCI_SET_DATA(0x40, 0x80008000); + + 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); + } + + if (diskimage_exist(machine, 2, DISKIMAGE_IDE) || + diskimage_exist(machine, 3, DISKIMAGE_IDE)) { + 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); + } +} + +PCIINIT(piix4_ide) { char tmpstr[100]; @@ -859,7 +952,7 @@ { uint64_t port, memaddr; int irq = 0; /* TODO */ - int int_line = 1; /* TODO */ + int pci_int_line = 0x101; char tmpstr[200]; PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_DEC, @@ -874,19 +967,42 @@ switch (machine->machine_type) { case MACHINE_CATS: + /* CATS int 18 = PCI. */ irq = 18; - int_line = 1; + pci_int_line = 0x101; + break; + case MACHINE_COBALT: + /* On Cobalt, IRQ 7 = PCI. */ + irq = 8 + 7; + pci_int_line = 0x407; + break; + case MACHINE_ALGOR: + /* TODO */ + irq = 8 + 7; + pci_int_line = 0x407; break; case MACHINE_PREP: - int_line = 0xa; - irq = 31 - int_line; + irq = 32 + 10; + pci_int_line = 0x20a; + break; + case MACHINE_MVMEPPC: + /* TODO */ + irq = 32 + 10; + pci_int_line = 0x40a; break; case MACHINE_PMPPC: + /* TODO, not working yet */ irq = 31 - 21; + pci_int_line = 0x201; + break; + case MACHINE_MACPPC: + /* TODO, not working yet */ + irq = 25; + pci_int_line = 0x101; break; } - PCI_SET_DATA(PCI_INTERRUPT_REG, 0x28140100 | int_line); + PCI_SET_DATA(PCI_INTERRUPT_REG, 0x28140000 | pci_int_line); allocate_device_space(pd, 0x100, 0x100, &port, &memaddr); @@ -950,6 +1066,7 @@ } + /* * Motorola MPC105 "Eagle" Host Bridge * @@ -971,3 +1088,75 @@ PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0)); } + + +/* + * Apple (MacPPC) stuff: + * + * Grand Central (I/O controller) + * Uni-North (PCI controller) + */ + +#define PCI_VENDOR_APPLE 0x106b +#define PCI_PRODUCT_APPLE_GC 0x0002 +#define PCI_PRODUCT_APPLE_UNINORTH1 0x001e + +PCIINIT(gc_obio) +{ + uint64_t port, memaddr; + + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_APPLE, + PCI_PRODUCT_APPLE_GC)); + + /* TODO: */ + PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_SYSTEM, + PCI_SUBCLASS_SYSTEM_PIC, 0) + 0x00); + + PCI_SET_DATA(PCI_BHLC_REG, + PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0)); + + /* TODO */ + allocate_device_space(pd, 0x10000, 0x10000, &port, &memaddr); +} + +PCIINIT(uninorth) +{ + uint64_t port, memaddr; + + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_APPLE, + PCI_PRODUCT_APPLE_UNINORTH1)); + + PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE, + PCI_SUBCLASS_BRIDGE_HOST, 0) + 0xff); + + PCI_SET_DATA(PCI_BHLC_REG, + PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0)); + + /* TODO */ + allocate_device_space(pd, 0x10000, 0x10000, &port, &memaddr); +} + + + +/* + * ATI graphics cards + */ + +#define PCI_VENDOR_ATI 0x1002 +#define PCI_PRODUCT_ATI_RADEON_9200_2 0x5962 + +PCIINIT(ati_radeon_9200_2) +{ + uint64_t port, memaddr; + + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_ATI, + PCI_PRODUCT_ATI_RADEON_9200_2)); + + /* TODO: other subclass? */ + PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_DISPLAY, + PCI_SUBCLASS_DISPLAY_VGA, 0) + 0x03); + + /* TODO */ + allocate_device_space(pd, 0x1000, 0x400000, &port, &memaddr); +} +