18ffdff6aSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
28ffdff6aSGreg Kroah-Hartman /*
38ffdff6aSGreg Kroah-Hartman * adv_pci1710.c
48ffdff6aSGreg Kroah-Hartman * Comedi driver for Advantech PCI-1710 series boards
58ffdff6aSGreg Kroah-Hartman * Author: Michal Dobes <dobes@tesnet.cz>
68ffdff6aSGreg Kroah-Hartman *
78ffdff6aSGreg Kroah-Hartman * Thanks to ZhenGang Shang <ZhenGang.Shang@Advantech.com.cn>
88ffdff6aSGreg Kroah-Hartman * for testing and information.
98ffdff6aSGreg Kroah-Hartman */
108ffdff6aSGreg Kroah-Hartman
118ffdff6aSGreg Kroah-Hartman /*
128ffdff6aSGreg Kroah-Hartman * Driver: adv_pci1710
138ffdff6aSGreg Kroah-Hartman * Description: Comedi driver for Advantech PCI-1710 series boards
148ffdff6aSGreg Kroah-Hartman * Devices: [Advantech] PCI-1710 (adv_pci1710), PCI-1710HG, PCI-1711,
158ffdff6aSGreg Kroah-Hartman * PCI-1713, PCI-1731
168ffdff6aSGreg Kroah-Hartman * Author: Michal Dobes <dobes@tesnet.cz>
178ffdff6aSGreg Kroah-Hartman * Updated: Fri, 29 Oct 2015 17:19:35 -0700
188ffdff6aSGreg Kroah-Hartman * Status: works
198ffdff6aSGreg Kroah-Hartman *
208ffdff6aSGreg Kroah-Hartman * Configuration options: not applicable, uses PCI auto config
218ffdff6aSGreg Kroah-Hartman *
228ffdff6aSGreg Kroah-Hartman * This driver supports AI, AO, DI and DO subdevices.
238ffdff6aSGreg Kroah-Hartman * AI subdevice supports cmd and insn interface,
248ffdff6aSGreg Kroah-Hartman * other subdevices support only insn interface.
258ffdff6aSGreg Kroah-Hartman *
268ffdff6aSGreg Kroah-Hartman * The PCI-1710 and PCI-1710HG have the same PCI device ID, so the
278ffdff6aSGreg Kroah-Hartman * driver cannot distinguish between them, as would be normal for a
288ffdff6aSGreg Kroah-Hartman * PCI driver.
298ffdff6aSGreg Kroah-Hartman */
308ffdff6aSGreg Kroah-Hartman
318ffdff6aSGreg Kroah-Hartman #include <linux/module.h>
328ffdff6aSGreg Kroah-Hartman #include <linux/interrupt.h>
33df0e68c1SIan Abbott #include <linux/comedi/comedi_pci.h>
3444fb7affSIan Abbott #include <linux/comedi/comedi_8254.h>
358ffdff6aSGreg Kroah-Hartman
368ffdff6aSGreg Kroah-Hartman #include "amcc_s5933.h"
378ffdff6aSGreg Kroah-Hartman
388ffdff6aSGreg Kroah-Hartman /*
398ffdff6aSGreg Kroah-Hartman * PCI BAR2 Register map (dev->iobase)
408ffdff6aSGreg Kroah-Hartman */
418ffdff6aSGreg Kroah-Hartman #define PCI171X_AD_DATA_REG 0x00 /* R: A/D data */
428ffdff6aSGreg Kroah-Hartman #define PCI171X_SOFTTRG_REG 0x00 /* W: soft trigger for A/D */
438ffdff6aSGreg Kroah-Hartman #define PCI171X_RANGE_REG 0x02 /* W: A/D gain/range register */
448ffdff6aSGreg Kroah-Hartman #define PCI171X_RANGE_DIFF BIT(5)
458ffdff6aSGreg Kroah-Hartman #define PCI171X_RANGE_UNI BIT(4)
468ffdff6aSGreg Kroah-Hartman #define PCI171X_RANGE_GAIN(x) (((x) & 0x7) << 0)
478ffdff6aSGreg Kroah-Hartman #define PCI171X_MUX_REG 0x04 /* W: A/D multiplexor control */
488ffdff6aSGreg Kroah-Hartman #define PCI171X_MUX_CHANH(x) (((x) & 0xff) << 8)
498ffdff6aSGreg Kroah-Hartman #define PCI171X_MUX_CHANL(x) (((x) & 0xff) << 0)
508ffdff6aSGreg Kroah-Hartman #define PCI171X_MUX_CHAN(x) (PCI171X_MUX_CHANH(x) | PCI171X_MUX_CHANL(x))
518ffdff6aSGreg Kroah-Hartman #define PCI171X_STATUS_REG 0x06 /* R: status register */
528ffdff6aSGreg Kroah-Hartman #define PCI171X_STATUS_IRQ BIT(11) /* 1=IRQ occurred */
538ffdff6aSGreg Kroah-Hartman #define PCI171X_STATUS_FF BIT(10) /* 1=FIFO is full, fatal error */
548ffdff6aSGreg Kroah-Hartman #define PCI171X_STATUS_FH BIT(9) /* 1=FIFO is half full */
558ffdff6aSGreg Kroah-Hartman #define PCI171X_STATUS_FE BIT(8) /* 1=FIFO is empty */
568ffdff6aSGreg Kroah-Hartman #define PCI171X_CTRL_REG 0x06 /* W: control register */
578ffdff6aSGreg Kroah-Hartman #define PCI171X_CTRL_CNT0 BIT(6) /* 1=ext. clk, 0=int. 100kHz clk */
588ffdff6aSGreg Kroah-Hartman #define PCI171X_CTRL_ONEFH BIT(5) /* 1=on FIFO half full, 0=on sample */
598ffdff6aSGreg Kroah-Hartman #define PCI171X_CTRL_IRQEN BIT(4) /* 1=enable IRQ */
608ffdff6aSGreg Kroah-Hartman #define PCI171X_CTRL_GATE BIT(3) /* 1=enable ext. trigger GATE (8254?) */
618ffdff6aSGreg Kroah-Hartman #define PCI171X_CTRL_EXT BIT(2) /* 1=enable ext. trigger source */
628ffdff6aSGreg Kroah-Hartman #define PCI171X_CTRL_PACER BIT(1) /* 1=enable int. 8254 trigger source */
638ffdff6aSGreg Kroah-Hartman #define PCI171X_CTRL_SW BIT(0) /* 1=enable software trigger source */
648ffdff6aSGreg Kroah-Hartman #define PCI171X_CLRINT_REG 0x08 /* W: clear interrupts request */
658ffdff6aSGreg Kroah-Hartman #define PCI171X_CLRFIFO_REG 0x09 /* W: clear FIFO */
668ffdff6aSGreg Kroah-Hartman #define PCI171X_DA_REG(x) (0x0a + ((x) * 2)) /* W: D/A register */
678ffdff6aSGreg Kroah-Hartman #define PCI171X_DAREF_REG 0x0e /* W: D/A reference control */
688ffdff6aSGreg Kroah-Hartman #define PCI171X_DAREF(c, r) (((r) & 0x3) << ((c) * 2))
698ffdff6aSGreg Kroah-Hartman #define PCI171X_DAREF_MASK(c) PCI171X_DAREF((c), 0x3)
708ffdff6aSGreg Kroah-Hartman #define PCI171X_DI_REG 0x10 /* R: digital inputs */
718ffdff6aSGreg Kroah-Hartman #define PCI171X_DO_REG 0x10 /* W: digital outputs */
728ffdff6aSGreg Kroah-Hartman #define PCI171X_TIMER_BASE 0x18 /* R/W: 8254 timer */
738ffdff6aSGreg Kroah-Hartman
748ffdff6aSGreg Kroah-Hartman static const struct comedi_lrange pci1710_ai_range = {
758ffdff6aSGreg Kroah-Hartman 9, {
768ffdff6aSGreg Kroah-Hartman BIP_RANGE(5), /* gain 1 (0x00) */
778ffdff6aSGreg Kroah-Hartman BIP_RANGE(2.5), /* gain 2 (0x01) */
788ffdff6aSGreg Kroah-Hartman BIP_RANGE(1.25), /* gain 4 (0x02) */
798ffdff6aSGreg Kroah-Hartman BIP_RANGE(0.625), /* gain 8 (0x03) */
808ffdff6aSGreg Kroah-Hartman BIP_RANGE(10), /* gain 0.5 (0x04) */
818ffdff6aSGreg Kroah-Hartman UNI_RANGE(10), /* gain 1 (0x00 | UNI) */
828ffdff6aSGreg Kroah-Hartman UNI_RANGE(5), /* gain 2 (0x01 | UNI) */
838ffdff6aSGreg Kroah-Hartman UNI_RANGE(2.5), /* gain 4 (0x02 | UNI) */
848ffdff6aSGreg Kroah-Hartman UNI_RANGE(1.25) /* gain 8 (0x03 | UNI) */
858ffdff6aSGreg Kroah-Hartman }
868ffdff6aSGreg Kroah-Hartman };
878ffdff6aSGreg Kroah-Hartman
888ffdff6aSGreg Kroah-Hartman static const struct comedi_lrange pci1710hg_ai_range = {
898ffdff6aSGreg Kroah-Hartman 12, {
908ffdff6aSGreg Kroah-Hartman BIP_RANGE(5), /* gain 1 (0x00) */
918ffdff6aSGreg Kroah-Hartman BIP_RANGE(0.5), /* gain 10 (0x01) */
928ffdff6aSGreg Kroah-Hartman BIP_RANGE(0.05), /* gain 100 (0x02) */
938ffdff6aSGreg Kroah-Hartman BIP_RANGE(0.005), /* gain 1000 (0x03) */
948ffdff6aSGreg Kroah-Hartman BIP_RANGE(10), /* gain 0.5 (0x04) */
958ffdff6aSGreg Kroah-Hartman BIP_RANGE(1), /* gain 5 (0x05) */
968ffdff6aSGreg Kroah-Hartman BIP_RANGE(0.1), /* gain 50 (0x06) */
978ffdff6aSGreg Kroah-Hartman BIP_RANGE(0.01), /* gain 500 (0x07) */
988ffdff6aSGreg Kroah-Hartman UNI_RANGE(10), /* gain 1 (0x00 | UNI) */
998ffdff6aSGreg Kroah-Hartman UNI_RANGE(1), /* gain 10 (0x01 | UNI) */
1008ffdff6aSGreg Kroah-Hartman UNI_RANGE(0.1), /* gain 100 (0x02 | UNI) */
1018ffdff6aSGreg Kroah-Hartman UNI_RANGE(0.01) /* gain 1000 (0x03 | UNI) */
1028ffdff6aSGreg Kroah-Hartman }
1038ffdff6aSGreg Kroah-Hartman };
1048ffdff6aSGreg Kroah-Hartman
1058ffdff6aSGreg Kroah-Hartman static const struct comedi_lrange pci1711_ai_range = {
1068ffdff6aSGreg Kroah-Hartman 5, {
1078ffdff6aSGreg Kroah-Hartman BIP_RANGE(10), /* gain 1 (0x00) */
1088ffdff6aSGreg Kroah-Hartman BIP_RANGE(5), /* gain 2 (0x01) */
1098ffdff6aSGreg Kroah-Hartman BIP_RANGE(2.5), /* gain 4 (0x02) */
1108ffdff6aSGreg Kroah-Hartman BIP_RANGE(1.25), /* gain 8 (0x03) */
1118ffdff6aSGreg Kroah-Hartman BIP_RANGE(0.625) /* gain 16 (0x04) */
1128ffdff6aSGreg Kroah-Hartman }
1138ffdff6aSGreg Kroah-Hartman };
1148ffdff6aSGreg Kroah-Hartman
1158ffdff6aSGreg Kroah-Hartman static const struct comedi_lrange pci171x_ao_range = {
1168ffdff6aSGreg Kroah-Hartman 3, {
1178ffdff6aSGreg Kroah-Hartman UNI_RANGE(5), /* internal -5V ref */
1188ffdff6aSGreg Kroah-Hartman UNI_RANGE(10), /* internal -10V ref */
1198ffdff6aSGreg Kroah-Hartman RANGE_ext(0, 1) /* external -Vref (+/-10V max) */
1208ffdff6aSGreg Kroah-Hartman }
1218ffdff6aSGreg Kroah-Hartman };
1228ffdff6aSGreg Kroah-Hartman
1238ffdff6aSGreg Kroah-Hartman enum pci1710_boardid {
1248ffdff6aSGreg Kroah-Hartman BOARD_PCI1710,
1258ffdff6aSGreg Kroah-Hartman BOARD_PCI1710HG,
1268ffdff6aSGreg Kroah-Hartman BOARD_PCI1711,
1278ffdff6aSGreg Kroah-Hartman BOARD_PCI1713,
1288ffdff6aSGreg Kroah-Hartman BOARD_PCI1731,
1298ffdff6aSGreg Kroah-Hartman };
1308ffdff6aSGreg Kroah-Hartman
1318ffdff6aSGreg Kroah-Hartman struct boardtype {
1328ffdff6aSGreg Kroah-Hartman const char *name;
1338ffdff6aSGreg Kroah-Hartman const struct comedi_lrange *ai_range;
1348ffdff6aSGreg Kroah-Hartman unsigned int is_pci1711:1;
1358ffdff6aSGreg Kroah-Hartman unsigned int is_pci1713:1;
1368ffdff6aSGreg Kroah-Hartman unsigned int has_ao:1;
1378ffdff6aSGreg Kroah-Hartman };
1388ffdff6aSGreg Kroah-Hartman
1398ffdff6aSGreg Kroah-Hartman static const struct boardtype boardtypes[] = {
1408ffdff6aSGreg Kroah-Hartman [BOARD_PCI1710] = {
1418ffdff6aSGreg Kroah-Hartman .name = "pci1710",
1428ffdff6aSGreg Kroah-Hartman .ai_range = &pci1710_ai_range,
1438ffdff6aSGreg Kroah-Hartman .has_ao = 1,
1448ffdff6aSGreg Kroah-Hartman },
1458ffdff6aSGreg Kroah-Hartman [BOARD_PCI1710HG] = {
1468ffdff6aSGreg Kroah-Hartman .name = "pci1710hg",
1478ffdff6aSGreg Kroah-Hartman .ai_range = &pci1710hg_ai_range,
1488ffdff6aSGreg Kroah-Hartman .has_ao = 1,
1498ffdff6aSGreg Kroah-Hartman },
1508ffdff6aSGreg Kroah-Hartman [BOARD_PCI1711] = {
1518ffdff6aSGreg Kroah-Hartman .name = "pci1711",
1528ffdff6aSGreg Kroah-Hartman .ai_range = &pci1711_ai_range,
1538ffdff6aSGreg Kroah-Hartman .is_pci1711 = 1,
1548ffdff6aSGreg Kroah-Hartman .has_ao = 1,
1558ffdff6aSGreg Kroah-Hartman },
1568ffdff6aSGreg Kroah-Hartman [BOARD_PCI1713] = {
1578ffdff6aSGreg Kroah-Hartman .name = "pci1713",
1588ffdff6aSGreg Kroah-Hartman .ai_range = &pci1710_ai_range,
1598ffdff6aSGreg Kroah-Hartman .is_pci1713 = 1,
1608ffdff6aSGreg Kroah-Hartman },
1618ffdff6aSGreg Kroah-Hartman [BOARD_PCI1731] = {
1628ffdff6aSGreg Kroah-Hartman .name = "pci1731",
1638ffdff6aSGreg Kroah-Hartman .ai_range = &pci1711_ai_range,
1648ffdff6aSGreg Kroah-Hartman .is_pci1711 = 1,
1658ffdff6aSGreg Kroah-Hartman },
1668ffdff6aSGreg Kroah-Hartman };
1678ffdff6aSGreg Kroah-Hartman
1688ffdff6aSGreg Kroah-Hartman struct pci1710_private {
1698ffdff6aSGreg Kroah-Hartman unsigned int max_samples;
1708ffdff6aSGreg Kroah-Hartman unsigned int ctrl; /* control register value */
1718ffdff6aSGreg Kroah-Hartman unsigned int ctrl_ext; /* used to switch from TRIG_EXT to TRIG_xxx */
1728ffdff6aSGreg Kroah-Hartman unsigned int mux_scan; /* used to set the channel interval to scan */
1738ffdff6aSGreg Kroah-Hartman unsigned char ai_et;
1748ffdff6aSGreg Kroah-Hartman unsigned int act_chanlist[32]; /* list of scanned channel */
1758ffdff6aSGreg Kroah-Hartman unsigned char saved_seglen; /* len of the non-repeating chanlist */
1768ffdff6aSGreg Kroah-Hartman unsigned char da_ranges; /* copy of D/A outpit range register */
1778ffdff6aSGreg Kroah-Hartman unsigned char unipolar_gain; /* adjust for unipolar gain codes */
1788ffdff6aSGreg Kroah-Hartman };
1798ffdff6aSGreg Kroah-Hartman
pci1710_ai_check_chanlist(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_cmd * cmd)1808ffdff6aSGreg Kroah-Hartman static int pci1710_ai_check_chanlist(struct comedi_device *dev,
1818ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s,
1828ffdff6aSGreg Kroah-Hartman struct comedi_cmd *cmd)
1838ffdff6aSGreg Kroah-Hartman {
1848ffdff6aSGreg Kroah-Hartman struct pci1710_private *devpriv = dev->private;
1858ffdff6aSGreg Kroah-Hartman unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
1868ffdff6aSGreg Kroah-Hartman unsigned int last_aref = CR_AREF(cmd->chanlist[0]);
1878ffdff6aSGreg Kroah-Hartman unsigned int next_chan = (chan0 + 1) % s->n_chan;
1888ffdff6aSGreg Kroah-Hartman unsigned int chansegment[32];
1898ffdff6aSGreg Kroah-Hartman unsigned int seglen;
1908ffdff6aSGreg Kroah-Hartman int i;
1918ffdff6aSGreg Kroah-Hartman
1928ffdff6aSGreg Kroah-Hartman if (cmd->chanlist_len == 1) {
1938ffdff6aSGreg Kroah-Hartman devpriv->saved_seglen = cmd->chanlist_len;
1948ffdff6aSGreg Kroah-Hartman return 0;
1958ffdff6aSGreg Kroah-Hartman }
1968ffdff6aSGreg Kroah-Hartman
1978ffdff6aSGreg Kroah-Hartman /* first channel is always ok */
1988ffdff6aSGreg Kroah-Hartman chansegment[0] = cmd->chanlist[0];
1998ffdff6aSGreg Kroah-Hartman
2008ffdff6aSGreg Kroah-Hartman for (i = 1; i < cmd->chanlist_len; i++) {
2018ffdff6aSGreg Kroah-Hartman unsigned int chan = CR_CHAN(cmd->chanlist[i]);
2028ffdff6aSGreg Kroah-Hartman unsigned int aref = CR_AREF(cmd->chanlist[i]);
2038ffdff6aSGreg Kroah-Hartman
2048ffdff6aSGreg Kroah-Hartman if (cmd->chanlist[0] == cmd->chanlist[i])
2058ffdff6aSGreg Kroah-Hartman break; /* we detected a loop, stop */
2068ffdff6aSGreg Kroah-Hartman
2078ffdff6aSGreg Kroah-Hartman if (aref == AREF_DIFF && (chan & 1)) {
2088ffdff6aSGreg Kroah-Hartman dev_err(dev->class_dev,
2098ffdff6aSGreg Kroah-Hartman "Odd channel cannot be differential input!\n");
2108ffdff6aSGreg Kroah-Hartman return -EINVAL;
2118ffdff6aSGreg Kroah-Hartman }
2128ffdff6aSGreg Kroah-Hartman
2138ffdff6aSGreg Kroah-Hartman if (last_aref == AREF_DIFF)
2148ffdff6aSGreg Kroah-Hartman next_chan = (next_chan + 1) % s->n_chan;
2158ffdff6aSGreg Kroah-Hartman if (chan != next_chan) {
2168ffdff6aSGreg Kroah-Hartman dev_err(dev->class_dev,
2178ffdff6aSGreg Kroah-Hartman "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
2188ffdff6aSGreg Kroah-Hartman i, chan, next_chan, chan0);
2198ffdff6aSGreg Kroah-Hartman return -EINVAL;
2208ffdff6aSGreg Kroah-Hartman }
2218ffdff6aSGreg Kroah-Hartman
2228ffdff6aSGreg Kroah-Hartman /* next correct channel in list */
2238ffdff6aSGreg Kroah-Hartman chansegment[i] = cmd->chanlist[i];
2248ffdff6aSGreg Kroah-Hartman last_aref = aref;
2258ffdff6aSGreg Kroah-Hartman }
2268ffdff6aSGreg Kroah-Hartman seglen = i;
2278ffdff6aSGreg Kroah-Hartman
2288ffdff6aSGreg Kroah-Hartman for (i = 0; i < cmd->chanlist_len; i++) {
2298ffdff6aSGreg Kroah-Hartman if (cmd->chanlist[i] != chansegment[i % seglen]) {
2308ffdff6aSGreg Kroah-Hartman dev_err(dev->class_dev,
2318ffdff6aSGreg Kroah-Hartman "bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
2328ffdff6aSGreg Kroah-Hartman i, CR_CHAN(chansegment[i]),
2338ffdff6aSGreg Kroah-Hartman CR_RANGE(chansegment[i]),
2348ffdff6aSGreg Kroah-Hartman CR_AREF(chansegment[i]),
2358ffdff6aSGreg Kroah-Hartman CR_CHAN(cmd->chanlist[i % seglen]),
2368ffdff6aSGreg Kroah-Hartman CR_RANGE(cmd->chanlist[i % seglen]),
2378ffdff6aSGreg Kroah-Hartman CR_AREF(chansegment[i % seglen]));
2388ffdff6aSGreg Kroah-Hartman return -EINVAL;
2398ffdff6aSGreg Kroah-Hartman }
2408ffdff6aSGreg Kroah-Hartman }
2418ffdff6aSGreg Kroah-Hartman devpriv->saved_seglen = seglen;
2428ffdff6aSGreg Kroah-Hartman
2438ffdff6aSGreg Kroah-Hartman return 0;
2448ffdff6aSGreg Kroah-Hartman }
2458ffdff6aSGreg Kroah-Hartman
pci1710_ai_setup_chanlist(struct comedi_device * dev,struct comedi_subdevice * s,unsigned int * chanlist,unsigned int n_chan,unsigned int seglen)2468ffdff6aSGreg Kroah-Hartman static void pci1710_ai_setup_chanlist(struct comedi_device *dev,
2478ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s,
2488ffdff6aSGreg Kroah-Hartman unsigned int *chanlist,
2498ffdff6aSGreg Kroah-Hartman unsigned int n_chan,
2508ffdff6aSGreg Kroah-Hartman unsigned int seglen)
2518ffdff6aSGreg Kroah-Hartman {
2528ffdff6aSGreg Kroah-Hartman struct pci1710_private *devpriv = dev->private;
2538ffdff6aSGreg Kroah-Hartman unsigned int first_chan = CR_CHAN(chanlist[0]);
2548ffdff6aSGreg Kroah-Hartman unsigned int last_chan = CR_CHAN(chanlist[seglen - 1]);
2558ffdff6aSGreg Kroah-Hartman unsigned int i;
2568ffdff6aSGreg Kroah-Hartman
2578ffdff6aSGreg Kroah-Hartman for (i = 0; i < seglen; i++) { /* store range list to card */
2588ffdff6aSGreg Kroah-Hartman unsigned int chan = CR_CHAN(chanlist[i]);
2598ffdff6aSGreg Kroah-Hartman unsigned int range = CR_RANGE(chanlist[i]);
2608ffdff6aSGreg Kroah-Hartman unsigned int aref = CR_AREF(chanlist[i]);
2618ffdff6aSGreg Kroah-Hartman unsigned int rangeval = 0;
2628ffdff6aSGreg Kroah-Hartman
2638ffdff6aSGreg Kroah-Hartman if (aref == AREF_DIFF)
2648ffdff6aSGreg Kroah-Hartman rangeval |= PCI171X_RANGE_DIFF;
2658ffdff6aSGreg Kroah-Hartman if (comedi_range_is_unipolar(s, range)) {
2668ffdff6aSGreg Kroah-Hartman rangeval |= PCI171X_RANGE_UNI;
2678ffdff6aSGreg Kroah-Hartman range -= devpriv->unipolar_gain;
2688ffdff6aSGreg Kroah-Hartman }
2698ffdff6aSGreg Kroah-Hartman rangeval |= PCI171X_RANGE_GAIN(range);
2708ffdff6aSGreg Kroah-Hartman
2718ffdff6aSGreg Kroah-Hartman /* select channel and set range */
2728ffdff6aSGreg Kroah-Hartman outw(PCI171X_MUX_CHAN(chan), dev->iobase + PCI171X_MUX_REG);
2738ffdff6aSGreg Kroah-Hartman outw(rangeval, dev->iobase + PCI171X_RANGE_REG);
2748ffdff6aSGreg Kroah-Hartman
2758ffdff6aSGreg Kroah-Hartman devpriv->act_chanlist[i] = chan;
2768ffdff6aSGreg Kroah-Hartman }
2778ffdff6aSGreg Kroah-Hartman for ( ; i < n_chan; i++) /* store remainder of channel list */
2788ffdff6aSGreg Kroah-Hartman devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
2798ffdff6aSGreg Kroah-Hartman
2808ffdff6aSGreg Kroah-Hartman /* select channel interval to scan */
2818ffdff6aSGreg Kroah-Hartman devpriv->mux_scan = PCI171X_MUX_CHANL(first_chan) |
2828ffdff6aSGreg Kroah-Hartman PCI171X_MUX_CHANH(last_chan);
2838ffdff6aSGreg Kroah-Hartman outw(devpriv->mux_scan, dev->iobase + PCI171X_MUX_REG);
2848ffdff6aSGreg Kroah-Hartman }
2858ffdff6aSGreg Kroah-Hartman
pci1710_ai_eoc(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned long context)2868ffdff6aSGreg Kroah-Hartman static int pci1710_ai_eoc(struct comedi_device *dev,
2878ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s,
2888ffdff6aSGreg Kroah-Hartman struct comedi_insn *insn,
2898ffdff6aSGreg Kroah-Hartman unsigned long context)
2908ffdff6aSGreg Kroah-Hartman {
2918ffdff6aSGreg Kroah-Hartman unsigned int status;
2928ffdff6aSGreg Kroah-Hartman
2938ffdff6aSGreg Kroah-Hartman status = inw(dev->iobase + PCI171X_STATUS_REG);
2948ffdff6aSGreg Kroah-Hartman if ((status & PCI171X_STATUS_FE) == 0)
2958ffdff6aSGreg Kroah-Hartman return 0;
2968ffdff6aSGreg Kroah-Hartman return -EBUSY;
2978ffdff6aSGreg Kroah-Hartman }
2988ffdff6aSGreg Kroah-Hartman
pci1710_ai_read_sample(struct comedi_device * dev,struct comedi_subdevice * s,unsigned int cur_chan,unsigned short * val)2998ffdff6aSGreg Kroah-Hartman static int pci1710_ai_read_sample(struct comedi_device *dev,
3008ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s,
3018ffdff6aSGreg Kroah-Hartman unsigned int cur_chan,
3028ffdff6aSGreg Kroah-Hartman unsigned short *val)
3038ffdff6aSGreg Kroah-Hartman {
3048ffdff6aSGreg Kroah-Hartman const struct boardtype *board = dev->board_ptr;
3058ffdff6aSGreg Kroah-Hartman struct pci1710_private *devpriv = dev->private;
3068ffdff6aSGreg Kroah-Hartman unsigned short sample;
3078ffdff6aSGreg Kroah-Hartman unsigned int chan;
3088ffdff6aSGreg Kroah-Hartman
3098ffdff6aSGreg Kroah-Hartman sample = inw(dev->iobase + PCI171X_AD_DATA_REG);
3108ffdff6aSGreg Kroah-Hartman if (!board->is_pci1713) {
3118ffdff6aSGreg Kroah-Hartman /*
3128ffdff6aSGreg Kroah-Hartman * The upper 4 bits of the 16-bit sample are the channel number
3138ffdff6aSGreg Kroah-Hartman * that the sample was acquired from. Verify that this channel
3148ffdff6aSGreg Kroah-Hartman * number matches the expected channel number.
3158ffdff6aSGreg Kroah-Hartman */
3168ffdff6aSGreg Kroah-Hartman chan = sample >> 12;
3178ffdff6aSGreg Kroah-Hartman if (chan != devpriv->act_chanlist[cur_chan]) {
3188ffdff6aSGreg Kroah-Hartman dev_err(dev->class_dev,
3198ffdff6aSGreg Kroah-Hartman "A/D data dropout: received from channel %d, expected %d\n",
3208ffdff6aSGreg Kroah-Hartman chan, devpriv->act_chanlist[cur_chan]);
3218ffdff6aSGreg Kroah-Hartman return -ENODATA;
3228ffdff6aSGreg Kroah-Hartman }
3238ffdff6aSGreg Kroah-Hartman }
3248ffdff6aSGreg Kroah-Hartman *val = sample & s->maxdata;
3258ffdff6aSGreg Kroah-Hartman return 0;
3268ffdff6aSGreg Kroah-Hartman }
3278ffdff6aSGreg Kroah-Hartman
pci1710_ai_insn_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)3288ffdff6aSGreg Kroah-Hartman static int pci1710_ai_insn_read(struct comedi_device *dev,
3298ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s,
3308ffdff6aSGreg Kroah-Hartman struct comedi_insn *insn,
3318ffdff6aSGreg Kroah-Hartman unsigned int *data)
3328ffdff6aSGreg Kroah-Hartman {
3338ffdff6aSGreg Kroah-Hartman struct pci1710_private *devpriv = dev->private;
3348ffdff6aSGreg Kroah-Hartman int ret = 0;
3358ffdff6aSGreg Kroah-Hartman int i;
3368ffdff6aSGreg Kroah-Hartman
3378ffdff6aSGreg Kroah-Hartman /* enable software trigger */
3388ffdff6aSGreg Kroah-Hartman devpriv->ctrl |= PCI171X_CTRL_SW;
3398ffdff6aSGreg Kroah-Hartman outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
3408ffdff6aSGreg Kroah-Hartman
3418ffdff6aSGreg Kroah-Hartman outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
3428ffdff6aSGreg Kroah-Hartman outb(0, dev->iobase + PCI171X_CLRINT_REG);
3438ffdff6aSGreg Kroah-Hartman
3448ffdff6aSGreg Kroah-Hartman pci1710_ai_setup_chanlist(dev, s, &insn->chanspec, 1, 1);
3458ffdff6aSGreg Kroah-Hartman
3468ffdff6aSGreg Kroah-Hartman for (i = 0; i < insn->n; i++) {
3478ffdff6aSGreg Kroah-Hartman unsigned short val;
3488ffdff6aSGreg Kroah-Hartman
3498ffdff6aSGreg Kroah-Hartman /* start conversion */
3508ffdff6aSGreg Kroah-Hartman outw(0, dev->iobase + PCI171X_SOFTTRG_REG);
3518ffdff6aSGreg Kroah-Hartman
3528ffdff6aSGreg Kroah-Hartman ret = comedi_timeout(dev, s, insn, pci1710_ai_eoc, 0);
3538ffdff6aSGreg Kroah-Hartman if (ret)
3548ffdff6aSGreg Kroah-Hartman break;
3558ffdff6aSGreg Kroah-Hartman
3568ffdff6aSGreg Kroah-Hartman ret = pci1710_ai_read_sample(dev, s, 0, &val);
3578ffdff6aSGreg Kroah-Hartman if (ret)
3588ffdff6aSGreg Kroah-Hartman break;
3598ffdff6aSGreg Kroah-Hartman
3608ffdff6aSGreg Kroah-Hartman data[i] = val;
3618ffdff6aSGreg Kroah-Hartman }
3628ffdff6aSGreg Kroah-Hartman
3638ffdff6aSGreg Kroah-Hartman /* disable software trigger */
3648ffdff6aSGreg Kroah-Hartman devpriv->ctrl &= ~PCI171X_CTRL_SW;
3658ffdff6aSGreg Kroah-Hartman outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
3668ffdff6aSGreg Kroah-Hartman
3678ffdff6aSGreg Kroah-Hartman outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
3688ffdff6aSGreg Kroah-Hartman outb(0, dev->iobase + PCI171X_CLRINT_REG);
3698ffdff6aSGreg Kroah-Hartman
3708ffdff6aSGreg Kroah-Hartman return ret ? ret : insn->n;
3718ffdff6aSGreg Kroah-Hartman }
3728ffdff6aSGreg Kroah-Hartman
pci1710_ai_cancel(struct comedi_device * dev,struct comedi_subdevice * s)3738ffdff6aSGreg Kroah-Hartman static int pci1710_ai_cancel(struct comedi_device *dev,
3748ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s)
3758ffdff6aSGreg Kroah-Hartman {
3768ffdff6aSGreg Kroah-Hartman struct pci1710_private *devpriv = dev->private;
3778ffdff6aSGreg Kroah-Hartman
3788ffdff6aSGreg Kroah-Hartman /* disable A/D triggers and interrupt sources */
3798ffdff6aSGreg Kroah-Hartman devpriv->ctrl &= PCI171X_CTRL_CNT0; /* preserve counter 0 clk src */
3808ffdff6aSGreg Kroah-Hartman outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
3818ffdff6aSGreg Kroah-Hartman
3828ffdff6aSGreg Kroah-Hartman /* disable pacer */
3838ffdff6aSGreg Kroah-Hartman comedi_8254_pacer_enable(dev->pacer, 1, 2, false);
3848ffdff6aSGreg Kroah-Hartman
3858ffdff6aSGreg Kroah-Hartman /* clear A/D FIFO and any pending interrutps */
3868ffdff6aSGreg Kroah-Hartman outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
3878ffdff6aSGreg Kroah-Hartman outb(0, dev->iobase + PCI171X_CLRINT_REG);
3888ffdff6aSGreg Kroah-Hartman
3898ffdff6aSGreg Kroah-Hartman return 0;
3908ffdff6aSGreg Kroah-Hartman }
3918ffdff6aSGreg Kroah-Hartman
pci1710_handle_every_sample(struct comedi_device * dev,struct comedi_subdevice * s)3928ffdff6aSGreg Kroah-Hartman static void pci1710_handle_every_sample(struct comedi_device *dev,
3938ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s)
3948ffdff6aSGreg Kroah-Hartman {
3958ffdff6aSGreg Kroah-Hartman struct comedi_cmd *cmd = &s->async->cmd;
3968ffdff6aSGreg Kroah-Hartman unsigned int status;
3978ffdff6aSGreg Kroah-Hartman unsigned short val;
3988ffdff6aSGreg Kroah-Hartman int ret;
3998ffdff6aSGreg Kroah-Hartman
4008ffdff6aSGreg Kroah-Hartman status = inw(dev->iobase + PCI171X_STATUS_REG);
4018ffdff6aSGreg Kroah-Hartman if (status & PCI171X_STATUS_FE) {
4028ffdff6aSGreg Kroah-Hartman dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status);
4038ffdff6aSGreg Kroah-Hartman s->async->events |= COMEDI_CB_ERROR;
4048ffdff6aSGreg Kroah-Hartman return;
4058ffdff6aSGreg Kroah-Hartman }
4068ffdff6aSGreg Kroah-Hartman if (status & PCI171X_STATUS_FF) {
4078ffdff6aSGreg Kroah-Hartman dev_dbg(dev->class_dev,
4088ffdff6aSGreg Kroah-Hartman "A/D FIFO Full status (Fatal Error!) (%4x)\n", status);
4098ffdff6aSGreg Kroah-Hartman s->async->events |= COMEDI_CB_ERROR;
4108ffdff6aSGreg Kroah-Hartman return;
4118ffdff6aSGreg Kroah-Hartman }
4128ffdff6aSGreg Kroah-Hartman
4138ffdff6aSGreg Kroah-Hartman outb(0, dev->iobase + PCI171X_CLRINT_REG);
4148ffdff6aSGreg Kroah-Hartman
4158ffdff6aSGreg Kroah-Hartman for (; !(inw(dev->iobase + PCI171X_STATUS_REG) & PCI171X_STATUS_FE);) {
4168ffdff6aSGreg Kroah-Hartman ret = pci1710_ai_read_sample(dev, s, s->async->cur_chan, &val);
4178ffdff6aSGreg Kroah-Hartman if (ret) {
4188ffdff6aSGreg Kroah-Hartman s->async->events |= COMEDI_CB_ERROR;
4198ffdff6aSGreg Kroah-Hartman break;
4208ffdff6aSGreg Kroah-Hartman }
4218ffdff6aSGreg Kroah-Hartman
4228ffdff6aSGreg Kroah-Hartman comedi_buf_write_samples(s, &val, 1);
4238ffdff6aSGreg Kroah-Hartman
4248ffdff6aSGreg Kroah-Hartman if (cmd->stop_src == TRIG_COUNT &&
4258ffdff6aSGreg Kroah-Hartman s->async->scans_done >= cmd->stop_arg) {
4268ffdff6aSGreg Kroah-Hartman s->async->events |= COMEDI_CB_EOA;
4278ffdff6aSGreg Kroah-Hartman break;
4288ffdff6aSGreg Kroah-Hartman }
4298ffdff6aSGreg Kroah-Hartman }
4308ffdff6aSGreg Kroah-Hartman
4318ffdff6aSGreg Kroah-Hartman outb(0, dev->iobase + PCI171X_CLRINT_REG);
4328ffdff6aSGreg Kroah-Hartman }
4338ffdff6aSGreg Kroah-Hartman
pci1710_handle_fifo(struct comedi_device * dev,struct comedi_subdevice * s)4348ffdff6aSGreg Kroah-Hartman static void pci1710_handle_fifo(struct comedi_device *dev,
4358ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s)
4368ffdff6aSGreg Kroah-Hartman {
4378ffdff6aSGreg Kroah-Hartman struct pci1710_private *devpriv = dev->private;
4388ffdff6aSGreg Kroah-Hartman struct comedi_async *async = s->async;
4398ffdff6aSGreg Kroah-Hartman struct comedi_cmd *cmd = &async->cmd;
4408ffdff6aSGreg Kroah-Hartman unsigned int status;
4418ffdff6aSGreg Kroah-Hartman int i;
4428ffdff6aSGreg Kroah-Hartman
4438ffdff6aSGreg Kroah-Hartman status = inw(dev->iobase + PCI171X_STATUS_REG);
4448ffdff6aSGreg Kroah-Hartman if (!(status & PCI171X_STATUS_FH)) {
4458ffdff6aSGreg Kroah-Hartman dev_dbg(dev->class_dev, "A/D FIFO not half full!\n");
4468ffdff6aSGreg Kroah-Hartman async->events |= COMEDI_CB_ERROR;
4478ffdff6aSGreg Kroah-Hartman return;
4488ffdff6aSGreg Kroah-Hartman }
4498ffdff6aSGreg Kroah-Hartman if (status & PCI171X_STATUS_FF) {
4508ffdff6aSGreg Kroah-Hartman dev_dbg(dev->class_dev,
4518ffdff6aSGreg Kroah-Hartman "A/D FIFO Full status (Fatal Error!)\n");
4528ffdff6aSGreg Kroah-Hartman async->events |= COMEDI_CB_ERROR;
4538ffdff6aSGreg Kroah-Hartman return;
4548ffdff6aSGreg Kroah-Hartman }
4558ffdff6aSGreg Kroah-Hartman
4568ffdff6aSGreg Kroah-Hartman for (i = 0; i < devpriv->max_samples; i++) {
4578ffdff6aSGreg Kroah-Hartman unsigned short val;
4588ffdff6aSGreg Kroah-Hartman int ret;
4598ffdff6aSGreg Kroah-Hartman
4608ffdff6aSGreg Kroah-Hartman ret = pci1710_ai_read_sample(dev, s, s->async->cur_chan, &val);
4618ffdff6aSGreg Kroah-Hartman if (ret) {
4628ffdff6aSGreg Kroah-Hartman s->async->events |= COMEDI_CB_ERROR;
4638ffdff6aSGreg Kroah-Hartman break;
4648ffdff6aSGreg Kroah-Hartman }
4658ffdff6aSGreg Kroah-Hartman
4668ffdff6aSGreg Kroah-Hartman if (!comedi_buf_write_samples(s, &val, 1))
4678ffdff6aSGreg Kroah-Hartman break;
4688ffdff6aSGreg Kroah-Hartman
4698ffdff6aSGreg Kroah-Hartman if (cmd->stop_src == TRIG_COUNT &&
4708ffdff6aSGreg Kroah-Hartman async->scans_done >= cmd->stop_arg) {
4718ffdff6aSGreg Kroah-Hartman async->events |= COMEDI_CB_EOA;
4728ffdff6aSGreg Kroah-Hartman break;
4738ffdff6aSGreg Kroah-Hartman }
4748ffdff6aSGreg Kroah-Hartman }
4758ffdff6aSGreg Kroah-Hartman
4768ffdff6aSGreg Kroah-Hartman outb(0, dev->iobase + PCI171X_CLRINT_REG);
4778ffdff6aSGreg Kroah-Hartman }
4788ffdff6aSGreg Kroah-Hartman
pci1710_irq_handler(int irq,void * d)4798ffdff6aSGreg Kroah-Hartman static irqreturn_t pci1710_irq_handler(int irq, void *d)
4808ffdff6aSGreg Kroah-Hartman {
4818ffdff6aSGreg Kroah-Hartman struct comedi_device *dev = d;
4828ffdff6aSGreg Kroah-Hartman struct pci1710_private *devpriv = dev->private;
4838ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s;
4848ffdff6aSGreg Kroah-Hartman struct comedi_cmd *cmd;
4858ffdff6aSGreg Kroah-Hartman
4868ffdff6aSGreg Kroah-Hartman if (!dev->attached) /* is device attached? */
4878ffdff6aSGreg Kroah-Hartman return IRQ_NONE; /* no, exit */
4888ffdff6aSGreg Kroah-Hartman
4898ffdff6aSGreg Kroah-Hartman s = dev->read_subdev;
4908ffdff6aSGreg Kroah-Hartman cmd = &s->async->cmd;
4918ffdff6aSGreg Kroah-Hartman
4928ffdff6aSGreg Kroah-Hartman /* is this interrupt from our board? */
4938ffdff6aSGreg Kroah-Hartman if (!(inw(dev->iobase + PCI171X_STATUS_REG) & PCI171X_STATUS_IRQ))
4948ffdff6aSGreg Kroah-Hartman return IRQ_NONE; /* no, exit */
4958ffdff6aSGreg Kroah-Hartman
4968ffdff6aSGreg Kroah-Hartman if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
4978ffdff6aSGreg Kroah-Hartman devpriv->ai_et = 0;
4988ffdff6aSGreg Kroah-Hartman devpriv->ctrl &= PCI171X_CTRL_CNT0;
4998ffdff6aSGreg Kroah-Hartman devpriv->ctrl |= PCI171X_CTRL_SW; /* set software trigger */
5008ffdff6aSGreg Kroah-Hartman outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
5018ffdff6aSGreg Kroah-Hartman devpriv->ctrl = devpriv->ctrl_ext;
5028ffdff6aSGreg Kroah-Hartman outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
5038ffdff6aSGreg Kroah-Hartman outb(0, dev->iobase + PCI171X_CLRINT_REG);
5048ffdff6aSGreg Kroah-Hartman /* no sample on this interrupt; reset the channel interval */
5058ffdff6aSGreg Kroah-Hartman outw(devpriv->mux_scan, dev->iobase + PCI171X_MUX_REG);
5068ffdff6aSGreg Kroah-Hartman outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
5078ffdff6aSGreg Kroah-Hartman comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
5088ffdff6aSGreg Kroah-Hartman return IRQ_HANDLED;
5098ffdff6aSGreg Kroah-Hartman }
5108ffdff6aSGreg Kroah-Hartman
5118ffdff6aSGreg Kroah-Hartman if (cmd->flags & CMDF_WAKE_EOS)
5128ffdff6aSGreg Kroah-Hartman pci1710_handle_every_sample(dev, s);
5138ffdff6aSGreg Kroah-Hartman else
5148ffdff6aSGreg Kroah-Hartman pci1710_handle_fifo(dev, s);
5158ffdff6aSGreg Kroah-Hartman
5168ffdff6aSGreg Kroah-Hartman comedi_handle_events(dev, s);
5178ffdff6aSGreg Kroah-Hartman
5188ffdff6aSGreg Kroah-Hartman return IRQ_HANDLED;
5198ffdff6aSGreg Kroah-Hartman }
5208ffdff6aSGreg Kroah-Hartman
pci1710_ai_cmd(struct comedi_device * dev,struct comedi_subdevice * s)5218ffdff6aSGreg Kroah-Hartman static int pci1710_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
5228ffdff6aSGreg Kroah-Hartman {
5238ffdff6aSGreg Kroah-Hartman struct pci1710_private *devpriv = dev->private;
5248ffdff6aSGreg Kroah-Hartman struct comedi_cmd *cmd = &s->async->cmd;
5258ffdff6aSGreg Kroah-Hartman
5268ffdff6aSGreg Kroah-Hartman pci1710_ai_setup_chanlist(dev, s, cmd->chanlist, cmd->chanlist_len,
5278ffdff6aSGreg Kroah-Hartman devpriv->saved_seglen);
5288ffdff6aSGreg Kroah-Hartman
5298ffdff6aSGreg Kroah-Hartman outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
5308ffdff6aSGreg Kroah-Hartman outb(0, dev->iobase + PCI171X_CLRINT_REG);
5318ffdff6aSGreg Kroah-Hartman
5328ffdff6aSGreg Kroah-Hartman devpriv->ctrl &= PCI171X_CTRL_CNT0;
5338ffdff6aSGreg Kroah-Hartman if ((cmd->flags & CMDF_WAKE_EOS) == 0)
5348ffdff6aSGreg Kroah-Hartman devpriv->ctrl |= PCI171X_CTRL_ONEFH;
5358ffdff6aSGreg Kroah-Hartman
5368ffdff6aSGreg Kroah-Hartman if (cmd->convert_src == TRIG_TIMER) {
5378ffdff6aSGreg Kroah-Hartman comedi_8254_update_divisors(dev->pacer);
5388ffdff6aSGreg Kroah-Hartman
5398ffdff6aSGreg Kroah-Hartman devpriv->ctrl |= PCI171X_CTRL_PACER | PCI171X_CTRL_IRQEN;
5408ffdff6aSGreg Kroah-Hartman if (cmd->start_src == TRIG_EXT) {
5418ffdff6aSGreg Kroah-Hartman devpriv->ctrl_ext = devpriv->ctrl;
5428ffdff6aSGreg Kroah-Hartman devpriv->ctrl &= ~(PCI171X_CTRL_PACER |
5438ffdff6aSGreg Kroah-Hartman PCI171X_CTRL_ONEFH |
5448ffdff6aSGreg Kroah-Hartman PCI171X_CTRL_GATE);
5458ffdff6aSGreg Kroah-Hartman devpriv->ctrl |= PCI171X_CTRL_EXT;
5468ffdff6aSGreg Kroah-Hartman devpriv->ai_et = 1;
5478ffdff6aSGreg Kroah-Hartman } else { /* TRIG_NOW */
5488ffdff6aSGreg Kroah-Hartman devpriv->ai_et = 0;
5498ffdff6aSGreg Kroah-Hartman }
5508ffdff6aSGreg Kroah-Hartman outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
5518ffdff6aSGreg Kroah-Hartman
5528ffdff6aSGreg Kroah-Hartman if (cmd->start_src == TRIG_NOW)
5538ffdff6aSGreg Kroah-Hartman comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
5548ffdff6aSGreg Kroah-Hartman } else { /* TRIG_EXT */
5558ffdff6aSGreg Kroah-Hartman devpriv->ctrl |= PCI171X_CTRL_EXT | PCI171X_CTRL_IRQEN;
5568ffdff6aSGreg Kroah-Hartman outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
5578ffdff6aSGreg Kroah-Hartman }
5588ffdff6aSGreg Kroah-Hartman
5598ffdff6aSGreg Kroah-Hartman return 0;
5608ffdff6aSGreg Kroah-Hartman }
5618ffdff6aSGreg Kroah-Hartman
pci1710_ai_cmdtest(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_cmd * cmd)5628ffdff6aSGreg Kroah-Hartman static int pci1710_ai_cmdtest(struct comedi_device *dev,
5638ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s,
5648ffdff6aSGreg Kroah-Hartman struct comedi_cmd *cmd)
5658ffdff6aSGreg Kroah-Hartman {
5668ffdff6aSGreg Kroah-Hartman int err = 0;
5678ffdff6aSGreg Kroah-Hartman
5688ffdff6aSGreg Kroah-Hartman /* Step 1 : check if triggers are trivially valid */
5698ffdff6aSGreg Kroah-Hartman
5708ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
5718ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
5728ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_src(&cmd->convert_src,
5738ffdff6aSGreg Kroah-Hartman TRIG_TIMER | TRIG_EXT);
5748ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
5758ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
5768ffdff6aSGreg Kroah-Hartman
5778ffdff6aSGreg Kroah-Hartman if (err)
5788ffdff6aSGreg Kroah-Hartman return 1;
5798ffdff6aSGreg Kroah-Hartman
5808ffdff6aSGreg Kroah-Hartman /* step 2a: make sure trigger sources are unique */
5818ffdff6aSGreg Kroah-Hartman
5828ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_is_unique(cmd->start_src);
5838ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_is_unique(cmd->convert_src);
5848ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_is_unique(cmd->stop_src);
5858ffdff6aSGreg Kroah-Hartman
5868ffdff6aSGreg Kroah-Hartman /* step 2b: and mutually compatible */
5878ffdff6aSGreg Kroah-Hartman
5888ffdff6aSGreg Kroah-Hartman if (err)
5898ffdff6aSGreg Kroah-Hartman return 2;
5908ffdff6aSGreg Kroah-Hartman
5918ffdff6aSGreg Kroah-Hartman /* Step 3: check if arguments are trivially valid */
5928ffdff6aSGreg Kroah-Hartman
5938ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
5948ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
5958ffdff6aSGreg Kroah-Hartman
5968ffdff6aSGreg Kroah-Hartman if (cmd->convert_src == TRIG_TIMER)
5978ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_arg_min(&cmd->convert_arg, 10000);
5988ffdff6aSGreg Kroah-Hartman else /* TRIG_FOLLOW */
5998ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
6008ffdff6aSGreg Kroah-Hartman
6018ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
6028ffdff6aSGreg Kroah-Hartman cmd->chanlist_len);
6038ffdff6aSGreg Kroah-Hartman
6048ffdff6aSGreg Kroah-Hartman if (cmd->stop_src == TRIG_COUNT)
6058ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
6068ffdff6aSGreg Kroah-Hartman else /* TRIG_NONE */
6078ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
6088ffdff6aSGreg Kroah-Hartman
6098ffdff6aSGreg Kroah-Hartman if (err)
6108ffdff6aSGreg Kroah-Hartman return 3;
6118ffdff6aSGreg Kroah-Hartman
6128ffdff6aSGreg Kroah-Hartman /* step 4: fix up any arguments */
6138ffdff6aSGreg Kroah-Hartman
6148ffdff6aSGreg Kroah-Hartman if (cmd->convert_src == TRIG_TIMER) {
6158ffdff6aSGreg Kroah-Hartman unsigned int arg = cmd->convert_arg;
6168ffdff6aSGreg Kroah-Hartman
6178ffdff6aSGreg Kroah-Hartman comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
6188ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
6198ffdff6aSGreg Kroah-Hartman }
6208ffdff6aSGreg Kroah-Hartman
6218ffdff6aSGreg Kroah-Hartman if (err)
6228ffdff6aSGreg Kroah-Hartman return 4;
6238ffdff6aSGreg Kroah-Hartman
6248ffdff6aSGreg Kroah-Hartman /* Step 5: check channel list */
6258ffdff6aSGreg Kroah-Hartman
6268ffdff6aSGreg Kroah-Hartman err |= pci1710_ai_check_chanlist(dev, s, cmd);
6278ffdff6aSGreg Kroah-Hartman
6288ffdff6aSGreg Kroah-Hartman if (err)
6298ffdff6aSGreg Kroah-Hartman return 5;
6308ffdff6aSGreg Kroah-Hartman
6318ffdff6aSGreg Kroah-Hartman return 0;
6328ffdff6aSGreg Kroah-Hartman }
6338ffdff6aSGreg Kroah-Hartman
pci1710_ao_insn_write(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)6348ffdff6aSGreg Kroah-Hartman static int pci1710_ao_insn_write(struct comedi_device *dev,
6358ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s,
6368ffdff6aSGreg Kroah-Hartman struct comedi_insn *insn,
6378ffdff6aSGreg Kroah-Hartman unsigned int *data)
6388ffdff6aSGreg Kroah-Hartman {
6398ffdff6aSGreg Kroah-Hartman struct pci1710_private *devpriv = dev->private;
6408ffdff6aSGreg Kroah-Hartman unsigned int chan = CR_CHAN(insn->chanspec);
6418ffdff6aSGreg Kroah-Hartman unsigned int range = CR_RANGE(insn->chanspec);
6428ffdff6aSGreg Kroah-Hartman unsigned int val = s->readback[chan];
6438ffdff6aSGreg Kroah-Hartman int i;
6448ffdff6aSGreg Kroah-Hartman
6458ffdff6aSGreg Kroah-Hartman devpriv->da_ranges &= ~PCI171X_DAREF_MASK(chan);
6468ffdff6aSGreg Kroah-Hartman devpriv->da_ranges |= PCI171X_DAREF(chan, range);
6478ffdff6aSGreg Kroah-Hartman outw(devpriv->da_ranges, dev->iobase + PCI171X_DAREF_REG);
6488ffdff6aSGreg Kroah-Hartman
6498ffdff6aSGreg Kroah-Hartman for (i = 0; i < insn->n; i++) {
6508ffdff6aSGreg Kroah-Hartman val = data[i];
6518ffdff6aSGreg Kroah-Hartman outw(val, dev->iobase + PCI171X_DA_REG(chan));
6528ffdff6aSGreg Kroah-Hartman }
6538ffdff6aSGreg Kroah-Hartman
6548ffdff6aSGreg Kroah-Hartman s->readback[chan] = val;
6558ffdff6aSGreg Kroah-Hartman
6568ffdff6aSGreg Kroah-Hartman return insn->n;
6578ffdff6aSGreg Kroah-Hartman }
6588ffdff6aSGreg Kroah-Hartman
pci1710_di_insn_bits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)6598ffdff6aSGreg Kroah-Hartman static int pci1710_di_insn_bits(struct comedi_device *dev,
6608ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s,
6618ffdff6aSGreg Kroah-Hartman struct comedi_insn *insn,
6628ffdff6aSGreg Kroah-Hartman unsigned int *data)
6638ffdff6aSGreg Kroah-Hartman {
6648ffdff6aSGreg Kroah-Hartman data[1] = inw(dev->iobase + PCI171X_DI_REG);
6658ffdff6aSGreg Kroah-Hartman
6668ffdff6aSGreg Kroah-Hartman return insn->n;
6678ffdff6aSGreg Kroah-Hartman }
6688ffdff6aSGreg Kroah-Hartman
pci1710_do_insn_bits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)6698ffdff6aSGreg Kroah-Hartman static int pci1710_do_insn_bits(struct comedi_device *dev,
6708ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s,
6718ffdff6aSGreg Kroah-Hartman struct comedi_insn *insn,
6728ffdff6aSGreg Kroah-Hartman unsigned int *data)
6738ffdff6aSGreg Kroah-Hartman {
6748ffdff6aSGreg Kroah-Hartman if (comedi_dio_update_state(s, data))
6758ffdff6aSGreg Kroah-Hartman outw(s->state, dev->iobase + PCI171X_DO_REG);
6768ffdff6aSGreg Kroah-Hartman
6778ffdff6aSGreg Kroah-Hartman data[1] = s->state;
6788ffdff6aSGreg Kroah-Hartman
6798ffdff6aSGreg Kroah-Hartman return insn->n;
6808ffdff6aSGreg Kroah-Hartman }
6818ffdff6aSGreg Kroah-Hartman
pci1710_counter_insn_config(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)6828ffdff6aSGreg Kroah-Hartman static int pci1710_counter_insn_config(struct comedi_device *dev,
6838ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s,
6848ffdff6aSGreg Kroah-Hartman struct comedi_insn *insn,
6858ffdff6aSGreg Kroah-Hartman unsigned int *data)
6868ffdff6aSGreg Kroah-Hartman {
6878ffdff6aSGreg Kroah-Hartman struct pci1710_private *devpriv = dev->private;
6888ffdff6aSGreg Kroah-Hartman
6898ffdff6aSGreg Kroah-Hartman switch (data[0]) {
6908ffdff6aSGreg Kroah-Hartman case INSN_CONFIG_SET_CLOCK_SRC:
6918ffdff6aSGreg Kroah-Hartman switch (data[1]) {
6928ffdff6aSGreg Kroah-Hartman case 0: /* internal */
6938ffdff6aSGreg Kroah-Hartman devpriv->ctrl_ext &= ~PCI171X_CTRL_CNT0;
6948ffdff6aSGreg Kroah-Hartman break;
6958ffdff6aSGreg Kroah-Hartman case 1: /* external */
6968ffdff6aSGreg Kroah-Hartman devpriv->ctrl_ext |= PCI171X_CTRL_CNT0;
6978ffdff6aSGreg Kroah-Hartman break;
6988ffdff6aSGreg Kroah-Hartman default:
6998ffdff6aSGreg Kroah-Hartman return -EINVAL;
7008ffdff6aSGreg Kroah-Hartman }
7018ffdff6aSGreg Kroah-Hartman outw(devpriv->ctrl_ext, dev->iobase + PCI171X_CTRL_REG);
7028ffdff6aSGreg Kroah-Hartman break;
7038ffdff6aSGreg Kroah-Hartman case INSN_CONFIG_GET_CLOCK_SRC:
7048ffdff6aSGreg Kroah-Hartman if (devpriv->ctrl_ext & PCI171X_CTRL_CNT0) {
7058ffdff6aSGreg Kroah-Hartman data[1] = 1;
7068ffdff6aSGreg Kroah-Hartman data[2] = 0;
7078ffdff6aSGreg Kroah-Hartman } else {
7088ffdff6aSGreg Kroah-Hartman data[1] = 0;
7098ffdff6aSGreg Kroah-Hartman data[2] = I8254_OSC_BASE_1MHZ;
7108ffdff6aSGreg Kroah-Hartman }
7118ffdff6aSGreg Kroah-Hartman break;
7128ffdff6aSGreg Kroah-Hartman default:
7138ffdff6aSGreg Kroah-Hartman return -EINVAL;
7148ffdff6aSGreg Kroah-Hartman }
7158ffdff6aSGreg Kroah-Hartman
7168ffdff6aSGreg Kroah-Hartman return insn->n;
7178ffdff6aSGreg Kroah-Hartman }
7188ffdff6aSGreg Kroah-Hartman
pci1710_reset(struct comedi_device * dev)7198ffdff6aSGreg Kroah-Hartman static void pci1710_reset(struct comedi_device *dev)
7208ffdff6aSGreg Kroah-Hartman {
7218ffdff6aSGreg Kroah-Hartman const struct boardtype *board = dev->board_ptr;
7228ffdff6aSGreg Kroah-Hartman
7238ffdff6aSGreg Kroah-Hartman /*
7248ffdff6aSGreg Kroah-Hartman * Disable A/D triggers and interrupt sources, set counter 0
7258ffdff6aSGreg Kroah-Hartman * to use internal 1 MHz clock.
7268ffdff6aSGreg Kroah-Hartman */
7278ffdff6aSGreg Kroah-Hartman outw(0, dev->iobase + PCI171X_CTRL_REG);
7288ffdff6aSGreg Kroah-Hartman
7298ffdff6aSGreg Kroah-Hartman /* clear A/D FIFO and any pending interrutps */
7308ffdff6aSGreg Kroah-Hartman outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
7318ffdff6aSGreg Kroah-Hartman outb(0, dev->iobase + PCI171X_CLRINT_REG);
7328ffdff6aSGreg Kroah-Hartman
7338ffdff6aSGreg Kroah-Hartman if (board->has_ao) {
7348ffdff6aSGreg Kroah-Hartman /* set DACs to 0..5V and outputs to 0V */
7358ffdff6aSGreg Kroah-Hartman outb(0, dev->iobase + PCI171X_DAREF_REG);
7368ffdff6aSGreg Kroah-Hartman outw(0, dev->iobase + PCI171X_DA_REG(0));
7378ffdff6aSGreg Kroah-Hartman outw(0, dev->iobase + PCI171X_DA_REG(1));
7388ffdff6aSGreg Kroah-Hartman }
7398ffdff6aSGreg Kroah-Hartman
7408ffdff6aSGreg Kroah-Hartman /* set digital outputs to 0 */
7418ffdff6aSGreg Kroah-Hartman outw(0, dev->iobase + PCI171X_DO_REG);
7428ffdff6aSGreg Kroah-Hartman }
7438ffdff6aSGreg Kroah-Hartman
pci1710_auto_attach(struct comedi_device * dev,unsigned long context)7448ffdff6aSGreg Kroah-Hartman static int pci1710_auto_attach(struct comedi_device *dev,
7458ffdff6aSGreg Kroah-Hartman unsigned long context)
7468ffdff6aSGreg Kroah-Hartman {
7478ffdff6aSGreg Kroah-Hartman struct pci_dev *pcidev = comedi_to_pci_dev(dev);
7488ffdff6aSGreg Kroah-Hartman const struct boardtype *board = NULL;
7498ffdff6aSGreg Kroah-Hartman struct pci1710_private *devpriv;
7508ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s;
7518ffdff6aSGreg Kroah-Hartman int ret, subdev, n_subdevices;
7528ffdff6aSGreg Kroah-Hartman int i;
7538ffdff6aSGreg Kroah-Hartman
7548ffdff6aSGreg Kroah-Hartman if (context < ARRAY_SIZE(boardtypes))
7558ffdff6aSGreg Kroah-Hartman board = &boardtypes[context];
7568ffdff6aSGreg Kroah-Hartman if (!board)
7578ffdff6aSGreg Kroah-Hartman return -ENODEV;
7588ffdff6aSGreg Kroah-Hartman dev->board_ptr = board;
7598ffdff6aSGreg Kroah-Hartman dev->board_name = board->name;
7608ffdff6aSGreg Kroah-Hartman
7618ffdff6aSGreg Kroah-Hartman devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
7628ffdff6aSGreg Kroah-Hartman if (!devpriv)
7638ffdff6aSGreg Kroah-Hartman return -ENOMEM;
7648ffdff6aSGreg Kroah-Hartman
7658ffdff6aSGreg Kroah-Hartman ret = comedi_pci_enable(dev);
7668ffdff6aSGreg Kroah-Hartman if (ret)
7678ffdff6aSGreg Kroah-Hartman return ret;
7688ffdff6aSGreg Kroah-Hartman dev->iobase = pci_resource_start(pcidev, 2);
7698ffdff6aSGreg Kroah-Hartman
770*fade5e5bSIan Abbott dev->pacer = comedi_8254_io_alloc(dev->iobase + PCI171X_TIMER_BASE,
7718ffdff6aSGreg Kroah-Hartman I8254_OSC_BASE_10MHZ, I8254_IO16, 0);
772*fade5e5bSIan Abbott if (IS_ERR(dev->pacer))
773*fade5e5bSIan Abbott return PTR_ERR(dev->pacer);
7748ffdff6aSGreg Kroah-Hartman
7758ffdff6aSGreg Kroah-Hartman n_subdevices = 1; /* all boards have analog inputs */
7768ffdff6aSGreg Kroah-Hartman if (board->has_ao)
7778ffdff6aSGreg Kroah-Hartman n_subdevices++;
7788ffdff6aSGreg Kroah-Hartman if (!board->is_pci1713) {
7798ffdff6aSGreg Kroah-Hartman /*
7808ffdff6aSGreg Kroah-Hartman * All other boards have digital inputs and outputs as
7818ffdff6aSGreg Kroah-Hartman * well as a user counter.
7828ffdff6aSGreg Kroah-Hartman */
7838ffdff6aSGreg Kroah-Hartman n_subdevices += 3;
7848ffdff6aSGreg Kroah-Hartman }
7858ffdff6aSGreg Kroah-Hartman
7868ffdff6aSGreg Kroah-Hartman ret = comedi_alloc_subdevices(dev, n_subdevices);
7878ffdff6aSGreg Kroah-Hartman if (ret)
7888ffdff6aSGreg Kroah-Hartman return ret;
7898ffdff6aSGreg Kroah-Hartman
7908ffdff6aSGreg Kroah-Hartman pci1710_reset(dev);
7918ffdff6aSGreg Kroah-Hartman
7928ffdff6aSGreg Kroah-Hartman if (pcidev->irq) {
7938ffdff6aSGreg Kroah-Hartman ret = request_irq(pcidev->irq, pci1710_irq_handler,
7948ffdff6aSGreg Kroah-Hartman IRQF_SHARED, dev->board_name, dev);
7958ffdff6aSGreg Kroah-Hartman if (ret == 0)
7968ffdff6aSGreg Kroah-Hartman dev->irq = pcidev->irq;
7978ffdff6aSGreg Kroah-Hartman }
7988ffdff6aSGreg Kroah-Hartman
7998ffdff6aSGreg Kroah-Hartman subdev = 0;
8008ffdff6aSGreg Kroah-Hartman
8018ffdff6aSGreg Kroah-Hartman /* Analog Input subdevice */
8028ffdff6aSGreg Kroah-Hartman s = &dev->subdevices[subdev++];
8038ffdff6aSGreg Kroah-Hartman s->type = COMEDI_SUBD_AI;
8048ffdff6aSGreg Kroah-Hartman s->subdev_flags = SDF_READABLE | SDF_GROUND;
8058ffdff6aSGreg Kroah-Hartman if (!board->is_pci1711)
8068ffdff6aSGreg Kroah-Hartman s->subdev_flags |= SDF_DIFF;
8078ffdff6aSGreg Kroah-Hartman s->n_chan = board->is_pci1713 ? 32 : 16;
8088ffdff6aSGreg Kroah-Hartman s->maxdata = 0x0fff;
8098ffdff6aSGreg Kroah-Hartman s->range_table = board->ai_range;
8108ffdff6aSGreg Kroah-Hartman s->insn_read = pci1710_ai_insn_read;
8118ffdff6aSGreg Kroah-Hartman if (dev->irq) {
8128ffdff6aSGreg Kroah-Hartman dev->read_subdev = s;
8138ffdff6aSGreg Kroah-Hartman s->subdev_flags |= SDF_CMD_READ;
8148ffdff6aSGreg Kroah-Hartman s->len_chanlist = s->n_chan;
8158ffdff6aSGreg Kroah-Hartman s->do_cmdtest = pci1710_ai_cmdtest;
8168ffdff6aSGreg Kroah-Hartman s->do_cmd = pci1710_ai_cmd;
8178ffdff6aSGreg Kroah-Hartman s->cancel = pci1710_ai_cancel;
8188ffdff6aSGreg Kroah-Hartman }
8198ffdff6aSGreg Kroah-Hartman
8208ffdff6aSGreg Kroah-Hartman /* find the value needed to adjust for unipolar gain codes */
8218ffdff6aSGreg Kroah-Hartman for (i = 0; i < s->range_table->length; i++) {
8228ffdff6aSGreg Kroah-Hartman if (comedi_range_is_unipolar(s, i)) {
8238ffdff6aSGreg Kroah-Hartman devpriv->unipolar_gain = i;
8248ffdff6aSGreg Kroah-Hartman break;
8258ffdff6aSGreg Kroah-Hartman }
8268ffdff6aSGreg Kroah-Hartman }
8278ffdff6aSGreg Kroah-Hartman
8288ffdff6aSGreg Kroah-Hartman if (board->has_ao) {
8298ffdff6aSGreg Kroah-Hartman /* Analog Output subdevice */
8308ffdff6aSGreg Kroah-Hartman s = &dev->subdevices[subdev++];
8318ffdff6aSGreg Kroah-Hartman s->type = COMEDI_SUBD_AO;
8328ffdff6aSGreg Kroah-Hartman s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
8338ffdff6aSGreg Kroah-Hartman s->n_chan = 2;
8348ffdff6aSGreg Kroah-Hartman s->maxdata = 0x0fff;
8358ffdff6aSGreg Kroah-Hartman s->range_table = &pci171x_ao_range;
8368ffdff6aSGreg Kroah-Hartman s->insn_write = pci1710_ao_insn_write;
8378ffdff6aSGreg Kroah-Hartman
8388ffdff6aSGreg Kroah-Hartman ret = comedi_alloc_subdev_readback(s);
8398ffdff6aSGreg Kroah-Hartman if (ret)
8408ffdff6aSGreg Kroah-Hartman return ret;
8418ffdff6aSGreg Kroah-Hartman }
8428ffdff6aSGreg Kroah-Hartman
8438ffdff6aSGreg Kroah-Hartman if (!board->is_pci1713) {
8448ffdff6aSGreg Kroah-Hartman /* Digital Input subdevice */
8458ffdff6aSGreg Kroah-Hartman s = &dev->subdevices[subdev++];
8468ffdff6aSGreg Kroah-Hartman s->type = COMEDI_SUBD_DI;
8478ffdff6aSGreg Kroah-Hartman s->subdev_flags = SDF_READABLE;
8488ffdff6aSGreg Kroah-Hartman s->n_chan = 16;
8498ffdff6aSGreg Kroah-Hartman s->maxdata = 1;
8508ffdff6aSGreg Kroah-Hartman s->range_table = &range_digital;
8518ffdff6aSGreg Kroah-Hartman s->insn_bits = pci1710_di_insn_bits;
8528ffdff6aSGreg Kroah-Hartman
8538ffdff6aSGreg Kroah-Hartman /* Digital Output subdevice */
8548ffdff6aSGreg Kroah-Hartman s = &dev->subdevices[subdev++];
8558ffdff6aSGreg Kroah-Hartman s->type = COMEDI_SUBD_DO;
8568ffdff6aSGreg Kroah-Hartman s->subdev_flags = SDF_WRITABLE;
8578ffdff6aSGreg Kroah-Hartman s->n_chan = 16;
8588ffdff6aSGreg Kroah-Hartman s->maxdata = 1;
8598ffdff6aSGreg Kroah-Hartman s->range_table = &range_digital;
8608ffdff6aSGreg Kroah-Hartman s->insn_bits = pci1710_do_insn_bits;
8618ffdff6aSGreg Kroah-Hartman
8628ffdff6aSGreg Kroah-Hartman /* Counter subdevice (8254) */
8638ffdff6aSGreg Kroah-Hartman s = &dev->subdevices[subdev++];
8648ffdff6aSGreg Kroah-Hartman comedi_8254_subdevice_init(s, dev->pacer);
8658ffdff6aSGreg Kroah-Hartman
8668ffdff6aSGreg Kroah-Hartman dev->pacer->insn_config = pci1710_counter_insn_config;
8678ffdff6aSGreg Kroah-Hartman
8688ffdff6aSGreg Kroah-Hartman /* counters 1 and 2 are used internally for the pacer */
8698ffdff6aSGreg Kroah-Hartman comedi_8254_set_busy(dev->pacer, 1, true);
8708ffdff6aSGreg Kroah-Hartman comedi_8254_set_busy(dev->pacer, 2, true);
8718ffdff6aSGreg Kroah-Hartman }
8728ffdff6aSGreg Kroah-Hartman
8738ffdff6aSGreg Kroah-Hartman /* max_samples is half the FIFO size (2 bytes/sample) */
8748ffdff6aSGreg Kroah-Hartman devpriv->max_samples = (board->is_pci1711) ? 512 : 2048;
8758ffdff6aSGreg Kroah-Hartman
8768ffdff6aSGreg Kroah-Hartman return 0;
8778ffdff6aSGreg Kroah-Hartman }
8788ffdff6aSGreg Kroah-Hartman
8798ffdff6aSGreg Kroah-Hartman static struct comedi_driver adv_pci1710_driver = {
8808ffdff6aSGreg Kroah-Hartman .driver_name = "adv_pci1710",
8818ffdff6aSGreg Kroah-Hartman .module = THIS_MODULE,
8828ffdff6aSGreg Kroah-Hartman .auto_attach = pci1710_auto_attach,
8838ffdff6aSGreg Kroah-Hartman .detach = comedi_pci_detach,
8848ffdff6aSGreg Kroah-Hartman };
8858ffdff6aSGreg Kroah-Hartman
adv_pci1710_pci_probe(struct pci_dev * dev,const struct pci_device_id * id)8868ffdff6aSGreg Kroah-Hartman static int adv_pci1710_pci_probe(struct pci_dev *dev,
8878ffdff6aSGreg Kroah-Hartman const struct pci_device_id *id)
8888ffdff6aSGreg Kroah-Hartman {
8898ffdff6aSGreg Kroah-Hartman return comedi_pci_auto_config(dev, &adv_pci1710_driver,
8908ffdff6aSGreg Kroah-Hartman id->driver_data);
8918ffdff6aSGreg Kroah-Hartman }
8928ffdff6aSGreg Kroah-Hartman
8938ffdff6aSGreg Kroah-Hartman static const struct pci_device_id adv_pci1710_pci_table[] = {
8948ffdff6aSGreg Kroah-Hartman {
8958ffdff6aSGreg Kroah-Hartman PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
8968ffdff6aSGreg Kroah-Hartman PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
8978ffdff6aSGreg Kroah-Hartman .driver_data = BOARD_PCI1710,
8988ffdff6aSGreg Kroah-Hartman }, {
8998ffdff6aSGreg Kroah-Hartman PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
9008ffdff6aSGreg Kroah-Hartman PCI_VENDOR_ID_ADVANTECH, 0x0000),
9018ffdff6aSGreg Kroah-Hartman .driver_data = BOARD_PCI1710,
9028ffdff6aSGreg Kroah-Hartman }, {
9038ffdff6aSGreg Kroah-Hartman PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
9048ffdff6aSGreg Kroah-Hartman PCI_VENDOR_ID_ADVANTECH, 0xb100),
9058ffdff6aSGreg Kroah-Hartman .driver_data = BOARD_PCI1710,
9068ffdff6aSGreg Kroah-Hartman }, {
9078ffdff6aSGreg Kroah-Hartman PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
9088ffdff6aSGreg Kroah-Hartman PCI_VENDOR_ID_ADVANTECH, 0xb200),
9098ffdff6aSGreg Kroah-Hartman .driver_data = BOARD_PCI1710,
9108ffdff6aSGreg Kroah-Hartman }, {
9118ffdff6aSGreg Kroah-Hartman PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
9128ffdff6aSGreg Kroah-Hartman PCI_VENDOR_ID_ADVANTECH, 0xc100),
9138ffdff6aSGreg Kroah-Hartman .driver_data = BOARD_PCI1710,
9148ffdff6aSGreg Kroah-Hartman }, {
9158ffdff6aSGreg Kroah-Hartman PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
9168ffdff6aSGreg Kroah-Hartman PCI_VENDOR_ID_ADVANTECH, 0xc200),
9178ffdff6aSGreg Kroah-Hartman .driver_data = BOARD_PCI1710,
9188ffdff6aSGreg Kroah-Hartman }, {
9198ffdff6aSGreg Kroah-Hartman PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100),
9208ffdff6aSGreg Kroah-Hartman .driver_data = BOARD_PCI1710,
9218ffdff6aSGreg Kroah-Hartman }, {
9228ffdff6aSGreg Kroah-Hartman PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
9238ffdff6aSGreg Kroah-Hartman PCI_VENDOR_ID_ADVANTECH, 0x0002),
9248ffdff6aSGreg Kroah-Hartman .driver_data = BOARD_PCI1710HG,
9258ffdff6aSGreg Kroah-Hartman }, {
9268ffdff6aSGreg Kroah-Hartman PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
9278ffdff6aSGreg Kroah-Hartman PCI_VENDOR_ID_ADVANTECH, 0xb102),
9288ffdff6aSGreg Kroah-Hartman .driver_data = BOARD_PCI1710HG,
9298ffdff6aSGreg Kroah-Hartman }, {
9308ffdff6aSGreg Kroah-Hartman PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
9318ffdff6aSGreg Kroah-Hartman PCI_VENDOR_ID_ADVANTECH, 0xb202),
9328ffdff6aSGreg Kroah-Hartman .driver_data = BOARD_PCI1710HG,
9338ffdff6aSGreg Kroah-Hartman }, {
9348ffdff6aSGreg Kroah-Hartman PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
9358ffdff6aSGreg Kroah-Hartman PCI_VENDOR_ID_ADVANTECH, 0xc102),
9368ffdff6aSGreg Kroah-Hartman .driver_data = BOARD_PCI1710HG,
9378ffdff6aSGreg Kroah-Hartman }, {
9388ffdff6aSGreg Kroah-Hartman PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
9398ffdff6aSGreg Kroah-Hartman PCI_VENDOR_ID_ADVANTECH, 0xc202),
9408ffdff6aSGreg Kroah-Hartman .driver_data = BOARD_PCI1710HG,
9418ffdff6aSGreg Kroah-Hartman }, {
9428ffdff6aSGreg Kroah-Hartman PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102),
9438ffdff6aSGreg Kroah-Hartman .driver_data = BOARD_PCI1710HG,
9448ffdff6aSGreg Kroah-Hartman },
9458ffdff6aSGreg Kroah-Hartman { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
9468ffdff6aSGreg Kroah-Hartman { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
9478ffdff6aSGreg Kroah-Hartman { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
9488ffdff6aSGreg Kroah-Hartman { 0 }
9498ffdff6aSGreg Kroah-Hartman };
9508ffdff6aSGreg Kroah-Hartman MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
9518ffdff6aSGreg Kroah-Hartman
9528ffdff6aSGreg Kroah-Hartman static struct pci_driver adv_pci1710_pci_driver = {
9538ffdff6aSGreg Kroah-Hartman .name = "adv_pci1710",
9548ffdff6aSGreg Kroah-Hartman .id_table = adv_pci1710_pci_table,
9558ffdff6aSGreg Kroah-Hartman .probe = adv_pci1710_pci_probe,
9568ffdff6aSGreg Kroah-Hartman .remove = comedi_pci_auto_unconfig,
9578ffdff6aSGreg Kroah-Hartman };
9588ffdff6aSGreg Kroah-Hartman module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
9598ffdff6aSGreg Kroah-Hartman
9608ffdff6aSGreg Kroah-Hartman MODULE_AUTHOR("Comedi https://www.comedi.org");
9618ffdff6aSGreg Kroah-Hartman MODULE_DESCRIPTION("Comedi: Advantech PCI-1710 Series Multifunction DAS Cards");
9628ffdff6aSGreg Kroah-Hartman MODULE_LICENSE("GPL");
963