1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
41MODULE_AUTHOR("David Schleef <ds@schleef.org>");
42MODULE_DESCRIPTION("Comedi kernel library");
43MODULE_LICENSE("GPL");
44
45void *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
73void *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
92int 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
101int comedi_loglevel(int newlevel)
102{
103 return 0;
104}
105
106void comedi_perror(const char *message)
107{
108 printk("%s: unknown error\n", message);
109}
110
111char *comedi_strerror(int err)
112{
113 return "unknown error";
114}
115
116int comedi_fileno(void *d)
117{
118 struct comedi_device *dev = (struct comedi_device *)d;
119
120
121 return dev->minor;
122}
123
124int 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
160int 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
180
181
182int 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
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
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
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
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
293 if (ret != insn->n) {
294 printk("BUG: result of insn != insn.n\n");
295 ret = -EINVAL;
296 goto error;
297 }
298#endif
299error:
300
301 return ret;
302}
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323int 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
354
355
356
357
358
359
360
361
362
363
364
365
366int 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
406
407
408
409
410
411
412
413
414
415
416
417
418int 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
457
458int comedi_register_callback(void *d, unsigned int subdevice,
459 unsigned int mask, int (*cb) (unsigned int,
460 void *), void *arg)
461{
462 struct comedi_device *dev = (struct comedi_device *)d;
463 struct comedi_subdevice *s;
464 struct comedi_async *async;
465
466 if (subdevice >= dev->n_subdevices)
467 return -EINVAL;
468
469 s = dev->subdevices + subdevice;
470
471 async = s->async;
472 if (s->type == COMEDI_SUBD_UNUSED || !async)
473 return -EIO;
474
475
476 if (s->lock && s->lock != d)
477 return -EACCES;
478
479
480 if (s->busy)
481 return -EBUSY;
482
483 if (!mask) {
484 async->cb_mask = 0;
485 async->cb_func = NULL;
486 async->cb_arg = NULL;
487 } else {
488 async->cb_mask = mask;
489 async->cb_func = cb;
490 async->cb_arg = arg;
491 }
492
493 return 0;
494}
495
496int comedi_poll(void *d, unsigned int subdevice)
497{
498 struct comedi_device *dev = (struct comedi_device *)d;
499 struct comedi_subdevice *s = dev->subdevices;
500 struct comedi_async *async;
501
502 if (subdevice >= dev->n_subdevices)
503 return -EINVAL;
504
505 s = dev->subdevices + subdevice;
506
507 async = s->async;
508 if (s->type == COMEDI_SUBD_UNUSED || !async)
509 return -EIO;
510
511
512 if (s->lock && s->lock != d)
513 return -EACCES;
514
515
516 if (!s->busy)
517 return -EIO;
518
519 return s->poll(dev, s);
520}
521
522
523int comedi_map(void *d, unsigned int subdevice, void *ptr)
524{
525 struct comedi_device *dev = (struct comedi_device *)d;
526 struct comedi_subdevice *s;
527
528 if (subdevice >= dev->n_subdevices)
529 return -EINVAL;
530
531 s = dev->subdevices + subdevice;
532
533 if (!s->async)
534 return -EINVAL;
535
536 if (ptr)
537 *((void **)ptr) = s->async->prealloc_buf;
538
539
540
541 return 0;
542}
543
544
545int comedi_unmap(void *d, unsigned int subdevice)
546{
547 struct comedi_device *dev = (struct comedi_device *)d;
548 struct comedi_subdevice *s;
549
550 if (subdevice >= dev->n_subdevices)
551 return -EINVAL;
552
553 s = dev->subdevices + subdevice;
554
555 if (!s->async)
556 return -EINVAL;
557
558
559
560 return 0;
561}
562