Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ke_counter.c
Go to the documentation of this file.
1 /*
2  comedi/drivers/ke_counter.c
3  Comedi driver for Kolter-Electronic PCI Counter 1 Card
4 
5  COMEDI - Linux Control and Measurement Device Interface
6  Copyright (C) 2000 David A. Schleef <[email protected]>
7 
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.
12 
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.
17 
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.
21 
22 */
23 /*
24 Driver: ke_counter
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
29 Status: tested
30 
31 Configuration Options: not applicable, uses PCI auto config
32 
33 This driver is a simple driver to read the counter values from
34 Kolter Electronic PCI Counter Card.
35 */
36 
37 #include "../comedidev.h"
38 
39 #define CNT_DRIVER_NAME "ke_counter"
40 #define PCI_VENDOR_ID_KOLTER 0x1001
41 #define CNT_CARD_DEVICE_ID 0x0014
42 
43 /*-- board specification structure ------------------------------------------*/
44 
46 
47  const char *name;
48  int device_id;
50  int cnt_bits;
51 };
52 
53 static const struct cnt_board_struct cnt_boards[] = {
54  {
55  .name = CNT_DRIVER_NAME,
56  .device_id = CNT_CARD_DEVICE_ID,
57  .cnt_channel_nbr = 3,
58  .cnt_bits = 24}
59 };
60 
61 /*-- counter write ----------------------------------------------------------*/
62 
63 /* This should be used only for resetting the counters; maybe it is better
64  to make a special command 'reset'. */
65 static int cnt_winsn(struct comedi_device *dev,
66  struct comedi_subdevice *s, struct comedi_insn *insn,
67  unsigned int *data)
68 {
69  int chan = CR_CHAN(insn->chanspec);
70 
71  outb((unsigned char)((data[0] >> 24) & 0xff),
72  dev->iobase + chan * 0x20 + 0x10);
73  outb((unsigned char)((data[0] >> 16) & 0xff),
74  dev->iobase + chan * 0x20 + 0x0c);
75  outb((unsigned char)((data[0] >> 8) & 0xff),
76  dev->iobase + chan * 0x20 + 0x08);
77  outb((unsigned char)((data[0] >> 0) & 0xff),
78  dev->iobase + chan * 0x20 + 0x04);
79 
80  /* return the number of samples written */
81  return 1;
82 }
83 
84 /*-- counter read -----------------------------------------------------------*/
85 
86 static int cnt_rinsn(struct comedi_device *dev,
87  struct comedi_subdevice *s, struct comedi_insn *insn,
88  unsigned int *data)
89 {
90  unsigned char a0, a1, a2, a3, a4;
91  int chan = CR_CHAN(insn->chanspec);
92  int result;
93 
94  a0 = inb(dev->iobase + chan * 0x20);
95  a1 = inb(dev->iobase + chan * 0x20 + 0x04);
96  a2 = inb(dev->iobase + chan * 0x20 + 0x08);
97  a3 = inb(dev->iobase + chan * 0x20 + 0x0c);
98  a4 = inb(dev->iobase + chan * 0x20 + 0x10);
99 
100  result = (a1 + (a2 * 256) + (a3 * 65536));
101  if (a4 > 0)
102  result = result - s->maxdata;
103 
104  *data = (unsigned int)result;
105 
106  /* return the number of samples read */
107  return 1;
108 }
109 
110 static const void *cnt_find_boardinfo(struct comedi_device *dev,
111  struct pci_dev *pcidev)
112 {
113  const struct cnt_board_struct *board;
114  int i;
115 
116  for (i = 0; i < ARRAY_SIZE(cnt_boards); i++) {
117  board = &cnt_boards[i];
118  if (board->device_id == pcidev->device)
119  return board;
120  }
121  return NULL;
122 }
123 
124 static int cnt_attach_pci(struct comedi_device *dev,
125  struct pci_dev *pcidev)
126 {
127  const struct cnt_board_struct *board;
128  struct comedi_subdevice *s;
129  int ret;
130 
131  comedi_set_hw_dev(dev, &pcidev->dev);
132 
133  board = cnt_find_boardinfo(dev, pcidev);
134  if (!board)
135  return -ENODEV;
136  dev->board_ptr = board;
137  dev->board_name = board->name;
138 
139  ret = comedi_pci_enable(pcidev, dev->board_name);
140  if (ret)
141  return ret;
142  dev->iobase = pci_resource_start(pcidev, 0);
143 
144  ret = comedi_alloc_subdevices(dev, 1);
145  if (ret)
146  return ret;
147 
148  s = &dev->subdevices[0];
149  dev->read_subdev = s;
150 
152  s->subdev_flags = SDF_READABLE /* | SDF_COMMON */ ;
153  s->n_chan = board->cnt_channel_nbr;
154  s->maxdata = (1 << board->cnt_bits) - 1;
155  s->insn_read = cnt_rinsn;
156  s->insn_write = cnt_winsn;
157 
158  /* select 20MHz clock */
159  outb(3, dev->iobase + 248);
160 
161  /* reset all counters */
162  outb(0, dev->iobase);
163  outb(0, dev->iobase + 0x20);
164  outb(0, dev->iobase + 0x40);
165 
166  dev_info(dev->class_dev, "%s: %s attached\n",
167  dev->driver->driver_name, dev->board_name);
168 
169  return 0;
170 }
171 
172 static void cnt_detach(struct comedi_device *dev)
173 {
174  struct pci_dev *pcidev = comedi_to_pci_dev(dev);
175 
176  if (pcidev) {
177  if (dev->iobase)
178  comedi_pci_disable(pcidev);
179  }
180 }
181 
182 static struct comedi_driver ke_counter_driver = {
183  .driver_name = "ke_counter",
184  .module = THIS_MODULE,
185  .attach_pci = cnt_attach_pci,
186  .detach = cnt_detach,
187 };
188 
189 static int __devinit ke_counter_pci_probe(struct pci_dev *dev,
190  const struct pci_device_id *ent)
191 {
192  return comedi_pci_auto_config(dev, &ke_counter_driver);
193 }
194 
195 static void __devexit ke_counter_pci_remove(struct pci_dev *dev)
196 {
198 }
199 
200 static DEFINE_PCI_DEVICE_TABLE(ke_counter_pci_table) = {
202  { 0 }
203 };
204 MODULE_DEVICE_TABLE(pci, ke_counter_pci_table);
205 
206 static struct pci_driver ke_counter_pci_driver = {
207  .name = "ke_counter",
208  .id_table = ke_counter_pci_table,
209  .probe = ke_counter_pci_probe,
210  .remove = __devexit_p(ke_counter_pci_remove),
211 };
212 module_comedi_pci_driver(ke_counter_driver, ke_counter_pci_driver);
213 
214 MODULE_AUTHOR("Comedi http://www.comedi.org");
215 MODULE_DESCRIPTION("Comedi low-level driver");
216 MODULE_LICENSE("GPL");