📄 ni_labpc.c
字号:
/* ni_labpc.c driver for National Instruments Lab-PC series boards and compatibles Copyright (C) 2001, 2002 Frank Mori Hess <fmhess@users.sourceforge.net> PCMCIA crap at end of file is adapted from dummy_cs.c 1.31 2001/08/24 12:13:13 from the pcmcia package. The initial developer of the pcmcia dummy_cs.c code is David A. Hinds <dahinds@users.sourceforge.net>. Portions created by David A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*************************************************************************//*Driver: ni_labpc.oDescription: National Instruments Lab-PC (& compatibles)Author: Frank Mori Hess <fmhess@users.sourceforge.net>Devices: [National Instruments] DAQCard-1200 (daqcard-1200), Lab-PC-1200 (labpc-1200), Lab-PC-1200AI (labpc-1200ai), Lab-PC+ (lab-pc+), PCI-1200 (pci-1200)Status: worksThanks go to Fredrik Lingvall for much testing and perseverance inhelping to debug daqcard-1200 support.Tested with lab-pc-1200. For the older Lab-PC+, not all input rangesand analog references will work, the available ranges/arefs willdepend on how you have configured the jumpers on your board(see your owner's manual).The 1200 series boards have onboard calibration dacs for correctinganalog input/output offsets and gains. The proper settings for thesecaldacs are stored on the board's eeprom. To read the caldac valuesfrom the eeprom and store them into a file that can be then be used bycomedilib, use the comedi_calibrate program.Configuration options - ISA boards: [0] - I/O port base address [1] - IRQ (optional, required for timed or externally triggered conversions) [2] - DMA channel (optional)Configuration options - PCI boards: [0] - bus (optional) [1] - slot (optional)Configuration options - PCMCIA boards: noneThe Lab-pc+ and daqcard-1200 have quirky chanlist requirementswhen scanning multiple channels. Multiple channel scansequence must start at highest channel, then decrement down tochannel 0. The rest of the cards can scan down like lab-pc+ or scanup from channel zero. Chanlists consisting of all one channelare also legal, and allow you to pace conversions in bursts.*//*NI manuals:341309a (labpc-1200 register manual)340988a (daqcard-1200)340914a (pci-1200)320502b (lab-pc+)*/#undef LABPC_DEBUG//#define LABPC_DEBUG // enable debugging messages#include <linux/comedidev.h>#include <linux/delay.h>#include <asm/dma.h>#include "8253.h"#include "8255.h"#include "mite.h"#include "comedi_fc.h"#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)#include <pcmcia/version.h>#include <pcmcia/cs_types.h>#include <pcmcia/cs.h>#include <pcmcia/cistpl.h>#include <pcmcia/cisreg.h>#include <pcmcia/ds.h>#include <pcmcia/bus_ops.h>/* A linked list of "instances" of the dummy device. Each actual PCMCIA card corresponds to one device instance, and is described by one dev_link_t structure (defined in ds.h). You may not want to use a linked list for this -- for example, the memory card driver uses an array of dev_link_t pointers, where minor device numbers are used to derive the corresponding array index.*/static dev_link_t *pcmcia_dev_list = NULL;#endif // CONFIG_PCMCIA#define LABPC_SIZE 32 // size of io region used by board#define LABPC_TIMER_BASE 500 // 2 MHz master clock#define EEPROM_SIZE 256 // 256 byte eeprom#define NUM_AO_CHAN 2 // boards have two analog output channels/* Registers for the lab-pc+ *///write-only registers#define COMMAND1_REG 0x0#define ADC_GAIN_MASK (0x7 << 4)#define ADC_CHAN_BITS(x) ((x) & 0x7)#define ADC_SCAN_EN_BIT 0x80 // enables multi channel scans#define COMMAND2_REG 0x1#define PRETRIG_BIT 0x1 // enable pretriggering (used in conjunction with SWTRIG)#define HWTRIG_BIT 0x2 // enable paced conversions on external trigger#define SWTRIG_BIT 0x4 // enable paced conversions#define CASCADE_BIT 0x8 // use two cascaded counters for pacing#define DAC_PACED_BIT(channel) (0x40 << ((channel) & 0x1))#define COMMAND3_REG 0x2#define DMA_EN_BIT 0x1 // enable dma transfers#define DIO_INTR_EN_BIT 0x2 // enable interrupts for 8255#define DMATC_INTR_EN_BIT 0x4 // enable dma terminal count interrupt#define TIMER_INTR_EN_BIT 0x8 // enable timer interrupt#define ERR_INTR_EN_BIT 0x10 // enable error interrupt#define ADC_FNE_INTR_EN_BIT 0x20 // enable fifo not empty interrupt#define ADC_CONVERT_REG 0x3#define DAC_LSB_REG(channel) (0x4 + 2 * ((channel) & 0x1))#define DAC_MSB_REG(channel) (0x5 + 2 * ((channel) & 0x1))#define ADC_CLEAR_REG 0x8#define DMATC_CLEAR_REG 0xa#define TIMER_CLEAR_REG 0xc#define COMMAND6_REG 0xe // 1200 boards only#define ADC_COMMON_BIT 0x1 // select ground or common-mode reference#define ADC_UNIP_BIT 0x2 // adc unipolar#define DAC_UNIP_BIT(channel) (0x4 << ((channel) & 0x1)) // dac unipolar#define ADC_FHF_INTR_EN_BIT 0x20 // enable fifo half full interrupt#define A1_INTR_EN_BIT 0x40 // enable interrupt on end of hardware count#define ADC_SCAN_UP_BIT 0x80 // scan up from channel zero instead of down to zero#define COMMAND4_REG 0xf#define INTERVAL_SCAN_EN_BIT 0x1 // enables 'interval' scanning#define EXT_SCAN_EN_BIT 0x2 // enables external signal on counter b1 output to trigger scan#define EXT_CONVERT_OUT_BIT 0x4 // chooses direction (output or input) for EXTCONV* line#define ADC_DIFF_BIT 0x8 // chooses differential inputs for adc (in conjunction with board jumper)#define EXT_CONVERT_DISABLE_BIT 0x10#define COMMAND5_REG 0x1c // 1200 boards only, calibration stuff#define EEPROM_WRITE_UNPROTECT_BIT 0x4// enable eeprom for write#define DITHER_EN_BIT 0x8 // enable dithering#define CALDAC_LOAD_BIT 0x10 // load calibration dac#define SCLOCK_BIT 0x20 // serial clock - rising edge writes, falling edge reads#define SDATA_BIT 0x40 // serial data bit for writing to eeprom or calibration dacs#define EEPROM_EN_BIT 0x80 // enable eeprom for read/write#define INTERVAL_COUNT_REG 0x1e#define INTERVAL_LOAD_REG 0x1f#define INTERVAL_LOAD_BITS 0x1// read-only registers#define STATUS1_REG 0x0#define DATA_AVAIL_BIT 0x1 // data is available in fifo#define OVERRUN_BIT 0x2 // overrun has occurred#define OVERFLOW_BIT 0x4 // fifo overflow#define TIMER_BIT 0x8 // timer interrupt has occured#define DMATC_BIT 0x10 // dma terminal count has occured#define EXT_TRIG_BIT 0x40 // external trigger has occured#define STATUS2_REG 0x1d // 1200 boards only#define EEPROM_OUT_BIT 0x1 // programmable eeprom serial output#define A1_TC_BIT 0x2 // counter A1 terminal count#define FNHF_BIT 0x4 // fifo not half full#define ADC_FIFO_REG 0xa#define DIO_BASE_REG 0x10#define COUNTER_A_BASE_REG 0x14#define COUNTER_A_CONTROL_REG (COUNTER_A_BASE_REG + 0x3)#define INIT_A0_BITS 0x14 // check modes put conversion pacer output in harmless state (a0 mode 2)#define INIT_A1_BITS 0x70 // put hardware conversion counter output in harmless state (a1 mode 0)#define COUNTER_B_BASE_REG 0x18static int labpc_attach(comedi_device *dev,comedi_devconfig *it);static int labpc_detach(comedi_device *dev);static int labpc_cancel(comedi_device *dev, comedi_subdevice *s);static void labpc_interrupt(int irq, void *d, struct pt_regs *regs);static int labpc_drain_fifo(comedi_device *dev);static void labpc_drain_dma(comedi_device *dev);static void handle_isa_dma(comedi_device *dev);static void labpc_drain_dregs(comedi_device *dev);static int labpc_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd);static int labpc_ai_cmd(comedi_device *dev, comedi_subdevice *s);static int labpc_ai_rinsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);static int labpc_ao_winsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);static int labpc_ao_rinsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);static int labpc_calib_read_insn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);static int labpc_calib_write_insn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);static int labpc_eeprom_read_insn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);static int labpc_eeprom_write_insn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);static unsigned int labpc_suggest_transfer_size(comedi_cmd cmd);static void labpc_adc_timing(comedi_device *dev, comedi_cmd *cmd);static struct mite_struct* labpc_find_device(int bus, int slot);static unsigned int labpc_inb(unsigned long address);static void labpc_outb(unsigned int byte, unsigned long address);static unsigned int labpc_readb(unsigned long address);static void labpc_writeb(unsigned int byte, unsigned long address);static int labpc_dio_mem_callback(int dir, int port, int data, unsigned long arg);static void labpc_serial_out(comedi_device *dev, unsigned int value, unsigned int num_bits);static unsigned int labpc_serial_in(comedi_device *dev);static unsigned int labpc_eeprom_read(comedi_device *dev, unsigned int address);static unsigned int labpc_eeprom_read_status(comedi_device *dev);static unsigned int labpc_eeprom_write(comedi_device *dev, unsigned int address, unsigned int value);static void write_caldac(comedi_device *dev, unsigned int channel, unsigned int value);enum labpc_bustype {isa_bustype, pci_bustype, pcmcia_bustype};enum labpc_register_layout {labpc_plus_layout, labpc_1200_layout};enum transfer_type {fifo_not_empty_transfer, fifo_half_full_transfer, isa_dma_transfer};enum scan_mode{ MODE_SINGLE_CHAN, MODE_SINGLE_CHAN_INTERVAL, MODE_MULT_CHAN_UP, MODE_MULT_CHAN_DOWN,};typedef struct labpc_board_struct{ char *name; int device_id; // device id for pci and pcmcia boards int ai_speed; // maximum input speed in nanoseconds enum labpc_bustype bustype; // ISA/PCI/etc. enum labpc_register_layout register_layout; // 1200 has extra registers compared to pc+ int has_ao; // has analog output true/false // function pointers so we can use inb/outb or readb/writeb as appropriate unsigned int (*read_byte)(unsigned long address); void (*write_byte)(unsigned int byte, unsigned long address); comedi_lrange *ai_range_table; int *ai_range_code; int *ai_range_is_unipolar; unsigned ai_scan_up : 1; // board can auto scan up in ai channels, not just down}labpc_board;//analog input ranges#define NUM_LABPC_PLUS_AI_RANGES 16// indicates unipolar rangesstatic int labpc_plus_is_unipolar[NUM_LABPC_PLUS_AI_RANGES] ={ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,};// map range index to gain bitsstatic int labpc_plus_ai_gain_bits[NUM_LABPC_PLUS_AI_RANGES] ={ 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,};static comedi_lrange range_labpc_plus_ai = { NUM_LABPC_PLUS_AI_RANGES, { BIP_RANGE(5), BIP_RANGE(4), BIP_RANGE(2.5), BIP_RANGE(1), BIP_RANGE(0.5), BIP_RANGE(0.25), BIP_RANGE(0.1), BIP_RANGE(0.05), UNI_RANGE(10), UNI_RANGE(8), UNI_RANGE(5), UNI_RANGE(2), UNI_RANGE(1), UNI_RANGE(0.5), UNI_RANGE(0.2), UNI_RANGE(0.1), }};#define NUM_LABPC_1200_AI_RANGES 14// indicates unipolar rangesstatic int labpc_1200_is_unipolar[NUM_LABPC_1200_AI_RANGES] ={ 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,};// map range index to gain bitsstatic int labpc_1200_ai_gain_bits[NUM_LABPC_1200_AI_RANGES] ={ 0x00, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x00, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,};static comedi_lrange range_labpc_1200_ai = { NUM_LABPC_1200_AI_RANGES, { BIP_RANGE(5), BIP_RANGE(2.5), BIP_RANGE(1), BIP_RANGE(0.5), BIP_RANGE(0.25), BIP_RANGE(0.1), BIP_RANGE(0.05), UNI_RANGE(10), UNI_RANGE(5), UNI_RANGE(2), UNI_RANGE(1), UNI_RANGE(0.5), UNI_RANGE(0.2), UNI_RANGE(0.1), }};//analog output ranges#define AO_RANGE_IS_UNIPOLAR 0x1static comedi_lrange range_labpc_ao = { 2, { BIP_RANGE(5), UNI_RANGE(10), }};static labpc_board labpc_boards[] ={#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE) { name: "daqcard-1200", device_id: 0x103, // 0x10b is manufacturer id, 0x103 is device id ai_speed: 10000, bustype: pcmcia_bustype, register_layout: labpc_1200_layout, has_ao: 1, read_byte: labpc_inb, write_byte: labpc_outb, ai_range_table: &range_labpc_1200_ai, ai_range_code: labpc_1200_ai_gain_bits, ai_range_is_unipolar: labpc_1200_is_unipolar, ai_scan_up: 0, },#endif // CONFIG_PCMCIA { name: "lab-pc-1200", ai_speed: 10000, bustype: isa_bustype, register_layout: labpc_1200_layout, has_ao: 1, read_byte: labpc_inb, write_byte: labpc_outb, ai_range_table: &range_labpc_1200_ai, ai_range_code: labpc_1200_ai_gain_bits, ai_range_is_unipolar: labpc_1200_is_unipolar, ai_scan_up: 1, }, { name: "lab-pc-1200ai", ai_speed: 10000, bustype: isa_bustype, register_layout: labpc_1200_layout, has_ao: 0, read_byte: labpc_inb, write_byte: labpc_outb, ai_range_table: &range_labpc_1200_ai, ai_range_code: labpc_1200_ai_gain_bits, ai_range_is_unipolar: labpc_1200_is_unipolar, ai_scan_up: 1, }, { name: "lab-pc+", ai_speed: 12000, bustype: isa_bustype, register_layout: labpc_plus_layout,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -