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 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,	/* unknown, device is not writeable */
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 
vmk80xx_do_bulk_msg(struct comedi_device * dev)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 	 * The max packet size attributes of the K8061
169 	 * input/output endpoints are identical
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 
vmk80xx_read_packet(struct comedi_device * dev)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 
vmk80xx_write_packet(struct comedi_device * dev,int cmd)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 
vmk80xx_reset_device(struct comedi_device * dev)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 	/* set outputs to known state as we cannot read them */
230 	return vmk80xx_write_packet(dev, VMK8055_CMD_WRT_AD);
231 }
232 
vmk80xx_ai_insn_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)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 		/* VMK8061_MODEL */
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 
vmk80xx_ao_insn_write(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)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:		/* NOTE: avoid compiler warnings */
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 
vmk80xx_ao_insn_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)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 
vmk80xx_di_insn_bits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)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 
vmk80xx_do_insn_bits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)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 { /* VMK8055_MODEL */
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 
vmk80xx_cnt_insn_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)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 /* VMK8061_MODEL */
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 
vmk80xx_cnt_insn_config(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)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 
vmk80xx_cnt_insn_write(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)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 		/* TODO: Prevent overflows */
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 
vmk80xx_pwm_insn_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)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 
vmk80xx_pwm_insn_write(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)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 	 * The followin piece of code was translated from the inline
614 	 * assembler code in the DLL source code.
615 	 *
616 	 * asm
617 	 *   mov eax, k  ; k is the value (data[n])
618 	 *   and al, 03h ; al are the lower 8 bits of eax
619 	 *   mov lo, al  ; lo is the low part (tx_buf[reg[0]])
620 	 *   mov eax, k
621 	 *   shr eax, 2  ; right shift eax register by 2
622 	 *   mov hi, al  ; hi is the high part (tx_buf[reg[1]])
623 	 * end;
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 
vmk80xx_find_usb_endpoints(struct comedi_device * dev)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 
vmk80xx_alloc_usb_buffers(struct comedi_device * dev)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 		kfree(devpriv->usb_rx_buf);
687 		return -ENOMEM;
688 	}
689 
690 	return 0;
691 }
692 
vmk80xx_init_subdevices(struct comedi_device * dev)693 static int vmk80xx_init_subdevices(struct comedi_device *dev)
694 {
695 	const struct vmk80xx_board *board = dev->board_ptr;
696 	struct vmk80xx_private *devpriv = dev->private;
697 	struct comedi_subdevice *s;
698 	int n_subd;
699 	int ret;
700 
701 	down(&devpriv->limit_sem);
702 
703 	if (devpriv->model == VMK8055_MODEL)
704 		n_subd = 5;
705 	else
706 		n_subd = 6;
707 	ret = comedi_alloc_subdevices(dev, n_subd);
708 	if (ret) {
709 		up(&devpriv->limit_sem);
710 		return ret;
711 	}
712 
713 	/* Analog input subdevice */
714 	s = &dev->subdevices[0];
715 	s->type		= COMEDI_SUBD_AI;
716 	s->subdev_flags	= SDF_READABLE | SDF_GROUND;
717 	s->n_chan	= board->ai_nchans;
718 	s->maxdata	= board->ai_maxdata;
719 	s->range_table	= board->range;
720 	s->insn_read	= vmk80xx_ai_insn_read;
721 
722 	/* Analog output subdevice */
723 	s = &dev->subdevices[1];
724 	s->type		= COMEDI_SUBD_AO;
725 	s->subdev_flags	= SDF_WRITABLE | SDF_GROUND;
726 	s->n_chan	= board->ao_nchans;
727 	s->maxdata	= 0x00ff;
728 	s->range_table	= board->range;
729 	s->insn_write	= vmk80xx_ao_insn_write;
730 	if (devpriv->model == VMK8061_MODEL) {
731 		s->subdev_flags	|= SDF_READABLE;
732 		s->insn_read	= vmk80xx_ao_insn_read;
733 	}
734 
735 	/* Digital input subdevice */
736 	s = &dev->subdevices[2];
737 	s->type		= COMEDI_SUBD_DI;
738 	s->subdev_flags	= SDF_READABLE;
739 	s->n_chan	= board->di_nchans;
740 	s->maxdata	= 1;
741 	s->range_table	= &range_digital;
742 	s->insn_bits	= vmk80xx_di_insn_bits;
743 
744 	/* Digital output subdevice */
745 	s = &dev->subdevices[3];
746 	s->type		= COMEDI_SUBD_DO;
747 	s->subdev_flags	= SDF_WRITABLE;
748 	s->n_chan	= 8;
749 	s->maxdata	= 1;
750 	s->range_table	= &range_digital;
751 	s->insn_bits	= vmk80xx_do_insn_bits;
752 
753 	/* Counter subdevice */
754 	s = &dev->subdevices[4];
755 	s->type		= COMEDI_SUBD_COUNTER;
756 	s->subdev_flags	= SDF_READABLE;
757 	s->n_chan	= 2;
758 	s->maxdata	= board->cnt_maxdata;
759 	s->insn_read	= vmk80xx_cnt_insn_read;
760 	s->insn_config	= vmk80xx_cnt_insn_config;
761 	if (devpriv->model == VMK8055_MODEL) {
762 		s->subdev_flags	|= SDF_WRITABLE;
763 		s->insn_write	= vmk80xx_cnt_insn_write;
764 	}
765 
766 	/* PWM subdevice */
767 	if (devpriv->model == VMK8061_MODEL) {
768 		s = &dev->subdevices[5];
769 		s->type		= COMEDI_SUBD_PWM;
770 		s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
771 		s->n_chan	= board->pwm_nchans;
772 		s->maxdata	= board->pwm_maxdata;
773 		s->insn_read	= vmk80xx_pwm_insn_read;
774 		s->insn_write	= vmk80xx_pwm_insn_write;
775 	}
776 
777 	up(&devpriv->limit_sem);
778 
779 	return 0;
780 }
781 
vmk80xx_auto_attach(struct comedi_device * dev,unsigned long context)782 static int vmk80xx_auto_attach(struct comedi_device *dev,
783 			       unsigned long context)
784 {
785 	struct usb_interface *intf = comedi_to_usb_interface(dev);
786 	const struct vmk80xx_board *board = NULL;
787 	struct vmk80xx_private *devpriv;
788 	int ret;
789 
790 	if (context < ARRAY_SIZE(vmk80xx_boardinfo))
791 		board = &vmk80xx_boardinfo[context];
792 	if (!board)
793 		return -ENODEV;
794 	dev->board_ptr = board;
795 	dev->board_name = board->name;
796 
797 	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
798 	if (!devpriv)
799 		return -ENOMEM;
800 
801 	devpriv->model = board->model;
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 	sema_init(&devpriv->limit_sem, 8);
812 
813 	usb_set_intfdata(intf, devpriv);
814 
815 	if (devpriv->model == VMK8055_MODEL)
816 		vmk80xx_reset_device(dev);
817 
818 	return vmk80xx_init_subdevices(dev);
819 }
820 
vmk80xx_detach(struct comedi_device * dev)821 static void vmk80xx_detach(struct comedi_device *dev)
822 {
823 	struct usb_interface *intf = comedi_to_usb_interface(dev);
824 	struct vmk80xx_private *devpriv = dev->private;
825 
826 	if (!devpriv)
827 		return;
828 
829 	down(&devpriv->limit_sem);
830 
831 	usb_set_intfdata(intf, NULL);
832 
833 	kfree(devpriv->usb_rx_buf);
834 	kfree(devpriv->usb_tx_buf);
835 
836 	up(&devpriv->limit_sem);
837 }
838 
839 static struct comedi_driver vmk80xx_driver = {
840 	.module		= THIS_MODULE,
841 	.driver_name	= "vmk80xx",
842 	.auto_attach	= vmk80xx_auto_attach,
843 	.detach		= vmk80xx_detach,
844 };
845 
vmk80xx_usb_probe(struct usb_interface * intf,const struct usb_device_id * id)846 static int vmk80xx_usb_probe(struct usb_interface *intf,
847 			     const struct usb_device_id *id)
848 {
849 	return comedi_usb_auto_config(intf, &vmk80xx_driver, id->driver_info);
850 }
851 
852 static const struct usb_device_id vmk80xx_usb_id_table[] = {
853 	{ USB_DEVICE(0x10cf, 0x5500), .driver_info = DEVICE_VMK8055 },
854 	{ USB_DEVICE(0x10cf, 0x5501), .driver_info = DEVICE_VMK8055 },
855 	{ USB_DEVICE(0x10cf, 0x5502), .driver_info = DEVICE_VMK8055 },
856 	{ USB_DEVICE(0x10cf, 0x5503), .driver_info = DEVICE_VMK8055 },
857 	{ USB_DEVICE(0x10cf, 0x8061), .driver_info = DEVICE_VMK8061 },
858 	{ USB_DEVICE(0x10cf, 0x8062), .driver_info = DEVICE_VMK8061 },
859 	{ USB_DEVICE(0x10cf, 0x8063), .driver_info = DEVICE_VMK8061 },
860 	{ USB_DEVICE(0x10cf, 0x8064), .driver_info = DEVICE_VMK8061 },
861 	{ USB_DEVICE(0x10cf, 0x8065), .driver_info = DEVICE_VMK8061 },
862 	{ USB_DEVICE(0x10cf, 0x8066), .driver_info = DEVICE_VMK8061 },
863 	{ USB_DEVICE(0x10cf, 0x8067), .driver_info = DEVICE_VMK8061 },
864 	{ USB_DEVICE(0x10cf, 0x8068), .driver_info = DEVICE_VMK8061 },
865 	{ }
866 };
867 MODULE_DEVICE_TABLE(usb, vmk80xx_usb_id_table);
868 
869 static struct usb_driver vmk80xx_usb_driver = {
870 	.name		= "vmk80xx",
871 	.id_table	= vmk80xx_usb_id_table,
872 	.probe		= vmk80xx_usb_probe,
873 	.disconnect	= comedi_usb_auto_unconfig,
874 };
875 module_comedi_usb_driver(vmk80xx_driver, vmk80xx_usb_driver);
876 
877 MODULE_AUTHOR("Manuel Gebele <forensixs@gmx.de>");
878 MODULE_DESCRIPTION("Velleman USB Board Low-Level Driver");
879 MODULE_SUPPORTED_DEVICE("K8055/K8061 aka VM110/VM140");
880 MODULE_LICENSE("GPL");
881