blob: f44566416f5b698063e94d1f0251751830fa8624 [file] [log] [blame]
David Schleefed9eccb2008-11-04 20:29:31 -08001/*
2 comedi/comedi_fops.c
3 comedi kernel module
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#undef DEBUG
25
26#define __NO_VERSION__
27#include "comedi_fops.h"
28#include "comedi_compat32.h"
29
30#include <linux/module.h>
31#include <linux/errno.h>
32#include <linux/kernel.h>
33#include <linux/sched.h>
34#include <linux/fcntl.h>
35#include <linux/delay.h>
36#include <linux/ioport.h>
37#include <linux/mm.h>
38#include <linux/slab.h>
39#include <linux/kmod.h>
40#include <linux/poll.h>
41#include <linux/init.h>
42#include <linux/device.h>
43#include <linux/vmalloc.h>
44#include <linux/fs.h>
45#include "comedidev.h"
46#include <linux/cdev.h>
47
48#include <asm/io.h>
49#include <asm/uaccess.h>
50
51//#include "kvmem.h"
52
53MODULE_AUTHOR("http://www.comedi.org");
54MODULE_DESCRIPTION("Comedi core module");
55MODULE_LICENSE("GPL");
56
57#ifdef CONFIG_COMEDI_DEBUG
58int comedi_debug;
59module_param(comedi_debug, int, 0644);
60#endif
61
62static DEFINE_SPINLOCK(comedi_file_info_table_lock);
63static struct comedi_device_file_info* comedi_file_info_table[COMEDI_NUM_MINORS];
64
65static int do_devconfig_ioctl(comedi_device * dev, comedi_devconfig * arg);
66static int do_bufconfig_ioctl(comedi_device * dev, void *arg);
67static int do_devinfo_ioctl(comedi_device * dev, comedi_devinfo * arg,
68 struct file *file);
69static int do_subdinfo_ioctl(comedi_device * dev, comedi_subdinfo * arg,
70 void *file);
71static int do_chaninfo_ioctl(comedi_device * dev, comedi_chaninfo * arg);
72static int do_bufinfo_ioctl(comedi_device * dev, void *arg);
73static int do_cmd_ioctl(comedi_device * dev, void *arg, void *file);
74static int do_lock_ioctl(comedi_device * dev, unsigned int arg, void *file);
75static int do_unlock_ioctl(comedi_device * dev, unsigned int arg, void *file);
76static int do_cancel_ioctl(comedi_device * dev, unsigned int arg, void *file);
77static int do_cmdtest_ioctl(comedi_device * dev, void *arg, void *file);
78static int do_insnlist_ioctl(comedi_device * dev, void *arg, void *file);
79static int do_insn_ioctl(comedi_device * dev, void *arg, void *file);
80static int do_poll_ioctl(comedi_device * dev, unsigned int subd, void *file);
81
82void do_become_nonbusy(comedi_device * dev, comedi_subdevice * s);
83static int do_cancel(comedi_device * dev, comedi_subdevice * s);
84
85static int comedi_fasync(int fd, struct file *file, int on);
86
87static int is_device_busy(comedi_device * dev);
88
89#ifdef HAVE_UNLOCKED_IOCTL
90static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
91 unsigned long arg)
92#else
93static int comedi_ioctl(struct inode *inode, struct file *file,
94 unsigned int cmd, unsigned long arg)
95#endif
96{
97 const unsigned minor = iminor(file->f_dentry->d_inode);
98 struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(minor);
99 comedi_device *dev = dev_file_info->device;
100 int rc;
101
102 mutex_lock(&dev->mutex);
103
104 /* Device config is special, because it must work on
105 * an unconfigured device. */
106 if (cmd == COMEDI_DEVCONFIG) {
107 rc = do_devconfig_ioctl(dev, (void *)arg);
108 goto done;
109 }
110
111 if (!dev->attached) {
112 DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor);
113 rc = -ENODEV;
114 goto done;
115 }
116
117 switch (cmd) {
118 case COMEDI_BUFCONFIG:
119 rc = do_bufconfig_ioctl(dev, (void *)arg);
120 break;
121 case COMEDI_DEVINFO:
122 rc = do_devinfo_ioctl(dev, (void *)arg, file);
123 break;
124 case COMEDI_SUBDINFO:
125 rc = do_subdinfo_ioctl(dev, (void *)arg, file);
126 break;
127 case COMEDI_CHANINFO:
128 rc = do_chaninfo_ioctl(dev, (void *)arg);
129 break;
130 case COMEDI_RANGEINFO:
131 rc = do_rangeinfo_ioctl(dev, (void *)arg);
132 break;
133 case COMEDI_BUFINFO:
134 rc = do_bufinfo_ioctl(dev, (void *)arg);
135 break;
136 case COMEDI_LOCK:
137 rc = do_lock_ioctl(dev, arg, file);
138 break;
139 case COMEDI_UNLOCK:
140 rc = do_unlock_ioctl(dev, arg, file);
141 break;
142 case COMEDI_CANCEL:
143 rc = do_cancel_ioctl(dev, arg, file);
144 break;
145 case COMEDI_CMD:
146 rc = do_cmd_ioctl(dev, (void *)arg, file);
147 break;
148 case COMEDI_CMDTEST:
149 rc = do_cmdtest_ioctl(dev, (void *)arg, file);
150 break;
151 case COMEDI_INSNLIST:
152 rc = do_insnlist_ioctl(dev, (void *)arg, file);
153 break;
154 case COMEDI_INSN:
155 rc = do_insn_ioctl(dev, (void *)arg, file);
156 break;
157 case COMEDI_POLL:
158 rc = do_poll_ioctl(dev, arg, file);
159 break;
160 default:
161 rc = -ENOTTY;
162 break;
163 }
164
165 done:
166 mutex_unlock(&dev->mutex);
167 return rc;
168}
169
170/*
171 COMEDI_DEVCONFIG
172 device config ioctl
173
174 arg:
175 pointer to devconfig structure
176
177 reads:
178 devconfig structure at arg
179
180 writes:
181 none
182*/
183static int do_devconfig_ioctl(comedi_device * dev, comedi_devconfig * arg)
184{
185 comedi_devconfig it;
186 int ret;
187 unsigned char *aux_data = NULL;
188 int aux_len;
189
190 if (!capable(CAP_SYS_ADMIN))
191 return -EPERM;
192
193 if (arg == NULL) {
194 if (is_device_busy(dev))
195 return -EBUSY;
196 if(dev->attached)
197 {
198 struct module *driver_module = dev->driver->module;
199 comedi_device_detach(dev);
200 module_put(driver_module);
201 }
202 return 0;
203 }
204
205 if (copy_from_user(&it, arg, sizeof(comedi_devconfig)))
206 return -EFAULT;
207
208 it.board_name[COMEDI_NAMELEN - 1] = 0;
209
210 if (comedi_aux_data(it.options, 0) &&
211 it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
212 int bit_shift;
213 aux_len = it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
214 if (aux_len < 0)
215 return -EFAULT;
216
217 aux_data = vmalloc(aux_len);
218 if (!aux_data)
219 return -ENOMEM;
220
221 if (copy_from_user(aux_data,
222 comedi_aux_data(it.options, 0), aux_len)) {
223 vfree(aux_data);
224 return -EFAULT;
225 }
226 it.options[COMEDI_DEVCONF_AUX_DATA_LO] =
227 (unsigned long)aux_data;
228 if (sizeof(void *) > sizeof(int)) {
229 bit_shift = sizeof(int) * 8;
230 it.options[COMEDI_DEVCONF_AUX_DATA_HI] =
231 ((unsigned long)aux_data) >> bit_shift;
232 } else
233 it.options[COMEDI_DEVCONF_AUX_DATA_HI] = 0;
234 }
235
236 ret = comedi_device_attach(dev, &it);
237 if(ret == 0)
238 {
239 if(!try_module_get(dev->driver->module)) {
240 comedi_device_detach(dev);
241 return -ENOSYS;
242 }
243 }
244
245 if (aux_data)
246 vfree(aux_data);
247
248 return ret;
249}
250
251/*
252 COMEDI_BUFCONFIG
253 buffer configuration ioctl
254
255 arg:
256 pointer to bufconfig structure
257
258 reads:
259 bufconfig at arg
260
261 writes:
262 modified bufconfig at arg
263
264*/
265static int do_bufconfig_ioctl(comedi_device * dev, void *arg)
266{
267 comedi_bufconfig bc;
268 comedi_async *async;
269 comedi_subdevice *s;
270 int ret = 0;
271
272 if (copy_from_user(&bc, arg, sizeof(comedi_bufconfig)))
273 return -EFAULT;
274
275 if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0)
276 return -EINVAL;
277
278 s = dev->subdevices + bc.subdevice;
279 async = s->async;
280
281 if (!async) {
282 DPRINTK("subdevice does not have async capability\n");
283 bc.size = 0;
284 bc.maximum_size = 0;
285 goto copyback;
286 }
287
288 if (bc.maximum_size) {
289 if (!capable(CAP_SYS_ADMIN))
290 return -EPERM;
291
292 async->max_bufsize = bc.maximum_size;
293 }
294
295 if (bc.size) {
296 if (bc.size > async->max_bufsize)
297 return -EPERM;
298
299 if (s->busy) {
300 DPRINTK("subdevice is busy, cannot resize buffer\n");
301 return -EBUSY;
302 }
303 if (async->mmap_count) {
304 DPRINTK("subdevice is mmapped, cannot resize buffer\n");
305 return -EBUSY;
306 }
307
308 if (!async->prealloc_buf)
309 return -EINVAL;
310
311 /* make sure buffer is an integral number of pages
312 * (we round up) */
313 bc.size = (bc.size + PAGE_SIZE - 1) & PAGE_MASK;
314
315 ret = comedi_buf_alloc(dev, s, bc.size);
316 if (ret < 0)
317 return ret;
318
319 if (s->buf_change) {
320 ret = s->buf_change(dev, s, bc.size);
321 if (ret < 0)
322 return ret;
323 }
324
325 DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
326 dev->minor, bc.subdevice, async->prealloc_bufsz);
327 }
328
329 bc.size = async->prealloc_bufsz;
330 bc.maximum_size = async->max_bufsize;
331
332 copyback:
333 if (copy_to_user(arg, &bc, sizeof(comedi_bufconfig)))
334 return -EFAULT;
335
336 return 0;
337}
338
339/*
340 COMEDI_DEVINFO
341 device info ioctl
342
343 arg:
344 pointer to devinfo structure
345
346 reads:
347 none
348
349 writes:
350 devinfo structure
351
352*/
353static int do_devinfo_ioctl(comedi_device * dev, comedi_devinfo * arg,
354 struct file *file)
355{
356 comedi_devinfo devinfo;
357 const unsigned minor = iminor(file->f_dentry->d_inode);
358 struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(minor);
359 comedi_subdevice *read_subdev = comedi_get_read_subdevice(dev_file_info);
360 comedi_subdevice *write_subdev = comedi_get_write_subdevice(dev_file_info);
361
362 memset(&devinfo, 0, sizeof(devinfo));
363
364 /* fill devinfo structure */
365 devinfo.version_code = COMEDI_VERSION_CODE;
366 devinfo.n_subdevs = dev->n_subdevices;
367 memcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN);
368 memcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN);
369
370 if (read_subdev) {
371 devinfo.read_subdevice = read_subdev - dev->subdevices;
372 } else {
373 devinfo.read_subdevice = -1;
374 }
375 if (write_subdev) {
376 devinfo.write_subdevice = write_subdev - dev->subdevices;
377 } else {
378 devinfo.write_subdevice = -1;
379 }
380
381 if (copy_to_user(arg, &devinfo, sizeof(comedi_devinfo)))
382 return -EFAULT;
383
384 return 0;
385}
386
387/*
388 COMEDI_SUBDINFO
389 subdevice info ioctl
390
391 arg:
392 pointer to array of subdevice info structures
393
394 reads:
395 none
396
397 writes:
398 array of subdevice info structures at arg
399
400*/
401static int do_subdinfo_ioctl(comedi_device * dev, comedi_subdinfo * arg,
402 void *file)
403{
404 int ret, i;
405 comedi_subdinfo *tmp, *us;
406 comedi_subdevice *s;
407
408 tmp = kcalloc(dev->n_subdevices, sizeof(comedi_subdinfo), GFP_KERNEL);
409 if (!tmp)
410 return -ENOMEM;
411
412 /* fill subdinfo structs */
413 for (i = 0; i < dev->n_subdevices; i++) {
414 s = dev->subdevices + i;
415 us = tmp + i;
416
417 us->type = s->type;
418 us->n_chan = s->n_chan;
419 us->subd_flags = s->subdev_flags;
420 if (comedi_get_subdevice_runflags(s) & SRF_RUNNING)
421 us->subd_flags |= SDF_RUNNING;
422#define TIMER_nanosec 5 /* backwards compatibility */
423 us->timer_type = TIMER_nanosec;
424 us->len_chanlist = s->len_chanlist;
425 us->maxdata = s->maxdata;
426 if (s->range_table) {
427 us->range_type =
428 (i << 24) | (0 << 16) | (s->
429 range_table->length);
430 } else {
431 us->range_type = 0; /* XXX */
432 }
433 us->flags = s->flags;
434
435 if (s->busy)
436 us->subd_flags |= SDF_BUSY;
437 if (s->busy == file)
438 us->subd_flags |= SDF_BUSY_OWNER;
439 if (s->lock)
440 us->subd_flags |= SDF_LOCKED;
441 if (s->lock == file)
442 us->subd_flags |= SDF_LOCK_OWNER;
443 if (!s->maxdata && s->maxdata_list)
444 us->subd_flags |= SDF_MAXDATA;
445 if (s->flaglist)
446 us->subd_flags |= SDF_FLAGS;
447 if (s->range_table_list)
448 us->subd_flags |= SDF_RANGETYPE;
449 if (s->do_cmd)
450 us->subd_flags |= SDF_CMD;
451
452 if (s->insn_bits != &insn_inval)
453 us->insn_bits_support = COMEDI_SUPPORTED;
454 else
455 us->insn_bits_support = COMEDI_UNSUPPORTED;
456
457 us->settling_time_0 = s->settling_time_0;
458 }
459
460 ret = copy_to_user(arg, tmp,
461 dev->n_subdevices * sizeof(comedi_subdinfo));
462
463 kfree(tmp);
464
465 return ret ? -EFAULT : 0;
466}
467
468/*
469 COMEDI_CHANINFO
470 subdevice info ioctl
471
472 arg:
473 pointer to chaninfo structure
474
475 reads:
476 chaninfo structure at arg
477
478 writes:
479 arrays at elements of chaninfo structure
480
481*/
482static int do_chaninfo_ioctl(comedi_device * dev, comedi_chaninfo * arg)
483{
484 comedi_subdevice *s;
485 comedi_chaninfo it;
486
487 if (copy_from_user(&it, arg, sizeof(comedi_chaninfo)))
488 return -EFAULT;
489
490 if (it.subdev >= dev->n_subdevices)
491 return -EINVAL;
492 s = dev->subdevices + it.subdev;
493
494 if (it.maxdata_list) {
495 if (s->maxdata || !s->maxdata_list)
496 return -EINVAL;
497 if (copy_to_user(it.maxdata_list, s->maxdata_list,
498 s->n_chan * sizeof(lsampl_t)))
499 return -EFAULT;
500 }
501
502 if (it.flaglist) {
503 if (!s->flaglist)
504 return -EINVAL;
505 if (copy_to_user(it.flaglist, s->flaglist,
506 s->n_chan * sizeof(unsigned int)))
507 return -EFAULT;
508 }
509
510 if (it.rangelist) {
511 int i;
512
513 if (!s->range_table_list)
514 return -EINVAL;
515 for (i = 0; i < s->n_chan; i++) {
516 int x;
517
518 x = (dev->minor << 28) | (it.subdev << 24) | (i << 16) |
519 (s->range_table_list[i]->length);
520 put_user(x, it.rangelist + i);
521 }
522 //if(copy_to_user(it.rangelist,s->range_type_list,s->n_chan*sizeof(unsigned int)))
523 // return -EFAULT;
524 }
525
526 return 0;
527}
528
529 /*
530 COMEDI_BUFINFO
531 buffer information ioctl
532
533 arg:
534 pointer to bufinfo structure
535
536 reads:
537 bufinfo at arg
538
539 writes:
540 modified bufinfo at arg
541
542 */
543static int do_bufinfo_ioctl(comedi_device * dev, void *arg)
544{
545 comedi_bufinfo bi;
546 comedi_subdevice *s;
547 comedi_async *async;
548
549 if (copy_from_user(&bi, arg, sizeof(comedi_bufinfo)))
550 return -EFAULT;
551
552 if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0)
553 return -EINVAL;
554
555 s = dev->subdevices + bi.subdevice;
556 async = s->async;
557
558 if (!async) {
559 DPRINTK("subdevice does not have async capability\n");
560 bi.buf_write_ptr = 0;
561 bi.buf_read_ptr = 0;
562 bi.buf_write_count = 0;
563 bi.buf_read_count = 0;
564 goto copyback;
565 }
566
567 if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) {
568 bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read);
569 comedi_buf_read_free(async, bi.bytes_read);
570
571 if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR |
572 SRF_RUNNING))
573 && async->buf_write_count == async->buf_read_count) {
574 do_become_nonbusy(dev, s);
575 }
576 }
577
578 if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) {
579 bi.bytes_written =
580 comedi_buf_write_alloc(async, bi.bytes_written);
581 comedi_buf_write_free(async, bi.bytes_written);
582 }
583
584 bi.buf_write_count = async->buf_write_count;
585 bi.buf_write_ptr = async->buf_write_ptr;
586 bi.buf_read_count = async->buf_read_count;
587 bi.buf_read_ptr = async->buf_read_ptr;
588
589 copyback:
590 if (copy_to_user(arg, &bi, sizeof(comedi_bufinfo)))
591 return -EFAULT;
592
593 return 0;
594}
595
596static int parse_insn(comedi_device * dev, comedi_insn * insn, lsampl_t * data,
597 void *file);
598/*
599 * COMEDI_INSNLIST
600 * synchronous instructions
601 *
602 * arg:
603 * pointer to sync cmd structure
604 *
605 * reads:
606 * sync cmd struct at arg
607 * instruction list
608 * data (for writes)
609 *
610 * writes:
611 * data (for reads)
612 */
613/* arbitrary limits */
614#define MAX_SAMPLES 256
615static int do_insnlist_ioctl(comedi_device * dev, void *arg, void *file)
616{
617 comedi_insnlist insnlist;
618 comedi_insn *insns = NULL;
619 lsampl_t *data = NULL;
620 int i = 0;
621 int ret = 0;
622
623 if (copy_from_user(&insnlist, arg, sizeof(comedi_insnlist)))
624 return -EFAULT;
625
626 data = kmalloc(sizeof(lsampl_t) * MAX_SAMPLES, GFP_KERNEL);
627 if (!data) {
628 DPRINTK("kmalloc failed\n");
629 ret = -ENOMEM;
630 goto error;
631 }
632
633 insns = kmalloc(sizeof(comedi_insn) * insnlist.n_insns, GFP_KERNEL);
634 if (!insns) {
635 DPRINTK("kmalloc failed\n");
636 ret = -ENOMEM;
637 goto error;
638 }
639
640 if (copy_from_user(insns, insnlist.insns,
641 sizeof(comedi_insn) * insnlist.n_insns)) {
642 DPRINTK("copy_from_user failed\n");
643 ret = -EFAULT;
644 goto error;
645 }
646
647 for (i = 0; i < insnlist.n_insns; i++) {
648 if (insns[i].n > MAX_SAMPLES) {
649 DPRINTK("number of samples too large\n");
650 ret = -EINVAL;
651 goto error;
652 }
653 if (insns[i].insn & INSN_MASK_WRITE) {
654 if (copy_from_user(data, insns[i].data,
655 insns[i].n * sizeof(lsampl_t))) {
656 DPRINTK("copy_from_user failed\n");
657 ret = -EFAULT;
658 goto error;
659 }
660 }
661 ret = parse_insn(dev, insns + i, data, file);
662 if (ret < 0)
663 goto error;
664 if (insns[i].insn & INSN_MASK_READ) {
665 if (copy_to_user(insns[i].data, data,
666 insns[i].n * sizeof(lsampl_t))) {
667 DPRINTK("copy_to_user failed\n");
668 ret = -EFAULT;
669 goto error;
670 }
671 }
672 if (need_resched())
673 schedule();
674 }
675
676 error:
677 if (insns)
678 kfree(insns);
679 if (data)
680 kfree(data);
681
682 if (ret < 0)
683 return ret;
684 return i;
685}
686
687static int check_insn_config_length(comedi_insn * insn, lsampl_t * data)
688{
689 if(insn->n < 1) return -EINVAL;
690
691 switch (data[0]) {
692 case INSN_CONFIG_DIO_OUTPUT:
693 case INSN_CONFIG_DIO_INPUT:
694 case INSN_CONFIG_DISARM:
695 case INSN_CONFIG_RESET:
696 if (insn->n == 1)
697 return 0;
698 break;
699 case INSN_CONFIG_ARM:
700 case INSN_CONFIG_DIO_QUERY:
701 case INSN_CONFIG_BLOCK_SIZE:
702 case INSN_CONFIG_FILTER:
703 case INSN_CONFIG_SERIAL_CLOCK:
704 case INSN_CONFIG_BIDIRECTIONAL_DATA:
705 case INSN_CONFIG_ALT_SOURCE:
706 case INSN_CONFIG_SET_COUNTER_MODE:
707 case INSN_CONFIG_8254_READ_STATUS:
708 case INSN_CONFIG_SET_ROUTING:
709 case INSN_CONFIG_GET_ROUTING:
710 case INSN_CONFIG_GET_PWM_STATUS:
711 case INSN_CONFIG_PWM_SET_PERIOD:
712 case INSN_CONFIG_PWM_GET_PERIOD:
713 if (insn->n == 2)
714 return 0;
715 break;
716 case INSN_CONFIG_SET_GATE_SRC:
717 case INSN_CONFIG_GET_GATE_SRC:
718 case INSN_CONFIG_SET_CLOCK_SRC:
719 case INSN_CONFIG_GET_CLOCK_SRC:
720 case INSN_CONFIG_SET_OTHER_SRC:
721 case INSN_CONFIG_GET_COUNTER_STATUS:
722 case INSN_CONFIG_PWM_SET_H_BRIDGE:
723 case INSN_CONFIG_PWM_GET_H_BRIDGE:
724 case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE:
725 if (insn->n == 3)
726 return 0;
727 break;
728 case INSN_CONFIG_PWM_OUTPUT:
729 case INSN_CONFIG_ANALOG_TRIG:
730 if (insn->n == 5)
731 return 0;
732 break;
733 //by default we allow the insn since we don't have checks for all possible cases yet
734 default:
735 rt_printk
736 ("comedi: no check for data length of config insn id %i is implemented.\n"
737 " Add a check to %s in %s.\n"
738 " Assuming n=%i is correct.\n", data[0], __FUNCTION__,
739 __FILE__, insn->n);
740 return 0;
741 break;
742 }
743 return -EINVAL;
744}
745
746static int parse_insn(comedi_device * dev, comedi_insn * insn, lsampl_t * data,
747 void *file)
748{
749 comedi_subdevice *s;
750 int ret = 0;
751 int i;
752
753 if (insn->insn & INSN_MASK_SPECIAL) {
754 /* a non-subdevice instruction */
755
756 switch (insn->insn) {
757 case INSN_GTOD:
758 {
759 struct timeval tv;
760
761 if (insn->n != 2) {
762 ret = -EINVAL;
763 break;
764 }
765
766 do_gettimeofday(&tv);
767 data[0] = tv.tv_sec;
768 data[1] = tv.tv_usec;
769 ret = 2;
770
771 break;
772 }
773 case INSN_WAIT:
774 if (insn->n != 1 || data[0] >= 100000) {
775 ret = -EINVAL;
776 break;
777 }
778 udelay(data[0] / 1000);
779 ret = 1;
780 break;
781 case INSN_INTTRIG:
782 if (insn->n != 1) {
783 ret = -EINVAL;
784 break;
785 }
786 if (insn->subdev >= dev->n_subdevices) {
787 DPRINTK("%d not usable subdevice\n",
788 insn->subdev);
789 ret = -EINVAL;
790 break;
791 }
792 s = dev->subdevices + insn->subdev;
793 if (!s->async) {
794 DPRINTK("no async\n");
795 ret = -EINVAL;
796 break;
797 }
798 if (!s->async->inttrig) {
799 DPRINTK("no inttrig\n");
800 ret = -EAGAIN;
801 break;
802 }
803 ret = s->async->inttrig(dev, s, insn->data[0]);
804 if (ret >= 0)
805 ret = 1;
806 break;
807 default:
808 DPRINTK("invalid insn\n");
809 ret = -EINVAL;
810 break;
811 }
812 } else {
813 /* a subdevice instruction */
814 lsampl_t maxdata;
815
816 if (insn->subdev >= dev->n_subdevices) {
817 DPRINTK("subdevice %d out of range\n", insn->subdev);
818 ret = -EINVAL;
819 goto out;
820 }
821 s = dev->subdevices + insn->subdev;
822
823 if (s->type == COMEDI_SUBD_UNUSED) {
824 DPRINTK("%d not usable subdevice\n", insn->subdev);
825 ret = -EIO;
826 goto out;
827 }
828
829 /* are we locked? (ioctl lock) */
830 if (s->lock && s->lock != file) {
831 DPRINTK("device locked\n");
832 ret = -EACCES;
833 goto out;
834 }
835
836 if ((ret = check_chanlist(s, 1, &insn->chanspec)) < 0) {
837 ret = -EINVAL;
838 DPRINTK("bad chanspec\n");
839 goto out;
840 }
841
842 if (s->busy) {
843 ret = -EBUSY;
844 goto out;
845 }
846 /* This looks arbitrary. It is. */
847 s->busy = &parse_insn;
848 switch (insn->insn) {
849 case INSN_READ:
850 ret = s->insn_read(dev, s, insn, data);
851 break;
852 case INSN_WRITE:
853 maxdata = s->maxdata_list
854 ? s->maxdata_list[CR_CHAN(insn->chanspec)]
855 : s->maxdata;
856 for (i = 0; i < insn->n; ++i) {
857 if (data[i] > maxdata) {
858 ret = -EINVAL;
859 DPRINTK("bad data value(s)\n");
860 break;
861 }
862 }
863 if (ret == 0)
864 ret = s->insn_write(dev, s, insn, data);
865 break;
866 case INSN_BITS:
867 if (insn->n != 2) {
868 ret = -EINVAL;
869 break;
870 }
871 ret = s->insn_bits(dev, s, insn, data);
872 break;
873 case INSN_CONFIG:
874 ret = check_insn_config_length(insn, data);
875 if (ret)
876 break;
877 ret = s->insn_config(dev, s, insn, data);
878 break;
879 default:
880 ret = -EINVAL;
881 break;
882 }
883
884 s->busy = NULL;
885 }
886
887 out:
888 return ret;
889}
890
891/*
892 * COMEDI_INSN
893 * synchronous instructions
894 *
895 * arg:
896 * pointer to insn
897 *
898 * reads:
899 * comedi_insn struct at arg
900 * data (for writes)
901 *
902 * writes:
903 * data (for reads)
904 */
905static int do_insn_ioctl(comedi_device * dev, void *arg, void *file)
906{
907 comedi_insn insn;
908 lsampl_t *data = NULL;
909 int ret = 0;
910
911 data = kmalloc(sizeof(lsampl_t) * MAX_SAMPLES, GFP_KERNEL);
912 if (!data) {
913 ret = -ENOMEM;
914 goto error;
915 }
916
917 if (copy_from_user(&insn, arg, sizeof(comedi_insn))) {
918 ret = -EFAULT;
919 goto error;
920 }
921
922 /* This is where the behavior of insn and insnlist deviate. */
923 if (insn.n > MAX_SAMPLES)
924 insn.n = MAX_SAMPLES;
925 if (insn.insn & INSN_MASK_WRITE) {
926 if (copy_from_user(data, insn.data, insn.n * sizeof(lsampl_t))) {
927 ret = -EFAULT;
928 goto error;
929 }
930 }
931 ret = parse_insn(dev, &insn, data, file);
932 if (ret < 0)
933 goto error;
934 if (insn.insn & INSN_MASK_READ) {
935 if (copy_to_user(insn.data, data, insn.n * sizeof(lsampl_t))) {
936 ret = -EFAULT;
937 goto error;
938 }
939 }
940 ret = insn.n;
941
942 error:
943 if (data)
944 kfree(data);
945
946 return ret;
947}
948
949/*
950 COMEDI_CMD
951 command ioctl
952
953 arg:
954 pointer to cmd structure
955
956 reads:
957 cmd structure at arg
958 channel/range list
959
960 writes:
961 modified cmd structure at arg
962
963*/
964static int do_cmd_ioctl(comedi_device * dev, void *arg, void *file)
965{
966 comedi_cmd user_cmd;
967 comedi_subdevice *s;
968 comedi_async *async;
969 int ret = 0;
970 unsigned int *chanlist_saver = NULL;
971
972 if (copy_from_user(&user_cmd, arg, sizeof(comedi_cmd))) {
973 DPRINTK("bad cmd address\n");
974 return -EFAULT;
975 }
976 // save user's chanlist pointer so it can be restored later
977 chanlist_saver = user_cmd.chanlist;
978
979 if (user_cmd.subdev >= dev->n_subdevices) {
980 DPRINTK("%d no such subdevice\n", user_cmd.subdev);
981 return -ENODEV;
982 }
983
984 s = dev->subdevices + user_cmd.subdev;
985 async = s->async;
986
987 if (s->type == COMEDI_SUBD_UNUSED) {
988 DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
989 return -EIO;
990 }
991
992 if (!s->do_cmd || !s->do_cmdtest || !s->async) {
993 DPRINTK("subdevice %i does not support commands\n",
994 user_cmd.subdev);
995 return -EIO;
996 }
997
998 /* are we locked? (ioctl lock) */
999 if (s->lock && s->lock != file) {
1000 DPRINTK("subdevice locked\n");
1001 return -EACCES;
1002 }
1003
1004 /* are we busy? */
1005 if (s->busy) {
1006 DPRINTK("subdevice busy\n");
1007 return -EBUSY;
1008 }
1009 s->busy = file;
1010
1011 /* make sure channel/gain list isn't too long */
1012 if (user_cmd.chanlist_len > s->len_chanlist) {
1013 DPRINTK("channel/gain list too long %u > %d\n",
1014 user_cmd.chanlist_len, s->len_chanlist);
1015 ret = -EINVAL;
1016 goto cleanup;
1017 }
1018
1019 /* make sure channel/gain list isn't too short */
1020 if (user_cmd.chanlist_len < 1) {
1021 DPRINTK("channel/gain list too short %u < 1\n",
1022 user_cmd.chanlist_len);
1023 ret = -EINVAL;
1024 goto cleanup;
1025 }
1026
1027 if (async->cmd.chanlist)
1028 kfree(async->cmd.chanlist);
1029 async->cmd = user_cmd;
1030 async->cmd.data = NULL;
1031 /* load channel/gain list */
1032 async->cmd.chanlist =
1033 kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1034 if (!async->cmd.chanlist) {
1035 DPRINTK("allocation failed\n");
1036 ret = -ENOMEM;
1037 goto cleanup;
1038 }
1039
1040 if (copy_from_user(async->cmd.chanlist, user_cmd.chanlist,
1041 async->cmd.chanlist_len * sizeof(int))) {
1042 DPRINTK("fault reading chanlist\n");
1043 ret = -EFAULT;
1044 goto cleanup;
1045 }
1046
1047 /* make sure each element in channel/gain list is valid */
1048 if ((ret = check_chanlist(s, async->cmd.chanlist_len,
1049 async->cmd.chanlist)) < 0) {
1050 DPRINTK("bad chanlist\n");
1051 goto cleanup;
1052 }
1053
1054 ret = s->do_cmdtest(dev, s, &async->cmd);
1055
1056 if (async->cmd.flags & TRIG_BOGUS || ret) {
1057 DPRINTK("test returned %d\n", ret);
1058 user_cmd = async->cmd;
1059 // restore chanlist pointer before copying back
1060 user_cmd.chanlist = chanlist_saver;
1061 user_cmd.data = NULL;
1062 if (copy_to_user(arg, &user_cmd, sizeof(comedi_cmd))) {
1063 DPRINTK("fault writing cmd\n");
1064 ret = -EFAULT;
1065 goto cleanup;
1066 }
1067 ret = -EAGAIN;
1068 goto cleanup;
1069 }
1070
1071 if (!async->prealloc_bufsz) {
1072 ret = -ENOMEM;
1073 DPRINTK("no buffer (?)\n");
1074 goto cleanup;
1075 }
1076
1077 comedi_reset_async_buf(async);
1078
1079 async->cb_mask =
1080 COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
1081 COMEDI_CB_OVERFLOW;
1082 if (async->cmd.flags & TRIG_WAKE_EOS) {
1083 async->cb_mask |= COMEDI_CB_EOS;
1084 }
1085
1086 comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING);
1087
1088#ifdef CONFIG_COMEDI_RT
1089 if (async->cmd.flags & TRIG_RT) {
1090 if (comedi_switch_to_rt(dev) == 0)
1091 comedi_set_subdevice_runflags(s, SRF_RT, SRF_RT);
1092 }
1093#endif
1094
1095 ret = s->do_cmd(dev, s);
1096 if (ret == 0)
1097 return 0;
1098
1099 cleanup:
1100 do_become_nonbusy(dev, s);
1101
1102 return ret;
1103}
1104
1105/*
1106 COMEDI_CMDTEST
1107 command testing ioctl
1108
1109 arg:
1110 pointer to cmd structure
1111
1112 reads:
1113 cmd structure at arg
1114 channel/range list
1115
1116 writes:
1117 modified cmd structure at arg
1118
1119*/
1120static int do_cmdtest_ioctl(comedi_device * dev, void *arg, void *file)
1121{
1122 comedi_cmd user_cmd;
1123 comedi_subdevice *s;
1124 int ret = 0;
1125 unsigned int *chanlist = NULL;
1126 unsigned int *chanlist_saver = NULL;
1127
1128 if (copy_from_user(&user_cmd, arg, sizeof(comedi_cmd))) {
1129 DPRINTK("bad cmd address\n");
1130 return -EFAULT;
1131 }
1132 // save user's chanlist pointer so it can be restored later
1133 chanlist_saver = user_cmd.chanlist;
1134
1135 if (user_cmd.subdev >= dev->n_subdevices) {
1136 DPRINTK("%d no such subdevice\n", user_cmd.subdev);
1137 return -ENODEV;
1138 }
1139
1140 s = dev->subdevices + user_cmd.subdev;
1141 if (s->type == COMEDI_SUBD_UNUSED) {
1142 DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
1143 return -EIO;
1144 }
1145
1146 if (!s->do_cmd || !s->do_cmdtest) {
1147 DPRINTK("subdevice %i does not support commands\n",
1148 user_cmd.subdev);
1149 return -EIO;
1150 }
1151
1152 /* make sure channel/gain list isn't too long */
1153 if (user_cmd.chanlist_len > s->len_chanlist) {
1154 DPRINTK("channel/gain list too long %d > %d\n",
1155 user_cmd.chanlist_len, s->len_chanlist);
1156 ret = -EINVAL;
1157 goto cleanup;
1158 }
1159
1160 /* load channel/gain list */
1161 if (user_cmd.chanlist) {
1162 chanlist =
1163 kmalloc(user_cmd.chanlist_len * sizeof(int),
1164 GFP_KERNEL);
1165 if (!chanlist) {
1166 DPRINTK("allocation failed\n");
1167 ret = -ENOMEM;
1168 goto cleanup;
1169 }
1170
1171 if (copy_from_user(chanlist, user_cmd.chanlist,
1172 user_cmd.chanlist_len * sizeof(int))) {
1173 DPRINTK("fault reading chanlist\n");
1174 ret = -EFAULT;
1175 goto cleanup;
1176 }
1177
1178 /* make sure each element in channel/gain list is valid */
1179 if ((ret = check_chanlist(s, user_cmd.chanlist_len,
1180 chanlist)) < 0) {
1181 DPRINTK("bad chanlist\n");
1182 goto cleanup;
1183 }
1184
1185 user_cmd.chanlist = chanlist;
1186 }
1187
1188 ret = s->do_cmdtest(dev, s, &user_cmd);
1189
1190 // restore chanlist pointer before copying back
1191 user_cmd.chanlist = chanlist_saver;
1192
1193 if (copy_to_user(arg, &user_cmd, sizeof(comedi_cmd))) {
1194 DPRINTK("bad cmd address\n");
1195 ret = -EFAULT;
1196 goto cleanup;
1197 }
1198 cleanup:
1199 if (chanlist)
1200 kfree(chanlist);
1201
1202 return ret;
1203}
1204
1205/*
1206 COMEDI_LOCK
1207 lock subdevice
1208
1209 arg:
1210 subdevice number
1211
1212 reads:
1213 none
1214
1215 writes:
1216 none
1217
1218*/
1219
1220static int do_lock_ioctl(comedi_device * dev, unsigned int arg, void *file)
1221{
1222 int ret = 0;
1223 unsigned long flags;
1224 comedi_subdevice *s;
1225
1226 if (arg >= dev->n_subdevices)
1227 return -EINVAL;
1228 s = dev->subdevices + arg;
1229
1230 comedi_spin_lock_irqsave(&s->spin_lock, flags);
1231 if (s->busy || s->lock) {
1232 ret = -EBUSY;
1233 } else {
1234 s->lock = file;
1235 }
1236 comedi_spin_unlock_irqrestore(&s->spin_lock, flags);
1237
1238 if (ret < 0)
1239 return ret;
1240
1241#if 0
1242 if (s->lock_f)
1243 ret = s->lock_f(dev, s);
1244#endif
1245
1246 return ret;
1247}
1248
1249/*
1250 COMEDI_UNLOCK
1251 unlock subdevice
1252
1253 arg:
1254 subdevice number
1255
1256 reads:
1257 none
1258
1259 writes:
1260 none
1261
1262 This function isn't protected by the semaphore, since
1263 we already own the lock.
1264*/
1265static int do_unlock_ioctl(comedi_device * dev, unsigned int arg, void *file)
1266{
1267 comedi_subdevice *s;
1268
1269 if (arg >= dev->n_subdevices)
1270 return -EINVAL;
1271 s = dev->subdevices + arg;
1272
1273 if (s->busy)
1274 return -EBUSY;
1275
1276 if (s->lock && s->lock != file)
1277 return -EACCES;
1278
1279 if (s->lock == file) {
1280#if 0
1281 if (s->unlock)
1282 s->unlock(dev, s);
1283#endif
1284
1285 s->lock = NULL;
1286 }
1287
1288 return 0;
1289}
1290
1291/*
1292 COMEDI_CANCEL
1293 cancel acquisition ioctl
1294
1295 arg:
1296 subdevice number
1297
1298 reads:
1299 nothing
1300
1301 writes:
1302 nothing
1303
1304*/
1305static int do_cancel_ioctl(comedi_device * dev, unsigned int arg, void *file)
1306{
1307 comedi_subdevice *s;
1308
1309 if (arg >= dev->n_subdevices)
1310 return -EINVAL;
1311 s = dev->subdevices + arg;
1312 if (s->async == NULL)
1313 return -EINVAL;
1314
1315 if (s->lock && s->lock != file)
1316 return -EACCES;
1317
1318 if (!s->busy)
1319 return 0;
1320
1321 if (s->busy != file)
1322 return -EBUSY;
1323
1324 return do_cancel(dev, s);
1325}
1326
1327/*
1328 COMEDI_POLL ioctl
1329 instructs driver to synchronize buffers
1330
1331 arg:
1332 subdevice number
1333
1334 reads:
1335 nothing
1336
1337 writes:
1338 nothing
1339
1340*/
1341static int do_poll_ioctl(comedi_device * dev, unsigned int arg, void *file)
1342{
1343 comedi_subdevice *s;
1344
1345 if (arg >= dev->n_subdevices)
1346 return -EINVAL;
1347 s = dev->subdevices + arg;
1348
1349 if (s->lock && s->lock != file)
1350 return -EACCES;
1351
1352 if (!s->busy)
1353 return 0;
1354
1355 if (s->busy != file)
1356 return -EBUSY;
1357
1358 if (s->poll)
1359 return s->poll(dev, s);
1360
1361 return -EINVAL;
1362}
1363
1364static int do_cancel(comedi_device * dev, comedi_subdevice * s)
1365{
1366 int ret = 0;
1367
1368 if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) && s->cancel)
1369 ret = s->cancel(dev, s);
1370
1371 do_become_nonbusy(dev, s);
1372
1373 return ret;
1374}
1375
1376void comedi_unmap(struct vm_area_struct *area)
1377{
1378 comedi_async *async;
1379 comedi_device *dev;
1380
1381 async = area->vm_private_data;
1382 dev = async->subdevice->device;
1383
1384 mutex_lock(&dev->mutex);
1385 async->mmap_count--;
1386 mutex_unlock(&dev->mutex);
1387}
1388
1389static struct vm_operations_struct comedi_vm_ops = {
1390 close:comedi_unmap,
1391};
1392
1393static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
1394{
1395 const unsigned minor = iminor(file->f_dentry->d_inode);
1396 struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(minor);
1397 comedi_device *dev = dev_file_info->device;
1398 comedi_async *async = NULL;
1399 unsigned long start = vma->vm_start;
1400 unsigned long size;
1401 int n_pages;
1402 int i;
1403 int retval;
1404 comedi_subdevice *s;
1405
1406 mutex_lock(&dev->mutex);
1407 if (!dev->attached) {
1408 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1409 retval = -ENODEV;
1410 goto done;
1411 }
1412 if (vma->vm_flags & VM_WRITE) {
1413 s = comedi_get_write_subdevice(dev_file_info);
1414 } else {
1415 s = comedi_get_read_subdevice(dev_file_info);
1416 }
1417 if (s == NULL) {
1418 retval = -EINVAL;
1419 goto done;
1420 }
1421 async = s->async;
1422 if (async == NULL) {
1423 retval = -EINVAL;
1424 goto done;
1425 }
1426
1427 if (vma->vm_pgoff != 0) {
1428 DPRINTK("comedi: mmap() offset must be 0.\n");
1429 retval = -EINVAL;
1430 goto done;
1431 }
1432
1433 size = vma->vm_end - vma->vm_start;
1434 if (size > async->prealloc_bufsz) {
1435 retval = -EFAULT;
1436 goto done;
1437 }
1438 if (size & (~PAGE_MASK)) {
1439 retval = -EFAULT;
1440 goto done;
1441 }
1442
1443 n_pages = size >> PAGE_SHIFT;
1444 for (i = 0; i < n_pages; ++i) {
1445 if (remap_pfn_range(vma, start,
1446 page_to_pfn(virt_to_page(async->
1447 buf_page_list[i].virt_addr)),
1448 PAGE_SIZE, PAGE_SHARED)) {
1449 retval = -EAGAIN;
1450 goto done;
1451 }
1452 start += PAGE_SIZE;
1453 }
1454
1455 vma->vm_ops = &comedi_vm_ops;
1456 vma->vm_private_data = async;
1457
1458 async->mmap_count++;
1459
1460 retval = 0;
1461 done:
1462 mutex_unlock(&dev->mutex);
1463 return retval;
1464}
1465
1466static unsigned int comedi_poll(struct file *file, poll_table * wait)
1467{
1468 unsigned int mask = 0;
1469 const unsigned minor = iminor(file->f_dentry->d_inode);
1470 struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(minor);
1471 comedi_device *dev = dev_file_info->device;
1472 comedi_subdevice *read_subdev;
1473 comedi_subdevice *write_subdev;
1474
1475 mutex_lock(&dev->mutex);
1476 if (!dev->attached) {
1477 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1478 mutex_unlock(&dev->mutex);
1479 return 0;
1480 }
1481
1482 mask = 0;
1483 read_subdev = comedi_get_read_subdevice(dev_file_info);
1484 if (read_subdev) {
1485 poll_wait(file, &read_subdev->async->wait_head, wait);
1486 if (!read_subdev->busy
1487 || comedi_buf_read_n_available(read_subdev->async) > 0
1488 || !(comedi_get_subdevice_runflags(read_subdev) &
1489 SRF_RUNNING)) {
1490 mask |= POLLIN | POLLRDNORM;
1491 }
1492 }
1493 write_subdev = comedi_get_write_subdevice(dev_file_info);
1494 if (write_subdev) {
1495 poll_wait(file, &write_subdev->async->wait_head, wait);
1496 comedi_buf_write_alloc(write_subdev->async, write_subdev->async->prealloc_bufsz);
1497 if (!write_subdev->busy
1498 || !(comedi_get_subdevice_runflags(write_subdev) &
1499 SRF_RUNNING)
1500 || comedi_buf_write_n_allocated(write_subdev->async) >=
1501 bytes_per_sample(write_subdev->async->subdevice)) {
1502 mask |= POLLOUT | POLLWRNORM;
1503 }
1504 }
1505
1506 mutex_unlock(&dev->mutex);
1507 return mask;
1508}
1509
1510static ssize_t comedi_write(struct file *file, const char *buf, size_t nbytes,
1511 loff_t * offset)
1512{
1513 comedi_subdevice *s;
1514 comedi_async *async;
1515 int n, m, count = 0, retval = 0;
1516 DECLARE_WAITQUEUE(wait, current);
1517 const unsigned minor = iminor(file->f_dentry->d_inode);
1518 struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(minor);
1519 comedi_device *dev = dev_file_info->device;
1520
1521 if (!dev->attached) {
1522 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1523 retval = -ENODEV;
1524 goto done;
1525 }
1526
1527 s = comedi_get_write_subdevice(dev_file_info);
1528 if (s == NULL) {
1529 retval = -EIO;
1530 goto done;
1531 }
1532 async = s->async;
1533
1534 if (!nbytes) {
1535 retval = 0;
1536 goto done;
1537 }
1538 if (!s->busy) {
1539 retval = 0;
1540 goto done;
1541 }
1542 if (s->busy != file) {
1543 retval = -EACCES;
1544 goto done;
1545 }
1546 add_wait_queue(&async->wait_head, &wait);
1547 while (nbytes > 0 && !retval) {
1548 set_current_state(TASK_INTERRUPTIBLE);
1549
1550 n = nbytes;
1551
1552 m = n;
1553 if (async->buf_write_ptr + m > async->prealloc_bufsz) {
1554 m = async->prealloc_bufsz - async->buf_write_ptr;
1555 }
1556 comedi_buf_write_alloc(async, async->prealloc_bufsz);
1557 if (m > comedi_buf_write_n_allocated(async)) {
1558 m = comedi_buf_write_n_allocated(async);
1559 }
1560 if (m < n)
1561 n = m;
1562
1563 if (n == 0) {
1564 if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1565 if (comedi_get_subdevice_runflags(s) &
1566 SRF_ERROR) {
1567 retval = -EPIPE;
1568 } else {
1569 retval = 0;
1570 }
1571 do_become_nonbusy(dev, s);
1572 break;
1573 }
1574 if (file->f_flags & O_NONBLOCK) {
1575 retval = -EAGAIN;
1576 break;
1577 }
1578 if (signal_pending(current)) {
1579 retval = -ERESTARTSYS;
1580 break;
1581 }
1582 schedule();
1583 if (!s->busy) {
1584 break;
1585 }
1586 if (s->busy != file) {
1587 retval = -EACCES;
1588 break;
1589 }
1590 continue;
1591 }
1592
1593 m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
1594 buf, n);
1595 if (m) {
1596 n -= m;
1597 retval = -EFAULT;
1598 }
1599 comedi_buf_write_free(async, n);
1600
1601 count += n;
1602 nbytes -= n;
1603
1604 buf += n;
1605 break; /* makes device work like a pipe */
1606 }
1607 set_current_state(TASK_RUNNING);
1608 remove_wait_queue(&async->wait_head, &wait);
1609
1610done:
1611 return (count ? count : retval);
1612}
1613
1614static ssize_t comedi_read(struct file *file, char *buf, size_t nbytes,
1615 loff_t * offset)
1616{
1617 comedi_subdevice *s;
1618 comedi_async *async;
1619 int n, m, count = 0, retval = 0;
1620 DECLARE_WAITQUEUE(wait, current);
1621 const unsigned minor = iminor(file->f_dentry->d_inode);
1622 struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(minor);
1623 comedi_device *dev = dev_file_info->device;
1624
1625 if (!dev->attached) {
1626 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1627 retval = -ENODEV;
1628 goto done;
1629 }
1630
1631 s = comedi_get_read_subdevice(dev_file_info);
1632 if (s == NULL) {
1633 retval = -EIO;
1634 goto done;
1635 }
1636 async = s->async;
1637 if (!nbytes) {
1638 retval = 0;
1639 goto done;
1640 }
1641 if (!s->busy) {
1642 retval = 0;
1643 goto done;
1644 }
1645 if (s->busy != file) {
1646 retval = -EACCES;
1647 goto done;
1648 }
1649
1650 add_wait_queue(&async->wait_head, &wait);
1651 while (nbytes > 0 && !retval) {
1652 set_current_state(TASK_INTERRUPTIBLE);
1653
1654 n = nbytes;
1655
1656 m = comedi_buf_read_n_available(async);
1657//printk("%d available\n",m);
1658 if (async->buf_read_ptr + m > async->prealloc_bufsz) {
1659 m = async->prealloc_bufsz - async->buf_read_ptr;
1660 }
1661//printk("%d contiguous\n",m);
1662 if (m < n)
1663 n = m;
1664
1665 if (n == 0) {
1666 if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1667 do_become_nonbusy(dev, s);
1668 if (comedi_get_subdevice_runflags(s) &
1669 SRF_ERROR) {
1670 retval = -EPIPE;
1671 } else {
1672 retval = 0;
1673 }
1674 break;
1675 }
1676 if (file->f_flags & O_NONBLOCK) {
1677 retval = -EAGAIN;
1678 break;
1679 }
1680 if (signal_pending(current)) {
1681 retval = -ERESTARTSYS;
1682 break;
1683 }
1684 schedule();
1685 if (!s->busy) {
1686 retval = 0;
1687 break;
1688 }
1689 if (s->busy != file) {
1690 retval = -EACCES;
1691 break;
1692 }
1693 continue;
1694 }
1695 m = copy_to_user(buf, async->prealloc_buf +
1696 async->buf_read_ptr, n);
1697 if (m) {
1698 n -= m;
1699 retval = -EFAULT;
1700 }
1701
1702 comedi_buf_read_alloc(async, n);
1703 comedi_buf_read_free(async, n);
1704
1705 count += n;
1706 nbytes -= n;
1707
1708 buf += n;
1709 break; /* makes device work like a pipe */
1710 }
1711 if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) &&
1712 async->buf_read_count - async->buf_write_count == 0) {
1713 do_become_nonbusy(dev, s);
1714 }
1715 set_current_state(TASK_RUNNING);
1716 remove_wait_queue(&async->wait_head, &wait);
1717
1718done:
1719 return (count ? count : retval);
1720}
1721
1722/*
1723 This function restores a subdevice to an idle state.
1724 */
1725void do_become_nonbusy(comedi_device * dev, comedi_subdevice * s)
1726{
1727 comedi_async *async = s->async;
1728
1729 comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
1730#ifdef CONFIG_COMEDI_RT
1731 if (comedi_get_subdevice_runflags(s) & SRF_RT) {
1732 comedi_switch_to_non_rt(dev);
1733 comedi_set_subdevice_runflags(s, SRF_RT, 0);
1734 }
1735#endif
1736 if (async) {
1737 comedi_reset_async_buf(async);
1738 async->inttrig = NULL;
1739 } else {
1740 printk("BUG: (?) do_become_nonbusy called with async=0\n");
1741 }
1742
1743 s->busy = NULL;
1744}
1745
1746static int comedi_open(struct inode *inode, struct file *file)
1747{
1748 char mod[32];
1749 const unsigned minor = iminor(inode);
1750 struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(minor);
1751 comedi_device *dev = dev_file_info->device;
1752 if (dev == NULL) {
1753 DPRINTK("invalid minor number\n");
1754 return -ENODEV;
1755 }
1756
1757 /* This is slightly hacky, but we want module autoloading
1758 * to work for root.
1759 * case: user opens device, attached -> ok
1760 * case: user opens device, unattached, in_request_module=0 -> autoload
1761 * case: user opens device, unattached, in_request_module=1 -> fail
1762 * case: root opens device, attached -> ok
1763 * case: root opens device, unattached, in_request_module=1 -> ok
1764 * (typically called from modprobe)
1765 * case: root opens device, unattached, in_request_module=0 -> autoload
1766 *
1767 * The last could be changed to "-> ok", which would deny root
1768 * autoloading.
1769 */
1770 mutex_lock(&dev->mutex);
1771 if (dev->attached)
1772 goto ok;
1773 if (!capable(CAP_SYS_MODULE) && dev->in_request_module) {
1774 DPRINTK("in request module\n");
1775 mutex_unlock(&dev->mutex);
1776 return -ENODEV;
1777 }
1778 if (capable(CAP_SYS_MODULE) && dev->in_request_module)
1779 goto ok;
1780
1781 dev->in_request_module = 1;
1782
1783 sprintf(mod, "char-major-%i-%i", COMEDI_MAJOR, dev->minor);
1784#ifdef CONFIG_KMOD
1785 mutex_unlock(&dev->mutex);
1786 request_module(mod);
1787 mutex_lock(&dev->mutex);
1788#endif
1789
1790 dev->in_request_module = 0;
1791
1792 if (!dev->attached && !capable(CAP_SYS_MODULE)) {
1793 DPRINTK("not attached and not CAP_SYS_MODULE\n");
1794 mutex_unlock(&dev->mutex);
1795 return -ENODEV;
1796 }
1797ok:
1798 __module_get(THIS_MODULE);
1799
1800 if (dev->attached) {
1801 if (!try_module_get(dev->driver->module)) {
1802 module_put(THIS_MODULE);
1803 mutex_unlock(&dev->mutex);
1804 return -ENOSYS;
1805 }
1806 }
1807
1808 if (dev->attached && dev->use_count == 0 && dev->open) {
1809 dev->open(dev);
1810 }
1811
1812 dev->use_count++;
1813
1814 mutex_unlock(&dev->mutex);
1815
1816 return 0;
1817}
1818
1819static int comedi_close(struct inode *inode, struct file *file)
1820{
1821 const unsigned minor = iminor(inode);
1822 struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(minor);
1823 comedi_device *dev = dev_file_info->device;
1824 comedi_subdevice *s = NULL;
1825 int i;
1826
1827 mutex_lock(&dev->mutex);
1828
1829 if (dev->subdevices) {
1830 for (i = 0; i < dev->n_subdevices; i++) {
1831 s = dev->subdevices + i;
1832
1833 if (s->busy == file) {
1834 do_cancel(dev, s);
1835 }
1836 if (s->lock == file) {
1837 s->lock = NULL;
1838 }
1839 }
1840 }
1841 if (dev->attached && dev->use_count == 1 && dev->close) {
1842 dev->close(dev);
1843 }
1844
1845 module_put(THIS_MODULE);
1846 if (dev->attached) {
1847 module_put(dev->driver->module);
1848 }
1849
1850 dev->use_count--;
1851
1852 mutex_unlock(&dev->mutex);
1853
1854 if (file->f_flags & FASYNC) {
1855 comedi_fasync(-1, file, 0);
1856 }
1857
1858 return 0;
1859}
1860
1861static int comedi_fasync(int fd, struct file *file, int on)
1862{
1863 const unsigned minor = iminor(file->f_dentry->d_inode);
1864 struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(minor);
1865 comedi_device *dev = dev_file_info->device;
1866
1867 return fasync_helper(fd, file, on, &dev->async_queue);
1868}
1869
1870const struct file_operations comedi_fops = {
1871 owner:THIS_MODULE,
1872#ifdef HAVE_UNLOCKED_IOCTL
1873 unlocked_ioctl:comedi_unlocked_ioctl,
1874#else
1875 ioctl:comedi_ioctl,
1876#endif
1877#ifdef HAVE_COMPAT_IOCTL
1878 compat_ioctl:comedi_compat_ioctl,
1879#endif
1880 open:comedi_open,
1881 release:comedi_close,
1882 read:comedi_read,
1883 write:comedi_write,
1884 mmap:comedi_mmap,
1885 poll:comedi_poll,
1886 fasync:comedi_fasync,
1887};
1888
1889struct class *comedi_class = NULL;
1890static struct cdev comedi_cdev;
1891
1892static void comedi_cleanup_legacy_minors(void)
1893{
1894 unsigned i;
1895 for (i = 0; i < COMEDI_NUM_LEGACY_MINORS; i++) {
1896 comedi_free_board_minor(i);
1897 }
1898}
1899
1900static int __init comedi_init(void)
1901{
1902 int i;
1903 int retval;
1904
1905 printk("comedi: version " COMEDI_RELEASE
1906 " - http://www.comedi.org\n");
1907
1908 memset(comedi_file_info_table, 0, sizeof(struct comedi_device_file_info*) * COMEDI_NUM_MINORS);
1909
1910 retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1911 COMEDI_NUM_MINORS, "comedi");
1912 if (retval)
1913 return -EIO;
1914 cdev_init(&comedi_cdev, &comedi_fops);
1915 comedi_cdev.owner = THIS_MODULE;
1916 kobject_set_name(&comedi_cdev.kobj, "comedi");
1917 if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
1918 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1919 COMEDI_NUM_MINORS);
1920 return -EIO;
1921 }
1922 comedi_class = class_create(THIS_MODULE, "comedi");
1923 if (IS_ERR(comedi_class)) {
1924 printk("comedi: failed to create class");
1925 cdev_del(&comedi_cdev);
1926 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1927 COMEDI_NUM_MINORS);
1928 return PTR_ERR(comedi_class);
1929 }
1930
1931 /* XXX requires /proc interface */
1932 comedi_proc_init();
1933
1934 // create devices files for legacy/manual use
1935 for (i = 0; i < COMEDI_NUM_LEGACY_MINORS; i++) {
1936 int minor;
1937 minor = comedi_alloc_board_minor(NULL);
1938 if(minor < 0)
1939 {
1940 comedi_cleanup_legacy_minors();
1941 cdev_del(&comedi_cdev);
1942 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1943 COMEDI_NUM_MINORS);
1944 return minor;
1945 }
1946 }
1947
1948 comedi_rt_init();
1949
1950 comedi_register_ioctl32();
1951
1952 return 0;
1953}
1954
1955static void __exit comedi_cleanup(void)
1956{
1957 int i;
1958
1959 comedi_cleanup_legacy_minors();
1960 for(i = 0; i < COMEDI_NUM_MINORS; ++i)
1961 {
1962 BUG_ON(comedi_file_info_table[i]);
1963 }
1964
1965 class_destroy(comedi_class);
1966 cdev_del(&comedi_cdev);
1967 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
1968
1969 comedi_proc_cleanup();
1970
1971 comedi_rt_cleanup();
1972
1973 comedi_unregister_ioctl32();
1974}
1975
1976module_init(comedi_init);
1977module_exit(comedi_cleanup);
1978
1979void comedi_error(const comedi_device * dev, const char *s)
1980{
1981 rt_printk("comedi%d: %s: %s\n", dev->minor, dev->driver->driver_name,
1982 s);
1983}
1984
1985void comedi_event(comedi_device * dev, comedi_subdevice * s)
1986{
1987 comedi_async *async = s->async;
1988 unsigned runflags = 0;
1989 unsigned runflags_mask = 0;
1990
1991 //DPRINTK("comedi_event 0x%x\n",mask);
1992
1993 if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0)
1994 return;
1995
1996 if (s->async->
1997 events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW))
1998 {
1999 runflags_mask |= SRF_RUNNING;
2000 }
2001 /* remember if an error event has occured, so an error
2002 * can be returned the next time the user does a read() */
2003 if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2004 runflags_mask |= SRF_ERROR;
2005 runflags |= SRF_ERROR;
2006 }
2007 if (runflags_mask) {
2008 /*sets SRF_ERROR and SRF_RUNNING together atomically */
2009 comedi_set_subdevice_runflags(s, runflags_mask, runflags);
2010 }
2011
2012 if (async->cb_mask & s->async->events) {
2013 if (comedi_get_subdevice_runflags(s) & SRF_USER) {
2014
2015 if (dev->rt) {
2016#ifdef CONFIG_COMEDI_RT
2017 // pend wake up
2018 comedi_rt_pend_wakeup(&async->wait_head);
2019#else
2020 printk("BUG: comedi_event() code unreachable\n");
2021#endif
2022 } else {
2023 wake_up_interruptible(&async->wait_head);
2024 if (s->subdev_flags & SDF_CMD_READ) {
2025 kill_fasync(&dev->async_queue, SIGIO,
2026 POLL_IN);
2027 }
2028 if (s->subdev_flags & SDF_CMD_WRITE) {
2029 kill_fasync(&dev->async_queue, SIGIO,
2030 POLL_OUT);
2031 }
2032 }
2033 } else {
2034 if (async->cb_func)
2035 async->cb_func(s->async->events, async->cb_arg);
2036 /* XXX bug here. If subdevice A is rt, and
2037 * subdevice B tries to callback to a normal
2038 * linux kernel function, it will be at the
2039 * wrong priority. Since this isn't very
2040 * common, I'm not going to worry about it. */
2041 }
2042 }
2043 s->async->events = 0;
2044}
2045
2046void comedi_set_subdevice_runflags(comedi_subdevice * s, unsigned mask,
2047 unsigned bits)
2048{
2049 unsigned long flags;
2050
2051 comedi_spin_lock_irqsave(&s->spin_lock, flags);
2052 s->runflags &= ~mask;
2053 s->runflags |= (bits & mask);
2054 comedi_spin_unlock_irqrestore(&s->spin_lock, flags);
2055}
2056
2057unsigned comedi_get_subdevice_runflags(comedi_subdevice * s)
2058{
2059 unsigned long flags;
2060 unsigned runflags;
2061
2062 comedi_spin_lock_irqsave(&s->spin_lock, flags);
2063 runflags = s->runflags;
2064 comedi_spin_unlock_irqrestore(&s->spin_lock, flags);
2065 return runflags;
2066}
2067
2068static int is_device_busy(comedi_device * dev)
2069{
2070 comedi_subdevice *s;
2071 int i;
2072
2073 if (!dev->attached)
2074 return 0;
2075
2076 for (i = 0; i < dev->n_subdevices; i++) {
2077 s = dev->subdevices + i;
2078 if (s->busy)
2079 return 1;
2080 if (s->async && s->async->mmap_count)
2081 return 1;
2082 }
2083
2084 return 0;
2085}
2086
2087void comedi_device_init(comedi_device *dev)
2088{
2089 memset(dev, 0, sizeof(comedi_device));
2090 spin_lock_init(&dev->spinlock);
2091 mutex_init(&dev->mutex);
2092 dev->minor = -1;
2093}
2094
2095void comedi_device_cleanup(comedi_device *dev)
2096{
2097 if(dev == NULL) return;
2098 mutex_lock(&dev->mutex);
2099 comedi_device_detach(dev);
2100 mutex_unlock(&dev->mutex);
2101 mutex_destroy(&dev->mutex);
2102}
2103
2104int comedi_alloc_board_minor(struct device *hardware_device)
2105{
2106 unsigned long flags;
2107 struct comedi_device_file_info *info;
2108 device_create_result_type *csdev;
2109 unsigned i;
2110
2111 info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2112 if(info == NULL) return -ENOMEM;
2113 info->device = kzalloc(sizeof(comedi_device), GFP_KERNEL);
2114 if(info->device == NULL)
2115 {
2116 kfree(info);
2117 return -ENOMEM;
2118 }
2119 comedi_device_init(info->device);
2120 comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2121 for(i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i)
2122 {
2123 if(comedi_file_info_table[i] == NULL)
2124 {
2125 comedi_file_info_table[i] = info;
2126 break;
2127 }
2128 }
2129 comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2130 if(i == COMEDI_NUM_BOARD_MINORS)
2131 {
2132 comedi_device_cleanup(info->device);
2133 kfree(info->device);
2134 kfree(info);
2135 rt_printk("comedi: error: ran out of minor numbers for board device files.\n");
2136 return -EBUSY;
2137 }
2138 info->device->minor = i;
2139 csdev = COMEDI_DEVICE_CREATE(comedi_class, NULL,
2140 MKDEV(COMEDI_MAJOR, i), NULL, hardware_device, "comedi%i", i);
2141 if(!IS_ERR(csdev)) {
2142 info->device->class_dev = csdev;
2143 }
2144 return i;
2145}
2146
2147void comedi_free_board_minor(unsigned minor)
2148{
2149 unsigned long flags;
2150 struct comedi_device_file_info *info;
2151
2152 BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
2153 comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2154 info = comedi_file_info_table[minor];
2155 comedi_file_info_table[minor] = NULL;
2156 comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2157
2158 if(info)
2159 {
2160 comedi_device *dev = info->device;
2161 if(dev)
2162 {
2163 if(dev->class_dev)
2164 {
2165 device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, dev->minor));
2166 }
2167 comedi_device_cleanup(dev);
2168 kfree(dev);
2169 }
2170 kfree(info);
2171 }
2172}
2173
2174int comedi_alloc_subdevice_minor(comedi_device *dev, comedi_subdevice *s)
2175{
2176 unsigned long flags;
2177 struct comedi_device_file_info *info;
2178 device_create_result_type *csdev;
2179 unsigned i;
2180
2181 info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2182 if(info == NULL) return -ENOMEM;
2183 info->device = dev;
2184 info->read_subdevice = s;
2185 info->write_subdevice = s;
2186 comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2187 for(i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_BOARD_MINORS; ++i)
2188 {
2189 if(comedi_file_info_table[i] == NULL)
2190 {
2191 comedi_file_info_table[i] = info;
2192 break;
2193 }
2194 }
2195 comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2196 if(i == COMEDI_NUM_MINORS)
2197 {
2198 kfree(info);
2199 rt_printk("comedi: error: ran out of minor numbers for board device files.\n");
2200 return -EBUSY;
2201 }
2202 s->minor = i;
2203 csdev = COMEDI_DEVICE_CREATE(comedi_class, dev->class_dev,
2204 MKDEV(COMEDI_MAJOR, i), NULL, NULL, "comedi%i_subd%i", dev->minor, (int)(s - dev->subdevices));
2205 if(!IS_ERR(csdev))
2206 {
2207 s->class_dev = csdev;
2208 }
2209 return i;
2210}
2211
2212void comedi_free_subdevice_minor(comedi_subdevice *s)
2213{
2214 unsigned long flags;
2215 struct comedi_device_file_info *info;
2216
2217 if(s == NULL) return;
2218 if(s->minor < 0) return;
2219
2220 BUG_ON(s->minor >= COMEDI_NUM_MINORS);
2221 BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
2222
2223 comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2224 info = comedi_file_info_table[s->minor];
2225 comedi_file_info_table[s->minor] = NULL;
2226 comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2227
2228 if(s->class_dev)
2229 {
2230 device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
2231 s->class_dev = NULL;
2232 }
2233 kfree(info);
2234}
2235
2236struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
2237{
2238 unsigned long flags;
2239 struct comedi_device_file_info *info;
2240
2241 BUG_ON(minor >= COMEDI_NUM_MINORS);
2242 comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2243 info = comedi_file_info_table[minor];
2244 comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2245 return info;
2246}