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