linux/drivers/staging/comedi/drivers/cb_pcimdas.c
<<
>>
Prefs
   1/*
   2    comedi/drivers/cb_pcimdas.c
   3    Comedi driver for Computer Boards PCIM-DAS1602/16
   4
   5    COMEDI - Linux Control and Measurement Device Interface
   6    Copyright (C) 2000 David A. Schleef <ds@schleef.org>
   7
   8    This program is free software; you can redistribute it and/or modify
   9    it under the terms of the GNU General Public License as published by
  10    the Free Software Foundation; either version 2 of the License, or
  11    (at your option) any later version.
  12
  13    This program is distributed in the hope that it will be useful,
  14    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16    GNU General Public License for more details.
  17
  18    You should have received a copy of the GNU General Public License
  19    along with this program; if not, write to the Free Software
  20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21
  22*/
  23/*
  24Driver: cb_pcimdas
  25Description: Measurement Computing PCI Migration series boards
  26Devices: [ComputerBoards] PCIM-DAS1602/16 (cb_pcimdas)
  27Author: Richard Bytheway
  28Updated: Wed, 13 Nov 2002 12:34:56 +0000
  29Status: experimental
  30
  31Written to support the PCIM-DAS1602/16 on a 2.4 series kernel.
  32
  33Configuration Options:
  34    [0] - PCI bus number
  35    [1] - PCI slot number
  36
  37Developed from cb_pcidas and skel by Richard Bytheway (mocelet@sucs.org).
  38Only supports DIO, AO and simple AI in it's present form.
  39No interrupts, multi channel or FIFO AI, although the card looks like it could support this.
  40See http://www.measurementcomputing.com/PDFManuals/pcim-das1602_16.pdf for more details.
  41*/
  42
  43#include "../comedidev.h"
  44
  45#include <linux/delay.h>
  46
  47#include "comedi_pci.h"
  48#include "plx9052.h"
  49#include "8255.h"
  50
  51//#define CBPCIMDAS_DEBUG
  52#undef CBPCIMDAS_DEBUG
  53
  54/* Registers for the PCIM-DAS1602/16 */
  55
  56// sizes of io regions (bytes)
  57#define BADR0_SIZE 2            //??
  58#define BADR1_SIZE 4
  59#define BADR2_SIZE 6
  60#define BADR3_SIZE 16
  61#define BADR4_SIZE 4
  62
  63//DAC Offsets
  64#define ADC_TRIG 0
  65#define DAC0_OFFSET 2
  66#define DAC1_OFFSET 4
  67
  68//AI and Counter Constants
  69#define MUX_LIMITS 0
  70#define MAIN_CONN_DIO 1
  71#define ADC_STAT 2
  72#define ADC_CONV_STAT 3
  73#define ADC_INT 4
  74#define ADC_PACER 5
  75#define BURST_MODE 6
  76#define PROG_GAIN 7
  77#define CLK8254_1_DATA 8
  78#define CLK8254_2_DATA 9
  79#define CLK8254_3_DATA 10
  80#define CLK8254_CONTROL 11
  81#define USER_COUNTER 12
  82#define RESID_COUNT_H 13
  83#define RESID_COUNT_L 14
  84
  85/* Board description */
  86struct cb_pcimdas_board {
  87        const char *name;
  88        unsigned short device_id;
  89        int ai_se_chans;        // Inputs in single-ended mode
  90        int ai_diff_chans;      // Inputs in differential mode
  91        int ai_bits;            // analog input resolution
  92        int ai_speed;           // fastest conversion period in ns
  93        int ao_nchan;           // number of analog out channels
  94        int ao_bits;            // analogue output resolution
  95        int has_ao_fifo;        // analog output has fifo
  96        int ao_scan_speed;      // analog output speed for 1602 series (for a scan, not conversion)
  97        int fifo_size;          // number of samples fifo can hold
  98        int dio_bits;           // number of dio bits
  99        int has_dio;            // has DIO
 100        const struct comedi_lrange *ranges;
 101};
 102
 103static const struct cb_pcimdas_board cb_pcimdas_boards[] = {
 104        {
 105              name:     "PCIM-DAS1602/16",
 106              device_id:0x56,
 107              ai_se_chans:16,
 108              ai_diff_chans:8,
 109              ai_bits:  16,
 110              ai_speed:10000,   //??
 111              ao_nchan:2,
 112              ao_bits:  12,
 113              has_ao_fifo:0,    //??
 114              ao_scan_speed:10000,
 115                        //??
 116              fifo_size:1024,
 117              dio_bits:24,
 118              has_dio:  1,
 119//              ranges:         &cb_pcimdas_ranges,
 120                },
 121};
 122
 123/* This is used by modprobe to translate PCI IDs to drivers.  Should
 124 * only be used for PCI and ISA-PnP devices */
 125static DEFINE_PCI_DEVICE_TABLE(cb_pcimdas_pci_table) = {
 126        {PCI_VENDOR_ID_COMPUTERBOARDS, 0x0056, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 127        {0}
 128};
 129
 130MODULE_DEVICE_TABLE(pci, cb_pcimdas_pci_table);
 131
 132#define N_BOARDS 1              // Max number of boards supported
 133
 134/*
 135 * Useful for shorthand access to the particular board structure
 136 */
 137#define thisboard ((const struct cb_pcimdas_board *)dev->board_ptr)
 138
 139/* this structure is for data unique to this hardware driver.  If
 140   several hardware drivers keep similar information in this structure,
 141   feel free to suggest moving the variable to the struct comedi_device struct.  */
 142struct cb_pcimdas_private {
 143        int data;
 144
 145        // would be useful for a PCI device
 146        struct pci_dev *pci_dev;
 147
 148        //base addresses
 149        unsigned long BADR0;
 150        unsigned long BADR1;
 151        unsigned long BADR2;
 152        unsigned long BADR3;
 153        unsigned long BADR4;
 154
 155        /* Used for AO readback */
 156        unsigned int ao_readback[2];
 157
 158        // Used for DIO
 159        unsigned short int port_a;      // copy of BADR4+0
 160        unsigned short int port_b;      // copy of BADR4+1
 161        unsigned short int port_c;      // copy of BADR4+2
 162        unsigned short int dio_mode;    // copy of BADR4+3
 163
 164};
 165
 166/*
 167 * most drivers define the following macro to make it easy to
 168 * access the private structure.
 169 */
 170#define devpriv ((struct cb_pcimdas_private *)dev->private)
 171
 172/*
 173 * The struct comedi_driver structure tells the Comedi core module
 174 * which functions to call to configure/deconfigure (attach/detach)
 175 * the board, and also about the kernel module that contains
 176 * the device code.
 177 */
 178static int cb_pcimdas_attach(struct comedi_device * dev, struct comedi_devconfig * it);
 179static int cb_pcimdas_detach(struct comedi_device * dev);
 180static struct comedi_driver driver_cb_pcimdas = {
 181      driver_name:"cb_pcimdas",
 182      module:THIS_MODULE,
 183      attach:cb_pcimdas_attach,
 184      detach:cb_pcimdas_detach,
 185};
 186
 187static int cb_pcimdas_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s,
 188        struct comedi_insn * insn, unsigned int * data);
 189static int cb_pcimdas_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s,
 190        struct comedi_insn * insn, unsigned int * data);
 191static int cb_pcimdas_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s,
 192        struct comedi_insn * insn, unsigned int * data);
 193
 194/*
 195 * Attach is called by the Comedi core to configure the driver
 196 * for a particular board.  If you specified a board_name array
 197 * in the driver structure, dev->board_ptr contains that
 198 * address.
 199 */
 200static int cb_pcimdas_attach(struct comedi_device * dev, struct comedi_devconfig * it)
 201{
 202        struct comedi_subdevice *s;
 203        struct pci_dev *pcidev;
 204        int index;
 205        //int i;
 206
 207        printk("comedi%d: cb_pcimdas: ", dev->minor);
 208
 209/*
 210 * Allocate the private structure area.
 211 */
 212        if (alloc_private(dev, sizeof(struct cb_pcimdas_private)) < 0)
 213                return -ENOMEM;
 214
 215/*
 216 * Probe the device to determine what device in the series it is.
 217 */
 218        printk("\n");
 219
 220        for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
 221                pcidev != NULL;
 222                pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
 223                // is it not a computer boards card?
 224                if (pcidev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS)
 225                        continue;
 226                // loop through cards supported by this driver
 227                for (index = 0; index < N_BOARDS; index++) {
 228                        if (cb_pcimdas_boards[index].device_id !=
 229                                pcidev->device)
 230                                continue;
 231                        // was a particular bus/slot requested?
 232                        if (it->options[0] || it->options[1]) {
 233                                // are we on the wrong bus/slot?
 234                                if (pcidev->bus->number != it->options[0] ||
 235                                        PCI_SLOT(pcidev->devfn) !=
 236                                        it->options[1]) {
 237                                        continue;
 238                                }
 239                        }
 240                        devpriv->pci_dev = pcidev;
 241                        dev->board_ptr = cb_pcimdas_boards + index;
 242                        goto found;
 243                }
 244        }
 245
 246        printk("No supported ComputerBoards/MeasurementComputing card found on "
 247                "requested position\n");
 248        return -EIO;
 249
 250      found:
 251
 252        printk("Found %s on bus %i, slot %i\n", cb_pcimdas_boards[index].name,
 253                pcidev->bus->number, PCI_SLOT(pcidev->devfn));
 254
 255        // Warn about non-tested features
 256        switch (thisboard->device_id) {
 257        case 0x56:
 258                break;
 259        default:
 260                printk("THIS CARD IS UNSUPPORTED.\n"
 261                        "PLEASE REPORT USAGE TO <mocelet@sucs.org>\n");
 262        };
 263
 264        if (comedi_pci_enable(pcidev, "cb_pcimdas")) {
 265                printk(" Failed to enable PCI device and request regions\n");
 266                return -EIO;
 267        }
 268
 269        devpriv->BADR0 = pci_resource_start(devpriv->pci_dev, 0);
 270        devpriv->BADR1 = pci_resource_start(devpriv->pci_dev, 1);
 271        devpriv->BADR2 = pci_resource_start(devpriv->pci_dev, 2);
 272        devpriv->BADR3 = pci_resource_start(devpriv->pci_dev, 3);
 273        devpriv->BADR4 = pci_resource_start(devpriv->pci_dev, 4);
 274
 275#ifdef CBPCIMDAS_DEBUG
 276        printk("devpriv->BADR0 = 0x%lx\n", devpriv->BADR0);
 277        printk("devpriv->BADR1 = 0x%lx\n", devpriv->BADR1);
 278        printk("devpriv->BADR2 = 0x%lx\n", devpriv->BADR2);
 279        printk("devpriv->BADR3 = 0x%lx\n", devpriv->BADR3);
 280        printk("devpriv->BADR4 = 0x%lx\n", devpriv->BADR4);
 281#endif
 282
 283// Dont support IRQ yet
 284//      // get irq
 285//      if(comedi_request_irq(devpriv->pci_dev->irq, cb_pcimdas_interrupt, IRQF_SHARED, "cb_pcimdas", dev ))
 286//      {
 287//              printk(" unable to allocate irq %u\n", devpriv->pci_dev->irq);
 288//              return -EINVAL;
 289//      }
 290//      dev->irq = devpriv->pci_dev->irq;
 291
 292        //Initialize dev->board_name
 293        dev->board_name = thisboard->name;
 294
 295/*
 296 * Allocate the subdevice structures.  alloc_subdevice() is a
 297 * convenient macro defined in comedidev.h.
 298 */
 299        if (alloc_subdevices(dev, 3) < 0)
 300                return -ENOMEM;
 301
 302        s = dev->subdevices + 0;
 303        //dev->read_subdev=s;
 304        // analog input subdevice
 305        s->type = COMEDI_SUBD_AI;
 306        s->subdev_flags = SDF_READABLE | SDF_GROUND;
 307        s->n_chan = thisboard->ai_se_chans;
 308        s->maxdata = (1 << thisboard->ai_bits) - 1;
 309        s->range_table = &range_unknown;
 310        s->len_chanlist = 1;    // This is the maximum chanlist length that
 311        // the board can handle
 312        s->insn_read = cb_pcimdas_ai_rinsn;
 313
 314        s = dev->subdevices + 1;
 315        // analog output subdevice
 316        s->type = COMEDI_SUBD_AO;
 317        s->subdev_flags = SDF_WRITABLE;
 318        s->n_chan = thisboard->ao_nchan;
 319        s->maxdata = 1 << thisboard->ao_bits;
 320        s->range_table = &range_unknown;        //ranges are hardware settable, but not software readable.
 321        s->insn_write = &cb_pcimdas_ao_winsn;
 322        s->insn_read = &cb_pcimdas_ao_rinsn;
 323
 324        s = dev->subdevices + 2;
 325        /* digital i/o subdevice */
 326        if (thisboard->has_dio) {
 327                subdev_8255_init(dev, s, NULL, devpriv->BADR4);
 328        } else {
 329                s->type = COMEDI_SUBD_UNUSED;
 330        }
 331
 332        printk("attached\n");
 333
 334        return 1;
 335}
 336
 337/*
 338 * _detach is called to deconfigure a device.  It should deallocate
 339 * resources.
 340 * This function is also called when _attach() fails, so it should be
 341 * careful not to release resources that were not necessarily
 342 * allocated by _attach().  dev->private and dev->subdevices are
 343 * deallocated automatically by the core.
 344 */
 345static int cb_pcimdas_detach(struct comedi_device * dev)
 346{
 347#ifdef CBPCIMDAS_DEBUG
 348        if (devpriv) {
 349                printk("devpriv->BADR0 = 0x%lx\n", devpriv->BADR0);
 350                printk("devpriv->BADR1 = 0x%lx\n", devpriv->BADR1);
 351                printk("devpriv->BADR2 = 0x%lx\n", devpriv->BADR2);
 352                printk("devpriv->BADR3 = 0x%lx\n", devpriv->BADR3);
 353                printk("devpriv->BADR4 = 0x%lx\n", devpriv->BADR4);
 354        }
 355#endif
 356        printk("comedi%d: cb_pcimdas: remove\n", dev->minor);
 357        if (dev->irq)
 358                comedi_free_irq(dev->irq, dev);
 359        if (devpriv) {
 360                if (devpriv->pci_dev) {
 361                        if (devpriv->BADR0) {
 362                                comedi_pci_disable(devpriv->pci_dev);
 363                        }
 364                        pci_dev_put(devpriv->pci_dev);
 365                }
 366        }
 367
 368        return 0;
 369}
 370
 371/*
 372 * "instructions" read/write data in "one-shot" or "software-triggered"
 373 * mode.
 374 */
 375static int cb_pcimdas_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s,
 376        struct comedi_insn * insn, unsigned int * data)
 377{
 378        int n, i;
 379        unsigned int d;
 380        unsigned int busy;
 381        int chan = CR_CHAN(insn->chanspec);
 382        unsigned short chanlims;
 383        int maxchans;
 384
 385        // only support sw initiated reads from a single channel
 386
 387        //check channel number
 388        if ((inb(devpriv->BADR3 + 2) & 0x20) == 0)      //differential mode
 389                maxchans = thisboard->ai_diff_chans;
 390        else
 391                maxchans = thisboard->ai_se_chans;
 392
 393        if (chan > (maxchans - 1))
 394                return -ETIMEDOUT;      //*** Wrong error code. Fixme.
 395
 396        //configure for sw initiated read
 397        d = inb(devpriv->BADR3 + 5);
 398        if ((d & 0x03) > 0) {   //only reset if needed.
 399                d = d & 0xfd;
 400                outb(d, devpriv->BADR3 + 5);
 401        }
 402        outb(0x01, devpriv->BADR3 + 6); //set bursting off, conversions on
 403        outb(0x00, devpriv->BADR3 + 7); //set range to 10V. UP/BP is controlled by a switch on the board
 404
 405        // write channel limits to multiplexer, set Low (bits 0-3) and High (bits 4-7) channels to chan.
 406        chanlims = chan | (chan << 4);
 407        outb(chanlims, devpriv->BADR3 + 0);
 408
 409        /* convert n samples */
 410        for (n = 0; n < insn->n; n++) {
 411                /* trigger conversion */
 412                outw(0, devpriv->BADR2 + 0);
 413
 414#define TIMEOUT 1000            //typically takes 5 loops on a lightly loaded Pentium 100MHz,
 415                //this is likely to be 100 loops on a 2GHz machine, so set 1000 as the limit.
 416
 417                /* wait for conversion to end */
 418                for (i = 0; i < TIMEOUT; i++) {
 419                        busy = inb(devpriv->BADR3 + 2) & 0x80;
 420                        if (!busy)
 421                                break;
 422                }
 423                if (i == TIMEOUT) {
 424                        printk("timeout\n");
 425                        return -ETIMEDOUT;
 426                }
 427                /* read data */
 428                d = inw(devpriv->BADR2 + 0);
 429
 430                /* mangle the data as necessary */
 431                //d ^= 1<<(thisboard->ai_bits-1); // 16 bit data from ADC, so no mangle needed.
 432
 433                data[n] = d;
 434        }
 435
 436        /* return the number of samples read/written */
 437        return n;
 438}
 439
 440static int cb_pcimdas_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s,
 441        struct comedi_insn * insn, unsigned int * data)
 442{
 443        int i;
 444        int chan = CR_CHAN(insn->chanspec);
 445
 446        /* Writing a list of values to an AO channel is probably not
 447         * very useful, but that's how the interface is defined. */
 448        for (i = 0; i < insn->n; i++) {
 449                switch (chan) {
 450                case 0:
 451                        outw(data[i] & 0x0FFF, devpriv->BADR2 + DAC0_OFFSET);
 452                        break;
 453                case 1:
 454                        outw(data[i] & 0x0FFF, devpriv->BADR2 + DAC1_OFFSET);
 455                        break;
 456                default:
 457                        return -1;
 458                }
 459                devpriv->ao_readback[chan] = data[i];
 460        }
 461
 462        /* return the number of samples read/written */
 463        return i;
 464}
 465
 466/* AO subdevices should have a read insn as well as a write insn.
 467 * Usually this means copying a value stored in devpriv. */
 468static int cb_pcimdas_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s,
 469        struct comedi_insn * insn, unsigned int * data)
 470{
 471        int i;
 472        int chan = CR_CHAN(insn->chanspec);
 473
 474        for (i = 0; i < insn->n; i++)
 475                data[i] = devpriv->ao_readback[chan];
 476
 477        return i;
 478}
 479
 480/*
 481 * A convenient macro that defines init_module() and cleanup_module(),
 482 * as necessary.
 483 */
 484COMEDI_PCI_INITCLEANUP(driver_cb_pcimdas, cb_pcimdas_pci_table);
 485
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.