From 165ddcae2579b51b72e1fcb37b31e9a996f6957c Mon Sep 17 00:00:00 2001 From: Frank Mori Hess Date: Sat, 8 Sep 2001 01:23:36 +0000 Subject: [PATCH] more work on ai command, still not functional yet though --- comedi/drivers/cb_pcidas64.c | 124 ++++++++++++++++-------- comedi/drivers/{plx9060.h => plx9080.h} | 28 +++++- 2 files changed, 109 insertions(+), 43 deletions(-) rename comedi/drivers/{plx9060.h => plx9080.h} (94%) diff --git a/comedi/drivers/cb_pcidas64.c b/comedi/drivers/cb_pcidas64.c index b1806e98..a2ed7285 100644 --- a/comedi/drivers/cb_pcidas64.c +++ b/comedi/drivers/cb_pcidas64.c @@ -38,11 +38,11 @@ TODO: calibration subdevice user counter subdevice there are a number of boards this driver will support when they are - fully released, but does not since yet since the pci device id numbers + fully released, but does not since yet since the pci device id numbers are not yet available. - add plx9080 stuff to make interrupts work - need to take care to prevent ai and ao from affecting each others register bits - support prescaled 100khz for slow pacing + add plx9080 stuff to make interrupts and dma work + need to take care to prevent ai and ao from affecting each others register bits + support prescaled 100khz clock for slow pacing */ #include @@ -62,7 +62,7 @@ TODO: #include #include "8253.h" #include "8255.h" -#include "plx9060.h" +#include "plx9080.h" #define PCIDAS64_DEBUG // enable debugging code //#undef PCIDAS64_DEBUG // disable debugging code @@ -114,6 +114,11 @@ TODO: #define ADC_MODE_BITS(x) (((x) & 0xf) << 12) #define ADC_SAMPLE_INTERVAL_LOWER_REG 0x16 // lower 16 bits of sample interval counter #define ADC_SAMPLE_INTERVAL_UPPER_REG 0x18 // upper 8 bits of sample interval counter +#define ADC_DELAY_INTERVAL_LOWER_REG 0x1a // lower 16 bits of delay interval counter +#define ADC_DELAY_INTERVAL_UPPER_REG 0x1c // upper 8 bits of delay interval counter +#define ADC_COUNT_LOWER_REG 0x1e // lower 16 bits of hardware conversion/scan counter +#define ADC_COUNT_UPPER_REG 0x20 // upper 8 bits of hardware conversion/scan counter +#define ADC_START_REG 0x22 // software trigger to start aquisition #define ADC_CONVERT_REG 0x24 // initiates single conversion #define ADC_QUEUE_CLEAR_REG 0x26 // clears adc queue #define ADC_QUEUE_LOAD_REG 0x28 // loads adc queue @@ -121,7 +126,8 @@ TODO: #define GAIN_BITS(x) (((x) & 0x3) << 8) // translates range index to gain bits #define UNIP_BIT(x) (((x) & 0x4) << 11) // translates range index to unipolar/bipolar bit #define SE_BIT 0x1000 // single-ended/ differential bit -#define QUEUE_EOS_BIT 0x8000 // queue end of scan +#define QUEUE_EOSEQ_BIT 0x4000 // queue end of sequence +#define QUEUE_EOSCAN_BIT 0x8000 // queue end of scan #define ADC_BUFFER_CLEAR_REG 0x2a #define ADC_QUEUE_HIGH_REG 0x2c // high channel for internal queue, use CHAN_BITS() macro above #define DAC_CONTROL0_REG 0x50 // dac control register 0 @@ -136,6 +142,8 @@ TODO: #define ADC_BUSY_BIT 0x8 #define HW_REVISION(x) (((x) >> 12) & 0xf) #define PIPE1_READ_REG 0x4 +// read-write +#define ADC_QUEUE_FIFO_REG 0x100 // external channel/gain queue, uses same bits as ADC_QUEUE_LOAD_REG // devpriv->dio_counter_iobase registers #define DIO_8255_OFFSET 0x0 @@ -535,6 +543,18 @@ printk(" irq %i\n", dev->irq); printk(" stc hardware revision %i\n", devpriv->hw_revision); +// plx9080 dump +printk(" plx interrupt status 0x%x\n", readl(devpriv->plx9080_iobase + PLX_INTRCS_REG)); +printk(" plx id bits 0x%x\n", readl(devpriv->plx9080_iobase + PLX_ID_REG)); +printk(" plx hardware revision 0x%x\n", readl(devpriv->plx9080_iobase + PLX_REVISION_REG)); +printk(" plx dma channel 0 mode 0x%x\n", readl(devpriv->plx9080_iobase + PLX_DMA0_MODE_REG)); +printk(" plx dma channel 0 pci address 0x%x\n", readl(devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG)); +printk(" plx dma channel 0 local address 0x%x\n", readl(devpriv->plx9080_iobase + PLX_DMA0_LOCAL_ADDRESS_REG)); +printk(" plx dma channel 0 transfer size 0x%x\n", readl(devpriv->plx9080_iobase + PLX_DMA0_TRANSFER_SIZE_REG)); +printk(" plx dma channel 0 descriptor 0x%x\n", readl(devpriv->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG)); +printk(" plx dma channel 0 command status 0x%x\n", readl(devpriv->plx9080_iobase + PLX_DMA0_CS_REG)); +printk(" plx dma channel 0 threshold 0x%x\n", readl(devpriv->plx9080_iobase + PLX_DMA0_THRESHOLD_REG)); + #endif @@ -547,18 +567,18 @@ printk(" stc hardware revision %i\n", devpriv->hw_revision); s = dev->subdevices + 0; /* analog input subdevice */ -// dev->read_subdev = s; + dev->read_subdev = s; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF; - /* WARNING: Number of inputs in differential mode is ignored */ + /* XXX Number of inputs in differential mode is ignored */ s->n_chan = thisboard->ai_se_chans; s->len_chanlist = 8092; s->maxdata = (1 << thisboard->ai_bits) - 1; s->range_table = &ai_ranges; s->insn_read = ai_rinsn; -// s->do_cmd = ai_cmd; -// s->do_cmdtest = ai_cmdtest; -// s->cancel = ai_cancel; + //s->do_cmd = ai_cmd; + //s->do_cmdtest = ai_cmdtest; + //s->cancel = ai_cancel; /* analog output subdevice */ s = dev->subdevices + 1; @@ -661,10 +681,10 @@ static int ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsa // disable card's interrupt sources writew(0, devpriv->main_iobase + INTR_ENABLE_REG); - - /* disable pacing, triggering, etc */ - writew(ADC_ENABLE_BIT, devpriv->main_iobase + ADC_CONTROL0_REG); - writew(0, devpriv->main_iobase + ADC_CONTROL1_REG); + + /* disable pacing, triggering, etc */ + writew(ADC_ENABLE_BIT, devpriv->main_iobase + ADC_CONTROL0_REG); + writew(0, devpriv->main_iobase + ADC_CONTROL1_REG); // use internal queue writew(HW_CONFIG_DUMMY_BITS, devpriv->main_iobase + HW_CONFIG_REG); @@ -755,7 +775,7 @@ static int ai_cmdtest(comedi_device *dev,comedi_subdevice *s, comedi_cmd *cmd) cmd->stop_src != TRIG_EXT) err++; // compatibility check - if(cmd->convert_src == TRIG_EXT && + if(cmd->convert_src == TRIG_EXT && cmd->scan_begin_src == TRIG_TIMER) err++; @@ -776,16 +796,16 @@ static int ai_cmdtest(comedi_device *dev,comedi_subdevice *s, comedi_cmd *cmd) err++; } if(cmd->scan_begin_src == TRIG_TIMER) - { + { // if scans are timed faster than conversion rate allows - if(cmd->convert_arg * cmd->chanlist_len > cmd->scan_begin_arg) + if(cmd->convert_arg * cmd->chanlist_len > cmd->scan_begin_arg) { cmd->scan_begin_arg = cmd->convert_arg * cmd->chanlist_len; err++; } } } - + if(!cmd->chanlist_len) { cmd->chanlist_len = 1; @@ -864,7 +884,9 @@ static int ai_cmd(comedi_device *dev,comedi_subdevice *s) comedi_async *async = s->async; comedi_cmd *cmd = &async->cmd; unsigned int bits; - unsigned int counter_value; + unsigned int convert_counter_value; + unsigned int scan_counter_value; + unsigned int i; // disable card's interrupt sources writew(0, devpriv->main_iobase + INTR_ENABLE_REG); @@ -884,30 +906,51 @@ static int ai_cmd(comedi_device *dev,comedi_subdevice *s) { check_adc_timing(cmd); // supposed to load counter with desired divisor minus 3 - counter_value = cmd->scan_begin_arg / TIMER_BASE - 3; + convert_counter_value = cmd->convert_arg / TIMER_BASE - 3; // load lower 16 bits - writew(counter_value & 0xffff, devpriv->main_iobase + ADC_SAMPLE_INTERVAL_LOWER_REG); + writew(convert_counter_value & 0xffff, devpriv->main_iobase + ADC_SAMPLE_INTERVAL_LOWER_REG); // load upper 8 bits - writew((counter_value >> 16) & 0xff, devpriv->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG); + writew((convert_counter_value >> 16) & 0xff, devpriv->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG); + // set scan pacing + if(cmd->convert_src == TRIG_TIMER) + { + // figure out how long we need to delay at end of scan + scan_counter_value = (cmd->scan_begin_arg - (cmd->convert_arg * cmd->chanlist_len)) + / TIMER_BASE; + // load lower 16 bits + writew(scan_counter_value & 0xffff, devpriv->main_iobase + ADC_DELAY_INTERVAL_LOWER_REG); + // load upper 8 bits + writew((scan_counter_value >> 16) & 0xff, devpriv->main_iobase + ADC_DELAY_INTERVAL_UPPER_REG); + } } -#if 0 + // load hardware conversion counter with non-zero value so it doesn't mess with us + writew(~0, devpriv->main_iobase + ADC_COUNT_LOWER_REG); + + /* XXX cannot write to queue fifo while dac fifo is being written to + * ( need spinlock, or try to use internal queue instead */ + // clear queue pointer + writew(0, devpriv->main_iobase + ADC_QUEUE_CLEAR_REG); // load external queue - bits = 0; - // set channel - bits |= CHAN_BITS(CR_CHAN(insn->chanspec)); - // set gain - bits |= GAIN_BITS(CR_RANGE(insn->chanspec)); - // set unipolar / bipolar - bits |= UNIP_BIT(CR_RANGE(insn->chanspec)); - // set single-ended / differential - if(CR_AREF(insn->chanspec) != AREF_DIFF) - bits |= SE_BIT; - // set stop channel - writew(CHAN_BITS(CR_CHAN(insn->chanspec)), devpriv->main_iobase + ADC_QUEUE_HIGH_REG); - // set start channel, and rest of settings - writew(bits, devpriv->main_iobase + ADC_QUEUE_LOAD_REG); -#endif + for(i = 0; i < cmd->chanlist_len; i++) + { + bits = 0; + // set channel + bits |= CHAN_BITS(CR_CHAN(cmd->chanlist[i])); + // set gain + bits |= GAIN_BITS(CR_RANGE(cmd->chanlist[i])); + // set unipolar / bipolar + bits |= UNIP_BIT(CR_RANGE(cmd->chanlist[i])); + // set single-ended / differential + if(CR_AREF(cmd->chanlist[i]) != AREF_DIFF) + bits |= SE_BIT; + // mark end of queue + if(i == cmd->chanlist_len - 1) + bits |= QUEUE_EOSCAN_BIT | QUEUE_EOSEQ_BIT; + writew(bits, devpriv->main_iobase + ADC_QUEUE_FIFO_REG); + } + // prime queue holding register + writew(0, devpriv->main_iobase + ADC_QUEUE_LOAD_REG); // clear adc buffer writew(0, devpriv->main_iobase + ADC_BUFFER_CLEAR_REG); @@ -930,6 +973,9 @@ static int ai_cmd(comedi_device *dev,comedi_subdevice *s) bits = ADC_ENABLE_BIT; writew(bits, devpriv->main_iobase + ADC_CONTROL0_REG); + // start aquisition + writew(0, devpriv->main_iobase + ADC_START_REG); + return 0; } diff --git a/comedi/drivers/plx9060.h b/comedi/drivers/plx9080.h similarity index 94% rename from comedi/drivers/plx9060.h rename to comedi/drivers/plx9080.h index 9cf6dca2..41ef31cf 100644 --- a/comedi/drivers/plx9060.h +++ b/comedi/drivers/plx9080.h @@ -1,7 +1,9 @@ -/* plx9060.h +/* plx9080.h * - * I took this file from the wanXL device driver in the linux kernel, + * I modified this file from the plx9060.h header for the + * wanXL device driver in the linux kernel, * for the register offsets and bit definitions. Minor modifications, + * added plx9080 registers and * stripped out stuff that was specifically for the wanXL driver. I * use this for the plx9080 chip used in the cards supported by * the cb_pcidas64.c driver. @@ -20,8 +22,8 @@ * 2 of the License, or (at your option) any later version. */ -#ifndef __COMEDI_PLX9060_H -#define __COMEDI_PLX9060_H +#ifndef __COMEDI_PLX9080_H +#define __COMEDI_PLX9080_H /********************************************************************** ** Register Offsets and Bit Definitions @@ -162,6 +164,24 @@ #define CTL_RESET 0x40000000 /* !! Adapter Reset !! */ #define CTL_READY 0x80000000 /* Local Init Done */ +#define PLX_ID_REG 0x70 // hard-coded plx vendor and device ids + +#define PLX_REVISION_REG 0x74 // silicon revision + +#define PLX_DMA0_MODE_REG 0x80 // dma channel 0 mode register + +#define PLX_DMA0_PCI_ADDRESS_REG 0x84 // pci address that dma transfers start at + +#define PLX_DMA0_LOCAL_ADDRESS_REG 0x88 // local address that dma transfers start at + +#define PLX_DMA0_TRANSFER_SIZE_REG 0x8c // number of bytes to transfer (first 23 bits) + +#define PLX_DMA0_DESCRIPTOR_REG 0x90 // descriptor pointer register + +#define PLX_DMA0_CS_REG 0xa8 // command status register + +#define PLX_DMA0_THRESHOLD_REG 0xb0 // command status register + /* * Accesses near the end of memory can cause the PLX chip * to pre-fetch data off of end-of-ram. Limit the size of -- 2.26.2