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