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