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