Patch from Michal Dobes
authorDavid Schleef <ds@schleef.org>
Tue, 3 Apr 2001 09:30:57 +0000 (09:30 +0000)
committerDavid Schleef <ds@schleef.org>
Tue, 3 Apr 2001 09:30:57 +0000 (09:30 +0000)
Documentation/comedi/drivers.txt
Documentation/comedi/hardware
comedi/Config.in
comedi/drivers/Makefile
comedi/drivers/adl_pci9118.c
comedi/drivers/amcc_s5933.h
scripts/Configure.help

index c652dece00dc0d699c461e511468e9e71496ca6b..c1add29b9f0375ef561be394b9c8c63c836e3382 100644 (file)
@@ -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 <majkl@tesnet.cz>
+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
index e9fe19d9315ccd4095117fab750cc5a7f4acaf81..8ba47d685bdd0774cb5621c69c4a5c2b2afe7bcc 100644 (file)
@@ -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
index 86c1ee4bcbe12726f58bbb7e927b2f938e97fd39..28f090453289918ca1e3c3e6e5154d07cd0e0f58 100644 (file)
@@ -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
index b68ceed8d0992dfe8081bd1a9ec83b5d543525d5..cbc34cc25d623439a5545ded9946105000530ea6 100644 (file)
@@ -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
 
index 6ff3a128309a929c82043d9a8c83d58879a63595..4123d8c9e761bfab83b48897c3eb5ecb56970227 100644 (file)
@@ -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 <majkl@tesnet.cz>
  *
  * 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;i<n;i++){
 #ifdef PCL9118_PARANOIDCHECK
                if ((*dma & 0x0f00)!=devpriv->chanlist[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<n;i++){
                *data=((*dma & 0xff)<<8)|((*dma & 0xff00)>>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 (samplesinbuf<devpriv->dmabuf_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_timer1<this_board->ai_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_timer2<this_board->ai_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;i<it->n_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; n<insn->n; 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; n<insn->n; 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; n<insn->n; 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; n<insn->n; 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_arg<this_board->ai_ns_min)){
+                       if((cmd->convert_arg)&&(cmd->convert_arg<this_board->ai_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_arg<this_board->ai_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_arg<cmd->chanlist_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_arg<this_board->ai_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_arg<this_board->ai_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 ; i<n_chan; i++) { // check S.E/diff
                        if ((CR_AREF(chanlist[i])==AREF_DIFF)!=(differencial)) {
-                               comedi_error(dev,"Differencial and single ended inputs cann't be mixture!");
+                               if (!check) comedi_error(dev,"Differencial and single ended inputs cann't be mixtured!");
                                return 0;             
                        }
                        if ((CR_RANGE(chanlist[i])<PCI9118_BIPOLAR_RANGES)!=(bipolar)) {
-                               comedi_error(dev,"Bipolar and unipolar ranges cann't be mixture!");
+                               if (!check) comedi_error(dev,"Bipolar and unipolar ranges cann't be mixtured!");
                                return 0;             
                        }
                        if ((!devpriv->usemux)&(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)
 */
-
index 5fbeae396d35fc9f713bc2e1f7ac29dd69f338fd..394d532e88e65c6a1ec5ad1b1e06a5e75c2c4272 100644 (file)
@@ -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 <linux/pci.h>
+#include <linux/comedidev.h>
 
 #ifdef PCI_SUPPORT_VER1
 #error    Sorry, no support for 2.1.55 and older! :-((((
 
 /****************************************************************************/
 
-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
index 1ca510306383503b2f7e6abcc1f0ff6d0fa37fd5..699acfe384ae73a50abfceadd09b5dca489e1801 100644 (file)
@@ -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.