1 /* 2 * pci_syscall.c 3 * 4 * For architectures where we want to allow direct access 5 * to the PCI config stuff - it would probably be preferable 6 * on PCs too, but there people just do it by hand with the 7 * magic northbridge registers.. 8 */ 9 10 #include <linux/errno.h> 11 #include <linux/pci.h> 12 #include <linux/smp_lock.h> 13 #include <linux/syscalls.h> 14 #include <asm/uaccess.h> 15 #include "pci.h" 16 17 asmlinkage long 18 sys_pciconfig_read(unsigned long bus, unsigned long dfn, 19 unsigned long off, unsigned long len, 20 void __user *buf) 21 { 22 struct pci_dev *dev; 23 u8 byte; 24 u16 word; 25 u32 dword; 26 long err; 27 long cfg_ret; 28 29 if (!capable(CAP_SYS_ADMIN)) 30 return -EPERM; 31 32 err = -ENODEV; 33 dev = pci_get_bus_and_slot(bus, dfn); 34 if (!dev) 35 goto error; 36 37 lock_kernel(); 38 switch (len) { 39 case 1: 40 cfg_ret = pci_user_read_config_byte(dev, off, &byte); 41 break; 42 case 2: 43 cfg_ret = pci_user_read_config_word(dev, off, &word); 44 break; 45 case 4: 46 cfg_ret = pci_user_read_config_dword(dev, off, &dword); 47 break; 48 default: 49 err = -EINVAL; 50 unlock_kernel(); 51 goto error; 52 }; 53 unlock_kernel(); 54 55 err = -EIO; 56 if (cfg_ret != PCIBIOS_SUCCESSFUL) 57 goto error; 58 59 switch (len) { 60 case 1: 61 err = put_user(byte, (unsigned char __user *)buf); 62 break; 63 case 2: 64 err = put_user(word, (unsigned short __user *)buf); 65 break; 66 case 4: 67 err = put_user(dword, (unsigned int __user *)buf); 68 break; 69 } 70 pci_dev_put(dev); 71 return err; 72 73 error: 74 /* ??? XFree86 doesn't even check the return value. They 75 just look for 0xffffffff in the output, since that's what 76 they get instead of a machine check on x86. */ 77 switch (len) { 78 case 1: 79 put_user(-1, (unsigned char __user *)buf); 80 break; 81 case 2: 82 put_user(-1, (unsigned short __user *)buf); 83 break; 84 case 4: 85 put_user(-1, (unsigned int __user *)buf); 86 break; 87 } 88 pci_dev_put(dev); 89 return err; 90 } 91 92 asmlinkage long 93 sys_pciconfig_write(unsigned long bus, unsigned long dfn, 94 unsigned long off, unsigned long len, 95 void __user *buf) 96 { 97 struct pci_dev *dev; 98 u8 byte; 99 u16 word; 100 u32 dword; 101 int err = 0; 102 103 if (!capable(CAP_SYS_ADMIN)) 104 return -EPERM; 105 106 dev = pci_get_bus_and_slot(bus, dfn); 107 if (!dev) 108 return -ENODEV; 109 110 lock_kernel(); 111 switch(len) { 112 case 1: 113 err = get_user(byte, (u8 __user *)buf); 114 if (err) 115 break; 116 err = pci_user_write_config_byte(dev, off, byte); 117 if (err != PCIBIOS_SUCCESSFUL) 118 err = -EIO; 119 break; 120 121 case 2: 122 err = get_user(word, (u16 __user *)buf); 123 if (err) 124 break; 125 err = pci_user_write_config_word(dev, off, word); 126 if (err != PCIBIOS_SUCCESSFUL) 127 err = -EIO; 128 break; 129 130 case 4: 131 err = get_user(dword, (u32 __user *)buf); 132 if (err) 133 break; 134 err = pci_user_write_config_dword(dev, off, dword); 135 if (err != PCIBIOS_SUCCESSFUL) 136 err = -EIO; 137 break; 138 139 default: 140 err = -EINVAL; 141 break; 142 } 143 unlock_kernel(); 144 pci_dev_put(dev); 145 return err; 146 } 147