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