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