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