linux/drivers/staging/comedi/drivers/adl_pci9111.c
<<
>>
Prefs
   1/*
   2
   3   comedi/drivers/adl_pci9111.c
   4
   5   Hardware driver for PCI9111 ADLink cards:
   6
   7     PCI-9111HR
   8
   9   Copyright (C) 2002-2005 Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr>
  10
  11    This program is free software; you can redistribute it and/or modify
  12    it under the terms of the GNU General Public License as published by
  13    the Free Software Foundation; either version 2 of the License, or
  14    (at your option) any later version.
  15
  16    This program is distributed in the hope that it will be useful,
  17    but WITHOUT ANY WARRANTY; without even the implied warranty of
  18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19    GNU General Public License for more details.
  20
  21    You should have received a copy of the GNU General Public License
  22    along with this program; if not, write to the Free Software
  23    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24*/
  25
  26/*
  27Driver: adl_pci9111
  28Description: Adlink PCI-9111HR
  29Author: Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr>
  30Devices: [ADLink] PCI-9111HR (adl_pci9111)
  31Status: experimental
  32
  33Supports:
  34
  35  - ai_insn read
  36  - ao_insn read/write
  37  - di_insn read
  38  - do_insn read/write
  39  - ai_do_cmd mode with the following sources:
  40
  41    - start_src                 TRIG_NOW
  42    - scan_begin_src            TRIG_FOLLOW     TRIG_TIMER      TRIG_EXT
  43    - convert_src                               TRIG_TIMER      TRIG_EXT
  44    - scan_end_src              TRIG_COUNT
  45    - stop_src                  TRIG_COUNT      TRIG_NONE
  46
  47    The scanned channels must be consecutive and start from 0. They must
  48    all have the same range and aref.
  49
  50Configuration options:
  51
  52    [0] - PCI bus number (optional)
  53    [1] - PCI slot number (optional)
  54
  55    If bus/slot is not specified, the first available PCI
  56    device will be used.
  57
  58*/
  59
  60/*
  61CHANGELOG:
  62
  63  2005/02/17 Extend AI streaming capabilities. Now, scan_begin_arg can be
  64  a multiple of chanlist_len*convert_arg.
  65  2002/02/19 Fixed the two's complement conversion in pci9111_(hr_)ai_get_data.
  66  2002/02/18 Added external trigger support for analog input.
  67
  68TODO:
  69
  70  - Really test implemented functionality.
  71  - Add support for the PCI-9111DG with a probe routine to identify the card type
  72    (perhaps with the help of the channel number readback of the A/D Data register).
  73  - Add external multiplexer support.
  74
  75*/
  76
  77#include "../comedidev.h"
  78
  79#include <linux/delay.h>
  80#include <linux/interrupt.h>
  81
  82#include "8253.h"
  83#include "comedi_pci.h"
  84#include "comedi_fc.h"
  85
  86#define PCI9111_DRIVER_NAME     "adl_pci9111"
  87#define PCI9111_HR_DEVICE_ID    0x9111
  88
  89/*  TODO: Add other pci9111 board id */
  90
  91#define PCI9111_IO_RANGE        0x0100
  92
  93#define PCI9111_FIFO_HALF_SIZE  512
  94
  95#define PCI9111_AI_CHANNEL_NBR                  16
  96
  97#define PCI9111_AI_RESOLUTION                   12
  98#define PCI9111_AI_RESOLUTION_MASK              0x0FFF
  99#define PCI9111_AI_RESOLUTION_2_CMP_BIT         0x0800
 100
 101#define PCI9111_HR_AI_RESOLUTION                16
 102#define PCI9111_HR_AI_RESOLUTION_MASK           0xFFFF
 103#define PCI9111_HR_AI_RESOLUTION_2_CMP_BIT      0x8000
 104
 105#define PCI9111_AI_ACQUISITION_PERIOD_MIN_NS    10000
 106#define PCI9111_AO_CHANNEL_NBR                  1
 107#define PCI9111_AO_RESOLUTION                   12
 108#define PCI9111_AO_RESOLUTION_MASK              0x0FFF
 109#define PCI9111_DI_CHANNEL_NBR                  16
 110#define PCI9111_DO_CHANNEL_NBR                  16
 111#define PCI9111_DO_MASK                         0xFFFF
 112
 113#define PCI9111_RANGE_SETTING_DELAY             10
 114#define PCI9111_AI_INSTANT_READ_UDELAY_US       2
 115#define PCI9111_AI_INSTANT_READ_TIMEOUT         100
 116
 117#define PCI9111_8254_CLOCK_PERIOD_NS            500
 118
 119#define PCI9111_8254_COUNTER_0                  0x00
 120#define PCI9111_8254_COUNTER_1                  0x40
 121#define PCI9111_8254_COUNTER_2                  0x80
 122#define PCI9111_8254_COUNTER_LATCH              0x00
 123#define PCI9111_8254_READ_LOAD_LSB_ONLY         0x10
 124#define PCI9111_8254_READ_LOAD_MSB_ONLY         0x20
 125#define PCI9111_8254_READ_LOAD_LSB_MSB          0x30
 126#define PCI9111_8254_MODE_0                     0x00
 127#define PCI9111_8254_MODE_1                     0x02
 128#define PCI9111_8254_MODE_2                     0x04
 129#define PCI9111_8254_MODE_3                     0x06
 130#define PCI9111_8254_MODE_4                     0x08
 131#define PCI9111_8254_MODE_5                     0x0A
 132#define PCI9111_8254_BINARY_COUNTER             0x00
 133#define PCI9111_8254_BCD_COUNTER                0x01
 134
 135/* IO address map */
 136
 137#define PCI9111_REGISTER_AD_FIFO_VALUE                  0x00    /*  AD Data stored in FIFO */
 138#define PCI9111_REGISTER_DA_OUTPUT                      0x00
 139#define PCI9111_REGISTER_DIGITAL_IO                     0x02
 140#define PCI9111_REGISTER_EXTENDED_IO_PORTS              0x04
 141#define PCI9111_REGISTER_AD_CHANNEL_CONTROL             0x06    /*  Channel selection */
 142#define PCI9111_REGISTER_AD_CHANNEL_READBACK            0x06
 143#define PCI9111_REGISTER_INPUT_SIGNAL_RANGE             0x08
 144#define PCI9111_REGISTER_RANGE_STATUS_READBACK          0x08
 145#define PCI9111_REGISTER_TRIGGER_MODE_CONTROL           0x0A
 146#define PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK     0x0A
 147#define PCI9111_REGISTER_SOFTWARE_TRIGGER               0x0E
 148#define PCI9111_REGISTER_INTERRUPT_CONTROL              0x0C
 149#define PCI9111_REGISTER_8254_COUNTER_0                 0x40
 150#define PCI9111_REGISTER_8254_COUNTER_1                 0x42
 151#define PCI9111_REGISTER_8254_COUNTER_2                 0X44
 152#define PCI9111_REGISTER_8254_CONTROL                   0x46
 153#define PCI9111_REGISTER_INTERRUPT_CLEAR                0x48
 154
 155#define PCI9111_TRIGGER_MASK                            0x0F
 156#define PCI9111_PTRG_OFF                                (0 << 3)
 157#define PCI9111_PTRG_ON                                 (1 << 3)
 158#define PCI9111_EITS_EXTERNAL                           (1 << 2)
 159#define PCI9111_EITS_INTERNAL                           (0 << 2)
 160#define PCI9111_TPST_SOFTWARE_TRIGGER                   (0 << 1)
 161#define PCI9111_TPST_TIMER_PACER                        (1 << 1)
 162#define PCI9111_ASCAN_ON                                (1 << 0)
 163#define PCI9111_ASCAN_OFF                               (0 << 0)
 164
 165#define PCI9111_ISC0_SET_IRQ_ON_ENDING_OF_AD_CONVERSION (0 << 0)
 166#define PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL          (1 << 0)
 167#define PCI9111_ISC1_SET_IRQ_ON_TIMER_TICK              (0 << 1)
 168#define PCI9111_ISC1_SET_IRQ_ON_EXT_TRG                 (1 << 1)
 169#define PCI9111_FFEN_SET_FIFO_ENABLE                    (0 << 2)
 170#define PCI9111_FFEN_SET_FIFO_DISABLE                   (1 << 2)
 171
 172#define PCI9111_CHANNEL_MASK                            0x0F
 173
 174#define PCI9111_RANGE_MASK                              0x07
 175#define PCI9111_FIFO_EMPTY_MASK                         0x10
 176#define PCI9111_FIFO_HALF_FULL_MASK                     0x20
 177#define PCI9111_FIFO_FULL_MASK                          0x40
 178#define PCI9111_AD_BUSY_MASK                            0x80
 179
 180#define PCI9111_IO_BASE dev->iobase
 181
 182/*
 183 * Define inlined function
 184 */
 185
 186#define pci9111_trigger_and_autoscan_get() \
 187  (inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK)&0x0F)
 188
 189#define pci9111_trigger_and_autoscan_set(flags) \
 190  outb(flags, PCI9111_IO_BASE+PCI9111_REGISTER_TRIGGER_MODE_CONTROL)
 191
 192#define pci9111_interrupt_and_fifo_get() \
 193  ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK) >> 4) &0x03)
 194
 195#define pci9111_interrupt_and_fifo_set(flags) \
 196  outb(flags, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL)
 197
 198#define pci9111_interrupt_clear() \
 199  outb(0, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CLEAR)
 200
 201#define pci9111_software_trigger() \
 202  outb(0, PCI9111_IO_BASE+PCI9111_REGISTER_SOFTWARE_TRIGGER)
 203
 204#define pci9111_fifo_reset() \
 205  outb(PCI9111_FFEN_SET_FIFO_ENABLE, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \
 206  outb(PCI9111_FFEN_SET_FIFO_DISABLE, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \
 207  outb(PCI9111_FFEN_SET_FIFO_ENABLE, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL)
 208
 209#define pci9111_is_fifo_full() \
 210  ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
 211    PCI9111_FIFO_FULL_MASK)==0)
 212
 213#define pci9111_is_fifo_half_full() \
 214  ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
 215    PCI9111_FIFO_HALF_FULL_MASK)==0)
 216
 217#define pci9111_is_fifo_empty() \
 218  ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
 219    PCI9111_FIFO_EMPTY_MASK)==0)
 220
 221#define pci9111_ai_channel_set(channel) \
 222  outb((channel)&PCI9111_CHANNEL_MASK, PCI9111_IO_BASE+PCI9111_REGISTER_AD_CHANNEL_CONTROL)
 223
 224#define pci9111_ai_channel_get() \
 225  inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_CHANNEL_READBACK)&PCI9111_CHANNEL_MASK
 226
 227#define pci9111_ai_range_set(range) \
 228  outb((range)&PCI9111_RANGE_MASK, PCI9111_IO_BASE+PCI9111_REGISTER_INPUT_SIGNAL_RANGE)
 229
 230#define pci9111_ai_range_get() \
 231  inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)&PCI9111_RANGE_MASK
 232
 233#define pci9111_ai_get_data() \
 234  ((inw(PCI9111_IO_BASE+PCI9111_REGISTER_AD_FIFO_VALUE)>>4)&PCI9111_AI_RESOLUTION_MASK) \
 235  ^ PCI9111_AI_RESOLUTION_2_CMP_BIT
 236
 237#define pci9111_hr_ai_get_data() \
 238  (inw(PCI9111_IO_BASE+PCI9111_REGISTER_AD_FIFO_VALUE) & PCI9111_HR_AI_RESOLUTION_MASK) \
 239  ^ PCI9111_HR_AI_RESOLUTION_2_CMP_BIT
 240
 241#define pci9111_ao_set_data(data) \
 242  outw(data&PCI9111_AO_RESOLUTION_MASK, PCI9111_IO_BASE+PCI9111_REGISTER_DA_OUTPUT)
 243
 244#define pci9111_di_get_bits() \
 245  inw(PCI9111_IO_BASE+PCI9111_REGISTER_DIGITAL_IO)
 246
 247#define pci9111_do_set_bits(bits) \
 248  outw(bits, PCI9111_IO_BASE+PCI9111_REGISTER_DIGITAL_IO)
 249
 250#define pci9111_8254_control_set(flags) \
 251  outb(flags, PCI9111_IO_BASE+PCI9111_REGISTER_8254_CONTROL)
 252
 253#define pci9111_8254_counter_0_set(data) \
 254  outb(data & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_0); \
 255  outb((data >> 8) & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_0)
 256
 257#define pci9111_8254_counter_1_set(data) \
 258  outb(data & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_1); \
 259  outb((data >> 8) & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_1)
 260
 261#define pci9111_8254_counter_2_set(data) \
 262  outb(data & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_2); \
 263  outb((data >> 8) & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_2)
 264
 265/*  Function prototypes */
 266
 267static int pci9111_attach(struct comedi_device *dev,
 268                          struct comedi_devconfig *it);
 269static int pci9111_detach(struct comedi_device *dev);
 270static void pci9111_ai_munge(struct comedi_device *dev,
 271                             struct comedi_subdevice *s, void *data,
 272                             unsigned int num_bytes,
 273                             unsigned int start_chan_index);
 274
 275static const struct comedi_lrange pci9111_hr_ai_range = {
 276        5,
 277        {
 278         BIP_RANGE(10),
 279         BIP_RANGE(5),
 280         BIP_RANGE(2.5),
 281         BIP_RANGE(1.25),
 282         BIP_RANGE(0.625)
 283         }
 284};
 285
 286static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = {
 287        {
 288        PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID, PCI_ANY_ID,
 289                    PCI_ANY_ID, 0, 0, 0},
 290            /* { PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */
 291        {
 292        0}
 293};
 294
 295MODULE_DEVICE_TABLE(pci, pci9111_pci_table);
 296
 297/*  */
 298/*  Board specification structure */
 299/*  */
 300
 301struct pci9111_board {
 302        const char *name;       /*  driver name */
 303        int device_id;
 304        int ai_channel_nbr;     /*  num of A/D chans */
 305        int ao_channel_nbr;     /*  num of D/A chans */
 306        int ai_resolution;      /*  resolution of A/D */
 307        int ai_resolution_mask;
 308        int ao_resolution;      /*  resolution of D/A */
 309        int ao_resolution_mask;
 310        const struct comedi_lrange *ai_range_list;      /*  rangelist for A/D */
 311        const struct comedi_lrange *ao_range_list;      /*  rangelist for D/A */
 312        unsigned int ai_acquisition_period_min_ns;
 313};
 314
 315static const struct pci9111_board pci9111_boards[] = {
 316        {
 317         .name = "pci9111_hr",
 318         .device_id = PCI9111_HR_DEVICE_ID,
 319         .ai_channel_nbr = PCI9111_AI_CHANNEL_NBR,
 320         .ao_channel_nbr = PCI9111_AO_CHANNEL_NBR,
 321         .ai_resolution = PCI9111_HR_AI_RESOLUTION,
 322         .ai_resolution_mask = PCI9111_HR_AI_RESOLUTION_MASK,
 323         .ao_resolution = PCI9111_AO_RESOLUTION,
 324         .ao_resolution_mask = PCI9111_AO_RESOLUTION_MASK,
 325         .ai_range_list = &pci9111_hr_ai_range,
 326         .ao_range_list = &range_bipolar10,
 327         .ai_acquisition_period_min_ns = PCI9111_AI_ACQUISITION_PERIOD_MIN_NS}
 328};
 329
 330#define pci9111_board_nbr \
 331  (sizeof(pci9111_boards)/sizeof(struct pci9111_board))
 332
 333static struct comedi_driver pci9111_driver = {
 334        .driver_name = PCI9111_DRIVER_NAME,
 335        .module = THIS_MODULE,
 336        .attach = pci9111_attach,
 337        .detach = pci9111_detach,
 338};
 339
 340COMEDI_PCI_INITCLEANUP(pci9111_driver, pci9111_pci_table);
 341
 342/*  Private data structure */
 343
 344struct pci9111_private_data {
 345        struct pci_dev *pci_device;
 346        unsigned long io_range; /*  PCI6503 io range */
 347
 348        unsigned long lcr_io_base;      /*  Local configuration register base address */
 349        unsigned long lcr_io_range;
 350
 351        int stop_counter;
 352        int stop_is_none;
 353
 354        unsigned int scan_delay;
 355        unsigned int chanlist_len;
 356        unsigned int chunk_counter;
 357        unsigned int chunk_num_samples;
 358
 359        int ao_readback;        /*  Last written analog output data */
 360
 361        int timer_divisor_1;    /*  Divisor values for the 8254 timer pacer */
 362        int timer_divisor_2;
 363
 364        int is_valid;           /*  Is device valid */
 365
 366        short ai_bounce_buffer[2 * PCI9111_FIFO_HALF_SIZE];
 367};
 368
 369#define dev_private     ((struct pci9111_private_data *)dev->private)
 370
 371/*  ------------------------------------------------------------------ */
 372/*  PLX9050 SECTION */
 373/*  ------------------------------------------------------------------ */
 374
 375#define PLX9050_REGISTER_INTERRUPT_CONTROL 0x4c
 376
 377#define PLX9050_LINTI1_ENABLE           (1 << 0)
 378#define PLX9050_LINTI1_ACTIVE_HIGH      (1 << 1)
 379#define PLX9050_LINTI1_STATUS           (1 << 2)
 380#define PLX9050_LINTI2_ENABLE           (1 << 3)
 381#define PLX9050_LINTI2_ACTIVE_HIGH      (1 << 4)
 382#define PLX9050_LINTI2_STATUS           (1 << 5)
 383#define PLX9050_PCI_INTERRUPT_ENABLE    (1 << 6)
 384#define PLX9050_SOFTWARE_INTERRUPT      (1 << 7)
 385
 386static void plx9050_interrupt_control(unsigned long io_base,
 387                                      bool LINTi1_enable,
 388                                      bool LINTi1_active_high,
 389                                      bool LINTi2_enable,
 390                                      bool LINTi2_active_high,
 391                                      bool interrupt_enable)
 392{
 393        int flags = 0;
 394
 395        if (LINTi1_enable)
 396                flags |= PLX9050_LINTI1_ENABLE;
 397        if (LINTi1_active_high)
 398                flags |= PLX9050_LINTI1_ACTIVE_HIGH;
 399        if (LINTi2_enable)
 400                flags |= PLX9050_LINTI2_ENABLE;
 401        if (LINTi2_active_high)
 402                flags |= PLX9050_LINTI2_ACTIVE_HIGH;
 403
 404        if (interrupt_enable)
 405                flags |= PLX9050_PCI_INTERRUPT_ENABLE;
 406
 407        outb(flags, io_base + PLX9050_REGISTER_INTERRUPT_CONTROL);
 408}
 409
 410/*  ------------------------------------------------------------------ */
 411/*  MISCELLANEOUS SECTION */
 412/*  ------------------------------------------------------------------ */
 413
 414/*  8254 timer */
 415
 416static void pci9111_timer_set(struct comedi_device *dev)
 417{
 418        pci9111_8254_control_set(PCI9111_8254_COUNTER_0 |
 419                                 PCI9111_8254_READ_LOAD_LSB_MSB |
 420                                 PCI9111_8254_MODE_0 |
 421                                 PCI9111_8254_BINARY_COUNTER);
 422
 423        pci9111_8254_control_set(PCI9111_8254_COUNTER_1 |
 424                                 PCI9111_8254_READ_LOAD_LSB_MSB |
 425                                 PCI9111_8254_MODE_2 |
 426                                 PCI9111_8254_BINARY_COUNTER);
 427
 428        pci9111_8254_control_set(PCI9111_8254_COUNTER_2 |
 429                                 PCI9111_8254_READ_LOAD_LSB_MSB |
 430                                 PCI9111_8254_MODE_2 |
 431                                 PCI9111_8254_BINARY_COUNTER);
 432
 433        udelay(1);
 434
 435        pci9111_8254_counter_2_set(dev_private->timer_divisor_2);
 436        pci9111_8254_counter_1_set(dev_private->timer_divisor_1);
 437}
 438
 439enum pci9111_trigger_sources {
 440        software,
 441        timer_pacer,
 442        external
 443};
 444
 445static void pci9111_trigger_source_set(struct comedi_device *dev,
 446                                       enum pci9111_trigger_sources source)
 447{
 448        int flags;
 449
 450        flags = pci9111_trigger_and_autoscan_get() & 0x09;
 451
 452        switch (source) {
 453        case software:
 454                flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_SOFTWARE_TRIGGER;
 455                break;
 456
 457        case timer_pacer:
 458                flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_TIMER_PACER;
 459                break;
 460
 461        case external:
 462                flags |= PCI9111_EITS_EXTERNAL;
 463                break;
 464        }
 465
 466        pci9111_trigger_and_autoscan_set(flags);
 467}
 468
 469static void pci9111_pretrigger_set(struct comedi_device *dev, bool pretrigger)
 470{
 471        int flags;
 472
 473        flags = pci9111_trigger_and_autoscan_get() & 0x07;
 474
 475        if (pretrigger)
 476                flags |= PCI9111_PTRG_ON;
 477
 478        pci9111_trigger_and_autoscan_set(flags);
 479}
 480
 481static void pci9111_autoscan_set(struct comedi_device *dev, bool autoscan)
 482{
 483        int flags;
 484
 485        flags = pci9111_trigger_and_autoscan_get() & 0x0e;
 486
 487        if (autoscan)
 488                flags |= PCI9111_ASCAN_ON;
 489
 490        pci9111_trigger_and_autoscan_set(flags);
 491}
 492
 493enum pci9111_ISC0_sources {
 494        irq_on_eoc,
 495        irq_on_fifo_half_full
 496};
 497
 498enum pci9111_ISC1_sources {
 499        irq_on_timer_tick,
 500        irq_on_external_trigger
 501};
 502
 503static void pci9111_interrupt_source_set(struct comedi_device *dev,
 504                                         enum pci9111_ISC0_sources irq_0_source,
 505                                         enum pci9111_ISC1_sources irq_1_source)
 506{
 507        int flags;
 508
 509        flags = pci9111_interrupt_and_fifo_get() & 0x04;
 510
 511        if (irq_0_source == irq_on_fifo_half_full)
 512                flags |= PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL;
 513
 514        if (irq_1_source == irq_on_external_trigger)
 515                flags |= PCI9111_ISC1_SET_IRQ_ON_EXT_TRG;
 516
 517        pci9111_interrupt_and_fifo_set(flags);
 518}
 519
 520/*  ------------------------------------------------------------------ */
 521/*  HARDWARE TRIGGERED ANALOG INPUT SECTION */
 522/*  ------------------------------------------------------------------ */
 523
 524/*  Cancel analog input autoscan */
 525
 526#undef AI_DO_CMD_DEBUG
 527
 528static int pci9111_ai_cancel(struct comedi_device *dev,
 529                             struct comedi_subdevice *s)
 530{
 531        /*  Disable interrupts */
 532
 533        plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true,
 534                                  true, false);
 535
 536        pci9111_trigger_source_set(dev, software);
 537
 538        pci9111_autoscan_set(dev, false);
 539
 540        pci9111_fifo_reset();
 541
 542#ifdef AI_DO_CMD_DEBUG
 543        printk(PCI9111_DRIVER_NAME ": ai_cancel\n");
 544#endif
 545
 546        return 0;
 547}
 548
 549/*  Test analog input command */
 550
 551#define pci9111_check_trigger_src(src, flags) \
 552  tmp = src; \
 553  src &= flags; \
 554  if (!src || tmp != src) error++
 555
 556static int
 557pci9111_ai_do_cmd_test(struct comedi_device *dev,
 558                       struct comedi_subdevice *s, struct comedi_cmd *cmd)
 559{
 560        int tmp;
 561        int error = 0;
 562        int range, reference;
 563        int i;
 564        struct pci9111_board *board = (struct pci9111_board *)dev->board_ptr;
 565
 566        /*  Step 1 : check if trigger are trivialy valid */
 567
 568        pci9111_check_trigger_src(cmd->start_src, TRIG_NOW);
 569        pci9111_check_trigger_src(cmd->scan_begin_src,
 570                                  TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT);
 571        pci9111_check_trigger_src(cmd->convert_src, TRIG_TIMER | TRIG_EXT);
 572        pci9111_check_trigger_src(cmd->scan_end_src, TRIG_COUNT);
 573        pci9111_check_trigger_src(cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 574
 575        if (error)
 576                return 1;
 577
 578        /*  step 2 : make sure trigger sources are unique and mutually compatible */
 579
 580        if (cmd->start_src != TRIG_NOW)
 581                error++;
 582
 583        if ((cmd->scan_begin_src != TRIG_TIMER) &&
 584            (cmd->scan_begin_src != TRIG_FOLLOW) &&
 585            (cmd->scan_begin_src != TRIG_EXT))
 586                error++;
 587
 588        if ((cmd->convert_src != TRIG_TIMER) && (cmd->convert_src != TRIG_EXT)) {
 589                error++;
 590        }
 591        if ((cmd->convert_src == TRIG_TIMER) &&
 592            !((cmd->scan_begin_src == TRIG_TIMER) ||
 593              (cmd->scan_begin_src == TRIG_FOLLOW))) {
 594                error++;
 595        }
 596        if ((cmd->convert_src == TRIG_EXT) &&
 597            !((cmd->scan_begin_src == TRIG_EXT) ||
 598              (cmd->scan_begin_src == TRIG_FOLLOW))) {
 599                error++;
 600        }
 601
 602        if (cmd->scan_end_src != TRIG_COUNT)
 603                error++;
 604        if ((cmd->stop_src != TRIG_COUNT) && (cmd->stop_src != TRIG_NONE))
 605                error++;
 606
 607        if (error)
 608                return 2;
 609
 610        /*  Step 3 : make sure arguments are trivialy compatible */
 611
 612        if (cmd->chanlist_len < 1) {
 613                cmd->chanlist_len = 1;
 614                error++;
 615        }
 616
 617        if (cmd->chanlist_len > board->ai_channel_nbr) {
 618                cmd->chanlist_len = board->ai_channel_nbr;
 619                error++;
 620        }
 621
 622        if ((cmd->start_src == TRIG_NOW) && (cmd->start_arg != 0)) {
 623                cmd->start_arg = 0;
 624                error++;
 625        }
 626
 627        if ((cmd->convert_src == TRIG_TIMER) &&
 628            (cmd->convert_arg < board->ai_acquisition_period_min_ns)) {
 629                cmd->convert_arg = board->ai_acquisition_period_min_ns;
 630                error++;
 631        }
 632        if ((cmd->convert_src == TRIG_EXT) && (cmd->convert_arg != 0)) {
 633                cmd->convert_arg = 0;
 634                error++;
 635        }
 636
 637        if ((cmd->scan_begin_src == TRIG_TIMER) &&
 638            (cmd->scan_begin_arg < board->ai_acquisition_period_min_ns)) {
 639                cmd->scan_begin_arg = board->ai_acquisition_period_min_ns;
 640                error++;
 641        }
 642        if ((cmd->scan_begin_src == TRIG_FOLLOW) && (cmd->scan_begin_arg != 0)) {
 643                cmd->scan_begin_arg = 0;
 644                error++;
 645        }
 646        if ((cmd->scan_begin_src == TRIG_EXT) && (cmd->scan_begin_arg != 0)) {
 647                cmd->scan_begin_arg = 0;
 648                error++;
 649        }
 650
 651        if ((cmd->scan_end_src == TRIG_COUNT) &&
 652            (cmd->scan_end_arg != cmd->chanlist_len)) {
 653                cmd->scan_end_arg = cmd->chanlist_len;
 654                error++;
 655        }
 656
 657        if ((cmd->stop_src == TRIG_COUNT) && (cmd->stop_arg < 1)) {
 658                cmd->stop_arg = 1;
 659                error++;
 660        }
 661        if ((cmd->stop_src == TRIG_NONE) && (cmd->stop_arg != 0)) {
 662                cmd->stop_arg = 0;
 663                error++;
 664        }
 665
 666        if (error)
 667                return 3;
 668
 669        /*  Step 4 : fix up any arguments */
 670
 671        if (cmd->convert_src == TRIG_TIMER) {
 672                tmp = cmd->convert_arg;
 673                i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS,
 674                                               &(dev_private->timer_divisor_1),
 675                                               &(dev_private->timer_divisor_2),
 676                                               &(cmd->convert_arg),
 677                                               cmd->flags & TRIG_ROUND_MASK);
 678                if (tmp != cmd->convert_arg)
 679                        error++;
 680        }
 681        /*  There's only one timer on this card, so the scan_begin timer must */
 682        /*  be a multiple of chanlist_len*convert_arg */
 683
 684        if (cmd->scan_begin_src == TRIG_TIMER) {
 685
 686                unsigned int scan_begin_min;
 687                unsigned int scan_begin_arg;
 688                unsigned int scan_factor;
 689
 690                scan_begin_min = cmd->chanlist_len * cmd->convert_arg;
 691
 692                if (cmd->scan_begin_arg != scan_begin_min) {
 693                        if (scan_begin_min < cmd->scan_begin_arg) {
 694                                scan_factor =
 695                                    cmd->scan_begin_arg / scan_begin_min;
 696                                scan_begin_arg = scan_factor * scan_begin_min;
 697                                if (cmd->scan_begin_arg != scan_begin_arg) {
 698                                        cmd->scan_begin_arg = scan_begin_arg;
 699                                        error++;
 700                                }
 701                        } else {
 702                                cmd->scan_begin_arg = scan_begin_min;
 703                                error++;
 704                        }
 705                }
 706        }
 707
 708        if (error)
 709                return 4;
 710
 711        /*  Step 5 : check channel list */
 712
 713        if (cmd->chanlist) {
 714
 715                range = CR_RANGE(cmd->chanlist[0]);
 716                reference = CR_AREF(cmd->chanlist[0]);
 717
 718                if (cmd->chanlist_len > 1) {
 719                        for (i = 0; i < cmd->chanlist_len; i++) {
 720                                if (CR_CHAN(cmd->chanlist[i]) != i) {
 721                                        comedi_error(dev,
 722                                                     "entries in chanlist must be consecutive "
 723                                                     "channels,counting upwards from 0\n");
 724                                        error++;
 725                                }
 726                                if (CR_RANGE(cmd->chanlist[i]) != range) {
 727                                        comedi_error(dev,
 728                                                     "entries in chanlist must all have the same gain\n");
 729                                        error++;
 730                                }
 731                                if (CR_AREF(cmd->chanlist[i]) != reference) {
 732                                        comedi_error(dev,
 733                                                     "entries in chanlist must all have the same reference\n");
 734                                        error++;
 735                                }
 736                        }
 737                } else {
 738                        if ((CR_CHAN(cmd->chanlist[0]) >
 739                             (board->ai_channel_nbr - 1))
 740                            || (CR_CHAN(cmd->chanlist[0]) < 0)) {
 741                                comedi_error(dev,
 742                                             "channel number is out of limits\n");
 743                                error++;
 744                        }
 745                }
 746        }
 747
 748        if (error)
 749                return 5;
 750
 751        return 0;
 752
 753}
 754
 755/*  Analog input command */
 756
 757static int pci9111_ai_do_cmd(struct comedi_device *dev,
 758                             struct comedi_subdevice *subdevice)
 759{
 760        struct comedi_cmd *async_cmd = &subdevice->async->cmd;
 761
 762        if (!dev->irq) {
 763                comedi_error(dev,
 764                             "no irq assigned for PCI9111, cannot do hardware conversion");
 765                return -1;
 766        }
 767        /*  Set channel scan limit */
 768        /*  PCI9111 allows only scanning from channel 0 to channel n */
 769        /*  TODO: handle the case of an external multiplexer */
 770
 771        if (async_cmd->chanlist_len > 1) {
 772                pci9111_ai_channel_set((async_cmd->chanlist_len) - 1);
 773                pci9111_autoscan_set(dev, true);
 774        } else {
 775                pci9111_ai_channel_set(CR_CHAN(async_cmd->chanlist[0]));
 776                pci9111_autoscan_set(dev, false);
 777        }
 778
 779        /*  Set gain */
 780        /*  This is the same gain on every channel */
 781
 782        pci9111_ai_range_set(CR_RANGE(async_cmd->chanlist[0]));
 783
 784        /* Set counter */
 785
 786        switch (async_cmd->stop_src) {
 787        case TRIG_COUNT:
 788                dev_private->stop_counter =
 789                    async_cmd->stop_arg * async_cmd->chanlist_len;
 790                dev_private->stop_is_none = 0;
 791                break;
 792
 793        case TRIG_NONE:
 794                dev_private->stop_counter = 0;
 795                dev_private->stop_is_none = 1;
 796                break;
 797
 798        default:
 799                comedi_error(dev, "Invalid stop trigger");
 800                return -1;
 801        }
 802
 803        /*  Set timer pacer */
 804
 805        dev_private->scan_delay = 0;
 806        switch (async_cmd->convert_src) {
 807        case TRIG_TIMER:
 808                i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS,
 809                                               &(dev_private->timer_divisor_1),
 810                                               &(dev_private->timer_divisor_2),
 811                                               &(async_cmd->convert_arg),
 812                                               async_cmd->
 813                                               flags & TRIG_ROUND_MASK);
 814#ifdef AI_DO_CMD_DEBUG
 815                printk(PCI9111_DRIVER_NAME ": divisors = %d, %d\n",
 816                       dev_private->timer_divisor_1,
 817                       dev_private->timer_divisor_2);
 818#endif
 819
 820                pci9111_trigger_source_set(dev, software);
 821                pci9111_timer_set(dev);
 822                pci9111_fifo_reset();
 823                pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
 824                                             irq_on_timer_tick);
 825                pci9111_trigger_source_set(dev, timer_pacer);
 826                plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
 827                                          false, true, true);
 828
 829                dev_private->scan_delay =
 830                    (async_cmd->scan_begin_arg / (async_cmd->convert_arg *
 831                                                  async_cmd->chanlist_len)) - 1;
 832
 833                break;
 834
 835        case TRIG_EXT:
 836
 837                pci9111_trigger_source_set(dev, external);
 838                pci9111_fifo_reset();
 839                pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
 840                                             irq_on_timer_tick);
 841                plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
 842                                          false, true, true);
 843
 844                break;
 845
 846        default:
 847                comedi_error(dev, "Invalid convert trigger");
 848                return -1;
 849        }
 850
 851        dev_private->stop_counter *= (1 + dev_private->scan_delay);
 852        dev_private->chanlist_len = async_cmd->chanlist_len;
 853        dev_private->chunk_counter = 0;
 854        dev_private->chunk_num_samples =
 855            dev_private->chanlist_len * (1 + dev_private->scan_delay);
 856
 857#ifdef AI_DO_CMD_DEBUG
 858        printk(PCI9111_DRIVER_NAME ": start interruptions!\n");
 859        printk(PCI9111_DRIVER_NAME ": trigger source = %2x\n",
 860               pci9111_trigger_and_autoscan_get());
 861        printk(PCI9111_DRIVER_NAME ": irq source     = %2x\n",
 862               pci9111_interrupt_and_fifo_get());
 863        printk(PCI9111_DRIVER_NAME ": ai_do_cmd\n");
 864        printk(PCI9111_DRIVER_NAME ": stop counter   = %d\n",
 865               dev_private->stop_counter);
 866        printk(PCI9111_DRIVER_NAME ": scan delay     = %d\n",
 867               dev_private->scan_delay);
 868        printk(PCI9111_DRIVER_NAME ": chanlist_len   = %d\n",
 869               dev_private->chanlist_len);
 870        printk(PCI9111_DRIVER_NAME ": chunk num samples = %d\n",
 871               dev_private->chunk_num_samples);
 872#endif
 873
 874        return 0;
 875}
 876
 877static void pci9111_ai_munge(struct comedi_device *dev,
 878                             struct comedi_subdevice *s, void *data,
 879                             unsigned int num_bytes,
 880                             unsigned int start_chan_index)
 881{
 882        unsigned int i, num_samples = num_bytes / sizeof(short);
 883        short *array = data;
 884        int resolution =
 885            ((struct pci9111_board *)dev->board_ptr)->ai_resolution;
 886
 887        for (i = 0; i < num_samples; i++) {
 888                if (resolution == PCI9111_HR_AI_RESOLUTION)
 889                        array[i] =
 890                            (array[i] & PCI9111_HR_AI_RESOLUTION_MASK) ^
 891                            PCI9111_HR_AI_RESOLUTION_2_CMP_BIT;
 892                else
 893                        array[i] =
 894                            ((array[i] >> 4) & PCI9111_AI_RESOLUTION_MASK) ^
 895                            PCI9111_AI_RESOLUTION_2_CMP_BIT;
 896        }
 897}
 898
 899/*  ------------------------------------------------------------------ */
 900/*  INTERRUPT SECTION */
 901/*  ------------------------------------------------------------------ */
 902
 903#undef INTERRUPT_DEBUG
 904
 905static irqreturn_t pci9111_interrupt(int irq, void *p_device)
 906{
 907        struct comedi_device *dev = p_device;
 908        struct comedi_subdevice *subdevice = dev->read_subdev;
 909        struct comedi_async *async;
 910        unsigned long irq_flags;
 911        unsigned char intcsr;
 912
 913        if (!dev->attached) {
 914                /*  Ignore interrupt before device fully attached. */
 915                /*  Might not even have allocated subdevices yet! */
 916                return IRQ_NONE;
 917        }
 918
 919        async = subdevice->async;
 920
 921        spin_lock_irqsave(&dev->spinlock, irq_flags);
 922
 923        /*  Check if we are source of interrupt */
 924        intcsr = inb(dev_private->lcr_io_base +
 925                     PLX9050_REGISTER_INTERRUPT_CONTROL);
 926        if (!(((intcsr & PLX9050_PCI_INTERRUPT_ENABLE) != 0)
 927              && (((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS))
 928                   == (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS))
 929                  || ((intcsr & (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS))
 930                      == (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS))))) {
 931                /*  Not the source of the interrupt. */
 932                /*  (N.B. not using PLX9050_SOFTWARE_INTERRUPT) */
 933                spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 934                return IRQ_NONE;
 935        }
 936
 937        if ((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) ==
 938            (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) {
 939                /*  Interrupt comes from fifo_half-full signal */
 940
 941                if (pci9111_is_fifo_full()) {
 942                        spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 943                        comedi_error(dev, PCI9111_DRIVER_NAME " fifo overflow");
 944                        pci9111_interrupt_clear();
 945                        pci9111_ai_cancel(dev, subdevice);
 946                        async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
 947                        comedi_event(dev, subdevice);
 948
 949                        return IRQ_HANDLED;
 950                }
 951
 952                if (pci9111_is_fifo_half_full()) {
 953                        unsigned int num_samples;
 954                        unsigned int bytes_written = 0;
 955
 956#ifdef INTERRUPT_DEBUG
 957                        printk(PCI9111_DRIVER_NAME ": fifo is half full\n");
 958#endif
 959
 960                        num_samples =
 961                            PCI9111_FIFO_HALF_SIZE >
 962                            dev_private->stop_counter
 963                            && !dev_private->
 964                            stop_is_none ? dev_private->stop_counter :
 965                            PCI9111_FIFO_HALF_SIZE;
 966                        insw(PCI9111_IO_BASE + PCI9111_REGISTER_AD_FIFO_VALUE,
 967                             dev_private->ai_bounce_buffer, num_samples);
 968
 969                        if (dev_private->scan_delay < 1) {
 970                                bytes_written =
 971                                    cfc_write_array_to_buffer(subdevice,
 972                                                              dev_private->
 973                                                              ai_bounce_buffer,
 974                                                              num_samples *
 975                                                              sizeof(short));
 976                        } else {
 977                                int position = 0;
 978                                int to_read;
 979
 980                                while (position < num_samples) {
 981                                        if (dev_private->chunk_counter <
 982                                            dev_private->chanlist_len) {
 983                                                to_read =
 984                                                    dev_private->chanlist_len -
 985                                                    dev_private->chunk_counter;
 986
 987                                                if (to_read >
 988                                                    num_samples - position)
 989                                                        to_read =
 990                                                            num_samples -
 991                                                            position;
 992
 993                                                bytes_written +=
 994                                                    cfc_write_array_to_buffer
 995                                                    (subdevice,
 996                                                     dev_private->ai_bounce_buffer
 997                                                     + position,
 998                                                     to_read * sizeof(short));
 999                                        } else {
1000                                                to_read =
1001                                                    dev_private->chunk_num_samples
1002                                                    -
1003                                                    dev_private->chunk_counter;
1004                                                if (to_read >
1005                                                    num_samples - position)
1006                                                        to_read =
1007                                                            num_samples -
1008                                                            position;
1009
1010                                                bytes_written +=
1011                                                    sizeof(short) * to_read;
1012                                        }
1013
1014                                        position += to_read;
1015                                        dev_private->chunk_counter += to_read;
1016
1017                                        if (dev_private->chunk_counter >=
1018                                            dev_private->chunk_num_samples)
1019                                                dev_private->chunk_counter = 0;
1020                                }
1021                        }
1022
1023                        dev_private->stop_counter -=
1024                            bytes_written / sizeof(short);
1025                }
1026        }
1027
1028        if ((dev_private->stop_counter == 0) && (!dev_private->stop_is_none)) {
1029                async->events |= COMEDI_CB_EOA;
1030                pci9111_ai_cancel(dev, subdevice);
1031        }
1032
1033        /* Very important, otherwise another interrupt request will be inserted
1034         * and will cause driver hangs on processing interrupt event. */
1035
1036        pci9111_interrupt_clear();
1037
1038        spin_unlock_irqrestore(&dev->spinlock, irq_flags);
1039
1040        comedi_event(dev, subdevice);
1041
1042        return IRQ_HANDLED;
1043}
1044
1045/*  ------------------------------------------------------------------ */
1046/*  INSTANT ANALOG INPUT OUTPUT SECTION */
1047/*  ------------------------------------------------------------------ */
1048
1049/*  analog instant input */
1050
1051#undef AI_INSN_DEBUG
1052
1053static int pci9111_ai_insn_read(struct comedi_device *dev,
1054                                struct comedi_subdevice *subdevice,
1055                                struct comedi_insn *insn, unsigned int *data)
1056{
1057        int resolution =
1058            ((struct pci9111_board *)dev->board_ptr)->ai_resolution;
1059
1060        int timeout, i;
1061
1062#ifdef AI_INSN_DEBUG
1063        printk(PCI9111_DRIVER_NAME ": ai_insn set c/r/n = %2x/%2x/%2x\n",
1064               CR_CHAN((&insn->chanspec)[0]),
1065               CR_RANGE((&insn->chanspec)[0]), insn->n);
1066#endif
1067
1068        pci9111_ai_channel_set(CR_CHAN((&insn->chanspec)[0]));
1069
1070        if ((pci9111_ai_range_get()) != CR_RANGE((&insn->chanspec)[0])) {
1071                pci9111_ai_range_set(CR_RANGE((&insn->chanspec)[0]));
1072        }
1073
1074        pci9111_fifo_reset();
1075
1076        for (i = 0; i < insn->n; i++) {
1077                pci9111_software_trigger();
1078
1079                timeout = PCI9111_AI_INSTANT_READ_TIMEOUT;
1080
1081                while (timeout--) {
1082                        if (!pci9111_is_fifo_empty())
1083                                goto conversion_done;
1084                }
1085
1086                comedi_error(dev, "A/D read timeout");
1087                data[i] = 0;
1088                pci9111_fifo_reset();
1089                return -ETIME;
1090
1091conversion_done:
1092
1093                if (resolution == PCI9111_HR_AI_RESOLUTION) {
1094                        data[i] = pci9111_hr_ai_get_data();
1095                } else {
1096                        data[i] = pci9111_ai_get_data();
1097                }
1098        }
1099
1100#ifdef AI_INSN_DEBUG
1101        printk(PCI9111_DRIVER_NAME ": ai_insn get c/r/t = %2x/%2x/%2x\n",
1102               pci9111_ai_channel_get(),
1103               pci9111_ai_range_get(), pci9111_trigger_and_autoscan_get());
1104#endif
1105
1106        return i;
1107}
1108
1109/*  Analog instant output */
1110
1111static int
1112pci9111_ao_insn_write(struct comedi_device *dev,
1113                      struct comedi_subdevice *s, struct comedi_insn *insn,
1114                      unsigned int *data)
1115{
1116        int i;
1117
1118        for (i = 0; i < insn->n; i++) {
1119                pci9111_ao_set_data(data[i]);
1120                dev_private->ao_readback = data[i];
1121        }
1122
1123        return i;
1124}
1125
1126/*  Analog output readback */
1127
1128static int pci9111_ao_insn_read(struct comedi_device *dev,
1129                                struct comedi_subdevice *s,
1130                                struct comedi_insn *insn, unsigned int *data)
1131{
1132        int i;
1133
1134        for (i = 0; i < insn->n; i++) {
1135                data[i] = dev_private->ao_readback & PCI9111_AO_RESOLUTION_MASK;
1136        }
1137
1138        return i;
1139}
1140
1141/*  ------------------------------------------------------------------ */
1142/*  DIGITAL INPUT OUTPUT SECTION */
1143/*  ------------------------------------------------------------------ */
1144
1145/*  Digital inputs */
1146
1147static int pci9111_di_insn_bits(struct comedi_device *dev,
1148                                struct comedi_subdevice *subdevice,
1149                                struct comedi_insn *insn, unsigned int *data)
1150{
1151        unsigned int bits;
1152
1153        bits = pci9111_di_get_bits();
1154        data[1] = bits;
1155
1156        return 2;
1157}
1158
1159/*  Digital outputs */
1160
1161static int pci9111_do_insn_bits(struct comedi_device *dev,
1162                                struct comedi_subdevice *subdevice,
1163                                struct comedi_insn *insn, unsigned int *data)
1164{
1165        unsigned int bits;
1166
1167        /*  Only set bits that have been masked */
1168        /*  data[0] = mask */
1169        /*  data[1] = bit state */
1170
1171        data[0] &= PCI9111_DO_MASK;
1172
1173        bits = subdevice->state;
1174        bits &= ~data[0];
1175        bits |= data[0] & data[1];
1176        subdevice->state = bits;
1177
1178        pci9111_do_set_bits(bits);
1179
1180        data[1] = bits;
1181
1182        return 2;
1183}
1184
1185/*  ------------------------------------------------------------------ */
1186/*  INITIALISATION SECTION */
1187/*  ------------------------------------------------------------------ */
1188
1189/*  Reset device */
1190
1191static int pci9111_reset(struct comedi_device *dev)
1192{
1193        /*  Set trigger source to software */
1194
1195        plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true,
1196                                  true, false);
1197
1198        pci9111_trigger_source_set(dev, software);
1199        pci9111_pretrigger_set(dev, false);
1200        pci9111_autoscan_set(dev, false);
1201
1202        /*  Reset 8254 chip */
1203
1204        dev_private->timer_divisor_1 = 0;
1205        dev_private->timer_divisor_2 = 0;
1206
1207        pci9111_timer_set(dev);
1208
1209        return 0;
1210}
1211
1212/*  Attach */
1213/*       - Register PCI device */
1214/*       - Declare device driver capability */
1215
1216static int pci9111_attach(struct comedi_device *dev,
1217                          struct comedi_devconfig *it)
1218{
1219        struct comedi_subdevice *subdevice;
1220        unsigned long io_base, io_range, lcr_io_base, lcr_io_range;
1221        struct pci_dev *pci_device;
1222        int error, i;
1223        const struct pci9111_board *board;
1224
1225        if (alloc_private(dev, sizeof(struct pci9111_private_data)) < 0) {
1226                return -ENOMEM;
1227        }
1228        /*  Probe the device to determine what device in the series it is. */
1229
1230        printk("comedi%d: " PCI9111_DRIVER_NAME " driver\n", dev->minor);
1231
1232        for (pci_device = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
1233             pci_device != NULL;
1234             pci_device = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_device)) {
1235                if (pci_device->vendor == PCI_VENDOR_ID_ADLINK) {
1236                        for (i = 0; i < pci9111_board_nbr; i++) {
1237                                if (pci9111_boards[i].device_id ==
1238                                    pci_device->device) {
1239                                        /*  was a particular bus/slot requested? */
1240                                        if ((it->options[0] != 0)
1241                                            || (it->options[1] != 0)) {
1242                                                /*  are we on the wrong bus/slot? */
1243                                                if (pci_device->bus->number !=
1244                                                    it->options[0]
1245                                                    ||
1246                                                    PCI_SLOT(pci_device->devfn)
1247                                                    != it->options[1]) {
1248                                                        continue;
1249                                                }
1250                                        }
1251
1252                                        dev->board_ptr = pci9111_boards + i;
1253                                        board =
1254                                            (struct pci9111_board *)
1255                                            dev->board_ptr;
1256                                        dev_private->pci_device = pci_device;
1257                                        goto found;
1258                                }
1259                        }
1260                }
1261        }
1262
1263        printk("comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
1264               dev->minor, it->options[0], it->options[1]);
1265        return -EIO;
1266
1267found:
1268
1269        printk("comedi%d: found %s (b:s:f=%d:%d:%d) , irq=%d\n",
1270               dev->minor,
1271               pci9111_boards[i].name,
1272               pci_device->bus->number,
1273               PCI_SLOT(pci_device->devfn),
1274               PCI_FUNC(pci_device->devfn), pci_device->irq);
1275
1276        /*  TODO: Warn about non-tested boards. */
1277
1278        switch (board->device_id) {
1279        };
1280
1281        /*  Read local configuration register base address [PCI_BASE_ADDRESS #1]. */
1282
1283        lcr_io_base = pci_resource_start(pci_device, 1);
1284        lcr_io_range = pci_resource_len(pci_device, 1);
1285
1286        printk
1287            ("comedi%d: local configuration registers at address 0x%4lx [0x%4lx]\n",
1288             dev->minor, lcr_io_base, lcr_io_range);
1289
1290        /*  Enable PCI device and request regions */
1291        if (comedi_pci_enable(pci_device, PCI9111_DRIVER_NAME) < 0) {
1292                printk
1293                    ("comedi%d: Failed to enable PCI device and request regions\n",
1294                     dev->minor);
1295                return -EIO;
1296        }
1297        /*  Read PCI6308 register base address [PCI_BASE_ADDRESS #2]. */
1298
1299        io_base = pci_resource_start(pci_device, 2);
1300        io_range = pci_resource_len(pci_device, 2);
1301
1302        printk("comedi%d: 6503 registers at address 0x%4lx [0x%4lx]\n",
1303               dev->minor, io_base, io_range);
1304
1305        dev->iobase = io_base;
1306        dev->board_name = board->name;
1307        dev_private->io_range = io_range;
1308        dev_private->is_valid = 0;
1309        dev_private->lcr_io_base = lcr_io_base;
1310        dev_private->lcr_io_range = lcr_io_range;
1311
1312        pci9111_reset(dev);
1313
1314        /*  Irq setup */
1315
1316        dev->irq = 0;
1317        if (pci_device->irq > 0) {
1318                if (request_irq(pci_device->irq, pci9111_interrupt,
1319                                IRQF_SHARED, PCI9111_DRIVER_NAME, dev) != 0) {
1320                        printk("comedi%d: unable to allocate irq  %u\n",
1321                               dev->minor, pci_device->irq);
1322                        return -EINVAL;
1323                }
1324        }
1325        dev->irq = pci_device->irq;
1326
1327        /*  TODO: Add external multiplexer setup (according to option[2]). */
1328
1329        error = alloc_subdevices(dev, 4);
1330        if (error < 0)
1331                return error;
1332
1333        subdevice = dev->subdevices + 0;
1334        dev->read_subdev = subdevice;
1335
1336        subdevice->type = COMEDI_SUBD_AI;
1337        subdevice->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_CMD_READ;
1338
1339        /*  TODO: Add external multiplexer data */
1340        /*     if (devpriv->usemux) { subdevice->n_chan = devpriv->usemux; } */
1341        /*     else { subdevice->n_chan = this_board->n_aichan; } */
1342
1343        subdevice->n_chan = board->ai_channel_nbr;
1344        subdevice->maxdata = board->ai_resolution_mask;
1345        subdevice->len_chanlist = board->ai_channel_nbr;
1346        subdevice->range_table = board->ai_range_list;
1347        subdevice->cancel = pci9111_ai_cancel;
1348        subdevice->insn_read = pci9111_ai_insn_read;
1349        subdevice->do_cmdtest = pci9111_ai_do_cmd_test;
1350        subdevice->do_cmd = pci9111_ai_do_cmd;
1351        subdevice->munge = pci9111_ai_munge;
1352
1353        subdevice = dev->subdevices + 1;
1354        subdevice->type = COMEDI_SUBD_AO;
1355        subdevice->subdev_flags = SDF_WRITABLE | SDF_COMMON;
1356        subdevice->n_chan = board->ao_channel_nbr;
1357        subdevice->maxdata = board->ao_resolution_mask;
1358        subdevice->len_chanlist = board->ao_channel_nbr;
1359        subdevice->range_table = board->ao_range_list;
1360        subdevice->insn_write = pci9111_ao_insn_write;
1361        subdevice->insn_read = pci9111_ao_insn_read;
1362
1363        subdevice = dev->subdevices + 2;
1364        subdevice->type = COMEDI_SUBD_DI;
1365        subdevice->subdev_flags = SDF_READABLE;
1366        subdevice->n_chan = PCI9111_DI_CHANNEL_NBR;
1367        subdevice->maxdata = 1;
1368        subdevice->range_table = &range_digital;
1369        subdevice->insn_bits = pci9111_di_insn_bits;
1370
1371        subdevice = dev->subdevices + 3;
1372        subdevice->type = COMEDI_SUBD_DO;
1373        subdevice->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1374        subdevice->n_chan = PCI9111_DO_CHANNEL_NBR;
1375        subdevice->maxdata = 1;
1376        subdevice->range_table = &range_digital;
1377        subdevice->insn_bits = pci9111_do_insn_bits;
1378
1379        dev_private->is_valid = 1;
1380
1381        return 0;
1382}
1383
1384/*  Detach */
1385
1386static int pci9111_detach(struct comedi_device *dev)
1387{
1388        /*  Reset device */
1389
1390        if (dev->private != 0) {
1391                if (dev_private->is_valid)
1392                        pci9111_reset(dev);
1393
1394        }
1395        /*  Release previously allocated irq */
1396
1397        if (dev->irq != 0) {
1398                free_irq(dev->irq, dev);
1399        }
1400
1401        if (dev_private != 0 && dev_private->pci_device != 0) {
1402                if (dev->iobase) {
1403                        comedi_pci_disable(dev_private->pci_device);
1404                }
1405                pci_dev_put(dev_private->pci_device);
1406        }
1407
1408        return 0;
1409}
1410