1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43#include "../comedidev.h"
44
45#include <linux/delay.h>
46#include <linux/interrupt.h>
47
48#include "comedi_pci.h"
49#include "plx9052.h"
50#include "8255.h"
51
52
53#undef CBPCIMDAS_DEBUG
54
55#define PCI_VENDOR_ID_COMPUTERBOARDS 0x1307
56
57
58
59
60#define BADR0_SIZE 2
61#define BADR1_SIZE 4
62#define BADR2_SIZE 6
63#define BADR3_SIZE 16
64#define BADR4_SIZE 4
65
66
67#define ADC_TRIG 0
68#define DAC0_OFFSET 2
69#define DAC1_OFFSET 4
70
71
72#define MUX_LIMITS 0
73#define MAIN_CONN_DIO 1
74#define ADC_STAT 2
75#define ADC_CONV_STAT 3
76#define ADC_INT 4
77#define ADC_PACER 5
78#define BURST_MODE 6
79#define PROG_GAIN 7
80#define CLK8254_1_DATA 8
81#define CLK8254_2_DATA 9
82#define CLK8254_3_DATA 10
83#define CLK8254_CONTROL 11
84#define USER_COUNTER 12
85#define RESID_COUNT_H 13
86#define RESID_COUNT_L 14
87
88
89struct cb_pcimdas_board {
90 const char *name;
91 unsigned short device_id;
92 int ai_se_chans;
93 int ai_diff_chans;
94 int ai_bits;
95 int ai_speed;
96 int ao_nchan;
97 int ao_bits;
98 int has_ao_fifo;
99 int ao_scan_speed;
100 int fifo_size;
101 int dio_bits;
102 int has_dio;
103 const struct comedi_lrange *ranges;
104};
105
106static const struct cb_pcimdas_board cb_pcimdas_boards[] = {
107 {
108 .name = "PCIM-DAS1602/16",
109 .device_id = 0x56,
110 .ai_se_chans = 16,
111 .ai_diff_chans = 8,
112 .ai_bits = 16,
113 .ai_speed = 10000,
114 .ao_nchan = 2,
115 .ao_bits = 12,
116 .has_ao_fifo = 0,
117 .ao_scan_speed = 10000,
118
119 .fifo_size = 1024,
120 .dio_bits = 24,
121 .has_dio = 1,
122
123 },
124};
125
126
127
128static DEFINE_PCI_DEVICE_TABLE(cb_pcimdas_pci_table) = {
129 { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0056) },
130 { 0 }
131};
132
133MODULE_DEVICE_TABLE(pci, cb_pcimdas_pci_table);
134
135#define N_BOARDS 1
136
137
138
139
140#define thisboard ((const struct cb_pcimdas_board *)dev->board_ptr)
141
142
143
144
145struct cb_pcimdas_private {
146 int data;
147
148
149 struct pci_dev *pci_dev;
150
151
152 unsigned long BADR0;
153 unsigned long BADR1;
154 unsigned long BADR2;
155 unsigned long BADR3;
156 unsigned long BADR4;
157
158
159 unsigned int ao_readback[2];
160
161
162 unsigned short int port_a;
163 unsigned short int port_b;
164 unsigned short int port_c;
165 unsigned short int dio_mode;
166
167};
168
169
170
171
172
173#define devpriv ((struct cb_pcimdas_private *)dev->private)
174
175
176
177
178
179
180
181static int cb_pcimdas_attach(struct comedi_device *dev,
182 struct comedi_devconfig *it);
183static int cb_pcimdas_detach(struct comedi_device *dev);
184static struct comedi_driver driver_cb_pcimdas = {
185 .driver_name = "cb_pcimdas",
186 .module = THIS_MODULE,
187 .attach = cb_pcimdas_attach,
188 .detach = cb_pcimdas_detach,
189};
190
191static int cb_pcimdas_ai_rinsn(struct comedi_device *dev,
192 struct comedi_subdevice *s,
193 struct comedi_insn *insn, unsigned int *data);
194static int cb_pcimdas_ao_winsn(struct comedi_device *dev,
195 struct comedi_subdevice *s,
196 struct comedi_insn *insn, unsigned int *data);
197static int cb_pcimdas_ao_rinsn(struct comedi_device *dev,
198 struct comedi_subdevice *s,
199 struct comedi_insn *insn, unsigned int *data);
200
201
202
203
204
205
206
207static int cb_pcimdas_attach(struct comedi_device *dev,
208 struct comedi_devconfig *it)
209{
210 struct comedi_subdevice *s;
211 struct pci_dev *pcidev = NULL;
212 int index;
213
214
215 printk("comedi%d: cb_pcimdas: ", dev->minor);
216
217
218
219
220 if (alloc_private(dev, sizeof(struct cb_pcimdas_private)) < 0)
221 return -ENOMEM;
222
223
224
225
226 printk("\n");
227
228 for_each_pci_dev(pcidev) {
229
230 if (pcidev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS)
231 continue;
232
233 for (index = 0; index < N_BOARDS; index++) {
234 if (cb_pcimdas_boards[index].device_id !=
235 pcidev->device)
236 continue;
237
238 if (it->options[0] || it->options[1]) {
239
240 if (pcidev->bus->number != it->options[0] ||
241 PCI_SLOT(pcidev->devfn) != it->options[1]) {
242 continue;
243 }
244 }
245 devpriv->pci_dev = pcidev;
246 dev->board_ptr = cb_pcimdas_boards + index;
247 goto found;
248 }
249 }
250
251 printk("No supported ComputerBoards/MeasurementComputing card found on "
252 "requested position\n");
253 return -EIO;
254
255found:
256
257 printk("Found %s on bus %i, slot %i\n", cb_pcimdas_boards[index].name,
258 pcidev->bus->number, PCI_SLOT(pcidev->devfn));
259
260
261 switch (thisboard->device_id) {
262 case 0x56:
263 break;
264 default:
265 printk("THIS CARD IS UNSUPPORTED.\n"
266 "PLEASE REPORT USAGE TO <mocelet@sucs.org>\n");
267 }
268
269 if (comedi_pci_enable(pcidev, "cb_pcimdas")) {
270 printk(" Failed to enable PCI device and request regions\n");
271 return -EIO;
272 }
273
274 devpriv->BADR0 = pci_resource_start(devpriv->pci_dev, 0);
275 devpriv->BADR1 = pci_resource_start(devpriv->pci_dev, 1);
276 devpriv->BADR2 = pci_resource_start(devpriv->pci_dev, 2);
277 devpriv->BADR3 = pci_resource_start(devpriv->pci_dev, 3);
278 devpriv->BADR4 = pci_resource_start(devpriv->pci_dev, 4);
279
280#ifdef CBPCIMDAS_DEBUG
281 printk("devpriv->BADR0 = 0x%lx\n", devpriv->BADR0);
282 printk("devpriv->BADR1 = 0x%lx\n", devpriv->BADR1);
283 printk("devpriv->BADR2 = 0x%lx\n", devpriv->BADR2);
284 printk("devpriv->BADR3 = 0x%lx\n", devpriv->BADR3);
285 printk("devpriv->BADR4 = 0x%lx\n", devpriv->BADR4);
286#endif
287
288
289
290
291
292
293
294
295
296
297
298 dev->board_name = thisboard->name;
299
300
301
302
303
304 if (alloc_subdevices(dev, 3) < 0)
305 return -ENOMEM;
306
307 s = dev->subdevices + 0;
308
309
310 s->type = COMEDI_SUBD_AI;
311 s->subdev_flags = SDF_READABLE | SDF_GROUND;
312 s->n_chan = thisboard->ai_se_chans;
313 s->maxdata = (1 << thisboard->ai_bits) - 1;
314 s->range_table = &range_unknown;
315 s->len_chanlist = 1;
316
317 s->insn_read = cb_pcimdas_ai_rinsn;
318
319 s = dev->subdevices + 1;
320
321 s->type = COMEDI_SUBD_AO;
322 s->subdev_flags = SDF_WRITABLE;
323 s->n_chan = thisboard->ao_nchan;
324 s->maxdata = 1 << thisboard->ao_bits;
325 s->range_table = &range_unknown;
326 s->insn_write = &cb_pcimdas_ao_winsn;
327 s->insn_read = &cb_pcimdas_ao_rinsn;
328
329 s = dev->subdevices + 2;
330
331 if (thisboard->has_dio)
332 subdev_8255_init(dev, s, NULL, devpriv->BADR4);
333 else
334 s->type = COMEDI_SUBD_UNUSED;
335
336 printk("attached\n");
337
338 return 1;
339}
340
341
342
343
344
345
346
347
348
349static int cb_pcimdas_detach(struct comedi_device *dev)
350{
351#ifdef CBPCIMDAS_DEBUG
352 if (devpriv) {
353 printk("devpriv->BADR0 = 0x%lx\n", devpriv->BADR0);
354 printk("devpriv->BADR1 = 0x%lx\n", devpriv->BADR1);
355 printk("devpriv->BADR2 = 0x%lx\n", devpriv->BADR2);
356 printk("devpriv->BADR3 = 0x%lx\n", devpriv->BADR3);
357 printk("devpriv->BADR4 = 0x%lx\n", devpriv->BADR4);
358 }
359#endif
360 printk("comedi%d: cb_pcimdas: remove\n", dev->minor);
361 if (dev->irq)
362 free_irq(dev->irq, dev);
363 if (devpriv) {
364 if (devpriv->pci_dev) {
365 if (devpriv->BADR0)
366 comedi_pci_disable(devpriv->pci_dev);
367 pci_dev_put(devpriv->pci_dev);
368 }
369 }
370
371 return 0;
372}
373
374
375
376
377
378static int cb_pcimdas_ai_rinsn(struct comedi_device *dev,
379 struct comedi_subdevice *s,
380 struct comedi_insn *insn, unsigned int *data)
381{
382 int n, i;
383 unsigned int d;
384 unsigned int busy;
385 int chan = CR_CHAN(insn->chanspec);
386 unsigned short chanlims;
387 int maxchans;
388
389
390
391
392 if ((inb(devpriv->BADR3 + 2) & 0x20) == 0)
393 maxchans = thisboard->ai_diff_chans;
394 else
395 maxchans = thisboard->ai_se_chans;
396
397 if (chan > (maxchans - 1))
398 return -ETIMEDOUT;
399
400
401 d = inb(devpriv->BADR3 + 5);
402 if ((d & 0x03) > 0) {
403 d = d & 0xfd;
404 outb(d, devpriv->BADR3 + 5);
405 }
406 outb(0x01, devpriv->BADR3 + 6);
407 outb(0x00, devpriv->BADR3 + 7);
408
409
410 chanlims = chan | (chan << 4);
411 outb(chanlims, devpriv->BADR3 + 0);
412
413
414 for (n = 0; n < insn->n; n++) {
415
416 outw(0, devpriv->BADR2 + 0);
417
418#define TIMEOUT 1000
419
420
421
422 for (i = 0; i < TIMEOUT; i++) {
423 busy = inb(devpriv->BADR3 + 2) & 0x80;
424 if (!busy)
425 break;
426 }
427 if (i == TIMEOUT) {
428 printk("timeout\n");
429 return -ETIMEDOUT;
430 }
431
432 d = inw(devpriv->BADR2 + 0);
433
434
435
436
437 data[n] = d;
438 }
439
440
441 return n;
442}
443
444static int cb_pcimdas_ao_winsn(struct comedi_device *dev,
445 struct comedi_subdevice *s,
446 struct comedi_insn *insn, unsigned int *data)
447{
448 int i;
449 int chan = CR_CHAN(insn->chanspec);
450
451
452
453 for (i = 0; i < insn->n; i++) {
454 switch (chan) {
455 case 0:
456 outw(data[i] & 0x0FFF, devpriv->BADR2 + DAC0_OFFSET);
457 break;
458 case 1:
459 outw(data[i] & 0x0FFF, devpriv->BADR2 + DAC1_OFFSET);
460 break;
461 default:
462 return -1;
463 }
464 devpriv->ao_readback[chan] = data[i];
465 }
466
467
468 return i;
469}
470
471
472
473static int cb_pcimdas_ao_rinsn(struct comedi_device *dev,
474 struct comedi_subdevice *s,
475 struct comedi_insn *insn, unsigned int *data)
476{
477 int i;
478 int chan = CR_CHAN(insn->chanspec);
479
480 for (i = 0; i < insn->n; i++)
481 data[i] = devpriv->ao_readback[chan];
482
483 return i;
484}
485
486
487
488
489
490static int __devinit driver_cb_pcimdas_pci_probe(struct pci_dev *dev,
491 const struct pci_device_id
492 *ent)
493{
494 return comedi_pci_auto_config(dev, driver_cb_pcimdas.driver_name);
495}
496
497static void __devexit driver_cb_pcimdas_pci_remove(struct pci_dev *dev)
498{
499 comedi_pci_auto_unconfig(dev);
500}
501
502static struct pci_driver driver_cb_pcimdas_pci_driver = {
503 .id_table = cb_pcimdas_pci_table,
504 .probe = &driver_cb_pcimdas_pci_probe,
505 .remove = __devexit_p(&driver_cb_pcimdas_pci_remove)
506};
507
508static int __init driver_cb_pcimdas_init_module(void)
509{
510 int retval;
511
512 retval = comedi_driver_register(&driver_cb_pcimdas);
513 if (retval < 0)
514 return retval;
515
516 driver_cb_pcimdas_pci_driver.name =
517 (char *)driver_cb_pcimdas.driver_name;
518 return pci_register_driver(&driver_cb_pcimdas_pci_driver);
519}
520
521static void __exit driver_cb_pcimdas_cleanup_module(void)
522{
523 pci_unregister_driver(&driver_cb_pcimdas_pci_driver);
524 comedi_driver_unregister(&driver_cb_pcimdas);
525}
526
527module_init(driver_cb_pcimdas_init_module);
528module_exit(driver_cb_pcimdas_cleanup_module);
529
530MODULE_AUTHOR("Comedi http://www.comedi.org");
531MODULE_DESCRIPTION("Comedi low-level driver");
532MODULE_LICENSE("GPL");
533