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