]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/staging/comedi/kcomedilib/kcomedilib_main.c
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[mirror_ubuntu-artful-kernel.git] / drivers / staging / comedi / kcomedilib / kcomedilib_main.c
1 /*
2 kcomedilib/kcomedilib.c
3 a comedlib interface for kernel modules
4
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
7
8 This program 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.
12
13 This program 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.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 */
23
24 #define __NO_VERSION__
25 #include <linux/module.h>
26
27 #include <linux/errno.h>
28 #include <linux/kernel.h>
29 #include <linux/sched.h>
30 #include <linux/fcntl.h>
31 #include <linux/delay.h>
32 #include <linux/ioport.h>
33 #include <linux/mm.h>
34 #include <asm/io.h>
35
36 #include "../comedi.h"
37 #include "../comedilib.h"
38 #include "../comedidev.h"
39
40 MODULE_AUTHOR("David Schleef <ds@schleef.org>");
41 MODULE_DESCRIPTION("Comedi kernel library");
42 MODULE_LICENSE("GPL");
43
44 void *comedi_open(const char *filename)
45 {
46 struct comedi_device_file_info *dev_file_info;
47 struct comedi_device *dev;
48 unsigned int minor;
49
50 if (strncmp(filename, "/dev/comedi", 11) != 0)
51 return NULL;
52
53 minor = simple_strtoul(filename + 11, NULL, 0);
54
55 if (minor >= COMEDI_NUM_BOARD_MINORS)
56 return NULL;
57
58 dev_file_info = comedi_get_device_file_info(minor);
59 if (dev_file_info == NULL)
60 return NULL;
61 dev = dev_file_info->device;
62
63 if (dev == NULL || !dev->attached)
64 return NULL;
65
66 if (!try_module_get(dev->driver->module))
67 return NULL;
68
69 return (void *)dev;
70 }
71
72 void *comedi_open_old(unsigned int minor)
73 {
74 struct comedi_device_file_info *dev_file_info;
75 struct comedi_device *dev;
76
77 if (minor >= COMEDI_NUM_MINORS)
78 return NULL;
79
80 dev_file_info = comedi_get_device_file_info(minor);
81 if (dev_file_info == NULL)
82 return NULL;
83 dev = dev_file_info->device;
84
85 if (dev == NULL || !dev->attached)
86 return NULL;
87
88 return (void *)dev;
89 }
90
91 int comedi_close(void *d)
92 {
93 struct comedi_device *dev = (struct comedi_device *)d;
94
95 module_put(dev->driver->module);
96
97 return 0;
98 }
99
100 int comedi_loglevel(int newlevel)
101 {
102 return 0;
103 }
104
105 void comedi_perror(const char *message)
106 {
107 printk("%s: unknown error\n", message);
108 }
109
110 char *comedi_strerror(int err)
111 {
112 return "unknown error";
113 }
114
115 int comedi_fileno(void *d)
116 {
117 struct comedi_device *dev = (struct comedi_device *)d;
118
119 /* return something random */
120 return dev->minor;
121 }
122
123 int comedi_command(void *d, struct comedi_cmd *cmd)
124 {
125 struct comedi_device *dev = (struct comedi_device *)d;
126 struct comedi_subdevice *s;
127 struct comedi_async *async;
128 unsigned runflags;
129
130 if (cmd->subdev >= dev->n_subdevices)
131 return -ENODEV;
132
133 s = dev->subdevices + cmd->subdev;
134 if (s->type == COMEDI_SUBD_UNUSED)
135 return -EIO;
136
137 async = s->async;
138 if (async == NULL)
139 return -ENODEV;
140
141 if (s->busy)
142 return -EBUSY;
143 s->busy = d;
144
145 if (async->cb_mask & COMEDI_CB_EOS)
146 cmd->flags |= TRIG_WAKE_EOS;
147
148 async->cmd = *cmd;
149
150 runflags = SRF_RUNNING;
151
152 comedi_set_subdevice_runflags(s, ~0, runflags);
153
154 comedi_reset_async_buf(async);
155
156 return s->do_cmd(dev, s);
157 }
158
159 int comedi_command_test(void *d, struct comedi_cmd *cmd)
160 {
161 struct comedi_device *dev = (struct comedi_device *)d;
162 struct comedi_subdevice *s;
163
164 if (cmd->subdev >= dev->n_subdevices)
165 return -ENODEV;
166
167 s = dev->subdevices + cmd->subdev;
168 if (s->type == COMEDI_SUBD_UNUSED)
169 return -EIO;
170
171 if (s->async == NULL)
172 return -ENODEV;
173
174 return s->do_cmdtest(dev, s, cmd);
175 }
176
177 /*
178 * COMEDI_INSN
179 * perform an instruction
180 */
181 int comedi_do_insn(void *d, struct comedi_insn *insn)
182 {
183 struct comedi_device *dev = (struct comedi_device *)d;
184 struct comedi_subdevice *s;
185 int ret = 0;
186
187 if (insn->insn & INSN_MASK_SPECIAL) {
188 switch (insn->insn) {
189 case INSN_GTOD:
190 {
191 struct timeval tv;
192
193 do_gettimeofday(&tv);
194 insn->data[0] = tv.tv_sec;
195 insn->data[1] = tv.tv_usec;
196 ret = 2;
197
198 break;
199 }
200 case INSN_WAIT:
201 /* XXX isn't the value supposed to be nanosecs? */
202 if (insn->n != 1 || insn->data[0] >= 100) {
203 ret = -EINVAL;
204 break;
205 }
206 udelay(insn->data[0]);
207 ret = 1;
208 break;
209 case INSN_INTTRIG:
210 if (insn->n != 1) {
211 ret = -EINVAL;
212 break;
213 }
214 if (insn->subdev >= dev->n_subdevices) {
215 printk("%d not usable subdevice\n",
216 insn->subdev);
217 ret = -EINVAL;
218 break;
219 }
220 s = dev->subdevices + insn->subdev;
221 if (!s->async) {
222 printk("no async\n");
223 ret = -EINVAL;
224 break;
225 }
226 if (!s->async->inttrig) {
227 printk("no inttrig\n");
228 ret = -EAGAIN;
229 break;
230 }
231 ret = s->async->inttrig(dev, s, insn->data[0]);
232 if (ret >= 0)
233 ret = 1;
234 break;
235 default:
236 ret = -EINVAL;
237 }
238 } else {
239 /* a subdevice instruction */
240 if (insn->subdev >= dev->n_subdevices) {
241 ret = -EINVAL;
242 goto error;
243 }
244 s = dev->subdevices + insn->subdev;
245
246 if (s->type == COMEDI_SUBD_UNUSED) {
247 printk("%d not useable subdevice\n", insn->subdev);
248 ret = -EIO;
249 goto error;
250 }
251
252 /* XXX check lock */
253
254 ret = check_chanlist(s, 1, &insn->chanspec);
255 if (ret < 0) {
256 printk("bad chanspec\n");
257 ret = -EINVAL;
258 goto error;
259 }
260
261 if (s->busy) {
262 ret = -EBUSY;
263 goto error;
264 }
265 s->busy = d;
266
267 switch (insn->insn) {
268 case INSN_READ:
269 ret = s->insn_read(dev, s, insn, insn->data);
270 break;
271 case INSN_WRITE:
272 ret = s->insn_write(dev, s, insn, insn->data);
273 break;
274 case INSN_BITS:
275 ret = s->insn_bits(dev, s, insn, insn->data);
276 break;
277 case INSN_CONFIG:
278 /* XXX should check instruction length */
279 ret = s->insn_config(dev, s, insn, insn->data);
280 break;
281 default:
282 ret = -EINVAL;
283 break;
284 }
285
286 s->busy = NULL;
287 }
288 if (ret < 0)
289 goto error;
290 #if 0
291 /* XXX do we want this? -- abbotti #if'ed it out for now. */
292 if (ret != insn->n) {
293 printk("BUG: result of insn != insn.n\n");
294 ret = -EINVAL;
295 goto error;
296 }
297 #endif
298 error:
299
300 return ret;
301 }
302
303 /*
304 COMEDI_LOCK
305 lock subdevice
306
307 arg:
308 subdevice number
309
310 reads:
311 none
312
313 writes:
314 none
315
316 necessary locking:
317 - ioctl/rt lock (this type)
318 - lock while subdevice busy
319 - lock while subdevice being programmed
320
321 */
322 int comedi_lock(void *d, unsigned int subdevice)
323 {
324 struct comedi_device *dev = (struct comedi_device *)d;
325 struct comedi_subdevice *s;
326 unsigned long flags;
327 int ret = 0;
328
329 if (subdevice >= dev->n_subdevices)
330 return -EINVAL;
331
332 s = dev->subdevices + subdevice;
333
334 spin_lock_irqsave(&s->spin_lock, flags);
335
336 if (s->busy) {
337 ret = -EBUSY;
338 } else {
339 if (s->lock) {
340 ret = -EBUSY;
341 } else {
342 s->lock = d;
343 }
344 }
345
346 spin_unlock_irqrestore(&s->spin_lock, flags);
347
348 return ret;
349 }
350
351 /*
352 COMEDI_UNLOCK
353 unlock subdevice
354
355 arg:
356 subdevice number
357
358 reads:
359 none
360
361 writes:
362 none
363
364 */
365 int comedi_unlock(void *d, unsigned int subdevice)
366 {
367 struct comedi_device *dev = (struct comedi_device *)d;
368 struct comedi_subdevice *s;
369 unsigned long flags;
370 struct comedi_async *async;
371 int ret;
372
373 if (subdevice >= dev->n_subdevices)
374 return -EINVAL;
375
376 s = dev->subdevices + subdevice;
377
378 async = s->async;
379
380 spin_lock_irqsave(&s->spin_lock, flags);
381
382 if (s->busy) {
383 ret = -EBUSY;
384 } else if (s->lock && s->lock != (void *)d) {
385 ret = -EACCES;
386 } else {
387 s->lock = NULL;
388
389 if (async) {
390 async->cb_mask = 0;
391 async->cb_func = NULL;
392 async->cb_arg = NULL;
393 }
394
395 ret = 0;
396 }
397
398 spin_unlock_irqrestore(&s->spin_lock, flags);
399
400 return ret;
401 }
402
403 /*
404 COMEDI_CANCEL
405 cancel acquisition ioctl
406
407 arg:
408 subdevice number
409
410 reads:
411 nothing
412
413 writes:
414 nothing
415
416 */
417 int comedi_cancel(void *d, unsigned int subdevice)
418 {
419 struct comedi_device *dev = (struct comedi_device *)d;
420 struct comedi_subdevice *s;
421 int ret = 0;
422
423 if (subdevice >= dev->n_subdevices)
424 return -EINVAL;
425
426 s = dev->subdevices + subdevice;
427
428 if (s->lock && s->lock != d)
429 return -EACCES;
430
431 #if 0
432 if (!s->busy)
433 return 0;
434
435 if (s->busy != d)
436 return -EBUSY;
437 #endif
438
439 if (!s->cancel || !s->async)
440 return -EINVAL;
441
442 ret = s->cancel(dev, s);
443
444 if (ret)
445 return ret;
446
447 comedi_set_subdevice_runflags(s, SRF_RUNNING | SRF_RT, 0);
448 s->async->inttrig = NULL;
449 s->busy = NULL;
450
451 return 0;
452 }
453
454 /*
455 registration of callback functions
456 */
457 int comedi_register_callback(void *d, unsigned int subdevice,
458 unsigned int mask, int (*cb) (unsigned int,
459 void *), void *arg)
460 {
461 struct comedi_device *dev = (struct comedi_device *)d;
462 struct comedi_subdevice *s;
463 struct comedi_async *async;
464
465 if (subdevice >= dev->n_subdevices)
466 return -EINVAL;
467
468 s = dev->subdevices + subdevice;
469
470 async = s->async;
471 if (s->type == COMEDI_SUBD_UNUSED || !async)
472 return -EIO;
473
474 /* are we locked? (ioctl lock) */
475 if (s->lock && s->lock != d)
476 return -EACCES;
477
478 /* are we busy? */
479 if (s->busy)
480 return -EBUSY;
481
482 if (!mask) {
483 async->cb_mask = 0;
484 async->cb_func = NULL;
485 async->cb_arg = NULL;
486 } else {
487 async->cb_mask = mask;
488 async->cb_func = cb;
489 async->cb_arg = arg;
490 }
491
492 return 0;
493 }
494
495 int comedi_poll(void *d, unsigned int subdevice)
496 {
497 struct comedi_device *dev = (struct comedi_device *)d;
498 struct comedi_subdevice *s = dev->subdevices;
499 struct comedi_async *async;
500
501 if (subdevice >= dev->n_subdevices)
502 return -EINVAL;
503
504 s = dev->subdevices + subdevice;
505
506 async = s->async;
507 if (s->type == COMEDI_SUBD_UNUSED || !async)
508 return -EIO;
509
510 /* are we locked? (ioctl lock) */
511 if (s->lock && s->lock != d)
512 return -EACCES;
513
514 /* are we running? XXX wrong? */
515 if (!s->busy)
516 return -EIO;
517
518 return s->poll(dev, s);
519 }
520
521 /* WARNING: not portable */
522 int comedi_map(void *d, unsigned int subdevice, void *ptr)
523 {
524 struct comedi_device *dev = (struct comedi_device *)d;
525 struct comedi_subdevice *s;
526
527 if (subdevice >= dev->n_subdevices)
528 return -EINVAL;
529
530 s = dev->subdevices + subdevice;
531
532 if (!s->async)
533 return -EINVAL;
534
535 if (ptr)
536 *((void **)ptr) = s->async->prealloc_buf;
537
538 /* XXX no reference counting */
539
540 return 0;
541 }
542
543 /* WARNING: not portable */
544 int comedi_unmap(void *d, unsigned int subdevice)
545 {
546 struct comedi_device *dev = (struct comedi_device *)d;
547 struct comedi_subdevice *s;
548
549 if (subdevice >= dev->n_subdevices)
550 return -EINVAL;
551
552 s = dev->subdevices + subdevice;
553
554 if (!s->async)
555 return -EINVAL;
556
557 /* XXX no reference counting */
558
559 return 0;
560 }