12f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann/*
22f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann    comedi/drivers/ke_counter.c
32f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann    Comedi driver for Kolter-Electronic PCI Counter 1 Card
42f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
52f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann    COMEDI - Linux Control and Measurement Device Interface
62f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann    Copyright (C) 2000 David A. Schleef <ds@schleef.org>
72f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
82f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann    This program is free software; you can redistribute it and/or modify
92f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann    it under the terms of the GNU General Public License as published by
102f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann    the Free Software Foundation; either version 2 of the License, or
112f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann    (at your option) any later version.
122f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
132f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann    This program is distributed in the hope that it will be useful,
142f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann    but WITHOUT ANY WARRANTY; without even the implied warranty of
152f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
162f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann    GNU General Public License for more details.
172f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
182f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann    You should have received a copy of the GNU General Public License
192f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann    along with this program; if not, write to the Free Software
202f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
212f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
222f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann*/
232f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann/*
242f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael HillmannDriver: ke_counter
252f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael HillmannDescription: Driver for Kolter Electronic Counter Card
262f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael HillmannDevices: [Kolter Electronic] PCI Counter Card (ke_counter)
272f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael HillmannAuthor: Michael Hillmann
282f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael HillmannUpdated: Mon, 14 Apr 2008 15:42:42 +0100
292f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael HillmannStatus: tested
302f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
312f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael HillmannConfiguration Options:
322f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann  [0] - PCI bus of device (optional)
332f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann  [1] - PCI slot of device (optional)
342f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann  If bus/slot is not specified, the first supported
352f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann  PCI device found will be used.
362f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
372f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael HillmannThis driver is a simple driver to read the counter values from
382f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael HillmannKolter Electronic PCI Counter Card.
392f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann*/
402f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
412f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann#include "../comedidev.h"
422f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
432f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann#include "comedi_pci.h"
442f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
452f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann#define CNT_DRIVER_NAME         "ke_counter"
462f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann#define PCI_VENDOR_ID_KOLTER    0x1001
472f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann#define CNT_CARD_DEVICE_ID      0x0014
482f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
492f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann/*-- function prototypes ----------------------------------------------------*/
502f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
51da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it);
52da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int cnt_detach(struct comedi_device *dev);
532f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
542f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmannstatic DEFINE_PCI_DEVICE_TABLE(cnt_pci_table) = {
5549d6f67245c11a18d0454b2101fa224133f59323Peter Huewe	{ PCI_DEVICE(PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID) },
5649d6f67245c11a18d0454b2101fa224133f59323Peter Huewe	{0}
572f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann};
582f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
592f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael HillmannMODULE_DEVICE_TABLE(pci, cnt_pci_table);
602f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
612f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann/*-- board specification structure ------------------------------------------*/
622f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
639beff277bb14a844b5cb437fcdca9db7534ee44aBill Pembertonstruct cnt_board_struct {
649beff277bb14a844b5cb437fcdca9db7534ee44aBill Pemberton
652f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	const char *name;
662f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	int device_id;
672f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	int cnt_channel_nbr;
682f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	int cnt_bits;
699beff277bb14a844b5cb437fcdca9db7534ee44aBill Pemberton};
709beff277bb14a844b5cb437fcdca9db7534ee44aBill Pemberton
719beff277bb14a844b5cb437fcdca9db7534ee44aBill Pembertonstatic const struct cnt_board_struct cnt_boards[] = {
722f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	{
730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .name = CNT_DRIVER_NAME,
740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .device_id = CNT_CARD_DEVICE_ID,
750a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .cnt_channel_nbr = 3,
760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .cnt_bits = 24}
772f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann};
782f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
799beff277bb14a844b5cb437fcdca9db7534ee44aBill Pemberton#define cnt_board_nbr (sizeof(cnt_boards)/sizeof(struct cnt_board_struct))
802f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
812f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann/*-- device private structure -----------------------------------------------*/
822f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
832e2269f90f2bb4e9438849f0690daba5cba29fc5Bill Pembertonstruct cnt_device_private {
842e2269f90f2bb4e9438849f0690daba5cba29fc5Bill Pemberton
852f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	struct pci_dev *pcidev;
862e2269f90f2bb4e9438849f0690daba5cba29fc5Bill Pemberton};
872e2269f90f2bb4e9438849f0690daba5cba29fc5Bill Pemberton
882e2269f90f2bb4e9438849f0690daba5cba29fc5Bill Pemberton#define devpriv ((struct cnt_device_private *)dev->private)
892f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
90139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88Bill Pembertonstatic struct comedi_driver cnt_driver = {
9168c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.driver_name = CNT_DRIVER_NAME,
9268c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.module = THIS_MODULE,
9368c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.attach = cnt_attach,
9468c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.detach = cnt_detach,
952f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann};
962f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
97727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasstatic int __devinit cnt_driver_pci_probe(struct pci_dev *dev,
98727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas					  const struct pci_device_id *ent)
99727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas{
100727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	return comedi_pci_auto_config(dev, cnt_driver.driver_name);
101727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas}
102727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
103727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasstatic void __devexit cnt_driver_pci_remove(struct pci_dev *dev)
104727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas{
105727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	comedi_pci_auto_unconfig(dev);
106727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas}
107727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
108727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasstatic struct pci_driver cnt_driver_pci_driver = {
109727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	.id_table = cnt_pci_table,
110727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	.probe = &cnt_driver_pci_probe,
111727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	.remove = __devexit_p(&cnt_driver_pci_remove)
112727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas};
113727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
114727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasstatic int __init cnt_driver_init_module(void)
115727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas{
116727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	int retval;
117727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
118727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	retval = comedi_driver_register(&cnt_driver);
119727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	if (retval < 0)
120727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas		return retval;
121727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
122727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	cnt_driver_pci_driver.name = (char *)cnt_driver.driver_name;
123727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	return pci_register_driver(&cnt_driver_pci_driver);
124727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas}
125727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
126727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasstatic void __exit cnt_driver_cleanup_module(void)
127727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas{
128727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	pci_unregister_driver(&cnt_driver_pci_driver);
129727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas	comedi_driver_unregister(&cnt_driver);
130727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas}
131727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomas
132727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasmodule_init(cnt_driver_init_module);
133727b286b44ea359d66f47d241cc2cdad36ed7bdcArun Thomasmodule_exit(cnt_driver_cleanup_module);
1342f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
1352f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann/*-- counter write ----------------------------------------------------------*/
1362f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
1372f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann/* This should be used only for resetting the counters; maybe it is better
1382f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann   to make a special command 'reset'. */
139da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int cnt_winsn(struct comedi_device *dev,
1400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		     struct comedi_subdevice *s, struct comedi_insn *insn,
1410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		     unsigned int *data)
1422f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann{
1432f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	int chan = CR_CHAN(insn->chanspec);
1442f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
1452f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	outb((unsigned char)((data[0] >> 24) & 0xff),
1460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	     dev->iobase + chan * 0x20 + 0x10);
1472f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	outb((unsigned char)((data[0] >> 16) & 0xff),
1480a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	     dev->iobase + chan * 0x20 + 0x0c);
1492f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	outb((unsigned char)((data[0] >> 8) & 0xff),
1500a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	     dev->iobase + chan * 0x20 + 0x08);
1512f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	outb((unsigned char)((data[0] >> 0) & 0xff),
1520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	     dev->iobase + chan * 0x20 + 0x04);
1532f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
1542f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	/* return the number of samples written */
1552f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	return 1;
1562f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann}
1572f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
1582f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann/*-- counter read -----------------------------------------------------------*/
1592f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
160da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int cnt_rinsn(struct comedi_device *dev,
1610a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		     struct comedi_subdevice *s, struct comedi_insn *insn,
1620a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		     unsigned int *data)
1632f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann{
1642f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	unsigned char a0, a1, a2, a3, a4;
1652f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	int chan = CR_CHAN(insn->chanspec);
1662f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	int result;
1672f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
1682f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	a0 = inb(dev->iobase + chan * 0x20);
1692f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	a1 = inb(dev->iobase + chan * 0x20 + 0x04);
1702f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	a2 = inb(dev->iobase + chan * 0x20 + 0x08);
1712f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	a3 = inb(dev->iobase + chan * 0x20 + 0x0c);
1722f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	a4 = inb(dev->iobase + chan * 0x20 + 0x10);
1732f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
1742f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	result = (a1 + (a2 * 256) + (a3 * 65536));
1752f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	if (a4 > 0)
1762f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann		result = result - s->maxdata;
1772f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
1780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	*data = (unsigned int)result;
1792f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
1802f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	/* return the number of samples read */
1812f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	return 1;
1822f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann}
1832f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
1842f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann/*-- attach -----------------------------------------------------------------*/
1852f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
186da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1872f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann{
18834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *subdevice;
18920fb2280815510533cbd7785b53821ca7209345bKulikov Vasiliy	struct pci_dev *pci_device = NULL;
1909beff277bb14a844b5cb437fcdca9db7534ee44aBill Pemberton	struct cnt_board_struct *board;
1912f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	unsigned long io_base;
1922f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	int error, i;
1932f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
1942f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	/* allocate device private structure */
195c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	error = alloc_private(dev, sizeof(struct cnt_device_private));
196c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	if (error < 0)
1972f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann		return error;
1982f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
1992f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	/* Probe the device to determine what device in the series it is. */
20020fb2280815510533cbd7785b53821ca7209345bKulikov Vasiliy	for_each_pci_dev(pci_device) {
2012f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann		if (pci_device->vendor == PCI_VENDOR_ID_KOLTER) {
2022f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann			for (i = 0; i < cnt_board_nbr; i++) {
2032f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann				if (cnt_boards[i].device_id ==
2040a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    pci_device->device) {
2052f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann					/* was a particular bus/slot requested? */
2062f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann					if ((it->options[0] != 0)
2070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					    || (it->options[1] != 0)) {
2082f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann						/* are we on the wrong bus/slot? */
2092f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann						if (pci_device->bus->number !=
2100a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						    it->options[0]
2110a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						    ||
2120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						    PCI_SLOT(pci_device->devfn)
2130a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						    != it->options[1]) {
2142f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann							continue;
2152f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann						}
2162f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann					}
2172f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
2182f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann					dev->board_ptr = cnt_boards + i;
2190a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					board =
2200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					    (struct cnt_board_struct *)
2210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					    dev->board_ptr;
2222f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann					goto found;
2232f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann				}
2242f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann			}
2252f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann		}
2262f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	}
22726ac87851aa65f6bc58c2d1aa9162951a1dcd999Dirk Hohndel	printk(KERN_WARNING
22826ac87851aa65f6bc58c2d1aa9162951a1dcd999Dirk Hohndel	       "comedi%d: no supported board found! (req. bus/slot: %d/%d)\n",
2290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	       dev->minor, it->options[0], it->options[1]);
2302f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	return -EIO;
2312f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
2320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralfound:
23326ac87851aa65f6bc58c2d1aa9162951a1dcd999Dirk Hohndel	printk(KERN_INFO
23426ac87851aa65f6bc58c2d1aa9162951a1dcd999Dirk Hohndel	       "comedi%d: found %s at PCI bus %d, slot %d\n", dev->minor,
2350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	       board->name, pci_device->bus->number,
2360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	       PCI_SLOT(pci_device->devfn));
2372f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	devpriv->pcidev = pci_device;
2382f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	dev->board_name = board->name;
2392f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
2402f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	/* enable PCI device and request regions */
241c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	error = comedi_pci_enable(pci_device, CNT_DRIVER_NAME);
242c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	if (error < 0) {
24326ac87851aa65f6bc58c2d1aa9162951a1dcd999Dirk Hohndel		printk(KERN_WARNING "comedi%d: "
24426ac87851aa65f6bc58c2d1aa9162951a1dcd999Dirk Hohndel		       "failed to enable PCI device and request regions!\n",
24526ac87851aa65f6bc58c2d1aa9162951a1dcd999Dirk Hohndel		       dev->minor);
2462f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann		return error;
2472f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	}
2482f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
2492f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	/* read register base address [PCI_BASE_ADDRESS #0] */
2502f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	io_base = pci_resource_start(pci_device, 0);
2512f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	dev->iobase = io_base;
2522f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
2532f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	/* allocate the subdevice structures */
254c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	error = alloc_subdevices(dev, 1);
255c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	if (error < 0)
2562f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann		return error;
2572f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
2582f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	subdevice = dev->subdevices + 0;
2592f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	dev->read_subdev = subdevice;
2602f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
2612f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	subdevice->type = COMEDI_SUBD_COUNTER;
2622f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	subdevice->subdev_flags = SDF_READABLE /* | SDF_COMMON */ ;
2632f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	subdevice->n_chan = board->cnt_channel_nbr;
2642f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	subdevice->maxdata = (1 << board->cnt_bits) - 1;
2652f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	subdevice->insn_read = cnt_rinsn;
2662f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	subdevice->insn_write = cnt_winsn;
2672f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
2682696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	/*  select 20MHz clock */
2692f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	outb(3, dev->iobase + 248);
2702f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
2712696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	/*  reset all counters */
2722f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	outb(0, dev->iobase);
2732f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	outb(0, dev->iobase + 0x20);
2742f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	outb(0, dev->iobase + 0x40);
2752f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
27626ac87851aa65f6bc58c2d1aa9162951a1dcd999Dirk Hohndel	printk(KERN_INFO "comedi%d: " CNT_DRIVER_NAME " attached.\n",
27726ac87851aa65f6bc58c2d1aa9162951a1dcd999Dirk Hohndel	       dev->minor);
2782f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	return 0;
2792f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann}
2802f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
2812f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann/*-- detach -----------------------------------------------------------------*/
2822f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann
283da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int cnt_detach(struct comedi_device *dev)
2842f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann{
2852f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	if (devpriv && devpriv->pcidev) {
28626ac87851aa65f6bc58c2d1aa9162951a1dcd999Dirk Hohndel		if (dev->iobase)
2872f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann			comedi_pci_disable(devpriv->pcidev);
2882f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann		pci_dev_put(devpriv->pcidev);
2892f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	}
29026ac87851aa65f6bc58c2d1aa9162951a1dcd999Dirk Hohndel	printk(KERN_INFO "comedi%d: " CNT_DRIVER_NAME " remove\n",
29126ac87851aa65f6bc58c2d1aa9162951a1dcd999Dirk Hohndel	       dev->minor);
2922f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann	return 0;
2932f82613d3a7ef447be4ce656f757fc1ea101a4f1Michael Hillmann}
29490f703d30dd3e0c16ff80f35e34e511385a05ad5Arun Thomas
29590f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_AUTHOR("Comedi http://www.comedi.org");
29690f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_DESCRIPTION("Comedi low-level driver");
29790f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_LICENSE("GPL");
298