2 * Direct Hardware Access (DHA) kernel helper
4 * Copyright (C) 2002 Alex Beregszaszi <alex@fsn.hu>
6 * This file is part of MPlayer.
8 * MPlayer is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * MPlayer is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 Accessing hardware from userspace as USER (no root needed!)
26 Tested on 2.2.x (2.2.19) and 2.4.x (2.4.3,2.4.17).
28 WARNING! THIS MODULE VIOLATES SEVERAL SECURITY LINES! DON'T USE IT
29 ON PRODUCTION SYSTEMS, ONLY AT HOME, ON A "SINGLE-USER" SYSTEM.
33 Communication between userspace and kernelspace goes over character
37 mknod -m 666 /dev/dhahelper c 180 0
39 Also you can change the major number, setting the "dhahelper_major"
40 module parameter, the default is 180, specified in dhahelper.h.
42 Note: do not use other than minor==0, the module forbids it.
45 * do memory mapping without fops:mmap
46 * implement unmap memory
47 * select (request?) a "valid" major number (from Linux project? ;)
49 * is pci handling needed? (libdha does this with lowlevel port funcs)
50 * is mttr handling needed?
51 * test on older kernels (2.0.x (?))
62 #include <linux/config.h>
64 #ifdef CONFIG_MODVERSION
66 #include <linux/modversions.h>
69 #include <linux/version.h>
70 #include <linux/module.h>
71 #include <linux/types.h>
72 #include <linux/kernel.h>
73 #include <linux/sched.h>
75 #include <linux/string.h>
76 #include <linux/errno.h>
78 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
79 #include <linux/malloc.h>
81 #include <linux/slab.h>
84 #include <linux/pci.h>
85 #include <linux/ioport.h>
86 #include <linux/init.h>
88 #include <asm/uaccess.h>
89 #include <asm/system.h>
92 #include <linux/mman.h>
95 #include <linux/unistd.h>
97 #include "dhahelper.h"
99 MODULE_AUTHOR("Alex Beregszaszi <alex@fsn.hu>");
100 MODULE_DESCRIPTION("Provides userspace access to hardware (security violation!)");
101 #ifdef MODULE_LICENSE
102 MODULE_LICENSE("GPL");
105 static int dhahelper_major
= DEFAULT_MAJOR
;
106 MODULE_PARM(dhahelper_major
, "i");
107 MODULE_PARM_DESC(dhahelper_major
, "Major number of dhahelper characterdevice");
110 /* 1 = report errors (default) */
112 static int dhahelper_verbosity
= 1;
113 MODULE_PARM(dhahelper_verbosity
, "i");
114 MODULE_PARM_DESC(dhahelper_verbosity
, "Level of verbosity (0 = silent, 1 = only errors, 2 = debug)");
116 static dhahelper_memory_t last_mem_request
;
119 static int dhahelper_open(struct inode
*inode
, struct file
*file
)
121 if (dhahelper_verbosity
> 1)
122 printk(KERN_DEBUG
"dhahelper: device opened\n");
124 if (MINOR(inode
->i_rdev
) != 0)
132 static int dhahelper_release(struct inode
*inode
, struct file
*file
)
134 if (dhahelper_verbosity
> 1)
135 printk(KERN_DEBUG
"dhahelper: device released\n");
137 if (MINOR(inode
->i_rdev
) != 0)
145 static int dhahelper_ioctl(struct inode
*inode
, struct file
*file
,
146 unsigned int cmd
, unsigned long arg
)
148 if (dhahelper_verbosity
> 1)
149 printk(KERN_DEBUG
"dhahelper: ioctl(cmd=%x, arg=%lx)\n",
152 if (MINOR(inode
->i_rdev
) != 0)
157 case DHAHELPER_GET_VERSION
:
159 int version
= API_VERSION
;
161 if (copy_to_user((int *)arg
, &version
, sizeof(int)))
163 if (dhahelper_verbosity
> 0)
164 printk(KERN_ERR
"dhahelper: failed copy to userspace\n");
172 dhahelper_port_t port
;
174 if (copy_from_user(&port
, (dhahelper_port_t
*)arg
, sizeof(dhahelper_port_t
)))
176 if (dhahelper_verbosity
> 0)
177 printk(KERN_ERR
"dhahelper: failed copy from userspace\n");
181 switch(port
.operation
)
188 port
.value
= inb(port
.addr
);
191 port
.value
= inw(port
.addr
);
194 port
.value
= inl(port
.addr
);
197 if (dhahelper_verbosity
> 0)
198 printk(KERN_ERR
"dhahelper: invalid port read size (%d)\n",
209 outb(port
.value
, port
.addr
);
212 outw(port
.value
, port
.addr
);
215 outl(port
.value
, port
.addr
);
218 if (dhahelper_verbosity
> 0)
219 printk(KERN_ERR
"dhahelper: invalid port write size (%d)\n",
226 if (dhahelper_verbosity
> 0)
227 printk(KERN_ERR
"dhahelper: invalid port operation (%d)\n",
232 /* copy back only if read was performed */
233 if (port
.operation
== PORT_OP_READ
)
234 if (copy_to_user((dhahelper_port_t
*)arg
, &port
, sizeof(dhahelper_port_t
)))
236 if (dhahelper_verbosity
> 0)
237 printk(KERN_ERR
"dhahelper: failed copy to userspace\n");
243 case DHAHELPER_MEMORY
:
245 dhahelper_memory_t mem
;
247 if (copy_from_user(&mem
, (dhahelper_memory_t
*)arg
, sizeof(dhahelper_memory_t
)))
249 if (dhahelper_verbosity
> 0)
250 printk(KERN_ERR
"dhahelper: failed copy from userspace\n");
254 switch(mem
.operation
)
259 memcpy(&last_mem_request
, &mem
, sizeof(dhahelper_memory_t
));
261 mem
.ret
= do_mmap(file
, mem
.start
, mem
.size
, PROT_READ
|PROT_WRITE
,
262 MAP_SHARED
, mem
.offset
);
267 case MEMORY_OP_UNMAP
:
270 if (dhahelper_verbosity
> 0)
271 printk(KERN_ERR
"dhahelper: invalid memory operation (%d)\n",
276 if (copy_to_user((dhahelper_memory_t
*)arg
, &mem
, sizeof(dhahelper_memory_t
)))
278 if (dhahelper_verbosity
> 0)
279 printk(KERN_ERR
"dhahelper: failed copy to userspace\n");
286 if (dhahelper_verbosity
> 0)
287 printk(KERN_ERR
"dhahelper: invalid ioctl (%x)\n", cmd
);
294 static int dhahelper_mmap(struct file
*file
, struct vm_area_struct
*vma
)
296 if (last_mem_request
.operation
!= MEMORY_OP_MAP
)
298 if (dhahelper_verbosity
> 0)
299 printk(KERN_ERR
"dhahelper: mapping not requested before mmap\n");
303 if (dhahelper_verbosity
> 1)
304 printk(KERN_INFO
"dhahelper: mapping %x (size: %x)\n",
305 last_mem_request
.start
+last_mem_request
.offset
, last_mem_request
.size
);
307 if (remap_page_range(0, last_mem_request
.start
+ last_mem_request
.offset
,
308 last_mem_request
.size
, vma
->vm_page_prot
))
310 if (dhahelper_verbosity
> 0)
311 printk(KERN_ERR
"dhahelper: error mapping memory\n");
318 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
319 static struct file_operations dhahelper_fops
=
326 /*ioctl*/ dhahelper_ioctl
,
327 /*mmap*/ dhahelper_mmap
,
328 /*open*/ dhahelper_open
,
330 /*release*/ dhahelper_release
,
331 /* zero out the last 5 entries too ? */
334 static struct file_operations dhahelper_fops
=
337 ioctl
: dhahelper_ioctl
,
338 mmap
: dhahelper_mmap
,
339 open
: dhahelper_open
,
340 release
: dhahelper_release
344 #if KERNEL_VERSION < KERNEL_VERSION(2,4,0)
345 int init_module(void)
347 static int __init
init_dhahelper(void)
350 printk(KERN_INFO
"Direct Hardware Access kernel helper (C) Alex Beregszaszi\n");
352 if(register_chrdev(dhahelper_major
, "dhahelper", &dhahelper_fops
))
354 if (dhahelper_verbosity
> 0)
355 printk(KERN_ERR
"dhahelper: unable to register character device (major: %d)\n",
363 #if KERNEL_VERSION < KERNEL_VERSION(2,4,0)
364 void cleanup_module(void)
366 static void __exit
exit_dhahelper(void)
369 unregister_chrdev(dhahelper_major
, "dhahelper");
374 #if KERNEL_VERSION >= KERNEL_VERSION(2,4,0)
375 module_init(init_dhahelper
);
376 module_exit(exit_dhahelper
);