GNU Linux-libre 4.9.337-gnu1
[releases.git] / drivers / pci / syscall.c
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/syscalls.h>
13 #include <asm/uaccess.h>
14 #include "pci.h"
15
16 SYSCALL_DEFINE5(pciconfig_read, unsigned long, bus, unsigned long, dfn,
17                 unsigned long, off, unsigned long, len, void __user *, buf)
18 {
19         struct pci_dev *dev;
20         u8 byte;
21         u16 word;
22         u32 dword;
23         long err;
24         int cfg_ret;
25
26         err = -EPERM;
27         dev = NULL;
28         if (!capable(CAP_SYS_ADMIN))
29                 goto error;
30
31         err = -ENODEV;
32         dev = pci_get_bus_and_slot(bus, dfn);
33         if (!dev)
34                 goto error;
35
36         switch (len) {
37         case 1:
38                 cfg_ret = pci_user_read_config_byte(dev, off, &byte);
39                 break;
40         case 2:
41                 cfg_ret = pci_user_read_config_word(dev, off, &word);
42                 break;
43         case 4:
44                 cfg_ret = pci_user_read_config_dword(dev, off, &dword);
45                 break;
46         default:
47                 err = -EINVAL;
48                 goto error;
49         }
50
51         err = -EIO;
52         if (cfg_ret)
53                 goto error;
54
55         switch (len) {
56         case 1:
57                 err = put_user(byte, (unsigned char __user *)buf);
58                 break;
59         case 2:
60                 err = put_user(word, (unsigned short __user *)buf);
61                 break;
62         case 4:
63                 err = put_user(dword, (unsigned int __user *)buf);
64                 break;
65         }
66         pci_dev_put(dev);
67         return err;
68
69 error:
70         /* ??? XFree86 doesn't even check the return value.  They
71            just look for 0xffffffff in the output, since that's what
72            they get instead of a machine check on x86.  */
73         switch (len) {
74         case 1:
75                 put_user(-1, (unsigned char __user *)buf);
76                 break;
77         case 2:
78                 put_user(-1, (unsigned short __user *)buf);
79                 break;
80         case 4:
81                 put_user(-1, (unsigned int __user *)buf);
82                 break;
83         }
84         pci_dev_put(dev);
85         return err;
86 }
87
88 SYSCALL_DEFINE5(pciconfig_write, unsigned long, bus, unsigned long, dfn,
89                 unsigned long, off, unsigned long, len, void __user *, buf)
90 {
91         struct pci_dev *dev;
92         u8 byte;
93         u16 word;
94         u32 dword;
95         int err = 0;
96
97         if (!capable(CAP_SYS_ADMIN))
98                 return -EPERM;
99
100         dev = pci_get_bus_and_slot(bus, dfn);
101         if (!dev)
102                 return -ENODEV;
103
104         switch (len) {
105         case 1:
106                 err = get_user(byte, (u8 __user *)buf);
107                 if (err)
108                         break;
109                 err = pci_user_write_config_byte(dev, off, byte);
110                 if (err)
111                         err = -EIO;
112                 break;
113
114         case 2:
115                 err = get_user(word, (u16 __user *)buf);
116                 if (err)
117                         break;
118                 err = pci_user_write_config_word(dev, off, word);
119                 if (err)
120                         err = -EIO;
121                 break;
122
123         case 4:
124                 err = get_user(dword, (u32 __user *)buf);
125                 if (err)
126                         break;
127                 err = pci_user_write_config_dword(dev, off, dword);
128                 if (err)
129                         err = -EIO;
130                 break;
131
132         default:
133                 err = -EINVAL;
134                 break;
135         }
136         pci_dev_put(dev);
137         return err;
138 }