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/sched.h> 11 #include <linux/errno.h> 12 #include <linux/pci.h> 13 #include <linux/smp_lock.h> 14 #include <linux/syscalls.h> 15 #include <asm/uaccess.h> 16 17 18 asmlinkage long 19 sys_pciconfig_read(unsigned long bus, unsigned long dfn, 20 unsigned long off, unsigned long len, 21 void __user *buf) 22 { 23 struct pci_dev *dev; 24 u8 byte; 25 u16 word; 26 u32 dword; 27 long err, cfg_ret; 28 29 err = -EPERM; 30 if (!capable(CAP_SYS_ADMIN)) 31 goto error; 32 33 err = -ENODEV; 34 dev = pci_find_slot(bus, dfn); 35 if (!dev) 36 goto error; 37 38 lock_kernel(); 39 switch (len) { 40 case 1: 41 cfg_ret = pci_read_config_byte(dev, off, &byte); 42 break; 43 case 2: 44 cfg_ret = pci_read_config_word(dev, off, &word); 45 break; 46 case 4: 47 cfg_ret = pci_read_config_dword(dev, off, &dword); 48 break; 49 default: 50 err = -EINVAL; 51 unlock_kernel(); 52 goto error; 53 }; 54 unlock_kernel(); 55 56 err = -EIO; 57 if (cfg_ret != PCIBIOS_SUCCESSFUL) 58 goto error; 59 60 switch (len) { 61 case 1: 62 err = put_user(byte, (unsigned char __user *)buf); 63 break; 64 case 2: 65 err = put_user(word, (unsigned short __user *)buf); 66 break; 67 case 4: 68 err = put_user(dword, (unsigned int __user *)buf); 69 break; 70 }; 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 return err; 89 } 90 91 asmlinkage long 92 sys_pciconfig_write(unsigned long bus, unsigned long dfn, 93 unsigned long off, unsigned long len, 94 void __user *buf) 95 { 96 struct pci_dev *dev; 97 u8 byte; 98 u16 word; 99 u32 dword; 100 int err = 0; 101 102 if (!capable(CAP_SYS_ADMIN)) 103 return -EPERM; 104 105 dev = pci_find_slot(bus, dfn); 106 if (!dev) 107 return -ENODEV; 108 109 lock_kernel(); 110 switch(len) { 111 case 1: 112 err = get_user(byte, (u8 __user *)buf); 113 if (err) 114 break; 115 err = pci_write_config_byte(dev, off, byte); 116 if (err != PCIBIOS_SUCCESSFUL) 117 err = -EIO; 118 break; 119 120 case 2: 121 err = get_user(word, (u16 __user *)buf); 122 if (err) 123 break; 124 err = pci_write_config_word(dev, off, word); 125 if (err != PCIBIOS_SUCCESSFUL) 126 err = -EIO; 127 break; 128 129 case 4: 130 err = get_user(dword, (u32 __user *)buf); 131 if (err) 132 break; 133 err = pci_write_config_dword(dev, off, dword); 134 if (err != PCIBIOS_SUCCESSFUL) 135 err = -EIO; 136 break; 137 138 default: 139 err = -EINVAL; 140 break; 141 }; 142 unlock_kernel(); 143 144 return err; 145 } 146