Mercurial > mplayer.hg
comparison libdha/kernelhelper/dhahelper.c @ 4470:2d28c737ed13
initial
author | alex |
---|---|
date | Sat, 02 Feb 2002 06:28:49 +0000 |
parents | |
children | 423ce4451ca8 |
comparison
equal
deleted
inserted
replaced
4469:ac00b30ac80f | 4470:2d28c737ed13 |
---|---|
1 /* | |
2 Direct Hardware Access kernel helper | |
3 | |
4 (C) 2002 Alex Beregszaszi <alex@naxine.org> | |
5 | |
6 Accessing hardware from userspace as USER (no root needed!) | |
7 | |
8 WARNING! | |
9 Don't use this on a production system! Use only at home, on a | |
10 "single-user" Unix system. | |
11 | |
12 Tech: | |
13 Communication between userspace and kernelspace is going trought | |
14 character device using ioctl. | |
15 | |
16 Usage: | |
17 mknod -m 666 /dev/dhahelper c 180 0 | |
18 | |
19 Also you can change the major number, setting the "dhahelper_major" | |
20 module parameter, the default is 180, specified in dhahelper.h. | |
21 | |
22 Note: do not use other than minor==0, the module forbids it. | |
23 | |
24 TODO: | |
25 * do memory mappin without fops:mmap | |
26 * implement unmap memory | |
27 * select (request?) a "valid" major number | |
28 * make security | |
29 * is pci handling needed? (libdha does this with lowlevel port funcs) | |
30 * test on older kernels (2.0.x (?) and 2.2.x) | |
31 */ | |
32 | |
33 #ifndef MODULE | |
34 #define MODULE | |
35 #endif | |
36 | |
37 #ifndef __KERNEL__ | |
38 #define __KERNEL__ | |
39 #endif | |
40 | |
41 #include <linux/config.h> | |
42 #include <linux/version.h> | |
43 #include <linux/module.h> | |
44 #include <linux/types.h> | |
45 #include <linux/kernel.h> | |
46 #include <linux/sched.h> | |
47 #include <linux/mm.h> | |
48 #include <linux/string.h> | |
49 #include <linux/errno.h> | |
50 | |
51 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) | |
52 #include <linux/malloc.h> | |
53 #else | |
54 #include <linux/slab.h> | |
55 #endif | |
56 | |
57 #include <linux/pci.h> | |
58 #include <linux/ioport.h> | |
59 #include <linux/init.h> | |
60 | |
61 #include <asm/uaccess.h> | |
62 #include <asm/system.h> | |
63 #include <asm/io.h> | |
64 | |
65 #include <linux/mman.h> | |
66 | |
67 #include <linux/fs.h> | |
68 #include <linux/unistd.h> | |
69 | |
70 #include "dhahelper.h" | |
71 | |
72 MODULE_AUTHOR("Alex Beregszaszi <alex@naxine.org>"); | |
73 #ifdef MODULE_LICENSE | |
74 MODULE_LICENSE("GPL"); /* modulelicensesh*t */ | |
75 #endif | |
76 | |
77 static int dhahelper_major = DEFAULT_MAJOR; | |
78 MODULE_PARM(dhahelper_major, "i"); | |
79 | |
80 /* 0 = silent */ | |
81 /* 1 = report errors (default) */ | |
82 /* 2 = debug */ | |
83 static int dhahelper_verbosity = 1; | |
84 MODULE_PARM(dhahelper_verbosity, "i"); | |
85 | |
86 static dhahelper_memory_t last_mem_request; | |
87 | |
88 | |
89 static int dhahelper_open(struct inode *inode, struct file *file) | |
90 { | |
91 if (dhahelper_verbosity > 1) | |
92 printk(KERN_DEBUG "dhahelper: device opened\n"); | |
93 | |
94 if (MINOR(inode->i_rdev) != 0) | |
95 return(-ENXIO); | |
96 | |
97 MOD_INC_USE_COUNT; | |
98 | |
99 return(0); | |
100 } | |
101 | |
102 static int dhahelper_release(struct inode *inode, struct file *file) | |
103 { | |
104 if (dhahelper_verbosity > 1) | |
105 printk(KERN_DEBUG "dhahelper: device released\n"); | |
106 | |
107 if (MINOR(inode->i_rdev) != 0) | |
108 return(-ENXIO); | |
109 | |
110 MOD_DEC_USE_COUNT; | |
111 | |
112 return(0); | |
113 } | |
114 | |
115 static int dhahelper_ioctl(struct inode *inode, struct file *file, | |
116 unsigned int cmd, unsigned long arg) | |
117 { | |
118 if (dhahelper_verbosity > 1) | |
119 printk(KERN_DEBUG "dhahelper: ioctl(cmd=%x, arg=%lx)\n", | |
120 cmd, arg); | |
121 | |
122 if (MINOR(inode->i_rdev) != 0) | |
123 return(-ENXIO); | |
124 | |
125 switch(cmd) | |
126 { | |
127 case DHAHELPER_GET_VERSION: | |
128 { | |
129 int version = API_VERSION; | |
130 | |
131 if (copy_to_user((int *)arg, &version, sizeof(int))) | |
132 { | |
133 if (dhahelper_verbosity > 0) | |
134 printk(KERN_ERR "dhahelper: failed copy to userspace\n"); | |
135 return(-EFAULT); | |
136 } | |
137 | |
138 break; | |
139 } | |
140 case DHAHELPER_PORT: | |
141 { | |
142 dhahelper_port_t port; | |
143 | |
144 if (copy_from_user(&port, (dhahelper_port_t *)arg, sizeof(dhahelper_port_t))) | |
145 { | |
146 if (dhahelper_verbosity > 0) | |
147 printk(KERN_ERR "dhahelper: failed copy from userspace\n"); | |
148 return(-EFAULT); | |
149 } | |
150 | |
151 switch(port.operation) | |
152 { | |
153 case PORT_OP_READ: | |
154 { | |
155 switch(port.size) | |
156 { | |
157 case 1: | |
158 port.value = inb(port.addr); | |
159 break; | |
160 case 2: | |
161 port.value = inw(port.addr); | |
162 break; | |
163 case 4: | |
164 port.value = inl(port.addr); | |
165 break; | |
166 default: | |
167 if (dhahelper_verbosity > 0) | |
168 printk(KERN_ERR "dhahelper: invalid port read size (%d)\n", | |
169 port.size); | |
170 return(-EINVAL); | |
171 } | |
172 break; | |
173 } | |
174 case PORT_OP_WRITE: | |
175 { | |
176 switch(port.size) | |
177 { | |
178 case 1: | |
179 outb(port.value, port.addr); | |
180 break; | |
181 case 2: | |
182 outw(port.value, port.addr); | |
183 break; | |
184 case 4: | |
185 outl(port.value, port.addr); | |
186 break; | |
187 default: | |
188 if (dhahelper_verbosity > 0) | |
189 printk(KERN_ERR "dhahelper: invalid port write size (%d)\n", | |
190 port.size); | |
191 return(-EINVAL); | |
192 } | |
193 break; | |
194 } | |
195 default: | |
196 if (dhahelper_verbosity > 0) | |
197 printk(KERN_ERR "dhahelper: invalid port operation (%d)\n", | |
198 port.operation); | |
199 return(-EINVAL); | |
200 } | |
201 | |
202 /* copy back only if read was performed */ | |
203 if (port.operation == PORT_OP_READ) | |
204 if (copy_to_user((dhahelper_port_t *)arg, &port, sizeof(dhahelper_port_t))) | |
205 { | |
206 if (dhahelper_verbosity > 0) | |
207 printk(KERN_ERR "dhahelper: failed copy to userspace\n"); | |
208 return(-EFAULT); | |
209 } | |
210 | |
211 break; | |
212 } | |
213 case DHAHELPER_MEMORY: | |
214 { | |
215 dhahelper_memory_t mem; | |
216 | |
217 if (copy_from_user(&mem, (dhahelper_memory_t *)arg, sizeof(dhahelper_memory_t))) | |
218 { | |
219 if (dhahelper_verbosity > 0) | |
220 printk(KERN_ERR "dhahelper: failed copy from userspace\n"); | |
221 return(-EFAULT); | |
222 } | |
223 | |
224 switch(mem.operation) | |
225 { | |
226 case MEMORY_OP_MAP: | |
227 { | |
228 memcpy(&last_mem_request, &mem, sizeof(dhahelper_memory_t)); | |
229 | |
230 break; | |
231 } | |
232 case MEMORY_OP_UNMAP: | |
233 break; | |
234 default: | |
235 if (dhahelper_verbosity > 0) | |
236 printk(KERN_ERR "dhahelper: invalid memory operation (%d)\n", | |
237 mem.operation); | |
238 return(-EINVAL); | |
239 } | |
240 | |
241 if (copy_to_user((dhahelper_memory_t *)arg, &mem, sizeof(dhahelper_memory_t))) | |
242 { | |
243 if (dhahelper_verbosity > 0) | |
244 printk(KERN_ERR "dhahelper: failed copy to userspace\n"); | |
245 return(-EFAULT); | |
246 } | |
247 | |
248 break; | |
249 } | |
250 default: | |
251 if (dhahelper_verbosity > 0) | |
252 printk(KERN_ERR "dhahelper: invalid ioctl (%x)\n", cmd); | |
253 return(-EINVAL); | |
254 } | |
255 | |
256 return(0); | |
257 } | |
258 | |
259 static int dhahelper_mmap(struct file *file, struct vm_area_struct *vma) | |
260 { | |
261 if (last_mem_request.operation != MEMORY_OP_MAP) | |
262 { | |
263 if (dhahelper_verbosity > 0) | |
264 printk(KERN_ERR "dhahelper: mapping not requested before mmap\n"); | |
265 return(-EFAULT); | |
266 } | |
267 | |
268 if (dhahelper_verbosity > 1) | |
269 printk(KERN_INFO "dhahelper: mapping %x (size: %x)\n", | |
270 last_mem_request.start+last_mem_request.offset, last_mem_request.size); | |
271 | |
272 if (remap_page_range(0, last_mem_request.start + last_mem_request.offset, | |
273 last_mem_request.size, vma->vm_page_prot)) | |
274 { | |
275 if (dhahelper_verbosity > 0) | |
276 printk(KERN_ERR "dhahelper: error mapping memory\n"); | |
277 return(-EFAULT); | |
278 } | |
279 | |
280 return(0); | |
281 } | |
282 | |
283 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) | |
284 static struct file_operations dhahelper_fops = | |
285 { | |
286 /*llseek*/ NULL, | |
287 /*read*/ NULL, | |
288 /*write*/ NULL, | |
289 /*readdir*/ NULL, | |
290 /*poll*/ NULL, | |
291 /*ioctl*/ dhahelper_ioctl, | |
292 /*mmap*/ dhahelper_mmap, | |
293 /*open*/ dhahelper_open, | |
294 /*flush*/ NULL, | |
295 /*release*/ dhahelper_release, | |
296 /* zero out the last 5 entries too ? */ | |
297 }; | |
298 #else | |
299 static struct file_operations dhahelper_fops = | |
300 { | |
301 owner: THIS_MODULE, | |
302 ioctl: dhahelper_ioctl, | |
303 mmap: dhahelper_mmap, | |
304 open: dhahelper_open, | |
305 release: dhahelper_release | |
306 }; | |
307 #endif | |
308 | |
309 static int __init init_dhahelper(void) | |
310 { | |
311 printk(KERN_INFO "Direct Hardware Access kernel helper (C) Alex Beregszaszi\n"); | |
312 | |
313 if(register_chrdev(dhahelper_major, "dhahelper", &dhahelper_fops)) | |
314 { | |
315 if (dhahelper_verbosity > 0) | |
316 printk(KERN_ERR "dhahelper: unable to register character device (major: %d)\n", | |
317 dhahelper_major); | |
318 return(-EIO); | |
319 } | |
320 | |
321 return(0); | |
322 } | |
323 | |
324 static void __exit exit_dhahelper(void) | |
325 { | |
326 unregister_chrdev(dhahelper_major, "dhahelper"); | |
327 } | |
328 | |
329 EXPORT_NO_SYMBOLS; | |
330 | |
331 module_init(init_dhahelper); | |
332 module_exit(exit_dhahelper); |