random cruft that needs to be merged, or not
authorDavid Schleef <ds@schleef.org>
Mon, 5 Feb 2001 03:06:22 +0000 (03:06 +0000)
committerDavid Schleef <ds@schleef.org>
Mon, 5 Feb 2001 03:06:22 +0000 (03:06 +0000)
patches/cascade-test.c [new file with mode: 0644]
patches/patch-bufconfig [new file with mode: 0644]
patches/patch-pcmad [new file with mode: 0644]
patches/patch-scxi [new file with mode: 0644]
patches/pcmad.c [new file with mode: 0644]

diff --git a/patches/cascade-test.c b/patches/cascade-test.c
new file mode 100644 (file)
index 0000000..9850808
--- /dev/null
@@ -0,0 +1,144 @@
+#include <comedi.h>
+#include <math.h>
+#include <stdio.h>
+#include "../comedi/drivers/8253.h"
+
+#if NOT
+/* this function is meant to replace i8253_cascade_ns_to_timer_2div
+ * (which is completely broken at the moment)
+ */
+static inline void cascade_new(int i8253_osc_base, unsigned int *d1, unsigned int *d2, unsigned int *nanosec, int round_mode)
+{
+       unsigned int divider;
+       unsigned int div1, div2;
+       unsigned int div1_glb, div2_glb, ns_glb;
+       unsigned int div1_lub, div2_lub, ns_lub;
+       unsigned int ns;
+       unsigned int start;
+       unsigned int ns_low, ns_high;
+
+       divider = *nanosec / i8253_osc_base;
+
+       div1_lub = div2_lub = 0;
+       div1_glb = div2_glb = 0;
+
+       ns_glb = 0;
+       ns_lub = 0xffffffff;
+
+       div2 = 0x10000;
+       start = divider / div2;
+       if(start < 2) start = 2;
+       for (div1 = start; div1 <= divider / div1 + 1; div1++) {
+               for(div2 = divider / div1; div1 * div2 <= divider + div1 + 1; div2++) {
+                       ns = i8253_osc_base * div1 * div2;
+                       if (ns <= *nanosec && ns > ns_glb) {
+                               ns_glb = ns;
+                               div1_glb = div1;
+                               div2_glb = div2;
+                       }
+                       if (div2 <= 0x10000) {
+                               ns = i8253_osc_base * div1 * div2;
+                               if (ns >= *nanosec && ns < ns_lub) {
+                                       ns_lub = ns;
+                                       div1_lub = div1;
+                                       div2_lub = div2;
+                               }
+                       }
+               }
+       }
+
+       switch (round_mode) {
+       case TRIG_ROUND_NEAREST:
+       default:
+               ns_high = div1_lub * div2_lub * i8253_osc_base;
+               ns_low = div1_glb * div2_glb * i8253_osc_base;
+               if( ns_high - *nanosec < *nanosec - ns_low) {
+                       div1 = div1_lub;
+                       div2 = div2_lub;
+               } else {
+                       div1 = div1_glb;
+                       div2 = div2_glb;
+               }
+               break;
+       case TRIG_ROUND_UP:
+               div1 = div1_lub;
+               div2 = div2_lub;
+               break;
+       case TRIG_ROUND_DOWN:
+               div1 = div1_glb;
+               div2 = div2_glb;
+               break;
+       }
+
+       *nanosec = div1 * div2 * i8253_osc_base;
+       *d1 = div1;
+       *d2 = div2;
+       return;
+}
+#endif
+
+#ifdef ROGI
+int main(int argc,vhar *argv[])
+{
+       int osc_base = 1000;
+       int round_mode = TRIG_ROUND_NEAREST;
+       int i;
+       int div1_old, div2_old, ns_old, err_old;
+       int div1_new, div2_new, ns_new, err_new;
+       int div1_pow, div2_pow, ns_pow, err_pow;
+       int err = 0;
+
+       /* loop over desired nanosecond timings to test */
+       for(i = 10000; i < 100000; i++)
+       {
+               ns_old = ns_new = ns_pow = i;
+
+               i8253_cascade_ns_to_timer_2div(osc_base, &div1_old, &div2_old, &ns_old, round_mode);
+               err_old = ns_old - i;
+
+               i8253_cascade_ns_to_timer_power(osc_base, &div1_pow, &div2_pow, &ns_pow, round_mode);
+               err_pow = ns_pow - i;
+
+               cascade_new(osc_base, &div1_new, &div2_new, &ns_new, round_mode);
+               err_new = ns_new - i;
+
+               /* print results on this condition */
+               if(abs(err_new) > abs(err_pow))
+                       printf("nanosec %i\terr_new %i\tdiv1_new %i\tdiv2_new %i\n"
+                               "\t\terr_pow %i\tdiv1_pow %i\tdiv2_pow %i\n",
+                               i, err_new, div1_new, div2_new, err_pow, div1_pow, div2_pow);
+
+       /* consistency checks */
+               if(div1_old * div2_old * osc_base != ns_old) err = 1;
+               if(div1_pow * div2_pow * osc_base != ns_pow) err = 2;
+               if(div1_new * div2_new * osc_base != ns_new) err = 3;
+               if(err)
+               {
+                       printf("err %i\n", err);
+                       err=0;
+               }
+       }
+       return 0;
+}
+#endif
+
+int main(int argc,char *argv[])
+{
+       int osc_base = 1000;
+       unsigned int ns;
+       unsigned int div1,div2;
+       int i=0;
+
+       for(ns = 4*osc_base; ns<0x80000000;ns++){
+               i8253_cascade_ns_to_timer_2div
+                       (osc_base, &div1, &div2, &ns, TRIG_ROUND_UP);
+
+               i++;
+               if(!(i&0xff))
+                       printf("ns=%d div1=%d div2=%d\n",ns,div1,div2);
+               if(i==100000)exit(0);
+       }
+
+       return 0;
+}
+
diff --git a/patches/patch-bufconfig b/patches/patch-bufconfig
new file mode 100644 (file)
index 0000000..5c2b959
--- /dev/null
@@ -0,0 +1,182 @@
+diff -ur comedi-0.7.53/comedi/comedi_fops.c comedi-0.7.53-patched/comedi/comedi_fops.c
+--- comedi-0.7.53/comedi/comedi_fops.c Fri Dec  1 13:06:29 2000
++++ comedi-0.7.53-patched/comedi/comedi_fops.c Sun Jan  7 21:30:20 2001
+@@ -60,9 +60,12 @@
+ static int do_cancel_ioctl(comedi_device *dev,unsigned int arg,void *file);
+ static int do_cmdtest_ioctl(comedi_device *dev,void *arg,void *file);
+ static int do_insnlist_ioctl(comedi_device *dev,void *arg,void *file);
++static int do_bufconfig_ioctl(comedi_device *dev,void *arg);
+
+ static void do_become_nonbusy(comedi_device *dev,comedi_subdevice *s);
+
++void* resize_buf(comedi_device *dev,comedi_subdevice *s);
++
+ static int comedi_ioctl(struct inode * inode,struct file * file,unsigned int cmd,unsigned long arg)
+ {
+       kdev_t minor=MINOR(inode->i_rdev);
+@@ -96,11 +99,43 @@
+               return do_cmdtest_ioctl(dev,(void *)arg,file);
+       case COMEDI_INSNLIST:
+               return do_insnlist_ioctl(dev,(void *)arg,file);
++      case COMEDI_BUFCONFIG:
++              return do_bufconfig_ioctl(dev,(void*)arg);
+       default:
+               return -EIO;
+       }
+ }
+
++/*
++      COMEDI_BUFCONFIG
++      buffer configuration ioctl
++
++      arg:
++              pointer to bufconfig structure
++
++      reads:
++              bufconfig at arg
++
++      writes:
++              modified bufconfig at arg
++*/
++static int do_bufconfig_ioctl(comedi_device *dev,void *arg)
++{
++      comedi_bufconfig bc;
++
++      if(!suser())
++              return -EPERM;
++
++      if(copy_from_user(&bc,arg,sizeof(comedi_bufconfig)))
++              return -EFAULT;
++
++      dev->subdev_bufsz = bc.size;
++
++      if(copy_to_user(arg,&bc,sizeof(comedi_bufconfig)))
++              return -EFAULT;
++
++      return 0;
++}
+
+ /*
+       COMEDI_DEVCONFIG
+@@ -529,6 +564,8 @@
+               goto cleanup;
+       }
+
++      /* make sure preallocated buffer is the correct size */
++      resize_buf(dev, s);
+       if(!s->prealloc_buf){
+               printk("comedi: bug: s->prealloc_buf=NULL\n");
+       }
+@@ -818,12 +855,15 @@
+               goto cleanup;
+       }
+
+-      if(!s->prealloc_bufsz){
++      /* make sure preallocated buffer is the correct size */
++      resize_buf(dev, s);
++      if(!s->prealloc_buf){
+               ret=-ENOMEM;
+               DPRINTK("no buffer (?)\n");
+               goto cleanup;
+       }
+       s->cmd.data_len=s->prealloc_bufsz;
++      s->cmd.data=s->prealloc_buf;
+
+ #ifdef CONFIG_COMEDI_MODE_CORE
+       s->cur_trig.data=s->prealloc_buf;       /* XXX */
+@@ -1102,6 +1143,28 @@
+       do_become_nonbusy(dev,s);
+
+       return ret;
++}
++
++/* utility function that resizes the prealloc_buf for
++ * a subdevice according to the value of dev->subdev_bufsz
++ * Frank Mori Hess 2001-01-07
++ */
++void* resize_buf(comedi_device *dev, comedi_subdevice *s)
++{
++      unsigned int size;
++
++      // make sure buffer is an integral number of pages (we round up)
++      size = ((dev->subdev_bufsz + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
++
++      if(s->prealloc_buf && s->prealloc_bufsz)
++      {
++              if(s->prealloc_bufsz == size)
++                      return s->prealloc_buf;
++              else
++                      rvfree(s->prealloc_buf, s->prealloc_bufsz);
++      }
++      s->prealloc_bufsz = size;
++      return s->prealloc_buf = rvmalloc(s->prealloc_bufsz);
+ }
+
+ #ifdef LINUX_V22
+Only in comedi-0.7.53-patched/comedi: comedi_fops.c.orig
+diff -ur comedi-0.7.53/comedi/drivers.c comedi-0.7.53-patched/comedi/drivers.c
+--- comedi-0.7.53/comedi/drivers.c     Tue Nov  7 15:48:16 2000
++++ comedi-0.7.53-patched/comedi/drivers.c     Sun Jan  7 21:30:20 2001
+@@ -201,6 +201,10 @@
+       int have_trig;
+       comedi_subdevice *s;
+
++      // set the default buffer size if appropriate
++      if(dev->subdev_bufsz == 0)
++              dev->subdev_bufsz = PAGE_SIZE * 32;
++
+       for(i=0;i<dev->n_subdevices;i++){
+               s=dev->subdevices+i;
+
+@@ -221,7 +225,7 @@
+                       s->trig[4]=command_trig;
+               }
+               if(s->do_cmd || have_trig){
+-                      s->prealloc_bufsz=1024*128;
++                      s->prealloc_bufsz=dev->subdev_bufsz;
+               }else{
+                       s->prealloc_bufsz=0;
+               }
+diff -ur comedi-0.7.53/include/linux/comedi.h comedi-0.7.53-patched/include/linux/comedi.h
+--- comedi-0.7.53/include/linux/comedi.h       Tue Nov  7 14:47:37 2000
++++ comedi-0.7.53-patched/include/linux/comedi.h       Sun Jan  7 21:30:20 2001
+@@ -170,6 +170,7 @@
+ #define COMEDI_CMDTEST _IOR(CIO,10,comedi_cmd)
+ #define COMEDI_INSNLIST _IOR(CIO,11,comedi_insnlist)
+ #define COMEDI_INSN _IOR(CIO,12,comedi_insn)
++#define COMEDI_BUFCONFIG _IOR(CIO,13,comedi_bufconfig)
+
+
+
+@@ -185,6 +186,7 @@
+ typedef struct comedi_devconfig_struct comedi_devconfig;
+ typedef struct comedi_rangeinfo_struct comedi_rangeinfo;
+ typedef struct comedi_krange_struct comedi_krange;
++typedef struct comedi_bufconfig_struct comedi_bufconfig;
+
+ struct comedi_trig_struct{
+       unsigned int subdev;            /* subdevice */
+@@ -283,6 +285,11 @@
+ struct comedi_devconfig_struct{
+       char board_name[COMEDI_NAMELEN];
+       int options[COMEDI_NDEVCONFOPTS];
++};
++
++struct comedi_bufconfig_struct{
++      unsigned int size;              /* buffer size in bytes */
++      int unused[5];
+ };
+
+
+diff -ur comedi-0.7.53/include/linux/comedidev.h comedi-0.7.53-patched/include/linux/comedidev.h
+--- comedi-0.7.53/include/linux/comedidev.h    Fri Nov 24 18:10:34 2000
++++ comedi-0.7.53-patched/include/linux/comedidev.h    Sun Jan  7 21:30:20 2001
+@@ -148,6 +148,8 @@
+       int n_subdevices;
+       comedi_subdevice *subdevices;
+       int options[COMEDI_NDEVCONFOPTS];
++      // size in bytes subdevices should use for prealloc_buf
++      unsigned int subdev_bufsz;
+
+       /* dumb */
+       int iobase;
diff --git a/patches/patch-pcmad b/patches/patch-pcmad
new file mode 100644 (file)
index 0000000..119ef46
--- /dev/null
@@ -0,0 +1,37 @@
+? patch
+? comedi/drivers/patch
+? comedi/drivers/pcmad.c
+? comedi/drivers/diff_ni-E.c
+? include/comedi
+? include/modbuild
+Index: comedi/Config.in
+===================================================================
+RCS file: /d/ds/cvsroot/comedi/comedi/Config.in,v
+retrieving revision 1.20
+diff -u -r1.20 Config.in
+--- comedi/Config.in   2000/08/09 20:44:20     1.20
++++ comedi/Config.in   2000/09/03 01:54:35
+@@ -87,6 +87,7 @@
+ if [ "$CONFIG_PCI" = "y" ];then
+       dep_tristate 'IOtech DaqBoard/2000' CONFIG_COMEDI_DAQBOARD2000 $CONFIG_COMEDI
+ fi
++dep_tristate 'Winsystems PCM-A/D' CONFIG_COMEDI_PCMAD $CONFIG_COMEDI
+ dep_tristate 'Skeleton driver' CONFIG_COMEDI_SKEL $CONFIG_COMEDI
+ if [ "$CONFIG_COMEDI_RT" = "y" ];then
+Index: comedi/drivers/Makefile
+===================================================================
+RCS file: /d/ds/cvsroot/comedi/comedi/drivers/Makefile,v
+retrieving revision 1.14
+diff -u -r1.14 Makefile
+--- comedi/drivers/Makefile    2000/07/24 19:43:29     1.14
++++ comedi/drivers/Makefile    2000/09/03 01:54:36
+@@ -39,6 +39,8 @@
+ obj-$(CONFIG_COMEDI_II_PCI20KC)               += ii_pci20kc.o
++obj-$(CONFIG_COMEDI_PCMAD)            += pcmad.o
++
+ obj-$(CONFIG_COMEDI_MULTIQ3)          += multiq3.o
+ obj-$(CONFIG_COMEDI_NI_ATMIO)         += ni_atmio.o
diff --git a/patches/patch-scxi b/patches/patch-scxi
new file mode 100644 (file)
index 0000000..4a6785d
--- /dev/null
@@ -0,0 +1,314 @@
+Index: comedi/drivers/ni_mio_common.c
+===================================================================
+RCS file: /var/cvs/comedi/comedi/drivers/ni_mio_common.c,v
+retrieving revision 1.43
+diff -u -r1.43 ni_mio_common.c
+--- comedi/drivers/ni_mio_common.c     2001/02/05 02:58:40     1.43
++++ comedi/drivers/ni_mio_common.c     2001/02/05 02:59:48
+@@ -161,6 +161,11 @@
+ static int ni_dio(comedi_device *dev,comedi_subdevice *s,comedi_trig *it);
+ #endif
++static int ni_serial_insn_config(comedi_device *dev,comedi_subdevice *s,
++                               comedi_insn *insn,lsampl_t *data);
++static int ni_serial_insn_bits(comedi_device *dev,comedi_subdevice *s,
++                             comedi_insn *insn,lsampl_t *data);
++
+ #ifdef USE_TRIG
+ static int ni_eeprom(comedi_device *dev,comedi_subdevice *s,comedi_trig *it);
+ #endif
+@@ -203,6 +208,11 @@
+ #define AIMODE_SCAN           2
+ #define AIMODE_SAMPLE         3
++/* supported serial clock intervals */
++#define SERIAL_DISABLED         0
++#define SERIAL_600NS          600
++#define SERIAL_1_2US         1200
++#define SERIAL_10US         10000
+ static void ni_E_interrupt(int irq,void *d,struct pt_regs * regs)
+ {
+@@ -1991,6 +2001,203 @@
+       return 2;
+ }
++static int ni_serial_insn_config(comedi_device *dev,comedi_subdevice *s,
++                               comedi_insn *insn,lsampl_t *data)
++{
++#ifdef DEBUG_DIO
++      printk("SPI serial I/O Config %d\n", data[0]);
++#endif
++
++      if(insn->n!=1)return -EINVAL;
++      devpriv->serial_interval_ns = data[0];
++      devpriv->serial_hw_mode = 1;
++      devpriv->dio_control |= DIO_HW_Serial_Enable;
++      switch(data[0]) {
++      default:
++      case SERIAL_DISABLED:
++              /* Disable (or use software serial) */
++              devpriv->serial_hw_mode = 0;
++              devpriv->dio_control &= ~(DIO_HW_Serial_Enable |
++                                        DIO_Software_Serial_Control);
++              break;
++      case SERIAL_600NS:
++              /* Warning: this clock speed is too fast to reliably
++                 control SCXI. */
++              devpriv->dio_control &= ~DIO_HW_Serial_Timebase;
++              devpriv->clock_and_fout |= Slow_Internal_Timebase;
++              devpriv->clock_and_fout &= ~DIO_Serial_Out_Divide_By_2;
++              break;
++      case SERIAL_1_2US:
++              devpriv->dio_control &= ~DIO_HW_Serial_Timebase;
++              devpriv->clock_and_fout |= Slow_Internal_Timebase |
++                      DIO_Serial_Out_Divide_By_2;
++              break;
++      case SERIAL_10US:
++              devpriv->dio_control |= DIO_HW_Serial_Timebase;
++              devpriv->clock_and_fout |= Slow_Internal_Timebase |
++                      DIO_Serial_Out_Divide_By_2;
++              /* Note: DIO_Serial_Out_Divide_By_2 only affects
++                 600ns/1.2us. If you turn divide_by_2 off with the
++                 slow clock, you will still get 10us, except then
++                 all your delays are wrong. */
++              break;
++      }
++      win_out(devpriv->dio_control,DIO_Control_Register);
++      win_out(devpriv->clock_and_fout,Clock_and_FOUT_Register);
++      return 1;
++}
++
++static int ni_serial_hw_readwrite8(comedi_device *dev,comedi_subdevice *s,
++                                 unsigned char data_out, 
++                                 unsigned char *data_in)
++{
++      unsigned int status1;
++      int err = 0, count = 20;
++
++#ifdef DEBUG_DIO
++      printk("ni_serial_hw_readwrite8: outputting 0x%x\n", data_out);
++#endif
++
++      if(devpriv->serial_interval_ns == 0) {
++              err = -EINVAL;
++              goto Error;
++      }
++
++      devpriv->dio_output &= ~DIO_Serial_Data_Mask;
++      devpriv->dio_output |= DIO_Serial_Data_Out(data_out);
++      win_out(devpriv->dio_output,DIO_Output_Register);
++
++      status1 = win_in(Joint_Status_1_Register);
++      if(status1 & DIO_Serial_IO_In_Progress_St) {
++              err = -EBUSY;
++              goto Error;
++      }
++
++      devpriv->dio_control |= DIO_HW_Serial_Start;
++      win_out(devpriv->dio_control,DIO_Control_Register);
++      devpriv->dio_control &= ~DIO_HW_Serial_Start;
++      
++      /* Wait until STC says we're done, but don't loop infinitely. Also,
++         we don't have to keep updating the window address for this. */
++      ni_writew(Joint_Status_1_Register,Window_Address);
++      while((status1 = ni_readw(Window_Data)) & DIO_Serial_IO_In_Progress_St) {
++              /* Delay one bit per loop */
++              nanodelay(devpriv->serial_interval_ns);
++              if(--count < 0) {
++                      printk("ni_serial_hw_readwrite8: SPI serial I/O didn't finish in time!\n");
++                      err = -ETIME;
++                      goto Error;
++              }
++      }
++
++      /* Delay for last bit. This delay is absolutely necessary, because
++         DIO_Serial_IO_In_Progress_St goes high one bit too early. */
++      nanodelay(devpriv->serial_interval_ns);
++
++      if(data_in != NULL) {
++              *data_in = win_in(DIO_Serial_Input_Register);
++#ifdef DEBUG_DIO
++              printk("ni_serial_hw_readwrite8: inputted 0x%x\n", *data_in);
++#endif
++      }
++      
++ Error:
++      win_out(devpriv->dio_control,DIO_Control_Register);
++      
++      return err;
++}
++
++static int ni_serial_sw_readwrite8(comedi_device *dev,comedi_subdevice *s,
++                                 unsigned char data_out, 
++                                 unsigned char *data_in)
++{
++      unsigned char mask, input = 0;
++
++#ifdef DEBUG_DIO
++      printk("ni_serial_sw_readwrite8: outputting 0x%x\n", data_out);
++#endif
++
++      /* Wait for one bit before transfer */
++      nanodelay(devpriv->serial_interval_ns);
++
++      for(mask = 0x80; mask; mask >>= 1) {
++              /* Output current bit; note that we cannot touch s->state
++                 because it is a per-subdevice field, and serial is
++                 a separate subdevice from DIO. */
++              devpriv->dio_output &= ~DIO_SDOUT;
++              if(data_out & mask) {
++                      devpriv->dio_output |= DIO_SDOUT;
++              }
++              win_out(devpriv->dio_output,DIO_Output_Register);
++
++              /* Assert SDCLK (active low, inverted), wait for half of
++                 the delay, deassert SDCLK, and wait for the other half. */
++              devpriv->dio_control |= DIO_Software_Serial_Control;
++              win_out(devpriv->dio_control,DIO_Control_Register);
++
++              nanodelay(devpriv->serial_interval_ns / 2);
++
++              devpriv->dio_control &= ~DIO_Software_Serial_Control;
++              win_out(devpriv->dio_control,DIO_Control_Register);
++
++              nanodelay(devpriv->serial_interval_ns / 2);
++
++              /* Input current bit */
++              if(ni_readw(DIO_Parallel_Input) & DIO_SDIN) {
++                      input |= mask;
++              }
++      }
++#ifdef DEBUG_DIO
++      printk("ni_serial_sw_readwrite8: inputted 0x%x\n", input);
++#endif
++      if(data_in) *data_in = input;
++
++      return 0;
++}
++
++static int ni_serial_insn_bits(comedi_device *dev,comedi_subdevice *s,
++                             comedi_insn *insn,lsampl_t *data)
++{
++      int err = insn->n;
++      lsampl_t data_out, data_in, num_bits;
++      unsigned char byteOut, byteIn;
++
++#ifdef DEBUG_DIO
++      printk("ni_serial_insn_bits: num_bits=0x%x data_out=0x%x\n", data[0],
++             data[1]);
++#endif
++
++      if(insn->n!=2) return -EINVAL;
++
++      num_bits = data[0];
++
++      if((num_bits % 8) != 0) return -EINVAL;
++
++      data_out = data[1];
++      data_in = 0;
++      while(num_bits > 0) {
++              /* Read from MSB to LSB */
++              data_in <<= 8;
++
++              byteOut = (data_out >> (num_bits - 8)) & 0xff;
++              if(devpriv->serial_hw_mode) {
++                      err = ni_serial_hw_readwrite8(dev,s,byteOut,&byteIn);
++              } else if(devpriv->serial_interval_ns > 0) {
++                      err = ni_serial_sw_readwrite8(dev,s,byteOut,&byteIn);
++              } else {
++                      printk("ni_serial_insn_bits: serial disabled!\n");
++                      return -EINVAL;
++              }
++              if(err < 0) return err;
++              data_in |= byteIn;
++
++              /* Write from MSB to LSB */
++              num_bits -= 8;
++      }
++      data[1] = data_in;
++      return insn->n;
++}
++
+ /*
+       HACK! 
+@@ -2031,7 +2238,7 @@
+ {
+       comedi_subdevice *s;
+       
+-      dev->n_subdevices=7;
++      dev->n_subdevices=8;
+       
+       if(alloc_subdevices(dev)<0)
+               return -ENOMEM;
+@@ -2144,11 +2351,24 @@
+ #ifdef USE_TRIG
+       s->trig[0]=ni_eeprom;
+ #endif
+-      
++
++      /* SPI serial I/O */
++      s=dev->subdevices+7;
++      s->type=COMEDI_SUBD_SERIAL;
++      s->subdev_flags=SDF_READABLE|SDF_WRITEABLE|SDF_INTERNAL;
++      s->n_chan=1;
++      s->maxdata=0xff;
++      s->insn_bits=ni_serial_insn_bits;
++      s->insn_config=ni_serial_insn_config;
++
++      /* serial configuration */
++      devpriv->serial_interval_ns = 0;
++      devpriv->serial_hw_mode = 0;
++
+       /* ai configuration */
+       ni_ai_reset(dev,dev->subdevices+0);
+-      win_out(0x1ba0,Clock_and_FOUT_Register);
+-
++      devpriv->clock_and_fout = 0x1ba0;
++      win_out(devpriv->clock_and_fout,Clock_and_FOUT_Register);
+       /* analog output configuration */
+       
+Index: include/linux/comedi.h
+===================================================================
+RCS file: /var/cvs/comedi/include/linux/comedi.h,v
+retrieving revision 1.5
+diff -u -r1.5 comedi.h
+--- include/linux/comedi.h     2001/01/30 20:19:39     1.5
++++ include/linux/comedi.h     2001/02/05 02:59:50
+@@ -148,7 +148,7 @@
+ #define COMEDI_SUBD_MEMORY              8     /* memory, EEPROM, DPRAM */
+ #define COMEDI_SUBD_CALIB               9     /* calibration DACs */
+ #define COMEDI_SUBD_PROC                10    /* processor, DSP */
+-
++#define COMEDI_SUBD_SERIAL              11      /* SPI serial I/O */
+ #define COMEDI_INPUT                  0
+ #define COMEDI_OUTPUT                 1
+Index: include/linux/comedidev.h
+===================================================================
+RCS file: /var/cvs/comedi/include/linux/comedidev.h,v
+retrieving revision 1.8
+diff -u -r1.8 comedidev.h
+--- include/linux/comedidev.h  2001/02/05 02:09:19     1.8
++++ include/linux/comedidev.h  2001/02/05 02:59:51
+@@ -276,6 +276,18 @@
+       return 0;
+ }
++static inline int nanodelay(unsigned long ns)
++{
++      /* We round up, so the result should always be longer than the
++       * specified time. It's probably not much more precise than
++       * using udelay(). Hopefully, one day Linux will have an
++       * nanodelay() function. */
++      unsigned long loops_per_us = (loops_per_sec + 999999) / 1000000;
++      unsigned long loops = ((ns * loops_per_us) + 999) / 1000; 
++      /* printk("nanodelay: ns=%ld loops=%ld\n", ns, loops); */
++      __delay(loops);
++}
++
+ #ifdef LINUX_V20
+ extern struct symbol_table comedi_syms;
diff --git a/patches/pcmad.c b/patches/pcmad.c
new file mode 100644 (file)
index 0000000..21cd6ba
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+    module/pcmad
+    hardware driver for Winsystems PCM-A/D12 and PCM-A/D16
+
+    COMEDI - Linux Control and Measurement Device Interface
+    Copyright (C) 2000 David A. Schleef <ds@stm.lbl.gov>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/timer.h>
+#include <asm/io.h>
+#include <comedi_module.h>
+
+
+#define PCMAD_SIZE             4
+
+#define PCMAD_STATUS           0
+#define PCMAD_LSB              1
+#define PCMAD_MSB              2
+#define PCMAD_CONVERT          1
+
+static int pcmad_attach(comedi_device *dev,comedi_devconfig *it);
+static int pcmad_detach(comedi_device *dev);
+static int pcmad_recognize(char *name);
+comedi_driver driver_pcmad={
+       driver_name:    "pcmad",
+       module:         THIS_MODULE,
+       attach:         pcmad_attach,
+       detach:         pcmad_detach,
+       recognize:      pcmad_recognize,
+};
+
+struct pcmad_board_struct{
+       char *name;
+       int n_ai_bits;
+};
+struct pcmad_board_struct pcmad_boards[]={
+       {
+       name:           "pcmad12",
+       n_ai_bits:      12,
+       },
+       {
+       name:           "pcmad16",
+       n_ai_bits:      16,
+       },
+};
+#define this_board ((struct pcmad_board_struct *)(dev->board_ptr))
+static int n_pcmad_boards=(sizeof(pcmad_boards)/sizeof(pcmad_boards[0]));
+
+struct pcmad_priv_struct{
+       int differential;
+       int twos_comp;
+};
+#define devpriv ((struct pcmad_priv_struct *)dev->private)
+
+
+#define TIMEOUT        100
+
+static int pcmad_ai_mode0(comedi_device *dev,comedi_subdevice *s,comedi_trig *it)
+{
+       int i,msb,lsb;
+       int chan;
+       int data;
+
+       chan=CR_CHAN(it->chanlist[0]);
+
+       outb(chan,dev->iobase+PCMAD_CONVERT);
+
+       for(i=0;i<TIMEOUT;i++){
+               if((inb(dev->iobase+PCMAD_STATUS)&0x3) == 0x3)
+                       break;
+       }
+       lsb=inb(dev->iobase+PCMAD_LSB);
+       msb=inb(dev->iobase+PCMAD_MSB);
+
+       data=(msb<<8)|(lsb);
+
+       if(devpriv->twos_comp){
+               data ^= (1<<(this_board->n_ai_bits-1));
+       }
+       it->data[0]=data;
+       
+       return 1;
+}
+
+static int pcmad_recognize(char *name)
+{
+       int i;
+
+       for(i=0;i<n_pcmad_boards;i++){
+               if(!strcmp(pcmad_boards[i].name,name))
+                       return i;
+       }
+
+       return -1;
+}
+
+/*
+ * options:
+ * 0   i/o base
+ * 1   unused
+ * 2   0=single ended 1=differential
+ * 3   0=straight binary 1=two's comp
+ */
+static int pcmad_attach(comedi_device *dev,comedi_devconfig *it)
+{
+       int ret;
+       comedi_subdevice *s;
+
+       dev->iobase=it->options[0];
+       printk("comedi%d: pcmad: 0x%04x ",dev->minor,dev->iobase);
+       if(check_region(dev->iobase,PCMAD_SIZE)<0){
+               printk("I/O port conflict\n");
+               return -EIO;
+       }
+       request_region(dev->iobase,PCMAD_SIZE,"pcmad");
+       dev->iobase=dev->iobase;
+       dev->iosize=PCMAD_SIZE;
+
+       dev->n_subdevices=1;
+       if((ret=alloc_subdevices(dev))<0)
+               return ret;
+       if((ret=alloc_private(dev,sizeof(struct pcmad_priv_struct)))<0)
+               return ret;
+
+       dev->board_ptr = pcmad_boards+dev->board;
+
+       s=dev->subdevices+0;
+       s->type=COMEDI_SUBD_AI;
+       s->subdev_flags=SDF_READABLE;
+       s->n_chan=16;                   /* XXX */
+       s->len_chanlist=1;
+       s->trig[0]=pcmad_ai_mode0;
+       s->maxdata=(1<<this_board->n_ai_bits)-1;
+       s->range_table=&range_unknown;
+
+       return 0;
+}
+
+
+static int pcmad_detach(comedi_device *dev)
+{
+       printk("comedi%d: pcmad: remove\n",dev->minor);
+       
+       if(dev->irq){
+               free_irq(dev->irq,dev);
+       }
+       release_region(dev->iobase,dev->iosize);
+
+       return 0;
+}
+
+
+COMEDI_INITCLEANUP(driver_pcmad);
+