linux/drivers/staging/comedi/drivers/pcmmio.c
<<
>>
Prefs
   1/*
   2    comedi/drivers/pcmmio.c
   3    Driver for Winsystems PC-104 based multifunction IO board.
   4
   5    COMEDI - Linux Control and Measurement Device Interface
   6    Copyright (C) 2007 Calin A. Culianu <calin@ajvar.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/*
  23Driver: pcmmio
  24Description: A driver for the PCM-MIO multifunction board
  25Devices: [Winsystems] PCM-MIO (pcmmio)
  26Author: Calin Culianu <calin@ajvar.org>
  27Updated: Wed, May 16 2007 16:21:10 -0500
  28Status: works
  29
  30A driver for the relatively new PCM-MIO multifunction board from
  31Winsystems.  This board is a PC-104 based I/O board.  It contains
  32four subdevices:
  33  subdevice 0 - 16 channels of 16-bit AI
  34  subdevice 1 - 8 channels of 16-bit AO
  35  subdevice 2 - first 24 channels of the 48 channel of DIO
  36        (with edge-triggered interrupt support)
  37  subdevice 3 - last 24 channels of the 48 channel DIO
  38        (no interrupt support for this bank of channels)
  39
  40  Some notes:
  41
  42  Synchronous reads and writes are the only things implemented for AI and AO,
  43  even though the hardware itself can do streaming acquisition, etc.  Anyone
  44  want to add asynchronous I/O for AI/AO as a feature?  Be my guest...
  45
  46  Asynchronous I/O for the DIO subdevices *is* implemented, however!  They are
  47  basically edge-triggered interrupts for any configuration of the first
  48  24 DIO-lines.
  49
  50  Also note that this interrupt support is untested.
  51
  52  A few words about edge-detection IRQ support (commands on DIO):
  53
  54  * To use edge-detection IRQ support for the DIO subdevice, pass the IRQ
  55    of the board to the comedi_config command.  The board IRQ is not jumpered
  56    but rather configured through software, so any IRQ from 1-15 is OK.
  57
  58  * Due to the genericity of the comedi API, you need to create a special
  59    comedi_command in order to use edge-triggered interrupts for DIO.
  60
  61  * Use comedi_commands with TRIG_NOW.  Your callback will be called each
  62    time an edge is detected on the specified DIO line(s), and the data
  63    values will be two sample_t's, which should be concatenated to form
  64    one 32-bit unsigned int.  This value is the mask of channels that had
  65    edges detected from your channel list.  Note that the bits positions
  66    in the mask correspond to positions in your chanlist when you
  67    specified the command and *not* channel id's!
  68
  69 *  To set the polarity of the edge-detection interrupts pass a nonzero value
  70    for either CR_RANGE or CR_AREF for edge-up polarity, or a zero
  71    value for both CR_RANGE and CR_AREF if you want edge-down polarity.
  72
  73Configuration Options:
  74  [0] - I/O port base address
  75  [1] - IRQ (optional -- for edge-detect interrupt support only,
  76        leave out if you don't need this feature)
  77*/
  78
  79#include <linux/interrupt.h>
  80#include <linux/slab.h>
  81#include "../comedidev.h"
  82#include "pcm_common.h"
  83#include <linux/pci.h>          /* for PCI devices */
  84
  85/* This stuff is all from pcmuio.c -- it refers to the DIO subdevices only */
  86#define CHANS_PER_PORT   8
  87#define PORTS_PER_ASIC   6
  88#define INTR_PORTS_PER_ASIC   3
  89#define MAX_CHANS_PER_SUBDEV 24 /* number of channels per comedi subdevice */
  90#define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT)
  91#define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC)
  92#define INTR_CHANS_PER_ASIC 24
  93#define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT)
  94#define MAX_DIO_CHANS   (PORTS_PER_ASIC*1*CHANS_PER_PORT)
  95#define MAX_ASICS       (MAX_DIO_CHANS/CHANS_PER_ASIC)
  96#define SDEV_NO ((int)(s - dev->subdevices))
  97#define CALC_N_DIO_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/)
  98/* IO Memory sizes */
  99#define ASIC_IOSIZE (0x0B)
 100#define PCMMIO48_IOSIZE ASIC_IOSIZE
 101
 102/* Some offsets - these are all in the 16byte IO memory offset from
 103   the base address.  Note that there is a paging scheme to swap out
 104   offsets 0x8-0xA using the PAGELOCK register.  See the table below.
 105
 106  Register(s)       Pages        R/W?        Description
 107  --------------------------------------------------------------
 108  REG_PORTx         All          R/W         Read/Write/Configure IO
 109  REG_INT_PENDING   All          ReadOnly    Quickly see which INT_IDx has int.
 110  REG_PAGELOCK      All          WriteOnly   Select a page
 111  REG_POLx          Pg. 1 only   WriteOnly   Select edge-detection polarity
 112  REG_ENABx         Pg. 2 only   WriteOnly   Enable/Disable edge-detect. int.
 113  REG_INT_IDx       Pg. 3 only   R/W         See which ports/bits have ints.
 114 */
 115#define REG_PORT0 0x0
 116#define REG_PORT1 0x1
 117#define REG_PORT2 0x2
 118#define REG_PORT3 0x3
 119#define REG_PORT4 0x4
 120#define REG_PORT5 0x5
 121#define REG_INT_PENDING 0x6
 122#define REG_PAGELOCK 0x7        /*
 123                                 * page selector register, upper 2 bits select
 124                                 * a page and bits 0-5 are used to 'lock down'
 125                                 * a particular port above to make it readonly.
 126                                 */
 127#define REG_POL0 0x8
 128#define REG_POL1 0x9
 129#define REG_POL2 0xA
 130#define REG_ENAB0 0x8
 131#define REG_ENAB1 0x9
 132#define REG_ENAB2 0xA
 133#define REG_INT_ID0 0x8
 134#define REG_INT_ID1 0x9
 135#define REG_INT_ID2 0xA
 136
 137#define NUM_PAGED_REGS 3
 138#define NUM_PAGES 4
 139#define FIRST_PAGED_REG 0x8
 140#define REG_PAGE_BITOFFSET 6
 141#define REG_LOCK_BITOFFSET 0
 142#define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1))
 143#define REG_LOCK_MASK (~(REG_PAGE_MASK))
 144#define PAGE_POL 1
 145#define PAGE_ENAB 2
 146#define PAGE_INT_ID 3
 147
 148static int ai_rinsn(struct comedi_device *, struct comedi_subdevice *,
 149                    struct comedi_insn *, unsigned int *);
 150static int ao_rinsn(struct comedi_device *, struct comedi_subdevice *,
 151                    struct comedi_insn *, unsigned int *);
 152static int ao_winsn(struct comedi_device *, struct comedi_subdevice *,
 153                    struct comedi_insn *, unsigned int *);
 154
 155/*
 156 * Board descriptions for two imaginary boards.  Describing the
 157 * boards in this way is optional, and completely driver-dependent.
 158 * Some drivers use arrays such as this, other do not.
 159 */
 160struct pcmmio_board {
 161        const char *name;
 162        const int dio_num_asics;
 163        const int dio_num_ports;
 164        const int total_iosize;
 165        const int ai_bits;
 166        const int ao_bits;
 167        const int n_ai_chans;
 168        const int n_ao_chans;
 169        const struct comedi_lrange *ai_range_table, *ao_range_table;
 170        int (*ai_rinsn) (struct comedi_device *dev,
 171                        struct comedi_subdevice *s,
 172                        struct comedi_insn *insn,
 173                        unsigned int *data);
 174        int (*ao_rinsn) (struct comedi_device *dev,
 175                        struct comedi_subdevice *s,
 176                        struct comedi_insn *insn,
 177                        unsigned int *data);
 178        int (*ao_winsn) (struct comedi_device *dev,
 179                        struct comedi_subdevice *s,
 180                        struct comedi_insn *insn,
 181                        unsigned int *data);
 182};
 183
 184static const struct comedi_lrange ranges_ai = {
 185        4, {RANGE(-5., 5.), RANGE(-10., 10.), RANGE(0., 5.), RANGE(0., 10.)}
 186};
 187
 188static const struct comedi_lrange ranges_ao = {
 189        6, {RANGE(0., 5.), RANGE(0., 10.), RANGE(-5., 5.), RANGE(-10., 10.),
 190          RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)}
 191};
 192
 193static const struct pcmmio_board pcmmio_boards[] = {
 194        {
 195         .name = "pcmmio",
 196         .dio_num_asics = 1,
 197         .dio_num_ports = 6,
 198         .total_iosize = 32,
 199         .ai_bits = 16,
 200         .ao_bits = 16,
 201         .n_ai_chans = 16,
 202         .n_ao_chans = 8,
 203         .ai_range_table = &ranges_ai,
 204         .ao_range_table = &ranges_ao,
 205         .ai_rinsn = ai_rinsn,
 206         .ao_rinsn = ao_rinsn,
 207         .ao_winsn = ao_winsn},
 208};
 209
 210/*
 211 * Useful for shorthand access to the particular board structure
 212 */
 213#define thisboard ((const struct pcmmio_board *)dev->board_ptr)
 214
 215/* this structure is for data unique to this subdevice.  */
 216struct pcmmio_subdev_private {
 217
 218        union {
 219                /* for DIO: mapping of halfwords (bytes)
 220                   in port/chanarray to iobase */
 221                unsigned long iobases[PORTS_PER_SUBDEV];
 222
 223                /* for AI/AO */
 224                unsigned long iobase;
 225        };
 226        union {
 227                struct {
 228
 229                        /* The below is only used for intr subdevices */
 230                        struct {
 231                                /*
 232                                 * if non-negative, this subdev has an
 233                                 * interrupt asic
 234                                 */
 235                                int asic;
 236                                /*
 237                                 * if nonnegative, the first channel id for
 238                                 * interrupts.
 239                                 */
 240                                int first_chan;
 241                                /*
 242                                 * the number of asic channels in this subdev
 243                                 * that have interrutps
 244                                 */
 245                                int num_asic_chans;
 246                                /*
 247                                 * if nonnegative, the first channel id with
 248                                 * respect to the asic that has interrupts
 249                                 */
 250                                int asic_chan;
 251                                /*
 252                                 * subdev-relative channel mask for channels
 253                                 * we are interested in
 254                                 */
 255                                int enabled_mask;
 256                                int active;
 257                                int stop_count;
 258                                int continuous;
 259                                spinlock_t spinlock;
 260                        } intr;
 261                } dio;
 262                struct {
 263                        /* the last unsigned int data written */
 264                        unsigned int shadow_samples[8];
 265                } ao;
 266        };
 267};
 268
 269/*
 270 * this structure is for data unique to this hardware driver.  If
 271 * several hardware drivers keep similar information in this structure,
 272 * feel free to suggest moving the variable to the struct comedi_device struct.
 273 */
 274struct pcmmio_private {
 275        /* stuff for DIO */
 276        struct {
 277                unsigned char pagelock; /* current page and lock */
 278                /* shadow of POLx registers */
 279                unsigned char pol[NUM_PAGED_REGS];
 280                /* shadow of ENABx registers */
 281                unsigned char enab[NUM_PAGED_REGS];
 282                int num;
 283                unsigned long iobase;
 284                unsigned int irq;
 285                spinlock_t spinlock;
 286        } asics[MAX_ASICS];
 287        struct pcmmio_subdev_private *sprivs;
 288};
 289
 290/*
 291 * most drivers define the following macro to make it easy to
 292 * access the private structure.
 293 */
 294#define devpriv ((struct pcmmio_private *)dev->private)
 295#define subpriv ((struct pcmmio_subdev_private *)s->private)
 296/*
 297 * The struct comedi_driver structure tells the Comedi core module
 298 * which functions to call to configure/deconfigure (attach/detach)
 299 * the board, and also about the kernel module that contains
 300 * the device code.
 301 */
 302static int pcmmio_attach(struct comedi_device *dev,
 303                         struct comedi_devconfig *it);
 304static int pcmmio_detach(struct comedi_device *dev);
 305
 306static struct comedi_driver driver = {
 307        .driver_name = "pcmmio",
 308        .module = THIS_MODULE,
 309        .attach = pcmmio_attach,
 310        .detach = pcmmio_detach,
 311/* It is not necessary to implement the following members if you are
 312 * writing a driver for a ISA PnP or PCI card */
 313        /* Most drivers will support multiple types of boards by
 314         * having an array of board structures.  These were defined
 315         * in pcmmio_boards[] above.  Note that the element 'name'
 316         * was first in the structure -- Comedi uses this fact to
 317         * extract the name of the board without knowing any details
 318         * about the structure except for its length.
 319         * When a device is attached (by comedi_config), the name
 320         * of the device is given to Comedi, and Comedi tries to
 321         * match it by going through the list of board names.  If
 322         * there is a match, the address of the pointer is put
 323         * into dev->board_ptr and driver->attach() is called.
 324         *
 325         * Note that these are not necessary if you can determine
 326         * the type of board in software.  ISA PnP, PCI, and PCMCIA
 327         * devices are such boards.
 328         */
 329        .board_name = &pcmmio_boards[0].name,
 330        .offset = sizeof(struct pcmmio_board),
 331        .num_names = ARRAY_SIZE(pcmmio_boards),
 332};
 333
 334static int pcmmio_dio_insn_bits(struct comedi_device *dev,
 335                                struct comedi_subdevice *s,
 336                                struct comedi_insn *insn, unsigned int *data);
 337static int pcmmio_dio_insn_config(struct comedi_device *dev,
 338                                  struct comedi_subdevice *s,
 339                                  struct comedi_insn *insn, unsigned int *data);
 340
 341static irqreturn_t interrupt_pcmmio(int irq, void *d);
 342static void pcmmio_stop_intr(struct comedi_device *, struct comedi_subdevice *);
 343static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
 344static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
 345static int pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
 346                          struct comedi_cmd *cmd);
 347
 348/* some helper functions to deal with specifics of this device's registers */
 349/* sets up/clears ASIC chips to defaults */
 350static void init_asics(struct comedi_device *dev);
 351static void switch_page(struct comedi_device *dev, int asic, int page);
 352#ifdef notused
 353static void lock_port(struct comedi_device *dev, int asic, int port);
 354static void unlock_port(struct comedi_device *dev, int asic, int port);
 355#endif
 356
 357/*
 358 * Attach is called by the Comedi core to configure the driver
 359 * for a particular board.  If you specified a board_name array
 360 * in the driver structure, dev->board_ptr contains that
 361 * address.
 362 */
 363static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 364{
 365        struct comedi_subdevice *s;
 366        int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic,
 367            thisasic_chanct = 0;
 368        unsigned long iobase;
 369        unsigned int irq[MAX_ASICS];
 370
 371        iobase = it->options[0];
 372        irq[0] = it->options[1];
 373
 374        printk("comedi%d: %s: io: %lx ", dev->minor, driver.driver_name,
 375               iobase);
 376
 377        dev->iobase = iobase;
 378
 379        if (!iobase || !request_region(iobase,
 380                                       thisboard->total_iosize,
 381                                       driver.driver_name)) {
 382                printk("I/O port conflict\n");
 383                return -EIO;
 384        }
 385
 386/*
 387 * Initialize dev->board_name.  Note that we can use the "thisboard"
 388 * macro now, since we just initialized it in the last line.
 389 */
 390        dev->board_name = thisboard->name;
 391
 392/*
 393 * Allocate the private structure area.  alloc_private() is a
 394 * convenient macro defined in comedidev.h.
 395 */
 396        if (alloc_private(dev, sizeof(struct pcmmio_private)) < 0) {
 397                printk("cannot allocate private data structure\n");
 398                return -ENOMEM;
 399        }
 400
 401        for (asic = 0; asic < MAX_ASICS; ++asic) {
 402                devpriv->asics[asic].num = asic;
 403                devpriv->asics[asic].iobase =
 404                    dev->iobase + 16 + asic * ASIC_IOSIZE;
 405                /*
 406                 * this gets actually set at the end of this function when we
 407                 * request_irqs
 408                 */
 409                devpriv->asics[asic].irq = 0;
 410                spin_lock_init(&devpriv->asics[asic].spinlock);
 411        }
 412
 413        chans_left = CHANS_PER_ASIC * thisboard->dio_num_asics;
 414        n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left);
 415        n_subdevs = n_dio_subdevs + 2;
 416        devpriv->sprivs =
 417            kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private),
 418                    GFP_KERNEL);
 419        if (!devpriv->sprivs) {
 420                printk("cannot allocate subdevice private data structures\n");
 421                return -ENOMEM;
 422        }
 423        /*
 424         * Allocate the subdevice structures.  alloc_subdevice() is a
 425         * convenient macro defined in comedidev.h.
 426         *
 427         * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO)
 428         */
 429        if (alloc_subdevices(dev, n_subdevs) < 0) {
 430                printk("cannot allocate subdevice data structures\n");
 431                return -ENOMEM;
 432        }
 433
 434        /* First, AI */
 435        sdev_no = 0;
 436        s = dev->subdevices + sdev_no;
 437        s->private = devpriv->sprivs + sdev_no;
 438        s->maxdata = (1 << thisboard->ai_bits) - 1;
 439        s->range_table = thisboard->ai_range_table;
 440        s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
 441        s->type = COMEDI_SUBD_AI;
 442        s->n_chan = thisboard->n_ai_chans;
 443        s->len_chanlist = s->n_chan;
 444        s->insn_read = thisboard->ai_rinsn;
 445        subpriv->iobase = dev->iobase + 0;
 446        /* initialize the resource enable register by clearing it */
 447        outb(0, subpriv->iobase + 3);
 448        outb(0, subpriv->iobase + 4 + 3);
 449
 450        /* Next, AO */
 451        ++sdev_no;
 452        s = dev->subdevices + sdev_no;
 453        s->private = devpriv->sprivs + sdev_no;
 454        s->maxdata = (1 << thisboard->ao_bits) - 1;
 455        s->range_table = thisboard->ao_range_table;
 456        s->subdev_flags = SDF_READABLE;
 457        s->type = COMEDI_SUBD_AO;
 458        s->n_chan = thisboard->n_ao_chans;
 459        s->len_chanlist = s->n_chan;
 460        s->insn_read = thisboard->ao_rinsn;
 461        s->insn_write = thisboard->ao_winsn;
 462        subpriv->iobase = dev->iobase + 8;
 463        /* initialize the resource enable register by clearing it */
 464        outb(0, subpriv->iobase + 3);
 465        outb(0, subpriv->iobase + 4 + 3);
 466
 467        ++sdev_no;
 468        port = 0;
 469        asic = 0;
 470        for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
 471                int byte_no;
 472
 473                s = dev->subdevices + sdev_no;
 474                s->private = devpriv->sprivs + sdev_no;
 475                s->maxdata = 1;
 476                s->range_table = &range_digital;
 477                s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 478                s->type = COMEDI_SUBD_DIO;
 479                s->insn_bits = pcmmio_dio_insn_bits;
 480                s->insn_config = pcmmio_dio_insn_config;
 481                s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
 482                subpriv->dio.intr.asic = -1;
 483                subpriv->dio.intr.first_chan = -1;
 484                subpriv->dio.intr.asic_chan = -1;
 485                subpriv->dio.intr.num_asic_chans = -1;
 486                subpriv->dio.intr.active = 0;
 487                s->len_chanlist = 1;
 488
 489                /* save the ioport address for each 'port' of 8 channels in the
 490                   subdevice */
 491                for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
 492                        if (port >= PORTS_PER_ASIC) {
 493                                port = 0;
 494                                ++asic;
 495                                thisasic_chanct = 0;
 496                        }
 497                        subpriv->iobases[byte_no] =
 498                            devpriv->asics[asic].iobase + port;
 499
 500                        if (thisasic_chanct <
 501                            CHANS_PER_PORT * INTR_PORTS_PER_ASIC
 502                            && subpriv->dio.intr.asic < 0) {
 503                                /*
 504                                 * this is an interrupt subdevice,
 505                                 * so setup the struct
 506                                 */
 507                                subpriv->dio.intr.asic = asic;
 508                                subpriv->dio.intr.active = 0;
 509                                subpriv->dio.intr.stop_count = 0;
 510                                subpriv->dio.intr.first_chan = byte_no * 8;
 511                                subpriv->dio.intr.asic_chan = thisasic_chanct;
 512                                subpriv->dio.intr.num_asic_chans =
 513                                    s->n_chan - subpriv->dio.intr.first_chan;
 514                                s->cancel = pcmmio_cancel;
 515                                s->do_cmd = pcmmio_cmd;
 516                                s->do_cmdtest = pcmmio_cmdtest;
 517                                s->len_chanlist =
 518                                    subpriv->dio.intr.num_asic_chans;
 519                        }
 520                        thisasic_chanct += CHANS_PER_PORT;
 521                }
 522                spin_lock_init(&subpriv->dio.intr.spinlock);
 523
 524                chans_left -= s->n_chan;
 525
 526                if (!chans_left) {
 527                        /*
 528                         * reset the asic to our first asic,
 529                         * to do intr subdevs
 530                         */
 531                        asic = 0;
 532                        port = 0;
 533                }
 534
 535        }
 536
 537        init_asics(dev);        /* clear out all the registers, basically */
 538
 539        for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
 540                if (irq[asic]
 541                    && request_irq(irq[asic], interrupt_pcmmio,
 542                                   IRQF_SHARED, thisboard->name, dev)) {
 543                        int i;
 544                        /* unroll the allocated irqs.. */
 545                        for (i = asic - 1; i >= 0; --i) {
 546                                free_irq(irq[i], dev);
 547                                devpriv->asics[i].irq = irq[i] = 0;
 548                        }
 549                        irq[asic] = 0;
 550                }
 551                devpriv->asics[asic].irq = irq[asic];
 552        }
 553
 554        dev->irq = irq[0];      /*
 555                                 * grr.. wish comedi dev struct supported
 556                                 * multiple irqs..
 557                                 */
 558
 559        if (irq[0]) {
 560                printk("irq: %u ", irq[0]);
 561                if (thisboard->dio_num_asics == 2 && irq[1])
 562                        printk("second ASIC irq: %u ", irq[1]);
 563        } else {
 564                printk("(IRQ mode disabled) ");
 565        }
 566
 567        printk("attached\n");
 568
 569        return 1;
 570}
 571
 572/*
 573 * _detach is called to deconfigure a device.  It should deallocate
 574 * resources.
 575 * This function is also called when _attach() fails, so it should be
 576 * careful not to release resources that were not necessarily
 577 * allocated by _attach().  dev->private and dev->subdevices are
 578 * deallocated automatically by the core.
 579 */
 580static int pcmmio_detach(struct comedi_device *dev)
 581{
 582        int i;
 583
 584        printk("comedi%d: %s: remove\n", dev->minor, driver.driver_name);
 585        if (dev->iobase)
 586                release_region(dev->iobase, thisboard->total_iosize);
 587
 588        for (i = 0; i < MAX_ASICS; ++i) {
 589                if (devpriv && devpriv->asics[i].irq)
 590                        free_irq(devpriv->asics[i].irq, dev);
 591        }
 592
 593        if (devpriv && devpriv->sprivs)
 594                kfree(devpriv->sprivs);
 595
 596        return 0;
 597}
 598
 599/* DIO devices are slightly special.  Although it is possible to
 600 * implement the insn_read/insn_write interface, it is much more
 601 * useful to applications if you implement the insn_bits interface.
 602 * This allows packed reading/writing of the DIO channels.  The
 603 * comedi core can convert between insn_bits and insn_read/write */
 604static int pcmmio_dio_insn_bits(struct comedi_device *dev,
 605                                struct comedi_subdevice *s,
 606                                struct comedi_insn *insn, unsigned int *data)
 607{
 608        int byte_no;
 609        if (insn->n != 2)
 610                return -EINVAL;
 611
 612        /* NOTE:
 613           reading a 0 means this channel was high
 614           writine a 0 sets the channel high
 615           reading a 1 means this channel was low
 616           writing a 1 means set this channel low
 617
 618           Therefore everything is always inverted. */
 619
 620        /* The insn data is a mask in data[0] and the new data
 621         * in data[1], each channel cooresponding to a bit. */
 622
 623#ifdef DAMMIT_ITS_BROKEN
 624        /* DEBUG */
 625        printk("write mask: %08x  data: %08x\n", data[0], data[1]);
 626#endif
 627
 628        s->state = 0;
 629
 630        for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
 631                /* address of 8-bit port */
 632                unsigned long ioaddr = subpriv->iobases[byte_no],
 633                    /* bit offset of port in 32-bit doubleword */
 634                    offset = byte_no * 8;
 635                /* this 8-bit port's data */
 636                unsigned char byte = 0,
 637                    /* The write mask for this port (if any) */
 638                    write_mask_byte = (data[0] >> offset) & 0xff,
 639                    /* The data byte for this port */
 640                    data_byte = (data[1] >> offset) & 0xff;
 641
 642                byte = inb(ioaddr);     /* read all 8-bits for this port */
 643
 644#ifdef DAMMIT_ITS_BROKEN
 645                /* DEBUG */
 646                printk
 647                    ("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ",
 648                     byte_no, (unsigned)write_mask_byte, (unsigned)data_byte,
 649                     offset, ioaddr, (unsigned)byte);
 650#endif
 651
 652                if (write_mask_byte) {
 653                        /*
 654                         * this byte has some write_bits
 655                         * -- so set the output lines
 656                         */
 657                        /* clear bits for write mask */
 658                        byte &= ~write_mask_byte;
 659                        /* set to inverted data_byte */
 660                        byte |= ~data_byte & write_mask_byte;
 661                        /* Write out the new digital output state */
 662                        outb(byte, ioaddr);
 663                }
 664#ifdef DAMMIT_ITS_BROKEN
 665                /* DEBUG */
 666                printk("data_out_byte %02x\n", (unsigned)byte);
 667#endif
 668                /* save the digital input lines for this byte.. */
 669                s->state |= ((unsigned int)byte) << offset;
 670        }
 671
 672        /* now return the DIO lines to data[1] - note they came inverted! */
 673        data[1] = ~s->state;
 674
 675#ifdef DAMMIT_ITS_BROKEN
 676        /* DEBUG */
 677        printk("s->state %08x data_out %08x\n", s->state, data[1]);
 678#endif
 679
 680        return 2;
 681}
 682
 683/* The input or output configuration of each digital line is
 684 * configured by a special insn_config instruction.  chanspec
 685 * contains the channel to be changed, and data[0] contains the
 686 * value COMEDI_INPUT or COMEDI_OUTPUT. */
 687static int pcmmio_dio_insn_config(struct comedi_device *dev,
 688                                  struct comedi_subdevice *s,
 689                                  struct comedi_insn *insn, unsigned int *data)
 690{
 691        int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
 692            chan % 8;
 693        unsigned long ioaddr;
 694        unsigned char byte;
 695
 696        /* Compute ioaddr for this channel */
 697        ioaddr = subpriv->iobases[byte_no];
 698
 699        /* NOTE:
 700           writing a 0 an IO channel's bit sets the channel to INPUT
 701           and pulls the line high as well
 702
 703           writing a 1 to an IO channel's  bit pulls the line low
 704
 705           All channels are implicitly always in OUTPUT mode -- but when
 706           they are high they can be considered to be in INPUT mode..
 707
 708           Thus, we only force channels low if the config request was INPUT,
 709           otherwise we do nothing to the hardware.    */
 710
 711        switch (data[0]) {
 712        case INSN_CONFIG_DIO_OUTPUT:
 713                /* save to io_bits -- don't actually do anything since
 714                   all input channels are also output channels... */
 715                s->io_bits |= 1 << chan;
 716                break;
 717        case INSN_CONFIG_DIO_INPUT:
 718                /* write a 0 to the actual register representing the channel
 719                   to set it to 'input'.  0 means "float high". */
 720                byte = inb(ioaddr);
 721                byte &= ~(1 << bit_no);
 722                                /**< set input channel to '0' */
 723
 724                /*
 725                 * write out byte -- this is the only time we actually affect
 726                 * the hardware as all channels are implicitly output
 727                 * -- but input channels are set to float-high
 728                 */
 729                outb(byte, ioaddr);
 730
 731                /* save to io_bits */
 732                s->io_bits &= ~(1 << chan);
 733                break;
 734
 735        case INSN_CONFIG_DIO_QUERY:
 736                /* retreive from shadow register */
 737                data[1] =
 738                    (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
 739                return insn->n;
 740                break;
 741
 742        default:
 743                return -EINVAL;
 744                break;
 745        }
 746
 747        return insn->n;
 748}
 749
 750static void init_asics(struct comedi_device *dev)
 751{                               /* sets up an
 752                                   ASIC chip to defaults */
 753        int asic;
 754
 755        for (asic = 0; asic < thisboard->dio_num_asics; ++asic) {
 756                int port, page;
 757                unsigned long baseaddr = devpriv->asics[asic].iobase;
 758
 759                switch_page(dev, asic, 0);      /* switch back to page 0 */
 760
 761                /* first, clear all the DIO port bits */
 762                for (port = 0; port < PORTS_PER_ASIC; ++port)
 763                        outb(0, baseaddr + REG_PORT0 + port);
 764
 765                /* Next, clear all the paged registers for each page */
 766                for (page = 1; page < NUM_PAGES; ++page) {
 767                        int reg;
 768                        /* now clear all the paged registers */
 769                        switch_page(dev, asic, page);
 770                        for (reg = FIRST_PAGED_REG;
 771                             reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
 772                                outb(0, baseaddr + reg);
 773                }
 774
 775                /* DEBUG  set rising edge interrupts on port0 of both asics */
 776                /*switch_page(dev, asic, PAGE_POL);
 777                   outb(0xff, baseaddr + REG_POL0);
 778                   switch_page(dev, asic, PAGE_ENAB);
 779                   outb(0xff, baseaddr + REG_ENAB0); */
 780                /* END DEBUG */
 781
 782                /* switch back to default page 0 */
 783                switch_page(dev, asic, 0);
 784        }
 785}
 786
 787static void switch_page(struct comedi_device *dev, int asic, int page)
 788{
 789        if (asic < 0 || asic >= thisboard->dio_num_asics)
 790                return;         /* paranoia */
 791        if (page < 0 || page >= NUM_PAGES)
 792                return;         /* more paranoia */
 793
 794        devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
 795        devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
 796
 797        /* now write out the shadow register */
 798        outb(devpriv->asics[asic].pagelock,
 799             devpriv->asics[asic].iobase + REG_PAGELOCK);
 800}
 801
 802#ifdef notused
 803static void lock_port(struct comedi_device *dev, int asic, int port)
 804{
 805        if (asic < 0 || asic >= thisboard->dio_num_asics)
 806                return;         /* paranoia */
 807        if (port < 0 || port >= PORTS_PER_ASIC)
 808                return;         /* more paranoia */
 809
 810        devpriv->asics[asic].pagelock |= 0x1 << port;
 811        /* now write out the shadow register */
 812        outb(devpriv->asics[asic].pagelock,
 813             devpriv->asics[asic].iobase + REG_PAGELOCK);
 814        return;
 815}
 816
 817static void unlock_port(struct comedi_device *dev, int asic, int port)
 818{
 819        if (asic < 0 || asic >= thisboard->dio_num_asics)
 820                return;         /* paranoia */
 821        if (port < 0 || port >= PORTS_PER_ASIC)
 822                return;         /* more paranoia */
 823        devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
 824        /* now write out the shadow register */
 825        outb(devpriv->asics[asic].pagelock,
 826             devpriv->asics[asic].iobase + REG_PAGELOCK);
 827}
 828#endif /* notused */
 829
 830static irqreturn_t interrupt_pcmmio(int irq, void *d)
 831{
 832        int asic, got1 = 0;
 833        struct comedi_device *dev = (struct comedi_device *)d;
 834
 835        for (asic = 0; asic < MAX_ASICS; ++asic) {
 836                if (irq == devpriv->asics[asic].irq) {
 837                        unsigned long flags;
 838                        unsigned triggered = 0;
 839                        unsigned long iobase = devpriv->asics[asic].iobase;
 840                        /* it is an interrupt for ASIC #asic */
 841                        unsigned char int_pend;
 842
 843                        spin_lock_irqsave(&devpriv->asics[asic].spinlock,
 844                                          flags);
 845
 846                        int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
 847
 848                        if (int_pend) {
 849                                int port;
 850                                for (port = 0; port < INTR_PORTS_PER_ASIC;
 851                                     ++port) {
 852                                        if (int_pend & (0x1 << port)) {
 853                                                unsigned char
 854                                                    io_lines_with_edges = 0;
 855                                                switch_page(dev, asic,
 856                                                            PAGE_INT_ID);
 857                                                io_lines_with_edges =
 858                                                    inb(iobase +
 859                                                        REG_INT_ID0 + port);
 860
 861                                                if (io_lines_with_edges)
 862                                                        /*
 863                                                         * clear pending
 864                                                         * interrupt
 865                                                         */
 866                                                        outb(0, iobase +
 867                                                             REG_INT_ID0 +
 868                                                             port);
 869
 870                                                triggered |=
 871                                                    io_lines_with_edges <<
 872                                                    port * 8;
 873                                        }
 874                                }
 875
 876                                ++got1;
 877                        }
 878
 879                        spin_unlock_irqrestore(&devpriv->asics[asic].spinlock,
 880                                               flags);
 881
 882                        if (triggered) {
 883                                struct comedi_subdevice *s;
 884                                /*
 885                                 * TODO here: dispatch io lines to subdevs
 886                                 * with commands..
 887                                 */
 888                                printk
 889                                    ("PCMMIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n",
 890                                     irq, asic, triggered);
 891                                for (s = dev->subdevices + 2;
 892                                     s < dev->subdevices + dev->n_subdevices;
 893                                     ++s) {
 894                                        /*
 895                                         * this is an interrupt subdev,
 896                                         * and it matches this asic!
 897                                         */
 898                                        if (subpriv->dio.intr.asic == asic) {
 899                                                unsigned long flags;
 900                                                unsigned oldevents;
 901
 902                                                spin_lock_irqsave(&subpriv->dio.
 903                                                                  intr.spinlock,
 904                                                                  flags);
 905
 906                                                oldevents = s->async->events;
 907
 908                                                if (subpriv->dio.intr.active) {
 909                                                        unsigned mytrig =
 910                                                            ((triggered >>
 911                                                              subpriv->dio.intr.asic_chan)
 912                                                             &
 913                                                             ((0x1 << subpriv->
 914                                                               dio.intr.
 915                                                               num_asic_chans) -
 916                                                              1)) << subpriv->
 917                                                            dio.intr.first_chan;
 918                                                        if (mytrig &
 919                                                            subpriv->dio.
 920                                                            intr.enabled_mask) {
 921                                                                unsigned int val
 922                                                                    = 0;
 923                                                                unsigned int n,
 924                                                                    ch, len;
 925
 926                                                                len =
 927                                                                    s->
 928                                                                    async->cmd.chanlist_len;
 929                                                                for (n = 0;
 930                                                                     n < len;
 931                                                                     n++) {
 932                                                                        ch = CR_CHAN(s->async->cmd.chanlist[n]);
 933                                                                        if (mytrig & (1U << ch))
 934                                                                                val |= (1U << n);
 935                                                                }
 936                                                                /* Write the scan to the buffer. */
 937                                                                if (comedi_buf_put(s->async, ((short *)&val)[0])
 938                                                                    &&
 939                                                                    comedi_buf_put
 940                                                                    (s->async,
 941                                                                     ((short *)
 942                                                                      &val)[1])) {
 943                                                                        s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
 944                                                                } else {
 945                                                                        /* Overflow! Stop acquisition!! */
 946                                                                        /* TODO: STOP_ACQUISITION_CALL_HERE!! */
 947                                                                        pcmmio_stop_intr
 948                                                                            (dev,
 949                                                                             s);
 950                                                                }
 951
 952                                                                /* Check for end of acquisition. */
 953                                                                if (!subpriv->dio.intr.continuous) {
 954                                                                        /* stop_src == TRIG_COUNT */
 955                                                                        if (subpriv->dio.intr.stop_count > 0) {
 956                                                                                subpriv->dio.intr.stop_count--;
 957                                                                                if (subpriv->dio.intr.stop_count == 0) {
 958                                                                                        s->async->events |= COMEDI_CB_EOA;
 959                                                                                        /* TODO: STOP_ACQUISITION_CALL_HERE!! */
 960                                                                                        pcmmio_stop_intr
 961                                                                                            (dev,
 962                                                                                             s);
 963                                                                                }
 964                                                                        }
 965                                                                }
 966                                                        }
 967                                                }
 968
 969                                                spin_unlock_irqrestore
 970                                                    (&subpriv->dio.intr.
 971                                                     spinlock, flags);
 972
 973                                                if (oldevents !=
 974                                                    s->async->events) {
 975                                                        comedi_event(dev, s);
 976                                                }
 977
 978                                        }
 979
 980                                }
 981                        }
 982
 983                }
 984        }
 985        if (!got1)
 986                return IRQ_NONE;        /* interrupt from other source */
 987        return IRQ_HANDLED;
 988}
 989
 990static void pcmmio_stop_intr(struct comedi_device *dev,
 991                             struct comedi_subdevice *s)
 992{
 993        int nports, firstport, asic, port;
 994
 995        asic = subpriv->dio.intr.asic;
 996        if (asic < 0)
 997                return;         /* not an interrupt subdev */
 998
 999        subpriv->dio.intr.enabled_mask = 0;
1000        subpriv->dio.intr.active = 0;
1001        s->async->inttrig = 0;
1002        nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
1003        firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
1004        switch_page(dev, asic, PAGE_ENAB);
1005        for (port = firstport; port < firstport + nports; ++port) {
1006                /* disable all intrs for this subdev.. */
1007                outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
1008        }
1009}
1010
1011static int pcmmio_start_intr(struct comedi_device *dev,
1012                             struct comedi_subdevice *s)
1013{
1014        if (!subpriv->dio.intr.continuous && subpriv->dio.intr.stop_count == 0) {
1015                /* An empty acquisition! */
1016                s->async->events |= COMEDI_CB_EOA;
1017                subpriv->dio.intr.active = 0;
1018                return 1;
1019        } else {
1020                unsigned bits = 0, pol_bits = 0, n;
1021                int nports, firstport, asic, port;
1022                struct comedi_cmd *cmd = &s->async->cmd;
1023
1024                asic = subpriv->dio.intr.asic;
1025                if (asic < 0)
1026                        return 1;       /* not an interrupt
1027                                           subdev */
1028                subpriv->dio.intr.enabled_mask = 0;
1029                subpriv->dio.intr.active = 1;
1030                nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
1031                firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
1032                if (cmd->chanlist) {
1033                        for (n = 0; n < cmd->chanlist_len; n++) {
1034                                bits |= (1U << CR_CHAN(cmd->chanlist[n]));
1035                                pol_bits |= (CR_AREF(cmd->chanlist[n])
1036                                             || CR_RANGE(cmd->
1037                                                         chanlist[n]) ? 1U : 0U)
1038                                    << CR_CHAN(cmd->chanlist[n]);
1039                        }
1040                }
1041                bits &= ((0x1 << subpriv->dio.intr.num_asic_chans) -
1042                         1) << subpriv->dio.intr.first_chan;
1043                subpriv->dio.intr.enabled_mask = bits;
1044
1045                {
1046                        /*
1047                         * the below code configures the board
1048                         * to use a specific IRQ from 0-15.
1049                         */
1050                        unsigned char b;
1051                        /*
1052                         * set resource enable register
1053                         * to enable IRQ operation
1054                         */
1055                        outb(1 << 4, dev->iobase + 3);
1056                        /* set bits 0-3 of b to the irq number from 0-15 */
1057                        b = dev->irq & ((1 << 4) - 1);
1058                        outb(b, dev->iobase + 2);
1059                        /* done, we told the board what irq to use */
1060                }
1061
1062                switch_page(dev, asic, PAGE_ENAB);
1063                for (port = firstport; port < firstport + nports; ++port) {
1064                        unsigned enab =
1065                            bits >> (subpriv->dio.intr.first_chan + (port -
1066                                                                     firstport)
1067                                     * 8) & 0xff, pol =
1068                            pol_bits >> (subpriv->dio.intr.first_chan +
1069                                         (port - firstport) * 8) & 0xff;
1070                        /* set enab intrs for this subdev.. */
1071                        outb(enab,
1072                             devpriv->asics[asic].iobase + REG_ENAB0 + port);
1073                        switch_page(dev, asic, PAGE_POL);
1074                        outb(pol,
1075                             devpriv->asics[asic].iobase + REG_ENAB0 + port);
1076                }
1077        }
1078        return 0;
1079}
1080
1081static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
1082{
1083        unsigned long flags;
1084
1085        spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
1086        if (subpriv->dio.intr.active)
1087                pcmmio_stop_intr(dev, s);
1088        spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
1089
1090        return 0;
1091}
1092
1093/*
1094 * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
1095 */
1096static int
1097pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
1098                          unsigned int trignum)
1099{
1100        unsigned long flags;
1101        int event = 0;
1102
1103        if (trignum != 0)
1104                return -EINVAL;
1105
1106        spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
1107        s->async->inttrig = 0;
1108        if (subpriv->dio.intr.active)
1109                event = pcmmio_start_intr(dev, s);
1110        spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
1111
1112        if (event)
1113                comedi_event(dev, s);
1114
1115        return 1;
1116}
1117
1118/*
1119 * 'do_cmd' function for an 'INTERRUPT' subdevice.
1120 */
1121static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1122{
1123        struct comedi_cmd *cmd = &s->async->cmd;
1124        unsigned long flags;
1125        int event = 0;
1126
1127        spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
1128        subpriv->dio.intr.active = 1;
1129
1130        /* Set up end of acquisition. */
1131        switch (cmd->stop_src) {
1132        case TRIG_COUNT:
1133                subpriv->dio.intr.continuous = 0;
1134                subpriv->dio.intr.stop_count = cmd->stop_arg;
1135                break;
1136        default:
1137                /* TRIG_NONE */
1138                subpriv->dio.intr.continuous = 1;
1139                subpriv->dio.intr.stop_count = 0;
1140                break;
1141        }
1142
1143        /* Set up start of acquisition. */
1144        switch (cmd->start_src) {
1145        case TRIG_INT:
1146                s->async->inttrig = pcmmio_inttrig_start_intr;
1147                break;
1148        default:
1149                /* TRIG_NOW */
1150                event = pcmmio_start_intr(dev, s);
1151                break;
1152        }
1153        spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
1154
1155        if (event)
1156                comedi_event(dev, s);
1157
1158        return 0;
1159}
1160
1161static int
1162pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
1163               struct comedi_cmd *cmd)
1164{
1165        return comedi_pcm_cmdtest(dev, s, cmd);
1166}
1167
1168static int adc_wait_ready(unsigned long iobase)
1169{
1170        unsigned long retry = 100000;
1171        while (retry--)
1172                if (inb(iobase + 3) & 0x80)
1173                        return 0;
1174        return 1;
1175}
1176
1177/* All this is for AI and AO */
1178static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
1179                    struct comedi_insn *insn, unsigned int *data)
1180{
1181        int n;
1182        unsigned long iobase = subpriv->iobase;
1183
1184        /*
1185           1. write the CMD byte (to BASE+2)
1186           2. read junk lo byte (BASE+0)
1187           3. read junk hi byte (BASE+1)
1188           4. (mux settled so) write CMD byte again (BASE+2)
1189           5. read valid lo byte(BASE+0)
1190           6. read valid hi byte(BASE+1)
1191
1192           Additionally note that the BASE += 4 if the channel >= 8
1193         */
1194
1195        /* convert n samples */
1196        for (n = 0; n < insn->n; n++) {
1197                unsigned chan = CR_CHAN(insn->chanspec), range =
1198                    CR_RANGE(insn->chanspec), aref = CR_AREF(insn->chanspec);
1199                unsigned char command_byte = 0;
1200                unsigned iooffset = 0;
1201                short sample, adc_adjust = 0;
1202
1203                if (chan > 7)
1204                        chan -= 8, iooffset = 4;        /*
1205                                                         * use the second dword
1206                                                         * for channels > 7
1207                                                         */
1208
1209                if (aref != AREF_DIFF) {
1210                        aref = AREF_GROUND;
1211                        command_byte |= 1 << 7; /*
1212                                                 * set bit 7 to indicate
1213                                                 * single-ended
1214                                                 */
1215                }
1216                if (range < 2)
1217                        adc_adjust = 0x8000;    /*
1218                                                 * bipolar ranges
1219                                                 * (-5,5 .. -10,10 need to be
1220                                                 * adjusted -- that is.. they
1221                                                 * need to wrap around by
1222                                                 * adding 0x8000
1223                                                 */
1224
1225                if (chan % 2) {
1226                        command_byte |= 1 << 6; /*
1227                                                 * odd-numbered channels
1228                                                 * have bit 6 set
1229                                                 */
1230                }
1231
1232                /* select the channel, bits 4-5 == chan/2 */
1233                command_byte |= ((chan / 2) & 0x3) << 4;
1234
1235                /* set the range, bits 2-3 */
1236                command_byte |= (range & 0x3) << 2;
1237
1238                /* need to do this twice to make sure mux settled */
1239                /* chan/range/aref select */
1240                outb(command_byte, iobase + iooffset + 2);
1241
1242                /* wait for the adc to say it finised the conversion */
1243                adc_wait_ready(iobase + iooffset);
1244
1245                /* select the chan/range/aref AGAIN */
1246                outb(command_byte, iobase + iooffset + 2);
1247
1248                adc_wait_ready(iobase + iooffset);
1249
1250                /* read data lo byte */
1251                sample = inb(iobase + iooffset + 0);
1252
1253                /* read data hi byte */
1254                sample |= inb(iobase + iooffset + 1) << 8;
1255                sample += adc_adjust;   /* adjustment .. munge data */
1256                data[n] = sample;
1257        }
1258        /* return the number of samples read/written */
1259        return n;
1260}
1261
1262static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
1263                    struct comedi_insn *insn, unsigned int *data)
1264{
1265        int n;
1266        for (n = 0; n < insn->n; n++) {
1267                unsigned chan = CR_CHAN(insn->chanspec);
1268                if (chan < s->n_chan)
1269                        data[n] = subpriv->ao.shadow_samples[chan];
1270        }
1271        return n;
1272}
1273
1274static int wait_dac_ready(unsigned long iobase)
1275{
1276        unsigned long retry = 100000L;
1277
1278        /* This may seem like an absurd way to handle waiting and violates the
1279           "no busy waiting" policy. The fact is that the hardware is
1280           normally so fast that we usually only need one time through the loop
1281           anyway. The longer timeout is for rare occasions and for detecting
1282           non-existant hardware.  */
1283
1284        while (retry--) {
1285                if (inb(iobase + 3) & 0x80)
1286                        return 0;
1287
1288        }
1289        return 1;
1290}
1291
1292static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
1293                    struct comedi_insn *insn, unsigned int *data)
1294{
1295        int n;
1296        unsigned iobase = subpriv->iobase, iooffset = 0;
1297
1298        for (n = 0; n < insn->n; n++) {
1299                unsigned chan = CR_CHAN(insn->chanspec), range =
1300                    CR_RANGE(insn->chanspec);
1301                if (chan < s->n_chan) {
1302                        unsigned char command_byte = 0, range_byte =
1303                            range & ((1 << 4) - 1);
1304                        if (chan >= 4)
1305                                chan -= 4, iooffset += 4;
1306                        /* set the range.. */
1307                        outb(range_byte, iobase + iooffset + 0);
1308                        outb(0, iobase + iooffset + 1);
1309
1310                        /* tell it to begin */
1311                        command_byte = (chan << 1) | 0x60;
1312                        outb(command_byte, iobase + iooffset + 2);
1313
1314                        wait_dac_ready(iobase + iooffset);
1315
1316                        /* low order byte */
1317                        outb(data[n] & 0xff, iobase + iooffset + 0);
1318
1319                        /* high order byte */
1320                        outb((data[n] >> 8) & 0xff, iobase + iooffset + 1);
1321
1322                        /*
1323                         * set bit 4 of command byte to indicate
1324                         * data is loaded and trigger conversion
1325                         */
1326                        command_byte = 0x70 | (chan << 1);
1327                        /* trigger converion */
1328                        outb(command_byte, iobase + iooffset + 2);
1329
1330                        wait_dac_ready(iobase + iooffset);
1331
1332                        /* save to shadow register for ao_rinsn */
1333                        subpriv->ao.shadow_samples[chan] = data[n];
1334                }
1335        }
1336        return n;
1337}
1338
1339/*
1340 * A convenient macro that defines init_module() and cleanup_module(),
1341 * as necessary.
1342 */
1343static int __init driver_init_module(void)
1344{
1345        return comedi_driver_register(&driver);
1346}
1347
1348static void __exit driver_cleanup_module(void)
1349{
1350        comedi_driver_unregister(&driver);
1351}
1352
1353module_init(driver_init_module);
1354module_exit(driver_cleanup_module);
1355
1356MODULE_AUTHOR("Comedi http://www.comedi.org");
1357MODULE_DESCRIPTION("Comedi low-level driver");
1358MODULE_LICENSE("GPL");
1359