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 <linux/slab.h>
35 #include <asm/io.h>
36
37 #include "../comedi.h"
38 #include "../comedilib.h"
39 #include "../comedidev.h"
40
41 MODULE_AUTHOR("David Schleef <ds@schleef.org>");
42 MODULE_DESCRIPTION("Comedi kernel library");
43 MODULE_LICENSE("GPL");
44
45 void *comedi_open(const char *filename)
46 {
47 struct comedi_device_file_info *dev_file_info;
48 struct comedi_device *dev;
49 unsigned int minor;
50
51 if (strncmp(filename, "/dev/comedi", 11) != 0)
52 return NULL;
53
54 minor = simple_strtoul(filename + 11, NULL, 0);
55
56 if (minor >= COMEDI_NUM_BOARD_MINORS)
57 return NULL;
58
59 dev_file_info = comedi_get_device_file_info(minor);
60 if (dev_file_info == NULL)
61 return NULL;
62 dev = dev_file_info->device;
63
64 if (dev == NULL || !dev->attached)
65 return NULL;
66
67 if (!try_module_get(dev->driver->module))
68 return NULL;
69
70 return (void *) dev;
71 }
72
73 void *comedi_open_old(unsigned int minor)
74 {
75 struct comedi_device_file_info *dev_file_info;
76 struct comedi_device *dev;
77
78 if (minor >= COMEDI_NUM_MINORS)
79 return NULL;
80
81 dev_file_info = comedi_get_device_file_info(minor);
82 if (dev_file_info == NULL)
83 return NULL;
84 dev = dev_file_info->device;
85
86 if (dev == NULL || !dev->attached)
87 return NULL;
88
89 return (void *) dev;
90 }
91
92 int comedi_close(void *d)
93 {
94 struct comedi_device *dev = (struct comedi_device *) d;
95
96 module_put(dev->driver->module);
97
98 return 0;
99 }
100
101 int comedi_loglevel(int newlevel)
102 {
103 return 0;
104 }
105
106 void comedi_perror(const char *message)
107 {
108 printk("%s: unknown error\n", message);
109 }
110
111 char *comedi_strerror(int err)
112 {
113 return "unknown error";
114 }
115
116 int comedi_fileno(void *d)
117 {
118 struct comedi_device *dev = (struct comedi_device *) d;
119
120 /* return something random */
121 return dev->minor;
122 }
123
124 int comedi_command(void *d, struct comedi_cmd *cmd)
125 {
126 struct comedi_device *dev = (struct comedi_device *) d;
127 struct comedi_subdevice *s;
128 struct comedi_async *async;
129 unsigned runflags;
130
131 if (cmd->subdev >= dev->n_subdevices)
132 return -ENODEV;
133
134 s = dev->subdevices + cmd->subdev;
135 if (s->type == COMEDI_SUBD_UNUSED)
136 return -EIO;
137
138 async = s->async;
139 if (async == NULL)
140 return -ENODEV;
141
142 if (s->busy)
143 return -EBUSY;
144 s->busy = d;
145
146 if (async->cb_mask & COMEDI_CB_EOS)
147 cmd->flags |= TRIG_WAKE_EOS;
148
149 async->cmd = *cmd;
150
151 runflags = SRF_RUNNING;
152
153 comedi_set_subdevice_runflags(s, ~0, runflags);
154
155 comedi_reset_async_buf(async);
156
157 return s->do_cmd(dev, s);
158 }
159
160 int comedi_command_test(void *d, struct comedi_cmd *cmd)
161 {
162 struct comedi_device *dev = (struct comedi_device *) d;
163 struct comedi_subdevice *s;
164
165 if (cmd->subdev >= dev->n_subdevices)
166 return -ENODEV;
167
168 s = dev->subdevices + cmd->subdev;
169 if (s->type == COMEDI_SUBD_UNUSED)
170 return -EIO;
171
172 if (s->async == NULL)
173 return -ENODEV;
174
175 return s->do_cmdtest(dev, s, cmd);
176 }
177
178 /*
179 * COMEDI_INSN
180 * perform an instruction
181 */
182 int comedi_do_insn(void *d, struct comedi_insn *insn)
183 {
184 struct comedi_device *dev = (struct comedi_device *) d;
185 struct comedi_subdevice *s;
186 int ret = 0;
187
188 if (insn->insn & INSN_MASK_SPECIAL) {
189 switch (insn->insn) {
190 case INSN_GTOD:
191 {
192 struct timeval tv;
193
194 do_gettimeofday(&tv);
195 insn->data[0] = tv.tv_sec;
196 insn->data[1] = tv.tv_usec;
197 ret = 2;
198
199 break;
200 }
201 case INSN_WAIT:
202 /* XXX isn't the value supposed to be nanosecs? */
203 if (insn->n != 1 || insn->data[0] >= 100) {
204 ret = -EINVAL;
205 break;
206 }
207 udelay(insn->data[0]);
208 ret = 1;
209 break;
210 case INSN_INTTRIG:
211 if (insn->n != 1) {
212 ret = -EINVAL;
213 break;
214 }
215 if (insn->subdev >= dev->n_subdevices) {
216 printk("%d not usable subdevice\n",
217 insn->subdev);
218 ret = -EINVAL;
219 break;
220 }
221 s = dev->subdevices + insn->subdev;
222 if (!s->async) {
223 printk("no async\n");
224 ret = -EINVAL;
225 break;
226 }
227 if (!s->async->inttrig) {
228 printk("no inttrig\n");
229 ret = -EAGAIN;
230 break;
231 }
232 ret = s->async->inttrig(dev, s, insn->data[0]);
233 if (ret >= 0)
234 ret = 1;
235 break;
236 default:
237 ret = -EINVAL;
238 }
239 } else {
240 /* a subdevice instruction */
241 if (insn->subdev >= dev->n_subdevices) {
242 ret = -EINVAL;
243 goto error;
244 }
245 s = dev->subdevices + insn->subdev;
246
247 if (s->type == COMEDI_SUBD_UNUSED) {
248 printk("%d not useable subdevice\n", insn->subdev);
249 ret = -EIO;
250 goto error;
251 }
252
253 /* XXX check lock */
254
255 ret = check_chanlist(s, 1, &insn->chanspec);
256 if (ret < 0) {
257 printk("bad chanspec\n");
258 ret = -EINVAL;
259 goto error;
260 }
261
262 if (s->busy) {
263 ret = -EBUSY;
264 goto error;
265 }
266 s->busy = d;
267
268 switch (insn->insn) {
269 case INSN_READ:
270 ret = s->insn_read(dev, s, insn, insn->data);
271 break;
272 case INSN_WRITE:
273 ret = s->insn_write(dev, s, insn, insn->data);
274 break;
275 case INSN_BITS:
276 ret = s->insn_bits(dev, s, insn, insn->data);
277 break;
278 case INSN_CONFIG:
279 /* XXX should check instruction length */
280 ret = s->insn_config(dev, s, insn, insn->data);
281 break;
282 default:
283 ret = -EINVAL;
284 break;
285 }
286
287 s->busy = NULL;
288 }
289 if (ret < 0)
290 goto error;
291 #if 0
292 /* XXX do we want this? -- abbotti #if'ed it out for now. */
293 if (ret != insn->n) {
294 printk("BUG: result of insn != insn.n\n");
295 ret = -EINVAL;
296 goto error;
297 }
298 #endif
299 error:
300
301 return ret;
302 }
303
304 /*
305 COMEDI_LOCK
306 lock subdevice
307
308 arg:
309 subdevice number
310
311 reads:
312 none
313
314 writes:
315 none
316
317 necessary locking:
318 - ioctl/rt lock (this type)
319 - lock while subdevice busy
320 - lock while subdevice being programmed
321
322 */
323 int comedi_lock(void *d, unsigned int subdevice)
324 {
325 struct comedi_device *dev = (struct comedi_device *) d;
326 struct comedi_subdevice *s;
327 unsigned long flags;
328 int ret = 0;
329
330 if (subdevice >= dev->n_subdevices)
331 return -EINVAL;
332
333 s = dev->subdevices + subdevice;
334
335 spin_lock_irqsave(&s->spin_lock, flags);
336
337 if (s->busy) {
338 ret = -EBUSY;
339 } else {
340 if (s->lock) {
341 ret = -EBUSY;
342 } else {
343 s->lock = d;
344 }
345 }
346
347 spin_unlock_irqrestore(&s->spin_lock, flags);
348
349 return ret;
350 }
351
352 /*
353 COMEDI_UNLOCK
354 unlock subdevice
355
356 arg:
357 subdevice number
358
359 reads:
360 none
361
362 writes:
363 none
364
365 */
366 int comedi_unlock(void *d, unsigned int subdevice)
367 {
368 struct comedi_device *dev = (struct comedi_device *) d;
369 struct comedi_subdevice *s;
370 unsigned long flags;
371 struct comedi_async *async;
372 int ret;
373
374 if (subdevice >= dev->n_subdevices)
375 return -EINVAL;
376
377 s = dev->subdevices + subdevice;
378
379 async = s->async;
380
381 spin_lock_irqsave(&s->spin_lock, flags);
382
383 if (s->busy) {
384 ret = -EBUSY;
385 } else if (s->lock && s->lock != (void *)d) {
386 ret = -EACCES;
387 } else {
388 s->lock = NULL;
389
390 if (async) {
391 async->cb_mask = 0;
392 async->cb_func = NULL;
393 async->cb_arg = NULL;
394 }
395
396 ret = 0;
397 }
398
399 spin_unlock_irqrestore(&s->spin_lock, flags);
400
401 return ret;
402 }
403
404 /*
405 COMEDI_CANCEL
406 cancel acquisition ioctl
407
408 arg:
409 subdevice number
410
411 reads:
412 nothing
413
414 writes:
415 nothing
416
417 */
418 int comedi_cancel(void *d, unsigned int subdevice)
419 {
420 struct comedi_device *dev = (struct comedi_device *) d;
421 struct comedi_subdevice *s;
422 int ret = 0;
423
424 if (subdevice >= dev->n_subdevices)
425 return -EINVAL;
426
427 s = dev->subdevices + subdevice;
428
429 if (s->lock && s->lock != d)
430 return -EACCES;
431
432 #if 0
433 if (!s->busy)
434 return 0;
435
436 if (s->busy != d)
437 return -EBUSY;
438 #endif
439
440 if (!s->cancel || !s->async)
441 return -EINVAL;
442
443 ret = s->cancel(dev, s);
444
445 if (ret)
446 return ret;
447
448 comedi_set_subdevice_runflags(s, SRF_RUNNING | SRF_RT, 0);
449 s->async->inttrig = NULL;
450 s->busy = NULL;
451
452 return 0;
453 }
454
455 /*
456 registration of callback functions
457 */
458 int comedi_register_callback(void *d, unsigned int subdevice,
459 unsigned int mask, int (*cb) (unsigned int, 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 }
561
|
This page was automatically generated by the
LXR engine.
|