📄 adl_pci9111.c
字号:
/* comedi/drivers/adl_pci9111.c Hardware driver for PCI9111 ADLink cards: PCI-9111HR Copyright (C) 2002 Emmanuel Pacaud <emmanuel.pacaud@free.fr> 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: adl_pci9111.oDescription: Driver for the Adlink PCI-9111HR card.Author: Emmanuel Pacaud <emmanuel.pacaud@free.fr>Devices: [ADLink] PCI-9111HR (adl_pci9111)Status: experimentalSupports: - ai_insn read - ao_insn read/write - di_insn read - do_insn read/write - ai_do_cmd mode with the following sources: - start_src TRIG_NOW - scan_begin_src TRIG_FOLLOW TRIG_TIMER TRIG_EXT - convert_src TRIG_TIMER TRIG_EXT - scan_end_src TRIG_COUNT - stop_src TRIG_COUNT TRIG_NONE The scanned channels must be consecutive and start from 0. They must all have the same range and aref. Configuration options: [0] - PCI bus number (optional) [1] - PCI slot number (optional) If bus/slot is not specified, the first available PCI device will be used. *//*CHANGELOG: 2002/02/19 Fixed the two's complement conversion in pci9111_(hr_)ai_get_data. 2002/02/18 Added external trigger support for analog input.TODO: - Really test implemented functionality. - Add support for the PCI-9111DG with a probe routine to identify the card type (perhaps with the help of the channel number readback of the A/D Data register). - Add analog input mode 4 suppport. - Add external multiplexer support. - Add analog output cmd support (use irq_on_timer_tick to update analog output). - Add kernel < 2.4 support.*/#include <linux/comedidev.h>#include <linux/delay.h>#include <linux/pci.h>#include "8253.h"typedef enum{ false, true} bool;#define PCI9111_DRIVER_NAME "adl_pci9111"#define PCI9111_HR_DEVICE_ID 0x9111// TODO: Add other pci9111 board id#define PCI9111_IO_RANGE 0x0100#define PCI9111_FIFO_HALF_SIZE 512#define PCI9111_AI_CHANNEL_NBR 16#define PCI9111_AI_RESOLUTION 12#define PCI9111_AI_RESOLUTION_MASK 0x0FFF#define PCI9111_AI_RESOLUTION_2_CMP_BIT 0x0800#define PCI9111_HR_AI_RESOLUTION 16#define PCI9111_HR_AI_RESOLUTION_MASK 0xFFFF#define PCI9111_HR_AI_RESOLUTION_2_CMP_BIT 0x8000#define PCI9111_AI_ACQUISITION_PERIOD_MIN_NS 10000#define PCI9111_AO_CHANNEL_NBR 1#define PCI9111_AO_RESOLUTION 12#define PCI9111_AO_RESOLUTION_MASK 0x0FFF#define PCI9111_DI_CHANNEL_NBR 16#define PCI9111_DO_CHANNEL_NBR 16#define PCI9111_DO_MASK 0xFFFF#define PCI9111_RANGE_SETTING_DELAY 10#define PCI9111_AI_INSTANT_READ_UDELAY_US 2 #define PCI9111_AI_INSTANT_READ_TIMEOUT 100#define PCI9111_8254_CLOCK_PERIOD_NS 500#define PCI9111_8254_COUNTER_0 0x00#define PCI9111_8254_COUNTER_1 0x40#define PCI9111_8254_COUNTER_2 0x80#define PCI9111_8254_COUNTER_LATCH 0x00#define PCI9111_8254_READ_LOAD_LSB_ONLY 0x10#define PCI9111_8254_READ_LOAD_MSB_ONLY 0x20#define PCI9111_8254_READ_LOAD_LSB_MSB 0x30#define PCI9111_8254_MODE_0 0x00#define PCI9111_8254_MODE_1 0x02#define PCI9111_8254_MODE_2 0x04#define PCI9111_8254_MODE_3 0x06#define PCI9111_8254_MODE_4 0x08#define PCI9111_8254_MODE_5 0x0A#define PCI9111_8254_BINARY_COUNTER 0x00#define PCI9111_8254_BCD_COUNTER 0x01/* IO address map */#define PCI9111_REGISTER_AD_FIFO_VALUE 0x00 // AD Data stored in FIFO #define PCI9111_REGISTER_DA_OUTPUT 0x00#define PCI9111_REGISTER_DIGITAL_IO 0x02#define PCI9111_REGISTER_EXTENDED_IO_PORTS 0x04#define PCI9111_REGISTER_AD_CHANNEL_CONTROL 0x06 // Channel selection #define PCI9111_REGISTER_AD_CHANNEL_READBACK 0x06#define PCI9111_REGISTER_INPUT_SIGNAL_RANGE 0x08#define PCI9111_REGISTER_RANGE_STATUS_READBACK 0x08#define PCI9111_REGISTER_TRIGGER_MODE_CONTROL 0x0A#define PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK 0x0A#define PCI9111_REGISTER_SOFTWARE_TRIGGER 0x0E#define PCI9111_REGISTER_INTERRUPT_CONTROL 0x0C#define PCI9111_REGISTER_8254_COUNTER_0 0x40#define PCI9111_REGISTER_8254_COUNTER_1 0x42#define PCI9111_REGISTER_8254_COUNTER_2 0X44#define PCI9111_REGISTER_8254_CONTROL 0x46#define PCI9111_REGISTER_INTERRUPT_CLEAR 0x48#define PCI9111_TRIGGER_MASK 0x0F#define PCI9111_PTRG_OFF (0 << 3)#define PCI9111_PTRG_ON (1 << 3)#define PCI9111_EITS_EXTERNAL (1 << 2)#define PCI9111_EITS_INTERNAL (0 << 2)#define PCI9111_TPST_SOFTWARE_TRIGGER (0 << 1)#define PCI9111_TPST_TIMER_PACER (1 << 1)#define PCI9111_ASCAN_ON (1 << 0)#define PCI9111_ASCAN_OFF (0 << 0)#define PCI9111_ISC0_SET_IRQ_ON_ENDING_OF_AD_CONVERSION (0 << 0)#define PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL (1 << 0)#define PCI9111_ISC1_SET_IRQ_ON_TIMER_TICK (0 << 1)#define PCI9111_ISC1_SET_IRQ_ON_EXT_TRG (1 << 1)#define PCI9111_FFEN_SET_FIFO_ENABLE (0 << 2)#define PCI9111_FFEN_SET_FIFO_DISABLE (1 << 2)#define PCI9111_CHANNEL_MASK 0x0F#define PCI9111_RANGE_MASK 0x07#define PCI9111_FIFO_EMPTY_MASK 0x10#define PCI9111_FIFO_HALF_FULL_MASK 0x20#define PCI9111_FIFO_FULL_MASK 0x40#define PCI9111_AD_BUSY_MASK 0x80#define PCI9111_IO_BASE dev->iobase/* * Define inlined function */#define pci9111_trigger_and_autoscan_get() \ (inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK)&0x0F)#define pci9111_trigger_and_autoscan_set(flags) \ outb(flags,PCI9111_IO_BASE+PCI9111_REGISTER_TRIGGER_MODE_CONTROL)#define pci9111_interrupt_and_fifo_get() \ ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK) >> 4) &0x03)#define pci9111_interrupt_and_fifo_set(flags) \ outb(flags,PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL)#define pci9111_interrupt_clear() \ outb(0,PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CLEAR) #define pci9111_software_trigger() \ outb(0,PCI9111_IO_BASE+PCI9111_REGISTER_SOFTWARE_TRIGGER)#define pci9111_fifo_reset() \ outb(PCI9111_FFEN_SET_FIFO_ENABLE,PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \ outb(PCI9111_FFEN_SET_FIFO_DISABLE,PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \ outb(PCI9111_FFEN_SET_FIFO_ENABLE,PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL)#define pci9111_is_fifo_full() \ ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \ PCI9111_FIFO_FULL_MASK)==0)#define pci9111_is_fifo_half_full() \ ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \ PCI9111_FIFO_HALF_FULL_MASK)==0)#define pci9111_is_fifo_empty() \ ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \ PCI9111_FIFO_EMPTY_MASK)==0)#define pci9111_ai_channel_set(channel) \ outb((channel)&PCI9111_CHANNEL_MASK,PCI9111_IO_BASE+PCI9111_REGISTER_AD_CHANNEL_CONTROL)#define pci9111_ai_channel_get() \ inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_CHANNEL_READBACK)&PCI9111_CHANNEL_MASK#define pci9111_ai_range_set(range) \ outb((range)&PCI9111_RANGE_MASK,PCI9111_IO_BASE+PCI9111_REGISTER_INPUT_SIGNAL_RANGE)#define pci9111_ai_range_get() \ inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)&PCI9111_RANGE_MASK#define pci9111_ai_get_data() \ ((inw(PCI9111_IO_BASE+PCI9111_REGISTER_AD_FIFO_VALUE)>>4)&PCI9111_AI_RESOLUTION_MASK) \ ^ PCI9111_AI_RESOLUTION_2_CMP_BIT#define pci9111_hr_ai_get_data() \ (inw(PCI9111_IO_BASE+PCI9111_REGISTER_AD_FIFO_VALUE) & PCI9111_HR_AI_RESOLUTION_MASK) \ ^ PCI9111_HR_AI_RESOLUTION_2_CMP_BIT #define pci9111_ao_set_data(data) \ outb(data&PCI9111_AO_RESOLUTION_MASK,PCI9111_IO_BASE+PCI9111_REGISTER_DA_OUTPUT)#define pci9111_di_get_bits() \ inw(PCI9111_IO_BASE+PCI9111_REGISTER_DIGITAL_IO)#define pci9111_do_set_bits(bits) \ outw(bits,PCI9111_IO_BASE+PCI9111_REGISTER_DIGITAL_IO) #define pci9111_8254_control_set(flags) \ outb(flags,PCI9111_IO_BASE+PCI9111_REGISTER_8254_CONTROL)#define pci9111_8254_counter_0_set(data) \ outb(data & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_0); \ outb( (data >> 8) & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_0) #define pci9111_8254_counter_1_set(data) \ outb(data & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_1); \ outb( (data >> 8) & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_1) #define pci9111_8254_counter_2_set(data) \ outb(data & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_2); \ outb( (data >> 8) & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_2) // // Function prototypes// static int pci9111_attach (comedi_device *dev,comedi_devconfig *it);static int pci9111_detach (comedi_device *dev);static comedi_lrange pci9111_hr_ai_range={ 5, { BIP_RANGE(10), BIP_RANGE(5), BIP_RANGE(2.5), BIP_RANGE(1.25), BIP_RANGE(0.625) }};static struct pci_device_id pci9111_pci_table[] __devinitdata = { { PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, //{ PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { 0 }};MODULE_DEVICE_TABLE(pci, pci9111_pci_table);//// Board specification structure//typedef struct { char *name; // driver name int device_id; int ai_channel_nbr; // num of A/D chans int ao_channel_nbr; // num of D/A chans int ai_resolution; // resolution of A/D int ai_resolution_mask; int ao_resolution; // resolution of D/A int ao_resolution_mask; comedi_lrange *ai_range_list; // rangelist for A/D comedi_lrange *ao_range_list; // rangelist for D/A unsigned int ai_acquisition_period_min_ns;} pci9111_board_struct;static pci9111_board_struct pci9111_boards[] ={ { name: "pci9111_hr", device_id: PCI9111_HR_DEVICE_ID, ai_channel_nbr: PCI9111_AI_CHANNEL_NBR, ao_channel_nbr: PCI9111_AO_CHANNEL_NBR, ai_resolution: PCI9111_HR_AI_RESOLUTION, ai_resolution_mask: PCI9111_HR_AI_RESOLUTION_MASK, ao_resolution: PCI9111_AO_RESOLUTION, ao_resolution_mask: PCI9111_AO_RESOLUTION_MASK, ai_range_list: &pci9111_hr_ai_range, ao_range_list: &range_bipolar10, ai_acquisition_period_min_ns: PCI9111_AI_ACQUISITION_PERIOD_MIN_NS }};#define pci9111_board_nbr \ (sizeof(pci9111_boards)/sizeof(pci9111_board_struct))static comedi_driver pci9111_driver={ driver_name: PCI9111_DRIVER_NAME, module: THIS_MODULE, attach: pci9111_attach, detach: pci9111_detach, num_names: pci9111_board_nbr, board_name: pci9111_boards, offset: sizeof(pci9111_board_struct),};COMEDI_INITCLEANUP(pci9111_driver);//// Private data structure//typedef struct { struct pci_dev* pci_device; int io_range; // PCI6503 io range int lcr_io_base; // Local configuration register base address int lcr_io_range; int scan_begin_counter; int scan_begin_counter_limit; int stop_counter; int stop_is_none; int ao_readback; // Last written analog output data int timer_divisor_1; // Divisor values for the 8254 timer pacer int timer_divisor_2; int is_valid; // Is device valid} pci9111_private_data_struct;#define dev_private ((pci9111_private_data_struct *)dev->private)// ------------------------------------------------------------------// // PLX9050 SECTION// // ------------------------------------------------------------------#define PLX9050_REGISTER_INTERRUPT_CONTROL 0x4c#define PLX9050_LINTI1_ENABLE (1 << 0)#define PLX9050_LINTI1_ACTIVE_HIGH (1 << 1)#define PLX9050_LINTI1_STATUS (1 << 2)#define PLX9050_LINTI2_ENABLE (1 << 3)#define PLX9050_LINTI2_ACTIVE_HIGH (1 << 4)#define PLX9050_LINTI2_STATUS (1 << 5)#define PLX9050_PCI_INTERRUPT_ENABLE (1 << 6)#define PLX9050_SOFTWARE_INTERRUPT (1 << 7)static void plx9050_interrupt_control (int io_base, bool LINTi1_enable, bool LINTi1_active_high, bool LINTi2_enable, bool LINTi2_active_high, bool interrupt_enable){ int flags = 0; if (LINTi1_enable) flags |= PLX9050_LINTI1_ENABLE; if (LINTi1_active_high) flags |= PLX9050_LINTI1_ACTIVE_HIGH; if (LINTi2_enable) flags |= PLX9050_LINTI2_ENABLE; if (LINTi2_active_high) flags |= PLX9050_LINTI2_ACTIVE_HIGH; if (interrupt_enable) flags |= PLX9050_PCI_INTERRUPT_ENABLE; outb (flags, io_base + PLX9050_REGISTER_INTERRUPT_CONTROL);} // ------------------------------------------------------------------// // MISCELLANEOUS SECTION// // ------------------------------------------------------------------//// 8254 timer //static void pci9111_timer_set ( comedi_device * dev) { pci9111_8254_control_set ( PCI9111_8254_COUNTER_0| PCI9111_8254_READ_LOAD_LSB_MSB| PCI9111_8254_MODE_0| PCI9111_8254_BINARY_COUNTER); pci9111_8254_control_set ( PCI9111_8254_COUNTER_1| PCI9111_8254_READ_LOAD_LSB_MSB| PCI9111_8254_MODE_2| PCI9111_8254_BINARY_COUNTER); pci9111_8254_control_set ( PCI9111_8254_COUNTER_2| PCI9111_8254_READ_LOAD_LSB_MSB| PCI9111_8254_MODE_2| PCI9111_8254_BINARY_COUNTER); comedi_udelay(1); pci9111_8254_counter_2_set (dev_private->timer_divisor_2); pci9111_8254_counter_1_set (dev_private->timer_divisor_1);}typedef enum { software, timer_pacer, external} pci9111_trigger_sources; static void pci9111_trigger_source_set (comedi_device *dev, pci9111_trigger_sources source){ int flags; flags = pci9111_trigger_and_autoscan_get() & 0x09; switch (source) { case software : flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_SOFTWARE_TRIGGER; break; case timer_pacer : flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_TIMER_PACER; break; case external : flags |= PCI9111_EITS_EXTERNAL; break; } pci9111_trigger_and_autoscan_set (flags);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -