--- /dev/null
+/*
+ * comedi/drivers/adv_pci_dio.c
+ *
+ * Author: Michal Dobes <dobes@tesnet.cz>
+ *
+ * Hardware driver for Advantech PCI DIO cards.
+*/
+/*
+Driver: adv_pci_dio.o
+Description: Advantech PCI-1730, PCI-1733, PCI-1734, PCI-1750, PCI-1751,
+ Advantech PCI-1752, PCI-1753/E, PCI-1754, PCI-1756, PCI-1762
+Author: Michal Dobes <dobes@tesnet.cz>
+Devices: [Advantech] PCI-1730 (pci1730), PCI-1733 (pci1733),
+ PCI-1734 (pci1734), PCI-1750 (pci1750), PCI-1751 (pci1751),
+ PCI-1752 (pci1752), PCI-1753 (pci1753), PCI-1753+PCI-1753E (pci1753e),
+ PCI-1754 (pci1754), PCI-1756 (pci1756), PCI-1760(pci1760),
+ PCI-1762 (pci1762)
+Status: untested
+Updated: 2003-04-06
+
+This driver supports now only insn interface for DI/DO/DIO.
+
+Configuration options:
+ [0] - PCI bus of device (optional)
+ [1] - PCI slot of device (optional)
+ If bus/slot is not specified, the first available PCI
+ device will be used.
+
+*/
+
+#include <linux/comedidev.h>
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "8255.h"
+
+#undef PCI_DIO_EXTDEBUG /* if defined, enable extensive debug logging */
+
+#undef DPRINTK
+#ifdef PCI_DIO_EXTDEBUG
+#define DPRINTK(fmt, args...) rt_printk(fmt, ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+// hardware types of the cards
+typedef enum {
+ TYPE_PCI1730, TYPE_PCI1733, TYPE_PCI1734,
+ TYPE_PCI1750,
+ TYPE_PCI1751,
+ TYPE_PCI1752,
+ TYPE_PCI1753, TYPE_PCI1753E,
+ TYPE_PCI1754, TYPE_PCI1756,
+ TYPE_PCI1760,
+ TYPE_PCI1762
+} hw_cards_id;
+
+// which I/O instructions to use
+typedef enum {
+ IO_8b, IO_16b
+} hw_io_access;
+
+#define MAX_DI_SUBDEVS 2 /* max number of DI subdevices per card */
+#define MAX_DO_SUBDEVS 2 /* max number of DO subdevices per card */
+#define MAX_DIO_SUBDEVG 2 /* max number of DIO subdevices group per card */
+
+#define SIZE_8255 4 /* 8255 IO space length */
+
+#define PCIDIO_MAINREG 2 /* main I/O region for all Advantech cards? */
+
+/* Register offset definitions */
+// Advantech PCI-1730/3/4
+#define PCI1730_IDI 0 /* R: Isolated digital input 0-15 */
+#define PCI1730_IDO 0 /* W: Isolated digital output 0-15 */
+#define PCI1730_DI 2 /* R: Digital input 0-15 */
+#define PCI1730_DO 2 /* W: Digital output 0-15 */
+#define PCI1733_IDI 0 /* R: Isolated digital input 0-31 */
+#define PCI1730_3_INT_EN 0x08 /* R/W: enable/disable interrupts */
+#define PCI1730_3_INT_RF 0x0c /* R/W: set falling/raising edge for interrupts */
+#define PCI1730_3_INT_CLR 0x10 /* R/W: clear interrupts */
+#define PCI1734_IDO 0 /* W: Isolated digital output 0-31 */
+#define PCI173x_BOARDID 4 /* R: Board I/D switch for 1730/3/4 */
+
+// Advantech PCI-1750
+#define PCI1750_IDI 0 /* R: Isolated digital input 0-15 */
+#define PCI1750_IDO 0 /* W: Isolated digital output 0-15 */
+#define PCI1750_ICR 32 /* W: Interrupt control register */
+#define PCI1750_ISR 32 /* R: Interrupt status register */
+
+// Advantech PCI-1751/3/3E
+#define PCI1751_DIO 0 /* R/W: begin of 8255 registers block */
+#define PCI1751_ICR 32 /* W: Interrupt control register */
+#define PCI1751_ISR 32 /* R: Interrupt status register */
+#define PCI1753_DIO 0 /* R/W: begin of 8255 registers block */
+#define PCI1753_ICR0 17 /* R/W: Interrupt control register group 0 */
+#define PCI1753_ICR1 18 /* R/W: Interrupt control register group 0 */
+#define PCI1753_ICR2 19 /* R/W: Interrupt control register group 0 */
+#define PCI1753_ICR3 48 /* R/W: Interrupt control register group 0 */
+#define PCI1753E_DIO 32 /* R/W: begin of 8255 registers block */
+#define PCI1753E_ICR0 49 /* R/W: Interrupt control register group 0 */
+#define PCI1753E_ICR1 50 /* R/W: Interrupt control register group 0 */
+#define PCI1753E_ICR2 51 /* R/W: Interrupt control register group 0 */
+#define PCI1753E_ICR3 52 /* R/W: Interrupt control register group 0 */
+
+
+// Advantech PCI-1752/4/6
+#define PCI1752_IDO 0 /* R/W: Digital output 0-31 */
+#define PCI1752_IDO2 4 /* R/W: Digital output 32-63 */
+#define PCI1754_IDI 0 /* R: Digital input 0-31 */
+#define PCI1754_IDI2 4 /* R: Digital input 32-64 */
+#define PCI1756_IDI 0 /* R: Digital input 0-31 */
+#define PCI1756_IDO 4 /* R/W: Digital output 0-31 */
+#define PCI1754_6_ICR0 0x08 /* R/W: Interrupt control register group 0 */
+#define PCI1754_6_ICR1 0x0a /* R/W: Interrupt control register group 1 */
+#define PCI1754_ICR2 0x0c /* R/W: Interrupt control register group 2 */
+#define PCI1754_ICR3 0x0e /* R/W: Interrupt control register group 3 */
+#define PCI1752_6_CFC 0x12 /* R/W: set/read channel freeze function */
+#define PCI175x_BOARDID 0x10 /* R: Board I/D switch for 1752/4/6 */
+
+// Advantech PCI-1762 registers
+#define PCI1762_RO 0 /* R/W: Relays status/output */
+#define PCI1762_IDI 0 /* R: Isolated input status */
+#define PCI1762_BOARDID 4 /* R: Board I/D switch */
+#define PCI1762_ICR 6 /* W: Interrupt control register */
+#define PCI1762_ISR 6 /* R: Interrupt status register */
+
+// Advantech PCI-1760 registers
+#define OMB0 0x0c /* W: Mailbox outgoing registers */
+#define OMB1 0x0d
+#define OMB2 0x0e
+#define OMB3 0x0f
+#define IMB0 0x1c /* R: Mailbox incoming registers */
+#define IMB1 0x1d
+#define IMB2 0x1e
+#define IMB3 0x1f
+#define INTCSR0 0x38 /* R/W: Interrupt control registers */
+#define INTCSR1 0x39
+#define INTCSR2 0x3a
+#define INTCSR3 0x3b
+
+// PCI-1760 mailbox commands
+#define CMD_ClearIMB2 0x00 /* Clear IMB2 status and return actaul DI status in IMB3 */
+#define CMD_SetRelaysOutput 0x01 /* Set relay output from OMB0 */
+#define CMD_GetRelaysStatus 0x02 /* Get relay status to IMB0 */
+#define CMD_ReadCurrentStatus 0x07 /* Read the current status of the register in OMB0, result in IMB0 */
+#define CMD_ReadFirmwareVersion 0x0e /* Read the firmware ver., result in IMB1.IMB0 */
+#define CMD_ReadHardwareVersion 0x0f /* Read the hardware ver., result in IMB1.IMB0 */
+#define CMD_EnableIDIFilters 0x20 /* Enable IDI filters based on bits in OMB0 */
+#define CMD_EnableIDIPatternMatch 0x21 /* Enable IDI pattern match based on bits in OMB0 */
+#define CMD_SetIDIPatternMatch 0x22 /* Enable IDI pattern match based on bits in OMB0 */
+#define CMD_EnableIDICounters 0x28 /* Enable IDI counters based on bits in OMB0 */
+#define CMD_ResetIDICounters 0x29 /* Reset IDI counters based on bits in OMB0 to its reset values */
+#define CMD_OverflowIDICounters 0x2a /* Enable IDI counters overflow interrupts based on bits in OMB0 */
+#define CMD_MatchIntIDICounters 0x2b /* Enable IDI counters match value interrupts based on bits in OMB0 */
+#define CMD_EdgeIDICounters 0x2c /* Set IDI up counters count edge (bit=0 - rising, =1 - falling) */
+#define CMD_GetIDICntCurValue 0x2f /* Read IDI{OMB0} up counter current value */
+#define CMD_SetIDI0CntResetValue 0x40 /* Set IDI0 Counter Reset Value 256*OMB1+OMB0 */
+#define CMD_SetIDI1CntResetValue 0x41 /* Set IDI1 Counter Reset Value 256*OMB1+OMB0 */
+#define CMD_SetIDI2CntResetValue 0x42 /* Set IDI2 Counter Reset Value 256*OMB1+OMB0 */
+#define CMD_SetIDI3CntResetValue 0x43 /* Set IDI3 Counter Reset Value 256*OMB1+OMB0 */
+#define CMD_SetIDI4CntResetValue 0x44 /* Set IDI4 Counter Reset Value 256*OMB1+OMB0 */
+#define CMD_SetIDI5CntResetValue 0x45 /* Set IDI5 Counter Reset Value 256*OMB1+OMB0 */
+#define CMD_SetIDI6CntResetValue 0x46 /* Set IDI6 Counter Reset Value 256*OMB1+OMB0 */
+#define CMD_SetIDI7CntResetValue 0x47 /* Set IDI7 Counter Reset Value 256*OMB1+OMB0 */
+#define CMD_SetIDI0CntMatchValue 0x48 /* Set IDI0 Counter Match Value 256*OMB1+OMB0 */
+#define CMD_SetIDI1CntMatchValue 0x49 /* Set IDI1 Counter Match Value 256*OMB1+OMB0 */
+#define CMD_SetIDI2CntMatchValue 0x4a /* Set IDI2 Counter Match Value 256*OMB1+OMB0 */
+#define CMD_SetIDI3CntMatchValue 0x4b /* Set IDI3 Counter Match Value 256*OMB1+OMB0 */
+#define CMD_SetIDI4CntMatchValue 0x4c /* Set IDI4 Counter Match Value 256*OMB1+OMB0 */
+#define CMD_SetIDI5CntMatchValue 0x4d /* Set IDI5 Counter Match Value 256*OMB1+OMB0 */
+#define CMD_SetIDI6CntMatchValue 0x4e /* Set IDI6 Counter Match Value 256*OMB1+OMB0 */
+#define CMD_SetIDI7CntMatchValue 0x4f /* Set IDI7 Counter Match Value 256*OMB1+OMB0 */
+
+#define OMBCMD_RETRY 0x03 /* 3 times try request before error */
+
+static int pci_dio_attach(comedi_device *dev,comedi_devconfig *it);
+static int pci_dio_detach(comedi_device *dev);
+
+typedef struct {
+ int chans; // num of chans
+ int addr; // PCI address ofset
+ int regs; // number of registers to read or 8255 subdevices
+ unsigned int specflags; // addon subdevice flags
+} diosubd_data;
+
+typedef struct {
+ char *name; // driver name
+ int vendor_id; // vendor/device PCI ID
+ int device_id;
+ int main_pci_region;// main I/O OCI region
+ hw_cards_id cardtype; // {enum hw_cards_id_enum}
+ diosubd_data sdi[MAX_DI_SUBDEVS]; // DI chans
+ diosubd_data sdo[MAX_DO_SUBDEVS]; // DO chans
+ diosubd_data sdio[MAX_DIO_SUBDEVG]; // DIO 8255 chans
+ diosubd_data boardid; // card supports board ID switch
+ hw_io_access io_access; // {enum hw_io_access_enum}
+} boardtype;
+
+static struct pci_device_id pci_dio_pci_table[] = __devinitdata {
+ { PCI_VENDOR_ID_ADVANTECH, 0x1730, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_ADVANTECH, 0x1733, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_ADVANTECH, 0x1734, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_ADVANTECH, 0x1750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_ADVANTECH, 0x1751, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_ADVANTECH, 0x1752, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_ADVANTECH, 0x1753, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_ADVANTECH, 0x1754, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_ADVANTECH, 0x1756, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_ADVANTECH, 0x1760, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_ADVANTECH, 0x1762, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, pci_dio_pci_table);
+
+static boardtype boardtypes[] =
+{
+ {"pci1730", PCI_VENDOR_ID_ADVANTECH, 0x1730, PCIDIO_MAINREG,
+ TYPE_PCI1730,
+ {{16, PCI1730_DI, 2, 0}, {16, PCI1730_IDI, 2, 0}},
+ {{16, PCI1730_DO, 2, 0}, {16, PCI1730_IDO, 2, 0}},
+ {{ 0, 0, 0, 0}, { 0, 0, 0, 0}},
+ { 4, PCI173x_BOARDID, 1, SDF_INTERNAL},
+ IO_8b,
+ },
+ {"pci1733", PCI_VENDOR_ID_ADVANTECH, 0x1733, PCIDIO_MAINREG,
+ TYPE_PCI1733,
+ {{ 0, 0, 0, 0}, {32, PCI1733_IDI, 4, 0}},
+ {{ 0, 0, 0, 0}, { 0, 0, 0, 0}},
+ {{ 0, 0, 0, 0}, { 0, 0, 0, 0}},
+ { 4, PCI173x_BOARDID, 1, SDF_INTERNAL},
+ IO_8b
+ },
+ {"pci1734", PCI_VENDOR_ID_ADVANTECH, 0x1734, PCIDIO_MAINREG,
+ TYPE_PCI1734,
+ {{ 0, 0, 0, 0}, { 0, 0, 0, 0}},
+ {{ 0, 0, 0, 0}, {32, PCI1734_IDO, 4, 0}},
+ {{ 0, 0, 0, 0}, { 0, 0, 0, 0}},
+ { 4, PCI173x_BOARDID, 1, SDF_INTERNAL},
+ IO_8b
+ },
+ {"pci1750", PCI_VENDOR_ID_ADVANTECH, 0x1750, PCIDIO_MAINREG,
+ TYPE_PCI1750,
+ {{ 0, 0, 0, 0}, {16, PCI1750_IDI, 2, 0}},
+ {{ 0, 0, 0, 0}, {16, PCI1750_IDO, 2, 0}},
+ {{ 0, 0, 0, 0}, { 0, 0, 0, 0}},
+ { 0, 0, 0, 0},
+ IO_8b
+ },
+ {"pci1751", PCI_VENDOR_ID_ADVANTECH, 0x1751, PCIDIO_MAINREG,
+ TYPE_PCI1751,
+ {{ 0, 0, 0, 0}, { 0, 0, 0, 0}},
+ {{ 0, 0, 0, 0}, { 0, 0, 0, 0}},
+ {{48, PCI1751_DIO, 2, 0}, { 0, 0, 0, 0}},
+ { 0, 0, 0, 0},
+ IO_8b
+ },
+ {"pci1752", PCI_VENDOR_ID_ADVANTECH, 0x1752, PCIDIO_MAINREG,
+ TYPE_PCI1752,
+ {{ 0, 0, 0, 0}, { 0, 0, 0, 0}},
+ {{32, PCI1752_IDO, 2, 0}, {32, PCI1752_IDO2, 2, 0}},
+ {{ 0, 0, 0, 0}, { 0, 0, 0, 0}},
+ { 4, PCI175x_BOARDID, 1, SDF_INTERNAL},
+ IO_16b
+ },
+ {"pci1753", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG,
+ TYPE_PCI1753,
+ {{ 0, 0, 0, 0}, { 0, 0, 0, 0}},
+ {{ 0, 0, 0, 0}, { 0, 0, 0, 0}},
+ {{96, PCI1753_DIO, 4, 0}, { 0, 0, 0, 0}},
+ { 0, 0, 0, 0},
+ IO_8b
+ },
+ {"pci1753e", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG,
+ TYPE_PCI1753E,
+ {{ 0, 0, 0, 0}, { 0, 0, 0, 0}},
+ {{ 0, 0, 0, 0}, { 0, 0, 0, 0}},
+ {{96, PCI1753_DIO, 4, 0}, {96, PCI1753E_DIO, 4, 0}},
+ { 0, 0, 0, 0},
+ IO_8b
+ },
+ {"pci1754", PCI_VENDOR_ID_ADVANTECH, 0x1754, PCIDIO_MAINREG,
+ TYPE_PCI1754,
+ {{32, PCI1754_IDI, 2, 0}, {32, PCI1754_IDI2, 2, 0}},
+ {{ 0, 0, 0, 0}, { 0, 0, 0, 0}},
+ {{ 0, 0, 0, 0}, { 0, 0, 0, 0}},
+ { 4, PCI175x_BOARDID, 1, SDF_INTERNAL},
+ IO_16b
+ },
+ {"pci1756", PCI_VENDOR_ID_ADVANTECH, 0x1756, PCIDIO_MAINREG,
+ TYPE_PCI1756,
+ {{ 0, 0, 0, 0}, {32, PCI1756_IDI, 2, 0}},
+ {{ 0, 0, 0, 0}, {32, PCI1756_IDO, 2, 0}},
+ {{ 0, 0, 0, 0}, { 0, 0, 0, 0}},
+ { 4, PCI175x_BOARDID, 1, SDF_INTERNAL},
+ IO_16b
+ },
+ {"pci1760", PCI_VENDOR_ID_ADVANTECH, 0x1760, PCIDIO_MAINREG,
+ TYPE_PCI1760,
+ {{ 0, 0, 0, 0}, { 0, 0, 0, 0}}, // This card have own setup work
+ {{ 0, 0, 0, 0}, { 0, 0, 0, 0}},
+ {{ 0, 0, 0, 0}, { 0, 0, 0, 0}},
+ { 0, 0, 0, 0},
+ IO_8b
+ },
+ {"pci1762", PCI_VENDOR_ID_ADVANTECH, 0x1762, PCIDIO_MAINREG,
+ TYPE_PCI1762,
+ {{ 0, 0, 0, 0}, {16, PCI1762_IDI, 1, 0}},
+ {{ 0, 0, 0, 0}, {16, PCI1762_RO, 1, 0}},
+ {{ 0, 0, 0, 0}, { 0, 0, 0, 0}},
+ { 4, PCI1762_BOARDID, 1, SDF_INTERNAL},
+ IO_16b
+ }
+};
+
+#define n_boardtypes (sizeof(boardtypes)/sizeof(boardtype))
+
+static comedi_driver driver_pci_dio={
+ driver_name: "adv_pci_dio",
+ module: THIS_MODULE,
+ attach: pci_dio_attach,
+ detach: pci_dio_detach,
+ num_names: n_boardtypes,
+ board_name: boardtypes,
+ offset: sizeof(boardtype),
+};
+typedef struct pci_dio_private_st pci_dio_private;
+struct pci_dio_private_st {
+ pci_dio_private *prev; // previous private struct
+ pci_dio_private *next; // next private struct
+ struct pci_dev *pcidev; // pointer to board's pci_dev
+ char valid; // card is usable
+ char enabled; // PCI card is enabled
+ char GlobalIrqEnabled;// 1= any IRQ source is enabled
+ // PCI-1760 specific data
+ unsigned char IDICntEnable; // counter's counting enable status
+ unsigned char IDICntOverEnable;// counter's overflow interrupts enable status
+ unsigned char IDICntMatchEnable;// counter's match interrupts enable status
+ unsigned char IDICntEdge; // counter's count edge value (bit=0 - rising, =1 - falling)
+ unsigned short CntResValue[8]; // counters' reset value
+ unsigned short CntMatchValue[8];// counters' match interrupt value
+ unsigned char IDIFiltersEn; // IDI's digital filters enable status
+ unsigned char IDIPatMatchEn; // IDI's pattern match enable status
+ unsigned char IDIPatMatchValue;// IDI's pattern match value
+ unsigned short IDIFiltrLow[8]; // IDI's filter value low signal
+ unsigned short IDIFiltrHigh[8];// IDI's filter value high signal
+};
+
+static pci_dio_private *pci_priv=NULL; /* list of allocated cards */
+
+#define devpriv ((pci_dio_private *)dev->private)
+#define this_board ((boardtype *)dev->board_ptr)
+
+/*
+==============================================================================
+*/
+static int pci_dio_insn_bits_di_b(comedi_device *dev, comedi_subdevice *s,
+ comedi_insn *insn, lsampl_t *data)
+{
+ diosubd_data *d=(diosubd_data *)s->private;
+ int i;
+
+ data[1]=0;
+ for (i=0; i<d->regs;i++) {
+ data[1]|=inb(dev->iobase+d->addr+i)<<(8*i);
+ }
+
+ return 2;
+}
+
+/*
+==============================================================================
+*/
+static int pci_dio_insn_bits_di_w(comedi_device *dev, comedi_subdevice *s,
+ comedi_insn *insn, lsampl_t *data)
+{
+ diosubd_data *d=(diosubd_data *)s->private;
+ int i;
+
+ data[1]=0;
+ for (i=0; i<d->regs; i++)
+ data[1]|=inw(dev->iobase+d->addr+2*i)<<(16*i);
+
+ return 2;
+}
+
+/*
+==============================================================================
+*/
+static int pci_dio_insn_bits_do_b(comedi_device *dev, comedi_subdevice *s,
+ comedi_insn *insn, lsampl_t *data)
+{
+ diosubd_data *d=(diosubd_data *)s->private;
+ int i;
+
+ if (data[0]) {
+ s->state &= ~data[0];
+ s->state |= (data[0]&data[1]);
+ for (i=0; i<d->regs; i++)
+ outb((s->state>>(8*i))&0xff, dev->iobase+d->addr+i);
+ }
+ data[1] = s->state;
+
+ return 2;
+}
+
+/*
+==============================================================================
+*/
+static int pci_dio_insn_bits_do_w(comedi_device *dev, comedi_subdevice *s,
+ comedi_insn *insn,lsampl_t *data)
+{
+ diosubd_data *d=(diosubd_data *)s->private;
+ int i;
+
+ if (data[0]) {
+ s->state &= ~data[0];
+ s->state |= (data[0]&data[1]);
+ for (i=0; i<d->regs; i++)
+ outw((s->state>>(16*i))&0xffff, dev->iobase+d->addr+2*i);
+ }
+ data[1] = s->state;
+
+ return 2;
+}
+
+
+/*
+==============================================================================
+*/
+static int pci1760_mbxrequest(comedi_device *dev, comedi_subdevice *s,
+ unsigned char *omb, unsigned char *imb,
+ int repeats)
+{
+ int cnt, tout, ok=0;
+
+ for (cnt=0; cnt<repeats; cnt++) {
+ outb(omb[0], dev->iobase+OMB0);
+ outb(omb[1], dev->iobase+OMB1);
+ outb(omb[2], dev->iobase+OMB2);
+ outb(omb[3], dev->iobase+OMB3);
+ for(tout=0; tout<251; tout++) {
+ if ((imb[2]=inb(dev->iobase+IMB2))==omb[2]) {
+ imb[0]=inb(dev->iobase+IMB0);
+ imb[1]=inb(dev->iobase+IMB1);
+ imb[3]=inb(dev->iobase+IMB3);
+ ok=1;
+ break;
+ }
+ comedi_udelay(1);
+ }
+ if (ok) return 0;
+ }
+
+ comedi_error(dev, "PCI-1760 mailbox request timeout!");
+ return -ETIME;
+}
+
+/*
+==============================================================================
+*/
+static int pci1760_insn_bits_di(comedi_device *dev, comedi_subdevice *s,
+ comedi_insn *insn, lsampl_t *data)
+{
+ int ret;
+ unsigned char omb[4]={
+ 0x00,
+ 0x00,
+ CMD_ClearIMB2,
+ 0x00};
+ unsigned char imb[4];
+
+ if (!(ret=pci1760_mbxrequest(dev, s, omb, imb, OMBCMD_RETRY)))
+ return ret;
+
+ data[1]=imb[3];
+
+ return 2;
+}
+
+/*
+==============================================================================
+*/
+static int pci1760_insn_read_di(comedi_device *dev, comedi_subdevice *s,
+ comedi_insn *insn, lsampl_t *data)
+{
+ int ret, n;
+ unsigned char omb[4]={
+ 0x00,
+ 0x00,
+ CMD_ClearIMB2,
+ 0x00};
+ unsigned char imb[4];
+
+ for (n=0; n<insn->n; n++) {
+ if (!(ret=pci1760_mbxrequest(dev, s, omb, imb, OMBCMD_RETRY)))
+ return ret;
+ data[n] = imb[3];
+ }
+
+ return n;
+}
+
+/*
+==============================================================================
+*/
+static int pci1760_insn_bits_do(comedi_device *dev, comedi_subdevice *s,
+ comedi_insn *insn, lsampl_t *data)
+{
+ int ret;
+ unsigned char omb[4]={
+ 0x00,
+ 0x00,
+ CMD_SetRelaysOutput,
+ 0x00};
+ unsigned char imb[4];
+
+ if (data[0]) {
+ s->state &= ~data[0];
+ s->state |= (data[0]&data[1]);
+ omb[0] = s->state;
+ if (!(ret=pci1760_mbxrequest(dev, s, omb, imb, OMBCMD_RETRY)))
+ return ret;
+ }
+ data[1] = s->state;
+
+ return 2;
+}
+
+/*
+==============================================================================
+*/
+static int pci1760_insn_cnt_read(comedi_device *dev, comedi_subdevice *s,
+ comedi_insn *insn, lsampl_t *data)
+{
+ int ret, n;
+ unsigned char omb[4]={
+ CR_CHAN(insn->chanspec)&0x07,
+ 0x00,
+ CMD_GetIDICntCurValue,
+ 0x00};
+ unsigned char imb[4];
+
+ for (n=0; n<insn->n; n++) {
+ if (!(ret=pci1760_mbxrequest(dev, s, omb, imb, OMBCMD_RETRY)))
+ return ret;
+ data[n] = (imb[1]<<8) + imb[0];
+ }
+
+ return n;
+}
+
+/*
+==============================================================================
+*/
+static int pci1760_insn_cnt_write(comedi_device *dev, comedi_subdevice *s,
+ comedi_insn *insn, lsampl_t *data)
+{
+ int ret;
+ unsigned char chan=CR_CHAN(insn->chanspec)&0x07;
+ unsigned char bitmask=1<<chan;
+ unsigned char omb[4]={
+ data[0]&0xff,
+ (data[0]>>8)&0xff,
+ CMD_SetIDI0CntResetValue+chan,
+ 0x00};
+ unsigned char imb[4];
+
+ if (devpriv->CntResValue[chan] != (data[0]&0xffff)) { // Set reset value if different
+ if (!(ret=pci1760_mbxrequest(dev, s, omb, imb, OMBCMD_RETRY)))
+ return ret;
+ devpriv->CntResValue[chan] = data[0]&0xffff;
+ }
+
+ omb[0] = bitmask; // reset counter to it reset value
+ omb[2] = CMD_ResetIDICounters;
+ if (!(ret=pci1760_mbxrequest(dev, s, omb, imb, OMBCMD_RETRY)))
+ return ret;
+
+ if (!(bitmask & devpriv->IDICntEnable)) { // start counter if it don't run
+ omb[0] = bitmask;
+ omb[2] = CMD_EnableIDICounters;
+ if (!(ret=pci1760_mbxrequest(dev, s, omb, imb, OMBCMD_RETRY)))
+ return ret;
+ devpriv->IDICntEnable |= bitmask;
+ }
+ return 1;
+}
+
+/*
+==============================================================================
+*/
+static int pci1760_reset(comedi_device *dev)
+{
+ int i;
+ unsigned char omb[4]={0x00, 0x00, 0x00, 0x00 };
+ unsigned char imb[4];
+
+ outb(0, dev->iobase+INTCSR0); // disable IRQ
+ outb(0, dev->iobase+INTCSR1);
+ outb(0, dev->iobase+INTCSR2);
+ outb(0, dev->iobase+INTCSR3);
+ devpriv->GlobalIrqEnabled = 0;
+
+ omb[0] = 0x00;
+ omb[2] = CMD_SetRelaysOutput; // reset relay outputs
+ pci1760_mbxrequest(dev, NULL, omb, imb, OMBCMD_RETRY);
+
+ omb[0] = 0x00;
+ omb[2] = CMD_EnableIDICounters; // disable IDI up counters
+ pci1760_mbxrequest(dev, NULL, omb, imb, OMBCMD_RETRY);
+ devpriv->IDICntEnable = 0;
+
+ omb[0] = 0x00;
+ omb[2] = CMD_OverflowIDICounters; // disable counters overflow interrupts
+ pci1760_mbxrequest(dev, NULL, omb, imb, OMBCMD_RETRY);
+ devpriv->IDICntOverEnable = 0;
+
+ omb[0] = 0x00;
+ omb[2] = CMD_MatchIntIDICounters; // disable counters match value interrupts
+ pci1760_mbxrequest(dev, NULL, omb, imb, OMBCMD_RETRY);
+ devpriv->IDICntMatchEnable = 0;
+
+ omb[0] = 0x00;
+ omb[1] = 0x80;
+ for (i=0; i<8; i++) { // set IDI up counters match value
+ omb[2] = CMD_SetIDI0CntMatchValue+i;
+ pci1760_mbxrequest(dev, NULL, omb, imb, OMBCMD_RETRY);
+ devpriv->CntMatchValue[i] = 0x8000;
+ }
+
+ omb[0] = 0x00;
+ omb[1] = 0x00;
+ for (i=0; i<8; i++) { // set IDI up counters reset value
+ omb[2] = CMD_SetIDI0CntResetValue+i;
+ pci1760_mbxrequest(dev, NULL, omb, imb, OMBCMD_RETRY);
+ devpriv->CntResValue[i] = 0x0000;
+ }
+
+ omb[0] = 0xff;
+ omb[2] = CMD_ResetIDICounters; // reset IDI up counters to reset values
+ pci1760_mbxrequest(dev, NULL, omb, imb, OMBCMD_RETRY);
+
+ omb[0] = 0x00;
+ omb[2] = CMD_EdgeIDICounters; // set IDI up counters count edge
+ pci1760_mbxrequest(dev, NULL, omb, imb, OMBCMD_RETRY);
+ devpriv->IDICntEdge = 0x00;
+
+ omb[0] = 0x00;
+ omb[2] = CMD_EnableIDIFilters; // disable all digital in filters
+ pci1760_mbxrequest(dev, NULL, omb, imb, OMBCMD_RETRY);
+ devpriv->IDIFiltersEn = 0x00;
+
+ omb[0] = 0x00;
+ omb[2] = CMD_EnableIDIPatternMatch; // disable pattern matching
+ pci1760_mbxrequest(dev, NULL, omb, imb, OMBCMD_RETRY);
+ devpriv->IDIPatMatchEn = 0x00;
+
+ omb[0] = 0x00;
+ omb[2] = CMD_SetIDIPatternMatch; // set pattern match value
+ pci1760_mbxrequest(dev, NULL, omb, imb, OMBCMD_RETRY);
+ devpriv->IDIPatMatchValue = 0x00;
+
+ return 0;
+}
+
+/*
+==============================================================================
+*/
+static int pci_dio_reset(comedi_device *dev)
+{
+ DPRINTK("adv_pci_dio EDBG: BGN: pci171x_reset(...)\n");
+
+ switch (this_board->cardtype) {
+ case TYPE_PCI1730:
+ outb(0, dev->iobase+PCI1730_DO); // clear outputs
+ outb(0, dev->iobase+PCI1730_DO+1);
+ outb(0, dev->iobase+PCI1730_IDO);
+ outb(0, dev->iobase+PCI1730_IDO+1);
+ /* NO break there! */
+ case TYPE_PCI1733:
+ outb(0, dev->iobase+PCI1730_3_INT_EN); // disable interrupts
+ outb(0x0f, dev->iobase+PCI1730_3_INT_CLR);// clear interrupts
+ outb(0, dev->iobase+PCI1730_3_INT_RF); // set rising edge trigger
+ break;
+ case TYPE_PCI1734:
+ outb(0, dev->iobase+PCI1734_IDO); // clear outputs
+ outb(0, dev->iobase+PCI1734_IDO+1);
+ outb(0, dev->iobase+PCI1734_IDO+2);
+ outb(0, dev->iobase+PCI1734_IDO+3);
+ break;
+ case TYPE_PCI1750:
+ case TYPE_PCI1751:
+ outb(0x88, dev->iobase+PCI1750_ICR); // disable & clear interrupts
+ break;
+ case TYPE_PCI1752:
+ outw(0, dev->iobase+PCI1752_6_CFC); // disable channel freeze function
+ outw(0, dev->iobase+PCI1752_IDO); // clear outputs
+ outw(0, dev->iobase+PCI1752_IDO+2);
+ outw(0, dev->iobase+PCI1752_IDO2);
+ outw(0, dev->iobase+PCI1752_IDO2+2);
+ break;
+ case TYPE_PCI1753E:
+ outb(0x88, dev->iobase+PCI1753E_ICR0); // disable & clear interrupts
+ outb(0x80, dev->iobase+PCI1753E_ICR1);
+ outb(0x80, dev->iobase+PCI1753E_ICR2);
+ outb(0x80, dev->iobase+PCI1753E_ICR3);
+ /* NO break there! */
+ case TYPE_PCI1753:
+ outb(0x88, dev->iobase+PCI1753_ICR0); // disable & clear interrupts
+ outb(0x80, dev->iobase+PCI1753_ICR1);
+ outb(0x80, dev->iobase+PCI1753_ICR2);
+ outb(0x80, dev->iobase+PCI1753_ICR3);
+ break;
+ case TYPE_PCI1754:
+ outw(0x08, dev->iobase+PCI1754_6_ICR0); // disable and clear interrupts
+ outw(0x08, dev->iobase+PCI1754_6_ICR1);
+ outw(0x08, dev->iobase+PCI1754_ICR2);
+ outw(0x08, dev->iobase+PCI1754_ICR3);
+ break;
+ case TYPE_PCI1756:
+ outw(0, dev->iobase+PCI1752_6_CFC); // disable channel freeze function
+ outw(0x08, dev->iobase+PCI1754_6_ICR0); // disable and clear interrupts
+ outw(0x08, dev->iobase+PCI1754_6_ICR1);
+ outw(0, dev->iobase+PCI1756_IDO); // clear outputs
+ outw(0, dev->iobase+PCI1756_IDO+2);
+ break;
+ case TYPE_PCI1760:
+ pci1760_reset(dev);
+ break;
+ case TYPE_PCI1762:
+ outw(0x0101, dev->iobase+PCI1750_ICR); // disable & clear interrupts
+ break;
+ }
+
+ DPRINTK("adv_pci_dio EDBG: END: pci171x_reset(...)\n");
+
+ return 0;
+}
+
+/*
+==============================================================================
+*/
+static int pci1760_attach(comedi_device *dev, comedi_devconfig *it)
+{
+ comedi_subdevice *s;
+ int subdev=0;
+
+ s = dev->subdevices + subdev;
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE|SDF_GROUND|SDF_COMMON;
+ s->n_chan = 8;
+ s->maxdata = 1;
+ s->len_chanlist = 8;
+ s->range_table = &range_digital;
+ s->io_bits=0; /* all bits input */
+ s->insn_read=pci1760_insn_read_di;
+ s->insn_bits=pci1760_insn_bits_di;
+ subdev++;
+
+ s = dev->subdevices + subdev;
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE|SDF_GROUND|SDF_COMMON;
+ s->n_chan = 8;
+ s->maxdata = 1;
+ s->len_chanlist = 8;
+ s->range_table = &range_digital;
+ s->io_bits=255; /* all bits output */
+ s->state=0;
+ s->insn_bits=pci1760_insn_bits_do;
+ subdev++;
+
+ s = dev->subdevices + subdev;
+ s->type = COMEDI_SUBD_TIMER;
+ s->subdev_flags = SDF_WRITABLE|SDF_LSAMPL;
+ s->n_chan = 2;
+ s->maxdata = 0xffffffff;
+ s->len_chanlist = 2;
+// s->insn_config=pci1760_insn_pwm_cfg;
+ subdev++;
+
+ s = dev->subdevices + subdev;
+ s->type = COMEDI_SUBD_COUNTER;
+ s->subdev_flags = SDF_READABLE|SDF_WRITABLE;
+ s->n_chan = 8;
+ s->maxdata = 0xffff;
+ s->len_chanlist = 8;
+ s->insn_read=pci1760_insn_cnt_read;
+ s->insn_write=pci1760_insn_cnt_write;
+// s->insn_config=pci1760_insn_cnt_cfg;
+ subdev++;
+
+ return 0;
+}
+
+/*
+==============================================================================
+*/
+static int pci_dio_add_di(comedi_device *dev, comedi_subdevice *s,
+ diosubd_data *d, int subdev)
+{
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE|SDF_GROUND|SDF_COMMON|d->specflags;
+ if (d->chans>16) s->subdev_flags |= SDF_LSAMPL;
+ s->n_chan = d->chans;
+ s->maxdata = 1;
+ s->len_chanlist = d->chans;
+ s->range_table = &range_digital;
+ s->io_bits=0; /* all bits input */
+ switch (this_board->io_access) {
+ case IO_8b:
+ s->insn_bits=pci_dio_insn_bits_di_b;
+ break;
+ case IO_16b:
+ s->insn_bits=pci_dio_insn_bits_di_w;
+ break;
+ }
+ s->private=d;
+
+ return 0;
+}
+
+/*
+==============================================================================
+*/
+static int pci_dio_add_do(comedi_device *dev, comedi_subdevice *s,
+ diosubd_data *d, int subdev)
+{
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE|SDF_GROUND|SDF_COMMON;
+ if (d->chans>16) s->subdev_flags |= SDF_LSAMPL;
+ s->n_chan = d->chans;
+ s->maxdata = 1;
+ s->len_chanlist = d->chans;
+ s->range_table = &range_digital;
+ s->io_bits=(1 << d->chans)-1; /* all bits output */
+ s->state=0;
+ switch (this_board->io_access) {
+ case IO_8b:
+ s->insn_bits=pci_dio_insn_bits_do_b;
+ break;
+ case IO_16b:
+ s->insn_bits=pci_dio_insn_bits_do_w;
+ break;
+ }
+ s->private=d;
+
+ return 0;
+}
+
+/*
+==============================================================================
+*/
+static int CheckAndAllocCard(comedi_device *dev, comedi_devconfig *it,
+ struct pci_dev* pcidev)
+{
+ pci_dio_private *pr, *prev;
+
+ if (!pci_priv) { // well, first card in system
+ pci_priv=devpriv;
+ return 1;
+ }
+
+ for (pr=pci_priv, prev=NULL; pr!=NULL; prev=pr, pr=pr->next)
+ if (pr->pcidev==pcidev) {
+ if (it->options[0]||it->options[1]) {
+ if ((pr->pcidev->bus->number==it->options[0])&&
+ (PCI_SLOT(pr->pcidev->devfn)==it->options[1])) {
+ rt_printk(", Error: Card on requested position is used!\n");
+ return 2;
+ }
+ }
+ return 0; // this card is used, look for another
+ }
+
+ if (prev) { devpriv->prev=prev; }
+ { pci_priv=devpriv; }
+
+ return 1;
+}
+
+/*
+==============================================================================
+*/
+static int pci_dio_attach(comedi_device *dev, comedi_devconfig *it)
+{
+ comedi_subdevice *s;
+ int ret, subdev, n_subdevices, i, j, iobase, found=0;
+ struct pci_dev* pcidev;
+
+ rt_printk("comedi%d: adv_pci_dio: board=%s",
+ dev->minor, this_board->name);
+
+ if ((ret=alloc_private(dev,sizeof(pci_dio_private)))<0) {
+ rt_printk(", Error: Cann't allocate private memory!\n");
+ return -ENOMEM;
+ }
+
+ pci_for_each_dev(pcidev) {
+ if ((pcidev->vendor!=this_board->vendor_id)||
+ (pcidev->device!=this_board->device_id))
+ continue;
+ if (it->options[0]||it->options[1]) {
+ if ((pcidev->bus->number!=it->options[0])||
+ (PCI_SLOT(pcidev->devfn)!=it->options[1])) {
+ continue;
+ }
+ }
+ ret=CheckAndAllocCard(dev, it, pcidev);
+ if (ret==1) { found=1; break; }
+ if (ret>1) {
+ pci_dio_detach(dev);
+ return -EIO;
+ }
+ }
+
+ if (!found) {
+ rt_printk(", Error: Requested type of the card was not found!\n");
+ pci_dio_detach(dev);
+ return -EIO;
+ }
+
+ iobase=pci_resource_start(pcidev, this_board->main_pci_region);
+ rt_printk(", b:s:f=%d:%d:%d, io=0x%4x",
+ pcidev->bus->number, PCI_SLOT(pcidev->devfn), PCI_FUNC(pcidev->devfn),
+ iobase);
+
+ if (pci_request_regions(pcidev, driver_pci_dio.driver_name)) {
+ pci_dio_detach(dev);
+ rt_printk(", Error: Cann't allocate PCI device!\n");
+ return -EIO;
+ }
+ devpriv->pcidev=pcidev;
+
+ if (pci_enable_device(pcidev)) {
+ pci_dio_detach(dev);
+ rt_printk(", Error: Cann't enable PCI device!\n");
+ return -EIO;
+ }
+ devpriv->enabled=1;
+
+ dev->iobase=iobase;
+ dev->board_name=this_board->name;
+
+ if (this_board->cardtype==TYPE_PCI1760) {
+ n_subdevices=4; // 8 IDI, 8 IDO, 2 PWM, 8 CNT
+ } else {
+ n_subdevices=0;
+ for (i=0; i<MAX_DI_SUBDEVS; i++)
+ if (this_board->sdi[i].chans) n_subdevices++;
+ for (i=0; i<MAX_DO_SUBDEVS; i++)
+ if (this_board->sdo[i].chans) n_subdevices++;
+ for (i=0; i<MAX_DIO_SUBDEVG; i++)
+ n_subdevices+=this_board->sdio[i].regs;
+ if (this_board->boardid.chans) n_subdevices++;
+ }
+
+ if((ret=alloc_subdevices(dev, n_subdevices))<0) {
+ rt_printk(", Error: Cann't allocate subdevice memory!\n");
+ pci_dio_detach(dev);
+ return ret;
+ }
+
+ rt_printk(".\n");
+
+ subdev=0;
+
+ for (i=0; i<MAX_DI_SUBDEVS; i++)
+ if (this_board->sdi[i].chans) {
+ s = dev->subdevices + subdev;
+ pci_dio_add_di(dev, s, &this_board->sdi[i], subdev);
+ subdev++;
+ }
+
+ for (i=0; i<MAX_DO_SUBDEVS; i++)
+ if (this_board->sdo[i].chans) {
+ s = dev->subdevices + subdev;
+ pci_dio_add_do(dev, s, &this_board->sdo[i], subdev);
+ subdev++;
+ }
+
+ for (i=0; i<MAX_DIO_SUBDEVG; i++)
+ for (j=0; j<this_board->sdio[i].regs; j++) {
+ s = dev->subdevices + subdev;
+ subdev_8255_init(dev, s, NULL,
+ dev->iobase+this_board->sdio[i].addr+SIZE_8255*j);
+ subdev++;
+ }
+
+ if (this_board->boardid.chans) {
+ s = dev->subdevices + subdev;
+ s->type = COMEDI_SUBD_DI;
+ pci_dio_add_di(dev, s, &this_board->boardid, subdev);
+ subdev++;
+ }
+
+ if (this_board->cardtype==TYPE_PCI1760)
+ pci1760_attach(dev, it);
+
+ devpriv->valid=1;
+
+ pci_dio_reset(dev);
+
+ return 0;
+}
+
+/*
+==============================================================================
+*/
+static int pci_dio_detach(comedi_device *dev)
+{
+ int i;
+ comedi_subdevice *s;
+
+ if (dev->private) {
+ if (devpriv->valid) {
+ pci_dio_reset(dev);
+ }
+
+ for (i=0; i<dev->n_subdevices; i++) {
+ s=dev->subdevices+i;
+ s->private=NULL;
+ }
+
+ if (devpriv->enabled)
+ pci_disable_device(devpriv->pcidev);
+
+ if (devpriv->pcidev)
+ pci_release_regions(devpriv->pcidev);
+
+ if (devpriv->prev) { devpriv->prev->next=devpriv->next; }
+ { pci_priv=devpriv->next; }
+ if (devpriv->next) { devpriv->next->prev=devpriv->prev; }
+
+ }
+
+ return 0;
+}
+
+/*
+==============================================================================
+*/
+COMEDI_INITCLEANUP(driver_pci_dio);
+/*
+==============================================================================
+*/