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