This source file includes following definitions.
- vmk80xx_do_bulk_msg
- vmk80xx_read_packet
- vmk80xx_write_packet
- vmk80xx_reset_device
- vmk80xx_ai_insn_read
- vmk80xx_ao_insn_write
- vmk80xx_ao_insn_read
- vmk80xx_di_insn_bits
- vmk80xx_do_insn_bits
- vmk80xx_cnt_insn_read
- vmk80xx_cnt_insn_config
- vmk80xx_cnt_insn_write
- vmk80xx_pwm_insn_read
- vmk80xx_pwm_insn_write
- vmk80xx_find_usb_endpoints
- vmk80xx_alloc_usb_buffers
- vmk80xx_init_subdevices
- vmk80xx_auto_attach
- vmk80xx_detach
- vmk80xx_usb_probe
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 #include <linux/kernel.h>
31 #include <linux/module.h>
32 #include <linux/mutex.h>
33 #include <linux/errno.h>
34 #include <linux/input.h>
35 #include <linux/slab.h>
36 #include <linux/poll.h>
37 #include <linux/uaccess.h>
38
39 #include "../comedi_usb.h"
40
41 enum {
42 DEVICE_VMK8055,
43 DEVICE_VMK8061
44 };
45
46 #define VMK8055_DI_REG 0x00
47 #define VMK8055_DO_REG 0x01
48 #define VMK8055_AO1_REG 0x02
49 #define VMK8055_AO2_REG 0x03
50 #define VMK8055_AI1_REG 0x02
51 #define VMK8055_AI2_REG 0x03
52 #define VMK8055_CNT1_REG 0x04
53 #define VMK8055_CNT2_REG 0x06
54
55 #define VMK8061_CH_REG 0x01
56 #define VMK8061_DI_REG 0x01
57 #define VMK8061_DO_REG 0x01
58 #define VMK8061_PWM_REG1 0x01
59 #define VMK8061_PWM_REG2 0x02
60 #define VMK8061_CNT_REG 0x02
61 #define VMK8061_AO_REG 0x02
62 #define VMK8061_AI_REG1 0x02
63 #define VMK8061_AI_REG2 0x03
64
65 #define VMK8055_CMD_RST 0x00
66 #define VMK8055_CMD_DEB1_TIME 0x01
67 #define VMK8055_CMD_DEB2_TIME 0x02
68 #define VMK8055_CMD_RST_CNT1 0x03
69 #define VMK8055_CMD_RST_CNT2 0x04
70 #define VMK8055_CMD_WRT_AD 0x05
71
72 #define VMK8061_CMD_RD_AI 0x00
73 #define VMK8061_CMR_RD_ALL_AI 0x01
74 #define VMK8061_CMD_SET_AO 0x02
75 #define VMK8061_CMD_SET_ALL_AO 0x03
76 #define VMK8061_CMD_OUT_PWM 0x04
77 #define VMK8061_CMD_RD_DI 0x05
78 #define VMK8061_CMD_DO 0x06
79 #define VMK8061_CMD_CLR_DO 0x07
80 #define VMK8061_CMD_SET_DO 0x08
81 #define VMK8061_CMD_RD_CNT 0x09
82 #define VMK8061_CMD_RST_CNT 0x0a
83 #define VMK8061_CMD_RD_VERSION 0x0b
84 #define VMK8061_CMD_RD_JMP_STAT 0x0c
85 #define VMK8061_CMD_RD_PWR_STAT 0x0d
86 #define VMK8061_CMD_RD_DO 0x0e
87 #define VMK8061_CMD_RD_AO 0x0f
88 #define VMK8061_CMD_RD_PWM 0x10
89
90 #define IC3_VERSION BIT(0)
91 #define IC6_VERSION BIT(1)
92
93 enum vmk80xx_model {
94 VMK8055_MODEL,
95 VMK8061_MODEL
96 };
97
98 static const struct comedi_lrange vmk8061_range = {
99 2, {
100 UNI_RANGE(5),
101 UNI_RANGE(10)
102 }
103 };
104
105 struct vmk80xx_board {
106 const char *name;
107 enum vmk80xx_model model;
108 const struct comedi_lrange *range;
109 int ai_nchans;
110 unsigned int ai_maxdata;
111 int ao_nchans;
112 int di_nchans;
113 unsigned int cnt_maxdata;
114 int pwm_nchans;
115 unsigned int pwm_maxdata;
116 };
117
118 static const struct vmk80xx_board vmk80xx_boardinfo[] = {
119 [DEVICE_VMK8055] = {
120 .name = "K8055 (VM110)",
121 .model = VMK8055_MODEL,
122 .range = &range_unipolar5,
123 .ai_nchans = 2,
124 .ai_maxdata = 0x00ff,
125 .ao_nchans = 2,
126 .di_nchans = 6,
127 .cnt_maxdata = 0xffff,
128 },
129 [DEVICE_VMK8061] = {
130 .name = "K8061 (VM140)",
131 .model = VMK8061_MODEL,
132 .range = &vmk8061_range,
133 .ai_nchans = 8,
134 .ai_maxdata = 0x03ff,
135 .ao_nchans = 8,
136 .di_nchans = 8,
137 .cnt_maxdata = 0,
138 .pwm_nchans = 1,
139 .pwm_maxdata = 0x03ff,
140 },
141 };
142
143 struct vmk80xx_private {
144 struct usb_endpoint_descriptor *ep_rx;
145 struct usb_endpoint_descriptor *ep_tx;
146 struct semaphore limit_sem;
147 unsigned char *usb_rx_buf;
148 unsigned char *usb_tx_buf;
149 enum vmk80xx_model model;
150 };
151
152 static void vmk80xx_do_bulk_msg(struct comedi_device *dev)
153 {
154 struct vmk80xx_private *devpriv = dev->private;
155 struct usb_device *usb = comedi_to_usb_dev(dev);
156 __u8 tx_addr;
157 __u8 rx_addr;
158 unsigned int tx_pipe;
159 unsigned int rx_pipe;
160 size_t size;
161
162 tx_addr = devpriv->ep_tx->bEndpointAddress;
163 rx_addr = devpriv->ep_rx->bEndpointAddress;
164 tx_pipe = usb_sndbulkpipe(usb, tx_addr);
165 rx_pipe = usb_rcvbulkpipe(usb, rx_addr);
166
167
168
169
170
171 size = usb_endpoint_maxp(devpriv->ep_tx);
172
173 usb_bulk_msg(usb, tx_pipe, devpriv->usb_tx_buf,
174 size, NULL, devpriv->ep_tx->bInterval);
175 usb_bulk_msg(usb, rx_pipe, devpriv->usb_rx_buf, size, NULL, HZ * 10);
176 }
177
178 static int vmk80xx_read_packet(struct comedi_device *dev)
179 {
180 struct vmk80xx_private *devpriv = dev->private;
181 struct usb_device *usb = comedi_to_usb_dev(dev);
182 struct usb_endpoint_descriptor *ep;
183 unsigned int pipe;
184
185 if (devpriv->model == VMK8061_MODEL) {
186 vmk80xx_do_bulk_msg(dev);
187 return 0;
188 }
189
190 ep = devpriv->ep_rx;
191 pipe = usb_rcvintpipe(usb, ep->bEndpointAddress);
192 return usb_interrupt_msg(usb, pipe, devpriv->usb_rx_buf,
193 usb_endpoint_maxp(ep), NULL,
194 HZ * 10);
195 }
196
197 static int vmk80xx_write_packet(struct comedi_device *dev, int cmd)
198 {
199 struct vmk80xx_private *devpriv = dev->private;
200 struct usb_device *usb = comedi_to_usb_dev(dev);
201 struct usb_endpoint_descriptor *ep;
202 unsigned int pipe;
203
204 devpriv->usb_tx_buf[0] = cmd;
205
206 if (devpriv->model == VMK8061_MODEL) {
207 vmk80xx_do_bulk_msg(dev);
208 return 0;
209 }
210
211 ep = devpriv->ep_tx;
212 pipe = usb_sndintpipe(usb, ep->bEndpointAddress);
213 return usb_interrupt_msg(usb, pipe, devpriv->usb_tx_buf,
214 usb_endpoint_maxp(ep), NULL,
215 HZ * 10);
216 }
217
218 static int vmk80xx_reset_device(struct comedi_device *dev)
219 {
220 struct vmk80xx_private *devpriv = dev->private;
221 size_t size;
222 int retval;
223
224 size = usb_endpoint_maxp(devpriv->ep_tx);
225 memset(devpriv->usb_tx_buf, 0, size);
226 retval = vmk80xx_write_packet(dev, VMK8055_CMD_RST);
227 if (retval)
228 return retval;
229
230 return vmk80xx_write_packet(dev, VMK8055_CMD_WRT_AD);
231 }
232
233 static int vmk80xx_ai_insn_read(struct comedi_device *dev,
234 struct comedi_subdevice *s,
235 struct comedi_insn *insn,
236 unsigned int *data)
237 {
238 struct vmk80xx_private *devpriv = dev->private;
239 int chan;
240 int reg[2];
241 int n;
242
243 down(&devpriv->limit_sem);
244 chan = CR_CHAN(insn->chanspec);
245
246 switch (devpriv->model) {
247 case VMK8055_MODEL:
248 if (!chan)
249 reg[0] = VMK8055_AI1_REG;
250 else
251 reg[0] = VMK8055_AI2_REG;
252 break;
253 case VMK8061_MODEL:
254 default:
255 reg[0] = VMK8061_AI_REG1;
256 reg[1] = VMK8061_AI_REG2;
257 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_AI;
258 devpriv->usb_tx_buf[VMK8061_CH_REG] = chan;
259 break;
260 }
261
262 for (n = 0; n < insn->n; n++) {
263 if (vmk80xx_read_packet(dev))
264 break;
265
266 if (devpriv->model == VMK8055_MODEL) {
267 data[n] = devpriv->usb_rx_buf[reg[0]];
268 continue;
269 }
270
271
272 data[n] = devpriv->usb_rx_buf[reg[0]] + 256 *
273 devpriv->usb_rx_buf[reg[1]];
274 }
275
276 up(&devpriv->limit_sem);
277
278 return n;
279 }
280
281 static int vmk80xx_ao_insn_write(struct comedi_device *dev,
282 struct comedi_subdevice *s,
283 struct comedi_insn *insn,
284 unsigned int *data)
285 {
286 struct vmk80xx_private *devpriv = dev->private;
287 int chan;
288 int cmd;
289 int reg;
290 int n;
291
292 down(&devpriv->limit_sem);
293 chan = CR_CHAN(insn->chanspec);
294
295 switch (devpriv->model) {
296 case VMK8055_MODEL:
297 cmd = VMK8055_CMD_WRT_AD;
298 if (!chan)
299 reg = VMK8055_AO1_REG;
300 else
301 reg = VMK8055_AO2_REG;
302 break;
303 default:
304 cmd = VMK8061_CMD_SET_AO;
305 reg = VMK8061_AO_REG;
306 devpriv->usb_tx_buf[VMK8061_CH_REG] = chan;
307 break;
308 }
309
310 for (n = 0; n < insn->n; n++) {
311 devpriv->usb_tx_buf[reg] = data[n];
312
313 if (vmk80xx_write_packet(dev, cmd))
314 break;
315 }
316
317 up(&devpriv->limit_sem);
318
319 return n;
320 }
321
322 static int vmk80xx_ao_insn_read(struct comedi_device *dev,
323 struct comedi_subdevice *s,
324 struct comedi_insn *insn,
325 unsigned int *data)
326 {
327 struct vmk80xx_private *devpriv = dev->private;
328 int chan;
329 int reg;
330 int n;
331
332 down(&devpriv->limit_sem);
333 chan = CR_CHAN(insn->chanspec);
334
335 reg = VMK8061_AO_REG - 1;
336
337 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_AO;
338
339 for (n = 0; n < insn->n; n++) {
340 if (vmk80xx_read_packet(dev))
341 break;
342
343 data[n] = devpriv->usb_rx_buf[reg + chan];
344 }
345
346 up(&devpriv->limit_sem);
347
348 return n;
349 }
350
351 static int vmk80xx_di_insn_bits(struct comedi_device *dev,
352 struct comedi_subdevice *s,
353 struct comedi_insn *insn,
354 unsigned int *data)
355 {
356 struct vmk80xx_private *devpriv = dev->private;
357 unsigned char *rx_buf;
358 int reg;
359 int retval;
360
361 down(&devpriv->limit_sem);
362
363 rx_buf = devpriv->usb_rx_buf;
364
365 if (devpriv->model == VMK8061_MODEL) {
366 reg = VMK8061_DI_REG;
367 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
368 } else {
369 reg = VMK8055_DI_REG;
370 }
371
372 retval = vmk80xx_read_packet(dev);
373
374 if (!retval) {
375 if (devpriv->model == VMK8055_MODEL)
376 data[1] = (((rx_buf[reg] >> 4) & 0x03) |
377 ((rx_buf[reg] << 2) & 0x04) |
378 ((rx_buf[reg] >> 3) & 0x18));
379 else
380 data[1] = rx_buf[reg];
381
382 retval = 2;
383 }
384
385 up(&devpriv->limit_sem);
386
387 return retval;
388 }
389
390 static int vmk80xx_do_insn_bits(struct comedi_device *dev,
391 struct comedi_subdevice *s,
392 struct comedi_insn *insn,
393 unsigned int *data)
394 {
395 struct vmk80xx_private *devpriv = dev->private;
396 unsigned char *rx_buf = devpriv->usb_rx_buf;
397 unsigned char *tx_buf = devpriv->usb_tx_buf;
398 int reg, cmd;
399 int ret = 0;
400
401 if (devpriv->model == VMK8061_MODEL) {
402 reg = VMK8061_DO_REG;
403 cmd = VMK8061_CMD_DO;
404 } else {
405 reg = VMK8055_DO_REG;
406 cmd = VMK8055_CMD_WRT_AD;
407 }
408
409 down(&devpriv->limit_sem);
410
411 if (comedi_dio_update_state(s, data)) {
412 tx_buf[reg] = s->state;
413 ret = vmk80xx_write_packet(dev, cmd);
414 if (ret)
415 goto out;
416 }
417
418 if (devpriv->model == VMK8061_MODEL) {
419 tx_buf[0] = VMK8061_CMD_RD_DO;
420 ret = vmk80xx_read_packet(dev);
421 if (ret)
422 goto out;
423 data[1] = rx_buf[reg];
424 } else {
425 data[1] = s->state;
426 }
427
428 out:
429 up(&devpriv->limit_sem);
430
431 return ret ? ret : insn->n;
432 }
433
434 static int vmk80xx_cnt_insn_read(struct comedi_device *dev,
435 struct comedi_subdevice *s,
436 struct comedi_insn *insn,
437 unsigned int *data)
438 {
439 struct vmk80xx_private *devpriv = dev->private;
440 int chan;
441 int reg[2];
442 int n;
443
444 down(&devpriv->limit_sem);
445 chan = CR_CHAN(insn->chanspec);
446
447 switch (devpriv->model) {
448 case VMK8055_MODEL:
449 if (!chan)
450 reg[0] = VMK8055_CNT1_REG;
451 else
452 reg[0] = VMK8055_CNT2_REG;
453 break;
454 case VMK8061_MODEL:
455 default:
456 reg[0] = VMK8061_CNT_REG;
457 reg[1] = VMK8061_CNT_REG;
458 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_CNT;
459 break;
460 }
461
462 for (n = 0; n < insn->n; n++) {
463 if (vmk80xx_read_packet(dev))
464 break;
465
466 if (devpriv->model == VMK8055_MODEL)
467 data[n] = devpriv->usb_rx_buf[reg[0]];
468 else
469 data[n] = devpriv->usb_rx_buf[reg[0] * (chan + 1) + 1]
470 + 256 * devpriv->usb_rx_buf[reg[1] * 2 + 2];
471 }
472
473 up(&devpriv->limit_sem);
474
475 return n;
476 }
477
478 static int vmk80xx_cnt_insn_config(struct comedi_device *dev,
479 struct comedi_subdevice *s,
480 struct comedi_insn *insn,
481 unsigned int *data)
482 {
483 struct vmk80xx_private *devpriv = dev->private;
484 unsigned int chan = CR_CHAN(insn->chanspec);
485 int cmd;
486 int reg;
487 int ret;
488
489 down(&devpriv->limit_sem);
490 switch (data[0]) {
491 case INSN_CONFIG_RESET:
492 if (devpriv->model == VMK8055_MODEL) {
493 if (!chan) {
494 cmd = VMK8055_CMD_RST_CNT1;
495 reg = VMK8055_CNT1_REG;
496 } else {
497 cmd = VMK8055_CMD_RST_CNT2;
498 reg = VMK8055_CNT2_REG;
499 }
500 devpriv->usb_tx_buf[reg] = 0x00;
501 } else {
502 cmd = VMK8061_CMD_RST_CNT;
503 }
504 ret = vmk80xx_write_packet(dev, cmd);
505 break;
506 default:
507 ret = -EINVAL;
508 break;
509 }
510 up(&devpriv->limit_sem);
511
512 return ret ? ret : insn->n;
513 }
514
515 static int vmk80xx_cnt_insn_write(struct comedi_device *dev,
516 struct comedi_subdevice *s,
517 struct comedi_insn *insn,
518 unsigned int *data)
519 {
520 struct vmk80xx_private *devpriv = dev->private;
521 unsigned long debtime;
522 unsigned long val;
523 int chan;
524 int cmd;
525 int n;
526
527 down(&devpriv->limit_sem);
528 chan = CR_CHAN(insn->chanspec);
529
530 if (!chan)
531 cmd = VMK8055_CMD_DEB1_TIME;
532 else
533 cmd = VMK8055_CMD_DEB2_TIME;
534
535 for (n = 0; n < insn->n; n++) {
536 debtime = data[n];
537 if (debtime == 0)
538 debtime = 1;
539
540
541 if (debtime > 7450)
542 debtime = 7450;
543
544 val = int_sqrt(debtime * 1000 / 115);
545 if (((val + 1) * val) < debtime * 1000 / 115)
546 val += 1;
547
548 devpriv->usb_tx_buf[6 + chan] = val;
549
550 if (vmk80xx_write_packet(dev, cmd))
551 break;
552 }
553
554 up(&devpriv->limit_sem);
555
556 return n;
557 }
558
559 static int vmk80xx_pwm_insn_read(struct comedi_device *dev,
560 struct comedi_subdevice *s,
561 struct comedi_insn *insn,
562 unsigned int *data)
563 {
564 struct vmk80xx_private *devpriv = dev->private;
565 unsigned char *tx_buf;
566 unsigned char *rx_buf;
567 int reg[2];
568 int n;
569
570 down(&devpriv->limit_sem);
571
572 tx_buf = devpriv->usb_tx_buf;
573 rx_buf = devpriv->usb_rx_buf;
574
575 reg[0] = VMK8061_PWM_REG1;
576 reg[1] = VMK8061_PWM_REG2;
577
578 tx_buf[0] = VMK8061_CMD_RD_PWM;
579
580 for (n = 0; n < insn->n; n++) {
581 if (vmk80xx_read_packet(dev))
582 break;
583
584 data[n] = rx_buf[reg[0]] + 4 * rx_buf[reg[1]];
585 }
586
587 up(&devpriv->limit_sem);
588
589 return n;
590 }
591
592 static int vmk80xx_pwm_insn_write(struct comedi_device *dev,
593 struct comedi_subdevice *s,
594 struct comedi_insn *insn,
595 unsigned int *data)
596 {
597 struct vmk80xx_private *devpriv = dev->private;
598 unsigned char *tx_buf;
599 int reg[2];
600 int cmd;
601 int n;
602
603 down(&devpriv->limit_sem);
604
605 tx_buf = devpriv->usb_tx_buf;
606
607 reg[0] = VMK8061_PWM_REG1;
608 reg[1] = VMK8061_PWM_REG2;
609
610 cmd = VMK8061_CMD_OUT_PWM;
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625 for (n = 0; n < insn->n; n++) {
626 tx_buf[reg[0]] = (unsigned char)(data[n] & 0x03);
627 tx_buf[reg[1]] = (unsigned char)(data[n] >> 2) & 0xff;
628
629 if (vmk80xx_write_packet(dev, cmd))
630 break;
631 }
632
633 up(&devpriv->limit_sem);
634
635 return n;
636 }
637
638 static int vmk80xx_find_usb_endpoints(struct comedi_device *dev)
639 {
640 struct vmk80xx_private *devpriv = dev->private;
641 struct usb_interface *intf = comedi_to_usb_interface(dev);
642 struct usb_host_interface *iface_desc = intf->cur_altsetting;
643 struct usb_endpoint_descriptor *ep_desc;
644 int i;
645
646 if (iface_desc->desc.bNumEndpoints != 2)
647 return -ENODEV;
648
649 for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
650 ep_desc = &iface_desc->endpoint[i].desc;
651
652 if (usb_endpoint_is_int_in(ep_desc) ||
653 usb_endpoint_is_bulk_in(ep_desc)) {
654 if (!devpriv->ep_rx)
655 devpriv->ep_rx = ep_desc;
656 continue;
657 }
658
659 if (usb_endpoint_is_int_out(ep_desc) ||
660 usb_endpoint_is_bulk_out(ep_desc)) {
661 if (!devpriv->ep_tx)
662 devpriv->ep_tx = ep_desc;
663 continue;
664 }
665 }
666
667 if (!devpriv->ep_rx || !devpriv->ep_tx)
668 return -ENODEV;
669
670 return 0;
671 }
672
673 static int vmk80xx_alloc_usb_buffers(struct comedi_device *dev)
674 {
675 struct vmk80xx_private *devpriv = dev->private;
676 size_t size;
677
678 size = usb_endpoint_maxp(devpriv->ep_rx);
679 devpriv->usb_rx_buf = kzalloc(size, GFP_KERNEL);
680 if (!devpriv->usb_rx_buf)
681 return -ENOMEM;
682
683 size = usb_endpoint_maxp(devpriv->ep_tx);
684 devpriv->usb_tx_buf = kzalloc(size, GFP_KERNEL);
685 if (!devpriv->usb_tx_buf)
686 return -ENOMEM;
687
688 return 0;
689 }
690
691 static int vmk80xx_init_subdevices(struct comedi_device *dev)
692 {
693 const struct vmk80xx_board *board = dev->board_ptr;
694 struct vmk80xx_private *devpriv = dev->private;
695 struct comedi_subdevice *s;
696 int n_subd;
697 int ret;
698
699 down(&devpriv->limit_sem);
700
701 if (devpriv->model == VMK8055_MODEL)
702 n_subd = 5;
703 else
704 n_subd = 6;
705 ret = comedi_alloc_subdevices(dev, n_subd);
706 if (ret) {
707 up(&devpriv->limit_sem);
708 return ret;
709 }
710
711
712 s = &dev->subdevices[0];
713 s->type = COMEDI_SUBD_AI;
714 s->subdev_flags = SDF_READABLE | SDF_GROUND;
715 s->n_chan = board->ai_nchans;
716 s->maxdata = board->ai_maxdata;
717 s->range_table = board->range;
718 s->insn_read = vmk80xx_ai_insn_read;
719
720
721 s = &dev->subdevices[1];
722 s->type = COMEDI_SUBD_AO;
723 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
724 s->n_chan = board->ao_nchans;
725 s->maxdata = 0x00ff;
726 s->range_table = board->range;
727 s->insn_write = vmk80xx_ao_insn_write;
728 if (devpriv->model == VMK8061_MODEL) {
729 s->subdev_flags |= SDF_READABLE;
730 s->insn_read = vmk80xx_ao_insn_read;
731 }
732
733
734 s = &dev->subdevices[2];
735 s->type = COMEDI_SUBD_DI;
736 s->subdev_flags = SDF_READABLE;
737 s->n_chan = board->di_nchans;
738 s->maxdata = 1;
739 s->range_table = &range_digital;
740 s->insn_bits = vmk80xx_di_insn_bits;
741
742
743 s = &dev->subdevices[3];
744 s->type = COMEDI_SUBD_DO;
745 s->subdev_flags = SDF_WRITABLE;
746 s->n_chan = 8;
747 s->maxdata = 1;
748 s->range_table = &range_digital;
749 s->insn_bits = vmk80xx_do_insn_bits;
750
751
752 s = &dev->subdevices[4];
753 s->type = COMEDI_SUBD_COUNTER;
754 s->subdev_flags = SDF_READABLE;
755 s->n_chan = 2;
756 s->maxdata = board->cnt_maxdata;
757 s->insn_read = vmk80xx_cnt_insn_read;
758 s->insn_config = vmk80xx_cnt_insn_config;
759 if (devpriv->model == VMK8055_MODEL) {
760 s->subdev_flags |= SDF_WRITABLE;
761 s->insn_write = vmk80xx_cnt_insn_write;
762 }
763
764
765 if (devpriv->model == VMK8061_MODEL) {
766 s = &dev->subdevices[5];
767 s->type = COMEDI_SUBD_PWM;
768 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
769 s->n_chan = board->pwm_nchans;
770 s->maxdata = board->pwm_maxdata;
771 s->insn_read = vmk80xx_pwm_insn_read;
772 s->insn_write = vmk80xx_pwm_insn_write;
773 }
774
775 up(&devpriv->limit_sem);
776
777 return 0;
778 }
779
780 static int vmk80xx_auto_attach(struct comedi_device *dev,
781 unsigned long context)
782 {
783 struct usb_interface *intf = comedi_to_usb_interface(dev);
784 const struct vmk80xx_board *board = NULL;
785 struct vmk80xx_private *devpriv;
786 int ret;
787
788 if (context < ARRAY_SIZE(vmk80xx_boardinfo))
789 board = &vmk80xx_boardinfo[context];
790 if (!board)
791 return -ENODEV;
792 dev->board_ptr = board;
793 dev->board_name = board->name;
794
795 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
796 if (!devpriv)
797 return -ENOMEM;
798
799 devpriv->model = board->model;
800
801 sema_init(&devpriv->limit_sem, 8);
802
803 ret = vmk80xx_find_usb_endpoints(dev);
804 if (ret)
805 return ret;
806
807 ret = vmk80xx_alloc_usb_buffers(dev);
808 if (ret)
809 return ret;
810
811 usb_set_intfdata(intf, devpriv);
812
813 if (devpriv->model == VMK8055_MODEL)
814 vmk80xx_reset_device(dev);
815
816 return vmk80xx_init_subdevices(dev);
817 }
818
819 static void vmk80xx_detach(struct comedi_device *dev)
820 {
821 struct usb_interface *intf = comedi_to_usb_interface(dev);
822 struct vmk80xx_private *devpriv = dev->private;
823
824 if (!devpriv)
825 return;
826
827 down(&devpriv->limit_sem);
828
829 usb_set_intfdata(intf, NULL);
830
831 kfree(devpriv->usb_rx_buf);
832 kfree(devpriv->usb_tx_buf);
833
834 up(&devpriv->limit_sem);
835 }
836
837 static struct comedi_driver vmk80xx_driver = {
838 .module = THIS_MODULE,
839 .driver_name = "vmk80xx",
840 .auto_attach = vmk80xx_auto_attach,
841 .detach = vmk80xx_detach,
842 };
843
844 static int vmk80xx_usb_probe(struct usb_interface *intf,
845 const struct usb_device_id *id)
846 {
847 return comedi_usb_auto_config(intf, &vmk80xx_driver, id->driver_info);
848 }
849
850 static const struct usb_device_id vmk80xx_usb_id_table[] = {
851 { USB_DEVICE(0x10cf, 0x5500), .driver_info = DEVICE_VMK8055 },
852 { USB_DEVICE(0x10cf, 0x5501), .driver_info = DEVICE_VMK8055 },
853 { USB_DEVICE(0x10cf, 0x5502), .driver_info = DEVICE_VMK8055 },
854 { USB_DEVICE(0x10cf, 0x5503), .driver_info = DEVICE_VMK8055 },
855 { USB_DEVICE(0x10cf, 0x8061), .driver_info = DEVICE_VMK8061 },
856 { USB_DEVICE(0x10cf, 0x8062), .driver_info = DEVICE_VMK8061 },
857 { USB_DEVICE(0x10cf, 0x8063), .driver_info = DEVICE_VMK8061 },
858 { USB_DEVICE(0x10cf, 0x8064), .driver_info = DEVICE_VMK8061 },
859 { USB_DEVICE(0x10cf, 0x8065), .driver_info = DEVICE_VMK8061 },
860 { USB_DEVICE(0x10cf, 0x8066), .driver_info = DEVICE_VMK8061 },
861 { USB_DEVICE(0x10cf, 0x8067), .driver_info = DEVICE_VMK8061 },
862 { USB_DEVICE(0x10cf, 0x8068), .driver_info = DEVICE_VMK8061 },
863 { }
864 };
865 MODULE_DEVICE_TABLE(usb, vmk80xx_usb_id_table);
866
867 static struct usb_driver vmk80xx_usb_driver = {
868 .name = "vmk80xx",
869 .id_table = vmk80xx_usb_id_table,
870 .probe = vmk80xx_usb_probe,
871 .disconnect = comedi_usb_auto_unconfig,
872 };
873 module_comedi_usb_driver(vmk80xx_driver, vmk80xx_usb_driver);
874
875 MODULE_AUTHOR("Manuel Gebele <forensixs@gmx.de>");
876 MODULE_DESCRIPTION("Velleman USB Board Low-Level Driver");
877 MODULE_SUPPORTED_DEVICE("K8055/K8061 aka VM110/VM140");
878 MODULE_LICENSE("GPL");