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