Merge branch 'parisc' from /home/kyle/repos/parisc-2.6.git
[linux-2.6] / 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/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 #include "pci.h"
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_user_read_config_byte(dev, off, &byte);
42                 break;
43         case 2:
44                 cfg_ret = pci_user_read_config_word(dev, off, &word);
45                 break;
46         case 4:
47                 cfg_ret = pci_user_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_user_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_user_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_user_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 }