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