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.
21 * Description: Driver for Kolter Electronic Counter Card
22 * Devices: (Kolter Electronic) PCI Counter Card [ke_counter]
23 * Author: Michael Hillmann
24 * Updated: Mon, 14 Apr 2008 15:42:42 +0100
27 * Configuration Options: not applicable, uses PCI auto config
30 #include <linux/module.h>
31 #include <linux/pci.h>
33 #include "../comedidev.h"
36 * PCI BAR 0 Register I/O map
38 #define KE_RESET_REG(x) (0x00 + ((x) * 0x20))
39 #define KE_LATCH_REG(x) (0x00 + ((x) * 0x20))
40 #define KE_LSB_REG(x) (0x04 + ((x) * 0x20))
41 #define KE_MID_REG(x) (0x08 + ((x) * 0x20))
42 #define KE_MSB_REG(x) (0x0c + ((x) * 0x20))
43 #define KE_SIGN_REG(x) (0x10 + ((x) * 0x20))
44 #define KE_OSC_SEL_REG 0xf8
45 #define KE_OSC_SEL_EXT (1 << 0)
46 #define KE_OSC_SEL_4MHZ (2 << 0)
47 #define KE_OSC_SEL_20MHZ (3 << 0)
48 #define KE_DO_REG 0xfc
50 static int ke_counter_insn_write(struct comedi_device
*dev
,
51 struct comedi_subdevice
*s
,
52 struct comedi_insn
*insn
,
55 unsigned int chan
= CR_CHAN(insn
->chanspec
);
59 for (i
= 0; i
< insn
->n
; i
++) {
63 outb((val
>> 24) & 0xff, dev
->iobase
+ KE_SIGN_REG(chan
));
64 outb((val
>> 16) & 0xff, dev
->iobase
+ KE_MSB_REG(chan
));
65 outb((val
>> 8) & 0xff, dev
->iobase
+ KE_MID_REG(chan
));
66 outb((val
>> 0) & 0xff, dev
->iobase
+ KE_LSB_REG(chan
));
72 static int ke_counter_insn_read(struct comedi_device
*dev
,
73 struct comedi_subdevice
*s
,
74 struct comedi_insn
*insn
,
77 unsigned int chan
= CR_CHAN(insn
->chanspec
);
81 for (i
= 0; i
< insn
->n
; i
++) {
83 inb(dev
->iobase
+ KE_LATCH_REG(chan
));
85 val
= inb(dev
->iobase
+ KE_LSB_REG(chan
));
86 val
|= (inb(dev
->iobase
+ KE_MID_REG(chan
)) << 8);
87 val
|= (inb(dev
->iobase
+ KE_MSB_REG(chan
)) << 16);
88 val
|= (inb(dev
->iobase
+ KE_SIGN_REG(chan
)) << 24);
96 static void ke_counter_reset(struct comedi_device
*dev
)
100 for (chan
= 0; chan
< 3; chan
++)
101 outb(0, dev
->iobase
+ KE_RESET_REG(chan
));
104 static int ke_counter_insn_config(struct comedi_device
*dev
,
105 struct comedi_subdevice
*s
,
106 struct comedi_insn
*insn
,
112 case INSN_CONFIG_SET_CLOCK_SRC
:
114 case KE_CLK_20MHZ
: /* default */
115 src
= KE_OSC_SEL_20MHZ
;
117 case KE_CLK_4MHZ
: /* option */
118 src
= KE_OSC_SEL_4MHZ
;
120 case KE_CLK_EXT
: /* Pin 21 on D-sub */
121 src
= KE_OSC_SEL_EXT
;
126 outb(src
, dev
->iobase
+ KE_OSC_SEL_REG
);
128 case INSN_CONFIG_GET_CLOCK_SRC
:
129 src
= inb(dev
->iobase
+ KE_OSC_SEL_REG
);
131 case KE_OSC_SEL_20MHZ
:
132 data
[1] = KE_CLK_20MHZ
;
133 data
[2] = 50; /* 50ns */
135 case KE_OSC_SEL_4MHZ
:
136 data
[1] = KE_CLK_4MHZ
;
137 data
[2] = 250; /* 250ns */
140 data
[1] = KE_CLK_EXT
;
141 data
[2] = 0; /* Unknown */
147 case INSN_CONFIG_RESET
:
148 ke_counter_reset(dev
);
157 static int ke_counter_do_insn_bits(struct comedi_device
*dev
,
158 struct comedi_subdevice
*s
,
159 struct comedi_insn
*insn
,
162 if (comedi_dio_update_state(s
, data
))
163 outb(s
->state
, dev
->iobase
+ KE_DO_REG
);
170 static int ke_counter_auto_attach(struct comedi_device
*dev
,
171 unsigned long context_unused
)
173 struct pci_dev
*pcidev
= comedi_to_pci_dev(dev
);
174 struct comedi_subdevice
*s
;
177 ret
= comedi_pci_enable(dev
);
180 dev
->iobase
= pci_resource_start(pcidev
, 0);
182 ret
= comedi_alloc_subdevices(dev
, 2);
186 s
= &dev
->subdevices
[0];
187 s
->type
= COMEDI_SUBD_COUNTER
;
188 s
->subdev_flags
= SDF_READABLE
;
190 s
->maxdata
= 0x01ffffff;
191 s
->range_table
= &range_unknown
;
192 s
->insn_read
= ke_counter_insn_read
;
193 s
->insn_write
= ke_counter_insn_write
;
194 s
->insn_config
= ke_counter_insn_config
;
196 s
= &dev
->subdevices
[1];
197 s
->type
= COMEDI_SUBD_DO
;
198 s
->subdev_flags
= SDF_WRITABLE
;
201 s
->range_table
= &range_digital
;
202 s
->insn_bits
= ke_counter_do_insn_bits
;
204 outb(KE_OSC_SEL_20MHZ
, dev
->iobase
+ KE_OSC_SEL_REG
);
206 ke_counter_reset(dev
);
211 static struct comedi_driver ke_counter_driver
= {
212 .driver_name
= "ke_counter",
213 .module
= THIS_MODULE
,
214 .auto_attach
= ke_counter_auto_attach
,
215 .detach
= comedi_pci_detach
,
218 static int ke_counter_pci_probe(struct pci_dev
*dev
,
219 const struct pci_device_id
*id
)
221 return comedi_pci_auto_config(dev
, &ke_counter_driver
,
225 static const struct pci_device_id ke_counter_pci_table
[] = {
226 { PCI_DEVICE(PCI_VENDOR_ID_KOLTER
, 0x0014) },
229 MODULE_DEVICE_TABLE(pci
, ke_counter_pci_table
);
231 static struct pci_driver ke_counter_pci_driver
= {
232 .name
= "ke_counter",
233 .id_table
= ke_counter_pci_table
,
234 .probe
= ke_counter_pci_probe
,
235 .remove
= comedi_pci_auto_unconfig
,
237 module_comedi_pci_driver(ke_counter_driver
, ke_counter_pci_driver
);
239 MODULE_AUTHOR("Comedi http://www.comedi.org");
240 MODULE_DESCRIPTION("Comedi driver for Kolter Electronic Counter Card");
241 MODULE_LICENSE("GPL");