pci-sysfs.c
来自「linux 内核源代码」· C语言 代码 · 共 715 行 · 第 1/2 页
C
715 行
{ struct pci_bus *bus = to_pci_bus(container_of(kobj, struct class_device, kobj)); /* Only support 1, 2 or 4 byte accesses */ if (count != 1 && count != 2 && count != 4) return -EINVAL; return pci_legacy_read(bus, off, (u32 *)buf, count);}/** * pci_write_legacy_io - write byte(s) to legacy I/O port space * @kobj: kobject corresponding to file to read from * @buf: buffer containing value to be written * @off: offset into legacy I/O port space * @count: number of bytes to write * * Writes 1, 2, or 4 bytes from legacy I/O port space using an arch specific * callback routine (pci_legacy_write). */ssize_tpci_write_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count){ struct pci_bus *bus = to_pci_bus(container_of(kobj, struct class_device, kobj)); /* Only support 1, 2 or 4 byte accesses */ if (count != 1 && count != 2 && count != 4) return -EINVAL; return pci_legacy_write(bus, off, *(u32 *)buf, count);}/** * pci_mmap_legacy_mem - map legacy PCI memory into user memory space * @kobj: kobject corresponding to device to be mapped * @attr: struct bin_attribute for this file * @vma: struct vm_area_struct passed to mmap * * Uses an arch specific callback, pci_mmap_legacy_page_range, to mmap * legacy memory space (first meg of bus space) into application virtual * memory space. */intpci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr, struct vm_area_struct *vma){ struct pci_bus *bus = to_pci_bus(container_of(kobj, struct class_device, kobj)); return pci_mmap_legacy_page_range(bus, vma);}#endif /* HAVE_PCI_LEGACY */#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? maybe automatic for prefetchable regions? */static intpci_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; resource_size_t start, end; int i; for (i = 0; i < PCI_ROM_RESOURCE; i++) if (res == &pdev->resource[i]) break; if (i >= PCI_ROM_RESOURCE) return -ENODEV; /* pci_mmap_page_range() expects the same kind of entry as coming * from /proc/bus/pci/ which is a "user visible" value. If this is * different from the resource itself, arch will do necessary fixup. */ pci_resource_to_user(pdev, i, res, &start, &end); vma->vm_pgoff += 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);}/** * pci_remove_resource_files - cleanup resource files * @dev: dev to cleanup * * If we created resource files for @dev, remove them from sysfs and * free their resources. */static voidpci_remove_resource_files(struct pci_dev *pdev){ int i; 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); } }}/** * pci_create_resource_files - create resource files in sysfs for @dev * @dev: dev in question * * Walk the resources in @dev creating files for each resource available. */static int pci_create_resource_files(struct pci_dev *pdev){ int i; int retval; /* 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; /* allocate attribute structure, piggyback attribute name */ res_attr = kzalloc(sizeof(*res_attr) + 10, GFP_ATOMIC); if (res_attr) { char *res_attr_name = (char *)(res_attr + 1); pdev->res_attr[i] = res_attr; sprintf(res_attr_name, "resource%d", i); res_attr->attr.name = res_attr_name; res_attr->attr.mode = S_IRUSR | S_IWUSR; res_attr->size = pci_resource_len(pdev, i); res_attr->mmap = pci_mmap_resource; res_attr->private = &pdev->resource[i]; retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr); if (retval) { pci_remove_resource_files(pdev); return retval; } } else { return -ENOMEM; } } return 0;}#else /* !HAVE_PCI_MMAP */static inline int pci_create_resource_files(struct pci_dev *dev) { return 0; }static inline void pci_remove_resource_files(struct pci_dev *dev) { return; }#endif /* HAVE_PCI_MMAP *//** * pci_write_rom - used to enable access to the PCI ROM display * @kobj: kernel object handle * @buf: user input * @off: file offset * @count: number of byte in input * * writing anything except 0 enables it */static ssize_tpci_write_rom(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count){ struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj)); if ((off == 0) && (*buf == '0') && (count == 2)) pdev->rom_attr_enabled = 0; else pdev->rom_attr_enabled = 1; return count;}/** * pci_read_rom - read a PCI ROM * @kobj: kernel object handle * @buf: where to put the data we read from the ROM * @off: file offset * @count: number of bytes to read * * Put @count bytes starting at @off into @buf from the ROM in the PCI * device corresponding to @kobj. */static ssize_tpci_read_rom(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count){ struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj)); void __iomem *rom; size_t size; if (!pdev->rom_attr_enabled) return -EINVAL; rom = pci_map_rom(pdev, &size); /* size starts out as PCI window size */ if (!rom) return 0; if (off >= size) count = 0; else { if (off + count > size) count = size - off; memcpy_fromio(buf, rom + off, count); } pci_unmap_rom(pdev, rom); 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,};static struct bin_attribute pcie_config_attr = { .attr = { .name = "config", .mode = S_IRUGO | S_IWUSR, }, .size = 4096, .read = pci_read_config, .write = pci_write_config,};int __attribute__ ((weak)) pcibios_add_platform_entries(struct pci_dev *dev){ return 0;}int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev){ struct bin_attribute *rom_attr = NULL; int retval; if (!sysfs_initialized) return -EACCES; if (pdev->cfg_size < 4096) retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr); else retval = sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr); if (retval) goto err; retval = pci_create_resource_files(pdev); if (retval) goto err_bin_file; /* If the device has a ROM, try to expose it in sysfs. */ if (pci_resource_len(pdev, PCI_ROM_RESOURCE) || (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)) { rom_attr = kzalloc(sizeof(*rom_attr), GFP_ATOMIC); if (rom_attr) { pdev->rom_attr = rom_attr; rom_attr->size = pci_resource_len(pdev, PCI_ROM_RESOURCE); rom_attr->attr.name = "rom"; rom_attr->attr.mode = S_IRUSR; rom_attr->read = pci_read_rom; rom_attr->write = pci_write_rom; retval = sysfs_create_bin_file(&pdev->dev.kobj, rom_attr); if (retval) goto err_rom; } else { retval = -ENOMEM; goto err_resource_files; } } /* add platform-specific attributes */ if (pcibios_add_platform_entries(pdev)) goto err_rom_file; return 0;err_rom_file: if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) sysfs_remove_bin_file(&pdev->dev.kobj, rom_attr);err_rom: kfree(rom_attr);err_resource_files: pci_remove_resource_files(pdev);err_bin_file: 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);err: return retval;}/** * pci_remove_sysfs_dev_files - cleanup PCI specific sysfs files * @pdev: device whose entries we should free * * Cleanup when @pdev is removed from sysfs. */void pci_remove_sysfs_dev_files(struct pci_dev *pdev){ if (!sysfs_initialized) return; 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); pci_remove_resource_files(pdev); if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) { if (pdev->rom_attr) { sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); kfree(pdev->rom_attr); } }}static int __init pci_sysfs_init(void){ struct pci_dev *pdev = NULL; int retval; sysfs_initialized = 1; for_each_pci_dev(pdev) { retval = pci_create_sysfs_dev_files(pdev); if (retval) { pci_dev_put(pdev); return retval; } } return 0;}late_initcall(pci_sysfs_init);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?