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