Commit 93482f5c authored by Matthew Wilcox's avatar Matthew Wilcox Committed by Greg Kroah-Hartman

[PATCH] PCI config space in sysfs

 - Fix a couple of bugs in sysfs's handling of binary files (my fault).
 - Implement pci config space reads and writes in sysfs
parent bac11c6f
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
* *
* (C) Copyright 2002 Greg Kroah-Hartman * (C) Copyright 2002 Greg Kroah-Hartman
* (C) Copyright 2002 IBM Corp. * (C) Copyright 2002 IBM Corp.
* (C) Copyright 2003 Matthew Wilcox
* (C) Copyright 2003 Hewlett-Packard
* *
* File attributes for PCI devices * File attributes for PCI devices
* *
...@@ -60,6 +62,108 @@ pci_show_resources(struct device * dev, char * buf) ...@@ -60,6 +62,108 @@ pci_show_resources(struct device * dev, char * buf)
static DEVICE_ATTR(resource,S_IRUGO,pci_show_resources,NULL); 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) void pci_create_sysfs_dev_files (struct pci_dev *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -72,4 +176,5 @@ void pci_create_sysfs_dev_files (struct pci_dev *pdev) ...@@ -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_class);
device_create_file (dev, &dev_attr_irq); device_create_file (dev, &dev_attr_irq);
device_create_file (dev, &dev_attr_resource); device_create_file (dev, &dev_attr_resource);
sysfs_create_bin_file(&dev->kobj, &pci_config_attr);
} }
...@@ -42,18 +42,17 @@ read(struct file * file, char __user * userbuf, size_t count, loff_t * off) ...@@ -42,18 +42,17 @@ read(struct file * file, char __user * userbuf, size_t count, loff_t * off)
ret = fill_read(dentry, buffer, offs, count); ret = fill_read(dentry, buffer, offs, count);
if (ret < 0) if (ret < 0)
goto Done; return ret;
count = ret; count = ret;
ret = -EFAULT; if (copy_to_user(userbuf, buffer + offs, count) != 0)
if (copy_to_user(userbuf, buffer, count) != 0) return -EINVAL;
goto Done;
printk("offs = %lld, *off = %lld, count = %zd\n", offs, *off, count);
*off = offs + count; *off = offs + count;
ret = count;
Done: return count;
return ret;
} }
static int static int
...@@ -72,7 +71,6 @@ static ssize_t write(struct file * file, const char __user * userbuf, ...@@ -72,7 +71,6 @@ static ssize_t write(struct file * file, const char __user * userbuf,
struct dentry *dentry = file->f_dentry; struct dentry *dentry = file->f_dentry;
int size = dentry->d_inode->i_size; int size = dentry->d_inode->i_size;
loff_t offs = *off; loff_t offs = *off;
int ret;
if (count > PAGE_SIZE) if (count > PAGE_SIZE)
count = PAGE_SIZE; count = PAGE_SIZE;
...@@ -83,16 +81,13 @@ static ssize_t write(struct file * file, const char __user * userbuf, ...@@ -83,16 +81,13 @@ static ssize_t write(struct file * file, const char __user * userbuf,
count = size - offs; count = size - offs;
} }
ret = -EFAULT; if (copy_from_user(buffer + offs, userbuf, count))
if (copy_from_user(buffer, userbuf, count)) return -EFAULT;
goto Done;
count = flush_write(dentry, buffer, offs, count); count = flush_write(dentry, buffer, offs, count);
if (count > 0) if (count > 0)
*off = offs + count; *off = offs + count;
ret = count; return count;
Done:
return ret;
} }
static int open(struct inode * inode, struct file * file) static int open(struct inode * inode, struct file * file)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment