SYSCALL_DEFINE5(pciconfig_write, unsigned long, bus, unsigned long, dfn, unsigned long, off, unsigned long, len, void __user *, buf) { struct pci_dev *dev; u8 byte; u16 word; u32 dword; int err = 0; if (!capable(CAP_SYS_ADMIN) || (get_securelevel() > 0)) return -EPERM; dev = pci_get_bus_and_slot(bus, dfn); if (!dev) return -ENODEV; switch (len) { case 1: err = get_user(byte, (u8 __user *)buf); if (err) break; err = pci_user_write_config_byte(dev, off, byte); if (err != PCIBIOS_SUCCESSFUL) err = -EIO; break; case 2: err = get_user(word, (u16 __user *)buf); if (err) break; err = pci_user_write_config_word(dev, off, word); if (err != PCIBIOS_SUCCESSFUL) err = -EIO; break; case 4: err = get_user(dword, (u32 __user *)buf); if (err) break; err = pci_user_write_config_dword(dev, off, dword); if (err != PCIBIOS_SUCCESSFUL) err = -EIO; break; default: err = -EINVAL; break; } pci_dev_put(dev); return err; }
static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos) { struct inode *ino = file_inode(file); struct pci_dev *dev = PDE_DATA(ino); int pos = *ppos; int size = dev->cfg_size; int cnt; if (pos >= size) return 0; if (nbytes >= size) nbytes = size; if (pos + nbytes > size) nbytes = size - pos; cnt = nbytes; if (!access_ok(VERIFY_READ, buf, cnt)) return -EINVAL; pci_config_pm_runtime_get(dev); if ((pos & 1) && cnt) { unsigned char val; __get_user(val, buf); pci_user_write_config_byte(dev, pos, val); buf++; pos++; cnt--; } if ((pos & 3) && cnt > 2) { __le16 val; __get_user(val, (__le16 __user *) buf); pci_user_write_config_word(dev, pos, le16_to_cpu(val)); buf += 2; pos += 2; cnt -= 2; } while (cnt >= 4) { __le32 val; __get_user(val, (__le32 __user *) buf); pci_user_write_config_dword(dev, pos, le32_to_cpu(val)); buf += 4; pos += 4; cnt -= 4; } if (cnt >= 2) { __le16 val; __get_user(val, (__le16 __user *) buf); pci_user_write_config_word(dev, pos, le16_to_cpu(val)); buf += 2; pos += 2; cnt -= 2; } if (cnt) { unsigned char val; __get_user(val, buf); pci_user_write_config_byte(dev, pos, val); buf++; pos++; cnt--; } pci_config_pm_runtime_put(dev); *ppos = pos; i_size_write(ino, dev->cfg_size); return nbytes; }