/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

  1. /*
  2. * comedi/drivers/adv_pci1710.c
  3. *
  4. * Author: Michal Dobes <dobes@tesnet.cz>
  5. *
  6. * Thanks to ZhenGang Shang <ZhenGang.Shang@Advantech.com.cn>
  7. * for testing and informations.
  8. *
  9. * hardware driver for Advantech cards:
  10. * card: PCI-1710, PCI-1710HG, PCI-1711, PCI-1713, PCI-1720, PCI-1731
  11. * driver: pci1710, pci1710hg, pci1711, pci1713, pci1720, pci1731
  12. *
  13. * Options:
  14. * [0] - PCI bus number - if bus number and slot number are 0,
  15. * then driver search for first unused card
  16. * [1] - PCI slot number
  17. *
  18. */
  19. /*
  20. Driver: adv_pci1710
  21. Description: Advantech PCI-1710, PCI-1710HG, PCI-1711, PCI-1713,
  22. Advantech PCI-1720, PCI-1731
  23. Author: Michal Dobes <dobes@tesnet.cz>
  24. Devices: [Advantech] PCI-1710 (adv_pci1710), PCI-1710HG (pci1710hg),
  25. PCI-1711 (adv_pci1710), PCI-1713, PCI-1720,
  26. PCI-1731
  27. Status: works
  28. This driver supports AI, AO, DI and DO subdevices.
  29. AI subdevice supports cmd and insn interface,
  30. other subdevices support only insn interface.
  31. The PCI-1710 and PCI-1710HG have the same PCI device ID, so the
  32. driver cannot distinguish between them, as would be normal for a
  33. PCI driver.
  34. Configuration options:
  35. [0] - PCI bus of device (optional)
  36. [1] - PCI slot of device (optional)
  37. If bus/slot is not specified, the first available PCI
  38. device will be used.
  39. */
  40. #include <linux/interrupt.h>
  41. #include "../comedidev.h"
  42. #include "comedi_pci.h"
  43. #include "8253.h"
  44. #include "amcc_s5933.h"
  45. #define PCI171x_PARANOIDCHECK /* if defined, then is used code which control
  46. * correct channel number on every 12 bit
  47. * sample */
  48. #undef PCI171X_EXTDEBUG
  49. #define DRV_NAME "adv_pci1710"
  50. #undef DPRINTK
  51. #ifdef PCI171X_EXTDEBUG
  52. #define DPRINTK(fmt, args...) printk(fmt, ## args)
  53. #else
  54. #define DPRINTK(fmt, args...)
  55. #endif
  56. #define PCI_VENDOR_ID_ADVANTECH 0x13fe
  57. /* hardware types of the cards */
  58. #define TYPE_PCI171X 0
  59. #define TYPE_PCI1713 2
  60. #define TYPE_PCI1720 3
  61. #define IORANGE_171x 32
  62. #define IORANGE_1720 16
  63. #define PCI171x_AD_DATA 0 /* R: A/D data */
  64. #define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */
  65. #define PCI171x_RANGE 2 /* W: A/D gain/range register */
  66. #define PCI171x_MUX 4 /* W: A/D multiplexor control */
  67. #define PCI171x_STATUS 6 /* R: status register */
  68. #define PCI171x_CONTROL 6 /* W: control register */
  69. #define PCI171x_CLRINT 8 /* W: clear interrupts request */
  70. #define PCI171x_CLRFIFO 9 /* W: clear FIFO */
  71. #define PCI171x_DA1 10 /* W: D/A register */
  72. #define PCI171x_DA2 12 /* W: D/A register */
  73. #define PCI171x_DAREF 14 /* W: D/A reference control */
  74. #define PCI171x_DI 16 /* R: digi inputs */
  75. #define PCI171x_DO 16 /* R: digi inputs */
  76. #define PCI171x_CNT0 24 /* R/W: 8254 counter 0 */
  77. #define PCI171x_CNT1 26 /* R/W: 8254 counter 1 */
  78. #define PCI171x_CNT2 28 /* R/W: 8254 counter 2 */
  79. #define PCI171x_CNTCTRL 30 /* W: 8254 counter control */
  80. /* upper bits from status register (PCI171x_STATUS) (lower is same with control
  81. * reg) */
  82. #define Status_FE 0x0100 /* 1=FIFO is empty */
  83. #define Status_FH 0x0200 /* 1=FIFO is half full */
  84. #define Status_FF 0x0400 /* 1=FIFO is full, fatal error */
  85. #define Status_IRQ 0x0800 /* 1=IRQ occurred */
  86. /* bits from control register (PCI171x_CONTROL) */
  87. #define Control_CNT0 0x0040 /* 1=CNT0 have external source,
  88. * 0=have internal 100kHz source */
  89. #define Control_ONEFH 0x0020 /* 1=IRQ on FIFO is half full, 0=every sample */
  90. #define Control_IRQEN 0x0010 /* 1=enable IRQ */
  91. #define Control_GATE 0x0008 /* 1=enable external trigger GATE (8254?) */
  92. #define Control_EXT 0x0004 /* 1=external trigger source */
  93. #define Control_PACER 0x0002 /* 1=enable internal 8254 trigger source */
  94. #define Control_SW 0x0001 /* 1=enable software trigger source */
  95. /* bits from counter control register (PCI171x_CNTCTRL) */
  96. #define Counter_BCD 0x0001 /* 0 = binary counter, 1 = BCD counter */
  97. #define Counter_M0 0x0002 /* M0-M2 select modes 0-5 */
  98. #define Counter_M1 0x0004 /* 000 = mode 0, 010 = mode 2 ... */
  99. #define Counter_M2 0x0008
  100. #define Counter_RW0 0x0010 /* RW0/RW1 select read/write mode */
  101. #define Counter_RW1 0x0020
  102. #define Counter_SC0 0x0040 /* Select Counter. Only 00 or 11 may */
  103. #define Counter_SC1 0x0080 /* be used, 00 for CNT0,
  104. * 11 for read-back command */
  105. #define PCI1720_DA0 0 /* W: D/A register 0 */
  106. #define PCI1720_DA1 2 /* W: D/A register 1 */
  107. #define PCI1720_DA2 4 /* W: D/A register 2 */
  108. #define PCI1720_DA3 6 /* W: D/A register 3 */
  109. #define PCI1720_RANGE 8 /* R/W: D/A range register */
  110. #define PCI1720_SYNCOUT 9 /* W: D/A synchronized output register */
  111. #define PCI1720_SYNCONT 15 /* R/W: D/A synchronized control */
  112. /* D/A synchronized control (PCI1720_SYNCONT) */
  113. #define Syncont_SC0 1 /* set synchronous output mode */
  114. static const struct comedi_lrange range_pci1710_3 = { 9, {
  115. BIP_RANGE(5),
  116. BIP_RANGE(2.5),
  117. BIP_RANGE(1.25),
  118. BIP_RANGE(0.625),
  119. BIP_RANGE(10),
  120. UNI_RANGE(10),
  121. UNI_RANGE(5),
  122. UNI_RANGE(2.5),
  123. UNI_RANGE(1.25)
  124. }
  125. };
  126. static const char range_codes_pci1710_3[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
  127. 0x10, 0x11, 0x12, 0x13 };
  128. static const struct comedi_lrange range_pci1710hg = { 12, {
  129. BIP_RANGE(5),
  130. BIP_RANGE(0.5),
  131. BIP_RANGE(0.05),
  132. BIP_RANGE(0.005),
  133. BIP_RANGE(10),
  134. BIP_RANGE(1),
  135. BIP_RANGE(0.1),
  136. BIP_RANGE(0.01),
  137. UNI_RANGE(10),
  138. UNI_RANGE(1),
  139. UNI_RANGE(0.1),
  140. UNI_RANGE(0.01)
  141. }
  142. };
  143. static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
  144. 0x05, 0x06, 0x07, 0x10, 0x11,
  145. 0x12, 0x13 };
  146. static const struct comedi_lrange range_pci17x1 = { 5, {
  147. BIP_RANGE(10),
  148. BIP_RANGE(5),
  149. BIP_RANGE(2.5),
  150. BIP_RANGE(1.25),
  151. BIP_RANGE(0.625)
  152. }
  153. };
  154. static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
  155. static const struct comedi_lrange range_pci1720 = { 4, {
  156. UNI_RANGE(5),
  157. UNI_RANGE(10),
  158. BIP_RANGE(5),
  159. BIP_RANGE(10)
  160. }
  161. };
  162. static const struct comedi_lrange range_pci171x_da = { 2, {
  163. UNI_RANGE(5),
  164. UNI_RANGE(10),
  165. }
  166. };
  167. static int pci1710_attach(struct comedi_device *dev,
  168. struct comedi_devconfig *it);
  169. static int pci1710_detach(struct comedi_device *dev);
  170. struct boardtype {
  171. const char *name; /* board name */
  172. int device_id;
  173. int iorange; /* I/O range len */
  174. char have_irq; /* 1=card support IRQ */
  175. char cardtype; /* 0=1710& co. 2=1713, ... */
  176. int n_aichan; /* num of A/D chans */
  177. int n_aichand; /* num of A/D chans in diff mode */
  178. int n_aochan; /* num of D/A chans */
  179. int n_dichan; /* num of DI chans */
  180. int n_dochan; /* num of DO chans */
  181. int n_counter; /* num of counters */
  182. int ai_maxdata; /* resolution of A/D */
  183. int ao_maxdata; /* resolution of D/A */
  184. const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */
  185. const char *rangecode_ai; /* range codes for programming */
  186. const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */
  187. unsigned int ai_ns_min; /* max sample speed of card v ns */
  188. unsigned int fifo_half_size; /* size of FIFO/2 */
  189. };
  190. static DEFINE_PCI_DEVICE_TABLE(pci1710_pci_table) = {
  191. { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1710) },
  192. { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1711) },
  193. { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1713) },
  194. { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1720) },
  195. { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1731) },
  196. { 0 }
  197. };
  198. MODULE_DEVICE_TABLE(pci, pci1710_pci_table);
  199. static const struct boardtype boardtypes[] = {
  200. {"pci1710", 0x1710,
  201. IORANGE_171x, 1, TYPE_PCI171X,
  202. 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
  203. &range_pci1710_3, range_codes_pci1710_3,
  204. &range_pci171x_da,
  205. 10000, 2048},
  206. {"pci1710hg", 0x1710,
  207. IORANGE_171x, 1, TYPE_PCI171X,
  208. 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
  209. &range_pci1710hg, range_codes_pci1710hg,
  210. &range_pci171x_da,
  211. 10000, 2048},
  212. {"pci1711", 0x1711,
  213. IORANGE_171x, 1, TYPE_PCI171X,
  214. 16, 0, 2, 16, 16, 1, 0x0fff, 0x0fff,
  215. &range_pci17x1, range_codes_pci17x1, &range_pci171x_da,
  216. 10000, 512},
  217. {"pci1713", 0x1713,
  218. IORANGE_171x, 1, TYPE_PCI1713,
  219. 32, 16, 0, 0, 0, 0, 0x0fff, 0x0000,
  220. &range_pci1710_3, range_codes_pci1710_3, NULL,
  221. 10000, 2048},
  222. {"pci1720", 0x1720,
  223. IORANGE_1720, 0, TYPE_PCI1720,
  224. 0, 0, 4, 0, 0, 0, 0x0000, 0x0fff,
  225. NULL, NULL, &range_pci1720,
  226. 0, 0},
  227. {"pci1731", 0x1731,
  228. IORANGE_171x, 1, TYPE_PCI171X,
  229. 16, 0, 0, 16, 16, 0, 0x0fff, 0x0000,
  230. &range_pci17x1, range_codes_pci17x1, NULL,
  231. 10000, 512},
  232. /* dummy entry corresponding to driver name */
  233. {.name = DRV_NAME},
  234. };
  235. #define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
  236. static struct comedi_driver driver_pci1710 = {
  237. .driver_name = DRV_NAME,
  238. .module = THIS_MODULE,
  239. .attach = pci1710_attach,
  240. .detach = pci1710_detach,
  241. .num_names = n_boardtypes,
  242. .board_name = &boardtypes[0].name,
  243. .offset = sizeof(struct boardtype),
  244. };
  245. struct pci1710_private {
  246. struct pci_dev *pcidev; /* ptr to PCI device */
  247. char valid; /* card is usable */
  248. char neverending_ai; /* we do unlimited AI */
  249. unsigned int CntrlReg; /* Control register */
  250. unsigned int i8254_osc_base; /* frequence of onboard oscilator */
  251. unsigned int ai_do; /* what do AI? 0=nothing, 1 to 4 mode */
  252. unsigned int ai_act_scan; /* how many scans we finished */
  253. unsigned int ai_act_chan; /* actual position in actual scan */
  254. unsigned int ai_buf_ptr; /* data buffer ptr in samples */
  255. unsigned char ai_eos; /* 1=EOS wake up */
  256. unsigned char ai_et;
  257. unsigned int ai_et_CntrlReg;
  258. unsigned int ai_et_MuxVal;
  259. unsigned int ai_et_div1, ai_et_div2;
  260. unsigned int act_chanlist[32]; /* list of scaned channel */
  261. unsigned char act_chanlist_len; /* len of scanlist */
  262. unsigned char act_chanlist_pos; /* actual position in MUX list */
  263. unsigned char da_ranges; /* copy of D/A outpit range register */
  264. unsigned int ai_scans; /* len of scanlist */
  265. unsigned int ai_n_chan; /* how many channels is measured */
  266. unsigned int *ai_chanlist; /* actaul chanlist */
  267. unsigned int ai_flags; /* flaglist */
  268. unsigned int ai_data_len; /* len of data buffer */
  269. short *ai_data; /* data buffer */
  270. unsigned int ai_timer1; /* timers */
  271. unsigned int ai_timer2;
  272. short ao_data[4]; /* data output buffer */
  273. unsigned int cnt0_write_wait; /* after a write, wait for update of the
  274. * internal state */
  275. };
  276. #define devpriv ((struct pci1710_private *)dev->private)
  277. #define this_board ((const struct boardtype *)dev->board_ptr)
  278. /*
  279. ==============================================================================
  280. */
  281. static int check_channel_list(struct comedi_device *dev,
  282. struct comedi_subdevice *s,
  283. unsigned int *chanlist, unsigned int n_chan);
  284. static void setup_channel_list(struct comedi_device *dev,
  285. struct comedi_subdevice *s,
  286. unsigned int *chanlist, unsigned int n_chan,
  287. unsigned int seglen);
  288. static void start_pacer(struct comedi_device *dev, int mode,
  289. unsigned int divisor1, unsigned int divisor2);
  290. static int pci1710_reset(struct comedi_device *dev);
  291. static int pci171x_ai_cancel(struct comedi_device *dev,
  292. struct comedi_subdevice *s);
  293. /* used for gain list programming */
  294. static const unsigned int muxonechan[] = {
  295. 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,
  296. 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
  297. 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
  298. 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
  299. };
  300. /*
  301. ==============================================================================
  302. */
  303. static int pci171x_insn_read_ai(struct comedi_device *dev,
  304. struct comedi_subdevice *s,
  305. struct comedi_insn *insn, unsigned int *data)
  306. {
  307. int n, timeout;
  308. #ifdef PCI171x_PARANOIDCHECK
  309. unsigned int idata;
  310. #endif
  311. DPRINTK("adv_pci1710 EDBG: BGN: pci171x_insn_read_ai(...)\n");
  312. devpriv->CntrlReg &= Control_CNT0;
  313. devpriv->CntrlReg |= Control_SW; /* set software trigger */
  314. outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
  315. outb(0, dev->iobase + PCI171x_CLRFIFO);
  316. outb(0, dev->iobase + PCI171x_CLRINT);
  317. setup_channel_list(dev, s, &insn->chanspec, 1, 1);
  318. DPRINTK("adv_pci1710 A ST=%4x IO=%x\n",
  319. inw(dev->iobase + PCI171x_STATUS),
  320. dev->iobase + PCI171x_STATUS);
  321. for (n = 0; n < insn->n; n++) {
  322. outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
  323. DPRINTK("adv_pci1710 B n=%d ST=%4x\n", n,
  324. inw(dev->iobase + PCI171x_STATUS));
  325. /* udelay(1); */
  326. DPRINTK("adv_pci1710 C n=%d ST=%4x\n", n,
  327. inw(dev->iobase + PCI171x_STATUS));
  328. timeout = 100;
  329. while (timeout--) {
  330. if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE))
  331. goto conv_finish;
  332. if (!(timeout % 10))
  333. DPRINTK("adv_pci1710 D n=%d tm=%d ST=%4x\n", n,
  334. timeout,
  335. inw(dev->iobase + PCI171x_STATUS));
  336. }
  337. comedi_error(dev, "A/D insn timeout");
  338. outb(0, dev->iobase + PCI171x_CLRFIFO);
  339. outb(0, dev->iobase + PCI171x_CLRINT);
  340. data[n] = 0;
  341. DPRINTK
  342. ("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n",
  343. n);
  344. return -ETIME;
  345. conv_finish:
  346. #ifdef PCI171x_PARANOIDCHECK
  347. idata = inw(dev->iobase + PCI171x_AD_DATA);
  348. if (this_board->cardtype != TYPE_PCI1713)
  349. if ((idata & 0xf000) != devpriv->act_chanlist[0]) {
  350. comedi_error(dev, "A/D insn data droput!");
  351. return -ETIME;
  352. }
  353. data[n] = idata & 0x0fff;
  354. #else
  355. data[n] = inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff;
  356. #endif
  357. }
  358. outb(0, dev->iobase + PCI171x_CLRFIFO);
  359. outb(0, dev->iobase + PCI171x_CLRINT);
  360. DPRINTK("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n", n);
  361. return n;
  362. }
  363. /*
  364. ==============================================================================
  365. */
  366. static int pci171x_insn_write_ao(struct comedi_device *dev,
  367. struct comedi_subdevice *s,
  368. struct comedi_insn *insn, unsigned int *data)
  369. {
  370. int n, chan, range, ofs;
  371. chan = CR_CHAN(insn->chanspec);
  372. range = CR_RANGE(insn->chanspec);
  373. if (chan) {
  374. devpriv->da_ranges &= 0xfb;
  375. devpriv->da_ranges |= (range << 2);
  376. outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
  377. ofs = PCI171x_DA2;
  378. } else {
  379. devpriv->da_ranges &= 0xfe;
  380. devpriv->da_ranges |= range;
  381. outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
  382. ofs = PCI171x_DA1;
  383. }
  384. for (n = 0; n < insn->n; n++)
  385. outw(data[n], dev->iobase + ofs);
  386. devpriv->ao_data[chan] = data[n];
  387. return n;
  388. }
  389. /*
  390. ==============================================================================
  391. */
  392. static int pci171x_insn_read_ao(struct comedi_device *dev,
  393. struct comedi_subdevice *s,
  394. struct comedi_insn *insn, unsigned int *data)
  395. {
  396. int n, chan;
  397. chan = CR_CHAN(insn->chanspec);
  398. for (n = 0; n < insn->n; n++)
  399. data[n] = devpriv->ao_data[chan];
  400. return n;
  401. }
  402. /*
  403. ==============================================================================
  404. */
  405. static int pci171x_insn_bits_di(struct comedi_device *dev,
  406. struct comedi_subdevice *s,
  407. struct comedi_insn *insn, unsigned int *data)
  408. {
  409. data[1] = inw(dev->iobase + PCI171x_DI);
  410. return 2;
  411. }
  412. /*
  413. ==============================================================================
  414. */
  415. static int pci171x_insn_bits_do(struct comedi_device *dev,
  416. struct comedi_subdevice *s,
  417. struct comedi_insn *insn, unsigned int *data)
  418. {
  419. if (data[0]) {
  420. s->state &= ~data[0];
  421. s->state |= (data[0] & data[1]);
  422. outw(s->state, dev->iobase + PCI171x_DO);
  423. }
  424. data[1] = s->state;
  425. return 2;
  426. }
  427. /*
  428. ==============================================================================
  429. */
  430. static int pci171x_insn_counter_read(struct comedi_device *dev,
  431. struct comedi_subdevice *s,
  432. struct comedi_insn *insn,
  433. unsigned int *data)
  434. {
  435. unsigned int msb, lsb, ccntrl;
  436. int i;
  437. ccntrl = 0xD2; /* count only */
  438. for (i = 0; i < insn->n; i++) {
  439. outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
  440. lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
  441. msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
  442. data[0] = lsb | (msb << 8);
  443. }
  444. return insn->n;
  445. }
  446. /*
  447. ==============================================================================
  448. */
  449. static int pci171x_insn_counter_write(struct comedi_device *dev,
  450. struct comedi_subdevice *s,
  451. struct comedi_insn *insn,
  452. unsigned int *data)
  453. {
  454. uint msb, lsb, ccntrl, status;
  455. lsb = data[0] & 0x00FF;
  456. msb = (data[0] & 0xFF00) >> 8;
  457. /* write lsb, then msb */
  458. outw(lsb, dev->iobase + PCI171x_CNT0);
  459. outw(msb, dev->iobase + PCI171x_CNT0);
  460. if (devpriv->cnt0_write_wait) {
  461. /* wait for the new count to be loaded */
  462. ccntrl = 0xE2;
  463. do {
  464. outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
  465. status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
  466. } while (status & 0x40);
  467. }
  468. return insn->n;
  469. }
  470. /*
  471. ==============================================================================
  472. */
  473. static int pci171x_insn_counter_config(struct comedi_device *dev,
  474. struct comedi_subdevice *s,
  475. struct comedi_insn *insn,
  476. unsigned int *data)
  477. {
  478. #ifdef unused
  479. /* This doesn't work like a normal Comedi counter config */
  480. uint ccntrl = 0;
  481. devpriv->cnt0_write_wait = data[0] & 0x20;
  482. /* internal or external clock? */
  483. if (!(data[0] & 0x10)) { /* internal */
  484. devpriv->CntrlReg &= ~Control_CNT0;
  485. } else {
  486. devpriv->CntrlReg |= Control_CNT0;
  487. }
  488. outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
  489. if (data[0] & 0x01)
  490. ccntrl |= Counter_M0;
  491. if (data[0] & 0x02)
  492. ccntrl |= Counter_M1;
  493. if (data[0] & 0x04)
  494. ccntrl |= Counter_M2;
  495. if (data[0] & 0x08)
  496. ccntrl |= Counter_BCD;
  497. ccntrl |= Counter_RW0; /* set read/write mode */
  498. ccntrl |= Counter_RW1;
  499. outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
  500. #endif
  501. return 1;
  502. }
  503. /*
  504. ==============================================================================
  505. */
  506. static int pci1720_insn_write_ao(struct comedi_device *dev,
  507. struct comedi_subdevice *s,
  508. struct comedi_insn *insn, unsigned int *data)
  509. {
  510. int n, rangereg, chan;
  511. chan = CR_CHAN(insn->chanspec);
  512. rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1)));
  513. rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1));
  514. if (rangereg != devpriv->da_ranges) {
  515. outb(rangereg, dev->iobase + PCI1720_RANGE);
  516. devpriv->da_ranges = rangereg;
  517. }
  518. for (n = 0; n < insn->n; n++) {
  519. outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1));
  520. outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
  521. }
  522. devpriv->ao_data[chan] = data[n];
  523. return n;
  524. }
  525. /*
  526. ==============================================================================
  527. */
  528. static void interrupt_pci1710_every_sample(void *d)
  529. {
  530. struct comedi_device *dev = d;
  531. struct comedi_subdevice *s = dev->subdevices + 0;
  532. int m;
  533. #ifdef PCI171x_PARANOIDCHECK
  534. short sampl;
  535. #endif
  536. DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_every_sample(...)\n");
  537. m = inw(dev->iobase + PCI171x_STATUS);
  538. if (m & Status_FE) {
  539. printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m);
  540. pci171x_ai_cancel(dev, s);
  541. s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
  542. comedi_event(dev, s);
  543. return;
  544. }
  545. if (m & Status_FF) {
  546. printk
  547. ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
  548. dev->minor, m);
  549. pci171x_ai_cancel(dev, s);
  550. s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
  551. comedi_event(dev, s);
  552. return;
  553. }
  554. outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
  555. DPRINTK("FOR ");
  556. for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
  557. #ifdef PCI171x_PARANOIDCHECK
  558. sampl = inw(dev->iobase + PCI171x_AD_DATA);
  559. DPRINTK("%04x:", sampl);
  560. if (this_board->cardtype != TYPE_PCI1713)
  561. if ((sampl & 0xf000) !=
  562. devpriv->act_chanlist[s->async->cur_chan]) {
  563. printk
  564. ("comedi: A/D data dropout: received data from channel %d, expected %d!\n",
  565. (sampl & 0xf000) >> 12,
  566. (devpriv->
  567. act_chanlist[s->
  568. async->cur_chan] & 0xf000) >>
  569. 12);
  570. pci171x_ai_cancel(dev, s);
  571. s->async->events |=
  572. COMEDI_CB_EOA | COMEDI_CB_ERROR;
  573. comedi_event(dev, s);
  574. return;
  575. }
  576. DPRINTK("%8d %2d %8d~", s->async->buf_int_ptr,
  577. s->async->cur_chan, s->async->buf_int_count);
  578. comedi_buf_put(s->async, sampl & 0x0fff);
  579. #else
  580. comedi_buf_put(s->async,
  581. inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
  582. #endif
  583. ++s->async->cur_chan;
  584. if (s->async->cur_chan >= devpriv->ai_n_chan)
  585. s->async->cur_chan = 0;
  586. if (s->async->cur_chan == 0) { /* one scan done */
  587. devpriv->ai_act_scan++;
  588. DPRINTK
  589. ("adv_pci1710 EDBG: EOS1 bic %d bip %d buc %d bup %d\n",
  590. s->async->buf_int_count, s->async->buf_int_ptr,
  591. s->async->buf_user_count, s->async->buf_user_ptr);
  592. DPRINTK("adv_pci1710 EDBG: EOS2\n");
  593. if ((!devpriv->neverending_ai) && (devpriv->ai_act_scan >= devpriv->ai_scans)) { /* all data sampled */
  594. pci171x_ai_cancel(dev, s);
  595. s->async->events |= COMEDI_CB_EOA;
  596. comedi_event(dev, s);
  597. return;
  598. }
  599. }
  600. }
  601. outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
  602. DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_every_sample(...)\n");
  603. comedi_event(dev, s);
  604. }
  605. /*
  606. ==============================================================================
  607. */
  608. static int move_block_from_fifo(struct comedi_device *dev,
  609. struct comedi_subdevice *s, int n, int turn)
  610. {
  611. int i, j;
  612. #ifdef PCI171x_PARANOIDCHECK
  613. int sampl;
  614. #endif
  615. DPRINTK("adv_pci1710 EDBG: BGN: move_block_from_fifo(...,%d,%d)\n", n,
  616. turn);
  617. j = s->async->cur_chan;
  618. for (i = 0; i < n; i++) {
  619. #ifdef PCI171x_PARANOIDCHECK
  620. sampl = inw(dev->iobase + PCI171x_AD_DATA);
  621. if (this_board->cardtype != TYPE_PCI1713)
  622. if ((sampl & 0xf000) != devpriv->act_chanlist[j]) {
  623. printk
  624. ("comedi%d: A/D FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n",
  625. dev->minor, (sampl & 0xf000) >> 12,
  626. (devpriv->act_chanlist[j] & 0xf000) >> 12,
  627. i, j, devpriv->ai_act_scan, n, turn,
  628. sampl);
  629. pci171x_ai_cancel(dev, s);
  630. s->async->events |=
  631. COMEDI_CB_EOA | COMEDI_CB_ERROR;
  632. comedi_event(dev, s);
  633. return 1;
  634. }
  635. comedi_buf_put(s->async, sampl & 0x0fff);
  636. #else
  637. comedi_buf_put(s->async,
  638. inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
  639. #endif
  640. j++;
  641. if (j >= devpriv->ai_n_chan) {
  642. j = 0;
  643. devpriv->ai_act_scan++;
  644. }
  645. }
  646. s->async->cur_chan = j;
  647. DPRINTK("adv_pci1710 EDBG: END: move_block_from_fifo(...)\n");
  648. return 0;
  649. }
  650. /*
  651. ==============================================================================
  652. */
  653. static void interrupt_pci1710_half_fifo(void *d)
  654. {
  655. struct comedi_device *dev = d;
  656. struct comedi_subdevice *s = dev->subdevices + 0;
  657. int m, samplesinbuf;
  658. DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_half_fifo(...)\n");
  659. m = inw(dev->iobase + PCI171x_STATUS);
  660. if (!(m & Status_FH)) {
  661. printk("comedi%d: A/D FIFO not half full! (%4x)\n",
  662. dev->minor, m);
  663. pci171x_ai_cancel(dev, s);
  664. s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
  665. comedi_event(dev, s);
  666. return;
  667. }
  668. if (m & Status_FF) {
  669. printk
  670. ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
  671. dev->minor, m);
  672. pci171x_ai_cancel(dev, s);
  673. s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
  674. comedi_event(dev, s);
  675. return;
  676. }
  677. samplesinbuf = this_board->fifo_half_size;
  678. if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) {
  679. m = devpriv->ai_data_len / sizeof(short);
  680. if (move_block_from_fifo(dev, s, m, 0))
  681. return;
  682. samplesinbuf -= m;
  683. }
  684. if (samplesinbuf) {
  685. if (move_block_from_fifo(dev, s, samplesinbuf, 1))
  686. return;
  687. }
  688. if (!devpriv->neverending_ai)
  689. if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data
  690. sampled */
  691. pci171x_ai_cancel(dev, s);
  692. s->async->events |= COMEDI_CB_EOA;
  693. comedi_event(dev, s);
  694. return;
  695. }
  696. outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
  697. DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_half_fifo(...)\n");
  698. comedi_event(dev, s);
  699. }
  700. /*
  701. ==============================================================================
  702. */
  703. static irqreturn_t interrupt_service_pci1710(int irq, void *d)
  704. {
  705. struct comedi_device *dev = d;
  706. DPRINTK("adv_pci1710 EDBG: BGN: interrupt_service_pci1710(%d,...)\n",
  707. irq);
  708. if (!dev->attached) /* is device attached? */
  709. return IRQ_NONE; /* no, exit */
  710. if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ)) /* is this interrupt from our board? */
  711. return IRQ_NONE; /* no, exit */
  712. DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n",
  713. inw(dev->iobase + PCI171x_STATUS));
  714. if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
  715. devpriv->ai_et = 0;
  716. devpriv->CntrlReg &= Control_CNT0;
  717. devpriv->CntrlReg |= Control_SW; /* set software trigger */
  718. outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
  719. devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
  720. outb(0, dev->iobase + PCI171x_CLRFIFO);
  721. outb(0, dev->iobase + PCI171x_CLRINT);
  722. outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
  723. outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
  724. /* start pacer */
  725. start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2);
  726. return IRQ_HANDLED;
  727. }
  728. if (devpriv->ai_eos) { /* We use FIFO half full INT or not? */
  729. interrupt_pci1710_every_sample(d);
  730. } else {
  731. interrupt_pci1710_half_fifo(d);
  732. }
  733. DPRINTK("adv_pci1710 EDBG: END: interrupt_service_pci1710(...)\n");
  734. return IRQ_HANDLED;
  735. }
  736. /*
  737. ==============================================================================
  738. */
  739. static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
  740. struct comedi_subdevice *s)
  741. {
  742. unsigned int divisor1 = 0, divisor2 = 0;
  743. unsigned int seglen;
  744. DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_docmd_and_mode(%d,...)\n",
  745. mode);
  746. start_pacer(dev, -1, 0, 0); /* stop pacer */
  747. seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
  748. devpriv->ai_n_chan);
  749. if (seglen < 1)
  750. return -EINVAL;
  751. setup_channel_list(dev, s, devpriv->ai_chanlist,
  752. devpriv->ai_n_chan, seglen);
  753. outb(0, dev->iobase + PCI171x_CLRFIFO);
  754. outb(0, dev->iobase + PCI171x_CLRINT);
  755. devpriv->ai_do = mode;
  756. devpriv->ai_act_scan = 0;
  757. s->async->cur_chan = 0;
  758. devpriv->ai_buf_ptr = 0;
  759. devpriv->neverending_ai = 0;
  760. devpriv->CntrlReg &= Control_CNT0;
  761. if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { /* don't we want wake up every scan? devpriv->ai_eos=1; */
  762. devpriv->ai_eos = 1;
  763. } else {
  764. devpriv->CntrlReg |= Control_ONEFH;
  765. devpriv->ai_eos = 0;
  766. }
  767. if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
  768. devpriv->neverending_ai = 1;
  769. /* well, user want neverending */
  770. else
  771. devpriv->neverending_ai = 0;
  772. switch (mode) {
  773. case 1:
  774. case 2:
  775. if (devpriv->ai_timer1 < this_board->ai_ns_min)
  776. devpriv->ai_timer1 = this_board->ai_ns_min;
  777. devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
  778. if (mode == 2) {
  779. devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
  780. devpriv->CntrlReg &=
  781. ~(Control_PACER | Control_ONEFH | Control_GATE);
  782. devpriv->CntrlReg |= Control_EXT;
  783. devpriv->ai_et = 1;
  784. } else {
  785. devpriv->ai_et = 0;
  786. }
  787. i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
  788. &divisor2, &devpriv->ai_timer1,
  789. devpriv->ai_flags & TRIG_ROUND_MASK);
  790. DPRINTK
  791. ("adv_pci1710 EDBG: OSC base=%u div1=%u div2=%u timer=%u\n",
  792. devpriv->i8254_osc_base, divisor1, divisor2,
  793. devpriv->ai_timer1);
  794. outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
  795. if (mode != 2) {
  796. /* start pacer */
  797. start_pacer(dev, mode, divisor1, divisor2);
  798. } else {
  799. devpriv->ai_et_div1 = divisor1;
  800. devpriv->ai_et_div2 = divisor2;
  801. }
  802. break;
  803. case 3:
  804. devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
  805. outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
  806. break;
  807. }
  808. DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_docmd_and_mode(...)\n");
  809. return 0;
  810. }
  811. #ifdef PCI171X_EXTDEBUG
  812. /*
  813. ==============================================================================
  814. */
  815. static void pci171x_cmdtest_out(int e, struct comedi_cmd *cmd)
  816. {
  817. printk("adv_pci1710 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
  818. cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
  819. printk("adv_pci1710 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
  820. cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
  821. printk("adv_pci1710 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src,
  822. cmd->scan_end_src);
  823. printk("adv_pci1710 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
  824. e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
  825. }
  826. #endif
  827. /*
  828. ==============================================================================
  829. */
  830. static int pci171x_ai_cmdtest(struct comedi_device *dev,
  831. struct comedi_subdevice *s,
  832. struct comedi_cmd *cmd)
  833. {
  834. int err = 0;
  835. int tmp;
  836. unsigned int divisor1 = 0, divisor2 = 0;
  837. DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...)\n");
  838. #ifdef PCI171X_EXTDEBUG
  839. pci171x_cmdtest_out(-1, cmd);
  840. #endif
  841. /* step 1: make sure trigger sources are trivially valid */
  842. tmp = cmd->start_src;
  843. cmd->start_src &= TRIG_NOW | TRIG_EXT;
  844. if (!cmd->start_src || tmp != cmd->start_src)
  845. err++;
  846. tmp = cmd->scan_begin_src;
  847. cmd->scan_begin_src &= TRIG_FOLLOW;
  848. if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
  849. err++;
  850. tmp = cmd->convert_src;
  851. cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
  852. if (!cmd->convert_src || tmp != cmd->convert_src)
  853. err++;
  854. tmp = cmd->scan_end_src;
  855. cmd->scan_end_src &= TRIG_COUNT;
  856. if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
  857. err++;
  858. tmp = cmd->stop_src;
  859. cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
  860. if (!cmd->stop_src || tmp != cmd->stop_src)
  861. err++;
  862. if (err) {
  863. #ifdef PCI171X_EXTDEBUG
  864. pci171x_cmdtest_out(1, cmd);
  865. #endif
  866. DPRINTK
  867. ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n",
  868. err);
  869. return 1;
  870. }
  871. /* step 2: make sure trigger sources are unique and mutually compatible */
  872. if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
  873. cmd->start_src = TRIG_NOW;
  874. err++;
  875. }
  876. if (cmd->scan_begin_src != TRIG_FOLLOW) {
  877. cmd->scan_begin_src = TRIG_FOLLOW;
  878. err++;
  879. }
  880. if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
  881. err++;
  882. if (cmd->scan_end_src != TRIG_COUNT) {
  883. cmd->scan_end_src = TRIG_COUNT;
  884. err++;
  885. }
  886. if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
  887. err++;
  888. if (err) {
  889. #ifdef PCI171X_EXTDEBUG
  890. pci171x_cmdtest_out(2, cmd);
  891. #endif
  892. DPRINTK
  893. ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n",
  894. err);
  895. return 2;
  896. }
  897. /* step 3: make sure arguments are trivially compatible */
  898. if (cmd->start_arg != 0) {
  899. cmd->start_arg = 0;
  900. err++;
  901. }
  902. if (cmd->scan_begin_arg != 0) {
  903. cmd->scan_begin_arg = 0;
  904. err++;
  905. }
  906. if (cmd->convert_src == TRIG_TIMER) {
  907. if (cmd->convert_arg < this_board->ai_ns_min) {
  908. cmd->convert_arg = this_board->ai_ns_min;
  909. err++;
  910. }
  911. } else { /* TRIG_FOLLOW */
  912. if (cmd->convert_arg != 0) {
  913. cmd->convert_arg = 0;
  914. err++;
  915. }
  916. }
  917. if (cmd->scan_end_arg != cmd->chanlist_len) {
  918. cmd->scan_end_arg = cmd->chanlist_len;
  919. err++;
  920. }
  921. if (cmd->stop_src == TRIG_COUNT) {
  922. if (!cmd->stop_arg) {
  923. cmd->stop_arg = 1;
  924. err++;
  925. }
  926. } else { /* TRIG_NONE */
  927. if (cmd->stop_arg != 0) {
  928. cmd->stop_arg = 0;
  929. err++;
  930. }
  931. }
  932. if (err) {
  933. #ifdef PCI171X_EXTDEBUG
  934. pci171x_cmdtest_out(3, cmd);
  935. #endif
  936. DPRINTK
  937. ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n",
  938. err);
  939. return 3;
  940. }
  941. /* step 4: fix up any arguments */
  942. if (cmd->convert_src == TRIG_TIMER) {
  943. tmp = cmd->convert_arg;
  944. i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
  945. &divisor2, &cmd->convert_arg,
  946. cmd->flags & TRIG_ROUND_MASK);
  947. if (cmd->convert_arg < this_board->ai_ns_min)
  948. cmd->convert_arg = this_board->ai_ns_min;
  949. if (tmp != cmd->convert_arg)
  950. err++;
  951. }
  952. if (err) {
  953. DPRINTK
  954. ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=4\n",
  955. err);
  956. return 4;
  957. }
  958. /* step 5: complain about special chanlist considerations */
  959. if (cmd->chanlist) {
  960. if (!check_channel_list(dev, s, cmd->chanlist,
  961. cmd->chanlist_len))
  962. return 5; /* incorrect channels list */
  963. }
  964. DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) ret=0\n");
  965. return 0;
  966. }
  967. /*
  968. ==============================================================================
  969. */
  970. static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
  971. {
  972. struct comedi_cmd *cmd = &s->async->cmd;
  973. DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmd(...)\n");
  974. devpriv->ai_n_chan = cmd->chanlist_len;
  975. devpriv->ai_chanlist = cmd->chanlist;
  976. devpriv->ai_flags = cmd->flags;
  977. devpriv->ai_data_len = s->async->prealloc_bufsz;
  978. devpriv->ai_data = s->async->prealloc_buf;
  979. devpriv->ai_timer1 = 0;
  980. devpriv->ai_timer2 = 0;
  981. if (cmd->stop_src == TRIG_COUNT)
  982. devpriv->ai_scans = cmd->stop_arg;
  983. else
  984. devpriv->ai_scans = 0;
  985. if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 2, 3 */
  986. if (cmd->convert_src == TRIG_TIMER) { /* mode 1 and 2 */
  987. devpriv->ai_timer1 = cmd->convert_arg;
  988. return pci171x_ai_docmd_and_mode(cmd->start_src ==
  989. TRIG_EXT ? 2 : 1, dev,
  990. s);
  991. }
  992. if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
  993. return pci171x_ai_docmd_and_mode(3, dev, s);
  994. }
  995. }
  996. return -1;
  997. }
  998. /*
  999. ==============================================================================
  1000. Check if channel list from user is builded correctly
  1001. If it's ok, then program scan/gain logic.
  1002. This works for all cards.
  1003. */
  1004. static int check_channel_list(struct comedi_device *dev,
  1005. struct comedi_subdevice *s,
  1006. unsigned int *chanlist, unsigned int n_chan)
  1007. {
  1008. unsigned int chansegment[32];
  1009. unsigned int i, nowmustbechan, seglen, segpos;
  1010. DPRINTK("adv_pci1710 EDBG: check_channel_list(...,%d)\n", n_chan);
  1011. /* correct channel and range number check itself comedi/range.c */
  1012. if (n_chan < 1) {
  1013. comedi_error(dev, "range/channel list is empty!");
  1014. return 0;
  1015. }
  1016. if (n_chan > 1) {
  1017. chansegment[0] = chanlist[0]; /* first channel is every time ok */
  1018. for (i = 1, seglen = 1; i < n_chan; i++, seglen++) { /* build part of chanlist */
  1019. /* printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
  1020. if (chanlist[0] == chanlist[i])
  1021. break; /* we detect loop, this must by finish */
  1022. if (CR_CHAN(chanlist[i]) & 1) /* odd channel cann't by differencial */
  1023. if (CR_AREF(chanlist[i]) == AREF_DIFF) {
  1024. comedi_error(dev,
  1025. "Odd channel can't be differential input!\n");
  1026. return 0;
  1027. }
  1028. nowmustbechan =
  1029. (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
  1030. if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
  1031. nowmustbechan = (nowmustbechan + 1) % s->n_chan;
  1032. if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continuous :-( */
  1033. printk
  1034. ("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
  1035. i, CR_CHAN(chanlist[i]), nowmustbechan,
  1036. CR_CHAN(chanlist[0]));
  1037. return 0;
  1038. }
  1039. chansegment[i] = chanlist[i]; /* well, this is next correct channel in list */
  1040. }
  1041. for (i = 0, segpos = 0; i < n_chan; i++) { /* check whole chanlist */
  1042. /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
  1043. if (chanlist[i] != chansegment[i % seglen]) {
  1044. printk
  1045. ("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
  1046. i, CR_CHAN(chansegment[i]),
  1047. CR_RANGE(chansegment[i]),
  1048. CR_AREF(chansegment[i]),
  1049. CR_CHAN(chanlist[i % seglen]),
  1050. CR_RANGE(chanlist[i % seglen]),
  1051. CR_AREF(chansegment[i % seglen]));
  1052. return 0; /* chan/gain list is strange */
  1053. }
  1054. }
  1055. } else {
  1056. seglen = 1;
  1057. }
  1058. return seglen;
  1059. }
  1060. static void setup_channel_list(struct comedi_device *dev,
  1061. struct comedi_subdevice *s,
  1062. unsigned int *chanlist, unsigned int n_chan,
  1063. unsigned int seglen)
  1064. {
  1065. unsigned int i, range, chanprog;
  1066. DPRINTK("adv_pci1710 EDBG: setup_channel_list(...,%d,%d)\n", n_chan,
  1067. seglen);
  1068. devpriv->act_chanlist_len = seglen;
  1069. devpriv->act_chanlist_pos = 0;
  1070. DPRINTK("SegLen: %d\n", seglen);
  1071. for (i = 0; i < seglen; i++) { /* store range list to card */
  1072. chanprog = muxonechan[CR_CHAN(chanlist[i])];
  1073. outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
  1074. range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
  1075. if (CR_AREF(chanlist[i]) == AREF_DIFF)
  1076. range |= 0x0020;
  1077. outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
  1078. #ifdef PCI171x_PARANOIDCHECK
  1079. devpriv->act_chanlist[i] =
  1080. (CR_CHAN(chanlist[i]) << 12) & 0xf000;
  1081. #endif
  1082. DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
  1083. devpriv->act_chanlist[i]);
  1084. }
  1085. #ifdef PCI171x_PARANOIDCHECK
  1086. for ( ; i < n_chan; i++) { /* store remainder of channel list */
  1087. devpriv->act_chanlist[i] =
  1088. (CR_CHAN(chanlist[i]) << 12) & 0xf000;
  1089. }
  1090. #endif
  1091. devpriv->ai_et_MuxVal =
  1092. CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
  1093. outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); /* select channel interval to scan */
  1094. DPRINTK("MUX: %4x L%4x.H%4x\n",
  1095. CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8),
  1096. CR_CHAN(chanlist[0]), CR_CHAN(chanlist[seglen - 1]));
  1097. }
  1098. /*
  1099. ==============================================================================
  1100. */
  1101. static void start_pacer(struct comedi_device *dev, int mode,
  1102. unsigned int divisor1, unsigned int divisor2)
  1103. {
  1104. DPRINTK("adv_pci1710 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode,
  1105. divisor1, divisor2);
  1106. outw(0xb4, dev->iobase + PCI171x_CNTCTRL);
  1107. outw(0x74, dev->iobase + PCI171x_CNTCTRL);
  1108. if (mode == 1) {
  1109. outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2);
  1110. outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2);
  1111. outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1);
  1112. outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1);
  1113. }
  1114. DPRINTK("adv_pci1710 EDBG: END: start_pacer(...)\n");
  1115. }
  1116. /*
  1117. ==============================================================================
  1118. */
  1119. static int pci171x_ai_cancel(struct comedi_device *dev,
  1120. struct comedi_subdevice *s)
  1121. {
  1122. DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cancel(...)\n");
  1123. switch (this_board->cardtype) {
  1124. default:
  1125. devpriv->CntrlReg &= Control_CNT0;
  1126. devpriv->CntrlReg |= Control_SW;
  1127. outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
  1128. start_pacer(dev, -1, 0, 0);
  1129. outb(0, dev->iobase + PCI171x_CLRFIFO);
  1130. outb(0, dev->iobase + PCI171x_CLRINT);
  1131. break;
  1132. }
  1133. devpriv->ai_do = 0;
  1134. devpriv->ai_act_scan = 0;
  1135. s->async->cur_chan = 0;
  1136. devpriv->ai_buf_ptr = 0;
  1137. devpriv->neverending_ai = 0;
  1138. DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_cancel(...)\n");
  1139. return 0;
  1140. }
  1141. /*
  1142. ==============================================================================
  1143. */
  1144. static int pci171x_reset(struct comedi_device *dev)
  1145. {
  1146. DPRINTK("adv_pci1710 EDBG: BGN: pci171x_reset(...)\n");
  1147. outw(0x30, dev->iobase + PCI171x_CNTCTRL);
  1148. devpriv->CntrlReg = Control_SW | Control_CNT0; /* Software trigger, CNT0=external */
  1149. outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
  1150. outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
  1151. outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
  1152. start_pacer(dev, -1, 0, 0); /* stop 8254 */
  1153. devpriv->da_ranges = 0;
  1154. if (this_board->n_aochan) {
  1155. outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); /* set DACs to 0..5V */
  1156. outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
  1157. devpriv->ao_data[0] = 0x0000;
  1158. if (this_board->n_aochan > 1) {
  1159. outw(0, dev->iobase + PCI171x_DA2);
  1160. devpriv->ao_data[1] = 0x0000;
  1161. }
  1162. }
  1163. outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */
  1164. outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
  1165. outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
  1166. DPRINTK("adv_pci1710 EDBG: END: pci171x_reset(...)\n");
  1167. return 0;
  1168. }
  1169. /*
  1170. ==============================================================================
  1171. */
  1172. static int pci1720_reset(struct comedi_device *dev)
  1173. {
  1174. DPRINTK("adv_pci1710 EDBG: BGN: pci1720_reset(...)\n");
  1175. outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT); /* set synchronous output mode */
  1176. devpriv->da_ranges = 0xAA;
  1177. outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE); /* set all ranges to +/-5V */
  1178. outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */
  1179. outw(0x0800, dev->iobase + PCI1720_DA1);
  1180. outw(0x0800, dev->iobase + PCI1720_DA2);
  1181. outw(0x0800, dev->iobase + PCI1720_DA3);
  1182. outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
  1183. devpriv->ao_data[0] = 0x0800;
  1184. devpriv->ao_data[1] = 0x0800;
  1185. devpriv->ao_data[2] = 0x0800;
  1186. devpriv->ao_data[3] = 0x0800;
  1187. DPRINTK("adv_pci1710 EDBG: END: pci1720_reset(...)\n");
  1188. return 0;
  1189. }
  1190. /*
  1191. ==============================================================================
  1192. */
  1193. static int pci1710_reset(struct comedi_device *dev)
  1194. {
  1195. DPRINTK("adv_pci1710 EDBG: BGN: pci1710_reset(...)\n");
  1196. switch (this_board->cardtype) {
  1197. case TYPE_PCI1720:
  1198. return pci1720_reset(dev);
  1199. default:
  1200. return pci171x_reset(dev);
  1201. }
  1202. DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n");
  1203. }
  1204. /*
  1205. ==============================================================================
  1206. */
  1207. static int pci1710_attach(struct comedi_device *dev,
  1208. struct comedi_devconfig *it)
  1209. {
  1210. struct comedi_subdevice *s;
  1211. int ret, subdev, n_subdevices;
  1212. unsigned int irq;
  1213. unsigned long iobase;
  1214. struct pci_dev *pcidev;
  1215. int opt_bus, opt_slot;
  1216. const char *errstr;
  1217. unsigned char pci_bus, pci_slot, pci_func;
  1218. int i;
  1219. int board_index;
  1220. printk("comedi%d: adv_pci1710: ", dev->minor);
  1221. opt_bus = it->options[0];
  1222. opt_slot = it->options[1];
  1223. ret = alloc_private(dev, sizeof(struct pci1710_private));
  1224. if (ret < 0) {
  1225. printk(" - Allocation failed!\n");
  1226. return -ENOMEM;
  1227. }
  1228. /* Look for matching PCI device */
  1229. errstr = "not found!";
  1230. pcidev = NULL;
  1231. board_index = this_board - boardtypes;
  1232. while (NULL != (pcidev = pci_get_device(PCI_VENDOR_ID_ADVANTECH,
  1233. PCI_ANY_ID, pcidev))) {
  1234. if (strcmp(this_board->name, DRV_NAME) == 0) {
  1235. for (i = 0; i < n_boardtypes; ++i) {
  1236. if (pcidev->device == boardtypes[i].device_id) {
  1237. board_index = i;
  1238. break;
  1239. }
  1240. }
  1241. if (i == n_boardtypes)
  1242. continue;
  1243. } else {
  1244. if (pcidev->device != boardtypes[board_index].device_id)
  1245. continue;
  1246. }
  1247. /* Found matching vendor/device. */
  1248. if (opt_bus || opt_slot) {
  1249. /* Check bus/slot. */
  1250. if (opt_bus != pcidev->bus->number
  1251. || opt_slot != PCI_SLOT(pcidev->devfn))
  1252. continue; /* no match */
  1253. }
  1254. /*
  1255. * Look for device that isn't in use.
  1256. * Enable PCI device and request regions.
  1257. */
  1258. if (comedi_pci_enable(pcidev, DRV_NAME)) {
  1259. errstr =
  1260. "failed to enable PCI device and request regions!";
  1261. continue;
  1262. }
  1263. /* fixup board_ptr in case we were using the dummy entry with the driver name */
  1264. dev->board_ptr = &boardtypes[board_index];
  1265. break;
  1266. }
  1267. if (!pcidev) {
  1268. if (opt_bus || opt_slot) {
  1269. printk(" - Card at b:s %d:%d %s\n",
  1270. opt_bus, opt_slot, errstr);
  1271. } else {
  1272. printk(" - Card %s\n", errstr);
  1273. }
  1274. return -EIO;
  1275. }
  1276. pci_bus = pcidev->bus->number;
  1277. pci_slot = PCI_SLOT(pcidev->devfn);
  1278. pci_func = PCI_FUNC(pcidev->devfn);
  1279. irq = pcidev->irq;
  1280. iobase = pci_resource_start(pcidev, 2);
  1281. printk(", b:s:f=%d:%d:%d, io=0x%4lx", pci_bus, pci_slot, pci_func,
  1282. iobase);
  1283. dev->iobase = iobase;
  1284. dev->board_name = this_board->name;
  1285. devpriv->pcidev = pcidev;
  1286. n_subdevices = 0;
  1287. if (this_board->n_aichan)
  1288. n_subdevices++;
  1289. if (this_board->n_aochan)
  1290. n_subdevices++;
  1291. if (this_board->n_dichan)
  1292. n_subdevices++;
  1293. if (this_board->n_dochan)
  1294. n_subdevices++;
  1295. if (this_board->n_counter)
  1296. n_subdevices++;
  1297. ret = alloc_subdevices(dev, n_subdevices);
  1298. if (ret < 0) {
  1299. printk(" - Allocation failed!\n");
  1300. return ret;
  1301. }
  1302. pci1710_reset(dev);
  1303. if (this_board->have_irq) {
  1304. if (irq) {
  1305. if (request_irq(irq, interrupt_service_pci1710,
  1306. IRQF_SHARED, "Advantech PCI-1710",
  1307. dev)) {
  1308. printk
  1309. (", unable to allocate IRQ %d, DISABLING IT",
  1310. irq);
  1311. irq = 0; /* Can't use IRQ */
  1312. } else {
  1313. printk(", irq=%u", irq);
  1314. }
  1315. } else {
  1316. printk(", IRQ disabled");
  1317. }
  1318. } else {
  1319. irq = 0;
  1320. }
  1321. dev->irq = irq;
  1322. printk(".\n");
  1323. subdev = 0;
  1324. if (this_board->n_aichan) {
  1325. s = dev->subdevices + subdev;
  1326. dev->read_subdev = s;
  1327. s->type = COMEDI_SUBD_AI;
  1328. s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
  1329. if (this_board->n_aichand)
  1330. s->subdev_flags |= SDF_DIFF;
  1331. s->n_chan = this_board->n_aichan;
  1332. s->maxdata = this_board->ai_maxdata;
  1333. s->len_chanlist = this_board->n_aichan;
  1334. s->range_table = this_board->rangelist_ai;
  1335. s->cancel = pci171x_ai_cancel;
  1336. s->insn_read = pci171x_insn_read_ai;
  1337. if (irq) {
  1338. s->subdev_flags |= SDF_CMD_READ;
  1339. s->do_cmdtest = pci171x_ai_cmdtest;
  1340. s->do_cmd = pci171x_ai_cmd;
  1341. }
  1342. devpriv->i8254_osc_base = 100; /* 100ns=10MHz */
  1343. subdev++;
  1344. }
  1345. if (this_board->n_aochan) {
  1346. s = dev->subdevices + subdev;
  1347. s->type = COMEDI_SUBD_AO;
  1348. s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
  1349. s->n_chan = this_board->n_aochan;
  1350. s->maxdata = this_board->ao_maxdata;
  1351. s->len_chanlist = this_board->n_aochan;
  1352. s->range_table = this_board->rangelist_ao;
  1353. switch (this_board->cardtype) {
  1354. case TYPE_PCI1720:
  1355. s->insn_write = pci1720_insn_write_ao;
  1356. break;
  1357. default:
  1358. s->insn_write = pci171x_insn_write_ao;
  1359. break;
  1360. }
  1361. s->insn_read = pci171x_insn_read_ao;
  1362. subdev++;
  1363. }
  1364. if (this_board->n_dichan) {
  1365. s = dev->subdevices + subdev;
  1366. s->type = COMEDI_SUBD_DI;
  1367. s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
  1368. s->n_chan = this_board->n_dichan;
  1369. s->maxdata = 1;
  1370. s->len_chanlist = this_board->n_dichan;
  1371. s->range_table = &range_digital;
  1372. s->io_bits = 0; /* all bits input */
  1373. s->insn_bits = pci171x_insn_bits_di;
  1374. subdev++;
  1375. }
  1376. if (this_board->n_dochan) {
  1377. s = dev->subdevices + subdev;
  1378. s->type = COMEDI_SUBD_DO;
  1379. s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
  1380. s->n_chan = this_board->n_dochan;
  1381. s->maxdata = 1;
  1382. s->len_chanlist = this_board->n_dochan;
  1383. s->range_table = &range_digital;
  1384. /* all bits output */
  1385. s->io_bits = (1 << this_board->n_dochan) - 1;
  1386. s->state = 0;
  1387. s->insn_bits = pci171x_insn_bits_do;
  1388. subdev++;
  1389. }
  1390. if (this_board->n_counter) {
  1391. s = dev->subdevices + subdev;
  1392. s->type = COMEDI_SUBD_COUNTER;
  1393. s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
  1394. s->n_chan = this_board->n_counter;
  1395. s->len_chanlist = this_board->n_counter;
  1396. s->maxdata = 0xffff;
  1397. s->range_table = &range_unknown;
  1398. s->insn_read = pci171x_insn_counter_read;
  1399. s->insn_write = pci171x_insn_counter_write;
  1400. s->insn_config = pci171x_insn_counter_config;
  1401. subdev++;
  1402. }
  1403. devpriv->valid = 1;
  1404. return 0;
  1405. }
  1406. /*
  1407. ==============================================================================
  1408. */
  1409. static int pci1710_detach(struct comedi_device *dev)
  1410. {
  1411. if (dev->private) {
  1412. if (devpriv->valid)
  1413. pci1710_reset(dev);
  1414. if (dev->irq)
  1415. free_irq(dev->irq, dev);
  1416. if (devpriv->pcidev) {
  1417. if (dev->iobase)
  1418. comedi_pci_disable(devpriv->pcidev);
  1419. pci_dev_put(devpriv->pcidev);
  1420. }
  1421. }
  1422. return 0;
  1423. }
  1424. /*
  1425. ==============================================================================
  1426. */
  1427. static int __devinit driver_pci1710_pci_probe(struct pci_dev *dev,
  1428. const struct pci_device_id *ent)
  1429. {
  1430. return comedi_pci_auto_config(dev, driver_pci1710.driver_name);
  1431. }
  1432. static void __devexit driver_pci1710_pci_remove(struct pci_dev *dev)
  1433. {
  1434. comedi_pci_auto_unconfig(dev);
  1435. }
  1436. static struct pci_driver driver_pci1710_pci_driver = {
  1437. .id_table = pci1710_pci_table,
  1438. .probe = &driver_pci1710_pci_probe,
  1439. .remove = __devexit_p(&driver_pci1710_pci_remove)
  1440. };
  1441. static int __init driver_pci1710_init_module(void)
  1442. {
  1443. int retval;
  1444. retval = comedi_driver_register(&driver_pci1710);
  1445. if (retval < 0)
  1446. return retval;
  1447. driver_pci1710_pci_driver.name = (char *)driver_pci1710.driver_name;
  1448. return pci_register_driver(&driver_pci1710_pci_driver);
  1449. }
  1450. static void __exit driver_pci1710_cleanup_module(void)
  1451. {
  1452. pci_unregister_driver(&driver_pci1710_pci_driver);
  1453. comedi_driver_unregister(&driver_pci1710);
  1454. }
  1455. module_init(driver_pci1710_init_module);
  1456. module_exit(driver_pci1710_cleanup_module);
  1457. /*
  1458. ==============================================================================
  1459. */
  1460. MODULE_AUTHOR("Comedi http://www.comedi.org");
  1461. MODULE_DESCRIPTION("Comedi low-level driver");
  1462. MODULE_LICENSE("GPL");