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