]>
Commit | Line | Data |
---|---|---|
e184e2be | 1 | // SPDX-License-Identifier: GPL-2.0+ |
87450c02 HS |
2 | /* |
3 | * addi_apci_1516.c | |
4 | * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. | |
5 | * Project manager: Eric Stolz | |
6 | * | |
7 | * ADDI-DATA GmbH | |
8 | * Dieselstrasse 3 | |
9 | * D-77833 Ottersweier | |
10 | * Tel: +19(0)7223/9493-0 | |
11 | * Fax: +49(0)7223/9493-92 | |
12 | * http://www.addi-data.com | |
13 | * info@addi-data.com | |
87450c02 HS |
14 | */ |
15 | ||
ce157f80 | 16 | #include <linux/module.h> |
33782dd5 | 17 | |
bfa3c585 | 18 | #include "../comedi_pci.h" |
1445ea15 | 19 | #include "addi_watchdog.h" |
3d41c443 | 20 | |
87450c02 | 21 | /* |
1567ceaa | 22 | * PCI bar 1 I/O Register map - Digital input/output |
87450c02 | 23 | */ |
1567ceaa HS |
24 | #define APCI1516_DI_REG 0x00 |
25 | #define APCI1516_DO_REG 0x04 | |
a29cd0ee | 26 | |
87450c02 | 27 | /* |
1567ceaa | 28 | * PCI bar 2 I/O Register map - Watchdog (APCI-1516 and APCI-2016) |
87450c02 | 29 | */ |
1567ceaa | 30 | #define APCI1516_WDOG_REG 0x00 |
317285d7 | 31 | |
852f3378 HS |
32 | enum apci1516_boardid { |
33 | BOARD_APCI1016, | |
34 | BOARD_APCI1516, | |
35 | BOARD_APCI2016, | |
36 | }; | |
37 | ||
e195bf80 HS |
38 | struct apci1516_boardinfo { |
39 | const char *name; | |
e195bf80 HS |
40 | int di_nchan; |
41 | int do_nchan; | |
07e95712 | 42 | int has_wdog; |
e195bf80 HS |
43 | }; |
44 | ||
45 | static const struct apci1516_boardinfo apci1516_boardtypes[] = { | |
852f3378 | 46 | [BOARD_APCI1016] = { |
e195bf80 | 47 | .name = "apci1016", |
e195bf80 | 48 | .di_nchan = 16, |
852f3378 HS |
49 | }, |
50 | [BOARD_APCI1516] = { | |
e195bf80 | 51 | .name = "apci1516", |
e195bf80 HS |
52 | .di_nchan = 8, |
53 | .do_nchan = 8, | |
07e95712 | 54 | .has_wdog = 1, |
852f3378 HS |
55 | }, |
56 | [BOARD_APCI2016] = { | |
e195bf80 | 57 | .name = "apci2016", |
e195bf80 | 58 | .do_nchan = 16, |
07e95712 | 59 | .has_wdog = 1, |
c0a053b8 HS |
60 | }, |
61 | }; | |
62 | ||
87450c02 HS |
63 | struct apci1516_private { |
64 | unsigned long wdog_iobase; | |
65 | }; | |
66 | ||
67 | static int apci1516_di_insn_bits(struct comedi_device *dev, | |
68 | struct comedi_subdevice *s, | |
69 | struct comedi_insn *insn, | |
70 | unsigned int *data) | |
71 | { | |
72 | data[1] = inw(dev->iobase + APCI1516_DI_REG); | |
73 | ||
74 | return insn->n; | |
75 | } | |
76 | ||
77 | static int apci1516_do_insn_bits(struct comedi_device *dev, | |
78 | struct comedi_subdevice *s, | |
79 | struct comedi_insn *insn, | |
80 | unsigned int *data) | |
81 | { | |
87450c02 | 82 | s->state = inw(dev->iobase + APCI1516_DO_REG); |
87450c02 | 83 | |
97f4289a | 84 | if (comedi_dio_update_state(s, data)) |
87450c02 | 85 | outw(s->state, dev->iobase + APCI1516_DO_REG); |
87450c02 HS |
86 | |
87 | data[1] = s->state; | |
88 | ||
89 | return insn->n; | |
90 | } | |
91 | ||
3b9323b4 | 92 | static int apci1516_reset(struct comedi_device *dev) |
049ff74c | 93 | { |
1867e04d | 94 | const struct apci1516_boardinfo *board = dev->board_ptr; |
a29cd0ee | 95 | struct apci1516_private *devpriv = dev->private; |
3b9323b4 | 96 | |
1867e04d | 97 | if (!board->has_wdog) |
722bf0f0 HS |
98 | return 0; |
99 | ||
d330b1da | 100 | outw(0x0, dev->iobase + APCI1516_DO_REG); |
1445ea15 HS |
101 | |
102 | addi_watchdog_reset(devpriv->wdog_iobase); | |
049ff74c | 103 | |
049ff74c HS |
104 | return 0; |
105 | } | |
106 | ||
a690b7e5 | 107 | static int apci1516_auto_attach(struct comedi_device *dev, |
852f3378 | 108 | unsigned long context) |
049ff74c HS |
109 | { |
110 | struct pci_dev *pcidev = comedi_to_pci_dev(dev); | |
1867e04d | 111 | const struct apci1516_boardinfo *board = NULL; |
a29cd0ee | 112 | struct apci1516_private *devpriv; |
049ff74c | 113 | struct comedi_subdevice *s; |
005ce48e | 114 | int ret; |
049ff74c | 115 | |
852f3378 | 116 | if (context < ARRAY_SIZE(apci1516_boardtypes)) |
1867e04d HS |
117 | board = &apci1516_boardtypes[context]; |
118 | if (!board) | |
049ff74c | 119 | return -ENODEV; |
1867e04d HS |
120 | dev->board_ptr = board; |
121 | dev->board_name = board->name; | |
049ff74c | 122 | |
0bdab509 | 123 | devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); |
049ff74c HS |
124 | if (!devpriv) |
125 | return -ENOMEM; | |
049ff74c | 126 | |
818f569f | 127 | ret = comedi_pci_enable(dev); |
049ff74c HS |
128 | if (ret) |
129 | return ret; | |
130 | ||
a3003b41 | 131 | dev->iobase = pci_resource_start(pcidev, 1); |
a29cd0ee | 132 | devpriv->wdog_iobase = pci_resource_start(pcidev, 2); |
049ff74c | 133 | |
005ce48e | 134 | ret = comedi_alloc_subdevices(dev, 3); |
049ff74c HS |
135 | if (ret) |
136 | return ret; | |
137 | ||
3f0732a7 | 138 | /* Initialize the digital input subdevice */ |
005ce48e | 139 | s = &dev->subdevices[0]; |
1867e04d | 140 | if (board->di_nchan) { |
5c7c8323 HS |
141 | s->type = COMEDI_SUBD_DI; |
142 | s->subdev_flags = SDF_READABLE; | |
1867e04d | 143 | s->n_chan = board->di_nchan; |
5c7c8323 HS |
144 | s->maxdata = 1; |
145 | s->range_table = &range_digital; | |
146 | s->insn_bits = apci1516_di_insn_bits; | |
049ff74c | 147 | } else { |
5c7c8323 | 148 | s->type = COMEDI_SUBD_UNUSED; |
049ff74c | 149 | } |
3f0732a7 HS |
150 | |
151 | /* Initialize the digital output subdevice */ | |
005ce48e | 152 | s = &dev->subdevices[1]; |
1867e04d | 153 | if (board->do_nchan) { |
5c7c8323 | 154 | s->type = COMEDI_SUBD_DO; |
ef49d832 | 155 | s->subdev_flags = SDF_WRITABLE; |
1867e04d | 156 | s->n_chan = board->do_nchan; |
5c7c8323 HS |
157 | s->maxdata = 1; |
158 | s->range_table = &range_digital; | |
159 | s->insn_bits = apci1516_do_insn_bits; | |
049ff74c | 160 | } else { |
5c7c8323 | 161 | s->type = COMEDI_SUBD_UNUSED; |
049ff74c HS |
162 | } |
163 | ||
3f0732a7 | 164 | /* Initialize the watchdog subdevice */ |
005ce48e | 165 | s = &dev->subdevices[2]; |
1867e04d | 166 | if (board->has_wdog) { |
1445ea15 HS |
167 | ret = addi_watchdog_init(s, devpriv->wdog_iobase); |
168 | if (ret) | |
169 | return ret; | |
049ff74c | 170 | } else { |
5c7c8323 | 171 | s->type = COMEDI_SUBD_UNUSED; |
049ff74c HS |
172 | } |
173 | ||
3b9323b4 | 174 | apci1516_reset(dev); |
049ff74c HS |
175 | return 0; |
176 | } | |
177 | ||
178 | static void apci1516_detach(struct comedi_device *dev) | |
179 | { | |
1445ea15 | 180 | if (dev->iobase) |
4bcf9593 | 181 | apci1516_reset(dev); |
aac307f9 | 182 | comedi_pci_detach(dev); |
049ff74c HS |
183 | } |
184 | ||
20a22b70 HS |
185 | static struct comedi_driver apci1516_driver = { |
186 | .driver_name = "addi_apci_1516", | |
187 | .module = THIS_MODULE, | |
049ff74c HS |
188 | .auto_attach = apci1516_auto_attach, |
189 | .detach = apci1516_detach, | |
20a22b70 HS |
190 | }; |
191 | ||
a690b7e5 | 192 | static int apci1516_pci_probe(struct pci_dev *dev, |
b8f4ac23 | 193 | const struct pci_device_id *id) |
20a22b70 | 194 | { |
b8f4ac23 | 195 | return comedi_pci_auto_config(dev, &apci1516_driver, id->driver_data); |
20a22b70 HS |
196 | } |
197 | ||
41e043fc | 198 | static const struct pci_device_id apci1516_pci_table[] = { |
852f3378 HS |
199 | { PCI_VDEVICE(ADDIDATA, 0x1000), BOARD_APCI1016 }, |
200 | { PCI_VDEVICE(ADDIDATA, 0x1001), BOARD_APCI1516 }, | |
201 | { PCI_VDEVICE(ADDIDATA, 0x1002), BOARD_APCI2016 }, | |
317285d7 HS |
202 | { 0 } |
203 | }; | |
20a22b70 | 204 | MODULE_DEVICE_TABLE(pci, apci1516_pci_table); |
317285d7 | 205 | |
20a22b70 HS |
206 | static struct pci_driver apci1516_pci_driver = { |
207 | .name = "addi_apci_1516", | |
208 | .id_table = apci1516_pci_table, | |
209 | .probe = apci1516_pci_probe, | |
9901a4d7 | 210 | .remove = comedi_pci_auto_unconfig, |
20a22b70 HS |
211 | }; |
212 | module_comedi_pci_driver(apci1516_driver, apci1516_pci_driver); | |
90f703d3 | 213 | |
be3c5126 | 214 | MODULE_DESCRIPTION("ADDI-DATA APCI-1016/1516/2016, 16 channel DIO boards"); |
58b1d3f8 | 215 | MODULE_AUTHOR("Comedi https://www.comedi.org"); |
90f703d3 | 216 | MODULE_LICENSE("GPL"); |