diff options
author | David Kiliani <mail@davidkiliani.de> | 2008-10-31 19:39:12 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-01-06 16:52:29 -0500 |
commit | 3fedd14818592016f7ffd84dfe134881b3896ecf (patch) | |
tree | 22574873dc7d844d4cc33d04f7e6ba03f23c639e /drivers/staging/meilhaus/me4600_device.c | |
parent | 5ec5ec78060481e6a0cecc06ab0c6ec8b213ec80 (diff) |
Staging: Add the Meilhaus ME-IDS driver package
Originally written by Guenter Gebhardt <g.gebhardt@meilhaus.de>
and Krzysztof Gantzke <k.gantzke@meilhaus.de>
This is the drv/lnx/mod directory of ME-IDS 1.2.9 tarball with
some files from drv/lnx/include.
Signed-off-by: David Kiliani <mail@davidkiliani.de>
Cc: Guenter Gebhardt <g.gebhardt@meilhaus.de>
Cc: Krzysztof Gantzke <k.gantzke@meilhaus.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/meilhaus/me4600_device.c')
-rw-r--r-- | drivers/staging/meilhaus/me4600_device.c | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/drivers/staging/meilhaus/me4600_device.c b/drivers/staging/meilhaus/me4600_device.c new file mode 100644 index 00000000000..fa455844f4e --- /dev/null +++ b/drivers/staging/meilhaus/me4600_device.c | |||
@@ -0,0 +1,373 @@ | |||
1 | /** | ||
2 | * @file me4600_device.c | ||
3 | * | ||
4 | * @brief ME-4600 device class implementation. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | * @author Krzysztof Gantzke (k.gantzke@meilhaus.de) | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
12 | * | ||
13 | * This file is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
26 | */ | ||
27 | |||
28 | #ifndef __KERNEL__ | ||
29 | # define __KERNEL__ | ||
30 | #endif | ||
31 | |||
32 | #ifndef MODULE | ||
33 | # define MODULE | ||
34 | #endif | ||
35 | |||
36 | #include <linux/module.h> | ||
37 | |||
38 | #include <linux/pci.h> | ||
39 | #include <linux/slab.h> | ||
40 | |||
41 | #include "meids.h" | ||
42 | #include "meerror.h" | ||
43 | #include "mecommon.h" | ||
44 | #include "meinternal.h" | ||
45 | |||
46 | #include "medebug.h" | ||
47 | #include "medevice.h" | ||
48 | #include "me4600_device.h" | ||
49 | #include "meplx_reg.h" | ||
50 | |||
51 | #include "mefirmware.h" | ||
52 | |||
53 | #include "mesubdevice.h" | ||
54 | #include "me4600_do.h" | ||
55 | #include "me4600_di.h" | ||
56 | #include "me4600_dio.h" | ||
57 | #include "me8254.h" | ||
58 | #include "me4600_ai.h" | ||
59 | #include "me4600_ao.h" | ||
60 | #include "me4600_ext_irq.h" | ||
61 | |||
62 | /** | ||
63 | * @brief Global variable. | ||
64 | * This is working queue for runing a separate atask that will be responsible for work status (start, stop, timeouts). | ||
65 | */ | ||
66 | static struct workqueue_struct *me4600_workqueue; | ||
67 | |||
68 | #ifdef BOSCH | ||
69 | me_device_t *me4600_pci_constructor(struct pci_dev *pci_device, int me_bosch_fw) | ||
70 | #else //~BOSCH | ||
71 | me_device_t *me4600_pci_constructor(struct pci_dev *pci_device) | ||
72 | #endif //BOSCH | ||
73 | { | ||
74 | me4600_device_t *me4600_device; | ||
75 | me_subdevice_t *subdevice; | ||
76 | unsigned int version_idx; | ||
77 | int err; | ||
78 | int i; | ||
79 | |||
80 | PDEBUG("executed.\n"); | ||
81 | |||
82 | // Allocate structure for device instance. | ||
83 | me4600_device = kmalloc(sizeof(me4600_device_t), GFP_KERNEL); | ||
84 | |||
85 | if (!me4600_device) { | ||
86 | PERROR("Cannot get memory for ME-4600 device instance.\n"); | ||
87 | return NULL; | ||
88 | } | ||
89 | |||
90 | memset(me4600_device, 0, sizeof(me4600_device_t)); | ||
91 | |||
92 | // Initialize base class structure. | ||
93 | err = me_device_pci_init((me_device_t *) me4600_device, pci_device); | ||
94 | |||
95 | if (err) { | ||
96 | kfree(me4600_device); | ||
97 | PERROR("Cannot initialize device base class.\n"); | ||
98 | return NULL; | ||
99 | } | ||
100 | // Download the xilinx firmware. | ||
101 | if (me4600_device->base.info.pci.device_id == PCI_DEVICE_ID_MEILHAUS_ME4610) { //Jekyll <=> me4610 | ||
102 | err = | ||
103 | me_xilinx_download(me4600_device->base.info.pci. | ||
104 | reg_bases[1], | ||
105 | me4600_device->base.info.pci. | ||
106 | reg_bases[5], &pci_device->dev, | ||
107 | "me4610.bin"); | ||
108 | } else { // General me4600 firmware | ||
109 | #ifdef BOSCH | ||
110 | err = | ||
111 | me_xilinx_download(me4600_device->base.info.pci. | ||
112 | reg_bases[1], | ||
113 | me4600_device->base.info.pci. | ||
114 | reg_bases[5], &pci_device->dev, | ||
115 | (me_bosch_fw) ? "me4600_bosch.bin" : | ||
116 | "me4600.bin"); | ||
117 | #else //~BOSCH | ||
118 | err = | ||
119 | me_xilinx_download(me4600_device->base.info.pci. | ||
120 | reg_bases[1], | ||
121 | me4600_device->base.info.pci. | ||
122 | reg_bases[5], &pci_device->dev, | ||
123 | "me4600.bin"); | ||
124 | #endif | ||
125 | } | ||
126 | |||
127 | if (err) { | ||
128 | me_device_deinit((me_device_t *) me4600_device); | ||
129 | kfree(me4600_device); | ||
130 | PERROR("Cannot download firmware.\n"); | ||
131 | return NULL; | ||
132 | } | ||
133 | // Get the index in the device version information table. | ||
134 | version_idx = | ||
135 | me4600_versions_get_device_index(me4600_device->base.info.pci. | ||
136 | device_id); | ||
137 | |||
138 | // Initialize spin locks. | ||
139 | spin_lock_init(&me4600_device->preload_reg_lock); | ||
140 | |||
141 | me4600_device->preload_flags = 0; | ||
142 | |||
143 | spin_lock_init(&me4600_device->dio_lock); | ||
144 | spin_lock_init(&me4600_device->ai_ctrl_lock); | ||
145 | spin_lock_init(&me4600_device->ctr_ctrl_reg_lock); | ||
146 | spin_lock_init(&me4600_device->ctr_clk_src_reg_lock); | ||
147 | |||
148 | // Create digital input instances. | ||
149 | for (i = 0; i < me4600_versions[version_idx].di_subdevices; i++) { | ||
150 | subdevice = | ||
151 | (me_subdevice_t *) me4600_di_constructor(me4600_device-> | ||
152 | base.info.pci. | ||
153 | reg_bases[2], | ||
154 | &me4600_device-> | ||
155 | dio_lock); | ||
156 | |||
157 | if (!subdevice) { | ||
158 | me_device_deinit((me_device_t *) me4600_device); | ||
159 | kfree(me4600_device); | ||
160 | PERROR("Cannot get memory for subdevice.\n"); | ||
161 | return NULL; | ||
162 | } | ||
163 | |||
164 | me_slist_add_subdevice_tail(&me4600_device->base.slist, | ||
165 | subdevice); | ||
166 | } | ||
167 | |||
168 | // Create digital output instances. | ||
169 | for (i = 0; i < me4600_versions[version_idx].do_subdevices; i++) { | ||
170 | subdevice = | ||
171 | (me_subdevice_t *) me4600_do_constructor(me4600_device-> | ||
172 | base.info.pci. | ||
173 | reg_bases[2], | ||
174 | &me4600_device-> | ||
175 | dio_lock); | ||
176 | |||
177 | if (!subdevice) { | ||
178 | me_device_deinit((me_device_t *) me4600_device); | ||
179 | kfree(me4600_device); | ||
180 | PERROR("Cannot get memory for subdevice.\n"); | ||
181 | return NULL; | ||
182 | } | ||
183 | |||
184 | me_slist_add_subdevice_tail(&me4600_device->base.slist, | ||
185 | subdevice); | ||
186 | } | ||
187 | |||
188 | // Create digital input/output instances. | ||
189 | for (i = 0; i < me4600_versions[version_idx].dio_subdevices; i++) { | ||
190 | subdevice = | ||
191 | (me_subdevice_t *) me4600_dio_constructor(me4600_device-> | ||
192 | base.info.pci. | ||
193 | reg_bases[2], | ||
194 | me4600_versions | ||
195 | [version_idx]. | ||
196 | do_subdevices + | ||
197 | me4600_versions | ||
198 | [version_idx]. | ||
199 | di_subdevices + i, | ||
200 | &me4600_device-> | ||
201 | dio_lock); | ||
202 | |||
203 | if (!subdevice) { | ||
204 | me_device_deinit((me_device_t *) me4600_device); | ||
205 | kfree(me4600_device); | ||
206 | PERROR("Cannot get memory for subdevice.\n"); | ||
207 | return NULL; | ||
208 | } | ||
209 | |||
210 | me_slist_add_subdevice_tail(&me4600_device->base.slist, | ||
211 | subdevice); | ||
212 | } | ||
213 | |||
214 | // Create analog input instances. | ||
215 | for (i = 0; i < me4600_versions[version_idx].ai_subdevices; i++) { | ||
216 | subdevice = | ||
217 | (me_subdevice_t *) me4600_ai_constructor(me4600_device-> | ||
218 | base.info.pci. | ||
219 | reg_bases[2], | ||
220 | me4600_versions | ||
221 | [version_idx]. | ||
222 | ai_channels, | ||
223 | me4600_versions | ||
224 | [version_idx]. | ||
225 | ai_ranges, | ||
226 | me4600_versions | ||
227 | [version_idx]. | ||
228 | ai_isolated, | ||
229 | me4600_versions | ||
230 | [version_idx]. | ||
231 | ai_sh, | ||
232 | me4600_device-> | ||
233 | base.irq, | ||
234 | &me4600_device-> | ||
235 | ai_ctrl_lock, | ||
236 | me4600_workqueue); | ||
237 | |||
238 | if (!subdevice) { | ||
239 | me_device_deinit((me_device_t *) me4600_device); | ||
240 | kfree(me4600_device); | ||
241 | PERROR("Cannot get memory for subdevice.\n"); | ||
242 | return NULL; | ||
243 | } | ||
244 | |||
245 | me_slist_add_subdevice_tail(&me4600_device->base.slist, | ||
246 | subdevice); | ||
247 | } | ||
248 | |||
249 | // Create analog output instances. | ||
250 | for (i = 0; i < me4600_versions[version_idx].ao_subdevices; i++) { | ||
251 | #ifdef BOSCH | ||
252 | subdevice = | ||
253 | (me_subdevice_t *) me4600_ao_constructor(me4600_device-> | ||
254 | base.info.pci. | ||
255 | reg_bases[2], | ||
256 | &me4600_device-> | ||
257 | preload_reg_lock, | ||
258 | &me4600_device-> | ||
259 | preload_flags, i, | ||
260 | me4600_versions | ||
261 | [version_idx]. | ||
262 | ao_fifo, | ||
263 | me4600_device-> | ||
264 | base.irq); | ||
265 | #else //~BOSCH | ||
266 | subdevice = | ||
267 | (me_subdevice_t *) me4600_ao_constructor(me4600_device-> | ||
268 | base.info.pci. | ||
269 | reg_bases[2], | ||
270 | &me4600_device-> | ||
271 | preload_reg_lock, | ||
272 | &me4600_device-> | ||
273 | preload_flags, i, | ||
274 | me4600_versions | ||
275 | [version_idx]. | ||
276 | ao_fifo, | ||
277 | me4600_device-> | ||
278 | base.irq, | ||
279 | me4600_workqueue); | ||
280 | #endif | ||
281 | |||
282 | if (!subdevice) { | ||
283 | me_device_deinit((me_device_t *) me4600_device); | ||
284 | kfree(me4600_device); | ||
285 | PERROR("Cannot get memory for subdevice.\n"); | ||
286 | return NULL; | ||
287 | } | ||
288 | |||
289 | me_slist_add_subdevice_tail(&me4600_device->base.slist, | ||
290 | subdevice); | ||
291 | } | ||
292 | |||
293 | // Create counter instances. | ||
294 | for (i = 0; i < me4600_versions[version_idx].ctr_subdevices; i++) { | ||
295 | subdevice = | ||
296 | (me_subdevice_t *) me8254_constructor(me4600_device->base. | ||
297 | info.pci.device_id, | ||
298 | me4600_device->base. | ||
299 | info.pci.reg_bases[3], | ||
300 | 0, i, | ||
301 | &me4600_device-> | ||
302 | ctr_ctrl_reg_lock, | ||
303 | &me4600_device-> | ||
304 | ctr_clk_src_reg_lock); | ||
305 | |||
306 | if (!subdevice) { | ||
307 | me_device_deinit((me_device_t *) me4600_device); | ||
308 | kfree(me4600_device); | ||
309 | PERROR("Cannot get memory for subdevice.\n"); | ||
310 | return NULL; | ||
311 | } | ||
312 | |||
313 | me_slist_add_subdevice_tail(&me4600_device->base.slist, | ||
314 | subdevice); | ||
315 | } | ||
316 | |||
317 | // Create external interrupt instances. | ||
318 | for (i = 0; i < me4600_versions[version_idx].ext_irq_subdevices; i++) { | ||
319 | subdevice = | ||
320 | (me_subdevice_t *) | ||
321 | me4600_ext_irq_constructor(me4600_device->base.info.pci. | ||
322 | reg_bases[2], | ||
323 | me4600_device->base.irq, | ||
324 | &me4600_device->ai_ctrl_lock); | ||
325 | |||
326 | if (!subdevice) { | ||
327 | me_device_deinit((me_device_t *) me4600_device); | ||
328 | kfree(me4600_device); | ||
329 | PERROR("Cannot get memory for subdevice.\n"); | ||
330 | return NULL; | ||
331 | } | ||
332 | |||
333 | me_slist_add_subdevice_tail(&me4600_device->base.slist, | ||
334 | subdevice); | ||
335 | } | ||
336 | |||
337 | return (me_device_t *) me4600_device; | ||
338 | } | ||
339 | |||
340 | // Init and exit of module. | ||
341 | |||
342 | static int __init me4600_init(void) | ||
343 | { | ||
344 | PDEBUG("executed.\n"); | ||
345 | |||
346 | #ifndef BOSCH | ||
347 | me4600_workqueue = create_singlethread_workqueue("me4600"); | ||
348 | #endif | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | static void __exit me4600_exit(void) | ||
353 | { | ||
354 | PDEBUG("executed.\n"); | ||
355 | |||
356 | #ifndef BOSCH | ||
357 | flush_workqueue(me4600_workqueue); | ||
358 | destroy_workqueue(me4600_workqueue); | ||
359 | #endif | ||
360 | } | ||
361 | |||
362 | module_init(me4600_init); | ||
363 | module_exit(me4600_exit); | ||
364 | |||
365 | // Administrative stuff for modinfo. | ||
366 | MODULE_AUTHOR | ||
367 | ("Guenter Gebhardt <g.gebhardt@meilhaus.de> & Krzysztof Gantzke <k.gantzke@meilhaus.de>"); | ||
368 | MODULE_DESCRIPTION("Device Driver Module for ME-46xx Devices"); | ||
369 | MODULE_SUPPORTED_DEVICE("Meilhaus ME-46xx Devices"); | ||
370 | MODULE_LICENSE("GPL"); | ||
371 | |||
372 | // Export the constructor. | ||
373 | EXPORT_SYMBOL(me4600_pci_constructor); | ||