1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87#include <linux/kernel.h>
88#include <linux/module.h>
89#include <linux/slab.h>
90
91#include "../comedi_usb.h"
92
93#define NI6501_TIMEOUT 1000
94
95
96static const u8 READ_PORT_REQUEST[] = {0x00, 0x01, 0x00, 0x10,
97 0x00, 0x0C, 0x01, 0x0E,
98 0x02, 0x10, 0x00, 0x00,
99 0x00, 0x03, 0x00, 0x00};
100
101static const u8 WRITE_PORT_REQUEST[] = {0x00, 0x01, 0x00, 0x14,
102 0x00, 0x10, 0x01, 0x0F,
103 0x02, 0x10, 0x00, 0x00,
104 0x00, 0x03, 0x00, 0x00,
105 0x03, 0x00, 0x00, 0x00};
106
107static const u8 SET_PORT_DIR_REQUEST[] = {0x00, 0x01, 0x00, 0x18,
108 0x00, 0x14, 0x01, 0x12,
109 0x02, 0x10, 0x00, 0x00,
110 0x00, 0x05, 0x00, 0x00,
111 0x00, 0x00, 0x05, 0x00,
112 0x00, 0x00, 0x00, 0x00};
113
114
115static const u8 START_COUNTER_REQUEST[] = {0x00, 0x01, 0x00, 0x0C,
116 0x00, 0x08, 0x01, 0x09,
117 0x02, 0x20, 0x00, 0x00};
118
119static const u8 STOP_COUNTER_REQUEST[] = {0x00, 0x01, 0x00, 0x0C,
120 0x00, 0x08, 0x01, 0x0C,
121 0x02, 0x20, 0x00, 0x00};
122
123static const u8 READ_COUNTER_REQUEST[] = {0x00, 0x01, 0x00, 0x0C,
124 0x00, 0x08, 0x01, 0x0E,
125 0x02, 0x20, 0x00, 0x00};
126
127static const u8 WRITE_COUNTER_REQUEST[] = {0x00, 0x01, 0x00, 0x10,
128 0x00, 0x0C, 0x01, 0x0F,
129 0x02, 0x20, 0x00, 0x00,
130 0x00, 0x00, 0x00, 0x00};
131
132
133static const u8 GENERIC_RESPONSE[] = {0x00, 0x01, 0x00, 0x0C,
134 0x00, 0x08, 0x01, 0x00,
135 0x00, 0x00, 0x00, 0x02};
136
137static const u8 READ_PORT_RESPONSE[] = {0x00, 0x01, 0x00, 0x10,
138 0x00, 0x0C, 0x01, 0x00,
139 0x00, 0x00, 0x00, 0x02,
140 0x00, 0x03, 0x00, 0x00};
141
142static const u8 READ_COUNTER_RESPONSE[] = {0x00, 0x01, 0x00, 0x10,
143 0x00, 0x0C, 0x01, 0x00,
144 0x00, 0x00, 0x00, 0x02,
145 0x00, 0x00, 0x00, 0x00};
146
147enum commands {
148 READ_PORT,
149 WRITE_PORT,
150 SET_PORT_DIR,
151 START_COUNTER,
152 STOP_COUNTER,
153 READ_COUNTER,
154 WRITE_COUNTER
155};
156
157struct ni6501_private {
158 struct usb_endpoint_descriptor *ep_rx;
159 struct usb_endpoint_descriptor *ep_tx;
160 struct mutex mut;
161 u8 *usb_rx_buf;
162 u8 *usb_tx_buf;
163};
164
165static int ni6501_port_command(struct comedi_device *dev, int command,
166 unsigned int val, u8 *bitmap)
167{
168 struct usb_device *usb = comedi_to_usb_dev(dev);
169 struct ni6501_private *devpriv = dev->private;
170 int request_size, response_size;
171 u8 *tx = devpriv->usb_tx_buf;
172 int ret;
173
174 if (command != SET_PORT_DIR && !bitmap)
175 return -EINVAL;
176
177 mutex_lock(&devpriv->mut);
178
179 switch (command) {
180 case READ_PORT:
181 request_size = sizeof(READ_PORT_REQUEST);
182 response_size = sizeof(READ_PORT_RESPONSE);
183 memcpy(tx, READ_PORT_REQUEST, request_size);
184 tx[14] = val & 0xff;
185 break;
186 case WRITE_PORT:
187 request_size = sizeof(WRITE_PORT_REQUEST);
188 response_size = sizeof(GENERIC_RESPONSE);
189 memcpy(tx, WRITE_PORT_REQUEST, request_size);
190 tx[14] = val & 0xff;
191 tx[17] = *bitmap;
192 break;
193 case SET_PORT_DIR:
194 request_size = sizeof(SET_PORT_DIR_REQUEST);
195 response_size = sizeof(GENERIC_RESPONSE);
196 memcpy(tx, SET_PORT_DIR_REQUEST, request_size);
197 tx[14] = val & 0xff;
198 tx[15] = (val >> 8) & 0xff;
199 tx[16] = (val >> 16) & 0xff;
200 break;
201 default:
202 ret = -EINVAL;
203 goto end;
204 }
205
206 ret = usb_bulk_msg(usb,
207 usb_sndbulkpipe(usb,
208 devpriv->ep_tx->bEndpointAddress),
209 devpriv->usb_tx_buf,
210 request_size,
211 NULL,
212 NI6501_TIMEOUT);
213 if (ret)
214 goto end;
215
216 ret = usb_bulk_msg(usb,
217 usb_rcvbulkpipe(usb,
218 devpriv->ep_rx->bEndpointAddress),
219 devpriv->usb_rx_buf,
220 response_size,
221 NULL,
222 NI6501_TIMEOUT);
223 if (ret)
224 goto end;
225
226
227
228 if (command == READ_PORT) {
229 *bitmap = devpriv->usb_rx_buf[14];
230
231 devpriv->usb_rx_buf[14] = 0x00;
232
233 if (memcmp(devpriv->usb_rx_buf, READ_PORT_RESPONSE,
234 sizeof(READ_PORT_RESPONSE))) {
235 ret = -EINVAL;
236 }
237 } else if (memcmp(devpriv->usb_rx_buf, GENERIC_RESPONSE,
238 sizeof(GENERIC_RESPONSE))) {
239 ret = -EINVAL;
240 }
241end:
242 mutex_unlock(&devpriv->mut);
243
244 return ret;
245}
246
247static int ni6501_counter_command(struct comedi_device *dev, int command,
248 u32 *val)
249{
250 struct usb_device *usb = comedi_to_usb_dev(dev);
251 struct ni6501_private *devpriv = dev->private;
252 int request_size, response_size;
253 u8 *tx = devpriv->usb_tx_buf;
254 int ret;
255
256 if ((command == READ_COUNTER || command == WRITE_COUNTER) && !val)
257 return -EINVAL;
258
259 mutex_lock(&devpriv->mut);
260
261 switch (command) {
262 case START_COUNTER:
263 request_size = sizeof(START_COUNTER_REQUEST);
264 response_size = sizeof(GENERIC_RESPONSE);
265 memcpy(tx, START_COUNTER_REQUEST, request_size);
266 break;
267 case STOP_COUNTER:
268 request_size = sizeof(STOP_COUNTER_REQUEST);
269 response_size = sizeof(GENERIC_RESPONSE);
270 memcpy(tx, STOP_COUNTER_REQUEST, request_size);
271 break;
272 case READ_COUNTER:
273 request_size = sizeof(READ_COUNTER_REQUEST);
274 response_size = sizeof(READ_COUNTER_RESPONSE);
275 memcpy(tx, READ_COUNTER_REQUEST, request_size);
276 break;
277 case WRITE_COUNTER:
278 request_size = sizeof(WRITE_COUNTER_REQUEST);
279 response_size = sizeof(GENERIC_RESPONSE);
280 memcpy(tx, WRITE_COUNTER_REQUEST, request_size);
281
282
283 *((__be32 *)&tx[12]) = cpu_to_be32(*val);
284 break;
285 default:
286 ret = -EINVAL;
287 goto end;
288 }
289
290 ret = usb_bulk_msg(usb,
291 usb_sndbulkpipe(usb,
292 devpriv->ep_tx->bEndpointAddress),
293 devpriv->usb_tx_buf,
294 request_size,
295 NULL,
296 NI6501_TIMEOUT);
297 if (ret)
298 goto end;
299
300 ret = usb_bulk_msg(usb,
301 usb_rcvbulkpipe(usb,
302 devpriv->ep_rx->bEndpointAddress),
303 devpriv->usb_rx_buf,
304 response_size,
305 NULL,
306 NI6501_TIMEOUT);
307 if (ret)
308 goto end;
309
310
311
312 if (command == READ_COUNTER) {
313 int i;
314
315
316
317 *val = be32_to_cpu(*((__be32 *)&devpriv->usb_rx_buf[12]));
318
319
320 for (i = 12; i < sizeof(READ_COUNTER_RESPONSE); ++i)
321 devpriv->usb_rx_buf[i] = 0x00;
322
323 if (memcmp(devpriv->usb_rx_buf, READ_COUNTER_RESPONSE,
324 sizeof(READ_COUNTER_RESPONSE))) {
325 ret = -EINVAL;
326 }
327 } else if (memcmp(devpriv->usb_rx_buf, GENERIC_RESPONSE,
328 sizeof(GENERIC_RESPONSE))) {
329 ret = -EINVAL;
330 }
331end:
332 mutex_unlock(&devpriv->mut);
333
334 return ret;
335}
336
337static int ni6501_dio_insn_config(struct comedi_device *dev,
338 struct comedi_subdevice *s,
339 struct comedi_insn *insn,
340 unsigned int *data)
341{
342 int ret;
343
344 ret = comedi_dio_insn_config(dev, s, insn, data, 0);
345 if (ret)
346 return ret;
347
348 ret = ni6501_port_command(dev, SET_PORT_DIR, s->io_bits, NULL);
349 if (ret)
350 return ret;
351
352 return insn->n;
353}
354
355static int ni6501_dio_insn_bits(struct comedi_device *dev,
356 struct comedi_subdevice *s,
357 struct comedi_insn *insn,
358 unsigned int *data)
359{
360 unsigned int mask;
361 int ret;
362 u8 port;
363 u8 bitmap;
364
365 mask = comedi_dio_update_state(s, data);
366
367 for (port = 0; port < 3; port++) {
368 if (mask & (0xFF << port * 8)) {
369 bitmap = (s->state >> port * 8) & 0xFF;
370 ret = ni6501_port_command(dev, WRITE_PORT,
371 port, &bitmap);
372 if (ret)
373 return ret;
374 }
375 }
376
377 data[1] = 0;
378
379 for (port = 0; port < 3; port++) {
380 ret = ni6501_port_command(dev, READ_PORT, port, &bitmap);
381 if (ret)
382 return ret;
383 data[1] |= bitmap << port * 8;
384 }
385
386 return insn->n;
387}
388
389static int ni6501_cnt_insn_config(struct comedi_device *dev,
390 struct comedi_subdevice *s,
391 struct comedi_insn *insn,
392 unsigned int *data)
393{
394 int ret;
395 u32 val = 0;
396
397 switch (data[0]) {
398 case INSN_CONFIG_ARM:
399 ret = ni6501_counter_command(dev, START_COUNTER, NULL);
400 break;
401 case INSN_CONFIG_DISARM:
402 ret = ni6501_counter_command(dev, STOP_COUNTER, NULL);
403 break;
404 case INSN_CONFIG_RESET:
405 ret = ni6501_counter_command(dev, STOP_COUNTER, NULL);
406 if (ret)
407 break;
408 ret = ni6501_counter_command(dev, WRITE_COUNTER, &val);
409 break;
410 default:
411 return -EINVAL;
412 }
413
414 return ret ? ret : insn->n;
415}
416
417static int ni6501_cnt_insn_read(struct comedi_device *dev,
418 struct comedi_subdevice *s,
419 struct comedi_insn *insn,
420 unsigned int *data)
421{
422 int ret;
423 u32 val;
424 unsigned int i;
425
426 for (i = 0; i < insn->n; i++) {
427 ret = ni6501_counter_command(dev, READ_COUNTER, &val);
428 if (ret)
429 return ret;
430 data[i] = val;
431 }
432
433 return insn->n;
434}
435
436static int ni6501_cnt_insn_write(struct comedi_device *dev,
437 struct comedi_subdevice *s,
438 struct comedi_insn *insn,
439 unsigned int *data)
440{
441 int ret;
442
443 if (insn->n) {
444 u32 val = data[insn->n - 1];
445
446 ret = ni6501_counter_command(dev, WRITE_COUNTER, &val);
447 if (ret)
448 return ret;
449 }
450
451 return insn->n;
452}
453
454static int ni6501_alloc_usb_buffers(struct comedi_device *dev)
455{
456 struct ni6501_private *devpriv = dev->private;
457 size_t size;
458
459 size = usb_endpoint_maxp(devpriv->ep_rx);
460 devpriv->usb_rx_buf = kzalloc(size, GFP_KERNEL);
461 if (!devpriv->usb_rx_buf)
462 return -ENOMEM;
463
464 size = usb_endpoint_maxp(devpriv->ep_tx);
465 devpriv->usb_tx_buf = kzalloc(size, GFP_KERNEL);
466 if (!devpriv->usb_tx_buf) {
467 kfree(devpriv->usb_rx_buf);
468 return -ENOMEM;
469 }
470
471 return 0;
472}
473
474static int ni6501_find_endpoints(struct comedi_device *dev)
475{
476 struct usb_interface *intf = comedi_to_usb_interface(dev);
477 struct ni6501_private *devpriv = dev->private;
478 struct usb_host_interface *iface_desc = intf->cur_altsetting;
479 struct usb_endpoint_descriptor *ep_desc;
480 int i;
481
482 if (iface_desc->desc.bNumEndpoints != 2) {
483 dev_err(dev->class_dev, "Wrong number of endpoints\n");
484 return -ENODEV;
485 }
486
487 for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
488 ep_desc = &iface_desc->endpoint[i].desc;
489
490 if (usb_endpoint_is_bulk_in(ep_desc)) {
491 if (!devpriv->ep_rx)
492 devpriv->ep_rx = ep_desc;
493 continue;
494 }
495
496 if (usb_endpoint_is_bulk_out(ep_desc)) {
497 if (!devpriv->ep_tx)
498 devpriv->ep_tx = ep_desc;
499 continue;
500 }
501 }
502
503 if (!devpriv->ep_rx || !devpriv->ep_tx)
504 return -ENODEV;
505
506 return 0;
507}
508
509static int ni6501_auto_attach(struct comedi_device *dev,
510 unsigned long context)
511{
512 struct usb_interface *intf = comedi_to_usb_interface(dev);
513 struct ni6501_private *devpriv;
514 struct comedi_subdevice *s;
515 int ret;
516
517 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
518 if (!devpriv)
519 return -ENOMEM;
520
521 ret = ni6501_find_endpoints(dev);
522 if (ret)
523 return ret;
524
525 ret = ni6501_alloc_usb_buffers(dev);
526 if (ret)
527 return ret;
528
529 mutex_init(&devpriv->mut);
530 usb_set_intfdata(intf, devpriv);
531
532 ret = comedi_alloc_subdevices(dev, 2);
533 if (ret)
534 return ret;
535
536
537 s = &dev->subdevices[0];
538 s->type = COMEDI_SUBD_DIO;
539 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
540 s->n_chan = 24;
541 s->maxdata = 1;
542 s->range_table = &range_digital;
543 s->insn_bits = ni6501_dio_insn_bits;
544 s->insn_config = ni6501_dio_insn_config;
545
546
547 s = &dev->subdevices[1];
548 s->type = COMEDI_SUBD_COUNTER;
549 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL;
550 s->n_chan = 1;
551 s->maxdata = 0xffffffff;
552 s->insn_read = ni6501_cnt_insn_read;
553 s->insn_write = ni6501_cnt_insn_write;
554 s->insn_config = ni6501_cnt_insn_config;
555
556 return 0;
557}
558
559static void ni6501_detach(struct comedi_device *dev)
560{
561 struct usb_interface *intf = comedi_to_usb_interface(dev);
562 struct ni6501_private *devpriv = dev->private;
563
564 if (!devpriv)
565 return;
566
567 mutex_lock(&devpriv->mut);
568
569 usb_set_intfdata(intf, NULL);
570
571 kfree(devpriv->usb_rx_buf);
572 kfree(devpriv->usb_tx_buf);
573
574 mutex_unlock(&devpriv->mut);
575}
576
577static struct comedi_driver ni6501_driver = {
578 .module = THIS_MODULE,
579 .driver_name = "ni6501",
580 .auto_attach = ni6501_auto_attach,
581 .detach = ni6501_detach,
582};
583
584static int ni6501_usb_probe(struct usb_interface *intf,
585 const struct usb_device_id *id)
586{
587 return comedi_usb_auto_config(intf, &ni6501_driver, id->driver_info);
588}
589
590static const struct usb_device_id ni6501_usb_table[] = {
591 { USB_DEVICE(0x3923, 0x718a) },
592 { }
593};
594MODULE_DEVICE_TABLE(usb, ni6501_usb_table);
595
596static struct usb_driver ni6501_usb_driver = {
597 .name = "ni6501",
598 .id_table = ni6501_usb_table,
599 .probe = ni6501_usb_probe,
600 .disconnect = comedi_usb_auto_unconfig,
601};
602module_comedi_usb_driver(ni6501_driver, ni6501_usb_driver);
603
604MODULE_AUTHOR("Luca Ellero");
605MODULE_DESCRIPTION("Comedi driver for National Instruments USB-6501");
606MODULE_LICENSE("GPL");
607