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 = devpriv->usb_rx_buf;
 466        unsigned char *tx_buf = devpriv->usb_tx_buf;
 467        int reg, cmd;
 468        int ret = 0;
 469
 470        if (devpriv->model == VMK8061_MODEL) {
 471                reg = VMK8061_DO_REG;
 472                cmd = VMK8061_CMD_DO;
 473        } else { /* VMK8055_MODEL */
 474                reg = VMK8055_DO_REG;
 475                cmd = VMK8055_CMD_WRT_AD;
 476        }
 477
 478        down(&devpriv->limit_sem);
 479
 480        if (comedi_dio_update_state(s, data)) {
 481                tx_buf[reg] = s->state;
 482                ret = vmk80xx_write_packet(dev, cmd);
 483                if (ret)
 484                        goto out;
 485        }
 486
 487        if (devpriv->model == VMK8061_MODEL) {
 488                tx_buf[0] = VMK8061_CMD_RD_DO;
 489                ret = vmk80xx_read_packet(dev);
 490                if (ret)
 491                        goto out;
 492                data[1] = rx_buf[reg];
 493        } else {
 494                data[1] = s->state;
 495        }
 496
 497out:
 498        up(&devpriv->limit_sem);
 499
 500        return ret ? ret : insn->n;
 501}
 502
 503static int vmk80xx_cnt_insn_read(struct comedi_device *dev,
 504                                 struct comedi_subdevice *s,
 505                                 struct comedi_insn *insn,
 506                                 unsigned int *data)
 507{
 508        struct vmk80xx_private *devpriv = dev->private;
 509        int chan;
 510        int reg[2];
 511        int n;
 512
 513        down(&devpriv->limit_sem);
 514        chan = CR_CHAN(insn->chanspec);
 515
 516        switch (devpriv->model) {
 517        case VMK8055_MODEL:
 518                if (!chan)
 519                        reg[0] = VMK8055_CNT1_REG;
 520                else
 521                        reg[0] = VMK8055_CNT2_REG;
 522                break;
 523        case VMK8061_MODEL:
 524        default:
 525                reg[0] = VMK8061_CNT_REG;
 526                reg[1] = VMK8061_CNT_REG;
 527                devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_CNT;
 528                break;
 529        }
 530
 531        for (n = 0; n < insn->n; n++) {
 532                if (vmk80xx_read_packet(dev))
 533                        break;
 534
 535                if (devpriv->model == VMK8055_MODEL)
 536                        data[n] = devpriv->usb_rx_buf[reg[0]];
 537                else /* VMK8061_MODEL */
 538                        data[n] = devpriv->usb_rx_buf[reg[0] * (chan + 1) + 1]
 539                            + 256 * devpriv->usb_rx_buf[reg[1] * 2 + 2];
 540        }
 541
 542        up(&devpriv->limit_sem);
 543
 544        return n;
 545}
 546
 547static int vmk80xx_cnt_insn_config(struct comedi_device *dev,
 548                                   struct comedi_subdevice *s,
 549                                   struct comedi_insn *insn,
 550                                   unsigned int *data)
 551{
 552        struct vmk80xx_private *devpriv = dev->private;
 553        unsigned int insn_cmd;
 554        int chan;
 555        int cmd;
 556        int reg;
 557        int n;
 558
 559        insn_cmd = data[0];
 560        if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET)
 561                return -EINVAL;
 562
 563        down(&devpriv->limit_sem);
 564
 565        chan = CR_CHAN(insn->chanspec);
 566
 567        if (devpriv->model == VMK8055_MODEL) {
 568                if (!chan) {
 569                        cmd = VMK8055_CMD_RST_CNT1;
 570                        reg = VMK8055_CNT1_REG;
 571                } else {
 572                        cmd = VMK8055_CMD_RST_CNT2;
 573                        reg = VMK8055_CNT2_REG;
 574                }
 575
 576                devpriv->usb_tx_buf[reg] = 0x00;
 577        } else {
 578                cmd = VMK8061_CMD_RST_CNT;
 579        }
 580
 581        for (n = 0; n < insn->n; n++)
 582                if (vmk80xx_write_packet(dev, cmd))
 583                        break;
 584
 585        up(&devpriv->limit_sem);
 586
 587        return n;
 588}
 589
 590static int vmk80xx_cnt_insn_write(struct comedi_device *dev,
 591                                  struct comedi_subdevice *s,
 592                                  struct comedi_insn *insn,
 593                                  unsigned int *data)
 594{
 595        struct vmk80xx_private *devpriv = dev->private;
 596        unsigned long debtime;
 597        unsigned long val;
 598        int chan;
 599        int cmd;
 600        int n;
 601
 602        down(&devpriv->limit_sem);
 603        chan = CR_CHAN(insn->chanspec);
 604
 605        if (!chan)
 606                cmd = VMK8055_CMD_DEB1_TIME;
 607        else
 608                cmd = VMK8055_CMD_DEB2_TIME;
 609
 610        for (n = 0; n < insn->n; n++) {
 611                debtime = data[n];
 612                if (debtime == 0)
 613                        debtime = 1;
 614
 615                /* TODO: Prevent overflows */
 616                if (debtime > 7450)
 617                        debtime = 7450;
 618
 619                val = int_sqrt(debtime * 1000 / 115);
 620                if (((val + 1) * val) < debtime * 1000 / 115)
 621                        val += 1;
 622
 623                devpriv->usb_tx_buf[6 + chan] = val;
 624
 625                if (vmk80xx_write_packet(dev, cmd))
 626                        break;
 627        }
 628
 629        up(&devpriv->limit_sem);
 630
 631        return n;
 632}
 633
 634static int vmk80xx_pwm_insn_read(struct comedi_device *dev,
 635                                 struct comedi_subdevice *s,
 636                                 struct comedi_insn *insn,
 637                                 unsigned int *data)
 638{
 639        struct vmk80xx_private *devpriv = dev->private;
 640        unsigned char *tx_buf;
 641        unsigned char *rx_buf;
 642        int reg[2];
 643        int n;
 644
 645        down(&devpriv->limit_sem);
 646
 647        tx_buf = devpriv->usb_tx_buf;
 648        rx_buf = devpriv->usb_rx_buf;
 649
 650        reg[0] = VMK8061_PWM_REG1;
 651        reg[1] = VMK8061_PWM_REG2;
 652
 653        tx_buf[0] = VMK8061_CMD_RD_PWM;
 654
 655        for (n = 0; n < insn->n; n++) {
 656                if (vmk80xx_read_packet(dev))
 657                        break;
 658
 659                data[n] = rx_buf[reg[0]] + 4 * rx_buf[reg[1]];
 660        }
 661
 662        up(&devpriv->limit_sem);
 663
 664        return n;
 665}
 666
 667static int vmk80xx_pwm_insn_write(struct comedi_device *dev,
 668                                  struct comedi_subdevice *s,
 669                                  struct comedi_insn *insn,
 670                                  unsigned int *data)
 671{
 672        struct vmk80xx_private *devpriv = dev->private;
 673        unsigned char *tx_buf;
 674        int reg[2];
 675        int cmd;
 676        int n;
 677
 678        down(&devpriv->limit_sem);
 679
 680        tx_buf = devpriv->usb_tx_buf;
 681
 682        reg[0] = VMK8061_PWM_REG1;
 683        reg[1] = VMK8061_PWM_REG2;
 684
 685        cmd = VMK8061_CMD_OUT_PWM;
 686
 687        /*
 688         * The followin piece of code was translated from the inline
 689         * assembler code in the DLL source code.
 690         *
 691         * asm
 692         *   mov eax, k  ; k is the value (data[n])
 693         *   and al, 03h ; al are the lower 8 bits of eax
 694         *   mov lo, al  ; lo is the low part (tx_buf[reg[0]])
 695         *   mov eax, k
 696         *   shr eax, 2  ; right shift eax register by 2
 697         *   mov hi, al  ; hi is the high part (tx_buf[reg[1]])
 698         * end;
 699         */
 700        for (n = 0; n < insn->n; n++) {
 701                tx_buf[reg[0]] = (unsigned char)(data[n] & 0x03);
 702                tx_buf[reg[1]] = (unsigned char)(data[n] >> 2) & 0xff;
 703
 704                if (vmk80xx_write_packet(dev, cmd))
 705                        break;
 706        }
 707
 708        up(&devpriv->limit_sem);
 709
 710        return n;
 711}
 712
 713static int vmk80xx_find_usb_endpoints(struct comedi_device *dev)
 714{
 715        struct vmk80xx_private *devpriv = dev->private;
 716        struct usb_interface *intf = comedi_to_usb_interface(dev);
 717        struct usb_host_interface *iface_desc = intf->cur_altsetting;
 718        struct usb_endpoint_descriptor *ep_desc;
 719        int i;
 720
 721        if (iface_desc->desc.bNumEndpoints != 2)
 722                return -ENODEV;
 723
 724        for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
 725                ep_desc = &iface_desc->endpoint[i].desc;
 726
 727                if (usb_endpoint_is_int_in(ep_desc) ||
 728                    usb_endpoint_is_bulk_in(ep_desc)) {
 729                        if (!devpriv->ep_rx)
 730                                devpriv->ep_rx = ep_desc;
 731                        continue;
 732                }
 733
 734                if (usb_endpoint_is_int_out(ep_desc) ||
 735                    usb_endpoint_is_bulk_out(ep_desc)) {
 736                        if (!devpriv->ep_tx)
 737                                devpriv->ep_tx = ep_desc;
 738                        continue;
 739                }
 740        }
 741
 742        if (!devpriv->ep_rx || !devpriv->ep_tx)
 743                return -ENODEV;
 744
 745        return 0;
 746}
 747
 748static int vmk80xx_alloc_usb_buffers(struct comedi_device *dev)
 749{
 750        struct vmk80xx_private *devpriv = dev->private;
 751        size_t size;
 752
 753        size = le16_to_cpu(devpriv->ep_rx->wMaxPacketSize);
 754        devpriv->usb_rx_buf = kzalloc(size, GFP_KERNEL);
 755        if (!devpriv->usb_rx_buf)
 756                return -ENOMEM;
 757
 758        size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize);
 759        devpriv->usb_tx_buf = kzalloc(size, GFP_KERNEL);
 760        if (!devpriv->usb_tx_buf) {
 761                kfree(devpriv->usb_rx_buf);
 762                return -ENOMEM;
 763        }
 764
 765        return 0;
 766}
 767
 768static int vmk80xx_init_subdevices(struct comedi_device *dev)
 769{
 770        const struct vmk80xx_board *boardinfo = comedi_board(dev);
 771        struct vmk80xx_private *devpriv = dev->private;
 772        struct comedi_subdevice *s;
 773        int n_subd;
 774        int ret;
 775
 776        down(&devpriv->limit_sem);
 777
 778        if (devpriv->model == VMK8055_MODEL)
 779                n_subd = 5;
 780        else
 781                n_subd = 6;
 782        ret = comedi_alloc_subdevices(dev, n_subd);
 783        if (ret) {
 784                up(&devpriv->limit_sem);
 785                return ret;
 786        }
 787
 788        /* Analog input subdevice */
 789        s = &dev->subdevices[0];
 790        s->type         = COMEDI_SUBD_AI;
 791        s->subdev_flags = SDF_READABLE | SDF_GROUND;
 792        s->n_chan       = boardinfo->ai_nchans;
 793        s->maxdata      = boardinfo->ai_maxdata;
 794        s->range_table  = boardinfo->range;
 795        s->insn_read    = vmk80xx_ai_insn_read;
 796
 797        /* Analog output subdevice */
 798        s = &dev->subdevices[1];
 799        s->type         = COMEDI_SUBD_AO;
 800        s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
 801        s->n_chan       = boardinfo->ao_nchans;
 802        s->maxdata      = 0x00ff;
 803        s->range_table  = boardinfo->range;
 804        s->insn_write   = vmk80xx_ao_insn_write;
 805        if (devpriv->model == VMK8061_MODEL) {
 806                s->subdev_flags |= SDF_READABLE;
 807                s->insn_read    = vmk80xx_ao_insn_read;
 808        }
 809
 810        /* Digital input subdevice */
 811        s = &dev->subdevices[2];
 812        s->type         = COMEDI_SUBD_DI;
 813        s->subdev_flags = SDF_READABLE;
 814        s->n_chan       = boardinfo->di_nchans;
 815        s->maxdata      = 1;
 816        s->range_table  = &range_digital;
 817        s->insn_bits    = vmk80xx_di_insn_bits;
 818
 819        /* Digital output subdevice */
 820        s = &dev->subdevices[3];
 821        s->type         = COMEDI_SUBD_DO;
 822        s->subdev_flags = SDF_WRITEABLE;
 823        s->n_chan       = 8;
 824        s->maxdata      = 1;
 825        s->range_table  = &range_digital;
 826        s->insn_bits    = vmk80xx_do_insn_bits;
 827
 828        /* Counter subdevice */
 829        s = &dev->subdevices[4];
 830        s->type         = COMEDI_SUBD_COUNTER;
 831        s->subdev_flags = SDF_READABLE;
 832        s->n_chan       = 2;
 833        s->maxdata      = boardinfo->cnt_maxdata;
 834        s->insn_read    = vmk80xx_cnt_insn_read;
 835        s->insn_config  = vmk80xx_cnt_insn_config;
 836        if (devpriv->model == VMK8055_MODEL) {
 837                s->subdev_flags |= SDF_WRITEABLE;
 838                s->insn_write   = vmk80xx_cnt_insn_write;
 839        }
 840
 841        /* PWM subdevice */
 842        if (devpriv->model == VMK8061_MODEL) {
 843                s = &dev->subdevices[5];
 844                s->type         = COMEDI_SUBD_PWM;
 845                s->subdev_flags = SDF_READABLE | SDF_WRITEABLE;
 846                s->n_chan       = boardinfo->pwm_nchans;
 847                s->maxdata      = boardinfo->pwm_maxdata;
 848                s->insn_read    = vmk80xx_pwm_insn_read;
 849                s->insn_write   = vmk80xx_pwm_insn_write;
 850        }
 851
 852        up(&devpriv->limit_sem);
 853
 854        return 0;
 855}
 856
 857static int vmk80xx_auto_attach(struct comedi_device *dev,
 858                               unsigned long context)
 859{
 860        struct usb_interface *intf = comedi_to_usb_interface(dev);
 861        const struct vmk80xx_board *boardinfo;
 862        struct vmk80xx_private *devpriv;
 863        int ret;
 864
 865        boardinfo = &vmk80xx_boardinfo[context];
 866        dev->board_ptr = boardinfo;
 867        dev->board_name = boardinfo->name;
 868
 869        devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 870        if (!devpriv)
 871                return -ENOMEM;
 872
 873        devpriv->model = boardinfo->model;
 874
 875        ret = vmk80xx_find_usb_endpoints(dev);
 876        if (ret)
 877                return ret;
 878
 879        ret = vmk80xx_alloc_usb_buffers(dev);
 880        if (ret)
 881                return ret;
 882
 883        sema_init(&devpriv->limit_sem, 8);
 884
 885        usb_set_intfdata(intf, devpriv);
 886
 887        if (devpriv->model == VMK8061_MODEL) {
 888                vmk80xx_read_eeprom(dev, IC3_VERSION);
 889                dev_info(&intf->dev, "%s\n", devpriv->fw.ic3_vers);
 890
 891                if (vmk80xx_check_data_link(dev)) {
 892                        vmk80xx_read_eeprom(dev, IC6_VERSION);
 893                        dev_info(&intf->dev, "%s\n", devpriv->fw.ic6_vers);
 894                }
 895        }
 896
 897        if (devpriv->model == VMK8055_MODEL)
 898                vmk80xx_reset_device(dev);
 899
 900        return vmk80xx_init_subdevices(dev);
 901}
 902
 903static void vmk80xx_detach(struct comedi_device *dev)
 904{
 905        struct usb_interface *intf = comedi_to_usb_interface(dev);
 906        struct vmk80xx_private *devpriv = dev->private;
 907
 908        if (!devpriv)
 909                return;
 910
 911        down(&devpriv->limit_sem);
 912
 913        usb_set_intfdata(intf, NULL);
 914
 915        kfree(devpriv->usb_rx_buf);
 916        kfree(devpriv->usb_tx_buf);
 917
 918        up(&devpriv->limit_sem);
 919}
 920
 921static struct comedi_driver vmk80xx_driver = {
 922        .module         = THIS_MODULE,
 923        .driver_name    = "vmk80xx",
 924        .auto_attach    = vmk80xx_auto_attach,
 925        .detach         = vmk80xx_detach,
 926};
 927
 928static int vmk80xx_usb_probe(struct usb_interface *intf,
 929                             const struct usb_device_id *id)
 930{
 931        return comedi_usb_auto_config(intf, &vmk80xx_driver, id->driver_info);
 932}
 933
 934static const struct usb_device_id vmk80xx_usb_id_table[] = {
 935        { USB_DEVICE(0x10cf, 0x5500), .driver_info = DEVICE_VMK8055 },
 936        { USB_DEVICE(0x10cf, 0x5501), .driver_info = DEVICE_VMK8055 },
 937        { USB_DEVICE(0x10cf, 0x5502), .driver_info = DEVICE_VMK8055 },
 938        { USB_DEVICE(0x10cf, 0x5503), .driver_info = DEVICE_VMK8055 },
 939        { USB_DEVICE(0x10cf, 0x8061), .driver_info = DEVICE_VMK8061 },
 940        { USB_DEVICE(0x10cf, 0x8062), .driver_info = DEVICE_VMK8061 },
 941        { USB_DEVICE(0x10cf, 0x8063), .driver_info = DEVICE_VMK8061 },
 942        { USB_DEVICE(0x10cf, 0x8064), .driver_info = DEVICE_VMK8061 },
 943        { USB_DEVICE(0x10cf, 0x8065), .driver_info = DEVICE_VMK8061 },
 944        { USB_DEVICE(0x10cf, 0x8066), .driver_info = DEVICE_VMK8061 },
 945        { USB_DEVICE(0x10cf, 0x8067), .driver_info = DEVICE_VMK8061 },
 946        { USB_DEVICE(0x10cf, 0x8068), .driver_info = DEVICE_VMK8061 },
 947        { }
 948};
 949MODULE_DEVICE_TABLE(usb, vmk80xx_usb_id_table);
 950
 951static struct usb_driver vmk80xx_usb_driver = {
 952        .name           = "vmk80xx",
 953        .id_table       = vmk80xx_usb_id_table,
 954        .probe          = vmk80xx_usb_probe,
 955        .disconnect     = comedi_usb_auto_unconfig,
 956};
 957module_comedi_usb_driver(vmk80xx_driver, vmk80xx_usb_driver);
 958
 959MODULE_AUTHOR("Manuel Gebele <forensixs@gmx.de>");
 960MODULE_DESCRIPTION("Velleman USB Board Low-Level Driver");
 961MODULE_SUPPORTED_DEVICE("K8055/K8061 aka VM110/VM140");
 962MODULE_VERSION("0.8.01");
 963MODULE_LICENSE("GPL");
 964