Staging: comedi: Remove comedi_device typedef
[GitHub/mt8127/android_kernel_alcatel_ttab.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
71b5f4f1
BP
72static int do_devconfig_ioctl(struct comedi_device *dev, comedi_devconfig *arg);
73static int do_bufconfig_ioctl(struct comedi_device *dev, void *arg);
74static int do_devinfo_ioctl(struct comedi_device *dev, comedi_devinfo *arg,
476b8477 75 struct file *file);
71b5f4f1 76static int do_subdinfo_ioctl(struct comedi_device *dev, comedi_subdinfo *arg,
476b8477 77 void *file);
71b5f4f1
BP
78static int do_chaninfo_ioctl(struct comedi_device *dev, comedi_chaninfo *arg);
79static int do_bufinfo_ioctl(struct comedi_device *dev, void *arg);
80static int do_cmd_ioctl(struct comedi_device *dev, void *arg, void *file);
81static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg, void *file);
82static int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg, void *file);
83static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg, void *file);
84static int do_cmdtest_ioctl(struct comedi_device *dev, void *arg, void *file);
85static int do_insnlist_ioctl(struct comedi_device *dev, void *arg, void *file);
86static int do_insn_ioctl(struct comedi_device *dev, void *arg, void *file);
87static int do_poll_ioctl(struct comedi_device *dev, unsigned int subd, void *file);
88
89extern void do_become_nonbusy(struct comedi_device *dev, comedi_subdevice *s);
90static int do_cancel(struct comedi_device *dev, comedi_subdevice *s);
ed9eccbe
DS
91
92static int comedi_fasync(int fd, struct file *file, int on);
93
71b5f4f1 94static int is_device_busy(struct 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);
71b5f4f1 107 struct 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*/
71b5f4f1 195static int do_devconfig_ioctl(struct 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*/
71b5f4f1 275static int do_bufconfig_ioctl(struct 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*/
71b5f4f1 363static int do_devinfo_ioctl(struct comedi_device *dev, comedi_devinfo *arg,
476b8477 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*/
71b5f4f1 413static int do_subdinfo_ioctl(struct comedi_device *dev, comedi_subdinfo *arg,
476b8477 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*/
71b5f4f1 493static int do_chaninfo_ioctl(struct 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,
790c5541 509 s->n_chan * sizeof(unsigned int)))
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 */
71b5f4f1 557static int do_bufinfo_ioctl(struct 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
71b5f4f1 610static int parse_insn(struct comedi_device *dev, comedi_insn *insn, unsigned int *data,
476b8477 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
71b5f4f1 629static int do_insnlist_ioctl(struct comedi_device *dev, void *arg, void *file)
ed9eccbe
DS
630{
631 comedi_insnlist insnlist;
632 comedi_insn *insns = NULL;
790c5541 633 unsigned int *data = NULL;
ed9eccbe
DS
634 int i = 0;
635 int ret = 0;
636
637 if (copy_from_user(&insnlist, arg, sizeof(comedi_insnlist)))
638 return -EFAULT;
639
790c5541 640 data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
ed9eccbe
DS
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,
790c5541 669 insns[i].n * sizeof(unsigned int))) {
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,
790c5541 680 insns[i].n * sizeof(unsigned int))) {
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
790c5541 699static int check_insn_config_length(comedi_insn *insn, unsigned int *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
71b5f4f1 760static int parse_insn(struct comedi_device *dev, comedi_insn *insn, unsigned int *data,
476b8477 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 */
790c5541 828 unsigned int maxdata;
ed9eccbe
DS
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 */
71b5f4f1 920static int do_insn_ioctl(struct comedi_device *dev, void *arg, void *file)
ed9eccbe
DS
921{
922 comedi_insn insn;
790c5541 923 unsigned int *data = NULL;
ed9eccbe
DS
924 int ret = 0;
925
790c5541 926 data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
ed9eccbe
DS
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) {
790c5541 941 if (copy_from_user(data, insn.data, insn.n * sizeof(unsigned int))) {
ed9eccbe
DS
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) {
790c5541 950 if (copy_to_user(insn.data, data, insn.n * sizeof(unsigned int))) {
ed9eccbe
DS
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*/
71b5f4f1 978static int do_cmd_ioctl(struct 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*/
71b5f4f1 1132static int do_cmdtest_ioctl(struct 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
71b5f4f1 1230static int do_lock_ioctl(struct 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*/
71b5f4f1 1274static int do_unlock_ioctl(struct 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*/
71b5f4f1 1314static int do_cancel_ioctl(struct 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*/
71b5f4f1 1350static int do_poll_ioctl(struct 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
71b5f4f1 1373static int do_cancel(struct 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;
71b5f4f1 1388 struct comedi_device *dev;
ed9eccbe
DS
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);
71b5f4f1 1407 struct comedi_device *dev = dev_file_info->device;
ed9eccbe
DS
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);
71b5f4f1 1483 struct comedi_device *dev = dev_file_info->device;
ed9eccbe
DS
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);
71b5f4f1 1533 struct comedi_device *dev = dev_file_info->device;
ed9eccbe
DS
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);
71b5f4f1 1635 struct comedi_device *dev = dev_file_info->device;
ed9eccbe
DS
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 */
71b5f4f1 1736void do_become_nonbusy(struct 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);
71b5f4f1 1763 struct comedi_device *dev = dev_file_info ? dev_file_info->device : NULL;
97920071 1764
ed9eccbe
DS
1765 if (dev == NULL) {
1766 DPRINTK("invalid minor number\n");
1767 return -ENODEV;
1768 }
1769
1770 /* This is slightly hacky, but we want module autoloading
1771 * to work for root.
1772 * case: user opens device, attached -> ok
1773 * case: user opens device, unattached, in_request_module=0 -> autoload
1774 * case: user opens device, unattached, in_request_module=1 -> fail
1775 * case: root opens device, attached -> ok
1776 * case: root opens device, unattached, in_request_module=1 -> ok
1777 * (typically called from modprobe)
1778 * case: root opens device, unattached, in_request_module=0 -> autoload
1779 *
1780 * The last could be changed to "-> ok", which would deny root
1781 * autoloading.
1782 */
1783 mutex_lock(&dev->mutex);
1784 if (dev->attached)
1785 goto ok;
1786 if (!capable(CAP_SYS_MODULE) && dev->in_request_module) {
1787 DPRINTK("in request module\n");
1788 mutex_unlock(&dev->mutex);
1789 return -ENODEV;
1790 }
1791 if (capable(CAP_SYS_MODULE) && dev->in_request_module)
1792 goto ok;
1793
1794 dev->in_request_module = 1;
1795
ed9eccbe
DS
1796#ifdef CONFIG_KMOD
1797 mutex_unlock(&dev->mutex);
56d92c60 1798 request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor);
ed9eccbe
DS
1799 mutex_lock(&dev->mutex);
1800#endif
1801
1802 dev->in_request_module = 0;
1803
1804 if (!dev->attached && !capable(CAP_SYS_MODULE)) {
1805 DPRINTK("not attached and not CAP_SYS_MODULE\n");
1806 mutex_unlock(&dev->mutex);
1807 return -ENODEV;
1808 }
1809ok:
1810 __module_get(THIS_MODULE);
1811
1812 if (dev->attached) {
1813 if (!try_module_get(dev->driver->module)) {
1814 module_put(THIS_MODULE);
1815 mutex_unlock(&dev->mutex);
1816 return -ENOSYS;
1817 }
1818 }
1819
476b8477 1820 if (dev->attached && dev->use_count == 0 && dev->open)
ed9eccbe 1821 dev->open(dev);
ed9eccbe
DS
1822
1823 dev->use_count++;
1824
1825 mutex_unlock(&dev->mutex);
1826
1827 return 0;
1828}
1829
1830static int comedi_close(struct inode *inode, struct file *file)
1831{
1832 const unsigned minor = iminor(inode);
476b8477
GKH
1833 struct comedi_device_file_info *dev_file_info =
1834 comedi_get_device_file_info(minor);
71b5f4f1 1835 struct comedi_device *dev = dev_file_info->device;
ed9eccbe
DS
1836 comedi_subdevice *s = NULL;
1837 int i;
1838
1839 mutex_lock(&dev->mutex);
1840
1841 if (dev->subdevices) {
1842 for (i = 0; i < dev->n_subdevices; i++) {
1843 s = dev->subdevices + i;
1844
476b8477 1845 if (s->busy == file)
ed9eccbe 1846 do_cancel(dev, s);
476b8477 1847 if (s->lock == file)
ed9eccbe 1848 s->lock = NULL;
ed9eccbe
DS
1849 }
1850 }
476b8477 1851 if (dev->attached && dev->use_count == 1 && dev->close)
ed9eccbe 1852 dev->close(dev);
ed9eccbe
DS
1853
1854 module_put(THIS_MODULE);
476b8477 1855 if (dev->attached)
ed9eccbe 1856 module_put(dev->driver->module);
ed9eccbe
DS
1857
1858 dev->use_count--;
1859
1860 mutex_unlock(&dev->mutex);
1861
476b8477 1862 if (file->f_flags & FASYNC)
ed9eccbe 1863 comedi_fasync(-1, file, 0);
ed9eccbe
DS
1864
1865 return 0;
1866}
1867
1868static int comedi_fasync(int fd, struct file *file, int on)
1869{
1870 const unsigned minor = iminor(file->f_dentry->d_inode);
476b8477
GKH
1871 struct comedi_device_file_info *dev_file_info =
1872 comedi_get_device_file_info(minor);
1873
71b5f4f1 1874 struct comedi_device *dev = dev_file_info->device;
ed9eccbe
DS
1875
1876 return fasync_helper(fd, file, on, &dev->async_queue);
1877}
1878
1879const struct file_operations comedi_fops = {
476b8477 1880 .owner = THIS_MODULE,
ed9eccbe 1881#ifdef HAVE_UNLOCKED_IOCTL
476b8477 1882 .unlocked_ioctl = comedi_unlocked_ioctl,
ed9eccbe 1883#else
476b8477 1884 .ioctl = comedi_ioctl,
ed9eccbe
DS
1885#endif
1886#ifdef HAVE_COMPAT_IOCTL
476b8477 1887 .compat_ioctl = comedi_compat_ioctl,
ed9eccbe 1888#endif
476b8477
GKH
1889 .open = comedi_open,
1890 .release = comedi_close,
1891 .read = comedi_read,
1892 .write = comedi_write,
1893 .mmap = comedi_mmap,
1894 .poll = comedi_poll,
1895 .fasync = comedi_fasync,
ed9eccbe
DS
1896};
1897
476b8477 1898struct class *comedi_class;
ed9eccbe
DS
1899static struct cdev comedi_cdev;
1900
1901static void comedi_cleanup_legacy_minors(void)
1902{
1903 unsigned i;
476b8477 1904
1dd33ab8 1905 for (i = 0; i < comedi_num_legacy_minors; i++)
ed9eccbe 1906 comedi_free_board_minor(i);
ed9eccbe
DS
1907}
1908
1909static int __init comedi_init(void)
1910{
1911 int i;
1912 int retval;
1913
476b8477
GKH
1914 printk(KERN_INFO "comedi: version " COMEDI_RELEASE
1915 " - http://www.comedi.org\n");
ed9eccbe 1916
a3cb729e
FMH
1917 if (comedi_num_legacy_minors < 0 ||
1918 comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
1919 printk(KERN_ERR "comedi: error: invalid value for module "
1920 "parameter \"comedi_num_legacy_minors\". Valid values "
1921 "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS);
1922 return -EINVAL;
1923 }
1924
1925 /*
1926 * comedi is unusable if both comedi_autoconfig and
1927 * comedi_num_legacy_minors are zero, so we might as well adjust the
1928 * defaults in that case
1929 */
1930 if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0)
1931 comedi_num_legacy_minors = 16;
1932
476b8477
GKH
1933 memset(comedi_file_info_table, 0,
1934 sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS);
ed9eccbe
DS
1935
1936 retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
476b8477 1937 COMEDI_NUM_MINORS, "comedi");
ed9eccbe
DS
1938 if (retval)
1939 return -EIO;
1940 cdev_init(&comedi_cdev, &comedi_fops);
1941 comedi_cdev.owner = THIS_MODULE;
1942 kobject_set_name(&comedi_cdev.kobj, "comedi");
1943 if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
1944 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
476b8477 1945 COMEDI_NUM_MINORS);
ed9eccbe
DS
1946 return -EIO;
1947 }
1948 comedi_class = class_create(THIS_MODULE, "comedi");
1949 if (IS_ERR(comedi_class)) {
1950 printk("comedi: failed to create class");
1951 cdev_del(&comedi_cdev);
1952 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
476b8477 1953 COMEDI_NUM_MINORS);
ed9eccbe
DS
1954 return PTR_ERR(comedi_class);
1955 }
1956
1957 /* XXX requires /proc interface */
1958 comedi_proc_init();
1959
476b8477 1960 /* create devices files for legacy/manual use */
1dd33ab8 1961 for (i = 0; i < comedi_num_legacy_minors; i++) {
ed9eccbe
DS
1962 int minor;
1963 minor = comedi_alloc_board_minor(NULL);
476b8477 1964 if (minor < 0) {
ed9eccbe
DS
1965 comedi_cleanup_legacy_minors();
1966 cdev_del(&comedi_cdev);
1967 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
476b8477 1968 COMEDI_NUM_MINORS);
ed9eccbe
DS
1969 return minor;
1970 }
1971 }
1972
1973 comedi_rt_init();
1974
1975 comedi_register_ioctl32();
1976
1977 return 0;
1978}
1979
1980static void __exit comedi_cleanup(void)
1981{
1982 int i;
1983
1984 comedi_cleanup_legacy_minors();
476b8477 1985 for (i = 0; i < COMEDI_NUM_MINORS; ++i)
ed9eccbe 1986 BUG_ON(comedi_file_info_table[i]);
476b8477 1987
ed9eccbe
DS
1988
1989 class_destroy(comedi_class);
1990 cdev_del(&comedi_cdev);
1991 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
1992
1993 comedi_proc_cleanup();
1994
1995 comedi_rt_cleanup();
1996
1997 comedi_unregister_ioctl32();
1998}
1999
2000module_init(comedi_init);
2001module_exit(comedi_cleanup);
2002
71b5f4f1 2003void comedi_error(const struct comedi_device *dev, const char *s)
ed9eccbe
DS
2004{
2005 rt_printk("comedi%d: %s: %s\n", dev->minor, dev->driver->driver_name,
476b8477 2006 s);
ed9eccbe
DS
2007}
2008
71b5f4f1 2009void comedi_event(struct comedi_device *dev, comedi_subdevice *s)
ed9eccbe
DS
2010{
2011 comedi_async *async = s->async;
2012 unsigned runflags = 0;
2013 unsigned runflags_mask = 0;
2014
476b8477 2015 /* DPRINTK("comedi_event 0x%x\n",mask); */
ed9eccbe
DS
2016
2017 if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0)
2018 return;
2019
2020 if (s->async->
476b8477 2021 events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
ed9eccbe
DS
2022 runflags_mask |= SRF_RUNNING;
2023 }
2024 /* remember if an error event has occured, so an error
2025 * can be returned the next time the user does a read() */
2026 if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2027 runflags_mask |= SRF_ERROR;
2028 runflags |= SRF_ERROR;
2029 }
2030 if (runflags_mask) {
2031 /*sets SRF_ERROR and SRF_RUNNING together atomically */
2032 comedi_set_subdevice_runflags(s, runflags_mask, runflags);
2033 }
2034
2035 if (async->cb_mask & s->async->events) {
2036 if (comedi_get_subdevice_runflags(s) & SRF_USER) {
2037
2038 if (dev->rt) {
2039#ifdef CONFIG_COMEDI_RT
476b8477 2040 /* pend wake up */
ed9eccbe
DS
2041 comedi_rt_pend_wakeup(&async->wait_head);
2042#else
476b8477
GKH
2043 printk
2044 ("BUG: comedi_event() code unreachable\n");
ed9eccbe
DS
2045#endif
2046 } else {
2047 wake_up_interruptible(&async->wait_head);
2048 if (s->subdev_flags & SDF_CMD_READ) {
2049 kill_fasync(&dev->async_queue, SIGIO,
476b8477 2050 POLL_IN);
ed9eccbe
DS
2051 }
2052 if (s->subdev_flags & SDF_CMD_WRITE) {
2053 kill_fasync(&dev->async_queue, SIGIO,
476b8477 2054 POLL_OUT);
ed9eccbe
DS
2055 }
2056 }
2057 } else {
2058 if (async->cb_func)
2059 async->cb_func(s->async->events, async->cb_arg);
2060 /* XXX bug here. If subdevice A is rt, and
2061 * subdevice B tries to callback to a normal
2062 * linux kernel function, it will be at the
2063 * wrong priority. Since this isn't very
2064 * common, I'm not going to worry about it. */
2065 }
2066 }
2067 s->async->events = 0;
2068}
2069
476b8477
GKH
2070void comedi_set_subdevice_runflags(comedi_subdevice *s, unsigned mask,
2071 unsigned bits)
ed9eccbe
DS
2072{
2073 unsigned long flags;
2074
2075 comedi_spin_lock_irqsave(&s->spin_lock, flags);
2076 s->runflags &= ~mask;
2077 s->runflags |= (bits & mask);
2078 comedi_spin_unlock_irqrestore(&s->spin_lock, flags);
2079}
2080
476b8477 2081unsigned comedi_get_subdevice_runflags(comedi_subdevice *s)
ed9eccbe
DS
2082{
2083 unsigned long flags;
2084 unsigned runflags;
2085
2086 comedi_spin_lock_irqsave(&s->spin_lock, flags);
2087 runflags = s->runflags;
2088 comedi_spin_unlock_irqrestore(&s->spin_lock, flags);
2089 return runflags;
2090}
2091
71b5f4f1 2092static int is_device_busy(struct comedi_device *dev)
ed9eccbe
DS
2093{
2094 comedi_subdevice *s;
2095 int i;
2096
2097 if (!dev->attached)
2098 return 0;
2099
2100 for (i = 0; i < dev->n_subdevices; i++) {
2101 s = dev->subdevices + i;
2102 if (s->busy)
2103 return 1;
2104 if (s->async && s->async->mmap_count)
2105 return 1;
2106 }
2107
2108 return 0;
2109}
2110
71b5f4f1 2111void comedi_device_init(struct comedi_device *dev)
ed9eccbe 2112{
71b5f4f1 2113 memset(dev, 0, sizeof(struct comedi_device));
ed9eccbe
DS
2114 spin_lock_init(&dev->spinlock);
2115 mutex_init(&dev->mutex);
2116 dev->minor = -1;
2117}
2118
71b5f4f1 2119void comedi_device_cleanup(struct comedi_device *dev)
ed9eccbe 2120{
476b8477
GKH
2121 if (dev == NULL)
2122 return;
ed9eccbe
DS
2123 mutex_lock(&dev->mutex);
2124 comedi_device_detach(dev);
2125 mutex_unlock(&dev->mutex);
2126 mutex_destroy(&dev->mutex);
2127}
2128
2129int comedi_alloc_board_minor(struct device *hardware_device)
2130{
2131 unsigned long flags;
2132 struct comedi_device_file_info *info;
2133 device_create_result_type *csdev;
2134 unsigned i;
2135
2136 info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
476b8477
GKH
2137 if (info == NULL)
2138 return -ENOMEM;
71b5f4f1 2139 info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL);
476b8477 2140 if (info->device == NULL) {
ed9eccbe
DS
2141 kfree(info);
2142 return -ENOMEM;
2143 }
2144 comedi_device_init(info->device);
2145 comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
476b8477
GKH
2146 for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) {
2147 if (comedi_file_info_table[i] == NULL) {
ed9eccbe
DS
2148 comedi_file_info_table[i] = info;
2149 break;
2150 }
2151 }
2152 comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
476b8477 2153 if (i == COMEDI_NUM_BOARD_MINORS) {
ed9eccbe
DS
2154 comedi_device_cleanup(info->device);
2155 kfree(info->device);
2156 kfree(info);
476b8477
GKH
2157 rt_printk
2158 ("comedi: error: ran out of minor numbers for board device files.\n");
ed9eccbe
DS
2159 return -EBUSY;
2160 }
2161 info->device->minor = i;
2162 csdev = COMEDI_DEVICE_CREATE(comedi_class, NULL,
476b8477
GKH
2163 MKDEV(COMEDI_MAJOR, i), NULL,
2164 hardware_device, "comedi%i", i);
2165 if (!IS_ERR(csdev))
ed9eccbe 2166 info->device->class_dev = csdev;
476b8477 2167
ed9eccbe
DS
2168 return i;
2169}
2170
2171void comedi_free_board_minor(unsigned minor)
2172{
2173 unsigned long flags;
2174 struct comedi_device_file_info *info;
2175
2176 BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
2177 comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2178 info = comedi_file_info_table[minor];
2179 comedi_file_info_table[minor] = NULL;
2180 comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2181
476b8477 2182 if (info) {
71b5f4f1 2183 struct comedi_device *dev = info->device;
476b8477
GKH
2184 if (dev) {
2185 if (dev->class_dev) {
2186 device_destroy(comedi_class,
2187 MKDEV(COMEDI_MAJOR, dev->minor));
ed9eccbe
DS
2188 }
2189 comedi_device_cleanup(dev);
2190 kfree(dev);
2191 }
2192 kfree(info);
2193 }
2194}
2195
71b5f4f1 2196int comedi_alloc_subdevice_minor(struct comedi_device *dev, comedi_subdevice *s)
ed9eccbe
DS
2197{
2198 unsigned long flags;
2199 struct comedi_device_file_info *info;
2200 device_create_result_type *csdev;
2201 unsigned i;
2202
2203 info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
476b8477
GKH
2204 if (info == NULL)
2205 return -ENOMEM;
ed9eccbe
DS
2206 info->device = dev;
2207 info->read_subdevice = s;
2208 info->write_subdevice = s;
2209 comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
4c41f3ae 2210 for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
476b8477 2211 if (comedi_file_info_table[i] == NULL) {
ed9eccbe
DS
2212 comedi_file_info_table[i] = info;
2213 break;
2214 }
2215 }
2216 comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
476b8477 2217 if (i == COMEDI_NUM_MINORS) {
ed9eccbe 2218 kfree(info);
476b8477
GKH
2219 rt_printk
2220 ("comedi: error: ran out of minor numbers for board device files.\n");
ed9eccbe
DS
2221 return -EBUSY;
2222 }
2223 s->minor = i;
2224 csdev = COMEDI_DEVICE_CREATE(comedi_class, dev->class_dev,
476b8477
GKH
2225 MKDEV(COMEDI_MAJOR, i), NULL, NULL,
2226 "comedi%i_subd%i", dev->minor,
2227 (int)(s - dev->subdevices));
2228 if (!IS_ERR(csdev))
ed9eccbe 2229 s->class_dev = csdev;
476b8477 2230
ed9eccbe
DS
2231 return i;
2232}
2233
2234void comedi_free_subdevice_minor(comedi_subdevice *s)
2235{
2236 unsigned long flags;
2237 struct comedi_device_file_info *info;
2238
476b8477
GKH
2239 if (s == NULL)
2240 return;
2241 if (s->minor < 0)
2242 return;
ed9eccbe
DS
2243
2244 BUG_ON(s->minor >= COMEDI_NUM_MINORS);
2245 BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
2246
2247 comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2248 info = comedi_file_info_table[s->minor];
2249 comedi_file_info_table[s->minor] = NULL;
2250 comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2251
476b8477 2252 if (s->class_dev) {
ed9eccbe
DS
2253 device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
2254 s->class_dev = NULL;
2255 }
2256 kfree(info);
2257}
2258
2259struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
2260{
2261 unsigned long flags;
2262 struct comedi_device_file_info *info;
2263
2264 BUG_ON(minor >= COMEDI_NUM_MINORS);
2265 comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2266 info = comedi_file_info_table[minor];
2267 comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2268 return info;
2269}