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, cfg_ret; 27 28 err = -EPERM; 29 if (!capable(CAP_SYS_ADMIN)) 30 goto error; 31 32 err = -ENODEV; 33 dev = pci_find_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 return err; 71 72 error: 73 /* ??? XFree86 doesn't even check the return value. They 74 just look for 0xffffffff in the output, since that's what 75 they get instead of a machine check on x86. */ 76 switch (len) { 77 case 1: 78 put_user(-1, (unsigned char __user *)buf); 79 break; 80 case 2: 81 put_user(-1, (unsigned short __user *)buf); 82 break; 83 case 4: 84 put_user(-1, (unsigned int __user *)buf); 85 break; 86 }; 87 return err; 88 } 89 90 asmlinkage long 91 sys_pciconfig_write(unsigned long bus, unsigned long dfn, 92 unsigned long off, unsigned long len, 93 void __user *buf) 94 { 95 struct pci_dev *dev; 96 u8 byte; 97 u16 word; 98 u32 dword; 99 int err = 0; 100 101 if (!capable(CAP_SYS_ADMIN)) 102 return -EPERM; 103 104 dev = pci_find_slot(bus, dfn); 105 if (!dev) 106 return -ENODEV; 107 108 lock_kernel(); 109 switch(len) { 110 case 1: 111 err = get_user(byte, (u8 __user *)buf); 112 if (err) 113 break; 114 err = pci_user_write_config_byte(dev, off, byte); 115 if (err != PCIBIOS_SUCCESSFUL) 116 err = -EIO; 117 break; 118 119 case 2: 120 err = get_user(word, (u16 __user *)buf); 121 if (err) 122 break; 123 err = pci_user_write_config_word(dev, off, word); 124 if (err != PCIBIOS_SUCCESSFUL) 125 err = -EIO; 126 break; 127 128 case 4: 129 err = get_user(dword, (u32 __user *)buf); 130 if (err) 131 break; 132 err = pci_user_write_config_dword(dev, off, dword); 133 if (err != PCIBIOS_SUCCESSFUL) 134 err = -EIO; 135 break; 136 137 default: 138 err = -EINVAL; 139 break; 140 }; 141 unlock_kernel(); 142 143 return err; 144 } 145