diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-16 01:07:24 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-16 01:07:24 +0000 |
commit | 95db6b748fc86297827fbd9c9ef174d491c9ad89 (patch) | |
tree | 27a92a942821cde1edda9a1b088718d436b3efe4 /drivers/pnp | |
parent | 45b27b0a0652331d104c953a5b192d843fff88f8 (diff) |
Merge with Linux 2.3.40.
Diffstat (limited to 'drivers/pnp')
-rw-r--r-- | drivers/pnp/Makefile | 28 | ||||
-rw-r--r-- | drivers/pnp/isapnp.c | 50 | ||||
-rw-r--r-- | drivers/pnp/isapnp_proc.c | 265 | ||||
-rw-r--r-- | drivers/pnp/quirks.c | 10 |
4 files changed, 276 insertions, 77 deletions
diff --git a/drivers/pnp/Makefile b/drivers/pnp/Makefile index 9a8ad136c..9c024342a 100644 --- a/drivers/pnp/Makefile +++ b/drivers/pnp/Makefile @@ -12,18 +12,26 @@ SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) -L_TARGET := pnp.a -MX_OBJS := -LX_OBJS := -MI_OBJS := -MIX_OBJS := +PROC_OBJS := + +ifdef CONFIG_PROC_FS +PROC_OBJS += isapnp_proc.o +endif + +ifeq ($(CONFIG_ISAPNP),m) + M_OBJS := isa-pnp.o + MIX_OBJS := isapnp.o + MI_OBJS := quirks.o $(PROC_OBJS) +endif ifeq ($(CONFIG_ISAPNP),y) - LX_OBJS += isapnp.o quirks.o -else - ifeq ($(CONFIG_ISAPNP),m) - MX_OBJS += isapnp.o quirks.o - endif + O_TARGET := isa-pnp.o + OX_OBJS := isapnp.o + O_OBJS := quirks.o $(PROC_OBJS) endif + include $(TOPDIR)/Rules.make + +isa-pnp.o: isapnp.o quirks.o $(PROC_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ isapnp.o quirks.o $(PROC_OBJS) diff --git a/drivers/pnp/isapnp.c b/drivers/pnp/isapnp.c index 8b6a42b7d..ec81da498 100644 --- a/drivers/pnp/isapnp.c +++ b/drivers/pnp/isapnp.c @@ -18,7 +18,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Changelog: - * 2000-01-01 Added ISAPnP quirks handling + * 2000-01-01 Added quirks handling for buggy hardware * Peter Denison <peterd@pnd-pc.demon.co.uk> */ @@ -30,31 +30,17 @@ #include <linux/ioport.h> #include <linux/string.h> #include <linux/malloc.h> -#include <linux/proc_fs.h> #include <linux/delay.h> #include <asm/io.h> #include <asm/dma.h> #include <asm/irq.h> #include <linux/pci.h> -#include <linux/vmalloc.h> -#include <linux/poll.h> #include <linux/init.h> -#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 - #if 0 #define ISAPNP_REGION_OK #endif @@ -286,6 +272,12 @@ static int isapnp_next_rdp(void) return 0; } rdp += RDP_STEP; + /* + * We cannot use NE2000 probe spaces for ISAPnP or we + * will lock up machines. + */ + if(rdp >= 0x280 && rdp <= 0x380) + continue; } return -1; } @@ -298,12 +290,8 @@ static inline void isapnp_set_rdp(void) } /* - * This code is badly broken. We cannot simply pick ports as the - * ISAPnP specification implies. We should try 4 or 5 safe ports - * then bale by default. - * - * This code touches NE2K cards or other devices and your box is - * history. + * Perform an isolation. The port selection code now tries to avoid + * "dangerous to read" ports. */ static int __init isapnp_isolate_rdp_select(void) @@ -996,6 +984,8 @@ static int __init isapnp_build_device_list(void) card->device = (header[3] << 8) | header[2]; card->serial = (header[7] << 24) | (header[6] << 16) | (header[5] << 8) | header[4]; isapnp_checksum_value = 0x00; + INIT_LIST_HEAD(&card->children); + INIT_LIST_HEAD(&card->devices); isapnp_parse_resource_map(card); if (isapnp_checksum_value != 0x00) printk("isapnp: checksum for device %i is not valid (0x%x)\n", csn, isapnp_checksum_value); @@ -1196,10 +1186,11 @@ struct pci_dev *isapnp_find_dev(struct pci_bus *card, struct list_head *list; list = card->devices.next; - if (from) + if (from) { list = from->bus_list.next; - if (from->bus != card) /* something is wrong */ - return NULL; + if (from->bus != card) /* something is wrong */ + return NULL; + } while (list != &card->devices) { int idx; struct pci_dev *dev = pci_dev_b(list); @@ -1633,7 +1624,10 @@ static int isapnp_check_dma(struct isapnp_cfgtmp *cfg, int dma, int idx) int i; struct pci_dev *dev; - if (dma < 0 || dma == 4 || dma > 7) + /* Some machines allow DMA 0, but others don't. In fact on some + boxes DMA 0 is the memory refresh. Play safe */ + + if (dma < 1 || dma == 4 || dma > 7) return 1; for (i = 0; i < 8; i++) { if (isapnp_reserve_dma[i] == dma) @@ -1773,8 +1767,8 @@ static int isapnp_valid_mem(struct isapnp_cfgtmp *cfg, int idx) mem = cfg->mem[idx]; if (!mem) return -EINVAL; - value1 = &cfg->result.resource[idx].start; - value2 = &cfg->result.resource[idx].end; + value1 = &cfg->result.resource[idx + 8].start; + value2 = &cfg->result.resource[idx + 8].end; if (cfg->result.resource[idx + 8].flags & IORESOURCE_AUTO) { cfg->result.resource[idx + 8].flags &= ~IORESOURCE_AUTO; *value1 = mem->min; @@ -1785,7 +1779,7 @@ static int isapnp_valid_mem(struct isapnp_cfgtmp *cfg, int idx) do { *value1 += mem->align; *value2 = *value1 + mem->size - 1; - if (*value1 >= 8 || !mem->align) { + if (*value1 > mem->max || !mem->align) { if (mem->res && mem->res->alt) { if ((err = isapnp_alternative_switch(cfg, mem->res, mem->res->alt))<0) return err; diff --git a/drivers/pnp/isapnp_proc.c b/drivers/pnp/isapnp_proc.c index 1a742823f..a26670fc7 100644 --- a/drivers/pnp/isapnp_proc.c +++ b/drivers/pnp/isapnp_proc.c @@ -19,6 +19,17 @@ * */ +#define __NO_VERSION__ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/proc_fs.h> +#include <linux/poll.h> +#include <linux/vmalloc.h> +#include <asm/uaccess.h> +#include <linux/isapnp.h> + struct isapnp_info_buffer { char *buffer; /* pointer to begin of buffer */ char *curr; /* current position in buffer */ @@ -31,6 +42,8 @@ struct isapnp_info_buffer { typedef struct isapnp_info_buffer isapnp_info_buffer_t; static struct proc_dir_entry *isapnp_proc_entry = NULL; +static struct proc_dir_entry *isapnp_proc_bus_dir = NULL; +static struct proc_dir_entry *isapnp_proc_devices_entry = NULL; static void isapnp_info_read(isapnp_info_buffer_t *buffer); static void isapnp_info_write(isapnp_info_buffer_t *buffer); @@ -56,6 +69,18 @@ int isapnp_printf(isapnp_info_buffer_t * buffer, char *fmt,...) return res; } +static void isapnp_devid(char *str, unsigned short vendor, unsigned short device) +{ + sprintf(str, "%c%c%c%x%x%x%x", + 'A' + ((vendor >> 2) & 0x3f) - 1, + 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1, + 'A' + ((vendor >> 8) & 0x1f) - 1, + (device >> 4) & 0x0f, + device & 0x0f, + (device >> 12) & 0x0f, + (device >> 8) & 0x0f); +} + static loff_t isapnp_info_entry_lseek(struct file *file, loff_t offset, int orig) { switch (orig) { @@ -175,17 +200,6 @@ static unsigned int isapnp_info_entry_poll(struct file *file, poll_table * wait) return POLLIN | POLLRDNORM; } -static int isapnp_info_entry_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return -EINVAL; -} - -static int isapnp_info_entry_mmap(struct file *file, struct vm_area_struct *vma) -{ - return -ENXIO; -} - static struct file_operations isapnp_info_entry_operations = { isapnp_info_entry_lseek, /* lseek */ @@ -193,8 +207,8 @@ static struct file_operations isapnp_info_entry_operations = isapnp_info_entry_write, /* write */ NULL, /* readdir */ isapnp_info_entry_poll, /* poll */ - isapnp_info_entry_ioctl, /* ioctl - default */ - isapnp_info_entry_mmap, /* mmap */ + NULL, /* ioctl - default */ + NULL, /* mmap */ isapnp_info_entry_open, /* open */ NULL, /* flush */ isapnp_info_entry_release, /* release */ @@ -208,24 +222,210 @@ static struct inode_operations isapnp_info_entry_inode_operations = &isapnp_info_entry_operations, /* default sound info directory file-ops */ }; -static int __init isapnp_proc_init(void) +static loff_t isapnp_proc_bus_lseek(struct file *file, loff_t off, int whence) +{ + loff_t new; + + switch (whence) { + case 0: + new = off; + break; + case 1: + new = file->f_pos + off; + break; + case 2: + new = 256 + off; + break; + default: + return -EINVAL; + } + if (new < 0 || new > 256) + return -EINVAL; + return (file->f_pos = new); +} + +static ssize_t isapnp_proc_bus_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos) +{ + struct inode *ino = file->f_dentry->d_inode; + struct proc_dir_entry *dp = ino->u.generic_ip; + struct pci_dev *dev = dp->data; + int pos = *ppos; + int cnt, size = 256; + + if (pos >= size) + return 0; + if (nbytes >= size) + nbytes = size; + if (pos + nbytes > size) + nbytes = size - pos; + cnt = nbytes; + + if (!access_ok(VERIFY_WRITE, buf, cnt)) + return -EINVAL; + + isapnp_cfg_begin(dev->bus->number, dev->devfn); + for ( ; pos < 256 && cnt > 0; pos++, buf++, cnt--) { + unsigned char val; + val = isapnp_read_byte(pos); + __put_user(val, buf); + } + isapnp_cfg_end(); + + *ppos = pos; + return nbytes; +} + +static struct file_operations isapnp_proc_bus_file_operations = +{ + isapnp_proc_bus_lseek, /* lseek */ + isapnp_proc_bus_read, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* open */ + NULL, /* flush */ + NULL, /* release */ + NULL, /* can't fsync */ + NULL, /* fasync */ + NULL, /* lock */ +}; + +static struct inode_operations isapnp_proc_bus_inode_operations = +{ + &isapnp_proc_bus_file_operations, +}; + +static int isapnp_proc_attach_device(struct pci_dev *dev) +{ + struct pci_bus *bus = dev->bus; + struct proc_dir_entry *de, *e; + char name[16]; + + if (!(de = bus->procdir)) { + sprintf(name, "%02x", bus->number); + de = bus->procdir = proc_mkdir(name, isapnp_proc_bus_dir); + if (!de) + return -ENOMEM; + } + sprintf(name, "%02x", dev->devfn); + e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO, de); + if (!e) + return -ENOMEM; + e->ops = &isapnp_proc_bus_inode_operations; + e->data = dev; + e->size = 256; + return 0; +} + +#ifdef MODULE +static int __exit isapnp_proc_detach_device(struct pci_dev *dev) +{ + struct pci_bus *bus = dev->bus; + struct proc_dir_entry *de; + char name[16]; + + if (!(de = bus->procdir)) + return -EINVAL; + sprintf(name, "%02x", dev->devfn); + remove_proc_entry(name, de); + return 0; +} + +static int __exit isapnp_proc_detach_bus(struct pci_bus *bus) +{ + struct proc_dir_entry *de; + char name[16]; + + if (!(de = bus->procdir)) + return -EINVAL; + sprintf(name, "%02x", bus->number); + remove_proc_entry(name, isapnp_proc_bus_dir); + return 0; +} +#endif + +static int isapnp_proc_read_devices(char *buf, char **start, off_t pos, int count) +{ + struct pci_dev *dev; + off_t at = 0; + int len, cnt, i; + + cnt = 0; + isapnp_for_each_dev(dev) { + char bus_id[8], device_id[8]; + + isapnp_devid(bus_id, dev->bus->vendor, dev->bus->device); + isapnp_devid(device_id, dev->vendor, dev->device); + len = sprintf(buf, "%02x%02x\t%s%s\t", + dev->bus->number, + dev->devfn, + bus_id, + device_id); + isapnp_cfg_begin(dev->bus->number, dev->devfn); + len += sprintf(buf+len, "%02x", isapnp_read_byte(ISAPNP_CFG_ACTIVATE)); + for (i = 0; i < 8; i++) + len += sprintf(buf+len, "%04x", isapnp_read_word(ISAPNP_CFG_PORT + (i << 1))); + for (i = 0; i < 2; i++) + len += sprintf(buf+len, "%04x", isapnp_read_word(ISAPNP_CFG_IRQ + (i << 1))); + for (i = 0; i < 2; i++) + len += sprintf(buf+len, "%04x", isapnp_read_word(ISAPNP_CFG_DMA + i)); + for (i = 0; i < 4; i++) + len += sprintf(buf+len, "%08x", isapnp_read_dword(ISAPNP_CFG_MEM + (i << 3))); + isapnp_cfg_end(); + buf[len++] = '\n'; + at += len; + if (at >= pos) { + if (!*start) { + *start = buf + (pos - (at - len)); + cnt = at - pos; + } else + cnt += len; + buf += len; + } + } + return (count > cnt) ? cnt : count; +} + +int __init isapnp_proc_init(void) { struct proc_dir_entry *p; + struct pci_dev *dev; isapnp_proc_entry = NULL; p = create_proc_entry("isapnp", S_IFREG | S_IRUGO | S_IWUSR, &proc_root); - if (!p) - return -ENOMEM; - p->ops = &isapnp_info_entry_inode_operations; + if (p) + p->ops = &isapnp_info_entry_inode_operations; isapnp_proc_entry = p; + isapnp_proc_bus_dir = proc_mkdir("isapnp", proc_bus); + isapnp_proc_devices_entry = create_proc_info_entry("devices", 0, + isapnp_proc_bus_dir, + isapnp_proc_read_devices); + isapnp_for_each_dev(dev) { + isapnp_proc_attach_device(dev); + } return 0; } #ifdef MODULE -static int isapnp_proc_done(void) +int __exit isapnp_proc_done(void) { + struct pci_dev *dev; + struct pci_bus *card; + + isapnp_for_each_dev(dev) { + isapnp_proc_detach_device(dev); + } + isapnp_for_each_card(card) { + isapnp_proc_detach_bus(card); + } + if (isapnp_proc_devices_entry) + remove_proc_entry("devices", isapnp_proc_devices_entry); + if (isapnp_proc_bus_dir) + remove_proc_entry("isapnp", proc_bus); if (isapnp_proc_entry) - remove_proc_entry("isapnp",&proc_root); + remove_proc_entry("isapnp", &proc_root); return 0; } #endif /* MODULE */ @@ -238,14 +438,7 @@ static void isapnp_print_devid(isapnp_info_buffer_t *buffer, unsigned short vend { char tmp[8]; - sprintf(tmp, "%c%c%c%x%x%x%x", - 'A' + ((vendor >> 2) & 0x3f) - 1, - 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1, - 'A' + ((vendor >> 8) & 0x1f) - 1, - (device >> 4) & 0x0f, - device & 0x0f, - (device >> 12) & 0x0f, - (device >> 8) & 0x0f); + isapnp_devid(tmp, vendor, device); isapnp_printf(buffer, tmp); } @@ -533,10 +726,9 @@ 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 list_head *card_list; - - 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 pci_bus *card; + + isapnp_for_each_card(card) { struct list_head *dev_list; isapnp_printf(buffer, "Card %i '", card->number); @@ -547,10 +739,8 @@ 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_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); - } + for (dev_list = card->devices.next; dev_list != &card->devices; dev_list = dev_list->next) + isapnp_print_device(buffer, pci_dev_b(dev_list)); } } @@ -644,12 +834,13 @@ static int isapnp_select_csn(char *line) isapnp_info_device = NULL; isapnp_get_str(index, line, sizeof(index)); csn = simple_strtoul(index, NULL, 0); + for (list = isapnp_cards.next; list != &isapnp_cards; list = list->next) { - isapnp_info_card = list_entry(list, struct pci_bus, node); + isapnp_info_card = pci_bus_b(list); if (isapnp_info_card->number == csn) break; } - if (isapnp_info_card == NULL) { + if (list == &isapnp_cards) { printk("isapnp: cannot find CSN %i\n", csn); return 1; } diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index 028eda7da..838241de2 100644 --- a/drivers/pnp/quirks.c +++ b/drivers/pnp/quirks.c @@ -16,6 +16,8 @@ #include <linux/pci.h> #include <linux/init.h> #include <linux/isapnp.h> +#include <linux/string.h> + static void __init quirk_awe32_resources(struct pci_dev *dev) { @@ -55,6 +57,10 @@ static void __init quirk_awe32_resources(struct pci_dev *dev) static struct isapnp_fixup isapnp_fixups[] __initdata = { { ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0021), quirk_awe32_resources }, + { ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0022), + quirk_awe32_resources }, + { ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0023), + quirk_awe32_resources }, { 0 } }; @@ -65,8 +71,8 @@ void isapnp_fixup_device(struct pci_dev *dev) 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); + printk(KERN_DEBUG "PnP: Calling quirk for %02x:%02x\n", + dev->bus->number, dev->devfn); isapnp_fixups[i].quirk_function(dev); } i++; |