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