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/*
  42Changelog:
  43
  440.8.81  -3-  code completely rewritten (adjust driver logic)
  450.8.81  -2-  full support for K8061
  460.8.81  -1-  fix some mistaken among others the number of
  47             supported boards and I/O handling
  48
  490.7.76  -4-  renamed to vmk80xx
  500.7.76  -3-  detect K8061 (only theoretically supported)
  510.7.76  -2-  code completely rewritten (adjust driver logic)
  520.7.76  -1-  support for digital and counter subdevice
  53*/
  54
  55#include <linux/kernel.h>
  56#include <linux/module.h>
  57#include <linux/mutex.h>
  58#include <linux/errno.h>
  59#include <linux/input.h>
  60#include <linux/slab.h>
  61#include <linux/poll.h>
  62#include <linux/usb.h>
  63#include <linux/uaccess.h>
  64
  65#include "../comedidev.h"
  66
  67#define BOARDNAME "vmk80xx"
  68
  69MODULE_AUTHOR("Manuel Gebele <forensixs@gmx.de>");
  70MODULE_DESCRIPTION("Velleman USB Board Low-Level Driver");
  71MODULE_SUPPORTED_DEVICE("K8055/K8061 aka VM110/VM140");
  72MODULE_VERSION("0.8.01");
  73MODULE_LICENSE("GPL");
  74
  75enum {
  76        DEVICE_VMK8055,
  77        DEVICE_VMK8061
  78};
  79
  80static const struct usb_device_id vmk80xx_id_table[] = {
  81        {USB_DEVICE(0x10cf, 0x5500), .driver_info = DEVICE_VMK8055},
  82        {USB_DEVICE(0x10cf, 0x5501), .driver_info = DEVICE_VMK8055},
  83        {USB_DEVICE(0x10cf, 0x5502), .driver_info = DEVICE_VMK8055},
  84        {USB_DEVICE(0x10cf, 0x5503), .driver_info = DEVICE_VMK8055},
  85        {USB_DEVICE(0x10cf, 0x8061), .driver_info = DEVICE_VMK8061},
  86        {USB_DEVICE(0x10cf, 0x8062), .driver_info = DEVICE_VMK8061},
  87        {USB_DEVICE(0x10cf, 0x8063), .driver_info = DEVICE_VMK8061},
  88        {USB_DEVICE(0x10cf, 0x8064), .driver_info = DEVICE_VMK8061},
  89        {USB_DEVICE(0x10cf, 0x8065), .driver_info = DEVICE_VMK8061},
  90        {USB_DEVICE(0x10cf, 0x8066), .driver_info = DEVICE_VMK8061},
  91        {USB_DEVICE(0x10cf, 0x8067), .driver_info = DEVICE_VMK8061},
  92        {USB_DEVICE(0x10cf, 0x8068), .driver_info = DEVICE_VMK8061},
  93        {}                      /* terminating entry */
  94};
  95
  96MODULE_DEVICE_TABLE(usb, vmk80xx_id_table);
  97
  98#define VMK8055_DI_REG          0x00
  99#define VMK8055_DO_REG          0x01
 100#define VMK8055_AO1_REG         0x02
 101#define VMK8055_AO2_REG         0x03
 102#define VMK8055_AI1_REG         0x02
 103#define VMK8055_AI2_REG         0x03
 104#define VMK8055_CNT1_REG        0x04
 105#define VMK8055_CNT2_REG        0x06
 106
 107#define VMK8061_CH_REG          0x01
 108#define VMK8061_DI_REG          0x01
 109#define VMK8061_DO_REG          0x01
 110#define VMK8061_PWM_REG1        0x01
 111#define VMK8061_PWM_REG2        0x02
 112#define VMK8061_CNT_REG         0x02
 113#define VMK8061_AO_REG          0x02
 114#define VMK8061_AI_REG1         0x02
 115#define VMK8061_AI_REG2         0x03
 116
 117#define VMK8055_CMD_RST         0x00
 118#define VMK8055_CMD_DEB1_TIME   0x01
 119#define VMK8055_CMD_DEB2_TIME   0x02
 120#define VMK8055_CMD_RST_CNT1    0x03
 121#define VMK8055_CMD_RST_CNT2    0x04
 122#define VMK8055_CMD_WRT_AD      0x05
 123
 124#define VMK8061_CMD_RD_AI       0x00
 125#define VMK8061_CMR_RD_ALL_AI   0x01    /* !non-active! */
 126#define VMK8061_CMD_SET_AO      0x02
 127#define VMK8061_CMD_SET_ALL_AO  0x03    /* !non-active! */
 128#define VMK8061_CMD_OUT_PWM     0x04
 129#define VMK8061_CMD_RD_DI       0x05
 130#define VMK8061_CMD_DO          0x06    /* !non-active! */
 131#define VMK8061_CMD_CLR_DO      0x07
 132#define VMK8061_CMD_SET_DO      0x08
 133#define VMK8061_CMD_RD_CNT      0x09    /* TODO: completely pointless? */
 134#define VMK8061_CMD_RST_CNT     0x0a    /* TODO: completely pointless? */
 135#define VMK8061_CMD_RD_VERSION  0x0b    /* internal usage */
 136#define VMK8061_CMD_RD_JMP_STAT 0x0c    /* TODO: not implemented yet */
 137#define VMK8061_CMD_RD_PWR_STAT 0x0d    /* internal usage */
 138#define VMK8061_CMD_RD_DO       0x0e
 139#define VMK8061_CMD_RD_AO       0x0f
 140#define VMK8061_CMD_RD_PWM      0x10
 141
 142#define VMK80XX_MAX_BOARDS      COMEDI_NUM_BOARD_MINORS
 143
 144#define TRANS_OUT_BUSY          1
 145#define TRANS_IN_BUSY           2
 146#define TRANS_IN_RUNNING        3
 147
 148#define IC3_VERSION             (1 << 0)
 149#define IC6_VERSION             (1 << 1)
 150
 151#define URB_RCV_FLAG            (1 << 0)
 152#define URB_SND_FLAG            (1 << 1)
 153
 154#define CONFIG_VMK80XX_DEBUG
 155#undef CONFIG_VMK80XX_DEBUG
 156
 157#ifdef CONFIG_VMK80XX_DEBUG
 158static int dbgvm = 1;
 159#else
 160static int dbgvm;
 161#endif
 162
 163#ifdef CONFIG_COMEDI_DEBUG
 164static int dbgcm = 1;
 165#else
 166static int dbgcm;
 167#endif
 168
 169#define dbgvm(fmt, arg...)                     \
 170do {                                           \
 171        if (dbgvm)                             \
 172                printk(KERN_DEBUG fmt, ##arg); \
 173} while (0)
 174
 175#define dbgcm(fmt, arg...)                     \
 176do {                                           \
 177        if (dbgcm)                             \
 178                printk(KERN_DEBUG fmt, ##arg); \
 179} while (0)
 180
 181enum vmk80xx_model {
 182        VMK8055_MODEL,
 183        VMK8061_MODEL
 184};
 185
 186struct firmware_version {
 187        unsigned char ic3_vers[32];     /* USB-Controller */
 188        unsigned char ic6_vers[32];     /* CPU */
 189};
 190
 191static const struct comedi_lrange vmk8055_range = {
 192        1, {UNI_RANGE(5)}
 193};
 194
 195static const struct comedi_lrange vmk8061_range = {
 196        2, {UNI_RANGE(5), UNI_RANGE(10)}
 197};
 198
 199struct vmk80xx_board {
 200        const char *name;
 201        enum vmk80xx_model model;
 202        const struct comedi_lrange *range;
 203        __u8 ai_chans;
 204        __le16 ai_bits;
 205        __u8 ao_chans;
 206        __le16 ao_bits;
 207        __u8 di_chans;
 208        __le16 di_bits;
 209        __u8 do_chans;
 210        __le16 do_bits;
 211        __u8 cnt_chans;
 212        __le16 cnt_bits;
 213        __u8 pwm_chans;
 214        __le16 pwm_bits;
 215};
 216
 217enum {
 218        VMK80XX_SUBD_AI,
 219        VMK80XX_SUBD_AO,
 220        VMK80XX_SUBD_DI,
 221        VMK80XX_SUBD_DO,
 222        VMK80XX_SUBD_CNT,
 223        VMK80XX_SUBD_PWM,
 224};
 225
 226struct vmk80xx_usb {
 227        struct usb_device *udev;
 228        struct usb_interface *intf;
 229        struct usb_endpoint_descriptor *ep_rx;
 230        struct usb_endpoint_descriptor *ep_tx;
 231        struct usb_anchor rx_anchor;
 232        struct usb_anchor tx_anchor;
 233        struct vmk80xx_board board;
 234        struct firmware_version fw;
 235        struct semaphore limit_sem;
 236        wait_queue_head_t read_wait;
 237        wait_queue_head_t write_wait;
 238        unsigned char *usb_rx_buf;
 239        unsigned char *usb_tx_buf;
 240        unsigned long flags;
 241        int probed;
 242        int attached;
 243        int count;
 244};
 245
 246static struct vmk80xx_usb vmb[VMK80XX_MAX_BOARDS];
 247
 248static DEFINE_MUTEX(glb_mutex);
 249
 250static void vmk80xx_tx_callback(struct urb *urb)
 251{
 252        struct vmk80xx_usb *dev = urb->context;
 253        int stat = urb->status;
 254
 255        dbgvm("vmk80xx: %s\n", __func__);
 256
 257        if (stat && !(stat == -ENOENT
 258                      || stat == -ECONNRESET || stat == -ESHUTDOWN))
 259                dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
 260                      __func__, stat);
 261
 262        if (!test_bit(TRANS_OUT_BUSY, &dev->flags))
 263                return;
 264
 265        clear_bit(TRANS_OUT_BUSY, &dev->flags);
 266
 267        wake_up_interruptible(&dev->write_wait);
 268}
 269
 270static void vmk80xx_rx_callback(struct urb *urb)
 271{
 272        struct vmk80xx_usb *dev = urb->context;
 273        int stat = urb->status;
 274
 275        dbgvm("vmk80xx: %s\n", __func__);
 276
 277        switch (stat) {
 278        case 0:
 279                break;
 280        case -ENOENT:
 281        case -ECONNRESET:
 282        case -ESHUTDOWN:
 283                break;
 284        default:
 285                dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
 286                      __func__, stat);
 287                goto resubmit;
 288        }
 289
 290        goto exit;
 291resubmit:
 292        if (test_bit(TRANS_IN_RUNNING, &dev->flags) && dev->intf) {
 293                usb_anchor_urb(urb, &dev->rx_anchor);
 294
 295                if (!usb_submit_urb(urb, GFP_KERNEL))
 296                        goto exit;
 297
 298                err("comedi#: vmk80xx: %s - submit urb failed\n", __func__);
 299
 300                usb_unanchor_urb(urb);
 301        }
 302exit:
 303        clear_bit(TRANS_IN_BUSY, &dev->flags);
 304
 305        wake_up_interruptible(&dev->read_wait);
 306}
 307
 308static int vmk80xx_check_data_link(struct vmk80xx_usb *dev)
 309{
 310        unsigned int tx_pipe;
 311        unsigned int rx_pipe;
 312        unsigned char tx[1];
 313        unsigned char rx[2];
 314
 315        dbgvm("vmk80xx: %s\n", __func__);
 316
 317        tx_pipe = usb_sndbulkpipe(dev->udev, 0x01);
 318        rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81);
 319
 320        tx[0] = VMK8061_CMD_RD_PWR_STAT;
 321
 322        /*
 323         * Check that IC6 (PIC16F871) is powered and
 324         * running and the data link between IC3 and
 325         * IC6 is working properly
 326         */
 327        usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL, dev->ep_tx->bInterval);
 328        usb_bulk_msg(dev->udev, rx_pipe, rx, 2, NULL, HZ * 10);
 329
 330        return (int)rx[1];
 331}
 332
 333static void vmk80xx_read_eeprom(struct vmk80xx_usb *dev, int flag)
 334{
 335        unsigned int tx_pipe;
 336        unsigned int rx_pipe;
 337        unsigned char tx[1];
 338        unsigned char rx[64];
 339        int cnt;
 340
 341        dbgvm("vmk80xx: %s\n", __func__);
 342
 343        tx_pipe = usb_sndbulkpipe(dev->udev, 0x01);
 344        rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81);
 345
 346        tx[0] = VMK8061_CMD_RD_VERSION;
 347
 348        /*
 349         * Read the firmware version info of IC3 and
 350         * IC6 from the internal EEPROM of the IC
 351         */
 352        usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL, dev->ep_tx->bInterval);
 353        usb_bulk_msg(dev->udev, rx_pipe, rx, 64, &cnt, HZ * 10);
 354
 355        rx[cnt] = '\0';
 356
 357        if (flag & IC3_VERSION)
 358                strncpy(dev->fw.ic3_vers, rx + 1, 24);
 359        else                    /* IC6_VERSION */
 360                strncpy(dev->fw.ic6_vers, rx + 25, 24);
 361}
 362
 363static int vmk80xx_reset_device(struct vmk80xx_usb *dev)
 364{
 365        struct urb *urb;
 366        unsigned int tx_pipe;
 367        int ival;
 368        size_t size;
 369
 370        dbgvm("vmk80xx: %s\n", __func__);
 371
 372        urb = usb_alloc_urb(0, GFP_KERNEL);
 373        if (!urb)
 374                return -ENOMEM;
 375
 376        tx_pipe = usb_sndintpipe(dev->udev, 0x01);
 377
 378        ival = dev->ep_tx->bInterval;
 379        size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
 380
 381        dev->usb_tx_buf[0] = VMK8055_CMD_RST;
 382        dev->usb_tx_buf[1] = 0x00;
 383        dev->usb_tx_buf[2] = 0x00;
 384        dev->usb_tx_buf[3] = 0x00;
 385        dev->usb_tx_buf[4] = 0x00;
 386        dev->usb_tx_buf[5] = 0x00;
 387        dev->usb_tx_buf[6] = 0x00;
 388        dev->usb_tx_buf[7] = 0x00;
 389
 390        usb_fill_int_urb(urb, dev->udev, tx_pipe, dev->usb_tx_buf,
 391                         size, vmk80xx_tx_callback, dev, ival);
 392
 393        usb_anchor_urb(urb, &dev->tx_anchor);
 394
 395        return usb_submit_urb(urb, GFP_KERNEL);
 396}
 397
 398static void vmk80xx_build_int_urb(struct urb *urb, int flag)
 399{
 400        struct vmk80xx_usb *dev = urb->context;
 401        __u8 rx_addr;
 402        __u8 tx_addr;
 403        unsigned int pipe;
 404        unsigned char *buf;
 405        size_t size;
 406        void (*callback) (struct urb *);
 407        int ival;
 408
 409        dbgvm("vmk80xx: %s\n", __func__);
 410
 411        if (flag & URB_RCV_FLAG) {
 412                rx_addr = dev->ep_rx->bEndpointAddress;
 413                pipe = usb_rcvintpipe(dev->udev, rx_addr);
 414                buf = dev->usb_rx_buf;
 415                size = le16_to_cpu(dev->ep_rx->wMaxPacketSize);
 416                callback = vmk80xx_rx_callback;
 417                ival = dev->ep_rx->bInterval;
 418        } else {                /* URB_SND_FLAG */
 419                tx_addr = dev->ep_tx->bEndpointAddress;
 420                pipe = usb_sndintpipe(dev->udev, tx_addr);
 421                buf = dev->usb_tx_buf;
 422                size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
 423                callback = vmk80xx_tx_callback;
 424                ival = dev->ep_tx->bInterval;
 425        }
 426
 427        usb_fill_int_urb(urb, dev->udev, pipe, buf, size, callback, dev, ival);
 428}
 429
 430static void vmk80xx_do_bulk_msg(struct vmk80xx_usb *dev)
 431{
 432        __u8 tx_addr;
 433        __u8 rx_addr;
 434        unsigned int tx_pipe;
 435        unsigned int rx_pipe;
 436        size_t size;
 437
 438        dbgvm("vmk80xx: %s\n", __func__);
 439
 440        set_bit(TRANS_IN_BUSY, &dev->flags);
 441        set_bit(TRANS_OUT_BUSY, &dev->flags);
 442
 443        tx_addr = dev->ep_tx->bEndpointAddress;
 444        rx_addr = dev->ep_rx->bEndpointAddress;
 445        tx_pipe = usb_sndbulkpipe(dev->udev, tx_addr);
 446        rx_pipe = usb_rcvbulkpipe(dev->udev, rx_addr);
 447
 448        /*
 449         * The max packet size attributes of the K8061
 450         * input/output endpoints are identical
 451         */
 452        size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
 453
 454        usb_bulk_msg(dev->udev, tx_pipe, dev->usb_tx_buf,
 455                     size, NULL, dev->ep_tx->bInterval);
 456        usb_bulk_msg(dev->udev, rx_pipe, dev->usb_rx_buf, size, NULL, HZ * 10);
 457
 458        clear_bit(TRANS_OUT_BUSY, &dev->flags);
 459        clear_bit(TRANS_IN_BUSY, &dev->flags);
 460}
 461
 462static int vmk80xx_read_packet(struct vmk80xx_usb *dev)
 463{
 464        struct urb *urb;
 465        int retval;
 466
 467        dbgvm("vmk80xx: %s\n", __func__);
 468
 469        if (!dev->intf)
 470                return -ENODEV;
 471
 472        /* Only useful for interrupt transfers */
 473        if (test_bit(TRANS_IN_BUSY, &dev->flags))
 474                if (wait_event_interruptible(dev->read_wait,
 475                                             !test_bit(TRANS_IN_BUSY,
 476                                                       &dev->flags)))
 477                        return -ERESTART;
 478
 479        if (dev->board.model == VMK8061_MODEL) {
 480                vmk80xx_do_bulk_msg(dev);
 481
 482                return 0;
 483        }
 484
 485        urb = usb_alloc_urb(0, GFP_KERNEL);
 486        if (!urb)
 487                return -ENOMEM;
 488
 489        urb->context = dev;
 490        vmk80xx_build_int_urb(urb, URB_RCV_FLAG);
 491
 492        set_bit(TRANS_IN_RUNNING, &dev->flags);
 493        set_bit(TRANS_IN_BUSY, &dev->flags);
 494
 495        usb_anchor_urb(urb, &dev->rx_anchor);
 496
 497        retval = usb_submit_urb(urb, GFP_KERNEL);
 498        if (!retval)
 499                goto exit;
 500
 501        clear_bit(TRANS_IN_RUNNING, &dev->flags);
 502        usb_unanchor_urb(urb);
 503
 504exit:
 505        usb_free_urb(urb);
 506
 507        return retval;
 508}
 509
 510static int vmk80xx_write_packet(struct vmk80xx_usb *dev, int cmd)
 511{
 512        struct urb *urb;
 513        int retval;
 514
 515        dbgvm("vmk80xx: %s\n", __func__);
 516
 517        if (!dev->intf)
 518                return -ENODEV;
 519
 520        if (test_bit(TRANS_OUT_BUSY, &dev->flags))
 521                if (wait_event_interruptible(dev->write_wait,
 522                                             !test_bit(TRANS_OUT_BUSY,
 523                                                       &dev->flags)))
 524                        return -ERESTART;
 525
 526        if (dev->board.model == VMK8061_MODEL) {
 527                dev->usb_tx_buf[0] = cmd;
 528                vmk80xx_do_bulk_msg(dev);
 529
 530                return 0;
 531        }
 532
 533        urb = usb_alloc_urb(0, GFP_KERNEL);
 534        if (!urb)
 535                return -ENOMEM;
 536
 537        urb->context = dev;
 538        vmk80xx_build_int_urb(urb, URB_SND_FLAG);
 539
 540        set_bit(TRANS_OUT_BUSY, &dev->flags);
 541
 542        usb_anchor_urb(urb, &dev->tx_anchor);
 543
 544        dev->usb_tx_buf[0] = cmd;
 545
 546        retval = usb_submit_urb(urb, GFP_KERNEL);
 547        if (!retval)
 548                goto exit;
 549
 550        clear_bit(TRANS_OUT_BUSY, &dev->flags);
 551        usb_unanchor_urb(urb);
 552
 553exit:
 554        usb_free_urb(urb);
 555
 556        return retval;
 557}
 558
 559#define DIR_IN  1
 560#define DIR_OUT 2
 561
 562static int rudimentary_check(struct vmk80xx_usb *dev, int dir)
 563{
 564        if (!dev)
 565                return -EFAULT;
 566        if (!dev->probed)
 567                return -ENODEV;
 568        if (!dev->attached)
 569                return -ENODEV;
 570        if (dir & DIR_IN) {
 571                if (test_bit(TRANS_IN_BUSY, &dev->flags))
 572                        return -EBUSY;
 573        }
 574        if (dir & DIR_OUT) {
 575                if (test_bit(TRANS_OUT_BUSY, &dev->flags))
 576                        return -EBUSY;
 577        }
 578
 579        return 0;
 580}
 581
 582static int vmk80xx_ai_rinsn(struct comedi_device *cdev,
 583                            struct comedi_subdevice *s,
 584                            struct comedi_insn *insn, unsigned int *data)
 585{
 586        struct vmk80xx_usb *dev = cdev->private;
 587        int chan;
 588        int reg[2];
 589        int n;
 590
 591        dbgvm("vmk80xx: %s\n", __func__);
 592
 593        n = rudimentary_check(dev, DIR_IN);
 594        if (n)
 595                return n;
 596
 597        down(&dev->limit_sem);
 598        chan = CR_CHAN(insn->chanspec);
 599
 600        switch (dev->board.model) {
 601        case VMK8055_MODEL:
 602                if (!chan)
 603                        reg[0] = VMK8055_AI1_REG;
 604                else
 605                        reg[0] = VMK8055_AI2_REG;
 606                break;
 607        case VMK8061_MODEL:
 608                reg[0] = VMK8061_AI_REG1;
 609                reg[1] = VMK8061_AI_REG2;
 610                dev->usb_tx_buf[0] = VMK8061_CMD_RD_AI;
 611                dev->usb_tx_buf[VMK8061_CH_REG] = chan;
 612                break;
 613        }
 614
 615        for (n = 0; n < insn->n; n++) {
 616                if (vmk80xx_read_packet(dev))
 617                        break;
 618
 619                if (dev->board.model == VMK8055_MODEL) {
 620                        data[n] = dev->usb_rx_buf[reg[0]];
 621                        continue;
 622                }
 623
 624                /* VMK8061_MODEL */
 625                data[n] = dev->usb_rx_buf[reg[0]] + 256 *
 626                    dev->usb_rx_buf[reg[1]];
 627        }
 628
 629        up(&dev->limit_sem);
 630
 631        return n;
 632}
 633
 634static int vmk80xx_ao_winsn(struct comedi_device *cdev,
 635                            struct comedi_subdevice *s,
 636                            struct comedi_insn *insn, unsigned int *data)
 637{
 638        struct vmk80xx_usb *dev = cdev->private;
 639        int chan;
 640        int cmd;
 641        int reg;
 642        int n;
 643
 644        dbgvm("vmk80xx: %s\n", __func__);
 645
 646        n = rudimentary_check(dev, DIR_OUT);
 647        if (n)
 648                return n;
 649
 650        down(&dev->limit_sem);
 651        chan = CR_CHAN(insn->chanspec);
 652
 653        switch (dev->board.model) {
 654        case VMK8055_MODEL:
 655                cmd = VMK8055_CMD_WRT_AD;
 656                if (!chan)
 657                        reg = VMK8055_AO1_REG;
 658                else
 659                        reg = VMK8055_AO2_REG;
 660                break;
 661        default:                /* NOTE: avoid compiler warnings */
 662                cmd = VMK8061_CMD_SET_AO;
 663                reg = VMK8061_AO_REG;
 664                dev->usb_tx_buf[VMK8061_CH_REG] = chan;
 665                break;
 666        }
 667
 668        for (n = 0; n < insn->n; n++) {
 669                dev->usb_tx_buf[reg] = data[n];
 670
 671                if (vmk80xx_write_packet(dev, cmd))
 672                        break;
 673        }
 674
 675        up(&dev->limit_sem);
 676
 677        return n;
 678}
 679
 680static int vmk80xx_ao_rinsn(struct comedi_device *cdev,
 681                            struct comedi_subdevice *s,
 682                            struct comedi_insn *insn, unsigned int *data)
 683{
 684        struct vmk80xx_usb *dev = cdev->private;
 685        int chan;
 686        int reg;
 687        int n;
 688
 689        dbgvm("vmk80xx: %s\n", __func__);
 690
 691        n = rudimentary_check(dev, DIR_IN);
 692        if (n)
 693                return n;
 694
 695        down(&dev->limit_sem);
 696        chan = CR_CHAN(insn->chanspec);
 697
 698        reg = VMK8061_AO_REG - 1;
 699
 700        dev->usb_tx_buf[0] = VMK8061_CMD_RD_AO;
 701
 702        for (n = 0; n < insn->n; n++) {
 703                if (vmk80xx_read_packet(dev))
 704                        break;
 705
 706                data[n] = dev->usb_rx_buf[reg + chan];
 707        }
 708
 709        up(&dev->limit_sem);
 710
 711        return n;
 712}
 713
 714static int vmk80xx_di_bits(struct comedi_device *cdev,
 715                           struct comedi_subdevice *s,
 716                           struct comedi_insn *insn, unsigned int *data)
 717{
 718        struct vmk80xx_usb *dev = cdev->private;
 719        unsigned char *rx_buf;
 720        int reg;
 721        int retval;
 722
 723        dbgvm("vmk80xx: %s\n", __func__);
 724
 725        retval = rudimentary_check(dev, DIR_IN);
 726        if (retval)
 727                return retval;
 728
 729        down(&dev->limit_sem);
 730
 731        rx_buf = dev->usb_rx_buf;
 732
 733        if (dev->board.model == VMK8061_MODEL) {
 734                reg = VMK8061_DI_REG;
 735                dev->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
 736        } else {
 737                reg = VMK8055_DI_REG;
 738        }
 739
 740        retval = vmk80xx_read_packet(dev);
 741
 742        if (!retval) {
 743                if (dev->board.model == VMK8055_MODEL)
 744                        data[1] = (((rx_buf[reg] >> 4) & 0x03) |
 745                                  ((rx_buf[reg] << 2) & 0x04) |
 746                                  ((rx_buf[reg] >> 3) & 0x18));
 747                else
 748                        data[1] = rx_buf[reg];
 749
 750                retval = 2;
 751        }
 752
 753        up(&dev->limit_sem);
 754
 755        return retval;
 756}
 757
 758static int vmk80xx_di_rinsn(struct comedi_device *cdev,
 759                            struct comedi_subdevice *s,
 760                            struct comedi_insn *insn, unsigned int *data)
 761{
 762        struct vmk80xx_usb *dev = cdev->private;
 763        int chan;
 764        unsigned char *rx_buf;
 765        int reg;
 766        int inp;
 767        int n;
 768
 769        dbgvm("vmk80xx: %s\n", __func__);
 770
 771        n = rudimentary_check(dev, DIR_IN);
 772        if (n)
 773                return n;
 774
 775        down(&dev->limit_sem);
 776        chan = CR_CHAN(insn->chanspec);
 777
 778        rx_buf = dev->usb_rx_buf;
 779
 780        if (dev->board.model == VMK8061_MODEL) {
 781                reg = VMK8061_DI_REG;
 782                dev->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
 783        } else {
 784                reg = VMK8055_DI_REG;
 785        }
 786        for (n = 0; n < insn->n; n++) {
 787                if (vmk80xx_read_packet(dev))
 788                        break;
 789
 790                if (dev->board.model == VMK8055_MODEL)
 791                        inp = (((rx_buf[reg] >> 4) & 0x03) |
 792                               ((rx_buf[reg] << 2) & 0x04) |
 793                               ((rx_buf[reg] >> 3) & 0x18));
 794                else
 795                        inp = rx_buf[reg];
 796
 797                data[n] = (inp >> chan) & 1;
 798        }
 799
 800        up(&dev->limit_sem);
 801
 802        return n;
 803}
 804
 805static int vmk80xx_do_winsn(struct comedi_device *cdev,
 806                            struct comedi_subdevice *s,
 807                            struct comedi_insn *insn, unsigned int *data)
 808{
 809        struct vmk80xx_usb *dev = cdev->private;
 810        int chan;
 811        unsigned char *tx_buf;
 812        int reg;
 813        int cmd;
 814        int n;
 815
 816        dbgvm("vmk80xx: %s\n", __func__);
 817
 818        n = rudimentary_check(dev, DIR_OUT);
 819        if (n)
 820                return n;
 821
 822        down(&dev->limit_sem);
 823        chan = CR_CHAN(insn->chanspec);
 824
 825        tx_buf = dev->usb_tx_buf;
 826
 827        for (n = 0; n < insn->n; n++) {
 828                if (dev->board.model == VMK8055_MODEL) {
 829                        reg = VMK8055_DO_REG;
 830                        cmd = VMK8055_CMD_WRT_AD;
 831                        if (data[n] == 1)
 832                                tx_buf[reg] |= (1 << chan);
 833                        else
 834                                tx_buf[reg] ^= (1 << chan);
 835                } else { /* VMK8061_MODEL */
 836                        reg = VMK8061_DO_REG;
 837                        if (data[n] == 1) {
 838                                cmd = VMK8061_CMD_SET_DO;
 839                                tx_buf[reg] = 1 << chan;
 840                        } else {
 841                                cmd = VMK8061_CMD_CLR_DO;
 842                                tx_buf[reg] = 0xff - (1 << chan);
 843                        }
 844                }
 845
 846                if (vmk80xx_write_packet(dev, cmd))
 847                        break;
 848        }
 849
 850        up(&dev->limit_sem);
 851
 852        return n;
 853}
 854
 855static int vmk80xx_do_rinsn(struct comedi_device *cdev,
 856                            struct comedi_subdevice *s,
 857                            struct comedi_insn *insn, unsigned int *data)
 858{
 859        struct vmk80xx_usb *dev = cdev->private;
 860        int chan;
 861        int reg;
 862        int n;
 863
 864        dbgvm("vmk80xx: %s\n", __func__);
 865
 866        n = rudimentary_check(dev, DIR_IN);
 867        if (n)
 868                return n;
 869
 870        down(&dev->limit_sem);
 871        chan = CR_CHAN(insn->chanspec);
 872
 873        reg = VMK8061_DO_REG;
 874
 875        dev->usb_tx_buf[0] = VMK8061_CMD_RD_DO;
 876
 877        for (n = 0; n < insn->n; n++) {
 878                if (vmk80xx_read_packet(dev))
 879                        break;
 880
 881                data[n] = (dev->usb_rx_buf[reg] >> chan) & 1;
 882        }
 883
 884        up(&dev->limit_sem);
 885
 886        return n;
 887}
 888
 889static int vmk80xx_do_bits(struct comedi_device *cdev,
 890                           struct comedi_subdevice *s,
 891                           struct comedi_insn *insn, unsigned int *data)
 892{
 893        struct vmk80xx_usb *dev = cdev->private;
 894        unsigned char *rx_buf, *tx_buf;
 895        int dir, reg, cmd;
 896        int retval;
 897
 898        dbgvm("vmk80xx: %s\n", __func__);
 899
 900        dir = 0;
 901
 902        if (data[0])
 903                dir |= DIR_OUT;
 904
 905        if (dev->board.model == VMK8061_MODEL)
 906                dir |= DIR_IN;
 907
 908        retval = rudimentary_check(dev, dir);
 909        if (retval)
 910                return retval;
 911
 912        down(&dev->limit_sem);
 913
 914        rx_buf = dev->usb_rx_buf;
 915        tx_buf = dev->usb_tx_buf;
 916
 917        if (data[0]) {
 918                if (dev->board.model == VMK8055_MODEL) {
 919                        reg = VMK8055_DO_REG;
 920                        cmd = VMK8055_CMD_WRT_AD;
 921                } else { /* VMK8061_MODEL */
 922                        reg = VMK8061_DO_REG;
 923                        cmd = VMK8061_CMD_DO;
 924                }
 925
 926                tx_buf[reg] &= ~data[0];
 927                tx_buf[reg] |= (data[0] & data[1]);
 928
 929                retval = vmk80xx_write_packet(dev, cmd);
 930
 931                if (retval)
 932                        goto out;
 933        }
 934
 935        if (dev->board.model == VMK8061_MODEL) {
 936                reg = VMK8061_DO_REG;
 937                tx_buf[0] = VMK8061_CMD_RD_DO;
 938
 939                retval = vmk80xx_read_packet(dev);
 940
 941                if (!retval) {
 942                        data[1] = rx_buf[reg];
 943                        retval = 2;
 944                }
 945        } else {
 946                data[1] = tx_buf[reg];
 947                retval = 2;
 948        }
 949
 950out:
 951        up(&dev->limit_sem);
 952
 953        return retval;
 954}
 955
 956static int vmk80xx_cnt_rinsn(struct comedi_device *cdev,
 957                             struct comedi_subdevice *s,
 958                             struct comedi_insn *insn, unsigned int *data)
 959{
 960        struct vmk80xx_usb *dev = cdev->private;
 961        int chan;
 962        int reg[2];
 963        int n;
 964
 965        dbgvm("vmk80xx: %s\n", __func__);
 966
 967        n = rudimentary_check(dev, DIR_IN);
 968        if (n)
 969                return n;
 970
 971        down(&dev->limit_sem);
 972        chan = CR_CHAN(insn->chanspec);
 973
 974        switch (dev->board.model) {
 975        case VMK8055_MODEL:
 976                if (!chan)
 977                        reg[0] = VMK8055_CNT1_REG;
 978                else
 979                        reg[0] = VMK8055_CNT2_REG;
 980                break;
 981        case VMK8061_MODEL:
 982                reg[0] = VMK8061_CNT_REG;
 983                reg[1] = VMK8061_CNT_REG;
 984                dev->usb_tx_buf[0] = VMK8061_CMD_RD_CNT;
 985                break;
 986        }
 987
 988        for (n = 0; n < insn->n; n++) {
 989                if (vmk80xx_read_packet(dev))
 990                        break;
 991
 992                if (dev->board.model == VMK8055_MODEL)
 993                        data[n] = dev->usb_rx_buf[reg[0]];
 994                else /* VMK8061_MODEL */
 995                        data[n] = dev->usb_rx_buf[reg[0] * (chan + 1) + 1]
 996                            + 256 * dev->usb_rx_buf[reg[1] * 2 + 2];
 997        }
 998
 999        up(&dev->limit_sem);
1000
1001        return n;
1002}
1003
1004static int vmk80xx_cnt_cinsn(struct comedi_device *cdev,
1005                             struct comedi_subdevice *s,
1006                             struct comedi_insn *insn, unsigned int *data)
1007{
1008        struct vmk80xx_usb *dev = cdev->private;
1009        unsigned int insn_cmd;
1010        int chan;
1011        int cmd;
1012        int reg;
1013        int n;
1014
1015        dbgvm("vmk80xx: %s\n", __func__);
1016
1017        n = rudimentary_check(dev, DIR_OUT);
1018        if (n)
1019                return n;
1020
1021        down(&dev->limit_sem);
1022
1023        insn_cmd = data[0];
1024        if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET)
1025                return -EINVAL;
1026
1027        chan = CR_CHAN(insn->chanspec);
1028
1029        if (dev->board.model == VMK8055_MODEL) {
1030                if (!chan) {
1031                        cmd = VMK8055_CMD_RST_CNT1;
1032                        reg = VMK8055_CNT1_REG;
1033                } else {
1034                        cmd = VMK8055_CMD_RST_CNT2;
1035                        reg = VMK8055_CNT2_REG;
1036                }
1037
1038                dev->usb_tx_buf[reg] = 0x00;
1039        } else {
1040                cmd = VMK8061_CMD_RST_CNT;
1041        }
1042
1043        for (n = 0; n < insn->n; n++)
1044                if (vmk80xx_write_packet(dev, cmd))
1045                        break;
1046
1047        up(&dev->limit_sem);
1048
1049        return n;
1050}
1051
1052static int vmk80xx_cnt_winsn(struct comedi_device *cdev,
1053                             struct comedi_subdevice *s,
1054                             struct comedi_insn *insn, unsigned int *data)
1055{
1056        struct vmk80xx_usb *dev = cdev->private;
1057        unsigned long debtime;
1058        unsigned long val;
1059        int chan;
1060        int cmd;
1061        int n;
1062
1063        dbgvm("vmk80xx: %s\n", __func__);
1064
1065        n = rudimentary_check(dev, DIR_OUT);
1066        if (n)
1067                return n;
1068
1069        down(&dev->limit_sem);
1070        chan = CR_CHAN(insn->chanspec);
1071
1072        if (!chan)
1073                cmd = VMK8055_CMD_DEB1_TIME;
1074        else
1075                cmd = VMK8055_CMD_DEB2_TIME;
1076
1077        for (n = 0; n < insn->n; n++) {
1078                debtime = data[n];
1079                if (debtime == 0)
1080                        debtime = 1;
1081
1082                /* TODO: Prevent overflows */
1083                if (debtime > 7450)
1084                        debtime = 7450;
1085
1086                val = int_sqrt(debtime * 1000 / 115);
1087                if (((val + 1) * val) < debtime * 1000 / 115)
1088                        val += 1;
1089
1090                dev->usb_tx_buf[6 + chan] = val;
1091
1092                if (vmk80xx_write_packet(dev, cmd))
1093                        break;
1094        }
1095
1096        up(&dev->limit_sem);
1097
1098        return n;
1099}
1100
1101static int vmk80xx_pwm_rinsn(struct comedi_device *cdev,
1102                             struct comedi_subdevice *s,
1103                             struct comedi_insn *insn, unsigned int *data)
1104{
1105        struct vmk80xx_usb *dev = cdev->private;
1106        int reg[2];
1107        int n;
1108
1109        dbgvm("vmk80xx: %s\n", __func__);
1110
1111        n = rudimentary_check(dev, DIR_IN);
1112        if (n)
1113                return n;
1114
1115        down(&dev->limit_sem);
1116
1117        reg[0] = VMK8061_PWM_REG1;
1118        reg[1] = VMK8061_PWM_REG2;
1119
1120        dev->usb_tx_buf[0] = VMK8061_CMD_RD_PWM;
1121
1122        for (n = 0; n < insn->n; n++) {
1123                if (vmk80xx_read_packet(dev))
1124                        break;
1125
1126                data[n] = dev->usb_rx_buf[reg[0]] + 4 * dev->usb_rx_buf[reg[1]];
1127        }
1128
1129        up(&dev->limit_sem);
1130
1131        return n;
1132}
1133
1134static int vmk80xx_pwm_winsn(struct comedi_device *cdev,
1135                             struct comedi_subdevice *s,
1136                             struct comedi_insn *insn, unsigned int *data)
1137{
1138        struct vmk80xx_usb *dev = cdev->private;
1139        unsigned char *tx_buf;
1140        int reg[2];
1141        int cmd;
1142        int n;
1143
1144        dbgvm("vmk80xx: %s\n", __func__);
1145
1146        n = rudimentary_check(dev, DIR_OUT);
1147        if (n)
1148                return n;
1149
1150        down(&dev->limit_sem);
1151
1152        tx_buf = dev->usb_tx_buf;
1153
1154        reg[0] = VMK8061_PWM_REG1;
1155        reg[1] = VMK8061_PWM_REG2;
1156
1157        cmd = VMK8061_CMD_OUT_PWM;
1158
1159        /*
1160         * The followin piece of code was translated from the inline
1161         * assembler code in the DLL source code.
1162         *
1163         * asm
1164         *   mov eax, k  ; k is the value (data[n])
1165         *   and al, 03h ; al are the lower 8 bits of eax
1166         *   mov lo, al  ; lo is the low part (tx_buf[reg[0]])
1167         *   mov eax, k
1168         *   shr eax, 2  ; right shift eax register by 2
1169         *   mov hi, al  ; hi is the high part (tx_buf[reg[1]])
1170         * end;
1171         */
1172        for (n = 0; n < insn->n; n++) {
1173                tx_buf[reg[0]] = (unsigned char)(data[n] & 0x03);
1174                tx_buf[reg[1]] = (unsigned char)(data[n] >> 2) & 0xff;
1175
1176                if (vmk80xx_write_packet(dev, cmd))
1177                        break;
1178        }
1179
1180        up(&dev->limit_sem);
1181
1182        return n;
1183}
1184
1185static int vmk80xx_attach(struct comedi_device *cdev,
1186                          struct comedi_devconfig *it)
1187{
1188        int i;
1189        struct vmk80xx_usb *dev;
1190        int n_subd;
1191        struct comedi_subdevice *s;
1192        int minor;
1193
1194        dbgvm("vmk80xx: %s\n", __func__);
1195
1196        mutex_lock(&glb_mutex);
1197
1198        for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
1199                if (vmb[i].probed && !vmb[i].attached)
1200                        break;
1201
1202        if (i == VMK80XX_MAX_BOARDS) {
1203                mutex_unlock(&glb_mutex);
1204                return -ENODEV;
1205        }
1206
1207        dev = &vmb[i];
1208
1209        down(&dev->limit_sem);
1210
1211        cdev->board_name = dev->board.name;
1212        cdev->private = dev;
1213
1214        if (dev->board.model == VMK8055_MODEL)
1215                n_subd = 5;
1216        else
1217                n_subd = 6;
1218
1219        if (alloc_subdevices(cdev, n_subd) < 0) {
1220                up(&dev->limit_sem);
1221                mutex_unlock(&glb_mutex);
1222                return -ENOMEM;
1223        }
1224
1225        /* Analog input subdevice */
1226        s = cdev->subdevices + VMK80XX_SUBD_AI;
1227        s->type = COMEDI_SUBD_AI;
1228        s->subdev_flags = SDF_READABLE | SDF_GROUND;
1229        s->n_chan = dev->board.ai_chans;
1230        s->maxdata = (1 << dev->board.ai_bits) - 1;
1231        s->range_table = dev->board.range;
1232        s->insn_read = vmk80xx_ai_rinsn;
1233
1234        /* Analog output subdevice */
1235        s = cdev->subdevices + VMK80XX_SUBD_AO;
1236        s->type = COMEDI_SUBD_AO;
1237        s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
1238        s->n_chan = dev->board.ao_chans;
1239        s->maxdata = (1 << dev->board.ao_bits) - 1;
1240        s->range_table = dev->board.range;
1241        s->insn_write = vmk80xx_ao_winsn;
1242
1243        if (dev->board.model == VMK8061_MODEL) {
1244                s->subdev_flags |= SDF_READABLE;
1245                s->insn_read = vmk80xx_ao_rinsn;
1246        }
1247
1248        /* Digital input subdevice */
1249        s = cdev->subdevices + VMK80XX_SUBD_DI;
1250        s->type = COMEDI_SUBD_DI;
1251        s->subdev_flags = SDF_READABLE | SDF_GROUND;
1252        s->n_chan = dev->board.di_chans;
1253        s->maxdata = 1;
1254        s->insn_read = vmk80xx_di_rinsn;
1255        s->insn_bits = vmk80xx_di_bits;
1256
1257        /* Digital output subdevice */
1258        s = cdev->subdevices + VMK80XX_SUBD_DO;
1259        s->type = COMEDI_SUBD_DO;
1260        s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
1261        s->n_chan = dev->board.do_chans;
1262        s->maxdata = 1;
1263        s->insn_write = vmk80xx_do_winsn;
1264        s->insn_bits = vmk80xx_do_bits;
1265
1266        if (dev->board.model == VMK8061_MODEL) {
1267                s->subdev_flags |= SDF_READABLE;
1268                s->insn_read = vmk80xx_do_rinsn;
1269        }
1270
1271        /* Counter subdevice */
1272        s = cdev->subdevices + VMK80XX_SUBD_CNT;
1273        s->type = COMEDI_SUBD_COUNTER;
1274        s->subdev_flags = SDF_READABLE;
1275        s->n_chan = dev->board.cnt_chans;
1276        s->insn_read = vmk80xx_cnt_rinsn;
1277        s->insn_config = vmk80xx_cnt_cinsn;
1278
1279        if (dev->board.model == VMK8055_MODEL) {
1280                s->subdev_flags |= SDF_WRITEABLE;
1281                s->maxdata = (1 << dev->board.cnt_bits) - 1;
1282                s->insn_write = vmk80xx_cnt_winsn;
1283        }
1284
1285        /* PWM subdevice */
1286        if (dev->board.model == VMK8061_MODEL) {
1287                s = cdev->subdevices + VMK80XX_SUBD_PWM;
1288                s->type = COMEDI_SUBD_PWM;
1289                s->subdev_flags = SDF_READABLE | SDF_WRITEABLE;
1290                s->n_chan = dev->board.pwm_chans;
1291                s->maxdata = (1 << dev->board.pwm_bits) - 1;
1292                s->insn_read = vmk80xx_pwm_rinsn;
1293                s->insn_write = vmk80xx_pwm_winsn;
1294        }
1295
1296        dev->attached = 1;
1297
1298        minor = cdev->minor;
1299
1300        printk(KERN_INFO
1301               "comedi%d: vmk80xx: board #%d [%s] attached to comedi\n",
1302               minor, dev->count, dev->board.name);
1303
1304        up(&dev->limit_sem);
1305        mutex_unlock(&glb_mutex);
1306
1307        return 0;
1308}
1309
1310static int vmk80xx_detach(struct comedi_device *cdev)
1311{
1312        struct vmk80xx_usb *dev;
1313        int minor;
1314
1315        dbgvm("vmk80xx: %s\n", __func__);
1316
1317        if (!cdev)
1318                return -EFAULT;
1319
1320        dev = cdev->private;
1321        if (!dev)
1322                return -EFAULT;
1323
1324        down(&dev->limit_sem);
1325
1326        cdev->private = NULL;
1327        dev->attached = 0;
1328
1329        minor = cdev->minor;
1330
1331        printk(KERN_INFO
1332               "comedi%d: vmk80xx: board #%d [%s] detached from comedi\n",
1333               minor, dev->count, dev->board.name);
1334
1335        up(&dev->limit_sem);
1336
1337        return 0;
1338}
1339
1340static int vmk80xx_probe(struct usb_interface *intf,
1341                         const struct usb_device_id *id)
1342{
1343        int i;
1344        struct vmk80xx_usb *dev;
1345        struct usb_host_interface *iface_desc;
1346        struct usb_endpoint_descriptor *ep_desc;
1347        size_t size;
1348
1349        dbgvm("vmk80xx: %s\n", __func__);
1350
1351        mutex_lock(&glb_mutex);
1352
1353        for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
1354                if (!vmb[i].probed)
1355                        break;
1356
1357        if (i == VMK80XX_MAX_BOARDS) {
1358                mutex_unlock(&glb_mutex);
1359                return -EMFILE;
1360        }
1361
1362        dev = &vmb[i];
1363
1364        memset(dev, 0x00, sizeof(struct vmk80xx_usb));
1365        dev->count = i;
1366
1367        iface_desc = intf->cur_altsetting;
1368        if (iface_desc->desc.bNumEndpoints != 2)
1369                goto error;
1370
1371        for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
1372                ep_desc = &iface_desc->endpoint[i].desc;
1373
1374                if (usb_endpoint_is_int_in(ep_desc)) {
1375                        dev->ep_rx = ep_desc;
1376                        continue;
1377                }
1378
1379                if (usb_endpoint_is_int_out(ep_desc)) {
1380                        dev->ep_tx = ep_desc;
1381                        continue;
1382                }
1383
1384                if (usb_endpoint_is_bulk_in(ep_desc)) {
1385                        dev->ep_rx = ep_desc;
1386                        continue;
1387                }
1388
1389                if (usb_endpoint_is_bulk_out(ep_desc)) {
1390                        dev->ep_tx = ep_desc;
1391                        continue;
1392                }
1393        }
1394
1395        if (!dev->ep_rx || !dev->ep_tx)
1396                goto error;
1397
1398        size = le16_to_cpu(dev->ep_rx->wMaxPacketSize);
1399        dev->usb_rx_buf = kmalloc(size, GFP_KERNEL);
1400        if (!dev->usb_rx_buf) {
1401                mutex_unlock(&glb_mutex);
1402                return -ENOMEM;
1403        }
1404
1405        size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
1406        dev->usb_tx_buf = kmalloc(size, GFP_KERNEL);
1407        if (!dev->usb_tx_buf) {
1408                kfree(dev->usb_rx_buf);
1409                mutex_unlock(&glb_mutex);
1410                return -ENOMEM;
1411        }
1412
1413        dev->udev = interface_to_usbdev(intf);
1414        dev->intf = intf;
1415
1416        sema_init(&dev->limit_sem, 8);
1417        init_waitqueue_head(&dev->read_wait);
1418        init_waitqueue_head(&dev->write_wait);
1419
1420        init_usb_anchor(&dev->rx_anchor);
1421        init_usb_anchor(&dev->tx_anchor);
1422
1423        usb_set_intfdata(intf, dev);
1424
1425        switch (id->driver_info) {
1426        case DEVICE_VMK8055:
1427                dev->board.name = "K8055 (VM110)";
1428                dev->board.model = VMK8055_MODEL;
1429                dev->board.range = &vmk8055_range;
1430                dev->board.ai_chans = 2;
1431                dev->board.ai_bits = 8;
1432                dev->board.ao_chans = 2;
1433                dev->board.ao_bits = 8;
1434                dev->board.di_chans = 5;
1435                dev->board.di_bits = 1;
1436                dev->board.do_chans = 8;
1437                dev->board.do_bits = 1;
1438                dev->board.cnt_chans = 2;
1439                dev->board.cnt_bits = 16;
1440                dev->board.pwm_chans = 0;
1441                dev->board.pwm_bits = 0;
1442                break;
1443        case DEVICE_VMK8061:
1444                dev->board.name = "K8061 (VM140)";
1445                dev->board.model = VMK8061_MODEL;
1446                dev->board.range = &vmk8061_range;
1447                dev->board.ai_chans = 8;
1448                dev->board.ai_bits = 10;
1449                dev->board.ao_chans = 8;
1450                dev->board.ao_bits = 8;
1451                dev->board.di_chans = 8;
1452                dev->board.di_bits = 1;
1453                dev->board.do_chans = 8;
1454                dev->board.do_bits = 1;
1455                dev->board.cnt_chans = 2;
1456                dev->board.cnt_bits = 0;
1457                dev->board.pwm_chans = 1;
1458                dev->board.pwm_bits = 10;
1459                break;
1460        }
1461
1462        if (dev->board.model == VMK8061_MODEL) {
1463                vmk80xx_read_eeprom(dev, IC3_VERSION);
1464                printk(KERN_INFO "comedi#: vmk80xx: %s\n", dev->fw.ic3_vers);
1465
1466                if (vmk80xx_check_data_link(dev)) {
1467                        vmk80xx_read_eeprom(dev, IC6_VERSION);
1468                        printk(KERN_INFO "comedi#: vmk80xx: %s\n",
1469                               dev->fw.ic6_vers);
1470                } else {
1471                        dbgcm("comedi#: vmk80xx: no conn. to CPU\n");
1472                }
1473        }
1474
1475        if (dev->board.model == VMK8055_MODEL)
1476                vmk80xx_reset_device(dev);
1477
1478        dev->probed = 1;
1479
1480        printk(KERN_INFO "comedi#: vmk80xx: board #%d [%s] now attached\n",
1481               dev->count, dev->board.name);
1482
1483        mutex_unlock(&glb_mutex);
1484
1485        comedi_usb_auto_config(dev->udev, BOARDNAME);
1486
1487        return 0;
1488error:
1489        mutex_unlock(&glb_mutex);
1490
1491        return -ENODEV;
1492}
1493
1494static void vmk80xx_disconnect(struct usb_interface *intf)
1495{
1496        struct vmk80xx_usb *dev = usb_get_intfdata(intf);
1497
1498        dbgvm("vmk80xx: %s\n", __func__);
1499
1500        if (!dev)
1501                return;
1502
1503        comedi_usb_auto_unconfig(dev->udev);
1504
1505        mutex_lock(&glb_mutex);
1506        down(&dev->limit_sem);
1507
1508        dev->probed = 0;
1509        usb_set_intfdata(dev->intf, NULL);
1510
1511        usb_kill_anchored_urbs(&dev->rx_anchor);
1512        usb_kill_anchored_urbs(&dev->tx_anchor);
1513
1514        kfree(dev->usb_rx_buf);
1515        kfree(dev->usb_tx_buf);
1516
1517        printk(KERN_INFO "comedi#: vmk80xx: board #%d [%s] now detached\n",
1518               dev->count, dev->board.name);
1519
1520        up(&dev->limit_sem);
1521        mutex_unlock(&glb_mutex);
1522}
1523
1524/* TODO: Add support for suspend, resume, pre_reset,
1525 * post_reset and flush */
1526static struct usb_driver vmk80xx_driver = {
1527        .name = "vmk80xx",
1528        .probe = vmk80xx_probe,
1529        .disconnect = vmk80xx_disconnect,
1530        .id_table = vmk80xx_id_table
1531};
1532
1533static struct comedi_driver driver_vmk80xx = {
1534        .module = THIS_MODULE,
1535        .driver_name = "vmk80xx",
1536        .attach = vmk80xx_attach,
1537        .detach = vmk80xx_detach
1538};
1539
1540static int __init vmk80xx_init(void)
1541{
1542        int retval;
1543
1544        printk(KERN_INFO "vmk80xx: version 0.8.01 "
1545               "Manuel Gebele <forensixs@gmx.de>\n");
1546
1547        retval = comedi_driver_register(&driver_vmk80xx);
1548        if (retval < 0)
1549                return retval;
1550
1551        return usb_register(&vmk80xx_driver);
1552}
1553
1554static void __exit vmk80xx_exit(void)
1555{
1556        comedi_driver_unregister(&driver_vmk80xx);
1557        usb_deregister(&vmk80xx_driver);
1558}
1559
1560module_init(vmk80xx_init);
1561module_exit(vmk80xx_exit);
1562