new driver from Michal Dobes, plus fixes to docs
authorDavid Schleef <ds@schleef.org>
Thu, 12 Oct 2000 20:00:46 +0000 (20:00 +0000)
committerDavid Schleef <ds@schleef.org>
Thu, 12 Oct 2000 20:00:46 +0000 (20:00 +0000)
Documentation/comedi/drivers.txt
Documentation/comedi/hardware
comedi/Config.in
comedi/drivers/adl_pci9118.c [new file with mode: 0644]
comedi/drivers/amcc_s5933.h [new file with mode: 0644]
scripts/Configure.help

index b4da8f09c0f7272d9a00835e72f6d059bcf57897..695d71de3bc8937c083082bada26d05c2b0ff037 100644 (file)
@@ -435,7 +435,7 @@ Interrupts are not supported.
 
 
 
-pcl812.o: Advantech PCL-812PG and Advantech PCL-813B
+pcl812.o: Advantech PCL-812PG, Advantech PCL-813B and ADLink ACL-8113
 
 Author: Michal Dobes <majkl@tesnet.cz>
 Status: works (I hope. My board fire up under my hands 
@@ -458,8 +458,8 @@ Options:
           1=D/A outputs 0-10V (internal reference -10V)
          2=D/A outputs unknow (external reference)
 
-Card: Advantech PCL-813B
-  This card have integrated 32SE A/D 25kHz.
+Card: Advantech PCL-813B, ADLink ACL-8113
+  These cards have integrated 32SE A/D 25kHz.
   Driver support only mode0 A/D becouse construction of this card 
   don't allow anything else.
   
@@ -518,4 +518,19 @@ Author: Anders Blomdell <anders.blomdell@control.lth.se>
 Status: works
 
 
+adl_pci9118.o: Adlink PCI-9118DG, PCI-9118HG, PCI-9118HR
+
+Author: Michal Dobes <majkl@tesnet.cz>
+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.
+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).
+
+
 
index 8e2f0832fa28ac617f07ac3114385b59ccda133f..b66195ae75dee78221a98318c31e97dd853c4f4e 100644 (file)
@@ -1,14 +1,24 @@
-ADLink                         ACL-8112-DG                     pcl711
-ADLink                         ACL-8112-HG                     pcl711
 ADLink                         ACL-6126                        pcl726
 ADLink                         ACL-6128                        pcl726
+ADLink                         ACL-7122                        pcl724
+ADLink                         ACL-7124                        pcl724
+ADLink                         ACL-8112-DG                     pcl711
+ADLink                         ACL-8112-HG                     pcl711
+ADLink                         ACL-8113                        pcl812
+ADLink                         PCI-9118DG                      adl_pci9118
+ADLink                         PCI-9118HG                      adl_pci9118
+ADLink                         PCI-9118HR                      adl_pci9118
+ADLink                         PET-48DIO                       pcl724
 Advantech                      PCL-711                         pcl711
 Advantech                      PCL-711B                        pcl711
 Advantech                      PCL-718                         pcl818
+Advantech                      PCL-722                         pcl724
+Advantech                      PCL-724                         pcl724
 Advantech                      PCL-725                         pcl725
 Advantech                      PCL-726                         pcl726
 Advantech                      PCL-727                         pcl726
 Advantech                      PCL-728                         pcl726
+Advantech                      PCL-731                         pcl724
 Advantech                      PCL-812PG                       pcl812
 Advantech                      PCL-813B                        pcl812
 Advantech                      PCL-818                         pcl818
index 493add4d4aef90e8177803a544437dbf268cd446..45818de5bd20317fd4c6d8f589e4e8d2413295dc 100644 (file)
@@ -72,6 +72,7 @@ dep_tristate 'DAS-6402 and compatibles' CONFIG_COMEDI_DAS6402 $CONFIG_COMEDI
 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_ADLPCI9118 $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
 if [ "$CONFIG_COMEDI_PCL724" = "m" ];then
diff --git a/comedi/drivers/adl_pci9118.c b/comedi/drivers/adl_pci9118.c
new file mode 100644 (file)
index 0000000..b73cdd9
--- /dev/null
@@ -0,0 +1,1508 @@
+/*
+ *  module/adl_pci9118.c
+ *
+ *  hardware driver for ADLink cards:
+ *   card:   PCI-9118DG, PCI-9118HG, PCI-9118HR
+ *   driver: pci9118dg,  pci9118hg,  pci9118hr
+ *
+ * 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
+ *  [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)
+ * 
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/timer.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <comedi_module.h>
+#include <amcc_s5933.h>
+#include <8253.h>
+
+#define PCL9118_PARANOIDCHECK          /* if defined, then is used code which control correct channel number on every 12 bit sample */
+
+#define IORANGE_9118   64              /* XXX: I hope */
+#define PCI9118_CHANLEN        255             /* len of chanlist, some source say 256, but reality is 255 :-( */
+
+#define PCI9118_CNT0   0x00            /* R/W: 8254 couter 0 */
+#define PCI9118_CNT1   0x04            /* R/W: 8254 couter 0 */
+#define PCI9118_CNT2   0x08            /* R/W: 8254 couter 0 */
+#define PCI9118_CNTCTRL        0x0c            /* W:   8254 counter control */
+#define PCI9118_AD_DATA        0x10            /* R:   A/D data */
+#define PCI9118_DA1    0x10            /* W:   D/A registers */
+#define PCI9118_DA2    0x14
+#define PCI9118_ADSTAT 0x18            /* R:   A/D status register */
+#define PCI9118_ADCNTRL        0x18            /* W:   A/D control register */
+#define PCI9118_DI     0x1c            /* R:   digi input register */
+#define PCI9118_DO     0x1c            /* W:   digi output register */
+#define PCI9118_SOFTTRG        0x20            /* W:   soft trigger for A/D */
+#define PCI9118_GAIN   0x24            /* W:   A/D gain/channel register */
+#define PCI9118_BURST  0x28            /* W:   A/D burst number register */
+#define PCI9118_SCANMOD        0x2c            /* W:   A/D auto scan mode */
+#define PCI9118_ADFUNC 0x30            /* W:   A/D function register */
+#define PCI9118_DELFIFO        0x34            /* W:   A/D data FIFO reset */
+#define PCI9118_INTSRC 0x38            /* R:   interrupt reason register */
+#define PCI9118_INTCTRL        0x38            /* W:   interrupt control register */
+
+// bits from A/D control register (PCI9118_ADCNTRL)
+#define AdControl_UniP 0x80            /* 1=bipolar, 0=unipolar */
+#define AdControl_Diff 0x40            /* 1=differential, 0= single end inputs */
+#define AdControl_SoftG        0x20            /* 1=8254 counter works, 0=counter stops */
+#define        AdControl_ExtG  0x10            /* 1=8254 countrol controlled by TGIN(pin 46), 0=controled by SoftG */
+#define AdControl_ExtM 0x08            /* 1=external hardware trigger (pin 44), 0=internal trigger */
+#define AdControl_TmrTr        0x04            /* 1=8254 is iternal trigger source, 0=software trigger is source (register PCI9118_SOFTTRG) */
+#define AdControl_Int  0x02            /* 1=enable INT, 0=disable */
+#define AdControl_Dma  0x01            /* 1=enable DMA, 0=disable */
+
+// bits from A/D function register (PCI9118_ADFUNC)
+#define AdFunction_PDTrg       0x80            /* 1=positive, 0=negative digital trigger (only positive is correct) */
+#define AdFunction_PETrg       0x40            /* 1=positive, 0=negative external trigger (only positive is correct) */
+#define AdFunction_BSSH                0x20            /* 1=with sample&hold, 0=without */
+#define AdFunction_BM          0x10            /* 1=burst mode, 0=normal mode */
+#define AdFunction_BS          0x08            /* 1=burst mode start, 0=burst mode stop */
+#define AdFunction_PM          0x04            /* 1=post trigger mode, 0=not post trigger */
+#define AdFunction_AM          0x02            /* 1=about trigger mode, 0=not about trigger */
+#define AdFunction_Start       0x01            /* 1=trigger start, 0=trigger stop */
+
+// bits from A/D status register (PCI9118_ADSTAT)
+#define AdStatus_nFull 0x100           /* 0=FIFO full (fatal), 1=not full */
+#define AdStatus_nHfull        0x080           /* 0=FIFO half full, 1=FIFO not half full */
+#define AdStatus_nEpty 0x040           /* 0=FIFO empty, 1=FIFO not empty */
+#define AdStatus_Acmp  0x020           /*  */
+#define AdStatus_DTH   0x010           /* 1=external digital trigger */
+#define AdStatus_Bover 0x008           /* 1=burst mode overrun (fatal) */
+#define AdStatus_ADOS  0x004           /* 1=A/D over speed (warning) */
+#define AdStatus_ADOR  0x002           /* 1=A/D overrun (fatal) */
+#define AdStatus_ADrdy 0x001           /* 1=A/D already ready, 0=not ready */
+
+// bits for interrupt reason and control (PCI9118_INTSRC, PCI9118_INTCTRL)
+// 1=interrupt occur, enable source,  0=interrupt not occur, disable source
+#define Int_Timer      0x08            /* timer interrupt */
+#define Int_About      0x04            /* about trigger complete */
+#define Int_Hfull      0x02            /* A/D FIFO hlaf full */
+#define Int_DTrg       0x01            /* external digital trigger */
+
+comedi_lrange range_pci9118dg_hr={ 8, {
+       BIP_RANGE(5),
+       BIP_RANGE(2.5),
+       BIP_RANGE(1.25),
+       BIP_RANGE(0.625),
+       UNI_RANGE(10),
+       UNI_RANGE(5),
+       UNI_RANGE(2.5),
+       UNI_RANGE(1.25)
+       }
+};
+
+comedi_lrange range_pci9118hg={ 8, {
+       BIP_RANGE(5),
+       BIP_RANGE(0.5),
+       BIP_RANGE(0.05),
+       BIP_RANGE(0.005),
+       UNI_RANGE(10),
+       UNI_RANGE(1),
+       UNI_RANGE(0.1),
+       UNI_RANGE(0.01)
+       }
+};
+
+#define PCI9118_BIPOLAR_RANGES 4       /* used for test on mixture of BIP/UNI ranges */
+
+static int pci9118_attach(comedi_device *dev,comedi_devconfig *it);
+static int pci9118_detach(comedi_device *dev);
+static int pci9118_recognize(char *name);
+
+comedi_driver driver_pci9118={
+       driver_name:    "adl_pci9118",
+       module:         THIS_MODULE,
+       attach:         pci9118_attach,
+       detach:         pci9118_detach,
+       recognize:      pci9118_recognize,
+};
+
+typedef struct {
+       char            *name;          // driver name
+       int             vendor_id;      // PCI vendor a device ID of card
+       int             device_id;
+       int             iorange_amcc;   // iorange for own S5933 region
+       int             iorange_9118;   // pass thru card region size
+       int             n_aichan;       // num of A/D chans
+       int             n_aichand;      // num of A/D chans in diff mode
+       int             mux_aichan;     // num of A/D chans with external multiplexor
+       int             n_aichanlist;   // len of chanlist
+       int             n_aochan;       // num of D/A chans
+       int             ai_maxdata;     // resolution of A/D
+       int             ao_maxdata;     // resolution of D/A
+       comedi_lrange   *rangelist_ai;  // rangelist for A/D
+       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[] =
+{
+       {"pci9118dg", PCI_VENDOR_ID_AMCC, 0x80d9,
+        AMCC_OP_REG_SIZE, IORANGE_9118,
+        16, 8, 256, PCI9118_CHANLEN, 2, 0x0fff, 0x0fff,
+        &range_pci9118dg_hr, &range_bipolar10,
+        3030, 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 },
+       {"pci9118hr", PCI_VENDOR_ID_AMCC, 0x80d9,
+        AMCC_OP_REG_SIZE, IORANGE_9118,
+        16, 8, 256, PCI9118_CHANLEN, 2, 0xffff, 0x0fff, 
+        &range_pci9118dg_hr,    &range_bipolar10,
+        10000, 40 },
+};
+
+#define n_boardtypes (sizeof(boardtypes)/sizeof(boardtype))
+
+typedef struct{
+       int                     iobase_a;       // base+size for AMCC chip
+       int                     iosize_a;
+       struct amcc_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!
+#ifdef PCL9118_PARANOIDCHECK
+       unsigned short          chanlist[PCI9118_CHANLEN]; // list of scaned channel
+       unsigned char           chanlistlen;    // number of scanlist
+#endif
+       unsigned char           AdControlReg;   // A/D control register
+       unsigned char           IntControlReg;  // Interrupt control register
+       unsigned char           AdFunctionReg;  // A/D function register
+       char                    valid;          // driver is ok
+       char                    neverending_ai; // we do unlimited AI
+       unsigned int            i8254_osc_base; // frequence of onboard oscilator
+       unsigned int            ai_do;          // what do AI? 0=nothing, 1 to 4 mode
+       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_chanlist;// actaul chanlist
+       unsigned int            ai1234_timer1;  
+       unsigned int            ai1234_timer2;  
+       unsigned int            ai1234_flags;
+       unsigned int            ai1234_data_len;
+       sampl_t                 *ai1234_data;
+       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;
+       char                    dma_doublebuf;  // we can use double buffring
+       unsigned int            dma_actbuf;     // which buffer is used now
+       unsigned long           dmabuf_virt[2]; // pointers to begin of DMA buffer
+       unsigned long           dmabuf_hw[2];   // hw address of DMA buff
+       unsigned int            dmabuf_size[2]; // size of dma buffer in bytes
+       unsigned int            dmabuf_use_size[2];     // which size e may now used for transfer
+       unsigned int            dmabuf_samples[2];      // size in samples
+       int                     dmabuf_pages[2];        // number of pages in buffer
+       unsigned char           cnt0_users;     // bit field of 8254 CNT0 users (0-unused, 1-AO, 2-DI, 3-DO)
+       unsigned char           exttrg_users;   // bit field of external trigger users (0-AI, 1-AO, 2-DI, 3-DO)
+       unsigned int            cnt0_divisor;   // actual CNT0 divisor
+}pci9118_private;
+
+#define devpriv ((pci9118_private *)dev->private)
+#define this_board (boardtypes+dev->board)
+
+/* 
+==============================================================================
+*/
+
+int check_and_setup_channel_list(comedi_device * dev, comedi_subdevice * s, int n_chan, unsigned int *chanlist,char rot);
+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);
+int pci9118_exttrg_del(comedi_device * dev, unsigned char source);
+int pci9118_ai_cancel(comedi_device * dev, comedi_subdevice * s);
+
+/* 
+==============================================================================
+*/
+static void interrupt_pci9118_ai_mode4_switch(void *d) 
+{
+       comedi_device   *dev = d;
+
+       if (devpriv->ai4_status) {
+               pci9118_exttrg_add(dev,0);              // activate EXT trigger
+               devpriv->ai4_status=0;                  // next int start pacer!
+               outl(inl(devpriv->iobase_a+AMCC_OP_REG_INTCSR)&(~AINT_WRITE_COMPL), devpriv->iobase_a+AMCC_OP_REG_INTCSR);      // stop dma irq
+               outl(devpriv->ai4_cntrl0, dev->iobase+PCI9118_ADCNTRL);
+               start_pacer(dev, 0, 0, 0);              // stop pacer
+       } else {
+               pci9118_exttrg_del(dev,0);              // deactivate EXT trigger
+               outl(inl(devpriv->iobase_a+AMCC_OP_REG_INTCSR)|(AINT_WRITE_COMPL), devpriv->iobase_a+AMCC_OP_REG_INTCSR);       // enable dma irq
+               //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
+       }
+}
+
+/* 
+==============================================================================
+*/
+static void move_block_from_dma_12bit(comedi_device *dev,comedi_subdevice *s,sampl_t *dma,sampl_t *data,int n)
+{
+       int i,j;
+
+       j=s->cur_chan;
+       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]);
+                       pci9118_ai_cancel(dev,s);
+                       comedi_error_done(dev,s);
+                       return;
+               }
+#endif
+               *data=((*dma & 0xff)<<4)|((*dma & 0xf000)>>12); // get one sample
+               data++; dma++; 
+               j++;
+               if(j>=devpriv->ai1234_n_chan){
+                       j=0;
+                       devpriv->ai1234_act_scan++;
+                       if (devpriv->ai1234_flags & TRIG_WAKE_EOS) 
+                               comedi_eos(dev,s);  
+               }
+       }
+       s->cur_chan=j;
+}
+
+/* 
+==============================================================================
+*/
+static void move_block_from_dma_16bit(comedi_device *dev,comedi_subdevice *s,sampl_t *dma,sampl_t *data,int n)
+{
+       int i,j;
+
+       j=s->cur_chan;
+       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){
+                       j=0;
+                       devpriv->ai1234_act_scan++;
+                       if (devpriv->ai1234_flags & TRIG_WAKE_EOS) 
+                               comedi_eos(dev,s);  
+               }
+       }
+       s->cur_chan=j;
+}
+
+/* 
+==============================================================================
+*/
+static void interrupt_pci9118_ai_dma(int irq, void *d, struct pt_regs *regs) 
+{
+       comedi_device   *dev = d;
+       comedi_subdevice *s = dev->subdevices + 0;
+        sampl_t        *ptr;
+       unsigned int    next_dma_buf, samplesinbuf, m;
+
+       if (devpriv->ai_do==4) 
+               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!");
+       }
+
+       if (samplesinbuf & 1) {
+               comedi_error(dev,"Odd count of bytes in DMA ring!");
+               pci9118_ai_cancel(dev,s);
+               comedi_error_done(dev,s);
+               return;
+       }
+
+       m=inw(dev->iobase+PCI9118_ADSTAT);
+       if (m & 0x10e) {
+               if (m & 0x100)
+                       comedi_error(dev,"A/D FIFO Full status (Fatal Error!)");
+               if (m & 0x008)
+                       comedi_error(dev,"A/D Burst Mode Overrun Status (Fatal Error!)");
+               if (m & 0x004)
+                       comedi_error(dev,"A/D Over Speed Status (Warning!)");
+               if (m & 0x002)
+                       comedi_error(dev,"A/D Overrun Status (Fatal Error!)");
+               if (m & 0x10a) {
+                       pci9118_ai_cancel(dev,s);
+                       comedi_error_done(dev,s);
+                       return;
+               }
+       }
+
+       samplesinbuf=samplesinbuf>>1;   // number of received samples
+               
+       if (devpriv->dma_doublebuf) {   // switch DMA buffers if is used double buffering
+               next_dma_buf=1-devpriv->dma_actbuf;
+               outl(devpriv->dmabuf_hw[next_dma_buf], devpriv->iobase_a+AMCC_OP_REG_MWAR);
+               outl(devpriv->dmabuf_use_size[next_dma_buf], devpriv->iobase_a+AMCC_OP_REG_MWTC);
+       }
+       
+        ptr=(sampl_t *)devpriv->dmabuf_virt[devpriv->dma_actbuf];
+
+       if(s->buf_int_ptr+samplesinbuf*sizeof(sampl_t)>=devpriv->ai1234_data_len){
+               m=(devpriv->ai1234_data_len-s->buf_int_ptr)/sizeof(sampl_t);
+               if (this_board->ai_maxdata==0xfff) { move_block_from_dma_12bit(dev,s,(void *)ptr,((void *)(s->cur_trig.data))+s->buf_int_ptr,m); }
+                                           else   { move_block_from_dma_16bit(dev,s,(void *)ptr,((void *)(s->cur_trig.data))+s->buf_int_ptr,m); }
+               s->buf_int_count+=m*sizeof(sampl_t);
+               ptr+=m*sizeof(sampl_t);
+               samplesinbuf-=m;
+               s->buf_int_ptr=0;
+
+               comedi_eobuf(dev,s);
+       }
+       if (this_board->ai_maxdata==0xfff) { move_block_from_dma_12bit(dev,s,(void *)ptr,((void *)(s->cur_trig.data))+s->buf_int_ptr,samplesinbuf); }
+                                   else   { move_block_from_dma_16bit(dev,s,(void *)ptr,((void *)(s->cur_trig.data))+s->buf_int_ptr,samplesinbuf); }
+       s->buf_int_count+=samplesinbuf*sizeof(sampl_t);
+       s->buf_int_ptr+=samplesinbuf*sizeof(sampl_t);
+
+
+       if (!devpriv->neverending_ai)
+               if ( devpriv->ai1234_act_scan>=devpriv->ai1234_scans ) { /* all data sampled */
+                       pci9118_ai_cancel(dev,s);
+                       comedi_done(dev,s); 
+                       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; 
+       } else { // restart DMA if is not used double buffering
+               outl(devpriv->dmabuf_hw[0], devpriv->iobase_a+AMCC_OP_REG_MWAR);
+               outl(devpriv->dmabuf_use_size[0], devpriv->iobase_a+AMCC_OP_REG_MWTC);
+       }
+}
+
+/* 
+==============================================================================
+*/
+static void interrupt_pci9118(int irq, void *d, struct pt_regs *regs) 
+{
+       comedi_device *dev = d;
+       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),
+               int_adstat);
+#endif
+
+       if ((!int_daq)&&(!(int_amcc&ANY_S593X_INT))) {
+               comedi_error(dev,"IRQ from unknow source");
+               return;
+       }
+       if (int_amcc&MASTER_ABORT_INT)
+               comedi_error(dev,"AMCC IRQ - MASTER DMA ABORT!");
+       if (int_amcc&TARGET_ABORT_INT)
+               comedi_error(dev,"AMCC IRQ - TARGET DMA ABORT!");
+       
+
+       if (devpriv->ai_do) {
+               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
+               }
+       }
+       
+}
+
+/* 
+==============================================================================
+*/
+static int pci9118_ai_docmd_and_mode(int mode, comedi_device * dev, comedi_subdevice * s) 
+{
+        unsigned int divisor1, divisor2;
+       unsigned int    dmalen0,dmalen1;
+       char    use_bssh=0;
+       
+       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
+
+       if (!check_and_setup_channel_list(dev, s, devpriv->ai1234_n_chan, devpriv->ai1234_chanlist, 8)) 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);
+       outl(0,dev->iobase+PCI9118_DELFIFO); // flush FIFO
+       inl(dev->iobase+PCI9118_ADSTAT); // flush A/D status register
+
+        devpriv->ai1234_act_scan=0;
+        s->cur_chan=0;
+        devpriv->ai1234_buf_ptr=0;
+        devpriv->neverending_ai=0;
+
+       devpriv->dma_actbuf=0;
+  
+       if ((devpriv->ai1234_scans==0)||(devpriv->ai1234_scans==-1)) devpriv->neverending_ai=1; //well, user want neverending
+  
+        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);
+               break;
+       case 2:
+               if (devpriv->ai1234_timer2==0) use_bssh=1;      // use S&H
+               if (devpriv->ai1234_timer2<this_board->ai_ns_min) devpriv->ai1234_timer2=this_board->ai_ns_min;
+               divisor1=(devpriv->ai1234_timer2+devpriv->i8254_osc_base/2)/devpriv->i8254_osc_base; // minor timer
+               if (divisor1<this_board->ai_pacer_min) divisor1=this_board->ai_pacer_min;
+               divisor2=(devpriv->ai1234_timer1+devpriv->i8254_osc_base/2)/devpriv->i8254_osc_base;
+               divisor2=divisor2/divisor1;                                             // major timer is c1*c2
+               if (divisor2<devpriv->ai1234_n_chan) divisor2=devpriv->ai1234_n_chan;
+               if (use_bssh) 
+                       if (divisor2<(devpriv->ai1234_n_chan+2))
+                                divisor2=devpriv->ai1234_n_chan+2;
+               devpriv->ai1234_timer2=divisor1*devpriv->i8254_osc_base;
+               devpriv->ai1234_timer1=divisor1*divisor2*devpriv->i8254_osc_base;
+               break;
+       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;
+       }
+   
+        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;
+                       } 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 ((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;
+               } else {                                // isn't output buff smaller that our DMA buff?
+                       if (dmalen0>(devpriv->ai1234_data_len))
+                               dmalen0=devpriv->ai1234_data_len;
+                       if (dmalen1>(devpriv->ai1234_data_len))
+                               dmalen1=devpriv->ai1234_data_len;
+               }
+               
+               devpriv->dmabuf_use_size[0]=dmalen0;
+               devpriv->dmabuf_use_size[1]=dmalen1; 
+               outl(devpriv->dmabuf_hw[0], devpriv->iobase_a+AMCC_OP_REG_MWAR);
+               outl(devpriv->dmabuf_use_size[0], devpriv->iobase_a+AMCC_OP_REG_MWTC);
+
+               outl(0x02000000|AINT_WRITE_COMPL, devpriv->iobase_a+AMCC_OP_REG_INTCSR); 
+               outl(inl(devpriv->iobase_a+AMCC_OP_REG_MCSR)|RESET_A2P_FLAGS|A2P_HI_PRIORITY|EN_A2P_TRANSFERS, devpriv->iobase_a+AMCC_OP_REG_MCSR);
+
+               switch (mode) {
+               case 1: 
+                       devpriv->AdControlReg|=((AdControl_SoftG|AdControl_TmrTr|AdControl_Dma) & 0xff);
+                       break;
+               case 2: 
+                       devpriv->AdControlReg|=((AdControl_SoftG|AdControl_TmrTr|AdControl_Dma) & 0xff);
+                       devpriv->AdFunctionReg|=AdFunction_BM;
+                       if (use_bssh) { outl(devpriv->ai1234_n_chan+1, dev->iobase+PCI9118_BURST); devpriv->AdFunctionReg|=AdFunction_BSSH; }
+                               else  { outl(devpriv->ai1234_n_chan, dev->iobase+PCI9118_BURST); }
+                       break;
+               case 3: 
+                       devpriv->AdControlReg|=((AdControl_ExtM|AdControl_Dma) & 0xff);
+                       break;
+               case 4: 
+                       devpriv->ai4_cntrl1=devpriv->AdControlReg|((AdControl_SoftG|AdControl_TmrTr|AdControl_Dma) & 0xff);
+                       devpriv->AdControlReg|=((AdControl_Int) & 0xff);
+                       devpriv->ai4_cntrl0=devpriv->AdControlReg;
+                       pci9118_exttrg_add(dev,0);      // activate EXT trigger
+                       break;
+               }; 
+
+               devpriv->ai_do=mode;
+
+               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 (mode==2) {
+                       devpriv->AdFunctionReg=AdFunction_PDTrg|AdFunction_PETrg|AdFunction_BM|AdFunction_BS;
+                       if (use_bssh) devpriv->AdFunctionReg|=AdFunction_BSSH;
+                       outl(devpriv->AdFunctionReg,dev->iobase+PCI9118_ADFUNC);
+               }
+
+        } else {
+                return -EINVAL;
+       }
+
+       return 0;
+}
+
+
+#ifdef CONFIG_COMEDI_MODES
+
+/* 
+==============================================================================
+*/
+static int pci9118_ai_mode1234(int mode, comedi_device * dev, comedi_subdevice * s, comedi_trig * it) 
+{
+       int ret;
+       
+       devpriv->ai1234_n_chan=it->n_chan;
+       devpriv->ai1234_chanlist=it->chanlist;
+       devpriv->ai1234_scans=it->n;
+       devpriv->ai1234_flags=it->flags;
+       devpriv->ai1234_data_len=it->data_len;
+       devpriv->ai1234_data=it->data;
+       devpriv->ai1234_timer1=it->trigvar;
+       devpriv->ai1234_timer2=it->trigvar1;
+
+       ret=pci9118_ai_docmd_and_mode(mode, dev, s);
+
+       it->trigvar=devpriv->ai1234_timer1;
+       it->trigvar1=devpriv->ai1234_timer2;
+
+       return ret;
+}
+
+/* 
+==============================================================================
+*/
+static int pci9118_ai_mode1(comedi_device * dev, comedi_subdevice * s, comedi_trig * it) 
+{
+        return pci9118_ai_mode1234(1, dev, s, it);
+}
+
+/* 
+==============================================================================
+*/
+static int pci9118_ai_mode2(comedi_device * dev, comedi_subdevice * s, comedi_trig * it) 
+{
+        return pci9118_ai_mode1234(2, dev, s, it);
+}
+
+/* 
+==============================================================================
+*/
+static int pci9118_ai_mode3(comedi_device * dev, comedi_subdevice * s, comedi_trig * it) 
+{
+        return pci9118_ai_mode1234(3, dev, s, it);
+}
+
+/* 
+==============================================================================
+*/
+static int pci9118_ai_mode4(comedi_device * dev, comedi_subdevice * s, comedi_trig * it) 
+{
+        return pci9118_ai_mode1234(4, dev, s, it);
+}
+
+#endif
+
+#ifdef CONFIG_COMEDI_MODE0
+
+/* 
+==============================================================================
+*/
+static int pci9118_ai_mode0(comedi_device * dev, comedi_subdevice * s, comedi_trig * it) 
+{
+        int timeout,i;
+#ifdef PCL9118_PARANOIDCHECK
+       unsigned int data,m=0;
+#endif
+       
+       devpriv->AdControlReg=AdControl_Int & 0xff;
+       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;
+
+       outl(0,dev->iobase+PCI9118_DELFIFO); // flush FIFO
+       
+       if (it->n==0) it->n=1;
+       
+       for (i=0; i<(it->n_chan*it->n); i++) {
+               outw(0, dev->iobase+PCI9118_SOFTTRG); /* start conversion */
+               udelay(3);
+               timeout=100;
+               while (timeout--) {
+                       if (inl(dev->iobase+PCI9118_ADSTAT) & AdStatus_ADrdy) goto conv_finish;
+                       udelay(1);
+               }
+
+               comedi_error(dev,"A/D mode0 timeout");
+               it->data[i]=0;
+               outl(0,dev->iobase+PCI9118_DELFIFO); // flush FIFO
+               return -ETIME;
+
+conv_finish:
+               if (this_board->ai_maxdata==0xfff) {
+#ifdef PCL9118_PARANOIDCHECK
+                       data=inw(dev->iobase+PCI9118_AD_DATA);
+                       if ((data & 0xf)!=devpriv->chanlist[m++]) {
+                               comedi_error(dev,"A/D mode0 data droput!");
+                               return -ETIME;
+                       }
+                       it->data[i] = (data >> 4) & 0xfff; 
+                       if (m>=it->n_chan) m=0;
+#else
+                       it->data[i] = (inw(dev->iobase+PCI9118_AD_DATA)>>4) & 0xfff; 
+#endif
+               } else {
+                       it->data[i] = inl(dev->iobase+PCI9118_AD_DATA) & 0xffff;
+               }
+       }
+
+       outl(0,dev->iobase+PCI9118_DELFIFO); // flush FIFO
+
+        return i;
+}
+
+/* 
+==============================================================================
+*/
+static int pci9118_ao_mode0(comedi_device * dev, comedi_subdevice * s, comedi_trig * it) 
+{
+        int chan,i;
+        sampl_t data;
+       for (i=0;i<it->n_chan;i++){
+               data=it->data[i];
+               chan=CR_CHAN(it->chanlist[i]);
+               if (chan) {
+                       outl(data, dev->iobase + PCI9118_DA2);
+               } else {
+                       outl(data, dev->iobase + PCI9118_DA1);
+               } 
+        }    
+
+        return it->n_chan;
+}
+/* 
+==============================================================================
+*/
+static int pci9118_di_mode0(comedi_device * dev, comedi_subdevice * s, comedi_trig * it) 
+{ 
+        unsigned int data;
+        int chan;
+        int i;
+
+       data = inl(dev->iobase + PCI9118_DI);
+
+        for(i=0;i<it->n_chan;i++) {
+               chan=CR_CHAN(it->chanlist[i]);
+               it->data[i]=(data>>chan)&1;
+        }
+
+       return it->n_chan;
+}
+
+/* 
+==============================================================================
+*/
+static int pci9118_do_mode0(comedi_device * dev, comedi_subdevice * s, comedi_trig * it) 
+{
+        unsigned int mask, data;
+        int chan;
+        int i;
+
+       data=s->state;
+        for(i=0;i<it->n_chan;i++) {
+               chan=CR_CHAN(it->chanlist[i]);
+               mask=(1<<chan);
+               data &= ~mask;
+               if(it->data[i])
+                       data |= mask;
+        }
+       outl((data & 0xf), dev->iobase + PCI9118_DO);
+        s->state = data;
+
+       return it->n_chan;
+}
+
+#endif
+
+/*
+==============================================================================
+*/
+int pci9118_insn_read_ai(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data)
+{
+
+       int n,timeout;
+
+       devpriv->AdControlReg=AdControl_Int & 0xff;
+       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;
+
+       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);
+               timeout=100;
+               while (timeout--) {
+                       if (inl(dev->iobase+PCI9118_ADSTAT) & AdStatus_ADrdy) goto conv_finish;
+                       udelay(1);
+               }
+
+               comedi_error(dev,"A/D insn timeout");
+               insn->data[n]=0;
+               outl(0,dev->iobase+PCI9118_DELFIFO); // flush FIFO
+               return -ETIME;
+
+conv_finish:
+               if (this_board->ai_maxdata==0xfff) {
+                       data[n] = (inw(dev->iobase+PCI9118_AD_DATA)>>4) & 0xfff; 
+               } else {
+                       data[n] = inl(dev->iobase+PCI9118_AD_DATA) & 0xffff;
+               }
+       }
+
+       outl(0,dev->iobase+PCI9118_DELFIFO); // flush FIFO
+       return n;
+
+}
+
+/*
+==============================================================================
+*/
+int pci9118_insn_write_ao(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data)
+{
+       int n,chanreg;
+       
+       if (CR_CHAN(insn->chanspec)) { chanreg=PCI9118_DA2;} 
+                               else { chanreg=PCI9118_DA1; } 
+
+       for (n=0; n<insn->n; n++) {
+               outl(data[n], dev->iobase + chanreg);
+       }
+
+       return n;
+}
+
+/*
+==============================================================================
+*/
+int pci9118_insn_read_di(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data)
+{
+       int n;
+       
+       for (n=0; n<insn->n; n++) {
+               data[n] = inl(dev->iobase + PCI9118_DI) & 0xf;
+       }
+
+       return n;
+}
+
+/*
+==============================================================================
+*/
+int pci9118_insn_bits_di(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data)
+{
+       data[1] = inl(dev->iobase + PCI9118_DI) & 0xf;
+
+       return 2;
+}
+
+/*
+==============================================================================
+*/
+int pci9118_insn_write_do(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data)
+{
+       int n;
+       
+       for (n=0; n<insn->n; n++) {
+               s->state=data[n]& 0xf;
+               outl(s->state, dev->iobase + PCI9118_DO);
+       }
+       
+       return n;
+}
+
+/*
+==============================================================================
+*/
+int pci9118_insn_bits_do(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data)
+{
+       if(data[0]){
+               s->state &= ~data[0];
+               s->state |= (data[0]&data[1]);
+               outl(s->state & 0xf, dev->iobase + PCI9118_DO);
+       }
+       data[1] = inl(dev->iobase + PCI9118_DI) & 0xf;
+
+       return 2;
+}
+
+/*
+==============================================================================
+*/
+static int pci9118_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
+{
+       int err=0;
+       int tmp,divisor1,divisor2;
+
+       /* 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++;
+
+       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++;
+
+       tmp=cmd->convert_src;
+       cmd->convert_src &= TRIG_TIMER|TRIG_EXT;
+       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++;
+
+       tmp=cmd->stop_src;
+       cmd->stop_src &= TRIG_COUNT|TRIG_NONE;
+       if(!cmd->stop_src && tmp!=cmd->stop_src)err++;
+
+       if(err)return 1;
+
+       /* step 2: make sure trigger sources are unique and mutually compatible */
+
+       if(cmd->scan_begin_src!=TRIG_TIMER &&
+          cmd->scan_begin_src!=TRIG_EXT &&
+          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++;
+
+       if(err)return 2;
+
+       /* step 3: make sure arguments are trivially compatible */
+
+       if(cmd->start_arg!=0){
+               cmd->start_arg=0;
+               err++;
+       }
+       if(cmd->scan_begin_src==TRIG_TIMER){
+               if(cmd->scan_begin_arg<this_board->ai_ns_min){
+                       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)){
+                               cmd->convert_arg=this_board->ai_ns_min;
+                               err++;
+                       }               
+               } else {
+                       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){
+               cmd->chanlist_len=1;
+               err++;
+       }
+       if(cmd->chanlist_len>this_board->n_aichanlist){
+               cmd->chanlist_len=this_board->n_aichanlist;
+               err++;
+       }
+       if(cmd->scan_end_arg!=cmd->chanlist_len){
+               cmd->scan_end_arg=cmd->chanlist_len;
+               err++;
+       }
+       if(cmd->stop_src==TRIG_COUNT){
+               if(!cmd->stop_arg){
+                       cmd->stop_arg=1;
+                       err++;
+               }
+       } else { /* TRIG_NONE */
+               if(cmd->stop_arg!=0){
+                       cmd->stop_arg=0;
+                       err++;
+               }
+       }
+
+       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(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(tmp!=cmd->convert_arg)err++;
+               if(cmd->scan_begin_src==TRIG_TIMER) {
+                       if (cmd->convert_arg==0) {
+                               if (cmd->scan_begin_arg<this_board->ai_ns_min*(cmd->scan_end_arg+2)) {
+                                       cmd->scan_begin_arg=this_board->ai_ns_min*(cmd->scan_end_arg+2);
+                                       err++;
+                               }
+                       } else {
+                               if (cmd->scan_begin_arg<cmd->convert_arg*cmd->scan_end_arg){
+                                       cmd->scan_begin_arg=cmd->convert_arg*cmd->scan_end_arg;
+                                       err++;
+                               }
+                       }
+               }
+       }
+
+       if(err)return 4;
+
+       return 0;
+}
+
+/*
+==============================================================================
+*/
+static int pci9118_ai_cmd(comedi_device *dev,comedi_subdevice *s)
+{
+       comedi_cmd *cmd=&s->cmd;
+       
+       devpriv->ai1234_flags=cmd->flags;
+       devpriv->ai1234_n_chan=cmd->chanlist_len;
+       devpriv->ai1234_chanlist=cmd->chanlist;
+       devpriv->ai1234_data=cmd->data;
+       devpriv->ai1234_data_len=cmd->data_len;
+       if (cmd->stop_arg==TRIG_COUNT) { devpriv->ai1234_scans=cmd->stop_arg; }
+                               else   { devpriv->ai1234_scans=0; }
+       devpriv->ai1234_timer1=0;
+       devpriv->ai1234_timer2=0;
+
+       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);
+               }
+               if (cmd->convert_src==TRIG_EXT) { // mode 3
+                       return pci9118_ai_docmd_and_mode(3,dev,s);
+               }
+       }
+
+       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);
+       }
+               
+       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 -1;
+}
+
+/*
+==============================================================================
+*/
+int check_and_setup_channel_list(comedi_device * dev, comedi_subdevice * s, int n_chan, unsigned int *chanlist,char rot) 
+{
+        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!");
+               return 0;             
+        }
+
+       if (CR_AREF(chanlist[0])==AREF_DIFF)
+               differencial=1;  // all input must be diff
+       if (CR_RANGE(chanlist[0])<PCI9118_BIPOLAR_RANGES)
+               bipolar=1;  // all input must be bipolar
+        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!");
+                               return 0;             
+                       }
+                       if ((CR_RANGE(chanlist[i])<PCI9118_BIPOLAR_RANGES)!=(bipolar)) {
+                               comedi_error(dev,"Bipolar and unipolar ranges cann't be mixture!");
+                               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!");
+                               return 0;             
+                       }
+               }
+               
+       // All is ok, so we can setup channel/range list
+
+       if (!bipolar) {
+           devpriv->AdControlReg|=AdControl_UniP;      // enable bipolar
+       } else {
+           devpriv->AdControlReg&=((~AdControl_UniP)&0xff);    // set unibipolar
+       }
+
+       if (differencial) {
+           devpriv->AdControlReg|=AdControl_UniP;      // enable diff inputs
+       } else {
+           devpriv->AdControlReg&=((~AdControl_Diff)&0xff);    // set single ended inputs
+       }
+
+        outl(devpriv->AdControlReg, dev->iobase+PCI9118_ADCNTRL); // setup mode
+
+       outl(2,dev->iobase+PCI9118_SCANMOD); // gods know why this sequence (disasembled from DOS driver)!
+       outl(0,dev->iobase+PCI9118_SCANMOD);
+       outl(1,dev->iobase+PCI9118_SCANMOD);
+       
+#ifdef PCL9118_PARANOIDCHECK
+       devpriv->chanlistlen=n_chan;
+#endif
+       
+       for (i=0; i<n_chan; i++) {  // store range list to card
+               scanquad=CR_CHAN(chanlist[i]);  // get channel number;
+#ifdef PCL9118_PARANOIDCHECK
+               devpriv->chanlist[i]=(scanquad & 0xf)<<rot;
+#endif
+               gain=CR_RANGE(chanlist[i]);             // get gain number
+               scanquad|=((gain & 0x03)<<8);
+               outl(scanquad,dev->iobase+PCI9118_GAIN);
+       }
+
+       outl(0,dev->iobase+PCI9118_SCANMOD);    // close scan queue
+       udelay(100);                            // important delay, or first sample will be cripled
+
+       return 1; // we can serve this with scan logic
+}
+
+
+/*
+==============================================================================
+*/
+void start_pacer(comedi_device * dev, int mode, unsigned int divisor1, unsigned int divisor2) 
+{
+        outl(0x74, dev->iobase + PCI9118_CNTCTRL);
+       outl(0x30, dev->iobase + PCI9118_CNTCTRL);
+        udelay(1);
+  
+        if ((mode==1)||(mode==2)||(mode==4)) {
+               outl(divisor2 & 0xff, dev->iobase + PCI9118_CNT2);
+               outl((divisor2 >> 8) & 0xff, dev->iobase + PCI9118_CNT2);
+               outl(divisor1  & 0xff, dev->iobase + PCI9118_CNT1);
+               outl((divisor1 >> 8) & 0xff, dev->iobase + PCI9118_CNT1);
+        }
+}
+
+/* 
+==============================================================================
+*/
+int pci9118_exttrg_add(comedi_device * dev, unsigned char source)
+{
+       if (source>3) return -1; // incorrect source
+       devpriv->exttrg_users|=(1<<source);
+       devpriv->IntControlReg|=Int_DTrg;
+       outl(devpriv->IntControlReg,dev->iobase+PCI9118_INTCTRL);
+       outl(inl(devpriv->iobase_a+AMCC_OP_REG_INTCSR)|0x1f00, devpriv->iobase_a+AMCC_OP_REG_INTCSR); // allow INT in AMCC
+       return 0;
+}
+
+/* 
+==============================================================================
+*/
+int pci9118_exttrg_del(comedi_device * dev, unsigned char source)
+{
+       if (source>3) return -1; // incorrect source
+       devpriv->exttrg_users&=~(1<<source);
+       if (!devpriv->exttrg_users) { // shutdown ext trg intterrupts
+               devpriv->IntControlReg&=~Int_DTrg;
+               if (!devpriv->IntControlReg) // all IRQ disabled
+                       outl(inl(devpriv->iobase_a+AMCC_OP_REG_INTCSR)&(~0x00001f00), devpriv->iobase_a+AMCC_OP_REG_INTCSR); // disable int in AMCC
+               outl(devpriv->IntControlReg,dev->iobase+PCI9118_INTCTRL);
+       }
+       return 0;
+}
+
+/* 
+==============================================================================
+*/
+int pci9118_ai_cancel(comedi_device * dev, comedi_subdevice * s)
+{
+       outl(inl(devpriv->iobase_a+AMCC_OP_REG_INTCSR)&(~AINT_WRITE_COMPL), devpriv->iobase_a+AMCC_OP_REG_INTCSR);      // stop amcc irqs
+       outl(inl(devpriv->iobase_a+AMCC_OP_REG_MCSR)&(~EN_A2P_TRANSFERS), devpriv->iobase_a+AMCC_OP_REG_MCSR); // stop DMA
+       pci9118_exttrg_del(dev,0);
+       start_pacer(dev,0,0,0);                 // stop 8254 counters
+       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
+       devpriv->AdControlReg=AdControl_Int;
+       outl(devpriv->AdControlReg,dev->iobase+PCI9118_ADCNTRL);// bipolar, S.E., use 8254, stop 8354, internal trigger, soft trigger, disable INT and DMA
+       outl(0,dev->iobase+PCI9118_BURST);
+       outl(1,dev->iobase+PCI9118_SCANMOD);
+       outl(2,dev->iobase+PCI9118_SCANMOD);// reset scan queue
+       outl(0,dev->iobase+PCI9118_DELFIFO); // flush FIFO
+
+       devpriv->ai_do=0;
+        devpriv->ai1234_act_scan=0;
+        s->cur_chan=0;
+        devpriv->ai1234_buf_ptr=0;
+        devpriv->neverending_ai=0;
+       devpriv->ai4_status=0;
+       devpriv->dma_actbuf=0;
+  
+       return 0;
+}
+
+/* 
+==============================================================================
+*/
+static int pci9118_reset(comedi_device *dev)
+{
+       devpriv->IntControlReg=0;
+       devpriv->exttrg_users=0;
+       inl(dev->iobase+PCI9118_INTCTRL);
+       outl(devpriv->IntControlReg,dev->iobase+PCI9118_INTCTRL);// disable interrupts source
+        outl(0xb4, dev->iobase + PCI9118_CNTCTRL);
+       start_pacer(dev,0,0,0);                 // stop 8254 counters
+       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
+       outl(0,dev->iobase+PCI9118_BURST);
+       outl(1,dev->iobase+PCI9118_SCANMOD);
+       outl(2,dev->iobase+PCI9118_SCANMOD);// reset scan queue
+       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
+
+       outl(2047,dev->iobase+PCI9118_DA1);// reset A/D outs to 0V
+       outl(2047,dev->iobase+PCI9118_DA2);
+       outl(0,dev->iobase+PCI9118_DO); // reset digi outs to L
+       udelay(10);
+       inl(dev->iobase+PCI9118_AD_DATA);
+       outl(0,dev->iobase+PCI9118_DELFIFO); // flush FIFO
+       inl(dev->iobase+PCI9118_ADSTAT); // flush A/D status register
+       inl(dev->iobase+PCI9118_INTSRC); // flush INT requests
+       devpriv->AdControlReg=AdControl_Int;
+       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;
+       devpriv->exttrg_users=0;
+       
+       return 0;
+}
+
+/* 
+==============================================================================
+*/
+static int pci9118_attach(comedi_device *dev,comedi_devconfig *it)
+{
+       comedi_subdevice *s;
+       int ret,pages,i;
+        unsigned int board,iobase_a,iobase_9,irq;
+       struct amcc_struct *card=NULL;
+       unsigned char pci_bus,pci_slot,pci_func;
+       unsigned int master;
+       
+        board=dev->board;
+       
+       rt_printk("comedi%d: adl_pci9118: board=%s",dev->minor,boardtypes[board].name);
+
+       if ((it->options[0]<1)&(it->options[1]<1)) { // use autodetection
+               if ((card=find_free_card_by_device(boardtypes[board].device_id))==NULL) {
+                       rt_printk(" - Unused card not found in system!\n");
+                       return -EIO;
+               }
+       } else {
+               switch (find_free_card_by_position(boardtypes[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 (alloc_amcc_card(card)!=0) {
+               rt_printk(" - Can't allocate card!\n");
+               return -EIO;
+       }
+       
+       if ((card_data(card,&pci_bus,&pci_slot,&pci_func,
+                           &iobase_a,&iobase_9,&irq,&master))<0) {
+               rt_printk(" - Can't get AMCC data!\n");
+               return -EIO;
+       }
+
+       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, boardtypes[board].iorange_9118) < 0) {
+               rt_printk("I/O port conflict\n");
+               return -EIO;
+        }
+
+        dev->iobase=iobase_9;
+        dev->iosize=boardtypes[board].iorange_9118;
+        request_region(dev->iobase, dev->iosize, "ADLink PCI-9118");
+    
+       dev->board_name = boardtypes[board].name;
+
+       if((ret=alloc_private(dev,sizeof(pci9118_private)))<0)
+               return -ENOMEM;
+
+       devpriv->amcc=card;
+       devpriv->master=master;
+       devpriv->iobase_a=iobase_a;
+       devpriv->iosize_a=boardtypes[board].iorange_amcc;
+        request_region(devpriv->iobase_a, devpriv->iosize_a, "ADLink PCI-9118");
+       
+       if (irq>0)  {
+               if (request_irq(irq, interrupt_pci9118, SA_INTERRUPT, "ADLink PCI-9118", dev)) {
+                       rt_printk(", unable to allocate IRQ %d, DISABLING IT", irq);
+                       irq=0; /* Can't use IRQ */
+               } else {
+                       rt_printk(", irq=%d", irq);
+               }    
+       } else {
+                       rt_printk(", IRQ disabled");
+       }
+
+        dev->irq = irq;
+
+       if (master) {   // alloc DMA buffers
+               devpriv->dma_doublebuf=0;
+               for (i=0; i<2; i++) {
+                       for (pages=4; pages>=0; pages--)
+                               if ((devpriv->dmabuf_virt[i]=__get_free_pages(GFP_KERNEL,4)))
+                                       break;
+                       if (devpriv->dmabuf_virt[i]) {
+                               devpriv->dmabuf_pages[i]=pages;
+                               devpriv->dmabuf_size[i]=PAGE_SIZE*pages;
+                               devpriv->dmabuf_samples[i]=devpriv->dmabuf_size[i]>>1;
+                               devpriv->dmabuf_hw[i]=virt_to_bus((void *)devpriv->dmabuf_virt[i]);
+                       }
+               }
+               if (!devpriv->dmabuf_virt[0]) {
+                       rt_printk(", Can't allocate DMA buffer, DMA disabled!");
+                       master=0;
+               }
+
+               if (devpriv->dmabuf_virt[1])
+                       devpriv->dma_doublebuf=0;
+
+       }
+       
+       if ((devpriv->master=master)) {
+               rt_printk(", bus master");
+       } else {
+               rt_printk(", no bus master");
+       }
+
+       devpriv->usemux=0;
+       if (it->options[2]>0)   {
+               devpriv->usemux=it->options[2];
+               if (devpriv->usemux>256) devpriv->usemux=256; // max 256 channels!
+               if (it->options[3]>0)
+                       if (devpriv->usemux>128) {
+                               devpriv->usemux=128; // max 128 channels with softare S&H!
+                       }
+               rt_printk(", ext. mux %d channels",devpriv->usemux);
+       }
+
+       printk(".\n");
+
+        dev->n_subdevices = 4;
+        if((ret=alloc_subdevices(dev))<0)
+               return ret;
+
+       s = dev->subdevices + 0;
+       s->type = COMEDI_SUBD_AI;
+       s->subdev_flags = SDF_READABLE|SDF_RT|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;
+       s->len_chanlist = this_board->n_aichanlist;
+       s->range_table = this_board->rangelist_ai;
+       s->cancel=pci9118_ai_cancel;
+#ifdef CONFIG_COMEDI_MODE0
+       s->trig[0] = pci9118_ai_mode0;
+#endif
+#ifdef CONFIG_COMEDI_MODES
+       if (irq&&master) {
+               s->trig[1] = pci9118_ai_mode1;
+               s->trig[2] = pci9118_ai_mode2;
+               s->trig[3] = pci9118_ai_mode3;
+               s->trig[4] = pci9118_ai_mode4;
+       } 
+#endif
+       s->insn_read=pci9118_insn_read_ai;
+       s->do_cmdtest=pci9118_ai_cmdtest;
+       s->do_cmd=pci9118_ai_cmd;
+
+       s = dev->subdevices + 1;
+       s->type = COMEDI_SUBD_AO;
+       s->subdev_flags = SDF_WRITEABLE|SDF_GROUND|SDF_COMMON|SDF_RT;
+       s->n_chan = this_board->n_aochan;
+       s->maxdata = this_board->ao_maxdata;
+       s->len_chanlist = this_board->n_aochan;
+       s->range_table = this_board->rangelist_ao;
+#ifdef CONFIG_COMEDI_MODE0
+       s->trig[0] = pci9118_ao_mode0;
+#endif
+       s->insn_write=pci9118_insn_write_ao;
+
+       s = dev->subdevices + 2;
+       s->type = COMEDI_SUBD_DI;
+       s->subdev_flags = SDF_READABLE|SDF_RT|SDF_GROUND|SDF_COMMON;
+       s->n_chan = 4;
+       s->maxdata = 1;
+       s->len_chanlist = 4;
+       s->range_table = &range_digital;
+#ifdef CONFIG_COMEDI_MODE0
+       s->trig[0] = pci9118_di_mode0;
+#endif
+       s->io_bits=0;           /* all bits input */
+       s->insn_read=pci9118_insn_read_di;
+       s->insn_bits=pci9118_insn_bits_di;
+
+       s = dev->subdevices + 3;
+       s->type = COMEDI_SUBD_DO;
+       s->subdev_flags = SDF_WRITEABLE|SDF_RT|SDF_GROUND|SDF_COMMON;
+       s->n_chan = 4;
+       s->maxdata = 1;
+       s->len_chanlist = 4;
+       s->range_table = &range_digital;
+#ifdef CONFIG_COMEDI_MODE0
+       s->trig[0] = pci9118_do_mode0;
+#endif
+       s->io_bits=0xf;         /* all bits output */
+       s->insn_write=pci9118_insn_write_do;
+       s->insn_bits=pci9118_insn_bits_do;
+
+       pci9118_reset(dev);
+
+       devpriv->valid=1;
+       devpriv->i8254_osc_base=250;    // 250ns=4MHz
+
+       return 0;
+}
+
+
+/* 
+==============================================================================
+*/
+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]);
+       }
+       
+       if(dev->irq){
+               free_irq(dev->irq,dev);
+       }
+
+       release_region(dev->iobase,dev->iosize);
+
+       return 0;
+}
+
+/* 
+==============================================================================
+*/
+static int pci9118_recognize(char *name) 
+{
+        int i;
+
+        for (i = 0; i < n_boardtypes; i++) {
+               if (!strcmp(boardtypes[i].name, name)) {
+                       return i;
+               }
+       }
+
+        return -1;
+}
+
+
+
+#ifdef MODULE
+/* 
+==============================================================================
+*/
+ int init_module(void)
+{
+       amcc_init();
+       comedi_driver_register(&driver_pci9118);
+       
+       return 0;
+}
+
+/* 
+==============================================================================
+*/
+void cleanup_module(void)
+{
+       comedi_driver_unregister(&driver_pci9118);
+       amcc_cleanup();
+
+}
+/* 
+==============================================================================
+*/
+
+#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)
+*/
\ No newline at end of file
diff --git a/comedi/drivers/amcc_s5933.h b/comedi/drivers/amcc_s5933.h
new file mode 100644 (file)
index 0000000..d28faeb
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+    module/amcc_s5933.h
+
+    Stuff for AMCC S5933 PCI Controller
+    
+    Author: Michal Dobes <majkl@tesnet.cz>
+
+    Inspirated from general-purpose AMCC S5933 PCI Matchmaker driver  
+    made by Andrea Cisternino  <acister@pcape1.pi.infn.it>
+    and as result of espionage from MITE code made by David A. Schleef.
+    Thanks to AMCC for their on-line documentation and bus master DMA
+    example.
+*/
+
+#ifndef _AMCC_S5933_H_
+#define _AMCC_S5933_H_
+
+#include <linux/pci.h>
+
+#ifdef PCI_SUPPORT_VER1
+    Sorry, no support for 2.1.55 and older! :-((((
+#endif
+
+
+/****************************************************************************/
+/* AMCC Operation Register Offsets - PCI                                    */
+/****************************************************************************/
+
+#define AMCC_OP_REG_OMB1         0x00
+#define AMCC_OP_REG_OMB2         0x04
+#define AMCC_OP_REG_OMB3         0x08
+#define AMCC_OP_REG_OMB4         0x0c
+#define AMCC_OP_REG_IMB1         0x10
+#define AMCC_OP_REG_IMB2         0x14
+#define AMCC_OP_REG_IMB3         0x18
+#define AMCC_OP_REG_IMB4         0x1c
+#define AMCC_OP_REG_FIFO         0x20
+#define AMCC_OP_REG_MWAR         0x24
+#define AMCC_OP_REG_MWTC         0x28
+#define AMCC_OP_REG_MRAR         0x2c
+#define AMCC_OP_REG_MRTC         0x30
+#define AMCC_OP_REG_MBEF         0x34
+#define AMCC_OP_REG_INTCSR       0x38
+#define  AMCC_OP_REG_INTCSR_SRC  (AMCC_OP_REG_INTCSR + 2) /* INT source */
+#define  AMCC_OP_REG_INTCSR_FEC  (AMCC_OP_REG_INTCSR + 3) /* FIFO ctrl */
+#define AMCC_OP_REG_MCSR         0x3c
+#define  AMCC_OP_REG_MCSR_NVDATA (AMCC_OP_REG_MCSR + 2) /* Data in byte 2 */
+#define  AMCC_OP_REG_MCSR_NVCMD  (AMCC_OP_REG_MCSR + 3) /* Command in byte 3 */
+
+#define AMCC_FIFO_DEPTH_DWORD  8
+#define AMCC_FIFO_DEPTH_BYTES  (8 * sizeof (u32))
+
+/****************************************************************************/
+/* AMCC Operation Registers Size - PCI                                      */
+/****************************************************************************/
+
+#define AMCC_OP_REG_SIZE        64     /* in bytes */
+
+/****************************************************************************/
+/* AMCC Operation Register Offsets - Add-on                                 */
+/****************************************************************************/
+
+#define AMCC_OP_REG_AIMB1         0x00
+#define AMCC_OP_REG_AIMB2         0x04
+#define AMCC_OP_REG_AIMB3         0x08
+#define AMCC_OP_REG_AIMB4         0x0c
+#define AMCC_OP_REG_AOMB1         0x10
+#define AMCC_OP_REG_AOMB2         0x14
+#define AMCC_OP_REG_AOMB3         0x18
+#define AMCC_OP_REG_AOMB4         0x1c
+#define AMCC_OP_REG_AFIFO         0x20
+#define AMCC_OP_REG_AMWAR         0x24
+#define AMCC_OP_REG_APTA          0x28
+#define AMCC_OP_REG_APTD          0x2c
+#define AMCC_OP_REG_AMRAR         0x30
+#define AMCC_OP_REG_AMBEF         0x34
+#define AMCC_OP_REG_AINT          0x38
+#define AMCC_OP_REG_AGCSTS        0x3c
+#define AMCC_OP_REG_AMWTC         0x58
+#define AMCC_OP_REG_AMRTC         0x5c
+
+/****************************************************************************/
+/* AMCC - Add-on General Control/Status Register                            */
+/****************************************************************************/
+
+#define AGCSTS_CONTROL_MASK    0xfffff000
+#define  AGCSTS_NV_ACC_MASK    0xe0000000
+#define  AGCSTS_RESET_MASK     0x0e000000
+#define  AGCSTS_NV_DA_MASK     0x00ff0000
+#define  AGCSTS_BIST_MASK      0x0000f000
+#define AGCSTS_STATUS_MASK     0x000000ff
+#define  AGCSTS_TCZERO_MASK    0x000000c0
+#define  AGCSTS_FIFO_ST_MASK   0x0000003f
+
+#define AGCSTS_RESET_MBFLAGS   0x08000000
+#define AGCSTS_RESET_P2A_FIFO  0x04000000
+#define AGCSTS_RESET_A2P_FIFO  0x02000000
+#define AGCSTS_RESET_FIFOS     (AGCSTS_RESET_A2P_FIFO | AGCSTS_RESET_P2A_FIFO)
+
+#define AGCSTS_A2P_TCOUNT      0x00000080
+#define AGCSTS_P2A_TCOUNT      0x00000040
+
+#define AGCSTS_FS_P2A_EMPTY    0x00000020
+#define AGCSTS_FS_P2A_HALF     0x00000010
+#define AGCSTS_FS_P2A_FULL     0x00000008
+
+#define AGCSTS_FS_A2P_EMPTY    0x00000004
+#define AGCSTS_FS_A2P_HALF     0x00000002
+#define AGCSTS_FS_A2P_FULL     0x00000001
+
+/****************************************************************************/
+/* AMCC - Add-on Interrupt Control/Status Register                            */
+/****************************************************************************/
+
+#define AINT_INT_MASK          0x00ff0000
+#define AINT_SEL_MASK          0x0000ffff
+#define  AINT_IS_ENSEL_MASK    0x00001f1f
+
+#define AINT_INT_ASSERTED      0x00800000
+#define AINT_BM_ERROR          0x00200000
+#define AINT_BIST_INT          0x00100000
+
+#define AINT_RT_COMPLETE       0x00080000
+#define AINT_WT_COMPLETE       0x00040000
+
+#define AINT_OUT_MB_INT                0x00020000
+#define AINT_IN_MB_INT         0x00010000
+
+#define AINT_READ_COMPL                0x00008000
+#define AINT_WRITE_COMPL       0x00004000
+
+#define AINT_OMB_ENABLE        0x00001000
+#define AINT_OMB_SELECT        0x00000c00
+#define AINT_OMB_BYTE          0x00000300
+
+#define AINT_IMB_ENABLE        0x00000010
+#define AINT_IMB_SELECT        0x0000000c
+#define AINT_IMB_BYTE          0x00000003
+
+/* Enable Bus Mastering */
+#define EN_A2P_TRANSFERS       0x00000400
+/* FIFO Flag Reset */
+#define RESET_A2P_FLAGS                0x04000000L
+/* FIFO Relative Priority */
+#define A2P_HI_PRIORITY                0x00000100L
+/* Identify Interrupt Sources */
+#define ANY_S593X_INT          0x00800000L
+#define READ_TC_INT            0x00080000L
+#define WRITE_TC_INT           0x00040000L
+#define IN_MB_INT              0x00020000L
+#define MASTER_ABORT_INT       0x00100000L
+#define TARGET_ABORT_INT       0x00200000L
+#define BUS_MASTER_INT         0x00200000L
+
+/****************************************************************************/
+
+struct amcc_struct{
+       struct          amcc_struct *next;
+       int             used;
+       struct pci_dev  *pcidev;
+       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    irq;
+};
+
+struct amcc_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,
+       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);
+
+/****************************************************************************/
+
+/* build list of amcc cards in this system */
+void amcc_init(void)
+{
+       struct pci_dev *pcidev;
+       struct amcc_struct *amcc,*last;
+
+       amcc_devices=NULL;
+       last=NULL;
+       
+#if LINUX_VERSION_CODE < 0x020300
+       for(pcidev=pci_devices;pcidev;pcidev=pcidev->next){
+#else
+       pci_for_each_dev(pcidev){
+#endif
+               if(pcidev->vendor==PCI_VENDOR_ID_AMCC){
+                       amcc=kmalloc(sizeof(*amcc),GFP_KERNEL);
+                       memset(amcc,0,sizeof(*amcc));
+
+                       amcc->pcidev=pcidev;
+                       if (last) { last->next=amcc; }
+                            else { amcc_devices=amcc; }
+                       last=amcc;
+                       
+#if LINUX_VERSION_CODE < 0x020300
+                       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;
+                       amcc->irq=pcidev->irq;
+#else
+                       amcc->device=???;
+                       amcc->master=???;
+                       amcc->pci_bus=???;
+                       amcc->pci_slot=???;
+                       amcc->pci_func=???;
+                       amcc->amcc_io_addr=pcidev->resource[0].start & ~3UL;
+                       amcc->daq_io_addr=pcidev->resource[2].start & ~3UL;
+                       amcc->irq=???;
+#endif
+                       
+               }
+       }
+
+#if 0
+       display_amcc_cards();
+#endif
+}
+
+/****************************************************************************/
+/* free up list of amcc cards in this system */
+void amcc_cleanup(void)
+{
+       struct amcc_struct *amcc,*next;
+
+       for(amcc=amcc_devices;amcc;amcc=next){
+               next=amcc->next;
+               kfree(amcc);
+       }
+       
+       amcc_devices=NULL;
+}
+
+/****************************************************************************/
+/* find first unused card with this device_id */
+struct amcc_struct *find_free_card_by_device(unsigned short device_id)
+{
+       struct amcc_struct *amcc,*next;
+
+       for (amcc=amcc_devices;amcc;amcc=next) {
+               next=amcc->next;
+               if ((!amcc->used)&&(amcc->device==device_id)) return amcc;
+               
+       }
+
+       return NULL;
+}
+
+/****************************************************************************/
+/* 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)
+{
+       struct amcc_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->used)) {
+                               *card=amcc;
+                               return 0;       // ok, card is found
+                       } else {
+                               return 2;       // card exist but is used
+                       }
+               }
+       }
+
+        return 1; // no card found
+}
+
+/****************************************************************************/
+/* mark card as used */
+int alloc_amcc_card(struct amcc_struct *amcc)
+{
+       if (!amcc) return -1;
+
+       if (amcc->used) return 1;
+       amcc->used=1;
+       return 0;
+}
+
+/****************************************************************************/
+/* mark card as free */
+int free_amcc_card(struct amcc_struct *amcc)
+{
+       if (!amcc) return -1;
+
+       if (!amcc->used) return 1;
+       amcc->used=0;
+       return 0;
+}
+
+/****************************************************************************/
+/* display list of found cards */
+void display_amcc_cards(void)
+{
+       struct amcc_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");
+
+       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);
+               
+       }
+}
+
+/****************************************************************************/
+/* return all card information for driver */
+int card_data(struct amcc_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)
+{
+       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;
+       *irq=amcc->irq;
+       *master=amcc->master;
+       return 0;
+}
+
+#endif
index a12fa125ef1c9c23627450a67cb0a9beb8f1f181..1ca510306383503b2f7e6abcc1f0ff6d0fa37fd5 100644 (file)
@@ -152,6 +152,13 @@ CONFIG_COMEDI_PARPORT
   cause your printer to stop working.  This driver is not
   compatible with the generic Linux parallel port interface.
 
+ADLink PCI-9118DG/HR/HG driver
+CONFIG_COMEDI_ADLPCI9118
+  Includes support for these ADLink cards:
+    ADLink PCI-9118DG
+    ADLink PCI-9118HR
+    ADLink PCI-9118HG
+  
 PCL 711 driver
 CONFIG_COMEDI_PCL711
   Includes support for PCL 711, 711b and ACL 8112.
@@ -170,9 +177,10 @@ PCL 726 driver
 CONFIG_COMEDI_PCL726
   Includes support for PCL 726.
 
-Advantech PCL-812PG, PCL-813B
+Advantech PCL-812PG, PCL-813B, ADLink ACL-8113
 CONFIG_COMEDI_PCL812
-  Includes support for PCL-812PG and PCL813B.
+  Includes support for Advantech PCL-812PG, Advantech PCL-813B
+  and ADLink ACL-8113.
 
 Advantech PCL-818, PCL-718
 CONFIG_COMEDI_PCL818