2 * Direct Hardware Access (DHA) kernel helper
4 * Copyright (C) 2002 Alex Beregszaszi <alex@fsn.hu>
5 * This file is part of MPlayer.
7 * MPlayer is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * MPlayer is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 Accessing hardware from userspace as USER (no root needed!)
25 Tested on 2.2.x (2.2.19) and 2.4.x (2.4.3,2.4.17).
27 WARNING! THIS MODULE VIOLATES SEVERAL SECURITY LINES! DON'T USE IT
28 ON PRODUCTION SYSTEMS, ONLY AT HOME, ON A "SINGLE-USER" SYSTEM.
32 Communication between userspace and kernelspace goes over character
36 mknod -m 666 /dev/dhahelper c 180 0
38 Also you can change the major number, setting the "dhahelper_major"
39 module parameter, the default is 180, specified in dhahelper.h.
41 Note: do not use other than minor==0, the module forbids it.
44 * do memory mapping without fops:mmap
45 * implement unmap memory
46 * select (request?) a "valid" major number (from Linux project? ;)
48 * is pci handling needed? (libdha does this with lowlevel port funcs)
49 * is mttr handling needed?
50 * test on older kernels (2.0.x (?))
61 #include <linux/config.h>
63 #ifdef CONFIG_MODVERSION
65 #include <linux/modversions.h>
68 #include <linux/version.h>
69 #include <linux/module.h>
70 #include <linux/types.h>
71 #include <linux/kernel.h>
72 #include <linux/sched.h>
74 #include <linux/string.h>
75 #include <linux/errno.h>
77 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
78 #include <linux/malloc.h>
80 #include <linux/slab.h>
83 #include <linux/pci.h>
84 #include <linux/ioport.h>
85 #include <linux/init.h>
87 #include <asm/uaccess.h>
88 #include <asm/system.h>
91 #include <linux/mman.h>
94 #include <linux/unistd.h>
96 #include "dhahelper.h"
98 MODULE_AUTHOR("Alex Beregszaszi <alex@fsn.hu>");
99 MODULE_DESCRIPTION("Provides userspace access to hardware (security violation!)");
100 #ifdef MODULE_LICENSE
101 MODULE_LICENSE("GPL");
104 static int dhahelper_major
= DEFAULT_MAJOR
;
105 MODULE_PARM(dhahelper_major
, "i");
106 MODULE_PARM_DESC(dhahelper_major
, "Major number of dhahelper characterdevice");
109 /* 1 = report errors (default) */
111 static int dhahelper_verbosity
= 1;
112 MODULE_PARM(dhahelper_verbosity
, "i");
113 MODULE_PARM_DESC(dhahelper_verbosity
, "Level of verbosity (0 = silent, 1 = only errors, 2 = debug)");
115 static dhahelper_memory_t last_mem_request
;
118 static int dhahelper_open(struct inode
*inode
, struct file
*file
)
120 if (dhahelper_verbosity
> 1)
121 printk(KERN_DEBUG
"dhahelper: device opened\n");
123 if (MINOR(inode
->i_rdev
) != 0)
131 static int dhahelper_release(struct inode
*inode
, struct file
*file
)
133 if (dhahelper_verbosity
> 1)
134 printk(KERN_DEBUG
"dhahelper: device released\n");
136 if (MINOR(inode
->i_rdev
) != 0)
144 static int dhahelper_ioctl(struct inode
*inode
, struct file
*file
,
145 unsigned int cmd
, unsigned long arg
)
147 if (dhahelper_verbosity
> 1)
148 printk(KERN_DEBUG
"dhahelper: ioctl(cmd=%x, arg=%lx)\n",
151 if (MINOR(inode
->i_rdev
) != 0)
156 case DHAHELPER_GET_VERSION
:
158 int version
= API_VERSION
;
160 if (copy_to_user((int *)arg
, &version
, sizeof(int)))
162 if (dhahelper_verbosity
> 0)
163 printk(KERN_ERR
"dhahelper: failed copy to userspace\n");
171 dhahelper_port_t port
;
173 if (copy_from_user(&port
, (dhahelper_port_t
*)arg
, sizeof(dhahelper_port_t
)))
175 if (dhahelper_verbosity
> 0)
176 printk(KERN_ERR
"dhahelper: failed copy from userspace\n");
180 switch(port
.operation
)
187 port
.value
= inb(port
.addr
);
190 port
.value
= inw(port
.addr
);
193 port
.value
= inl(port
.addr
);
196 if (dhahelper_verbosity
> 0)
197 printk(KERN_ERR
"dhahelper: invalid port read size (%d)\n",
208 outb(port
.value
, port
.addr
);
211 outw(port
.value
, port
.addr
);
214 outl(port
.value
, port
.addr
);
217 if (dhahelper_verbosity
> 0)
218 printk(KERN_ERR
"dhahelper: invalid port write size (%d)\n",
225 if (dhahelper_verbosity
> 0)
226 printk(KERN_ERR
"dhahelper: invalid port operation (%d)\n",
231 /* copy back only if read was performed */
232 if (port
.operation
== PORT_OP_READ
)
233 if (copy_to_user((dhahelper_port_t
*)arg
, &port
, sizeof(dhahelper_port_t
)))
235 if (dhahelper_verbosity
> 0)
236 printk(KERN_ERR
"dhahelper: failed copy to userspace\n");
242 case DHAHELPER_MEMORY
:
244 dhahelper_memory_t mem
;
246 if (copy_from_user(&mem
, (dhahelper_memory_t
*)arg
, sizeof(dhahelper_memory_t
)))
248 if (dhahelper_verbosity
> 0)
249 printk(KERN_ERR
"dhahelper: failed copy from userspace\n");
253 switch(mem
.operation
)
258 memcpy(&last_mem_request
, &mem
, sizeof(dhahelper_memory_t
));
260 mem
.ret
= do_mmap(file
, mem
.start
, mem
.size
, PROT_READ
|PROT_WRITE
,
261 MAP_SHARED
, mem
.offset
);
266 case MEMORY_OP_UNMAP
:
269 if (dhahelper_verbosity
> 0)
270 printk(KERN_ERR
"dhahelper: invalid memory operation (%d)\n",
275 if (copy_to_user((dhahelper_memory_t
*)arg
, &mem
, sizeof(dhahelper_memory_t
)))
277 if (dhahelper_verbosity
> 0)
278 printk(KERN_ERR
"dhahelper: failed copy to userspace\n");
285 if (dhahelper_verbosity
> 0)
286 printk(KERN_ERR
"dhahelper: invalid ioctl (%x)\n", cmd
);
293 static int dhahelper_mmap(struct file
*file
, struct vm_area_struct
*vma
)
295 if (last_mem_request
.operation
!= MEMORY_OP_MAP
)
297 if (dhahelper_verbosity
> 0)
298 printk(KERN_ERR
"dhahelper: mapping not requested before mmap\n");
302 if (dhahelper_verbosity
> 1)
303 printk(KERN_INFO
"dhahelper: mapping %x (size: %x)\n",
304 last_mem_request
.start
+last_mem_request
.offset
, last_mem_request
.size
);
306 if (remap_page_range(0, last_mem_request
.start
+ last_mem_request
.offset
,
307 last_mem_request
.size
, vma
->vm_page_prot
))
309 if (dhahelper_verbosity
> 0)
310 printk(KERN_ERR
"dhahelper: error mapping memory\n");
317 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
318 static struct file_operations dhahelper_fops
=
325 /*ioctl*/ dhahelper_ioctl
,
326 /*mmap*/ dhahelper_mmap
,
327 /*open*/ dhahelper_open
,
329 /*release*/ dhahelper_release
,
330 /* zero out the last 5 entries too ? */
333 static struct file_operations dhahelper_fops
=
336 ioctl
: dhahelper_ioctl
,
337 mmap
: dhahelper_mmap
,
338 open
: dhahelper_open
,
339 release
: dhahelper_release
343 #if KERNEL_VERSION < KERNEL_VERSION(2,4,0)
344 int init_module(void)
346 static int __init
init_dhahelper(void)
349 printk(KERN_INFO
"Direct Hardware Access kernel helper (C) Alex Beregszaszi\n");
351 if(register_chrdev(dhahelper_major
, "dhahelper", &dhahelper_fops
))
353 if (dhahelper_verbosity
> 0)
354 printk(KERN_ERR
"dhahelper: unable to register character device (major: %d)\n",
362 #if KERNEL_VERSION < KERNEL_VERSION(2,4,0)
363 void cleanup_module(void)
365 static void __exit
exit_dhahelper(void)
368 unregister_chrdev(dhahelper_major
, "dhahelper");
373 #if KERNEL_VERSION >= KERNEL_VERSION(2,4,0)
374 module_init(init_dhahelper
);
375 module_exit(exit_dhahelper
);