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