From 618a49b523432cd0080e2ccfb1987109173928a0 Mon Sep 17 00:00:00 2001 From: David Schleef Date: Tue, 3 Apr 2001 09:30:57 +0000 Subject: [PATCH] Patch from Michal Dobes --- Documentation/comedi/drivers.txt | 21 ++ Documentation/comedi/hardware | 6 + comedi/Config.in | 1 + comedi/drivers/Makefile | 1 + comedi/drivers/adl_pci9118.c | 447 +++++++++++++++++++------------ comedi/drivers/amcc_s5933.h | 134 +++++---- scripts/Configure.help | 12 +- 7 files changed, 400 insertions(+), 222 deletions(-) diff --git a/Documentation/comedi/drivers.txt b/Documentation/comedi/drivers.txt index c652dece..c1add29b 100644 --- a/Documentation/comedi/drivers.txt +++ b/Documentation/comedi/drivers.txt @@ -30,12 +30,33 @@ Status works This driver supports AI, AO, DI and DO subdevices. AI subdevice support cmd, insn and mode0-4 interface, other subdevices support insn and mode0 interface. +See the head of the source file adv_pci1710.c for configuration options. For AI: - If cmd->scan_begin_src=TRIG_EXT (or trigger mode4) then trigger input is TGIN (pin 46). - If cmd->convert_src=TRIG_EXT (or trigger mode3) then trigger input is EXTTRG (pin 44). +- If cmd->start_src/stop_src=TRIG_EXT then trigger input is TGIN (pin 46). +- It is not neccessary to have cmd.scan_end_arg=cmd.chanlist_len but + cmd.scan_end_arg modulo cmd.chanlist_len must by 0. +- If return value of cmdtest is 5 then you've bad channel list + (it isn't possible mixture S.E. and DIFF inputs or bipolar and unipolar + ranges). +There is know problem with this driver: +- If you use trigger mode4 (scan_begin_src=TRIG_EXT&convert_src=TRIG_TIMER) + then this mode sometimes discards some samples. :-(( + + +Driver: adv_pci1710.o +Description: Advantech PCI-1710, PCI-1710HG, PCI-1711, PCI-1713, + Advantech PCI-1720, PCI-1731 +Author: Michal Dobes +Status: works +This driver supports AI, AO, DI and DO subdevices. +AI subdevice supports cmd, insn, mode0, mode1 and mode3 interface, +other subdevices support insn and mode0 interface. +See the head of the source file adv_pci1710.c for configuration options. Driver: cb_pcidas.o diff --git a/Documentation/comedi/hardware b/Documentation/comedi/hardware index e9fe19d9..8ba47d68 100644 --- a/Documentation/comedi/hardware +++ b/Documentation/comedi/hardware @@ -9,6 +9,12 @@ ADLink PCI-9118DG adl_pci9118 ADLink PCI-9118HG adl_pci9118 ADLink PCI-9118HR adl_pci9118 ADLink PET-48DIO pcl724 +Advantech PCI-1710 adv_pci1710 +Advantech PCI-1710HG adv_pci1710 +Advantech PCI-1711 adv_pci1710 +Advantech PCI-1713 adv_pci1710 +Advantech PCI-1720 adv_pci1710 +Advantech PCI-1731 adv_pci1710 Advantech PCL-711 pcl711 Advantech PCL-711B pcl711 Advantech PCL-718 pcl818 diff --git a/comedi/Config.in b/comedi/Config.in index 86c1ee4b..28f09045 100644 --- a/comedi/Config.in +++ b/comedi/Config.in @@ -82,6 +82,7 @@ dep_tristate 'Generic 8255 support' CONFIG_COMEDI_8255 $CONFIG_COMEDI dep_tristate 'Quanser Consulting MultiQ-3' CONFIG_COMEDI_MULTIQ3 $CONFIG_COMEDI dep_tristate 'Generic parallel port support' CONFIG_COMEDI_PARPORT $CONFIG_COMEDI dep_tristate 'ADLink PCI-9118DG/HR/HG' CONFIG_COMEDI_ADL_PCI9118 $CONFIG_COMEDI +dep_tristate 'Advantech PCI-1710/HG/11/13/20/31' CONFIG_COMEDI_ADV_PCI1710 $CONFIG_COMEDI dep_tristate 'PCL-711, PCL-711b, ACL-8112, and compatibles' CONFIG_COMEDI_PCL711 $CONFIG_COMEDI dep_tristate 'PCL-722/724/731, ACL-7122/7124, PET-48DIO' CONFIG_COMEDI_PCL724 $CONFIG_COMEDI dep_tristate 'PCL-725' CONFIG_COMEDI_PCL725 $CONFIG_COMEDI diff --git a/comedi/drivers/Makefile b/comedi/drivers/Makefile index b68ceed8..cbc34cc2 100644 --- a/comedi/drivers/Makefile +++ b/comedi/drivers/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_COMEDI_8255) += 8255.o obj-$(CONFIG_COMEDI_MPC8260CPM) += mpc8260cpm.o obj-$(CONFIG_COMEDI_ADL_PCI9118) += adl_pci9118.o +obj-$(CONFIG_COMEDI_ADV_PCI1710) += adv_pci1710.o obj-$(CONFIG_COMEDI_CB_PCIDAS) += cb_pcidas.o diff --git a/comedi/drivers/adl_pci9118.c b/comedi/drivers/adl_pci9118.c index 6ff3a128..4123d8c9 100644 --- a/comedi/drivers/adl_pci9118.c +++ b/comedi/drivers/adl_pci9118.c @@ -1,5 +1,5 @@ /* - * module/adl_pci9118.c + * comedi/drivers/adl_pci9118.c * * hardware driver for ADLink cards: * card: PCI-9118DG, PCI-9118HG, PCI-9118HR @@ -8,7 +8,8 @@ * Author: Michal Dobes * * Options: - * [0] - PCI bus number - if bus number and slot number are 0, then driver search for first unused card + * [0] - PCI bus number - if bus number and slot number are 0, + * then driver search for first unused card * [1] - PCI slot number * [2] - A/D channels - card have 16 channels, but supports external multiplexor, * you can select from 1 to 256 channels (0=16 SE/8 DIFF channels) @@ -95,6 +96,9 @@ #define Int_Hfull 0x02 /* A/D FIFO hlaf full */ #define Int_DTrg 0x01 /* external digital trigger */ +#define START_AI_EXT 0x01 /* start measure on external trigger */ +#define STOP_AI_EXT 0x02 /* stop measure on external trigger */ + comedi_lrange range_pci9118dg_hr={ 8, { BIP_RANGE(5), BIP_RANGE(2.5), @@ -124,6 +128,8 @@ comedi_lrange range_pci9118hg={ 8, { static int pci9118_attach(comedi_device *dev,comedi_devconfig *it); static int pci9118_detach(comedi_device *dev); +static unsigned short pci_list_builded=0; /*=1 list of card is know */ + typedef struct { char *name; // driver name int vendor_id; // PCI vendor a device ID of card @@ -141,6 +147,7 @@ typedef struct { comedi_lrange *rangelist_ao; // rangelist for D/A unsigned int ai_ns_min; // max sample speed of card v ns unsigned int ai_pacer_min; // minimal pacer value (c1*c2 or c1 in burst) + } boardtype; static boardtype boardtypes[] = @@ -149,12 +156,12 @@ static boardtype boardtypes[] = AMCC_OP_REG_SIZE, IORANGE_9118, 16, 8, 256, PCI9118_CHANLEN, 2, 0x0fff, 0x0fff, &range_pci9118dg_hr, &range_bipolar10, - 3030, 12 }, + 3000, 12 }, {"pci9118hg", PCI_VENDOR_ID_AMCC, 0x80d9, AMCC_OP_REG_SIZE, IORANGE_9118, 16, 8, 256, PCI9118_CHANLEN, 2, 0x0fff, 0x0fff, &range_pci9118hg, &range_bipolar10, - 3030, 12 }, + 3000, 12 }, {"pci9118hr", PCI_VENDOR_ID_AMCC, 0x80d9, AMCC_OP_REG_SIZE, IORANGE_9118, 16, 8, 256, PCI9118_CHANLEN, 2, 0xffff, 0x0fff, @@ -176,8 +183,7 @@ comedi_driver driver_pci9118={ typedef struct{ int iobase_a; // base+size for AMCC chip - int iosize_a; - struct amcc_struct *amcc; // ptr too AMCC data + struct pcilst_struct *amcc; // ptr too AMCC data unsigned int master; // master capable unsigned char allocated; // we have blocked card unsigned int usemux; // we want to use external multiplexor! @@ -195,15 +201,18 @@ typedef struct{ unsigned int ai1234_act_scan;// how many scans we finished unsigned int ai1234_buf_ptr; // data buffer ptr in samples unsigned int ai1234_n_chan;// how many channels is measured + unsigned int ai1234_n_scanlen;// len of actual scanlist + unsigned int ai1234_act_scanpos; // position in actual scan unsigned int *ai1234_chanlist;// actaul chanlist unsigned int ai1234_timer1; unsigned int ai1234_timer2; unsigned int ai1234_flags; + char ai12_startstop; // measure can start/stop on external trigger + unsigned int ai1234_divisor1,ai1234_divisor2; // divisors for start of measure on external start unsigned int ai1234_data_len; sampl_t *ai1234_data; + sampl_t ao_data[2]; // data output buffer unsigned int ai1234_scans; // number of scans to do - unsigned int ai4_divisor1; // AI mode4 divisors - unsigned int ai4_divisor2; unsigned char ai4_status; // 0=wait for ext trg 1=sampling unsigned char ai4_cntrl0; // control register for status 0 and 1 unsigned char ai4_cntrl1; @@ -227,7 +236,7 @@ typedef struct{ ============================================================================== */ -int check_and_setup_channel_list(comedi_device * dev, comedi_subdevice * s, int n_chan, unsigned int *chanlist,char rot); +int check_and_setup_channel_list(comedi_device * dev, comedi_subdevice * s, int n_chan, unsigned int *chanlist,char rot, char check); void start_pacer(comedi_device * dev, int mode, unsigned int divisor1, unsigned int divisor2); static int pci9118_reset(comedi_device *dev); int pci9118_exttrg_add(comedi_device * dev, unsigned char source); @@ -253,7 +262,7 @@ static void interrupt_pci9118_ai_mode4_switch(void *d) //outw(0, dev->iobase+PCI9118_SOFTTRG); /* start 1. conversion */ devpriv->ai4_status++; // next int wi will have data! outl(devpriv->ai4_cntrl1, dev->iobase+PCI9118_ADCNTRL); - start_pacer(dev, 4, devpriv->ai4_divisor1, devpriv->ai4_divisor2); // start pacer + start_pacer(dev, 4, devpriv->ai1234_divisor1, devpriv->ai1234_divisor2); // start pacer } } @@ -262,13 +271,14 @@ static void interrupt_pci9118_ai_mode4_switch(void *d) */ static void move_block_from_dma_12bit(comedi_device *dev,comedi_subdevice *s,sampl_t *dma,sampl_t *data,int n) { - int i,j; + unsigned int i,j,m; j=s->async->cur_chan; + m=devpriv->ai1234_act_scanpos; for(i=0;ichanlist[j]) { // data dropout! - rt_printk("comedi: A/D DMA - data dropout: received channel %d, expected %d!\n",(*dma & 0x0f00)>>8,devpriv->chanlist[j]); + rt_printk("comedi: A/D DMA - data dropout: received channel %d, expected %d!\n",(*dma & 0x0f00)>>8,devpriv->chanlist[j]>>8); pci9118_ai_cancel(dev,s); comedi_error_done(dev,s); return; @@ -277,13 +287,18 @@ static void move_block_from_dma_12bit(comedi_device *dev,comedi_subdevice *s,sam *data=((*dma & 0xff)<<4)|((*dma & 0xf000)>>12); // get one sample data++; dma++; j++; - if(j>=devpriv->ai1234_n_chan){ + if(j>=devpriv->ai1234_n_chan) { + m+=j; j=0; - devpriv->ai1234_act_scan++; - if (devpriv->ai1234_flags & TRIG_WAKE_EOS) - comedi_eos(dev,s); + if(m>=devpriv->ai1234_n_scanlen) { + m=0; + devpriv->ai1234_act_scan++; + if (devpriv->ai1234_flags & TRIG_WAKE_EOS) + comedi_eos(dev,s); + } } } + devpriv->ai1234_act_scanpos=m; s->async->cur_chan=j; } @@ -292,20 +307,26 @@ static void move_block_from_dma_12bit(comedi_device *dev,comedi_subdevice *s,sam */ static void move_block_from_dma_16bit(comedi_device *dev,comedi_subdevice *s,sampl_t *dma,sampl_t *data,int n) { - int i,j; + int i,j,m; j=s->async->cur_chan; + m=devpriv->ai1234_act_scanpos; for(i=0;i>8); // get one sample data++; dma++; j++; - if(j>=devpriv->ai1234_n_chan){ + if(j>=devpriv->ai1234_n_chan) { + m+=j; j=0; - devpriv->ai1234_act_scan++; - if (devpriv->ai1234_flags & TRIG_WAKE_EOS) - comedi_eos(dev,s); + if(m>=devpriv->ai1234_n_scanlen) { + m=0; + devpriv->ai1234_act_scan++; + if (devpriv->ai1234_flags & TRIG_WAKE_EOS) + comedi_eos(dev,s); + } } } + devpriv->ai1234_act_scanpos=m; s->async->cur_chan=j; } @@ -323,7 +344,7 @@ static void interrupt_pci9118_ai_dma(int irq, void *d, struct pt_regs *regs) interrupt_pci9118_ai_mode4_switch(d); samplesinbuf=devpriv->dmabuf_use_size[devpriv->dma_actbuf]-inl(devpriv->iobase_a+AMCC_OP_REG_MWTC); // how many bytes is in DMA buffer? - + if (samplesinbufdmabuf_use_size[devpriv->dma_actbuf]) { comedi_error(dev,"Interrupted DMA transfer!"); } @@ -373,11 +394,16 @@ static void interrupt_pci9118_ai_dma(int irq, void *d, struct pt_regs *regs) comedi_eobuf(dev,s); } - if (this_board->ai_maxdata==0xfff) { move_block_from_dma_12bit(dev,s,(void *)ptr,((void *)(s->async->data))+s->async->buf_int_ptr,samplesinbuf); } - else { move_block_from_dma_16bit(dev,s,(void *)ptr,((void *)(s->async->data))+s->async->buf_int_ptr,samplesinbuf); } - s->async->buf_int_count+=samplesinbuf*sizeof(sampl_t); - s->async->buf_int_ptr+=samplesinbuf*sizeof(sampl_t); - + + if (samplesinbuf) { + if (this_board->ai_maxdata==0xfff) { move_block_from_dma_12bit(dev,s,(void *)ptr,((void *)(s->async->data))+s->async->buf_int_ptr,samplesinbuf); } + else { move_block_from_dma_16bit(dev,s,(void *)ptr,((void *)(s->async->data))+s->async->buf_int_ptr,samplesinbuf); } + s->async->buf_int_count+=samplesinbuf*sizeof(sampl_t); + s->async->buf_int_ptr+=samplesinbuf*sizeof(sampl_t); + if (!(devpriv->ai1234_flags & TRIG_WAKE_EOS)) { + comedi_bufcheck(dev,s); + } + } if (!devpriv->neverending_ai) if ( devpriv->ai1234_act_scan>=devpriv->ai1234_scans ) { /* all data sampled */ @@ -386,8 +412,6 @@ static void interrupt_pci9118_ai_dma(int irq, void *d, struct pt_regs *regs) return; } - if (!(devpriv->ai1234_flags & TRIG_WAKE_EOS)) - comedi_bufcheck(dev,s); if (devpriv->dma_doublebuf) { // switch dma buffers devpriv->dma_actbuf=1-devpriv->dma_actbuf; @@ -406,11 +430,8 @@ static void interrupt_pci9118(int irq, void *d, struct pt_regs *regs) unsigned int int_daq,int_amcc,int_adstat; int_daq=inl(dev->iobase+PCI9118_INTSRC) & 0xf; // get IRQ reasons - int_adstat=inw(dev->iobase+PCI9118_ADSTAT)&0x1ff; // get STATUS register int_amcc=inl(devpriv->iobase_a+AMCC_OP_REG_INTCSR); // get AMCC INT register - outl(int_amcc|0x00ff0000, devpriv->iobase_a+AMCC_OP_REG_INTCSR); // shutdown IRQ reasons in AMCC - #if 0 rt_printk("INT daq=0x%01x amcc=0x%08x MWAR=0x%08x MWTC=0x%08x ADSTAT=0x%02x\n", int_daq, int_amcc, inl(devpriv->iobase_a+AMCC_OP_REG_MWAR), inl(devpriv->iobase_a+AMCC_OP_REG_MWTC), @@ -418,9 +439,13 @@ static void interrupt_pci9118(int irq, void *d, struct pt_regs *regs) #endif if ((!int_daq)&&(!(int_amcc&ANY_S593X_INT))) { +#if 0 comedi_error(dev,"IRQ from unknow source"); +#endif return; } + outl(int_amcc|0x00ff0000, devpriv->iobase_a+AMCC_OP_REG_INTCSR); // shutdown IRQ reasons in AMCC + if (int_amcc&MASTER_ABORT_INT) comedi_error(dev,"AMCC IRQ - MASTER DMA ABORT!"); if (int_amcc&TARGET_ABORT_INT) @@ -428,10 +453,29 @@ static void interrupt_pci9118(int irq, void *d, struct pt_regs *regs) if (devpriv->ai_do) { + + int_adstat=inw(dev->iobase+PCI9118_ADSTAT)&0x1ff; // get STATUS register + + if ((int_adstat&AdStatus_DTH)&&(int_daq&Int_DTrg)&&(devpriv->ai12_startstop)) { // start stop of measure + if (devpriv->ai12_startstop&START_AI_EXT) { + devpriv->ai12_startstop&=~START_AI_EXT; + if (!(devpriv->ai12_startstop&STOP_AI_EXT)) + pci9118_exttrg_del(dev,0); // deactivate EXT trigger + start_pacer(dev, devpriv->ai_do, devpriv->ai1234_divisor1, devpriv->ai1234_divisor2); // start pacer + } else { + if (devpriv->ai12_startstop&STOP_AI_EXT) { + devpriv->ai12_startstop&=~STOP_AI_EXT; + pci9118_exttrg_del(dev,0); // deactivate EXT trigger + devpriv->neverending_ai=0; + } + } + } + if (int_amcc&WRITE_TC_INT) if (devpriv->master) { interrupt_pci9118_ai_dma(irq,d,regs); // do some data transfer } + if ((int_adstat&AdStatus_DTH)&&(int_daq&Int_DTrg)&&(int_amcc&IN_MB_INT)&&(devpriv->ai_do==4)) { interrupt_pci9118_ai_mode4_switch(d); // AI mode 4, scan begin EXT interrupt } @@ -442,7 +486,7 @@ static void interrupt_pci9118(int irq, void *d, struct pt_regs *regs) /* ============================================================================== */ -static int pci9118_ai_docmd_and_mode(int mode, comedi_device * dev, comedi_subdevice * s) +static int pci9118_ai_docmd_and_mode(int mode, comedi_device * dev, comedi_subdevice * s, char startstop) { unsigned int divisor1, divisor2; unsigned int dmalen0,dmalen1; @@ -450,30 +494,35 @@ static int pci9118_ai_docmd_and_mode(int mode, comedi_device * dev, comedi_subde start_pacer(dev, -1, 0, 0); // stop pacer - devpriv->AdControlReg=AdControl_Int; // bipolar, S.E., use 8254, stop 8354, internal trigger, soft trigger, disable DMA + devpriv->AdControlReg=0; // bipolar, S.E., use 8254, stop 8354, internal trigger, soft trigger, disable DMA - if (!check_and_setup_channel_list(dev, s, devpriv->ai1234_n_chan, devpriv->ai1234_chanlist, 8)) return -EINVAL; + if (!check_and_setup_channel_list(dev, s, devpriv->ai1234_n_chan, devpriv->ai1234_chanlist, 8, 0)) return -EINVAL; outl(devpriv->AdControlReg,dev->iobase+PCI9118_ADCNTRL); devpriv->AdFunctionReg=AdFunction_PDTrg|AdFunction_PETrg; // positive triggers, no S&H, no burst, burst stop, no post trigger, no about trigger, trigger stop outl(devpriv->AdFunctionReg,dev->iobase+PCI9118_ADFUNC); - udelay(10); + udelay(1); outl(0,dev->iobase+PCI9118_DELFIFO); // flush FIFO inl(dev->iobase+PCI9118_ADSTAT); // flush A/D status register + inl(dev->iobase+PCI9118_INTSRC); devpriv->ai1234_act_scan=0; + devpriv->ai1234_act_scanpos=0; s->async->cur_chan=0; devpriv->ai1234_buf_ptr=0; devpriv->neverending_ai=0; - + devpriv->ai12_startstop=startstop; devpriv->dma_actbuf=0; - if ((devpriv->ai1234_scans==0)||(devpriv->ai1234_scans==-1)) devpriv->neverending_ai=1; //well, user want neverending + if (startstop&STOP_AI_EXT) + devpriv->neverending_ai=1; // stop on external account + switch (mode) { case 1: if (devpriv->ai1234_timer1ai_ns_min) devpriv->ai1234_timer1=this_board->ai_ns_min; i8253_cascade_ns_to_timer(devpriv->i8254_osc_base,&divisor1,&divisor2,&devpriv->ai1234_timer1,TRIG_ROUND_NEAREST); + // rt_printk("OSC base=%u div1=%u div2=%u timer=%u\n",devpriv->i8254_osc_base,divisor1,divisor2,devpriv->ai1234_timer1); break; case 2: if (devpriv->ai1234_timer2==0) use_bssh=1; // use S&H @@ -492,35 +541,43 @@ static int pci9118_ai_docmd_and_mode(int mode, comedi_device * dev, comedi_subde case 4: if (devpriv->ai1234_timer2ai_ns_min) devpriv->ai1234_timer2=this_board->ai_ns_min; i8253_cascade_ns_to_timer(devpriv->i8254_osc_base,&divisor1,&divisor2,&devpriv->ai1234_timer2,TRIG_ROUND_NEAREST); - devpriv->ai4_divisor1=divisor1; - devpriv->ai4_divisor2=divisor2; devpriv->ai4_status=0; break; } + devpriv->ai1234_divisor1=divisor1; + devpriv->ai1234_divisor2=divisor2; + if (devpriv->master) { // bus master DMA dmalen0=devpriv->dmabuf_size[0]; dmalen1=devpriv->dmabuf_size[1]; if (!devpriv->neverending_ai) { - if (dmalen0>(devpriv->ai1234_scans*devpriv->ai1234_n_chan*2)) { // must we fill full first buffer? - dmalen0=devpriv->ai1234_scans*devpriv->ai1234_n_chan*2; + if (dmalen0>(devpriv->ai1234_scans*devpriv->ai1234_n_scanlen*2)) { // must we fill full first buffer? + dmalen0=devpriv->ai1234_scans*devpriv->ai1234_n_scanlen*2; } else - if (dmalen1>(devpriv->ai1234_scans*devpriv->ai1234_n_chan*2-dmalen0)) // and must we fill full second buffer when first is once filled? - dmalen1=devpriv->ai1234_scans*devpriv->ai1234_n_chan*2-dmalen0; + if (dmalen1>(devpriv->ai1234_scans*devpriv->ai1234_n_scanlen*2-dmalen0)) // and must we fill full second buffer when first is once filled? + dmalen1=devpriv->ai1234_scans*devpriv->ai1234_n_scanlen*2-dmalen0; } - if ((devpriv->ai1234_flags & TRIG_WAKE_EOS)||(mode==4)) { // don't we want wake up every scan? - if (dmalen0>(devpriv->ai1234_n_chan*2)) - dmalen0=devpriv->ai1234_n_chan*2; - if (dmalen1>(devpriv->ai1234_n_chan*2)) - dmalen1=devpriv->ai1234_n_chan*2; + if (devpriv->ai1234_flags & TRIG_WAKE_EOS) { // don't we want wake up every scan? + if (dmalen0>(devpriv->ai1234_n_scanlen*2)) { + dmalen0=devpriv->ai1234_n_scanlen*2; + if (devpriv->ai1234_n_scanlen&1) dmalen0+=2; + } + if (dmalen1>(devpriv->ai1234_n_scanlen*2)) { + dmalen1=devpriv->ai1234_n_scanlen*2; + if (devpriv->ai1234_n_scanlen&1) dmalen1-=2; + if (dmalen1<4) dmalen1=4; + } } else { // isn't output buff smaller that our DMA buff? - if (dmalen0>(devpriv->ai1234_data_len)) + if (dmalen0>(devpriv->ai1234_data_len)) { dmalen0=devpriv->ai1234_data_len; - if (dmalen1>(devpriv->ai1234_data_len)) + } + if (dmalen1>(devpriv->ai1234_data_len)) { dmalen1=devpriv->ai1234_data_len; + } } devpriv->dmabuf_use_size[0]=dmalen0; @@ -551,14 +608,19 @@ static int pci9118_ai_docmd_and_mode(int mode, comedi_device * dev, comedi_subde pci9118_exttrg_add(dev,0); // activate EXT trigger break; }; - devpriv->ai_do=mode; + if (devpriv->ai12_startstop) { + pci9118_exttrg_add(dev,0); // activate EXT trigger + devpriv->AdControlReg|=AdControl_Int; + } + outl(devpriv->AdFunctionReg,dev->iobase+PCI9118_ADFUNC); outl(devpriv->AdControlReg, dev->iobase+PCI9118_ADCNTRL); - if ((mode==1)||(mode==2)) - start_pacer(dev, mode, divisor1, divisor2); + if (!(devpriv->ai12_startstop&START_AI_EXT)) + if ((mode==1)||(mode==2)) + start_pacer(dev, mode, divisor1, divisor2); if (mode==2) { devpriv->AdFunctionReg=AdFunction_PDTrg|AdFunction_PETrg|AdFunction_BM|AdFunction_BS; @@ -584,6 +646,7 @@ static int pci9118_ai_mode1234(int mode, comedi_device * dev, comedi_subdevice * int ret; devpriv->ai1234_n_chan=it->n_chan; + devpriv->ai1234_n_scanlen=it->n_chan; devpriv->ai1234_chanlist=it->chanlist; devpriv->ai1234_scans=it->n; devpriv->ai1234_flags=it->flags; @@ -592,7 +655,7 @@ static int pci9118_ai_mode1234(int mode, comedi_device * dev, comedi_subdevice * devpriv->ai1234_timer1=it->trigvar; devpriv->ai1234_timer2=it->trigvar1; - ret=pci9118_ai_docmd_and_mode(mode, dev, s); + ret=pci9118_ai_docmd_and_mode(mode, dev, s,0); it->trigvar=devpriv->ai1234_timer1; it->trigvar1=devpriv->ai1234_timer2; @@ -650,7 +713,7 @@ static int pci9118_ai_mode0(comedi_device * dev, comedi_subdevice * s, comedi_tr devpriv->AdFunctionReg=AdFunction_PDTrg|AdFunction_PETrg; outl(devpriv->AdFunctionReg,dev->iobase+PCI9118_ADFUNC);// positive triggers, no S&H, no burst, burst stop, no post trigger, no about trigger, trigger stop - if (!check_and_setup_channel_list(dev,s,it->n_chan, it->chanlist, 0)) return -EINVAL; + if (!check_and_setup_channel_list(dev,s,it->n_chan, it->chanlist, 0, 0)) return -EINVAL; outl(0,dev->iobase+PCI9118_DELFIFO); // flush FIFO @@ -658,7 +721,7 @@ static int pci9118_ai_mode0(comedi_device * dev, comedi_subdevice * s, comedi_tr for (i=0; i<(it->n_chan*it->n); i++) { outw(0, dev->iobase+PCI9118_SOFTTRG); /* start conversion */ - udelay(3); + udelay(2); timeout=100; while (timeout--) { if (inl(dev->iobase+PCI9118_ADSTAT) & AdStatus_ADrdy) goto conv_finish; @@ -704,6 +767,7 @@ static int pci9118_ao_mode0(comedi_device * dev, comedi_subdevice * s, comedi_tr for (i=0;in_chan;i++){ data=it->data[i]; chan=CR_CHAN(it->chanlist[i]); + devpriv->ao_data[0]=data; if (chan) { outl(data, dev->iobase + PCI9118_DA2); } else { @@ -769,13 +833,13 @@ int pci9118_insn_read_ai(comedi_device *dev,comedi_subdevice *s, comedi_insn *in devpriv->AdFunctionReg=AdFunction_PDTrg|AdFunction_PETrg; outl(devpriv->AdFunctionReg,dev->iobase+PCI9118_ADFUNC);// positive triggers, no S&H, no burst, burst stop, no post trigger, no about trigger, trigger stop - if (!check_and_setup_channel_list(dev,s,1,&insn->chanspec, 0)) return -EINVAL; + if (!check_and_setup_channel_list(dev,s,1,&insn->chanspec, 0, 0)) return -EINVAL; outl(0,dev->iobase+PCI9118_DELFIFO); // flush FIFO for (n=0; nn; n++) { outw(0, dev->iobase+PCI9118_SOFTTRG); /* start conversion */ - udelay(3); + udelay(2); timeout=100; while (timeout--) { if (inl(dev->iobase+PCI9118_ADSTAT) & AdStatus_ADrdy) goto conv_finish; @@ -805,18 +869,34 @@ conv_finish: */ int pci9118_insn_write_ao(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data) { - int n,chanreg; + int n,chanreg,ch; - if (CR_CHAN(insn->chanspec)) { chanreg=PCI9118_DA2;} - else { chanreg=PCI9118_DA1; } + ch=CR_CHAN(insn->chanspec); + if (ch) { chanreg=PCI9118_DA2;} + else { chanreg=PCI9118_DA1; } for (n=0; nn; n++) { outl(data[n], dev->iobase + chanreg); + devpriv->ao_data[ch]=data[n]; } return n; } +/* +============================================================================== +*/ +int pci9118_insn_read_ao(comedi_device * dev, comedi_subdevice * s, comedi_insn *insn, lsampl_t *data) +{ + int n,chan; + + chan=CR_CHAN(insn->chanspec); + for (n=0; nn; n++) + data[n]=devpriv->ao_data[chan]; + + return n; +} + /* ============================================================================== */ @@ -864,13 +944,26 @@ int pci9118_insn_bits_do(comedi_device *dev,comedi_subdevice *s, comedi_insn *in if(data[0]){ s->state &= ~data[0]; s->state |= (data[0]&data[1]); - outl(s->state & 0xf, dev->iobase + PCI9118_DO); + outl(s->state & 0x0f, dev->iobase + PCI9118_DO); } - data[1] = inl(dev->iobase + PCI9118_DI) & 0xf; + data[1] = inl(dev->iobase + PCI9118_DI) & 0x0f; return 2; } +/* +============================================================================== +*/ +int pci9118_insn_read_do(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data) +{ + int n; + + for (n=0; nn; n++) + data[n]=s->state & 0x0f; + + return n; +} + /* ============================================================================== */ @@ -882,38 +975,66 @@ static int pci9118_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd /* step 1: make sure trigger sources are trivially valid */ tmp=cmd->start_src; - cmd->start_src &= TRIG_NOW; - if(!cmd->start_src && tmp!=cmd->start_src)err++; + cmd->start_src &= TRIG_NOW|TRIG_EXT; + if(!cmd->start_src || tmp!=cmd->start_src)err++; tmp=cmd->scan_begin_src; cmd->scan_begin_src &= TRIG_TIMER|TRIG_EXT|TRIG_FOLLOW; - if(!cmd->scan_begin_src && tmp!=cmd->scan_begin_src)err++; + if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src)err++; tmp=cmd->convert_src; cmd->convert_src &= TRIG_TIMER|TRIG_EXT; - if(!cmd->convert_src && tmp!=cmd->convert_src)err++; + if(!cmd->convert_src || tmp!=cmd->convert_src)err++; tmp=cmd->scan_end_src; cmd->scan_end_src &= TRIG_COUNT; - if(!cmd->scan_end_src && tmp!=cmd->scan_end_src)err++; + if(!cmd->scan_end_src || tmp!=cmd->scan_end_src)err++; tmp=cmd->stop_src; - cmd->stop_src &= TRIG_COUNT|TRIG_NONE; - if(!cmd->stop_src && tmp!=cmd->stop_src)err++; + cmd->stop_src &= TRIG_COUNT|TRIG_NONE|TRIG_EXT; + if(!cmd->stop_src || tmp!=cmd->stop_src)err++; - if(err)return 1; + if(err) return 1; /* step 2: make sure trigger sources are unique and mutually compatible */ + if(cmd->start_src!=TRIG_NOW && + cmd->start_src!=TRIG_EXT) { + err++; + } + if(cmd->scan_begin_src!=TRIG_TIMER && cmd->scan_begin_src!=TRIG_EXT && - cmd->scan_begin_src!=TRIG_FOLLOW)err++; + cmd->scan_begin_src!=TRIG_FOLLOW) err++; + if(cmd->convert_src!=TRIG_TIMER && - cmd->convert_src!=TRIG_EXT)err++; - if(cmd->scan_begin_src==!TRIG_FOLLOW && - cmd->convert_src==TRIG_EXT)err++; + cmd->convert_src!=TRIG_EXT) err++; - if(err)return 2; + if((cmd->scan_begin_src&(TRIG_TIMER|TRIG_EXT)) && + cmd->convert_src!=TRIG_TIMER) { + cmd->convert_src=TRIG_TIMER; + err++; + } + + if(cmd->scan_end_src!=TRIG_COUNT) { + cmd->scan_end_src=TRIG_COUNT; + err++; + } + + if(cmd->stop_src!=TRIG_NONE && + cmd->stop_src!=TRIG_COUNT && + cmd->stop_src!=TRIG_EXT) err++; + + if(cmd->start_src==TRIG_EXT && + cmd->scan_begin_src==TRIG_EXT) { + cmd->start_src=TRIG_NOW; + err++; + } + + if(cmd->stop_src==TRIG_EXT && + cmd->scan_begin_src==TRIG_EXT) err++; + + if(err) { return 2;} /* step 3: make sure arguments are trivially compatible */ @@ -926,14 +1047,10 @@ static int pci9118_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd cmd->scan_begin_arg=this_board->ai_ns_min; err++; } - if(cmd->scan_begin_arg>devpriv->i8254_osc_base*0xffffff){ - cmd->scan_begin_arg=devpriv->i8254_osc_base*0xffffff; - err++; - } } if(cmd->convert_src==TRIG_TIMER){ if (cmd->scan_begin_src==TRIG_TIMER) { - if((cmd->convert_arg)&&(cmd->convert_argai_ns_min)){ + if((cmd->convert_arg)&&(cmd->convert_argai_ns_min)){ // convert_arg=0 -> use S&H cmd->convert_arg=this_board->ai_ns_min; err++; } @@ -941,12 +1058,9 @@ static int pci9118_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd if(cmd->convert_argai_ns_min){ cmd->convert_arg=this_board->ai_ns_min; err++; + } } - if(cmd->convert_arg>devpriv->i8254_osc_base*0xffffff){ - cmd->convert_arg=devpriv->i8254_osc_base*0xffffff; - err++; - } } if(!cmd->chanlist_len){ @@ -957,10 +1071,14 @@ static int pci9118_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd cmd->chanlist_len=this_board->n_aichanlist; err++; } - if(cmd->scan_end_arg!=cmd->chanlist_len){ + if(cmd->scan_end_argchanlist_len){ cmd->scan_end_arg=cmd->chanlist_len; err++; } + if((cmd->scan_end_arg % cmd->chanlist_len)){ + cmd->scan_end_arg=cmd->scan_end_arg/cmd->chanlist_len; + err++; + } if(cmd->stop_src==TRIG_COUNT){ if(!cmd->stop_arg){ cmd->stop_arg=1; @@ -973,18 +1091,22 @@ static int pci9118_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd } } - if(err)return 3; + if(err) return 3; /* step 4: fix up any arguments */ if(cmd->scan_begin_src==TRIG_TIMER){ tmp=cmd->scan_begin_arg; i8253_cascade_ns_to_timer(devpriv->i8254_osc_base,&divisor1,&divisor2,&cmd->scan_begin_arg,cmd->flags&TRIG_ROUND_MASK); + if(cmd->scan_begin_argai_ns_min) + cmd->scan_begin_arg=this_board->ai_ns_min; if(tmp!=cmd->scan_begin_arg)err++; } if(cmd->convert_src==TRIG_TIMER){ tmp=cmd->convert_arg; i8253_cascade_ns_to_timer(devpriv->i8254_osc_base,&divisor1,&divisor2,&cmd->convert_arg,cmd->flags&TRIG_ROUND_MASK); + if(cmd->scan_begin_argai_ns_min) + cmd->scan_begin_arg=this_board->ai_ns_min; if(tmp!=cmd->convert_arg)err++; if(cmd->scan_begin_src==TRIG_TIMER) { if (cmd->convert_arg==0) { @@ -1001,7 +1123,10 @@ static int pci9118_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd } } - if(err)return 4; + if (cmd->chanlist) + if (!check_and_setup_channel_list(dev, s, cmd->chanlist_len, cmd->chanlist, 0, 1)) return 5; // incorrect channels list + + if(err) return 4; return 0; } @@ -1012,36 +1137,41 @@ static int pci9118_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd static int pci9118_ai_cmd(comedi_device *dev,comedi_subdevice *s) { comedi_cmd *cmd=&s->async->cmd; + char startstop; + startstop=0; devpriv->ai1234_flags=cmd->flags; devpriv->ai1234_n_chan=cmd->chanlist_len; + devpriv->ai1234_n_scanlen=cmd->scan_end_arg; devpriv->ai1234_chanlist=cmd->chanlist; devpriv->ai1234_data=s->async->data; devpriv->ai1234_data_len=s->async->data_len; - if (cmd->stop_arg==TRIG_COUNT) { devpriv->ai1234_scans=cmd->stop_arg; } + if (cmd->stop_src==TRIG_COUNT) { devpriv->ai1234_scans=cmd->stop_arg; } else { devpriv->ai1234_scans=0; } devpriv->ai1234_timer1=0; devpriv->ai1234_timer2=0; - + if (cmd->start_src==TRIG_EXT) startstop|=START_AI_EXT; + if (cmd->stop_src==TRIG_EXT) startstop|=STOP_AI_EXT; + if(cmd->scan_begin_src==TRIG_FOLLOW){ // mode 1 or 3 if (cmd->convert_src==TRIG_TIMER) { // mode 1 devpriv->ai1234_timer1=cmd->convert_arg; - return pci9118_ai_docmd_and_mode(1,dev,s); + return pci9118_ai_docmd_and_mode(1,dev,s,startstop); } if (cmd->convert_src==TRIG_EXT) { // mode 3 - return pci9118_ai_docmd_and_mode(3,dev,s); + return pci9118_ai_docmd_and_mode(3,dev,s,startstop); } } if((cmd->scan_begin_src==TRIG_TIMER)&&(cmd->convert_src==TRIG_TIMER)){ // mode 2 devpriv->ai1234_timer1=cmd->scan_begin_arg; devpriv->ai1234_timer2=cmd->convert_arg; - return pci9118_ai_docmd_and_mode(2,dev,s); + return pci9118_ai_docmd_and_mode(2,dev,s,startstop); } if((cmd->scan_begin_src==TRIG_EXT)&&(cmd->convert_src==TRIG_TIMER)){ // mode 4 devpriv->ai1234_timer2=cmd->convert_arg; - return pci9118_ai_docmd_and_mode(4,dev,s); + return pci9118_ai_docmd_and_mode(4,dev,s,startstop); } return -1; @@ -1050,14 +1180,14 @@ static int pci9118_ai_cmd(comedi_device *dev,comedi_subdevice *s) /* ============================================================================== */ -int check_and_setup_channel_list(comedi_device * dev, comedi_subdevice * s, int n_chan, unsigned int *chanlist,char rot) +int check_and_setup_channel_list(comedi_device * dev, comedi_subdevice * s, int n_chan, unsigned int *chanlist,char rot,char check) { unsigned int i, differencial=0, bipolar=0; unsigned int scanquad, gain; /* correct channel and range number check itself comedi/range.c */ if (n_chan<1) { - comedi_error(dev,"range/channel list is empty!"); + if (!check) comedi_error(dev,"range/channel list is empty!"); return 0; } @@ -1068,19 +1198,21 @@ int check_and_setup_channel_list(comedi_device * dev, comedi_subdevice * s, int if (n_chan > 1) for (i=1 ; iusemux)&(differencial)&(CR_CHAN(chanlist[i])>=this_board->n_aichand)) { - comedi_error(dev,"If AREF_DIFF is used then is available only 8 channels!"); + if (!check) comedi_error(dev,"If AREF_DIFF is used then is available only 8 channels!"); return 0; } } + if (check) return 1; + // All is ok, so we can setup channel/range list if (!bipolar) { @@ -1116,7 +1248,7 @@ int check_and_setup_channel_list(comedi_device * dev, comedi_subdevice * s, int } outl(0,dev->iobase+PCI9118_SCANMOD); // close scan queue - udelay(100); // important delay, or first sample will be cripled +// udelay(100); // important delay, or first sample will be cripled return 1; // we can serve this with scan logic } @@ -1188,6 +1320,7 @@ int pci9118_ai_cancel(comedi_device * dev, comedi_subdevice * s) devpriv->ai_do=0; devpriv->ai1234_act_scan=0; + devpriv->ai1234_act_scanpos=0; s->async->cur_chan=0; devpriv->ai1234_buf_ptr=0; devpriv->neverending_ai=0; @@ -1222,9 +1355,10 @@ static int pci9118_reset(comedi_device *dev) udelay(10); inl(dev->iobase+PCI9118_AD_DATA); outl(0,dev->iobase+PCI9118_DELFIFO); // flush FIFO + outl(0,dev->iobase+PCI9118_INTSRC); // remove INT requests inl(dev->iobase+PCI9118_ADSTAT); // flush A/D status register inl(dev->iobase+PCI9118_INTSRC); // flush INT requests - devpriv->AdControlReg=AdControl_Int; + devpriv->AdControlReg=0; outl(devpriv->AdControlReg,dev->iobase+PCI9118_ADCNTRL);// bipolar, S.E., use 8254, stop 8354, internal trigger, soft trigger, disable INT and DMA devpriv->cnt0_users=0; @@ -1240,47 +1374,42 @@ static int pci9118_attach(comedi_device *dev,comedi_devconfig *it) { comedi_subdevice *s; int ret,pages,i; - unsigned int iobase_a,iobase_9,irq; - struct amcc_struct *card=NULL; + unsigned short io_addr[5],master,irq; + unsigned int iobase_a,iobase_9; + struct pcilst_struct *card=NULL; unsigned char pci_bus,pci_slot,pci_func; - unsigned int master; - printk("comedi%d: adl_pci9118: board=%s",dev->minor,this_board->name); - - if ((it->options[0]<1)&(it->options[1]<1)) { // use autodetection - if ((card=find_free_card_by_device(this_board->device_id))==NULL) { - rt_printk(" - Unused card not found in system!\n"); - return -EIO; - } - } else { - switch (find_free_card_by_position(this_board->device_id,it->options[0],it->options[1],&card)) { - case 1: - rt_printk(" - Card not found on requested position!\n"); - return -EIO; - case 2: - rt_printk(" - Card on requested position is used!\n"); - return -EIO; - } + if (!pci_list_builded) { + pci_card_list_init(PCI_VENDOR_ID_AMCC,0); + pci_list_builded=1; } + rt_printk("comedi%d: adl_pci9118: board=%s",dev->minor,this_board->name); - if (alloc_amcc_card(card)!=0) { - rt_printk(" - Can't allocate card!\n"); + if ((card=select_and_alloc_pci_card(PCI_VENDOR_ID_AMCC, this_board->device_id, it->options[0], it->options[1]))==NULL) return -EIO; - } - if ((card_data(card,&pci_bus,&pci_slot,&pci_func, - &iobase_a,&iobase_9,&irq,&master))<0) { + if ((pci_card_data(card,&pci_bus,&pci_slot,&pci_func, + &io_addr[0],&irq,&master))<0) { + pci_card_free(card); rt_printk(" - Can't get AMCC data!\n"); return -EIO; } + iobase_a=io_addr[0]; + iobase_9=io_addr[2]; + + rt_printk(", b:s:f=%d:%d:%d, io=0x%4x, 0x%4x",pci_bus,pci_slot,pci_func,iobase_9,iobase_a); if (check_region(iobase_9, this_board->iorange_9118) < 0) { rt_printk("I/O port conflict\n"); return -EIO; } + if (check_region(iobase_a, this_board->iorange_amcc) < 0) { + rt_printk("I/O port conflict\n"); + return -EIO; + } dev->iobase=iobase_9; request_region(dev->iobase, this_board->iorange_9118, "ADLink PCI-9118"); @@ -1293,11 +1422,10 @@ static int pci9118_attach(comedi_device *dev,comedi_devconfig *it) devpriv->amcc=card; devpriv->master=master; devpriv->iobase_a=iobase_a; - devpriv->iosize_a=this_board->iorange_amcc; - request_region(devpriv->iobase_a, devpriv->iosize_a, "ADLink PCI-9118"); + request_region(devpriv->iobase_a, this_board->iorange_amcc, "ADLink PCI-9118"); if (irq>0) { - if (comedi_request_irq(irq, interrupt_pci9118, 0, "ADLink PCI-9118", dev)) { + if (comedi_request_irq(irq, interrupt_pci9118, SA_SHIRQ, "ADLink PCI-9118", dev)) { rt_printk(", unable to allocate IRQ %d, DISABLING IT", irq); irq=0; /* Can't use IRQ */ } else { @@ -1328,7 +1456,7 @@ static int pci9118_attach(comedi_device *dev,comedi_devconfig *it) } if (devpriv->dmabuf_virt[1]) - devpriv->dma_doublebuf=0; + devpriv->dma_doublebuf=1; } @@ -1358,7 +1486,7 @@ static int pci9118_attach(comedi_device *dev,comedi_devconfig *it) s = dev->subdevices + 0; dev->read_subdev = s; s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE|SDF_RT|SDF_COMMON|SDF_GROUND|SDF_DIFF; + s->subdev_flags = SDF_READABLE|SDF_COMMON|SDF_GROUND|SDF_DIFF; if (devpriv->usemux) { s->n_chan = devpriv->usemux; } else { s->n_chan = this_board->n_aichan; } s->maxdata = this_board->ai_maxdata; @@ -1382,7 +1510,7 @@ static int pci9118_attach(comedi_device *dev,comedi_devconfig *it) s = dev->subdevices + 1; s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE|SDF_GROUND|SDF_COMMON|SDF_RT; + s->subdev_flags = SDF_WRITEABLE|SDF_GROUND|SDF_COMMON; s->n_chan = this_board->n_aochan; s->maxdata = this_board->ao_maxdata; s->len_chanlist = this_board->n_aochan; @@ -1391,10 +1519,11 @@ static int pci9118_attach(comedi_device *dev,comedi_devconfig *it) s->trig[0] = pci9118_ao_mode0; #endif s->insn_write=pci9118_insn_write_ao; + s->insn_read=pci9118_insn_read_ao; s = dev->subdevices + 2; s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE|SDF_RT|SDF_GROUND|SDF_COMMON; + s->subdev_flags = SDF_READABLE|SDF_GROUND|SDF_COMMON; s->n_chan = 4; s->maxdata = 1; s->len_chanlist = 4; @@ -1408,7 +1537,7 @@ static int pci9118_attach(comedi_device *dev,comedi_devconfig *it) s = dev->subdevices + 3; s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITEABLE|SDF_RT|SDF_GROUND|SDF_COMMON; + s->subdev_flags = SDF_WRITEABLE|SDF_GROUND|SDF_COMMON; s->n_chan = 4; s->maxdata = 1; s->len_chanlist = 4; @@ -1419,6 +1548,7 @@ static int pci9118_attach(comedi_device *dev,comedi_devconfig *it) s->io_bits=0xf; /* all bits output */ s->insn_write=pci9118_insn_write_do; s->insn_bits=pci9118_insn_bits_do; + s->insn_read=pci9118_insn_read_do; pci9118_reset(dev); @@ -1436,62 +1566,35 @@ static int pci9118_detach(comedi_device *dev) { if (dev->private) { if (devpriv->valid) pci9118_reset(dev); - release_region(devpriv->iobase_a,devpriv->iosize_a); - if (devpriv->allocated) - free_amcc_card(devpriv->amcc); - if (devpriv->dmabuf_virt[0]) - free_pages(devpriv->dmabuf_virt[0],devpriv->dmabuf_pages[0]); - if (devpriv->dmabuf_virt[1]) - free_pages(devpriv->dmabuf_virt[1],devpriv->dmabuf_pages[1]); + release_region(devpriv->iobase_a,this_board->iorange_amcc); + if (devpriv->allocated) pci_card_free(devpriv->amcc); + if (devpriv->dmabuf_virt[0]) free_pages(devpriv->dmabuf_virt[0],devpriv->dmabuf_pages[0]); + if (devpriv->dmabuf_virt[1]) free_pages(devpriv->dmabuf_virt[1],devpriv->dmabuf_pages[1]); } - if(dev->irq){ - free_irq(dev->irq,dev); - } + if(dev->irq) free_irq(dev->irq,dev); - if(dev->iobase){ - release_region(dev->iobase, this_board->iorange_9118); + if(dev->iobase) release_region(dev->iobase,this_board->iorange_9118); + + if (pci_list_builded) { + pci_card_list_cleanup(PCI_VENDOR_ID_AMCC); + pci_list_builded=0; } return 0; } -#ifdef MODULE /* ============================================================================== */ - int init_module(void) -{ - int ret; - - ret = comedi_driver_register(&driver_pci9118); - if(ret < 0); - return ret; - - amcc_init(); - - return ret; -} - -/* -============================================================================== -*/ -void cleanup_module(void) -{ - comedi_driver_unregister(&driver_pci9118); - amcc_cleanup(); - -} +COMEDI_INITCLEANUP(driver_pci9118); /* ============================================================================== */ -#endif - /* a unknow future: * [3] - sample&hold signal - card can generate hold signal for external S&H board * 0=use SSHO (pin 45) signal with onboard hardware S&H logic * 1=use ADCHN7 (pin 23) signal and use software for timing * (in this case external multiplexor can serve only 128 A/D channels) */ - diff --git a/comedi/drivers/amcc_s5933.h b/comedi/drivers/amcc_s5933.h index 5fbeae39..394d532e 100644 --- a/comedi/drivers/amcc_s5933.h +++ b/comedi/drivers/amcc_s5933.h @@ -1,5 +1,5 @@ /* - module/amcc_s5933.h + comedi/drivers/amcc_s5933.h Stuff for AMCC S5933 PCI Controller @@ -16,6 +16,7 @@ #define _AMCC_S5933_H_ #include +#include #ifdef PCI_SUPPORT_VER1 #error Sorry, no support for 2.1.55 and older! :-(((( @@ -154,42 +155,45 @@ /****************************************************************************/ -struct amcc_struct{ - struct amcc_struct *next; +struct pcilst_struct{ + struct pcilst_struct *next; int used; struct pci_dev *pcidev; + unsigned short vendor; unsigned short device; unsigned int master; unsigned char pci_bus; unsigned char pci_slot; unsigned char pci_func; - unsigned int amcc_io_addr; - unsigned int daq_io_addr; + unsigned int io_addr[5]; unsigned int irq; }; -struct amcc_struct *amcc_devices; // ptr to root list of all amcc devices +struct pcilst_struct *amcc_devices; // ptr to root list of all amcc devices /****************************************************************************/ -void amcc_init(void); -void amcc_cleanup(void); -struct amcc_struct *find_free_card_by_device(unsigned short device_id); -int alloc_amcc_card(struct amcc_struct *amcc); -int free_amcc_card(struct amcc_struct *amcc); -void display_amcc_cards(void); -int card_data(struct amcc_struct *amcc, +void pci_card_list_init(unsigned short pci_vendor, char display); +void pci_card_list_cleanup(unsigned short pci_vendor); +struct pcilst_struct *find_free_pci_card_by_device(unsigned short vendor_id, unsigned short device_id); +int find_free_pci_card_by_position(unsigned short vendor_id, unsigned short device_id, unsigned short pci_bus, unsigned short pci_slot, struct pcilst_struct **card); +struct pcilst_struct *select_and_alloc_pci_card(unsigned short vendor_id, unsigned short device_id, unsigned short pci_bus, unsigned short pci_slot); + +int pci_card_alloc(struct pcilst_struct *amcc); +int pci_card_free(struct pcilst_struct *amcc); +void pci_card_list_display(void); +int pci_card_data(struct pcilst_struct *amcc, unsigned char *pci_bus, unsigned char *pci_slot, unsigned char *pci_func, - unsigned int *amcc_io, unsigned int *daq_io, unsigned int *irq, - unsigned int *master); + unsigned short *io_addr, unsigned short *irq, unsigned short *master); /****************************************************************************/ /* build list of amcc cards in this system */ -void amcc_init(void) +void pci_card_list_init(unsigned short pci_vendor, char display) { struct pci_dev *pcidev; - struct amcc_struct *amcc,*last; + struct pcilst_struct *amcc,*last; + int i; amcc_devices=NULL; last=NULL; @@ -199,7 +203,7 @@ void amcc_init(void) #else pci_for_each_dev(pcidev){ #endif - if(pcidev->vendor==PCI_VENDOR_ID_AMCC){ + if(pcidev->vendor==pci_vendor){ amcc=kmalloc(sizeof(*amcc),GFP_KERNEL); memset(amcc,0,sizeof(*amcc)); @@ -209,40 +213,40 @@ void amcc_init(void) last=amcc; #if LINUX_VERSION_CODE < 0x020300 + amcc->vendor=pcidev->vendor; amcc->device=pcidev->device; amcc->master=pcidev->master; amcc->pci_bus=pcidev->bus->number; amcc->pci_slot=PCI_SLOT(pcidev->devfn); amcc->pci_func=PCI_FUNC(pcidev->devfn); - amcc->amcc_io_addr=pcidev->base_address[0] & ~3UL; - amcc->daq_io_addr=pcidev->base_address[2] & ~3UL; + for (i=0;i<5;i++) + amcc->io_addr[i]=pcidev->base_address[i] & ~3UL; amcc->irq=pcidev->irq; #else + amcc->vendor=pcidev->vendor; amcc->device=pcidev->device; #if 0 - amcc->master=pcidev->master; + amcc->master=pcidev->master; // how get this information under 2.4 kernels? +#endif amcc->pci_bus=pcidev->bus->number; amcc->pci_slot=PCI_SLOT(pcidev->devfn); amcc->pci_func=PCI_FUNC(pcidev->devfn); -#endif - amcc->amcc_io_addr=pcidev->resource[0].start & ~3UL; - amcc->daq_io_addr=pcidev->resource[2].start & ~3UL; + for (i=0;i<5;i++) + amcc->io_addr[i]=pcidev->resource[i].start & ~3UL; amcc->irq=pcidev->irq; #endif } } -#if 0 - display_amcc_cards(); -#endif + if (display) pci_card_list_display(); } /****************************************************************************/ /* free up list of amcc cards in this system */ -void amcc_cleanup(void) +void pci_card_list_cleanup(unsigned short pci_vendor) { - struct amcc_struct *amcc,*next; + struct pcilst_struct *amcc,*next; for(amcc=amcc_devices;amcc;amcc=next){ next=amcc->next; @@ -254,13 +258,13 @@ void amcc_cleanup(void) /****************************************************************************/ /* find first unused card with this device_id */ -struct amcc_struct *find_free_card_by_device(unsigned short device_id) +struct pcilst_struct *find_free_pci_card_by_device(unsigned short vendor_id, unsigned short device_id) { - struct amcc_struct *amcc,*next; + struct pcilst_struct *amcc,*next; for (amcc=amcc_devices;amcc;amcc=next) { next=amcc->next; - if ((!amcc->used)&&(amcc->device==device_id)) return amcc; + if ((!amcc->used)&&(amcc->device==device_id)&&(amcc->vendor==vendor_id)) return amcc; } @@ -269,14 +273,14 @@ struct amcc_struct *find_free_card_by_device(unsigned short device_id) /****************************************************************************/ /* find card on requested position */ -int find_free_card_by_position(unsigned short device_id, unsigned short pci_bus, unsigned short pci_slot, struct amcc_struct **card) +int find_free_pci_card_by_position(unsigned short vendor_id, unsigned short device_id, unsigned short pci_bus, unsigned short pci_slot, struct pcilst_struct **card) { - struct amcc_struct *amcc,*next; + struct pcilst_struct *amcc,*next; *card=NULL; for (amcc=amcc_devices;amcc;amcc=next) { next=amcc->next; - if ((amcc->device==device_id)&(amcc->pci_bus==pci_bus)&(amcc->pci_slot==pci_slot)) { + if ((amcc->vendor==vendor_id)&&(amcc->device==device_id)&&(amcc->pci_bus==pci_bus)&&(amcc->pci_slot==pci_slot)) { if (!(amcc->used)) { *card=amcc; return 0; // ok, card is found @@ -291,7 +295,7 @@ int find_free_card_by_position(unsigned short device_id, unsigned short pci_bus, /****************************************************************************/ /* mark card as used */ -int alloc_amcc_card(struct amcc_struct *amcc) +int pci_card_alloc(struct pcilst_struct *amcc) { if (!amcc) return -1; @@ -302,7 +306,7 @@ int alloc_amcc_card(struct amcc_struct *amcc) /****************************************************************************/ /* mark card as free */ -int free_amcc_card(struct amcc_struct *amcc) +int pci_card_free(struct pcilst_struct *amcc) { if (!amcc) return -1; @@ -313,38 +317,70 @@ int free_amcc_card(struct amcc_struct *amcc) /****************************************************************************/ /* display list of found cards */ -void display_amcc_cards(void) +void pci_card_list_display(void) { - struct amcc_struct *amcc,*next; + struct pcilst_struct *amcc,*next; - printk("List of cards with AMCC S5933 PCI chip\n"); - printk("bus:slot:func device master io_amcc io_daq irq used\n"); + printk("List of pci cards\n"); + printk("bus:slot:func vendor device master io_amcc io_daq irq used\n"); for (amcc=amcc_devices;amcc;amcc=next) { next=amcc->next; - printk("%2d %2d %2d 0x%4x %2d 0x%4x 0x%4x %2d %2d\n", - amcc->pci_bus,amcc->pci_slot,amcc->pci_func,amcc->device,amcc->master, - amcc->amcc_io_addr,amcc->daq_io_addr,amcc->irq,amcc->used); + printk("%2d %2d %2d 0x%4x 0x%4x %3s 0x%4x 0x%4x %2d %2d\n", + amcc->pci_bus,amcc->pci_slot,amcc->pci_func,amcc->vendor,amcc->device,amcc->master?"yes":"no", + amcc->io_addr[0],amcc->io_addr[2],amcc->irq,amcc->used); } } /****************************************************************************/ /* return all card information for driver */ -int card_data(struct amcc_struct *amcc, +int pci_card_data(struct pcilst_struct *amcc, unsigned char *pci_bus, unsigned char *pci_slot, unsigned char *pci_func, - unsigned int *amcc_io, unsigned int *daq_io, unsigned int *irq, - unsigned int *master) + unsigned short *io_addr, unsigned short *irq, unsigned short *master) { + int i; + if (!amcc) return -1; *pci_bus=amcc->pci_bus; *pci_slot=amcc->pci_slot; *pci_func=amcc->pci_func; - *amcc_io=amcc->amcc_io_addr; - *daq_io=amcc->daq_io_addr; + for (i=0;i<5;i++) + io_addr[i]=amcc->io_addr[i]; *irq=amcc->irq; *master=amcc->master; return 0; } +/****************************************************************************/ +/* select and alloc card */ +struct pcilst_struct *select_and_alloc_pci_card(unsigned short vendor_id, unsigned short device_id, unsigned short pci_bus, unsigned short pci_slot) +{ + struct pcilst_struct *card; + + if ((pci_bus<1)&(pci_slot<1)) { // use autodetection + if ((card=find_free_pci_card_by_device(vendor_id,device_id))==NULL) { + rt_printk(" - Unused card not found in system!\n"); + return NULL; + } + } else { + switch (find_free_pci_card_by_position(vendor_id,device_id,pci_bus,pci_slot,&card)) { + case 1: + rt_printk(" - Card not found on requested position b:s %d:%d!\n",pci_bus,pci_slot); + return NULL; + case 2: + rt_printk(" - Card on requested position is used b:s %d:%d!\n",pci_bus,pci_slot); + return NULL; + } + } + + + if (pci_card_alloc(card)!=0) { + rt_printk(" - Can't allocate card!\n"); + return NULL; + } + + return card; +} + #endif diff --git a/scripts/Configure.help b/scripts/Configure.help index 1ca51030..699acfe3 100644 --- a/scripts/Configure.help +++ b/scripts/Configure.help @@ -158,7 +158,17 @@ CONFIG_COMEDI_ADLPCI9118 ADLink PCI-9118DG ADLink PCI-9118HR ADLink PCI-9118HG - + +Advantech PCI-1710 and clones +CONFIG_COMEDI_ADV_PCI1710 + Includes support for these cards: + Advantech PCI-1710 + Advantech PCI-1710HG + Advantech PCI-1711 + Advantech PCI-1713 + Advantech PCI-1720 + Advantech PCI-1731 + PCL 711 driver CONFIG_COMEDI_PCL711 Includes support for PCL 711, 711b and ACL 8112. -- 2.26.2