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