summaryrefslogtreecommitdiffstats
path: root/drivers/pnp/isapnp_proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pnp/isapnp_proc.c')
-rw-r--r--drivers/pnp/isapnp_proc.c265
1 files changed, 228 insertions, 37 deletions
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;
}