staging: comedi: vmk80xx: wait for URBs to complete
[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*/
3faad673
MG
41
42#include <linux/kernel.h>
3faad673
MG
43#include <linux/module.h>
44#include <linux/mutex.h>
45#include <linux/errno.h>
46#include <linux/input.h>
47#include <linux/slab.h>
48#include <linux/poll.h>
49#include <linux/usb.h>
985cafcc
MG
50#include <linux/uaccess.h>
51
52#include "../comedidev.h"
53
985cafcc
MG
54enum {
55 DEVICE_VMK8055,
56 DEVICE_VMK8061
57};
58
985cafcc
MG
59#define VMK8055_DI_REG 0x00
60#define VMK8055_DO_REG 0x01
61#define VMK8055_AO1_REG 0x02
62#define VMK8055_AO2_REG 0x03
63#define VMK8055_AI1_REG 0x02
64#define VMK8055_AI2_REG 0x03
65#define VMK8055_CNT1_REG 0x04
66#define VMK8055_CNT2_REG 0x06
67
68#define VMK8061_CH_REG 0x01
69#define VMK8061_DI_REG 0x01
70#define VMK8061_DO_REG 0x01
71#define VMK8061_PWM_REG1 0x01
72#define VMK8061_PWM_REG2 0x02
73#define VMK8061_CNT_REG 0x02
74#define VMK8061_AO_REG 0x02
75#define VMK8061_AI_REG1 0x02
76#define VMK8061_AI_REG2 0x03
77
78#define VMK8055_CMD_RST 0x00
79#define VMK8055_CMD_DEB1_TIME 0x01
80#define VMK8055_CMD_DEB2_TIME 0x02
81#define VMK8055_CMD_RST_CNT1 0x03
82#define VMK8055_CMD_RST_CNT2 0x04
83#define VMK8055_CMD_WRT_AD 0x05
84
85#define VMK8061_CMD_RD_AI 0x00
0a85b6f0 86#define VMK8061_CMR_RD_ALL_AI 0x01 /* !non-active! */
985cafcc 87#define VMK8061_CMD_SET_AO 0x02
0a85b6f0 88#define VMK8061_CMD_SET_ALL_AO 0x03 /* !non-active! */
985cafcc
MG
89#define VMK8061_CMD_OUT_PWM 0x04
90#define VMK8061_CMD_RD_DI 0x05
0a85b6f0 91#define VMK8061_CMD_DO 0x06 /* !non-active! */
985cafcc
MG
92#define VMK8061_CMD_CLR_DO 0x07
93#define VMK8061_CMD_SET_DO 0x08
0a85b6f0
MT
94#define VMK8061_CMD_RD_CNT 0x09 /* TODO: completely pointless? */
95#define VMK8061_CMD_RST_CNT 0x0a /* TODO: completely pointless? */
96#define VMK8061_CMD_RD_VERSION 0x0b /* internal usage */
97#define VMK8061_CMD_RD_JMP_STAT 0x0c /* TODO: not implemented yet */
98#define VMK8061_CMD_RD_PWR_STAT 0x0d /* internal usage */
985cafcc
MG
99#define VMK8061_CMD_RD_DO 0x0e
100#define VMK8061_CMD_RD_AO 0x0f
101#define VMK8061_CMD_RD_PWM 0x10
102
985cafcc
MG
103#define IC3_VERSION (1 << 0)
104#define IC6_VERSION (1 << 1)
105
985cafcc
MG
106enum vmk80xx_model {
107 VMK8055_MODEL,
108 VMK8061_MODEL
109};
3faad673 110
985cafcc 111struct firmware_version {
0a85b6f0
MT
112 unsigned char ic3_vers[32]; /* USB-Controller */
113 unsigned char ic6_vers[32]; /* CPU */
3faad673
MG
114};
115
985cafcc 116static const struct comedi_lrange vmk8061_range = {
f45787c6
HS
117 2, {
118 UNI_RANGE(5),
119 UNI_RANGE(10)
120 }
985cafcc 121};
3faad673 122
985cafcc
MG
123struct vmk80xx_board {
124 const char *name;
125 enum vmk80xx_model model;
126 const struct comedi_lrange *range;
658cd3ac
HS
127 int ai_nchans;
128 unsigned int ai_maxdata;
8b3ec9f1 129 int ao_nchans;
268e5148 130 int di_nchans;
75a45d92 131 unsigned int cnt_maxdata;
9a23a748
HS
132 int pwm_nchans;
133 unsigned int pwm_maxdata;
985cafcc 134};
3faad673 135
20d60077
HS
136static const struct vmk80xx_board vmk80xx_boardinfo[] = {
137 [DEVICE_VMK8055] = {
138 .name = "K8055 (VM110)",
139 .model = VMK8055_MODEL,
f45787c6 140 .range = &range_unipolar5,
658cd3ac
HS
141 .ai_nchans = 2,
142 .ai_maxdata = 0x00ff,
8b3ec9f1 143 .ao_nchans = 2,
268e5148 144 .di_nchans = 6,
75a45d92 145 .cnt_maxdata = 0xffff,
20d60077
HS
146 },
147 [DEVICE_VMK8061] = {
148 .name = "K8061 (VM140)",
149 .model = VMK8061_MODEL,
150 .range = &vmk8061_range,
658cd3ac
HS
151 .ai_nchans = 8,
152 .ai_maxdata = 0x03ff,
8b3ec9f1 153 .ao_nchans = 8,
268e5148 154 .di_nchans = 8,
75a45d92 155 .cnt_maxdata = 0, /* unknown, device is not writeable */
9a23a748
HS
156 .pwm_nchans = 1,
157 .pwm_maxdata = 0x03ff,
20d60077
HS
158 },
159};
160
dc49cbfc 161struct vmk80xx_private {
da7b18ee 162 struct usb_device *usb;
985cafcc
MG
163 struct usb_interface *intf;
164 struct usb_endpoint_descriptor *ep_rx;
165 struct usb_endpoint_descriptor *ep_tx;
985cafcc
MG
166 struct firmware_version fw;
167 struct semaphore limit_sem;
985cafcc
MG
168 unsigned char *usb_rx_buf;
169 unsigned char *usb_tx_buf;
52d895d3 170 enum vmk80xx_model model;
985cafcc
MG
171};
172
da7b18ee 173static int vmk80xx_check_data_link(struct vmk80xx_private *devpriv)
3faad673 174{
da7b18ee 175 struct usb_device *usb = devpriv->usb;
3a229fd5
AH
176 unsigned int tx_pipe;
177 unsigned int rx_pipe;
178 unsigned char tx[1];
179 unsigned char rx[2];
985cafcc 180
da7b18ee
HS
181 tx_pipe = usb_sndbulkpipe(usb, 0x01);
182 rx_pipe = usb_rcvbulkpipe(usb, 0x81);
3faad673 183
985cafcc 184 tx[0] = VMK8061_CMD_RD_PWR_STAT;
3faad673 185
3a229fd5
AH
186 /*
187 * Check that IC6 (PIC16F871) is powered and
985cafcc 188 * running and the data link between IC3 and
3a229fd5
AH
189 * IC6 is working properly
190 */
da7b18ee
HS
191 usb_bulk_msg(usb, tx_pipe, tx, 1, NULL, devpriv->ep_tx->bInterval);
192 usb_bulk_msg(usb, rx_pipe, rx, 2, NULL, HZ * 10);
3faad673 193
985cafcc 194 return (int)rx[1];
3faad673
MG
195}
196
da7b18ee 197static void vmk80xx_read_eeprom(struct vmk80xx_private *devpriv, int flag)
3faad673 198{
da7b18ee 199 struct usb_device *usb = devpriv->usb;
3a229fd5
AH
200 unsigned int tx_pipe;
201 unsigned int rx_pipe;
202 unsigned char tx[1];
203 unsigned char rx[64];
985cafcc 204 int cnt;
3faad673 205
da7b18ee
HS
206 tx_pipe = usb_sndbulkpipe(usb, 0x01);
207 rx_pipe = usb_rcvbulkpipe(usb, 0x81);
3faad673 208
985cafcc
MG
209 tx[0] = VMK8061_CMD_RD_VERSION;
210
3a229fd5
AH
211 /*
212 * Read the firmware version info of IC3 and
213 * IC6 from the internal EEPROM of the IC
214 */
da7b18ee
HS
215 usb_bulk_msg(usb, tx_pipe, tx, 1, NULL, devpriv->ep_tx->bInterval);
216 usb_bulk_msg(usb, rx_pipe, rx, 64, &cnt, HZ * 10);
985cafcc
MG
217
218 rx[cnt] = '\0';
219
220 if (flag & IC3_VERSION)
da7b18ee 221 strncpy(devpriv->fw.ic3_vers, rx + 1, 24);
0a85b6f0 222 else /* IC6_VERSION */
da7b18ee 223 strncpy(devpriv->fw.ic6_vers, rx + 25, 24);
985cafcc
MG
224}
225
da7b18ee 226static void vmk80xx_do_bulk_msg(struct vmk80xx_private *devpriv)
985cafcc 227{
da7b18ee 228 struct usb_device *usb = devpriv->usb;
3a229fd5
AH
229 __u8 tx_addr;
230 __u8 rx_addr;
231 unsigned int tx_pipe;
232 unsigned int rx_pipe;
985cafcc 233 size_t size;
3faad673 234
da7b18ee
HS
235 tx_addr = devpriv->ep_tx->bEndpointAddress;
236 rx_addr = devpriv->ep_rx->bEndpointAddress;
237 tx_pipe = usb_sndbulkpipe(usb, tx_addr);
238 rx_pipe = usb_rcvbulkpipe(usb, rx_addr);
985cafcc 239
3a229fd5
AH
240 /*
241 * The max packet size attributes of the K8061
242 * input/output endpoints are identical
243 */
da7b18ee 244 size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize);
985cafcc 245
da7b18ee
HS
246 usb_bulk_msg(usb, tx_pipe, devpriv->usb_tx_buf,
247 size, NULL, devpriv->ep_tx->bInterval);
248 usb_bulk_msg(usb, rx_pipe, devpriv->usb_rx_buf, size, NULL, HZ * 10);
3faad673
MG
249}
250
da7b18ee 251static int vmk80xx_read_packet(struct vmk80xx_private *devpriv)
3faad673 252{
951348b3
IA
253 struct usb_device *usb;
254 struct usb_endpoint_descriptor *ep;
255 unsigned int pipe;
3faad673 256
da7b18ee 257 if (!devpriv->intf)
985cafcc 258 return -ENODEV;
3faad673 259
52d895d3 260 if (devpriv->model == VMK8061_MODEL) {
da7b18ee 261 vmk80xx_do_bulk_msg(devpriv);
985cafcc 262 return 0;
3faad673
MG
263 }
264
951348b3
IA
265 usb = devpriv->usb;
266 ep = devpriv->ep_rx;
267 pipe = usb_rcvintpipe(usb, ep->bEndpointAddress);
268 return usb_interrupt_msg(usb, pipe, devpriv->usb_rx_buf,
269 le16_to_cpu(ep->wMaxPacketSize), NULL,
270 HZ * 10);
3faad673
MG
271}
272
da7b18ee 273static int vmk80xx_write_packet(struct vmk80xx_private *devpriv, int cmd)
3faad673 274{
951348b3
IA
275 struct usb_device *usb;
276 struct usb_endpoint_descriptor *ep;
277 unsigned int pipe;
3faad673 278
da7b18ee 279 if (!devpriv->intf)
985cafcc 280 return -ENODEV;
3faad673 281
951348b3 282 devpriv->usb_tx_buf[0] = cmd;
3faad673 283
52d895d3 284 if (devpriv->model == VMK8061_MODEL) {
da7b18ee 285 vmk80xx_do_bulk_msg(devpriv);
985cafcc 286 return 0;
3faad673
MG
287 }
288
951348b3
IA
289 usb = devpriv->usb;
290 ep = devpriv->ep_tx;
291 pipe = usb_sndintpipe(usb, ep->bEndpointAddress);
292 return usb_interrupt_msg(usb, pipe, devpriv->usb_tx_buf,
293 le16_to_cpu(ep->wMaxPacketSize), NULL,
294 HZ * 10);
3faad673
MG
295}
296
e8f311a5
IA
297static int vmk80xx_reset_device(struct vmk80xx_private *devpriv)
298{
299 size_t size;
f06a23c9 300 int retval;
e8f311a5
IA
301
302 size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize);
303 memset(devpriv->usb_tx_buf, 0, size);
f06a23c9
IA
304 retval = vmk80xx_write_packet(devpriv, VMK8055_CMD_RST);
305 if (retval)
306 return retval;
307 /* set outputs to known state as we cannot read them */
308 return vmk80xx_write_packet(devpriv, VMK8055_CMD_WRT_AD);
e8f311a5
IA
309}
310
658cd3ac
HS
311static int vmk80xx_ai_insn_read(struct comedi_device *dev,
312 struct comedi_subdevice *s,
313 struct comedi_insn *insn,
314 unsigned int *data)
3faad673 315{
da7b18ee 316 struct vmk80xx_private *devpriv = dev->private;
3a229fd5
AH
317 int chan;
318 int reg[2];
985cafcc 319 int n;
3faad673 320
da7b18ee 321 down(&devpriv->limit_sem);
985cafcc 322 chan = CR_CHAN(insn->chanspec);
3faad673 323
52d895d3 324 switch (devpriv->model) {
985cafcc
MG
325 case VMK8055_MODEL:
326 if (!chan)
327 reg[0] = VMK8055_AI1_REG;
328 else
329 reg[0] = VMK8055_AI2_REG;
330 break;
331 case VMK8061_MODEL:
13f7952f 332 default:
985cafcc
MG
333 reg[0] = VMK8061_AI_REG1;
334 reg[1] = VMK8061_AI_REG2;
da7b18ee
HS
335 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_AI;
336 devpriv->usb_tx_buf[VMK8061_CH_REG] = chan;
985cafcc 337 break;
3faad673
MG
338 }
339
985cafcc 340 for (n = 0; n < insn->n; n++) {
da7b18ee 341 if (vmk80xx_read_packet(devpriv))
985cafcc 342 break;
3faad673 343
52d895d3 344 if (devpriv->model == VMK8055_MODEL) {
da7b18ee 345 data[n] = devpriv->usb_rx_buf[reg[0]];
985cafcc
MG
346 continue;
347 }
3faad673 348
985cafcc 349 /* VMK8061_MODEL */
da7b18ee
HS
350 data[n] = devpriv->usb_rx_buf[reg[0]] + 256 *
351 devpriv->usb_rx_buf[reg[1]];
985cafcc 352 }
3faad673 353
da7b18ee 354 up(&devpriv->limit_sem);
3faad673 355
985cafcc 356 return n;
3faad673
MG
357}
358
8b3ec9f1
HS
359static int vmk80xx_ao_insn_write(struct comedi_device *dev,
360 struct comedi_subdevice *s,
361 struct comedi_insn *insn,
362 unsigned int *data)
3faad673 363{
da7b18ee 364 struct vmk80xx_private *devpriv = dev->private;
3a229fd5
AH
365 int chan;
366 int cmd;
367 int reg;
985cafcc 368 int n;
3faad673 369
da7b18ee 370 down(&devpriv->limit_sem);
985cafcc 371 chan = CR_CHAN(insn->chanspec);
3faad673 372
52d895d3 373 switch (devpriv->model) {
985cafcc
MG
374 case VMK8055_MODEL:
375 cmd = VMK8055_CMD_WRT_AD;
376 if (!chan)
377 reg = VMK8055_AO1_REG;
378 else
379 reg = VMK8055_AO2_REG;
380 break;
0a85b6f0 381 default: /* NOTE: avoid compiler warnings */
985cafcc
MG
382 cmd = VMK8061_CMD_SET_AO;
383 reg = VMK8061_AO_REG;
da7b18ee 384 devpriv->usb_tx_buf[VMK8061_CH_REG] = chan;
985cafcc 385 break;
3faad673
MG
386 }
387
985cafcc 388 for (n = 0; n < insn->n; n++) {
da7b18ee 389 devpriv->usb_tx_buf[reg] = data[n];
3faad673 390
da7b18ee 391 if (vmk80xx_write_packet(devpriv, cmd))
985cafcc 392 break;
3faad673
MG
393 }
394
da7b18ee 395 up(&devpriv->limit_sem);
3faad673 396
985cafcc 397 return n;
3faad673
MG
398}
399
8b3ec9f1
HS
400static int vmk80xx_ao_insn_read(struct comedi_device *dev,
401 struct comedi_subdevice *s,
402 struct comedi_insn *insn,
403 unsigned int *data)
3faad673 404{
da7b18ee 405 struct vmk80xx_private *devpriv = dev->private;
3a229fd5
AH
406 int chan;
407 int reg;
985cafcc 408 int n;
3faad673 409
da7b18ee 410 down(&devpriv->limit_sem);
985cafcc 411 chan = CR_CHAN(insn->chanspec);
3faad673 412
985cafcc 413 reg = VMK8061_AO_REG - 1;
3faad673 414
da7b18ee 415 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_AO;
985cafcc
MG
416
417 for (n = 0; n < insn->n; n++) {
da7b18ee 418 if (vmk80xx_read_packet(devpriv))
985cafcc
MG
419 break;
420
da7b18ee 421 data[n] = devpriv->usb_rx_buf[reg + chan];
3faad673
MG
422 }
423
da7b18ee 424 up(&devpriv->limit_sem);
3faad673 425
985cafcc
MG
426 return n;
427}
3faad673 428
268e5148
HS
429static int vmk80xx_di_insn_bits(struct comedi_device *dev,
430 struct comedi_subdevice *s,
431 struct comedi_insn *insn,
432 unsigned int *data)
c647ed56 433{
da7b18ee 434 struct vmk80xx_private *devpriv = dev->private;
c647ed56
AH
435 unsigned char *rx_buf;
436 int reg;
437 int retval;
438
da7b18ee 439 down(&devpriv->limit_sem);
c647ed56 440
da7b18ee 441 rx_buf = devpriv->usb_rx_buf;
c647ed56 442
52d895d3 443 if (devpriv->model == VMK8061_MODEL) {
c647ed56 444 reg = VMK8061_DI_REG;
da7b18ee 445 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
c647ed56
AH
446 } else {
447 reg = VMK8055_DI_REG;
448 }
449
da7b18ee 450 retval = vmk80xx_read_packet(devpriv);
c647ed56
AH
451
452 if (!retval) {
52d895d3 453 if (devpriv->model == VMK8055_MODEL)
c647ed56
AH
454 data[1] = (((rx_buf[reg] >> 4) & 0x03) |
455 ((rx_buf[reg] << 2) & 0x04) |
456 ((rx_buf[reg] >> 3) & 0x18));
457 else
458 data[1] = rx_buf[reg];
459
460 retval = 2;
461 }
462
da7b18ee 463 up(&devpriv->limit_sem);
c647ed56
AH
464
465 return retval;
466}
467
b639e096
HS
468static int vmk80xx_do_insn_bits(struct comedi_device *dev,
469 struct comedi_subdevice *s,
470 struct comedi_insn *insn,
471 unsigned int *data)
c647ed56 472{
da7b18ee 473 struct vmk80xx_private *devpriv = dev->private;
c647ed56 474 unsigned char *rx_buf, *tx_buf;
951348b3 475 int reg, cmd;
c647ed56
AH
476 int retval;
477
fc9ca48e 478 if (devpriv->model == VMK8061_MODEL) {
fc9ca48e
PH
479 reg = VMK8061_DO_REG;
480 cmd = VMK8061_CMD_DO;
481 } else { /* VMK8055_MODEL */
482 reg = VMK8055_DO_REG;
483 cmd = VMK8055_CMD_WRT_AD;
484 }
c647ed56 485
da7b18ee 486 down(&devpriv->limit_sem);
c647ed56 487
da7b18ee
HS
488 rx_buf = devpriv->usb_rx_buf;
489 tx_buf = devpriv->usb_tx_buf;
c647ed56
AH
490
491 if (data[0]) {
c647ed56
AH
492 tx_buf[reg] &= ~data[0];
493 tx_buf[reg] |= (data[0] & data[1]);
494
da7b18ee 495 retval = vmk80xx_write_packet(devpriv, cmd);
c647ed56
AH
496
497 if (retval)
498 goto out;
499 }
500
52d895d3 501 if (devpriv->model == VMK8061_MODEL) {
c647ed56
AH
502 tx_buf[0] = VMK8061_CMD_RD_DO;
503
da7b18ee 504 retval = vmk80xx_read_packet(devpriv);
c647ed56
AH
505
506 if (!retval) {
507 data[1] = rx_buf[reg];
508 retval = 2;
509 }
510 } else {
511 data[1] = tx_buf[reg];
512 retval = 2;
513 }
514
515out:
da7b18ee 516 up(&devpriv->limit_sem);
c647ed56
AH
517
518 return retval;
519}
520
75a45d92
HS
521static int vmk80xx_cnt_insn_read(struct comedi_device *dev,
522 struct comedi_subdevice *s,
523 struct comedi_insn *insn,
524 unsigned int *data)
985cafcc 525{
da7b18ee 526 struct vmk80xx_private *devpriv = dev->private;
3a229fd5
AH
527 int chan;
528 int reg[2];
985cafcc
MG
529 int n;
530
da7b18ee 531 down(&devpriv->limit_sem);
985cafcc 532 chan = CR_CHAN(insn->chanspec);
3faad673 533
52d895d3 534 switch (devpriv->model) {
985cafcc
MG
535 case VMK8055_MODEL:
536 if (!chan)
537 reg[0] = VMK8055_CNT1_REG;
538 else
539 reg[0] = VMK8055_CNT2_REG;
540 break;
541 case VMK8061_MODEL:
13f7952f 542 default:
985cafcc
MG
543 reg[0] = VMK8061_CNT_REG;
544 reg[1] = VMK8061_CNT_REG;
da7b18ee 545 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_CNT;
985cafcc 546 break;
3faad673
MG
547 }
548
985cafcc 549 for (n = 0; n < insn->n; n++) {
da7b18ee 550 if (vmk80xx_read_packet(devpriv))
985cafcc 551 break;
3faad673 552
52d895d3 553 if (devpriv->model == VMK8055_MODEL)
da7b18ee 554 data[n] = devpriv->usb_rx_buf[reg[0]];
3a229fd5 555 else /* VMK8061_MODEL */
da7b18ee
HS
556 data[n] = devpriv->usb_rx_buf[reg[0] * (chan + 1) + 1]
557 + 256 * devpriv->usb_rx_buf[reg[1] * 2 + 2];
985cafcc
MG
558 }
559
da7b18ee 560 up(&devpriv->limit_sem);
985cafcc
MG
561
562 return n;
3faad673
MG
563}
564
75a45d92
HS
565static int vmk80xx_cnt_insn_config(struct comedi_device *dev,
566 struct comedi_subdevice *s,
567 struct comedi_insn *insn,
568 unsigned int *data)
3faad673 569{
da7b18ee 570 struct vmk80xx_private *devpriv = dev->private;
985cafcc 571 unsigned int insn_cmd;
3a229fd5
AH
572 int chan;
573 int cmd;
574 int reg;
985cafcc 575 int n;
3faad673 576
985cafcc
MG
577 insn_cmd = data[0];
578 if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET)
579 return -EINVAL;
3faad673 580
da7b18ee 581 down(&devpriv->limit_sem);
8f9064a8 582
985cafcc 583 chan = CR_CHAN(insn->chanspec);
3faad673 584
52d895d3 585 if (devpriv->model == VMK8055_MODEL) {
985cafcc
MG
586 if (!chan) {
587 cmd = VMK8055_CMD_RST_CNT1;
588 reg = VMK8055_CNT1_REG;
589 } else {
590 cmd = VMK8055_CMD_RST_CNT2;
591 reg = VMK8055_CNT2_REG;
592 }
593
da7b18ee 594 devpriv->usb_tx_buf[reg] = 0x00;
3a229fd5 595 } else {
985cafcc 596 cmd = VMK8061_CMD_RST_CNT;
3a229fd5 597 }
985cafcc
MG
598
599 for (n = 0; n < insn->n; n++)
da7b18ee 600 if (vmk80xx_write_packet(devpriv, cmd))
985cafcc
MG
601 break;
602
da7b18ee 603 up(&devpriv->limit_sem);
985cafcc
MG
604
605 return n;
606}
607
75a45d92
HS
608static int vmk80xx_cnt_insn_write(struct comedi_device *dev,
609 struct comedi_subdevice *s,
610 struct comedi_insn *insn,
611 unsigned int *data)
985cafcc 612{
da7b18ee 613 struct vmk80xx_private *devpriv = dev->private;
3a229fd5
AH
614 unsigned long debtime;
615 unsigned long val;
616 int chan;
617 int cmd;
985cafcc
MG
618 int n;
619
da7b18ee 620 down(&devpriv->limit_sem);
985cafcc
MG
621 chan = CR_CHAN(insn->chanspec);
622
623 if (!chan)
624 cmd = VMK8055_CMD_DEB1_TIME;
625 else
626 cmd = VMK8055_CMD_DEB2_TIME;
627
628 for (n = 0; n < insn->n; n++) {
629 debtime = data[n];
3faad673
MG
630 if (debtime == 0)
631 debtime = 1;
985cafcc
MG
632
633 /* TODO: Prevent overflows */
634 if (debtime > 7450)
635 debtime = 7450;
636
3faad673
MG
637 val = int_sqrt(debtime * 1000 / 115);
638 if (((val + 1) * val) < debtime * 1000 / 115)
639 val += 1;
640
da7b18ee 641 devpriv->usb_tx_buf[6 + chan] = val;
3faad673 642
da7b18ee 643 if (vmk80xx_write_packet(devpriv, cmd))
985cafcc 644 break;
3faad673
MG
645 }
646
da7b18ee 647 up(&devpriv->limit_sem);
3faad673 648
985cafcc
MG
649 return n;
650}
3faad673 651
9a23a748
HS
652static int vmk80xx_pwm_insn_read(struct comedi_device *dev,
653 struct comedi_subdevice *s,
654 struct comedi_insn *insn,
655 unsigned int *data)
985cafcc 656{
da7b18ee
HS
657 struct vmk80xx_private *devpriv = dev->private;
658 unsigned char *tx_buf;
659 unsigned char *rx_buf;
985cafcc
MG
660 int reg[2];
661 int n;
662
da7b18ee
HS
663 down(&devpriv->limit_sem);
664
665 tx_buf = devpriv->usb_tx_buf;
666 rx_buf = devpriv->usb_rx_buf;
985cafcc
MG
667
668 reg[0] = VMK8061_PWM_REG1;
669 reg[1] = VMK8061_PWM_REG2;
670
da7b18ee 671 tx_buf[0] = VMK8061_CMD_RD_PWM;
985cafcc
MG
672
673 for (n = 0; n < insn->n; n++) {
da7b18ee 674 if (vmk80xx_read_packet(devpriv))
985cafcc
MG
675 break;
676
da7b18ee 677 data[n] = rx_buf[reg[0]] + 4 * rx_buf[reg[1]];
985cafcc
MG
678 }
679
da7b18ee 680 up(&devpriv->limit_sem);
985cafcc
MG
681
682 return n;
3faad673
MG
683}
684
9a23a748
HS
685static int vmk80xx_pwm_insn_write(struct comedi_device *dev,
686 struct comedi_subdevice *s,
687 struct comedi_insn *insn,
688 unsigned int *data)
985cafcc 689{
da7b18ee 690 struct vmk80xx_private *devpriv = dev->private;
985cafcc 691 unsigned char *tx_buf;
3a229fd5
AH
692 int reg[2];
693 int cmd;
985cafcc 694 int n;
3faad673 695
da7b18ee 696 down(&devpriv->limit_sem);
985cafcc 697
da7b18ee 698 tx_buf = devpriv->usb_tx_buf;
985cafcc
MG
699
700 reg[0] = VMK8061_PWM_REG1;
701 reg[1] = VMK8061_PWM_REG2;
702
703 cmd = VMK8061_CMD_OUT_PWM;
704
705 /*
706 * The followin piece of code was translated from the inline
707 * assembler code in the DLL source code.
708 *
709 * asm
710 * mov eax, k ; k is the value (data[n])
711 * and al, 03h ; al are the lower 8 bits of eax
712 * mov lo, al ; lo is the low part (tx_buf[reg[0]])
713 * mov eax, k
714 * shr eax, 2 ; right shift eax register by 2
715 * mov hi, al ; hi is the high part (tx_buf[reg[1]])
716 * end;
717 */
718 for (n = 0; n < insn->n; n++) {
719 tx_buf[reg[0]] = (unsigned char)(data[n] & 0x03);
720 tx_buf[reg[1]] = (unsigned char)(data[n] >> 2) & 0xff;
721
da7b18ee 722 if (vmk80xx_write_packet(devpriv, cmd))
985cafcc
MG
723 break;
724 }
3faad673 725
da7b18ee 726 up(&devpriv->limit_sem);
985cafcc
MG
727
728 return n;
729}
730
57cf09ae 731static int vmk80xx_find_usb_endpoints(struct comedi_device *dev)
49253d54 732{
57cf09ae
HS
733 struct vmk80xx_private *devpriv = dev->private;
734 struct usb_interface *intf = devpriv->intf;
49253d54
HS
735 struct usb_host_interface *iface_desc = intf->cur_altsetting;
736 struct usb_endpoint_descriptor *ep_desc;
737 int i;
738
739 if (iface_desc->desc.bNumEndpoints != 2)
740 return -ENODEV;
741
742 for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
743 ep_desc = &iface_desc->endpoint[i].desc;
744
745 if (usb_endpoint_is_int_in(ep_desc) ||
746 usb_endpoint_is_bulk_in(ep_desc)) {
747 if (!devpriv->ep_rx)
748 devpriv->ep_rx = ep_desc;
749 continue;
750 }
751
752 if (usb_endpoint_is_int_out(ep_desc) ||
753 usb_endpoint_is_bulk_out(ep_desc)) {
754 if (!devpriv->ep_tx)
755 devpriv->ep_tx = ep_desc;
756 continue;
757 }
758 }
759
760 if (!devpriv->ep_rx || !devpriv->ep_tx)
761 return -ENODEV;
762
763 return 0;
764}
765
57cf09ae 766static int vmk80xx_alloc_usb_buffers(struct comedi_device *dev)
78f8fa7f 767{
57cf09ae 768 struct vmk80xx_private *devpriv = dev->private;
78f8fa7f
HS
769 size_t size;
770
771 size = le16_to_cpu(devpriv->ep_rx->wMaxPacketSize);
0cbfc826 772 devpriv->usb_rx_buf = kzalloc(size, GFP_KERNEL);
78f8fa7f
HS
773 if (!devpriv->usb_rx_buf)
774 return -ENOMEM;
775
776 size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize);
0cbfc826 777 devpriv->usb_tx_buf = kzalloc(size, GFP_KERNEL);
78f8fa7f
HS
778 if (!devpriv->usb_tx_buf) {
779 kfree(devpriv->usb_rx_buf);
780 return -ENOMEM;
781 }
782
783 return 0;
784}
785
66dbc7b1 786static int vmk80xx_init_subdevices(struct comedi_device *dev)
3faad673 787{
57cf09ae
HS
788 const struct vmk80xx_board *boardinfo = comedi_board(dev);
789 struct vmk80xx_private *devpriv = dev->private;
b153d83e 790 struct comedi_subdevice *s;
57cf09ae 791 int n_subd;
8b6c5694 792 int ret;
3faad673 793
da7b18ee 794 down(&devpriv->limit_sem);
0dd772bf 795
52d895d3 796 if (devpriv->model == VMK8055_MODEL)
985cafcc
MG
797 n_subd = 5;
798 else
799 n_subd = 6;
da7b18ee 800 ret = comedi_alloc_subdevices(dev, n_subd);
8b6c5694 801 if (ret) {
da7b18ee 802 up(&devpriv->limit_sem);
8b6c5694 803 return ret;
3faad673 804 }
0dd772bf 805
985cafcc 806 /* Analog input subdevice */
da7b18ee 807 s = &dev->subdevices[0];
658cd3ac
HS
808 s->type = COMEDI_SUBD_AI;
809 s->subdev_flags = SDF_READABLE | SDF_GROUND;
810 s->n_chan = boardinfo->ai_nchans;
811 s->maxdata = boardinfo->ai_maxdata;
812 s->range_table = boardinfo->range;
813 s->insn_read = vmk80xx_ai_insn_read;
0dd772bf 814
985cafcc 815 /* Analog output subdevice */
da7b18ee 816 s = &dev->subdevices[1];
8b3ec9f1
HS
817 s->type = COMEDI_SUBD_AO;
818 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
819 s->n_chan = boardinfo->ao_nchans;
820 s->maxdata = 0x00ff;
821 s->range_table = boardinfo->range;
822 s->insn_write = vmk80xx_ao_insn_write;
52d895d3 823 if (devpriv->model == VMK8061_MODEL) {
8b3ec9f1
HS
824 s->subdev_flags |= SDF_READABLE;
825 s->insn_read = vmk80xx_ao_insn_read;
985cafcc 826 }
0dd772bf 827
985cafcc 828 /* Digital input subdevice */
da7b18ee 829 s = &dev->subdevices[2];
268e5148
HS
830 s->type = COMEDI_SUBD_DI;
831 s->subdev_flags = SDF_READABLE;
832 s->n_chan = boardinfo->di_nchans;
833 s->maxdata = 1;
834 s->range_table = &range_digital;
268e5148 835 s->insn_bits = vmk80xx_di_insn_bits;
0dd772bf 836
985cafcc 837 /* Digital output subdevice */
da7b18ee 838 s = &dev->subdevices[3];
b639e096
HS
839 s->type = COMEDI_SUBD_DO;
840 s->subdev_flags = SDF_WRITEABLE;
841 s->n_chan = 8;
842 s->maxdata = 1;
843 s->range_table = &range_digital;
b639e096 844 s->insn_bits = vmk80xx_do_insn_bits;
0dd772bf 845
985cafcc 846 /* Counter subdevice */
da7b18ee 847 s = &dev->subdevices[4];
75a45d92
HS
848 s->type = COMEDI_SUBD_COUNTER;
849 s->subdev_flags = SDF_READABLE;
850 s->n_chan = 2;
851 s->maxdata = boardinfo->cnt_maxdata;
852 s->insn_read = vmk80xx_cnt_insn_read;
853 s->insn_config = vmk80xx_cnt_insn_config;
52d895d3 854 if (devpriv->model == VMK8055_MODEL) {
75a45d92
HS
855 s->subdev_flags |= SDF_WRITEABLE;
856 s->insn_write = vmk80xx_cnt_insn_write;
985cafcc 857 }
0dd772bf 858
985cafcc 859 /* PWM subdevice */
52d895d3 860 if (devpriv->model == VMK8061_MODEL) {
da7b18ee 861 s = &dev->subdevices[5];
9a23a748
HS
862 s->type = COMEDI_SUBD_PWM;
863 s->subdev_flags = SDF_READABLE | SDF_WRITEABLE;
864 s->n_chan = boardinfo->pwm_nchans;
865 s->maxdata = boardinfo->pwm_maxdata;
866 s->insn_read = vmk80xx_pwm_insn_read;
867 s->insn_write = vmk80xx_pwm_insn_write;
985cafcc 868 }
0dd772bf 869
da7b18ee 870 up(&devpriv->limit_sem);
0dd772bf 871
f7d4d3bc
IA
872 return 0;
873}
3faad673 874
da7b18ee 875static int vmk80xx_auto_attach(struct comedi_device *dev,
57cf09ae 876 unsigned long context)
f7d4d3bc 877{
da7b18ee 878 struct usb_interface *intf = comedi_to_usb_interface(dev);
0dd772bf 879 const struct vmk80xx_board *boardinfo;
da7b18ee 880 struct vmk80xx_private *devpriv;
49253d54 881 int ret;
3faad673 882
57cf09ae
HS
883 boardinfo = &vmk80xx_boardinfo[context];
884 dev->board_ptr = boardinfo;
885 dev->board_name = boardinfo->name;
3faad673 886
57cf09ae
HS
887 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
888 if (!devpriv)
889 return -ENOMEM;
890 dev->private = devpriv;
3faad673 891
57cf09ae
HS
892 devpriv->usb = interface_to_usbdev(intf);
893 devpriv->intf = intf;
52d895d3 894 devpriv->model = boardinfo->model;
985cafcc 895
57cf09ae 896 ret = vmk80xx_find_usb_endpoints(dev);
db7dabf7 897 if (ret)
57cf09ae 898 return ret;
3faad673 899
57cf09ae 900 ret = vmk80xx_alloc_usb_buffers(dev);
db7dabf7 901 if (ret)
57cf09ae 902 return ret;
985cafcc 903
da7b18ee 904 sema_init(&devpriv->limit_sem, 8);
985cafcc 905
da7b18ee 906 usb_set_intfdata(intf, devpriv);
985cafcc 907
52d895d3 908 if (devpriv->model == VMK8061_MODEL) {
da7b18ee
HS
909 vmk80xx_read_eeprom(devpriv, IC3_VERSION);
910 dev_info(&intf->dev, "%s\n", devpriv->fw.ic3_vers);
985cafcc 911
da7b18ee
HS
912 if (vmk80xx_check_data_link(devpriv)) {
913 vmk80xx_read_eeprom(devpriv, IC6_VERSION);
914 dev_info(&intf->dev, "%s\n", devpriv->fw.ic6_vers);
3a229fd5 915 }
3faad673
MG
916 }
917
52d895d3 918 if (devpriv->model == VMK8055_MODEL)
da7b18ee 919 vmk80xx_reset_device(devpriv);
3faad673 920
66dbc7b1 921 return vmk80xx_init_subdevices(dev);
57cf09ae 922}
3faad673 923
57cf09ae
HS
924static void vmk80xx_detach(struct comedi_device *dev)
925{
926 struct vmk80xx_private *devpriv = dev->private;
8ba69ce4 927
57cf09ae
HS
928 if (!devpriv)
929 return;
db7dabf7 930
57cf09ae
HS
931 down(&devpriv->limit_sem);
932
933 usb_set_intfdata(devpriv->intf, NULL);
934
57cf09ae
HS
935 kfree(devpriv->usb_rx_buf);
936 kfree(devpriv->usb_tx_buf);
937
938 up(&devpriv->limit_sem);
939}
940
941static struct comedi_driver vmk80xx_driver = {
942 .module = THIS_MODULE,
943 .driver_name = "vmk80xx",
944 .auto_attach = vmk80xx_auto_attach,
945 .detach = vmk80xx_detach,
946};
947
948static int vmk80xx_usb_probe(struct usb_interface *intf,
949 const struct usb_device_id *id)
950{
951 return comedi_usb_auto_config(intf, &vmk80xx_driver, id->driver_info);
3faad673
MG
952}
953
007ff2af
HS
954static const struct usb_device_id vmk80xx_usb_id_table[] = {
955 { USB_DEVICE(0x10cf, 0x5500), .driver_info = DEVICE_VMK8055 },
956 { USB_DEVICE(0x10cf, 0x5501), .driver_info = DEVICE_VMK8055 },
957 { USB_DEVICE(0x10cf, 0x5502), .driver_info = DEVICE_VMK8055 },
958 { USB_DEVICE(0x10cf, 0x5503), .driver_info = DEVICE_VMK8055 },
959 { USB_DEVICE(0x10cf, 0x8061), .driver_info = DEVICE_VMK8061 },
960 { USB_DEVICE(0x10cf, 0x8062), .driver_info = DEVICE_VMK8061 },
961 { USB_DEVICE(0x10cf, 0x8063), .driver_info = DEVICE_VMK8061 },
962 { USB_DEVICE(0x10cf, 0x8064), .driver_info = DEVICE_VMK8061 },
963 { USB_DEVICE(0x10cf, 0x8065), .driver_info = DEVICE_VMK8061 },
964 { USB_DEVICE(0x10cf, 0x8066), .driver_info = DEVICE_VMK8061 },
965 { USB_DEVICE(0x10cf, 0x8067), .driver_info = DEVICE_VMK8061 },
966 { USB_DEVICE(0x10cf, 0x8068), .driver_info = DEVICE_VMK8061 },
967 { }
968};
969MODULE_DEVICE_TABLE(usb, vmk80xx_usb_id_table);
970
d6cc3ec8
HS
971static struct usb_driver vmk80xx_usb_driver = {
972 .name = "vmk80xx",
007ff2af 973 .id_table = vmk80xx_usb_id_table,
ce874227
HS
974 .probe = vmk80xx_usb_probe,
975 .disconnect = comedi_usb_auto_unconfig,
3faad673 976};
d6cc3ec8 977module_comedi_usb_driver(vmk80xx_driver, vmk80xx_usb_driver);
007ff2af
HS
978
979MODULE_AUTHOR("Manuel Gebele <forensixs@gmx.de>");
980MODULE_DESCRIPTION("Velleman USB Board Low-Level Driver");
981MODULE_SUPPORTED_DEVICE("K8055/K8061 aka VM110/VM140");
982MODULE_VERSION("0.8.01");
983MODULE_LICENSE("GPL");
This page took 0.532646 seconds and 5 git commands to generate.