linux/drivers/staging/comedi/drivers/cb_pcimdda.c
<<
>>
Prefs
   1/*
   2    comedi/drivers/cb_pcimdda.c
   3    Computer Boards PCIM-DDA06-16 Comedi driver
   4    Author: Calin Culianu <calin@ajvar.org>
   5
   6    COMEDI - Linux Control and Measurement Device Interface
   7    Copyright (C) 2000 David A. Schleef <ds@schleef.org>
   8
   9    This program is free software; you can redistribute it and/or modify
  10    it under the terms of the GNU General Public License as published by
  11    the Free Software Foundation; either version 2 of the License, or
  12    (at your option) any later version.
  13
  14    This program is distributed in the hope that it will be useful,
  15    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17    GNU General Public License for more details.
  18*/
  19/*
  20Driver: cb_pcimdda
  21Description: Measurement Computing PCIM-DDA06-16
  22Devices: [Measurement Computing] PCIM-DDA06-16 (cb_pcimdda)
  23Author: Calin Culianu <calin@ajvar.org>
  24Updated: Mon, 14 Apr 2008 15:15:51 +0100
  25Status: works
  26
  27All features of the PCIM-DDA06-16 board are supported.  This board
  28has 6 16-bit AO channels, and the usual 8255 DIO setup.  (24 channels,
  29configurable in banks of 8 and 4, etc.).  This board does not support commands.
  30
  31The board has a peculiar way of specifying AO gain/range settings -- You have
  321 jumper bank on the card, which either makes all 6 AO channels either
  335 Volt unipolar, 5V bipolar, 10 Volt unipolar or 10V bipolar.
  34
  35Since there is absolutely _no_ way to tell in software how this jumper is set
  36(well, at least according  to the rather thin spec. from Measurement Computing
  37 that comes with the board), the driver assumes the jumper is at its factory
  38default setting of +/-5V.
  39
  40Also of note is the fact that this board features another jumper, whose
  41state is also completely invisible to software.  It toggles two possible AO
  42output modes on the board:
  43
  44  - Update Mode: Writing to an AO channel instantaneously updates the actual
  45    signal output by the DAC on the board (this is the factory default).
  46  - Simultaneous XFER Mode: Writing to an AO channel has no effect until
  47    you read from any one of the AO channels.  This is useful for loading
  48    all 6 AO values, and then reading from any one of the AO channels on the
  49    device to instantly update all 6 AO values in unison.  Useful for some
  50    control apps, I would assume?  If your jumper is in this setting, then you
  51    need to issue your comedi_data_write()s to load all the values you want,
  52    then issue one comedi_data_read() on any channel on the AO subdevice
  53    to initiate the simultaneous XFER.
  54
  55Configuration Options: not applicable, uses PCI auto config
  56*/
  57
  58/*
  59    This is a driver for the Computer Boards PCIM-DDA06-16 Analog Output
  60    card.  This board has a unique register layout and as such probably
  61    deserves its own driver file.
  62
  63    It is theoretically possible to integrate this board into the cb_pcidda
  64    file, but since that isn't my code, I didn't want to significantly
  65    modify that file to support this board (I thought it impolite to do so).
  66
  67    At any rate, if you feel ambitious, please feel free to take
  68    the code out of this file and combine it with a more unified driver
  69    file.
  70
  71    I would like to thank Timothy Curry <Timothy.Curry@rdec.redstone.army.mil>
  72    for lending me a board so that I could write this driver.
  73
  74    -Calin Culianu <calin@ajvar.org>
  75 */
  76
  77#include <linux/module.h>
  78#include <linux/pci.h>
  79
  80#include "../comedidev.h"
  81
  82#include "8255.h"
  83
  84/* device ids of the cards we support -- currently only 1 card supported */
  85#define PCI_ID_PCIM_DDA06_16            0x0053
  86
  87/*
  88 * Register map, 8-bit access only
  89 */
  90#define PCIMDDA_DA_CHAN(x)              (0x00 + (x) * 2)
  91#define PCIMDDA_8255_BASE_REG           0x0c
  92
  93static int cb_pcimdda_ao_insn_write(struct comedi_device *dev,
  94                                    struct comedi_subdevice *s,
  95                                    struct comedi_insn *insn,
  96                                    unsigned int *data)
  97{
  98        unsigned int chan = CR_CHAN(insn->chanspec);
  99        unsigned long offset = dev->iobase + PCIMDDA_DA_CHAN(chan);
 100        unsigned int val = s->readback[chan];
 101        int i;
 102
 103        for (i = 0; i < insn->n; i++) {
 104                val = data[i];
 105
 106                /*
 107                 * Write the LSB then MSB.
 108                 *
 109                 * If the simultaneous xfer mode is selected by the
 110                 * jumper on the card, a read instruction is needed
 111                 * in order to initiate the simultaneous transfer.
 112                 * Otherwise, the DAC will be updated when the MSB
 113                 * is written.
 114                 */
 115                outb(val & 0x00ff, offset);
 116                outb((val >> 8) & 0x00ff, offset + 1);
 117        }
 118        s->readback[chan] = val;
 119
 120        return insn->n;
 121}
 122
 123static int cb_pcimdda_ao_insn_read(struct comedi_device *dev,
 124                                   struct comedi_subdevice *s,
 125                                   struct comedi_insn *insn,
 126                                   unsigned int *data)
 127{
 128        unsigned int chan = CR_CHAN(insn->chanspec);
 129
 130        /* Initiate the simultaneous transfer */
 131        inw(dev->iobase + PCIMDDA_DA_CHAN(chan));
 132
 133        return comedi_readback_insn_read(dev, s, insn, data);
 134}
 135
 136static int cb_pcimdda_auto_attach(struct comedi_device *dev,
 137                                            unsigned long context_unused)
 138{
 139        struct pci_dev *pcidev = comedi_to_pci_dev(dev);
 140        struct comedi_subdevice *s;
 141        int ret;
 142
 143        ret = comedi_pci_enable(dev);
 144        if (ret)
 145                return ret;
 146        dev->iobase = pci_resource_start(pcidev, 3);
 147
 148        ret = comedi_alloc_subdevices(dev, 2);
 149        if (ret)
 150                return ret;
 151
 152        s = &dev->subdevices[0];
 153        /* analog output subdevice */
 154        s->type         = COMEDI_SUBD_AO;
 155        s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
 156        s->n_chan       = 6;
 157        s->maxdata      = 0xffff;
 158        s->range_table  = &range_bipolar5;
 159        s->insn_write   = cb_pcimdda_ao_insn_write;
 160        s->insn_read    = cb_pcimdda_ao_insn_read;
 161
 162        ret = comedi_alloc_subdev_readback(s);
 163        if (ret)
 164                return ret;
 165
 166        s = &dev->subdevices[1];
 167        /* digital i/o subdevice */
 168        ret = subdev_8255_init(dev, s, NULL, PCIMDDA_8255_BASE_REG);
 169        if (ret)
 170                return ret;
 171
 172        return 0;
 173}
 174
 175static struct comedi_driver cb_pcimdda_driver = {
 176        .driver_name    = "cb_pcimdda",
 177        .module         = THIS_MODULE,
 178        .auto_attach    = cb_pcimdda_auto_attach,
 179        .detach         = comedi_pci_detach,
 180};
 181
 182static int cb_pcimdda_pci_probe(struct pci_dev *dev,
 183                                const struct pci_device_id *id)
 184{
 185        return comedi_pci_auto_config(dev, &cb_pcimdda_driver,
 186                                      id->driver_data);
 187}
 188
 189static const struct pci_device_id cb_pcimdda_pci_table[] = {
 190        { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_ID_PCIM_DDA06_16) },
 191        { 0 }
 192};
 193MODULE_DEVICE_TABLE(pci, cb_pcimdda_pci_table);
 194
 195static struct pci_driver cb_pcimdda_driver_pci_driver = {
 196        .name           = "cb_pcimdda",
 197        .id_table       = cb_pcimdda_pci_table,
 198        .probe          = cb_pcimdda_pci_probe,
 199        .remove         = comedi_pci_auto_unconfig,
 200};
 201module_comedi_pci_driver(cb_pcimdda_driver, cb_pcimdda_driver_pci_driver);
 202
 203MODULE_AUTHOR("Calin A. Culianu <calin@rtlab.org>");
 204MODULE_DESCRIPTION("Comedi low-level driver for the Computerboards PCIM-DDA "
 205                   "series.  Currently only supports PCIM-DDA06-16 (which "
 206                   "also happens to be the only board in this series. :) ) ");
 207MODULE_LICENSE("GPL");
 208
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.