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

Archive Download this file



interactive