]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/staging/comedi/kcomedilib/kcomedilib_main.c
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[mv-sheeva.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 }