|
@@ -778,6 +778,70 @@ pci_mmap_resource_wc(struct file *filp, struct kobject *kobj,
|
|
|
return pci_mmap_resource(kobj, attr, vma, 1);
|
|
|
}
|
|
|
|
|
|
+static ssize_t
|
|
|
+pci_resource_io(struct file *filp, struct kobject *kobj,
|
|
|
+ struct bin_attribute *attr, char *buf,
|
|
|
+ loff_t off, size_t count, bool write)
|
|
|
+{
|
|
|
+ struct pci_dev *pdev = to_pci_dev(container_of(kobj,
|
|
|
+ struct device, kobj));
|
|
|
+ struct resource *res = attr->private;
|
|
|
+ unsigned long port = off;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < PCI_ROM_RESOURCE; i++)
|
|
|
+ if (res == &pdev->resource[i])
|
|
|
+ break;
|
|
|
+ if (i >= PCI_ROM_RESOURCE)
|
|
|
+ return -ENODEV;
|
|
|
+
|
|
|
+ port += pci_resource_start(pdev, i);
|
|
|
+
|
|
|
+ if (port > pci_resource_end(pdev, i))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (port + count - 1 > pci_resource_end(pdev, i))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ switch (count) {
|
|
|
+ case 1:
|
|
|
+ if (write)
|
|
|
+ outb(*(u8 *)buf, port);
|
|
|
+ else
|
|
|
+ *(u8 *)buf = inb(port);
|
|
|
+ return 1;
|
|
|
+ case 2:
|
|
|
+ if (write)
|
|
|
+ outw(*(u16 *)buf, port);
|
|
|
+ else
|
|
|
+ *(u16 *)buf = inw(port);
|
|
|
+ return 2;
|
|
|
+ case 4:
|
|
|
+ if (write)
|
|
|
+ outl(*(u32 *)buf, port);
|
|
|
+ else
|
|
|
+ *(u32 *)buf = inl(port);
|
|
|
+ return 4;
|
|
|
+ }
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t
|
|
|
+pci_read_resource_io(struct file *filp, struct kobject *kobj,
|
|
|
+ struct bin_attribute *attr, char *buf,
|
|
|
+ loff_t off, size_t count)
|
|
|
+{
|
|
|
+ return pci_resource_io(filp, kobj, attr, buf, off, count, false);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t
|
|
|
+pci_write_resource_io(struct file *filp, struct kobject *kobj,
|
|
|
+ struct bin_attribute *attr, char *buf,
|
|
|
+ loff_t off, size_t count)
|
|
|
+{
|
|
|
+ return pci_resource_io(filp, kobj, attr, buf, off, count, true);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* pci_remove_resource_files - cleanup resource files
|
|
|
* @pdev: dev to cleanup
|
|
@@ -828,6 +892,10 @@ static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine)
|
|
|
sprintf(res_attr_name, "resource%d", num);
|
|
|
res_attr->mmap = pci_mmap_resource_uc;
|
|
|
}
|
|
|
+ if (pci_resource_flags(pdev, num) & IORESOURCE_IO) {
|
|
|
+ res_attr->read = pci_read_resource_io;
|
|
|
+ res_attr->write = pci_write_resource_io;
|
|
|
+ }
|
|
|
res_attr->attr.name = res_attr_name;
|
|
|
res_attr->attr.mode = S_IRUSR | S_IWUSR;
|
|
|
res_attr->size = pci_resource_len(pdev, num);
|