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