]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/staging/comedi/comedi_fops.c
ARM: delete struct sys_timer
[karo-tx-linux.git] / drivers / staging / comedi / comedi_fops.c
1 /*
2     comedi/comedi_fops.c
3     comedi kernel module
4
5     COMEDI - Linux Control and Measurement Device Interface
6     Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
7
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 */
23
24 #undef DEBUG
25
26 #include "comedi_compat32.h"
27
28 #include <linux/module.h>
29 #include <linux/errno.h>
30 #include <linux/kernel.h>
31 #include <linux/sched.h>
32 #include <linux/fcntl.h>
33 #include <linux/delay.h>
34 #include <linux/ioport.h>
35 #include <linux/mm.h>
36 #include <linux/slab.h>
37 #include <linux/kmod.h>
38 #include <linux/poll.h>
39 #include <linux/init.h>
40 #include <linux/device.h>
41 #include <linux/vmalloc.h>
42 #include <linux/fs.h>
43 #include "comedidev.h"
44 #include <linux/cdev.h>
45 #include <linux/stat.h>
46
47 #include <linux/io.h>
48 #include <linux/uaccess.h>
49
50 #include "comedi_internal.h"
51
52 MODULE_AUTHOR("http://www.comedi.org");
53 MODULE_DESCRIPTION("Comedi core module");
54 MODULE_LICENSE("GPL");
55
56 #ifdef CONFIG_COMEDI_DEBUG
57 int comedi_debug;
58 EXPORT_SYMBOL(comedi_debug);
59 module_param(comedi_debug, int, S_IRUGO | S_IWUSR);
60 MODULE_PARM_DESC(comedi_debug,
61                  "enable comedi core and driver debugging if non-zero (default 0)"
62                 );
63 #endif
64
65 bool comedi_autoconfig = 1;
66 module_param(comedi_autoconfig, bool, S_IRUGO);
67 MODULE_PARM_DESC(comedi_autoconfig,
68                  "enable drivers to auto-configure comedi devices (default 1)");
69
70 static int comedi_num_legacy_minors;
71 module_param(comedi_num_legacy_minors, int, S_IRUGO);
72 MODULE_PARM_DESC(comedi_num_legacy_minors,
73                  "number of comedi minor devices to reserve for non-auto-configured devices (default 0)"
74                 );
75
76 unsigned int comedi_default_buf_size_kb = CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB;
77 module_param(comedi_default_buf_size_kb, uint, S_IRUGO | S_IWUSR);
78 MODULE_PARM_DESC(comedi_default_buf_size_kb,
79                  "default asynchronous buffer size in KiB (default "
80                  __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB) ")");
81
82 unsigned int comedi_default_buf_maxsize_kb
83         = CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB;
84 module_param(comedi_default_buf_maxsize_kb, uint, S_IRUGO | S_IWUSR);
85 MODULE_PARM_DESC(comedi_default_buf_maxsize_kb,
86                  "default maximum size of asynchronous buffer in KiB (default "
87                  __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB) ")");
88
89 static DEFINE_SPINLOCK(comedi_file_info_table_lock);
90 static struct comedi_device_file_info
91 *comedi_file_info_table[COMEDI_NUM_MINORS];
92
93 static void do_become_nonbusy(struct comedi_device *dev,
94                               struct comedi_subdevice *s);
95 static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
96
97 static int comedi_fasync(int fd, struct file *file, int on);
98
99 static int is_device_busy(struct comedi_device *dev);
100
101 static int resize_async_buffer(struct comedi_device *dev,
102                                struct comedi_subdevice *s,
103                                struct comedi_async *async, unsigned new_size)
104 {
105         int retval;
106
107         if (new_size > async->max_bufsize)
108                 return -EPERM;
109
110         if (s->busy) {
111                 DPRINTK("subdevice is busy, cannot resize buffer\n");
112                 return -EBUSY;
113         }
114         if (async->mmap_count) {
115                 DPRINTK("subdevice is mmapped, cannot resize buffer\n");
116                 return -EBUSY;
117         }
118
119         if (!async->prealloc_buf)
120                 return -EINVAL;
121
122         /* make sure buffer is an integral number of pages
123          * (we round up) */
124         new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
125
126         retval = comedi_buf_alloc(dev, s, new_size);
127         if (retval < 0)
128                 return retval;
129
130         if (s->buf_change) {
131                 retval = s->buf_change(dev, s, new_size);
132                 if (retval < 0)
133                         return retval;
134         }
135
136         DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
137                 dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz);
138         return 0;
139 }
140
141 /* sysfs attribute files */
142
143 static ssize_t show_max_read_buffer_kb(struct device *dev,
144                                        struct device_attribute *attr, char *buf)
145 {
146         struct comedi_device_file_info *info = dev_get_drvdata(dev);
147         struct comedi_subdevice *s = comedi_get_read_subdevice(info);
148         unsigned int size = 0;
149
150         mutex_lock(&info->device->mutex);
151         if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
152                 size = s->async->max_bufsize / 1024;
153         mutex_unlock(&info->device->mutex);
154
155         return snprintf(buf, PAGE_SIZE, "%i\n", size);
156 }
157
158 static ssize_t store_max_read_buffer_kb(struct device *dev,
159                                         struct device_attribute *attr,
160                                         const char *buf, size_t count)
161 {
162         struct comedi_device_file_info *info = dev_get_drvdata(dev);
163         struct comedi_subdevice *s = comedi_get_read_subdevice(info);
164         unsigned int size;
165         int err;
166
167         err = kstrtouint(buf, 10, &size);
168         if (err)
169                 return err;
170         if (size > (UINT_MAX / 1024))
171                 return -EINVAL;
172         size *= 1024;
173
174         mutex_lock(&info->device->mutex);
175         if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
176                 s->async->max_bufsize = size;
177         else
178                 err = -EINVAL;
179         mutex_unlock(&info->device->mutex);
180
181         return err ? err : count;
182 }
183
184 static ssize_t show_read_buffer_kb(struct device *dev,
185                                    struct device_attribute *attr, char *buf)
186 {
187         struct comedi_device_file_info *info = dev_get_drvdata(dev);
188         struct comedi_subdevice *s = comedi_get_read_subdevice(info);
189         unsigned int size = 0;
190
191         mutex_lock(&info->device->mutex);
192         if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
193                 size = s->async->prealloc_bufsz / 1024;
194         mutex_unlock(&info->device->mutex);
195
196         return snprintf(buf, PAGE_SIZE, "%i\n", size);
197 }
198
199 static ssize_t store_read_buffer_kb(struct device *dev,
200                                     struct device_attribute *attr,
201                                     const char *buf, size_t count)
202 {
203         struct comedi_device_file_info *info = dev_get_drvdata(dev);
204         struct comedi_subdevice *s = comedi_get_read_subdevice(info);
205         unsigned int size;
206         int err;
207
208         err = kstrtouint(buf, 10, &size);
209         if (err)
210                 return err;
211         if (size > (UINT_MAX / 1024))
212                 return -EINVAL;
213         size *= 1024;
214
215         mutex_lock(&info->device->mutex);
216         if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
217                 err = resize_async_buffer(info->device, s, s->async, size);
218         else
219                 err = -EINVAL;
220         mutex_unlock(&info->device->mutex);
221
222         return err ? err : count;
223 }
224
225 static ssize_t show_max_write_buffer_kb(struct device *dev,
226                                         struct device_attribute *attr,
227                                         char *buf)
228 {
229         struct comedi_device_file_info *info = dev_get_drvdata(dev);
230         struct comedi_subdevice *s = comedi_get_write_subdevice(info);
231         unsigned int size = 0;
232
233         mutex_lock(&info->device->mutex);
234         if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
235                 size = s->async->max_bufsize / 1024;
236         mutex_unlock(&info->device->mutex);
237
238         return snprintf(buf, PAGE_SIZE, "%i\n", size);
239 }
240
241 static ssize_t store_max_write_buffer_kb(struct device *dev,
242                                          struct device_attribute *attr,
243                                          const char *buf, size_t count)
244 {
245         struct comedi_device_file_info *info = dev_get_drvdata(dev);
246         struct comedi_subdevice *s = comedi_get_write_subdevice(info);
247         unsigned int size;
248         int err;
249
250         err = kstrtouint(buf, 10, &size);
251         if (err)
252                 return err;
253         if (size > (UINT_MAX / 1024))
254                 return -EINVAL;
255         size *= 1024;
256
257         mutex_lock(&info->device->mutex);
258         if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
259                 s->async->max_bufsize = size;
260         else
261                 err = -EINVAL;
262         mutex_unlock(&info->device->mutex);
263
264         return err ? err : count;
265 }
266
267 static ssize_t show_write_buffer_kb(struct device *dev,
268                                     struct device_attribute *attr, char *buf)
269 {
270         struct comedi_device_file_info *info = dev_get_drvdata(dev);
271         struct comedi_subdevice *s = comedi_get_write_subdevice(info);
272         unsigned int size = 0;
273
274         mutex_lock(&info->device->mutex);
275         if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
276                 size = s->async->prealloc_bufsz / 1024;
277         mutex_unlock(&info->device->mutex);
278
279         return snprintf(buf, PAGE_SIZE, "%i\n", size);
280 }
281
282 static ssize_t store_write_buffer_kb(struct device *dev,
283                                      struct device_attribute *attr,
284                                      const char *buf, size_t count)
285 {
286         struct comedi_device_file_info *info = dev_get_drvdata(dev);
287         struct comedi_subdevice *s = comedi_get_write_subdevice(info);
288         unsigned int size;
289         int err;
290
291         err = kstrtouint(buf, 10, &size);
292         if (err)
293                 return err;
294         if (size > (UINT_MAX / 1024))
295                 return -EINVAL;
296         size *= 1024;
297
298         mutex_lock(&info->device->mutex);
299         if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
300                 err = resize_async_buffer(info->device, s, s->async, size);
301         else
302                 err = -EINVAL;
303         mutex_unlock(&info->device->mutex);
304
305         return err ? err : count;
306 }
307
308 static struct device_attribute comedi_dev_attrs[] = {
309         __ATTR(max_read_buffer_kb, S_IRUGO | S_IWUSR,
310                 show_max_read_buffer_kb, store_max_read_buffer_kb),
311         __ATTR(read_buffer_kb, S_IRUGO | S_IWUSR | S_IWGRP,
312                 show_read_buffer_kb, store_read_buffer_kb),
313         __ATTR(max_write_buffer_kb, S_IRUGO | S_IWUSR,
314                 show_max_write_buffer_kb, store_max_write_buffer_kb),
315         __ATTR(write_buffer_kb, S_IRUGO | S_IWUSR | S_IWGRP,
316                 show_write_buffer_kb, store_write_buffer_kb),
317         __ATTR_NULL
318 };
319
320 /*
321         COMEDI_DEVCONFIG
322         device config ioctl
323
324         arg:
325                 pointer to devconfig structure
326
327         reads:
328                 devconfig structure at arg
329
330         writes:
331                 none
332 */
333 static int do_devconfig_ioctl(struct comedi_device *dev,
334                               struct comedi_devconfig __user *arg)
335 {
336         struct comedi_devconfig it;
337         int ret;
338         unsigned char *aux_data = NULL;
339         int aux_len;
340
341         if (!capable(CAP_SYS_ADMIN))
342                 return -EPERM;
343
344         if (arg == NULL) {
345                 if (is_device_busy(dev))
346                         return -EBUSY;
347                 if (dev->attached) {
348                         struct module *driver_module = dev->driver->module;
349                         comedi_device_detach(dev);
350                         module_put(driver_module);
351                 }
352                 return 0;
353         }
354
355         if (copy_from_user(&it, arg, sizeof(struct comedi_devconfig)))
356                 return -EFAULT;
357
358         it.board_name[COMEDI_NAMELEN - 1] = 0;
359
360         if (comedi_aux_data(it.options, 0) &&
361             it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
362                 int bit_shift;
363                 aux_len = it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
364                 if (aux_len < 0)
365                         return -EFAULT;
366
367                 aux_data = vmalloc(aux_len);
368                 if (!aux_data)
369                         return -ENOMEM;
370
371                 if (copy_from_user(aux_data,
372                                    (unsigned char __user *
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         case INSN_CONFIG_DIGITAL_TRIG:
883                 if (insn->n == 6)
884                         return 0;
885                 break;
886                 /* by default we allow the insn since we don't have checks for
887                  * all possible cases yet */
888         default:
889                 pr_warn("comedi: No check for data length of config insn id %i is implemented.\n",
890                         data[0]);
891                 pr_warn("comedi: Add a check to %s in %s.\n",
892                         __func__, __FILE__);
893                 pr_warn("comedi: Assuming n=%i is correct.\n", insn->n);
894                 return 0;
895         }
896         return -EINVAL;
897 }
898
899 static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
900                       unsigned int *data, void *file)
901 {
902         struct comedi_subdevice *s;
903         int ret = 0;
904         int i;
905
906         if (insn->insn & INSN_MASK_SPECIAL) {
907                 /* a non-subdevice instruction */
908
909                 switch (insn->insn) {
910                 case INSN_GTOD:
911                         {
912                                 struct timeval tv;
913
914                                 if (insn->n != 2) {
915                                         ret = -EINVAL;
916                                         break;
917                                 }
918
919                                 do_gettimeofday(&tv);
920                                 data[0] = tv.tv_sec;
921                                 data[1] = tv.tv_usec;
922                                 ret = 2;
923
924                                 break;
925                         }
926                 case INSN_WAIT:
927                         if (insn->n != 1 || data[0] >= 100000) {
928                                 ret = -EINVAL;
929                                 break;
930                         }
931                         udelay(data[0] / 1000);
932                         ret = 1;
933                         break;
934                 case INSN_INTTRIG:
935                         if (insn->n != 1) {
936                                 ret = -EINVAL;
937                                 break;
938                         }
939                         if (insn->subdev >= dev->n_subdevices) {
940                                 DPRINTK("%d not usable subdevice\n",
941                                         insn->subdev);
942                                 ret = -EINVAL;
943                                 break;
944                         }
945                         s = &dev->subdevices[insn->subdev];
946                         if (!s->async) {
947                                 DPRINTK("no async\n");
948                                 ret = -EINVAL;
949                                 break;
950                         }
951                         if (!s->async->inttrig) {
952                                 DPRINTK("no inttrig\n");
953                                 ret = -EAGAIN;
954                                 break;
955                         }
956                         ret = s->async->inttrig(dev, s, data[0]);
957                         if (ret >= 0)
958                                 ret = 1;
959                         break;
960                 default:
961                         DPRINTK("invalid insn\n");
962                         ret = -EINVAL;
963                         break;
964                 }
965         } else {
966                 /* a subdevice instruction */
967                 unsigned int maxdata;
968
969                 if (insn->subdev >= dev->n_subdevices) {
970                         DPRINTK("subdevice %d out of range\n", insn->subdev);
971                         ret = -EINVAL;
972                         goto out;
973                 }
974                 s = &dev->subdevices[insn->subdev];
975
976                 if (s->type == COMEDI_SUBD_UNUSED) {
977                         DPRINTK("%d not usable subdevice\n", insn->subdev);
978                         ret = -EIO;
979                         goto out;
980                 }
981
982                 /* are we locked? (ioctl lock) */
983                 if (s->lock && s->lock != file) {
984                         DPRINTK("device locked\n");
985                         ret = -EACCES;
986                         goto out;
987                 }
988
989                 ret = comedi_check_chanlist(s, 1, &insn->chanspec);
990                 if (ret < 0) {
991                         ret = -EINVAL;
992                         DPRINTK("bad chanspec\n");
993                         goto out;
994                 }
995
996                 if (s->busy) {
997                         ret = -EBUSY;
998                         goto out;
999                 }
1000                 /* This looks arbitrary.  It is. */
1001                 s->busy = &parse_insn;
1002                 switch (insn->insn) {
1003                 case INSN_READ:
1004                         ret = s->insn_read(dev, s, insn, data);
1005                         break;
1006                 case INSN_WRITE:
1007                         maxdata = s->maxdata_list
1008                             ? s->maxdata_list[CR_CHAN(insn->chanspec)]
1009                             : s->maxdata;
1010                         for (i = 0; i < insn->n; ++i) {
1011                                 if (data[i] > maxdata) {
1012                                         ret = -EINVAL;
1013                                         DPRINTK("bad data value(s)\n");
1014                                         break;
1015                                 }
1016                         }
1017                         if (ret == 0)
1018                                 ret = s->insn_write(dev, s, insn, data);
1019                         break;
1020                 case INSN_BITS:
1021                         if (insn->n != 2) {
1022                                 ret = -EINVAL;
1023                         } else {
1024                                 /* Most drivers ignore the base channel in
1025                                  * insn->chanspec.  Fix this here if
1026                                  * the subdevice has <= 32 channels.  */
1027                                 unsigned int shift;
1028                                 unsigned int orig_mask;
1029
1030                                 orig_mask = data[0];
1031                                 if (s->n_chan <= 32) {
1032                                         shift = CR_CHAN(insn->chanspec);
1033                                         if (shift > 0) {
1034                                                 insn->chanspec = 0;
1035                                                 data[0] <<= shift;
1036                                                 data[1] <<= shift;
1037                                         }
1038                                 } else
1039                                         shift = 0;
1040                                 ret = s->insn_bits(dev, s, insn, data);
1041                                 data[0] = orig_mask;
1042                                 if (shift > 0)
1043                                         data[1] >>= shift;
1044                         }
1045                         break;
1046                 case INSN_CONFIG:
1047                         ret = check_insn_config_length(insn, data);
1048                         if (ret)
1049                                 break;
1050                         ret = s->insn_config(dev, s, insn, data);
1051                         break;
1052                 default:
1053                         ret = -EINVAL;
1054                         break;
1055                 }
1056
1057                 s->busy = NULL;
1058         }
1059
1060 out:
1061         return ret;
1062 }
1063
1064 /*
1065  *      COMEDI_INSN
1066  *      synchronous instructions
1067  *
1068  *      arg:
1069  *              pointer to insn
1070  *
1071  *      reads:
1072  *              struct comedi_insn struct at arg
1073  *              data (for writes)
1074  *
1075  *      writes:
1076  *              data (for reads)
1077  */
1078 static int do_insn_ioctl(struct comedi_device *dev,
1079                          struct comedi_insn __user *arg, void *file)
1080 {
1081         struct comedi_insn insn;
1082         unsigned int *data = NULL;
1083         int ret = 0;
1084
1085         data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
1086         if (!data) {
1087                 ret = -ENOMEM;
1088                 goto error;
1089         }
1090
1091         if (copy_from_user(&insn, arg, sizeof(struct comedi_insn))) {
1092                 ret = -EFAULT;
1093                 goto error;
1094         }
1095
1096         /* This is where the behavior of insn and insnlist deviate. */
1097         if (insn.n > MAX_SAMPLES)
1098                 insn.n = MAX_SAMPLES;
1099         if (insn.insn & INSN_MASK_WRITE) {
1100                 if (copy_from_user(data,
1101                                    insn.data,
1102                                    insn.n * sizeof(unsigned int))) {
1103                         ret = -EFAULT;
1104                         goto error;
1105                 }
1106         }
1107         ret = parse_insn(dev, &insn, data, file);
1108         if (ret < 0)
1109                 goto error;
1110         if (insn.insn & INSN_MASK_READ) {
1111                 if (copy_to_user(insn.data,
1112                                  data,
1113                                  insn.n * sizeof(unsigned int))) {
1114                         ret = -EFAULT;
1115                         goto error;
1116                 }
1117         }
1118         ret = insn.n;
1119
1120 error:
1121         kfree(data);
1122
1123         return ret;
1124 }
1125
1126 static void comedi_set_subdevice_runflags(struct comedi_subdevice *s,
1127                                           unsigned mask, unsigned bits)
1128 {
1129         unsigned long flags;
1130
1131         spin_lock_irqsave(&s->spin_lock, flags);
1132         s->runflags &= ~mask;
1133         s->runflags |= (bits & mask);
1134         spin_unlock_irqrestore(&s->spin_lock, flags);
1135 }
1136
1137 static int do_cmd_ioctl(struct comedi_device *dev,
1138                         struct comedi_cmd __user *arg, void *file)
1139 {
1140         struct comedi_cmd cmd;
1141         struct comedi_subdevice *s;
1142         struct comedi_async *async;
1143         int ret = 0;
1144         unsigned int __user *user_chanlist;
1145
1146         if (copy_from_user(&cmd, arg, sizeof(struct comedi_cmd))) {
1147                 DPRINTK("bad cmd address\n");
1148                 return -EFAULT;
1149         }
1150         /* save user's chanlist pointer so it can be restored later */
1151         user_chanlist = (unsigned int __user *)cmd.chanlist;
1152
1153         if (cmd.subdev >= dev->n_subdevices) {
1154                 DPRINTK("%d no such subdevice\n", cmd.subdev);
1155                 return -ENODEV;
1156         }
1157
1158         s = &dev->subdevices[cmd.subdev];
1159         async = s->async;
1160
1161         if (s->type == COMEDI_SUBD_UNUSED) {
1162                 DPRINTK("%d not valid subdevice\n", cmd.subdev);
1163                 return -EIO;
1164         }
1165
1166         if (!s->do_cmd || !s->do_cmdtest || !s->async) {
1167                 DPRINTK("subdevice %i does not support commands\n",
1168                         cmd.subdev);
1169                 return -EIO;
1170         }
1171
1172         /* are we locked? (ioctl lock) */
1173         if (s->lock && s->lock != file) {
1174                 DPRINTK("subdevice locked\n");
1175                 return -EACCES;
1176         }
1177
1178         /* are we busy? */
1179         if (s->busy) {
1180                 DPRINTK("subdevice busy\n");
1181                 return -EBUSY;
1182         }
1183         s->busy = file;
1184
1185         /* make sure channel/gain list isn't too long */
1186         if (cmd.chanlist_len > s->len_chanlist) {
1187                 DPRINTK("channel/gain list too long %u > %d\n",
1188                         cmd.chanlist_len, s->len_chanlist);
1189                 ret = -EINVAL;
1190                 goto cleanup;
1191         }
1192
1193         /* make sure channel/gain list isn't too short */
1194         if (cmd.chanlist_len < 1) {
1195                 DPRINTK("channel/gain list too short %u < 1\n",
1196                         cmd.chanlist_len);
1197                 ret = -EINVAL;
1198                 goto cleanup;
1199         }
1200
1201         async->cmd = cmd;
1202         async->cmd.data = NULL;
1203         /* load channel/gain list */
1204         async->cmd.chanlist =
1205             kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1206         if (!async->cmd.chanlist) {
1207                 DPRINTK("allocation failed\n");
1208                 ret = -ENOMEM;
1209                 goto cleanup;
1210         }
1211
1212         if (copy_from_user(async->cmd.chanlist, user_chanlist,
1213                            async->cmd.chanlist_len * sizeof(int))) {
1214                 DPRINTK("fault reading chanlist\n");
1215                 ret = -EFAULT;
1216                 goto cleanup;
1217         }
1218
1219         /* make sure each element in channel/gain list is valid */
1220         ret = comedi_check_chanlist(s,
1221                                     async->cmd.chanlist_len,
1222                                     async->cmd.chanlist);
1223         if (ret < 0) {
1224                 DPRINTK("bad chanlist\n");
1225                 goto cleanup;
1226         }
1227
1228         ret = s->do_cmdtest(dev, s, &async->cmd);
1229
1230         if (async->cmd.flags & TRIG_BOGUS || ret) {
1231                 DPRINTK("test returned %d\n", ret);
1232                 cmd = async->cmd;
1233                 /* restore chanlist pointer before copying back */
1234                 cmd.chanlist = (unsigned int __force *)user_chanlist;
1235                 cmd.data = NULL;
1236                 if (copy_to_user(arg, &cmd, sizeof(struct comedi_cmd))) {
1237                         DPRINTK("fault writing cmd\n");
1238                         ret = -EFAULT;
1239                         goto cleanup;
1240                 }
1241                 ret = -EAGAIN;
1242                 goto cleanup;
1243         }
1244
1245         if (!async->prealloc_bufsz) {
1246                 ret = -ENOMEM;
1247                 DPRINTK("no buffer (?)\n");
1248                 goto cleanup;
1249         }
1250
1251         comedi_reset_async_buf(async);
1252
1253         async->cb_mask =
1254             COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
1255             COMEDI_CB_OVERFLOW;
1256         if (async->cmd.flags & TRIG_WAKE_EOS)
1257                 async->cb_mask |= COMEDI_CB_EOS;
1258
1259         comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING);
1260
1261         ret = s->do_cmd(dev, s);
1262         if (ret == 0)
1263                 return 0;
1264
1265 cleanup:
1266         do_become_nonbusy(dev, s);
1267
1268         return ret;
1269 }
1270
1271 /*
1272         COMEDI_CMDTEST
1273         command testing ioctl
1274
1275         arg:
1276                 pointer to cmd structure
1277
1278         reads:
1279                 cmd structure at arg
1280                 channel/range list
1281
1282         writes:
1283                 modified cmd structure at arg
1284
1285 */
1286 static int do_cmdtest_ioctl(struct comedi_device *dev,
1287                             struct comedi_cmd __user *arg, void *file)
1288 {
1289         struct comedi_cmd cmd;
1290         struct comedi_subdevice *s;
1291         int ret = 0;
1292         unsigned int *chanlist = NULL;
1293         unsigned int __user *user_chanlist;
1294
1295         if (copy_from_user(&cmd, arg, sizeof(struct comedi_cmd))) {
1296                 DPRINTK("bad cmd address\n");
1297                 return -EFAULT;
1298         }
1299         /* save user's chanlist pointer so it can be restored later */
1300         user_chanlist = (unsigned int __user *)cmd.chanlist;
1301
1302         if (cmd.subdev >= dev->n_subdevices) {
1303                 DPRINTK("%d no such subdevice\n", cmd.subdev);
1304                 return -ENODEV;
1305         }
1306
1307         s = &dev->subdevices[cmd.subdev];
1308         if (s->type == COMEDI_SUBD_UNUSED) {
1309                 DPRINTK("%d not valid subdevice\n", cmd.subdev);
1310                 return -EIO;
1311         }
1312
1313         if (!s->do_cmd || !s->do_cmdtest) {
1314                 DPRINTK("subdevice %i does not support commands\n",
1315                         cmd.subdev);
1316                 return -EIO;
1317         }
1318
1319         /* make sure channel/gain list isn't too long */
1320         if (cmd.chanlist_len > s->len_chanlist) {
1321                 DPRINTK("channel/gain list too long %d > %d\n",
1322                         cmd.chanlist_len, s->len_chanlist);
1323                 ret = -EINVAL;
1324                 goto cleanup;
1325         }
1326
1327         /* load channel/gain list */
1328         if (cmd.chanlist) {
1329                 chanlist =
1330                     kmalloc(cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1331                 if (!chanlist) {
1332                         DPRINTK("allocation failed\n");
1333                         ret = -ENOMEM;
1334                         goto cleanup;
1335                 }
1336
1337                 if (copy_from_user(chanlist, user_chanlist,
1338                                    cmd.chanlist_len * sizeof(int))) {
1339                         DPRINTK("fault reading chanlist\n");
1340                         ret = -EFAULT;
1341                         goto cleanup;
1342                 }
1343
1344                 /* make sure each element in channel/gain list is valid */
1345                 ret = comedi_check_chanlist(s, cmd.chanlist_len, chanlist);
1346                 if (ret < 0) {
1347                         DPRINTK("bad chanlist\n");
1348                         goto cleanup;
1349                 }
1350
1351                 cmd.chanlist = chanlist;
1352         }
1353
1354         ret = s->do_cmdtest(dev, s, &cmd);
1355
1356         /* restore chanlist pointer before copying back */
1357         cmd.chanlist = (unsigned int __force *)user_chanlist;
1358
1359         if (copy_to_user(arg, &cmd, sizeof(struct comedi_cmd))) {
1360                 DPRINTK("bad cmd address\n");
1361                 ret = -EFAULT;
1362                 goto cleanup;
1363         }
1364 cleanup:
1365         kfree(chanlist);
1366
1367         return ret;
1368 }
1369
1370 /*
1371         COMEDI_LOCK
1372         lock subdevice
1373
1374         arg:
1375                 subdevice number
1376
1377         reads:
1378                 none
1379
1380         writes:
1381                 none
1382
1383 */
1384
1385 static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
1386                          void *file)
1387 {
1388         int ret = 0;
1389         unsigned long flags;
1390         struct comedi_subdevice *s;
1391
1392         if (arg >= dev->n_subdevices)
1393                 return -EINVAL;
1394         s = &dev->subdevices[arg];
1395
1396         spin_lock_irqsave(&s->spin_lock, flags);
1397         if (s->busy || s->lock)
1398                 ret = -EBUSY;
1399         else
1400                 s->lock = file;
1401         spin_unlock_irqrestore(&s->spin_lock, flags);
1402
1403 #if 0
1404         if (ret < 0)
1405                 return ret;
1406
1407         if (s->lock_f)
1408                 ret = s->lock_f(dev, s);
1409 #endif
1410
1411         return ret;
1412 }
1413
1414 /*
1415         COMEDI_UNLOCK
1416         unlock subdevice
1417
1418         arg:
1419                 subdevice number
1420
1421         reads:
1422                 none
1423
1424         writes:
1425                 none
1426
1427         This function isn't protected by the semaphore, since
1428         we already own the lock.
1429 */
1430 static int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
1431                            void *file)
1432 {
1433         struct comedi_subdevice *s;
1434
1435         if (arg >= dev->n_subdevices)
1436                 return -EINVAL;
1437         s = &dev->subdevices[arg];
1438
1439         if (s->busy)
1440                 return -EBUSY;
1441
1442         if (s->lock && s->lock != file)
1443                 return -EACCES;
1444
1445         if (s->lock == file) {
1446 #if 0
1447                 if (s->unlock)
1448                         s->unlock(dev, s);
1449 #endif
1450
1451                 s->lock = NULL;
1452         }
1453
1454         return 0;
1455 }
1456
1457 /*
1458         COMEDI_CANCEL
1459         cancel acquisition ioctl
1460
1461         arg:
1462                 subdevice number
1463
1464         reads:
1465                 nothing
1466
1467         writes:
1468                 nothing
1469
1470 */
1471 static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
1472                            void *file)
1473 {
1474         struct comedi_subdevice *s;
1475
1476         if (arg >= dev->n_subdevices)
1477                 return -EINVAL;
1478         s = &dev->subdevices[arg];
1479         if (s->async == NULL)
1480                 return -EINVAL;
1481
1482         if (s->lock && s->lock != file)
1483                 return -EACCES;
1484
1485         if (!s->busy)
1486                 return 0;
1487
1488         if (s->busy != file)
1489                 return -EBUSY;
1490
1491         return do_cancel(dev, s);
1492 }
1493
1494 /*
1495         COMEDI_POLL ioctl
1496         instructs driver to synchronize buffers
1497
1498         arg:
1499                 subdevice number
1500
1501         reads:
1502                 nothing
1503
1504         writes:
1505                 nothing
1506
1507 */
1508 static int do_poll_ioctl(struct comedi_device *dev, unsigned int arg,
1509                          void *file)
1510 {
1511         struct comedi_subdevice *s;
1512
1513         if (arg >= dev->n_subdevices)
1514                 return -EINVAL;
1515         s = &dev->subdevices[arg];
1516
1517         if (s->lock && s->lock != file)
1518                 return -EACCES;
1519
1520         if (!s->busy)
1521                 return 0;
1522
1523         if (s->busy != file)
1524                 return -EBUSY;
1525
1526         if (s->poll)
1527                 return s->poll(dev, s);
1528
1529         return -EINVAL;
1530 }
1531
1532 static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
1533                                   unsigned long arg)
1534 {
1535         const unsigned minor = iminor(file->f_dentry->d_inode);
1536         struct comedi_device_file_info *dev_file_info =
1537             comedi_get_device_file_info(minor);
1538         struct comedi_device *dev;
1539         int rc;
1540
1541         if (dev_file_info == NULL || dev_file_info->device == NULL)
1542                 return -ENODEV;
1543         dev = dev_file_info->device;
1544
1545         mutex_lock(&dev->mutex);
1546
1547         /* Device config is special, because it must work on
1548          * an unconfigured device. */
1549         if (cmd == COMEDI_DEVCONFIG) {
1550                 rc = do_devconfig_ioctl(dev,
1551                                         (struct comedi_devconfig __user *)arg);
1552                 goto done;
1553         }
1554
1555         if (!dev->attached) {
1556                 DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor);
1557                 rc = -ENODEV;
1558                 goto done;
1559         }
1560
1561         switch (cmd) {
1562         case COMEDI_BUFCONFIG:
1563                 rc = do_bufconfig_ioctl(dev,
1564                                         (struct comedi_bufconfig __user *)arg);
1565                 break;
1566         case COMEDI_DEVINFO:
1567                 rc = do_devinfo_ioctl(dev, (struct comedi_devinfo __user *)arg,
1568                                       file);
1569                 break;
1570         case COMEDI_SUBDINFO:
1571                 rc = do_subdinfo_ioctl(dev,
1572                                        (struct comedi_subdinfo __user *)arg,
1573                                        file);
1574                 break;
1575         case COMEDI_CHANINFO:
1576                 rc = do_chaninfo_ioctl(dev, (void __user *)arg);
1577                 break;
1578         case COMEDI_RANGEINFO:
1579                 rc = do_rangeinfo_ioctl(dev, (void __user *)arg);
1580                 break;
1581         case COMEDI_BUFINFO:
1582                 rc = do_bufinfo_ioctl(dev,
1583                                       (struct comedi_bufinfo __user *)arg,
1584                                       file);
1585                 break;
1586         case COMEDI_LOCK:
1587                 rc = do_lock_ioctl(dev, arg, file);
1588                 break;
1589         case COMEDI_UNLOCK:
1590                 rc = do_unlock_ioctl(dev, arg, file);
1591                 break;
1592         case COMEDI_CANCEL:
1593                 rc = do_cancel_ioctl(dev, arg, file);
1594                 break;
1595         case COMEDI_CMD:
1596                 rc = do_cmd_ioctl(dev, (struct comedi_cmd __user *)arg, file);
1597                 break;
1598         case COMEDI_CMDTEST:
1599                 rc = do_cmdtest_ioctl(dev, (struct comedi_cmd __user *)arg,
1600                                       file);
1601                 break;
1602         case COMEDI_INSNLIST:
1603                 rc = do_insnlist_ioctl(dev,
1604                                        (struct comedi_insnlist __user *)arg,
1605                                        file);
1606                 break;
1607         case COMEDI_INSN:
1608                 rc = do_insn_ioctl(dev, (struct comedi_insn __user *)arg,
1609                                    file);
1610                 break;
1611         case COMEDI_POLL:
1612                 rc = do_poll_ioctl(dev, arg, file);
1613                 break;
1614         default:
1615                 rc = -ENOTTY;
1616                 break;
1617         }
1618
1619 done:
1620         mutex_unlock(&dev->mutex);
1621         return rc;
1622 }
1623
1624 static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
1625 {
1626         int ret = 0;
1627
1628         if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) && s->cancel)
1629                 ret = s->cancel(dev, s);
1630
1631         do_become_nonbusy(dev, s);
1632
1633         return ret;
1634 }
1635
1636
1637 static void comedi_vm_open(struct vm_area_struct *area)
1638 {
1639         struct comedi_async *async;
1640         struct comedi_device *dev;
1641
1642         async = area->vm_private_data;
1643         dev = async->subdevice->device;
1644
1645         mutex_lock(&dev->mutex);
1646         async->mmap_count++;
1647         mutex_unlock(&dev->mutex);
1648 }
1649
1650 static void comedi_vm_close(struct vm_area_struct *area)
1651 {
1652         struct comedi_async *async;
1653         struct comedi_device *dev;
1654
1655         async = area->vm_private_data;
1656         dev = async->subdevice->device;
1657
1658         mutex_lock(&dev->mutex);
1659         async->mmap_count--;
1660         mutex_unlock(&dev->mutex);
1661 }
1662
1663 static struct vm_operations_struct comedi_vm_ops = {
1664         .open = comedi_vm_open,
1665         .close = comedi_vm_close,
1666 };
1667
1668 static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
1669 {
1670         const unsigned minor = iminor(file->f_dentry->d_inode);
1671         struct comedi_async *async = NULL;
1672         unsigned long start = vma->vm_start;
1673         unsigned long size;
1674         int n_pages;
1675         int i;
1676         int retval;
1677         struct comedi_subdevice *s;
1678         struct comedi_device_file_info *dev_file_info;
1679         struct comedi_device *dev;
1680
1681         dev_file_info = comedi_get_device_file_info(minor);
1682         if (dev_file_info == NULL)
1683                 return -ENODEV;
1684         dev = dev_file_info->device;
1685         if (dev == NULL)
1686                 return -ENODEV;
1687
1688         mutex_lock(&dev->mutex);
1689         if (!dev->attached) {
1690                 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1691                 retval = -ENODEV;
1692                 goto done;
1693         }
1694         if (vma->vm_flags & VM_WRITE)
1695                 s = comedi_get_write_subdevice(dev_file_info);
1696         else
1697                 s = comedi_get_read_subdevice(dev_file_info);
1698
1699         if (s == NULL) {
1700                 retval = -EINVAL;
1701                 goto done;
1702         }
1703         async = s->async;
1704         if (async == NULL) {
1705                 retval = -EINVAL;
1706                 goto done;
1707         }
1708
1709         if (vma->vm_pgoff != 0) {
1710                 DPRINTK("comedi: mmap() offset must be 0.\n");
1711                 retval = -EINVAL;
1712                 goto done;
1713         }
1714
1715         size = vma->vm_end - vma->vm_start;
1716         if (size > async->prealloc_bufsz) {
1717                 retval = -EFAULT;
1718                 goto done;
1719         }
1720         if (size & (~PAGE_MASK)) {
1721                 retval = -EFAULT;
1722                 goto done;
1723         }
1724
1725         n_pages = size >> PAGE_SHIFT;
1726         for (i = 0; i < n_pages; ++i) {
1727                 if (remap_pfn_range(vma, start,
1728                                     page_to_pfn(virt_to_page
1729                                                 (async->buf_page_list
1730                                                  [i].virt_addr)), PAGE_SIZE,
1731                                     PAGE_SHARED)) {
1732                         retval = -EAGAIN;
1733                         goto done;
1734                 }
1735                 start += PAGE_SIZE;
1736         }
1737
1738         vma->vm_ops = &comedi_vm_ops;
1739         vma->vm_private_data = async;
1740
1741         async->mmap_count++;
1742
1743         retval = 0;
1744 done:
1745         mutex_unlock(&dev->mutex);
1746         return retval;
1747 }
1748
1749 static unsigned int comedi_poll(struct file *file, poll_table *wait)
1750 {
1751         unsigned int mask = 0;
1752         const unsigned minor = iminor(file->f_dentry->d_inode);
1753         struct comedi_subdevice *read_subdev;
1754         struct comedi_subdevice *write_subdev;
1755         struct comedi_device_file_info *dev_file_info;
1756         struct comedi_device *dev;
1757         dev_file_info = comedi_get_device_file_info(minor);
1758
1759         if (dev_file_info == NULL)
1760                 return -ENODEV;
1761         dev = dev_file_info->device;
1762         if (dev == NULL)
1763                 return -ENODEV;
1764
1765         mutex_lock(&dev->mutex);
1766         if (!dev->attached) {
1767                 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1768                 mutex_unlock(&dev->mutex);
1769                 return 0;
1770         }
1771
1772         mask = 0;
1773         read_subdev = comedi_get_read_subdevice(dev_file_info);
1774         if (read_subdev) {
1775                 poll_wait(file, &read_subdev->async->wait_head, wait);
1776                 if (!read_subdev->busy
1777                     || comedi_buf_read_n_available(read_subdev->async) > 0
1778                     || !(comedi_get_subdevice_runflags(read_subdev) &
1779                          SRF_RUNNING)) {
1780                         mask |= POLLIN | POLLRDNORM;
1781                 }
1782         }
1783         write_subdev = comedi_get_write_subdevice(dev_file_info);
1784         if (write_subdev) {
1785                 poll_wait(file, &write_subdev->async->wait_head, wait);
1786                 comedi_buf_write_alloc(write_subdev->async,
1787                                        write_subdev->async->prealloc_bufsz);
1788                 if (!write_subdev->busy
1789                     || !(comedi_get_subdevice_runflags(write_subdev) &
1790                          SRF_RUNNING)
1791                     || comedi_buf_write_n_allocated(write_subdev->async) >=
1792                     bytes_per_sample(write_subdev->async->subdevice)) {
1793                         mask |= POLLOUT | POLLWRNORM;
1794                 }
1795         }
1796
1797         mutex_unlock(&dev->mutex);
1798         return mask;
1799 }
1800
1801 static ssize_t comedi_write(struct file *file, const char __user *buf,
1802                             size_t nbytes, loff_t *offset)
1803 {
1804         struct comedi_subdevice *s;
1805         struct comedi_async *async;
1806         int n, m, count = 0, retval = 0;
1807         DECLARE_WAITQUEUE(wait, current);
1808         const unsigned minor = iminor(file->f_dentry->d_inode);
1809         struct comedi_device_file_info *dev_file_info;
1810         struct comedi_device *dev;
1811         dev_file_info = comedi_get_device_file_info(minor);
1812
1813         if (dev_file_info == NULL)
1814                 return -ENODEV;
1815         dev = dev_file_info->device;
1816         if (dev == NULL)
1817                 return -ENODEV;
1818
1819         if (!dev->attached) {
1820                 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1821                 retval = -ENODEV;
1822                 goto done;
1823         }
1824
1825         s = comedi_get_write_subdevice(dev_file_info);
1826         if (s == NULL) {
1827                 retval = -EIO;
1828                 goto done;
1829         }
1830         async = s->async;
1831
1832         if (!nbytes) {
1833                 retval = 0;
1834                 goto done;
1835         }
1836         if (!s->busy) {
1837                 retval = 0;
1838                 goto done;
1839         }
1840         if (s->busy != file) {
1841                 retval = -EACCES;
1842                 goto done;
1843         }
1844         add_wait_queue(&async->wait_head, &wait);
1845         while (nbytes > 0 && !retval) {
1846                 set_current_state(TASK_INTERRUPTIBLE);
1847
1848                 if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1849                         if (count == 0) {
1850                                 if (comedi_get_subdevice_runflags(s) &
1851                                         SRF_ERROR) {
1852                                         retval = -EPIPE;
1853                                 } else {
1854                                         retval = 0;
1855                                 }
1856                                 do_become_nonbusy(dev, s);
1857                         }
1858                         break;
1859                 }
1860
1861                 n = nbytes;
1862
1863                 m = n;
1864                 if (async->buf_write_ptr + m > async->prealloc_bufsz)
1865                         m = async->prealloc_bufsz - async->buf_write_ptr;
1866                 comedi_buf_write_alloc(async, async->prealloc_bufsz);
1867                 if (m > comedi_buf_write_n_allocated(async))
1868                         m = comedi_buf_write_n_allocated(async);
1869                 if (m < n)
1870                         n = m;
1871
1872                 if (n == 0) {
1873                         if (file->f_flags & O_NONBLOCK) {
1874                                 retval = -EAGAIN;
1875                                 break;
1876                         }
1877                         schedule();
1878                         if (signal_pending(current)) {
1879                                 retval = -ERESTARTSYS;
1880                                 break;
1881                         }
1882                         if (!s->busy)
1883                                 break;
1884                         if (s->busy != file) {
1885                                 retval = -EACCES;
1886                                 break;
1887                         }
1888                         continue;
1889                 }
1890
1891                 m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
1892                                    buf, n);
1893                 if (m) {
1894                         n -= m;
1895                         retval = -EFAULT;
1896                 }
1897                 comedi_buf_write_free(async, n);
1898
1899                 count += n;
1900                 nbytes -= n;
1901
1902                 buf += n;
1903                 break;          /* makes device work like a pipe */
1904         }
1905         set_current_state(TASK_RUNNING);
1906         remove_wait_queue(&async->wait_head, &wait);
1907
1908 done:
1909         return count ? count : retval;
1910 }
1911
1912 static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
1913                                 loff_t *offset)
1914 {
1915         struct comedi_subdevice *s;
1916         struct comedi_async *async;
1917         int n, m, count = 0, retval = 0;
1918         DECLARE_WAITQUEUE(wait, current);
1919         const unsigned minor = iminor(file->f_dentry->d_inode);
1920         struct comedi_device_file_info *dev_file_info;
1921         struct comedi_device *dev;
1922         dev_file_info = comedi_get_device_file_info(minor);
1923
1924         if (dev_file_info == NULL)
1925                 return -ENODEV;
1926         dev = dev_file_info->device;
1927         if (dev == NULL)
1928                 return -ENODEV;
1929
1930         if (!dev->attached) {
1931                 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1932                 retval = -ENODEV;
1933                 goto done;
1934         }
1935
1936         s = comedi_get_read_subdevice(dev_file_info);
1937         if (s == NULL) {
1938                 retval = -EIO;
1939                 goto done;
1940         }
1941         async = s->async;
1942         if (!nbytes) {
1943                 retval = 0;
1944                 goto done;
1945         }
1946         if (!s->busy) {
1947                 retval = 0;
1948                 goto done;
1949         }
1950         if (s->busy != file) {
1951                 retval = -EACCES;
1952                 goto done;
1953         }
1954
1955         add_wait_queue(&async->wait_head, &wait);
1956         while (nbytes > 0 && !retval) {
1957                 set_current_state(TASK_INTERRUPTIBLE);
1958
1959                 n = nbytes;
1960
1961                 m = comedi_buf_read_n_available(async);
1962                 /* printk("%d available\n",m); */
1963                 if (async->buf_read_ptr + m > async->prealloc_bufsz)
1964                         m = async->prealloc_bufsz - async->buf_read_ptr;
1965                 /* printk("%d contiguous\n",m); */
1966                 if (m < n)
1967                         n = m;
1968
1969                 if (n == 0) {
1970                         if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1971                                 do_become_nonbusy(dev, s);
1972                                 if (comedi_get_subdevice_runflags(s) &
1973                                     SRF_ERROR) {
1974                                         retval = -EPIPE;
1975                                 } else {
1976                                         retval = 0;
1977                                 }
1978                                 break;
1979                         }
1980                         if (file->f_flags & O_NONBLOCK) {
1981                                 retval = -EAGAIN;
1982                                 break;
1983                         }
1984                         schedule();
1985                         if (signal_pending(current)) {
1986                                 retval = -ERESTARTSYS;
1987                                 break;
1988                         }
1989                         if (!s->busy) {
1990                                 retval = 0;
1991                                 break;
1992                         }
1993                         if (s->busy != file) {
1994                                 retval = -EACCES;
1995                                 break;
1996                         }
1997                         continue;
1998                 }
1999                 m = copy_to_user(buf, async->prealloc_buf +
2000                                  async->buf_read_ptr, n);
2001                 if (m) {
2002                         n -= m;
2003                         retval = -EFAULT;
2004                 }
2005
2006                 comedi_buf_read_alloc(async, n);
2007                 comedi_buf_read_free(async, n);
2008
2009                 count += n;
2010                 nbytes -= n;
2011
2012                 buf += n;
2013                 break;          /* makes device work like a pipe */
2014         }
2015         if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) &&
2016             async->buf_read_count - async->buf_write_count == 0) {
2017                 do_become_nonbusy(dev, s);
2018         }
2019         set_current_state(TASK_RUNNING);
2020         remove_wait_queue(&async->wait_head, &wait);
2021
2022 done:
2023         return count ? count : retval;
2024 }
2025
2026 /*
2027    This function restores a subdevice to an idle state.
2028  */
2029 static void do_become_nonbusy(struct comedi_device *dev,
2030                               struct comedi_subdevice *s)
2031 {
2032         struct comedi_async *async = s->async;
2033
2034         comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
2035         if (async) {
2036                 comedi_reset_async_buf(async);
2037                 async->inttrig = NULL;
2038                 kfree(async->cmd.chanlist);
2039                 async->cmd.chanlist = NULL;
2040         } else {
2041                 dev_err(dev->class_dev,
2042                         "BUG: (?) do_become_nonbusy called with async=NULL\n");
2043         }
2044
2045         s->busy = NULL;
2046 }
2047
2048 static int comedi_open(struct inode *inode, struct file *file)
2049 {
2050         const unsigned minor = iminor(inode);
2051         struct comedi_device_file_info *dev_file_info =
2052             comedi_get_device_file_info(minor);
2053         struct comedi_device *dev =
2054             dev_file_info ? dev_file_info->device : NULL;
2055
2056         if (dev == NULL) {
2057                 DPRINTK("invalid minor number\n");
2058                 return -ENODEV;
2059         }
2060
2061         /* This is slightly hacky, but we want module autoloading
2062          * to work for root.
2063          * case: user opens device, attached -> ok
2064          * case: user opens device, unattached, in_request_module=0 -> autoload
2065          * case: user opens device, unattached, in_request_module=1 -> fail
2066          * case: root opens device, attached -> ok
2067          * case: root opens device, unattached, in_request_module=1 -> ok
2068          *   (typically called from modprobe)
2069          * case: root opens device, unattached, in_request_module=0 -> autoload
2070          *
2071          * The last could be changed to "-> ok", which would deny root
2072          * autoloading.
2073          */
2074         mutex_lock(&dev->mutex);
2075         if (dev->attached)
2076                 goto ok;
2077         if (!capable(CAP_NET_ADMIN) && dev->in_request_module) {
2078                 DPRINTK("in request module\n");
2079                 mutex_unlock(&dev->mutex);
2080                 return -ENODEV;
2081         }
2082         if (capable(CAP_NET_ADMIN) && dev->in_request_module)
2083                 goto ok;
2084
2085         dev->in_request_module = 1;
2086
2087 #ifdef CONFIG_KMOD
2088         mutex_unlock(&dev->mutex);
2089         request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor);
2090         mutex_lock(&dev->mutex);
2091 #endif
2092
2093         dev->in_request_module = 0;
2094
2095         if (!dev->attached && !capable(CAP_NET_ADMIN)) {
2096                 DPRINTK("not attached and not CAP_NET_ADMIN\n");
2097                 mutex_unlock(&dev->mutex);
2098                 return -ENODEV;
2099         }
2100 ok:
2101         __module_get(THIS_MODULE);
2102
2103         if (dev->attached) {
2104                 if (!try_module_get(dev->driver->module)) {
2105                         module_put(THIS_MODULE);
2106                         mutex_unlock(&dev->mutex);
2107                         return -ENOSYS;
2108                 }
2109         }
2110
2111         if (dev->attached && dev->use_count == 0 && dev->open) {
2112                 int rc = dev->open(dev);
2113                 if (rc < 0) {
2114                         module_put(dev->driver->module);
2115                         module_put(THIS_MODULE);
2116                         mutex_unlock(&dev->mutex);
2117                         return rc;
2118                 }
2119         }
2120
2121         dev->use_count++;
2122
2123         mutex_unlock(&dev->mutex);
2124
2125         return 0;
2126 }
2127
2128 static int comedi_close(struct inode *inode, struct file *file)
2129 {
2130         const unsigned minor = iminor(inode);
2131         struct comedi_subdevice *s = NULL;
2132         int i;
2133         struct comedi_device_file_info *dev_file_info;
2134         struct comedi_device *dev;
2135         dev_file_info = comedi_get_device_file_info(minor);
2136
2137         if (dev_file_info == NULL)
2138                 return -ENODEV;
2139         dev = dev_file_info->device;
2140         if (dev == NULL)
2141                 return -ENODEV;
2142
2143         mutex_lock(&dev->mutex);
2144
2145         if (dev->subdevices) {
2146                 for (i = 0; i < dev->n_subdevices; i++) {
2147                         s = &dev->subdevices[i];
2148
2149                         if (s->busy == file)
2150                                 do_cancel(dev, s);
2151                         if (s->lock == file)
2152                                 s->lock = NULL;
2153                 }
2154         }
2155         if (dev->attached && dev->use_count == 1 && dev->close)
2156                 dev->close(dev);
2157
2158         module_put(THIS_MODULE);
2159         if (dev->attached)
2160                 module_put(dev->driver->module);
2161
2162         dev->use_count--;
2163
2164         mutex_unlock(&dev->mutex);
2165
2166         if (file->f_flags & FASYNC)
2167                 comedi_fasync(-1, file, 0);
2168
2169         return 0;
2170 }
2171
2172 static int comedi_fasync(int fd, struct file *file, int on)
2173 {
2174         const unsigned minor = iminor(file->f_dentry->d_inode);
2175         struct comedi_device_file_info *dev_file_info;
2176         struct comedi_device *dev;
2177         dev_file_info = comedi_get_device_file_info(minor);
2178
2179         if (dev_file_info == NULL)
2180                 return -ENODEV;
2181         dev = dev_file_info->device;
2182         if (dev == NULL)
2183                 return -ENODEV;
2184
2185         return fasync_helper(fd, file, on, &dev->async_queue);
2186 }
2187
2188 static const struct file_operations comedi_fops = {
2189         .owner = THIS_MODULE,
2190         .unlocked_ioctl = comedi_unlocked_ioctl,
2191         .compat_ioctl = comedi_compat_ioctl,
2192         .open = comedi_open,
2193         .release = comedi_close,
2194         .read = comedi_read,
2195         .write = comedi_write,
2196         .mmap = comedi_mmap,
2197         .poll = comedi_poll,
2198         .fasync = comedi_fasync,
2199         .llseek = noop_llseek,
2200 };
2201
2202 static struct class *comedi_class;
2203 static struct cdev comedi_cdev;
2204
2205 static void comedi_cleanup_legacy_minors(void)
2206 {
2207         unsigned i;
2208
2209         for (i = 0; i < comedi_num_legacy_minors; i++)
2210                 comedi_free_board_minor(i);
2211 }
2212
2213 static int __init comedi_init(void)
2214 {
2215         int i;
2216         int retval;
2217
2218         pr_info("comedi: version " COMEDI_RELEASE " - http://www.comedi.org\n");
2219
2220         if (comedi_num_legacy_minors < 0 ||
2221             comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
2222                 pr_err("comedi: error: invalid value for module parameter \"comedi_num_legacy_minors\".  Valid values are 0 through %i.\n",
2223                        COMEDI_NUM_BOARD_MINORS);
2224                 return -EINVAL;
2225         }
2226
2227         /*
2228          * comedi is unusable if both comedi_autoconfig and
2229          * comedi_num_legacy_minors are zero, so we might as well adjust the
2230          * defaults in that case
2231          */
2232         if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0)
2233                 comedi_num_legacy_minors = 16;
2234
2235         memset(comedi_file_info_table, 0,
2236                sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS);
2237
2238         retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2239                                         COMEDI_NUM_MINORS, "comedi");
2240         if (retval)
2241                 return -EIO;
2242         cdev_init(&comedi_cdev, &comedi_fops);
2243         comedi_cdev.owner = THIS_MODULE;
2244         kobject_set_name(&comedi_cdev.kobj, "comedi");
2245         if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
2246                 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2247                                          COMEDI_NUM_MINORS);
2248                 return -EIO;
2249         }
2250         comedi_class = class_create(THIS_MODULE, "comedi");
2251         if (IS_ERR(comedi_class)) {
2252                 pr_err("comedi: failed to create class\n");
2253                 cdev_del(&comedi_cdev);
2254                 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2255                                          COMEDI_NUM_MINORS);
2256                 return PTR_ERR(comedi_class);
2257         }
2258
2259         comedi_class->dev_attrs = comedi_dev_attrs;
2260
2261         /* XXX requires /proc interface */
2262         comedi_proc_init();
2263
2264         /* create devices files for legacy/manual use */
2265         for (i = 0; i < comedi_num_legacy_minors; i++) {
2266                 int minor;
2267                 minor = comedi_alloc_board_minor(NULL);
2268                 if (minor < 0) {
2269                         comedi_cleanup_legacy_minors();
2270                         cdev_del(&comedi_cdev);
2271                         unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2272                                                  COMEDI_NUM_MINORS);
2273                         return minor;
2274                 }
2275         }
2276
2277         return 0;
2278 }
2279
2280 static void __exit comedi_cleanup(void)
2281 {
2282         int i;
2283
2284         comedi_cleanup_legacy_minors();
2285         for (i = 0; i < COMEDI_NUM_MINORS; ++i)
2286                 BUG_ON(comedi_file_info_table[i]);
2287
2288         class_destroy(comedi_class);
2289         cdev_del(&comedi_cdev);
2290         unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
2291
2292         comedi_proc_cleanup();
2293 }
2294
2295 module_init(comedi_init);
2296 module_exit(comedi_cleanup);
2297
2298 void comedi_error(const struct comedi_device *dev, const char *s)
2299 {
2300         dev_err(dev->class_dev, "%s: %s\n", dev->driver->driver_name, s);
2301 }
2302 EXPORT_SYMBOL(comedi_error);
2303
2304 void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
2305 {
2306         struct comedi_async *async = s->async;
2307         unsigned runflags = 0;
2308         unsigned runflags_mask = 0;
2309
2310         /* DPRINTK("comedi_event 0x%x\n",mask); */
2311
2312         if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0)
2313                 return;
2314
2315         if (s->
2316             async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
2317                              COMEDI_CB_OVERFLOW)) {
2318                 runflags_mask |= SRF_RUNNING;
2319         }
2320         /* remember if an error event has occurred, so an error
2321          * can be returned the next time the user does a read() */
2322         if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2323                 runflags_mask |= SRF_ERROR;
2324                 runflags |= SRF_ERROR;
2325         }
2326         if (runflags_mask) {
2327                 /*sets SRF_ERROR and SRF_RUNNING together atomically */
2328                 comedi_set_subdevice_runflags(s, runflags_mask, runflags);
2329         }
2330
2331         if (async->cb_mask & s->async->events) {
2332                 if (comedi_get_subdevice_runflags(s) & SRF_USER) {
2333                         wake_up_interruptible(&async->wait_head);
2334                         if (s->subdev_flags & SDF_CMD_READ)
2335                                 kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
2336                         if (s->subdev_flags & SDF_CMD_WRITE)
2337                                 kill_fasync(&dev->async_queue, SIGIO, POLL_OUT);
2338                 } else {
2339                         if (async->cb_func)
2340                                 async->cb_func(s->async->events, async->cb_arg);
2341                 }
2342         }
2343         s->async->events = 0;
2344 }
2345 EXPORT_SYMBOL(comedi_event);
2346
2347 unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
2348 {
2349         unsigned long flags;
2350         unsigned runflags;
2351
2352         spin_lock_irqsave(&s->spin_lock, flags);
2353         runflags = s->runflags;
2354         spin_unlock_irqrestore(&s->spin_lock, flags);
2355         return runflags;
2356 }
2357 EXPORT_SYMBOL(comedi_get_subdevice_runflags);
2358
2359 static int is_device_busy(struct comedi_device *dev)
2360 {
2361         struct comedi_subdevice *s;
2362         int i;
2363
2364         if (!dev->attached)
2365                 return 0;
2366
2367         for (i = 0; i < dev->n_subdevices; i++) {
2368                 s = &dev->subdevices[i];
2369                 if (s->busy)
2370                         return 1;
2371                 if (s->async && s->async->mmap_count)
2372                         return 1;
2373         }
2374
2375         return 0;
2376 }
2377
2378 static void comedi_device_init(struct comedi_device *dev)
2379 {
2380         memset(dev, 0, sizeof(struct comedi_device));
2381         spin_lock_init(&dev->spinlock);
2382         mutex_init(&dev->mutex);
2383         dev->minor = -1;
2384 }
2385
2386 static void comedi_device_cleanup(struct comedi_device *dev)
2387 {
2388         if (dev == NULL)
2389                 return;
2390         mutex_lock(&dev->mutex);
2391         comedi_device_detach(dev);
2392         mutex_unlock(&dev->mutex);
2393         mutex_destroy(&dev->mutex);
2394 }
2395
2396 int comedi_alloc_board_minor(struct device *hardware_device)
2397 {
2398         struct comedi_device_file_info *info;
2399         struct device *csdev;
2400         unsigned i;
2401
2402         info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2403         if (info == NULL)
2404                 return -ENOMEM;
2405         info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL);
2406         if (info->device == NULL) {
2407                 kfree(info);
2408                 return -ENOMEM;
2409         }
2410         info->hardware_device = hardware_device;
2411         comedi_device_init(info->device);
2412         spin_lock(&comedi_file_info_table_lock);
2413         for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) {
2414                 if (comedi_file_info_table[i] == NULL) {
2415                         comedi_file_info_table[i] = info;
2416                         break;
2417                 }
2418         }
2419         spin_unlock(&comedi_file_info_table_lock);
2420         if (i == COMEDI_NUM_BOARD_MINORS) {
2421                 comedi_device_cleanup(info->device);
2422                 kfree(info->device);
2423                 kfree(info);
2424                 pr_err("comedi: error: ran out of minor numbers for board device files.\n");
2425                 return -EBUSY;
2426         }
2427         info->device->minor = i;
2428         csdev = device_create(comedi_class, hardware_device,
2429                               MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i);
2430         if (!IS_ERR(csdev))
2431                 info->device->class_dev = csdev;
2432         dev_set_drvdata(csdev, info);
2433
2434         return i;
2435 }
2436
2437 void comedi_free_board_minor(unsigned minor)
2438 {
2439         struct comedi_device_file_info *info;
2440
2441         BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
2442         spin_lock(&comedi_file_info_table_lock);
2443         info = comedi_file_info_table[minor];
2444         comedi_file_info_table[minor] = NULL;
2445         spin_unlock(&comedi_file_info_table_lock);
2446
2447         if (info) {
2448                 struct comedi_device *dev = info->device;
2449                 if (dev) {
2450                         if (dev->class_dev) {
2451                                 device_destroy(comedi_class,
2452                                                MKDEV(COMEDI_MAJOR, dev->minor));
2453                         }
2454                         comedi_device_cleanup(dev);
2455                         kfree(dev);
2456                 }
2457                 kfree(info);
2458         }
2459 }
2460
2461 int comedi_find_board_minor(struct device *hardware_device)
2462 {
2463         int minor;
2464         struct comedi_device_file_info *info;
2465
2466         for (minor = 0; minor < COMEDI_NUM_BOARD_MINORS; minor++) {
2467                 spin_lock(&comedi_file_info_table_lock);
2468                 info = comedi_file_info_table[minor];
2469                 if (info && info->hardware_device == hardware_device) {
2470                         spin_unlock(&comedi_file_info_table_lock);
2471                         return minor;
2472                 }
2473                 spin_unlock(&comedi_file_info_table_lock);
2474         }
2475         return -ENODEV;
2476 }
2477
2478 int comedi_alloc_subdevice_minor(struct comedi_device *dev,
2479                                  struct comedi_subdevice *s)
2480 {
2481         struct comedi_device_file_info *info;
2482         struct device *csdev;
2483         unsigned i;
2484
2485         info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2486         if (info == NULL)
2487                 return -ENOMEM;
2488         info->device = dev;
2489         info->read_subdevice = s;
2490         info->write_subdevice = s;
2491         spin_lock(&comedi_file_info_table_lock);
2492         for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
2493                 if (comedi_file_info_table[i] == NULL) {
2494                         comedi_file_info_table[i] = info;
2495                         break;
2496                 }
2497         }
2498         spin_unlock(&comedi_file_info_table_lock);
2499         if (i == COMEDI_NUM_MINORS) {
2500                 kfree(info);
2501                 pr_err("comedi: error: ran out of minor numbers for board device files.\n");
2502                 return -EBUSY;
2503         }
2504         s->minor = i;
2505         csdev = device_create(comedi_class, dev->class_dev,
2506                               MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i_subd%i",
2507                               dev->minor, (int)(s - dev->subdevices));
2508         if (!IS_ERR(csdev))
2509                 s->class_dev = csdev;
2510         dev_set_drvdata(csdev, info);
2511
2512         return i;
2513 }
2514
2515 void comedi_free_subdevice_minor(struct comedi_subdevice *s)
2516 {
2517         struct comedi_device_file_info *info;
2518
2519         if (s == NULL)
2520                 return;
2521         if (s->minor < 0)
2522                 return;
2523
2524         BUG_ON(s->minor >= COMEDI_NUM_MINORS);
2525         BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
2526
2527         spin_lock(&comedi_file_info_table_lock);
2528         info = comedi_file_info_table[s->minor];
2529         comedi_file_info_table[s->minor] = NULL;
2530         spin_unlock(&comedi_file_info_table_lock);
2531
2532         if (s->class_dev) {
2533                 device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
2534                 s->class_dev = NULL;
2535         }
2536         kfree(info);
2537 }
2538
2539 struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
2540 {
2541         struct comedi_device_file_info *info;
2542
2543         BUG_ON(minor >= COMEDI_NUM_MINORS);
2544         spin_lock(&comedi_file_info_table_lock);
2545         info = comedi_file_info_table[minor];
2546         spin_unlock(&comedi_file_info_table_lock);
2547         return info;
2548 }
2549 EXPORT_SYMBOL_GPL(comedi_get_device_file_info);