Contributors: 17
Author Tokens Token Proportion Commits Commit Proportion
David A. Schleef 3703 54.42% 3 3.57%
H Hartley Sweeten 2046 30.07% 42 50.00%
Ian Abbott 685 10.07% 12 14.29%
Spencer E. Olson 189 2.78% 2 2.38%
Frank Mori Hess 66 0.97% 2 2.38%
Bill Pemberton 34 0.50% 8 9.52%
Greg Kroah-Hartman 33 0.48% 4 4.76%
Arun Thomas 17 0.25% 2 2.38%
Éric Piel 8 0.12% 1 1.19%
Jingoo Han 6 0.09% 1 1.19%
Nikita Eshkeev 4 0.06% 1 1.19%
Calin A. Culianu 4 0.06% 1 1.19%
Anders Blomdell 3 0.04% 1 1.19%
Ravishankar Karkala Mallikarjunayya 2 0.03% 1 1.19%
Peter Hüwe 2 0.03% 1 1.19%
Eric Yu 2 0.03% 1 1.19%
Alexander A. Klimov 1 0.01% 1 1.19%
Total 6805 84

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475
// SPDX-License-Identifier: GPL-2.0+
/*
 * Comedi 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>
 */

/*
 * 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, PXI-6220,
 *   PCI-6221, PXI-6221, PCI-6224, PXI-6224, PCI-6225, PXI-6225,
 *   PCI-6229, PXI-6229, PCI-6250, PXI-6250, PCI-6251, PXI-6251,
 *   PCIe-6251, PXIe-6251, PCI-6254, PXI-6254, PCI-6259, PXI-6259,
 *   PCIe-6259, PXIe-6259, PCI-6280, PXI-6280, PCI-6281, PXI-6281,
 *   PCI-6284, PXI-6284, PCI-6289, PXI-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, 16 Jan 2017 12:56:04 +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 <linux/module.h>
#include <linux/delay.h>
#include <linux/comedi/comedi_pci.h>
#include <asm/byteorder.h>

#include "ni_stc.h"
#include "mite.h"

#define PCIDMA

/*
 * 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, {
		BIP_RANGE(10),
		BIP_RANGE(5),
		BIP_RANGE(2),
		BIP_RANGE(1),
		RANGE(-5, 15),
		UNI_RANGE(10),
		RANGE(3, 7),
		RANGE(4, 6),
		RANGE_ext(-1, 1)
	}
};

static const struct comedi_lrange range_ni_M_625x_ao = {
	3, {
		BIP_RANGE(10),
		BIP_RANGE(5),
		RANGE_ext(-1, 1)
	}
};

enum ni_pcimio_boardid {
	BOARD_PCIMIO_16XE_50,
	BOARD_PCIMIO_16XE_10,
	BOARD_PCI6014,
	BOARD_PXI6030E,
	BOARD_PCIMIO_16E_1,
	BOARD_PCIMIO_16E_4,
	BOARD_PXI6040E,
	BOARD_PCI6031E,
	BOARD_PCI6032E,
	BOARD_PCI6033E,
	BOARD_PCI6071E,
	BOARD_PCI6023E,
	BOARD_PCI6024E,
	BOARD_PCI6025E,
	BOARD_PXI6025E,
	BOARD_PCI6034E,
	BOARD_PCI6035E,
	BOARD_PCI6052E,
	BOARD_PCI6110,
	BOARD_PCI6111,
	/* BOARD_PCI6115, */
	/* BOARD_PXI6115, */
	BOARD_PCI6711,
	BOARD_PXI6711,
	BOARD_PCI6713,
	BOARD_PXI6713,
	BOARD_PCI6731,
	/* BOARD_PXI6731, */
	BOARD_PCI6733,
	BOARD_PXI6733,
	BOARD_PXI6071E,
	BOARD_PXI6070E,
	BOARD_PXI6052E,
	BOARD_PXI6031E,
	BOARD_PCI6036E,
	BOARD_PCI6220,
	BOARD_PXI6220,
	BOARD_PCI6221,
	BOARD_PCI6221_37PIN,
	BOARD_PXI6221,
	BOARD_PCI6224,
	BOARD_PXI6224,
	BOARD_PCI6225,
	BOARD_PXI6225,
	BOARD_PCI6229,
	BOARD_PXI6229,
	BOARD_PCI6250,
	BOARD_PXI6250,
	BOARD_PCI6251,
	BOARD_PXI6251,
	BOARD_PCIE6251,
	BOARD_PXIE6251,
	BOARD_PCI6254,
	BOARD_PXI6254,
	BOARD_PCI6259,
	BOARD_PXI6259,
	BOARD_PCIE6259,
	BOARD_PXIE6259,
	BOARD_PCI6280,
	BOARD_PXI6280,
	BOARD_PCI6281,
	BOARD_PXI6281,
	BOARD_PCI6284,
	BOARD_PXI6284,
	BOARD_PCI6289,
	BOARD_PXI6289,
	BOARD_PCI6143,
	BOARD_PXI6143,
};

static const struct ni_board_struct ni_boards[] = {
	[BOARD_PCIMIO_16XE_50] = {
		.name		= "pci-mio-16xe-50",
		.n_adchan	= 16,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 2048,
		.alwaysdither	= 1,
		.gainlkup	= ai_gain_8,
		.ai_speed	= 50000,
		.n_aochan	= 2,
		.ao_maxdata	= 0x0fff,
		.ao_range_table	= &range_bipolar10,
		.ao_speed	= 50000,
		.caldac		= { dac8800, dac8043 },
	},
	[BOARD_PCIMIO_16XE_10] = {
		.name		= "pci-mio-16xe-10",	/*  aka pci-6030E */
		.n_adchan	= 16,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 512,
		.alwaysdither	= 1,
		.gainlkup	= ai_gain_14,
		.ai_speed	= 10000,
		.n_aochan	= 2,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 2048,
		.ao_range_table	= &range_ni_E_ao_ext,
		.ao_speed	= 10000,
		.caldac		= { dac8800, dac8043, ad8522 },
	},
	[BOARD_PCI6014] = {
		.name		= "pci-6014",
		.n_adchan	= 16,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 512,
		.alwaysdither	= 1,
		.gainlkup	= ai_gain_4,
		.ai_speed	= 5000,
		.n_aochan	= 2,
		.ao_maxdata	= 0xffff,
		.ao_range_table	= &range_bipolar10,
		.ao_speed	= 100000,
		.caldac		= { ad8804_debug },
	},
	[BOARD_PXI6030E] = {
		.name		= "pxi-6030e",
		.n_adchan	= 16,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 512,
		.alwaysdither	= 1,
		.gainlkup	= ai_gain_14,
		.ai_speed	= 10000,
		.n_aochan	= 2,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 2048,
		.ao_range_table	= &range_ni_E_ao_ext,
		.ao_speed	= 10000,
		.caldac		= { dac8800, dac8043, ad8522 },
	},
	[BOARD_PCIMIO_16E_1] = {
		.name		= "pci-mio-16e-1",	/* aka pci-6070e */
		.n_adchan	= 16,
		.ai_maxdata	= 0x0fff,
		.ai_fifo_depth	= 512,
		.gainlkup	= ai_gain_16,
		.ai_speed	= 800,
		.n_aochan	= 2,
		.ao_maxdata	= 0x0fff,
		.ao_fifo_depth	= 2048,
		.ao_range_table	= &range_ni_E_ao_ext,
		.ao_speed	= 1000,
		.caldac		= { mb88341 },
	},
	[BOARD_PCIMIO_16E_4] = {
		.name		= "pci-mio-16e-4",	/* aka pci-6040e */
		.n_adchan	= 16,
		.ai_maxdata	= 0x0fff,
		.ai_fifo_depth	= 512,
		.gainlkup	= ai_gain_16,
		/*
		 * there have been reported problems with
		 * full speed on this board
		 */
		.ai_speed	= 2000,
		.n_aochan	= 2,
		.ao_maxdata	= 0x0fff,
		.ao_fifo_depth	= 512,
		.ao_range_table	= &range_ni_E_ao_ext,
		.ao_speed	= 1000,
		.caldac		= { ad8804_debug },	/* doc says mb88341 */
	},
	[BOARD_PXI6040E] = {
		.name		= "pxi-6040e",
		.n_adchan	= 16,
		.ai_maxdata	= 0x0fff,
		.ai_fifo_depth	= 512,
		.gainlkup	= ai_gain_16,
		.ai_speed	= 2000,
		.n_aochan	= 2,
		.ao_maxdata	= 0x0fff,
		.ao_fifo_depth	= 512,
		.ao_range_table	= &range_ni_E_ao_ext,
		.ao_speed	= 1000,
		.caldac		= { mb88341 },
	},
	[BOARD_PCI6031E] = {
		.name		= "pci-6031e",
		.n_adchan	= 64,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 512,
		.alwaysdither	= 1,
		.gainlkup	= ai_gain_14,
		.ai_speed	= 10000,
		.n_aochan	= 2,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 2048,
		.ao_range_table	= &range_ni_E_ao_ext,
		.ao_speed	= 10000,
		.caldac		= { dac8800, dac8043, ad8522 },
	},
	[BOARD_PCI6032E] = {
		.name		= "pci-6032e",
		.n_adchan	= 16,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 512,
		.alwaysdither	= 1,
		.gainlkup	= ai_gain_14,
		.ai_speed	= 10000,
		.caldac		= { dac8800, dac8043, ad8522 },
	},
	[BOARD_PCI6033E] = {
		.name		= "pci-6033e",
		.n_adchan	= 64,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 512,
		.alwaysdither	= 1,
		.gainlkup	= ai_gain_14,
		.ai_speed	= 10000,
		.caldac		= { dac8800, dac8043, ad8522 },
	},
	[BOARD_PCI6071E] = {
		.name		= "pci-6071e",
		.n_adchan	= 64,
		.ai_maxdata	= 0x0fff,
		.ai_fifo_depth	= 512,
		.alwaysdither	= 1,
		.gainlkup	= ai_gain_16,
		.ai_speed	= 800,
		.n_aochan	= 2,
		.ao_maxdata	= 0x0fff,
		.ao_fifo_depth	= 2048,
		.ao_range_table	= &range_ni_E_ao_ext,
		.ao_speed	= 1000,
		.caldac		= { ad8804_debug },
	},
	[BOARD_PCI6023E] = {
		.name		= "pci-6023e",
		.n_adchan	= 16,
		.ai_maxdata	= 0x0fff,
		.ai_fifo_depth	= 512,
		.gainlkup	= ai_gain_4,
		.ai_speed	= 5000,
		.caldac		= { ad8804_debug },	/* manual is wrong */
	},
	[BOARD_PCI6024E] = {
		.name		= "pci-6024e",
		.n_adchan	= 16,
		.ai_maxdata	= 0x0fff,
		.ai_fifo_depth	= 512,
		.gainlkup	= ai_gain_4,
		.ai_speed	= 5000,
		.n_aochan	= 2,
		.ao_maxdata	= 0x0fff,
		.ao_range_table	= &range_bipolar10,
		.ao_speed	= 100000,
		.caldac		= { ad8804_debug },	/* manual is wrong */
	},
	[BOARD_PCI6025E] = {
		.name		= "pci-6025e",
		.n_adchan	= 16,
		.ai_maxdata	= 0x0fff,
		.ai_fifo_depth	= 512,
		.gainlkup	= ai_gain_4,
		.ai_speed	= 5000,
		.n_aochan	= 2,
		.ao_maxdata	= 0x0fff,
		.ao_range_table	= &range_bipolar10,
		.ao_speed	= 100000,
		.caldac		= { ad8804_debug },	/* manual is wrong */
		.has_8255	= 1,
	},
	[BOARD_PXI6025E] = {
		.name		= "pxi-6025e",
		.n_adchan	= 16,
		.ai_maxdata	= 0x0fff,
		.ai_fifo_depth	= 512,
		.gainlkup	= ai_gain_4,
		.ai_speed	= 5000,
		.n_aochan	= 2,
		.ao_maxdata	= 0x0fff,
		.ao_range_table	= &range_ni_E_ao_ext,
		.ao_speed	= 100000,
		.caldac		= { ad8804_debug },	/* manual is wrong */
		.has_8255	= 1,
	},
	[BOARD_PCI6034E] = {
		.name		= "pci-6034e",
		.n_adchan	= 16,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 512,
		.alwaysdither	= 1,
		.gainlkup	= ai_gain_4,
		.ai_speed	= 5000,
		.caldac		= { ad8804_debug },
	},
	[BOARD_PCI6035E] = {
		.name		= "pci-6035e",
		.n_adchan	= 16,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 512,
		.alwaysdither	= 1,
		.gainlkup	= ai_gain_4,
		.ai_speed	= 5000,
		.n_aochan	= 2,
		.ao_maxdata	= 0x0fff,
		.ao_range_table	= &range_bipolar10,
		.ao_speed	= 100000,
		.caldac		= { ad8804_debug },
	},
	[BOARD_PCI6052E] = {
		.name		= "pci-6052e",
		.n_adchan	= 16,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 512,
		.alwaysdither	= 1,
		.gainlkup	= ai_gain_16,
		.ai_speed	= 3000,
		.n_aochan	= 2,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 2048,
		.ao_range_table	= &range_ni_E_ao_ext,
		.ao_speed	= 3000,
		/* manual is wrong */
		.caldac		= { ad8804_debug, ad8804_debug, ad8522 },
	},
	[BOARD_PCI6110] = {
		.name		= "pci-6110",
		.n_adchan	= 4,
		.ai_maxdata	= 0x0fff,
		.ai_fifo_depth	= 8192,
		.alwaysdither	= 0,
		.gainlkup	= ai_gain_611x,
		.ai_speed	= 200,
		.n_aochan	= 2,
		.ao_maxdata	= 0xffff,
		.reg_type	= ni_reg_611x,
		.ao_range_table	= &range_bipolar10,
		.ao_fifo_depth	= 2048,
		.ao_speed	= 250,
		.caldac		= { ad8804, ad8804 },
	},
	[BOARD_PCI6111] = {
		.name		= "pci-6111",
		.n_adchan	= 2,
		.ai_maxdata	= 0x0fff,
		.ai_fifo_depth	= 8192,
		.gainlkup	= ai_gain_611x,
		.ai_speed	= 200,
		.n_aochan	= 2,
		.ao_maxdata	= 0xffff,
		.reg_type	= ni_reg_611x,
		.ao_range_table	= &range_bipolar10,
		.ao_fifo_depth	= 2048,
		.ao_speed	= 250,
		.caldac		= { ad8804, ad8804 },
	},
#if 0
	/* The 6115 boards probably need their own driver */
	[BOARD_PCI6115] = {	/* .device_id = 0x2ed0, */
		.name		= "pci-6115",
		.n_adchan	= 4,
		.ai_maxdata	= 0x0fff,
		.ai_fifo_depth	= 8192,
		.gainlkup	= ai_gain_611x,
		.ai_speed	= 100,
		.n_aochan	= 2,
		.ao_maxdata	= 0xffff,
		.ao_671x	= 1,
		.ao_fifo_depth	= 2048,
		.ao_speed	= 250,
		.reg_611x	= 1,
		/* XXX */
		.caldac		= { ad8804_debug, ad8804_debug, ad8804_debug },
	},
#endif
#if 0
	[BOARD_PXI6115] = {	/* .device_id = ????, */
		.name		= "pxi-6115",
		.n_adchan	= 4,
		.ai_maxdata	= 0x0fff,
		.ai_fifo_depth	= 8192,
		.gainlkup	= ai_gain_611x,
		.ai_speed	= 100,
		.n_aochan	= 2,
		.ao_maxdata	= 0xffff,
		.ao_671x	= 1,
		.ao_fifo_depth	= 2048,
		.ao_speed	= 250,
		.reg_611x	= 1,
		/* XXX */
		.caldac		= { ad8804_debug, ad8804_debug, ad8804_debug },
	},
#endif
	[BOARD_PCI6711] = {
		.name = "pci-6711",
		.n_aochan	= 4,
		.ao_maxdata	= 0x0fff,
		/* data sheet says 8192, but fifo really holds 16384 samples */
		.ao_fifo_depth	= 16384,
		.ao_range_table	= &range_bipolar10,
		.ao_speed	= 1000,
		.reg_type	= ni_reg_6711,
		.caldac		= { ad8804_debug },
	},
	[BOARD_PXI6711] = {
		.name		= "pxi-6711",
		.n_aochan	= 4,
		.ao_maxdata	= 0x0fff,
		.ao_fifo_depth	= 16384,
		.ao_range_table	= &range_bipolar10,
		.ao_speed	= 1000,
		.reg_type	= ni_reg_6711,
		.caldac		= { ad8804_debug },
	},
	[BOARD_PCI6713] = {
		.name		= "pci-6713",
		.n_aochan	= 8,
		.ao_maxdata	= 0x0fff,
		.ao_fifo_depth	= 16384,
		.ao_range_table	= &range_bipolar10,
		.ao_speed	= 1000,
		.reg_type	= ni_reg_6713,
		.caldac		= { ad8804_debug, ad8804_debug },
	},
	[BOARD_PXI6713] = {
		.name		= "pxi-6713",
		.n_aochan	= 8,
		.ao_maxdata	= 0x0fff,
		.ao_fifo_depth	= 16384,
		.ao_range_table	= &range_bipolar10,
		.ao_speed	= 1000,
		.reg_type	= ni_reg_6713,
		.caldac		= { ad8804_debug, ad8804_debug },
	},
	[BOARD_PCI6731] = {
		.name		= "pci-6731",
		.n_aochan	= 4,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 8192,
		.ao_range_table	= &range_bipolar10,
		.ao_speed	= 1000,
		.reg_type	= ni_reg_6711,
		.caldac		= { ad8804_debug },
	},
#if 0
	[BOARD_PXI6731] = {	/* .device_id = ????, */
		.name		= "pxi-6731",
		.n_aochan	= 4,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 8192,
		.ao_range_table	= &range_bipolar10,
		.reg_type	= ni_reg_6711,
		.caldac		= { ad8804_debug },
	},
#endif
	[BOARD_PCI6733] = {
		.name		= "pci-6733",
		.n_aochan	= 8,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 16384,
		.ao_range_table	= &range_bipolar10,
		.ao_speed	= 1000,
		.reg_type	= ni_reg_6713,
		.caldac		= { ad8804_debug, ad8804_debug },
	},
	[BOARD_PXI6733] = {
		.name		= "pxi-6733",
		.n_aochan	= 8,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 16384,
		.ao_range_table	= &range_bipolar10,
		.ao_speed	= 1000,
		.reg_type	= ni_reg_6713,
		.caldac		= { ad8804_debug, ad8804_debug },
	},
	[BOARD_PXI6071E] = {
		.name		= "pxi-6071e",
		.n_adchan	= 64,
		.ai_maxdata	= 0x0fff,
		.ai_fifo_depth	= 512,
		.alwaysdither	= 1,
		.gainlkup	= ai_gain_16,
		.ai_speed	= 800,
		.n_aochan	= 2,
		.ao_maxdata	= 0x0fff,
		.ao_fifo_depth	= 2048,
		.ao_range_table	= &range_ni_E_ao_ext,
		.ao_speed	= 1000,
		.caldac		= { ad8804_debug },
	},
	[BOARD_PXI6070E] = {
		.name		= "pxi-6070e",
		.n_adchan	= 16,
		.ai_maxdata	= 0x0fff,
		.ai_fifo_depth	= 512,
		.alwaysdither	= 1,
		.gainlkup	= ai_gain_16,
		.ai_speed	= 800,
		.n_aochan	= 2,
		.ao_maxdata	= 0x0fff,
		.ao_fifo_depth	= 2048,
		.ao_range_table	= &range_ni_E_ao_ext,
		.ao_speed	= 1000,
		.caldac		= { ad8804_debug },
	},
	[BOARD_PXI6052E] = {
		.name		= "pxi-6052e",
		.n_adchan	= 16,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 512,
		.alwaysdither	= 1,
		.gainlkup	= ai_gain_16,
		.ai_speed	= 3000,
		.n_aochan	= 2,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 2048,
		.ao_range_table	= &range_ni_E_ao_ext,
		.ao_speed	= 3000,
		.caldac		= { mb88341, mb88341, ad8522 },
	},
	[BOARD_PXI6031E] = {
		.name		= "pxi-6031e",
		.n_adchan	= 64,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 512,
		.alwaysdither	= 1,
		.gainlkup	= ai_gain_14,
		.ai_speed	= 10000,
		.n_aochan	= 2,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 2048,
		.ao_range_table	= &range_ni_E_ao_ext,
		.ao_speed	= 10000,
		.caldac		= { dac8800, dac8043, ad8522 },
	},
	[BOARD_PCI6036E] = {
		.name = "pci-6036e",
		.n_adchan	= 16,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 512,
		.alwaysdither	= 1,
		.gainlkup	= ai_gain_4,
		.ai_speed	= 5000,
		.n_aochan	= 2,
		.ao_maxdata	= 0xffff,
		.ao_range_table	= &range_bipolar10,
		.ao_speed	= 100000,
		.caldac		= { ad8804_debug },
	},
	[BOARD_PCI6220] = {
		.name		= "pci-6220",
		.n_adchan	= 16,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 512,		/* FIXME: guess */
		.gainlkup	= ai_gain_622x,
		.ai_speed	= 4000,
		.reg_type	= ni_reg_622x,
		.caldac		= { caldac_none },
	},
	[BOARD_PXI6220] = {
		.name		= "pxi-6220",
		.n_adchan	= 16,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 512,		/* FIXME: guess */
		.gainlkup	= ai_gain_622x,
		.ai_speed	= 4000,
		.reg_type	= ni_reg_622x,
		.caldac		= { caldac_none },
		.dio_speed	= 1000,
	},
	[BOARD_PCI6221] = {
		.name		= "pci-6221",
		.n_adchan	= 16,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 4095,
		.gainlkup	= ai_gain_622x,
		.ai_speed	= 4000,
		.n_aochan	= 2,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 8191,
		.ao_range_table	= &range_bipolar10,
		.reg_type	= ni_reg_622x,
		.ao_speed	= 1200,
		.caldac		= { caldac_none },
		.dio_speed	= 1000,
	},
	[BOARD_PCI6221_37PIN] = {
		.name		= "pci-6221_37pin",
		.n_adchan	= 16,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 4095,
		.gainlkup	= ai_gain_622x,
		.ai_speed	= 4000,
		.n_aochan	= 2,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 8191,
		.ao_range_table	= &range_bipolar10,
		.reg_type	= ni_reg_622x,
		.ao_speed	= 1200,
		.caldac		= { caldac_none },
	},
	[BOARD_PXI6221] = {
		.name		= "pxi-6221",
		.n_adchan	= 16,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 4095,
		.gainlkup	= ai_gain_622x,
		.ai_speed	= 4000,
		.n_aochan	= 2,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 8191,
		.ao_range_table	= &range_bipolar10,
		.reg_type	= ni_reg_622x,
		.ao_speed	= 1200,
		.caldac		= { caldac_none },
		.dio_speed	= 1000,
	},
	[BOARD_PCI6224] = {
		.name		= "pci-6224",
		.n_adchan	= 32,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 4095,
		.gainlkup	= ai_gain_622x,
		.ai_speed	= 4000,
		.reg_type	= ni_reg_622x,
		.has_32dio_chan	= 1,
		.caldac		= { caldac_none },
		.dio_speed	= 1000,
	},
	[BOARD_PXI6224] = {
		.name		= "pxi-6224",
		.n_adchan	= 32,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 4095,
		.gainlkup	= ai_gain_622x,
		.ai_speed	= 4000,
		.reg_type	= ni_reg_622x,
		.has_32dio_chan	= 1,
		.caldac		= { caldac_none },
		.dio_speed	= 1000,
	},
	[BOARD_PCI6225] = {
		.name		= "pci-6225",
		.n_adchan	= 80,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 4095,
		.gainlkup	= ai_gain_622x,
		.ai_speed	= 4000,
		.n_aochan	= 2,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 8191,
		.ao_range_table	= &range_bipolar10,
		.reg_type	= ni_reg_622x,
		.ao_speed	= 1200,
		.has_32dio_chan	= 1,
		.caldac		= { caldac_none },
		.dio_speed	= 1000,
	},
	[BOARD_PXI6225] = {
		.name		= "pxi-6225",
		.n_adchan	= 80,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 4095,
		.gainlkup	= ai_gain_622x,
		.ai_speed	= 4000,
		.n_aochan	= 2,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 8191,
		.ao_range_table	= &range_bipolar10,
		.reg_type	= ni_reg_622x,
		.ao_speed	= 1200,
		.has_32dio_chan	= 1,
		.caldac		= { caldac_none },
		.dio_speed	= 1000,
	},
	[BOARD_PCI6229] = {
		.name		= "pci-6229",
		.n_adchan	= 32,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 4095,
		.gainlkup	= ai_gain_622x,
		.ai_speed	= 4000,
		.n_aochan	= 4,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 8191,
		.ao_range_table	= &range_bipolar10,
		.reg_type	= ni_reg_622x,
		.ao_speed	= 1200,
		.has_32dio_chan	= 1,
		.caldac		= { caldac_none },
	},
	[BOARD_PXI6229] = {
		.name		= "pxi-6229",
		.n_adchan	= 32,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 4095,
		.gainlkup	= ai_gain_622x,
		.ai_speed	= 4000,
		.n_aochan	= 4,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 8191,
		.ao_range_table	= &range_bipolar10,
		.reg_type	= ni_reg_622x,
		.ao_speed	= 1200,
		.has_32dio_chan	= 1,
		.caldac		= { caldac_none },
		.dio_speed	= 1000,
	},
	[BOARD_PCI6250] = {
		.name		= "pci-6250",
		.n_adchan	= 16,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 4095,
		.gainlkup	= ai_gain_628x,
		.ai_speed	= 800,
		.reg_type	= ni_reg_625x,
		.caldac		= { caldac_none },
	},
	[BOARD_PXI6250] = {
		.name		= "pxi-6250",
		.n_adchan	= 16,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 4095,
		.gainlkup	= ai_gain_628x,
		.ai_speed	= 800,
		.reg_type	= ni_reg_625x,
		.caldac		= { caldac_none },
		.dio_speed	= 100,
	},
	[BOARD_PCI6251] = {
		.name		= "pci-6251",
		.n_adchan	= 16,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 4095,
		.gainlkup	= ai_gain_628x,
		.ai_speed	= 800,
		.n_aochan	= 2,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 8191,
		.ao_range_table	= &range_ni_M_625x_ao,
		.reg_type	= ni_reg_625x,
		.ao_speed	= 350,
		.caldac		= { caldac_none },
		.dio_speed	= 100,
	},
	[BOARD_PXI6251] = {
		.name		= "pxi-6251",
		.n_adchan	= 16,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 4095,
		.gainlkup	= ai_gain_628x,
		.ai_speed	= 800,
		.n_aochan	= 2,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 8191,
		.ao_range_table	= &range_ni_M_625x_ao,
		.reg_type	= ni_reg_625x,
		.ao_speed	= 350,
		.caldac		= { caldac_none },
		.dio_speed	= 100,
	},
	[BOARD_PCIE6251] = {
		.name		= "pcie-6251",
		.alt_route_name	= "pci-6251",
		.n_adchan	= 16,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 4095,
		.gainlkup	= ai_gain_628x,
		.ai_speed	= 800,
		.n_aochan	= 2,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 8191,
		.ao_range_table	= &range_ni_M_625x_ao,
		.reg_type	= ni_reg_625x,
		.ao_speed	= 350,
		.caldac		= { caldac_none },
		.dio_speed	= 100,
	},
	[BOARD_PXIE6251] = {
		.name		= "pxie-6251",
		.n_adchan	= 16,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 4095,
		.gainlkup	= ai_gain_628x,
		.ai_speed	= 800,
		.n_aochan	= 2,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 8191,
		.ao_range_table	= &range_ni_M_625x_ao,
		.reg_type	= ni_reg_625x,
		.ao_speed	= 350,
		.caldac		= { caldac_none },
		.dio_speed	= 100,
	},
	[BOARD_PCI6254] = {
		.name		= "pci-6254",
		.n_adchan	= 32,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 4095,
		.gainlkup	= ai_gain_628x,
		.ai_speed	= 800,
		.reg_type	= ni_reg_625x,
		.has_32dio_chan	= 1,
		.caldac		= { caldac_none },
	},
	[BOARD_PXI6254] = {
		.name		= "pxi-6254",
		.n_adchan	= 32,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 4095,
		.gainlkup	= ai_gain_628x,
		.ai_speed	= 800,
		.reg_type	= ni_reg_625x,
		.has_32dio_chan	= 1,
		.caldac		= { caldac_none },
		.dio_speed	= 100,
	},
	[BOARD_PCI6259] = {
		.name		= "pci-6259",
		.n_adchan	= 32,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 4095,
		.gainlkup	= ai_gain_628x,
		.ai_speed	= 800,
		.n_aochan	= 4,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 8191,
		.ao_range_table	= &range_ni_M_625x_ao,
		.reg_type	= ni_reg_625x,
		.ao_speed	= 350,
		.has_32dio_chan	= 1,
		.caldac		= { caldac_none },
	},
	[BOARD_PXI6259] = {
		.name		= "pxi-6259",
		.n_adchan	= 32,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 4095,
		.gainlkup	= ai_gain_628x,
		.ai_speed	= 800,
		.n_aochan	= 4,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 8191,
		.ao_range_table	= &range_ni_M_625x_ao,
		.reg_type	= ni_reg_625x,
		.ao_speed	= 350,
		.has_32dio_chan	= 1,
		.caldac		= { caldac_none },
		.dio_speed	= 100,
	},
	[BOARD_PCIE6259] = {
		.name		= "pcie-6259",
		.alt_route_name	= "pci-6259",
		.n_adchan	= 32,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 4095,
		.gainlkup	= ai_gain_628x,
		.ai_speed	= 800,
		.n_aochan	= 4,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 8191,
		.ao_range_table	= &range_ni_M_625x_ao,
		.reg_type	= ni_reg_625x,
		.ao_speed	= 350,
		.has_32dio_chan	= 1,
		.caldac		= { caldac_none },
	},
	[BOARD_PXIE6259] = {
		.name		= "pxie-6259",
		.n_adchan	= 32,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 4095,
		.gainlkup	= ai_gain_628x,
		.ai_speed	= 800,
		.n_aochan	= 4,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 8191,
		.ao_range_table	= &range_ni_M_625x_ao,
		.reg_type	= ni_reg_625x,
		.ao_speed	= 350,
		.has_32dio_chan	= 1,
		.caldac		= { caldac_none },
		.dio_speed	= 100,
	},
	[BOARD_PCI6280] = {
		.name		= "pci-6280",
		.n_adchan	= 16,
		.ai_maxdata	= 0x3ffff,
		.ai_fifo_depth	= 2047,
		.gainlkup	= ai_gain_628x,
		.ai_speed	= 1600,
		.ao_fifo_depth	= 8191,
		.reg_type	= ni_reg_628x,
		.caldac		= { caldac_none },
	},
	[BOARD_PXI6280] = {
		.name		= "pxi-6280",
		.n_adchan	= 16,
		.ai_maxdata	= 0x3ffff,
		.ai_fifo_depth	= 2047,
		.gainlkup	= ai_gain_628x,
		.ai_speed	= 1600,
		.ao_fifo_depth	= 8191,
		.reg_type	= ni_reg_628x,
		.caldac		= { caldac_none },
		.dio_speed	= 100,
	},
	[BOARD_PCI6281] = {
		.name		= "pci-6281",
		.n_adchan	= 16,
		.ai_maxdata	= 0x3ffff,
		.ai_fifo_depth	= 2047,
		.gainlkup	= ai_gain_628x,
		.ai_speed	= 1600,
		.n_aochan	= 2,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 8191,
		.ao_range_table = &range_ni_M_628x_ao,
		.reg_type	= ni_reg_628x,
		.ao_speed	= 350,
		.caldac		= { caldac_none },
		.dio_speed	= 100,
	},
	[BOARD_PXI6281] = {
		.name		= "pxi-6281",
		.n_adchan	= 16,
		.ai_maxdata	= 0x3ffff,
		.ai_fifo_depth	= 2047,
		.gainlkup	= ai_gain_628x,
		.ai_speed	= 1600,
		.n_aochan	= 2,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 8191,
		.ao_range_table	= &range_ni_M_628x_ao,
		.reg_type	= ni_reg_628x,
		.ao_speed	= 350,
		.caldac		= { caldac_none },
		.dio_speed	= 100,
	},
	[BOARD_PCI6284] = {
		.name		= "pci-6284",
		.n_adchan	= 32,
		.ai_maxdata	= 0x3ffff,
		.ai_fifo_depth	= 2047,
		.gainlkup	= ai_gain_628x,
		.ai_speed	= 1600,
		.reg_type	= ni_reg_628x,
		.has_32dio_chan	= 1,
		.caldac		= { caldac_none },
	},
	[BOARD_PXI6284] = {
		.name		= "pxi-6284",
		.n_adchan	= 32,
		.ai_maxdata	= 0x3ffff,
		.ai_fifo_depth	= 2047,
		.gainlkup	= ai_gain_628x,
		.ai_speed	= 1600,
		.reg_type	= ni_reg_628x,
		.has_32dio_chan	= 1,
		.caldac		= { caldac_none },
		.dio_speed	= 100,
	},
	[BOARD_PCI6289] = {
		.name		= "pci-6289",
		.n_adchan	= 32,
		.ai_maxdata	= 0x3ffff,
		.ai_fifo_depth	= 2047,
		.gainlkup	= ai_gain_628x,
		.ai_speed	= 1600,
		.n_aochan	= 4,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 8191,
		.ao_range_table	= &range_ni_M_628x_ao,
		.reg_type	= ni_reg_628x,
		.ao_speed	= 350,
		.has_32dio_chan	= 1,
		.caldac		= { caldac_none },
	},
	[BOARD_PXI6289] = {
		.name		= "pxi-6289",
		.n_adchan	= 32,
		.ai_maxdata	= 0x3ffff,
		.ai_fifo_depth	= 2047,
		.gainlkup	= ai_gain_628x,
		.ai_speed	= 1600,
		.n_aochan	= 4,
		.ao_maxdata	= 0xffff,
		.ao_fifo_depth	= 8191,
		.ao_range_table	= &range_ni_M_628x_ao,
		.reg_type	= ni_reg_628x,
		.ao_speed	= 350,
		.has_32dio_chan	= 1,
		.caldac		= { caldac_none },
		.dio_speed	= 100,
	},
	[BOARD_PCI6143] = {
		.name		= "pci-6143",
		.n_adchan	= 8,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 1024,
		.gainlkup	= ai_gain_6143,
		.ai_speed	= 4000,
		.reg_type	= ni_reg_6143,
		.caldac		= { ad8804_debug, ad8804_debug },
	},
	[BOARD_PXI6143] = {
		.name		= "pxi-6143",
		.n_adchan	= 8,
		.ai_maxdata	= 0xffff,
		.ai_fifo_depth	= 1024,
		.gainlkup	= ai_gain_6143,
		.ai_speed	= 4000,
		.reg_type	= ni_reg_6143,
		.caldac		= { ad8804_debug, ad8804_debug },
	},
};

#include "ni_mio_common.c"

static int pcimio_ai_change(struct comedi_device *dev,
			    struct comedi_subdevice *s)
{
	struct ni_private *devpriv = dev->private;
	int ret;

	ret = mite_buf_change(devpriv->ai_mite_ring, s);
	if (ret < 0)
		return ret;

	return 0;
}

static int pcimio_ao_change(struct comedi_device *dev,
			    struct comedi_subdevice *s)
{
	struct ni_private *devpriv = dev->private;
	int ret;

	ret = mite_buf_change(devpriv->ao_mite_ring, s);
	if (ret < 0)
		return ret;

	return 0;
}

static int pcimio_gpct0_change(struct comedi_device *dev,
			       struct comedi_subdevice *s)
{
	struct ni_private *devpriv = dev->private;
	int ret;

	ret = mite_buf_change(devpriv->gpct_mite_ring[0], s);
	if (ret < 0)
		return ret;

	return 0;
}

static int pcimio_gpct1_change(struct comedi_device *dev,
			       struct comedi_subdevice *s)
{
	struct ni_private *devpriv = dev->private;
	int ret;

	ret = mite_buf_change(devpriv->gpct_mite_ring[1], s);
	if (ret < 0)
		return ret;

	return 0;
}

static int pcimio_dio_change(struct comedi_device *dev,
			     struct comedi_subdevice *s)
{
	struct ni_private *devpriv = dev->private;
	int ret;

	ret = mite_buf_change(devpriv->cdo_mite_ring, s);
	if (ret < 0)
		return ret;

	return 0;
}

static void m_series_init_eeprom_buffer(struct comedi_device *dev)
{
	struct ni_private *devpriv = dev->private;
	struct mite *mite = devpriv->mite;
	resource_size_t daq_phys_addr;
	static const int start_cal_eeprom = 0x400;
	static const unsigned int window_size = 10;
	unsigned int old_iodwbsr_bits;
	unsigned int old_iodwbsr1_bits;
	unsigned int old_iodwcr1_bits;
	int i;

	/* IO Window 1 needs to be temporarily mapped to read the eeprom */
	daq_phys_addr = pci_resource_start(mite->pcidev, 1);

	old_iodwbsr_bits = readl(mite->mmio + MITE_IODWBSR);
	old_iodwbsr1_bits = readl(mite->mmio + MITE_IODWBSR_1);
	old_iodwcr1_bits = readl(mite->mmio + MITE_IODWCR_1);
	writel(0x0, mite->mmio + MITE_IODWBSR);
	writel(((0x80 | window_size) | daq_phys_addr),
	       mite->mmio + MITE_IODWBSR_1);
	writel(0x1 | old_iodwcr1_bits, mite->mmio + MITE_IODWCR_1);
	writel(0xf, mite->mmio + 0x30);

	for (i = 0; i < M_SERIES_EEPROM_SIZE; ++i)
		devpriv->eeprom_buffer[i] = ni_readb(dev, start_cal_eeprom + i);

	writel(old_iodwbsr1_bits, mite->mmio + MITE_IODWBSR_1);
	writel(old_iodwbsr_bits, mite->mmio + MITE_IODWBSR);
	writel(old_iodwcr1_bits, mite->mmio + MITE_IODWCR_1);
	writel(0x0, mite->mmio + 0x30);
}

static void init_6143(struct comedi_device *dev)
{
	const struct ni_board_struct *board = dev->board_ptr;
	struct ni_private *devpriv = dev->private;

	/*  Disable interrupts */
	ni_stc_writew(dev, 0, NISTC_INT_CTRL_REG);

	/*  Initialise 6143 AI specific bits */

	/* Set G0,G1 DMA mode to E series version */
	ni_writeb(dev, 0x00, NI6143_MAGIC_REG);
	/* Set EOCMode, ADCMode and pipelinedelay */
	ni_writeb(dev, 0x80, NI6143_PIPELINE_DELAY_REG);
	/* Set EOC Delay */
	ni_writeb(dev, 0x00, NI6143_EOC_SET_REG);

	/* Set the FIFO half full level */
	ni_writel(dev, board->ai_fifo_depth / 2, NI6143_AI_FIFO_FLAG_REG);

	/*  Strobe Relay disable bit */
	devpriv->ai_calib_source_enabled = 0;
	ni_writew(dev, devpriv->ai_calib_source | NI6143_CALIB_CHAN_RELAY_OFF,
		  NI6143_CALIB_CHAN_REG);
	ni_writew(dev, devpriv->ai_calib_source, NI6143_CALIB_CHAN_REG);
}

static void pcimio_detach(struct comedi_device *dev)
{
	struct ni_private *devpriv = dev->private;

	mio_common_detach(dev);
	if (dev->irq)
		free_irq(dev->irq, dev);
	if (devpriv) {
		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]);
		mite_detach(devpriv->mite);
	}
	if (dev->mmio)
		iounmap(dev->mmio);
	comedi_pci_disable(dev);
}

static int pcimio_auto_attach(struct comedi_device *dev,
			      unsigned long context)
{
	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
	const struct ni_board_struct *board = NULL;
	struct ni_private *devpriv;
	unsigned int irq;
	int ret;

	if (context < ARRAY_SIZE(ni_boards))
		board = &ni_boards[context];
	if (!board)
		return -ENODEV;
	dev->board_ptr = board;
	dev->board_name = board->name;

	ret = comedi_pci_enable(dev);
	if (ret)
		return ret;

	ret = ni_alloc_private(dev);
	if (ret)
		return ret;
	devpriv = dev->private;

	devpriv->mite = mite_attach(dev, false);	/* use win0 */
	if (!devpriv->mite)
		return -ENOMEM;

	if (board->reg_type & ni_reg_m_series_mask)
		devpriv->is_m_series = 1;
	if (board->reg_type & ni_reg_6xxx_mask)
		devpriv->is_6xxx = 1;
	if (board->reg_type == ni_reg_611x)
		devpriv->is_611x = 1;
	if (board->reg_type == ni_reg_6143)
		devpriv->is_6143 = 1;
	if (board->reg_type == ni_reg_622x)
		devpriv->is_622x = 1;
	if (board->reg_type == ni_reg_625x)
		devpriv->is_625x = 1;
	if (board->reg_type == ni_reg_628x)
		devpriv->is_628x = 1;
	if (board->reg_type & ni_reg_67xx_mask)
		devpriv->is_67xx = 1;
	if (board->reg_type == ni_reg_6711)
		devpriv->is_6711 = 1;
	if (board->reg_type == ni_reg_6713)
		devpriv->is_6713 = 1;

	devpriv->ai_mite_ring = mite_alloc_ring(devpriv->mite);
	if (!devpriv->ai_mite_ring)
		return -ENOMEM;
	devpriv->ao_mite_ring = mite_alloc_ring(devpriv->mite);
	if (!devpriv->ao_mite_ring)
		return -ENOMEM;
	devpriv->cdo_mite_ring = mite_alloc_ring(devpriv->mite);
	if (!devpriv->cdo_mite_ring)
		return -ENOMEM;
	devpriv->gpct_mite_ring[0] = mite_alloc_ring(devpriv->mite);
	if (!devpriv->gpct_mite_ring[0])
		return -ENOMEM;
	devpriv->gpct_mite_ring[1] = mite_alloc_ring(devpriv->mite);
	if (!devpriv->gpct_mite_ring[1])
		return -ENOMEM;

	if (devpriv->is_m_series)
		m_series_init_eeprom_buffer(dev);
	if (devpriv->is_6143)
		init_6143(dev);

	irq = pcidev->irq;
	if (irq) {
		ret = request_irq(irq, ni_E_interrupt, IRQF_SHARED,
				  dev->board_name, dev);
		if (ret == 0)
			dev->irq = irq;
	}

	ret = ni_E_init(dev, 0, 1);
	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 0;
}

static struct comedi_driver ni_pcimio_driver = {
	.driver_name	= "ni_pcimio",
	.module		= THIS_MODULE,
	.auto_attach	= pcimio_auto_attach,
	.detach		= pcimio_detach,
};

static int ni_pcimio_pci_probe(struct pci_dev *dev,
			       const struct pci_device_id *id)
{
	return comedi_pci_auto_config(dev, &ni_pcimio_driver, id->driver_data);
}

static const struct pci_device_id ni_pcimio_pci_table[] = {
	{ PCI_VDEVICE(NI, 0x0162), BOARD_PCIMIO_16XE_50 },	/* 0x1620? */
	{ PCI_VDEVICE(NI, 0x1170), BOARD_PCIMIO_16XE_10 },
	{ PCI_VDEVICE(NI, 0x1180), BOARD_PCIMIO_16E_1 },
	{ PCI_VDEVICE(NI, 0x1190), BOARD_PCIMIO_16E_4 },
	{ PCI_VDEVICE(NI, 0x11b0), BOARD_PXI6070E },
	{ PCI_VDEVICE(NI, 0x11c0), BOARD_PXI6040E },
	{ PCI_VDEVICE(NI, 0x11d0), BOARD_PXI6030E },
	{ PCI_VDEVICE(NI, 0x1270), BOARD_PCI6032E },
	{ PCI_VDEVICE(NI, 0x1330), BOARD_PCI6031E },
	{ PCI_VDEVICE(NI, 0x1340), BOARD_PCI6033E },
	{ PCI_VDEVICE(NI, 0x1350), BOARD_PCI6071E },
	{ PCI_VDEVICE(NI, 0x14e0), BOARD_PCI6110 },
	{ PCI_VDEVICE(NI, 0x14f0), BOARD_PCI6111 },
	{ PCI_VDEVICE(NI, 0x1580), BOARD_PXI6031E },
	{ PCI_VDEVICE(NI, 0x15b0), BOARD_PXI6071E },
	{ PCI_VDEVICE(NI, 0x1880), BOARD_PCI6711 },
	{ PCI_VDEVICE(NI, 0x1870), BOARD_PCI6713 },
	{ PCI_VDEVICE(NI, 0x18b0), BOARD_PCI6052E },
	{ PCI_VDEVICE(NI, 0x18c0), BOARD_PXI6052E },
	{ PCI_VDEVICE(NI, 0x2410), BOARD_PCI6733 },
	{ PCI_VDEVICE(NI, 0x2420), BOARD_PXI6733 },
	{ PCI_VDEVICE(NI, 0x2430), BOARD_PCI6731 },
	{ PCI_VDEVICE(NI, 0x2890), BOARD_PCI6036E },
	{ PCI_VDEVICE(NI, 0x28c0), BOARD_PCI6014 },
	{ PCI_VDEVICE(NI, 0x2a60), BOARD_PCI6023E },
	{ PCI_VDEVICE(NI, 0x2a70), BOARD_PCI6024E },
	{ PCI_VDEVICE(NI, 0x2a80), BOARD_PCI6025E },
	{ PCI_VDEVICE(NI, 0x2ab0), BOARD_PXI6025E },
	{ PCI_VDEVICE(NI, 0x2b80), BOARD_PXI6713 },
	{ PCI_VDEVICE(NI, 0x2b90), BOARD_PXI6711 },
	{ PCI_VDEVICE(NI, 0x2c80), BOARD_PCI6035E },
	{ PCI_VDEVICE(NI, 0x2ca0), BOARD_PCI6034E },
	{ PCI_VDEVICE(NI, 0x70aa), BOARD_PCI6229 },
	{ PCI_VDEVICE(NI, 0x70ab), BOARD_PCI6259 },
	{ PCI_VDEVICE(NI, 0x70ac), BOARD_PCI6289 },
	{ PCI_VDEVICE(NI, 0x70ad), BOARD_PXI6251 },
	{ PCI_VDEVICE(NI, 0x70ae), BOARD_PXI6220 },
	{ PCI_VDEVICE(NI, 0x70af), BOARD_PCI6221 },
	{ PCI_VDEVICE(NI, 0x70b0), BOARD_PCI6220 },
	{ PCI_VDEVICE(NI, 0x70b1), BOARD_PXI6229 },
	{ PCI_VDEVICE(NI, 0x70b2), BOARD_PXI6259 },
	{ PCI_VDEVICE(NI, 0x70b3), BOARD_PXI6289 },
	{ PCI_VDEVICE(NI, 0x70b4), BOARD_PCI6250 },
	{ PCI_VDEVICE(NI, 0x70b5), BOARD_PXI6221 },
	{ PCI_VDEVICE(NI, 0x70b6), BOARD_PCI6280 },
	{ PCI_VDEVICE(NI, 0x70b7), BOARD_PCI6254 },
	{ PCI_VDEVICE(NI, 0x70b8), BOARD_PCI6251 },
	{ PCI_VDEVICE(NI, 0x70b9), BOARD_PXI6250 },
	{ PCI_VDEVICE(NI, 0x70ba), BOARD_PXI6254 },
	{ PCI_VDEVICE(NI, 0x70bb), BOARD_PXI6280 },
	{ PCI_VDEVICE(NI, 0x70bc), BOARD_PCI6284 },
	{ PCI_VDEVICE(NI, 0x70bd), BOARD_PCI6281 },
	{ PCI_VDEVICE(NI, 0x70be), BOARD_PXI6284 },
	{ PCI_VDEVICE(NI, 0x70bf), BOARD_PXI6281 },
	{ PCI_VDEVICE(NI, 0x70c0), BOARD_PCI6143 },
	{ PCI_VDEVICE(NI, 0x70f2), BOARD_PCI6224 },
	{ PCI_VDEVICE(NI, 0x70f3), BOARD_PXI6224 },
	{ PCI_VDEVICE(NI, 0x710d), BOARD_PXI6143 },
	{ PCI_VDEVICE(NI, 0x716c), BOARD_PCI6225 },
	{ PCI_VDEVICE(NI, 0x716d), BOARD_PXI6225 },
	{ PCI_VDEVICE(NI, 0x717d), BOARD_PCIE6251 },
	{ PCI_VDEVICE(NI, 0x717f), BOARD_PCIE6259 },
	{ PCI_VDEVICE(NI, 0x71bc), BOARD_PCI6221_37PIN },
	{ PCI_VDEVICE(NI, 0x72e8), BOARD_PXIE6251 },
	{ PCI_VDEVICE(NI, 0x72e9), BOARD_PXIE6259 },
	{ 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		= comedi_pci_auto_unconfig,
};
module_comedi_pci_driver(ni_pcimio_driver, ni_pcimio_pci_driver);

MODULE_AUTHOR("Comedi https://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");