include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[linux-block.git] / drivers / staging / comedi / kcomedilib / kcomedilib_main.c
CommitLineData
b79a7a20
DS
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>
b79a7a20
DS
34#include <asm/io.h>
35
36#include "../comedi.h"
37#include "../comedilib.h"
38#include "../comedidev.h"
39
40MODULE_AUTHOR("David Schleef <ds@schleef.org>");
41MODULE_DESCRIPTION("Comedi kernel library");
42MODULE_LICENSE("GPL");
43
0b3fb27f 44void *comedi_open(const char *filename)
b79a7a20
DS
45{
46 struct comedi_device_file_info *dev_file_info;
71b5f4f1 47 struct comedi_device *dev;
b79a7a20
DS
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);
6a98d36e 59 if (dev_file_info == NULL)
b79a7a20
DS
60 return NULL;
61 dev = dev_file_info->device;
62
6a98d36e 63 if (dev == NULL || !dev->attached)
b79a7a20
DS
64 return NULL;
65
66 if (!try_module_get(dev->driver->module))
67 return NULL;
68
0a85b6f0 69 return (void *)dev;
b79a7a20
DS
70}
71
0b3fb27f 72void *comedi_open_old(unsigned int minor)
b79a7a20
DS
73{
74 struct comedi_device_file_info *dev_file_info;
71b5f4f1 75 struct comedi_device *dev;
b79a7a20
DS
76
77 if (minor >= COMEDI_NUM_MINORS)
78 return NULL;
79
80 dev_file_info = comedi_get_device_file_info(minor);
6a98d36e 81 if (dev_file_info == NULL)
b79a7a20
DS
82 return NULL;
83 dev = dev_file_info->device;
84
6a98d36e 85 if (dev == NULL || !dev->attached)
b79a7a20
DS
86 return NULL;
87
0a85b6f0 88 return (void *)dev;
b79a7a20
DS
89}
90
0b3fb27f 91int comedi_close(void *d)
b79a7a20 92{
0a85b6f0 93 struct comedi_device *dev = (struct comedi_device *)d;
b79a7a20
DS
94
95 module_put(dev->driver->module);
96
97 return 0;
98}
99
100int comedi_loglevel(int newlevel)
101{
102 return 0;
103}
104
105void comedi_perror(const char *message)
106{
5f74ea14 107 printk("%s: unknown error\n", message);
b79a7a20
DS
108}
109
110char *comedi_strerror(int err)
111{
112 return "unknown error";
113}
114
0b3fb27f 115int comedi_fileno(void *d)
b79a7a20 116{
0a85b6f0 117 struct comedi_device *dev = (struct comedi_device *)d;
b79a7a20
DS
118
119 /* return something random */
120 return dev->minor;
121}
122
ea6d0d4c 123int comedi_command(void *d, struct comedi_cmd *cmd)
b79a7a20 124{
0a85b6f0 125 struct comedi_device *dev = (struct comedi_device *)d;
34c43922 126 struct comedi_subdevice *s;
d163679c 127 struct comedi_async *async;
b79a7a20
DS
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
b79a7a20
DS
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
ea6d0d4c 159int comedi_command_test(void *d, struct comedi_cmd *cmd)
b79a7a20 160{
0a85b6f0 161 struct comedi_device *dev = (struct comedi_device *)d;
34c43922 162 struct comedi_subdevice *s;
b79a7a20
DS
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 */
90035c08 181int comedi_do_insn(void *d, struct comedi_insn *insn)
b79a7a20 182{
0a85b6f0 183 struct comedi_device *dev = (struct comedi_device *)d;
34c43922 184 struct comedi_subdevice *s;
b79a7a20
DS
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 }
5f74ea14 206 udelay(insn->data[0]);
b79a7a20
DS
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) {
5f74ea14 215 printk("%d not usable subdevice\n",
0a85b6f0 216 insn->subdev);
b79a7a20
DS
217 ret = -EINVAL;
218 break;
219 }
220 s = dev->subdevices + insn->subdev;
221 if (!s->async) {
5f74ea14 222 printk("no async\n");
b79a7a20
DS
223 ret = -EINVAL;
224 break;
225 }
226 if (!s->async->inttrig) {
5f74ea14 227 printk("no inttrig\n");
b79a7a20
DS
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) {
5f74ea14 247 printk("%d not useable subdevice\n", insn->subdev);
b79a7a20
DS
248 ret = -EIO;
249 goto error;
250 }
251
252 /* XXX check lock */
253
197c82bf
BP
254 ret = check_chanlist(s, 1, &insn->chanspec);
255 if (ret < 0) {
5f74ea14 256 printk("bad chanspec\n");
b79a7a20
DS
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) {
5f74ea14 293 printk("BUG: result of insn != insn.n\n");
b79a7a20
DS
294 ret = -EINVAL;
295 goto error;
296 }
297#endif
0a85b6f0 298error:
b79a7a20
DS
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*/
0b3fb27f 322int comedi_lock(void *d, unsigned int subdevice)
b79a7a20 323{
0a85b6f0 324 struct comedi_device *dev = (struct comedi_device *)d;
34c43922 325 struct comedi_subdevice *s;
b79a7a20
DS
326 unsigned long flags;
327 int ret = 0;
328
82675f35 329 if (subdevice >= dev->n_subdevices)
b79a7a20 330 return -EINVAL;
82675f35 331
b79a7a20
DS
332 s = dev->subdevices + subdevice;
333
5f74ea14 334 spin_lock_irqsave(&s->spin_lock, flags);
b79a7a20
DS
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
5f74ea14 346 spin_unlock_irqrestore(&s->spin_lock, flags);
b79a7a20
DS
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*/
0b3fb27f 365int comedi_unlock(void *d, unsigned int subdevice)
b79a7a20 366{
0a85b6f0 367 struct comedi_device *dev = (struct comedi_device *)d;
34c43922 368 struct comedi_subdevice *s;
b79a7a20 369 unsigned long flags;
d163679c 370 struct comedi_async *async;
b79a7a20
DS
371 int ret;
372
82675f35 373 if (subdevice >= dev->n_subdevices)
b79a7a20 374 return -EINVAL;
82675f35 375
b79a7a20
DS
376 s = dev->subdevices + subdevice;
377
378 async = s->async;
379
5f74ea14 380 spin_lock_irqsave(&s->spin_lock, flags);
b79a7a20
DS
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
5f74ea14 398 spin_unlock_irqrestore(&s->spin_lock, flags);
b79a7a20
DS
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*/
0b3fb27f 417int comedi_cancel(void *d, unsigned int subdevice)
b79a7a20 418{
0a85b6f0 419 struct comedi_device *dev = (struct comedi_device *)d;
34c43922 420 struct comedi_subdevice *s;
b79a7a20
DS
421 int ret = 0;
422
82675f35 423 if (subdevice >= dev->n_subdevices)
b79a7a20 424 return -EINVAL;
82675f35 425
b79a7a20
DS
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
197c82bf
BP
442 ret = s->cancel(dev, s);
443
444 if (ret)
b79a7a20
DS
445 return ret;
446
b79a7a20
DS
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 */
0b3fb27f 457int comedi_register_callback(void *d, unsigned int subdevice,
0a85b6f0
MT
458 unsigned int mask, int (*cb) (unsigned int,
459 void *), void *arg)
b79a7a20 460{
0a85b6f0 461 struct comedi_device *dev = (struct comedi_device *)d;
34c43922 462 struct comedi_subdevice *s;
d163679c 463 struct comedi_async *async;
b79a7a20 464
82675f35 465 if (subdevice >= dev->n_subdevices)
b79a7a20 466 return -EINVAL;
82675f35 467
b79a7a20
DS
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
0b3fb27f 495int comedi_poll(void *d, unsigned int subdevice)
b79a7a20 496{
0a85b6f0 497 struct comedi_device *dev = (struct comedi_device *)d;
34c43922 498 struct comedi_subdevice *s = dev->subdevices;
d163679c 499 struct comedi_async *async;
b79a7a20 500
82675f35 501 if (subdevice >= dev->n_subdevices)
b79a7a20 502 return -EINVAL;
82675f35 503
b79a7a20
DS
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 */
0b3fb27f 522int comedi_map(void *d, unsigned int subdevice, void *ptr)
b79a7a20 523{
0a85b6f0 524 struct comedi_device *dev = (struct comedi_device *)d;
34c43922 525 struct comedi_subdevice *s;
b79a7a20 526
82675f35 527 if (subdevice >= dev->n_subdevices)
b79a7a20 528 return -EINVAL;
82675f35 529
b79a7a20
DS
530 s = dev->subdevices + subdevice;
531
532 if (!s->async)
533 return -EINVAL;
534
82675f35 535 if (ptr)
b79a7a20 536 *((void **)ptr) = s->async->prealloc_buf;
b79a7a20
DS
537
538 /* XXX no reference counting */
539
540 return 0;
541}
542
543/* WARNING: not portable */
0b3fb27f 544int comedi_unmap(void *d, unsigned int subdevice)
b79a7a20 545{
0a85b6f0 546 struct comedi_device *dev = (struct comedi_device *)d;
34c43922 547 struct comedi_subdevice *s;
b79a7a20 548
82675f35 549 if (subdevice >= dev->n_subdevices)
b79a7a20 550 return -EINVAL;
82675f35 551
b79a7a20
DS
552 s = dev->subdevices + subdevice;
553
554 if (!s->async)
555 return -EINVAL;
556
557 /* XXX no reference counting */
558
559 return 0;
560}