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