Commit | Line | Data |
---|---|---|
6a3734af HS |
1 | /* |
2 | * addi_apci_1032.c | |
3 | * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. | |
4 | * Project manager: Eric Stolz | |
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. | |
23 | * | |
24 | * You should have received a copy of the GNU General Public License along with | |
25 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
26 | * Place, Suite 330, Boston, MA 02111-1307 USA | |
27 | * | |
28 | * You should also find the complete GPL in the COPYING file accompanying this | |
29 | * source code. | |
30 | */ | |
31 | ||
3d41c443 HS |
32 | #include "../comedidev.h" |
33 | #include "comedi_fc.h" | |
bf36f012 | 34 | #include "amcc_s5933.h" |
3d41c443 HS |
35 | |
36 | #include "addi-data/addi_common.h" | |
3d41c443 | 37 | |
6a3734af HS |
38 | /* |
39 | * I/O Register Map | |
40 | */ | |
41 | #define APCI1032_DI_REG 0x00 | |
42 | #define APCI1032_MODE1_REG 0x04 | |
43 | #define APCI1032_MODE2_REG 0x08 | |
44 | #define APCI1032_STATUS_REG 0x0c | |
45 | #define APCI1032_CTRL_REG 0x10 | |
46 | #define APCI1032_CTRL_INT_OR (0 << 1) | |
47 | #define APCI1032_CTRL_INT_AND (1 << 1) | |
48 | #define APCI1032_CTRL_INT_ENA (1 << 2) | |
49 | ||
50 | /* Digital Input IRQ Function Selection */ | |
51 | #define ADDIDATA_OR 0 | |
52 | #define ADDIDATA_AND 1 | |
53 | ||
54 | static unsigned int ui_InterruptStatus; | |
55 | ||
56 | /* | |
57 | * data[0] : 1 Enable Digital Input Interrupt | |
58 | * 0 Disable Digital Input Interrupt | |
59 | * data[1] : 0 ADDIDATA Interrupt OR LOGIC | |
60 | * : 1 ADDIDATA Interrupt AND LOGIC | |
61 | * data[2] : Interrupt mask for the mode 1 | |
62 | * data[3] : Interrupt mask for the mode 2 | |
63 | */ | |
6835a17a HS |
64 | static int apci1032_intr_insn_config(struct comedi_device *dev, |
65 | struct comedi_subdevice *s, | |
66 | struct comedi_insn *insn, | |
67 | unsigned int *data) | |
6a3734af | 68 | { |
6a3734af HS |
69 | unsigned int ui_TmpValue; |
70 | unsigned int ul_Command1 = 0; | |
71 | unsigned int ul_Command2 = 0; | |
72 | ||
6a3734af HS |
73 | /*******************************/ |
74 | /* Set the digital input logic */ | |
75 | /*******************************/ | |
76 | if (data[0] == ADDIDATA_ENABLE) { | |
77 | ul_Command1 = ul_Command1 | data[2]; | |
78 | ul_Command2 = ul_Command2 | data[3]; | |
79 | outl(ul_Command1, dev->iobase + APCI1032_MODE1_REG); | |
80 | outl(ul_Command2, dev->iobase + APCI1032_MODE2_REG); | |
81 | if (data[1] == ADDIDATA_OR) { | |
82 | outl(APCI1032_CTRL_INT_ENA | | |
83 | APCI1032_CTRL_INT_OR, | |
84 | dev->iobase + APCI1032_CTRL_REG); | |
85 | ui_TmpValue = | |
86 | inl(dev->iobase + APCI1032_CTRL_REG); | |
87 | } /* if (data[1] == ADDIDATA_OR) */ | |
88 | else | |
89 | outl(APCI1032_CTRL_INT_ENA | | |
90 | APCI1032_CTRL_INT_AND, | |
91 | dev->iobase + APCI1032_CTRL_REG); | |
92 | /* else if(data[1] == ADDIDATA_OR) */ | |
93 | } /* if( data[0] == ADDIDATA_ENABLE) */ | |
94 | else { | |
95 | ul_Command1 = ul_Command1 & 0xFFFF0000; | |
96 | ul_Command2 = ul_Command2 & 0xFFFF0000; | |
97 | outl(ul_Command1, dev->iobase + APCI1032_MODE1_REG); | |
98 | outl(ul_Command2, dev->iobase + APCI1032_MODE2_REG); | |
99 | outl(0x0, dev->iobase + APCI1032_CTRL_REG); | |
100 | } /* else if ( data[0] == ADDIDATA_ENABLE) */ | |
101 | ||
102 | return insn->n; | |
103 | } | |
2bb8b1df | 104 | |
12d606f7 | 105 | static irqreturn_t apci1032_interrupt(int irq, void *d) |
2bb8b1df | 106 | { |
12d606f7 | 107 | struct comedi_device *dev = d; |
12d606f7 HS |
108 | unsigned int ctrl; |
109 | ||
110 | /* disable the interrupt */ | |
111 | ctrl = inl(dev->iobase + APCI1032_CTRL_REG); | |
112 | outl(ctrl & ~APCI1032_CTRL_INT_ENA, dev->iobase + APCI1032_CTRL_REG); | |
113 | ||
114 | ui_InterruptStatus = inl(dev->iobase + APCI1032_STATUS_REG); | |
115 | ui_InterruptStatus = ui_InterruptStatus & 0X0000FFFF; | |
12d606f7 HS |
116 | |
117 | /* enable the interrupt */ | |
118 | outl(ctrl, dev->iobase + APCI1032_CTRL_REG); | |
119 | ||
120 | return IRQ_HANDLED; | |
2bb8b1df HS |
121 | } |
122 | ||
a3de4cd3 HS |
123 | static int apci1032_di_insn_bits(struct comedi_device *dev, |
124 | struct comedi_subdevice *s, | |
125 | struct comedi_insn *insn, | |
126 | unsigned int *data) | |
127 | { | |
128 | data[1] = inl(dev->iobase + APCI1032_DI_REG); | |
129 | ||
130 | return insn->n; | |
131 | } | |
132 | ||
274113fd HS |
133 | static int apci1032_reset(struct comedi_device *dev) |
134 | { | |
135 | /* disable the interrupts */ | |
136 | outl(0x0, dev->iobase + APCI1032_CTRL_REG); | |
137 | /* Reset the interrupt status register */ | |
138 | inl(dev->iobase + APCI1032_STATUS_REG); | |
139 | /* Disable the and/or interrupt */ | |
140 | outl(0x0, dev->iobase + APCI1032_MODE1_REG); | |
141 | outl(0x0, dev->iobase + APCI1032_MODE2_REG); | |
142 | ||
143 | return 0; | |
144 | } | |
145 | ||
2bb8b1df HS |
146 | static int apci1032_attach_pci(struct comedi_device *dev, |
147 | struct pci_dev *pcidev) | |
148 | { | |
2bb8b1df | 149 | struct comedi_subdevice *s; |
b37f84d5 | 150 | int ret; |
2bb8b1df | 151 | |
ac467b5e | 152 | dev->board_name = dev->driver->driver_name; |
2bb8b1df | 153 | |
2bb8b1df HS |
154 | ret = comedi_pci_enable(pcidev, dev->board_name); |
155 | if (ret) | |
156 | return ret; | |
157 | ||
05f22ad7 | 158 | dev->iobase = pci_resource_start(pcidev, 2); |
2bb8b1df | 159 | |
2bb8b1df | 160 | if (pcidev->irq > 0) { |
12d606f7 | 161 | ret = request_irq(pcidev->irq, apci1032_interrupt, IRQF_SHARED, |
2bb8b1df HS |
162 | dev->board_name, dev); |
163 | if (ret == 0) | |
164 | dev->irq = pcidev->irq; | |
165 | } | |
166 | ||
6835a17a | 167 | ret = comedi_alloc_subdevices(dev, 2); |
2bb8b1df HS |
168 | if (ret) |
169 | return ret; | |
170 | ||
2bb8b1df | 171 | /* Allocate and Initialise DI Subdevice Structures */ |
b37f84d5 | 172 | s = &dev->subdevices[0]; |
4c2c1488 HS |
173 | s->type = COMEDI_SUBD_DI; |
174 | s->subdev_flags = SDF_READABLE; | |
175 | s->n_chan = 32; | |
176 | s->maxdata = 1; | |
177 | s->len_chanlist = 32; | |
178 | s->range_table = &range_digital; | |
a3de4cd3 | 179 | s->insn_bits = apci1032_di_insn_bits; |
5dbdbf67 | 180 | |
6835a17a HS |
181 | if (dev->irq) { |
182 | s = &dev->subdevices[1]; | |
183 | s->type = COMEDI_SUBD_DI; | |
184 | s->subdev_flags = SDF_READABLE; | |
185 | s->n_chan = 1; | |
186 | s->maxdata = 1; | |
187 | s->range_table = &range_digital; | |
188 | s->insn_config = apci1032_intr_insn_config; | |
189 | } | |
190 | ||
274113fd | 191 | apci1032_reset(dev); |
2bb8b1df HS |
192 | return 0; |
193 | } | |
194 | ||
195 | static void apci1032_detach(struct comedi_device *dev) | |
196 | { | |
197 | struct pci_dev *pcidev = comedi_to_pci_dev(dev); | |
2bb8b1df | 198 | |
14696bbe HS |
199 | if (dev->iobase) |
200 | apci1032_reset(dev); | |
201 | if (dev->irq) | |
202 | free_irq(dev->irq, dev); | |
2bb8b1df HS |
203 | if (pcidev) { |
204 | if (dev->iobase) | |
205 | comedi_pci_disable(pcidev); | |
206 | } | |
207 | } | |
208 | ||
20a22b70 HS |
209 | static struct comedi_driver apci1032_driver = { |
210 | .driver_name = "addi_apci_1032", | |
211 | .module = THIS_MODULE, | |
2bb8b1df HS |
212 | .attach_pci = apci1032_attach_pci, |
213 | .detach = apci1032_detach, | |
20a22b70 HS |
214 | }; |
215 | ||
216 | static int __devinit apci1032_pci_probe(struct pci_dev *dev, | |
217 | const struct pci_device_id *ent) | |
218 | { | |
219 | return comedi_pci_auto_config(dev, &apci1032_driver); | |
220 | } | |
221 | ||
222 | static void __devexit apci1032_pci_remove(struct pci_dev *dev) | |
223 | { | |
224 | comedi_pci_auto_unconfig(dev); | |
225 | } | |
226 | ||
227 | static DEFINE_PCI_DEVICE_TABLE(apci1032_pci_table) = { | |
317285d7 HS |
228 | { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1003) }, |
229 | { 0 } | |
230 | }; | |
20a22b70 | 231 | MODULE_DEVICE_TABLE(pci, apci1032_pci_table); |
317285d7 | 232 | |
20a22b70 HS |
233 | static struct pci_driver apci1032_pci_driver = { |
234 | .name = "addi_apci_1032", | |
235 | .id_table = apci1032_pci_table, | |
236 | .probe = apci1032_pci_probe, | |
237 | .remove = __devexit_p(apci1032_pci_remove), | |
238 | }; | |
239 | module_comedi_pci_driver(apci1032_driver, apci1032_pci_driver); | |
90f703d3 AT |
240 | |
241 | MODULE_AUTHOR("Comedi http://www.comedi.org"); | |
242 | MODULE_DESCRIPTION("Comedi low-level driver"); | |
243 | MODULE_LICENSE("GPL"); |