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