From: David Schleef Date: Mon, 5 Feb 2001 03:06:22 +0000 (+0000) Subject: random cruft that needs to be merged, or not X-Git-Tag: r0_7_56~2 X-Git-Url: http://git.tremily.us/gitweb.cgi?a=commitdiff_plain;h=f6e8e4fe7414bc5535f0c558ff0e509733878c65;p=comedi.git random cruft that needs to be merged, or not --- diff --git a/patches/cascade-test.c b/patches/cascade-test.c new file mode 100644 index 00000000..9850808b --- /dev/null +++ b/patches/cascade-test.c @@ -0,0 +1,144 @@ +#include +#include +#include +#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 index 00000000..5c2b959d --- /dev/null +++ b/patches/patch-bufconfig @@ -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;in_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 index 00000000..119ef460 --- /dev/null +++ b/patches/patch-pcmad @@ -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 index 00000000..4a6785d1 --- /dev/null +++ b/patches/patch-scxi @@ -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 index 00000000..21cd6ba5 --- /dev/null +++ b/patches/pcmad.c @@ -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 + + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#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;iiobase+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;iiobase=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<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); +