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