diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-05 06:47:02 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-05 06:47:02 +0000 |
commit | 99a7e12f34b3661a0d1354eef83a0eef4df5e34c (patch) | |
tree | 3560aca9ca86792f9ab7bd87861ea143a1b3c7a3 /drivers/pnp | |
parent | e73a04659c0b8cdee4dd40e58630e2cf63afb316 (diff) |
Merge with Linux 2.3.38.
Diffstat (limited to 'drivers/pnp')
-rw-r--r-- | drivers/pnp/Makefile | 4 | ||||
-rw-r--r-- | drivers/pnp/isapnp.c | 164 | ||||
-rw-r--r-- | drivers/pnp/isapnp_proc.c | 23 | ||||
-rw-r--r-- | drivers/pnp/quirks.c | 75 |
4 files changed, 170 insertions, 96 deletions
diff --git a/drivers/pnp/Makefile b/drivers/pnp/Makefile index f12b5686d..9a8ad136c 100644 --- a/drivers/pnp/Makefile +++ b/drivers/pnp/Makefile @@ -19,10 +19,10 @@ MI_OBJS := MIX_OBJS := ifeq ($(CONFIG_ISAPNP),y) - LX_OBJS += isapnp.o + LX_OBJS += isapnp.o quirks.o else ifeq ($(CONFIG_ISAPNP),m) - MX_OBJS += isapnp.o + MX_OBJS += isapnp.o quirks.o endif endif diff --git a/drivers/pnp/isapnp.c b/drivers/pnp/isapnp.c index 3ec11f092..8b6a42b7d 100644 --- a/drivers/pnp/isapnp.c +++ b/drivers/pnp/isapnp.c @@ -17,6 +17,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + * Changelog: + * 2000-01-01 Added ISAPnP quirks handling + * Peter Denison <peterd@pnd-pc.demon.co.uk> */ #include <linux/config.h> @@ -39,6 +42,15 @@ #include <asm/uaccess.h> #include <linux/isapnp.h> +LIST_HEAD(isapnp_cards); +LIST_HEAD(isapnp_devices); + +#define isapnp_for_each_card(card) \ + for(card = pci_bus_b(isapnp_cards.next); card != pci_bus_b(&isapnp_cards); card = pci_bus_b(card->node.next)) +#define isapnp_for_each_dev(dev) \ + for(dev = pci_dev_g(isapnp_devices.next); dev != pci_dev_g(&isapnp_devices); dev = pci_dev_g(dev->global_list.next)) + + #ifdef CONFIG_PROC_FS #include "isapnp_proc.c" #endif @@ -108,9 +120,6 @@ MODULE_PARM_DESC(isapnp_reserve_mem, "ISA Plug & Play - reserve memory region(s) #define _LTAG_MEM32RANGE 0x85 #define _LTAG_FIXEDMEM32RANGE 0x86 -struct pci_bus *isapnp_cards = NULL; /* ISA PnP cards */ -struct pci_dev *isapnp_devices = NULL; /* ISA PnP devices */ -static struct pci_dev *isapnp_last_device = NULL; static unsigned char isapnp_checksum_value; static DECLARE_MUTEX(isapnp_cfg_mutex); static int isapnp_detected = 0; @@ -184,7 +193,7 @@ void isapnp_write_dword(unsigned char idx, unsigned int val) isapnp_write_byte(idx+3, val); } -static void *isapnp_alloc(long size) +void *isapnp_alloc(long size) { void *result; @@ -749,18 +758,13 @@ static int __init isapnp_create_device(struct pci_bus *card, { int number = 0, skip = 0, dependent = 0, compat = 0; unsigned char type, tmp[17]; - struct pci_dev *dev, *prev_dev; + struct pci_dev *dev; struct isapnp_resources *res = NULL; if ((dev = isapnp_parse_device(card, size, number++)) == NULL) return 1; - card->devices = dev; - if (isapnp_last_device) { - isapnp_last_device->next = dev; - isapnp_last_device = dev; - } else { - isapnp_devices = isapnp_last_device = dev; - } + list_add(&dev->bus_list, &card->devices); + list_add_tail(&dev->global_list, &isapnp_devices); while (1) { if (isapnp_read_tag(&type, &size)<0) return 1; @@ -769,13 +773,11 @@ static int __init isapnp_create_device(struct pci_bus *card, switch (type) { case _STAG_LOGDEVID: if (size >= 5 && size <= 6) { - prev_dev = dev; isapnp_config_prepare(dev); if ((dev = isapnp_parse_device(card, size, number++)) == NULL) return 1; - prev_dev->sibling = dev; - isapnp_last_device->next = dev; - isapnp_last_device = dev; + list_add_tail(&dev->bus_list, &card->devices); + list_add_tail(&dev->global_list, &isapnp_devices); size = 0; skip = 0; } else { @@ -970,7 +972,8 @@ static int __init isapnp_build_device_list(void) { int csn; unsigned char header[9], checksum; - struct pci_bus *card, *prev = NULL; + struct pci_bus *card; + struct pci_dev *dev; isapnp_wait(); isapnp_key(); @@ -997,11 +1000,11 @@ static int __init isapnp_build_device_list(void) if (isapnp_checksum_value != 0x00) printk("isapnp: checksum for device %i is not valid (0x%x)\n", csn, isapnp_checksum_value); card->checksum = isapnp_checksum_value; - if (!isapnp_cards) - isapnp_cards = card; - else - prev->next = card; - prev = card; + + list_add_tail(&card->node, &isapnp_cards); + } + isapnp_for_each_dev(dev) { + isapnp_fixup_device(dev); } return 0; } @@ -1012,9 +1015,7 @@ static int __init isapnp_build_device_list(void) int isapnp_present(void) { - if (isapnp_devices) - return 1; - return 0; + return !list_empty(&isapnp_devices); } int isapnp_cfg_begin(int csn, int logdev) @@ -1152,16 +1153,17 @@ struct pci_bus *isapnp_find_card(unsigned short vendor, unsigned short device, struct pci_bus *from) { - struct pci_bus *card; + struct list_head *list; - if (from == NULL) { - from = isapnp_cards; - } else { - from = from->next; - } - for (card = from; card; card = card->next) { + list = isapnp_cards.next; + if (from) + list = from->node.next; + + while (list != &isapnp_cards) { + struct pci_bus *card = pci_bus_b(list); if (card->vendor == vendor && card->device == device) return card; + list = list->next; } return NULL; } @@ -1171,39 +1173,45 @@ struct pci_dev *isapnp_find_dev(struct pci_bus *card, unsigned short function, struct pci_dev *from) { - struct pci_dev *dev; - int idx; - if (card == NULL) { /* look for a logical device from all cards */ - if (from == NULL) { - from = isapnp_devices; - } else { - from = from->next; - } - for (dev = from; dev; dev = dev->next) { + struct list_head *list; + + list = isapnp_devices.next; + if (from) + list = from->global_list.next; + + while (list != &isapnp_devices) { + int idx; + struct pci_dev *dev = pci_dev_g(list); + if (dev->vendor == vendor && dev->device == function) return dev; for (idx = 0; idx < DEVICE_COUNT_COMPATIBLE; idx++) if (dev->vendor_compatible[idx] == vendor && dev->device_compatible[idx] == function) return dev; + list = list->next; } } else { - if (from == NULL) { - from = card->devices; - } else { - from = from->next; - } + struct list_head *list; + + list = card->devices.next; + if (from) + list = from->bus_list.next; if (from->bus != card) /* something is wrong */ return NULL; - for (dev = from; dev; dev = dev->sibling) { + while (list != &card->devices) { + int idx; + struct pci_dev *dev = pci_dev_b(list); + if (dev->vendor == vendor && dev->device == function) return dev; for (idx = 0; idx < DEVICE_COUNT_COMPATIBLE; idx++) if (dev->vendor_compatible[idx] == vendor && dev->device_compatible[idx] == function) return dev; - } + list = list->next; + } } return NULL; } @@ -1454,7 +1462,8 @@ static int isapnp_check_port(struct isapnp_cfgtmp *cfg, int port, int size, int if (port + size > rport && port + size < (rport + rsize) - 1) return 1; } - for (dev = isapnp_devices; dev; dev = dev->next) { + + isapnp_for_each_dev(dev) { if (dev->active) { for (tmp = 0; tmp < 8; tmp++) { if (dev->resource[tmp].flags) { @@ -1551,7 +1560,7 @@ static int isapnp_check_interrupt(struct isapnp_cfgtmp *cfg, int irq, int idx) if (isapnp_reserve_irq[i] == irq) return 1; } - for (dev = isapnp_devices; dev; dev = dev->next) { + isapnp_for_each_dev(dev) { if (dev->active) { if (dev->irq_resource[0].start == irq || dev->irq_resource[1].start == irq) @@ -1630,7 +1639,7 @@ static int isapnp_check_dma(struct isapnp_cfgtmp *cfg, int dma, int idx) if (isapnp_reserve_dma[i] == dma) return 1; } - for (dev = isapnp_devices; dev; dev = dev->next) { + isapnp_for_each_dev(dev) { if (dev->active) { if (dev->dma_resource[0].start == dma || dev->dma_resource[1].start == dma) return 1; @@ -1695,8 +1704,8 @@ static int isapnp_check_mem(struct isapnp_cfgtmp *cfg, unsigned int addr, unsign { int i, tmp; unsigned int raddr, rsize; - struct pci_dev *dev; struct isapnp_mem *xmem; + struct pci_dev *dev; for (i = 0; i < 8; i++) { raddr = (unsigned int)isapnp_reserve_mem[i << 1]; @@ -1708,7 +1717,7 @@ static int isapnp_check_mem(struct isapnp_cfgtmp *cfg, unsigned int addr, unsign if (__check_region(&iomem_resource, addr, size)) return 1; } - for (dev = isapnp_devices; dev; dev = dev->next) { + isapnp_for_each_dev(dev) { if (dev->active) { for (tmp = 0; tmp < 4; tmp++) { if (dev->resource[tmp].flags) { @@ -1988,26 +1997,22 @@ static void isapnp_free_resources(struct isapnp_resources *resources, int alt) } } -static void isapnp_free_device(struct pci_dev *dev) +static void isapnp_free_card(struct pci_bus *card) { - struct pci_dev *next; - - while (dev) { - next = dev->sibling; + while (!list_empty(&card->devices)) { + struct list_head *list = card->devices.next; + struct pci_dev *dev = pci_dev_b(list); + list_del(list); isapnp_free_resources((struct isapnp_resources *)dev->sysdata, 0); kfree(dev); - dev = next; } + kfree(card); } #endif /* MODULE */ static void isapnp_free_all_resources(void) { -#ifdef MODULE - struct pci_bus *card, *cardnext; -#endif - #ifdef ISAPNP_REGION_OK release_resource(pidxr_res); #endif @@ -2015,10 +2020,10 @@ static void isapnp_free_all_resources(void) if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff) release_resource(isapnp_rdp_res); #ifdef MODULE - for (card = isapnp_cards; card; card = cardnext) { - cardnext = card->next; - isapnp_free_device(card->devices); - kfree(card); + while (!list_empty(&isapnp_cards)) { + struct list_head *list = isapnp_cards.next; + list_del(list); + isapnp_free_card(pci_bus_b(list)); } #ifdef CONFIG_PROC_FS isapnp_proc_done(); @@ -2052,23 +2057,14 @@ static int __init isapnp_do_reserve_irq(int irq) static void __init isapnp_pci_init(void) { - int devfn; struct pci_dev *dev; - - for (devfn = 0; devfn < 255; devfn++) { - dev = pci_find_slot(0, devfn); - if (dev != NULL) - break; - } - if (dev == NULL) - return; - while (dev) { + + pci_for_each_dev(dev) { #ifdef ISAPNP_DEBUG printk("PCI: reserved IRQ: %i\n", dev->irq); #endif if (dev->irq > 0) isapnp_do_reserve_irq(dev->irq); - dev = dev->next; } } @@ -2095,7 +2091,6 @@ int __init isapnp_init(void) { int cards; struct pci_bus *card; - struct pci_dev *dev; if (isapnp_disable) { isapnp_detected = 0; @@ -2144,15 +2139,18 @@ int __init isapnp_init(void) } isapnp_build_device_list(); cards = 0; - for (card = isapnp_cards; card; card = card->next) + + isapnp_for_each_card(card) { cards++; - if (isapnp_verbose) { - for (card = isapnp_cards; card; card = card->next) { + if (isapnp_verbose) { + struct list_head *devlist; printk( "isapnp: Card '%s'\n", card->name[0]?card->name:"Unknown"); if (isapnp_verbose < 2) continue; - for (dev = card->devices; dev; dev = dev->next) + for (devlist = card->devices.next; devlist != &card->devices; devlist = devlist->next) { + struct pci_dev *dev = pci_dev_b(devlist); printk("isapnp: Device '%s'\n", dev->name[0]?card->name:"Unknown"); + } } } if (cards) { diff --git a/drivers/pnp/isapnp_proc.c b/drivers/pnp/isapnp_proc.c index f78e3488b..1a742823f 100644 --- a/drivers/pnp/isapnp_proc.c +++ b/drivers/pnp/isapnp_proc.c @@ -19,10 +19,6 @@ * */ -static void *isapnp_alloc(long size); -struct pci_bus *isapnp_cards; -struct pci_dev *isapnp_devices; - struct isapnp_info_buffer { char *buffer; /* pointer to begin of buffer */ char *curr; /* current position in buffer */ @@ -204,8 +200,6 @@ static struct file_operations isapnp_info_entry_operations = isapnp_info_entry_release, /* release */ NULL, /* can't fsync */ NULL, /* fasync */ - NULL, /* check_media_change */ - NULL, /* revalidate */ NULL, /* lock */ }; @@ -539,10 +533,12 @@ static void isapnp_print_device(isapnp_info_buffer_t *buffer, struct pci_dev *de static void isapnp_info_read(isapnp_info_buffer_t *buffer) { - struct pci_bus *card; - struct pci_dev *dev; + struct list_head *card_list; - for (card = isapnp_cards; card; card = card->next) { + for (card_list = isapnp_cards.next; card_list != &isapnp_cards; card_list = card_list->next) { + struct pci_bus *card = list_entry(card_list, struct pci_bus, node); + struct list_head *dev_list; + isapnp_printf(buffer, "Card %i '", card->number); isapnp_print_devid(buffer, card->vendor, card->device); isapnp_printf(buffer, ":%s'", card->name[0]?card->name:"Unknown"); @@ -551,8 +547,10 @@ static void isapnp_info_read(isapnp_info_buffer_t *buffer) if (card->productver) isapnp_printf(buffer, " Product version %x.%x", card->productver >> 4, card->productver & 0x0f); isapnp_printf(buffer,"\n"); - for (dev = card->devices; dev; dev = dev->sibling) + for (dev_list = card->devices.next; dev_list != &card->devices; dev_list = dev_list->next) { + struct pci_dev *dev = list_entry(dev_list, struct pci_dev, bus_list); isapnp_print_device(buffer, dev); + } } } @@ -640,14 +638,17 @@ static int isapnp_set_card(char *line) static int isapnp_select_csn(char *line) { int csn; + struct list_head *list; char index[16], value[32]; isapnp_info_device = NULL; isapnp_get_str(index, line, sizeof(index)); csn = simple_strtoul(index, NULL, 0); - for (isapnp_info_card = isapnp_cards; isapnp_info_card; isapnp_info_card = isapnp_info_card->next) + for (list = isapnp_cards.next; list != &isapnp_cards; list = list->next) { + isapnp_info_card = list_entry(list, struct pci_bus, node); if (isapnp_info_card->number == csn) break; + } if (isapnp_info_card == NULL) { printk("isapnp: cannot find CSN %i\n", csn); return 1; diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c new file mode 100644 index 000000000..028eda7da --- /dev/null +++ b/drivers/pnp/quirks.c @@ -0,0 +1,75 @@ +/* + * This file contains quirk handling code for ISAPnP devices + * Some devices do not report all their resources, and need to have extra + * resources added. This is most easily accomplished at initialisation time + * when building up the resource structure for the first time. + * + * Copyright (c) 2000 Peter Denison <peterd@pnd-pc.demon.co.uk> + * + * Heavily based on PCI quirks handling which is + * + * Copyright (c) 1999 Martin Mares <mj@suse.cz> + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/isapnp.h> + +static void __init quirk_awe32_resources(struct pci_dev *dev) +{ + struct isapnp_port *port, *port2, *port3; + struct isapnp_resources *res = dev->sysdata; + + /* + * Unfortunately the isapnp_add_port_resource is too tightly bound + * into the PnP discovery sequence, and cannot be used. Link in the + * two extra ports (at offset 0x400 and 0x800 from the one given) by + * hand. + */ + for ( ; res ; res = res->alt ) { + port2 = isapnp_alloc(sizeof(struct isapnp_port)); + port3 = isapnp_alloc(sizeof(struct isapnp_port)); + if (!port2 || !port3) + return; + port = res->port; + memcpy(port2, port, sizeof(struct isapnp_port)); + memcpy(port3, port, sizeof(struct isapnp_port)); + port->next = port2; + port2->next = port3; + port2->min += 0x400; + port2->max += 0x400; + port3->min += 0x800; + port3->max += 0x800; + } + printk(KERN_INFO "ISAPnP: AWE32 quirk - adding two ports\n"); +} + + +/* + * ISAPnP Quirks + * Cards or devices that need some tweaking due to broken hardware + */ + +static struct isapnp_fixup isapnp_fixups[] __initdata = { + { ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0021), + quirk_awe32_resources }, + { 0 } +}; + +void isapnp_fixup_device(struct pci_dev *dev) +{ + int i = 0; + + while (isapnp_fixups[i].vendor != 0) { + if ((isapnp_fixups[i].vendor == dev->vendor) && + (isapnp_fixups[i].device == dev->device)) { + printk(KERN_DEBUG "PnP: Calling quirk for %s\n", + dev->slot_name); + isapnp_fixups[i].quirk_function(dev); + } + i++; + } +} + |