/drivers/staging/comedi/drivers/adv_pci1710.c
https://bitbucket.org/wisechild/galaxy-nexus · C · 1663 lines · 1297 code · 198 blank · 168 comment · 214 complexity · 89e11d93bacbf1bb80d511b219b6b1f6 MD5 · raw file
- /*
- * comedi/drivers/adv_pci1710.c
- *
- * Author: Michal Dobes <dobes@tesnet.cz>
- *
- * Thanks to ZhenGang Shang <ZhenGang.Shang@Advantech.com.cn>
- * for testing and informations.
- *
- * hardware driver for Advantech cards:
- * card: PCI-1710, PCI-1710HG, PCI-1711, PCI-1713, PCI-1720, PCI-1731
- * driver: pci1710, pci1710hg, pci1711, pci1713, pci1720, pci1731
- *
- * Options:
- * [0] - PCI bus number - if bus number and slot number are 0,
- * then driver search for first unused card
- * [1] - PCI slot number
- *
- */
- /*
- Driver: adv_pci1710
- Description: Advantech PCI-1710, PCI-1710HG, PCI-1711, PCI-1713,
- Advantech PCI-1720, PCI-1731
- Author: Michal Dobes <dobes@tesnet.cz>
- Devices: [Advantech] PCI-1710 (adv_pci1710), PCI-1710HG (pci1710hg),
- PCI-1711 (adv_pci1710), PCI-1713, PCI-1720,
- PCI-1731
- Status: works
- This driver supports AI, AO, DI and DO subdevices.
- AI subdevice supports cmd and insn interface,
- other subdevices support only insn interface.
- The PCI-1710 and PCI-1710HG have the same PCI device ID, so the
- driver cannot distinguish between them, as would be normal for a
- PCI driver.
- 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/interrupt.h>
- #include "../comedidev.h"
- #include "comedi_pci.h"
- #include "8253.h"
- #include "amcc_s5933.h"
- #define PCI171x_PARANOIDCHECK /* if defined, then is used code which control
- * correct channel number on every 12 bit
- * sample */
- #undef PCI171X_EXTDEBUG
- #define DRV_NAME "adv_pci1710"
- #undef DPRINTK
- #ifdef PCI171X_EXTDEBUG
- #define DPRINTK(fmt, args...) printk(fmt, ## args)
- #else
- #define DPRINTK(fmt, args...)
- #endif
- #define PCI_VENDOR_ID_ADVANTECH 0x13fe
- /* hardware types of the cards */
- #define TYPE_PCI171X 0
- #define TYPE_PCI1713 2
- #define TYPE_PCI1720 3
- #define IORANGE_171x 32
- #define IORANGE_1720 16
- #define PCI171x_AD_DATA 0 /* R: A/D data */
- #define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */
- #define PCI171x_RANGE 2 /* W: A/D gain/range register */
- #define PCI171x_MUX 4 /* W: A/D multiplexor control */
- #define PCI171x_STATUS 6 /* R: status register */
- #define PCI171x_CONTROL 6 /* W: control register */
- #define PCI171x_CLRINT 8 /* W: clear interrupts request */
- #define PCI171x_CLRFIFO 9 /* W: clear FIFO */
- #define PCI171x_DA1 10 /* W: D/A register */
- #define PCI171x_DA2 12 /* W: D/A register */
- #define PCI171x_DAREF 14 /* W: D/A reference control */
- #define PCI171x_DI 16 /* R: digi inputs */
- #define PCI171x_DO 16 /* R: digi inputs */
- #define PCI171x_CNT0 24 /* R/W: 8254 counter 0 */
- #define PCI171x_CNT1 26 /* R/W: 8254 counter 1 */
- #define PCI171x_CNT2 28 /* R/W: 8254 counter 2 */
- #define PCI171x_CNTCTRL 30 /* W: 8254 counter control */
- /* upper bits from status register (PCI171x_STATUS) (lower is same with control
- * reg) */
- #define Status_FE 0x0100 /* 1=FIFO is empty */
- #define Status_FH 0x0200 /* 1=FIFO is half full */
- #define Status_FF 0x0400 /* 1=FIFO is full, fatal error */
- #define Status_IRQ 0x0800 /* 1=IRQ occurred */
- /* bits from control register (PCI171x_CONTROL) */
- #define Control_CNT0 0x0040 /* 1=CNT0 have external source,
- * 0=have internal 100kHz source */
- #define Control_ONEFH 0x0020 /* 1=IRQ on FIFO is half full, 0=every sample */
- #define Control_IRQEN 0x0010 /* 1=enable IRQ */
- #define Control_GATE 0x0008 /* 1=enable external trigger GATE (8254?) */
- #define Control_EXT 0x0004 /* 1=external trigger source */
- #define Control_PACER 0x0002 /* 1=enable internal 8254 trigger source */
- #define Control_SW 0x0001 /* 1=enable software trigger source */
- /* bits from counter control register (PCI171x_CNTCTRL) */
- #define Counter_BCD 0x0001 /* 0 = binary counter, 1 = BCD counter */
- #define Counter_M0 0x0002 /* M0-M2 select modes 0-5 */
- #define Counter_M1 0x0004 /* 000 = mode 0, 010 = mode 2 ... */
- #define Counter_M2 0x0008
- #define Counter_RW0 0x0010 /* RW0/RW1 select read/write mode */
- #define Counter_RW1 0x0020
- #define Counter_SC0 0x0040 /* Select Counter. Only 00 or 11 may */
- #define Counter_SC1 0x0080 /* be used, 00 for CNT0,
- * 11 for read-back command */
- #define PCI1720_DA0 0 /* W: D/A register 0 */
- #define PCI1720_DA1 2 /* W: D/A register 1 */
- #define PCI1720_DA2 4 /* W: D/A register 2 */
- #define PCI1720_DA3 6 /* W: D/A register 3 */
- #define PCI1720_RANGE 8 /* R/W: D/A range register */
- #define PCI1720_SYNCOUT 9 /* W: D/A synchronized output register */
- #define PCI1720_SYNCONT 15 /* R/W: D/A synchronized control */
- /* D/A synchronized control (PCI1720_SYNCONT) */
- #define Syncont_SC0 1 /* set synchronous output mode */
- static const struct comedi_lrange range_pci1710_3 = { 9, {
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- BIP_RANGE(0.625),
- BIP_RANGE(10),
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2.5),
- UNI_RANGE(1.25)
- }
- };
- static const char range_codes_pci1710_3[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
- 0x10, 0x11, 0x12, 0x13 };
- static const struct comedi_lrange range_pci1710hg = { 12, {
- BIP_RANGE(5),
- BIP_RANGE(0.5),
- BIP_RANGE(0.05),
- BIP_RANGE(0.005),
- BIP_RANGE(10),
- BIP_RANGE(1),
- BIP_RANGE(0.1),
- BIP_RANGE(0.01),
- UNI_RANGE(10),
- UNI_RANGE(1),
- UNI_RANGE(0.1),
- UNI_RANGE(0.01)
- }
- };
- static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x10, 0x11,
- 0x12, 0x13 };
- static const struct comedi_lrange range_pci17x1 = { 5, {
- BIP_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- BIP_RANGE(0.625)
- }
- };
- static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
- static const struct comedi_lrange range_pci1720 = { 4, {
- UNI_RANGE(5),
- UNI_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(10)
- }
- };
- static const struct comedi_lrange range_pci171x_da = { 2, {
- UNI_RANGE(5),
- UNI_RANGE(10),
- }
- };
- static int pci1710_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
- static int pci1710_detach(struct comedi_device *dev);
- struct boardtype {
- const char *name; /* board name */
- int device_id;
- int iorange; /* I/O range len */
- char have_irq; /* 1=card support IRQ */
- char cardtype; /* 0=1710& co. 2=1713, ... */
- int n_aichan; /* num of A/D chans */
- int n_aichand; /* num of A/D chans in diff mode */
- int n_aochan; /* num of D/A chans */
- int n_dichan; /* num of DI chans */
- int n_dochan; /* num of DO chans */
- int n_counter; /* num of counters */
- int ai_maxdata; /* resolution of A/D */
- int ao_maxdata; /* resolution of D/A */
- const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */
- const char *rangecode_ai; /* range codes for programming */
- const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */
- unsigned int ai_ns_min; /* max sample speed of card v ns */
- unsigned int fifo_half_size; /* size of FIFO/2 */
- };
- static DEFINE_PCI_DEVICE_TABLE(pci1710_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1710) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1711) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1713) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1720) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1731) },
- { 0 }
- };
- MODULE_DEVICE_TABLE(pci, pci1710_pci_table);
- static const struct boardtype boardtypes[] = {
- {"pci1710", 0x1710,
- IORANGE_171x, 1, TYPE_PCI171X,
- 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
- &range_pci1710_3, range_codes_pci1710_3,
- &range_pci171x_da,
- 10000, 2048},
- {"pci1710hg", 0x1710,
- IORANGE_171x, 1, TYPE_PCI171X,
- 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
- &range_pci1710hg, range_codes_pci1710hg,
- &range_pci171x_da,
- 10000, 2048},
- {"pci1711", 0x1711,
- IORANGE_171x, 1, TYPE_PCI171X,
- 16, 0, 2, 16, 16, 1, 0x0fff, 0x0fff,
- &range_pci17x1, range_codes_pci17x1, &range_pci171x_da,
- 10000, 512},
- {"pci1713", 0x1713,
- IORANGE_171x, 1, TYPE_PCI1713,
- 32, 16, 0, 0, 0, 0, 0x0fff, 0x0000,
- &range_pci1710_3, range_codes_pci1710_3, NULL,
- 10000, 2048},
- {"pci1720", 0x1720,
- IORANGE_1720, 0, TYPE_PCI1720,
- 0, 0, 4, 0, 0, 0, 0x0000, 0x0fff,
- NULL, NULL, &range_pci1720,
- 0, 0},
- {"pci1731", 0x1731,
- IORANGE_171x, 1, TYPE_PCI171X,
- 16, 0, 0, 16, 16, 0, 0x0fff, 0x0000,
- &range_pci17x1, range_codes_pci17x1, NULL,
- 10000, 512},
- /* dummy entry corresponding to driver name */
- {.name = DRV_NAME},
- };
- #define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
- static struct comedi_driver driver_pci1710 = {
- .driver_name = DRV_NAME,
- .module = THIS_MODULE,
- .attach = pci1710_attach,
- .detach = pci1710_detach,
- .num_names = n_boardtypes,
- .board_name = &boardtypes[0].name,
- .offset = sizeof(struct boardtype),
- };
- struct pci1710_private {
- struct pci_dev *pcidev; /* ptr to PCI device */
- char valid; /* card is usable */
- char neverending_ai; /* we do unlimited AI */
- unsigned int CntrlReg; /* Control register */
- unsigned int i8254_osc_base; /* frequence of onboard oscilator */
- unsigned int ai_do; /* what do AI? 0=nothing, 1 to 4 mode */
- unsigned int ai_act_scan; /* how many scans we finished */
- unsigned int ai_act_chan; /* actual position in actual scan */
- unsigned int ai_buf_ptr; /* data buffer ptr in samples */
- unsigned char ai_eos; /* 1=EOS wake up */
- unsigned char ai_et;
- unsigned int ai_et_CntrlReg;
- unsigned int ai_et_MuxVal;
- unsigned int ai_et_div1, ai_et_div2;
- unsigned int act_chanlist[32]; /* list of scaned channel */
- unsigned char act_chanlist_len; /* len of scanlist */
- unsigned char act_chanlist_pos; /* actual position in MUX list */
- unsigned char da_ranges; /* copy of D/A outpit range register */
- unsigned int ai_scans; /* len of scanlist */
- unsigned int ai_n_chan; /* how many channels is measured */
- unsigned int *ai_chanlist; /* actaul chanlist */
- unsigned int ai_flags; /* flaglist */
- unsigned int ai_data_len; /* len of data buffer */
- short *ai_data; /* data buffer */
- unsigned int ai_timer1; /* timers */
- unsigned int ai_timer2;
- short ao_data[4]; /* data output buffer */
- unsigned int cnt0_write_wait; /* after a write, wait for update of the
- * internal state */
- };
- #define devpriv ((struct pci1710_private *)dev->private)
- #define this_board ((const struct boardtype *)dev->board_ptr)
- /*
- ==============================================================================
- */
- static int check_channel_list(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int *chanlist, unsigned int n_chan);
- static void setup_channel_list(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int *chanlist, unsigned int n_chan,
- unsigned int seglen);
- static void start_pacer(struct comedi_device *dev, int mode,
- unsigned int divisor1, unsigned int divisor2);
- static int pci1710_reset(struct comedi_device *dev);
- static int pci171x_ai_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s);
- /* used for gain list programming */
- static const unsigned int muxonechan[] = {
- 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,
- 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
- 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
- 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
- };
- /*
- ==============================================================================
- */
- static int pci171x_insn_read_ai(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
- {
- int n, timeout;
- #ifdef PCI171x_PARANOIDCHECK
- unsigned int idata;
- #endif
- DPRINTK("adv_pci1710 EDBG: BGN: pci171x_insn_read_ai(...)\n");
- devpriv->CntrlReg &= Control_CNT0;
- devpriv->CntrlReg |= Control_SW; /* set software trigger */
- outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
- outb(0, dev->iobase + PCI171x_CLRFIFO);
- outb(0, dev->iobase + PCI171x_CLRINT);
- setup_channel_list(dev, s, &insn->chanspec, 1, 1);
- DPRINTK("adv_pci1710 A ST=%4x IO=%x\n",
- inw(dev->iobase + PCI171x_STATUS),
- dev->iobase + PCI171x_STATUS);
- for (n = 0; n < insn->n; n++) {
- outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
- DPRINTK("adv_pci1710 B n=%d ST=%4x\n", n,
- inw(dev->iobase + PCI171x_STATUS));
- /* udelay(1); */
- DPRINTK("adv_pci1710 C n=%d ST=%4x\n", n,
- inw(dev->iobase + PCI171x_STATUS));
- timeout = 100;
- while (timeout--) {
- if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE))
- goto conv_finish;
- if (!(timeout % 10))
- DPRINTK("adv_pci1710 D n=%d tm=%d ST=%4x\n", n,
- timeout,
- inw(dev->iobase + PCI171x_STATUS));
- }
- comedi_error(dev, "A/D insn timeout");
- outb(0, dev->iobase + PCI171x_CLRFIFO);
- outb(0, dev->iobase + PCI171x_CLRINT);
- data[n] = 0;
- DPRINTK
- ("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n",
- n);
- return -ETIME;
- conv_finish:
- #ifdef PCI171x_PARANOIDCHECK
- idata = inw(dev->iobase + PCI171x_AD_DATA);
- if (this_board->cardtype != TYPE_PCI1713)
- if ((idata & 0xf000) != devpriv->act_chanlist[0]) {
- comedi_error(dev, "A/D insn data droput!");
- return -ETIME;
- }
- data[n] = idata & 0x0fff;
- #else
- data[n] = inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff;
- #endif
- }
- outb(0, dev->iobase + PCI171x_CLRFIFO);
- outb(0, dev->iobase + PCI171x_CLRINT);
- DPRINTK("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n", n);
- return n;
- }
- /*
- ==============================================================================
- */
- static int pci171x_insn_write_ao(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
- {
- int n, chan, range, ofs;
- chan = CR_CHAN(insn->chanspec);
- range = CR_RANGE(insn->chanspec);
- if (chan) {
- devpriv->da_ranges &= 0xfb;
- devpriv->da_ranges |= (range << 2);
- outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
- ofs = PCI171x_DA2;
- } else {
- devpriv->da_ranges &= 0xfe;
- devpriv->da_ranges |= range;
- outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
- ofs = PCI171x_DA1;
- }
- for (n = 0; n < insn->n; n++)
- outw(data[n], dev->iobase + ofs);
- devpriv->ao_data[chan] = data[n];
- return n;
- }
- /*
- ==============================================================================
- */
- static int pci171x_insn_read_ao(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
- {
- int n, chan;
- chan = CR_CHAN(insn->chanspec);
- for (n = 0; n < insn->n; n++)
- data[n] = devpriv->ao_data[chan];
- return n;
- }
- /*
- ==============================================================================
- */
- static int pci171x_insn_bits_di(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
- {
- data[1] = inw(dev->iobase + PCI171x_DI);
- return 2;
- }
- /*
- ==============================================================================
- */
- static int pci171x_insn_bits_do(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
- {
- if (data[0]) {
- s->state &= ~data[0];
- s->state |= (data[0] & data[1]);
- outw(s->state, dev->iobase + PCI171x_DO);
- }
- data[1] = s->state;
- return 2;
- }
- /*
- ==============================================================================
- */
- static int pci171x_insn_counter_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
- {
- unsigned int msb, lsb, ccntrl;
- int i;
- ccntrl = 0xD2; /* count only */
- for (i = 0; i < insn->n; i++) {
- outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
- lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
- msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
- data[0] = lsb | (msb << 8);
- }
- return insn->n;
- }
- /*
- ==============================================================================
- */
- static int pci171x_insn_counter_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
- {
- uint msb, lsb, ccntrl, status;
- lsb = data[0] & 0x00FF;
- msb = (data[0] & 0xFF00) >> 8;
- /* write lsb, then msb */
- outw(lsb, dev->iobase + PCI171x_CNT0);
- outw(msb, dev->iobase + PCI171x_CNT0);
- if (devpriv->cnt0_write_wait) {
- /* wait for the new count to be loaded */
- ccntrl = 0xE2;
- do {
- outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
- status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
- } while (status & 0x40);
- }
- return insn->n;
- }
- /*
- ==============================================================================
- */
- static int pci171x_insn_counter_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
- {
- #ifdef unused
- /* This doesn't work like a normal Comedi counter config */
- uint ccntrl = 0;
- devpriv->cnt0_write_wait = data[0] & 0x20;
- /* internal or external clock? */
- if (!(data[0] & 0x10)) { /* internal */
- devpriv->CntrlReg &= ~Control_CNT0;
- } else {
- devpriv->CntrlReg |= Control_CNT0;
- }
- outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
- if (data[0] & 0x01)
- ccntrl |= Counter_M0;
- if (data[0] & 0x02)
- ccntrl |= Counter_M1;
- if (data[0] & 0x04)
- ccntrl |= Counter_M2;
- if (data[0] & 0x08)
- ccntrl |= Counter_BCD;
- ccntrl |= Counter_RW0; /* set read/write mode */
- ccntrl |= Counter_RW1;
- outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
- #endif
- return 1;
- }
- /*
- ==============================================================================
- */
- static int pci1720_insn_write_ao(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
- {
- int n, rangereg, chan;
- chan = CR_CHAN(insn->chanspec);
- rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1)));
- rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1));
- if (rangereg != devpriv->da_ranges) {
- outb(rangereg, dev->iobase + PCI1720_RANGE);
- devpriv->da_ranges = rangereg;
- }
- for (n = 0; n < insn->n; n++) {
- outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1));
- outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
- }
- devpriv->ao_data[chan] = data[n];
- return n;
- }
- /*
- ==============================================================================
- */
- static void interrupt_pci1710_every_sample(void *d)
- {
- struct comedi_device *dev = d;
- struct comedi_subdevice *s = dev->subdevices + 0;
- int m;
- #ifdef PCI171x_PARANOIDCHECK
- short sampl;
- #endif
- DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_every_sample(...)\n");
- m = inw(dev->iobase + PCI171x_STATUS);
- if (m & Status_FE) {
- printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m);
- pci171x_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return;
- }
- if (m & Status_FF) {
- printk
- ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
- dev->minor, m);
- pci171x_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return;
- }
- outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
- DPRINTK("FOR ");
- for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
- #ifdef PCI171x_PARANOIDCHECK
- sampl = inw(dev->iobase + PCI171x_AD_DATA);
- DPRINTK("%04x:", sampl);
- if (this_board->cardtype != TYPE_PCI1713)
- if ((sampl & 0xf000) !=
- devpriv->act_chanlist[s->async->cur_chan]) {
- printk
- ("comedi: A/D data dropout: received data from channel %d, expected %d!\n",
- (sampl & 0xf000) >> 12,
- (devpriv->
- act_chanlist[s->
- async->cur_chan] & 0xf000) >>
- 12);
- pci171x_ai_cancel(dev, s);
- s->async->events |=
- COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return;
- }
- DPRINTK("%8d %2d %8d~", s->async->buf_int_ptr,
- s->async->cur_chan, s->async->buf_int_count);
- comedi_buf_put(s->async, sampl & 0x0fff);
- #else
- comedi_buf_put(s->async,
- inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
- #endif
- ++s->async->cur_chan;
- if (s->async->cur_chan >= devpriv->ai_n_chan)
- s->async->cur_chan = 0;
- if (s->async->cur_chan == 0) { /* one scan done */
- devpriv->ai_act_scan++;
- DPRINTK
- ("adv_pci1710 EDBG: EOS1 bic %d bip %d buc %d bup %d\n",
- s->async->buf_int_count, s->async->buf_int_ptr,
- s->async->buf_user_count, s->async->buf_user_ptr);
- DPRINTK("adv_pci1710 EDBG: EOS2\n");
- if ((!devpriv->neverending_ai) && (devpriv->ai_act_scan >= devpriv->ai_scans)) { /* all data sampled */
- pci171x_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA;
- comedi_event(dev, s);
- return;
- }
- }
- }
- outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
- DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_every_sample(...)\n");
- comedi_event(dev, s);
- }
- /*
- ==============================================================================
- */
- static int move_block_from_fifo(struct comedi_device *dev,
- struct comedi_subdevice *s, int n, int turn)
- {
- int i, j;
- #ifdef PCI171x_PARANOIDCHECK
- int sampl;
- #endif
- DPRINTK("adv_pci1710 EDBG: BGN: move_block_from_fifo(...,%d,%d)\n", n,
- turn);
- j = s->async->cur_chan;
- for (i = 0; i < n; i++) {
- #ifdef PCI171x_PARANOIDCHECK
- sampl = inw(dev->iobase + PCI171x_AD_DATA);
- if (this_board->cardtype != TYPE_PCI1713)
- if ((sampl & 0xf000) != devpriv->act_chanlist[j]) {
- printk
- ("comedi%d: A/D FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n",
- dev->minor, (sampl & 0xf000) >> 12,
- (devpriv->act_chanlist[j] & 0xf000) >> 12,
- i, j, devpriv->ai_act_scan, n, turn,
- sampl);
- pci171x_ai_cancel(dev, s);
- s->async->events |=
- COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return 1;
- }
- comedi_buf_put(s->async, sampl & 0x0fff);
- #else
- comedi_buf_put(s->async,
- inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
- #endif
- j++;
- if (j >= devpriv->ai_n_chan) {
- j = 0;
- devpriv->ai_act_scan++;
- }
- }
- s->async->cur_chan = j;
- DPRINTK("adv_pci1710 EDBG: END: move_block_from_fifo(...)\n");
- return 0;
- }
- /*
- ==============================================================================
- */
- static void interrupt_pci1710_half_fifo(void *d)
- {
- struct comedi_device *dev = d;
- struct comedi_subdevice *s = dev->subdevices + 0;
- int m, samplesinbuf;
- DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_half_fifo(...)\n");
- m = inw(dev->iobase + PCI171x_STATUS);
- if (!(m & Status_FH)) {
- printk("comedi%d: A/D FIFO not half full! (%4x)\n",
- dev->minor, m);
- pci171x_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return;
- }
- if (m & Status_FF) {
- printk
- ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
- dev->minor, m);
- pci171x_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return;
- }
- samplesinbuf = this_board->fifo_half_size;
- if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) {
- m = devpriv->ai_data_len / sizeof(short);
- if (move_block_from_fifo(dev, s, m, 0))
- return;
- samplesinbuf -= m;
- }
- if (samplesinbuf) {
- if (move_block_from_fifo(dev, s, samplesinbuf, 1))
- return;
- }
- if (!devpriv->neverending_ai)
- if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data
- sampled */
- pci171x_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA;
- comedi_event(dev, s);
- return;
- }
- outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
- DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_half_fifo(...)\n");
- comedi_event(dev, s);
- }
- /*
- ==============================================================================
- */
- static irqreturn_t interrupt_service_pci1710(int irq, void *d)
- {
- struct comedi_device *dev = d;
- DPRINTK("adv_pci1710 EDBG: BGN: interrupt_service_pci1710(%d,...)\n",
- irq);
- if (!dev->attached) /* is device attached? */
- return IRQ_NONE; /* no, exit */
- if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ)) /* is this interrupt from our board? */
- return IRQ_NONE; /* no, exit */
- DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n",
- inw(dev->iobase + PCI171x_STATUS));
- if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
- devpriv->ai_et = 0;
- devpriv->CntrlReg &= Control_CNT0;
- devpriv->CntrlReg |= Control_SW; /* set software trigger */
- outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
- devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
- outb(0, dev->iobase + PCI171x_CLRFIFO);
- outb(0, dev->iobase + PCI171x_CLRINT);
- outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
- outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
- /* start pacer */
- start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2);
- return IRQ_HANDLED;
- }
- if (devpriv->ai_eos) { /* We use FIFO half full INT or not? */
- interrupt_pci1710_every_sample(d);
- } else {
- interrupt_pci1710_half_fifo(d);
- }
- DPRINTK("adv_pci1710 EDBG: END: interrupt_service_pci1710(...)\n");
- return IRQ_HANDLED;
- }
- /*
- ==============================================================================
- */
- static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
- struct comedi_subdevice *s)
- {
- unsigned int divisor1 = 0, divisor2 = 0;
- unsigned int seglen;
- DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_docmd_and_mode(%d,...)\n",
- mode);
- start_pacer(dev, -1, 0, 0); /* stop pacer */
- seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
- devpriv->ai_n_chan);
- if (seglen < 1)
- return -EINVAL;
- setup_channel_list(dev, s, devpriv->ai_chanlist,
- devpriv->ai_n_chan, seglen);
- outb(0, dev->iobase + PCI171x_CLRFIFO);
- outb(0, dev->iobase + PCI171x_CLRINT);
- devpriv->ai_do = mode;
- devpriv->ai_act_scan = 0;
- s->async->cur_chan = 0;
- devpriv->ai_buf_ptr = 0;
- devpriv->neverending_ai = 0;
- devpriv->CntrlReg &= Control_CNT0;
- if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { /* don't we want wake up every scan? devpriv->ai_eos=1; */
- devpriv->ai_eos = 1;
- } else {
- devpriv->CntrlReg |= Control_ONEFH;
- devpriv->ai_eos = 0;
- }
- if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
- devpriv->neverending_ai = 1;
- /* well, user want neverending */
- else
- devpriv->neverending_ai = 0;
- switch (mode) {
- case 1:
- case 2:
- if (devpriv->ai_timer1 < this_board->ai_ns_min)
- devpriv->ai_timer1 = this_board->ai_ns_min;
- devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
- if (mode == 2) {
- devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
- devpriv->CntrlReg &=
- ~(Control_PACER | Control_ONEFH | Control_GATE);
- devpriv->CntrlReg |= Control_EXT;
- devpriv->ai_et = 1;
- } else {
- devpriv->ai_et = 0;
- }
- i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
- &divisor2, &devpriv->ai_timer1,
- devpriv->ai_flags & TRIG_ROUND_MASK);
- DPRINTK
- ("adv_pci1710 EDBG: OSC base=%u div1=%u div2=%u timer=%u\n",
- devpriv->i8254_osc_base, divisor1, divisor2,
- devpriv->ai_timer1);
- outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
- if (mode != 2) {
- /* start pacer */
- start_pacer(dev, mode, divisor1, divisor2);
- } else {
- devpriv->ai_et_div1 = divisor1;
- devpriv->ai_et_div2 = divisor2;
- }
- break;
- case 3:
- devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
- outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
- break;
- }
- DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_docmd_and_mode(...)\n");
- return 0;
- }
- #ifdef PCI171X_EXTDEBUG
- /*
- ==============================================================================
- */
- static void pci171x_cmdtest_out(int e, struct comedi_cmd *cmd)
- {
- printk("adv_pci1710 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
- cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
- printk("adv_pci1710 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
- cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
- printk("adv_pci1710 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src,
- cmd->scan_end_src);
- printk("adv_pci1710 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
- e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
- }
- #endif
- /*
- ==============================================================================
- */
- static int pci171x_ai_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd)
- {
- int err = 0;
- int tmp;
- unsigned int divisor1 = 0, divisor2 = 0;
- DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...)\n");
- #ifdef PCI171X_EXTDEBUG
- pci171x_cmdtest_out(-1, cmd);
- #endif
- /* step 1: make sure trigger sources are trivially valid */
- tmp = cmd->start_src;
- cmd->start_src &= TRIG_NOW | TRIG_EXT;
- if (!cmd->start_src || tmp != cmd->start_src)
- err++;
- tmp = cmd->scan_begin_src;
- cmd->scan_begin_src &= TRIG_FOLLOW;
- if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
- err++;
- tmp = cmd->convert_src;
- cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
- if (!cmd->convert_src || tmp != cmd->convert_src)
- err++;
- tmp = cmd->scan_end_src;
- cmd->scan_end_src &= TRIG_COUNT;
- if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
- err++;
- tmp = cmd->stop_src;
- cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
- if (!cmd->stop_src || tmp != cmd->stop_src)
- err++;
- if (err) {
- #ifdef PCI171X_EXTDEBUG
- pci171x_cmdtest_out(1, cmd);
- #endif
- DPRINTK
- ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n",
- err);
- return 1;
- }
- /* step 2: make sure trigger sources are unique and mutually compatible */
- if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
- cmd->start_src = TRIG_NOW;
- err++;
- }
- if (cmd->scan_begin_src != TRIG_FOLLOW) {
- cmd->scan_begin_src = TRIG_FOLLOW;
- err++;
- }
- if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
- err++;
- if (cmd->scan_end_src != TRIG_COUNT) {
- cmd->scan_end_src = TRIG_COUNT;
- err++;
- }
- if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
- err++;
- if (err) {
- #ifdef PCI171X_EXTDEBUG
- pci171x_cmdtest_out(2, cmd);
- #endif
- DPRINTK
- ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n",
- err);
- return 2;
- }
- /* step 3: make sure arguments are trivially compatible */
- if (cmd->start_arg != 0) {
- cmd->start_arg = 0;
- err++;
- }
- if (cmd->scan_begin_arg != 0) {
- cmd->scan_begin_arg = 0;
- err++;
- }
- if (cmd->convert_src == TRIG_TIMER) {
- if (cmd->convert_arg < this_board->ai_ns_min) {
- cmd->convert_arg = this_board->ai_ns_min;
- err++;
- }
- } else { /* TRIG_FOLLOW */
- if (cmd->convert_arg != 0) {
- cmd->convert_arg = 0;
- err++;
- }
- }
- if (cmd->scan_end_arg != cmd->chanlist_len) {
- cmd->scan_end_arg = cmd->chanlist_len;
- err++;
- }
- if (cmd->stop_src == TRIG_COUNT) {
- if (!cmd->stop_arg) {
- cmd->stop_arg = 1;
- err++;
- }
- } else { /* TRIG_NONE */
- if (cmd->stop_arg != 0) {
- cmd->stop_arg = 0;
- err++;
- }
- }
- if (err) {
- #ifdef PCI171X_EXTDEBUG
- pci171x_cmdtest_out(3, cmd);
- #endif
- DPRINTK
- ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n",
- err);
- return 3;
- }
- /* step 4: fix up any arguments */
- if (cmd->convert_src == TRIG_TIMER) {
- tmp = cmd->convert_arg;
- i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
- &divisor2, &cmd->convert_arg,
- cmd->flags & TRIG_ROUND_MASK);
- if (cmd->convert_arg < this_board->ai_ns_min)
- cmd->convert_arg = this_board->ai_ns_min;
- if (tmp != cmd->convert_arg)
- err++;
- }
- if (err) {
- DPRINTK
- ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=4\n",
- err);
- return 4;
- }
- /* step 5: complain about special chanlist considerations */
- if (cmd->chanlist) {
- if (!check_channel_list(dev, s, cmd->chanlist,
- cmd->chanlist_len))
- return 5; /* incorrect channels list */
- }
- DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) ret=0\n");
- return 0;
- }
- /*
- ==============================================================================
- */
- static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
- {
- struct comedi_cmd *cmd = &s->async->cmd;
- DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmd(...)\n");
- devpriv->ai_n_chan = cmd->chanlist_len;
- devpriv->ai_chanlist = cmd->chanlist;
- devpriv->ai_flags = cmd->flags;
- devpriv->ai_data_len = s->async->prealloc_bufsz;
- devpriv->ai_data = s->async->prealloc_buf;
- devpriv->ai_timer1 = 0;
- devpriv->ai_timer2 = 0;
- if (cmd->stop_src == TRIG_COUNT)
- devpriv->ai_scans = cmd->stop_arg;
- else
- devpriv->ai_scans = 0;
- if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 2, 3 */
- if (cmd->convert_src == TRIG_TIMER) { /* mode 1 and 2 */
- devpriv->ai_timer1 = cmd->convert_arg;
- return pci171x_ai_docmd_and_mode(cmd->start_src ==
- TRIG_EXT ? 2 : 1, dev,
- s);
- }
- if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
- return pci171x_ai_docmd_and_mode(3, dev, s);
- }
- }
- return -1;
- }
- /*
- ==============================================================================
- Check if channel list from user is builded correctly
- If it's ok, then program scan/gain logic.
- This works for all cards.
- */
- static int check_channel_list(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int *chanlist, unsigned int n_chan)
- {
- unsigned int chansegment[32];
- unsigned int i, nowmustbechan, seglen, segpos;
- DPRINTK("adv_pci1710 EDBG: check_channel_list(...,%d)\n", n_chan);
- /* correct channel and range number check itself comedi/range.c */
- if (n_chan < 1) {
- comedi_error(dev, "range/channel list is empty!");
- return 0;
- }
- if (n_chan > 1) {
- chansegment[0] = chanlist[0]; /* first channel is every time ok */
- for (i = 1, seglen = 1; i < n_chan; i++, seglen++) { /* build part of chanlist */
- /* printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
- if (chanlist[0] == chanlist[i])
- break; /* we detect loop, this must by finish */
- if (CR_CHAN(chanlist[i]) & 1) /* odd channel cann't by differencial */
- if (CR_AREF(chanlist[i]) == AREF_DIFF) {
- comedi_error(dev,
- "Odd channel can't be differential input!\n");
- return 0;
- }
- nowmustbechan =
- (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
- if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
- nowmustbechan = (nowmustbechan + 1) % s->n_chan;
- if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continuous :-( */
- printk
- ("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
- i, CR_CHAN(chanlist[i]), nowmustbechan,
- CR_CHAN(chanlist[0]));
- return 0;
- }
- chansegment[i] = chanlist[i]; /* well, this is next correct channel in list */
- }
- for (i = 0, segpos = 0; i < n_chan; i++) { /* check whole chanlist */
- /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
- if (chanlist[i] != chansegment[i % seglen]) {
- printk
- ("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
- i, CR_CHAN(chansegment[i]),
- CR_RANGE(chansegment[i]),
- CR_AREF(chansegment[i]),
- CR_CHAN(chanlist[i % seglen]),
- CR_RANGE(chanlist[i % seglen]),
- CR_AREF(chansegment[i % seglen]));
- return 0; /* chan/gain list is strange */
- }
- }
- } else {
- seglen = 1;
- }
- return seglen;
- }
- static void setup_channel_list(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int *chanlist, unsigned int n_chan,
- unsigned int seglen)
- {
- unsigned int i, range, chanprog;
- DPRINTK("adv_pci1710 EDBG: setup_channel_list(...,%d,%d)\n", n_chan,
- seglen);
- devpriv->act_chanlist_len = seglen;
- devpriv->act_chanlist_pos = 0;
- DPRINTK("SegLen: %d\n", seglen);
- for (i = 0; i < seglen; i++) { /* store range list to card */
- chanprog = muxonechan[CR_CHAN(chanlist[i])];
- outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
- range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
- if (CR_AREF(chanlist[i]) == AREF_DIFF)
- range |= 0x0020;
- outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
- #ifdef PCI171x_PARANOIDCHECK
- devpriv->act_chanlist[i] =
- (CR_CHAN(chanlist[i]) << 12) & 0xf000;
- #endif
- DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
- devpriv->act_chanlist[i]);
- }
- #ifdef PCI171x_PARANOIDCHECK
- for ( ; i < n_chan; i++) { /* store remainder of channel list */
- devpriv->act_chanlist[i] =
- (CR_CHAN(chanlist[i]) << 12) & 0xf000;
- }
- #endif
- devpriv->ai_et_MuxVal =
- CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
- outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); /* select channel interval to scan */
- DPRINTK("MUX: %4x L%4x.H%4x\n",
- CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8),
- CR_CHAN(chanlist[0]), CR_CHAN(chanlist[seglen - 1]));
- }
- /*
- ==============================================================================
- */
- static void start_pacer(struct comedi_device *dev, int mode,
- unsigned int divisor1, unsigned int divisor2)
- {
- DPRINTK("adv_pci1710 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode,
- divisor1, divisor2);
- outw(0xb4, dev->iobase + PCI171x_CNTCTRL);
- outw(0x74, dev->iobase + PCI171x_CNTCTRL);
- if (mode == 1) {
- outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2);
- outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2);
- outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1);
- outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1);
- }
- DPRINTK("adv_pci1710 EDBG: END: start_pacer(...)\n");
- }
- /*
- ==============================================================================
- */
- static int pci171x_ai_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s)
- {
- DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cancel(...)\n");
- switch (this_board->cardtype) {
- default:
- devpriv->CntrlReg &= Control_CNT0;
- devpriv->CntrlReg |= Control_SW;
- outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
- start_pacer(dev, -1, 0, 0);
- outb(0, dev->iobase + PCI171x_CLRFIFO);
- outb(0, dev->iobase + PCI171x_CLRINT);
- break;
- }
- devpriv->ai_do = 0;
- devpriv->ai_act_scan = 0;
- s->async->cur_chan = 0;
- devpriv->ai_buf_ptr = 0;
- devpriv->neverending_ai = 0;
- DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_cancel(...)\n");
- return 0;
- }
- /*
- ==============================================================================
- */
- static int pci171x_reset(struct comedi_device *dev)
- {
- DPRINTK("adv_pci1710 EDBG: BGN: pci171x_reset(...)\n");
- outw(0x30, dev->iobase + PCI171x_CNTCTRL);
- devpriv->CntrlReg = Control_SW | Control_CNT0; /* Software trigger, CNT0=external */
- outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
- outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
- outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
- start_pacer(dev, -1, 0, 0); /* stop 8254 */
- devpriv->da_ranges = 0;
- if (this_board->n_aochan) {
- outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); /* set DACs to 0..5V */
- outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
- devpriv->ao_data[0] = 0x0000;
- if (this_board->n_aochan > 1) {
- outw(0, dev->iobase + PCI171x_DA2);
- devpriv->ao_data[1] = 0x0000;
- }
- }
- outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */
- outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
- outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
- DPRINTK("adv_pci1710 EDBG: END: pci171x_reset(...)\n");
- return 0;
- }
- /*
- ==============================================================================
- */
- static int pci1720_reset(struct comedi_device *dev)
- {
- DPRINTK("adv_pci1710 EDBG: BGN: pci1720_reset(...)\n");
- outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT); /* set synchronous output mode */
- devpriv->da_ranges = 0xAA;
- outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE); /* set all ranges to +/-5V */
- outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */
- outw(0x0800, dev->iobase + PCI1720_DA1);
- outw(0x0800, dev->iobase + PCI1720_DA2);
- outw(0x0800, dev->iobase + PCI1720_DA3);
- outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
- devpriv->ao_data[0] = 0x0800;
- devpriv->ao_data[1] = 0x0800;
- devpriv->ao_data[2] = 0x0800;
- devpriv->ao_data[3] = 0x0800;
- DPRINTK("adv_pci1710 EDBG: END: pci1720_reset(...)\n");
- return 0;
- }
- /*
- ==============================================================================
- */
- static int pci1710_reset(struct comedi_device *dev)
- {
- DPRINTK("adv_pci1710 EDBG: BGN: pci1710_reset(...)\n");
- switch (this_board->cardtype) {
- case TYPE_PCI1720:
- return pci1720_reset(dev);
- default:
- return pci171x_reset(dev);
- }
- DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n");
- }
- /*
- ==============================================================================
- */
- static int pci1710_attach(struct comedi_device *dev,
- struct comedi_devconfig *it)
- {
- struct comedi_subdevice *s;
- int ret, subdev, n_subdevices;
- unsigned int irq;
- unsigned long iobase;
- struct pci_dev *pcidev;
- int opt_bus, opt_slot;
- const char *errstr;
- unsigned char pci_bus, pci_slot, pci_func;
- int i;
- int board_index;
- printk("comedi%d: adv_pci1710: ", dev->minor);
- opt_bus = it->options[0];
- opt_slot = it->options[1];
- ret = alloc_private(dev, sizeof(struct pci1710_private));
- if (ret < 0) {
- printk(" - Allocation failed!\n");
- return -ENOMEM;
- }
- /* Look for matching PCI device */
- errstr = "not found!";
- pcidev = NULL;
- board_index = this_board - boardtypes;
- while (NULL != (pcidev = pci_get_device(PCI_VENDOR_ID_ADVANTECH,
- PCI_ANY_ID, pcidev))) {
- if (strcmp(this_board->name, DRV_NAME) == 0) {
- for (i = 0; i < n_boardtypes; ++i) {
- if (pcidev->device == boardtypes[i].device_id) {
- board_index = i;
- break;
- }
- }
- if (i == n_boardtypes)
- continue;
- } else {
- if (pcidev->device != boardtypes[board_index].device_id)
- continue;
- }
- /* Found matching vendor/device. */
- if (opt_bus || opt_slot) {
- /* Check bus/slot. */
- if (opt_bus != pcidev->bus->number
- || opt_slot != PCI_SLOT(pcidev->devfn))
- continue; /* no match */
- }
- /*
- * Look for device that isn't in use.
- * Enable PCI device and request regions.
- */
- if (comedi_pci_enable(pcidev, DRV_NAME)) {
- errstr =
- "failed to enable PCI device and request regions!";
- continue;
- }
- /* fixup board_ptr in case we were using the dummy entry with the driver name */
- dev->board_ptr = &boardtypes[board_index];
- break;
- }
- if (!pcidev) {
- if (opt_bus || opt_slot) {
- printk(" - Card at b:s %d:%d %s\n",
- opt_bus, opt_slot, errstr);
- } else {
- printk(" - Card %s\n", errstr);
- }
- return -EIO;
- }
- pci_bus = pcidev->bus->number;
- pci_slot = PCI_SLOT(pcidev->devfn);
- pci_func = PCI_FUNC(pcidev->devfn);
- irq = pcidev->irq;
- iobase = pci_resource_start(pcidev, 2);
- printk(", b:s:f=%d:%d:%d, io=0x%4lx", pci_bus, pci_slot, pci_func,
- iobase);
- dev->iobase = iobase;
- dev->board_name = this_board->name;
- devpriv->pcidev = pcidev;
- n_subdevices = 0;
- if (this_board->n_aichan)
- n_subdevices++;
- if (this_board->n_aochan)
- n_subdevices++;
- if (this_board->n_dichan)
- n_subdevices++;
- if (this_board->n_dochan)
- n_subdevices++;
- if (this_board->n_counter)
- n_subdevices++;
- ret = alloc_subdevices(dev, n_subdevices);
- if (ret < 0) {
- printk(" - Allocation failed!\n");
- return ret;
- }
- pci1710_reset(dev);
- if (this_board->have_irq) {
- if (irq) {
- if (request_irq(irq, interrupt_service_pci1710,
- IRQF_SHARED, "Advantech PCI-1710",
- dev)) {
- printk
- (", unable to allocate IRQ %d, DISABLING IT",
- irq);
- irq = 0; /* Can't use IRQ */
- } else {
- printk(", irq=%u", irq);
- }
- } else {
- printk(", IRQ disabled");
- }
- } else {
- irq = 0;
- }
- dev->irq = irq;
- printk(".\n");
- subdev = 0;
- if (this_board->n_aichan) {
- s = dev->subdevices + subdev;
- dev->read_subdev = s;
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
- if (this_board->n_aichand)
- s->subdev_flags |= SDF_DIFF;
- s->n_chan = this_board->n_aichan;
- s->maxdata = this_board->ai_maxdata;
- s->len_chanlist = this_board->n_aichan;
- s->range_table = this_board->rangelist_ai;
- s->cancel = pci171x_ai_cancel;
- s->insn_read = pci171x_insn_read_ai;
- if (irq) {
- s->subdev_flags |= SDF_CMD_READ;
- s->do_cmdtest = pci171x_ai_cmdtest;
- s->do_cmd = pci171x_ai_cmd;
- }
- devpriv->i8254_osc_base = 100; /* 100ns=10MHz */
- subdev++;
- }
- if (this_board->n_aochan) {
- s = dev->subdevices + subdev;
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
- s->n_chan = this_board->n_aochan;
- s->maxdata = this_board->ao_maxdata;
- s->len_chanlist = this_board->n_aochan;
- s->range_table = this_board->rangelist_ao;
- switch (this_board->cardtype) {
- case TYPE_PCI1720:
- s->insn_write = pci1720_insn_write_ao;
- break;
- default:
- s->insn_write = pci171x_insn_write_ao;
- break;
- }
- s->insn_read = pci171x_insn_read_ao;
- subdev++;
- }
- if (this_board->n_dichan) {
- s = dev->subdevices + subdev;
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
- s->n_chan = this_board->n_dichan;
- s->maxdata = 1;
- s->len_chanlist = this_board->n_dichan;
- s->range_table = &range_digital;
- s->io_bits = 0; /* all bits input */
- s->insn_bits = pci171x_insn_bits_di;
- subdev++;
- }
- if (this_board->n_dochan) {
- s = dev->subdevices + subdev;
- s->type = COMEDI_SUBD_DO;
- s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
- s->n_chan = this_board->n_dochan;
- s->maxdata = 1;
- s->len_chanlist = this_board->n_dochan;
- s->range_table = &range_digital;
- /* all bits output */
- s->io_bits = (1 << this_board->n_dochan) - 1;
- s->state = 0;
- s->insn_bits = pci171x_insn_bits_do;
- subdev++;
- }
- if (this_board->n_counter) {
- s = dev->subdevices + subdev;
- s->type = COMEDI_SUBD_COUNTER;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = this_board->n_counter;
- s->len_chanlist = this_board->n_counter;
- s->maxdata = 0xffff;
- s->range_table = &range_unknown;
- s->insn_read = pci171x_insn_counter_read;
- s->insn_write = pci171x_insn_counter_write;
- s->insn_config = pci171x_insn_counter_config;
- subdev++;
- }
- devpriv->valid = 1;
- return 0;
- }
- /*
- ==============================================================================
- */
- static int pci1710_detach(struct comedi_device *dev)
- {
- if (dev->private) {
- if (devpriv->valid)
- pci1710_reset(dev);
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (devpriv->pcidev) {
- if (dev->iobase)
- comedi_pci_disable(devpriv->pcidev);
- pci_dev_put(devpriv->pcidev);
- }
- }
- return 0;
- }
- /*
- ==============================================================================
- */
- static int __devinit driver_pci1710_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
- {
- return comedi_pci_auto_config(dev, driver_pci1710.driver_name);
- }
- static void __devexit driver_pci1710_pci_remove(struct pci_dev *dev)
- {
- comedi_pci_auto_unconfig(dev);
- }
- static struct pci_driver driver_pci1710_pci_driver = {
- .id_table = pci1710_pci_table,
- .probe = &driver_pci1710_pci_probe,
- .remove = __devexit_p(&driver_pci1710_pci_remove)
- };
- static int __init driver_pci1710_init_module(void)
- {
- int retval;
- retval = comedi_driver_register(&driver_pci1710);
- if (retval < 0)
- return retval;
- driver_pci1710_pci_driver.name = (char *)driver_pci1710.driver_name;
- return pci_register_driver(&driver_pci1710_pci_driver);
- }
- static void __exit driver_pci1710_cleanup_module(void)
- {
- pci_unregister_driver(&driver_pci1710_pci_driver);
- comedi_driver_unregister(&driver_pci1710);
- }
- module_init(driver_pci1710_init_module);
- module_exit(driver_pci1710_cleanup_module);
- /*
- ==============================================================================
- */
- MODULE_AUTHOR("Comedi http://www.comedi.org");
- MODULE_DESCRIPTION("Comedi low-level driver");
- MODULE_LICENSE("GPL");