linux/drivers/staging/comedi/drivers/adv_pci_dio.c
<<
>>
Prefs
   1/*
   2 * comedi/drivers/adv_pci_dio.c
   3 *
   4 * Author: Michal Dobes <dobes@tesnet.cz>
   5 *
   6 *  Hardware driver for Advantech PCI DIO cards.
   7*/
   8/*
   9Driver: adv_pci_dio
  10Description: Advantech PCI-1730, PCI-1733, PCI-1734, PCI-1736UP,
  11             PCI-1750, PCI-1751, PCI-1752, PCI-1753/E, PCI-1754,
  12             PCI-1756, PCI-1762
  13Author: Michal Dobes <dobes@tesnet.cz>
  14Devices: [Advantech] PCI-1730 (adv_pci_dio), PCI-1733,
  15  PCI-1734, PCI-1736UP, PCI-1750,
  16  PCI-1751, PCI-1752, PCI-1753,
  17  PCI-1753+PCI-1753E, PCI-1754, PCI-1756,
  18  PCI-1760, PCI-1762
  19Status: untested
  20Updated: Mon, 14 Apr 2008 10:43:08 +0100
  21
  22This driver supports now only insn interface for DI/DO/DIO.
  23
  24Configuration options:
  25  [0] - PCI bus of device (optional)
  26  [1] - PCI slot of device (optional)
  27          If bus/slot is not specified, the first available PCI
  28          device will be used.
  29
  30*/
  31
  32#include "../comedidev.h"
  33
  34#include <linux/delay.h>
  35
  36#include "comedi_pci.h"
  37#include "8255.h"
  38
  39#undef PCI_DIO_EXTDEBUG         /* if defined, enable extensive debug logging */
  40
  41#undef DPRINTK
  42#ifdef PCI_DIO_EXTDEBUG
  43#define DPRINTK(fmt, args...) printk(fmt, ## args)
  44#else
  45#define DPRINTK(fmt, args...)
  46#endif
  47
  48/* hardware types of the cards */
  49enum hw_cards_id {
  50        TYPE_PCI1730, TYPE_PCI1733, TYPE_PCI1734, TYPE_PCI1736,
  51        TYPE_PCI1750,
  52        TYPE_PCI1751,
  53        TYPE_PCI1752,
  54        TYPE_PCI1753, TYPE_PCI1753E,
  55        TYPE_PCI1754, TYPE_PCI1756,
  56        TYPE_PCI1760,
  57        TYPE_PCI1762
  58};
  59
  60/* which I/O instructions to use */
  61enum hw_io_access {
  62        IO_8b, IO_16b
  63};
  64
  65#define MAX_DI_SUBDEVS  2       /* max number of DI subdevices per card */
  66#define MAX_DO_SUBDEVS  2       /* max number of DO subdevices per card */
  67#define MAX_DIO_SUBDEVG 2       /* max number of DIO subdevices group per card */
  68
  69#define SIZE_8255          4    /* 8255 IO space length */
  70
  71#define PCIDIO_MAINREG     2    /* main I/O region for all Advantech cards? */
  72
  73/* Register offset definitions */
  74/*  Advantech PCI-1730/3/4 */
  75#define PCI1730_IDI        0    /* R:   Isolated digital input  0-15 */
  76#define PCI1730_IDO        0    /* W:   Isolated digital output 0-15 */
  77#define PCI1730_DI         2    /* R:   Digital input  0-15 */
  78#define PCI1730_DO         2    /* W:   Digital output 0-15 */
  79#define PCI1733_IDI        0    /* R:   Isolated digital input  0-31 */
  80#define PCI1730_3_INT_EN        0x08    /* R/W: enable/disable interrupts */
  81#define PCI1730_3_INT_RF        0x0c    /* R/W: set falling/raising edge for interrupts */
  82#define PCI1730_3_INT_CLR       0x10    /* R/W: clear interrupts */
  83#define PCI1734_IDO        0    /* W:   Isolated digital output 0-31 */
  84#define PCI173x_BOARDID    4    /* R:   Board I/D switch for 1730/3/4 */
  85
  86/*  Advantech PCI-1736UP */
  87#define PCI1736_IDI        0    /* R:   Isolated digital input  0-15 */
  88#define PCI1736_IDO        0    /* W:   Isolated digital output 0-15 */
  89#define PCI1736_3_INT_EN        0x08    /* R/W: enable/disable interrupts */
  90#define PCI1736_3_INT_RF        0x0c    /* R/W: set falling/raising edge for interrupts */
  91#define PCI1736_3_INT_CLR       0x10    /* R/W: clear interrupts */
  92#define PCI1736_BOARDID    4    /* R:   Board I/D switch for 1736UP */
  93#define PCI1736_MAINREG    0    /* Normal register (2) doesn't work */
  94
  95/*  Advantech PCI-1750 */
  96#define PCI1750_IDI        0    /* R:   Isolated digital input  0-15 */
  97#define PCI1750_IDO        0    /* W:   Isolated digital output 0-15 */
  98#define PCI1750_ICR       32    /* W:   Interrupt control register */
  99#define PCI1750_ISR       32    /* R:   Interrupt status register */
 100
 101/*  Advantech PCI-1751/3/3E */
 102#define PCI1751_DIO        0    /* R/W: begin of 8255 registers block */
 103#define PCI1751_ICR       32    /* W:   Interrupt control register */
 104#define PCI1751_ISR       32    /* R:   Interrupt status register */
 105#define PCI1753_DIO        0    /* R/W: begin of 8255 registers block */
 106#define PCI1753_ICR0      16    /* R/W: Interrupt control register group 0 */
 107#define PCI1753_ICR1      17    /* R/W: Interrupt control register group 1 */
 108#define PCI1753_ICR2      18    /* R/W: Interrupt control register group 2 */
 109#define PCI1753_ICR3      19    /* R/W: Interrupt control register group 3 */
 110#define PCI1753E_DIO      32    /* R/W: begin of 8255 registers block */
 111#define PCI1753E_ICR0     48    /* R/W: Interrupt control register group 0 */
 112#define PCI1753E_ICR1     49    /* R/W: Interrupt control register group 1 */
 113#define PCI1753E_ICR2     50    /* R/W: Interrupt control register group 2 */
 114#define PCI1753E_ICR3     51    /* R/W: Interrupt control register group 3 */
 115
 116/*  Advantech PCI-1752/4/6 */
 117#define PCI1752_IDO        0    /* R/W: Digital output  0-31 */
 118#define PCI1752_IDO2       4    /* R/W: Digital output 32-63 */
 119#define PCI1754_IDI        0    /* R:   Digital input   0-31 */
 120#define PCI1754_IDI2       4    /* R:   Digital input  32-64 */
 121#define PCI1756_IDI        0    /* R:   Digital input   0-31 */
 122#define PCI1756_IDO        4    /* R/W: Digital output  0-31 */
 123#define PCI1754_6_ICR0  0x08    /* R/W: Interrupt control register group 0 */
 124#define PCI1754_6_ICR1  0x0a    /* R/W: Interrupt control register group 1 */
 125#define PCI1754_ICR2    0x0c    /* R/W: Interrupt control register group 2 */
 126#define PCI1754_ICR3    0x0e    /* R/W: Interrupt control register group 3 */
 127#define PCI1752_6_CFC   0x12    /* R/W: set/read channel freeze function */
 128#define PCI175x_BOARDID 0x10    /* R:   Board I/D switch for 1752/4/6 */
 129
 130/*  Advantech PCI-1762 registers */
 131#define PCI1762_RO         0    /* R/W: Relays status/output */
 132#define PCI1762_IDI        2    /* R:   Isolated input status */
 133#define PCI1762_BOARDID    4    /* R:   Board I/D switch */
 134#define PCI1762_ICR        6    /* W:   Interrupt control register */
 135#define PCI1762_ISR        6    /* R:   Interrupt status register */
 136
 137/*  Advantech PCI-1760 registers */
 138#define OMB0            0x0c    /* W:   Mailbox outgoing registers */
 139#define OMB1            0x0d
 140#define OMB2            0x0e
 141#define OMB3            0x0f
 142#define IMB0            0x1c    /* R:   Mailbox incoming registers */
 143#define IMB1            0x1d
 144#define IMB2            0x1e
 145#define IMB3            0x1f
 146#define INTCSR0         0x38    /* R/W: Interrupt control registers */
 147#define INTCSR1         0x39
 148#define INTCSR2         0x3a
 149#define INTCSR3         0x3b
 150
 151/*  PCI-1760 mailbox commands */
 152#define CMD_ClearIMB2           0x00    /* Clear IMB2 status and return actaul DI status in IMB3 */
 153#define CMD_SetRelaysOutput     0x01    /* Set relay output from OMB0 */
 154#define CMD_GetRelaysStatus     0x02    /* Get relay status to IMB0 */
 155#define CMD_ReadCurrentStatus   0x07    /* Read the current status of the register in OMB0, result in IMB0 */
 156#define CMD_ReadFirmwareVersion 0x0e    /* Read the firmware ver., result in IMB1.IMB0 */
 157#define CMD_ReadHardwareVersion 0x0f    /* Read the hardware ver., result in IMB1.IMB0 */
 158#define CMD_EnableIDIFilters    0x20    /* Enable IDI filters based on bits in OMB0 */
 159#define CMD_EnableIDIPatternMatch 0x21  /* Enable IDI pattern match based on bits in OMB0 */
 160#define CMD_SetIDIPatternMatch  0x22    /* Enable IDI pattern match based on bits in OMB0 */
 161#define CMD_EnableIDICounters   0x28    /* Enable IDI counters based on bits in OMB0 */
 162#define CMD_ResetIDICounters    0x29    /* Reset IDI counters based on bits in OMB0 to its reset values */
 163#define CMD_OverflowIDICounters 0x2a    /* Enable IDI counters overflow interrupts  based on bits in OMB0 */
 164#define CMD_MatchIntIDICounters 0x2b    /* Enable IDI counters match value interrupts  based on bits in OMB0 */
 165#define CMD_EdgeIDICounters     0x2c    /* Set IDI up counters count edge (bit=0 - rising, =1 - falling) */
 166#define CMD_GetIDICntCurValue   0x2f    /* Read IDI{OMB0} up counter current value */
 167#define CMD_SetIDI0CntResetValue 0x40   /* Set IDI0 Counter Reset Value 256*OMB1+OMB0 */
 168#define CMD_SetIDI1CntResetValue 0x41   /* Set IDI1 Counter Reset Value 256*OMB1+OMB0 */
 169#define CMD_SetIDI2CntResetValue 0x42   /* Set IDI2 Counter Reset Value 256*OMB1+OMB0 */
 170#define CMD_SetIDI3CntResetValue 0x43   /* Set IDI3 Counter Reset Value 256*OMB1+OMB0 */
 171#define CMD_SetIDI4CntResetValue 0x44   /* Set IDI4 Counter Reset Value 256*OMB1+OMB0 */
 172#define CMD_SetIDI5CntResetValue 0x45   /* Set IDI5 Counter Reset Value 256*OMB1+OMB0 */
 173#define CMD_SetIDI6CntResetValue 0x46   /* Set IDI6 Counter Reset Value 256*OMB1+OMB0 */
 174#define CMD_SetIDI7CntResetValue 0x47   /* Set IDI7 Counter Reset Value 256*OMB1+OMB0 */
 175#define CMD_SetIDI0CntMatchValue 0x48   /* Set IDI0 Counter Match Value 256*OMB1+OMB0 */
 176#define CMD_SetIDI1CntMatchValue 0x49   /* Set IDI1 Counter Match Value 256*OMB1+OMB0 */
 177#define CMD_SetIDI2CntMatchValue 0x4a   /* Set IDI2 Counter Match Value 256*OMB1+OMB0 */
 178#define CMD_SetIDI3CntMatchValue 0x4b   /* Set IDI3 Counter Match Value 256*OMB1+OMB0 */
 179#define CMD_SetIDI4CntMatchValue 0x4c   /* Set IDI4 Counter Match Value 256*OMB1+OMB0 */
 180#define CMD_SetIDI5CntMatchValue 0x4d   /* Set IDI5 Counter Match Value 256*OMB1+OMB0 */
 181#define CMD_SetIDI6CntMatchValue 0x4e   /* Set IDI6 Counter Match Value 256*OMB1+OMB0 */
 182#define CMD_SetIDI7CntMatchValue 0x4f   /* Set IDI7 Counter Match Value 256*OMB1+OMB0 */
 183
 184#define OMBCMD_RETRY    0x03    /* 3 times try request before error */
 185
 186static int pci_dio_attach(struct comedi_device *dev,
 187                          struct comedi_devconfig *it);
 188static int pci_dio_detach(struct comedi_device *dev);
 189
 190struct diosubd_data {
 191        int chans;              /*  num of chans */
 192        int addr;               /*  PCI address ofset */
 193        int regs;               /*  number of registers to read or 8255 subdevices */
 194        unsigned int specflags; /*  addon subdevice flags */
 195};
 196
 197struct dio_boardtype {
 198        const char *name;       /*  board name */
 199        int vendor_id;          /*  vendor/device PCI ID */
 200        int device_id;
 201        int main_pci_region;    /*  main I/O PCI region */
 202        enum hw_cards_id cardtype;
 203        struct diosubd_data sdi[MAX_DI_SUBDEVS];        /*  DI chans */
 204        struct diosubd_data sdo[MAX_DO_SUBDEVS];        /*  DO chans */
 205        struct diosubd_data sdio[MAX_DIO_SUBDEVG];      /*  DIO 8255 chans */
 206        struct diosubd_data boardid;    /*  card supports board ID switch */
 207        enum hw_io_access io_access;
 208};
 209
 210static DEFINE_PCI_DEVICE_TABLE(pci_dio_pci_table) = {
 211        {
 212        PCI_VENDOR_ID_ADVANTECH, 0x1730, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 213        PCI_VENDOR_ID_ADVANTECH, 0x1733, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 214        PCI_VENDOR_ID_ADVANTECH, 0x1734, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 215        PCI_VENDOR_ID_ADVANTECH, 0x1736, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 216        PCI_VENDOR_ID_ADVANTECH, 0x1750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 217        PCI_VENDOR_ID_ADVANTECH, 0x1751, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 218        PCI_VENDOR_ID_ADVANTECH, 0x1752, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 219        PCI_VENDOR_ID_ADVANTECH, 0x1753, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 220        PCI_VENDOR_ID_ADVANTECH, 0x1754, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 221        PCI_VENDOR_ID_ADVANTECH, 0x1756, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 222        PCI_VENDOR_ID_ADVANTECH, 0x1760, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 223        PCI_VENDOR_ID_ADVANTECH, 0x1762, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 224        0}
 225};
 226
 227MODULE_DEVICE_TABLE(pci, pci_dio_pci_table);
 228
 229static const struct dio_boardtype boardtypes[] = {
 230        {"pci1730", PCI_VENDOR_ID_ADVANTECH, 0x1730, PCIDIO_MAINREG,
 231         TYPE_PCI1730,
 232         {{16, PCI1730_DI, 2, 0}, {16, PCI1730_IDI, 2, 0}},
 233         {{16, PCI1730_DO, 2, 0}, {16, PCI1730_IDO, 2, 0}},
 234         {{0, 0, 0, 0}, {0, 0, 0, 0}},
 235         {4, PCI173x_BOARDID, 1, SDF_INTERNAL},
 236         IO_8b,
 237         },
 238        {"pci1733", PCI_VENDOR_ID_ADVANTECH, 0x1733, PCIDIO_MAINREG,
 239         TYPE_PCI1733,
 240         {{0, 0, 0, 0}, {32, PCI1733_IDI, 4, 0}},
 241         {{0, 0, 0, 0}, {0, 0, 0, 0}},
 242         {{0, 0, 0, 0}, {0, 0, 0, 0}},
 243         {4, PCI173x_BOARDID, 1, SDF_INTERNAL},
 244         IO_8b},
 245        {"pci1734", PCI_VENDOR_ID_ADVANTECH, 0x1734, PCIDIO_MAINREG,
 246         TYPE_PCI1734,
 247         {{0, 0, 0, 0}, {0, 0, 0, 0}},
 248         {{0, 0, 0, 0}, {32, PCI1734_IDO, 4, 0}},
 249         {{0, 0, 0, 0}, {0, 0, 0, 0}},
 250         {4, PCI173x_BOARDID, 1, SDF_INTERNAL},
 251         IO_8b},
 252        {"pci1736", PCI_VENDOR_ID_ADVANTECH, 0x1736, PCI1736_MAINREG,
 253         TYPE_PCI1736,
 254         {{0, 0, 0, 0}, {16, PCI1736_IDI, 2, 0}},
 255         {{0, 0, 0, 0}, {16, PCI1736_IDO, 2, 0}},
 256         {{0, 0, 0, 0}, {0, 0, 0, 0}},
 257         {4, PCI1736_BOARDID, 1, SDF_INTERNAL},
 258         IO_8b,
 259         },
 260        {"pci1750", PCI_VENDOR_ID_ADVANTECH, 0x1750, PCIDIO_MAINREG,
 261         TYPE_PCI1750,
 262         {{0, 0, 0, 0}, {16, PCI1750_IDI, 2, 0}},
 263         {{0, 0, 0, 0}, {16, PCI1750_IDO, 2, 0}},
 264         {{0, 0, 0, 0}, {0, 0, 0, 0}},
 265         {0, 0, 0, 0},
 266         IO_8b},
 267        {"pci1751", PCI_VENDOR_ID_ADVANTECH, 0x1751, PCIDIO_MAINREG,
 268         TYPE_PCI1751,
 269         {{0, 0, 0, 0}, {0, 0, 0, 0}},
 270         {{0, 0, 0, 0}, {0, 0, 0, 0}},
 271         {{48, PCI1751_DIO, 2, 0}, {0, 0, 0, 0}},
 272         {0, 0, 0, 0},
 273         IO_8b},
 274        {"pci1752", PCI_VENDOR_ID_ADVANTECH, 0x1752, PCIDIO_MAINREG,
 275         TYPE_PCI1752,
 276         {{0, 0, 0, 0}, {0, 0, 0, 0}},
 277         {{32, PCI1752_IDO, 2, 0}, {32, PCI1752_IDO2, 2, 0}},
 278         {{0, 0, 0, 0}, {0, 0, 0, 0}},
 279         {4, PCI175x_BOARDID, 1, SDF_INTERNAL},
 280         IO_16b},
 281        {"pci1753", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG,
 282         TYPE_PCI1753,
 283         {{0, 0, 0, 0}, {0, 0, 0, 0}},
 284         {{0, 0, 0, 0}, {0, 0, 0, 0}},
 285         {{96, PCI1753_DIO, 4, 0}, {0, 0, 0, 0}},
 286         {0, 0, 0, 0},
 287         IO_8b},
 288        {"pci1753e", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG,
 289         TYPE_PCI1753E,
 290         {{0, 0, 0, 0}, {0, 0, 0, 0}},
 291         {{0, 0, 0, 0}, {0, 0, 0, 0}},
 292         {{96, PCI1753_DIO, 4, 0}, {96, PCI1753E_DIO, 4, 0}},
 293         {0, 0, 0, 0},
 294         IO_8b},
 295        {"pci1754", PCI_VENDOR_ID_ADVANTECH, 0x1754, PCIDIO_MAINREG,
 296         TYPE_PCI1754,
 297         {{32, PCI1754_IDI, 2, 0}, {32, PCI1754_IDI2, 2, 0}},
 298         {{0, 0, 0, 0}, {0, 0, 0, 0}},
 299         {{0, 0, 0, 0}, {0, 0, 0, 0}},
 300         {4, PCI175x_BOARDID, 1, SDF_INTERNAL},
 301         IO_16b},
 302        {"pci1756", PCI_VENDOR_ID_ADVANTECH, 0x1756, PCIDIO_MAINREG,
 303         TYPE_PCI1756,
 304         {{0, 0, 0, 0}, {32, PCI1756_IDI, 2, 0}},
 305         {{0, 0, 0, 0}, {32, PCI1756_IDO, 2, 0}},
 306         {{0, 0, 0, 0}, {0, 0, 0, 0}},
 307         {4, PCI175x_BOARDID, 1, SDF_INTERNAL},
 308         IO_16b},
 309        {"pci1760", PCI_VENDOR_ID_ADVANTECH, 0x1760, 0,
 310         TYPE_PCI1760,
 311         {{0, 0, 0, 0}, {0, 0, 0, 0}},  /*  This card have own setup work */
 312         {{0, 0, 0, 0}, {0, 0, 0, 0}},
 313         {{0, 0, 0, 0}, {0, 0, 0, 0}},
 314         {0, 0, 0, 0},
 315         IO_8b},
 316        {"pci1762", PCI_VENDOR_ID_ADVANTECH, 0x1762, PCIDIO_MAINREG,
 317         TYPE_PCI1762,
 318         {{0, 0, 0, 0}, {16, PCI1762_IDI, 1, 0}},
 319         {{0, 0, 0, 0}, {16, PCI1762_RO, 1, 0}},
 320         {{0, 0, 0, 0}, {0, 0, 0, 0}},
 321         {4, PCI1762_BOARDID, 1, SDF_INTERNAL},
 322         IO_16b}
 323};
 324
 325#define n_boardtypes (sizeof(boardtypes)/sizeof(struct dio_boardtype))
 326
 327static struct comedi_driver driver_pci_dio = {
 328        .driver_name = "adv_pci_dio",
 329        .module = THIS_MODULE,
 330        .attach = pci_dio_attach,
 331        .detach = pci_dio_detach
 332};
 333
 334struct pci_dio_private {
 335        struct pci_dio_private *prev;   /*  previous private struct */
 336        struct pci_dio_private *next;   /*  next private struct */
 337        struct pci_dev *pcidev; /*  pointer to board's pci_dev */
 338        char valid;             /*  card is usable */
 339        char GlobalIrqEnabled;  /*  1= any IRQ source is enabled */
 340        /*  PCI-1760 specific data */
 341        unsigned char IDICntEnable;     /*  counter's counting enable status */
 342        unsigned char IDICntOverEnable; /*  counter's overflow interrupts enable status */
 343        unsigned char IDICntMatchEnable;        /*  counter's match interrupts enable status */
 344        unsigned char IDICntEdge;       /*  counter's count edge value (bit=0 - rising, =1 - falling) */
 345        unsigned short CntResValue[8];  /*  counters' reset value */
 346        unsigned short CntMatchValue[8];        /*  counters' match interrupt value */
 347        unsigned char IDIFiltersEn;     /*  IDI's digital filters enable status */
 348        unsigned char IDIPatMatchEn;    /*  IDI's pattern match enable status */
 349        unsigned char IDIPatMatchValue; /*  IDI's pattern match value */
 350        unsigned short IDIFiltrLow[8];  /*  IDI's filter value low signal */
 351        unsigned short IDIFiltrHigh[8]; /*  IDI's filter value high signal */
 352};
 353
 354static struct pci_dio_private *pci_priv = NULL; /* list of allocated cards */
 355
 356#define devpriv ((struct pci_dio_private *)dev->private)
 357#define this_board ((const struct dio_boardtype *)dev->board_ptr)
 358
 359/*
 360==============================================================================
 361*/
 362static int pci_dio_insn_bits_di_b(struct comedi_device *dev,
 363                                  struct comedi_subdevice *s,
 364                                  struct comedi_insn *insn, unsigned int *data)
 365{
 366        const struct diosubd_data *d = (const struct diosubd_data *)s->private;
 367        int i;
 368
 369        data[1] = 0;
 370        for (i = 0; i < d->regs; i++) {
 371                data[1] |= inb(dev->iobase + d->addr + i) << (8 * i);
 372        }
 373
 374        return 2;
 375}
 376
 377/*
 378==============================================================================
 379*/
 380static int pci_dio_insn_bits_di_w(struct comedi_device *dev,
 381                                  struct comedi_subdevice *s,
 382                                  struct comedi_insn *insn, unsigned int *data)
 383{
 384        const struct diosubd_data *d = (const struct diosubd_data *)s->private;
 385        int i;
 386
 387        data[1] = 0;
 388        for (i = 0; i < d->regs; i++)
 389                data[1] |= inw(dev->iobase + d->addr + 2 * i) << (16 * i);
 390
 391        return 2;
 392}
 393
 394/*
 395==============================================================================
 396*/
 397static int pci_dio_insn_bits_do_b(struct comedi_device *dev,
 398                                  struct comedi_subdevice *s,
 399                                  struct comedi_insn *insn, unsigned int *data)
 400{
 401        const struct diosubd_data *d = (const struct diosubd_data *)s->private;
 402        int i;
 403
 404        if (data[0]) {
 405                s->state &= ~data[0];
 406                s->state |= (data[0] & data[1]);
 407                for (i = 0; i < d->regs; i++)
 408                        outb((s->state >> (8 * i)) & 0xff,
 409                             dev->iobase + d->addr + i);
 410        }
 411        data[1] = s->state;
 412
 413        return 2;
 414}
 415
 416/*
 417==============================================================================
 418*/
 419static int pci_dio_insn_bits_do_w(struct comedi_device *dev,
 420                                  struct comedi_subdevice *s,
 421                                  struct comedi_insn *insn, unsigned int *data)
 422{
 423        const struct diosubd_data *d = (const struct diosubd_data *)s->private;
 424        int i;
 425
 426        if (data[0]) {
 427                s->state &= ~data[0];
 428                s->state |= (data[0] & data[1]);
 429                for (i = 0; i < d->regs; i++)
 430                        outw((s->state >> (16 * i)) & 0xffff,
 431                             dev->iobase + d->addr + 2 * i);
 432        }
 433        data[1] = s->state;
 434
 435        return 2;
 436}
 437
 438/*
 439==============================================================================
 440*/
 441static int pci1760_unchecked_mbxrequest(struct comedi_device *dev,
 442                                        unsigned char *omb, unsigned char *imb,
 443                                        int repeats)
 444{
 445        int cnt, tout, ok = 0;
 446
 447        for (cnt = 0; cnt < repeats; cnt++) {
 448                outb(omb[0], dev->iobase + OMB0);
 449                outb(omb[1], dev->iobase + OMB1);
 450                outb(omb[2], dev->iobase + OMB2);
 451                outb(omb[3], dev->iobase + OMB3);
 452                for (tout = 0; tout < 251; tout++) {
 453                        imb[2] = inb(dev->iobase + IMB2);
 454                        if (imb[2] == omb[2]) {
 455                                imb[0] = inb(dev->iobase + IMB0);
 456                                imb[1] = inb(dev->iobase + IMB1);
 457                                imb[3] = inb(dev->iobase + IMB3);
 458                                ok = 1;
 459                                break;
 460                        }
 461                        udelay(1);
 462                }
 463                if (ok)
 464                        return 0;
 465        }
 466
 467        comedi_error(dev, "PCI-1760 mailbox request timeout!");
 468        return -ETIME;
 469}
 470
 471static int pci1760_clear_imb2(struct comedi_device *dev)
 472{
 473        unsigned char omb[4] = { 0x0, 0x0, CMD_ClearIMB2, 0x0 };
 474        unsigned char imb[4];
 475        /* check if imb2 is already clear */
 476        if (inb(dev->iobase + IMB2) == CMD_ClearIMB2)
 477                return 0;
 478        return pci1760_unchecked_mbxrequest(dev, omb, imb, OMBCMD_RETRY);
 479}
 480
 481static int pci1760_mbxrequest(struct comedi_device *dev,
 482                              unsigned char *omb, unsigned char *imb)
 483{
 484        if (omb[2] == CMD_ClearIMB2) {
 485                comedi_error(dev,
 486                             "bug! this function should not be used for CMD_ClearIMB2 command");
 487                return -EINVAL;
 488        }
 489        if (inb(dev->iobase + IMB2) == omb[2]) {
 490                int retval;
 491                retval = pci1760_clear_imb2(dev);
 492                if (retval < 0)
 493                        return retval;
 494        }
 495        return pci1760_unchecked_mbxrequest(dev, omb, imb, OMBCMD_RETRY);
 496}
 497
 498/*
 499==============================================================================
 500*/
 501static int pci1760_insn_bits_di(struct comedi_device *dev,
 502                                struct comedi_subdevice *s,
 503                                struct comedi_insn *insn, unsigned int *data)
 504{
 505        data[1] = inb(dev->iobase + IMB3);
 506
 507        return 2;
 508}
 509
 510/*
 511==============================================================================
 512*/
 513static int pci1760_insn_bits_do(struct comedi_device *dev,
 514                                struct comedi_subdevice *s,
 515                                struct comedi_insn *insn, unsigned int *data)
 516{
 517        int ret;
 518        unsigned char omb[4] = {
 519                0x00,
 520                0x00,
 521                CMD_SetRelaysOutput,
 522                0x00
 523        };
 524        unsigned char imb[4];
 525
 526        if (data[0]) {
 527                s->state &= ~data[0];
 528                s->state |= (data[0] & data[1]);
 529                omb[0] = s->state;
 530                ret = pci1760_mbxrequest(dev, omb, imb);
 531                if (!ret)
 532                        return ret;
 533        }
 534        data[1] = s->state;
 535
 536        return 2;
 537}
 538
 539/*
 540==============================================================================
 541*/
 542static int pci1760_insn_cnt_read(struct comedi_device *dev,
 543                                 struct comedi_subdevice *s,
 544                                 struct comedi_insn *insn, unsigned int *data)
 545{
 546        int ret, n;
 547        unsigned char omb[4] = {
 548                CR_CHAN(insn->chanspec) & 0x07,
 549                0x00,
 550                CMD_GetIDICntCurValue,
 551                0x00
 552        };
 553        unsigned char imb[4];
 554
 555        for (n = 0; n < insn->n; n++) {
 556                ret = pci1760_mbxrequest(dev, omb, imb);
 557                if (!ret)
 558                        return ret;
 559                data[n] = (imb[1] << 8) + imb[0];
 560        }
 561
 562        return n;
 563}
 564
 565/*
 566==============================================================================
 567*/
 568static int pci1760_insn_cnt_write(struct comedi_device *dev,
 569                                  struct comedi_subdevice *s,
 570                                  struct comedi_insn *insn, unsigned int *data)
 571{
 572        int ret;
 573        unsigned char chan = CR_CHAN(insn->chanspec) & 0x07;
 574        unsigned char bitmask = 1 << chan;
 575        unsigned char omb[4] = {
 576                data[0] & 0xff,
 577                (data[0] >> 8) & 0xff,
 578                CMD_SetIDI0CntResetValue + chan,
 579                0x00
 580        };
 581        unsigned char imb[4];
 582
 583        if (devpriv->CntResValue[chan] != (data[0] & 0xffff)) { /*  Set reset value if different */
 584                ret = pci1760_mbxrequest(dev, omb, imb);
 585                if (!ret)
 586                        return ret;
 587                devpriv->CntResValue[chan] = data[0] & 0xffff;
 588        }
 589
 590        omb[0] = bitmask;       /*  reset counter to it reset value */
 591        omb[2] = CMD_ResetIDICounters;
 592        ret = pci1760_mbxrequest(dev, omb, imb);
 593        if (!ret)
 594                return ret;
 595
 596        if (!(bitmask & devpriv->IDICntEnable)) {       /*  start counter if it don't run */
 597                omb[0] = bitmask;
 598                omb[2] = CMD_EnableIDICounters;
 599                ret = pci1760_mbxrequest(dev, omb, imb);
 600                if (!ret)
 601                        return ret;
 602                devpriv->IDICntEnable |= bitmask;
 603        }
 604        return 1;
 605}
 606
 607/*
 608==============================================================================
 609*/
 610static int pci1760_reset(struct comedi_device *dev)
 611{
 612        int i;
 613        unsigned char omb[4] = { 0x00, 0x00, 0x00, 0x00 };
 614        unsigned char imb[4];
 615
 616        outb(0, dev->iobase + INTCSR0); /*  disable IRQ */
 617        outb(0, dev->iobase + INTCSR1);
 618        outb(0, dev->iobase + INTCSR2);
 619        outb(0, dev->iobase + INTCSR3);
 620        devpriv->GlobalIrqEnabled = 0;
 621
 622        omb[0] = 0x00;
 623        omb[2] = CMD_SetRelaysOutput;   /*  reset relay outputs */
 624        pci1760_mbxrequest(dev, omb, imb);
 625
 626        omb[0] = 0x00;
 627        omb[2] = CMD_EnableIDICounters; /*  disable IDI up counters */
 628        pci1760_mbxrequest(dev, omb, imb);
 629        devpriv->IDICntEnable = 0;
 630
 631        omb[0] = 0x00;
 632        omb[2] = CMD_OverflowIDICounters;       /*  disable counters overflow interrupts */
 633        pci1760_mbxrequest(dev, omb, imb);
 634        devpriv->IDICntOverEnable = 0;
 635
 636        omb[0] = 0x00;
 637        omb[2] = CMD_MatchIntIDICounters;       /*  disable counters match value interrupts */
 638        pci1760_mbxrequest(dev, omb, imb);
 639        devpriv->IDICntMatchEnable = 0;
 640
 641        omb[0] = 0x00;
 642        omb[1] = 0x80;
 643        for (i = 0; i < 8; i++) {       /*  set IDI up counters match value */
 644                omb[2] = CMD_SetIDI0CntMatchValue + i;
 645                pci1760_mbxrequest(dev, omb, imb);
 646                devpriv->CntMatchValue[i] = 0x8000;
 647        }
 648
 649        omb[0] = 0x00;
 650        omb[1] = 0x00;
 651        for (i = 0; i < 8; i++) {       /*  set IDI up counters reset value */
 652                omb[2] = CMD_SetIDI0CntResetValue + i;
 653                pci1760_mbxrequest(dev, omb, imb);
 654                devpriv->CntResValue[i] = 0x0000;
 655        }
 656
 657        omb[0] = 0xff;
 658        omb[2] = CMD_ResetIDICounters;  /*  reset IDI up counters to reset values */
 659        pci1760_mbxrequest(dev, omb, imb);
 660
 661        omb[0] = 0x00;
 662        omb[2] = CMD_EdgeIDICounters;   /*  set IDI up counters count edge */
 663        pci1760_mbxrequest(dev, omb, imb);
 664        devpriv->IDICntEdge = 0x00;
 665
 666        omb[0] = 0x00;
 667        omb[2] = CMD_EnableIDIFilters;  /*  disable all digital in filters */
 668        pci1760_mbxrequest(dev, omb, imb);
 669        devpriv->IDIFiltersEn = 0x00;
 670
 671        omb[0] = 0x00;
 672        omb[2] = CMD_EnableIDIPatternMatch;     /*  disable pattern matching */
 673        pci1760_mbxrequest(dev, omb, imb);
 674        devpriv->IDIPatMatchEn = 0x00;
 675
 676        omb[0] = 0x00;
 677        omb[2] = CMD_SetIDIPatternMatch;        /*  set pattern match value */
 678        pci1760_mbxrequest(dev, omb, imb);
 679        devpriv->IDIPatMatchValue = 0x00;
 680
 681        return 0;
 682}
 683
 684/*
 685==============================================================================
 686*/
 687static int pci_dio_reset(struct comedi_device *dev)
 688{
 689        DPRINTK("adv_pci_dio EDBG: BGN: pci171x_reset(...)\n");
 690
 691        switch (this_board->cardtype) {
 692        case TYPE_PCI1730:
 693                outb(0, dev->iobase + PCI1730_DO);      /*  clear outputs */
 694                outb(0, dev->iobase + PCI1730_DO + 1);
 695                outb(0, dev->iobase + PCI1730_IDO);
 696                outb(0, dev->iobase + PCI1730_IDO + 1);
 697                /* NO break there! */
 698        case TYPE_PCI1733:
 699                outb(0, dev->iobase + PCI1730_3_INT_EN);        /*  disable interrupts */
 700                outb(0x0f, dev->iobase + PCI1730_3_INT_CLR);    /*  clear interrupts */
 701                outb(0, dev->iobase + PCI1730_3_INT_RF);        /*  set rising edge trigger */
 702                break;
 703        case TYPE_PCI1734:
 704                outb(0, dev->iobase + PCI1734_IDO);     /*  clear outputs */
 705                outb(0, dev->iobase + PCI1734_IDO + 1);
 706                outb(0, dev->iobase + PCI1734_IDO + 2);
 707                outb(0, dev->iobase + PCI1734_IDO + 3);
 708                break;
 709
 710        case TYPE_PCI1736:
 711                outb(0, dev->iobase + PCI1736_IDO);
 712                outb(0, dev->iobase + PCI1736_IDO + 1);
 713                outb(0, dev->iobase + PCI1736_3_INT_EN);        /*  disable interrupts */
 714                outb(0x0f, dev->iobase + PCI1736_3_INT_CLR);    /*  clear interrupts */
 715                outb(0, dev->iobase + PCI1736_3_INT_RF);        /*  set rising edge trigger */
 716                break;
 717
 718        case TYPE_PCI1750:
 719        case TYPE_PCI1751:
 720                outb(0x88, dev->iobase + PCI1750_ICR);  /*  disable & clear interrupts */
 721                break;
 722        case TYPE_PCI1752:
 723                outw(0, dev->iobase + PCI1752_6_CFC);   /*  disable channel freeze function */
 724                outw(0, dev->iobase + PCI1752_IDO);     /*  clear outputs */
 725                outw(0, dev->iobase + PCI1752_IDO + 2);
 726                outw(0, dev->iobase + PCI1752_IDO2);
 727                outw(0, dev->iobase + PCI1752_IDO2 + 2);
 728                break;
 729        case TYPE_PCI1753E:
 730                outb(0x88, dev->iobase + PCI1753E_ICR0);        /*  disable & clear interrupts */
 731                outb(0x80, dev->iobase + PCI1753E_ICR1);
 732                outb(0x80, dev->iobase + PCI1753E_ICR2);
 733                outb(0x80, dev->iobase + PCI1753E_ICR3);
 734                /* NO break there! */
 735        case TYPE_PCI1753:
 736                outb(0x88, dev->iobase + PCI1753_ICR0); /*  disable & clear interrupts */
 737                outb(0x80, dev->iobase + PCI1753_ICR1);
 738                outb(0x80, dev->iobase + PCI1753_ICR2);
 739                outb(0x80, dev->iobase + PCI1753_ICR3);
 740                break;
 741        case TYPE_PCI1754:
 742                outw(0x08, dev->iobase + PCI1754_6_ICR0);       /*  disable and clear interrupts */
 743                outw(0x08, dev->iobase + PCI1754_6_ICR1);
 744                outw(0x08, dev->iobase + PCI1754_ICR2);
 745                outw(0x08, dev->iobase + PCI1754_ICR3);
 746                break;
 747        case TYPE_PCI1756:
 748                outw(0, dev->iobase + PCI1752_6_CFC);   /*  disable channel freeze function */
 749                outw(0x08, dev->iobase + PCI1754_6_ICR0);       /*  disable and clear interrupts */
 750                outw(0x08, dev->iobase + PCI1754_6_ICR1);
 751                outw(0, dev->iobase + PCI1756_IDO);     /*  clear outputs */
 752                outw(0, dev->iobase + PCI1756_IDO + 2);
 753                break;
 754        case TYPE_PCI1760:
 755                pci1760_reset(dev);
 756                break;
 757        case TYPE_PCI1762:
 758                outw(0x0101, dev->iobase + PCI1762_ICR);        /*  disable & clear interrupts */
 759                break;
 760        }
 761
 762        DPRINTK("adv_pci_dio EDBG: END: pci171x_reset(...)\n");
 763
 764        return 0;
 765}
 766
 767/*
 768==============================================================================
 769*/
 770static int pci1760_attach(struct comedi_device *dev,
 771                          struct comedi_devconfig *it)
 772{
 773        struct comedi_subdevice *s;
 774        int subdev = 0;
 775
 776        s = dev->subdevices + subdev;
 777        s->type = COMEDI_SUBD_DI;
 778        s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
 779        s->n_chan = 8;
 780        s->maxdata = 1;
 781        s->len_chanlist = 8;
 782        s->range_table = &range_digital;
 783        s->insn_bits = pci1760_insn_bits_di;
 784        subdev++;
 785
 786        s = dev->subdevices + subdev;
 787        s->type = COMEDI_SUBD_DO;
 788        s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
 789        s->n_chan = 8;
 790        s->maxdata = 1;
 791        s->len_chanlist = 8;
 792        s->range_table = &range_digital;
 793        s->state = 0;
 794        s->insn_bits = pci1760_insn_bits_do;
 795        subdev++;
 796
 797        s = dev->subdevices + subdev;
 798        s->type = COMEDI_SUBD_TIMER;
 799        s->subdev_flags = SDF_WRITABLE | SDF_LSAMPL;
 800        s->n_chan = 2;
 801        s->maxdata = 0xffffffff;
 802        s->len_chanlist = 2;
 803/*       s->insn_config=pci1760_insn_pwm_cfg; */
 804        subdev++;
 805
 806        s = dev->subdevices + subdev;
 807        s->type = COMEDI_SUBD_COUNTER;
 808        s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 809        s->n_chan = 8;
 810        s->maxdata = 0xffff;
 811        s->len_chanlist = 8;
 812        s->insn_read = pci1760_insn_cnt_read;
 813        s->insn_write = pci1760_insn_cnt_write;
 814/*       s->insn_config=pci1760_insn_cnt_cfg; */
 815        subdev++;
 816
 817        return 0;
 818}
 819
 820/*
 821==============================================================================
 822*/
 823static int pci_dio_add_di(struct comedi_device *dev, struct comedi_subdevice *s,
 824                          const struct diosubd_data *d, int subdev)
 825{
 826        s->type = COMEDI_SUBD_DI;
 827        s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | d->specflags;
 828        if (d->chans > 16)
 829                s->subdev_flags |= SDF_LSAMPL;
 830        s->n_chan = d->chans;
 831        s->maxdata = 1;
 832        s->len_chanlist = d->chans;
 833        s->range_table = &range_digital;
 834        switch (this_board->io_access) {
 835        case IO_8b:
 836                s->insn_bits = pci_dio_insn_bits_di_b;
 837                break;
 838        case IO_16b:
 839                s->insn_bits = pci_dio_insn_bits_di_w;
 840                break;
 841        }
 842        s->private = (void *)d;
 843
 844        return 0;
 845}
 846
 847/*
 848==============================================================================
 849*/
 850static int pci_dio_add_do(struct comedi_device *dev, struct comedi_subdevice *s,
 851                          const struct diosubd_data *d, int subdev)
 852{
 853        s->type = COMEDI_SUBD_DO;
 854        s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
 855        if (d->chans > 16)
 856                s->subdev_flags |= SDF_LSAMPL;
 857        s->n_chan = d->chans;
 858        s->maxdata = 1;
 859        s->len_chanlist = d->chans;
 860        s->range_table = &range_digital;
 861        s->state = 0;
 862        switch (this_board->io_access) {
 863        case IO_8b:
 864                s->insn_bits = pci_dio_insn_bits_do_b;
 865                break;
 866        case IO_16b:
 867                s->insn_bits = pci_dio_insn_bits_do_w;
 868                break;
 869        }
 870        s->private = (void *)d;
 871
 872        return 0;
 873}
 874
 875/*
 876==============================================================================
 877*/
 878static int CheckAndAllocCard(struct comedi_device *dev,
 879                             struct comedi_devconfig *it,
 880                             struct pci_dev *pcidev)
 881{
 882        struct pci_dio_private *pr, *prev;
 883
 884        for (pr = pci_priv, prev = NULL; pr != NULL; prev = pr, pr = pr->next) {
 885                if (pr->pcidev == pcidev) {
 886                        return 0;       /*  this card is used, look for another */
 887                }
 888        }
 889
 890        if (prev) {
 891                devpriv->prev = prev;
 892                prev->next = devpriv;
 893        } else {
 894                pci_priv = devpriv;
 895        }
 896
 897        devpriv->pcidev = pcidev;
 898
 899        return 1;
 900}
 901
 902/*
 903==============================================================================
 904*/
 905static int pci_dio_attach(struct comedi_device *dev,
 906                          struct comedi_devconfig *it)
 907{
 908        struct comedi_subdevice *s;
 909        int ret, subdev, n_subdevices, i, j;
 910        unsigned long iobase;
 911        struct pci_dev *pcidev;
 912
 913        printk("comedi%d: adv_pci_dio: ", dev->minor);
 914
 915        ret = alloc_private(dev, sizeof(struct pci_dio_private));
 916        if (ret < 0) {
 917                printk(", Error: Cann't allocate private memory!\n");
 918                return -ENOMEM;
 919        }
 920
 921        for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
 922             pcidev != NULL;
 923             pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
 924                /*  loop through cards supported by this driver */
 925                for (i = 0; i < n_boardtypes; ++i) {
 926                        if (boardtypes[i].vendor_id != pcidev->vendor)
 927                                continue;
 928                        if (boardtypes[i].device_id != pcidev->device)
 929                                continue;
 930                        /*  was a particular bus/slot requested? */
 931                        if (it->options[0] || it->options[1]) {
 932                                /*  are we on the wrong bus/slot? */
 933                                if (pcidev->bus->number != it->options[0] ||
 934                                    PCI_SLOT(pcidev->devfn) != it->options[1]) {
 935                                        continue;
 936                                }
 937                        }
 938                        ret = CheckAndAllocCard(dev, it, pcidev);
 939                        if (ret != 1)
 940                                continue;
 941                        dev->board_ptr = boardtypes + i;
 942                        break;
 943                }
 944                if (dev->board_ptr)
 945                        break;
 946        }
 947
 948        if (!dev->board_ptr) {
 949                printk(", Error: Requested type of the card was not found!\n");
 950                return -EIO;
 951        }
 952
 953        if (comedi_pci_enable(pcidev, driver_pci_dio.driver_name)) {
 954                printk
 955                    (", Error: Can't enable PCI device and request regions!\n");
 956                return -EIO;
 957        }
 958        iobase = pci_resource_start(pcidev, this_board->main_pci_region);
 959        printk(", b:s:f=%d:%d:%d, io=0x%4lx",
 960               pcidev->bus->number, PCI_SLOT(pcidev->devfn),
 961               PCI_FUNC(pcidev->devfn), iobase);
 962
 963        dev->iobase = iobase;
 964        dev->board_name = this_board->name;
 965
 966        if (this_board->cardtype == TYPE_PCI1760) {
 967                n_subdevices = 4;       /*  8 IDI, 8 IDO, 2 PWM, 8 CNT */
 968        } else {
 969                n_subdevices = 0;
 970                for (i = 0; i < MAX_DI_SUBDEVS; i++)
 971                        if (this_board->sdi[i].chans)
 972                                n_subdevices++;
 973                for (i = 0; i < MAX_DO_SUBDEVS; i++)
 974                        if (this_board->sdo[i].chans)
 975                                n_subdevices++;
 976                for (i = 0; i < MAX_DIO_SUBDEVG; i++)
 977                        n_subdevices += this_board->sdio[i].regs;
 978                if (this_board->boardid.chans)
 979                        n_subdevices++;
 980        }
 981
 982        ret = alloc_subdevices(dev, n_subdevices);
 983        if (ret < 0) {
 984                printk(", Error: Cann't allocate subdevice memory!\n");
 985                return ret;
 986        }
 987
 988        printk(".\n");
 989
 990        subdev = 0;
 991
 992        for (i = 0; i < MAX_DI_SUBDEVS; i++)
 993                if (this_board->sdi[i].chans) {
 994                        s = dev->subdevices + subdev;
 995                        pci_dio_add_di(dev, s, &this_board->sdi[i], subdev);
 996                        subdev++;
 997                }
 998
 999        for (i = 0; i < MAX_DO_SUBDEVS; i++)
1000                if (this_board->sdo[i].chans) {
1001                        s = dev->subdevices + subdev;
1002                        pci_dio_add_do(dev, s, &this_board->sdo[i], subdev);
1003                        subdev++;
1004                }
1005
1006        for (i = 0; i < MAX_DIO_SUBDEVG; i++)
1007                for (j = 0; j < this_board->sdio[i].regs; j++) {
1008                        s = dev->subdevices + subdev;
1009                        subdev_8255_init(dev, s, NULL,
1010                                         dev->iobase +
1011                                         this_board->sdio[i].addr +
1012                                         SIZE_8255 * j);
1013                        subdev++;
1014                }
1015
1016        if (this_board->boardid.chans) {
1017                s = dev->subdevices + subdev;
1018                s->type = COMEDI_SUBD_DI;
1019                pci_dio_add_di(dev, s, &this_board->boardid, subdev);
1020                subdev++;
1021        }
1022
1023        if (this_board->cardtype == TYPE_PCI1760)
1024                pci1760_attach(dev, it);
1025
1026        devpriv->valid = 1;
1027
1028        pci_dio_reset(dev);
1029
1030        return 0;
1031}
1032
1033/*
1034==============================================================================
1035*/
1036static int pci_dio_detach(struct comedi_device *dev)
1037{
1038        int i, j;
1039        struct comedi_subdevice *s;
1040        int subdev;
1041
1042        if (dev->private) {
1043                if (devpriv->valid) {
1044                        pci_dio_reset(dev);
1045                }
1046
1047                /* This shows the silliness of using this kind of
1048                 * scheme for numbering subdevices.  Don't do it.  --ds */
1049                subdev = 0;
1050                for (i = 0; i < MAX_DI_SUBDEVS; i++) {
1051                        if (this_board->sdi[i].chans) {
1052                                subdev++;
1053                        }
1054                }
1055                for (i = 0; i < MAX_DO_SUBDEVS; i++) {
1056                        if (this_board->sdo[i].chans) {
1057                                subdev++;
1058                        }
1059                }
1060                for (i = 0; i < MAX_DIO_SUBDEVG; i++) {
1061                        for (j = 0; j < this_board->sdio[i].regs; j++) {
1062                                s = dev->subdevices + subdev;
1063                                subdev_8255_cleanup(dev, s);
1064                                subdev++;
1065                        }
1066                }
1067
1068                for (i = 0; i < dev->n_subdevices; i++) {
1069                        s = dev->subdevices + i;
1070                        s->private = NULL;
1071                }
1072
1073                if (devpriv->pcidev) {
1074                        if (dev->iobase) {
1075                                comedi_pci_disable(devpriv->pcidev);
1076                        }
1077                        pci_dev_put(devpriv->pcidev);
1078                }
1079
1080                if (devpriv->prev) {
1081                        devpriv->prev->next = devpriv->next;
1082                } else {
1083                        pci_priv = devpriv->next;
1084                }
1085                if (devpriv->next) {
1086                        devpriv->next->prev = devpriv->prev;
1087                }
1088        }
1089
1090        return 0;
1091}
1092
1093/*
1094==============================================================================
1095*/
1096COMEDI_PCI_INITCLEANUP(driver_pci_dio, pci_dio_pci_table);
1097/*
1098==============================================================================
1099*/
1100