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