Subversion Repositories shark

Rev

Details | Last modification | View Log | RSS feed

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