cdea1bf0120a3cde950c867acb9adc28069b25db
[comedi.git] / comedi / comedi_fops.c
1 /*
2     comedi/comedi_fops.c
3     comedi kernel module
4
5     COMEDI - Linux Control and Measurement Device Interface
6     Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
7
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 */
23
24 #undef DEBUG
25
26 #define __NO_VERSION__
27 #include "comedi_fops.h"
28
29 #include <linux/module.h>
30 #include <linux/errno.h>
31 #include <linux/kernel.h>
32 #include <linux/sched.h>
33 #include <linux/fcntl.h>
34 #include <linux/delay.h>
35 #include <linux/ioport.h>
36 #include <linux/mm.h>
37 #include <linux/slab.h>
38 #include <linux/kmod.h>
39 #include <linux/poll.h>
40 #include <linux/init.h>
41 #include <linux/devfs_fs_kernel.h>
42 #include <linux/device.h>
43 #include <linux/vmalloc.h>
44 #include <linux/fs.h>
45 #include <linux/comedidev.h>
46 #include <linux/cdev.h>
47
48 #include <asm/io.h>
49 #include <asm/uaccess.h>
50
51 //#include "kvmem.h"
52
53 MODULE_AUTHOR("David Schleef <ds@schleef.org>");
54 MODULE_DESCRIPTION("Comedi core module");
55 MODULE_LICENSE("GPL");
56
57 #ifdef CONFIG_COMEDI_DEBUG
58 int comedi_debug;
59 module_param(comedi_debug, int, 0644);
60 #endif
61
62 comedi_device *comedi_devices;
63 spinlock_t big_comedi_lock; /* Dynamic initialization */
64
65 static int do_devconfig_ioctl(comedi_device *dev,comedi_devconfig *arg);
66 static int do_bufconfig_ioctl(comedi_device *dev,void *arg);
67 static int do_devinfo_ioctl(comedi_device *dev,comedi_devinfo *arg);
68 static int do_subdinfo_ioctl(comedi_device *dev,comedi_subdinfo *arg,void *file);
69 static int do_chaninfo_ioctl(comedi_device *dev,comedi_chaninfo *arg);
70 static int do_bufinfo_ioctl(comedi_device *dev,void *arg);
71 static int do_cmd_ioctl(comedi_device *dev,void *arg,void *file);
72 static int do_lock_ioctl(comedi_device *dev,unsigned int arg,void * file);
73 static int do_unlock_ioctl(comedi_device *dev,unsigned int arg,void * file);
74 static int do_cancel_ioctl(comedi_device *dev,unsigned int arg,void *file);
75 static int do_cmdtest_ioctl(comedi_device *dev,void *arg,void *file);
76 static int do_insnlist_ioctl(comedi_device *dev,void *arg,void *file);
77 static int do_insn_ioctl(comedi_device *dev,void *arg,void *file);
78 static int do_poll_ioctl(comedi_device *dev,unsigned int subd,void *file);
79
80 void do_become_nonbusy(comedi_device *dev,comedi_subdevice *s);
81 static int do_cancel(comedi_device *dev,comedi_subdevice *s);
82
83 static int comedi_fasync (int fd, struct file *file, int on);
84
85 static int comedi_ioctl(struct inode * inode,struct file * file,
86         unsigned int cmd, unsigned long arg)
87 {
88         const unsigned minor = iminor(inode);
89         comedi_device *dev = comedi_get_device_by_minor(minor);
90
91         /* Device config is special, because it must work on
92          * an unconfigured device. */
93         if(cmd==COMEDI_DEVCONFIG){
94                 return do_devconfig_ioctl(dev,(void *)arg);
95         }
96
97         if(!dev->attached){
98                 DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor);
99                 return -ENODEV;
100         }
101
102         switch(cmd)
103         {
104         case COMEDI_BUFCONFIG:
105                 return do_bufconfig_ioctl(dev,(void*)arg);
106         case COMEDI_DEVINFO:
107                 return do_devinfo_ioctl(dev,(void *)arg);
108         case COMEDI_SUBDINFO:
109                 return do_subdinfo_ioctl(dev,(void *)arg,file);
110         case COMEDI_CHANINFO:
111                 return do_chaninfo_ioctl(dev,(void *)arg);
112         case COMEDI_RANGEINFO:
113                 return do_rangeinfo_ioctl(dev,(void *)arg);
114         case COMEDI_BUFINFO:
115                 return do_bufinfo_ioctl(dev,(void*)arg);
116         case COMEDI_LOCK:
117                 return do_lock_ioctl(dev,arg,file);
118         case COMEDI_UNLOCK:
119                 return do_unlock_ioctl(dev,arg,file);
120         case COMEDI_CANCEL:
121                 return do_cancel_ioctl(dev,arg,file);
122         case COMEDI_CMD:
123                 return do_cmd_ioctl(dev,(void *)arg,file);
124         case COMEDI_CMDTEST:
125                 return do_cmdtest_ioctl(dev,(void *)arg,file);
126         case COMEDI_INSNLIST:
127                 return do_insnlist_ioctl(dev,(void *)arg,file);
128         case COMEDI_INSN:
129                 return do_insn_ioctl(dev,(void *)arg,file);
130         case COMEDI_POLL:
131                 return do_poll_ioctl(dev,arg,file);
132         default:
133                 return -ENOTTY;
134         }
135 }
136
137
138 /*
139         COMEDI_DEVCONFIG
140         device config ioctl
141
142         arg:
143                 pointer to devconfig structure
144
145         reads:
146                 devconfig structure at arg
147
148         writes:
149                 none
150 */
151 static int do_devconfig_ioctl(comedi_device *dev, comedi_devconfig *arg)
152 {
153         comedi_devconfig it;
154         int ret;
155         unsigned char *aux_data = NULL;
156         int aux_len;
157
158         if(!capable(CAP_SYS_ADMIN))
159                 return -EPERM;
160
161         if(arg==NULL){
162                 return comedi_device_detach(dev);
163         }
164
165         if(copy_from_user(&it,arg,sizeof(comedi_devconfig)))
166                 return -EFAULT;
167
168         it.board_name[COMEDI_NAMELEN-1]=0;
169
170         if(comedi_aux_data(it.options, 0) &&
171                 it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]){
172                 int bit_shift;
173                 aux_len = it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
174                 if(aux_len<0)return -EFAULT;
175
176                 aux_data = vmalloc(aux_len);
177                 if(!aux_data) return -ENOMEM;
178
179                 if(copy_from_user(aux_data,
180                         comedi_aux_data(it.options, 0), aux_len)){
181                         vfree(aux_data);
182                         return -EFAULT;
183                 }
184                 it.options[COMEDI_DEVCONF_AUX_DATA_LO] = (unsigned long)aux_data;
185                 if(sizeof(void*) > sizeof(int))
186                 {
187                         bit_shift = sizeof(int) * 8;
188                         it.options[COMEDI_DEVCONF_AUX_DATA_HI] = ((unsigned long)aux_data) >> bit_shift;
189                 }else
190                         it.options[COMEDI_DEVCONF_AUX_DATA_HI] = 0;
191         }
192
193         ret = comedi_device_attach(dev,&it);
194
195         if(aux_data) vfree(aux_data);
196
197         return ret;
198 }
199
200 /*
201         COMEDI_BUFCONFIG
202         buffer configuration ioctl
203
204         arg:
205                 pointer to bufconfig structure
206
207         reads:
208                 bufconfig at arg
209
210         writes:
211                 modified bufconfig at arg
212
213 */
214 static int do_bufconfig_ioctl(comedi_device *dev,void *arg)
215 {
216         comedi_bufconfig bc;
217         comedi_async *async;
218         comedi_subdevice *s;
219         int ret = 0;
220
221         if(copy_from_user(&bc,arg,sizeof(comedi_bufconfig)))
222                 return -EFAULT;
223
224         if(bc.subdevice>=dev->n_subdevices || bc.subdevice<0)
225                 return -EINVAL;
226
227         s=dev->subdevices+bc.subdevice;
228         async=s->async;
229
230         if(!async){
231                 DPRINTK("subdevice does not have async capability\n");
232                 bc.size = 0;
233                 bc.maximum_size = 0;
234                 goto copyback;
235         }
236
237         if(bc.maximum_size){
238                 if(!capable(CAP_SYS_ADMIN))return -EPERM;
239
240                 async->max_bufsize = bc.maximum_size;
241         }
242
243         if(bc.size){
244                 if(bc.size > async->max_bufsize)
245                         return -EPERM;
246
247                 if(s->busy)
248                 {
249                         DPRINTK("subdevice is busy, cannot resize buffer\n");
250                         return -EBUSY;
251                 }
252                 if(async->mmap_count){
253                         DPRINTK("subdevice is mmapped, cannot resize buffer\n");
254                         return -EBUSY;
255                 }
256
257                 if(!async->prealloc_buf)
258                         return -EINVAL;
259
260                 /* make sure buffer is an integral number of pages
261                  * (we round up) */
262                 bc.size = (bc.size + PAGE_SIZE - 1) & PAGE_MASK;
263
264                 ret = comedi_buf_alloc(dev, s, bc.size);
265                 if(ret < 0) return ret;
266
267                 if(s->buf_change){
268                         ret = s->buf_change(dev,s,bc.size);
269                         if(ret < 0) return ret;
270                 }
271
272                 DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
273                         dev->minor, bc.subdevice, async->prealloc_bufsz);
274         }
275
276         bc.size = async->prealloc_bufsz;
277         bc.maximum_size = async->max_bufsize;
278
279 copyback:
280         if(copy_to_user(arg,&bc,sizeof(comedi_bufconfig)))
281                 return -EFAULT;
282
283         return 0;
284 }
285
286 /*
287         COMEDI_DEVINFO
288         device info ioctl
289
290         arg:
291                 pointer to devinfo structure
292
293         reads:
294                 none
295
296         writes:
297                 devinfo structure
298
299 */
300 static int do_devinfo_ioctl(comedi_device *dev,comedi_devinfo *arg)
301 {
302         comedi_devinfo devinfo;
303
304         memset(&devinfo,0,sizeof(devinfo));
305
306         /* fill devinfo structure */
307         devinfo.version_code=COMEDI_VERSION_CODE;
308         devinfo.n_subdevs=dev->n_subdevices;
309         memcpy(devinfo.driver_name,dev->driver->driver_name,COMEDI_NAMELEN);
310         memcpy(devinfo.board_name,dev->board_name,COMEDI_NAMELEN);
311
312         if(dev->read_subdev){
313                 devinfo.read_subdevice = dev->read_subdev - dev->subdevices;
314         }else{
315                 devinfo.read_subdevice = -1;
316         }
317         if(dev->write_subdev){
318                 devinfo.write_subdevice = dev->write_subdev - dev->subdevices;
319         }else{
320                 devinfo.write_subdevice = -1;
321         }
322
323         if(copy_to_user(arg,&devinfo,sizeof(comedi_devinfo)))
324                 return -EFAULT;
325
326         return 0;
327 }
328
329
330 /*
331         COMEDI_SUBDINFO
332         subdevice info ioctl
333
334         arg:
335                 pointer to array of subdevice info structures
336
337         reads:
338                 none
339
340         writes:
341                 array of subdevice info structures at arg
342
343 */
344 static int do_subdinfo_ioctl(comedi_device *dev,comedi_subdinfo *arg,void *file)
345 {
346         int ret,i;
347         comedi_subdinfo *tmp,*us;
348         comedi_subdevice *s;
349
350
351         tmp=kmalloc(dev->n_subdevices*sizeof(comedi_subdinfo),GFP_KERNEL);
352         if(!tmp)
353                 return -ENOMEM;
354
355         memset(tmp,0,sizeof(comedi_subdinfo)*dev->n_subdevices);
356
357         /* fill subdinfo structs */
358         for(i=0;i<dev->n_subdevices;i++){
359                 s=dev->subdevices+i;
360                 us=tmp+i;
361
362                 us->type                = s->type;
363                 us->n_chan              = s->n_chan;
364                 us->subd_flags          = s->subdev_flags;
365 #define TIMER_nanosec 5 /* backwards compatibility */
366                 us->timer_type          = TIMER_nanosec;
367                 us->len_chanlist        = s->len_chanlist;
368                 us->maxdata             = s->maxdata;
369                 if(s->range_table){
370                         us->range_type  = (dev->minor << 28) | (i << 24) | (0 << 16) |
371                                 (s->range_table->length);
372                 }else{
373                         us->range_type  = 0; /* XXX */
374                 }
375                 us->flags               = s->flags;
376
377                 if(s->busy)
378                         us->subd_flags |= SDF_BUSY;
379                 if(s->busy == file)
380                         us->subd_flags |= SDF_BUSY_OWNER;
381                 if(s->lock)
382                         us->subd_flags |= SDF_LOCKED;
383                 if(s->lock == file)
384                         us->subd_flags |= SDF_LOCK_OWNER;
385                 if(!s->maxdata && s->maxdata_list)
386                         us->subd_flags |= SDF_MAXDATA;
387                 if(s->flaglist)
388                         us->subd_flags |= SDF_FLAGS;
389                 if(s->range_table_list)
390                         us->subd_flags |= SDF_RANGETYPE;
391                 if(s->do_cmd)
392                         us->subd_flags |= SDF_CMD;
393
394                 us->settling_time_0 = s->settling_time_0;
395         }
396
397         ret=copy_to_user(arg,tmp,dev->n_subdevices*sizeof(comedi_subdinfo));
398
399         kfree(tmp);
400
401         return ret?-EFAULT:0;
402 }
403
404
405 /*
406         COMEDI_CHANINFO
407         subdevice info ioctl
408
409         arg:
410                 pointer to chaninfo structure
411
412         reads:
413                 chaninfo structure at arg
414
415         writes:
416                 arrays at elements of chaninfo structure
417
418 */
419 static int do_chaninfo_ioctl(comedi_device *dev,comedi_chaninfo *arg)
420 {
421         comedi_subdevice *s;
422         comedi_chaninfo it;
423
424         if(copy_from_user(&it,arg,sizeof(comedi_chaninfo)))
425                 return -EFAULT;
426
427         if(it.subdev>=dev->n_subdevices)
428                 return -EINVAL;
429         s=dev->subdevices+it.subdev;
430
431         if(it.maxdata_list){
432                 if(s->maxdata || !s->maxdata_list)
433                         return -EINVAL;
434                 if(copy_to_user(it.maxdata_list,s->maxdata_list,s->n_chan*sizeof(lsampl_t)))
435                         return -EFAULT;
436         }
437
438         if(it.flaglist){
439                 if(!s->flaglist)return -EINVAL;
440                 if(copy_to_user(it.flaglist,s->flaglist,s->n_chan*sizeof(unsigned int)))
441                         return -EFAULT;
442         }
443
444         if(it.rangelist){
445                 int i;
446
447                 if(!s->range_table_list)return -EINVAL;
448                 for(i=0;i<s->n_chan;i++){
449                         int x;
450
451                         x=(dev->minor << 28) | (it.subdev << 24) | (i << 16) |
452                                 (s->range_table_list[i]->length);
453                         put_user(x,it.rangelist+i);
454                 }
455                 //if(copy_to_user(it.rangelist,s->range_type_list,s->n_chan*sizeof(unsigned int)))
456                 //      return -EFAULT;
457         }
458
459         return 0;
460 }
461
462  /*
463         COMEDI_BUFINFO
464         buffer information ioctl
465
466         arg:
467                 pointer to bufinfo structure
468
469         reads:
470                 bufinfo at arg
471
472         writes:
473                 modified bufinfo at arg
474
475 */
476 static int do_bufinfo_ioctl(comedi_device *dev,void *arg)
477 {
478         comedi_bufinfo bi;
479         comedi_subdevice *s;
480         comedi_async *async;
481
482         if(copy_from_user(&bi,arg, sizeof(comedi_bufinfo)))
483                 return -EFAULT;
484
485         if(bi.subdevice >= dev->n_subdevices || bi.subdevice < 0)
486                 return -EINVAL;
487
488         s = dev->subdevices + bi.subdevice;
489         async = s->async;
490
491         if(!async){
492                 DPRINTK("subdevice does not have async capability\n");
493                 bi.buf_write_ptr = 0;
494                 bi.buf_read_ptr = 0;
495                 bi.buf_write_count = 0;
496                 bi.buf_read_count = 0;
497                 goto copyback;
498         }
499
500         if(bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)){
501                 bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read);
502                 comedi_buf_read_free(async, bi.bytes_read);
503
504                 if(!(s->subdev_flags&SDF_RUNNING) &&
505                    !(s->runflags & SRF_ERROR) &&
506                    async->buf_write_count==async->buf_read_count){
507                         do_become_nonbusy(dev,s);
508                 }
509         }
510
511         if(bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)){
512                 bi.bytes_written = comedi_buf_write_alloc( async, bi.bytes_written );
513                 comedi_buf_write_free(async, bi.bytes_written);
514         }
515
516         bi.buf_write_count = async->buf_write_count;
517         bi.buf_write_ptr = async->buf_write_ptr;
518         bi.buf_read_count = async->buf_read_count;
519         bi.buf_read_ptr = async->buf_read_ptr;
520
521 copyback:
522         if(copy_to_user(arg, &bi, sizeof(comedi_bufinfo)))
523                 return -EFAULT;
524
525         return 0;
526 }
527
528
529 static int parse_insn(comedi_device *dev,comedi_insn *insn,lsampl_t *data,void *file);
530 /*
531  *      COMEDI_INSNLIST
532  *      synchronous instructions
533  *
534  *      arg:
535  *              pointer to sync cmd structure
536  *
537  *      reads:
538  *              sync cmd struct at arg
539  *              instruction list
540  *              data (for writes)
541  *
542  *      writes:
543  *              data (for reads)
544  */
545 /* arbitrary limits */
546 #define MAX_SAMPLES 256
547 static int do_insnlist_ioctl(comedi_device *dev,void *arg,void *file)
548 {
549         comedi_insnlist insnlist;
550         comedi_insn     *insns = NULL;
551         lsampl_t        *data = NULL;
552         int i = 0;
553         int ret=0;
554
555         if(copy_from_user(&insnlist,arg,sizeof(comedi_insnlist)))
556                 return -EFAULT;
557
558         data=kmalloc(sizeof(lsampl_t)*MAX_SAMPLES,GFP_KERNEL);
559         if(!data){
560                 DPRINTK("kmalloc failed\n");
561                 ret = -ENOMEM;
562                 goto error;
563         }
564
565         insns=kmalloc(sizeof(comedi_insn)*insnlist.n_insns,GFP_KERNEL);
566         if(!insns){
567                 DPRINTK("kmalloc failed\n");
568                 ret = -ENOMEM;
569                 goto error;
570         }
571
572         if(copy_from_user(insns,insnlist.insns,sizeof(comedi_insn)*insnlist.n_insns)){
573                 DPRINTK("copy_from_user failed\n");
574                 ret=-EFAULT;
575                 goto error;
576         }
577
578         for(i=0;i<insnlist.n_insns;i++){
579                 if(insns[i].n>MAX_SAMPLES){
580                         DPRINTK("number of samples too large\n");
581                         ret=-EINVAL;
582                         goto error;
583                 }
584                 if(insns[i].insn&INSN_MASK_WRITE){
585                         if(copy_from_user(data,insns[i].data,
586                                         insns[i].n*sizeof(lsampl_t))){
587                                 DPRINTK("copy_from_user failed\n");
588                                 ret=-EFAULT;
589                                 goto error;
590                         }
591                 }
592                 ret = parse_insn(dev,insns+i,data,file);
593                 if(ret<0)goto error;
594                 if(insns[i].insn&INSN_MASK_READ){
595                         if(copy_to_user(insns[i].data,data,
596                                         insns[i].n*sizeof(lsampl_t))){
597                                 DPRINTK("copy_to_user failed\n");
598                                 ret=-EFAULT;
599                                 goto error;
600                         }
601                 }
602                 if(need_resched())
603                         schedule();
604         }
605
606 error:
607         if(insns)kfree(insns);
608         if(data)kfree(data);
609
610         if(ret<0)return ret;
611         return i;
612 }
613
614 static int check_insn_config_length(comedi_insn *insn, lsampl_t *data)
615 {
616         switch(data[0])
617         {
618         case INSN_CONFIG_DIO_OUTPUT:
619         case INSN_CONFIG_DIO_INPUT:
620         case INSN_CONFIG_DISARM:
621         case INSN_CONFIG_RESET:
622                 if(insn->n == 1) return 0;
623                 break;
624         case INSN_CONFIG_ARM:
625         case INSN_CONFIG_DIO_QUERY:
626         case INSN_CONFIG_BLOCK_SIZE:
627         case INSN_CONFIG_FILTER:
628         case INSN_CONFIG_SERIAL_CLOCK:
629         case INSN_CONFIG_BIDIRECTIONAL_DATA:
630         case INSN_CONFIG_ALT_SOURCE:
631         case INSN_CONFIG_SET_COUNTER_MODE:
632         case INSN_CONFIG_8254_READ_STATUS:
633         case INSN_CONFIG_SET_ROUTING:
634         case INSN_CONFIG_GET_ROUTING:
635                 if(insn->n == 2) return 0;
636                 break;
637         case INSN_CONFIG_SET_GATE_SRC:
638         case INSN_CONFIG_GET_GATE_SRC:
639         case INSN_CONFIG_SET_CLOCK_SRC:
640         case INSN_CONFIG_GET_CLOCK_SRC:
641         case INSN_CONFIG_GET_COUNTER_STATUS:
642                 if(insn->n == 3) return 0;
643                 break;
644         case INSN_CONFIG_PWM_OUTPUT:
645         case INSN_CONFIG_ANALOG_TRIG:
646                 if(insn->n == 5) return 0;
647                 break;
648         //by default we allow the insn since we don't have checks for all possible cases yet
649         default:
650                 rt_printk("comedi: no check for data length of config insn id %i is implemented.\n"
651                         " Add a check to %s in %s.\n"
652                         " Assuming n=%i is correct.\n",
653                         data[0], __FUNCTION__, __FILE__, insn->n);
654                 return 0;
655                 break;
656         }
657         return -EINVAL;
658 }
659
660 static int parse_insn(comedi_device *dev,comedi_insn *insn,lsampl_t *data,void *file)
661 {
662         comedi_subdevice *s;
663         int ret = 0;
664
665         if(insn->insn&INSN_MASK_SPECIAL){
666                 /* a non-subdevice instruction */
667
668                 switch(insn->insn){
669                 case INSN_GTOD:
670                 {
671                         struct timeval tv;
672
673                         if(insn->n!=2){
674                                 ret=-EINVAL;
675                                 break;
676                         }
677
678                         do_gettimeofday(&tv);
679                         data[0]=tv.tv_sec;
680                         data[1]=tv.tv_usec;
681                         ret=2;
682
683                         break;
684                 }
685                 case INSN_WAIT:
686                         if(insn->n!=1 || data[0]>=100000){
687                                 ret=-EINVAL;
688                                 break;
689                         }
690                         udelay(data[0]/1000);
691                         ret=1;
692                         break;
693                 case INSN_INTTRIG:
694                         if(insn->n!=1){
695                                 ret=-EINVAL;
696                                 break;
697                         }
698                         if(insn->subdev>=dev->n_subdevices){
699                                 DPRINTK("%d not usable subdevice\n",insn->subdev);
700                                 ret=-EINVAL;
701                                 break;
702                         }
703                         s=dev->subdevices+insn->subdev;
704                         if(!s->async){
705                                 DPRINTK("no async\n");
706                                 ret=-EINVAL;
707                                 break;
708                         }
709                         if(!s->async->inttrig){
710                                 DPRINTK("no inttrig\n");
711                                 ret=-EAGAIN;
712                                 break;
713                         }
714                         ret = s->async->inttrig(dev,s,insn->data[0]);
715                         if(ret>=0)ret = 1;
716                         break;
717                 default:
718                         DPRINTK("invalid insn\n");
719                         ret=-EINVAL;
720                         break;
721                 }
722         }else{
723                 /* a subdevice instruction */
724                 if(insn->subdev>=dev->n_subdevices){
725                         DPRINTK("subdevice %d out of range\n",insn->subdev);
726                         ret=-EINVAL;
727                         goto out;
728                 }
729                 s=dev->subdevices+insn->subdev;
730
731                 if(s->type==COMEDI_SUBD_UNUSED){
732                         DPRINTK("%d not usable subdevice\n",insn->subdev);
733                         ret = -EIO;
734                         goto out;
735                 }
736
737                 /* are we locked? (ioctl lock) */
738                 if(s->lock && s->lock!=file){
739                         DPRINTK("device locked\n");
740                         ret = -EACCES;
741                         goto out;
742                 }
743
744                 if((ret=check_chanlist(s,1,&insn->chanspec))<0){
745                         ret=-EINVAL;
746                         DPRINTK("bad chanspec\n");
747                         goto out;
748                 }
749
750                 if(s->busy){
751                         ret=-EBUSY;
752                         goto out;
753                 }
754                 /* This looks arbitrary.  It is. */
755                 s->busy=&parse_insn;
756                 switch(insn->insn){
757                         case INSN_READ:
758                                 ret=s->insn_read(dev,s,insn,data);
759                                 break;
760                         case INSN_WRITE:
761                                 //XXX check against subdevice's maxdata
762                                 ret=s->insn_write(dev,s,insn,data);
763                                 break;
764                         case INSN_BITS:
765                                 if(insn->n != 2)
766                                 {
767                                         ret=-EINVAL;
768                                         break;
769                                 }
770                                 ret=s->insn_bits(dev,s,insn,data);
771                                 break;
772                         case INSN_CONFIG:
773                                 ret=check_insn_config_length(insn, data);
774                                 if(ret) break;
775                                 ret=s->insn_config(dev,s,insn,data);
776                                 break;
777                         default:
778                                 ret=-EINVAL;
779                                 break;
780                 }
781
782                 s->busy=NULL;
783         }
784
785 out:
786         return ret;
787 }
788
789 /*
790  *      COMEDI_INSN
791  *      synchronous instructions
792  *
793  *      arg:
794  *              pointer to insn
795  *
796  *      reads:
797  *              comedi_insn struct at arg
798  *              data (for writes)
799  *
800  *      writes:
801  *              data (for reads)
802  */
803 static int do_insn_ioctl(comedi_device *dev,void *arg,void *file)
804 {
805         comedi_insn     insn;
806         lsampl_t        *data = NULL;
807         int ret=0;
808
809         data=kmalloc(sizeof(lsampl_t)*MAX_SAMPLES,GFP_KERNEL);
810         if(!data){
811                 ret = -ENOMEM;
812                 goto error;
813         }
814
815         if(copy_from_user(&insn,arg,sizeof(comedi_insn))){
816                 ret=-EFAULT;
817                 goto error;
818         }
819
820         /* This is where the behavior of insn and insnlist deviate. */
821         if(insn.n>MAX_SAMPLES)insn.n=MAX_SAMPLES;
822         if(insn.insn&INSN_MASK_WRITE){
823                 if(copy_from_user(data,insn.data,insn.n*sizeof(lsampl_t))){
824                         ret=-EFAULT;
825                         goto error;
826                 }
827         }
828         ret = parse_insn(dev,&insn,data,file);
829         if(ret<0)goto error;
830         if(insn.insn&INSN_MASK_READ){
831                 if(copy_to_user(insn.data,data,insn.n*sizeof(lsampl_t))){
832                         ret=-EFAULT;
833                         goto error;
834                 }
835         }
836         ret = insn.n;
837
838 error:
839         if(data)kfree(data);
840
841         return ret;
842 }
843
844 /*
845         COMEDI_CMD
846         command ioctl
847
848         arg:
849                 pointer to cmd structure
850
851         reads:
852                 cmd structure at arg
853                 channel/range list
854
855         writes:
856                 modified cmd structure at arg
857
858 */
859 static int do_cmd_ioctl(comedi_device *dev,void *arg,void *file)
860 {
861         comedi_cmd user_cmd;
862         comedi_subdevice *s;
863         comedi_async *async;
864         int ret=0;
865         unsigned int *chanlist_saver=NULL;
866
867         if(copy_from_user(&user_cmd,arg,sizeof(comedi_cmd))){
868                 DPRINTK("bad cmd address\n");
869                 return -EFAULT;
870         }
871
872         // save user's chanlist pointer so it can be restored later
873         chanlist_saver = user_cmd.chanlist;
874
875         if(user_cmd.subdev>=dev->n_subdevices){
876                 DPRINTK("%d no such subdevice\n",user_cmd.subdev);
877                 return -ENODEV;
878         }
879
880         s=dev->subdevices+user_cmd.subdev;
881         async = s->async;
882
883         if(s->type==COMEDI_SUBD_UNUSED){
884                 DPRINTK("%d not valid subdevice\n",user_cmd.subdev);
885                 return -EIO;
886         }
887
888         if(!s->do_cmd || !s->async){
889                 DPRINTK("subdevice %i does not support commands\n", user_cmd.subdev);
890                 return -EIO;
891         }
892
893         /* are we locked? (ioctl lock) */
894         if(s->lock && s->lock!=file){
895                 DPRINTK("subdevice locked\n");
896                 return -EACCES;
897         }
898
899         /* are we busy? */
900         if(s->busy){
901                 DPRINTK("subdevice busy\n");
902                 return -EBUSY;
903         }
904         s->busy=file;
905
906         /* make sure channel/gain list isn't too long */
907         if(user_cmd.chanlist_len > s->len_chanlist){
908                 DPRINTK("channel/gain list too long %d > %d\n",user_cmd.chanlist_len,s->len_chanlist);
909                 ret = -EINVAL;
910                 goto cleanup;
911         }
912
913         if(async->cmd.chanlist) kfree(async->cmd.chanlist);
914         async->cmd=user_cmd;
915         async->cmd.data=NULL;
916         /* load channel/gain list */
917         async->cmd.chanlist=kmalloc(async->cmd.chanlist_len*sizeof(int),GFP_KERNEL);
918         if(!async->cmd.chanlist){
919                 DPRINTK("allocation failed\n");
920                 ret = -ENOMEM;
921                 goto cleanup;
922         }
923
924         if(copy_from_user(async->cmd.chanlist,user_cmd.chanlist,async->cmd.chanlist_len*sizeof(int))){
925                 DPRINTK("fault reading chanlist\n");
926                 ret = -EFAULT;
927                 goto cleanup;
928         }
929
930         /* make sure each element in channel/gain list is valid */
931         if((ret=check_chanlist(s,async->cmd.chanlist_len,async->cmd.chanlist))<0){
932                 DPRINTK("bad chanlist\n");
933                 goto cleanup;
934         }
935
936         ret=s->do_cmdtest(dev,s,&async->cmd);
937
938         if(async->cmd.flags&TRIG_BOGUS || ret){
939                 DPRINTK("test returned %d\n",ret);
940                 user_cmd=async->cmd;
941                 // restore chanlist pointer before copying back
942                 user_cmd.chanlist = chanlist_saver;
943                 user_cmd.data = NULL;
944                 if(copy_to_user(arg,&user_cmd,sizeof(comedi_cmd))){
945                         DPRINTK("fault writing cmd\n");
946                         ret = -EFAULT;
947                         goto cleanup;
948                 }
949                 ret = -EAGAIN;
950                 goto cleanup;
951         }
952
953         if(!async->prealloc_bufsz){
954                 ret=-ENOMEM;
955                 DPRINTK("no buffer (?)\n");
956                 goto cleanup;
957         }
958
959         comedi_reset_async_buf( async );
960
961         async->cb_mask = COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW;
962         if(async->cmd.flags & TRIG_WAKE_EOS){
963                 async->cb_mask |= COMEDI_CB_EOS;
964         }
965
966         s->runflags=SRF_USER;
967
968         s->subdev_flags|=SDF_RUNNING;
969
970 #ifdef CONFIG_COMEDI_RT
971         if(async->cmd.flags&TRIG_RT){
972                 comedi_switch_to_rt(dev);
973                 s->runflags |= SRF_RT;
974         }
975 #endif
976
977         ret=s->do_cmd(dev,s);
978
979         if(ret==0)return 0;
980
981 cleanup:
982         do_become_nonbusy(dev,s);
983
984         return ret;
985 }
986
987 /*
988         COMEDI_CMDTEST
989         command testing ioctl
990
991         arg:
992                 pointer to cmd structure
993
994         reads:
995                 cmd structure at arg
996                 channel/range list
997
998         writes:
999                 modified cmd structure at arg
1000
1001 */
1002 static int do_cmdtest_ioctl(comedi_device *dev,void *arg,void *file)
1003 {
1004         comedi_cmd user_cmd;
1005         comedi_subdevice *s;
1006         int ret=0;
1007         unsigned int *chanlist=NULL;
1008         unsigned int *chanlist_saver=NULL;
1009
1010         if(copy_from_user(&user_cmd,arg,sizeof(comedi_cmd))){
1011                 DPRINTK("bad cmd address\n");
1012                 return -EFAULT;
1013         }
1014
1015         // save user's chanlist pointer so it can be restored later
1016         chanlist_saver = user_cmd.chanlist;
1017
1018         if(user_cmd.subdev>=dev->n_subdevices){
1019                 DPRINTK("%d no such subdevice\n",user_cmd.subdev);
1020                 return -ENODEV;
1021         }
1022
1023         s=dev->subdevices+user_cmd.subdev;
1024         if(s->type==COMEDI_SUBD_UNUSED){
1025                 DPRINTK("%d not valid subdevice\n",user_cmd.subdev);
1026                 return -EIO;
1027         }
1028
1029         if(!s->do_cmd){
1030                 DPRINTK("subdevice %i does not support commands\n", user_cmd.subdev);
1031                 return -EIO;
1032         }
1033
1034         /* make sure channel/gain list isn't too long */
1035         if(user_cmd.chanlist_len > s->len_chanlist){
1036                 DPRINTK("channel/gain list too long %d > %d\n",user_cmd.chanlist_len,s->len_chanlist);
1037                 ret = -EINVAL;
1038                 goto cleanup;
1039         }
1040
1041         /* load channel/gain list */
1042         if(user_cmd.chanlist){
1043                 chanlist=kmalloc(user_cmd.chanlist_len*sizeof(int),GFP_KERNEL);
1044                 if(!chanlist){
1045                         DPRINTK("allocation failed\n");
1046                         ret = -ENOMEM;
1047                         goto cleanup;
1048                 }
1049
1050                 if(copy_from_user(chanlist,user_cmd.chanlist,user_cmd.chanlist_len*sizeof(int))){
1051                         DPRINTK("fault reading chanlist\n");
1052                         ret = -EFAULT;
1053                         goto cleanup;
1054                 }
1055
1056                 /* make sure each element in channel/gain list is valid */
1057                 if((ret=check_chanlist(s,user_cmd.chanlist_len,chanlist))<0){
1058                         DPRINTK("bad chanlist\n");
1059                         goto cleanup;
1060                 }
1061
1062                 user_cmd.chanlist=chanlist;
1063         }
1064
1065         ret=s->do_cmdtest(dev,s,&user_cmd);
1066
1067         // restore chanlist pointer before copying back
1068         user_cmd.chanlist = chanlist_saver;
1069
1070         if(copy_to_user(arg,&user_cmd,sizeof(comedi_cmd))){
1071                 DPRINTK("bad cmd address\n");
1072                 ret=-EFAULT;
1073                 goto cleanup;
1074         }
1075 cleanup:
1076         if(chanlist)
1077                 kfree(chanlist);
1078
1079         return ret;
1080 }
1081
1082 /*
1083         COMEDI_LOCK
1084         lock subdevice
1085
1086         arg:
1087                 subdevice number
1088
1089         reads:
1090                 none
1091
1092         writes:
1093                 none
1094
1095 */
1096
1097 static int do_lock_ioctl(comedi_device *dev,unsigned int arg,void * file)
1098 {
1099         int ret=0;
1100         unsigned long flags;
1101         comedi_subdevice *s;
1102
1103         if(arg>=dev->n_subdevices)
1104                 return -EINVAL;
1105         s=dev->subdevices+arg;
1106
1107         comedi_spin_lock_irqsave(&big_comedi_lock, flags);
1108         if(s->busy)
1109         {
1110                 comedi_spin_unlock_irqrestore(&big_comedi_lock, flags);
1111                 return -EBUSY;
1112         }
1113         if(s->lock){
1114                 ret=-EBUSY;
1115         }else{
1116                 s->lock=file;
1117         }
1118         comedi_spin_unlock_irqrestore(&big_comedi_lock, flags);
1119
1120         if(ret<0)
1121                 return ret;
1122
1123 #if 0
1124         if(s->lock_f)
1125                 ret=s->lock_f(dev,s);
1126 #endif
1127
1128         return ret;
1129 }
1130
1131
1132 /*
1133         COMEDI_UNLOCK
1134         unlock subdevice
1135
1136         arg:
1137                 subdevice number
1138
1139         reads:
1140                 none
1141
1142         writes:
1143                 none
1144
1145         This function isn't protected by the semaphore, since
1146         we already own the lock.
1147 */
1148 static int do_unlock_ioctl(comedi_device *dev,unsigned int arg,void * file)
1149 {
1150         comedi_subdevice *s;
1151
1152         if(arg>=dev->n_subdevices)
1153                 return -EINVAL;
1154         s=dev->subdevices+arg;
1155
1156         if(s->busy)
1157                 return -EBUSY;
1158
1159         if(s->lock && s->lock!=file)
1160                 return -EACCES;
1161
1162         if(s->lock==file){
1163 #if 0
1164                 if(s->unlock)
1165                         s->unlock(dev,s);
1166 #endif
1167
1168                 s->lock=NULL;
1169         }
1170
1171         return 0;
1172 }
1173
1174 /*
1175         COMEDI_CANCEL
1176         cancel acquisition ioctl
1177
1178         arg:
1179                 subdevice number
1180
1181         reads:
1182                 nothing
1183
1184         writes:
1185                 nothing
1186
1187 */
1188 static int do_cancel_ioctl(comedi_device *dev,unsigned int arg,void *file)
1189 {
1190         comedi_subdevice *s;
1191
1192         if(arg>=dev->n_subdevices)
1193                 return -EINVAL;
1194         s=dev->subdevices+arg;
1195
1196         if(s->lock && s->lock!=file)
1197                 return -EACCES;
1198
1199         if(!s->busy)
1200                 return 0;
1201
1202         if(s->busy!=file)
1203                 return -EBUSY;
1204
1205         return do_cancel(dev,s);
1206 }
1207
1208 /*
1209         COMEDI_POLL ioctl
1210         instructs driver to synchronize buffers
1211
1212         arg:
1213                 subdevice number
1214
1215         reads:
1216                 nothing
1217
1218         writes:
1219                 nothing
1220
1221 */
1222 static int do_poll_ioctl(comedi_device *dev,unsigned int arg,void *file)
1223 {
1224         comedi_subdevice *s;
1225
1226         if(arg>=dev->n_subdevices)
1227                 return -EINVAL;
1228         s=dev->subdevices+arg;
1229
1230         if(s->lock && s->lock!=file)
1231                 return -EACCES;
1232
1233         if(!s->busy)
1234                 return 0;
1235
1236         if(s->busy!=file)
1237                 return -EBUSY;
1238
1239         if(s->poll)return s->poll(dev,s);
1240
1241         return -EINVAL;
1242 }
1243
1244 static int do_cancel(comedi_device *dev,comedi_subdevice *s)
1245 {
1246         int ret=0;
1247
1248         if((s->subdev_flags&SDF_RUNNING) && s->cancel)
1249                 ret=s->cancel(dev,s);
1250
1251         do_become_nonbusy(dev,s);
1252
1253         return ret;
1254 }
1255
1256
1257 void comedi_unmap(struct vm_area_struct *area)
1258 {
1259         comedi_async *async;
1260
1261         async = area->vm_private_data;
1262
1263         async->mmap_count--;
1264 }
1265
1266 static struct vm_operations_struct comedi_vm_ops={
1267         close:          comedi_unmap,
1268 };
1269
1270 static int comedi_mmap(struct file * file, struct vm_area_struct *vma)
1271 {
1272         const unsigned minor = iminor(file->f_dentry->d_inode);
1273         comedi_device *dev = comedi_get_device_by_minor(minor);
1274         comedi_async *async = NULL;
1275         unsigned long start = vma->vm_start;
1276         unsigned long size;
1277         int n_pages;
1278         int i;
1279         comedi_subdevice *s;
1280
1281         if(!dev->attached)
1282         {
1283                 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1284                 return -ENODEV;
1285         }
1286         s = comedi_get_subdevice_by_minor(minor);
1287         if(s == NULL)
1288         {       if(vma->vm_flags & VM_WRITE){
1289                         s = dev->write_subdev;
1290                 }else{
1291                         s = dev->read_subdev;
1292                 }
1293                 if(s == NULL) return -EINVAL;
1294         }
1295         async = s->async;
1296         if(async==NULL){
1297                 return -EINVAL;
1298         }
1299
1300         if(vma->vm_pgoff != 0){
1301                 DPRINTK("comedi: mmap() offset must be 0.\n");
1302                 return -EINVAL;
1303         }
1304
1305         size = vma->vm_end - vma->vm_start;
1306         if(size>async->prealloc_bufsz)
1307                 return -EFAULT;
1308         if(size&(~PAGE_MASK))
1309                 return -EFAULT;
1310
1311         n_pages = size >> PAGE_SHIFT;
1312         for(i = 0; i < n_pages; ++i){
1313                 if(remap_pfn_range(vma, start, page_to_pfn(virt_to_page(async->prealloc_buf + PAGE_SIZE * i)),
1314                                 PAGE_SIZE, PAGE_SHARED)){
1315                         return -EAGAIN;
1316                 }
1317                 start += PAGE_SIZE;
1318         }
1319
1320         vma->vm_ops = &comedi_vm_ops;
1321         vma->vm_private_data = async;
1322
1323         async->mmap_count++;
1324
1325         return 0;
1326 }
1327
1328
1329 static unsigned int comedi_poll(struct file *file, poll_table * wait)
1330 {
1331         comedi_subdevice *s;
1332         comedi_async *async;
1333         unsigned int mask;
1334         const unsigned minor = iminor(file->f_dentry->d_inode);
1335         comedi_device *dev = comedi_get_device_by_minor(minor);
1336
1337         if(!dev->attached)
1338         {
1339                 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1340                 return -ENODEV;
1341         }
1342
1343         poll_wait(file, &dev->read_wait, wait);
1344         poll_wait(file, &dev->write_wait, wait);
1345         mask = 0;
1346         if(dev->read_subdev && dev->read_subdev->async){
1347                 s = dev->read_subdev;
1348                 async = s->async;
1349                 if(!s->busy
1350                    || comedi_buf_read_n_available(async)>0
1351                    || !(s->subdev_flags&SDF_RUNNING)){
1352                         mask |= POLLIN | POLLRDNORM;
1353                 }
1354         }
1355         if(dev->write_subdev && dev->write_subdev->async){
1356                 s = dev->write_subdev;
1357                 async = s->async;
1358                 if(!s->busy
1359                    || !(s->subdev_flags&SDF_RUNNING)
1360                    || comedi_buf_write_n_available(async) > 0){
1361                         mask |= POLLOUT | POLLWRNORM;
1362                 }
1363         }
1364
1365         return mask;
1366 }
1367
1368 static ssize_t comedi_write(struct file *file,const char *buf,size_t nbytes,loff_t *offset)
1369 {
1370         comedi_device *dev;
1371         comedi_subdevice *s;
1372         comedi_async *async;
1373         int n,m,count=0,retval=0;
1374         DECLARE_WAITQUEUE(wait,current);
1375         const unsigned minor = iminor(file->f_dentry->d_inode);
1376         dev = comedi_get_device_by_minor(minor);
1377
1378         if(!dev->attached)
1379         {
1380                 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1381                 return -ENODEV;
1382         }
1383
1384         s = comedi_get_subdevice_by_minor(minor);
1385         if(s == NULL)
1386                 s = dev->write_subdev;
1387         if(s == NULL || s->async == NULL || (s->subdev_flags & SDF_CMD_WRITE) == 0) return -EIO;
1388         async = s->async;
1389
1390         if(!nbytes)return 0;
1391
1392         if(!s->busy)
1393                 return 0;
1394
1395         if(s->busy != file)
1396                 return -EACCES;
1397
1398         add_wait_queue(&dev->write_wait,&wait);
1399         while(nbytes>0 && !retval){
1400                 current->state=TASK_INTERRUPTIBLE;
1401
1402                 n=nbytes;
1403
1404                 m = n;
1405                 if(async->buf_write_ptr + m > async->prealloc_bufsz){
1406                         m = async->prealloc_bufsz - async->buf_write_ptr;
1407                 }
1408                 m = comedi_buf_write_alloc(async, m);
1409
1410                 if(m < n) n = m;
1411
1412                 if(n==0){
1413                         if(file->f_flags&O_NONBLOCK){
1414                                 retval=-EAGAIN;
1415                                 break;
1416                         }
1417                         if(signal_pending(current)){
1418                                 retval=-ERESTARTSYS;
1419                                 break;
1420                         }
1421                         if(!(s->subdev_flags&SDF_RUNNING)){
1422                                 if(s->runflags & SRF_ERROR){
1423                                         retval = -EPIPE;
1424                                 }else{
1425                                         retval = 0;
1426                                 }
1427                                 do_become_nonbusy(dev,s);
1428                                 break;
1429                         }
1430                         schedule();
1431                         continue;
1432                 }
1433
1434                 m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
1435                         buf, n);
1436                 if(m){
1437                         n -= m;
1438                         retval = -EFAULT;
1439                 }
1440                 comedi_buf_write_free(async, n);
1441
1442                 count+=n;
1443                 nbytes-=n;
1444
1445                 buf+=n;
1446                 break;  /* makes device work like a pipe */
1447         }
1448         current->state=TASK_RUNNING;
1449         remove_wait_queue(&dev->write_wait,&wait);
1450
1451         return (count ? count : retval);
1452 }
1453
1454
1455 static ssize_t comedi_read(struct file * file,char *buf,size_t nbytes,loff_t *offset)
1456 {
1457         comedi_subdevice *s;
1458         comedi_async *async;
1459         int n,m,count=0,retval=0;
1460         DECLARE_WAITQUEUE(wait,current);
1461         const unsigned minor = iminor(file->f_dentry->d_inode);
1462         comedi_device *dev = comedi_get_device_by_minor(minor);
1463
1464         if(!dev->attached)
1465         {
1466                 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1467                 return -ENODEV;
1468         }
1469
1470         s = comedi_get_subdevice_by_minor(minor);
1471         if(s == NULL)
1472                 s = dev->read_subdev;
1473         if(s == NULL || s->async == NULL || (s->subdev_flags & SDF_CMD_READ) == 0) return -EIO;
1474         async = s->async;
1475
1476         if(!nbytes)return 0;
1477
1478         if(!s->busy)
1479                 return 0;
1480
1481         if(s->busy != file)
1482                 return -EACCES;
1483
1484         add_wait_queue(&dev->read_wait,&wait);
1485         while(nbytes>0 && !retval){
1486                 current->state=TASK_INTERRUPTIBLE;
1487
1488                 n=nbytes;
1489
1490                 m = comedi_buf_read_n_available(async);
1491 //printk("%d available\n",m);
1492                 if(async->buf_read_ptr + m > async->prealloc_bufsz){
1493                         m = async->prealloc_bufsz - async->buf_read_ptr;
1494                 }
1495 //printk("%d contiguous\n",m);
1496                 if(m<n)n=m;
1497
1498                 if(n==0){
1499                         if(!(s->subdev_flags&SDF_RUNNING)){
1500                                 do_become_nonbusy(dev,s);
1501                                 if(s->runflags & SRF_ERROR){
1502                                         retval = -EPIPE;
1503                                 }else{
1504                                         retval = 0;
1505                                 }
1506                                 break;
1507                         }
1508                         if(file->f_flags&O_NONBLOCK){
1509                                 retval=-EAGAIN;
1510                                 break;
1511                         }
1512                         if(signal_pending(current)){
1513                                 retval=-ERESTARTSYS;
1514                                 break;
1515                         }
1516                         schedule();
1517                         continue;
1518                 }
1519                 m = copy_to_user(buf, async->prealloc_buf +
1520                         async->buf_read_ptr, n);
1521                 if(m){
1522                         n -= m;
1523                         retval = -EFAULT;
1524                 }
1525
1526                 comedi_buf_read_alloc(async, n);
1527                 comedi_buf_read_free(async, n);
1528
1529                 count+=n;
1530                 nbytes-=n;
1531
1532                 buf+=n;
1533                 break;  /* makes device work like a pipe */
1534         }
1535         if(!(s->subdev_flags&SDF_RUNNING) &&
1536                 !(s->runflags & SRF_ERROR) &&
1537                 async->buf_read_count - async->buf_write_count == 0)
1538         {
1539                 do_become_nonbusy(dev,s);
1540         }
1541         current->state=TASK_RUNNING;
1542         remove_wait_queue(&dev->read_wait,&wait);
1543
1544         return (count ? count : retval);
1545 }
1546
1547 /*
1548    This function restores a subdevice to an idle state.
1549  */
1550 void do_become_nonbusy(comedi_device *dev,comedi_subdevice *s)
1551 {
1552         comedi_async *async = s->async;
1553
1554         s->subdev_flags &= ~SDF_RUNNING;
1555 #ifdef CONFIG_COMEDI_RT
1556         if(s->runflags&SRF_RT){
1557                 comedi_switch_to_non_rt(dev);
1558                 s->runflags &= ~SRF_RT;
1559         }
1560 #endif
1561         if(s->busy)
1562         {
1563                 if(s->cmd_cleanup)
1564                 {
1565                         (*s->cmd_cleanup)(dev, s);
1566                 }
1567         }
1568         if(async){
1569                 comedi_reset_async_buf( async );
1570         }else{
1571                 printk("BUG: (?) do_become_nonbusy called with async=0\n");
1572         }
1573
1574         s->busy=NULL;
1575 }
1576
1577 /* no chance that these will change soon */
1578 #define SEEK_SET 0
1579 #define SEEK_CUR 1
1580 #define SEEK_END 2
1581
1582 static loff_t comedi_lseek(struct file *file,loff_t offset,int origin)
1583 {
1584         loff_t new_offset;
1585         const unsigned minor = iminor(file->f_dentry->d_inode);
1586         comedi_device *dev = comedi_get_device_by_minor(minor);
1587
1588         switch(origin){
1589         case SEEK_SET:
1590                 new_offset = offset;
1591                 break;
1592         case SEEK_CUR:
1593                 new_offset = file->f_pos + offset;
1594                 break;
1595         case SEEK_END:
1596                 new_offset = dev->n_subdevices + offset;
1597                 break;
1598         default:
1599                 return -EINVAL;
1600         }
1601         if(new_offset<0 || new_offset >= dev->n_subdevices)
1602                 return -EINVAL;
1603
1604         return file->f_pos=new_offset;
1605 }
1606
1607 static int comedi_open(struct inode *inode, struct file *file)
1608 {
1609         char mod[32];
1610         const unsigned minor = iminor(inode);
1611         comedi_device *dev = comedi_get_device_by_minor(minor);
1612         if(dev == NULL)
1613         {
1614                 DPRINTK("invalid minor number\n");
1615                 return -ENODEV;
1616         }
1617
1618         /* This is slightly hacky, but we want module autoloading
1619          * to work for root.
1620          * case: user opens device, attached -> ok
1621          * case: user opens device, unattached, in_request_module=0 -> autoload
1622          * case: user opens device, unattached, in_request_module=1 -> fail
1623          * case: root opens device, attached -> ok
1624          * case: root opens device, unattached, in_request_module=1 -> ok
1625          *   (typically called from modprobe)
1626          * case: root opens device, unattached, in_request_module=0 -> autoload
1627          *
1628          * The last could be changed to "-> ok", which would deny root
1629          * autoloading.
1630          */
1631         if(dev->attached)
1632                 goto ok;
1633         if(!capable(CAP_SYS_MODULE) && dev->in_request_module){
1634                 DPRINTK("in request module\n");
1635                 return -ENODEV;
1636         }
1637         if(capable(CAP_SYS_MODULE) && dev->in_request_module)
1638                 goto ok;
1639
1640         dev->in_request_module=1;
1641
1642         sprintf(mod,"char-major-%i-%i", COMEDI_MAJOR, dev->minor);
1643 #ifdef CONFIG_KMOD
1644         request_module(mod);
1645 #endif
1646
1647         dev->in_request_module=0;
1648
1649         if(!dev->attached && !capable(CAP_SYS_MODULE)){
1650                 DPRINTK("not attached and not CAP_SYS_MODULE\n");
1651                 return -ENODEV;
1652         }
1653 ok:
1654         if(!try_module_get(THIS_MODULE))
1655                 return -ENOSYS;
1656
1657         if(dev->attached){
1658                 try_module_get( dev->driver->module );
1659         }
1660
1661         if(dev->attached && dev->use_count==0 && dev->open){
1662                 dev->open(dev);
1663         }
1664
1665         dev->use_count++;
1666
1667         return 0;
1668 }
1669
1670 static int comedi_close(struct inode *inode,struct file *file)
1671 {
1672         const unsigned minor = iminor(inode);
1673         comedi_device *dev = comedi_get_device_by_minor(minor);
1674         comedi_subdevice *s = NULL;
1675         int i;
1676
1677         if(dev->subdevices)
1678         {
1679                 for(i=0;i<dev->n_subdevices;i++){
1680                         s=dev->subdevices+i;
1681
1682                         if(s->busy==file){
1683                                 do_cancel(dev,s);
1684                         }
1685                         if(s->lock==file){
1686                                 s->lock=NULL;
1687                         }
1688                 }
1689         }
1690         if(dev->attached && dev->use_count==1 && dev->close){
1691                 dev->close(dev);
1692         }
1693
1694         module_put(THIS_MODULE);
1695         if(dev->attached){
1696                 module_put(dev->driver->module);
1697         }
1698
1699         dev->use_count--;
1700
1701         if(file->f_flags & FASYNC){
1702                 comedi_fasync(-1,file,0);
1703         }
1704
1705         return 0;
1706 }
1707
1708 static int comedi_fasync (int fd, struct file *file, int on)
1709 {
1710         const unsigned minor = iminor(file->f_dentry->d_inode);
1711         comedi_device *dev = comedi_get_device_by_minor(minor);
1712
1713         return fasync_helper(fd,file,on,&dev->async_queue);
1714 }
1715
1716
1717 struct file_operations comedi_fops={
1718         owner           : THIS_MODULE,
1719         llseek          : comedi_lseek,
1720         ioctl           : comedi_ioctl,
1721         open            : comedi_open,
1722         release         : comedi_close,
1723         read            : comedi_read,
1724         write           : comedi_write,
1725         mmap            : comedi_mmap,
1726         poll            : comedi_poll,
1727         fasync          : comedi_fasync,
1728 };
1729
1730 struct class *comedi_class = NULL;
1731 static struct cdev comedi_cdev;
1732
1733 static int __init comedi_init(void)
1734 {
1735         int i;
1736         int retval;
1737
1738         printk("comedi: version " COMEDI_RELEASE " - David Schleef <ds@schleef.org>\n");
1739         spin_lock_init(&big_comedi_lock);
1740         retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS, "comedi");
1741         if(retval) return -EIO;
1742         cdev_init(&comedi_cdev, &comedi_fops);
1743         comedi_cdev.owner = THIS_MODULE;
1744         kobject_set_name(&comedi_cdev.kobj, "comedi");
1745         if(cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS))
1746         {
1747                 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
1748                 return -EIO;
1749         }
1750         comedi_class = class_create(THIS_MODULE, "comedi");
1751         if(IS_ERR(comedi_class))
1752         {
1753                 printk("comedi: failed to create class");
1754                 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
1755                 cdev_del(&comedi_cdev);
1756                 return PTR_ERR(comedi_class);
1757         }
1758         comedi_devices=(comedi_device *)kmalloc(sizeof(comedi_device)*COMEDI_NDEVICES,GFP_KERNEL);
1759         if(!comedi_devices)
1760         {
1761                 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
1762                 cdev_del(&comedi_cdev);
1763                 class_destroy(comedi_class);
1764                 return -ENOMEM;
1765         }
1766         memset(comedi_devices,0,sizeof(comedi_device)*COMEDI_NDEVICES);
1767
1768         /* XXX requires /proc interface */
1769         comedi_proc_init();
1770
1771         for(i=0;i<COMEDI_NDEVICES;i++){
1772                 char name[20];
1773                 sprintf(name, "comedi%d", i);
1774                 comedi_devices[i].minor = i;
1775                 comedi_devices[i].class_dev = COMEDI_CLASS_DEVICE_CREATE(comedi_class, 0,
1776                         MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i);
1777                 spin_lock_init(&comedi_devices[i].spinlock);
1778         }
1779
1780         comedi_rt_init();
1781
1782         return 0;
1783 }
1784
1785 static void __exit comedi_cleanup(void)
1786 {
1787         int i;
1788
1789         if(MOD_IN_USE)
1790                 printk("comedi: module in use -- remove delayed\n");
1791
1792         for(i = 0; i < COMEDI_NDEVICES; i++){
1793                 comedi_device *dev;
1794
1795                 dev = comedi_devices + i;
1796                 if(dev->attached)
1797                         comedi_device_detach(dev);
1798         }
1799
1800         for(i = 0; i < COMEDI_NDEVICES; i++){
1801                 char name[20];
1802                 class_device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, i));
1803                 sprintf(name, "comedi%d", i);
1804         }
1805         class_destroy(comedi_class);
1806         cdev_del(&comedi_cdev);
1807         unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
1808
1809         comedi_proc_cleanup();
1810
1811         kfree(comedi_devices);
1812
1813         comedi_rt_cleanup();
1814 }
1815
1816 module_init(comedi_init);
1817 module_exit(comedi_cleanup);
1818
1819 void comedi_error(const comedi_device *dev,const char *s)
1820 {
1821         rt_printk("comedi%d: %s: %s\n", dev->minor, dev->driver->driver_name, s);
1822 }
1823
1824 void comedi_event(comedi_device *dev,comedi_subdevice *s, unsigned int mask)
1825 {
1826         comedi_async *async = s->async;
1827
1828         mask = s->async->events;
1829         s->async->events = 0;
1830
1831         //DPRINTK("comedi_event %x\n",mask);
1832
1833         if( (s->subdev_flags & SDF_RUNNING) == 0)
1834                 return;
1835
1836         if(mask&(COMEDI_CB_EOA|COMEDI_CB_ERROR|COMEDI_CB_OVERFLOW)){
1837                 s->subdev_flags &= ~SDF_RUNNING;
1838         }
1839
1840         /* remember if an error event has occured, so an error
1841          * can be returned the next time the user does a read() */
1842         if(mask & (COMEDI_CB_ERROR|COMEDI_CB_OVERFLOW)){
1843                 s->runflags |= SRF_ERROR;
1844         }
1845         if(async->cb_mask&mask){
1846                 if(s->runflags&SRF_USER){
1847
1848                         if(dev->rt){
1849 #ifdef CONFIG_COMEDI_RT
1850                                 // pend wake up
1851                                 if(s->subdev_flags & SDF_CMD_READ)
1852                                         comedi_rt_pend_wakeup(&dev->read_wait);
1853                                 if(s->subdev_flags & SDF_CMD_WRITE)
1854                                         comedi_rt_pend_wakeup(&dev->write_wait);
1855 #else
1856                                 printk("BUG: comedi_event() code unreachable\n");
1857 #endif
1858                         }else{
1859                                 if(s->subdev_flags & SDF_CMD_READ){
1860                                         wake_up_interruptible(&dev->read_wait);
1861                                         kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
1862                                 }
1863                                 if(s->subdev_flags & SDF_CMD_WRITE){
1864                                         wake_up_interruptible(&dev->write_wait);
1865                                         kill_fasync(&dev->async_queue, SIGIO, POLL_OUT);
1866                                 }
1867                         }
1868                 }else{
1869                         if(async->cb_func)async->cb_func(mask,async->cb_arg);
1870                         /* XXX bug here.  If subdevice A is rt, and
1871                          * subdevice B tries to callback to a normal
1872                          * linux kernel function, it will be at the
1873                          * wrong priority.  Since this isn't very
1874                          * common, I'm not going to worry about it. */
1875                 }
1876         }
1877 }