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