Commit | Line | Data |
---|---|---|
0ecb3ea9 HS |
1 | /* |
2 | * addi_apci_16xx.c | |
3 | * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. | |
4 | * Project manager: S. Weber | |
5 | * | |
6 | * ADDI-DATA GmbH | |
7 | * Dieselstrasse 3 | |
8 | * D-77833 Ottersweier | |
9 | * Tel: +19(0)7223/9493-0 | |
10 | * Fax: +49(0)7223/9493-92 | |
11 | * http://www.addi-data.com | |
12 | * info@addi-data.com | |
13 | * | |
14 | * This program is free software; you can redistribute it and/or modify it | |
15 | * under the terms of the GNU General Public License as published by the | |
16 | * Free Software Foundation; either version 2 of the License, or (at your | |
17 | * option) any later version. | |
18 | * | |
19 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
20 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
21 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
22 | * more details. | |
0ecb3ea9 HS |
23 | */ |
24 | ||
ce157f80 | 25 | #include <linux/module.h> |
33782dd5 HS |
26 | #include <linux/pci.h> |
27 | ||
3d41c443 | 28 | #include "../comedidev.h" |
3d41c443 | 29 | |
92eb3795 HS |
30 | /* |
31 | * Register I/O map | |
32 | */ | |
33 | #define APCI16XX_IN_REG(x) (((x) * 4) + 0x08) | |
34 | #define APCI16XX_OUT_REG(x) (((x) * 4) + 0x14) | |
35 | #define APCI16XX_DIR_REG(x) (((x) * 4) + 0x20) | |
317285d7 | 36 | |
a4732f35 HS |
37 | enum apci16xx_boardid { |
38 | BOARD_APCI1648, | |
39 | BOARD_APCI1696, | |
40 | }; | |
41 | ||
2a2e63dd HS |
42 | struct apci16xx_boardinfo { |
43 | const char *name; | |
2a2e63dd HS |
44 | int n_chan; |
45 | }; | |
46 | ||
47 | static const struct apci16xx_boardinfo apci16xx_boardtypes[] = { | |
a4732f35 | 48 | [BOARD_APCI1648] = { |
2a2e63dd | 49 | .name = "apci1648", |
92eb3795 | 50 | .n_chan = 48, /* 2 subdevices */ |
a4732f35 HS |
51 | }, |
52 | [BOARD_APCI1696] = { | |
2a2e63dd | 53 | .name = "apci1696", |
92eb3795 | 54 | .n_chan = 96, /* 3 subdevices */ |
c0a053b8 HS |
55 | }, |
56 | }; | |
57 | ||
92eb3795 HS |
58 | static int apci16xx_insn_config(struct comedi_device *dev, |
59 | struct comedi_subdevice *s, | |
60 | struct comedi_insn *insn, | |
61 | unsigned int *data) | |
62 | { | |
5dacadcc HS |
63 | unsigned int chan = CR_CHAN(insn->chanspec); |
64 | unsigned int mask; | |
65 | int ret; | |
66 | ||
67 | if (chan < 8) | |
68 | mask = 0x000000ff; | |
69 | else if (chan < 16) | |
70 | mask = 0x0000ff00; | |
71 | else if (chan < 24) | |
72 | mask = 0x00ff0000; | |
92eb3795 | 73 | else |
5dacadcc HS |
74 | mask = 0xff000000; |
75 | ||
76 | ret = comedi_dio_insn_config(dev, s, insn, data, mask); | |
77 | if (ret) | |
78 | return ret; | |
92eb3795 HS |
79 | |
80 | outl(s->io_bits, dev->iobase + APCI16XX_DIR_REG(s->index)); | |
81 | ||
82 | return insn->n; | |
83 | } | |
84 | ||
85 | static int apci16xx_dio_insn_bits(struct comedi_device *dev, | |
86 | struct comedi_subdevice *s, | |
87 | struct comedi_insn *insn, | |
88 | unsigned int *data) | |
89 | { | |
a485f4d6 | 90 | if (comedi_dio_update_state(s, data)) |
92eb3795 | 91 | outl(s->state, dev->iobase + APCI16XX_OUT_REG(s->index)); |
92eb3795 HS |
92 | |
93 | data[1] = inl(dev->iobase + APCI16XX_IN_REG(s->index)); | |
94 | ||
95 | return insn->n; | |
96 | } | |
97 | ||
36846332 | 98 | static int apci16xx_auto_attach(struct comedi_device *dev, |
a4732f35 | 99 | unsigned long context) |
36846332 HS |
100 | { |
101 | struct pci_dev *pcidev = comedi_to_pci_dev(dev); | |
a4732f35 | 102 | const struct apci16xx_boardinfo *board = NULL; |
36846332 | 103 | struct comedi_subdevice *s; |
92eb3795 HS |
104 | unsigned int n_subdevs; |
105 | unsigned int last; | |
106 | int i; | |
b6e7714c | 107 | int ret; |
36846332 | 108 | |
a4732f35 HS |
109 | if (context < ARRAY_SIZE(apci16xx_boardtypes)) |
110 | board = &apci16xx_boardtypes[context]; | |
0e2bd50b | 111 | if (!board) |
36846332 | 112 | return -ENODEV; |
0e2bd50b HS |
113 | dev->board_ptr = board; |
114 | dev->board_name = board->name; | |
36846332 | 115 | |
818f569f | 116 | ret = comedi_pci_enable(dev); |
36846332 HS |
117 | if (ret) |
118 | return ret; | |
119 | ||
ebea8c69 | 120 | dev->iobase = pci_resource_start(pcidev, 0); |
36846332 | 121 | |
92eb3795 HS |
122 | /* |
123 | * Work out the nubmer of subdevices needed to support all the | |
124 | * digital i/o channels on the board. Each subdevice supports | |
125 | * up to 32 channels. | |
126 | */ | |
127 | n_subdevs = board->n_chan / 32; | |
128 | if ((n_subdevs * 32) < board->n_chan) { | |
129 | last = board->n_chan - (n_subdevs * 32); | |
130 | n_subdevs++; | |
131 | } else { | |
132 | last = 0; | |
133 | } | |
134 | ||
135 | ret = comedi_alloc_subdevices(dev, n_subdevs); | |
36846332 HS |
136 | if (ret) |
137 | return ret; | |
138 | ||
92eb3795 HS |
139 | /* Initialize the TTL digital i/o subdevices */ |
140 | for (i = 0; i < n_subdevs; i++) { | |
141 | s = &dev->subdevices[i]; | |
142 | s->type = COMEDI_SUBD_DIO; | |
ef49d832 | 143 | s->subdev_flags = SDF_WRITABLE | SDF_READABLE; |
92eb3795 HS |
144 | s->n_chan = ((i * 32) < board->n_chan) ? 32 : last; |
145 | s->maxdata = 1; | |
146 | s->range_table = &range_digital; | |
147 | s->insn_config = apci16xx_insn_config; | |
148 | s->insn_bits = apci16xx_dio_insn_bits; | |
149 | ||
150 | /* Default all channels to inputs */ | |
151 | s->io_bits = 0; | |
152 | outl(s->io_bits, dev->iobase + APCI16XX_DIR_REG(i)); | |
153 | } | |
36846332 | 154 | |
36846332 HS |
155 | return 0; |
156 | } | |
157 | ||
20a22b70 HS |
158 | static struct comedi_driver apci16xx_driver = { |
159 | .driver_name = "addi_apci_16xx", | |
160 | .module = THIS_MODULE, | |
36846332 | 161 | .auto_attach = apci16xx_auto_attach, |
aac307f9 | 162 | .detach = comedi_pci_detach, |
20a22b70 HS |
163 | }; |
164 | ||
a690b7e5 | 165 | static int apci16xx_pci_probe(struct pci_dev *dev, |
b8f4ac23 | 166 | const struct pci_device_id *id) |
20a22b70 | 167 | { |
b8f4ac23 | 168 | return comedi_pci_auto_config(dev, &apci16xx_driver, id->driver_data); |
20a22b70 HS |
169 | } |
170 | ||
41e043fc | 171 | static const struct pci_device_id apci16xx_pci_table[] = { |
a4732f35 HS |
172 | { PCI_VDEVICE(ADDIDATA, 0x1009), BOARD_APCI1648 }, |
173 | { PCI_VDEVICE(ADDIDATA, 0x100a), BOARD_APCI1696 }, | |
317285d7 HS |
174 | { 0 } |
175 | }; | |
20a22b70 | 176 | MODULE_DEVICE_TABLE(pci, apci16xx_pci_table); |
317285d7 | 177 | |
20a22b70 HS |
178 | static struct pci_driver apci16xx_pci_driver = { |
179 | .name = "addi_apci_16xx", | |
180 | .id_table = apci16xx_pci_table, | |
181 | .probe = apci16xx_pci_probe, | |
9901a4d7 | 182 | .remove = comedi_pci_auto_unconfig, |
20a22b70 HS |
183 | }; |
184 | module_comedi_pci_driver(apci16xx_driver, apci16xx_pci_driver); | |
90f703d3 | 185 | |
5e72c174 | 186 | MODULE_DESCRIPTION("ADDI-DATA APCI-1648/1696, TTL I/O boards"); |
90f703d3 | 187 | MODULE_AUTHOR("Comedi http://www.comedi.org"); |
90f703d3 | 188 | MODULE_LICENSE("GPL"); |