Added support for changing routing of signals to RTSI pins. Fixed
[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_ALT_SOURCE:
639         case INSN_CONFIG_8254_SET_MODE:
640         case INSN_CONFIG_8254_READ_STATUS:
641         case INSN_CONFIG_SET_GATE_SRC:
642         case INSN_CONFIG_GET_GATE_SRC:
643         case INSN_CONFIG_SET_ROUTING:
644         case INSN_CONFIG_GET_ROUTING:
645                 if(insn->n == 2) return 0;
646                 break;
647         case INSN_CONFIG_SET_CLOCK_SRC:
648         case INSN_CONFIG_GET_CLOCK_SRC:
649                 if(insn->n == 3) return 0;
650                 break;
651         case INSN_CONFIG_PWM_OUTPUT:
652                 if(insn->n == 5) return 0;
653                 break;
654         //by default we allow the insn since we don't have checks for all possible cases yet
655         default:
656                 rt_printk("comedi: no check for data length of config insn id %i is implemented.\n"
657                         " Add a check to %s in %s.\n"
658                         " Assuming n=%i is correct.\n",
659                         data[0], __FUNCTION__, __FILE__, insn->n);
660                 return 0;
661                 break;
662         }
663         return -EINVAL;
664 }
665
666 static int parse_insn(comedi_device *dev,comedi_insn *insn,lsampl_t *data,void *file)
667 {
668         comedi_subdevice *s;
669         int ret = 0;
670
671         if(insn->insn&INSN_MASK_SPECIAL){
672                 /* a non-subdevice instruction */
673
674                 switch(insn->insn){
675                 case INSN_GTOD:
676                 {
677                         struct timeval tv;
678
679                         if(insn->n!=2){
680                                 ret=-EINVAL;
681                                 break;
682                         }
683
684                         do_gettimeofday(&tv);
685                         data[0]=tv.tv_sec;
686                         data[1]=tv.tv_usec;
687                         ret=2;
688
689                         break;
690                 }
691                 case INSN_WAIT:
692                         if(insn->n!=1 || data[0]>=100000){
693                                 ret=-EINVAL;
694                                 break;
695                         }
696                         udelay(data[0]/1000);
697                         ret=1;
698                         break;
699                 case INSN_INTTRIG:
700                         if(insn->n!=1){
701                                 ret=-EINVAL;
702                                 break;
703                         }
704                         if(insn->subdev>=dev->n_subdevices){
705                                 DPRINTK("%d not usable subdevice\n",insn->subdev);
706                                 ret=-EINVAL;
707                                 break;
708                         }
709                         s=dev->subdevices+insn->subdev;
710                         if(!s->async){
711                                 DPRINTK("no async\n");
712                                 ret=-EINVAL;
713                                 break;
714                         }
715                         if(!s->async->inttrig){
716                                 DPRINTK("no inttrig\n");
717                                 ret=-EAGAIN;
718                                 break;
719                         }
720                         ret = s->async->inttrig(dev,s,insn->data[0]);
721                         if(ret>=0)ret = 1;
722                         break;
723                 default:
724                         DPRINTK("invalid insn\n");
725                         ret=-EINVAL;
726                         break;
727                 }
728         }else{
729                 /* a subdevice instruction */
730                 if(insn->subdev>=dev->n_subdevices){
731                         DPRINTK("subdevice %d out of range\n",insn->subdev);
732                         ret=-EINVAL;
733                         goto out;
734                 }
735                 s=dev->subdevices+insn->subdev;
736
737                 if(s->type==COMEDI_SUBD_UNUSED){
738                         DPRINTK("%d not usable subdevice\n",insn->subdev);
739                         ret = -EIO;
740                         goto out;
741                 }
742
743                 /* are we locked? (ioctl lock) */
744                 if(s->lock && s->lock!=file){
745                         DPRINTK("device locked\n");
746                         ret = -EACCES;
747                         goto out;
748                 }
749
750                 if((ret=check_chanlist(s,1,&insn->chanspec))<0){
751                         ret=-EINVAL;
752                         DPRINTK("bad chanspec\n");
753                         goto out;
754                 }
755
756                 if(s->busy){
757                         ret=-EBUSY;
758                         goto out;
759                 }
760                 /* This looks arbitrary.  It is. */
761                 s->busy=&parse_insn;
762                 switch(insn->insn){
763                         case INSN_READ:
764                                 ret=s->insn_read(dev,s,insn,data);
765                                 break;
766                         case INSN_WRITE:
767                                 //XXX check against subdevice's maxdata
768                                 ret=s->insn_write(dev,s,insn,data);
769                                 break;
770                         case INSN_BITS:
771                                 ret=s->insn_bits(dev,s,insn,data);
772                                 break;
773                         case INSN_CONFIG:
774                                 ret=check_insn_config_length(insn, data);
775                                 if(ret) break;
776                                 ret=s->insn_config(dev,s,insn,data);
777                                 break;
778                         default:
779                                 ret=-EINVAL;
780                                 break;
781                 }
782
783                 s->busy=NULL;
784         }
785
786 out:
787         return ret;
788 }
789
790 /*
791  *      COMEDI_INSN
792  *      synchronous instructions
793  *
794  *      arg:
795  *              pointer to insn
796  *
797  *      reads:
798  *              comedi_insn struct at arg
799  *              data (for writes)
800  *
801  *      writes:
802  *              data (for reads)
803  */
804 static int do_insn_ioctl(comedi_device *dev,void *arg,void *file)
805 {
806         comedi_insn     insn;
807         lsampl_t        *data = NULL;
808         int ret=0;
809
810         data=kmalloc(sizeof(lsampl_t)*MAX_SAMPLES,GFP_KERNEL);
811         if(!data){
812                 ret = -ENOMEM;
813                 goto error;
814         }
815
816         if(copy_from_user(&insn,arg,sizeof(comedi_insn))){
817                 ret=-EFAULT;
818                 goto error;
819         }
820
821         /* This is where the behavior of insn and insnlist deviate. */
822         if(insn.n>MAX_SAMPLES)insn.n=MAX_SAMPLES;
823         if(insn.insn&INSN_MASK_WRITE){
824                 if(copy_from_user(data,insn.data,insn.n*sizeof(lsampl_t))){
825                         ret=-EFAULT;
826                         goto error;
827                 }
828         }
829         ret = parse_insn(dev,&insn,data,file);
830         if(ret<0)goto error;
831         if(insn.insn&INSN_MASK_READ){
832                 if(copy_to_user(insn.data,data,insn.n*sizeof(lsampl_t))){
833                         ret=-EFAULT;
834                         goto error;
835                 }
836         }
837         ret = insn.n;
838
839 error:
840         if(data)kfree(data);
841
842         return ret;
843 }
844
845 /*
846         COMEDI_CMD
847         command ioctl
848
849         arg:
850                 pointer to cmd structure
851
852         reads:
853                 cmd structure at arg
854                 channel/range list
855
856         writes:
857                 modified cmd structure at arg
858
859 */
860 static int do_cmd_ioctl(comedi_device *dev,void *arg,void *file)
861 {
862         comedi_cmd user_cmd;
863         comedi_subdevice *s;
864         comedi_async *async;
865         int ret=0;
866         unsigned int *chanlist_saver=NULL;
867
868         if(copy_from_user(&user_cmd,arg,sizeof(comedi_cmd))){
869                 DPRINTK("bad cmd address\n");
870                 return -EFAULT;
871         }
872
873         // save user's chanlist pointer so it can be restored later
874         chanlist_saver = user_cmd.chanlist;
875
876         if(user_cmd.subdev>=dev->n_subdevices){
877                 DPRINTK("%d no such subdevice\n",user_cmd.subdev);
878                 return -ENODEV;
879         }
880
881         s=dev->subdevices+user_cmd.subdev;
882         async = s->async;
883
884         if(s->type==COMEDI_SUBD_UNUSED){
885                 DPRINTK("%d not valid subdevice\n",user_cmd.subdev);
886                 return -EIO;
887         }
888
889         if(!s->do_cmd || !s->async){
890                 DPRINTK("subdevice %i does not support commands\n", user_cmd.subdev);
891                 return -EIO;
892         }
893
894         /* are we locked? (ioctl lock) */
895         if(s->lock && s->lock!=file){
896                 DPRINTK("subdevice locked\n");
897                 return -EACCES;
898         }
899
900         /* are we busy? */
901         if(s->busy){
902                 DPRINTK("subdevice busy\n");
903                 return -EBUSY;
904         }
905         s->busy=file;
906
907         /* make sure channel/gain list isn't too long */
908         if(user_cmd.chanlist_len > s->len_chanlist){
909                 DPRINTK("channel/gain list too long %d > %d\n",user_cmd.chanlist_len,s->len_chanlist);
910                 ret = -EINVAL;
911                 goto cleanup;
912         }
913
914         if(async->cmd.chanlist) kfree(async->cmd.chanlist);
915         async->cmd=user_cmd;
916         async->cmd.data=NULL;
917         /* load channel/gain list */
918         async->cmd.chanlist=kmalloc(async->cmd.chanlist_len*sizeof(int),GFP_KERNEL);
919         if(!async->cmd.chanlist){
920                 DPRINTK("allocation failed\n");
921                 ret = -ENOMEM;
922                 goto cleanup;
923         }
924
925         if(copy_from_user(async->cmd.chanlist,user_cmd.chanlist,async->cmd.chanlist_len*sizeof(int))){
926                 DPRINTK("fault reading chanlist\n");
927                 ret = -EFAULT;
928                 goto cleanup;
929         }
930
931         /* make sure each element in channel/gain list is valid */
932         if((ret=check_chanlist(s,async->cmd.chanlist_len,async->cmd.chanlist))<0){
933                 DPRINTK("bad chanlist\n");
934                 goto cleanup;
935         }
936
937         ret=s->do_cmdtest(dev,s,&async->cmd);
938
939         if(async->cmd.flags&TRIG_BOGUS || ret){
940                 DPRINTK("test returned %d\n",ret);
941                 user_cmd=async->cmd;
942                 // restore chanlist pointer before copying back
943                 user_cmd.chanlist = chanlist_saver;
944                 user_cmd.data = NULL;
945                 if(copy_to_user(arg,&user_cmd,sizeof(comedi_cmd))){
946                         DPRINTK("fault writing cmd\n");
947                         ret = -EFAULT;
948                         goto cleanup;
949                 }
950                 ret = -EAGAIN;
951                 goto cleanup;
952         }
953
954         if(!async->prealloc_bufsz){
955                 ret=-ENOMEM;
956                 DPRINTK("no buffer (?)\n");
957                 goto cleanup;
958         }
959
960         init_async_buf( async );
961
962         async->cb_mask = COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW;
963         if(async->cmd.flags & TRIG_WAKE_EOS){
964                 async->cb_mask |= COMEDI_CB_EOS;
965         }
966
967         s->runflags=SRF_USER;
968
969         s->subdev_flags|=SDF_RUNNING;
970
971 #ifdef CONFIG_COMEDI_RT
972         if(async->cmd.flags&TRIG_RT){
973                 comedi_switch_to_rt(dev);
974                 s->runflags |= SRF_RT;
975         }
976 #endif
977
978         ret=s->do_cmd(dev,s);
979
980         if(ret==0)return 0;
981
982 cleanup:
983         do_become_nonbusy(dev,s);
984
985         return ret;
986 }
987
988 /*
989         COMEDI_CMDTEST
990         command testing ioctl
991
992         arg:
993                 pointer to cmd structure
994
995         reads:
996                 cmd structure at arg
997                 channel/range list
998
999         writes:
1000                 modified cmd structure at arg
1001
1002 */
1003 static int do_cmdtest_ioctl(comedi_device *dev,void *arg,void *file)
1004 {
1005         comedi_cmd user_cmd;
1006         comedi_subdevice *s;
1007         int ret=0;
1008         unsigned int *chanlist=NULL;
1009         unsigned int *chanlist_saver=NULL;
1010
1011         if(copy_from_user(&user_cmd,arg,sizeof(comedi_cmd))){
1012                 DPRINTK("bad cmd address\n");
1013                 return -EFAULT;
1014         }
1015
1016         // save user's chanlist pointer so it can be restored later
1017         chanlist_saver = user_cmd.chanlist;
1018
1019         if(user_cmd.subdev>=dev->n_subdevices){
1020                 DPRINTK("%d no such subdevice\n",user_cmd.subdev);
1021                 return -ENODEV;
1022         }
1023
1024         s=dev->subdevices+user_cmd.subdev;
1025         if(s->type==COMEDI_SUBD_UNUSED){
1026                 DPRINTK("%d not valid subdevice\n",user_cmd.subdev);
1027                 return -EIO;
1028         }
1029
1030         if(!s->do_cmd){
1031                 DPRINTK("subdevice %i does not support commands\n", user_cmd.subdev);
1032                 return -EIO;
1033         }
1034
1035         /* make sure channel/gain list isn't too long */
1036         if(user_cmd.chanlist_len > s->len_chanlist){
1037                 DPRINTK("channel/gain list too long %d > %d\n",user_cmd.chanlist_len,s->len_chanlist);
1038                 ret = -EINVAL;
1039                 goto cleanup;
1040         }
1041
1042         /* load channel/gain list */
1043         if(user_cmd.chanlist){
1044                 chanlist=kmalloc(user_cmd.chanlist_len*sizeof(int),GFP_KERNEL);
1045                 if(!chanlist){
1046                         DPRINTK("allocation failed\n");
1047                         ret = -ENOMEM;
1048                         goto cleanup;
1049                 }
1050
1051                 if(copy_from_user(chanlist,user_cmd.chanlist,user_cmd.chanlist_len*sizeof(int))){
1052                         DPRINTK("fault reading chanlist\n");
1053                         ret = -EFAULT;
1054                         goto cleanup;
1055                 }
1056
1057                 /* make sure each element in channel/gain list is valid */
1058                 if((ret=check_chanlist(s,user_cmd.chanlist_len,chanlist))<0){
1059                         DPRINTK("bad chanlist\n");
1060                         goto cleanup;
1061                 }
1062
1063                 user_cmd.chanlist=chanlist;
1064         }
1065
1066         ret=s->do_cmdtest(dev,s,&user_cmd);
1067
1068         // restore chanlist pointer before copying back
1069         user_cmd.chanlist = chanlist_saver;
1070
1071         if(copy_to_user(arg,&user_cmd,sizeof(comedi_cmd))){
1072                 DPRINTK("bad cmd address\n");
1073                 ret=-EFAULT;
1074                 goto cleanup;
1075         }
1076 cleanup:
1077         if(chanlist)
1078                 kfree(chanlist);
1079
1080         return ret;
1081 }
1082
1083 /*
1084         COMEDI_LOCK
1085         lock subdevice
1086
1087         arg:
1088                 subdevice number
1089
1090         reads:
1091                 none
1092
1093         writes:
1094                 none
1095
1096 */
1097
1098 static int do_lock_ioctl(comedi_device *dev,unsigned int arg,void * file)
1099 {
1100         int ret=0;
1101         unsigned long flags;
1102         comedi_subdevice *s;
1103
1104         if(arg>=dev->n_subdevices)
1105                 return -EINVAL;
1106         s=dev->subdevices+arg;
1107
1108         comedi_spin_lock_irqsave(&big_comedi_lock, flags);
1109         if(s->busy)
1110         {
1111                 comedi_spin_unlock_irqrestore(&big_comedi_lock, flags);
1112                 return -EBUSY;
1113         }
1114         if(s->lock){
1115                 ret=-EBUSY;
1116         }else{
1117                 s->lock=file;
1118         }
1119         comedi_spin_unlock_irqrestore(&big_comedi_lock, flags);
1120
1121         if(ret<0)
1122                 return ret;
1123
1124 #if 0
1125         if(s->lock_f)
1126                 ret=s->lock_f(dev,s);
1127 #endif
1128
1129         return ret;
1130 }
1131
1132
1133 /*
1134         COMEDI_UNLOCK
1135         unlock subdevice
1136
1137         arg:
1138                 subdevice number
1139
1140         reads:
1141                 none
1142
1143         writes:
1144                 none
1145
1146         This function isn't protected by the semaphore, since
1147         we already own the lock.
1148 */
1149 static int do_unlock_ioctl(comedi_device *dev,unsigned int arg,void * file)
1150 {
1151         comedi_subdevice *s;
1152
1153         if(arg>=dev->n_subdevices)
1154                 return -EINVAL;
1155         s=dev->subdevices+arg;
1156
1157         if(s->busy)
1158                 return -EBUSY;
1159
1160         if(s->lock && s->lock!=file)
1161                 return -EACCES;
1162
1163         if(s->lock==file){
1164 #if 0
1165                 if(s->unlock)
1166                         s->unlock(dev,s);
1167 #endif
1168
1169                 s->lock=NULL;
1170         }
1171
1172         return 0;
1173 }
1174
1175 /*
1176         COMEDI_CANCEL
1177         cancel acquisition ioctl
1178
1179         arg:
1180                 subdevice number
1181
1182         reads:
1183                 nothing
1184
1185         writes:
1186                 nothing
1187
1188 */
1189 static int do_cancel_ioctl(comedi_device *dev,unsigned int arg,void *file)
1190 {
1191         comedi_subdevice *s;
1192
1193         if(arg>=dev->n_subdevices)
1194                 return -EINVAL;
1195         s=dev->subdevices+arg;
1196
1197         if(s->lock && s->lock!=file)
1198                 return -EACCES;
1199
1200         if(!s->busy)
1201                 return 0;
1202
1203         if(s->busy!=file)
1204                 return -EBUSY;
1205
1206         return do_cancel(dev,s);
1207 }
1208
1209 /*
1210         COMEDI_POLL ioctl
1211         instructs driver to synchronize buffers
1212
1213         arg:
1214                 subdevice number
1215
1216         reads:
1217                 nothing
1218
1219         writes:
1220                 nothing
1221
1222 */
1223 static int do_poll_ioctl(comedi_device *dev,unsigned int arg,void *file)
1224 {
1225         comedi_subdevice *s;
1226
1227         if(arg>=dev->n_subdevices)
1228                 return -EINVAL;
1229         s=dev->subdevices+arg;
1230
1231         if(s->lock && s->lock!=file)
1232                 return -EACCES;
1233
1234         if(!s->busy)
1235                 return 0;
1236
1237         if(s->busy!=file)
1238                 return -EBUSY;
1239
1240         if(s->poll)return s->poll(dev,s);
1241
1242         return -EINVAL;
1243 }
1244
1245 static int do_cancel(comedi_device *dev,comedi_subdevice *s)
1246 {
1247         int ret=0;
1248
1249         if((s->subdev_flags&SDF_RUNNING) && s->cancel)
1250                 ret=s->cancel(dev,s);
1251
1252         do_become_nonbusy(dev,s);
1253
1254         return ret;
1255 }
1256
1257
1258 #define RDEV_OF_FILE(x)        ((x)->f_dentry->d_inode->i_rdev)
1259
1260 void comedi_unmap(struct vm_area_struct *area)
1261 {
1262         comedi_async *async;
1263
1264         async = area->vm_private_data;
1265
1266         async->mmap_count--;
1267 }
1268
1269 static struct vm_operations_struct comedi_vm_ops={
1270         close:          comedi_unmap,
1271 };
1272
1273 static int comedi_mmap(struct file * file, struct vm_area_struct *vma)
1274 {
1275         unsigned int minor=MINOR(RDEV_OF_FILE(file));
1276         comedi_device *dev=comedi_get_device_by_minor(minor);
1277         comedi_async *async = NULL;
1278         unsigned long start = vma->vm_start;
1279         unsigned long size;
1280         int n_pages;
1281         int i;
1282
1283         if(!dev->attached)
1284         {
1285                 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1286                 return -ENODEV;
1287         }
1288
1289         if(vma->vm_flags & VM_WRITE){
1290                 async=dev->write_subdev->async;
1291         }else{
1292                 async=dev->read_subdev->async;
1293         }
1294         if(async==NULL){
1295                 return -EINVAL;
1296         }
1297
1298         if(vma->vm_pgoff != 0){
1299                 DPRINTK("comedi: mmap() offset must be 0.\n");
1300                 return -EINVAL;
1301         }
1302
1303         size = vma->vm_end - vma->vm_start;
1304         if(size>async->prealloc_bufsz)
1305                 return -EFAULT;
1306         if(size&(~PAGE_MASK))
1307                 return -EFAULT;
1308
1309         n_pages = size >> PAGE_SHIFT;
1310         for(i=0;i<n_pages;i++){
1311                 if(remap_pfn_range(vma, start, __pa(async->buf_page_list[i]) >> PAGE_SHIFT,
1312                                 PAGE_SIZE, PAGE_SHARED)){
1313                         return -EAGAIN;
1314                 }
1315                 start += PAGE_SIZE;
1316         }
1317
1318         vma->vm_ops = &comedi_vm_ops;
1319         vma->vm_private_data = async;
1320
1321         async->mmap_count++;
1322
1323         return 0;
1324 }
1325
1326
1327 static unsigned int comedi_poll(struct file *file, poll_table * wait)
1328 {
1329         comedi_device *dev;
1330         comedi_subdevice *s;
1331         comedi_async *async;
1332         unsigned int mask;
1333
1334         dev=comedi_get_device_by_minor(MINOR(RDEV_OF_FILE(file)));
1335
1336         if(!dev->attached)
1337         {
1338                 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1339                 return -ENODEV;
1340         }
1341
1342         poll_wait(file, &dev->read_wait, wait);
1343         poll_wait(file, &dev->write_wait, wait);
1344         mask = 0;
1345         if(dev->read_subdev && dev->read_subdev->async){
1346                 s = dev->read_subdev;
1347                 async = s->async;
1348                 if(!s->busy
1349                    || comedi_buf_read_n_available(s)>0
1350                    || !(s->subdev_flags&SDF_RUNNING)){
1351                         mask |= POLLIN | POLLRDNORM;
1352                 }
1353         }
1354         if(dev->write_subdev && dev->write_subdev->async){
1355                 s = dev->write_subdev;
1356                 async = s->async;
1357                 if(!s->busy
1358                    || !(s->subdev_flags&SDF_RUNNING)
1359                    || comedi_buf_write_n_available(s)>0){
1360                         mask |= POLLOUT | POLLWRNORM;
1361                 }
1362         }
1363
1364         return mask;
1365 }
1366
1367 static ssize_t comedi_write(struct file *file,const char *buf,size_t nbytes,loff_t *offset)
1368 {
1369         comedi_device *dev;
1370         comedi_subdevice *s;
1371         comedi_async *async;
1372         int n,m,count=0,retval=0;
1373         DECLARE_WAITQUEUE(wait,current);
1374
1375         dev=comedi_get_device_by_minor(MINOR(RDEV_OF_FILE(file)));
1376
1377         if(!dev->attached)
1378         {
1379                 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1380                 return -ENODEV;
1381         }
1382
1383         if(dev->write_subdev == NULL)return -EIO;
1384         s = dev->write_subdev;
1385         async = s->async;
1386
1387         if(!nbytes)return 0;
1388
1389         if(!s->busy)
1390                 return 0;
1391
1392         if(s->busy != file)
1393                 return -EACCES;
1394
1395         add_wait_queue(&dev->write_wait,&wait);
1396         while(nbytes>0 && !retval){
1397                 current->state=TASK_INTERRUPTIBLE;
1398
1399                 n=nbytes;
1400
1401                 m = n;
1402                 if(async->buf_write_ptr + m > async->prealloc_bufsz){
1403                         m = async->prealloc_bufsz - async->buf_write_ptr;
1404                 }
1405                 m = comedi_buf_write_alloc(async, m);
1406
1407                 if(m < n) n = m;
1408
1409                 if(n==0){
1410                         if(file->f_flags&O_NONBLOCK){
1411                                 retval=-EAGAIN;
1412                                 break;
1413                         }
1414                         if(signal_pending(current)){
1415                                 retval=-ERESTARTSYS;
1416                                 break;
1417                         }
1418                         if(!(s->subdev_flags&SDF_RUNNING)){
1419                                 if(s->runflags & SRF_ERROR){
1420                                         retval = -EPIPE;
1421                                 }else{
1422                                         retval = 0;
1423                                 }
1424                                 do_become_nonbusy(dev,s);
1425                                 break;
1426                         }
1427                         schedule();
1428                         continue;
1429                 }
1430
1431                 m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
1432                         buf, n);
1433                 if(m){
1434                         n -= m;
1435                         retval = -EFAULT;
1436                 }
1437                 comedi_buf_munge(dev, s, async->buf_write_alloc_count - async->munge_count);
1438                 comedi_buf_write_free(async, n);
1439
1440                 count+=n;
1441                 nbytes-=n;
1442
1443                 buf+=n;
1444                 break;  /* makes device work like a pipe */
1445         }
1446         current->state=TASK_RUNNING;
1447         remove_wait_queue(&dev->write_wait,&wait);
1448
1449         return (count ? count : retval);
1450 }
1451
1452
1453 static ssize_t comedi_read(struct file * file,char *buf,size_t nbytes,loff_t *offset)
1454 {
1455         comedi_device *dev;
1456         comedi_subdevice *s;
1457         comedi_async *async;
1458         int n,m,count=0,retval=0;
1459         DECLARE_WAITQUEUE(wait,current);
1460
1461         dev=comedi_get_device_by_minor(MINOR(RDEV_OF_FILE(file)));
1462
1463         if(!dev->attached)
1464         {
1465                 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1466                 return -ENODEV;
1467         }
1468
1469         s = dev->read_subdev;
1470         if(s == NULL)return -EIO;
1471         async = s->async;
1472
1473         if(!nbytes)return 0;
1474
1475         if(!s->busy)
1476                 return 0;
1477
1478         if(s->busy != file)
1479                 return -EACCES;
1480
1481         add_wait_queue(&dev->read_wait,&wait);
1482         while(nbytes>0 && !retval){
1483                 current->state=TASK_INTERRUPTIBLE;
1484
1485                 n=nbytes;
1486
1487                 m = comedi_buf_read_n_available(s);
1488 //printk("%d available\n",m);
1489                 if(async->buf_read_ptr + m > async->prealloc_bufsz){
1490                         m = async->prealloc_bufsz - async->buf_read_ptr;
1491                 }
1492 //printk("%d contiguous\n",m);
1493                 if(m<n)n=m;
1494
1495                 if(n==0){
1496                         if(!(s->subdev_flags&SDF_RUNNING)){
1497                                 do_become_nonbusy(dev,s);
1498                                 if(s->runflags & SRF_ERROR){
1499                                         retval = -EPIPE;
1500                                 }else{
1501                                         retval = 0;
1502                                 }
1503                                 break;
1504                         }
1505                         if(file->f_flags&O_NONBLOCK){
1506                                 retval=-EAGAIN;
1507                                 break;
1508                         }
1509                         if(signal_pending(current)){
1510                                 retval=-ERESTARTSYS;
1511                                 break;
1512                         }
1513                         schedule();
1514                         continue;
1515                 }
1516                 comedi_buf_munge(dev, s, async->buf_write_count - async->munge_count);
1517                 m = copy_to_user(buf, async->prealloc_buf +
1518                         async->buf_read_ptr, n);
1519                 if(m){
1520                         n -= m;
1521                         retval = -EFAULT;
1522                 }
1523
1524                 comedi_buf_read_free(async, n);
1525
1526                 count+=n;
1527                 nbytes-=n;
1528
1529                 buf+=n;
1530                 break;  /* makes device work like a pipe */
1531         }
1532         if(!(s->subdev_flags&SDF_RUNNING) &&
1533                 !(s->runflags & SRF_ERROR) &&
1534                 async->buf_read_count - async->buf_write_count == 0)
1535         {
1536                 do_become_nonbusy(dev,s);
1537         }
1538         current->state=TASK_RUNNING;
1539         remove_wait_queue(&dev->read_wait,&wait);
1540
1541         return (count ? count : retval);
1542 }
1543
1544 /*
1545    This function restores a subdevice to an idle state.
1546  */
1547 void do_become_nonbusy(comedi_device *dev,comedi_subdevice *s)
1548 {
1549         comedi_async *async = s->async;
1550         /* we do this because it's useful for the non-standard cases */
1551         s->subdev_flags &= ~SDF_RUNNING;
1552
1553 #ifdef CONFIG_COMEDI_RT
1554         if(s->runflags&SRF_RT){
1555                 comedi_switch_to_non_rt(dev);
1556                 s->runflags &= ~SRF_RT;
1557         }
1558 #endif
1559
1560         if(async){
1561                 init_async_buf( async );
1562         }else{
1563                 printk("BUG: (?) do_become_nonbusy called with async=0\n");
1564         }
1565
1566         s->busy=NULL;
1567 }
1568
1569 /* no chance that these will change soon */
1570 #define SEEK_SET 0
1571 #define SEEK_CUR 1
1572 #define SEEK_END 2
1573
1574 static loff_t comedi_lseek(struct file *file,loff_t offset,int origin)
1575 {
1576         comedi_device *dev;
1577         loff_t new_offset;
1578
1579         dev=comedi_get_device_by_minor(MINOR(RDEV_OF_FILE(file)));
1580
1581         switch(origin){
1582         case SEEK_SET:
1583                 new_offset = offset;
1584                 break;
1585         case SEEK_CUR:
1586                 new_offset = file->f_pos + offset;
1587                 break;
1588         case SEEK_END:
1589                 new_offset = dev->n_subdevices + offset;
1590                 break;
1591         default:
1592                 return -EINVAL;
1593         }
1594         if(new_offset<0 || new_offset >= dev->n_subdevices)
1595                 return -EINVAL;
1596
1597         return file->f_pos=new_offset;
1598 }
1599
1600 static int comedi_open(struct inode *inode,struct file *file)
1601 {
1602         unsigned int minor=MINOR(inode->i_rdev);
1603         comedi_device *dev;
1604         char mod[32];
1605
1606         if(minor>=COMEDI_NDEVICES){
1607                 DPRINTK("invalid minor number\n");
1608                 return -ENODEV;
1609         }
1610         dev=comedi_get_device_by_minor(minor);
1611
1612         /* This is slightly hacky, but we want module autoloading
1613          * to work for root.
1614          * case: user opens device, attached -> ok
1615          * case: user opens device, unattached, in_request_module=0 -> autoload
1616          * case: user opens device, unattached, in_request_module=1 -> fail
1617          * case: root opens device, attached -> ok
1618          * case: root opens device, unattached, in_request_module=1 -> ok
1619          *   (typically called from modprobe)
1620          * case: root opens device, unattached, in_request_module=0 -> autoload
1621          *
1622          * The last could be changed to "-> ok", which would deny root
1623          * autoloading.
1624          */
1625         if(dev->attached)
1626                 goto ok;
1627         if(!capable(CAP_SYS_MODULE) && dev->in_request_module){
1628                 DPRINTK("in request module\n");
1629                 return -ENODEV;
1630         }
1631         if(capable(CAP_SYS_MODULE) && dev->in_request_module)
1632                 goto ok;
1633
1634         dev->in_request_module=1;
1635
1636         sprintf(mod,"char-major-%i-%i",COMEDI_MAJOR,minor);
1637 #ifdef CONFIG_KMOD
1638         request_module(mod);
1639 #endif
1640
1641         dev->in_request_module=0;
1642
1643         if(!dev->attached && !capable(CAP_SYS_MODULE)){
1644                 DPRINTK("not attached and not CAP_SYS_MODULE\n");
1645                 return -ENODEV;
1646         }
1647 ok:
1648         if(!try_module_get(THIS_MODULE))
1649                 return -ENOSYS;
1650
1651         if(dev->attached){
1652                 try_module_get( dev->driver->module );
1653         }
1654
1655         if(dev->attached && dev->use_count==0 && dev->open){
1656                 dev->open(dev);
1657         }
1658
1659         dev->use_count++;
1660
1661         return 0;
1662 }
1663
1664 static int comedi_close(struct inode *inode,struct file *file)
1665 {
1666         comedi_device *dev=comedi_get_device_by_minor(MINOR(inode->i_rdev));
1667         comedi_subdevice *s = NULL;
1668         int i;
1669
1670         if(dev->subdevices)
1671         {
1672                 for(i=0;i<dev->n_subdevices;i++){
1673                         s=dev->subdevices+i;
1674
1675                         if(s->busy==file){
1676                                 do_cancel(dev,s);
1677                         }
1678                         if(s->lock==file){
1679                                 s->lock=NULL;
1680                         }
1681                 }
1682         }
1683         if(dev->attached && dev->use_count==1 && dev->close){
1684                 dev->close(dev);
1685         }
1686
1687         module_put(THIS_MODULE);
1688         if(dev->attached){
1689                 module_put(dev->driver->module);
1690         }
1691
1692         dev->use_count--;
1693
1694         if(file->f_flags & FASYNC){
1695                 comedi_fasync(-1,file,0);
1696         }
1697
1698         return 0;
1699 }
1700
1701 static int comedi_fasync (int fd, struct file *file, int on)
1702 {
1703         comedi_device *dev=comedi_get_device_by_minor(MINOR(RDEV_OF_FILE(file)));
1704
1705         return fasync_helper(fd,file,on,&dev->async_queue);
1706 }
1707
1708
1709 static struct file_operations comedi_fops={
1710         owner           : THIS_MODULE,
1711         llseek          : comedi_lseek,
1712         ioctl           : comedi_ioctl,
1713         open            : comedi_open,
1714         release         : comedi_close,
1715         read            : comedi_read,
1716         write           : comedi_write,
1717         mmap            : comedi_mmap,
1718         poll            : comedi_poll,
1719         fasync          : comedi_fasync,
1720 };
1721
1722 static struct class *comedi_class;
1723
1724 static int __init comedi_init(void)
1725 {
1726         int i;
1727
1728         printk("comedi: version " COMEDI_RELEASE " - David Schleef <ds@schleef.org>\n");
1729         spin_lock_init(&big_comedi_lock);
1730         if(devfs_register_chrdev(COMEDI_MAJOR,"comedi",&comedi_fops)){
1731                 printk("comedi: unable to get major %d\n",COMEDI_MAJOR);
1732                 return -EIO;
1733         }
1734         comedi_class = class_create(THIS_MODULE, "comedi");
1735         if(IS_ERR(comedi_class))
1736         {
1737                 printk("comedi: failed to create class");
1738                 devfs_unregister_chrdev(COMEDI_MAJOR,"comedi");
1739                 return PTR_ERR(comedi_class);
1740         }
1741         comedi_devices=(comedi_device *)kmalloc(sizeof(comedi_device)*COMEDI_NDEVICES,GFP_KERNEL);
1742         if(!comedi_devices)
1743         {
1744                 class_destroy(comedi_class);
1745                 devfs_unregister_chrdev(COMEDI_MAJOR,"comedi");
1746                 return -ENOMEM;
1747         }
1748         memset(comedi_devices,0,sizeof(comedi_device)*COMEDI_NDEVICES);
1749         for(i=0;i<COMEDI_NDEVICES;i++){
1750                 comedi_devices[i].minor=i;
1751                 spin_lock_init(&(comedi_devices[i].spinlock));
1752         }
1753
1754         /* XXX requires /proc interface */
1755         comedi_proc_init();
1756
1757         for(i=0;i<COMEDI_NDEVICES;i++){
1758                 char name[20];
1759                 sprintf(name, "comedi%d", i);
1760                 devfs_register(NULL, name, DEVFS_FL_DEFAULT,
1761                         COMEDI_MAJOR, i, 0666 | S_IFCHR, &comedi_fops, NULL);
1762                 COMEDI_CLASS_DEVICE_CREATE(comedi_class, 0,
1763                                 MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i);
1764         }
1765
1766         comedi_rt_init();
1767
1768         return 0;
1769 }
1770
1771 static void __exit comedi_cleanup(void)
1772 {
1773         int i;
1774
1775         if(MOD_IN_USE)
1776                 printk("comedi: module in use -- remove delayed\n");
1777
1778         for(i=0;i<COMEDI_NDEVICES;i++){
1779                 char name[20];
1780                 class_device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, i));
1781                 sprintf(name, "comedi%d", i);
1782                 devfs_unregister(devfs_find_handle(NULL, name,
1783                         COMEDI_MAJOR, i, DEVFS_SPECIAL_CHR, 0));
1784         }
1785         class_destroy(comedi_class);
1786         devfs_unregister_chrdev(COMEDI_MAJOR,"comedi");
1787
1788         comedi_proc_cleanup();
1789
1790         for(i=0;i<COMEDI_NDEVICES;i++){
1791                 comedi_device *dev;
1792
1793                 dev=comedi_get_device_by_minor(i);
1794                 if(dev->attached)
1795                         comedi_device_detach(dev);
1796         }
1797         kfree(comedi_devices);
1798
1799         comedi_rt_cleanup();
1800 }
1801
1802 module_init(comedi_init);
1803 module_exit(comedi_cleanup);
1804
1805 void comedi_error(const comedi_device *dev,const char *s)
1806 {
1807         rt_printk("comedi%d: %s: %s\n",dev->minor,dev->driver->driver_name,s);
1808 }
1809
1810 void comedi_event(comedi_device *dev,comedi_subdevice *s, unsigned int mask)
1811 {
1812         comedi_async *async = s->async;
1813
1814         mask = s->async->events;
1815         s->async->events = 0;
1816
1817         //DPRINTK("comedi_event %x\n",mask);
1818
1819         if( (s->subdev_flags & SDF_RUNNING) == 0)
1820                 return;
1821
1822         if(mask&(COMEDI_CB_EOA|COMEDI_CB_ERROR|COMEDI_CB_OVERFLOW)){
1823                 s->subdev_flags &= ~SDF_RUNNING;
1824         }
1825
1826         /* remember if an error event has occured, so an error
1827          * can be returned the next time the user does a read() */
1828         if(mask & (COMEDI_CB_ERROR|COMEDI_CB_OVERFLOW)){
1829                 s->runflags |= SRF_ERROR;
1830         }
1831         if(async->cb_mask&mask){
1832                 if(s->runflags&SRF_USER){
1833
1834                         if(dev->rt){
1835 #ifdef CONFIG_COMEDI_RT
1836                                 // pend wake up
1837                                 if(s==dev->read_subdev)
1838                                         comedi_rt_pend_wakeup(&dev->read_wait);
1839                                 if(s==dev->write_subdev)
1840                                         comedi_rt_pend_wakeup(&dev->write_wait);
1841 #else
1842                                 printk("BUG: comedi_event() code unreachable\n");
1843 #endif
1844                         }else{
1845                                 if(s==dev->read_subdev){
1846                                         wake_up_interruptible(&dev->read_wait);
1847                                         kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
1848                                 }
1849                                 if(s==dev->write_subdev){
1850                                         wake_up_interruptible(&dev->write_wait);
1851                                         kill_fasync(&dev->async_queue, SIGIO, POLL_OUT);
1852                                 }
1853                         }
1854                 }else{
1855                         if(async->cb_func)async->cb_func(mask,async->cb_arg);
1856                         /* XXX bug here.  If subdevice A is rt, and
1857                          * subdevice B tries to callback to a normal
1858                          * linux kernel function, it will be at the
1859                          * wrong priority.  Since this isn't very
1860                          * common, I'm not going to worry about it. */
1861                 }
1862         }
1863 }
1864
1865 static void init_async_buf( comedi_async *async )
1866 {
1867         async->buf_write_alloc_count = 0;
1868         async->buf_write_count = 0;
1869         async->buf_read_count = 0;
1870
1871         async->buf_write_ptr = 0;
1872         async->buf_read_ptr = 0;
1873
1874         async->cur_chan = 0;
1875         async->scan_progress = 0;
1876         async->munge_chan = 0;
1877         async->munge_count = 0;
1878         async->munge_ptr = 0;
1879
1880         async->events = 0;
1881 }
1882