===== drivers/pci/pci-sysfs.c 1.13 vs edited ===== --- 1.13/drivers/pci/pci-sysfs.c 2004-11-30 11:54:02 -08:00 +++ edited/drivers/pci/pci-sysfs.c 2004-12-20 11:24:34 -08:00 @@ -20,6 +20,7 @@ #include #include #include +#include #include "pci.h" @@ -178,6 +179,32 @@ return count; } +#ifdef HAVE_PCI_MMAP +/** + * pci_mmap_resource - map a PCI resource into user memory space + * @kobj: kobject for mapping + * @attr: struct bin_attribute for the file being mapped + * @vma: struct vm_area_struct passed into the mmap + * + * Use the regular PCI mapping routines to map a PCI resource into userspace. + * FIXME: write combining should work + */ +static int +pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, + struct vm_area_struct *vma) +{ + struct pci_dev *pdev = to_pci_dev(container_of(kobj, + struct device, kobj)); + struct resource *res = (struct resource *)attr->private; + enum pci_mmap_state mmap_type; + + vma->vm_pgoff += res->start >> PAGE_SHIFT; + mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; + + return pci_mmap_page_range(pdev, vma, mmap_type, 0); +} +#endif /* HAVE_PCI_MMAP */ + /** * pci_write_rom - used to enable access to the PCI ROM display * @kobj: kernel object handle @@ -261,6 +288,8 @@ int pci_create_sysfs_dev_files (struct pci_dev *pdev) { + int i; + if (!sysfs_initialized) return -EACCES; @@ -268,6 +297,29 @@ sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr); else sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr); +#ifdef HAVE_PCI_MMAP + /* Expose the PCI resources from this device as files */ + for (i = 0; i < PCI_ROM_RESOURCE; i++) { + struct bin_attribute *res_attr; + + /* skip empty resources */ + if (!pci_resource_len(pdev, i)) + continue; + + res_attr = kmalloc(sizeof(*res_attr), GFP_ATOMIC); + if (res_attr) { + pdev->res_attr[i] = res_attr; + res_attr->attr.name = kmalloc(10, GFP_ATOMIC); + sprintf(res_attr->attr.name, "resource%d", i); + res_attr->size = pci_resource_len(pdev, i); + res_attr->attr.mode = S_IRUSR | S_IWUSR; + res_attr->attr.owner = THIS_MODULE; + res_attr->mmap = pci_mmap_resource; + res_attr->private = &pdev->resource[i]; + sysfs_create_bin_file(&pdev->dev.kobj, res_attr); + } + } +#endif /* HAVE_PCI_MMAP */ /* If the device has a ROM, try to expose it in sysfs. */ if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) { @@ -299,10 +351,22 @@ */ void pci_remove_sysfs_dev_files(struct pci_dev *pdev) { + int i; + if (pdev->cfg_size < 4096) sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); else sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr); + + for (i = 0; i < PCI_ROM_RESOURCE; i++) { + struct bin_attribute *res_attr; + + res_attr = pdev->res_attr[i]; + if (res_attr) { + sysfs_remove_bin_file(&pdev->dev.kobj, res_attr); + kfree(res_attr); + } + } if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) { if (pdev->rom_attr) { ===== fs/sysfs/bin.c 1.19 vs edited ===== --- 1.19/fs/sysfs/bin.c 2004-11-01 12:46:46 -08:00 +++ edited/fs/sysfs/bin.c 2004-12-20 11:07:58 -08:00 @@ -92,6 +92,15 @@ return count; } +static int mmap(struct file *file, struct vm_area_struct *vma) +{ + struct dentry *dentry = file->f_dentry; + struct bin_attribute *attr = to_bin_attr(dentry); + struct kobject *kobj = to_kobj(dentry->d_parent); + + return attr->mmap(kobj, attr, vma); +} + static int open(struct inode * inode, struct file * file) { struct kobject *kobj = sysfs_get_kobject(file->f_dentry->d_parent); @@ -107,9 +116,9 @@ goto Done; error = -EACCES; - if ((file->f_mode & FMODE_WRITE) && !attr->write) + if ((file->f_mode & FMODE_WRITE) && !(attr->write || attr->mmap)) goto Error; - if ((file->f_mode & FMODE_READ) && !attr->read) + if ((file->f_mode & FMODE_READ) && !(attr->read || attr->mmap)) goto Error; error = -ENOMEM; @@ -144,6 +153,7 @@ struct file_operations bin_fops = { .read = read, .write = write, + .mmap = mmap, .llseek = generic_file_llseek, .open = open, .release = release, ===== include/linux/sysfs.h 1.38 vs edited ===== --- 1.38/include/linux/sysfs.h 2004-11-01 12:47:02 -08:00 +++ edited/include/linux/sysfs.h 2004-12-20 11:36:14 -08:00 @@ -47,11 +47,16 @@ #define attr_name(_attr) (_attr).attr.name +struct vm_area_struct; /* circular dependencies? */ + struct bin_attribute { struct attribute attr; size_t size; + void *private; ssize_t (*read)(struct kobject *, char *, loff_t, size_t); ssize_t (*write)(struct kobject *, char *, loff_t, size_t); + int (*mmap)(struct kobject *, struct bin_attribute *attr, + struct vm_area_struct *vma); }; struct sysfs_ops { ===== include/linux/pci.h 1.142 vs edited ===== --- 1.142/include/linux/pci.h 2004-10-31 14:10:04 -08:00 +++ edited/include/linux/pci.h 2004-12-20 11:34:43 -08:00 @@ -539,6 +539,7 @@ u32 saved_config_space[16]; /* config space saved at suspend time */ struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */ int rom_attr_enabled; /* has display of the rom attribute been enabled? */ + struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */ #ifdef CONFIG_PCI_NAMES #define PCI_NAME_SIZE 96 #define PCI_NAME_HALF __stringify(43) /* less than half to handle slop */