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);