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