2 comedi/drivers/ke_counter.c
3 Comedi driver for Kolter-Electronic PCI Counter 1 Card
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 2000 David A. Schleef <ds@schleef.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 Description: Driver for Kolter Electronic Counter Card
26 Devices: [Kolter Electronic] PCI Counter Card (ke_counter)
27 Author: Michael Hillmann
28 Updated: Mon, 14 Apr 2008 15:42:42 +0100
31 Configuration Options:
32 [0] - PCI bus of device (optional)
33 [1] - PCI slot of device (optional)
34 If bus/slot is not specified, the first supported
35 PCI device found will be used.
37 This driver is a simple driver to read the counter values from
38 Kolter Electronic PCI Counter Card.
41 #include "../comedidev.h"
43 #define CNT_DRIVER_NAME "ke_counter"
44 #define PCI_VENDOR_ID_KOLTER 0x1001
45 #define CNT_CARD_DEVICE_ID 0x0014
47 /*-- board specification structure ------------------------------------------*/
49 struct cnt_board_struct
{
57 static const struct cnt_board_struct cnt_boards
[] = {
59 .name
= CNT_DRIVER_NAME
,
60 .device_id
= CNT_CARD_DEVICE_ID
,
65 #define cnt_board_nbr (sizeof(cnt_boards)/sizeof(struct cnt_board_struct))
67 /*-- device private structure -----------------------------------------------*/
69 struct cnt_device_private
{
71 struct pci_dev
*pcidev
;
74 #define devpriv ((struct cnt_device_private *)dev->private)
76 /*-- counter write ----------------------------------------------------------*/
78 /* This should be used only for resetting the counters; maybe it is better
79 to make a special command 'reset'. */
80 static int cnt_winsn(struct comedi_device
*dev
,
81 struct comedi_subdevice
*s
, struct comedi_insn
*insn
,
84 int chan
= CR_CHAN(insn
->chanspec
);
86 outb((unsigned char)((data
[0] >> 24) & 0xff),
87 dev
->iobase
+ chan
* 0x20 + 0x10);
88 outb((unsigned char)((data
[0] >> 16) & 0xff),
89 dev
->iobase
+ chan
* 0x20 + 0x0c);
90 outb((unsigned char)((data
[0] >> 8) & 0xff),
91 dev
->iobase
+ chan
* 0x20 + 0x08);
92 outb((unsigned char)((data
[0] >> 0) & 0xff),
93 dev
->iobase
+ chan
* 0x20 + 0x04);
95 /* return the number of samples written */
99 /*-- counter read -----------------------------------------------------------*/
101 static int cnt_rinsn(struct comedi_device
*dev
,
102 struct comedi_subdevice
*s
, struct comedi_insn
*insn
,
105 unsigned char a0
, a1
, a2
, a3
, a4
;
106 int chan
= CR_CHAN(insn
->chanspec
);
109 a0
= inb(dev
->iobase
+ chan
* 0x20);
110 a1
= inb(dev
->iobase
+ chan
* 0x20 + 0x04);
111 a2
= inb(dev
->iobase
+ chan
* 0x20 + 0x08);
112 a3
= inb(dev
->iobase
+ chan
* 0x20 + 0x0c);
113 a4
= inb(dev
->iobase
+ chan
* 0x20 + 0x10);
115 result
= (a1
+ (a2
* 256) + (a3
* 65536));
117 result
= result
- s
->maxdata
;
119 *data
= (unsigned int)result
;
121 /* return the number of samples read */
125 static int cnt_attach(struct comedi_device
*dev
, struct comedi_devconfig
*it
)
127 struct comedi_subdevice
*subdevice
;
128 struct pci_dev
*pci_device
= NULL
;
129 struct cnt_board_struct
*board
;
130 unsigned long io_base
;
133 /* allocate device private structure */
134 error
= alloc_private(dev
, sizeof(struct cnt_device_private
));
138 /* Probe the device to determine what device in the series it is. */
139 for_each_pci_dev(pci_device
) {
140 if (pci_device
->vendor
== PCI_VENDOR_ID_KOLTER
) {
141 for (i
= 0; i
< cnt_board_nbr
; i
++) {
142 if (cnt_boards
[i
].device_id
==
143 pci_device
->device
) {
144 /* was a particular bus/slot requested? */
145 if ((it
->options
[0] != 0)
146 || (it
->options
[1] != 0)) {
147 /* are we on the wrong bus/slot? */
148 if (pci_device
->bus
->number
!=
151 PCI_SLOT(pci_device
->devfn
)
157 dev
->board_ptr
= cnt_boards
+ i
;
159 (struct cnt_board_struct
*)
167 "comedi%d: no supported board found! (req. bus/slot: %d/%d)\n",
168 dev
->minor
, it
->options
[0], it
->options
[1]);
173 "comedi%d: found %s at PCI bus %d, slot %d\n", dev
->minor
,
174 board
->name
, pci_device
->bus
->number
,
175 PCI_SLOT(pci_device
->devfn
));
176 devpriv
->pcidev
= pci_device
;
177 dev
->board_name
= board
->name
;
179 /* enable PCI device and request regions */
180 error
= comedi_pci_enable(pci_device
, CNT_DRIVER_NAME
);
182 printk(KERN_WARNING
"comedi%d: "
183 "failed to enable PCI device and request regions!\n",
188 /* read register base address [PCI_BASE_ADDRESS #0] */
189 io_base
= pci_resource_start(pci_device
, 0);
190 dev
->iobase
= io_base
;
192 error
= comedi_alloc_subdevices(dev
, 1);
196 subdevice
= dev
->subdevices
+ 0;
197 dev
->read_subdev
= subdevice
;
199 subdevice
->type
= COMEDI_SUBD_COUNTER
;
200 subdevice
->subdev_flags
= SDF_READABLE
/* | SDF_COMMON */ ;
201 subdevice
->n_chan
= board
->cnt_channel_nbr
;
202 subdevice
->maxdata
= (1 << board
->cnt_bits
) - 1;
203 subdevice
->insn_read
= cnt_rinsn
;
204 subdevice
->insn_write
= cnt_winsn
;
206 /* select 20MHz clock */
207 outb(3, dev
->iobase
+ 248);
209 /* reset all counters */
210 outb(0, dev
->iobase
);
211 outb(0, dev
->iobase
+ 0x20);
212 outb(0, dev
->iobase
+ 0x40);
214 printk(KERN_INFO
"comedi%d: " CNT_DRIVER_NAME
" attached.\n",
219 static void cnt_detach(struct comedi_device
*dev
)
221 if (devpriv
&& devpriv
->pcidev
) {
223 comedi_pci_disable(devpriv
->pcidev
);
224 pci_dev_put(devpriv
->pcidev
);
228 static struct comedi_driver ke_counter_driver
= {
229 .driver_name
= "ke_counter",
230 .module
= THIS_MODULE
,
231 .attach
= cnt_attach
,
232 .detach
= cnt_detach
,
235 static int __devinit
ke_counter_pci_probe(struct pci_dev
*dev
,
236 const struct pci_device_id
*ent
)
238 return comedi_pci_auto_config(dev
, &ke_counter_driver
);
241 static void __devexit
ke_counter_pci_remove(struct pci_dev
*dev
)
243 comedi_pci_auto_unconfig(dev
);
246 static DEFINE_PCI_DEVICE_TABLE(ke_counter_pci_table
) = {
247 { PCI_DEVICE(PCI_VENDOR_ID_KOLTER
, CNT_CARD_DEVICE_ID
) },
250 MODULE_DEVICE_TABLE(pci
, ke_counter_pci_table
);
252 static struct pci_driver ke_counter_pci_driver
= {
253 .name
= "ke_counter",
254 .id_table
= ke_counter_pci_table
,
255 .probe
= ke_counter_pci_probe
,
256 .remove
= __devexit_p(ke_counter_pci_remove
),
258 module_comedi_pci_driver(ke_counter_driver
, ke_counter_pci_driver
);
260 MODULE_AUTHOR("Comedi http://www.comedi.org");
261 MODULE_DESCRIPTION("Comedi low-level driver");
262 MODULE_LICENSE("GPL");