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