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 + -
显示快捷键?