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