Staging: comedi: Change "foo * bar" to "foo *bar"
[pandora-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 <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 comedi_t *comedi_open(const char *filename)
46 {
47         struct comedi_device_file_info *dev_file_info;
48         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 (comedi_t *) dev;
71 }
72
73 comedi_t *comedi_open_old(unsigned int minor)
74 {
75         struct comedi_device_file_info *dev_file_info;
76         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 (comedi_t *) dev;
90 }
91
92 int comedi_close(comedi_t *d)
93 {
94         comedi_device *dev = (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         rt_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(comedi_t *d)
117 {
118         comedi_device *dev = (comedi_device *) d;
119
120         /* return something random */
121         return dev->minor;
122 }
123
124 int comedi_command(comedi_t *d, comedi_cmd *cmd)
125 {
126         comedi_device *dev = (comedi_device *) d;
127         comedi_subdevice *s;
128         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 #ifdef CONFIG_COMEDI_RT
154         if (comedi_switch_to_rt(dev) == 0)
155                 runflags |= SRF_RT;
156 #endif
157         comedi_set_subdevice_runflags(s, ~0, runflags);
158
159         comedi_reset_async_buf(async);
160
161         return s->do_cmd(dev, s);
162 }
163
164 int comedi_command_test(comedi_t *d, comedi_cmd *cmd)
165 {
166         comedi_device *dev = (comedi_device *) d;
167         comedi_subdevice *s;
168
169         if (cmd->subdev >= dev->n_subdevices)
170                 return -ENODEV;
171
172         s = dev->subdevices + cmd->subdev;
173         if (s->type == COMEDI_SUBD_UNUSED)
174                 return -EIO;
175
176         if (s->async == NULL)
177                 return -ENODEV;
178
179         return s->do_cmdtest(dev, s, cmd);
180 }
181
182 /*
183  *      COMEDI_INSN
184  *      perform an instruction
185  */
186 int comedi_do_insn(comedi_t *d, comedi_insn *insn)
187 {
188         comedi_device *dev = (comedi_device *) d;
189         comedi_subdevice *s;
190         int ret = 0;
191
192         if (insn->insn & INSN_MASK_SPECIAL) {
193                 switch (insn->insn) {
194                 case INSN_GTOD:
195                         {
196                                 struct timeval tv;
197
198                                 do_gettimeofday(&tv);
199                                 insn->data[0] = tv.tv_sec;
200                                 insn->data[1] = tv.tv_usec;
201                                 ret = 2;
202
203                                 break;
204                         }
205                 case INSN_WAIT:
206                         /* XXX isn't the value supposed to be nanosecs? */
207                         if (insn->n != 1 || insn->data[0] >= 100) {
208                                 ret = -EINVAL;
209                                 break;
210                         }
211                         comedi_udelay(insn->data[0]);
212                         ret = 1;
213                         break;
214                 case INSN_INTTRIG:
215                         if (insn->n != 1) {
216                                 ret = -EINVAL;
217                                 break;
218                         }
219                         if (insn->subdev >= dev->n_subdevices) {
220                                 rt_printk("%d not usable subdevice\n",
221                                         insn->subdev);
222                                 ret = -EINVAL;
223                                 break;
224                         }
225                         s = dev->subdevices + insn->subdev;
226                         if (!s->async) {
227                                 rt_printk("no async\n");
228                                 ret = -EINVAL;
229                                 break;
230                         }
231                         if (!s->async->inttrig) {
232                                 rt_printk("no inttrig\n");
233                                 ret = -EAGAIN;
234                                 break;
235                         }
236                         ret = s->async->inttrig(dev, s, insn->data[0]);
237                         if (ret >= 0)
238                                 ret = 1;
239                         break;
240                 default:
241                         ret = -EINVAL;
242                 }
243         } else {
244                 /* a subdevice instruction */
245                 if (insn->subdev >= dev->n_subdevices) {
246                         ret = -EINVAL;
247                         goto error;
248                 }
249                 s = dev->subdevices + insn->subdev;
250
251                 if (s->type == COMEDI_SUBD_UNUSED) {
252                         rt_printk("%d not useable subdevice\n", insn->subdev);
253                         ret = -EIO;
254                         goto error;
255                 }
256
257                 /* XXX check lock */
258
259                 if ((ret = check_chanlist(s, 1, &insn->chanspec)) < 0) {
260                         rt_printk("bad chanspec\n");
261                         ret = -EINVAL;
262                         goto error;
263                 }
264
265                 if (s->busy) {
266                         ret = -EBUSY;
267                         goto error;
268                 }
269                 s->busy = d;
270
271                 switch (insn->insn) {
272                 case INSN_READ:
273                         ret = s->insn_read(dev, s, insn, insn->data);
274                         break;
275                 case INSN_WRITE:
276                         ret = s->insn_write(dev, s, insn, insn->data);
277                         break;
278                 case INSN_BITS:
279                         ret = s->insn_bits(dev, s, insn, insn->data);
280                         break;
281                 case INSN_CONFIG:
282                         /* XXX should check instruction length */
283                         ret = s->insn_config(dev, s, insn, insn->data);
284                         break;
285                 default:
286                         ret = -EINVAL;
287                         break;
288                 }
289
290                 s->busy = NULL;
291         }
292         if (ret < 0)
293                 goto error;
294 #if 0
295         /* XXX do we want this? -- abbotti #if'ed it out for now. */
296         if (ret != insn->n) {
297                 rt_printk("BUG: result of insn != insn.n\n");
298                 ret = -EINVAL;
299                 goto error;
300         }
301 #endif
302       error:
303
304         return ret;
305 }
306
307 /*
308         COMEDI_LOCK
309         lock subdevice
310
311         arg:
312                 subdevice number
313
314         reads:
315                 none
316
317         writes:
318                 none
319
320         necessary locking:
321         - ioctl/rt lock  (this type)
322         - lock while subdevice busy
323         - lock while subdevice being programmed
324
325 */
326 int comedi_lock(comedi_t *d, unsigned int subdevice)
327 {
328         comedi_device *dev = (comedi_device *) d;
329         comedi_subdevice *s;
330         unsigned long flags;
331         int ret = 0;
332
333         if (subdevice >= dev->n_subdevices) {
334                 return -EINVAL;
335         }
336         s = dev->subdevices + subdevice;
337
338         comedi_spin_lock_irqsave(&s->spin_lock, flags);
339
340         if (s->busy) {
341                 ret = -EBUSY;
342         } else {
343                 if (s->lock) {
344                         ret = -EBUSY;
345                 } else {
346                         s->lock = d;
347                 }
348         }
349
350         comedi_spin_unlock_irqrestore(&s->spin_lock, flags);
351
352         return ret;
353 }
354
355 /*
356         COMEDI_UNLOCK
357         unlock subdevice
358
359         arg:
360                 subdevice number
361
362         reads:
363                 none
364
365         writes:
366                 none
367
368 */
369 int comedi_unlock(comedi_t *d, unsigned int subdevice)
370 {
371         comedi_device *dev = (comedi_device *) d;
372         comedi_subdevice *s;
373         unsigned long flags;
374         comedi_async *async;
375         int ret;
376
377         if (subdevice >= dev->n_subdevices) {
378                 return -EINVAL;
379         }
380         s = dev->subdevices + subdevice;
381
382         async = s->async;
383
384         comedi_spin_lock_irqsave(&s->spin_lock, flags);
385
386         if (s->busy) {
387                 ret = -EBUSY;
388         } else if (s->lock && s->lock != (void *)d) {
389                 ret = -EACCES;
390         } else {
391                 s->lock = NULL;
392
393                 if (async) {
394                         async->cb_mask = 0;
395                         async->cb_func = NULL;
396                         async->cb_arg = NULL;
397                 }
398
399                 ret = 0;
400         }
401
402         comedi_spin_unlock_irqrestore(&s->spin_lock, flags);
403
404         return ret;
405 }
406
407 /*
408         COMEDI_CANCEL
409         cancel acquisition ioctl
410
411         arg:
412                 subdevice number
413
414         reads:
415                 nothing
416
417         writes:
418                 nothing
419
420 */
421 int comedi_cancel(comedi_t *d, unsigned int subdevice)
422 {
423         comedi_device *dev = (comedi_device *) d;
424         comedi_subdevice *s;
425         int ret = 0;
426
427         if (subdevice >= dev->n_subdevices) {
428                 return -EINVAL;
429         }
430         s = dev->subdevices + subdevice;
431
432         if (s->lock && s->lock != d)
433                 return -EACCES;
434
435 #if 0
436         if (!s->busy)
437                 return 0;
438
439         if (s->busy != d)
440                 return -EBUSY;
441 #endif
442
443         if (!s->cancel || !s->async)
444                 return -EINVAL;
445
446         if ((ret = s->cancel(dev, s)))
447                 return ret;
448
449 #ifdef CONFIG_COMEDI_RT
450         if (comedi_get_subdevice_runflags(s) & SRF_RT) {
451                 comedi_switch_to_non_rt(dev);
452         }
453 #endif
454         comedi_set_subdevice_runflags(s, SRF_RUNNING | SRF_RT, 0);
455         s->async->inttrig = NULL;
456         s->busy = NULL;
457
458         return 0;
459 }
460
461 /*
462    registration of callback functions
463  */
464 int comedi_register_callback(comedi_t *d, unsigned int subdevice,
465         unsigned int mask, int (*cb) (unsigned int, void *), void *arg)
466 {
467         comedi_device *dev = (comedi_device *) d;
468         comedi_subdevice *s;
469         comedi_async *async;
470
471         if (subdevice >= dev->n_subdevices) {
472                 return -EINVAL;
473         }
474         s = dev->subdevices + subdevice;
475
476         async = s->async;
477         if (s->type == COMEDI_SUBD_UNUSED || !async)
478                 return -EIO;
479
480         /* are we locked? (ioctl lock) */
481         if (s->lock && s->lock != d)
482                 return -EACCES;
483
484         /* are we busy? */
485         if (s->busy)
486                 return -EBUSY;
487
488         if (!mask) {
489                 async->cb_mask = 0;
490                 async->cb_func = NULL;
491                 async->cb_arg = NULL;
492         } else {
493                 async->cb_mask = mask;
494                 async->cb_func = cb;
495                 async->cb_arg = arg;
496         }
497
498         return 0;
499 }
500
501 int comedi_poll(comedi_t *d, unsigned int subdevice)
502 {
503         comedi_device *dev = (comedi_device *) d;
504         comedi_subdevice *s = dev->subdevices;
505         comedi_async *async;
506
507         if (subdevice >= dev->n_subdevices) {
508                 return -EINVAL;
509         }
510         s = dev->subdevices + subdevice;
511
512         async = s->async;
513         if (s->type == COMEDI_SUBD_UNUSED || !async)
514                 return -EIO;
515
516         /* are we locked? (ioctl lock) */
517         if (s->lock && s->lock != d)
518                 return -EACCES;
519
520         /* are we running? XXX wrong? */
521         if (!s->busy)
522                 return -EIO;
523
524         return s->poll(dev, s);
525 }
526
527 /* WARNING: not portable */
528 int comedi_map(comedi_t *d, unsigned int subdevice, void *ptr)
529 {
530         comedi_device *dev = (comedi_device *) d;
531         comedi_subdevice *s;
532
533         if (subdevice >= dev->n_subdevices) {
534                 return -EINVAL;
535         }
536         s = dev->subdevices + subdevice;
537
538         if (!s->async)
539                 return -EINVAL;
540
541         if (ptr) {
542                 *((void **)ptr) = s->async->prealloc_buf;
543         }
544
545         /* XXX no reference counting */
546
547         return 0;
548 }
549
550 /* WARNING: not portable */
551 int comedi_unmap(comedi_t *d, unsigned int subdevice)
552 {
553         comedi_device *dev = (comedi_device *) d;
554         comedi_subdevice *s;
555
556         if (subdevice >= dev->n_subdevices) {
557                 return -EINVAL;
558         }
559         s = dev->subdevices + subdevice;
560
561         if (!s->async)
562                 return -EINVAL;
563
564         /* XXX no reference counting */
565
566         return 0;
567 }