root/drivers/staging/comedi/drivers/ni_usb6501.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ni6501_port_command
  2. ni6501_counter_command
  3. ni6501_dio_insn_config
  4. ni6501_dio_insn_bits
  5. ni6501_cnt_insn_config
  6. ni6501_cnt_insn_read
  7. ni6501_cnt_insn_write
  8. ni6501_alloc_usb_buffers
  9. ni6501_find_endpoints
  10. ni6501_auto_attach
  11. ni6501_detach
  12. ni6501_usb_probe

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * comedi/drivers/ni_usb6501.c
   4  * Comedi driver for National Instruments USB-6501
   5  *
   6  * COMEDI - Linux Control and Measurement Device Interface
   7  * Copyright (C) 2014 Luca Ellero <luca.ellero@brickedbrain.com>
   8  */
   9 
  10 /*
  11  * Driver: ni_usb6501
  12  * Description: National Instruments USB-6501 module
  13  * Devices: [National Instruments] USB-6501 (ni_usb6501)
  14  * Author: Luca Ellero <luca.ellero@brickedbrain.com>
  15  * Updated: 8 Sep 2014
  16  * Status: works
  17  *
  18  *
  19  * Configuration Options:
  20  * none
  21  */
  22 
  23 /*
  24  * NI-6501 - USB PROTOCOL DESCRIPTION
  25  *
  26  * Every command is composed by two USB packets:
  27  *      - request (out)
  28  *      - response (in)
  29  *
  30  * Every packet is at least 12 bytes long, here is the meaning of
  31  * every field (all values are hex):
  32  *
  33  *      byte 0 is always 00
  34  *      byte 1 is always 01
  35  *      byte 2 is always 00
  36  *      byte 3 is the total packet length
  37  *
  38  *      byte 4 is always 00
  39  *      byte 5 is the total packet length - 4
  40  *      byte 6 is always 01
  41  *      byte 7 is the command
  42  *
  43  *      byte 8 is 02 (request) or 00 (response)
  44  *      byte 9 is 00 (response) or 10 (port request) or 20 (counter request)
  45  *      byte 10 is always 00
  46  *      byte 11 is 00 (request) or 02 (response)
  47  *
  48  * PORT PACKETS
  49  *
  50  *      CMD: 0xE READ_PORT
  51  *      REQ: 00 01 00 10 00 0C 01 0E 02 10 00 00 00 03 <PORT> 00
  52  *      RES: 00 01 00 10 00 0C 01 00 00 00 00 02 00 03 <BMAP> 00
  53  *
  54  *      CMD: 0xF WRITE_PORT
  55  *      REQ: 00 01 00 14 00 10 01 0F 02 10 00 00 00 03 <PORT> 00 03 <BMAP> 00 00
  56  *      RES: 00 01 00 0C 00 08 01 00 00 00 00 02
  57  *
  58  *      CMD: 0x12 SET_PORT_DIR (0 = input, 1 = output)
  59  *      REQ: 00 01 00 18 00 14 01 12 02 10 00 00
  60  *           00 05 <PORT 0> <PORT 1> <PORT 2> 00 05 00 00 00 00 00
  61  *      RES: 00 01 00 0C 00 08 01 00 00 00 00 02
  62  *
  63  * COUNTER PACKETS
  64  *
  65  *      CMD 0x9: START_COUNTER
  66  *      REQ: 00 01 00 0C 00 08 01 09 02 20 00 00
  67  *      RES: 00 01 00 0C 00 08 01 00 00 00 00 02
  68  *
  69  *      CMD 0xC: STOP_COUNTER
  70  *      REQ: 00 01 00 0C 00 08 01 0C 02 20 00 00
  71  *      RES: 00 01 00 0C 00 08 01 00 00 00 00 02
  72  *
  73  *      CMD 0xE: READ_COUNTER
  74  *      REQ: 00 01 00 0C 00 08 01 0E 02 20 00 00
  75  *      RES: 00 01 00 10 00 0C 01 00 00 00 00 02 <u32 counter value, Big Endian>
  76  *
  77  *      CMD 0xF: WRITE_COUNTER
  78  *      REQ: 00 01 00 10 00 0C 01 0F 02 20 00 00 <u32 counter value, Big Endian>
  79  *      RES: 00 01 00 0C 00 08 01 00 00 00 00 02
  80  *
  81  *
  82  *      Please  visit http://www.brickedbrain.com if you need
  83  *      additional information or have any questions.
  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 /* Port request packets */
  96 static 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 
 101 static 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 
 107 static 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 /* Counter request packets */
 115 static const u8 START_COUNTER_REQUEST[] = {0x00, 0x01, 0x00, 0x0C,
 116                                            0x00, 0x08, 0x01, 0x09,
 117                                            0x02, 0x20, 0x00, 0x00};
 118 
 119 static const u8 STOP_COUNTER_REQUEST[]  = {0x00, 0x01, 0x00, 0x0C,
 120                                            0x00, 0x08, 0x01, 0x0C,
 121                                            0x02, 0x20, 0x00, 0x00};
 122 
 123 static const u8 READ_COUNTER_REQUEST[]  = {0x00, 0x01, 0x00, 0x0C,
 124                                            0x00, 0x08, 0x01, 0x0E,
 125                                            0x02, 0x20, 0x00, 0x00};
 126 
 127 static 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 /* Response packets */
 133 static const u8 GENERIC_RESPONSE[]      = {0x00, 0x01, 0x00, 0x0C,
 134                                            0x00, 0x08, 0x01, 0x00,
 135                                            0x00, 0x00, 0x00, 0x02};
 136 
 137 static 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 
 142 static 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 
 147 enum 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 
 157 struct 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 
 165 static 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         /* Check if results are valid */
 227 
 228         if (command == READ_PORT) {
 229                 *bitmap = devpriv->usb_rx_buf[14];
 230                 /* mask bitmap for comparing */
 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         }
 241 end:
 242         mutex_unlock(&devpriv->mut);
 243 
 244         return ret;
 245 }
 246 
 247 static 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                 /* Setup tx packet: bytes 12,13,14,15 hold the */
 282                 /* u32 counter value (Big Endian)              */
 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         /* Check if results are valid */
 311 
 312         if (command == READ_COUNTER) {
 313                 int i;
 314 
 315                 /* Read counter value: bytes 12,13,14,15 of rx packet */
 316                 /* hold the u32 counter value (Big Endian)            */
 317                 *val = be32_to_cpu(*((__be32 *)&devpriv->usb_rx_buf[12]));
 318 
 319                 /* mask counter value for comparing */
 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         }
 331 end:
 332         mutex_unlock(&devpriv->mut);
 333 
 334         return ret;
 335 }
 336 
 337 static 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 
 355 static 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 
 389 static 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 
 417 static 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 
 436 static 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 
 454 static 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                 return -ENOMEM;
 468 
 469         return 0;
 470 }
 471 
 472 static int ni6501_find_endpoints(struct comedi_device *dev)
 473 {
 474         struct usb_interface *intf = comedi_to_usb_interface(dev);
 475         struct ni6501_private *devpriv = dev->private;
 476         struct usb_host_interface *iface_desc = intf->cur_altsetting;
 477         struct usb_endpoint_descriptor *ep_desc;
 478         int i;
 479 
 480         if (iface_desc->desc.bNumEndpoints != 2) {
 481                 dev_err(dev->class_dev, "Wrong number of endpoints\n");
 482                 return -ENODEV;
 483         }
 484 
 485         for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
 486                 ep_desc = &iface_desc->endpoint[i].desc;
 487 
 488                 if (usb_endpoint_is_bulk_in(ep_desc)) {
 489                         if (!devpriv->ep_rx)
 490                                 devpriv->ep_rx = ep_desc;
 491                         continue;
 492                 }
 493 
 494                 if (usb_endpoint_is_bulk_out(ep_desc)) {
 495                         if (!devpriv->ep_tx)
 496                                 devpriv->ep_tx = ep_desc;
 497                         continue;
 498                 }
 499         }
 500 
 501         if (!devpriv->ep_rx || !devpriv->ep_tx)
 502                 return -ENODEV;
 503 
 504         return 0;
 505 }
 506 
 507 static int ni6501_auto_attach(struct comedi_device *dev,
 508                               unsigned long context)
 509 {
 510         struct usb_interface *intf = comedi_to_usb_interface(dev);
 511         struct ni6501_private *devpriv;
 512         struct comedi_subdevice *s;
 513         int ret;
 514 
 515         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 516         if (!devpriv)
 517                 return -ENOMEM;
 518 
 519         mutex_init(&devpriv->mut);
 520         usb_set_intfdata(intf, devpriv);
 521 
 522         ret = ni6501_find_endpoints(dev);
 523         if (ret)
 524                 return ret;
 525 
 526         ret = ni6501_alloc_usb_buffers(dev);
 527         if (ret)
 528                 return ret;
 529 
 530         ret = comedi_alloc_subdevices(dev, 2);
 531         if (ret)
 532                 return ret;
 533 
 534         /* Digital Input/Output subdevice */
 535         s = &dev->subdevices[0];
 536         s->type         = COMEDI_SUBD_DIO;
 537         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 538         s->n_chan       = 24;
 539         s->maxdata      = 1;
 540         s->range_table  = &range_digital;
 541         s->insn_bits    = ni6501_dio_insn_bits;
 542         s->insn_config  = ni6501_dio_insn_config;
 543 
 544         /* Counter subdevice */
 545         s = &dev->subdevices[1];
 546         s->type         = COMEDI_SUBD_COUNTER;
 547         s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL;
 548         s->n_chan       = 1;
 549         s->maxdata      = 0xffffffff;
 550         s->insn_read    = ni6501_cnt_insn_read;
 551         s->insn_write   = ni6501_cnt_insn_write;
 552         s->insn_config  = ni6501_cnt_insn_config;
 553 
 554         return 0;
 555 }
 556 
 557 static void ni6501_detach(struct comedi_device *dev)
 558 {
 559         struct usb_interface *intf = comedi_to_usb_interface(dev);
 560         struct ni6501_private *devpriv = dev->private;
 561 
 562         if (!devpriv)
 563                 return;
 564 
 565         mutex_destroy(&devpriv->mut);
 566 
 567         usb_set_intfdata(intf, NULL);
 568 
 569         kfree(devpriv->usb_rx_buf);
 570         kfree(devpriv->usb_tx_buf);
 571 }
 572 
 573 static struct comedi_driver ni6501_driver = {
 574         .module         = THIS_MODULE,
 575         .driver_name    = "ni6501",
 576         .auto_attach    = ni6501_auto_attach,
 577         .detach         = ni6501_detach,
 578 };
 579 
 580 static int ni6501_usb_probe(struct usb_interface *intf,
 581                             const struct usb_device_id *id)
 582 {
 583         return comedi_usb_auto_config(intf, &ni6501_driver, id->driver_info);
 584 }
 585 
 586 static const struct usb_device_id ni6501_usb_table[] = {
 587         { USB_DEVICE(0x3923, 0x718a) },
 588         { }
 589 };
 590 MODULE_DEVICE_TABLE(usb, ni6501_usb_table);
 591 
 592 static struct usb_driver ni6501_usb_driver = {
 593         .name           = "ni6501",
 594         .id_table       = ni6501_usb_table,
 595         .probe          = ni6501_usb_probe,
 596         .disconnect     = comedi_usb_auto_unconfig,
 597 };
 598 module_comedi_usb_driver(ni6501_driver, ni6501_usb_driver);
 599 
 600 MODULE_AUTHOR("Luca Ellero");
 601 MODULE_DESCRIPTION("Comedi driver for National Instruments USB-6501");
 602 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */