vmk80xx.c revision 8ba69ce4b3567de881514c61ea8b04b14d8e68ae
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    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
24*/
25/*
26Driver: vmk80xx
27Description: Velleman USB Board Low-Level Driver
28Devices: K8055/K8061 aka VM110/VM140
29Author: Manuel Gebele <forensixs@gmx.de>
30Updated: Sun, 10 May 2009 11:14:59 +0200
31Status: works
32
33Supports:
34 - analog input
35 - analog output
36 - digital input
37 - digital output
38 - counter
39 - pwm
40*/
41/*
42Changelog:
43
440.8.81	-3-  code completely rewritten (adjust driver logic)
450.8.81  -2-  full support for K8061
460.8.81  -1-  fix some mistaken among others the number of
47	     supported boards and I/O handling
48
490.7.76  -4-  renamed to vmk80xx
500.7.76  -3-  detect K8061 (only theoretically supported)
510.7.76  -2-  code completely rewritten (adjust driver logic)
520.7.76  -1-  support for digital and counter subdevice
53*/
54
55#include <linux/kernel.h>
56#include <linux/module.h>
57#include <linux/mutex.h>
58#include <linux/errno.h>
59#include <linux/input.h>
60#include <linux/slab.h>
61#include <linux/poll.h>
62#include <linux/usb.h>
63#include <linux/uaccess.h>
64
65#include "../comedidev.h"
66
67#define BOARDNAME "vmk80xx"
68
69MODULE_AUTHOR("Manuel Gebele <forensixs@gmx.de>");
70MODULE_DESCRIPTION("Velleman USB Board Low-Level Driver");
71MODULE_SUPPORTED_DEVICE("K8055/K8061 aka VM110/VM140");
72MODULE_VERSION("0.8.01");
73MODULE_LICENSE("GPL");
74
75enum {
76	DEVICE_VMK8055,
77	DEVICE_VMK8061
78};
79
80static const struct usb_device_id vmk80xx_id_table[] = {
81	{USB_DEVICE(0x10cf, 0x5500), .driver_info = DEVICE_VMK8055},
82	{USB_DEVICE(0x10cf, 0x5501), .driver_info = DEVICE_VMK8055},
83	{USB_DEVICE(0x10cf, 0x5502), .driver_info = DEVICE_VMK8055},
84	{USB_DEVICE(0x10cf, 0x5503), .driver_info = DEVICE_VMK8055},
85	{USB_DEVICE(0x10cf, 0x8061), .driver_info = DEVICE_VMK8061},
86	{USB_DEVICE(0x10cf, 0x8062), .driver_info = DEVICE_VMK8061},
87	{USB_DEVICE(0x10cf, 0x8063), .driver_info = DEVICE_VMK8061},
88	{USB_DEVICE(0x10cf, 0x8064), .driver_info = DEVICE_VMK8061},
89	{USB_DEVICE(0x10cf, 0x8065), .driver_info = DEVICE_VMK8061},
90	{USB_DEVICE(0x10cf, 0x8066), .driver_info = DEVICE_VMK8061},
91	{USB_DEVICE(0x10cf, 0x8067), .driver_info = DEVICE_VMK8061},
92	{USB_DEVICE(0x10cf, 0x8068), .driver_info = DEVICE_VMK8061},
93	{}			/* terminating entry */
94};
95
96MODULE_DEVICE_TABLE(usb, vmk80xx_id_table);
97
98#define VMK8055_DI_REG          0x00
99#define VMK8055_DO_REG          0x01
100#define VMK8055_AO1_REG         0x02
101#define VMK8055_AO2_REG         0x03
102#define VMK8055_AI1_REG         0x02
103#define VMK8055_AI2_REG         0x03
104#define VMK8055_CNT1_REG        0x04
105#define VMK8055_CNT2_REG        0x06
106
107#define VMK8061_CH_REG          0x01
108#define VMK8061_DI_REG          0x01
109#define VMK8061_DO_REG          0x01
110#define VMK8061_PWM_REG1        0x01
111#define VMK8061_PWM_REG2        0x02
112#define VMK8061_CNT_REG         0x02
113#define VMK8061_AO_REG          0x02
114#define VMK8061_AI_REG1         0x02
115#define VMK8061_AI_REG2         0x03
116
117#define VMK8055_CMD_RST         0x00
118#define VMK8055_CMD_DEB1_TIME   0x01
119#define VMK8055_CMD_DEB2_TIME   0x02
120#define VMK8055_CMD_RST_CNT1    0x03
121#define VMK8055_CMD_RST_CNT2    0x04
122#define VMK8055_CMD_WRT_AD      0x05
123
124#define VMK8061_CMD_RD_AI       0x00
125#define VMK8061_CMR_RD_ALL_AI   0x01	/* !non-active! */
126#define VMK8061_CMD_SET_AO      0x02
127#define VMK8061_CMD_SET_ALL_AO  0x03	/* !non-active! */
128#define VMK8061_CMD_OUT_PWM     0x04
129#define VMK8061_CMD_RD_DI       0x05
130#define VMK8061_CMD_DO          0x06	/* !non-active! */
131#define VMK8061_CMD_CLR_DO      0x07
132#define VMK8061_CMD_SET_DO      0x08
133#define VMK8061_CMD_RD_CNT      0x09	/* TODO: completely pointless? */
134#define VMK8061_CMD_RST_CNT     0x0a	/* TODO: completely pointless? */
135#define VMK8061_CMD_RD_VERSION  0x0b	/* internal usage */
136#define VMK8061_CMD_RD_JMP_STAT 0x0c	/* TODO: not implemented yet */
137#define VMK8061_CMD_RD_PWR_STAT 0x0d	/* internal usage */
138#define VMK8061_CMD_RD_DO       0x0e
139#define VMK8061_CMD_RD_AO       0x0f
140#define VMK8061_CMD_RD_PWM      0x10
141
142#define VMK80XX_MAX_BOARDS      COMEDI_NUM_BOARD_MINORS
143
144#define TRANS_OUT_BUSY          1
145#define TRANS_IN_BUSY           2
146#define TRANS_IN_RUNNING        3
147
148#define IC3_VERSION             (1 << 0)
149#define IC6_VERSION             (1 << 1)
150
151#define URB_RCV_FLAG            (1 << 0)
152#define URB_SND_FLAG            (1 << 1)
153
154#define CONFIG_VMK80XX_DEBUG
155#undef CONFIG_VMK80XX_DEBUG
156
157#ifdef CONFIG_VMK80XX_DEBUG
158static int dbgvm = 1;
159#else
160static int dbgvm;
161#endif
162
163#ifdef CONFIG_COMEDI_DEBUG
164static int dbgcm = 1;
165#else
166static int dbgcm;
167#endif
168
169#define dbgvm(fmt, arg...)                     \
170do {                                           \
171	if (dbgvm)                             \
172		printk(KERN_DEBUG fmt, ##arg); \
173} while (0)
174
175#define dbgcm(fmt, arg...)                     \
176do {                                           \
177	if (dbgcm)                             \
178		printk(KERN_DEBUG fmt, ##arg); \
179} while (0)
180
181enum vmk80xx_model {
182	VMK8055_MODEL,
183	VMK8061_MODEL
184};
185
186struct firmware_version {
187	unsigned char ic3_vers[32];	/* USB-Controller */
188	unsigned char ic6_vers[32];	/* CPU */
189};
190
191static const struct comedi_lrange vmk8055_range = {
192	1, {UNI_RANGE(5)}
193};
194
195static const struct comedi_lrange vmk8061_range = {
196	2, {UNI_RANGE(5), UNI_RANGE(10)}
197};
198
199struct vmk80xx_board {
200	const char *name;
201	enum vmk80xx_model model;
202	const struct comedi_lrange *range;
203	__u8 ai_chans;
204	__le16 ai_bits;
205	__u8 ao_chans;
206	__le16 ao_bits;
207	__u8 di_chans;
208	__le16 di_bits;
209	__u8 do_chans;
210	__le16 do_bits;
211	__u8 cnt_chans;
212	__le16 cnt_bits;
213	__u8 pwm_chans;
214	__le16 pwm_bits;
215};
216
217enum {
218	VMK80XX_SUBD_AI,
219	VMK80XX_SUBD_AO,
220	VMK80XX_SUBD_DI,
221	VMK80XX_SUBD_DO,
222	VMK80XX_SUBD_CNT,
223	VMK80XX_SUBD_PWM,
224};
225
226struct vmk80xx_usb {
227	struct usb_device *udev;
228	struct usb_interface *intf;
229	struct usb_endpoint_descriptor *ep_rx;
230	struct usb_endpoint_descriptor *ep_tx;
231	struct usb_anchor rx_anchor;
232	struct usb_anchor tx_anchor;
233	struct vmk80xx_board board;
234	struct firmware_version fw;
235	struct semaphore limit_sem;
236	wait_queue_head_t read_wait;
237	wait_queue_head_t write_wait;
238	unsigned char *usb_rx_buf;
239	unsigned char *usb_tx_buf;
240	unsigned long flags;
241	int probed;
242	int attached;
243	int count;
244};
245
246static struct vmk80xx_usb vmb[VMK80XX_MAX_BOARDS];
247
248static DEFINE_MUTEX(glb_mutex);
249
250static void vmk80xx_tx_callback(struct urb *urb)
251{
252	struct vmk80xx_usb *dev = urb->context;
253	int stat = urb->status;
254
255	dbgvm("vmk80xx: %s\n", __func__);
256
257	if (stat && !(stat == -ENOENT
258		      || stat == -ECONNRESET || stat == -ESHUTDOWN))
259		dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
260		      __func__, stat);
261
262	if (!test_bit(TRANS_OUT_BUSY, &dev->flags))
263		return;
264
265	clear_bit(TRANS_OUT_BUSY, &dev->flags);
266
267	wake_up_interruptible(&dev->write_wait);
268}
269
270static void vmk80xx_rx_callback(struct urb *urb)
271{
272	struct vmk80xx_usb *dev = urb->context;
273	int stat = urb->status;
274
275	dbgvm("vmk80xx: %s\n", __func__);
276
277	switch (stat) {
278	case 0:
279		break;
280	case -ENOENT:
281	case -ECONNRESET:
282	case -ESHUTDOWN:
283		break;
284	default:
285		dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
286		      __func__, stat);
287		goto resubmit;
288	}
289
290	goto exit;
291resubmit:
292	if (test_bit(TRANS_IN_RUNNING, &dev->flags) && dev->intf) {
293		usb_anchor_urb(urb, &dev->rx_anchor);
294
295		if (!usb_submit_urb(urb, GFP_KERNEL))
296			goto exit;
297
298		err("comedi#: vmk80xx: %s - submit urb failed\n", __func__);
299
300		usb_unanchor_urb(urb);
301	}
302exit:
303	clear_bit(TRANS_IN_BUSY, &dev->flags);
304
305	wake_up_interruptible(&dev->read_wait);
306}
307
308static int vmk80xx_check_data_link(struct vmk80xx_usb *dev)
309{
310	unsigned int tx_pipe;
311	unsigned int rx_pipe;
312	unsigned char tx[1];
313	unsigned char rx[2];
314
315	dbgvm("vmk80xx: %s\n", __func__);
316
317	tx_pipe = usb_sndbulkpipe(dev->udev, 0x01);
318	rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81);
319
320	tx[0] = VMK8061_CMD_RD_PWR_STAT;
321
322	/*
323	 * Check that IC6 (PIC16F871) is powered and
324	 * running and the data link between IC3 and
325	 * IC6 is working properly
326	 */
327	usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL, dev->ep_tx->bInterval);
328	usb_bulk_msg(dev->udev, rx_pipe, rx, 2, NULL, HZ * 10);
329
330	return (int)rx[1];
331}
332
333static void vmk80xx_read_eeprom(struct vmk80xx_usb *dev, int flag)
334{
335	unsigned int tx_pipe;
336	unsigned int rx_pipe;
337	unsigned char tx[1];
338	unsigned char rx[64];
339	int cnt;
340
341	dbgvm("vmk80xx: %s\n", __func__);
342
343	tx_pipe = usb_sndbulkpipe(dev->udev, 0x01);
344	rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81);
345
346	tx[0] = VMK8061_CMD_RD_VERSION;
347
348	/*
349	 * Read the firmware version info of IC3 and
350	 * IC6 from the internal EEPROM of the IC
351	 */
352	usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL, dev->ep_tx->bInterval);
353	usb_bulk_msg(dev->udev, rx_pipe, rx, 64, &cnt, HZ * 10);
354
355	rx[cnt] = '\0';
356
357	if (flag & IC3_VERSION)
358		strncpy(dev->fw.ic3_vers, rx + 1, 24);
359	else			/* IC6_VERSION */
360		strncpy(dev->fw.ic6_vers, rx + 25, 24);
361}
362
363static int vmk80xx_reset_device(struct vmk80xx_usb *dev)
364{
365	struct urb *urb;
366	unsigned int tx_pipe;
367	int ival;
368	size_t size;
369
370	dbgvm("vmk80xx: %s\n", __func__);
371
372	urb = usb_alloc_urb(0, GFP_KERNEL);
373	if (!urb)
374		return -ENOMEM;
375
376	tx_pipe = usb_sndintpipe(dev->udev, 0x01);
377
378	ival = dev->ep_tx->bInterval;
379	size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
380
381	dev->usb_tx_buf[0] = VMK8055_CMD_RST;
382	dev->usb_tx_buf[1] = 0x00;
383	dev->usb_tx_buf[2] = 0x00;
384	dev->usb_tx_buf[3] = 0x00;
385	dev->usb_tx_buf[4] = 0x00;
386	dev->usb_tx_buf[5] = 0x00;
387	dev->usb_tx_buf[6] = 0x00;
388	dev->usb_tx_buf[7] = 0x00;
389
390	usb_fill_int_urb(urb, dev->udev, tx_pipe, dev->usb_tx_buf,
391			 size, vmk80xx_tx_callback, dev, ival);
392
393	usb_anchor_urb(urb, &dev->tx_anchor);
394
395	return usb_submit_urb(urb, GFP_KERNEL);
396}
397
398static void vmk80xx_build_int_urb(struct urb *urb, int flag)
399{
400	struct vmk80xx_usb *dev = urb->context;
401	__u8 rx_addr;
402	__u8 tx_addr;
403	unsigned int pipe;
404	unsigned char *buf;
405	size_t size;
406	void (*callback) (struct urb *);
407	int ival;
408
409	dbgvm("vmk80xx: %s\n", __func__);
410
411	if (flag & URB_RCV_FLAG) {
412		rx_addr = dev->ep_rx->bEndpointAddress;
413		pipe = usb_rcvintpipe(dev->udev, rx_addr);
414		buf = dev->usb_rx_buf;
415		size = le16_to_cpu(dev->ep_rx->wMaxPacketSize);
416		callback = vmk80xx_rx_callback;
417		ival = dev->ep_rx->bInterval;
418	} else {		/* URB_SND_FLAG */
419		tx_addr = dev->ep_tx->bEndpointAddress;
420		pipe = usb_sndintpipe(dev->udev, tx_addr);
421		buf = dev->usb_tx_buf;
422		size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
423		callback = vmk80xx_tx_callback;
424		ival = dev->ep_tx->bInterval;
425	}
426
427	usb_fill_int_urb(urb, dev->udev, pipe, buf, size, callback, dev, ival);
428}
429
430static void vmk80xx_do_bulk_msg(struct vmk80xx_usb *dev)
431{
432	__u8 tx_addr;
433	__u8 rx_addr;
434	unsigned int tx_pipe;
435	unsigned int rx_pipe;
436	size_t size;
437
438	dbgvm("vmk80xx: %s\n", __func__);
439
440	set_bit(TRANS_IN_BUSY, &dev->flags);
441	set_bit(TRANS_OUT_BUSY, &dev->flags);
442
443	tx_addr = dev->ep_tx->bEndpointAddress;
444	rx_addr = dev->ep_rx->bEndpointAddress;
445	tx_pipe = usb_sndbulkpipe(dev->udev, tx_addr);
446	rx_pipe = usb_rcvbulkpipe(dev->udev, rx_addr);
447
448	/*
449	 * The max packet size attributes of the K8061
450	 * input/output endpoints are identical
451	 */
452	size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
453
454	usb_bulk_msg(dev->udev, tx_pipe, dev->usb_tx_buf,
455		     size, NULL, dev->ep_tx->bInterval);
456	usb_bulk_msg(dev->udev, rx_pipe, dev->usb_rx_buf, size, NULL, HZ * 10);
457
458	clear_bit(TRANS_OUT_BUSY, &dev->flags);
459	clear_bit(TRANS_IN_BUSY, &dev->flags);
460}
461
462static int vmk80xx_read_packet(struct vmk80xx_usb *dev)
463{
464	struct urb *urb;
465	int retval;
466
467	dbgvm("vmk80xx: %s\n", __func__);
468
469	if (!dev->intf)
470		return -ENODEV;
471
472	/* Only useful for interrupt transfers */
473	if (test_bit(TRANS_IN_BUSY, &dev->flags))
474		if (wait_event_interruptible(dev->read_wait,
475					     !test_bit(TRANS_IN_BUSY,
476						       &dev->flags)))
477			return -ERESTART;
478
479	if (dev->board.model == VMK8061_MODEL) {
480		vmk80xx_do_bulk_msg(dev);
481
482		return 0;
483	}
484
485	urb = usb_alloc_urb(0, GFP_KERNEL);
486	if (!urb)
487		return -ENOMEM;
488
489	urb->context = dev;
490	vmk80xx_build_int_urb(urb, URB_RCV_FLAG);
491
492	set_bit(TRANS_IN_RUNNING, &dev->flags);
493	set_bit(TRANS_IN_BUSY, &dev->flags);
494
495	usb_anchor_urb(urb, &dev->rx_anchor);
496
497	retval = usb_submit_urb(urb, GFP_KERNEL);
498	if (!retval)
499		goto exit;
500
501	clear_bit(TRANS_IN_RUNNING, &dev->flags);
502	usb_unanchor_urb(urb);
503
504exit:
505	usb_free_urb(urb);
506
507	return retval;
508}
509
510static int vmk80xx_write_packet(struct vmk80xx_usb *dev, int cmd)
511{
512	struct urb *urb;
513	int retval;
514
515	dbgvm("vmk80xx: %s\n", __func__);
516
517	if (!dev->intf)
518		return -ENODEV;
519
520	if (test_bit(TRANS_OUT_BUSY, &dev->flags))
521		if (wait_event_interruptible(dev->write_wait,
522					     !test_bit(TRANS_OUT_BUSY,
523						       &dev->flags)))
524			return -ERESTART;
525
526	if (dev->board.model == VMK8061_MODEL) {
527		dev->usb_tx_buf[0] = cmd;
528		vmk80xx_do_bulk_msg(dev);
529
530		return 0;
531	}
532
533	urb = usb_alloc_urb(0, GFP_KERNEL);
534	if (!urb)
535		return -ENOMEM;
536
537	urb->context = dev;
538	vmk80xx_build_int_urb(urb, URB_SND_FLAG);
539
540	set_bit(TRANS_OUT_BUSY, &dev->flags);
541
542	usb_anchor_urb(urb, &dev->tx_anchor);
543
544	dev->usb_tx_buf[0] = cmd;
545
546	retval = usb_submit_urb(urb, GFP_KERNEL);
547	if (!retval)
548		goto exit;
549
550	clear_bit(TRANS_OUT_BUSY, &dev->flags);
551	usb_unanchor_urb(urb);
552
553exit:
554	usb_free_urb(urb);
555
556	return retval;
557}
558
559#define DIR_IN  1
560#define DIR_OUT 2
561
562static int rudimentary_check(struct vmk80xx_usb *dev, int dir)
563{
564	if (!dev)
565		return -EFAULT;
566	if (!dev->probed)
567		return -ENODEV;
568	if (!dev->attached)
569		return -ENODEV;
570	if (dir & DIR_IN) {
571		if (test_bit(TRANS_IN_BUSY, &dev->flags))
572			return -EBUSY;
573	}
574	if (dir & DIR_OUT) {
575		if (test_bit(TRANS_OUT_BUSY, &dev->flags))
576			return -EBUSY;
577	}
578
579	return 0;
580}
581
582static int vmk80xx_ai_rinsn(struct comedi_device *cdev,
583			    struct comedi_subdevice *s,
584			    struct comedi_insn *insn, unsigned int *data)
585{
586	struct vmk80xx_usb *dev = cdev->private;
587	int chan;
588	int reg[2];
589	int n;
590
591	dbgvm("vmk80xx: %s\n", __func__);
592
593	n = rudimentary_check(dev, DIR_IN);
594	if (n)
595		return n;
596
597	down(&dev->limit_sem);
598	chan = CR_CHAN(insn->chanspec);
599
600	switch (dev->board.model) {
601	case VMK8055_MODEL:
602		if (!chan)
603			reg[0] = VMK8055_AI1_REG;
604		else
605			reg[0] = VMK8055_AI2_REG;
606		break;
607	case VMK8061_MODEL:
608		reg[0] = VMK8061_AI_REG1;
609		reg[1] = VMK8061_AI_REG2;
610		dev->usb_tx_buf[0] = VMK8061_CMD_RD_AI;
611		dev->usb_tx_buf[VMK8061_CH_REG] = chan;
612		break;
613	}
614
615	for (n = 0; n < insn->n; n++) {
616		if (vmk80xx_read_packet(dev))
617			break;
618
619		if (dev->board.model == VMK8055_MODEL) {
620			data[n] = dev->usb_rx_buf[reg[0]];
621			continue;
622		}
623
624		/* VMK8061_MODEL */
625		data[n] = dev->usb_rx_buf[reg[0]] + 256 *
626		    dev->usb_rx_buf[reg[1]];
627	}
628
629	up(&dev->limit_sem);
630
631	return n;
632}
633
634static int vmk80xx_ao_winsn(struct comedi_device *cdev,
635			    struct comedi_subdevice *s,
636			    struct comedi_insn *insn, unsigned int *data)
637{
638	struct vmk80xx_usb *dev = cdev->private;
639	int chan;
640	int cmd;
641	int reg;
642	int n;
643
644	dbgvm("vmk80xx: %s\n", __func__);
645
646	n = rudimentary_check(dev, DIR_OUT);
647	if (n)
648		return n;
649
650	down(&dev->limit_sem);
651	chan = CR_CHAN(insn->chanspec);
652
653	switch (dev->board.model) {
654	case VMK8055_MODEL:
655		cmd = VMK8055_CMD_WRT_AD;
656		if (!chan)
657			reg = VMK8055_AO1_REG;
658		else
659			reg = VMK8055_AO2_REG;
660		break;
661	default:		/* NOTE: avoid compiler warnings */
662		cmd = VMK8061_CMD_SET_AO;
663		reg = VMK8061_AO_REG;
664		dev->usb_tx_buf[VMK8061_CH_REG] = chan;
665		break;
666	}
667
668	for (n = 0; n < insn->n; n++) {
669		dev->usb_tx_buf[reg] = data[n];
670
671		if (vmk80xx_write_packet(dev, cmd))
672			break;
673	}
674
675	up(&dev->limit_sem);
676
677	return n;
678}
679
680static int vmk80xx_ao_rinsn(struct comedi_device *cdev,
681			    struct comedi_subdevice *s,
682			    struct comedi_insn *insn, unsigned int *data)
683{
684	struct vmk80xx_usb *dev = cdev->private;
685	int chan;
686	int reg;
687	int n;
688
689	dbgvm("vmk80xx: %s\n", __func__);
690
691	n = rudimentary_check(dev, DIR_IN);
692	if (n)
693		return n;
694
695	down(&dev->limit_sem);
696	chan = CR_CHAN(insn->chanspec);
697
698	reg = VMK8061_AO_REG - 1;
699
700	dev->usb_tx_buf[0] = VMK8061_CMD_RD_AO;
701
702	for (n = 0; n < insn->n; n++) {
703		if (vmk80xx_read_packet(dev))
704			break;
705
706		data[n] = dev->usb_rx_buf[reg + chan];
707	}
708
709	up(&dev->limit_sem);
710
711	return n;
712}
713
714static int vmk80xx_di_bits(struct comedi_device *cdev,
715			   struct comedi_subdevice *s,
716			   struct comedi_insn *insn, unsigned int *data)
717{
718	struct vmk80xx_usb *dev = cdev->private;
719	unsigned char *rx_buf;
720	int reg;
721	int retval;
722
723	dbgvm("vmk80xx: %s\n", __func__);
724
725	retval = rudimentary_check(dev, DIR_IN);
726	if (retval)
727		return retval;
728
729	down(&dev->limit_sem);
730
731	rx_buf = dev->usb_rx_buf;
732
733	if (dev->board.model == VMK8061_MODEL) {
734		reg = VMK8061_DI_REG;
735		dev->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
736	} else {
737		reg = VMK8055_DI_REG;
738	}
739
740	retval = vmk80xx_read_packet(dev);
741
742	if (!retval) {
743		if (dev->board.model == VMK8055_MODEL)
744			data[1] = (((rx_buf[reg] >> 4) & 0x03) |
745				  ((rx_buf[reg] << 2) & 0x04) |
746				  ((rx_buf[reg] >> 3) & 0x18));
747		else
748			data[1] = rx_buf[reg];
749
750		retval = 2;
751	}
752
753	up(&dev->limit_sem);
754
755	return retval;
756}
757
758static int vmk80xx_di_rinsn(struct comedi_device *cdev,
759			    struct comedi_subdevice *s,
760			    struct comedi_insn *insn, unsigned int *data)
761{
762	struct vmk80xx_usb *dev = cdev->private;
763	int chan;
764	unsigned char *rx_buf;
765	int reg;
766	int inp;
767	int n;
768
769	dbgvm("vmk80xx: %s\n", __func__);
770
771	n = rudimentary_check(dev, DIR_IN);
772	if (n)
773		return n;
774
775	down(&dev->limit_sem);
776	chan = CR_CHAN(insn->chanspec);
777
778	rx_buf = dev->usb_rx_buf;
779
780	if (dev->board.model == VMK8061_MODEL) {
781		reg = VMK8061_DI_REG;
782		dev->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
783	} else {
784		reg = VMK8055_DI_REG;
785	}
786	for (n = 0; n < insn->n; n++) {
787		if (vmk80xx_read_packet(dev))
788			break;
789
790		if (dev->board.model == VMK8055_MODEL)
791			inp = (((rx_buf[reg] >> 4) & 0x03) |
792			       ((rx_buf[reg] << 2) & 0x04) |
793			       ((rx_buf[reg] >> 3) & 0x18));
794		else
795			inp = rx_buf[reg];
796
797		data[n] = (inp >> chan) & 1;
798	}
799
800	up(&dev->limit_sem);
801
802	return n;
803}
804
805static int vmk80xx_do_winsn(struct comedi_device *cdev,
806			    struct comedi_subdevice *s,
807			    struct comedi_insn *insn, unsigned int *data)
808{
809	struct vmk80xx_usb *dev = cdev->private;
810	int chan;
811	unsigned char *tx_buf;
812	int reg;
813	int cmd;
814	int n;
815
816	dbgvm("vmk80xx: %s\n", __func__);
817
818	n = rudimentary_check(dev, DIR_OUT);
819	if (n)
820		return n;
821
822	down(&dev->limit_sem);
823	chan = CR_CHAN(insn->chanspec);
824
825	tx_buf = dev->usb_tx_buf;
826
827	for (n = 0; n < insn->n; n++) {
828		if (dev->board.model == VMK8055_MODEL) {
829			reg = VMK8055_DO_REG;
830			cmd = VMK8055_CMD_WRT_AD;
831			if (data[n] == 1)
832				tx_buf[reg] |= (1 << chan);
833			else
834				tx_buf[reg] ^= (1 << chan);
835		} else { /* VMK8061_MODEL */
836			reg = VMK8061_DO_REG;
837			if (data[n] == 1) {
838				cmd = VMK8061_CMD_SET_DO;
839				tx_buf[reg] = 1 << chan;
840			} else {
841				cmd = VMK8061_CMD_CLR_DO;
842				tx_buf[reg] = 0xff - (1 << chan);
843			}
844		}
845
846		if (vmk80xx_write_packet(dev, cmd))
847			break;
848	}
849
850	up(&dev->limit_sem);
851
852	return n;
853}
854
855static int vmk80xx_do_rinsn(struct comedi_device *cdev,
856			    struct comedi_subdevice *s,
857			    struct comedi_insn *insn, unsigned int *data)
858{
859	struct vmk80xx_usb *dev = cdev->private;
860	int chan;
861	int reg;
862	int n;
863
864	dbgvm("vmk80xx: %s\n", __func__);
865
866	n = rudimentary_check(dev, DIR_IN);
867	if (n)
868		return n;
869
870	down(&dev->limit_sem);
871	chan = CR_CHAN(insn->chanspec);
872
873	reg = VMK8061_DO_REG;
874
875	dev->usb_tx_buf[0] = VMK8061_CMD_RD_DO;
876
877	for (n = 0; n < insn->n; n++) {
878		if (vmk80xx_read_packet(dev))
879			break;
880
881		data[n] = (dev->usb_rx_buf[reg] >> chan) & 1;
882	}
883
884	up(&dev->limit_sem);
885
886	return n;
887}
888
889static int vmk80xx_do_bits(struct comedi_device *cdev,
890			   struct comedi_subdevice *s,
891			   struct comedi_insn *insn, unsigned int *data)
892{
893	struct vmk80xx_usb *dev = cdev->private;
894	unsigned char *rx_buf, *tx_buf;
895	int dir, reg, cmd;
896	int retval;
897
898	dbgvm("vmk80xx: %s\n", __func__);
899
900	dir = 0;
901
902	if (data[0])
903		dir |= DIR_OUT;
904
905	if (dev->board.model == VMK8061_MODEL)
906		dir |= DIR_IN;
907
908	retval = rudimentary_check(dev, dir);
909	if (retval)
910		return retval;
911
912	down(&dev->limit_sem);
913
914	rx_buf = dev->usb_rx_buf;
915	tx_buf = dev->usb_tx_buf;
916
917	if (data[0]) {
918		if (dev->board.model == VMK8055_MODEL) {
919			reg = VMK8055_DO_REG;
920			cmd = VMK8055_CMD_WRT_AD;
921		} else { /* VMK8061_MODEL */
922			reg = VMK8061_DO_REG;
923			cmd = VMK8061_CMD_DO;
924		}
925
926		tx_buf[reg] &= ~data[0];
927		tx_buf[reg] |= (data[0] & data[1]);
928
929		retval = vmk80xx_write_packet(dev, cmd);
930
931		if (retval)
932			goto out;
933	}
934
935	if (dev->board.model == VMK8061_MODEL) {
936		reg = VMK8061_DO_REG;
937		tx_buf[0] = VMK8061_CMD_RD_DO;
938
939		retval = vmk80xx_read_packet(dev);
940
941		if (!retval) {
942			data[1] = rx_buf[reg];
943			retval = 2;
944		}
945	} else {
946		data[1] = tx_buf[reg];
947		retval = 2;
948	}
949
950out:
951	up(&dev->limit_sem);
952
953	return retval;
954}
955
956static int vmk80xx_cnt_rinsn(struct comedi_device *cdev,
957			     struct comedi_subdevice *s,
958			     struct comedi_insn *insn, unsigned int *data)
959{
960	struct vmk80xx_usb *dev = cdev->private;
961	int chan;
962	int reg[2];
963	int n;
964
965	dbgvm("vmk80xx: %s\n", __func__);
966
967	n = rudimentary_check(dev, DIR_IN);
968	if (n)
969		return n;
970
971	down(&dev->limit_sem);
972	chan = CR_CHAN(insn->chanspec);
973
974	switch (dev->board.model) {
975	case VMK8055_MODEL:
976		if (!chan)
977			reg[0] = VMK8055_CNT1_REG;
978		else
979			reg[0] = VMK8055_CNT2_REG;
980		break;
981	case VMK8061_MODEL:
982		reg[0] = VMK8061_CNT_REG;
983		reg[1] = VMK8061_CNT_REG;
984		dev->usb_tx_buf[0] = VMK8061_CMD_RD_CNT;
985		break;
986	}
987
988	for (n = 0; n < insn->n; n++) {
989		if (vmk80xx_read_packet(dev))
990			break;
991
992		if (dev->board.model == VMK8055_MODEL)
993			data[n] = dev->usb_rx_buf[reg[0]];
994		else /* VMK8061_MODEL */
995			data[n] = dev->usb_rx_buf[reg[0] * (chan + 1) + 1]
996			    + 256 * dev->usb_rx_buf[reg[1] * 2 + 2];
997	}
998
999	up(&dev->limit_sem);
1000
1001	return n;
1002}
1003
1004static int vmk80xx_cnt_cinsn(struct comedi_device *cdev,
1005			     struct comedi_subdevice *s,
1006			     struct comedi_insn *insn, unsigned int *data)
1007{
1008	struct vmk80xx_usb *dev = cdev->private;
1009	unsigned int insn_cmd;
1010	int chan;
1011	int cmd;
1012	int reg;
1013	int n;
1014
1015	dbgvm("vmk80xx: %s\n", __func__);
1016
1017	n = rudimentary_check(dev, DIR_OUT);
1018	if (n)
1019		return n;
1020
1021	down(&dev->limit_sem);
1022
1023	insn_cmd = data[0];
1024	if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET)
1025		return -EINVAL;
1026
1027	chan = CR_CHAN(insn->chanspec);
1028
1029	if (dev->board.model == VMK8055_MODEL) {
1030		if (!chan) {
1031			cmd = VMK8055_CMD_RST_CNT1;
1032			reg = VMK8055_CNT1_REG;
1033		} else {
1034			cmd = VMK8055_CMD_RST_CNT2;
1035			reg = VMK8055_CNT2_REG;
1036		}
1037
1038		dev->usb_tx_buf[reg] = 0x00;
1039	} else {
1040		cmd = VMK8061_CMD_RST_CNT;
1041	}
1042
1043	for (n = 0; n < insn->n; n++)
1044		if (vmk80xx_write_packet(dev, cmd))
1045			break;
1046
1047	up(&dev->limit_sem);
1048
1049	return n;
1050}
1051
1052static int vmk80xx_cnt_winsn(struct comedi_device *cdev,
1053			     struct comedi_subdevice *s,
1054			     struct comedi_insn *insn, unsigned int *data)
1055{
1056	struct vmk80xx_usb *dev = cdev->private;
1057	unsigned long debtime;
1058	unsigned long val;
1059	int chan;
1060	int cmd;
1061	int n;
1062
1063	dbgvm("vmk80xx: %s\n", __func__);
1064
1065	n = rudimentary_check(dev, DIR_OUT);
1066	if (n)
1067		return n;
1068
1069	down(&dev->limit_sem);
1070	chan = CR_CHAN(insn->chanspec);
1071
1072	if (!chan)
1073		cmd = VMK8055_CMD_DEB1_TIME;
1074	else
1075		cmd = VMK8055_CMD_DEB2_TIME;
1076
1077	for (n = 0; n < insn->n; n++) {
1078		debtime = data[n];
1079		if (debtime == 0)
1080			debtime = 1;
1081
1082		/* TODO: Prevent overflows */
1083		if (debtime > 7450)
1084			debtime = 7450;
1085
1086		val = int_sqrt(debtime * 1000 / 115);
1087		if (((val + 1) * val) < debtime * 1000 / 115)
1088			val += 1;
1089
1090		dev->usb_tx_buf[6 + chan] = val;
1091
1092		if (vmk80xx_write_packet(dev, cmd))
1093			break;
1094	}
1095
1096	up(&dev->limit_sem);
1097
1098	return n;
1099}
1100
1101static int vmk80xx_pwm_rinsn(struct comedi_device *cdev,
1102			     struct comedi_subdevice *s,
1103			     struct comedi_insn *insn, unsigned int *data)
1104{
1105	struct vmk80xx_usb *dev = cdev->private;
1106	int reg[2];
1107	int n;
1108
1109	dbgvm("vmk80xx: %s\n", __func__);
1110
1111	n = rudimentary_check(dev, DIR_IN);
1112	if (n)
1113		return n;
1114
1115	down(&dev->limit_sem);
1116
1117	reg[0] = VMK8061_PWM_REG1;
1118	reg[1] = VMK8061_PWM_REG2;
1119
1120	dev->usb_tx_buf[0] = VMK8061_CMD_RD_PWM;
1121
1122	for (n = 0; n < insn->n; n++) {
1123		if (vmk80xx_read_packet(dev))
1124			break;
1125
1126		data[n] = dev->usb_rx_buf[reg[0]] + 4 * dev->usb_rx_buf[reg[1]];
1127	}
1128
1129	up(&dev->limit_sem);
1130
1131	return n;
1132}
1133
1134static int vmk80xx_pwm_winsn(struct comedi_device *cdev,
1135			     struct comedi_subdevice *s,
1136			     struct comedi_insn *insn, unsigned int *data)
1137{
1138	struct vmk80xx_usb *dev = cdev->private;
1139	unsigned char *tx_buf;
1140	int reg[2];
1141	int cmd;
1142	int n;
1143
1144	dbgvm("vmk80xx: %s\n", __func__);
1145
1146	n = rudimentary_check(dev, DIR_OUT);
1147	if (n)
1148		return n;
1149
1150	down(&dev->limit_sem);
1151
1152	tx_buf = dev->usb_tx_buf;
1153
1154	reg[0] = VMK8061_PWM_REG1;
1155	reg[1] = VMK8061_PWM_REG2;
1156
1157	cmd = VMK8061_CMD_OUT_PWM;
1158
1159	/*
1160	 * The followin piece of code was translated from the inline
1161	 * assembler code in the DLL source code.
1162	 *
1163	 * asm
1164	 *   mov eax, k  ; k is the value (data[n])
1165	 *   and al, 03h ; al are the lower 8 bits of eax
1166	 *   mov lo, al  ; lo is the low part (tx_buf[reg[0]])
1167	 *   mov eax, k
1168	 *   shr eax, 2  ; right shift eax register by 2
1169	 *   mov hi, al  ; hi is the high part (tx_buf[reg[1]])
1170	 * end;
1171	 */
1172	for (n = 0; n < insn->n; n++) {
1173		tx_buf[reg[0]] = (unsigned char)(data[n] & 0x03);
1174		tx_buf[reg[1]] = (unsigned char)(data[n] >> 2) & 0xff;
1175
1176		if (vmk80xx_write_packet(dev, cmd))
1177			break;
1178	}
1179
1180	up(&dev->limit_sem);
1181
1182	return n;
1183}
1184
1185static int vmk80xx_attach(struct comedi_device *cdev,
1186			  struct comedi_devconfig *it)
1187{
1188	int i;
1189	struct vmk80xx_usb *dev;
1190	int n_subd;
1191	struct comedi_subdevice *s;
1192	int minor;
1193
1194	dbgvm("vmk80xx: %s\n", __func__);
1195
1196	mutex_lock(&glb_mutex);
1197
1198	for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
1199		if (vmb[i].probed && !vmb[i].attached)
1200			break;
1201
1202	if (i == VMK80XX_MAX_BOARDS) {
1203		mutex_unlock(&glb_mutex);
1204		return -ENODEV;
1205	}
1206
1207	dev = &vmb[i];
1208
1209	down(&dev->limit_sem);
1210
1211	cdev->board_name = dev->board.name;
1212	cdev->private = dev;
1213
1214	if (dev->board.model == VMK8055_MODEL)
1215		n_subd = 5;
1216	else
1217		n_subd = 6;
1218
1219	if (alloc_subdevices(cdev, n_subd) < 0) {
1220		up(&dev->limit_sem);
1221		mutex_unlock(&glb_mutex);
1222		return -ENOMEM;
1223	}
1224
1225	/* Analog input subdevice */
1226	s = cdev->subdevices + VMK80XX_SUBD_AI;
1227	s->type = COMEDI_SUBD_AI;
1228	s->subdev_flags = SDF_READABLE | SDF_GROUND;
1229	s->n_chan = dev->board.ai_chans;
1230	s->maxdata = (1 << dev->board.ai_bits) - 1;
1231	s->range_table = dev->board.range;
1232	s->insn_read = vmk80xx_ai_rinsn;
1233
1234	/* Analog output subdevice */
1235	s = cdev->subdevices + VMK80XX_SUBD_AO;
1236	s->type = COMEDI_SUBD_AO;
1237	s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
1238	s->n_chan = dev->board.ao_chans;
1239	s->maxdata = (1 << dev->board.ao_bits) - 1;
1240	s->range_table = dev->board.range;
1241	s->insn_write = vmk80xx_ao_winsn;
1242
1243	if (dev->board.model == VMK8061_MODEL) {
1244		s->subdev_flags |= SDF_READABLE;
1245		s->insn_read = vmk80xx_ao_rinsn;
1246	}
1247
1248	/* Digital input subdevice */
1249	s = cdev->subdevices + VMK80XX_SUBD_DI;
1250	s->type = COMEDI_SUBD_DI;
1251	s->subdev_flags = SDF_READABLE | SDF_GROUND;
1252	s->n_chan = dev->board.di_chans;
1253	s->maxdata = 1;
1254	s->insn_read = vmk80xx_di_rinsn;
1255	s->insn_bits = vmk80xx_di_bits;
1256
1257	/* Digital output subdevice */
1258	s = cdev->subdevices + VMK80XX_SUBD_DO;
1259	s->type = COMEDI_SUBD_DO;
1260	s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
1261	s->n_chan = dev->board.do_chans;
1262	s->maxdata = 1;
1263	s->insn_write = vmk80xx_do_winsn;
1264	s->insn_bits = vmk80xx_do_bits;
1265
1266	if (dev->board.model == VMK8061_MODEL) {
1267		s->subdev_flags |= SDF_READABLE;
1268		s->insn_read = vmk80xx_do_rinsn;
1269	}
1270
1271	/* Counter subdevice */
1272	s = cdev->subdevices + VMK80XX_SUBD_CNT;
1273	s->type = COMEDI_SUBD_COUNTER;
1274	s->subdev_flags = SDF_READABLE;
1275	s->n_chan = dev->board.cnt_chans;
1276	s->insn_read = vmk80xx_cnt_rinsn;
1277	s->insn_config = vmk80xx_cnt_cinsn;
1278
1279	if (dev->board.model == VMK8055_MODEL) {
1280		s->subdev_flags |= SDF_WRITEABLE;
1281		s->maxdata = (1 << dev->board.cnt_bits) - 1;
1282		s->insn_write = vmk80xx_cnt_winsn;
1283	}
1284
1285	/* PWM subdevice */
1286	if (dev->board.model == VMK8061_MODEL) {
1287		s = cdev->subdevices + VMK80XX_SUBD_PWM;
1288		s->type = COMEDI_SUBD_PWM;
1289		s->subdev_flags = SDF_READABLE | SDF_WRITEABLE;
1290		s->n_chan = dev->board.pwm_chans;
1291		s->maxdata = (1 << dev->board.pwm_bits) - 1;
1292		s->insn_read = vmk80xx_pwm_rinsn;
1293		s->insn_write = vmk80xx_pwm_winsn;
1294	}
1295
1296	dev->attached = 1;
1297
1298	minor = cdev->minor;
1299
1300	printk(KERN_INFO
1301	       "comedi%d: vmk80xx: board #%d [%s] attached to comedi\n",
1302	       minor, dev->count, dev->board.name);
1303
1304	up(&dev->limit_sem);
1305	mutex_unlock(&glb_mutex);
1306
1307	return 0;
1308}
1309
1310static int vmk80xx_detach(struct comedi_device *cdev)
1311{
1312	struct vmk80xx_usb *dev;
1313	int minor;
1314
1315	dbgvm("vmk80xx: %s\n", __func__);
1316
1317	if (!cdev)
1318		return -EFAULT;
1319
1320	dev = cdev->private;
1321	if (!dev)
1322		return -EFAULT;
1323
1324	down(&dev->limit_sem);
1325
1326	cdev->private = NULL;
1327	dev->attached = 0;
1328
1329	minor = cdev->minor;
1330
1331	printk(KERN_INFO
1332	       "comedi%d: vmk80xx: board #%d [%s] detached from comedi\n",
1333	       minor, dev->count, dev->board.name);
1334
1335	up(&dev->limit_sem);
1336
1337	return 0;
1338}
1339
1340static int vmk80xx_probe(struct usb_interface *intf,
1341			 const struct usb_device_id *id)
1342{
1343	int i;
1344	struct vmk80xx_usb *dev;
1345	struct usb_host_interface *iface_desc;
1346	struct usb_endpoint_descriptor *ep_desc;
1347	size_t size;
1348
1349	dbgvm("vmk80xx: %s\n", __func__);
1350
1351	mutex_lock(&glb_mutex);
1352
1353	for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
1354		if (!vmb[i].probed)
1355			break;
1356
1357	if (i == VMK80XX_MAX_BOARDS) {
1358		mutex_unlock(&glb_mutex);
1359		return -EMFILE;
1360	}
1361
1362	dev = &vmb[i];
1363
1364	memset(dev, 0x00, sizeof(struct vmk80xx_usb));
1365	dev->count = i;
1366
1367	iface_desc = intf->cur_altsetting;
1368	if (iface_desc->desc.bNumEndpoints != 2)
1369		goto error;
1370
1371	for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
1372		ep_desc = &iface_desc->endpoint[i].desc;
1373
1374		if (usb_endpoint_is_int_in(ep_desc)) {
1375			dev->ep_rx = ep_desc;
1376			continue;
1377		}
1378
1379		if (usb_endpoint_is_int_out(ep_desc)) {
1380			dev->ep_tx = ep_desc;
1381			continue;
1382		}
1383
1384		if (usb_endpoint_is_bulk_in(ep_desc)) {
1385			dev->ep_rx = ep_desc;
1386			continue;
1387		}
1388
1389		if (usb_endpoint_is_bulk_out(ep_desc)) {
1390			dev->ep_tx = ep_desc;
1391			continue;
1392		}
1393	}
1394
1395	if (!dev->ep_rx || !dev->ep_tx)
1396		goto error;
1397
1398	size = le16_to_cpu(dev->ep_rx->wMaxPacketSize);
1399	dev->usb_rx_buf = kmalloc(size, GFP_KERNEL);
1400	if (!dev->usb_rx_buf) {
1401		mutex_unlock(&glb_mutex);
1402		return -ENOMEM;
1403	}
1404
1405	size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
1406	dev->usb_tx_buf = kmalloc(size, GFP_KERNEL);
1407	if (!dev->usb_tx_buf) {
1408		kfree(dev->usb_rx_buf);
1409		mutex_unlock(&glb_mutex);
1410		return -ENOMEM;
1411	}
1412
1413	dev->udev = interface_to_usbdev(intf);
1414	dev->intf = intf;
1415
1416	sema_init(&dev->limit_sem, 8);
1417	init_waitqueue_head(&dev->read_wait);
1418	init_waitqueue_head(&dev->write_wait);
1419
1420	init_usb_anchor(&dev->rx_anchor);
1421	init_usb_anchor(&dev->tx_anchor);
1422
1423	usb_set_intfdata(intf, dev);
1424
1425	switch (id->driver_info) {
1426	case DEVICE_VMK8055:
1427		dev->board.name = "K8055 (VM110)";
1428		dev->board.model = VMK8055_MODEL;
1429		dev->board.range = &vmk8055_range;
1430		dev->board.ai_chans = 2;
1431		dev->board.ai_bits = 8;
1432		dev->board.ao_chans = 2;
1433		dev->board.ao_bits = 8;
1434		dev->board.di_chans = 5;
1435		dev->board.di_bits = 1;
1436		dev->board.do_chans = 8;
1437		dev->board.do_bits = 1;
1438		dev->board.cnt_chans = 2;
1439		dev->board.cnt_bits = 16;
1440		dev->board.pwm_chans = 0;
1441		dev->board.pwm_bits = 0;
1442		break;
1443	case DEVICE_VMK8061:
1444		dev->board.name = "K8061 (VM140)";
1445		dev->board.model = VMK8061_MODEL;
1446		dev->board.range = &vmk8061_range;
1447		dev->board.ai_chans = 8;
1448		dev->board.ai_bits = 10;
1449		dev->board.ao_chans = 8;
1450		dev->board.ao_bits = 8;
1451		dev->board.di_chans = 8;
1452		dev->board.di_bits = 1;
1453		dev->board.do_chans = 8;
1454		dev->board.do_bits = 1;
1455		dev->board.cnt_chans = 2;
1456		dev->board.cnt_bits = 0;
1457		dev->board.pwm_chans = 1;
1458		dev->board.pwm_bits = 10;
1459		break;
1460	}
1461
1462	if (dev->board.model == VMK8061_MODEL) {
1463		vmk80xx_read_eeprom(dev, IC3_VERSION);
1464		printk(KERN_INFO "comedi#: vmk80xx: %s\n", dev->fw.ic3_vers);
1465
1466		if (vmk80xx_check_data_link(dev)) {
1467			vmk80xx_read_eeprom(dev, IC6_VERSION);
1468			printk(KERN_INFO "comedi#: vmk80xx: %s\n",
1469			       dev->fw.ic6_vers);
1470		} else {
1471			dbgcm("comedi#: vmk80xx: no conn. to CPU\n");
1472		}
1473	}
1474
1475	if (dev->board.model == VMK8055_MODEL)
1476		vmk80xx_reset_device(dev);
1477
1478	dev->probed = 1;
1479
1480	printk(KERN_INFO "comedi#: vmk80xx: board #%d [%s] now attached\n",
1481	       dev->count, dev->board.name);
1482
1483	mutex_unlock(&glb_mutex);
1484
1485	comedi_usb_auto_config(dev->udev, BOARDNAME);
1486
1487	return 0;
1488error:
1489	mutex_unlock(&glb_mutex);
1490
1491	return -ENODEV;
1492}
1493
1494static void vmk80xx_disconnect(struct usb_interface *intf)
1495{
1496	struct vmk80xx_usb *dev = usb_get_intfdata(intf);
1497
1498	dbgvm("vmk80xx: %s\n", __func__);
1499
1500	if (!dev)
1501		return;
1502
1503	comedi_usb_auto_unconfig(dev->udev);
1504
1505	mutex_lock(&glb_mutex);
1506	down(&dev->limit_sem);
1507
1508	dev->probed = 0;
1509	usb_set_intfdata(dev->intf, NULL);
1510
1511	usb_kill_anchored_urbs(&dev->rx_anchor);
1512	usb_kill_anchored_urbs(&dev->tx_anchor);
1513
1514	kfree(dev->usb_rx_buf);
1515	kfree(dev->usb_tx_buf);
1516
1517	printk(KERN_INFO "comedi#: vmk80xx: board #%d [%s] now detached\n",
1518	       dev->count, dev->board.name);
1519
1520	up(&dev->limit_sem);
1521	mutex_unlock(&glb_mutex);
1522}
1523
1524/* TODO: Add support for suspend, resume, pre_reset,
1525 * post_reset and flush */
1526static struct usb_driver vmk80xx_driver = {
1527	.name = "vmk80xx",
1528	.probe = vmk80xx_probe,
1529	.disconnect = vmk80xx_disconnect,
1530	.id_table = vmk80xx_id_table
1531};
1532
1533static struct comedi_driver driver_vmk80xx = {
1534	.module = THIS_MODULE,
1535	.driver_name = "vmk80xx",
1536	.attach = vmk80xx_attach,
1537	.detach = vmk80xx_detach
1538};
1539
1540static int __init vmk80xx_init(void)
1541{
1542	int retval;
1543
1544	printk(KERN_INFO "vmk80xx: version 0.8.01 "
1545	       "Manuel Gebele <forensixs@gmx.de>\n");
1546
1547	retval = comedi_driver_register(&driver_vmk80xx);
1548	if (retval < 0)
1549		return retval;
1550
1551	return usb_register(&vmk80xx_driver);
1552}
1553
1554static void __exit vmk80xx_exit(void)
1555{
1556	comedi_driver_unregister(&driver_vmk80xx);
1557	usb_deregister(&vmk80xx_driver);
1558}
1559
1560module_init(vmk80xx_init);
1561module_exit(vmk80xx_exit);
1562