17f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/*
27f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    comedi/drivers/cb_pcimdda.c
37f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    Computer Boards PCIM-DDA06-16 Comedi driver
47f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    Author: Calin Culianu <calin@ajvar.org>
57f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
67f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    COMEDI - Linux Control and Measurement Device Interface
77f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    Copyright (C) 2000 David A. Schleef <ds@schleef.org>
87f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
97f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    This program is free software; you can redistribute it and/or modify
107f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    it under the terms of the GNU General Public License as published by
117f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    the Free Software Foundation; either version 2 of the License, or
127f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    (at your option) any later version.
137f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
147f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    This program is distributed in the hope that it will be useful,
157f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    but WITHOUT ANY WARRANTY; without even the implied warranty of
167f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
177f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    GNU General Public License for more details.
187f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
197f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    You should have received a copy of the GNU General Public License
207f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    along with this program; if not, write to the Free Software
217f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
227f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
237f62d87d6876445d460c110054b6d38561cdff45Calin Culianu*/
247f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/*
257f62d87d6876445d460c110054b6d38561cdff45Calin CulianuDriver: cb_pcimdda
267f62d87d6876445d460c110054b6d38561cdff45Calin CulianuDescription: Measurement Computing PCIM-DDA06-16
277f62d87d6876445d460c110054b6d38561cdff45Calin CulianuDevices: [Measurement Computing] PCIM-DDA06-16 (cb_pcimdda)
287f62d87d6876445d460c110054b6d38561cdff45Calin CulianuAuthor: Calin Culianu <calin@ajvar.org>
297f62d87d6876445d460c110054b6d38561cdff45Calin CulianuUpdated: Mon, 14 Apr 2008 15:15:51 +0100
307f62d87d6876445d460c110054b6d38561cdff45Calin CulianuStatus: works
317f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
327f62d87d6876445d460c110054b6d38561cdff45Calin CulianuAll features of the PCIM-DDA06-16 board are supported.  This board
337f62d87d6876445d460c110054b6d38561cdff45Calin Culianuhas 6 16-bit AO channels, and the usual 8255 DIO setup.  (24 channels,
347f62d87d6876445d460c110054b6d38561cdff45Calin Culianuconfigurable in banks of 8 and 4, etc.).  This board does not support commands.
357f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
367f62d87d6876445d460c110054b6d38561cdff45Calin CulianuThe board has a peculiar way of specifying AO gain/range settings -- You have
377f62d87d6876445d460c110054b6d38561cdff45Calin Culianu1 jumper bank on the card, which either makes all 6 AO channels either
387f62d87d6876445d460c110054b6d38561cdff45Calin Culianu5 Volt unipolar, 5V bipolar, 10 Volt unipolar or 10V bipolar.
397f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
407f62d87d6876445d460c110054b6d38561cdff45Calin CulianuSince there is absolutely _no_ way to tell in software how this jumper is set
417f62d87d6876445d460c110054b6d38561cdff45Calin Culianu(well, at least according  to the rather thin spec. from Measurement Computing
427f62d87d6876445d460c110054b6d38561cdff45Calin Culianu that comes with the board), the driver assumes the jumper is at its factory
437f62d87d6876445d460c110054b6d38561cdff45Calin Culianudefault setting of +/-5V.
447f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
457f62d87d6876445d460c110054b6d38561cdff45Calin CulianuAlso of note is the fact that this board features another jumper, whose
467f62d87d6876445d460c110054b6d38561cdff45Calin Culianustate is also completely invisible to software.  It toggles two possible AO
477f62d87d6876445d460c110054b6d38561cdff45Calin Culianuoutput modes on the board:
487f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
497f62d87d6876445d460c110054b6d38561cdff45Calin Culianu  - Update Mode: Writing to an AO channel instantaneously updates the actual
507f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    signal output by the DAC on the board (this is the factory default).
517f62d87d6876445d460c110054b6d38561cdff45Calin Culianu  - Simultaneous XFER Mode: Writing to an AO channel has no effect until
527f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    you read from any one of the AO channels.  This is useful for loading
537f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    all 6 AO values, and then reading from any one of the AO channels on the
547f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    device to instantly update all 6 AO values in unison.  Useful for some
557f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    control apps, I would assume?  If your jumper is in this setting, then you
567f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    need to issue your comedi_data_write()s to load all the values you want,
577f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    then issue one comedi_data_read() on any channel on the AO subdevice
587f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    to initiate the simultaneous XFER.
597f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
607f62d87d6876445d460c110054b6d38561cdff45Calin CulianuConfiguration Options:
617f62d87d6876445d460c110054b6d38561cdff45Calin Culianu  [0] PCI bus (optional)
627f62d87d6876445d460c110054b6d38561cdff45Calin Culianu  [1] PCI slot (optional)
637f62d87d6876445d460c110054b6d38561cdff45Calin Culianu  [2] analog output range jumper setting
647f62d87d6876445d460c110054b6d38561cdff45Calin Culianu      0 == +/- 5 V
657f62d87d6876445d460c110054b6d38561cdff45Calin Culianu      1 == +/- 10 V
667f62d87d6876445d460c110054b6d38561cdff45Calin Culianu*/
677f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
687f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/*
697f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    This is a driver for the Computer Boards PCIM-DDA06-16 Analog Output
707f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    card.  This board has a unique register layout and as such probably
717f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    deserves its own driver file.
727f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
737f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    It is theoretically possible to integrate this board into the cb_pcidda
747f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    file, but since that isn't my code, I didn't want to significantly
757f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    modify that file to support this board (I thought it impolite to do so).
767f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
777f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    At any rate, if you feel ambitious, please feel free to take
787f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    the code out of this file and combine it with a more unified driver
797f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    file.
807f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
817f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    I would like to thank Timothy Curry <Timothy.Curry@rdec.redstone.army.mil>
827f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    for lending me a board so that I could write this driver.
837f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
847f62d87d6876445d460c110054b6d38561cdff45Calin Culianu    -Calin Culianu <calin@ajvar.org>
857f62d87d6876445d460c110054b6d38561cdff45Calin Culianu */
867f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
877f62d87d6876445d460c110054b6d38561cdff45Calin Culianu#include "../comedidev.h"
887f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
897f62d87d6876445d460c110054b6d38561cdff45Calin Culianu#include "comedi_pci.h"
907f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
917f62d87d6876445d460c110054b6d38561cdff45Calin Culianu#include "8255.h"
927f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
937f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/* device ids of the cards we support -- currently only 1 card supported */
94558587e2d96a4f5439a609509e4ea88f7536203bGreg Kroah-Hartman#define PCI_VENDOR_ID_COMPUTERBOARDS	0x1307
95558587e2d96a4f5439a609509e4ea88f7536203bGreg Kroah-Hartman#define PCI_ID_PCIM_DDA06_16		0x0053
967f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
977f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/*
987f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * This is straight from skel.c -- I did this in case this source file
997f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * will someday support more than 1 board...
1007f62d87d6876445d460c110054b6d38561cdff45Calin Culianu */
101324da11efaea562c8270834ac03c7c3df03aa79bBill Pembertonstruct board_struct {
1027f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	const char *name;
1037f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	unsigned short device_id;
1047f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	int ao_chans;
1057f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	int ao_bits;
1067f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	int dio_chans;
1077f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	int dio_method;
10841912a3f231e97efa154f4662608c024238ffe5eRavishankar karkala Mallikarjunayya	/* how many bytes into the BADR are the DIO ports */
10941912a3f231e97efa154f4662608c024238ffe5eRavishankar karkala Mallikarjunayya	int dio_offset;
1107f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	int regs_badrindex;	/* IO Region for the control, analog output,
1117f62d87d6876445d460c110054b6d38561cdff45Calin Culianu				   and DIO registers */
1127f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	int reg_sz;		/* number of bytes of registers in io region */
113324da11efaea562c8270834ac03c7c3df03aa79bBill Pemberton};
1147f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
1157f62d87d6876445d460c110054b6d38561cdff45Calin Culianuenum DIO_METHODS {
1167f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	DIO_NONE = 0,
1177f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	DIO_8255,
1187f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	DIO_INTERNAL		/* unimplemented */
1197f62d87d6876445d460c110054b6d38561cdff45Calin Culianu};
1207f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
121324da11efaea562c8270834ac03c7c3df03aa79bBill Pembertonstatic const struct board_struct boards[] = {
1227f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	{
1230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .name = "cb_pcimdda06-16",
1240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .device_id = PCI_ID_PCIM_DDA06_16,
1250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ao_chans = 6,
1260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ao_bits = 16,
1270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .dio_chans = 24,
1280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .dio_method = DIO_8255,
1290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .dio_offset = 12,
1300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .regs_badrindex = 3,
1310a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .reg_sz = 16,
1320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 }
1337f62d87d6876445d460c110054b6d38561cdff45Calin Culianu};
1347f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
1357f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/*
1367f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * Useful for shorthand access to the particular board structure
1377f62d87d6876445d460c110054b6d38561cdff45Calin Culianu */
138324da11efaea562c8270834ac03c7c3df03aa79bBill Pemberton#define thisboard    ((const struct board_struct *)dev->board_ptr)
1397f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
1407f62d87d6876445d460c110054b6d38561cdff45Calin Culianu#define REG_SZ (thisboard->reg_sz)
1417f62d87d6876445d460c110054b6d38561cdff45Calin Culianu#define REGS_BADRINDEX (thisboard->regs_badrindex)
1427f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
1437f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/* This is used by modprobe to translate PCI IDs to drivers.  Should
1447f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * only be used for PCI and ISA-PnP devices */
1457f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/* Please add your PCI vendor ID to comedidev.h, and it will be forwarded
1467f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * upstream. */
1477f62d87d6876445d460c110054b6d38561cdff45Calin Culianustatic DEFINE_PCI_DEVICE_TABLE(pci_table) = {
14871d4c80db1e042baae6c5a2ca1bbfc16c89bd2b5Peter Huewe	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, PCI_ID_PCIM_DDA06_16) },
14971d4c80db1e042baae6c5a2ca1bbfc16c89bd2b5Peter Huewe	{0}
1507f62d87d6876445d460c110054b6d38561cdff45Calin Culianu};
1517f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
1527f62d87d6876445d460c110054b6d38561cdff45Calin CulianuMODULE_DEVICE_TABLE(pci, pci_table);
1537f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
15441912a3f231e97efa154f4662608c024238ffe5eRavishankar karkala Mallikarjunayya/*
15541912a3f231e97efa154f4662608c024238ffe5eRavishankar karkala Mallikarjunayya * this structure is for data unique to this hardware driver.  If
15641912a3f231e97efa154f4662608c024238ffe5eRavishankar karkala Mallikarjunayya * several hardware drivers keep similar information in this structure,
15741912a3f231e97efa154f4662608c024238ffe5eRavishankar karkala Mallikarjunayya * feel free to suggest moving the variable to the struct comedi_device
15841912a3f231e97efa154f4662608c024238ffe5eRavishankar karkala Mallikarjunayya * struct.
15941912a3f231e97efa154f4662608c024238ffe5eRavishankar karkala Mallikarjunayya */
1600ff297c4ebf5f7119e928d74a9d952158d329acaBill Pembertonstruct board_private_struct {
1617f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	unsigned long registers;	/* set by probe */
1627f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	unsigned long dio_registers;
1637f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	char attached_to_8255;	/* boolean */
1647f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	char attached_successfully;	/* boolean */
1657f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	/* would be useful for a PCI device */
1667f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	struct pci_dev *pci_dev;
1677f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
1687f62d87d6876445d460c110054b6d38561cdff45Calin Culianu#define MAX_AO_READBACK_CHANNELS 6
1697f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	/* Used for AO readback */
170790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	unsigned int ao_readback[MAX_AO_READBACK_CHANNELS];
1717f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
1720ff297c4ebf5f7119e928d74a9d952158d329acaBill Pemberton};
1737f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
1747f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/*
1757f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * most drivers define the following macro to make it easy to
1767f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * access the private structure.
1777f62d87d6876445d460c110054b6d38561cdff45Calin Culianu */
1780ff297c4ebf5f7119e928d74a9d952158d329acaBill Pemberton#define devpriv ((struct board_private_struct *)dev->private)
1797f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
1807f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/*
181139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88Bill Pemberton * The struct comedi_driver structure tells the Comedi core module
1827f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * which functions to call to configure/deconfigure (attach/detach)
1837f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * the board, and also about the kernel module that contains
1847f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * the device code.
1857f62d87d6876445d460c110054b6d38561cdff45Calin Culianu */
186da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int attach(struct comedi_device *dev, struct comedi_devconfig *it);
187da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int detach(struct comedi_device *dev);
188139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88Bill Pembertonstatic struct comedi_driver cb_pcimdda_driver = {
18968c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.driver_name = "cb_pcimdda",
19068c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.module = THIS_MODULE,
19168c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.attach = attach,
19268c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.detach = detach,
1937f62d87d6876445d460c110054b6d38561cdff45Calin Culianu};
1947f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
1957f62d87d6876445d460c110054b6d38561cdff45Calin CulianuMODULE_AUTHOR("Calin A. Culianu <calin@rtlab.org>");
1967f62d87d6876445d460c110054b6d38561cdff45Calin CulianuMODULE_DESCRIPTION("Comedi low-level driver for the Computerboards PCIM-DDA "
1970a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		   "series.  Currently only supports PCIM-DDA06-16 (which "
1980a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		   "also happens to be the only board in this series. :) ) ");
1997f62d87d6876445d460c110054b6d38561cdff45Calin CulianuMODULE_LICENSE("GPL");
200727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasstatic int __devinit cb_pcimdda_driver_pci_probe(struct pci_dev *dev,
201727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas						 const struct pci_device_id
202727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas						 *ent)
203727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas{
204727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	return comedi_pci_auto_config(dev, cb_pcimdda_driver.driver_name);
205727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas}
206727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
207727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasstatic void __devexit cb_pcimdda_driver_pci_remove(struct pci_dev *dev)
208727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas{
209727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	comedi_pci_auto_unconfig(dev);
210727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas}
211727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
212727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasstatic struct pci_driver cb_pcimdda_driver_pci_driver = {
213727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	.id_table = pci_table,
214727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	.probe = &cb_pcimdda_driver_pci_probe,
215727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	.remove = __devexit_p(&cb_pcimdda_driver_pci_remove)
216727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas};
217727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
218727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasstatic int __init cb_pcimdda_driver_init_module(void)
219727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas{
220727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	int retval;
221727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
222727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	retval = comedi_driver_register(&cb_pcimdda_driver);
223727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	if (retval < 0)
224727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas		return retval;
225727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
226727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	cb_pcimdda_driver_pci_driver.name =
227727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	    (char *)cb_pcimdda_driver.driver_name;
228727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	return pci_register_driver(&cb_pcimdda_driver_pci_driver);
229727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas}
230727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
231727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasstatic void __exit cb_pcimdda_driver_cleanup_module(void)
232727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas{
233727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	pci_unregister_driver(&cb_pcimdda_driver_pci_driver);
234727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	comedi_driver_unregister(&cb_pcimdda_driver);
235727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas}
236727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
237727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasmodule_init(cb_pcimdda_driver_init_module);
238727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasmodule_exit(cb_pcimdda_driver_cleanup_module);
2397f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
240da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
2410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    struct comedi_insn *insn, unsigned int *data);
242da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
2430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    struct comedi_insn *insn, unsigned int *data);
2447f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
2457f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/*---------------------------------------------------------------------------
2467f62d87d6876445d460c110054b6d38561cdff45Calin Culianu  HELPER FUNCTION DECLARATIONS
2477f62d87d6876445d460c110054b6d38561cdff45Calin Culianu-----------------------------------------------------------------------------*/
2487f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
2497f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/* returns a maxdata value for a given n_bits */
250790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pembertonstatic inline unsigned int figure_out_maxdata(int bits)
2517f62d87d6876445d460c110054b6d38561cdff45Calin Culianu{
2520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	return ((unsigned int)1 << bits) - 1;
2537f62d87d6876445d460c110054b6d38561cdff45Calin Culianu}
2547f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
2557f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/*
2567f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *  Probes for a supported device.
2577f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *
2587f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *  Prerequisite: private be allocated already inside dev
2597f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *
2607f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *  If the device is found, it returns 0 and has the following side effects:
2617f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *
2627f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *  o  assigns a struct pci_dev * to dev->private->pci_dev
2637f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *  o  assigns a struct board * to dev->board_ptr
2647f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *  o  sets dev->private->registers
2657f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *  o  sets dev->private->dio_registers
2667f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *
2677f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *  Otherwise, returns a -errno on error
2687f62d87d6876445d460c110054b6d38561cdff45Calin Culianu */
269da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int probe(struct comedi_device *dev, const struct comedi_devconfig *it);
2707f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
2717f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/*---------------------------------------------------------------------------
2727f62d87d6876445d460c110054b6d38561cdff45Calin Culianu  FUNCTION DEFINITIONS
2737f62d87d6876445d460c110054b6d38561cdff45Calin Culianu-----------------------------------------------------------------------------*/
2747f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
2757f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/*
2767f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * Attach is called by the Comedi core to configure the driver
2777f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * for a particular board.  If you specified a board_name array
2787f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * in the driver structure, dev->board_ptr contains that
2797f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * address.
2807f62d87d6876445d460c110054b6d38561cdff45Calin Culianu */
281da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int attach(struct comedi_device *dev, struct comedi_devconfig *it)
2827f62d87d6876445d460c110054b6d38561cdff45Calin Culianu{
28334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
2847f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	int err;
2857f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
2867f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/*
2877f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * Allocate the private structure area.  alloc_private() is a
2887f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * convenient macro defined in comedidev.h.
2897f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * if this function fails (returns negative) then the private area is
2907f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * kfree'd by comedi
2917f62d87d6876445d460c110054b6d38561cdff45Calin Culianu */
2920ff297c4ebf5f7119e928d74a9d952158d329acaBill Pemberton	if (alloc_private(dev, sizeof(struct board_private_struct)) < 0)
2937f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		return -ENOMEM;
2947f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
2957f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/*
2967f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * If you can probe the device to determine what device in a series
2977f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * it is, this is the place to do it.  Otherwise, dev->board_ptr
2987f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * should already be initialized.
2997f62d87d6876445d460c110054b6d38561cdff45Calin Culianu */
300c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	err = probe(dev, it);
301c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	if (err)
3027f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		return err;
3037f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
3047f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/* Output some info */
3057f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	printk("comedi%d: %s: ", dev->minor, thisboard->name);
3067f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
3077f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/*
3087f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * Initialize dev->board_name.  Note that we can use the "thisboard"
3097f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * macro now, since we just initialized it in the last line.
3107f62d87d6876445d460c110054b6d38561cdff45Calin Culianu */
3117f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	dev->board_name = thisboard->name;
3127f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
3137f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/*
3147f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * Allocate the subdevice structures.  alloc_subdevice() is a
3157f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * convenient macro defined in comedidev.h.
3167f62d87d6876445d460c110054b6d38561cdff45Calin Culianu */
3177f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	if (alloc_subdevices(dev, 2) < 0)
3187f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		return -ENOMEM;
3197f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
3207f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	s = dev->subdevices + 0;
3217f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
3227f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	/* analog output subdevice */
3237f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	s->type = COMEDI_SUBD_AO;
3247f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
3257f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	s->n_chan = thisboard->ao_chans;
3267f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	s->maxdata = figure_out_maxdata(thisboard->ao_bits);
3277f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	/* this is hard-coded here */
328f1c54e82726fe51a55a18d15dc9377b8fd568ca2Andrea Gelmini	if (it->options[2])
3297f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		s->range_table = &range_bipolar10;
330f1c54e82726fe51a55a18d15dc9377b8fd568ca2Andrea Gelmini	else
3317f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		s->range_table = &range_bipolar5;
3327f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	s->insn_write = &ao_winsn;
3337f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	s->insn_read = &ao_rinsn;
3347f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
3357f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	s = dev->subdevices + 1;
3367f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	/* digital i/o subdevice */
3377f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	if (thisboard->dio_chans) {
3387f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		switch (thisboard->dio_method) {
3397f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		case DIO_8255:
34041912a3f231e97efa154f4662608c024238ffe5eRavishankar karkala Mallikarjunayya			/*
34141912a3f231e97efa154f4662608c024238ffe5eRavishankar karkala Mallikarjunayya			 * this is a straight 8255, so register us with
34241912a3f231e97efa154f4662608c024238ffe5eRavishankar karkala Mallikarjunayya			 * the 8255 driver
34341912a3f231e97efa154f4662608c024238ffe5eRavishankar karkala Mallikarjunayya			 */
3447f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			subdev_8255_init(dev, s, NULL, devpriv->dio_registers);
3457f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			devpriv->attached_to_8255 = 1;
3467f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			break;
3477f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		case DIO_INTERNAL:
3487f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		default:
3497f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			printk("DIO_INTERNAL not implemented yet!\n");
3507f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			return -ENXIO;
3517f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			break;
3527f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		}
3537f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	} else {
3547f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		s->type = COMEDI_SUBD_UNUSED;
3557f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	}
3567f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
3577f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	devpriv->attached_successfully = 1;
3587f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
3597f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	printk("attached\n");
3607f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
3617f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	return 1;
3627f62d87d6876445d460c110054b6d38561cdff45Calin Culianu}
3637f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
3647f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/*
3657f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * _detach is called to deconfigure a device.  It should deallocate
3667f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * resources.
3677f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * This function is also called when _attach() fails, so it should be
3687f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * careful not to release resources that were not necessarily
3697f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * allocated by _attach().  dev->private and dev->subdevices are
3707f62d87d6876445d460c110054b6d38561cdff45Calin Culianu * deallocated automatically by the core.
3717f62d87d6876445d460c110054b6d38561cdff45Calin Culianu */
372da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int detach(struct comedi_device *dev)
3737f62d87d6876445d460c110054b6d38561cdff45Calin Culianu{
3747f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	if (devpriv) {
3757f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
3767f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		if (dev->subdevices && devpriv->attached_to_8255) {
3777f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			/* de-register us from the 8255 driver */
3787f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			subdev_8255_cleanup(dev, dev->subdevices + 2);
3797f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			devpriv->attached_to_8255 = 0;
3807f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		}
3817f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
3827f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		if (devpriv->pci_dev) {
383f1c54e82726fe51a55a18d15dc9377b8fd568ca2Andrea Gelmini			if (devpriv->registers)
3847f62d87d6876445d460c110054b6d38561cdff45Calin Culianu				comedi_pci_disable(devpriv->pci_dev);
3857f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			pci_dev_put(devpriv->pci_dev);
3867f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		}
3877f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
3887f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		if (devpriv->attached_successfully && thisboard)
3897f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			printk("comedi%d: %s: detached\n", dev->minor,
3900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       thisboard->name);
3917f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
3927f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	}
3937f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
3947f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	return 0;
3957f62d87d6876445d460c110054b6d38561cdff45Calin Culianu}
3967f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
397da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
3980a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    struct comedi_insn *insn, unsigned int *data)
3997f62d87d6876445d460c110054b6d38561cdff45Calin Culianu{
4007f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	int i;
4017f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	int chan = CR_CHAN(insn->chanspec);
4027f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	unsigned long offset = devpriv->registers + chan * 2;
4037f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
4047f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	/* Writing a list of values to an AO channel is probably not
4057f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	 * very useful, but that's how the interface is defined. */
4067f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	for (i = 0; i < insn->n; i++) {
4077f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		/*  first, load the low byte */
4087f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		outb((char)(data[i] & 0x00ff), offset);
4097f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		/*  next, write the high byte -- only after this is written is
4107f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		   the channel voltage updated in the DAC, unless
4117f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		   we're in simultaneous xfer mode (jumper on card)
4127f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		   then a rinsn is necessary to actually update the DAC --
4137f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		   see ao_rinsn() below... */
4147f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		outb((char)(data[i] >> 8 & 0x00ff), offset + 1);
4157f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
4167f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		/* for testing only.. the actual rinsn SHOULD do an inw!
4177f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		   (see the stuff about simultaneous XFER mode on this board) */
4187f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		devpriv->ao_readback[chan] = data[i];
4197f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	}
4207f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
4217f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	/* return the number of samples read/written */
4227f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	return i;
4237f62d87d6876445d460c110054b6d38561cdff45Calin Culianu}
4247f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
4257f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/* AO subdevices should have a read insn as well as a write insn.
4267f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
4277f62d87d6876445d460c110054b6d38561cdff45Calin Culianu   Usually this means copying a value stored in devpriv->ao_readback.
4287f62d87d6876445d460c110054b6d38561cdff45Calin Culianu   However, since this board has this jumper setting called "Simultaneous
4297f62d87d6876445d460c110054b6d38561cdff45Calin Culianu   Xfer mode" (off by default), we will support it.  Simultaneaous xfer
4307f62d87d6876445d460c110054b6d38561cdff45Calin Culianu   mode is accomplished by loading ALL the values you want for AO in all the
4317f62d87d6876445d460c110054b6d38561cdff45Calin Culianu   channels, then READing off one of the AO registers to initiate the
4327f62d87d6876445d460c110054b6d38561cdff45Calin Culianu   instantaneous simultaneous update of all DAC outputs, which makes
4337f62d87d6876445d460c110054b6d38561cdff45Calin Culianu   all AO channels update simultaneously.  This is useful for some control
4347f62d87d6876445d460c110054b6d38561cdff45Calin Culianu   applications, I would imagine.
4357f62d87d6876445d460c110054b6d38561cdff45Calin Culianu*/
436da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
4370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    struct comedi_insn *insn, unsigned int *data)
4387f62d87d6876445d460c110054b6d38561cdff45Calin Culianu{
4397f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	int i;
4407f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	int chan = CR_CHAN(insn->chanspec);
4417f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
4427f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	for (i = 0; i < insn->n; i++) {
4437f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		inw(devpriv->registers + chan * 2);
44441912a3f231e97efa154f4662608c024238ffe5eRavishankar karkala Mallikarjunayya		/*
44541912a3f231e97efa154f4662608c024238ffe5eRavishankar karkala Mallikarjunayya		 * should I set data[i] to the result of the actual read
44641912a3f231e97efa154f4662608c024238ffe5eRavishankar karkala Mallikarjunayya		 * on the register or the cached unsigned int in
44741912a3f231e97efa154f4662608c024238ffe5eRavishankar karkala Mallikarjunayya		 * devpriv->ao_readback[]?
44841912a3f231e97efa154f4662608c024238ffe5eRavishankar karkala Mallikarjunayya		 */
4497f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		data[i] = devpriv->ao_readback[chan];
4507f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	}
4517f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
4527f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	return i;
4537f62d87d6876445d460c110054b6d38561cdff45Calin Culianu}
4547f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
4557f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/*---------------------------------------------------------------------------
4567f62d87d6876445d460c110054b6d38561cdff45Calin Culianu  HELPER FUNCTION DEFINITIONS
4577f62d87d6876445d460c110054b6d38561cdff45Calin Culianu-----------------------------------------------------------------------------*/
4587f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
4597f62d87d6876445d460c110054b6d38561cdff45Calin Culianu/*
4607f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *  Probes for a supported device.
4617f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *
4627f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *  Prerequisite: private be allocated already inside dev
4637f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *
4647f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *  If the device is found, it returns 0 and has the following side effects:
4657f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *
4667f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *  o  assigns a struct pci_dev * to dev->private->pci_dev
4677f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *  o  assigns a struct board * to dev->board_ptr
4687f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *  o  sets dev->private->registers
4697f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *  o  sets dev->private->dio_registers
4707f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *
4717f62d87d6876445d460c110054b6d38561cdff45Calin Culianu *  Otherwise, returns a -errno on error
4727f62d87d6876445d460c110054b6d38561cdff45Calin Culianu */
473da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int probe(struct comedi_device *dev, const struct comedi_devconfig *it)
4747f62d87d6876445d460c110054b6d38561cdff45Calin Culianu{
47520fb2280815510533cbd7785b53821ca7209345bKulikov Vasiliy	struct pci_dev *pcidev = NULL;
4767f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	int index;
4777f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	unsigned long registers;
4787f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
47920fb2280815510533cbd7785b53821ca7209345bKulikov Vasiliy	for_each_pci_dev(pcidev) {
4802696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton		/*  is it not a computer boards card? */
4817f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		if (pcidev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS)
4827f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			continue;
4832696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton		/*  loop through cards supported by this driver */
4848629efa4cbf6f89a54a85af4b8bc31762af01800Bill Pemberton		for (index = 0; index < ARRAY_SIZE(boards); index++) {
4857f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			if (boards[index].device_id != pcidev->device)
4867f62d87d6876445d460c110054b6d38561cdff45Calin Culianu				continue;
4872696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton			/*  was a particular bus/slot requested? */
4887f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			if (it->options[0] || it->options[1]) {
4892696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton				/*  are we on the wrong bus/slot? */
4907f62d87d6876445d460c110054b6d38561cdff45Calin Culianu				if (pcidev->bus->number != it->options[0] ||
4910a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    PCI_SLOT(pcidev->devfn) != it->options[1]) {
4927f62d87d6876445d460c110054b6d38561cdff45Calin Culianu					continue;
4937f62d87d6876445d460c110054b6d38561cdff45Calin Culianu				}
4947f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			}
4957f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			/* found ! */
4967f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
4977f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			devpriv->pci_dev = pcidev;
4987f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			dev->board_ptr = boards + index;
4997f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			if (comedi_pci_enable(pcidev, thisboard->name)) {
5000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				printk
5010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    ("cb_pcimdda: Failed to enable PCI device and request regions\n");
5027f62d87d6876445d460c110054b6d38561cdff45Calin Culianu				return -EIO;
5037f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			}
5047f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			registers =
5050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    pci_resource_start(devpriv->pci_dev,
5060a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					       REGS_BADRINDEX);
5077f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			devpriv->registers = registers;
5087f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			devpriv->dio_registers
5090a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    = devpriv->registers + thisboard->dio_offset;
5107f62d87d6876445d460c110054b6d38561cdff45Calin Culianu			return 0;
5117f62d87d6876445d460c110054b6d38561cdff45Calin Culianu		}
5127f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	}
5137f62d87d6876445d460c110054b6d38561cdff45Calin Culianu
5147f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	printk("cb_pcimdda: No supported ComputerBoards/MeasurementComputing "
5150a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	       "card found at the requested position\n");
5167f62d87d6876445d460c110054b6d38561cdff45Calin Culianu	return -ENODEV;
5177f62d87d6876445d460c110054b6d38561cdff45Calin Culianu}
518