addi_apci_3xxx.c revision 93c0dc284dff2e2fec320662d8ef01b933096e36
1#include <linux/pci.h>
2
3#include "../comedidev.h"
4#include "comedi_fc.h"
5#include "amcc_s5933.h"
6
7#include "addi-data/addi_common.h"
8
9#include "addi-data/hwdrv_apci3xxx.c"
10
11#ifndef COMEDI_SUBD_TTLIO
12#define COMEDI_SUBD_TTLIO   11	/* Digital Input Output But TTL */
13#endif
14
15static const struct comedi_lrange apci3xxx_ai_range = {
16	8, {
17		BIP_RANGE(10),
18		BIP_RANGE(5),
19		BIP_RANGE(2),
20		BIP_RANGE(1),
21		UNI_RANGE(10),
22		UNI_RANGE(5),
23		UNI_RANGE(2),
24		UNI_RANGE(1)
25	}
26};
27
28static const struct comedi_lrange apci3xxx_ao_range = {
29	2, {
30		BIP_RANGE(10),
31		UNI_RANGE(10)
32	}
33};
34
35enum apci3xxx_boardid {
36	BOARD_APCI3000_16,
37	BOARD_APCI3000_8,
38	BOARD_APCI3000_4,
39	BOARD_APCI3006_16,
40	BOARD_APCI3006_8,
41	BOARD_APCI3006_4,
42	BOARD_APCI3010_16,
43	BOARD_APCI3010_8,
44	BOARD_APCI3010_4,
45	BOARD_APCI3016_16,
46	BOARD_APCI3016_8,
47	BOARD_APCI3016_4,
48	BOARD_APCI3100_16_4,
49	BOARD_APCI3100_8_4,
50	BOARD_APCI3106_16_4,
51	BOARD_APCI3106_8_4,
52	BOARD_APCI3110_16_4,
53	BOARD_APCI3110_8_4,
54	BOARD_APCI3116_16_4,
55	BOARD_APCI3116_8_4,
56	BOARD_APCI3003,
57	BOARD_APCI3002_16,
58	BOARD_APCI3002_8,
59	BOARD_APCI3002_4,
60	BOARD_APCI3500,
61};
62
63static const struct addi_board apci3xxx_boardtypes[] = {
64	[BOARD_APCI3000_16] = {
65		.pc_DriverName		= "apci3000-16",
66		.i_IorangeBase1		= 256,
67		.i_NbrAiChannel		= 16,
68		.i_NbrAiChannelDiff	= 8,
69		.i_AiChannelList	= 16,
70		.i_AiMaxdata		= 4095,
71		.i_NbrTTLChannel	= 24,
72		.b_AvailableConvertUnit	= 6,
73		.ui_MinAcquisitiontimeNs = 10000,
74		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
75		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
76		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
77		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
78		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
79		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
80	},
81	[BOARD_APCI3000_8] = {
82		.pc_DriverName		= "apci3000-8",
83		.i_IorangeBase1		= 256,
84		.i_NbrAiChannel		= 8,
85		.i_NbrAiChannelDiff	= 4,
86		.i_AiChannelList	= 8,
87		.i_AiMaxdata		= 4095,
88		.i_NbrTTLChannel	= 24,
89		.b_AvailableConvertUnit	= 6,
90		.ui_MinAcquisitiontimeNs = 10000,
91		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
92		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
93		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
94		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
95		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
96		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
97	},
98	[BOARD_APCI3000_4] = {
99		.pc_DriverName		= "apci3000-4",
100		.i_IorangeBase1		= 256,
101		.i_NbrAiChannel		= 4,
102		.i_NbrAiChannelDiff	= 2,
103		.i_AiChannelList	= 4,
104		.i_AiMaxdata		= 4095,
105		.i_NbrTTLChannel	= 24,
106		.b_AvailableConvertUnit	= 6,
107		.ui_MinAcquisitiontimeNs = 10000,
108		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
109		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
110		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
111		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
112		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
113		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
114	},
115	[BOARD_APCI3006_16] = {
116		.pc_DriverName		= "apci3006-16",
117		.i_IorangeBase1		= 256,
118		.i_NbrAiChannel		= 16,
119		.i_NbrAiChannelDiff	= 8,
120		.i_AiChannelList	= 16,
121		.i_AiMaxdata		= 65535,
122		.i_NbrTTLChannel	= 24,
123		.b_AvailableConvertUnit	= 6,
124		.ui_MinAcquisitiontimeNs = 10000,
125		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
126		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
127		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
128		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
129		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
130		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
131	},
132	[BOARD_APCI3006_8] = {
133		.pc_DriverName		= "apci3006-8",
134		.i_IorangeBase1		= 256,
135		.i_NbrAiChannel		= 8,
136		.i_NbrAiChannelDiff	= 4,
137		.i_AiChannelList	= 8,
138		.i_AiMaxdata		= 65535,
139		.i_NbrTTLChannel	= 24,
140		.b_AvailableConvertUnit	= 6,
141		.ui_MinAcquisitiontimeNs = 10000,
142		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
143		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
144		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
145		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
146		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
147		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
148	},
149	[BOARD_APCI3006_4] = {
150		.pc_DriverName		= "apci3006-4",
151		.i_IorangeBase1		= 256,
152		.i_NbrAiChannel		= 4,
153		.i_NbrAiChannelDiff	= 2,
154		.i_AiChannelList	= 4,
155		.i_AiMaxdata		= 65535,
156		.i_NbrTTLChannel	= 24,
157		.b_AvailableConvertUnit	= 6,
158		.ui_MinAcquisitiontimeNs = 10000,
159		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
160		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
161		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
162		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
163		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
164		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
165	},
166	[BOARD_APCI3010_16] = {
167		.pc_DriverName		= "apci3010-16",
168		.i_IorangeBase1		= 256,
169		.i_NbrAiChannel		= 16,
170		.i_NbrAiChannelDiff	= 8,
171		.i_AiChannelList	= 16,
172		.i_AiMaxdata		= 4095,
173		.i_NbrDiChannel		= 4,
174		.i_NbrDoChannel		= 4,
175		.i_DoMaxdata		= 1,
176		.i_NbrTTLChannel	= 24,
177		.b_AvailableConvertUnit	= 6,
178		.ui_MinAcquisitiontimeNs = 5000,
179		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
180		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
181		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
182		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
183		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
184		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
185	},
186	[BOARD_APCI3010_8] = {
187		.pc_DriverName		= "apci3010-8",
188		.i_IorangeBase1		= 256,
189		.i_NbrAiChannel		= 8,
190		.i_NbrAiChannelDiff	= 4,
191		.i_AiChannelList	= 8,
192		.i_AiMaxdata		= 4095,
193		.i_NbrDiChannel		= 4,
194		.i_NbrDoChannel		= 4,
195		.i_DoMaxdata		= 1,
196		.i_NbrTTLChannel	= 24,
197		.b_AvailableConvertUnit	= 6,
198		.ui_MinAcquisitiontimeNs = 5000,
199		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
200		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
201		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
202		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
203		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
204		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
205	},
206	[BOARD_APCI3010_4] = {
207		.pc_DriverName		= "apci3010-4",
208		.i_IorangeBase1		= 256,
209		.i_NbrAiChannel		= 4,
210		.i_NbrAiChannelDiff	= 2,
211		.i_AiChannelList	= 4,
212		.i_AiMaxdata		= 4095,
213		.i_NbrDiChannel		= 4,
214		.i_NbrDoChannel		= 4,
215		.i_DoMaxdata		= 1,
216		.i_NbrTTLChannel	= 24,
217		.b_AvailableConvertUnit	= 6,
218		.ui_MinAcquisitiontimeNs = 5000,
219		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
220		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
221		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
222		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
223		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
224		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
225	},
226	[BOARD_APCI3016_16] = {
227		.pc_DriverName		= "apci3016-16",
228		.i_IorangeBase1		= 256,
229		.i_NbrAiChannel		= 16,
230		.i_NbrAiChannelDiff	= 8,
231		.i_AiChannelList	= 16,
232		.i_AiMaxdata		= 65535,
233		.i_NbrDiChannel		= 4,
234		.i_NbrDoChannel		= 4,
235		.i_DoMaxdata		= 1,
236		.i_NbrTTLChannel	= 24,
237		.b_AvailableConvertUnit	= 6,
238		.ui_MinAcquisitiontimeNs = 5000,
239		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
240		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
241		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
242		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
243		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
244		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
245	},
246	[BOARD_APCI3016_8] = {
247		.pc_DriverName		= "apci3016-8",
248		.i_IorangeBase1		= 256,
249		.i_NbrAiChannel		= 8,
250		.i_NbrAiChannelDiff	= 4,
251		.i_AiChannelList	= 8,
252		.i_AiMaxdata		= 65535,
253		.i_NbrDiChannel		= 4,
254		.i_NbrDoChannel		= 4,
255		.i_DoMaxdata		= 1,
256		.i_NbrTTLChannel	= 24,
257		.b_AvailableConvertUnit	= 6,
258		.ui_MinAcquisitiontimeNs = 5000,
259		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
260		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
261		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
262		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
263		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
264		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
265	},
266	[BOARD_APCI3016_4] = {
267		.pc_DriverName		= "apci3016-4",
268		.i_IorangeBase1		= 256,
269		.i_NbrAiChannel		= 4,
270		.i_NbrAiChannelDiff	= 2,
271		.i_AiChannelList	= 4,
272		.i_AiMaxdata		= 65535,
273		.i_NbrDiChannel		= 4,
274		.i_NbrDoChannel		= 4,
275		.i_DoMaxdata		= 1,
276		.i_NbrTTLChannel	= 24,
277		.b_AvailableConvertUnit	= 6,
278		.ui_MinAcquisitiontimeNs = 5000,
279		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
280		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
281		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
282		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
283		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
284		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
285	},
286	[BOARD_APCI3100_16_4] = {
287		.pc_DriverName		= "apci3100-16-4",
288		.i_IorangeBase1		= 256,
289		.i_NbrAiChannel		= 16,
290		.i_NbrAiChannelDiff	= 8,
291		.i_AiChannelList	= 16,
292		.i_NbrAoChannel		= 4,
293		.i_AiMaxdata		= 4095,
294		.i_AoMaxdata		= 4095,
295		.i_NbrTTLChannel	= 24,
296		.b_AvailableConvertUnit	= 6,
297		.ui_MinAcquisitiontimeNs = 10000,
298		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
299		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
300		.ao_write		= i_APCI3XXX_InsnWriteAnalogOutput,
301		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
302		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
303		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
304		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
305	},
306	[BOARD_APCI3100_8_4] = {
307		.pc_DriverName		= "apci3100-8-4",
308		.i_IorangeBase1		= 256,
309		.i_NbrAiChannel		= 8,
310		.i_NbrAiChannelDiff	= 4,
311		.i_AiChannelList	= 8,
312		.i_NbrAoChannel		= 4,
313		.i_AiMaxdata		= 4095,
314		.i_AoMaxdata		= 4095,
315		.i_NbrTTLChannel	= 24,
316		.b_AvailableConvertUnit	= 6,
317		.ui_MinAcquisitiontimeNs = 10000,
318		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
319		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
320		.ao_write		= i_APCI3XXX_InsnWriteAnalogOutput,
321		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
322		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
323		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
324		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
325	},
326	[BOARD_APCI3106_16_4] = {
327		.pc_DriverName		= "apci3106-16-4",
328		.i_IorangeBase1		= 256,
329		.i_NbrAiChannel		= 16,
330		.i_NbrAiChannelDiff	= 8,
331		.i_AiChannelList	= 16,
332		.i_NbrAoChannel		= 4,
333		.i_AiMaxdata		= 65535,
334		.i_AoMaxdata		= 4095,
335		.i_NbrTTLChannel	= 24,
336		.b_AvailableConvertUnit	= 6,
337		.ui_MinAcquisitiontimeNs = 10000,
338		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
339		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
340		.ao_write		= i_APCI3XXX_InsnWriteAnalogOutput,
341		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
342		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
343		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
344		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
345	},
346	[BOARD_APCI3106_8_4] = {
347		.pc_DriverName		= "apci3106-8-4",
348		.i_IorangeBase1		= 256,
349		.i_NbrAiChannel		= 8,
350		.i_NbrAiChannelDiff	= 4,
351		.i_AiChannelList	= 8,
352		.i_NbrAoChannel		= 4,
353		.i_AiMaxdata		= 65535,
354		.i_AoMaxdata		= 4095,
355		.i_NbrTTLChannel	= 24,
356		.b_AvailableConvertUnit	= 6,
357		.ui_MinAcquisitiontimeNs = 10000,
358		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
359		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
360		.ao_write		= i_APCI3XXX_InsnWriteAnalogOutput,
361		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
362		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
363		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
364		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
365	},
366	[BOARD_APCI3110_16_4] = {
367		.pc_DriverName		= "apci3110-16-4",
368		.i_IorangeBase1		= 256,
369		.i_NbrAiChannel		= 16,
370		.i_NbrAiChannelDiff	= 8,
371		.i_AiChannelList	= 16,
372		.i_NbrAoChannel		= 4,
373		.i_AiMaxdata		= 4095,
374		.i_AoMaxdata		= 4095,
375		.i_NbrDiChannel		= 4,
376		.i_NbrDoChannel		= 4,
377		.i_DoMaxdata		= 1,
378		.i_NbrTTLChannel	= 24,
379		.b_AvailableConvertUnit	= 6,
380		.ui_MinAcquisitiontimeNs = 5000,
381		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
382		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
383		.ao_write		= i_APCI3XXX_InsnWriteAnalogOutput,
384		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
385		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
386		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
387		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
388	},
389	[BOARD_APCI3110_8_4] = {
390		.pc_DriverName		= "apci3110-8-4",
391		.i_IorangeBase1		= 256,
392		.i_NbrAiChannel		= 8,
393		.i_NbrAiChannelDiff	= 4,
394		.i_AiChannelList	= 8,
395		.i_NbrAoChannel		= 4,
396		.i_AiMaxdata		= 4095,
397		.i_AoMaxdata		= 4095,
398		.i_NbrDiChannel		= 4,
399		.i_NbrDoChannel		= 4,
400		.i_DoMaxdata		= 1,
401		.i_NbrTTLChannel	= 24,
402		.b_AvailableConvertUnit	= 6,
403		.ui_MinAcquisitiontimeNs = 5000,
404		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
405		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
406		.ao_write		= i_APCI3XXX_InsnWriteAnalogOutput,
407		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
408		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
409		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
410		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
411	},
412	[BOARD_APCI3116_16_4] = {
413		.pc_DriverName		= "apci3116-16-4",
414		.i_IorangeBase1		= 256,
415		.i_NbrAiChannel		= 16,
416		.i_NbrAiChannelDiff	= 8,
417		.i_AiChannelList	= 16,
418		.i_NbrAoChannel		= 4,
419		.i_AiMaxdata		= 65535,
420		.i_AoMaxdata		= 4095,
421		.i_NbrDiChannel		= 4,
422		.i_NbrDoChannel		= 4,
423		.i_DoMaxdata		= 1,
424		.i_NbrTTLChannel	= 24,
425		.b_AvailableConvertUnit	= 6,
426		.ui_MinAcquisitiontimeNs = 5000,
427		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
428		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
429		.ao_write		= i_APCI3XXX_InsnWriteAnalogOutput,
430		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
431		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
432		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
433		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
434	},
435	[BOARD_APCI3116_8_4] = {
436		.pc_DriverName		= "apci3116-8-4",
437		.i_IorangeBase1		= 256,
438		.i_NbrAiChannel		= 8,
439		.i_NbrAiChannelDiff	= 4,
440		.i_AiChannelList	= 8,
441		.i_NbrAoChannel		= 4,
442		.i_AiMaxdata		= 65535,
443		.i_AoMaxdata		= 4095,
444		.i_NbrDiChannel		= 4,
445		.i_NbrDoChannel		= 4,
446		.i_DoMaxdata		= 1,
447		.i_NbrTTLChannel	= 24,
448		.b_AvailableConvertUnit	= 6,
449		.ui_MinAcquisitiontimeNs = 5000,
450		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
451		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
452		.ao_write		= i_APCI3XXX_InsnWriteAnalogOutput,
453		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
454		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
455		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
456		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
457	},
458	[BOARD_APCI3003] = {
459		.pc_DriverName		= "apci3003",
460		.i_IorangeBase1		= 256,
461		.i_NbrAiChannelDiff	= 4,
462		.i_AiChannelList	= 4,
463		.i_AiMaxdata		= 65535,
464		.i_NbrDiChannel		= 4,
465		.i_NbrDoChannel		= 4,
466		.i_DoMaxdata		= 1,
467		.b_AvailableConvertUnit	= 7,
468		.ui_MinAcquisitiontimeNs = 2500,
469		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
470		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
471	},
472	[BOARD_APCI3002_16] = {
473		.pc_DriverName		= "apci3002-16",
474		.i_IorangeBase1		= 256,
475		.i_NbrAiChannelDiff	= 16,
476		.i_AiChannelList	= 16,
477		.i_AiMaxdata		= 65535,
478		.i_NbrDiChannel		= 4,
479		.i_NbrDoChannel		= 4,
480		.i_DoMaxdata		= 1,
481		.b_AvailableConvertUnit	= 6,
482		.ui_MinAcquisitiontimeNs = 5000,
483		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
484		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
485	},
486	[BOARD_APCI3002_8] = {
487		.pc_DriverName		= "apci3002-8",
488		.i_IorangeBase1		= 256,
489		.i_NbrAiChannelDiff	= 8,
490		.i_AiChannelList	= 8,
491		.i_AiMaxdata		= 65535,
492		.i_NbrDiChannel		= 4,
493		.i_NbrDoChannel		= 4,
494		.i_DoMaxdata		= 1,
495		.b_AvailableConvertUnit	= 6,
496		.ui_MinAcquisitiontimeNs = 5000,
497		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
498		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
499	},
500	[BOARD_APCI3002_4] = {
501		.pc_DriverName		= "apci3002-4",
502		.i_IorangeBase1		= 256,
503		.i_NbrAiChannelDiff	= 4,
504		.i_AiChannelList	= 4,
505		.i_AiMaxdata		= 65535,
506		.i_NbrDiChannel		= 4,
507		.i_NbrDoChannel		= 4,
508		.i_DoMaxdata		= 1,
509		.b_AvailableConvertUnit	= 6,
510		.ui_MinAcquisitiontimeNs = 5000,
511		.ai_config		= i_APCI3XXX_InsnConfigAnalogInput,
512		.ai_read		= i_APCI3XXX_InsnReadAnalogInput,
513	},
514	[BOARD_APCI3500] = {
515		.pc_DriverName		= "apci3500",
516		.i_IorangeBase1		= 256,
517		.i_NbrAoChannel		= 4,
518		.i_AoMaxdata		= 4095,
519		.i_NbrTTLChannel	= 24,
520		.ao_write		= i_APCI3XXX_InsnWriteAnalogOutput,
521		.ttl_config		= i_APCI3XXX_InsnConfigInitTTLIO,
522		.ttl_bits		= i_APCI3XXX_InsnBitsTTLIO,
523		.ttl_read		= i_APCI3XXX_InsnReadTTLIO,
524		.ttl_write		= i_APCI3XXX_InsnWriteTTLIO,
525	},
526};
527
528static irqreturn_t apci3xxx_irq_handler(int irq, void *d)
529{
530	struct comedi_device *dev = d;
531	struct addi_private *devpriv = dev->private;
532	unsigned int status;
533	int i;
534
535	/* Test if interrupt occur */
536	status = readl(devpriv->dw_AiBase + 16);
537	if ((status & 0x2) == 0x2) {
538		/* Reset the interrupt */
539		writel(status, devpriv->dw_AiBase + 16);
540
541		/* Test if interrupt enabled */
542		if (devpriv->b_EocEosInterrupt == 1) {
543			/* Read all analog inputs value */
544			for (i = 0; i < devpriv->ui_AiNbrofChannels; i++) {
545				unsigned int val;
546
547				val = readl(devpriv->dw_AiBase + 28);
548				devpriv->ui_AiReadData[i] = val;
549			}
550
551			/* Set the interrupt flag */
552			devpriv->b_EocEosInterrupt = 2;
553
554			/* Send a signal to from kernel to user space */
555			send_sig(SIGIO, devpriv->tsk_Current, 0);
556		}
557	}
558	return IRQ_RETVAL(1);
559}
560
561static int apci3xxx_di_insn_bits(struct comedi_device *dev,
562				 struct comedi_subdevice *s,
563				 struct comedi_insn *insn,
564				 unsigned int *data)
565{
566	struct addi_private *devpriv = dev->private;
567
568	data[1] = inl(devpriv->iobase + 32) & 0xf;
569
570	return insn->n;
571}
572
573static int apci3xxx_do_insn_bits(struct comedi_device *dev,
574				 struct comedi_subdevice *s,
575				 struct comedi_insn *insn,
576				 unsigned int *data)
577{
578	struct addi_private *devpriv = dev->private;
579	unsigned int mask = data[0];
580	unsigned int bits = data[1];
581
582	s->state = inl(devpriv->iobase + 48) & 0xf;
583	if (mask) {
584		s->state &= ~mask;
585		s->state |= (bits & mask);
586
587		outl(s->state, devpriv->iobase + 48);
588	}
589
590	data[1] = s->state;
591
592	return insn->n;
593}
594
595static int apci3xxx_reset(struct comedi_device *dev)
596{
597	struct addi_private *devpriv = dev->private;
598	unsigned int val;
599	int i;
600
601	/* Disable the interrupt */
602	disable_irq(dev->irq);
603
604	/* Reset the interrupt flag */
605	devpriv->b_EocEosInterrupt = 0;
606
607	/* Clear the start command */
608	writel(0, devpriv->dw_AiBase + 8);
609
610	/* Reset the interrupt flags */
611	val = readl(devpriv->dw_AiBase + 16);
612	writel(val, devpriv->dw_AiBase + 16);
613
614	/* clear the EOS */
615	readl(devpriv->dw_AiBase + 20);
616
617	/* Clear the FIFO */
618	for (i = 0; i < 16; i++)
619		val = readl(devpriv->dw_AiBase + 28);
620
621	/* Enable the interrupt */
622	enable_irq(dev->irq);
623
624	return 0;
625}
626
627static int apci3xxx_auto_attach(struct comedi_device *dev,
628				unsigned long context)
629{
630	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
631	const struct addi_board *board = NULL;
632	struct addi_private *devpriv;
633	struct comedi_subdevice *s;
634	int ret, n_subdevices;
635
636	if (context < ARRAY_SIZE(apci3xxx_boardtypes))
637		board = &apci3xxx_boardtypes[context];
638	if (!board)
639		return -ENODEV;
640	dev->board_ptr = board;
641	dev->board_name = board->pc_DriverName;
642
643	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
644	if (!devpriv)
645		return -ENOMEM;
646	dev->private = devpriv;
647
648	ret = comedi_pci_enable(dev);
649	if (ret)
650		return ret;
651
652	/* board has an ADDIDATA_9054 eeprom */
653	dev->iobase = pci_resource_start(pcidev, 2);
654	devpriv->iobase = pci_resource_start(pcidev, 2);
655	devpriv->dw_AiBase = pci_ioremap_bar(pcidev, 3);
656	devpriv->i_IobaseReserved = pci_resource_start(pcidev, 3);
657
658	/* Initialize parameters that can be overridden in EEPROM */
659	devpriv->s_EeParameters.i_NbrAiChannel = board->i_NbrAiChannel;
660	devpriv->s_EeParameters.i_NbrAoChannel = board->i_NbrAoChannel;
661	devpriv->s_EeParameters.i_AiMaxdata = board->i_AiMaxdata;
662	devpriv->s_EeParameters.i_AoMaxdata = board->i_AoMaxdata;
663	devpriv->s_EeParameters.i_NbrDiChannel = board->i_NbrDiChannel;
664	devpriv->s_EeParameters.i_NbrDoChannel = board->i_NbrDoChannel;
665	devpriv->s_EeParameters.i_DoMaxdata = board->i_DoMaxdata;
666	devpriv->s_EeParameters.ui_MinAcquisitiontimeNs =
667						board->ui_MinAcquisitiontimeNs;
668	devpriv->s_EeParameters.ui_MinDelaytimeNs = board->ui_MinDelaytimeNs;
669
670	/* ## */
671
672	if (pcidev->irq > 0) {
673		ret = request_irq(pcidev->irq, apci3xxx_irq_handler,
674				  IRQF_SHARED, dev->board_name, dev);
675		if (ret == 0)
676			dev->irq = pcidev->irq;
677	}
678
679	n_subdevices = 7;
680	ret = comedi_alloc_subdevices(dev, n_subdevices);
681	if (ret)
682		return ret;
683
684	/*  Allocate and Initialise AI Subdevice Structures */
685	s = &dev->subdevices[0];
686	if (devpriv->s_EeParameters.i_NbrAiChannel ||
687	    board->i_NbrAiChannelDiff) {
688		dev->read_subdev = s;
689		s->type = COMEDI_SUBD_AI;
690		s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND |
691				  SDF_DIFF;
692		if (devpriv->s_EeParameters.i_NbrAiChannel) {
693			s->n_chan = devpriv->s_EeParameters.i_NbrAiChannel;
694			devpriv->b_SingelDiff = 0;
695		} else {
696			s->n_chan = board->i_NbrAiChannelDiff;
697			devpriv->b_SingelDiff = 1;
698		}
699		s->maxdata = devpriv->s_EeParameters.i_AiMaxdata;
700		s->len_chanlist = board->i_AiChannelList;
701		s->range_table = &apci3xxx_ai_range;
702
703		/* Set the initialisation flag */
704		devpriv->b_AiInitialisation = 1;
705
706		s->insn_config = board->ai_config;
707		s->insn_read = board->ai_read;
708		s->insn_write = board->ai_write;
709		s->insn_bits = board->ai_bits;
710		s->do_cmdtest = board->ai_cmdtest;
711		s->do_cmd = board->ai_cmd;
712		s->cancel = board->ai_cancel;
713
714	} else {
715		s->type = COMEDI_SUBD_UNUSED;
716	}
717
718	/*  Allocate and Initialise AO Subdevice Structures */
719	s = &dev->subdevices[1];
720	if (devpriv->s_EeParameters.i_NbrAoChannel) {
721		s->type = COMEDI_SUBD_AO;
722		s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON;
723		s->n_chan = devpriv->s_EeParameters.i_NbrAoChannel;
724		s->maxdata = devpriv->s_EeParameters.i_AoMaxdata;
725		s->len_chanlist = devpriv->s_EeParameters.i_NbrAoChannel;
726		s->range_table = &apci3xxx_ao_range;
727		s->insn_config = board->ao_config;
728		s->insn_write = board->ao_write;
729	} else {
730		s->type = COMEDI_SUBD_UNUSED;
731	}
732	/*  Allocate and Initialise DI Subdevice Structures */
733	s = &dev->subdevices[2];
734	if (devpriv->s_EeParameters.i_NbrDiChannel) {
735		s->type = COMEDI_SUBD_DI;
736		s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
737		s->n_chan = devpriv->s_EeParameters.i_NbrDiChannel;
738		s->maxdata = 1;
739		s->len_chanlist = devpriv->s_EeParameters.i_NbrDiChannel;
740		s->range_table = &range_digital;
741		s->io_bits = 0;	/* all bits input */
742		s->insn_bits = apci3xxx_di_insn_bits;
743	} else {
744		s->type = COMEDI_SUBD_UNUSED;
745	}
746	/*  Allocate and Initialise DO Subdevice Structures */
747	s = &dev->subdevices[3];
748	if (devpriv->s_EeParameters.i_NbrDoChannel) {
749		s->type = COMEDI_SUBD_DO;
750		s->subdev_flags =
751			SDF_READABLE | SDF_WRITEABLE | SDF_GROUND | SDF_COMMON;
752		s->n_chan = devpriv->s_EeParameters.i_NbrDoChannel;
753		s->maxdata = devpriv->s_EeParameters.i_DoMaxdata;
754		s->len_chanlist = devpriv->s_EeParameters.i_NbrDoChannel;
755		s->range_table = &range_digital;
756		s->io_bits = 0xf;	/* all bits output */
757		s->insn_bits = apci3xxx_do_insn_bits;
758	} else {
759		s->type = COMEDI_SUBD_UNUSED;
760	}
761
762	/*  Allocate and Initialise Timer Subdevice Structures */
763	s = &dev->subdevices[4];
764	s->type = COMEDI_SUBD_UNUSED;
765
766	/*  Allocate and Initialise TTL */
767	s = &dev->subdevices[5];
768	if (board->i_NbrTTLChannel) {
769		s->type = COMEDI_SUBD_TTLIO;
770		s->subdev_flags =
771			SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON;
772		s->n_chan = board->i_NbrTTLChannel;
773		s->maxdata = 1;
774		s->io_bits = 0;	/* all bits input */
775		s->len_chanlist = board->i_NbrTTLChannel;
776		s->range_table = &range_digital;
777		s->insn_config = board->ttl_config;
778		s->insn_bits = board->ttl_bits;
779		s->insn_read = board->ttl_read;
780		s->insn_write = board->ttl_write;
781	} else {
782		s->type = COMEDI_SUBD_UNUSED;
783	}
784
785	/* EEPROM */
786	s = &dev->subdevices[6];
787	s->type = COMEDI_SUBD_UNUSED;
788
789	apci3xxx_reset(dev);
790	return 0;
791}
792
793static void apci3xxx_detach(struct comedi_device *dev)
794{
795	struct addi_private *devpriv = dev->private;
796
797	if (devpriv) {
798		if (dev->iobase)
799			apci3xxx_reset(dev);
800		if (dev->irq)
801			free_irq(dev->irq, dev);
802		if (devpriv->dw_AiBase)
803			iounmap(devpriv->dw_AiBase);
804	}
805	comedi_pci_disable(dev);
806}
807
808static struct comedi_driver apci3xxx_driver = {
809	.driver_name	= "addi_apci_3xxx",
810	.module		= THIS_MODULE,
811	.auto_attach	= apci3xxx_auto_attach,
812	.detach		= apci3xxx_detach,
813};
814
815static int apci3xxx_pci_probe(struct pci_dev *dev,
816			      const struct pci_device_id *id)
817{
818	return comedi_pci_auto_config(dev, &apci3xxx_driver, id->driver_data);
819}
820
821static DEFINE_PCI_DEVICE_TABLE(apci3xxx_pci_table) = {
822	{ PCI_VDEVICE(ADDIDATA, 0x3010), BOARD_APCI3000_16 },
823	{ PCI_VDEVICE(ADDIDATA, 0x300f), BOARD_APCI3000_8 },
824	{ PCI_VDEVICE(ADDIDATA, 0x300e), BOARD_APCI3000_4 },
825	{ PCI_VDEVICE(ADDIDATA, 0x3013), BOARD_APCI3006_16 },
826	{ PCI_VDEVICE(ADDIDATA, 0x3014), BOARD_APCI3006_8 },
827	{ PCI_VDEVICE(ADDIDATA, 0x3015), BOARD_APCI3006_4 },
828	{ PCI_VDEVICE(ADDIDATA, 0x3016), BOARD_APCI3010_16 },
829	{ PCI_VDEVICE(ADDIDATA, 0x3017), BOARD_APCI3010_8 },
830	{ PCI_VDEVICE(ADDIDATA, 0x3018), BOARD_APCI3010_4 },
831	{ PCI_VDEVICE(ADDIDATA, 0x3019), BOARD_APCI3016_16 },
832	{ PCI_VDEVICE(ADDIDATA, 0x301a), BOARD_APCI3016_8 },
833	{ PCI_VDEVICE(ADDIDATA, 0x301b), BOARD_APCI3016_4 },
834	{ PCI_VDEVICE(ADDIDATA, 0x301c), BOARD_APCI3100_16_4 },
835	{ PCI_VDEVICE(ADDIDATA, 0x301d), BOARD_APCI3100_8_4 },
836	{ PCI_VDEVICE(ADDIDATA, 0x301e), BOARD_APCI3106_16_4 },
837	{ PCI_VDEVICE(ADDIDATA, 0x301f), BOARD_APCI3106_8_4 },
838	{ PCI_VDEVICE(ADDIDATA, 0x3020), BOARD_APCI3110_16_4 },
839	{ PCI_VDEVICE(ADDIDATA, 0x3021), BOARD_APCI3110_8_4 },
840	{ PCI_VDEVICE(ADDIDATA, 0x3022), BOARD_APCI3116_16_4 },
841	{ PCI_VDEVICE(ADDIDATA, 0x3023), BOARD_APCI3116_8_4 },
842	{ PCI_VDEVICE(ADDIDATA, 0x300B), BOARD_APCI3003 },
843	{ PCI_VDEVICE(ADDIDATA, 0x3002), BOARD_APCI3002_16 },
844	{ PCI_VDEVICE(ADDIDATA, 0x3003), BOARD_APCI3002_8 },
845	{ PCI_VDEVICE(ADDIDATA, 0x3004), BOARD_APCI3002_4 },
846	{ PCI_VDEVICE(ADDIDATA, 0x3024), BOARD_APCI3500 },
847	{ 0 }
848};
849MODULE_DEVICE_TABLE(pci, apci3xxx_pci_table);
850
851static struct pci_driver apci3xxx_pci_driver = {
852	.name		= "addi_apci_3xxx",
853	.id_table	= apci3xxx_pci_table,
854	.probe		= apci3xxx_pci_probe,
855	.remove		= comedi_pci_auto_unconfig,
856};
857module_comedi_pci_driver(apci3xxx_driver, apci3xxx_pci_driver);
858
859MODULE_AUTHOR("Comedi http://www.comedi.org");
860MODULE_DESCRIPTION("Comedi low-level driver");
861MODULE_LICENSE("GPL");
862