Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
hwdrv_apci3120.c
Go to the documentation of this file.
1 
24 /*
25  +-----------------------------------------------------------------------+
26  | (C) ADDI-DATA GmbH Dieselstrasse 3 D-77833 Ottersweier |
27  +-----------------------------------------------------------------------+
28  | Tel : +49 (0) 7223/9493-0 | email : [email protected] |
29  | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com |
30  +-----------------------------------------------------------------------+
31  | Project : APCI-3120 | Compiler : GCC |
32  | Module name : hwdrv_apci3120.c| Version : 2.96 |
33  +-------------------------------+---------------------------------------+
34  | Project manager: Eric Stolz | Date : 02/12/2002 |
35  +-----------------------------------------------------------------------+
36  | Description :APCI3120 Module. Hardware abstraction Layer for APCI3120|
37  +-----------------------------------------------------------------------+
38  | UPDATE'S |
39  +-----------------------------------------------------------------------+
40  | Date | Author | Description of updates |
41  +----------+-----------+------------------------------------------------+
42  | | | |
43  | | | |
44  +----------+-----------+------------------------------------------------+
45 */
46 
47 #include "hwdrv_apci3120.h"
48 static unsigned int ui_Temp;
49 
50 /* FUNCTION DEFINITIONS */
51 
52 /*
53 +----------------------------------------------------------------------------+
54 | ANALOG INPUT SUBDEVICE |
55 +----------------------------------------------------------------------------+
56 */
57 
58 /*
59 +----------------------------------------------------------------------------+
60 | Function name :int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev,|
61 | struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
62 | |
63 +----------------------------------------------------------------------------+
64 | Task : Calls card specific function |
65 | |
66 +----------------------------------------------------------------------------+
67 | Input Parameters : struct comedi_device *dev |
68 | struct comedi_subdevice *s |
69 | struct comedi_insn *insn |
70 | unsigned int *data |
71 +----------------------------------------------------------------------------+
72 | Return Value : |
73 | |
74 +----------------------------------------------------------------------------+
75 */
76 
78  struct comedi_insn *insn, unsigned int *data)
79 {
80  unsigned int i;
81 
82  if ((data[0] != APCI3120_EOC_MODE) && (data[0] != APCI3120_EOS_MODE))
83  return -1;
84 
85  /* Check for Conversion time to be added ?? */
86  devpriv->ui_EocEosConversionTime = data[2];
87 
88  if (data[0] == APCI3120_EOS_MODE) {
89 
90  /* Test the number of the channel */
91  for (i = 0; i < data[3]; i++) {
92 
93  if (CR_CHAN(data[4 + i]) >=
94  devpriv->s_EeParameters.i_NbrAiChannel) {
95  printk("bad channel list\n");
96  return -2;
97  }
98  }
99 
100  devpriv->b_InterruptMode = APCI3120_EOS_MODE;
101 
102  if (data[1])
103  devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
104  else
105  devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
106  /* Copy channel list and Range List to devpriv */
107 
108  devpriv->ui_AiNbrofChannels = data[3];
109  for (i = 0; i < devpriv->ui_AiNbrofChannels; i++)
110  devpriv->ui_AiChannelList[i] = data[4 + i];
111 
112  } else { /* EOC */
113  devpriv->b_InterruptMode = APCI3120_EOC_MODE;
114  if (data[1])
115  devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
116  else
117  devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
118  }
119 
120  return insn->n;
121 }
122 
123 /*
124 +----------------------------------------------------------------------------+
125 | Function name :int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, |
126 | struct comedi_subdevice *s,struct comedi_insn *insn, unsigned int *data) |
127 | |
128 +----------------------------------------------------------------------------+
129 | Task : card specific function |
130 | Reads analog input in synchronous mode |
131 | EOC and EOS is selected as per configured |
132 | if no conversion time is set uses default conversion |
133 | time 10 microsec. |
134 | |
135 +----------------------------------------------------------------------------+
136 | Input Parameters : struct comedi_device *dev |
137 | struct comedi_subdevice *s |
138 | struct comedi_insn *insn |
139 | unsigned int *data |
140 +----------------------------------------------------------------------------+
141 | Return Value : |
142 | |
143 +----------------------------------------------------------------------------+
144 */
145 
147  struct comedi_insn *insn, unsigned int *data)
148 {
149  unsigned short us_ConvertTiming, us_TmpValue, i;
150  unsigned char b_Tmp;
151 
152  /* fix conversion time to 10 us */
153  if (!devpriv->ui_EocEosConversionTime) {
154  printk("No timer0 Value using 10 us\n");
155  us_ConvertTiming = 10;
156  } else
157  us_ConvertTiming = (unsigned short) (devpriv->ui_EocEosConversionTime / 1000); /* nano to useconds */
158 
159  /* this_board->ai_read(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]); */
160 
161  /* Clear software registers */
162  devpriv->b_TimerSelectMode = 0;
163  devpriv->b_ModeSelectRegister = 0;
164  devpriv->us_OutputRegister = 0;
165 /* devpriv->b_DigitalOutputRegister=0; */
166 
167  if (insn->unused[0] == 222) { /* second insn read */
168  for (i = 0; i < insn->n; i++)
169  data[i] = devpriv->ui_AiReadData[i];
170  } else {
171  devpriv->tsk_Current = current; /* Save the current process task structure */
172 /*
173  * Testing if board have the new Quartz and calculate the time value
174  * to set in the timer
175  */
176 
177  us_TmpValue =
178  (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
179 
180  /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
181  if ((us_TmpValue & 0x00B0) == 0x00B0
182  || !strcmp(this_board->pc_DriverName, "apci3001")) {
183  us_ConvertTiming = (us_ConvertTiming * 2) - 2;
184  } else {
185  us_ConvertTiming =
186  ((us_ConvertTiming * 12926) / 10000) - 1;
187  }
188 
189  us_TmpValue = (unsigned short) devpriv->b_InterruptMode;
190 
191  switch (us_TmpValue) {
192 
193  case APCI3120_EOC_MODE:
194 
195 /*
196  * Testing the interrupt flag and set the EOC bit Clears the FIFO
197  */
198  inw(devpriv->iobase + APCI3120_RESET_FIFO);
199 
200  /* Initialize the sequence array */
201 
202  /* if (!i_APCI3120_SetupChannelList(dev,s,1,chanlist,0)) return -EINVAL; */
203 
204  if (!i_APCI3120_SetupChannelList(dev, s, 1,
205  &insn->chanspec, 0))
206  return -EINVAL;
207 
208  /* Initialize Timer 0 mode 4 */
209  devpriv->b_TimerSelectMode =
210  (devpriv->
211  b_TimerSelectMode & 0xFC) |
213  outb(devpriv->b_TimerSelectMode,
214  devpriv->iobase + APCI3120_TIMER_CRT1);
215 
216  /* Reset the scan bit and Disables the EOS, DMA, EOC interrupt */
217  devpriv->b_ModeSelectRegister =
218  devpriv->
219  b_ModeSelectRegister & APCI3120_DISABLE_SCAN;
220 
221  if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
222 
223  /* Disables the EOS,DMA and enables the EOC interrupt */
224  devpriv->b_ModeSelectRegister =
225  (devpriv->
226  b_ModeSelectRegister &
229  inw(devpriv->iobase);
230 
231  } else {
232  devpriv->b_ModeSelectRegister =
233  devpriv->
234  b_ModeSelectRegister &
236  }
237 
238  outb(devpriv->b_ModeSelectRegister,
240 
241  /* Sets gate 0 */
242  devpriv->us_OutputRegister =
243  (devpriv->
244  us_OutputRegister & APCI3120_CLEAR_PA_PR) |
246  outw(devpriv->us_OutputRegister,
247  devpriv->iobase + APCI3120_WR_ADDRESS);
248 
249  /* Select Timer 0 */
250  b_Tmp = ((devpriv->
251  b_DigitalOutputRegister) & 0xF0) |
253  outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
254 
255  /* Set the conversion time */
256  outw(us_ConvertTiming,
257  devpriv->iobase + APCI3120_TIMER_VALUE);
258 
259  us_TmpValue =
260  (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
261 
262  if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
263 
264  do {
265  /* Waiting for the end of conversion */
266  us_TmpValue =
267  inw(devpriv->iobase +
269  } while ((us_TmpValue & APCI3120_EOC) ==
270  APCI3120_EOC);
271 
272  /* Read the result in FIFO and put it in insn data pointer */
273  us_TmpValue = inw(devpriv->iobase + 0);
274  *data = us_TmpValue;
275 
276  inw(devpriv->iobase + APCI3120_RESET_FIFO);
277  }
278 
279  break;
280 
281  case APCI3120_EOS_MODE:
282 
283  inw(devpriv->iobase);
284  /* Clears the FIFO */
285  inw(devpriv->iobase + APCI3120_RESET_FIFO);
286  /* clear PA PR and disable timer 0 */
287 
288  devpriv->us_OutputRegister =
289  (devpriv->
290  us_OutputRegister & APCI3120_CLEAR_PA_PR) |
292 
293  outw(devpriv->us_OutputRegister,
294  devpriv->iobase + APCI3120_WR_ADDRESS);
295 
296  if (!i_APCI3120_SetupChannelList(dev, s,
297  devpriv->ui_AiNbrofChannels,
298  devpriv->ui_AiChannelList, 0))
299  return -EINVAL;
300 
301  /* Initialize Timer 0 mode 2 */
302  devpriv->b_TimerSelectMode =
303  (devpriv->
304  b_TimerSelectMode & 0xFC) |
306  outb(devpriv->b_TimerSelectMode,
307  devpriv->iobase + APCI3120_TIMER_CRT1);
308 
309  /* Select Timer 0 */
310  b_Tmp = ((devpriv->
311  b_DigitalOutputRegister) & 0xF0) |
313  outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
314 
315  /* Set the conversion time */
316  outw(us_ConvertTiming,
317  devpriv->iobase + APCI3120_TIMER_VALUE);
318 
319  /* Set the scan bit */
320  devpriv->b_ModeSelectRegister =
321  devpriv->
322  b_ModeSelectRegister | APCI3120_ENABLE_SCAN;
323  outb(devpriv->b_ModeSelectRegister,
325 
326  /* If Interrupt function is loaded */
327  if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
328  /* Disables the EOC,DMA and enables the EOS interrupt */
329  devpriv->b_ModeSelectRegister =
330  (devpriv->
331  b_ModeSelectRegister &
334  inw(devpriv->iobase);
335 
336  } else
337  devpriv->b_ModeSelectRegister =
338  devpriv->
339  b_ModeSelectRegister &
341 
342  outb(devpriv->b_ModeSelectRegister,
344 
345  inw(devpriv->iobase + APCI3120_RD_STATUS);
346 
347  /* Sets gate 0 */
348 
349  devpriv->us_OutputRegister =
350  devpriv->
351  us_OutputRegister | APCI3120_ENABLE_TIMER0;
352  outw(devpriv->us_OutputRegister,
353  devpriv->iobase + APCI3120_WR_ADDRESS);
354 
355  /* Start conversion */
356  outw(0, devpriv->iobase + APCI3120_START_CONVERSION);
357 
358  /* Waiting of end of conversion if interrupt is not installed */
359  if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
360  /* Waiting the end of conversion */
361  do {
362  us_TmpValue =
363  inw(devpriv->iobase +
365  } while ((us_TmpValue & APCI3120_EOS) !=
366  APCI3120_EOS);
367 
368  for (i = 0; i < devpriv->ui_AiNbrofChannels;
369  i++) {
370  /* Read the result in FIFO and write them in shared memory */
371  us_TmpValue = inw(devpriv->iobase);
372  data[i] = (unsigned int) us_TmpValue;
373  }
374 
375  devpriv->b_InterruptMode = APCI3120_EOC_MODE; /* Restore defaults. */
376  }
377  break;
378 
379  default:
380  printk("inputs wrong\n");
381 
382  }
383  devpriv->ui_EocEosConversionTime = 0; /* re initializing the variable; */
384  }
385 
386  return insn->n;
387 
388 }
389 
390 /*
391 +----------------------------------------------------------------------------+
392 | Function name :int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev,|
393 | struct comedi_subdevice *s)|
394 | |
395 +----------------------------------------------------------------------------+
396 | Task : Stops Cyclic acquisition |
397 | |
398 +----------------------------------------------------------------------------+
399 | Input Parameters : struct comedi_device *dev |
400 | struct comedi_subdevice *s |
401 | |
402 +----------------------------------------------------------------------------+
403 | Return Value :0 |
404 | |
405 +----------------------------------------------------------------------------+
406 */
407 
409 {
410  /* Disable A2P Fifo write and AMWEN signal */
411  outw(0, devpriv->i_IobaseAddon + 4);
412 
413  /* Disable Bus Master ADD ON */
414  outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
415  outw(0, devpriv->i_IobaseAddon + 2);
416  outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
417  outw(0, devpriv->i_IobaseAddon + 2);
418 
419  /* Disable BUS Master PCI */
420  outl(0, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
421 
422  /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR)&(~AINT_WRITE_COMPL),
423  * devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR); stop amcc irqs */
424 
425  /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR)&(~EN_A2P_TRANSFERS),
426  * devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR); stop DMA */
427 
428  /* Disable ext trigger */
430 
431  devpriv->us_OutputRegister = 0;
432  /* stop counters */
433  outw(devpriv->
434  us_OutputRegister & APCI3120_DISABLE_TIMER0 &
436 
438 
439  /* DISABLE_ALL_INTERRUPT */
442  /* Flush FIFO */
444  inw(dev->iobase + APCI3120_RD_STATUS);
445  devpriv->ui_AiActualScan = 0;
446  devpriv->ui_AiActualScanPosition = 0;
447  s->async->cur_chan = 0;
448  devpriv->ui_AiBufferPtr = 0;
449  devpriv->b_AiContinuous = 0;
450  devpriv->ui_DmaActualBuffer = 0;
451 
452  devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
453  devpriv->b_InterruptMode = APCI3120_EOC_MODE;
454  devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
455  i_APCI3120_Reset(dev);
456  return 0;
457 }
458 
459 /*
460 +----------------------------------------------------------------------------+
461 | Function name :int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev|
462 | ,struct comedi_subdevice *s,struct comedi_cmd *cmd) |
463 | |
464 +----------------------------------------------------------------------------+
465 | Task : Test validity for a command for cyclic anlog input |
466 | acquisition |
467 | |
468 +----------------------------------------------------------------------------+
469 | Input Parameters : struct comedi_device *dev |
470 | struct comedi_subdevice *s |
471 | struct comedi_cmd *cmd |
472 +----------------------------------------------------------------------------+
473 | Return Value :0 |
474 | |
475 +----------------------------------------------------------------------------+
476 */
477 
479  struct comedi_cmd *cmd)
480 {
481  int err = 0;
482 
483  /* Step 1 : check if triggers are trivially valid */
484 
485  err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
486  err |= cfc_check_trigger_src(&cmd->scan_begin_src,
488  err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
489  err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
490  err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
491 
492  if (err)
493  return 1;
494 
495  /* Step 2a : make sure trigger sources are unique */
496 
497  err |= cfc_check_trigger_is_unique(cmd->start_src);
498  err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
499  err |= cfc_check_trigger_is_unique(cmd->stop_src);
500 
501  /* Step 2b : and mutually compatible */
502 
503  if (err)
504  return 2;
505 
506  /* step 3: make sure arguments are trivially compatible */
507 
508  if (cmd->start_arg != 0) {
509  cmd->start_arg = 0;
510  err++;
511  }
512 
513  if (cmd->scan_begin_src == TRIG_TIMER) { /* Test Delay timing */
514  if (cmd->scan_begin_arg <
515  devpriv->s_EeParameters.ui_MinDelaytimeNs) {
516  cmd->scan_begin_arg =
517  devpriv->s_EeParameters.ui_MinDelaytimeNs;
518  err++;
519  }
520  }
521 
522  if (cmd->convert_src == TRIG_TIMER) { /* Test Acquisition timing */
523  if (cmd->scan_begin_src == TRIG_TIMER) {
524  if ((cmd->convert_arg)
525  && (cmd->convert_arg <
526  devpriv->s_EeParameters.
527  ui_MinAcquisitiontimeNs)) {
528  cmd->convert_arg = devpriv->s_EeParameters.
529  ui_MinAcquisitiontimeNs;
530  err++;
531  }
532  } else {
533  if (cmd->convert_arg <
534  devpriv->s_EeParameters.ui_MinAcquisitiontimeNs
535  ) {
536  cmd->convert_arg = devpriv->s_EeParameters.
537  ui_MinAcquisitiontimeNs;
538  err++;
539 
540  }
541  }
542  }
543 
544  if (!cmd->chanlist_len) {
545  cmd->chanlist_len = 1;
546  err++;
547  }
548  if (cmd->chanlist_len > this_board->i_AiChannelList) {
549  cmd->chanlist_len = this_board->i_AiChannelList;
550  err++;
551  }
552  if (cmd->stop_src == TRIG_COUNT) {
553  if (!cmd->stop_arg) {
554  cmd->stop_arg = 1;
555  err++;
556  }
557  } else { /* TRIG_NONE */
558  if (cmd->stop_arg != 0) {
559  cmd->stop_arg = 0;
560  err++;
561  }
562  }
563 
564  if (err)
565  return 3;
566 
567  /* step 4: fix up any arguments */
568 
569  if (cmd->convert_src == TRIG_TIMER) {
570 
571  if (cmd->scan_begin_src == TRIG_TIMER &&
572  cmd->scan_begin_arg <
573  cmd->convert_arg * cmd->scan_end_arg) {
574  cmd->scan_begin_arg =
575  cmd->convert_arg * cmd->scan_end_arg;
576  err++;
577  }
578  }
579 
580  if (err)
581  return 4;
582 
583  return 0;
584 }
585 
586 /*
587 +----------------------------------------------------------------------------+
588 | Function name : int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, |
589 | struct comedi_subdevice *s) |
590 | |
591 +----------------------------------------------------------------------------+
592 | Task : Does asynchronous acquisition |
593 | Determines the mode 1 or 2. |
594 | |
595 +----------------------------------------------------------------------------+
596 | Input Parameters : struct comedi_device *dev |
597 | struct comedi_subdevice *s |
598 | |
599 +----------------------------------------------------------------------------+
600 | Return Value : |
601 | |
602 +----------------------------------------------------------------------------+
603 */
604 
606 {
607  struct comedi_cmd *cmd = &s->async->cmd;
608 
609  /* loading private structure with cmd structure inputs */
610  devpriv->ui_AiFlags = cmd->flags;
611  devpriv->ui_AiNbrofChannels = cmd->chanlist_len;
612  devpriv->ui_AiScanLength = cmd->scan_end_arg;
613  devpriv->pui_AiChannelList = cmd->chanlist;
614 
615  /* UPDATE-0.7.57->0.7.68devpriv->AiData=s->async->data; */
616  devpriv->AiData = s->async->prealloc_buf;
617  /* UPDATE-0.7.57->0.7.68devpriv->ui_AiDataLength=s->async->data_len; */
618  devpriv->ui_AiDataLength = s->async->prealloc_bufsz;
619 
620  if (cmd->stop_src == TRIG_COUNT)
621  devpriv->ui_AiNbrofScans = cmd->stop_arg;
622  else
623  devpriv->ui_AiNbrofScans = 0;
624 
625  devpriv->ui_AiTimer0 = 0; /* variables changed to timer0,timer1 */
626  devpriv->ui_AiTimer1 = 0;
627  if ((devpriv->ui_AiNbrofScans == 0) || (devpriv->ui_AiNbrofScans == -1))
628  devpriv->b_AiContinuous = 1; /* user want neverending analog acquisition */
629  /* stopped using cancel */
630 
631  if (cmd->start_src == TRIG_EXT)
632  devpriv->b_ExttrigEnable = APCI3120_ENABLE;
633  else
634  devpriv->b_ExttrigEnable = APCI3120_DISABLE;
635 
636  if (cmd->scan_begin_src == TRIG_FOLLOW) {
637  /* mode 1 or 3 */
638  if (cmd->convert_src == TRIG_TIMER) {
639  /* mode 1 */
640 
641  devpriv->ui_AiTimer0 = cmd->convert_arg; /* timer constant in nano seconds */
642  /* return this_board->ai_cmd(1,dev,s); */
643  return i_APCI3120_CyclicAnalogInput(1, dev, s);
644  }
645 
646  }
647  if ((cmd->scan_begin_src == TRIG_TIMER)
648  && (cmd->convert_src == TRIG_TIMER)) {
649  /* mode 2 */
650  devpriv->ui_AiTimer1 = cmd->scan_begin_arg;
651  devpriv->ui_AiTimer0 = cmd->convert_arg; /* variable changed timer2 to timer0 */
652  /* return this_board->ai_cmd(2,dev,s); */
653  return i_APCI3120_CyclicAnalogInput(2, dev, s);
654  }
655  return -1;
656 }
657 
658 /*
659 +----------------------------------------------------------------------------+
660 | Function name : int i_APCI3120_CyclicAnalogInput(int mode, |
661 | struct comedi_device * dev,struct comedi_subdevice * s) |
662 +----------------------------------------------------------------------------+
663 | Task : This is used for analog input cyclic acquisition |
664 | Performs the command operations. |
665 | If DMA is configured does DMA initialization |
666 | otherwise does the acquisition with EOS interrupt. |
667 | |
668 +----------------------------------------------------------------------------+
669 | Input Parameters : |
670 | |
671 | |
672 +----------------------------------------------------------------------------+
673 | Return Value : |
674 | |
675 +----------------------------------------------------------------------------+
676 */
677 
679  struct comedi_subdevice *s)
680 {
681  unsigned char b_Tmp;
682  unsigned int ui_Tmp, ui_DelayTiming = 0, ui_TimerValue1 = 0, dmalen0 =
683  0, dmalen1 = 0, ui_TimerValue2 =
684  0, ui_TimerValue0, ui_ConvertTiming;
685  unsigned short us_TmpValue;
686 
687  /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
688  /* devpriv->b_AiCyclicAcquisition=APCI3120_ENABLE; */
689  /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
690 
691  /*******************/
692  /* Resets the FIFO */
693  /*******************/
695 
696  /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
697  /* inw(dev->iobase+APCI3120_RD_STATUS); */
698  /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
699 
700  /***************************/
701  /* Acquisition initialized */
702  /***************************/
703  /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
704  devpriv->b_AiCyclicAcquisition = APCI3120_ENABLE;
705  /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
706 
707  /* clear software registers */
708  devpriv->b_TimerSelectMode = 0;
709  devpriv->us_OutputRegister = 0;
710  devpriv->b_ModeSelectRegister = 0;
711  /* devpriv->b_DigitalOutputRegister=0; */
712 
713  /* COMMENT JK 07.05.04: Followings calls are in i_APCI3120_StartAnalogInputAcquisition */
714 
715  /****************************/
716  /* Clear Timer Write TC int */
717  /****************************/
719  devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_REG_INTCSR);
720 
721  /************************************/
722  /* Clears the timer status register */
723  /************************************/
724 
725  /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
726  /* inw(dev->iobase+APCI3120_TIMER_STATUS_REGISTER); */
727  /* inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); */
728  /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
729 
730  /**************************/
731  /* Disables All Timer */
732  /* Sets PR and PA to 0 */
733  /**************************/
734  devpriv->us_OutputRegister = devpriv->us_OutputRegister &
737 
738  outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
739 
740  /*******************/
741  /* Resets the FIFO */
742  /*******************/
743  /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
744  inb(devpriv->iobase + APCI3120_RESET_FIFO);
745  /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
746 
747  devpriv->ui_AiActualScan = 0;
748  devpriv->ui_AiActualScanPosition = 0;
749  s->async->cur_chan = 0;
750  devpriv->ui_AiBufferPtr = 0;
751  devpriv->ui_DmaActualBuffer = 0;
752 
753  /* value for timer2 minus -2 has to be done .....dunno y?? */
754  ui_TimerValue2 = devpriv->ui_AiNbrofScans - 2;
755  ui_ConvertTiming = devpriv->ui_AiTimer0;
756 
757  if (mode == 2)
758  ui_DelayTiming = devpriv->ui_AiTimer1;
759 
760  /**********************************/
761  /* Initializes the sequence array */
762  /**********************************/
763  if (!i_APCI3120_SetupChannelList(dev, s, devpriv->ui_AiNbrofChannels,
764  devpriv->pui_AiChannelList, 0))
765  return -EINVAL;
766 
767  us_TmpValue = (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
768 /*** EL241003 : add this section in comment because floats must not be used
769  if((us_TmpValue & 0x00B0)==0x00B0)
770  {
771  f_ConvertValue=(((float)ui_ConvertTiming * 0.002) - 2);
772  ui_TimerValue0=(unsigned int)f_ConvertValue;
773  if (mode==2)
774  {
775  f_DelayValue = (((float)ui_DelayTiming * 0.00002) - 2);
776  ui_TimerValue1 = (unsigned int) f_DelayValue;
777  }
778  }
779  else
780  {
781  f_ConvertValue=(((float)ui_ConvertTiming * 0.0012926) - 1);
782  ui_TimerValue0=(unsigned int)f_ConvertValue;
783  if (mode == 2)
784  {
785  f_DelayValue = (((float)ui_DelayTiming * 0.000012926) - 1);
786  ui_TimerValue1 = (unsigned int) f_DelayValue;
787  }
788  }
789 ***********************************************************************************************/
790 /*** EL241003 Begin : add this section to replace floats calculation by integer calculations **/
791  /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
792  if ((us_TmpValue & 0x00B0) == 0x00B0
793  || !strcmp(this_board->pc_DriverName, "apci3001")) {
794  ui_TimerValue0 = ui_ConvertTiming * 2 - 2000;
795  ui_TimerValue0 = ui_TimerValue0 / 1000;
796 
797  if (mode == 2) {
798  ui_DelayTiming = ui_DelayTiming / 1000;
799  ui_TimerValue1 = ui_DelayTiming * 2 - 200;
800  ui_TimerValue1 = ui_TimerValue1 / 100;
801  }
802  } else {
803  ui_ConvertTiming = ui_ConvertTiming / 1000;
804  ui_TimerValue0 = ui_ConvertTiming * 12926 - 10000;
805  ui_TimerValue0 = ui_TimerValue0 / 10000;
806 
807  if (mode == 2) {
808  ui_DelayTiming = ui_DelayTiming / 1000;
809  ui_TimerValue1 = ui_DelayTiming * 12926 - 1;
810  ui_TimerValue1 = ui_TimerValue1 / 1000000;
811  }
812  }
813 /*** EL241003 End ******************************************************************************/
814 
815  if (devpriv->b_ExttrigEnable == APCI3120_ENABLE)
816  i_APCI3120_ExttrigEnable(dev); /* activate EXT trigger */
817  switch (mode) {
818  case 1:
819  /* init timer0 in mode 2 */
820  devpriv->b_TimerSelectMode =
821  (devpriv->
822  b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
823  outb(devpriv->b_TimerSelectMode,
824  dev->iobase + APCI3120_TIMER_CRT1);
825 
826  /* Select Timer 0 */
827  b_Tmp = ((devpriv->
828  b_DigitalOutputRegister) & 0xF0) |
830  outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
831  /* Set the conversion time */
832  outw(((unsigned short) ui_TimerValue0),
834  break;
835 
836  case 2:
837  /* init timer1 in mode 2 */
838  devpriv->b_TimerSelectMode =
839  (devpriv->
840  b_TimerSelectMode & 0xF3) | APCI3120_TIMER_1_MODE_2;
841  outb(devpriv->b_TimerSelectMode,
842  dev->iobase + APCI3120_TIMER_CRT1);
843 
844  /* Select Timer 1 */
845  b_Tmp = ((devpriv->
846  b_DigitalOutputRegister) & 0xF0) |
848  outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
849  /* Set the conversion time */
850  outw(((unsigned short) ui_TimerValue1),
852 
853  /* init timer0 in mode 2 */
854  devpriv->b_TimerSelectMode =
855  (devpriv->
856  b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
857  outb(devpriv->b_TimerSelectMode,
858  dev->iobase + APCI3120_TIMER_CRT1);
859 
860  /* Select Timer 0 */
861  b_Tmp = ((devpriv->
862  b_DigitalOutputRegister) & 0xF0) |
864  outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
865 
866  /* Set the conversion time */
867  outw(((unsigned short) ui_TimerValue0),
869  break;
870 
871  }
872  /* ##########common for all modes################# */
873 
874  /***********************/
875  /* Clears the SCAN bit */
876  /***********************/
877 
878  /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
879  /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister | APCI3120_DISABLE_SCAN; */
880 
881  devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
883  /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
884 
885  outb(devpriv->b_ModeSelectRegister,
887 
888  /* If DMA is disabled */
889  if (devpriv->us_UseDma == APCI3120_DISABLE) {
890  /* disable EOC and enable EOS */
891  devpriv->b_InterruptMode = APCI3120_EOS_MODE;
892  devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
893 
894  devpriv->b_ModeSelectRegister =
895  (devpriv->
896  b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT) |
898  outb(devpriv->b_ModeSelectRegister,
900 
901  if (!devpriv->b_AiContinuous) {
902 /*
903  * configure Timer2 For counting EOS Reset gate 2 of Timer 2 to
904  * disable it (Set Bit D14 to 0)
905  */
906  devpriv->us_OutputRegister =
907  devpriv->
908  us_OutputRegister & APCI3120_DISABLE_TIMER2;
909  outw(devpriv->us_OutputRegister,
910  dev->iobase + APCI3120_WR_ADDRESS);
911 
912  /* DISABLE TIMER intERRUPT */
913  devpriv->b_ModeSelectRegister =
914  devpriv->
915  b_ModeSelectRegister &
917  outb(devpriv->b_ModeSelectRegister,
919 
920  /* (1) Init timer 2 in mode 0 and write timer value */
921  devpriv->b_TimerSelectMode =
922  (devpriv->
923  b_TimerSelectMode & 0x0F) |
925  outb(devpriv->b_TimerSelectMode,
926  dev->iobase + APCI3120_TIMER_CRT1);
927 
928  /* Writing LOW unsigned short */
929  b_Tmp = ((devpriv->
930  b_DigitalOutputRegister) & 0xF0) |
932  outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
933  outw(LOWORD(ui_TimerValue2),
935 
936  /* Writing HIGH unsigned short */
937  b_Tmp = ((devpriv->
938  b_DigitalOutputRegister) & 0xF0) |
940  outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
941  outw(HIWORD(ui_TimerValue2),
943 
944  /* (2) Reset FC_TIMER BIT Clearing timer status register */
946  /* enable timer counter and disable watch dog */
947  devpriv->b_ModeSelectRegister =
948  (devpriv->
949  b_ModeSelectRegister |
952  /* select EOS clock input for timer 2 */
953  devpriv->b_ModeSelectRegister =
954  devpriv->
955  b_ModeSelectRegister |
957  /* Enable timer2 interrupt */
958  devpriv->b_ModeSelectRegister =
959  devpriv->
960  b_ModeSelectRegister |
962  outb(devpriv->b_ModeSelectRegister,
964  devpriv->b_Timer2Mode = APCI3120_COUNTER;
965  devpriv->b_Timer2Interrupt = APCI3120_ENABLE;
966  }
967  } else {
968  /* If DMA Enabled */
969 
970  /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
971  /* inw(dev->iobase+0); reset EOC bit */
972  /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
973  devpriv->b_InterruptMode = APCI3120_DMA_MODE;
974 
975  /************************************/
976  /* Disables the EOC, EOS interrupt */
977  /************************************/
978  devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
980 
981  outb(devpriv->b_ModeSelectRegister,
983 
984  dmalen0 = devpriv->ui_DmaBufferSize[0];
985  dmalen1 = devpriv->ui_DmaBufferSize[1];
986 
987  if (!devpriv->b_AiContinuous) {
988 
989  if (dmalen0 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2)) { /* must we fill full first buffer? */
990  dmalen0 =
991  devpriv->ui_AiNbrofScans *
992  devpriv->ui_AiScanLength * 2;
993  } else if (dmalen1 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2 - dmalen0)) /* and must we fill full second buffer when first is once filled? */
994  dmalen1 =
995  devpriv->ui_AiNbrofScans *
996  devpriv->ui_AiScanLength * 2 - dmalen0;
997  }
998 
999  if (devpriv->ui_AiFlags & TRIG_WAKE_EOS) {
1000  /* don't we want wake up every scan? */
1001  if (dmalen0 > (devpriv->ui_AiScanLength * 2)) {
1002  dmalen0 = devpriv->ui_AiScanLength * 2;
1003  if (devpriv->ui_AiScanLength & 1)
1004  dmalen0 += 2;
1005  }
1006  if (dmalen1 > (devpriv->ui_AiScanLength * 2)) {
1007  dmalen1 = devpriv->ui_AiScanLength * 2;
1008  if (devpriv->ui_AiScanLength & 1)
1009  dmalen1 -= 2;
1010  if (dmalen1 < 4)
1011  dmalen1 = 4;
1012  }
1013  } else { /* isn't output buff smaller that our DMA buff? */
1014  if (dmalen0 > (devpriv->ui_AiDataLength))
1015  dmalen0 = devpriv->ui_AiDataLength;
1016  if (dmalen1 > (devpriv->ui_AiDataLength))
1017  dmalen1 = devpriv->ui_AiDataLength;
1018  }
1019  devpriv->ui_DmaBufferUsesize[0] = dmalen0;
1020  devpriv->ui_DmaBufferUsesize[1] = dmalen1;
1021 
1022  /* Initialize DMA */
1023 
1024 /*
1025  * Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS
1026  * register 1
1027  */
1029  outl(ui_Tmp, devpriv->i_IobaseAmcc + AMCC_OP_REG_AGCSTS);
1030 
1031  /* changed since 16 bit interface for add on */
1032  /*********************/
1033  /* ENABLE BUS MASTER */
1034  /*********************/
1035  outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1037  devpriv->i_IobaseAddon + 2);
1038 
1039  outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1041  devpriv->i_IobaseAddon + 2);
1042 
1043 /*
1044  * TO VERIFIED BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1045  * driver
1046  */
1047  outw(0x1000, devpriv->i_IobaseAddon + 2);
1048  /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1049 
1050  /* 2 No change */
1051  /* A2P FIFO MANAGEMENT */
1052  /* A2P fifo reset & transfer control enable */
1053 
1054  /***********************/
1055  /* A2P FIFO MANAGEMENT */
1056  /***********************/
1057  outl(APCI3120_A2P_FIFO_MANAGEMENT, devpriv->i_IobaseAmcc +
1059 
1060 /*
1061  * 3
1062  * beginning address of dma buf The 32 bit address of dma buffer
1063  * is converted into two 16 bit addresses Can done by using _attach
1064  * and put into into an array array used may be for differnet pages
1065  */
1066 
1067  /* DMA Start Address Low */
1068  outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1069  outw((devpriv->ul_DmaBufferHw[0] & 0xFFFF),
1070  devpriv->i_IobaseAddon + 2);
1071 
1072  /*************************/
1073  /* DMA Start Address High */
1074  /*************************/
1075  outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1076  outw((devpriv->ul_DmaBufferHw[0] / 65536),
1077  devpriv->i_IobaseAddon + 2);
1078 
1079 /*
1080  * 4
1081  * amount of bytes to be transferred set transfer count used ADDON
1082  * MWTC register commented testing
1083  * outl(devpriv->ui_DmaBufferUsesize[0],
1084  * devpriv->i_IobaseAddon+AMCC_OP_REG_AMWTC);
1085  */
1086 
1087  /**************************/
1088  /* Nbr of acquisition LOW */
1089  /**************************/
1090  outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1091  outw((devpriv->ui_DmaBufferUsesize[0] & 0xFFFF),
1092  devpriv->i_IobaseAddon + 2);
1093 
1094  /***************************/
1095  /* Nbr of acquisition HIGH */
1096  /***************************/
1097  outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1098  outw((devpriv->ui_DmaBufferUsesize[0] / 65536),
1099  devpriv->i_IobaseAddon + 2);
1100 
1101 /*
1102  * 5
1103  * To configure A2P FIFO testing outl(
1104  * FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR);
1105  */
1106 
1107  /******************/
1108  /* A2P FIFO RESET */
1109  /******************/
1110 /*
1111  * TO VERIFY BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1112  * driver
1113  */
1114  outl(0x04000000UL, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1115  /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1116 
1117 /*
1118  * 6
1119  * ENABLE A2P FIFO WRITE AND ENABLE AMWEN AMWEN_ENABLE |
1120  * A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1121  */
1122 
1123  /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1124  /* outw(3,devpriv->i_IobaseAddon + 4); */
1125  /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1126 
1127 /*
1128  * 7
1129  * initialise end of dma interrupt AINT_WRITE_COMPL =
1130  * ENABLE_WRITE_TC_INT(ADDI)
1131  */
1132  /***************************************************/
1133  /* A2P FIFO CONFIGURATE, END OF DMA intERRUPT INIT */
1134  /***************************************************/
1137  devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1138 
1139  /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1140  /******************************************/
1141  /* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */
1142  /******************************************/
1143  outw(3, devpriv->i_IobaseAddon + 4);
1144  /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1145 
1146  /******************/
1147  /* A2P FIFO RESET */
1148  /******************/
1149  /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1150  outl(0x04000000UL,
1151  devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_MCSR);
1152  /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1153  }
1154 
1155  if ((devpriv->us_UseDma == APCI3120_DISABLE)
1156  && !devpriv->b_AiContinuous) {
1157  /* set gate 2 to start conversion */
1158  devpriv->us_OutputRegister =
1159  devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER2;
1160  outw(devpriv->us_OutputRegister,
1161  dev->iobase + APCI3120_WR_ADDRESS);
1162  }
1163 
1164  switch (mode) {
1165  case 1:
1166  /* set gate 0 to start conversion */
1167  devpriv->us_OutputRegister =
1168  devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1169  outw(devpriv->us_OutputRegister,
1170  dev->iobase + APCI3120_WR_ADDRESS);
1171  break;
1172  case 2:
1173  /* set gate 0 and gate 1 */
1174  devpriv->us_OutputRegister =
1175  devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER1;
1176  devpriv->us_OutputRegister =
1177  devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1178  outw(devpriv->us_OutputRegister,
1179  dev->iobase + APCI3120_WR_ADDRESS);
1180  break;
1181 
1182  }
1183 
1184  return 0;
1185 
1186 }
1187 
1188 /*
1189 +----------------------------------------------------------------------------+
1190 | intERNAL FUNCTIONS |
1191 +----------------------------------------------------------------------------+
1192 */
1193 
1194 /*
1195 +----------------------------------------------------------------------------+
1196 | Function name : int i_APCI3120_Reset(struct comedi_device *dev) |
1197 | |
1198 | |
1199 +----------------------------------------------------------------------------+
1200 | Task : Hardware reset function |
1201 | |
1202 +----------------------------------------------------------------------------+
1203 | Input Parameters : struct comedi_device *dev |
1204 | |
1205 | |
1206 +----------------------------------------------------------------------------+
1207 | Return Value : |
1208 | |
1209 +----------------------------------------------------------------------------+
1210 */
1211 
1213 {
1214  unsigned int i;
1215  unsigned short us_TmpValue;
1216 
1217  devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1218  devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1219  devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1220  devpriv->ui_EocEosConversionTime = 0; /* set eoc eos conv time to 0 */
1221  devpriv->b_OutputMemoryStatus = 0;
1222 
1223  /* variables used in timer subdevice */
1224  devpriv->b_Timer2Mode = 0;
1225  devpriv->b_Timer2Interrupt = 0;
1226  devpriv->b_ExttrigEnable = 0; /* Disable ext trigger */
1227 
1228  /* Disable all interrupts, watchdog for the anolog output */
1229  devpriv->b_ModeSelectRegister = 0;
1230  outb(devpriv->b_ModeSelectRegister,
1232 
1233  /* Disables all counters, ext trigger and clears PA, PR */
1234  devpriv->us_OutputRegister = 0;
1235  outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1236 
1237 /*
1238  * Code to set the all anolog o/p channel to 0v 8191 is decimal
1239  * value for zero(0 v)volt in bipolar mode(default)
1240  */
1241  outw(8191 | APCI3120_ANALOG_OP_CHANNEL_1, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 1 */
1242  outw(8191 | APCI3120_ANALOG_OP_CHANNEL_2, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 2 */
1243  outw(8191 | APCI3120_ANALOG_OP_CHANNEL_3, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 3 */
1244  outw(8191 | APCI3120_ANALOG_OP_CHANNEL_4, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 4 */
1245 
1246  outw(8191 | APCI3120_ANALOG_OP_CHANNEL_5, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 5 */
1247  outw(8191 | APCI3120_ANALOG_OP_CHANNEL_6, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 6 */
1248  outw(8191 | APCI3120_ANALOG_OP_CHANNEL_7, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 7 */
1249  outw(8191 | APCI3120_ANALOG_OP_CHANNEL_8, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 8 */
1250 
1251  /* Reset digital output to L0W */
1252 
1253 /* ES05 outb(0x0,dev->iobase+APCI3120_DIGITAL_OUTPUT); */
1254  udelay(10);
1255 
1256  inw(dev->iobase + 0); /* make a dummy read */
1257  inb(dev->iobase + APCI3120_RESET_FIFO); /* flush FIFO */
1258  inw(dev->iobase + APCI3120_RD_STATUS); /* flush A/D status register */
1259 
1260  /* code to reset the RAM sequence */
1261  for (i = 0; i < 16; i++) {
1262  us_TmpValue = i << 8; /* select the location */
1263  outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
1264  }
1265  return 0;
1266 }
1267 
1268 /*
1269 +----------------------------------------------------------------------------+
1270 | Function name : int i_APCI3120_SetupChannelList(struct comedi_device * dev, |
1271 | struct comedi_subdevice * s, int n_chan,unsigned int *chanlist|
1272 | ,char check) |
1273 | |
1274 +----------------------------------------------------------------------------+
1275 | Task :This function will first check channel list is ok or not|
1276 |and then initialize the sequence RAM with the polarity, Gain,Channel number |
1277 |If the last argument of function "check"is 1 then it only checks the channel|
1278 |list is ok or not. |
1279 | |
1280 +----------------------------------------------------------------------------+
1281 | Input Parameters : struct comedi_device * dev |
1282 | struct comedi_subdevice * s |
1283 | int n_chan |
1284  unsigned int *chanlist
1285  char check
1286 +----------------------------------------------------------------------------+
1287 | Return Value : |
1288 | |
1289 +----------------------------------------------------------------------------+
1290 */
1291 
1293  int n_chan, unsigned int *chanlist, char check)
1294 {
1295  unsigned int i; /* , differencial=0, bipolar=0; */
1296  unsigned int gain;
1297  unsigned short us_TmpValue;
1298 
1299  /* correct channel and range number check itself comedi/range.c */
1300  if (n_chan < 1) {
1301  if (!check)
1302  comedi_error(dev, "range/channel list is empty!");
1303  return 0;
1304  }
1305  /* All is ok, so we can setup channel/range list */
1306  if (check)
1307  return 1;
1308 
1309  /* Code to set the PA and PR...Here it set PA to 0.. */
1310  devpriv->us_OutputRegister =
1311  devpriv->us_OutputRegister & APCI3120_CLEAR_PA_PR;
1312  devpriv->us_OutputRegister = ((n_chan - 1) & 0xf) << 8;
1313  outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1314 
1315  for (i = 0; i < n_chan; i++) {
1316  /* store range list to card */
1317  us_TmpValue = CR_CHAN(chanlist[i]); /* get channel number; */
1318 
1319  if (CR_RANGE(chanlist[i]) < APCI3120_BIPOLAR_RANGES)
1320  us_TmpValue &= ((~APCI3120_UNIPOLAR) & 0xff); /* set bipolar */
1321  else
1322  us_TmpValue |= APCI3120_UNIPOLAR; /* enable unipolar...... */
1323 
1324  gain = CR_RANGE(chanlist[i]); /* get gain number */
1325  us_TmpValue |= ((gain & 0x03) << 4); /* <<4 for G0 and G1 bit in RAM */
1326  us_TmpValue |= i << 8; /* To select the RAM LOCATION.... */
1327  outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
1328 
1329  printk("\n Gain = %i",
1330  (((unsigned char)CR_RANGE(chanlist[i]) & 0x03) << 2));
1331  printk("\n Channel = %i", CR_CHAN(chanlist[i]));
1332  printk("\n Polarity = %i", us_TmpValue & APCI3120_UNIPOLAR);
1333  }
1334  return 1; /* we can serve this with scan logic */
1335 }
1336 
1337 /*
1338 +----------------------------------------------------------------------------+
1339 | Function name : int i_APCI3120_ExttrigEnable(struct comedi_device * dev) |
1340 | |
1341 | |
1342 +----------------------------------------------------------------------------+
1343 | Task : Enable the external trigger |
1344 | |
1345 +----------------------------------------------------------------------------+
1346 | Input Parameters : struct comedi_device * dev |
1347 | |
1348 | |
1349 +----------------------------------------------------------------------------+
1350 | Return Value : 0 |
1351 | |
1352 +----------------------------------------------------------------------------+
1353 */
1354 
1356 {
1357 
1358  devpriv->us_OutputRegister |= APCI3120_ENABLE_EXT_TRIGGER;
1359  outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1360  return 0;
1361 }
1362 
1363 /*
1364 +----------------------------------------------------------------------------+
1365 | Function name : int i_APCI3120_ExttrigDisable(struct comedi_device * dev) |
1366 | |
1367 +----------------------------------------------------------------------------+
1368 | Task : Disables the external trigger |
1369 | |
1370 +----------------------------------------------------------------------------+
1371 | Input Parameters : struct comedi_device * dev |
1372 | |
1373 | |
1374 +----------------------------------------------------------------------------+
1375 | Return Value : 0 |
1376 | |
1377 +----------------------------------------------------------------------------+
1378 */
1379 
1381 {
1382  devpriv->us_OutputRegister &= ~APCI3120_ENABLE_EXT_TRIGGER;
1383  outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1384  return 0;
1385 }
1386 
1387 /*
1388 +----------------------------------------------------------------------------+
1389 | intERRUPT FUNCTIONS |
1390 +----------------------------------------------------------------------------+
1391 */
1392 
1393 /*
1394 +----------------------------------------------------------------------------+
1395 | Function name : void v_APCI3120_Interrupt(int irq, void *d) |
1396 | |
1397 | |
1398 +----------------------------------------------------------------------------+
1399 | Task :Interrupt handler for APCI3120 |
1400 | When interrupt occurs this gets called. |
1401 | First it finds which interrupt has been generated and |
1402 | handles corresponding interrupt |
1403 | |
1404 +----------------------------------------------------------------------------+
1405 | Input Parameters : int irq |
1406 | void *d |
1407 | |
1408 +----------------------------------------------------------------------------+
1409 | Return Value : void |
1410 | |
1411 +----------------------------------------------------------------------------+
1412 */
1413 
1414 void v_APCI3120_Interrupt(int irq, void *d)
1415 {
1416  struct comedi_device *dev = d;
1417  unsigned short int_daq;
1418 
1419  unsigned int int_amcc, ui_Check, i;
1420  unsigned short us_TmpValue;
1421  unsigned char b_DummyRead;
1422 
1423  struct comedi_subdevice *s = &dev->subdevices[0];
1424  ui_Check = 1;
1425 
1426  int_daq = inw(dev->iobase + APCI3120_RD_STATUS) & 0xf000; /* get IRQ reasons */
1427  int_amcc = inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); /* get AMCC int register */
1428 
1429  if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) {
1430  comedi_error(dev, "IRQ from unknown source");
1431  return;
1432  }
1433 
1434  outl(int_amcc | 0x00ff0000, devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); /* shutdown IRQ reasons in AMCC */
1435 
1436  int_daq = (int_daq >> 12) & 0xF;
1437 
1438  if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
1439  /* Disable ext trigger */
1441  devpriv->b_ExttrigEnable = APCI3120_DISABLE;
1442  }
1443  /* clear the timer 2 interrupt */
1444  inb(devpriv->i_IobaseAmcc + APCI3120_TIMER_STATUS_REGISTER);
1445 
1446  if (int_amcc & MASTER_ABORT_INT)
1447  comedi_error(dev, "AMCC IRQ - MASTER DMA ABORT!");
1448  if (int_amcc & TARGET_ABORT_INT)
1449  comedi_error(dev, "AMCC IRQ - TARGET DMA ABORT!");
1450 
1451  /* Ckeck if EOC interrupt */
1452  if (((int_daq & 0x8) == 0)
1453  && (devpriv->b_InterruptMode == APCI3120_EOC_MODE)) {
1454  if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
1455 
1456  /* Read the AI Value */
1457 
1458  devpriv->ui_AiReadData[0] =
1459  (unsigned int) inw(devpriv->iobase + 0);
1460  devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1461  send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
1462  } else {
1463  /* Disable EOC Interrupt */
1464  devpriv->b_ModeSelectRegister =
1465  devpriv->
1466  b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT;
1467  outb(devpriv->b_ModeSelectRegister,
1469 
1470  }
1471  }
1472 
1473  /* Check If EOS interrupt */
1474  if ((int_daq & 0x2) && (devpriv->b_InterruptMode == APCI3120_EOS_MODE)) {
1475 
1476  if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) { /* enable this in without DMA ??? */
1477 
1478  if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
1479  ui_Check = 0;
1481  devpriv->ui_AiActualScan++;
1482  devpriv->b_ModeSelectRegister =
1483  devpriv->
1484  b_ModeSelectRegister |
1486  outb(devpriv->b_ModeSelectRegister,
1487  dev->iobase +
1489  } else {
1490  ui_Check = 0;
1491  for (i = 0; i < devpriv->ui_AiNbrofChannels;
1492  i++) {
1493  us_TmpValue = inw(devpriv->iobase + 0);
1494  devpriv->ui_AiReadData[i] =
1495  (unsigned int) us_TmpValue;
1496  }
1497  devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1498  devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1499 
1500  send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
1501 
1502  }
1503 
1504  } else {
1505  devpriv->b_ModeSelectRegister =
1506  devpriv->
1507  b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1508  outb(devpriv->b_ModeSelectRegister,
1510  devpriv->b_EocEosInterrupt = APCI3120_DISABLE; /* Default settings */
1511  devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1512  }
1513 
1514  }
1515  /* Timer2 interrupt */
1516  if (int_daq & 0x1) {
1517 
1518  switch (devpriv->b_Timer2Mode) {
1519  case APCI3120_COUNTER:
1520 
1521  devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1522  devpriv->b_ModeSelectRegister =
1523  devpriv->
1524  b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1525  outb(devpriv->b_ModeSelectRegister,
1527 
1528  /* stop timer 2 */
1529  devpriv->us_OutputRegister =
1530  devpriv->
1531  us_OutputRegister & APCI3120_DISABLE_ALL_TIMER;
1532  outw(devpriv->us_OutputRegister,
1533  dev->iobase + APCI3120_WR_ADDRESS);
1534 
1535  /* stop timer 0 and timer 1 */
1537  devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1538 
1539  /* UPDATE-0.7.57->0.7.68comedi_done(dev,s); */
1540  s->async->events |= COMEDI_CB_EOA;
1541  comedi_event(dev, s);
1542 
1543  break;
1544 
1545  case APCI3120_TIMER:
1546 
1547  /* Send a signal to from kernel to user space */
1548  send_sig(SIGIO, devpriv->tsk_Current, 0);
1549  break;
1550 
1551  case APCI3120_WATCHDOG:
1552 
1553  /* Send a signal to from kernel to user space */
1554  send_sig(SIGIO, devpriv->tsk_Current, 0);
1555  break;
1556 
1557  default:
1558 
1559  /* disable Timer Interrupt */
1560 
1561  devpriv->b_ModeSelectRegister =
1562  devpriv->
1563  b_ModeSelectRegister &
1565 
1566  outb(devpriv->b_ModeSelectRegister,
1568 
1569  }
1570 
1571  b_DummyRead = inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1572 
1573  }
1574 
1575  if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) {
1576  if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
1577 
1578  /****************************/
1579  /* Clear Timer Write TC int */
1580  /****************************/
1581 
1583  devpriv->i_IobaseAmcc +
1585 
1586  /************************************/
1587  /* Clears the timer status register */
1588  /************************************/
1590  v_APCI3120_InterruptDma(irq, d); /* do some data transfer */
1591  } else {
1592  /* Stops the Timer */
1593  outw(devpriv->
1594  us_OutputRegister & APCI3120_DISABLE_TIMER0 &
1596  dev->iobase + APCI3120_WR_ADDRESS);
1597  }
1598 
1599  }
1600 
1601  return;
1602 }
1603 
1604 /*
1605 +----------------------------------------------------------------------------+
1606 | Function name :int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) |
1607 | |
1608 | |
1609 +----------------------------------------------------------------------------+
1610 | Task : This function handles EOS interrupt. |
1611 | This function copies the acquired data(from FIFO) |
1612 | to Comedi buffer. |
1613 | |
1614 +----------------------------------------------------------------------------+
1615 | Input Parameters : struct comedi_device *dev |
1616 | |
1617 | |
1618 +----------------------------------------------------------------------------+
1619 | Return Value : 0 |
1620 | |
1621 +----------------------------------------------------------------------------+
1622 */
1623 
1624 
1626 {
1627  int n_chan, i;
1628  struct comedi_subdevice *s = &dev->subdevices[0];
1629  int err = 1;
1630 
1631  n_chan = devpriv->ui_AiNbrofChannels;
1632 
1633  s->async->events = 0;
1634 
1635  for (i = 0; i < n_chan; i++)
1636  err &= comedi_buf_put(s->async, inw(dev->iobase + 0));
1637 
1638  s->async->events |= COMEDI_CB_EOS;
1639 
1640  if (err == 0)
1641  s->async->events |= COMEDI_CB_OVERFLOW;
1642 
1643  comedi_event(dev, s);
1644 
1645  return 0;
1646 }
1647 
1648 /*
1649 +----------------------------------------------------------------------------+
1650 | Function name : void v_APCI3120_InterruptDma(int irq, void *d) |
1651 | |
1652 +----------------------------------------------------------------------------+
1653 | Task : This is a handler for the DMA interrupt |
1654 | This function copies the data to Comedi Buffer. |
1655 | For continuous DMA it reinitializes the DMA operation. |
1656 | For single mode DMA it stop the acquisition. |
1657 | |
1658 +----------------------------------------------------------------------------+
1659 | Input Parameters : int irq, void *d |
1660 | |
1661 +----------------------------------------------------------------------------+
1662 | Return Value : void |
1663 | |
1664 +----------------------------------------------------------------------------+
1665 */
1666 
1667 void v_APCI3120_InterruptDma(int irq, void *d)
1668 {
1669  struct comedi_device *dev = d;
1670  struct comedi_subdevice *s = &dev->subdevices[0];
1671  unsigned int next_dma_buf, samplesinbuf;
1672  unsigned long low_word, high_word, var;
1673 
1674  unsigned int ui_Tmp;
1675  samplesinbuf =
1676  devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer] -
1677  inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_MWTC);
1678 
1679  if (samplesinbuf <
1680  devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer]) {
1681  comedi_error(dev, "Interrupted DMA transfer!");
1682  }
1683  if (samplesinbuf & 1) {
1684  comedi_error(dev, "Odd count of bytes in DMA ring!");
1686  devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1687 
1688  return;
1689  }
1690  samplesinbuf = samplesinbuf >> 1; /* number of received samples */
1691  if (devpriv->b_DmaDoubleBuffer) {
1692  /* switch DMA buffers if is used double buffering */
1693  next_dma_buf = 1 - devpriv->ui_DmaActualBuffer;
1694 
1696  outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1697 
1698  /* changed since 16 bit interface for add on */
1699  outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1701  devpriv->i_IobaseAddon + 2);
1702  outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1703  outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /* 0x1000 is out putted in windows driver */
1704 
1705  var = devpriv->ul_DmaBufferHw[next_dma_buf];
1706  low_word = var & 0xffff;
1707  var = devpriv->ul_DmaBufferHw[next_dma_buf];
1708  high_word = var / 65536;
1709 
1710  /* DMA Start Address Low */
1711  outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1712  outw(low_word, devpriv->i_IobaseAddon + 2);
1713 
1714  /* DMA Start Address High */
1715  outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1716  outw(high_word, devpriv->i_IobaseAddon + 2);
1717 
1718  var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1719  low_word = var & 0xffff;
1720  var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1721  high_word = var / 65536;
1722 
1723  /* Nbr of acquisition LOW */
1724  outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1725  outw(low_word, devpriv->i_IobaseAddon + 2);
1726 
1727  /* Nbr of acquisition HIGH */
1728  outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1729  outw(high_word, devpriv->i_IobaseAddon + 2);
1730 
1731 /*
1732  * To configure A2P FIFO
1733  * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1734  * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1735  */
1736  outw(3, devpriv->i_IobaseAddon + 4);
1737  /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
1740  devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1741 
1742  }
1743  if (samplesinbuf) {
1745  devpriv->ul_DmaBufferVirtual[devpriv->
1746  ui_DmaActualBuffer], samplesinbuf);
1747 
1748  if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS)) {
1749  s->async->events |= COMEDI_CB_EOS;
1750  comedi_event(dev, s);
1751  }
1752  }
1753  if (!devpriv->b_AiContinuous)
1754  if (devpriv->ui_AiActualScan >= devpriv->ui_AiNbrofScans) {
1755  /* all data sampled */
1757  devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1758  s->async->events |= COMEDI_CB_EOA;
1759  comedi_event(dev, s);
1760  return;
1761  }
1762 
1763  if (devpriv->b_DmaDoubleBuffer) { /* switch dma buffers */
1764  devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer;
1765  } else {
1766 /*
1767  * restart DMA if is not used double buffering
1768  * ADDED REINITIALISE THE DMA
1769  */
1771  outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1772 
1773  /* changed since 16 bit interface for add on */
1774  outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1776  devpriv->i_IobaseAddon + 2);
1777  outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1778  outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /* */
1779 /*
1780  * A2P FIFO MANAGEMENT
1781  * A2P fifo reset & transfer control enable
1782  */
1784  devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1785 
1786  var = devpriv->ul_DmaBufferHw[0];
1787  low_word = var & 0xffff;
1788  var = devpriv->ul_DmaBufferHw[0];
1789  high_word = var / 65536;
1790  outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1791  outw(low_word, devpriv->i_IobaseAddon + 2);
1792  outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1793  outw(high_word, devpriv->i_IobaseAddon + 2);
1794 
1795  var = devpriv->ui_DmaBufferUsesize[0];
1796  low_word = var & 0xffff; /* changed */
1797  var = devpriv->ui_DmaBufferUsesize[0];
1798  high_word = var / 65536;
1799  outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1800  outw(low_word, devpriv->i_IobaseAddon + 2);
1801  outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1802  outw(high_word, devpriv->i_IobaseAddon + 2);
1803 
1804 /*
1805  * To configure A2P FIFO
1806  * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1807  * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1808  */
1809  outw(3, devpriv->i_IobaseAddon + 4);
1810  /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
1813  devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1814  }
1815 }
1816 
1817 /*
1818 +----------------------------------------------------------------------------+
1819 | Function name :void v_APCI3120_InterruptDmaMoveBlock16bit(comedi_device|
1820 |*dev,struct comedi_subdevice *s,short *dma,short *data,int n) |
1821 | |
1822 +----------------------------------------------------------------------------+
1823 | Task : This function copies the data from DMA buffer to the |
1824 | Comedi buffer |
1825 | |
1826 +----------------------------------------------------------------------------+
1827 | Input Parameters : struct comedi_device *dev |
1828 | struct comedi_subdevice *s |
1829 | short *dma |
1830 | short *data,int n |
1831 +----------------------------------------------------------------------------+
1832 | Return Value : void |
1833 | |
1834 +----------------------------------------------------------------------------+
1835 */
1836 
1838  struct comedi_subdevice *s, short *dma_buffer, unsigned int num_samples)
1839 {
1840  devpriv->ui_AiActualScan +=
1841  (s->async->cur_chan + num_samples) / devpriv->ui_AiScanLength;
1842  s->async->cur_chan += num_samples;
1843  s->async->cur_chan %= devpriv->ui_AiScanLength;
1844 
1845  cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(short));
1846 }
1847 
1848 /*
1849 +----------------------------------------------------------------------------+
1850 | TIMER SUBDEVICE |
1851 +----------------------------------------------------------------------------+
1852 */
1853 
1854 /*
1855 +----------------------------------------------------------------------------+
1856 | Function name :int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, |
1857 | struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
1858 | |
1859 +----------------------------------------------------------------------------+
1860 | Task :Configure Timer 2 |
1861 | |
1862 +----------------------------------------------------------------------------+
1863 | Input Parameters : struct comedi_device *dev |
1864 | struct comedi_subdevice *s |
1865 | struct comedi_insn *insn |
1866 | unsigned int *data |
1867 | |
1868 | data[0]= TIMER configure as timer |
1869 | = WATCHDOG configure as watchdog |
1870 | data[1] = Timer constant |
1871 | data[2] = Timer2 interrupt (1)enable or(0) disable |
1872 | |
1873 +----------------------------------------------------------------------------+
1874 | Return Value : |
1875 | |
1876 +----------------------------------------------------------------------------+
1877 */
1878 
1880  struct comedi_insn *insn, unsigned int *data)
1881 {
1882 
1883  unsigned int ui_Timervalue2;
1884  unsigned short us_TmpValue;
1885  unsigned char b_Tmp;
1886 
1887  if (!data[1])
1888  comedi_error(dev, "config:No timer constant !");
1889 
1890  devpriv->b_Timer2Interrupt = (unsigned char) data[2]; /* save info whether to enable or disable interrupt */
1891 
1892  ui_Timervalue2 = data[1] / 1000; /* convert nano seconds to u seconds */
1893 
1894  /* this_board->timer_config(dev, ui_Timervalue2,(unsigned char)data[0]); */
1895  us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
1896 
1897 /*
1898  * EL250804: Testing if board APCI3120 have the new Quartz or if it
1899  * is an APCI3001 and calculate the time value to set in the timer
1900  */
1901  if ((us_TmpValue & 0x00B0) == 0x00B0
1902  || !strcmp(this_board->pc_DriverName, "apci3001")) {
1903  /* Calculate the time value to set in the timer */
1904  ui_Timervalue2 = ui_Timervalue2 / 50;
1905  } else {
1906  /* Calculate the time value to set in the timer */
1907  ui_Timervalue2 = ui_Timervalue2 / 70;
1908  }
1909 
1910  /* Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0) */
1911  devpriv->us_OutputRegister =
1912  devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER2;
1913  outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS);
1914 
1915  /* Disable TIMER Interrupt */
1916  devpriv->b_ModeSelectRegister =
1917  devpriv->
1918  b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT & 0xEF;
1919 
1920  /* Disable Eoc and Eos Interrupts */
1921  devpriv->b_ModeSelectRegister =
1922  devpriv->
1923  b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT &
1925  outb(devpriv->b_ModeSelectRegister,
1927  if (data[0] == APCI3120_TIMER) { /* initialize timer */
1928  /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister |
1929  * APCI3120_ENABLE_TIMER_INT; */
1930 
1931  /* outb(devpriv->b_ModeSelectRegister,devpriv->iobase+APCI3120_WRITE_MODE_SELECT); */
1932 
1933  /* Set the Timer 2 in mode 2(Timer) */
1934  devpriv->b_TimerSelectMode =
1935  (devpriv->
1936  b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_2;
1937  outb(devpriv->b_TimerSelectMode,
1938  devpriv->iobase + APCI3120_TIMER_CRT1);
1939 
1940 /*
1941  * Configure the timer 2 for writing the LOW unsigned short of timer
1942  * is Delay value You must make a b_tmp variable with
1943  * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
1944  * you can set the digital output and configure the timer 2,and if
1945  * you don't make this, digital output are erase (Set to 0)
1946  */
1947 
1948  /* Writing LOW unsigned short */
1949  b_Tmp = ((devpriv->
1950  b_DigitalOutputRegister) & 0xF0) |
1952  outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1953  outw(LOWORD(ui_Timervalue2),
1954  devpriv->iobase + APCI3120_TIMER_VALUE);
1955 
1956  /* Writing HIGH unsigned short */
1957  b_Tmp = ((devpriv->
1958  b_DigitalOutputRegister) & 0xF0) |
1960  outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1961  outw(HIWORD(ui_Timervalue2),
1962  devpriv->iobase + APCI3120_TIMER_VALUE);
1963  /* timer2 in Timer mode enabled */
1964  devpriv->b_Timer2Mode = APCI3120_TIMER;
1965 
1966  } else { /* Initialize Watch dog */
1967 
1968  /* Set the Timer 2 in mode 5(Watchdog) */
1969 
1970  devpriv->b_TimerSelectMode =
1971  (devpriv->
1972  b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_5;
1973  outb(devpriv->b_TimerSelectMode,
1974  devpriv->iobase + APCI3120_TIMER_CRT1);
1975 
1976 /*
1977  * Configure the timer 2 for writing the LOW unsigned short of timer
1978  * is Delay value You must make a b_tmp variable with
1979  * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
1980  * you can set the digital output and configure the timer 2,and if
1981  * you don't make this, digital output are erase (Set to 0)
1982  */
1983 
1984  /* Writing LOW unsigned short */
1985  b_Tmp = ((devpriv->
1986  b_DigitalOutputRegister) & 0xF0) |
1988  outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1989  outw(LOWORD(ui_Timervalue2),
1990  devpriv->iobase + APCI3120_TIMER_VALUE);
1991 
1992  /* Writing HIGH unsigned short */
1993  b_Tmp = ((devpriv->
1994  b_DigitalOutputRegister) & 0xF0) |
1996  outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1997 
1998  outw(HIWORD(ui_Timervalue2),
1999  devpriv->iobase + APCI3120_TIMER_VALUE);
2000  /* watchdog enabled */
2001  devpriv->b_Timer2Mode = APCI3120_WATCHDOG;
2002 
2003  }
2004 
2005  return insn->n;
2006 
2007 }
2008 
2009 /*
2010 +----------------------------------------------------------------------------+
2011 | Function name :int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, |
2012 | struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2013 | |
2014 +----------------------------------------------------------------------------+
2015 | Task : To start and stop the timer |
2016 +----------------------------------------------------------------------------+
2017 | Input Parameters : struct comedi_device *dev |
2018 | struct comedi_subdevice *s |
2019 | struct comedi_insn *insn |
2020 | unsigned int *data |
2021 | |
2022 | data[0] = 1 (start) |
2023 | data[0] = 0 (stop ) |
2024 | data[0] = 2 (write new value) |
2025 | data[1]= new value |
2026 | |
2027 | devpriv->b_Timer2Mode = 0 DISABLE |
2028 | 1 Timer |
2029 | 2 Watch dog |
2030 | |
2031 +----------------------------------------------------------------------------+
2032 | Return Value : |
2033 | |
2034 +----------------------------------------------------------------------------+
2035 */
2036 
2038  struct comedi_insn *insn, unsigned int *data)
2039 {
2040 
2041  unsigned int ui_Timervalue2 = 0;
2042  unsigned short us_TmpValue;
2043  unsigned char b_Tmp;
2044 
2045  if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
2046  && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
2047  comedi_error(dev, "\nwrite:timer2 not configured ");
2048  return -EINVAL;
2049  }
2050 
2051  if (data[0] == 2) { /* write new value */
2052  if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
2053  comedi_error(dev,
2054  "write :timer2 not configured in TIMER MODE");
2055  return -EINVAL;
2056  }
2057 
2058  if (data[1])
2059  ui_Timervalue2 = data[1];
2060  else
2061  ui_Timervalue2 = 0;
2062  }
2063 
2064  /* this_board->timer_write(dev,data[0],ui_Timervalue2); */
2065 
2066  switch (data[0]) {
2067  case APCI3120_START:
2068 
2069  /* Reset FC_TIMER BIT */
2071  if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* start timer */
2072  /* Enable Timer */
2073  devpriv->b_ModeSelectRegister =
2074  devpriv->b_ModeSelectRegister & 0x0B;
2075  } else { /* start watch dog */
2076  /* Enable WatchDog */
2077  devpriv->b_ModeSelectRegister =
2078  (devpriv->
2079  b_ModeSelectRegister & 0x0B) |
2081  }
2082 
2083  /* enable disable interrupt */
2084  if ((devpriv->b_Timer2Interrupt) == APCI3120_ENABLE) {
2085 
2086  devpriv->b_ModeSelectRegister =
2087  devpriv->
2088  b_ModeSelectRegister |
2090  /* save the task structure to pass info to user */
2091  devpriv->tsk_Current = current;
2092  } else {
2093 
2094  devpriv->b_ModeSelectRegister =
2095  devpriv->
2096  b_ModeSelectRegister &
2098  }
2099  outb(devpriv->b_ModeSelectRegister,
2101 
2102  if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* start timer */
2103  /* For Timer mode is Gate2 must be activated **timer started */
2104  devpriv->us_OutputRegister =
2105  devpriv->
2106  us_OutputRegister | APCI3120_ENABLE_TIMER2;
2107  outw(devpriv->us_OutputRegister,
2108  devpriv->iobase + APCI3120_WR_ADDRESS);
2109  }
2110 
2111  break;
2112 
2113  case APCI3120_STOP:
2114  if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
2115  /* Disable timer */
2116  devpriv->b_ModeSelectRegister =
2117  devpriv->
2118  b_ModeSelectRegister &
2120  } else {
2121  /* Disable WatchDog */
2122  devpriv->b_ModeSelectRegister =
2123  devpriv->
2124  b_ModeSelectRegister &
2126  }
2127  /* Disable timer interrupt */
2128  devpriv->b_ModeSelectRegister =
2129  devpriv->
2130  b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT;
2131 
2132  /* Write above states to register */
2133  outb(devpriv->b_ModeSelectRegister,
2135 
2136  /* Reset Gate 2 */
2137  devpriv->us_OutputRegister =
2138  devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER_INT;
2139  outw(devpriv->us_OutputRegister,
2140  devpriv->iobase + APCI3120_WR_ADDRESS);
2141 
2142  /* Reset FC_TIMER BIT */
2144 
2145  /* Disable timer */
2146  /* devpriv->b_Timer2Mode=APCI3120_DISABLE; */
2147 
2148  break;
2149 
2150  case 2: /* write new value to Timer */
2151  if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
2152  comedi_error(dev,
2153  "write :timer2 not configured in TIMER MODE");
2154  return -EINVAL;
2155  }
2156  /* ui_Timervalue2=data[1]; // passed as argument */
2157  us_TmpValue =
2158  (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
2159 
2160 /*
2161  * EL250804: Testing if board APCI3120 have the new Quartz or if it
2162  * is an APCI3001 and calculate the time value to set in the timer
2163  */
2164  if ((us_TmpValue & 0x00B0) == 0x00B0
2165  || !strcmp(this_board->pc_DriverName, "apci3001")) {
2166  /* Calculate the time value to set in the timer */
2167  ui_Timervalue2 = ui_Timervalue2 / 50;
2168  } else {
2169  /* Calculate the time value to set in the timer */
2170  ui_Timervalue2 = ui_Timervalue2 / 70;
2171  }
2172  /* Writing LOW unsigned short */
2173  b_Tmp = ((devpriv->
2174  b_DigitalOutputRegister) & 0xF0) |
2176  outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2177 
2178  outw(LOWORD(ui_Timervalue2),
2179  devpriv->iobase + APCI3120_TIMER_VALUE);
2180 
2181  /* Writing HIGH unsigned short */
2182  b_Tmp = ((devpriv->
2183  b_DigitalOutputRegister) & 0xF0) |
2185  outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2186 
2187  outw(HIWORD(ui_Timervalue2),
2188  devpriv->iobase + APCI3120_TIMER_VALUE);
2189 
2190  break;
2191  default:
2192  return -EINVAL; /* Not a valid input */
2193  }
2194 
2195  return insn->n;
2196 }
2197 
2198 /*
2199 +----------------------------------------------------------------------------+
2200 | Function name : int i_APCI3120_InsnReadTimer(struct comedi_device *dev, |
2201 | struct comedi_subdevice *s,struct comedi_insn *insn, unsigned int *data) |
2202 | |
2203 | |
2204 +----------------------------------------------------------------------------+
2205 | Task : read the Timer value |
2206 +----------------------------------------------------------------------------+
2207 | Input Parameters : struct comedi_device *dev |
2208 | struct comedi_subdevice *s |
2209 | struct comedi_insn *insn |
2210 | unsigned int *data |
2211 | |
2212 +----------------------------------------------------------------------------+
2213 | Return Value : |
2214 | for Timer: data[0]= Timer constant |
2215 | |
2216 | for watchdog: data[0]=0 (still running) |
2217 | data[0]=1 (run down) |
2218 | |
2219 +----------------------------------------------------------------------------+
2220 */
2222  struct comedi_insn *insn, unsigned int *data)
2223 {
2224  unsigned char b_Tmp;
2225  unsigned short us_TmpValue, us_TmpValue_2, us_StatusValue;
2226 
2227  if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
2228  && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
2229  comedi_error(dev, "\nread:timer2 not configured ");
2230  }
2231 
2232  /* this_board->timer_read(dev,data); */
2233  if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
2234 
2235  /* Read the LOW unsigned short of Timer 2 register */
2236  b_Tmp = ((devpriv->
2237  b_DigitalOutputRegister) & 0xF0) |
2239  outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2240 
2241  us_TmpValue = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2242 
2243  /* Read the HIGH unsigned short of Timer 2 register */
2244  b_Tmp = ((devpriv->
2245  b_DigitalOutputRegister) & 0xF0) |
2247  outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2248 
2249  us_TmpValue_2 = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2250 
2251  /* combining both words */
2252  data[0] = (unsigned int) ((us_TmpValue) | ((us_TmpValue_2) << 16));
2253 
2254  } else { /* Read watch dog status */
2255 
2256  us_StatusValue = inw(devpriv->iobase + APCI3120_RD_STATUS);
2257  us_StatusValue =
2258  ((us_StatusValue & APCI3120_FC_TIMER) >> 12) & 1;
2259  if (us_StatusValue == 1) {
2260  /* RESET FC_TIMER BIT */
2262  }
2263  data[0] = us_StatusValue; /* when data[0] = 1 then the watch dog has rundown */
2264  }
2265  return insn->n;
2266 }
2267 
2268 /*
2269 +----------------------------------------------------------------------------+
2270 | DIGITAL INPUT SUBDEVICE |
2271 +----------------------------------------------------------------------------+
2272 */
2273 
2274 /*
2275 +----------------------------------------------------------------------------+
2276 | Function name :int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev, |
2277 | struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2278 | |
2279 | |
2280 +----------------------------------------------------------------------------+
2281 | Task : Reads the value of the specified Digital input channel|
2282 | |
2283 +----------------------------------------------------------------------------+
2284 | Input Parameters : struct comedi_device *dev |
2285 | struct comedi_subdevice *s |
2286 | struct comedi_insn *insn |
2287 | unsigned int *data |
2288 +----------------------------------------------------------------------------+
2289 | Return Value : |
2290 | |
2291 +----------------------------------------------------------------------------+
2292 */
2293 
2295  struct comedi_subdevice *s,
2296  struct comedi_insn *insn,
2297  unsigned int *data)
2298 {
2299  unsigned int ui_Chan, ui_TmpValue;
2300 
2301  ui_Chan = CR_CHAN(insn->chanspec); /* channel specified */
2302 
2303  /* this_board->di_read(dev,ui_Chan,data); */
2304  if (ui_Chan <= 3) {
2305  ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI3120_RD_STATUS);
2306 
2307 /*
2308  * since only 1 channel reqd to bring it to last bit it is rotated 8
2309  * +(chan - 1) times then ANDed with 1 for last bit.
2310  */
2311  *data = (ui_TmpValue >> (ui_Chan + 8)) & 1;
2312  /* return 0; */
2313  } else {
2314  /* comedi_error(dev," chan spec wrong"); */
2315  return -EINVAL; /* "sorry channel spec wrong " */
2316  }
2317  return insn->n;
2318 
2319 }
2320 
2321 /*
2322 +----------------------------------------------------------------------------+
2323 | Function name :int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, |
2324 |struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2325 | |
2326 +----------------------------------------------------------------------------+
2327 | Task : Reads the value of the Digital input Port i.e.4channels|
2328 | value is returned in data[0] |
2329 | |
2330 +----------------------------------------------------------------------------+
2331 | Input Parameters : struct comedi_device *dev |
2332 | struct comedi_subdevice *s |
2333 | struct comedi_insn *insn |
2334 | unsigned int *data |
2335 +----------------------------------------------------------------------------+
2336 | Return Value : |
2337 | |
2338 +----------------------------------------------------------------------------+
2339 */
2341  struct comedi_insn *insn, unsigned int *data)
2342 {
2343  unsigned int ui_TmpValue;
2344  ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI3120_RD_STATUS);
2345  /***** state of 4 channels in the 11, 10, 9, 8 bits of status reg
2346  rotated right 8 times to bring them to last four bits
2347  ANDed with oxf for value.
2348  *****/
2349 
2350  *data = (ui_TmpValue >> 8) & 0xf;
2351  /* this_board->di_bits(dev,data); */
2352  return insn->n;
2353 }
2354 
2355 /*
2356 +----------------------------------------------------------------------------+
2357 | DIGITAL OUTPUT SUBDEVICE |
2358 +----------------------------------------------------------------------------+
2359 */
2360 /*
2361 +----------------------------------------------------------------------------+
2362 | Function name :int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device |
2363 | *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
2364 | |
2365 +----------------------------------------------------------------------------+
2366 | Task :Configure the output memory ON or OFF |
2367 | |
2368 +----------------------------------------------------------------------------+
2369 | Input Parameters :struct comedi_device *dev |
2370 | struct comedi_subdevice *s |
2371 | struct comedi_insn *insn |
2372 | unsigned int *data |
2373 +----------------------------------------------------------------------------+
2374 | Return Value : |
2375 | |
2376 +----------------------------------------------------------------------------+
2377 */
2378 
2380  struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data)
2381 {
2382 
2383  if ((data[0] != 0) && (data[0] != 1)) {
2384  comedi_error(dev,
2385  "Not a valid Data !!! ,Data should be 1 or 0\n");
2386  return -EINVAL;
2387  }
2388  if (data[0]) {
2389  devpriv->b_OutputMemoryStatus = APCI3120_ENABLE;
2390 
2391  } else {
2392  devpriv->b_OutputMemoryStatus = APCI3120_DISABLE;
2393  devpriv->b_DigitalOutputRegister = 0;
2394  }
2395  if (!devpriv->b_OutputMemoryStatus)
2396  ui_Temp = 0;
2397  /* if(!devpriv->b_OutputMemoryStatus ) */
2398 
2399  return insn->n;
2400 }
2401 
2402 /*
2403 +----------------------------------------------------------------------------+
2404 | Function name :int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device *dev, |
2405 | struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2406 | |
2407 +----------------------------------------------------------------------------+
2408 | Task : write diatal output port |
2409 | |
2410 +----------------------------------------------------------------------------+
2411 | Input Parameters : struct comedi_device *dev |
2412 | struct comedi_subdevice *s |
2413 | struct comedi_insn *insn |
2414 | unsigned int *data |
2415 | data[0] Value to be written
2416 | data[1] :1 Set digital o/p ON
2417 | data[1] 2 Set digital o/p OFF with memory ON
2418 +----------------------------------------------------------------------------+
2419 | Return Value : |
2420 | |
2421 +----------------------------------------------------------------------------+
2422 */
2423 
2425  struct comedi_subdevice *s,
2426  struct comedi_insn *insn,
2427  unsigned int *data)
2428 {
2429  if ((data[0] > devpriv->s_EeParameters.i_DoMaxdata) || (data[0] < 0)) {
2430 
2431  comedi_error(dev, "Data is not valid !!! \n");
2432  return -EINVAL;
2433  }
2434 
2435  switch (data[1]) {
2436  case 1:
2437  data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister;
2438  break;
2439 
2440  case 2:
2441  data[0] = data[0];
2442  break;
2443  default:
2444  printk("\nThe parameter passed is in error \n");
2445  return -EINVAL;
2446  } /* switch(data[1]) */
2447  outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
2448 
2449  devpriv->b_DigitalOutputRegister = data[0] & 0xF0;
2450 
2451  return insn->n;
2452 
2453 }
2454 
2455 /*
2456 +----------------------------------------------------------------------------+
2457 | Function name :int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,|
2458 |struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
2459 | |
2460 +----------------------------------------------------------------------------+
2461 | Task : Write digiatl output |
2462 | |
2463 +----------------------------------------------------------------------------+
2464 | Input Parameters : struct comedi_device *dev |
2465 | struct comedi_subdevice *s |
2466 | struct comedi_insn *insn |
2467 | unsigned int *data |
2468  data[0] Value to be written
2469  data[1] :1 Set digital o/p ON
2470  data[1] 2 Set digital o/p OFF with memory ON
2471 +----------------------------------------------------------------------------+
2472 | Return Value : |
2473 | |
2474 +----------------------------------------------------------------------------+
2475 */
2476 
2478  struct comedi_subdevice *s,
2479  struct comedi_insn *insn,
2480  unsigned int *data)
2481 {
2482 
2483  unsigned int ui_Temp1;
2484 
2485  unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */
2486 
2487  if ((data[0] != 0) && (data[0] != 1)) {
2488  comedi_error(dev,
2489  "Not a valid Data !!! ,Data should be 1 or 0\n");
2490  return -EINVAL;
2491  }
2492  if (ui_NoOfChannel > devpriv->s_EeParameters.i_NbrDoChannel - 1) {
2493  comedi_error(dev,
2494  "This board doesn't have specified channel !!! \n");
2495  return -EINVAL;
2496  }
2497 
2498  switch (data[1]) {
2499  case 1:
2500  data[0] = (data[0] << ui_NoOfChannel);
2501 /* ES05 data[0]=(data[0]<<4)|ui_Temp; */
2502  data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister;
2503  break;
2504 
2505  case 2:
2506  data[0] = ~data[0] & 0x1;
2507  ui_Temp1 = 1;
2508  ui_Temp1 = ui_Temp1 << ui_NoOfChannel;
2509  ui_Temp1 = ui_Temp1 << 4;
2510 /* ES05 ui_Temp=ui_Temp|ui_Temp1; */
2511  devpriv->b_DigitalOutputRegister =
2512  devpriv->b_DigitalOutputRegister | ui_Temp1;
2513 
2514  data[0] = (data[0] << ui_NoOfChannel) ^ 0xf;
2515  data[0] = data[0] << 4;
2516 /* ES05 data[0]=data[0]& ui_Temp; */
2517  data[0] = data[0] & devpriv->b_DigitalOutputRegister;
2518  break;
2519  default:
2520  printk("\nThe parameter passed is in error \n");
2521  return -EINVAL;
2522  } /* switch(data[1]) */
2523  outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
2524 
2525 /* ES05 ui_Temp=data[0] & 0xf0; */
2526  devpriv->b_DigitalOutputRegister = data[0] & 0xf0;
2527  return insn->n;
2528 
2529 }
2530 
2531 /*
2532 +----------------------------------------------------------------------------+
2533 | ANALOG OUTPUT SUBDEVICE |
2534 +----------------------------------------------------------------------------+
2535 */
2536 
2537 /*
2538 +----------------------------------------------------------------------------+
2539 | Function name :int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,|
2540 |struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2541 | |
2542 +----------------------------------------------------------------------------+
2543 | Task : Write analog output |
2544 | |
2545 +----------------------------------------------------------------------------+
2546 | Input Parameters : struct comedi_device *dev |
2547 | struct comedi_subdevice *s |
2548 | struct comedi_insn *insn |
2549 | unsigned int *data |
2550 +----------------------------------------------------------------------------+
2551 | Return Value : |
2552 | |
2553 +----------------------------------------------------------------------------+
2554 */
2555 
2557  struct comedi_subdevice *s,
2558  struct comedi_insn *insn,
2559  unsigned int *data)
2560 {
2561  unsigned int ui_Range, ui_Channel;
2562  unsigned short us_TmpValue;
2563 
2564  ui_Range = CR_RANGE(insn->chanspec);
2565  ui_Channel = CR_CHAN(insn->chanspec);
2566 
2567  /* this_board->ao_write(dev, ui_Range, ui_Channel,data[0]); */
2568  if (ui_Range) { /* if 1 then unipolar */
2569 
2570  if (data[0] != 0)
2571  data[0] =
2572  ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2573  13) | (data[0] + 8191));
2574  else
2575  data[0] =
2576  ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2577  13) | 8192);
2578 
2579  } else { /* if 0 then bipolar */
2580  data[0] =
2581  ((((ui_Channel & 0x03) << 14) & 0xC000) | (0 << 13) |
2582  data[0]);
2583 
2584  }
2585 
2586 /*
2587  * out put n values at the given channel. printk("\nwaiting for
2588  * DA_READY BIT");
2589  */
2590  do { /* Waiting of DA_READY BIT */
2591  us_TmpValue =
2592  ((unsigned short) inw(devpriv->iobase +
2593  APCI3120_RD_STATUS)) & 0x0001;
2594  } while (us_TmpValue != 0x0001);
2595 
2596  if (ui_Channel <= 3)
2597 /*
2598  * for channel 0-3 out at the register 1 (wrDac1-8) data[i]
2599  * typecasted to ushort since word write is to be done
2600  */
2601  outw((unsigned short) data[0],
2602  devpriv->iobase + APCI3120_ANALOG_OUTPUT_1);
2603  else
2604 /*
2605  * for channel 4-7 out at the register 2 (wrDac5-8) data[i]
2606  * typecasted to ushort since word write is to be done
2607  */
2608  outw((unsigned short) data[0],
2609  devpriv->iobase + APCI3120_ANALOG_OUTPUT_2);
2610 
2611  return insn->n;
2612 }