root/drivers/staging/comedi/drivers/vmk80xx.c

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

DEFINITIONS

This source file includes following definitions.
  1. vmk80xx_do_bulk_msg
  2. vmk80xx_read_packet
  3. vmk80xx_write_packet
  4. vmk80xx_reset_device
  5. vmk80xx_ai_insn_read
  6. vmk80xx_ao_insn_write
  7. vmk80xx_ao_insn_read
  8. vmk80xx_di_insn_bits
  9. vmk80xx_do_insn_bits
  10. vmk80xx_cnt_insn_read
  11. vmk80xx_cnt_insn_config
  12. vmk80xx_cnt_insn_write
  13. vmk80xx_pwm_insn_read
  14. vmk80xx_pwm_insn_write
  15. vmk80xx_find_usb_endpoints
  16. vmk80xx_alloc_usb_buffers
  17. vmk80xx_init_subdevices
  18. vmk80xx_auto_attach
  19. vmk80xx_detach
  20. vmk80xx_usb_probe

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

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