From: Frank Mori Hess Date: Wed, 15 Aug 2007 21:22:49 +0000 (+0000) Subject: Moved some interrupt enable/disable and interrupt handling X-Git-Tag: r0_7_75~45 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=13f64be4a909e2728b7f6a06dd5acb65c047361a;p=comedi.git Moved some interrupt enable/disable and interrupt handling stuff from client drivers into ni_tio.c. ni_stc.h: Added some stuff for correlated digital output waveforms that I missed in earlier commit. ni_660x.c: Added beginnings of support for buffered input counting (untested, definitely doesn't work yet due to empty interrupt handler). Added INSN_CONFIG_SET/GET_ROUTING support, to allow switching of output signals between counter outputs and static digital output. Fixed channel mix-ups on input/output selection for static dio. Fixed static digital output to work on full 32 bits. Replaced some preprocessor macros with inline functions. --- diff --git a/comedi/drivers/ni_660x.c b/comedi/drivers/ni_660x.c index d1d8c175..02fdd910 100644 --- a/comedi/drivers/ni_660x.c +++ b/comedi/drivers/ni_660x.c @@ -49,6 +49,8 @@ Things to do: #define CTRS_PER_CHIP 4 // The number of counters per ni-tio chip #define NUM_PFI_CHANNELS 40 +// really there are only up to 3 dma channels, but the register layout allows for 4 +#define MAX_DMA_CHANNEL 4 /* See Register-Level Programmer Manual page 3.1 */ typedef enum @@ -59,14 +61,18 @@ typedef enum G1StatusRegister, G01StatusRegister, G0CommandRegister, + STCDIOParallelInput, G1CommandRegister, G0HWSaveRegister, G1HWSaveRegister, + STCDIOOutput, + STCDIOControl, G0SWSaveRegister, G1SWSaveRegister, G0ModeRegister, G01JointStatus1Register, G1ModeRegister, + STCDIOSerialInput, G0LoadARegister, G01JointStatus2Register, G0LoadBRegister, @@ -121,8 +127,12 @@ typedef enum G2DMAStatusRegister, G3DMAConfigRegister, G3DMAStatusRegister, + DIO32Input, + DIO32Output, ClockConfigRegister, - DMAConfigRegister, // XXX will need to use this according to mite channel used + GlobalInterruptStatusRegister, + DMAConfigRegister, + GlobalInterruptConfigRegister, IOConfigReg0_1, IOConfigReg2_3, IOConfigReg4_5, @@ -143,12 +153,6 @@ typedef enum IOConfigReg34_35, IOConfigReg36_37, IOConfigReg38_39, - STCDIOParallelInput, - STCDIOOutput, - STCDIOControl, - STCDIOSerialInput, - DIO32Input, - DIO32Output, NumRegisters, } NI_660x_Register; @@ -173,6 +177,14 @@ enum ni_660x_register_direction NI_660x_READ_WRITE }; +enum ni_660x_pfi_output_select +{ + pfi_output_select_high_Z = 0, + pfi_output_select_counter = 1, + pfi_output_select_do = 2, + num_pfi_output_selects +}; + typedef struct { const char *name; // Register Name @@ -190,14 +202,18 @@ static const NI_660xRegisterData registerData[NumRegisters] = {"G1 Status Register", 0x006, NI_660x_READ, DATA_2B}, {"G01 Status Register ", 0x008, NI_660x_READ, DATA_2B}, {"G0 Command Register", 0x00C, NI_660x_WRITE, DATA_2B}, + {"STD DIO Parallel Input", 0x00E, NI_660x_READ, DATA_2B}, {"G1 Command Register", 0x00E, NI_660x_WRITE, DATA_2B}, {"G0 HW Save Register", 0x010, NI_660x_READ, DATA_4B}, {"G1 HW Save Register", 0x014, NI_660x_READ, DATA_4B}, + {"STD DIO Output", 0x014, NI_660x_WRITE, DATA_2B}, + {"STD DIO Control", 0x016, NI_660x_WRITE, DATA_2B}, {"G0 SW Save Register", 0x018, NI_660x_READ, DATA_4B}, {"G1 SW Save Register", 0x01C, NI_660x_READ, DATA_4B}, {"G0 Mode Register", 0x034, NI_660x_WRITE, DATA_2B}, {"G01 Joint Status 1 Register", 0x036, NI_660x_READ, DATA_2B}, {"G1 Mode Register", 0x036, NI_660x_WRITE, DATA_2B}, + {"STD DIO Serial Input", 0x038, NI_660x_READ, DATA_2B}, {"G0 Load A Register", 0x038, NI_660x_WRITE, DATA_4B}, {"G01 Joint Status 2 Register", 0x03A, NI_660x_READ, DATA_2B}, {"G0 Load B Register", 0x03C, NI_660x_WRITE, DATA_4B}, @@ -252,9 +268,13 @@ static const NI_660xRegisterData registerData[NumRegisters] = {"G2 DMA Status Register", 0x1B8, NI_660x_READ, DATA_2B}, {"G3 DMA Config Register", 0x1BA, NI_660x_WRITE, DATA_2B}, {"G3 DMA Status Register", 0x1BA, NI_660x_READ, DATA_2B}, + {"32 bit Digital Input", 0x414, NI_660x_READ, DATA_4B}, + {"32 bit Digital Output", 0x510, NI_660x_WRITE, DATA_4B}, {"Clock Config Register", 0x73C, NI_660x_WRITE, DATA_4B}, - {"DMA Configuration Register", 0x76c, NI_660x_WRITE, DATA_4B}, - {"IO Config Register 0-1", 0x77C, NI_660x_READ_WRITE, DATA_2B}, // READWRITE + {"Global Interrupt Status Register", 0x754, NI_660x_READ, DATA_4B}, + {"DMA Configuration Register", 0x76C, NI_660x_WRITE, DATA_4B}, + {"Global Interrupt Config Register", 0x770, NI_660x_WRITE, DATA_4B}, + {"IO Config Register 0-1", 0x77C, NI_660x_READ_WRITE, DATA_2B}, {"IO Config Register 2-3", 0x77E, NI_660x_READ_WRITE, DATA_2B}, {"IO Config Register 4-5", 0x780, NI_660x_READ_WRITE, DATA_2B}, {"IO Config Register 6-7", 0x782, NI_660x_READ_WRITE, DATA_2B}, @@ -273,36 +293,62 @@ static const NI_660xRegisterData registerData[NumRegisters] = {"IO Config Register 32-33", 0x79C, NI_660x_READ_WRITE, DATA_2B}, {"IO Config Register 34-35", 0x79E, NI_660x_READ_WRITE, DATA_2B}, {"IO Config Register 36-37", 0x7A0, NI_660x_READ_WRITE, DATA_2B}, - {"IO Config Register 38-39", 0x7A2, NI_660x_READ_WRITE, DATA_2B}, - {"STD DIO Parallel Input", 0x00E, NI_660x_READ, DATA_2B}, - {"STD DIO Output", 0x014, NI_660x_WRITE, DATA_2B}, - {"STD DIO Control", 0x016, NI_660x_WRITE, DATA_2B}, - {"STD DIO Serial Input", 0x038, NI_660x_READ, DATA_2B}, - {"32 bit Digital Input", 0x414, NI_660x_READ, DATA_4B}, - {"32 bit Digital Output", 0x414, NI_660x_WRITE, DATA_4B} + {"IO Config Register 38-39", 0x7A2, NI_660x_READ_WRITE, DATA_2B} }; -#define GateSelectPin38 0x1<<8 // Take internal time-based 20 - // kind of ENABLE for the second counter -#define CounterSwap 0x1<<21 +enum clock_config_register_bits +{ + CounterSwap = 0x1 << 21 +}; // ioconfigreg +static inline unsigned ioconfig_bitshift(unsigned pfi_channel) +{ + if(pfi_channel % 2) return 0; + else return 8; +} static inline unsigned pfi_output_select_mask(unsigned pfi_channel) { - return 0x3 << (8 * (pfi_channel % 2)); + return 0x3 << ioconfig_bitshift(pfi_channel); } static inline unsigned pfi_output_select_bits(unsigned pfi_channel, unsigned output_select) { - return (output_select & 0x3) << (8 * (pfi_channel % 2)); + return (output_select & 0x3) << ioconfig_bitshift(pfi_channel); } static inline unsigned pfi_input_select_mask(unsigned pfi_channel) { - return 0x7 << (4 + 8 * (pfi_channel % 2)); + return 0x7 << (4 + ioconfig_bitshift(pfi_channel)); } static inline unsigned pfi_input_select_bits(unsigned pfi_channel, unsigned input_select) { - return (input_select & 0x7) << (4 + 8 * (pfi_channel % 2)); + return (input_select & 0x7) << (4 + ioconfig_bitshift(pfi_channel)); +} + +// dma configuration register bits +static inline unsigned dma_select_mask(unsigned dma_channel) +{ + BUG_ON(dma_channel >= MAX_DMA_CHANNEL); + return 0x1f << (8 * dma_channel); +} +enum dma_selection +{ + dma_selection_none = 0x1f, +}; +static inline unsigned dma_selection_counter(unsigned counter_index) +{ + BUG_ON(counter_index >= CTRS_PER_CHIP); + return counter_index; +} +static inline unsigned dma_select_bits(unsigned dma_channel, unsigned selection) +{ + BUG_ON(dma_channel >= MAX_DMA_CHANNEL); + return (selection << (8 * dma_channel)) & dma_select_mask(dma_channel); +} +static inline unsigned dma_reset_bit(unsigned dma_channel) +{ + BUG_ON(dma_channel >= MAX_DMA_CHANNEL); + return 0x80 << (8 * dma_channel); } // Offset of the GPCT chips from the base-adress of the card @@ -314,8 +360,7 @@ typedef struct { unsigned short dev_id; /* `lspci` will show you this */ const char *name; - int n_ctrs; /* total number of counters */ - int cnt_bits; /* number of bits in each counter */ + unsigned n_chips; /* total number of TIO chips */ } ni_660x_board; static const ni_660x_board ni_660x_boards[] = @@ -323,17 +368,16 @@ static const ni_660x_board ni_660x_boards[] = { dev_id : 0x2c60, name : "PCI-6601", - n_ctrs : 1*CTRS_PER_CHIP, - cnt_bits : 32, + n_chips : 1, }, { dev_id : 0x1310, name : "PCI-6602", - n_ctrs : 2*CTRS_PER_CHIP, - cnt_bits : 32, + n_chips : 2, }, }; -#define NI_660X_MAX_NUM_COUNTERS 8 +#define NI_660X_MAX_NUM_CHIPS 2 +#define NI_660X_MAX_NUM_COUNTERS (NI_660X_MAX_NUM_CHIPS * CTRS_PER_CHIP) static struct pci_device_id ni_660x_pci_table[] __devinitdata = { { PCI_VENDOR_ID_NATINST, 0x2c60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, @@ -342,23 +386,34 @@ static struct pci_device_id ni_660x_pci_table[] __devinitdata = { }; MODULE_DEVICE_TABLE(pci, ni_660x_pci_table); -#define thisboard ((const ni_660x_board *)dev->board_ptr) -/* initialized in ni_660x_find_device() */ - typedef struct { struct mite_struct *mite; - int boardtype; struct ni_gpct_device *counter_dev; uint64_t pfi_direction_bits; + struct mite_dma_descriptor_ring *mite_rings[NI_660X_MAX_NUM_CHIPS][CTRS_PER_CHIP]; + spinlock_t mite_channel_lock; + unsigned dma_configuration_soft_copies[NI_660X_MAX_NUM_CHIPS]; + spinlock_t soft_reg_copy_lock; + unsigned short pfi_output_selects[NUM_PFI_CHANNELS]; }ni_660x_private; -#define devpriv ((ni_660x_private *)dev->private) +static inline ni_660x_private* private(comedi_device *dev) +{ + return dev->private; +} +/* initialized in ni_660x_find_device() */ +static inline const ni_660x_board* board(comedi_device *dev) +{ + return dev->board_ptr; +} + #define n_ni_660x_boards (sizeof(ni_660x_boards)/sizeof(ni_660x_boards[0])) static int ni_660x_attach(comedi_device *dev,comedi_devconfig *it); static int ni_660x_detach(comedi_device *dev); static void init_tio_chip(comedi_device *dev, int chipset); +static void ni_660x_select_pfi_output(comedi_device *dev, unsigned pfi_channel, unsigned output_select); static comedi_driver driver_ni_660x= { @@ -386,13 +441,6 @@ static int ni_660x_GPCT_winsn(comedi_device *dev, comedi_insn *insn, lsampl_t * data); -// NYI -#if 0 -static int ni_660x_GPCT_cmdtest(comedi_device *dev,comedi_subdevice *s, - comedi_cmd *cmd); -static int ni_660x_GPCT_cmd(comedi_device *dev,comedi_subdevice *s); -#endif - /* Possible instructions for Digital IO */ static int ni_660x_dio_insn_config(comedi_device *dev, comedi_subdevice *s, @@ -403,20 +451,10 @@ static int ni_660x_dio_insn_bits(comedi_device *dev, comedi_insn *insn, lsampl_t *data); -#if 0 -static int ni_660x_GPCT_cmdtest(comedi_device *dev,comedi_subdevice *s, - comedi_cmd *cmd) -{ - DPRINTK("NI_660X: COMMANDS not implemented yet for GPCT\n"); - return -EINVAL; -} - -static int ni_660x_GPCT_cmd(comedi_device *dev,comedi_subdevice *s) +static inline unsigned ni_660x_num_counters(comedi_device *dev) { - DPRINTK("NI_660X: COMMANDS not implemented yet for GPCT\n"); - return -EINVAL; + return board(dev)->n_chips * CTRS_PER_CHIP; } -#endif static NI_660x_Register ni_gpct_to_660x_register(enum ni_gpct_register reg) { @@ -615,6 +653,18 @@ static NI_660x_Register ni_gpct_to_660x_register(enum ni_gpct_register reg) case NITIO_G3_Status_Reg: ni_660x_register = G0StatusRegister; break; + case NITIO_G0_Interrupt_Enable_Reg: + ni_660x_register = G0InterruptEnable; + break; + case NITIO_G1_Interrupt_Enable_Reg: + ni_660x_register = G1InterruptEnable; + break; + case NITIO_G2_Interrupt_Enable_Reg: + ni_660x_register = G2InterruptEnable; + break; + case NITIO_G3_Interrupt_Enable_Reg: + ni_660x_register = G3InterruptEnable; + break; default: rt_printk("%s: unhandled register 0x%x in switch.\n", __FUNCTION__, reg); BUG(); @@ -624,13 +674,12 @@ static NI_660x_Register ni_gpct_to_660x_register(enum ni_gpct_register reg) return ni_660x_register; } -static void ni_gpct_write_register(struct ni_gpct *counter, unsigned bits, enum ni_gpct_register reg) +static inline void ni_660x_write_register(comedi_device *dev, unsigned chip_index, unsigned bits, NI_660x_Register reg) { - NI_660x_Register ni_660x_register = ni_gpct_to_660x_register(reg); - comedi_device *dev = counter->counter_dev->dev; - void * const write_address = devpriv->mite->daq_io_addr + GPCT_OFFSET[counter->chip_index] + registerData[ni_660x_register].offset; + void * const write_address = private(dev)->mite->daq_io_addr + GPCT_OFFSET[chip_index] + + registerData[reg].offset; - switch(registerData[ni_660x_register].size) + switch(registerData[reg].size) { case DATA_2B: writew(bits, write_address); @@ -639,19 +688,17 @@ static void ni_gpct_write_register(struct ni_gpct *counter, unsigned bits, enum writel(bits, write_address); break; default: - rt_printk("%s: %s: bug! unhandled case = 0x%x in switch.\n", __FILE__, __FUNCTION__, reg); + rt_printk("%s: %s: bug! unhandled case (reg=0x%x) in switch.\n", __FILE__, __FUNCTION__, reg); BUG(); break; } } -static unsigned ni_gpct_read_register(struct ni_gpct *counter, enum ni_gpct_register reg) +static inline unsigned ni_660x_read_register(comedi_device *dev, unsigned chip_index, NI_660x_Register reg) { - NI_660x_Register ni_660x_register = ni_gpct_to_660x_register(reg); - comedi_device *dev = counter->counter_dev->dev; - void * const read_address = devpriv->mite->daq_io_addr + GPCT_OFFSET[counter->chip_index] + registerData[ni_660x_register].offset; + void * const read_address = private(dev)->mite->daq_io_addr + GPCT_OFFSET[chip_index] + registerData[reg].offset; - switch(registerData[ni_660x_register].size) + switch(registerData[reg].size) { case DATA_2B: return readw(read_address); @@ -660,13 +707,197 @@ static unsigned ni_gpct_read_register(struct ni_gpct *counter, enum ni_gpct_regi return readl(read_address); break; default: - rt_printk("%s: %s: bug! unhandled case = 0x%x in switch.\n", __FILE__, __FUNCTION__, reg); + rt_printk("%s: %s: bug! unhandled case (reg=0x%x) in switch.\n", __FILE__, __FUNCTION__, reg); BUG(); break; } return 0; } +static void ni_gpct_write_register(struct ni_gpct *counter, unsigned bits, enum ni_gpct_register reg) +{ + comedi_device *dev = counter->counter_dev->dev; + NI_660x_Register ni_660x_register = ni_gpct_to_660x_register(reg); + ni_660x_write_register(dev, counter->chip_index, bits, ni_660x_register); +} + +static unsigned ni_gpct_read_register(struct ni_gpct *counter, enum ni_gpct_register reg) +{ + comedi_device *dev = counter->counter_dev->dev; + NI_660x_Register ni_660x_register = ni_gpct_to_660x_register(reg); + return ni_660x_read_register(dev, counter->chip_index, ni_660x_register); +} + +static inline struct mite_dma_descriptor_ring* mite_ring(ni_660x_private *priv, struct ni_gpct *counter) +{ + return priv->mite_rings[counter->chip_index][counter->counter_index]; +} + +static inline void ni_660x_set_dma_channel(comedi_device *dev, unsigned mite_channel, struct ni_gpct *counter) +{ + unsigned long flags; + comedi_spin_lock_irqsave(&private(dev)->soft_reg_copy_lock, flags); + private(dev)->dma_configuration_soft_copies[counter->chip_index] &= + ~dma_select_mask(mite_channel); + private(dev)->dma_configuration_soft_copies[counter->chip_index] |= + dma_select_bits(mite_channel, dma_selection_counter(counter->counter_index)); + ni_660x_write_register(dev, counter->chip_index, private(dev)->dma_configuration_soft_copies[counter->chip_index] | + dma_reset_bit(mite_channel), DMAConfigRegister); + mmiowb(); + comedi_spin_unlock_irqrestore(&private(dev)->soft_reg_copy_lock, flags); +} + +static inline void ni_660x_unset_dma_channel(comedi_device *dev, unsigned mite_channel, struct ni_gpct *counter) +{ + unsigned long flags; + comedi_spin_lock_irqsave(&private(dev)->soft_reg_copy_lock, flags); + private(dev)->dma_configuration_soft_copies[counter->chip_index] &= + ~dma_select_mask(mite_channel); + private(dev)->dma_configuration_soft_copies[counter->chip_index] |= + dma_select_bits(mite_channel, dma_selection_none); + ni_660x_write_register(dev, counter->chip_index, private(dev)->dma_configuration_soft_copies[counter->chip_index], + DMAConfigRegister); + mmiowb(); + comedi_spin_unlock_irqrestore(&private(dev)->soft_reg_copy_lock, flags); +} + +static int ni_660x_request_mite_channel(comedi_device *dev, struct ni_gpct *counter, enum comedi_io_direction direction) +{ + unsigned long flags; + struct mite_channel *mite_chan; + + comedi_spin_lock_irqsave(&private(dev)->mite_channel_lock, flags); + BUG_ON(counter->mite_chan); + mite_chan = mite_request_channel(private(dev)->mite, mite_ring(private(dev), counter)); + if(mite_chan == NULL) + { + comedi_spin_unlock_irqrestore(&private(dev)->mite_channel_lock, flags); + comedi_error(dev, "failed to reserve mite dma channel for counter."); + return -EBUSY; + } + mite_chan->dir = direction; + ni_tio_set_mite_channel(counter, mite_chan); + ni_660x_set_dma_channel(dev, mite_chan->channel, counter); + comedi_spin_unlock_irqrestore(&private(dev)->mite_channel_lock, flags); + return 0; +} + +void ni_660x_release_mite_channel(comedi_device *dev, struct ni_gpct *counter) +{ + unsigned long flags; + + comedi_spin_lock_irqsave(&private(dev)->mite_channel_lock, flags); + if(counter->mite_chan) + { + struct mite_channel *mite_chan = counter->mite_chan; + + ni_660x_unset_dma_channel(dev, mite_chan->channel, counter); + ni_tio_set_mite_channel(counter, NULL); + mite_release_channel(mite_chan); + } + comedi_spin_unlock_irqrestore(&private(dev)->mite_channel_lock, flags); +} + +static int ni_660x_cmd(comedi_device *dev, comedi_subdevice *s) +{ + int retval; + + struct ni_gpct *counter = subdev_to_counter(s); +// const comedi_cmd *cmd = &s->async->cmd; + + retval = ni_660x_request_mite_channel(dev, counter, COMEDI_INPUT); + if(retval) + { + comedi_error(dev, "no dma channel available for use by counter"); + return retval; + } + ni_tio_acknowledge_and_confirm(counter, NULL, NULL, NULL, NULL); + retval = ni_tio_cmd(counter, s->async); + + return retval; +} + +static int ni_660x_cmdtest(comedi_device *dev, comedi_subdevice *s, comedi_cmd *cmd) +{ + struct ni_gpct *counter = subdev_to_counter(s); + + return ni_tio_cmdtest(counter, cmd); +} + +static int ni_660x_cancel(comedi_device *dev, comedi_subdevice *s) +{ + struct ni_gpct *counter = subdev_to_counter(s); + int retval; + + retval = ni_tio_cancel(counter); + ni_660x_release_mite_channel(dev, counter); + return retval; +} + +static irqreturn_t ni_660x_interrupt(int irq, void *d PT_REGS_ARG) +{ + return IRQ_HANDLED; +} + +static int ni_660x_buf_change(comedi_device *dev, comedi_subdevice *s, + unsigned long new_size) +{ + int ret; + + ret = mite_buf_change(mite_ring(private(dev), subdev_to_counter(s)), s->async); + if(ret < 0) return ret; + + return 0; +} + +static int ni_660x_allocate_private(comedi_device *dev) +{ + int retval; + unsigned i; + + if((retval = alloc_private(dev, sizeof(ni_660x_private))) < 0) return retval; + spin_lock_init(&private(dev)->mite_channel_lock); + spin_lock_init(&private(dev)->soft_reg_copy_lock); + for(i = 0; i < NUM_PFI_CHANNELS; ++i) + { + private(dev)->pfi_output_selects[i] = pfi_output_select_counter; + } + return 0; +} + +static int ni_660x_alloc_mite_rings(comedi_device *dev) +{ + unsigned i; + unsigned j; + + for(i = 0; i < board(dev)->n_chips; ++i) + { + for(j = 0; j < CTRS_PER_CHIP; ++j) + { + private(dev)->mite_rings[i][j] = mite_alloc_ring(private(dev)->mite); + if(private(dev)->mite_rings[i][j] == NULL) + { + return -ENOMEM; + } + } + } + return 0; +} + +static void ni_660x_free_mite_rings(comedi_device *dev) +{ + unsigned i; + unsigned j; + + for(i = 0; i < board(dev)->n_chips; ++i) + { + for(j = 0; j < CTRS_PER_CHIP; ++j) + { + mite_free_ring(private(dev)->mite_rings[i][j]); + } + } +} + static int ni_660x_attach(comedi_device *dev,comedi_devconfig *it) { comedi_subdevice *s; @@ -675,19 +906,21 @@ static int ni_660x_attach(comedi_device *dev,comedi_devconfig *it) printk("comedi%d: ni_660x: ",dev->minor); - if ((ret=alloc_private(dev,sizeof(ni_660x_private))) < 0) return ret; - + ret = ni_660x_allocate_private(dev); + if(ret < 0) return ret; ret = ni_660x_find_device(dev, it->options[0], it->options[1]); if (ret<0) return ret; - ret = mite_setup(devpriv->mite); + dev->board_name = board(dev)->name; + + ret = mite_setup(private(dev)->mite); if (ret < 0) { - printk("error setting up mite\n"); - return ret; + printk("error setting up mite\n"); + return ret; } - dev->board_name = thisboard->name; - /* we don't support the interrupt yet */ - //dev->irq = mite_irq(devpriv->mite); + comedi_set_hw_dev(dev, &private(dev)->mite->pcidev->dev); + ret = ni_660x_alloc_mite_rings(dev); + if(ret < 0) return ret; printk(" %s ", dev->board_name); @@ -710,42 +943,57 @@ static int ni_660x_attach(comedi_device *dev,comedi_devconfig *it) s->insn_config = ni_660x_dio_insn_config; s->io_bits = 0; /* all bits default to input */ // we use the ioconfig registers to control dio direction, so zero output enables in stc dio control reg - writew(0, devpriv->mite->daq_io_addr + registerData[STCDIOControl].offset); + ni_660x_write_register(dev, 0, 0, STCDIOControl); - devpriv->counter_dev = ni_gpct_device_construct(dev, + private(dev)->counter_dev = ni_gpct_device_construct(dev, &ni_gpct_write_register, &ni_gpct_read_register, - ni_gpct_variant_660x, thisboard->n_ctrs); - if(devpriv->counter_dev == NULL) return -ENOMEM; + ni_gpct_variant_660x, ni_660x_num_counters(dev)); + if(private(dev)->counter_dev == NULL) return -ENOMEM; for(i = 0; i < NI_660X_MAX_NUM_COUNTERS; ++i) { s = dev->subdevices + 2 + i; - if(i < thisboard->n_ctrs) + if(i < ni_660x_num_counters(dev)) { s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL | SDF_CMD_READ /* | SDF_CMD_WRITE */; s->n_chan = 3; s->maxdata = 0xffffffff; s->insn_read = ni_660x_GPCT_rinsn; s->insn_write = ni_660x_GPCT_winsn; s->insn_config = ni_660x_GPCT_insn_config; - s->private = &devpriv->counter_dev->counters[i]; - - devpriv->counter_dev->counters[i].chip_index = i / CTRS_PER_CHIP; - devpriv->counter_dev->counters[i].counter_index = i % CTRS_PER_CHIP; + s->do_cmd = &ni_660x_cmd; + s->len_chanlist = 1; + s->do_cmdtest = &ni_660x_cmdtest; + s->cancel = &ni_660x_cancel; + s->async_dma_dir = DMA_BIDIRECTIONAL; + s->buf_change = &ni_660x_buf_change; + s->private = &private(dev)->counter_dev->counters[i]; + + private(dev)->counter_dev->counters[i].chip_index = i / CTRS_PER_CHIP; + private(dev)->counter_dev->counters[i].counter_index = i % CTRS_PER_CHIP; }else { s->type = COMEDI_SUBD_UNUSED; } } - for(i = 0; i < thisboard->n_ctrs / CTRS_PER_CHIP; ++i) + for(i = 0; i < board(dev)->n_chips; ++i) { init_tio_chip(dev, i); } - for(i = 0; i < thisboard->n_ctrs; ++i) + for(i = 0; i < ni_660x_num_counters(dev); ++i) { - ni_tio_init_counter(&devpriv->counter_dev->counters[i]); + ni_tio_init_counter(&private(dev)->counter_dev->counters[i]); } - + for(i = 0; i < NUM_PFI_CHANNELS; ++i) + { + ni_660x_select_pfi_output(dev, i, pfi_output_select_high_Z); + } + if((ret = comedi_request_irq(mite_irq(private(dev)->mite), &ni_660x_interrupt, IRQF_SHARED, "ni_660x", dev)) < 0) + { + printk(" irq not available\n"); + return ret; + } + dev->irq = mite_irq(private(dev)->mite); printk("attached\n"); return 0; } @@ -756,18 +1004,19 @@ ni_660x_detach(comedi_device *dev) { printk("comedi%d: ni_660x: remove\n",dev->minor); + /* Free irq */ + if(dev->irq) comedi_free_irq(dev->irq, dev); + if(dev->private) { - if(devpriv->counter_dev) - ni_gpct_device_destroy(devpriv->counter_dev); - if(devpriv->mite) - mite_unsetup(devpriv->mite); + if(private(dev)->counter_dev) + ni_gpct_device_destroy(private(dev)->counter_dev); + if(private(dev)->mite) + { + ni_660x_free_mite_rings(dev); + mite_unsetup(private(dev)->mite); + } } - /* Free irq */ - - if(dev->irq) comedi_free_irq(dev->irq,dev); - - /* Same question as with attach ... */ return 0; } @@ -775,30 +1024,37 @@ static int ni_660x_GPCT_rinsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data) { - struct ni_gpct *counter = s->private; - return ni_tio_rinsn(counter, insn, data); + return ni_tio_rinsn(subdev_to_counter(s), insn, data); } static void init_tio_chip(comedi_device *dev, int chipset) { + unsigned i; + /* See P. 3.5 of the Register-Level Programming manual. The CounterSwap bit has to be set on the second chip, otherwise it will try to use the same pins as the first chip. */ if(chipset) - writel(CounterSwap,devpriv->mite->daq_io_addr + GPCT_OFFSET[1] - + registerData[ClockConfigRegister].offset); + ni_660x_write_register(dev, chipset, CounterSwap, ClockConfigRegister); else - writel(0,devpriv->mite->daq_io_addr + GPCT_OFFSET[0] - + registerData[ClockConfigRegister].offset); + ni_660x_write_register(dev, chipset, 0, ClockConfigRegister); + // init dma configuration register + private(dev)->dma_configuration_soft_copies[chipset] = 0; + for(i = 0; i < MAX_DMA_CHANNEL; ++i) + { + private(dev)->dma_configuration_soft_copies[chipset] |= + dma_select_bits(i, dma_selection_none) & dma_select_mask(i); + } + ni_660x_write_register(dev, chipset, private(dev)->dma_configuration_soft_copies[chipset], + DMAConfigRegister); } static int ni_660x_GPCT_insn_config(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data) { - struct ni_gpct *counter = s->private; - return ni_tio_insn_config(counter, insn, data); + return ni_tio_insn_config(subdev_to_counter(s), insn, data); } static int ni_660x_GPCT_winsn(comedi_device *dev, @@ -806,8 +1062,7 @@ static int ni_660x_GPCT_winsn(comedi_device *dev, comedi_insn *insn, lsampl_t * data) { - struct ni_gpct *counter = s->private; - return ni_tio_winsn(counter, insn, data); + return ni_tio_winsn(subdev_to_counter(s), insn, data); } static int @@ -826,7 +1081,7 @@ ni_660x_find_device(comedi_device *dev, int bus, int slot) for (i=0; iboard_ptr=ni_660x_boards+i; - devpriv->mite=mite; + private(dev)->mite=mite; return 0; } } @@ -847,43 +1102,49 @@ static int ni_660x_dio_insn_bits(comedi_device *dev, // Check if we have to write some bits if(data[0]) { - /* Only the first 8 lines can be read/written. The rest can - only have their input/output configuration changed (although - the user manual implies the first 32 channels can be used as - general purpose dio, the register manual doesn't tell you how - this can be accomplished. */ - /*FIXME: use DIO32Input and DIO32Output registers for dio - to the 32 bit port */ - if((data[0] << base_bitfield_channel) > 0xff) - { - return -EINVAL; - } s->state &= ~(data[0] << base_bitfield_channel); s->state |= (data[0] & data[1]) << base_bitfield_channel; /* Write out the new digital output lines */ - writew(s->state,devpriv->mite->daq_io_addr + registerData[STCDIOOutput].offset); + ni_660x_write_register(dev, 0, s->state, DIO32Output); } /* on return, data[1] contains the value of the digital * input and output lines. */ - data[1] = (readw(devpriv->mite->daq_io_addr + registerData[STCDIOParallelInput].offset) >> base_bitfield_channel) & - (0xff >> base_bitfield_channel); + data[1] = (ni_660x_read_register(dev, 0, DIO32Input) >> base_bitfield_channel); return 2; } static void ni_660x_select_pfi_output(comedi_device *dev, unsigned pfi_channel, unsigned output_select) { - unsigned bits = readw(devpriv->mite->daq_io_addr + registerData[IOConfigReg(pfi_channel)].offset); + unsigned bits = ni_660x_read_register(dev, 0, IOConfigReg(pfi_channel)); + bits &= ~pfi_output_select_mask(pfi_channel); bits |= pfi_output_select_bits(pfi_channel, output_select); - writew(bits, devpriv->mite->daq_io_addr + registerData[IOConfigReg(pfi_channel)].offset); + ni_660x_write_register(dev, 0, bits, IOConfigReg(pfi_channel)); +} + +static int ni_660x_set_pfi_routing(comedi_device *dev, unsigned chan, unsigned source) +{ + if(source > num_pfi_output_selects) return -EINVAL; + BUG_ON(chan >= NUM_PFI_CHANNELS); + + private(dev)->pfi_output_selects[chan] = source; + if(private(dev)->pfi_direction_bits & (((uint64_t)1) << chan)) + ni_660x_select_pfi_output(dev, chan, private(dev)->pfi_output_selects[chan]); + return 0; +} + +static unsigned ni_660x_get_pfi_routing(comedi_device *dev, unsigned chan) +{ + BUG_ON(chan >= NUM_PFI_CHANNELS); + return private(dev)->pfi_output_selects[chan]; } static void ni660x_config_filter(comedi_device *dev, unsigned pfi_channel, enum ni_gpct_filter_select filter) { - unsigned bits = readw(devpriv->mite->daq_io_addr + registerData[IOConfigReg(pfi_channel)].offset); + unsigned bits = ni_660x_read_register(dev, 0, IOConfigReg(pfi_channel)); bits &= ~pfi_input_select_mask(pfi_channel); bits |= pfi_input_select_bits(pfi_channel, filter); - writew(bits, devpriv->mite->daq_io_addr + registerData[IOConfigReg(pfi_channel)].offset); + ni_660x_write_register(dev, 0, bits, IOConfigReg(pfi_channel)); } static int ni_660x_dio_insn_config(comedi_device *dev, @@ -891,7 +1152,7 @@ static int ni_660x_dio_insn_config(comedi_device *dev, comedi_insn *insn, lsampl_t *data) { - int chan=CR_CHAN(insn->chanspec); + int chan = CR_CHAN(insn->chanspec); /* The input or output configuration of each digital line is * configured by a special insn_config instruction. chanspec @@ -901,17 +1162,22 @@ static int ni_660x_dio_insn_config(comedi_device *dev, switch(data[0]) { case INSN_CONFIG_DIO_OUTPUT: - devpriv->pfi_direction_bits |= ((uint64_t)1) << chan; - //FIXME: output select 1 is counter output, 2 is digital output - ni_660x_select_pfi_output(dev, chan, 1); + private(dev)->pfi_direction_bits |= ((uint64_t)1) << chan; + ni_660x_select_pfi_output(dev, chan, private(dev)->pfi_output_selects[chan]); break; case INSN_CONFIG_DIO_INPUT: - devpriv->pfi_direction_bits &= ~(((uint64_t)1) << chan); - ni_660x_select_pfi_output(dev, chan, 0); + private(dev)->pfi_direction_bits &= ~(((uint64_t)1) << chan); + ni_660x_select_pfi_output(dev, chan, pfi_output_select_high_Z); break; case INSN_CONFIG_DIO_QUERY: - data[1] = (devpriv->pfi_direction_bits & (((uint64_t)1) << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; + data[1] = (private(dev)->pfi_direction_bits & (((uint64_t)1) << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; return 0; + case INSN_CONFIG_SET_ROUTING: + return ni_660x_set_pfi_routing(dev, chan, data[1]); + break; + case INSN_CONFIG_GET_ROUTING: + data[1] = ni_660x_get_pfi_routing(dev, chan); + break; case INSN_CONFIG_FILTER: ni660x_config_filter(dev, chan, data[1]); break; diff --git a/comedi/drivers/ni_mio_common.c b/comedi/drivers/ni_mio_common.c index 36f96ac4..fdac6580 100644 --- a/comedi/drivers/ni_mio_common.c +++ b/comedi/drivers/ni_mio_common.c @@ -347,55 +347,53 @@ static void get_last_sample_611x( comedi_device *dev ); static void get_last_sample_6143( comedi_device *dev ); #ifdef PCIDMA static int ni_ai_drain_dma(comedi_device *dev ); +static inline void ni_set_bitfield(comedi_device *dev, int reg, unsigned bit_mask, unsigned bit_values); /* DMA channel setup */ // negative channel means no channel static inline void ni_set_ai_dma_channel(comedi_device *dev, int channel) { - unsigned long flags; + unsigned bitfield; - comedi_spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags); - devpriv->ai_ao_select_reg &= ~AI_DMA_Select_Mask; if(channel >= 0) { - devpriv->ai_ao_select_reg |= (ni_stc_dma_channel_select_bitfield(channel) << AI_DMA_Select_Shift) & AI_DMA_Select_Mask; + bitfield = (ni_stc_dma_channel_select_bitfield(channel) << AI_DMA_Select_Shift) & AI_DMA_Select_Mask; + }else + { + bitfield = 0; } - ni_writeb(devpriv->ai_ao_select_reg, AI_AO_Select); - mmiowb(); - comedi_spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags); + ni_set_bitfield(dev, AI_AO_Select, AI_DMA_Select_Mask, bitfield); } // negative channel means no channel static inline void ni_set_ao_dma_channel(comedi_device *dev, int channel) { - unsigned long flags; + unsigned bitfield; - comedi_spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags); - devpriv->ai_ao_select_reg &= ~AO_DMA_Select_Mask; if(channel >= 0) { - devpriv->ai_ao_select_reg |= (ni_stc_dma_channel_select_bitfield(channel) << AO_DMA_Select_Shift) & AO_DMA_Select_Mask; + bitfield = (ni_stc_dma_channel_select_bitfield(channel) << AO_DMA_Select_Shift) & AO_DMA_Select_Mask; + }else + { + bitfield = 0; } - ni_writeb(devpriv->ai_ao_select_reg, AI_AO_Select); - mmiowb(); - comedi_spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags); + ni_set_bitfield(dev, AI_AO_Select, AO_DMA_Select_Mask, bitfield); } // negative mite_channel means no channel static inline void ni_set_gpct_dma_channel(comedi_device *dev, unsigned gpct_index, int mite_channel) { - unsigned long flags; + unsigned bitfield; - comedi_spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags); - devpriv->g0_g1_select_reg &= ~GPCT_DMA_Select_Mask(gpct_index); if(mite_channel >= 0) { - devpriv->g0_g1_select_reg |= GPCT_DMA_Select_Bits(gpct_index, mite_channel); + bitfield = GPCT_DMA_Select_Bits(gpct_index, mite_channel); + }else + { + bitfield = 0; } - ni_writeb(devpriv->g0_g1_select_reg, G0_G1_Select); - mmiowb(); - comedi_spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags); + ni_set_bitfield(dev, G0_G1_Select, GPCT_DMA_Select_Mask(gpct_index), bitfield); } // negative mite_channel means no channel @@ -542,9 +540,11 @@ void ni_release_gpct_mite_channel(comedi_device *dev, unsigned gpct_index) comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if(devpriv->counter_dev->counters[gpct_index].mite_chan) { + struct mite_channel *mite_chan = devpriv->counter_dev->counters[gpct_index].mite_chan; + ni_set_gpct_dma_channel(dev, gpct_index, -1); - mite_release_channel(devpriv->counter_dev->counters[gpct_index].mite_chan); ni_tio_set_mite_channel(&devpriv->counter_dev->counters[gpct_index], NULL); + mite_release_channel(mite_chan); } comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); #endif // PCIDMA @@ -666,51 +666,66 @@ static inline unsigned short ni_ao_win_inw( comedi_device *dev, int addr ) return data; } -/* ni_set_bits( ) allows different parts of the ni_mio_common driver to -* share registers (such as Interrupt_A_Register) without interfering with -* each other. -* -* NOTE: the switch/case statements are optimized out for a constant argument -* so this is actually quite fast--- If you must wrap another function around this -* make it inline to avoid a large speed penalty. -* -* value should only be 1 or 0. -*/ -static inline void ni_set_bits(comedi_device *dev, int reg, int bits, int value) +static inline void ni_set_bitfield(comedi_device *dev, int reg, unsigned bit_mask, unsigned bit_values) { unsigned long flags; comedi_spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags); switch (reg){ case Interrupt_A_Enable_Register: - if(value) - devpriv->int_a_enable_reg |= bits; - else - devpriv->int_a_enable_reg &= ~bits; - devpriv->stc_writew(dev, devpriv->int_a_enable_reg,Interrupt_A_Enable_Register); + devpriv->int_a_enable_reg &= ~bit_mask; + devpriv->int_a_enable_reg |= bit_values & bit_mask; + devpriv->stc_writew(dev, devpriv->int_a_enable_reg, Interrupt_A_Enable_Register); break; case Interrupt_B_Enable_Register: - if(value) - devpriv->int_b_enable_reg |= bits; - else - devpriv->int_b_enable_reg &= ~bits; - devpriv->stc_writew(dev, devpriv->int_b_enable_reg,Interrupt_B_Enable_Register); + devpriv->int_b_enable_reg &= ~bit_mask; + devpriv->int_b_enable_reg |= bit_values & bit_mask; + devpriv->stc_writew(dev, devpriv->int_b_enable_reg, Interrupt_B_Enable_Register); break; case IO_Bidirection_Pin_Register: - if(value) - devpriv->io_bidirection_pin_reg |= bits; - else - devpriv->io_bidirection_pin_reg &= ~bits; - devpriv->stc_writew(dev, devpriv->io_bidirection_pin_reg,IO_Bidirection_Pin_Register); + devpriv->io_bidirection_pin_reg &= ~bit_mask; + devpriv->io_bidirection_pin_reg |= bit_values & bit_mask; + devpriv->stc_writew(dev, devpriv->io_bidirection_pin_reg, IO_Bidirection_Pin_Register); + break; + case AI_AO_Select: + devpriv->ai_ao_select_reg &= ~bit_mask; + devpriv->ai_ao_select_reg |= bit_values & bit_mask; + ni_writeb(devpriv->ai_ao_select_reg, AI_AO_Select); + break; + case G0_G1_Select: + devpriv->g0_g1_select_reg &= ~bit_mask; + devpriv->g0_g1_select_reg |= bit_values & bit_mask; + ni_writeb(devpriv->g0_g1_select_reg, G0_G1_Select); break; default: - rt_printk("Warning ni_set_bits() called with invalid arguments\n"); - rt_printk("reg is %d\n",reg); + rt_printk("Warning %s() called with invalid register\n", __FUNCTION__); + rt_printk("reg is %d\n", reg); break; } + mmiowb(); comedi_spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags ); } +/* ni_set_bits( ) allows different parts of the ni_mio_common driver to +* share registers (such as Interrupt_A_Register) without interfering with +* each other. +* +* NOTE: the switch/case statements are optimized out for a constant argument +* so this is actually quite fast--- If you must wrap another function around this +* make it inline to avoid a large speed penalty. +* +* value should only be 1 or 0. +*/ +static inline void ni_set_bits(comedi_device *dev, int reg, unsigned bits, unsigned value) +{ + unsigned bit_values; + + if(value) + bit_values = bits; + else + bit_values = 0; + ni_set_bitfield(dev, reg, bits, bit_values); +} static irqreturn_t ni_E_interrupt(int irq, void *d PT_REGS_ARG) { @@ -3758,6 +3773,12 @@ static unsigned ni_gpct_to_stc_register(enum ni_gpct_register reg) case NITIO_G1_Status_Reg: stc_register = AO_Status_1_Register; break; + case NITIO_G0_Interrupt_Enable_Reg: + stc_register = Interrupt_A_Enable_Register; + break; + case NITIO_G1_Interrupt_Enable_Reg: + stc_register = Interrupt_B_Enable_Register; + break; default: rt_printk("%s: unhandled register 0x%x in switch.\n", __FUNCTION__, reg); BUG(); @@ -3773,6 +3794,9 @@ static void ni_gpct_write_register(struct ni_gpct *counter, unsigned bits, enum unsigned stc_register; /* bits in the join reset register which are relevant to counters */ static const unsigned gpct_joint_reset_mask = G0_Reset | G1_Reset; + static const unsigned gpct_interrupt_a_enable_mask = G0_Gate_Interrupt_Enable | G0_TC_Interrupt_Enable; + static const unsigned gpct_interrupt_b_enable_mask = G1_Gate_Interrupt_Enable | G1_TC_Interrupt_Enable; + switch(reg) { /* m-series-only registers */ @@ -3811,6 +3835,14 @@ static void ni_gpct_write_register(struct ni_gpct *counter, unsigned bits, enum break; /* 16 bit registers */ + case NITIO_G0_Interrupt_Enable_Reg: + BUG_ON(bits & ~gpct_interrupt_a_enable_mask); + ni_set_bitfield(dev, Interrupt_A_Enable_Register, gpct_interrupt_a_enable_mask, bits); + break; + case NITIO_G1_Interrupt_Enable_Reg: + BUG_ON(bits & ~gpct_interrupt_b_enable_mask); + ni_set_bitfield(dev, Interrupt_B_Enable_Register, gpct_interrupt_b_enable_mask, bits); + break; case NITIO_G01_Joint_Reset_Reg: BUG_ON(bits & ~gpct_joint_reset_mask); /* fall-through */ @@ -4650,132 +4682,12 @@ static int ni_gpct_insn_write(comedi_device *dev, comedi_subdevice *s, return ni_tio_winsn(counter, insn, data); } -static inline unsigned Gi_Interrupt_Enable_Register(unsigned counter_index) -{ - unsigned reg; - - switch(counter_index) - { - case 0: - reg = Interrupt_A_Enable_Register; - break; - case 1: - reg = Interrupt_B_Enable_Register; - break; - default: - BUG(); - return 0; - break; - } - return reg; -} - -static inline unsigned Gi_Gate_Interrupt_Enable_Bit(unsigned counter_index) -{ - unsigned bit; - - switch(counter_index) - { - case 0: - bit = G0_Gate_Interrupt_Enable; - break; - case 1: - bit = G1_Gate_Interrupt_Enable; - break; - default: - BUG(); - return 0; - break; - } - return bit; -} - -static inline unsigned Gi_Interrupt_Ack_Register(unsigned counter_index) -{ - unsigned reg; - - switch(counter_index) - { - case 0: - reg = Interrupt_A_Ack_Register; - break; - case 1: - reg = Interrupt_B_Ack_Register; - break; - default: - BUG(); - return 0; - break; - } - return reg; -} - -static inline unsigned Gi_Gate_Interrupt_Ack_Bit(unsigned counter_index) -{ - unsigned bit; - - switch(counter_index) - { - case 0: - bit = G0_Gate_Interrupt_Ack; - break; - case 1: - bit = G1_Gate_Interrupt_Ack; - break; - default: - BUG(); - return 0; - break; - } - return bit; -} - -static inline unsigned Gi_Gate_Error_Confirm_Bit(unsigned counter_index) -{ - unsigned bit; - - switch(counter_index) - { - case 0: - bit = G0_Gate_Error_Confirm; - break; - case 1: - bit = G1_Gate_Error_Confirm; - break; - default: - BUG(); - return 0; - break; - } - return bit; -} - -static inline unsigned Gi_TC_Error_Confirm_Bit(unsigned counter_index) -{ - unsigned bit; - - switch(counter_index) - { - case 0: - bit = G0_TC_Error_Confirm; - break; - case 1: - bit = G1_TC_Error_Confirm; - break; - default: - BUG(); - return 0; - break; - } - return bit; -} - static int ni_gpct_cmd(comedi_device *dev, comedi_subdevice *s) { int retval; #ifdef PCIDMA struct ni_gpct *counter = s->private; - const comedi_cmd *cmd = &s->async->cmd; +// const comedi_cmd *cmd = &s->async->cmd; retval = ni_request_gpct_mite_channel(dev, counter->counter_index, COMEDI_INPUT); if(retval) @@ -4783,15 +4695,7 @@ static int ni_gpct_cmd(comedi_device *dev, comedi_subdevice *s) comedi_error(dev, "no dma channel available for use by counter"); return retval; } - devpriv->stc_writew(dev, Gi_Gate_Interrupt_Ack_Bit(counter->counter_index) | - Gi_Gate_Error_Confirm_Bit(counter->counter_index) | - Gi_TC_Error_Confirm_Bit(counter->counter_index), - Gi_Interrupt_Ack_Register(counter->counter_index)); - if(cmd->flags & TRIG_WAKE_EOS) - { - ni_set_bits(dev, Gi_Interrupt_Enable_Register(counter->counter_index), - Gi_Gate_Interrupt_Enable_Bit(counter->counter_index), 1); - } + ni_tio_acknowledge_and_confirm(counter, NULL, NULL, NULL, NULL); ni_e_series_enable_second_irq(dev, counter->counter_index, 1); retval = ni_tio_cmd(counter, s->async); #else @@ -4814,8 +4718,6 @@ static int ni_gpct_cancel(comedi_device *dev, comedi_subdevice *s) retval = ni_tio_cancel(counter); ni_e_series_enable_second_irq(dev, counter->counter_index, 0); - ni_set_bits(dev, Gi_Interrupt_Enable_Register(counter->counter_index), - Gi_Gate_Interrupt_Enable_Bit(counter->counter_index), 0); ni_release_gpct_mite_channel(dev, counter->counter_index); return retval; } diff --git a/comedi/drivers/ni_stc.h b/comedi/drivers/ni_stc.h index bf213c00..e544d8d3 100644 --- a/comedi/drivers/ni_stc.h +++ b/comedi/drivers/ni_stc.h @@ -1345,9 +1345,15 @@ enum CDI_Mode_Bits { CDI_Sample_Source_Select_Mask = 0x3f, CDI_Halt_On_Error_Bit = 0x200, - CDI_Polarity_Bit = 0x400, - CDI_FIFO_Mode_Bit = 0x800, - CDI_Data_Lane_Mask = 0x3000 + CDI_Polarity_Bit = 0x400, // sample clock on falling edge + CDI_FIFO_Mode_Bit = 0x800, // set for half full mode, clear for not empty mode + CDI_Data_Lane_Mask = 0x3000, // data lanes specify which dio channels map to byte or word accesses to the dio fifos + CDI_Data_Lane_0_15_Bits = 0x0, + CDI_Data_Lane_16_31_Bits = 0x1000, + CDI_Data_Lane_0_7_Bits = 0x0, + CDI_Data_Lane_8_15_Bits = 0x1000, + CDI_Data_Lane_16_23_Bits = 0x2000, + CDI_Data_Lane_24_31_Bits = 0x3000 }; enum CDO_Mode_Bits @@ -1355,9 +1361,25 @@ enum CDO_Mode_Bits CDO_Sample_Source_Select_Mask = 0x3f, CDO_Retransmit_Bit = 0x100, CDO_Halt_On_Error_Bit = 0x200, - CDO_Polarity_Bit = 0x400, - CDO_FIFO_Mode_Bit = 0x800, - CDO_Data_Lane_Mask = 0x3000 + CDO_Polarity_Bit = 0x400, // sample clock on falling edge + CDO_FIFO_Mode_Bit = 0x800, // set for half full mode, clear for not full mode + CDO_Data_Lane_Mask = 0x3000, // data lanes specify which dio channels map to byte or word accesses to the dio fifos + CDO_Data_Lane_0_15_Bits = 0x0, + CDO_Data_Lane_16_31_Bits = 0x1000, + CDO_Data_Lane_0_7_Bits = 0x0, + CDO_Data_Lane_8_15_Bits = 0x1000, + CDO_Data_Lane_16_23_Bits = 0x2000, + CDO_Data_Lane_24_31_Bits = 0x3000 +}; + +enum Interrupt_C_Enable_Bits +{ + Interrupt_Group_C_Enable_Bit = 0x1 +}; + +enum Interrupt_C_Status_Bits +{ + Interrupt_Group_C_Status_Bit = 0x1 }; #define M_SERIES_EEPROM_SIZE 1024 @@ -1458,6 +1480,7 @@ typedef struct ni_board_struct{ unsigned short pfi_output_select_reg[NUM_PFI_OUTPUT_SELECT_REGS]; \ unsigned short ai_ao_select_reg; \ unsigned short g0_g1_select_reg; \ + unsigned short cdio_dma_select_reg; \ \ unsigned clock_ns; \ unsigned clock_source; \ @@ -1475,8 +1498,10 @@ typedef struct ni_board_struct{ struct mite_struct *mite; \ struct mite_channel *ai_mite_chan; \ struct mite_channel *ao_mite_chan;\ + struct mite_channel *cdo_mite_chan;\ struct mite_dma_descriptor_ring *ai_mite_ring; \ struct mite_dma_descriptor_ring *ao_mite_ring; \ + struct mite_dma_descriptor_ring *cdo_mite_ring; \ struct mite_dma_descriptor_ring *gpct_mite_ring[NUM_GPCT]; diff --git a/comedi/drivers/ni_tio.c b/comedi/drivers/ni_tio.c index 0350ecb5..e78dede0 100644 --- a/comedi/drivers/ni_tio.c +++ b/comedi/drivers/ni_tio.c @@ -29,7 +29,7 @@ Author: J.P. Mellor , Klaas.Gadeyne@mech.kuleuven.ac.be, Frank Mori Hess Updated: Thu Nov 16 09:50:32 EST 2006 -Status: experimental +Status: works This module is not used directly by end-users. Rather, it is used by other drivers (for example ni_660x and ni_pcimio) @@ -427,6 +427,29 @@ static inline enum ni_gpct_register NITIO_Gi_Status_Reg(int counter_index) return 0; } +static inline enum ni_gpct_register NITIO_Gi_Interrupt_Enable_Reg(int counter_index) +{ + switch(counter_index) + { + case 0: + return NITIO_G0_Interrupt_Enable_Reg; + break; + case 1: + return NITIO_G1_Interrupt_Enable_Reg; + break; + case 2: + return NITIO_G2_Interrupt_Enable_Reg; + break; + case 3: + return NITIO_G3_Interrupt_Enable_Reg; + break; + default: + BUG(); + break; + } + return 0; +} + enum Gi_Auto_Increment_Reg_Bits { Gi_Auto_Increment_Mask = 0xff @@ -871,6 +894,31 @@ enum Gi_Status_Bits Gi_Interrupt_Bit = 0x8000 }; +enum G02_Interrupt_Enable_Bits +{ + G0_TC_Interrupt_Enable_Bit = 0x40, + G0_Gate_Interrupt_Enable_Bit = 0x100 +}; +enum G13_Interrupt_Enable_Bits +{ + G1_TC_Interrupt_Enable_Bit = 0x200, + G1_Gate_Interrupt_Enable_Bit = 0x400 +}; +static inline unsigned Gi_Gate_Interrupt_Enable_Bit(unsigned counter_index) +{ + unsigned bit; + + if(counter_index % 2) + { + bit = G1_Gate_Interrupt_Enable_Bit; + }else + { + bit = G0_Gate_Interrupt_Enable_Bit; + } + return bit; +} + + static const lsampl_t counter_status_mask = COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING; static inline void write_register(struct ni_gpct *counter, unsigned bits, enum ni_gpct_register reg) @@ -2438,10 +2486,12 @@ static int ni_tio_output_cmd(struct ni_gpct *counter, comedi_async *async) static int ni_tio_cmd_setup(struct ni_gpct *counter, comedi_async *async) { + struct ni_gpct_device *counter_dev = counter->counter_dev; comedi_cmd *cmd = &async->cmd; int set_gate_source = 0; unsigned gate_source; int retval = 0; + const unsigned interrupt_enable_reg = NITIO_Gi_Interrupt_Enable_Reg(counter->counter_index); if(cmd->scan_begin_src == TRIG_EXT) { @@ -2456,6 +2506,11 @@ static int ni_tio_cmd_setup(struct ni_gpct *counter, comedi_async *async) { retval = ni_tio_set_gate_src(counter, 0, gate_source); } + if(cmd->flags & TRIG_WAKE_EOS) + { + counter_dev->regs[interrupt_enable_reg] |= Gi_Gate_Interrupt_Enable_Bit(counter->counter_index); + write_register(counter, counter_dev->regs[interrupt_enable_reg], interrupt_enable_reg); + } return retval; } @@ -2593,6 +2648,8 @@ int ni_tio_cmdtest(struct ni_gpct *counter, comedi_cmd *cmd) int ni_tio_cancel(struct ni_gpct *counter) { + struct ni_gpct_device *counter_dev = counter->counter_dev; + const unsigned interrupt_enable_reg = NITIO_Gi_Interrupt_Enable_Reg(counter->counter_index); unsigned long flags; ni_tio_arm(counter, 0, 0); @@ -2603,6 +2660,9 @@ int ni_tio_cancel(struct ni_gpct *counter) } comedi_spin_unlock_irqrestore(&counter->lock, flags); ni_tio_configure_dma(counter, 0, 0); + + counter_dev->regs[interrupt_enable_reg] &= ~Gi_Gate_Interrupt_Enable_Bit(counter->counter_index); + write_register(counter, counter_dev->regs[interrupt_enable_reg], interrupt_enable_reg); return 0; } @@ -2636,7 +2696,8 @@ static int should_ack_gate(struct ni_gpct *counter) return retval; } -static void acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error, int *tc_error, int *stale_data) +void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error, int *tc_error, + int *perm_stale_data, int *stale_data) { const unsigned short gxx_status = read_register(counter, NITIO_Gxx_Status_Reg(counter->counter_index)); const unsigned short gi_status = read_register(counter, NITIO_Gi_Status_Reg(counter->counter_index)); @@ -2666,20 +2727,17 @@ static void acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error, in ack |= Gi_Gate_Interrupt_Ack_Bit; } if(ack) write_register(counter, ack, NITIO_Gi_Interrupt_Acknowledge_Reg(counter->counter_index)); - if(gxx_status & Gi_Stale_Data_Bit(counter->counter_index)) - { - /* If we should support interrupt transfers in addition to dma in the future, - then we would put a zero into the buffer instead of the (stale) counter value if - reload on gate is enabled. */ -// rt_printk("%s: Gi_Stale_Data detected.\n", __FUNCTION__); - } - if(read_register(counter, NITIO_Gxx_Joint_Status2_Reg(counter->counter_index)) & Gi_Permanent_Stale_Bit(counter->counter_index)) + if(ni_tio_get_soft_copy(counter, NITIO_Gi_Mode_Reg(counter->counter_index)) & Gi_Loading_On_Gate_Bit) { - if(ni_tio_get_soft_copy(counter, NITIO_Gi_Mode_Reg(counter->counter_index)) & Gi_Loading_On_Gate_Bit) + if(gxx_status & Gi_Stale_Data_Bit(counter->counter_index)) { - rt_printk("%s: Gi_Permanent_Stale_Data detected.\n", __FUNCTION__); if(stale_data) *stale_data = 1; } + if(read_register(counter, NITIO_Gxx_Joint_Status2_Reg(counter->counter_index)) & Gi_Permanent_Stale_Bit(counter->counter_index)) + { + rt_printk("%s: Gi_Permanent_Stale_Data detected.\n", __FUNCTION__); + if(perm_stale_data) *perm_stale_data = 1; + } } } @@ -2689,15 +2747,15 @@ void ni_tio_handle_interrupt(struct ni_gpct *counter, comedi_subdevice *s) unsigned long flags; int gate_error; int tc_error; - int stale_data; + int perm_stale_data; - acknowledge_and_confirm(counter, &gate_error, &tc_error, &stale_data); + ni_tio_acknowledge_and_confirm(counter, &gate_error, &tc_error, &perm_stale_data, NULL); if(gate_error) { rt_printk("%s: Gi_Gate_Error detected.\n", __FUNCTION__); s->async->events |= COMEDI_CB_OVERFLOW; } - if(stale_data) + if(perm_stale_data) { s->async->events |= COMEDI_CB_ERROR; } @@ -2750,3 +2808,4 @@ EXPORT_SYMBOL_GPL(ni_gpct_device_construct); EXPORT_SYMBOL_GPL(ni_gpct_device_destroy); EXPORT_SYMBOL_GPL(ni_tio_handle_interrupt); EXPORT_SYMBOL_GPL(ni_tio_set_mite_channel); +EXPORT_SYMBOL_GPL(ni_tio_acknowledge_and_confirm); diff --git a/comedi/drivers/ni_tio.h b/comedi/drivers/ni_tio.h index 18e5803a..6e3e3ba4 100644 --- a/comedi/drivers/ni_tio.h +++ b/comedi/drivers/ni_tio.h @@ -97,6 +97,10 @@ enum ni_gpct_register NITIO_G1_Status_Reg, NITIO_G2_Status_Reg, NITIO_G3_Status_Reg, + NITIO_G0_Interrupt_Enable_Reg, + NITIO_G1_Interrupt_Enable_Reg, + NITIO_G2_Interrupt_Enable_Reg, + NITIO_G3_Interrupt_Enable_Reg, NITIO_Num_Registers, }; @@ -107,8 +111,6 @@ enum ni_gpct_variant ni_gpct_variant_660x }; -#define MAX_NUM_NITIO_REGS 0x40 - struct ni_gpct { struct ni_gpct_device *counter_dev; @@ -127,7 +129,7 @@ struct ni_gpct_device enum ni_gpct_variant variant; struct ni_gpct *counters; unsigned num_counters; - unsigned regs[MAX_NUM_NITIO_REGS]; + unsigned regs[NITIO_Num_Registers]; spinlock_t regs_lock; }; @@ -151,6 +153,13 @@ extern int ni_tio_cmdtest(struct ni_gpct *counter, comedi_cmd *cmd); extern int ni_tio_cancel(struct ni_gpct *counter); extern void ni_tio_handle_interrupt(struct ni_gpct *counter, comedi_subdevice *s); extern void ni_tio_set_mite_channel(struct ni_gpct *counter, struct mite_channel *mite_chan); +extern void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error, int *tc_error, + int *perm_stale_data, int *stale_data); + +static inline struct ni_gpct* subdev_to_counter(comedi_subdevice *s) +{ + return s->private; +} #endif /* _COMEDI_NI_TIO_H */