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