]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/staging/comedi/drivers/adl_pci9111.c
Staging: comedi: drivers: adl_pci9111: Fix AI commands in TRIG_FOLLOW case
[net-next-2.6.git] / drivers / staging / comedi / drivers / adl_pci9111.c
CommitLineData
8cb9b9fb
EP
1/*
2
3 comedi/drivers/adl_pci9111.c
4
5 Hardware driver for PCI9111 ADLink cards:
6
7 PCI-9111HR
8
9 Copyright (C) 2002-2005 Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr>
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24*/
25
26/*
27Driver: adl_pci9111
28Description: Adlink PCI-9111HR
29Author: Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr>
30Devices: [ADLink] PCI-9111HR (adl_pci9111)
31Status: experimental
32
33Supports:
34
35 - ai_insn read
36 - ao_insn read/write
37 - di_insn read
38 - do_insn read/write
39 - ai_do_cmd mode with the following sources:
40
41 - start_src TRIG_NOW
42 - scan_begin_src TRIG_FOLLOW TRIG_TIMER TRIG_EXT
43 - convert_src TRIG_TIMER TRIG_EXT
44 - scan_end_src TRIG_COUNT
45 - stop_src TRIG_COUNT TRIG_NONE
46
47 The scanned channels must be consecutive and start from 0. They must
48 all have the same range and aref.
49
50Configuration options:
51
52 [0] - PCI bus number (optional)
53 [1] - PCI slot number (optional)
54
55 If bus/slot is not specified, the first available PCI
56 device will be used.
57
58*/
59
60/*
61CHANGELOG:
62
63 2005/02/17 Extend AI streaming capabilities. Now, scan_begin_arg can be
64 a multiple of chanlist_len*convert_arg.
65 2002/02/19 Fixed the two's complement conversion in pci9111_(hr_)ai_get_data.
66 2002/02/18 Added external trigger support for analog input.
67
68TODO:
69
70 - Really test implemented functionality.
71 - Add support for the PCI-9111DG with a probe routine to identify the card type
72 (perhaps with the help of the channel number readback of the A/D Data register).
73 - Add external multiplexer support.
74
75*/
76
77#include "../comedidev.h"
78
79#include <linux/delay.h>
70265d24 80#include <linux/interrupt.h>
8cb9b9fb
EP
81
82#include "8253.h"
83#include "comedi_pci.h"
84#include "comedi_fc.h"
85
86#define PCI9111_DRIVER_NAME "adl_pci9111"
87#define PCI9111_HR_DEVICE_ID 0x9111
88
52f8ac98 89/* TODO: Add other pci9111 board id */
8cb9b9fb
EP
90
91#define PCI9111_IO_RANGE 0x0100
92
93#define PCI9111_FIFO_HALF_SIZE 512
94
95#define PCI9111_AI_CHANNEL_NBR 16
96
97#define PCI9111_AI_RESOLUTION 12
98#define PCI9111_AI_RESOLUTION_MASK 0x0FFF
99#define PCI9111_AI_RESOLUTION_2_CMP_BIT 0x0800
100
101#define PCI9111_HR_AI_RESOLUTION 16
102#define PCI9111_HR_AI_RESOLUTION_MASK 0xFFFF
103#define PCI9111_HR_AI_RESOLUTION_2_CMP_BIT 0x8000
104
105#define PCI9111_AI_ACQUISITION_PERIOD_MIN_NS 10000
106#define PCI9111_AO_CHANNEL_NBR 1
107#define PCI9111_AO_RESOLUTION 12
108#define PCI9111_AO_RESOLUTION_MASK 0x0FFF
109#define PCI9111_DI_CHANNEL_NBR 16
110#define PCI9111_DO_CHANNEL_NBR 16
111#define PCI9111_DO_MASK 0xFFFF
112
113#define PCI9111_RANGE_SETTING_DELAY 10
114#define PCI9111_AI_INSTANT_READ_UDELAY_US 2
115#define PCI9111_AI_INSTANT_READ_TIMEOUT 100
116
117#define PCI9111_8254_CLOCK_PERIOD_NS 500
118
119#define PCI9111_8254_COUNTER_0 0x00
120#define PCI9111_8254_COUNTER_1 0x40
121#define PCI9111_8254_COUNTER_2 0x80
122#define PCI9111_8254_COUNTER_LATCH 0x00
123#define PCI9111_8254_READ_LOAD_LSB_ONLY 0x10
124#define PCI9111_8254_READ_LOAD_MSB_ONLY 0x20
125#define PCI9111_8254_READ_LOAD_LSB_MSB 0x30
126#define PCI9111_8254_MODE_0 0x00
127#define PCI9111_8254_MODE_1 0x02
128#define PCI9111_8254_MODE_2 0x04
129#define PCI9111_8254_MODE_3 0x06
130#define PCI9111_8254_MODE_4 0x08
131#define PCI9111_8254_MODE_5 0x0A
132#define PCI9111_8254_BINARY_COUNTER 0x00
133#define PCI9111_8254_BCD_COUNTER 0x01
134
135/* IO address map */
136
52f8ac98 137#define PCI9111_REGISTER_AD_FIFO_VALUE 0x00 /* AD Data stored in FIFO */
8cb9b9fb
EP
138#define PCI9111_REGISTER_DA_OUTPUT 0x00
139#define PCI9111_REGISTER_DIGITAL_IO 0x02
140#define PCI9111_REGISTER_EXTENDED_IO_PORTS 0x04
52f8ac98 141#define PCI9111_REGISTER_AD_CHANNEL_CONTROL 0x06 /* Channel selection */
8cb9b9fb
EP
142#define PCI9111_REGISTER_AD_CHANNEL_READBACK 0x06
143#define PCI9111_REGISTER_INPUT_SIGNAL_RANGE 0x08
144#define PCI9111_REGISTER_RANGE_STATUS_READBACK 0x08
145#define PCI9111_REGISTER_TRIGGER_MODE_CONTROL 0x0A
146#define PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK 0x0A
147#define PCI9111_REGISTER_SOFTWARE_TRIGGER 0x0E
148#define PCI9111_REGISTER_INTERRUPT_CONTROL 0x0C
149#define PCI9111_REGISTER_8254_COUNTER_0 0x40
150#define PCI9111_REGISTER_8254_COUNTER_1 0x42
151#define PCI9111_REGISTER_8254_COUNTER_2 0X44
152#define PCI9111_REGISTER_8254_CONTROL 0x46
153#define PCI9111_REGISTER_INTERRUPT_CLEAR 0x48
154
155#define PCI9111_TRIGGER_MASK 0x0F
156#define PCI9111_PTRG_OFF (0 << 3)
157#define PCI9111_PTRG_ON (1 << 3)
158#define PCI9111_EITS_EXTERNAL (1 << 2)
159#define PCI9111_EITS_INTERNAL (0 << 2)
160#define PCI9111_TPST_SOFTWARE_TRIGGER (0 << 1)
161#define PCI9111_TPST_TIMER_PACER (1 << 1)
162#define PCI9111_ASCAN_ON (1 << 0)
163#define PCI9111_ASCAN_OFF (0 << 0)
164
165#define PCI9111_ISC0_SET_IRQ_ON_ENDING_OF_AD_CONVERSION (0 << 0)
166#define PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL (1 << 0)
167#define PCI9111_ISC1_SET_IRQ_ON_TIMER_TICK (0 << 1)
168#define PCI9111_ISC1_SET_IRQ_ON_EXT_TRG (1 << 1)
169#define PCI9111_FFEN_SET_FIFO_ENABLE (0 << 2)
170#define PCI9111_FFEN_SET_FIFO_DISABLE (1 << 2)
171
172#define PCI9111_CHANNEL_MASK 0x0F
173
174#define PCI9111_RANGE_MASK 0x07
175#define PCI9111_FIFO_EMPTY_MASK 0x10
176#define PCI9111_FIFO_HALF_FULL_MASK 0x20
177#define PCI9111_FIFO_FULL_MASK 0x40
178#define PCI9111_AD_BUSY_MASK 0x80
179
180#define PCI9111_IO_BASE dev->iobase
181
182/*
183 * Define inlined function
184 */
185
186#define pci9111_trigger_and_autoscan_get() \
187 (inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK)&0x0F)
188
189#define pci9111_trigger_and_autoscan_set(flags) \
f7cbd7aa 190 outb(flags, PCI9111_IO_BASE+PCI9111_REGISTER_TRIGGER_MODE_CONTROL)
8cb9b9fb
EP
191
192#define pci9111_interrupt_and_fifo_get() \
193 ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK) >> 4) &0x03)
194
195#define pci9111_interrupt_and_fifo_set(flags) \
f7cbd7aa 196 outb(flags, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL)
8cb9b9fb
EP
197
198#define pci9111_interrupt_clear() \
f7cbd7aa 199 outb(0, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CLEAR)
8cb9b9fb
EP
200
201#define pci9111_software_trigger() \
f7cbd7aa 202 outb(0, PCI9111_IO_BASE+PCI9111_REGISTER_SOFTWARE_TRIGGER)
8cb9b9fb
EP
203
204#define pci9111_fifo_reset() \
f7cbd7aa
BP
205 outb(PCI9111_FFEN_SET_FIFO_ENABLE, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \
206 outb(PCI9111_FFEN_SET_FIFO_DISABLE, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \
207 outb(PCI9111_FFEN_SET_FIFO_ENABLE, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL)
8cb9b9fb
EP
208
209#define pci9111_is_fifo_full() \
210 ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
211 PCI9111_FIFO_FULL_MASK)==0)
212
213#define pci9111_is_fifo_half_full() \
214 ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
215 PCI9111_FIFO_HALF_FULL_MASK)==0)
216
217#define pci9111_is_fifo_empty() \
218 ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
219 PCI9111_FIFO_EMPTY_MASK)==0)
220
221#define pci9111_ai_channel_set(channel) \
f7cbd7aa 222 outb((channel)&PCI9111_CHANNEL_MASK, PCI9111_IO_BASE+PCI9111_REGISTER_AD_CHANNEL_CONTROL)
8cb9b9fb
EP
223
224#define pci9111_ai_channel_get() \
225 inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_CHANNEL_READBACK)&PCI9111_CHANNEL_MASK
226
227#define pci9111_ai_range_set(range) \
f7cbd7aa 228 outb((range)&PCI9111_RANGE_MASK, PCI9111_IO_BASE+PCI9111_REGISTER_INPUT_SIGNAL_RANGE)
8cb9b9fb
EP
229
230#define pci9111_ai_range_get() \
231 inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)&PCI9111_RANGE_MASK
232
233#define pci9111_ai_get_data() \
234 ((inw(PCI9111_IO_BASE+PCI9111_REGISTER_AD_FIFO_VALUE)>>4)&PCI9111_AI_RESOLUTION_MASK) \
235 ^ PCI9111_AI_RESOLUTION_2_CMP_BIT
236
237#define pci9111_hr_ai_get_data() \
238 (inw(PCI9111_IO_BASE+PCI9111_REGISTER_AD_FIFO_VALUE) & PCI9111_HR_AI_RESOLUTION_MASK) \
239 ^ PCI9111_HR_AI_RESOLUTION_2_CMP_BIT
240
241#define pci9111_ao_set_data(data) \
f7cbd7aa 242 outw(data&PCI9111_AO_RESOLUTION_MASK, PCI9111_IO_BASE+PCI9111_REGISTER_DA_OUTPUT)
8cb9b9fb
EP
243
244#define pci9111_di_get_bits() \
245 inw(PCI9111_IO_BASE+PCI9111_REGISTER_DIGITAL_IO)
246
247#define pci9111_do_set_bits(bits) \
f7cbd7aa 248 outw(bits, PCI9111_IO_BASE+PCI9111_REGISTER_DIGITAL_IO)
8cb9b9fb
EP
249
250#define pci9111_8254_control_set(flags) \
f7cbd7aa 251 outb(flags, PCI9111_IO_BASE+PCI9111_REGISTER_8254_CONTROL)
8cb9b9fb
EP
252
253#define pci9111_8254_counter_0_set(data) \
254 outb(data & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_0); \
53106ae6 255 outb((data >> 8) & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_0)
8cb9b9fb
EP
256
257#define pci9111_8254_counter_1_set(data) \
258 outb(data & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_1); \
53106ae6 259 outb((data >> 8) & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_1)
8cb9b9fb
EP
260
261#define pci9111_8254_counter_2_set(data) \
262 outb(data & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_2); \
53106ae6 263 outb((data >> 8) & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_2)
8cb9b9fb 264
52f8ac98 265/* Function prototypes */
8cb9b9fb 266
0a85b6f0
MT
267static int pci9111_attach(struct comedi_device *dev,
268 struct comedi_devconfig *it);
da91b269 269static int pci9111_detach(struct comedi_device *dev);
0a85b6f0
MT
270static void pci9111_ai_munge(struct comedi_device *dev,
271 struct comedi_subdevice *s, void *data,
272 unsigned int num_bytes,
273 unsigned int start_chan_index);
8cb9b9fb 274
9ced1de6 275static const struct comedi_lrange pci9111_hr_ai_range = {
8cb9b9fb
EP
276 5,
277 {
0a85b6f0
MT
278 BIP_RANGE(10),
279 BIP_RANGE(5),
280 BIP_RANGE(2.5),
281 BIP_RANGE(1.25),
282 BIP_RANGE(0.625)
283 }
8cb9b9fb
EP
284};
285
286static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = {
0a85b6f0
MT
287 {
288 PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID, PCI_ANY_ID,
289 PCI_ANY_ID, 0, 0, 0},
290 /* { PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */
291 {
292 0}
8cb9b9fb
EP
293};
294
295MODULE_DEVICE_TABLE(pci, pci9111_pci_table);
296
52f8ac98
BP
297/* */
298/* Board specification structure */
299/* */
8cb9b9fb 300
940579fb 301struct pci9111_board {
52f8ac98 302 const char *name; /* driver name */
8cb9b9fb 303 int device_id;
52f8ac98
BP
304 int ai_channel_nbr; /* num of A/D chans */
305 int ao_channel_nbr; /* num of D/A chans */
306 int ai_resolution; /* resolution of A/D */
8cb9b9fb 307 int ai_resolution_mask;
52f8ac98 308 int ao_resolution; /* resolution of D/A */
8cb9b9fb 309 int ao_resolution_mask;
52f8ac98
BP
310 const struct comedi_lrange *ai_range_list; /* rangelist for A/D */
311 const struct comedi_lrange *ao_range_list; /* rangelist for D/A */
8cb9b9fb 312 unsigned int ai_acquisition_period_min_ns;
940579fb 313};
8cb9b9fb 314
940579fb 315static const struct pci9111_board pci9111_boards[] = {
8cb9b9fb 316 {
0a85b6f0
MT
317 .name = "pci9111_hr",
318 .device_id = PCI9111_HR_DEVICE_ID,
319 .ai_channel_nbr = PCI9111_AI_CHANNEL_NBR,
320 .ao_channel_nbr = PCI9111_AO_CHANNEL_NBR,
321 .ai_resolution = PCI9111_HR_AI_RESOLUTION,
322 .ai_resolution_mask = PCI9111_HR_AI_RESOLUTION_MASK,
323 .ao_resolution = PCI9111_AO_RESOLUTION,
324 .ao_resolution_mask = PCI9111_AO_RESOLUTION_MASK,
325 .ai_range_list = &pci9111_hr_ai_range,
326 .ao_range_list = &range_bipolar10,
327 .ai_acquisition_period_min_ns = PCI9111_AI_ACQUISITION_PERIOD_MIN_NS}
8cb9b9fb
EP
328};
329
330#define pci9111_board_nbr \
940579fb 331 (sizeof(pci9111_boards)/sizeof(struct pci9111_board))
8cb9b9fb 332
139dfbdf 333static struct comedi_driver pci9111_driver = {
68c3dbff
BP
334 .driver_name = PCI9111_DRIVER_NAME,
335 .module = THIS_MODULE,
336 .attach = pci9111_attach,
337 .detach = pci9111_detach,
8cb9b9fb
EP
338};
339
340COMEDI_PCI_INITCLEANUP(pci9111_driver, pci9111_pci_table);
341
52f8ac98 342/* Private data structure */
8cb9b9fb 343
c350fa19 344struct pci9111_private_data {
8cb9b9fb 345 struct pci_dev *pci_device;
52f8ac98 346 unsigned long io_range; /* PCI6503 io range */
8cb9b9fb 347
52f8ac98 348 unsigned long lcr_io_base; /* Local configuration register base address */
8cb9b9fb
EP
349 unsigned long lcr_io_range;
350
351 int stop_counter;
352 int stop_is_none;
353
354 unsigned int scan_delay;
355 unsigned int chanlist_len;
356 unsigned int chunk_counter;
357 unsigned int chunk_num_samples;
358
52f8ac98 359 int ao_readback; /* Last written analog output data */
8cb9b9fb 360
525d1b13
GKH
361 unsigned int timer_divisor_1; /* Divisor values for the 8254 timer pacer */
362 unsigned int timer_divisor_2;
8cb9b9fb 363
52f8ac98 364 int is_valid; /* Is device valid */
8cb9b9fb 365
790c5541 366 short ai_bounce_buffer[2 * PCI9111_FIFO_HALF_SIZE];
c350fa19 367};
8cb9b9fb 368
c350fa19 369#define dev_private ((struct pci9111_private_data *)dev->private)
8cb9b9fb 370
52f8ac98
BP
371/* ------------------------------------------------------------------ */
372/* PLX9050 SECTION */
373/* ------------------------------------------------------------------ */
8cb9b9fb
EP
374
375#define PLX9050_REGISTER_INTERRUPT_CONTROL 0x4c
376
377#define PLX9050_LINTI1_ENABLE (1 << 0)
378#define PLX9050_LINTI1_ACTIVE_HIGH (1 << 1)
379#define PLX9050_LINTI1_STATUS (1 << 2)
380#define PLX9050_LINTI2_ENABLE (1 << 3)
381#define PLX9050_LINTI2_ACTIVE_HIGH (1 << 4)
382#define PLX9050_LINTI2_STATUS (1 << 5)
383#define PLX9050_PCI_INTERRUPT_ENABLE (1 << 6)
384#define PLX9050_SOFTWARE_INTERRUPT (1 << 7)
385
386static void plx9050_interrupt_control(unsigned long io_base,
0a85b6f0
MT
387 bool LINTi1_enable,
388 bool LINTi1_active_high,
389 bool LINTi2_enable,
390 bool LINTi2_active_high,
391 bool interrupt_enable)
8cb9b9fb
EP
392{
393 int flags = 0;
394
395 if (LINTi1_enable)
396 flags |= PLX9050_LINTI1_ENABLE;
397 if (LINTi1_active_high)
398 flags |= PLX9050_LINTI1_ACTIVE_HIGH;
399 if (LINTi2_enable)
400 flags |= PLX9050_LINTI2_ENABLE;
401 if (LINTi2_active_high)
402 flags |= PLX9050_LINTI2_ACTIVE_HIGH;
403
404 if (interrupt_enable)
405 flags |= PLX9050_PCI_INTERRUPT_ENABLE;
406
407 outb(flags, io_base + PLX9050_REGISTER_INTERRUPT_CONTROL);
408}
409
52f8ac98
BP
410/* ------------------------------------------------------------------ */
411/* MISCELLANEOUS SECTION */
412/* ------------------------------------------------------------------ */
8cb9b9fb 413
52f8ac98 414/* 8254 timer */
8cb9b9fb 415
da91b269 416static void pci9111_timer_set(struct comedi_device *dev)
8cb9b9fb
EP
417{
418 pci9111_8254_control_set(PCI9111_8254_COUNTER_0 |
0a85b6f0
MT
419 PCI9111_8254_READ_LOAD_LSB_MSB |
420 PCI9111_8254_MODE_0 |
421 PCI9111_8254_BINARY_COUNTER);
8cb9b9fb
EP
422
423 pci9111_8254_control_set(PCI9111_8254_COUNTER_1 |
0a85b6f0
MT
424 PCI9111_8254_READ_LOAD_LSB_MSB |
425 PCI9111_8254_MODE_2 |
426 PCI9111_8254_BINARY_COUNTER);
8cb9b9fb
EP
427
428 pci9111_8254_control_set(PCI9111_8254_COUNTER_2 |
0a85b6f0
MT
429 PCI9111_8254_READ_LOAD_LSB_MSB |
430 PCI9111_8254_MODE_2 |
431 PCI9111_8254_BINARY_COUNTER);
8cb9b9fb 432
5f74ea14 433 udelay(1);
8cb9b9fb
EP
434
435 pci9111_8254_counter_2_set(dev_private->timer_divisor_2);
436 pci9111_8254_counter_1_set(dev_private->timer_divisor_1);
437}
438
655f78f6 439enum pci9111_trigger_sources {
8cb9b9fb
EP
440 software,
441 timer_pacer,
442 external
655f78f6 443};
8cb9b9fb 444
da91b269 445static void pci9111_trigger_source_set(struct comedi_device *dev,
0a85b6f0 446 enum pci9111_trigger_sources source)
8cb9b9fb
EP
447{
448 int flags;
449
450 flags = pci9111_trigger_and_autoscan_get() & 0x09;
451
452 switch (source) {
453 case software:
454 flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_SOFTWARE_TRIGGER;
455 break;
456
457 case timer_pacer:
458 flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_TIMER_PACER;
459 break;
460
461 case external:
462 flags |= PCI9111_EITS_EXTERNAL;
463 break;
464 }
465
466 pci9111_trigger_and_autoscan_set(flags);
467}
468
da91b269 469static void pci9111_pretrigger_set(struct comedi_device *dev, bool pretrigger)
8cb9b9fb
EP
470{
471 int flags;
472
473 flags = pci9111_trigger_and_autoscan_get() & 0x07;
474
475 if (pretrigger)
476 flags |= PCI9111_PTRG_ON;
477
478 pci9111_trigger_and_autoscan_set(flags);
479}
480
da91b269 481static void pci9111_autoscan_set(struct comedi_device *dev, bool autoscan)
8cb9b9fb
EP
482{
483 int flags;
484
485 flags = pci9111_trigger_and_autoscan_get() & 0x0e;
486
487 if (autoscan)
488 flags |= PCI9111_ASCAN_ON;
489
490 pci9111_trigger_and_autoscan_set(flags);
491}
492
3ba97b3c 493enum pci9111_ISC0_sources {
8cb9b9fb
EP
494 irq_on_eoc,
495 irq_on_fifo_half_full
3ba97b3c 496};
8cb9b9fb 497
52f8ac98 498enum pci9111_ISC1_sources {
8cb9b9fb
EP
499 irq_on_timer_tick,
500 irq_on_external_trigger
52f8ac98 501};
8cb9b9fb 502
da91b269 503static void pci9111_interrupt_source_set(struct comedi_device *dev,
0a85b6f0
MT
504 enum pci9111_ISC0_sources irq_0_source,
505 enum pci9111_ISC1_sources irq_1_source)
8cb9b9fb
EP
506{
507 int flags;
508
509 flags = pci9111_interrupt_and_fifo_get() & 0x04;
510
511 if (irq_0_source == irq_on_fifo_half_full)
512 flags |= PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL;
513
514 if (irq_1_source == irq_on_external_trigger)
515 flags |= PCI9111_ISC1_SET_IRQ_ON_EXT_TRG;
516
517 pci9111_interrupt_and_fifo_set(flags);
518}
519
52f8ac98
BP
520/* ------------------------------------------------------------------ */
521/* HARDWARE TRIGGERED ANALOG INPUT SECTION */
522/* ------------------------------------------------------------------ */
8cb9b9fb 523
52f8ac98 524/* Cancel analog input autoscan */
8cb9b9fb
EP
525
526#undef AI_DO_CMD_DEBUG
527
0a85b6f0
MT
528static int pci9111_ai_cancel(struct comedi_device *dev,
529 struct comedi_subdevice *s)
8cb9b9fb 530{
52f8ac98 531 /* Disable interrupts */
8cb9b9fb
EP
532
533 plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true,
0a85b6f0 534 true, false);
8cb9b9fb
EP
535
536 pci9111_trigger_source_set(dev, software);
537
538 pci9111_autoscan_set(dev, false);
539
540 pci9111_fifo_reset();
541
542#ifdef AI_DO_CMD_DEBUG
543 printk(PCI9111_DRIVER_NAME ": ai_cancel\n");
544#endif
545
546 return 0;
547}
548
52f8ac98 549/* Test analog input command */
8cb9b9fb 550
f7cbd7aa 551#define pci9111_check_trigger_src(src, flags) \
8cb9b9fb
EP
552 tmp = src; \
553 src &= flags; \
554 if (!src || tmp != src) error++
555
556static int
da91b269 557pci9111_ai_do_cmd_test(struct comedi_device *dev,
0a85b6f0 558 struct comedi_subdevice *s, struct comedi_cmd *cmd)
8cb9b9fb
EP
559{
560 int tmp;
561 int error = 0;
562 int range, reference;
563 int i;
0a85b6f0 564 struct pci9111_board *board = (struct pci9111_board *)dev->board_ptr;
8cb9b9fb 565
52f8ac98 566 /* Step 1 : check if trigger are trivialy valid */
8cb9b9fb
EP
567
568 pci9111_check_trigger_src(cmd->start_src, TRIG_NOW);
569 pci9111_check_trigger_src(cmd->scan_begin_src,
0a85b6f0 570 TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT);
8cb9b9fb
EP
571 pci9111_check_trigger_src(cmd->convert_src, TRIG_TIMER | TRIG_EXT);
572 pci9111_check_trigger_src(cmd->scan_end_src, TRIG_COUNT);
573 pci9111_check_trigger_src(cmd->stop_src, TRIG_COUNT | TRIG_NONE);
574
575 if (error)
576 return 1;
577
52f8ac98 578 /* step 2 : make sure trigger sources are unique and mutually compatible */
8cb9b9fb
EP
579
580 if (cmd->start_src != TRIG_NOW)
581 error++;
582
583 if ((cmd->scan_begin_src != TRIG_TIMER) &&
0a85b6f0
MT
584 (cmd->scan_begin_src != TRIG_FOLLOW) &&
585 (cmd->scan_begin_src != TRIG_EXT))
8cb9b9fb
EP
586 error++;
587
2306d9b1 588 if ((cmd->convert_src != TRIG_TIMER) && (cmd->convert_src != TRIG_EXT))
8cb9b9fb 589 error++;
8cb9b9fb 590 if ((cmd->convert_src == TRIG_TIMER) &&
0a85b6f0 591 !((cmd->scan_begin_src == TRIG_TIMER) ||
2306d9b1 592 (cmd->scan_begin_src == TRIG_FOLLOW)))
8cb9b9fb 593 error++;
8cb9b9fb 594 if ((cmd->convert_src == TRIG_EXT) &&
0a85b6f0 595 !((cmd->scan_begin_src == TRIG_EXT) ||
2306d9b1 596 (cmd->scan_begin_src == TRIG_FOLLOW)))
8cb9b9fb 597 error++;
2306d9b1 598
8cb9b9fb
EP
599
600 if (cmd->scan_end_src != TRIG_COUNT)
601 error++;
602 if ((cmd->stop_src != TRIG_COUNT) && (cmd->stop_src != TRIG_NONE))
603 error++;
604
605 if (error)
606 return 2;
607
52f8ac98 608 /* Step 3 : make sure arguments are trivialy compatible */
8cb9b9fb
EP
609
610 if (cmd->chanlist_len < 1) {
611 cmd->chanlist_len = 1;
612 error++;
613 }
614
615 if (cmd->chanlist_len > board->ai_channel_nbr) {
616 cmd->chanlist_len = board->ai_channel_nbr;
617 error++;
618 }
619
620 if ((cmd->start_src == TRIG_NOW) && (cmd->start_arg != 0)) {
621 cmd->start_arg = 0;
622 error++;
623 }
624
625 if ((cmd->convert_src == TRIG_TIMER) &&
0a85b6f0 626 (cmd->convert_arg < board->ai_acquisition_period_min_ns)) {
8cb9b9fb
EP
627 cmd->convert_arg = board->ai_acquisition_period_min_ns;
628 error++;
629 }
630 if ((cmd->convert_src == TRIG_EXT) && (cmd->convert_arg != 0)) {
631 cmd->convert_arg = 0;
632 error++;
633 }
634
635 if ((cmd->scan_begin_src == TRIG_TIMER) &&
0a85b6f0 636 (cmd->scan_begin_arg < board->ai_acquisition_period_min_ns)) {
8cb9b9fb
EP
637 cmd->scan_begin_arg = board->ai_acquisition_period_min_ns;
638 error++;
639 }
640 if ((cmd->scan_begin_src == TRIG_FOLLOW) && (cmd->scan_begin_arg != 0)) {
641 cmd->scan_begin_arg = 0;
642 error++;
643 }
644 if ((cmd->scan_begin_src == TRIG_EXT) && (cmd->scan_begin_arg != 0)) {
645 cmd->scan_begin_arg = 0;
646 error++;
647 }
648
649 if ((cmd->scan_end_src == TRIG_COUNT) &&
0a85b6f0 650 (cmd->scan_end_arg != cmd->chanlist_len)) {
8cb9b9fb
EP
651 cmd->scan_end_arg = cmd->chanlist_len;
652 error++;
653 }
654
655 if ((cmd->stop_src == TRIG_COUNT) && (cmd->stop_arg < 1)) {
656 cmd->stop_arg = 1;
657 error++;
658 }
659 if ((cmd->stop_src == TRIG_NONE) && (cmd->stop_arg != 0)) {
660 cmd->stop_arg = 0;
661 error++;
662 }
663
664 if (error)
665 return 3;
666
52f8ac98 667 /* Step 4 : fix up any arguments */
8cb9b9fb
EP
668
669 if (cmd->convert_src == TRIG_TIMER) {
670 tmp = cmd->convert_arg;
671 i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS,
0a85b6f0
MT
672 &(dev_private->timer_divisor_1),
673 &(dev_private->timer_divisor_2),
674 &(cmd->convert_arg),
675 cmd->flags & TRIG_ROUND_MASK);
8cb9b9fb
EP
676 if (tmp != cmd->convert_arg)
677 error++;
678 }
52f8ac98
BP
679 /* There's only one timer on this card, so the scan_begin timer must */
680 /* be a multiple of chanlist_len*convert_arg */
8cb9b9fb
EP
681
682 if (cmd->scan_begin_src == TRIG_TIMER) {
683
684 unsigned int scan_begin_min;
685 unsigned int scan_begin_arg;
686 unsigned int scan_factor;
687
688 scan_begin_min = cmd->chanlist_len * cmd->convert_arg;
689
690 if (cmd->scan_begin_arg != scan_begin_min) {
691 if (scan_begin_min < cmd->scan_begin_arg) {
692 scan_factor =
0a85b6f0 693 cmd->scan_begin_arg / scan_begin_min;
8cb9b9fb
EP
694 scan_begin_arg = scan_factor * scan_begin_min;
695 if (cmd->scan_begin_arg != scan_begin_arg) {
696 cmd->scan_begin_arg = scan_begin_arg;
697 error++;
698 }
699 } else {
700 cmd->scan_begin_arg = scan_begin_min;
701 error++;
702 }
703 }
704 }
705
706 if (error)
707 return 4;
708
52f8ac98 709 /* Step 5 : check channel list */
8cb9b9fb
EP
710
711 if (cmd->chanlist) {
712
713 range = CR_RANGE(cmd->chanlist[0]);
714 reference = CR_AREF(cmd->chanlist[0]);
715
716 if (cmd->chanlist_len > 1) {
717 for (i = 0; i < cmd->chanlist_len; i++) {
718 if (CR_CHAN(cmd->chanlist[i]) != i) {
719 comedi_error(dev,
0a85b6f0
MT
720 "entries in chanlist must be consecutive "
721 "channels,counting upwards from 0\n");
8cb9b9fb
EP
722 error++;
723 }
724 if (CR_RANGE(cmd->chanlist[i]) != range) {
725 comedi_error(dev,
0a85b6f0 726 "entries in chanlist must all have the same gain\n");
8cb9b9fb
EP
727 error++;
728 }
729 if (CR_AREF(cmd->chanlist[i]) != reference) {
730 comedi_error(dev,
0a85b6f0 731 "entries in chanlist must all have the same reference\n");
8cb9b9fb
EP
732 error++;
733 }
734 }
735 } else {
736 if ((CR_CHAN(cmd->chanlist[0]) >
0a85b6f0
MT
737 (board->ai_channel_nbr - 1))
738 || (CR_CHAN(cmd->chanlist[0]) < 0)) {
8cb9b9fb 739 comedi_error(dev,
0a85b6f0 740 "channel number is out of limits\n");
8cb9b9fb
EP
741 error++;
742 }
743 }
744 }
745
746 if (error)
747 return 5;
748
749 return 0;
750
751}
752
52f8ac98 753/* Analog input command */
8cb9b9fb 754
0a85b6f0
MT
755static int pci9111_ai_do_cmd(struct comedi_device *dev,
756 struct comedi_subdevice *subdevice)
8cb9b9fb 757{
ea6d0d4c 758 struct comedi_cmd *async_cmd = &subdevice->async->cmd;
8cb9b9fb
EP
759
760 if (!dev->irq) {
761 comedi_error(dev,
0a85b6f0 762 "no irq assigned for PCI9111, cannot do hardware conversion");
8cb9b9fb
EP
763 return -1;
764 }
52f8ac98
BP
765 /* Set channel scan limit */
766 /* PCI9111 allows only scanning from channel 0 to channel n */
767 /* TODO: handle the case of an external multiplexer */
8cb9b9fb
EP
768
769 if (async_cmd->chanlist_len > 1) {
770 pci9111_ai_channel_set((async_cmd->chanlist_len) - 1);
771 pci9111_autoscan_set(dev, true);
772 } else {
773 pci9111_ai_channel_set(CR_CHAN(async_cmd->chanlist[0]));
774 pci9111_autoscan_set(dev, false);
775 }
776
52f8ac98
BP
777 /* Set gain */
778 /* This is the same gain on every channel */
8cb9b9fb
EP
779
780 pci9111_ai_range_set(CR_RANGE(async_cmd->chanlist[0]));
781
782 /* Set counter */
783
784 switch (async_cmd->stop_src) {
785 case TRIG_COUNT:
786 dev_private->stop_counter =
0a85b6f0 787 async_cmd->stop_arg * async_cmd->chanlist_len;
8cb9b9fb
EP
788 dev_private->stop_is_none = 0;
789 break;
790
791 case TRIG_NONE:
792 dev_private->stop_counter = 0;
793 dev_private->stop_is_none = 1;
794 break;
795
796 default:
797 comedi_error(dev, "Invalid stop trigger");
798 return -1;
799 }
800
52f8ac98 801 /* Set timer pacer */
8cb9b9fb
EP
802
803 dev_private->scan_delay = 0;
804 switch (async_cmd->convert_src) {
805 case TRIG_TIMER:
806 i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS,
0a85b6f0
MT
807 &(dev_private->timer_divisor_1),
808 &(dev_private->timer_divisor_2),
809 &(async_cmd->convert_arg),
810 async_cmd->
811 flags & TRIG_ROUND_MASK);
8cb9b9fb
EP
812#ifdef AI_DO_CMD_DEBUG
813 printk(PCI9111_DRIVER_NAME ": divisors = %d, %d\n",
0a85b6f0
MT
814 dev_private->timer_divisor_1,
815 dev_private->timer_divisor_2);
8cb9b9fb
EP
816#endif
817
818 pci9111_trigger_source_set(dev, software);
819 pci9111_timer_set(dev);
820 pci9111_fifo_reset();
821 pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
0a85b6f0 822 irq_on_timer_tick);
8cb9b9fb
EP
823 pci9111_trigger_source_set(dev, timer_pacer);
824 plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
0a85b6f0 825 false, true, true);
8cb9b9fb 826
6c2fd308
IA
827 if (async_cmd->scan_begin_src == TRIG_TIMER) {
828 dev_private->scan_delay =
829 (async_cmd->scan_begin_arg /
830 (async_cmd->convert_arg *
831 async_cmd->chanlist_len)) - 1;
832 }
8cb9b9fb
EP
833
834 break;
835
836 case TRIG_EXT:
837
838 pci9111_trigger_source_set(dev, external);
839 pci9111_fifo_reset();
840 pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
0a85b6f0 841 irq_on_timer_tick);
8cb9b9fb 842 plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
0a85b6f0 843 false, true, true);
8cb9b9fb
EP
844
845 break;
846
847 default:
848 comedi_error(dev, "Invalid convert trigger");
849 return -1;
850 }
851
852 dev_private->stop_counter *= (1 + dev_private->scan_delay);
853 dev_private->chanlist_len = async_cmd->chanlist_len;
854 dev_private->chunk_counter = 0;
855 dev_private->chunk_num_samples =
0a85b6f0 856 dev_private->chanlist_len * (1 + dev_private->scan_delay);
8cb9b9fb
EP
857
858#ifdef AI_DO_CMD_DEBUG
859 printk(PCI9111_DRIVER_NAME ": start interruptions!\n");
860 printk(PCI9111_DRIVER_NAME ": trigger source = %2x\n",
0a85b6f0 861 pci9111_trigger_and_autoscan_get());
8cb9b9fb 862 printk(PCI9111_DRIVER_NAME ": irq source = %2x\n",
0a85b6f0 863 pci9111_interrupt_and_fifo_get());
8cb9b9fb
EP
864 printk(PCI9111_DRIVER_NAME ": ai_do_cmd\n");
865 printk(PCI9111_DRIVER_NAME ": stop counter = %d\n",
0a85b6f0 866 dev_private->stop_counter);
8cb9b9fb 867 printk(PCI9111_DRIVER_NAME ": scan delay = %d\n",
0a85b6f0 868 dev_private->scan_delay);
8cb9b9fb 869 printk(PCI9111_DRIVER_NAME ": chanlist_len = %d\n",
0a85b6f0 870 dev_private->chanlist_len);
8cb9b9fb 871 printk(PCI9111_DRIVER_NAME ": chunk num samples = %d\n",
0a85b6f0 872 dev_private->chunk_num_samples);
8cb9b9fb
EP
873#endif
874
875 return 0;
876}
877
0a85b6f0
MT
878static void pci9111_ai_munge(struct comedi_device *dev,
879 struct comedi_subdevice *s, void *data,
880 unsigned int num_bytes,
881 unsigned int start_chan_index)
8cb9b9fb 882{
790c5541
BP
883 unsigned int i, num_samples = num_bytes / sizeof(short);
884 short *array = data;
8cb9b9fb 885 int resolution =
0a85b6f0 886 ((struct pci9111_board *)dev->board_ptr)->ai_resolution;
8cb9b9fb
EP
887
888 for (i = 0; i < num_samples; i++) {
889 if (resolution == PCI9111_HR_AI_RESOLUTION)
890 array[i] =
0a85b6f0
MT
891 (array[i] & PCI9111_HR_AI_RESOLUTION_MASK) ^
892 PCI9111_HR_AI_RESOLUTION_2_CMP_BIT;
8cb9b9fb
EP
893 else
894 array[i] =
0a85b6f0
MT
895 ((array[i] >> 4) & PCI9111_AI_RESOLUTION_MASK) ^
896 PCI9111_AI_RESOLUTION_2_CMP_BIT;
8cb9b9fb
EP
897 }
898}
899
52f8ac98
BP
900/* ------------------------------------------------------------------ */
901/* INTERRUPT SECTION */
902/* ------------------------------------------------------------------ */
8cb9b9fb
EP
903
904#undef INTERRUPT_DEBUG
905
70265d24 906static irqreturn_t pci9111_interrupt(int irq, void *p_device)
8cb9b9fb 907{
71b5f4f1 908 struct comedi_device *dev = p_device;
34c43922 909 struct comedi_subdevice *subdevice = dev->read_subdev;
d163679c 910 struct comedi_async *async;
8cb9b9fb
EP
911 unsigned long irq_flags;
912 unsigned char intcsr;
913
914 if (!dev->attached) {
52f8ac98
BP
915 /* Ignore interrupt before device fully attached. */
916 /* Might not even have allocated subdevices yet! */
8cb9b9fb
EP
917 return IRQ_NONE;
918 }
919
920 async = subdevice->async;
921
5f74ea14 922 spin_lock_irqsave(&dev->spinlock, irq_flags);
8cb9b9fb 923
52f8ac98 924 /* Check if we are source of interrupt */
8cb9b9fb 925 intcsr = inb(dev_private->lcr_io_base +
0a85b6f0 926 PLX9050_REGISTER_INTERRUPT_CONTROL);
8cb9b9fb 927 if (!(((intcsr & PLX9050_PCI_INTERRUPT_ENABLE) != 0)
0a85b6f0
MT
928 && (((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS))
929 == (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS))
930 || ((intcsr & (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS))
931 == (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS))))) {
52f8ac98
BP
932 /* Not the source of the interrupt. */
933 /* (N.B. not using PLX9050_SOFTWARE_INTERRUPT) */
5f74ea14 934 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
8cb9b9fb
EP
935 return IRQ_NONE;
936 }
937
938 if ((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) ==
0a85b6f0 939 (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) {
52f8ac98 940 /* Interrupt comes from fifo_half-full signal */
8cb9b9fb
EP
941
942 if (pci9111_is_fifo_full()) {
0a85b6f0 943 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
8cb9b9fb
EP
944 comedi_error(dev, PCI9111_DRIVER_NAME " fifo overflow");
945 pci9111_interrupt_clear();
946 pci9111_ai_cancel(dev, subdevice);
947 async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
948 comedi_event(dev, subdevice);
949
950 return IRQ_HANDLED;
951 }
952
953 if (pci9111_is_fifo_half_full()) {
954 unsigned int num_samples;
955 unsigned int bytes_written = 0;
956
957#ifdef INTERRUPT_DEBUG
958 printk(PCI9111_DRIVER_NAME ": fifo is half full\n");
959#endif
960
961 num_samples =
0a85b6f0
MT
962 PCI9111_FIFO_HALF_SIZE >
963 dev_private->stop_counter
964 && !dev_private->
965 stop_is_none ? dev_private->stop_counter :
966 PCI9111_FIFO_HALF_SIZE;
8cb9b9fb 967 insw(PCI9111_IO_BASE + PCI9111_REGISTER_AD_FIFO_VALUE,
0a85b6f0 968 dev_private->ai_bounce_buffer, num_samples);
8cb9b9fb
EP
969
970 if (dev_private->scan_delay < 1) {
971 bytes_written =
0a85b6f0
MT
972 cfc_write_array_to_buffer(subdevice,
973 dev_private->
974 ai_bounce_buffer,
975 num_samples *
976 sizeof(short));
8cb9b9fb
EP
977 } else {
978 int position = 0;
979 int to_read;
980
981 while (position < num_samples) {
982 if (dev_private->chunk_counter <
0a85b6f0 983 dev_private->chanlist_len) {
8cb9b9fb 984 to_read =
0a85b6f0
MT
985 dev_private->chanlist_len -
986 dev_private->chunk_counter;
8cb9b9fb
EP
987
988 if (to_read >
0a85b6f0 989 num_samples - position)
8cb9b9fb 990 to_read =
0a85b6f0
MT
991 num_samples -
992 position;
8cb9b9fb
EP
993
994 bytes_written +=
0a85b6f0
MT
995 cfc_write_array_to_buffer
996 (subdevice,
997 dev_private->ai_bounce_buffer
998 + position,
999 to_read * sizeof(short));
8cb9b9fb
EP
1000 } else {
1001 to_read =
0a85b6f0
MT
1002 dev_private->chunk_num_samples
1003 -
1004 dev_private->chunk_counter;
8cb9b9fb 1005 if (to_read >
0a85b6f0 1006 num_samples - position)
8cb9b9fb 1007 to_read =
0a85b6f0
MT
1008 num_samples -
1009 position;
8cb9b9fb
EP
1010
1011 bytes_written +=
0a85b6f0 1012 sizeof(short) * to_read;
8cb9b9fb
EP
1013 }
1014
1015 position += to_read;
1016 dev_private->chunk_counter += to_read;
1017
1018 if (dev_private->chunk_counter >=
0a85b6f0 1019 dev_private->chunk_num_samples)
8cb9b9fb
EP
1020 dev_private->chunk_counter = 0;
1021 }
1022 }
1023
1024 dev_private->stop_counter -=
0a85b6f0 1025 bytes_written / sizeof(short);
8cb9b9fb
EP
1026 }
1027 }
1028
1029 if ((dev_private->stop_counter == 0) && (!dev_private->stop_is_none)) {
1030 async->events |= COMEDI_CB_EOA;
1031 pci9111_ai_cancel(dev, subdevice);
1032 }
1033
1034 /* Very important, otherwise another interrupt request will be inserted
1035 * and will cause driver hangs on processing interrupt event. */
1036
1037 pci9111_interrupt_clear();
1038
5f74ea14 1039 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
8cb9b9fb
EP
1040
1041 comedi_event(dev, subdevice);
1042
1043 return IRQ_HANDLED;
1044}
1045
52f8ac98
BP
1046/* ------------------------------------------------------------------ */
1047/* INSTANT ANALOG INPUT OUTPUT SECTION */
1048/* ------------------------------------------------------------------ */
8cb9b9fb 1049
52f8ac98 1050/* analog instant input */
8cb9b9fb
EP
1051
1052#undef AI_INSN_DEBUG
1053
da91b269 1054static int pci9111_ai_insn_read(struct comedi_device *dev,
0a85b6f0
MT
1055 struct comedi_subdevice *subdevice,
1056 struct comedi_insn *insn, unsigned int *data)
8cb9b9fb
EP
1057{
1058 int resolution =
0a85b6f0 1059 ((struct pci9111_board *)dev->board_ptr)->ai_resolution;
8cb9b9fb
EP
1060
1061 int timeout, i;
1062
1063#ifdef AI_INSN_DEBUG
1064 printk(PCI9111_DRIVER_NAME ": ai_insn set c/r/n = %2x/%2x/%2x\n",
0a85b6f0
MT
1065 CR_CHAN((&insn->chanspec)[0]),
1066 CR_RANGE((&insn->chanspec)[0]), insn->n);
8cb9b9fb
EP
1067#endif
1068
1069 pci9111_ai_channel_set(CR_CHAN((&insn->chanspec)[0]));
1070
2306d9b1 1071 if ((pci9111_ai_range_get()) != CR_RANGE((&insn->chanspec)[0]))
8cb9b9fb 1072 pci9111_ai_range_set(CR_RANGE((&insn->chanspec)[0]));
8cb9b9fb
EP
1073
1074 pci9111_fifo_reset();
1075
1076 for (i = 0; i < insn->n; i++) {
1077 pci9111_software_trigger();
1078
1079 timeout = PCI9111_AI_INSTANT_READ_TIMEOUT;
1080
1081 while (timeout--) {
1082 if (!pci9111_is_fifo_empty())
1083 goto conversion_done;
1084 }
1085
1086 comedi_error(dev, "A/D read timeout");
1087 data[i] = 0;
1088 pci9111_fifo_reset();
1089 return -ETIME;
1090
0a85b6f0 1091conversion_done:
8cb9b9fb 1092
2306d9b1 1093 if (resolution == PCI9111_HR_AI_RESOLUTION)
8cb9b9fb 1094 data[i] = pci9111_hr_ai_get_data();
2306d9b1 1095 else
8cb9b9fb 1096 data[i] = pci9111_ai_get_data();
8cb9b9fb
EP
1097 }
1098
1099#ifdef AI_INSN_DEBUG
1100 printk(PCI9111_DRIVER_NAME ": ai_insn get c/r/t = %2x/%2x/%2x\n",
0a85b6f0
MT
1101 pci9111_ai_channel_get(),
1102 pci9111_ai_range_get(), pci9111_trigger_and_autoscan_get());
8cb9b9fb
EP
1103#endif
1104
1105 return i;
1106}
1107
52f8ac98 1108/* Analog instant output */
8cb9b9fb
EP
1109
1110static int
da91b269 1111pci9111_ao_insn_write(struct comedi_device *dev,
0a85b6f0
MT
1112 struct comedi_subdevice *s, struct comedi_insn *insn,
1113 unsigned int *data)
8cb9b9fb
EP
1114{
1115 int i;
1116
1117 for (i = 0; i < insn->n; i++) {
1118 pci9111_ao_set_data(data[i]);
1119 dev_private->ao_readback = data[i];
1120 }
1121
1122 return i;
1123}
1124
52f8ac98 1125/* Analog output readback */
8cb9b9fb 1126
da91b269 1127static int pci9111_ao_insn_read(struct comedi_device *dev,
0a85b6f0
MT
1128 struct comedi_subdevice *s,
1129 struct comedi_insn *insn, unsigned int *data)
8cb9b9fb
EP
1130{
1131 int i;
1132
2306d9b1 1133 for (i = 0; i < insn->n; i++)
8cb9b9fb 1134 data[i] = dev_private->ao_readback & PCI9111_AO_RESOLUTION_MASK;
8cb9b9fb
EP
1135
1136 return i;
1137}
1138
52f8ac98
BP
1139/* ------------------------------------------------------------------ */
1140/* DIGITAL INPUT OUTPUT SECTION */
1141/* ------------------------------------------------------------------ */
8cb9b9fb 1142
52f8ac98 1143/* Digital inputs */
8cb9b9fb 1144
da91b269 1145static int pci9111_di_insn_bits(struct comedi_device *dev,
0a85b6f0
MT
1146 struct comedi_subdevice *subdevice,
1147 struct comedi_insn *insn, unsigned int *data)
8cb9b9fb 1148{
790c5541 1149 unsigned int bits;
8cb9b9fb
EP
1150
1151 bits = pci9111_di_get_bits();
1152 data[1] = bits;
1153
1154 return 2;
1155}
1156
52f8ac98 1157/* Digital outputs */
8cb9b9fb 1158
da91b269 1159static int pci9111_do_insn_bits(struct comedi_device *dev,
0a85b6f0
MT
1160 struct comedi_subdevice *subdevice,
1161 struct comedi_insn *insn, unsigned int *data)
8cb9b9fb 1162{
790c5541 1163 unsigned int bits;
8cb9b9fb 1164
52f8ac98
BP
1165 /* Only set bits that have been masked */
1166 /* data[0] = mask */
1167 /* data[1] = bit state */
8cb9b9fb
EP
1168
1169 data[0] &= PCI9111_DO_MASK;
1170
1171 bits = subdevice->state;
1172 bits &= ~data[0];
1173 bits |= data[0] & data[1];
1174 subdevice->state = bits;
1175
1176 pci9111_do_set_bits(bits);
1177
1178 data[1] = bits;
1179
1180 return 2;
1181}
1182
52f8ac98
BP
1183/* ------------------------------------------------------------------ */
1184/* INITIALISATION SECTION */
1185/* ------------------------------------------------------------------ */
8cb9b9fb 1186
52f8ac98 1187/* Reset device */
8cb9b9fb 1188
da91b269 1189static int pci9111_reset(struct comedi_device *dev)
8cb9b9fb 1190{
52f8ac98 1191 /* Set trigger source to software */
8cb9b9fb
EP
1192
1193 plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true,
0a85b6f0 1194 true, false);
8cb9b9fb
EP
1195
1196 pci9111_trigger_source_set(dev, software);
1197 pci9111_pretrigger_set(dev, false);
1198 pci9111_autoscan_set(dev, false);
1199
52f8ac98 1200 /* Reset 8254 chip */
8cb9b9fb
EP
1201
1202 dev_private->timer_divisor_1 = 0;
1203 dev_private->timer_divisor_2 = 0;
1204
1205 pci9111_timer_set(dev);
1206
1207 return 0;
1208}
1209
52f8ac98
BP
1210/* Attach */
1211/* - Register PCI device */
1212/* - Declare device driver capability */
8cb9b9fb 1213
0a85b6f0
MT
1214static int pci9111_attach(struct comedi_device *dev,
1215 struct comedi_devconfig *it)
8cb9b9fb 1216{
34c43922 1217 struct comedi_subdevice *subdevice;
8cb9b9fb
EP
1218 unsigned long io_base, io_range, lcr_io_base, lcr_io_range;
1219 struct pci_dev *pci_device;
1220 int error, i;
940579fb 1221 const struct pci9111_board *board;
8cb9b9fb 1222
2306d9b1 1223 if (alloc_private(dev, sizeof(struct pci9111_private_data)) < 0)
8cb9b9fb 1224 return -ENOMEM;
52f8ac98 1225 /* Probe the device to determine what device in the series it is. */
8cb9b9fb
EP
1226
1227 printk("comedi%d: " PCI9111_DRIVER_NAME " driver\n", dev->minor);
1228
1229 for (pci_device = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
0a85b6f0
MT
1230 pci_device != NULL;
1231 pci_device = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_device)) {
8cb9b9fb
EP
1232 if (pci_device->vendor == PCI_VENDOR_ID_ADLINK) {
1233 for (i = 0; i < pci9111_board_nbr; i++) {
1234 if (pci9111_boards[i].device_id ==
0a85b6f0 1235 pci_device->device) {
52f8ac98 1236 /* was a particular bus/slot requested? */
8cb9b9fb 1237 if ((it->options[0] != 0)
0a85b6f0 1238 || (it->options[1] != 0)) {
52f8ac98 1239 /* are we on the wrong bus/slot? */
8cb9b9fb 1240 if (pci_device->bus->number !=
0a85b6f0
MT
1241 it->options[0]
1242 ||
1243 PCI_SLOT(pci_device->devfn)
1244 != it->options[1]) {
8cb9b9fb
EP
1245 continue;
1246 }
1247 }
1248
1249 dev->board_ptr = pci9111_boards + i;
0a85b6f0
MT
1250 board =
1251 (struct pci9111_board *)
1252 dev->board_ptr;
8cb9b9fb
EP
1253 dev_private->pci_device = pci_device;
1254 goto found;
1255 }
1256 }
1257 }
1258 }
1259
1260 printk("comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
0a85b6f0 1261 dev->minor, it->options[0], it->options[1]);
8cb9b9fb
EP
1262 return -EIO;
1263
0a85b6f0 1264found:
8cb9b9fb
EP
1265
1266 printk("comedi%d: found %s (b:s:f=%d:%d:%d) , irq=%d\n",
0a85b6f0
MT
1267 dev->minor,
1268 pci9111_boards[i].name,
1269 pci_device->bus->number,
1270 PCI_SLOT(pci_device->devfn),
1271 PCI_FUNC(pci_device->devfn), pci_device->irq);
8cb9b9fb 1272
52f8ac98 1273 /* TODO: Warn about non-tested boards. */
8cb9b9fb 1274
52f8ac98 1275 /* Read local configuration register base address [PCI_BASE_ADDRESS #1]. */
8cb9b9fb
EP
1276
1277 lcr_io_base = pci_resource_start(pci_device, 1);
1278 lcr_io_range = pci_resource_len(pci_device, 1);
1279
0a85b6f0
MT
1280 printk
1281 ("comedi%d: local configuration registers at address 0x%4lx [0x%4lx]\n",
1282 dev->minor, lcr_io_base, lcr_io_range);
8cb9b9fb 1283
52f8ac98 1284 /* Enable PCI device and request regions */
8cb9b9fb 1285 if (comedi_pci_enable(pci_device, PCI9111_DRIVER_NAME) < 0) {
0a85b6f0
MT
1286 printk
1287 ("comedi%d: Failed to enable PCI device and request regions\n",
1288 dev->minor);
8cb9b9fb
EP
1289 return -EIO;
1290 }
52f8ac98 1291 /* Read PCI6308 register base address [PCI_BASE_ADDRESS #2]. */
8cb9b9fb
EP
1292
1293 io_base = pci_resource_start(pci_device, 2);
1294 io_range = pci_resource_len(pci_device, 2);
1295
1296 printk("comedi%d: 6503 registers at address 0x%4lx [0x%4lx]\n",
0a85b6f0 1297 dev->minor, io_base, io_range);
8cb9b9fb
EP
1298
1299 dev->iobase = io_base;
1300 dev->board_name = board->name;
1301 dev_private->io_range = io_range;
1302 dev_private->is_valid = 0;
1303 dev_private->lcr_io_base = lcr_io_base;
1304 dev_private->lcr_io_range = lcr_io_range;
1305
1306 pci9111_reset(dev);
1307
52f8ac98 1308 /* Irq setup */
8cb9b9fb
EP
1309
1310 dev->irq = 0;
1311 if (pci_device->irq > 0) {
5f74ea14 1312 if (request_irq(pci_device->irq, pci9111_interrupt,
8cb9b9fb
EP
1313 IRQF_SHARED, PCI9111_DRIVER_NAME, dev) != 0) {
1314 printk("comedi%d: unable to allocate irq %u\n",
0a85b6f0 1315 dev->minor, pci_device->irq);
8cb9b9fb
EP
1316 return -EINVAL;
1317 }
1318 }
1319 dev->irq = pci_device->irq;
1320
52f8ac98 1321 /* TODO: Add external multiplexer setup (according to option[2]). */
8cb9b9fb 1322
c3744138
BP
1323 error = alloc_subdevices(dev, 4);
1324 if (error < 0)
8cb9b9fb
EP
1325 return error;
1326
1327 subdevice = dev->subdevices + 0;
1328 dev->read_subdev = subdevice;
1329
1330 subdevice->type = COMEDI_SUBD_AI;
1331 subdevice->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_CMD_READ;
1332
52f8ac98
BP
1333 /* TODO: Add external multiplexer data */
1334 /* if (devpriv->usemux) { subdevice->n_chan = devpriv->usemux; } */
1335 /* else { subdevice->n_chan = this_board->n_aichan; } */
8cb9b9fb
EP
1336
1337 subdevice->n_chan = board->ai_channel_nbr;
1338 subdevice->maxdata = board->ai_resolution_mask;
1339 subdevice->len_chanlist = board->ai_channel_nbr;
1340 subdevice->range_table = board->ai_range_list;
1341 subdevice->cancel = pci9111_ai_cancel;
1342 subdevice->insn_read = pci9111_ai_insn_read;
1343 subdevice->do_cmdtest = pci9111_ai_do_cmd_test;
1344 subdevice->do_cmd = pci9111_ai_do_cmd;
1345 subdevice->munge = pci9111_ai_munge;
1346
1347 subdevice = dev->subdevices + 1;
1348 subdevice->type = COMEDI_SUBD_AO;
1349 subdevice->subdev_flags = SDF_WRITABLE | SDF_COMMON;
1350 subdevice->n_chan = board->ao_channel_nbr;
1351 subdevice->maxdata = board->ao_resolution_mask;
1352 subdevice->len_chanlist = board->ao_channel_nbr;
1353 subdevice->range_table = board->ao_range_list;
1354 subdevice->insn_write = pci9111_ao_insn_write;
1355 subdevice->insn_read = pci9111_ao_insn_read;
1356
1357 subdevice = dev->subdevices + 2;
1358 subdevice->type = COMEDI_SUBD_DI;
1359 subdevice->subdev_flags = SDF_READABLE;
1360 subdevice->n_chan = PCI9111_DI_CHANNEL_NBR;
1361 subdevice->maxdata = 1;
1362 subdevice->range_table = &range_digital;
1363 subdevice->insn_bits = pci9111_di_insn_bits;
1364
1365 subdevice = dev->subdevices + 3;
1366 subdevice->type = COMEDI_SUBD_DO;
1367 subdevice->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1368 subdevice->n_chan = PCI9111_DO_CHANNEL_NBR;
1369 subdevice->maxdata = 1;
1370 subdevice->range_table = &range_digital;
1371 subdevice->insn_bits = pci9111_do_insn_bits;
1372
1373 dev_private->is_valid = 1;
1374
1375 return 0;
1376}
1377
52f8ac98 1378/* Detach */
8cb9b9fb 1379
da91b269 1380static int pci9111_detach(struct comedi_device *dev)
8cb9b9fb 1381{
52f8ac98 1382 /* Reset device */
8cb9b9fb 1383
525d1b13 1384 if (dev->private != NULL) {
8cb9b9fb
EP
1385 if (dev_private->is_valid)
1386 pci9111_reset(dev);
1387
1388 }
52f8ac98 1389 /* Release previously allocated irq */
8cb9b9fb 1390
2306d9b1 1391 if (dev->irq != 0)
5f74ea14 1392 free_irq(dev->irq, dev);
8cb9b9fb 1393
525d1b13 1394 if (dev_private != NULL && dev_private->pci_device != NULL) {
2306d9b1 1395 if (dev->iobase)
8cb9b9fb 1396 comedi_pci_disable(dev_private->pci_device);
8cb9b9fb
EP
1397 pci_dev_put(dev_private->pci_device);
1398 }
1399
1400 return 0;
1401}