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