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