diff -urN comedi-0.7.27/include/comedi.h comedi-0.7.27-test/include/comedi.h --- comedi-0.7.27/include/comedi.h Fri Oct 29 15:44:59 1999 +++ comedi-0.7.27-test/include/comedi.h Thu Nov 4 21:27:54 1999 @@ -98,6 +98,8 @@ #define SDF_MODE2 0x0200 /* can do mode 2 */ #define SDF_MODE3 0x0400 /* can do mode 3 */ #define SDF_MODE4 0x0800 /* can do mode 4 */ +#define SDF_ASYNC 0x1000 /* subdevice is capable of asynchronous commands */ +#define SDF_PERMBUF 0x2000 /* subdevice has a permanently allocated buffer */ #define SDF_READABLE 0x00010000 /* subdevice can be read (e.g. analog input) */ #define SDF_WRITEABLE 0x00020000 /* subdevice can be written (e.g. analog output) */ @@ -145,6 +147,10 @@ #define COMEDI_CANCEL _IO(CIO,7) #define COMEDI_RANGEINFO _IOR(CIO,8,comedi_rangeinfo) #define COMEDI_CMD _IOR(CIO,9,comedi_cmd) +#define COMEDI_SUBDCONFIG _IOW(CIO,10,comedi_subdconfig) +#define COMEDI_SETBUFSIZE _IO(CIO,11) +#define COMEDI_SETMAXBUFSIZE _IO(CIO,12) +#define COMEDI_SETPERMBUF _IO(CIO,13) @@ -156,6 +162,7 @@ typedef struct comedi_subdinfo_struct comedi_subdinfo; typedef struct comedi_devinfo_struct comedi_devinfo; typedef struct comedi_devconfig_struct comedi_devconfig; +typedef struct comedi_subdconfig_struct comedi_subdconfig; typedef struct comedi_rangeinfo_struct comedi_rangeinfo; typedef struct comedi_krange_struct comedi_krange; @@ -228,7 +235,9 @@ lsampl_t maxdata; unsigned int flags; /* channel flags */ unsigned int range_type; /* lookup in kernel */ - unsigned int unused[10]; + unsigned int max_buffer_size; /* maximum allowed buffer size */ + unsigned int buffer_size; /* currently configured buffer size */ + unsigned int unused[8]; }; struct comedi_devinfo_struct{ @@ -242,6 +251,12 @@ struct comedi_devconfig_struct{ char board_name[COMEDI_NAMELEN]; int options[COMEDI_NDEVCONFOPTS]; +}; + +struct comedi_subdconfig_struct{ + unsigned int subdev; + unsigned int cmd; + long arg; }; diff -urN comedi-0.7.27/module/comedi_module.h comedi-0.7.27-test/module/comedi_module.h --- comedi-0.7.27/module/comedi_module.h Fri Oct 29 15:44:59 1999 +++ comedi-0.7.27-test/module/comedi_module.h Thu Nov 4 21:12:08 1999 @@ -97,17 +97,38 @@ struct comedi_subdevice_struct{ int type; - int n_chan; - int subdev_flags; - int timer_type; - int len_chanlist; /* length of channel/gain list, if available */ - void *prealloc_buf; /* pre-allocated buffer */ - unsigned int prealloc_bufsz; /* buffer size, in bytes */ + /* internal parameters */ + void *private; void *lock; void *busy; + void *buffer; + unsigned int buffer_ref_count; + + comedi_trig cur_trig; /* current trig structure */ + comedi_cmd cmd; + + volatile unsigned int buf_int_ptr; /* buffer marker for interrupt */ + unsigned int buf_user_ptr; /* buffer marker for read() and write() */ + volatile unsigned int buf_int_count; /* byte count for interrupt */ + unsigned int buf_user_count; /* byte count for read() and write() */ + unsigned int cur_chan; /* useless channel marker for interrupt */ + + unsigned int state; + + /* user-configurable parameters */ + + unsigned int max_buffer_size; + unsigned int buffer_size; + /* informational parameters */ + + int n_chan; + int subdev_flags; + int timer_type; + int len_chanlist; /* length of channel/gain list, if available */ + int io_bits; lsampl_t maxdata; /* if maxdata==0, use list */ @@ -121,18 +142,7 @@ unsigned int *chanlist; /* driver-owned chanlist (not used) */ - comedi_trig cur_trig; /* current trig structure */ - comedi_cmd cmd; - - volatile unsigned int buf_int_ptr; /* buffer marker for interrupt */ - unsigned int buf_user_ptr; /* buffer marker for read() and write() */ - volatile unsigned int buf_int_count; /* byte count for interrupt */ - unsigned int buf_user_count; /* byte count for read() and write() */ - unsigned int cur_chan; /* useless channel marker for interrupt */ - -#if 0 - unsigned int *range_list; /* is this necessary? */ -#endif + /* virtual functions */ int (*trig[5])(comedi_device *,comedi_subdevice *,comedi_trig *); @@ -140,11 +150,11 @@ int (*poll)(comedi_device *,comedi_subdevice *); int (*cancel)(comedi_device *,comedi_subdevice *); + /* callback parameters */ + unsigned int cb_mask; int (*cb_func)(unsigned int flags,void *); void *cb_arg; - - unsigned int state; }; struct comedi_device_struct{ diff -urN comedi-0.7.27/module/module.c comedi-0.7.27-test/module/module.c --- comedi-0.7.27/module/module.c Fri Oct 29 15:44:59 1999 +++ comedi-0.7.27-test/module/module.c Thu Nov 4 21:47:51 1999 @@ -43,8 +43,11 @@ comedi_device *comedi_devices; +int comedi_allocate_buffer(comedi_device *dev,comedi_subdevice *s); +void comedi_free_buffer(comedi_device *dev,comedi_subdevice *s); static int do_devconfig_ioctl(comedi_device *dev,comedi_devconfig *arg,kdev_t minor); +static int do_subdconfig_ioctl(comedi_device *dev,comedi_subdconfig *arg); static int do_devinfo_ioctl(comedi_device *dev,comedi_devinfo *arg); static int do_subdinfo_ioctl(comedi_device *dev,comedi_subdinfo *arg,void *file); static int do_chaninfo_ioctl(comedi_device *dev,comedi_chaninfo *arg); @@ -85,6 +88,8 @@ return do_cancel_ioctl(dev,arg,file); case COMEDI_CMD: return do_cmd_ioctl(dev,(void *)arg,file); + case COMEDI_SUBDCONFIG: + return do_subdconfig_ioctl(dev,(void *)arg); default: return -EIO; } @@ -144,6 +149,54 @@ return -EINVAL; } +/* + subdevice ioctls + + the decision to make devices/subdevices, although stupid at + the time, seems _very_ stupid now. These are 'subdevice specific' + ioctls. + + fortunately, this should all be hidden behind a nice library + interface. + */ +static int do_subdconfig_ioctl(comedi_device *dev,comedi_subdconfig *arg) +{ + comedi_subdconfig it; + comedi_subdevice *s; + + if(copy_from_user(&it,arg,sizeof(comedi_subdconfig))) + return -EFAULT; + + if(it.subdev>=dev->n_subdevices) + return -EINVAL; + s=dev->subdevices+it.subdev; + + switch(it.cmd){ + case COMEDI_SETBUFSIZE: + if(((unsigned int)it.arg)>=s->max_buffer_size) + return -EPERM; + + if(s->buffer_ref_count) + return -EBUSY; + + s->buffer_size=it.arg; + + return 0; + case COMEDI_SETMAXBUFSIZE: + if(!suser()) + return -EPERM; + + s->max_buffer_size=it.arg; + + return 0; + case COMEDI_SETPERMBUF: + if(it.arg)s->flags|=SDF_PERMBUF; + else s->flags&=~SDF_PERMBUF; + + return 0; + } + return -EINVAL; +} /* COMEDI_DEVINFO @@ -226,6 +279,8 @@ us->maxdata = s->maxdata; us->range_type = s->range_type; us->flags = s->flags; + us->max_buffer_size = s->max_buffer_size; + us->buffer_size = s->buffer_size; if(s->busy) us->subd_flags |= SDF_BUSY; @@ -331,7 +386,7 @@ { comedi_trig user_trig; comedi_subdevice *s; - int ret=0,i,bufsz; + int ret=0,i; int reading; #if 0 @@ -405,28 +460,13 @@ goto cleanup; } - if(!s->prealloc_bufsz){ - /* allocate temporary buffer */ - - if(s->subdev_flags&SDF_LSAMPL){ - bufsz=s->cur_trig.n*s->cur_trig.n_chan*sizeof(lsampl_t); - }else{ - bufsz=s->cur_trig.n*s->cur_trig.n_chan*sizeof(sampl_t); - } - - if(!(s->cur_trig.data=kmalloc(bufsz,GFP_KERNEL))){ - DPRINTK("failed to allocate buffer\n"); - ret=-ENOMEM; - goto cleanup; - } - }else{ - bufsz=s->prealloc_bufsz; - if(!s->prealloc_buf){ - printk("comedi: bug: s->prealloc_buf=NULL\n"); - } - s->cur_trig.data=s->prealloc_buf; + if((ret=comedi_allocate_buffer(dev,s))<0){ + ret=-ENOMEM; + goto cleanup; } - s->cur_trig.data_len=bufsz; + s->cur_trig.data=s->buffer; + s->cur_trig.data_len=s->buffer_size; + #if 0 /* debugging */ @@ -498,10 +538,12 @@ }else{ i=ret*sizeof(sampl_t); } +#if 0 if(i>bufsz){ printk("comedi: (bug) trig returned too many samples\n"); i=bufsz; } +#endif if(reading){ if(copy_to_user(user_trig.data,s->cur_trig.data,i)){ ret=-EFAULT; @@ -603,12 +645,12 @@ goto cleanup; } - if(!s->prealloc_bufsz){ - ret=-ENOMEM; - DPRINTK("no buffer (?)\n"); + if((ret=comedi_allocate_buffer(dev,s))<0){ + DPRINTK("buffer problems\n"); goto cleanup; } - s->cmd.data_len=s->prealloc_bufsz; + s->cmd.data=s->buffer; + s->cmd.data_len=s->buffer_size; s->buf_int_ptr=0; s->buf_int_count=0; @@ -805,6 +847,7 @@ comedi_device *dev=comedi_devices+minor; comedi_subdevice *s; int size; + int ret; if(vma->vm_offset >= dev->n_subdevices) return -EIO; @@ -820,7 +863,10 @@ if(size>(1<<16)) return -EINVAL; - if(remap_page_range(vma->vm_start, virt_to_phys(s->prealloc_buf), + if((ret=comedi_allocate_buffer(dev,s))<0) + return ret; + + if(remap_page_range(vma->vm_start, virt_to_phys(s->buffer), size,vma->vm_page_prot)) return -EAGAIN; @@ -880,15 +926,13 @@ if(!(s->subdev_flags&SDF_WRITEABLE)) return -EIO; - if(!s->busy){ - buf_ptr=s->prealloc_buf; - buf_len=s->prealloc_bufsz; + if(!s->busy && s->buffer){ + buf_ptr=s->buffer; + buf_len=s->buffer_size; }else{ if(s->busy != file) return -EACCES; - - buf_ptr=s->cur_trig.data; - buf_len=s->cur_trig.data_len; + return -ENOMEM; } if(!buf_ptr) @@ -971,7 +1015,7 @@ if(!s->busy) return 0; - if(!s->cur_trig.data || !(s->subdev_flags&SDF_READABLE)) + if(!s->buffer || !(s->subdev_flags&SDF_READABLE)) return -EIO; if(s->busy != file) @@ -984,14 +1028,14 @@ n=nbytes; m=s->buf_int_count-s->buf_user_count; - if(m>s->cur_trig.data_len){ + if(m>s->buffer_size){ s->buf_user_count=s->buf_int_count; s->buf_user_ptr=s->buf_int_ptr; retval=-EINVAL; /* OVERRUN */ break; } - if(s->buf_user_ptr+m > s->cur_trig.data_len){ - m=s->cur_trig.data_len - s->buf_user_ptr; + if(s->buf_user_ptr+m > s->buffer_size){ + m=s->buffer_size - s->buf_user_ptr; #if 0 printk("m is %d\n",m); #endif @@ -1015,7 +1059,7 @@ schedule(); continue; } - m=copy_to_user(buf,((void *)(s->cur_trig.data))+s->buf_user_ptr,n); + m=copy_to_user(buf,s->buffer+s->buf_user_ptr,n); if(m) retval=-EFAULT; n-=m; @@ -1024,7 +1068,7 @@ s->buf_user_ptr+=n; s->buf_user_count+=n; - if(s->buf_user_ptr>=s->cur_trig.data_len ){ + if(s->buf_user_ptr>=s->buffer_size ){ s->buf_user_ptr=0; #if 0 if(s->subdev_flags & SDF_RUNNING) @@ -1059,12 +1103,10 @@ s->cur_trig.chanlist=NULL; } - if(s->cur_trig.data){ - if(s->cur_trig.data != s->prealloc_buf) - kfree(s->cur_trig.data); - - s->cur_trig.data=NULL; + if(s->cur_trig.data == s->buffer){ + comedi_free_buffer(dev,s); } + s->cur_trig.data=NULL; s->buf_user_ptr=0; s->buf_int_ptr=0; @@ -1249,8 +1291,15 @@ for(i=0;in_subdevices;i++){ s=dev->subdevices+i; - if(s->prealloc_buf) - vfree(s->prealloc_buf); + if(s->buffer){ + if(s->buffer_ref_count!=1){ + printk("buffer ref count != 1 (%d)\n", + s->buffer_ref_count); + s->buffer_ref_count=1; + } + comedi_free_buffer(dev,s); + } + if(s->private)kfree(s->private); } if(dev->rem)dev->rem(dev); if(dev->subdevices)kfree(dev->subdevices); @@ -1360,23 +1409,14 @@ if(s->type==COMEDI_SUBD_UNUSED) continue; - if(s->len_chanlist==0) - s->len_chanlist=1; - - /* XXX */ - if(s->trig[1] || s->trig[2] || s->trig[3] ||s->trig[4]){ - s->prealloc_bufsz=1024*128; - }else{ - s->prealloc_bufsz=0; + if(s->trig[1] || s->trig[2] || s->trig[3] || s->trig[4] + || s->do_cmd){ + s->max_buffer_size=65536; + s->buffer_size=65536; } - if(s->prealloc_bufsz){ - /* XXX */ - s->prealloc_buf=vmalloc(s->prealloc_bufsz*sizeof(sampl_t)); - if(!s->prealloc_buf){ - printk("ENOMEM\n"); - } - } + if(s->len_chanlist==0) + s->len_chanlist=1; if(!s->range_type && !s->range_type_list) s->range_type=RANGE_unknown; @@ -1635,4 +1675,36 @@ } #endif + +/* + This function is called when we've decided we need a buffer. + If there is one permanently allocated, that is returned, + otherwise a temporary buffer is allocated. + */ +int comedi_allocate_buffer(comedi_device *dev,comedi_subdevice *s) +{ + if(!s->buffer_ref_count){ + //s->buffer=kmalloc(s->buffer_size,GFP_KERNEL); + s->buffer=vmalloc(s->buffer_size); + if(!s->buffer){ + printk("comedi: gack! no mem\n"); + return -ENOMEM; + } + } + s->buffer_ref_count++; + + return 0; +} + +void comedi_free_buffer(comedi_device *dev,comedi_subdevice *s) +{ + s->buffer_ref_count--; + + if(!s->buffer_ref_count){ + //kfree(s->buffer); + vfree(s->buffer); + s->buffer=NULL; + } +} + diff -urN comedi-0.7.27/module/ni-E.c comedi-0.7.27-test/module/ni-E.c --- comedi-0.7.27/module/ni-E.c Fri Oct 29 15:44:59 1999 +++ comedi-0.7.27-test/module/ni-E.c Thu Nov 4 19:47:03 1999 @@ -836,6 +836,37 @@ return 0; } +/* ai command */ + +static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s) +{ + comedi_cmd *cmd=&s->cmd; + + if( cmd->start_src==TRIG_NOW + && cmd->scan_begin_src==TRIG_TIMER + && cmd->convert_src==TRIG_TIMER + && cmd->scan_end_src==TRIG_COUNT + && cmd->stop_src==TRIG_COUNT){ + comedi_trig *trig=&s->cur_trig; + + trig->subdev=0; + trig->mode=2; + trig->flags=0; + trig->n_chan=cmd->scan_end_arg; + trig->data=cmd->data; + trig->chanlist=cmd->chanlist; + trig->n=cmd->stop_arg; + trig->trigsrc=0; + trig->trigvar=cmd->convert_arg/20-1; + trig->trigvar1=cmd->scan_begin_arg/20-1; + trig->data_len=cmd->data_len; + + return ni_ai_mode2(dev,s,trig); + } + + return -EIO; +} + static void ni_ao_fifo_load(comedi_device *dev,comedi_subdevice *s, sampl_t *data,int n) @@ -1214,6 +1245,7 @@ s->trig[1]=ni_ai_mode1; /* not true mode 1 */ s->trig[2]=ni_ai_mode2; s->trig[4]=ni_ai_mode4; + s->do_cmd=ni_ai_cmd; s->cancel=ni_ai_reset; /* analog output subdevice */