| /* |
| comedi/drivers/ni_pcimio.c |
| Hardware driver for NI PCI-MIO E series cards |
| |
| COMEDI - Linux Control and Measurement Device Interface |
| Copyright (C) 1997-8 David A. Schleef <ds@schleef.org> |
| |
| 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_pcimio |
| Description: National Instruments PCI-MIO-E series and M series (all boards) |
| Author: ds, John Hallen, Frank Mori Hess, Rolf Mueller, Herbert Peremans, |
| Herman Bruyninckx, Terry Barnaby |
| Status: works |
| Devices: [National Instruments] PCI-MIO-16XE-50 (ni_pcimio), |
| PCI-MIO-16XE-10, PXI-6030E, PCI-MIO-16E-1, PCI-MIO-16E-4, PCI-6014, PCI-6040E, |
| PXI-6040E, PCI-6030E, PCI-6031E, PCI-6032E, PCI-6033E, PCI-6071E, PCI-6023E, |
| PCI-6024E, PCI-6025E, PXI-6025E, PCI-6034E, PCI-6035E, PCI-6052E, |
| PCI-6110, PCI-6111, PCI-6220, PCI-6221, PCI-6224, PXI-6224, |
| PCI-6225, PXI-6225, PCI-6229, PCI-6250, PCI-6251, PCIe-6251, PXIe-6251, |
| PCI-6254, PCI-6259, PCIe-6259, |
| PCI-6280, PCI-6281, PXI-6281, PCI-6284, PCI-6289, |
| PCI-6711, PXI-6711, PCI-6713, PXI-6713, |
| PXI-6071E, PCI-6070E, PXI-6070E, |
| PXI-6052E, PCI-6036E, PCI-6731, PCI-6733, PXI-6733, |
| PCI-6143, PXI-6143 |
| Updated: Mon, 09 Jan 2012 14:52:48 +0000 |
| |
| These boards are almost identical to the AT-MIO E series, except that |
| they use the PCI bus instead of ISA (i.e., AT). See the notes for |
| the ni_atmio.o driver for additional information about these boards. |
| |
| Autocalibration is supported on many of the devices, using the |
| comedi_calibrate (or comedi_soft_calibrate for m-series) utility. |
| M-Series boards do analog input and analog output calibration entirely |
| in software. The software calibration corrects |
| the analog input for offset, gain and |
| nonlinearity. The analog outputs are corrected for offset and gain. |
| See the comedilib documentation on comedi_get_softcal_converter() for |
| more information. |
| |
| By default, the driver uses DMA to transfer analog input data to |
| memory. When DMA is enabled, not all triggering features are |
| supported. |
| |
| Digital I/O may not work on 673x. |
| |
| Note that the PCI-6143 is a simultaineous sampling device with 8 convertors. |
| With this board all of the convertors perform one simultaineous sample during |
| a scan interval. The period for a scan is used for the convert time in a |
| Comedi cmd. The convert trigger source is normally set to TRIG_NOW by default. |
| |
| The RTSI trigger bus is supported on these cards on |
| subdevice 10. See the comedilib documentation for details. |
| |
| Information (number of channels, bits, etc.) for some devices may be |
| incorrect. Please check this and submit a bug if there are problems |
| for your device. |
| |
| SCXI is probably broken for m-series boards. |
| |
| Bugs: |
| - When DMA is enabled, COMEDI_EV_CONVERT does |
| not work correctly. |
| |
| */ |
| /* |
| The PCI-MIO E series driver was originally written by |
| Tomasz Motylewski <...>, and ported to comedi by ds. |
| |
| References: |
| |
| 341079b.pdf PCI E Series Register-Level Programmer Manual |
| 340934b.pdf DAQ-STC reference manual |
| |
| 322080b.pdf 6711/6713/6715 User Manual |
| |
| 320945c.pdf PCI E Series User Manual |
| 322138a.pdf PCI-6052E and DAQPad-6052E User Manual |
| |
| ISSUES: |
| |
| need to deal with external reference for DAC, and other DAC |
| properties in board properties |
| |
| deal with at-mio-16de-10 revision D to N changes, etc. |
| |
| need to add other CALDAC type |
| |
| need to slow down DAC loading. I don't trust NI's claim that |
| two writes to the PCI bus slows IO enough. I would prefer to |
| use udelay(). Timing specs: (clock) |
| AD8522 30ns |
| DAC8043 120ns |
| DAC8800 60ns |
| MB88341 ? |
| |
| */ |
| |
| #include "../comedidev.h" |
| |
| #include <asm/byteorder.h> |
| #include <linux/delay.h> |
| |
| #include "ni_stc.h" |
| #include "mite.h" |
| |
| /* #define PCI_DEBUG */ |
| |
| #define PCIDMA |
| |
| #define PCIMIO 1 |
| #undef ATMIO |
| |
| #define MAX_N_CALDACS (16+16+2) |
| |
| #define DRV_NAME "ni_pcimio" |
| |
| /* These are not all the possible ao ranges for 628x boards. |
| They can do OFFSET +- REFERENCE where OFFSET can be |
| 0V, 5V, APFI<0,1>, or AO<0...3> and RANGE can |
| be 10V, 5V, 2V, 1V, APFI<0,1>, AO<0...3>. That's |
| 63 different possibilities. An AO channel |
| can not act as it's own OFFSET or REFERENCE. |
| */ |
| static const struct comedi_lrange range_ni_M_628x_ao = { 8, { |
| RANGE(-10, 10), |
| RANGE(-5, 5), |
| RANGE(-2, 2), |
| RANGE(-1, 1), |
| RANGE(-5, 15), |
| RANGE(0, 10), |
| RANGE(3, 7), |
| RANGE(4, 6), |
| RANGE_ext(-1, 1) |
| } |
| }; |
| |
| static const struct comedi_lrange range_ni_M_625x_ao = { 3, { |
| RANGE(-10, 10), |
| RANGE(-5, 5), |
| RANGE_ext(-1, 1) |
| } |
| }; |
| |
| static const struct comedi_lrange range_ni_M_622x_ao = { 1, { |
| RANGE(-10, 10), |
| } |
| }; |
| |
| static const struct ni_board_struct ni_boards[] = { |
| { |
| .device_id = 0x0162, /* NI also says 0x1620. typo? */ |
| .name = "pci-mio-16xe-50", |
| .n_adchan = 16, |
| .adbits = 16, |
| .ai_fifo_depth = 2048, |
| .alwaysdither = 1, |
| .gainlkup = ai_gain_8, |
| .ai_speed = 50000, |
| .n_aochan = 2, |
| .aobits = 12, |
| .ao_fifo_depth = 0, |
| .ao_range_table = &range_bipolar10, |
| .ao_unipolar = 0, |
| .ao_speed = 50000, |
| .num_p0_dio_channels = 8, |
| .caldac = {dac8800, dac8043}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x1170, |
| .name = "pci-mio-16xe-10", /* aka pci-6030E */ |
| .n_adchan = 16, |
| .adbits = 16, |
| .ai_fifo_depth = 512, |
| .alwaysdither = 1, |
| .gainlkup = ai_gain_14, |
| .ai_speed = 10000, |
| .n_aochan = 2, |
| .aobits = 16, |
| .ao_fifo_depth = 2048, |
| .ao_range_table = &range_ni_E_ao_ext, |
| .ao_unipolar = 1, |
| .ao_speed = 10000, |
| .num_p0_dio_channels = 8, |
| .caldac = {dac8800, dac8043, ad8522}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x28c0, |
| .name = "pci-6014", |
| .n_adchan = 16, |
| .adbits = 16, |
| .ai_fifo_depth = 512, |
| .alwaysdither = 1, |
| .gainlkup = ai_gain_4, |
| .ai_speed = 5000, |
| .n_aochan = 2, |
| .aobits = 16, |
| .ao_fifo_depth = 0, |
| .ao_range_table = &range_bipolar10, |
| .ao_unipolar = 0, |
| .ao_speed = 100000, |
| .num_p0_dio_channels = 8, |
| .caldac = {ad8804_debug}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x11d0, |
| .name = "pxi-6030e", |
| .n_adchan = 16, |
| .adbits = 16, |
| .ai_fifo_depth = 512, |
| .alwaysdither = 1, |
| .gainlkup = ai_gain_14, |
| .ai_speed = 10000, |
| .n_aochan = 2, |
| .aobits = 16, |
| .ao_fifo_depth = 2048, |
| .ao_range_table = &range_ni_E_ao_ext, |
| .ao_unipolar = 1, |
| .ao_speed = 10000, |
| .num_p0_dio_channels = 8, |
| .caldac = {dac8800, dac8043, ad8522}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x1180, |
| .name = "pci-mio-16e-1", /* aka pci-6070e */ |
| .n_adchan = 16, |
| .adbits = 12, |
| .ai_fifo_depth = 512, |
| .alwaysdither = 0, |
| .gainlkup = ai_gain_16, |
| .ai_speed = 800, |
| .n_aochan = 2, |
| .aobits = 12, |
| .ao_fifo_depth = 2048, |
| .ao_range_table = &range_ni_E_ao_ext, |
| .ao_unipolar = 1, |
| .ao_speed = 1000, |
| .num_p0_dio_channels = 8, |
| .caldac = {mb88341}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x1190, |
| .name = "pci-mio-16e-4", /* aka pci-6040e */ |
| .n_adchan = 16, |
| .adbits = 12, |
| .ai_fifo_depth = 512, |
| .alwaysdither = 0, |
| .gainlkup = ai_gain_16, |
| /* .Note = there have been reported problems with full speed |
| * on this board */ |
| .ai_speed = 2000, |
| .n_aochan = 2, |
| .aobits = 12, |
| .ao_fifo_depth = 512, |
| .ao_range_table = &range_ni_E_ao_ext, |
| .ao_unipolar = 1, |
| .ao_speed = 1000, |
| .num_p0_dio_channels = 8, |
| .caldac = {ad8804_debug}, /* doc says mb88341 */ |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x11c0, |
| .name = "pxi-6040e", |
| .n_adchan = 16, |
| .adbits = 12, |
| .ai_fifo_depth = 512, |
| .alwaysdither = 0, |
| .gainlkup = ai_gain_16, |
| .ai_speed = 2000, |
| .n_aochan = 2, |
| .aobits = 12, |
| .ao_fifo_depth = 512, |
| .ao_range_table = &range_ni_E_ao_ext, |
| .ao_unipolar = 1, |
| .ao_speed = 1000, |
| .num_p0_dio_channels = 8, |
| .caldac = {mb88341}, |
| .has_8255 = 0, |
| }, |
| |
| { |
| .device_id = 0x1330, |
| .name = "pci-6031e", |
| .n_adchan = 64, |
| .adbits = 16, |
| .ai_fifo_depth = 512, |
| .alwaysdither = 1, |
| .gainlkup = ai_gain_14, |
| .ai_speed = 10000, |
| .n_aochan = 2, |
| .aobits = 16, |
| .ao_fifo_depth = 2048, |
| .ao_range_table = &range_ni_E_ao_ext, |
| .ao_unipolar = 1, |
| .ao_speed = 10000, |
| .num_p0_dio_channels = 8, |
| .caldac = {dac8800, dac8043, ad8522}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x1270, |
| .name = "pci-6032e", |
| .n_adchan = 16, |
| .adbits = 16, |
| .ai_fifo_depth = 512, |
| .alwaysdither = 1, |
| .gainlkup = ai_gain_14, |
| .ai_speed = 10000, |
| .n_aochan = 0, |
| .aobits = 0, |
| .ao_fifo_depth = 0, |
| .ao_unipolar = 0, |
| .num_p0_dio_channels = 8, |
| .caldac = {dac8800, dac8043, ad8522}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x1340, |
| .name = "pci-6033e", |
| .n_adchan = 64, |
| .adbits = 16, |
| .ai_fifo_depth = 512, |
| .alwaysdither = 1, |
| .gainlkup = ai_gain_14, |
| .ai_speed = 10000, |
| .n_aochan = 0, |
| .aobits = 0, |
| .ao_fifo_depth = 0, |
| .ao_unipolar = 0, |
| .num_p0_dio_channels = 8, |
| .caldac = {dac8800, dac8043, ad8522}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x1350, |
| .name = "pci-6071e", |
| .n_adchan = 64, |
| .adbits = 12, |
| .ai_fifo_depth = 512, |
| .alwaysdither = 1, |
| .gainlkup = ai_gain_16, |
| .ai_speed = 800, |
| .n_aochan = 2, |
| .aobits = 12, |
| .ao_fifo_depth = 2048, |
| .ao_range_table = &range_ni_E_ao_ext, |
| .ao_unipolar = 1, |
| .ao_speed = 1000, |
| .num_p0_dio_channels = 8, |
| .caldac = {ad8804_debug}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x2a60, |
| .name = "pci-6023e", |
| .n_adchan = 16, |
| .adbits = 12, |
| .ai_fifo_depth = 512, |
| .alwaysdither = 0, |
| .gainlkup = ai_gain_4, |
| .ai_speed = 5000, |
| .n_aochan = 0, |
| .aobits = 0, |
| .ao_unipolar = 0, |
| .num_p0_dio_channels = 8, |
| .caldac = {ad8804_debug}, /* manual is wrong */ |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x2a70, |
| .name = "pci-6024e", |
| .n_adchan = 16, |
| .adbits = 12, |
| .ai_fifo_depth = 512, |
| .alwaysdither = 0, |
| .gainlkup = ai_gain_4, |
| .ai_speed = 5000, |
| .n_aochan = 2, |
| .aobits = 12, |
| .ao_fifo_depth = 0, |
| .ao_range_table = &range_bipolar10, |
| .ao_unipolar = 0, |
| .ao_speed = 100000, |
| .num_p0_dio_channels = 8, |
| .caldac = {ad8804_debug}, /* manual is wrong */ |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x2a80, |
| .name = "pci-6025e", |
| .n_adchan = 16, |
| .adbits = 12, |
| .ai_fifo_depth = 512, |
| .alwaysdither = 0, |
| .gainlkup = ai_gain_4, |
| .ai_speed = 5000, |
| .n_aochan = 2, |
| .aobits = 12, |
| .ao_fifo_depth = 0, |
| .ao_range_table = &range_bipolar10, |
| .ao_unipolar = 0, |
| .ao_speed = 100000, |
| .num_p0_dio_channels = 8, |
| .caldac = {ad8804_debug}, /* manual is wrong */ |
| .has_8255 = 1, |
| }, |
| { |
| .device_id = 0x2ab0, |
| .name = "pxi-6025e", |
| .n_adchan = 16, |
| .adbits = 12, |
| .ai_fifo_depth = 512, |
| .alwaysdither = 0, |
| .gainlkup = ai_gain_4, |
| .ai_speed = 5000, |
| .n_aochan = 2, |
| .aobits = 12, |
| .ao_fifo_depth = 0, |
| .ao_range_table = &range_ni_E_ao_ext, |
| .ao_unipolar = 1, |
| .ao_speed = 100000, |
| .num_p0_dio_channels = 8, |
| .caldac = {ad8804_debug}, /* manual is wrong */ |
| .has_8255 = 1, |
| }, |
| |
| { |
| .device_id = 0x2ca0, |
| .name = "pci-6034e", |
| .n_adchan = 16, |
| .adbits = 16, |
| .ai_fifo_depth = 512, |
| .alwaysdither = 1, |
| .gainlkup = ai_gain_4, |
| .ai_speed = 5000, |
| .n_aochan = 0, |
| .aobits = 0, |
| .ao_fifo_depth = 0, |
| .ao_unipolar = 0, |
| .num_p0_dio_channels = 8, |
| .caldac = {ad8804_debug}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x2c80, |
| .name = "pci-6035e", |
| .n_adchan = 16, |
| .adbits = 16, |
| .ai_fifo_depth = 512, |
| .alwaysdither = 1, |
| .gainlkup = ai_gain_4, |
| .ai_speed = 5000, |
| .n_aochan = 2, |
| .aobits = 12, |
| .ao_fifo_depth = 0, |
| .ao_range_table = &range_bipolar10, |
| .ao_unipolar = 0, |
| .ao_speed = 100000, |
| .num_p0_dio_channels = 8, |
| .caldac = {ad8804_debug}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x18b0, |
| .name = "pci-6052e", |
| .n_adchan = 16, |
| .adbits = 16, |
| .ai_fifo_depth = 512, |
| .alwaysdither = 1, |
| .gainlkup = ai_gain_16, |
| .ai_speed = 3000, |
| .n_aochan = 2, |
| .aobits = 16, |
| .ao_unipolar = 1, |
| .ao_fifo_depth = 2048, |
| .ao_range_table = &range_ni_E_ao_ext, |
| .ao_speed = 3000, |
| .num_p0_dio_channels = 8, |
| .caldac = {ad8804_debug, ad8804_debug, ad8522}, /* manual is wrong */ |
| }, |
| {.device_id = 0x14e0, |
| .name = "pci-6110", |
| .n_adchan = 4, |
| .adbits = 12, |
| .ai_fifo_depth = 8192, |
| .alwaysdither = 0, |
| .gainlkup = ai_gain_611x, |
| .ai_speed = 200, |
| .n_aochan = 2, |
| .aobits = 16, |
| .reg_type = ni_reg_611x, |
| .ao_range_table = &range_bipolar10, |
| .ao_unipolar = 0, |
| .ao_fifo_depth = 2048, |
| .ao_speed = 250, |
| .num_p0_dio_channels = 8, |
| .caldac = {ad8804, ad8804}, |
| }, |
| { |
| .device_id = 0x14f0, |
| .name = "pci-6111", |
| .n_adchan = 2, |
| .adbits = 12, |
| .ai_fifo_depth = 8192, |
| .alwaysdither = 0, |
| .gainlkup = ai_gain_611x, |
| .ai_speed = 200, |
| .n_aochan = 2, |
| .aobits = 16, |
| .reg_type = ni_reg_611x, |
| .ao_range_table = &range_bipolar10, |
| .ao_unipolar = 0, |
| .ao_fifo_depth = 2048, |
| .ao_speed = 250, |
| .num_p0_dio_channels = 8, |
| .caldac = {ad8804, ad8804}, |
| }, |
| #if 0 |
| /* The 6115 boards probably need their own driver */ |
| { |
| .device_id = 0x2ed0, |
| .name = "pci-6115", |
| .n_adchan = 4, |
| .adbits = 12, |
| .ai_fifo_depth = 8192, |
| .alwaysdither = 0, |
| .gainlkup = ai_gain_611x, |
| .ai_speed = 100, |
| .n_aochan = 2, |
| .aobits = 16, |
| .ao_671x = 1, |
| .ao_unipolar = 0, |
| .ao_fifo_depth = 2048, |
| .ao_speed = 250, |
| .num_p0_dio_channels = 8, |
| .reg_611x = 1, |
| .caldac = {ad8804_debug, ad8804_debug, ad8804_debug}, /* XXX */ |
| }, |
| #endif |
| #if 0 |
| { |
| .device_id = 0x0000, |
| .name = "pxi-6115", |
| .n_adchan = 4, |
| .adbits = 12, |
| .ai_fifo_depth = 8192, |
| .alwaysdither = 0, |
| .gainlkup = ai_gain_611x, |
| .ai_speed = 100, |
| .n_aochan = 2, |
| .aobits = 16, |
| .ao_671x = 1, |
| .ao_unipolar = 0, |
| .ao_fifo_depth = 2048, |
| .ao_speed = 250, |
| .reg_611x = 1, |
| .num_p0_dio_channels = 8, |
| caldac = {ad8804_debug, ad8804_debug, ad8804_debug}, /* XXX */ |
| }, |
| #endif |
| { |
| .device_id = 0x1880, |
| .name = "pci-6711", |
| .n_adchan = 0, /* no analog input */ |
| .n_aochan = 4, |
| .aobits = 12, |
| .ao_unipolar = 0, |
| .ao_fifo_depth = 16384, |
| /* data sheet says 8192, but fifo really holds 16384 samples */ |
| .ao_range_table = &range_bipolar10, |
| .ao_speed = 1000, |
| .num_p0_dio_channels = 8, |
| .reg_type = ni_reg_6711, |
| .caldac = {ad8804_debug}, |
| }, |
| { |
| .device_id = 0x2b90, |
| .name = "pxi-6711", |
| .n_adchan = 0, /* no analog input */ |
| .n_aochan = 4, |
| .aobits = 12, |
| .ao_unipolar = 0, |
| .ao_fifo_depth = 16384, |
| .ao_range_table = &range_bipolar10, |
| .ao_speed = 1000, |
| .num_p0_dio_channels = 8, |
| .reg_type = ni_reg_6711, |
| .caldac = {ad8804_debug}, |
| }, |
| { |
| .device_id = 0x1870, |
| .name = "pci-6713", |
| .n_adchan = 0, /* no analog input */ |
| .n_aochan = 8, |
| .aobits = 12, |
| .ao_unipolar = 0, |
| .ao_fifo_depth = 16384, |
| .ao_range_table = &range_bipolar10, |
| .ao_speed = 1000, |
| .num_p0_dio_channels = 8, |
| .reg_type = ni_reg_6713, |
| .caldac = {ad8804_debug, ad8804_debug}, |
| }, |
| { |
| .device_id = 0x2b80, |
| .name = "pxi-6713", |
| .n_adchan = 0, /* no analog input */ |
| .n_aochan = 8, |
| .aobits = 12, |
| .ao_unipolar = 0, |
| .ao_fifo_depth = 16384, |
| .ao_range_table = &range_bipolar10, |
| .ao_speed = 1000, |
| .num_p0_dio_channels = 8, |
| .reg_type = ni_reg_6713, |
| .caldac = {ad8804_debug, ad8804_debug}, |
| }, |
| { |
| .device_id = 0x2430, |
| .name = "pci-6731", |
| .n_adchan = 0, /* no analog input */ |
| .n_aochan = 4, |
| .aobits = 16, |
| .ao_unipolar = 0, |
| .ao_fifo_depth = 8192, |
| .ao_range_table = &range_bipolar10, |
| .ao_speed = 1000, |
| .num_p0_dio_channels = 8, |
| .reg_type = ni_reg_6711, |
| .caldac = {ad8804_debug}, |
| }, |
| #if 0 /* need device ids */ |
| { |
| .device_id = 0x0, |
| .name = "pxi-6731", |
| .n_adchan = 0, /* no analog input */ |
| .n_aochan = 4, |
| .aobits = 16, |
| .ao_unipolar = 0, |
| .ao_fifo_depth = 8192, |
| .ao_range_table = &range_bipolar10, |
| .num_p0_dio_channels = 8, |
| .reg_type = ni_reg_6711, |
| .caldac = {ad8804_debug}, |
| }, |
| #endif |
| { |
| .device_id = 0x2410, |
| .name = "pci-6733", |
| .n_adchan = 0, /* no analog input */ |
| .n_aochan = 8, |
| .aobits = 16, |
| .ao_unipolar = 0, |
| .ao_fifo_depth = 16384, |
| .ao_range_table = &range_bipolar10, |
| .ao_speed = 1000, |
| .num_p0_dio_channels = 8, |
| .reg_type = ni_reg_6713, |
| .caldac = {ad8804_debug, ad8804_debug}, |
| }, |
| { |
| .device_id = 0x2420, |
| .name = "pxi-6733", |
| .n_adchan = 0, /* no analog input */ |
| .n_aochan = 8, |
| .aobits = 16, |
| .ao_unipolar = 0, |
| .ao_fifo_depth = 16384, |
| .ao_range_table = &range_bipolar10, |
| .ao_speed = 1000, |
| .num_p0_dio_channels = 8, |
| .reg_type = ni_reg_6713, |
| .caldac = {ad8804_debug, ad8804_debug}, |
| }, |
| { |
| .device_id = 0x15b0, |
| .name = "pxi-6071e", |
| .n_adchan = 64, |
| .adbits = 12, |
| .ai_fifo_depth = 512, |
| .alwaysdither = 1, |
| .gainlkup = ai_gain_16, |
| .ai_speed = 800, |
| .n_aochan = 2, |
| .aobits = 12, |
| .ao_fifo_depth = 2048, |
| .ao_range_table = &range_ni_E_ao_ext, |
| .ao_unipolar = 1, |
| .ao_speed = 1000, |
| .num_p0_dio_channels = 8, |
| .caldac = {ad8804_debug}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x11b0, |
| .name = "pxi-6070e", |
| .n_adchan = 16, |
| .adbits = 12, |
| .ai_fifo_depth = 512, |
| .alwaysdither = 1, |
| .gainlkup = ai_gain_16, |
| .ai_speed = 800, |
| .n_aochan = 2, |
| .aobits = 12, |
| .ao_fifo_depth = 2048, |
| .ao_range_table = &range_ni_E_ao_ext, |
| .ao_unipolar = 1, |
| .ao_speed = 1000, |
| .num_p0_dio_channels = 8, |
| .caldac = {ad8804_debug}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x18c0, |
| .name = "pxi-6052e", |
| .n_adchan = 16, |
| .adbits = 16, |
| .ai_fifo_depth = 512, |
| .alwaysdither = 1, |
| .gainlkup = ai_gain_16, |
| .ai_speed = 3000, |
| .n_aochan = 2, |
| .aobits = 16, |
| .ao_unipolar = 1, |
| .ao_fifo_depth = 2048, |
| .ao_range_table = &range_ni_E_ao_ext, |
| .ao_speed = 3000, |
| .num_p0_dio_channels = 8, |
| .caldac = {mb88341, mb88341, ad8522}, |
| }, |
| { |
| .device_id = 0x1580, |
| .name = "pxi-6031e", |
| .n_adchan = 64, |
| .adbits = 16, |
| .ai_fifo_depth = 512, |
| .alwaysdither = 1, |
| .gainlkup = ai_gain_14, |
| .ai_speed = 10000, |
| .n_aochan = 2, |
| .aobits = 16, |
| .ao_fifo_depth = 2048, |
| .ao_range_table = &range_ni_E_ao_ext, |
| .ao_unipolar = 1, |
| .ao_speed = 10000, |
| .num_p0_dio_channels = 8, |
| .caldac = {dac8800, dac8043, ad8522}, |
| }, |
| { |
| .device_id = 0x2890, |
| .name = "pci-6036e", |
| .n_adchan = 16, |
| .adbits = 16, |
| .ai_fifo_depth = 512, |
| .alwaysdither = 1, |
| .gainlkup = ai_gain_4, |
| .ai_speed = 5000, |
| .n_aochan = 2, |
| .aobits = 16, |
| .ao_fifo_depth = 0, |
| .ao_range_table = &range_bipolar10, |
| .ao_unipolar = 0, |
| .ao_speed = 100000, |
| .num_p0_dio_channels = 8, |
| .caldac = {ad8804_debug}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x70b0, |
| .name = "pci-6220", |
| .n_adchan = 16, |
| .adbits = 16, |
| .ai_fifo_depth = 512, |
| /* .FIXME = guess */ |
| .gainlkup = ai_gain_622x, |
| .ai_speed = 4000, |
| .n_aochan = 0, |
| .aobits = 0, |
| .ao_fifo_depth = 0, |
| .num_p0_dio_channels = 8, |
| .reg_type = ni_reg_622x, |
| .ao_unipolar = 0, |
| .caldac = {caldac_none}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x70af, |
| .name = "pci-6221", |
| .n_adchan = 16, |
| .adbits = 16, |
| .ai_fifo_depth = 4095, |
| .gainlkup = ai_gain_622x, |
| .ai_speed = 4000, |
| .n_aochan = 2, |
| .aobits = 16, |
| .ao_fifo_depth = 8191, |
| .ao_range_table = &range_ni_M_622x_ao, |
| .reg_type = ni_reg_622x, |
| .ao_unipolar = 0, |
| .ao_speed = 1200, |
| .num_p0_dio_channels = 8, |
| .caldac = {caldac_none}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x71bc, |
| .name = "pci-6221_37pin", |
| .n_adchan = 16, |
| .adbits = 16, |
| .ai_fifo_depth = 4095, |
| .gainlkup = ai_gain_622x, |
| .ai_speed = 4000, |
| .n_aochan = 2, |
| .aobits = 16, |
| .ao_fifo_depth = 8191, |
| .ao_range_table = &range_ni_M_622x_ao, |
| .reg_type = ni_reg_622x, |
| .ao_unipolar = 0, |
| .ao_speed = 1200, |
| .num_p0_dio_channels = 8, |
| .caldac = {caldac_none}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x70f2, |
| .name = "pci-6224", |
| .n_adchan = 32, |
| .adbits = 16, |
| .ai_fifo_depth = 4095, |
| .gainlkup = ai_gain_622x, |
| .ai_speed = 4000, |
| .n_aochan = 0, |
| .aobits = 0, |
| .ao_fifo_depth = 0, |
| .reg_type = ni_reg_622x, |
| .ao_unipolar = 0, |
| .num_p0_dio_channels = 32, |
| .caldac = {caldac_none}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x70f3, |
| .name = "pxi-6224", |
| .n_adchan = 32, |
| .adbits = 16, |
| .ai_fifo_depth = 4095, |
| .gainlkup = ai_gain_622x, |
| .ai_speed = 4000, |
| .n_aochan = 0, |
| .aobits = 0, |
| .ao_fifo_depth = 0, |
| .reg_type = ni_reg_622x, |
| .ao_unipolar = 0, |
| .num_p0_dio_channels = 32, |
| .caldac = {caldac_none}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x716c, |
| .name = "pci-6225", |
| .n_adchan = 80, |
| .adbits = 16, |
| .ai_fifo_depth = 4095, |
| .gainlkup = ai_gain_622x, |
| .ai_speed = 4000, |
| .n_aochan = 2, |
| .aobits = 16, |
| .ao_fifo_depth = 8191, |
| .ao_range_table = &range_ni_M_622x_ao, |
| .reg_type = ni_reg_622x, |
| .ao_unipolar = 0, |
| .ao_speed = 1200, |
| .num_p0_dio_channels = 32, |
| .caldac = {caldac_none}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x716d, |
| .name = "pxi-6225", |
| .n_adchan = 80, |
| .adbits = 16, |
| .ai_fifo_depth = 4095, |
| .gainlkup = ai_gain_622x, |
| .ai_speed = 4000, |
| .n_aochan = 2, |
| .aobits = 16, |
| .ao_fifo_depth = 8191, |
| .ao_range_table = &range_ni_M_622x_ao, |
| .reg_type = ni_reg_622x, |
| .ao_unipolar = 0, |
| .ao_speed = 1200, |
| .num_p0_dio_channels = 32, |
| .caldac = {caldac_none}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x70aa, |
| .name = "pci-6229", |
| .n_adchan = 32, |
| .adbits = 16, |
| .ai_fifo_depth = 4095, |
| .gainlkup = ai_gain_622x, |
| .ai_speed = 4000, |
| .n_aochan = 4, |
| .aobits = 16, |
| .ao_fifo_depth = 8191, |
| .ao_range_table = &range_ni_M_622x_ao, |
| .reg_type = ni_reg_622x, |
| .ao_unipolar = 0, |
| .ao_speed = 1200, |
| .num_p0_dio_channels = 32, |
| .caldac = {caldac_none}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x70b4, |
| .name = "pci-6250", |
| .n_adchan = 16, |
| .adbits = 16, |
| .ai_fifo_depth = 4095, |
| .gainlkup = ai_gain_628x, |
| .ai_speed = 800, |
| .n_aochan = 0, |
| .aobits = 0, |
| .ao_fifo_depth = 0, |
| .reg_type = ni_reg_625x, |
| .ao_unipolar = 0, |
| .num_p0_dio_channels = 8, |
| .caldac = {caldac_none}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x70b8, |
| .name = "pci-6251", |
| .n_adchan = 16, |
| .adbits = 16, |
| .ai_fifo_depth = 4095, |
| .gainlkup = ai_gain_628x, |
| .ai_speed = 800, |
| .n_aochan = 2, |
| .aobits = 16, |
| .ao_fifo_depth = 8191, |
| .ao_range_table = &range_ni_M_625x_ao, |
| .reg_type = ni_reg_625x, |
| .ao_unipolar = 0, |
| .ao_speed = 357, |
| .num_p0_dio_channels = 8, |
| .caldac = {caldac_none}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x717d, |
| .name = "pcie-6251", |
| .n_adchan = 16, |
| .adbits = 16, |
| .ai_fifo_depth = 4095, |
| .gainlkup = ai_gain_628x, |
| .ai_speed = 800, |
| .n_aochan = 2, |
| .aobits = 16, |
| .ao_fifo_depth = 8191, |
| .ao_range_table = &range_ni_M_625x_ao, |
| .reg_type = ni_reg_625x, |
| .ao_unipolar = 0, |
| .ao_speed = 357, |
| .num_p0_dio_channels = 8, |
| .caldac = {caldac_none}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x72e8, |
| .name = "pxie-6251", |
| .n_adchan = 16, |
| .adbits = 16, |
| .ai_fifo_depth = 4095, |
| .gainlkup = ai_gain_628x, |
| .ai_speed = 800, |
| .n_aochan = 2, |
| .aobits = 16, |
| .ao_fifo_depth = 8191, |
| .ao_range_table = &range_ni_M_625x_ao, |
| .reg_type = ni_reg_625x, |
| .ao_unipolar = 0, |
| .ao_speed = 357, |
| .num_p0_dio_channels = 8, |
| .caldac = {caldac_none}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x70b7, |
| .name = "pci-6254", |
| .n_adchan = 32, |
| .adbits = 16, |
| .ai_fifo_depth = 4095, |
| .gainlkup = ai_gain_628x, |
| .ai_speed = 800, |
| .n_aochan = 0, |
| .aobits = 0, |
| .ao_fifo_depth = 0, |
| .reg_type = ni_reg_625x, |
| .ao_unipolar = 0, |
| .num_p0_dio_channels = 32, |
| .caldac = {caldac_none}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x70ab, |
| .name = "pci-6259", |
| .n_adchan = 32, |
| .adbits = 16, |
| .ai_fifo_depth = 4095, |
| .gainlkup = ai_gain_628x, |
| .ai_speed = 800, |
| .n_aochan = 4, |
| .aobits = 16, |
| .ao_fifo_depth = 8191, |
| .ao_range_table = &range_ni_M_625x_ao, |
| .reg_type = ni_reg_625x, |
| .ao_unipolar = 0, |
| .ao_speed = 357, |
| .num_p0_dio_channels = 32, |
| .caldac = {caldac_none}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x717f, |
| .name = "pcie-6259", |
| .n_adchan = 32, |
| .adbits = 16, |
| .ai_fifo_depth = 4095, |
| .gainlkup = ai_gain_628x, |
| .ai_speed = 800, |
| .n_aochan = 4, |
| .aobits = 16, |
| .ao_fifo_depth = 8191, |
| .ao_range_table = &range_ni_M_625x_ao, |
| .reg_type = ni_reg_625x, |
| .ao_unipolar = 0, |
| .ao_speed = 357, |
| .num_p0_dio_channels = 32, |
| .caldac = {caldac_none}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x70b6, |
| .name = "pci-6280", |
| .n_adchan = 16, |
| .adbits = 18, |
| .ai_fifo_depth = 2047, |
| .gainlkup = ai_gain_628x, |
| .ai_speed = 1600, |
| .n_aochan = 0, |
| .aobits = 0, |
| .ao_fifo_depth = 8191, |
| .reg_type = ni_reg_628x, |
| .ao_unipolar = 0, |
| .num_p0_dio_channels = 8, |
| .caldac = {caldac_none}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x70bd, |
| .name = "pci-6281", |
| .n_adchan = 16, |
| .adbits = 18, |
| .ai_fifo_depth = 2047, |
| .gainlkup = ai_gain_628x, |
| .ai_speed = 1600, |
| .n_aochan = 2, |
| .aobits = 16, |
| .ao_fifo_depth = 8191, |
| .ao_range_table = &range_ni_M_628x_ao, |
| .reg_type = ni_reg_628x, |
| .ao_unipolar = 1, |
| .ao_speed = 357, |
| .num_p0_dio_channels = 8, |
| .caldac = {caldac_none}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x70bf, |
| .name = "pxi-6281", |
| .n_adchan = 16, |
| .adbits = 18, |
| .ai_fifo_depth = 2047, |
| .gainlkup = ai_gain_628x, |
| .ai_speed = 1600, |
| .n_aochan = 2, |
| .aobits = 16, |
| .ao_fifo_depth = 8191, |
| .ao_range_table = &range_ni_M_628x_ao, |
| .reg_type = ni_reg_628x, |
| .ao_unipolar = 1, |
| .ao_speed = 357, |
| .num_p0_dio_channels = 8, |
| .caldac = {caldac_none}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x70bc, |
| .name = "pci-6284", |
| .n_adchan = 32, |
| .adbits = 18, |
| .ai_fifo_depth = 2047, |
| .gainlkup = ai_gain_628x, |
| .ai_speed = 1600, |
| .n_aochan = 0, |
| .aobits = 0, |
| .ao_fifo_depth = 0, |
| .reg_type = ni_reg_628x, |
| .ao_unipolar = 0, |
| .num_p0_dio_channels = 32, |
| .caldac = {caldac_none}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x70ac, |
| .name = "pci-6289", |
| .n_adchan = 32, |
| .adbits = 18, |
| .ai_fifo_depth = 2047, |
| .gainlkup = ai_gain_628x, |
| .ai_speed = 1600, |
| .n_aochan = 4, |
| .aobits = 16, |
| .ao_fifo_depth = 8191, |
| .ao_range_table = &range_ni_M_628x_ao, |
| .reg_type = ni_reg_628x, |
| .ao_unipolar = 1, |
| .ao_speed = 357, |
| .num_p0_dio_channels = 32, |
| .caldac = {caldac_none}, |
| .has_8255 = 0, |
| }, |
| { |
| .device_id = 0x70C0, |
| .name = "pci-6143", |
| .n_adchan = 8, |
| .adbits = 16, |
| .ai_fifo_depth = 1024, |
| .alwaysdither = 0, |
| .gainlkup = ai_gain_6143, |
| .ai_speed = 4000, |
| .n_aochan = 0, |
| .aobits = 0, |
| .reg_type = ni_reg_6143, |
| .ao_unipolar = 0, |
| .ao_fifo_depth = 0, |
| .num_p0_dio_channels = 8, |
| .caldac = {ad8804_debug, ad8804_debug}, |
| }, |
| { |
| .device_id = 0x710D, |
| .name = "pxi-6143", |
| .n_adchan = 8, |
| .adbits = 16, |
| .ai_fifo_depth = 1024, |
| .alwaysdither = 0, |
| .gainlkup = ai_gain_6143, |
| .ai_speed = 4000, |
| .n_aochan = 0, |
| .aobits = 0, |
| .reg_type = ni_reg_6143, |
| .ao_unipolar = 0, |
| .ao_fifo_depth = 0, |
| .num_p0_dio_channels = 8, |
| .caldac = {ad8804_debug, ad8804_debug}, |
| }, |
| }; |
| |
| struct ni_private { |
| NI_PRIVATE_COMMON}; |
| #define devpriv ((struct ni_private *)dev->private) |
| |
| /* How we access registers */ |
| |
| #define ni_writel(a, b) (writel((a), devpriv->mite->daq_io_addr + (b))) |
| #define ni_readl(a) (readl(devpriv->mite->daq_io_addr + (a))) |
| #define ni_writew(a, b) (writew((a), devpriv->mite->daq_io_addr + (b))) |
| #define ni_readw(a) (readw(devpriv->mite->daq_io_addr + (a))) |
| #define ni_writeb(a, b) (writeb((a), devpriv->mite->daq_io_addr + (b))) |
| #define ni_readb(a) (readb(devpriv->mite->daq_io_addr + (a))) |
| |
| /* How we access STC registers */ |
| |
| /* We automatically take advantage of STC registers that can be |
| * read/written directly in the I/O space of the board. Most |
| * PCIMIO devices map the low 8 STC registers to iobase+addr*2. |
| * The 611x devices map the write registers to iobase+addr*2, and |
| * the read registers to iobase+(addr-1)*2. */ |
| /* However, the 611x boards still aren't working, so I'm disabling |
| * non-windowed STC access temporarily */ |
| |
| static void e_series_win_out(struct comedi_device *dev, uint16_t data, int reg) |
| { |
| unsigned long flags; |
| |
| spin_lock_irqsave(&devpriv->window_lock, flags); |
| ni_writew(reg, Window_Address); |
| ni_writew(data, Window_Data); |
| spin_unlock_irqrestore(&devpriv->window_lock, flags); |
| } |
| |
| static uint16_t e_series_win_in(struct comedi_device *dev, int reg) |
| { |
| unsigned long flags; |
| uint16_t ret; |
| |
| spin_lock_irqsave(&devpriv->window_lock, flags); |
| ni_writew(reg, Window_Address); |
| ret = ni_readw(Window_Data); |
| spin_unlock_irqrestore(&devpriv->window_lock, flags); |
| |
| return ret; |
| } |
| |
| static void m_series_stc_writew(struct comedi_device *dev, uint16_t data, |
| int reg) |
| { |
| unsigned offset; |
| switch (reg) { |
| case ADC_FIFO_Clear: |
| offset = M_Offset_AI_FIFO_Clear; |
| break; |
| case AI_Command_1_Register: |
| offset = M_Offset_AI_Command_1; |
| break; |
| case AI_Command_2_Register: |
| offset = M_Offset_AI_Command_2; |
| break; |
| case AI_Mode_1_Register: |
| offset = M_Offset_AI_Mode_1; |
| break; |
| case AI_Mode_2_Register: |
| offset = M_Offset_AI_Mode_2; |
| break; |
| case AI_Mode_3_Register: |
| offset = M_Offset_AI_Mode_3; |
| break; |
| case AI_Output_Control_Register: |
| offset = M_Offset_AI_Output_Control; |
| break; |
| case AI_Personal_Register: |
| offset = M_Offset_AI_Personal; |
| break; |
| case AI_SI2_Load_A_Register: |
| /* this is actually a 32 bit register on m series boards */ |
| ni_writel(data, M_Offset_AI_SI2_Load_A); |
| return; |
| break; |
| case AI_SI2_Load_B_Register: |
| /* this is actually a 32 bit register on m series boards */ |
| ni_writel(data, M_Offset_AI_SI2_Load_B); |
| return; |
| break; |
| case AI_START_STOP_Select_Register: |
| offset = M_Offset_AI_START_STOP_Select; |
| break; |
| case AI_Trigger_Select_Register: |
| offset = M_Offset_AI_Trigger_Select; |
| break; |
| case Analog_Trigger_Etc_Register: |
| offset = M_Offset_Analog_Trigger_Etc; |
| break; |
| case AO_Command_1_Register: |
| offset = M_Offset_AO_Command_1; |
| break; |
| case AO_Command_2_Register: |
| offset = M_Offset_AO_Command_2; |
| break; |
| case AO_Mode_1_Register: |
| offset = M_Offset_AO_Mode_1; |
| break; |
| case AO_Mode_2_Register: |
| offset = M_Offset_AO_Mode_2; |
| break; |
| case AO_Mode_3_Register: |
| offset = M_Offset_AO_Mode_3; |
| break; |
| case AO_Output_Control_Register: |
| offset = M_Offset_AO_Output_Control; |
| break; |
| case AO_Personal_Register: |
| offset = M_Offset_AO_Personal; |
| break; |
| case AO_Start_Select_Register: |
| offset = M_Offset_AO_Start_Select; |
| break; |
| case AO_Trigger_Select_Register: |
| offset = M_Offset_AO_Trigger_Select; |
| break; |
| case Clock_and_FOUT_Register: |
| offset = M_Offset_Clock_and_FOUT; |
| break; |
| case Configuration_Memory_Clear: |
| offset = M_Offset_Configuration_Memory_Clear; |
| break; |
| case DAC_FIFO_Clear: |
| offset = M_Offset_AO_FIFO_Clear; |
| break; |
| case DIO_Control_Register: |
| printk |
| ("%s: FIXME: register 0x%x does not map cleanly on to m-series boards.\n", |
| __func__, reg); |
| return; |
| break; |
| case G_Autoincrement_Register(0): |
| offset = M_Offset_G0_Autoincrement; |
| break; |
| case G_Autoincrement_Register(1): |
| offset = M_Offset_G1_Autoincrement; |
| break; |
| case G_Command_Register(0): |
| offset = M_Offset_G0_Command; |
| break; |
| case G_Command_Register(1): |
| offset = M_Offset_G1_Command; |
| break; |
| case G_Input_Select_Register(0): |
| offset = M_Offset_G0_Input_Select; |
| break; |
| case G_Input_Select_Register(1): |
| offset = M_Offset_G1_Input_Select; |
| break; |
| case G_Mode_Register(0): |
| offset = M_Offset_G0_Mode; |
| break; |
| case G_Mode_Register(1): |
| offset = M_Offset_G1_Mode; |
| break; |
| case Interrupt_A_Ack_Register: |
| offset = M_Offset_Interrupt_A_Ack; |
| break; |
| case Interrupt_A_Enable_Register: |
| offset = M_Offset_Interrupt_A_Enable; |
| break; |
| case Interrupt_B_Ack_Register: |
| offset = M_Offset_Interrupt_B_Ack; |
| break; |
| case Interrupt_B_Enable_Register: |
| offset = M_Offset_Interrupt_B_Enable; |
| break; |
| case Interrupt_Control_Register: |
| offset = M_Offset_Interrupt_Control; |
| break; |
| case IO_Bidirection_Pin_Register: |
| offset = M_Offset_IO_Bidirection_Pin; |
| break; |
| case Joint_Reset_Register: |
| offset = M_Offset_Joint_Reset; |
| break; |
| case RTSI_Trig_A_Output_Register: |
| offset = M_Offset_RTSI_Trig_A_Output; |
| break; |
| case RTSI_Trig_B_Output_Register: |
| offset = M_Offset_RTSI_Trig_B_Output; |
| break; |
| case RTSI_Trig_Direction_Register: |
| offset = M_Offset_RTSI_Trig_Direction; |
| break; |
| /* FIXME: DIO_Output_Register (16 bit reg) is replaced by M_Offset_Static_Digital_Output (32 bit) |
| and M_Offset_SCXI_Serial_Data_Out (8 bit) */ |
| default: |
| printk(KERN_WARNING "%s: bug! unhandled register=0x%x in switch.\n", |
| __func__, reg); |
| BUG(); |
| return; |
| break; |
| } |
| ni_writew(data, offset); |
| } |
| |
| static uint16_t m_series_stc_readw(struct comedi_device *dev, int reg) |
| { |
| unsigned offset; |
| switch (reg) { |
| case AI_Status_1_Register: |
| offset = M_Offset_AI_Status_1; |
| break; |
| case AO_Status_1_Register: |
| offset = M_Offset_AO_Status_1; |
| break; |
| case AO_Status_2_Register: |
| offset = M_Offset_AO_Status_2; |
| break; |
| case DIO_Serial_Input_Register: |
| return ni_readb(M_Offset_SCXI_Serial_Data_In); |
| break; |
| case Joint_Status_1_Register: |
| offset = M_Offset_Joint_Status_1; |
| break; |
| case Joint_Status_2_Register: |
| offset = M_Offset_Joint_Status_2; |
| break; |
| case G_Status_Register: |
| offset = M_Offset_G01_Status; |
| break; |
| default: |
| printk(KERN_WARNING "%s: bug! unhandled register=0x%x in switch.\n", |
| __func__, reg); |
| BUG(); |
| return 0; |
| break; |
| } |
| return ni_readw(offset); |
| } |
| |
| static void m_series_stc_writel(struct comedi_device *dev, uint32_t data, |
| int reg) |
| { |
| unsigned offset; |
| switch (reg) { |
| case AI_SC_Load_A_Registers: |
| offset = M_Offset_AI_SC_Load_A; |
| break; |
| case AI_SI_Load_A_Registers: |
| offset = M_Offset_AI_SI_Load_A; |
| break; |
| case AO_BC_Load_A_Register: |
| offset = M_Offset_AO_BC_Load_A; |
| break; |
| case AO_UC_Load_A_Register: |
| offset = M_Offset_AO_UC_Load_A; |
| break; |
| case AO_UI_Load_A_Register: |
| offset = M_Offset_AO_UI_Load_A; |
| break; |
| case G_Load_A_Register(0): |
| offset = M_Offset_G0_Load_A; |
| break; |
| case G_Load_A_Register(1): |
| offset = M_Offset_G1_Load_A; |
| break; |
| case G_Load_B_Register(0): |
| offset = M_Offset_G0_Load_B; |
| break; |
| case G_Load_B_Register(1): |
| offset = M_Offset_G1_Load_B; |
| break; |
| default: |
| printk(KERN_WARNING "%s: bug! unhandled register=0x%x in switch.\n", |
| __func__, reg); |
| BUG(); |
| return; |
| break; |
| } |
| ni_writel(data, offset); |
| } |
| |
| static uint32_t m_series_stc_readl(struct comedi_device *dev, int reg) |
| { |
| unsigned offset; |
| switch (reg) { |
| case G_HW_Save_Register(0): |
| offset = M_Offset_G0_HW_Save; |
| break; |
| case G_HW_Save_Register(1): |
| offset = M_Offset_G1_HW_Save; |
| break; |
| case G_Save_Register(0): |
| offset = M_Offset_G0_Save; |
| break; |
| case G_Save_Register(1): |
| offset = M_Offset_G1_Save; |
| break; |
| default: |
| printk(KERN_WARNING "%s: bug! unhandled register=0x%x in switch.\n", |
| __func__, reg); |
| BUG(); |
| return 0; |
| break; |
| } |
| return ni_readl(offset); |
| } |
| |
| #define interrupt_pin(a) 0 |
| #define IRQ_POLARITY 1 |
| |
| #define NI_E_IRQ_FLAGS IRQF_SHARED |
| |
| #include "ni_mio_common.c" |
| |
| static int pcimio_ai_change(struct comedi_device *dev, |
| struct comedi_subdevice *s, unsigned long new_size); |
| static int pcimio_ao_change(struct comedi_device *dev, |
| struct comedi_subdevice *s, unsigned long new_size); |
| static int pcimio_gpct0_change(struct comedi_device *dev, |
| struct comedi_subdevice *s, |
| unsigned long new_size); |
| static int pcimio_gpct1_change(struct comedi_device *dev, |
| struct comedi_subdevice *s, |
| unsigned long new_size); |
| static int pcimio_dio_change(struct comedi_device *dev, |
| struct comedi_subdevice *s, |
| unsigned long new_size); |
| |
| static void m_series_init_eeprom_buffer(struct comedi_device *dev) |
| { |
| static const int Start_Cal_EEPROM = 0x400; |
| static const unsigned window_size = 10; |
| static const int serial_number_eeprom_offset = 0x4; |
| static const int serial_number_eeprom_length = 0x4; |
| unsigned old_iodwbsr_bits; |
| unsigned old_iodwbsr1_bits; |
| unsigned old_iodwcr1_bits; |
| int i; |
| |
| old_iodwbsr_bits = readl(devpriv->mite->mite_io_addr + MITE_IODWBSR); |
| old_iodwbsr1_bits = readl(devpriv->mite->mite_io_addr + MITE_IODWBSR_1); |
| old_iodwcr1_bits = readl(devpriv->mite->mite_io_addr + MITE_IODWCR_1); |
| writel(0x0, devpriv->mite->mite_io_addr + MITE_IODWBSR); |
| writel(((0x80 | window_size) | devpriv->mite->daq_phys_addr), |
| devpriv->mite->mite_io_addr + MITE_IODWBSR_1); |
| writel(0x1 | old_iodwcr1_bits, |
| devpriv->mite->mite_io_addr + MITE_IODWCR_1); |
| writel(0xf, devpriv->mite->mite_io_addr + 0x30); |
| |
| BUG_ON(serial_number_eeprom_length > sizeof(devpriv->serial_number)); |
| for (i = 0; i < serial_number_eeprom_length; ++i) { |
| char *byte_ptr = (char *)&devpriv->serial_number + i; |
| *byte_ptr = ni_readb(serial_number_eeprom_offset + i); |
| } |
| devpriv->serial_number = be32_to_cpu(devpriv->serial_number); |
| |
| for (i = 0; i < M_SERIES_EEPROM_SIZE; ++i) |
| devpriv->eeprom_buffer[i] = ni_readb(Start_Cal_EEPROM + i); |
| |
| writel(old_iodwbsr1_bits, devpriv->mite->mite_io_addr + MITE_IODWBSR_1); |
| writel(old_iodwbsr_bits, devpriv->mite->mite_io_addr + MITE_IODWBSR); |
| writel(old_iodwcr1_bits, devpriv->mite->mite_io_addr + MITE_IODWCR_1); |
| writel(0x0, devpriv->mite->mite_io_addr + 0x30); |
| } |
| |
| static void init_6143(struct comedi_device *dev) |
| { |
| /* Disable interrupts */ |
| devpriv->stc_writew(dev, 0, Interrupt_Control_Register); |
| |
| /* Initialise 6143 AI specific bits */ |
| ni_writeb(0x00, Magic_6143); /* Set G0,G1 DMA mode to E series version */ |
| ni_writeb(0x80, PipelineDelay_6143); /* Set EOCMode, ADCMode and pipelinedelay */ |
| ni_writeb(0x00, EOC_Set_6143); /* Set EOC Delay */ |
| |
| ni_writel(boardtype.ai_fifo_depth / 2, AIFIFO_Flag_6143); /* Set the FIFO half full level */ |
| |
| /* Strobe Relay disable bit */ |
| devpriv->ai_calib_source_enabled = 0; |
| ni_writew(devpriv->ai_calib_source | Calibration_Channel_6143_RelayOff, |
| Calibration_Channel_6143); |
| ni_writew(devpriv->ai_calib_source, Calibration_Channel_6143); |
| } |
| |
| static void pcimio_detach(struct comedi_device *dev) |
| { |
| mio_common_detach(dev); |
| if (dev->irq) |
| free_irq(dev->irq, dev); |
| if (dev->private) { |
| mite_free_ring(devpriv->ai_mite_ring); |
| mite_free_ring(devpriv->ao_mite_ring); |
| mite_free_ring(devpriv->cdo_mite_ring); |
| mite_free_ring(devpriv->gpct_mite_ring[0]); |
| mite_free_ring(devpriv->gpct_mite_ring[1]); |
| if (devpriv->mite) { |
| mite_unsetup(devpriv->mite); |
| mite_free(devpriv->mite); |
| } |
| } |
| } |
| |
| static const struct ni_board_struct * |
| pcimio_find_boardinfo(struct pci_dev *pcidev) |
| { |
| unsigned int device_id = pcidev->device; |
| unsigned int n; |
| |
| for (n = 0; n < ARRAY_SIZE(ni_boards); n++) { |
| const struct ni_board_struct *board = &ni_boards[n]; |
| if (board->device_id == device_id) |
| return board; |
| } |
| return NULL; |
| } |
| |
| static int __devinit pcimio_attach_pci(struct comedi_device *dev, |
| struct pci_dev *pcidev) |
| { |
| int ret; |
| |
| dev_info(dev->class_dev, "ni_pcimio: attach %s\n", pci_name(pcidev)); |
| |
| ret = ni_alloc_private(dev); |
| if (ret < 0) |
| return ret; |
| |
| dev->board_ptr = pcimio_find_boardinfo(pcidev); |
| if (!dev->board_ptr) |
| return -ENODEV; |
| |
| devpriv->mite = mite_alloc(pcidev); |
| if (!devpriv->mite) |
| return -ENOMEM; |
| |
| dev_dbg(dev->class_dev, "%s\n", boardtype.name); |
| dev->board_name = boardtype.name; |
| |
| if (boardtype.reg_type & ni_reg_m_series_mask) { |
| devpriv->stc_writew = &m_series_stc_writew; |
| devpriv->stc_readw = &m_series_stc_readw; |
| devpriv->stc_writel = &m_series_stc_writel; |
| devpriv->stc_readl = &m_series_stc_readl; |
| } else { |
| devpriv->stc_writew = &e_series_win_out; |
| devpriv->stc_readw = &e_series_win_in; |
| devpriv->stc_writel = &win_out2; |
| devpriv->stc_readl = &win_in2; |
| } |
| |
| ret = mite_setup(devpriv->mite); |
| if (ret < 0) { |
| pr_warn("error setting up mite\n"); |
| return ret; |
| } |
| comedi_set_hw_dev(dev, &devpriv->mite->pcidev->dev); |
| devpriv->ai_mite_ring = mite_alloc_ring(devpriv->mite); |
| if (devpriv->ai_mite_ring == NULL) |
| return -ENOMEM; |
| devpriv->ao_mite_ring = mite_alloc_ring(devpriv->mite); |
| if (devpriv->ao_mite_ring == NULL) |
| return -ENOMEM; |
| devpriv->cdo_mite_ring = mite_alloc_ring(devpriv->mite); |
| if (devpriv->cdo_mite_ring == NULL) |
| return -ENOMEM; |
| devpriv->gpct_mite_ring[0] = mite_alloc_ring(devpriv->mite); |
| if (devpriv->gpct_mite_ring[0] == NULL) |
| return -ENOMEM; |
| devpriv->gpct_mite_ring[1] = mite_alloc_ring(devpriv->mite); |
| if (devpriv->gpct_mite_ring[1] == NULL) |
| return -ENOMEM; |
| |
| if (boardtype.reg_type & ni_reg_m_series_mask) |
| m_series_init_eeprom_buffer(dev); |
| if (boardtype.reg_type == ni_reg_6143) |
| init_6143(dev); |
| |
| dev->irq = mite_irq(devpriv->mite); |
| |
| if (dev->irq == 0) { |
| pr_warn("unknown irq (bad)\n"); |
| } else { |
| pr_debug("( irq = %u )\n", dev->irq); |
| ret = request_irq(dev->irq, ni_E_interrupt, NI_E_IRQ_FLAGS, |
| DRV_NAME, dev); |
| if (ret < 0) { |
| pr_warn("irq not available\n"); |
| dev->irq = 0; |
| } |
| } |
| |
| ret = ni_E_init(dev); |
| if (ret < 0) |
| return ret; |
| |
| dev->subdevices[NI_AI_SUBDEV].buf_change = &pcimio_ai_change; |
| dev->subdevices[NI_AO_SUBDEV].buf_change = &pcimio_ao_change; |
| dev->subdevices[NI_GPCT_SUBDEV(0)].buf_change = &pcimio_gpct0_change; |
| dev->subdevices[NI_GPCT_SUBDEV(1)].buf_change = &pcimio_gpct1_change; |
| dev->subdevices[NI_DIO_SUBDEV].buf_change = &pcimio_dio_change; |
| |
| return ret; |
| } |
| |
| static int pcimio_ai_change(struct comedi_device *dev, |
| struct comedi_subdevice *s, unsigned long new_size) |
| { |
| int ret; |
| |
| ret = mite_buf_change(devpriv->ai_mite_ring, s->async); |
| if (ret < 0) |
| return ret; |
| |
| return 0; |
| } |
| |
| static int pcimio_ao_change(struct comedi_device *dev, |
| struct comedi_subdevice *s, unsigned long new_size) |
| { |
| int ret; |
| |
| ret = mite_buf_change(devpriv->ao_mite_ring, s->async); |
| if (ret < 0) |
| return ret; |
| |
| return 0; |
| } |
| |
| static int pcimio_gpct0_change(struct comedi_device *dev, |
| struct comedi_subdevice *s, |
| unsigned long new_size) |
| { |
| int ret; |
| |
| ret = mite_buf_change(devpriv->gpct_mite_ring[0], s->async); |
| if (ret < 0) |
| return ret; |
| |
| return 0; |
| } |
| |
| static int pcimio_gpct1_change(struct comedi_device *dev, |
| struct comedi_subdevice *s, |
| unsigned long new_size) |
| { |
| int ret; |
| |
| ret = mite_buf_change(devpriv->gpct_mite_ring[1], s->async); |
| if (ret < 0) |
| return ret; |
| |
| return 0; |
| } |
| |
| static int pcimio_dio_change(struct comedi_device *dev, |
| struct comedi_subdevice *s, unsigned long new_size) |
| { |
| int ret; |
| |
| ret = mite_buf_change(devpriv->cdo_mite_ring, s->async); |
| if (ret < 0) |
| return ret; |
| |
| return 0; |
| } |
| |
| static struct comedi_driver ni_pcimio_driver = { |
| .driver_name = "ni_pcimio", |
| .module = THIS_MODULE, |
| .attach_pci = pcimio_attach_pci, |
| .detach = pcimio_detach, |
| }; |
| |
| static int __devinit ni_pcimio_pci_probe(struct pci_dev *dev, |
| const struct pci_device_id *ent) |
| { |
| return comedi_pci_auto_config(dev, &ni_pcimio_driver); |
| } |
| |
| static void __devexit ni_pcimio_pci_remove(struct pci_dev *dev) |
| { |
| comedi_pci_auto_unconfig(dev); |
| } |
| |
| static DEFINE_PCI_DEVICE_TABLE(ni_pcimio_pci_table) = { |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0162) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1170) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1180) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1190) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11b0) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11c0) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11d0) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1270) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1330) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1340) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1350) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x14e0) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x14f0) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1580) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x15b0) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1880) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1870) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x18b0) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x18c0) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2410) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2420) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2430) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2890) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x28c0) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a60) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a70) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a80) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2ab0) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b80) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b90) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2c80) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2ca0) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70aa) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70ab) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70ac) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70af) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b0) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b4) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b6) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b7) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b8) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bc) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bd) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bf) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70c0) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70f2) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x710d) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x716c) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x716d) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717f) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x71bc) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717d) }, |
| { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x72e8) }, |
| { 0 } |
| }; |
| MODULE_DEVICE_TABLE(pci, ni_pcimio_pci_table); |
| |
| static struct pci_driver ni_pcimio_pci_driver = { |
| .name = "ni_pcimio", |
| .id_table = ni_pcimio_pci_table, |
| .probe = ni_pcimio_pci_probe, |
| .remove = __devexit_p(ni_pcimio_pci_remove) |
| }; |
| module_comedi_pci_driver(ni_pcimio_driver, ni_pcimio_pci_driver); |
| |
| MODULE_AUTHOR("Comedi http://www.comedi.org"); |
| MODULE_DESCRIPTION("Comedi low-level driver"); |
| MODULE_LICENSE("GPL"); |