#define TIMER_BASE 25 // 40MHz master clock
#define PRESCALED_TIMER_BASE 10000 // 100kHz 'prescaled' clock for slow aquisition, maybe I'll support this someday
#define QUARTER_AI_FIFO_SIZE 2048 // 1/4 analog input fifo size
+// size in bytes of transfers used for dma transfers, also size of buffers that make up dma ring
+#define AI_DMA_TRANSFER_SIZE 0x4000
+// number of dma transfers we will chain together into a ring (and the number of dma buffers we maintain)
+#define DMA_RING_COUNT 10
/* PCI-DAS64xxx base addresses */
#define ADC_INTR_EOSEQ_BITS 0x3 // interrupt end of sequence (probably wont use this it's pretty fancy)
#define EN_ADC_INTR_SRC_BIT 0x4 // enable adc interrupt source
#define EN_ADC_DONE_INTR_BIT 0x8 // enable adc aquisition done interrupt
+#define EN_ADC_ACTIVE_INTR_BIT 0x200 // enable adc active interrupt
#define EN_ADC_STOP_INTR_BIT 0x400 // enable adc stop trigger interrupt
+#define EN_DAC_ACTIVE_INTR_BIT 0x800 // enable dac active interrupt
#define EN_DAC_UNDERRUN_BIT 0x4000 // enable dac underrun status bit
#define EN_ADC_OVERRUN_BIT 0x8000 // enable adc overrun status bit
#define HW_CONFIG_REG 0x2 // hardware config register
feel free to suggest moving the variable to the comedi_device struct. */
typedef struct
{
+ struct pci_dev *hw_dev; // pointer to board's pci_dev struct
// base addresses (physical)
unsigned long plx9080_phys_iobase;
unsigned long main_phys_iobase;
unsigned long plx9080_iobase;
unsigned long main_iobase;
unsigned long dio_counter_iobase;
- // divisor of master clock for analog input pacing
- unsigned int ai_divisor;
volatile unsigned int ai_count; // number of analog input samples remaining
- // divisors of master clock for analog output pacing
- unsigned int ao_divisor;
+ u16 *ai_buffer[DMA_RING_COUNT]; // dma buffers for analog input
+ dma_addr_t ai_buffer_phys_addr[DMA_RING_COUNT]; // physical addresses of ai dma buffers
volatile unsigned int ao_count; // number of analog output samples remaining
unsigned int ao_value[2]; // remember what the analog outputs are set to, to allow readback
unsigned int hw_revision; // stc chip hardware revision number
unsigned int do_bits; // remember digital ouput levels
+ volatile unsigned int intr_enable_bits; // bits to send to INTR_ENABLE_REG register
} pcidas64_private;
/*
printk("Found %s on bus %i, slot %i\n", pcidas64_boards[index].name,
pcidev->bus->number, PCI_SLOT(pcidev->devfn));
+ devpriv->hw_dev = pcidev;
//Initialize dev->board_name
dev->board_name = thisboard->name;
#else
if(pci_enable_device(pcidev))
return -EIO;
+#ifdef PCIDMA
pci_set_master(pcidev);
+#endif
plx9080_iobase =
pcidev->resource[PLX9080_BADRINDEX].start &
PCI_BASE_ADDRESS_MEM_MASK;
}
dev->irq = pcidev->irq;
+#ifdef PCIDMA
+ // alocate pci dma buffers
+ for(index = 0; index < DMA_RING_COUNT; i++)
+ {
+ devpriv->ai_buffer[index] =
+ pci_alloc_consistent(devpriv->hw_dev, DMA_BUFFER_SIZE, &devpriv->ai_buffer_phys_addr[index]);
+ }
+#endif
+
#ifdef PCIDAS64_DEBUG
printk(" plx9080 phys io addr 0x%lx\n", devpriv->plx9080_phys_iobase);
*/
static int detach(comedi_device *dev)
{
+#ifdef PCIDMA
+ unsigned int i;
+#endif
+
printk("comedi%d: cb_pcidas: remove\n",dev->minor);
if(devpriv)
release_mem_region(devpriv->main_phys_iobase, MAIN_IOSIZE);
if(devpriv->dio_counter_iobase)
release_mem_region(devpriv->dio_counter_phys_iobase, DIO_COUNTER_IOSIZE);
+#ifdef PCIDMA
+ // free pci dma buffers
+ for(i = 0; i < DMA_RING_COUNT; i++)
+ {
+ if(devpriv->ai_buffer[i])
+ pci_free_consistent(devpriv->hw_dev, DMA_BUFFER_SIZE,
+ devpriv->ai_buffer[i], devpriv->ai_buffer_phys_addr[i]);
+ }
+#endif
}
if(dev->irq)
comedi_free_irq(dev->irq, dev);
unsigned int bits, n, i;
const int timeout = 1000;
- // disable card's interrupt sources
- writew(0, devpriv->main_iobase + INTR_ENABLE_REG);
+ // disable card's analog input interrupt sources
+ devpriv->intr_enable_bits &= ~EN_ADC_INTR_SRC_BIT & ~EN_ADC_DONE_INTR_BIT &
+ ~EN_ADC_ACTIVE_INTR_BIT & ~EN_ADC_STOP_INTR_BIT & ~EN_ADC_OVERRUN_BIT;
+ writew(devpriv->intr_enable_bits, devpriv->main_iobase + INTR_ENABLE_REG);
/* disable pacing, triggering, etc */
writew(ADC_ENABLE_BIT, devpriv->main_iobase + ADC_CONTROL0_REG);
unsigned int i;
// disable card's interrupt sources
- writew(0, devpriv->main_iobase + INTR_ENABLE_REG);
+ // disable card's analog input interrupt sources
+ devpriv->intr_enable_bits &= ~EN_ADC_INTR_SRC_BIT & ~EN_ADC_DONE_INTR_BIT &
+ ~EN_ADC_ACTIVE_INTR_BIT & ~EN_ADC_STOP_INTR_BIT & ~EN_ADC_OVERRUN_BIT;
+ writew(devpriv->intr_enable_bits, devpriv->main_iobase + INTR_ENABLE_REG);
/* disable pacing, triggering, etc */
writew(0, devpriv->main_iobase + ADC_CONTROL0_REG);
writew(0, devpriv->main_iobase + ADC_BUFFER_CLEAR_REG);
// enable interrupts
- bits = EN_ADC_OVERRUN_BIT | EN_ADC_DONE_INTR_BIT;
+ devpriv->intr_enable_bits |= EN_ADC_OVERRUN_BIT | EN_ADC_DONE_INTR_BIT;
if(cmd->stop_src == TRIG_EXT)
- bits |= EN_ADC_STOP_INTR_BIT;
+ devpriv->intr_enable_bits |= EN_ADC_STOP_INTR_BIT;
if(cmd->flags & TRIG_WAKE_EOS)
- bits |= ADC_INTR_EOSCAN_BITS;
+ devpriv->intr_enable_bits |= ADC_INTR_EOSCAN_BITS;
else
- bits |= ADC_INTR_QFULL_BITS; // for clairity only, since quarter-full bits are zero
- writew(bits, devpriv->main_iobase + INTR_ENABLE_REG);
+ devpriv->intr_enable_bits |= ADC_INTR_QFULL_BITS; // for clairity only, since quarter-full bits are zero
+ writew(devpriv->intr_enable_bits, devpriv->main_iobase + INTR_ENABLE_REG);
// enable interrupts on plx 9080 XXX enabling more interrupt sources than are actually used
bits = ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_PDIE | ICS_LIE | ICS_LDIE | ICS_DMA0_E | ICS_DMA1_E;
writel(bits, devpriv->plx9080_iobase + PLX_INTRCS_REG);
- // disable dma for now XXX
+#ifdef PCIDMA
+//XXX
+#else
writeb(0, devpriv->plx9080_iobase + PLX_DMA0_CS_REG);
writeb(0, devpriv->plx9080_iobase + PLX_DMA1_CS_REG);
+#endif
/* set mode, disable software conversion gate */
bits = ADC_CONTROL1_DUMMY_BITS | SW_NOGATE_BIT;
read_index <<= 15;
write_index <<= 15;
// get least significant 15 bits
- read_index += readw(devpriv->main_iobase + ADC_READ_PNTR_REG);
- write_index += readw(devpriv->main_iobase + ADC_WRITE_PNTR_REG);
+ read_index += readw(devpriv->main_iobase + ADC_READ_PNTR_REG) & 0x7fff;
+ write_index += readw(devpriv->main_iobase + ADC_WRITE_PNTR_REG) & 0x7fff;
num_samples = write_index - read_index;
if(num_samples < 0)
num_samples += 4 * QUARTER_AI_FIFO_SIZE;
#ifndef __COMEDI_PLX9080_H
#define __COMEDI_PLX9080_H
+// descriptor block used for chained dma transfers
+struct plx_dma_desc
+{
+ u32 pci_start_addr;
+ u32 local_start_addr;
+ // transfer_size is in bytes, only first 23 bits of register are used
+ u32 transfer_size;
+ /* address of next descriptor (quad word aligned), plus some
+ * additional bits (see PLX_DMA0_DESCRIPTOR_REG) */
+ u32 next;
+};
+
/**********************************************************************
** Register Offsets and Bit Definitions
**
#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_DMA1_DESCRIPTOR_REG 0xa4
+#define PLX_LOCAL_BUS_16_WIDE_BITS 0x1
+#define PLX_LOCAL_BUS_WIDTH_MASK 0x3
+#define PLX_EN_CHAIN_BIT 0x200 // enables chaining
+#define PLX_EN_DMA_DONE_INTR_BIT 0x400 // enables interrupt on dma done
+#define PLX_LOCAL_ADDR_CONST_BIT 0x800 // hold local address constant (don't increment)
+#define PLX_DMA_INTR_PCI_BIT 0x20000 // routes dma interrupt to pci bus (instead of local bus)
#define PLX_DMA0_CS_REG 0xa8 // command status register
#define PLX_DMA1_CS_REG 0xa9
#define MBX_ADDR_SPACE_360 0x80 /* wanXL100s/200/400 */
#define MBX_ADDR_MASK_360 (MBX_ADDR_SPACE_360-1)
-#endif /* __PLX9060_H */
+#endif /* __COMEDI_PLX9080_H */