From 88b27f5c35ee394608773a381a1f290df1491524 Mon Sep 17 00:00:00 2001 From: David Schleef Date: Tue, 27 May 2003 17:27:43 +0000 Subject: [PATCH] Add adv_pci_dio driver from Michal Dobes --- comedi/drivers/Makefile.in | 1 + comedi/drivers/adv_pci_dio.c | 1046 ++++++++++++++++++++++++++++++++++ 2 files changed, 1047 insertions(+) create mode 100644 comedi/drivers/adv_pci_dio.c diff --git a/comedi/drivers/Makefile.in b/comedi/drivers/Makefile.in index 0b40ae6f..ab8e04a2 100644 --- a/comedi/drivers/Makefile.in +++ b/comedi/drivers/Makefile.in @@ -5,6 +5,7 @@ select(CONFIG_COMEDI_8255 8255.o) select(CONFIG_COMEDI_ADL_PCI9111 adl_pci9111.o) select(CONFIG_COMEDI_ADL_PCI9118 adl_pci9118.o amcc_s5933.o) select(CONFIG_COMEDI_ADV_PCI1710 adv_pci1710.o amcc_s5933.o) +select(CONFIG_COMEDI_ADV_PCI_DIO adv_pci_dio.o) select(CONFIG_COMEDI_AMPLC_PCI230 amplc_pci230.o) select(CONFIG_COMEDI_AMPLC_PC236 amplc_pc236.o) select(CONFIG_COMEDI_AMPLC_PC263 amplc_pc263.o) diff --git a/comedi/drivers/adv_pci_dio.c b/comedi/drivers/adv_pci_dio.c new file mode 100644 index 00000000..d138cf27 --- /dev/null +++ b/comedi/drivers/adv_pci_dio.c @@ -0,0 +1,1046 @@ +/* + * comedi/drivers/adv_pci_dio.c + * + * Author: Michal Dobes + * + * 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 +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 + +#include +#include + +#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; iregs;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; iregs; 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; iregs; 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; iregs; 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; cntiobase+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; nn; 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; nn; 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<>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; isdi[i].chans) n_subdevices++; + for (i=0; isdo[i].chans) n_subdevices++; + for (i=0; isdio[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; isdi[i].chans) { + s = dev->subdevices + subdev; + pci_dio_add_di(dev, s, &this_board->sdi[i], subdev); + subdev++; + } + + for (i=0; isdo[i].chans) { + s = dev->subdevices + subdev; + pci_dio_add_do(dev, s, &this_board->sdo[i], subdev); + subdev++; + } + + for (i=0; isdio[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; in_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); +/* +============================================================================== +*/ -- 2.26.2