summaryrefslogtreecommitdiffstats
path: root/drivers/pnp
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-02-16 01:07:24 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-02-16 01:07:24 +0000
commit95db6b748fc86297827fbd9c9ef174d491c9ad89 (patch)
tree27a92a942821cde1edda9a1b088718d436b3efe4 /drivers/pnp
parent45b27b0a0652331d104c953a5b192d843fff88f8 (diff)
Merge with Linux 2.3.40.
Diffstat (limited to 'drivers/pnp')
-rw-r--r--drivers/pnp/Makefile28
-rw-r--r--drivers/pnp/isapnp.c50
-rw-r--r--drivers/pnp/isapnp_proc.c265
-rw-r--r--drivers/pnp/quirks.c10
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++;