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