staging: comedi: adv_pci1710: store the pci_dev in the comedi_device
[deliverable/linux.git] / drivers / staging / comedi / drivers / adv_pci_dio.c
CommitLineData
ebd127c3
MD
1/*
2 * comedi/drivers/adv_pci_dio.c
3 *
4 * Author: Michal Dobes <dobes@tesnet.cz>
5 *
6 * Hardware driver for Advantech PCI DIO cards.
7*/
8/*
9Driver: adv_pci_dio
d4da77a7 10Description: Advantech PCI-1730, PCI-1733, PCI-1734, PCI-1735U,
9e77e6b6
IA
11 PCI-1736UP, PCI-1739U, PCI-1750, PCI-1751, PCI-1752,
12 PCI-1753/E, PCI-1754, PCI-1756, PCI-1760, PCI-1762
ebd127c3
MD
13Author: Michal Dobes <dobes@tesnet.cz>
14Devices: [Advantech] PCI-1730 (adv_pci_dio), PCI-1733,
9e77e6b6 15 PCI-1734, PCI-1735U, PCI-1736UP, PCI-1739U, PCI-1750,
ebd127c3
MD
16 PCI-1751, PCI-1752, PCI-1753,
17 PCI-1753+PCI-1753E, PCI-1754, PCI-1756,
18 PCI-1760, PCI-1762
19Status: untested
9e77e6b6 20Updated: Mon, 09 Jan 2012 12:40:46 +0000
ebd127c3
MD
21
22This driver supports now only insn interface for DI/DO/DIO.
23
24Configuration options:
25 [0] - PCI bus of device (optional)
26 [1] - PCI slot of device (optional)
3afbe13c
M
27 If bus/slot is not specified, the first available PCI
28 device will be used.
ebd127c3
MD
29
30*/
31
32#include "../comedidev.h"
33
34#include <linux/delay.h>
35
ebd127c3 36#include "8255.h"
d4da77a7 37#include "8253.h"
ebd127c3
MD
38
39#undef PCI_DIO_EXTDEBUG /* if defined, enable extensive debug logging */
40
41#undef DPRINTK
42#ifdef PCI_DIO_EXTDEBUG
5f74ea14 43#define DPRINTK(fmt, args...) printk(fmt, ## args)
ebd127c3
MD
44#else
45#define DPRINTK(fmt, args...)
46#endif
47
59af888d
GKH
48#define PCI_VENDOR_ID_ADVANTECH 0x13fe
49
a8f1152e
BP
50/* hardware types of the cards */
51enum hw_cards_id {
d4da77a7 52 TYPE_PCI1730, TYPE_PCI1733, TYPE_PCI1734, TYPE_PCI1735, TYPE_PCI1736,
9e77e6b6 53 TYPE_PCI1739,
ebd127c3
MD
54 TYPE_PCI1750,
55 TYPE_PCI1751,
56 TYPE_PCI1752,
57 TYPE_PCI1753, TYPE_PCI1753E,
58 TYPE_PCI1754, TYPE_PCI1756,
59 TYPE_PCI1760,
60 TYPE_PCI1762
a8f1152e 61};
ebd127c3 62
a8f1152e
BP
63/* which I/O instructions to use */
64enum hw_io_access {
ebd127c3 65 IO_8b, IO_16b
a8f1152e 66};
ebd127c3
MD
67
68#define MAX_DI_SUBDEVS 2 /* max number of DI subdevices per card */
69#define MAX_DO_SUBDEVS 2 /* max number of DO subdevices per card */
3afbe13c
M
70#define MAX_DIO_SUBDEVG 2 /* max number of DIO subdevices group per
71 * card */
72#define MAX_8254_SUBDEVS 1 /* max number of 8254 counter subdevs per
73 * card */
74 /* (could be more than one 8254 per
75 * subdevice) */
ebd127c3 76
d4da77a7 77#define SIZE_8254 4 /* 8254 IO space length */
ebd127c3
MD
78#define SIZE_8255 4 /* 8255 IO space length */
79
80#define PCIDIO_MAINREG 2 /* main I/O region for all Advantech cards? */
81
82/* Register offset definitions */
ba23095c 83/* Advantech PCI-1730/3/4 */
ebd127c3
MD
84#define PCI1730_IDI 0 /* R: Isolated digital input 0-15 */
85#define PCI1730_IDO 0 /* W: Isolated digital output 0-15 */
86#define PCI1730_DI 2 /* R: Digital input 0-15 */
87#define PCI1730_DO 2 /* W: Digital output 0-15 */
88#define PCI1733_IDI 0 /* R: Isolated digital input 0-31 */
89#define PCI1730_3_INT_EN 0x08 /* R/W: enable/disable interrupts */
3afbe13c
M
90#define PCI1730_3_INT_RF 0x0c /* R/W: set falling/raising edge for
91 * interrupts */
ebd127c3
MD
92#define PCI1730_3_INT_CLR 0x10 /* R/W: clear interrupts */
93#define PCI1734_IDO 0 /* W: Isolated digital output 0-31 */
94#define PCI173x_BOARDID 4 /* R: Board I/D switch for 1730/3/4 */
95
d4da77a7
IA
96/* Advantech PCI-1735U */
97#define PCI1735_DI 0 /* R: Digital input 0-31 */
98#define PCI1735_DO 0 /* W: Digital output 0-31 */
99#define PCI1735_C8254 4 /* R/W: 8254 counter */
100#define PCI1735_BOARDID 8 /* R: Board I/D switch for 1735U */
101
ba23095c 102/* Advantech PCI-1736UP */
0a85b6f0
MT
103#define PCI1736_IDI 0 /* R: Isolated digital input 0-15 */
104#define PCI1736_IDO 0 /* W: Isolated digital output 0-15 */
105#define PCI1736_3_INT_EN 0x08 /* R/W: enable/disable interrupts */
3afbe13c
M
106#define PCI1736_3_INT_RF 0x0c /* R/W: set falling/raising edge for
107 * interrupts */
0a85b6f0
MT
108#define PCI1736_3_INT_CLR 0x10 /* R/W: clear interrupts */
109#define PCI1736_BOARDID 4 /* R: Board I/D switch for 1736UP */
110#define PCI1736_MAINREG 0 /* Normal register (2) doesn't work */
ebd127c3 111
9e77e6b6
IA
112/* Advantech PCI-1739U */
113#define PCI1739_DIO 0 /* R/W: begin of 8255 registers block */
114#define PCI1739_ICR 32 /* W: Interrupt control register */
115#define PCI1739_ISR 32 /* R: Interrupt status register */
116#define PCI1739_BOARDID 8 /* R: Board I/D switch for 1739U */
117
ba23095c 118/* Advantech PCI-1750 */
ebd127c3
MD
119#define PCI1750_IDI 0 /* R: Isolated digital input 0-15 */
120#define PCI1750_IDO 0 /* W: Isolated digital output 0-15 */
121#define PCI1750_ICR 32 /* W: Interrupt control register */
122#define PCI1750_ISR 32 /* R: Interrupt status register */
123
ba23095c 124/* Advantech PCI-1751/3/3E */
ebd127c3 125#define PCI1751_DIO 0 /* R/W: begin of 8255 registers block */
cfe3cffd 126#define PCI1751_CNT 24 /* R/W: begin of 8254 registers block */
ebd127c3
MD
127#define PCI1751_ICR 32 /* W: Interrupt control register */
128#define PCI1751_ISR 32 /* R: Interrupt status register */
129#define PCI1753_DIO 0 /* R/W: begin of 8255 registers block */
130#define PCI1753_ICR0 16 /* R/W: Interrupt control register group 0 */
131#define PCI1753_ICR1 17 /* R/W: Interrupt control register group 1 */
132#define PCI1753_ICR2 18 /* R/W: Interrupt control register group 2 */
133#define PCI1753_ICR3 19 /* R/W: Interrupt control register group 3 */
134#define PCI1753E_DIO 32 /* R/W: begin of 8255 registers block */
135#define PCI1753E_ICR0 48 /* R/W: Interrupt control register group 0 */
136#define PCI1753E_ICR1 49 /* R/W: Interrupt control register group 1 */
137#define PCI1753E_ICR2 50 /* R/W: Interrupt control register group 2 */
138#define PCI1753E_ICR3 51 /* R/W: Interrupt control register group 3 */
139
ba23095c 140/* Advantech PCI-1752/4/6 */
ebd127c3
MD
141#define PCI1752_IDO 0 /* R/W: Digital output 0-31 */
142#define PCI1752_IDO2 4 /* R/W: Digital output 32-63 */
143#define PCI1754_IDI 0 /* R: Digital input 0-31 */
144#define PCI1754_IDI2 4 /* R: Digital input 32-64 */
145#define PCI1756_IDI 0 /* R: Digital input 0-31 */
146#define PCI1756_IDO 4 /* R/W: Digital output 0-31 */
147#define PCI1754_6_ICR0 0x08 /* R/W: Interrupt control register group 0 */
148#define PCI1754_6_ICR1 0x0a /* R/W: Interrupt control register group 1 */
149#define PCI1754_ICR2 0x0c /* R/W: Interrupt control register group 2 */
150#define PCI1754_ICR3 0x0e /* R/W: Interrupt control register group 3 */
151#define PCI1752_6_CFC 0x12 /* R/W: set/read channel freeze function */
152#define PCI175x_BOARDID 0x10 /* R: Board I/D switch for 1752/4/6 */
153
ba23095c 154/* Advantech PCI-1762 registers */
ebd127c3
MD
155#define PCI1762_RO 0 /* R/W: Relays status/output */
156#define PCI1762_IDI 2 /* R: Isolated input status */
157#define PCI1762_BOARDID 4 /* R: Board I/D switch */
158#define PCI1762_ICR 6 /* W: Interrupt control register */
159#define PCI1762_ISR 6 /* R: Interrupt status register */
160
ba23095c 161/* Advantech PCI-1760 registers */
ebd127c3
MD
162#define OMB0 0x0c /* W: Mailbox outgoing registers */
163#define OMB1 0x0d
164#define OMB2 0x0e
165#define OMB3 0x0f
166#define IMB0 0x1c /* R: Mailbox incoming registers */
167#define IMB1 0x1d
168#define IMB2 0x1e
169#define IMB3 0x1f
170#define INTCSR0 0x38 /* R/W: Interrupt control registers */
171#define INTCSR1 0x39
172#define INTCSR2 0x3a
173#define INTCSR3 0x3b
174
ba23095c 175/* PCI-1760 mailbox commands */
3afbe13c
M
176#define CMD_ClearIMB2 0x00 /* Clear IMB2 status and return actual
177 * DI status in IMB3 */
ebd127c3
MD
178#define CMD_SetRelaysOutput 0x01 /* Set relay output from OMB0 */
179#define CMD_GetRelaysStatus 0x02 /* Get relay status to IMB0 */
3afbe13c
M
180#define CMD_ReadCurrentStatus 0x07 /* Read the current status of the
181 * register in OMB0, result in IMB0 */
182#define CMD_ReadFirmwareVersion 0x0e /* Read the firmware ver., result in
183 * IMB1.IMB0 */
184#define CMD_ReadHardwareVersion 0x0f /* Read the hardware ver., result in
185 * IMB1.IMB0 */
186#define CMD_EnableIDIFilters 0x20 /* Enable IDI filters based on bits in
187 * OMB0 */
188#define CMD_EnableIDIPatternMatch 0x21 /* Enable IDI pattern match based on
189 * bits in OMB0 */
190#define CMD_SetIDIPatternMatch 0x22 /* Enable IDI pattern match based on
191 * bits in OMB0 */
192#define CMD_EnableIDICounters 0x28 /* Enable IDI counters based on bits in
193 * OMB0 */
194#define CMD_ResetIDICounters 0x29 /* Reset IDI counters based on bits in
195 * OMB0 to its reset values */
196#define CMD_OverflowIDICounters 0x2a /* Enable IDI counters overflow
197 * interrupts based on bits in OMB0 */
198#define CMD_MatchIntIDICounters 0x2b /* Enable IDI counters match value
199 * interrupts based on bits in OMB0 */
200#define CMD_EdgeIDICounters 0x2c /* Set IDI up counters count edge (bit=0
201 * - rising, =1 - falling) */
202#define CMD_GetIDICntCurValue 0x2f /* Read IDI{OMB0} up counter current
203 * value */
204#define CMD_SetIDI0CntResetValue 0x40 /* Set IDI0 Counter Reset Value
205 * 256*OMB1+OMB0 */
206#define CMD_SetIDI1CntResetValue 0x41 /* Set IDI1 Counter Reset Value
207 * 256*OMB1+OMB0 */
208#define CMD_SetIDI2CntResetValue 0x42 /* Set IDI2 Counter Reset Value
209 * 256*OMB1+OMB0 */
210#define CMD_SetIDI3CntResetValue 0x43 /* Set IDI3 Counter Reset Value
211 * 256*OMB1+OMB0 */
212#define CMD_SetIDI4CntResetValue 0x44 /* Set IDI4 Counter Reset Value
213 * 256*OMB1+OMB0 */
214#define CMD_SetIDI5CntResetValue 0x45 /* Set IDI5 Counter Reset Value
215 * 256*OMB1+OMB0 */
216#define CMD_SetIDI6CntResetValue 0x46 /* Set IDI6 Counter Reset Value
217 * 256*OMB1+OMB0 */
218#define CMD_SetIDI7CntResetValue 0x47 /* Set IDI7 Counter Reset Value
219 * 256*OMB1+OMB0 */
220#define CMD_SetIDI0CntMatchValue 0x48 /* Set IDI0 Counter Match Value
221 * 256*OMB1+OMB0 */
222#define CMD_SetIDI1CntMatchValue 0x49 /* Set IDI1 Counter Match Value
223 * 256*OMB1+OMB0 */
224#define CMD_SetIDI2CntMatchValue 0x4a /* Set IDI2 Counter Match Value
225 * 256*OMB1+OMB0 */
226#define CMD_SetIDI3CntMatchValue 0x4b /* Set IDI3 Counter Match Value
227 * 256*OMB1+OMB0 */
228#define CMD_SetIDI4CntMatchValue 0x4c /* Set IDI4 Counter Match Value
229 * 256*OMB1+OMB0 */
230#define CMD_SetIDI5CntMatchValue 0x4d /* Set IDI5 Counter Match Value
231 * 256*OMB1+OMB0 */
232#define CMD_SetIDI6CntMatchValue 0x4e /* Set IDI6 Counter Match Value
233 * 256*OMB1+OMB0 */
234#define CMD_SetIDI7CntMatchValue 0x4f /* Set IDI7 Counter Match Value
235 * 256*OMB1+OMB0 */
ebd127c3
MD
236
237#define OMBCMD_RETRY 0x03 /* 3 times try request before error */
238
673bc56a 239struct diosubd_data {
ba23095c
BP
240 int chans; /* num of chans */
241 int addr; /* PCI address ofset */
d4da77a7
IA
242 int regs; /* number of registers to read or 8255
243 subdevices or 8254 chips */
ba23095c 244 unsigned int specflags; /* addon subdevice flags */
673bc56a 245};
ebd127c3 246
dea1776a 247struct dio_boardtype {
ba23095c
BP
248 const char *name; /* board name */
249 int vendor_id; /* vendor/device PCI ID */
ebd127c3 250 int device_id;
ba23095c 251 int main_pci_region; /* main I/O PCI region */
a8f1152e 252 enum hw_cards_id cardtype;
ba23095c
BP
253 struct diosubd_data sdi[MAX_DI_SUBDEVS]; /* DI chans */
254 struct diosubd_data sdo[MAX_DO_SUBDEVS]; /* DO chans */
255 struct diosubd_data sdio[MAX_DIO_SUBDEVG]; /* DIO 8255 chans */
256 struct diosubd_data boardid; /* card supports board ID switch */
d4da77a7 257 struct diosubd_data s8254[MAX_8254_SUBDEVS]; /* 8254 subdevices */
a8f1152e 258 enum hw_io_access io_access;
dea1776a 259};
ebd127c3 260
dea1776a 261static const struct dio_boardtype boardtypes[] = {
ebd127c3 262 {"pci1730", PCI_VENDOR_ID_ADVANTECH, 0x1730, PCIDIO_MAINREG,
0a85b6f0 263 TYPE_PCI1730,
3afbe13c
M
264 { {16, PCI1730_DI, 2, 0}, {16, PCI1730_IDI, 2, 0} },
265 { {16, PCI1730_DO, 2, 0}, {16, PCI1730_IDO, 2, 0} },
266 { {0, 0, 0, 0}, {0, 0, 0, 0} },
0a85b6f0 267 {4, PCI173x_BOARDID, 1, SDF_INTERNAL},
3afbe13c 268 { {0, 0, 0, 0} },
d4da77a7 269 IO_8b},
ebd127c3 270 {"pci1733", PCI_VENDOR_ID_ADVANTECH, 0x1733, PCIDIO_MAINREG,
0a85b6f0 271 TYPE_PCI1733,
3afbe13c
M
272 { {0, 0, 0, 0}, {32, PCI1733_IDI, 4, 0} },
273 { {0, 0, 0, 0}, {0, 0, 0, 0} },
274 { {0, 0, 0, 0}, {0, 0, 0, 0} },
0a85b6f0 275 {4, PCI173x_BOARDID, 1, SDF_INTERNAL},
3afbe13c 276 { {0, 0, 0, 0} },
0a85b6f0 277 IO_8b},
ebd127c3 278 {"pci1734", PCI_VENDOR_ID_ADVANTECH, 0x1734, PCIDIO_MAINREG,
0a85b6f0 279 TYPE_PCI1734,
3afbe13c
M
280 { {0, 0, 0, 0}, {0, 0, 0, 0} },
281 { {0, 0, 0, 0}, {32, PCI1734_IDO, 4, 0} },
282 { {0, 0, 0, 0}, {0, 0, 0, 0} },
0a85b6f0 283 {4, PCI173x_BOARDID, 1, SDF_INTERNAL},
3afbe13c 284 { {0, 0, 0, 0} },
d4da77a7
IA
285 IO_8b},
286 {"pci1735", PCI_VENDOR_ID_ADVANTECH, 0x1735, PCIDIO_MAINREG,
287 TYPE_PCI1735,
3afbe13c
M
288 { {32, PCI1735_DI, 4, 0}, {0, 0, 0, 0} },
289 { {32, PCI1735_DO, 4, 0}, {0, 0, 0, 0} },
290 { {0, 0, 0, 0}, {0, 0, 0, 0} },
d4da77a7 291 { 4, PCI1735_BOARDID, 1, SDF_INTERNAL},
3afbe13c 292 { {3, PCI1735_C8254, 1, 0} },
0a85b6f0 293 IO_8b},
ebd127c3 294 {"pci1736", PCI_VENDOR_ID_ADVANTECH, 0x1736, PCI1736_MAINREG,
0a85b6f0 295 TYPE_PCI1736,
3afbe13c
M
296 { {0, 0, 0, 0}, {16, PCI1736_IDI, 2, 0} },
297 { {0, 0, 0, 0}, {16, PCI1736_IDO, 2, 0} },
298 { {0, 0, 0, 0}, {0, 0, 0, 0} },
0a85b6f0 299 {4, PCI1736_BOARDID, 1, SDF_INTERNAL},
3afbe13c 300 { {0, 0, 0, 0} },
d4da77a7 301 IO_8b},
9e77e6b6
IA
302 {"pci1739", PCI_VENDOR_ID_ADVANTECH, 0x1739, PCIDIO_MAINREG,
303 TYPE_PCI1739,
304 { {0, 0, 0, 0}, {0, 0, 0, 0} },
305 { {0, 0, 0, 0}, {0, 0, 0, 0} },
306 { {48, PCI1739_DIO, 2, 0}, {0, 0, 0, 0} },
307 {0, 0, 0, 0},
308 { {0, 0, 0, 0} },
309 IO_8b},
ebd127c3 310 {"pci1750", PCI_VENDOR_ID_ADVANTECH, 0x1750, PCIDIO_MAINREG,
0a85b6f0 311 TYPE_PCI1750,
3afbe13c
M
312 { {0, 0, 0, 0}, {16, PCI1750_IDI, 2, 0} },
313 { {0, 0, 0, 0}, {16, PCI1750_IDO, 2, 0} },
314 { {0, 0, 0, 0}, {0, 0, 0, 0} },
0a85b6f0 315 {0, 0, 0, 0},
3afbe13c 316 { {0, 0, 0, 0} },
0a85b6f0 317 IO_8b},
ebd127c3 318 {"pci1751", PCI_VENDOR_ID_ADVANTECH, 0x1751, PCIDIO_MAINREG,
0a85b6f0 319 TYPE_PCI1751,
3afbe13c
M
320 { {0, 0, 0, 0}, {0, 0, 0, 0} },
321 { {0, 0, 0, 0}, {0, 0, 0, 0} },
322 { {48, PCI1751_DIO, 2, 0}, {0, 0, 0, 0} },
0a85b6f0 323 {0, 0, 0, 0},
cfe3cffd 324 { {3, PCI1751_CNT, 1, 0} },
0a85b6f0 325 IO_8b},
ebd127c3 326 {"pci1752", PCI_VENDOR_ID_ADVANTECH, 0x1752, PCIDIO_MAINREG,
0a85b6f0 327 TYPE_PCI1752,
3afbe13c
M
328 { {0, 0, 0, 0}, {0, 0, 0, 0} },
329 { {32, PCI1752_IDO, 2, 0}, {32, PCI1752_IDO2, 2, 0} },
330 { {0, 0, 0, 0}, {0, 0, 0, 0} },
0a85b6f0 331 {4, PCI175x_BOARDID, 1, SDF_INTERNAL},
3afbe13c 332 { {0, 0, 0, 0} },
0a85b6f0 333 IO_16b},
ebd127c3 334 {"pci1753", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG,
0a85b6f0 335 TYPE_PCI1753,
3afbe13c
M
336 { {0, 0, 0, 0}, {0, 0, 0, 0} },
337 { {0, 0, 0, 0}, {0, 0, 0, 0} },
338 { {96, PCI1753_DIO, 4, 0}, {0, 0, 0, 0} },
0a85b6f0 339 {0, 0, 0, 0},
3afbe13c 340 { {0, 0, 0, 0} },
0a85b6f0 341 IO_8b},
ebd127c3 342 {"pci1753e", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG,
0a85b6f0 343 TYPE_PCI1753E,
3afbe13c
M
344 { {0, 0, 0, 0}, {0, 0, 0, 0} },
345 { {0, 0, 0, 0}, {0, 0, 0, 0} },
346 { {96, PCI1753_DIO, 4, 0}, {96, PCI1753E_DIO, 4, 0} },
0a85b6f0 347 {0, 0, 0, 0},
3afbe13c 348 { {0, 0, 0, 0} },
0a85b6f0 349 IO_8b},
ebd127c3 350 {"pci1754", PCI_VENDOR_ID_ADVANTECH, 0x1754, PCIDIO_MAINREG,
0a85b6f0 351 TYPE_PCI1754,
3afbe13c
M
352 { {32, PCI1754_IDI, 2, 0}, {32, PCI1754_IDI2, 2, 0} },
353 { {0, 0, 0, 0}, {0, 0, 0, 0} },
354 { {0, 0, 0, 0}, {0, 0, 0, 0} },
0a85b6f0 355 {4, PCI175x_BOARDID, 1, SDF_INTERNAL},
3afbe13c 356 { {0, 0, 0, 0} },
0a85b6f0 357 IO_16b},
ebd127c3 358 {"pci1756", PCI_VENDOR_ID_ADVANTECH, 0x1756, PCIDIO_MAINREG,
0a85b6f0 359 TYPE_PCI1756,
3afbe13c
M
360 { {0, 0, 0, 0}, {32, PCI1756_IDI, 2, 0} },
361 { {0, 0, 0, 0}, {32, PCI1756_IDO, 2, 0} },
362 { {0, 0, 0, 0}, {0, 0, 0, 0} },
0a85b6f0 363 {4, PCI175x_BOARDID, 1, SDF_INTERNAL},
3afbe13c 364 { {0, 0, 0, 0} },
0a85b6f0 365 IO_16b},
ebd127c3 366 {"pci1760", PCI_VENDOR_ID_ADVANTECH, 0x1760, 0,
0a85b6f0 367 TYPE_PCI1760,
3afbe13c
M
368 { {0, 0, 0, 0}, {0, 0, 0, 0} }, /* This card have own setup work */
369 { {0, 0, 0, 0}, {0, 0, 0, 0} },
370 { {0, 0, 0, 0}, {0, 0, 0, 0} },
0a85b6f0 371 {0, 0, 0, 0},
3afbe13c 372 { {0, 0, 0, 0} },
0a85b6f0 373 IO_8b},
ebd127c3 374 {"pci1762", PCI_VENDOR_ID_ADVANTECH, 0x1762, PCIDIO_MAINREG,
0a85b6f0 375 TYPE_PCI1762,
3afbe13c
M
376 { {0, 0, 0, 0}, {16, PCI1762_IDI, 1, 0} },
377 { {0, 0, 0, 0}, {16, PCI1762_RO, 1, 0} },
378 { {0, 0, 0, 0}, {0, 0, 0, 0} },
0a85b6f0 379 {4, PCI1762_BOARDID, 1, SDF_INTERNAL},
3afbe13c 380 { {0, 0, 0, 0} },
0a85b6f0 381 IO_16b}
ebd127c3
MD
382};
383
4cb13356
BP
384struct pci_dio_private {
385 struct pci_dio_private *prev; /* previous private struct */
386 struct pci_dio_private *next; /* next private struct */
ba23095c
BP
387 struct pci_dev *pcidev; /* pointer to board's pci_dev */
388 char valid; /* card is usable */
389 char GlobalIrqEnabled; /* 1= any IRQ source is enabled */
390 /* PCI-1760 specific data */
3afbe13c
M
391 unsigned char IDICntEnable; /* counter's counting enable status */
392 unsigned char IDICntOverEnable; /* counter's overflow interrupts enable
393 * status */
394 unsigned char IDICntMatchEnable; /* counter's match interrupts
395 * enable status */
396 unsigned char IDICntEdge; /* counter's count edge value
397 * (bit=0 - rising, =1 - falling) */
ba23095c 398 unsigned short CntResValue[8]; /* counters' reset value */
3afbe13c
M
399 unsigned short CntMatchValue[8]; /* counters' match interrupt value */
400 unsigned char IDIFiltersEn; /* IDI's digital filters enable status */
ba23095c
BP
401 unsigned char IDIPatMatchEn; /* IDI's pattern match enable status */
402 unsigned char IDIPatMatchValue; /* IDI's pattern match value */
403 unsigned short IDIFiltrLow[8]; /* IDI's filter value low signal */
404 unsigned short IDIFiltrHigh[8]; /* IDI's filter value high signal */
ebd127c3
MD
405};
406
654e8fb5 407static struct pci_dio_private *pci_priv; /* list of allocated cards */
ebd127c3 408
4cb13356 409#define devpriv ((struct pci_dio_private *)dev->private)
dea1776a 410#define this_board ((const struct dio_boardtype *)dev->board_ptr)
ebd127c3
MD
411
412/*
413==============================================================================
414*/
0a85b6f0
MT
415static int pci_dio_insn_bits_di_b(struct comedi_device *dev,
416 struct comedi_subdevice *s,
417 struct comedi_insn *insn, unsigned int *data)
ebd127c3 418{
673bc56a 419 const struct diosubd_data *d = (const struct diosubd_data *)s->private;
ebd127c3
MD
420 int i;
421
422 data[1] = 0;
402a01ae 423 for (i = 0; i < d->regs; i++)
ebd127c3 424 data[1] |= inb(dev->iobase + d->addr + i) << (8 * i);
402a01ae 425
ebd127c3 426
a2714e3e 427 return insn->n;
ebd127c3
MD
428}
429
430/*
431==============================================================================
432*/
0a85b6f0
MT
433static int pci_dio_insn_bits_di_w(struct comedi_device *dev,
434 struct comedi_subdevice *s,
435 struct comedi_insn *insn, unsigned int *data)
ebd127c3 436{
673bc56a 437 const struct diosubd_data *d = (const struct diosubd_data *)s->private;
ebd127c3
MD
438 int i;
439
440 data[1] = 0;
441 for (i = 0; i < d->regs; i++)
442 data[1] |= inw(dev->iobase + d->addr + 2 * i) << (16 * i);
443
a2714e3e 444 return insn->n;
ebd127c3
MD
445}
446
447/*
448==============================================================================
449*/
0a85b6f0
MT
450static int pci_dio_insn_bits_do_b(struct comedi_device *dev,
451 struct comedi_subdevice *s,
452 struct comedi_insn *insn, unsigned int *data)
ebd127c3 453{
673bc56a 454 const struct diosubd_data *d = (const struct diosubd_data *)s->private;
ebd127c3
MD
455 int i;
456
457 if (data[0]) {
458 s->state &= ~data[0];
459 s->state |= (data[0] & data[1]);
460 for (i = 0; i < d->regs; i++)
461 outb((s->state >> (8 * i)) & 0xff,
0a85b6f0 462 dev->iobase + d->addr + i);
ebd127c3
MD
463 }
464 data[1] = s->state;
465
a2714e3e 466 return insn->n;
ebd127c3
MD
467}
468
469/*
470==============================================================================
471*/
0a85b6f0
MT
472static int pci_dio_insn_bits_do_w(struct comedi_device *dev,
473 struct comedi_subdevice *s,
474 struct comedi_insn *insn, unsigned int *data)
ebd127c3 475{
673bc56a 476 const struct diosubd_data *d = (const struct diosubd_data *)s->private;
ebd127c3
MD
477 int i;
478
479 if (data[0]) {
480 s->state &= ~data[0];
481 s->state |= (data[0] & data[1]);
482 for (i = 0; i < d->regs; i++)
483 outw((s->state >> (16 * i)) & 0xffff,
0a85b6f0 484 dev->iobase + d->addr + 2 * i);
ebd127c3
MD
485 }
486 data[1] = s->state;
487
a2714e3e 488 return insn->n;
ebd127c3
MD
489}
490
d4da77a7
IA
491/*
492==============================================================================
493*/
494static int pci_8254_insn_read(struct comedi_device *dev,
495 struct comedi_subdevice *s,
496 struct comedi_insn *insn, unsigned int *data)
497{
498 const struct diosubd_data *d = (const struct diosubd_data *)s->private;
499 unsigned int chan, chip, chipchan;
500 unsigned long flags;
501
502 chan = CR_CHAN(insn->chanspec); /* channel on subdevice */
503 chip = chan / 3; /* chip on subdevice */
504 chipchan = chan - (3 * chip); /* channel on chip on subdevice */
505 spin_lock_irqsave(&s->spin_lock, flags);
506 data[0] = i8254_read(dev->iobase + d->addr + (SIZE_8254 * chip),
507 0, chipchan);
508 spin_unlock_irqrestore(&s->spin_lock, flags);
509 return 1;
510}
511
512/*
513==============================================================================
514*/
515static int pci_8254_insn_write(struct comedi_device *dev,
516 struct comedi_subdevice *s,
517 struct comedi_insn *insn, unsigned int *data)
518{
519 const struct diosubd_data *d = (const struct diosubd_data *)s->private;
520 unsigned int chan, chip, chipchan;
521 unsigned long flags;
522
523 chan = CR_CHAN(insn->chanspec); /* channel on subdevice */
524 chip = chan / 3; /* chip on subdevice */
525 chipchan = chan - (3 * chip); /* channel on chip on subdevice */
526 spin_lock_irqsave(&s->spin_lock, flags);
527 i8254_write(dev->iobase + d->addr + (SIZE_8254 * chip),
528 0, chipchan, data[0]);
529 spin_unlock_irqrestore(&s->spin_lock, flags);
530 return 1;
531}
532
533/*
534==============================================================================
535*/
536static int pci_8254_insn_config(struct comedi_device *dev,
537 struct comedi_subdevice *s,
538 struct comedi_insn *insn, unsigned int *data)
539{
540 const struct diosubd_data *d = (const struct diosubd_data *)s->private;
541 unsigned int chan, chip, chipchan;
542 unsigned long iobase;
543 int ret = 0;
544 unsigned long flags;
545
546 chan = CR_CHAN(insn->chanspec); /* channel on subdevice */
547 chip = chan / 3; /* chip on subdevice */
548 chipchan = chan - (3 * chip); /* channel on chip on subdevice */
549 iobase = dev->iobase + d->addr + (SIZE_8254 * chip);
550 spin_lock_irqsave(&s->spin_lock, flags);
551 switch (data[0]) {
552 case INSN_CONFIG_SET_COUNTER_MODE:
553 ret = i8254_set_mode(iobase, 0, chipchan, data[1]);
554 if (ret < 0)
555 ret = -EINVAL;
556 break;
557 case INSN_CONFIG_8254_READ_STATUS:
558 data[1] = i8254_status(iobase, 0, chipchan);
559 break;
560 default:
561 ret = -EINVAL;
562 break;
563 }
564 spin_unlock_irqrestore(&s->spin_lock, flags);
565 return ret < 0 ? ret : insn->n;
566}
567
ebd127c3
MD
568/*
569==============================================================================
570*/
da91b269 571static int pci1760_unchecked_mbxrequest(struct comedi_device *dev,
0a85b6f0
MT
572 unsigned char *omb, unsigned char *imb,
573 int repeats)
ebd127c3
MD
574{
575 int cnt, tout, ok = 0;
576
577 for (cnt = 0; cnt < repeats; cnt++) {
578 outb(omb[0], dev->iobase + OMB0);
579 outb(omb[1], dev->iobase + OMB1);
580 outb(omb[2], dev->iobase + OMB2);
581 outb(omb[3], dev->iobase + OMB3);
582 for (tout = 0; tout < 251; tout++) {
c3744138
BP
583 imb[2] = inb(dev->iobase + IMB2);
584 if (imb[2] == omb[2]) {
ebd127c3
MD
585 imb[0] = inb(dev->iobase + IMB0);
586 imb[1] = inb(dev->iobase + IMB1);
587 imb[3] = inb(dev->iobase + IMB3);
588 ok = 1;
589 break;
590 }
5f74ea14 591 udelay(1);
ebd127c3
MD
592 }
593 if (ok)
594 return 0;
595 }
596
597 comedi_error(dev, "PCI-1760 mailbox request timeout!");
598 return -ETIME;
599}
600
da91b269 601static int pci1760_clear_imb2(struct comedi_device *dev)
ebd127c3
MD
602{
603 unsigned char omb[4] = { 0x0, 0x0, CMD_ClearIMB2, 0x0 };
604 unsigned char imb[4];
605 /* check if imb2 is already clear */
606 if (inb(dev->iobase + IMB2) == CMD_ClearIMB2)
607 return 0;
608 return pci1760_unchecked_mbxrequest(dev, omb, imb, OMBCMD_RETRY);
609}
610
da91b269 611static int pci1760_mbxrequest(struct comedi_device *dev,
0a85b6f0 612 unsigned char *omb, unsigned char *imb)
ebd127c3
MD
613{
614 if (omb[2] == CMD_ClearIMB2) {
615 comedi_error(dev,
0a85b6f0 616 "bug! this function should not be used for CMD_ClearIMB2 command");
ebd127c3
MD
617 return -EINVAL;
618 }
619 if (inb(dev->iobase + IMB2) == omb[2]) {
620 int retval;
621 retval = pci1760_clear_imb2(dev);
622 if (retval < 0)
623 return retval;
624 }
625 return pci1760_unchecked_mbxrequest(dev, omb, imb, OMBCMD_RETRY);
626}
627
628/*
629==============================================================================
630*/
0a85b6f0
MT
631static int pci1760_insn_bits_di(struct comedi_device *dev,
632 struct comedi_subdevice *s,
633 struct comedi_insn *insn, unsigned int *data)
ebd127c3
MD
634{
635 data[1] = inb(dev->iobase + IMB3);
636
a2714e3e 637 return insn->n;
ebd127c3
MD
638}
639
640/*
641==============================================================================
642*/
0a85b6f0
MT
643static int pci1760_insn_bits_do(struct comedi_device *dev,
644 struct comedi_subdevice *s,
645 struct comedi_insn *insn, unsigned int *data)
ebd127c3
MD
646{
647 int ret;
648 unsigned char omb[4] = {
649 0x00,
650 0x00,
651 CMD_SetRelaysOutput,
652 0x00
653 };
654 unsigned char imb[4];
655
656 if (data[0]) {
657 s->state &= ~data[0];
658 s->state |= (data[0] & data[1]);
659 omb[0] = s->state;
c3744138
BP
660 ret = pci1760_mbxrequest(dev, omb, imb);
661 if (!ret)
ebd127c3
MD
662 return ret;
663 }
664 data[1] = s->state;
665
a2714e3e 666 return insn->n;
ebd127c3
MD
667}
668
669/*
670==============================================================================
671*/
0a85b6f0
MT
672static int pci1760_insn_cnt_read(struct comedi_device *dev,
673 struct comedi_subdevice *s,
674 struct comedi_insn *insn, unsigned int *data)
ebd127c3
MD
675{
676 int ret, n;
677 unsigned char omb[4] = {
678 CR_CHAN(insn->chanspec) & 0x07,
679 0x00,
680 CMD_GetIDICntCurValue,
681 0x00
682 };
683 unsigned char imb[4];
684
685 for (n = 0; n < insn->n; n++) {
c3744138
BP
686 ret = pci1760_mbxrequest(dev, omb, imb);
687 if (!ret)
ebd127c3
MD
688 return ret;
689 data[n] = (imb[1] << 8) + imb[0];
690 }
691
692 return n;
693}
694
695/*
696==============================================================================
697*/
0a85b6f0
MT
698static int pci1760_insn_cnt_write(struct comedi_device *dev,
699 struct comedi_subdevice *s,
700 struct comedi_insn *insn, unsigned int *data)
ebd127c3
MD
701{
702 int ret;
703 unsigned char chan = CR_CHAN(insn->chanspec) & 0x07;
704 unsigned char bitmask = 1 << chan;
705 unsigned char omb[4] = {
706 data[0] & 0xff,
707 (data[0] >> 8) & 0xff,
708 CMD_SetIDI0CntResetValue + chan,
709 0x00
710 };
711 unsigned char imb[4];
712
3afbe13c
M
713 /* Set reset value if different */
714 if (devpriv->CntResValue[chan] != (data[0] & 0xffff)) {
0a85b6f0 715 ret = pci1760_mbxrequest(dev, omb, imb);
c3744138 716 if (!ret)
ebd127c3
MD
717 return ret;
718 devpriv->CntResValue[chan] = data[0] & 0xffff;
719 }
720
ba23095c 721 omb[0] = bitmask; /* reset counter to it reset value */
ebd127c3 722 omb[2] = CMD_ResetIDICounters;
c3744138
BP
723 ret = pci1760_mbxrequest(dev, omb, imb);
724 if (!ret)
ebd127c3
MD
725 return ret;
726
3afbe13c
M
727 /* start counter if it don't run */
728 if (!(bitmask & devpriv->IDICntEnable)) {
ebd127c3
MD
729 omb[0] = bitmask;
730 omb[2] = CMD_EnableIDICounters;
c3744138
BP
731 ret = pci1760_mbxrequest(dev, omb, imb);
732 if (!ret)
ebd127c3
MD
733 return ret;
734 devpriv->IDICntEnable |= bitmask;
735 }
736 return 1;
737}
738
739/*
740==============================================================================
741*/
da91b269 742static int pci1760_reset(struct comedi_device *dev)
ebd127c3
MD
743{
744 int i;
745 unsigned char omb[4] = { 0x00, 0x00, 0x00, 0x00 };
746 unsigned char imb[4];
747
ba23095c 748 outb(0, dev->iobase + INTCSR0); /* disable IRQ */
ebd127c3
MD
749 outb(0, dev->iobase + INTCSR1);
750 outb(0, dev->iobase + INTCSR2);
751 outb(0, dev->iobase + INTCSR3);
752 devpriv->GlobalIrqEnabled = 0;
753
754 omb[0] = 0x00;
ba23095c 755 omb[2] = CMD_SetRelaysOutput; /* reset relay outputs */
ebd127c3
MD
756 pci1760_mbxrequest(dev, omb, imb);
757
758 omb[0] = 0x00;
ba23095c 759 omb[2] = CMD_EnableIDICounters; /* disable IDI up counters */
ebd127c3
MD
760 pci1760_mbxrequest(dev, omb, imb);
761 devpriv->IDICntEnable = 0;
762
763 omb[0] = 0x00;
3afbe13c
M
764 omb[2] = CMD_OverflowIDICounters; /* disable counters overflow
765 * interrupts */
ebd127c3
MD
766 pci1760_mbxrequest(dev, omb, imb);
767 devpriv->IDICntOverEnable = 0;
768
769 omb[0] = 0x00;
3afbe13c
M
770 omb[2] = CMD_MatchIntIDICounters; /* disable counters match value
771 * interrupts */
ebd127c3
MD
772 pci1760_mbxrequest(dev, omb, imb);
773 devpriv->IDICntMatchEnable = 0;
774
775 omb[0] = 0x00;
776 omb[1] = 0x80;
ba23095c 777 for (i = 0; i < 8; i++) { /* set IDI up counters match value */
ebd127c3
MD
778 omb[2] = CMD_SetIDI0CntMatchValue + i;
779 pci1760_mbxrequest(dev, omb, imb);
780 devpriv->CntMatchValue[i] = 0x8000;
781 }
782
783 omb[0] = 0x00;
784 omb[1] = 0x00;
ba23095c 785 for (i = 0; i < 8; i++) { /* set IDI up counters reset value */
ebd127c3
MD
786 omb[2] = CMD_SetIDI0CntResetValue + i;
787 pci1760_mbxrequest(dev, omb, imb);
788 devpriv->CntResValue[i] = 0x0000;
789 }
790
791 omb[0] = 0xff;
3afbe13c
M
792 omb[2] = CMD_ResetIDICounters; /* reset IDI up counters to reset
793 * values */
ebd127c3
MD
794 pci1760_mbxrequest(dev, omb, imb);
795
796 omb[0] = 0x00;
ba23095c 797 omb[2] = CMD_EdgeIDICounters; /* set IDI up counters count edge */
ebd127c3
MD
798 pci1760_mbxrequest(dev, omb, imb);
799 devpriv->IDICntEdge = 0x00;
800
801 omb[0] = 0x00;
ba23095c 802 omb[2] = CMD_EnableIDIFilters; /* disable all digital in filters */
ebd127c3
MD
803 pci1760_mbxrequest(dev, omb, imb);
804 devpriv->IDIFiltersEn = 0x00;
805
806 omb[0] = 0x00;
ba23095c 807 omb[2] = CMD_EnableIDIPatternMatch; /* disable pattern matching */
ebd127c3
MD
808 pci1760_mbxrequest(dev, omb, imb);
809 devpriv->IDIPatMatchEn = 0x00;
810
811 omb[0] = 0x00;
ba23095c 812 omb[2] = CMD_SetIDIPatternMatch; /* set pattern match value */
ebd127c3
MD
813 pci1760_mbxrequest(dev, omb, imb);
814 devpriv->IDIPatMatchValue = 0x00;
815
816 return 0;
817}
818
819/*
820==============================================================================
821*/
da91b269 822static int pci_dio_reset(struct comedi_device *dev)
ebd127c3
MD
823{
824 DPRINTK("adv_pci_dio EDBG: BGN: pci171x_reset(...)\n");
825
826 switch (this_board->cardtype) {
827 case TYPE_PCI1730:
ba23095c 828 outb(0, dev->iobase + PCI1730_DO); /* clear outputs */
ebd127c3
MD
829 outb(0, dev->iobase + PCI1730_DO + 1);
830 outb(0, dev->iobase + PCI1730_IDO);
831 outb(0, dev->iobase + PCI1730_IDO + 1);
832 /* NO break there! */
833 case TYPE_PCI1733:
3afbe13c
M
834 /* disable interrupts */
835 outb(0, dev->iobase + PCI1730_3_INT_EN);
836 /* clear interrupts */
837 outb(0x0f, dev->iobase + PCI1730_3_INT_CLR);
838 /* set rising edge trigger */
839 outb(0, dev->iobase + PCI1730_3_INT_RF);
ebd127c3
MD
840 break;
841 case TYPE_PCI1734:
ba23095c 842 outb(0, dev->iobase + PCI1734_IDO); /* clear outputs */
ebd127c3
MD
843 outb(0, dev->iobase + PCI1734_IDO + 1);
844 outb(0, dev->iobase + PCI1734_IDO + 2);
845 outb(0, dev->iobase + PCI1734_IDO + 3);
846 break;
d4da77a7
IA
847 case TYPE_PCI1735:
848 outb(0, dev->iobase + PCI1735_DO); /* clear outputs */
849 outb(0, dev->iobase + PCI1735_DO + 1);
850 outb(0, dev->iobase + PCI1735_DO + 2);
851 outb(0, dev->iobase + PCI1735_DO + 3);
852 i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 0, I8254_MODE0);
853 i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 1, I8254_MODE0);
854 i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 2, I8254_MODE0);
855 break;
ebd127c3
MD
856
857 case TYPE_PCI1736:
0a85b6f0
MT
858 outb(0, dev->iobase + PCI1736_IDO);
859 outb(0, dev->iobase + PCI1736_IDO + 1);
3afbe13c
M
860 /* disable interrupts */
861 outb(0, dev->iobase + PCI1736_3_INT_EN);
862 /* clear interrupts */
863 outb(0x0f, dev->iobase + PCI1736_3_INT_CLR);
864 /* set rising edge trigger */
865 outb(0, dev->iobase + PCI1736_3_INT_RF);
ebd127c3
MD
866 break;
867
9e77e6b6
IA
868 case TYPE_PCI1739:
869 /* disable & clear interrupts */
870 outb(0x88, dev->iobase + PCI1739_ICR);
871 break;
872
ebd127c3
MD
873 case TYPE_PCI1750:
874 case TYPE_PCI1751:
3afbe13c
M
875 /* disable & clear interrupts */
876 outb(0x88, dev->iobase + PCI1750_ICR);
ebd127c3
MD
877 break;
878 case TYPE_PCI1752:
3afbe13c
M
879 outw(0, dev->iobase + PCI1752_6_CFC); /* disable channel freeze
880 * function */
ba23095c 881 outw(0, dev->iobase + PCI1752_IDO); /* clear outputs */
ebd127c3
MD
882 outw(0, dev->iobase + PCI1752_IDO + 2);
883 outw(0, dev->iobase + PCI1752_IDO2);
884 outw(0, dev->iobase + PCI1752_IDO2 + 2);
885 break;
886 case TYPE_PCI1753E:
3afbe13c
M
887 outb(0x88, dev->iobase + PCI1753E_ICR0); /* disable & clear
888 * interrupts */
ebd127c3
MD
889 outb(0x80, dev->iobase + PCI1753E_ICR1);
890 outb(0x80, dev->iobase + PCI1753E_ICR2);
891 outb(0x80, dev->iobase + PCI1753E_ICR3);
892 /* NO break there! */
893 case TYPE_PCI1753:
3afbe13c
M
894 outb(0x88, dev->iobase + PCI1753_ICR0); /* disable & clear
895 * interrupts */
ebd127c3
MD
896 outb(0x80, dev->iobase + PCI1753_ICR1);
897 outb(0x80, dev->iobase + PCI1753_ICR2);
898 outb(0x80, dev->iobase + PCI1753_ICR3);
899 break;
900 case TYPE_PCI1754:
3afbe13c
M
901 outw(0x08, dev->iobase + PCI1754_6_ICR0); /* disable and clear
902 * interrupts */
ebd127c3
MD
903 outw(0x08, dev->iobase + PCI1754_6_ICR1);
904 outw(0x08, dev->iobase + PCI1754_ICR2);
905 outw(0x08, dev->iobase + PCI1754_ICR3);
906 break;
907 case TYPE_PCI1756:
3afbe13c
M
908 outw(0, dev->iobase + PCI1752_6_CFC); /* disable channel freeze
909 * function */
910 outw(0x08, dev->iobase + PCI1754_6_ICR0); /* disable and clear
911 * interrupts */
ebd127c3 912 outw(0x08, dev->iobase + PCI1754_6_ICR1);
ba23095c 913 outw(0, dev->iobase + PCI1756_IDO); /* clear outputs */
ebd127c3
MD
914 outw(0, dev->iobase + PCI1756_IDO + 2);
915 break;
916 case TYPE_PCI1760:
917 pci1760_reset(dev);
918 break;
919 case TYPE_PCI1762:
3afbe13c
M
920 outw(0x0101, dev->iobase + PCI1762_ICR); /* disable & clear
921 * interrupts */
ebd127c3
MD
922 break;
923 }
924
925 DPRINTK("adv_pci_dio EDBG: END: pci171x_reset(...)\n");
926
927 return 0;
928}
929
930/*
931==============================================================================
932*/
0a85b6f0
MT
933static int pci1760_attach(struct comedi_device *dev,
934 struct comedi_devconfig *it)
ebd127c3 935{
34c43922 936 struct comedi_subdevice *s;
ebd127c3
MD
937 int subdev = 0;
938
939 s = dev->subdevices + subdev;
940 s->type = COMEDI_SUBD_DI;
941 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
942 s->n_chan = 8;
943 s->maxdata = 1;
944 s->len_chanlist = 8;
945 s->range_table = &range_digital;
946 s->insn_bits = pci1760_insn_bits_di;
947 subdev++;
948
949 s = dev->subdevices + subdev;
950 s->type = COMEDI_SUBD_DO;
951 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
952 s->n_chan = 8;
953 s->maxdata = 1;
954 s->len_chanlist = 8;
955 s->range_table = &range_digital;
956 s->state = 0;
957 s->insn_bits = pci1760_insn_bits_do;
958 subdev++;
959
960 s = dev->subdevices + subdev;
961 s->type = COMEDI_SUBD_TIMER;
962 s->subdev_flags = SDF_WRITABLE | SDF_LSAMPL;
963 s->n_chan = 2;
964 s->maxdata = 0xffffffff;
965 s->len_chanlist = 2;
ba23095c 966/* s->insn_config=pci1760_insn_pwm_cfg; */
ebd127c3
MD
967 subdev++;
968
969 s = dev->subdevices + subdev;
970 s->type = COMEDI_SUBD_COUNTER;
971 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
972 s->n_chan = 8;
973 s->maxdata = 0xffff;
974 s->len_chanlist = 8;
975 s->insn_read = pci1760_insn_cnt_read;
976 s->insn_write = pci1760_insn_cnt_write;
ba23095c 977/* s->insn_config=pci1760_insn_cnt_cfg; */
ebd127c3
MD
978 subdev++;
979
980 return 0;
981}
982
983/*
984==============================================================================
985*/
da91b269 986static int pci_dio_add_di(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 987 const struct diosubd_data *d, int subdev)
ebd127c3
MD
988{
989 s->type = COMEDI_SUBD_DI;
990 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | d->specflags;
991 if (d->chans > 16)
992 s->subdev_flags |= SDF_LSAMPL;
993 s->n_chan = d->chans;
994 s->maxdata = 1;
995 s->len_chanlist = d->chans;
996 s->range_table = &range_digital;
997 switch (this_board->io_access) {
998 case IO_8b:
999 s->insn_bits = pci_dio_insn_bits_di_b;
1000 break;
1001 case IO_16b:
1002 s->insn_bits = pci_dio_insn_bits_di_w;
1003 break;
1004 }
1005 s->private = (void *)d;
1006
1007 return 0;
1008}
1009
1010/*
1011==============================================================================
1012*/
da91b269 1013static int pci_dio_add_do(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 1014 const struct diosubd_data *d, int subdev)
ebd127c3
MD
1015{
1016 s->type = COMEDI_SUBD_DO;
1017 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1018 if (d->chans > 16)
1019 s->subdev_flags |= SDF_LSAMPL;
1020 s->n_chan = d->chans;
1021 s->maxdata = 1;
1022 s->len_chanlist = d->chans;
1023 s->range_table = &range_digital;
1024 s->state = 0;
1025 switch (this_board->io_access) {
1026 case IO_8b:
1027 s->insn_bits = pci_dio_insn_bits_do_b;
1028 break;
1029 case IO_16b:
1030 s->insn_bits = pci_dio_insn_bits_do_w;
1031 break;
1032 }
1033 s->private = (void *)d;
1034
1035 return 0;
1036}
1037
d4da77a7
IA
1038/*
1039==============================================================================
1040*/
1041static int pci_dio_add_8254(struct comedi_device *dev,
3afbe13c 1042 struct comedi_subdevice *s,
d4da77a7
IA
1043 const struct diosubd_data *d, int subdev)
1044{
1045 s->type = COMEDI_SUBD_COUNTER;
1046 s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
1047 s->n_chan = d->chans;
1048 s->maxdata = 65535;
1049 s->len_chanlist = d->chans;
1050 s->insn_read = pci_8254_insn_read;
1051 s->insn_write = pci_8254_insn_write;
1052 s->insn_config = pci_8254_insn_config;
1053 s->private = (void *)d;
1054
1055 return 0;
1056}
1057
ebd127c3
MD
1058/*
1059==============================================================================
1060*/
0a85b6f0
MT
1061static int CheckAndAllocCard(struct comedi_device *dev,
1062 struct comedi_devconfig *it,
1063 struct pci_dev *pcidev)
ebd127c3 1064{
4cb13356 1065 struct pci_dio_private *pr, *prev;
ebd127c3
MD
1066
1067 for (pr = pci_priv, prev = NULL; pr != NULL; prev = pr, pr = pr->next) {
402a01ae 1068 if (pr->pcidev == pcidev)
3afbe13c 1069 return 0; /* this card is used, look for another */
402a01ae 1070
ebd127c3
MD
1071 }
1072
1073 if (prev) {
1074 devpriv->prev = prev;
1075 prev->next = devpriv;
1076 } else {
1077 pci_priv = devpriv;
1078 }
1079
1080 devpriv->pcidev = pcidev;
1081
1082 return 1;
1083}
1084
0a85b6f0
MT
1085static int pci_dio_attach(struct comedi_device *dev,
1086 struct comedi_devconfig *it)
ebd127c3 1087{
34c43922 1088 struct comedi_subdevice *s;
ebd127c3
MD
1089 int ret, subdev, n_subdevices, i, j;
1090 unsigned long iobase;
20fb2280 1091 struct pci_dev *pcidev = NULL;
ebd127c3 1092
ebd127c3 1093
c3744138 1094 ret = alloc_private(dev, sizeof(struct pci_dio_private));
f15d651b 1095 if (ret < 0)
ebd127c3 1096 return -ENOMEM;
ebd127c3 1097
20fb2280 1098 for_each_pci_dev(pcidev) {
ba23095c 1099 /* loop through cards supported by this driver */
542038f4 1100 for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) {
ebd127c3
MD
1101 if (boardtypes[i].vendor_id != pcidev->vendor)
1102 continue;
1103 if (boardtypes[i].device_id != pcidev->device)
1104 continue;
ba23095c 1105 /* was a particular bus/slot requested? */
ebd127c3 1106 if (it->options[0] || it->options[1]) {
ba23095c 1107 /* are we on the wrong bus/slot? */
ebd127c3 1108 if (pcidev->bus->number != it->options[0] ||
0a85b6f0 1109 PCI_SLOT(pcidev->devfn) != it->options[1]) {
ebd127c3
MD
1110 continue;
1111 }
1112 }
1113 ret = CheckAndAllocCard(dev, it, pcidev);
0a85b6f0
MT
1114 if (ret != 1)
1115 continue;
ebd127c3
MD
1116 dev->board_ptr = boardtypes + i;
1117 break;
1118 }
1119 if (dev->board_ptr)
1120 break;
1121 }
1122
1123 if (!dev->board_ptr) {
f41ad667
IA
1124 dev_err(dev->class_dev,
1125 "Error: Requested type of the card was not found!\n");
ebd127c3
MD
1126 return -EIO;
1127 }
1128
c95dbeac 1129 if (comedi_pci_enable(pcidev, dev->driver->driver_name)) {
f41ad667
IA
1130 dev_err(dev->class_dev,
1131 "Error: Can't enable PCI device and request regions!\n");
ebd127c3
MD
1132 return -EIO;
1133 }
1134 iobase = pci_resource_start(pcidev, this_board->main_pci_region);
f41ad667 1135 dev_dbg(dev->class_dev, "b:s:f=%d:%d:%d, io=0x%4lx\n",
f15d651b
RM
1136 pcidev->bus->number, PCI_SLOT(pcidev->devfn),
1137 PCI_FUNC(pcidev->devfn), iobase);
ebd127c3
MD
1138
1139 dev->iobase = iobase;
1140 dev->board_name = this_board->name;
1141
1142 if (this_board->cardtype == TYPE_PCI1760) {
ba23095c 1143 n_subdevices = 4; /* 8 IDI, 8 IDO, 2 PWM, 8 CNT */
ebd127c3
MD
1144 } else {
1145 n_subdevices = 0;
1146 for (i = 0; i < MAX_DI_SUBDEVS; i++)
1147 if (this_board->sdi[i].chans)
1148 n_subdevices++;
1149 for (i = 0; i < MAX_DO_SUBDEVS; i++)
1150 if (this_board->sdo[i].chans)
1151 n_subdevices++;
1152 for (i = 0; i < MAX_DIO_SUBDEVG; i++)
1153 n_subdevices += this_board->sdio[i].regs;
1154 if (this_board->boardid.chans)
1155 n_subdevices++;
d4da77a7
IA
1156 for (i = 0; i < MAX_8254_SUBDEVS; i++)
1157 if (this_board->s8254[i].chans)
1158 n_subdevices++;
ebd127c3
MD
1159 }
1160
2f0b9d08 1161 ret = comedi_alloc_subdevices(dev, n_subdevices);
8b6c5694 1162 if (ret)
ebd127c3 1163 return ret;
ebd127c3
MD
1164
1165 subdev = 0;
ebd127c3
MD
1166 for (i = 0; i < MAX_DI_SUBDEVS; i++)
1167 if (this_board->sdi[i].chans) {
1168 s = dev->subdevices + subdev;
1169 pci_dio_add_di(dev, s, &this_board->sdi[i], subdev);
1170 subdev++;
1171 }
1172
1173 for (i = 0; i < MAX_DO_SUBDEVS; i++)
1174 if (this_board->sdo[i].chans) {
1175 s = dev->subdevices + subdev;
1176 pci_dio_add_do(dev, s, &this_board->sdo[i], subdev);
1177 subdev++;
1178 }
1179
1180 for (i = 0; i < MAX_DIO_SUBDEVG; i++)
1181 for (j = 0; j < this_board->sdio[i].regs; j++) {
1182 s = dev->subdevices + subdev;
1183 subdev_8255_init(dev, s, NULL,
0a85b6f0
MT
1184 dev->iobase +
1185 this_board->sdio[i].addr +
1186 SIZE_8255 * j);
ebd127c3
MD
1187 subdev++;
1188 }
1189
1190 if (this_board->boardid.chans) {
1191 s = dev->subdevices + subdev;
1192 s->type = COMEDI_SUBD_DI;
1193 pci_dio_add_di(dev, s, &this_board->boardid, subdev);
1194 subdev++;
1195 }
1196
d4da77a7
IA
1197 for (i = 0; i < MAX_8254_SUBDEVS; i++)
1198 if (this_board->s8254[i].chans) {
1199 s = dev->subdevices + subdev;
1200 pci_dio_add_8254(dev, s, &this_board->s8254[i], subdev);
1201 subdev++;
1202 }
1203
ebd127c3
MD
1204 if (this_board->cardtype == TYPE_PCI1760)
1205 pci1760_attach(dev, it);
1206
1207 devpriv->valid = 1;
1208
1209 pci_dio_reset(dev);
1210
1211 return 0;
1212}
1213
484ecc95 1214static void pci_dio_detach(struct comedi_device *dev)
ebd127c3
MD
1215{
1216 int i, j;
34c43922 1217 struct comedi_subdevice *s;
ebd127c3
MD
1218 int subdev;
1219
1220 if (dev->private) {
402a01ae 1221 if (devpriv->valid)
ebd127c3 1222 pci_dio_reset(dev);
ebd127c3
MD
1223 subdev = 0;
1224 for (i = 0; i < MAX_DI_SUBDEVS; i++) {
402a01ae 1225 if (this_board->sdi[i].chans)
ebd127c3 1226 subdev++;
ebd127c3
MD
1227 }
1228 for (i = 0; i < MAX_DO_SUBDEVS; i++) {
402a01ae 1229 if (this_board->sdo[i].chans)
ebd127c3 1230 subdev++;
ebd127c3
MD
1231 }
1232 for (i = 0; i < MAX_DIO_SUBDEVG; i++) {
1233 for (j = 0; j < this_board->sdio[i].regs; j++) {
1234 s = dev->subdevices + subdev;
1235 subdev_8255_cleanup(dev, s);
1236 subdev++;
1237 }
1238 }
3afbe13c 1239 if (this_board->boardid.chans)
d4da77a7 1240 subdev++;
3afbe13c
M
1241 for (i = 0; i < MAX_8254_SUBDEVS; i++)
1242 if (this_board->s8254[i].chans)
d4da77a7 1243 subdev++;
ebd127c3
MD
1244 for (i = 0; i < dev->n_subdevices; i++) {
1245 s = dev->subdevices + i;
1246 s->private = NULL;
1247 }
ebd127c3 1248 if (devpriv->pcidev) {
402a01ae 1249 if (dev->iobase)
ebd127c3 1250 comedi_pci_disable(devpriv->pcidev);
ebd127c3
MD
1251 pci_dev_put(devpriv->pcidev);
1252 }
402a01ae 1253 if (devpriv->prev)
ebd127c3 1254 devpriv->prev->next = devpriv->next;
402a01ae 1255 else
ebd127c3 1256 pci_priv = devpriv->next;
402a01ae 1257 if (devpriv->next)
ebd127c3 1258 devpriv->next->prev = devpriv->prev;
ebd127c3 1259 }
ebd127c3
MD
1260}
1261
c95dbeac
HS
1262static struct comedi_driver adv_pci_dio_driver = {
1263 .driver_name = "adv_pci_dio",
1264 .module = THIS_MODULE,
1265 .attach = pci_dio_attach,
1266 .detach = pci_dio_detach
1267};
1268
1269static int __devinit adv_pci_dio_pci_probe(struct pci_dev *dev,
1270 const struct pci_device_id *ent)
727b286b 1271{
c95dbeac 1272 return comedi_pci_auto_config(dev, &adv_pci_dio_driver);
727b286b
AT
1273}
1274
c95dbeac 1275static void __devexit adv_pci_dio_pci_remove(struct pci_dev *dev)
727b286b
AT
1276{
1277 comedi_pci_auto_unconfig(dev);
1278}
1279
c95dbeac
HS
1280static DEFINE_PCI_DEVICE_TABLE(adv_pci_dio_pci_table) = {
1281 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1730) },
1282 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1733) },
1283 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1734) },
1284 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1735) },
1285 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1736) },
1286 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1739) },
1287 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1750) },
1288 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1751) },
1289 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1752) },
1290 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1753) },
1291 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1754) },
1292 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1756) },
1293 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1760) },
1294 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1762) },
1295 { 0 }
727b286b 1296};
c95dbeac 1297MODULE_DEVICE_TABLE(pci, adv_pci_dio_pci_table);
727b286b 1298
c95dbeac
HS
1299static struct pci_driver adv_pci_dio_pci_driver = {
1300 .name = "adv_pci_dio",
1301 .id_table = adv_pci_dio_pci_table,
1302 .probe = adv_pci_dio_pci_probe,
1303 .remove = __devexit_p(adv_pci_dio_pci_remove),
1304};
1305module_comedi_pci_driver(adv_pci_dio_driver, adv_pci_dio_pci_driver);
90f703d3
AT
1306
1307MODULE_AUTHOR("Comedi http://www.comedi.org");
1308MODULE_DESCRIPTION("Comedi low-level driver");
1309MODULE_LICENSE("GPL");
This page took 0.460576 seconds and 5 git commands to generate.