aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/comedi/drivers/adl_pci9118.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/comedi/drivers/adl_pci9118.c')
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9118.c2084
1 files changed, 873 insertions, 1211 deletions
diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c
index f30b84e1987b..e18fd9569a2b 100644
--- a/drivers/staging/comedi/drivers/adl_pci9118.c
+++ b/drivers/staging/comedi/drivers/adl_pci9118.c
@@ -36,8 +36,8 @@
* b) DMA transfers must have the length aligned to two samples (32 bit),
* so there is some problems if cmd->chanlist_len is odd. This driver tries
* bypass this with adding one sample to the end of the every scan and discard
- * it on output but this cann't be used if cmd->scan_begin_src=TRIG_FOLLOW
- * and is used flag TRIG_WAKE_EOS, then driver switch to interrupt driven mode
+ * it on output but this can't be used if cmd->scan_begin_src=TRIG_FOLLOW
+ * and is used flag CMDF_WAKE_EOS, then driver switch to interrupt driven mode
* with interrupt after every sample.
* c) If isn't used DMA then you can use only mode where
* cmd->scan_begin_src=TRIG_FOLLOW.
@@ -49,19 +49,13 @@
* card will be used.
* [2] - 0= standard 8 DIFF/16 SE channels configuration
* n = external multiplexer connected, 1 <= n <= 256
- * [3] - 0=autoselect DMA or EOC interrupts operation
- * 1 = disable DMA mode
- * 3 = disable DMA and INT, only insn interface will work
+ * [3] - ignored
* [4] - sample&hold signal - card can generate signal for external S&H board
* 0 = use SSHO(pin 45) signal is generated in onboard hardware S&H logic
* 0 != use ADCHN7(pin 23) signal is generated from driver, number say how
* long delay is requested in ns and sign polarity of the hold
* (in this case external multiplexor can serve only 128 channels)
- * [5] - 0=stop measure on all hardware errors
- * 2 | = ignore ADOR - A/D Overrun status
- * 8|=ignore Bover - A/D Burst Mode Overrun status
- * 256|=ignore nFull - A/D FIFO Full status
- *
+ * [5] - ignored
*/
/*
@@ -91,111 +85,68 @@
#include "8253.h"
#include "comedi_fc.h"
-/* paranoid checks are broken */
-#undef PCI9118_PARANOIDCHECK /*
- * if defined, then is used code which control
- * correct channel number on every 12 bit sample
- */
-
#define IORANGE_9118 64 /* I hope */
#define PCI9118_CHANLEN 255 /*
* len of chanlist, some source say 256,
* but reality looks like 255 :-(
*/
-#define PCI9118_CNT0 0x00 /* R/W: 8254 counter 0 */
-#define PCI9118_CNT1 0x04 /* R/W: 8254 counter 0 */
-#define PCI9118_CNT2 0x08 /* R/W: 8254 counter 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=controlled 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 */
+/*
+ * PCI BAR2 Register map (dev->iobase)
+ */
+#define PCI9118_TIMER_REG(x) (0x00 + ((x) * 4))
+#define PCI9118_TIMER_CTRL_REG 0x0c
+#define PCI9118_AI_FIFO_REG 0x10
+#define PCI9118_AO_REG(x) (0x10 + ((x) * 4))
+#define PCI9118_AI_STATUS_REG 0x18
+#define PCI9118_AI_STATUS_NFULL (1 << 8) /* 0=FIFO full (fatal) */
+#define PCI9118_AI_STATUS_NHFULL (1 << 7) /* 0=FIFO half full */
+#define PCI9118_AI_STATUS_NEPTY (1 << 6) /* 0=FIFO empty */
+#define PCI9118_AI_STATUS_ACMP (1 << 5) /* 1=about trigger complete */
+#define PCI9118_AI_STATUS_DTH (1 << 4) /* 1=ext. digital trigger */
+#define PCI9118_AI_STATUS_BOVER (1 << 3) /* 1=burst overrun (fatal) */
+#define PCI9118_AI_STATUS_ADOS (1 << 2) /* 1=A/D over speed (warn) */
+#define PCI9118_AI_STATUS_ADOR (1 << 1) /* 1=A/D overrun (fatal) */
+#define PCI9118_AI_STATUS_ADRDY (1 << 0) /* 1=A/D ready */
+#define PCI9118_AI_CTRL_REG 0x18
+#define PCI9118_AI_CTRL_UNIP (1 << 7) /* 1=unipolar */
+#define PCI9118_AI_CTRL_DIFF (1 << 6) /* 1=differential inputs */
+#define PCI9118_AI_CTRL_SOFTG (1 << 5) /* 1=8254 software gate */
+#define PCI9118_AI_CTRL_EXTG (1 << 4) /* 1=8254 TGIN(pin 46) gate */
+#define PCI9118_AI_CTRL_EXTM (1 << 3) /* 1=ext. trigger (pin 44) */
+#define PCI9118_AI_CTRL_TMRTR (1 << 2) /* 1=8254 is trigger source */
+#define PCI9118_AI_CTRL_INT (1 << 1) /* 1=enable interrupt */
+#define PCI9118_AI_CTRL_DMA (1 << 0) /* 1=enable DMA */
+#define PCI9118_DIO_REG 0x1c
+#define PCI9118_SOFTTRG_REG 0x20
+#define PCI9118_AI_CHANLIST_REG 0x24
+#define PCI9118_AI_CHANLIST_RANGE(x) (((x) & 0x3) << 8)
+#define PCI9118_AI_CHANLIST_CHAN(x) ((x) << 0)
+#define PCI9118_AI_BURST_NUM_REG 0x28
+#define PCI9118_AI_AUTOSCAN_MODE_REG 0x2c
+#define PCI9118_AI_CFG_REG 0x30
+#define PCI9118_AI_CFG_PDTRG (1 << 7) /* 1=positive trigger */
+#define PCI9118_AI_CFG_PETRG (1 << 6) /* 1=positive ext. trigger */
+#define PCI9118_AI_CFG_BSSH (1 << 5) /* 1=with sample & hold */
+#define PCI9118_AI_CFG_BM (1 << 4) /* 1=burst mode */
+#define PCI9118_AI_CFG_BS (1 << 3) /* 1=burst mode start */
+#define PCI9118_AI_CFG_PM (1 << 2) /* 1=post trigger */
+#define PCI9118_AI_CFG_AM (1 << 1) /* 1=about trigger */
+#define PCI9118_AI_CFG_START (1 << 0) /* 1=trigger start */
+#define PCI9118_FIFO_RESET_REG 0x34
+#define PCI9118_INT_CTRL_REG 0x38
+#define PCI9118_INT_CTRL_TIMER (1 << 3) /* timer interrupt */
+#define PCI9118_INT_CTRL_ABOUT (1 << 2) /* about trigger complete */
+#define PCI9118_INT_CTRL_HFULL (1 << 1) /* A/D FIFO half full */
+#define PCI9118_INT_CTRL_DTRG (1 << 0) /* ext. digital trigger */
#define START_AI_EXT 0x01 /* start measure on external trigger */
#define STOP_AI_EXT 0x02 /* stop measure on external trigger */
-#define START_AI_INT 0x04 /* start measure on internal trigger */
#define STOP_AI_INT 0x08 /* stop measure on internal trigger */
-#define EXTTRG_AI 0 /* ext trg is used by AI */
+#define PCI9118_HALF_FIFO_SZ (1024 / 2)
-static const struct comedi_lrange range_pci9118dg_hr = {
+static const struct comedi_lrange pci9118_ai_range = {
8, {
BIP_RANGE(5),
BIP_RANGE(2.5),
@@ -208,7 +159,7 @@ static const struct comedi_lrange range_pci9118dg_hr = {
}
};
-static const struct comedi_lrange range_pci9118hg = {
+static const struct comedi_lrange pci9118hg_ai_range = {
8, {
BIP_RANGE(5),
BIP_RANGE(0.5),
@@ -226,102 +177,49 @@ static const struct comedi_lrange range_pci9118hg = {
* of BIP/UNI ranges
*/
-struct boardtype {
- const char *name; /* board name */
- int device_id; /* PCI device ID of card */
- 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 */
- const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */
- const 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)
- */
- int half_fifo_size; /* size of FIFO/2 */
+enum pci9118_boardid {
+ BOARD_PCI9118DG,
+ BOARD_PCI9118HG,
+ BOARD_PCI9118HR,
+};
+struct pci9118_boardinfo {
+ const char *name;
+ unsigned int ai_is_16bit:1;
+ unsigned int is_hg:1;
};
-static const struct boardtype boardtypes[] = {
- {
+static const struct pci9118_boardinfo pci9118_boards[] = {
+ [BOARD_PCI9118DG] = {
.name = "pci9118dg",
- .device_id = 0x80d9,
- .iorange_amcc = AMCC_OP_REG_SIZE,
- .iorange_9118 = IORANGE_9118,
- .n_aichan = 16,
- .n_aichand = 8,
- .mux_aichan = 256,
- .n_aichanlist = PCI9118_CHANLEN,
- .n_aochan = 2,
- .ai_maxdata = 0x0fff,
- .ao_maxdata = 0x0fff,
- .rangelist_ai = &range_pci9118dg_hr,
- .rangelist_ao = &range_bipolar10,
- .ai_ns_min = 3000,
- .ai_pacer_min = 12,
- .half_fifo_size = 512,
- }, {
+ },
+ [BOARD_PCI9118HG] = {
.name = "pci9118hg",
- .device_id = 0x80d9,
- .iorange_amcc = AMCC_OP_REG_SIZE,
- .iorange_9118 = IORANGE_9118,
- .n_aichan = 16,
- .n_aichand = 8,
- .mux_aichan = 256,
- .n_aichanlist = PCI9118_CHANLEN,
- .n_aochan = 2,
- .ai_maxdata = 0x0fff,
- .ao_maxdata = 0x0fff,
- .rangelist_ai = &range_pci9118hg,
- .rangelist_ao = &range_bipolar10,
- .ai_ns_min = 3000,
- .ai_pacer_min = 12,
- .half_fifo_size = 512,
- }, {
+ .is_hg = 1,
+ },
+ [BOARD_PCI9118HR] = {
.name = "pci9118hr",
- .device_id = 0x80d9,
- .iorange_amcc = AMCC_OP_REG_SIZE,
- .iorange_9118 = IORANGE_9118,
- .n_aichan = 16,
- .n_aichand = 8,
- .mux_aichan = 256,
- .n_aichanlist = PCI9118_CHANLEN,
- .n_aochan = 2,
- .ai_maxdata = 0xffff,
- .ao_maxdata = 0x0fff,
- .rangelist_ai = &range_pci9118dg_hr,
- .rangelist_ao = &range_bipolar10,
- .ai_ns_min = 10000,
- .ai_pacer_min = 40,
- .half_fifo_size = 512,
+ .ai_is_16bit = 1,
},
};
+struct pci9118_dmabuf {
+ unsigned short *virt; /* virtual address of buffer */
+ dma_addr_t hw; /* hardware (bus) address of buffer */
+ unsigned int size; /* size of dma buffer in bytes */
+ unsigned int use_size; /* which size we may now use for transfer */
+};
+
struct pci9118_private {
unsigned long iobase_a; /* base+size for AMCC chip */
- unsigned int master; /* master capable */
- unsigned int usemux; /* we want to use external multiplexor! */
-#ifdef PCI9118_PARANOIDCHECK
- unsigned short chanlist[PCI9118_CHANLEN + 1]; /*
- * list of
- * scanned 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 ai_neverending; /* we do unlimited AI */
+ unsigned int master:1;
+ unsigned int dma_doublebuf:1;
+ unsigned int ai_neverending:1;
+ unsigned int usedma:1;
+ unsigned int usemux:1;
+ unsigned char ai_ctrl;
+ unsigned char int_ctrl;
+ unsigned char ai_cfg;
unsigned int ai_do; /* what do AI? 0=nothing, 1 to 4 mode */
unsigned int ai_act_scan; /* how many scans we finished */
unsigned int ai_n_realscanlen; /*
@@ -346,29 +244,8 @@ struct pci9118_private {
* divisors for start of measure
* on external start
*/
- unsigned short ao_data[2]; /* data output buffer */
- char dma_doublebuf; /* use double buffering */
unsigned int dma_actbuf; /* which buffer is used now */
- unsigned short *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 we may now use
- * for transfer
- */
- unsigned int dmabuf_used_size[2]; /* which size was truly used */
- unsigned int dmabuf_panic_size[2];
- int dmabuf_pages[2]; /* number of pages in buffer */
- unsigned char exttrg_users; /*
- * bit field of external trigger
- * users(0-AI, 1-AO, 2-DI, 3-DO)
- */
- unsigned char usedma; /* =1 use DMA transfer and not INT */
+ struct pci9118_dmabuf dmabuf[2];
int softsshdelay; /*
* >0 use software S&H,
* numer is requested delay in ns
@@ -381,15 +258,74 @@ struct pci9118_private {
* polarity of S&H signal
* in hold state
*/
- unsigned int ai_maskerr; /* which warning was printed */
- unsigned int ai_maskharderr; /* on which error bits stops */
+ unsigned int ai_ns_min;
};
+static void pci9118_amcc_setup_dma(struct comedi_device *dev, unsigned int buf)
+{
+ struct pci9118_private *devpriv = dev->private;
+ struct pci9118_dmabuf *dmabuf = &devpriv->dmabuf[buf];
+
+ /* set the master write address and transfer count */
+ outl(dmabuf->hw, devpriv->iobase_a + AMCC_OP_REG_MWAR);
+ outl(dmabuf->use_size, devpriv->iobase_a + AMCC_OP_REG_MWTC);
+}
+
+static void pci9118_amcc_dma_ena(struct comedi_device *dev, bool enable)
+{
+ struct pci9118_private *devpriv = dev->private;
+ unsigned int mcsr;
+
+ mcsr = inl(devpriv->iobase_a + AMCC_OP_REG_MCSR);
+ if (enable)
+ mcsr |= RESET_A2P_FLAGS | A2P_HI_PRIORITY | EN_A2P_TRANSFERS;
+ else
+ mcsr &= ~EN_A2P_TRANSFERS;
+ outl(mcsr, devpriv->iobase_a + AMCC_OP_REG_MCSR);
+}
+
+static void pci9118_amcc_int_ena(struct comedi_device *dev, bool enable)
+{
+ struct pci9118_private *devpriv = dev->private;
+ unsigned int intcsr;
+
+ /* enable/disable interrupt for AMCC Incoming Mailbox 4 (32-bit) */
+ intcsr = inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR);
+ if (enable)
+ intcsr |= 0x1f00;
+ else
+ intcsr &= ~0x1f00;
+ outl(intcsr, devpriv->iobase_a + AMCC_OP_REG_INTCSR);
+}
+
+static void pci9118_timer_write(struct comedi_device *dev,
+ unsigned int timer, unsigned int val)
+{
+ outl(val & 0xff, dev->iobase + PCI9118_TIMER_REG(timer));
+ outl((val >> 8) & 0xff, dev->iobase + PCI9118_TIMER_REG(timer));
+}
+
+static void pci9118_timer_set_mode(struct comedi_device *dev,
+ unsigned int timer, unsigned int mode)
+{
+ unsigned int val;
+
+ val = timer << 6; /* select timer */
+ val |= 0x30; /* load low then high byte */
+ val |= mode; /* set timer mode and BCD|binary */
+ outl(val, dev->iobase + PCI9118_TIMER_CTRL_REG);
+}
+
+static void pci9118_ai_reset_fifo(struct comedi_device *dev)
+{
+ /* writing any value resets the A/D FIFO */
+ outl(0, dev->iobase + PCI9118_FIFO_RESET_REG);
+}
+
static int check_channel_list(struct comedi_device *dev,
struct comedi_subdevice *s, int n_chan,
unsigned int *chanlist, int frontadd, int backadd)
{
- const struct boardtype *this_board = comedi_board(dev);
struct pci9118_private *devpriv = dev->private;
unsigned int i, differencial = 0, bipolar = 0;
@@ -423,7 +359,7 @@ static int check_channel_list(struct comedi_device *dev,
return 0;
}
if (!devpriv->usemux && differencial &&
- (CR_CHAN(chanlist[i]) >= this_board->n_aichand)) {
+ (CR_CHAN(chanlist[i]) >= (s->n_chan / 2))) {
dev_err(dev->class_dev,
"AREF_DIFF is only available for the first 8 channels!\n");
return 0;
@@ -433,234 +369,82 @@ static int check_channel_list(struct comedi_device *dev,
return 1;
}
-static int setup_channel_list(struct comedi_device *dev,
- struct comedi_subdevice *s, int n_chan,
- unsigned int *chanlist, int rot, int frontadd,
- int backadd, int usedma)
+static void pci9118_set_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ int n_chan, unsigned int *chanlist,
+ int frontadd, int backadd)
{
struct pci9118_private *devpriv = dev->private;
- unsigned int i, differencial = 0, bipolar = 0;
- unsigned int scanquad, gain, ssh = 0x00;
-
- if (usedma == 1) {
- rot = 8;
- usedma = 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 */
-
- /* All is ok, so we can setup channel/range list */
-
- if (!bipolar) {
- devpriv->AdControlReg |= AdControl_UniP;
- /* set unibipolar */
- } else {
- devpriv->AdControlReg &= ((~AdControl_UniP) & 0xff);
- /* enable bipolar */
- }
-
- if (differencial) {
- devpriv->AdControlReg |= AdControl_Diff;
- /* enable diff inputs */
- } else {
- devpriv->AdControlReg &= ((~AdControl_Diff) & 0xff);
- /* set single ended inputs */
- }
-
- outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL);
- /* setup mode */
+ unsigned int chan0 = CR_CHAN(chanlist[0]);
+ unsigned int range0 = CR_RANGE(chanlist[0]);
+ unsigned int aref0 = CR_AREF(chanlist[0]);
+ unsigned int ssh = 0x00;
+ unsigned int val;
+ int i;
- outl(2, dev->iobase + PCI9118_SCANMOD);
- /* gods know why this sequence! */
- outl(0, dev->iobase + PCI9118_SCANMOD);
- outl(1, dev->iobase + PCI9118_SCANMOD);
-
-#ifdef PCI9118_PARANOIDCHECK
- devpriv->chanlistlen = n_chan;
- for (i = 0; i < (PCI9118_CHANLEN + 1); i++)
- devpriv->chanlist[i] = 0x55aa;
-#endif
-
- if (frontadd) { /* insert channels for S&H */
+ /*
+ * Configure analog input based on the first chanlist entry.
+ * All entries are either unipolar or bipolar and single-ended
+ * or differential.
+ */
+ devpriv->ai_ctrl = 0;
+ if (comedi_range_is_unipolar(s, range0))
+ devpriv->ai_ctrl |= PCI9118_AI_CTRL_UNIP;
+ if (aref0 == AREF_DIFF)
+ devpriv->ai_ctrl |= PCI9118_AI_CTRL_DIFF;
+ outl(devpriv->ai_ctrl, dev->iobase + PCI9118_AI_CTRL_REG);
+
+ /* gods know why this sequence! */
+ outl(2, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
+ outl(0, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
+ outl(1, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
+
+ /* insert channels for S&H */
+ if (frontadd) {
+ val = PCI9118_AI_CHANLIST_CHAN(chan0) |
+ PCI9118_AI_CHANLIST_RANGE(range0);
ssh = devpriv->softsshsample;
for (i = 0; i < frontadd; i++) {
- /* store range list to card */
- scanquad = CR_CHAN(chanlist[0]);
- /* get channel number; */
- gain = CR_RANGE(chanlist[0]);
- /* get gain number */
- scanquad |= ((gain & 0x03) << 8);
- outl(scanquad | ssh, dev->iobase + PCI9118_GAIN);
+ outl(val | ssh, dev->iobase + PCI9118_AI_CHANLIST_REG);
ssh = devpriv->softsshhold;
}
}
- for (i = 0; i < n_chan; i++) { /* store range list to card */
- scanquad = CR_CHAN(chanlist[i]); /* get channel number */
-#ifdef PCI9118_PARANOIDCHECK
- devpriv->chanlist[i ^ usedma] = (scanquad & 0xf) << rot;
-#endif
- gain = CR_RANGE(chanlist[i]); /* get gain number */
- scanquad |= ((gain & 0x03) << 8);
- outl(scanquad | ssh, dev->iobase + PCI9118_GAIN);
- }
+ /* store chanlist */
+ for (i = 0; i < n_chan; i++) {
+ unsigned int chan = CR_CHAN(chanlist[i]);
+ unsigned int range = CR_RANGE(chanlist[i]);
- if (backadd) { /* insert channels for fit onto 32bit DMA */
- for (i = 0; i < backadd; i++) { /* store range list to card */
- scanquad = CR_CHAN(chanlist[0]);
- /* get channel number */
- gain = CR_RANGE(chanlist[0]); /* get gain number */
- scanquad |= ((gain & 0x03) << 8);
- outl(scanquad | ssh, dev->iobase + PCI9118_GAIN);
- }
+ val = PCI9118_AI_CHANLIST_CHAN(chan) |
+ PCI9118_AI_CHANLIST_RANGE(range);
+ outl(val | ssh, dev->iobase + PCI9118_AI_CHANLIST_REG);
}
-#ifdef PCI9118_PARANOIDCHECK
- devpriv->chanlist[n_chan ^ usedma] = devpriv->chanlist[0 ^ usedma];
- /* for 32bit operations */
-#endif
- outl(0, dev->iobase + PCI9118_SCANMOD); /* close scan queue */
- /* udelay(100); important delay, or first sample will be crippled */
-
- return 1; /* we can serve this with scan logic */
-}
-
-static int pci9118_ai_eoc(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned long context)
-{
- unsigned int status;
-
- status = inl(dev->iobase + PCI9118_ADSTAT);
- if (status & AdStatus_ADrdy)
- return 0;
- return -EBUSY;
-}
-
-static int pci9118_insn_read_ai(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct pci9118_private *devpriv = dev->private;
- int ret;
- int n;
-
- 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 (!setup_channel_list(dev, s, 1, &insn->chanspec, 0, 0, 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(2);
-
- ret = comedi_timeout(dev, s, insn, pci9118_ai_eoc, 0);
- if (ret) {
- outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */
- return ret;
- }
-
- if (s->maxdata == 0xffff) {
- data[n] =
- (inl(dev->iobase +
- PCI9118_AD_DATA) & 0xffff) ^ 0x8000;
- } else {
- data[n] =
- (inw(dev->iobase + PCI9118_AD_DATA) >> 4) & 0xfff;
- }
- }
-
- outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */
- return n;
-
-}
-
-static int pci9118_insn_write_ao(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct pci9118_private *devpriv = dev->private;
- int n, chanreg, ch;
-
- 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];
+ /* insert channels to fit onto 32bit DMA */
+ if (backadd) {
+ val = PCI9118_AI_CHANLIST_CHAN(chan0) |
+ PCI9118_AI_CHANLIST_RANGE(range0);
+ for (i = 0; i < backadd; i++)
+ outl(val | ssh, dev->iobase + PCI9118_AI_CHANLIST_REG);
}
-
- return n;
-}
-
-static int pci9118_insn_read_ao(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct pci9118_private *devpriv = dev->private;
- int n, chan;
-
- chan = CR_CHAN(insn->chanspec);
- for (n = 0; n < insn->n; n++)
- data[n] = devpriv->ao_data[chan];
-
- return n;
-}
-
-static int pci9118_insn_bits_di(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- data[1] = inl(dev->iobase + PCI9118_DI) & 0xf;
-
- return insn->n;
-}
-
-static int pci9118_insn_bits_do(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- if (comedi_dio_update_state(s, data))
- outl(s->state & 0x0f, dev->iobase + PCI9118_DO);
-
- data[1] = s->state;
-
- return insn->n;
+ /* close scan queue */
+ outl(0, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
+ /* udelay(100); important delay, or first sample will be crippled */
}
-static void interrupt_pci9118_ai_mode4_switch(struct comedi_device *dev)
+static void interrupt_pci9118_ai_mode4_switch(struct comedi_device *dev,
+ unsigned int next_buf)
{
struct pci9118_private *devpriv = dev->private;
-
- devpriv->AdFunctionReg =
- AdFunction_PDTrg | AdFunction_PETrg | AdFunction_AM;
- outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC);
- outl(0x30, dev->iobase + PCI9118_CNTCTRL);
- outl((devpriv->dmabuf_hw[1 - devpriv->dma_actbuf] >> 1) & 0xff,
- dev->iobase + PCI9118_CNT0);
- outl((devpriv->dmabuf_hw[1 - devpriv->dma_actbuf] >> 9) & 0xff,
- dev->iobase + PCI9118_CNT0);
- devpriv->AdFunctionReg |= AdFunction_Start;
- outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC);
+ struct pci9118_dmabuf *dmabuf = &devpriv->dmabuf[next_buf];
+
+ devpriv->ai_cfg = PCI9118_AI_CFG_PDTRG | PCI9118_AI_CFG_PETRG |
+ PCI9118_AI_CFG_AM;
+ outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
+ pci9118_timer_set_mode(dev, 0, I8254_MODE0);
+ pci9118_timer_write(dev, 0, dmabuf->hw >> 1);
+ devpriv->ai_cfg |= PCI9118_AI_CFG_START;
+ outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
}
static unsigned int defragment_dma_buffer(struct comedi_device *dev,
@@ -689,9 +473,9 @@ static unsigned int defragment_dma_buffer(struct comedi_device *dev,
}
static int move_block_from_dma(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned short *dma_buffer,
- unsigned int num_samples)
+ struct comedi_subdevice *s,
+ unsigned short *dma_buffer,
+ unsigned int num_samples)
{
struct pci9118_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
@@ -710,100 +494,59 @@ static int move_block_from_dma(struct comedi_device *dev,
return 0;
}
-static int pci9118_exttrg_add(struct comedi_device *dev, unsigned char source)
+static void pci9118_exttrg_enable(struct comedi_device *dev, bool enable)
{
struct pci9118_private *devpriv = dev->private;
- 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;
-}
-
-static int pci9118_exttrg_del(struct comedi_device *dev, unsigned char source)
-{
- struct pci9118_private *devpriv = dev->private;
+ if (enable)
+ devpriv->int_ctrl |= PCI9118_INT_CTRL_DTRG;
+ else
+ devpriv->int_ctrl &= ~PCI9118_INT_CTRL_DTRG;
+ outl(devpriv->int_ctrl, dev->iobase + PCI9118_INT_CTRL_REG);
- 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;
+ if (devpriv->int_ctrl)
+ pci9118_amcc_int_ena(dev, true);
+ else
+ pci9118_amcc_int_ena(dev, false);
}
-static void pci9118_calc_divisors(char mode, struct comedi_device *dev,
+static void pci9118_calc_divisors(struct comedi_device *dev,
struct comedi_subdevice *s,
unsigned int *tim1, unsigned int *tim2,
unsigned int flags, int chans,
unsigned int *div1, unsigned int *div2,
unsigned int chnsshfront)
{
- const struct boardtype *this_board = comedi_board(dev);
struct comedi_cmd *cmd = &s->async->cmd;
- switch (mode) {
- case 1:
- case 4:
- if (*tim2 < this_board->ai_ns_min)
- *tim2 = this_board->ai_ns_min;
- i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ,
- div1, div2,
- tim2, flags & TRIG_ROUND_NEAREST);
- break;
- case 2:
- if (*tim2 < this_board->ai_ns_min)
- *tim2 = this_board->ai_ns_min;
- *div1 = *tim2 / I8254_OSC_BASE_4MHZ;
- /* convert timer (burst) */
- if (*div1 < this_board->ai_pacer_min)
- *div1 = this_board->ai_pacer_min;
- *div2 = *tim1 / I8254_OSC_BASE_4MHZ; /* scan timer */
- *div2 = *div2 / *div1; /* major timer is c1*c2 */
- if (*div2 < chans)
- *div2 = chans;
-
- *tim2 = *div1 * I8254_OSC_BASE_4MHZ; /* real convert timer */
-
- if (cmd->convert_src == TRIG_NOW && !chnsshfront) {
- /* use BSSH signal */
- if (*div2 < (chans + 2))
- *div2 = chans + 2;
- }
+ *div1 = *tim2 / I8254_OSC_BASE_4MHZ; /* convert timer (burst) */
+ *div2 = *tim1 / I8254_OSC_BASE_4MHZ; /* scan timer */
+ *div2 = *div2 / *div1; /* major timer is c1*c2 */
+ if (*div2 < chans)
+ *div2 = chans;
- *tim1 = *div1 * *div2 * I8254_OSC_BASE_4MHZ;
- break;
+ *tim2 = *div1 * I8254_OSC_BASE_4MHZ; /* real convert timer */
+
+ if (cmd->convert_src == TRIG_NOW && !chnsshfront) {
+ /* use BSSH signal */
+ if (*div2 < (chans + 2))
+ *div2 = chans + 2;
}
+
+ *tim1 = *div1 * *div2 * I8254_OSC_BASE_4MHZ;
}
static void pci9118_start_pacer(struct comedi_device *dev, int mode)
{
struct pci9118_private *devpriv = dev->private;
- unsigned int divisor1 = devpriv->ai_divisor1;
- unsigned int divisor2 = devpriv->ai_divisor2;
- outl(0x74, dev->iobase + PCI9118_CNTCTRL);
- outl(0xb4, dev->iobase + PCI9118_CNTCTRL);
-/* outl(0x30, dev->iobase + PCI9118_CNTCTRL); */
+ pci9118_timer_set_mode(dev, 1, I8254_MODE2);
+ pci9118_timer_set_mode(dev, 2, I8254_MODE2);
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);
+ pci9118_timer_write(dev, 2, devpriv->ai_divisor2);
+ pci9118_timer_write(dev, 1, devpriv->ai_divisor1);
}
}
@@ -813,29 +556,24 @@ static int pci9118_ai_cancel(struct comedi_device *dev,
struct pci9118_private *devpriv = dev->private;
if (devpriv->usedma)
- 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, EXTTRG_AI);
+ pci9118_amcc_dma_ena(dev, false);
+ pci9118_exttrg_enable(dev, false);
pci9118_start_pacer(dev, 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 = 0x00;
- 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 */
+ /* set default config (disable burst and triggers) */
+ devpriv->ai_cfg = PCI9118_AI_CFG_PDTRG | PCI9118_AI_CFG_PETRG;
+ outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
+ /* reset acqusition control */
+ devpriv->ai_ctrl = 0;
+ outl(devpriv->ai_ctrl, dev->iobase + PCI9118_AI_CTRL_REG);
+ outl(0, dev->iobase + PCI9118_AI_BURST_NUM_REG);
+ /* reset scan queue */
+ outl(1, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
+ outl(2, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
+ pci9118_ai_reset_fifo(dev);
+
+ devpriv->int_ctrl = 0;
+ outl(devpriv->int_ctrl, dev->iobase + PCI9118_INT_CTRL_REG);
+ pci9118_amcc_int_ena(dev, false);
devpriv->ai_do = 0;
devpriv->usedma = 0;
@@ -847,44 +585,6 @@ static int pci9118_ai_cancel(struct comedi_device *dev,
devpriv->ai_neverending = 0;
devpriv->dma_actbuf = 0;
- if (!devpriv->IntControlReg)
- outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00,
- devpriv->iobase_a + AMCC_OP_REG_INTCSR);
- /* allow INT in AMCC */
-
- return 0;
-}
-
-static char pci9118_decode_error_status(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned char m)
-{
- struct pci9118_private *devpriv = dev->private;
-
- if (m & 0x100) {
- dev_err(dev->class_dev,
- "A/D FIFO Full status (Fatal Error!)\n");
- devpriv->ai_maskerr &= ~0x100L;
- }
- if (m & 0x008) {
- dev_err(dev->class_dev,
- "A/D Burst Mode Overrun Status (Fatal Error!)\n");
- devpriv->ai_maskerr &= ~0x008L;
- }
- if (m & 0x004) {
- dev_err(dev->class_dev, "A/D Over Speed Status (Warning!)\n");
- devpriv->ai_maskerr &= ~0x004L;
- }
- if (m & 0x002) {
- dev_err(dev->class_dev, "A/D Overrun Status (Fatal Error!)\n");
- devpriv->ai_maskerr &= ~0x002L;
- }
- if (m & devpriv->ai_maskharderr) {
- s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- cfc_handle_events(dev, s);
- return 1;
- }
-
return 0;
}
@@ -909,35 +609,14 @@ static void pci9118_ai_munge(struct comedi_device *dev,
}
static void interrupt_pci9118_ai_onesample(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned short int_adstat,
- unsigned int int_amcc,
- unsigned short int_daq)
+ struct comedi_subdevice *s)
{
struct pci9118_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
unsigned short sampl;
- if (int_adstat & devpriv->ai_maskerr)
- if (pci9118_decode_error_status(dev, s, int_adstat))
- return;
-
- sampl = inw(dev->iobase + PCI9118_AD_DATA);
+ sampl = inl(dev->iobase + PCI9118_AI_FIFO_REG);
-#ifdef PCI9118_PARANOIDCHECK
- if (s->maxdata != 0xffff) {
- if ((sampl & 0x000f) != devpriv->chanlist[s->async->cur_chan]) {
- /* data dropout! */
- dev_info(dev->class_dev,
- "A/D SAMPL - data dropout: received channel %d, expected %d!\n",
- sampl & 0x000f,
- devpriv->chanlist[s->async->cur_chan]);
- s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- cfc_handle_events(dev, s);
- return;
- }
- }
-#endif
cfc_write_to_buffer(s, sampl);
s->async->cur_chan++;
if (s->async->cur_chan >= cmd->scan_end_arg) {
@@ -950,63 +629,33 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev,
s->async->events |= COMEDI_CB_EOA;
}
}
-
- cfc_handle_events(dev, s);
}
static void interrupt_pci9118_ai_dma(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned short int_adstat,
- unsigned int int_amcc,
- unsigned short int_daq)
+ struct comedi_subdevice *s)
{
struct pci9118_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
+ struct pci9118_dmabuf *dmabuf = &devpriv->dmabuf[devpriv->dma_actbuf];
unsigned int next_dma_buf, samplesinbuf, sampls, m;
- if (int_amcc & MASTER_ABORT_INT) {
- dev_err(dev->class_dev, "AMCC IRQ - MASTER DMA ABORT!\n");
- s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- cfc_handle_events(dev, s);
- return;
- }
-
- if (int_amcc & TARGET_ABORT_INT) {
- dev_err(dev->class_dev, "AMCC IRQ - TARGET DMA ABORT!\n");
- s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- cfc_handle_events(dev, s);
- return;
- }
- if (int_adstat & devpriv->ai_maskerr)
- /* if (int_adstat & 0x106) */
- if (pci9118_decode_error_status(dev, s, int_adstat))
- return;
-
- samplesinbuf = devpriv->dmabuf_use_size[devpriv->dma_actbuf] >> 1;
- /* number of received real samples */
+ samplesinbuf = dmabuf->use_size >> 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);
- devpriv->dmabuf_used_size[next_dma_buf] =
- devpriv->dmabuf_use_size[next_dma_buf];
+ pci9118_amcc_setup_dma(dev, next_dma_buf);
if (devpriv->ai_do == 4)
- interrupt_pci9118_ai_mode4_switch(dev);
+ interrupt_pci9118_ai_mode4_switch(dev, next_dma_buf);
}
if (samplesinbuf) {
/* how many samples is to end of buffer */
m = s->async->prealloc_bufsz >> 1;
sampls = m;
- move_block_from_dma(dev, s,
- devpriv->dmabuf_virt[devpriv->dma_actbuf],
- samplesinbuf);
+ move_block_from_dma(dev, s, dmabuf->virt, samplesinbuf);
m = m - sampls; /* m=how many samples was transferred */
}
@@ -1016,18 +665,15 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev,
s->async->events |= COMEDI_CB_EOA;
}
- if (devpriv->dma_doublebuf) { /* switch dma buffers */
+ 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);
+ } else {
+ /* restart DMA if is not used double buffering */
+ pci9118_amcc_setup_dma(dev, 0);
if (devpriv->ai_do == 4)
- interrupt_pci9118_ai_mode4_switch(dev);
+ interrupt_pci9118_ai_mode4_switch(dev, 0);
}
-
- cfc_handle_events(dev, s);
}
static irqreturn_t pci9118_interrupt(int irq, void *d)
@@ -1042,7 +688,7 @@ static irqreturn_t pci9118_interrupt(int irq, void *d)
if (!dev->attached)
return IRQ_NONE;
- intsrc = inl(dev->iobase + PCI9118_INTSRC) & 0xf;
+ intsrc = inl(dev->iobase + PCI9118_INT_CTRL_REG) & 0xf;
intcsr = inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR);
if (!intsrc && !(intcsr & ANY_S593X_INT))
@@ -1050,28 +696,63 @@ static irqreturn_t pci9118_interrupt(int irq, void *d)
outl(intcsr | 0x00ff0000, devpriv->iobase_a + AMCC_OP_REG_INTCSR);
- adstat = inw(dev->iobase + PCI9118_ADSTAT) & 0x1ff;
+ if (intcsr & MASTER_ABORT_INT) {
+ dev_err(dev->class_dev, "AMCC IRQ - MASTER DMA ABORT!\n");
+ s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ goto interrupt_exit;
+ }
+
+ if (intcsr & TARGET_ABORT_INT) {
+ dev_err(dev->class_dev, "AMCC IRQ - TARGET DMA ABORT!\n");
+ s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ goto interrupt_exit;
+ }
+
+ adstat = inl(dev->iobase + PCI9118_AI_STATUS_REG);
+ if ((adstat & PCI9118_AI_STATUS_NFULL) == 0) {
+ dev_err(dev->class_dev,
+ "A/D FIFO Full status (Fatal Error!)\n");
+ s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW;
+ goto interrupt_exit;
+ }
+ if (adstat & PCI9118_AI_STATUS_BOVER) {
+ dev_err(dev->class_dev,
+ "A/D Burst Mode Overrun Status (Fatal Error!)\n");
+ s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW;
+ goto interrupt_exit;
+ }
+ if (adstat & PCI9118_AI_STATUS_ADOS) {
+ dev_err(dev->class_dev, "A/D Over Speed Status (Warning!)\n");
+ s->async->events |= COMEDI_CB_ERROR;
+ goto interrupt_exit;
+ }
+ if (adstat & PCI9118_AI_STATUS_ADOR) {
+ dev_err(dev->class_dev, "A/D Overrun Status (Fatal Error!)\n");
+ s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW;
+ goto interrupt_exit;
+ }
if (!devpriv->ai_do)
return IRQ_HANDLED;
if (devpriv->ai12_startstop) {
- if ((adstat & AdStatus_DTH) && (intsrc & Int_DTrg)) {
+ if ((adstat & PCI9118_AI_STATUS_DTH) &&
+ (intsrc & PCI9118_INT_CTRL_DTRG)) {
/* start/stop of measure */
if (devpriv->ai12_startstop & START_AI_EXT) {
/* deactivate EXT trigger */
devpriv->ai12_startstop &= ~START_AI_EXT;
if (!(devpriv->ai12_startstop & STOP_AI_EXT))
- pci9118_exttrg_del(dev, EXTTRG_AI);
+ pci9118_exttrg_enable(dev, false);
/* start pacer */
pci9118_start_pacer(dev, devpriv->ai_do);
- outl(devpriv->AdControlReg,
- dev->iobase + PCI9118_ADCNTRL);
+ outl(devpriv->ai_ctrl,
+ dev->iobase + PCI9118_AI_CTRL_REG);
} else if (devpriv->ai12_startstop & STOP_AI_EXT) {
/* deactivate EXT trigger */
devpriv->ai12_startstop &= ~STOP_AI_EXT;
- pci9118_exttrg_del(dev, EXTTRG_AI);
+ pci9118_exttrg_enable(dev, false);
/* on next interrupt measure will stop */
devpriv->ai_neverending = 0;
@@ -1080,198 +761,41 @@ static irqreturn_t pci9118_interrupt(int irq, void *d)
}
if (devpriv->usedma)
- interrupt_pci9118_ai_dma(dev, s, adstat, intcsr, intsrc);
+ interrupt_pci9118_ai_dma(dev, s);
else
- interrupt_pci9118_ai_onesample(dev, s, adstat, intcsr, intsrc);
+ interrupt_pci9118_ai_onesample(dev, s);
+interrupt_exit:
+ cfc_handle_events(dev, s);
return IRQ_HANDLED;
}
-static int pci9118_ai_inttrig(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int trig_num)
+static void pci9118_ai_cmd_start(struct comedi_device *dev)
{
struct pci9118_private *devpriv = dev->private;
- struct comedi_cmd *cmd = &s->async->cmd;
-
- if (trig_num != cmd->start_arg)
- return -EINVAL;
-
- devpriv->ai12_startstop &= ~START_AI_INT;
- s->async->inttrig = NULL;
- outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL);
- outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC);
+ outl(devpriv->int_ctrl, dev->iobase + PCI9118_INT_CTRL_REG);
+ outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
if (devpriv->ai_do != 3) {
pci9118_start_pacer(dev, devpriv->ai_do);
- devpriv->AdControlReg |= AdControl_SoftG;
+ devpriv->ai_ctrl |= PCI9118_AI_CTRL_SOFTG;
}
- outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL);
-
- return 1;
+ outl(devpriv->ai_ctrl, dev->iobase + PCI9118_AI_CTRL_REG);
}
-static int pci9118_ai_cmdtest(struct comedi_device *dev,
+static int pci9118_ai_inttrig(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_cmd *cmd)
+ unsigned int trig_num)
{
- const struct boardtype *this_board = comedi_board(dev);
- struct pci9118_private *devpriv = dev->private;
- int err = 0;
- unsigned int flags;
- unsigned int arg;
- unsigned int divisor1 = 0, divisor2 = 0;
-
- /* Step 1 : check if triggers are trivially valid */
-
- err |= cfc_check_trigger_src(&cmd->start_src,
- TRIG_NOW | TRIG_EXT | TRIG_INT);
-
- flags = TRIG_FOLLOW;
- if (devpriv->master)
- flags |= TRIG_TIMER | TRIG_EXT;
- err |= cfc_check_trigger_src(&cmd->scan_begin_src, flags);
-
- flags = TRIG_TIMER | TRIG_EXT;
- if (devpriv->master)
- flags |= TRIG_NOW;
- err |= cfc_check_trigger_src(&cmd->convert_src, flags);
-
- err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
- err |= cfc_check_trigger_src(&cmd->stop_src,
- TRIG_COUNT | TRIG_NONE | TRIG_EXT);
-
- if (err)
- return 1;
-
- /* Step 2a : make sure trigger sources are unique */
-
- err |= cfc_check_trigger_is_unique(cmd->start_src);
- err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
- err |= cfc_check_trigger_is_unique(cmd->convert_src);
- err |= cfc_check_trigger_is_unique(cmd->stop_src);
-
- /* Step 2b : and mutually compatible */
-
- if (cmd->start_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT)
- err |= -EINVAL;
-
- if (cmd->start_src == TRIG_INT && cmd->scan_begin_src == TRIG_INT)
- err |= -EINVAL;
-
- if ((cmd->scan_begin_src & (TRIG_TIMER | TRIG_EXT)) &&
- (!(cmd->convert_src & (TRIG_TIMER | TRIG_NOW))))
- err |= -EINVAL;
-
- if ((cmd->scan_begin_src == TRIG_FOLLOW) &&
- (!(cmd->convert_src & (TRIG_TIMER | TRIG_EXT))))
- err |= -EINVAL;
-
- if (cmd->stop_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT)
- err |= -EINVAL;
-
- if (err)
- return 2;
-
- /* Step 3: check if arguments are trivially valid */
-
- switch (cmd->start_src) {
- case TRIG_NOW:
- case TRIG_EXT:
- err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
- break;
- case TRIG_INT:
- /* start_arg is the internal trigger (any value) */
- break;
- }
-
- if (cmd->scan_begin_src & (TRIG_FOLLOW | TRIG_EXT))
- err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
-
- if ((cmd->scan_begin_src == TRIG_TIMER) &&
- (cmd->convert_src == TRIG_TIMER) && (cmd->scan_end_arg == 1)) {
- cmd->scan_begin_src = TRIG_FOLLOW;
- cmd->convert_arg = cmd->scan_begin_arg;
- cmd->scan_begin_arg = 0;
- }
-
- if (cmd->scan_begin_src == TRIG_TIMER)
- err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
- this_board->ai_ns_min);
-
- if (cmd->scan_begin_src == TRIG_EXT)
- if (cmd->scan_begin_arg) {
- cmd->scan_begin_arg = 0;
- err |= -EINVAL;
- err |= cfc_check_trigger_arg_max(&cmd->scan_end_arg,
- 65535);
- }
-
- if (cmd->convert_src & (TRIG_TIMER | TRIG_NOW))
- err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
- this_board->ai_ns_min);
-
- if (cmd->convert_src == TRIG_EXT)
- err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
-
- if (cmd->stop_src == TRIG_COUNT)
- err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
- else /* TRIG_NONE */
- err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
-
- err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1);
-
- err |= cfc_check_trigger_arg_min(&cmd->scan_end_arg,
- cmd->chanlist_len);
-
- if ((cmd->scan_end_arg % cmd->chanlist_len)) {
- cmd->scan_end_arg =
- cmd->chanlist_len * (cmd->scan_end_arg / cmd->chanlist_len);
- err |= -EINVAL;
- }
-
- if (err)
- return 3;
-
- /* step 4: fix up any arguments */
-
- if (cmd->scan_begin_src == TRIG_TIMER) {
- arg = cmd->scan_begin_arg;
- i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ,
- &divisor1, &divisor2,
- &arg, cmd->flags);
- err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
- }
-
- if (cmd->convert_src & (TRIG_TIMER | TRIG_NOW)) {
- arg = cmd->convert_arg;
- i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ,
- &divisor1, &divisor2,
- &arg, cmd->flags);
- err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
-
- if (cmd->scan_begin_src == TRIG_TIMER &&
- cmd->convert_src == TRIG_NOW) {
- if (cmd->convert_arg == 0) {
- arg = this_board->ai_ns_min *
- (cmd->scan_end_arg + 2);
- } else {
- arg = cmd->convert_arg * cmd->chanlist_len;
- }
- err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
- arg);
- }
- }
+ struct comedi_cmd *cmd = &s->async->cmd;
- if (err)
- return 4;
+ if (trig_num != cmd->start_arg)
+ return -EINVAL;
- if (cmd->chanlist)
- if (!check_channel_list(dev, s, cmd->chanlist_len,
- cmd->chanlist, 0, 0))
- return 5; /* incorrect channels list */
+ s->async->inttrig = NULL;
+ pci9118_ai_cmd_start(dev);
- return 0;
+ return 1;
}
static int Compute_and_setup_dma(struct comedi_device *dev,
@@ -1279,10 +803,12 @@ static int Compute_and_setup_dma(struct comedi_device *dev,
{
struct pci9118_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
+ struct pci9118_dmabuf *dmabuf0 = &devpriv->dmabuf[0];
+ struct pci9118_dmabuf *dmabuf1 = &devpriv->dmabuf[1];
unsigned int dmalen0, dmalen1, i;
- dmalen0 = devpriv->dmabuf_size[0];
- dmalen1 = devpriv->dmabuf_size[1];
+ dmalen0 = dmabuf0->size;
+ dmalen1 = dmabuf1->size;
/* isn't output buff smaller that our DMA buff? */
if (dmalen0 > s->async->prealloc_bufsz) {
/* align to 32bit down */
@@ -1294,12 +820,12 @@ static int Compute_and_setup_dma(struct comedi_device *dev,
}
/* we want wake up every scan? */
- if (devpriv->ai_flags & TRIG_WAKE_EOS) {
+ if (devpriv->ai_flags & CMDF_WAKE_EOS) {
if (dmalen0 < (devpriv->ai_n_realscanlen << 1)) {
/* uff, too short DMA buffer, disable EOS support! */
- devpriv->ai_flags &= (~TRIG_WAKE_EOS);
+ devpriv->ai_flags &= (~CMDF_WAKE_EOS);
dev_info(dev->class_dev,
- "WAR: DMA0 buf too short, can't support TRIG_WAKE_EOS (%d<%d)\n",
+ "WAR: DMA0 buf too short, can't support CMDF_WAKE_EOS (%d<%d)\n",
dmalen0, devpriv->ai_n_realscanlen << 1);
} else {
/* short first DMA buffer to one scan */
@@ -1312,12 +838,12 @@ static int Compute_and_setup_dma(struct comedi_device *dev,
}
}
}
- if (devpriv->ai_flags & TRIG_WAKE_EOS) {
+ if (devpriv->ai_flags & CMDF_WAKE_EOS) {
if (dmalen1 < (devpriv->ai_n_realscanlen << 1)) {
/* uff, too short DMA buffer, disable EOS support! */
- devpriv->ai_flags &= (~TRIG_WAKE_EOS);
+ devpriv->ai_flags &= (~CMDF_WAKE_EOS);
dev_info(dev->class_dev,
- "WAR: DMA1 buf too short, can't support TRIG_WAKE_EOS (%d<%d)\n",
+ "WAR: DMA1 buf too short, can't support CMDF_WAKE_EOS (%d<%d)\n",
dmalen1, devpriv->ai_n_realscanlen << 1);
} else {
/* short second DMA buffer to one scan */
@@ -1331,8 +857,8 @@ static int Compute_and_setup_dma(struct comedi_device *dev,
}
}
- /* transfer without TRIG_WAKE_EOS */
- if (!(devpriv->ai_flags & TRIG_WAKE_EOS)) {
+ /* transfer without CMDF_WAKE_EOS */
+ if (!(devpriv->ai_flags & CMDF_WAKE_EOS)) {
/* if it's possible then align DMA buffers to length of scan */
i = dmalen0;
dmalen0 =
@@ -1378,37 +904,16 @@ static int Compute_and_setup_dma(struct comedi_device *dev,
/* these DMA buffer size will be used */
devpriv->dma_actbuf = 0;
- devpriv->dmabuf_use_size[0] = dmalen0;
- devpriv->dmabuf_use_size[1] = dmalen1;
-
-#if 0
- if (cmd->scan_end_arg < this_board->half_fifo_size) {
- devpriv->dmabuf_panic_size[0] =
- (this_board->half_fifo_size / cmd->scan_end_arg +
- 1) * cmd->scan_end_arg * sizeof(short);
- devpriv->dmabuf_panic_size[1] =
- (this_board->half_fifo_size / cmd->scan_end_arg +
- 1) * cmd->scan_end_arg * sizeof(short);
- } else {
- devpriv->dmabuf_panic_size[0] =
- (cmd->scan_end_arg << 1) % devpriv->dmabuf_size[0];
- devpriv->dmabuf_panic_size[1] =
- (cmd->scan_end_arg << 1) % devpriv->dmabuf_size[1];
- }
-#endif
+ dmabuf0->use_size = dmalen0;
+ dmabuf1->use_size = dmalen1;
- outl(inl(devpriv->iobase_a + AMCC_OP_REG_MCSR) & (~EN_A2P_TRANSFERS),
- devpriv->iobase_a + AMCC_OP_REG_MCSR); /* stop DMA */
- 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);
+ pci9118_amcc_dma_ena(dev, false);
+ pci9118_amcc_setup_dma(dev, 0);
/* init DMA transfer */
outl(0x00000000 | AINT_WRITE_COMPL,
devpriv->iobase_a + AMCC_OP_REG_INTCSR);
/* 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);
+ pci9118_amcc_dma_ena(dev, true);
outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | EN_A2P_TRANSFERS,
devpriv->iobase_a + AMCC_OP_REG_INTCSR);
/* allow bus mastering */
@@ -1416,135 +921,16 @@ static int Compute_and_setup_dma(struct comedi_device *dev,
return 0;
}
-static int pci9118_ai_docmd_sampl(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- struct pci9118_private *devpriv = dev->private;
-
- switch (devpriv->ai_do) {
- case 1:
- devpriv->AdControlReg |= AdControl_TmrTr;
- break;
- case 2:
- dev_err(dev->class_dev, "%s mode 2 bug!\n", __func__);
- return -EIO;
- case 3:
- devpriv->AdControlReg |= AdControl_ExtM;
- break;
- case 4:
- dev_err(dev->class_dev, "%s mode 4 bug!\n", __func__);
- return -EIO;
- default:
- dev_err(dev->class_dev, "%s mode number bug!\n", __func__);
- return -EIO;
- }
-
- if (devpriv->ai12_startstop)
- pci9118_exttrg_add(dev, EXTTRG_AI);
- /* activate EXT trigger */
-
- if ((devpriv->ai_do == 1) || (devpriv->ai_do == 2))
- devpriv->IntControlReg |= Int_Timer;
-
- devpriv->AdControlReg |= AdControl_Int;
-
- outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00,
- devpriv->iobase_a + AMCC_OP_REG_INTCSR);
- /* allow INT in AMCC */
-
- if (!(devpriv->ai12_startstop & (START_AI_EXT | START_AI_INT))) {
- outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL);
- outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC);
- if (devpriv->ai_do != 3) {
- pci9118_start_pacer(dev, devpriv->ai_do);
- devpriv->AdControlReg |= AdControl_SoftG;
- }
- outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL);
- }
-
- return 0;
-}
-
-static int pci9118_ai_docmd_dma(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- struct pci9118_private *devpriv = dev->private;
- struct comedi_cmd *cmd = &s->async->cmd;
-
- Compute_and_setup_dma(dev, s);
-
- switch (devpriv->ai_do) {
- case 1:
- devpriv->AdControlReg |=
- ((AdControl_TmrTr | AdControl_Dma) & 0xff);
- break;
- case 2:
- devpriv->AdControlReg |=
- ((AdControl_TmrTr | AdControl_Dma) & 0xff);
- devpriv->AdFunctionReg =
- AdFunction_PDTrg | AdFunction_PETrg | AdFunction_BM |
- AdFunction_BS;
- if (cmd->convert_src == TRIG_NOW && !devpriv->softsshdelay)
- devpriv->AdFunctionReg |= AdFunction_BSSH;
- outl(devpriv->ai_n_realscanlen, dev->iobase + PCI9118_BURST);
- break;
- case 3:
- devpriv->AdControlReg |=
- ((AdControl_ExtM | AdControl_Dma) & 0xff);
- devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg;
- break;
- case 4:
- devpriv->AdControlReg |=
- ((AdControl_TmrTr | AdControl_Dma) & 0xff);
- devpriv->AdFunctionReg =
- AdFunction_PDTrg | AdFunction_PETrg | AdFunction_AM;
- outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC);
- outl(0x30, dev->iobase + PCI9118_CNTCTRL);
- outl((devpriv->dmabuf_hw[0] >> 1) & 0xff,
- dev->iobase + PCI9118_CNT0);
- outl((devpriv->dmabuf_hw[0] >> 9) & 0xff,
- dev->iobase + PCI9118_CNT0);
- devpriv->AdFunctionReg |= AdFunction_Start;
- break;
- default:
- dev_err(dev->class_dev, "%s mode number bug!\n", __func__);
- return -EIO;
- }
-
- if (devpriv->ai12_startstop) {
- pci9118_exttrg_add(dev, EXTTRG_AI);
- /* activate EXT trigger */
- }
-
- outl(0x02000000 | AINT_WRITE_COMPL,
- devpriv->iobase_a + AMCC_OP_REG_INTCSR);
-
- if (!(devpriv->ai12_startstop & (START_AI_EXT | START_AI_INT))) {
- outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC);
- outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL);
- if (devpriv->ai_do != 3) {
- pci9118_start_pacer(dev, devpriv->ai_do);
- devpriv->AdControlReg |= AdControl_SoftG;
- }
- outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL);
- }
-
- return 0;
-}
-
static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
- const struct boardtype *this_board = comedi_board(dev);
struct pci9118_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
unsigned int addchans = 0;
- int ret = 0;
devpriv->ai12_startstop = 0;
devpriv->ai_flags = cmd->flags;
devpriv->ai_add_front = 0;
devpriv->ai_add_back = 0;
- devpriv->ai_maskerr = 0x10e;
/* prepare for start/stop conditions */
if (cmd->start_src == TRIG_EXT)
@@ -1553,10 +939,6 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->ai_neverending = 1;
devpriv->ai12_startstop |= STOP_AI_EXT;
}
- if (cmd->start_src == TRIG_INT) {
- devpriv->ai12_startstop |= START_AI_INT;
- s->async->inttrig = pci9118_ai_inttrig;
- }
if (cmd->stop_src == TRIG_NONE)
devpriv->ai_neverending = 1;
if (cmd->stop_src == TRIG_COUNT)
@@ -1570,7 +952,7 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->ai_add_back = 0;
if (devpriv->master) {
devpriv->usedma = 1;
- if ((cmd->flags & TRIG_WAKE_EOS) &&
+ if ((cmd->flags & CMDF_WAKE_EOS) &&
(cmd->scan_end_arg == 1)) {
if (cmd->convert_src == TRIG_NOW)
devpriv->ai_add_back = 1;
@@ -1582,7 +964,7 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
*/
}
}
- if ((cmd->flags & TRIG_WAKE_EOS) &&
+ if ((cmd->flags & CMDF_WAKE_EOS) &&
(cmd->scan_end_arg & 1) &&
(cmd->scan_end_arg > 1)) {
if (cmd->scan_begin_src == TRIG_FOLLOW) {
@@ -1612,8 +994,8 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->ai_add_front++;
devpriv->ai_add_back = 0;
}
- if (cmd->convert_arg < this_board->ai_ns_min)
- cmd->convert_arg = this_board->ai_ns_min;
+ if (cmd->convert_arg < devpriv->ai_ns_min)
+ cmd->convert_arg = devpriv->ai_ns_min;
addchans = devpriv->softsshdelay / cmd->convert_arg;
if (devpriv->softsshdelay % cmd->convert_arg)
addchans++;
@@ -1642,171 +1024,432 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
cmd->chanlist, devpriv->ai_add_front,
devpriv->ai_add_back))
return -EINVAL;
- if (!setup_channel_list(dev, s, cmd->chanlist_len,
- cmd->chanlist, 0, devpriv->ai_add_front,
- devpriv->ai_add_back, devpriv->usedma))
- return -EINVAL;
- /* compute timers settings */
/*
- * simplest way, fr=4Mhz/(tim1*tim2),
- * channel manipulation without timers effect
+ * Configure analog input and load the chanlist.
+ * The acqusition control bits are enabled later.
*/
- if (((cmd->scan_begin_src == TRIG_FOLLOW) ||
- (cmd->scan_begin_src == TRIG_EXT) ||
- (cmd->scan_begin_src == TRIG_INT)) &&
- (cmd->convert_src == TRIG_TIMER)) {
- /* both timer is used for one time */
+ pci9118_set_chanlist(dev, s, cmd->chanlist_len, cmd->chanlist,
+ devpriv->ai_add_front, devpriv->ai_add_back);
+
+ /* Determine acqusition mode and calculate timing */
+ devpriv->ai_do = 0;
+ if (cmd->scan_begin_src != TRIG_TIMER &&
+ cmd->convert_src == TRIG_TIMER) {
+ /* cascaded timers 1 and 2 are used for convert timing */
if (cmd->scan_begin_src == TRIG_EXT)
devpriv->ai_do = 4;
else
devpriv->ai_do = 1;
- pci9118_calc_divisors(devpriv->ai_do, dev, s,
- &cmd->scan_begin_arg, &cmd->convert_arg,
- devpriv->ai_flags,
- devpriv->ai_n_realscanlen,
- &devpriv->ai_divisor1,
- &devpriv->ai_divisor2,
- devpriv->ai_add_front);
+
+ i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ,
+ &devpriv->ai_divisor1,
+ &devpriv->ai_divisor2,
+ &cmd->convert_arg,
+ devpriv->ai_flags &
+ CMDF_ROUND_NEAREST);
+
+ devpriv->ai_ctrl |= PCI9118_AI_CTRL_TMRTR;
+
+ if (!devpriv->usedma) {
+ devpriv->ai_ctrl |= PCI9118_AI_CTRL_INT;
+ devpriv->int_ctrl |= PCI9118_INT_CTRL_TIMER;
+ }
+
+ if (cmd->scan_begin_src == TRIG_EXT) {
+ struct pci9118_dmabuf *dmabuf = &devpriv->dmabuf[0];
+
+ devpriv->ai_cfg |= PCI9118_AI_CFG_AM;
+ outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
+ pci9118_timer_set_mode(dev, 0, I8254_MODE0);
+ pci9118_timer_write(dev, 0, dmabuf->hw >> 1);
+ devpriv->ai_cfg |= PCI9118_AI_CFG_START;
+ }
}
- if ((cmd->scan_begin_src == TRIG_TIMER) &&
- ((cmd->convert_src == TRIG_TIMER) ||
- (cmd->convert_src == TRIG_NOW))) {
- /* double timed action */
+ if (cmd->scan_begin_src == TRIG_TIMER &&
+ cmd->convert_src != TRIG_EXT) {
if (!devpriv->usedma) {
dev_err(dev->class_dev,
"cmd->scan_begin_src=TRIG_TIMER works only with bus mastering!\n");
return -EIO;
}
+ /* double timed action */
devpriv->ai_do = 2;
- pci9118_calc_divisors(devpriv->ai_do, dev, s,
+
+ pci9118_calc_divisors(dev, s,
&cmd->scan_begin_arg, &cmd->convert_arg,
devpriv->ai_flags,
devpriv->ai_n_realscanlen,
&devpriv->ai_divisor1,
&devpriv->ai_divisor2,
devpriv->ai_add_front);
+
+ devpriv->ai_ctrl |= PCI9118_AI_CTRL_TMRTR;
+ devpriv->ai_cfg |= PCI9118_AI_CFG_BM | PCI9118_AI_CFG_BS;
+ if (cmd->convert_src == TRIG_NOW && !devpriv->softsshdelay)
+ devpriv->ai_cfg |= PCI9118_AI_CFG_BSSH;
+ outl(devpriv->ai_n_realscanlen,
+ dev->iobase + PCI9118_AI_BURST_NUM_REG);
}
- if ((cmd->scan_begin_src == TRIG_FOLLOW)
- && (cmd->convert_src == TRIG_EXT)) {
+ if (cmd->scan_begin_src == TRIG_FOLLOW &&
+ cmd->convert_src == TRIG_EXT) {
+ /* external trigger conversion */
devpriv->ai_do = 3;
+
+ devpriv->ai_ctrl |= PCI9118_AI_CTRL_EXTM;
+ }
+
+ if (devpriv->ai_do == 0) {
+ dev_err(dev->class_dev,
+ "Unable to determine acqusition mode! BUG in (*do_cmdtest)?\n");
+ return -EINVAL;
}
+ if (devpriv->usedma)
+ devpriv->ai_ctrl |= PCI9118_AI_CTRL_DMA;
+
pci9118_start_pacer(dev, -1); /* stop pacer */
- devpriv->AdControlReg = 0; /*
- * bipolar, S.E., use 8254, stop 8354,
- * internal trigger, soft trigger,
- * disable DMA
- */
- 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);
+ /* set default config (disable burst and triggers) */
+ devpriv->ai_cfg = PCI9118_AI_CFG_PDTRG | PCI9118_AI_CFG_PETRG;
+ outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
udelay(1);
- outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */
- inl(dev->iobase + PCI9118_ADSTAT); /*
- * flush A/D and INT
- * status register
- */
- inl(dev->iobase + PCI9118_INTSRC);
+ pci9118_ai_reset_fifo(dev);
+
+ /* clear A/D and INT status registers */
+ inl(dev->iobase + PCI9118_AI_STATUS_REG);
+ inl(dev->iobase + PCI9118_INT_CTRL_REG);
devpriv->ai_act_scan = 0;
devpriv->ai_act_dmapos = 0;
s->async->cur_chan = 0;
- if (devpriv->usedma)
- ret = pci9118_ai_docmd_dma(dev, s);
- else
- ret = pci9118_ai_docmd_sampl(dev, s);
+ if (devpriv->usedma) {
+ Compute_and_setup_dma(dev, s);
+
+ outl(0x02000000 | AINT_WRITE_COMPL,
+ devpriv->iobase_a + AMCC_OP_REG_INTCSR);
+ } else {
+ pci9118_amcc_int_ena(dev, true);
+ }
- return ret;
+ /* start async command now or wait for internal trigger */
+ if (cmd->start_src == TRIG_NOW)
+ pci9118_ai_cmd_start(dev);
+ else if (cmd->start_src == TRIG_INT)
+ s->async->inttrig = pci9118_ai_inttrig;
+
+ /* enable external trigger for command start/stop */
+ if (cmd->start_src == TRIG_EXT || cmd->stop_src == TRIG_EXT)
+ pci9118_exttrg_enable(dev, true);
+
+ return 0;
}
-static int pci9118_reset(struct comedi_device *dev)
+static int pci9118_ai_cmdtest(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
{
struct pci9118_private *devpriv = dev->private;
+ int err = 0;
+ unsigned int flags;
+ unsigned int arg;
+ unsigned int divisor1 = 0, divisor2 = 0;
- devpriv->IntControlReg = 0;
- devpriv->exttrg_users = 0;
- inl(dev->iobase + PCI9118_INTCTRL);
- outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL);
- /* disable interrupts source */
- outl(0x30, dev->iobase + PCI9118_CNTCTRL);
-/* outl(0xb4, dev->iobase + PCI9118_CNTCTRL); */
- pci9118_start_pacer(dev, 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
- */
+ /* Step 1 : check if triggers are trivially valid */
- devpriv->ao_data[0] = 2047;
- devpriv->ao_data[1] = 2047;
- outl(devpriv->ao_data[0], dev->iobase + PCI9118_DA1);
- /* reset A/D outs to 0V */
- outl(devpriv->ao_data[1], 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 */
- 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 = 0;
- outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL);
- /*
- * bipolar, S.E., use 8254,
- * stop 8354, internal trigger,
- * soft trigger,
- * disable INT and DMA
- */
+ err |= cfc_check_trigger_src(&cmd->start_src,
+ TRIG_NOW | TRIG_EXT | TRIG_INT);
+
+ flags = TRIG_FOLLOW;
+ if (devpriv->master)
+ flags |= TRIG_TIMER | TRIG_EXT;
+ err |= cfc_check_trigger_src(&cmd->scan_begin_src, flags);
+
+ flags = TRIG_TIMER | TRIG_EXT;
+ if (devpriv->master)
+ flags |= TRIG_NOW;
+ err |= cfc_check_trigger_src(&cmd->convert_src, flags);
+
+ err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+ err |= cfc_check_trigger_src(&cmd->stop_src,
+ TRIG_COUNT | TRIG_NONE | TRIG_EXT);
+
+ if (err)
+ return 1;
+
+ /* Step 2a : make sure trigger sources are unique */
+
+ err |= cfc_check_trigger_is_unique(cmd->start_src);
+ err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+ err |= cfc_check_trigger_is_unique(cmd->convert_src);
+ err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+ /* Step 2b : and mutually compatible */
+
+ if (cmd->start_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT)
+ err |= -EINVAL;
+
+ if (cmd->start_src == TRIG_INT && cmd->scan_begin_src == TRIG_INT)
+ err |= -EINVAL;
- devpriv->exttrg_users = 0;
+ if ((cmd->scan_begin_src & (TRIG_TIMER | TRIG_EXT)) &&
+ (!(cmd->convert_src & (TRIG_TIMER | TRIG_NOW))))
+ err |= -EINVAL;
+
+ if ((cmd->scan_begin_src == TRIG_FOLLOW) &&
+ (!(cmd->convert_src & (TRIG_TIMER | TRIG_EXT))))
+ err |= -EINVAL;
+
+ if (cmd->stop_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT)
+ err |= -EINVAL;
+
+ if (err)
+ return 2;
+
+ /* Step 3: check if arguments are trivially valid */
+
+ switch (cmd->start_src) {
+ case TRIG_NOW:
+ case TRIG_EXT:
+ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
+ break;
+ case TRIG_INT:
+ /* start_arg is the internal trigger (any value) */
+ break;
+ }
+
+ if (cmd->scan_begin_src & (TRIG_FOLLOW | TRIG_EXT))
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
+
+ if ((cmd->scan_begin_src == TRIG_TIMER) &&
+ (cmd->convert_src == TRIG_TIMER) && (cmd->scan_end_arg == 1)) {
+ cmd->scan_begin_src = TRIG_FOLLOW;
+ cmd->convert_arg = cmd->scan_begin_arg;
+ cmd->scan_begin_arg = 0;
+ }
+
+ if (cmd->scan_begin_src == TRIG_TIMER)
+ err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
+ devpriv->ai_ns_min);
+
+ if (cmd->scan_begin_src == TRIG_EXT)
+ if (cmd->scan_begin_arg) {
+ cmd->scan_begin_arg = 0;
+ err |= -EINVAL;
+ err |= cfc_check_trigger_arg_max(&cmd->scan_end_arg,
+ 65535);
+ }
+
+ if (cmd->convert_src & (TRIG_TIMER | TRIG_NOW))
+ err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
+ devpriv->ai_ns_min);
+
+ if (cmd->convert_src == TRIG_EXT)
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
+
+ if (cmd->stop_src == TRIG_COUNT)
+ err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
+ else /* TRIG_NONE */
+ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
+
+ err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1);
+
+ err |= cfc_check_trigger_arg_min(&cmd->scan_end_arg,
+ cmd->chanlist_len);
+
+ if ((cmd->scan_end_arg % cmd->chanlist_len)) {
+ cmd->scan_end_arg =
+ cmd->chanlist_len * (cmd->scan_end_arg / cmd->chanlist_len);
+ err |= -EINVAL;
+ }
+
+ if (err)
+ return 3;
+
+ /* step 4: fix up any arguments */
+
+ if (cmd->scan_begin_src == TRIG_TIMER) {
+ arg = cmd->scan_begin_arg;
+ i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ,
+ &divisor1, &divisor2,
+ &arg, cmd->flags);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
+ }
+
+ if (cmd->convert_src & (TRIG_TIMER | TRIG_NOW)) {
+ arg = cmd->convert_arg;
+ i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ,
+ &divisor1, &divisor2,
+ &arg, cmd->flags);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
+
+ if (cmd->scan_begin_src == TRIG_TIMER &&
+ cmd->convert_src == TRIG_NOW) {
+ if (cmd->convert_arg == 0) {
+ arg = devpriv->ai_ns_min *
+ (cmd->scan_end_arg + 2);
+ } else {
+ arg = cmd->convert_arg * cmd->chanlist_len;
+ }
+ err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
+ arg);
+ }
+ }
+
+ if (err)
+ return 4;
+
+ if (cmd->chanlist)
+ if (!check_channel_list(dev, s, cmd->chanlist_len,
+ cmd->chanlist, 0, 0))
+ return 5; /* incorrect channels list */
return 0;
}
-/*
- * FIXME - this is pretty ineffective because all the supported board types
- * have the same device ID!
- */
-static const struct boardtype *pci9118_find_boardinfo(struct pci_dev *pcidev)
+static int pci9118_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
- unsigned int i;
+ unsigned int status;
- for (i = 0; i < ARRAY_SIZE(boardtypes); i++)
- if (pcidev->device == boardtypes[i].device_id)
- return &boardtypes[i];
- return NULL;
+ status = inl(dev->iobase + PCI9118_AI_STATUS_REG);
+ if (status & PCI9118_AI_STATUS_ADRDY)
+ return 0;
+ return -EBUSY;
+}
+
+static void pci9118_ai_start_conv(struct comedi_device *dev)
+{
+ /* writing any value triggers an A/D conversion */
+ outl(0, dev->iobase + PCI9118_SOFTTRG_REG);
+}
+
+static int pci9118_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct pci9118_private *devpriv = dev->private;
+ unsigned int val;
+ int ret;
+ int i;
+
+ /*
+ * Configure analog input based on the chanspec.
+ * Acqusition is software controlled without interrupts.
+ */
+ pci9118_set_chanlist(dev, s, 1, &insn->chanspec, 0, 0);
+
+ /* set default config (disable burst and triggers) */
+ devpriv->ai_cfg = PCI9118_AI_CFG_PDTRG | PCI9118_AI_CFG_PETRG;
+ outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
+
+ pci9118_ai_reset_fifo(dev);
+
+ for (i = 0; i < insn->n; i++) {
+ pci9118_ai_start_conv(dev);
+
+ ret = comedi_timeout(dev, s, insn, pci9118_ai_eoc, 0);
+ if (ret)
+ return ret;
+
+ val = inl(dev->iobase + PCI9118_AI_FIFO_REG);
+ if (s->maxdata == 0xffff)
+ data[i] = (val & 0xffff) ^ 0x8000;
+ else
+ data[i] = (val >> 4) & 0xfff;
+ }
+
+ return insn->n;
+}
+
+static int pci9118_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val = s->readback[chan];
+ int i;
+
+ for (i = 0; i < insn->n; i++) {
+ val = data[i];
+ outl(val, dev->iobase + PCI9118_AO_REG(chan));
+ }
+ s->readback[chan] = val;
+
+ return insn->n;
+}
+
+static int pci9118_di_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ /*
+ * The digital inputs and outputs share the read register.
+ * bits [7:4] are the digital outputs
+ * bits [3:0] are the digital inputs
+ */
+ data[1] = inl(dev->iobase + PCI9118_DIO_REG) & 0xf;
+
+ return insn->n;
+}
+
+static int pci9118_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ /*
+ * The digital outputs are set with the same register that
+ * the digital inputs and outputs are read from. But the
+ * outputs are set with bits [3:0] so we can simply write
+ * the s->state to set them.
+ */
+ if (comedi_dio_update_state(s, data))
+ outl(s->state, dev->iobase + PCI9118_DIO_REG);
+
+ data[1] = s->state;
+
+ return insn->n;
+}
+
+static void pci9118_reset(struct comedi_device *dev)
+{
+ /* reset analog input subsystem */
+ outl(0, dev->iobase + PCI9118_INT_CTRL_REG);
+ outl(0, dev->iobase + PCI9118_AI_CTRL_REG);
+ outl(0, dev->iobase + PCI9118_AI_CFG_REG);
+ pci9118_ai_reset_fifo(dev);
+
+ /* clear any pending interrupts and status */
+ inl(dev->iobase + PCI9118_INT_CTRL_REG);
+ inl(dev->iobase + PCI9118_AI_STATUS_REG);
+
+ /* reset and stop counters */
+ pci9118_timer_set_mode(dev, 0, I8254_MODE0);
+ pci9118_start_pacer(dev, 0);
+
+ /* reset DMA and scan queue */
+ outl(0, dev->iobase + PCI9118_AI_BURST_NUM_REG);
+ outl(1, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
+ outl(2, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
+
+ /* reset analog outputs to 0V */
+ outl(2047, dev->iobase + PCI9118_AO_REG(0));
+ outl(2047, dev->iobase + PCI9118_AO_REG(1));
}
static struct pci_dev *pci9118_find_pci(struct comedi_device *dev,
struct comedi_devconfig *it)
{
- const struct boardtype *this_board = comedi_board(dev);
struct pci_dev *pcidev = NULL;
int bus = it->options[0];
int slot = it->options[1];
@@ -1814,7 +1457,7 @@ static struct pci_dev *pci9118_find_pci(struct comedi_device *dev,
for_each_pci_dev(pcidev) {
if (pcidev->vendor != PCI_VENDOR_ID_AMCC)
continue;
- if (pcidev->device != this_board->device_id)
+ if (pcidev->device != 0x80d9)
continue;
if (bus || slot) {
/* requested particular bus/slot */
@@ -1830,56 +1473,85 @@ static struct pci_dev *pci9118_find_pci(struct comedi_device *dev,
return NULL;
}
-static int pci9118_common_attach(struct comedi_device *dev, int disable_irq,
- int master, int ext_mux, int softsshdelay,
- int hw_err_mask)
+static void pci9118_alloc_dma(struct comedi_device *dev)
+{
+ struct pci9118_private *devpriv = dev->private;
+ struct pci9118_dmabuf *dmabuf;
+ int order;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ dmabuf = &devpriv->dmabuf[i];
+ for (order = 2; order >= 0; order--) {
+ dmabuf->virt =
+ dma_alloc_coherent(dev->hw_dev, PAGE_SIZE << order,
+ &dmabuf->hw, GFP_KERNEL);
+ if (dmabuf->virt)
+ break;
+ }
+ if (!dmabuf->virt)
+ break;
+ dmabuf->size = PAGE_SIZE << order;
+
+ if (i == 0)
+ devpriv->master = 1;
+ if (i == 1)
+ devpriv->dma_doublebuf = 1;
+ }
+}
+
+static void pci9118_free_dma(struct comedi_device *dev)
{
- const struct boardtype *this_board = comedi_board(dev);
struct pci9118_private *devpriv = dev->private;
+ struct pci9118_dmabuf *dmabuf;
+ int i;
+
+ if (!devpriv)
+ return;
+
+ for (i = 0; i < 2; i++) {
+ dmabuf = &devpriv->dmabuf[i];
+ if (dmabuf->virt) {
+ dma_free_coherent(dev->hw_dev, dmabuf->size,
+ dmabuf->virt, dmabuf->hw);
+ }
+ }
+}
+
+static int pci9118_common_attach(struct comedi_device *dev,
+ int ext_mux, int softsshdelay)
+{
+ const struct pci9118_boardinfo *board = dev->board_ptr;
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ struct pci9118_private *devpriv;
struct comedi_subdevice *s;
- int ret, pages, i;
+ int ret;
+ int i;
u16 u16w;
- dev->board_name = this_board->name;
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
+ if (!devpriv)
+ return -ENOMEM;
+
ret = comedi_pci_enable(dev);
if (ret)
return ret;
- if (master)
- pci_set_master(pcidev);
+ pci_set_master(pcidev);
devpriv->iobase_a = pci_resource_start(pcidev, 0);
dev->iobase = pci_resource_start(pcidev, 2);
pci9118_reset(dev);
- if (master) { /* alloc DMA buffers */
- devpriv->dma_doublebuf = 0;
- for (i = 0; i < 2; i++) {
- for (pages = 4; pages >= 0; pages--) {
- devpriv->dmabuf_virt[i] =
- (unsigned short *)
- __get_free_pages(GFP_KERNEL, pages);
- if (devpriv->dmabuf_virt[i])
- break;
- }
- if (devpriv->dmabuf_virt[i]) {
- devpriv->dmabuf_pages[i] = pages;
- devpriv->dmabuf_size[i] = PAGE_SIZE * pages;
- devpriv->dmabuf_hw[i] =
- virt_to_bus((void *)
- devpriv->dmabuf_virt[i]);
- }
- }
- if (!devpriv->dmabuf_virt[0]) {
- dev_warn(dev->class_dev,
- "Can't allocate DMA buffer, DMA disabled!\n");
- master = 0;
+ if (pcidev->irq) {
+ ret = request_irq(pcidev->irq, pci9118_interrupt, IRQF_SHARED,
+ dev->board_name, dev);
+ if (ret == 0) {
+ dev->irq = pcidev->irq;
+
+ pci9118_alloc_dma(dev);
}
- if (devpriv->dmabuf_virt[1])
- devpriv->dma_doublebuf = 1;
}
- devpriv->master = master;
if (ext_mux > 0) {
if (ext_mux > 256)
@@ -1887,7 +1559,7 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq,
if (softsshdelay > 0)
if (ext_mux > 128)
ext_mux = 128;
- devpriv->usemux = ext_mux;
+ devpriv->usemux = 1;
} else {
devpriv->usemux = 0;
}
@@ -1907,70 +1579,81 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq,
pci_write_config_word(pcidev, PCI_COMMAND, u16w | 64);
/* Enable parity check for parity error */
- if (!disable_irq && pcidev->irq) {
- ret = request_irq(pcidev->irq, pci9118_interrupt, IRQF_SHARED,
- dev->board_name, dev);
- if (ret == 0)
- dev->irq = pcidev->irq;
- }
-
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
return ret;
+ /* Analog Input subdevice */
s = &dev->subdevices[0];
- s->type = COMEDI_SUBD_AI;
- 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;
- s->range_table = this_board->rangelist_ai;
- s->insn_read = pci9118_insn_read_ai;
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF;
+ s->n_chan = (devpriv->usemux) ? ext_mux : 16;
+ s->maxdata = board->ai_is_16bit ? 0xffff : 0x0fff;
+ s->range_table = board->is_hg ? &pci9118hg_ai_range
+ : &pci9118_ai_range;
+ s->insn_read = pci9118_ai_insn_read;
if (dev->irq) {
dev->read_subdev = s;
- s->subdev_flags |= SDF_CMD_READ;
- s->len_chanlist = this_board->n_aichanlist;
- s->do_cmdtest = pci9118_ai_cmdtest;
- s->do_cmd = pci9118_ai_cmd;
- s->cancel = pci9118_ai_cancel;
- s->munge = pci9118_ai_munge;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = PCI9118_CHANLEN;
+ s->do_cmdtest = pci9118_ai_cmdtest;
+ s->do_cmd = pci9118_ai_cmd;
+ s->cancel = pci9118_ai_cancel;
+ s->munge = pci9118_ai_munge;
+ }
+
+ if (s->maxdata == 0xffff) {
+ /*
+ * 16-bit samples are from an ADS7805 A/D converter.
+ * Minimum sampling rate is 10us.
+ */
+ devpriv->ai_ns_min = 10000;
+ } else {
+ /*
+ * 12-bit samples are from an ADS7800 A/D converter.
+ * Minimum sampling rate is 3us.
+ */
+ devpriv->ai_ns_min = 3000;
}
+ /* Analog Output subdevice */
s = &dev->subdevices[1];
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
- 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;
- s->insn_write = pci9118_insn_write_ao;
- s->insn_read = pci9118_insn_read_ao;
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
+ s->n_chan = 2;
+ s->maxdata = 0x0fff;
+ s->range_table = &range_bipolar10;
+ s->insn_write = pci9118_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
- s = &dev->subdevices[2];
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
- s->n_chan = 4;
- s->maxdata = 1;
- s->len_chanlist = 4;
- s->range_table = &range_digital;
- s->insn_bits = pci9118_insn_bits_di;
+ /* the analog outputs were reset to 0V, make the readback match */
+ for (i = 0; i < s->n_chan; i++)
+ s->readback[i] = 2047;
+ /* Digital Input subdevice */
+ s = &dev->subdevices[2];
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 4;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pci9118_di_insn_bits;
+
+ /* Digital Output subdevice */
s = &dev->subdevices[3];
- s->type = COMEDI_SUBD_DO;
- s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
- s->n_chan = 4;
- s->maxdata = 1;
- s->len_chanlist = 4;
- s->range_table = &range_digital;
- s->insn_bits = pci9118_insn_bits_do;
-
- devpriv->ai_maskharderr = 0x10a;
- /* default measure crash condition */
- if (hw_err_mask) /* disable some requested */
- devpriv->ai_maskharderr &= ~hw_err_mask;
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 4;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pci9118_do_insn_bits;
+
+ /* get the current state of the digital outputs */
+ s->state = inl(dev->iobase + PCI9118_DIO_REG) >> 4;
return 0;
}
@@ -1978,74 +1661,50 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq,
static int pci9118_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
- struct pci9118_private *devpriv;
struct pci_dev *pcidev;
- int ext_mux, disable_irq, master, softsshdelay, hw_err_mask;
+ int ext_mux, softsshdelay;
ext_mux = it->options[2];
- master = ((it->options[3] & 1) == 0);
- disable_irq = ((it->options[3] & 2) != 0);
softsshdelay = it->options[4];
- hw_err_mask = it->options[5];
-
- devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
- if (!devpriv)
- return -ENOMEM;
pcidev = pci9118_find_pci(dev, it);
if (!pcidev)
return -EIO;
comedi_set_hw_dev(dev, &pcidev->dev);
- return pci9118_common_attach(dev, disable_irq, master, ext_mux,
- softsshdelay, hw_err_mask);
+ return pci9118_common_attach(dev, ext_mux, softsshdelay);
}
static int pci9118_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- struct pci9118_private *devpriv;
+ const struct pci9118_boardinfo *board = NULL;
- devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
- if (!devpriv)
- return -ENOMEM;
+ if (context < ARRAY_SIZE(pci9118_boards))
+ board = &pci9118_boards[context];
+ if (!board)
+ return -ENODEV;
+ dev->board_ptr = board;
+ dev->board_name = board->name;
- dev->board_ptr = pci9118_find_boardinfo(pcidev);
- if (dev->board_ptr == NULL) {
- dev_err(dev->class_dev,
- "adl_pci9118: cannot determine board type for pci %s\n",
- pci_name(pcidev));
- return -EINVAL;
- }
/*
* Need to 'get' the PCI device to match the 'put' in pci9118_detach().
* (The 'put' also matches the implicit 'get' by pci9118_find_pci().)
*/
pci_dev_get(pcidev);
- /* Don't disable irq, use bus master, no external mux,
- * no sample-hold delay, no error mask. */
- return pci9118_common_attach(dev, 0, 1, 0, 0, 0);
+ /* no external mux, no sample-hold delay */
+ return pci9118_common_attach(dev, 0, 0);
}
static void pci9118_detach(struct comedi_device *dev)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- struct pci9118_private *devpriv = dev->private;
- if (devpriv) {
- if (dev->iobase)
- pci9118_reset(dev);
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (devpriv->dmabuf_virt[0])
- free_pages((unsigned long)devpriv->dmabuf_virt[0],
- devpriv->dmabuf_pages[0]);
- if (devpriv->dmabuf_virt[1])
- free_pages((unsigned long)devpriv->dmabuf_virt[1],
- devpriv->dmabuf_pages[1]);
- }
- comedi_pci_disable(dev);
+ if (dev->iobase)
+ pci9118_reset(dev);
+ comedi_pci_detach(dev);
+ pci9118_free_dma(dev);
if (pcidev)
pci_dev_put(pcidev);
}
@@ -2056,9 +1715,9 @@ static struct comedi_driver adl_pci9118_driver = {
.attach = pci9118_attach,
.auto_attach = pci9118_auto_attach,
.detach = pci9118_detach,
- .num_names = ARRAY_SIZE(boardtypes),
- .board_name = &boardtypes[0].name,
- .offset = sizeof(struct boardtype),
+ .num_names = ARRAY_SIZE(pci9118_boards),
+ .board_name = &pci9118_boards[0].name,
+ .offset = sizeof(struct pci9118_boardinfo),
};
static int adl_pci9118_pci_probe(struct pci_dev *dev,
@@ -2068,8 +1727,11 @@ static int adl_pci9118_pci_probe(struct pci_dev *dev,
id->driver_data);
}
+/* FIXME: All the supported board types have the same device ID! */
static const struct pci_device_id adl_pci9118_pci_table[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_AMCC, 0x80d9) },
+ { PCI_VDEVICE(AMCC, 0x80d9), BOARD_PCI9118DG },
+/* { PCI_VDEVICE(AMCC, 0x80d9), BOARD_PCI9118HG }, */
+/* { PCI_VDEVICE(AMCC, 0x80d9), BOARD_PCI9118HR }, */
{ 0 }
};
MODULE_DEVICE_TABLE(pci, adl_pci9118_pci_table);