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