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
56
57
58#define BADR0_SIZE 2
59#define BADR1_SIZE 4
60#define BADR2_SIZE 6
61#define BADR3_SIZE 16
62#define BADR4_SIZE 4
63
64
65#define ADC_TRIG 0
66#define DAC0_OFFSET 2
67#define DAC1_OFFSET 4
68
69
70#define MUX_LIMITS 0
71#define MAIN_CONN_DIO 1
72#define ADC_STAT 2
73#define ADC_CONV_STAT 3
74#define ADC_INT 4
75#define ADC_PACER 5
76#define BURST_MODE 6
77#define PROG_GAIN 7
78#define CLK8254_1_DATA 8
79#define CLK8254_2_DATA 9
80#define CLK8254_3_DATA 10
81#define CLK8254_CONTROL 11
82#define USER_COUNTER 12
83#define RESID_COUNT_H 13
84#define RESID_COUNT_L 14
85
86
87struct cb_pcimdas_board {
88 const char *name;
89 unsigned short device_id;
90 int ai_se_chans;
91 int ai_diff_chans;
92 int ai_bits;
93 int ai_speed;
94 int ao_nchan;
95 int ao_bits;
96 int has_ao_fifo;
97 int ao_scan_speed;
98 int fifo_size;
99 int dio_bits;
100 int has_dio;
101 const struct comedi_lrange *ranges;
102};
103
104static const struct cb_pcimdas_board cb_pcimdas_boards[] = {
105 {
106 .name = "PCIM-DAS1602/16",
107 .device_id = 0x56,
108 .ai_se_chans = 16,
109 .ai_diff_chans = 8,
110 .ai_bits = 16,
111 .ai_speed = 10000,
112 .ao_nchan = 2,
113 .ao_bits = 12,
114 .has_ao_fifo = 0,
115 .ao_scan_speed = 10000,
116
117 .fifo_size = 1024,
118 .dio_bits = 24,
119 .has_dio = 1,
120
121 },
122};
123
124
125
126static DEFINE_PCI_DEVICE_TABLE(cb_pcimdas_pci_table) = {
127 {
128 PCI_VENDOR_ID_COMPUTERBOARDS, 0x0056, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
129 {
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;
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 (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
229 pcidev != NULL;
230 pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
231
232 if (pcidev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS)
233 continue;
234
235 for (index = 0; index < N_BOARDS; index++) {
236 if (cb_pcimdas_boards[index].device_id !=
237 pcidev->device)
238 continue;
239
240 if (it->options[0] || it->options[1]) {
241
242 if (pcidev->bus->number != it->options[0] ||
243 PCI_SLOT(pcidev->devfn) != it->options[1]) {
244 continue;
245 }
246 }
247 devpriv->pci_dev = pcidev;
248 dev->board_ptr = cb_pcimdas_boards + index;
249 goto found;
250 }
251 }
252
253 printk("No supported ComputerBoards/MeasurementComputing card found on "
254 "requested position\n");
255 return -EIO;
256
257found:
258
259 printk("Found %s on bus %i, slot %i\n", cb_pcimdas_boards[index].name,
260 pcidev->bus->number, PCI_SLOT(pcidev->devfn));
261
262
263 switch (thisboard->device_id) {
264 case 0x56:
265 break;
266 default:
267 printk("THIS CARD IS UNSUPPORTED.\n"
268 "PLEASE REPORT USAGE TO <mocelet@sucs.org>\n");
269 };
270
271 if (comedi_pci_enable(pcidev, "cb_pcimdas")) {
272 printk(" Failed to enable PCI device and request regions\n");
273 return -EIO;
274 }
275
276 devpriv->BADR0 = pci_resource_start(devpriv->pci_dev, 0);
277 devpriv->BADR1 = pci_resource_start(devpriv->pci_dev, 1);
278 devpriv->BADR2 = pci_resource_start(devpriv->pci_dev, 2);
279 devpriv->BADR3 = pci_resource_start(devpriv->pci_dev, 3);
280 devpriv->BADR4 = pci_resource_start(devpriv->pci_dev, 4);
281
282#ifdef CBPCIMDAS_DEBUG
283 printk("devpriv->BADR0 = 0x%lx\n", devpriv->BADR0);
284 printk("devpriv->BADR1 = 0x%lx\n", devpriv->BADR1);
285 printk("devpriv->BADR2 = 0x%lx\n", devpriv->BADR2);
286 printk("devpriv->BADR3 = 0x%lx\n", devpriv->BADR3);
287 printk("devpriv->BADR4 = 0x%lx\n", devpriv->BADR4);
288#endif
289
290
291
292
293
294
295
296
297
298
299
300 dev->board_name = thisboard->name;
301
302
303
304
305
306 if (alloc_subdevices(dev, 3) < 0)
307 return -ENOMEM;
308
309 s = dev->subdevices + 0;
310
311
312 s->type = COMEDI_SUBD_AI;
313 s->subdev_flags = SDF_READABLE | SDF_GROUND;
314 s->n_chan = thisboard->ai_se_chans;
315 s->maxdata = (1 << thisboard->ai_bits) - 1;
316 s->range_table = &range_unknown;
317 s->len_chanlist = 1;
318
319 s->insn_read = cb_pcimdas_ai_rinsn;
320
321 s = dev->subdevices + 1;
322
323 s->type = COMEDI_SUBD_AO;
324 s->subdev_flags = SDF_WRITABLE;
325 s->n_chan = thisboard->ao_nchan;
326 s->maxdata = 1 << thisboard->ao_bits;
327 s->range_table = &range_unknown;
328 s->insn_write = &cb_pcimdas_ao_winsn;
329 s->insn_read = &cb_pcimdas_ao_rinsn;
330
331 s = dev->subdevices + 2;
332
333 if (thisboard->has_dio) {
334 subdev_8255_init(dev, s, NULL, devpriv->BADR4);
335 } else {
336 s->type = COMEDI_SUBD_UNUSED;
337 }
338
339 printk("attached\n");
340
341 return 1;
342}
343
344
345
346
347
348
349
350
351
352static int cb_pcimdas_detach(struct comedi_device *dev)
353{
354#ifdef CBPCIMDAS_DEBUG
355 if (devpriv) {
356 printk("devpriv->BADR0 = 0x%lx\n", devpriv->BADR0);
357 printk("devpriv->BADR1 = 0x%lx\n", devpriv->BADR1);
358 printk("devpriv->BADR2 = 0x%lx\n", devpriv->BADR2);
359 printk("devpriv->BADR3 = 0x%lx\n", devpriv->BADR3);
360 printk("devpriv->BADR4 = 0x%lx\n", devpriv->BADR4);
361 }
362#endif
363 printk("comedi%d: cb_pcimdas: remove\n", dev->minor);
364 if (dev->irq)
365 free_irq(dev->irq, dev);
366 if (devpriv) {
367 if (devpriv->pci_dev) {
368 if (devpriv->BADR0) {
369 comedi_pci_disable(devpriv->pci_dev);
370 }
371 pci_dev_put(devpriv->pci_dev);
372 }
373 }
374
375 return 0;
376}
377
378
379
380
381
382static int cb_pcimdas_ai_rinsn(struct comedi_device *dev,
383 struct comedi_subdevice *s,
384 struct comedi_insn *insn, unsigned int *data)
385{
386 int n, i;
387 unsigned int d;
388 unsigned int busy;
389 int chan = CR_CHAN(insn->chanspec);
390 unsigned short chanlims;
391 int maxchans;
392
393
394
395
396 if ((inb(devpriv->BADR3 + 2) & 0x20) == 0)
397 maxchans = thisboard->ai_diff_chans;
398 else
399 maxchans = thisboard->ai_se_chans;
400
401 if (chan > (maxchans - 1))
402 return -ETIMEDOUT;
403
404
405 d = inb(devpriv->BADR3 + 5);
406 if ((d & 0x03) > 0) {
407 d = d & 0xfd;
408 outb(d, devpriv->BADR3 + 5);
409 }
410 outb(0x01, devpriv->BADR3 + 6);
411 outb(0x00, devpriv->BADR3 + 7);
412
413
414 chanlims = chan | (chan << 4);
415 outb(chanlims, devpriv->BADR3 + 0);
416
417
418 for (n = 0; n < insn->n; n++) {
419
420 outw(0, devpriv->BADR2 + 0);
421
422#define TIMEOUT 1000
423
424
425
426 for (i = 0; i < TIMEOUT; i++) {
427 busy = inb(devpriv->BADR3 + 2) & 0x80;
428 if (!busy)
429 break;
430 }
431 if (i == TIMEOUT) {
432 printk("timeout\n");
433 return -ETIMEDOUT;
434 }
435
436 d = inw(devpriv->BADR2 + 0);
437
438
439
440
441 data[n] = d;
442 }
443
444
445 return n;
446}
447
448static int cb_pcimdas_ao_winsn(struct comedi_device *dev,
449 struct comedi_subdevice *s,
450 struct comedi_insn *insn, unsigned int *data)
451{
452 int i;
453 int chan = CR_CHAN(insn->chanspec);
454
455
456
457 for (i = 0; i < insn->n; i++) {
458 switch (chan) {
459 case 0:
460 outw(data[i] & 0x0FFF, devpriv->BADR2 + DAC0_OFFSET);
461 break;
462 case 1:
463 outw(data[i] & 0x0FFF, devpriv->BADR2 + DAC1_OFFSET);
464 break;
465 default:
466 return -1;
467 }
468 devpriv->ao_readback[chan] = data[i];
469 }
470
471
472 return i;
473}
474
475
476
477static int cb_pcimdas_ao_rinsn(struct comedi_device *dev,
478 struct comedi_subdevice *s,
479 struct comedi_insn *insn, unsigned int *data)
480{
481 int i;
482 int chan = CR_CHAN(insn->chanspec);
483
484 for (i = 0; i < insn->n; i++)
485 data[i] = devpriv->ao_readback[chan];
486
487 return i;
488}
489
490
491
492
493
494COMEDI_PCI_INITCLEANUP(driver_cb_pcimdas, cb_pcimdas_pci_table);
495