diff options
Diffstat (limited to 'src/devices')
-rw-r--r-- | src/devices/Config.lb | 1 | ||||
-rw-r--r-- | src/devices/chip.c | 11 | ||||
-rw-r--r-- | src/devices/device.c | 20 | ||||
-rw-r--r-- | src/devices/device_util.c | 73 | ||||
-rw-r--r-- | src/devices/hypertransport.c | 51 | ||||
-rw-r--r-- | src/devices/pci_device.c | 124 | ||||
-rw-r--r-- | src/devices/pnp_device.c | 217 |
7 files changed, 414 insertions, 83 deletions
diff --git a/src/devices/Config.lb b/src/devices/Config.lb index 6da04ee2e4..50d05579e5 100644 --- a/src/devices/Config.lb +++ b/src/devices/Config.lb @@ -2,5 +2,6 @@ object device.o object root_device.o object device_util.o object pci_device.o +object pnp_device.o object hypertransport.o object chip.o diff --git a/src/devices/chip.c b/src/devices/chip.c index c9e1ac5643..d8a59e3062 100644 --- a/src/devices/chip.c +++ b/src/devices/chip.c @@ -80,6 +80,7 @@ void chip_enumerate(struct chip *chip) link += 1; } if (dev) { + struct chip_resource *res, *res_limit; printk_spew("path (%p) %s %s", dev, dev_path(dev), identical_paths?"identical":""); printk_spew(" parent: (%p) %s\n",dev->bus->dev, dev_path(dev->bus->dev)); dev->chip = chip; @@ -90,6 +91,16 @@ void chip_enumerate(struct chip *chip) child->bus = &dev->link[link]; } } + res = &chip->path[i].resource[0]; + res_limit = &chip->path[i].resource[MAX_RESOURCES]; + for(; res < res_limit; res++) { + if (res->flags) { + struct resource *resource; + resource = get_resource(dev, res->index); + resource->flags = res->flags | IORESOURCE_FIXED | IORESOURCE_ASSIGNED; + resource->base = res->base; + } + } } if (dev && !chip->dev) { chip->dev = dev; diff --git a/src/devices/device.c b/src/devices/device.c index 4f1cbb2c5d..b54e770294 100644 --- a/src/devices/device.c +++ b/src/devices/device.c @@ -23,9 +23,9 @@ #include <string.h> /* Linked list of ALL devices */ -struct device *all_devices = 0; +struct device *all_devices = &dev_root; /* pointer to the last device */ -static struct device **last_dev_p = &all_devices; +static struct device **last_dev_p = &dev_root.next; #define DEVICE_MEM_HIGH 0xFEC00000UL /* Reserve 20M for the system */ #define DEVICE_IO_START 0x1000 @@ -323,7 +323,8 @@ void compute_allocate_resource( /* base must be aligned to size */ base = round(base, 1UL << align); resource->base = base; - resource->flags |= IORESOURCE_SET; + resource->flags |= IORESOURCE_ASSIGNED; + resource->flags &= ~IORESOURCE_STORED; base += size; printk_spew( @@ -459,19 +460,24 @@ void dev_configure(void) * safe. */ root->resource[0].base = DEVICE_IO_START; - root->resource[0].flags |= IORESOURCE_SET; + root->resource[0].flags |= IORESOURCE_ASSIGNED; + root->resource[0].flags &= ~IORESOURCE_STORED; /* Now reallocate the pci resources memory with the * highest addresses I can manage. */ root->resource[1].base = round_down(DEVICE_MEM_HIGH - root->resource[1].size, 1UL << root->resource[1].align); - root->resource[1].flags |= IORESOURCE_SET; + root->resource[1].flags |= IORESOURCE_ASSIGNED; + root->resource[1].flags &= ~IORESOURCE_STORED; + + /* Allocate the VGA I/O resource.. + */ + allocate_vga_resource(); + // now just set things into registers ... we hope ... root->ops->set_resources(root); - allocate_vga_resource(); - printk_info("done.\n"); } diff --git a/src/devices/device_util.c b/src/devices/device_util.c index c806726853..013501474c 100644 --- a/src/devices/device_util.c +++ b/src/devices/device_util.c @@ -34,7 +34,8 @@ struct device *dev_find_slot(unsigned int bus, unsigned int devfn) result = 0; for (dev = all_devices; dev; dev = dev->next) { - if ((dev->bus->secondary == bus) && + if ((dev->path.type == DEVICE_PATH_PCI) && + (dev->bus->secondary == bus) && (dev->path.u.pci.devfn == devfn)) { result = dev; break; @@ -57,8 +58,9 @@ struct device *dev_find_device(unsigned int vendor, unsigned int device, struct from = all_devices; else from = from->next; - while (from && (from->vendor != vendor || from->device != device)) + while (from && (from->vendor != vendor || from->device != device)) { from = from->next; + } return from; } @@ -142,3 +144,70 @@ int path_eq(struct device_path *path1, struct device_path *path2) } return equal; } + +/** + * See if we have unused but allocated resource structures. + * If so remove the allocation. + * @param dev The device to find the resource on + */ +void compact_resources(device_t dev) +{ + struct resource *resource; + int i; + /* Move all of the free resources to the end */ + for(i = 0; i < dev->resources;) { + resource = &dev->resource[i]; + if (!resource->flags) { + memmove(resource, resource + 1, dev->resources - i); + dev->resources -= 1; + memset(&dev->resource[dev->resources], 0, sizeof(*resource)); + } else { + i++; + } + } +} + +/** + * See if a resource structure already exists for a given index and if + * not allocate one. + * @param dev The device to find the resource on + * @param index The index of the resource on the device. + */ +struct resource *get_resource(device_t dev, unsigned index) +{ + struct resource *resource; + int i; + + /* First move all of the free resources to the end */ + compact_resources(dev); + + /* See if there is a resource with the appropriate index */ + resource = 0; + for(i = 0; i < dev->resources; i++) { + if (dev->resource[i].index == index) { + resource = &dev->resource[i]; + break; + } + } + if (!resource) { + if (dev->resources == MAX_RESOURCES) { + die("MAX_RESOURCES exceeded."); + } + resource = &dev->resource[dev->resources]; + memset(resource, 0, sizeof(*resource)); + dev->resources++; + } + /* Initialize the resource values */ + if (!(resource->flags & IORESOURCE_FIXED)) { + resource->flags = 0; + resource->base = 0; + } + resource->size = 0; + resource->limit = 0; + resource->index = index; + resource->align = 0; + resource->gran = 0; + + return resource; +} + diff --git a/src/devices/hypertransport.c b/src/devices/hypertransport.c index b65f518d3a..e50ebf6f20 100644 --- a/src/devices/hypertransport.c +++ b/src/devices/hypertransport.c @@ -3,6 +3,7 @@ #include <device/device.h> #include <device/path.h> #include <device/pci.h> +#include <device/pci_ids.h> #include <device/hypertransport.h> #include <device/chip.h> #include <part/hard_reset.h> @@ -25,6 +26,30 @@ static device_t ht_scan_get_devs(device_t *old_devices) return first; } +static unsigned ht_read_freq_cap(device_t dev, unsigned pos) +{ + /* Handle bugs in valid hypertransport frequency reporting */ + unsigned freq_cap; + + freq_cap = pci_read_config16(dev, pos); + freq_cap &= ~(1 << HT_FREQ_VENDOR); /* Ignore Vendor HT frequencies */ + + /* AMD 8131 Errata 48 */ + if ((dev->vendor == PCI_VENDOR_ID_AMD) && + (dev->device == PCI_DEVICE_ID_AMD_8131_PCIX)) { + freq_cap &= ~(1 << HT_FREQ_800Mhz); + } + /* AMD 8151 Errata 23 */ + if ((dev->vendor == PCI_VENDOR_ID_AMD) && + (dev->device == PCI_DEVICE_ID_AMD_8151_SYSCTRL)) { + freq_cap &= ~(1 << HT_FREQ_800Mhz); + } + /* AMD K8 Unsupported 1Ghz? */ + if ((dev->vendor == PCI_VENDOR_ID_AMD) && (dev->device == 0x1100)) { + freq_cap &= ~(1 << HT_FREQ_1000Mhz); + } + return freq_cap; +} struct prev_link { struct device *dev; @@ -48,18 +73,13 @@ static int ht_setup_link(struct prev_link *prev, device_t dev, unsigned pos) reset_needed = 0; /* Read the capabilities */ - present_freq_cap = pci_read_config16(dev, pos + PCI_HT_CAP_SLAVE_FREQ_CAP0); - upstream_freq_cap = pci_read_config16(prev->dev, prev->pos + prev->freq_cap_off); + present_freq_cap = ht_read_freq_cap(dev, pos + PCI_HT_CAP_SLAVE_FREQ_CAP0); + upstream_freq_cap = ht_read_freq_cap(prev->dev, prev->pos + prev->freq_cap_off); present_width_cap = pci_read_config8(dev, pos + PCI_HT_CAP_SLAVE_WIDTH0); upstream_width_cap = pci_read_config8(prev->dev, prev->pos + prev->config_off); /* Calculate the highest useable frequency */ -#if 0 freq = log2(present_freq_cap & upstream_freq_cap); -#else - /* Errata for 8131 - freq 5 has hardware problems don't support it */ - freq = log2(present_freq_cap & upstream_freq_cap & 0x1f); -#endif /* Calculate the highest width */ ln_upstream_width_in = link_width_to_pow2[upstream_width_cap & 7]; @@ -144,9 +164,7 @@ static unsigned ht_lookup_slave_capability(struct device *dev) break; } } - if(pos) { - pos = pci_read_config8(dev, pos + PCI_CAP_LIST_NEXT); - } + pos = pci_read_config8(dev, pos + PCI_CAP_LIST_NEXT); } return pos; } @@ -244,9 +262,12 @@ unsigned int hypertransport_scan_chain(struct bus *bus, unsigned int max) else { /* Add this device to the pci bus chain */ *chain_last = dev; - /* Run the magice enable/disable sequence for the device */ + /* Run the magice enable sequence for the device */ if (dev->chip && dev->chip->control && dev->chip->control->enable_dev) { + int enable = dev->enable; + dev->enable = 1; dev->chip->control->enable_dev(dev); + dev->enable = enable; } /* Now read the vendor and device id */ id = pci_read_config32(dev, PCI_VENDOR_ID); @@ -320,9 +341,11 @@ unsigned int hypertransport_scan_chain(struct bus *bus, unsigned int max) #if HAVE_HARD_RESET == 1 if(reset_needed) { printk_info("HyperT reset needed\n"); -// By LYH hard_reset(); - } else - printk_debug("HyperT reset not needed\n"); + hard_reset(); + } + else { + printk_debug("HyperT reset not needed\n"); + } #endif if (next_unitid > 0x1f) { next_unitid = 0x1f; diff --git a/src/devices/pci_device.c b/src/devices/pci_device.c index 734b982a6d..c3f1f6ac8c 100644 --- a/src/devices/pci_device.c +++ b/src/devices/pci_device.c @@ -27,19 +27,14 @@ * @param resource Pointer to the resource structure * @param index Address of the pci configuration register */ -static void pci_get_resource(struct device *dev, struct resource *resource, unsigned long index) +static struct resource *pci_get_resource(struct device *dev, unsigned long index) { + struct resource *resource; uint32_t addr, size, base; unsigned long type; /* Initialize the resources to nothing */ - resource->base = 0; - resource->size = 0; - resource->align = 0; - resource->gran = 0; - resource->limit = 0; - resource->flags = 0; - resource->index = index; + resource = get_resource(dev, index); addr = pci_read_config32(dev, index); @@ -87,7 +82,7 @@ static void pci_get_resource(struct device *dev, struct resource *resource, unsi resource->size = (~((size | 0xffff0000) & PCI_BASE_ADDRESS_IO_MASK)) +1; resource->align = log2(resource->size); resource->gran = resource->align; - resource->flags = IORESOURCE_IO; + resource->flags |= IORESOURCE_IO; resource->limit = 0xffff; } else { @@ -96,7 +91,7 @@ static void pci_get_resource(struct device *dev, struct resource *resource, unsi resource->size = (~(size &PCI_BASE_ADDRESS_MEM_MASK)) +1; resource->align = log2(resource->size); resource->gran = resource->align; - resource->flags = IORESOURCE_MEM; + resource->flags |= IORESOURCE_MEM; if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { resource->flags |= IORESOURCE_PREFETCH; } @@ -145,7 +140,7 @@ static void pci_get_resource(struct device *dev, struct resource *resource, unsi } } /* dev->size holds the flags... */ - return; + return resource; } /** Read the base address registers for a given device. @@ -154,75 +149,63 @@ static void pci_get_resource(struct device *dev, struct resource *resource, unsi */ static void pci_read_bases(struct device *dev, unsigned int howmany) { - unsigned int reg; unsigned long index; - reg = dev->resources; - for(index = PCI_BASE_ADDRESS_0; - (reg < MAX_RESOURCES) && (index < PCI_BASE_ADDRESS_0 + (howmany << 2)); ) { + for(index = PCI_BASE_ADDRESS_0; (index < PCI_BASE_ADDRESS_0 + (howmany << 2)); ) { struct resource *resource; - resource = &dev->resource[reg]; - pci_get_resource(dev, resource, index); - reg += (resource->flags & (IORESOURCE_IO | IORESOURCE_MEM))? 1:0; + resource = pci_get_resource(dev, index); index += (resource->flags & IORESOURCE_PCI64)?8:4; } - dev->resources = reg; + compact_resources(dev); } static void pci_bridge_read_bases(struct device *dev) { - unsigned int reg = dev->resources; + struct resource *resource; /* FIXME handle bridges without some of the optional resources */ /* Initialize the io space constraints on the current bus */ - dev->resource[reg].base = 0; - dev->resource[reg].size = 0; - dev->resource[reg].align = log2(PCI_IO_BRIDGE_ALIGN); - dev->resource[reg].gran = log2(PCI_IO_BRIDGE_ALIGN); - dev->resource[reg].limit = 0xffffUL; - dev->resource[reg].flags = IORESOURCE_IO | IORESOURCE_PCI_BRIDGE; - dev->resource[reg].index = PCI_IO_BASE; - compute_allocate_resource(&dev->link[0], &dev->resource[reg], + resource = get_resource(dev, PCI_IO_BASE); + resource->size = 0; + resource->align = log2(PCI_IO_BRIDGE_ALIGN); + resource->gran = log2(PCI_IO_BRIDGE_ALIGN); + resource->limit = 0xffffUL; + resource->flags |= IORESOURCE_IO | IORESOURCE_PCI_BRIDGE; + compute_allocate_resource(&dev->link[0], resource, IORESOURCE_IO, IORESOURCE_IO); - reg++; /* Initiliaze the prefetchable memory constraints on the current bus */ - dev->resource[reg].base = 0; - dev->resource[reg].size = 0; - dev->resource[reg].align = log2(PCI_MEM_BRIDGE_ALIGN); - dev->resource[reg].gran = log2(PCI_MEM_BRIDGE_ALIGN); - dev->resource[reg].limit = 0xffffffffUL; - dev->resource[reg].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_PCI_BRIDGE; - dev->resource[reg].index = PCI_PREF_MEMORY_BASE; - compute_allocate_resource(&dev->link[0], &dev->resource[reg], + resource = get_resource(dev, PCI_PREF_MEMORY_BASE); + resource->size = 0; + resource->align = log2(PCI_MEM_BRIDGE_ALIGN); + resource->gran = log2(PCI_MEM_BRIDGE_ALIGN); + resource->limit = 0xffffffffUL; + resource->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_PCI_BRIDGE; + resource->index = PCI_PREF_MEMORY_BASE; + compute_allocate_resource(&dev->link[0], resource, IORESOURCE_MEM | IORESOURCE_PREFETCH, IORESOURCE_MEM | IORESOURCE_PREFETCH); - reg++; /* Initialize the memory resources on the current bus */ - dev->resource[reg].base = 0; - dev->resource[reg].size = 0; - dev->resource[reg].align = log2(PCI_MEM_BRIDGE_ALIGN); - dev->resource[reg].gran = log2(PCI_MEM_BRIDGE_ALIGN); - dev->resource[reg].limit = 0xffffffffUL; - dev->resource[reg].flags = IORESOURCE_MEM | IORESOURCE_PCI_BRIDGE; - dev->resource[reg].index = PCI_MEMORY_BASE; - compute_allocate_resource(&dev->link[0], &dev->resource[reg], - IORESOURCE_MEM | IORESOURCE_PREFETCH, + resource = get_resource(dev, PCI_MEMORY_BASE); + resource->size = 0; + resource->align = log2(PCI_MEM_BRIDGE_ALIGN); + resource->gran = log2(PCI_MEM_BRIDGE_ALIGN); + resource->limit = 0xffffffffUL; + resource->flags = IORESOURCE_MEM | IORESOURCE_PCI_BRIDGE; + compute_allocate_resource(&dev->link[0], resource, + IORESOURCE_MEM | IORESOURCE_PREFETCH, IORESOURCE_MEM); - reg++; - dev->resources = reg; + compact_resources(dev); } void pci_dev_read_resources(struct device *dev) { uint32_t addr; - dev->resources = 0; - memset(&dev->resource[0], 0, sizeof(dev->resource)); pci_read_bases(dev, 6); addr = pci_read_config32(dev, PCI_ROM_ADDRESS); dev->rom_address = (addr == 0xffffffff)? 0 : addr; @@ -231,8 +214,6 @@ void pci_dev_read_resources(struct device *dev) void pci_bus_read_resources(struct device *dev) { uint32_t addr; - dev->resources = 0; - memset(&dev->resource, 0, sizeof(dev->resource)); pci_bridge_read_bases(dev); pci_read_bases(dev, 2); @@ -246,10 +227,10 @@ static void pci_set_resource(struct device *dev, struct resource *resource) { unsigned long base, limit; unsigned char buf[10]; - unsigned long align; + unsigned long gran; /* Make certain the resource has actually been set */ - if (!(resource->flags & IORESOURCE_SET)) { + if (!(resource->flags & IORESOURCE_ASSIGNED)) { #if 1 printk_err("ERROR: %s %02x not allocated\n", dev_path(dev), resource->index); @@ -257,6 +238,11 @@ static void pci_set_resource(struct device *dev, struct resource *resource) return; } + /* If I have already stored this resource don't worry about it */ + if (resource->flags & IORESOURCE_STORED) { + return; + } + /* Only handle PCI memory and IO resources for now */ if (!(resource->flags & (IORESOURCE_MEM |IORESOURCE_IO))) return; @@ -272,12 +258,20 @@ static void pci_set_resource(struct device *dev, struct resource *resource) } /* Get the base address */ base = resource->base; - /* Get the resource alignment */ - align = 1UL << resource->align; + /* Get the resource granularity */ + gran = 1UL << resource->gran; + + /* For a non bridge resource granularity and alignment are the same. + * For a bridge resource align is the largest needed alignment below + * the bridge. While the granularity is simply how many low bits of the + * address cannot be set. + */ /* Get the limit (rounded up) */ - limit = base + ((resource->size + align - 1UL) & ~(align - 1UL)) -1UL; + limit = base + ((resource->size + gran - 1UL) & ~(gran - 1UL)) -1UL; + /* Now store the resource */ + resource->flags |= IORESOURCE_STORED; if (!(resource->flags & IORESOURCE_PCI_BRIDGE)) { /* * some chipsets allow us to set/clear the IO bit. @@ -326,6 +320,8 @@ static void pci_set_resource(struct device *dev, struct resource *resource) pci_write_config32(dev, PCI_PREF_LIMIT_UPPER32, 0); } else { + /* Don't let me think I stored the resource */ + resource->flags &= ~IORESOURCE_STORED; printk_err("ERROR: invalid resource->index %x\n", resource->index); } @@ -386,6 +382,7 @@ void pci_dev_enable_resources(struct device *dev) uint16_t command; command = pci_read_config16(dev, PCI_COMMAND); command |= dev->command; + command |= (PCI_COMMAND_PARITY + PCI_COMMAND_SERR); /* error check */ printk_debug("%s cmd <- %02x\n", dev_path(dev), command); pci_write_config16(dev, PCI_COMMAND, command); @@ -397,6 +394,7 @@ void pci_bus_enable_resources(struct device *dev) uint16_t ctrl; ctrl = pci_read_config16(dev, PCI_BRIDGE_CONTROL); ctrl |= dev->link[0].bridge_ctrl; + ctrl |= (PCI_BRIDGE_CTL_PARITY + PCI_BRIDGE_CTL_SERR); /* error check */ printk_debug("%s bridge ctrl <- %04x\n", dev_path(dev), ctrl); pci_write_config16(dev, PCI_BRIDGE_CONTROL, ctrl); @@ -560,9 +558,12 @@ unsigned int pci_scan_bus(struct bus *bus, dev = alloc_dev(bus, &dummy.path); } else { - /* Run the magic enable/disable sequence for the device */ + /* Run the magic enable sequence for the device */ if (dev->chip && dev->chip->control && dev->chip->control->enable_dev) { + int enable = dev->enable; + dev->enable = 1; dev->chip->control->enable_dev(dev); + dev->enable = enable; } /* Now read the vendor and device id */ id = pci_read_config32(dev, PCI_VENDOR_ID); @@ -584,7 +585,7 @@ unsigned int pci_scan_bus(struct bus *bus, */ set_pci_ops(dev); /* Error if we don't have some pci operations for it */ - if (dev->enable && !dev->ops) { + if (!dev->ops) { printk_err("%s No device operations\n", dev_path(dev)); continue; @@ -594,6 +595,9 @@ unsigned int pci_scan_bus(struct bus *bus, if (dev->ops && dev->ops->enable) { dev->ops->enable(dev); } + else if (dev->chip && dev->chip->control && dev->chip->control->enable_dev) { + dev->chip->control->enable_dev(dev); + } printk_debug("%s [%04x/%04x] %s\n", dev_path(dev), diff --git a/src/devices/pnp_device.c b/src/devices/pnp_device.c new file mode 100644 index 0000000000..0bccd7d151 --- /dev/null +++ b/src/devices/pnp_device.c @@ -0,0 +1,217 @@ +/* Copyright 2004 Linux Networx */ +/* This code is distrubted wihtout warrant under the GPL v2 (see COPYING) */ + +#include <console/console.h> +#include <stdlib.h> +#include <stdint.h> +#include <bitops.h> +#include <string.h> +#include <arch/io.h> +#include <device/device.h> +#include <device/pnp.h> + + +/* PNP fundamental operations */ + +void pnp_write_config(device_t dev, uint8_t reg, uint8_t value) +{ + outb(reg, dev->path.u.pnp.port); + outb(value, dev->path.u.pnp.port + 1); +} + +uint8_t pnp_read_config(device_t dev, uint8_t reg) +{ + outb(reg, dev->path.u.pnp.port); + return inb(dev->path.u.pnp.port + 1); +} + +void pnp_set_logical_device(device_t dev) +{ + pnp_write_config(dev, 0x07, dev->path.u.pnp.device); +} + +void pnp_set_enable(device_t dev, int enable) +{ + pnp_write_config(dev, 0x30, enable?0x1:0x0); +} + +int pnp_read_enable(device_t dev) +{ + return !!pnp_read_config(dev, 0x30); +} + +void pnp_set_iobase(device_t dev, unsigned index, unsigned iobase) +{ + /* Index == 0x60 or 0x62 */ + pnp_write_config(dev, index + 0, (iobase >> 8) & 0xff); + pnp_write_config(dev, index + 1, iobase & 0xff); +} + +void pnp_set_irq(device_t dev, unsigned index, unsigned irq) +{ + /* Index == 0x70 or 0x72 */ + pnp_write_config(dev, index, irq); +} + + +void pnp_set_drq(device_t dev, unsigned drq, unsigned index) +{ + /* Index == 0x74 */ + pnp_write_config(dev, index, drq & 0xff); +} + +/* PNP device operations */ + +void pnp_read_resources(device_t dev) +{ + return; +} + +static void pnp_set_resource(device_t dev, struct resource *resource) +{ + if (!(resource->flags & IORESOURCE_ASSIGNED)) { +#if 1 + printk_err("ERROR: %s %02x not allocated\n", + dev_path(dev), resource->index); +#endif + return; + } + /* Now store the resource */ + resource->flags |= IORESOURCE_STORED; + if (resource->flags & IORESOURCE_IO) { + pnp_set_iobase(dev, resource->index, resource->base); + } + else if (resource->flags & IORESOURCE_DRQ) { + pnp_set_drq(dev, resource->index, resource->base); + } + else if (resource->flags & IORESOURCE_IRQ) { + pnp_set_irq(dev, resource->index, resource->base); + } + else { + /* Don't let me think I stored the resource */ + resource->flags &= IORESOURCE_STORED; + printk_err("ERROR: %s %02x unknown resource type\n", + dev_path(dev), resource->index); + return; + } + + printk_debug( + "%s %02x <- [0x%08lx - 0x%08lx] %s\n", + dev_path(dev), + resource->index, + resource->base, resource->base + resource->size - 1, + (resource->flags & IORESOURCE_IO)? "io": + (resource->flags & IORESOURCE_DRQ)? "drq": + (resource->flags & IORESOURCE_IRQ)? "irq": + (resource->flags & IORESOURCE_MEM)? "mem": + "???"); +} + +void pnp_set_resources(device_t dev) +{ + int i; + + /* Select the device */ + pnp_set_logical_device(dev); + + /* Paranoia says I should disable the device here... */ + for(i = 0; i < dev->resources; i++) { + pnp_set_resource(dev, &dev->resource[i]); + } +} + +void pnp_enable_resources(device_t dev) +{ + pnp_set_logical_device(dev); + pnp_set_enable(dev, 1); + +} + +void pnp_enable(device_t dev) +{ + pnp_set_logical_device(dev); + if (!dev->enable) { + pnp_set_enable(dev, 0); + } +} + +struct device_operations pnp_ops = { + .read_resources = pnp_read_resources, + .set_resources = pnp_set_resources, + .enable_resources = pnp_enable_resources, + .enable = pnp_enable, +}; + +/* PNP chip opertations */ + +static void pnp_get_ioresource(device_t dev, unsigned index, struct io_info *info) +{ + struct resource *resource; + uint32_t size; + resource = get_resource(dev, index); + + /* Initilize the resource */ + resource->limit = 0xffff; + resource->flags |= IORESOURCE_IO; + + /* Set the resource size and alignment */ + size = (0xffff & info->mask); + resource->size = (~(size | 0xfffff800) + 1); + resource->align = log2(resource->size); + resource->gran = resource->align; +} + +static void get_resources(device_t dev, struct pnp_info *info) +{ + struct resource *resource; + + pnp_set_logical_device(dev); + + if (info->flags & PNP_IO0) { + pnp_get_ioresource(dev, PNP_IDX_IO0, &info->io0); + } + if (info->flags & PNP_IO1) { + pnp_get_ioresource(dev, PNP_IDX_IO1, &info->io1); + } + if (info->flags & PNP_IRQ0) { + resource = get_resource(dev, PNP_IDX_IRQ0); + resource->size = 1; + resource->flags |= IORESOURCE_IRQ; + } + if (info->flags & PNP_IRQ1) { + resource = get_resource(dev, PNP_IDX_IRQ1); + resource->size = 1; + resource->flags |= IORESOURCE_IRQ; + } + if (info->flags & PNP_DRQ0) { + resource = get_resource(dev, PNP_IDX_DRQ0); + resource->size = 1; + resource->flags |= IORESOURCE_DRQ; + } + if (info->flags & PNP_DRQ1) { + resource = get_resource(dev, PNP_IDX_DRQ1); + resource->size = 1; + resource->flags |= IORESOURCE_DRQ; + } + +} + +void pnp_enumerate(struct chip *chip, unsigned functions, + struct device_operations *ops, struct pnp_info *info) +{ + struct device_path path; + device_t dev; + int i; + + chip_enumerate(chip); + path.type = DEVICE_PATH_PNP; + path.u.pnp.port = chip->dev->path.u.pnp.port; + + /* Setup the ops and resources on the newly allocated devices */ + for(i = 0; i < functions; i++) { + path.u.pnp.device = info[i].function; + dev = alloc_find_dev(chip->bus, &path); + dev->ops = ops; + get_resources(dev, &info[i]); + } +} |