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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75#include "../comedidev.h"
76
77#include <linux/pci.h>
78
79
80
81#define SKEL_SIZE 0
82
83#define SKEL_START_AI_CONV 0
84#define SKEL_AI_READ 0
85
86
87
88
89
90
91struct skel_board {
92 const char *name;
93 int ai_chans;
94 int ai_bits;
95 int have_dio;
96};
97
98static const struct skel_board skel_boards[] = {
99 {
100 .name = "skel-100",
101 .ai_chans = 16,
102 .ai_bits = 12,
103 .have_dio = 1,
104 },
105 {
106 .name = "skel-200",
107 .ai_chans = 8,
108 .ai_bits = 16,
109 .have_dio = 0,
110 },
111};
112
113
114
115
116
117#define PCI_VENDOR_ID_SKEL 0xdafe
118static DEFINE_PCI_DEVICE_TABLE(skel_pci_table) = {
119 {
120 PCI_VENDOR_ID_SKEL, 0x0100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
121 PCI_VENDOR_ID_SKEL, 0x0200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
122 0}
123};
124
125MODULE_DEVICE_TABLE(pci, skel_pci_table);
126
127
128
129
130#define thisboard ((const struct skel_board *)dev->board_ptr)
131
132
133
134
135struct skel_private {
136
137 int data;
138
139
140 struct pci_dev *pci_dev;
141
142
143 unsigned int ao_readback[2];
144};
145
146
147
148
149
150#define devpriv ((struct skel_private *)dev->private)
151
152
153
154
155
156
157
158static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it);
159static int skel_detach(struct comedi_device *dev);
160static struct comedi_driver driver_skel = {
161 .driver_name = "dummy",
162 .module = THIS_MODULE,
163 .attach = skel_attach,
164 .detach = skel_detach,
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183 .board_name = &skel_boards[0].name,
184 .offset = sizeof(struct skel_board),
185 .num_names = ARRAY_SIZE(skel_boards),
186};
187
188static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
189 struct comedi_insn *insn, unsigned int *data);
190static int skel_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
191 struct comedi_insn *insn, unsigned int *data);
192static int skel_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
193 struct comedi_insn *insn, unsigned int *data);
194static int skel_dio_insn_bits(struct comedi_device *dev,
195 struct comedi_subdevice *s,
196 struct comedi_insn *insn, unsigned int *data);
197static int skel_dio_insn_config(struct comedi_device *dev,
198 struct comedi_subdevice *s,
199 struct comedi_insn *insn, unsigned int *data);
200static int skel_ai_cmdtest(struct comedi_device *dev,
201 struct comedi_subdevice *s, struct comedi_cmd *cmd);
202static int skel_ns_to_timer(unsigned int *ns, int round);
203
204
205
206
207
208
209
210static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it)
211{
212 struct comedi_subdevice *s;
213
214 printk("comedi%d: skel: ", dev->minor);
215
216
217
218
219
220
221
222
223
224
225
226
227 dev->board_name = thisboard->name;
228
229
230
231
232
233 if (alloc_private(dev, sizeof(struct skel_private)) < 0)
234 return -ENOMEM;
235
236
237
238
239
240 if (alloc_subdevices(dev, 3) < 0)
241 return -ENOMEM;
242
243 s = dev->subdevices + 0;
244
245
246 s->type = COMEDI_SUBD_AI;
247
248 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
249 s->n_chan = thisboard->ai_chans;
250 s->maxdata = (1 << thisboard->ai_bits) - 1;
251 s->range_table = &range_bipolar10;
252 s->len_chanlist = 16;
253
254 s->insn_read = skel_ai_rinsn;
255
256
257
258
259 s->do_cmdtest = skel_ai_cmdtest;
260
261 s = dev->subdevices + 1;
262
263 s->type = COMEDI_SUBD_AO;
264 s->subdev_flags = SDF_WRITABLE;
265 s->n_chan = 1;
266 s->maxdata = 0xffff;
267 s->range_table = &range_bipolar5;
268 s->insn_write = skel_ao_winsn;
269 s->insn_read = skel_ao_rinsn;
270
271 s = dev->subdevices + 2;
272
273 if (thisboard->have_dio) {
274 s->type = COMEDI_SUBD_DIO;
275 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
276 s->n_chan = 16;
277 s->maxdata = 1;
278 s->range_table = &range_digital;
279 s->insn_bits = skel_dio_insn_bits;
280 s->insn_config = skel_dio_insn_config;
281 } else {
282 s->type = COMEDI_SUBD_UNUSED;
283 }
284
285 printk("attached\n");
286
287 return 0;
288}
289
290
291
292
293
294
295
296
297
298static int skel_detach(struct comedi_device *dev)
299{
300 printk("comedi%d: skel: remove\n", dev->minor);
301
302 return 0;
303}
304
305
306
307
308
309static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
310 struct comedi_insn *insn, unsigned int *data)
311{
312 int n, i;
313 unsigned int d;
314 unsigned int status;
315
316
317
318
319
320
321
322
323
324 for (n = 0; n < insn->n; n++) {
325
326
327
328#define TIMEOUT 100
329
330 for (i = 0; i < TIMEOUT; i++) {
331 status = 1;
332
333 if (status)
334 break;
335 }
336 if (i == TIMEOUT) {
337
338
339 printk("timeout\n");
340 return -ETIMEDOUT;
341 }
342
343
344
345 d = 0;
346
347
348 d ^= 1 << (thisboard->ai_bits - 1);
349
350 data[n] = d;
351 }
352
353
354 return n;
355}
356
357static int skel_ai_cmdtest(struct comedi_device *dev,
358 struct comedi_subdevice *s, struct comedi_cmd *cmd)
359{
360 int err = 0;
361 int tmp;
362
363
364
365
366
367
368
369
370
371
372 tmp = cmd->start_src;
373 cmd->start_src &= TRIG_NOW;
374 if (!cmd->start_src || tmp != cmd->start_src)
375 err++;
376
377 tmp = cmd->scan_begin_src;
378 cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
379 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
380 err++;
381
382 tmp = cmd->convert_src;
383 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
384 if (!cmd->convert_src || tmp != cmd->convert_src)
385 err++;
386
387 tmp = cmd->scan_end_src;
388 cmd->scan_end_src &= TRIG_COUNT;
389 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
390 err++;
391
392 tmp = cmd->stop_src;
393 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
394 if (!cmd->stop_src || tmp != cmd->stop_src)
395 err++;
396
397 if (err)
398 return 1;
399
400
401
402
403 if (cmd->scan_begin_src != TRIG_TIMER &&
404 cmd->scan_begin_src != TRIG_EXT)
405 err++;
406 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
407 err++;
408 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
409 err++;
410
411 if (err)
412 return 2;
413
414
415
416 if (cmd->start_arg != 0) {
417 cmd->start_arg = 0;
418 err++;
419 }
420#define MAX_SPEED 10000
421#define MIN_SPEED 1000000000
422
423 if (cmd->scan_begin_src == TRIG_TIMER) {
424 if (cmd->scan_begin_arg < MAX_SPEED) {
425 cmd->scan_begin_arg = MAX_SPEED;
426 err++;
427 }
428 if (cmd->scan_begin_arg > MIN_SPEED) {
429 cmd->scan_begin_arg = MIN_SPEED;
430 err++;
431 }
432 } else {
433
434
435
436 if (cmd->scan_begin_arg > 9) {
437 cmd->scan_begin_arg = 9;
438 err++;
439 }
440 }
441 if (cmd->convert_src == TRIG_TIMER) {
442 if (cmd->convert_arg < MAX_SPEED) {
443 cmd->convert_arg = MAX_SPEED;
444 err++;
445 }
446 if (cmd->convert_arg > MIN_SPEED) {
447 cmd->convert_arg = MIN_SPEED;
448 err++;
449 }
450 } else {
451
452
453 if (cmd->convert_arg > 9) {
454 cmd->convert_arg = 9;
455 err++;
456 }
457 }
458
459 if (cmd->scan_end_arg != cmd->chanlist_len) {
460 cmd->scan_end_arg = cmd->chanlist_len;
461 err++;
462 }
463 if (cmd->stop_src == TRIG_COUNT) {
464 if (cmd->stop_arg > 0x00ffffff) {
465 cmd->stop_arg = 0x00ffffff;
466 err++;
467 }
468 } else {
469
470 if (cmd->stop_arg != 0) {
471 cmd->stop_arg = 0;
472 err++;
473 }
474 }
475
476 if (err)
477 return 3;
478
479
480
481 if (cmd->scan_begin_src == TRIG_TIMER) {
482 tmp = cmd->scan_begin_arg;
483 skel_ns_to_timer(&cmd->scan_begin_arg,
484 cmd->flags & TRIG_ROUND_MASK);
485 if (tmp != cmd->scan_begin_arg)
486 err++;
487 }
488 if (cmd->convert_src == TRIG_TIMER) {
489 tmp = cmd->convert_arg;
490 skel_ns_to_timer(&cmd->convert_arg,
491 cmd->flags & TRIG_ROUND_MASK);
492 if (tmp != cmd->convert_arg)
493 err++;
494 if (cmd->scan_begin_src == TRIG_TIMER &&
495 cmd->scan_begin_arg <
496 cmd->convert_arg * cmd->scan_end_arg) {
497 cmd->scan_begin_arg =
498 cmd->convert_arg * cmd->scan_end_arg;
499 err++;
500 }
501 }
502
503 if (err)
504 return 4;
505
506 return 0;
507}
508
509
510
511
512
513
514static int skel_ns_to_timer(unsigned int *ns, int round)
515{
516
517
518
519
520
521
522
523 return *ns;
524}
525
526static int skel_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
527 struct comedi_insn *insn, unsigned int *data)
528{
529 int i;
530 int chan = CR_CHAN(insn->chanspec);
531
532 printk("skel_ao_winsn\n");
533
534
535 for (i = 0; i < insn->n; i++) {
536
537
538 devpriv->ao_readback[chan] = data[i];
539 }
540
541
542 return i;
543}
544
545
546
547static int skel_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
548 struct comedi_insn *insn, unsigned int *data)
549{
550 int i;
551 int chan = CR_CHAN(insn->chanspec);
552
553 for (i = 0; i < insn->n; i++)
554 data[i] = devpriv->ao_readback[chan];
555
556 return i;
557}
558
559
560
561
562
563
564static int skel_dio_insn_bits(struct comedi_device *dev,
565 struct comedi_subdevice *s,
566 struct comedi_insn *insn, unsigned int *data)
567{
568 if (insn->n != 2)
569 return -EINVAL;
570
571
572
573 if (data[0]) {
574 s->state &= ~data[0];
575 s->state |= data[0] & data[1];
576
577
578 }
579
580
581
582
583
584
585
586
587 return 2;
588}
589
590static int skel_dio_insn_config(struct comedi_device *dev,
591 struct comedi_subdevice *s,
592 struct comedi_insn *insn, unsigned int *data)
593{
594 int chan = CR_CHAN(insn->chanspec);
595
596
597
598
599
600 switch (data[0]) {
601 case INSN_CONFIG_DIO_OUTPUT:
602 s->io_bits |= 1 << chan;
603 break;
604 case INSN_CONFIG_DIO_INPUT:
605 s->io_bits &= ~(1 << chan);
606 break;
607 case INSN_CONFIG_DIO_QUERY:
608 data[1] =
609 (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
610 return insn->n;
611 break;
612 default:
613 return -EINVAL;
614 break;
615 }
616
617
618 return insn->n;
619}
620
621
622
623
624
625COMEDI_INITCLEANUP(driver_skel);
626
627
628
629