mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 11:41:38 -04:00
PCI: Allow read/write access to sysfs I/O port resources
PCI sysfs resource files currently only allow mmap'ing. On x86 this works fine for memory backed BARs, but doesn't work at all for I/O port backed BARs. Add read/write to I/O port PCI sysfs resource files to allow userspace access to these device regions. Acked-by: Chris Wright <[email protected]> Signed-off-by: Alex Williamson <[email protected]> Signed-off-by: Jesse Barnes <[email protected]>
This commit is contained in:
parent
2491762cfb
commit
8633328be2
2 changed files with 73 additions and 2 deletions
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue