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