Commit | Line | Data |
---|---|---|
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. | |
74409905 | 7 | */ |
ebd127c3 | 8 | |
74409905 HS |
9 | /* |
10 | * Driver: adv_pci_dio | |
11 | * Description: Advantech PCI-1730, PCI-1733, PCI-1734, PCI-1735U, | |
12 | * PCI-1736UP, PCI-1739U, PCI-1750, PCI-1751, PCI-1752, | |
13 | * PCI-1753/E, PCI-1754, PCI-1756, PCI-1762 | |
14 | * Devices: [Advantech] PCI-1730 (adv_pci_dio), PCI-1733, | |
15 | * PCI-1734, PCI-1735U, PCI-1736UP, PCI-1739U, PCI-1750, | |
16 | * PCI-1751, PCI-1752, PCI-1753, | |
17 | * PCI-1753+PCI-1753E, PCI-1754, PCI-1756, | |
18 | * PCI-1762 | |
19 | * Author: Michal Dobes <dobes@tesnet.cz> | |
20 | * Updated: Mon, 09 Jan 2012 12:40:46 +0000 | |
21 | * Status: untested | |
22 | * | |
23 | * Configuration Options: not applicable, uses PCI auto config | |
24 | */ | |
ebd127c3 | 25 | |
ce157f80 | 26 | #include <linux/module.h> |
ebd127c3 MD |
27 | #include <linux/delay.h> |
28 | ||
5f22dadd | 29 | #include "../comedi_pci.h" |
33782dd5 | 30 | |
ebd127c3 | 31 | #include "8255.h" |
1e1fe085 | 32 | #include "comedi_8254.h" |
ebd127c3 | 33 | |
a8f1152e BP |
34 | /* hardware types of the cards */ |
35 | enum hw_cards_id { | |
d4da77a7 | 36 | TYPE_PCI1730, TYPE_PCI1733, TYPE_PCI1734, TYPE_PCI1735, TYPE_PCI1736, |
9e77e6b6 | 37 | TYPE_PCI1739, |
ebd127c3 MD |
38 | TYPE_PCI1750, |
39 | TYPE_PCI1751, | |
40 | TYPE_PCI1752, | |
41 | TYPE_PCI1753, TYPE_PCI1753E, | |
42 | TYPE_PCI1754, TYPE_PCI1756, | |
ebd127c3 | 43 | TYPE_PCI1762 |
a8f1152e | 44 | }; |
ebd127c3 | 45 | |
ebd127c3 MD |
46 | #define MAX_DI_SUBDEVS 2 /* max number of DI subdevices per card */ |
47 | #define MAX_DO_SUBDEVS 2 /* max number of DO subdevices per card */ | |
3afbe13c M |
48 | #define MAX_DIO_SUBDEVG 2 /* max number of DIO subdevices group per |
49 | * card */ | |
ebd127c3 | 50 | |
86065e4d HS |
51 | /* |
52 | * Register offset definitions | |
53 | */ | |
54 | ||
55 | /* PCI-1730, PCI-1733, PCI-1736 interrupt control registers */ | |
56 | #define PCI173X_INT_EN_REG 0x08 /* R/W: enable/disable */ | |
57 | #define PCI173X_INT_RF_REG 0x0c /* R/W: falling/rising edge */ | |
58 | #define PCI173X_INT_CLR_REG 0x10 /* R/W: clear */ | |
ebd127c3 | 59 | |
db2c830d HS |
60 | /* PCI-1739U, PCI-1750, PCI1751 interrupt control registers */ |
61 | #define PCI1750_INT_REG 0x20 /* R/W: status/control */ | |
ebd127c3 | 62 | |
774a8c57 HS |
63 | /* PCI-1753, PCI-1753E interrupt control registers */ |
64 | #define PCI1753_INT_REG(x) (0x10 + (x)) /* R/W: control group 0 to 3 */ | |
65 | #define PCI1753E_INT_REG(x) (0x30 + (x)) /* R/W: control group 0 to 3 */ | |
ebd127c3 | 66 | |
008342eb HS |
67 | /* PCI-1754, PCI-1756 interrupt control registers */ |
68 | #define PCI1754_INT_REG(x) (0x08 + (x) * 2) /* R/W: control group 0 to 3 */ | |
69 | ||
6a1c0149 HS |
70 | /* PCI-1752, PCI-1756 special registers */ |
71 | #define PCI1752_CFC_REG 0x12 /* R/W: channel freeze function */ | |
ebd127c3 | 72 | |
ba23095c | 73 | /* Advantech PCI-1762 registers */ |
ebd127c3 MD |
74 | #define PCI1762_ICR 6 /* W: Interrupt control register */ |
75 | #define PCI1762_ISR 6 /* R: Interrupt status register */ | |
76 | ||
673bc56a | 77 | struct diosubd_data { |
039c5c1b | 78 | int chans; /* num of chans or 8255 devices */ |
66f516e6 | 79 | unsigned long addr; /* PCI address ofset */ |
673bc56a | 80 | }; |
ebd127c3 | 81 | |
dea1776a | 82 | struct dio_boardtype { |
ba23095c | 83 | const char *name; /* board name */ |
a8f1152e | 84 | enum hw_cards_id cardtype; |
4bf75257 | 85 | int nsubdevs; |
ba23095c BP |
86 | struct diosubd_data sdi[MAX_DI_SUBDEVS]; /* DI chans */ |
87 | struct diosubd_data sdo[MAX_DO_SUBDEVS]; /* DO chans */ | |
88 | struct diosubd_data sdio[MAX_DIO_SUBDEVG]; /* DIO 8255 chans */ | |
2001807e | 89 | unsigned long id_reg; |
0275299f | 90 | unsigned long timer_regbase; |
3cdddd63 | 91 | unsigned int is_16bit:1; |
dea1776a | 92 | }; |
ebd127c3 | 93 | |
dea1776a | 94 | static const struct dio_boardtype boardtypes[] = { |
87f6991b | 95 | [TYPE_PCI1730] = { |
59bd6752 | 96 | .name = "pci1730", |
59bd6752 | 97 | .cardtype = TYPE_PCI1730, |
4bf75257 | 98 | .nsubdevs = 5, |
e01b70bc HS |
99 | .sdi[0] = { 16, 0x02, }, /* DI 0-15 */ |
100 | .sdi[1] = { 16, 0x00, }, /* ISO DI 0-15 */ | |
7f442292 HS |
101 | .sdo[0] = { 16, 0x02, }, /* DO 0-15 */ |
102 | .sdo[1] = { 16, 0x00, }, /* ISO DO 0-15 */ | |
2001807e | 103 | .id_reg = 0x04, |
c0a0e0ca | 104 | }, |
87f6991b | 105 | [TYPE_PCI1733] = { |
59bd6752 | 106 | .name = "pci1733", |
59bd6752 | 107 | .cardtype = TYPE_PCI1733, |
4bf75257 | 108 | .nsubdevs = 2, |
e01b70bc | 109 | .sdi[1] = { 32, 0x00, }, /* ISO DI 0-31 */ |
2001807e | 110 | .id_reg = 0x04, |
c0a0e0ca | 111 | }, |
87f6991b | 112 | [TYPE_PCI1734] = { |
59bd6752 | 113 | .name = "pci1734", |
59bd6752 | 114 | .cardtype = TYPE_PCI1734, |
4bf75257 | 115 | .nsubdevs = 2, |
7f442292 | 116 | .sdo[1] = { 32, 0x00, }, /* ISO DO 0-31 */ |
2001807e | 117 | .id_reg = 0x04, |
c0a0e0ca | 118 | }, |
87f6991b | 119 | [TYPE_PCI1735] = { |
59bd6752 | 120 | .name = "pci1735", |
59bd6752 | 121 | .cardtype = TYPE_PCI1735, |
4bf75257 | 122 | .nsubdevs = 4, |
e01b70bc | 123 | .sdi[0] = { 32, 0x00, }, /* DI 0-31 */ |
7f442292 | 124 | .sdo[0] = { 32, 0x00, }, /* DO 0-31 */ |
2001807e | 125 | .id_reg = 0x08, |
d9d238d8 | 126 | .timer_regbase = 0x04, |
c0a0e0ca | 127 | }, |
87f6991b | 128 | [TYPE_PCI1736] = { |
59bd6752 | 129 | .name = "pci1736", |
59bd6752 | 130 | .cardtype = TYPE_PCI1736, |
4bf75257 | 131 | .nsubdevs = 3, |
e01b70bc | 132 | .sdi[1] = { 16, 0x00, }, /* ISO DI 0-15 */ |
7f442292 | 133 | .sdo[1] = { 16, 0x00, }, /* ISO DO 0-15 */ |
2001807e | 134 | .id_reg = 0x04, |
c0a0e0ca | 135 | }, |
87f6991b | 136 | [TYPE_PCI1739] = { |
59bd6752 | 137 | .name = "pci1739", |
59bd6752 | 138 | .cardtype = TYPE_PCI1739, |
2001807e | 139 | .nsubdevs = 3, |
4cabeb10 | 140 | .sdio[0] = { 2, 0x00, }, /* 8255 DIO */ |
2001807e | 141 | .id_reg = 0x08, |
c0a0e0ca | 142 | }, |
87f6991b | 143 | [TYPE_PCI1750] = { |
59bd6752 | 144 | .name = "pci1750", |
59bd6752 | 145 | .cardtype = TYPE_PCI1750, |
4bf75257 | 146 | .nsubdevs = 2, |
e01b70bc | 147 | .sdi[1] = { 16, 0x00, }, /* ISO DI 0-15 */ |
7f442292 | 148 | .sdo[1] = { 16, 0x00, }, /* ISO DO 0-15 */ |
c0a0e0ca | 149 | }, |
87f6991b | 150 | [TYPE_PCI1751] = { |
59bd6752 | 151 | .name = "pci1751", |
59bd6752 | 152 | .cardtype = TYPE_PCI1751, |
4bf75257 | 153 | .nsubdevs = 3, |
4cabeb10 | 154 | .sdio[0] = { 2, 0x00, }, /* 8255 DIO */ |
d9d238d8 | 155 | .timer_regbase = 0x18, |
c0a0e0ca | 156 | }, |
87f6991b | 157 | [TYPE_PCI1752] = { |
59bd6752 | 158 | .name = "pci1752", |
59bd6752 | 159 | .cardtype = TYPE_PCI1752, |
4bf75257 | 160 | .nsubdevs = 3, |
7f442292 HS |
161 | .sdo[0] = { 32, 0x00, }, /* DO 0-31 */ |
162 | .sdo[1] = { 32, 0x04, }, /* DO 32-63 */ | |
2001807e | 163 | .id_reg = 0x10, |
3cdddd63 | 164 | .is_16bit = 1, |
c0a0e0ca | 165 | }, |
87f6991b | 166 | [TYPE_PCI1753] = { |
59bd6752 | 167 | .name = "pci1753", |
59bd6752 | 168 | .cardtype = TYPE_PCI1753, |
4bf75257 | 169 | .nsubdevs = 4, |
4cabeb10 | 170 | .sdio[0] = { 4, 0x00, }, /* 8255 DIO */ |
87f6991b IA |
171 | }, |
172 | [TYPE_PCI1753E] = { | |
59bd6752 | 173 | .name = "pci1753e", |
59bd6752 | 174 | .cardtype = TYPE_PCI1753E, |
4bf75257 | 175 | .nsubdevs = 8, |
4cabeb10 HS |
176 | .sdio[0] = { 4, 0x00, }, /* 8255 DIO */ |
177 | .sdio[1] = { 4, 0x20, }, /* 8255 DIO */ | |
c0a0e0ca | 178 | }, |
87f6991b | 179 | [TYPE_PCI1754] = { |
59bd6752 | 180 | .name = "pci1754", |
59bd6752 | 181 | .cardtype = TYPE_PCI1754, |
4bf75257 | 182 | .nsubdevs = 3, |
e01b70bc HS |
183 | .sdi[0] = { 32, 0x00, }, /* DI 0-31 */ |
184 | .sdi[1] = { 32, 0x04, }, /* DI 32-63 */ | |
2001807e | 185 | .id_reg = 0x10, |
3cdddd63 | 186 | .is_16bit = 1, |
c0a0e0ca | 187 | }, |
87f6991b | 188 | [TYPE_PCI1756] = { |
59bd6752 | 189 | .name = "pci1756", |
59bd6752 | 190 | .cardtype = TYPE_PCI1756, |
4bf75257 | 191 | .nsubdevs = 3, |
e01b70bc | 192 | .sdi[1] = { 32, 0x00, }, /* DI 0-31 */ |
7f442292 | 193 | .sdo[1] = { 32, 0x04, }, /* DO 0-31 */ |
2001807e | 194 | .id_reg = 0x10, |
3cdddd63 | 195 | .is_16bit = 1, |
c0a0e0ca | 196 | }, |
87f6991b | 197 | [TYPE_PCI1762] = { |
59bd6752 | 198 | .name = "pci1762", |
59bd6752 | 199 | .cardtype = TYPE_PCI1762, |
4bf75257 | 200 | .nsubdevs = 3, |
e01b70bc | 201 | .sdi[1] = { 16, 0x02, }, /* ISO DI 0-15 */ |
7f442292 | 202 | .sdo[1] = { 16, 0x00, }, /* ISO DO 0-15 */ |
2001807e | 203 | .id_reg = 0x04, |
3cdddd63 | 204 | .is_16bit = 1, |
59bd6752 | 205 | }, |
ebd127c3 MD |
206 | }; |
207 | ||
0a85b6f0 MT |
208 | static int pci_dio_insn_bits_di_b(struct comedi_device *dev, |
209 | struct comedi_subdevice *s, | |
039c5c1b HS |
210 | struct comedi_insn *insn, |
211 | unsigned int *data) | |
ebd127c3 | 212 | { |
66f516e6 HS |
213 | unsigned long reg = (unsigned long)s->private; |
214 | unsigned long iobase = dev->iobase + reg; | |
ebd127c3 | 215 | |
039c5c1b HS |
216 | data[1] = inb(iobase); |
217 | if (s->n_chan > 8) | |
218 | data[1] |= (inb(iobase + 1) << 8); | |
219 | if (s->n_chan > 16) | |
220 | data[1] |= (inb(iobase + 2) << 16); | |
221 | if (s->n_chan > 24) | |
222 | data[1] |= (inb(iobase + 3) << 24); | |
402a01ae | 223 | |
a2714e3e | 224 | return insn->n; |
ebd127c3 MD |
225 | } |
226 | ||
0a85b6f0 MT |
227 | static int pci_dio_insn_bits_di_w(struct comedi_device *dev, |
228 | struct comedi_subdevice *s, | |
039c5c1b HS |
229 | struct comedi_insn *insn, |
230 | unsigned int *data) | |
ebd127c3 | 231 | { |
66f516e6 HS |
232 | unsigned long reg = (unsigned long)s->private; |
233 | unsigned long iobase = dev->iobase + reg; | |
ebd127c3 | 234 | |
039c5c1b HS |
235 | data[1] = inw(iobase); |
236 | if (s->n_chan > 16) | |
237 | data[1] |= (inw(iobase + 2) << 16); | |
ebd127c3 | 238 | |
a2714e3e | 239 | return insn->n; |
ebd127c3 MD |
240 | } |
241 | ||
0a85b6f0 MT |
242 | static int pci_dio_insn_bits_do_b(struct comedi_device *dev, |
243 | struct comedi_subdevice *s, | |
97f4289a HS |
244 | struct comedi_insn *insn, |
245 | unsigned int *data) | |
ebd127c3 | 246 | { |
66f516e6 HS |
247 | unsigned long reg = (unsigned long)s->private; |
248 | unsigned long iobase = dev->iobase + reg; | |
ebd127c3 | 249 | |
97f4289a | 250 | if (comedi_dio_update_state(s, data)) { |
039c5c1b HS |
251 | outb(s->state & 0xff, iobase); |
252 | if (s->n_chan > 8) | |
253 | outb((s->state >> 8) & 0xff, iobase + 1); | |
254 | if (s->n_chan > 16) | |
255 | outb((s->state >> 16) & 0xff, iobase + 2); | |
256 | if (s->n_chan > 24) | |
257 | outb((s->state >> 24) & 0xff, iobase + 3); | |
ebd127c3 | 258 | } |
97f4289a | 259 | |
ebd127c3 MD |
260 | data[1] = s->state; |
261 | ||
a2714e3e | 262 | return insn->n; |
ebd127c3 MD |
263 | } |
264 | ||
0a85b6f0 MT |
265 | static int pci_dio_insn_bits_do_w(struct comedi_device *dev, |
266 | struct comedi_subdevice *s, | |
97f4289a HS |
267 | struct comedi_insn *insn, |
268 | unsigned int *data) | |
ebd127c3 | 269 | { |
66f516e6 HS |
270 | unsigned long reg = (unsigned long)s->private; |
271 | unsigned long iobase = dev->iobase + reg; | |
ebd127c3 | 272 | |
97f4289a | 273 | if (comedi_dio_update_state(s, data)) { |
039c5c1b HS |
274 | outw(s->state & 0xffff, iobase); |
275 | if (s->n_chan > 16) | |
276 | outw((s->state >> 16) & 0xffff, iobase + 2); | |
ebd127c3 | 277 | } |
97f4289a | 278 | |
ebd127c3 MD |
279 | data[1] = s->state; |
280 | ||
a2714e3e | 281 | return insn->n; |
ebd127c3 MD |
282 | } |
283 | ||
da91b269 | 284 | static int pci_dio_reset(struct comedi_device *dev) |
ebd127c3 | 285 | { |
1a127f31 | 286 | const struct dio_boardtype *board = dev->board_ptr; |
242f5223 | 287 | |
c94a5991 HS |
288 | /* disable channel freeze function on the PCI-1752/1756 boards */ |
289 | if (board->cardtype == TYPE_PCI1752 || board->cardtype == TYPE_PCI1756) | |
6a1c0149 | 290 | outw(0, dev->iobase + PCI1752_CFC_REG); |
c94a5991 | 291 | |
ac67a3b9 | 292 | /* disable and clear interrupts */ |
1a127f31 | 293 | switch (board->cardtype) { |
ebd127c3 | 294 | case TYPE_PCI1730: |
ebd127c3 | 295 | case TYPE_PCI1733: |
ebd127c3 | 296 | case TYPE_PCI1736: |
86065e4d HS |
297 | outb(0, dev->iobase + PCI173X_INT_EN_REG); |
298 | outb(0x0f, dev->iobase + PCI173X_INT_CLR_REG); | |
299 | outb(0, dev->iobase + PCI173X_INT_RF_REG); | |
ebd127c3 | 300 | break; |
9e77e6b6 | 301 | case TYPE_PCI1739: |
ebd127c3 MD |
302 | case TYPE_PCI1750: |
303 | case TYPE_PCI1751: | |
db2c830d | 304 | outb(0x88, dev->iobase + PCI1750_INT_REG); |
ebd127c3 | 305 | break; |
ebd127c3 | 306 | case TYPE_PCI1753: |
774a8c57 HS |
307 | case TYPE_PCI1753E: |
308 | outb(0x88, dev->iobase + PCI1753_INT_REG(0)); | |
309 | outb(0x80, dev->iobase + PCI1753_INT_REG(1)); | |
310 | outb(0x80, dev->iobase + PCI1753_INT_REG(2)); | |
311 | outb(0x80, dev->iobase + PCI1753_INT_REG(3)); | |
312 | if (board->cardtype == TYPE_PCI1753E) { | |
313 | outb(0x88, dev->iobase + PCI1753E_INT_REG(0)); | |
314 | outb(0x80, dev->iobase + PCI1753E_INT_REG(1)); | |
315 | outb(0x80, dev->iobase + PCI1753E_INT_REG(2)); | |
316 | outb(0x80, dev->iobase + PCI1753E_INT_REG(3)); | |
317 | } | |
ebd127c3 MD |
318 | break; |
319 | case TYPE_PCI1754: | |
ebd127c3 | 320 | case TYPE_PCI1756: |
008342eb HS |
321 | outw(0x08, dev->iobase + PCI1754_INT_REG(0)); |
322 | outw(0x08, dev->iobase + PCI1754_INT_REG(1)); | |
323 | if (board->cardtype == TYPE_PCI1754) { | |
324 | outw(0x08, dev->iobase + PCI1754_INT_REG(2)); | |
325 | outw(0x08, dev->iobase + PCI1754_INT_REG(3)); | |
326 | } | |
ebd127c3 | 327 | break; |
ebd127c3 | 328 | case TYPE_PCI1762: |
ac67a3b9 | 329 | outw(0x0101, dev->iobase + PCI1762_ICR); |
ebd127c3 | 330 | break; |
eaf1e647 HS |
331 | default: |
332 | break; | |
ebd127c3 MD |
333 | } |
334 | ||
ebd127c3 MD |
335 | return 0; |
336 | } | |
337 | ||
87f6991b IA |
338 | static unsigned long pci_dio_override_cardtype(struct pci_dev *pcidev, |
339 | unsigned long cardtype) | |
340 | { | |
341 | /* | |
342 | * Change cardtype from TYPE_PCI1753 to TYPE_PCI1753E if expansion | |
343 | * board available. Need to enable PCI device and request the main | |
344 | * registers PCI BAR temporarily to perform the test. | |
345 | */ | |
346 | if (cardtype != TYPE_PCI1753) | |
347 | return cardtype; | |
348 | if (pci_enable_device(pcidev) < 0) | |
349 | return cardtype; | |
c1e07ea2 | 350 | if (pci_request_region(pcidev, 2, "adv_pci_dio") == 0) { |
87f6991b IA |
351 | /* |
352 | * This test is based on Advantech's "advdaq" driver source | |
353 | * (which declares its module licence as "GPL" although the | |
354 | * driver source does not include a "COPYING" file). | |
355 | */ | |
c1e07ea2 | 356 | unsigned long reg = pci_resource_start(pcidev, 2) + 53; |
87f6991b IA |
357 | |
358 | outb(0x05, reg); | |
359 | if ((inb(reg) & 0x07) == 0x02) { | |
360 | outb(0x02, reg); | |
361 | if ((inb(reg) & 0x07) == 0x05) | |
362 | cardtype = TYPE_PCI1753E; | |
363 | } | |
c1e07ea2 | 364 | pci_release_region(pcidev, 2); |
87f6991b IA |
365 | } |
366 | pci_disable_device(pcidev); | |
367 | return cardtype; | |
368 | } | |
369 | ||
a690b7e5 | 370 | static int pci_dio_auto_attach(struct comedi_device *dev, |
c0a0e0ca | 371 | unsigned long context) |
54b303c4 | 372 | { |
750af5e5 | 373 | struct pci_dev *pcidev = comedi_to_pci_dev(dev); |
1a127f31 | 374 | const struct dio_boardtype *board = NULL; |
a1132fc1 | 375 | const struct diosubd_data *d; |
54b303c4 | 376 | struct comedi_subdevice *s; |
4bf75257 | 377 | int ret, subdev, i, j; |
54b303c4 | 378 | |
c0a0e0ca | 379 | if (context < ARRAY_SIZE(boardtypes)) |
1a127f31 HS |
380 | board = &boardtypes[context]; |
381 | if (!board) | |
e5200165 | 382 | return -ENODEV; |
1a127f31 HS |
383 | dev->board_ptr = board; |
384 | dev->board_name = board->name; | |
e5200165 | 385 | |
818f569f | 386 | ret = comedi_pci_enable(dev); |
242f5223 HS |
387 | if (ret) |
388 | return ret; | |
c1e07ea2 HS |
389 | if (board->cardtype == TYPE_PCI1736) |
390 | dev->iobase = pci_resource_start(pcidev, 0); | |
391 | else | |
392 | dev->iobase = pci_resource_start(pcidev, 2); | |
ebd127c3 | 393 | |
42100e30 HS |
394 | pci_dio_reset(dev); |
395 | ||
1a127f31 | 396 | ret = comedi_alloc_subdevices(dev, board->nsubdevs); |
8b6c5694 | 397 | if (ret) |
ebd127c3 | 398 | return ret; |
ebd127c3 MD |
399 | |
400 | subdev = 0; | |
a1132fc1 HS |
401 | for (i = 0; i < MAX_DI_SUBDEVS; i++) { |
402 | d = &board->sdi[i]; | |
403 | if (d->chans) { | |
afe5c118 | 404 | s = &dev->subdevices[subdev++]; |
f5ceac9b HS |
405 | s->type = COMEDI_SUBD_DI; |
406 | s->subdev_flags = SDF_READABLE; | |
407 | s->n_chan = d->chans; | |
408 | s->maxdata = 1; | |
409 | s->range_table = &range_digital; | |
3cdddd63 HS |
410 | s->insn_bits = board->is_16bit |
411 | ? pci_dio_insn_bits_di_w | |
412 | : pci_dio_insn_bits_di_b; | |
66f516e6 | 413 | s->private = (void *)d->addr; |
ebd127c3 | 414 | } |
a1132fc1 | 415 | } |
ebd127c3 | 416 | |
a1132fc1 HS |
417 | for (i = 0; i < MAX_DO_SUBDEVS; i++) { |
418 | d = &board->sdo[i]; | |
419 | if (d->chans) { | |
afe5c118 | 420 | s = &dev->subdevices[subdev++]; |
ac93d19a HS |
421 | s->type = COMEDI_SUBD_DO; |
422 | s->subdev_flags = SDF_WRITABLE; | |
423 | s->n_chan = d->chans; | |
424 | s->maxdata = 1; | |
425 | s->range_table = &range_digital; | |
3cdddd63 HS |
426 | s->insn_bits = board->is_16bit |
427 | ? pci_dio_insn_bits_do_w | |
428 | : pci_dio_insn_bits_do_b; | |
66f516e6 | 429 | s->private = (void *)d->addr; |
d06ddc19 HS |
430 | |
431 | /* reset all outputs to 0 */ | |
432 | if (board->is_16bit) { | |
433 | outw(0, dev->iobase + d->addr); | |
434 | if (s->n_chan > 16) | |
435 | outw(0, dev->iobase + d->addr + 2); | |
436 | } else { | |
437 | outb(0, dev->iobase + d->addr); | |
438 | if (s->n_chan > 8) | |
439 | outb(0, dev->iobase + d->addr + 1); | |
440 | if (s->n_chan > 16) | |
441 | outb(0, dev->iobase + d->addr + 2); | |
442 | if (s->n_chan > 24) | |
443 | outb(0, dev->iobase + d->addr + 3); | |
444 | } | |
ebd127c3 | 445 | } |
a1132fc1 | 446 | } |
ebd127c3 | 447 | |
a1132fc1 HS |
448 | for (i = 0; i < MAX_DIO_SUBDEVG; i++) { |
449 | d = &board->sdio[i]; | |
039c5c1b | 450 | for (j = 0; j < d->chans; j++) { |
afe5c118 | 451 | s = &dev->subdevices[subdev++]; |
e6439a45 | 452 | ret = subdev_8255_init(dev, s, NULL, |
a1132fc1 | 453 | d->addr + j * I8255_SIZE); |
e6439a45 HS |
454 | if (ret) |
455 | return ret; | |
ebd127c3 | 456 | } |
a1132fc1 | 457 | } |
ebd127c3 | 458 | |
2001807e | 459 | if (board->id_reg) { |
afe5c118 | 460 | s = &dev->subdevices[subdev++]; |
f5ceac9b HS |
461 | s->type = COMEDI_SUBD_DI; |
462 | s->subdev_flags = SDF_READABLE | SDF_INTERNAL; | |
2001807e | 463 | s->n_chan = 4; |
f5ceac9b HS |
464 | s->maxdata = 1; |
465 | s->range_table = &range_digital; | |
3cdddd63 HS |
466 | s->insn_bits = board->is_16bit ? pci_dio_insn_bits_di_w |
467 | : pci_dio_insn_bits_di_b; | |
2001807e | 468 | s->private = (void *)board->id_reg; |
ebd127c3 MD |
469 | } |
470 | ||
1a127f31 | 471 | if (board->timer_regbase) { |
afe5c118 | 472 | s = &dev->subdevices[subdev++]; |
1e1fe085 HS |
473 | |
474 | dev->pacer = comedi_8254_init(dev->iobase + | |
1a127f31 | 475 | board->timer_regbase, |
1e1fe085 HS |
476 | 0, I8254_IO8, 0); |
477 | if (!dev->pacer) | |
478 | return -ENOMEM; | |
479 | ||
480 | comedi_8254_subdevice_init(s, dev->pacer); | |
50e338b9 | 481 | } |
d4da77a7 | 482 | |
ebd127c3 MD |
483 | return 0; |
484 | } | |
485 | ||
c95dbeac HS |
486 | static struct comedi_driver adv_pci_dio_driver = { |
487 | .driver_name = "adv_pci_dio", | |
488 | .module = THIS_MODULE, | |
750af5e5 | 489 | .auto_attach = pci_dio_auto_attach, |
4190c220 | 490 | .detach = comedi_pci_detach, |
c95dbeac HS |
491 | }; |
492 | ||
a690b7e5 | 493 | static int adv_pci_dio_pci_probe(struct pci_dev *dev, |
b8f4ac23 | 494 | const struct pci_device_id *id) |
727b286b | 495 | { |
87f6991b IA |
496 | unsigned long cardtype; |
497 | ||
498 | cardtype = pci_dio_override_cardtype(dev, id->driver_data); | |
499 | return comedi_pci_auto_config(dev, &adv_pci_dio_driver, cardtype); | |
727b286b AT |
500 | } |
501 | ||
41e043fc | 502 | static const struct pci_device_id adv_pci_dio_pci_table[] = { |
87f6991b IA |
503 | { PCI_VDEVICE(ADVANTECH, 0x1730), TYPE_PCI1730 }, |
504 | { PCI_VDEVICE(ADVANTECH, 0x1733), TYPE_PCI1733 }, | |
505 | { PCI_VDEVICE(ADVANTECH, 0x1734), TYPE_PCI1734 }, | |
506 | { PCI_VDEVICE(ADVANTECH, 0x1735), TYPE_PCI1735 }, | |
507 | { PCI_VDEVICE(ADVANTECH, 0x1736), TYPE_PCI1736 }, | |
508 | { PCI_VDEVICE(ADVANTECH, 0x1739), TYPE_PCI1739 }, | |
509 | { PCI_VDEVICE(ADVANTECH, 0x1750), TYPE_PCI1750 }, | |
510 | { PCI_VDEVICE(ADVANTECH, 0x1751), TYPE_PCI1751 }, | |
511 | { PCI_VDEVICE(ADVANTECH, 0x1752), TYPE_PCI1752 }, | |
512 | { PCI_VDEVICE(ADVANTECH, 0x1753), TYPE_PCI1753 }, | |
513 | { PCI_VDEVICE(ADVANTECH, 0x1754), TYPE_PCI1754 }, | |
514 | { PCI_VDEVICE(ADVANTECH, 0x1756), TYPE_PCI1756 }, | |
87f6991b | 515 | { PCI_VDEVICE(ADVANTECH, 0x1762), TYPE_PCI1762 }, |
c95dbeac | 516 | { 0 } |
727b286b | 517 | }; |
c95dbeac | 518 | MODULE_DEVICE_TABLE(pci, adv_pci_dio_pci_table); |
727b286b | 519 | |
c95dbeac HS |
520 | static struct pci_driver adv_pci_dio_pci_driver = { |
521 | .name = "adv_pci_dio", | |
522 | .id_table = adv_pci_dio_pci_table, | |
523 | .probe = adv_pci_dio_pci_probe, | |
9901a4d7 | 524 | .remove = comedi_pci_auto_unconfig, |
c95dbeac HS |
525 | }; |
526 | module_comedi_pci_driver(adv_pci_dio_driver, adv_pci_dio_pci_driver); | |
90f703d3 AT |
527 | |
528 | MODULE_AUTHOR("Comedi http://www.comedi.org"); | |
529 | MODULE_DESCRIPTION("Comedi low-level driver"); | |
530 | MODULE_LICENSE("GPL"); |