]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] PCI config space in sysfs
authorMatthew Wilcox <willy@debian.org>
Thu, 3 Jul 2003 08:52:14 +0000 (01:52 -0700)
committerGreg Kroah-Hartman <greg@kroah.com>
Thu, 3 Jul 2003 08:52:14 +0000 (01:52 -0700)
 - Fix a couple of bugs in sysfs's handling of binary files (my fault).
 - Implement pci config space reads and writes in sysfs

drivers/pci/pci-sysfs.c
fs/sysfs/bin.c

index 4e13d7141b7849baee66c3b822072fdf539686bf..dc560bf77421e7198312598f0b37430f7f49f48a 100644 (file)
@@ -3,6 +3,8 @@
  *
  * (C) Copyright 2002 Greg Kroah-Hartman
  * (C) Copyright 2002 IBM Corp.
+ * (C) Copyright 2003 Matthew Wilcox
+ * (C) Copyright 2003 Hewlett-Packard
  *
  * File attributes for PCI devices
  *
@@ -60,6 +62,108 @@ pci_show_resources(struct device * dev, char * buf)
 
 static DEVICE_ATTR(resource,S_IRUGO,pci_show_resources,NULL);
 
+static ssize_t
+pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+       struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
+       unsigned int size = 64;
+
+       /* Several chips lock up trying to read undefined config space */
+       if (capable(CAP_SYS_ADMIN)) {
+               size = 256;
+       } else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
+               size = 128;
+       }
+
+       if (off > size)
+               return 0;
+       if (off + count > size) {
+               size -= off;
+               count = size;
+       } else {
+               size = count;
+       }
+
+       while (off & 3) {
+               unsigned char val;
+               pci_read_config_byte(dev, off, &val);
+               buf[off] = val;
+               off++;
+               if (--size == 0)
+                       break;
+       }
+
+       while (size > 3) {
+               unsigned int val;
+               pci_read_config_dword(dev, off, &val);
+               buf[off] = val & 0xff;
+               buf[off + 1] = (val >> 8) & 0xff;
+               buf[off + 2] = (val >> 16) & 0xff;
+               buf[off + 3] = (val >> 24) & 0xff;
+               off += 4;
+               size -= 4;
+       }
+
+       while (size > 0) {
+               unsigned char val;
+               pci_read_config_byte(dev, off, &val);
+               buf[off] = val;
+               off++;
+               --size;
+       }
+
+       return count;
+}
+
+static ssize_t
+pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+       struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
+       unsigned int size = count;
+
+       if (off > 256)
+               return 0;
+       if (off + count > 256) {
+               size = 256 - off;
+               count = size;
+       }
+
+       while (off & 3) {
+               pci_write_config_byte(dev, off, buf[off]);
+               off++;
+               if (--size == 0)
+                       break;
+       }
+
+       while (size > 3) {
+               unsigned int val = buf[off];
+               val |= (unsigned int) buf[off + 1] << 8;
+               val |= (unsigned int) buf[off + 2] << 16;
+               val |= (unsigned int) buf[off + 3] << 24;
+               pci_write_config_dword(dev, off, val);
+               off += 4;
+               size -= 4;
+       }
+
+       while (size > 0) {
+               pci_write_config_byte(dev, off, buf[off]);
+               off++;
+               --size;
+       }
+
+       return count;
+}
+
+static struct bin_attribute pci_config_attr = {
+       .attr = {
+               .name = "config",
+               .mode = S_IRUGO | S_IWUSR,
+       },
+       .size = 256,
+       .read = pci_read_config,
+       .write = pci_write_config,
+};
+
 void pci_create_sysfs_dev_files (struct pci_dev *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -72,4 +176,5 @@ void pci_create_sysfs_dev_files (struct pci_dev *pdev)
        device_create_file (dev, &dev_attr_class);
        device_create_file (dev, &dev_attr_irq);
        device_create_file (dev, &dev_attr_resource);
+       sysfs_create_bin_file(&dev->kobj, &pci_config_attr);
 }
index e5439f1aafa5674304a3212401639b7028239655..09ef6dcec6b284806e462a6771a8d654650772db 100644 (file)
@@ -42,18 +42,17 @@ read(struct file * file, char __user * userbuf, size_t count, loff_t * off)
 
        ret = fill_read(dentry, buffer, offs, count);
        if (ret < 0) 
-               goto Done;
+               return ret;
        count = ret;
 
-       ret = -EFAULT;
-       if (copy_to_user(userbuf, buffer, count) != 0)
-               goto Done;
+       if (copy_to_user(userbuf, buffer + offs, count) != 0)
+               return -EINVAL;
+
+       printk("offs = %lld, *off = %lld, count = %zd\n", offs, *off, count);
 
        *off = offs + count;
-       ret = count;
 
- Done:
-       return ret;
+       return count;
 }
 
 static int
@@ -72,7 +71,6 @@ static ssize_t write(struct file * file, const char __user * userbuf,
        struct dentry *dentry = file->f_dentry;
        int size = dentry->d_inode->i_size;
        loff_t offs = *off;
-       int ret;
 
        if (count > PAGE_SIZE)
                count = PAGE_SIZE;
@@ -83,16 +81,13 @@ static ssize_t write(struct file * file, const char __user * userbuf,
                        count = size - offs;
        }
 
-       ret = -EFAULT;
-       if (copy_from_user(buffer, userbuf, count))
-               goto Done;
+       if (copy_from_user(buffer + offs, userbuf, count))
+               return -EFAULT;
 
        count = flush_write(dentry, buffer, offs, count);
        if (count > 0)
                *off = offs + count;
-       ret = count;
- Done:
-       return ret;
+       return count;
 }
 
 static int open(struct inode * inode, struct file * file)