1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64#include <linux/module.h>
65
66#include "../comedi_pci.h"
67
68#include "8255.h"
69
70enum pci_8255_boardid {
71 BOARD_ADLINK_PCI7224,
72 BOARD_ADLINK_PCI7248,
73 BOARD_ADLINK_PCI7296,
74 BOARD_CB_PCIDIO24,
75 BOARD_CB_PCIDIO24H,
76 BOARD_CB_PCIDIO48H_OLD,
77 BOARD_CB_PCIDIO48H_NEW,
78 BOARD_CB_PCIDIO96H,
79 BOARD_NI_PCIDIO96,
80 BOARD_NI_PCIDIO96B,
81 BOARD_NI_PXI6508,
82 BOARD_NI_PCI6503,
83 BOARD_NI_PCI6503B,
84 BOARD_NI_PCI6503X,
85 BOARD_NI_PXI_6503,
86};
87
88struct pci_8255_boardinfo {
89 const char *name;
90 int dio_badr;
91 int n_8255;
92 unsigned int has_mite:1;
93};
94
95static const struct pci_8255_boardinfo pci_8255_boards[] = {
96 [BOARD_ADLINK_PCI7224] = {
97 .name = "adl_pci-7224",
98 .dio_badr = 2,
99 .n_8255 = 1,
100 },
101 [BOARD_ADLINK_PCI7248] = {
102 .name = "adl_pci-7248",
103 .dio_badr = 2,
104 .n_8255 = 2,
105 },
106 [BOARD_ADLINK_PCI7296] = {
107 .name = "adl_pci-7296",
108 .dio_badr = 2,
109 .n_8255 = 4,
110 },
111 [BOARD_CB_PCIDIO24] = {
112 .name = "cb_pci-dio24",
113 .dio_badr = 2,
114 .n_8255 = 1,
115 },
116 [BOARD_CB_PCIDIO24H] = {
117 .name = "cb_pci-dio24h",
118 .dio_badr = 2,
119 .n_8255 = 1,
120 },
121 [BOARD_CB_PCIDIO48H_OLD] = {
122 .name = "cb_pci-dio48h",
123 .dio_badr = 1,
124 .n_8255 = 2,
125 },
126 [BOARD_CB_PCIDIO48H_NEW] = {
127 .name = "cb_pci-dio48h",
128 .dio_badr = 2,
129 .n_8255 = 2,
130 },
131 [BOARD_CB_PCIDIO96H] = {
132 .name = "cb_pci-dio96h",
133 .dio_badr = 2,
134 .n_8255 = 4,
135 },
136 [BOARD_NI_PCIDIO96] = {
137 .name = "ni_pci-dio-96",
138 .dio_badr = 1,
139 .n_8255 = 4,
140 .has_mite = 1,
141 },
142 [BOARD_NI_PCIDIO96B] = {
143 .name = "ni_pci-dio-96b",
144 .dio_badr = 1,
145 .n_8255 = 4,
146 .has_mite = 1,
147 },
148 [BOARD_NI_PXI6508] = {
149 .name = "ni_pxi-6508",
150 .dio_badr = 1,
151 .n_8255 = 4,
152 .has_mite = 1,
153 },
154 [BOARD_NI_PCI6503] = {
155 .name = "ni_pci-6503",
156 .dio_badr = 1,
157 .n_8255 = 1,
158 .has_mite = 1,
159 },
160 [BOARD_NI_PCI6503B] = {
161 .name = "ni_pci-6503b",
162 .dio_badr = 1,
163 .n_8255 = 1,
164 .has_mite = 1,
165 },
166 [BOARD_NI_PCI6503X] = {
167 .name = "ni_pci-6503x",
168 .dio_badr = 1,
169 .n_8255 = 1,
170 .has_mite = 1,
171 },
172 [BOARD_NI_PXI_6503] = {
173 .name = "ni_pxi-6503",
174 .dio_badr = 1,
175 .n_8255 = 1,
176 .has_mite = 1,
177 },
178};
179
180
181#define MITE_IODWBSR 0xc0
182#define WENAB BIT(7)
183
184static int pci_8255_mite_init(struct pci_dev *pcidev)
185{
186 void __iomem *mite_base;
187 u32 main_phys_addr;
188
189
190 mite_base = pci_ioremap_bar(pcidev, 0);
191 if (!mite_base)
192 return -ENOMEM;
193
194
195 main_phys_addr = pci_resource_start(pcidev, 1);
196 writel(main_phys_addr | WENAB, mite_base + MITE_IODWBSR);
197
198
199 iounmap(mite_base);
200 return 0;
201}
202
203static int pci_8255_auto_attach(struct comedi_device *dev,
204 unsigned long context)
205{
206 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
207 const struct pci_8255_boardinfo *board = NULL;
208 struct comedi_subdevice *s;
209 int ret;
210 int i;
211
212 if (context < ARRAY_SIZE(pci_8255_boards))
213 board = &pci_8255_boards[context];
214 if (!board)
215 return -ENODEV;
216 dev->board_ptr = board;
217 dev->board_name = board->name;
218
219 ret = comedi_pci_enable(dev);
220 if (ret)
221 return ret;
222
223 if (board->has_mite) {
224 ret = pci_8255_mite_init(pcidev);
225 if (ret)
226 return ret;
227 }
228
229 if ((pci_resource_flags(pcidev, board->dio_badr) & IORESOURCE_MEM)) {
230 dev->mmio = pci_ioremap_bar(pcidev, board->dio_badr);
231 if (!dev->mmio)
232 return -ENOMEM;
233 } else {
234 dev->iobase = pci_resource_start(pcidev, board->dio_badr);
235 }
236
237
238
239
240
241
242 ret = comedi_alloc_subdevices(dev, board->n_8255);
243 if (ret)
244 return ret;
245
246 for (i = 0; i < board->n_8255; i++) {
247 s = &dev->subdevices[i];
248 if (dev->mmio)
249 ret = subdev_8255_mm_init(dev, s, NULL, i * I8255_SIZE);
250 else
251 ret = subdev_8255_init(dev, s, NULL, i * I8255_SIZE);
252 if (ret)
253 return ret;
254 }
255
256 return 0;
257}
258
259static struct comedi_driver pci_8255_driver = {
260 .driver_name = "8255_pci",
261 .module = THIS_MODULE,
262 .auto_attach = pci_8255_auto_attach,
263 .detach = comedi_pci_detach,
264};
265
266static int pci_8255_pci_probe(struct pci_dev *dev,
267 const struct pci_device_id *id)
268{
269 return comedi_pci_auto_config(dev, &pci_8255_driver, id->driver_data);
270}
271
272static const struct pci_device_id pci_8255_pci_table[] = {
273 { PCI_VDEVICE(ADLINK, 0x7224), BOARD_ADLINK_PCI7224 },
274 { PCI_VDEVICE(ADLINK, 0x7248), BOARD_ADLINK_PCI7248 },
275 { PCI_VDEVICE(ADLINK, 0x7296), BOARD_ADLINK_PCI7296 },
276 { PCI_VDEVICE(CB, 0x0028), BOARD_CB_PCIDIO24 },
277 { PCI_VDEVICE(CB, 0x0014), BOARD_CB_PCIDIO24H },
278 { PCI_DEVICE_SUB(PCI_VENDOR_ID_CB, 0x000b, 0x0000, 0x0000),
279 .driver_data = BOARD_CB_PCIDIO48H_OLD },
280 { PCI_DEVICE_SUB(PCI_VENDOR_ID_CB, 0x000b, PCI_VENDOR_ID_CB, 0x000b),
281 .driver_data = BOARD_CB_PCIDIO48H_NEW },
282 { PCI_VDEVICE(CB, 0x0017), BOARD_CB_PCIDIO96H },
283 { PCI_VDEVICE(NI, 0x0160), BOARD_NI_PCIDIO96 },
284 { PCI_VDEVICE(NI, 0x1630), BOARD_NI_PCIDIO96B },
285 { PCI_VDEVICE(NI, 0x13c0), BOARD_NI_PXI6508 },
286 { PCI_VDEVICE(NI, 0x0400), BOARD_NI_PCI6503 },
287 { PCI_VDEVICE(NI, 0x1250), BOARD_NI_PCI6503B },
288 { PCI_VDEVICE(NI, 0x17d0), BOARD_NI_PCI6503X },
289 { PCI_VDEVICE(NI, 0x1800), BOARD_NI_PXI_6503 },
290 { 0 }
291};
292MODULE_DEVICE_TABLE(pci, pci_8255_pci_table);
293
294static struct pci_driver pci_8255_pci_driver = {
295 .name = "8255_pci",
296 .id_table = pci_8255_pci_table,
297 .probe = pci_8255_pci_probe,
298 .remove = comedi_pci_auto_unconfig,
299};
300module_comedi_pci_driver(pci_8255_driver, pci_8255_pci_driver);
301
302MODULE_DESCRIPTION("COMEDI - Generic PCI based 8255 Digital I/O boards");
303MODULE_AUTHOR("Comedi http://www.comedi.org");
304MODULE_LICENSE("GPL");
305