drm/radeon/kms: enable use of unmappable VRAM V2
[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 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,
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         /* are we locked? (ioctl lock) */
476         if (s->lock && s->lock != d)
477                 return -EACCES;
478
479         /* are we busy? */
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
496 int 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         /* are we locked? (ioctl lock) */
512         if (s->lock && s->lock != d)
513                 return -EACCES;
514
515         /* are we running? XXX wrong? */
516         if (!s->busy)
517                 return -EIO;
518
519         return s->poll(dev, s);
520 }
521
522 /* WARNING: not portable */
523 int 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         /* XXX no reference counting */
540
541         return 0;
542 }
543
544 /* WARNING: not portable */
545 int 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         /* XXX no reference counting */
559
560         return 0;
561 }