File: /usr/src/linux/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 <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     	if (!pcibios_present())
102     		return -ENOSYS;
103     
104     	dev = pci_find_slot(bus, dfn);
105     	if (!dev)
106     		return -ENODEV;
107     
108     	lock_kernel();
109     	switch(len) {
110     	case 1:
111     		err = get_user(byte, (u8 *)buf);
112     		if (err)
113     			break;
114     		err = pci_write_config_byte(dev, off, byte);
115     		if (err != PCIBIOS_SUCCESSFUL)
116     			err = -EIO;
117     		break;
118     
119     	case 2:
120     		err = get_user(word, (u16 *)buf);
121     		if (err)
122     			break;
123     		err = pci_write_config_word(dev, off, word);
124     		if (err != PCIBIOS_SUCCESSFUL)
125     			err = -EIO;
126     		break;
127     
128     	case 4:
129     		err = get_user(dword, (u32 *)buf);
130     		if (err)
131     			break;
132     		err = pci_write_config_dword(dev, off, dword);
133     		if (err != PCIBIOS_SUCCESSFUL)
134     			err = -EIO;
135     		break;
136     
137     	default:
138     		err = -EINVAL;
139     		break;
140     	};
141     	unlock_kernel();
142     
143     	return err;
144     }
145