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