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 | |
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')
133 files changed, 41371 insertions, 0 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index d8f26acf957b..a3e361db69fe 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig | |||
@@ -49,6 +49,8 @@ source "drivers/staging/sxg/Kconfig" | |||
49 | 49 | ||
50 | source "drivers/staging/me4000/Kconfig" | 50 | source "drivers/staging/me4000/Kconfig" |
51 | 51 | ||
52 | source "drivers/staging/meilhaus/Kconfig" | ||
53 | |||
52 | source "drivers/staging/go7007/Kconfig" | 54 | source "drivers/staging/go7007/Kconfig" |
53 | 55 | ||
54 | source "drivers/staging/usbip/Kconfig" | 56 | source "drivers/staging/usbip/Kconfig" |
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index dd9a625d46b9..06613bb05085 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile | |||
@@ -7,6 +7,7 @@ obj-$(CONFIG_ET131X) += et131x/ | |||
7 | obj-$(CONFIG_SLICOSS) += slicoss/ | 7 | obj-$(CONFIG_SLICOSS) += slicoss/ |
8 | obj-$(CONFIG_SXG) += sxg/ | 8 | obj-$(CONFIG_SXG) += sxg/ |
9 | obj-$(CONFIG_ME4000) += me4000/ | 9 | obj-$(CONFIG_ME4000) += me4000/ |
10 | obj-$(CONFIG_MEILHAUS) += meilhaus/ | ||
10 | obj-$(CONFIG_VIDEO_GO7007) += go7007/ | 11 | obj-$(CONFIG_VIDEO_GO7007) += go7007/ |
11 | obj-$(CONFIG_USB_IP_COMMON) += usbip/ | 12 | obj-$(CONFIG_USB_IP_COMMON) += usbip/ |
12 | obj-$(CONFIG_W35UND) += winbond/ | 13 | obj-$(CONFIG_W35UND) += winbond/ |
diff --git a/drivers/staging/meilhaus/Kconfig b/drivers/staging/meilhaus/Kconfig new file mode 100644 index 000000000000..6def83fa2c96 --- /dev/null +++ b/drivers/staging/meilhaus/Kconfig | |||
@@ -0,0 +1,127 @@ | |||
1 | # | ||
2 | # Meilhaus configuration | ||
3 | # | ||
4 | |||
5 | menuconfig MEILHAUS | ||
6 | tristate "Meilhaus support" | ||
7 | ---help--- | ||
8 | If you have a Meilhaus card, say Y (or M) here. | ||
9 | |||
10 | You need both this driver, and the driver for the particular | ||
11 | data collection card. | ||
12 | |||
13 | To compile this driver as a module, choose M here. The module will | ||
14 | be called memain. | ||
15 | |||
16 | if MEILHAUS | ||
17 | |||
18 | config ME0600 | ||
19 | tristate "Meilhaus ME-600 support" | ||
20 | default n | ||
21 | depends on PCI | ||
22 | help | ||
23 | This driver supports the Meilhaus ME-600 family of boards | ||
24 | that do data collection and multipurpose I/O. | ||
25 | |||
26 | To compile this driver as a module, choose M here: the module | ||
27 | will be called me0600. | ||
28 | |||
29 | config ME0900 | ||
30 | tristate "Meilhaus ME-900 support" | ||
31 | default n | ||
32 | depends on PCI | ||
33 | help | ||
34 | This driver supports the Meilhaus ME-900 family of boards | ||
35 | that do data collection and multipurpose I/O. | ||
36 | |||
37 | To compile this driver as a module, choose M here: the module | ||
38 | will be called me0900. | ||
39 | |||
40 | config ME1000 | ||
41 | tristate "Meilhaus ME-1000 support" | ||
42 | default n | ||
43 | depends on PCI | ||
44 | help | ||
45 | This driver supports the Meilhaus ME-1000 family of boards | ||
46 | that do data collection and multipurpose I/O. | ||
47 | |||
48 | To compile this driver as a module, choose M here: the module | ||
49 | will be called me1000. | ||
50 | |||
51 | config ME1400 | ||
52 | tristate "Meilhaus ME-1400 support" | ||
53 | default n | ||
54 | depends on PCI | ||
55 | help | ||
56 | This driver supports the Meilhaus ME-1400 family of boards | ||
57 | that do data collection and multipurpose I/O. | ||
58 | |||
59 | To compile this driver as a module, choose M here: the module | ||
60 | will be called me1400. | ||
61 | |||
62 | config ME1600 | ||
63 | tristate "Meilhaus ME-1600 support" | ||
64 | default n | ||
65 | depends on PCI | ||
66 | help | ||
67 | This driver supports the Meilhaus ME-1600 family of boards | ||
68 | that do data collection and multipurpose I/O. | ||
69 | |||
70 | To compile this driver as a module, choose M here: the module | ||
71 | will be called me1600. | ||
72 | |||
73 | config ME4600 | ||
74 | tristate "Meilhaus ME-4600 support" | ||
75 | default n | ||
76 | depends on PCI | ||
77 | help | ||
78 | This driver supports the Meilhaus ME-4600 family of boards | ||
79 | that do data collection and multipurpose I/O. | ||
80 | |||
81 | To compile this driver as a module, choose M here: the module | ||
82 | will be called me4600. | ||
83 | |||
84 | config ME6000 | ||
85 | tristate "Meilhaus ME-6000 support" | ||
86 | default n | ||
87 | depends on PCI | ||
88 | help | ||
89 | This driver supports the Meilhaus ME-6000 family of boards | ||
90 | that do data collection and multipurpose I/O. | ||
91 | |||
92 | To compile this driver as a module, choose M here: the module | ||
93 | will be called me6000. | ||
94 | |||
95 | config ME8100 | ||
96 | tristate "Meilhaus ME-8100 support" | ||
97 | default n | ||
98 | depends on PCI | ||
99 | help | ||
100 | This driver supports the Meilhaus ME-8100 family of boards | ||
101 | that do data collection and multipurpose I/O. | ||
102 | |||
103 | To compile this driver as a module, choose M here: the module | ||
104 | will be called me8100. | ||
105 | |||
106 | config ME8200 | ||
107 | tristate "Meilhaus ME-8200 support" | ||
108 | default n | ||
109 | depends on PCI | ||
110 | help | ||
111 | This driver supports the Meilhaus ME-8200 family of boards | ||
112 | that do data collection and multipurpose I/O. | ||
113 | |||
114 | To compile this driver as a module, choose M here: the module | ||
115 | will be called me8200. | ||
116 | |||
117 | config MEDUMMY | ||
118 | tristate "Meilhaus dummy driver" | ||
119 | default n | ||
120 | depends on PCI | ||
121 | help | ||
122 | This provides a dummy driver for the Meilhaus driver package | ||
123 | |||
124 | To compile this driver as a module, choose M here: the module | ||
125 | will be called medummy. | ||
126 | |||
127 | endif # MEILHAUS | ||
diff --git a/drivers/staging/meilhaus/Makefile b/drivers/staging/meilhaus/Makefile new file mode 100644 index 000000000000..5ab2c1c9c861 --- /dev/null +++ b/drivers/staging/meilhaus/Makefile | |||
@@ -0,0 +1,43 @@ | |||
1 | # | ||
2 | # Makefile for Meilhaus linux driver system | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_MEILHAUS) += memain.o | ||
6 | obj-$(CONFIG_ME1600) += me1600.o | ||
7 | obj-$(CONFIG_ME1000) += me1000.o | ||
8 | obj-$(CONFIG_ME1400) += me1400.o | ||
9 | obj-$(CONFIG_ME4600) += me4600.o | ||
10 | obj-$(CONFIG_ME6000) += me6000.o | ||
11 | obj-$(CONFIG_ME0600) += me0600.o | ||
12 | obj-$(CONFIG_ME8100) += me8100.o | ||
13 | obj-$(CONFIG_ME8200) += me8200.o | ||
14 | obj-$(CONFIG_ME0900) += me0900.o | ||
15 | obj-$(CONFIG_MEDUMMY) += medummy.o | ||
16 | |||
17 | |||
18 | me1600-objs := medevice.o medlist.o medlock.o me1600_device.o | ||
19 | me1600-objs += mesubdevice.o meslist.o meslock.o me1600_ao.o | ||
20 | |||
21 | me1000-objs := medevice.o medlist.o medlock.o me1000_device.o | ||
22 | me1000-objs += mesubdevice.o meslist.o meslock.o me1000_dio.o | ||
23 | |||
24 | me1400-objs := medevice.o medlist.o medlock.o me1400_device.o | ||
25 | me1400-objs += mesubdevice.o meslist.o meslock.o me8254.o me8255.o me1400_ext_irq.o | ||
26 | |||
27 | me4600-objs := medevice.o medlist.o medlock.o mefirmware.o me4600_device.o | ||
28 | me4600-objs += mesubdevice.o meslist.o meslock.o me4600_do.o me4600_di.o me4600_dio.o me8254.o me4600_ai.o me4600_ao.o me4600_ext_irq.o | ||
29 | |||
30 | me6000-objs := medevice.o medlist.o medlock.o mefirmware.o me6000_device.o | ||
31 | me6000-objs += mesubdevice.o meslist.o meslock.o me6000_dio.o me6000_ao.o | ||
32 | |||
33 | me0600-objs := medevice.o medlist.o medlock.o me0600_device.o | ||
34 | me0600-objs += mesubdevice.o meslist.o meslock.o me0600_relay.o me0600_ttli.o me0600_optoi.o me0600_dio.o me0600_ext_irq.o | ||
35 | |||
36 | me8100-objs := medevice.o medlist.o medlock.o me8100_device.o | ||
37 | me8100-objs += mesubdevice.o meslist.o meslock.o me8100_di.o me8100_do.o me8254.o | ||
38 | |||
39 | me8200-objs := medevice.o medlist.o medlock.o me8200_device.o | ||
40 | me8200-objs += mesubdevice.o meslist.o meslock.o me8200_di.o me8200_do.o me8200_dio.o | ||
41 | |||
42 | me0900-objs := medevice.o medlist.o medlock.o me0900_device.o | ||
43 | me0900-objs += mesubdevice.o meslist.o meslock.o me0900_do.o me0900_di.o | ||
diff --git a/drivers/staging/meilhaus/TODO b/drivers/staging/meilhaus/TODO new file mode 100644 index 000000000000..6ec25203089c --- /dev/null +++ b/drivers/staging/meilhaus/TODO | |||
@@ -0,0 +1,10 @@ | |||
1 | TODO: | ||
2 | - checkpatch.pl cleanups | ||
3 | - sparse issues | ||
4 | - Lindent | ||
5 | - audit userspace interface | ||
6 | - handle firmware properly | ||
7 | - possible comedi merge | ||
8 | |||
9 | Please send cleanup patches to Greg Kroah-Hartman <greg@kroah.com> | ||
10 | and CC: David Kiliani <mail@davidkiliani.de> | ||
diff --git a/drivers/staging/meilhaus/me0600_device.c b/drivers/staging/meilhaus/me0600_device.c new file mode 100644 index 000000000000..8950e47e0e86 --- /dev/null +++ b/drivers/staging/meilhaus/me0600_device.c | |||
@@ -0,0 +1,215 @@ | |||
1 | /** | ||
2 | * @file me0600_device.c | ||
3 | * | ||
4 | * @brief ME-630 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 "me0600_device.h" | ||
49 | #include "mesubdevice.h" | ||
50 | #include "me0600_relay.h" | ||
51 | #include "me0600_ttli.h" | ||
52 | #include "me0600_optoi.h" | ||
53 | #include "me0600_dio.h" | ||
54 | #include "me0600_ext_irq.h" | ||
55 | |||
56 | me_device_t *me0600_pci_constructor(struct pci_dev *pci_device) | ||
57 | { | ||
58 | me0600_device_t *me0600_device; | ||
59 | me_subdevice_t *subdevice; | ||
60 | unsigned int version_idx; | ||
61 | int err; | ||
62 | int i; | ||
63 | |||
64 | PDEBUG("executed.\n"); | ||
65 | |||
66 | // Allocate structure for device instance. | ||
67 | me0600_device = kmalloc(sizeof(me0600_device_t), GFP_KERNEL); | ||
68 | |||
69 | if (!me0600_device) { | ||
70 | PERROR("Cannot get memory for device instance.\n"); | ||
71 | return NULL; | ||
72 | } | ||
73 | |||
74 | memset(me0600_device, 0, sizeof(me0600_device_t)); | ||
75 | |||
76 | // Initialize base class structure. | ||
77 | err = me_device_pci_init((me_device_t *) me0600_device, pci_device); | ||
78 | |||
79 | if (err) { | ||
80 | kfree(me0600_device); | ||
81 | PERROR("Cannot initialize device base class.\n"); | ||
82 | return NULL; | ||
83 | } | ||
84 | |||
85 | /* Get the index in the device version information table. */ | ||
86 | version_idx = | ||
87 | me0600_versions_get_device_index(me0600_device->base.info.pci. | ||
88 | device_id); | ||
89 | |||
90 | // Initialize spin lock . | ||
91 | spin_lock_init(&me0600_device->dio_ctrl_reg_lock); | ||
92 | spin_lock_init(&me0600_device->intcsr_lock); | ||
93 | |||
94 | // Create subdevice instances. | ||
95 | |||
96 | for (i = 0; i < me0600_versions[version_idx].optoi_subdevices; i++) { | ||
97 | subdevice = | ||
98 | (me_subdevice_t *) me0600_optoi_constructor(me0600_device-> | ||
99 | base.info.pci. | ||
100 | reg_bases[2]); | ||
101 | |||
102 | if (!subdevice) { | ||
103 | me_device_deinit((me_device_t *) me0600_device); | ||
104 | kfree(me0600_device); | ||
105 | PERROR("Cannot get memory for subdevice.\n"); | ||
106 | return NULL; | ||
107 | } | ||
108 | |||
109 | me_slist_add_subdevice_tail(&me0600_device->base.slist, | ||
110 | subdevice); | ||
111 | } | ||
112 | |||
113 | for (i = 0; i < me0600_versions[version_idx].relay_subdevices; i++) { | ||
114 | subdevice = | ||
115 | (me_subdevice_t *) me0600_relay_constructor(me0600_device-> | ||
116 | base.info.pci. | ||
117 | reg_bases[2]); | ||
118 | |||
119 | if (!subdevice) { | ||
120 | me_device_deinit((me_device_t *) me0600_device); | ||
121 | kfree(me0600_device); | ||
122 | PERROR("Cannot get memory for subdevice.\n"); | ||
123 | return NULL; | ||
124 | } | ||
125 | |||
126 | me_slist_add_subdevice_tail(&me0600_device->base.slist, | ||
127 | subdevice); | ||
128 | } | ||
129 | |||
130 | for (i = 0; i < me0600_versions[version_idx].ttli_subdevices; i++) { | ||
131 | subdevice = | ||
132 | (me_subdevice_t *) me0600_ttli_constructor(me0600_device-> | ||
133 | base.info.pci. | ||
134 | reg_bases[2]); | ||
135 | |||
136 | if (!subdevice) { | ||
137 | me_device_deinit((me_device_t *) me0600_device); | ||
138 | kfree(me0600_device); | ||
139 | PERROR("Cannot get memory for subdevice.\n"); | ||
140 | return NULL; | ||
141 | } | ||
142 | |||
143 | me_slist_add_subdevice_tail(&me0600_device->base.slist, | ||
144 | subdevice); | ||
145 | } | ||
146 | |||
147 | for (i = 0; i < me0600_versions[version_idx].dio_subdevices; i++) { | ||
148 | subdevice = | ||
149 | (me_subdevice_t *) me0600_dio_constructor(me0600_device-> | ||
150 | base.info.pci. | ||
151 | reg_bases[2], i, | ||
152 | &me0600_device-> | ||
153 | dio_ctrl_reg_lock); | ||
154 | |||
155 | if (!subdevice) { | ||
156 | me_device_deinit((me_device_t *) me0600_device); | ||
157 | kfree(me0600_device); | ||
158 | PERROR("Cannot get memory for subdevice.\n"); | ||
159 | return NULL; | ||
160 | } | ||
161 | |||
162 | me_slist_add_subdevice_tail(&me0600_device->base.slist, | ||
163 | subdevice); | ||
164 | } | ||
165 | |||
166 | for (i = 0; i < me0600_versions[version_idx].ext_irq_subdevices; i++) { | ||
167 | subdevice = | ||
168 | (me_subdevice_t *) | ||
169 | me0600_ext_irq_constructor(me0600_device->base.info.pci. | ||
170 | reg_bases[1], | ||
171 | me0600_device->base.info.pci. | ||
172 | reg_bases[2], | ||
173 | &me0600_device->intcsr_lock, i, | ||
174 | me0600_device->base.irq); | ||
175 | |||
176 | if (!subdevice) { | ||
177 | me_device_deinit((me_device_t *) me0600_device); | ||
178 | kfree(me0600_device); | ||
179 | PERROR("Cannot get memory for subdevice.\n"); | ||
180 | return NULL; | ||
181 | } | ||
182 | |||
183 | me_slist_add_subdevice_tail(&me0600_device->base.slist, | ||
184 | subdevice); | ||
185 | } | ||
186 | |||
187 | return (me_device_t *) me0600_device; | ||
188 | } | ||
189 | |||
190 | // Init and exit of module. | ||
191 | |||
192 | static int __init me0600_init(void) | ||
193 | { | ||
194 | PDEBUG("executed.\n"); | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | static void __exit me0600_exit(void) | ||
199 | { | ||
200 | PDEBUG("executed.\n"); | ||
201 | } | ||
202 | |||
203 | module_init(me0600_init); | ||
204 | |||
205 | module_exit(me0600_exit); | ||
206 | |||
207 | // Administrative stuff for modinfo. | ||
208 | MODULE_AUTHOR | ||
209 | ("Guenter Gebhardt <g.gebhardt@meilhaus.de> & Krzysztof Gantzke <k.gantzke@meilhaus.de>"); | ||
210 | MODULE_DESCRIPTION("Device Driver Module for ME-6xx Device"); | ||
211 | MODULE_SUPPORTED_DEVICE("Meilhaus ME-6xx Devices"); | ||
212 | MODULE_LICENSE("GPL"); | ||
213 | |||
214 | // Export the constructor. | ||
215 | EXPORT_SYMBOL(me0600_pci_constructor); | ||
diff --git a/drivers/staging/meilhaus/me0600_device.h b/drivers/staging/meilhaus/me0600_device.h new file mode 100644 index 000000000000..d93a8aee581b --- /dev/null +++ b/drivers/staging/meilhaus/me0600_device.h | |||
@@ -0,0 +1,97 @@ | |||
1 | /** | ||
2 | * @file me0600_device.h | ||
3 | * | ||
4 | * @brief ME-630 device class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME0600_DEVICE_H | ||
28 | #define _ME0600_DEVICE_H | ||
29 | |||
30 | #include <linux/pci.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | |||
33 | #include "medevice.h" | ||
34 | |||
35 | #ifdef __KERNEL__ | ||
36 | |||
37 | /** | ||
38 | * @brief Structure holding ME-630 device capabilities. | ||
39 | */ | ||
40 | typedef struct me0600_version { | ||
41 | uint16_t device_id; | ||
42 | unsigned int relay_subdevices; | ||
43 | unsigned int ttli_subdevices; | ||
44 | unsigned int optoi_subdevices; | ||
45 | unsigned int dio_subdevices; | ||
46 | unsigned int ext_irq_subdevices; | ||
47 | } me0600_version_t; | ||
48 | |||
49 | /** | ||
50 | * @brief Device capabilities. | ||
51 | */ | ||
52 | static me0600_version_t me0600_versions[] = { | ||
53 | {PCI_DEVICE_ID_MEILHAUS_ME0630, 1, 1, 1, 2, 2}, | ||
54 | {0}, | ||
55 | }; | ||
56 | |||
57 | #define ME0600_DEVICE_VERSIONS (sizeof(me0600_versions) / sizeof(me0600_version_t) - 1) /**< Returns the number of entries in #me0600_versions. */ | ||
58 | |||
59 | /** | ||
60 | * @brief Returns the index of the device entry in #me0600_versions. | ||
61 | * | ||
62 | * @param device_id The PCI device id of the device to query. | ||
63 | * @return The index of the device in #me0600_versions. | ||
64 | */ | ||
65 | static inline unsigned int me0600_versions_get_device_index(uint16_t device_id) | ||
66 | { | ||
67 | unsigned int i; | ||
68 | for (i = 0; i < ME0600_DEVICE_VERSIONS; i++) | ||
69 | if (me0600_versions[i].device_id == device_id) | ||
70 | break; | ||
71 | return i; | ||
72 | } | ||
73 | |||
74 | /** | ||
75 | * @brief The ME-630 device class structure. | ||
76 | */ | ||
77 | typedef struct me0600_device { | ||
78 | me_device_t base; /**< The Meilhaus device base class. */ | ||
79 | |||
80 | /* Child class attributes. */ | ||
81 | spinlock_t dio_ctrl_reg_lock; | ||
82 | spinlock_t intcsr_lock; | ||
83 | } me0600_device_t; | ||
84 | |||
85 | /** | ||
86 | * @brief The ME-630 device class constructor. | ||
87 | * | ||
88 | * @param pci_device The pci device structure given by the PCI subsystem. | ||
89 | * | ||
90 | * @return On succes a new ME-630 device instance. \n | ||
91 | * NULL on error. | ||
92 | */ | ||
93 | me_device_t *me0600_pci_constructor(struct pci_dev *pci_device) | ||
94 | __attribute__ ((weak)); | ||
95 | |||
96 | #endif | ||
97 | #endif | ||
diff --git a/drivers/staging/meilhaus/me0600_dio.c b/drivers/staging/meilhaus/me0600_dio.c new file mode 100644 index 000000000000..3a2775749a2c --- /dev/null +++ b/drivers/staging/meilhaus/me0600_dio.c | |||
@@ -0,0 +1,415 @@ | |||
1 | /** | ||
2 | * @file me0600_dio.c | ||
3 | * | ||
4 | * @brief ME-630 digital input/output subdevice instance. | ||
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 | /* | ||
33 | * Includes | ||
34 | */ | ||
35 | #include <linux/module.h> | ||
36 | |||
37 | #include <linux/slab.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | #include <asm/io.h> | ||
40 | #include <linux/types.h> | ||
41 | |||
42 | #include "medefines.h" | ||
43 | #include "meinternal.h" | ||
44 | #include "meerror.h" | ||
45 | |||
46 | #include "medebug.h" | ||
47 | #include "me0600_dio_reg.h" | ||
48 | #include "me0600_dio.h" | ||
49 | |||
50 | /* | ||
51 | * Defines | ||
52 | */ | ||
53 | |||
54 | /* | ||
55 | * Functions | ||
56 | */ | ||
57 | |||
58 | static int me0600_dio_io_reset_subdevice(struct me_subdevice *subdevice, | ||
59 | struct file *filep, int flags) | ||
60 | { | ||
61 | me0600_dio_subdevice_t *instance; | ||
62 | uint8_t mode; | ||
63 | |||
64 | PDEBUG("executed.\n"); | ||
65 | |||
66 | instance = (me0600_dio_subdevice_t *) subdevice; | ||
67 | |||
68 | if (flags) { | ||
69 | PERROR("Invalid flag specified.\n"); | ||
70 | return ME_ERRNO_INVALID_FLAGS; | ||
71 | } | ||
72 | |||
73 | ME_SUBDEVICE_ENTER; | ||
74 | |||
75 | spin_lock(&instance->subdevice_lock); | ||
76 | spin_lock(instance->ctrl_reg_lock); | ||
77 | mode = inb(instance->ctrl_reg); | ||
78 | mode &= ~(0x3 << (instance->dio_idx * 2)); | ||
79 | outb(mode, instance->ctrl_reg); | ||
80 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
81 | instance->ctrl_reg - instance->reg_base, mode); | ||
82 | spin_unlock(instance->ctrl_reg_lock); | ||
83 | |||
84 | outb(0x00, instance->port_reg); | ||
85 | PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
86 | instance->port_reg - instance->reg_base, 0x00); | ||
87 | spin_unlock(&instance->subdevice_lock); | ||
88 | |||
89 | ME_SUBDEVICE_EXIT; | ||
90 | |||
91 | return ME_ERRNO_SUCCESS; | ||
92 | } | ||
93 | |||
94 | static int me0600_dio_io_single_config(me_subdevice_t * subdevice, | ||
95 | struct file *filep, | ||
96 | int channel, | ||
97 | int single_config, | ||
98 | int ref, | ||
99 | int trig_chan, | ||
100 | int trig_type, int trig_edge, int flags) | ||
101 | { | ||
102 | me0600_dio_subdevice_t *instance; | ||
103 | int err = ME_ERRNO_SUCCESS; | ||
104 | uint8_t mode; | ||
105 | int size = | ||
106 | flags & (ME_IO_SINGLE_CONFIG_DIO_BIT | ME_IO_SINGLE_CONFIG_DIO_BYTE | ||
107 | | ME_IO_SINGLE_CONFIG_DIO_WORD | | ||
108 | ME_IO_SINGLE_CONFIG_DIO_DWORD); | ||
109 | |||
110 | PDEBUG("executed.\n"); | ||
111 | |||
112 | instance = (me0600_dio_subdevice_t *) subdevice; | ||
113 | |||
114 | ME_SUBDEVICE_ENTER; | ||
115 | |||
116 | spin_lock(&instance->subdevice_lock); | ||
117 | spin_lock(instance->ctrl_reg_lock); | ||
118 | mode = inb(instance->ctrl_reg); | ||
119 | switch (size) { | ||
120 | case ME_IO_SINGLE_CONFIG_NO_FLAGS: | ||
121 | case ME_IO_SINGLE_CONFIG_DIO_BYTE: | ||
122 | if (channel == 0) { | ||
123 | if (single_config == ME_SINGLE_CONFIG_DIO_INPUT) { | ||
124 | mode &= | ||
125 | ~((ME0600_DIO_CONFIG_BIT_OUT_0) << | ||
126 | (instance->dio_idx * 2)); | ||
127 | } else if (single_config == ME_SINGLE_CONFIG_DIO_OUTPUT) { | ||
128 | mode &= | ||
129 | ~((ME0600_DIO_CONFIG_BIT_OUT_0) << | ||
130 | (instance->dio_idx * 2)); | ||
131 | mode |= | ||
132 | ME0600_DIO_CONFIG_BIT_OUT_0 << (instance-> | ||
133 | dio_idx * | ||
134 | 2); | ||
135 | } else { | ||
136 | PERROR | ||
137 | ("Invalid port configuration specified.\n"); | ||
138 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
139 | } | ||
140 | } else { | ||
141 | PERROR("Invalid channel number.\n"); | ||
142 | err = ME_ERRNO_INVALID_CHANNEL; | ||
143 | } | ||
144 | break; | ||
145 | |||
146 | default: | ||
147 | PERROR("Invalid flags.\n"); | ||
148 | err = ME_ERRNO_INVALID_FLAGS; | ||
149 | } | ||
150 | |||
151 | if (!err) { | ||
152 | outb(mode, instance->ctrl_reg); | ||
153 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
154 | instance->reg_base, | ||
155 | instance->ctrl_reg - instance->reg_base, mode); | ||
156 | } | ||
157 | spin_unlock(instance->ctrl_reg_lock); | ||
158 | spin_unlock(&instance->subdevice_lock); | ||
159 | |||
160 | ME_SUBDEVICE_EXIT; | ||
161 | |||
162 | return err; | ||
163 | } | ||
164 | |||
165 | static int me0600_dio_io_single_read(me_subdevice_t * subdevice, | ||
166 | struct file *filep, | ||
167 | int channel, | ||
168 | int *value, int time_out, int flags) | ||
169 | { | ||
170 | me0600_dio_subdevice_t *instance; | ||
171 | int err = ME_ERRNO_SUCCESS; | ||
172 | uint8_t mode; | ||
173 | |||
174 | PDEBUG("executed.\n"); | ||
175 | |||
176 | instance = (me0600_dio_subdevice_t *) subdevice; | ||
177 | |||
178 | ME_SUBDEVICE_ENTER; | ||
179 | |||
180 | spin_lock(&instance->subdevice_lock); | ||
181 | spin_lock(instance->ctrl_reg_lock); | ||
182 | switch (flags) { | ||
183 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
184 | if ((channel >= 0) && (channel < 8)) { | ||
185 | mode = | ||
186 | inb(instance-> | ||
187 | ctrl_reg) & ((ME0600_DIO_CONFIG_BIT_OUT_0) << | ||
188 | (instance->dio_idx * 2)); | ||
189 | |||
190 | if ((mode == | ||
191 | (ME0600_DIO_CONFIG_BIT_OUT_0 << | ||
192 | (instance->dio_idx * 2))) || !mode) { | ||
193 | *value = | ||
194 | inb(instance-> | ||
195 | port_reg) & (0x0001 << channel); | ||
196 | } else { | ||
197 | PERROR("Port not in output or input mode.\n"); | ||
198 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
199 | } | ||
200 | } else { | ||
201 | PERROR("Invalid bit number specified.\n"); | ||
202 | err = ME_ERRNO_INVALID_CHANNEL; | ||
203 | } | ||
204 | |||
205 | break; | ||
206 | |||
207 | case ME_IO_SINGLE_NO_FLAGS: | ||
208 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
209 | if (channel == 0) { | ||
210 | mode = | ||
211 | inb(instance-> | ||
212 | ctrl_reg) & ((ME0600_DIO_CONFIG_BIT_OUT_0) << | ||
213 | (instance->dio_idx * 2)); | ||
214 | |||
215 | if ((mode == | ||
216 | (ME0600_DIO_CONFIG_BIT_OUT_0 << | ||
217 | (instance->dio_idx * 2))) || !mode) { | ||
218 | *value = inb(instance->port_reg) & 0x00FF; | ||
219 | } else { | ||
220 | PERROR("Port not in output or input mode.\n"); | ||
221 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
222 | } | ||
223 | } else { | ||
224 | PERROR("Invalid byte number specified.\n"); | ||
225 | err = ME_ERRNO_INVALID_CHANNEL; | ||
226 | } | ||
227 | |||
228 | break; | ||
229 | |||
230 | default: | ||
231 | PERROR("Invalid flags specified.\n"); | ||
232 | |||
233 | err = ME_ERRNO_INVALID_FLAGS; | ||
234 | |||
235 | break; | ||
236 | } | ||
237 | spin_unlock(instance->ctrl_reg_lock); | ||
238 | spin_unlock(&instance->subdevice_lock); | ||
239 | |||
240 | ME_SUBDEVICE_EXIT; | ||
241 | |||
242 | return err; | ||
243 | } | ||
244 | |||
245 | static int me0600_dio_io_single_write(me_subdevice_t * subdevice, | ||
246 | struct file *filep, | ||
247 | int channel, | ||
248 | int value, int time_out, int flags) | ||
249 | { | ||
250 | me0600_dio_subdevice_t *instance; | ||
251 | int err = ME_ERRNO_SUCCESS; | ||
252 | uint8_t mode; | ||
253 | uint8_t byte; | ||
254 | |||
255 | PDEBUG("executed.\n"); | ||
256 | |||
257 | instance = (me0600_dio_subdevice_t *) subdevice; | ||
258 | |||
259 | ME_SUBDEVICE_ENTER; | ||
260 | |||
261 | spin_lock(&instance->subdevice_lock); | ||
262 | spin_lock(instance->ctrl_reg_lock); | ||
263 | switch (flags) { | ||
264 | |||
265 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
266 | if ((channel >= 0) && (channel < 8)) { | ||
267 | mode = | ||
268 | inb(instance-> | ||
269 | ctrl_reg) & ((ME0600_DIO_CONFIG_BIT_OUT_0) << | ||
270 | (instance->dio_idx * 2)); | ||
271 | |||
272 | if (mode == | ||
273 | (ME0600_DIO_CONFIG_BIT_OUT_0 << | ||
274 | (instance->dio_idx * 2))) { | ||
275 | byte = inb(instance->port_reg); | ||
276 | |||
277 | if (value) | ||
278 | byte |= 0x1 << channel; | ||
279 | else | ||
280 | byte &= ~(0x1 << channel); | ||
281 | |||
282 | outb(byte, instance->port_reg); | ||
283 | } else { | ||
284 | PERROR("Port not in output or input mode.\n"); | ||
285 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
286 | } | ||
287 | } else { | ||
288 | PERROR("Invalid bit number specified.\n"); | ||
289 | err = ME_ERRNO_INVALID_CHANNEL; | ||
290 | } | ||
291 | |||
292 | break; | ||
293 | |||
294 | case ME_IO_SINGLE_NO_FLAGS: | ||
295 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
296 | if (channel == 0) { | ||
297 | mode = | ||
298 | inb(instance-> | ||
299 | ctrl_reg) & ((ME0600_DIO_CONFIG_BIT_OUT_0) << | ||
300 | (instance->dio_idx * 2)); | ||
301 | |||
302 | if (mode == | ||
303 | (ME0600_DIO_CONFIG_BIT_OUT_0 << | ||
304 | (instance->dio_idx * 2))) { | ||
305 | outb(value, instance->port_reg); | ||
306 | } else { | ||
307 | PERROR("Port not in output or input mode.\n"); | ||
308 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
309 | } | ||
310 | } else { | ||
311 | PERROR("Invalid byte number specified.\n"); | ||
312 | err = ME_ERRNO_INVALID_CHANNEL; | ||
313 | } | ||
314 | |||
315 | break; | ||
316 | |||
317 | default: | ||
318 | PERROR("Invalid flags specified.\n"); | ||
319 | |||
320 | err = ME_ERRNO_INVALID_FLAGS; | ||
321 | |||
322 | break; | ||
323 | } | ||
324 | spin_unlock(instance->ctrl_reg_lock); | ||
325 | spin_unlock(&instance->subdevice_lock); | ||
326 | |||
327 | ME_SUBDEVICE_EXIT; | ||
328 | |||
329 | return err; | ||
330 | } | ||
331 | |||
332 | static int me0600_dio_query_number_channels(me_subdevice_t * subdevice, | ||
333 | int *number) | ||
334 | { | ||
335 | PDEBUG("executed.\n"); | ||
336 | *number = 8; | ||
337 | return ME_ERRNO_SUCCESS; | ||
338 | } | ||
339 | |||
340 | static int me0600_dio_query_subdevice_type(me_subdevice_t * subdevice, | ||
341 | int *type, int *subtype) | ||
342 | { | ||
343 | PDEBUG("executed.\n"); | ||
344 | *type = ME_TYPE_DIO; | ||
345 | *subtype = ME_SUBTYPE_SINGLE; | ||
346 | return ME_ERRNO_SUCCESS; | ||
347 | } | ||
348 | |||
349 | static int me0600_dio_query_subdevice_caps(me_subdevice_t * subdevice, | ||
350 | int *caps) | ||
351 | { | ||
352 | PDEBUG("executed.\n"); | ||
353 | *caps = ME_CAPS_DIO_DIR_BYTE; | ||
354 | return ME_ERRNO_SUCCESS; | ||
355 | } | ||
356 | |||
357 | me0600_dio_subdevice_t *me0600_dio_constructor(uint32_t reg_base, | ||
358 | unsigned int dio_idx, | ||
359 | spinlock_t * ctrl_reg_lock) | ||
360 | { | ||
361 | me0600_dio_subdevice_t *subdevice; | ||
362 | int err; | ||
363 | |||
364 | PDEBUG("executed.\n"); | ||
365 | |||
366 | /* Allocate memory for subdevice instance */ | ||
367 | subdevice = kmalloc(sizeof(me0600_dio_subdevice_t), GFP_KERNEL); | ||
368 | |||
369 | if (!subdevice) { | ||
370 | PERROR("Cannot get memory for subdevice instance.\n"); | ||
371 | return NULL; | ||
372 | } | ||
373 | |||
374 | memset(subdevice, 0, sizeof(me0600_dio_subdevice_t)); | ||
375 | |||
376 | /* Initialize subdevice base class */ | ||
377 | err = me_subdevice_init(&subdevice->base); | ||
378 | |||
379 | if (err) { | ||
380 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
381 | kfree(subdevice); | ||
382 | return NULL; | ||
383 | } | ||
384 | // Initialize spin locks. | ||
385 | spin_lock_init(&subdevice->subdevice_lock); | ||
386 | |||
387 | subdevice->ctrl_reg_lock = ctrl_reg_lock; | ||
388 | |||
389 | /* Save digital i/o index */ | ||
390 | subdevice->dio_idx = dio_idx; | ||
391 | |||
392 | /* Save the subdevice index */ | ||
393 | subdevice->ctrl_reg = reg_base + ME0600_DIO_CONFIG_REG; | ||
394 | subdevice->port_reg = reg_base + ME0600_DIO_PORT_REG + dio_idx; | ||
395 | #ifdef MEDEBUG_DEBUG_REG | ||
396 | subdevice->reg_base = reg_base; | ||
397 | #endif | ||
398 | |||
399 | /* Overload base class methods. */ | ||
400 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
401 | me0600_dio_io_reset_subdevice; | ||
402 | subdevice->base.me_subdevice_io_single_config = | ||
403 | me0600_dio_io_single_config; | ||
404 | subdevice->base.me_subdevice_io_single_read = me0600_dio_io_single_read; | ||
405 | subdevice->base.me_subdevice_io_single_write = | ||
406 | me0600_dio_io_single_write; | ||
407 | subdevice->base.me_subdevice_query_number_channels = | ||
408 | me0600_dio_query_number_channels; | ||
409 | subdevice->base.me_subdevice_query_subdevice_type = | ||
410 | me0600_dio_query_subdevice_type; | ||
411 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
412 | me0600_dio_query_subdevice_caps; | ||
413 | |||
414 | return subdevice; | ||
415 | } | ||
diff --git a/drivers/staging/meilhaus/me0600_dio.h b/drivers/staging/meilhaus/me0600_dio.h new file mode 100644 index 000000000000..5d075c7d6882 --- /dev/null +++ b/drivers/staging/meilhaus/me0600_dio.h | |||
@@ -0,0 +1,68 @@ | |||
1 | /** | ||
2 | * @file me0600_dio.h | ||
3 | * | ||
4 | * @brief ME-630 digital input/output subdevice class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME0600_DIO_H_ | ||
28 | #define _ME0600_DIO_H_ | ||
29 | |||
30 | #include "mesubdevice.h" | ||
31 | |||
32 | #ifdef __KERNEL__ | ||
33 | |||
34 | /** | ||
35 | * @brief The template subdevice class. | ||
36 | */ | ||
37 | typedef struct me0600_dio_subdevice { | ||
38 | /* Inheritance */ | ||
39 | me_subdevice_t base; /**< The subdevice base class. */ | ||
40 | |||
41 | /* Attributes */ | ||
42 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
43 | spinlock_t *ctrl_reg_lock; /**< Spin lock to protect #ctrl_reg from concurrent access. */ | ||
44 | unsigned int dio_idx; /**< The index of the digital i/o on the device. */ | ||
45 | |||
46 | unsigned long port_reg; /**< Register holding the port status. */ | ||
47 | unsigned long ctrl_reg; /**< Register to configure the port direction. */ | ||
48 | #ifdef MEDEBUG_DEBUG_REG | ||
49 | unsigned long reg_base; | ||
50 | #endif | ||
51 | } me0600_dio_subdevice_t; | ||
52 | |||
53 | /** | ||
54 | * @brief The constructor to generate a ME-630 digital input/ouput subdevice instance. | ||
55 | * | ||
56 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
57 | * @param dio_idx The index of the digital i/o port on the device. | ||
58 | * @param ctrl_reg_lock Spin lock protecting the control register. | ||
59 | * | ||
60 | * @return Pointer to new instance on success.\n | ||
61 | * NULL on error. | ||
62 | */ | ||
63 | me0600_dio_subdevice_t *me0600_dio_constructor(uint32_t reg_base, | ||
64 | unsigned int dio_idx, | ||
65 | spinlock_t * ctrl_reg_lock); | ||
66 | |||
67 | #endif | ||
68 | #endif | ||
diff --git a/drivers/staging/meilhaus/me0600_dio_reg.h b/drivers/staging/meilhaus/me0600_dio_reg.h new file mode 100644 index 000000000000..f116ea3b79d2 --- /dev/null +++ b/drivers/staging/meilhaus/me0600_dio_reg.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /** | ||
2 | * @file me0600_dio_reg.h | ||
3 | * | ||
4 | * @brief ME-630 digital input/output subdevice register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME0600_DIO_REG_H_ | ||
28 | #define _ME0600_DIO_REG_H_ | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | #define ME0600_DIO_CONFIG_REG 0x0007 | ||
33 | #define ME0600_DIO_PORT_0_REG 0x0008 | ||
34 | #define ME0600_DIO_PORT_1_REG 0x0009 | ||
35 | #define ME0600_DIO_PORT_REG ME0600_DIO_PORT_0_REG | ||
36 | |||
37 | #define ME0600_DIO_CONFIG_BIT_OUT_0 0x0001 | ||
38 | #define ME0600_DIO_CONFIG_BIT_OUT_1 0x0004 | ||
39 | |||
40 | #endif | ||
41 | #endif | ||
diff --git a/drivers/staging/meilhaus/me0600_ext_irq.c b/drivers/staging/meilhaus/me0600_ext_irq.c new file mode 100644 index 000000000000..a449ab200940 --- /dev/null +++ b/drivers/staging/meilhaus/me0600_ext_irq.c | |||
@@ -0,0 +1,478 @@ | |||
1 | /** | ||
2 | * @file me0600_ext_irq.c | ||
3 | * | ||
4 | * @brief ME-630 external interrupt subdevice instance. | ||
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 | /* | ||
33 | * Includes | ||
34 | */ | ||
35 | #include <linux/version.h> | ||
36 | #include <linux/module.h> | ||
37 | |||
38 | #include <linux/slab.h> | ||
39 | #include <linux/spinlock.h> | ||
40 | #include <asm/io.h> | ||
41 | #include <linux/types.h> | ||
42 | #include <linux/interrupt.h> | ||
43 | |||
44 | #include "medefines.h" | ||
45 | #include "meinternal.h" | ||
46 | #include "meerror.h" | ||
47 | #include "meids.h" | ||
48 | #include "medebug.h" | ||
49 | |||
50 | #include "meplx_reg.h" | ||
51 | #include "me0600_ext_irq_reg.h" | ||
52 | #include "me0600_ext_irq.h" | ||
53 | |||
54 | /* | ||
55 | * Functions | ||
56 | */ | ||
57 | |||
58 | static int me0600_ext_irq_io_irq_start(struct me_subdevice *subdevice, | ||
59 | struct file *filep, | ||
60 | int channel, | ||
61 | int irq_source, | ||
62 | int irq_edge, int irq_arg, int flags) | ||
63 | { | ||
64 | me0600_ext_irq_subdevice_t *instance; | ||
65 | uint32_t tmp; | ||
66 | unsigned long cpu_flags; | ||
67 | |||
68 | PDEBUG("executed.\n"); | ||
69 | |||
70 | instance = (me0600_ext_irq_subdevice_t *) subdevice; | ||
71 | |||
72 | if (flags & ~ME_IO_IRQ_START_DIO_BIT) { | ||
73 | PERROR("Invalid flag specified.\n"); | ||
74 | return ME_ERRNO_INVALID_FLAGS; | ||
75 | } | ||
76 | |||
77 | if (instance->lintno > 1) { | ||
78 | PERROR("Wrong idx=%d.\n", instance->lintno); | ||
79 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
80 | } | ||
81 | |||
82 | if (channel) { | ||
83 | PERROR("Invalid channel specified.\n"); | ||
84 | return ME_ERRNO_INVALID_CHANNEL; | ||
85 | } | ||
86 | |||
87 | if (irq_source != ME_IRQ_SOURCE_DIO_LINE) { | ||
88 | PERROR("Invalid irq source specified.\n"); | ||
89 | return ME_ERRNO_INVALID_IRQ_SOURCE; | ||
90 | } | ||
91 | |||
92 | if (irq_edge != ME_IRQ_EDGE_RISING) { | ||
93 | PERROR("Invalid irq edge specified.\n"); | ||
94 | return ME_ERRNO_INVALID_IRQ_EDGE; | ||
95 | } | ||
96 | |||
97 | ME_SUBDEVICE_ENTER; | ||
98 | |||
99 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
100 | spin_lock(instance->intcsr_lock); | ||
101 | tmp = inl(instance->intcsr); | ||
102 | switch (instance->lintno) { | ||
103 | case 0: | ||
104 | tmp |= | ||
105 | PLX_INTCSR_LOCAL_INT1_EN | PLX_INTCSR_LOCAL_INT1_POL | | ||
106 | PLX_INTCSR_PCI_INT_EN; | ||
107 | break; | ||
108 | case 1: | ||
109 | tmp |= | ||
110 | PLX_INTCSR_LOCAL_INT2_EN | PLX_INTCSR_LOCAL_INT2_POL | | ||
111 | PLX_INTCSR_PCI_INT_EN; | ||
112 | break; | ||
113 | } | ||
114 | outl(tmp, instance->intcsr); | ||
115 | PDEBUG_REG("intcsr outl(plx:0x%X)=0x%x\n", instance->intcsr, tmp); | ||
116 | spin_unlock(instance->intcsr_lock); | ||
117 | instance->rised = 0; | ||
118 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
119 | |||
120 | ME_SUBDEVICE_EXIT; | ||
121 | |||
122 | return ME_ERRNO_SUCCESS; | ||
123 | } | ||
124 | |||
125 | static int me0600_ext_irq_io_irq_wait(struct me_subdevice *subdevice, | ||
126 | struct file *filep, | ||
127 | int channel, | ||
128 | int *irq_count, | ||
129 | int *value, int time_out, int flags) | ||
130 | { | ||
131 | me0600_ext_irq_subdevice_t *instance; | ||
132 | int err = ME_ERRNO_SUCCESS; | ||
133 | long t = 0; | ||
134 | unsigned long cpu_flags; | ||
135 | |||
136 | PDEBUG("executed.\n"); | ||
137 | |||
138 | instance = (me0600_ext_irq_subdevice_t *) subdevice; | ||
139 | |||
140 | if (flags) { | ||
141 | PERROR("Invalid flag specified.\n"); | ||
142 | return ME_ERRNO_INVALID_FLAGS; | ||
143 | } | ||
144 | |||
145 | if (channel) { | ||
146 | PERROR("Invalid channel specified.\n"); | ||
147 | return ME_ERRNO_INVALID_CHANNEL; | ||
148 | } | ||
149 | |||
150 | if (time_out < 0) { | ||
151 | PERROR("Invalid time_out specified.\n"); | ||
152 | return ME_ERRNO_INVALID_TIMEOUT; | ||
153 | } | ||
154 | |||
155 | if (time_out) { | ||
156 | t = (time_out * HZ) / 1000; | ||
157 | |||
158 | if (t == 0) | ||
159 | t = 1; | ||
160 | } | ||
161 | |||
162 | ME_SUBDEVICE_ENTER; | ||
163 | |||
164 | if (instance->rised <= 0) { | ||
165 | instance->rised = 0; | ||
166 | |||
167 | if (time_out) { | ||
168 | t = wait_event_interruptible_timeout(instance-> | ||
169 | wait_queue, | ||
170 | (instance->rised != | ||
171 | 0), t); | ||
172 | |||
173 | if (t == 0) { | ||
174 | PERROR("Wait on interrupt timed out.\n"); | ||
175 | err = ME_ERRNO_TIMEOUT; | ||
176 | } | ||
177 | } else { | ||
178 | wait_event_interruptible(instance->wait_queue, | ||
179 | (instance->rised != 0)); | ||
180 | } | ||
181 | |||
182 | if (instance->rised < 0) { | ||
183 | PERROR("Wait on interrupt aborted by user.\n"); | ||
184 | err = ME_ERRNO_CANCELLED; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | if (signal_pending(current)) { | ||
189 | PERROR("Wait on interrupt aborted by signal.\n"); | ||
190 | err = ME_ERRNO_SIGNAL; | ||
191 | } | ||
192 | |||
193 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
194 | instance->rised = 0; | ||
195 | *irq_count = instance->n; | ||
196 | *value = 1; | ||
197 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
198 | |||
199 | ME_SUBDEVICE_EXIT; | ||
200 | |||
201 | return err; | ||
202 | } | ||
203 | |||
204 | static int me0600_ext_irq_io_irq_stop(struct me_subdevice *subdevice, | ||
205 | struct file *filep, | ||
206 | int channel, int flags) | ||
207 | { | ||
208 | me0600_ext_irq_subdevice_t *instance; | ||
209 | int err = ME_ERRNO_SUCCESS; | ||
210 | uint32_t tmp; | ||
211 | unsigned long cpu_flags; | ||
212 | |||
213 | PDEBUG("executed.\n"); | ||
214 | |||
215 | instance = (me0600_ext_irq_subdevice_t *) subdevice; | ||
216 | |||
217 | if (flags) { | ||
218 | PERROR("Invalid flag specified.\n"); | ||
219 | return ME_ERRNO_INVALID_FLAGS; | ||
220 | } | ||
221 | |||
222 | if (instance->lintno > 1) { | ||
223 | PERROR("Wrong idx=%d.\n", instance->lintno); | ||
224 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
225 | } | ||
226 | |||
227 | if (channel) { | ||
228 | PERROR("Invalid channel specified.\n"); | ||
229 | return ME_ERRNO_INVALID_CHANNEL; | ||
230 | } | ||
231 | |||
232 | ME_SUBDEVICE_ENTER; | ||
233 | |||
234 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
235 | spin_lock(instance->intcsr_lock); | ||
236 | tmp = inl(instance->intcsr); | ||
237 | switch (instance->lintno) { | ||
238 | case 0: | ||
239 | tmp &= ~PLX_INTCSR_LOCAL_INT1_EN; | ||
240 | break; | ||
241 | case 1: | ||
242 | tmp &= ~PLX_INTCSR_LOCAL_INT2_EN; | ||
243 | break; | ||
244 | } | ||
245 | outl(tmp, instance->intcsr); | ||
246 | PDEBUG_REG("intcsr outl(plx:0x%X)=0x%x\n", instance->intcsr, tmp); | ||
247 | spin_unlock(instance->intcsr_lock); | ||
248 | instance->rised = -1; | ||
249 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
250 | wake_up_interruptible_all(&instance->wait_queue); | ||
251 | |||
252 | ME_SUBDEVICE_EXIT; | ||
253 | |||
254 | return err; | ||
255 | } | ||
256 | |||
257 | static int me0600_ext_irq_io_reset_subdevice(struct me_subdevice *subdevice, | ||
258 | struct file *filep, int flags) | ||
259 | { | ||
260 | me0600_ext_irq_subdevice_t *instance; | ||
261 | uint32_t tmp; | ||
262 | unsigned long cpu_flags; | ||
263 | |||
264 | PDEBUG("executed.\n"); | ||
265 | |||
266 | instance = (me0600_ext_irq_subdevice_t *) subdevice; | ||
267 | |||
268 | if (flags) { | ||
269 | PERROR("Invalid flag specified.\n"); | ||
270 | return ME_ERRNO_INVALID_FLAGS; | ||
271 | } | ||
272 | |||
273 | ME_SUBDEVICE_ENTER; | ||
274 | |||
275 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
276 | spin_lock(instance->intcsr_lock); | ||
277 | tmp = inl(instance->intcsr); | ||
278 | switch (instance->lintno) { | ||
279 | case 0: | ||
280 | tmp |= PLX_INTCSR_LOCAL_INT1_POL | PLX_INTCSR_PCI_INT_EN; | ||
281 | tmp &= ~PLX_INTCSR_LOCAL_INT1_EN; | ||
282 | break; | ||
283 | case 1: | ||
284 | tmp |= PLX_INTCSR_LOCAL_INT2_POL | PLX_INTCSR_PCI_INT_EN; | ||
285 | tmp &= ~PLX_INTCSR_LOCAL_INT2_EN; | ||
286 | break; | ||
287 | } | ||
288 | outl(tmp, instance->intcsr); | ||
289 | PDEBUG_REG("intcsr outl(plx:0x%X)=0x%x\n", instance->intcsr, tmp); | ||
290 | spin_unlock(instance->intcsr_lock); | ||
291 | |||
292 | instance->rised = -1; | ||
293 | instance->n = 0; | ||
294 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
295 | wake_up_interruptible_all(&instance->wait_queue); | ||
296 | |||
297 | ME_SUBDEVICE_EXIT; | ||
298 | |||
299 | return ME_ERRNO_SUCCESS; | ||
300 | } | ||
301 | |||
302 | static int me0600_ext_irq_query_number_channels(struct me_subdevice *subdevice, | ||
303 | int *number) | ||
304 | { | ||
305 | PDEBUG("executed.\n"); | ||
306 | *number = 1; | ||
307 | return ME_ERRNO_SUCCESS; | ||
308 | } | ||
309 | |||
310 | static int me0600_ext_irq_query_subdevice_type(struct me_subdevice *subdevice, | ||
311 | int *type, int *subtype) | ||
312 | { | ||
313 | PDEBUG("executed.\n"); | ||
314 | *type = ME_TYPE_EXT_IRQ; | ||
315 | *subtype = ME_SUBTYPE_SINGLE; | ||
316 | return ME_ERRNO_SUCCESS; | ||
317 | } | ||
318 | |||
319 | static int me0600_ext_irq_query_subdevice_caps(struct me_subdevice *subdevice, | ||
320 | int *caps) | ||
321 | { | ||
322 | PDEBUG("executed.\n"); | ||
323 | *caps = ME_CAPS_EXT_IRQ_EDGE_RISING; | ||
324 | return ME_ERRNO_SUCCESS; | ||
325 | } | ||
326 | |||
327 | static void me0600_ext_irq_destructor(struct me_subdevice *subdevice) | ||
328 | { | ||
329 | me0600_ext_irq_subdevice_t *instance; | ||
330 | |||
331 | PDEBUG("executed.\n"); | ||
332 | |||
333 | instance = (me0600_ext_irq_subdevice_t *) subdevice; | ||
334 | |||
335 | free_irq(instance->irq, (void *)instance); | ||
336 | me_subdevice_deinit(&instance->base); | ||
337 | kfree(instance); | ||
338 | } | ||
339 | |||
340 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) | ||
341 | static irqreturn_t me0600_isr(int irq, void *dev_id) | ||
342 | #else | ||
343 | static irqreturn_t me0600_isr(int irq, void *dev_id, struct pt_regs *regs) | ||
344 | #endif | ||
345 | { | ||
346 | me0600_ext_irq_subdevice_t *instance; | ||
347 | uint32_t status; | ||
348 | uint32_t mask = PLX_INTCSR_PCI_INT_EN; | ||
349 | irqreturn_t ret = IRQ_HANDLED; | ||
350 | |||
351 | instance = (me0600_ext_irq_subdevice_t *) dev_id; | ||
352 | |||
353 | if (irq != instance->irq) { | ||
354 | PERROR("Incorrect interrupt num: %d.\n", irq); | ||
355 | return IRQ_NONE; | ||
356 | } | ||
357 | |||
358 | PDEBUG("executed.\n"); | ||
359 | |||
360 | if (instance->lintno > 1) { | ||
361 | PERROR_CRITICAL | ||
362 | ("%s():Wrong subdevice index=%d plx:irq_status_reg=0x%04X.\n", | ||
363 | __FUNCTION__, instance->lintno, inl(instance->intcsr)); | ||
364 | return IRQ_NONE; | ||
365 | } | ||
366 | |||
367 | spin_lock(&instance->subdevice_lock); | ||
368 | spin_lock(instance->intcsr_lock); | ||
369 | status = inl(instance->intcsr); | ||
370 | switch (instance->lintno) { | ||
371 | case 0: | ||
372 | mask |= PLX_INTCSR_LOCAL_INT1_STATE | PLX_INTCSR_LOCAL_INT1_EN; | ||
373 | break; | ||
374 | case 1: | ||
375 | mask |= PLX_INTCSR_LOCAL_INT2_STATE | PLX_INTCSR_LOCAL_INT2_EN; | ||
376 | break; | ||
377 | } | ||
378 | |||
379 | if ((status & mask) == mask) { | ||
380 | instance->rised = 1; | ||
381 | instance->n++; | ||
382 | inb(instance->reset_reg); | ||
383 | PDEBUG("Interrupt detected.\n"); | ||
384 | } else { | ||
385 | PINFO | ||
386 | ("%ld Shared interrupt. %s(): idx=0 plx:irq_status_reg=0x%04X\n", | ||
387 | jiffies, __FUNCTION__, status); | ||
388 | ret = IRQ_NONE; | ||
389 | } | ||
390 | spin_unlock(instance->intcsr_lock); | ||
391 | spin_unlock(&instance->subdevice_lock); | ||
392 | |||
393 | wake_up_interruptible_all(&instance->wait_queue); | ||
394 | |||
395 | return ret; | ||
396 | } | ||
397 | |||
398 | me0600_ext_irq_subdevice_t *me0600_ext_irq_constructor(uint32_t plx_reg_base, | ||
399 | uint32_t me0600_reg_base, | ||
400 | spinlock_t * intcsr_lock, | ||
401 | unsigned ext_irq_idx, | ||
402 | int irq) | ||
403 | { | ||
404 | me0600_ext_irq_subdevice_t *subdevice; | ||
405 | int err; | ||
406 | |||
407 | PDEBUG("executed.\n"); | ||
408 | |||
409 | /* Allocate memory for subdevice instance */ | ||
410 | subdevice = kmalloc(sizeof(me0600_ext_irq_subdevice_t), GFP_KERNEL); | ||
411 | |||
412 | if (!subdevice) { | ||
413 | PERROR("Cannot get memory for 630_ext_irq instance.\n"); | ||
414 | return NULL; | ||
415 | } | ||
416 | |||
417 | memset(subdevice, 0, sizeof(me0600_ext_irq_subdevice_t)); | ||
418 | |||
419 | /* Initialize subdevice base class */ | ||
420 | err = me_subdevice_init(&subdevice->base); | ||
421 | |||
422 | if (err) { | ||
423 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
424 | kfree(subdevice); | ||
425 | return NULL; | ||
426 | } | ||
427 | // Initialize spin locks. | ||
428 | spin_lock_init(&subdevice->subdevice_lock); | ||
429 | |||
430 | subdevice->intcsr_lock = intcsr_lock; | ||
431 | |||
432 | /* Initialize wait queue */ | ||
433 | init_waitqueue_head(&subdevice->wait_queue); | ||
434 | |||
435 | subdevice->lintno = ext_irq_idx; | ||
436 | |||
437 | /* Request interrupt line */ | ||
438 | subdevice->irq = irq; | ||
439 | |||
440 | err = request_irq(subdevice->irq, me0600_isr, | ||
441 | #ifdef IRQF_DISABLED | ||
442 | IRQF_DISABLED | IRQF_SHARED, | ||
443 | #else | ||
444 | SA_INTERRUPT | SA_SHIRQ, | ||
445 | #endif | ||
446 | ME0600_NAME, (void *)subdevice); | ||
447 | |||
448 | if (err) { | ||
449 | PERROR("Cannot get interrupt line.\n"); | ||
450 | kfree(subdevice); | ||
451 | return NULL; | ||
452 | } | ||
453 | PINFO("Registered irq=%d.\n", subdevice->irq); | ||
454 | |||
455 | /* Initialize registers */ | ||
456 | subdevice->intcsr = plx_reg_base + PLX_INTCSR; | ||
457 | subdevice->reset_reg = | ||
458 | me0600_reg_base + ME0600_INT_0_RESET_REG + ext_irq_idx; | ||
459 | |||
460 | /* Initialize the subdevice methods */ | ||
461 | subdevice->base.me_subdevice_io_irq_start = me0600_ext_irq_io_irq_start; | ||
462 | subdevice->base.me_subdevice_io_irq_wait = me0600_ext_irq_io_irq_wait; | ||
463 | subdevice->base.me_subdevice_io_irq_stop = me0600_ext_irq_io_irq_stop; | ||
464 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
465 | me0600_ext_irq_io_reset_subdevice; | ||
466 | subdevice->base.me_subdevice_query_number_channels = | ||
467 | me0600_ext_irq_query_number_channels; | ||
468 | subdevice->base.me_subdevice_query_subdevice_type = | ||
469 | me0600_ext_irq_query_subdevice_type; | ||
470 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
471 | me0600_ext_irq_query_subdevice_caps; | ||
472 | subdevice->base.me_subdevice_destructor = me0600_ext_irq_destructor; | ||
473 | |||
474 | subdevice->rised = 0; | ||
475 | subdevice->n = 0; | ||
476 | |||
477 | return subdevice; | ||
478 | } | ||
diff --git a/drivers/staging/meilhaus/me0600_ext_irq.h b/drivers/staging/meilhaus/me0600_ext_irq.h new file mode 100644 index 000000000000..f5f2204b49a0 --- /dev/null +++ b/drivers/staging/meilhaus/me0600_ext_irq.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /** | ||
2 | * @file me0600_ext_irq.h | ||
3 | * | ||
4 | * @brief ME-630 external interrupt implementation. | ||
5 | * @note Copyright (C) 2006 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | #ifndef _ME0600_EXT_IRQ_H_ | ||
10 | #define _ME0600_EXT_IRQ_H_ | ||
11 | |||
12 | #include <linux/sched.h> | ||
13 | |||
14 | #include "mesubdevice.h" | ||
15 | #include "meslock.h" | ||
16 | |||
17 | #ifdef __KERNEL__ | ||
18 | |||
19 | /** | ||
20 | * @brief The ME-630 external interrupt subdevice class. | ||
21 | */ | ||
22 | typedef struct me0600_ext_irq_subdevice { | ||
23 | /* Inheritance */ | ||
24 | me_subdevice_t base; /**< The subdevice base class. */ | ||
25 | |||
26 | /* Attributes */ | ||
27 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
28 | spinlock_t *intcsr_lock; /**< Spin lock to protect #intcsr. */ | ||
29 | |||
30 | wait_queue_head_t wait_queue; /**< Queue to put on threads waiting for an interrupt. */ | ||
31 | |||
32 | int irq; /**< The irq number assigned by PCI BIOS. */ | ||
33 | int rised; /**< If true an interrupt has occured. */ | ||
34 | unsigned int n; /**< The number of interrupt since the driver was loaded. */ | ||
35 | unsigned int lintno; /**< The number of the local PCI interrupt. */ | ||
36 | |||
37 | uint32_t intcsr; /**< The PLX interrupt control and status register. */ | ||
38 | uint32_t reset_reg; /**< The control register. */ | ||
39 | } me0600_ext_irq_subdevice_t; | ||
40 | |||
41 | /** | ||
42 | * @brief The constructor to generate a ME-630 external interrupt instance. | ||
43 | * | ||
44 | * @param plx_reg_base The register base address of the PLX chip as returned by the PCI BIOS. | ||
45 | * @param me0600_reg_base The register base address of the ME-630 device as returned by the PCI BIOS. | ||
46 | * @param irq The irq assigned by the PCI BIOS. | ||
47 | * | ||
48 | * @return Pointer to new instance on success.\n | ||
49 | * NULL on error. | ||
50 | */ | ||
51 | me0600_ext_irq_subdevice_t *me0600_ext_irq_constructor(uint32_t plx_reg_base, | ||
52 | uint32_t me0600_reg_base, | ||
53 | spinlock_t * intcsr_lock, | ||
54 | unsigned int ext_irq_idx, | ||
55 | int irq); | ||
56 | |||
57 | #endif | ||
58 | #endif | ||
diff --git a/drivers/staging/meilhaus/me0600_ext_irq_reg.h b/drivers/staging/meilhaus/me0600_ext_irq_reg.h new file mode 100644 index 000000000000..f6198fa6d2b2 --- /dev/null +++ b/drivers/staging/meilhaus/me0600_ext_irq_reg.h | |||
@@ -0,0 +1,18 @@ | |||
1 | /** | ||
2 | * @file me0600_ext_irq_reg.h | ||
3 | * | ||
4 | * @brief ME-630 external interrupt register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | #ifndef _ME0600_EXT_IRQ_REG_H_ | ||
10 | #define _ME0600_EXT_IRQ_REG_H_ | ||
11 | |||
12 | #ifdef __KERNEL__ | ||
13 | |||
14 | #define ME0600_INT_0_RESET_REG 0x0005 | ||
15 | #define ME0600_INT_1_RESET_REG 0x0006 | ||
16 | |||
17 | #endif | ||
18 | #endif | ||
diff --git a/drivers/staging/meilhaus/me0600_optoi.c b/drivers/staging/meilhaus/me0600_optoi.c new file mode 100644 index 000000000000..b6d977f228ca --- /dev/null +++ b/drivers/staging/meilhaus/me0600_optoi.c | |||
@@ -0,0 +1,243 @@ | |||
1 | /** | ||
2 | * @file me0600_optoi.c | ||
3 | * | ||
4 | * @brief ME-630 Optoisolated input subdevice instance. | ||
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 | /* | ||
33 | * Includes | ||
34 | */ | ||
35 | #include <linux/module.h> | ||
36 | |||
37 | #include <linux/slab.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | #include <asm/io.h> | ||
40 | #include <linux/types.h> | ||
41 | |||
42 | #include "medefines.h" | ||
43 | #include "meinternal.h" | ||
44 | #include "meerror.h" | ||
45 | |||
46 | #include "medebug.h" | ||
47 | #include "me0600_optoi_reg.h" | ||
48 | #include "me0600_optoi.h" | ||
49 | |||
50 | /* | ||
51 | * Defines | ||
52 | */ | ||
53 | |||
54 | /* | ||
55 | * Functions | ||
56 | */ | ||
57 | |||
58 | static int me0600_optoi_io_reset_subdevice(struct me_subdevice *subdevice, | ||
59 | struct file *filep, int flags) | ||
60 | { | ||
61 | |||
62 | if (flags) { | ||
63 | PERROR("Invalid flag specified.\n"); | ||
64 | return ME_ERRNO_INVALID_FLAGS; | ||
65 | } | ||
66 | |||
67 | PDEBUG("executed.\n"); | ||
68 | return ME_ERRNO_SUCCESS; | ||
69 | } | ||
70 | |||
71 | static int me0600_optoi_io_single_config(me_subdevice_t * subdevice, | ||
72 | struct file *filep, | ||
73 | int channel, | ||
74 | int single_config, | ||
75 | int ref, | ||
76 | int trig_chan, | ||
77 | int trig_type, | ||
78 | int trig_edge, int flags) | ||
79 | { | ||
80 | me0600_optoi_subdevice_t *instance; | ||
81 | int err = ME_ERRNO_SUCCESS; | ||
82 | |||
83 | PDEBUG("executed.\n"); | ||
84 | |||
85 | instance = (me0600_optoi_subdevice_t *) subdevice; | ||
86 | |||
87 | ME_SUBDEVICE_ENTER; | ||
88 | |||
89 | spin_lock(&instance->subdevice_lock); | ||
90 | |||
91 | switch (flags) { | ||
92 | case ME_IO_SINGLE_CONFIG_NO_FLAGS: | ||
93 | case ME_IO_SINGLE_CONFIG_DIO_BYTE: | ||
94 | if (channel == 0) { | ||
95 | if (single_config != ME_SINGLE_CONFIG_DIO_INPUT) { | ||
96 | PERROR("Invalid port direction specified.\n"); | ||
97 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
98 | } | ||
99 | } else { | ||
100 | PERROR("Invalid channel specified.\n"); | ||
101 | err = ME_ERRNO_INVALID_CHANNEL; | ||
102 | } | ||
103 | |||
104 | break; | ||
105 | |||
106 | default: | ||
107 | PERROR("Invalid flags specified.\n"); | ||
108 | |||
109 | err = ME_ERRNO_INVALID_FLAGS; | ||
110 | |||
111 | break; | ||
112 | } | ||
113 | |||
114 | spin_unlock(&instance->subdevice_lock); | ||
115 | |||
116 | ME_SUBDEVICE_EXIT; | ||
117 | |||
118 | return err; | ||
119 | } | ||
120 | |||
121 | static int me0600_optoi_io_single_read(me_subdevice_t * subdevice, | ||
122 | struct file *filep, | ||
123 | int channel, | ||
124 | int *value, int time_out, int flags) | ||
125 | { | ||
126 | me0600_optoi_subdevice_t *instance; | ||
127 | int err = ME_ERRNO_SUCCESS; | ||
128 | |||
129 | PDEBUG("executed.\n"); | ||
130 | |||
131 | instance = (me0600_optoi_subdevice_t *) subdevice; | ||
132 | |||
133 | ME_SUBDEVICE_ENTER; | ||
134 | |||
135 | spin_lock(&instance->subdevice_lock); | ||
136 | |||
137 | switch (flags) { | ||
138 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
139 | if ((channel >= 0) && (channel < 8)) { | ||
140 | *value = inb(instance->port_reg) & (0x1 << channel); | ||
141 | } else { | ||
142 | PERROR("Invalid bit number specified.\n"); | ||
143 | err = ME_ERRNO_INVALID_CHANNEL; | ||
144 | } | ||
145 | |||
146 | break; | ||
147 | |||
148 | case ME_IO_SINGLE_NO_FLAGS: | ||
149 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
150 | if (channel == 0) { | ||
151 | *value = inb(instance->port_reg); | ||
152 | } else { | ||
153 | PERROR("Invalid byte number specified.\n"); | ||
154 | err = ME_ERRNO_INVALID_CHANNEL; | ||
155 | } | ||
156 | |||
157 | break; | ||
158 | |||
159 | default: | ||
160 | PERROR("Invalid flags specified.\n"); | ||
161 | |||
162 | err = ME_ERRNO_INVALID_FLAGS; | ||
163 | } | ||
164 | |||
165 | spin_unlock(&instance->subdevice_lock); | ||
166 | |||
167 | ME_SUBDEVICE_EXIT; | ||
168 | |||
169 | return err; | ||
170 | } | ||
171 | |||
172 | static int me0600_optoi_query_number_channels(me_subdevice_t * subdevice, | ||
173 | int *number) | ||
174 | { | ||
175 | PDEBUG("executed.\n"); | ||
176 | *number = 8; | ||
177 | return ME_ERRNO_SUCCESS; | ||
178 | } | ||
179 | |||
180 | static int me0600_optoi_query_subdevice_type(me_subdevice_t * subdevice, | ||
181 | int *type, int *subtype) | ||
182 | { | ||
183 | PDEBUG("executed.\n"); | ||
184 | *type = ME_TYPE_DI; | ||
185 | *subtype = ME_SUBTYPE_SINGLE; | ||
186 | return ME_ERRNO_SUCCESS; | ||
187 | } | ||
188 | |||
189 | static int me0600_optoi_query_subdevice_caps(me_subdevice_t * subdevice, | ||
190 | int *caps) | ||
191 | { | ||
192 | PDEBUG("executed.\n"); | ||
193 | *caps = 0; | ||
194 | return ME_ERRNO_SUCCESS; | ||
195 | } | ||
196 | |||
197 | me0600_optoi_subdevice_t *me0600_optoi_constructor(uint32_t reg_base) | ||
198 | { | ||
199 | me0600_optoi_subdevice_t *subdevice; | ||
200 | int err; | ||
201 | |||
202 | PDEBUG("executed.\n"); | ||
203 | |||
204 | /* Allocate memory for subdevice instance */ | ||
205 | subdevice = kmalloc(sizeof(me0600_optoi_subdevice_t), GFP_KERNEL); | ||
206 | |||
207 | if (!subdevice) { | ||
208 | PERROR("Cannot get memory for subdevice instance.\n"); | ||
209 | return NULL; | ||
210 | } | ||
211 | |||
212 | memset(subdevice, 0, sizeof(me0600_optoi_subdevice_t)); | ||
213 | |||
214 | /* Initialize subdevice base class */ | ||
215 | err = me_subdevice_init(&subdevice->base); | ||
216 | |||
217 | if (err) { | ||
218 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
219 | kfree(subdevice); | ||
220 | return NULL; | ||
221 | } | ||
222 | // Initialize spin locks. | ||
223 | spin_lock_init(&subdevice->subdevice_lock); | ||
224 | |||
225 | /* Save the subdevice index */ | ||
226 | subdevice->port_reg = reg_base + ME0600_OPTO_INPUT_REG; | ||
227 | |||
228 | /* Overload base class methods. */ | ||
229 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
230 | me0600_optoi_io_reset_subdevice; | ||
231 | subdevice->base.me_subdevice_io_single_config = | ||
232 | me0600_optoi_io_single_config; | ||
233 | subdevice->base.me_subdevice_io_single_read = | ||
234 | me0600_optoi_io_single_read; | ||
235 | subdevice->base.me_subdevice_query_number_channels = | ||
236 | me0600_optoi_query_number_channels; | ||
237 | subdevice->base.me_subdevice_query_subdevice_type = | ||
238 | me0600_optoi_query_subdevice_type; | ||
239 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
240 | me0600_optoi_query_subdevice_caps; | ||
241 | |||
242 | return subdevice; | ||
243 | } | ||
diff --git a/drivers/staging/meilhaus/me0600_optoi.h b/drivers/staging/meilhaus/me0600_optoi.h new file mode 100644 index 000000000000..e7e69bcde9c9 --- /dev/null +++ b/drivers/staging/meilhaus/me0600_optoi.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /** | ||
2 | * @file me0600_optoi.h | ||
3 | * | ||
4 | * @brief ME-630 Optoisolated input subdevice class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME0600_OPTOI_H_ | ||
28 | #define _ME0600_OPTOI_H_ | ||
29 | |||
30 | #include "mesubdevice.h" | ||
31 | |||
32 | #ifdef __KERNEL__ | ||
33 | |||
34 | /** | ||
35 | * @brief The template subdevice class. | ||
36 | */ | ||
37 | typedef struct me0600_optoi_subdevice { | ||
38 | /* Inheritance */ | ||
39 | me_subdevice_t base; /**< The subdevice base class. */ | ||
40 | |||
41 | /* Attributes */ | ||
42 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
43 | |||
44 | uint32_t port_reg; /**< Register holding the port status. */ | ||
45 | } me0600_optoi_subdevice_t; | ||
46 | |||
47 | /** | ||
48 | * @brief The constructor to generate a ME-630 Optoisolated input subdevice instance. | ||
49 | * | ||
50 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
51 | * | ||
52 | * @return Pointer to new instance on success.\n | ||
53 | * NULL on error. | ||
54 | */ | ||
55 | me0600_optoi_subdevice_t *me0600_optoi_constructor(uint32_t reg_base); | ||
56 | |||
57 | #endif | ||
58 | #endif | ||
diff --git a/drivers/staging/meilhaus/me0600_optoi_reg.h b/drivers/staging/meilhaus/me0600_optoi_reg.h new file mode 100644 index 000000000000..e0bc45054000 --- /dev/null +++ b/drivers/staging/meilhaus/me0600_optoi_reg.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /** | ||
2 | * @file me0600_optoi_reg.h | ||
3 | * | ||
4 | * @brief ME-630 Optoisolated input subdevice register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME0600_OPTOI_REG_H_ | ||
28 | #define _ME0600_OPTOI_REG_H_ | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | #define ME0600_OPTO_INPUT_REG 0x0004 | ||
33 | |||
34 | #endif | ||
35 | #endif | ||
diff --git a/drivers/staging/meilhaus/me0600_relay.c b/drivers/staging/meilhaus/me0600_relay.c new file mode 100644 index 000000000000..2665c69addd2 --- /dev/null +++ b/drivers/staging/meilhaus/me0600_relay.c | |||
@@ -0,0 +1,359 @@ | |||
1 | /** | ||
2 | * @file me0600_relay.c | ||
3 | * | ||
4 | * @brief ME-630 relay subdevice instance. | ||
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 | /* | ||
33 | * Includes | ||
34 | */ | ||
35 | #include <linux/module.h> | ||
36 | |||
37 | #include <linux/slab.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | #include <asm/io.h> | ||
40 | #include <linux/types.h> | ||
41 | |||
42 | #include "medefines.h" | ||
43 | #include "meinternal.h" | ||
44 | #include "meerror.h" | ||
45 | |||
46 | #include "medebug.h" | ||
47 | #include "me0600_relay_reg.h" | ||
48 | #include "me0600_relay.h" | ||
49 | |||
50 | /* | ||
51 | * Defines | ||
52 | */ | ||
53 | |||
54 | /* | ||
55 | * Functions | ||
56 | */ | ||
57 | |||
58 | static int me0600_relay_io_reset_subdevice(struct me_subdevice *subdevice, | ||
59 | struct file *filep, int flags) | ||
60 | { | ||
61 | me0600_relay_subdevice_t *instance; | ||
62 | |||
63 | PDEBUG("executed.\n"); | ||
64 | |||
65 | instance = (me0600_relay_subdevice_t *) subdevice; | ||
66 | |||
67 | if (flags) { | ||
68 | PERROR("Invalid flag specified.\n"); | ||
69 | return ME_ERRNO_INVALID_FLAGS; | ||
70 | } | ||
71 | |||
72 | ME_SUBDEVICE_ENTER; | ||
73 | |||
74 | spin_lock(&instance->subdevice_lock); | ||
75 | outb(0x0, instance->port_0_reg); | ||
76 | PDEBUG_REG("port_0_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
77 | instance->port_0_reg - instance->reg_base, 0); | ||
78 | outb(0x0, instance->port_1_reg); | ||
79 | PDEBUG_REG("port_1_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
80 | instance->port_1_reg - instance->reg_base, 0); | ||
81 | spin_unlock(&instance->subdevice_lock); | ||
82 | |||
83 | ME_SUBDEVICE_EXIT; | ||
84 | |||
85 | return ME_ERRNO_SUCCESS; | ||
86 | } | ||
87 | |||
88 | static int me0600_relay_io_single_config(me_subdevice_t * subdevice, | ||
89 | struct file *filep, | ||
90 | int channel, | ||
91 | int single_config, | ||
92 | int ref, | ||
93 | int trig_chan, | ||
94 | int trig_type, | ||
95 | int trig_edge, int flags) | ||
96 | { | ||
97 | me0600_relay_subdevice_t *instance; | ||
98 | int err = ME_ERRNO_SUCCESS; | ||
99 | |||
100 | PDEBUG("executed.\n"); | ||
101 | |||
102 | instance = (me0600_relay_subdevice_t *) subdevice; | ||
103 | |||
104 | ME_SUBDEVICE_ENTER; | ||
105 | |||
106 | spin_lock(&instance->subdevice_lock); | ||
107 | |||
108 | switch (flags) { | ||
109 | case ME_IO_SINGLE_CONFIG_NO_FLAGS: | ||
110 | case ME_IO_SINGLE_CONFIG_DIO_WORD: | ||
111 | if (channel == 0) { | ||
112 | if (single_config != ME_SINGLE_CONFIG_DIO_OUTPUT) { | ||
113 | PERROR("Invalid word direction specified.\n"); | ||
114 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
115 | } | ||
116 | } else { | ||
117 | PERROR("Invalid channel specified.\n"); | ||
118 | err = ME_ERRNO_INVALID_CHANNEL; | ||
119 | } | ||
120 | |||
121 | break; | ||
122 | |||
123 | default: | ||
124 | PERROR("Invalid flags specified.\n"); | ||
125 | |||
126 | err = ME_ERRNO_INVALID_FLAGS; | ||
127 | |||
128 | break; | ||
129 | } | ||
130 | |||
131 | spin_unlock(&instance->subdevice_lock); | ||
132 | |||
133 | ME_SUBDEVICE_EXIT; | ||
134 | |||
135 | return err; | ||
136 | } | ||
137 | |||
138 | static int me0600_relay_io_single_read(me_subdevice_t * subdevice, | ||
139 | struct file *filep, | ||
140 | int channel, | ||
141 | int *value, int time_out, int flags) | ||
142 | { | ||
143 | me0600_relay_subdevice_t *instance; | ||
144 | int err = ME_ERRNO_SUCCESS; | ||
145 | |||
146 | PDEBUG("executed.\n"); | ||
147 | |||
148 | instance = (me0600_relay_subdevice_t *) subdevice; | ||
149 | |||
150 | ME_SUBDEVICE_ENTER; | ||
151 | |||
152 | spin_lock(&instance->subdevice_lock); | ||
153 | |||
154 | switch (flags) { | ||
155 | |||
156 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
157 | if ((channel >= 0) && (channel < 8)) { | ||
158 | *value = inb(instance->port_0_reg) & (0x1 << channel); | ||
159 | } else if ((channel >= 8) && (channel < 16)) { | ||
160 | *value = | ||
161 | inb(instance->port_1_reg) & (0x1 << (channel - 8)); | ||
162 | } else { | ||
163 | PERROR("Invalid bit number specified.\n"); | ||
164 | err = ME_ERRNO_INVALID_CHANNEL; | ||
165 | } | ||
166 | |||
167 | break; | ||
168 | |||
169 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
170 | if (channel == 0) { | ||
171 | *value = inb(instance->port_0_reg); | ||
172 | } else if (channel == 1) { | ||
173 | *value = inb(instance->port_1_reg); | ||
174 | } else { | ||
175 | PERROR("Invalid byte number specified.\n"); | ||
176 | err = ME_ERRNO_INVALID_CHANNEL; | ||
177 | } | ||
178 | |||
179 | break; | ||
180 | |||
181 | case ME_IO_SINGLE_NO_FLAGS: | ||
182 | case ME_IO_SINGLE_TYPE_DIO_WORD: | ||
183 | if (channel == 0) { | ||
184 | *value = (uint32_t) inb(instance->port_1_reg) << 8; | ||
185 | *value |= inb(instance->port_0_reg); | ||
186 | } else { | ||
187 | PERROR("Invalid word number specified.\n"); | ||
188 | err = ME_ERRNO_INVALID_CHANNEL; | ||
189 | } | ||
190 | |||
191 | break; | ||
192 | |||
193 | default: | ||
194 | PERROR("Invalid flags specified.\n"); | ||
195 | |||
196 | err = ME_ERRNO_INVALID_FLAGS; | ||
197 | } | ||
198 | |||
199 | spin_unlock(&instance->subdevice_lock); | ||
200 | |||
201 | ME_SUBDEVICE_EXIT; | ||
202 | |||
203 | return err; | ||
204 | } | ||
205 | |||
206 | static int me0600_relay_io_single_write(me_subdevice_t * subdevice, | ||
207 | struct file *filep, | ||
208 | int channel, | ||
209 | int value, int time_out, int flags) | ||
210 | { | ||
211 | me0600_relay_subdevice_t *instance; | ||
212 | int err = ME_ERRNO_SUCCESS; | ||
213 | uint8_t state; | ||
214 | |||
215 | PDEBUG("executed.\n"); | ||
216 | |||
217 | instance = (me0600_relay_subdevice_t *) subdevice; | ||
218 | |||
219 | ME_SUBDEVICE_ENTER; | ||
220 | |||
221 | spin_lock(&instance->subdevice_lock); | ||
222 | |||
223 | switch (flags) { | ||
224 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
225 | if ((channel >= 0) && (channel < 8)) { | ||
226 | state = inb(instance->port_0_reg); | ||
227 | state = | ||
228 | value ? (state | (0x1 << channel)) : (state & | ||
229 | ~(0x1 << | ||
230 | channel)); | ||
231 | outb(state, instance->port_0_reg); | ||
232 | } else if ((channel >= 8) && (channel < 16)) { | ||
233 | state = inb(instance->port_1_reg); | ||
234 | state = | ||
235 | value ? (state | (0x1 << (channel - 8))) : (state & | ||
236 | ~(0x1 << | ||
237 | (channel | ||
238 | - | ||
239 | 8))); | ||
240 | outb(state, instance->port_1_reg); | ||
241 | } else { | ||
242 | PERROR("Invalid bit number specified.\n"); | ||
243 | err = ME_ERRNO_INVALID_CHANNEL; | ||
244 | } | ||
245 | break; | ||
246 | |||
247 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
248 | if (channel == 0) { | ||
249 | outb(value, instance->port_0_reg); | ||
250 | } else if (channel == 1) { | ||
251 | outb(value, instance->port_1_reg); | ||
252 | } else { | ||
253 | PERROR("Invalid byte number specified.\n"); | ||
254 | err = ME_ERRNO_INVALID_CHANNEL; | ||
255 | } | ||
256 | break; | ||
257 | |||
258 | case ME_IO_SINGLE_NO_FLAGS: | ||
259 | case ME_IO_SINGLE_TYPE_DIO_WORD: | ||
260 | if (channel == 0) { | ||
261 | outb(value, instance->port_0_reg); | ||
262 | outb(value >> 8, instance->port_1_reg); | ||
263 | } else { | ||
264 | PERROR("Invalid word number specified.\n"); | ||
265 | err = ME_ERRNO_INVALID_CHANNEL; | ||
266 | } | ||
267 | break; | ||
268 | |||
269 | default: | ||
270 | PERROR("Invalid flags specified.\n"); | ||
271 | err = ME_ERRNO_INVALID_FLAGS; | ||
272 | break; | ||
273 | } | ||
274 | |||
275 | spin_unlock(&instance->subdevice_lock); | ||
276 | |||
277 | ME_SUBDEVICE_EXIT; | ||
278 | |||
279 | return err; | ||
280 | } | ||
281 | |||
282 | static int me0600_relay_query_number_channels(me_subdevice_t * subdevice, | ||
283 | int *number) | ||
284 | { | ||
285 | PDEBUG("executed.\n"); | ||
286 | *number = 16; | ||
287 | return ME_ERRNO_SUCCESS; | ||
288 | } | ||
289 | |||
290 | static int me0600_relay_query_subdevice_type(me_subdevice_t * subdevice, | ||
291 | int *type, int *subtype) | ||
292 | { | ||
293 | PDEBUG("executed.\n"); | ||
294 | *type = ME_TYPE_DO; | ||
295 | *subtype = ME_SUBTYPE_SINGLE; | ||
296 | return ME_ERRNO_SUCCESS; | ||
297 | } | ||
298 | |||
299 | static int me0600_relay_query_subdevice_caps(me_subdevice_t * subdevice, | ||
300 | int *caps) | ||
301 | { | ||
302 | PDEBUG("executed.\n"); | ||
303 | *caps = 0; | ||
304 | return ME_ERRNO_SUCCESS; | ||
305 | } | ||
306 | |||
307 | me0600_relay_subdevice_t *me0600_relay_constructor(uint32_t reg_base) | ||
308 | { | ||
309 | me0600_relay_subdevice_t *subdevice; | ||
310 | int err; | ||
311 | |||
312 | PDEBUG("executed.\n"); | ||
313 | |||
314 | /* Allocate memory for subdevice instance */ | ||
315 | subdevice = kmalloc(sizeof(me0600_relay_subdevice_t), GFP_KERNEL); | ||
316 | |||
317 | if (!subdevice) { | ||
318 | PERROR("Cannot get memory for subdevice instance.\n"); | ||
319 | return NULL; | ||
320 | } | ||
321 | |||
322 | memset(subdevice, 0, sizeof(me0600_relay_subdevice_t)); | ||
323 | |||
324 | /* Initialize subdevice base class */ | ||
325 | err = me_subdevice_init(&subdevice->base); | ||
326 | |||
327 | if (err) { | ||
328 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
329 | kfree(subdevice); | ||
330 | return NULL; | ||
331 | } | ||
332 | // Initialize spin locks. | ||
333 | spin_lock_init(&subdevice->subdevice_lock); | ||
334 | |||
335 | /* Save the subdevice index */ | ||
336 | subdevice->port_0_reg = reg_base + ME0600_RELAIS_0_REG; | ||
337 | subdevice->port_1_reg = reg_base + ME0600_RELAIS_1_REG; | ||
338 | #ifdef MEDEBUG_DEBUG_REG | ||
339 | subdevice->reg_base = reg_base; | ||
340 | #endif | ||
341 | |||
342 | /* Overload base class methods. */ | ||
343 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
344 | me0600_relay_io_reset_subdevice; | ||
345 | subdevice->base.me_subdevice_io_single_config = | ||
346 | me0600_relay_io_single_config; | ||
347 | subdevice->base.me_subdevice_io_single_read = | ||
348 | me0600_relay_io_single_read; | ||
349 | subdevice->base.me_subdevice_io_single_write = | ||
350 | me0600_relay_io_single_write; | ||
351 | subdevice->base.me_subdevice_query_number_channels = | ||
352 | me0600_relay_query_number_channels; | ||
353 | subdevice->base.me_subdevice_query_subdevice_type = | ||
354 | me0600_relay_query_subdevice_type; | ||
355 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
356 | me0600_relay_query_subdevice_caps; | ||
357 | |||
358 | return subdevice; | ||
359 | } | ||
diff --git a/drivers/staging/meilhaus/me0600_relay.h b/drivers/staging/meilhaus/me0600_relay.h new file mode 100644 index 000000000000..2ce7dcab8b39 --- /dev/null +++ b/drivers/staging/meilhaus/me0600_relay.h | |||
@@ -0,0 +1,63 @@ | |||
1 | /** | ||
2 | * @file me0600_relay.h | ||
3 | * | ||
4 | * @brief ME-630 relay subdevice class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME0600_RELAY_H_ | ||
28 | #define _ME0600_RELAY_H_ | ||
29 | |||
30 | #include "mesubdevice.h" | ||
31 | |||
32 | #ifdef __KERNEL__ | ||
33 | |||
34 | /** | ||
35 | * @brief The template subdevice class. | ||
36 | */ | ||
37 | typedef struct me0600_relay_subdevice { | ||
38 | /* Inheritance */ | ||
39 | me_subdevice_t base; /**< The subdevice base class. */ | ||
40 | |||
41 | /* Attributes */ | ||
42 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
43 | |||
44 | unsigned long port_0_reg; /**< Register holding the port status. */ | ||
45 | unsigned long port_1_reg; /**< Register holding the port status. */ | ||
46 | #ifdef MEDEBUG_DEBUG_REG | ||
47 | unsigned long reg_base; | ||
48 | #endif | ||
49 | } me0600_relay_subdevice_t; | ||
50 | |||
51 | /** | ||
52 | * @brief The constructor to generate a ME-630 relay subdevice instance. | ||
53 | * | ||
54 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
55 | * @param ctrl_reg_lock Spin lock protecting the control register. | ||
56 | * | ||
57 | * @return Pointer to new instance on success.\n | ||
58 | * NULL on error. | ||
59 | */ | ||
60 | me0600_relay_subdevice_t *me0600_relay_constructor(uint32_t reg_base); | ||
61 | |||
62 | #endif | ||
63 | #endif | ||
diff --git a/drivers/staging/meilhaus/me0600_relay_reg.h b/drivers/staging/meilhaus/me0600_relay_reg.h new file mode 100644 index 000000000000..ba4db2e223c5 --- /dev/null +++ b/drivers/staging/meilhaus/me0600_relay_reg.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /** | ||
2 | * @file me0600_relay_reg.h | ||
3 | * | ||
4 | * @brief ME-630 relay subdevice register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME0600_RELAY_REG_H_ | ||
28 | #define _ME0600_RELAY_REG_H_ | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | #define ME0600_RELAIS_0_REG 0x0001 | ||
33 | #define ME0600_RELAIS_1_REG 0x0002 | ||
34 | |||
35 | #endif | ||
36 | #endif | ||
diff --git a/drivers/staging/meilhaus/me0600_ttli.c b/drivers/staging/meilhaus/me0600_ttli.c new file mode 100644 index 000000000000..ab8e13b6f329 --- /dev/null +++ b/drivers/staging/meilhaus/me0600_ttli.c | |||
@@ -0,0 +1,238 @@ | |||
1 | /** | ||
2 | * @file me0600_ttli.c | ||
3 | * | ||
4 | * @brief ME-630 TTL input subdevice instance. | ||
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 | /* | ||
33 | * Includes | ||
34 | */ | ||
35 | #include <linux/module.h> | ||
36 | |||
37 | #include <linux/slab.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | #include <asm/io.h> | ||
40 | #include <linux/types.h> | ||
41 | |||
42 | #include "medefines.h" | ||
43 | #include "meinternal.h" | ||
44 | #include "meerror.h" | ||
45 | |||
46 | #include "medebug.h" | ||
47 | #include "me0600_ttli_reg.h" | ||
48 | #include "me0600_ttli.h" | ||
49 | |||
50 | /* | ||
51 | * Defines | ||
52 | */ | ||
53 | |||
54 | /* | ||
55 | * Functions | ||
56 | */ | ||
57 | |||
58 | static int me0600_ttli_io_reset_subdevice(struct me_subdevice *subdevice, | ||
59 | struct file *filep, int flags) | ||
60 | { | ||
61 | if (flags) { | ||
62 | PERROR("Invalid flag specified.\n"); | ||
63 | return ME_ERRNO_INVALID_FLAGS; | ||
64 | } | ||
65 | |||
66 | PDEBUG("executed.\n"); | ||
67 | return ME_ERRNO_SUCCESS; | ||
68 | } | ||
69 | |||
70 | static int me0600_ttli_io_single_config(me_subdevice_t * subdevice, | ||
71 | struct file *filep, | ||
72 | int channel, | ||
73 | int single_config, | ||
74 | int ref, | ||
75 | int trig_chan, | ||
76 | int trig_type, int trig_edge, int flags) | ||
77 | { | ||
78 | me0600_ttli_subdevice_t *instance; | ||
79 | int err = ME_ERRNO_SUCCESS; | ||
80 | |||
81 | PDEBUG("executed.\n"); | ||
82 | |||
83 | instance = (me0600_ttli_subdevice_t *) subdevice; | ||
84 | |||
85 | ME_SUBDEVICE_ENTER; | ||
86 | |||
87 | spin_lock(&instance->subdevice_lock); | ||
88 | |||
89 | switch (flags) { | ||
90 | case ME_IO_SINGLE_CONFIG_NO_FLAGS: | ||
91 | case ME_IO_SINGLE_CONFIG_DIO_BYTE: | ||
92 | if (channel == 0) { | ||
93 | if (single_config != ME_SINGLE_CONFIG_DIO_INPUT) { | ||
94 | PERROR("Invalid port direction specified.\n"); | ||
95 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
96 | } | ||
97 | } else { | ||
98 | PERROR("Invalid channel specified.\n"); | ||
99 | err = ME_ERRNO_INVALID_CHANNEL; | ||
100 | } | ||
101 | |||
102 | break; | ||
103 | |||
104 | default: | ||
105 | PERROR("Invalid flags specified.\n"); | ||
106 | |||
107 | err = ME_ERRNO_INVALID_FLAGS; | ||
108 | |||
109 | break; | ||
110 | } | ||
111 | |||
112 | spin_unlock(&instance->subdevice_lock); | ||
113 | |||
114 | ME_SUBDEVICE_EXIT; | ||
115 | |||
116 | return err; | ||
117 | } | ||
118 | |||
119 | static int me0600_ttli_io_single_read(me_subdevice_t * subdevice, | ||
120 | struct file *filep, | ||
121 | int channel, | ||
122 | int *value, int time_out, int flags) | ||
123 | { | ||
124 | me0600_ttli_subdevice_t *instance; | ||
125 | int err = ME_ERRNO_SUCCESS; | ||
126 | |||
127 | PDEBUG("executed.\n"); | ||
128 | |||
129 | instance = (me0600_ttli_subdevice_t *) subdevice; | ||
130 | |||
131 | ME_SUBDEVICE_ENTER; | ||
132 | |||
133 | spin_lock(&instance->subdevice_lock); | ||
134 | |||
135 | switch (flags) { | ||
136 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
137 | if ((channel >= 0) && (channel < 8)) { | ||
138 | *value = inb(instance->port_reg) & (0x1 << channel); | ||
139 | } else { | ||
140 | PERROR("Invalid bit number specified.\n"); | ||
141 | err = ME_ERRNO_INVALID_CHANNEL; | ||
142 | } | ||
143 | break; | ||
144 | |||
145 | case ME_IO_SINGLE_NO_FLAGS: | ||
146 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
147 | if (channel == 0) { | ||
148 | *value = inb(instance->port_reg); | ||
149 | } else { | ||
150 | PERROR("Invalid byte number specified.\n"); | ||
151 | err = ME_ERRNO_INVALID_CHANNEL; | ||
152 | } | ||
153 | break; | ||
154 | |||
155 | default: | ||
156 | PERROR("Invalid flags specified.\n"); | ||
157 | err = ME_ERRNO_INVALID_FLAGS; | ||
158 | } | ||
159 | |||
160 | spin_unlock(&instance->subdevice_lock); | ||
161 | |||
162 | ME_SUBDEVICE_EXIT; | ||
163 | |||
164 | return err; | ||
165 | } | ||
166 | |||
167 | static int me0600_ttli_query_number_channels(me_subdevice_t * subdevice, | ||
168 | int *number) | ||
169 | { | ||
170 | PDEBUG("executed.\n"); | ||
171 | *number = 8; | ||
172 | return ME_ERRNO_SUCCESS; | ||
173 | } | ||
174 | |||
175 | static int me0600_ttli_query_subdevice_type(me_subdevice_t * subdevice, | ||
176 | int *type, int *subtype) | ||
177 | { | ||
178 | PDEBUG("executed.\n"); | ||
179 | *type = ME_TYPE_DI; | ||
180 | *subtype = ME_SUBTYPE_SINGLE; | ||
181 | return ME_ERRNO_SUCCESS; | ||
182 | } | ||
183 | |||
184 | static int me0600_ttli_query_subdevice_caps(me_subdevice_t * subdevice, | ||
185 | int *caps) | ||
186 | { | ||
187 | PDEBUG("executed.\n"); | ||
188 | *caps = 0; | ||
189 | return ME_ERRNO_SUCCESS; | ||
190 | } | ||
191 | |||
192 | me0600_ttli_subdevice_t *me0600_ttli_constructor(uint32_t reg_base) | ||
193 | { | ||
194 | me0600_ttli_subdevice_t *subdevice; | ||
195 | int err; | ||
196 | |||
197 | PDEBUG("executed.\n"); | ||
198 | |||
199 | /* Allocate memory for subdevice instance */ | ||
200 | subdevice = kmalloc(sizeof(me0600_ttli_subdevice_t), GFP_KERNEL); | ||
201 | |||
202 | if (!subdevice) { | ||
203 | PERROR("Cannot get memory for subdevice instance.\n"); | ||
204 | return NULL; | ||
205 | } | ||
206 | |||
207 | memset(subdevice, 0, sizeof(me0600_ttli_subdevice_t)); | ||
208 | |||
209 | /* Initialize subdevice base class */ | ||
210 | err = me_subdevice_init(&subdevice->base); | ||
211 | |||
212 | if (err) { | ||
213 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
214 | kfree(subdevice); | ||
215 | return NULL; | ||
216 | } | ||
217 | // Initialize spin locks. | ||
218 | spin_lock_init(&subdevice->subdevice_lock); | ||
219 | |||
220 | /* Save the subdevice index */ | ||
221 | subdevice->port_reg = reg_base + ME0600_TTL_INPUT_REG; | ||
222 | |||
223 | /* Overload base class methods. */ | ||
224 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
225 | me0600_ttli_io_reset_subdevice; | ||
226 | subdevice->base.me_subdevice_io_single_config = | ||
227 | me0600_ttli_io_single_config; | ||
228 | subdevice->base.me_subdevice_io_single_read = | ||
229 | me0600_ttli_io_single_read; | ||
230 | subdevice->base.me_subdevice_query_number_channels = | ||
231 | me0600_ttli_query_number_channels; | ||
232 | subdevice->base.me_subdevice_query_subdevice_type = | ||
233 | me0600_ttli_query_subdevice_type; | ||
234 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
235 | me0600_ttli_query_subdevice_caps; | ||
236 | |||
237 | return subdevice; | ||
238 | } | ||
diff --git a/drivers/staging/meilhaus/me0600_ttli.h b/drivers/staging/meilhaus/me0600_ttli.h new file mode 100644 index 000000000000..6c9039614867 --- /dev/null +++ b/drivers/staging/meilhaus/me0600_ttli.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /** | ||
2 | * @file me0600_ttli.h | ||
3 | * | ||
4 | * @brief ME-630 TTL input subdevice class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME0600_TTLI_H_ | ||
28 | #define _ME0600_TTLI_H_ | ||
29 | |||
30 | #include "mesubdevice.h" | ||
31 | |||
32 | #ifdef __KERNEL__ | ||
33 | |||
34 | /** | ||
35 | * @brief The template subdevice class. | ||
36 | */ | ||
37 | typedef struct me0600_ttli_subdevice { | ||
38 | /* Inheritance */ | ||
39 | me_subdevice_t base; /**< The subdevice base class. */ | ||
40 | |||
41 | /* Attributes */ | ||
42 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
43 | |||
44 | uint32_t port_reg; /**< Register holding the port status. */ | ||
45 | } me0600_ttli_subdevice_t; | ||
46 | |||
47 | /** | ||
48 | * @brief The constructor to generate a ME-630 TTL input subdevice instance. | ||
49 | * | ||
50 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
51 | * | ||
52 | * @return Pointer to new instance on success.\n | ||
53 | * NULL on error. | ||
54 | */ | ||
55 | me0600_ttli_subdevice_t *me0600_ttli_constructor(uint32_t reg_base); | ||
56 | |||
57 | #endif | ||
58 | #endif | ||
diff --git a/drivers/staging/meilhaus/me0600_ttli_reg.h b/drivers/staging/meilhaus/me0600_ttli_reg.h new file mode 100644 index 000000000000..4f986d160934 --- /dev/null +++ b/drivers/staging/meilhaus/me0600_ttli_reg.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /** | ||
2 | * @file me0600_ttli_reg.h | ||
3 | * | ||
4 | * @brief ME-630 TTL input subdevice register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME0600_TTLI_REG_H_ | ||
28 | #define _ME0600_TTLI_REG_H_ | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | #define ME0600_TTL_INPUT_REG 0x0003 | ||
33 | |||
34 | #endif | ||
35 | #endif | ||
diff --git a/drivers/staging/meilhaus/me0900_device.c b/drivers/staging/meilhaus/me0900_device.c new file mode 100644 index 000000000000..764d5d307c44 --- /dev/null +++ b/drivers/staging/meilhaus/me0900_device.c | |||
@@ -0,0 +1,180 @@ | |||
1 | /** | ||
2 | * @file me0900_device.c | ||
3 | * | ||
4 | * @brief ME-9x 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 "me0900_device.h" | ||
49 | #include "me0900_reg.h" | ||
50 | #include "mesubdevice.h" | ||
51 | #include "me0900_do.h" | ||
52 | #include "me0900_di.h" | ||
53 | |||
54 | me_device_t *me0900_pci_constructor(struct pci_dev *pci_device) | ||
55 | { | ||
56 | me0900_device_t *me0900_device; | ||
57 | me_subdevice_t *subdevice; | ||
58 | unsigned int version_idx; | ||
59 | int err; | ||
60 | int i; | ||
61 | int port_shift; | ||
62 | |||
63 | PDEBUG("executed.\n"); | ||
64 | |||
65 | // Allocate structure for device instance. | ||
66 | me0900_device = kmalloc(sizeof(me0900_device_t), GFP_KERNEL); | ||
67 | |||
68 | if (!me0900_device) { | ||
69 | PERROR("Cannot get memory for device instance.\n"); | ||
70 | return NULL; | ||
71 | } | ||
72 | |||
73 | memset(me0900_device, 0, sizeof(me0900_device_t)); | ||
74 | |||
75 | // Initialize base class structure. | ||
76 | err = me_device_pci_init((me_device_t *) me0900_device, pci_device); | ||
77 | |||
78 | if (err) { | ||
79 | kfree(me0900_device); | ||
80 | PERROR("Cannot initialize device base class.\n"); | ||
81 | return NULL; | ||
82 | } | ||
83 | |||
84 | /* Get the index in the device version information table. */ | ||
85 | version_idx = | ||
86 | me0900_versions_get_device_index(me0900_device->base.info.pci. | ||
87 | device_id); | ||
88 | |||
89 | /* Initialize 8255 chip to desired mode */ | ||
90 | if (me0900_device->base.info.pci.device_id == | ||
91 | PCI_DEVICE_ID_MEILHAUS_ME0940) { | ||
92 | outb(0x9B, | ||
93 | me0900_device->base.info.pci.reg_bases[2] + | ||
94 | ME0900_CTRL_REG); | ||
95 | } else if (me0900_device->base.info.pci.device_id == | ||
96 | PCI_DEVICE_ID_MEILHAUS_ME0950) { | ||
97 | outb(0x89, | ||
98 | me0900_device->base.info.pci.reg_bases[2] + | ||
99 | ME0900_CTRL_REG); | ||
100 | outb(0x00, | ||
101 | me0900_device->base.info.pci.reg_bases[2] + | ||
102 | ME0900_WRITE_ENABLE_REG); | ||
103 | } else if (me0900_device->base.info.pci.device_id == | ||
104 | PCI_DEVICE_ID_MEILHAUS_ME0960) { | ||
105 | outb(0x8B, | ||
106 | me0900_device->base.info.pci.reg_bases[2] + | ||
107 | ME0900_CTRL_REG); | ||
108 | outb(0x00, | ||
109 | me0900_device->base.info.pci.reg_bases[2] + | ||
110 | ME0900_WRITE_ENABLE_REG); | ||
111 | } | ||
112 | |||
113 | port_shift = | ||
114 | (me0900_device->base.info.pci.device_id == | ||
115 | PCI_DEVICE_ID_MEILHAUS_ME0960) ? 1 : 0; | ||
116 | // Create subdevice instances. | ||
117 | |||
118 | for (i = 0; i < me0900_versions[version_idx].di_subdevices; i++) { | ||
119 | subdevice = | ||
120 | (me_subdevice_t *) me0900_di_constructor(me0900_device-> | ||
121 | base.info.pci. | ||
122 | reg_bases[2], | ||
123 | i + port_shift); | ||
124 | |||
125 | if (!subdevice) { | ||
126 | me_device_deinit((me_device_t *) me0900_device); | ||
127 | kfree(me0900_device); | ||
128 | PERROR("Cannot get memory for subdevice.\n"); | ||
129 | return NULL; | ||
130 | } | ||
131 | |||
132 | me_slist_add_subdevice_tail(&me0900_device->base.slist, | ||
133 | subdevice); | ||
134 | } | ||
135 | |||
136 | for (i = 0; i < me0900_versions[version_idx].do_subdevices; i++) { | ||
137 | subdevice = | ||
138 | (me_subdevice_t *) me0900_do_constructor(me0900_device-> | ||
139 | base.info.pci. | ||
140 | reg_bases[2], i); | ||
141 | |||
142 | if (!subdevice) { | ||
143 | me_device_deinit((me_device_t *) me0900_device); | ||
144 | kfree(me0900_device); | ||
145 | PERROR("Cannot get memory for subdevice.\n"); | ||
146 | return NULL; | ||
147 | } | ||
148 | |||
149 | me_slist_add_subdevice_tail(&me0900_device->base.slist, | ||
150 | subdevice); | ||
151 | } | ||
152 | |||
153 | return (me_device_t *) me0900_device; | ||
154 | } | ||
155 | |||
156 | // Init and exit of module. | ||
157 | |||
158 | static int __init me0900_init(void) | ||
159 | { | ||
160 | PDEBUG("executed.\n."); | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | static void __exit me0900_exit(void) | ||
165 | { | ||
166 | PDEBUG("executed.\n."); | ||
167 | } | ||
168 | |||
169 | module_init(me0900_init); | ||
170 | module_exit(me0900_exit); | ||
171 | |||
172 | // Administrative stuff for modinfo. | ||
173 | MODULE_AUTHOR | ||
174 | ("Guenter Gebhardt <g.gebhardt@meilhaus.de> & Krzysztof Gantzke <k.gantzke@meilhaus.de>"); | ||
175 | MODULE_DESCRIPTION("Device Driver Module for ME-9x Device"); | ||
176 | MODULE_SUPPORTED_DEVICE("Meilhaus ME-9x Devices"); | ||
177 | MODULE_LICENSE("GPL"); | ||
178 | |||
179 | // Export the constructor. | ||
180 | EXPORT_SYMBOL(me0900_pci_constructor); | ||
diff --git a/drivers/staging/meilhaus/me0900_device.h b/drivers/staging/meilhaus/me0900_device.h new file mode 100644 index 000000000000..bd17f2521511 --- /dev/null +++ b/drivers/staging/meilhaus/me0900_device.h | |||
@@ -0,0 +1,92 @@ | |||
1 | /** | ||
2 | * @file me0900_device.h | ||
3 | * | ||
4 | * @brief ME-0900 (ME-9x) device class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME0900_DEVICE_H | ||
28 | #define _ME0900_DEVICE_H | ||
29 | |||
30 | #include <linux/pci.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | |||
33 | #include "medevice.h" | ||
34 | |||
35 | #ifdef __KERNEL__ | ||
36 | |||
37 | /** | ||
38 | * @brief Structure holding ME-0900 (ME-9x) device capabilities. | ||
39 | */ | ||
40 | typedef struct me0900_version { | ||
41 | uint16_t device_id; | ||
42 | unsigned int di_subdevices; | ||
43 | unsigned int do_subdevices; | ||
44 | } me0900_version_t; | ||
45 | |||
46 | /** | ||
47 | * @brief Device capabilities. | ||
48 | */ | ||
49 | static me0900_version_t me0900_versions[] = { | ||
50 | {PCI_DEVICE_ID_MEILHAUS_ME0940, 2, 0}, | ||
51 | {PCI_DEVICE_ID_MEILHAUS_ME0950, 0, 2}, | ||
52 | {PCI_DEVICE_ID_MEILHAUS_ME0960, 1, 1}, | ||
53 | {0}, | ||
54 | }; | ||
55 | |||
56 | #define ME0900_DEVICE_VERSIONS (sizeof(me0900_versions) / sizeof(me0900_version_t) - 1) /**< Returns the number of entries in #me0900_versions. */ | ||
57 | |||
58 | /** | ||
59 | * @brief Returns the index of the device entry in #me0900_versions. | ||
60 | * | ||
61 | * @param device_id The PCI device id of the device to query. | ||
62 | * @return The index of the device in #me0900_versions. | ||
63 | */ | ||
64 | static inline unsigned int me0900_versions_get_device_index(uint16_t device_id) | ||
65 | { | ||
66 | unsigned int i; | ||
67 | for (i = 0; i < ME0900_DEVICE_VERSIONS; i++) | ||
68 | if (me0900_versions[i].device_id == device_id) | ||
69 | break; | ||
70 | return i; | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * @brief The ME-0900 (ME-9x) device class structure. | ||
75 | */ | ||
76 | typedef struct me0900_device { | ||
77 | me_device_t base; /**< The Meilhaus device base class. */ | ||
78 | } me0900_device_t; | ||
79 | |||
80 | /** | ||
81 | * @brief The ME-9x device class constructor. | ||
82 | * | ||
83 | * @param pci_device The pci device structure given by the PCI subsystem. | ||
84 | * | ||
85 | * @return On succes a new ME-0900 (ME-9x) device instance. \n | ||
86 | * NULL on error. | ||
87 | */ | ||
88 | me_device_t *me0900_pci_constructor(struct pci_dev *pci_device) | ||
89 | __attribute__ ((weak)); | ||
90 | |||
91 | #endif | ||
92 | #endif | ||
diff --git a/drivers/staging/meilhaus/me0900_di.c b/drivers/staging/meilhaus/me0900_di.c new file mode 100644 index 000000000000..d7d7394f800a --- /dev/null +++ b/drivers/staging/meilhaus/me0900_di.c | |||
@@ -0,0 +1,246 @@ | |||
1 | /** | ||
2 | * @file me0900_di.c | ||
3 | * | ||
4 | * @brief ME-9x digital input subdevice instance. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef __KERNEL__ | ||
28 | # define __KERNEL__ | ||
29 | #endif | ||
30 | |||
31 | /* | ||
32 | * Includes | ||
33 | */ | ||
34 | #include <linux/module.h> | ||
35 | |||
36 | #include <linux/slab.h> | ||
37 | #include <linux/spinlock.h> | ||
38 | #include <asm/io.h> | ||
39 | #include <linux/types.h> | ||
40 | #include <linux/interrupt.h> | ||
41 | #include <linux/version.h> | ||
42 | |||
43 | #include "medefines.h" | ||
44 | #include "meinternal.h" | ||
45 | #include "meerror.h" | ||
46 | |||
47 | #include "meids.h" | ||
48 | #include "medebug.h" | ||
49 | #include "meplx_reg.h" | ||
50 | #include "me0900_reg.h" | ||
51 | #include "me0900_di.h" | ||
52 | |||
53 | /* | ||
54 | * Defines | ||
55 | */ | ||
56 | |||
57 | /* | ||
58 | * Functions | ||
59 | */ | ||
60 | |||
61 | static int me0900_di_io_reset_subdevice(struct me_subdevice *subdevice, | ||
62 | struct file *filep, int flags) | ||
63 | { | ||
64 | PDEBUG("executed.\n"); | ||
65 | |||
66 | if (flags) { | ||
67 | PERROR("Invalid flag specified.\n"); | ||
68 | return ME_ERRNO_INVALID_FLAGS; | ||
69 | } | ||
70 | |||
71 | return ME_ERRNO_SUCCESS; | ||
72 | } | ||
73 | |||
74 | static int me0900_di_io_single_config(me_subdevice_t * subdevice, | ||
75 | struct file *filep, | ||
76 | int channel, | ||
77 | int single_config, | ||
78 | int ref, | ||
79 | int trig_chan, | ||
80 | int trig_type, int trig_edge, int flags) | ||
81 | { | ||
82 | me0900_di_subdevice_t *instance; | ||
83 | int err = ME_ERRNO_SUCCESS; | ||
84 | |||
85 | PDEBUG("executed.\n"); | ||
86 | |||
87 | instance = (me0900_di_subdevice_t *) subdevice; | ||
88 | |||
89 | ME_SUBDEVICE_ENTER; | ||
90 | |||
91 | spin_lock(&instance->subdevice_lock); | ||
92 | switch (flags) { | ||
93 | case ME_IO_SINGLE_CONFIG_NO_FLAGS: | ||
94 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
95 | if (channel == 0) { | ||
96 | if (single_config == ME_SINGLE_CONFIG_DIO_INPUT) { | ||
97 | } else { | ||
98 | PERROR("Invalid byte direction specified.\n"); | ||
99 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
100 | } | ||
101 | } else { | ||
102 | PERROR("Invalid byte number specified.\n"); | ||
103 | err = ME_ERRNO_INVALID_CHANNEL; | ||
104 | } | ||
105 | break; | ||
106 | |||
107 | default: | ||
108 | PERROR("Invalid flags specified.\n"); | ||
109 | err = ME_ERRNO_INVALID_FLAGS; | ||
110 | } | ||
111 | spin_unlock(&instance->subdevice_lock); | ||
112 | |||
113 | ME_SUBDEVICE_EXIT; | ||
114 | |||
115 | return err; | ||
116 | } | ||
117 | |||
118 | static int me0900_di_io_single_read(me_subdevice_t * subdevice, | ||
119 | struct file *filep, | ||
120 | int channel, | ||
121 | int *value, int time_out, int flags) | ||
122 | { | ||
123 | me0900_di_subdevice_t *instance; | ||
124 | int err = ME_ERRNO_SUCCESS; | ||
125 | |||
126 | PDEBUG("executed.\n"); | ||
127 | |||
128 | instance = (me0900_di_subdevice_t *) subdevice; | ||
129 | |||
130 | ME_SUBDEVICE_ENTER; | ||
131 | |||
132 | spin_lock(&instance->subdevice_lock); | ||
133 | switch (flags) { | ||
134 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
135 | if ((channel >= 0) && (channel < 8)) { | ||
136 | *value = (~inb(instance->port_reg)) & (0x1 << channel); | ||
137 | } else { | ||
138 | PERROR("Invalid bit number specified.\n"); | ||
139 | err = ME_ERRNO_INVALID_CHANNEL; | ||
140 | } | ||
141 | break; | ||
142 | |||
143 | case ME_IO_SINGLE_NO_FLAGS: | ||
144 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
145 | if (channel == 0) { | ||
146 | *value = ~inb(instance->port_reg); | ||
147 | } else { | ||
148 | PERROR("Invalid byte number specified.\n"); | ||
149 | err = ME_ERRNO_INVALID_CHANNEL; | ||
150 | } | ||
151 | break; | ||
152 | |||
153 | default: | ||
154 | PERROR("Invalid flags specified.\n"); | ||
155 | err = ME_ERRNO_INVALID_FLAGS; | ||
156 | } | ||
157 | spin_unlock(&instance->subdevice_lock); | ||
158 | |||
159 | ME_SUBDEVICE_EXIT; | ||
160 | |||
161 | return err; | ||
162 | } | ||
163 | |||
164 | static int me0900_di_query_number_channels(me_subdevice_t * subdevice, | ||
165 | int *number) | ||
166 | { | ||
167 | PDEBUG("executed.\n"); | ||
168 | *number = 8; | ||
169 | return ME_ERRNO_SUCCESS; | ||
170 | } | ||
171 | |||
172 | static int me0900_di_query_subdevice_type(me_subdevice_t * subdevice, | ||
173 | int *type, int *subtype) | ||
174 | { | ||
175 | PDEBUG("executed.\n"); | ||
176 | *type = ME_TYPE_DI; | ||
177 | *subtype = ME_SUBTYPE_SINGLE; | ||
178 | return ME_ERRNO_SUCCESS; | ||
179 | } | ||
180 | |||
181 | static int me0900_di_query_subdevice_caps(me_subdevice_t * subdevice, int *caps) | ||
182 | { | ||
183 | PDEBUG("executed.\n"); | ||
184 | *caps = 0; | ||
185 | return ME_ERRNO_SUCCESS; | ||
186 | } | ||
187 | |||
188 | me0900_di_subdevice_t *me0900_di_constructor(uint32_t reg_base, | ||
189 | unsigned int di_idx) | ||
190 | { | ||
191 | me0900_di_subdevice_t *subdevice; | ||
192 | int err; | ||
193 | |||
194 | PDEBUG("executed.\n"); | ||
195 | |||
196 | /* Allocate memory for subdevice instance */ | ||
197 | subdevice = kmalloc(sizeof(me0900_di_subdevice_t), GFP_KERNEL); | ||
198 | |||
199 | if (!subdevice) { | ||
200 | PERROR("Cannot get memory for subdevice instance.\n"); | ||
201 | return NULL; | ||
202 | } | ||
203 | |||
204 | memset(subdevice, 0, sizeof(me0900_di_subdevice_t)); | ||
205 | |||
206 | /* Initialize subdevice base class */ | ||
207 | err = me_subdevice_init(&subdevice->base); | ||
208 | |||
209 | if (err) { | ||
210 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
211 | kfree(subdevice); | ||
212 | return NULL; | ||
213 | } | ||
214 | // Initialize spin locks. | ||
215 | spin_lock_init(&subdevice->subdevice_lock); | ||
216 | |||
217 | /* Save the subdevice index. */ | ||
218 | subdevice->di_idx = di_idx; | ||
219 | |||
220 | /* Initialize registers */ | ||
221 | if (di_idx == 0) { | ||
222 | subdevice->ctrl_reg = reg_base + ME0900_CTRL_REG; | ||
223 | subdevice->port_reg = reg_base + ME0900_PORT_A_REG; | ||
224 | } else { | ||
225 | subdevice->ctrl_reg = reg_base + ME0900_CTRL_REG; | ||
226 | subdevice->port_reg = reg_base + ME0900_PORT_B_REG; | ||
227 | } | ||
228 | #ifdef MEDEBUG_DEBUG_REG | ||
229 | subdevice->reg_base = reg_base; | ||
230 | #endif | ||
231 | |||
232 | /* Overload base class methods. */ | ||
233 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
234 | me0900_di_io_reset_subdevice; | ||
235 | subdevice->base.me_subdevice_io_single_config = | ||
236 | me0900_di_io_single_config; | ||
237 | subdevice->base.me_subdevice_io_single_read = me0900_di_io_single_read; | ||
238 | subdevice->base.me_subdevice_query_number_channels = | ||
239 | me0900_di_query_number_channels; | ||
240 | subdevice->base.me_subdevice_query_subdevice_type = | ||
241 | me0900_di_query_subdevice_type; | ||
242 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
243 | me0900_di_query_subdevice_caps; | ||
244 | |||
245 | return subdevice; | ||
246 | } | ||
diff --git a/drivers/staging/meilhaus/me0900_di.h b/drivers/staging/meilhaus/me0900_di.h new file mode 100644 index 000000000000..014f1348fc9f --- /dev/null +++ b/drivers/staging/meilhaus/me0900_di.h | |||
@@ -0,0 +1,65 @@ | |||
1 | /** | ||
2 | * @file me0900_di.h | ||
3 | * | ||
4 | * @brief ME-9x digital input subdevice class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME0900_DI_H_ | ||
28 | #define _ME0900_DI_H_ | ||
29 | |||
30 | #include "mesubdevice.h" | ||
31 | |||
32 | #ifdef __KERNEL__ | ||
33 | |||
34 | /** | ||
35 | * @brief The template subdevice class. | ||
36 | */ | ||
37 | typedef struct me0900_di_subdevice { | ||
38 | /* Inheritance */ | ||
39 | me_subdevice_t base; /**< The subdevice base class. */ | ||
40 | |||
41 | /* Attributes */ | ||
42 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
43 | |||
44 | unsigned int di_idx; | ||
45 | |||
46 | unsigned long ctrl_reg; | ||
47 | unsigned long port_reg; | ||
48 | #ifdef MEDEBUG_DEBUG_REG | ||
49 | unsigned long reg_base; | ||
50 | #endif | ||
51 | } me0900_di_subdevice_t; | ||
52 | |||
53 | /** | ||
54 | * @brief The constructor to generate a ME-9x digital input subdevice instance. | ||
55 | * | ||
56 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
57 | * | ||
58 | * @return Pointer to new instance on success.\n | ||
59 | * NULL on error. | ||
60 | */ | ||
61 | me0900_di_subdevice_t *me0900_di_constructor(uint32_t me0900_reg_base, | ||
62 | unsigned int di_idx); | ||
63 | |||
64 | #endif | ||
65 | #endif | ||
diff --git a/drivers/staging/meilhaus/me0900_do.c b/drivers/staging/meilhaus/me0900_do.c new file mode 100644 index 000000000000..b5b9c3a98c94 --- /dev/null +++ b/drivers/staging/meilhaus/me0900_do.c | |||
@@ -0,0 +1,314 @@ | |||
1 | /** | ||
2 | * @file me0900_do.c | ||
3 | * | ||
4 | * @brief ME-9x digital output subdevice instance. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef __KERNEL__ | ||
28 | # define __KERNEL__ | ||
29 | #endif | ||
30 | |||
31 | /* | ||
32 | * Includes | ||
33 | */ | ||
34 | #include <linux/module.h> | ||
35 | |||
36 | #include <linux/slab.h> | ||
37 | #include <linux/spinlock.h> | ||
38 | #include <asm/io.h> | ||
39 | #include <linux/types.h> | ||
40 | |||
41 | #include "medefines.h" | ||
42 | #include "meinternal.h" | ||
43 | #include "meerror.h" | ||
44 | |||
45 | #include "medebug.h" | ||
46 | #include "me0900_reg.h" | ||
47 | #include "me0900_do.h" | ||
48 | |||
49 | /* | ||
50 | * Defines | ||
51 | */ | ||
52 | |||
53 | /* | ||
54 | * Functions | ||
55 | */ | ||
56 | |||
57 | static int me0900_do_io_reset_subdevice(struct me_subdevice *subdevice, | ||
58 | struct file *filep, int flags) | ||
59 | { | ||
60 | me0900_do_subdevice_t *instance; | ||
61 | |||
62 | PDEBUG("executed.\n"); | ||
63 | |||
64 | instance = (me0900_do_subdevice_t *) subdevice; | ||
65 | |||
66 | if (flags) { | ||
67 | PERROR("Invalid flag specified.\n"); | ||
68 | return ME_ERRNO_INVALID_FLAGS; | ||
69 | } | ||
70 | |||
71 | ME_SUBDEVICE_ENTER; | ||
72 | |||
73 | spin_lock(&instance->subdevice_lock); | ||
74 | outb(0xFF, instance->port_reg); | ||
75 | PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
76 | instance->port_reg - instance->reg_base, 0xff); | ||
77 | spin_unlock(&instance->subdevice_lock); | ||
78 | |||
79 | ME_SUBDEVICE_EXIT; | ||
80 | |||
81 | return ME_ERRNO_SUCCESS; | ||
82 | } | ||
83 | |||
84 | static int me0900_do_io_single_config(me_subdevice_t * subdevice, | ||
85 | struct file *filep, | ||
86 | int channel, | ||
87 | int single_config, | ||
88 | int ref, | ||
89 | int trig_chan, | ||
90 | int trig_type, int trig_edge, int flags) | ||
91 | { | ||
92 | me0900_do_subdevice_t *instance; | ||
93 | int err = ME_ERRNO_SUCCESS; | ||
94 | |||
95 | PDEBUG("executed.\n"); | ||
96 | |||
97 | instance = (me0900_do_subdevice_t *) subdevice; | ||
98 | |||
99 | ME_SUBDEVICE_ENTER; | ||
100 | |||
101 | spin_lock(&instance->subdevice_lock); | ||
102 | switch (flags) { | ||
103 | case ME_IO_SINGLE_CONFIG_NO_FLAGS: | ||
104 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
105 | if (channel == 0) { | ||
106 | if (single_config == ME_SINGLE_CONFIG_DIO_OUTPUT) { | ||
107 | } else { | ||
108 | PERROR("Invalid byte direction specified.\n"); | ||
109 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
110 | } | ||
111 | } else { | ||
112 | PERROR("Invalid byte number specified.\n"); | ||
113 | err = ME_ERRNO_INVALID_CHANNEL; | ||
114 | } | ||
115 | break; | ||
116 | |||
117 | default: | ||
118 | PERROR("Invalid flags specified.\n"); | ||
119 | err = ME_ERRNO_INVALID_FLAGS; | ||
120 | } | ||
121 | spin_unlock(&instance->subdevice_lock); | ||
122 | |||
123 | ME_SUBDEVICE_EXIT; | ||
124 | |||
125 | return err; | ||
126 | } | ||
127 | |||
128 | static int me0900_do_io_single_read(me_subdevice_t * subdevice, | ||
129 | struct file *filep, | ||
130 | int channel, | ||
131 | int *value, int time_out, int flags) | ||
132 | { | ||
133 | me0900_do_subdevice_t *instance; | ||
134 | int err = ME_ERRNO_SUCCESS; | ||
135 | |||
136 | PDEBUG("executed.\n"); | ||
137 | |||
138 | instance = (me0900_do_subdevice_t *) subdevice; | ||
139 | |||
140 | ME_SUBDEVICE_ENTER; | ||
141 | |||
142 | spin_lock(&instance->subdevice_lock); | ||
143 | switch (flags) { | ||
144 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
145 | if ((channel >= 0) && (channel < 8)) { | ||
146 | *value = (~inb(instance->port_reg)) & (0x1 << channel); | ||
147 | } else { | ||
148 | PERROR("Invalid bit number specified.\n"); | ||
149 | err = ME_ERRNO_INVALID_CHANNEL; | ||
150 | } | ||
151 | break; | ||
152 | |||
153 | case ME_IO_SINGLE_NO_FLAGS: | ||
154 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
155 | if (channel == 0) { | ||
156 | *value = ~inb(instance->port_reg); | ||
157 | } else { | ||
158 | PERROR("Invalid byte number specified.\n"); | ||
159 | err = ME_ERRNO_INVALID_CHANNEL; | ||
160 | } | ||
161 | break; | ||
162 | |||
163 | default: | ||
164 | PERROR("Invalid flags specified.\n"); | ||
165 | err = ME_ERRNO_INVALID_FLAGS; | ||
166 | } | ||
167 | spin_unlock(&instance->subdevice_lock); | ||
168 | |||
169 | ME_SUBDEVICE_EXIT; | ||
170 | |||
171 | return err; | ||
172 | } | ||
173 | |||
174 | static int me0900_do_io_single_write(me_subdevice_t * subdevice, | ||
175 | struct file *filep, | ||
176 | int channel, | ||
177 | int value, int time_out, int flags) | ||
178 | { | ||
179 | me0900_do_subdevice_t *instance; | ||
180 | int err = ME_ERRNO_SUCCESS; | ||
181 | unsigned long state; | ||
182 | |||
183 | PDEBUG("executed.\n"); | ||
184 | |||
185 | instance = (me0900_do_subdevice_t *) subdevice; | ||
186 | |||
187 | ME_SUBDEVICE_ENTER; | ||
188 | |||
189 | spin_lock(&instance->subdevice_lock); | ||
190 | switch (flags) { | ||
191 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
192 | if ((channel >= 0) && (channel < 8)) { | ||
193 | state = inb(instance->port_reg); | ||
194 | state = | ||
195 | (!value) ? (state | (0x1 << channel)) : (state & | ||
196 | ~(0x1 << | ||
197 | channel)); | ||
198 | outb(state, instance->port_reg); | ||
199 | } else { | ||
200 | PERROR("Invalid bit number specified.\n"); | ||
201 | err = ME_ERRNO_INVALID_CHANNEL; | ||
202 | } | ||
203 | break; | ||
204 | |||
205 | case ME_IO_SINGLE_NO_FLAGS: | ||
206 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
207 | if (channel == 0) { | ||
208 | outb(~(value), instance->port_reg); | ||
209 | } else { | ||
210 | PERROR("Invalid byte number specified.\n"); | ||
211 | err = ME_ERRNO_INVALID_CHANNEL; | ||
212 | } | ||
213 | break; | ||
214 | |||
215 | default: | ||
216 | PERROR("Invalid flags specified.\n"); | ||
217 | err = ME_ERRNO_INVALID_FLAGS; | ||
218 | } | ||
219 | spin_unlock(&instance->subdevice_lock); | ||
220 | |||
221 | ME_SUBDEVICE_EXIT; | ||
222 | |||
223 | return err; | ||
224 | } | ||
225 | |||
226 | static int me0900_do_query_number_channels(me_subdevice_t * subdevice, | ||
227 | int *number) | ||
228 | { | ||
229 | PDEBUG("executed.\n"); | ||
230 | *number = 8; | ||
231 | return ME_ERRNO_SUCCESS; | ||
232 | } | ||
233 | |||
234 | static int me0900_do_query_subdevice_type(me_subdevice_t * subdevice, | ||
235 | int *type, int *subtype) | ||
236 | { | ||
237 | PDEBUG("executed.\n"); | ||
238 | *type = ME_TYPE_DO; | ||
239 | *subtype = ME_SUBTYPE_SINGLE; | ||
240 | return ME_ERRNO_SUCCESS; | ||
241 | } | ||
242 | |||
243 | static int me0900_do_query_subdevice_caps(me_subdevice_t * subdevice, int *caps) | ||
244 | { | ||
245 | PDEBUG("executed.\n"); | ||
246 | *caps = 0; | ||
247 | return ME_ERRNO_SUCCESS; | ||
248 | } | ||
249 | |||
250 | me0900_do_subdevice_t *me0900_do_constructor(uint32_t reg_base, | ||
251 | unsigned int do_idx) | ||
252 | { | ||
253 | me0900_do_subdevice_t *subdevice; | ||
254 | int err; | ||
255 | |||
256 | PDEBUG("executed.\n"); | ||
257 | |||
258 | /* Allocate memory for subdevice instance */ | ||
259 | subdevice = kmalloc(sizeof(me0900_do_subdevice_t), GFP_KERNEL); | ||
260 | |||
261 | if (!subdevice) { | ||
262 | PERROR("Cannot get memory for subdevice instance.\n"); | ||
263 | return NULL; | ||
264 | } | ||
265 | |||
266 | memset(subdevice, 0, sizeof(me0900_do_subdevice_t)); | ||
267 | |||
268 | /* Initialize subdevice base class */ | ||
269 | err = me_subdevice_init(&subdevice->base); | ||
270 | |||
271 | if (err) { | ||
272 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
273 | kfree(subdevice); | ||
274 | return NULL; | ||
275 | } | ||
276 | // Initialize spin locks. | ||
277 | spin_lock_init(&subdevice->subdevice_lock); | ||
278 | |||
279 | /* Save the subdevice index */ | ||
280 | subdevice->do_idx = do_idx; | ||
281 | |||
282 | /* Initialize registers */ | ||
283 | if (do_idx == 0) { | ||
284 | subdevice->ctrl_reg = reg_base + ME0900_CTRL_REG; | ||
285 | subdevice->port_reg = reg_base + ME0900_PORT_A_REG; | ||
286 | subdevice->enable_reg = reg_base + ME0900_WRITE_ENABLE_REG; | ||
287 | subdevice->disable_reg = reg_base + ME0900_WRITE_DISABLE_REG; | ||
288 | } else { | ||
289 | subdevice->ctrl_reg = reg_base + ME0900_CTRL_REG; | ||
290 | subdevice->port_reg = reg_base + ME0900_PORT_B_REG; | ||
291 | subdevice->enable_reg = reg_base + ME0900_WRITE_ENABLE_REG; | ||
292 | subdevice->disable_reg = reg_base + ME0900_WRITE_DISABLE_REG; | ||
293 | } | ||
294 | #ifdef MEDEBUG_DEBUG_REG | ||
295 | subdevice->reg_base = reg_base; | ||
296 | #endif | ||
297 | |||
298 | /* Overload base class methods. */ | ||
299 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
300 | me0900_do_io_reset_subdevice; | ||
301 | subdevice->base.me_subdevice_io_single_config = | ||
302 | me0900_do_io_single_config; | ||
303 | subdevice->base.me_subdevice_io_single_read = me0900_do_io_single_read; | ||
304 | subdevice->base.me_subdevice_io_single_write = | ||
305 | me0900_do_io_single_write; | ||
306 | subdevice->base.me_subdevice_query_number_channels = | ||
307 | me0900_do_query_number_channels; | ||
308 | subdevice->base.me_subdevice_query_subdevice_type = | ||
309 | me0900_do_query_subdevice_type; | ||
310 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
311 | me0900_do_query_subdevice_caps; | ||
312 | |||
313 | return subdevice; | ||
314 | } | ||
diff --git a/drivers/staging/meilhaus/me0900_do.h b/drivers/staging/meilhaus/me0900_do.h new file mode 100644 index 000000000000..13e8a8b94cfa --- /dev/null +++ b/drivers/staging/meilhaus/me0900_do.h | |||
@@ -0,0 +1,68 @@ | |||
1 | /** | ||
2 | * @file me0900_do.h | ||
3 | * | ||
4 | * @brief ME-9x digital output subdevice class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME0900_DO_H_ | ||
28 | #define _ME0900_DO_H_ | ||
29 | |||
30 | #include "mesubdevice.h" | ||
31 | |||
32 | #ifdef __KERNEL__ | ||
33 | |||
34 | /** | ||
35 | * @brief The template subdevice class. | ||
36 | */ | ||
37 | typedef struct me0900_do_subdevice { | ||
38 | /* Inheritance */ | ||
39 | me_subdevice_t base; /**< The subdevice base class. */ | ||
40 | |||
41 | /* Attributes */ | ||
42 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
43 | |||
44 | unsigned int do_idx; | ||
45 | |||
46 | unsigned long ctrl_reg; | ||
47 | unsigned long port_reg; | ||
48 | unsigned long enable_reg; | ||
49 | unsigned long disable_reg; | ||
50 | #ifdef MEDEBUG_DEBUG_REG | ||
51 | unsigned long reg_base; | ||
52 | #endif | ||
53 | } me0900_do_subdevice_t; | ||
54 | |||
55 | /** | ||
56 | * @brief The constructor to generate a ME-9x digital output subdevice instance. | ||
57 | * | ||
58 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
59 | * @param do_idx The index of the digital output subdevice on this device. | ||
60 | * | ||
61 | * @return Pointer to new instance on success.\n | ||
62 | * NULL on error. | ||
63 | */ | ||
64 | me0900_do_subdevice_t *me0900_do_constructor(uint32_t reg_base, | ||
65 | unsigned int do_idx); | ||
66 | |||
67 | #endif | ||
68 | #endif | ||
diff --git a/drivers/staging/meilhaus/me0900_reg.h b/drivers/staging/meilhaus/me0900_reg.h new file mode 100644 index 000000000000..3bf163b6ac49 --- /dev/null +++ b/drivers/staging/meilhaus/me0900_reg.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /** | ||
2 | * @file me0900_reg.h | ||
3 | * | ||
4 | * @brief ME-9x register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME0900_REG_H_ | ||
28 | #define _ME0900_REG_H_ | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | #define ME0900_PORT_A_REG 0x00 | ||
33 | #define ME0900_PORT_B_REG 0x01 | ||
34 | #define ME0900_PORT_C_REG 0x02 | ||
35 | #define ME0900_CTRL_REG 0x03 // ( ,w) | ||
36 | #define ME0900_WRITE_ENABLE_REG 0x04 // (r,w) | ||
37 | #define ME0900_WRITE_DISABLE_REG 0x08 // (r,w) | ||
38 | |||
39 | #endif | ||
40 | #endif | ||
diff --git a/drivers/staging/meilhaus/me1000_device.c b/drivers/staging/meilhaus/me1000_device.c new file mode 100644 index 000000000000..c44e214af26c --- /dev/null +++ b/drivers/staging/meilhaus/me1000_device.c | |||
@@ -0,0 +1,208 @@ | |||
1 | /** | ||
2 | * @file me1000_device.c | ||
3 | * | ||
4 | * @brief ME-1000 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 "me1000_device.h" | ||
49 | #include "mesubdevice.h" | ||
50 | #include "me1000_dio.h" | ||
51 | |||
52 | static int me1000_config_load(me_device_t * me_device, struct file *filep, | ||
53 | me_cfg_device_entry_t * config) | ||
54 | { | ||
55 | me1000_device_t *me1000_device; | ||
56 | me1000_dio_subdevice_t *dio; | ||
57 | |||
58 | PDEBUG("executed.\n"); | ||
59 | |||
60 | me1000_device = (me1000_device_t *) me_device; | ||
61 | |||
62 | if (config->count == 2) { | ||
63 | if (me_slist_get_number_subdevices(&me1000_device->base.slist) | ||
64 | == 2) { | ||
65 | // Nothing to do. | ||
66 | } else { | ||
67 | // Remove 2 extra subdevices | ||
68 | dio = | ||
69 | (me1000_dio_subdevice_t *) | ||
70 | me_slist_del_subdevice_tail(&me1000_device->base. | ||
71 | slist); | ||
72 | if (dio) | ||
73 | dio->base. | ||
74 | me_subdevice_destructor((me_subdevice_t *) | ||
75 | dio); | ||
76 | |||
77 | dio = | ||
78 | (me1000_dio_subdevice_t *) | ||
79 | me_slist_del_subdevice_tail(&me1000_device->base. | ||
80 | slist); | ||
81 | if (dio) | ||
82 | dio->base. | ||
83 | me_subdevice_destructor((me_subdevice_t *) | ||
84 | dio); | ||
85 | } | ||
86 | } else if (config->count == 4) { | ||
87 | //Add 2 subdevices | ||
88 | if (me_slist_get_number_subdevices(&me1000_device->base.slist) | ||
89 | == 2) { | ||
90 | dio = | ||
91 | me1000_dio_constructor(me1000_device->base.info.pci. | ||
92 | reg_bases[2], 2, | ||
93 | &me1000_device->ctrl_lock); | ||
94 | if (!dio) { | ||
95 | PERROR("Cannot create dio subdevice.\n"); | ||
96 | return ME_ERRNO_INTERNAL; | ||
97 | } | ||
98 | me_slist_add_subdevice_tail(&me1000_device->base.slist, | ||
99 | (me_subdevice_t *) dio); | ||
100 | |||
101 | dio = | ||
102 | me1000_dio_constructor(me1000_device->base.info.pci. | ||
103 | reg_bases[2], 3, | ||
104 | &me1000_device->ctrl_lock); | ||
105 | if (!dio) { | ||
106 | dio = | ||
107 | (me1000_dio_subdevice_t *) | ||
108 | me_slist_del_subdevice_tail(&me1000_device-> | ||
109 | base.slist); | ||
110 | if (dio) | ||
111 | dio->base. | ||
112 | me_subdevice_destructor((me_subdevice_t *) dio); | ||
113 | |||
114 | PERROR("Cannot create dio subdevice.\n"); | ||
115 | return ME_ERRNO_INTERNAL; | ||
116 | } | ||
117 | me_slist_add_subdevice_tail(&me1000_device->base.slist, | ||
118 | (me_subdevice_t *) dio); | ||
119 | } else { | ||
120 | // Nothing to do. | ||
121 | } | ||
122 | } else { | ||
123 | PERROR("Invalid configuration.\n"); | ||
124 | return ME_ERRNO_INTERNAL; | ||
125 | } | ||
126 | |||
127 | return ME_ERRNO_SUCCESS; | ||
128 | } | ||
129 | |||
130 | me_device_t *me1000_pci_constructor(struct pci_dev * pci_device) | ||
131 | { | ||
132 | me1000_device_t *me1000_device; | ||
133 | me_subdevice_t *subdevice; | ||
134 | int err; | ||
135 | int i; | ||
136 | |||
137 | PDEBUG("executed.\n"); | ||
138 | |||
139 | // Allocate structure for device instance. | ||
140 | me1000_device = kmalloc(sizeof(me1000_device_t), GFP_KERNEL); | ||
141 | |||
142 | if (!me1000_device) { | ||
143 | PERROR("Cannot get memory for ME-1000 device instance.\n"); | ||
144 | return NULL; | ||
145 | } | ||
146 | |||
147 | memset(me1000_device, 0, sizeof(me1000_device_t)); | ||
148 | |||
149 | // Initialize base class structure. | ||
150 | err = me_device_pci_init((me_device_t *) me1000_device, pci_device); | ||
151 | |||
152 | if (err) { | ||
153 | kfree(me1000_device); | ||
154 | PERROR("Cannot initialize device base class.\n"); | ||
155 | return NULL; | ||
156 | } | ||
157 | // Initialize spin lock . | ||
158 | spin_lock_init(&me1000_device->ctrl_lock); | ||
159 | |||
160 | for (i = 0; i < 4; i++) { | ||
161 | subdevice = | ||
162 | (me_subdevice_t *) me1000_dio_constructor(me1000_device-> | ||
163 | base.info.pci. | ||
164 | reg_bases[2], i, | ||
165 | &me1000_device-> | ||
166 | ctrl_lock); | ||
167 | |||
168 | if (!subdevice) { | ||
169 | me_device_deinit((me_device_t *) me1000_device); | ||
170 | kfree(me1000_device); | ||
171 | PERROR("Cannot get memory for subdevice.\n"); | ||
172 | return NULL; | ||
173 | } | ||
174 | |||
175 | me_slist_add_subdevice_tail(&me1000_device->base.slist, | ||
176 | subdevice); | ||
177 | } | ||
178 | |||
179 | // Overwrite base class methods. | ||
180 | me1000_device->base.me_device_config_load = me1000_config_load; | ||
181 | |||
182 | return (me_device_t *) me1000_device; | ||
183 | } | ||
184 | |||
185 | // Init and exit of module. | ||
186 | static int __init me1000_init(void) | ||
187 | { | ||
188 | PDEBUG("executed.\n"); | ||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | static void __exit me1000_exit(void) | ||
193 | { | ||
194 | PDEBUG("executed.\n"); | ||
195 | } | ||
196 | |||
197 | module_init(me1000_init); | ||
198 | module_exit(me1000_exit); | ||
199 | |||
200 | // Administrative stuff for modinfo. | ||
201 | MODULE_AUTHOR | ||
202 | ("Guenter Gebhardt <g.gebhardt@meilhaus.de> & Krzysztof Gantzke <k.gantzke@meilhaus.de>"); | ||
203 | MODULE_DESCRIPTION("Device Driver Module for Meilhaus ME-1000 Devices"); | ||
204 | MODULE_SUPPORTED_DEVICE("Meilhaus ME-1000 Digital I/O Devices"); | ||
205 | MODULE_LICENSE("GPL"); | ||
206 | |||
207 | // Export the constructor. | ||
208 | EXPORT_SYMBOL(me1000_pci_constructor); | ||
diff --git a/drivers/staging/meilhaus/me1000_device.h b/drivers/staging/meilhaus/me1000_device.h new file mode 100644 index 000000000000..cbbe1263017d --- /dev/null +++ b/drivers/staging/meilhaus/me1000_device.h | |||
@@ -0,0 +1,59 @@ | |||
1 | /** | ||
2 | * @file me1000_device.h | ||
3 | * | ||
4 | * @brief ME-1000 device class instance. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME1000_H_ | ||
28 | #define _ME1000_H_ | ||
29 | |||
30 | #include <linux/pci.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | |||
33 | #include "medevice.h" | ||
34 | |||
35 | #ifdef __KERNEL__ | ||
36 | |||
37 | #define ME1000_MAGIC_NUMBER 1000 | ||
38 | |||
39 | /** | ||
40 | * @brief The ME-1000 device class structure. | ||
41 | */ | ||
42 | typedef struct me1000_device { | ||
43 | me_device_t base; /**< The Meilhaus device base class. */ | ||
44 | spinlock_t ctrl_lock; /**< Guards the DIO mode register. */ | ||
45 | } me1000_device_t; | ||
46 | |||
47 | /** | ||
48 | * @brief The ME-1000 device class constructor. | ||
49 | * | ||
50 | * @param pci_device The pci device structure given by the PCI subsystem. | ||
51 | * | ||
52 | * @return On succes a new ME-1000 device instance. \n | ||
53 | * NULL on error. | ||
54 | */ | ||
55 | me_device_t *me1000_pci_constructor(struct pci_dev *pci_device) | ||
56 | __attribute__ ((weak)); | ||
57 | |||
58 | #endif | ||
59 | #endif | ||
diff --git a/drivers/staging/meilhaus/me1000_dio.c b/drivers/staging/meilhaus/me1000_dio.c new file mode 100644 index 000000000000..87605a9108ae --- /dev/null +++ b/drivers/staging/meilhaus/me1000_dio.c | |||
@@ -0,0 +1,438 @@ | |||
1 | /** | ||
2 | * @file me1000_dio.c | ||
3 | * | ||
4 | * @brief ME-1000 DIO subdevice instance. | ||
5 | * @note Copyright (C) 2006 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | * @author Krzysztof Gantzke (k.gantzke@meilhaus.de) | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * Copyright (C) 2006 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 | /* | ||
33 | * Includes | ||
34 | */ | ||
35 | #include <linux/module.h> | ||
36 | |||
37 | #include <linux/slab.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | #include <asm/io.h> | ||
40 | #include <linux/types.h> | ||
41 | |||
42 | #include "medefines.h" | ||
43 | #include "meinternal.h" | ||
44 | #include "meerror.h" | ||
45 | #include "medebug.h" | ||
46 | |||
47 | #include "me1000_dio_reg.h" | ||
48 | #include "me1000_dio.h" | ||
49 | |||
50 | /* | ||
51 | * Defines | ||
52 | */ | ||
53 | #define ME1000_DIO_MAGIC_NUMBER 0x1000 /**< The magic number of the class structure. */ | ||
54 | |||
55 | /* | ||
56 | * Functions | ||
57 | */ | ||
58 | |||
59 | static int me1000_dio_io_reset_subdevice(struct me_subdevice *subdevice, | ||
60 | struct file *filep, int flags) | ||
61 | { | ||
62 | me1000_dio_subdevice_t *instance; | ||
63 | uint32_t tmp; | ||
64 | |||
65 | PDEBUG("executed.\n"); | ||
66 | |||
67 | instance = (me1000_dio_subdevice_t *) subdevice; | ||
68 | |||
69 | if (flags) { | ||
70 | PERROR("Invalid flag specified.\n"); | ||
71 | return ME_ERRNO_INVALID_FLAGS; | ||
72 | } | ||
73 | |||
74 | ME_SUBDEVICE_ENTER; | ||
75 | |||
76 | spin_lock(&instance->subdevice_lock); | ||
77 | spin_lock(instance->ctrl_reg_lock); | ||
78 | tmp = inl(instance->ctrl_reg); | ||
79 | tmp &= ~(0x1 << instance->dio_idx); | ||
80 | outl(tmp, instance->ctrl_reg); | ||
81 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
82 | instance->ctrl_reg - instance->reg_base, tmp); | ||
83 | spin_unlock(instance->ctrl_reg_lock); | ||
84 | |||
85 | outl(0x00000000, instance->port_reg); | ||
86 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
87 | instance->ctrl_reg - instance->reg_base, 0); | ||
88 | spin_unlock(&instance->subdevice_lock); | ||
89 | |||
90 | ME_SUBDEVICE_EXIT; | ||
91 | |||
92 | return ME_ERRNO_SUCCESS; | ||
93 | } | ||
94 | |||
95 | static int me1000_dio_io_single_config(struct me_subdevice *subdevice, | ||
96 | struct file *filep, | ||
97 | int channel, | ||
98 | int single_config, | ||
99 | int ref, | ||
100 | int trig_chan, | ||
101 | int trig_type, int trig_edge, int flags) | ||
102 | { | ||
103 | me1000_dio_subdevice_t *instance; | ||
104 | int err = ME_ERRNO_SUCCESS; | ||
105 | int ctrl; | ||
106 | int size = | ||
107 | flags & (ME_IO_SINGLE_CONFIG_DIO_BIT | ME_IO_SINGLE_CONFIG_DIO_BYTE | ||
108 | | ME_IO_SINGLE_CONFIG_DIO_WORD | | ||
109 | ME_IO_SINGLE_CONFIG_DIO_DWORD); | ||
110 | |||
111 | PDEBUG("executed.\n"); | ||
112 | |||
113 | instance = (me1000_dio_subdevice_t *) subdevice; | ||
114 | |||
115 | ME_SUBDEVICE_ENTER; | ||
116 | |||
117 | spin_lock(&instance->subdevice_lock); | ||
118 | spin_lock(instance->ctrl_reg_lock); | ||
119 | ctrl = inl(instance->ctrl_reg); | ||
120 | |||
121 | switch (size) { | ||
122 | case ME_IO_SINGLE_CONFIG_NO_FLAGS: | ||
123 | case ME_IO_SINGLE_CONFIG_DIO_DWORD: | ||
124 | if (channel == 0) { | ||
125 | if (single_config == ME_SINGLE_CONFIG_DIO_INPUT) { | ||
126 | ctrl &= ~(0x1 << instance->dio_idx); | ||
127 | } else if (single_config == ME_SINGLE_CONFIG_DIO_OUTPUT) { | ||
128 | ctrl |= 0x1 << instance->dio_idx; | ||
129 | } else { | ||
130 | PERROR("Invalid port direction.\n"); | ||
131 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
132 | } | ||
133 | } else { | ||
134 | PERROR("Invalid channel number.\n"); | ||
135 | err = ME_ERRNO_INVALID_CHANNEL; | ||
136 | } | ||
137 | break; | ||
138 | |||
139 | default: | ||
140 | PERROR("Invalid flags.\n"); | ||
141 | err = ME_ERRNO_INVALID_FLAGS; | ||
142 | } | ||
143 | |||
144 | if (!err) { | ||
145 | outl(ctrl, instance->ctrl_reg); | ||
146 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
147 | instance->reg_base, | ||
148 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
149 | } | ||
150 | spin_unlock(instance->ctrl_reg_lock); | ||
151 | spin_unlock(&instance->subdevice_lock); | ||
152 | |||
153 | ME_SUBDEVICE_EXIT; | ||
154 | |||
155 | return err; | ||
156 | } | ||
157 | |||
158 | static int me1000_dio_io_single_read(struct me_subdevice *subdevice, | ||
159 | struct file *filep, | ||
160 | int channel, | ||
161 | int *value, int time_out, int flags) | ||
162 | { | ||
163 | me1000_dio_subdevice_t *instance; | ||
164 | int err = ME_ERRNO_SUCCESS; | ||
165 | |||
166 | PDEBUG("executed.\n"); | ||
167 | |||
168 | instance = (me1000_dio_subdevice_t *) subdevice; | ||
169 | |||
170 | ME_SUBDEVICE_ENTER; | ||
171 | |||
172 | spin_lock(&instance->subdevice_lock); | ||
173 | switch (flags) { | ||
174 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
175 | if ((channel >= 0) && (channel < 32)) { | ||
176 | *value = inl(instance->port_reg) & (0x1 << channel); | ||
177 | } else { | ||
178 | PERROR("Invalid bit number.\n"); | ||
179 | err = ME_ERRNO_INVALID_CHANNEL; | ||
180 | } | ||
181 | break; | ||
182 | |||
183 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
184 | if ((channel >= 0) && (channel < 4)) { | ||
185 | *value = | ||
186 | (inl(instance->port_reg) >> (channel * 8)) & 0xFF; | ||
187 | } else { | ||
188 | PERROR("Invalid byte number.\n"); | ||
189 | err = ME_ERRNO_INVALID_CHANNEL; | ||
190 | } | ||
191 | break; | ||
192 | |||
193 | case ME_IO_SINGLE_TYPE_DIO_WORD: | ||
194 | if ((channel >= 0) && (channel < 2)) { | ||
195 | *value = | ||
196 | (inl(instance->port_reg) >> (channel * 16)) & | ||
197 | 0xFFFF; | ||
198 | } else { | ||
199 | PERROR("Invalid word number.\n"); | ||
200 | err = ME_ERRNO_INVALID_CHANNEL; | ||
201 | } | ||
202 | break; | ||
203 | |||
204 | case ME_IO_SINGLE_NO_FLAGS: | ||
205 | case ME_IO_SINGLE_TYPE_DIO_DWORD: | ||
206 | if (channel == 0) { | ||
207 | *value = inl(instance->port_reg); | ||
208 | } else { | ||
209 | PERROR("Invalid dword number.\n"); | ||
210 | err = ME_ERRNO_INVALID_CHANNEL; | ||
211 | } | ||
212 | break; | ||
213 | |||
214 | default: | ||
215 | PERROR("Invalid flags specified.\n"); | ||
216 | err = ME_ERRNO_INVALID_FLAGS; | ||
217 | } | ||
218 | spin_unlock(&instance->subdevice_lock); | ||
219 | |||
220 | ME_SUBDEVICE_EXIT; | ||
221 | |||
222 | return err; | ||
223 | } | ||
224 | |||
225 | static int me1000_dio_io_single_write(struct me_subdevice *subdevice, | ||
226 | struct file *filep, | ||
227 | int channel, | ||
228 | int value, int time_out, int flags) | ||
229 | { | ||
230 | me1000_dio_subdevice_t *instance; | ||
231 | int err = ME_ERRNO_SUCCESS; | ||
232 | uint32_t config; | ||
233 | uint32_t state; | ||
234 | |||
235 | PDEBUG("executed.\n"); | ||
236 | |||
237 | instance = (me1000_dio_subdevice_t *) subdevice; | ||
238 | |||
239 | ME_SUBDEVICE_ENTER spin_lock(&instance->subdevice_lock); | ||
240 | spin_lock(instance->ctrl_reg_lock); | ||
241 | config = inl(instance->ctrl_reg) & (0x1 << instance->dio_idx); | ||
242 | switch (flags) { | ||
243 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
244 | if ((channel >= 0) && (channel < 32)) { | ||
245 | if (config) { | ||
246 | state = inl(instance->port_reg); | ||
247 | state = | ||
248 | value ? (state | (0x1 << channel)) : (state | ||
249 | & | ||
250 | ~(0x1 | ||
251 | << | ||
252 | channel)); | ||
253 | outl(state, instance->port_reg); | ||
254 | PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
255 | instance->reg_base, | ||
256 | instance->port_reg - | ||
257 | instance->reg_base, state); | ||
258 | } else { | ||
259 | PERROR("Port is not in output mode.\n"); | ||
260 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
261 | } | ||
262 | } else { | ||
263 | PERROR("Invalid bit number.\n"); | ||
264 | err = ME_ERRNO_INVALID_CHANNEL; | ||
265 | } | ||
266 | break; | ||
267 | |||
268 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
269 | if ((channel >= 0) && (channel < 4)) { | ||
270 | if (config) { | ||
271 | state = inl(instance->port_reg); | ||
272 | state &= ~(0xFF << (channel * 8)); | ||
273 | state |= (value & 0xFF) << (channel * 8); | ||
274 | outl(state, instance->port_reg); | ||
275 | PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
276 | instance->reg_base, | ||
277 | instance->port_reg - | ||
278 | instance->reg_base, state); | ||
279 | } else { | ||
280 | PERROR("Port is not in output mode.\n"); | ||
281 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
282 | } | ||
283 | } else { | ||
284 | PERROR("Invalid byte number.\n"); | ||
285 | err = ME_ERRNO_INVALID_CHANNEL; | ||
286 | } | ||
287 | break; | ||
288 | |||
289 | case ME_IO_SINGLE_TYPE_DIO_WORD: | ||
290 | if ((channel >= 0) && (channel < 2)) { | ||
291 | if (config) { | ||
292 | state = inl(instance->port_reg); | ||
293 | state &= ~(0xFFFF << (channel * 16)); | ||
294 | state |= (value & 0xFFFF) << (channel * 16); | ||
295 | outl(state, instance->port_reg); | ||
296 | PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
297 | instance->reg_base, | ||
298 | instance->port_reg - | ||
299 | instance->reg_base, state); | ||
300 | } else { | ||
301 | PERROR("Port is not in output mode.\n"); | ||
302 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
303 | } | ||
304 | } else { | ||
305 | PERROR("Invalid word number.\n"); | ||
306 | err = ME_ERRNO_INVALID_CHANNEL; | ||
307 | } | ||
308 | break; | ||
309 | |||
310 | case ME_IO_SINGLE_NO_FLAGS: | ||
311 | case ME_IO_SINGLE_TYPE_DIO_DWORD: | ||
312 | if (channel == 0) { | ||
313 | if (config) { | ||
314 | outl(value, instance->port_reg); | ||
315 | PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
316 | instance->reg_base, | ||
317 | instance->port_reg - | ||
318 | instance->reg_base, value); | ||
319 | } else { | ||
320 | PERROR("Port is not in output mode.\n"); | ||
321 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
322 | } | ||
323 | } else { | ||
324 | PERROR("Invalid dword number.\n"); | ||
325 | err = ME_ERRNO_INVALID_CHANNEL; | ||
326 | } | ||
327 | break; | ||
328 | |||
329 | default: | ||
330 | PERROR("Invalid flags specified.\n"); | ||
331 | err = ME_ERRNO_INVALID_FLAGS; | ||
332 | } | ||
333 | spin_unlock(instance->ctrl_reg_lock); | ||
334 | spin_unlock(&instance->subdevice_lock); | ||
335 | |||
336 | ME_SUBDEVICE_EXIT; | ||
337 | |||
338 | return err; | ||
339 | } | ||
340 | |||
341 | static int me1000_dio_query_number_channels(struct me_subdevice *subdevice, | ||
342 | int *number) | ||
343 | { | ||
344 | PDEBUG("executed.\n"); | ||
345 | *number = ME1000_DIO_NUMBER_CHANNELS; | ||
346 | return ME_ERRNO_SUCCESS; | ||
347 | } | ||
348 | |||
349 | static int me1000_dio_query_subdevice_type(struct me_subdevice *subdevice, | ||
350 | int *type, int *subtype) | ||
351 | { | ||
352 | PDEBUG("executed.\n"); | ||
353 | *type = ME_TYPE_DIO; | ||
354 | *subtype = ME_SUBTYPE_SINGLE; | ||
355 | return ME_ERRNO_SUCCESS; | ||
356 | } | ||
357 | |||
358 | static int me1000_dio_query_subdevice_caps(struct me_subdevice *subdevice, | ||
359 | int *caps) | ||
360 | { | ||
361 | me1000_dio_subdevice_t *instance; | ||
362 | |||
363 | PDEBUG("executed.\n"); | ||
364 | |||
365 | instance = (me1000_dio_subdevice_t *) subdevice; | ||
366 | |||
367 | *caps = ME_CAPS_DIO_DIR_DWORD; | ||
368 | |||
369 | return ME_ERRNO_SUCCESS; | ||
370 | } | ||
371 | |||
372 | me1000_dio_subdevice_t *me1000_dio_constructor(uint32_t reg_base, | ||
373 | unsigned int dio_idx, | ||
374 | spinlock_t * ctrl_reg_lock) | ||
375 | { | ||
376 | me1000_dio_subdevice_t *subdevice; | ||
377 | int err; | ||
378 | |||
379 | PDEBUG("executed.\n"); | ||
380 | |||
381 | /* Allocate memory for subdevice instance */ | ||
382 | subdevice = kmalloc(sizeof(me1000_dio_subdevice_t), GFP_KERNEL); | ||
383 | |||
384 | if (!subdevice) { | ||
385 | PERROR("Cannot get memory for ME-1000 DIO instance.\n"); | ||
386 | return NULL; | ||
387 | } | ||
388 | |||
389 | memset(subdevice, 0, sizeof(me1000_dio_subdevice_t)); | ||
390 | |||
391 | /* Check if counter index is out of range */ | ||
392 | |||
393 | if (dio_idx >= ME1000_DIO_NUMBER_PORTS) { | ||
394 | PERROR("DIO index is out of range.\n"); | ||
395 | kfree(subdevice); | ||
396 | return NULL; | ||
397 | } | ||
398 | |||
399 | /* Initialize subdevice base class */ | ||
400 | err = me_subdevice_init(&subdevice->base); | ||
401 | |||
402 | if (err) { | ||
403 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
404 | kfree(subdevice); | ||
405 | return NULL; | ||
406 | } | ||
407 | // Initialize spin locks. | ||
408 | spin_lock_init(&subdevice->subdevice_lock); | ||
409 | subdevice->ctrl_reg_lock = ctrl_reg_lock; | ||
410 | |||
411 | /* Save the DIO index */ | ||
412 | subdevice->dio_idx = dio_idx; | ||
413 | |||
414 | /* Initialize registers. */ | ||
415 | #ifdef MEDEBUG_DEBUG_REG | ||
416 | subdevice->reg_base = reg_base; | ||
417 | #endif | ||
418 | subdevice->ctrl_reg = reg_base + ME1000_PORT_MODE; | ||
419 | subdevice->port_reg = | ||
420 | reg_base + ME1000_PORT + (dio_idx * ME1000_PORT_STEP); | ||
421 | |||
422 | /* Override base class methods. */ | ||
423 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
424 | me1000_dio_io_reset_subdevice; | ||
425 | subdevice->base.me_subdevice_io_single_config = | ||
426 | me1000_dio_io_single_config; | ||
427 | subdevice->base.me_subdevice_io_single_read = me1000_dio_io_single_read; | ||
428 | subdevice->base.me_subdevice_io_single_write = | ||
429 | me1000_dio_io_single_write; | ||
430 | subdevice->base.me_subdevice_query_number_channels = | ||
431 | me1000_dio_query_number_channels; | ||
432 | subdevice->base.me_subdevice_query_subdevice_type = | ||
433 | me1000_dio_query_subdevice_type; | ||
434 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
435 | me1000_dio_query_subdevice_caps; | ||
436 | |||
437 | return subdevice; | ||
438 | } | ||
diff --git a/drivers/staging/meilhaus/me1000_dio.h b/drivers/staging/meilhaus/me1000_dio.h new file mode 100644 index 000000000000..d26e93f531af --- /dev/null +++ b/drivers/staging/meilhaus/me1000_dio.h | |||
@@ -0,0 +1,71 @@ | |||
1 | /** | ||
2 | * @file me1000_dio.h | ||
3 | * | ||
4 | * @brief Meilhaus ME-1000 digital i/o implementation. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME1000_DIO_H_ | ||
28 | #define _ME1000_DIO_H_ | ||
29 | |||
30 | #include "mesubdevice.h" | ||
31 | #include "meslock.h" | ||
32 | |||
33 | #ifdef __KERNEL__ | ||
34 | |||
35 | /** | ||
36 | * @brief The ME-1000 DIO subdevice class. | ||
37 | */ | ||
38 | typedef struct me1000_dio_subdevice { | ||
39 | /* Inheritance */ | ||
40 | me_subdevice_t base; /**< The subdevice base class. */ | ||
41 | |||
42 | /* Attributes */ | ||
43 | // uint32_t magic; /**< The magic number unique for this structure. */ | ||
44 | |||
45 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
46 | spinlock_t *ctrl_reg_lock; /**< Spin lock to protect #ctrl_reg and #ctrl_reg_mirror from concurrent access. */ | ||
47 | int dio_idx; /**< The index of the DIO port on the device. */ | ||
48 | |||
49 | unsigned long port_reg; /**< Register to read or write a value from or to the port respectively. */ | ||
50 | unsigned long ctrl_reg; /**< Register to configure the DIO modes. */ | ||
51 | #ifdef MEDEBUG_DEBUG_REG | ||
52 | unsigned long reg_base; | ||
53 | #endif | ||
54 | } me1000_dio_subdevice_t; | ||
55 | |||
56 | /** | ||
57 | * @brief The constructor to generate a ME-1000 DIO instance. | ||
58 | * | ||
59 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
60 | * @param dio_idx The index of the DIO on the device. | ||
61 | * @param ctrl_reg_lock Pointer to spin lock protecting the control register and from concurrent access. | ||
62 | * | ||
63 | * @return Pointer to new instance on success.\n | ||
64 | * NULL on error. | ||
65 | */ | ||
66 | me1000_dio_subdevice_t *me1000_dio_constructor(uint32_t reg_base, | ||
67 | unsigned int dio_idx, | ||
68 | spinlock_t * ctrl_reg_lock); | ||
69 | |||
70 | #endif | ||
71 | #endif | ||
diff --git a/drivers/staging/meilhaus/me1000_dio_reg.h b/drivers/staging/meilhaus/me1000_dio_reg.h new file mode 100644 index 000000000000..4d5b38df437f --- /dev/null +++ b/drivers/staging/meilhaus/me1000_dio_reg.h | |||
@@ -0,0 +1,50 @@ | |||
1 | /** | ||
2 | * @file me1000_dio_reg.h | ||
3 | * | ||
4 | * @brief ME-1000 digital i/o register definitions. | ||
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 _ME1000_DIO_REG_H_ | ||
29 | # define _ME1000_DIO_REG_H_ | ||
30 | |||
31 | # ifdef __KERNEL__ | ||
32 | |||
33 | # define ME1000_DIO_NUMBER_CHANNELS 32 /**< The number of channels per DIO port. */ | ||
34 | # define ME1000_DIO_NUMBER_PORTS 4 /**< The number of ports per ME-1000. */ | ||
35 | |||
36 | // # define ME1000_PORT_A 0x0000 /**< Port A base register offset. */ | ||
37 | // # define ME1000_PORT_B 0x0004 /**< Port B base register offset. */ | ||
38 | // # define ME1000_PORT_C 0x0008 /**< Port C base register offset. */ | ||
39 | // # define ME1000_PORT_D 0x000C /**< Port D base register offset. */ | ||
40 | # define ME1000_PORT 0x0000 /**< Base for port's register. */ | ||
41 | # define ME1000_PORT_STEP 4 /**< Distance between port's register. */ | ||
42 | |||
43 | # define ME1000_PORT_MODE 0x0010 /**< Configuration register to switch the port direction. */ | ||
44 | // # define ME1000_PORT_MODE_OUTPUT_A (1 << 0) /**< If set, port A is in output, otherwise in input mode. */ | ||
45 | // # define ME1000_PORT_MODE_OUTPUT_B (1 << 1) /**< If set, port B is in output, otherwise in input mode. */ | ||
46 | // # define ME1000_PORT_MODE_OUTPUT_C (1 << 2) /**< If set, port C is in output, otherwise in input mode. */ | ||
47 | // # define ME1000_PORT_MODE_OUTPUT_D (1 << 3) /**< If set, port D is in output, otherwise in input mode. */ | ||
48 | |||
49 | # endif //__KERNEL__ | ||
50 | #endif //_ME1000_DIO_REG_H_ | ||
diff --git a/drivers/staging/meilhaus/me1400_device.c b/drivers/staging/meilhaus/me1400_device.c new file mode 100644 index 000000000000..b95bb4fce6ab --- /dev/null +++ b/drivers/staging/meilhaus/me1400_device.c | |||
@@ -0,0 +1,256 @@ | |||
1 | /** | ||
2 | * @file me1400_device.c | ||
3 | * | ||
4 | * @brief ME-1400 device instance. | ||
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 | /* | ||
29 | * User application could also include the kernel header files. But the | ||
30 | * real kernel functions are protected by #ifdef __KERNEL__. | ||
31 | */ | ||
32 | #ifndef __KERNEL__ | ||
33 | # define __KERNEL__ | ||
34 | #endif | ||
35 | |||
36 | /* | ||
37 | * This must be defined before module.h is included. Not needed, when | ||
38 | * it is a built in driver. | ||
39 | */ | ||
40 | #ifndef MODULE | ||
41 | # define MODULE | ||
42 | #endif | ||
43 | |||
44 | #include <linux/module.h> | ||
45 | |||
46 | #include <linux/pci.h> | ||
47 | #include <linux/slab.h> | ||
48 | #include <linux/sched.h> | ||
49 | #include <linux/interrupt.h> | ||
50 | #include <linux/version.h> | ||
51 | |||
52 | #include "meids.h" | ||
53 | #include "meerror.h" | ||
54 | #include "mecommon.h" | ||
55 | #include "meinternal.h" | ||
56 | |||
57 | #include "medebug.h" | ||
58 | |||
59 | #include "me1400_device.h" | ||
60 | #include "me8254.h" | ||
61 | #include "me8254_reg.h" | ||
62 | #include "me8255.h" | ||
63 | #include "me1400_ext_irq.h" | ||
64 | |||
65 | me_device_t *me1400_pci_constructor(struct pci_dev *pci_device) | ||
66 | { | ||
67 | int err; | ||
68 | me1400_device_t *me1400_device; | ||
69 | me_subdevice_t *subdevice; | ||
70 | unsigned int version_idx; | ||
71 | unsigned int me8255_idx; | ||
72 | unsigned int dio_idx; | ||
73 | unsigned int me8254_idx; | ||
74 | unsigned int ctr_idx; | ||
75 | unsigned int ext_irq_idx; | ||
76 | |||
77 | PDEBUG("executed.\n"); | ||
78 | |||
79 | // Allocate structure for device instance. | ||
80 | me1400_device = kmalloc(sizeof(me1400_device_t), GFP_KERNEL); | ||
81 | |||
82 | if (!me1400_device) { | ||
83 | PERROR("Cannot get memory for 1400ate device instance.\n"); | ||
84 | return NULL; | ||
85 | } | ||
86 | |||
87 | memset(me1400_device, 0, sizeof(me1400_device_t)); | ||
88 | |||
89 | // Initialize base class structure. | ||
90 | err = me_device_pci_init((me_device_t *) me1400_device, pci_device); | ||
91 | |||
92 | if (err) { | ||
93 | kfree(me1400_device); | ||
94 | PERROR("Cannot initialize device base class.\n"); | ||
95 | return NULL; | ||
96 | } | ||
97 | |||
98 | /* Check for ME1400 extension device. If detected we fake a ME-1400 D device id. */ | ||
99 | if (me1400_device->base.info.pci.device_id == | ||
100 | PCI_DEVICE_ID_MEILHAUS_ME140C) { | ||
101 | uint8_t ctrl; | ||
102 | ctrl = | ||
103 | inb(me1400_device->base.info.pci.reg_bases[2] + | ||
104 | ME1400D_CLK_SRC_2_REG); | ||
105 | PDEBUG_REG("xxx_reg inb(0x%X+0x%X)=0x%x\n", | ||
106 | me1400_device->base.info.pci.reg_bases[2], | ||
107 | ME1400D_CLK_SRC_2_REG, ctrl); | ||
108 | outb(ctrl | 0xF0, | ||
109 | me1400_device->base.info.pci.reg_bases[2] + | ||
110 | ME1400D_CLK_SRC_2_REG); | ||
111 | PDEBUG_REG("xxx_reg outb(0x%X+0x%X)=0x%x\n", | ||
112 | me1400_device->base.info.pci.reg_bases[2], | ||
113 | ME1400D_CLK_SRC_2_REG, ctrl | 0xF0); | ||
114 | ctrl = | ||
115 | inb(me1400_device->base.info.pci.reg_bases[2] + | ||
116 | ME1400D_CLK_SRC_2_REG); | ||
117 | PDEBUG_REG("xxx_reg inb(0x%X+0x%X)=0x%x\n", | ||
118 | me1400_device->base.info.pci.reg_bases[2], | ||
119 | ME1400D_CLK_SRC_2_REG, ctrl); | ||
120 | |||
121 | if ((ctrl & 0xF0) == 0xF0) { | ||
122 | PINFO("ME1400 D detected.\n"); | ||
123 | me1400_device->base.info.pci.device_id = | ||
124 | PCI_DEVICE_ID_MEILHAUS_ME140D; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | /* Initialize global stuff of digital i/o subdevices. */ | ||
129 | for (me8255_idx = 0; me8255_idx < ME1400_MAX_8255; me8255_idx++) { | ||
130 | me1400_device->dio_current_mode[me8255_idx] = 0; | ||
131 | spin_lock_init(&me1400_device->dio_ctrl_reg_lock[me8255_idx]); | ||
132 | } | ||
133 | |||
134 | /* Initialize global stuff of counter subdevices. */ | ||
135 | spin_lock_init(&me1400_device->clk_src_reg_lock); | ||
136 | |||
137 | for (me8254_idx = 0; me8254_idx < ME1400_MAX_8254; me8254_idx++) | ||
138 | spin_lock_init(&me1400_device->ctr_ctrl_reg_lock[me8254_idx]); | ||
139 | |||
140 | /* Get the index in the device version information table. */ | ||
141 | version_idx = | ||
142 | me1400_versions_get_device_index(me1400_device->base.info.pci. | ||
143 | device_id); | ||
144 | |||
145 | /* Generate DIO subdevice instances. */ | ||
146 | for (me8255_idx = 0; | ||
147 | me8255_idx < me1400_versions[version_idx].dio_chips; | ||
148 | me8255_idx++) { | ||
149 | for (dio_idx = 0; dio_idx < 3; dio_idx++) { | ||
150 | subdevice = | ||
151 | (me_subdevice_t *) | ||
152 | me8255_constructor(me1400_versions[version_idx]. | ||
153 | device_id, | ||
154 | me1400_device->base.info.pci. | ||
155 | reg_bases[2], me8255_idx, | ||
156 | dio_idx, | ||
157 | &me1400_device-> | ||
158 | dio_current_mode[me8255_idx], | ||
159 | &me1400_device-> | ||
160 | dio_ctrl_reg_lock[me8255_idx]); | ||
161 | |||
162 | if (!subdevice) { | ||
163 | me_device_deinit((me_device_t *) me1400_device); | ||
164 | kfree(me1400_device); | ||
165 | PERROR("Cannot get memory for subdevice.\n"); | ||
166 | return NULL; | ||
167 | } | ||
168 | |||
169 | me_slist_add_subdevice_tail(&me1400_device->base.slist, | ||
170 | subdevice); | ||
171 | } | ||
172 | } | ||
173 | |||
174 | /* Generate counter subdevice instances. */ | ||
175 | for (me8254_idx = 0; | ||
176 | me8254_idx < me1400_versions[version_idx].ctr_chips; | ||
177 | me8254_idx++) { | ||
178 | for (ctr_idx = 0; ctr_idx < 3; ctr_idx++) { | ||
179 | subdevice = | ||
180 | (me_subdevice_t *) | ||
181 | me8254_constructor(me1400_device->base.info.pci. | ||
182 | device_id, | ||
183 | me1400_device->base.info.pci. | ||
184 | reg_bases[2], me8254_idx, | ||
185 | ctr_idx, | ||
186 | &me1400_device-> | ||
187 | ctr_ctrl_reg_lock[me8254_idx], | ||
188 | &me1400_device-> | ||
189 | clk_src_reg_lock); | ||
190 | |||
191 | if (!subdevice) { | ||
192 | me_device_deinit((me_device_t *) me1400_device); | ||
193 | kfree(me1400_device); | ||
194 | PERROR("Cannot get memory for subdevice.\n"); | ||
195 | return NULL; | ||
196 | } | ||
197 | |||
198 | me_slist_add_subdevice_tail(&me1400_device->base.slist, | ||
199 | subdevice); | ||
200 | } | ||
201 | } | ||
202 | |||
203 | /* Generate external interrupt subdevice instances. */ | ||
204 | for (ext_irq_idx = 0; | ||
205 | ext_irq_idx < me1400_versions[version_idx].ext_irq_subdevices; | ||
206 | ext_irq_idx++) { | ||
207 | subdevice = | ||
208 | (me_subdevice_t *) | ||
209 | me1400_ext_irq_constructor(me1400_device->base.info.pci. | ||
210 | device_id, | ||
211 | me1400_device->base.info.pci. | ||
212 | reg_bases[1], | ||
213 | me1400_device->base.info.pci. | ||
214 | reg_bases[2], | ||
215 | &me1400_device->clk_src_reg_lock, | ||
216 | me1400_device->base.irq); | ||
217 | |||
218 | if (!subdevice) { | ||
219 | me_device_deinit((me_device_t *) me1400_device); | ||
220 | kfree(me1400_device); | ||
221 | PERROR("Cannot get memory for subdevice.\n"); | ||
222 | return NULL; | ||
223 | } | ||
224 | |||
225 | me_slist_add_subdevice_tail(&me1400_device->base.slist, | ||
226 | subdevice); | ||
227 | } | ||
228 | |||
229 | return (me_device_t *) me1400_device; | ||
230 | } | ||
231 | |||
232 | // Init and exit of module. | ||
233 | |||
234 | static int __init me1400_init(void) | ||
235 | { | ||
236 | PDEBUG("executed.\n"); | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static void __exit me1400_exit(void) | ||
241 | { | ||
242 | PDEBUG("executed.\n"); | ||
243 | } | ||
244 | |||
245 | module_init(me1400_init); | ||
246 | module_exit(me1400_exit); | ||
247 | |||
248 | // Administrative stuff for modinfo. | ||
249 | MODULE_AUTHOR | ||
250 | ("Guenter Gebhardt <g.gebhardt@meilhaus.de> & Krzysztof Gantzke <k.gantzke@meilhaus.de>"); | ||
251 | MODULE_DESCRIPTION("Device Driver Module for Meilhaus ME-14xx devices"); | ||
252 | MODULE_SUPPORTED_DEVICE("Meilhaus ME-14xx MIO devices"); | ||
253 | MODULE_LICENSE("GPL"); | ||
254 | |||
255 | // Export the constructor. | ||
256 | EXPORT_SYMBOL(me1400_pci_constructor); | ||
diff --git a/drivers/staging/meilhaus/me1400_device.h b/drivers/staging/meilhaus/me1400_device.h new file mode 100644 index 000000000000..6215b250047d --- /dev/null +++ b/drivers/staging/meilhaus/me1400_device.h | |||
@@ -0,0 +1,108 @@ | |||
1 | /** | ||
2 | * @file me1400_device.c | ||
3 | * | ||
4 | * @brief ME-1400 device family instance. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME1400_DEVICE_H_ | ||
28 | #define _ME1400_DEVICE_H_ | ||
29 | |||
30 | #include "metypes.h" | ||
31 | #include "medefines.h" | ||
32 | #include "meinternal.h" | ||
33 | |||
34 | #include "medevice.h" | ||
35 | |||
36 | #ifdef __KERNEL__ | ||
37 | |||
38 | /** | ||
39 | * @brief Structure to store device capabilities. | ||
40 | */ | ||
41 | typedef struct me1400_version { | ||
42 | uint16_t device_id; /**< The PCI device id of the device. */ | ||
43 | unsigned int dio_chips; /**< The number of 8255 chips on the device. */ | ||
44 | unsigned int ctr_chips; /**< The number of 8254 chips on the device. */ | ||
45 | unsigned int ext_irq_subdevices; /**< The number of external interrupt inputs on the device. */ | ||
46 | } me1400_version_t; | ||
47 | |||
48 | /** | ||
49 | * @brief Defines for each ME-1400 device version its capabilities. | ||
50 | */ | ||
51 | static me1400_version_t me1400_versions[] = { | ||
52 | {PCI_DEVICE_ID_MEILHAUS_ME1400, 1, 0, 0}, | ||
53 | {PCI_DEVICE_ID_MEILHAUS_ME140A, 1, 1, 1}, | ||
54 | {PCI_DEVICE_ID_MEILHAUS_ME140B, 2, 2, 1}, | ||
55 | {PCI_DEVICE_ID_MEILHAUS_ME14E0, 1, 0, 0}, | ||
56 | {PCI_DEVICE_ID_MEILHAUS_ME14EA, 1, 1, 1}, | ||
57 | {PCI_DEVICE_ID_MEILHAUS_ME14EB, 2, 2, 1}, | ||
58 | {PCI_DEVICE_ID_MEILHAUS_ME140C, 1, 5, 1}, | ||
59 | {PCI_DEVICE_ID_MEILHAUS_ME140D, 2, 10, 1}, | ||
60 | {0} | ||
61 | }; | ||
62 | |||
63 | #define ME1400_DEVICE_VERSIONS (sizeof(me1400_versions) / sizeof(me1400_version_t) - 1) /**< Returns the number of entries in #me1400_versions. */ | ||
64 | |||
65 | /** | ||
66 | * @brief Returns the index of the device entry in #me1400_versions. | ||
67 | * | ||
68 | * @param device_id The PCI device id of the device to query. | ||
69 | * @return The index of the device in #me1400_versions. | ||
70 | */ | ||
71 | static inline unsigned int me1400_versions_get_device_index(uint16_t device_id) | ||
72 | { | ||
73 | unsigned int i; | ||
74 | for (i = 0; i < ME1400_DEVICE_VERSIONS; i++) | ||
75 | if (me1400_versions[i].device_id == device_id) | ||
76 | break; | ||
77 | return i; | ||
78 | } | ||
79 | |||
80 | #define ME1400_MAX_8254 10 /**< The maximum number of 8254 counter subdevices available on any ME-1400 device. */ | ||
81 | #define ME1400_MAX_8255 2 /**< The maximum number of 8255 digital i/o subdevices available on any ME-1400 device. */ | ||
82 | |||
83 | /** | ||
84 | * @brief The ME-1400 device class. | ||
85 | */ | ||
86 | typedef struct me1400_device { | ||
87 | me_device_t base; /**< The Meilhaus device base class. */ | ||
88 | |||
89 | spinlock_t clk_src_reg_lock; /**< Guards the 8254 clock source registers. */ | ||
90 | spinlock_t ctr_ctrl_reg_lock[ME1400_MAX_8254]; /**< Guards the 8254 ctrl registers. */ | ||
91 | |||
92 | int dio_current_mode[ME1400_MAX_8255]; /**< Saves the current mode setting of a single 8255 DIO chip. */ | ||
93 | spinlock_t dio_ctrl_reg_lock[ME1400_MAX_8255]; /**< Guards the 8255 ctrl register and #dio_current_mode. */ | ||
94 | } me1400_device_t; | ||
95 | |||
96 | /** | ||
97 | * @brief The ME-1400 device class constructor. | ||
98 | * | ||
99 | * @param pci_device The pci device structure given by the PCI subsystem. | ||
100 | * | ||
101 | * @return On succes a new ME-1400 device instance. \n | ||
102 | * NULL on error. | ||
103 | */ | ||
104 | me_device_t *me1400_pci_constructor(struct pci_dev *pci_device) | ||
105 | __attribute__ ((weak)); | ||
106 | |||
107 | #endif | ||
108 | #endif | ||
diff --git a/drivers/staging/meilhaus/me1400_ext_irq.c b/drivers/staging/meilhaus/me1400_ext_irq.c new file mode 100644 index 000000000000..b8c2696bc150 --- /dev/null +++ b/drivers/staging/meilhaus/me1400_ext_irq.c | |||
@@ -0,0 +1,517 @@ | |||
1 | /** | ||
2 | * @file me1400_ext_irq.c | ||
3 | * | ||
4 | * @brief ME-1400 external interrupt subdevice instance. | ||
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 | /* | ||
33 | * Includes | ||
34 | */ | ||
35 | #include <linux/version.h> | ||
36 | #include <linux/module.h> | ||
37 | |||
38 | #include <linux/slab.h> | ||
39 | #include <linux/spinlock.h> | ||
40 | #include <asm/io.h> | ||
41 | #include <linux/types.h> | ||
42 | #include <linux/interrupt.h> | ||
43 | |||
44 | #include "medefines.h" | ||
45 | #include "meinternal.h" | ||
46 | #include "meerror.h" | ||
47 | #include "medebug.h" | ||
48 | #include "meids.h" | ||
49 | |||
50 | #include "me1400_ext_irq.h" | ||
51 | #include "me1400_ext_irq_reg.h" | ||
52 | |||
53 | /* | ||
54 | * Defines | ||
55 | */ | ||
56 | #define ME1400_EXT_IRQ_MAGIC_NUMBER 0x1401 /**< The magic number of the class structure. */ | ||
57 | #define ME1400_EXT_IRQ_NUMBER_CHANNELS 1 /**< One channel per counter. */ | ||
58 | |||
59 | /* | ||
60 | * Functions | ||
61 | */ | ||
62 | |||
63 | static int me1400_ext_irq_io_irq_start(struct me_subdevice *subdevice, | ||
64 | struct file *filep, | ||
65 | int channel, | ||
66 | int irq_source, | ||
67 | int irq_edge, int irq_arg, int flags) | ||
68 | { | ||
69 | me1400_ext_irq_subdevice_t *instance; | ||
70 | unsigned long cpu_flags; | ||
71 | uint8_t tmp; | ||
72 | |||
73 | PDEBUG("executed.\n"); | ||
74 | |||
75 | instance = (me1400_ext_irq_subdevice_t *) subdevice; | ||
76 | |||
77 | if (flags & ~ME_IO_IRQ_START_DIO_BIT) { | ||
78 | PERROR("Invalid flag specified.\n"); | ||
79 | return ME_ERRNO_INVALID_FLAGS; | ||
80 | } | ||
81 | |||
82 | if (channel) { | ||
83 | PERROR("Invalid channel.\n"); | ||
84 | return ME_ERRNO_INVALID_CHANNEL; | ||
85 | } | ||
86 | |||
87 | if (irq_source != ME_IRQ_SOURCE_DIO_LINE) { | ||
88 | PERROR("Invalid irq source.\n"); | ||
89 | return ME_ERRNO_INVALID_IRQ_SOURCE; | ||
90 | } | ||
91 | |||
92 | if (irq_edge != ME_IRQ_EDGE_RISING) { | ||
93 | PERROR("Invalid irq edge.\n"); | ||
94 | return ME_ERRNO_INVALID_IRQ_EDGE; | ||
95 | } | ||
96 | |||
97 | ME_SUBDEVICE_ENTER; | ||
98 | |||
99 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
100 | |||
101 | spin_lock(instance->clk_src_reg_lock); | ||
102 | // // Enable IRQ on PLX | ||
103 | // tmp = inb(instance->plx_intcs_reg) | (PLX_LOCAL_INT1_EN | PLX_LOCAL_INT1_POL | PLX_PCI_INT_EN); | ||
104 | // outb(tmp, instance->plx_intcs_reg); | ||
105 | // PDEBUG_REG("ctrl_reg outb(PLX:0x%lX)=0x%x\n", instance->plx_intcs_reg, tmp); | ||
106 | |||
107 | // Enable IRQ | ||
108 | switch (instance->device_id) { | ||
109 | case PCI_DEVICE_ID_MEILHAUS_ME140C: | ||
110 | case PCI_DEVICE_ID_MEILHAUS_ME140D: | ||
111 | tmp = inb(instance->ctrl_reg); | ||
112 | tmp |= ME1400CD_EXT_IRQ_CLK_EN; | ||
113 | outb(tmp, instance->ctrl_reg); | ||
114 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
115 | instance->reg_base, | ||
116 | instance->ctrl_reg - instance->reg_base, tmp); | ||
117 | break; | ||
118 | |||
119 | default: | ||
120 | outb(ME1400AB_EXT_IRQ_IRQ_EN, instance->ctrl_reg); | ||
121 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
122 | instance->reg_base, | ||
123 | instance->ctrl_reg - instance->reg_base, | ||
124 | ME1400AB_EXT_IRQ_IRQ_EN); | ||
125 | break; | ||
126 | } | ||
127 | spin_unlock(instance->clk_src_reg_lock); | ||
128 | instance->rised = 0; | ||
129 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
130 | |||
131 | ME_SUBDEVICE_EXIT; | ||
132 | |||
133 | return ME_ERRNO_SUCCESS; | ||
134 | } | ||
135 | |||
136 | static int me1400_ext_irq_io_irq_wait(struct me_subdevice *subdevice, | ||
137 | struct file *filep, | ||
138 | int channel, | ||
139 | int *irq_count, | ||
140 | int *value, int time_out, int flags) | ||
141 | { | ||
142 | me1400_ext_irq_subdevice_t *instance; | ||
143 | unsigned long cpu_flags; | ||
144 | long t = 0; | ||
145 | int err = ME_ERRNO_SUCCESS; | ||
146 | |||
147 | PDEBUG("executed.\n"); | ||
148 | |||
149 | instance = (me1400_ext_irq_subdevice_t *) subdevice; | ||
150 | |||
151 | if (flags) { | ||
152 | PERROR("Invalid flag specified.\n"); | ||
153 | return ME_ERRNO_INVALID_FLAGS; | ||
154 | } | ||
155 | |||
156 | if (channel) { | ||
157 | PERROR("Invalid channel.\n"); | ||
158 | return ME_ERRNO_INVALID_CHANNEL; | ||
159 | } | ||
160 | |||
161 | if (time_out < 0) { | ||
162 | PERROR("Invalid time out.\n"); | ||
163 | return ME_ERRNO_INVALID_TIMEOUT; | ||
164 | } | ||
165 | |||
166 | if (time_out) { | ||
167 | /* Convert to ticks */ | ||
168 | t = (time_out * HZ) / 1000; | ||
169 | |||
170 | if (t == 0) | ||
171 | t = 1; | ||
172 | } | ||
173 | |||
174 | ME_SUBDEVICE_ENTER; | ||
175 | |||
176 | if (instance->rised <= 0) { | ||
177 | instance->rised = 0; | ||
178 | if (time_out) { | ||
179 | t = wait_event_interruptible_timeout(instance-> | ||
180 | wait_queue, | ||
181 | (instance->rised != | ||
182 | 0), t); | ||
183 | |||
184 | if (t == 0) { | ||
185 | PERROR("Wait on interrupt timed out.\n"); | ||
186 | err = ME_ERRNO_TIMEOUT; | ||
187 | } | ||
188 | } else { | ||
189 | wait_event_interruptible(instance->wait_queue, | ||
190 | (instance->rised != 0)); | ||
191 | } | ||
192 | |||
193 | if (instance->rised < 0) { | ||
194 | PERROR("Wait on interrupt aborted by user.\n"); | ||
195 | err = ME_ERRNO_CANCELLED; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | if (signal_pending(current)) { | ||
200 | PERROR("Wait on interrupt aborted by signal.\n"); | ||
201 | err = ME_ERRNO_SIGNAL; | ||
202 | } | ||
203 | |||
204 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
205 | instance->rised = 0; | ||
206 | *irq_count = instance->n; | ||
207 | *value = 1; | ||
208 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
209 | |||
210 | ME_SUBDEVICE_EXIT; | ||
211 | |||
212 | return err; | ||
213 | } | ||
214 | |||
215 | static int me1400_ext_irq_io_irq_stop(struct me_subdevice *subdevice, | ||
216 | struct file *filep, | ||
217 | int channel, int flags) | ||
218 | { | ||
219 | me1400_ext_irq_subdevice_t *instance; | ||
220 | unsigned long cpu_flags; | ||
221 | uint8_t tmp; | ||
222 | int err = ME_ERRNO_SUCCESS; | ||
223 | |||
224 | PDEBUG("executed.\n"); | ||
225 | |||
226 | instance = (me1400_ext_irq_subdevice_t *) subdevice; | ||
227 | |||
228 | if (flags) { | ||
229 | PERROR("Invalid flag specified.\n"); | ||
230 | return ME_ERRNO_INVALID_FLAGS; | ||
231 | } | ||
232 | |||
233 | if (channel) { | ||
234 | PERROR("Invalid channel.\n"); | ||
235 | return ME_ERRNO_INVALID_CHANNEL; | ||
236 | } | ||
237 | |||
238 | ME_SUBDEVICE_ENTER; | ||
239 | |||
240 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
241 | spin_lock(instance->clk_src_reg_lock); | ||
242 | // // Disable IRQ on PLX | ||
243 | // tmp = inb(instance->plx_intcs_reg) & ( ~(PLX_LOCAL_INT1_EN | PLX_LOCAL_INT1_POL | PLX_PCI_INT_EN)); | ||
244 | // outb(tmp, instance->plx_intcs_reg); | ||
245 | // PDEBUG_REG("ctrl_reg outb(PLX:0x%lX)=0x%x\n", instance->plx_intcs_reg, tmp); | ||
246 | |||
247 | switch (instance->device_id) { | ||
248 | case PCI_DEVICE_ID_MEILHAUS_ME140C: | ||
249 | case PCI_DEVICE_ID_MEILHAUS_ME140D: | ||
250 | tmp = inb(instance->ctrl_reg); | ||
251 | tmp &= ~ME1400CD_EXT_IRQ_CLK_EN; | ||
252 | outb(tmp, instance->ctrl_reg); | ||
253 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
254 | instance->reg_base, | ||
255 | instance->ctrl_reg - instance->reg_base, tmp); | ||
256 | |||
257 | break; | ||
258 | |||
259 | default: | ||
260 | outb(0x00, instance->ctrl_reg); | ||
261 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
262 | instance->reg_base, | ||
263 | instance->ctrl_reg - instance->reg_base, 0x00); | ||
264 | break; | ||
265 | } | ||
266 | spin_unlock(instance->clk_src_reg_lock); | ||
267 | instance->rised = -1; | ||
268 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
269 | wake_up_interruptible_all(&instance->wait_queue); | ||
270 | |||
271 | ME_SUBDEVICE_EXIT; | ||
272 | |||
273 | return err; | ||
274 | } | ||
275 | |||
276 | static int me1400_ext_irq_io_reset_subdevice(struct me_subdevice *subdevice, | ||
277 | struct file *filep, int flags) | ||
278 | { | ||
279 | me1400_ext_irq_subdevice_t *instance = | ||
280 | (me1400_ext_irq_subdevice_t *) subdevice; | ||
281 | |||
282 | PDEBUG("executed.\n"); | ||
283 | |||
284 | if (flags) { | ||
285 | PERROR("Invalid flag specified.\n"); | ||
286 | return ME_ERRNO_INVALID_FLAGS; | ||
287 | } | ||
288 | |||
289 | instance->n = 0; | ||
290 | return me1400_ext_irq_io_irq_stop(subdevice, filep, 0, flags); | ||
291 | } | ||
292 | |||
293 | static int me1400_ext_irq_query_number_channels(struct me_subdevice *subdevice, | ||
294 | int *number) | ||
295 | { | ||
296 | PDEBUG("executed.\n"); | ||
297 | *number = ME1400_EXT_IRQ_NUMBER_CHANNELS; | ||
298 | return ME_ERRNO_SUCCESS; | ||
299 | } | ||
300 | |||
301 | static int me1400_ext_irq_query_subdevice_type(struct me_subdevice *subdevice, | ||
302 | int *type, int *subtype) | ||
303 | { | ||
304 | PDEBUG("executed.\n"); | ||
305 | *type = ME_TYPE_EXT_IRQ; | ||
306 | *subtype = ME_SUBTYPE_SINGLE; | ||
307 | return ME_ERRNO_SUCCESS; | ||
308 | } | ||
309 | |||
310 | static int me1400_ext_irq_query_subdevice_caps(struct me_subdevice *subdevice, | ||
311 | int *caps) | ||
312 | { | ||
313 | PDEBUG("executed.\n"); | ||
314 | *caps = ME_CAPS_EXT_IRQ_EDGE_RISING; | ||
315 | return ME_ERRNO_SUCCESS; | ||
316 | } | ||
317 | |||
318 | static int me1400_ext_irq_query_subdevice_caps_args(struct me_subdevice | ||
319 | *subdevice, int cap, | ||
320 | int *args, int count) | ||
321 | { | ||
322 | PDEBUG("executed.\n"); | ||
323 | return ME_ERRNO_NOT_SUPPORTED; | ||
324 | } | ||
325 | |||
326 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) | ||
327 | static irqreturn_t me1400_ext_irq_isr(int irq, void *dev_id) | ||
328 | #else | ||
329 | static irqreturn_t me1400_ext_irq_isr(int irq, void *dev_id, | ||
330 | struct pt_regs *regs) | ||
331 | #endif | ||
332 | { | ||
333 | me1400_ext_irq_subdevice_t *instance; | ||
334 | uint32_t status; | ||
335 | uint8_t tmp; | ||
336 | |||
337 | instance = (me1400_ext_irq_subdevice_t *) dev_id; | ||
338 | |||
339 | if (irq != instance->irq) { | ||
340 | PERROR("Incorrect interrupt num: %d.\n", irq); | ||
341 | return IRQ_NONE; | ||
342 | } | ||
343 | |||
344 | spin_lock(&instance->subdevice_lock); | ||
345 | status = inl(instance->plx_intcs_reg); | ||
346 | // if (!((status & PLX_LOCAL_INT1_STATE) && (status & PLX_LOCAL_INT1_EN) && (status & PLX_PCI_INT_EN))) | ||
347 | if ((status & | ||
348 | (PLX_LOCAL_INT1_STATE | PLX_LOCAL_INT1_EN | PLX_PCI_INT_EN)) != | ||
349 | (PLX_LOCAL_INT1_STATE | PLX_LOCAL_INT1_EN | PLX_PCI_INT_EN)) { | ||
350 | spin_unlock(&instance->subdevice_lock); | ||
351 | PINFO("%ld Shared interrupt. %s(): irq_status_reg=0x%04X\n", | ||
352 | jiffies, __FUNCTION__, status); | ||
353 | return IRQ_NONE; | ||
354 | } | ||
355 | |||
356 | inl(instance->ctrl_reg); | ||
357 | |||
358 | PDEBUG("executed.\n"); | ||
359 | |||
360 | instance->n++; | ||
361 | instance->rised = 1; | ||
362 | |||
363 | switch (instance->device_id) { | ||
364 | |||
365 | case PCI_DEVICE_ID_MEILHAUS_ME140C: | ||
366 | case PCI_DEVICE_ID_MEILHAUS_ME140D: | ||
367 | spin_lock(instance->clk_src_reg_lock); | ||
368 | tmp = inb(instance->ctrl_reg); | ||
369 | tmp &= ~ME1400CD_EXT_IRQ_CLK_EN; | ||
370 | outb(tmp, instance->ctrl_reg); | ||
371 | PDEBUG_REG("ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", | ||
372 | instance->reg_base, | ||
373 | instance->ctrl_reg - instance->reg_base, tmp); | ||
374 | tmp |= ME1400CD_EXT_IRQ_CLK_EN; | ||
375 | outb(tmp, instance->ctrl_reg); | ||
376 | PDEBUG_REG("ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", | ||
377 | instance->reg_base, | ||
378 | instance->ctrl_reg - instance->reg_base, tmp); | ||
379 | spin_unlock(instance->clk_src_reg_lock); | ||
380 | |||
381 | break; | ||
382 | |||
383 | default: | ||
384 | outb(0, instance->ctrl_reg); | ||
385 | PDEBUG_REG("ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", | ||
386 | instance->reg_base, | ||
387 | instance->ctrl_reg - instance->reg_base, 0); | ||
388 | outb(ME1400AB_EXT_IRQ_IRQ_EN, instance->ctrl_reg); | ||
389 | PDEBUG_REG("ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", | ||
390 | instance->reg_base, | ||
391 | instance->ctrl_reg - instance->reg_base, | ||
392 | ME1400AB_EXT_IRQ_IRQ_EN); | ||
393 | break; | ||
394 | } | ||
395 | |||
396 | spin_unlock(&instance->subdevice_lock); | ||
397 | wake_up_interruptible_all(&instance->wait_queue); | ||
398 | |||
399 | return IRQ_HANDLED; | ||
400 | } | ||
401 | |||
402 | static void me1400_ext_irq_destructor(struct me_subdevice *subdevice) | ||
403 | { | ||
404 | me1400_ext_irq_subdevice_t *instance; | ||
405 | uint8_t tmp; | ||
406 | |||
407 | PDEBUG("executed.\n"); | ||
408 | |||
409 | instance = (me1400_ext_irq_subdevice_t *) subdevice; | ||
410 | |||
411 | // Disable IRQ on PLX | ||
412 | tmp = | ||
413 | inb(instance-> | ||
414 | plx_intcs_reg) & (~(PLX_LOCAL_INT1_EN | PLX_LOCAL_INT1_POL | | ||
415 | PLX_PCI_INT_EN)); | ||
416 | outb(tmp, instance->plx_intcs_reg); | ||
417 | PDEBUG_REG("ctrl_reg outb(plx:0x%lX)=0x%x\n", instance->plx_intcs_reg, | ||
418 | tmp); | ||
419 | |||
420 | free_irq(instance->irq, (void *)instance); | ||
421 | me_subdevice_deinit(&instance->base); | ||
422 | kfree(instance); | ||
423 | } | ||
424 | |||
425 | me1400_ext_irq_subdevice_t *me1400_ext_irq_constructor(uint32_t device_id, | ||
426 | uint32_t plx_reg_base, | ||
427 | uint32_t me1400_reg_base, | ||
428 | spinlock_t * | ||
429 | clk_src_reg_lock, | ||
430 | int irq) | ||
431 | { | ||
432 | me1400_ext_irq_subdevice_t *subdevice; | ||
433 | int err; | ||
434 | uint8_t tmp; | ||
435 | |||
436 | PDEBUG("executed.\n"); | ||
437 | |||
438 | /* Allocate memory for subdevice instance */ | ||
439 | subdevice = kmalloc(sizeof(me1400_ext_irq_subdevice_t), GFP_KERNEL); | ||
440 | |||
441 | if (!subdevice) { | ||
442 | PERROR("Cannot get memory for 1400_ext_irq instance.\n"); | ||
443 | return NULL; | ||
444 | } | ||
445 | |||
446 | memset(subdevice, 0, sizeof(me1400_ext_irq_subdevice_t)); | ||
447 | |||
448 | /* Initialize subdevice base class */ | ||
449 | err = me_subdevice_init(&subdevice->base); | ||
450 | |||
451 | if (err) { | ||
452 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
453 | kfree(subdevice); | ||
454 | return NULL; | ||
455 | } | ||
456 | // Initialize spin locks. | ||
457 | spin_lock_init(&subdevice->subdevice_lock); | ||
458 | subdevice->clk_src_reg_lock = clk_src_reg_lock; | ||
459 | |||
460 | /* Initialize wait queue */ | ||
461 | init_waitqueue_head(&subdevice->wait_queue); | ||
462 | |||
463 | subdevice->irq = irq; | ||
464 | |||
465 | err = request_irq(irq, me1400_ext_irq_isr, | ||
466 | #ifdef IRQF_DISABLED | ||
467 | IRQF_DISABLED | IRQF_SHARED, | ||
468 | #else | ||
469 | SA_INTERRUPT | SA_SHIRQ, | ||
470 | #endif | ||
471 | ME1400_NAME, (void *)subdevice); | ||
472 | |||
473 | if (err) { | ||
474 | PERROR("Can't get irq.\n"); | ||
475 | me_subdevice_deinit(&subdevice->base); | ||
476 | kfree(subdevice); | ||
477 | return NULL; | ||
478 | } | ||
479 | PINFO("Registered irq=%d.\n", subdevice->irq); | ||
480 | |||
481 | /* Initialize registers */ | ||
482 | subdevice->plx_intcs_reg = plx_reg_base + PLX_INTCSR_REG; | ||
483 | subdevice->ctrl_reg = me1400_reg_base + ME1400AB_EXT_IRQ_CTRL_REG; | ||
484 | #ifdef MEDEBUG_DEBUG_REG | ||
485 | subdevice->reg_base = me1400_reg_base; | ||
486 | #endif | ||
487 | |||
488 | // Enable IRQ on PLX | ||
489 | tmp = | ||
490 | inb(subdevice-> | ||
491 | plx_intcs_reg) | (PLX_LOCAL_INT1_EN | PLX_LOCAL_INT1_POL | | ||
492 | PLX_PCI_INT_EN); | ||
493 | outb(tmp, subdevice->plx_intcs_reg); | ||
494 | PDEBUG_REG("ctrl_reg outb(Pplx:0x%lX)=0x%x\n", subdevice->plx_intcs_reg, | ||
495 | tmp); | ||
496 | |||
497 | /* Initialize the subdevice methods */ | ||
498 | subdevice->base.me_subdevice_io_irq_start = me1400_ext_irq_io_irq_start; | ||
499 | subdevice->base.me_subdevice_io_irq_wait = me1400_ext_irq_io_irq_wait; | ||
500 | subdevice->base.me_subdevice_io_irq_stop = me1400_ext_irq_io_irq_stop; | ||
501 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
502 | me1400_ext_irq_io_reset_subdevice; | ||
503 | subdevice->base.me_subdevice_query_number_channels = | ||
504 | me1400_ext_irq_query_number_channels; | ||
505 | subdevice->base.me_subdevice_query_subdevice_type = | ||
506 | me1400_ext_irq_query_subdevice_type; | ||
507 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
508 | me1400_ext_irq_query_subdevice_caps; | ||
509 | subdevice->base.me_subdevice_query_subdevice_caps_args = | ||
510 | me1400_ext_irq_query_subdevice_caps_args; | ||
511 | subdevice->base.me_subdevice_destructor = me1400_ext_irq_destructor; | ||
512 | |||
513 | subdevice->rised = 0; | ||
514 | subdevice->n = 0; | ||
515 | |||
516 | return subdevice; | ||
517 | } | ||
diff --git a/drivers/staging/meilhaus/me1400_ext_irq.h b/drivers/staging/meilhaus/me1400_ext_irq.h new file mode 100644 index 000000000000..9b72a04701c0 --- /dev/null +++ b/drivers/staging/meilhaus/me1400_ext_irq.h | |||
@@ -0,0 +1,62 @@ | |||
1 | /** | ||
2 | * @file me1400_ext_irq.h | ||
3 | * | ||
4 | * @brief ME-1400 external interrupt implementation. | ||
5 | * @note Copyright (C) 2006 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | #ifndef _ME1400_EXT_IRQ_H_ | ||
10 | #define _ME1400_EXT_IRQ_H_ | ||
11 | |||
12 | #include <linux/sched.h> | ||
13 | |||
14 | #include "mesubdevice.h" | ||
15 | #include "meslock.h" | ||
16 | |||
17 | #ifdef __KERNEL__ | ||
18 | |||
19 | /** | ||
20 | * @brief The ME-1400 external interrupt subdevice class. | ||
21 | */ | ||
22 | typedef struct me1400_ext_irq_subdevice { | ||
23 | /* Inheritance */ | ||
24 | me_subdevice_t base; /**< The subdevice base class. */ | ||
25 | |||
26 | /* Attributes */ | ||
27 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
28 | spinlock_t *clk_src_reg_lock; /**< Lock protecting the clock control register. */ | ||
29 | |||
30 | wait_queue_head_t wait_queue; /**< Queue to put on threads waiting for an interrupt. */ | ||
31 | |||
32 | uint32_t device_id; /**< The device id of the device holding the subdevice. */ | ||
33 | int irq; /**< The irq number assigned by PCI BIOS. */ | ||
34 | int rised; /**< If true an interrupt has occured. */ | ||
35 | unsigned int n; /**< The number of interrupt since the driver was loaded. */ | ||
36 | |||
37 | unsigned long plx_intcs_reg; /**< The PLX interrupt control and status register. */ | ||
38 | unsigned long ctrl_reg; /**< The control register. */ | ||
39 | #ifdef MEDEBUG_DEBUG_REG | ||
40 | unsigned long reg_base; | ||
41 | #endif | ||
42 | } me1400_ext_irq_subdevice_t; | ||
43 | |||
44 | /** | ||
45 | * @brief The constructor to generate a ME-1400 external interrupt instance. | ||
46 | * | ||
47 | * @param plx_reg_base The register base address of the PLX chip as returned by the PCI BIOS. | ||
48 | * @param me1400_reg_base The register base address of the ME-1400 device as returned by the PCI BIOS. | ||
49 | * @param irq The irq assigned by the PCI BIOS. | ||
50 | * | ||
51 | * @return Pointer to new instance on success.\n | ||
52 | * NULL on error. | ||
53 | */ | ||
54 | me1400_ext_irq_subdevice_t *me1400_ext_irq_constructor(uint32_t device_id, | ||
55 | uint32_t plx_reg_base, | ||
56 | uint32_t me1400_reg_base, | ||
57 | spinlock_t * | ||
58 | clk_src_reg_lock, | ||
59 | int irq); | ||
60 | |||
61 | #endif | ||
62 | #endif | ||
diff --git a/drivers/staging/meilhaus/me1400_ext_irq_reg.h b/drivers/staging/meilhaus/me1400_ext_irq_reg.h new file mode 100644 index 000000000000..c9740f2dd3a7 --- /dev/null +++ b/drivers/staging/meilhaus/me1400_ext_irq_reg.h | |||
@@ -0,0 +1,56 @@ | |||
1 | /** | ||
2 | * @file me1400_ext_irq_reg.h | ||
3 | * | ||
4 | * @brief ME-1400 external interrupt register definitions. | ||
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 _ME1400_EXT_IRQ_REG_H_ | ||
29 | # define _ME1400_EXT_IRQ_REG_H_ | ||
30 | |||
31 | # ifdef __KERNEL__ | ||
32 | |||
33 | # define PLX_INTCSR_REG 0x4C /**< The PLX interrupt control and status register offset. */ | ||
34 | # define PLX_ICR_REG 0x50 /**< The PLX initialization control register offset. */ | ||
35 | |||
36 | # define PLX_LOCAL_INT1_EN 0x01 /**< If set the local interrupt 1 is enabled. */ | ||
37 | # define PLX_LOCAL_INT1_POL 0x02 /**< If set the local interrupt 1 polarity is high active. */ | ||
38 | # define PLX_LOCAL_INT1_STATE 0x04 /**< If set the local interrupt 1 is activ. */ | ||
39 | # define PLX_LOCAL_INT2_EN 0x08 /**< If set the local interrupt 2 is enabled. */ | ||
40 | # define PLX_LOCAL_INT2_POL 0x10 /**< If set the local interrupt 2 polarity is high active. */ | ||
41 | # define PLX_LOCAL_INT2_STATE 0x20 /**< If set the local interrupt 2 is activ. */ | ||
42 | # define PLX_PCI_INT_EN 0x40 /**< If set the PCI interrupt is enabled. */ | ||
43 | # define PLX_SOFT_INT 0x80 /**< If set an interrupt is generated. */ | ||
44 | |||
45 | # define ME1400AB_EXT_IRQ_CTRL_REG 0x11 /**< The external interrupt control register offset. */ | ||
46 | |||
47 | # define ME1400AB_EXT_IRQ_CLK_EN 0x01 /**< If this bit is set, the clock output is enabled. */ | ||
48 | # define ME1400AB_EXT_IRQ_IRQ_EN 0x02 /**< If set the external interrupt is enabled. Clearing this bit clears a pending interrupt. */ | ||
49 | |||
50 | # define ME1400CD_EXT_IRQ_CTRL_REG 0x11 /**< The external interrupt control register offset. */ | ||
51 | |||
52 | # define ME1400CD_EXT_IRQ_CLK_EN 0x10 /**< If set the external interrupt is enabled. Clearing this bit clears a pending interrupt.*/ | ||
53 | |||
54 | # endif //__KERNEL__ | ||
55 | |||
56 | #endif //_ME1400_EXT_IRQ_REG_H_ | ||
diff --git a/drivers/staging/meilhaus/me1600_ao.c b/drivers/staging/meilhaus/me1600_ao.c new file mode 100644 index 000000000000..6f26665b30b7 --- /dev/null +++ b/drivers/staging/meilhaus/me1600_ao.c | |||
@@ -0,0 +1,1033 @@ | |||
1 | /** | ||
2 | * @file me1600_ao.c | ||
3 | * | ||
4 | * @brief ME-1600 analog output subdevice instance. | ||
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 | /* Includes | ||
33 | */ | ||
34 | |||
35 | #include <linux/module.h> | ||
36 | |||
37 | #include <linux/slab.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | #include <asm/io.h> | ||
40 | #include <linux/types.h> | ||
41 | #include <linux/sched.h> | ||
42 | |||
43 | #include <linux/workqueue.h> | ||
44 | |||
45 | #include "medefines.h" | ||
46 | #include "meinternal.h" | ||
47 | #include "meerror.h" | ||
48 | #include "medebug.h" | ||
49 | |||
50 | #include "me1600_ao_reg.h" | ||
51 | #include "me1600_ao.h" | ||
52 | |||
53 | /* Defines | ||
54 | */ | ||
55 | |||
56 | static void me1600_ao_destructor(struct me_subdevice *subdevice); | ||
57 | |||
58 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) | ||
59 | static void me1600_ao_work_control_task(void *subdevice); | ||
60 | #else | ||
61 | static void me1600_ao_work_control_task(struct work_struct *work); | ||
62 | #endif | ||
63 | |||
64 | static int me1600_ao_io_reset_subdevice(me_subdevice_t * subdevice, | ||
65 | struct file *filep, int flags); | ||
66 | static int me1600_ao_io_single_config(me_subdevice_t * subdevice, | ||
67 | struct file *filep, int channel, | ||
68 | int single_config, int ref, int trig_chan, | ||
69 | int trig_type, int trig_edge, int flags); | ||
70 | static int me1600_ao_io_single_read(me_subdevice_t * subdevice, | ||
71 | struct file *filep, int channel, int *value, | ||
72 | int time_out, int flags); | ||
73 | static int me1600_ao_io_single_write(me_subdevice_t * subdevice, | ||
74 | struct file *filep, int channel, int value, | ||
75 | int time_out, int flags); | ||
76 | static int me1600_ao_query_number_channels(me_subdevice_t * subdevice, | ||
77 | int *number); | ||
78 | static int me1600_ao_query_subdevice_type(me_subdevice_t * subdevice, int *type, | ||
79 | int *subtype); | ||
80 | static int me1600_ao_query_subdevice_caps(me_subdevice_t * subdevice, | ||
81 | int *caps); | ||
82 | static int me1600_ao_query_range_by_min_max(me_subdevice_t * subdevice, | ||
83 | int unit, int *min, int *max, | ||
84 | int *maxdata, int *range); | ||
85 | static int me1600_ao_query_number_ranges(me_subdevice_t * subdevice, int unit, | ||
86 | int *count); | ||
87 | static int me1600_ao_query_range_info(me_subdevice_t * subdevice, int range, | ||
88 | int *unit, int *min, int *max, | ||
89 | int *maxdata); | ||
90 | |||
91 | /* Functions | ||
92 | */ | ||
93 | |||
94 | me1600_ao_subdevice_t *me1600_ao_constructor(uint32_t reg_base, | ||
95 | unsigned int ao_idx, | ||
96 | int curr, | ||
97 | spinlock_t * config_regs_lock, | ||
98 | spinlock_t * ao_shadows_lock, | ||
99 | me1600_ao_shadow_t * | ||
100 | ao_regs_shadows, | ||
101 | struct workqueue_struct *me1600_wq) | ||
102 | { | ||
103 | me1600_ao_subdevice_t *subdevice; | ||
104 | int err; | ||
105 | |||
106 | PDEBUG("executed. idx=%d\n", ao_idx); | ||
107 | |||
108 | // Allocate memory for subdevice instance. | ||
109 | subdevice = kmalloc(sizeof(me1600_ao_subdevice_t), GFP_KERNEL); | ||
110 | |||
111 | if (!subdevice) { | ||
112 | PERROR | ||
113 | ("Cannot get memory for analog output subdevice instance.\n"); | ||
114 | return NULL; | ||
115 | } | ||
116 | |||
117 | memset(subdevice, 0, sizeof(me1600_ao_subdevice_t)); | ||
118 | |||
119 | // Initialize subdevice base class. | ||
120 | err = me_subdevice_init(&subdevice->base); | ||
121 | |||
122 | if (err) { | ||
123 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
124 | kfree(subdevice); | ||
125 | return NULL; | ||
126 | } | ||
127 | // Initialize spin locks. | ||
128 | spin_lock_init(&subdevice->subdevice_lock); | ||
129 | subdevice->config_regs_lock = config_regs_lock; | ||
130 | subdevice->ao_shadows_lock = ao_shadows_lock; | ||
131 | |||
132 | // Save the subdevice index. | ||
133 | subdevice->ao_idx = ao_idx; | ||
134 | |||
135 | // Initialize range lists. | ||
136 | subdevice->u_ranges_count = 2; | ||
137 | |||
138 | subdevice->u_ranges[0].min = 0; //0V | ||
139 | subdevice->u_ranges[0].max = 9997558; //10V | ||
140 | |||
141 | subdevice->u_ranges[1].min = -10E6; //-10V | ||
142 | subdevice->u_ranges[1].max = 9995117; //10V | ||
143 | |||
144 | if (curr) { // This is version with current outputs. | ||
145 | subdevice->i_ranges_count = 2; | ||
146 | |||
147 | subdevice->i_ranges[0].min = 0; //0mA | ||
148 | subdevice->i_ranges[0].max = 19995117; //20mA | ||
149 | |||
150 | subdevice->i_ranges[1].min = 4E3; //4mA | ||
151 | subdevice->i_ranges[1].max = 19995118; //20mA | ||
152 | } else { // This is version without current outputs. | ||
153 | subdevice->i_ranges_count = 0; | ||
154 | |||
155 | subdevice->i_ranges[0].min = 0; //0mA | ||
156 | subdevice->i_ranges[0].max = 0; //0mA | ||
157 | |||
158 | subdevice->i_ranges[1].min = 0; //0mA | ||
159 | subdevice->i_ranges[1].max = 0; //0mA | ||
160 | } | ||
161 | |||
162 | // Initialize registers. | ||
163 | subdevice->uni_bi_reg = reg_base + ME1600_UNI_BI_REG; | ||
164 | subdevice->i_range_reg = reg_base + ME1600_020_420_REG; | ||
165 | subdevice->sim_output_reg = reg_base + ME1600_SIM_OUTPUT_REG; | ||
166 | subdevice->current_on_reg = reg_base + ME1600_CURRENT_ON_REG; | ||
167 | #ifdef MEDEBUG_DEBUG_REG | ||
168 | subdevice->reg_base = reg_base; | ||
169 | #endif | ||
170 | |||
171 | // Initialize shadow structure. | ||
172 | subdevice->ao_regs_shadows = ao_regs_shadows; | ||
173 | |||
174 | // Override base class methods. | ||
175 | subdevice->base.me_subdevice_destructor = me1600_ao_destructor; | ||
176 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
177 | me1600_ao_io_reset_subdevice; | ||
178 | subdevice->base.me_subdevice_io_single_config = | ||
179 | me1600_ao_io_single_config; | ||
180 | subdevice->base.me_subdevice_io_single_read = me1600_ao_io_single_read; | ||
181 | subdevice->base.me_subdevice_io_single_write = | ||
182 | me1600_ao_io_single_write; | ||
183 | subdevice->base.me_subdevice_query_number_channels = | ||
184 | me1600_ao_query_number_channels; | ||
185 | subdevice->base.me_subdevice_query_subdevice_type = | ||
186 | me1600_ao_query_subdevice_type; | ||
187 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
188 | me1600_ao_query_subdevice_caps; | ||
189 | subdevice->base.me_subdevice_query_range_by_min_max = | ||
190 | me1600_ao_query_range_by_min_max; | ||
191 | subdevice->base.me_subdevice_query_number_ranges = | ||
192 | me1600_ao_query_number_ranges; | ||
193 | subdevice->base.me_subdevice_query_range_info = | ||
194 | me1600_ao_query_range_info; | ||
195 | |||
196 | // Initialize wait queue. | ||
197 | init_waitqueue_head(&subdevice->wait_queue); | ||
198 | |||
199 | // Prepare work queue. | ||
200 | subdevice->me1600_workqueue = me1600_wq; | ||
201 | |||
202 | /* workqueue API changed in kernel 2.6.20 */ | ||
203 | #if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ) | ||
204 | INIT_WORK(&subdevice->ao_control_task, me1600_ao_work_control_task, | ||
205 | (void *)subdevice); | ||
206 | #else | ||
207 | INIT_DELAYED_WORK(&subdevice->ao_control_task, | ||
208 | me1600_ao_work_control_task); | ||
209 | #endif | ||
210 | return subdevice; | ||
211 | } | ||
212 | |||
213 | static void me1600_ao_destructor(struct me_subdevice *subdevice) | ||
214 | { | ||
215 | me1600_ao_subdevice_t *instance; | ||
216 | |||
217 | instance = (me1600_ao_subdevice_t *) subdevice; | ||
218 | |||
219 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
220 | |||
221 | instance->ao_control_task_flag = 0; | ||
222 | |||
223 | // Reset subdevice to asure clean exit. | ||
224 | me1600_ao_io_reset_subdevice(subdevice, NULL, | ||
225 | ME_IO_RESET_SUBDEVICE_NO_FLAGS); | ||
226 | |||
227 | // Remove any tasks from work queue. This is paranoic because it was done allready in reset(). | ||
228 | if (!cancel_delayed_work(&instance->ao_control_task)) { //Wait 2 ticks to be sure that control task is removed from queue. | ||
229 | set_current_state(TASK_INTERRUPTIBLE); | ||
230 | schedule_timeout(2); | ||
231 | } | ||
232 | } | ||
233 | |||
234 | static int me1600_ao_io_reset_subdevice(me_subdevice_t * subdevice, | ||
235 | struct file *filep, int flags) | ||
236 | { | ||
237 | me1600_ao_subdevice_t *instance; | ||
238 | uint16_t tmp; | ||
239 | |||
240 | instance = (me1600_ao_subdevice_t *) subdevice; | ||
241 | |||
242 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
243 | |||
244 | if (flags) { | ||
245 | PERROR("Invalid flag specified.\n"); | ||
246 | return ME_ERRNO_INVALID_FLAGS; | ||
247 | } | ||
248 | |||
249 | ME_SUBDEVICE_ENTER; | ||
250 | |||
251 | //Cancel control task | ||
252 | PDEBUG("Cancel control task. idx=%d\n", instance->ao_idx); | ||
253 | instance->ao_control_task_flag = 0; | ||
254 | cancel_delayed_work(&instance->ao_control_task); | ||
255 | (instance->ao_regs_shadows)->trigger &= ~(0x1 << instance->ao_idx); //Cancell waiting for trigger. | ||
256 | |||
257 | // Reset all settings. | ||
258 | spin_lock(&instance->subdevice_lock); | ||
259 | spin_lock(instance->ao_shadows_lock); | ||
260 | (instance->ao_regs_shadows)->shadow[instance->ao_idx] = 0; | ||
261 | (instance->ao_regs_shadows)->mirror[instance->ao_idx] = 0; | ||
262 | (instance->ao_regs_shadows)->trigger &= ~(0x1 << instance->ao_idx); //Not waiting for triggering. | ||
263 | (instance->ao_regs_shadows)->synchronous &= ~(0x1 << instance->ao_idx); //Individual triggering. | ||
264 | |||
265 | // Set output to default (safe) state. | ||
266 | spin_lock(instance->config_regs_lock); | ||
267 | tmp = inw(instance->uni_bi_reg); // unipolar | ||
268 | tmp |= (0x1 << instance->ao_idx); | ||
269 | outw(tmp, instance->uni_bi_reg); | ||
270 | PDEBUG_REG("uni_bi_reg outw(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
271 | instance->uni_bi_reg - instance->reg_base, tmp); | ||
272 | |||
273 | tmp = inw(instance->current_on_reg); // Volts only! | ||
274 | tmp &= ~(0x1 << instance->ao_idx); | ||
275 | tmp &= 0x00FF; | ||
276 | outw(tmp, instance->current_on_reg); | ||
277 | PDEBUG_REG("current_on_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
278 | instance->reg_base, | ||
279 | instance->current_on_reg - instance->reg_base, tmp); | ||
280 | |||
281 | tmp = inw(instance->i_range_reg); // 0..20mA <= If exists. | ||
282 | tmp &= ~(0x1 << instance->ao_idx); | ||
283 | outw(tmp, instance->i_range_reg); | ||
284 | PDEBUG_REG("i_range_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
285 | instance->i_range_reg - instance->reg_base, tmp); | ||
286 | |||
287 | outw(0, (instance->ao_regs_shadows)->registry[instance->ao_idx]); | ||
288 | PDEBUG_REG("channel_reg outw(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
289 | (instance->ao_regs_shadows)->registry[instance->ao_idx] - | ||
290 | instance->reg_base, 0); | ||
291 | |||
292 | // Trigger output. | ||
293 | outw(0x0000, instance->sim_output_reg); | ||
294 | PDEBUG_REG("sim_output_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
295 | instance->reg_base, | ||
296 | instance->sim_output_reg - instance->reg_base, 0x0000); | ||
297 | outw(0xFFFF, instance->sim_output_reg); | ||
298 | PDEBUG_REG("sim_output_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
299 | instance->reg_base, | ||
300 | instance->sim_output_reg - instance->reg_base, 0xFFFF); | ||
301 | spin_unlock(instance->config_regs_lock); | ||
302 | spin_unlock(instance->ao_shadows_lock); | ||
303 | |||
304 | // Set status to 'none' | ||
305 | instance->status = ao_status_none; | ||
306 | spin_unlock(&instance->subdevice_lock); | ||
307 | |||
308 | //Signal reset if user is on wait. | ||
309 | wake_up_interruptible_all(&instance->wait_queue); | ||
310 | |||
311 | ME_SUBDEVICE_EXIT; | ||
312 | |||
313 | return ME_ERRNO_SUCCESS; | ||
314 | } | ||
315 | |||
316 | static int me1600_ao_io_single_config(me_subdevice_t * subdevice, | ||
317 | struct file *filep, | ||
318 | int channel, | ||
319 | int single_config, | ||
320 | int ref, | ||
321 | int trig_chan, | ||
322 | int trig_type, int trig_edge, int flags) | ||
323 | { | ||
324 | me1600_ao_subdevice_t *instance; | ||
325 | uint16_t tmp; | ||
326 | |||
327 | instance = (me1600_ao_subdevice_t *) subdevice; | ||
328 | |||
329 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
330 | |||
331 | // Checking parameters. | ||
332 | if (flags) { | ||
333 | PERROR | ||
334 | ("Invalid flag specified. Must be ME_IO_SINGLE_CONFIG_NO_FLAGS.\n"); | ||
335 | return ME_ERRNO_INVALID_FLAGS; | ||
336 | } | ||
337 | |||
338 | if (trig_edge != ME_TRIG_EDGE_NONE) { | ||
339 | PERROR | ||
340 | ("Invalid trigger edge. Software trigger has not edge. Must be ME_TRIG_EDGE_NONE\n"); | ||
341 | return ME_ERRNO_INVALID_TRIG_EDGE; | ||
342 | } | ||
343 | |||
344 | if (trig_type != ME_TRIG_TYPE_SW) { | ||
345 | PERROR("Invalid trigger edge. Must be ME_TRIG_TYPE_SW.\n"); | ||
346 | return ME_ERRNO_INVALID_TRIG_TYPE; | ||
347 | } | ||
348 | |||
349 | if ((trig_chan != ME_TRIG_CHAN_DEFAULT) | ||
350 | && (trig_chan != ME_TRIG_CHAN_SYNCHRONOUS)) { | ||
351 | PERROR("Invalid trigger channel specified.\n"); | ||
352 | return ME_ERRNO_INVALID_TRIG_CHAN; | ||
353 | } | ||
354 | |||
355 | if (ref != ME_REF_AO_GROUND) { | ||
356 | PERROR | ||
357 | ("Invalid reference. Analog outputs have to have got REF_AO_GROUND.\n"); | ||
358 | return ME_ERRNO_INVALID_REF; | ||
359 | } | ||
360 | |||
361 | if (((single_config + 1) > | ||
362 | (instance->u_ranges_count + instance->i_ranges_count)) | ||
363 | || (single_config < 0)) { | ||
364 | PERROR("Invalid range specified.\n"); | ||
365 | return ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
366 | } | ||
367 | |||
368 | if (channel) { | ||
369 | PERROR("Invalid channel specified.\n"); | ||
370 | return ME_ERRNO_INVALID_CHANNEL; | ||
371 | } | ||
372 | // Checking parameters - done. All is fine. Do config. | ||
373 | |||
374 | ME_SUBDEVICE_ENTER; | ||
375 | |||
376 | //Cancel control task | ||
377 | PDEBUG("Cancel control task. idx=%d\n", instance->ao_idx); | ||
378 | instance->ao_control_task_flag = 0; | ||
379 | cancel_delayed_work(&instance->ao_control_task); | ||
380 | |||
381 | spin_lock(&instance->subdevice_lock); | ||
382 | spin_lock(instance->ao_shadows_lock); | ||
383 | (instance->ao_regs_shadows)->trigger &= ~(0x1 << instance->ao_idx); //Cancell waiting for trigger. | ||
384 | (instance->ao_regs_shadows)->shadow[instance->ao_idx] = 0; | ||
385 | (instance->ao_regs_shadows)->mirror[instance->ao_idx] = 0; | ||
386 | |||
387 | spin_lock(instance->config_regs_lock); | ||
388 | switch (single_config) { | ||
389 | case 0: // 0V 10V | ||
390 | tmp = inw(instance->current_on_reg); // Volts | ||
391 | tmp &= ~(0x1 << instance->ao_idx); | ||
392 | outw(tmp, instance->current_on_reg); | ||
393 | PDEBUG_REG("current_on_reg outw(0x%lX+0x%lX)=0x%x\n", | ||
394 | instance->reg_base, | ||
395 | instance->current_on_reg - instance->reg_base, tmp); | ||
396 | |||
397 | // 0V | ||
398 | outw(0, | ||
399 | (instance->ao_regs_shadows)->registry[instance->ao_idx]); | ||
400 | PDEBUG_REG("channel_reg outw(0x%lX+0x%lX)=0x%x\n", | ||
401 | instance->reg_base, | ||
402 | (instance->ao_regs_shadows)->registry[instance-> | ||
403 | ao_idx] - | ||
404 | instance->reg_base, 0); | ||
405 | |||
406 | tmp = inw(instance->uni_bi_reg); // unipolar | ||
407 | tmp |= (0x1 << instance->ao_idx); | ||
408 | outw(tmp, instance->uni_bi_reg); | ||
409 | PDEBUG_REG("uni_bi_reg outw(0x%lX+0x%lX)=0x%x\n", | ||
410 | instance->reg_base, | ||
411 | instance->uni_bi_reg - instance->reg_base, tmp); | ||
412 | |||
413 | tmp = inw(instance->i_range_reg); // 0..20mA <= If exists. | ||
414 | tmp &= ~(0x1 << instance->ao_idx); | ||
415 | outw(tmp, instance->i_range_reg); | ||
416 | PDEBUG_REG("i_range_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
417 | instance->reg_base, | ||
418 | instance->i_range_reg - instance->reg_base, tmp); | ||
419 | break; | ||
420 | |||
421 | case 1: // -10V 10V | ||
422 | tmp = inw(instance->current_on_reg); // Volts | ||
423 | tmp &= ~(0x1 << instance->ao_idx); | ||
424 | outw(tmp, instance->current_on_reg); | ||
425 | PDEBUG_REG("current_on_reg outw(0x%lX+0x%lX)=0x%x\n", | ||
426 | instance->reg_base, | ||
427 | instance->current_on_reg - instance->reg_base, tmp); | ||
428 | |||
429 | // 0V | ||
430 | outw(0x0800, | ||
431 | (instance->ao_regs_shadows)->registry[instance->ao_idx]); | ||
432 | PDEBUG_REG("channel_reg outw(0x%lX+0x%lX)=0x%x\n", | ||
433 | instance->reg_base, | ||
434 | (instance->ao_regs_shadows)->registry[instance-> | ||
435 | ao_idx] - | ||
436 | instance->reg_base, 0x0800); | ||
437 | |||
438 | tmp = inw(instance->uni_bi_reg); // bipolar | ||
439 | tmp &= ~(0x1 << instance->ao_idx); | ||
440 | outw(tmp, instance->uni_bi_reg); | ||
441 | PDEBUG_REG("uni_bi_reg outw(0x%lX+0x%lX)=0x%x\n", | ||
442 | instance->reg_base, | ||
443 | instance->uni_bi_reg - instance->reg_base, tmp); | ||
444 | |||
445 | tmp = inw(instance->i_range_reg); // 0..20mA <= If exists. | ||
446 | tmp &= ~(0x1 << instance->ao_idx); | ||
447 | outw(tmp, instance->i_range_reg); | ||
448 | PDEBUG_REG("i_range_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
449 | instance->reg_base, | ||
450 | instance->i_range_reg - instance->reg_base, tmp); | ||
451 | break; | ||
452 | |||
453 | case 2: // 0mA 20mA | ||
454 | tmp = inw(instance->current_on_reg); // mAmpers | ||
455 | tmp |= (0x1 << instance->ao_idx); | ||
456 | outw(tmp, instance->current_on_reg); | ||
457 | PDEBUG_REG("current_on_reg outw(0x%lX+0x%lX)=0x%x\n", | ||
458 | instance->reg_base, | ||
459 | instance->current_on_reg - instance->reg_base, tmp); | ||
460 | |||
461 | tmp = inw(instance->i_range_reg); // 0..20mA | ||
462 | tmp &= ~(0x1 << instance->ao_idx); | ||
463 | outw(tmp, instance->i_range_reg); | ||
464 | PDEBUG_REG("i_range_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
465 | instance->reg_base, | ||
466 | instance->i_range_reg - instance->reg_base, tmp); | ||
467 | |||
468 | // 0mA | ||
469 | outw(0, | ||
470 | (instance->ao_regs_shadows)->registry[instance->ao_idx]); | ||
471 | PDEBUG_REG("channel_reg outw(0x%lX+0x%lX)=0x%x\n", | ||
472 | instance->reg_base, | ||
473 | (instance->ao_regs_shadows)->registry[instance-> | ||
474 | ao_idx] - | ||
475 | instance->reg_base, 0); | ||
476 | |||
477 | tmp = inw(instance->uni_bi_reg); // unipolar | ||
478 | tmp |= (0x1 << instance->ao_idx); | ||
479 | outw(tmp, instance->uni_bi_reg); | ||
480 | PDEBUG_REG("uni_bi_reg outw(0x%lX+0x%lX)=0x%x\n", | ||
481 | instance->reg_base, | ||
482 | instance->uni_bi_reg - instance->reg_base, tmp); | ||
483 | break; | ||
484 | |||
485 | case 3: // 4mA 20mA | ||
486 | tmp = inw(instance->current_on_reg); // mAmpers | ||
487 | tmp |= (0x1 << instance->ao_idx); | ||
488 | outw(tmp, instance->current_on_reg); | ||
489 | PDEBUG_REG("current_on_reg outw(0x%lX+0x%lX)=0x%x\n", | ||
490 | instance->reg_base, | ||
491 | instance->current_on_reg - instance->reg_base, tmp); | ||
492 | |||
493 | tmp = inw(instance->i_range_reg); // 4..20mA | ||
494 | tmp |= (0x1 << instance->ao_idx); | ||
495 | outw(tmp, instance->i_range_reg); | ||
496 | PDEBUG_REG("i_range_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
497 | instance->reg_base, | ||
498 | instance->i_range_reg - instance->reg_base, tmp); | ||
499 | |||
500 | // 4mA | ||
501 | outw(0, | ||
502 | (instance->ao_regs_shadows)->registry[instance->ao_idx]); | ||
503 | PDEBUG_REG("channel_reg outw(0x%lX+0x%lX)=0x%x\n", | ||
504 | instance->reg_base, | ||
505 | (instance->ao_regs_shadows)->registry[instance-> | ||
506 | ao_idx] - | ||
507 | instance->reg_base, 0); | ||
508 | |||
509 | tmp = inw(instance->uni_bi_reg); // unipolar | ||
510 | tmp |= (0x1 << instance->ao_idx); | ||
511 | outw(tmp, instance->uni_bi_reg); | ||
512 | PDEBUG_REG("uni_bi_reg outw(0x%lX+0x%lX)=0x%x\n", | ||
513 | instance->reg_base, | ||
514 | instance->uni_bi_reg - instance->reg_base, tmp); | ||
515 | break; | ||
516 | } | ||
517 | |||
518 | // Trigger output. | ||
519 | outw(0x0000, instance->sim_output_reg); | ||
520 | PDEBUG_REG("sim_output_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
521 | instance->reg_base, | ||
522 | instance->sim_output_reg - instance->reg_base, 0x0000); | ||
523 | outw(0xFFFF, instance->sim_output_reg); | ||
524 | PDEBUG_REG("sim_output_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
525 | instance->reg_base, | ||
526 | instance->sim_output_reg - instance->reg_base, 0xFFFF); | ||
527 | |||
528 | if (trig_chan == ME_TRIG_CHAN_DEFAULT) { // Individual triggering. | ||
529 | (instance->ao_regs_shadows)->synchronous &= | ||
530 | ~(0x1 << instance->ao_idx); | ||
531 | PDEBUG("Individual triggering.\n"); | ||
532 | } else if (trig_chan == ME_TRIG_CHAN_SYNCHRONOUS) { // Synchronous triggering. | ||
533 | (instance->ao_regs_shadows)->synchronous |= | ||
534 | (0x1 << instance->ao_idx); | ||
535 | PDEBUG("Synchronous triggering.\n"); | ||
536 | } | ||
537 | spin_unlock(instance->config_regs_lock); | ||
538 | spin_unlock(instance->ao_shadows_lock); | ||
539 | |||
540 | instance->status = ao_status_single_configured; | ||
541 | spin_unlock(&instance->subdevice_lock); | ||
542 | |||
543 | ME_SUBDEVICE_EXIT; | ||
544 | |||
545 | return ME_ERRNO_SUCCESS; | ||
546 | } | ||
547 | |||
548 | static int me1600_ao_io_single_read(me_subdevice_t * subdevice, | ||
549 | struct file *filep, | ||
550 | int channel, | ||
551 | int *value, int time_out, int flags) | ||
552 | { | ||
553 | me1600_ao_subdevice_t *instance; | ||
554 | unsigned long delay = 0; | ||
555 | unsigned long j = 0; | ||
556 | int err = ME_ERRNO_SUCCESS; | ||
557 | |||
558 | instance = (me1600_ao_subdevice_t *) subdevice; | ||
559 | |||
560 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
561 | |||
562 | if (flags & ~ME_IO_SINGLE_NONBLOCKING) { | ||
563 | PERROR("Invalid flag specified. %d\n", flags); | ||
564 | return ME_ERRNO_INVALID_FLAGS; | ||
565 | } | ||
566 | |||
567 | if (time_out < 0) { | ||
568 | PERROR("Invalid timeout specified.\n"); | ||
569 | return ME_ERRNO_INVALID_TIMEOUT; | ||
570 | } | ||
571 | |||
572 | if (channel) { | ||
573 | PERROR("Invalid channel specified.\n"); | ||
574 | return ME_ERRNO_INVALID_CHANNEL; | ||
575 | } | ||
576 | |||
577 | if ((!flags) && ((instance->ao_regs_shadows)->trigger & instance->ao_idx)) { //Blocking mode. Wait for software trigger. | ||
578 | if (time_out) { | ||
579 | delay = (time_out * HZ) / 1000; | ||
580 | if (delay == 0) | ||
581 | delay = 1; | ||
582 | } | ||
583 | |||
584 | j = jiffies; | ||
585 | |||
586 | //Only runing process will interrupt this call. Events are signaled when status change. This procedure has own timeout. | ||
587 | wait_event_interruptible_timeout(instance->wait_queue, | ||
588 | (!((instance-> | ||
589 | ao_regs_shadows)-> | ||
590 | trigger & instance-> | ||
591 | ao_idx)), | ||
592 | (delay) ? delay : LONG_MAX); | ||
593 | |||
594 | if (instance == ao_status_none) { // Reset was called. | ||
595 | PDEBUG("Single canceled.\n"); | ||
596 | err = ME_ERRNO_CANCELLED; | ||
597 | } | ||
598 | |||
599 | if (signal_pending(current)) { | ||
600 | PERROR("Wait on start of state machine interrupted.\n"); | ||
601 | err = ME_ERRNO_SIGNAL; | ||
602 | } | ||
603 | |||
604 | if ((delay) && ((jiffies - j) >= delay)) { | ||
605 | PDEBUG("Timeout reached.\n"); | ||
606 | err = ME_ERRNO_TIMEOUT; | ||
607 | } | ||
608 | } | ||
609 | |||
610 | *value = (instance->ao_regs_shadows)->mirror[instance->ao_idx]; | ||
611 | |||
612 | return err; | ||
613 | } | ||
614 | |||
615 | static int me1600_ao_io_single_write(me_subdevice_t * subdevice, | ||
616 | struct file *filep, | ||
617 | int channel, | ||
618 | int value, int time_out, int flags) | ||
619 | { | ||
620 | me1600_ao_subdevice_t *instance; | ||
621 | int err = ME_ERRNO_SUCCESS; | ||
622 | unsigned long delay = 0; | ||
623 | int i; | ||
624 | unsigned long j = 0; | ||
625 | |||
626 | instance = (me1600_ao_subdevice_t *) subdevice; | ||
627 | |||
628 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
629 | |||
630 | if (flags & | ||
631 | ~(ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS | | ||
632 | ME_IO_SINGLE_TYPE_WRITE_NONBLOCKING)) { | ||
633 | PERROR("Invalid flag specified.\n"); | ||
634 | return ME_ERRNO_INVALID_FLAGS; | ||
635 | } | ||
636 | |||
637 | if (time_out < 0) { | ||
638 | PERROR("Invalid timeout specified.\n"); | ||
639 | return ME_ERRNO_INVALID_TIMEOUT; | ||
640 | } | ||
641 | |||
642 | if (value & ~ME1600_AO_MAX_DATA) { | ||
643 | PERROR("Invalid value provided.\n"); | ||
644 | return ME_ERRNO_VALUE_OUT_OF_RANGE; | ||
645 | } | ||
646 | |||
647 | if (channel) { | ||
648 | PERROR("Invalid channel specified.\n"); | ||
649 | return ME_ERRNO_INVALID_CHANNEL; | ||
650 | } | ||
651 | |||
652 | ME_SUBDEVICE_ENTER; | ||
653 | |||
654 | //Cancel control task | ||
655 | PDEBUG("Cancel control task. idx=%d\n", instance->ao_idx); | ||
656 | instance->ao_control_task_flag = 0; | ||
657 | cancel_delayed_work(&instance->ao_control_task); | ||
658 | (instance->ao_regs_shadows)->trigger &= ~(0x1 << instance->ao_idx); //Cancell waiting for trigger. | ||
659 | |||
660 | if (time_out) { | ||
661 | delay = (time_out * HZ) / 1000; | ||
662 | |||
663 | if (delay == 0) | ||
664 | delay = 1; | ||
665 | } | ||
666 | //Write value. | ||
667 | spin_lock(instance->ao_shadows_lock); | ||
668 | (instance->ao_regs_shadows)->shadow[instance->ao_idx] = | ||
669 | (uint16_t) value; | ||
670 | |||
671 | if (flags & ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS) { // Trigger all outputs from synchronous list. | ||
672 | for (i = 0; i < (instance->ao_regs_shadows)->count; i++) { | ||
673 | if (((instance->ao_regs_shadows)->synchronous & (0x1 << i)) || (i == instance->ao_idx)) { // Set all from synchronous list to correct state. | ||
674 | PDEBUG | ||
675 | ("Synchronous triggering: output %d. idx=%d\n", | ||
676 | i, instance->ao_idx); | ||
677 | (instance->ao_regs_shadows)->mirror[i] = | ||
678 | (instance->ao_regs_shadows)->shadow[i]; | ||
679 | |||
680 | outw((instance->ao_regs_shadows)->shadow[i], | ||
681 | (instance->ao_regs_shadows)->registry[i]); | ||
682 | PDEBUG_REG | ||
683 | ("channel_reg outw(0x%lX+0x%lX)=0x%x\n", | ||
684 | instance->reg_base, | ||
685 | (instance->ao_regs_shadows)->registry[i] - | ||
686 | instance->reg_base, | ||
687 | (instance->ao_regs_shadows)->shadow[i]); | ||
688 | |||
689 | (instance->ao_regs_shadows)->trigger &= | ||
690 | ~(0x1 << i); | ||
691 | } | ||
692 | } | ||
693 | |||
694 | // Trigger output. | ||
695 | outw(0x0000, instance->sim_output_reg); | ||
696 | PDEBUG_REG("sim_output_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
697 | instance->reg_base, | ||
698 | instance->sim_output_reg - instance->reg_base, 0); | ||
699 | outw(0xFFFF, instance->sim_output_reg); | ||
700 | PDEBUG_REG("sim_output_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
701 | instance->reg_base, | ||
702 | instance->sim_output_reg - instance->reg_base, | ||
703 | 0xFFFF); | ||
704 | instance->status = ao_status_single_end; | ||
705 | } else { // Individual mode. | ||
706 | if ((instance->ao_regs_shadows)->synchronous & (0x1 << instance->ao_idx)) { // Put on synchronous start list. Set output as waiting for trigger. | ||
707 | PDEBUG("Add to synchronous list. idx=%d\n", | ||
708 | instance->ao_idx); | ||
709 | (instance->ao_regs_shadows)->trigger |= | ||
710 | (0x1 << instance->ao_idx); | ||
711 | instance->status = ao_status_single_run; | ||
712 | PDEBUG("Synchronous list: 0x%x.\n", | ||
713 | (instance->ao_regs_shadows)->synchronous); | ||
714 | } else { // Fired this one. | ||
715 | PDEBUG("Triggering. idx=%d\n", instance->ao_idx); | ||
716 | (instance->ao_regs_shadows)->mirror[instance->ao_idx] = | ||
717 | (instance->ao_regs_shadows)->shadow[instance-> | ||
718 | ao_idx]; | ||
719 | |||
720 | outw((instance->ao_regs_shadows)-> | ||
721 | shadow[instance->ao_idx], | ||
722 | (instance->ao_regs_shadows)->registry[instance-> | ||
723 | ao_idx]); | ||
724 | PDEBUG_REG("channel_reg outw(0x%lX+0x%lX)=0x%x\n", | ||
725 | instance->reg_base, | ||
726 | (instance->ao_regs_shadows)-> | ||
727 | registry[instance->ao_idx] - | ||
728 | instance->reg_base, | ||
729 | (instance->ao_regs_shadows)-> | ||
730 | shadow[instance->ao_idx]); | ||
731 | |||
732 | // Set output as triggered. | ||
733 | (instance->ao_regs_shadows)->trigger &= | ||
734 | ~(0x1 << instance->ao_idx); | ||
735 | |||
736 | // Trigger output. | ||
737 | outw(0x0000, instance->sim_output_reg); | ||
738 | PDEBUG_REG("sim_output_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
739 | instance->reg_base, | ||
740 | instance->sim_output_reg - | ||
741 | instance->reg_base, 0); | ||
742 | outw(0xFFFF, instance->sim_output_reg); | ||
743 | PDEBUG_REG("sim_output_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
744 | instance->reg_base, | ||
745 | instance->sim_output_reg - | ||
746 | instance->reg_base, 0xFFFF); | ||
747 | instance->status = ao_status_single_end; | ||
748 | } | ||
749 | } | ||
750 | spin_unlock(instance->ao_shadows_lock); | ||
751 | |||
752 | //Init control task | ||
753 | instance->timeout.delay = delay; | ||
754 | instance->timeout.start_time = jiffies; | ||
755 | instance->ao_control_task_flag = 1; | ||
756 | queue_delayed_work(instance->me1600_workqueue, | ||
757 | &instance->ao_control_task, 1); | ||
758 | |||
759 | if ((!flags & ME_IO_SINGLE_TYPE_WRITE_NONBLOCKING) && ((instance->ao_regs_shadows)->trigger & instance->ao_idx)) { //Blocking mode. Wait for software trigger. | ||
760 | if (time_out) { | ||
761 | delay = (time_out * HZ) / 1000; | ||
762 | if (delay == 0) | ||
763 | delay = 1; | ||
764 | } | ||
765 | |||
766 | j = jiffies; | ||
767 | |||
768 | //Only runing process will interrupt this call. Events are signaled when status change. This procedure has own timeout. | ||
769 | wait_event_interruptible_timeout(instance->wait_queue, | ||
770 | (!((instance-> | ||
771 | ao_regs_shadows)-> | ||
772 | trigger & instance-> | ||
773 | ao_idx)), | ||
774 | (delay) ? delay : LONG_MAX); | ||
775 | |||
776 | if (instance == ao_status_none) { | ||
777 | PDEBUG("Single canceled.\n"); | ||
778 | err = ME_ERRNO_CANCELLED; | ||
779 | } | ||
780 | if (signal_pending(current)) { | ||
781 | PERROR("Wait on start of state machine interrupted.\n"); | ||
782 | err = ME_ERRNO_SIGNAL; | ||
783 | } | ||
784 | |||
785 | if ((delay) && ((jiffies - j) >= delay)) { | ||
786 | PDEBUG("Timeout reached.\n"); | ||
787 | err = ME_ERRNO_TIMEOUT; | ||
788 | } | ||
789 | } | ||
790 | |||
791 | ME_SUBDEVICE_EXIT; | ||
792 | |||
793 | return err; | ||
794 | } | ||
795 | |||
796 | static int me1600_ao_query_number_channels(me_subdevice_t * subdevice, | ||
797 | int *number) | ||
798 | { | ||
799 | me1600_ao_subdevice_t *instance; | ||
800 | instance = (me1600_ao_subdevice_t *) subdevice; | ||
801 | |||
802 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
803 | |||
804 | *number = 1; //Every subdevice has only 1 channel. | ||
805 | return ME_ERRNO_SUCCESS; | ||
806 | } | ||
807 | |||
808 | static int me1600_ao_query_subdevice_type(me_subdevice_t * subdevice, int *type, | ||
809 | int *subtype) | ||
810 | { | ||
811 | me1600_ao_subdevice_t *instance; | ||
812 | instance = (me1600_ao_subdevice_t *) subdevice; | ||
813 | |||
814 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
815 | |||
816 | *type = ME_TYPE_AO; | ||
817 | *subtype = ME_SUBTYPE_SINGLE; | ||
818 | return ME_ERRNO_SUCCESS; | ||
819 | } | ||
820 | |||
821 | static int me1600_ao_query_subdevice_caps(me_subdevice_t * subdevice, int *caps) | ||
822 | { | ||
823 | PDEBUG("executed.\n"); | ||
824 | *caps = ME_CAPS_AO_TRIG_SYNCHRONOUS; | ||
825 | return ME_ERRNO_SUCCESS; | ||
826 | } | ||
827 | |||
828 | static int me1600_ao_query_range_by_min_max(me_subdevice_t * subdevice, | ||
829 | int unit, | ||
830 | int *min, | ||
831 | int *max, int *maxdata, int *range) | ||
832 | { | ||
833 | me1600_ao_subdevice_t *instance; | ||
834 | int i; | ||
835 | int r = -1; | ||
836 | int diff = 21E6; | ||
837 | |||
838 | instance = (me1600_ao_subdevice_t *) subdevice; | ||
839 | |||
840 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
841 | |||
842 | if ((*max - *min) < 0) { | ||
843 | PERROR("Invalid minimum and maximum values specified.\n"); | ||
844 | return ME_ERRNO_INVALID_MIN_MAX; | ||
845 | } | ||
846 | // Maximum ranges are slightly less then 10V or 20mA. For convenient we accepted this value as valid one. | ||
847 | if (unit == ME_UNIT_VOLT) { | ||
848 | for (i = 0; i < instance->u_ranges_count; i++) { | ||
849 | if ((instance->u_ranges[i].min <= *min) | ||
850 | && ((instance->u_ranges[i].max + 5000) >= *max)) { | ||
851 | if ((instance->u_ranges[i].max - | ||
852 | instance->u_ranges[i].min) - (*max - | ||
853 | *min) < | ||
854 | diff) { | ||
855 | r = i; | ||
856 | diff = | ||
857 | (instance->u_ranges[i].max - | ||
858 | instance->u_ranges[i].min) - | ||
859 | (*max - *min); | ||
860 | } | ||
861 | } | ||
862 | } | ||
863 | |||
864 | if (r < 0) { | ||
865 | PERROR("No matching range found.\n"); | ||
866 | return ME_ERRNO_NO_RANGE; | ||
867 | } else { | ||
868 | *min = instance->u_ranges[r].min; | ||
869 | *max = instance->u_ranges[r].max; | ||
870 | *range = r; | ||
871 | } | ||
872 | } else if (unit == ME_UNIT_AMPERE) { | ||
873 | for (i = 0; i < instance->i_ranges_count; i++) { | ||
874 | if ((instance->i_ranges[i].min <= *min) | ||
875 | && (instance->i_ranges[i].max + 5000 >= *max)) { | ||
876 | if ((instance->i_ranges[i].max - | ||
877 | instance->i_ranges[i].min) - (*max - | ||
878 | *min) < | ||
879 | diff) { | ||
880 | r = i; | ||
881 | diff = | ||
882 | (instance->i_ranges[i].max - | ||
883 | instance->i_ranges[i].min) - | ||
884 | (*max - *min); | ||
885 | } | ||
886 | } | ||
887 | } | ||
888 | |||
889 | if (r < 0) { | ||
890 | PERROR("No matching range found.\n"); | ||
891 | return ME_ERRNO_NO_RANGE; | ||
892 | } else { | ||
893 | *min = instance->i_ranges[r].min; | ||
894 | *max = instance->i_ranges[r].max; | ||
895 | *range = r + instance->u_ranges_count; | ||
896 | } | ||
897 | } else { | ||
898 | PERROR("Invalid physical unit specified.\n"); | ||
899 | return ME_ERRNO_INVALID_UNIT; | ||
900 | } | ||
901 | *maxdata = ME1600_AO_MAX_DATA; | ||
902 | |||
903 | return ME_ERRNO_SUCCESS; | ||
904 | } | ||
905 | |||
906 | static int me1600_ao_query_number_ranges(me_subdevice_t * subdevice, | ||
907 | int unit, int *count) | ||
908 | { | ||
909 | me1600_ao_subdevice_t *instance; | ||
910 | |||
911 | PDEBUG("executed.\n"); | ||
912 | |||
913 | instance = (me1600_ao_subdevice_t *) subdevice; | ||
914 | switch (unit) { | ||
915 | case ME_UNIT_VOLT: | ||
916 | *count = instance->u_ranges_count; | ||
917 | break; | ||
918 | case ME_UNIT_AMPERE: | ||
919 | *count = instance->i_ranges_count; | ||
920 | break; | ||
921 | case ME_UNIT_ANY: | ||
922 | *count = instance->u_ranges_count + instance->i_ranges_count; | ||
923 | break; | ||
924 | default: | ||
925 | *count = 0; | ||
926 | } | ||
927 | |||
928 | return ME_ERRNO_SUCCESS; | ||
929 | } | ||
930 | |||
931 | static int me1600_ao_query_range_info(me_subdevice_t * subdevice, | ||
932 | int range, | ||
933 | int *unit, | ||
934 | int *min, int *max, int *maxdata) | ||
935 | { | ||
936 | me1600_ao_subdevice_t *instance; | ||
937 | |||
938 | PDEBUG("executed.\n"); | ||
939 | |||
940 | instance = (me1600_ao_subdevice_t *) subdevice; | ||
941 | |||
942 | if (((range + 1) > | ||
943 | (instance->u_ranges_count + instance->i_ranges_count)) | ||
944 | || (range < 0)) { | ||
945 | PERROR("Invalid range number specified.\n"); | ||
946 | return ME_ERRNO_INVALID_RANGE; | ||
947 | } | ||
948 | |||
949 | if (range < instance->u_ranges_count) { | ||
950 | *unit = ME_UNIT_VOLT; | ||
951 | *min = instance->u_ranges[range].min; | ||
952 | *max = instance->u_ranges[range].max; | ||
953 | } else if (range < instance->u_ranges_count + instance->i_ranges_count) { | ||
954 | *unit = ME_UNIT_AMPERE; | ||
955 | *min = instance->i_ranges[range - instance->u_ranges_count].min; | ||
956 | *max = instance->i_ranges[range - instance->u_ranges_count].max; | ||
957 | } | ||
958 | *maxdata = ME1600_AO_MAX_DATA; | ||
959 | |||
960 | return ME_ERRNO_SUCCESS; | ||
961 | } | ||
962 | |||
963 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) | ||
964 | static void me1600_ao_work_control_task(void *subdevice) | ||
965 | #else | ||
966 | static void me1600_ao_work_control_task(struct work_struct *work) | ||
967 | #endif | ||
968 | { | ||
969 | me1600_ao_subdevice_t *instance; | ||
970 | int reschedule = 1; | ||
971 | int signaling = 0; | ||
972 | |||
973 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) | ||
974 | instance = (me1600_ao_subdevice_t *) subdevice; | ||
975 | #else | ||
976 | instance = | ||
977 | container_of((void *)work, me1600_ao_subdevice_t, ao_control_task); | ||
978 | #endif | ||
979 | |||
980 | PINFO("<%s: %ld> executed. idx=%d\n", __FUNCTION__, jiffies, | ||
981 | instance->ao_idx); | ||
982 | |||
983 | if (!((instance->ao_regs_shadows)->trigger & instance->ao_idx)) { // Output was triggerd. | ||
984 | // Signal the end. | ||
985 | signaling = 1; | ||
986 | reschedule = 0; | ||
987 | if (instance->status == ao_status_single_run) { | ||
988 | instance->status = ao_status_single_end; | ||
989 | } | ||
990 | |||
991 | } else if ((instance->timeout.delay) && ((jiffies - instance->timeout.start_time) >= instance->timeout.delay)) { // Timeout | ||
992 | PDEBUG("Timeout reached.\n"); | ||
993 | spin_lock(instance->ao_shadows_lock); | ||
994 | // Restore old settings. | ||
995 | PDEBUG("Write old value back to register.\n"); | ||
996 | (instance->ao_regs_shadows)->shadow[instance->ao_idx] = | ||
997 | (instance->ao_regs_shadows)->mirror[instance->ao_idx]; | ||
998 | |||
999 | outw((instance->ao_regs_shadows)->mirror[instance->ao_idx], | ||
1000 | (instance->ao_regs_shadows)->registry[instance->ao_idx]); | ||
1001 | PDEBUG_REG("channel_reg outw(0x%lX+0x%lX)=0x%x\n", | ||
1002 | instance->reg_base, | ||
1003 | (instance->ao_regs_shadows)->registry[instance-> | ||
1004 | ao_idx] - | ||
1005 | instance->reg_base, | ||
1006 | (instance->ao_regs_shadows)->mirror[instance-> | ||
1007 | ao_idx]); | ||
1008 | |||
1009 | //Remove from synchronous strt list. | ||
1010 | (instance->ao_regs_shadows)->trigger &= | ||
1011 | ~(0x1 << instance->ao_idx); | ||
1012 | if (instance->status == ao_status_none) { | ||
1013 | instance->status = ao_status_single_end; | ||
1014 | } | ||
1015 | spin_unlock(instance->ao_shadows_lock); | ||
1016 | |||
1017 | // Signal the end. | ||
1018 | signaling = 1; | ||
1019 | reschedule = 0; | ||
1020 | } | ||
1021 | |||
1022 | if (signaling) { //Signal it. | ||
1023 | wake_up_interruptible_all(&instance->wait_queue); | ||
1024 | } | ||
1025 | |||
1026 | if (instance->ao_control_task_flag && reschedule) { // Reschedule task | ||
1027 | queue_delayed_work(instance->me1600_workqueue, | ||
1028 | &instance->ao_control_task, 1); | ||
1029 | } else { | ||
1030 | PINFO("<%s> Ending control task.\n", __FUNCTION__); | ||
1031 | } | ||
1032 | |||
1033 | } | ||
diff --git a/drivers/staging/meilhaus/me1600_ao.h b/drivers/staging/meilhaus/me1600_ao.h new file mode 100644 index 000000000000..b82bf5a1676e --- /dev/null +++ b/drivers/staging/meilhaus/me1600_ao.h | |||
@@ -0,0 +1,132 @@ | |||
1 | /** | ||
2 | * @file me1600_ao.h | ||
3 | * | ||
4 | * @brief Meilhaus ME-1600 analog output subdevice class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME1600_AO_H_ | ||
28 | #define _ME1600_AO_H_ | ||
29 | |||
30 | # include <linux/version.h> | ||
31 | # include "mesubdevice.h" | ||
32 | |||
33 | # ifdef __KERNEL__ | ||
34 | |||
35 | # define ME1600_MAX_RANGES 2 /**< Specifies the maximum number of ranges in me1600_ao_subdevice_t::u_ranges und me1600_ao_subdevice_t::i_ranges. */ | ||
36 | |||
37 | /** | ||
38 | * @brief Defines a entry in the range table. | ||
39 | */ | ||
40 | typedef struct me1600_ao_range_entry { | ||
41 | int32_t min; | ||
42 | int32_t max; | ||
43 | } me1600_ao_range_entry_t; | ||
44 | |||
45 | typedef struct me1600_ao_timeout { | ||
46 | unsigned long start_time; | ||
47 | unsigned long delay; | ||
48 | } me1600_ao_timeout_t; | ||
49 | |||
50 | typedef struct me1600_ao_shadow { | ||
51 | int count; | ||
52 | unsigned long *registry; | ||
53 | uint16_t *shadow; | ||
54 | uint16_t *mirror; | ||
55 | uint16_t synchronous; /**< Synchronization list. */ | ||
56 | uint16_t trigger; /**< Synchronization flag. */ | ||
57 | } me1600_ao_shadow_t; | ||
58 | |||
59 | typedef enum ME1600_AO_STATUS { | ||
60 | ao_status_none = 0, | ||
61 | ao_status_single_configured, | ||
62 | ao_status_single_run, | ||
63 | ao_status_single_end, | ||
64 | ao_status_last | ||
65 | } ME1600_AO_STATUS; | ||
66 | |||
67 | /** | ||
68 | * @brief The ME-1600 analog output subdevice class. | ||
69 | */ | ||
70 | typedef struct me1600_ao_subdevice { | ||
71 | /* Inheritance */ | ||
72 | me_subdevice_t base; /**< The subdevice base class. */ | ||
73 | |||
74 | /* Attributes */ | ||
75 | int ao_idx; /**< The index of the analog output subdevice on the device. */ | ||
76 | |||
77 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
78 | spinlock_t *config_regs_lock; /**< Spin lock to protect configuration registers from concurrent access. */ | ||
79 | |||
80 | int u_ranges_count; /**< The number of voltage ranges available on this subdevice. */ | ||
81 | me1600_ao_range_entry_t u_ranges[ME1600_MAX_RANGES]; /**< Array holding the voltage ranges on this subdevice. */ | ||
82 | int i_ranges_count; /**< The number of current ranges available on this subdevice. */ | ||
83 | me1600_ao_range_entry_t i_ranges[ME1600_MAX_RANGES]; /**< Array holding the current ranges on this subdevice. */ | ||
84 | |||
85 | /* Registers */ | ||
86 | unsigned long uni_bi_reg; /**< Register for switching between unipoar and bipolar output mode. */ | ||
87 | unsigned long i_range_reg; /**< Register for switching between ranges. */ | ||
88 | unsigned long sim_output_reg; /**< Register used in order to update all channels simultaneously. */ | ||
89 | unsigned long current_on_reg; /**< Register enabling current output on the fourth subdevice. */ | ||
90 | # ifdef PDEBUG_REG | ||
91 | unsigned long reg_base; | ||
92 | # endif | ||
93 | |||
94 | ME1600_AO_STATUS status; | ||
95 | me1600_ao_shadow_t *ao_regs_shadows; /**< Addresses and shadows of output's registers. */ | ||
96 | spinlock_t *ao_shadows_lock; /**< Protects the shadow's struct. */ | ||
97 | int mode; /**< Mode in witch output should works. */ | ||
98 | wait_queue_head_t wait_queue; /**< Wait queue to put on tasks waiting for data to arrive. */ | ||
99 | me1600_ao_timeout_t timeout; /**< The timeout for start in blocking and non-blocking mode. */ | ||
100 | struct workqueue_struct *me1600_workqueue; | ||
101 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) | ||
102 | struct work_struct ao_control_task; | ||
103 | #else | ||
104 | struct delayed_work ao_control_task; | ||
105 | #endif | ||
106 | |||
107 | volatile int ao_control_task_flag; /**< Flag controling reexecuting of control task */ | ||
108 | } me1600_ao_subdevice_t; | ||
109 | |||
110 | /** | ||
111 | * @brief The constructor to generate a subdevice template instance. | ||
112 | * | ||
113 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
114 | * @param ao_idx The index of the analog output subdevice on the device. | ||
115 | * @param current Flag indicating that analog output with #ao_idx of 3 is capable of current output. | ||
116 | * @param config_regs_lock Pointer to spin lock protecting the configuration registers and from concurrent access. | ||
117 | * | ||
118 | * @return Pointer to new instance on success.\n | ||
119 | * NULL on error. | ||
120 | */ | ||
121 | me1600_ao_subdevice_t *me1600_ao_constructor(uint32_t reg_base, | ||
122 | unsigned int ao_idx, | ||
123 | int curr, | ||
124 | spinlock_t * config_regs_lock, | ||
125 | spinlock_t * ao_shadows_lock, | ||
126 | me1600_ao_shadow_t * | ||
127 | ao_regs_shadows, | ||
128 | struct workqueue_struct | ||
129 | *me1600_wq); | ||
130 | |||
131 | # endif //__KERNEL__ | ||
132 | #endif //_ME1600_AO_H_ | ||
diff --git a/drivers/staging/meilhaus/me1600_ao_reg.h b/drivers/staging/meilhaus/me1600_ao_reg.h new file mode 100644 index 000000000000..31e7800e8074 --- /dev/null +++ b/drivers/staging/meilhaus/me1600_ao_reg.h | |||
@@ -0,0 +1,66 @@ | |||
1 | /** | ||
2 | * @file me1600_ao_reg.h | ||
3 | * | ||
4 | * @brief ME-1600 analog output subdevice register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME1600_AO_REG_H_ | ||
28 | #define _ME1600_AO_REG_H_ | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | #define ME1600_CHANNEL_0_REG 0x00 /**< Register to set a digital value on channel 0. */ | ||
33 | #define ME1600_CHANNEL_1_REG 0x02 /**< Register to set a digital value on channel 1. */ | ||
34 | #define ME1600_CHANNEL_2_REG 0x04 /**< Register to set a digital value on channel 2. */ | ||
35 | #define ME1600_CHANNEL_3_REG 0x06 /**< Register to set a digital value on channel 3. */ | ||
36 | #define ME1600_CHANNEL_4_REG 0x08 /**< Register to set a digital value on channel 4. */ | ||
37 | #define ME1600_CHANNEL_5_REG 0x0A /**< Register to set a digital value on channel 5. */ | ||
38 | #define ME1600_CHANNEL_6_REG 0x0C /**< Register to set a digital value on channel 6. */ | ||
39 | #define ME1600_CHANNEL_7_REG 0x0E /**< Register to set a digital value on channel 7. */ | ||
40 | #define ME1600_CHANNEL_8_REG 0x10 /**< Register to set a digital value on channel 8. */ | ||
41 | #define ME1600_CHANNEL_9_REG 0x12 /**< Register to set a digital value on channel 9. */ | ||
42 | #define ME1600_CHANNEL_10_REG 0x14 /**< Register to set a digital value on channel 10. */ | ||
43 | #define ME1600_CHANNEL_11_REG 0x16 /**< Register to set a digital value on channel 11. */ | ||
44 | #define ME1600_CHANNEL_12_REG 0x18 /**< Register to set a digital value on channel 12. */ | ||
45 | #define ME1600_CHANNEL_13_REG 0x1A /**< Register to set a digital value on channel 13. */ | ||
46 | #define ME1600_CHANNEL_14_REG 0x1C /**< Register to set a digital value on channel 14. */ | ||
47 | #define ME1600_CHANNEL_15_REG 0x1E /**< Register to set a digital value on channel 15. */ | ||
48 | |||
49 | /* Every channel one bit: bipolar = 0, unipolar = 1 */ | ||
50 | #define ME1600_UNI_BI_REG 0x20 /**< Register to switch between unipolar and bipolar. */ | ||
51 | |||
52 | /* Every channel one bit (only lower 8 Bits): 0..20mA = 0, 4..20mA = 1 */ | ||
53 | #define ME1600_020_420_REG 0x22 /**< Register to switch between the two current ranges. */ | ||
54 | |||
55 | /* If a bit is set, the corresponding DAC (4 ports each) is | ||
56 | not set at the moment you write to an output of it. | ||
57 | Clearing the bit updates the port. */ | ||
58 | #define ME1600_SIM_OUTPUT_REG 0x24 /**< Register to update all channels of a subdevice simultaneously. */ | ||
59 | |||
60 | /* Current on/off (only lower 8 bits): off = 0, on = 1 */ | ||
61 | #define ME1600_CURRENT_ON_REG 0x26 /**< Register to swicht between voltage and current output. */ | ||
62 | |||
63 | #define ME1600_AO_MAX_DATA 0x0FFF /**< The maximum digital data accepted by an analog output channel. */ | ||
64 | |||
65 | #endif | ||
66 | #endif | ||
diff --git a/drivers/staging/meilhaus/me1600_device.c b/drivers/staging/meilhaus/me1600_device.c new file mode 100644 index 000000000000..3bc2cb1dc869 --- /dev/null +++ b/drivers/staging/meilhaus/me1600_device.c | |||
@@ -0,0 +1,261 @@ | |||
1 | /** | ||
2 | * @file me1600_device.c | ||
3 | * | ||
4 | * @brief ME-1600 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 "mesubdevice.h" | ||
49 | #include "me1600_device.h" | ||
50 | |||
51 | static void me1600_set_registry(me1600_device_t * subdevice, uint32_t reg_base); | ||
52 | static void me1600_destructor(struct me_device *device); | ||
53 | |||
54 | /** | ||
55 | * @brief Global variable. | ||
56 | * This is working queue for runing a separate atask that will be responsible for work status (start, stop, timeouts). | ||
57 | */ | ||
58 | static struct workqueue_struct *me1600_workqueue; | ||
59 | |||
60 | me_device_t *me1600_pci_constructor(struct pci_dev *pci_device) | ||
61 | { | ||
62 | int err; | ||
63 | me1600_device_t *me1600_device; | ||
64 | me_subdevice_t *subdevice; | ||
65 | unsigned int chip_idx; | ||
66 | int i; | ||
67 | |||
68 | PDEBUG("executed.\n"); | ||
69 | |||
70 | // Allocate structure for device instance. | ||
71 | me1600_device = kmalloc(sizeof(me1600_device_t), GFP_KERNEL); | ||
72 | |||
73 | if (!me1600_device) { | ||
74 | PERROR("Cannot get memory for device instance.\n"); | ||
75 | return NULL; | ||
76 | } | ||
77 | |||
78 | memset(me1600_device, 0, sizeof(me1600_device_t)); | ||
79 | |||
80 | // Initialize base class structure. | ||
81 | err = me_device_pci_init((me_device_t *) me1600_device, pci_device); | ||
82 | |||
83 | if (err) { | ||
84 | kfree(me1600_device); | ||
85 | PERROR("Cannot initialize device base class.\n"); | ||
86 | return NULL; | ||
87 | } | ||
88 | // Initialize spin lock . | ||
89 | spin_lock_init(&me1600_device->config_regs_lock); | ||
90 | spin_lock_init(&me1600_device->ao_shadows_lock); | ||
91 | |||
92 | // Get the number of analog output subdevices. | ||
93 | chip_idx = | ||
94 | me1600_versions_get_device_index(me1600_device->base.info.pci. | ||
95 | device_id); | ||
96 | |||
97 | // Create shadow instance. | ||
98 | me1600_device->ao_regs_shadows.count = | ||
99 | me1600_versions[chip_idx].ao_chips; | ||
100 | me1600_device->ao_regs_shadows.registry = | ||
101 | kmalloc(me1600_versions[chip_idx].ao_chips * sizeof(unsigned long), | ||
102 | GFP_KERNEL); | ||
103 | me1600_set_registry(me1600_device, | ||
104 | me1600_device->base.info.pci.reg_bases[2]); | ||
105 | me1600_device->ao_regs_shadows.shadow = | ||
106 | kmalloc(me1600_versions[chip_idx].ao_chips * sizeof(uint16_t), | ||
107 | GFP_KERNEL); | ||
108 | me1600_device->ao_regs_shadows.mirror = | ||
109 | kmalloc(me1600_versions[chip_idx].ao_chips * sizeof(uint16_t), | ||
110 | GFP_KERNEL); | ||
111 | |||
112 | // Create subdevice instances. | ||
113 | for (i = 0; i < me1600_versions[chip_idx].ao_chips; i++) { | ||
114 | subdevice = | ||
115 | (me_subdevice_t *) me1600_ao_constructor(me1600_device-> | ||
116 | base.info.pci. | ||
117 | reg_bases[2], i, | ||
118 | ((me1600_versions | ||
119 | [chip_idx].curr > | ||
120 | i) ? 1 : 0), | ||
121 | &me1600_device-> | ||
122 | config_regs_lock, | ||
123 | &me1600_device-> | ||
124 | ao_shadows_lock, | ||
125 | &me1600_device-> | ||
126 | ao_regs_shadows, | ||
127 | me1600_workqueue); | ||
128 | |||
129 | if (!subdevice) { | ||
130 | me_device_deinit((me_device_t *) me1600_device); | ||
131 | kfree(me1600_device); | ||
132 | PERROR("Cannot get memory for subdevice.\n"); | ||
133 | return NULL; | ||
134 | } | ||
135 | |||
136 | me_slist_add_subdevice_tail(&me1600_device->base.slist, | ||
137 | subdevice); | ||
138 | } | ||
139 | |||
140 | // Overwrite base class methods. | ||
141 | me1600_device->base.me_device_destructor = me1600_destructor; | ||
142 | |||
143 | return (me_device_t *) me1600_device; | ||
144 | } | ||
145 | |||
146 | static void me1600_destructor(struct me_device *device) | ||
147 | { | ||
148 | me1600_device_t *me1600_device = (me1600_device_t *) device; | ||
149 | PDEBUG("executed.\n"); | ||
150 | |||
151 | // Destroy shadow instance. | ||
152 | kfree(me1600_device->ao_regs_shadows.registry); | ||
153 | kfree(me1600_device->ao_regs_shadows.shadow); | ||
154 | kfree(me1600_device->ao_regs_shadows.mirror); | ||
155 | |||
156 | me_device_deinit((me_device_t *) me1600_device); | ||
157 | kfree(me1600_device); | ||
158 | } | ||
159 | |||
160 | static void me1600_set_registry(me1600_device_t * subdevice, uint32_t reg_base) | ||
161 | { // Create shadow structure. | ||
162 | if (subdevice->ao_regs_shadows.count >= 1) { | ||
163 | subdevice->ao_regs_shadows.registry[0] = | ||
164 | (unsigned long)(reg_base + ME1600_CHANNEL_0_REG); | ||
165 | } | ||
166 | if (subdevice->ao_regs_shadows.count >= 2) { | ||
167 | subdevice->ao_regs_shadows.registry[1] = | ||
168 | (unsigned long)(reg_base + ME1600_CHANNEL_1_REG); | ||
169 | } | ||
170 | if (subdevice->ao_regs_shadows.count >= 3) { | ||
171 | subdevice->ao_regs_shadows.registry[2] = | ||
172 | (unsigned long)(reg_base + ME1600_CHANNEL_2_REG); | ||
173 | } | ||
174 | if (subdevice->ao_regs_shadows.count >= 4) { | ||
175 | subdevice->ao_regs_shadows.registry[3] = | ||
176 | (unsigned long)(reg_base + ME1600_CHANNEL_3_REG); | ||
177 | } | ||
178 | if (subdevice->ao_regs_shadows.count >= 5) { | ||
179 | subdevice->ao_regs_shadows.registry[4] = | ||
180 | (unsigned long)(reg_base + ME1600_CHANNEL_4_REG); | ||
181 | } | ||
182 | if (subdevice->ao_regs_shadows.count >= 6) { | ||
183 | subdevice->ao_regs_shadows.registry[5] = | ||
184 | (unsigned long)(reg_base + ME1600_CHANNEL_5_REG); | ||
185 | } | ||
186 | if (subdevice->ao_regs_shadows.count >= 7) { | ||
187 | subdevice->ao_regs_shadows.registry[6] = | ||
188 | (unsigned long)(reg_base + ME1600_CHANNEL_6_REG); | ||
189 | } | ||
190 | if (subdevice->ao_regs_shadows.count >= 8) { | ||
191 | subdevice->ao_regs_shadows.registry[7] = | ||
192 | (unsigned long)(reg_base + ME1600_CHANNEL_7_REG); | ||
193 | } | ||
194 | if (subdevice->ao_regs_shadows.count >= 9) { | ||
195 | subdevice->ao_regs_shadows.registry[8] = | ||
196 | (unsigned long)(reg_base + ME1600_CHANNEL_8_REG); | ||
197 | } | ||
198 | if (subdevice->ao_regs_shadows.count >= 10) { | ||
199 | subdevice->ao_regs_shadows.registry[9] = | ||
200 | (unsigned long)(reg_base + ME1600_CHANNEL_9_REG); | ||
201 | } | ||
202 | if (subdevice->ao_regs_shadows.count >= 11) { | ||
203 | subdevice->ao_regs_shadows.registry[10] = | ||
204 | (unsigned long)(reg_base + ME1600_CHANNEL_10_REG); | ||
205 | } | ||
206 | if (subdevice->ao_regs_shadows.count >= 12) { | ||
207 | subdevice->ao_regs_shadows.registry[11] = | ||
208 | (unsigned long)(reg_base + ME1600_CHANNEL_11_REG); | ||
209 | } | ||
210 | if (subdevice->ao_regs_shadows.count >= 13) { | ||
211 | subdevice->ao_regs_shadows.registry[12] = | ||
212 | (unsigned long)(reg_base + ME1600_CHANNEL_12_REG); | ||
213 | } | ||
214 | if (subdevice->ao_regs_shadows.count >= 14) { | ||
215 | subdevice->ao_regs_shadows.registry[13] = | ||
216 | (unsigned long)(reg_base + ME1600_CHANNEL_13_REG); | ||
217 | } | ||
218 | if (subdevice->ao_regs_shadows.count >= 15) { | ||
219 | subdevice->ao_regs_shadows.registry[14] = | ||
220 | (unsigned long)(reg_base + ME1600_CHANNEL_14_REG); | ||
221 | } | ||
222 | if (subdevice->ao_regs_shadows.count >= 16) { | ||
223 | subdevice->ao_regs_shadows.registry[15] = | ||
224 | (unsigned long)(reg_base + ME1600_CHANNEL_15_REG); | ||
225 | } | ||
226 | if (subdevice->ao_regs_shadows.count > 16) { | ||
227 | PERROR("More than 16 outputs! (%d)\n", | ||
228 | subdevice->ao_regs_shadows.count); | ||
229 | } | ||
230 | } | ||
231 | |||
232 | // Init and exit of module. | ||
233 | |||
234 | static int __init me1600_init(void) | ||
235 | { | ||
236 | PDEBUG("executed\n."); | ||
237 | |||
238 | me1600_workqueue = create_singlethread_workqueue("me1600"); | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static void __exit me1600_exit(void) | ||
243 | { | ||
244 | PDEBUG("executed\n."); | ||
245 | |||
246 | flush_workqueue(me1600_workqueue); | ||
247 | destroy_workqueue(me1600_workqueue); | ||
248 | } | ||
249 | |||
250 | module_init(me1600_init); | ||
251 | module_exit(me1600_exit); | ||
252 | |||
253 | // Administrative stuff for modinfo. | ||
254 | MODULE_AUTHOR | ||
255 | ("Guenter Gebhardt <g.gebhardt@meilhaus.de> & Krzysztof Gantzke <k.gantzke@meilhaus.de>"); | ||
256 | MODULE_DESCRIPTION("Device Driver Module for ME-1600 Device"); | ||
257 | MODULE_SUPPORTED_DEVICE("Meilhaus ME-1600 Devices"); | ||
258 | MODULE_LICENSE("GPL"); | ||
259 | |||
260 | // Export the constructor. | ||
261 | EXPORT_SYMBOL(me1600_pci_constructor); | ||
diff --git a/drivers/staging/meilhaus/me1600_device.h b/drivers/staging/meilhaus/me1600_device.h new file mode 100644 index 000000000000..f7b231f73ac8 --- /dev/null +++ b/drivers/staging/meilhaus/me1600_device.h | |||
@@ -0,0 +1,101 @@ | |||
1 | /** | ||
2 | * @file me1600_device.h | ||
3 | * | ||
4 | * @brief ME-1600 device class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME1600_H | ||
28 | #define _ME1600_H | ||
29 | |||
30 | #include <linux/pci.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | |||
33 | #include "medevice.h" | ||
34 | #include "me1600_ao.h" | ||
35 | #include "me1600_ao_reg.h" | ||
36 | |||
37 | #ifdef __KERNEL__ | ||
38 | |||
39 | /** | ||
40 | * @brief Structure to store device capabilities. | ||
41 | */ | ||
42 | typedef struct me1600_version { | ||
43 | uint16_t device_id; /**< The PCI device id of the device. */ | ||
44 | unsigned int ao_chips; /**< The number of analog outputs on the device. */ | ||
45 | int curr; /**< Flag to identify amounts of current output. */ | ||
46 | } me1600_version_t; | ||
47 | |||
48 | /** | ||
49 | * @brief Defines for each ME-1600 device version its capabilities. | ||
50 | */ | ||
51 | static me1600_version_t me1600_versions[] = { | ||
52 | {PCI_DEVICE_ID_MEILHAUS_ME1600_4U, 4, 0}, | ||
53 | {PCI_DEVICE_ID_MEILHAUS_ME1600_8U, 8, 0}, | ||
54 | {PCI_DEVICE_ID_MEILHAUS_ME1600_12U, 12, 0}, | ||
55 | {PCI_DEVICE_ID_MEILHAUS_ME1600_16U, 16, 0}, | ||
56 | {PCI_DEVICE_ID_MEILHAUS_ME1600_16U_8I, 16, 8}, | ||
57 | {0} | ||
58 | }; | ||
59 | |||
60 | /**< Returns the number of entries in #me1600_versions. */ | ||
61 | #define ME1600_DEVICE_VERSIONS (sizeof(me1600_versions) / sizeof(me1600_version_t) - 1) | ||
62 | |||
63 | /** | ||
64 | * @brief Returns the index of the device entry in #me1600_versions. | ||
65 | * | ||
66 | * @param device_id The PCI device id of the device to query. | ||
67 | * @return The index of the device in #me1600_versions. | ||
68 | */ | ||
69 | static inline unsigned int me1600_versions_get_device_index(uint16_t device_id) | ||
70 | { | ||
71 | unsigned int i; | ||
72 | for (i = 0; i < ME1600_DEVICE_VERSIONS; i++) | ||
73 | if (me1600_versions[i].device_id == device_id) | ||
74 | break; | ||
75 | return i; | ||
76 | } | ||
77 | |||
78 | /** | ||
79 | * @brief The ME-1600 device class structure. | ||
80 | */ | ||
81 | typedef struct me1600_device { | ||
82 | me_device_t base; /**< The Meilhaus device base class. */ | ||
83 | spinlock_t config_regs_lock; /**< Protects the configuration registers. */ | ||
84 | |||
85 | me1600_ao_shadow_t ao_regs_shadows; /**< Addresses and shadows of output's registers. */ | ||
86 | spinlock_t ao_shadows_lock; /**< Protects the shadow's struct. */ | ||
87 | } me1600_device_t; | ||
88 | |||
89 | /** | ||
90 | * @brief The ME-1600 device class constructor. | ||
91 | * | ||
92 | * @param pci_device The pci device structure given by the PCI subsystem. | ||
93 | * | ||
94 | * @return On succes a new ME-1600 device instance. \n | ||
95 | * NULL on error. | ||
96 | */ | ||
97 | me_device_t *me1600_pci_constructor(struct pci_dev *pci_device) | ||
98 | __attribute__ ((weak)); | ||
99 | |||
100 | #endif | ||
101 | #endif | ||
diff --git a/drivers/staging/meilhaus/me4600_ai.c b/drivers/staging/meilhaus/me4600_ai.c new file mode 100644 index 000000000000..1a0de5dea277 --- /dev/null +++ b/drivers/staging/meilhaus/me4600_ai.c | |||
@@ -0,0 +1,3434 @@ | |||
1 | /** | ||
2 | * @file me4600_ai.c | ||
3 | * | ||
4 | * @brief ME-4000 analog input subdevice instance. | ||
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 | /* | ||
33 | * Includes | ||
34 | */ | ||
35 | #include <linux/module.h> | ||
36 | |||
37 | #include <linux/slab.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | #include <asm/io.h> | ||
40 | #include <asm/uaccess.h> | ||
41 | #include <linux/types.h> | ||
42 | #include <linux/interrupt.h> | ||
43 | #include <linux/delay.h> | ||
44 | |||
45 | #include "medefines.h" | ||
46 | #include "meinternal.h" | ||
47 | #include "meerror.h" | ||
48 | #include "medebug.h" | ||
49 | #include "meids.h" | ||
50 | |||
51 | #include "me4600_reg.h" | ||
52 | #include "me4600_ai_reg.h" | ||
53 | #include "me4600_ai.h" | ||
54 | |||
55 | /* | ||
56 | * Declarations (local) | ||
57 | */ | ||
58 | |||
59 | static void me4600_ai_destructor(struct me_subdevice *subdevice); | ||
60 | static int me4600_ai_io_reset_subdevice(me_subdevice_t * subdevice, | ||
61 | struct file *filep, int flags); | ||
62 | |||
63 | static int me4600_ai_io_single_config(me_subdevice_t * subdevice, | ||
64 | struct file *filep, | ||
65 | int channel, | ||
66 | int single_config, | ||
67 | int ref, | ||
68 | int trig_chan, | ||
69 | int trig_type, int trig_edge, int flags); | ||
70 | |||
71 | static int me4600_ai_io_single_read(me_subdevice_t * subdevice, | ||
72 | struct file *filep, | ||
73 | int channel, | ||
74 | int *value, int time_out, int flags); | ||
75 | |||
76 | static int me4600_ai_io_stream_config(me_subdevice_t * subdevice, | ||
77 | struct file *filep, | ||
78 | meIOStreamConfig_t * config_list, | ||
79 | int count, | ||
80 | meIOStreamTrigger_t * trigger, | ||
81 | int fifo_irq_threshold, int flags); | ||
82 | static int me4600_ai_io_stream_read(me_subdevice_t * subdevice, | ||
83 | struct file *filep, | ||
84 | int read_mode, | ||
85 | int *values, int *count, int flags); | ||
86 | static int me4600_ai_io_stream_new_values(me_subdevice_t * subdevice, | ||
87 | struct file *filep, | ||
88 | int time_out, int *count, int flags); | ||
89 | static int inline me4600_ai_io_stream_read_get_value(me4600_ai_subdevice_t * | ||
90 | instance, int *values, | ||
91 | const int count, | ||
92 | const int flags); | ||
93 | |||
94 | static int me4600_ai_io_stream_start(me_subdevice_t * subdevice, | ||
95 | struct file *filep, | ||
96 | int start_mode, int time_out, int flags); | ||
97 | static int me4600_ai_io_stream_stop(me_subdevice_t * subdevice, | ||
98 | struct file *filep, | ||
99 | int stop_mode, int flags); | ||
100 | static int me4600_ai_io_stream_status(me_subdevice_t * subdevice, | ||
101 | struct file *filep, | ||
102 | int wait, | ||
103 | int *status, int *values, int flags); | ||
104 | |||
105 | static int me4600_ai_query_range_by_min_max(me_subdevice_t * subdevice, | ||
106 | int unit, | ||
107 | int *min, | ||
108 | int *max, int *maxdata, int *range); | ||
109 | static int me4600_ai_query_number_ranges(me_subdevice_t * subdevice, | ||
110 | int unit, int *count); | ||
111 | static int me4600_ai_query_range_info(me_subdevice_t * subdevice, | ||
112 | int range, | ||
113 | int *unit, | ||
114 | int *min, int *max, int *maxdata); | ||
115 | static int me4600_ai_query_timer(me_subdevice_t * subdevice, | ||
116 | int timer, | ||
117 | int *base_frequency, | ||
118 | long long *min_ticks, long long *max_ticks); | ||
119 | static int me4600_ai_query_number_channels(me_subdevice_t * subdevice, | ||
120 | int *number); | ||
121 | static int me4600_ai_query_subdevice_type(me_subdevice_t * subdevice, | ||
122 | int *type, int *subtype); | ||
123 | static int me4600_ai_query_subdevice_caps(me_subdevice_t * subdevice, | ||
124 | int *caps); | ||
125 | static int me4600_ai_query_subdevice_caps_args(struct me_subdevice *subdevice, | ||
126 | int cap, int *args, int count); | ||
127 | |||
128 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) | ||
129 | static irqreturn_t me4600_ai_isr(int irq, void *dev_id); | ||
130 | #else | ||
131 | static irqreturn_t me4600_ai_isr(int irq, void *dev_id, struct pt_regs *regs); | ||
132 | #endif | ||
133 | |||
134 | static int ai_mux_toggler(me4600_ai_subdevice_t * subdevice); | ||
135 | |||
136 | /** Immidiate stop. | ||
137 | * Reset all IRQ's sources. (block laches) | ||
138 | * Preserve FIFO | ||
139 | */ | ||
140 | static int ai_stop_immediately(me4600_ai_subdevice_t * instance); | ||
141 | |||
142 | /** Immidiate stop. | ||
143 | * Reset all IRQ's sources. (block laches) | ||
144 | * Reset data FIFO | ||
145 | */ | ||
146 | void inline ai_stop_isr(me4600_ai_subdevice_t * instance); | ||
147 | |||
148 | /** Interrupt logics. | ||
149 | * Read datas | ||
150 | * Reset latches | ||
151 | */ | ||
152 | void ai_limited_isr(me4600_ai_subdevice_t * instance, const uint32_t irq_status, | ||
153 | const uint32_t ctrl_status); | ||
154 | void ai_infinite_isr(me4600_ai_subdevice_t * instance, | ||
155 | const uint32_t irq_status, const uint32_t ctrl_status); | ||
156 | |||
157 | /** Last chunck of datas. We must reschedule sample counter. | ||
158 | * Leaving SC_RELOAD doesn't do any harm, but in some bad case can make extra interrupts. | ||
159 | * When threshold is wrongly set some IRQ are lost.(!!!) | ||
160 | */ | ||
161 | void inline ai_reschedule_SC(me4600_ai_subdevice_t * instance); | ||
162 | |||
163 | /** Read datas from FIFO and copy them to buffer */ | ||
164 | static int inline ai_read_data(me4600_ai_subdevice_t * instance, | ||
165 | const int count); | ||
166 | |||
167 | /** Copy rest of data from fifo to circular buffer.*/ | ||
168 | static int inline ai_read_data_pooling(me4600_ai_subdevice_t * instance); | ||
169 | |||
170 | /** Set ISM to next state for infinite data aqusation mode*/ | ||
171 | void inline ai_infinite_ISM(me4600_ai_subdevice_t * instance); | ||
172 | |||
173 | /** Set ISM to next state for define amount of data aqusation mode*/ | ||
174 | void inline ai_limited_ISM(me4600_ai_subdevice_t * instance, | ||
175 | uint32_t irq_status); | ||
176 | |||
177 | /** Set ISM to next stage for limited mode */ | ||
178 | void inline ai_data_acquisition_logic(me4600_ai_subdevice_t * instance); | ||
179 | |||
180 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) | ||
181 | static void me4600_ai_work_control_task(void *subdevice); | ||
182 | #else | ||
183 | static void me4600_ai_work_control_task(struct work_struct *work); | ||
184 | #endif | ||
185 | |||
186 | /* Definitions | ||
187 | */ | ||
188 | |||
189 | me4600_ai_subdevice_t *me4600_ai_constructor(uint32_t reg_base, | ||
190 | unsigned int channels, | ||
191 | unsigned int ranges, | ||
192 | int isolated, | ||
193 | int sh, | ||
194 | int irq, | ||
195 | spinlock_t * ctrl_reg_lock, | ||
196 | struct workqueue_struct *me4600_wq) | ||
197 | { | ||
198 | me4600_ai_subdevice_t *subdevice; | ||
199 | int err; | ||
200 | unsigned int i; | ||
201 | |||
202 | PDEBUG("executed. idx=0\n"); | ||
203 | |||
204 | // Allocate memory for subdevice instance. | ||
205 | subdevice = kmalloc(sizeof(me4600_ai_subdevice_t), GFP_KERNEL); | ||
206 | |||
207 | if (!subdevice) { | ||
208 | PERROR("Cannot get memory for subdevice instance.\n"); | ||
209 | return NULL; | ||
210 | } | ||
211 | |||
212 | memset(subdevice, 0, sizeof(me4600_ai_subdevice_t)); | ||
213 | |||
214 | // Initialize subdevice base class. | ||
215 | err = me_subdevice_init(&subdevice->base); | ||
216 | |||
217 | if (err) { | ||
218 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
219 | kfree(subdevice); | ||
220 | return NULL; | ||
221 | } | ||
222 | // Initialize spin locks. | ||
223 | spin_lock_init(&subdevice->subdevice_lock); | ||
224 | |||
225 | subdevice->ctrl_reg_lock = ctrl_reg_lock; | ||
226 | |||
227 | // Initialize circular buffer. | ||
228 | subdevice->circ_buf.mask = ME4600_AI_CIRC_BUF_COUNT - 1; | ||
229 | |||
230 | subdevice->circ_buf.buf = | ||
231 | (void *)__get_free_pages(GFP_KERNEL, ME4600_AI_CIRC_BUF_SIZE_ORDER); | ||
232 | PDEBUG("circ_buf = %p size=%ld\n", subdevice->circ_buf.buf, | ||
233 | ME4600_AI_CIRC_BUF_SIZE); | ||
234 | |||
235 | if (!subdevice->circ_buf.buf) { | ||
236 | PERROR("Cannot get circular buffer.\n"); | ||
237 | me_subdevice_deinit((me_subdevice_t *) subdevice); | ||
238 | kfree(subdevice); | ||
239 | return NULL; | ||
240 | } | ||
241 | |||
242 | memset(subdevice->circ_buf.buf, 0, ME4600_AI_CIRC_BUF_SIZE); | ||
243 | subdevice->circ_buf.head = 0; | ||
244 | subdevice->circ_buf.tail = 0; | ||
245 | subdevice->status = ai_status_none; | ||
246 | |||
247 | // Initialize wait queue. | ||
248 | init_waitqueue_head(&subdevice->wait_queue); | ||
249 | |||
250 | // Save the number of channels. | ||
251 | subdevice->channels = channels; | ||
252 | |||
253 | /* Initialize the single config entries to reset values */ | ||
254 | for (i = 0; i < channels; i++) { | ||
255 | subdevice->single_config[i].status = ME_SINGLE_CHANNEL_NOT_CONFIGURED; //not configured | ||
256 | } | ||
257 | |||
258 | // Save if isolated device. | ||
259 | subdevice->isolated = isolated; | ||
260 | |||
261 | // Save if sample and hold is available. | ||
262 | subdevice->sh = sh; | ||
263 | |||
264 | // Set stream config to not configured state. | ||
265 | subdevice->fifo_irq_threshold = 0; | ||
266 | subdevice->data_required = 0; | ||
267 | subdevice->chan_list_len = 0; | ||
268 | |||
269 | // Initialize registers addresses. | ||
270 | subdevice->ctrl_reg = reg_base + ME4600_AI_CTRL_REG; | ||
271 | subdevice->status_reg = reg_base + ME4600_AI_STATUS_REG; | ||
272 | subdevice->channel_list_reg = reg_base + ME4600_AI_CHANNEL_LIST_REG; | ||
273 | subdevice->data_reg = reg_base + ME4600_AI_DATA_REG; | ||
274 | subdevice->chan_timer_reg = reg_base + ME4600_AI_CHAN_TIMER_REG; | ||
275 | subdevice->chan_pre_timer_reg = reg_base + ME4600_AI_CHAN_PRE_TIMER_REG; | ||
276 | subdevice->scan_timer_low_reg = reg_base + ME4600_AI_SCAN_TIMER_LOW_REG; | ||
277 | subdevice->scan_timer_high_reg = | ||
278 | reg_base + ME4600_AI_SCAN_TIMER_HIGH_REG; | ||
279 | subdevice->scan_pre_timer_low_reg = | ||
280 | reg_base + ME4600_AI_SCAN_PRE_TIMER_LOW_REG; | ||
281 | subdevice->scan_pre_timer_high_reg = | ||
282 | reg_base + ME4600_AI_SCAN_PRE_TIMER_HIGH_REG; | ||
283 | subdevice->start_reg = reg_base + ME4600_AI_START_REG; | ||
284 | subdevice->irq_status_reg = reg_base + ME4600_IRQ_STATUS_REG; | ||
285 | subdevice->sample_counter_reg = reg_base + ME4600_AI_SAMPLE_COUNTER_REG; | ||
286 | #ifdef MEDEBUG_DEBUG_REG | ||
287 | subdevice->reg_base = reg_base; | ||
288 | #endif | ||
289 | |||
290 | // Initialize ranges. | ||
291 | subdevice->ranges_len = ranges; | ||
292 | subdevice->ranges[0].min = -10E6; | ||
293 | subdevice->ranges[0].max = 9999694; | ||
294 | |||
295 | subdevice->ranges[1].min = 0; | ||
296 | subdevice->ranges[1].max = 9999847; | ||
297 | |||
298 | subdevice->ranges[2].min = -25E5; | ||
299 | subdevice->ranges[2].max = 2499923; | ||
300 | |||
301 | subdevice->ranges[3].min = 0; | ||
302 | subdevice->ranges[3].max = 2499961; | ||
303 | |||
304 | // We have to switch the mux in order to get it work correctly. | ||
305 | ai_mux_toggler(subdevice); | ||
306 | |||
307 | // Register interrupt service routine. | ||
308 | subdevice->irq = irq; | ||
309 | if (request_irq(subdevice->irq, me4600_ai_isr, | ||
310 | #ifdef IRQF_DISABLED | ||
311 | IRQF_DISABLED | IRQF_SHARED, | ||
312 | #else | ||
313 | SA_INTERRUPT | SA_SHIRQ, | ||
314 | #endif | ||
315 | ME4600_NAME, subdevice)) { | ||
316 | PERROR("Cannot register interrupt service routine.\n"); | ||
317 | me_subdevice_deinit((me_subdevice_t *) subdevice); | ||
318 | free_pages((unsigned long)subdevice->circ_buf.buf, | ||
319 | ME4600_AI_CIRC_BUF_SIZE_ORDER); | ||
320 | subdevice->circ_buf.buf = NULL; | ||
321 | kfree(subdevice); | ||
322 | return NULL; | ||
323 | } | ||
324 | PINFO("Registered irq=%d.\n", subdevice->irq); | ||
325 | |||
326 | // Override base class methods. | ||
327 | subdevice->base.me_subdevice_destructor = me4600_ai_destructor; | ||
328 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
329 | me4600_ai_io_reset_subdevice; | ||
330 | subdevice->base.me_subdevice_io_single_config = | ||
331 | me4600_ai_io_single_config; | ||
332 | subdevice->base.me_subdevice_io_single_read = me4600_ai_io_single_read; | ||
333 | subdevice->base.me_subdevice_io_stream_config = | ||
334 | me4600_ai_io_stream_config; | ||
335 | subdevice->base.me_subdevice_io_stream_new_values = | ||
336 | me4600_ai_io_stream_new_values; | ||
337 | subdevice->base.me_subdevice_io_stream_read = me4600_ai_io_stream_read; | ||
338 | subdevice->base.me_subdevice_io_stream_start = | ||
339 | me4600_ai_io_stream_start; | ||
340 | subdevice->base.me_subdevice_io_stream_status = | ||
341 | me4600_ai_io_stream_status; | ||
342 | subdevice->base.me_subdevice_io_stream_stop = me4600_ai_io_stream_stop; | ||
343 | subdevice->base.me_subdevice_query_number_channels = | ||
344 | me4600_ai_query_number_channels; | ||
345 | subdevice->base.me_subdevice_query_subdevice_type = | ||
346 | me4600_ai_query_subdevice_type; | ||
347 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
348 | me4600_ai_query_subdevice_caps; | ||
349 | subdevice->base.me_subdevice_query_subdevice_caps_args = | ||
350 | me4600_ai_query_subdevice_caps_args; | ||
351 | subdevice->base.me_subdevice_query_range_by_min_max = | ||
352 | me4600_ai_query_range_by_min_max; | ||
353 | subdevice->base.me_subdevice_query_number_ranges = | ||
354 | me4600_ai_query_number_ranges; | ||
355 | subdevice->base.me_subdevice_query_range_info = | ||
356 | me4600_ai_query_range_info; | ||
357 | subdevice->base.me_subdevice_query_timer = me4600_ai_query_timer; | ||
358 | |||
359 | // Prepare work queue. | ||
360 | subdevice->me4600_workqueue = me4600_wq; | ||
361 | |||
362 | /* workqueue API changed in kernel 2.6.20 */ | ||
363 | #if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ) | ||
364 | INIT_WORK(&subdevice->ai_control_task, me4600_ai_work_control_task, | ||
365 | (void *)subdevice); | ||
366 | #else | ||
367 | INIT_DELAYED_WORK(&subdevice->ai_control_task, | ||
368 | me4600_ai_work_control_task); | ||
369 | #endif | ||
370 | |||
371 | return subdevice; | ||
372 | } | ||
373 | |||
374 | static void me4600_ai_destructor(struct me_subdevice *subdevice) | ||
375 | { | ||
376 | me4600_ai_subdevice_t *instance; | ||
377 | |||
378 | instance = (me4600_ai_subdevice_t *) subdevice; | ||
379 | |||
380 | PDEBUG("executed. idx=0\n"); | ||
381 | |||
382 | instance->ai_control_task_flag = 0; | ||
383 | // Reset subdevice to asure clean exit. | ||
384 | me4600_ai_io_reset_subdevice(subdevice, NULL, | ||
385 | ME_IO_RESET_SUBDEVICE_NO_FLAGS); | ||
386 | |||
387 | // Remove any tasks from work queue. This is paranoic because it was done allready in reset(). | ||
388 | if (!cancel_delayed_work(&instance->ai_control_task)) { //Wait 2 ticks to be sure that control task is removed from queue. | ||
389 | set_current_state(TASK_INTERRUPTIBLE); | ||
390 | schedule_timeout(2); | ||
391 | } | ||
392 | |||
393 | free_irq(instance->irq, instance); | ||
394 | free_pages((unsigned long)instance->circ_buf.buf, | ||
395 | ME4600_AI_CIRC_BUF_SIZE_ORDER); | ||
396 | me_subdevice_deinit(&instance->base); | ||
397 | kfree(instance); | ||
398 | } | ||
399 | |||
400 | static int me4600_ai_io_reset_subdevice(me_subdevice_t * subdevice, | ||
401 | struct file *filep, int flags) | ||
402 | { | ||
403 | me4600_ai_subdevice_t *instance; | ||
404 | int err = ME_ERRNO_SUCCESS; | ||
405 | volatile uint32_t ctrl; | ||
406 | unsigned long status; | ||
407 | const int timeout = HZ / 10; //100ms | ||
408 | int i; | ||
409 | |||
410 | PDEBUG("executed. idx=0\n"); | ||
411 | |||
412 | if (flags) { | ||
413 | PERROR("Invalid flag specified.\n"); | ||
414 | return ME_ERRNO_INVALID_FLAGS; | ||
415 | } | ||
416 | |||
417 | instance = (me4600_ai_subdevice_t *) subdevice; | ||
418 | |||
419 | ME_SUBDEVICE_ENTER; | ||
420 | |||
421 | instance->ai_control_task_flag = 0; | ||
422 | instance->status = ai_status_none; | ||
423 | |||
424 | for (i = 0; i <= timeout; i++) { | ||
425 | spin_lock_irqsave(instance->ctrl_reg_lock, status); | ||
426 | ctrl = inl(instance->ctrl_reg); | ||
427 | //Stop DMA | ||
428 | ctrl &= ~ME4600_AI_CTRL_RPCI_FIFO; | ||
429 | // Stop all actions. No conditions! | ||
430 | ctrl &= ~ME4600_AI_CTRL_BIT_STOP; | ||
431 | ctrl |= ME4600_AI_CTRL_BIT_IMMEDIATE_STOP; | ||
432 | |||
433 | outl(ctrl, instance->ctrl_reg); | ||
434 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
435 | instance->reg_base, | ||
436 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
437 | spin_unlock_irqrestore(instance->ctrl_reg_lock, status); | ||
438 | |||
439 | if (!(inl(instance->status_reg) & ME4600_AI_STATUS_BIT_FSM)) | ||
440 | break; | ||
441 | |||
442 | set_current_state(TASK_INTERRUPTIBLE); | ||
443 | schedule_timeout(1); | ||
444 | } | ||
445 | |||
446 | if (i > timeout) { | ||
447 | PERROR("FSM is still busy.\n"); | ||
448 | ME_SUBDEVICE_EXIT; | ||
449 | return ME_ERRNO_INTERNAL; | ||
450 | } | ||
451 | |||
452 | spin_lock_irqsave(instance->ctrl_reg_lock, status); | ||
453 | ctrl = inl(instance->ctrl_reg); | ||
454 | // Clear all features. Dissable interrupts. | ||
455 | ctrl &= ~(ME4600_AI_CTRL_BIT_STOP | ||
456 | | ME4600_AI_CTRL_BIT_LE_IRQ | ||
457 | | ME4600_AI_CTRL_BIT_HF_IRQ | ME4600_AI_CTRL_BIT_SC_IRQ); | ||
458 | ctrl |= (ME4600_AI_CTRL_BIT_IMMEDIATE_STOP | ||
459 | | ME4600_AI_CTRL_BIT_LE_IRQ_RESET | ||
460 | | ME4600_AI_CTRL_BIT_HF_IRQ_RESET | ||
461 | | ME4600_AI_CTRL_BIT_SC_IRQ_RESET); | ||
462 | |||
463 | outl(ctrl, instance->ctrl_reg); | ||
464 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
465 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
466 | spin_unlock_irqrestore(instance->ctrl_reg_lock, status); | ||
467 | |||
468 | outl(ME4600_AI_MIN_CHAN_TICKS - 1, instance->chan_timer_reg); | ||
469 | PDEBUG_REG("chan_timer_reg outl(0x%lX+0x%lX)=0x%llx\n", | ||
470 | instance->reg_base, | ||
471 | instance->chan_timer_reg - instance->reg_base, | ||
472 | ME4600_AI_MIN_CHAN_TICKS); | ||
473 | outl(ME4600_AI_MIN_ACQ_TICKS - 1, instance->chan_pre_timer_reg); | ||
474 | PDEBUG_REG("chan_pre_timer_reg outl(0x%lX+0x%lX)=0x%llx\n", | ||
475 | instance->reg_base, | ||
476 | instance->chan_pre_timer_reg - instance->reg_base, | ||
477 | ME4600_AI_MIN_ACQ_TICKS); | ||
478 | outl(0, instance->scan_timer_low_reg); | ||
479 | PDEBUG_REG("scan_timer_low_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
480 | instance->reg_base, | ||
481 | instance->scan_timer_low_reg - instance->reg_base, 0); | ||
482 | outl(0, instance->scan_timer_high_reg); | ||
483 | PDEBUG_REG("scan_timer_high_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
484 | instance->reg_base, | ||
485 | instance->scan_timer_high_reg - instance->reg_base, 0); | ||
486 | outl(0, instance->scan_pre_timer_low_reg); | ||
487 | PDEBUG_REG("scan_pre_timer_low_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
488 | instance->reg_base, | ||
489 | instance->scan_pre_timer_low_reg - instance->reg_base, 0); | ||
490 | outl(0, instance->scan_pre_timer_high_reg); | ||
491 | PDEBUG_REG("scan_pre_timer_high_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
492 | instance->reg_base, | ||
493 | instance->scan_pre_timer_high_reg - instance->reg_base, 0); | ||
494 | outl(0xEFFFFFFF, instance->sample_counter_reg); | ||
495 | PDEBUG_REG("sample_counter_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
496 | instance->reg_base, | ||
497 | instance->sample_counter_reg - instance->reg_base, | ||
498 | 0xEFFFFFFF); | ||
499 | |||
500 | instance->circ_buf.head = 0; | ||
501 | instance->circ_buf.tail = 0; | ||
502 | |||
503 | instance->fifo_irq_threshold = 0; | ||
504 | instance->data_required = 0; | ||
505 | instance->chan_list_len = 0; | ||
506 | |||
507 | // Initialize the single config entries to reset values. | ||
508 | for (i = 0; i < instance->channels; i++) { | ||
509 | instance->single_config[i].status = | ||
510 | ME_SINGLE_CHANNEL_NOT_CONFIGURED; | ||
511 | } | ||
512 | instance->status = ai_status_none; | ||
513 | |||
514 | //Signal reset if user is on wait. | ||
515 | wake_up_interruptible_all(&instance->wait_queue); | ||
516 | |||
517 | ME_SUBDEVICE_EXIT; | ||
518 | |||
519 | return err; | ||
520 | } | ||
521 | |||
522 | static int me4600_ai_io_single_config(me_subdevice_t * subdevice, | ||
523 | struct file *filep, | ||
524 | int channel, | ||
525 | int single_config, | ||
526 | int ref, | ||
527 | int trig_chan, | ||
528 | int trig_type, int trig_edge, int flags) | ||
529 | { | ||
530 | me4600_ai_subdevice_t *instance; | ||
531 | int err = ME_ERRNO_SUCCESS; | ||
532 | unsigned long cpu_flags; | ||
533 | int i; | ||
534 | |||
535 | instance = (me4600_ai_subdevice_t *) subdevice; | ||
536 | |||
537 | PDEBUG("executed. idx=0\n"); | ||
538 | |||
539 | if (flags & ~ME_IO_SINGLE_CONFIG_CONTINUE) { | ||
540 | PERROR("Invalid flag specified.\n"); | ||
541 | return ME_ERRNO_INVALID_FLAGS; | ||
542 | } | ||
543 | |||
544 | switch (trig_type) { | ||
545 | case ME_TRIG_TYPE_SW: | ||
546 | if (trig_edge != ME_TRIG_EDGE_NONE) { | ||
547 | PERROR | ||
548 | ("Invalid trigger edge. Software trigger has not edge.\n"); | ||
549 | return ME_ERRNO_INVALID_TRIG_EDGE; | ||
550 | } | ||
551 | break; | ||
552 | |||
553 | case ME_TRIG_TYPE_EXT_ANALOG: | ||
554 | if (instance->channels <= 16) //Only versions with 32 channels have analog trigger (4670 and 4680) | ||
555 | { | ||
556 | PERROR("Invalid trigger type specified.\n"); | ||
557 | return ME_ERRNO_INVALID_TRIG_TYPE; | ||
558 | } | ||
559 | |||
560 | case ME_TRIG_TYPE_EXT_DIGITAL: | ||
561 | if ((trig_edge != ME_TRIG_EDGE_ANY) | ||
562 | && (trig_edge != ME_TRIG_EDGE_RISING) | ||
563 | && (trig_edge != ME_TRIG_EDGE_FALLING)) { | ||
564 | PERROR("Invalid trigger edge specified.\n"); | ||
565 | return ME_ERRNO_INVALID_TRIG_EDGE; | ||
566 | } | ||
567 | break; | ||
568 | |||
569 | default: | ||
570 | PERROR("Invalid trigger type specified.\n"); | ||
571 | return ME_ERRNO_INVALID_TRIG_TYPE; | ||
572 | } | ||
573 | |||
574 | if (trig_chan != ME_TRIG_CHAN_DEFAULT) { | ||
575 | PERROR("Invalid trigger channel specified.\n"); | ||
576 | return ME_ERRNO_INVALID_TRIG_CHAN; | ||
577 | } | ||
578 | |||
579 | if ((single_config < 0) || (single_config >= instance->ranges_len)) { | ||
580 | PERROR("Invalid single config specified.\n"); | ||
581 | return ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
582 | } | ||
583 | |||
584 | if ((ref != ME_REF_AI_GROUND) && (ref != ME_REF_AI_DIFFERENTIAL)) { | ||
585 | PERROR("Invalid analog reference specified.\n"); | ||
586 | return ME_ERRNO_INVALID_REF; | ||
587 | } | ||
588 | |||
589 | if ((single_config % 2) && (ref != ME_REF_AI_GROUND)) { | ||
590 | PERROR("Invalid analog reference specified.\n"); | ||
591 | return ME_ERRNO_INVALID_REF; | ||
592 | } | ||
593 | |||
594 | if ((ref == ME_REF_AI_DIFFERENTIAL) | ||
595 | && ((instance->channels == 16) || (channel >= 16))) { | ||
596 | PERROR("Invalid analog reference specified.\n"); | ||
597 | return ME_ERRNO_INVALID_REF; | ||
598 | } | ||
599 | |||
600 | if (channel < 0) { | ||
601 | PERROR("Invalid channel number specified.\n"); | ||
602 | return ME_ERRNO_INVALID_CHANNEL; | ||
603 | } | ||
604 | |||
605 | if (channel >= instance->channels) { | ||
606 | PERROR("Invalid channel number specified.\n"); | ||
607 | return ME_ERRNO_INVALID_CHANNEL; | ||
608 | } | ||
609 | |||
610 | ME_SUBDEVICE_ENTER; | ||
611 | |||
612 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
613 | //Prepare data entry. | ||
614 | // Common for all modes. | ||
615 | instance->single_config[channel].entry = | ||
616 | channel | ME4600_AI_LIST_LAST_ENTRY; | ||
617 | |||
618 | if (ref == ME_REF_AI_DIFFERENTIAL) { // ME_REF_AI_DIFFERENTIAL | ||
619 | instance->single_config[channel].entry |= | ||
620 | ME4600_AI_LIST_INPUT_DIFFERENTIAL; | ||
621 | } | ||
622 | /* | ||
623 | // ME4600_AI_LIST_INPUT_SINGLE_ENDED = 0x0000 | ||
624 | // 'entry |= ME4600_AI_LIST_INPUT_SINGLE_ENDED' <== Do nothing. Removed. | ||
625 | else | ||
626 | {// ME_REF_AI_GROUND | ||
627 | instance->single_config[channel].entry |= ME4600_AI_LIST_INPUT_SINGLE_ENDED; | ||
628 | } | ||
629 | */ | ||
630 | switch (single_config) { | ||
631 | case 0: //-10V..10V | ||
632 | /* | ||
633 | // ME4600_AI_LIST_RANGE_BIPOLAR_10 = 0x0000 | ||
634 | // 'entry |= ME4600_AI_LIST_RANGE_BIPOLAR_10' <== Do nothing. Removed. | ||
635 | instance->single_config[channel].entry |= ME4600_AI_LIST_RANGE_BIPOLAR_10; | ||
636 | */ break; | ||
637 | |||
638 | case 1: //0V..10V | ||
639 | instance->single_config[channel].entry |= | ||
640 | ME4600_AI_LIST_RANGE_UNIPOLAR_10; | ||
641 | break; | ||
642 | |||
643 | case 2: //-2.5V..2.5V | ||
644 | instance->single_config[channel].entry |= | ||
645 | ME4600_AI_LIST_RANGE_BIPOLAR_2_5; | ||
646 | break; | ||
647 | |||
648 | case 3: //0V..2.5V | ||
649 | instance->single_config[channel].entry |= | ||
650 | ME4600_AI_LIST_RANGE_UNIPOLAR_2_5; | ||
651 | break; | ||
652 | } | ||
653 | |||
654 | // Prepare control register. | ||
655 | // Common for all modes. | ||
656 | instance->single_config[channel].ctrl = | ||
657 | ME4600_AI_CTRL_BIT_CHANNEL_FIFO | ME4600_AI_CTRL_BIT_DATA_FIFO; | ||
658 | |||
659 | switch (trig_type) { | ||
660 | case ME_TRIG_TYPE_SW: | ||
661 | // Nothing to set. | ||
662 | break; | ||
663 | |||
664 | case ME_TRIG_TYPE_EXT_ANALOG: | ||
665 | instance->single_config[channel].ctrl |= | ||
666 | ME4600_AI_CTRL_BIT_EX_TRIG_ANALOG; | ||
667 | |||
668 | case ME_TRIG_TYPE_EXT_DIGITAL: | ||
669 | instance->single_config[channel].ctrl |= | ||
670 | ME4600_AI_CTRL_BIT_EX_TRIG; | ||
671 | break; | ||
672 | } | ||
673 | |||
674 | switch (trig_edge) { | ||
675 | case ME_TRIG_EDGE_RISING: | ||
676 | // Nothing to set. | ||
677 | break; | ||
678 | |||
679 | case ME_TRIG_EDGE_ANY: | ||
680 | instance->single_config[channel].ctrl |= | ||
681 | ME4600_AI_CTRL_BIT_EX_TRIG_BOTH; | ||
682 | |||
683 | case ME_TRIG_EDGE_FALLING: | ||
684 | instance->single_config[channel].ctrl |= | ||
685 | ME4600_AI_CTRL_BIT_EX_TRIG_FALLING; | ||
686 | break; | ||
687 | } | ||
688 | |||
689 | // Enable this channel | ||
690 | instance->single_config[channel].status = ME_SINGLE_CHANNEL_CONFIGURED; | ||
691 | |||
692 | // Copy this settings to other outputs. | ||
693 | if (flags == ME_IO_SINGLE_CONFIG_CONTINUE) { | ||
694 | for (i = channel + 1; i < instance->channels; i++) { | ||
695 | instance->single_config[i].ctrl = | ||
696 | instance->single_config[channel].ctrl; | ||
697 | instance->single_config[i].entry = | ||
698 | instance->single_config[channel].entry; | ||
699 | instance->single_config[i].status = | ||
700 | ME_SINGLE_CHANNEL_CONFIGURED; | ||
701 | } | ||
702 | } | ||
703 | |||
704 | instance->status = ai_status_single_configured; | ||
705 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
706 | |||
707 | ME_SUBDEVICE_EXIT; | ||
708 | |||
709 | return err; | ||
710 | } | ||
711 | |||
712 | static int me4600_ai_io_single_read(me_subdevice_t * subdevice, | ||
713 | struct file *filep, | ||
714 | int channel, | ||
715 | int *value, int time_out, int flags) | ||
716 | { | ||
717 | me4600_ai_subdevice_t *instance; | ||
718 | volatile uint32_t tmp; | ||
719 | volatile uint32_t val; | ||
720 | unsigned long cpu_flags; | ||
721 | int err = ME_ERRNO_SUCCESS; | ||
722 | |||
723 | unsigned long j; | ||
724 | unsigned long delay = 0; | ||
725 | |||
726 | PDEBUG("executed. idx=0\n"); | ||
727 | |||
728 | instance = (me4600_ai_subdevice_t *) subdevice; | ||
729 | |||
730 | if (flags) { | ||
731 | PERROR("Invalid flag specified.\n"); | ||
732 | return ME_ERRNO_INVALID_FLAGS; | ||
733 | } | ||
734 | |||
735 | if (instance->status != ai_status_single_configured) { | ||
736 | PERROR("Subdevice not configured to work in single mode!\n"); | ||
737 | return ME_ERRNO_PREVIOUS_CONFIG; | ||
738 | } | ||
739 | |||
740 | if ((channel > instance->channels) || (channel < 0)) { | ||
741 | PERROR("Invalid channel specified.\n"); | ||
742 | return ME_ERRNO_INVALID_CHANNEL; | ||
743 | } | ||
744 | |||
745 | if (time_out < 0) { | ||
746 | PERROR("Invalid timeout specified.\n"); | ||
747 | return ME_ERRNO_INVALID_TIMEOUT; | ||
748 | } | ||
749 | |||
750 | if (instance->single_config[channel].status != | ||
751 | ME_SINGLE_CHANNEL_CONFIGURED) { | ||
752 | PERROR("Channel is not configured to work in single mode!\n"); | ||
753 | return ME_ERRNO_PREVIOUS_CONFIG; | ||
754 | } | ||
755 | |||
756 | if (inl(instance->status_reg) & ME4600_AI_STATUS_BIT_FSM) { | ||
757 | PERROR("Subdevice is busy.\n"); | ||
758 | return ME_ERRNO_SUBDEVICE_BUSY; | ||
759 | } | ||
760 | |||
761 | ME_SUBDEVICE_ENTER; | ||
762 | |||
763 | // Cancel control task | ||
764 | PDEBUG("Cancel control task.\n"); | ||
765 | instance->ai_control_task_flag = 0; | ||
766 | cancel_delayed_work(&instance->ai_control_task); | ||
767 | |||
768 | if (time_out) { | ||
769 | delay = (time_out * HZ) / 1000; | ||
770 | |||
771 | if (delay == 0) | ||
772 | delay = 1; | ||
773 | } | ||
774 | |||
775 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
776 | |||
777 | // Mark that StreamConfig is removed. | ||
778 | instance->chan_list_len = 0; | ||
779 | |||
780 | spin_lock_irqsave(instance->ctrl_reg_lock, cpu_flags); | ||
781 | /// @note Imprtant: Preserve EXT IRQ settings. | ||
782 | tmp = inl(instance->ctrl_reg); | ||
783 | // Clear FIFOs and dissable interrupts | ||
784 | tmp &= | ||
785 | ~(ME4600_AI_CTRL_BIT_CHANNEL_FIFO | ME4600_AI_CTRL_BIT_DATA_FIFO); | ||
786 | |||
787 | tmp &= | ||
788 | ~(ME4600_AI_CTRL_BIT_SC_IRQ | ME4600_AI_CTRL_BIT_HF_IRQ | | ||
789 | ME4600_AI_CTRL_BIT_LE_IRQ); | ||
790 | tmp |= | ||
791 | ME4600_AI_CTRL_BIT_SC_IRQ_RESET | ME4600_AI_CTRL_BIT_HF_IRQ_RESET | | ||
792 | ME4600_AI_CTRL_BIT_LE_IRQ_RESET; | ||
793 | |||
794 | tmp |= ME4600_AI_CTRL_BIT_IMMEDIATE_STOP; | ||
795 | outl(tmp, instance->ctrl_reg); | ||
796 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
797 | instance->ctrl_reg - instance->reg_base, tmp); | ||
798 | |||
799 | outl(0, instance->scan_pre_timer_low_reg); | ||
800 | PDEBUG_REG("scan_pre_timer_low_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
801 | instance->reg_base, | ||
802 | instance->scan_pre_timer_low_reg - instance->reg_base, 0); | ||
803 | outl(0, instance->scan_pre_timer_high_reg); | ||
804 | PDEBUG_REG("scan_pre_timer_high_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
805 | instance->reg_base, | ||
806 | instance->scan_pre_timer_high_reg - instance->reg_base, 0); | ||
807 | outl(0, instance->scan_timer_low_reg); | ||
808 | PDEBUG_REG("scan_timer_low_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
809 | instance->reg_base, | ||
810 | instance->scan_timer_low_reg - instance->reg_base, 0); | ||
811 | outl(0, instance->scan_timer_high_reg); | ||
812 | PDEBUG_REG("scan_timer_high_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
813 | instance->reg_base, | ||
814 | instance->scan_timer_high_reg - instance->reg_base, 0); | ||
815 | outl(65, instance->chan_timer_reg); | ||
816 | PDEBUG_REG("chan_timer_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
817 | instance->reg_base, | ||
818 | instance->chan_timer_reg - instance->reg_base, 65); | ||
819 | outl(65, instance->chan_pre_timer_reg); | ||
820 | PDEBUG_REG("chan_pre_timer_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
821 | instance->reg_base, | ||
822 | instance->chan_pre_timer_reg - instance->reg_base, 65); | ||
823 | |||
824 | //Reactive FIFOs. Enable work. | ||
825 | tmp |= ME4600_AI_CTRL_BIT_CHANNEL_FIFO | ME4600_AI_CTRL_BIT_DATA_FIFO; | ||
826 | outl(tmp, instance->ctrl_reg); | ||
827 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
828 | instance->ctrl_reg - instance->reg_base, tmp); | ||
829 | |||
830 | outl(instance->single_config[channel].entry, | ||
831 | instance->channel_list_reg); | ||
832 | PDEBUG_REG("channel_list_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
833 | instance->reg_base, | ||
834 | instance->channel_list_reg - instance->reg_base, | ||
835 | instance->single_config[channel].entry); | ||
836 | |||
837 | // Preserve EXT IRQ settings. | ||
838 | tmp &= (ME4600_AI_CTRL_BIT_EX_IRQ | ME4600_AI_CTRL_BIT_EX_IRQ_RESET); | ||
839 | outl(instance->single_config[channel].ctrl | tmp, instance->ctrl_reg); | ||
840 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
841 | instance->ctrl_reg - instance->reg_base, | ||
842 | instance->single_config[channel].ctrl | tmp); | ||
843 | |||
844 | spin_unlock_irqrestore(instance->ctrl_reg_lock, cpu_flags); | ||
845 | |||
846 | if (!(instance->single_config[channel].ctrl & ME4600_AI_CTRL_BIT_EX_TRIG)) { // Software start | ||
847 | inl(instance->start_reg); | ||
848 | PDEBUG_REG("start_reg inl(0x%lX+0x%lX)\n", instance->reg_base, | ||
849 | instance->start_reg - instance->reg_base); | ||
850 | |||
851 | delay = 2; | ||
852 | } | ||
853 | |||
854 | j = jiffies; | ||
855 | |||
856 | while (!(inl(instance->status_reg) & ME4600_AI_STATUS_BIT_EF_DATA)) { | ||
857 | if (delay && ((jiffies - j) >= delay)) { | ||
858 | if (!(instance->single_config[channel].ctrl & ME4600_AI_CTRL_BIT_EX_TRIG)) { // Software start. | ||
859 | PERROR("Value not available after wait.\n"); | ||
860 | err = ME_ERRNO_INTERNAL; | ||
861 | } else { // External start. | ||
862 | PERROR("Timeout reached.\n"); | ||
863 | err = ME_ERRNO_TIMEOUT; | ||
864 | } | ||
865 | break; | ||
866 | } | ||
867 | // Wait | ||
868 | set_current_state(TASK_INTERRUPTIBLE); | ||
869 | schedule_timeout(1); | ||
870 | |||
871 | if (signal_pending(current)) { | ||
872 | PERROR | ||
873 | ("Wait on external trigger interrupted by signal.\n"); | ||
874 | err = ME_ERRNO_SIGNAL; | ||
875 | break; | ||
876 | } | ||
877 | |||
878 | if (instance->status != ai_status_single_configured) { | ||
879 | PERROR("Wait interrupted by reset.\n"); | ||
880 | err = ME_ERRNO_CANCELLED; | ||
881 | break; | ||
882 | } | ||
883 | } | ||
884 | |||
885 | // Read value. | ||
886 | if (!err) { | ||
887 | val = inl(instance->data_reg) ^ 0x8000; | ||
888 | PDEBUG_REG("data_reg inl(0x%lX+0x%lX)=0x%x\n", | ||
889 | instance->reg_base, | ||
890 | instance->data_reg - instance->reg_base, val); | ||
891 | *value = val & ME4600_AI_MAX_DATA; | ||
892 | } else { | ||
893 | *value = 0xFFFFFFFF; | ||
894 | } | ||
895 | |||
896 | // Restore settings. | ||
897 | spin_lock_irqsave(instance->ctrl_reg_lock, cpu_flags); | ||
898 | tmp = inl(instance->ctrl_reg); | ||
899 | // Clear FIFOs and dissable interrupts. | ||
900 | tmp &= | ||
901 | ~(ME4600_AI_CTRL_BIT_CHANNEL_FIFO | ME4600_AI_CTRL_BIT_DATA_FIFO); | ||
902 | tmp |= ME4600_AI_CTRL_BIT_SC_IRQ | ME4600_AI_CTRL_BIT_HF_IRQ; | ||
903 | tmp |= | ||
904 | ME4600_AI_CTRL_BIT_SC_IRQ_RESET | ME4600_AI_CTRL_BIT_HF_IRQ_RESET | | ||
905 | ME4600_AI_CTRL_BIT_LE_IRQ_RESET | ME4600_AI_CTRL_BIT_IMMEDIATE_STOP; | ||
906 | outl(tmp, instance->ctrl_reg); | ||
907 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
908 | instance->ctrl_reg - instance->reg_base, tmp); | ||
909 | spin_unlock_irqrestore(instance->ctrl_reg_lock, cpu_flags); | ||
910 | |||
911 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
912 | |||
913 | ME_SUBDEVICE_EXIT; | ||
914 | |||
915 | return err; | ||
916 | } | ||
917 | |||
918 | static int me4600_ai_io_stream_config(me_subdevice_t * subdevice, | ||
919 | struct file *filep, | ||
920 | meIOStreamConfig_t * config_list, | ||
921 | int count, | ||
922 | meIOStreamTrigger_t * trigger, | ||
923 | int fifo_irq_threshold, int flags) | ||
924 | { | ||
925 | me4600_ai_subdevice_t *instance; | ||
926 | int err = ME_ERRNO_SUCCESS; | ||
927 | int i; // internal multipurpose variable | ||
928 | unsigned long long data_required; | ||
929 | |||
930 | volatile uint32_t entry; | ||
931 | volatile uint32_t ctrl = ME4600_AI_CTRL_BIT_IMMEDIATE_STOP; | ||
932 | volatile uint32_t tmp; // use when current copy of register's value needed | ||
933 | unsigned long cpu_flags; | ||
934 | |||
935 | uint64_t acq_ticks; | ||
936 | uint64_t scan_ticks; | ||
937 | uint64_t conv_ticks; | ||
938 | unsigned int acq_start_ticks_low = trigger->iAcqStartTicksLow; | ||
939 | unsigned int acq_start_ticks_high = trigger->iAcqStartTicksHigh; | ||
940 | unsigned int scan_start_ticks_low = trigger->iScanStartTicksLow; | ||
941 | unsigned int scan_start_ticks_high = trigger->iScanStartTicksHigh; | ||
942 | unsigned int conv_start_ticks_low = trigger->iConvStartTicksLow; | ||
943 | unsigned int conv_start_ticks_high = trigger->iConvStartTicksHigh; | ||
944 | |||
945 | PDEBUG("executed. idx=0\n"); | ||
946 | |||
947 | instance = (me4600_ai_subdevice_t *) subdevice; | ||
948 | |||
949 | if (flags) { | ||
950 | PERROR("Invalid flag specified.\n"); | ||
951 | return ME_ERRNO_INVALID_FLAGS; | ||
952 | } | ||
953 | |||
954 | ME_SUBDEVICE_ENTER | ||
955 | // Convert ticks to 64 bit long values | ||
956 | acq_ticks = | ||
957 | (uint64_t) acq_start_ticks_low + | ||
958 | ((uint64_t) acq_start_ticks_high << 32); | ||
959 | scan_ticks = | ||
960 | (uint64_t) scan_start_ticks_low + | ||
961 | ((uint64_t) scan_start_ticks_high << 32); | ||
962 | conv_ticks = | ||
963 | (uint64_t) conv_start_ticks_low + | ||
964 | ((uint64_t) conv_start_ticks_high << 32); | ||
965 | |||
966 | // Check settings - begin | ||
967 | switch (trigger->iAcqStartTrigType) { | ||
968 | case ME_TRIG_TYPE_SW: | ||
969 | case ME_TRIG_TYPE_EXT_DIGITAL: | ||
970 | case ME_TRIG_TYPE_EXT_ANALOG: | ||
971 | break; | ||
972 | |||
973 | default: | ||
974 | PERROR("Invalid acquisition start trigger type specified.\n"); | ||
975 | err = ME_ERRNO_INVALID_ACQ_START_TRIG_TYPE; | ||
976 | goto ERROR; | ||
977 | break; | ||
978 | } | ||
979 | |||
980 | if ((trigger->iAcqStartTrigType == ME_TRIG_TYPE_SW) | ||
981 | && (trigger->iAcqStartTrigEdge != ME_TRIG_EDGE_NONE)) { | ||
982 | PERROR("Invalid acquisition start trigger edge specified.\n"); | ||
983 | err = ME_ERRNO_INVALID_ACQ_START_TRIG_EDGE; | ||
984 | goto ERROR; | ||
985 | } | ||
986 | |||
987 | if (trigger->iAcqStartTrigType != ME_TRIG_TYPE_SW) { | ||
988 | switch (trigger->iAcqStartTrigEdge) { | ||
989 | case ME_TRIG_EDGE_RISING: | ||
990 | case ME_TRIG_EDGE_FALLING: | ||
991 | case ME_TRIG_EDGE_ANY: | ||
992 | break; | ||
993 | |||
994 | default: | ||
995 | PERROR | ||
996 | ("Invalid acquisition start trigger edge specified.\n"); | ||
997 | err = ME_ERRNO_INVALID_ACQ_START_TRIG_EDGE; | ||
998 | goto ERROR; | ||
999 | break; | ||
1000 | } | ||
1001 | } | ||
1002 | |||
1003 | if (trigger->iAcqStartTrigChan != ME_TRIG_CHAN_DEFAULT) { | ||
1004 | PERROR | ||
1005 | ("Invalid acquisition start trigger channel specified.\n"); | ||
1006 | err = ME_ERRNO_INVALID_ACQ_START_TRIG_CHAN; | ||
1007 | goto ERROR; | ||
1008 | } | ||
1009 | |||
1010 | if ((acq_ticks < ME4600_AI_MIN_ACQ_TICKS) | ||
1011 | || (acq_ticks > ME4600_AI_MAX_ACQ_TICKS)) { | ||
1012 | PERROR | ||
1013 | ("Invalid acquisition start trigger argument specified.\n"); | ||
1014 | err = ME_ERRNO_INVALID_ACQ_START_ARG; | ||
1015 | goto ERROR; | ||
1016 | } | ||
1017 | |||
1018 | switch (trigger->iScanStartTrigType) { | ||
1019 | |||
1020 | case ME_TRIG_TYPE_TIMER: | ||
1021 | if ((scan_ticks < ME4600_AI_MIN_SCAN_TICKS) | ||
1022 | || (scan_ticks > ME4600_AI_MAX_SCAN_TICKS) | ||
1023 | || (scan_ticks < count * conv_ticks) | ||
1024 | ) { | ||
1025 | PERROR("Invalid scan start argument specified.\n"); | ||
1026 | err = ME_ERRNO_INVALID_SCAN_START_ARG; | ||
1027 | goto ERROR; | ||
1028 | } | ||
1029 | break; | ||
1030 | |||
1031 | case ME_TRIG_TYPE_EXT_DIGITAL: | ||
1032 | if (trigger->iAcqStartTrigType != ME_TRIG_TYPE_EXT_DIGITAL) { | ||
1033 | PERROR | ||
1034 | ("Invalid scan start trigger type specified (Acq is HW digital)\n"); | ||
1035 | err = ME_ERRNO_INVALID_SCAN_START_TRIG_TYPE; | ||
1036 | goto ERROR; | ||
1037 | } | ||
1038 | break; | ||
1039 | |||
1040 | case ME_TRIG_TYPE_EXT_ANALOG: | ||
1041 | if (trigger->iAcqStartTrigType != ME_TRIG_TYPE_EXT_ANALOG) { | ||
1042 | PERROR | ||
1043 | ("Invalid scan start trigger type specified (Acq is HW analog)\n"); | ||
1044 | err = ME_ERRNO_INVALID_SCAN_START_TRIG_TYPE; | ||
1045 | goto ERROR; | ||
1046 | } | ||
1047 | break; | ||
1048 | |||
1049 | case ME_TRIG_TYPE_FOLLOW: | ||
1050 | break; | ||
1051 | |||
1052 | default: | ||
1053 | PERROR("Invalid scan start trigger type specified.\n"); | ||
1054 | err = ME_ERRNO_INVALID_SCAN_START_TRIG_TYPE; | ||
1055 | goto ERROR; | ||
1056 | break; | ||
1057 | } | ||
1058 | |||
1059 | switch (trigger->iConvStartTrigType) { | ||
1060 | |||
1061 | case ME_TRIG_TYPE_TIMER: | ||
1062 | if ((conv_ticks < ME4600_AI_MIN_CHAN_TICKS) | ||
1063 | || (conv_ticks > ME4600_AI_MAX_CHAN_TICKS)) { | ||
1064 | PERROR | ||
1065 | ("Invalid conv start trigger argument specified.\n"); | ||
1066 | err = ME_ERRNO_INVALID_CONV_START_ARG; | ||
1067 | goto ERROR; | ||
1068 | } | ||
1069 | break; | ||
1070 | |||
1071 | case ME_TRIG_TYPE_EXT_DIGITAL: | ||
1072 | if ((trigger->iScanStartTrigType != ME_TRIG_TYPE_FOLLOW) | ||
1073 | || (trigger->iAcqStartTrigType != | ||
1074 | ME_TRIG_TYPE_EXT_DIGITAL)) { | ||
1075 | PERROR("Invalid conv start trigger type specified.\n"); | ||
1076 | err = ME_ERRNO_INVALID_CONV_START_TRIG_TYPE; | ||
1077 | goto ERROR; | ||
1078 | } | ||
1079 | break; | ||
1080 | |||
1081 | case ME_TRIG_TYPE_EXT_ANALOG: | ||
1082 | if ((trigger->iScanStartTrigType != ME_TRIG_TYPE_FOLLOW) | ||
1083 | || (trigger->iAcqStartTrigType != | ||
1084 | ME_TRIG_TYPE_EXT_ANALOG)) { | ||
1085 | PERROR("Invalid conv start trigger type specified.\n"); | ||
1086 | err = ME_ERRNO_INVALID_CONV_START_TRIG_TYPE; | ||
1087 | goto ERROR; | ||
1088 | } | ||
1089 | break; | ||
1090 | |||
1091 | default: | ||
1092 | PERROR("Invalid conv start trigger type specified.\n"); | ||
1093 | err = ME_ERRNO_INVALID_CONV_START_TRIG_TYPE; | ||
1094 | goto ERROR; | ||
1095 | |||
1096 | break; | ||
1097 | } | ||
1098 | /** | ||
1099 | * Aceptable settings: | ||
1100 | * iScanStopTrigType : iAcqStopTrigType | ||
1101 | * | ||
1102 | * ME_TRIG_TYPE_NONE : ME_TRIG_TYPE_NONE -> infinite count with manual stop | ||
1103 | * ME_TRIG_TYPE_NONE : ME_TRIG_TYPE_COUNT -> stop after getting iScanStopCount list of values (iScanStopCount * count) | ||
1104 | * ME_TRIG_TYPE_COUNT : ME_TRIG_TYPE_FOLLOW -> stop after getting iAcqStopCount values (it can stops in midle of the list) | ||
1105 | */ | ||
1106 | switch (trigger->iScanStopTrigType) { | ||
1107 | |||
1108 | case ME_TRIG_TYPE_NONE: | ||
1109 | break; | ||
1110 | |||
1111 | case ME_TRIG_TYPE_COUNT: | ||
1112 | if (trigger->iScanStopCount <= 0) { | ||
1113 | PERROR("Invalid scan stop argument specified.\n"); | ||
1114 | err = ME_ERRNO_INVALID_SCAN_STOP_ARG; | ||
1115 | goto ERROR; | ||
1116 | } | ||
1117 | break; | ||
1118 | |||
1119 | default: | ||
1120 | PERROR("Invalid scan stop trigger type specified.\n"); | ||
1121 | err = ME_ERRNO_INVALID_SCAN_STOP_TRIG_TYPE; | ||
1122 | goto ERROR; | ||
1123 | break; | ||
1124 | } | ||
1125 | |||
1126 | switch (trigger->iAcqStopTrigType) { | ||
1127 | |||
1128 | case ME_TRIG_TYPE_NONE: | ||
1129 | if (trigger->iScanStopTrigType != ME_TRIG_TYPE_NONE) { | ||
1130 | PERROR("Invalid acq stop trigger type specified.\n"); | ||
1131 | err = ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE; | ||
1132 | goto ERROR; | ||
1133 | } | ||
1134 | break; | ||
1135 | |||
1136 | case ME_TRIG_TYPE_FOLLOW: | ||
1137 | if (trigger->iScanStopTrigType != ME_TRIG_TYPE_COUNT) { | ||
1138 | PERROR("Invalid acq stop trigger type specified.\n"); | ||
1139 | err = ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE; | ||
1140 | goto ERROR; | ||
1141 | } | ||
1142 | break; | ||
1143 | |||
1144 | case ME_TRIG_TYPE_COUNT: | ||
1145 | if (trigger->iScanStopTrigType != ME_TRIG_TYPE_NONE) { | ||
1146 | PERROR("Invalid acq stop trigger type specified.\n"); | ||
1147 | err = ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE; | ||
1148 | goto ERROR; | ||
1149 | } | ||
1150 | |||
1151 | if (trigger->iAcqStopCount <= 0) { | ||
1152 | PERROR | ||
1153 | ("Invalid acquisition or scan stop argument specified.\n"); | ||
1154 | err = ME_ERRNO_INVALID_ACQ_STOP_ARG; | ||
1155 | goto ERROR; | ||
1156 | } | ||
1157 | break; | ||
1158 | |||
1159 | default: | ||
1160 | PERROR("Invalid acq stop trigger type specified.\n"); | ||
1161 | err = ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE; | ||
1162 | goto ERROR; | ||
1163 | break; | ||
1164 | } | ||
1165 | |||
1166 | if ((count <= 0) || (count > ME4600_AI_LIST_COUNT)) { | ||
1167 | PERROR("Invalid channel list count specified.\n"); | ||
1168 | err = ME_ERRNO_INVALID_CONFIG_LIST_COUNT; | ||
1169 | goto ERROR; | ||
1170 | } | ||
1171 | ///This is general limitation | ||
1172 | // if (fifo_irq_threshold < 0 || fifo_irq_threshold >= ME4600_AI_CIRC_BUF_COUNT) | ||
1173 | ///This is limitation from Windows. I use it for compatibility. | ||
1174 | if (fifo_irq_threshold < 0 | ||
1175 | || fifo_irq_threshold >= ME4600_AI_FIFO_COUNT) { | ||
1176 | PERROR("Invalid fifo irq threshold specified.\n"); | ||
1177 | err = ME_ERRNO_INVALID_FIFO_IRQ_THRESHOLD; | ||
1178 | goto ERROR; | ||
1179 | } | ||
1180 | |||
1181 | if ((config_list[0].iRef == ME_REF_AI_DIFFERENTIAL) | ||
1182 | && (instance->channels == 16)) { | ||
1183 | PERROR | ||
1184 | ("Differential reference is not available on this subdevice.\n"); | ||
1185 | err = ME_ERRNO_INVALID_REF; | ||
1186 | goto ERROR; | ||
1187 | } | ||
1188 | |||
1189 | if (flags & ME_IO_STREAM_CONFIG_SAMPLE_AND_HOLD) { | ||
1190 | if (!instance->sh) { | ||
1191 | PERROR | ||
1192 | ("Sample and hold is not available for this board.\n"); | ||
1193 | err = ME_ERRNO_INVALID_FLAGS; | ||
1194 | goto ERROR; | ||
1195 | } | ||
1196 | if (config_list[0].iRef == ME_REF_AI_DIFFERENTIAL) { | ||
1197 | PERROR | ||
1198 | ("Sample and hold is not available in differential mode.\n"); | ||
1199 | err = ME_ERRNO_INVALID_FLAGS; | ||
1200 | goto ERROR; | ||
1201 | } | ||
1202 | } | ||
1203 | |||
1204 | for (i = 0; i < count; i++) { | ||
1205 | if ((config_list[i].iStreamConfig < 0) | ||
1206 | || (config_list[i].iStreamConfig >= instance->ranges_len)) { | ||
1207 | PERROR("Invalid stream config specified.\n"); | ||
1208 | err = ME_ERRNO_INVALID_STREAM_CONFIG; | ||
1209 | goto ERROR; | ||
1210 | } | ||
1211 | |||
1212 | if ((config_list[i].iRef != ME_REF_AI_GROUND) | ||
1213 | && (config_list[i].iRef != ME_REF_AI_DIFFERENTIAL)) { | ||
1214 | PERROR("Invalid references in the list. Ref=0x%x\n", | ||
1215 | config_list[i].iRef); | ||
1216 | err = ME_ERRNO_INVALID_REF; | ||
1217 | goto ERROR; | ||
1218 | } | ||
1219 | |||
1220 | if (config_list[i].iStreamConfig % 2) { // StreamConfig: 1 or 3 | ||
1221 | if (config_list[i].iRef == ME_REF_AI_DIFFERENTIAL) { | ||
1222 | PERROR | ||
1223 | ("Only bipolar modes support differential measurement.\n"); | ||
1224 | err = ME_ERRNO_INVALID_REF; | ||
1225 | goto ERROR; | ||
1226 | } | ||
1227 | } | ||
1228 | |||
1229 | if (config_list[i].iRef != config_list[0].iRef) { | ||
1230 | PERROR | ||
1231 | ("Not all references in the configuration list are equal. Ref[0]=0x%x Ref[%d]=0x%x\n", | ||
1232 | config_list[0].iRef, i, config_list[i].iRef); | ||
1233 | err = ME_ERRNO_INVALID_REF; | ||
1234 | goto ERROR; | ||
1235 | } | ||
1236 | |||
1237 | if ((config_list[i].iRef == ME_REF_AI_DIFFERENTIAL) | ||
1238 | && (config_list[i].iChannel >= 16)) { | ||
1239 | PERROR("Channel not available in differential mode.\n"); | ||
1240 | err = ME_ERRNO_INVALID_CHANNEL; | ||
1241 | goto ERROR; | ||
1242 | } | ||
1243 | |||
1244 | if ((config_list[i].iChannel < 0) | ||
1245 | || (config_list[i].iChannel >= instance->channels)) { | ||
1246 | PERROR("Invalid channel number specified.\n"); | ||
1247 | err = ME_ERRNO_INVALID_CHANNEL; | ||
1248 | goto ERROR; | ||
1249 | } | ||
1250 | } | ||
1251 | |||
1252 | // Check settings - end | ||
1253 | |||
1254 | //Cancel control task | ||
1255 | PDEBUG("Cancel control task.\n"); | ||
1256 | instance->ai_control_task_flag = 0; | ||
1257 | cancel_delayed_work(&instance->ai_control_task); | ||
1258 | |||
1259 | // Work around from Keith Hartley - begin | ||
1260 | if (trigger->iScanStartTrigType == ME_TRIG_TYPE_TIMER) { | ||
1261 | if (count == 1) { | ||
1262 | // The hardware does not work properly with a non-zero scan time | ||
1263 | // if there is only ONE channel in the channel list. In this case | ||
1264 | // we must set the scan time to zero and use the channel time. | ||
1265 | |||
1266 | conv_ticks = scan_ticks; | ||
1267 | trigger->iScanStartTrigType = ME_TRIG_TYPE_FOLLOW; | ||
1268 | } else if (scan_ticks == count * conv_ticks) { | ||
1269 | // Another hardware problem. If the number of scan ticks is | ||
1270 | // exactly equal to the number of channel ticks multiplied by | ||
1271 | // the number of channels then the sampling rate is reduced | ||
1272 | // by half. | ||
1273 | trigger->iScanStartTrigType = ME_TRIG_TYPE_FOLLOW; | ||
1274 | } | ||
1275 | } | ||
1276 | // Work around from Keith Hartley - end | ||
1277 | |||
1278 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
1279 | |||
1280 | if (inl(instance->status_reg) & ME4600_AI_STATUS_BIT_FSM) { | ||
1281 | PERROR("Subdevice is busy.\n"); | ||
1282 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
1283 | ME_SUBDEVICE_EXIT; | ||
1284 | return ME_ERRNO_SUBDEVICE_BUSY; | ||
1285 | } | ||
1286 | |||
1287 | instance->status = ai_status_none; | ||
1288 | spin_lock_irqsave(instance->ctrl_reg_lock, cpu_flags); | ||
1289 | // Stop all actions. Block all interrupts. Clear (disable) FIFOs. | ||
1290 | ctrl = | ||
1291 | ME4600_AI_CTRL_BIT_LE_IRQ_RESET | ME4600_AI_CTRL_BIT_HF_IRQ_RESET | | ||
1292 | ME4600_AI_CTRL_BIT_SC_IRQ_RESET; | ||
1293 | |||
1294 | tmp = inl(instance->ctrl_reg); | ||
1295 | // Preserve EXT IRQ and OFFSET settings. Clean other bits. | ||
1296 | tmp &= | ||
1297 | (ME4600_AI_CTRL_BIT_EX_IRQ | ME4600_AI_CTRL_BIT_EX_IRQ_RESET | | ||
1298 | ME4600_AI_CTRL_BIT_FULLSCALE | ME4600_AI_CTRL_BIT_OFFSET); | ||
1299 | |||
1300 | // Send it to register. | ||
1301 | outl(tmp | ctrl, instance->ctrl_reg); | ||
1302 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
1303 | instance->ctrl_reg - instance->reg_base, tmp | ctrl); | ||
1304 | |||
1305 | // Enable channel fifo -> data fifo in stream_start(). | ||
1306 | ctrl |= ME4600_AI_CTRL_BIT_CHANNEL_FIFO; | ||
1307 | outl(tmp | ctrl, instance->ctrl_reg); | ||
1308 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
1309 | instance->ctrl_reg - instance->reg_base, tmp | ctrl); | ||
1310 | spin_unlock_irqrestore(instance->ctrl_reg_lock, cpu_flags); | ||
1311 | |||
1312 | // Write the channel list | ||
1313 | for (i = 0; i < count; i++) { | ||
1314 | entry = config_list[i].iChannel; | ||
1315 | |||
1316 | switch (config_list[i].iStreamConfig) { | ||
1317 | case 0: //BIPOLAR 10V | ||
1318 | /* | ||
1319 | // ME4600_AI_LIST_RANGE_BIPOLAR_10 = 0x0000 | ||
1320 | // 'entry |= ME4600_AI_LIST_RANGE_BIPOLAR_10' <== Do nothing. Removed. | ||
1321 | entry |= ME4600_AI_LIST_RANGE_BIPOLAR_10; | ||
1322 | */ | ||
1323 | break; | ||
1324 | case 1: //UNIPOLAR 10V | ||
1325 | entry |= ME4600_AI_LIST_RANGE_UNIPOLAR_10; | ||
1326 | break; | ||
1327 | case 2: //BIPOLAR 2.5V | ||
1328 | entry |= ME4600_AI_LIST_RANGE_BIPOLAR_2_5; | ||
1329 | break; | ||
1330 | case 3: //UNIPOLAR 2.5V | ||
1331 | entry |= ME4600_AI_LIST_RANGE_UNIPOLAR_2_5; | ||
1332 | break; | ||
1333 | default: | ||
1334 | PERROR_CRITICAL("UNCHECK ERROR in config_list!\n"); | ||
1335 | PERROR_CRITICAL | ||
1336 | ("WRONG range\nPosition:%d Range:0x%04X\n", i, | ||
1337 | config_list[i].iStreamConfig); | ||
1338 | goto VERIFY_ERROR; | ||
1339 | break; | ||
1340 | } | ||
1341 | |||
1342 | switch (config_list[i].iRef) { | ||
1343 | case ME_REF_AI_GROUND: //SINGLE ENDED | ||
1344 | /* | ||
1345 | // ME4600_AI_LIST_INPUT_SINGLE_ENDED = 0x0000 | ||
1346 | // 'entry |= ME4600_AI_LIST_INPUT_SINGLE_ENDED' ==> Do nothing. Removed. | ||
1347 | entry |= ME4600_AI_LIST_INPUT_SINGLE_ENDED; | ||
1348 | */ break; | ||
1349 | case ME_REF_AI_DIFFERENTIAL: //DIFFERENTIAL | ||
1350 | entry |= ME4600_AI_LIST_INPUT_DIFFERENTIAL; | ||
1351 | break; | ||
1352 | default: | ||
1353 | PERROR_CRITICAL("UNCHECK ERROR in config_list!\n"); | ||
1354 | PERROR_CRITICAL | ||
1355 | ("WRONG reference\nPosition:%d Reference:0x%04X\n", | ||
1356 | i, config_list[i].iRef); | ||
1357 | goto VERIFY_ERROR; | ||
1358 | break; | ||
1359 | } | ||
1360 | |||
1361 | //Add last entry flag | ||
1362 | if (i == (count - 1)) { | ||
1363 | entry |= ME4600_AI_LIST_LAST_ENTRY; | ||
1364 | } | ||
1365 | |||
1366 | outl(entry, instance->channel_list_reg); | ||
1367 | PDEBUG_REG("channel_list_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
1368 | instance->reg_base, | ||
1369 | instance->channel_list_reg - instance->reg_base, | ||
1370 | entry); | ||
1371 | } | ||
1372 | |||
1373 | // Set triggering registers | ||
1374 | --acq_ticks; | ||
1375 | outl(acq_ticks, instance->chan_pre_timer_reg); | ||
1376 | PDEBUG_REG("chan_pre_timer_reg outl(0x%lX+0x%lX)=0x%llX\n", | ||
1377 | instance->reg_base, | ||
1378 | instance->chan_pre_timer_reg - instance->reg_base, | ||
1379 | acq_ticks); | ||
1380 | outl(acq_ticks, instance->scan_pre_timer_low_reg); | ||
1381 | PDEBUG_REG("scan_pre_timer_low_reg outl(0x%lX+0x%lX)=0x%llX\n", | ||
1382 | instance->reg_base, | ||
1383 | instance->scan_pre_timer_low_reg - instance->reg_base, | ||
1384 | acq_ticks & 0xFFFFFFFF); | ||
1385 | outl((acq_ticks >> 32), instance->scan_pre_timer_high_reg); | ||
1386 | PDEBUG_REG("scan_pre_timer_high_reg outl(0x%lX+0x%lX)=0x%llX\n", | ||
1387 | instance->reg_base, | ||
1388 | instance->scan_pre_timer_high_reg - instance->reg_base, | ||
1389 | (acq_ticks >> 32) & 0xFFFFFFFF); | ||
1390 | |||
1391 | // Set triggers | ||
1392 | switch (trigger->iAcqStartTrigType) { | ||
1393 | // Internal | ||
1394 | case ME_TRIG_TYPE_SW: | ||
1395 | // Nothing to set. | ||
1396 | break; | ||
1397 | |||
1398 | // External | ||
1399 | case ME_TRIG_TYPE_EXT_ANALOG: | ||
1400 | ctrl |= ME4600_AI_CTRL_BIT_EX_TRIG_ANALOG; | ||
1401 | case ME_TRIG_TYPE_EXT_DIGITAL: | ||
1402 | ctrl |= ME4600_AI_CTRL_BIT_EX_TRIG; | ||
1403 | |||
1404 | // External trigger needs edge's definition | ||
1405 | switch (trigger->iAcqStartTrigEdge) { | ||
1406 | case ME_TRIG_EDGE_RISING: | ||
1407 | // Nothing to set. | ||
1408 | break; | ||
1409 | |||
1410 | case ME_TRIG_EDGE_FALLING: | ||
1411 | ctrl |= ME4600_AI_CTRL_BIT_EX_TRIG_FALLING; | ||
1412 | break; | ||
1413 | |||
1414 | case ME_TRIG_EDGE_ANY: | ||
1415 | ctrl |= | ||
1416 | ME4600_AI_CTRL_BIT_EX_TRIG_FALLING | | ||
1417 | ME4600_AI_CTRL_BIT_EX_TRIG_BOTH; | ||
1418 | break; | ||
1419 | |||
1420 | default: | ||
1421 | PERROR_CRITICAL | ||
1422 | ("UNCHECK TRIGGER EDGE in triggers structure!\n"); | ||
1423 | PERROR_CRITICAL | ||
1424 | ("WRONG acquisition start trigger:0x%04X.\n", | ||
1425 | trigger->iAcqStartTrigEdge); | ||
1426 | err = ME_ERRNO_INVALID_ACQ_START_TRIG_EDGE; | ||
1427 | goto VERIFY_ERROR; | ||
1428 | break; | ||
1429 | } | ||
1430 | break; | ||
1431 | |||
1432 | default: | ||
1433 | PERROR_CRITICAL("UNCHECK TRIGGER in triggers structure!\n"); | ||
1434 | PERROR_CRITICAL("WRONG acquisition start trigger:0x%04X.\n", | ||
1435 | trigger->iAcqStartTrigType); | ||
1436 | err = ME_ERRNO_INVALID_ACQ_START_TRIG_TYPE; | ||
1437 | goto VERIFY_ERROR; | ||
1438 | break; | ||
1439 | } | ||
1440 | |||
1441 | switch (trigger->iScanStartTrigType) { | ||
1442 | case ME_TRIG_TYPE_TIMER: | ||
1443 | --scan_ticks; | ||
1444 | outl(scan_ticks, instance->scan_timer_low_reg); | ||
1445 | PDEBUG_REG("scan_timer_low_reg outl(0x%lX+0x%lX)=0x%llX\n", | ||
1446 | instance->reg_base, | ||
1447 | instance->scan_timer_low_reg - instance->reg_base, | ||
1448 | scan_ticks & 0xFFFFFFFF); | ||
1449 | outl((scan_ticks >> 32), instance->scan_timer_high_reg); | ||
1450 | PDEBUG_REG("scan_timer_high_reg outl(0x%lX+0x%lX)=0x%llX\n", | ||
1451 | instance->reg_base, | ||
1452 | instance->scan_timer_high_reg - instance->reg_base, | ||
1453 | (scan_ticks >> 32) & 0xFFFFFFFF); | ||
1454 | |||
1455 | if (trigger->iAcqStartTrigType == ME_TRIG_TYPE_SW) { | ||
1456 | ctrl |= ME4600_AI_CTRL_BIT_MODE_0; | ||
1457 | } else { | ||
1458 | ctrl |= ME4600_AI_CTRL_BIT_MODE_1; | ||
1459 | } | ||
1460 | break; | ||
1461 | |||
1462 | case ME_TRIG_TYPE_EXT_DIGITAL: | ||
1463 | case ME_TRIG_TYPE_EXT_ANALOG: | ||
1464 | outl(0, instance->scan_timer_low_reg); | ||
1465 | PDEBUG_REG("scan_timer_low_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
1466 | instance->reg_base, | ||
1467 | instance->scan_timer_low_reg - instance->reg_base, | ||
1468 | 0); | ||
1469 | outl(0, instance->scan_timer_high_reg); | ||
1470 | PDEBUG_REG("scan_timer_high_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
1471 | instance->reg_base, | ||
1472 | instance->scan_timer_high_reg - instance->reg_base, | ||
1473 | 0); | ||
1474 | ctrl |= ME4600_AI_CTRL_BIT_MODE_2; | ||
1475 | break; | ||
1476 | |||
1477 | case ME_TRIG_TYPE_FOLLOW: | ||
1478 | outl(0, instance->scan_timer_low_reg); | ||
1479 | PDEBUG_REG("scan_timer_low_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
1480 | instance->reg_base, | ||
1481 | instance->scan_timer_low_reg - instance->reg_base, | ||
1482 | 0); | ||
1483 | outl(0, instance->scan_timer_high_reg); | ||
1484 | PDEBUG_REG("scan_timer_high_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
1485 | instance->reg_base, | ||
1486 | instance->scan_timer_high_reg - instance->reg_base, | ||
1487 | 0); | ||
1488 | |||
1489 | if (trigger->iAcqStartTrigType == ME_TRIG_TYPE_SW) { | ||
1490 | ctrl |= ME4600_AI_CTRL_BIT_MODE_0; | ||
1491 | } else { | ||
1492 | ctrl |= ME4600_AI_CTRL_BIT_MODE_1; | ||
1493 | } | ||
1494 | break; | ||
1495 | |||
1496 | default: | ||
1497 | PERROR_CRITICAL("UNCHECK TRIGGER in triggers structure!\n"); | ||
1498 | PERROR_CRITICAL("WRONG scan start trigger:0x%04X.\n", | ||
1499 | trigger->iScanStartTrigType); | ||
1500 | err = ME_ERRNO_INVALID_SCAN_START_TRIG_TYPE; | ||
1501 | goto VERIFY_ERROR; | ||
1502 | break; | ||
1503 | } | ||
1504 | |||
1505 | switch (trigger->iConvStartTrigType) { | ||
1506 | |||
1507 | case ME_TRIG_TYPE_TIMER: | ||
1508 | --conv_ticks; | ||
1509 | outl(conv_ticks, instance->chan_timer_reg); | ||
1510 | PDEBUG_REG("chan_timer_reg outl(0x%lX+0x%lX)=0x%llX\n", | ||
1511 | instance->reg_base, | ||
1512 | instance->chan_timer_reg - instance->reg_base, | ||
1513 | conv_ticks); | ||
1514 | break; | ||
1515 | |||
1516 | case ME_TRIG_TYPE_EXT_DIGITAL: | ||
1517 | case ME_TRIG_TYPE_EXT_ANALOG: | ||
1518 | outl(0, instance->chan_timer_reg); | ||
1519 | PDEBUG_REG("chan_timer_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
1520 | instance->reg_base, | ||
1521 | instance->chan_timer_reg - instance->reg_base, 0); | ||
1522 | ctrl |= ME4600_AI_CTRL_BIT_MODE_0 | ME4600_AI_CTRL_BIT_MODE_1; | ||
1523 | break; | ||
1524 | |||
1525 | default: | ||
1526 | PERROR_CRITICAL("UNCHECK TRIGGER in triggers structure!\n"); | ||
1527 | PERROR_CRITICAL("WRONG conv start trigger:0x%04X.\n", | ||
1528 | trigger->iConvStartTrigType); | ||
1529 | err = ME_ERRNO_INVALID_CONV_START_TRIG_TYPE; | ||
1530 | goto VERIFY_ERROR; | ||
1531 | |||
1532 | break; | ||
1533 | } | ||
1534 | |||
1535 | //Sample & Hold feature | ||
1536 | if (flags & ME_IO_STREAM_CONFIG_SAMPLE_AND_HOLD) { | ||
1537 | if (instance->sh) { | ||
1538 | ctrl |= ME4600_AI_CTRL_BIT_SAMPLE_HOLD; | ||
1539 | } else { | ||
1540 | PERROR_CRITICAL("UNCHECK S&H feature!\n"); | ||
1541 | err = ME_ERRNO_INVALID_FLAGS; | ||
1542 | goto VERIFY_ERROR; | ||
1543 | } | ||
1544 | } | ||
1545 | //Enable IRQs sources but leave latches blocked. | ||
1546 | ctrl |= (ME4600_AI_CTRL_BIT_HF_IRQ | ME4600_AI_CTRL_BIT_SC_IRQ | ME4600_AI_CTRL_BIT_LE_IRQ); //The last IRQ source (ME4600_AI_CTRL_BIT_LE_IRQ) is unused! | ||
1547 | |||
1548 | //Everything is good. Finalize | ||
1549 | spin_lock_irqsave(instance->ctrl_reg_lock, cpu_flags); | ||
1550 | tmp = inl(instance->ctrl_reg); | ||
1551 | |||
1552 | //Preserve EXT IRQ and OFFSET settings. Clean other bits. | ||
1553 | tmp &= | ||
1554 | (ME4600_AI_CTRL_BIT_EX_IRQ | ME4600_AI_CTRL_BIT_EX_IRQ_RESET | | ||
1555 | ME4600_AI_CTRL_BIT_FULLSCALE | ME4600_AI_CTRL_BIT_OFFSET); | ||
1556 | |||
1557 | // write the control word | ||
1558 | outl(ctrl | tmp, instance->ctrl_reg); | ||
1559 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
1560 | instance->ctrl_reg - instance->reg_base, ctrl | tmp); | ||
1561 | spin_unlock_irqrestore(instance->ctrl_reg_lock, cpu_flags); | ||
1562 | |||
1563 | //Set the global parameters end exit. | ||
1564 | instance->chan_list_len = count; | ||
1565 | instance->fifo_irq_threshold = fifo_irq_threshold; | ||
1566 | |||
1567 | if (trigger->iAcqStopTrigType == ME_TRIG_TYPE_COUNT) { | ||
1568 | data_required = | ||
1569 | (unsigned long long)trigger->iAcqStopCount * | ||
1570 | (unsigned long long)count; | ||
1571 | if (data_required > UINT_MAX) | ||
1572 | data_required = UINT_MAX; | ||
1573 | instance->data_required = (unsigned int)data_required; | ||
1574 | } else if (trigger->iScanStopTrigType == ME_TRIG_TYPE_COUNT) | ||
1575 | instance->data_required = | ||
1576 | (unsigned long long)trigger->iScanStopCount; | ||
1577 | else | ||
1578 | instance->data_required = 0; | ||
1579 | |||
1580 | // Mark subdevice as configured to work in stream mode. | ||
1581 | instance->status = ai_status_stream_configured; | ||
1582 | |||
1583 | // Deinit single config. Set all entries to NOT_CONFIGURED. | ||
1584 | for (i = 0; i < instance->channels; i++) { | ||
1585 | instance->single_config[i].status = | ||
1586 | ME_SINGLE_CHANNEL_NOT_CONFIGURED; | ||
1587 | } | ||
1588 | |||
1589 | VERIFY_ERROR: // Error in code. Wrong setting check. This should never ever happend! | ||
1590 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
1591 | ERROR: // Error in settings. | ||
1592 | ME_SUBDEVICE_EXIT; | ||
1593 | |||
1594 | return err; | ||
1595 | } | ||
1596 | |||
1597 | static int me4600_ai_io_stream_new_values(me_subdevice_t * subdevice, | ||
1598 | struct file *filep, | ||
1599 | int time_out, int *count, int flags) | ||
1600 | { | ||
1601 | me4600_ai_subdevice_t *instance; | ||
1602 | int err = ME_ERRNO_SUCCESS; | ||
1603 | unsigned long t; | ||
1604 | unsigned long j; | ||
1605 | int volatile head; | ||
1606 | |||
1607 | PDEBUG("executed. idx=0\n"); | ||
1608 | |||
1609 | if (flags) { | ||
1610 | PERROR("Invalid flag specified.\n"); | ||
1611 | return ME_ERRNO_INVALID_FLAGS; | ||
1612 | } | ||
1613 | |||
1614 | if (time_out < 0) { | ||
1615 | PERROR("Invalid time_out specified.\n"); | ||
1616 | return ME_ERRNO_INVALID_TIMEOUT; | ||
1617 | } | ||
1618 | |||
1619 | if (time_out) { | ||
1620 | t = (time_out * HZ) / 1000; | ||
1621 | |||
1622 | if (t == 0) | ||
1623 | t = 1; | ||
1624 | } else { // Max time. | ||
1625 | t = LONG_MAX; | ||
1626 | } | ||
1627 | |||
1628 | instance = (me4600_ai_subdevice_t *) subdevice; | ||
1629 | |||
1630 | ME_SUBDEVICE_ENTER; | ||
1631 | |||
1632 | j = jiffies; | ||
1633 | |||
1634 | while (1) { | ||
1635 | // Only runing device can generate break. | ||
1636 | head = instance->circ_buf.head; | ||
1637 | wait_event_interruptible_timeout(instance->wait_queue, | ||
1638 | ((head != | ||
1639 | instance->circ_buf.head) | ||
1640 | || | ||
1641 | ((instance->status <= | ||
1642 | ai_status_stream_run_wait) | ||
1643 | && (instance->status >= | ||
1644 | ai_status_stream_end_wait))), | ||
1645 | t); | ||
1646 | |||
1647 | if (head != instance->circ_buf.head) { // New data in buffer. | ||
1648 | break; | ||
1649 | } else if (instance->status == ai_status_stream_end) { // End of work. | ||
1650 | break; | ||
1651 | } else if (instance->status == ai_status_stream_fifo_error) { | ||
1652 | err = ME_ERRNO_FIFO_BUFFER_OVERFLOW; | ||
1653 | break; | ||
1654 | } else if (instance->status == ai_status_stream_buffer_error) { | ||
1655 | err = ME_ERRNO_RING_BUFFER_OVERFLOW; | ||
1656 | break; | ||
1657 | } else if (instance->status == ai_status_stream_error) { | ||
1658 | err = ME_ERRNO_INTERNAL; | ||
1659 | break; | ||
1660 | } else if ((jiffies - j) >= t) { | ||
1661 | PERROR("Wait on values timed out.\n"); | ||
1662 | err = ME_ERRNO_TIMEOUT; | ||
1663 | break; | ||
1664 | } else if (signal_pending(current)) { | ||
1665 | PERROR("Wait on values interrupted from signal.\n"); | ||
1666 | err = ME_ERRNO_SIGNAL; | ||
1667 | break; | ||
1668 | } | ||
1669 | // Correct timeout. | ||
1670 | t -= jiffies - j; | ||
1671 | } | ||
1672 | |||
1673 | *count = me_circ_buf_values(&instance->circ_buf); | ||
1674 | |||
1675 | ME_SUBDEVICE_EXIT; | ||
1676 | |||
1677 | return err; | ||
1678 | } | ||
1679 | |||
1680 | static int inline me4600_ai_io_stream_read_get_value(me4600_ai_subdevice_t * | ||
1681 | instance, int *values, | ||
1682 | const int count, | ||
1683 | const int flags) | ||
1684 | { | ||
1685 | int n; | ||
1686 | int i; | ||
1687 | uint32_t value; | ||
1688 | |||
1689 | ///Checking how many datas can be copied. | ||
1690 | n = me_circ_buf_values(&instance->circ_buf); | ||
1691 | if (n <= 0) | ||
1692 | return 0; | ||
1693 | |||
1694 | if (n > count) | ||
1695 | n = count; | ||
1696 | |||
1697 | if (flags & ME_IO_STREAM_READ_FRAMES) { | ||
1698 | if (n < instance->chan_list_len) //Not enough data! | ||
1699 | return 0; | ||
1700 | n -= n % instance->chan_list_len; | ||
1701 | } | ||
1702 | |||
1703 | for (i = 0; i < n; i++) { | ||
1704 | value = *(instance->circ_buf.buf + instance->circ_buf.tail); | ||
1705 | if (put_user(value, values + i)) { | ||
1706 | PERROR("Cannot copy new values to user.\n"); | ||
1707 | return -ME_ERRNO_INTERNAL; | ||
1708 | } | ||
1709 | instance->circ_buf.tail++; | ||
1710 | instance->circ_buf.tail &= instance->circ_buf.mask; | ||
1711 | } | ||
1712 | return n; | ||
1713 | } | ||
1714 | |||
1715 | static int me4600_ai_io_stream_read(me_subdevice_t * subdevice, | ||
1716 | struct file *filep, | ||
1717 | int read_mode, | ||
1718 | int *values, int *count, int flags) | ||
1719 | { | ||
1720 | me4600_ai_subdevice_t *instance; | ||
1721 | int err = ME_ERRNO_SUCCESS; | ||
1722 | int ret; | ||
1723 | |||
1724 | int c = *count; | ||
1725 | int min = c; | ||
1726 | |||
1727 | PDEBUG("executed. idx=0\n"); | ||
1728 | |||
1729 | if (flags & ~ME_IO_STREAM_READ_FRAMES) { | ||
1730 | PERROR("Invalid flag specified.\n"); | ||
1731 | return ME_ERRNO_INVALID_FLAGS; | ||
1732 | } | ||
1733 | |||
1734 | if (!values || !count) { | ||
1735 | PERROR("Request has invalid pointer.\n"); | ||
1736 | return ME_ERRNO_INVALID_POINTER; | ||
1737 | } | ||
1738 | |||
1739 | if (c < 0) { | ||
1740 | PERROR("Request has invalid value's counter.\n"); | ||
1741 | return ME_ERRNO_INVALID_VALUE_COUNT; | ||
1742 | } | ||
1743 | |||
1744 | if ((read_mode != ME_READ_MODE_BLOCKING) | ||
1745 | && (read_mode != ME_READ_MODE_NONBLOCKING)) { | ||
1746 | PERROR("Invalid read mode specified.\n"); | ||
1747 | return ME_ERRNO_INVALID_READ_MODE; | ||
1748 | } | ||
1749 | |||
1750 | if (c == 0) { //You get what you want! Nothing more or less. | ||
1751 | return ME_ERRNO_SUCCESS; | ||
1752 | } | ||
1753 | |||
1754 | instance = (me4600_ai_subdevice_t *) subdevice; | ||
1755 | ME_SUBDEVICE_ENTER; | ||
1756 | |||
1757 | //Check if subdevice is configured. | ||
1758 | if (instance->chan_list_len <= 0) { | ||
1759 | PERROR("Subdevice wasn't configured.\n"); | ||
1760 | ME_SUBDEVICE_EXIT; | ||
1761 | return ME_ERRNO_PREVIOUS_CONFIG; | ||
1762 | } | ||
1763 | |||
1764 | if (flags & ME_IO_STREAM_READ_FRAMES) { | ||
1765 | if (c < instance->chan_list_len) { //Not enough data requested. | ||
1766 | PERROR | ||
1767 | ("When using FRAME_READ mode minimal size is defined by channel list.\n"); | ||
1768 | ME_SUBDEVICE_EXIT; | ||
1769 | return ME_ERRNO_INVALID_VALUE_COUNT; | ||
1770 | } | ||
1771 | } | ||
1772 | |||
1773 | if (c > (ME4600_AI_CIRC_BUF_COUNT - instance->chan_list_len)) { // To return acceptable amount of data when user pass too big value. | ||
1774 | min = ME4600_AI_CIRC_BUF_COUNT - instance->chan_list_len; | ||
1775 | } | ||
1776 | |||
1777 | if (flags & ME_IO_STREAM_READ_FRAMES) { | ||
1778 | //Wait for whole list. | ||
1779 | if (read_mode == ME_READ_MODE_BLOCKING) { | ||
1780 | min = c - (c % instance->chan_list_len); | ||
1781 | } | ||
1782 | |||
1783 | if (read_mode == ME_READ_MODE_NONBLOCKING) { | ||
1784 | min = instance->chan_list_len; | ||
1785 | } | ||
1786 | } | ||
1787 | |||
1788 | if ((inl(instance->status_reg) & ME4600_AI_STATUS_BIT_FSM)) { //Working | ||
1789 | //If blocking mode -> wait for data. | ||
1790 | if ((me_circ_buf_values(&instance->circ_buf) < min) | ||
1791 | && (read_mode == ME_READ_MODE_BLOCKING)) { | ||
1792 | wait_event_interruptible(instance->wait_queue, | ||
1793 | ((me_circ_buf_values | ||
1794 | (&instance->circ_buf) >= min) | ||
1795 | || !(inl(instance->status_reg) | ||
1796 | & | ||
1797 | ME4600_AI_STATUS_BIT_FSM))); | ||
1798 | |||
1799 | if (signal_pending(current)) { | ||
1800 | PERROR | ||
1801 | ("Wait on values interrupted from signal.\n"); | ||
1802 | err = ME_ERRNO_SIGNAL; | ||
1803 | } | ||
1804 | } | ||
1805 | } | ||
1806 | |||
1807 | ret = me4600_ai_io_stream_read_get_value(instance, values, c, flags); | ||
1808 | if (ret < 0) { | ||
1809 | err = -ret; | ||
1810 | *count = 0; | ||
1811 | } else if (ret == 0) { | ||
1812 | *count = 0; | ||
1813 | if (instance->status == ai_status_stream_fifo_error) { | ||
1814 | err = ME_ERRNO_FIFO_BUFFER_OVERFLOW; | ||
1815 | instance->status = ai_status_stream_end; | ||
1816 | } else if (instance->status == ai_status_stream_buffer_error) { | ||
1817 | err = ME_ERRNO_RING_BUFFER_OVERFLOW; | ||
1818 | instance->status = ai_status_stream_end; | ||
1819 | } else if (instance->status == ai_status_stream_end) { | ||
1820 | err = ME_ERRNO_SUBDEVICE_NOT_RUNNING; | ||
1821 | } else if (instance->status == ai_status_stream_error) { | ||
1822 | err = ME_ERRNO_INTERNAL; | ||
1823 | } else if (instance->status == ai_status_none) { | ||
1824 | PDEBUG("Stream canceled.\n"); | ||
1825 | err = ME_ERRNO_INTERNAL; | ||
1826 | } | ||
1827 | } else { | ||
1828 | *count = ret; | ||
1829 | } | ||
1830 | |||
1831 | ME_SUBDEVICE_EXIT; | ||
1832 | |||
1833 | return err; | ||
1834 | } | ||
1835 | |||
1836 | /** @brief Stop aqusation. Preserve FIFOs. | ||
1837 | * | ||
1838 | * @param instance The subdevice instance (pointer). | ||
1839 | */ | ||
1840 | |||
1841 | static int ai_stop_immediately(me4600_ai_subdevice_t * instance) | ||
1842 | { | ||
1843 | unsigned long cpu_flags = 0; | ||
1844 | volatile uint32_t ctrl; | ||
1845 | const int timeout = HZ / 10; //100ms | ||
1846 | int i; | ||
1847 | |||
1848 | for (i = 0; i <= timeout; i++) { | ||
1849 | spin_lock_irqsave(instance->ctrl_reg_lock, cpu_flags); | ||
1850 | ctrl = inl(instance->ctrl_reg); | ||
1851 | ctrl &= ~ME4600_AI_CTRL_BIT_STOP; | ||
1852 | ctrl |= | ||
1853 | (ME4600_AI_CTRL_BIT_IMMEDIATE_STOP | | ||
1854 | ME4600_AI_CTRL_BIT_HF_IRQ_RESET | | ||
1855 | ME4600_AI_CTRL_BIT_SC_IRQ_RESET); | ||
1856 | outl(ctrl, instance->ctrl_reg); | ||
1857 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
1858 | instance->reg_base, | ||
1859 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
1860 | spin_unlock_irqrestore(instance->ctrl_reg_lock, cpu_flags); | ||
1861 | |||
1862 | if (!(inl(instance->status_reg) & ME4600_AI_STATUS_BIT_FSM)) { // Exit. | ||
1863 | break; | ||
1864 | } | ||
1865 | |||
1866 | PINFO("Wait for stop: %d\n", i + 1); | ||
1867 | //Still working! | ||
1868 | set_current_state(TASK_INTERRUPTIBLE); | ||
1869 | schedule_timeout(1); | ||
1870 | } | ||
1871 | |||
1872 | if (i > timeout) { | ||
1873 | PERROR_CRITICAL("FSM IS BUSY!\n"); | ||
1874 | return ME_ERRNO_INTERNAL; | ||
1875 | } | ||
1876 | |||
1877 | return ME_ERRNO_SUCCESS; | ||
1878 | } | ||
1879 | |||
1880 | static int me4600_ai_io_stream_start(me_subdevice_t * subdevice, | ||
1881 | struct file *filep, | ||
1882 | int start_mode, int time_out, int flags) | ||
1883 | { | ||
1884 | me4600_ai_subdevice_t *instance; | ||
1885 | int err = ME_ERRNO_SUCCESS; | ||
1886 | unsigned long cpu_flags = 0; | ||
1887 | unsigned long ref; | ||
1888 | unsigned long delay = 0; | ||
1889 | |||
1890 | volatile uint32_t tmp; | ||
1891 | |||
1892 | PDEBUG("executed. idx=0\n"); | ||
1893 | |||
1894 | instance = (me4600_ai_subdevice_t *) subdevice; | ||
1895 | |||
1896 | if (flags) { | ||
1897 | PERROR("Invalid flag specified.\n"); | ||
1898 | return ME_ERRNO_INVALID_FLAGS; | ||
1899 | } | ||
1900 | |||
1901 | if ((start_mode != ME_START_MODE_BLOCKING) | ||
1902 | && (start_mode != ME_START_MODE_NONBLOCKING)) { | ||
1903 | PERROR("Invalid start mode specified.\n"); | ||
1904 | return ME_ERRNO_INVALID_START_MODE; | ||
1905 | } | ||
1906 | |||
1907 | if (time_out < 0) { | ||
1908 | PERROR("Invalid timeout specified.\n"); | ||
1909 | return ME_ERRNO_INVALID_TIMEOUT; | ||
1910 | } | ||
1911 | |||
1912 | if (time_out) { | ||
1913 | delay = (time_out * HZ) / 1000; | ||
1914 | |||
1915 | if (delay == 0) | ||
1916 | delay = 1; | ||
1917 | } | ||
1918 | |||
1919 | ME_SUBDEVICE_ENTER | ||
1920 | spin_lock_irqsave(instance->ctrl_reg_lock, cpu_flags); | ||
1921 | |||
1922 | tmp = inl(instance->ctrl_reg); | ||
1923 | |||
1924 | if ((tmp & ME4600_AI_STATUS_BIT_FSM)) { | ||
1925 | PERROR("Conversion is already running.\n"); | ||
1926 | spin_unlock_irqrestore(instance->ctrl_reg_lock, cpu_flags); | ||
1927 | err = ME_ERRNO_SUBDEVICE_BUSY; | ||
1928 | goto ERROR; | ||
1929 | } | ||
1930 | |||
1931 | if (instance->chan_list_len == 0) { //Not configured! | ||
1932 | PERROR("Subdevice is not configured to work in stream mode!\n"); | ||
1933 | spin_unlock_irqrestore(instance->ctrl_reg_lock, cpu_flags); | ||
1934 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
1935 | goto ERROR; | ||
1936 | } | ||
1937 | |||
1938 | if (!(tmp & (ME4600_AI_CTRL_BIT_MODE_0 | ME4600_AI_CTRL_BIT_MODE_1 | ME4600_AI_CTRL_BIT_MODE_2))) { //Mode 0 = single work => no stream config | ||
1939 | PERROR("Subdevice is configured to work in single mode.\n"); | ||
1940 | spin_unlock_irqrestore(instance->ctrl_reg_lock, cpu_flags); | ||
1941 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
1942 | goto ERROR; | ||
1943 | } | ||
1944 | //Reset stop bits. | ||
1945 | tmp |= ME4600_AI_CTRL_BIT_IMMEDIATE_STOP | ME4600_AI_CTRL_BIT_STOP; | ||
1946 | outl(tmp, instance->ctrl_reg); | ||
1947 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
1948 | instance->ctrl_reg - instance->reg_base, tmp); | ||
1949 | |||
1950 | //Start datas' FIFO. | ||
1951 | tmp |= ME4600_AI_CTRL_BIT_DATA_FIFO; | ||
1952 | //Free stop bits. | ||
1953 | tmp &= ~(ME4600_AI_CTRL_BIT_IMMEDIATE_STOP | ME4600_AI_CTRL_BIT_STOP); | ||
1954 | outl(tmp, instance->ctrl_reg); | ||
1955 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
1956 | instance->ctrl_reg - instance->reg_base, tmp); | ||
1957 | spin_unlock_irqrestore(instance->ctrl_reg_lock, cpu_flags); | ||
1958 | |||
1959 | //Cancel control task | ||
1960 | PDEBUG("Cancel control task.\n"); | ||
1961 | instance->ai_control_task_flag = 0; | ||
1962 | cancel_delayed_work(&instance->ai_control_task); | ||
1963 | |||
1964 | //Set the starting values. | ||
1965 | instance->ISM.global_read = 0; | ||
1966 | instance->ISM.read = 0; | ||
1967 | //Clear circular buffer | ||
1968 | instance->circ_buf.head = 0; | ||
1969 | instance->circ_buf.tail = 0; | ||
1970 | |||
1971 | //Set everything. | ||
1972 | ai_data_acquisition_logic(instance); | ||
1973 | |||
1974 | //Set status to 'wait for start' | ||
1975 | instance->status = ai_status_stream_run_wait; | ||
1976 | |||
1977 | // Set control task's timeout | ||
1978 | instance->timeout.delay = delay; | ||
1979 | instance->timeout.start_time = jiffies; | ||
1980 | |||
1981 | //Lets go! Start work | ||
1982 | inl(instance->start_reg); | ||
1983 | PDEBUG_REG("start_reg inl(0x%lX+0x%lX)\n", instance->reg_base, | ||
1984 | instance->start_reg - instance->reg_base); | ||
1985 | |||
1986 | // Schedule control task | ||
1987 | instance->ai_control_task_flag = 1; | ||
1988 | queue_delayed_work(instance->me4600_workqueue, | ||
1989 | &instance->ai_control_task, 1); | ||
1990 | |||
1991 | PDEVELOP("Delay:%ld\n", delay); | ||
1992 | |||
1993 | if (start_mode == ME_START_MODE_BLOCKING) { //Wait for start. | ||
1994 | ref = jiffies; | ||
1995 | //Only runing process will interrupt this call. Events are signaled when status change. Extra timeout add for safe reason. | ||
1996 | wait_event_interruptible_timeout(instance->wait_queue, | ||
1997 | (instance->status != | ||
1998 | ai_status_stream_run_wait), | ||
1999 | (delay) ? delay + | ||
2000 | 1 : LONG_MAX); | ||
2001 | |||
2002 | if ((instance->status != ai_status_stream_run) | ||
2003 | && (instance->status != ai_status_stream_end)) { | ||
2004 | PDEBUG("Starting stream canceled. %d\n", | ||
2005 | instance->status); | ||
2006 | err = ME_ERRNO_CANCELLED; | ||
2007 | } | ||
2008 | |||
2009 | if (signal_pending(current)) { | ||
2010 | PERROR("Wait on start of state machine interrupted.\n"); | ||
2011 | instance->status = ai_status_none; | ||
2012 | ai_stop_isr(instance); | ||
2013 | err = ME_ERRNO_SIGNAL; | ||
2014 | } else if ((delay) && ((jiffies - ref) > delay)) { | ||
2015 | if (instance->status != ai_status_stream_run) { | ||
2016 | if (instance->status == ai_status_stream_end) { | ||
2017 | PDEBUG("Timeout reached.\n"); | ||
2018 | } else if ((jiffies - ref) > delay + 1) { | ||
2019 | PERROR | ||
2020 | ("Timeout reached. Not handled by control task!\n"); | ||
2021 | ai_stop_isr(instance); | ||
2022 | instance->status = | ||
2023 | ai_status_stream_error; | ||
2024 | } else { | ||
2025 | PERROR | ||
2026 | ("Timeout reached. Signal come but status is strange: %d\n", | ||
2027 | instance->status); | ||
2028 | ai_stop_isr(instance); | ||
2029 | instance->status = | ||
2030 | ai_status_stream_error; | ||
2031 | } | ||
2032 | |||
2033 | instance->ai_control_task_flag = 0; | ||
2034 | cancel_delayed_work(&instance->ai_control_task); | ||
2035 | err = ME_ERRNO_TIMEOUT; | ||
2036 | } | ||
2037 | } | ||
2038 | } | ||
2039 | #ifdef MEDEBUG_INFO | ||
2040 | tmp = inl(instance->ctrl_reg); | ||
2041 | PDEBUG_REG("ctrl_reg inl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
2042 | instance->ctrl_reg - instance->reg_base, tmp); | ||
2043 | |||
2044 | PINFO("STATUS_BIT_FSM=%s.\n", | ||
2045 | (tmp & ME4600_AI_STATUS_BIT_FSM) ? "on" : "off"); | ||
2046 | PINFO("CTRL_BIT_HF_IRQ=%s.\n", | ||
2047 | (tmp & ME4600_AI_CTRL_BIT_HF_IRQ) ? "enable" : "disable"); | ||
2048 | PINFO("CTRL_BIT_HF_IRQ_RESET=%s.\n", | ||
2049 | (tmp & ME4600_AI_CTRL_BIT_HF_IRQ_RESET) ? "reset" : "work"); | ||
2050 | PINFO("CTRL_BIT_SC_IRQ=%s.\n", | ||
2051 | (tmp & ME4600_AI_CTRL_BIT_SC_IRQ) ? "enable" : "disable"); | ||
2052 | PINFO("CTRL_BIT_SC_RELOAD=%s.\n", | ||
2053 | (tmp & ME4600_AI_CTRL_BIT_SC_RELOAD) ? "on" : "off"); | ||
2054 | PINFO("CTRL_BIT_SC_IRQ_RESET=%s.\n", | ||
2055 | (tmp & ME4600_AI_CTRL_BIT_SC_IRQ_RESET) ? "reset" : "work"); | ||
2056 | #endif | ||
2057 | |||
2058 | ERROR: | ||
2059 | ME_SUBDEVICE_EXIT; | ||
2060 | |||
2061 | return err; | ||
2062 | } | ||
2063 | |||
2064 | static int me4600_ai_io_stream_status(me_subdevice_t * subdevice, | ||
2065 | struct file *filep, | ||
2066 | int wait, | ||
2067 | int *status, int *values, int flags) | ||
2068 | { | ||
2069 | me4600_ai_subdevice_t *instance; | ||
2070 | int err = ME_ERRNO_SUCCESS; | ||
2071 | |||
2072 | PDEBUG("executed. idx=0\n"); | ||
2073 | |||
2074 | instance = (me4600_ai_subdevice_t *) subdevice; | ||
2075 | |||
2076 | if (flags) { | ||
2077 | PERROR("Invalid flag specified.\n"); | ||
2078 | return ME_ERRNO_INVALID_FLAGS; | ||
2079 | } | ||
2080 | |||
2081 | ME_SUBDEVICE_ENTER; | ||
2082 | |||
2083 | switch (instance->status) { | ||
2084 | case ai_status_single_configured: | ||
2085 | case ai_status_stream_configured: | ||
2086 | case ai_status_stream_end: | ||
2087 | case ai_status_stream_fifo_error: | ||
2088 | case ai_status_stream_buffer_error: | ||
2089 | case ai_status_stream_error: | ||
2090 | *status = ME_STATUS_IDLE; | ||
2091 | break; | ||
2092 | |||
2093 | case ai_status_stream_run_wait: | ||
2094 | case ai_status_stream_run: | ||
2095 | case ai_status_stream_end_wait: | ||
2096 | *status = ME_STATUS_BUSY; | ||
2097 | break; | ||
2098 | |||
2099 | case ai_status_none: | ||
2100 | default: | ||
2101 | *status = | ||
2102 | (inl(instance->status_reg) & ME4600_AI_STATUS_BIT_FSM) ? | ||
2103 | ME_STATUS_BUSY : ME_STATUS_IDLE; | ||
2104 | break; | ||
2105 | } | ||
2106 | |||
2107 | if ((wait == ME_WAIT_IDLE) && (*status == ME_STATUS_BUSY)) { | ||
2108 | // Only runing process will interrupt this call. Events are signaled when status change. Extra timeout add for safe reason. | ||
2109 | wait_event_interruptible_timeout(instance->wait_queue, | ||
2110 | ((instance->status != | ||
2111 | ai_status_stream_run_wait) | ||
2112 | && (instance->status != | ||
2113 | ai_status_stream_run) | ||
2114 | && (instance->status != | ||
2115 | ai_status_stream_end_wait)), | ||
2116 | LONG_MAX); | ||
2117 | |||
2118 | if (instance->status != ai_status_stream_end) { | ||
2119 | PDEBUG("Wait for IDLE canceled. %d\n", | ||
2120 | instance->status); | ||
2121 | err = ME_ERRNO_CANCELLED; | ||
2122 | } | ||
2123 | |||
2124 | if (signal_pending(current)) { | ||
2125 | PERROR("Wait for IDLE interrupted.\n"); | ||
2126 | instance->status = ai_status_none; | ||
2127 | ai_stop_isr(instance); | ||
2128 | err = ME_ERRNO_SIGNAL; | ||
2129 | } | ||
2130 | |||
2131 | *status = ME_STATUS_IDLE; | ||
2132 | } | ||
2133 | |||
2134 | *values = me_circ_buf_values(&instance->circ_buf); | ||
2135 | PDEBUG("me_circ_buf_values(&instance->circ_buf)=%d.\n", *values); | ||
2136 | |||
2137 | ME_SUBDEVICE_EXIT; | ||
2138 | |||
2139 | return err; | ||
2140 | } | ||
2141 | |||
2142 | static int me4600_ai_io_stream_stop(me_subdevice_t * subdevice, | ||
2143 | struct file *filep, | ||
2144 | int stop_mode, int flags) | ||
2145 | { | ||
2146 | /** | ||
2147 | @note Stop is implemented only in blocking mode. | ||
2148 | @note Function return when state machine is stoped. | ||
2149 | */ | ||
2150 | me4600_ai_subdevice_t *instance; | ||
2151 | unsigned long cpu_flags; | ||
2152 | uint32_t ctrl; | ||
2153 | int ret; | ||
2154 | |||
2155 | PDEBUG("executed. idx=0\n"); | ||
2156 | |||
2157 | if (flags) { | ||
2158 | PERROR("Invalid flag specified.\n"); | ||
2159 | return ME_ERRNO_INVALID_FLAGS; | ||
2160 | } | ||
2161 | |||
2162 | if ((stop_mode != ME_STOP_MODE_IMMEDIATE) | ||
2163 | && (stop_mode != ME_STOP_MODE_LAST_VALUE)) { | ||
2164 | PERROR("Invalid stop mode specified.\n"); | ||
2165 | return ME_ERRNO_INVALID_STOP_MODE; | ||
2166 | } | ||
2167 | |||
2168 | instance = (me4600_ai_subdevice_t *) subdevice; | ||
2169 | |||
2170 | ME_SUBDEVICE_ENTER; | ||
2171 | |||
2172 | // Mark as stopping. => Software stop. | ||
2173 | instance->status = ai_status_stream_end_wait; | ||
2174 | |||
2175 | if (stop_mode == ME_STOP_MODE_IMMEDIATE) { | ||
2176 | ret = ai_stop_immediately(instance); | ||
2177 | |||
2178 | if (ret) { | ||
2179 | PERROR("FSM is still busy.\n"); | ||
2180 | ME_SUBDEVICE_EXIT; | ||
2181 | return ME_ERRNO_SUBDEVICE_BUSY; | ||
2182 | } | ||
2183 | instance->ai_control_task_flag = 0; | ||
2184 | |||
2185 | } else if (stop_mode == ME_STOP_MODE_LAST_VALUE) { | ||
2186 | // Set stop bit in registry. | ||
2187 | spin_lock_irqsave(instance->ctrl_reg_lock, cpu_flags); | ||
2188 | ctrl = inl(instance->ctrl_reg); | ||
2189 | ctrl |= ME4600_AI_CTRL_BIT_STOP; | ||
2190 | outl(ctrl, instance->ctrl_reg); | ||
2191 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2192 | instance->reg_base, | ||
2193 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
2194 | spin_unlock_irqrestore(instance->ctrl_reg_lock, cpu_flags); | ||
2195 | |||
2196 | // Only runing process will interrupt this call. Events are signaled when status change. | ||
2197 | wait_event_interruptible_timeout(instance->wait_queue, | ||
2198 | (instance->status != | ||
2199 | ai_status_stream_end_wait), | ||
2200 | LONG_MAX); | ||
2201 | |||
2202 | if (instance->status != ai_status_stream_end) { | ||
2203 | PDEBUG("Stopping stream canceled.\n"); | ||
2204 | ret = ME_ERRNO_CANCELLED; | ||
2205 | } | ||
2206 | |||
2207 | if (signal_pending(current)) { | ||
2208 | PERROR("Stopping stream interrupted.\n"); | ||
2209 | instance->status = ai_status_none; | ||
2210 | ret = ME_ERRNO_SIGNAL; | ||
2211 | } | ||
2212 | // End of work. | ||
2213 | ai_stop_immediately(instance); | ||
2214 | |||
2215 | } | ||
2216 | |||
2217 | ret = ai_read_data_pooling(instance); | ||
2218 | if (ret > 0) { // Everything fine. More datas put to software buffer. | ||
2219 | instance->status = ai_status_stream_end; | ||
2220 | ret = ME_ERRNO_SUCCESS; | ||
2221 | // Signal that we put last data to software buffer. | ||
2222 | wake_up_interruptible_all(&instance->wait_queue); | ||
2223 | } else if (ret == 0) { // Everything fine. No more datas in FIFO. | ||
2224 | instance->status = ai_status_stream_end; | ||
2225 | ret = ME_ERRNO_SUCCESS; | ||
2226 | } else if (ret == -ME_ERRNO_RING_BUFFER_OVERFLOW) { // Stop is unsuccessful, buffer is overflow. | ||
2227 | instance->status = ai_status_stream_buffer_error; | ||
2228 | ret = ME_ERRNO_SUCCESS; | ||
2229 | } else { // Stop is unsuccessful | ||
2230 | instance->status = ai_status_stream_end; | ||
2231 | ret = -ret; | ||
2232 | } | ||
2233 | |||
2234 | ME_SUBDEVICE_EXIT; | ||
2235 | |||
2236 | return ret; | ||
2237 | } | ||
2238 | |||
2239 | static int me4600_ai_query_range_by_min_max(me_subdevice_t * subdevice, | ||
2240 | int unit, | ||
2241 | int *min, | ||
2242 | int *max, int *maxdata, int *range) | ||
2243 | { | ||
2244 | me4600_ai_subdevice_t *instance; | ||
2245 | int i; | ||
2246 | int r = -1; | ||
2247 | int diff = 21E6; | ||
2248 | |||
2249 | PDEBUG("executed. idx=0\n"); | ||
2250 | |||
2251 | instance = (me4600_ai_subdevice_t *) subdevice; | ||
2252 | |||
2253 | if ((*max - *min) < 0) { | ||
2254 | PERROR("Invalid minimum and maximum values specified.\n"); | ||
2255 | return ME_ERRNO_INVALID_MIN_MAX; | ||
2256 | } | ||
2257 | |||
2258 | if ((unit == ME_UNIT_VOLT) || (unit == ME_UNIT_ANY)) { | ||
2259 | for (i = 0; i < instance->ranges_len; i++) { | ||
2260 | if ((instance->ranges[i].min <= *min) | ||
2261 | && ((instance->ranges[i].max + 1000) >= *max)) { | ||
2262 | if ((instance->ranges[i].max - | ||
2263 | instance->ranges[i].min) - (*max - *min) < | ||
2264 | diff) { | ||
2265 | r = i; | ||
2266 | diff = | ||
2267 | (instance->ranges[i].max - | ||
2268 | instance->ranges[i].min) - (*max - | ||
2269 | *min); | ||
2270 | } | ||
2271 | } | ||
2272 | } | ||
2273 | |||
2274 | if (r < 0) { | ||
2275 | PERROR("No matching range found.\n"); | ||
2276 | return ME_ERRNO_NO_RANGE; | ||
2277 | } else { | ||
2278 | *min = instance->ranges[r].min; | ||
2279 | *max = instance->ranges[r].max; | ||
2280 | *maxdata = ME4600_AI_MAX_DATA; | ||
2281 | *range = r; | ||
2282 | } | ||
2283 | } else { | ||
2284 | PERROR("Invalid physical unit specified.\n"); | ||
2285 | return ME_ERRNO_INVALID_UNIT; | ||
2286 | } | ||
2287 | |||
2288 | return ME_ERRNO_SUCCESS; | ||
2289 | } | ||
2290 | |||
2291 | static int me4600_ai_query_number_ranges(me_subdevice_t * subdevice, | ||
2292 | int unit, int *count) | ||
2293 | { | ||
2294 | me4600_ai_subdevice_t *instance; | ||
2295 | |||
2296 | PDEBUG("executed. idx=0\n"); | ||
2297 | |||
2298 | instance = (me4600_ai_subdevice_t *) subdevice; | ||
2299 | |||
2300 | if ((unit == ME_UNIT_VOLT) || (unit == ME_UNIT_ANY)) { | ||
2301 | *count = instance->ranges_len; | ||
2302 | } else { | ||
2303 | *count = 0; | ||
2304 | } | ||
2305 | |||
2306 | return ME_ERRNO_SUCCESS; | ||
2307 | } | ||
2308 | |||
2309 | static int me4600_ai_query_range_info(me_subdevice_t * subdevice, | ||
2310 | int range, | ||
2311 | int *unit, | ||
2312 | int *min, int *max, int *maxdata) | ||
2313 | { | ||
2314 | me4600_ai_subdevice_t *instance; | ||
2315 | |||
2316 | PDEBUG("executed. idx=0\n"); | ||
2317 | |||
2318 | instance = (me4600_ai_subdevice_t *) subdevice; | ||
2319 | |||
2320 | if ((range < instance->ranges_len) && (range >= 0)) { | ||
2321 | *unit = ME_UNIT_VOLT; | ||
2322 | *min = instance->ranges[range].min; | ||
2323 | *max = instance->ranges[range].max; | ||
2324 | *maxdata = ME4600_AI_MAX_DATA; | ||
2325 | } else { | ||
2326 | PERROR("Invalid range number specified.\n"); | ||
2327 | return ME_ERRNO_INVALID_RANGE; | ||
2328 | } | ||
2329 | |||
2330 | return ME_ERRNO_SUCCESS; | ||
2331 | } | ||
2332 | |||
2333 | static int me4600_ai_query_timer(me_subdevice_t * subdevice, | ||
2334 | int timer, | ||
2335 | int *base_frequency, | ||
2336 | long long *min_ticks, long long *max_ticks) | ||
2337 | { | ||
2338 | me4600_ai_subdevice_t *instance; | ||
2339 | |||
2340 | PDEBUG("executed. idx=0\n"); | ||
2341 | |||
2342 | instance = (me4600_ai_subdevice_t *) subdevice; | ||
2343 | |||
2344 | switch (timer) { | ||
2345 | |||
2346 | case ME_TIMER_ACQ_START: | ||
2347 | *base_frequency = ME4600_AI_BASE_FREQUENCY; | ||
2348 | *min_ticks = ME4600_AI_MIN_ACQ_TICKS; | ||
2349 | *max_ticks = ME4600_AI_MAX_ACQ_TICKS; | ||
2350 | break; | ||
2351 | |||
2352 | case ME_TIMER_SCAN_START: | ||
2353 | *base_frequency = ME4600_AI_BASE_FREQUENCY; | ||
2354 | *min_ticks = ME4600_AI_MIN_SCAN_TICKS; | ||
2355 | *max_ticks = ME4600_AI_MAX_SCAN_TICKS; | ||
2356 | break; | ||
2357 | |||
2358 | case ME_TIMER_CONV_START: | ||
2359 | *base_frequency = ME4600_AI_BASE_FREQUENCY; | ||
2360 | *min_ticks = ME4600_AI_MIN_CHAN_TICKS; | ||
2361 | *max_ticks = ME4600_AI_MAX_CHAN_TICKS; | ||
2362 | break; | ||
2363 | |||
2364 | default: | ||
2365 | PERROR("Invalid timer specified.(0x%04x)\n", timer); | ||
2366 | |||
2367 | return ME_ERRNO_INVALID_TIMER; | ||
2368 | } | ||
2369 | |||
2370 | return ME_ERRNO_SUCCESS; | ||
2371 | } | ||
2372 | |||
2373 | static int me4600_ai_query_number_channels(me_subdevice_t * subdevice, | ||
2374 | int *number) | ||
2375 | { | ||
2376 | me4600_ai_subdevice_t *instance; | ||
2377 | |||
2378 | PDEBUG("executed. idx=0\n"); | ||
2379 | |||
2380 | instance = (me4600_ai_subdevice_t *) subdevice; | ||
2381 | *number = instance->channels; | ||
2382 | |||
2383 | return ME_ERRNO_SUCCESS; | ||
2384 | } | ||
2385 | |||
2386 | static int me4600_ai_query_subdevice_type(me_subdevice_t * subdevice, | ||
2387 | int *type, int *subtype) | ||
2388 | { | ||
2389 | PDEBUG("executed. idx=0\n"); | ||
2390 | |||
2391 | *type = ME_TYPE_AI; | ||
2392 | *subtype = ME_SUBTYPE_STREAMING; | ||
2393 | |||
2394 | return ME_ERRNO_SUCCESS; | ||
2395 | } | ||
2396 | |||
2397 | static int me4600_ai_query_subdevice_caps(me_subdevice_t * subdevice, int *caps) | ||
2398 | { | ||
2399 | PDEBUG("executed. idx=0\n"); | ||
2400 | |||
2401 | *caps = | ||
2402 | ME_CAPS_AI_TRIG_SYNCHRONOUS | ME_CAPS_AI_FIFO | | ||
2403 | ME_CAPS_AI_FIFO_THRESHOLD; | ||
2404 | |||
2405 | return ME_ERRNO_SUCCESS; | ||
2406 | } | ||
2407 | |||
2408 | static int me4600_ai_query_subdevice_caps_args(struct me_subdevice *subdevice, | ||
2409 | int cap, int *args, int count) | ||
2410 | { | ||
2411 | me4600_ai_subdevice_t *instance; | ||
2412 | int err = ME_ERRNO_SUCCESS; | ||
2413 | |||
2414 | instance = (me4600_ai_subdevice_t *) subdevice; | ||
2415 | |||
2416 | PDEBUG("executed. idx=0\n"); | ||
2417 | |||
2418 | if (count != 1) { | ||
2419 | PERROR("Invalid capability argument count.\n"); | ||
2420 | return ME_ERRNO_INVALID_CAP_ARG_COUNT; | ||
2421 | } | ||
2422 | |||
2423 | switch (cap) { | ||
2424 | case ME_CAP_AI_FIFO_SIZE: | ||
2425 | args[0] = ME4600_AI_FIFO_COUNT; | ||
2426 | break; | ||
2427 | |||
2428 | case ME_CAP_AI_BUFFER_SIZE: | ||
2429 | args[0] = | ||
2430 | (instance->circ_buf.buf) ? ME4600_AI_CIRC_BUF_COUNT : 0; | ||
2431 | break; | ||
2432 | |||
2433 | default: | ||
2434 | PERROR("Invalid capability.\n"); | ||
2435 | err = ME_ERRNO_INVALID_CAP; | ||
2436 | args[0] = 0; | ||
2437 | } | ||
2438 | |||
2439 | return err; | ||
2440 | } | ||
2441 | |||
2442 | void ai_limited_isr(me4600_ai_subdevice_t * instance, const uint32_t irq_status, | ||
2443 | const uint32_t ctrl_status) | ||
2444 | { | ||
2445 | int to_read; | ||
2446 | |||
2447 | if (!instance->fifo_irq_threshold) { //No threshold provided. SC ends work. HF need reseting. | ||
2448 | if (irq_status & ME4600_IRQ_STATUS_BIT_SC) { | ||
2449 | if (ai_read_data(instance, instance->ISM.next) != instance->ISM.next) { //ERROR! | ||
2450 | PERROR | ||
2451 | ("Limited amounts aqusition with TH=0: Circular buffer full!\n"); | ||
2452 | instance->status = | ||
2453 | ai_status_stream_buffer_error; | ||
2454 | } else { | ||
2455 | instance->status = ai_status_stream_end; | ||
2456 | } | ||
2457 | //End of work. | ||
2458 | ai_stop_isr(instance); | ||
2459 | } else if (irq_status & ME4600_IRQ_STATUS_BIT_AI_HF) { | ||
2460 | instance->ISM.global_read += ME4600_AI_FIFO_HALF; | ||
2461 | |||
2462 | if (ai_read_data(instance, ME4600_AI_FIFO_HALF) != ME4600_AI_FIFO_HALF) { //ERROR! | ||
2463 | PERROR | ||
2464 | ("Limited amounts aqusition with TH = 0: Circular buffer full!\n"); | ||
2465 | //End of work. | ||
2466 | ai_stop_isr(instance); | ||
2467 | instance->status = | ||
2468 | ai_status_stream_buffer_error; | ||
2469 | } else { | ||
2470 | //Continue. | ||
2471 | ai_limited_ISM(instance, irq_status); | ||
2472 | } | ||
2473 | } | ||
2474 | //Signal user. | ||
2475 | wake_up_interruptible_all(&instance->wait_queue); | ||
2476 | } else //if(instance->fifo_irq_threshold) | ||
2477 | { | ||
2478 | if (irq_status & ME4600_IRQ_STATUS_BIT_SC) { | ||
2479 | instance->ISM.read = 0; | ||
2480 | if ((instance->fifo_irq_threshold < ME4600_AI_FIFO_HALF) | ||
2481 | && (!(ctrl_status & ME4600_AI_STATUS_BIT_HF_DATA))) | ||
2482 | { | ||
2483 | to_read = | ||
2484 | ME4600_AI_FIFO_HALF - | ||
2485 | (ME4600_AI_FIFO_HALF % | ||
2486 | instance->fifo_irq_threshold); | ||
2487 | PDEBUG | ||
2488 | ("Limited amounts aqusition with TH != 0: Not fast enough data aqusition! correction=%d\n", | ||
2489 | to_read); | ||
2490 | } else { | ||
2491 | to_read = instance->ISM.next; | ||
2492 | } | ||
2493 | instance->ISM.global_read += to_read; | ||
2494 | |||
2495 | ai_reschedule_SC(instance); | ||
2496 | |||
2497 | if (ai_read_data(instance, to_read) != to_read) { //ERROR! | ||
2498 | PERROR | ||
2499 | ("Limited amounts aqusition with TH != 0: Circular buffer full!\n"); | ||
2500 | //End of work. | ||
2501 | ai_stop_isr(instance); | ||
2502 | instance->status = | ||
2503 | ai_status_stream_buffer_error; | ||
2504 | } else { | ||
2505 | //Continue. | ||
2506 | ai_limited_ISM(instance, irq_status); | ||
2507 | } | ||
2508 | |||
2509 | //Signal user. | ||
2510 | wake_up_interruptible_all(&instance->wait_queue); | ||
2511 | } else if (irq_status & ME4600_IRQ_STATUS_BIT_AI_HF) { | ||
2512 | instance->ISM.read += ME4600_AI_FIFO_HALF; | ||
2513 | instance->ISM.global_read += ME4600_AI_FIFO_HALF; | ||
2514 | |||
2515 | if (ai_read_data(instance, ME4600_AI_FIFO_HALF) != ME4600_AI_FIFO_HALF) { //ERROR! | ||
2516 | PERROR | ||
2517 | ("Limited amounts aqusition with TH != 0: Circular buffer full!\n"); | ||
2518 | ai_stop_isr(instance); | ||
2519 | |||
2520 | instance->status = | ||
2521 | ai_status_stream_buffer_error; | ||
2522 | //Signal user. | ||
2523 | wake_up_interruptible_all(&instance-> | ||
2524 | wait_queue); | ||
2525 | } else { | ||
2526 | //Countinue. | ||
2527 | ai_limited_ISM(instance, irq_status); | ||
2528 | } | ||
2529 | } | ||
2530 | |||
2531 | if (instance->ISM.global_read >= instance->data_required) { //End of work. Next paranoid pice of code: '>=' instead od '==' only to be sure. | ||
2532 | ai_stop_isr(instance); | ||
2533 | if (instance->status < ai_status_stream_end) { | ||
2534 | instance->status = ai_status_stream_end; | ||
2535 | } | ||
2536 | #ifdef MEDEBUG_ERROR | ||
2537 | if (instance->ISM.global_read > instance->data_required) { //This is security check case. This should never ever happend! | ||
2538 | PERROR | ||
2539 | ("Limited amounts aqusition: Read more data than necessary! data_required=%d < read=%d\n", | ||
2540 | instance->data_required, | ||
2541 | instance->ISM.global_read); | ||
2542 | //Signal error (warning??). | ||
2543 | instance->status = ai_status_stream_error; | ||
2544 | } | ||
2545 | #endif | ||
2546 | } | ||
2547 | } | ||
2548 | } | ||
2549 | |||
2550 | void ai_infinite_isr(me4600_ai_subdevice_t * instance, | ||
2551 | const uint32_t irq_status, const uint32_t ctrl_status) | ||
2552 | { | ||
2553 | int to_read; | ||
2554 | |||
2555 | if (irq_status & ME4600_IRQ_STATUS_BIT_SC) { //next chunck of data -> read fifo | ||
2556 | //Set new state in ISM. | ||
2557 | if ((instance->fifo_irq_threshold < ME4600_AI_FIFO_HALF) && (!(ctrl_status & ME4600_AI_STATUS_BIT_HF_DATA))) { //There is more data than we ecpected. Propably we aren't fast enough. Read as many as possible. | ||
2558 | if (instance->fifo_irq_threshold) { | ||
2559 | to_read = | ||
2560 | ME4600_AI_FIFO_HALF - | ||
2561 | (ME4600_AI_FIFO_HALF % | ||
2562 | instance->fifo_irq_threshold); | ||
2563 | if (to_read > instance->fifo_irq_threshold) { | ||
2564 | PDEBUG | ||
2565 | ("Infinite aqusition: Not fast enough data aqusition! TH != 0: correction=%d\n", | ||
2566 | to_read); | ||
2567 | } | ||
2568 | } else { //No threshold specified. | ||
2569 | to_read = ME4600_AI_FIFO_HALF; | ||
2570 | } | ||
2571 | } else { | ||
2572 | to_read = instance->ISM.next; | ||
2573 | } | ||
2574 | |||
2575 | instance->ISM.read += to_read; | ||
2576 | |||
2577 | //Get data | ||
2578 | if (ai_read_data(instance, to_read) != to_read) { //ERROR! | ||
2579 | PERROR("Infinite aqusition: Circular buffer full!\n"); | ||
2580 | ai_stop_isr(instance); | ||
2581 | instance->status = ai_status_stream_buffer_error; | ||
2582 | } else { | ||
2583 | ai_infinite_ISM(instance); | ||
2584 | instance->ISM.global_read += instance->ISM.read; | ||
2585 | instance->ISM.read = 0; | ||
2586 | } | ||
2587 | |||
2588 | //Signal data to user | ||
2589 | wake_up_interruptible_all(&instance->wait_queue); | ||
2590 | } else if (irq_status & ME4600_IRQ_STATUS_BIT_AI_HF) { //fifo is half full -> read fifo Large blocks only! | ||
2591 | instance->ISM.read += ME4600_AI_FIFO_HALF; | ||
2592 | |||
2593 | if (ai_read_data(instance, ME4600_AI_FIFO_HALF) != ME4600_AI_FIFO_HALF) { //ERROR! | ||
2594 | PERROR("Infinite aqusition: Circular buffer full!\n"); | ||
2595 | ai_stop_isr(instance); | ||
2596 | instance->status = ai_status_stream_buffer_error; | ||
2597 | |||
2598 | //Signal it. | ||
2599 | wake_up_interruptible_all(&instance->wait_queue); | ||
2600 | } else { | ||
2601 | ai_infinite_ISM(instance); | ||
2602 | } | ||
2603 | } | ||
2604 | } | ||
2605 | |||
2606 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) | ||
2607 | static irqreturn_t me4600_ai_isr(int irq, void *dev_id) | ||
2608 | #else | ||
2609 | static irqreturn_t me4600_ai_isr(int irq, void *dev_id, struct pt_regs *regs) | ||
2610 | #endif | ||
2611 | { /// @note This is time critical function! | ||
2612 | uint32_t irq_status; | ||
2613 | uint32_t ctrl_status; | ||
2614 | me4600_ai_subdevice_t *instance = dev_id; | ||
2615 | //int to_read; | ||
2616 | |||
2617 | PDEBUG("executed. idx=0\n"); | ||
2618 | |||
2619 | if (irq != instance->irq) { | ||
2620 | PERROR("Incorrect interrupt num: %d.\n", irq); | ||
2621 | return IRQ_NONE; | ||
2622 | } | ||
2623 | |||
2624 | irq_status = inl(instance->irq_status_reg); | ||
2625 | if (! | ||
2626 | (irq_status & | ||
2627 | (ME4600_IRQ_STATUS_BIT_AI_HF | ME4600_IRQ_STATUS_BIT_SC))) { | ||
2628 | #ifdef MEDEBUG_INFO | ||
2629 | if ((irq_status & (ME4600_IRQ_STATUS_BIT_AI_HF | ME4600_IRQ_STATUS_BIT_SC | ME4600_IRQ_STATUS_BIT_LE)) == ME4600_IRQ_STATUS_BIT_LE) { //This is security check case. LE is unused. This should never ever happend. | ||
2630 | PINFO | ||
2631 | ("%ld Shared interrupt. %s(): irq_status_reg=LE_IRQ\n", | ||
2632 | jiffies, __FUNCTION__); | ||
2633 | } else { | ||
2634 | PINFO | ||
2635 | ("%ld Shared interrupt. %s(): irq_status_reg=0x%04X\n", | ||
2636 | jiffies, __FUNCTION__, irq_status); | ||
2637 | } | ||
2638 | #endif | ||
2639 | return IRQ_NONE; | ||
2640 | } | ||
2641 | |||
2642 | if (!instance->circ_buf.buf) { //Security check. | ||
2643 | PERROR_CRITICAL("CIRCULAR BUFFER NOT EXISTS!\n"); | ||
2644 | ai_stop_isr(instance); | ||
2645 | return IRQ_HANDLED; | ||
2646 | } | ||
2647 | //Get the status register. | ||
2648 | ctrl_status = inl(instance->status_reg); | ||
2649 | |||
2650 | #ifdef MEDEBUG_INFO | ||
2651 | if (irq_status & ME4600_IRQ_STATUS_BIT_AI_HF) | ||
2652 | PINFO("HF interrupt active\n"); | ||
2653 | if (irq_status & ME4600_IRQ_STATUS_BIT_SC) | ||
2654 | PINFO("SC interrupt active\n"); | ||
2655 | if (irq_status & ME4600_IRQ_STATUS_BIT_LE) | ||
2656 | PINFO("LE interrupt active\n"); | ||
2657 | #endif | ||
2658 | |||
2659 | //This is safety check! | ||
2660 | if ((irq_status & ME4600_IRQ_STATUS_BIT_AI_HF) | ||
2661 | && (ctrl_status & ME4600_AI_STATUS_BIT_HF_DATA)) { | ||
2662 | PDEBUG("HF interrupt active but FIFO under half\n"); | ||
2663 | //Reset HF interrupt latch. | ||
2664 | spin_lock(instance->ctrl_reg_lock); | ||
2665 | outl(ctrl_status | ME4600_AI_CTRL_BIT_HF_IRQ_RESET, | ||
2666 | instance->ctrl_reg); | ||
2667 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2668 | instance->reg_base, | ||
2669 | instance->ctrl_reg - instance->reg_base, | ||
2670 | ctrl_status); | ||
2671 | outl(ctrl_status, instance->ctrl_reg); | ||
2672 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2673 | instance->reg_base, | ||
2674 | instance->ctrl_reg - instance->reg_base, | ||
2675 | ctrl_status); | ||
2676 | spin_unlock(instance->ctrl_reg_lock); | ||
2677 | return IRQ_HANDLED; | ||
2678 | } | ||
2679 | #ifdef MEDEBUG_INFO | ||
2680 | PINFO("STATUS_BIT_FSM=%s.\n", | ||
2681 | (ctrl_status & ME4600_AI_STATUS_BIT_FSM) ? "on" : "off"); | ||
2682 | |||
2683 | PINFO("STATUS_BIT_EF_CHANNEL=%s.\n", | ||
2684 | (ctrl_status & ME4600_AI_STATUS_BIT_EF_CHANNEL) ? "not empty" : | ||
2685 | "empty"); | ||
2686 | PINFO("STATUS_BIT_HF_CHANNEL=%s.\n", | ||
2687 | (ctrl_status & ME4600_AI_STATUS_BIT_HF_CHANNEL) ? " < HF" : | ||
2688 | " > HF"); | ||
2689 | PINFO("STATUS_BIT_FF_CHANNEL=%s.\n", | ||
2690 | (ctrl_status & ME4600_AI_STATUS_BIT_FF_CHANNEL) ? "not full" : | ||
2691 | "full"); | ||
2692 | |||
2693 | PINFO("STATUS_BIT_EF_DATA=%s.\n", | ||
2694 | (ctrl_status & ME4600_AI_STATUS_BIT_EF_DATA) ? "not empty" : | ||
2695 | "empty"); | ||
2696 | PINFO("STATUS_BIT_HF_DATA=%s.\n", | ||
2697 | (ctrl_status & ME4600_AI_STATUS_BIT_HF_DATA) ? " < HF" : " > HF"); | ||
2698 | PINFO("STATUS_BIT_FF_DATA=%s.\n", | ||
2699 | (ctrl_status & ME4600_AI_STATUS_BIT_FF_DATA) ? "not full" : | ||
2700 | "full"); | ||
2701 | |||
2702 | PINFO("CTRL_BIT_HF_IRQ=%s.\n", | ||
2703 | (ctrl_status & ME4600_AI_CTRL_BIT_HF_IRQ) ? "enable" : "disable"); | ||
2704 | PINFO("CTRL_BIT_HF_IRQ_RESET=%s.\n", | ||
2705 | (ctrl_status & ME4600_AI_CTRL_BIT_HF_IRQ_RESET) ? "reset" : | ||
2706 | "work"); | ||
2707 | PINFO("CTRL_BIT_SC_IRQ=%s.\n", | ||
2708 | (ctrl_status & ME4600_AI_CTRL_BIT_SC_IRQ) ? "enable" : "disable"); | ||
2709 | PINFO("CTRL_BIT_SC_RELOAD=%s.\n", | ||
2710 | (ctrl_status & ME4600_AI_CTRL_BIT_SC_RELOAD) ? "on" : "off"); | ||
2711 | PINFO("CTRL_BIT_SC_IRQ_RESET=%s.\n", | ||
2712 | (ctrl_status & ME4600_AI_CTRL_BIT_SC_IRQ_RESET) ? "reset" : | ||
2713 | "work"); | ||
2714 | #endif | ||
2715 | |||
2716 | //Look for overflow error. | ||
2717 | if (!(ctrl_status & ME4600_AI_STATUS_BIT_FF_DATA)) { | ||
2718 | //FIFO is full. Read datas and reset all settings. | ||
2719 | PERROR("FIFO overflow.\n"); | ||
2720 | ai_read_data(instance, ME4600_AI_FIFO_COUNT); | ||
2721 | ai_stop_isr(instance); | ||
2722 | |||
2723 | instance->status = ai_status_stream_fifo_error; | ||
2724 | //Signal it. | ||
2725 | wake_up_interruptible_all(&instance->wait_queue); | ||
2726 | |||
2727 | return IRQ_HANDLED; | ||
2728 | } | ||
2729 | |||
2730 | if (!instance->data_required) { //This is infinite aqusition. | ||
2731 | #ifdef MEDEBUG_ERROR | ||
2732 | if ((irq_status & | ||
2733 | (ME4600_IRQ_STATUS_BIT_AI_HF | ME4600_IRQ_STATUS_BIT_SC)) | ||
2734 | == | ||
2735 | (ME4600_IRQ_STATUS_BIT_AI_HF | ME4600_IRQ_STATUS_BIT_SC)) { | ||
2736 | ///In infinite mode only one interrupt source should be reported! | ||
2737 | PERROR | ||
2738 | ("Error in ISM! Infinite aqusition: HF and SC interrupts active! threshold=%d next=%d ctrl=0x%04X irq_status_reg=0x%04X", | ||
2739 | instance->fifo_irq_threshold, instance->ISM.next, | ||
2740 | ctrl_status, irq_status); | ||
2741 | } | ||
2742 | #endif | ||
2743 | |||
2744 | ai_infinite_isr(instance, irq_status, ctrl_status); | ||
2745 | |||
2746 | #ifdef MEDEBUG_INFO | ||
2747 | ctrl_status = inl(instance->ctrl_reg); | ||
2748 | #endif | ||
2749 | } else { | ||
2750 | |||
2751 | ai_limited_isr(instance, irq_status, ctrl_status); | ||
2752 | ctrl_status = inl(instance->status_reg); | ||
2753 | if (!(ctrl_status & (ME4600_AI_STATUS_BIT_HF_DATA | ME4600_AI_CTRL_BIT_HF_IRQ_RESET))) { //HF active, but we have more than half already => HF will never come | ||
2754 | PDEBUG | ||
2755 | ("MISSED HF. data_required=%d ISM.read=%d ISM.global=%d ISM.next=%d\n", | ||
2756 | instance->data_required, instance->ISM.read, | ||
2757 | instance->ISM.global_read, instance->ISM.next); | ||
2758 | ai_limited_isr(instance, ME4600_IRQ_STATUS_BIT_AI_HF, | ||
2759 | ctrl_status); | ||
2760 | } | ||
2761 | } | ||
2762 | |||
2763 | #ifdef MEDEBUG_INFO | ||
2764 | PINFO("STATUS_BIT_FSM=%s.\n", | ||
2765 | (ctrl_status & ME4600_AI_STATUS_BIT_FSM) ? "on" : "off"); | ||
2766 | |||
2767 | PINFO("STATUS_BIT_EF_CHANNEL=%s.\n", | ||
2768 | (ctrl_status & ME4600_AI_STATUS_BIT_EF_CHANNEL) ? "not empty" : | ||
2769 | "empty"); | ||
2770 | PINFO("STATUS_BIT_HF_CHANNEL=%s.\n", | ||
2771 | (ctrl_status & ME4600_AI_STATUS_BIT_HF_CHANNEL) ? " < HF" : | ||
2772 | " > HF"); | ||
2773 | PINFO("STATUS_BIT_FF_CHANNEL=%s.\n", | ||
2774 | (ctrl_status & ME4600_AI_STATUS_BIT_FF_CHANNEL) ? "not full" : | ||
2775 | "full"); | ||
2776 | |||
2777 | PINFO("STATUS_BIT_EF_DATA=%s.\n", | ||
2778 | (ctrl_status & ME4600_AI_STATUS_BIT_EF_DATA) ? "not empty" : | ||
2779 | "empty"); | ||
2780 | PINFO("STATUS_BIT_HF_DATA=%s.\n", | ||
2781 | (ctrl_status & ME4600_AI_STATUS_BIT_HF_DATA) ? " < HF" : " > HF"); | ||
2782 | PINFO("STATUS_BIT_FF_DATA=%s.\n", | ||
2783 | (ctrl_status & ME4600_AI_STATUS_BIT_FF_DATA) ? "not full" : | ||
2784 | "full"); | ||
2785 | |||
2786 | PINFO("CTRL_BIT_HF_IRQ_RESET=%s.\n", | ||
2787 | (ctrl_status & ME4600_AI_CTRL_BIT_HF_IRQ_RESET) ? "reset" : | ||
2788 | "work"); | ||
2789 | PINFO("CTRL_BIT_SC_IRQ=%s.\n", | ||
2790 | (ctrl_status & ME4600_AI_CTRL_BIT_SC_IRQ) ? "enable" : "disable"); | ||
2791 | PINFO("CTRL_BIT_SC_RELOAD=%s.\n", | ||
2792 | (ctrl_status & ME4600_AI_CTRL_BIT_SC_RELOAD) ? "on" : "off"); | ||
2793 | PINFO("CTRL_BIT_SC_IRQ_RESET=%s.\n", | ||
2794 | (ctrl_status & ME4600_AI_CTRL_BIT_SC_IRQ_RESET) ? "reset" : | ||
2795 | "work"); | ||
2796 | PINFO("%ld END\n", jiffies); | ||
2797 | #endif | ||
2798 | |||
2799 | return IRQ_HANDLED; | ||
2800 | } | ||
2801 | |||
2802 | /** @brief Stop aqusation of data. Reset interrupts' laches. Clear data's FIFO. | ||
2803 | * | ||
2804 | * @param instance The subdevice instance (pointer). | ||
2805 | */ | ||
2806 | void inline ai_stop_isr(me4600_ai_subdevice_t * instance) | ||
2807 | { /// @note This is soft time critical function! | ||
2808 | register uint32_t tmp; | ||
2809 | |||
2810 | spin_lock(instance->ctrl_reg_lock); | ||
2811 | //Stop all. Reset interrupt laches. Reset data FIFO. | ||
2812 | tmp = inl(instance->ctrl_reg); | ||
2813 | tmp |= | ||
2814 | (ME4600_AI_CTRL_BIT_IMMEDIATE_STOP | ME4600_AI_CTRL_BIT_HF_IRQ_RESET | ||
2815 | | ME4600_AI_CTRL_BIT_LE_IRQ_RESET | | ||
2816 | ME4600_AI_CTRL_BIT_SC_IRQ_RESET); | ||
2817 | tmp &= ~ME4600_AI_CTRL_BIT_DATA_FIFO; | ||
2818 | outl(tmp, instance->ctrl_reg); | ||
2819 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
2820 | instance->ctrl_reg - instance->reg_base, tmp); | ||
2821 | spin_unlock(instance->ctrl_reg_lock); | ||
2822 | } | ||
2823 | |||
2824 | /** @brief Copy data from fifo to circular buffer. | ||
2825 | * | ||
2826 | * @param instance The subdevice instance (pointer). | ||
2827 | * @param count The number of requested data. | ||
2828 | * | ||
2829 | * @return On success: Number of copied values. | ||
2830 | * @return On error: -ME_ERRNO_RING_BUFFER_OVERFLOW. | ||
2831 | */ | ||
2832 | static int inline ai_read_data(me4600_ai_subdevice_t * instance, | ||
2833 | const int count) | ||
2834 | { /// @note This is time critical function! | ||
2835 | int c = count; | ||
2836 | int empty_space; | ||
2837 | int copied = 0; | ||
2838 | int i, j; | ||
2839 | |||
2840 | empty_space = me_circ_buf_space_to_end(&instance->circ_buf); | ||
2841 | if (empty_space <= 0) { | ||
2842 | PDEBUG("Circular buffer full.\n"); | ||
2843 | return -ME_ERRNO_RING_BUFFER_OVERFLOW; | ||
2844 | } | ||
2845 | |||
2846 | if (empty_space < c) { //Copy first part. Max to end of buffer. | ||
2847 | PDEBUG | ||
2848 | ("Try to copy %d values from FIFO to circular buffer (pass 1).\n", | ||
2849 | empty_space); | ||
2850 | for (i = 0; i < empty_space; i++) { | ||
2851 | *(instance->circ_buf.buf + instance->circ_buf.head) = | ||
2852 | (inw(instance->data_reg) ^ 0x8000); | ||
2853 | instance->circ_buf.head++; | ||
2854 | } | ||
2855 | instance->circ_buf.head &= instance->circ_buf.mask; | ||
2856 | c -= empty_space; | ||
2857 | copied = empty_space; | ||
2858 | |||
2859 | empty_space = me_circ_buf_space_to_end(&instance->circ_buf); | ||
2860 | } | ||
2861 | |||
2862 | if (empty_space > 0) { | ||
2863 | j = (empty_space < c) ? empty_space : c; | ||
2864 | PDEBUG | ||
2865 | ("Try to copy %d values from FIFO to circular buffer (pass 2).\n", | ||
2866 | c); | ||
2867 | for (i = 0; i < j; i++) { | ||
2868 | *(instance->circ_buf.buf + instance->circ_buf.head) = | ||
2869 | (inw(instance->data_reg) ^ 0x8000); | ||
2870 | instance->circ_buf.head++; | ||
2871 | } | ||
2872 | instance->circ_buf.head &= instance->circ_buf.mask; | ||
2873 | copied += j; | ||
2874 | } | ||
2875 | return copied; | ||
2876 | } | ||
2877 | |||
2878 | void inline ai_infinite_ISM(me4600_ai_subdevice_t * instance) | ||
2879 | { /// @note This is time critical function! | ||
2880 | register volatile uint32_t ctrl_set, ctrl_reset, tmp; | ||
2881 | |||
2882 | if (instance->fifo_irq_threshold < ME4600_AI_FIFO_MAX_SC) { // Only sample counter with reloadnig is working. Reset it. | ||
2883 | PINFO | ||
2884 | ("Only sample counter with reloadnig is working. Reset it.\n"); | ||
2885 | ctrl_set = ME4600_AI_CTRL_BIT_SC_IRQ_RESET; | ||
2886 | ctrl_reset = ~ME4600_AI_CTRL_BIT_SC_IRQ_RESET; | ||
2887 | } else if (instance->fifo_irq_threshold == instance->ISM.read) { //This is SC interrupt for large block. The whole section is done. Reset SC_IRQ an HF_IRQ and start everything again from beginning. | ||
2888 | PINFO | ||
2889 | ("This is SC interrupt for large block. The whole section is done. Reset SC_IRQ an HF_IRQ and start everything again from beginning.\n"); | ||
2890 | ctrl_set = | ||
2891 | ME4600_AI_CTRL_BIT_SC_IRQ_RESET | | ||
2892 | ME4600_AI_CTRL_BIT_HF_IRQ_RESET; | ||
2893 | ctrl_reset = | ||
2894 | ~(ME4600_AI_CTRL_BIT_SC_IRQ_RESET | | ||
2895 | ME4600_AI_CTRL_BIT_HF_IRQ_RESET); | ||
2896 | } else if (instance->fifo_irq_threshold >= (ME4600_AI_FIFO_MAX_SC + instance->ISM.read)) { //This is HF interrupt for large block.The next interrupt should be from HF, also. Reset HF. | ||
2897 | PINFO | ||
2898 | ("This is HF interrupt for large block.The next interrupt should be from HF, also. Reset HF.\n"); | ||
2899 | ctrl_set = ME4600_AI_CTRL_BIT_HF_IRQ_RESET; | ||
2900 | ctrl_reset = ~ME4600_AI_CTRL_BIT_HF_IRQ_RESET; | ||
2901 | } else { //This is HF interrupt for large block.The next interrupt should be from SC. Don't reset HF! | ||
2902 | PINFO | ||
2903 | ("This is HF interrupt for large block.The next interrupt should be from SC. Don't reset HF!\n"); | ||
2904 | ctrl_set = ME4600_AI_CTRL_BIT_HF_IRQ_RESET; | ||
2905 | ctrl_reset = 0xFFFFFFFF; | ||
2906 | } | ||
2907 | |||
2908 | //Reset interrupt latch. | ||
2909 | spin_lock(instance->ctrl_reg_lock); | ||
2910 | tmp = inl(instance->ctrl_reg); | ||
2911 | PINFO("ctrl=0x%x ctrl_set=0x%x ctrl_reset=0x%x\n", tmp, ctrl_set, | ||
2912 | ctrl_reset); | ||
2913 | tmp |= ctrl_set; | ||
2914 | outl(tmp, instance->ctrl_reg); | ||
2915 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
2916 | instance->ctrl_reg - instance->reg_base, tmp); | ||
2917 | if (ctrl_reset != 0xFFFFFFFF) { | ||
2918 | outl(tmp & ctrl_reset, instance->ctrl_reg); | ||
2919 | PDEBUG_REG("ctrl_reset outl(0x%lX+0x%lX)=0x%x\n", | ||
2920 | instance->reg_base, | ||
2921 | instance->ctrl_reg - instance->reg_base, | ||
2922 | tmp & ctrl_reset); | ||
2923 | } | ||
2924 | spin_unlock(instance->ctrl_reg_lock); | ||
2925 | |||
2926 | } | ||
2927 | |||
2928 | void inline ai_limited_ISM(me4600_ai_subdevice_t * instance, | ||
2929 | uint32_t irq_status) | ||
2930 | { /// @note This is time critical function! | ||
2931 | register volatile uint32_t ctrl_set, ctrl_reset = 0xFFFFFFFF, tmp; | ||
2932 | |||
2933 | if (!instance->fifo_irq_threshold) { //No threshold provided. SC ends work. | ||
2934 | PINFO("No threshold provided. SC ends work.\n"); | ||
2935 | ctrl_set = ME4600_AI_CTRL_BIT_HF_IRQ_RESET; | ||
2936 | if (instance->data_required > (ME4600_AI_FIFO_COUNT - 1 + instance->ISM.global_read)) { //HF need reseting. | ||
2937 | ctrl_reset &= ~ME4600_AI_CTRL_BIT_HF_IRQ_RESET; | ||
2938 | } | ||
2939 | } else //if(instance->fifo_irq_threshold) | ||
2940 | { | ||
2941 | if (irq_status & ME4600_IRQ_STATUS_BIT_AI_HF) { | ||
2942 | PINFO("Threshold provided. Clear HF latch.\n"); | ||
2943 | ctrl_set = ME4600_AI_CTRL_BIT_HF_IRQ_RESET; | ||
2944 | |||
2945 | if (instance->fifo_irq_threshold >= (ME4600_AI_FIFO_MAX_SC + instance->ISM.read)) { //This is not the last one. HF need reseting. | ||
2946 | PINFO | ||
2947 | ("The next interrupt is HF. HF need be activating.\n"); | ||
2948 | ctrl_reset = ~ME4600_AI_CTRL_BIT_HF_IRQ_RESET; | ||
2949 | } | ||
2950 | } | ||
2951 | |||
2952 | if (irq_status & ME4600_IRQ_STATUS_BIT_SC) { | ||
2953 | PINFO("Threshold provided. Restart SC.\n"); | ||
2954 | ctrl_set = ME4600_AI_CTRL_BIT_SC_IRQ_RESET; | ||
2955 | ctrl_reset &= ~ME4600_AI_CTRL_BIT_SC_IRQ_RESET; | ||
2956 | |||
2957 | if (instance->fifo_irq_threshold >= ME4600_AI_FIFO_MAX_SC) { //This is not the last one. HF need to be activating. | ||
2958 | PINFO | ||
2959 | ("The next interrupt is HF. HF need to be activating.\n"); | ||
2960 | ctrl_reset &= ~ME4600_AI_CTRL_BIT_HF_IRQ_RESET; | ||
2961 | } | ||
2962 | } | ||
2963 | } | ||
2964 | |||
2965 | //Reset interrupt latch. | ||
2966 | spin_lock(instance->ctrl_reg_lock); | ||
2967 | tmp = inl(instance->ctrl_reg); | ||
2968 | tmp |= ctrl_set; | ||
2969 | outl(tmp, instance->ctrl_reg); | ||
2970 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
2971 | instance->ctrl_reg - instance->reg_base, tmp); | ||
2972 | |||
2973 | if (ctrl_reset != 0xFFFFFFFF) { | ||
2974 | outl(tmp & ctrl_reset, instance->ctrl_reg); | ||
2975 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2976 | instance->reg_base, | ||
2977 | instance->ctrl_reg - instance->reg_base, | ||
2978 | tmp & ctrl_reset); | ||
2979 | } | ||
2980 | spin_unlock(instance->ctrl_reg_lock); | ||
2981 | |||
2982 | } | ||
2983 | |||
2984 | /** @brief Last chunck of datas. We must reschedule sample counter. | ||
2985 | * @note Last chunck. | ||
2986 | * Leaving SC_RELOAD doesn't do any harm, but in some bad case can make extra interrupts. | ||
2987 | * @warning When threshold is wrongly set some IRQ are lost.(!!!) | ||
2988 | */ | ||
2989 | void inline ai_reschedule_SC(me4600_ai_subdevice_t * instance) | ||
2990 | { | ||
2991 | register uint32_t rest; | ||
2992 | |||
2993 | if (instance->data_required <= instance->ISM.global_read) | ||
2994 | return; | ||
2995 | |||
2996 | rest = instance->data_required - instance->ISM.global_read; | ||
2997 | if (rest < instance->fifo_irq_threshold) { //End of work soon .... | ||
2998 | PDEBUG("Rescheduling SC from %d to %d.\n", | ||
2999 | instance->fifo_irq_threshold, rest); | ||
3000 | /// @note Write new value to SC <== DANGER! This is not safe solution! We can miss some inputs. | ||
3001 | outl(rest, instance->sample_counter_reg); | ||
3002 | PDEBUG_REG("sample_counter_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3003 | instance->reg_base, | ||
3004 | instance->sample_counter_reg - instance->reg_base, | ||
3005 | rest); | ||
3006 | instance->fifo_irq_threshold = rest; | ||
3007 | |||
3008 | if (rest < ME4600_AI_FIFO_MAX_SC) { | ||
3009 | instance->ISM.next = rest; | ||
3010 | } else { | ||
3011 | instance->ISM.next = rest % ME4600_AI_FIFO_HALF; | ||
3012 | if (instance->ISM.next + ME4600_AI_FIFO_HALF < | ||
3013 | ME4600_AI_FIFO_MAX_SC) { | ||
3014 | instance->ISM.next += ME4600_AI_FIFO_HALF; | ||
3015 | } | ||
3016 | } | ||
3017 | } | ||
3018 | } | ||
3019 | |||
3020 | /** Start the ISM. All must be reseted before enter to this function. */ | ||
3021 | void inline ai_data_acquisition_logic(me4600_ai_subdevice_t * instance) | ||
3022 | { | ||
3023 | register uint32_t tmp; | ||
3024 | |||
3025 | if (!instance->data_required) { //This is infinite aqusition. | ||
3026 | if (!instance->fifo_irq_threshold) { //No threshold provided. Set SC to 0.5*FIFO. Clear the SC's latch. | ||
3027 | //Set the sample counter | ||
3028 | outl(ME4600_AI_FIFO_HALF, instance->sample_counter_reg); | ||
3029 | PDEBUG_REG | ||
3030 | ("sample_counter_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3031 | instance->reg_base, | ||
3032 | instance->sample_counter_reg - instance->reg_base, | ||
3033 | ME4600_AI_FIFO_HALF); | ||
3034 | } else { //Threshold provided. Set SC to treshold. Clear the SC's latch. | ||
3035 | //Set the sample counter | ||
3036 | outl(instance->fifo_irq_threshold, | ||
3037 | instance->sample_counter_reg); | ||
3038 | PDEBUG_REG | ||
3039 | ("sample_counter_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3040 | instance->reg_base, | ||
3041 | instance->sample_counter_reg - instance->reg_base, | ||
3042 | instance->fifo_irq_threshold); | ||
3043 | } | ||
3044 | |||
3045 | if (instance->fifo_irq_threshold < ME4600_AI_FIFO_MAX_SC) { //Enable only sample counter's interrupt. Set reload bit. Clear the SC's latch. | ||
3046 | spin_lock(instance->ctrl_reg_lock); | ||
3047 | tmp = inl(instance->ctrl_reg); | ||
3048 | tmp |= ME4600_AI_CTRL_BIT_SC_RELOAD; | ||
3049 | tmp &= ~ME4600_AI_CTRL_BIT_SC_IRQ_RESET; | ||
3050 | outl(tmp, instance->ctrl_reg); | ||
3051 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3052 | instance->reg_base, | ||
3053 | instance->ctrl_reg - instance->reg_base, | ||
3054 | tmp); | ||
3055 | spin_unlock(instance->ctrl_reg_lock); | ||
3056 | if (!instance->fifo_irq_threshold) { //No threshold provided. Set ISM.next to 0.5*FIFO. | ||
3057 | instance->ISM.next = ME4600_AI_FIFO_HALF; | ||
3058 | } else { //Threshold provided. Set ISM.next to treshold. | ||
3059 | instance->ISM.next = | ||
3060 | instance->fifo_irq_threshold; | ||
3061 | } | ||
3062 | } else { //Enable sample counter's and HF's interrupts. | ||
3063 | spin_lock(instance->ctrl_reg_lock); | ||
3064 | tmp = inl(instance->ctrl_reg); | ||
3065 | tmp |= ME4600_AI_CTRL_BIT_SC_RELOAD; | ||
3066 | tmp &= | ||
3067 | ~(ME4600_AI_CTRL_BIT_SC_IRQ_RESET | | ||
3068 | ME4600_AI_CTRL_BIT_HF_IRQ_RESET); | ||
3069 | outl(tmp, instance->ctrl_reg); | ||
3070 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3071 | instance->reg_base, | ||
3072 | instance->ctrl_reg - instance->reg_base, | ||
3073 | tmp); | ||
3074 | spin_unlock(instance->ctrl_reg_lock); | ||
3075 | |||
3076 | instance->ISM.next = | ||
3077 | instance->fifo_irq_threshold % ME4600_AI_FIFO_HALF; | ||
3078 | if (instance->ISM.next + ME4600_AI_FIFO_HALF < | ||
3079 | ME4600_AI_FIFO_MAX_SC) { | ||
3080 | instance->ISM.next += ME4600_AI_FIFO_HALF; | ||
3081 | } | ||
3082 | } | ||
3083 | } else { //This aqusition is limited to set number of data. | ||
3084 | if (instance->fifo_irq_threshold >= instance->data_required) { //Stupid situation. | ||
3085 | instance->fifo_irq_threshold = 0; | ||
3086 | PDEBUG | ||
3087 | ("Stupid situation: data_required(%d) < threshold(%d).\n", | ||
3088 | instance->fifo_irq_threshold, | ||
3089 | instance->data_required); | ||
3090 | } | ||
3091 | |||
3092 | if (!instance->fifo_irq_threshold) { //No threshold provided. Easy case: HF=read and SC=end. | ||
3093 | //Set the sample counter to data_required. | ||
3094 | outl(instance->data_required, | ||
3095 | instance->sample_counter_reg); | ||
3096 | PDEBUG_REG | ||
3097 | ("sample_counter_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3098 | instance->reg_base, | ||
3099 | instance->sample_counter_reg - instance->reg_base, | ||
3100 | instance->data_required); | ||
3101 | |||
3102 | //Reset the latches of sample counter and HF (if SC>FIFO). | ||
3103 | //No SC reload! | ||
3104 | spin_lock(instance->ctrl_reg_lock); | ||
3105 | tmp = inl(instance->ctrl_reg); | ||
3106 | tmp &= | ||
3107 | ~(ME4600_AI_CTRL_BIT_SC_IRQ_RESET | | ||
3108 | ME4600_AI_CTRL_BIT_SC_RELOAD); | ||
3109 | if (instance->data_required > | ||
3110 | (ME4600_AI_FIFO_COUNT - 1)) { | ||
3111 | tmp &= ~ME4600_AI_CTRL_BIT_HF_IRQ_RESET; | ||
3112 | instance->ISM.next = | ||
3113 | instance->data_required % | ||
3114 | ME4600_AI_FIFO_HALF; | ||
3115 | instance->ISM.next += ME4600_AI_FIFO_HALF; | ||
3116 | |||
3117 | } else { | ||
3118 | instance->ISM.next = instance->data_required; | ||
3119 | } | ||
3120 | outl(tmp, instance->ctrl_reg); | ||
3121 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3122 | instance->reg_base, | ||
3123 | instance->ctrl_reg - instance->reg_base, | ||
3124 | tmp); | ||
3125 | spin_unlock(instance->ctrl_reg_lock); | ||
3126 | |||
3127 | } else { //The most general case. We have concret numbe of required data and threshold. SC=TH | ||
3128 | //Set the sample counter to threshold. | ||
3129 | outl(instance->fifo_irq_threshold, | ||
3130 | instance->sample_counter_reg); | ||
3131 | PDEBUG_REG | ||
3132 | ("sample_counter_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3133 | instance->reg_base, | ||
3134 | instance->sample_counter_reg - instance->reg_base, | ||
3135 | instance->fifo_irq_threshold); | ||
3136 | |||
3137 | spin_lock(instance->ctrl_reg_lock); | ||
3138 | tmp = inl(instance->ctrl_reg); | ||
3139 | //In this moment we are sure that SC will come more than once. | ||
3140 | tmp |= ME4600_AI_CTRL_BIT_SC_RELOAD; | ||
3141 | |||
3142 | if (instance->fifo_irq_threshold < ME4600_AI_FIFO_MAX_SC) { //The threshold is so small that we do need HF. | ||
3143 | tmp &= ~ME4600_AI_CTRL_BIT_SC_IRQ_RESET; | ||
3144 | instance->ISM.next = | ||
3145 | instance->fifo_irq_threshold; | ||
3146 | } else { //The threshold is large. The HF must be use. | ||
3147 | tmp &= | ||
3148 | ~(ME4600_AI_CTRL_BIT_SC_IRQ_RESET | | ||
3149 | ME4600_AI_CTRL_BIT_HF_IRQ_RESET); | ||
3150 | instance->ISM.next = | ||
3151 | instance->fifo_irq_threshold % | ||
3152 | ME4600_AI_FIFO_HALF; | ||
3153 | if (instance->ISM.next + ME4600_AI_FIFO_HALF < | ||
3154 | ME4600_AI_FIFO_MAX_SC) { | ||
3155 | instance->ISM.next += | ||
3156 | ME4600_AI_FIFO_HALF; | ||
3157 | } | ||
3158 | } | ||
3159 | outl(tmp, instance->ctrl_reg); | ||
3160 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3161 | instance->reg_base, | ||
3162 | instance->ctrl_reg - instance->reg_base, | ||
3163 | tmp); | ||
3164 | spin_unlock(instance->ctrl_reg_lock); | ||
3165 | } | ||
3166 | } | ||
3167 | } | ||
3168 | |||
3169 | static int ai_mux_toggler(me4600_ai_subdevice_t * instance) | ||
3170 | { | ||
3171 | uint32_t tmp; | ||
3172 | |||
3173 | PDEBUG("executed. idx=0\n"); | ||
3174 | |||
3175 | outl(0, instance->scan_pre_timer_low_reg); | ||
3176 | PDEBUG_REG("scan_pre_timer_low_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3177 | instance->reg_base, | ||
3178 | instance->scan_pre_timer_low_reg - instance->reg_base, 0); | ||
3179 | outl(0, instance->scan_pre_timer_high_reg); | ||
3180 | PDEBUG_REG("scan_pre_timer_high_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3181 | instance->reg_base, | ||
3182 | instance->scan_pre_timer_high_reg - instance->reg_base, 0); | ||
3183 | outl(0, instance->scan_timer_low_reg); | ||
3184 | PDEBUG_REG("scan_timer_low_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3185 | instance->reg_base, | ||
3186 | instance->scan_timer_low_reg - instance->reg_base, 0); | ||
3187 | outl(0, instance->scan_timer_high_reg); | ||
3188 | PDEBUG_REG("scan_timer_high_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3189 | instance->reg_base, | ||
3190 | instance->scan_timer_high_reg - instance->reg_base, 0); | ||
3191 | outl(65, instance->chan_timer_reg); | ||
3192 | PDEBUG_REG("chan_timer_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3193 | instance->reg_base, | ||
3194 | instance->chan_timer_reg - instance->reg_base, 65); | ||
3195 | outl(65, instance->chan_pre_timer_reg); | ||
3196 | PDEBUG_REG("chan_pre_timer_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3197 | instance->reg_base, | ||
3198 | instance->chan_pre_timer_reg - instance->reg_base, 65); | ||
3199 | |||
3200 | // Turn on internal reference. | ||
3201 | tmp = inl(instance->ctrl_reg); | ||
3202 | tmp |= ME4600_AI_CTRL_BIT_FULLSCALE; | ||
3203 | outl(tmp, instance->ctrl_reg); | ||
3204 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
3205 | instance->ctrl_reg - instance->reg_base, tmp); | ||
3206 | |||
3207 | // Clear data and channel fifo. | ||
3208 | tmp &= | ||
3209 | ~(ME4600_AI_CTRL_BIT_CHANNEL_FIFO | ME4600_AI_CTRL_BIT_DATA_FIFO); | ||
3210 | outl(tmp, instance->ctrl_reg); | ||
3211 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
3212 | instance->ctrl_reg - instance->reg_base, tmp); | ||
3213 | tmp |= ME4600_AI_CTRL_BIT_CHANNEL_FIFO | ME4600_AI_CTRL_BIT_DATA_FIFO; | ||
3214 | outl(tmp, instance->ctrl_reg); | ||
3215 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
3216 | instance->ctrl_reg - instance->reg_base, tmp); | ||
3217 | |||
3218 | // Write channel entry. | ||
3219 | outl(ME4600_AI_LIST_INPUT_DIFFERENTIAL | | ||
3220 | ME4600_AI_LIST_RANGE_UNIPOLAR_2_5 | 31, | ||
3221 | instance->channel_list_reg); | ||
3222 | PDEBUG_REG("channel_list_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3223 | instance->reg_base, | ||
3224 | instance->channel_list_reg - instance->reg_base, | ||
3225 | ME4600_AI_LIST_INPUT_DIFFERENTIAL | | ||
3226 | ME4600_AI_LIST_RANGE_UNIPOLAR_2_5 | 31); | ||
3227 | |||
3228 | // Start conversion. | ||
3229 | inl(instance->start_reg); | ||
3230 | PDEBUG_REG("start_reg inl(0x%lX+0x%lX)\n", instance->reg_base, | ||
3231 | instance->start_reg - instance->reg_base); | ||
3232 | udelay(10); | ||
3233 | |||
3234 | // Clear data and channel fifo. | ||
3235 | tmp &= | ||
3236 | ~(ME4600_AI_CTRL_BIT_CHANNEL_FIFO | ME4600_AI_CTRL_BIT_DATA_FIFO); | ||
3237 | outl(tmp, instance->ctrl_reg); | ||
3238 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
3239 | instance->ctrl_reg - instance->reg_base, tmp); | ||
3240 | tmp |= ME4600_AI_CTRL_BIT_CHANNEL_FIFO | ME4600_AI_CTRL_BIT_DATA_FIFO; | ||
3241 | outl(tmp, instance->ctrl_reg); | ||
3242 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
3243 | instance->ctrl_reg - instance->reg_base, tmp); | ||
3244 | |||
3245 | // Write channel entry. | ||
3246 | // ME4600_AI_LIST_INPUT_SINGLE_ENDED | ME4600_AI_LIST_RANGE_BIPOLAR_10 <= 0x0000 | ||
3247 | outl(ME4600_AI_LIST_INPUT_SINGLE_ENDED | | ||
3248 | ME4600_AI_LIST_RANGE_BIPOLAR_10, instance->channel_list_reg); | ||
3249 | PDEBUG_REG("channel_list_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3250 | instance->reg_base, | ||
3251 | instance->channel_list_reg - instance->reg_base, | ||
3252 | ME4600_AI_LIST_INPUT_SINGLE_ENDED | | ||
3253 | ME4600_AI_LIST_RANGE_BIPOLAR_10); | ||
3254 | |||
3255 | // Start conversion. | ||
3256 | inl(instance->start_reg); | ||
3257 | PDEBUG_REG("start_reg inl(0x%lX+0x%lX)\n", instance->reg_base, | ||
3258 | instance->start_reg - instance->reg_base); | ||
3259 | udelay(10); | ||
3260 | |||
3261 | // Clear control register. | ||
3262 | tmp &= (ME4600_AI_CTRL_BIT_EX_IRQ | ME4600_AI_CTRL_BIT_EX_IRQ_RESET); | ||
3263 | outl(tmp, instance->ctrl_reg); | ||
3264 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
3265 | instance->ctrl_reg - instance->reg_base, tmp); | ||
3266 | |||
3267 | return ME_ERRNO_SUCCESS; | ||
3268 | } | ||
3269 | |||
3270 | /** @brief Copy rest of data from fifo to circular buffer. | ||
3271 | * @note Helper for STOP command. After FSM is stopped. | ||
3272 | * @note This is slow function that copy all remainig data from FIFO to buffer. | ||
3273 | * | ||
3274 | * @param instance The subdevice instance (pointer). | ||
3275 | * | ||
3276 | * @return On success: Number of copied values. | ||
3277 | * @return On error: Negative error code -ME_ERRNO_RING_BUFFER_OVERFLOW. | ||
3278 | */ | ||
3279 | static int inline ai_read_data_pooling(me4600_ai_subdevice_t * instance) | ||
3280 | { /// @note This is time critical function! | ||
3281 | int empty_space; | ||
3282 | int copied = 0; | ||
3283 | int status = ME_ERRNO_SUCCESS; | ||
3284 | |||
3285 | PDEBUG("Space left in circular buffer = %d.\n", | ||
3286 | me_circ_buf_space(&instance->circ_buf)); | ||
3287 | |||
3288 | while ((empty_space = me_circ_buf_space(&instance->circ_buf))) { | ||
3289 | if (!(status = inl(instance->status_reg) & ME4600_AI_STATUS_BIT_EF_DATA)) { //No more data. status = ME_ERRNO_SUCCESS = 0 | ||
3290 | break; | ||
3291 | } | ||
3292 | *(instance->circ_buf.buf + instance->circ_buf.head) = | ||
3293 | (inw(instance->data_reg) ^ 0x8000); | ||
3294 | instance->circ_buf.head++; | ||
3295 | instance->circ_buf.head &= instance->circ_buf.mask; | ||
3296 | } | ||
3297 | |||
3298 | #ifdef MEDEBUG_ERROR | ||
3299 | if (!status) | ||
3300 | PDEBUG | ||
3301 | ("Copied all remaining datas (%d) from FIFO to circular buffer.\n", | ||
3302 | copied); | ||
3303 | else { | ||
3304 | PDEBUG("No more empty space in buffer.\n"); | ||
3305 | PDEBUG("Copied %d datas from FIFO to circular buffer.\n", | ||
3306 | copied); | ||
3307 | PDEBUG("FIFO still not empty.\n"); | ||
3308 | } | ||
3309 | #endif | ||
3310 | return (!status) ? copied : -ME_ERRNO_RING_BUFFER_OVERFLOW; | ||
3311 | } | ||
3312 | |||
3313 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) | ||
3314 | static void me4600_ai_work_control_task(void *subdevice) | ||
3315 | #else | ||
3316 | static void me4600_ai_work_control_task(struct work_struct *work) | ||
3317 | #endif | ||
3318 | { | ||
3319 | me4600_ai_subdevice_t *instance; | ||
3320 | uint32_t status; | ||
3321 | uint32_t ctrl; | ||
3322 | unsigned long cpu_flags = 0; | ||
3323 | int reschedule = 0; | ||
3324 | int signaling = 0; | ||
3325 | |||
3326 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) | ||
3327 | instance = (me4600_ai_subdevice_t *) subdevice; | ||
3328 | #else | ||
3329 | instance = | ||
3330 | container_of((void *)work, me4600_ai_subdevice_t, ai_control_task); | ||
3331 | #endif | ||
3332 | PINFO("<%s: %ld> executed.\n", __FUNCTION__, jiffies); | ||
3333 | |||
3334 | status = inl(instance->status_reg); | ||
3335 | PDEBUG_REG("status_reg inl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
3336 | instance->status_reg - instance->reg_base, status); | ||
3337 | |||
3338 | switch (instance->status) { // Checking actual mode. | ||
3339 | // Not configured for work. | ||
3340 | case ai_status_none: | ||
3341 | break; | ||
3342 | |||
3343 | //This are stable modes. No need to do anything. (?) | ||
3344 | case ai_status_single_configured: | ||
3345 | case ai_status_stream_configured: | ||
3346 | case ai_status_stream_fifo_error: | ||
3347 | case ai_status_stream_buffer_error: | ||
3348 | case ai_status_stream_error: | ||
3349 | PERROR("Shouldn't be running!.\n"); | ||
3350 | break; | ||
3351 | |||
3352 | // Stream modes | ||
3353 | case ai_status_stream_run_wait: | ||
3354 | if (status & ME4600_AI_STATUS_BIT_FSM) { // ISM started.. | ||
3355 | instance->status = ai_status_stream_run; | ||
3356 | // Signal the end of wait for start. | ||
3357 | signaling = 1; | ||
3358 | // Wait now for stop. | ||
3359 | reschedule = 1; | ||
3360 | break; | ||
3361 | |||
3362 | // Check timeout. | ||
3363 | if ((instance->timeout.delay) && ((jiffies - instance->timeout.start_time) >= instance->timeout.delay)) { // Timeout | ||
3364 | PDEBUG("Timeout reached.\n"); | ||
3365 | // Stop all actions. No conditions! Block interrupts. Reset FIFO => Too late! | ||
3366 | ai_stop_isr(instance); | ||
3367 | |||
3368 | instance->status = ai_status_stream_end; | ||
3369 | |||
3370 | // Signal the end. | ||
3371 | signaling = 1; | ||
3372 | } | ||
3373 | } | ||
3374 | break; | ||
3375 | |||
3376 | case ai_status_stream_run: | ||
3377 | // Wait for stop ISM. | ||
3378 | reschedule = 1; | ||
3379 | break; | ||
3380 | |||
3381 | case ai_status_stream_end_wait: | ||
3382 | if (!(status & ME4600_AI_STATUS_BIT_FSM)) { // ISM stoped. Overwrite ISR. | ||
3383 | instance->status = ai_status_stream_end; | ||
3384 | // Signal the end of wait for stop. | ||
3385 | signaling = 1; | ||
3386 | } else { | ||
3387 | // Wait for stop ISM. | ||
3388 | reschedule = 1; | ||
3389 | } | ||
3390 | break; | ||
3391 | |||
3392 | case ai_status_stream_end: | ||
3393 | //End work. | ||
3394 | if (status & ME4600_AI_STATUS_BIT_FSM) { // Still working? Stop it! | ||
3395 | PERROR | ||
3396 | ("Status is 'ai_status_stream_end' but hardware is still working!\n"); | ||
3397 | spin_lock_irqsave(instance->ctrl_reg_lock, cpu_flags); | ||
3398 | ctrl = inl(instance->ctrl_reg); | ||
3399 | ctrl |= | ||
3400 | (ME4600_AI_CTRL_BIT_IMMEDIATE_STOP | | ||
3401 | ME4600_AI_CTRL_BIT_HF_IRQ_RESET | | ||
3402 | ME4600_AI_CTRL_BIT_SC_IRQ_RESET); | ||
3403 | outl(ctrl, instance->ctrl_reg); | ||
3404 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3405 | instance->reg_base, | ||
3406 | instance->ctrl_reg - instance->reg_base, | ||
3407 | ctrl); | ||
3408 | spin_unlock_irqrestore(instance->ctrl_reg_lock, | ||
3409 | cpu_flags); | ||
3410 | } | ||
3411 | break; | ||
3412 | |||
3413 | default: | ||
3414 | PERROR_CRITICAL("Status is in wrong state (%d)!\n", | ||
3415 | instance->status); | ||
3416 | instance->status = ai_status_stream_error; | ||
3417 | // Signal the end. | ||
3418 | signaling = 1; | ||
3419 | break; | ||
3420 | |||
3421 | } | ||
3422 | |||
3423 | if (signaling) { //Signal it. | ||
3424 | wake_up_interruptible_all(&instance->wait_queue); | ||
3425 | } | ||
3426 | |||
3427 | if (instance->ai_control_task_flag && reschedule) { // Reschedule task | ||
3428 | queue_delayed_work(instance->me4600_workqueue, | ||
3429 | &instance->ai_control_task, 1); | ||
3430 | } else { | ||
3431 | PINFO("<%s> Ending control task.\n", __FUNCTION__); | ||
3432 | } | ||
3433 | |||
3434 | } | ||
diff --git a/drivers/staging/meilhaus/me4600_ai.h b/drivers/staging/meilhaus/me4600_ai.h new file mode 100644 index 000000000000..1d5a1b9c6f91 --- /dev/null +++ b/drivers/staging/meilhaus/me4600_ai.h | |||
@@ -0,0 +1,180 @@ | |||
1 | /** | ||
2 | * @file me4600_ai.h | ||
3 | * | ||
4 | * @brief Meilhaus ME-4000 analog input subdevice class. | ||
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 _ME4600_AI_H_ | ||
29 | #define _ME4600_AI_H_ | ||
30 | |||
31 | #include <linux/version.h> | ||
32 | #include "mesubdevice.h" | ||
33 | #include "meioctl.h" | ||
34 | #include "mecirc_buf.h" | ||
35 | |||
36 | #ifdef __KERNEL__ | ||
37 | |||
38 | #define ME4600_AI_MAX_DATA 0xFFFF | ||
39 | |||
40 | #ifdef ME_SYNAPSE | ||
41 | # define ME4600_AI_CIRC_BUF_SIZE_ORDER 8 // 2^n PAGES =>> Maximum value of 1MB for Synapse | ||
42 | #else | ||
43 | # define ME4600_AI_CIRC_BUF_SIZE_ORDER 5 // 2^n PAGES =>> 128KB | ||
44 | #endif | ||
45 | #define ME4600_AI_CIRC_BUF_SIZE PAGE_SIZE<<ME4600_AI_CIRC_BUF_SIZE_ORDER // Buffer size in bytes. | ||
46 | |||
47 | #ifdef _CBUFF_32b_t | ||
48 | # define ME4600_AI_CIRC_BUF_COUNT ((ME4600_AI_CIRC_BUF_SIZE) / sizeof(uint32_t)) // Size in values | ||
49 | #else | ||
50 | # define ME4600_AI_CIRC_BUF_COUNT ((ME4600_AI_CIRC_BUF_SIZE) / sizeof(uint16_t)) // Size in values | ||
51 | #endif | ||
52 | |||
53 | #define ME4600_AI_FIFO_HALF 1024 //ME4600_AI_FIFO_COUNT/2 //1024 | ||
54 | #define ME4600_AI_FIFO_MAX_SC 1352 //0.66*ME4600_AI_FIFO_COUNT //1352 | ||
55 | |||
56 | typedef enum ME4600_AI_STATUS { | ||
57 | ai_status_none = 0, | ||
58 | ai_status_single_configured, | ||
59 | ai_status_stream_configured, | ||
60 | ai_status_stream_run_wait, | ||
61 | ai_status_stream_run, | ||
62 | ai_status_stream_end_wait, | ||
63 | ai_status_stream_end, | ||
64 | ai_status_stream_fifo_error, | ||
65 | ai_status_stream_buffer_error, | ||
66 | ai_status_stream_error, | ||
67 | ai_status_last | ||
68 | } ME4600_AI_STATUS; | ||
69 | |||
70 | typedef struct me4600_single_config_entry { | ||
71 | unsigned short status; | ||
72 | uint32_t entry; | ||
73 | uint32_t ctrl; | ||
74 | } me4600_single_config_entry_t; | ||
75 | |||
76 | typedef struct me4600_range_entry { | ||
77 | int min; | ||
78 | int max; | ||
79 | } me4600_range_entry_t; | ||
80 | |||
81 | typedef struct me4600_ai_ISM { | ||
82 | volatile unsigned int global_read; /**< The number of data read in total. */ | ||
83 | volatile unsigned int read; /**< The number of data read for this chunck. */ | ||
84 | volatile unsigned int next; /**< The number of data request by user. */ | ||
85 | } me4600_ai_ISM_t; | ||
86 | |||
87 | typedef struct me4600_ai_timeout { | ||
88 | unsigned long start_time; | ||
89 | unsigned long delay; | ||
90 | } me4600_ai_timeout_t; | ||
91 | |||
92 | /** | ||
93 | * @brief The ME-4000 analog input subdevice class. | ||
94 | */ | ||
95 | typedef struct me4600_ai_subdevice { | ||
96 | /* Inheritance */ | ||
97 | me_subdevice_t base; /**< The subdevice base class. */ | ||
98 | |||
99 | /* Attributes */ | ||
100 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
101 | spinlock_t *ctrl_reg_lock; /**< Spin lock to protect #ctrl_reg from concurrent access. */ | ||
102 | |||
103 | /* Hardware feautres */ | ||
104 | unsigned int irq; /**< The interrupt request number assigned by the PCI BIOS. */ | ||
105 | int isolated; /**< Marks if this subdevice is on an optoisolated device. */ | ||
106 | int sh; /**< Marks if this subdevice has sample and hold devices. */ | ||
107 | |||
108 | unsigned int channels; /**< The number of channels available on this subdevice. */ | ||
109 | me4600_single_config_entry_t single_config[32]; /**< The configuration set for single acquisition. */ | ||
110 | |||
111 | unsigned int data_required; /**< The number of data request by user. */ | ||
112 | unsigned int fifo_irq_threshold; /**< The user adjusted FIFO high water interrupt level. */ | ||
113 | unsigned int chan_list_len; /**< The length of the user defined channel list. */ | ||
114 | |||
115 | me4600_ai_ISM_t ISM; /**< The information request by Interrupt-State-Machine. */ | ||
116 | volatile enum ME4600_AI_STATUS status; /**< The current stream status flag. */ | ||
117 | me4600_ai_timeout_t timeout; /**< The timeout for start in blocking and non-blocking mode. */ | ||
118 | |||
119 | /* Registers *//**< All registers are 32 bits long. */ | ||
120 | unsigned long ctrl_reg; | ||
121 | unsigned long status_reg; | ||
122 | unsigned long channel_list_reg; | ||
123 | unsigned long data_reg; | ||
124 | unsigned long chan_timer_reg; | ||
125 | unsigned long chan_pre_timer_reg; | ||
126 | unsigned long scan_timer_low_reg; | ||
127 | unsigned long scan_timer_high_reg; | ||
128 | unsigned long scan_pre_timer_low_reg; | ||
129 | unsigned long scan_pre_timer_high_reg; | ||
130 | unsigned long start_reg; | ||
131 | unsigned long irq_status_reg; | ||
132 | unsigned long sample_counter_reg; | ||
133 | |||
134 | unsigned int ranges_len; | ||
135 | me4600_range_entry_t ranges[4]; /**< The ranges available on this subdevice. */ | ||
136 | |||
137 | /* Software buffer */ | ||
138 | me_circ_buf_t circ_buf; /**< Circular buffer holding measurment data. */ | ||
139 | wait_queue_head_t wait_queue; /**< Wait queue to put on tasks waiting for data to arrive. */ | ||
140 | |||
141 | struct workqueue_struct *me4600_workqueue; | ||
142 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) | ||
143 | struct work_struct ai_control_task; | ||
144 | #else | ||
145 | struct delayed_work ai_control_task; | ||
146 | #endif | ||
147 | |||
148 | volatile int ai_control_task_flag; /**< Flag controling reexecuting of control task */ | ||
149 | |||
150 | #ifdef MEDEBUG_DEBUG_REG | ||
151 | unsigned long reg_base; | ||
152 | #endif | ||
153 | } me4600_ai_subdevice_t; | ||
154 | |||
155 | /** | ||
156 | * @brief The constructor to generate a ME-4000 analog input subdevice instance. | ||
157 | * | ||
158 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
159 | * @param channels The number of analog input channels available on this subdevice. | ||
160 | * @param channels The number of analog input ranges available on this subdevice. | ||
161 | * @param isolated Flag indicating if this device is opto isolated. | ||
162 | * @param sh Flag indicating if sample and hold devices are available. | ||
163 | * @param irq The irq number assigned by PCI BIOS. | ||
164 | * @param ctrl_reg_lock Pointer to spin lock protecting the control register from concurrent access. | ||
165 | * | ||
166 | * @return Pointer to new instance on success.\n | ||
167 | * NULL on error. | ||
168 | */ | ||
169 | me4600_ai_subdevice_t *me4600_ai_constructor(uint32_t reg_base, | ||
170 | unsigned int channels, | ||
171 | unsigned int ranges, | ||
172 | int isolated, | ||
173 | int sh, | ||
174 | int irq, | ||
175 | spinlock_t * ctrl_reg_lock, | ||
176 | struct workqueue_struct | ||
177 | *me4600_wq); | ||
178 | |||
179 | #endif | ||
180 | #endif | ||
diff --git a/drivers/staging/meilhaus/me4600_ai_reg.h b/drivers/staging/meilhaus/me4600_ai_reg.h new file mode 100644 index 000000000000..083fac7685f5 --- /dev/null +++ b/drivers/staging/meilhaus/me4600_ai_reg.h | |||
@@ -0,0 +1,107 @@ | |||
1 | /** | ||
2 | * @file me4600_ai_reg.h | ||
3 | * | ||
4 | * @brief ME-4000 analog input subdevice register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME4600_AI_REG_H_ | ||
28 | #define _ME4600_AI_REG_H_ | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | #define ME4600_AI_CTRL_REG 0x74 // _/W | ||
33 | #define ME4600_AI_STATUS_REG 0x74 // R/_ | ||
34 | #define ME4600_AI_CHANNEL_LIST_REG 0x78 // _/W | ||
35 | #define ME4600_AI_DATA_REG 0x7C // R/_ | ||
36 | #define ME4600_AI_CHAN_TIMER_REG 0x80 // _/W | ||
37 | #define ME4600_AI_CHAN_PRE_TIMER_REG 0x84 // _/W | ||
38 | #define ME4600_AI_SCAN_TIMER_LOW_REG 0x88 // _/W | ||
39 | #define ME4600_AI_SCAN_TIMER_HIGH_REG 0x8C // _/W | ||
40 | #define ME4600_AI_SCAN_PRE_TIMER_LOW_REG 0x90 // _/W | ||
41 | #define ME4600_AI_SCAN_PRE_TIMER_HIGH_REG 0x94 // _/W | ||
42 | #define ME4600_AI_START_REG 0x98 // R/_ | ||
43 | |||
44 | #define ME4600_AI_SAMPLE_COUNTER_REG 0xC0 // _/W | ||
45 | |||
46 | #define ME4600_AI_CTRL_BIT_MODE_0 0x00000001 | ||
47 | #define ME4600_AI_CTRL_BIT_MODE_1 0x00000002 | ||
48 | #define ME4600_AI_CTRL_BIT_MODE_2 0x00000004 | ||
49 | #define ME4600_AI_CTRL_BIT_SAMPLE_HOLD 0x00000008 | ||
50 | #define ME4600_AI_CTRL_BIT_IMMEDIATE_STOP 0x00000010 | ||
51 | #define ME4600_AI_CTRL_BIT_STOP 0x00000020 | ||
52 | #define ME4600_AI_CTRL_BIT_CHANNEL_FIFO 0x00000040 | ||
53 | #define ME4600_AI_CTRL_BIT_DATA_FIFO 0x00000080 | ||
54 | #define ME4600_AI_CTRL_BIT_FULLSCALE 0x00000100 | ||
55 | #define ME4600_AI_CTRL_BIT_OFFSET 0x00000200 | ||
56 | #define ME4600_AI_CTRL_BIT_EX_TRIG_ANALOG 0x00000400 | ||
57 | #define ME4600_AI_CTRL_BIT_EX_TRIG 0x00000800 | ||
58 | #define ME4600_AI_CTRL_BIT_EX_TRIG_FALLING 0x00001000 | ||
59 | #define ME4600_AI_CTRL_BIT_EX_IRQ 0x00002000 | ||
60 | #define ME4600_AI_CTRL_BIT_EX_IRQ_RESET 0x00004000 | ||
61 | #define ME4600_AI_CTRL_BIT_LE_IRQ 0x00008000 | ||
62 | #define ME4600_AI_CTRL_BIT_LE_IRQ_RESET 0x00010000 | ||
63 | #define ME4600_AI_CTRL_BIT_HF_IRQ 0x00020000 | ||
64 | #define ME4600_AI_CTRL_BIT_HF_IRQ_RESET 0x00040000 | ||
65 | #define ME4600_AI_CTRL_BIT_SC_IRQ 0x00080000 | ||
66 | #define ME4600_AI_CTRL_BIT_SC_IRQ_RESET 0x00100000 | ||
67 | #define ME4600_AI_CTRL_BIT_SC_RELOAD 0x00200000 | ||
68 | #define ME4600_AI_CTRL_BIT_EX_TRIG_BOTH 0x80000000 | ||
69 | |||
70 | #define ME4600_AI_STATUS_BIT_EF_CHANNEL 0x00400000 | ||
71 | #define ME4600_AI_STATUS_BIT_HF_CHANNEL 0x00800000 | ||
72 | #define ME4600_AI_STATUS_BIT_FF_CHANNEL 0x01000000 | ||
73 | #define ME4600_AI_STATUS_BIT_EF_DATA 0x02000000 | ||
74 | #define ME4600_AI_STATUS_BIT_HF_DATA 0x04000000 | ||
75 | #define ME4600_AI_STATUS_BIT_FF_DATA 0x08000000 | ||
76 | #define ME4600_AI_STATUS_BIT_LE 0x10000000 | ||
77 | #define ME4600_AI_STATUS_BIT_FSM 0x20000000 | ||
78 | |||
79 | #define ME4600_AI_CTRL_RPCI_FIFO 0x40000000 //Always set to zero! | ||
80 | |||
81 | #define ME4600_AI_BASE_FREQUENCY 33E6 | ||
82 | |||
83 | #define ME4600_AI_MIN_ACQ_TICKS 66LL | ||
84 | #define ME4600_AI_MAX_ACQ_TICKS 0xFFFFFFFFLL | ||
85 | |||
86 | #define ME4600_AI_MIN_SCAN_TICKS 66LL | ||
87 | #define ME4600_AI_MAX_SCAN_TICKS 0xFFFFFFFFFLL | ||
88 | |||
89 | #define ME4600_AI_MIN_CHAN_TICKS 66LL | ||
90 | #define ME4600_AI_MAX_CHAN_TICKS 0xFFFFFFFFLL | ||
91 | |||
92 | #define ME4600_AI_FIFO_COUNT 2048 | ||
93 | |||
94 | #define ME4600_AI_LIST_COUNT 1024 | ||
95 | |||
96 | #define ME4600_AI_LIST_INPUT_SINGLE_ENDED 0x000 | ||
97 | #define ME4600_AI_LIST_INPUT_DIFFERENTIAL 0x020 | ||
98 | |||
99 | #define ME4600_AI_LIST_RANGE_BIPOLAR_10 0x000 | ||
100 | #define ME4600_AI_LIST_RANGE_BIPOLAR_2_5 0x040 | ||
101 | #define ME4600_AI_LIST_RANGE_UNIPOLAR_10 0x080 | ||
102 | #define ME4600_AI_LIST_RANGE_UNIPOLAR_2_5 0x0C0 | ||
103 | |||
104 | #define ME4600_AI_LIST_LAST_ENTRY 0x100 | ||
105 | |||
106 | #endif | ||
107 | #endif | ||
diff --git a/drivers/staging/meilhaus/me4600_ao.c b/drivers/staging/meilhaus/me4600_ao.c new file mode 100644 index 000000000000..2c92e655a81e --- /dev/null +++ b/drivers/staging/meilhaus/me4600_ao.c | |||
@@ -0,0 +1,6011 @@ | |||
1 | /** | ||
2 | * @file me4600_ao.c | ||
3 | * | ||
4 | * @brief ME-4000 analog output subdevice instance. | ||
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 | ///Common part. (For normal and Bosch builds.) | ||
33 | |||
34 | /* Includes | ||
35 | */ | ||
36 | |||
37 | #include <linux/module.h> | ||
38 | |||
39 | #include <linux/slab.h> | ||
40 | #include <linux/spinlock.h> | ||
41 | #include <asm/io.h> | ||
42 | #include <asm/uaccess.h> | ||
43 | #include <linux/types.h> | ||
44 | #include <linux/version.h> | ||
45 | #include <linux/interrupt.h> | ||
46 | #include <linux/delay.h> | ||
47 | |||
48 | #include "medefines.h" | ||
49 | #include "meinternal.h" | ||
50 | #include "meerror.h" | ||
51 | |||
52 | #include "medebug.h" | ||
53 | #include "meids.h" | ||
54 | #include "me4600_reg.h" | ||
55 | #include "me4600_ao_reg.h" | ||
56 | #include "me4600_ao.h" | ||
57 | |||
58 | /* Defines | ||
59 | */ | ||
60 | |||
61 | static int me4600_ao_query_range_by_min_max(me_subdevice_t * subdevice, | ||
62 | int unit, | ||
63 | int *min, | ||
64 | int *max, int *maxdata, int *range); | ||
65 | |||
66 | static int me4600_ao_query_number_ranges(me_subdevice_t * subdevice, | ||
67 | int unit, int *count); | ||
68 | |||
69 | static int me4600_ao_query_range_info(me_subdevice_t * subdevice, | ||
70 | int range, | ||
71 | int *unit, | ||
72 | int *min, int *max, int *maxdata); | ||
73 | |||
74 | static int me4600_ao_query_timer(me_subdevice_t * subdevice, | ||
75 | int timer, | ||
76 | int *base_frequency, | ||
77 | long long *min_ticks, long long *max_ticks); | ||
78 | |||
79 | static int me4600_ao_query_number_channels(me_subdevice_t * subdevice, | ||
80 | int *number); | ||
81 | |||
82 | static int me4600_ao_query_subdevice_type(me_subdevice_t * subdevice, | ||
83 | int *type, int *subtype); | ||
84 | |||
85 | static int me4600_ao_query_subdevice_caps(me_subdevice_t * subdevice, | ||
86 | int *caps); | ||
87 | |||
88 | static int me4600_ao_query_subdevice_caps_args(struct me_subdevice *subdevice, | ||
89 | int cap, int *args, int count); | ||
90 | |||
91 | #ifndef BOSCH | ||
92 | /// @note NORMAL BUILD | ||
93 | /// @author Krzysztof Gantzke (k.gantzke@meilhaus.de) | ||
94 | /* Includes | ||
95 | */ | ||
96 | |||
97 | # include <linux/workqueue.h> | ||
98 | |||
99 | /* Defines | ||
100 | */ | ||
101 | |||
102 | /** Remove subdevice. | ||
103 | */ | ||
104 | static void me4600_ao_destructor(struct me_subdevice *subdevice); | ||
105 | |||
106 | /** Reset subdevice. Stop all actions. Reset registry. Disable FIFO. Set output to 0V and status to 'none'. | ||
107 | */ | ||
108 | static int me4600_ao_io_reset_subdevice(me_subdevice_t * subdevice, | ||
109 | struct file *filep, int flags); | ||
110 | |||
111 | /** Set output as single | ||
112 | */ | ||
113 | static int me4600_ao_io_single_config(me_subdevice_t * subdevice, | ||
114 | struct file *filep, | ||
115 | int channel, | ||
116 | int single_config, | ||
117 | int ref, | ||
118 | int trig_chan, | ||
119 | int trig_type, int trig_edge, int flags); | ||
120 | |||
121 | /** Pass to user actual value of output. | ||
122 | */ | ||
123 | static int me4600_ao_io_single_read(me_subdevice_t * subdevice, | ||
124 | struct file *filep, | ||
125 | int channel, | ||
126 | int *value, int time_out, int flags); | ||
127 | |||
128 | /** Write to output requed value. | ||
129 | */ | ||
130 | static int me4600_ao_io_single_write(me_subdevice_t * subdevice, | ||
131 | struct file *filep, | ||
132 | int channel, | ||
133 | int value, int time_out, int flags); | ||
134 | |||
135 | /** Set output as streamed device. | ||
136 | */ | ||
137 | static int me4600_ao_io_stream_config(me_subdevice_t * subdevice, | ||
138 | struct file *filep, | ||
139 | meIOStreamConfig_t * config_list, | ||
140 | int count, | ||
141 | meIOStreamTrigger_t * trigger, | ||
142 | int fifo_irq_threshold, int flags); | ||
143 | |||
144 | /** Wait for / Check empty space in buffer. | ||
145 | */ | ||
146 | static int me4600_ao_io_stream_new_values(me_subdevice_t * subdevice, | ||
147 | struct file *filep, | ||
148 | int time_out, int *count, int flags); | ||
149 | |||
150 | /** Start streaming. | ||
151 | */ | ||
152 | static int me4600_ao_io_stream_start(me_subdevice_t * subdevice, | ||
153 | struct file *filep, | ||
154 | int start_mode, int time_out, int flags); | ||
155 | |||
156 | /** Check actual state. / Wait for end. | ||
157 | */ | ||
158 | static int me4600_ao_io_stream_status(me_subdevice_t * subdevice, | ||
159 | struct file *filep, | ||
160 | int wait, | ||
161 | int *status, int *values, int flags); | ||
162 | |||
163 | /** Stop streaming. | ||
164 | */ | ||
165 | static int me4600_ao_io_stream_stop(me_subdevice_t * subdevice, | ||
166 | struct file *filep, | ||
167 | int stop_mode, int flags); | ||
168 | |||
169 | /** Write datas to buffor. | ||
170 | */ | ||
171 | static int me4600_ao_io_stream_write(me_subdevice_t * subdevice, | ||
172 | struct file *filep, | ||
173 | int write_mode, | ||
174 | int *values, int *count, int flags); | ||
175 | |||
176 | /** Interrupt handler. Copy from buffer to FIFO. | ||
177 | */ | ||
178 | static irqreturn_t me4600_ao_isr(int irq, void *dev_id | ||
179 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) | ||
180 | , struct pt_regs *regs | ||
181 | #endif | ||
182 | ); | ||
183 | /** Copy data from circular buffer to fifo (fast) in wraparound mode. | ||
184 | */ | ||
185 | int inline ao_write_data_wraparound(me4600_ao_subdevice_t * instance, int count, | ||
186 | int start_pos); | ||
187 | |||
188 | /** Copy data from circular buffer to fifo (fast). | ||
189 | */ | ||
190 | int inline ao_write_data(me4600_ao_subdevice_t * instance, int count, | ||
191 | int start_pos); | ||
192 | |||
193 | /** Copy data from circular buffer to fifo (slow). | ||
194 | */ | ||
195 | int inline ao_write_data_pooling(me4600_ao_subdevice_t * instance, int count, | ||
196 | int start_pos); | ||
197 | |||
198 | /** Copy data from user space to circular buffer. | ||
199 | */ | ||
200 | int inline ao_get_data_from_user(me4600_ao_subdevice_t * instance, int count, | ||
201 | int *user_values); | ||
202 | |||
203 | /** Stop presentation. Preserve FIFOs. | ||
204 | */ | ||
205 | int inline ao_stop_immediately(me4600_ao_subdevice_t * instance); | ||
206 | |||
207 | /** Task for asynchronical state verifying. | ||
208 | */ | ||
209 | static void me4600_ao_work_control_task( | ||
210 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) | ||
211 | void *subdevice | ||
212 | #else | ||
213 | struct work_struct *work | ||
214 | #endif | ||
215 | ); | ||
216 | /* Functions | ||
217 | */ | ||
218 | |||
219 | static int me4600_ao_io_reset_subdevice(me_subdevice_t * subdevice, | ||
220 | struct file *filep, int flags) | ||
221 | { | ||
222 | me4600_ao_subdevice_t *instance; | ||
223 | int err = ME_ERRNO_SUCCESS; | ||
224 | uint32_t tmp; | ||
225 | |||
226 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
227 | |||
228 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
229 | |||
230 | if (flags) { | ||
231 | PERROR("Invalid flag specified.\n"); | ||
232 | return ME_ERRNO_INVALID_FLAGS; | ||
233 | } | ||
234 | |||
235 | ME_SUBDEVICE_ENTER; | ||
236 | |||
237 | instance->status = ao_status_none; | ||
238 | instance->ao_control_task_flag = 0; | ||
239 | cancel_delayed_work(&instance->ao_control_task); | ||
240 | instance->timeout.delay = 0; | ||
241 | instance->timeout.start_time = jiffies; | ||
242 | |||
243 | //Stop state machine. | ||
244 | err = ao_stop_immediately(instance); | ||
245 | |||
246 | //Remove from synchronous start. | ||
247 | spin_lock(instance->preload_reg_lock); | ||
248 | tmp = inl(instance->preload_reg); | ||
249 | tmp &= | ||
250 | ~((ME4600_AO_SYNC_HOLD | ME4600_AO_SYNC_EXT_TRIG) << instance-> | ||
251 | ao_idx); | ||
252 | outl(tmp, instance->preload_reg); | ||
253 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
254 | instance->preload_reg - instance->reg_base, tmp); | ||
255 | *instance->preload_flags &= | ||
256 | ~((ME4600_AO_SYNC_HOLD | ME4600_AO_SYNC_EXT_TRIG) << instance-> | ||
257 | ao_idx); | ||
258 | spin_unlock(instance->preload_reg_lock); | ||
259 | |||
260 | //Set single mode, dissable FIFO, dissable external trigger, set output to analog, block interrupt. | ||
261 | outl(ME4600_AO_MODE_SINGLE | ME4600_AO_CTRL_BIT_STOP | | ||
262 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP | ME4600_AO_CTRL_BIT_RESET_IRQ, | ||
263 | instance->ctrl_reg); | ||
264 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
265 | instance->ctrl_reg - instance->reg_base, | ||
266 | ME4600_AO_MODE_SINGLE | ME4600_AO_CTRL_BIT_STOP | | ||
267 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP | | ||
268 | ME4600_AO_CTRL_BIT_RESET_IRQ); | ||
269 | |||
270 | //Set output to 0V | ||
271 | outl(0x8000, instance->single_reg); | ||
272 | PDEBUG_REG("single_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
273 | instance->single_reg - instance->reg_base, 0x8000); | ||
274 | |||
275 | instance->circ_buf.head = 0; | ||
276 | instance->circ_buf.tail = 0; | ||
277 | instance->preloaded_count = 0; | ||
278 | instance->data_count = 0; | ||
279 | instance->single_value = 0x8000; | ||
280 | instance->single_value_in_fifo = 0x8000; | ||
281 | |||
282 | //Set status to signal that device is unconfigured. | ||
283 | instance->status = ao_status_none; | ||
284 | |||
285 | //Signal reset if user is on wait. | ||
286 | wake_up_interruptible_all(&instance->wait_queue); | ||
287 | |||
288 | ME_SUBDEVICE_EXIT; | ||
289 | |||
290 | return err; | ||
291 | } | ||
292 | |||
293 | static int me4600_ao_io_single_config(me_subdevice_t * subdevice, | ||
294 | struct file *filep, | ||
295 | int channel, | ||
296 | int single_config, | ||
297 | int ref, | ||
298 | int trig_chan, | ||
299 | int trig_type, int trig_edge, int flags) | ||
300 | { | ||
301 | me4600_ao_subdevice_t *instance; | ||
302 | int err = ME_ERRNO_SUCCESS; | ||
303 | uint32_t ctrl; | ||
304 | uint32_t sync; | ||
305 | unsigned long cpu_flags; | ||
306 | |||
307 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
308 | |||
309 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
310 | |||
311 | // Checking parameters | ||
312 | if (flags) { | ||
313 | PERROR | ||
314 | ("Invalid flag specified. Must be ME_IO_SINGLE_CONFIG_NO_FLAGS.\n"); | ||
315 | return ME_ERRNO_INVALID_FLAGS; | ||
316 | } | ||
317 | |||
318 | switch (trig_type) { | ||
319 | case ME_TRIG_TYPE_SW: | ||
320 | if (trig_edge != ME_TRIG_EDGE_NONE) { | ||
321 | PERROR | ||
322 | ("Invalid trigger edge. Software trigger has not edge.\n"); | ||
323 | return ME_ERRNO_INVALID_TRIG_EDGE; | ||
324 | } | ||
325 | break; | ||
326 | |||
327 | case ME_TRIG_TYPE_EXT_DIGITAL: | ||
328 | switch (trig_edge) { | ||
329 | case ME_TRIG_EDGE_ANY: | ||
330 | case ME_TRIG_EDGE_RISING: | ||
331 | case ME_TRIG_EDGE_FALLING: | ||
332 | break; | ||
333 | |||
334 | default: | ||
335 | PERROR("Invalid trigger edge.\n"); | ||
336 | return ME_ERRNO_INVALID_TRIG_EDGE; | ||
337 | } | ||
338 | break; | ||
339 | |||
340 | default: | ||
341 | PERROR | ||
342 | ("Invalid trigger type. Trigger must be software or digital.\n"); | ||
343 | return ME_ERRNO_INVALID_TRIG_TYPE; | ||
344 | } | ||
345 | |||
346 | if ((trig_chan != ME_TRIG_CHAN_DEFAULT) | ||
347 | && (trig_chan != ME_TRIG_CHAN_SYNCHRONOUS)) { | ||
348 | PERROR("Invalid trigger channel specified.\n"); | ||
349 | return ME_ERRNO_INVALID_TRIG_CHAN; | ||
350 | } | ||
351 | |||
352 | if (ref != ME_REF_AO_GROUND) { | ||
353 | PERROR | ||
354 | ("Invalid reference. Analog outputs have to have got REF_AO_GROUND.\n"); | ||
355 | return ME_ERRNO_INVALID_REF; | ||
356 | } | ||
357 | |||
358 | if (single_config != 0) { | ||
359 | PERROR | ||
360 | ("Invalid single config specified. Only one range for anlog outputs is available.\n"); | ||
361 | return ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
362 | } | ||
363 | |||
364 | if (channel != 0) { | ||
365 | PERROR | ||
366 | ("Invalid channel number specified. Analog output have only one channel.\n"); | ||
367 | return ME_ERRNO_INVALID_CHANNEL; | ||
368 | } | ||
369 | |||
370 | ME_SUBDEVICE_ENTER; | ||
371 | |||
372 | //Subdevice running in stream mode! | ||
373 | if ((instance->status >= ao_status_stream_run_wait) | ||
374 | && (instance->status < ao_status_stream_end)) { | ||
375 | PERROR("Subdevice is busy.\n"); | ||
376 | ME_SUBDEVICE_EXIT; | ||
377 | |||
378 | return ME_ERRNO_SUBDEVICE_BUSY; | ||
379 | } | ||
380 | /// @note For single all calls (config and write) are erasing previous state! | ||
381 | |||
382 | instance->status = ao_status_none; | ||
383 | |||
384 | // Correct single mirrors | ||
385 | instance->single_value_in_fifo = instance->single_value; | ||
386 | |||
387 | //Stop device | ||
388 | err = ao_stop_immediately(instance); | ||
389 | if (err) { | ||
390 | PERROR_CRITICAL("FSM IS BUSY!\n"); | ||
391 | ME_SUBDEVICE_EXIT; | ||
392 | |||
393 | return ME_ERRNO_SUBDEVICE_BUSY; | ||
394 | } | ||
395 | // Set control register. | ||
396 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
397 | // Set stop bit. Stop streaming mode. | ||
398 | ctrl = inl(instance->ctrl_reg); | ||
399 | //Reset all bits. | ||
400 | ctrl = ME4600_AO_CTRL_BIT_IMMEDIATE_STOP | ME4600_AO_CTRL_BIT_STOP; | ||
401 | |||
402 | if (trig_type == ME_TRIG_TYPE_EXT_DIGITAL) { | ||
403 | PINFO("External digital trigger.\n"); | ||
404 | |||
405 | if (trig_edge == ME_TRIG_EDGE_ANY) { | ||
406 | // ctrl |= ME4600_AO_CTRL_BIT_EX_TRIG_EDGE | ME4600_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH; | ||
407 | instance->ctrl_trg = | ||
408 | ME4600_AO_CTRL_BIT_EX_TRIG_EDGE | | ||
409 | ME4600_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH; | ||
410 | } else if (trig_edge == ME_TRIG_EDGE_FALLING) { | ||
411 | // ctrl |= ME4600_AO_CTRL_BIT_EX_TRIG_EDGE; | ||
412 | instance->ctrl_trg = ME4600_AO_CTRL_BIT_EX_TRIG_EDGE; | ||
413 | } else if (trig_edge == ME_TRIG_EDGE_RISING) { | ||
414 | instance->ctrl_trg = 0x0; | ||
415 | } | ||
416 | } else if (trig_type == ME_TRIG_TYPE_SW) { | ||
417 | PDEBUG("Software trigger\n"); | ||
418 | instance->ctrl_trg = 0x0; | ||
419 | } | ||
420 | |||
421 | outl(ctrl, instance->ctrl_reg); | ||
422 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
423 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
424 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
425 | |||
426 | // Set preload/synchronization register. | ||
427 | spin_lock(instance->preload_reg_lock); | ||
428 | if (trig_type == ME_TRIG_TYPE_SW) { | ||
429 | *instance->preload_flags &= | ||
430 | ~(ME4600_AO_SYNC_EXT_TRIG << instance->ao_idx); | ||
431 | } else //if (trig_type == ME_TRIG_TYPE_EXT_DIGITAL) | ||
432 | { | ||
433 | *instance->preload_flags |= | ||
434 | ME4600_AO_SYNC_EXT_TRIG << instance->ao_idx; | ||
435 | } | ||
436 | |||
437 | if (trig_chan == ME_TRIG_CHAN_DEFAULT) { | ||
438 | *instance->preload_flags &= | ||
439 | ~(ME4600_AO_SYNC_HOLD << instance->ao_idx); | ||
440 | } else //if (trig_chan == ME_TRIG_CHAN_SYNCHRONOUS) | ||
441 | { | ||
442 | *instance->preload_flags |= | ||
443 | ME4600_AO_SYNC_HOLD << instance->ao_idx; | ||
444 | } | ||
445 | |||
446 | //Reset hardware register | ||
447 | sync = inl(instance->preload_reg); | ||
448 | PDEBUG_REG("preload_reg inl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
449 | instance->preload_reg - instance->reg_base, sync); | ||
450 | sync &= ~(ME4600_AO_SYNC_EXT_TRIG << instance->ao_idx); | ||
451 | sync |= ME4600_AO_SYNC_HOLD << instance->ao_idx; | ||
452 | |||
453 | //Output configured in default (safe) mode. | ||
454 | outl(sync, instance->preload_reg); | ||
455 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
456 | instance->preload_reg - instance->reg_base, sync); | ||
457 | spin_unlock(instance->preload_reg_lock); | ||
458 | |||
459 | instance->status = ao_status_single_configured; | ||
460 | |||
461 | ME_SUBDEVICE_EXIT; | ||
462 | |||
463 | return err; | ||
464 | } | ||
465 | |||
466 | static int me4600_ao_io_single_read(me_subdevice_t * subdevice, | ||
467 | struct file *filep, | ||
468 | int channel, | ||
469 | int *value, int time_out, int flags) | ||
470 | { | ||
471 | me4600_ao_subdevice_t *instance; | ||
472 | int err = ME_ERRNO_SUCCESS; | ||
473 | |||
474 | unsigned long j; | ||
475 | unsigned long delay = 0; | ||
476 | |||
477 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
478 | |||
479 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
480 | |||
481 | if (flags & ~ME_IO_SINGLE_NONBLOCKING) { | ||
482 | PERROR("Invalid flag specified. %d\n", flags); | ||
483 | return ME_ERRNO_INVALID_FLAGS; | ||
484 | } | ||
485 | |||
486 | if (time_out < 0) { | ||
487 | PERROR("Invalid timeout specified.\n"); | ||
488 | return ME_ERRNO_INVALID_TIMEOUT; | ||
489 | } | ||
490 | |||
491 | if (channel != 0) { | ||
492 | PERROR("Invalid channel number specified.\n"); | ||
493 | return ME_ERRNO_INVALID_CHANNEL; | ||
494 | } | ||
495 | |||
496 | if ((instance->status >= ao_status_stream_configured) | ||
497 | && (instance->status <= ao_status_stream_end)) { | ||
498 | PERROR("Subdevice not configured to work in single mode!\n"); | ||
499 | return ME_ERRNO_PREVIOUS_CONFIG; | ||
500 | } | ||
501 | |||
502 | ME_SUBDEVICE_ENTER; | ||
503 | if ((!flags) && (instance->status == ao_status_single_run_wait)) { //Blocking mode. Wait for trigger. | ||
504 | if (time_out) { | ||
505 | delay = (time_out * HZ) / 1000; | ||
506 | if (delay == 0) | ||
507 | delay = 1; | ||
508 | } | ||
509 | |||
510 | j = jiffies; | ||
511 | |||
512 | //Only runing process will interrupt this call. Events are signaled when status change. This procedure has own timeout. | ||
513 | wait_event_interruptible_timeout(instance->wait_queue, | ||
514 | (instance->status != | ||
515 | ao_status_single_run_wait), | ||
516 | (delay) ? delay + | ||
517 | 1 : LONG_MAX); | ||
518 | |||
519 | if (instance->status == ao_status_none) { | ||
520 | PDEBUG("Single canceled.\n"); | ||
521 | err = ME_ERRNO_CANCELLED; | ||
522 | } | ||
523 | |||
524 | if (signal_pending(current)) { | ||
525 | PERROR("Wait on start of state machine interrupted.\n"); | ||
526 | instance->status = ao_status_none; | ||
527 | ao_stop_immediately(instance); | ||
528 | err = ME_ERRNO_SIGNAL; | ||
529 | } | ||
530 | |||
531 | if ((delay) && ((jiffies - j) >= delay)) { | ||
532 | |||
533 | PDEBUG("Timeout reached.\n"); | ||
534 | err = ME_ERRNO_TIMEOUT; | ||
535 | } | ||
536 | |||
537 | *value = | ||
538 | (!err) ? instance->single_value_in_fifo : instance-> | ||
539 | single_value; | ||
540 | } else { //Non-blocking mode | ||
541 | //Read value | ||
542 | *value = instance->single_value; | ||
543 | } | ||
544 | |||
545 | ME_SUBDEVICE_EXIT; | ||
546 | |||
547 | return err; | ||
548 | } | ||
549 | |||
550 | static int me4600_ao_io_single_write(me_subdevice_t * subdevice, | ||
551 | struct file *filep, | ||
552 | int channel, | ||
553 | int value, int time_out, int flags) | ||
554 | { | ||
555 | me4600_ao_subdevice_t *instance; | ||
556 | int err = ME_ERRNO_SUCCESS; | ||
557 | unsigned long cpu_flags; | ||
558 | unsigned long j; | ||
559 | unsigned long delay = 0x0; | ||
560 | |||
561 | //Registry handling variables. | ||
562 | uint32_t sync_mask; | ||
563 | uint32_t mode; | ||
564 | uint32_t tmp; | ||
565 | uint32_t ctrl; | ||
566 | uint32_t status; | ||
567 | |||
568 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
569 | |||
570 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
571 | |||
572 | if (flags & | ||
573 | ~(ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS | | ||
574 | ME_IO_SINGLE_TYPE_WRITE_NONBLOCKING)) { | ||
575 | PERROR("Invalid flag specified.\n"); | ||
576 | return ME_ERRNO_INVALID_FLAGS; | ||
577 | } | ||
578 | |||
579 | if (time_out < 0) { | ||
580 | PERROR("Invalid timeout specified.\n"); | ||
581 | return ME_ERRNO_INVALID_TIMEOUT; | ||
582 | } | ||
583 | |||
584 | if (value & ~ME4600_AO_MAX_DATA) { | ||
585 | PERROR("Invalid value provided.\n"); | ||
586 | return ME_ERRNO_VALUE_OUT_OF_RANGE; | ||
587 | } | ||
588 | |||
589 | if (channel != 0) { | ||
590 | PERROR("Invalid channel number specified.\n"); | ||
591 | return ME_ERRNO_INVALID_CHANNEL; | ||
592 | } | ||
593 | |||
594 | if ((instance->status == ao_status_none) | ||
595 | || (instance->status > ao_status_single_end)) { | ||
596 | PERROR("Subdevice not configured to work in single mode!\n"); | ||
597 | return ME_ERRNO_PREVIOUS_CONFIG; | ||
598 | } | ||
599 | |||
600 | ME_SUBDEVICE_ENTER; | ||
601 | |||
602 | /// @note For single all calls (config and write) are erasing previous state! | ||
603 | |||
604 | //Cancel control task | ||
605 | PDEBUG("Cancel control task. idx=%d\n", instance->ao_idx); | ||
606 | instance->ao_control_task_flag = 0; | ||
607 | cancel_delayed_work(&instance->ao_control_task); | ||
608 | |||
609 | // Correct single mirrors | ||
610 | instance->single_value_in_fifo = instance->single_value; | ||
611 | |||
612 | //Stop device | ||
613 | err = ao_stop_immediately(instance); | ||
614 | if (err) { | ||
615 | PERROR_CRITICAL("FSM IS BUSY!\n"); | ||
616 | ME_SUBDEVICE_EXIT; | ||
617 | |||
618 | return ME_ERRNO_SUBDEVICE_BUSY; | ||
619 | } | ||
620 | |||
621 | if (time_out) { | ||
622 | delay = (time_out * HZ) / 1000; | ||
623 | |||
624 | if (delay == 0) | ||
625 | delay = 1; | ||
626 | } | ||
627 | |||
628 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
629 | |||
630 | instance->single_value_in_fifo = value; | ||
631 | |||
632 | ctrl = inl(instance->ctrl_reg); | ||
633 | |||
634 | if (!instance->fifo) { //No FIFO | ||
635 | //Set the single mode. | ||
636 | ctrl &= ~ME4600_AO_CTRL_MODE_MASK; | ||
637 | |||
638 | //Write value | ||
639 | PDEBUG("Write value\n"); | ||
640 | outl(value, instance->single_reg); | ||
641 | PDEBUG_REG("single_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
642 | instance->reg_base, | ||
643 | instance->single_reg - instance->reg_base, value); | ||
644 | } else { // mix-mode | ||
645 | //Set speed | ||
646 | outl(ME4600_AO_MIN_CHAN_TICKS - 1, instance->timer_reg); | ||
647 | PDEBUG_REG("timer_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
648 | instance->reg_base, | ||
649 | instance->timer_reg - instance->reg_base, | ||
650 | (int)ME4600_AO_MIN_CHAN_TICKS); | ||
651 | instance->hardware_stop_delay = HZ / 10; //100ms | ||
652 | |||
653 | status = inl(instance->status_reg); | ||
654 | |||
655 | //Set the continous mode. | ||
656 | ctrl &= ~ME4600_AO_CTRL_MODE_MASK; | ||
657 | ctrl |= ME4600_AO_MODE_CONTINUOUS; | ||
658 | |||
659 | //Prepare FIFO | ||
660 | if (!(ctrl & ME4600_AO_CTRL_BIT_ENABLE_FIFO)) { //FIFO wasn't enabeled. Do it. | ||
661 | PINFO("Enableing FIFO.\n"); | ||
662 | ctrl &= ~ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
663 | ctrl |= | ||
664 | ME4600_AO_CTRL_BIT_ENABLE_FIFO | | ||
665 | ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
666 | } else { //Check if FIFO is empty | ||
667 | if (status & ME4600_AO_STATUS_BIT_EF) { //FIFO not empty | ||
668 | PINFO("Reseting FIFO.\n"); | ||
669 | ctrl &= | ||
670 | ~(ME4600_AO_CTRL_BIT_ENABLE_FIFO | | ||
671 | ME4600_AO_CTRL_BIT_ENABLE_IRQ); | ||
672 | ctrl |= ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
673 | outl(ctrl, instance->ctrl_reg); | ||
674 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
675 | instance->reg_base, | ||
676 | instance->ctrl_reg - | ||
677 | instance->reg_base, ctrl); | ||
678 | |||
679 | ctrl |= | ||
680 | ME4600_AO_CTRL_BIT_ENABLE_FIFO | | ||
681 | ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
682 | } else { //FIFO empty, only interrupt needs to be disabled! | ||
683 | ctrl &= ~ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
684 | ctrl |= ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
685 | } | ||
686 | } | ||
687 | |||
688 | outl(ctrl, instance->ctrl_reg); | ||
689 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
690 | instance->reg_base, | ||
691 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
692 | |||
693 | //Write output - 1 value to FIFO | ||
694 | if (instance->ao_idx & 0x1) { | ||
695 | outl(value <<= 16, instance->fifo_reg); | ||
696 | PDEBUG_REG("fifo_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
697 | instance->reg_base, | ||
698 | instance->fifo_reg - instance->reg_base, | ||
699 | value <<= 16); | ||
700 | } else { | ||
701 | outl(value, instance->fifo_reg); | ||
702 | PDEBUG_REG("fifo_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
703 | instance->reg_base, | ||
704 | instance->fifo_reg - instance->reg_base, | ||
705 | value); | ||
706 | } | ||
707 | } | ||
708 | |||
709 | mode = *instance->preload_flags >> instance->ao_idx; | ||
710 | mode &= (ME4600_AO_SYNC_HOLD | ME4600_AO_SYNC_EXT_TRIG); | ||
711 | |||
712 | PINFO("Triggering mode: 0x%x\n", mode); | ||
713 | |||
714 | spin_lock(instance->preload_reg_lock); | ||
715 | sync_mask = inl(instance->preload_reg); | ||
716 | PDEBUG_REG("preload_reg inl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
717 | instance->preload_reg - instance->reg_base, sync_mask); | ||
718 | switch (mode) { | ||
719 | case 0: //Individual software | ||
720 | ctrl &= ~ME4600_AO_CTRL_BIT_ENABLE_EX_TRIG; | ||
721 | |||
722 | if (!instance->fifo) { // No FIFO - In this case resetting 'ME4600_AO_SYNC_HOLD' will trigger output. | ||
723 | if ((sync_mask & ((ME4600_AO_SYNC_HOLD | ME4600_AO_SYNC_EXT_TRIG) << instance->ao_idx)) != ME4600_AO_SYNC_HOLD) { //Now we can set correct mode. This is exception. It is set to synchronous and triggered later. | ||
724 | sync_mask &= | ||
725 | ~(ME4600_AO_SYNC_EXT_TRIG << instance-> | ||
726 | ao_idx); | ||
727 | sync_mask |= | ||
728 | ME4600_AO_SYNC_HOLD << instance->ao_idx; | ||
729 | |||
730 | outl(sync_mask, instance->preload_reg); | ||
731 | PDEBUG_REG | ||
732 | ("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
733 | instance->reg_base, | ||
734 | instance->preload_reg - instance->reg_base, | ||
735 | sync_mask); | ||
736 | } | ||
737 | } else { // FIFO | ||
738 | if ((sync_mask & ((ME4600_AO_SYNC_HOLD | ME4600_AO_SYNC_EXT_TRIG) << instance->ao_idx)) != 0x0) { //Now we can set correct mode. | ||
739 | sync_mask &= | ||
740 | ~((ME4600_AO_SYNC_EXT_TRIG | | ||
741 | ME4600_AO_SYNC_HOLD) << instance-> | ||
742 | ao_idx); | ||
743 | |||
744 | outl(sync_mask, instance->preload_reg); | ||
745 | PDEBUG_REG | ||
746 | ("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
747 | instance->reg_base, | ||
748 | instance->preload_reg - instance->reg_base, | ||
749 | sync_mask); | ||
750 | } | ||
751 | } | ||
752 | instance->single_value = value; | ||
753 | break; | ||
754 | |||
755 | case ME4600_AO_SYNC_EXT_TRIG: //Individual hardware | ||
756 | ctrl |= ME4600_AO_CTRL_BIT_ENABLE_EX_TRIG; | ||
757 | |||
758 | if (!instance->fifo) { // No FIFO - In this case resetting 'ME4600_AO_SYNC_HOLD' will trigger output. | ||
759 | if ((sync_mask & ((ME4600_AO_SYNC_HOLD | ME4600_AO_SYNC_EXT_TRIG) << instance->ao_idx)) != ME4600_AO_SYNC_HOLD) { //Now we can set correct mode | ||
760 | sync_mask &= | ||
761 | ~(ME4600_AO_SYNC_EXT_TRIG << instance-> | ||
762 | ao_idx); | ||
763 | sync_mask |= | ||
764 | ME4600_AO_SYNC_HOLD << instance->ao_idx; | ||
765 | |||
766 | outl(sync_mask, instance->preload_reg); | ||
767 | PDEBUG_REG | ||
768 | ("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
769 | instance->reg_base, | ||
770 | instance->preload_reg - instance->reg_base, | ||
771 | sync_mask); | ||
772 | } | ||
773 | } else { // FIFO | ||
774 | if ((sync_mask & ((ME4600_AO_SYNC_HOLD | ME4600_AO_SYNC_EXT_TRIG) << instance->ao_idx)) != 0x0) { //Now we can set correct mode. | ||
775 | sync_mask &= | ||
776 | ~((ME4600_AO_SYNC_EXT_TRIG | | ||
777 | ME4600_AO_SYNC_HOLD) << instance-> | ||
778 | ao_idx); | ||
779 | |||
780 | outl(sync_mask, instance->preload_reg); | ||
781 | PDEBUG_REG | ||
782 | ("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
783 | instance->reg_base, | ||
784 | instance->preload_reg - instance->reg_base, | ||
785 | sync_mask); | ||
786 | } | ||
787 | } | ||
788 | break; | ||
789 | |||
790 | case ME4600_AO_SYNC_HOLD: //Synchronous software | ||
791 | ctrl &= ~ME4600_AO_CTRL_BIT_ENABLE_EX_TRIG; | ||
792 | |||
793 | // if((sync_mask & ((ME4600_AO_SYNC_HOLD | ME4600_AO_SYNC_EXT_TRIG) << instance->ao_idx)) != ME4600_AO_SYNC_HOLD) | ||
794 | if ((sync_mask & ((ME4600_AO_SYNC_HOLD | ME4600_AO_SYNC_EXT_TRIG) << instance->ao_idx)) != (ME4600_AO_SYNC_HOLD | ME4600_AO_SYNC_EXT_TRIG)) { //Now we can set correct mode | ||
795 | sync_mask |= | ||
796 | ME4600_AO_SYNC_EXT_TRIG << instance->ao_idx; | ||
797 | // sync_mask &= ~(ME4600_AO_SYNC_EXT_TRIG << instance->ao_idx); | ||
798 | sync_mask |= ME4600_AO_SYNC_HOLD << instance->ao_idx; | ||
799 | |||
800 | outl(sync_mask, instance->preload_reg); | ||
801 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
802 | instance->reg_base, | ||
803 | instance->preload_reg - instance->reg_base, | ||
804 | sync_mask); | ||
805 | } | ||
806 | break; | ||
807 | |||
808 | case (ME4600_AO_SYNC_HOLD | ME4600_AO_SYNC_EXT_TRIG): //Synchronous hardware | ||
809 | ctrl |= ME4600_AO_CTRL_BIT_ENABLE_EX_TRIG; | ||
810 | if ((sync_mask & ((ME4600_AO_SYNC_HOLD | ME4600_AO_SYNC_EXT_TRIG) << instance->ao_idx)) != (ME4600_AO_SYNC_HOLD | ME4600_AO_SYNC_EXT_TRIG)) { //Now we can set correct mode | ||
811 | sync_mask |= | ||
812 | (ME4600_AO_SYNC_HOLD | ME4600_AO_SYNC_EXT_TRIG) << | ||
813 | instance->ao_idx; | ||
814 | |||
815 | outl(sync_mask, instance->preload_reg); | ||
816 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
817 | instance->reg_base, | ||
818 | instance->preload_reg - instance->reg_base, | ||
819 | sync_mask); | ||
820 | } | ||
821 | break; | ||
822 | } | ||
823 | // spin_unlock(instance->preload_reg_lock); // Moved down. | ||
824 | |||
825 | //Activate ISM (remove 'stop' bits) | ||
826 | ctrl &= | ||
827 | ~(ME4600_AO_CTRL_BIT_EX_TRIG_EDGE | | ||
828 | ME4600_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH); | ||
829 | ctrl |= instance->ctrl_trg; | ||
830 | ctrl &= ~(ME4600_AO_CTRL_BIT_STOP | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP); | ||
831 | outl(ctrl, instance->ctrl_reg); | ||
832 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
833 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
834 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
835 | |||
836 | /// @note When flag 'ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS' is set than output is triggered. ALWAYS! | ||
837 | |||
838 | if (!instance->fifo) { //No FIFO | ||
839 | if (flags & ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS) { //Fired all software synchronous outputs. | ||
840 | tmp = ~(*instance->preload_flags | 0xFFFF0000); | ||
841 | PINFO | ||
842 | ("Fired all software synchronous outputs. mask:0x%08x\n", | ||
843 | tmp); | ||
844 | tmp |= sync_mask & 0xFFFF0000; | ||
845 | // Add this channel to list | ||
846 | tmp &= ~(ME4600_AO_SYNC_HOLD << instance->ao_idx); | ||
847 | |||
848 | //Fire | ||
849 | PINFO("Software trigger.\n"); | ||
850 | outl(tmp, instance->preload_reg); | ||
851 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
852 | instance->reg_base, | ||
853 | instance->preload_reg - instance->reg_base, | ||
854 | tmp); | ||
855 | |||
856 | //Restore save settings | ||
857 | outl(sync_mask, instance->preload_reg); | ||
858 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
859 | instance->reg_base, | ||
860 | instance->preload_reg - instance->reg_base, | ||
861 | sync_mask); | ||
862 | } else if (!mode) { // Add this channel to list | ||
863 | outl(sync_mask & | ||
864 | ~(ME4600_AO_SYNC_HOLD << instance->ao_idx), | ||
865 | instance->preload_reg); | ||
866 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
867 | instance->reg_base, | ||
868 | instance->preload_reg - instance->reg_base, | ||
869 | sync_mask & ~(ME4600_AO_SYNC_HOLD << | ||
870 | instance->ao_idx)); | ||
871 | |||
872 | //Fire | ||
873 | PINFO("Software trigger.\n"); | ||
874 | |||
875 | //Restore save settings | ||
876 | outl(sync_mask, instance->preload_reg); | ||
877 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
878 | instance->reg_base, | ||
879 | instance->preload_reg - instance->reg_base, | ||
880 | sync_mask); | ||
881 | } | ||
882 | |||
883 | } else { // mix-mode - begin | ||
884 | if (flags & ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS) { //Trigger outputs | ||
885 | //Add channel to start list | ||
886 | outl(sync_mask | | ||
887 | (ME4600_AO_SYNC_HOLD << instance->ao_idx), | ||
888 | instance->preload_reg); | ||
889 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
890 | instance->reg_base, | ||
891 | instance->preload_reg - instance->reg_base, | ||
892 | sync_mask | (ME4600_AO_SYNC_HOLD << | ||
893 | instance->ao_idx)); | ||
894 | |||
895 | //Fire | ||
896 | PINFO | ||
897 | ("Fired all software synchronous outputs by software trigger.\n"); | ||
898 | outl(0x8000, instance->single_reg); | ||
899 | PDEBUG_REG("single_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
900 | instance->reg_base, | ||
901 | instance->single_reg - instance->reg_base, | ||
902 | 0x8000); | ||
903 | |||
904 | //Restore save settings | ||
905 | outl(sync_mask, instance->preload_reg); | ||
906 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
907 | instance->reg_base, | ||
908 | instance->preload_reg - instance->reg_base, | ||
909 | sync_mask); | ||
910 | } else if (!mode) { //Trigger outputs | ||
911 | /* //Remove channel from start list //<== Unnecessary. Removed. | ||
912 | outl(sync_mask & ~(ME4600_AO_SYNC_HOLD << instance->ao_idx), instance->preload_reg); | ||
913 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, instance->preload_reg - instance->reg_base, tmp); | ||
914 | */ | ||
915 | //Fire | ||
916 | PINFO("Software trigger.\n"); | ||
917 | outl(0x8000, instance->single_reg); | ||
918 | PDEBUG_REG("single_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
919 | instance->reg_base, | ||
920 | instance->single_reg - instance->reg_base, | ||
921 | 0x8000); | ||
922 | |||
923 | /* //Restore save settings //<== Unnecessary. Removed. | ||
924 | outl(sync_mask, instance->preload_reg); | ||
925 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, instance->preload_reg - instance->reg_base, sync_mask); | ||
926 | */ | ||
927 | } | ||
928 | } | ||
929 | spin_unlock(instance->preload_reg_lock); | ||
930 | |||
931 | j = jiffies; | ||
932 | instance->status = ao_status_single_run_wait; | ||
933 | |||
934 | instance->timeout.delay = delay; | ||
935 | instance->timeout.start_time = j; | ||
936 | instance->ao_control_task_flag = 1; | ||
937 | queue_delayed_work(instance->me4600_workqueue, | ||
938 | &instance->ao_control_task, 1); | ||
939 | |||
940 | if (!(flags & ME_IO_SINGLE_TYPE_WRITE_NONBLOCKING)) { | ||
941 | |||
942 | //Only runing process will interrupt this call. Events are signaled when status change. Extra timeout add for safe reason. | ||
943 | wait_event_interruptible_timeout(instance->wait_queue, | ||
944 | (instance->status != | ||
945 | ao_status_single_run_wait), | ||
946 | (delay) ? delay + | ||
947 | 1 : LONG_MAX); | ||
948 | |||
949 | if (((!delay) || ((jiffies - j) <= delay)) | ||
950 | && (instance->status != ao_status_single_end)) { | ||
951 | PDEBUG("Single canceled.\n"); | ||
952 | err = ME_ERRNO_CANCELLED; | ||
953 | } | ||
954 | |||
955 | if (signal_pending(current)) { | ||
956 | PERROR("Wait on start of state machine interrupted.\n"); | ||
957 | instance->ao_control_task_flag = 0; | ||
958 | cancel_delayed_work(&instance->ao_control_task); | ||
959 | ao_stop_immediately(instance); | ||
960 | instance->status = ao_status_none; | ||
961 | err = ME_ERRNO_SIGNAL; | ||
962 | } | ||
963 | |||
964 | if ((delay) && ((jiffies - j) >= delay)) { | ||
965 | if (instance->status == ao_status_single_end) { | ||
966 | PDEBUG("Timeout reached.\n"); | ||
967 | } else { | ||
968 | if ((jiffies - j) > delay) { | ||
969 | PERROR | ||
970 | ("Timeout reached. Not handled by control task!\n"); | ||
971 | } else { | ||
972 | PERROR | ||
973 | ("Timeout reached. Signal come but status is strange: %d\n", | ||
974 | instance->status); | ||
975 | } | ||
976 | |||
977 | ao_stop_immediately(instance); | ||
978 | } | ||
979 | |||
980 | instance->ao_control_task_flag = 0; | ||
981 | cancel_delayed_work(&instance->ao_control_task); | ||
982 | instance->status = ao_status_single_end; | ||
983 | err = ME_ERRNO_TIMEOUT; | ||
984 | } | ||
985 | } | ||
986 | |||
987 | ME_SUBDEVICE_EXIT; | ||
988 | |||
989 | return err; | ||
990 | } | ||
991 | |||
992 | static int me4600_ao_io_stream_config(me_subdevice_t * subdevice, | ||
993 | struct file *filep, | ||
994 | meIOStreamConfig_t * config_list, | ||
995 | int count, | ||
996 | meIOStreamTrigger_t * trigger, | ||
997 | int fifo_irq_threshold, int flags) | ||
998 | { | ||
999 | me4600_ao_subdevice_t *instance; | ||
1000 | int err = ME_ERRNO_SUCCESS; | ||
1001 | uint32_t ctrl; | ||
1002 | unsigned long cpu_flags; | ||
1003 | uint64_t conv_ticks; | ||
1004 | unsigned int conv_start_ticks_low = trigger->iConvStartTicksLow; | ||
1005 | unsigned int conv_start_ticks_high = trigger->iConvStartTicksHigh; | ||
1006 | |||
1007 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
1008 | |||
1009 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
1010 | |||
1011 | if (!instance->fifo) { | ||
1012 | PERROR("Not a streaming ao.\n"); | ||
1013 | return ME_ERRNO_NOT_SUPPORTED; | ||
1014 | } | ||
1015 | |||
1016 | conv_ticks = | ||
1017 | (uint64_t) conv_start_ticks_low + | ||
1018 | ((uint64_t) conv_start_ticks_high << 32); | ||
1019 | |||
1020 | if (flags & | ||
1021 | ~(ME_IO_STREAM_CONFIG_HARDWARE_ONLY | ME_IO_STREAM_CONFIG_WRAPAROUND | ||
1022 | | ME_IO_STREAM_CONFIG_BIT_PATTERN)) { | ||
1023 | PERROR("Invalid flags.\n"); | ||
1024 | return ME_ERRNO_INVALID_FLAGS; | ||
1025 | } | ||
1026 | |||
1027 | if (flags & ME_IO_STREAM_CONFIG_HARDWARE_ONLY) { | ||
1028 | if (!flags & ME_IO_STREAM_CONFIG_WRAPAROUND) { | ||
1029 | PERROR | ||
1030 | ("Hardware ME_IO_STREAM_CONFIG_HARDWARE_ONLY has to be with ME_IO_STREAM_CONFIG_WRAPAROUND.\n"); | ||
1031 | return ME_ERRNO_INVALID_FLAGS; | ||
1032 | } | ||
1033 | |||
1034 | if ((trigger->iAcqStopTrigType != ME_TRIG_TYPE_NONE) | ||
1035 | || (trigger->iScanStopTrigType != ME_TRIG_TYPE_NONE)) { | ||
1036 | PERROR | ||
1037 | ("Hardware wraparound mode must be in infinite mode.\n"); | ||
1038 | return ME_ERRNO_INVALID_FLAGS; | ||
1039 | } | ||
1040 | } | ||
1041 | |||
1042 | if (count != 1) { | ||
1043 | PERROR("Only 1 entry in config list acceptable.\n"); | ||
1044 | return ME_ERRNO_INVALID_CONFIG_LIST_COUNT; | ||
1045 | } | ||
1046 | |||
1047 | if (config_list[0].iChannel != 0) { | ||
1048 | PERROR("Invalid channel number specified.\n"); | ||
1049 | return ME_ERRNO_INVALID_CHANNEL; | ||
1050 | } | ||
1051 | |||
1052 | if (config_list[0].iStreamConfig != 0) { | ||
1053 | PERROR("Only one range available.\n"); | ||
1054 | return ME_ERRNO_INVALID_STREAM_CONFIG; | ||
1055 | } | ||
1056 | |||
1057 | if (config_list[0].iRef != ME_REF_AO_GROUND) { | ||
1058 | PERROR("Output is referenced to ground.\n"); | ||
1059 | return ME_ERRNO_INVALID_REF; | ||
1060 | } | ||
1061 | |||
1062 | if ((trigger->iAcqStartTicksLow != 0) | ||
1063 | || (trigger->iAcqStartTicksHigh != 0)) { | ||
1064 | PERROR | ||
1065 | ("Invalid acquisition start trigger argument specified.\n"); | ||
1066 | return ME_ERRNO_INVALID_ACQ_START_ARG; | ||
1067 | } | ||
1068 | |||
1069 | if (config_list[0].iFlags) { | ||
1070 | PERROR("Invalid config list flag.\n"); | ||
1071 | return ME_ERRNO_INVALID_FLAGS; | ||
1072 | } | ||
1073 | |||
1074 | switch (trigger->iAcqStartTrigType) { | ||
1075 | case ME_TRIG_TYPE_SW: | ||
1076 | if (trigger->iAcqStartTrigEdge != ME_TRIG_EDGE_NONE) { | ||
1077 | PERROR | ||
1078 | ("Invalid acquisition start trigger edge specified.\n"); | ||
1079 | return ME_ERRNO_INVALID_ACQ_START_TRIG_EDGE; | ||
1080 | } | ||
1081 | break; | ||
1082 | |||
1083 | case ME_TRIG_TYPE_EXT_DIGITAL: | ||
1084 | switch (trigger->iAcqStartTrigEdge) { | ||
1085 | case ME_TRIG_EDGE_ANY: | ||
1086 | case ME_TRIG_EDGE_RISING: | ||
1087 | case ME_TRIG_EDGE_FALLING: | ||
1088 | break; | ||
1089 | |||
1090 | default: | ||
1091 | PERROR | ||
1092 | ("Invalid acquisition start trigger edge specified.\n"); | ||
1093 | return ME_ERRNO_INVALID_ACQ_START_TRIG_EDGE; | ||
1094 | } | ||
1095 | break; | ||
1096 | |||
1097 | default: | ||
1098 | PERROR("Invalid acquisition start trigger type specified.\n"); | ||
1099 | return ME_ERRNO_INVALID_ACQ_START_TRIG_TYPE; | ||
1100 | } | ||
1101 | |||
1102 | if (trigger->iScanStartTrigType != ME_TRIG_TYPE_FOLLOW) { | ||
1103 | PERROR("Invalid scan start trigger type specified.\n"); | ||
1104 | return ME_ERRNO_INVALID_SCAN_START_TRIG_TYPE; | ||
1105 | } | ||
1106 | |||
1107 | if (trigger->iConvStartTrigType != ME_TRIG_TYPE_TIMER) { | ||
1108 | PERROR("Invalid conv start trigger type specified.\n"); | ||
1109 | return ME_ERRNO_INVALID_CONV_START_TRIG_TYPE; | ||
1110 | } | ||
1111 | |||
1112 | if ((conv_ticks < ME4600_AO_MIN_CHAN_TICKS) | ||
1113 | || (conv_ticks > ME4600_AO_MAX_CHAN_TICKS)) { | ||
1114 | PERROR("Invalid conv start trigger argument specified.\n"); | ||
1115 | return ME_ERRNO_INVALID_CONV_START_ARG; | ||
1116 | } | ||
1117 | |||
1118 | if (trigger->iAcqStartTicksLow || trigger->iAcqStartTicksHigh) { | ||
1119 | PERROR("Invalid acq start trigger argument specified.\n"); | ||
1120 | return ME_ERRNO_INVALID_ACQ_START_ARG; | ||
1121 | } | ||
1122 | |||
1123 | if (trigger->iScanStartTicksLow || trigger->iScanStartTicksHigh) { | ||
1124 | PERROR("Invalid scan start trigger argument specified.\n"); | ||
1125 | return ME_ERRNO_INVALID_SCAN_START_ARG; | ||
1126 | } | ||
1127 | |||
1128 | switch (trigger->iScanStopTrigType) { | ||
1129 | case ME_TRIG_TYPE_NONE: | ||
1130 | if (trigger->iScanStopCount != 0) { | ||
1131 | PERROR("Invalid scan stop count specified.\n"); | ||
1132 | return ME_ERRNO_INVALID_SCAN_STOP_ARG; | ||
1133 | } | ||
1134 | break; | ||
1135 | |||
1136 | case ME_TRIG_TYPE_COUNT: | ||
1137 | if (flags & ME_IO_STREAM_CONFIG_WRAPAROUND) { | ||
1138 | if (trigger->iScanStopCount <= 0) { | ||
1139 | PERROR("Invalid scan stop count specified.\n"); | ||
1140 | return ME_ERRNO_INVALID_SCAN_STOP_ARG; | ||
1141 | } | ||
1142 | } else { | ||
1143 | PERROR("The continous mode has not 'scan' contects.\n"); | ||
1144 | return ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE; | ||
1145 | } | ||
1146 | break; | ||
1147 | |||
1148 | default: | ||
1149 | PERROR("Invalid scan stop trigger type specified.\n"); | ||
1150 | return ME_ERRNO_INVALID_SCAN_STOP_TRIG_TYPE; | ||
1151 | } | ||
1152 | |||
1153 | switch (trigger->iAcqStopTrigType) { | ||
1154 | case ME_TRIG_TYPE_NONE: | ||
1155 | if (trigger->iAcqStopCount != 0) { | ||
1156 | PERROR("Invalid acq stop count specified.\n"); | ||
1157 | return ME_ERRNO_INVALID_ACQ_STOP_ARG; | ||
1158 | } | ||
1159 | break; | ||
1160 | |||
1161 | case ME_TRIG_TYPE_COUNT: | ||
1162 | if (trigger->iScanStopTrigType != ME_TRIG_TYPE_NONE) { | ||
1163 | PERROR("Invalid acq stop trigger type specified.\n"); | ||
1164 | return ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE; | ||
1165 | } | ||
1166 | |||
1167 | if (flags & ME_IO_STREAM_CONFIG_WRAPAROUND) { | ||
1168 | if (trigger->iAcqStopCount <= 0) { | ||
1169 | PERROR | ||
1170 | ("The continous mode has not 'scan' contects.\n"); | ||
1171 | return ME_ERRNO_INVALID_ACQ_STOP_ARG; | ||
1172 | } | ||
1173 | } | ||
1174 | break; | ||
1175 | |||
1176 | default: | ||
1177 | PERROR("Invalid acq stop trigger type specified.\n"); | ||
1178 | return ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE; | ||
1179 | } | ||
1180 | |||
1181 | switch (trigger->iAcqStartTrigChan) { | ||
1182 | case ME_TRIG_CHAN_DEFAULT: | ||
1183 | case ME_TRIG_CHAN_SYNCHRONOUS: | ||
1184 | break; | ||
1185 | |||
1186 | default: | ||
1187 | PERROR("Invalid acq start trigger channel specified.\n"); | ||
1188 | return ME_ERRNO_INVALID_ACQ_START_TRIG_CHAN; | ||
1189 | } | ||
1190 | |||
1191 | ME_SUBDEVICE_ENTER; | ||
1192 | |||
1193 | if ((flags & ME_IO_STREAM_CONFIG_BIT_PATTERN) && !instance->bitpattern) { | ||
1194 | PERROR("This subdevice not support output redirection.\n"); | ||
1195 | ME_SUBDEVICE_EXIT; | ||
1196 | return ME_ERRNO_INVALID_FLAGS; | ||
1197 | } | ||
1198 | //Stop device | ||
1199 | |||
1200 | //Cancel control task | ||
1201 | PDEBUG("Cancel control task. idx=%d\n", instance->ao_idx); | ||
1202 | instance->ao_control_task_flag = 0; | ||
1203 | cancel_delayed_work(&instance->ao_control_task); | ||
1204 | |||
1205 | //Check if state machine is stopped. | ||
1206 | err = ao_stop_immediately(instance); | ||
1207 | if (err) { | ||
1208 | PERROR_CRITICAL("FSM IS BUSY!\n"); | ||
1209 | ME_SUBDEVICE_EXIT; | ||
1210 | |||
1211 | return ME_ERRNO_SUBDEVICE_BUSY; | ||
1212 | } | ||
1213 | |||
1214 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
1215 | //Reset control register. Block all actions. Disable IRQ. Disable FIFO. | ||
1216 | ctrl = | ||
1217 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP | ME4600_AO_CTRL_BIT_STOP | | ||
1218 | ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
1219 | outl(ctrl, instance->ctrl_reg); | ||
1220 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
1221 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
1222 | |||
1223 | //This is paranoic, but to be sure. | ||
1224 | instance->preloaded_count = 0; | ||
1225 | instance->data_count = 0; | ||
1226 | instance->circ_buf.head = 0; | ||
1227 | instance->circ_buf.tail = 0; | ||
1228 | |||
1229 | /* Set mode. */ | ||
1230 | if (flags & ME_IO_STREAM_CONFIG_WRAPAROUND) { //Wraparound | ||
1231 | if (flags & ME_IO_STREAM_CONFIG_HARDWARE_ONLY) { //Hardware wraparound | ||
1232 | PINFO("Hardware wraparound.\n"); | ||
1233 | ctrl |= ME4600_AO_MODE_WRAPAROUND; | ||
1234 | instance->mode = ME4600_AO_HW_WRAP_MODE; | ||
1235 | } else { //Software wraparound | ||
1236 | PINFO("Software wraparound.\n"); | ||
1237 | ctrl |= ME4600_AO_MODE_CONTINUOUS; | ||
1238 | instance->mode = ME4600_AO_SW_WRAP_MODE; | ||
1239 | } | ||
1240 | } else { //Continous | ||
1241 | PINFO("Continous.\n"); | ||
1242 | ctrl |= ME4600_AO_MODE_CONTINUOUS; | ||
1243 | instance->mode = ME4600_AO_CONTINOUS; | ||
1244 | } | ||
1245 | |||
1246 | //Set the trigger edge. | ||
1247 | if (trigger->iAcqStartTrigType == ME_TRIG_TYPE_EXT_DIGITAL) { //Set the trigger type and edge for external trigger. | ||
1248 | PINFO("External digital trigger.\n"); | ||
1249 | instance->start_mode = ME4600_AO_EXT_TRIG; | ||
1250 | /* | ||
1251 | ctrl |= ME4600_AO_CTRL_BIT_ENABLE_EX_TRIG; | ||
1252 | */ | ||
1253 | switch (trigger->iAcqStartTrigEdge) { | ||
1254 | case ME_TRIG_EDGE_RISING: | ||
1255 | PINFO("Set the trigger edge: rising.\n"); | ||
1256 | instance->ctrl_trg = 0x0; | ||
1257 | break; | ||
1258 | |||
1259 | case ME_TRIG_EDGE_FALLING: | ||
1260 | PINFO("Set the trigger edge: falling.\n"); | ||
1261 | // ctrl |= ME4600_AO_CTRL_BIT_EX_TRIG_EDGE; | ||
1262 | instance->ctrl_trg = ME4600_AO_CTRL_BIT_EX_TRIG_EDGE; | ||
1263 | break; | ||
1264 | |||
1265 | case ME_TRIG_EDGE_ANY: | ||
1266 | PINFO("Set the trigger edge: both edges.\n"); | ||
1267 | // ctrl |= ME4600_AO_CTRL_BIT_EX_TRIG_EDGE | ME4600_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH; | ||
1268 | instance->ctrl_trg = | ||
1269 | ME4600_AO_CTRL_BIT_EX_TRIG_EDGE | | ||
1270 | ME4600_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH; | ||
1271 | break; | ||
1272 | } | ||
1273 | } else { | ||
1274 | PINFO("Internal software trigger.\n"); | ||
1275 | instance->start_mode = 0; | ||
1276 | } | ||
1277 | |||
1278 | //Set the stop mode and value. | ||
1279 | if (trigger->iAcqStopTrigType == ME_TRIG_TYPE_COUNT) { //Amount of data | ||
1280 | instance->stop_mode = ME4600_AO_ACQ_STOP_MODE; | ||
1281 | instance->stop_count = trigger->iAcqStopCount; | ||
1282 | } else if (trigger->iScanStopTrigType == ME_TRIG_TYPE_COUNT) { //Amount of 'scans' | ||
1283 | instance->stop_mode = ME4600_AO_SCAN_STOP_MODE; | ||
1284 | instance->stop_count = trigger->iScanStopCount; | ||
1285 | } else { //Infinite | ||
1286 | instance->stop_mode = ME4600_AO_INF_STOP_MODE; | ||
1287 | instance->stop_count = 0; | ||
1288 | } | ||
1289 | |||
1290 | PINFO("Stop count: %d.\n", instance->stop_count); | ||
1291 | |||
1292 | if (trigger->iAcqStartTrigChan == ME_TRIG_CHAN_SYNCHRONOUS) { //Synchronous start | ||
1293 | instance->start_mode |= ME4600_AO_SYNC_HOLD; | ||
1294 | if (trigger->iAcqStartTrigType == ME_TRIG_TYPE_EXT_DIGITAL) { //Externaly triggered | ||
1295 | PINFO("Synchronous start. Externaly trigger active.\n"); | ||
1296 | instance->start_mode |= ME4600_AO_SYNC_EXT_TRIG; | ||
1297 | } | ||
1298 | #ifdef MEDEBUG_INFO | ||
1299 | else { | ||
1300 | PINFO | ||
1301 | ("Synchronous start. Externaly trigger dissabled.\n"); | ||
1302 | } | ||
1303 | #endif | ||
1304 | |||
1305 | } | ||
1306 | //Set speed | ||
1307 | outl(conv_ticks - 2, instance->timer_reg); | ||
1308 | PDEBUG_REG("timer_reg outl(0x%lX+0x%lX)=0x%llx\n", instance->reg_base, | ||
1309 | instance->timer_reg - instance->reg_base, conv_ticks - 2); | ||
1310 | instance->hardware_stop_delay = (int)(conv_ticks * HZ) / ME4600_AO_BASE_FREQUENCY; //<== MUST be with cast! | ||
1311 | |||
1312 | //Conect outputs to analog or digital port. | ||
1313 | if (flags & ME_IO_STREAM_CONFIG_BIT_PATTERN) { | ||
1314 | ctrl |= ME4600_AO_CTRL_BIT_ENABLE_DO; | ||
1315 | } | ||
1316 | // Write the control word | ||
1317 | outl(ctrl, instance->ctrl_reg); | ||
1318 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
1319 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
1320 | |||
1321 | //Set status. | ||
1322 | instance->status = ao_status_stream_configured; | ||
1323 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
1324 | |||
1325 | ME_SUBDEVICE_EXIT; | ||
1326 | |||
1327 | return err; | ||
1328 | } | ||
1329 | |||
1330 | static int me4600_ao_io_stream_new_values(me_subdevice_t * subdevice, | ||
1331 | struct file *filep, | ||
1332 | int time_out, int *count, int flags) | ||
1333 | { | ||
1334 | me4600_ao_subdevice_t *instance; | ||
1335 | int err = ME_ERRNO_SUCCESS; | ||
1336 | long t = 0; | ||
1337 | long j; | ||
1338 | |||
1339 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
1340 | |||
1341 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
1342 | |||
1343 | if (!instance->fifo) { | ||
1344 | PERROR("Not a streaming ao.\n"); | ||
1345 | return ME_ERRNO_NOT_SUPPORTED; | ||
1346 | } | ||
1347 | |||
1348 | if (flags) { | ||
1349 | PERROR("Invalid flag specified.\n"); | ||
1350 | return ME_ERRNO_INVALID_FLAGS; | ||
1351 | } | ||
1352 | |||
1353 | if (!instance->circ_buf.buf) { | ||
1354 | PERROR("Circular buffer not exists.\n"); | ||
1355 | return ME_ERRNO_INTERNAL; | ||
1356 | } | ||
1357 | |||
1358 | if (time_out < 0) { | ||
1359 | PERROR("Invalid time_out specified.\n"); | ||
1360 | return ME_ERRNO_INVALID_TIMEOUT; | ||
1361 | } | ||
1362 | |||
1363 | ME_SUBDEVICE_ENTER; | ||
1364 | |||
1365 | if (me_circ_buf_space(&instance->circ_buf)) { //The buffer is NOT full. | ||
1366 | *count = me_circ_buf_space(&instance->circ_buf); | ||
1367 | } else { //The buffer is full. | ||
1368 | if (time_out) { | ||
1369 | t = (time_out * HZ) / 1000; | ||
1370 | |||
1371 | if (t == 0) | ||
1372 | t = 1; | ||
1373 | } else { //Max time. | ||
1374 | t = LONG_MAX; | ||
1375 | } | ||
1376 | |||
1377 | *count = 0; | ||
1378 | |||
1379 | j = jiffies; | ||
1380 | |||
1381 | //Only runing process will interrupt this call. Interrupts are when FIFO HF is signaled. | ||
1382 | wait_event_interruptible_timeout(instance->wait_queue, | ||
1383 | ((me_circ_buf_space | ||
1384 | (&instance->circ_buf)) | ||
1385 | || !(inl(instance->status_reg) | ||
1386 | & | ||
1387 | ME4600_AO_STATUS_BIT_FSM)), | ||
1388 | t); | ||
1389 | |||
1390 | if (!(inl(instance->status_reg) & ME4600_AO_STATUS_BIT_FSM)) { | ||
1391 | PERROR("AO subdevice is not running.\n"); | ||
1392 | err = ME_ERRNO_SUBDEVICE_NOT_RUNNING; | ||
1393 | } else if (signal_pending(current)) { | ||
1394 | PERROR("Wait on values interrupted from signal.\n"); | ||
1395 | instance->status = ao_status_none; | ||
1396 | ao_stop_immediately(instance); | ||
1397 | err = ME_ERRNO_SIGNAL; | ||
1398 | } else if ((jiffies - j) >= t) { | ||
1399 | PERROR("Wait on values timed out.\n"); | ||
1400 | err = ME_ERRNO_TIMEOUT; | ||
1401 | } else { //Uff... all is good. Inform user about empty space. | ||
1402 | *count = me_circ_buf_space(&instance->circ_buf); | ||
1403 | } | ||
1404 | } | ||
1405 | |||
1406 | ME_SUBDEVICE_EXIT; | ||
1407 | |||
1408 | return err; | ||
1409 | } | ||
1410 | |||
1411 | static int me4600_ao_io_stream_start(me_subdevice_t * subdevice, | ||
1412 | struct file *filep, | ||
1413 | int start_mode, int time_out, int flags) | ||
1414 | { | ||
1415 | me4600_ao_subdevice_t *instance; | ||
1416 | int err = ME_ERRNO_SUCCESS; | ||
1417 | unsigned long cpu_flags = 0; | ||
1418 | uint32_t status; | ||
1419 | uint32_t ctrl; | ||
1420 | uint32_t synch; | ||
1421 | int count = 0; | ||
1422 | int circ_buffer_count; | ||
1423 | |||
1424 | unsigned long ref; | ||
1425 | unsigned long delay = 0; | ||
1426 | |||
1427 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
1428 | |||
1429 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
1430 | |||
1431 | if (!instance->fifo) { | ||
1432 | PERROR("Not a streaming ao.\n"); | ||
1433 | return ME_ERRNO_NOT_SUPPORTED; | ||
1434 | } | ||
1435 | |||
1436 | if (flags & ~ME_IO_STREAM_START_TYPE_TRIG_SYNCHRONOUS) { | ||
1437 | PERROR("Invalid flags.\n"); | ||
1438 | return ME_ERRNO_INVALID_FLAGS; | ||
1439 | } | ||
1440 | |||
1441 | if (time_out < 0) { | ||
1442 | PERROR("Invalid timeout specified.\n"); | ||
1443 | return ME_ERRNO_INVALID_TIMEOUT; | ||
1444 | } | ||
1445 | |||
1446 | if ((start_mode != ME_START_MODE_BLOCKING) | ||
1447 | && (start_mode != ME_START_MODE_NONBLOCKING)) { | ||
1448 | PERROR("Invalid start mode specified.\n"); | ||
1449 | return ME_ERRNO_INVALID_START_MODE; | ||
1450 | } | ||
1451 | |||
1452 | if (time_out) { | ||
1453 | delay = (time_out * HZ) / 1000; | ||
1454 | if (delay == 0) | ||
1455 | delay = 1; | ||
1456 | } | ||
1457 | |||
1458 | switch (instance->status) { //Checking actual mode. | ||
1459 | case ao_status_stream_configured: | ||
1460 | case ao_status_stream_end: | ||
1461 | //Correct modes! | ||
1462 | break; | ||
1463 | |||
1464 | //The device is in wrong mode. | ||
1465 | case ao_status_none: | ||
1466 | case ao_status_single_configured: | ||
1467 | case ao_status_single_run_wait: | ||
1468 | case ao_status_single_run: | ||
1469 | case ao_status_single_end_wait: | ||
1470 | PERROR | ||
1471 | ("Subdevice must be preinitialize correctly for streaming.\n"); | ||
1472 | return ME_ERRNO_PREVIOUS_CONFIG; | ||
1473 | |||
1474 | case ao_status_stream_fifo_error: | ||
1475 | case ao_status_stream_buffer_error: | ||
1476 | case ao_status_stream_error: | ||
1477 | PDEBUG("Before restart broke stream 'STOP' must be caled.\n"); | ||
1478 | return ME_STATUS_ERROR; | ||
1479 | |||
1480 | case ao_status_stream_run_wait: | ||
1481 | case ao_status_stream_run: | ||
1482 | case ao_status_stream_end_wait: | ||
1483 | PDEBUG("Stream is already working.\n"); | ||
1484 | return ME_ERRNO_SUBDEVICE_BUSY; | ||
1485 | |||
1486 | default: | ||
1487 | instance->status = ao_status_stream_error; | ||
1488 | PERROR_CRITICAL("Status is in wrong state!\n"); | ||
1489 | return ME_ERRNO_INTERNAL; | ||
1490 | |||
1491 | } | ||
1492 | |||
1493 | ME_SUBDEVICE_ENTER; | ||
1494 | |||
1495 | if (instance->mode == ME4600_AO_CONTINOUS) { //Continous | ||
1496 | instance->circ_buf.tail += instance->preloaded_count; | ||
1497 | instance->circ_buf.tail &= instance->circ_buf.mask; | ||
1498 | } | ||
1499 | circ_buffer_count = me_circ_buf_values(&instance->circ_buf); | ||
1500 | |||
1501 | if (!circ_buffer_count && !instance->preloaded_count) { //No values in buffer | ||
1502 | ME_SUBDEVICE_EXIT; | ||
1503 | PERROR("No values in buffer!\n"); | ||
1504 | return ME_ERRNO_LACK_OF_RESOURCES; | ||
1505 | } | ||
1506 | |||
1507 | //Cancel control task | ||
1508 | PDEBUG("Cancel control task. idx=%d\n", instance->ao_idx); | ||
1509 | instance->ao_control_task_flag = 0; | ||
1510 | cancel_delayed_work(&instance->ao_control_task); | ||
1511 | |||
1512 | //Stop device | ||
1513 | err = ao_stop_immediately(instance); | ||
1514 | if (err) { | ||
1515 | PERROR_CRITICAL("FSM IS BUSY!\n"); | ||
1516 | ME_SUBDEVICE_EXIT; | ||
1517 | |||
1518 | return ME_ERRNO_SUBDEVICE_BUSY; | ||
1519 | } | ||
1520 | //Set values for single_read() | ||
1521 | instance->single_value = ME4600_AO_MAX_DATA + 1; | ||
1522 | instance->single_value_in_fifo = ME4600_AO_MAX_DATA + 1; | ||
1523 | |||
1524 | //Setting stop points | ||
1525 | if (instance->stop_mode == ME4600_AO_SCAN_STOP_MODE) { | ||
1526 | instance->stop_data_count = | ||
1527 | instance->stop_count * circ_buffer_count; | ||
1528 | } else { | ||
1529 | instance->stop_data_count = instance->stop_count; | ||
1530 | } | ||
1531 | |||
1532 | if ((instance->stop_data_count != 0) | ||
1533 | && (instance->stop_data_count < circ_buffer_count)) { | ||
1534 | PERROR("More data in buffer than previously set limit!\n"); | ||
1535 | } | ||
1536 | |||
1537 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
1538 | ctrl = inl(instance->ctrl_reg); | ||
1539 | //Check FIFO | ||
1540 | if (!(ctrl & ME4600_AO_CTRL_BIT_ENABLE_FIFO)) { //FIFO wasn't enabeled. Do it. <= This should be done by user call with ME_WRITE_MODE_PRELOAD | ||
1541 | PINFO("Enableing FIFO.\n"); | ||
1542 | ctrl |= | ||
1543 | ME4600_AO_CTRL_BIT_ENABLE_FIFO | | ||
1544 | ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
1545 | |||
1546 | instance->preloaded_count = 0; | ||
1547 | instance->data_count = 0; | ||
1548 | } else { //Block IRQ | ||
1549 | ctrl |= ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
1550 | } | ||
1551 | outl(ctrl, instance->ctrl_reg); | ||
1552 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
1553 | instance->ctrl_reg - instance->reg_base, | ||
1554 | ctrl | ME4600_AO_CTRL_BIT_RESET_IRQ); | ||
1555 | |||
1556 | //Fill FIFO <= Generaly this should be done by user pre-load call but this is second place to do it. | ||
1557 | status = inl(instance->status_reg); | ||
1558 | if (!(status & ME4600_AO_STATUS_BIT_EF)) { //FIFO empty | ||
1559 | if (instance->stop_data_count == 0) { | ||
1560 | count = ME4600_AO_FIFO_COUNT; | ||
1561 | } else { | ||
1562 | count = | ||
1563 | (ME4600_AO_FIFO_COUNT < | ||
1564 | instance-> | ||
1565 | stop_data_count) ? ME4600_AO_FIFO_COUNT : | ||
1566 | instance->stop_data_count; | ||
1567 | } | ||
1568 | |||
1569 | //Copy data | ||
1570 | count = | ||
1571 | ao_write_data(instance, count, instance->preloaded_count); | ||
1572 | |||
1573 | if (count < 0) { //This should never happend! | ||
1574 | PERROR_CRITICAL("COPY FINISH WITH ERROR!\n"); | ||
1575 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
1576 | cpu_flags); | ||
1577 | ME_SUBDEVICE_EXIT; | ||
1578 | return ME_ERRNO_INTERNAL; | ||
1579 | } | ||
1580 | } | ||
1581 | //Set pre-load features. | ||
1582 | spin_lock(instance->preload_reg_lock); | ||
1583 | synch = inl(instance->preload_reg); | ||
1584 | synch &= | ||
1585 | ~((ME4600_AO_SYNC_HOLD | ME4600_AO_SYNC_EXT_TRIG) << instance-> | ||
1586 | ao_idx); | ||
1587 | synch |= | ||
1588 | (instance->start_mode & ~ME4600_AO_EXT_TRIG) << instance->ao_idx; | ||
1589 | outl(synch, instance->preload_reg); | ||
1590 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
1591 | instance->preload_reg - instance->reg_base, synch); | ||
1592 | spin_unlock(instance->preload_reg_lock); | ||
1593 | |||
1594 | //Default count is '0' | ||
1595 | if (instance->mode == ME4600_AO_CONTINOUS) { //Continous | ||
1596 | instance->preloaded_count = 0; | ||
1597 | instance->circ_buf.tail += count; | ||
1598 | instance->circ_buf.tail &= instance->circ_buf.mask; | ||
1599 | } else { //Wraparound | ||
1600 | instance->preloaded_count += count; | ||
1601 | instance->data_count += count; | ||
1602 | |||
1603 | //Special case: Infinite wraparound with less than FIFO datas always should runs in hardware mode. | ||
1604 | if ((instance->stop_mode == ME4600_AO_INF_STOP_MODE) | ||
1605 | && (circ_buffer_count <= ME4600_AO_FIFO_COUNT)) { //Change to hardware wraparound | ||
1606 | PDEBUG | ||
1607 | ("Changeing mode from software wraparound to hardware wraparound.\n"); | ||
1608 | //Copy all data | ||
1609 | count = | ||
1610 | ao_write_data(instance, circ_buffer_count, | ||
1611 | instance->preloaded_count); | ||
1612 | ctrl &= ~ME4600_AO_CTRL_MODE_MASK; | ||
1613 | ctrl |= ME4600_AO_MODE_WRAPAROUND; | ||
1614 | } | ||
1615 | |||
1616 | if (instance->preloaded_count == me_circ_buf_values(&instance->circ_buf)) { //Reset position indicator. | ||
1617 | instance->preloaded_count = 0; | ||
1618 | } else if (instance->preloaded_count > me_circ_buf_values(&instance->circ_buf)) { //This should never happend! | ||
1619 | PERROR_CRITICAL | ||
1620 | ("PRELOADED MORE VALUES THAN ARE IN BUFFER!\n"); | ||
1621 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
1622 | cpu_flags); | ||
1623 | ME_SUBDEVICE_EXIT; | ||
1624 | return ME_ERRNO_INTERNAL; | ||
1625 | } | ||
1626 | } | ||
1627 | |||
1628 | //Set status to 'wait for start' | ||
1629 | instance->status = ao_status_stream_run_wait; | ||
1630 | |||
1631 | status = inl(instance->status_reg); | ||
1632 | //Start state machine and interrupts | ||
1633 | ctrl &= ~(ME4600_AO_CTRL_BIT_STOP | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP); | ||
1634 | if (instance->start_mode == ME4600_AO_EXT_TRIG) { // External trigger. | ||
1635 | PINFO("External trigger.\n"); | ||
1636 | ctrl |= ME4600_AO_CTRL_BIT_ENABLE_EX_TRIG; | ||
1637 | } | ||
1638 | if (!(status & ME4600_AO_STATUS_BIT_HF)) { //More than half! | ||
1639 | if ((ctrl & ME4600_AO_CTRL_MODE_MASK) == ME4600_AO_MODE_CONTINUOUS) { //Enable IRQ only when hardware_continous is set and FIFO is more than half | ||
1640 | ctrl &= ~ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
1641 | ctrl |= ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
1642 | } | ||
1643 | } | ||
1644 | outl(ctrl, instance->ctrl_reg); | ||
1645 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
1646 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
1647 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
1648 | |||
1649 | //Trigger output | ||
1650 | if (flags & ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS) { //Trigger outputs | ||
1651 | spin_lock(instance->preload_reg_lock); | ||
1652 | synch = inl(instance->preload_reg); | ||
1653 | //Add channel to start list | ||
1654 | outl(synch | (ME4600_AO_SYNC_HOLD << instance->ao_idx), | ||
1655 | instance->preload_reg); | ||
1656 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
1657 | instance->reg_base, | ||
1658 | instance->preload_reg - instance->reg_base, | ||
1659 | synch | (ME4600_AO_SYNC_HOLD << instance->ao_idx)); | ||
1660 | |||
1661 | //Fire | ||
1662 | PINFO | ||
1663 | ("Fired all software synchronous outputs by software trigger.\n"); | ||
1664 | outl(0x8000, instance->single_reg); | ||
1665 | PDEBUG_REG("single_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
1666 | instance->reg_base, | ||
1667 | instance->single_reg - instance->reg_base, 0x8000); | ||
1668 | |||
1669 | //Restore save settings | ||
1670 | outl(synch, instance->preload_reg); | ||
1671 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
1672 | instance->reg_base, | ||
1673 | instance->preload_reg - instance->reg_base, synch); | ||
1674 | spin_unlock(instance->preload_reg_lock); | ||
1675 | } else if (!instance->start_mode) { //Trigger outputs | ||
1676 | /* | ||
1677 | //Remove channel from start list. // <== Unnecessary. Removed. | ||
1678 | spin_lock(instance->preload_reg_lock); | ||
1679 | synch = inl(instance->preload_reg); | ||
1680 | outl(synch & ~(ME4600_AO_SYNC_HOLD << instance->ao_idx), instance->preload_reg); | ||
1681 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, instance->preload_reg - instance->reg_base, synch & ~(ME4600_AO_SYNC_HOLD << instance->ao_idx)); | ||
1682 | */ | ||
1683 | //Fire | ||
1684 | PINFO("Software trigger.\n"); | ||
1685 | outl(0x8000, instance->single_reg); | ||
1686 | PDEBUG_REG("single_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
1687 | instance->reg_base, | ||
1688 | instance->single_reg - instance->reg_base, 0x8000); | ||
1689 | |||
1690 | /* | ||
1691 | //Restore save settings. // <== Unnecessary. Removed. | ||
1692 | outl(synch, instance->preload_reg); | ||
1693 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, instance->preload_reg - instance->reg_base, synch); | ||
1694 | spin_unlock(instance->preload_reg_lock); | ||
1695 | */ | ||
1696 | } | ||
1697 | // Set control task's timeout | ||
1698 | ref = jiffies; | ||
1699 | instance->timeout.delay = delay; | ||
1700 | instance->timeout.start_time = ref; | ||
1701 | |||
1702 | if (status & ME4600_AO_STATUS_BIT_HF) { //Less than half but not empty! | ||
1703 | PINFO("Less than half.\n"); | ||
1704 | if (instance->stop_data_count != 0) { | ||
1705 | count = ME4600_AO_FIFO_COUNT / 2; | ||
1706 | } else { | ||
1707 | count = | ||
1708 | ((ME4600_AO_FIFO_COUNT / 2) < | ||
1709 | instance->stop_data_count) ? ME4600_AO_FIFO_COUNT / | ||
1710 | 2 : instance->stop_data_count; | ||
1711 | } | ||
1712 | |||
1713 | //Copy data | ||
1714 | count = | ||
1715 | ao_write_data(instance, count, instance->preloaded_count); | ||
1716 | |||
1717 | if (count < 0) { //This should never happend! | ||
1718 | PERROR_CRITICAL("COPY FINISH WITH ERROR!\n"); | ||
1719 | ME_SUBDEVICE_EXIT; | ||
1720 | return ME_ERRNO_INTERNAL; | ||
1721 | } | ||
1722 | |||
1723 | if (instance->mode == ME4600_AO_CONTINOUS) { //Continous | ||
1724 | instance->circ_buf.tail += count; | ||
1725 | instance->circ_buf.tail &= instance->circ_buf.mask; | ||
1726 | } else { //Wraparound | ||
1727 | instance->data_count += count; | ||
1728 | instance->preloaded_count += count; | ||
1729 | |||
1730 | if (instance->preloaded_count == me_circ_buf_values(&instance->circ_buf)) { //Reset position indicator. | ||
1731 | instance->preloaded_count = 0; | ||
1732 | } else if (instance->preloaded_count > me_circ_buf_values(&instance->circ_buf)) { //This should never happend! | ||
1733 | PERROR_CRITICAL | ||
1734 | ("PRELOADED MORE VALUES THAN ARE IN BUFFER!\n"); | ||
1735 | ME_SUBDEVICE_EXIT; | ||
1736 | return ME_ERRNO_INTERNAL; | ||
1737 | } | ||
1738 | } | ||
1739 | |||
1740 | status = inl(instance->status_reg); | ||
1741 | if (!(status & ME4600_AO_STATUS_BIT_HF)) { //More than half! | ||
1742 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
1743 | ctrl = inl(instance->ctrl_reg); | ||
1744 | ctrl &= ~ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
1745 | ctrl |= ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
1746 | outl(ctrl, instance->ctrl_reg); | ||
1747 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
1748 | instance->reg_base, | ||
1749 | instance->ctrl_reg - instance->reg_base, | ||
1750 | ctrl); | ||
1751 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
1752 | cpu_flags); | ||
1753 | } | ||
1754 | } | ||
1755 | //Special case: Limited wraparound with less than HALF FIFO datas need work around to generate first interrupt. | ||
1756 | if ((instance->stop_mode != ME4600_AO_INF_STOP_MODE) | ||
1757 | && (instance->mode == ME4600_AO_SW_WRAP_MODE) | ||
1758 | && (circ_buffer_count <= (ME4600_AO_FIFO_COUNT / 2))) { //Put more data to FIFO | ||
1759 | PINFO("Limited wraparound with less than HALF FIFO datas.\n"); | ||
1760 | if (instance->preloaded_count) { //This should never happend! | ||
1761 | PERROR_CRITICAL | ||
1762 | ("ERROR WHEN LOADING VALUES FOR WRAPAROUND!\n"); | ||
1763 | ME_SUBDEVICE_EXIT; | ||
1764 | return ME_ERRNO_INTERNAL; | ||
1765 | } | ||
1766 | |||
1767 | while (instance->stop_data_count > instance->data_count) { //Maximum data not set jet. | ||
1768 | //Copy to buffer | ||
1769 | if (circ_buffer_count != ao_write_data(instance, circ_buffer_count, 0)) { //This should never happend! | ||
1770 | PERROR_CRITICAL | ||
1771 | ("ERROR WHEN LOADING VALUES FOR WRAPAROUND!\n"); | ||
1772 | ME_SUBDEVICE_EXIT; | ||
1773 | return ME_ERRNO_INTERNAL; | ||
1774 | } | ||
1775 | instance->data_count += circ_buffer_count; | ||
1776 | |||
1777 | if (!((status = inl(instance->status_reg)) & ME4600_AO_STATUS_BIT_HF)) { //FIFO is more than half. Enable IRQ and end copy. | ||
1778 | spin_lock_irqsave(&instance->subdevice_lock, | ||
1779 | cpu_flags); | ||
1780 | ctrl = inl(instance->ctrl_reg); | ||
1781 | ctrl &= ~ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
1782 | ctrl |= ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
1783 | outl(ctrl, instance->ctrl_reg); | ||
1784 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
1785 | instance->reg_base, | ||
1786 | instance->ctrl_reg - | ||
1787 | instance->reg_base, ctrl); | ||
1788 | spin_unlock_irqrestore(&instance-> | ||
1789 | subdevice_lock, | ||
1790 | cpu_flags); | ||
1791 | break; | ||
1792 | } | ||
1793 | } | ||
1794 | } | ||
1795 | // Schedule control task. | ||
1796 | instance->ao_control_task_flag = 1; | ||
1797 | queue_delayed_work(instance->me4600_workqueue, | ||
1798 | &instance->ao_control_task, 1); | ||
1799 | |||
1800 | if (start_mode == ME_START_MODE_BLOCKING) { //Wait for start. | ||
1801 | //Only runing process will interrupt this call. Events are signaled when status change. Extra timeout add for safe reason. | ||
1802 | wait_event_interruptible_timeout(instance->wait_queue, | ||
1803 | (instance->status != | ||
1804 | ao_status_stream_run_wait), | ||
1805 | (delay) ? delay + | ||
1806 | 1 : LONG_MAX); | ||
1807 | |||
1808 | if ((instance->status != ao_status_stream_run) | ||
1809 | && (instance->status != ao_status_stream_end)) { | ||
1810 | PDEBUG("Starting stream canceled. %d\n", | ||
1811 | instance->status); | ||
1812 | err = ME_ERRNO_CANCELLED; | ||
1813 | } | ||
1814 | |||
1815 | if (signal_pending(current)) { | ||
1816 | PERROR("Wait on start of state machine interrupted.\n"); | ||
1817 | instance->status = ao_status_none; | ||
1818 | ao_stop_immediately(instance); | ||
1819 | err = ME_ERRNO_SIGNAL; | ||
1820 | } else if ((delay) && ((jiffies - ref) >= delay)) { | ||
1821 | if (instance->status != ao_status_stream_run) { | ||
1822 | if (instance->status == ao_status_stream_end) { | ||
1823 | PDEBUG("Timeout reached.\n"); | ||
1824 | } else { | ||
1825 | if ((jiffies - ref) > delay) { | ||
1826 | PERROR | ||
1827 | ("Timeout reached. Not handled by control task!\n"); | ||
1828 | } else { | ||
1829 | PERROR | ||
1830 | ("Timeout reached. Signal come but status is strange: %d\n", | ||
1831 | instance->status); | ||
1832 | } | ||
1833 | ao_stop_immediately(instance); | ||
1834 | } | ||
1835 | |||
1836 | instance->ao_control_task_flag = 0; | ||
1837 | cancel_delayed_work(&instance->ao_control_task); | ||
1838 | instance->status = ao_status_stream_end; | ||
1839 | err = ME_ERRNO_TIMEOUT; | ||
1840 | } | ||
1841 | } | ||
1842 | } | ||
1843 | |||
1844 | ME_SUBDEVICE_EXIT; | ||
1845 | return err; | ||
1846 | } | ||
1847 | |||
1848 | static int me4600_ao_io_stream_status(me_subdevice_t * subdevice, | ||
1849 | struct file *filep, | ||
1850 | int wait, | ||
1851 | int *status, int *values, int flags) | ||
1852 | { | ||
1853 | me4600_ao_subdevice_t *instance; | ||
1854 | int err = ME_ERRNO_SUCCESS; | ||
1855 | |||
1856 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
1857 | |||
1858 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
1859 | |||
1860 | if (!instance->fifo) { | ||
1861 | PERROR("Not a streaming ao.\n"); | ||
1862 | return ME_ERRNO_NOT_SUPPORTED; | ||
1863 | } | ||
1864 | |||
1865 | if (flags) { | ||
1866 | PERROR("Invalid flag specified.\n"); | ||
1867 | return ME_ERRNO_INVALID_FLAGS; | ||
1868 | } | ||
1869 | |||
1870 | if ((wait != ME_WAIT_NONE) && (wait != ME_WAIT_IDLE)) { | ||
1871 | PERROR("Invalid wait argument specified.\n"); | ||
1872 | *status = ME_STATUS_INVALID; | ||
1873 | return ME_ERRNO_INVALID_WAIT; | ||
1874 | } | ||
1875 | |||
1876 | ME_SUBDEVICE_ENTER; | ||
1877 | |||
1878 | switch (instance->status) { | ||
1879 | case ao_status_single_configured: | ||
1880 | case ao_status_single_end: | ||
1881 | case ao_status_stream_configured: | ||
1882 | case ao_status_stream_end: | ||
1883 | case ao_status_stream_fifo_error: | ||
1884 | case ao_status_stream_buffer_error: | ||
1885 | case ao_status_stream_error: | ||
1886 | *status = ME_STATUS_IDLE; | ||
1887 | break; | ||
1888 | |||
1889 | case ao_status_single_run_wait: | ||
1890 | case ao_status_single_run: | ||
1891 | case ao_status_single_end_wait: | ||
1892 | case ao_status_stream_run_wait: | ||
1893 | case ao_status_stream_run: | ||
1894 | case ao_status_stream_end_wait: | ||
1895 | *status = ME_STATUS_BUSY; | ||
1896 | break; | ||
1897 | |||
1898 | case ao_status_none: | ||
1899 | default: | ||
1900 | *status = | ||
1901 | (inl(instance->status_reg) & ME4600_AO_STATUS_BIT_FSM) ? | ||
1902 | ME_STATUS_BUSY : ME_STATUS_IDLE; | ||
1903 | break; | ||
1904 | } | ||
1905 | |||
1906 | if ((wait == ME_WAIT_IDLE) && (*status == ME_STATUS_BUSY)) { | ||
1907 | //Only runing process will interrupt this call. Events are signaled when status change. Extra timeout add for safe reason. | ||
1908 | wait_event_interruptible_timeout(instance->wait_queue, | ||
1909 | ((instance->status != | ||
1910 | ao_status_single_run_wait) | ||
1911 | && (instance->status != | ||
1912 | ao_status_single_run) | ||
1913 | && (instance->status != | ||
1914 | ao_status_single_end_wait) | ||
1915 | && (instance->status != | ||
1916 | ao_status_stream_run_wait) | ||
1917 | && (instance->status != | ||
1918 | ao_status_stream_run) | ||
1919 | && (instance->status != | ||
1920 | ao_status_stream_end_wait)), | ||
1921 | LONG_MAX); | ||
1922 | |||
1923 | if (instance->status != ao_status_stream_end) { | ||
1924 | PDEBUG("Wait for IDLE canceled. %d\n", | ||
1925 | instance->status); | ||
1926 | err = ME_ERRNO_CANCELLED; | ||
1927 | } | ||
1928 | |||
1929 | if (signal_pending(current)) { | ||
1930 | PERROR("Wait for IDLE interrupted.\n"); | ||
1931 | instance->status = ao_status_none; | ||
1932 | ao_stop_immediately(instance); | ||
1933 | err = ME_ERRNO_SIGNAL; | ||
1934 | } | ||
1935 | |||
1936 | *status = ME_STATUS_IDLE; | ||
1937 | } | ||
1938 | |||
1939 | *values = me_circ_buf_space(&instance->circ_buf); | ||
1940 | |||
1941 | ME_SUBDEVICE_EXIT; | ||
1942 | |||
1943 | return err; | ||
1944 | } | ||
1945 | |||
1946 | static int me4600_ao_io_stream_stop(me_subdevice_t * subdevice, | ||
1947 | struct file *filep, | ||
1948 | int stop_mode, int flags) | ||
1949 | { // Stop work and empty buffer and FIFO | ||
1950 | int err = ME_ERRNO_SUCCESS; | ||
1951 | me4600_ao_subdevice_t *instance; | ||
1952 | unsigned long cpu_flags; | ||
1953 | volatile uint32_t ctrl; | ||
1954 | |||
1955 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
1956 | |||
1957 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
1958 | |||
1959 | if (flags & ~ME_IO_STREAM_STOP_PRESERVE_BUFFERS) { | ||
1960 | PERROR("Invalid flag specified.\n"); | ||
1961 | return ME_ERRNO_INVALID_FLAGS; | ||
1962 | } | ||
1963 | |||
1964 | if ((stop_mode != ME_STOP_MODE_IMMEDIATE) | ||
1965 | && (stop_mode != ME_STOP_MODE_LAST_VALUE)) { | ||
1966 | PERROR("Invalid stop mode specified.\n"); | ||
1967 | return ME_ERRNO_INVALID_STOP_MODE; | ||
1968 | } | ||
1969 | |||
1970 | if (!instance->fifo) { | ||
1971 | PERROR("Not a streaming ao.\n"); | ||
1972 | return ME_ERRNO_NOT_SUPPORTED; | ||
1973 | } | ||
1974 | |||
1975 | if (instance->status < ao_status_stream_configured) { | ||
1976 | //There is nothing to stop! | ||
1977 | PERROR("Subdevice not in streaming mode. %d\n", | ||
1978 | instance->status); | ||
1979 | return ME_ERRNO_PREVIOUS_CONFIG; | ||
1980 | } | ||
1981 | |||
1982 | ME_SUBDEVICE_ENTER; | ||
1983 | |||
1984 | //Mark as stopping. => Software stop. | ||
1985 | instance->status = ao_status_stream_end_wait; | ||
1986 | |||
1987 | if (stop_mode == ME_STOP_MODE_IMMEDIATE) { //Stopped now! | ||
1988 | err = ao_stop_immediately(instance); | ||
1989 | } else if (stop_mode == ME_STOP_MODE_LAST_VALUE) { | ||
1990 | ctrl = inl(instance->ctrl_reg) & ME4600_AO_CTRL_MODE_MASK; | ||
1991 | if (ctrl == ME4600_AO_MODE_WRAPAROUND) { //Hardware wraparound => Hardware stop. | ||
1992 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
1993 | ctrl = inl(instance->ctrl_reg); | ||
1994 | ctrl |= | ||
1995 | ME4600_AO_CTRL_BIT_STOP | | ||
1996 | ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
1997 | ctrl &= ~ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
1998 | outl(ctrl, instance->ctrl_reg); | ||
1999 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2000 | instance->reg_base, | ||
2001 | instance->ctrl_reg - instance->reg_base, | ||
2002 | ctrl); | ||
2003 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
2004 | cpu_flags); | ||
2005 | } | ||
2006 | //Only runing process will interrupt this call. Events are signaled when status change. | ||
2007 | wait_event_interruptible_timeout(instance->wait_queue, | ||
2008 | (instance->status != | ||
2009 | ao_status_stream_end_wait), | ||
2010 | LONG_MAX); | ||
2011 | |||
2012 | if (instance->status != ao_status_stream_end) { | ||
2013 | PDEBUG("Stopping stream canceled.\n"); | ||
2014 | err = ME_ERRNO_CANCELLED; | ||
2015 | } | ||
2016 | |||
2017 | if (signal_pending(current)) { | ||
2018 | PERROR("Stopping stream interrupted.\n"); | ||
2019 | instance->status = ao_status_none; | ||
2020 | ao_stop_immediately(instance); | ||
2021 | err = ME_ERRNO_SIGNAL; | ||
2022 | } | ||
2023 | } | ||
2024 | |||
2025 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
2026 | ctrl = inl(instance->ctrl_reg); | ||
2027 | ctrl |= | ||
2028 | ME4600_AO_CTRL_BIT_STOP | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP | | ||
2029 | ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
2030 | ctrl &= ~ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
2031 | if (!flags) { //Reset FIFO | ||
2032 | ctrl &= ~ME4600_AO_CTRL_BIT_ENABLE_FIFO; | ||
2033 | } | ||
2034 | outl(ctrl, instance->ctrl_reg); | ||
2035 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
2036 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
2037 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
2038 | |||
2039 | if (!flags) { //Reset software buffer | ||
2040 | instance->circ_buf.head = 0; | ||
2041 | instance->circ_buf.tail = 0; | ||
2042 | instance->preloaded_count = 0; | ||
2043 | instance->data_count = 0; | ||
2044 | } | ||
2045 | |||
2046 | ME_SUBDEVICE_EXIT; | ||
2047 | |||
2048 | return err; | ||
2049 | } | ||
2050 | |||
2051 | static int me4600_ao_io_stream_write(me_subdevice_t * subdevice, | ||
2052 | struct file *filep, | ||
2053 | int write_mode, | ||
2054 | int *values, int *count, int flags) | ||
2055 | { | ||
2056 | int err = ME_ERRNO_SUCCESS; | ||
2057 | me4600_ao_subdevice_t *instance; | ||
2058 | unsigned long cpu_flags = 0; | ||
2059 | uint32_t reg_copy; | ||
2060 | |||
2061 | int copied_from_user = 0; | ||
2062 | int left_to_copy_from_user = *count; | ||
2063 | |||
2064 | int copied_values; | ||
2065 | |||
2066 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
2067 | |||
2068 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
2069 | |||
2070 | //Checking arguments | ||
2071 | if (!instance->fifo) { | ||
2072 | PERROR("Not a streaming ao.\n"); | ||
2073 | return ME_ERRNO_NOT_SUPPORTED; | ||
2074 | } | ||
2075 | |||
2076 | if (flags) { | ||
2077 | PERROR("Invalid flag specified.\n"); | ||
2078 | return ME_ERRNO_INVALID_FLAGS; | ||
2079 | } | ||
2080 | |||
2081 | if (*count <= 0) { | ||
2082 | PERROR("Invalid count of values specified.\n"); | ||
2083 | return ME_ERRNO_INVALID_VALUE_COUNT; | ||
2084 | } | ||
2085 | |||
2086 | if (values == NULL) { | ||
2087 | PERROR("Invalid address of values specified.\n"); | ||
2088 | return ME_ERRNO_INVALID_POINTER; | ||
2089 | } | ||
2090 | |||
2091 | if ((instance->status == ao_status_none) || (instance->status == ao_status_single_configured)) { //The device is in single mode. | ||
2092 | PERROR | ||
2093 | ("Subdevice must be preinitialize correctly for streaming.\n"); | ||
2094 | return ME_ERRNO_PREVIOUS_CONFIG; | ||
2095 | } | ||
2096 | /// @note If no 'pre-load' is used. stream_start() will move data to FIFO. | ||
2097 | switch (write_mode) { | ||
2098 | case ME_WRITE_MODE_PRELOAD: | ||
2099 | |||
2100 | //Device must be stopped. | ||
2101 | if ((instance->status != ao_status_stream_configured) | ||
2102 | && (instance->status != ao_status_stream_end)) { | ||
2103 | PERROR | ||
2104 | ("Subdevice mustn't be runing when 'pre-load' mode is used.\n"); | ||
2105 | return ME_ERRNO_PREVIOUS_CONFIG; | ||
2106 | } | ||
2107 | break; | ||
2108 | case ME_WRITE_MODE_NONBLOCKING: | ||
2109 | case ME_WRITE_MODE_BLOCKING: | ||
2110 | /// @note In blocking mode: When device is not runing and there is not enought space call will blocked up! | ||
2111 | /// @note Some other thread must empty buffer by starting engine. | ||
2112 | break; | ||
2113 | |||
2114 | default: | ||
2115 | PERROR("Invalid write mode specified.\n"); | ||
2116 | return ME_ERRNO_INVALID_WRITE_MODE; | ||
2117 | } | ||
2118 | |||
2119 | if (instance->mode & ME4600_AO_WRAP_MODE) { //Wraparound mode. Device must be stopped. | ||
2120 | if ((instance->status != ao_status_stream_configured) | ||
2121 | && (instance->status != ao_status_stream_end)) { | ||
2122 | PERROR | ||
2123 | ("Subdevice mustn't be runing when 'pre-load' mode is used.\n"); | ||
2124 | return ME_ERRNO_INVALID_WRITE_MODE; | ||
2125 | } | ||
2126 | } | ||
2127 | |||
2128 | if ((instance->mode == ME4600_AO_HW_WRAP_MODE) && (write_mode != ME_WRITE_MODE_PRELOAD)) { // hardware wrap_around mode. | ||
2129 | //This is transparent for user. | ||
2130 | PDEBUG("Changing write_mode to ME_WRITE_MODE_PRELOAD.\n"); | ||
2131 | write_mode = ME_WRITE_MODE_PRELOAD; | ||
2132 | } | ||
2133 | |||
2134 | ME_SUBDEVICE_ENTER; | ||
2135 | |||
2136 | if (write_mode == ME_WRITE_MODE_PRELOAD) { //Init enviroment - preload | ||
2137 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
2138 | reg_copy = inl(instance->ctrl_reg); | ||
2139 | //Check FIFO | ||
2140 | if (!(reg_copy & ME4600_AO_CTRL_BIT_ENABLE_FIFO)) { //FIFO not active. Enable it. | ||
2141 | reg_copy |= ME4600_AO_CTRL_BIT_ENABLE_FIFO; | ||
2142 | outl(reg_copy, instance->ctrl_reg); | ||
2143 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2144 | instance->reg_base, | ||
2145 | instance->ctrl_reg - instance->reg_base, | ||
2146 | reg_copy); | ||
2147 | instance->preloaded_count = 0; | ||
2148 | } | ||
2149 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
2150 | } | ||
2151 | |||
2152 | while (1) { | ||
2153 | //Copy to buffer. This step is common for all modes. | ||
2154 | copied_from_user = | ||
2155 | ao_get_data_from_user(instance, left_to_copy_from_user, | ||
2156 | values + (*count - | ||
2157 | left_to_copy_from_user)); | ||
2158 | left_to_copy_from_user -= copied_from_user; | ||
2159 | |||
2160 | reg_copy = inl(instance->status_reg); | ||
2161 | if ((instance->status == ao_status_stream_run) && !(reg_copy & ME4600_AO_STATUS_BIT_FSM)) { //BROKEN PIPE! The state machine is stoped but logical status show that should be working. | ||
2162 | PERROR("Broken pipe in write.\n"); | ||
2163 | err = ME_ERRNO_SUBDEVICE_NOT_RUNNING; | ||
2164 | break; | ||
2165 | } | ||
2166 | |||
2167 | if ((instance->status == ao_status_stream_run) && (instance->mode == ME4600_AO_CONTINOUS) && (reg_copy & ME4600_AO_STATUS_BIT_HF)) { //Continous mode runing and data are below half! | ||
2168 | |||
2169 | // Block interrupts. | ||
2170 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
2171 | reg_copy = inl(instance->ctrl_reg); | ||
2172 | //reg_copy &= ~ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
2173 | reg_copy |= ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
2174 | outl(reg_copy, instance->ctrl_reg); | ||
2175 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2176 | instance->reg_base, | ||
2177 | instance->ctrl_reg - instance->reg_base, | ||
2178 | reg_copy); | ||
2179 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
2180 | cpu_flags); | ||
2181 | |||
2182 | //Fast copy | ||
2183 | copied_values = | ||
2184 | ao_write_data(instance, ME4600_AO_FIFO_COUNT / 2, | ||
2185 | 0); | ||
2186 | if (copied_values > 0) { | ||
2187 | instance->circ_buf.tail += copied_values; | ||
2188 | instance->circ_buf.tail &= | ||
2189 | instance->circ_buf.mask; | ||
2190 | continue; | ||
2191 | } | ||
2192 | // Activate interrupts. | ||
2193 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
2194 | reg_copy = inl(instance->ctrl_reg); | ||
2195 | //reg_copy |= ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
2196 | reg_copy &= ~ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
2197 | outl(reg_copy, instance->ctrl_reg); | ||
2198 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2199 | instance->reg_base, | ||
2200 | instance->ctrl_reg - instance->reg_base, | ||
2201 | reg_copy); | ||
2202 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
2203 | cpu_flags); | ||
2204 | |||
2205 | if (copied_values == 0) { //This was checked and never should happend! | ||
2206 | PERROR_CRITICAL("COPING FINISH WITH 0!\n"); | ||
2207 | } | ||
2208 | |||
2209 | if (copied_values < 0) { //This was checked and never should happend! | ||
2210 | PERROR_CRITICAL | ||
2211 | ("COPING FINISH WITH AN ERROR!\n"); | ||
2212 | instance->status = ao_status_stream_fifo_error; | ||
2213 | err = ME_ERRNO_FIFO_BUFFER_OVERFLOW; | ||
2214 | break; | ||
2215 | } | ||
2216 | } | ||
2217 | |||
2218 | if (!left_to_copy_from_user) { //All datas were copied. | ||
2219 | break; | ||
2220 | } else { //Not all datas were copied. | ||
2221 | if (instance->mode & ME4600_AO_WRAP_MODE) { //Error too much datas! Wraparound is limited in size! | ||
2222 | PERROR | ||
2223 | ("Too much data for wraparound mode! Exceeded size of %ld.\n", | ||
2224 | ME4600_AO_CIRC_BUF_COUNT - 1); | ||
2225 | err = ME_ERRNO_RING_BUFFER_OVERFLOW; | ||
2226 | break; | ||
2227 | } | ||
2228 | |||
2229 | if (write_mode != ME_WRITE_MODE_BLOCKING) { //Non blocking calls | ||
2230 | break; | ||
2231 | } | ||
2232 | |||
2233 | wait_event_interruptible(instance->wait_queue, | ||
2234 | me_circ_buf_space(&instance-> | ||
2235 | circ_buf)); | ||
2236 | |||
2237 | if (signal_pending(current)) { | ||
2238 | PERROR("Writing interrupted by signal.\n"); | ||
2239 | instance->status = ao_status_none; | ||
2240 | ao_stop_immediately(instance); | ||
2241 | err = ME_ERRNO_SIGNAL; | ||
2242 | break; | ||
2243 | } | ||
2244 | |||
2245 | if (instance->status == ao_status_none) { //Reset | ||
2246 | PERROR("Writing interrupted by reset.\n"); | ||
2247 | err = ME_ERRNO_CANCELLED; | ||
2248 | break; | ||
2249 | } | ||
2250 | } | ||
2251 | } | ||
2252 | |||
2253 | if (write_mode == ME_WRITE_MODE_PRELOAD) { //Copy data to FIFO - preload | ||
2254 | copied_values = | ||
2255 | ao_write_data_pooling(instance, ME4600_AO_FIFO_COUNT, | ||
2256 | instance->preloaded_count); | ||
2257 | instance->preloaded_count += copied_values; | ||
2258 | instance->data_count += copied_values; | ||
2259 | |||
2260 | if ((instance->mode == ME4600_AO_HW_WRAP_MODE) | ||
2261 | && (me_circ_buf_values(&instance->circ_buf) > | ||
2262 | ME4600_AO_FIFO_COUNT)) { | ||
2263 | PERROR | ||
2264 | ("Too much data for hardware wraparound mode! Exceeded size of %d.\n", | ||
2265 | ME4600_AO_FIFO_COUNT); | ||
2266 | err = ME_ERRNO_FIFO_BUFFER_OVERFLOW; | ||
2267 | } | ||
2268 | } | ||
2269 | |||
2270 | *count = *count - left_to_copy_from_user; | ||
2271 | ME_SUBDEVICE_EXIT; | ||
2272 | |||
2273 | return err; | ||
2274 | } | ||
2275 | static irqreturn_t me4600_ao_isr(int irq, void *dev_id | ||
2276 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) | ||
2277 | , struct pt_regs *regs | ||
2278 | #endif | ||
2279 | ) | ||
2280 | { | ||
2281 | me4600_ao_subdevice_t *instance = dev_id; | ||
2282 | uint32_t irq_status; | ||
2283 | uint32_t ctrl; | ||
2284 | uint32_t status; | ||
2285 | int count = 0; | ||
2286 | |||
2287 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
2288 | |||
2289 | if (irq != instance->irq) { | ||
2290 | PERROR("Incorrect interrupt num: %d.\n", irq); | ||
2291 | return IRQ_NONE; | ||
2292 | } | ||
2293 | |||
2294 | irq_status = inl(instance->irq_status_reg); | ||
2295 | if (!(irq_status & (ME4600_IRQ_STATUS_BIT_AO_HF << instance->ao_idx))) { | ||
2296 | PINFO("%ld Shared interrupt. %s(): ID=%d: status_reg=0x%04X\n", | ||
2297 | jiffies, __FUNCTION__, instance->ao_idx, irq_status); | ||
2298 | return IRQ_NONE; | ||
2299 | } | ||
2300 | |||
2301 | if (!instance->circ_buf.buf) { | ||
2302 | instance->status = ao_status_stream_error; | ||
2303 | PERROR_CRITICAL("CIRCULAR BUFFER NOT EXISTS!\n"); | ||
2304 | //Block interrupts. Stop machine. | ||
2305 | ctrl = inl(instance->ctrl_reg); | ||
2306 | ctrl &= ~ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
2307 | ctrl |= | ||
2308 | ME4600_AO_CTRL_BIT_RESET_IRQ | | ||
2309 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP | ME4600_AO_CTRL_BIT_STOP; | ||
2310 | outl(ctrl, instance->ctrl_reg); | ||
2311 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2312 | instance->reg_base, | ||
2313 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
2314 | |||
2315 | //Inform user | ||
2316 | wake_up_interruptible_all(&instance->wait_queue); | ||
2317 | return IRQ_HANDLED; | ||
2318 | } | ||
2319 | |||
2320 | status = inl(instance->status_reg); | ||
2321 | if (!(status & ME4600_AO_STATUS_BIT_FSM)) { //Too late. Not working! END? BROKEN PIPE? | ||
2322 | PDEBUG("Interrupt come but ISM is not working!\n"); | ||
2323 | //Block interrupts. Stop machine. | ||
2324 | ctrl = inl(instance->ctrl_reg); | ||
2325 | ctrl &= ~ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
2326 | ctrl |= | ||
2327 | ME4600_AO_CTRL_BIT_RESET_IRQ | ME4600_AO_CTRL_BIT_STOP | | ||
2328 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
2329 | outl(ctrl, instance->ctrl_reg); | ||
2330 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2331 | instance->reg_base, | ||
2332 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
2333 | |||
2334 | return IRQ_HANDLED; | ||
2335 | } | ||
2336 | //General procedure. Process more datas. | ||
2337 | |||
2338 | #ifdef MEDEBUG_DEBUG | ||
2339 | if (!me_circ_buf_values(&instance->circ_buf)) { //Buffer is empty! | ||
2340 | PDEBUG("Circular buffer empty!\n"); | ||
2341 | } | ||
2342 | #endif | ||
2343 | |||
2344 | //Check FIFO | ||
2345 | if (status & ME4600_AO_STATUS_BIT_HF) { //OK less than half | ||
2346 | |||
2347 | //Block interrupts | ||
2348 | ctrl = inl(instance->ctrl_reg); | ||
2349 | ctrl &= ~ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
2350 | ctrl |= ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
2351 | outl(ctrl, instance->ctrl_reg); | ||
2352 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2353 | instance->reg_base, | ||
2354 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
2355 | |||
2356 | do { | ||
2357 | //Calculate how many should be copied. | ||
2358 | count = | ||
2359 | (instance->stop_data_count) ? instance-> | ||
2360 | stop_data_count - | ||
2361 | instance->data_count : ME4600_AO_FIFO_COUNT / 2; | ||
2362 | if (ME4600_AO_FIFO_COUNT / 2 < count) { | ||
2363 | count = ME4600_AO_FIFO_COUNT / 2; | ||
2364 | } | ||
2365 | //Copy data | ||
2366 | if (instance->mode == ME4600_AO_CONTINOUS) { //Continous | ||
2367 | count = ao_write_data(instance, count, 0); | ||
2368 | if (count > 0) { | ||
2369 | instance->circ_buf.tail += count; | ||
2370 | instance->circ_buf.tail &= | ||
2371 | instance->circ_buf.mask; | ||
2372 | instance->data_count += count; | ||
2373 | |||
2374 | if ((instance->status == ao_status_stream_end_wait) && !me_circ_buf_values(&instance->circ_buf)) { //Stoping. Whole buffer was copied. | ||
2375 | break; | ||
2376 | } | ||
2377 | } | ||
2378 | } else if ((instance->mode == ME4600_AO_SW_WRAP_MODE) && ((ctrl & ME4600_AO_CTRL_MODE_MASK) == ME4600_AO_MODE_CONTINUOUS)) { //Wraparound (software) | ||
2379 | if (instance->status == ao_status_stream_end_wait) { //We stoping => Copy to the end of the buffer. | ||
2380 | count = | ||
2381 | ao_write_data(instance, count, 0); | ||
2382 | } else { //Copy in wraparound mode. | ||
2383 | count = | ||
2384 | ao_write_data_wraparound(instance, | ||
2385 | count, | ||
2386 | instance-> | ||
2387 | preloaded_count); | ||
2388 | } | ||
2389 | |||
2390 | if (count > 0) { | ||
2391 | instance->data_count += count; | ||
2392 | instance->preloaded_count += count; | ||
2393 | instance->preloaded_count %= | ||
2394 | me_circ_buf_values(&instance-> | ||
2395 | circ_buf); | ||
2396 | |||
2397 | if ((instance->status == ao_status_stream_end_wait) && !instance->preloaded_count) { //Stoping. Whole buffer was copied. | ||
2398 | break; | ||
2399 | } | ||
2400 | } | ||
2401 | } | ||
2402 | |||
2403 | if ((count <= 0) || (instance->stop_data_count && (instance->stop_data_count <= instance->data_count))) { //End of work. | ||
2404 | break; | ||
2405 | } | ||
2406 | } //Repeat if still is under half fifo | ||
2407 | while ((status = | ||
2408 | inl(instance->status_reg)) & ME4600_AO_STATUS_BIT_HF); | ||
2409 | |||
2410 | //Unblock interrupts | ||
2411 | ctrl = inl(instance->ctrl_reg); | ||
2412 | if (count >= 0) { //Copy was successful. | ||
2413 | if (instance->stop_data_count && (instance->stop_data_count <= instance->data_count)) { //Finishing work. No more interrupts. | ||
2414 | PDEBUG("Finishing work. Interrupt disabled.\n"); | ||
2415 | instance->status = ao_status_stream_end_wait; | ||
2416 | } else if (count > 0) { //Normal work. Enable interrupt. | ||
2417 | PDEBUG("Normal work. Enable interrupt.\n"); | ||
2418 | ctrl &= ~ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
2419 | ctrl |= ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
2420 | } else { //Normal work but there are no more data in buffer. Interrupt active but blocked. stream_write() will unblock it. | ||
2421 | PDEBUG | ||
2422 | ("No data in software buffer. Interrupt blocked.\n"); | ||
2423 | ctrl |= ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
2424 | } | ||
2425 | } else { //Error during copy. | ||
2426 | instance->status = ao_status_stream_fifo_error; | ||
2427 | } | ||
2428 | |||
2429 | outl(ctrl, instance->ctrl_reg); | ||
2430 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2431 | instance->reg_base, | ||
2432 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
2433 | } else { //?? more than half | ||
2434 | PDEBUG | ||
2435 | ("Interrupt come but FIFO more than half full! Reset interrupt.\n"); | ||
2436 | //Reset pending interrupt | ||
2437 | ctrl = inl(instance->ctrl_reg); | ||
2438 | ctrl |= ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
2439 | outl(ctrl, instance->ctrl_reg); | ||
2440 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2441 | instance->reg_base, | ||
2442 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
2443 | ctrl &= ~ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
2444 | outl(ctrl, instance->ctrl_reg); | ||
2445 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2446 | instance->reg_base, | ||
2447 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
2448 | } | ||
2449 | |||
2450 | PINFO("ISR: Buffer count: %d.(T:%d H:%d)\n", | ||
2451 | me_circ_buf_values(&instance->circ_buf), instance->circ_buf.tail, | ||
2452 | instance->circ_buf.head); | ||
2453 | PINFO("ISR: Stop count: %d.\n", instance->stop_count); | ||
2454 | PINFO("ISR: Stop data count: %d.\n", instance->stop_data_count); | ||
2455 | PINFO("ISR: Data count: %d.\n", instance->data_count); | ||
2456 | |||
2457 | //Inform user | ||
2458 | wake_up_interruptible_all(&instance->wait_queue); | ||
2459 | |||
2460 | return IRQ_HANDLED; | ||
2461 | } | ||
2462 | |||
2463 | static void me4600_ao_destructor(struct me_subdevice *subdevice) | ||
2464 | { | ||
2465 | me4600_ao_subdevice_t *instance; | ||
2466 | |||
2467 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
2468 | |||
2469 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
2470 | |||
2471 | instance->ao_control_task_flag = 0; | ||
2472 | |||
2473 | // Reset subdevice to asure clean exit. | ||
2474 | me4600_ao_io_reset_subdevice(subdevice, NULL, | ||
2475 | ME_IO_RESET_SUBDEVICE_NO_FLAGS); | ||
2476 | |||
2477 | // Remove any tasks from work queue. This is paranoic because it was done allready in reset(). | ||
2478 | if (!cancel_delayed_work(&instance->ao_control_task)) { //Wait 2 ticks to be sure that control task is removed from queue. | ||
2479 | set_current_state(TASK_INTERRUPTIBLE); | ||
2480 | schedule_timeout(2); | ||
2481 | } | ||
2482 | |||
2483 | if (instance->fifo) { | ||
2484 | if (instance->irq) { | ||
2485 | free_irq(instance->irq, instance); | ||
2486 | instance->irq = 0; | ||
2487 | } | ||
2488 | |||
2489 | if (instance->circ_buf.buf) { | ||
2490 | free_pages((unsigned long)instance->circ_buf.buf, | ||
2491 | ME4600_AO_CIRC_BUF_SIZE_ORDER); | ||
2492 | } | ||
2493 | instance->circ_buf.buf = NULL; | ||
2494 | } | ||
2495 | |||
2496 | me_subdevice_deinit(&instance->base); | ||
2497 | kfree(instance); | ||
2498 | } | ||
2499 | |||
2500 | me4600_ao_subdevice_t *me4600_ao_constructor(uint32_t reg_base, | ||
2501 | spinlock_t * preload_reg_lock, | ||
2502 | uint32_t * preload_flags, | ||
2503 | int ao_idx, | ||
2504 | int fifo, | ||
2505 | int irq, | ||
2506 | struct workqueue_struct *me4600_wq) | ||
2507 | { | ||
2508 | me4600_ao_subdevice_t *subdevice; | ||
2509 | int err; | ||
2510 | |||
2511 | PDEBUG("executed. idx=%d\n", ao_idx); | ||
2512 | |||
2513 | // Allocate memory for subdevice instance. | ||
2514 | subdevice = kmalloc(sizeof(me4600_ao_subdevice_t), GFP_KERNEL); | ||
2515 | |||
2516 | if (!subdevice) { | ||
2517 | PERROR("Cannot get memory for subdevice instance.\n"); | ||
2518 | return NULL; | ||
2519 | } | ||
2520 | |||
2521 | memset(subdevice, 0, sizeof(me4600_ao_subdevice_t)); | ||
2522 | |||
2523 | // Initialize subdevice base class. | ||
2524 | err = me_subdevice_init(&subdevice->base); | ||
2525 | |||
2526 | if (err) { | ||
2527 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
2528 | kfree(subdevice); | ||
2529 | return NULL; | ||
2530 | } | ||
2531 | // Initialize spin locks. | ||
2532 | spin_lock_init(&subdevice->subdevice_lock); | ||
2533 | |||
2534 | subdevice->preload_reg_lock = preload_reg_lock; | ||
2535 | subdevice->preload_flags = preload_flags; | ||
2536 | |||
2537 | // Store analog output index. | ||
2538 | subdevice->ao_idx = ao_idx; | ||
2539 | |||
2540 | // Store if analog output has fifo. | ||
2541 | subdevice->fifo = (ao_idx < fifo) ? 1 : 0; | ||
2542 | |||
2543 | if (subdevice->fifo) { // Allocate and initialize circular buffer. | ||
2544 | subdevice->circ_buf.mask = ME4600_AO_CIRC_BUF_COUNT - 1; | ||
2545 | |||
2546 | subdevice->circ_buf.buf = | ||
2547 | (void *)__get_free_pages(GFP_KERNEL, | ||
2548 | ME4600_AO_CIRC_BUF_SIZE_ORDER); | ||
2549 | PDEBUG("circ_buf = %p size=%ld\n", subdevice->circ_buf.buf, | ||
2550 | ME4600_AO_CIRC_BUF_SIZE); | ||
2551 | |||
2552 | if (!subdevice->circ_buf.buf) { | ||
2553 | PERROR | ||
2554 | ("Cannot initialize subdevice base class instance.\n"); | ||
2555 | kfree(subdevice); | ||
2556 | return NULL; | ||
2557 | } | ||
2558 | |||
2559 | memset(subdevice->circ_buf.buf, 0, ME4600_AO_CIRC_BUF_SIZE); | ||
2560 | } else { // No FIFO. | ||
2561 | subdevice->circ_buf.mask = 0; | ||
2562 | subdevice->circ_buf.buf = NULL; | ||
2563 | } | ||
2564 | |||
2565 | subdevice->circ_buf.head = 0; | ||
2566 | subdevice->circ_buf.tail = 0; | ||
2567 | |||
2568 | subdevice->status = ao_status_none; | ||
2569 | subdevice->ao_control_task_flag = 0; | ||
2570 | subdevice->timeout.delay = 0; | ||
2571 | subdevice->timeout.start_time = jiffies; | ||
2572 | |||
2573 | // Initialize wait queue. | ||
2574 | init_waitqueue_head(&subdevice->wait_queue); | ||
2575 | |||
2576 | // Initialize single value to 0V. | ||
2577 | subdevice->single_value = 0x8000; | ||
2578 | subdevice->single_value_in_fifo = 0x8000; | ||
2579 | |||
2580 | // Register interrupt service routine. | ||
2581 | if (subdevice->fifo) { | ||
2582 | subdevice->irq = irq; | ||
2583 | if (request_irq(subdevice->irq, me4600_ao_isr, | ||
2584 | #ifdef IRQF_DISABLED | ||
2585 | IRQF_DISABLED | IRQF_SHARED, | ||
2586 | #else | ||
2587 | SA_INTERRUPT | SA_SHIRQ, | ||
2588 | #endif | ||
2589 | ME4600_NAME, subdevice)) { | ||
2590 | PERROR("Cannot get interrupt line.\n"); | ||
2591 | PDEBUG("free circ_buf = %p size=%d", | ||
2592 | subdevice->circ_buf.buf, | ||
2593 | PAGE_SHIFT << ME4600_AO_CIRC_BUF_SIZE_ORDER); | ||
2594 | free_pages((unsigned long)subdevice->circ_buf.buf, | ||
2595 | ME4600_AO_CIRC_BUF_SIZE_ORDER); | ||
2596 | me_subdevice_deinit((me_subdevice_t *) subdevice); | ||
2597 | kfree(subdevice); | ||
2598 | return NULL; | ||
2599 | } | ||
2600 | PINFO("Registered irq=%d.\n", subdevice->irq); | ||
2601 | } else { | ||
2602 | subdevice->irq = 0; | ||
2603 | } | ||
2604 | |||
2605 | // Initialize registers. | ||
2606 | subdevice->irq_status_reg = reg_base + ME4600_IRQ_STATUS_REG; | ||
2607 | subdevice->preload_reg = reg_base + ME4600_AO_SYNC_REG; | ||
2608 | if (ao_idx == 0) { | ||
2609 | subdevice->ctrl_reg = reg_base + ME4600_AO_00_CTRL_REG; | ||
2610 | subdevice->status_reg = reg_base + ME4600_AO_00_STATUS_REG; | ||
2611 | subdevice->fifo_reg = reg_base + ME4600_AO_00_FIFO_REG; | ||
2612 | subdevice->single_reg = reg_base + ME4600_AO_00_SINGLE_REG; | ||
2613 | subdevice->timer_reg = reg_base + ME4600_AO_00_TIMER_REG; | ||
2614 | subdevice->reg_base = reg_base; | ||
2615 | subdevice->bitpattern = 0; | ||
2616 | } else if (ao_idx == 1) { | ||
2617 | subdevice->ctrl_reg = reg_base + ME4600_AO_01_CTRL_REG; | ||
2618 | subdevice->status_reg = reg_base + ME4600_AO_01_STATUS_REG; | ||
2619 | subdevice->fifo_reg = reg_base + ME4600_AO_01_FIFO_REG; | ||
2620 | subdevice->single_reg = reg_base + ME4600_AO_01_SINGLE_REG; | ||
2621 | subdevice->timer_reg = reg_base + ME4600_AO_01_TIMER_REG; | ||
2622 | subdevice->reg_base = reg_base; | ||
2623 | subdevice->bitpattern = 0; | ||
2624 | } else if (ao_idx == 2) { | ||
2625 | subdevice->ctrl_reg = reg_base + ME4600_AO_02_CTRL_REG; | ||
2626 | subdevice->status_reg = reg_base + ME4600_AO_02_STATUS_REG; | ||
2627 | subdevice->fifo_reg = reg_base + ME4600_AO_02_FIFO_REG; | ||
2628 | subdevice->single_reg = reg_base + ME4600_AO_02_SINGLE_REG; | ||
2629 | subdevice->timer_reg = reg_base + ME4600_AO_02_TIMER_REG; | ||
2630 | subdevice->reg_base = reg_base; | ||
2631 | subdevice->bitpattern = 0; | ||
2632 | } else if (ao_idx == 3) { | ||
2633 | subdevice->ctrl_reg = reg_base + ME4600_AO_03_CTRL_REG; | ||
2634 | subdevice->status_reg = reg_base + ME4600_AO_03_STATUS_REG; | ||
2635 | subdevice->fifo_reg = reg_base + ME4600_AO_03_FIFO_REG; | ||
2636 | subdevice->single_reg = reg_base + ME4600_AO_03_SINGLE_REG; | ||
2637 | subdevice->timer_reg = reg_base + ME4600_AO_03_TIMER_REG; | ||
2638 | subdevice->reg_base = reg_base; | ||
2639 | subdevice->bitpattern = 1; | ||
2640 | } else { | ||
2641 | PERROR_CRITICAL("WRONG SUBDEVICE idx=%d!", ao_idx); | ||
2642 | me_subdevice_deinit((me_subdevice_t *) subdevice); | ||
2643 | if (subdevice->fifo) { | ||
2644 | free_pages((unsigned long)subdevice->circ_buf.buf, | ||
2645 | ME4600_AO_CIRC_BUF_SIZE_ORDER); | ||
2646 | } | ||
2647 | subdevice->circ_buf.buf = NULL; | ||
2648 | kfree(subdevice); | ||
2649 | return NULL; | ||
2650 | } | ||
2651 | |||
2652 | // Override base class methods. | ||
2653 | subdevice->base.me_subdevice_destructor = me4600_ao_destructor; | ||
2654 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
2655 | me4600_ao_io_reset_subdevice; | ||
2656 | subdevice->base.me_subdevice_io_single_config = | ||
2657 | me4600_ao_io_single_config; | ||
2658 | subdevice->base.me_subdevice_io_single_read = me4600_ao_io_single_read; | ||
2659 | subdevice->base.me_subdevice_io_single_write = | ||
2660 | me4600_ao_io_single_write; | ||
2661 | subdevice->base.me_subdevice_io_stream_config = | ||
2662 | me4600_ao_io_stream_config; | ||
2663 | subdevice->base.me_subdevice_io_stream_new_values = | ||
2664 | me4600_ao_io_stream_new_values; | ||
2665 | subdevice->base.me_subdevice_io_stream_write = | ||
2666 | me4600_ao_io_stream_write; | ||
2667 | subdevice->base.me_subdevice_io_stream_start = | ||
2668 | me4600_ao_io_stream_start; | ||
2669 | subdevice->base.me_subdevice_io_stream_status = | ||
2670 | me4600_ao_io_stream_status; | ||
2671 | subdevice->base.me_subdevice_io_stream_stop = me4600_ao_io_stream_stop; | ||
2672 | subdevice->base.me_subdevice_query_number_channels = | ||
2673 | me4600_ao_query_number_channels; | ||
2674 | subdevice->base.me_subdevice_query_subdevice_type = | ||
2675 | me4600_ao_query_subdevice_type; | ||
2676 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
2677 | me4600_ao_query_subdevice_caps; | ||
2678 | subdevice->base.me_subdevice_query_subdevice_caps_args = | ||
2679 | me4600_ao_query_subdevice_caps_args; | ||
2680 | subdevice->base.me_subdevice_query_range_by_min_max = | ||
2681 | me4600_ao_query_range_by_min_max; | ||
2682 | subdevice->base.me_subdevice_query_number_ranges = | ||
2683 | me4600_ao_query_number_ranges; | ||
2684 | subdevice->base.me_subdevice_query_range_info = | ||
2685 | me4600_ao_query_range_info; | ||
2686 | subdevice->base.me_subdevice_query_timer = me4600_ao_query_timer; | ||
2687 | |||
2688 | // Prepare work queue | ||
2689 | subdevice->me4600_workqueue = me4600_wq; | ||
2690 | |||
2691 | /* workqueue API changed in kernel 2.6.20 */ | ||
2692 | #if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ) | ||
2693 | INIT_WORK(&subdevice->ao_control_task, me4600_ao_work_control_task, | ||
2694 | (void *)subdevice); | ||
2695 | #else | ||
2696 | INIT_DELAYED_WORK(&subdevice->ao_control_task, | ||
2697 | me4600_ao_work_control_task); | ||
2698 | #endif | ||
2699 | |||
2700 | if (subdevice->fifo) { // Set speed for single operations. | ||
2701 | outl(ME4600_AO_MIN_CHAN_TICKS - 1, subdevice->timer_reg); | ||
2702 | subdevice->hardware_stop_delay = HZ / 10; //100ms | ||
2703 | } | ||
2704 | |||
2705 | return subdevice; | ||
2706 | } | ||
2707 | |||
2708 | /** @brief Stop presentation. Preserve FIFOs. | ||
2709 | * | ||
2710 | * @param instance The subdevice instance (pointer). | ||
2711 | */ | ||
2712 | int inline ao_stop_immediately(me4600_ao_subdevice_t * instance) | ||
2713 | { | ||
2714 | unsigned long cpu_flags; | ||
2715 | uint32_t ctrl; | ||
2716 | int timeout; | ||
2717 | int i; | ||
2718 | |||
2719 | timeout = | ||
2720 | (instance->hardware_stop_delay > | ||
2721 | (HZ / 10)) ? instance->hardware_stop_delay : HZ / 10; | ||
2722 | for (i = 0; i <= timeout; i++) { | ||
2723 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
2724 | // Stop all actions. No conditions! Block interrupts. Leave FIFO untouched! | ||
2725 | ctrl = inl(instance->ctrl_reg); | ||
2726 | ctrl |= | ||
2727 | ME4600_AO_CTRL_BIT_STOP | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP | ||
2728 | | ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
2729 | ctrl &= | ||
2730 | ~(ME4600_AO_CTRL_BIT_ENABLE_IRQ | | ||
2731 | ME4600_AO_CTRL_BIT_ENABLE_EX_TRIG); | ||
2732 | outl(ctrl, instance->ctrl_reg); | ||
2733 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2734 | instance->reg_base, | ||
2735 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
2736 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
2737 | |||
2738 | if (!(inl(instance->status_reg) & ME4600_AO_STATUS_BIT_FSM)) { // Exit. | ||
2739 | break; | ||
2740 | } | ||
2741 | //Still working! | ||
2742 | set_current_state(TASK_INTERRUPTIBLE); | ||
2743 | schedule_timeout(1); | ||
2744 | } | ||
2745 | |||
2746 | if (i > timeout) { | ||
2747 | PERROR_CRITICAL("FSM IS BUSY!\n"); | ||
2748 | return ME_ERRNO_INTERNAL; | ||
2749 | } | ||
2750 | return ME_ERRNO_SUCCESS; | ||
2751 | } | ||
2752 | |||
2753 | /** @brief Copy data from circular buffer to fifo (fast) in wraparound. | ||
2754 | * @note This is time critical function. Checking is done at begining and end only. | ||
2755 | * @note The is not reasonable way to check how many walues was in FIFO at begining. The count must be managed externaly. | ||
2756 | * | ||
2757 | * @param instance The subdevice instance (pointer). | ||
2758 | * @param count Maximum number of copied data. | ||
2759 | * @param start_pos Position of the firs value in buffer. | ||
2760 | * | ||
2761 | * @return On success: Number of copied data. | ||
2762 | * @return On error/success: 0. No datas were copied => no data in buffer. | ||
2763 | * @return On error: -ME_ERRNO_FIFO_BUFFER_OVERFLOW. | ||
2764 | */ | ||
2765 | int inline ao_write_data_wraparound(me4600_ao_subdevice_t * instance, int count, | ||
2766 | int start_pos) | ||
2767 | { /// @note This is time critical function! | ||
2768 | uint32_t status; | ||
2769 | uint32_t value; | ||
2770 | int pos = | ||
2771 | (instance->circ_buf.tail + start_pos) & instance->circ_buf.mask; | ||
2772 | int local_count = count; | ||
2773 | int i = 1; | ||
2774 | |||
2775 | if (count <= 0) { //Wrong count! | ||
2776 | return 0; | ||
2777 | } | ||
2778 | |||
2779 | while (i < local_count) { | ||
2780 | //Get value from buffer | ||
2781 | value = *(instance->circ_buf.buf + pos); | ||
2782 | //Prepare it | ||
2783 | if (instance->ao_idx & 0x1) { | ||
2784 | value <<= 16; | ||
2785 | } | ||
2786 | //Put value to FIFO | ||
2787 | outl(value, instance->fifo_reg); | ||
2788 | //PDEBUG_REG("idx=%d fifo_reg outl(0x%lX+0x%lX)=0x%x\n", instance->ao_idx, instance->reg_base, instance->fifo_reg - instance->reg_base, value); | ||
2789 | |||
2790 | pos++; | ||
2791 | pos &= instance->circ_buf.mask; | ||
2792 | if (pos == instance->circ_buf.head) { | ||
2793 | pos = instance->circ_buf.tail; | ||
2794 | } | ||
2795 | i++; | ||
2796 | } | ||
2797 | |||
2798 | status = inl(instance->status_reg); | ||
2799 | if (!(status & ME4600_AO_STATUS_BIT_FF)) { //FIFO is full before all datas were copied! | ||
2800 | PERROR("FIFO was full before all datas were copied! idx=%d\n", | ||
2801 | instance->ao_idx); | ||
2802 | return -ME_ERRNO_FIFO_BUFFER_OVERFLOW; | ||
2803 | } else { //Add last value | ||
2804 | value = *(instance->circ_buf.buf + pos); | ||
2805 | if (instance->ao_idx & 0x1) { | ||
2806 | value <<= 16; | ||
2807 | } | ||
2808 | //Put value to FIFO | ||
2809 | outl(value, instance->fifo_reg); | ||
2810 | //PDEBUG_REG("idx=%d fifo_reg outl(0x%lX+0x%lX)=0x%x\n", instance->ao_idx, instance->reg_base, instance->fifo_reg - instance->reg_base, value); | ||
2811 | } | ||
2812 | |||
2813 | PINFO("WRAPAROUND LOADED %d values. idx=%d\n", local_count, | ||
2814 | instance->ao_idx); | ||
2815 | return local_count; | ||
2816 | } | ||
2817 | |||
2818 | /** @brief Copy data from software buffer to fifo (fast). | ||
2819 | * @note This is time critical function. Checking is done at begining and end only. | ||
2820 | * @note The is not reasonable way to check how many walues was in FIFO at begining. The count must be managed externaly. | ||
2821 | * | ||
2822 | * @param instance The subdevice instance (pointer). | ||
2823 | * @param count Maximum number of copied data. | ||
2824 | * @param start_pos Position of the firs value in buffer. | ||
2825 | * | ||
2826 | * @return On success: Number of copied data. | ||
2827 | * @return On error/success: 0. No datas were copied => no data in buffer. | ||
2828 | * @return On error: -ME_ERRNO_FIFO_BUFFER_OVERFLOW. | ||
2829 | */ | ||
2830 | int inline ao_write_data(me4600_ao_subdevice_t * instance, int count, | ||
2831 | int start_pos) | ||
2832 | { /// @note This is time critical function! | ||
2833 | uint32_t status; | ||
2834 | uint32_t value; | ||
2835 | int pos = | ||
2836 | (instance->circ_buf.tail + start_pos) & instance->circ_buf.mask; | ||
2837 | int local_count = count; | ||
2838 | int max_count; | ||
2839 | int i = 1; | ||
2840 | |||
2841 | if (count <= 0) { //Wrong count! | ||
2842 | return 0; | ||
2843 | } | ||
2844 | |||
2845 | max_count = me_circ_buf_values(&instance->circ_buf) - start_pos; | ||
2846 | if (max_count <= 0) { //No data to copy! | ||
2847 | return 0; | ||
2848 | } | ||
2849 | |||
2850 | if (max_count < count) { | ||
2851 | local_count = max_count; | ||
2852 | } | ||
2853 | |||
2854 | while (i < local_count) { | ||
2855 | //Get value from buffer | ||
2856 | value = *(instance->circ_buf.buf + pos); | ||
2857 | //Prepare it | ||
2858 | if (instance->ao_idx & 0x1) { | ||
2859 | value <<= 16; | ||
2860 | } | ||
2861 | //Put value to FIFO | ||
2862 | outl(value, instance->fifo_reg); | ||
2863 | //PDEBUG_REG("idx=%d fifo_reg outl(0x%lX+0x%lX)=0x%x\n", instance->ao_idx, instance->reg_base, instance->fifo_reg - instance->reg_base, value); | ||
2864 | |||
2865 | pos++; | ||
2866 | pos &= instance->circ_buf.mask; | ||
2867 | i++; | ||
2868 | } | ||
2869 | |||
2870 | status = inl(instance->status_reg); | ||
2871 | if (!(status & ME4600_AO_STATUS_BIT_FF)) { //FIFO is full before all datas were copied! | ||
2872 | PERROR("FIFO was full before all datas were copied! idx=%d\n", | ||
2873 | instance->ao_idx); | ||
2874 | return -ME_ERRNO_FIFO_BUFFER_OVERFLOW; | ||
2875 | } else { //Add last value | ||
2876 | value = *(instance->circ_buf.buf + pos); | ||
2877 | if (instance->ao_idx & 0x1) { | ||
2878 | value <<= 16; | ||
2879 | } | ||
2880 | //Put value to FIFO | ||
2881 | outl(value, instance->fifo_reg); | ||
2882 | //PDEBUG_REG("idx=%d fifo_reg outl(0x%lX+0x%lX)=0x%x\n", instance->ao_idx, instance->reg_base, instance->fifo_reg - instance->reg_base, value); | ||
2883 | } | ||
2884 | |||
2885 | PINFO("FAST LOADED %d values. idx=%d\n", local_count, instance->ao_idx); | ||
2886 | return local_count; | ||
2887 | } | ||
2888 | |||
2889 | /** @brief Copy data from software buffer to fifo (slow). | ||
2890 | * @note This is slow function that copy all data from buffer to FIFO with full control. | ||
2891 | * | ||
2892 | * @param instance The subdevice instance (pointer). | ||
2893 | * @param count Maximum number of copied data. | ||
2894 | * @param start_pos Position of the firs value in buffer. | ||
2895 | * | ||
2896 | * @return On success: Number of copied values. | ||
2897 | * @return On error/success: 0. FIFO was full at begining. | ||
2898 | * @return On error: -ME_ERRNO_RING_BUFFER_UNDEFFLOW. | ||
2899 | */ | ||
2900 | int inline ao_write_data_pooling(me4600_ao_subdevice_t * instance, int count, | ||
2901 | int start_pos) | ||
2902 | { /// @note This is slow function! | ||
2903 | uint32_t status; | ||
2904 | uint32_t value; | ||
2905 | int pos = | ||
2906 | (instance->circ_buf.tail + start_pos) & instance->circ_buf.mask; | ||
2907 | int local_count = count; | ||
2908 | int i; | ||
2909 | int max_count; | ||
2910 | |||
2911 | if (count <= 0) { //Wrong count! | ||
2912 | PERROR("SLOW LOADED: Wrong count! idx=%d\n", instance->ao_idx); | ||
2913 | return 0; | ||
2914 | } | ||
2915 | |||
2916 | max_count = me_circ_buf_values(&instance->circ_buf) - start_pos; | ||
2917 | if (max_count <= 0) { //No data to copy! | ||
2918 | PERROR("SLOW LOADED: No data to copy! idx=%d\n", | ||
2919 | instance->ao_idx); | ||
2920 | return 0; | ||
2921 | } | ||
2922 | |||
2923 | if (max_count < count) { | ||
2924 | local_count = max_count; | ||
2925 | } | ||
2926 | |||
2927 | for (i = 0; i < local_count; i++) { | ||
2928 | status = inl(instance->status_reg); | ||
2929 | if (!(status & ME4600_AO_STATUS_BIT_FF)) { //FIFO is full! | ||
2930 | return i; | ||
2931 | } | ||
2932 | //Get value from buffer | ||
2933 | value = *(instance->circ_buf.buf + pos); | ||
2934 | //Prepare it | ||
2935 | if (instance->ao_idx & 0x1) { | ||
2936 | value <<= 16; | ||
2937 | } | ||
2938 | //Put value to FIFO | ||
2939 | outl(value, instance->fifo_reg); | ||
2940 | //PDEBUG_REG("idx=%d fifo_reg outl(0x%lX+0x%lX)=0x%x\n", instance->ao_idx, instance->reg_base, instance->fifo_reg - instance->reg_base, value); | ||
2941 | |||
2942 | pos++; | ||
2943 | pos &= instance->circ_buf.mask; | ||
2944 | } | ||
2945 | |||
2946 | PINFO("SLOW LOADED %d values. idx=%d\n", local_count, instance->ao_idx); | ||
2947 | return local_count; | ||
2948 | } | ||
2949 | |||
2950 | /** @brief Copy data from user space to circular buffer. | ||
2951 | * @param instance The subdevice instance (pointer). | ||
2952 | * @param count Number of datas in user space. | ||
2953 | * @param user_values Buffer's pointer. | ||
2954 | * | ||
2955 | * @return On success: Number of copied values. | ||
2956 | * @return On error: -ME_ERRNO_INTERNAL. | ||
2957 | */ | ||
2958 | int inline ao_get_data_from_user(me4600_ao_subdevice_t * instance, int count, | ||
2959 | int *user_values) | ||
2960 | { | ||
2961 | int i, err; | ||
2962 | int empty_space; | ||
2963 | int copied; | ||
2964 | int value; | ||
2965 | |||
2966 | empty_space = me_circ_buf_space(&instance->circ_buf); | ||
2967 | //We have only this space free. | ||
2968 | copied = (count < empty_space) ? count : empty_space; | ||
2969 | for (i = 0; i < copied; i++) { //Copy from user to buffer | ||
2970 | if ((err = get_user(value, (int *)(user_values + i)))) { | ||
2971 | PERROR | ||
2972 | ("BUFFER LOADED: get_user(0x%p) return an error: %d. idx=%d\n", | ||
2973 | user_values + i, err, instance->ao_idx); | ||
2974 | return -ME_ERRNO_INTERNAL; | ||
2975 | } | ||
2976 | /// @note The analog output in me4600 series has size of 16 bits. | ||
2977 | *(instance->circ_buf.buf + instance->circ_buf.head) = | ||
2978 | (uint16_t) value; | ||
2979 | instance->circ_buf.head++; | ||
2980 | instance->circ_buf.head &= instance->circ_buf.mask; | ||
2981 | } | ||
2982 | |||
2983 | PINFO("BUFFER LOADED %d values. idx=%d\n", copied, instance->ao_idx); | ||
2984 | return copied; | ||
2985 | } | ||
2986 | |||
2987 | /** @brief Checking actual hardware and logical state. | ||
2988 | * @param instance The subdevice instance (pointer). | ||
2989 | */ | ||
2990 | static void me4600_ao_work_control_task( | ||
2991 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) | ||
2992 | void *subdevice | ||
2993 | #else | ||
2994 | struct work_struct *work | ||
2995 | #endif | ||
2996 | ) | ||
2997 | { | ||
2998 | me4600_ao_subdevice_t *instance; | ||
2999 | unsigned long cpu_flags = 0; | ||
3000 | uint32_t status; | ||
3001 | uint32_t ctrl; | ||
3002 | uint32_t synch; | ||
3003 | int reschedule = 0; | ||
3004 | int signaling = 0; | ||
3005 | |||
3006 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) | ||
3007 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
3008 | #else | ||
3009 | instance = | ||
3010 | container_of((void *)work, me4600_ao_subdevice_t, ao_control_task); | ||
3011 | #endif | ||
3012 | PINFO("<%s: %ld> executed. idx=%d\n", __FUNCTION__, jiffies, | ||
3013 | instance->ao_idx); | ||
3014 | |||
3015 | status = inl(instance->status_reg); | ||
3016 | PDEBUG_REG("status_reg inl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
3017 | instance->status_reg - instance->reg_base, status); | ||
3018 | |||
3019 | switch (instance->status) { // Checking actual mode. | ||
3020 | |||
3021 | // Not configured for work. | ||
3022 | case ao_status_none: | ||
3023 | break; | ||
3024 | |||
3025 | //This are stable modes. No need to do anything. (?) | ||
3026 | case ao_status_single_configured: | ||
3027 | case ao_status_stream_configured: | ||
3028 | case ao_status_stream_fifo_error: | ||
3029 | case ao_status_stream_buffer_error: | ||
3030 | case ao_status_stream_error: | ||
3031 | PERROR("Shouldn't be running!.\n"); | ||
3032 | break; | ||
3033 | |||
3034 | case ao_status_stream_end: | ||
3035 | if (!instance->fifo) { | ||
3036 | PERROR_CRITICAL | ||
3037 | ("Streaming on single device! This feature is not implemented in this version!\n"); | ||
3038 | instance->status = ao_status_stream_error; | ||
3039 | // Signal the end. | ||
3040 | signaling = 1; | ||
3041 | break; | ||
3042 | } | ||
3043 | case ao_status_single_end: | ||
3044 | if (status & ME4600_AO_STATUS_BIT_FSM) { // State machine is working but the status is set to end. Force stop. | ||
3045 | |||
3046 | // Wait for stop. | ||
3047 | reschedule = 1; | ||
3048 | } | ||
3049 | |||
3050 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
3051 | // Stop all actions. No conditions! Block interrupts and trigger. Leave FIFO untouched! | ||
3052 | ctrl = inl(instance->ctrl_reg); | ||
3053 | ctrl |= | ||
3054 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP | ME4600_AO_CTRL_BIT_STOP | ||
3055 | | ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
3056 | ctrl &= | ||
3057 | ~(ME4600_AO_CTRL_BIT_ENABLE_IRQ | | ||
3058 | ME4600_AO_CTRL_BIT_ENABLE_EX_TRIG); | ||
3059 | ctrl &= | ||
3060 | ~(ME4600_AO_CTRL_BIT_EX_TRIG_EDGE | | ||
3061 | ME4600_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH); | ||
3062 | outl(ctrl, instance->ctrl_reg); | ||
3063 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3064 | instance->reg_base, | ||
3065 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
3066 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
3067 | break; | ||
3068 | |||
3069 | // Single modes | ||
3070 | case ao_status_single_run_wait: | ||
3071 | case ao_status_single_run: | ||
3072 | case ao_status_single_end_wait: | ||
3073 | |||
3074 | if (!(status & ME4600_AO_STATUS_BIT_FSM)) { // State machine is not working. | ||
3075 | if (((instance->fifo) | ||
3076 | && (!(status & ME4600_AO_STATUS_BIT_EF))) | ||
3077 | || (!(instance->fifo))) { // Single is in end state. | ||
3078 | PDEBUG("Single call has been complited.\n"); | ||
3079 | |||
3080 | // Set correct value for single_read(); | ||
3081 | instance->single_value = | ||
3082 | instance->single_value_in_fifo; | ||
3083 | |||
3084 | // Set status as 'ao_status_single_end' | ||
3085 | instance->status = ao_status_single_end; | ||
3086 | |||
3087 | // Signal the end. | ||
3088 | signaling = 1; | ||
3089 | // Wait for stop ISM. | ||
3090 | reschedule = 1; | ||
3091 | |||
3092 | break; | ||
3093 | } | ||
3094 | } | ||
3095 | // Check timeout. | ||
3096 | if ((instance->timeout.delay) && ((jiffies - instance->timeout.start_time) >= instance->timeout.delay)) { // Timeout | ||
3097 | PDEBUG("Timeout reached.\n"); | ||
3098 | // Stop all actions. No conditions! Block interrupts and trigger. Leave FIFO untouched! | ||
3099 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
3100 | ctrl = inl(instance->ctrl_reg); | ||
3101 | ctrl |= | ||
3102 | ME4600_AO_CTRL_BIT_STOP | | ||
3103 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP | | ||
3104 | ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
3105 | ctrl &= | ||
3106 | ~(ME4600_AO_CTRL_BIT_ENABLE_IRQ | | ||
3107 | ME4600_AO_CTRL_BIT_ENABLE_EX_TRIG); | ||
3108 | /// Fix for timeout error. | ||
3109 | ctrl &= | ||
3110 | ~(ME4600_AO_CTRL_BIT_EX_TRIG_EDGE | | ||
3111 | ME4600_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH); | ||
3112 | if (instance->fifo) { //Disabling FIFO | ||
3113 | ctrl &= ~ME4600_AO_CTRL_BIT_ENABLE_FIFO; | ||
3114 | } | ||
3115 | outl(ctrl, instance->ctrl_reg); | ||
3116 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3117 | instance->reg_base, | ||
3118 | instance->ctrl_reg - instance->reg_base, | ||
3119 | ctrl); | ||
3120 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
3121 | cpu_flags); | ||
3122 | |||
3123 | spin_lock(instance->preload_reg_lock); | ||
3124 | //Remove from synchronous start. Block triggering from this output. | ||
3125 | synch = inl(instance->preload_reg); | ||
3126 | synch &= | ||
3127 | ~((ME4600_AO_SYNC_HOLD | ME4600_AO_SYNC_EXT_TRIG) << | ||
3128 | instance->ao_idx); | ||
3129 | if (!(instance->fifo)) { // No FIFO - set to single safe mode | ||
3130 | synch |= | ||
3131 | ME4600_AO_SYNC_HOLD << instance->ao_idx; | ||
3132 | } | ||
3133 | outl(synch, instance->preload_reg); | ||
3134 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3135 | instance->reg_base, | ||
3136 | instance->preload_reg - instance->reg_base, | ||
3137 | synch); | ||
3138 | spin_unlock(instance->preload_reg_lock); | ||
3139 | |||
3140 | if (!(instance->fifo)) { // No FIFO | ||
3141 | // Restore old settings. | ||
3142 | PDEBUG("Write old value back to register.\n"); | ||
3143 | outl(instance->single_value, | ||
3144 | instance->single_reg); | ||
3145 | PDEBUG_REG | ||
3146 | ("single_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3147 | instance->reg_base, | ||
3148 | instance->single_reg - instance->reg_base, | ||
3149 | instance->single_value); | ||
3150 | } | ||
3151 | // Set correct value for single_read(); | ||
3152 | instance->single_value_in_fifo = instance->single_value; | ||
3153 | |||
3154 | instance->status = ao_status_single_end; | ||
3155 | |||
3156 | // Signal the end. | ||
3157 | signaling = 1; | ||
3158 | } | ||
3159 | // Wait for stop. | ||
3160 | reschedule = 1; | ||
3161 | break; | ||
3162 | |||
3163 | // Stream modes | ||
3164 | case ao_status_stream_run_wait: | ||
3165 | if (!instance->fifo) { | ||
3166 | PERROR_CRITICAL | ||
3167 | ("Streaming on single device! This feature is not implemented in this version!\n"); | ||
3168 | instance->status = ao_status_stream_error; | ||
3169 | // Signal the end. | ||
3170 | signaling = 1; | ||
3171 | break; | ||
3172 | } | ||
3173 | |||
3174 | if (status & ME4600_AO_STATUS_BIT_FSM) { // State machine is working. Waiting for start finish. | ||
3175 | instance->status = ao_status_stream_run; | ||
3176 | |||
3177 | // Signal end of this step | ||
3178 | signaling = 1; | ||
3179 | } else { // State machine is not working. | ||
3180 | if (!(status & ME4600_AO_STATUS_BIT_EF)) { // FIFO is empty. Procedure has started and finish already! | ||
3181 | instance->status = ao_status_stream_end; | ||
3182 | |||
3183 | // Signal the end. | ||
3184 | signaling = 1; | ||
3185 | // Wait for stop. | ||
3186 | reschedule = 1; | ||
3187 | break; | ||
3188 | } | ||
3189 | } | ||
3190 | |||
3191 | // Check timeout. | ||
3192 | if ((instance->timeout.delay) && ((jiffies - instance->timeout.start_time) >= instance->timeout.delay)) { // Timeout | ||
3193 | PDEBUG("Timeout reached.\n"); | ||
3194 | // Stop all actions. No conditions! Block interrupts. Leave FIFO untouched! | ||
3195 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
3196 | ctrl = inl(instance->ctrl_reg); | ||
3197 | ctrl |= | ||
3198 | ME4600_AO_CTRL_BIT_STOP | | ||
3199 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP | | ||
3200 | ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
3201 | ctrl &= | ||
3202 | ~(ME4600_AO_CTRL_BIT_ENABLE_IRQ | | ||
3203 | ME4600_AO_CTRL_BIT_ENABLE_EX_TRIG); | ||
3204 | outl(ctrl, instance->ctrl_reg); | ||
3205 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3206 | instance->reg_base, | ||
3207 | instance->ctrl_reg - instance->reg_base, | ||
3208 | ctrl); | ||
3209 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
3210 | cpu_flags); | ||
3211 | spin_lock(instance->preload_reg_lock); | ||
3212 | //Remove from synchronous start. Block triggering from this output. | ||
3213 | synch = inl(instance->preload_reg); | ||
3214 | synch &= | ||
3215 | ~((ME4600_AO_SYNC_HOLD | ME4600_AO_SYNC_EXT_TRIG) << | ||
3216 | instance->ao_idx); | ||
3217 | outl(synch, instance->preload_reg); | ||
3218 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3219 | instance->reg_base, | ||
3220 | instance->preload_reg - instance->reg_base, | ||
3221 | synch); | ||
3222 | spin_unlock(instance->preload_reg_lock); | ||
3223 | |||
3224 | instance->status = ao_status_stream_end; | ||
3225 | |||
3226 | // Signal the end. | ||
3227 | signaling = 1; | ||
3228 | } | ||
3229 | // Wait for stop. | ||
3230 | reschedule = 1; | ||
3231 | break; | ||
3232 | |||
3233 | case ao_status_stream_run: | ||
3234 | if (!instance->fifo) { | ||
3235 | PERROR_CRITICAL | ||
3236 | ("Streaming on single device! This feature is not implemented in this version!\n"); | ||
3237 | instance->status = ao_status_stream_error; | ||
3238 | // Signal the end. | ||
3239 | signaling = 1; | ||
3240 | break; | ||
3241 | } | ||
3242 | |||
3243 | if (!(status & ME4600_AO_STATUS_BIT_FSM)) { // State machine is not working. This is an error. | ||
3244 | // BROKEN PIPE! | ||
3245 | if (!(status & ME4600_AO_STATUS_BIT_EF)) { // FIFO is empty. | ||
3246 | if (me_circ_buf_values(&instance->circ_buf)) { // Software buffer is not empty. | ||
3247 | if (instance->stop_data_count && (instance->stop_data_count <= instance->data_count)) { //Finishing work. Requed data shown. | ||
3248 | PDEBUG | ||
3249 | ("ISM stoped. No data in FIFO. Buffer is not empty.\n"); | ||
3250 | instance->status = | ||
3251 | ao_status_stream_end; | ||
3252 | } else { | ||
3253 | PERROR | ||
3254 | ("Output stream has been broken. ISM stoped. No data in FIFO. Buffer is not empty.\n"); | ||
3255 | instance->status = | ||
3256 | ao_status_stream_buffer_error; | ||
3257 | } | ||
3258 | } else { // Software buffer is empty. | ||
3259 | PDEBUG | ||
3260 | ("ISM stoped. No data in FIFO. Buffer is empty.\n"); | ||
3261 | instance->status = ao_status_stream_end; | ||
3262 | } | ||
3263 | } else { // There are still datas in FIFO. | ||
3264 | if (me_circ_buf_values(&instance->circ_buf)) { // Software buffer is not empty. | ||
3265 | PERROR | ||
3266 | ("Output stream has been broken. ISM stoped but some data in FIFO and buffer.\n"); | ||
3267 | } else { // Software buffer is empty. | ||
3268 | PERROR | ||
3269 | ("Output stream has been broken. ISM stoped but some data in FIFO. Buffer is empty.\n"); | ||
3270 | } | ||
3271 | instance->status = ao_status_stream_fifo_error; | ||
3272 | |||
3273 | } | ||
3274 | |||
3275 | // Signal the failure. | ||
3276 | signaling = 1; | ||
3277 | break; | ||
3278 | } | ||
3279 | // Wait for stop. | ||
3280 | reschedule = 1; | ||
3281 | break; | ||
3282 | |||
3283 | case ao_status_stream_end_wait: | ||
3284 | if (!instance->fifo) { | ||
3285 | PERROR_CRITICAL | ||
3286 | ("Streaming on single device! This feature is not implemented in this version!\n"); | ||
3287 | instance->status = ao_status_stream_error; | ||
3288 | // Signal the end. | ||
3289 | signaling = 1; | ||
3290 | break; | ||
3291 | } | ||
3292 | |||
3293 | if (!(status & ME4600_AO_STATUS_BIT_FSM)) { // State machine is not working. Waiting for stop finish. | ||
3294 | instance->status = ao_status_stream_end; | ||
3295 | signaling = 1; | ||
3296 | } | ||
3297 | // State machine is working. | ||
3298 | reschedule = 1; | ||
3299 | break; | ||
3300 | |||
3301 | default: | ||
3302 | PERROR_CRITICAL("Status is in wrong state (%d)!\n", | ||
3303 | instance->status); | ||
3304 | instance->status = ao_status_stream_error; | ||
3305 | // Signal the end. | ||
3306 | signaling = 1; | ||
3307 | break; | ||
3308 | |||
3309 | } | ||
3310 | |||
3311 | if (signaling) { //Signal it. | ||
3312 | wake_up_interruptible_all(&instance->wait_queue); | ||
3313 | } | ||
3314 | |||
3315 | if (instance->ao_control_task_flag && reschedule) { // Reschedule task | ||
3316 | queue_delayed_work(instance->me4600_workqueue, | ||
3317 | &instance->ao_control_task, 1); | ||
3318 | } else { | ||
3319 | PINFO("<%s> Ending control task.\n", __FUNCTION__); | ||
3320 | } | ||
3321 | |||
3322 | } | ||
3323 | #else | ||
3324 | /// @note SPECIAL BUILD FOR BOSCH | ||
3325 | /// @author Guenter Gebhardt | ||
3326 | static int me4600_ao_io_reset_subdevice(me_subdevice_t * subdevice, | ||
3327 | struct file *filep, int flags) | ||
3328 | { | ||
3329 | me4600_ao_subdevice_t *instance; | ||
3330 | int err = ME_ERRNO_SUCCESS; | ||
3331 | uint32_t tmp; | ||
3332 | unsigned long status; | ||
3333 | |||
3334 | PDEBUG("executed.\n"); | ||
3335 | |||
3336 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
3337 | |||
3338 | ME_SUBDEVICE_ENTER spin_lock_irqsave(&instance->subdevice_lock, status); | ||
3339 | spin_lock(instance->preload_reg_lock); | ||
3340 | tmp = inl(instance->preload_reg); | ||
3341 | tmp &= ~(0x10001 << instance->ao_idx); | ||
3342 | outl(tmp, instance->preload_reg); | ||
3343 | *instance->preload_flags &= ~(0x1 << instance->ao_idx); | ||
3344 | spin_unlock(instance->preload_reg_lock); | ||
3345 | |||
3346 | tmp = inl(instance->ctrl_reg); | ||
3347 | tmp |= ME4600_AO_CTRL_BIT_STOP | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
3348 | outl(tmp, instance->ctrl_reg); | ||
3349 | |||
3350 | while (inl(instance->status_reg) & ME4600_AO_STATUS_BIT_FSM) ; | ||
3351 | |||
3352 | outl(ME4600_AO_CTRL_BIT_STOP | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP, | ||
3353 | instance->ctrl_reg); | ||
3354 | |||
3355 | outl(0x8000, instance->single_reg); | ||
3356 | |||
3357 | instance->single_value = 0x8000; | ||
3358 | instance->circ_buf.head = 0; | ||
3359 | instance->circ_buf.tail = 0; | ||
3360 | |||
3361 | spin_unlock_irqrestore(&instance->subdevice_lock, status); | ||
3362 | |||
3363 | ME_SUBDEVICE_EXIT; | ||
3364 | |||
3365 | return err; | ||
3366 | } | ||
3367 | |||
3368 | static int me4600_ao_io_single_config(me_subdevice_t * subdevice, | ||
3369 | struct file *filep, | ||
3370 | int channel, | ||
3371 | int single_config, | ||
3372 | int ref, | ||
3373 | int trig_chan, | ||
3374 | int trig_type, int trig_edge, int flags) | ||
3375 | { | ||
3376 | me4600_ao_subdevice_t *instance; | ||
3377 | int err = ME_ERRNO_SUCCESS; | ||
3378 | uint32_t tmp; | ||
3379 | unsigned long cpu_flags; | ||
3380 | |||
3381 | PDEBUG("executed.\n"); | ||
3382 | |||
3383 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
3384 | |||
3385 | ME_SUBDEVICE_ENTER | ||
3386 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
3387 | |||
3388 | if (inl(instance->status_reg) & ME4600_AO_STATUS_BIT_FSM) { | ||
3389 | PERROR("Subdevice is busy.\n"); | ||
3390 | err = ME_ERRNO_SUBDEVICE_BUSY; | ||
3391 | goto ERROR; | ||
3392 | } | ||
3393 | |||
3394 | if (channel == 0) { | ||
3395 | if (single_config == 0) { | ||
3396 | if (ref == ME_REF_AO_GROUND) { | ||
3397 | if (trig_chan == ME_TRIG_CHAN_DEFAULT) { | ||
3398 | if (trig_type == ME_TRIG_TYPE_SW) { | ||
3399 | tmp = inl(instance->ctrl_reg); | ||
3400 | tmp |= | ||
3401 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
3402 | outl(tmp, instance->ctrl_reg); | ||
3403 | tmp = | ||
3404 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
3405 | outl(tmp, instance->ctrl_reg); | ||
3406 | |||
3407 | spin_lock(instance-> | ||
3408 | preload_reg_lock); | ||
3409 | tmp = | ||
3410 | inl(instance->preload_reg); | ||
3411 | tmp &= | ||
3412 | ~(0x10001 << instance-> | ||
3413 | ao_idx); | ||
3414 | outl(tmp, | ||
3415 | instance->preload_reg); | ||
3416 | *instance->preload_flags &= | ||
3417 | ~(0x1 << instance->ao_idx); | ||
3418 | spin_unlock(instance-> | ||
3419 | preload_reg_lock); | ||
3420 | } else if (trig_type == | ||
3421 | ME_TRIG_TYPE_EXT_DIGITAL) { | ||
3422 | if (trig_edge == | ||
3423 | ME_TRIG_EDGE_RISING) { | ||
3424 | tmp = | ||
3425 | inl(instance-> | ||
3426 | ctrl_reg); | ||
3427 | tmp |= | ||
3428 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
3429 | outl(tmp, | ||
3430 | instance-> | ||
3431 | ctrl_reg); | ||
3432 | tmp = | ||
3433 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP | ||
3434 | | | ||
3435 | ME4600_AO_CTRL_BIT_ENABLE_EX_TRIG; | ||
3436 | outl(tmp, | ||
3437 | instance-> | ||
3438 | ctrl_reg); | ||
3439 | } else if (trig_edge == | ||
3440 | ME_TRIG_EDGE_FALLING) | ||
3441 | { | ||
3442 | tmp = | ||
3443 | inl(instance-> | ||
3444 | ctrl_reg); | ||
3445 | tmp |= | ||
3446 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
3447 | outl(tmp, | ||
3448 | instance-> | ||
3449 | ctrl_reg); | ||
3450 | tmp = | ||
3451 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP | ||
3452 | | | ||
3453 | ME4600_AO_CTRL_BIT_ENABLE_EX_TRIG | ||
3454 | | | ||
3455 | ME4600_AO_CTRL_BIT_EX_TRIG_EDGE; | ||
3456 | outl(tmp, | ||
3457 | instance-> | ||
3458 | ctrl_reg); | ||
3459 | } else if (trig_edge == | ||
3460 | ME_TRIG_EDGE_ANY) { | ||
3461 | tmp = | ||
3462 | inl(instance-> | ||
3463 | ctrl_reg); | ||
3464 | tmp |= | ||
3465 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
3466 | outl(tmp, | ||
3467 | instance-> | ||
3468 | ctrl_reg); | ||
3469 | tmp = | ||
3470 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP | ||
3471 | | | ||
3472 | ME4600_AO_CTRL_BIT_ENABLE_EX_TRIG | ||
3473 | | | ||
3474 | ME4600_AO_CTRL_BIT_EX_TRIG_EDGE | ||
3475 | | | ||
3476 | ME4600_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH; | ||
3477 | outl(tmp, | ||
3478 | instance-> | ||
3479 | ctrl_reg); | ||
3480 | } else { | ||
3481 | PERROR | ||
3482 | ("Invalid trigger edge.\n"); | ||
3483 | err = | ||
3484 | ME_ERRNO_INVALID_TRIG_EDGE; | ||
3485 | goto ERROR; | ||
3486 | } | ||
3487 | |||
3488 | spin_lock(instance-> | ||
3489 | preload_reg_lock); | ||
3490 | |||
3491 | tmp = | ||
3492 | inl(instance->preload_reg); | ||
3493 | tmp &= | ||
3494 | ~(0x10001 << instance-> | ||
3495 | ao_idx); | ||
3496 | tmp |= 0x1 << instance->ao_idx; | ||
3497 | outl(tmp, | ||
3498 | instance->preload_reg); | ||
3499 | *instance->preload_flags &= | ||
3500 | ~(0x1 << instance->ao_idx); | ||
3501 | spin_unlock(instance-> | ||
3502 | preload_reg_lock); | ||
3503 | } else { | ||
3504 | PERROR | ||
3505 | ("Invalid trigger type.\n"); | ||
3506 | err = | ||
3507 | ME_ERRNO_INVALID_TRIG_TYPE; | ||
3508 | goto ERROR; | ||
3509 | } | ||
3510 | } else if (trig_chan == | ||
3511 | ME_TRIG_CHAN_SYNCHRONOUS) { | ||
3512 | if (trig_type == ME_TRIG_TYPE_SW) { | ||
3513 | tmp = inl(instance->ctrl_reg); | ||
3514 | tmp |= | ||
3515 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
3516 | outl(tmp, instance->ctrl_reg); | ||
3517 | tmp = | ||
3518 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
3519 | outl(tmp, instance->ctrl_reg); | ||
3520 | |||
3521 | spin_lock(instance-> | ||
3522 | preload_reg_lock); | ||
3523 | tmp = | ||
3524 | inl(instance->preload_reg); | ||
3525 | tmp &= | ||
3526 | ~(0x10001 << instance-> | ||
3527 | ao_idx); | ||
3528 | tmp |= 0x1 << instance->ao_idx; | ||
3529 | outl(tmp, | ||
3530 | instance->preload_reg); | ||
3531 | *instance->preload_flags |= | ||
3532 | 0x1 << instance->ao_idx; | ||
3533 | spin_unlock(instance-> | ||
3534 | preload_reg_lock); | ||
3535 | } else if (trig_type == | ||
3536 | ME_TRIG_TYPE_EXT_DIGITAL) { | ||
3537 | if (trig_edge == | ||
3538 | ME_TRIG_EDGE_RISING) { | ||
3539 | tmp = | ||
3540 | inl(instance-> | ||
3541 | ctrl_reg); | ||
3542 | tmp |= | ||
3543 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
3544 | outl(tmp, | ||
3545 | instance-> | ||
3546 | ctrl_reg); | ||
3547 | tmp = | ||
3548 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
3549 | outl(tmp, | ||
3550 | instance-> | ||
3551 | ctrl_reg); | ||
3552 | } else if (trig_edge == | ||
3553 | ME_TRIG_EDGE_FALLING) | ||
3554 | { | ||
3555 | tmp = | ||
3556 | inl(instance-> | ||
3557 | ctrl_reg); | ||
3558 | tmp |= | ||
3559 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
3560 | outl(tmp, | ||
3561 | instance-> | ||
3562 | ctrl_reg); | ||
3563 | tmp = | ||
3564 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP | ||
3565 | | | ||
3566 | ME4600_AO_CTRL_BIT_EX_TRIG_EDGE; | ||
3567 | outl(tmp, | ||
3568 | instance-> | ||
3569 | ctrl_reg); | ||
3570 | } else if (trig_edge == | ||
3571 | ME_TRIG_EDGE_ANY) { | ||
3572 | tmp = | ||
3573 | inl(instance-> | ||
3574 | ctrl_reg); | ||
3575 | tmp |= | ||
3576 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
3577 | outl(tmp, | ||
3578 | instance-> | ||
3579 | ctrl_reg); | ||
3580 | tmp = | ||
3581 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP | ||
3582 | | | ||
3583 | ME4600_AO_CTRL_BIT_EX_TRIG_EDGE | ||
3584 | | | ||
3585 | ME4600_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH; | ||
3586 | outl(tmp, | ||
3587 | instance-> | ||
3588 | ctrl_reg); | ||
3589 | } else { | ||
3590 | PERROR | ||
3591 | ("Invalid trigger edge.\n"); | ||
3592 | err = | ||
3593 | ME_ERRNO_INVALID_TRIG_EDGE; | ||
3594 | goto ERROR; | ||
3595 | } | ||
3596 | |||
3597 | spin_lock(instance-> | ||
3598 | preload_reg_lock); | ||
3599 | |||
3600 | tmp = | ||
3601 | inl(instance->preload_reg); | ||
3602 | tmp |= | ||
3603 | 0x10001 << instance->ao_idx; | ||
3604 | outl(tmp, | ||
3605 | instance->preload_reg); | ||
3606 | *instance->preload_flags &= | ||
3607 | ~(0x1 << instance->ao_idx); | ||
3608 | spin_unlock(instance-> | ||
3609 | preload_reg_lock); | ||
3610 | } else { | ||
3611 | PERROR | ||
3612 | ("Invalid trigger type.\n"); | ||
3613 | err = | ||
3614 | ME_ERRNO_INVALID_TRIG_TYPE; | ||
3615 | goto ERROR; | ||
3616 | } | ||
3617 | } else { | ||
3618 | PERROR | ||
3619 | ("Invalid trigger channel specified.\n"); | ||
3620 | err = ME_ERRNO_INVALID_REF; | ||
3621 | goto ERROR; | ||
3622 | } | ||
3623 | } else { | ||
3624 | PERROR("Invalid analog reference specified.\n"); | ||
3625 | err = ME_ERRNO_INVALID_REF; | ||
3626 | goto ERROR; | ||
3627 | } | ||
3628 | } else { | ||
3629 | PERROR("Invalid single config specified.\n"); | ||
3630 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
3631 | goto ERROR; | ||
3632 | } | ||
3633 | } else { | ||
3634 | PERROR("Invalid channel number specified.\n"); | ||
3635 | err = ME_ERRNO_INVALID_CHANNEL; | ||
3636 | goto ERROR; | ||
3637 | } | ||
3638 | |||
3639 | ERROR: | ||
3640 | |||
3641 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
3642 | |||
3643 | ME_SUBDEVICE_EXIT; | ||
3644 | |||
3645 | return err; | ||
3646 | } | ||
3647 | |||
3648 | static int me4600_ao_io_single_read(me_subdevice_t * subdevice, | ||
3649 | struct file *filep, | ||
3650 | int channel, | ||
3651 | int *value, int time_out, int flags) | ||
3652 | { | ||
3653 | me4600_ao_subdevice_t *instance; | ||
3654 | int err = ME_ERRNO_SUCCESS; | ||
3655 | unsigned long tmp; | ||
3656 | unsigned long cpu_flags; | ||
3657 | |||
3658 | PDEBUG("executed.\n"); | ||
3659 | |||
3660 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
3661 | |||
3662 | if (channel != 0) { | ||
3663 | PERROR("Invalid channel number specified.\n"); | ||
3664 | return ME_ERRNO_INVALID_CHANNEL; | ||
3665 | } | ||
3666 | |||
3667 | ME_SUBDEVICE_ENTER | ||
3668 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
3669 | tmp = inl(instance->ctrl_reg); | ||
3670 | |||
3671 | if (tmp & 0x3) { | ||
3672 | PERROR("Not in single mode.\n"); | ||
3673 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
3674 | } else { | ||
3675 | *value = instance->single_value; | ||
3676 | } | ||
3677 | |||
3678 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
3679 | |||
3680 | ME_SUBDEVICE_EXIT; | ||
3681 | |||
3682 | return err; | ||
3683 | } | ||
3684 | |||
3685 | static int me4600_ao_io_single_write(me_subdevice_t * subdevice, | ||
3686 | struct file *filep, | ||
3687 | int channel, | ||
3688 | int value, int time_out, int flags) | ||
3689 | { | ||
3690 | me4600_ao_subdevice_t *instance; | ||
3691 | int err = ME_ERRNO_SUCCESS; | ||
3692 | unsigned long mask = 0; | ||
3693 | unsigned long tmp; | ||
3694 | unsigned long cpu_flags; | ||
3695 | int i; | ||
3696 | wait_queue_head_t queue; | ||
3697 | unsigned long j; | ||
3698 | unsigned long delay = 0; | ||
3699 | |||
3700 | PDEBUG("executed.\n"); | ||
3701 | |||
3702 | init_waitqueue_head(&queue); | ||
3703 | |||
3704 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
3705 | |||
3706 | if (channel != 0) { | ||
3707 | PERROR("Invalid channel number specified.\n"); | ||
3708 | return ME_ERRNO_INVALID_CHANNEL; | ||
3709 | } | ||
3710 | |||
3711 | if (time_out < 0) { | ||
3712 | PERROR("Invalid timeout specified.\n"); | ||
3713 | return ME_ERRNO_INVALID_TIMEOUT; | ||
3714 | } | ||
3715 | |||
3716 | if (time_out) { | ||
3717 | delay = (time_out * HZ) / 1000; | ||
3718 | |||
3719 | if (delay == 0) | ||
3720 | delay = 1; | ||
3721 | } | ||
3722 | |||
3723 | ME_SUBDEVICE_ENTER | ||
3724 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
3725 | |||
3726 | tmp = inl(instance->ctrl_reg); | ||
3727 | |||
3728 | if (tmp & 0x3) { | ||
3729 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
3730 | PERROR("Not in single mode.\n"); | ||
3731 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
3732 | goto ERROR; | ||
3733 | } | ||
3734 | |||
3735 | if (tmp & ME4600_AO_CTRL_BIT_ENABLE_EX_TRIG) { | ||
3736 | outl(value, instance->single_reg); | ||
3737 | instance->single_value = value; | ||
3738 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
3739 | |||
3740 | if (!(flags & ME_IO_SINGLE_TYPE_WRITE_NONBLOCKING)) { | ||
3741 | j = jiffies; | ||
3742 | |||
3743 | while (inl(instance->status_reg) & | ||
3744 | ME4600_AO_STATUS_BIT_FSM) { | ||
3745 | interruptible_sleep_on_timeout(&queue, 1); | ||
3746 | |||
3747 | if (signal_pending(current)) { | ||
3748 | PERROR | ||
3749 | ("Wait on external trigger interrupted by signal.\n"); | ||
3750 | err = ME_ERRNO_SIGNAL; | ||
3751 | goto ERROR; | ||
3752 | } | ||
3753 | |||
3754 | if (delay && ((jiffies - j) > delay)) { | ||
3755 | PERROR("Timeout reached.\n"); | ||
3756 | err = ME_ERRNO_TIMEOUT; | ||
3757 | goto ERROR; | ||
3758 | } | ||
3759 | } | ||
3760 | } | ||
3761 | } else if ((inl(instance->preload_reg) & (0x10001 << instance->ao_idx)) | ||
3762 | == (0x10001 << instance->ao_idx)) { | ||
3763 | if (flags & ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS) { | ||
3764 | tmp |= ME4600_AO_CTRL_BIT_ENABLE_EX_TRIG; | ||
3765 | outl(tmp, instance->ctrl_reg); | ||
3766 | outl(value, instance->single_reg); | ||
3767 | instance->single_value = value; | ||
3768 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
3769 | cpu_flags); | ||
3770 | |||
3771 | if (!(flags & ME_IO_SINGLE_TYPE_WRITE_NONBLOCKING)) { | ||
3772 | j = jiffies; | ||
3773 | |||
3774 | while (inl(instance->status_reg) & | ||
3775 | ME4600_AO_STATUS_BIT_FSM) { | ||
3776 | interruptible_sleep_on_timeout(&queue, | ||
3777 | 1); | ||
3778 | |||
3779 | if (signal_pending(current)) { | ||
3780 | PERROR | ||
3781 | ("Wait on external trigger interrupted by signal.\n"); | ||
3782 | err = ME_ERRNO_SIGNAL; | ||
3783 | goto ERROR; | ||
3784 | } | ||
3785 | |||
3786 | if (delay && ((jiffies - j) > delay)) { | ||
3787 | PERROR("Timeout reached.\n"); | ||
3788 | err = ME_ERRNO_TIMEOUT; | ||
3789 | goto ERROR; | ||
3790 | } | ||
3791 | } | ||
3792 | } | ||
3793 | } else { | ||
3794 | outl(value, instance->single_reg); | ||
3795 | instance->single_value = value; | ||
3796 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
3797 | cpu_flags); | ||
3798 | } | ||
3799 | } else if ((inl(instance->preload_reg) & (0x10001 << instance->ao_idx)) | ||
3800 | == (0x1 << instance->ao_idx)) { | ||
3801 | outl(value, instance->single_reg); | ||
3802 | instance->single_value = value; | ||
3803 | |||
3804 | PDEBUG("Synchronous SW, flags = 0x%X.\n", flags); | ||
3805 | |||
3806 | if (flags & ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS) { | ||
3807 | PDEBUG("Trigger synchronous SW.\n"); | ||
3808 | spin_lock(instance->preload_reg_lock); | ||
3809 | tmp = inl(instance->preload_reg); | ||
3810 | |||
3811 | for (i = 0; i < ME4600_AO_MAX_SUBDEVICES; i++) { | ||
3812 | if ((*instance->preload_flags & (0x1 << i))) { | ||
3813 | if ((tmp & (0x10001 << i)) == | ||
3814 | (0x1 << i)) { | ||
3815 | mask |= 0x1 << i; | ||
3816 | } | ||
3817 | } | ||
3818 | } | ||
3819 | |||
3820 | tmp &= ~(mask); | ||
3821 | |||
3822 | outl(tmp, instance->preload_reg); | ||
3823 | spin_unlock(instance->preload_reg_lock); | ||
3824 | } | ||
3825 | |||
3826 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
3827 | } else { | ||
3828 | outl(value, instance->single_reg); | ||
3829 | instance->single_value = value; | ||
3830 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
3831 | } | ||
3832 | |||
3833 | ERROR: | ||
3834 | |||
3835 | ME_SUBDEVICE_EXIT; | ||
3836 | |||
3837 | return err; | ||
3838 | } | ||
3839 | |||
3840 | static int me4600_ao_io_stream_config(me_subdevice_t * subdevice, | ||
3841 | struct file *filep, | ||
3842 | meIOStreamConfig_t * config_list, | ||
3843 | int count, | ||
3844 | meIOStreamTrigger_t * trigger, | ||
3845 | int fifo_irq_threshold, int flags) | ||
3846 | { | ||
3847 | me4600_ao_subdevice_t *instance; | ||
3848 | int err = ME_ERRNO_SUCCESS; | ||
3849 | unsigned long ctrl; | ||
3850 | unsigned long tmp; | ||
3851 | unsigned long cpu_flags; | ||
3852 | uint64_t conv_ticks; | ||
3853 | unsigned int conv_start_ticks_low = trigger->iConvStartTicksLow; | ||
3854 | unsigned int conv_start_ticks_high = trigger->iConvStartTicksHigh; | ||
3855 | |||
3856 | PDEBUG("executed.\n"); | ||
3857 | |||
3858 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
3859 | |||
3860 | conv_ticks = | ||
3861 | (uint64_t) conv_start_ticks_low + | ||
3862 | ((uint64_t) conv_start_ticks_high << 32); | ||
3863 | |||
3864 | if (!instance->fifo) { | ||
3865 | PERROR("Not a streaming ao.\n"); | ||
3866 | return ME_ERRNO_NOT_SUPPORTED; | ||
3867 | } | ||
3868 | |||
3869 | ME_SUBDEVICE_ENTER | ||
3870 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
3871 | |||
3872 | if ((inl(instance->status_reg)) & ME4600_AO_STATUS_BIT_FSM) { | ||
3873 | PERROR("Subdevice is busy.\n"); | ||
3874 | err = ME_ERRNO_SUBDEVICE_BUSY; | ||
3875 | goto ERROR; | ||
3876 | } | ||
3877 | |||
3878 | ctrl = inl(instance->ctrl_reg); | ||
3879 | ctrl |= ME4600_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
3880 | outl(ctrl, instance->ctrl_reg); | ||
3881 | ctrl = ME4600_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
3882 | outl(ctrl, instance->ctrl_reg); | ||
3883 | |||
3884 | if (count != 1) { | ||
3885 | PERROR("Invalid stream configuration list count specified.\n"); | ||
3886 | err = ME_ERRNO_INVALID_CONFIG_LIST_COUNT; | ||
3887 | goto ERROR; | ||
3888 | } | ||
3889 | |||
3890 | if (config_list[0].iChannel != 0) { | ||
3891 | PERROR("Invalid channel number specified.\n"); | ||
3892 | err = ME_ERRNO_INVALID_CHANNEL; | ||
3893 | goto ERROR; | ||
3894 | } | ||
3895 | |||
3896 | if (config_list[0].iStreamConfig != 0) { | ||
3897 | PERROR("Invalid stream config specified.\n"); | ||
3898 | err = ME_ERRNO_INVALID_STREAM_CONFIG; | ||
3899 | goto ERROR; | ||
3900 | } | ||
3901 | |||
3902 | if (config_list[0].iRef != ME_REF_AO_GROUND) { | ||
3903 | PERROR("Invalid analog reference.\n"); | ||
3904 | err = ME_ERRNO_INVALID_REF; | ||
3905 | goto ERROR; | ||
3906 | } | ||
3907 | |||
3908 | if ((trigger->iAcqStartTicksLow != 0) | ||
3909 | || (trigger->iAcqStartTicksHigh != 0)) { | ||
3910 | PERROR | ||
3911 | ("Invalid acquisition start trigger argument specified.\n"); | ||
3912 | err = ME_ERRNO_INVALID_ACQ_START_ARG; | ||
3913 | goto ERROR; | ||
3914 | } | ||
3915 | |||
3916 | switch (trigger->iAcqStartTrigType) { | ||
3917 | |||
3918 | case ME_TRIG_TYPE_SW: | ||
3919 | break; | ||
3920 | |||
3921 | case ME_TRIG_TYPE_EXT_DIGITAL: | ||
3922 | ctrl |= ME4600_AO_CTRL_BIT_ENABLE_EX_TRIG; | ||
3923 | |||
3924 | switch (trigger->iAcqStartTrigEdge) { | ||
3925 | |||
3926 | case ME_TRIG_EDGE_RISING: | ||
3927 | break; | ||
3928 | |||
3929 | case ME_TRIG_EDGE_FALLING: | ||
3930 | ctrl |= ME4600_AO_CTRL_BIT_EX_TRIG_EDGE; | ||
3931 | |||
3932 | break; | ||
3933 | |||
3934 | case ME_TRIG_EDGE_ANY: | ||
3935 | ctrl |= | ||
3936 | ME4600_AO_CTRL_BIT_EX_TRIG_EDGE | | ||
3937 | ME4600_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH; | ||
3938 | |||
3939 | break; | ||
3940 | |||
3941 | default: | ||
3942 | PERROR | ||
3943 | ("Invalid acquisition start trigger edge specified.\n"); | ||
3944 | |||
3945 | err = ME_ERRNO_INVALID_ACQ_START_TRIG_EDGE; | ||
3946 | |||
3947 | goto ERROR; | ||
3948 | |||
3949 | break; | ||
3950 | } | ||
3951 | |||
3952 | break; | ||
3953 | |||
3954 | default: | ||
3955 | PERROR("Invalid acquisition start trigger type specified.\n"); | ||
3956 | |||
3957 | err = ME_ERRNO_INVALID_ACQ_START_TRIG_TYPE; | ||
3958 | |||
3959 | goto ERROR; | ||
3960 | |||
3961 | break; | ||
3962 | } | ||
3963 | |||
3964 | switch (trigger->iScanStartTrigType) { | ||
3965 | |||
3966 | case ME_TRIG_TYPE_FOLLOW: | ||
3967 | break; | ||
3968 | |||
3969 | default: | ||
3970 | PERROR("Invalid scan start trigger type specified.\n"); | ||
3971 | |||
3972 | err = ME_ERRNO_INVALID_SCAN_START_TRIG_TYPE; | ||
3973 | |||
3974 | goto ERROR; | ||
3975 | |||
3976 | break; | ||
3977 | } | ||
3978 | |||
3979 | switch (trigger->iConvStartTrigType) { | ||
3980 | |||
3981 | case ME_TRIG_TYPE_TIMER: | ||
3982 | if ((conv_ticks < ME4600_AO_MIN_CHAN_TICKS) | ||
3983 | || (conv_ticks > ME4600_AO_MAX_CHAN_TICKS)) { | ||
3984 | PERROR | ||
3985 | ("Invalid conv start trigger argument specified.\n"); | ||
3986 | err = ME_ERRNO_INVALID_CONV_START_ARG; | ||
3987 | goto ERROR; | ||
3988 | } | ||
3989 | |||
3990 | break; | ||
3991 | |||
3992 | default: | ||
3993 | PERROR("Invalid conv start trigger type specified.\n"); | ||
3994 | |||
3995 | err = ME_ERRNO_INVALID_CONV_START_TRIG_TYPE; | ||
3996 | |||
3997 | goto ERROR; | ||
3998 | |||
3999 | break; | ||
4000 | } | ||
4001 | |||
4002 | /* Preset to hardware wraparound mode */ | ||
4003 | instance->flags &= ~(ME4600_AO_FLAGS_SW_WRAP_MODE_MASK); | ||
4004 | |||
4005 | switch (trigger->iScanStopTrigType) { | ||
4006 | |||
4007 | case ME_TRIG_TYPE_NONE: | ||
4008 | if (flags & ME_IO_STREAM_CONFIG_WRAPAROUND) { | ||
4009 | /* Set flags to indicate usage of software mode. */ | ||
4010 | instance->flags |= ME4600_AO_FLAGS_SW_WRAP_MODE_INF; | ||
4011 | instance->wrap_count = 0; | ||
4012 | instance->wrap_remaining = 0; | ||
4013 | } | ||
4014 | |||
4015 | break; | ||
4016 | |||
4017 | case ME_TRIG_TYPE_COUNT: | ||
4018 | if (flags & ME_IO_STREAM_CONFIG_WRAPAROUND) { | ||
4019 | if (trigger->iScanStopCount <= 0) { | ||
4020 | PERROR("Invalid scan stop count specified.\n"); | ||
4021 | err = ME_ERRNO_INVALID_SCAN_STOP_ARG; | ||
4022 | goto ERROR; | ||
4023 | } | ||
4024 | |||
4025 | /* Set flags to indicate usage of software mode. */ | ||
4026 | instance->flags |= ME4600_AO_FLAGS_SW_WRAP_MODE_FIN; | ||
4027 | instance->wrap_count = trigger->iScanStopCount; | ||
4028 | instance->wrap_remaining = trigger->iScanStopCount; | ||
4029 | } else { | ||
4030 | PERROR("Invalid scan stop trigger type specified.\n"); | ||
4031 | err = ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE; | ||
4032 | goto ERROR; | ||
4033 | } | ||
4034 | |||
4035 | break; | ||
4036 | |||
4037 | default: | ||
4038 | PERROR("Invalid scan stop trigger type specified.\n"); | ||
4039 | |||
4040 | err = ME_ERRNO_INVALID_SCAN_STOP_TRIG_TYPE; | ||
4041 | |||
4042 | goto ERROR; | ||
4043 | |||
4044 | break; | ||
4045 | } | ||
4046 | |||
4047 | switch (trigger->iAcqStopTrigType) { | ||
4048 | |||
4049 | case ME_TRIG_TYPE_NONE: | ||
4050 | break; | ||
4051 | |||
4052 | case ME_TRIG_TYPE_COUNT: | ||
4053 | if (trigger->iScanStopTrigType != ME_TRIG_TYPE_NONE) { | ||
4054 | PERROR("Invalid acq stop trigger type specified.\n"); | ||
4055 | err = ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE; | ||
4056 | goto ERROR; | ||
4057 | } | ||
4058 | |||
4059 | if (flags & ME_IO_STREAM_CONFIG_WRAPAROUND) { | ||
4060 | if (trigger->iAcqStopCount <= 0) { | ||
4061 | PERROR("Invalid acq stop count specified.\n"); | ||
4062 | err = ME_ERRNO_INVALID_ACQ_STOP_ARG; | ||
4063 | goto ERROR; | ||
4064 | } | ||
4065 | |||
4066 | /* Set flags to indicate usage of software mode. */ | ||
4067 | instance->flags |= ME4600_AO_FLAGS_SW_WRAP_MODE_FIN; | ||
4068 | instance->wrap_count = trigger->iAcqStopCount; | ||
4069 | instance->wrap_remaining = trigger->iAcqStopCount; | ||
4070 | } else { | ||
4071 | PERROR("Invalid acp stop trigger type specified.\n"); | ||
4072 | err = ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE; | ||
4073 | goto ERROR; | ||
4074 | } | ||
4075 | |||
4076 | break; | ||
4077 | |||
4078 | default: | ||
4079 | PERROR("Invalid acq stop trigger type specified.\n"); | ||
4080 | err = ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE; | ||
4081 | goto ERROR; | ||
4082 | break; | ||
4083 | } | ||
4084 | |||
4085 | switch (trigger->iAcqStartTrigChan) { | ||
4086 | |||
4087 | case ME_TRIG_CHAN_DEFAULT: | ||
4088 | spin_lock(instance->preload_reg_lock); | ||
4089 | tmp = inl(instance->preload_reg); | ||
4090 | tmp &= ~(0x10001 << instance->ao_idx); | ||
4091 | outl(tmp, instance->preload_reg); | ||
4092 | spin_unlock(instance->preload_reg_lock); | ||
4093 | |||
4094 | break; | ||
4095 | |||
4096 | case ME_TRIG_CHAN_SYNCHRONOUS: | ||
4097 | if (trigger->iAcqStartTrigType == ME_TRIG_TYPE_SW) { | ||
4098 | spin_lock(instance->preload_reg_lock); | ||
4099 | tmp = inl(instance->preload_reg); | ||
4100 | tmp &= ~(0x10001 << instance->ao_idx); | ||
4101 | outl(tmp, instance->preload_reg); | ||
4102 | tmp |= 0x1 << instance->ao_idx; | ||
4103 | outl(tmp, instance->preload_reg); | ||
4104 | spin_unlock(instance->preload_reg_lock); | ||
4105 | } else { | ||
4106 | ctrl &= ~(ME4600_AO_CTRL_BIT_ENABLE_EX_TRIG); | ||
4107 | spin_lock(instance->preload_reg_lock); | ||
4108 | tmp = inl(instance->preload_reg); | ||
4109 | tmp &= ~(0x10001 << instance->ao_idx); | ||
4110 | outl(tmp, instance->preload_reg); | ||
4111 | tmp |= 0x10000 << instance->ao_idx; | ||
4112 | outl(tmp, instance->preload_reg); | ||
4113 | spin_unlock(instance->preload_reg_lock); | ||
4114 | } | ||
4115 | |||
4116 | break; | ||
4117 | |||
4118 | default: | ||
4119 | PERROR("Invalid acq start trigger channel specified.\n"); | ||
4120 | err = ME_ERRNO_INVALID_ACQ_START_TRIG_CHAN; | ||
4121 | goto ERROR; | ||
4122 | |||
4123 | break; | ||
4124 | } | ||
4125 | |||
4126 | outl(conv_ticks - 2, instance->timer_reg); | ||
4127 | |||
4128 | if (flags & ME_IO_STREAM_CONFIG_BIT_PATTERN) { | ||
4129 | if (instance->ao_idx == 3) { | ||
4130 | ctrl |= ME4600_AO_CTRL_BIT_ENABLE_DO; | ||
4131 | } else { | ||
4132 | err = ME_ERRNO_INVALID_FLAGS; | ||
4133 | goto ERROR; | ||
4134 | } | ||
4135 | } else { | ||
4136 | if (instance->ao_idx == 3) { | ||
4137 | ctrl &= ~ME4600_AO_CTRL_BIT_ENABLE_DO; | ||
4138 | } | ||
4139 | } | ||
4140 | |||
4141 | /* Set hardware mode. */ | ||
4142 | if (flags & ME_IO_STREAM_CONFIG_WRAPAROUND) { | ||
4143 | ctrl |= ME4600_AO_CTRL_BIT_MODE_0; | ||
4144 | } else { | ||
4145 | ctrl |= ME4600_AO_CTRL_BIT_MODE_1; | ||
4146 | } | ||
4147 | |||
4148 | PDEBUG("Preload word = 0x%X.\n", inl(instance->preload_reg)); | ||
4149 | |||
4150 | PDEBUG("Ctrl word = 0x%lX.\n", ctrl); | ||
4151 | outl(ctrl, instance->ctrl_reg); // Write the control word | ||
4152 | |||
4153 | ERROR: | ||
4154 | |||
4155 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
4156 | |||
4157 | ME_SUBDEVICE_EXIT; | ||
4158 | |||
4159 | return err; | ||
4160 | } | ||
4161 | |||
4162 | static int me4600_ao_io_stream_new_values(me_subdevice_t * subdevice, | ||
4163 | struct file *filep, | ||
4164 | int time_out, int *count, int flags) | ||
4165 | { | ||
4166 | me4600_ao_subdevice_t *instance; | ||
4167 | int err = ME_ERRNO_SUCCESS; | ||
4168 | long t = 0; | ||
4169 | long j; | ||
4170 | |||
4171 | PDEBUG("executed.\n"); | ||
4172 | |||
4173 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
4174 | |||
4175 | if (!instance->fifo) { | ||
4176 | PERROR("Not a streaming ao.\n"); | ||
4177 | return ME_ERRNO_NOT_SUPPORTED; | ||
4178 | } | ||
4179 | |||
4180 | if (time_out < 0) { | ||
4181 | PERROR("Invalid time_out specified.\n"); | ||
4182 | return ME_ERRNO_INVALID_TIMEOUT; | ||
4183 | } | ||
4184 | |||
4185 | if (time_out) { | ||
4186 | t = (time_out * HZ) / 1000; | ||
4187 | |||
4188 | if (t == 0) | ||
4189 | t = 1; | ||
4190 | } | ||
4191 | |||
4192 | *count = 0; | ||
4193 | |||
4194 | ME_SUBDEVICE_ENTER; | ||
4195 | |||
4196 | if (t) { | ||
4197 | j = jiffies; | ||
4198 | wait_event_interruptible_timeout(instance->wait_queue, | ||
4199 | ((me_circ_buf_space | ||
4200 | (&instance->circ_buf)) | ||
4201 | || !(inl(instance->status_reg) | ||
4202 | & | ||
4203 | ME4600_AO_STATUS_BIT_FSM)), | ||
4204 | t); | ||
4205 | |||
4206 | if (!(inl(instance->status_reg) & ME4600_AO_STATUS_BIT_FSM)) { | ||
4207 | PERROR("AO subdevice is not running.\n"); | ||
4208 | err = ME_ERRNO_SUBDEVICE_NOT_RUNNING; | ||
4209 | } else if (signal_pending(current)) { | ||
4210 | PERROR("Wait on values interrupted from signal.\n"); | ||
4211 | err = ME_ERRNO_SIGNAL; | ||
4212 | } else if ((jiffies - j) >= t) { | ||
4213 | PERROR("Wait on values timed out.\n"); | ||
4214 | err = ME_ERRNO_TIMEOUT; | ||
4215 | } else { | ||
4216 | *count = me_circ_buf_space(&instance->circ_buf); | ||
4217 | } | ||
4218 | } else { | ||
4219 | wait_event_interruptible(instance->wait_queue, | ||
4220 | ((me_circ_buf_space | ||
4221 | (&instance->circ_buf)) | ||
4222 | || !(inl(instance->status_reg) & | ||
4223 | ME4600_AO_STATUS_BIT_FSM))); | ||
4224 | |||
4225 | if (!(inl(instance->status_reg) & ME4600_AO_STATUS_BIT_FSM)) { | ||
4226 | PERROR("AO subdevice is not running.\n"); | ||
4227 | err = ME_ERRNO_SUBDEVICE_NOT_RUNNING; | ||
4228 | } else if (signal_pending(current)) { | ||
4229 | PERROR("Wait on values interrupted from signal.\n"); | ||
4230 | err = ME_ERRNO_SIGNAL; | ||
4231 | } else { | ||
4232 | *count = me_circ_buf_space(&instance->circ_buf); | ||
4233 | } | ||
4234 | } | ||
4235 | |||
4236 | ME_SUBDEVICE_EXIT; | ||
4237 | |||
4238 | return err; | ||
4239 | } | ||
4240 | |||
4241 | static void stop_immediately(me4600_ao_subdevice_t * instance) | ||
4242 | { | ||
4243 | unsigned long cpu_flags; | ||
4244 | uint32_t tmp; | ||
4245 | |||
4246 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
4247 | tmp = inl(instance->ctrl_reg); | ||
4248 | tmp |= ME4600_AO_CTRL_BIT_STOP | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
4249 | outl(tmp, instance->ctrl_reg); | ||
4250 | |||
4251 | while (inl(instance->status_reg) & ME4600_AO_STATUS_BIT_FSM) ; | ||
4252 | |||
4253 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
4254 | } | ||
4255 | |||
4256 | static int me4600_ao_io_stream_start(me_subdevice_t * subdevice, | ||
4257 | struct file *filep, | ||
4258 | int start_mode, int time_out, int flags) | ||
4259 | { | ||
4260 | me4600_ao_subdevice_t *instance; | ||
4261 | int err = ME_ERRNO_SUCCESS; | ||
4262 | unsigned long cpu_flags = 0; | ||
4263 | unsigned long ref; | ||
4264 | unsigned long tmp; | ||
4265 | unsigned long delay = 0; | ||
4266 | wait_queue_head_t queue; | ||
4267 | |||
4268 | PDEBUG("executed.\n"); | ||
4269 | |||
4270 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
4271 | |||
4272 | init_waitqueue_head(&queue); | ||
4273 | |||
4274 | if (time_out < 0) { | ||
4275 | PERROR("Invalid timeout specified.\n"); | ||
4276 | return ME_ERRNO_INVALID_TIMEOUT; | ||
4277 | } | ||
4278 | |||
4279 | if (time_out) { | ||
4280 | delay = (time_out * HZ) / 1000; | ||
4281 | |||
4282 | if (delay == 0) | ||
4283 | delay = 1; | ||
4284 | } | ||
4285 | |||
4286 | if (!instance->fifo) { | ||
4287 | PERROR("Not a streaming ao.\n"); | ||
4288 | return ME_ERRNO_NOT_SUPPORTED; | ||
4289 | } | ||
4290 | |||
4291 | ME_SUBDEVICE_ENTER | ||
4292 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
4293 | |||
4294 | tmp = inl(instance->ctrl_reg); | ||
4295 | |||
4296 | switch (tmp & (ME4600_AO_CTRL_MASK_MODE)) { | ||
4297 | |||
4298 | case 0: // Single mode | ||
4299 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
4300 | PERROR("Subdevice is configured in single mode.\n"); | ||
4301 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
4302 | goto ERROR; | ||
4303 | |||
4304 | case 1: // Wraparound mode | ||
4305 | if (tmp & ME4600_AO_CTRL_BIT_ENABLE_EX_TRIG) { // Normal wraparound with external trigger | ||
4306 | |||
4307 | if ((inl(instance->status_reg) & | ||
4308 | ME4600_AO_STATUS_BIT_FSM)) { | ||
4309 | spin_unlock_irqrestore(&instance-> | ||
4310 | subdevice_lock, | ||
4311 | cpu_flags); | ||
4312 | PERROR("Conversion is already running.\n"); | ||
4313 | err = ME_ERRNO_SUBDEVICE_BUSY; | ||
4314 | goto ERROR; | ||
4315 | } | ||
4316 | |||
4317 | tmp &= | ||
4318 | ~(ME4600_AO_CTRL_BIT_ENABLE_IRQ | | ||
4319 | ME4600_AO_CTRL_BIT_STOP | | ||
4320 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP); | ||
4321 | |||
4322 | outl(tmp, instance->ctrl_reg); | ||
4323 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
4324 | cpu_flags); | ||
4325 | |||
4326 | if (start_mode == ME_START_MODE_BLOCKING) { | ||
4327 | init_waitqueue_head(&queue); | ||
4328 | |||
4329 | if (delay) { | ||
4330 | ref = jiffies; | ||
4331 | |||
4332 | while (! | ||
4333 | (inl(instance->status_reg) & | ||
4334 | ME4600_AO_STATUS_BIT_FSM)) { | ||
4335 | interruptible_sleep_on_timeout | ||
4336 | (&queue, 1); | ||
4337 | |||
4338 | if (signal_pending(current)) { | ||
4339 | PERROR | ||
4340 | ("Wait on start of state machine interrupted.\n"); | ||
4341 | stop_immediately | ||
4342 | (instance); | ||
4343 | err = ME_ERRNO_SIGNAL; | ||
4344 | goto ERROR; | ||
4345 | } | ||
4346 | |||
4347 | if (((jiffies - ref) >= delay)) { | ||
4348 | PERROR | ||
4349 | ("Timeout reached.\n"); | ||
4350 | stop_immediately | ||
4351 | (instance); | ||
4352 | err = ME_ERRNO_TIMEOUT; | ||
4353 | goto ERROR; | ||
4354 | } | ||
4355 | } | ||
4356 | } else { | ||
4357 | while (! | ||
4358 | (inl(instance->status_reg) & | ||
4359 | ME4600_AO_STATUS_BIT_FSM)) { | ||
4360 | interruptible_sleep_on_timeout | ||
4361 | (&queue, 1); | ||
4362 | |||
4363 | if (signal_pending(current)) { | ||
4364 | PERROR | ||
4365 | ("Wait on start of state machine interrupted.\n"); | ||
4366 | stop_immediately | ||
4367 | (instance); | ||
4368 | err = ME_ERRNO_SIGNAL; | ||
4369 | goto ERROR; | ||
4370 | } | ||
4371 | } | ||
4372 | } | ||
4373 | } else if (start_mode == ME_START_MODE_NONBLOCKING) { | ||
4374 | } else { | ||
4375 | PERROR("Invalid start mode specified.\n"); | ||
4376 | err = ME_ERRNO_INVALID_START_MODE; | ||
4377 | goto ERROR; | ||
4378 | } | ||
4379 | } else if ((inl(instance->preload_reg) & (0x10001 << instance->ao_idx)) == (0x10000 << instance->ao_idx)) { // Synchronous with external trigger | ||
4380 | |||
4381 | if ((inl(instance->status_reg) & | ||
4382 | ME4600_AO_STATUS_BIT_FSM)) { | ||
4383 | spin_unlock_irqrestore(&instance-> | ||
4384 | subdevice_lock, | ||
4385 | cpu_flags); | ||
4386 | PERROR("Conversion is already running.\n"); | ||
4387 | err = ME_ERRNO_SUBDEVICE_BUSY; | ||
4388 | goto ERROR; | ||
4389 | } | ||
4390 | |||
4391 | if (flags & ME_IO_STREAM_START_TYPE_TRIG_SYNCHRONOUS) { | ||
4392 | tmp |= ME4600_AO_CTRL_BIT_ENABLE_EX_TRIG; | ||
4393 | tmp &= | ||
4394 | ~(ME4600_AO_CTRL_BIT_ENABLE_IRQ | | ||
4395 | ME4600_AO_CTRL_BIT_STOP | | ||
4396 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP); | ||
4397 | outl(tmp, instance->ctrl_reg); | ||
4398 | spin_unlock_irqrestore(&instance-> | ||
4399 | subdevice_lock, | ||
4400 | cpu_flags); | ||
4401 | |||
4402 | if (start_mode == ME_START_MODE_BLOCKING) { | ||
4403 | init_waitqueue_head(&queue); | ||
4404 | |||
4405 | if (delay) { | ||
4406 | ref = jiffies; | ||
4407 | |||
4408 | while (! | ||
4409 | (inl | ||
4410 | (instance-> | ||
4411 | status_reg) & | ||
4412 | ME4600_AO_STATUS_BIT_FSM)) | ||
4413 | { | ||
4414 | interruptible_sleep_on_timeout | ||
4415 | (&queue, 1); | ||
4416 | |||
4417 | if (signal_pending | ||
4418 | (current)) { | ||
4419 | PERROR | ||
4420 | ("Wait on start of state machine interrupted.\n"); | ||
4421 | stop_immediately | ||
4422 | (instance); | ||
4423 | err = | ||
4424 | ME_ERRNO_SIGNAL; | ||
4425 | goto ERROR; | ||
4426 | } | ||
4427 | |||
4428 | if (((jiffies - ref) >= | ||
4429 | delay)) { | ||
4430 | PERROR | ||
4431 | ("Timeout reached.\n"); | ||
4432 | stop_immediately | ||
4433 | (instance); | ||
4434 | err = | ||
4435 | ME_ERRNO_TIMEOUT; | ||
4436 | goto ERROR; | ||
4437 | } | ||
4438 | } | ||
4439 | } else { | ||
4440 | while (! | ||
4441 | (inl | ||
4442 | (instance-> | ||
4443 | status_reg) & | ||
4444 | ME4600_AO_STATUS_BIT_FSM)) | ||
4445 | { | ||
4446 | interruptible_sleep_on_timeout | ||
4447 | (&queue, 1); | ||
4448 | |||
4449 | if (signal_pending | ||
4450 | (current)) { | ||
4451 | PERROR | ||
4452 | ("Wait on start of state machine interrupted.\n"); | ||
4453 | stop_immediately | ||
4454 | (instance); | ||
4455 | err = | ||
4456 | ME_ERRNO_SIGNAL; | ||
4457 | goto ERROR; | ||
4458 | } | ||
4459 | } | ||
4460 | } | ||
4461 | } else if (start_mode == | ||
4462 | ME_START_MODE_NONBLOCKING) { | ||
4463 | } else { | ||
4464 | PERROR | ||
4465 | ("Invalid start mode specified.\n"); | ||
4466 | err = ME_ERRNO_INVALID_START_MODE; | ||
4467 | goto ERROR; | ||
4468 | } | ||
4469 | } else { | ||
4470 | tmp &= | ||
4471 | ~(ME4600_AO_CTRL_BIT_ENABLE_IRQ | | ||
4472 | ME4600_AO_CTRL_BIT_STOP | | ||
4473 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP); | ||
4474 | outl(tmp, instance->ctrl_reg); | ||
4475 | spin_unlock_irqrestore(&instance-> | ||
4476 | subdevice_lock, | ||
4477 | cpu_flags); | ||
4478 | } | ||
4479 | } else if ((inl(instance->preload_reg) & (0x10001 << instance->ao_idx)) == (0x1 << instance->ao_idx)) { // Synchronous wraparound with sw trigger | ||
4480 | |||
4481 | if ((inl(instance->status_reg) & | ||
4482 | ME4600_AO_STATUS_BIT_FSM)) { | ||
4483 | spin_unlock_irqrestore(&instance-> | ||
4484 | subdevice_lock, | ||
4485 | cpu_flags); | ||
4486 | PERROR("Conversion is already running.\n"); | ||
4487 | err = ME_ERRNO_SUBDEVICE_BUSY; | ||
4488 | goto ERROR; | ||
4489 | } | ||
4490 | |||
4491 | tmp &= | ||
4492 | ~(ME4600_AO_CTRL_BIT_ENABLE_IRQ | | ||
4493 | ME4600_AO_CTRL_BIT_STOP | | ||
4494 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP); | ||
4495 | |||
4496 | outl(tmp, instance->ctrl_reg); | ||
4497 | |||
4498 | if (flags & ME_IO_STREAM_START_TYPE_TRIG_SYNCHRONOUS) { | ||
4499 | outl(0x8000, instance->single_reg); | ||
4500 | instance->single_value = 0x8000; | ||
4501 | } | ||
4502 | |||
4503 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
4504 | cpu_flags); | ||
4505 | } else { // Software start | ||
4506 | |||
4507 | if ((inl(instance->status_reg) & | ||
4508 | ME4600_AO_STATUS_BIT_FSM)) { | ||
4509 | spin_unlock_irqrestore(&instance-> | ||
4510 | subdevice_lock, | ||
4511 | cpu_flags); | ||
4512 | PERROR("Conversion is already running.\n"); | ||
4513 | err = ME_ERRNO_SUBDEVICE_BUSY; | ||
4514 | goto ERROR; | ||
4515 | } | ||
4516 | |||
4517 | tmp &= | ||
4518 | ~(ME4600_AO_CTRL_BIT_ENABLE_IRQ | | ||
4519 | ME4600_AO_CTRL_BIT_STOP | | ||
4520 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP); | ||
4521 | |||
4522 | outl(tmp, instance->ctrl_reg); | ||
4523 | |||
4524 | outl(0x8000, instance->single_reg); | ||
4525 | instance->single_value = 0x8000; | ||
4526 | |||
4527 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
4528 | cpu_flags); | ||
4529 | } | ||
4530 | |||
4531 | break; | ||
4532 | |||
4533 | case 2: // Continuous mode | ||
4534 | if (tmp & ME4600_AO_CTRL_BIT_ENABLE_EX_TRIG) { // Externally triggered | ||
4535 | |||
4536 | if ((inl(instance->status_reg) & | ||
4537 | ME4600_AO_STATUS_BIT_FSM)) { | ||
4538 | spin_unlock_irqrestore(&instance-> | ||
4539 | subdevice_lock, | ||
4540 | cpu_flags); | ||
4541 | PERROR("Conversion is already running.\n"); | ||
4542 | err = ME_ERRNO_SUBDEVICE_BUSY; | ||
4543 | goto ERROR; | ||
4544 | } | ||
4545 | |||
4546 | tmp &= | ||
4547 | ~(ME4600_AO_CTRL_BIT_STOP | | ||
4548 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP); | ||
4549 | tmp |= ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
4550 | outl(tmp, instance->ctrl_reg); | ||
4551 | instance->wrap_remaining = instance->wrap_count; | ||
4552 | instance->circ_buf.tail = 0; | ||
4553 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
4554 | cpu_flags); | ||
4555 | |||
4556 | if (start_mode == ME_START_MODE_BLOCKING) { | ||
4557 | init_waitqueue_head(&queue); | ||
4558 | |||
4559 | if (delay) { | ||
4560 | ref = jiffies; | ||
4561 | |||
4562 | while (! | ||
4563 | (inl(instance->status_reg) & | ||
4564 | ME4600_AO_STATUS_BIT_FSM)) { | ||
4565 | interruptible_sleep_on_timeout | ||
4566 | (&queue, 1); | ||
4567 | |||
4568 | if (signal_pending(current)) { | ||
4569 | PERROR | ||
4570 | ("Wait on start of state machine interrupted.\n"); | ||
4571 | stop_immediately | ||
4572 | (instance); | ||
4573 | err = ME_ERRNO_SIGNAL; | ||
4574 | goto ERROR; | ||
4575 | } | ||
4576 | |||
4577 | if (((jiffies - ref) >= delay)) { | ||
4578 | PERROR | ||
4579 | ("Timeout reached.\n"); | ||
4580 | stop_immediately | ||
4581 | (instance); | ||
4582 | err = ME_ERRNO_TIMEOUT; | ||
4583 | goto ERROR; | ||
4584 | } | ||
4585 | } | ||
4586 | } else { | ||
4587 | while (! | ||
4588 | (inl(instance->status_reg) & | ||
4589 | ME4600_AO_STATUS_BIT_FSM)) { | ||
4590 | interruptible_sleep_on_timeout | ||
4591 | (&queue, 1); | ||
4592 | |||
4593 | if (signal_pending(current)) { | ||
4594 | PERROR | ||
4595 | ("Wait on start of state machine interrupted.\n"); | ||
4596 | stop_immediately | ||
4597 | (instance); | ||
4598 | err = ME_ERRNO_SIGNAL; | ||
4599 | goto ERROR; | ||
4600 | } | ||
4601 | } | ||
4602 | } | ||
4603 | } else if (start_mode == ME_START_MODE_NONBLOCKING) { | ||
4604 | /* Do nothing */ | ||
4605 | } else { | ||
4606 | PERROR("Invalid start mode specified.\n"); | ||
4607 | stop_immediately(instance); | ||
4608 | err = ME_ERRNO_INVALID_START_MODE; | ||
4609 | goto ERROR; | ||
4610 | } | ||
4611 | } else if ((inl(instance->preload_reg) & (0x10001 << instance->ao_idx)) == (0x10000 << instance->ao_idx)) { // Synchronous with external trigger | ||
4612 | |||
4613 | if ((inl(instance->status_reg) & | ||
4614 | ME4600_AO_STATUS_BIT_FSM)) { | ||
4615 | spin_unlock_irqrestore(&instance-> | ||
4616 | subdevice_lock, | ||
4617 | cpu_flags); | ||
4618 | PERROR("Conversion is already running.\n"); | ||
4619 | err = ME_ERRNO_SUBDEVICE_BUSY; | ||
4620 | goto ERROR; | ||
4621 | } | ||
4622 | |||
4623 | if (flags & ME_IO_STREAM_START_TYPE_TRIG_SYNCHRONOUS) { | ||
4624 | tmp |= | ||
4625 | ME4600_AO_CTRL_BIT_ENABLE_EX_TRIG | | ||
4626 | ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
4627 | tmp &= | ||
4628 | ~(ME4600_AO_CTRL_BIT_STOP | | ||
4629 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP); | ||
4630 | outl(tmp, instance->ctrl_reg); | ||
4631 | instance->wrap_remaining = instance->wrap_count; | ||
4632 | instance->circ_buf.tail = 0; | ||
4633 | |||
4634 | spin_unlock_irqrestore(&instance-> | ||
4635 | subdevice_lock, | ||
4636 | cpu_flags); | ||
4637 | |||
4638 | if (start_mode == ME_START_MODE_BLOCKING) { | ||
4639 | init_waitqueue_head(&queue); | ||
4640 | |||
4641 | if (delay) { | ||
4642 | ref = jiffies; | ||
4643 | |||
4644 | while (! | ||
4645 | (inl | ||
4646 | (instance-> | ||
4647 | status_reg) & | ||
4648 | ME4600_AO_STATUS_BIT_FSM)) | ||
4649 | { | ||
4650 | interruptible_sleep_on_timeout | ||
4651 | (&queue, 1); | ||
4652 | |||
4653 | if (signal_pending | ||
4654 | (current)) { | ||
4655 | PERROR | ||
4656 | ("Wait on start of state machine interrupted.\n"); | ||
4657 | stop_immediately | ||
4658 | (instance); | ||
4659 | err = | ||
4660 | ME_ERRNO_SIGNAL; | ||
4661 | goto ERROR; | ||
4662 | } | ||
4663 | |||
4664 | if (((jiffies - ref) >= | ||
4665 | delay)) { | ||
4666 | PERROR | ||
4667 | ("Timeout reached.\n"); | ||
4668 | stop_immediately | ||
4669 | (instance); | ||
4670 | err = | ||
4671 | ME_ERRNO_TIMEOUT; | ||
4672 | goto ERROR; | ||
4673 | } | ||
4674 | } | ||
4675 | } else { | ||
4676 | while (! | ||
4677 | (inl | ||
4678 | (instance-> | ||
4679 | status_reg) & | ||
4680 | ME4600_AO_STATUS_BIT_FSM)) | ||
4681 | { | ||
4682 | interruptible_sleep_on_timeout | ||
4683 | (&queue, 1); | ||
4684 | |||
4685 | if (signal_pending | ||
4686 | (current)) { | ||
4687 | PERROR | ||
4688 | ("Wait on start of state machine interrupted.\n"); | ||
4689 | stop_immediately | ||
4690 | (instance); | ||
4691 | err = | ||
4692 | ME_ERRNO_SIGNAL; | ||
4693 | goto ERROR; | ||
4694 | } | ||
4695 | } | ||
4696 | } | ||
4697 | } else if (start_mode == | ||
4698 | ME_START_MODE_NONBLOCKING) { | ||
4699 | } else { | ||
4700 | PERROR | ||
4701 | ("Invalid start mode specified.\n"); | ||
4702 | stop_immediately(instance); | ||
4703 | err = ME_ERRNO_INVALID_START_MODE; | ||
4704 | goto ERROR; | ||
4705 | } | ||
4706 | } else { | ||
4707 | tmp |= ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
4708 | tmp &= | ||
4709 | ~(ME4600_AO_CTRL_BIT_STOP | | ||
4710 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP); | ||
4711 | outl(tmp, instance->ctrl_reg); | ||
4712 | instance->wrap_remaining = instance->wrap_count; | ||
4713 | instance->circ_buf.tail = 0; | ||
4714 | spin_unlock_irqrestore(&instance-> | ||
4715 | subdevice_lock, | ||
4716 | cpu_flags); | ||
4717 | } | ||
4718 | } else if ((inl(instance->preload_reg) & (0x10001 << instance->ao_idx)) == (0x1 << instance->ao_idx)) { // Synchronous wraparound with sw trigger | ||
4719 | |||
4720 | if ((inl(instance->status_reg) & | ||
4721 | ME4600_AO_STATUS_BIT_FSM)) { | ||
4722 | spin_unlock_irqrestore(&instance-> | ||
4723 | subdevice_lock, | ||
4724 | cpu_flags); | ||
4725 | PERROR("Conversion is already running.\n"); | ||
4726 | err = ME_ERRNO_SUBDEVICE_BUSY; | ||
4727 | goto ERROR; | ||
4728 | } | ||
4729 | |||
4730 | tmp &= | ||
4731 | ~(ME4600_AO_CTRL_BIT_STOP | | ||
4732 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP); | ||
4733 | tmp |= ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
4734 | instance->wrap_remaining = instance->wrap_count; | ||
4735 | instance->circ_buf.tail = 0; | ||
4736 | PDEBUG("CTRL Reg = 0x%X.\n", inl(instance->ctrl_reg)); | ||
4737 | outl(tmp, instance->ctrl_reg); | ||
4738 | |||
4739 | if (flags & ME_IO_STREAM_START_TYPE_TRIG_SYNCHRONOUS) { | ||
4740 | outl(0x8000, instance->single_reg); | ||
4741 | instance->single_value = 0x8000; | ||
4742 | } | ||
4743 | |||
4744 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
4745 | cpu_flags); | ||
4746 | } else { // Software start | ||
4747 | |||
4748 | if ((inl(instance->status_reg) & | ||
4749 | ME4600_AO_STATUS_BIT_FSM)) { | ||
4750 | spin_unlock_irqrestore(&instance-> | ||
4751 | subdevice_lock, | ||
4752 | cpu_flags); | ||
4753 | PERROR("Conversion is already running.\n"); | ||
4754 | err = ME_ERRNO_SUBDEVICE_BUSY; | ||
4755 | goto ERROR; | ||
4756 | } | ||
4757 | |||
4758 | tmp &= | ||
4759 | ~(ME4600_AO_CTRL_BIT_STOP | | ||
4760 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP); | ||
4761 | |||
4762 | tmp |= ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
4763 | outl(tmp, instance->ctrl_reg); | ||
4764 | outl(0x8000, instance->single_reg); | ||
4765 | instance->single_value = 0x8000; | ||
4766 | instance->wrap_remaining = instance->wrap_count; | ||
4767 | instance->circ_buf.tail = 0; | ||
4768 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
4769 | cpu_flags); | ||
4770 | } | ||
4771 | |||
4772 | break; | ||
4773 | |||
4774 | default: | ||
4775 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
4776 | PERROR("Invalid mode configured.\n"); | ||
4777 | err = ME_ERRNO_INTERNAL; | ||
4778 | goto ERROR; | ||
4779 | } | ||
4780 | |||
4781 | ERROR: | ||
4782 | |||
4783 | ME_SUBDEVICE_EXIT; | ||
4784 | |||
4785 | return err; | ||
4786 | } | ||
4787 | |||
4788 | static int me4600_ao_io_stream_status(me_subdevice_t * subdevice, | ||
4789 | struct file *filep, | ||
4790 | int wait, | ||
4791 | int *status, int *values, int flags) | ||
4792 | { | ||
4793 | me4600_ao_subdevice_t *instance; | ||
4794 | int err = ME_ERRNO_SUCCESS; | ||
4795 | wait_queue_head_t queue; | ||
4796 | |||
4797 | PDEBUG("executed.\n"); | ||
4798 | |||
4799 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
4800 | |||
4801 | init_waitqueue_head(&queue); | ||
4802 | |||
4803 | if (!instance->fifo) { | ||
4804 | PERROR("Not a streaming ao.\n"); | ||
4805 | return ME_ERRNO_NOT_SUPPORTED; | ||
4806 | } | ||
4807 | |||
4808 | ME_SUBDEVICE_ENTER; | ||
4809 | |||
4810 | if (wait == ME_WAIT_NONE) { | ||
4811 | *status = | ||
4812 | (inl(instance->status_reg) & ME4600_AO_STATUS_BIT_FSM) ? | ||
4813 | ME_STATUS_BUSY : ME_STATUS_IDLE; | ||
4814 | *values = me_circ_buf_space(&instance->circ_buf); | ||
4815 | } else if (wait == ME_WAIT_IDLE) { | ||
4816 | while (inl(instance->status_reg) & ME4600_AO_STATUS_BIT_FSM) { | ||
4817 | interruptible_sleep_on_timeout(&queue, 1); | ||
4818 | |||
4819 | if (instance->flags & ME4600_AO_FLAGS_BROKEN_PIPE) { | ||
4820 | PERROR("Output stream was interrupted.\n"); | ||
4821 | *status = ME_STATUS_ERROR; | ||
4822 | err = ME_ERRNO_SUCCESS; | ||
4823 | goto ERROR; | ||
4824 | } | ||
4825 | |||
4826 | if (signal_pending(current)) { | ||
4827 | PERROR | ||
4828 | ("Wait on state machine interrupted by signal.\n"); | ||
4829 | *status = ME_STATUS_INVALID; | ||
4830 | err = ME_ERRNO_SIGNAL; | ||
4831 | goto ERROR; | ||
4832 | } | ||
4833 | } | ||
4834 | |||
4835 | *status = ME_STATUS_IDLE; | ||
4836 | |||
4837 | *values = me_circ_buf_space(&instance->circ_buf); | ||
4838 | } else { | ||
4839 | PERROR("Invalid wait argument specified.\n"); | ||
4840 | *status = ME_STATUS_INVALID; | ||
4841 | err = ME_ERRNO_INVALID_WAIT; | ||
4842 | goto ERROR; | ||
4843 | } | ||
4844 | |||
4845 | ERROR: | ||
4846 | |||
4847 | ME_SUBDEVICE_EXIT; | ||
4848 | |||
4849 | return err; | ||
4850 | } | ||
4851 | |||
4852 | static int me4600_ao_io_stream_stop(me_subdevice_t * subdevice, | ||
4853 | struct file *filep, | ||
4854 | int stop_mode, int flags) | ||
4855 | { | ||
4856 | int err = ME_ERRNO_SUCCESS; | ||
4857 | me4600_ao_subdevice_t *instance; | ||
4858 | unsigned long cpu_flags; | ||
4859 | unsigned long tmp; | ||
4860 | |||
4861 | PDEBUG("executed.\n"); | ||
4862 | |||
4863 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
4864 | |||
4865 | if (!instance->fifo) { | ||
4866 | PERROR("Not a streaming ao.\n"); | ||
4867 | return ME_ERRNO_NOT_SUPPORTED; | ||
4868 | } | ||
4869 | |||
4870 | ME_SUBDEVICE_ENTER; | ||
4871 | |||
4872 | if (stop_mode == ME_STOP_MODE_IMMEDIATE) { | ||
4873 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
4874 | tmp = inl(instance->ctrl_reg); | ||
4875 | tmp |= | ||
4876 | ME4600_AO_CTRL_BIT_STOP | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
4877 | outl(tmp, instance->ctrl_reg); | ||
4878 | |||
4879 | while (inl(instance->status_reg) & ME4600_AO_STATUS_BIT_FSM) ; | ||
4880 | |||
4881 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
4882 | } else if (stop_mode == ME_STOP_MODE_LAST_VALUE) { | ||
4883 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
4884 | tmp = inl(instance->ctrl_reg); | ||
4885 | tmp |= ME4600_AO_CTRL_BIT_STOP; | ||
4886 | outl(tmp, instance->ctrl_reg); | ||
4887 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
4888 | } else { | ||
4889 | PERROR("Invalid stop mode specified.\n"); | ||
4890 | err = ME_ERRNO_INVALID_STOP_MODE; | ||
4891 | goto ERROR; | ||
4892 | } | ||
4893 | |||
4894 | ERROR: | ||
4895 | |||
4896 | ME_SUBDEVICE_EXIT; | ||
4897 | |||
4898 | return err; | ||
4899 | } | ||
4900 | |||
4901 | static int me4600_ao_io_stream_write(me_subdevice_t * subdevice, | ||
4902 | struct file *filep, | ||
4903 | int write_mode, | ||
4904 | int *values, int *count, int flags) | ||
4905 | { | ||
4906 | int err = ME_ERRNO_SUCCESS; | ||
4907 | me4600_ao_subdevice_t *instance; | ||
4908 | unsigned long tmp; | ||
4909 | int i; | ||
4910 | int value; | ||
4911 | int cnt = *count; | ||
4912 | int c; | ||
4913 | int k; | ||
4914 | int ret = 0; | ||
4915 | unsigned long cpu_flags = 0; | ||
4916 | |||
4917 | PDEBUG("executed.\n"); | ||
4918 | |||
4919 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
4920 | |||
4921 | if (!instance->fifo) { | ||
4922 | PERROR("Not a streaming ao.\n"); | ||
4923 | return ME_ERRNO_NOT_SUPPORTED; | ||
4924 | } | ||
4925 | |||
4926 | ME_SUBDEVICE_ENTER; | ||
4927 | |||
4928 | if (*count <= 0) { | ||
4929 | PERROR("Invalid count of values specified.\n"); | ||
4930 | err = ME_ERRNO_INVALID_VALUE_COUNT; | ||
4931 | goto ERROR; | ||
4932 | } | ||
4933 | |||
4934 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
4935 | |||
4936 | tmp = inl(instance->ctrl_reg); | ||
4937 | |||
4938 | switch (tmp & 0x3) { | ||
4939 | |||
4940 | case 1: // Wraparound mode | ||
4941 | if (instance->bosch_fw) { // Bosch firmware | ||
4942 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
4943 | cpu_flags); | ||
4944 | |||
4945 | if (cnt != 7) { | ||
4946 | PERROR | ||
4947 | ("Invalid count of values specified. 7 expected.\n"); | ||
4948 | err = ME_ERRNO_INVALID_VALUE_COUNT; | ||
4949 | goto ERROR; | ||
4950 | } | ||
4951 | |||
4952 | for (i = 0; i < 7; i++) { | ||
4953 | if (get_user(value, values)) { | ||
4954 | PERROR | ||
4955 | ("Can't copy value from user space.\n"); | ||
4956 | err = ME_ERRNO_INTERNAL; | ||
4957 | goto ERROR; | ||
4958 | } | ||
4959 | |||
4960 | if (i == 0) { | ||
4961 | /* Maximum voltage */ | ||
4962 | value <<= 16; | ||
4963 | value |= | ||
4964 | inl(instance->reg_base + | ||
4965 | 0xD4) & 0xFFFF; | ||
4966 | outl(value, instance->reg_base + 0xD4); | ||
4967 | } else if (i == 1) { | ||
4968 | /* Minimum voltage */ | ||
4969 | value &= 0xFFFF; | ||
4970 | value |= | ||
4971 | inl(instance->reg_base + | ||
4972 | 0xD4) & 0xFFFF0000; | ||
4973 | outl(value, instance->reg_base + 0xD4); | ||
4974 | } else if (i == 2) { | ||
4975 | /* Delta up */ | ||
4976 | value <<= 16; | ||
4977 | value |= | ||
4978 | inl(instance->reg_base + | ||
4979 | 0xD8) & 0xFFFF; | ||
4980 | outl(value, instance->reg_base + 0xD8); | ||
4981 | } else if (i == 3) { | ||
4982 | /* Delta down */ | ||
4983 | value &= 0xFFFF; | ||
4984 | value |= | ||
4985 | inl(instance->reg_base + | ||
4986 | 0xD8) & 0xFFFF0000; | ||
4987 | outl(value, instance->reg_base + 0xD8); | ||
4988 | } else if (i == 4) { | ||
4989 | /* Start value */ | ||
4990 | outl(value, instance->reg_base + 0xDC); | ||
4991 | } else if (i == 5) { | ||
4992 | /* Invert */ | ||
4993 | if (value) { | ||
4994 | value = inl(instance->ctrl_reg); | ||
4995 | value |= 0x100; | ||
4996 | outl(value, instance->ctrl_reg); | ||
4997 | } else { | ||
4998 | value = inl(instance->ctrl_reg); | ||
4999 | value &= ~0x100; | ||
5000 | outl(value, instance->ctrl_reg); | ||
5001 | } | ||
5002 | } else if (i == 6) { | ||
5003 | /* Timer for positive ramp */ | ||
5004 | outl(value, instance->reg_base + 0xE0); | ||
5005 | } | ||
5006 | |||
5007 | values++; | ||
5008 | } | ||
5009 | } else { // Normal firmware | ||
5010 | PDEBUG("Write for wraparound mode.\n"); | ||
5011 | |||
5012 | if (inl(instance->status_reg) & | ||
5013 | ME4600_AO_STATUS_BIT_FSM) { | ||
5014 | spin_unlock_irqrestore(&instance-> | ||
5015 | subdevice_lock, | ||
5016 | cpu_flags); | ||
5017 | PERROR | ||
5018 | ("There is already a conversion running.\n"); | ||
5019 | err = ME_ERRNO_SUBDEVICE_BUSY; | ||
5020 | goto ERROR; | ||
5021 | } | ||
5022 | |||
5023 | tmp |= ME4600_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
5024 | tmp &= ~ME4600_AO_CTRL_BIT_ENABLE_FIFO; | ||
5025 | outl(tmp, instance->ctrl_reg); | ||
5026 | tmp |= ME4600_AO_CTRL_BIT_ENABLE_FIFO; | ||
5027 | |||
5028 | if ((*count > ME4600_AO_FIFO_COUNT) || | ||
5029 | ((instance-> | ||
5030 | flags & ME4600_AO_FLAGS_SW_WRAP_MODE_MASK) == | ||
5031 | ME4600_AO_FLAGS_SW_WRAP_MODE_FIN)) { | ||
5032 | tmp &= | ||
5033 | ~(ME4600_AO_CTRL_BIT_MODE_0 | | ||
5034 | ME4600_AO_CTRL_BIT_MODE_1); | ||
5035 | tmp |= ME4600_AO_CTRL_BIT_MODE_1; | ||
5036 | } | ||
5037 | |||
5038 | outl(tmp, instance->ctrl_reg); | ||
5039 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
5040 | cpu_flags); | ||
5041 | |||
5042 | if ((*count <= ME4600_AO_FIFO_COUNT) && | ||
5043 | ((instance-> | ||
5044 | flags & ME4600_AO_FLAGS_SW_WRAP_MODE_MASK) == | ||
5045 | ME4600_AO_FLAGS_SW_WRAP_MODE_INF)) { | ||
5046 | for (i = 0; i < *count; i++) { | ||
5047 | if (get_user(value, values + i)) { | ||
5048 | PERROR | ||
5049 | ("Cannot copy value from user space.\n"); | ||
5050 | err = ME_ERRNO_INTERNAL; | ||
5051 | goto ERROR; | ||
5052 | } | ||
5053 | |||
5054 | if (instance->ao_idx & 0x1) | ||
5055 | value <<= 16; | ||
5056 | |||
5057 | outl(value, instance->fifo_reg); | ||
5058 | } | ||
5059 | } else if ((*count <= ME4600_AO_CIRC_BUF_COUNT) && | ||
5060 | ((instance-> | ||
5061 | flags & ME4600_AO_FLAGS_SW_WRAP_MODE_MASK) | ||
5062 | == ME4600_AO_FLAGS_SW_WRAP_MODE_INF)) { | ||
5063 | for (i = 0; i < *count; i++) { | ||
5064 | if (get_user(value, values + i)) { | ||
5065 | PERROR | ||
5066 | ("Cannot copy value from user space.\n"); | ||
5067 | err = ME_ERRNO_INTERNAL; | ||
5068 | goto ERROR; | ||
5069 | } | ||
5070 | |||
5071 | instance->circ_buf.buf[i] = value; /* Used to hold the values. */ | ||
5072 | } | ||
5073 | |||
5074 | instance->circ_buf.tail = 0; /* Used as the current read position. */ | ||
5075 | instance->circ_buf.head = *count; /* Used as the buffer size. */ | ||
5076 | |||
5077 | /* Preload the FIFO. */ | ||
5078 | |||
5079 | for (i = 0; i < ME4600_AO_FIFO_COUNT; | ||
5080 | i++, instance->circ_buf.tail++) { | ||
5081 | if (instance->circ_buf.tail >= | ||
5082 | instance->circ_buf.head) | ||
5083 | instance->circ_buf.tail = 0; | ||
5084 | |||
5085 | if (instance->ao_idx & 0x1) | ||
5086 | outl(instance->circ_buf. | ||
5087 | buf[instance->circ_buf. | ||
5088 | tail] << 16, | ||
5089 | instance->fifo_reg); | ||
5090 | else | ||
5091 | outl(instance->circ_buf. | ||
5092 | buf[instance->circ_buf. | ||
5093 | tail], | ||
5094 | instance->fifo_reg); | ||
5095 | } | ||
5096 | } else if ((*count <= ME4600_AO_CIRC_BUF_COUNT) && | ||
5097 | ((instance-> | ||
5098 | flags & ME4600_AO_FLAGS_SW_WRAP_MODE_MASK) | ||
5099 | == ME4600_AO_FLAGS_SW_WRAP_MODE_FIN)) { | ||
5100 | unsigned int preload_count; | ||
5101 | |||
5102 | for (i = 0; i < *count; i++) { | ||
5103 | if (get_user(value, values + i)) { | ||
5104 | PERROR | ||
5105 | ("Cannot copy value from user space.\n"); | ||
5106 | err = ME_ERRNO_INTERNAL; | ||
5107 | goto ERROR; | ||
5108 | } | ||
5109 | |||
5110 | instance->circ_buf.buf[i] = value; /* Used to hold the values. */ | ||
5111 | } | ||
5112 | |||
5113 | instance->circ_buf.tail = 0; /* Used as the current read position. */ | ||
5114 | instance->circ_buf.head = *count; /* Used as the buffer size. */ | ||
5115 | |||
5116 | /* Try to preload the whole FIFO. */ | ||
5117 | preload_count = ME4600_AO_FIFO_COUNT; | ||
5118 | |||
5119 | if (preload_count > instance->wrap_count) | ||
5120 | preload_count = instance->wrap_count; | ||
5121 | |||
5122 | /* Preload the FIFO. */ | ||
5123 | for (i = 0; i < preload_count; | ||
5124 | i++, instance->circ_buf.tail++) { | ||
5125 | if (instance->circ_buf.tail >= | ||
5126 | instance->circ_buf.head) | ||
5127 | instance->circ_buf.tail = 0; | ||
5128 | |||
5129 | if (instance->ao_idx & 0x1) | ||
5130 | outl(instance->circ_buf. | ||
5131 | buf[instance->circ_buf. | ||
5132 | tail] << 16, | ||
5133 | instance->fifo_reg); | ||
5134 | else | ||
5135 | outl(instance->circ_buf. | ||
5136 | buf[instance->circ_buf. | ||
5137 | tail], | ||
5138 | instance->fifo_reg); | ||
5139 | } | ||
5140 | |||
5141 | instance->wrap_remaining = | ||
5142 | instance->wrap_count - preload_count; | ||
5143 | } else { | ||
5144 | PERROR("To many values written.\n"); | ||
5145 | err = ME_ERRNO_INVALID_VALUE_COUNT; | ||
5146 | goto ERROR; | ||
5147 | } | ||
5148 | } | ||
5149 | |||
5150 | break; | ||
5151 | |||
5152 | case 2: // Continuous mode | ||
5153 | /* Check if in SW wrapround mode */ | ||
5154 | if (instance->flags & ME4600_AO_FLAGS_SW_WRAP_MODE_MASK) { | ||
5155 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
5156 | cpu_flags); | ||
5157 | PERROR("Subdevice is configured SW wrapround mode.\n"); | ||
5158 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
5159 | goto ERROR; | ||
5160 | } | ||
5161 | |||
5162 | switch (write_mode) { | ||
5163 | |||
5164 | case ME_WRITE_MODE_BLOCKING: | ||
5165 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
5166 | cpu_flags); | ||
5167 | |||
5168 | PDEBUG("Write for blocking continuous mode.\n"); | ||
5169 | |||
5170 | while (cnt > 0) { | ||
5171 | wait_event_interruptible(instance->wait_queue, | ||
5172 | (c = | ||
5173 | me_circ_buf_space_to_end | ||
5174 | (&instance-> | ||
5175 | circ_buf))); | ||
5176 | |||
5177 | if (instance-> | ||
5178 | flags & ME4600_AO_FLAGS_BROKEN_PIPE) { | ||
5179 | PERROR | ||
5180 | ("Broken pipe in blocking write.\n"); | ||
5181 | err = ME_ERRNO_SUBDEVICE_NOT_RUNNING; | ||
5182 | goto ERROR; | ||
5183 | } else if (signal_pending(current)) { | ||
5184 | PERROR | ||
5185 | ("Wait for free buffer interrupted from signal.\n"); | ||
5186 | err = ME_ERRNO_SIGNAL; | ||
5187 | goto ERROR; | ||
5188 | } | ||
5189 | |||
5190 | PDEBUG("Space to end = %d.\n", c); | ||
5191 | |||
5192 | /* Only able to write size of free buffer or size of count */ | ||
5193 | |||
5194 | if (cnt < c) | ||
5195 | c = cnt; | ||
5196 | k = sizeof(int) * c; | ||
5197 | k -= copy_from_user(instance->circ_buf.buf + | ||
5198 | instance->circ_buf.head, | ||
5199 | values, k); | ||
5200 | c = k / sizeof(int); | ||
5201 | |||
5202 | PDEBUG("Copy %d values from user space.\n", c); | ||
5203 | |||
5204 | if (!c) { | ||
5205 | PERROR | ||
5206 | ("Cannot copy values from user space.\n"); | ||
5207 | err = ME_ERRNO_INTERNAL; | ||
5208 | goto ERROR; | ||
5209 | } | ||
5210 | |||
5211 | instance->circ_buf.head = | ||
5212 | (instance->circ_buf.head + | ||
5213 | c) & (instance->circ_buf.mask); | ||
5214 | |||
5215 | values += c; | ||
5216 | cnt -= c; | ||
5217 | ret += c; | ||
5218 | |||
5219 | /* Values are now available so enable interrupts */ | ||
5220 | spin_lock_irqsave(&instance->subdevice_lock, | ||
5221 | cpu_flags); | ||
5222 | |||
5223 | if (me_circ_buf_space(&instance->circ_buf)) { | ||
5224 | tmp = inl(instance->ctrl_reg); | ||
5225 | tmp |= ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
5226 | outl(tmp, instance->ctrl_reg); | ||
5227 | } | ||
5228 | |||
5229 | spin_unlock_irqrestore(&instance-> | ||
5230 | subdevice_lock, | ||
5231 | cpu_flags); | ||
5232 | } | ||
5233 | |||
5234 | *count = ret; | ||
5235 | |||
5236 | break; | ||
5237 | |||
5238 | case ME_WRITE_MODE_NONBLOCKING: | ||
5239 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
5240 | cpu_flags); | ||
5241 | |||
5242 | PDEBUG("Write for non blocking continuous mode.\n"); | ||
5243 | |||
5244 | while (cnt > 0) { | ||
5245 | if (instance-> | ||
5246 | flags & ME4600_AO_FLAGS_BROKEN_PIPE) { | ||
5247 | PERROR | ||
5248 | ("ME4600:Broken pipe in nonblocking write.\n"); | ||
5249 | err = ME_ERRNO_SUBDEVICE_NOT_RUNNING; | ||
5250 | goto ERROR; | ||
5251 | } | ||
5252 | |||
5253 | c = me_circ_buf_space_to_end(&instance-> | ||
5254 | circ_buf); | ||
5255 | |||
5256 | if (!c) { | ||
5257 | PDEBUG | ||
5258 | ("Returning from nonblocking write.\n"); | ||
5259 | break; | ||
5260 | } | ||
5261 | |||
5262 | PDEBUG("Space to end = %d.\n", c); | ||
5263 | |||
5264 | /* Only able to write size of free buffer or size of count */ | ||
5265 | |||
5266 | if (cnt < c) | ||
5267 | c = cnt; | ||
5268 | k = sizeof(int) * c; | ||
5269 | k -= copy_from_user(instance->circ_buf.buf + | ||
5270 | instance->circ_buf.head, | ||
5271 | values, k); | ||
5272 | c = k / sizeof(int); | ||
5273 | |||
5274 | PDEBUG("Copy %d values from user space.\n", c); | ||
5275 | |||
5276 | if (!c) { | ||
5277 | PERROR | ||
5278 | ("Cannot copy values from user space.\n"); | ||
5279 | err = ME_ERRNO_INTERNAL; | ||
5280 | goto ERROR; | ||
5281 | } | ||
5282 | |||
5283 | instance->circ_buf.head = | ||
5284 | (instance->circ_buf.head + | ||
5285 | c) & (instance->circ_buf.mask); | ||
5286 | |||
5287 | values += c; | ||
5288 | cnt -= c; | ||
5289 | ret += c; | ||
5290 | |||
5291 | /* Values are now available so enable interrupts */ | ||
5292 | spin_lock_irqsave(&instance->subdevice_lock, | ||
5293 | cpu_flags); | ||
5294 | |||
5295 | if (me_circ_buf_space(&instance->circ_buf)) { | ||
5296 | tmp = inl(instance->ctrl_reg); | ||
5297 | tmp |= ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
5298 | outl(tmp, instance->ctrl_reg); | ||
5299 | } | ||
5300 | |||
5301 | spin_unlock_irqrestore(&instance-> | ||
5302 | subdevice_lock, | ||
5303 | cpu_flags); | ||
5304 | } | ||
5305 | |||
5306 | *count = ret; | ||
5307 | |||
5308 | break; | ||
5309 | |||
5310 | case ME_WRITE_MODE_PRELOAD: | ||
5311 | PDEBUG("Write for preload continuous mode.\n"); | ||
5312 | |||
5313 | if ((inl(instance->status_reg) & | ||
5314 | ME4600_AO_STATUS_BIT_FSM)) { | ||
5315 | spin_unlock_irqrestore(&instance-> | ||
5316 | subdevice_lock, | ||
5317 | cpu_flags); | ||
5318 | PERROR | ||
5319 | ("Can't Preload DAC FIFO while conversion is running.\n"); | ||
5320 | err = ME_ERRNO_SUBDEVICE_BUSY; | ||
5321 | goto ERROR; | ||
5322 | } | ||
5323 | |||
5324 | tmp = inl(instance->ctrl_reg); | ||
5325 | |||
5326 | tmp |= | ||
5327 | ME4600_AO_CTRL_BIT_STOP | | ||
5328 | ME4600_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
5329 | outl(tmp, instance->ctrl_reg); | ||
5330 | tmp &= | ||
5331 | ~(ME4600_AO_CTRL_BIT_ENABLE_FIFO | | ||
5332 | ME4600_AO_CTRL_BIT_ENABLE_IRQ); | ||
5333 | outl(tmp, instance->ctrl_reg); | ||
5334 | tmp |= ME4600_AO_CTRL_BIT_ENABLE_FIFO; | ||
5335 | outl(tmp, instance->ctrl_reg); | ||
5336 | |||
5337 | instance->circ_buf.head = 0; | ||
5338 | instance->circ_buf.tail = 0; | ||
5339 | instance->flags &= ~ME4600_AO_FLAGS_BROKEN_PIPE; | ||
5340 | |||
5341 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
5342 | cpu_flags); | ||
5343 | |||
5344 | c = ME4600_AO_FIFO_COUNT; | ||
5345 | |||
5346 | if (cnt < c) | ||
5347 | c = cnt; | ||
5348 | |||
5349 | for (i = 0; i < c; i++) { | ||
5350 | if (get_user(value, values)) { | ||
5351 | PERROR | ||
5352 | ("Can't copy value from user space.\n"); | ||
5353 | err = ME_ERRNO_INTERNAL; | ||
5354 | goto ERROR; | ||
5355 | } | ||
5356 | |||
5357 | if (instance->ao_idx & 0x1) | ||
5358 | value <<= 16; | ||
5359 | |||
5360 | outl(value, instance->fifo_reg); | ||
5361 | |||
5362 | values++; | ||
5363 | } | ||
5364 | |||
5365 | cnt -= c; | ||
5366 | |||
5367 | ret += c; | ||
5368 | |||
5369 | PDEBUG("Wrote %d values to fifo.\n", c); | ||
5370 | |||
5371 | while (1) { | ||
5372 | c = me_circ_buf_space_to_end(&instance-> | ||
5373 | circ_buf); | ||
5374 | |||
5375 | if (c == 0) | ||
5376 | break; | ||
5377 | |||
5378 | if (cnt < c) | ||
5379 | c = cnt; | ||
5380 | |||
5381 | if (c <= 0) | ||
5382 | break; | ||
5383 | |||
5384 | k = sizeof(int) * c; | ||
5385 | |||
5386 | k -= copy_from_user(instance->circ_buf.buf + | ||
5387 | instance->circ_buf.head, | ||
5388 | values, k); | ||
5389 | |||
5390 | c = k / sizeof(int); | ||
5391 | |||
5392 | PDEBUG("Wrote %d values to circular buffer.\n", | ||
5393 | c); | ||
5394 | |||
5395 | if (!c) { | ||
5396 | PERROR | ||
5397 | ("Can't copy values from user space.\n"); | ||
5398 | err = ME_ERRNO_INTERNAL; | ||
5399 | goto ERROR; | ||
5400 | } | ||
5401 | |||
5402 | instance->circ_buf.head = | ||
5403 | (instance->circ_buf.head + | ||
5404 | c) & (instance->circ_buf.mask); | ||
5405 | |||
5406 | values += c; | ||
5407 | cnt -= c; | ||
5408 | ret += c; | ||
5409 | } | ||
5410 | |||
5411 | *count = ret; | ||
5412 | |||
5413 | break; | ||
5414 | |||
5415 | default: | ||
5416 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
5417 | cpu_flags); | ||
5418 | |||
5419 | PERROR("Invalid write mode specified.\n"); | ||
5420 | |||
5421 | err = ME_ERRNO_INVALID_WRITE_MODE; | ||
5422 | |||
5423 | goto ERROR; | ||
5424 | } | ||
5425 | |||
5426 | break; | ||
5427 | |||
5428 | default: // Single mode of invalid | ||
5429 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
5430 | PERROR("Subdevice is configured in single mode.\n"); | ||
5431 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
5432 | goto ERROR; | ||
5433 | } | ||
5434 | |||
5435 | ERROR: | ||
5436 | |||
5437 | ME_SUBDEVICE_EXIT; | ||
5438 | |||
5439 | return err; | ||
5440 | } | ||
5441 | |||
5442 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) | ||
5443 | static irqreturn_t me4600_ao_isr(int irq, void *dev_id) | ||
5444 | #else | ||
5445 | static irqreturn_t me4600_ao_isr(int irq, void *dev_id, struct pt_regs *regs) | ||
5446 | #endif | ||
5447 | { | ||
5448 | unsigned long tmp; | ||
5449 | int value; | ||
5450 | me4600_ao_subdevice_t *instance = dev_id; | ||
5451 | int i; | ||
5452 | int c = 0; | ||
5453 | int c1 = 0; | ||
5454 | |||
5455 | if (irq != instance->irq) { | ||
5456 | PDEBUG("Incorrect interrupt num: %d.\n", irq); | ||
5457 | return IRQ_NONE; | ||
5458 | } | ||
5459 | |||
5460 | if (!((0x1 << (instance->ao_idx + 3)) & inl(instance->irq_status_reg))) { | ||
5461 | return IRQ_NONE; | ||
5462 | } | ||
5463 | |||
5464 | PDEBUG("executed.\n"); | ||
5465 | |||
5466 | tmp = inl(instance->status_reg); | ||
5467 | |||
5468 | if (!(tmp & ME4600_AO_STATUS_BIT_EF) && | ||
5469 | (tmp & ME4600_AO_STATUS_BIT_HF) && | ||
5470 | (tmp & ME4600_AO_STATUS_BIT_HF)) { | ||
5471 | c = ME4600_AO_FIFO_COUNT; | ||
5472 | PDEBUG("Fifo empty.\n"); | ||
5473 | } else if ((tmp & ME4600_AO_STATUS_BIT_EF) && | ||
5474 | (tmp & ME4600_AO_STATUS_BIT_HF) && | ||
5475 | (tmp & ME4600_AO_STATUS_BIT_HF)) { | ||
5476 | c = ME4600_AO_FIFO_COUNT / 2; | ||
5477 | PDEBUG("Fifo under half full.\n"); | ||
5478 | } else { | ||
5479 | c = 0; | ||
5480 | PDEBUG("Fifo full.\n"); | ||
5481 | } | ||
5482 | |||
5483 | PDEBUG("Try to write 0x%04X values.\n", c); | ||
5484 | |||
5485 | if ((instance->flags & ME4600_AO_FLAGS_SW_WRAP_MODE_MASK) == | ||
5486 | ME4600_AO_FLAGS_SW_WRAP_MODE_INF) { | ||
5487 | while (c) { | ||
5488 | c1 = c; | ||
5489 | |||
5490 | if (c1 > (instance->circ_buf.head - instance->circ_buf.tail)) /* Only up to the end of the buffer */ | ||
5491 | c1 = (instance->circ_buf.head - | ||
5492 | instance->circ_buf.tail); | ||
5493 | |||
5494 | /* Write the values to the FIFO */ | ||
5495 | for (i = 0; i < c1; i++, instance->circ_buf.tail++, c--) { | ||
5496 | if (instance->ao_idx & 0x1) | ||
5497 | outl(instance->circ_buf. | ||
5498 | buf[instance->circ_buf.tail] << 16, | ||
5499 | instance->fifo_reg); | ||
5500 | else | ||
5501 | outl(instance->circ_buf. | ||
5502 | buf[instance->circ_buf.tail], | ||
5503 | instance->fifo_reg); | ||
5504 | } | ||
5505 | |||
5506 | if (instance->circ_buf.tail >= instance->circ_buf.head) /* Start from beginning */ | ||
5507 | instance->circ_buf.tail = 0; | ||
5508 | } | ||
5509 | |||
5510 | spin_lock(&instance->subdevice_lock); | ||
5511 | |||
5512 | tmp = inl(instance->ctrl_reg); | ||
5513 | tmp |= ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
5514 | outl(tmp, instance->ctrl_reg); | ||
5515 | tmp &= ~ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
5516 | outl(tmp, instance->ctrl_reg); | ||
5517 | |||
5518 | if (!(inl(instance->status_reg) & ME4600_AO_STATUS_BIT_FSM)) { | ||
5519 | PERROR("Broken pipe.\n"); | ||
5520 | instance->flags |= ME4600_AO_FLAGS_BROKEN_PIPE; | ||
5521 | tmp &= ~ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
5522 | outl(tmp, instance->ctrl_reg); | ||
5523 | } | ||
5524 | |||
5525 | spin_unlock(&instance->subdevice_lock); | ||
5526 | } else if ((instance->flags & ME4600_AO_FLAGS_SW_WRAP_MODE_MASK) == | ||
5527 | ME4600_AO_FLAGS_SW_WRAP_MODE_FIN) { | ||
5528 | while (c && instance->wrap_remaining) { | ||
5529 | c1 = c; | ||
5530 | |||
5531 | if (c1 > (instance->circ_buf.head - instance->circ_buf.tail)) /* Only up to the end of the buffer */ | ||
5532 | c1 = (instance->circ_buf.head - | ||
5533 | instance->circ_buf.tail); | ||
5534 | |||
5535 | if (c1 > instance->wrap_remaining) /* Only up to count of user defined number of values */ | ||
5536 | c1 = instance->wrap_remaining; | ||
5537 | |||
5538 | /* Write the values to the FIFO */ | ||
5539 | for (i = 0; i < c1; | ||
5540 | i++, instance->circ_buf.tail++, c--, | ||
5541 | instance->wrap_remaining--) { | ||
5542 | if (instance->ao_idx & 0x1) | ||
5543 | outl(instance->circ_buf. | ||
5544 | buf[instance->circ_buf.tail] << 16, | ||
5545 | instance->fifo_reg); | ||
5546 | else | ||
5547 | outl(instance->circ_buf. | ||
5548 | buf[instance->circ_buf.tail], | ||
5549 | instance->fifo_reg); | ||
5550 | } | ||
5551 | |||
5552 | if (instance->circ_buf.tail >= instance->circ_buf.head) /* Start from beginning */ | ||
5553 | instance->circ_buf.tail = 0; | ||
5554 | } | ||
5555 | |||
5556 | spin_lock(&instance->subdevice_lock); | ||
5557 | |||
5558 | tmp = inl(instance->ctrl_reg); | ||
5559 | |||
5560 | if (!instance->wrap_remaining) { | ||
5561 | PDEBUG("Finite SW wraparound done.\n"); | ||
5562 | tmp &= ~ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
5563 | } | ||
5564 | |||
5565 | tmp |= ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
5566 | |||
5567 | outl(tmp, instance->ctrl_reg); | ||
5568 | tmp &= ~ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
5569 | outl(tmp, instance->ctrl_reg); | ||
5570 | |||
5571 | if (!(inl(instance->status_reg) & ME4600_AO_STATUS_BIT_FSM)) { | ||
5572 | PERROR("Broken pipe.\n"); | ||
5573 | instance->flags |= ME4600_AO_FLAGS_BROKEN_PIPE; | ||
5574 | tmp &= ~ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
5575 | outl(tmp, instance->ctrl_reg); | ||
5576 | } | ||
5577 | |||
5578 | spin_unlock(&instance->subdevice_lock); | ||
5579 | |||
5580 | } else { /* Regular continuous mode */ | ||
5581 | |||
5582 | while (1) { | ||
5583 | c1 = me_circ_buf_values_to_end(&instance->circ_buf); | ||
5584 | PDEBUG("Values to end = %d.\n", c1); | ||
5585 | |||
5586 | if (c1 > c) | ||
5587 | c1 = c; | ||
5588 | |||
5589 | if (c1 <= 0) { | ||
5590 | PDEBUG("Work done or buffer empty.\n"); | ||
5591 | break; | ||
5592 | } | ||
5593 | |||
5594 | if (instance->ao_idx & 0x1) { | ||
5595 | for (i = 0; i < c1; i++) { | ||
5596 | value = | ||
5597 | *(instance->circ_buf.buf + | ||
5598 | instance->circ_buf.tail + | ||
5599 | i) << 16; | ||
5600 | outl(value, instance->fifo_reg); | ||
5601 | } | ||
5602 | } else | ||
5603 | outsl(instance->fifo_reg, | ||
5604 | instance->circ_buf.buf + | ||
5605 | instance->circ_buf.tail, c1); | ||
5606 | |||
5607 | instance->circ_buf.tail = | ||
5608 | (instance->circ_buf.tail + | ||
5609 | c1) & (instance->circ_buf.mask); | ||
5610 | |||
5611 | PDEBUG("%d values wrote to port 0x%04X.\n", c1, | ||
5612 | instance->fifo_reg); | ||
5613 | |||
5614 | c -= c1; | ||
5615 | } | ||
5616 | |||
5617 | spin_lock(&instance->subdevice_lock); | ||
5618 | |||
5619 | tmp = inl(instance->ctrl_reg); | ||
5620 | |||
5621 | if (!me_circ_buf_values(&instance->circ_buf)) { | ||
5622 | PDEBUG | ||
5623 | ("Disable Interrupt because no values left in buffer.\n"); | ||
5624 | tmp &= ~ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
5625 | } | ||
5626 | |||
5627 | tmp |= ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
5628 | |||
5629 | outl(tmp, instance->ctrl_reg); | ||
5630 | tmp &= ~ME4600_AO_CTRL_BIT_RESET_IRQ; | ||
5631 | outl(tmp, instance->ctrl_reg); | ||
5632 | |||
5633 | if (!(inl(instance->status_reg) & ME4600_AO_STATUS_BIT_FSM)) { | ||
5634 | PDEBUG("Broken pipe in me4600_ao_isr.\n"); | ||
5635 | instance->flags |= ME4600_AO_FLAGS_BROKEN_PIPE; | ||
5636 | tmp &= ~ME4600_AO_CTRL_BIT_ENABLE_IRQ; | ||
5637 | outl(tmp, instance->ctrl_reg); | ||
5638 | } | ||
5639 | |||
5640 | spin_unlock(&instance->subdevice_lock); | ||
5641 | |||
5642 | wake_up_interruptible(&instance->wait_queue); | ||
5643 | } | ||
5644 | |||
5645 | return IRQ_HANDLED; | ||
5646 | } | ||
5647 | |||
5648 | static void me4600_ao_destructor(struct me_subdevice *subdevice) | ||
5649 | { | ||
5650 | me4600_ao_subdevice_t *instance; | ||
5651 | |||
5652 | PDEBUG("executed.\n"); | ||
5653 | |||
5654 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
5655 | |||
5656 | free_irq(instance->irq, instance); | ||
5657 | kfree(instance->circ_buf.buf); | ||
5658 | me_subdevice_deinit(&instance->base); | ||
5659 | kfree(instance); | ||
5660 | } | ||
5661 | |||
5662 | me4600_ao_subdevice_t *me4600_ao_constructor(uint32_t reg_base, | ||
5663 | spinlock_t * preload_reg_lock, | ||
5664 | uint32_t * preload_flags, | ||
5665 | int ao_idx, int fifo, int irq) | ||
5666 | { | ||
5667 | me4600_ao_subdevice_t *subdevice; | ||
5668 | int err; | ||
5669 | |||
5670 | PDEBUG("executed.\n"); | ||
5671 | |||
5672 | /* Allocate memory for subdevice instance */ | ||
5673 | subdevice = kmalloc(sizeof(me4600_ao_subdevice_t), GFP_KERNEL); | ||
5674 | |||
5675 | if (!subdevice) { | ||
5676 | PERROR("Cannot get memory for subdevice instance.\n"); | ||
5677 | return NULL; | ||
5678 | } | ||
5679 | |||
5680 | memset(subdevice, 0, sizeof(me4600_ao_subdevice_t)); | ||
5681 | |||
5682 | /* Initialize subdevice base class */ | ||
5683 | err = me_subdevice_init(&subdevice->base); | ||
5684 | |||
5685 | if (err) { | ||
5686 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
5687 | kfree(subdevice); | ||
5688 | return NULL; | ||
5689 | } | ||
5690 | // Initialize spin locks. | ||
5691 | spin_lock_init(&subdevice->subdevice_lock); | ||
5692 | |||
5693 | subdevice->preload_reg_lock = preload_reg_lock; | ||
5694 | subdevice->preload_flags = preload_flags; | ||
5695 | |||
5696 | /* Allocate and initialize circular buffer */ | ||
5697 | subdevice->circ_buf.mask = ME4600_AO_CIRC_BUF_COUNT - 1; | ||
5698 | subdevice->circ_buf.buf = kmalloc(ME4600_AO_CIRC_BUF_SIZE, GFP_KERNEL); | ||
5699 | |||
5700 | if (!subdevice->circ_buf.buf) { | ||
5701 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
5702 | me_subdevice_deinit((me_subdevice_t *) subdevice); | ||
5703 | kfree(subdevice); | ||
5704 | return NULL; | ||
5705 | } | ||
5706 | |||
5707 | memset(subdevice->circ_buf.buf, 0, ME4600_AO_CIRC_BUF_SIZE); | ||
5708 | |||
5709 | subdevice->circ_buf.head = 0; | ||
5710 | subdevice->circ_buf.tail = 0; | ||
5711 | |||
5712 | /* Initialize wait queue */ | ||
5713 | init_waitqueue_head(&subdevice->wait_queue); | ||
5714 | |||
5715 | /* Initialize single value to 0V */ | ||
5716 | subdevice->single_value = 0x8000; | ||
5717 | |||
5718 | /* Store analog output index */ | ||
5719 | subdevice->ao_idx = ao_idx; | ||
5720 | |||
5721 | /* Store if analog output has fifo */ | ||
5722 | subdevice->fifo = fifo; | ||
5723 | |||
5724 | /* Initialize registers */ | ||
5725 | |||
5726 | if (ao_idx == 0) { | ||
5727 | subdevice->ctrl_reg = reg_base + ME4600_AO_00_CTRL_REG; | ||
5728 | subdevice->status_reg = reg_base + ME4600_AO_00_STATUS_REG; | ||
5729 | subdevice->fifo_reg = reg_base + ME4600_AO_00_FIFO_REG; | ||
5730 | subdevice->single_reg = reg_base + ME4600_AO_00_SINGLE_REG; | ||
5731 | subdevice->timer_reg = reg_base + ME4600_AO_00_TIMER_REG; | ||
5732 | subdevice->reg_base = reg_base; | ||
5733 | |||
5734 | if (inl(subdevice->reg_base + ME4600_AO_BOSCH_REG) == 0x20000) { | ||
5735 | PINFO("Bosch firmware in use for channel 0.\n"); | ||
5736 | subdevice->bosch_fw = 1; | ||
5737 | } else { | ||
5738 | subdevice->bosch_fw = 0; | ||
5739 | } | ||
5740 | } else if (ao_idx == 1) { | ||
5741 | subdevice->ctrl_reg = reg_base + ME4600_AO_01_CTRL_REG; | ||
5742 | subdevice->status_reg = reg_base + ME4600_AO_01_STATUS_REG; | ||
5743 | subdevice->fifo_reg = reg_base + ME4600_AO_01_FIFO_REG; | ||
5744 | subdevice->single_reg = reg_base + ME4600_AO_01_SINGLE_REG; | ||
5745 | subdevice->timer_reg = reg_base + ME4600_AO_01_TIMER_REG; | ||
5746 | subdevice->reg_base = reg_base; | ||
5747 | subdevice->bosch_fw = 0; | ||
5748 | } else if (ao_idx == 2) { | ||
5749 | subdevice->ctrl_reg = reg_base + ME4600_AO_02_CTRL_REG; | ||
5750 | subdevice->status_reg = reg_base + ME4600_AO_02_STATUS_REG; | ||
5751 | subdevice->fifo_reg = reg_base + ME4600_AO_02_FIFO_REG; | ||
5752 | subdevice->single_reg = reg_base + ME4600_AO_02_SINGLE_REG; | ||
5753 | subdevice->timer_reg = reg_base + ME4600_AO_02_TIMER_REG; | ||
5754 | subdevice->reg_base = reg_base; | ||
5755 | subdevice->bosch_fw = 0; | ||
5756 | } else { | ||
5757 | subdevice->ctrl_reg = reg_base + ME4600_AO_03_CTRL_REG; | ||
5758 | subdevice->status_reg = reg_base + ME4600_AO_03_STATUS_REG; | ||
5759 | subdevice->fifo_reg = reg_base + ME4600_AO_03_FIFO_REG; | ||
5760 | subdevice->single_reg = reg_base + ME4600_AO_03_SINGLE_REG; | ||
5761 | subdevice->timer_reg = reg_base + ME4600_AO_03_TIMER_REG; | ||
5762 | subdevice->reg_base = reg_base; | ||
5763 | subdevice->bosch_fw = 0; | ||
5764 | } | ||
5765 | |||
5766 | subdevice->irq_status_reg = reg_base + ME4600_IRQ_STATUS_REG; | ||
5767 | subdevice->preload_reg = reg_base + ME4600_AO_LOADSETREG_XX; | ||
5768 | |||
5769 | /* Register interrupt service routine */ | ||
5770 | subdevice->irq = irq; | ||
5771 | |||
5772 | if (request_irq | ||
5773 | (subdevice->irq, me4600_ao_isr, SA_INTERRUPT | SA_SHIRQ, | ||
5774 | ME4600_NAME, subdevice)) { | ||
5775 | PERROR("Cannot get interrupt line.\n"); | ||
5776 | me_subdevice_deinit((me_subdevice_t *) subdevice); | ||
5777 | kfree(subdevice->circ_buf.buf); | ||
5778 | kfree(subdevice); | ||
5779 | return NULL; | ||
5780 | } | ||
5781 | |||
5782 | /* Override base class methods. */ | ||
5783 | subdevice->base.me_subdevice_destructor = me4600_ao_destructor; | ||
5784 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
5785 | me4600_ao_io_reset_subdevice; | ||
5786 | subdevice->base.me_subdevice_io_single_config = | ||
5787 | me4600_ao_io_single_config; | ||
5788 | subdevice->base.me_subdevice_io_single_read = me4600_ao_io_single_read; | ||
5789 | subdevice->base.me_subdevice_io_single_write = | ||
5790 | me4600_ao_io_single_write; | ||
5791 | subdevice->base.me_subdevice_io_stream_config = | ||
5792 | me4600_ao_io_stream_config; | ||
5793 | subdevice->base.me_subdevice_io_stream_new_values = | ||
5794 | me4600_ao_io_stream_new_values; | ||
5795 | subdevice->base.me_subdevice_io_stream_write = | ||
5796 | me4600_ao_io_stream_write; | ||
5797 | subdevice->base.me_subdevice_io_stream_start = | ||
5798 | me4600_ao_io_stream_start; | ||
5799 | subdevice->base.me_subdevice_io_stream_status = | ||
5800 | me4600_ao_io_stream_status; | ||
5801 | subdevice->base.me_subdevice_io_stream_stop = me4600_ao_io_stream_stop; | ||
5802 | subdevice->base.me_subdevice_query_number_channels = | ||
5803 | me4600_ao_query_number_channels; | ||
5804 | subdevice->base.me_subdevice_query_subdevice_type = | ||
5805 | me4600_ao_query_subdevice_type; | ||
5806 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
5807 | me4600_ao_query_subdevice_caps; | ||
5808 | subdevice->base.me_subdevice_query_subdevice_caps_args = | ||
5809 | me4600_ao_query_subdevice_caps_args; | ||
5810 | subdevice->base.me_subdevice_query_range_by_min_max = | ||
5811 | me4600_ao_query_range_by_min_max; | ||
5812 | subdevice->base.me_subdevice_query_number_ranges = | ||
5813 | me4600_ao_query_number_ranges; | ||
5814 | subdevice->base.me_subdevice_query_range_info = | ||
5815 | me4600_ao_query_range_info; | ||
5816 | subdevice->base.me_subdevice_query_timer = me4600_ao_query_timer; | ||
5817 | |||
5818 | return subdevice; | ||
5819 | } | ||
5820 | |||
5821 | #endif // BOSCH | ||
5822 | |||
5823 | /* Common functions | ||
5824 | */ | ||
5825 | |||
5826 | static int me4600_ao_query_range_by_min_max(me_subdevice_t * subdevice, | ||
5827 | int unit, | ||
5828 | int *min, | ||
5829 | int *max, int *maxdata, int *range) | ||
5830 | { | ||
5831 | me4600_ao_subdevice_t *instance; | ||
5832 | |||
5833 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
5834 | |||
5835 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
5836 | |||
5837 | if ((*max - *min) < 0) { | ||
5838 | PERROR("Invalid minimum and maximum values specified.\n"); | ||
5839 | return ME_ERRNO_INVALID_MIN_MAX; | ||
5840 | } | ||
5841 | |||
5842 | if ((unit == ME_UNIT_VOLT) || (unit == ME_UNIT_ANY)) { | ||
5843 | if ((*max <= (ME4600_AO_MAX_RANGE + 1000)) | ||
5844 | && (*min >= ME4600_AO_MIN_RANGE)) { | ||
5845 | *min = ME4600_AO_MIN_RANGE; | ||
5846 | *max = ME4600_AO_MAX_RANGE; | ||
5847 | *maxdata = ME4600_AO_MAX_DATA; | ||
5848 | *range = 0; | ||
5849 | } else { | ||
5850 | PERROR("No matching range available.\n"); | ||
5851 | return ME_ERRNO_NO_RANGE; | ||
5852 | } | ||
5853 | } else { | ||
5854 | PERROR("Invalid physical unit specified.\n"); | ||
5855 | return ME_ERRNO_INVALID_UNIT; | ||
5856 | } | ||
5857 | |||
5858 | return ME_ERRNO_SUCCESS; | ||
5859 | } | ||
5860 | |||
5861 | static int me4600_ao_query_number_ranges(me_subdevice_t * subdevice, | ||
5862 | int unit, int *count) | ||
5863 | { | ||
5864 | me4600_ao_subdevice_t *instance; | ||
5865 | |||
5866 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
5867 | |||
5868 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
5869 | |||
5870 | if ((unit == ME_UNIT_VOLT) || (unit == ME_UNIT_ANY)) { | ||
5871 | *count = 1; | ||
5872 | } else { | ||
5873 | *count = 0; | ||
5874 | } | ||
5875 | |||
5876 | return ME_ERRNO_SUCCESS; | ||
5877 | } | ||
5878 | |||
5879 | static int me4600_ao_query_range_info(me_subdevice_t * subdevice, | ||
5880 | int range, | ||
5881 | int *unit, | ||
5882 | int *min, int *max, int *maxdata) | ||
5883 | { | ||
5884 | me4600_ao_subdevice_t *instance; | ||
5885 | |||
5886 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
5887 | |||
5888 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
5889 | |||
5890 | if (range == 0) { | ||
5891 | *unit = ME_UNIT_VOLT; | ||
5892 | *min = ME4600_AO_MIN_RANGE; | ||
5893 | *max = ME4600_AO_MAX_RANGE; | ||
5894 | *maxdata = ME4600_AO_MAX_DATA; | ||
5895 | } else { | ||
5896 | PERROR("Invalid range number specified.\n"); | ||
5897 | return ME_ERRNO_INVALID_RANGE; | ||
5898 | } | ||
5899 | |||
5900 | return ME_ERRNO_SUCCESS; | ||
5901 | } | ||
5902 | |||
5903 | static int me4600_ao_query_timer(me_subdevice_t * subdevice, | ||
5904 | int timer, | ||
5905 | int *base_frequency, | ||
5906 | long long *min_ticks, long long *max_ticks) | ||
5907 | { | ||
5908 | me4600_ao_subdevice_t *instance; | ||
5909 | |||
5910 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
5911 | |||
5912 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
5913 | |||
5914 | if ((timer != ME_TIMER_ACQ_START) && (timer != ME_TIMER_CONV_START)) { | ||
5915 | PERROR("Invalid timer specified.\n"); | ||
5916 | return ME_ERRNO_INVALID_TIMER; | ||
5917 | } | ||
5918 | |||
5919 | if (instance->fifo) { //Streaming device. | ||
5920 | *base_frequency = ME4600_AO_BASE_FREQUENCY; | ||
5921 | if (timer == ME_TIMER_ACQ_START) { | ||
5922 | *min_ticks = ME4600_AO_MIN_ACQ_TICKS; | ||
5923 | *max_ticks = ME4600_AO_MAX_ACQ_TICKS; | ||
5924 | } else if (timer == ME_TIMER_CONV_START) { | ||
5925 | *min_ticks = ME4600_AO_MIN_CHAN_TICKS; | ||
5926 | *max_ticks = ME4600_AO_MAX_CHAN_TICKS; | ||
5927 | } | ||
5928 | } else { //Not streaming device! | ||
5929 | *base_frequency = 0; | ||
5930 | *min_ticks = 0; | ||
5931 | *max_ticks = 0; | ||
5932 | } | ||
5933 | |||
5934 | return ME_ERRNO_SUCCESS; | ||
5935 | } | ||
5936 | |||
5937 | static int me4600_ao_query_number_channels(me_subdevice_t * subdevice, | ||
5938 | int *number) | ||
5939 | { | ||
5940 | me4600_ao_subdevice_t *instance; | ||
5941 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
5942 | |||
5943 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
5944 | |||
5945 | *number = 1; | ||
5946 | |||
5947 | return ME_ERRNO_SUCCESS; | ||
5948 | } | ||
5949 | |||
5950 | static int me4600_ao_query_subdevice_type(me_subdevice_t * subdevice, | ||
5951 | int *type, int *subtype) | ||
5952 | { | ||
5953 | me4600_ao_subdevice_t *instance; | ||
5954 | |||
5955 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
5956 | |||
5957 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
5958 | |||
5959 | *type = ME_TYPE_AO; | ||
5960 | *subtype = (instance->fifo) ? ME_SUBTYPE_STREAMING : ME_SUBTYPE_SINGLE; | ||
5961 | |||
5962 | return ME_ERRNO_SUCCESS; | ||
5963 | } | ||
5964 | |||
5965 | static int me4600_ao_query_subdevice_caps(me_subdevice_t * subdevice, int *caps) | ||
5966 | { | ||
5967 | me4600_ao_subdevice_t *instance; | ||
5968 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
5969 | |||
5970 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
5971 | |||
5972 | *caps = | ||
5973 | ME_CAPS_AO_TRIG_SYNCHRONOUS | ((instance->fifo) ? ME_CAPS_AO_FIFO : | ||
5974 | ME_CAPS_NONE); | ||
5975 | |||
5976 | return ME_ERRNO_SUCCESS; | ||
5977 | } | ||
5978 | |||
5979 | static int me4600_ao_query_subdevice_caps_args(struct me_subdevice *subdevice, | ||
5980 | int cap, int *args, int count) | ||
5981 | { | ||
5982 | me4600_ao_subdevice_t *instance; | ||
5983 | int err = ME_ERRNO_SUCCESS; | ||
5984 | |||
5985 | instance = (me4600_ao_subdevice_t *) subdevice; | ||
5986 | |||
5987 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
5988 | |||
5989 | if (count != 1) { | ||
5990 | PERROR("Invalid capability argument count.\n"); | ||
5991 | return ME_ERRNO_INVALID_CAP_ARG_COUNT; | ||
5992 | } | ||
5993 | |||
5994 | switch (cap) { | ||
5995 | case ME_CAP_AI_FIFO_SIZE: | ||
5996 | args[0] = (instance->fifo) ? ME4600_AO_FIFO_COUNT : 0; | ||
5997 | break; | ||
5998 | |||
5999 | case ME_CAP_AI_BUFFER_SIZE: | ||
6000 | args[0] = | ||
6001 | (instance->circ_buf.buf) ? ME4600_AO_CIRC_BUF_COUNT : 0; | ||
6002 | break; | ||
6003 | |||
6004 | default: | ||
6005 | PERROR("Invalid capability.\n"); | ||
6006 | err = ME_ERRNO_INVALID_CAP; | ||
6007 | args[0] = 0; | ||
6008 | } | ||
6009 | |||
6010 | return err; | ||
6011 | } | ||
diff --git a/drivers/staging/meilhaus/me4600_ao.h b/drivers/staging/meilhaus/me4600_ao.h new file mode 100644 index 000000000000..6fbc4a2dd9dd --- /dev/null +++ b/drivers/staging/meilhaus/me4600_ao.h | |||
@@ -0,0 +1,263 @@ | |||
1 | /** | ||
2 | * @file me4600_ao.h | ||
3 | * | ||
4 | * @brief Meilhaus ME-4000 analog output subdevice class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME4600_AO_H_ | ||
28 | # define _ME4600_AO_H_ | ||
29 | |||
30 | # include <linux/version.h> | ||
31 | # include "mesubdevice.h" | ||
32 | # include "mecirc_buf.h" | ||
33 | # include "meioctl.h" | ||
34 | |||
35 | # ifdef __KERNEL__ | ||
36 | |||
37 | # ifdef BOSCH | ||
38 | # undef ME_SYNAPSE | ||
39 | # ifndef _CBUFF_32b_t | ||
40 | # define _CBUFF_32b_t | ||
41 | # endif //_CBUFF_32b_t | ||
42 | # endif //BOSCH | ||
43 | |||
44 | # define ME4600_AO_MAX_SUBDEVICES 4 | ||
45 | # define ME4600_AO_FIFO_COUNT 4096 | ||
46 | |||
47 | # define ME4600_AO_BASE_FREQUENCY 33000000LL | ||
48 | |||
49 | # define ME4600_AO_MIN_ACQ_TICKS 0LL | ||
50 | # define ME4600_AO_MAX_ACQ_TICKS 0LL | ||
51 | |||
52 | # define ME4600_AO_MIN_CHAN_TICKS 66LL | ||
53 | # define ME4600_AO_MAX_CHAN_TICKS 0xFFFFFFFFLL | ||
54 | |||
55 | # define ME4600_AO_MIN_RANGE -10000000 | ||
56 | # define ME4600_AO_MAX_RANGE 9999694 | ||
57 | |||
58 | # define ME4600_AO_MAX_DATA 0xFFFF | ||
59 | |||
60 | # ifdef ME_SYNAPSE | ||
61 | # define ME4600_AO_CIRC_BUF_SIZE_ORDER 8 // 2^n PAGES =>> Maximum value of 1MB for Synapse | ||
62 | # else | ||
63 | # define ME4600_AO_CIRC_BUF_SIZE_ORDER 5 // 2^n PAGES =>> 128KB | ||
64 | # endif | ||
65 | # define ME4600_AO_CIRC_BUF_SIZE PAGE_SIZE<<ME4600_AO_CIRC_BUF_SIZE_ORDER // Buffer size in bytes. | ||
66 | |||
67 | # ifdef _CBUFF_32b_t | ||
68 | # define ME4600_AO_CIRC_BUF_COUNT ((ME4600_AO_CIRC_BUF_SIZE) / sizeof(uint32_t)) // Size in values | ||
69 | # else | ||
70 | # define ME4600_AO_CIRC_BUF_COUNT ((ME4600_AO_CIRC_BUF_SIZE) / sizeof(uint16_t)) // Size in values | ||
71 | # endif | ||
72 | |||
73 | # define ME4600_AO_CONTINOUS 0x0 | ||
74 | # define ME4600_AO_WRAP_MODE 0x1 | ||
75 | # define ME4600_AO_HW_MODE 0x2 | ||
76 | |||
77 | # define ME4600_AO_HW_WRAP_MODE (ME4600_AO_WRAP_MODE | ME4600_AO_HW_MODE) | ||
78 | # define ME4600_AO_SW_WRAP_MODE ME4600_AO_WRAP_MODE | ||
79 | |||
80 | # define ME4600_AO_INF_STOP_MODE 0x0 | ||
81 | # define ME4600_AO_ACQ_STOP_MODE 0x1 | ||
82 | # define ME4600_AO_SCAN_STOP_MODE 0x2 | ||
83 | |||
84 | # ifdef BOSCH //SPECIAL BUILD FOR BOSCH | ||
85 | |||
86 | /* Bits for flags attribute. */ | ||
87 | # define ME4600_AO_FLAGS_BROKEN_PIPE 0x1 | ||
88 | # define ME4600_AO_FLAGS_SW_WRAP_MODE_0 0x2 | ||
89 | # define ME4600_AO_FLAGS_SW_WRAP_MODE_1 0x4 | ||
90 | # define ME4600_AO_FLAGS_SW_WRAP_MODE_MASK (ME4600_AO_FLAGS_SW_WRAP_MODE_0 | ME4600_AO_FLAGS_SW_WRAP_MODE_1) | ||
91 | |||
92 | # define ME4600_AO_FLAGS_SW_WRAP_MODE_NONE 0x0 | ||
93 | # define ME4600_AO_FLAGS_SW_WRAP_MODE_INF 0x2 | ||
94 | # define ME4600_AO_FLAGS_SW_WRAP_MODE_FIN 0x4 | ||
95 | |||
96 | /** | ||
97 | * @brief The ME-4000 analog output subdevice class. | ||
98 | */ | ||
99 | typedef struct me4600_ao_subdevice { | ||
100 | /* Inheritance */ | ||
101 | me_subdevice_t base; /**< The subdevice base class. */ | ||
102 | |||
103 | /* Attributes */ | ||
104 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
105 | spinlock_t *preload_reg_lock; /**< Spin lock to protect #preload_reg from concurrent access. */ | ||
106 | uint32_t *preload_flags; | ||
107 | |||
108 | unsigned int irq; /**< The interrupt request number assigned by the PCI BIOS. */ | ||
109 | me_circ_buf_t circ_buf; /**< Circular buffer holding measurment data. */ | ||
110 | wait_queue_head_t wait_queue; /**< Wait queue to put on tasks waiting for data to arrive. */ | ||
111 | |||
112 | int single_value; /**< Mirror of the value written in single mode. */ | ||
113 | |||
114 | int volatile flags; /**< Flags used for storing SW wraparound setup and error signalling from ISR. */ | ||
115 | unsigned int wrap_count; /**< The user defined wraparound cycle count. */ | ||
116 | unsigned int wrap_remaining; /**< The wraparound cycle down counter used by a running conversion. */ | ||
117 | unsigned int ao_idx; /**< The index of this analog output on this device. */ | ||
118 | int fifo; /**< If set this device has a FIFO. */ | ||
119 | |||
120 | int bosch_fw; /**< If set the bosch firmware is in PROM. */ | ||
121 | |||
122 | /* Registers */ | ||
123 | uint32_t ctrl_reg; | ||
124 | uint32_t status_reg; | ||
125 | uint32_t fifo_reg; | ||
126 | uint32_t single_reg; | ||
127 | uint32_t timer_reg; | ||
128 | uint32_t irq_status_reg; | ||
129 | uint32_t preload_reg; | ||
130 | uint32_t reg_base; | ||
131 | } me4600_ao_subdevice_t; | ||
132 | |||
133 | /** | ||
134 | * @brief The constructor to generate a ME-4000 analog output subdevice instance for BOSCH project. | ||
135 | * | ||
136 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
137 | * @param ctrl_reg_lock Pointer to spin lock protecting the control register from concurrent access. | ||
138 | * @param preload_flags Pointer to spin lock protecting the hold&trigger register from concurrent access. | ||
139 | * @param ao_idx Subdevice number. | ||
140 | * @param fifo Flag set if subdevice has hardware FIFO. | ||
141 | * @param irq IRQ number. | ||
142 | * | ||
143 | * @return Pointer to new instance on success.\n | ||
144 | * NULL on error. | ||
145 | */ | ||
146 | me4600_ao_subdevice_t *me4600_ao_constructor(uint32_t reg_base, | ||
147 | spinlock_t * preload_reg_lock, | ||
148 | uint32_t * preload_flags, | ||
149 | int ao_idx, int fifo, int irq); | ||
150 | |||
151 | # else //~BOSCH | ||
152 | |||
153 | //ME4600_AO_FLAGS_BROKEN_PIPE is OBSOLETE => Now problems are reported in status. | ||
154 | |||
155 | typedef enum ME4600_AO_STATUS { | ||
156 | ao_status_none = 0, | ||
157 | ao_status_single_configured, | ||
158 | ao_status_single_run_wait, | ||
159 | ao_status_single_run, | ||
160 | ao_status_single_end_wait, | ||
161 | ao_status_single_end, | ||
162 | ao_status_stream_configured, | ||
163 | ao_status_stream_run_wait, | ||
164 | ao_status_stream_run, | ||
165 | ao_status_stream_end_wait, | ||
166 | ao_status_stream_end, | ||
167 | ao_status_stream_fifo_error, | ||
168 | ao_status_stream_buffer_error, | ||
169 | ao_status_stream_error, | ||
170 | ao_status_last | ||
171 | } ME4600_AO_STATUS; | ||
172 | |||
173 | typedef struct me4600_ao_timeout { | ||
174 | unsigned long start_time; | ||
175 | unsigned long delay; | ||
176 | } me4600_ao_timeout_t; | ||
177 | |||
178 | /** | ||
179 | * @brief The ME-4600 analog output subdevice class. | ||
180 | */ | ||
181 | typedef struct me4600_ao_subdevice { | ||
182 | /* Inheritance */ | ||
183 | me_subdevice_t base; /**< The subdevice base class. */ | ||
184 | unsigned int ao_idx; /**< The index of this analog output on this device. */ | ||
185 | |||
186 | /* Attributes */ | ||
187 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
188 | spinlock_t *preload_reg_lock; /**< Spin lock to protect preload_reg from concurrent access. */ | ||
189 | |||
190 | uint32_t *preload_flags; | ||
191 | |||
192 | /* Hardware feautres */ | ||
193 | unsigned int irq; /**< The interrupt request number assigned by the PCI BIOS. */ | ||
194 | int fifo; /**< If set this device has a FIFO. */ | ||
195 | int bitpattern; /**< If set this device use bitpattern. */ | ||
196 | |||
197 | int single_value; /**< Mirror of the output value in single mode. */ | ||
198 | int single_value_in_fifo; /**< Mirror of the value written in single mode. */ | ||
199 | uint32_t ctrl_trg; /**< Mirror of the trigger settings. */ | ||
200 | |||
201 | volatile int mode; /**< Flags used for storing SW wraparound setup*/ | ||
202 | int stop_mode; /**< The user defined stop condition flag. */ | ||
203 | unsigned int start_mode; | ||
204 | unsigned int stop_count; /**< The user defined dates presentation end count. */ | ||
205 | unsigned int stop_data_count; /**< The stop presentation count. */ | ||
206 | unsigned int data_count; /**< The real presentation count. */ | ||
207 | unsigned int preloaded_count; /**< The next data addres in buffer. <= for wraparound mode. */ | ||
208 | int hardware_stop_delay; /**< The time that stop can take. This is only to not show hardware bug to user. */ | ||
209 | |||
210 | volatile enum ME4600_AO_STATUS status; /**< The current stream status flag. */ | ||
211 | me4600_ao_timeout_t timeout; /**< The timeout for start in blocking and non-blocking mode. */ | ||
212 | |||
213 | /* Registers *//**< All registers are 32 bits long. */ | ||
214 | unsigned long ctrl_reg; | ||
215 | unsigned long status_reg; | ||
216 | unsigned long fifo_reg; | ||
217 | unsigned long single_reg; | ||
218 | unsigned long timer_reg; | ||
219 | unsigned long irq_status_reg; | ||
220 | unsigned long preload_reg; | ||
221 | unsigned long reg_base; | ||
222 | |||
223 | /* Software buffer */ | ||
224 | me_circ_buf_t circ_buf; /**< Circular buffer holding measurment data. 32 bit long */ | ||
225 | wait_queue_head_t wait_queue; /**< Wait queue to put on tasks waiting for data to arrive. */ | ||
226 | |||
227 | struct workqueue_struct *me4600_workqueue; | ||
228 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) | ||
229 | struct work_struct ao_control_task; | ||
230 | #else | ||
231 | struct delayed_work ao_control_task; | ||
232 | #endif | ||
233 | |||
234 | volatile int ao_control_task_flag; /**< Flag controling reexecuting of control task */ | ||
235 | |||
236 | } me4600_ao_subdevice_t; | ||
237 | |||
238 | /** | ||
239 | * @brief The constructor to generate a ME-4600 analog output subdevice instance. | ||
240 | * | ||
241 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
242 | * @param ctrl_reg_lock Pointer to spin lock protecting the control register from concurrent access. | ||
243 | * @param preload_flags Pointer to spin lock protecting the hold&trigger register from concurrent access. | ||
244 | * @param ao_idx Subdevice number. | ||
245 | * @param fifo Flag set if subdevice has hardware FIFO. | ||
246 | * @param irq IRQ number. | ||
247 | * @param me4600_wq Queue for asynchronous task (1 queue for all subdevice on 1 board). | ||
248 | * | ||
249 | * @return Pointer to new instance on success.\n | ||
250 | * NULL on error. | ||
251 | */ | ||
252 | me4600_ao_subdevice_t *me4600_ao_constructor(uint32_t reg_base, | ||
253 | spinlock_t * preload_reg_lock, | ||
254 | uint32_t * preload_flags, | ||
255 | int ao_idx, | ||
256 | int fifo, | ||
257 | int irq, | ||
258 | struct workqueue_struct | ||
259 | *me4600_wq); | ||
260 | |||
261 | # endif //BOSCH | ||
262 | # endif //__KERNEL__ | ||
263 | #endif // ~_ME4600_AO_H_ | ||
diff --git a/drivers/staging/meilhaus/me4600_ao_reg.h b/drivers/staging/meilhaus/me4600_ao_reg.h new file mode 100644 index 000000000000..f83d82ecd4bf --- /dev/null +++ b/drivers/staging/meilhaus/me4600_ao_reg.h | |||
@@ -0,0 +1,113 @@ | |||
1 | /** | ||
2 | * @file me4600_ao_reg.h | ||
3 | * | ||
4 | * @brief ME-4000 analog output subdevice register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME4600_AO_REG_H_ | ||
28 | #define _ME4600_AO_REG_H_ | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | #define ME4600_AO_00_CTRL_REG 0x00 // R/W | ||
33 | #define ME4600_AO_00_STATUS_REG 0x04 // R/_ | ||
34 | #define ME4600_AO_00_FIFO_REG 0x08 // _/W | ||
35 | #define ME4600_AO_00_SINGLE_REG 0x0C // R/W | ||
36 | #define ME4600_AO_00_TIMER_REG 0x10 // _/W | ||
37 | |||
38 | #define ME4600_AO_01_CTRL_REG 0x18 // R/W | ||
39 | #define ME4600_AO_01_STATUS_REG 0x1C // R/_ | ||
40 | #define ME4600_AO_01_FIFO_REG 0x20 // _/W | ||
41 | #define ME4600_AO_01_SINGLE_REG 0x24 // R/W | ||
42 | #define ME4600_AO_01_TIMER_REG 0x28 // _/W | ||
43 | |||
44 | #define ME4600_AO_02_CTRL_REG 0x30 // R/W | ||
45 | #define ME4600_AO_02_STATUS_REG 0x34 // R/_ | ||
46 | #define ME4600_AO_02_FIFO_REG 0x38 // _/W | ||
47 | #define ME4600_AO_02_SINGLE_REG 0x3C // R/W | ||
48 | #define ME4600_AO_02_TIMER_REG 0x40 // _/W | ||
49 | |||
50 | #define ME4600_AO_03_CTRL_REG 0x48 // R/W | ||
51 | #define ME4600_AO_03_STATUS_REG 0x4C // R/_ | ||
52 | #define ME4600_AO_03_FIFO_REG 0x50 // _/W | ||
53 | #define ME4600_AO_03_SINGLE_REG 0x54 // R/W | ||
54 | #define ME4600_AO_03_TIMER_REG 0x58 // _/W | ||
55 | |||
56 | #define ME4600_AO_DEMUX_ADJUST_REG 0xBC // -/W | ||
57 | #define ME4600_AO_DEMUX_ADJUST_VALUE 0x4C | ||
58 | |||
59 | #ifdef BOSCH | ||
60 | # define ME4600_AO_BOSCH_REG 0xC4 | ||
61 | |||
62 | # define ME4600_AO_LOADSETREG_XX 0xB4 // R/W | ||
63 | |||
64 | # define ME4600_AO_CTRL_BIT_MODE_0 0x001 | ||
65 | # define ME4600_AO_CTRL_BIT_MODE_1 0x002 | ||
66 | # define ME4600_AO_CTRL_MASK_MODE 0x003 | ||
67 | |||
68 | #else //~BOSCH | ||
69 | |||
70 | #define ME4600_AO_SYNC_REG 0xB4 // R/W ///ME4600_AO_SYNC_REG <==> ME4600_AO_PRELOAD_REG <==> ME4600_AO_LOADSETREG_XX | ||
71 | |||
72 | # define ME4600_AO_MODE_SINGLE 0x00000000 | ||
73 | # define ME4600_AO_MODE_WRAPAROUND 0x00000001 | ||
74 | # define ME4600_AO_MODE_CONTINUOUS 0x00000002 | ||
75 | # define ME4600_AO_CTRL_MODE_MASK (ME4600_AO_MODE_WRAPAROUND | ME4600_AO_MODE_CONTINUOUS) | ||
76 | #endif //BOSCH | ||
77 | |||
78 | #define ME4600_AO_CTRL_BIT_MODE_WRAPAROUND ME4600_AO_MODE_WRAPAROUND | ||
79 | #define ME4600_AO_CTRL_BIT_MODE_CONTINOUS ME4600_AO_MODE_CONTINUOUS | ||
80 | #define ME4600_AO_CTRL_BIT_STOP 0x00000004 | ||
81 | #define ME4600_AO_CTRL_BIT_ENABLE_FIFO 0x00000008 | ||
82 | #define ME4600_AO_CTRL_BIT_ENABLE_EX_TRIG 0x00000010 | ||
83 | #define ME4600_AO_CTRL_BIT_EX_TRIG_EDGE 0x00000020 | ||
84 | #define ME4600_AO_CTRL_BIT_IMMEDIATE_STOP 0x00000080 | ||
85 | #define ME4600_AO_CTRL_BIT_ENABLE_DO 0x00000100 | ||
86 | #define ME4600_AO_CTRL_BIT_ENABLE_IRQ 0x00000200 | ||
87 | #define ME4600_AO_CTRL_BIT_RESET_IRQ 0x00000400 | ||
88 | #define ME4600_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH 0x00000800 | ||
89 | /* | ||
90 | #define ME4600_AO_SYNC_HOLD_0 0x00000001 | ||
91 | #define ME4600_AO_SYNC_HOLD_1 0x00000002 | ||
92 | #define ME4600_AO_SYNC_HOLD_2 0x00000004 | ||
93 | #define ME4600_AO_SYNC_HOLD_3 0x00000008 | ||
94 | */ | ||
95 | #define ME4600_AO_SYNC_HOLD 0x00000001 | ||
96 | |||
97 | /* | ||
98 | #define ME4600_AO_SYNC_EXT_TRIG_0 0x00010000 | ||
99 | #define ME4600_AO_SYNC_EXT_TRIG_1 0x00020000 | ||
100 | #define ME4600_AO_SYNC_EXT_TRIG_2 0x00040000 | ||
101 | #define ME4600_AO_SYNC_EXT_TRIG_3 0x00080000 | ||
102 | */ | ||
103 | #define ME4600_AO_SYNC_EXT_TRIG 0x00010000 | ||
104 | |||
105 | #define ME4600_AO_EXT_TRIG 0x80000000 | ||
106 | |||
107 | #define ME4600_AO_STATUS_BIT_FSM 0x00000001 | ||
108 | #define ME4600_AO_STATUS_BIT_FF 0x00000002 | ||
109 | #define ME4600_AO_STATUS_BIT_HF 0x00000004 | ||
110 | #define ME4600_AO_STATUS_BIT_EF 0x00000008 | ||
111 | |||
112 | #endif | ||
113 | #endif | ||
diff --git a/drivers/staging/meilhaus/me4600_device.c b/drivers/staging/meilhaus/me4600_device.c new file mode 100644 index 000000000000..fa455844f4e3 --- /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); | ||
diff --git a/drivers/staging/meilhaus/me4600_device.h b/drivers/staging/meilhaus/me4600_device.h new file mode 100644 index 000000000000..fa812d4cc6dc --- /dev/null +++ b/drivers/staging/meilhaus/me4600_device.h | |||
@@ -0,0 +1,151 @@ | |||
1 | /** | ||
2 | * @file me4600_device.h | ||
3 | * | ||
4 | * @brief ME-4600 device class. | ||
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 _ME4600_DEVICE_H | ||
29 | #define _ME4600_DEVICE_H | ||
30 | |||
31 | #include <linux/pci.h> | ||
32 | #include <linux/spinlock.h> | ||
33 | |||
34 | #include "medevice.h" | ||
35 | |||
36 | #ifdef __KERNEL__ | ||
37 | |||
38 | /** | ||
39 | * @brief Structure holding ME-4600 device capabilities. | ||
40 | */ | ||
41 | typedef struct me4600_version { | ||
42 | uint16_t device_id; | ||
43 | unsigned int do_subdevices; | ||
44 | unsigned int di_subdevices; | ||
45 | unsigned int dio_subdevices; | ||
46 | unsigned int ctr_subdevices; | ||
47 | unsigned int ai_subdevices; | ||
48 | unsigned int ai_channels; | ||
49 | unsigned int ai_ranges; | ||
50 | unsigned int ai_isolated; | ||
51 | unsigned int ai_sh; | ||
52 | unsigned int ao_subdevices; | ||
53 | unsigned int ao_fifo; //How many devices have FIFO | ||
54 | unsigned int ext_irq_subdevices; | ||
55 | } me4600_version_t; | ||
56 | |||
57 | /** | ||
58 | * @brief ME-4600 device capabilities. | ||
59 | */ | ||
60 | static me4600_version_t me4600_versions[] = { | ||
61 | {PCI_DEVICE_ID_MEILHAUS_ME4610, 0, 0, 4, 3, 1, 16, 1, 0, 0, 0, 0, 1}, | ||
62 | |||
63 | {PCI_DEVICE_ID_MEILHAUS_ME4650, 0, 0, 4, 0, 1, 16, 4, 0, 0, 0, 0, 1}, | ||
64 | |||
65 | {PCI_DEVICE_ID_MEILHAUS_ME4660, 0, 0, 4, 3, 1, 16, 4, 0, 0, 2, 0, 1}, | ||
66 | {PCI_DEVICE_ID_MEILHAUS_ME4660I, 1, 1, 2, 3, 1, 16, 4, 1, 0, 2, 0, 1}, | ||
67 | {PCI_DEVICE_ID_MEILHAUS_ME4660S, 0, 0, 4, 3, 1, 16, 4, 0, 1, 2, 0, 1}, | ||
68 | {PCI_DEVICE_ID_MEILHAUS_ME4660IS, 1, 1, 2, 3, 1, 16, 4, 1, 1, 2, 0, 1}, | ||
69 | |||
70 | {PCI_DEVICE_ID_MEILHAUS_ME4670, 0, 0, 4, 3, 1, 32, 4, 0, 0, 4, 0, 1}, | ||
71 | {PCI_DEVICE_ID_MEILHAUS_ME4670I, 1, 1, 2, 3, 1, 32, 4, 1, 0, 4, 0, 1}, | ||
72 | {PCI_DEVICE_ID_MEILHAUS_ME4670S, 0, 0, 4, 3, 1, 32, 4, 0, 1, 4, 0, 1}, | ||
73 | {PCI_DEVICE_ID_MEILHAUS_ME4670IS, 1, 1, 2, 3, 1, 32, 4, 1, 1, 4, 0, 1}, | ||
74 | |||
75 | {PCI_DEVICE_ID_MEILHAUS_ME4680, 0, 0, 4, 3, 1, 32, 4, 0, 0, 4, 4, 1}, | ||
76 | {PCI_DEVICE_ID_MEILHAUS_ME4680I, 1, 1, 2, 3, 1, 32, 4, 1, 0, 4, 4, 1}, | ||
77 | {PCI_DEVICE_ID_MEILHAUS_ME4680S, 0, 0, 4, 3, 1, 32, 4, 0, 1, 4, 4, 1}, | ||
78 | {PCI_DEVICE_ID_MEILHAUS_ME4680IS, 1, 1, 2, 3, 1, 32, 4, 1, 1, 4, 4, 1}, | ||
79 | |||
80 | {0}, | ||
81 | }; | ||
82 | |||
83 | #define ME4600_DEVICE_VERSIONS (sizeof(me4600_versions) / sizeof(me4600_version_t) - 1) /**< Returns the number of entries in #me4600_versions. */ | ||
84 | |||
85 | /** | ||
86 | * @brief Returns the index of the device entry in #me4600_versions. | ||
87 | * | ||
88 | * @param device_id The PCI device id of the device to query. | ||
89 | * @return The index of the device in #me4600_versions. | ||
90 | */ | ||
91 | static inline unsigned int me4600_versions_get_device_index(uint16_t device_id) | ||
92 | { | ||
93 | unsigned int i; | ||
94 | for (i = 0; i < ME4600_DEVICE_VERSIONS; i++) | ||
95 | if (me4600_versions[i].device_id == device_id) | ||
96 | break; | ||
97 | return i; | ||
98 | } | ||
99 | |||
100 | /** | ||
101 | * @brief The ME-4600 device class structure. | ||
102 | */ | ||
103 | typedef struct me4600_device { | ||
104 | me_device_t base; /**< The Meilhaus device base class. */ | ||
105 | |||
106 | /* Child class attributes. */ | ||
107 | spinlock_t preload_reg_lock; /**< Guards the preload register of the anaolog output devices. */ | ||
108 | unsigned int preload_flags; /**< Used in conjunction with #preload_reg_lock. */ | ||
109 | spinlock_t dio_lock; /**< Locks the control register of the digital input/output subdevices. */ | ||
110 | spinlock_t ai_ctrl_lock; /**< Locks the control register of the analog input subdevice. */ | ||
111 | spinlock_t ctr_ctrl_reg_lock; /**< Locks the counter control register. */ | ||
112 | spinlock_t ctr_clk_src_reg_lock; /**< Not used on this device but needed for the me8254 subdevice constructor call. */ | ||
113 | } me4600_device_t; | ||
114 | |||
115 | /** | ||
116 | * @brief The ME-4600 device class constructor. | ||
117 | * | ||
118 | * @param pci_device The pci device structure given by the PCI subsystem. | ||
119 | * @param me_bosch_fw If set the device shall use the bosch firmware. (Only for special BOSCH build) | ||
120 | * | ||
121 | * @return On succes a new ME-4600 device instance. \n | ||
122 | * NULL on error. | ||
123 | */ | ||
124 | |||
125 | #ifdef BOSCH | ||
126 | /** | ||
127 | * @brief The ME-4600 device class constructor. | ||
128 | * | ||
129 | * @param pci_device The pci device structure given by the PCI subsystem. | ||
130 | * @param me_bosch_fw If set the device shall use the bosch firmware. | ||
131 | * | ||
132 | * @return On succes a new ME-4600 device instance. \n | ||
133 | * NULL on error. | ||
134 | */ | ||
135 | me_device_t *me4600_pci_constructor(struct pci_dev *pci_device, int me_bosch_fw) | ||
136 | __attribute__ ((weak)); | ||
137 | #else //~BOSCH | ||
138 | /** | ||
139 | * @brief The ME-4600 device class constructor. | ||
140 | * | ||
141 | * @param pci_device The pci device structure given by the PCI subsystem. | ||
142 | * | ||
143 | * @return On succes a new ME-4600 device instance. \n | ||
144 | * NULL on error. | ||
145 | */ | ||
146 | me_device_t *me4600_pci_constructor(struct pci_dev *pci_device) | ||
147 | __attribute__ ((weak)); | ||
148 | #endif | ||
149 | |||
150 | #endif | ||
151 | #endif | ||
diff --git a/drivers/staging/meilhaus/me4600_di.c b/drivers/staging/meilhaus/me4600_di.c new file mode 100644 index 000000000000..7e3c9f4d2df2 --- /dev/null +++ b/drivers/staging/meilhaus/me4600_di.c | |||
@@ -0,0 +1,256 @@ | |||
1 | /** | ||
2 | * @file me4600_di.c | ||
3 | * | ||
4 | * @brief ME-4000 digital input subdevice instance. | ||
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 | /* | ||
33 | * Includes | ||
34 | */ | ||
35 | #include <linux/module.h> | ||
36 | |||
37 | #include <linux/slab.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | #include <asm/io.h> | ||
40 | #include <linux/types.h> | ||
41 | |||
42 | #include "medefines.h" | ||
43 | #include "meinternal.h" | ||
44 | #include "meerror.h" | ||
45 | |||
46 | #include "medebug.h" | ||
47 | #include "me4600_dio_reg.h" | ||
48 | #include "me4600_di.h" | ||
49 | |||
50 | /* | ||
51 | * Defines | ||
52 | */ | ||
53 | |||
54 | /* | ||
55 | * Functions | ||
56 | */ | ||
57 | |||
58 | static int me4600_di_io_reset_subdevice(struct me_subdevice *subdevice, | ||
59 | struct file *filep, int flags) | ||
60 | { | ||
61 | me4600_di_subdevice_t *instance; | ||
62 | uint32_t mode; | ||
63 | |||
64 | PDEBUG("executed.\n"); | ||
65 | |||
66 | instance = (me4600_di_subdevice_t *) subdevice; | ||
67 | |||
68 | if (flags) { | ||
69 | PERROR("Invalid flag specified.\n"); | ||
70 | return ME_ERRNO_INVALID_FLAGS; | ||
71 | } | ||
72 | |||
73 | ME_SUBDEVICE_ENTER; | ||
74 | |||
75 | spin_lock(&instance->subdevice_lock); | ||
76 | spin_lock(instance->ctrl_reg_lock); | ||
77 | mode = inl(instance->ctrl_reg); | ||
78 | mode &= ~(ME4600_DIO_CTRL_BIT_MODE_2 | ME4600_DIO_CTRL_BIT_MODE_3); //0xFFF3 | ||
79 | outl(mode, instance->ctrl_reg); | ||
80 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
81 | instance->ctrl_reg - instance->reg_base, mode); | ||
82 | spin_unlock(instance->ctrl_reg_lock); | ||
83 | |||
84 | outl(0, instance->port_reg); | ||
85 | PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
86 | instance->port_reg - instance->reg_base, 0); | ||
87 | spin_unlock(&instance->subdevice_lock); | ||
88 | |||
89 | ME_SUBDEVICE_EXIT; | ||
90 | |||
91 | return ME_ERRNO_SUCCESS; | ||
92 | } | ||
93 | |||
94 | static int me4600_di_io_single_config(me_subdevice_t * subdevice, | ||
95 | struct file *filep, | ||
96 | int channel, | ||
97 | int single_config, | ||
98 | int ref, | ||
99 | int trig_chan, | ||
100 | int trig_type, int trig_edge, int flags) | ||
101 | { | ||
102 | int err = ME_ERRNO_SUCCESS; | ||
103 | me4600_di_subdevice_t *instance; | ||
104 | |||
105 | PDEBUG("executed.\n"); | ||
106 | |||
107 | instance = (me4600_di_subdevice_t *) subdevice; | ||
108 | |||
109 | ME_SUBDEVICE_ENTER; | ||
110 | |||
111 | switch (flags) { | ||
112 | case ME_IO_SINGLE_CONFIG_NO_FLAGS: | ||
113 | case ME_IO_SINGLE_CONFIG_DIO_BYTE: | ||
114 | if (channel == 0) { | ||
115 | if (single_config == ME_SINGLE_CONFIG_DIO_INPUT) { | ||
116 | } else { | ||
117 | PERROR("Invalid port direction specified.\n"); | ||
118 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
119 | } | ||
120 | } else { | ||
121 | PERROR("Invalid channel number.\n"); | ||
122 | err = ME_ERRNO_INVALID_CHANNEL; | ||
123 | } | ||
124 | break; | ||
125 | |||
126 | default: | ||
127 | PERROR("Invalid flags specified.\n"); | ||
128 | err = ME_ERRNO_INVALID_FLAGS; | ||
129 | } | ||
130 | |||
131 | ME_SUBDEVICE_EXIT; | ||
132 | |||
133 | return err; | ||
134 | } | ||
135 | |||
136 | static int me4600_di_io_single_read(me_subdevice_t * subdevice, | ||
137 | struct file *filep, | ||
138 | int channel, | ||
139 | int *value, int time_out, int flags) | ||
140 | { | ||
141 | me4600_di_subdevice_t *instance; | ||
142 | int err = ME_ERRNO_SUCCESS; | ||
143 | |||
144 | PDEBUG("executed.\n"); | ||
145 | |||
146 | instance = (me4600_di_subdevice_t *) subdevice; | ||
147 | |||
148 | ME_SUBDEVICE_ENTER; | ||
149 | |||
150 | switch (flags) { | ||
151 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
152 | if ((channel >= 0) && (channel < 8)) { | ||
153 | *value = inl(instance->port_reg) & (0x1 << channel); | ||
154 | } else { | ||
155 | PERROR("Invalid bit number specified.\n"); | ||
156 | err = ME_ERRNO_INVALID_CHANNEL; | ||
157 | } | ||
158 | break; | ||
159 | |||
160 | case ME_IO_SINGLE_NO_FLAGS: | ||
161 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
162 | if (channel == 0) { | ||
163 | *value = inl(instance->port_reg) & 0xFF; | ||
164 | } else { | ||
165 | PERROR("Invalid byte number specified.\n"); | ||
166 | err = ME_ERRNO_INVALID_CHANNEL; | ||
167 | } | ||
168 | break; | ||
169 | |||
170 | default: | ||
171 | PERROR("Invalid flags specified.\n"); | ||
172 | err = ME_ERRNO_INVALID_FLAGS; | ||
173 | } | ||
174 | |||
175 | ME_SUBDEVICE_EXIT; | ||
176 | |||
177 | return err; | ||
178 | } | ||
179 | |||
180 | static int me4600_di_query_number_channels(me_subdevice_t * subdevice, | ||
181 | int *number) | ||
182 | { | ||
183 | PDEBUG("executed.\n"); | ||
184 | *number = 8; | ||
185 | return ME_ERRNO_SUCCESS; | ||
186 | } | ||
187 | |||
188 | static int me4600_di_query_subdevice_type(me_subdevice_t * subdevice, | ||
189 | int *type, int *subtype) | ||
190 | { | ||
191 | PDEBUG("executed.\n"); | ||
192 | *type = ME_TYPE_DI; | ||
193 | *subtype = ME_SUBTYPE_SINGLE; | ||
194 | return ME_ERRNO_SUCCESS; | ||
195 | } | ||
196 | |||
197 | static int me4600_di_query_subdevice_caps(me_subdevice_t * subdevice, int *caps) | ||
198 | { | ||
199 | PDEBUG("executed.\n"); | ||
200 | *caps = 0; | ||
201 | return ME_ERRNO_SUCCESS; | ||
202 | } | ||
203 | |||
204 | me4600_di_subdevice_t *me4600_di_constructor(uint32_t reg_base, | ||
205 | spinlock_t * ctrl_reg_lock) | ||
206 | { | ||
207 | me4600_di_subdevice_t *subdevice; | ||
208 | int err; | ||
209 | |||
210 | PDEBUG("executed.\n"); | ||
211 | |||
212 | /* Allocate memory for subdevice instance */ | ||
213 | subdevice = kmalloc(sizeof(me4600_di_subdevice_t), GFP_KERNEL); | ||
214 | |||
215 | if (!subdevice) { | ||
216 | PERROR("Cannot get memory for subdevice instance.\n"); | ||
217 | return NULL; | ||
218 | } | ||
219 | |||
220 | memset(subdevice, 0, sizeof(me4600_di_subdevice_t)); | ||
221 | |||
222 | /* Initialize subdevice base class */ | ||
223 | err = me_subdevice_init(&subdevice->base); | ||
224 | |||
225 | if (err) { | ||
226 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
227 | kfree(subdevice); | ||
228 | return NULL; | ||
229 | } | ||
230 | // Initialize spin locks. | ||
231 | spin_lock_init(&subdevice->subdevice_lock); | ||
232 | |||
233 | subdevice->ctrl_reg_lock = ctrl_reg_lock; | ||
234 | |||
235 | /* Save the subdevice index */ | ||
236 | subdevice->port_reg = reg_base + ME4600_DIO_PORT_1_REG; | ||
237 | subdevice->ctrl_reg = reg_base + ME4600_DIO_CTRL_REG; | ||
238 | #ifdef MEDEBUG_DEBUG_REG | ||
239 | subdevice->reg_base = reg_base; | ||
240 | #endif | ||
241 | |||
242 | /* Overload base class methods. */ | ||
243 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
244 | me4600_di_io_reset_subdevice; | ||
245 | subdevice->base.me_subdevice_io_single_config = | ||
246 | me4600_di_io_single_config; | ||
247 | subdevice->base.me_subdevice_io_single_read = me4600_di_io_single_read; | ||
248 | subdevice->base.me_subdevice_query_number_channels = | ||
249 | me4600_di_query_number_channels; | ||
250 | subdevice->base.me_subdevice_query_subdevice_type = | ||
251 | me4600_di_query_subdevice_type; | ||
252 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
253 | me4600_di_query_subdevice_caps; | ||
254 | |||
255 | return subdevice; | ||
256 | } | ||
diff --git a/drivers/staging/meilhaus/me4600_di.h b/drivers/staging/meilhaus/me4600_di.h new file mode 100644 index 000000000000..ec8b175755be --- /dev/null +++ b/drivers/staging/meilhaus/me4600_di.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /** | ||
2 | * @file me4600_di.h | ||
3 | * | ||
4 | * @brief ME-4000 digital input subdevice class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME4600_DI_H_ | ||
28 | #define _ME4600_DI_H_ | ||
29 | |||
30 | #include "mesubdevice.h" | ||
31 | |||
32 | #ifdef __KERNEL__ | ||
33 | |||
34 | /** | ||
35 | * @brief The template subdevice class. | ||
36 | */ | ||
37 | typedef struct me4600_di_subdevice { | ||
38 | /* Inheritance */ | ||
39 | me_subdevice_t base; /**< The subdevice base class. */ | ||
40 | |||
41 | /* Attributes */ | ||
42 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
43 | spinlock_t *ctrl_reg_lock; /**< Spin lock to protect #ctrl_reg from concurrent access. */ | ||
44 | |||
45 | unsigned long port_reg; /**< Register holding the port status. */ | ||
46 | unsigned long ctrl_reg; /**< Register to configure the port direction. */ | ||
47 | #ifdef MEDEBUG_DEBUG_REG | ||
48 | unsigned long reg_base; | ||
49 | #endif | ||
50 | } me4600_di_subdevice_t; | ||
51 | |||
52 | /** | ||
53 | * @brief The constructor to generate a ME-4000 digital input subdevice instance. | ||
54 | * | ||
55 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
56 | * | ||
57 | * @return Pointer to new instance on success.\n | ||
58 | * NULL on error. | ||
59 | */ | ||
60 | me4600_di_subdevice_t *me4600_di_constructor(uint32_t reg_base, | ||
61 | spinlock_t * ctrl_reg_lock); | ||
62 | |||
63 | #endif | ||
64 | #endif | ||
diff --git a/drivers/staging/meilhaus/me4600_dio.c b/drivers/staging/meilhaus/me4600_dio.c new file mode 100644 index 000000000000..0af95d1a8f5d --- /dev/null +++ b/drivers/staging/meilhaus/me4600_dio.c | |||
@@ -0,0 +1,510 @@ | |||
1 | /** | ||
2 | * @file me4600_dio.c | ||
3 | * | ||
4 | * @brief ME-4000 digital input/output subdevice instance. | ||
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 | /* | ||
33 | * Includes | ||
34 | */ | ||
35 | #include <linux/module.h> | ||
36 | |||
37 | #include <linux/slab.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | #include <asm/io.h> | ||
40 | #include <linux/types.h> | ||
41 | |||
42 | #include "medefines.h" | ||
43 | #include "meinternal.h" | ||
44 | #include "meerror.h" | ||
45 | |||
46 | #include "medebug.h" | ||
47 | #include "me4600_dio_reg.h" | ||
48 | #include "me4600_dio.h" | ||
49 | |||
50 | /* | ||
51 | * Defines | ||
52 | */ | ||
53 | |||
54 | /* | ||
55 | * Functions | ||
56 | */ | ||
57 | |||
58 | static int me4600_dio_io_reset_subdevice(struct me_subdevice *subdevice, | ||
59 | struct file *filep, int flags) | ||
60 | { | ||
61 | me4600_dio_subdevice_t *instance; | ||
62 | uint32_t mode; | ||
63 | |||
64 | PDEBUG("executed.\n"); | ||
65 | |||
66 | instance = (me4600_dio_subdevice_t *) subdevice; | ||
67 | |||
68 | if (flags) { | ||
69 | PERROR("Invalid flag specified.\n"); | ||
70 | return ME_ERRNO_INVALID_FLAGS; | ||
71 | } | ||
72 | |||
73 | ME_SUBDEVICE_ENTER; | ||
74 | |||
75 | /* Set port to input mode */ | ||
76 | spin_lock(&instance->subdevice_lock); | ||
77 | spin_lock(instance->ctrl_reg_lock); | ||
78 | mode = inl(instance->ctrl_reg); | ||
79 | mode &= | ||
80 | ~((ME4600_DIO_CTRL_BIT_MODE_0 | ME4600_DIO_CTRL_BIT_MODE_1) << | ||
81 | (instance->dio_idx * 2)); | ||
82 | outl(mode, instance->ctrl_reg); | ||
83 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
84 | instance->ctrl_reg - instance->reg_base, mode); | ||
85 | spin_unlock(instance->ctrl_reg_lock); | ||
86 | |||
87 | outl(0, instance->port_reg); | ||
88 | PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
89 | instance->port_reg - instance->reg_base, 0); | ||
90 | spin_unlock(&instance->subdevice_lock); | ||
91 | |||
92 | ME_SUBDEVICE_EXIT; | ||
93 | |||
94 | return ME_ERRNO_SUCCESS; | ||
95 | } | ||
96 | |||
97 | static int me4600_dio_io_single_config(me_subdevice_t * subdevice, | ||
98 | struct file *filep, | ||
99 | int channel, | ||
100 | int single_config, | ||
101 | int ref, | ||
102 | int trig_chan, | ||
103 | int trig_type, int trig_edge, int flags) | ||
104 | { | ||
105 | me4600_dio_subdevice_t *instance; | ||
106 | int err = ME_ERRNO_SUCCESS; | ||
107 | uint32_t mode; | ||
108 | uint32_t size = | ||
109 | flags & (ME_IO_SINGLE_CONFIG_DIO_BIT | ME_IO_SINGLE_CONFIG_DIO_BYTE | ||
110 | | ME_IO_SINGLE_CONFIG_DIO_WORD | | ||
111 | ME_IO_SINGLE_CONFIG_DIO_DWORD); | ||
112 | uint32_t mask; | ||
113 | |||
114 | PDEBUG("executed.\n"); | ||
115 | |||
116 | instance = (me4600_dio_subdevice_t *) subdevice; | ||
117 | |||
118 | ME_SUBDEVICE_ENTER spin_lock(&instance->subdevice_lock); | ||
119 | spin_lock(instance->ctrl_reg_lock); | ||
120 | mode = inl(instance->ctrl_reg); | ||
121 | switch (size) { | ||
122 | case ME_IO_SINGLE_CONFIG_NO_FLAGS: | ||
123 | case ME_IO_SINGLE_CONFIG_DIO_BYTE: | ||
124 | if (channel == 0) { | ||
125 | if (single_config == ME_SINGLE_CONFIG_DIO_INPUT) { | ||
126 | mode &= | ||
127 | ~((ME4600_DIO_CTRL_BIT_MODE_0 | | ||
128 | ME4600_DIO_CTRL_BIT_MODE_1) << | ||
129 | (instance->dio_idx * 2)); | ||
130 | } else if (single_config == ME_SINGLE_CONFIG_DIO_OUTPUT) { | ||
131 | mode &= | ||
132 | ~((ME4600_DIO_CTRL_BIT_MODE_0 | | ||
133 | ME4600_DIO_CTRL_BIT_MODE_1) << | ||
134 | (instance->dio_idx * 2)); | ||
135 | mode |= | ||
136 | ME4600_DIO_CTRL_BIT_MODE_0 << (instance-> | ||
137 | dio_idx * 2); | ||
138 | } else if (single_config == ME_SINGLE_CONFIG_DIO_MUX32M) { | ||
139 | mask = | ||
140 | (ME4600_DIO_CTRL_BIT_MODE_0 | | ||
141 | ME4600_DIO_CTRL_BIT_MODE_1) << (instance-> | ||
142 | dio_idx * | ||
143 | 2); | ||
144 | mask |= | ||
145 | ME4600_DIO_CTRL_BIT_FUNCTION_0 | | ||
146 | ME4600_DIO_CTRL_BIT_FUNCTION_1; | ||
147 | mask |= | ||
148 | ME4600_DIO_CTRL_BIT_FIFO_HIGH_0 << | ||
149 | instance->dio_idx; | ||
150 | mode &= ~mask; | ||
151 | |||
152 | if (ref == ME_REF_DIO_FIFO_LOW) { | ||
153 | mode |= | ||
154 | (ME4600_DIO_CTRL_BIT_MODE_0 | | ||
155 | ME4600_DIO_CTRL_BIT_MODE_1) << | ||
156 | (instance->dio_idx * 2); | ||
157 | mode |= ME4600_DIO_CTRL_BIT_FUNCTION_1; | ||
158 | } else if (ref == ME_REF_DIO_FIFO_HIGH) { | ||
159 | mode |= | ||
160 | (ME4600_DIO_CTRL_BIT_MODE_0 | | ||
161 | ME4600_DIO_CTRL_BIT_MODE_1) << | ||
162 | (instance->dio_idx * 2); | ||
163 | mode |= ME4600_DIO_CTRL_BIT_FUNCTION_1; | ||
164 | mode |= | ||
165 | ME4600_DIO_CTRL_BIT_FIFO_HIGH_0 << | ||
166 | instance->dio_idx; | ||
167 | } else { | ||
168 | PERROR | ||
169 | ("Invalid port reference specified.\n"); | ||
170 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
171 | } | ||
172 | } else if (single_config == | ||
173 | ME_SINGLE_CONFIG_DIO_DEMUX32) { | ||
174 | mask = | ||
175 | (ME4600_DIO_CTRL_BIT_MODE_0 | | ||
176 | ME4600_DIO_CTRL_BIT_MODE_1) << (instance-> | ||
177 | dio_idx * | ||
178 | 2); | ||
179 | mask |= | ||
180 | ME4600_DIO_CTRL_BIT_FUNCTION_0 | | ||
181 | ME4600_DIO_CTRL_BIT_FUNCTION_1; | ||
182 | mask |= | ||
183 | ME4600_DIO_CTRL_BIT_FIFO_HIGH_0 << | ||
184 | instance->dio_idx; | ||
185 | mode &= ~mask; | ||
186 | |||
187 | if (ref == ME_REF_DIO_FIFO_LOW) { | ||
188 | mode |= | ||
189 | (ME4600_DIO_CTRL_BIT_MODE_0 | | ||
190 | ME4600_DIO_CTRL_BIT_MODE_1) << | ||
191 | (instance->dio_idx * 2); | ||
192 | mode |= ME4600_DIO_CTRL_BIT_FUNCTION_0; | ||
193 | } else if (ref == ME_REF_DIO_FIFO_HIGH) { | ||
194 | mode |= | ||
195 | (ME4600_DIO_CTRL_BIT_MODE_0 | | ||
196 | ME4600_DIO_CTRL_BIT_MODE_1) << | ||
197 | (instance->dio_idx * 2); | ||
198 | mode |= ME4600_DIO_CTRL_BIT_FUNCTION_0; | ||
199 | mode |= | ||
200 | ME4600_DIO_CTRL_BIT_FIFO_HIGH_0 << | ||
201 | instance->dio_idx; | ||
202 | } else { | ||
203 | PERROR | ||
204 | ("Invalid port reference specified.\n"); | ||
205 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
206 | } | ||
207 | } else if (single_config == | ||
208 | ME_SINGLE_CONFIG_DIO_BIT_PATTERN) { | ||
209 | mask = | ||
210 | (ME4600_DIO_CTRL_BIT_MODE_0 | | ||
211 | ME4600_DIO_CTRL_BIT_MODE_1) << (instance-> | ||
212 | dio_idx * | ||
213 | 2); | ||
214 | mask |= | ||
215 | ME4600_DIO_CTRL_BIT_FUNCTION_0 | | ||
216 | ME4600_DIO_CTRL_BIT_FUNCTION_1; | ||
217 | mask |= | ||
218 | ME4600_DIO_CTRL_BIT_FIFO_HIGH_0 << | ||
219 | instance->dio_idx; | ||
220 | mode &= ~mask; | ||
221 | |||
222 | if (ref == ME_REF_DIO_FIFO_LOW) { | ||
223 | mode |= | ||
224 | (ME4600_DIO_CTRL_BIT_MODE_0 | | ||
225 | ME4600_DIO_CTRL_BIT_MODE_1) << | ||
226 | (instance->dio_idx * 2); | ||
227 | } else if (ref == ME_REF_DIO_FIFO_HIGH) { | ||
228 | mode |= | ||
229 | (ME4600_DIO_CTRL_BIT_MODE_0 | | ||
230 | ME4600_DIO_CTRL_BIT_MODE_1) << | ||
231 | (instance->dio_idx * 2); | ||
232 | mode |= | ||
233 | ME4600_DIO_CTRL_BIT_FIFO_HIGH_0 << | ||
234 | instance->dio_idx; | ||
235 | } else { | ||
236 | PERROR | ||
237 | ("Invalid port reference specified.\n"); | ||
238 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
239 | } | ||
240 | } else { | ||
241 | PERROR | ||
242 | ("Invalid port configuration specified.\n"); | ||
243 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
244 | } | ||
245 | } else { | ||
246 | PERROR("Invalid channel number.\n"); | ||
247 | err = ME_ERRNO_INVALID_CHANNEL; | ||
248 | } | ||
249 | |||
250 | break; | ||
251 | |||
252 | default: | ||
253 | PERROR("Invalid flags.\n"); | ||
254 | err = ME_ERRNO_INVALID_FLAGS; | ||
255 | } | ||
256 | |||
257 | if (!err) { | ||
258 | outl(mode, instance->ctrl_reg); | ||
259 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
260 | instance->reg_base, | ||
261 | instance->ctrl_reg - instance->reg_base, mode); | ||
262 | } | ||
263 | spin_unlock(instance->ctrl_reg_lock); | ||
264 | spin_unlock(&instance->subdevice_lock); | ||
265 | |||
266 | ME_SUBDEVICE_EXIT; | ||
267 | |||
268 | return err; | ||
269 | } | ||
270 | |||
271 | static int me4600_dio_io_single_read(me_subdevice_t * subdevice, | ||
272 | struct file *filep, | ||
273 | int channel, | ||
274 | int *value, int time_out, int flags) | ||
275 | { | ||
276 | me4600_dio_subdevice_t *instance; | ||
277 | int err = ME_ERRNO_SUCCESS; | ||
278 | uint32_t mode; | ||
279 | |||
280 | PDEBUG("executed.\n"); | ||
281 | |||
282 | instance = (me4600_dio_subdevice_t *) subdevice; | ||
283 | |||
284 | ME_SUBDEVICE_ENTER; | ||
285 | |||
286 | spin_lock(&instance->subdevice_lock); | ||
287 | spin_lock(instance->ctrl_reg_lock); | ||
288 | switch (flags) { | ||
289 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
290 | if ((channel >= 0) && (channel < 8)) { | ||
291 | mode = | ||
292 | inl(instance-> | ||
293 | ctrl_reg) & ((ME4600_DIO_CTRL_BIT_MODE_0 | | ||
294 | ME4600_DIO_CTRL_BIT_MODE_1) << | ||
295 | (instance->dio_idx * 2)); | ||
296 | if ((mode == | ||
297 | (ME4600_DIO_CTRL_BIT_MODE_0 << | ||
298 | (instance->dio_idx * 2))) || !mode) { | ||
299 | *value = | ||
300 | inl(instance->port_reg) & (0x1 << channel); | ||
301 | } else { | ||
302 | PERROR("Port not in output or input mode.\n"); | ||
303 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
304 | } | ||
305 | } else { | ||
306 | PERROR("Invalid bit number specified.\n"); | ||
307 | err = ME_ERRNO_INVALID_CHANNEL; | ||
308 | } | ||
309 | break; | ||
310 | |||
311 | case ME_IO_SINGLE_NO_FLAGS: | ||
312 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
313 | if (channel == 0) { | ||
314 | mode = | ||
315 | inl(instance-> | ||
316 | ctrl_reg) & ((ME4600_DIO_CTRL_BIT_MODE_0 | | ||
317 | ME4600_DIO_CTRL_BIT_MODE_1) << | ||
318 | (instance->dio_idx * 2)); | ||
319 | if ((mode == | ||
320 | (ME4600_DIO_CTRL_BIT_MODE_0 << | ||
321 | (instance->dio_idx * 2))) || !mode) { | ||
322 | *value = inl(instance->port_reg) & 0xFF; | ||
323 | } else { | ||
324 | PERROR("Port not in output or input mode.\n"); | ||
325 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
326 | } | ||
327 | } else { | ||
328 | PERROR("Invalid byte number specified.\n"); | ||
329 | err = ME_ERRNO_INVALID_CHANNEL; | ||
330 | } | ||
331 | break; | ||
332 | |||
333 | default: | ||
334 | PERROR("Invalid flags specified.\n"); | ||
335 | err = ME_ERRNO_INVALID_FLAGS; | ||
336 | } | ||
337 | spin_unlock(instance->ctrl_reg_lock); | ||
338 | spin_unlock(&instance->subdevice_lock); | ||
339 | |||
340 | ME_SUBDEVICE_EXIT; | ||
341 | |||
342 | return err; | ||
343 | } | ||
344 | |||
345 | static int me4600_dio_io_single_write(me_subdevice_t * subdevice, | ||
346 | struct file *filep, | ||
347 | int channel, | ||
348 | int value, int time_out, int flags) | ||
349 | { | ||
350 | me4600_dio_subdevice_t *instance; | ||
351 | int err = ME_ERRNO_SUCCESS; | ||
352 | uint32_t mode; | ||
353 | uint32_t byte; | ||
354 | |||
355 | PDEBUG("executed.\n"); | ||
356 | |||
357 | instance = (me4600_dio_subdevice_t *) subdevice; | ||
358 | |||
359 | ME_SUBDEVICE_ENTER; | ||
360 | |||
361 | spin_lock(&instance->subdevice_lock); | ||
362 | spin_lock(instance->ctrl_reg_lock); | ||
363 | switch (flags) { | ||
364 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
365 | if ((channel >= 0) && (channel < 8)) { | ||
366 | mode = | ||
367 | inl(instance-> | ||
368 | ctrl_reg) & ((ME4600_DIO_CTRL_BIT_MODE_0 | | ||
369 | ME4600_DIO_CTRL_BIT_MODE_1) << | ||
370 | (instance->dio_idx * 2)); | ||
371 | |||
372 | if (mode == | ||
373 | (ME4600_DIO_CTRL_BIT_MODE_0 << | ||
374 | (instance->dio_idx * 2))) { | ||
375 | byte = inl(instance->port_reg) & 0xFF; | ||
376 | |||
377 | if (value) | ||
378 | byte |= 0x1 << channel; | ||
379 | else | ||
380 | byte &= ~(0x1 << channel); | ||
381 | |||
382 | outl(byte, instance->port_reg); | ||
383 | } else { | ||
384 | PERROR("Port not in output or input mode.\n"); | ||
385 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
386 | } | ||
387 | } else { | ||
388 | PERROR("Invalid bit number specified.\n"); | ||
389 | err = ME_ERRNO_INVALID_CHANNEL; | ||
390 | } | ||
391 | break; | ||
392 | |||
393 | case ME_IO_SINGLE_NO_FLAGS: | ||
394 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
395 | if (channel == 0) { | ||
396 | mode = | ||
397 | inl(instance-> | ||
398 | ctrl_reg) & ((ME4600_DIO_CTRL_BIT_MODE_0 | | ||
399 | ME4600_DIO_CTRL_BIT_MODE_1) << | ||
400 | (instance->dio_idx * 2)); | ||
401 | |||
402 | if (mode == | ||
403 | (ME4600_DIO_CTRL_BIT_MODE_0 << | ||
404 | (instance->dio_idx * 2))) { | ||
405 | outl(value, instance->port_reg); | ||
406 | } else { | ||
407 | PERROR("Port not in output or input mode.\n"); | ||
408 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
409 | } | ||
410 | } else { | ||
411 | PERROR("Invalid byte number specified.\n"); | ||
412 | err = ME_ERRNO_INVALID_CHANNEL; | ||
413 | } | ||
414 | break; | ||
415 | |||
416 | default: | ||
417 | PERROR("Invalid flags specified.\n"); | ||
418 | err = ME_ERRNO_INVALID_FLAGS; | ||
419 | } | ||
420 | spin_unlock(instance->ctrl_reg_lock); | ||
421 | spin_unlock(&instance->subdevice_lock); | ||
422 | |||
423 | ME_SUBDEVICE_EXIT; | ||
424 | |||
425 | return err; | ||
426 | } | ||
427 | |||
428 | static int me4600_dio_query_number_channels(me_subdevice_t * subdevice, | ||
429 | int *number) | ||
430 | { | ||
431 | PDEBUG("executed.\n"); | ||
432 | *number = 8; | ||
433 | return ME_ERRNO_SUCCESS; | ||
434 | } | ||
435 | |||
436 | static int me4600_dio_query_subdevice_type(me_subdevice_t * subdevice, | ||
437 | int *type, int *subtype) | ||
438 | { | ||
439 | PDEBUG("executed.\n"); | ||
440 | *type = ME_TYPE_DIO; | ||
441 | *subtype = ME_SUBTYPE_SINGLE; | ||
442 | return ME_ERRNO_SUCCESS; | ||
443 | } | ||
444 | |||
445 | static int me4600_dio_query_subdevice_caps(me_subdevice_t * subdevice, | ||
446 | int *caps) | ||
447 | { | ||
448 | PDEBUG("executed.\n"); | ||
449 | *caps = ME_CAPS_DIO_DIR_BYTE; | ||
450 | return ME_ERRNO_SUCCESS; | ||
451 | } | ||
452 | |||
453 | me4600_dio_subdevice_t *me4600_dio_constructor(uint32_t reg_base, | ||
454 | unsigned int dio_idx, | ||
455 | spinlock_t * ctrl_reg_lock) | ||
456 | { | ||
457 | me4600_dio_subdevice_t *subdevice; | ||
458 | int err; | ||
459 | |||
460 | PDEBUG("executed.\n"); | ||
461 | |||
462 | /* Allocate memory for subdevice instance */ | ||
463 | subdevice = kmalloc(sizeof(me4600_dio_subdevice_t), GFP_KERNEL); | ||
464 | |||
465 | if (!subdevice) { | ||
466 | PERROR("Cannot get memory for subdevice instance.\n"); | ||
467 | return NULL; | ||
468 | } | ||
469 | |||
470 | memset(subdevice, 0, sizeof(me4600_dio_subdevice_t)); | ||
471 | |||
472 | /* Initialize subdevice base class */ | ||
473 | err = me_subdevice_init(&subdevice->base); | ||
474 | |||
475 | if (err) { | ||
476 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
477 | kfree(subdevice); | ||
478 | return NULL; | ||
479 | } | ||
480 | // Initialize spin locks. | ||
481 | spin_lock_init(&subdevice->subdevice_lock); | ||
482 | subdevice->ctrl_reg_lock = ctrl_reg_lock; | ||
483 | |||
484 | /* Save digital i/o index */ | ||
485 | subdevice->dio_idx = dio_idx; | ||
486 | |||
487 | /* Save the subdevice index */ | ||
488 | subdevice->ctrl_reg = reg_base + ME4600_DIO_CTRL_REG; | ||
489 | subdevice->port_reg = reg_base + ME4600_DIO_PORT_REG + (dio_idx * 4); | ||
490 | #ifdef MEDEBUG_DEBUG_REG | ||
491 | subdevice->reg_base = reg_base; | ||
492 | #endif | ||
493 | |||
494 | /* Overload base class methods. */ | ||
495 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
496 | me4600_dio_io_reset_subdevice; | ||
497 | subdevice->base.me_subdevice_io_single_config = | ||
498 | me4600_dio_io_single_config; | ||
499 | subdevice->base.me_subdevice_io_single_read = me4600_dio_io_single_read; | ||
500 | subdevice->base.me_subdevice_io_single_write = | ||
501 | me4600_dio_io_single_write; | ||
502 | subdevice->base.me_subdevice_query_number_channels = | ||
503 | me4600_dio_query_number_channels; | ||
504 | subdevice->base.me_subdevice_query_subdevice_type = | ||
505 | me4600_dio_query_subdevice_type; | ||
506 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
507 | me4600_dio_query_subdevice_caps; | ||
508 | |||
509 | return subdevice; | ||
510 | } | ||
diff --git a/drivers/staging/meilhaus/me4600_dio.h b/drivers/staging/meilhaus/me4600_dio.h new file mode 100644 index 000000000000..4625ba91f609 --- /dev/null +++ b/drivers/staging/meilhaus/me4600_dio.h | |||
@@ -0,0 +1,69 @@ | |||
1 | /** | ||
2 | * @file me4600_dio.h | ||
3 | * | ||
4 | * @brief ME-4000 digital input/output subdevice class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME4600_DIO_H_ | ||
28 | #define _ME4600_DIO_H_ | ||
29 | |||
30 | #include "mesubdevice.h" | ||
31 | |||
32 | #ifdef __KERNEL__ | ||
33 | |||
34 | /** | ||
35 | * @brief The template subdevice class. | ||
36 | */ | ||
37 | typedef struct me4600_dio_subdevice { | ||
38 | /* Inheritance */ | ||
39 | me_subdevice_t base; /**< The subdevice base class. */ | ||
40 | |||
41 | /* Attributes */ | ||
42 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
43 | spinlock_t *ctrl_reg_lock; /**< Spin lock to protect #ctrl_reg from concurrent access. */ | ||
44 | unsigned int dio_idx; /**< The index of the digital i/o on the device. */ | ||
45 | |||
46 | /* Registers */ | ||
47 | unsigned long port_reg; /**< Register holding the port status. */ | ||
48 | unsigned long ctrl_reg; /**< Register to configure the port direction. */ | ||
49 | #ifdef MEDEBUG_DEBUG_REG | ||
50 | unsigned long reg_base; | ||
51 | #endif | ||
52 | } me4600_dio_subdevice_t; | ||
53 | |||
54 | /** | ||
55 | * @brief The constructor to generate a ME-4000 digital input/ouput subdevice instance. | ||
56 | * | ||
57 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
58 | * @param dio_idx The index of the digital i/o port on the device. | ||
59 | * @param ctrl_reg_lock Spin lock protecting the control register. | ||
60 | * | ||
61 | * @return Pointer to new instance on success.\n | ||
62 | * NULL on error. | ||
63 | */ | ||
64 | me4600_dio_subdevice_t *me4600_dio_constructor(uint32_t reg_base, | ||
65 | unsigned int dio_idx, | ||
66 | spinlock_t * ctrl_reg_lock); | ||
67 | |||
68 | #endif | ||
69 | #endif | ||
diff --git a/drivers/staging/meilhaus/me4600_dio_reg.h b/drivers/staging/meilhaus/me4600_dio_reg.h new file mode 100644 index 000000000000..7a4016a80fd2 --- /dev/null +++ b/drivers/staging/meilhaus/me4600_dio_reg.h | |||
@@ -0,0 +1,63 @@ | |||
1 | /** | ||
2 | * @file me4600_dio_reg.h | ||
3 | * | ||
4 | * @brief ME-4000 digital input/output subdevice register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME4600_DIO_REG_H_ | ||
28 | #define _ME4600_DIO_REG_H_ | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | #define ME4600_DIO_PORT_0_REG 0xA0 /**< Port 0 register. */ | ||
33 | #define ME4600_DIO_PORT_1_REG 0xA4 /**< Port 1 register. */ | ||
34 | #define ME4600_DIO_PORT_2_REG 0xA8 /**< Port 2 register. */ | ||
35 | #define ME4600_DIO_PORT_3_REG 0xAC /**< Port 3 register. */ | ||
36 | |||
37 | #define ME4600_DIO_DIR_REG 0xB0 /**< Direction register. */ | ||
38 | #define ME4600_DIO_PORT_REG ME4600_DIO_PORT_0_REG /**< Base for port's register. */ | ||
39 | |||
40 | #define ME4600_DIO_CTRL_REG 0xB8 /**< Control register. */ | ||
41 | /** Port A - DO */ | ||
42 | #define ME4600_DIO_CTRL_BIT_MODE_0 0x0001 | ||
43 | #define ME4600_DIO_CTRL_BIT_MODE_1 0x0002 | ||
44 | /** Port B - DI */ | ||
45 | #define ME4600_DIO_CTRL_BIT_MODE_2 0x0004 | ||
46 | #define ME4600_DIO_CTRL_BIT_MODE_3 0x0008 | ||
47 | /** Port C - DIO */ | ||
48 | #define ME4600_DIO_CTRL_BIT_MODE_4 0x0010 | ||
49 | #define ME4600_DIO_CTRL_BIT_MODE_5 0x0020 | ||
50 | /** Port D - DIO */ | ||
51 | #define ME4600_DIO_CTRL_BIT_MODE_6 0x0040 | ||
52 | #define ME4600_DIO_CTRL_BIT_MODE_7 0x0080 | ||
53 | |||
54 | #define ME4600_DIO_CTRL_BIT_FUNCTION_0 0x0100 | ||
55 | #define ME4600_DIO_CTRL_BIT_FUNCTION_1 0x0200 | ||
56 | |||
57 | #define ME4600_DIO_CTRL_BIT_FIFO_HIGH_0 0x0400 | ||
58 | #define ME4600_DIO_CTRL_BIT_FIFO_HIGH_1 0x0800 | ||
59 | #define ME4600_DIO_CTRL_BIT_FIFO_HIGH_2 0x1000 | ||
60 | #define ME4600_DIO_CTRL_BIT_FIFO_HIGH_3 0x2000 | ||
61 | |||
62 | #endif | ||
63 | #endif | ||
diff --git a/drivers/staging/meilhaus/me4600_do.c b/drivers/staging/meilhaus/me4600_do.c new file mode 100644 index 000000000000..ee591bc1185e --- /dev/null +++ b/drivers/staging/meilhaus/me4600_do.c | |||
@@ -0,0 +1,433 @@ | |||
1 | /** | ||
2 | * @file me4600_do.c | ||
3 | * | ||
4 | * @brief ME-4000 digital output subdevice instance. | ||
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 | /* | ||
33 | * Includes | ||
34 | */ | ||
35 | #include <linux/module.h> | ||
36 | |||
37 | #include <linux/slab.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | #include <asm/io.h> | ||
40 | #include <linux/types.h> | ||
41 | |||
42 | #include "medefines.h" | ||
43 | #include "meinternal.h" | ||
44 | #include "meerror.h" | ||
45 | |||
46 | #include "medebug.h" | ||
47 | #include "me4600_dio_reg.h" | ||
48 | #include "me4600_do.h" | ||
49 | |||
50 | /* | ||
51 | * Defines | ||
52 | */ | ||
53 | |||
54 | /* | ||
55 | * Functions | ||
56 | */ | ||
57 | |||
58 | static int me4600_do_io_reset_subdevice(struct me_subdevice *subdevice, | ||
59 | struct file *filep, int flags) | ||
60 | { | ||
61 | me4600_do_subdevice_t *instance; | ||
62 | uint32_t mode; | ||
63 | |||
64 | PDEBUG("executed.\n"); | ||
65 | |||
66 | instance = (me4600_do_subdevice_t *) subdevice; | ||
67 | |||
68 | if (flags) { | ||
69 | PERROR("Invalid flag specified.\n"); | ||
70 | return ME_ERRNO_INVALID_FLAGS; | ||
71 | } | ||
72 | |||
73 | ME_SUBDEVICE_ENTER; | ||
74 | |||
75 | /* Set port to output mode */ | ||
76 | spin_lock(&instance->subdevice_lock); | ||
77 | spin_lock(instance->ctrl_reg_lock); | ||
78 | mode = inl(instance->ctrl_reg); | ||
79 | mode &= ~ME4600_DIO_CTRL_BIT_MODE_1; //0xFFFD | ||
80 | mode |= ME4600_DIO_CTRL_BIT_MODE_0; //0x1 | ||
81 | outl(mode, instance->ctrl_reg); | ||
82 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
83 | instance->ctrl_reg - instance->reg_base, mode); | ||
84 | spin_unlock(instance->ctrl_reg_lock); | ||
85 | |||
86 | outl(0, instance->port_reg); | ||
87 | PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
88 | instance->port_reg - instance->reg_base, 0); | ||
89 | spin_unlock(&instance->subdevice_lock); | ||
90 | |||
91 | ME_SUBDEVICE_EXIT; | ||
92 | |||
93 | return ME_ERRNO_SUCCESS; | ||
94 | } | ||
95 | |||
96 | static int me4600_do_io_single_config(me_subdevice_t * subdevice, | ||
97 | struct file *filep, | ||
98 | int channel, | ||
99 | int single_config, | ||
100 | int ref, | ||
101 | int trig_chan, | ||
102 | int trig_type, int trig_edge, int flags) | ||
103 | { | ||
104 | me4600_do_subdevice_t *instance; | ||
105 | int err = ME_ERRNO_SUCCESS; | ||
106 | uint32_t mode; | ||
107 | int size = | ||
108 | flags & (ME_IO_SINGLE_CONFIG_DIO_BIT | ME_IO_SINGLE_CONFIG_DIO_BYTE | ||
109 | | ME_IO_SINGLE_CONFIG_DIO_WORD | | ||
110 | ME_IO_SINGLE_CONFIG_DIO_DWORD); | ||
111 | |||
112 | PDEBUG("executed.\n"); | ||
113 | |||
114 | instance = (me4600_do_subdevice_t *) subdevice; | ||
115 | |||
116 | ME_SUBDEVICE_ENTER; | ||
117 | |||
118 | spin_lock(&instance->subdevice_lock); | ||
119 | spin_lock(instance->ctrl_reg_lock); | ||
120 | mode = inl(instance->ctrl_reg); | ||
121 | |||
122 | switch (size) { | ||
123 | case ME_IO_SINGLE_CONFIG_NO_FLAGS: | ||
124 | case ME_IO_SINGLE_CONFIG_DIO_BYTE: | ||
125 | if (channel == 0) { | ||
126 | if (single_config == ME_SINGLE_CONFIG_DIO_OUTPUT) { | ||
127 | mode &= ~(ME4600_DIO_CTRL_BIT_MODE_0 | | ||
128 | ME4600_DIO_CTRL_BIT_MODE_1); | ||
129 | mode |= (ME4600_DIO_CTRL_BIT_MODE_0); | ||
130 | } else if (single_config == ME_SINGLE_CONFIG_DIO_MUX32M) { | ||
131 | mode &= ~(ME4600_DIO_CTRL_BIT_MODE_0 | | ||
132 | ME4600_DIO_CTRL_BIT_MODE_1 | | ||
133 | ME4600_DIO_CTRL_BIT_FUNCTION_0 | | ||
134 | ME4600_DIO_CTRL_BIT_FUNCTION_1 | | ||
135 | ME4600_DIO_CTRL_BIT_FIFO_HIGH_0); | ||
136 | |||
137 | if (ref == ME_REF_DIO_FIFO_LOW) { | ||
138 | mode |= (ME4600_DIO_CTRL_BIT_MODE_0 | | ||
139 | ME4600_DIO_CTRL_BIT_MODE_1 | | ||
140 | ME4600_DIO_CTRL_BIT_FUNCTION_1); | ||
141 | } else if (ref == ME_REF_DIO_FIFO_HIGH) { | ||
142 | mode |= (ME4600_DIO_CTRL_BIT_MODE_0 | | ||
143 | ME4600_DIO_CTRL_BIT_MODE_1 | | ||
144 | ME4600_DIO_CTRL_BIT_FUNCTION_1 | ||
145 | | | ||
146 | ME4600_DIO_CTRL_BIT_FIFO_HIGH_0); | ||
147 | } else { | ||
148 | PERROR | ||
149 | ("Invalid port reference specified.\n"); | ||
150 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
151 | } | ||
152 | } else if (single_config == | ||
153 | ME_SINGLE_CONFIG_DIO_DEMUX32) { | ||
154 | mode &= | ||
155 | ~(ME4600_DIO_CTRL_BIT_MODE_0 | | ||
156 | ME4600_DIO_CTRL_BIT_MODE_1 | | ||
157 | ME4600_DIO_CTRL_BIT_FUNCTION_0 | | ||
158 | ME4600_DIO_CTRL_BIT_FUNCTION_1 | | ||
159 | ME4600_DIO_CTRL_BIT_FIFO_HIGH_0); | ||
160 | |||
161 | if (ref == ME_REF_DIO_FIFO_LOW) { | ||
162 | mode |= (ME4600_DIO_CTRL_BIT_MODE_0 | | ||
163 | ME4600_DIO_CTRL_BIT_MODE_1 | | ||
164 | ME4600_DIO_CTRL_BIT_FUNCTION_0); | ||
165 | } else if (ref == ME_REF_DIO_FIFO_HIGH) { | ||
166 | mode |= (ME4600_DIO_CTRL_BIT_MODE_0 | | ||
167 | ME4600_DIO_CTRL_BIT_MODE_1 | | ||
168 | ME4600_DIO_CTRL_BIT_FUNCTION_0 | ||
169 | | | ||
170 | ME4600_DIO_CTRL_BIT_FIFO_HIGH_0); | ||
171 | } else { | ||
172 | PERROR | ||
173 | ("Invalid port reference specified.\n"); | ||
174 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
175 | } | ||
176 | } else if (single_config == | ||
177 | ME_SINGLE_CONFIG_DIO_BIT_PATTERN) { | ||
178 | mode &= | ||
179 | ~(ME4600_DIO_CTRL_BIT_MODE_0 | | ||
180 | ME4600_DIO_CTRL_BIT_MODE_1 | | ||
181 | ME4600_DIO_CTRL_BIT_FUNCTION_0 | | ||
182 | ME4600_DIO_CTRL_BIT_FUNCTION_1 | | ||
183 | ME4600_DIO_CTRL_BIT_FIFO_HIGH_0); | ||
184 | |||
185 | if (ref == ME_REF_DIO_FIFO_LOW) { | ||
186 | mode |= (ME4600_DIO_CTRL_BIT_MODE_0 | | ||
187 | ME4600_DIO_CTRL_BIT_MODE_1); | ||
188 | } else if (ref == ME_REF_DIO_FIFO_HIGH) { | ||
189 | mode |= (ME4600_DIO_CTRL_BIT_MODE_0 | | ||
190 | ME4600_DIO_CTRL_BIT_MODE_1 | | ||
191 | ME4600_DIO_CTRL_BIT_FIFO_HIGH_0); | ||
192 | } else { | ||
193 | PERROR | ||
194 | ("Invalid port reference specified.\n"); | ||
195 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
196 | } | ||
197 | } else { | ||
198 | PERROR("Invalid port direction specified.\n"); | ||
199 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
200 | } | ||
201 | } else { | ||
202 | PERROR("Invalid channel number.\n"); | ||
203 | err = ME_ERRNO_INVALID_CHANNEL; | ||
204 | } | ||
205 | |||
206 | break; | ||
207 | |||
208 | default: | ||
209 | PERROR("Invalid flags specified.\n"); | ||
210 | err = ME_ERRNO_INVALID_FLAGS; | ||
211 | } | ||
212 | |||
213 | if (!err) { | ||
214 | outl(mode, instance->ctrl_reg); | ||
215 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
216 | instance->reg_base, | ||
217 | instance->ctrl_reg - instance->reg_base, mode); | ||
218 | } | ||
219 | spin_unlock(instance->ctrl_reg_lock); | ||
220 | spin_unlock(&instance->subdevice_lock); | ||
221 | |||
222 | ME_SUBDEVICE_EXIT; | ||
223 | |||
224 | return err; | ||
225 | } | ||
226 | |||
227 | static int me4600_do_io_single_read(me_subdevice_t * subdevice, | ||
228 | struct file *filep, | ||
229 | int channel, | ||
230 | int *value, int time_out, int flags) | ||
231 | { | ||
232 | me4600_do_subdevice_t *instance; | ||
233 | int err = ME_ERRNO_SUCCESS; | ||
234 | uint32_t mode; | ||
235 | |||
236 | PDEBUG("executed.\n"); | ||
237 | |||
238 | instance = (me4600_do_subdevice_t *) subdevice; | ||
239 | |||
240 | ME_SUBDEVICE_ENTER; | ||
241 | |||
242 | spin_lock(&instance->subdevice_lock); | ||
243 | spin_lock(instance->ctrl_reg_lock); | ||
244 | mode = | ||
245 | inl(instance-> | ||
246 | ctrl_reg) & (ME4600_DIO_CTRL_BIT_MODE_0 | | ||
247 | ME4600_DIO_CTRL_BIT_MODE_1); | ||
248 | |||
249 | if (mode == ME4600_DIO_CTRL_BIT_MODE_0) { | ||
250 | switch (flags) { | ||
251 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
252 | if ((channel >= 0) && (channel < 8)) { | ||
253 | *value = | ||
254 | inl(instance->port_reg) & (0x1 << channel); | ||
255 | } else { | ||
256 | PERROR("Invalid bit number specified.\n"); | ||
257 | err = ME_ERRNO_INVALID_CHANNEL; | ||
258 | } | ||
259 | break; | ||
260 | |||
261 | case ME_IO_SINGLE_NO_FLAGS: | ||
262 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
263 | if (channel == 0) { | ||
264 | *value = inl(instance->port_reg) & 0xFF; | ||
265 | } else { | ||
266 | PERROR("Invalid byte number specified.\n"); | ||
267 | err = ME_ERRNO_INVALID_CHANNEL; | ||
268 | } | ||
269 | break; | ||
270 | |||
271 | default: | ||
272 | PERROR("Invalid flags specified.\n"); | ||
273 | err = ME_ERRNO_INVALID_FLAGS; | ||
274 | } | ||
275 | } else { | ||
276 | PERROR("Port not in output mode.\n"); | ||
277 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
278 | } | ||
279 | spin_unlock(instance->ctrl_reg_lock); | ||
280 | spin_unlock(&instance->subdevice_lock); | ||
281 | |||
282 | ME_SUBDEVICE_EXIT; | ||
283 | |||
284 | return err; | ||
285 | } | ||
286 | |||
287 | static int me4600_do_io_single_write(me_subdevice_t * subdevice, | ||
288 | struct file *filep, | ||
289 | int channel, | ||
290 | int value, int time_out, int flags) | ||
291 | { | ||
292 | me4600_do_subdevice_t *instance; | ||
293 | int err = ME_ERRNO_SUCCESS; | ||
294 | uint32_t byte; | ||
295 | uint32_t mode; | ||
296 | |||
297 | PDEBUG("executed.\n"); | ||
298 | |||
299 | instance = (me4600_do_subdevice_t *) subdevice; | ||
300 | |||
301 | ME_SUBDEVICE_ENTER; | ||
302 | |||
303 | spin_lock(&instance->subdevice_lock); | ||
304 | spin_lock(instance->ctrl_reg_lock); | ||
305 | mode = | ||
306 | inl(instance-> | ||
307 | ctrl_reg) & (ME4600_DIO_CTRL_BIT_MODE_0 | | ||
308 | ME4600_DIO_CTRL_BIT_MODE_1); | ||
309 | |||
310 | if (mode == ME4600_DIO_CTRL_BIT_MODE_0) { | ||
311 | switch (flags) { | ||
312 | |||
313 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
314 | if ((channel >= 0) && (channel < 8)) { | ||
315 | byte = inl(instance->port_reg) & 0xFF; | ||
316 | |||
317 | if (value) | ||
318 | byte |= 0x1 << channel; | ||
319 | else | ||
320 | byte &= ~(0x1 << channel); | ||
321 | |||
322 | outl(byte, instance->port_reg); | ||
323 | } else { | ||
324 | PERROR("Invalid bit number specified.\n"); | ||
325 | err = ME_ERRNO_INVALID_CHANNEL; | ||
326 | } | ||
327 | break; | ||
328 | |||
329 | case ME_IO_SINGLE_NO_FLAGS: | ||
330 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
331 | if (channel == 0) { | ||
332 | outl(value, instance->port_reg); | ||
333 | } else { | ||
334 | PERROR("Invalid byte number specified.\n"); | ||
335 | err = ME_ERRNO_INVALID_CHANNEL; | ||
336 | } | ||
337 | break; | ||
338 | |||
339 | default: | ||
340 | PERROR("Invalid flags specified.\n"); | ||
341 | err = ME_ERRNO_INVALID_FLAGS; | ||
342 | } | ||
343 | } else { | ||
344 | PERROR("Port not in output mode.\n"); | ||
345 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
346 | } | ||
347 | spin_unlock(instance->ctrl_reg_lock); | ||
348 | spin_unlock(&instance->subdevice_lock); | ||
349 | |||
350 | ME_SUBDEVICE_EXIT; | ||
351 | |||
352 | return err; | ||
353 | } | ||
354 | |||
355 | static int me4600_do_query_number_channels(me_subdevice_t * subdevice, | ||
356 | int *number) | ||
357 | { | ||
358 | PDEBUG("executed.\n"); | ||
359 | *number = 8; | ||
360 | return ME_ERRNO_SUCCESS; | ||
361 | } | ||
362 | |||
363 | static int me4600_do_query_subdevice_type(me_subdevice_t * subdevice, | ||
364 | int *type, int *subtype) | ||
365 | { | ||
366 | PDEBUG("executed.\n"); | ||
367 | *type = ME_TYPE_DO; | ||
368 | *subtype = ME_SUBTYPE_SINGLE; | ||
369 | return ME_ERRNO_SUCCESS; | ||
370 | } | ||
371 | |||
372 | static int me4600_do_query_subdevice_caps(me_subdevice_t * subdevice, int *caps) | ||
373 | { | ||
374 | PDEBUG("executed.\n"); | ||
375 | *caps = 0; | ||
376 | return ME_ERRNO_SUCCESS; | ||
377 | } | ||
378 | |||
379 | me4600_do_subdevice_t *me4600_do_constructor(uint32_t reg_base, | ||
380 | spinlock_t * ctrl_reg_lock) | ||
381 | { | ||
382 | me4600_do_subdevice_t *subdevice; | ||
383 | int err; | ||
384 | |||
385 | PDEBUG("executed.\n"); | ||
386 | |||
387 | /* Allocate memory for subdevice instance */ | ||
388 | subdevice = kmalloc(sizeof(me4600_do_subdevice_t), GFP_KERNEL); | ||
389 | |||
390 | if (!subdevice) { | ||
391 | PERROR("Cannot get memory for subdevice instance.\n"); | ||
392 | return NULL; | ||
393 | } | ||
394 | |||
395 | memset(subdevice, 0, sizeof(me4600_do_subdevice_t)); | ||
396 | |||
397 | /* Initialize subdevice base class */ | ||
398 | err = me_subdevice_init(&subdevice->base); | ||
399 | |||
400 | if (err) { | ||
401 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
402 | kfree(subdevice); | ||
403 | return NULL; | ||
404 | } | ||
405 | // Initialize spin locks. | ||
406 | spin_lock_init(&subdevice->subdevice_lock); | ||
407 | |||
408 | subdevice->ctrl_reg_lock = ctrl_reg_lock; | ||
409 | |||
410 | /* Save the subdevice index */ | ||
411 | subdevice->ctrl_reg = reg_base + ME4600_DIO_CTRL_REG; | ||
412 | subdevice->port_reg = reg_base + ME4600_DIO_PORT_0_REG; | ||
413 | #ifdef MEDEBUG_DEBUG_REG | ||
414 | subdevice->reg_base = reg_base; | ||
415 | #endif | ||
416 | |||
417 | /* Overload base class methods. */ | ||
418 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
419 | me4600_do_io_reset_subdevice; | ||
420 | subdevice->base.me_subdevice_io_single_config = | ||
421 | me4600_do_io_single_config; | ||
422 | subdevice->base.me_subdevice_io_single_read = me4600_do_io_single_read; | ||
423 | subdevice->base.me_subdevice_io_single_write = | ||
424 | me4600_do_io_single_write; | ||
425 | subdevice->base.me_subdevice_query_number_channels = | ||
426 | me4600_do_query_number_channels; | ||
427 | subdevice->base.me_subdevice_query_subdevice_type = | ||
428 | me4600_do_query_subdevice_type; | ||
429 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
430 | me4600_do_query_subdevice_caps; | ||
431 | |||
432 | return subdevice; | ||
433 | } | ||
diff --git a/drivers/staging/meilhaus/me4600_do.h b/drivers/staging/meilhaus/me4600_do.h new file mode 100644 index 000000000000..e8385648e925 --- /dev/null +++ b/drivers/staging/meilhaus/me4600_do.h | |||
@@ -0,0 +1,65 @@ | |||
1 | /** | ||
2 | * @file me4600_do.h | ||
3 | * | ||
4 | * @brief ME-4000 digital output subdevice class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME4600_DO_H_ | ||
28 | #define _ME4600_DO_H_ | ||
29 | |||
30 | #include "mesubdevice.h" | ||
31 | |||
32 | #ifdef __KERNEL__ | ||
33 | |||
34 | /** | ||
35 | * @brief The template subdevice class. | ||
36 | */ | ||
37 | typedef struct me4600_do_subdevice { | ||
38 | /* Inheritance */ | ||
39 | me_subdevice_t base; /**< The subdevice base class. */ | ||
40 | |||
41 | /* Attributes */ | ||
42 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
43 | spinlock_t *ctrl_reg_lock; /**< Spin lock to protect #ctrl_reg from concurrent access. */ | ||
44 | |||
45 | unsigned long port_reg; /**< Register holding the port status. */ | ||
46 | unsigned long ctrl_reg; /**< Register to configure the port direction. */ | ||
47 | #ifdef MEDEBUG_DEBUG_REG | ||
48 | unsigned long reg_base; | ||
49 | #endif | ||
50 | } me4600_do_subdevice_t; | ||
51 | |||
52 | /** | ||
53 | * @brief The constructor to generate a ME-4000 digital output subdevice instance. | ||
54 | * | ||
55 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
56 | * @param ctrl_reg_lock Spin lock protecting the control register. | ||
57 | * | ||
58 | * @return Pointer to new instance on success.\n | ||
59 | * NULL on error. | ||
60 | */ | ||
61 | me4600_do_subdevice_t *me4600_do_constructor(uint32_t reg_base, | ||
62 | spinlock_t * ctrl_reg_lock); | ||
63 | |||
64 | #endif | ||
65 | #endif | ||
diff --git a/drivers/staging/meilhaus/me4600_ext_irq.c b/drivers/staging/meilhaus/me4600_ext_irq.c new file mode 100644 index 000000000000..8a10dceae32a --- /dev/null +++ b/drivers/staging/meilhaus/me4600_ext_irq.c | |||
@@ -0,0 +1,467 @@ | |||
1 | /** | ||
2 | * @file me4600_ext_irq.c | ||
3 | * | ||
4 | * @brief ME-4000 external interrupt subdevice instance. | ||
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 | /* | ||
33 | * Includes | ||
34 | */ | ||
35 | #include <linux/module.h> | ||
36 | |||
37 | #include <linux/slab.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | #include <linux/interrupt.h> | ||
40 | #include <asm/io.h> | ||
41 | #include <linux/types.h> | ||
42 | #include <linux/version.h> | ||
43 | |||
44 | #include "medefines.h" | ||
45 | #include "meinternal.h" | ||
46 | #include "meerror.h" | ||
47 | |||
48 | #include "medebug.h" | ||
49 | #include "meids.h" | ||
50 | #include "me4600_reg.h" | ||
51 | #include "me4600_ai_reg.h" | ||
52 | #include "me4600_ext_irq_reg.h" | ||
53 | #include "me4600_ext_irq.h" | ||
54 | |||
55 | /* | ||
56 | * Defines | ||
57 | */ | ||
58 | |||
59 | /* | ||
60 | * Functions | ||
61 | */ | ||
62 | |||
63 | static int me4600_ext_irq_io_irq_start(me_subdevice_t * subdevice, | ||
64 | struct file *filep, | ||
65 | int channel, | ||
66 | int irq_source, | ||
67 | int irq_edge, int irq_arg, int flags) | ||
68 | { | ||
69 | me4600_ext_irq_subdevice_t *instance; | ||
70 | int err = ME_ERRNO_SUCCESS; | ||
71 | unsigned long cpu_flags; | ||
72 | uint32_t tmp; | ||
73 | |||
74 | PDEBUG("executed.\n"); | ||
75 | |||
76 | instance = (me4600_ext_irq_subdevice_t *) subdevice; | ||
77 | |||
78 | if (flags & ~ME_IO_IRQ_START_DIO_BIT) { | ||
79 | PERROR("Invalid flag specified.\n"); | ||
80 | return ME_ERRNO_INVALID_FLAGS; | ||
81 | } | ||
82 | |||
83 | if ((irq_edge != ME_IRQ_EDGE_RISING) | ||
84 | && (irq_edge != ME_IRQ_EDGE_FALLING) | ||
85 | && (irq_edge != ME_IRQ_EDGE_ANY) | ||
86 | ) { | ||
87 | PERROR("Invalid irq edge specified.\n"); | ||
88 | return ME_ERRNO_INVALID_IRQ_EDGE; | ||
89 | } | ||
90 | |||
91 | if (irq_source != ME_IRQ_SOURCE_DIO_LINE) { | ||
92 | PERROR("Invalid irq source specified.\n"); | ||
93 | return ME_ERRNO_INVALID_IRQ_SOURCE; | ||
94 | } | ||
95 | |||
96 | if (channel) { | ||
97 | PERROR("Invalid channel specified.\n"); | ||
98 | return ME_ERRNO_INVALID_CHANNEL; | ||
99 | } | ||
100 | |||
101 | ME_SUBDEVICE_ENTER; | ||
102 | |||
103 | spin_lock(&instance->subdevice_lock); | ||
104 | tmp = 0x0; //inl(instance->ext_irq_config_reg); | ||
105 | |||
106 | if (irq_edge == ME_IRQ_EDGE_RISING) { | ||
107 | //tmp &= ~ME4600_EXT_IRQ_CONFIG_MASK; | ||
108 | //tmp |= ME4600_EXT_IRQ_CONFIG_MASK_RISING; | ||
109 | } else if (irq_edge == ME_IRQ_EDGE_FALLING) { | ||
110 | //tmp &= ~ME4600_EXT_IRQ_CONFIG_MASK; | ||
111 | //tmp |= ME4600_EXT_IRQ_CONFIG_MASK_FALLING; | ||
112 | tmp = ME4600_EXT_IRQ_CONFIG_MASK_FALLING; | ||
113 | } else if (irq_edge == ME_IRQ_EDGE_ANY) { | ||
114 | //tmp &= ~ME4600_EXT_IRQ_CONFIG_MASK; | ||
115 | //tmp |= ME4600_EXT_IRQ_CONFIG_MASK_ANY; | ||
116 | tmp = ME4600_EXT_IRQ_CONFIG_MASK_ANY; | ||
117 | } | ||
118 | |||
119 | outl(tmp, instance->ext_irq_config_reg); | ||
120 | PDEBUG_REG("ext_irq_config_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
121 | instance->reg_base, | ||
122 | instance->ext_irq_config_reg - instance->reg_base, tmp); | ||
123 | |||
124 | spin_lock_irqsave(instance->ctrl_reg_lock, cpu_flags); | ||
125 | tmp = inl(instance->ctrl_reg); | ||
126 | tmp &= ~(ME4600_AI_CTRL_BIT_EX_IRQ | ME4600_AI_CTRL_BIT_EX_IRQ_RESET); | ||
127 | tmp |= ME4600_AI_CTRL_BIT_EX_IRQ; | ||
128 | outl(tmp, instance->ctrl_reg); | ||
129 | spin_unlock_irqrestore(instance->ctrl_reg_lock, cpu_flags); | ||
130 | instance->rised = 0; | ||
131 | spin_unlock(&instance->subdevice_lock); | ||
132 | |||
133 | ME_SUBDEVICE_EXIT; | ||
134 | |||
135 | return err; | ||
136 | } | ||
137 | |||
138 | static int me4600_ext_irq_io_irq_wait(me_subdevice_t * subdevice, | ||
139 | struct file *filep, | ||
140 | int channel, | ||
141 | int *irq_count, | ||
142 | int *value, int time_out, int flags) | ||
143 | { | ||
144 | me4600_ext_irq_subdevice_t *instance; | ||
145 | int err = ME_ERRNO_SUCCESS; | ||
146 | long t = 0; | ||
147 | unsigned long cpu_flags; | ||
148 | |||
149 | PDEBUG("executed.\n"); | ||
150 | |||
151 | instance = (me4600_ext_irq_subdevice_t *) subdevice; | ||
152 | |||
153 | if (flags) { | ||
154 | PERROR("Invalid flag specified.\n"); | ||
155 | return ME_ERRNO_INVALID_FLAGS; | ||
156 | } | ||
157 | |||
158 | if (channel) { | ||
159 | PERROR("Invalid channel specified.\n"); | ||
160 | return ME_ERRNO_INVALID_CHANNEL; | ||
161 | } | ||
162 | |||
163 | if (time_out < 0) { | ||
164 | PERROR("Invalid time_out specified.\n"); | ||
165 | return ME_ERRNO_INVALID_TIMEOUT; | ||
166 | } | ||
167 | |||
168 | if (time_out) { | ||
169 | t = (time_out * HZ) / 1000; | ||
170 | |||
171 | if (t == 0) | ||
172 | t = 1; | ||
173 | } | ||
174 | |||
175 | ME_SUBDEVICE_ENTER; | ||
176 | |||
177 | if (instance->rised <= 0) { | ||
178 | instance->rised = 0; | ||
179 | if (time_out) { | ||
180 | t = wait_event_interruptible_timeout(instance-> | ||
181 | wait_queue, | ||
182 | (instance->rised != | ||
183 | 0), t); | ||
184 | |||
185 | if (t == 0) { | ||
186 | PERROR | ||
187 | ("Wait on external interrupt timed out.\n"); | ||
188 | err = ME_ERRNO_TIMEOUT; | ||
189 | } | ||
190 | } else { | ||
191 | wait_event_interruptible(instance->wait_queue, | ||
192 | (instance->rised != 0)); | ||
193 | } | ||
194 | |||
195 | if (instance->rised < 0) { | ||
196 | PERROR("Wait on interrupt aborted by user.\n"); | ||
197 | err = ME_ERRNO_CANCELLED; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | if (signal_pending(current)) { | ||
202 | PERROR("Wait on external interrupt aborted by signal.\n"); | ||
203 | err = ME_ERRNO_SIGNAL; | ||
204 | } | ||
205 | |||
206 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
207 | instance->rised = 0; | ||
208 | *irq_count = instance->count; | ||
209 | *value = instance->value; | ||
210 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
211 | |||
212 | ME_SUBDEVICE_EXIT; | ||
213 | |||
214 | return err; | ||
215 | } | ||
216 | |||
217 | static int me4600_ext_irq_io_irq_stop(me_subdevice_t * subdevice, | ||
218 | struct file *filep, | ||
219 | int channel, int flags) | ||
220 | { | ||
221 | me4600_ext_irq_subdevice_t *instance; | ||
222 | int err = ME_ERRNO_SUCCESS; | ||
223 | unsigned long cpu_flags; | ||
224 | uint32_t tmp; | ||
225 | |||
226 | PDEBUG("executed.\n"); | ||
227 | |||
228 | instance = (me4600_ext_irq_subdevice_t *) subdevice; | ||
229 | |||
230 | if (flags) { | ||
231 | PERROR("Invalid flag specified.\n"); | ||
232 | return ME_ERRNO_INVALID_FLAGS; | ||
233 | } | ||
234 | |||
235 | if (channel) { | ||
236 | PERROR("Invalid channel specified.\n"); | ||
237 | return ME_ERRNO_INVALID_CHANNEL; | ||
238 | } | ||
239 | |||
240 | ME_SUBDEVICE_ENTER; | ||
241 | |||
242 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
243 | spin_lock(instance->ctrl_reg_lock); | ||
244 | tmp = inl(instance->ctrl_reg); | ||
245 | tmp &= ~(ME4600_AI_CTRL_BIT_EX_IRQ | ME4600_AI_CTRL_BIT_EX_IRQ_RESET); | ||
246 | outl(tmp, instance->ctrl_reg); | ||
247 | PDEBUG_REG("ctrl_regv outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
248 | instance->ctrl_reg - instance->reg_base, tmp); | ||
249 | spin_unlock(instance->ctrl_reg_lock); | ||
250 | instance->rised = -1; | ||
251 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
252 | wake_up_interruptible_all(&instance->wait_queue); | ||
253 | |||
254 | ME_SUBDEVICE_EXIT; | ||
255 | |||
256 | return err; | ||
257 | } | ||
258 | |||
259 | static int me4600_ext_irq_io_reset_subdevice(me_subdevice_t * subdevice, | ||
260 | struct file *filep, int flags) | ||
261 | { | ||
262 | me4600_ext_irq_subdevice_t *instance; | ||
263 | unsigned long cpu_flags; | ||
264 | uint32_t tmp; | ||
265 | |||
266 | PDEBUG("executed.\n"); | ||
267 | |||
268 | instance = (me4600_ext_irq_subdevice_t *) subdevice; | ||
269 | |||
270 | if (flags) { | ||
271 | PERROR("Invalid flag specified.\n"); | ||
272 | return ME_ERRNO_INVALID_FLAGS; | ||
273 | } | ||
274 | |||
275 | ME_SUBDEVICE_ENTER; | ||
276 | |||
277 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
278 | spin_lock(instance->ctrl_reg_lock); | ||
279 | tmp = inl(instance->ctrl_reg); | ||
280 | tmp &= ~(ME4600_AI_CTRL_BIT_EX_IRQ | ME4600_AI_CTRL_BIT_EX_IRQ_RESET); | ||
281 | outl(tmp, instance->ctrl_reg); | ||
282 | PDEBUG_REG("ctrl_regv outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
283 | instance->ctrl_reg - instance->reg_base, tmp); | ||
284 | spin_unlock(instance->ctrl_reg_lock); | ||
285 | instance->rised = -1; | ||
286 | instance->count = 0; | ||
287 | outl(ME4600_EXT_IRQ_CONFIG_MASK_ANY, instance->ext_irq_config_reg); | ||
288 | PDEBUG_REG("ext_irq_config_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
289 | instance->reg_base, | ||
290 | instance->ext_irq_config_reg - instance->reg_base, | ||
291 | ME4600_EXT_IRQ_CONFIG_MASK_ANY); | ||
292 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
293 | wake_up_interruptible_all(&instance->wait_queue); | ||
294 | |||
295 | ME_SUBDEVICE_EXIT; | ||
296 | |||
297 | return ME_ERRNO_SUCCESS; | ||
298 | } | ||
299 | |||
300 | static void me4600_ext_irq_destructor(struct me_subdevice *subdevice) | ||
301 | { | ||
302 | me4600_ext_irq_subdevice_t *instance; | ||
303 | |||
304 | PDEBUG("executed.\n"); | ||
305 | instance = (me4600_ext_irq_subdevice_t *) subdevice; | ||
306 | me_subdevice_deinit(&instance->base); | ||
307 | free_irq(instance->irq, instance); | ||
308 | kfree(instance); | ||
309 | } | ||
310 | |||
311 | static int me4600_ext_irq_query_number_channels(me_subdevice_t * subdevice, | ||
312 | int *number) | ||
313 | { | ||
314 | PDEBUG("executed.\n"); | ||
315 | *number = 1; | ||
316 | return ME_ERRNO_SUCCESS; | ||
317 | } | ||
318 | |||
319 | static int me4600_ext_irq_query_subdevice_type(me_subdevice_t * subdevice, | ||
320 | int *type, int *subtype) | ||
321 | { | ||
322 | PDEBUG("executed.\n"); | ||
323 | *type = ME_TYPE_EXT_IRQ; | ||
324 | *subtype = ME_SUBTYPE_SINGLE; | ||
325 | return ME_ERRNO_SUCCESS; | ||
326 | } | ||
327 | |||
328 | static int me4600_ext_irq_query_subdevice_caps(me_subdevice_t * subdevice, | ||
329 | int *caps) | ||
330 | { | ||
331 | PDEBUG("executed.\n"); | ||
332 | *caps = | ||
333 | ME_CAPS_EXT_IRQ_EDGE_RISING | ME_CAPS_EXT_IRQ_EDGE_FALLING | | ||
334 | ME_CAPS_EXT_IRQ_EDGE_ANY; | ||
335 | return ME_ERRNO_SUCCESS; | ||
336 | } | ||
337 | |||
338 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) | ||
339 | static irqreturn_t me4600_ext_irq_isr(int irq, void *dev_id) | ||
340 | #else | ||
341 | static irqreturn_t me4600_ext_irq_isr(int irq, void *dev_id, | ||
342 | struct pt_regs *regs) | ||
343 | #endif | ||
344 | { | ||
345 | me4600_ext_irq_subdevice_t *instance; | ||
346 | uint32_t ctrl; | ||
347 | uint32_t irq_status; | ||
348 | |||
349 | instance = (me4600_ext_irq_subdevice_t *) dev_id; | ||
350 | |||
351 | if (irq != instance->irq) { | ||
352 | PERROR("Incorrect interrupt num: %d.\n", irq); | ||
353 | return IRQ_NONE; | ||
354 | } | ||
355 | |||
356 | irq_status = inl(instance->irq_status_reg); | ||
357 | if (!(irq_status & ME4600_IRQ_STATUS_BIT_EX)) { | ||
358 | PINFO("%ld Shared interrupt. %s(): irq_status_reg=0x%04X\n", | ||
359 | jiffies, __FUNCTION__, irq_status); | ||
360 | return IRQ_NONE; | ||
361 | } | ||
362 | |||
363 | PDEBUG("executed.\n"); | ||
364 | |||
365 | spin_lock(&instance->subdevice_lock); | ||
366 | instance->rised = 1; | ||
367 | instance->value = inl(instance->ext_irq_value_reg); | ||
368 | instance->count++; | ||
369 | |||
370 | spin_lock(instance->ctrl_reg_lock); | ||
371 | ctrl = inl(instance->ctrl_reg); | ||
372 | ctrl |= ME4600_AI_CTRL_BIT_EX_IRQ_RESET; | ||
373 | outl(ctrl, instance->ctrl_reg); | ||
374 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
375 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
376 | ctrl &= ~ME4600_AI_CTRL_BIT_EX_IRQ_RESET; | ||
377 | outl(ctrl, instance->ctrl_reg); | ||
378 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
379 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
380 | spin_unlock(instance->ctrl_reg_lock); | ||
381 | |||
382 | spin_unlock(&instance->subdevice_lock); | ||
383 | wake_up_interruptible_all(&instance->wait_queue); | ||
384 | |||
385 | return IRQ_HANDLED; | ||
386 | } | ||
387 | |||
388 | me4600_ext_irq_subdevice_t *me4600_ext_irq_constructor(uint32_t reg_base, | ||
389 | int irq, | ||
390 | spinlock_t * | ||
391 | ctrl_reg_lock) | ||
392 | { | ||
393 | me4600_ext_irq_subdevice_t *subdevice; | ||
394 | int err; | ||
395 | |||
396 | PDEBUG("executed.\n"); | ||
397 | |||
398 | /* Allocate memory for subdevice instance */ | ||
399 | subdevice = kmalloc(sizeof(me4600_ext_irq_subdevice_t), GFP_KERNEL); | ||
400 | |||
401 | if (!subdevice) { | ||
402 | PERROR("Cannot get memory for subdevice instance.\n"); | ||
403 | return NULL; | ||
404 | } | ||
405 | |||
406 | memset(subdevice, 0, sizeof(me4600_ext_irq_subdevice_t)); | ||
407 | |||
408 | /* Initialize subdevice base class */ | ||
409 | err = me_subdevice_init(&subdevice->base); | ||
410 | |||
411 | if (err) { | ||
412 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
413 | kfree(subdevice); | ||
414 | return NULL; | ||
415 | } | ||
416 | // Initialize spin locks. | ||
417 | spin_lock_init(&subdevice->subdevice_lock); | ||
418 | |||
419 | subdevice->ctrl_reg_lock = ctrl_reg_lock; | ||
420 | |||
421 | /* Initialize wait queue */ | ||
422 | init_waitqueue_head(&subdevice->wait_queue); | ||
423 | |||
424 | /* Register interrupt */ | ||
425 | subdevice->irq = irq; | ||
426 | |||
427 | if (request_irq(subdevice->irq, me4600_ext_irq_isr, | ||
428 | #ifdef IRQF_DISABLED | ||
429 | IRQF_DISABLED | IRQF_SHARED, | ||
430 | #else | ||
431 | SA_INTERRUPT | SA_SHIRQ, | ||
432 | #endif | ||
433 | ME4600_NAME, subdevice)) { | ||
434 | PERROR("Cannot register interrupt.\n"); | ||
435 | kfree(subdevice); | ||
436 | return NULL; | ||
437 | } | ||
438 | PINFO("Registered irq=%d.\n", subdevice->irq); | ||
439 | |||
440 | /* Initialize registers */ | ||
441 | subdevice->irq_status_reg = reg_base + ME4600_IRQ_STATUS_REG; | ||
442 | subdevice->ctrl_reg = reg_base + ME4600_AI_CTRL_REG; | ||
443 | subdevice->ext_irq_config_reg = reg_base + ME4600_EXT_IRQ_CONFIG_REG; | ||
444 | subdevice->ext_irq_value_reg = reg_base + ME4600_EXT_IRQ_VALUE_REG; | ||
445 | #ifdef MEDEBUG_DEBUG_REG | ||
446 | subdevice->reg_base = reg_base; | ||
447 | #endif | ||
448 | |||
449 | /* Override base class methods. */ | ||
450 | subdevice->base.me_subdevice_destructor = me4600_ext_irq_destructor; | ||
451 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
452 | me4600_ext_irq_io_reset_subdevice; | ||
453 | subdevice->base.me_subdevice_io_irq_start = me4600_ext_irq_io_irq_start; | ||
454 | subdevice->base.me_subdevice_io_irq_wait = me4600_ext_irq_io_irq_wait; | ||
455 | subdevice->base.me_subdevice_io_irq_stop = me4600_ext_irq_io_irq_stop; | ||
456 | subdevice->base.me_subdevice_query_number_channels = | ||
457 | me4600_ext_irq_query_number_channels; | ||
458 | subdevice->base.me_subdevice_query_subdevice_type = | ||
459 | me4600_ext_irq_query_subdevice_type; | ||
460 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
461 | me4600_ext_irq_query_subdevice_caps; | ||
462 | |||
463 | subdevice->rised = 0; | ||
464 | subdevice->count = 0; | ||
465 | |||
466 | return subdevice; | ||
467 | } | ||
diff --git a/drivers/staging/meilhaus/me4600_ext_irq.h b/drivers/staging/meilhaus/me4600_ext_irq.h new file mode 100644 index 000000000000..3c7b27f9e5dc --- /dev/null +++ b/drivers/staging/meilhaus/me4600_ext_irq.h | |||
@@ -0,0 +1,78 @@ | |||
1 | /** | ||
2 | * @file me4600_ext_irq.h | ||
3 | * | ||
4 | * @brief Meilhaus ME-4000 external interrupt subdevice class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME4600_EXT_IRQ_H_ | ||
28 | #define _ME4600_EXT_IRQ_H_ | ||
29 | |||
30 | #include "mesubdevice.h" | ||
31 | |||
32 | #ifdef __KERNEL__ | ||
33 | |||
34 | /** | ||
35 | * @brief The subdevice class. | ||
36 | */ | ||
37 | typedef struct me4600_ext_irq_subdevice { | ||
38 | /* Inheritance */ | ||
39 | me_subdevice_t base; /**< The subdevice base class. */ | ||
40 | |||
41 | /* Attributes */ | ||
42 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
43 | spinlock_t *ctrl_reg_lock; /**< Spin lock to protect #ctrl_reg from concurrent access. */ | ||
44 | |||
45 | wait_queue_head_t wait_queue; | ||
46 | |||
47 | int irq; | ||
48 | |||
49 | int rised; | ||
50 | int value; | ||
51 | int count; | ||
52 | |||
53 | unsigned long ctrl_reg; | ||
54 | unsigned long irq_status_reg; | ||
55 | unsigned long ext_irq_config_reg; | ||
56 | unsigned long ext_irq_value_reg; | ||
57 | #ifdef MEDEBUG_DEBUG_REG | ||
58 | unsigned long reg_base; | ||
59 | #endif | ||
60 | } me4600_ext_irq_subdevice_t; | ||
61 | |||
62 | /** | ||
63 | * @brief The constructor to generate a external interrupt subdevice instance. | ||
64 | * | ||
65 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
66 | * @param irq The interrupt number assigned by the PCI BIOS. | ||
67 | * @param ctrl_reg_lock Pointer to spin lock protecting the control register from concurrent access. | ||
68 | * | ||
69 | * @return Pointer to new instance on success.\n | ||
70 | * NULL on error. | ||
71 | */ | ||
72 | me4600_ext_irq_subdevice_t *me4600_ext_irq_constructor(uint32_t reg_base, | ||
73 | int irq, | ||
74 | spinlock_t * | ||
75 | ctrl_reg_lock); | ||
76 | |||
77 | #endif | ||
78 | #endif | ||
diff --git a/drivers/staging/meilhaus/me4600_ext_irq_reg.h b/drivers/staging/meilhaus/me4600_ext_irq_reg.h new file mode 100644 index 000000000000..898e1e74d9e7 --- /dev/null +++ b/drivers/staging/meilhaus/me4600_ext_irq_reg.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /** | ||
2 | * @file me4600_ext_irq_reg.h | ||
3 | * | ||
4 | * @brief ME-4000 external interrupt subdevice register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME4600_EXT_IRQ_REG_H_ | ||
28 | #define _ME4600_EXT_IRQ_REG_H_ | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | #define ME4600_EXT_IRQ_CONFIG_REG 0xCC // R/_ | ||
33 | #define ME4600_EXT_IRQ_VALUE_REG 0xD0 // R/_ | ||
34 | |||
35 | #define ME4600_EXT_IRQ_CONFIG_MASK_RISING 0x0 | ||
36 | #define ME4600_EXT_IRQ_CONFIG_MASK_FALLING 0x1 | ||
37 | #define ME4600_EXT_IRQ_CONFIG_MASK_ANY 0x3 | ||
38 | #define ME4600_EXT_IRQ_CONFIG_MASK 0x3 | ||
39 | |||
40 | #endif | ||
41 | #endif | ||
diff --git a/drivers/staging/meilhaus/me4600_reg.h b/drivers/staging/meilhaus/me4600_reg.h new file mode 100644 index 000000000000..ae152bbc6a3d --- /dev/null +++ b/drivers/staging/meilhaus/me4600_reg.h | |||
@@ -0,0 +1,46 @@ | |||
1 | /** | ||
2 | * @file me4600_reg.h | ||
3 | * | ||
4 | * @brief ME-4000 register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME4600_REG_H_ | ||
28 | #define _ME4600_REG_H_ | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | #define ME4600_IRQ_STATUS_REG 0x9C // R/_ | ||
33 | |||
34 | #define ME4600_IRQ_STATUS_BIT_EX 0x01 | ||
35 | #define ME4600_IRQ_STATUS_BIT_LE 0x02 | ||
36 | #define ME4600_IRQ_STATUS_BIT_AI_HF 0x04 | ||
37 | #define ME4600_IRQ_STATUS_BIT_AO_0_HF 0x08 | ||
38 | #define ME4600_IRQ_STATUS_BIT_AO_1_HF 0x10 | ||
39 | #define ME4600_IRQ_STATUS_BIT_AO_2_HF 0x20 | ||
40 | #define ME4600_IRQ_STATUS_BIT_AO_3_HF 0x40 | ||
41 | #define ME4600_IRQ_STATUS_BIT_SC 0x80 | ||
42 | |||
43 | #define ME4600_IRQ_STATUS_BIT_AO_HF ME4600_IRQ_STATUS_BIT_AO_0_HF | ||
44 | |||
45 | #endif | ||
46 | #endif | ||
diff --git a/drivers/staging/meilhaus/me6000_ao.c b/drivers/staging/meilhaus/me6000_ao.c new file mode 100644 index 000000000000..3f5ff6d1b991 --- /dev/null +++ b/drivers/staging/meilhaus/me6000_ao.c | |||
@@ -0,0 +1,3739 @@ | |||
1 | /** | ||
2 | * @file me6000_ao.c | ||
3 | * | ||
4 | * @brief ME-6000 analog output subdevice instance. | ||
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 | /* Includes | ||
33 | */ | ||
34 | #include <linux/version.h> | ||
35 | #include <linux/module.h> | ||
36 | |||
37 | #include <linux/slab.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | #include <asm/io.h> | ||
40 | #include <asm/uaccess.h> | ||
41 | #include <linux/types.h> | ||
42 | #include <linux/interrupt.h> | ||
43 | #include <linux/delay.h> | ||
44 | |||
45 | #include <linux/workqueue.h> | ||
46 | |||
47 | #include "medefines.h" | ||
48 | #include "meinternal.h" | ||
49 | #include "meerror.h" | ||
50 | |||
51 | #include "medebug.h" | ||
52 | #include "meids.h" | ||
53 | #include "me6000_reg.h" | ||
54 | #include "me6000_ao_reg.h" | ||
55 | #include "me6000_ao.h" | ||
56 | |||
57 | /* Defines | ||
58 | */ | ||
59 | |||
60 | static int me6000_ao_query_range_by_min_max(me_subdevice_t * subdevice, | ||
61 | int unit, | ||
62 | int *min, | ||
63 | int *max, int *maxdata, int *range); | ||
64 | |||
65 | static int me6000_ao_query_number_ranges(me_subdevice_t * subdevice, | ||
66 | int unit, int *count); | ||
67 | |||
68 | static int me6000_ao_query_range_info(me_subdevice_t * subdevice, | ||
69 | int range, | ||
70 | int *unit, | ||
71 | int *min, int *max, int *maxdata); | ||
72 | |||
73 | static int me6000_ao_query_timer(me_subdevice_t * subdevice, | ||
74 | int timer, | ||
75 | int *base_frequency, | ||
76 | long long *min_ticks, long long *max_ticks); | ||
77 | |||
78 | static int me6000_ao_query_number_channels(me_subdevice_t * subdevice, | ||
79 | int *number); | ||
80 | |||
81 | static int me6000_ao_query_subdevice_type(me_subdevice_t * subdevice, | ||
82 | int *type, int *subtype); | ||
83 | |||
84 | static int me6000_ao_query_subdevice_caps(me_subdevice_t * subdevice, | ||
85 | int *caps); | ||
86 | |||
87 | static int me6000_ao_query_subdevice_caps_args(struct me_subdevice *subdevice, | ||
88 | int cap, int *args, int count); | ||
89 | |||
90 | /** Remove subdevice. */ | ||
91 | static void me6000_ao_destructor(struct me_subdevice *subdevice); | ||
92 | |||
93 | /** Reset subdevice. Stop all actions. Reset registry. Disable FIFO. Set output to 0V and status to 'none'. */ | ||
94 | static int me6000_ao_io_reset_subdevice(me_subdevice_t * subdevice, | ||
95 | struct file *filep, int flags); | ||
96 | |||
97 | /** Set output as single */ | ||
98 | static int me6000_ao_io_single_config(me_subdevice_t * subdevice, | ||
99 | struct file *filep, | ||
100 | int channel, | ||
101 | int single_config, | ||
102 | int ref, | ||
103 | int trig_chan, | ||
104 | int trig_type, int trig_edge, int flags); | ||
105 | |||
106 | /** Pass to user actual value of output. */ | ||
107 | static int me6000_ao_io_single_read(me_subdevice_t * subdevice, | ||
108 | struct file *filep, | ||
109 | int channel, | ||
110 | int *value, int time_out, int flags); | ||
111 | |||
112 | /** Write to output requed value. */ | ||
113 | static int me6000_ao_io_single_write(me_subdevice_t * subdevice, | ||
114 | struct file *filep, | ||
115 | int channel, | ||
116 | int value, int time_out, int flags); | ||
117 | |||
118 | /** Set output as streamed device. */ | ||
119 | static int me6000_ao_io_stream_config(me_subdevice_t * subdevice, | ||
120 | struct file *filep, | ||
121 | meIOStreamConfig_t * config_list, | ||
122 | int count, | ||
123 | meIOStreamTrigger_t * trigger, | ||
124 | int fifo_irq_threshold, int flags); | ||
125 | |||
126 | /** Wait for / Check empty space in buffer. */ | ||
127 | static int me6000_ao_io_stream_new_values(me_subdevice_t * subdevice, | ||
128 | struct file *filep, | ||
129 | int time_out, int *count, int flags); | ||
130 | |||
131 | /** Start streaming. */ | ||
132 | static int me6000_ao_io_stream_start(me_subdevice_t * subdevice, | ||
133 | struct file *filep, | ||
134 | int start_mode, int time_out, int flags); | ||
135 | |||
136 | /** Check actual state. / Wait for end. */ | ||
137 | static int me6000_ao_io_stream_status(me_subdevice_t * subdevice, | ||
138 | struct file *filep, | ||
139 | int wait, | ||
140 | int *status, int *values, int flags); | ||
141 | |||
142 | /** Stop streaming. */ | ||
143 | static int me6000_ao_io_stream_stop(me_subdevice_t * subdevice, | ||
144 | struct file *filep, | ||
145 | int stop_mode, int flags); | ||
146 | |||
147 | /** Write datas to buffor. */ | ||
148 | static int me6000_ao_io_stream_write(me_subdevice_t * subdevice, | ||
149 | struct file *filep, | ||
150 | int write_mode, | ||
151 | int *values, int *count, int flags); | ||
152 | |||
153 | /** Interrupt handler. Copy from buffer to FIFO. */ | ||
154 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) | ||
155 | static irqreturn_t me6000_ao_isr(int irq, void *dev_id); | ||
156 | #else | ||
157 | static irqreturn_t me6000_ao_isr(int irq, void *dev_id, struct pt_regs *regs); | ||
158 | #endif | ||
159 | |||
160 | /** Copy data from circular buffer to fifo (fast) in wraparound mode. */ | ||
161 | int inline ao_write_data_wraparound(me6000_ao_subdevice_t * instance, int count, | ||
162 | int start_pos); | ||
163 | |||
164 | /** Copy data from circular buffer to fifo (fast).*/ | ||
165 | int inline ao_write_data(me6000_ao_subdevice_t * instance, int count, | ||
166 | int start_pos); | ||
167 | |||
168 | /** Copy data from circular buffer to fifo (slow).*/ | ||
169 | int inline ao_write_data_pooling(me6000_ao_subdevice_t * instance, int count, | ||
170 | int start_pos); | ||
171 | |||
172 | /** Copy data from user space to circular buffer. */ | ||
173 | int inline ao_get_data_from_user(me6000_ao_subdevice_t * instance, int count, | ||
174 | int *user_values); | ||
175 | |||
176 | /** Stop presentation. Preserve FIFOs. */ | ||
177 | int inline ao_stop_immediately(me6000_ao_subdevice_t * instance); | ||
178 | |||
179 | /** Function for checking timeout in non-blocking mode. */ | ||
180 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) | ||
181 | static void me6000_ao_work_control_task(void *subdevice); | ||
182 | #else | ||
183 | static void me6000_ao_work_control_task(struct work_struct *work); | ||
184 | #endif | ||
185 | |||
186 | /* Functions | ||
187 | */ | ||
188 | |||
189 | static int me6000_ao_io_reset_subdevice(me_subdevice_t * subdevice, | ||
190 | struct file *filep, int flags) | ||
191 | { | ||
192 | me6000_ao_subdevice_t *instance; | ||
193 | int err = ME_ERRNO_SUCCESS; | ||
194 | uint32_t tmp; | ||
195 | uint32_t ctrl; | ||
196 | |||
197 | instance = (me6000_ao_subdevice_t *) subdevice; | ||
198 | |||
199 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
200 | |||
201 | if (flags) { | ||
202 | PERROR("Invalid flag specified.\n"); | ||
203 | return ME_ERRNO_INVALID_FLAGS; | ||
204 | } | ||
205 | |||
206 | ME_SUBDEVICE_ENTER; | ||
207 | |||
208 | instance->status = ao_status_none; | ||
209 | instance->ao_control_task_flag = 0; | ||
210 | cancel_delayed_work(&instance->ao_control_task); | ||
211 | instance->timeout.delay = 0; | ||
212 | instance->timeout.start_time = jiffies; | ||
213 | |||
214 | //Stop state machine. | ||
215 | err = ao_stop_immediately(instance); | ||
216 | |||
217 | //Remove from synchronous start. | ||
218 | spin_lock(instance->preload_reg_lock); | ||
219 | tmp = inl(instance->preload_reg); | ||
220 | tmp &= | ||
221 | ~((ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG) << instance-> | ||
222 | ao_idx); | ||
223 | outl(tmp, instance->preload_reg); | ||
224 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
225 | instance->preload_reg - instance->reg_base, tmp); | ||
226 | *instance->preload_flags &= | ||
227 | ~((ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG) << instance-> | ||
228 | ao_idx); | ||
229 | |||
230 | //Reset triggering flag | ||
231 | *instance->triggering_flags &= ~(0x1 << instance->ao_idx); | ||
232 | spin_unlock(instance->preload_reg_lock); | ||
233 | |||
234 | if (instance->fifo) { | ||
235 | //Set single mode, dissable FIFO, dissable external trigger, block interrupt. | ||
236 | ctrl = ME6000_AO_MODE_SINGLE; | ||
237 | |||
238 | //Block ISM. | ||
239 | ctrl |= | ||
240 | (ME6000_AO_CTRL_BIT_STOP | | ||
241 | ME6000_AO_CTRL_BIT_IMMEDIATE_STOP); | ||
242 | |||
243 | outl(ctrl, instance->ctrl_reg); | ||
244 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
245 | instance->reg_base, | ||
246 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
247 | //Set speed | ||
248 | outl(ME6000_AO_MIN_CHAN_TICKS - 1, instance->timer_reg); | ||
249 | //Reset interrupt latch | ||
250 | inl(instance->irq_reset_reg); | ||
251 | } | ||
252 | |||
253 | instance->hardware_stop_delay = HZ / 10; //100ms | ||
254 | |||
255 | //Set output to 0V | ||
256 | outl(0x8000, instance->single_reg); | ||
257 | PDEBUG_REG("single_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
258 | instance->single_reg - instance->reg_base, 0x8000); | ||
259 | |||
260 | instance->circ_buf.head = 0; | ||
261 | instance->circ_buf.tail = 0; | ||
262 | instance->preloaded_count = 0; | ||
263 | instance->data_count = 0; | ||
264 | instance->single_value = 0x8000; | ||
265 | instance->single_value_in_fifo = 0x8000; | ||
266 | |||
267 | //Set status to signal that device is unconfigured. | ||
268 | instance->status = ao_status_none; | ||
269 | //Signal reset if user is on wait. | ||
270 | wake_up_interruptible_all(&instance->wait_queue); | ||
271 | |||
272 | ME_SUBDEVICE_EXIT; | ||
273 | |||
274 | return err; | ||
275 | } | ||
276 | |||
277 | static int me6000_ao_io_single_config(me_subdevice_t * subdevice, | ||
278 | struct file *filep, | ||
279 | int channel, | ||
280 | int single_config, | ||
281 | int ref, | ||
282 | int trig_chan, | ||
283 | int trig_type, int trig_edge, int flags) | ||
284 | { | ||
285 | me6000_ao_subdevice_t *instance; | ||
286 | int err = ME_ERRNO_SUCCESS; | ||
287 | uint32_t ctrl; | ||
288 | uint32_t sync; | ||
289 | unsigned long cpu_flags; | ||
290 | |||
291 | instance = (me6000_ao_subdevice_t *) subdevice; | ||
292 | |||
293 | PDEBUG("executed. ID=%d\n", instance->ao_idx); | ||
294 | |||
295 | // Checking parameters | ||
296 | if (flags) { | ||
297 | PERROR | ||
298 | ("Invalid flag specified. Must be ME_IO_SINGLE_CONFIG_NO_FLAGS.\n"); | ||
299 | return ME_ERRNO_INVALID_FLAGS; | ||
300 | } | ||
301 | |||
302 | if (instance->fifo) { //Stream hardware (with or without fifo) | ||
303 | if ((trig_edge == ME_TRIG_TYPE_SW) | ||
304 | && (trig_edge != ME_TRIG_EDGE_NONE)) { | ||
305 | PERROR | ||
306 | ("Invalid trigger edge. Software trigger has not edge.\n"); | ||
307 | return ME_ERRNO_INVALID_TRIG_EDGE; | ||
308 | } | ||
309 | |||
310 | if (trig_type == ME_TRIG_TYPE_EXT_DIGITAL) { | ||
311 | switch (trig_edge) { | ||
312 | case ME_TRIG_EDGE_ANY: | ||
313 | case ME_TRIG_EDGE_RISING: | ||
314 | case ME_TRIG_EDGE_FALLING: | ||
315 | break; | ||
316 | |||
317 | default: | ||
318 | PERROR("Invalid trigger edge.\n"); | ||
319 | return ME_ERRNO_INVALID_TRIG_EDGE; | ||
320 | } | ||
321 | } | ||
322 | |||
323 | if ((trig_type != ME_TRIG_TYPE_SW) | ||
324 | && (trig_type != ME_TRIG_TYPE_EXT_DIGITAL)) { | ||
325 | PERROR | ||
326 | ("Invalid trigger type. Trigger must be software or digital.\n"); | ||
327 | return ME_ERRNO_INVALID_TRIG_TYPE; | ||
328 | } | ||
329 | } else { //Single | ||
330 | if (trig_edge != ME_TRIG_EDGE_NONE) { | ||
331 | PERROR | ||
332 | ("Invalid trigger edge. Single output trigger hasn't own edge.\n"); | ||
333 | return ME_ERRNO_INVALID_TRIG_EDGE; | ||
334 | } | ||
335 | |||
336 | if (trig_type != ME_TRIG_TYPE_SW) { | ||
337 | PERROR | ||
338 | ("Invalid trigger type. Trigger must be software.\n"); | ||
339 | return ME_ERRNO_INVALID_TRIG_TYPE; | ||
340 | } | ||
341 | |||
342 | } | ||
343 | |||
344 | if ((trig_chan != ME_TRIG_CHAN_DEFAULT) | ||
345 | && (trig_chan != ME_TRIG_CHAN_SYNCHRONOUS)) { | ||
346 | PERROR("Invalid trigger channel specified.\n"); | ||
347 | return ME_ERRNO_INVALID_TRIG_CHAN; | ||
348 | } | ||
349 | /* | ||
350 | if ((trig_type == ME_TRIG_TYPE_EXT_DIGITAL) && (trig_chan != ME_TRIG_CHAN_SYNCHRONOUS)) | ||
351 | { | ||
352 | PERROR("Invalid trigger channel specified. Must be synchronous when digital is choose.\n"); | ||
353 | return ME_ERRNO_INVALID_TRIG_CHAN; | ||
354 | } | ||
355 | */ | ||
356 | if (ref != ME_REF_AO_GROUND) { | ||
357 | PERROR | ||
358 | ("Invalid reference. Analog outputs have to have got REF_AO_GROUND.\n"); | ||
359 | return ME_ERRNO_INVALID_REF; | ||
360 | } | ||
361 | |||
362 | if (single_config != 0) { | ||
363 | PERROR | ||
364 | ("Invalid single config specified. Only one range for anlog outputs is available.\n"); | ||
365 | return ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
366 | } | ||
367 | |||
368 | if (channel != 0) { | ||
369 | PERROR | ||
370 | ("Invalid channel number specified. Analog output have only one channel.\n"); | ||
371 | return ME_ERRNO_INVALID_CHANNEL; | ||
372 | } | ||
373 | |||
374 | ME_SUBDEVICE_ENTER; | ||
375 | |||
376 | //Subdevice running in stream mode! | ||
377 | if ((instance->status >= ao_status_stream_run_wait) | ||
378 | && (instance->status < ao_status_stream_end)) { | ||
379 | PERROR("Subdevice is busy.\n"); | ||
380 | ME_SUBDEVICE_EXIT; | ||
381 | |||
382 | return ME_ERRNO_SUBDEVICE_BUSY; | ||
383 | } | ||
384 | /// @note For single all calls (config and write) are erasing previous state! | ||
385 | |||
386 | instance->status = ao_status_none; | ||
387 | |||
388 | // Correct single mirrors | ||
389 | instance->single_value_in_fifo = instance->single_value; | ||
390 | |||
391 | //Stop device | ||
392 | err = ao_stop_immediately(instance); | ||
393 | if (err) { | ||
394 | PERROR_CRITICAL("FSM IS BUSY!\n"); | ||
395 | ME_SUBDEVICE_EXIT; | ||
396 | |||
397 | return ME_ERRNO_SUBDEVICE_BUSY; | ||
398 | } | ||
399 | |||
400 | if (instance->fifo) { // Set control register. | ||
401 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
402 | // Set stop bit. Stop streaming mode (If running.). | ||
403 | ctrl = inl(instance->ctrl_reg); | ||
404 | //Reset all bits. | ||
405 | ctrl = | ||
406 | ME6000_AO_CTRL_BIT_IMMEDIATE_STOP | ME6000_AO_CTRL_BIT_STOP; | ||
407 | if (trig_type == ME_TRIG_TYPE_EXT_DIGITAL) { | ||
408 | PINFO("External digital trigger.\n"); | ||
409 | |||
410 | if (trig_edge == ME_TRIG_EDGE_ANY) { | ||
411 | // ctrl |= ME6000_AO_CTRL_BIT_EX_TRIG_EDGE | ME6000_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH; | ||
412 | instance->ctrl_trg = | ||
413 | ME6000_AO_CTRL_BIT_EX_TRIG_EDGE | | ||
414 | ME6000_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH; | ||
415 | } else if (trig_edge == ME_TRIG_EDGE_FALLING) { | ||
416 | // ctrl |= ME6000_AO_CTRL_BIT_EX_TRIG_EDGE; | ||
417 | instance->ctrl_trg = | ||
418 | ME6000_AO_CTRL_BIT_EX_TRIG_EDGE; | ||
419 | } else if (trig_edge == ME_TRIG_EDGE_RISING) { | ||
420 | instance->ctrl_trg = 0x0; | ||
421 | } | ||
422 | } else if (trig_type == ME_TRIG_TYPE_SW) { | ||
423 | PDEBUG("SOFTWARE TRIGGER\n"); | ||
424 | instance->ctrl_trg = 0x0; | ||
425 | } | ||
426 | outl(ctrl, instance->ctrl_reg); | ||
427 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
428 | instance->reg_base, | ||
429 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
430 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
431 | } else { | ||
432 | PDEBUG("SOFTWARE TRIGGER\n"); | ||
433 | } | ||
434 | |||
435 | // Set preload/synchronization register. | ||
436 | spin_lock(instance->preload_reg_lock); | ||
437 | |||
438 | if (trig_type == ME_TRIG_TYPE_SW) { | ||
439 | *instance->preload_flags &= | ||
440 | ~(ME6000_AO_SYNC_EXT_TRIG << instance->ao_idx); | ||
441 | } else //if (trig_type == ME_TRIG_TYPE_EXT_DIGITAL) | ||
442 | { | ||
443 | *instance->preload_flags |= | ||
444 | ME6000_AO_SYNC_EXT_TRIG << instance->ao_idx; | ||
445 | } | ||
446 | |||
447 | if (trig_chan == ME_TRIG_CHAN_DEFAULT) { | ||
448 | *instance->preload_flags &= | ||
449 | ~(ME6000_AO_SYNC_HOLD << instance->ao_idx); | ||
450 | } else //if (trig_chan == ME_TRIG_CHAN_SYNCHRONOUS) | ||
451 | { | ||
452 | *instance->preload_flags |= | ||
453 | ME6000_AO_SYNC_HOLD << instance->ao_idx; | ||
454 | } | ||
455 | |||
456 | //Reset hardware register | ||
457 | sync = inl(instance->preload_reg); | ||
458 | PDEBUG_REG("preload_reg inl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
459 | instance->preload_reg - instance->reg_base, sync); | ||
460 | sync &= ~(ME6000_AO_SYNC_EXT_TRIG << instance->ao_idx); | ||
461 | sync |= ME6000_AO_SYNC_HOLD << instance->ao_idx; | ||
462 | |||
463 | //Output configured in default mode (safe one) | ||
464 | outl(sync, instance->preload_reg); | ||
465 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
466 | instance->preload_reg - instance->reg_base, sync); | ||
467 | spin_unlock(instance->preload_reg_lock); | ||
468 | |||
469 | instance->status = ao_status_single_configured; | ||
470 | |||
471 | ME_SUBDEVICE_EXIT; | ||
472 | |||
473 | return err; | ||
474 | } | ||
475 | |||
476 | static int me6000_ao_io_single_read(me_subdevice_t * subdevice, | ||
477 | struct file *filep, | ||
478 | int channel, | ||
479 | int *value, int time_out, int flags) | ||
480 | { | ||
481 | me6000_ao_subdevice_t *instance; | ||
482 | int err = ME_ERRNO_SUCCESS; | ||
483 | |||
484 | unsigned long j; | ||
485 | unsigned long delay = 0; | ||
486 | |||
487 | instance = (me6000_ao_subdevice_t *) subdevice; | ||
488 | |||
489 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
490 | |||
491 | if (flags & ~ME_IO_SINGLE_NONBLOCKING) { | ||
492 | PERROR("Invalid flag specified. %d\n", flags); | ||
493 | return ME_ERRNO_INVALID_FLAGS; | ||
494 | } | ||
495 | |||
496 | if ((instance->status >= ao_status_stream_configured) | ||
497 | && (instance->status <= ao_status_stream_end)) { | ||
498 | PERROR("Subdevice not configured to work in single mode!\n"); | ||
499 | return ME_ERRNO_PREVIOUS_CONFIG; | ||
500 | } | ||
501 | |||
502 | if (channel != 0) { | ||
503 | PERROR("Invalid channel number specified.\n"); | ||
504 | return ME_ERRNO_INVALID_CHANNEL; | ||
505 | } | ||
506 | |||
507 | if (time_out < 0) { | ||
508 | PERROR("Invalid timeout specified.\n"); | ||
509 | return ME_ERRNO_INVALID_TIMEOUT; | ||
510 | } | ||
511 | |||
512 | ME_SUBDEVICE_ENTER; | ||
513 | if ((!flags) && (instance->status == ao_status_single_run_wait)) { //Blocking mode. Wait for trigger. | ||
514 | if (time_out) { | ||
515 | delay = (time_out * HZ) / 1000; | ||
516 | if (delay == 0) | ||
517 | delay = 1; | ||
518 | } | ||
519 | |||
520 | j = jiffies; | ||
521 | |||
522 | //Only runing process will interrupt this call. Events are signaled when status change. This procedure has own timeout. | ||
523 | wait_event_interruptible_timeout(instance->wait_queue, | ||
524 | (instance->status != | ||
525 | ao_status_single_run_wait), | ||
526 | (delay) ? delay : LONG_MAX); | ||
527 | |||
528 | if (instance->status == ao_status_none) { | ||
529 | PDEBUG("Single canceled.\n"); | ||
530 | err = ME_ERRNO_CANCELLED; | ||
531 | } | ||
532 | |||
533 | if (signal_pending(current)) { | ||
534 | PERROR("Wait on start of state machine interrupted.\n"); | ||
535 | instance->status = ao_status_none; | ||
536 | ao_stop_immediately(instance); | ||
537 | err = ME_ERRNO_SIGNAL; | ||
538 | } | ||
539 | |||
540 | if ((delay) && ((jiffies - j) >= delay)) { | ||
541 | PDEBUG("Timeout reached.\n"); | ||
542 | err = ME_ERRNO_TIMEOUT; | ||
543 | } | ||
544 | |||
545 | *value = | ||
546 | (!err) ? instance->single_value_in_fifo : instance-> | ||
547 | single_value; | ||
548 | } else { //Non-blocking mode | ||
549 | //Read value | ||
550 | *value = instance->single_value; | ||
551 | } | ||
552 | |||
553 | ME_SUBDEVICE_EXIT; | ||
554 | |||
555 | return err; | ||
556 | } | ||
557 | |||
558 | static int me6000_ao_io_single_write(me_subdevice_t * subdevice, | ||
559 | struct file *filep, | ||
560 | int channel, | ||
561 | int value, int time_out, int flags) | ||
562 | { | ||
563 | me6000_ao_subdevice_t *instance; | ||
564 | int err = ME_ERRNO_SUCCESS; | ||
565 | unsigned long cpu_flags; | ||
566 | unsigned long j; | ||
567 | unsigned long delay = 0; | ||
568 | |||
569 | uint32_t sync_mask; | ||
570 | uint32_t mode; | ||
571 | |||
572 | uint32_t tmp; | ||
573 | |||
574 | /// Workaround for mix-mode - begin | ||
575 | uint32_t ctrl = 0x0; | ||
576 | uint32_t status; | ||
577 | /// Workaround for mix-mode - end | ||
578 | |||
579 | instance = (me6000_ao_subdevice_t *) subdevice; | ||
580 | |||
581 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
582 | |||
583 | if (flags & | ||
584 | ~(ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS | | ||
585 | ME_IO_SINGLE_TYPE_WRITE_NONBLOCKING)) { | ||
586 | PERROR("Invalid flag specified.\n"); | ||
587 | return ME_ERRNO_INVALID_FLAGS; | ||
588 | } | ||
589 | |||
590 | if ((instance->status == ao_status_none) | ||
591 | || (instance->status > ao_status_single_end)) { | ||
592 | PERROR("Subdevice not configured to work in single mode!\n"); | ||
593 | return ME_ERRNO_PREVIOUS_CONFIG; | ||
594 | } | ||
595 | |||
596 | if (channel != 0) { | ||
597 | PERROR("Invalid channel number specified.\n"); | ||
598 | return ME_ERRNO_INVALID_CHANNEL; | ||
599 | } | ||
600 | |||
601 | if (value & ~ME6000_AO_MAX_DATA) { | ||
602 | PERROR("Invalid value provided.\n"); | ||
603 | return ME_ERRNO_VALUE_OUT_OF_RANGE; | ||
604 | } | ||
605 | |||
606 | if (time_out < 0) { | ||
607 | PERROR("Invalid timeout specified.\n"); | ||
608 | return ME_ERRNO_INVALID_TIMEOUT; | ||
609 | } | ||
610 | |||
611 | ME_SUBDEVICE_ENTER; | ||
612 | |||
613 | /// @note For single all calls (config and write) are erasing previous state! | ||
614 | |||
615 | //Cancel control task | ||
616 | PDEBUG("Cancel control task. idx=%d\n", instance->ao_idx); | ||
617 | instance->ao_control_task_flag = 0; | ||
618 | cancel_delayed_work(&instance->ao_control_task); | ||
619 | |||
620 | // Correct single mirrors | ||
621 | instance->single_value_in_fifo = instance->single_value; | ||
622 | |||
623 | //Stop device | ||
624 | err = ao_stop_immediately(instance); | ||
625 | if (err) { | ||
626 | PERROR_CRITICAL("FSM IS BUSY!\n"); | ||
627 | ME_SUBDEVICE_EXIT; | ||
628 | |||
629 | return ME_ERRNO_SUBDEVICE_BUSY; | ||
630 | } | ||
631 | |||
632 | if (time_out) { | ||
633 | delay = (time_out * HZ) / 1000; | ||
634 | |||
635 | if (delay == 0) | ||
636 | delay = 1; | ||
637 | } | ||
638 | |||
639 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
640 | |||
641 | instance->single_value_in_fifo = value; | ||
642 | |||
643 | if (instance->fifo) { | ||
644 | ctrl = inl(instance->ctrl_reg); | ||
645 | } | ||
646 | |||
647 | if (instance->fifo & ME6000_AO_HAS_FIFO) { /// Workaround for mix-mode - begin | ||
648 | //Set speed | ||
649 | outl(ME6000_AO_MIN_CHAN_TICKS - 1, instance->timer_reg); | ||
650 | PDEBUG_REG("timer_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
651 | instance->reg_base, | ||
652 | instance->timer_reg - instance->reg_base, | ||
653 | (int)ME6000_AO_MIN_CHAN_TICKS); | ||
654 | instance->hardware_stop_delay = HZ / 10; //100ms | ||
655 | |||
656 | status = inl(instance->status_reg); | ||
657 | |||
658 | //Set the continous mode. | ||
659 | ctrl &= ~ME6000_AO_CTRL_MODE_MASK; | ||
660 | ctrl |= ME6000_AO_MODE_CONTINUOUS; | ||
661 | |||
662 | //Prepare FIFO | ||
663 | if (!(ctrl & ME6000_AO_CTRL_BIT_ENABLE_FIFO)) { //FIFO wasn't enabeled. Do it. | ||
664 | PINFO("Enableing FIFO.\n"); | ||
665 | ctrl &= ~ME6000_AO_CTRL_BIT_ENABLE_IRQ; | ||
666 | ctrl |= ME6000_AO_CTRL_BIT_ENABLE_FIFO; | ||
667 | } else { //Check if FIFO is empty | ||
668 | if (status & ME6000_AO_STATUS_BIT_EF) { //FIFO not empty | ||
669 | PINFO("Reseting FIFO.\n"); | ||
670 | ctrl &= | ||
671 | ~(ME6000_AO_CTRL_BIT_ENABLE_FIFO | | ||
672 | ME6000_AO_CTRL_BIT_ENABLE_IRQ); | ||
673 | outl(ctrl, instance->ctrl_reg); | ||
674 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
675 | instance->reg_base, | ||
676 | instance->ctrl_reg - | ||
677 | instance->reg_base, ctrl); | ||
678 | |||
679 | ctrl |= ME6000_AO_CTRL_BIT_ENABLE_FIFO; | ||
680 | } else { //FIFO empty, only interrupt needs to be disabled! | ||
681 | ctrl &= ~ME6000_AO_CTRL_BIT_ENABLE_IRQ; | ||
682 | } | ||
683 | } | ||
684 | |||
685 | outl(ctrl, instance->ctrl_reg); | ||
686 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
687 | instance->reg_base, | ||
688 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
689 | |||
690 | //Reset interrupt latch | ||
691 | inl(instance->irq_reset_reg); | ||
692 | |||
693 | //Write output - 1 value to FIFO | ||
694 | if (instance->ao_idx & 0x1) { | ||
695 | outl(value <<= 16, instance->fifo_reg); | ||
696 | PDEBUG_REG("fifo_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
697 | instance->reg_base, | ||
698 | instance->fifo_reg - instance->reg_base, | ||
699 | value <<= 16); | ||
700 | } else { | ||
701 | outl(value, instance->fifo_reg); | ||
702 | PDEBUG_REG("fifo_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
703 | instance->reg_base, | ||
704 | instance->fifo_reg - instance->reg_base, | ||
705 | value); | ||
706 | } | ||
707 | /// Workaround for mix-mode - end | ||
708 | } else { //No FIFO - always in single mode | ||
709 | //Write value | ||
710 | PDEBUG("Write value\n"); | ||
711 | outl(value, instance->single_reg); | ||
712 | PDEBUG_REG("single_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
713 | instance->reg_base, | ||
714 | instance->single_reg - instance->reg_base, value); | ||
715 | } | ||
716 | |||
717 | mode = *instance->preload_flags >> instance->ao_idx; | ||
718 | mode &= (ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG); | ||
719 | |||
720 | PINFO("Triggering mode: 0x%08x\n", mode); | ||
721 | |||
722 | spin_lock(instance->preload_reg_lock); | ||
723 | sync_mask = inl(instance->preload_reg); | ||
724 | PDEBUG_REG("preload_reg inl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
725 | instance->preload_reg - instance->reg_base, sync_mask); | ||
726 | switch (mode) { | ||
727 | case 0: //0x00000000: Individual software | ||
728 | ctrl &= ~ME6000_AO_CTRL_BIT_ENABLE_EX_TRIG; | ||
729 | |||
730 | if (instance->fifo & ME6000_AO_HAS_FIFO) { // FIFO - Continous mode | ||
731 | ctrl &= ~ME6000_AO_CTRL_BIT_ENABLE_EX_TRIG; | ||
732 | if ((sync_mask & ((ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG) << instance->ao_idx)) != 0x0) { //Now we can set correct mode. | ||
733 | sync_mask &= | ||
734 | ~((ME6000_AO_SYNC_EXT_TRIG | | ||
735 | ME6000_AO_SYNC_HOLD) << instance-> | ||
736 | ao_idx); | ||
737 | |||
738 | outl(sync_mask, instance->preload_reg); | ||
739 | PDEBUG_REG | ||
740 | ("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
741 | instance->reg_base, | ||
742 | instance->preload_reg - instance->reg_base, | ||
743 | sync_mask); | ||
744 | } | ||
745 | } else { // No FIFO - Single mode: In this case resetting 'ME6000_AO_SYNC_HOLD' will trigger output. | ||
746 | if ((sync_mask & ((ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG) << instance->ao_idx)) != ME6000_AO_SYNC_HOLD) { //Now we can set correct mode. This is exception. It is set to synchronous and triggered later. | ||
747 | sync_mask &= | ||
748 | ~(ME6000_AO_SYNC_EXT_TRIG << instance-> | ||
749 | ao_idx); | ||
750 | sync_mask |= | ||
751 | ME6000_AO_SYNC_HOLD << instance->ao_idx; | ||
752 | |||
753 | outl(sync_mask, instance->preload_reg); | ||
754 | PDEBUG_REG | ||
755 | ("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
756 | instance->reg_base, | ||
757 | instance->preload_reg - instance->reg_base, | ||
758 | sync_mask); | ||
759 | } | ||
760 | } | ||
761 | instance->single_value = value; | ||
762 | break; | ||
763 | |||
764 | case ME6000_AO_SYNC_EXT_TRIG: //0x00010000: Individual hardware | ||
765 | PDEBUG("DIGITAL TRIGGER\n"); | ||
766 | ctrl |= ME6000_AO_CTRL_BIT_ENABLE_EX_TRIG; | ||
767 | |||
768 | if (instance->fifo & ME6000_AO_HAS_FIFO) { // FIFO - Continous mode | ||
769 | if ((sync_mask & ((ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG) << instance->ao_idx)) != 0x0) { //Now we can set correct mode. | ||
770 | sync_mask &= | ||
771 | ~((ME6000_AO_SYNC_EXT_TRIG | | ||
772 | ME6000_AO_SYNC_HOLD) << instance-> | ||
773 | ao_idx); | ||
774 | |||
775 | outl(sync_mask, instance->preload_reg); | ||
776 | PDEBUG_REG | ||
777 | ("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
778 | instance->reg_base, | ||
779 | instance->preload_reg - instance->reg_base, | ||
780 | sync_mask); | ||
781 | } | ||
782 | } else { // No FIFO - Single mode | ||
783 | if ((sync_mask & | ||
784 | ((ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG) << | ||
785 | instance->ao_idx)) != ME6000_AO_SYNC_HOLD) { | ||
786 | //Now we can set correct mode | ||
787 | sync_mask &= | ||
788 | ~(ME6000_AO_SYNC_EXT_TRIG << instance-> | ||
789 | ao_idx); | ||
790 | sync_mask |= | ||
791 | ME6000_AO_SYNC_HOLD << instance->ao_idx; | ||
792 | |||
793 | outl(sync_mask, instance->preload_reg); | ||
794 | PDEBUG_REG | ||
795 | ("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
796 | instance->reg_base, | ||
797 | instance->preload_reg - instance->reg_base, | ||
798 | sync_mask); | ||
799 | } | ||
800 | } | ||
801 | break; | ||
802 | |||
803 | case ME6000_AO_SYNC_HOLD: //0x00000001: Synchronous software | ||
804 | ctrl &= ~ME6000_AO_CTRL_BIT_ENABLE_EX_TRIG; | ||
805 | |||
806 | if ((sync_mask & | ||
807 | ((ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG) << | ||
808 | instance->ao_idx)) != | ||
809 | (ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG)) { | ||
810 | //Now we can set correct mode | ||
811 | sync_mask |= | ||
812 | ME6000_AO_SYNC_EXT_TRIG << instance->ao_idx; | ||
813 | sync_mask |= ME6000_AO_SYNC_HOLD << instance->ao_idx; | ||
814 | outl(sync_mask, instance->preload_reg); | ||
815 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
816 | instance->reg_base, | ||
817 | instance->preload_reg - instance->reg_base, | ||
818 | sync_mask); | ||
819 | } | ||
820 | //Set triggering flag | ||
821 | *instance->triggering_flags |= 0x1 << instance->ao_idx; | ||
822 | break; | ||
823 | |||
824 | case (ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG): //0x00010001: Synchronous hardware | ||
825 | PDEBUG("DIGITAL TRIGGER\n"); | ||
826 | ctrl |= ME6000_AO_CTRL_BIT_ENABLE_EX_TRIG; | ||
827 | |||
828 | if ((sync_mask & | ||
829 | ((ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG) << | ||
830 | instance->ao_idx)) != | ||
831 | (ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG)) { | ||
832 | //Now we can set correct mode | ||
833 | sync_mask |= | ||
834 | (ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG) << | ||
835 | instance->ao_idx; | ||
836 | outl(sync_mask, instance->preload_reg); | ||
837 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
838 | instance->reg_base, | ||
839 | instance->preload_reg - instance->reg_base, | ||
840 | sync_mask); | ||
841 | } | ||
842 | //Set triggering flag | ||
843 | *instance->triggering_flags |= 0x1 << instance->ao_idx; | ||
844 | break; | ||
845 | } | ||
846 | // spin_unlock(instance->preload_reg_lock); // Moved down. | ||
847 | |||
848 | if (instance->fifo) { //Activate ISM (remove 'stop' bits) | ||
849 | ctrl &= | ||
850 | ~(ME6000_AO_CTRL_BIT_EX_TRIG_EDGE | | ||
851 | ME6000_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH); | ||
852 | ctrl |= instance->ctrl_trg; | ||
853 | ctrl &= | ||
854 | ~(ME6000_AO_CTRL_BIT_STOP | | ||
855 | ME6000_AO_CTRL_BIT_IMMEDIATE_STOP); | ||
856 | |||
857 | outl(ctrl, instance->ctrl_reg); | ||
858 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
859 | instance->reg_base, | ||
860 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
861 | } | ||
862 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
863 | |||
864 | /// @note When flag 'ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS' is set than output is triggered. ALWAYS! | ||
865 | |||
866 | PINFO("<%s> start mode= 0x%08x %s\n", __FUNCTION__, mode, | ||
867 | (flags & ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS) ? "SYNCHRONOUS" : | ||
868 | ""); | ||
869 | if (instance->fifo & ME6000_AO_HAS_FIFO) { // FIFO - Continous mode | ||
870 | if (flags & ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS) { //Trigger outputs | ||
871 | //Add channel to start list | ||
872 | outl(sync_mask | | ||
873 | (ME6000_AO_SYNC_HOLD << instance->ao_idx), | ||
874 | instance->preload_reg); | ||
875 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
876 | instance->reg_base, | ||
877 | instance->preload_reg - instance->reg_base, | ||
878 | sync_mask | (ME6000_AO_SYNC_HOLD << | ||
879 | instance->ao_idx)); | ||
880 | |||
881 | //Fire | ||
882 | PINFO | ||
883 | ("Fired all software synchronous outputs by software trigger.\n"); | ||
884 | outl(0x8000, instance->single_reg); | ||
885 | PDEBUG_REG("single_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
886 | instance->reg_base, | ||
887 | instance->single_reg - instance->reg_base, | ||
888 | 0x8000); | ||
889 | |||
890 | //Restore save settings | ||
891 | outl(sync_mask, instance->preload_reg); | ||
892 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
893 | instance->reg_base, | ||
894 | instance->preload_reg - instance->reg_base, | ||
895 | sync_mask); | ||
896 | |||
897 | } else if (!mode) { //Trigger outputs | ||
898 | /* //Remove channel from start list | ||
899 | outl(sync_mask & ~(ME6000_AO_SYNC_HOLD << instance->ao_idx), instance->preload_reg); | ||
900 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, instance->preload_reg - instance->reg_base, sync_mask & ~(ME6000_AO_SYNC_HOLD << instance->ao_idx)); | ||
901 | */ | ||
902 | //Fire | ||
903 | PINFO("Software trigger.\n"); | ||
904 | outl(0x8000, instance->single_reg); | ||
905 | PDEBUG_REG("single_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
906 | instance->reg_base, | ||
907 | instance->single_reg - instance->reg_base, | ||
908 | 0x8000); | ||
909 | |||
910 | /* //Restore save settings | ||
911 | outl(sync_mask, instance->preload_reg); | ||
912 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, instance->preload_reg - instance->reg_base, sync_mask); | ||
913 | */ | ||
914 | } | ||
915 | /// @note This is mix-mode case. For now I do not have possibility to trigger first 4 channels (continous mode) and other (single) ones at once. | ||
916 | /// @note Because triggering is not working it can not be add to synchronous list. First 4 channels don't need this information, anyway. | ||
917 | *instance->triggering_flags &= 0xFFFFFFF0; | ||
918 | } else { // No FIFO - Single mode | ||
919 | if (flags & ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS) { //Fired all software synchronous outputs. | ||
920 | tmp = ~(*instance->preload_flags | 0xFFFF0000); | ||
921 | PINFO | ||
922 | ("Fired all software synchronous outputs. mask:0x%08x\n", | ||
923 | tmp); | ||
924 | tmp |= sync_mask & 0xFFFF0000; | ||
925 | // Add this channel to list | ||
926 | tmp &= ~(ME6000_AO_SYNC_HOLD << instance->ao_idx); | ||
927 | |||
928 | //Fire | ||
929 | PINFO("Software trigger.\n"); | ||
930 | outl(tmp, instance->preload_reg); | ||
931 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
932 | instance->reg_base, | ||
933 | instance->preload_reg - instance->reg_base, | ||
934 | tmp); | ||
935 | |||
936 | //Restore save settings | ||
937 | outl(sync_mask, instance->preload_reg); | ||
938 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
939 | instance->reg_base, | ||
940 | instance->preload_reg - instance->reg_base, | ||
941 | sync_mask); | ||
942 | |||
943 | //Set all as triggered. | ||
944 | *instance->triggering_flags = 0x0; | ||
945 | } else if (!mode) { // Add this channel to list | ||
946 | outl(sync_mask & | ||
947 | ~(ME6000_AO_SYNC_HOLD << instance->ao_idx), | ||
948 | instance->preload_reg); | ||
949 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
950 | instance->reg_base, | ||
951 | instance->preload_reg - instance->reg_base, | ||
952 | sync_mask & ~(ME6000_AO_SYNC_HOLD << | ||
953 | instance->ao_idx)); | ||
954 | |||
955 | //Fire | ||
956 | PINFO("Software trigger.\n"); | ||
957 | |||
958 | //Restore save settings | ||
959 | outl(sync_mask, instance->preload_reg); | ||
960 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
961 | instance->reg_base, | ||
962 | instance->preload_reg - instance->reg_base, | ||
963 | sync_mask); | ||
964 | |||
965 | //Set all as triggered. | ||
966 | *instance->triggering_flags = 0x0; | ||
967 | } | ||
968 | |||
969 | } | ||
970 | spin_unlock(instance->preload_reg_lock); | ||
971 | |||
972 | instance->status = ao_status_single_run_wait; | ||
973 | |||
974 | instance->timeout.delay = delay; | ||
975 | instance->timeout.start_time = jiffies; | ||
976 | instance->ao_control_task_flag = 1; | ||
977 | queue_delayed_work(instance->me6000_workqueue, | ||
978 | &instance->ao_control_task, 1); | ||
979 | |||
980 | if (!(flags & ME_IO_SINGLE_TYPE_WRITE_NONBLOCKING)) { | ||
981 | j = jiffies; | ||
982 | |||
983 | //Only runing process will interrupt this call. Events are signaled when status change. Extra timeout add for safe reason. | ||
984 | wait_event_interruptible_timeout(instance->wait_queue, | ||
985 | (instance->status != | ||
986 | ao_status_single_run_wait), | ||
987 | (delay) ? delay + | ||
988 | 1 : LONG_MAX); | ||
989 | |||
990 | if (instance->status != ao_status_single_end) { | ||
991 | PDEBUG("Single canceled.\n"); | ||
992 | err = ME_ERRNO_CANCELLED; | ||
993 | } | ||
994 | |||
995 | if (signal_pending(current)) { | ||
996 | PERROR("Wait on start of state machine interrupted.\n"); | ||
997 | instance->ao_control_task_flag = 0; | ||
998 | cancel_delayed_work(&instance->ao_control_task); | ||
999 | ao_stop_immediately(instance); | ||
1000 | instance->status = ao_status_none; | ||
1001 | err = ME_ERRNO_SIGNAL; | ||
1002 | } | ||
1003 | |||
1004 | if ((delay) && ((jiffies - j) >= delay)) { | ||
1005 | if (instance->status == ao_status_single_end) { | ||
1006 | PDEBUG("Timeout reached.\n"); | ||
1007 | } else if ((jiffies - j) > delay) { | ||
1008 | PERROR | ||
1009 | ("Timeout reached. Not handled by control task!\n"); | ||
1010 | ao_stop_immediately(instance); | ||
1011 | } else { | ||
1012 | PERROR | ||
1013 | ("Timeout reached. Signal come but status is strange: %d\n", | ||
1014 | instance->status); | ||
1015 | ao_stop_immediately(instance); | ||
1016 | } | ||
1017 | |||
1018 | instance->ao_control_task_flag = 0; | ||
1019 | cancel_delayed_work(&instance->ao_control_task); | ||
1020 | instance->status = ao_status_single_end; | ||
1021 | err = ME_ERRNO_TIMEOUT; | ||
1022 | } | ||
1023 | } | ||
1024 | |||
1025 | ME_SUBDEVICE_EXIT; | ||
1026 | |||
1027 | return err; | ||
1028 | } | ||
1029 | |||
1030 | static int me6000_ao_io_stream_config(me_subdevice_t * subdevice, | ||
1031 | struct file *filep, | ||
1032 | meIOStreamConfig_t * config_list, | ||
1033 | int count, | ||
1034 | meIOStreamTrigger_t * trigger, | ||
1035 | int fifo_irq_threshold, int flags) | ||
1036 | { | ||
1037 | me6000_ao_subdevice_t *instance; | ||
1038 | int err = ME_ERRNO_SUCCESS; | ||
1039 | uint32_t ctrl; | ||
1040 | unsigned long cpu_flags; | ||
1041 | uint64_t conv_ticks; | ||
1042 | unsigned int conv_start_ticks_low = trigger->iConvStartTicksLow; | ||
1043 | unsigned int conv_start_ticks_high = trigger->iConvStartTicksHigh; | ||
1044 | |||
1045 | instance = (me6000_ao_subdevice_t *) subdevice; | ||
1046 | |||
1047 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
1048 | |||
1049 | if (!(instance->fifo & ME6000_AO_HAS_FIFO)) { | ||
1050 | PERROR("Not a streaming ao.\n"); | ||
1051 | return ME_ERRNO_NOT_SUPPORTED; | ||
1052 | } | ||
1053 | |||
1054 | conv_ticks = | ||
1055 | (uint64_t) conv_start_ticks_low + | ||
1056 | ((uint64_t) conv_start_ticks_high << 32); | ||
1057 | |||
1058 | if (flags & | ||
1059 | ~(ME_IO_STREAM_CONFIG_HARDWARE_ONLY | | ||
1060 | ME_IO_STREAM_CONFIG_WRAPAROUND)) { | ||
1061 | PERROR("Invalid flags.\n"); | ||
1062 | return ME_ERRNO_INVALID_FLAGS; | ||
1063 | } | ||
1064 | |||
1065 | if (flags & ME_IO_STREAM_CONFIG_HARDWARE_ONLY) { | ||
1066 | if (!flags & ME_IO_STREAM_CONFIG_WRAPAROUND) { | ||
1067 | PERROR | ||
1068 | ("Hardware ME_IO_STREAM_CONFIG_HARDWARE_ONLY has to be with ME_IO_STREAM_CONFIG_WRAPAROUND.\n"); | ||
1069 | return ME_ERRNO_INVALID_FLAGS; | ||
1070 | } | ||
1071 | |||
1072 | if ((trigger->iAcqStopTrigType != ME_TRIG_TYPE_NONE) | ||
1073 | || (trigger->iScanStopTrigType != ME_TRIG_TYPE_NONE)) { | ||
1074 | PERROR | ||
1075 | ("Hardware wraparound mode must be in infinite mode.\n"); | ||
1076 | return ME_ERRNO_INVALID_FLAGS; | ||
1077 | } | ||
1078 | } | ||
1079 | |||
1080 | if (count != 1) { | ||
1081 | PERROR("Only 1 entry in config list acceptable.\n"); | ||
1082 | return ME_ERRNO_INVALID_CONFIG_LIST_COUNT; | ||
1083 | } | ||
1084 | |||
1085 | if (config_list[0].iChannel != 0) { | ||
1086 | PERROR("Invalid channel number specified.\n"); | ||
1087 | return ME_ERRNO_INVALID_CHANNEL; | ||
1088 | } | ||
1089 | |||
1090 | if (config_list[0].iStreamConfig != 0) { | ||
1091 | PERROR("Only one range available.\n"); | ||
1092 | return ME_ERRNO_INVALID_STREAM_CONFIG; | ||
1093 | } | ||
1094 | |||
1095 | if (config_list[0].iRef != ME_REF_AO_GROUND) { | ||
1096 | PERROR("Output is referenced to ground.\n"); | ||
1097 | return ME_ERRNO_INVALID_REF; | ||
1098 | } | ||
1099 | |||
1100 | if ((trigger->iAcqStartTicksLow != 0) | ||
1101 | || (trigger->iAcqStartTicksHigh != 0)) { | ||
1102 | PERROR | ||
1103 | ("Invalid acquisition start trigger argument specified.\n"); | ||
1104 | return ME_ERRNO_INVALID_ACQ_START_ARG; | ||
1105 | } | ||
1106 | |||
1107 | if (config_list[0].iFlags) { | ||
1108 | PERROR("Invalid config list flag.\n"); | ||
1109 | return ME_ERRNO_INVALID_FLAGS; | ||
1110 | } | ||
1111 | |||
1112 | if ((trigger->iAcqStartTrigType != ME_TRIG_TYPE_SW) | ||
1113 | && (trigger->iAcqStartTrigType != ME_TRIG_TYPE_EXT_DIGITAL)) { | ||
1114 | PERROR("Invalid acquisition start trigger type specified.\n"); | ||
1115 | return ME_ERRNO_INVALID_ACQ_START_TRIG_TYPE; | ||
1116 | } | ||
1117 | |||
1118 | if (trigger->iAcqStartTrigType == ME_TRIG_TYPE_EXT_DIGITAL) { | ||
1119 | switch (trigger->iAcqStartTrigEdge) { | ||
1120 | case ME_TRIG_EDGE_RISING: | ||
1121 | case ME_TRIG_EDGE_FALLING: | ||
1122 | case ME_TRIG_EDGE_ANY: | ||
1123 | break; | ||
1124 | |||
1125 | default: | ||
1126 | PERROR | ||
1127 | ("Invalid acquisition start trigger edge specified.\n"); | ||
1128 | return ME_ERRNO_INVALID_ACQ_START_TRIG_EDGE; | ||
1129 | } | ||
1130 | } | ||
1131 | |||
1132 | if ((trigger->iAcqStartTrigType == ME_TRIG_TYPE_SW) | ||
1133 | && (trigger->iAcqStartTrigEdge != ME_TRIG_TYPE_NONE)) { | ||
1134 | PERROR("Invalid acquisition start trigger edge specified.\n"); | ||
1135 | return ME_ERRNO_INVALID_ACQ_START_TRIG_EDGE; | ||
1136 | } | ||
1137 | |||
1138 | if (trigger->iScanStartTrigType != ME_TRIG_TYPE_FOLLOW) { | ||
1139 | PERROR("Invalid scan start trigger type specified.\n"); | ||
1140 | return ME_ERRNO_INVALID_SCAN_START_TRIG_TYPE; | ||
1141 | } | ||
1142 | |||
1143 | if (trigger->iConvStartTrigType != ME_TRIG_TYPE_TIMER) { | ||
1144 | PERROR("Invalid conv start trigger type specified.\n"); | ||
1145 | return ME_ERRNO_INVALID_CONV_START_TRIG_TYPE; | ||
1146 | } | ||
1147 | |||
1148 | if ((conv_ticks < ME6000_AO_MIN_CHAN_TICKS) | ||
1149 | || (conv_ticks > ME6000_AO_MAX_CHAN_TICKS)) { | ||
1150 | PERROR("Invalid conv start trigger argument specified.\n"); | ||
1151 | return ME_ERRNO_INVALID_CONV_START_ARG; | ||
1152 | } | ||
1153 | |||
1154 | if (trigger->iAcqStartTicksLow || trigger->iAcqStartTicksHigh) { | ||
1155 | PERROR("Invalid acq start trigger argument specified.\n"); | ||
1156 | return ME_ERRNO_INVALID_ACQ_START_ARG; | ||
1157 | } | ||
1158 | |||
1159 | if (trigger->iScanStartTicksLow || trigger->iScanStartTicksHigh) { | ||
1160 | PERROR("Invalid scan start trigger argument specified.\n"); | ||
1161 | return ME_ERRNO_INVALID_SCAN_START_ARG; | ||
1162 | } | ||
1163 | |||
1164 | switch (trigger->iScanStopTrigType) { | ||
1165 | case ME_TRIG_TYPE_NONE: | ||
1166 | if (trigger->iScanStopCount != 0) { | ||
1167 | PERROR("Invalid scan stop count specified.\n"); | ||
1168 | return ME_ERRNO_INVALID_SCAN_STOP_ARG; | ||
1169 | } | ||
1170 | break; | ||
1171 | |||
1172 | case ME_TRIG_TYPE_COUNT: | ||
1173 | if (flags & ME_IO_STREAM_CONFIG_WRAPAROUND) { | ||
1174 | if (trigger->iScanStopCount <= 0) { | ||
1175 | PERROR("Invalid scan stop count specified.\n"); | ||
1176 | return ME_ERRNO_INVALID_SCAN_STOP_ARG; | ||
1177 | } | ||
1178 | } else { | ||
1179 | PERROR("The continous mode has not 'scan' contects.\n"); | ||
1180 | return ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE; | ||
1181 | } | ||
1182 | break; | ||
1183 | |||
1184 | default: | ||
1185 | PERROR("Invalid scan stop trigger type specified.\n"); | ||
1186 | return ME_ERRNO_INVALID_SCAN_STOP_TRIG_TYPE; | ||
1187 | } | ||
1188 | |||
1189 | switch (trigger->iAcqStopTrigType) { | ||
1190 | case ME_TRIG_TYPE_NONE: | ||
1191 | if (trigger->iAcqStopCount != 0) { | ||
1192 | PERROR("Invalid acq stop count specified.\n"); | ||
1193 | return ME_ERRNO_INVALID_ACQ_STOP_ARG; | ||
1194 | } | ||
1195 | break; | ||
1196 | |||
1197 | case ME_TRIG_TYPE_COUNT: | ||
1198 | if (trigger->iScanStopTrigType != ME_TRIG_TYPE_NONE) { | ||
1199 | PERROR("Invalid acq stop trigger type specified.\n"); | ||
1200 | return ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE; | ||
1201 | } | ||
1202 | |||
1203 | if (flags & ME_IO_STREAM_CONFIG_WRAPAROUND) { | ||
1204 | if (trigger->iAcqStopCount <= 0) { | ||
1205 | PERROR | ||
1206 | ("The continous mode has not 'scan' contects.\n"); | ||
1207 | return ME_ERRNO_INVALID_ACQ_STOP_ARG; | ||
1208 | } | ||
1209 | } | ||
1210 | // else | ||
1211 | // { | ||
1212 | // PERROR("Invalid acq stop trigger type specified.\n"); | ||
1213 | // return ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE; | ||
1214 | // } | ||
1215 | |||
1216 | break; | ||
1217 | |||
1218 | default: | ||
1219 | PERROR("Invalid acq stop trigger type specified.\n"); | ||
1220 | return ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE; | ||
1221 | } | ||
1222 | |||
1223 | switch (trigger->iAcqStartTrigChan) { | ||
1224 | case ME_TRIG_CHAN_DEFAULT: | ||
1225 | case ME_TRIG_CHAN_SYNCHRONOUS: | ||
1226 | break; | ||
1227 | |||
1228 | default: | ||
1229 | PERROR("Invalid acq start trigger channel specified.\n"); | ||
1230 | return ME_ERRNO_INVALID_ACQ_START_TRIG_CHAN; | ||
1231 | } | ||
1232 | |||
1233 | ME_SUBDEVICE_ENTER; | ||
1234 | |||
1235 | //Stop device | ||
1236 | |||
1237 | //Cancel control task | ||
1238 | PDEBUG("Cancel control task. idx=%d\n", instance->ao_idx); | ||
1239 | instance->ao_control_task_flag = 0; | ||
1240 | cancel_delayed_work(&instance->ao_control_task); | ||
1241 | |||
1242 | //Check if state machine is stopped. | ||
1243 | err = ao_stop_immediately(instance); | ||
1244 | if (err) { | ||
1245 | PERROR_CRITICAL("FSM IS BUSY!\n"); | ||
1246 | ME_SUBDEVICE_EXIT; | ||
1247 | |||
1248 | return ME_ERRNO_SUBDEVICE_BUSY; | ||
1249 | } | ||
1250 | |||
1251 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
1252 | //Reset control register. Block all actions. Disable IRQ. Disable FIFO. | ||
1253 | ctrl = ME6000_AO_CTRL_BIT_IMMEDIATE_STOP | ME6000_AO_CTRL_BIT_STOP; | ||
1254 | outl(ctrl, instance->ctrl_reg); | ||
1255 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
1256 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
1257 | |||
1258 | //Reset interrupt latch | ||
1259 | inl(instance->irq_reset_reg); | ||
1260 | |||
1261 | //This is paranoic, but to be sure. | ||
1262 | instance->preloaded_count = 0; | ||
1263 | instance->data_count = 0; | ||
1264 | instance->circ_buf.head = 0; | ||
1265 | instance->circ_buf.tail = 0; | ||
1266 | |||
1267 | /* Set mode. */ | ||
1268 | if (flags & ME_IO_STREAM_CONFIG_WRAPAROUND) { //Wraparound | ||
1269 | if (flags & ME_IO_STREAM_CONFIG_HARDWARE_ONLY) { //Hardware wraparound | ||
1270 | PINFO("Hardware wraparound.\n"); | ||
1271 | ctrl |= ME6000_AO_MODE_WRAPAROUND; | ||
1272 | instance->mode = ME6000_AO_HW_WRAP_MODE; | ||
1273 | } else { //Software wraparound | ||
1274 | PINFO("Software wraparound.\n"); | ||
1275 | ctrl |= ME6000_AO_MODE_CONTINUOUS; | ||
1276 | instance->mode = ME6000_AO_SW_WRAP_MODE; | ||
1277 | } | ||
1278 | } else { //Continous | ||
1279 | PINFO("Continous.\n"); | ||
1280 | ctrl |= ME6000_AO_MODE_CONTINUOUS; | ||
1281 | instance->mode = ME6000_AO_CONTINOUS; | ||
1282 | } | ||
1283 | |||
1284 | //Set the trigger edge. | ||
1285 | if (trigger->iAcqStartTrigType == ME_TRIG_TYPE_EXT_DIGITAL) { //Set the trigger type and edge for external trigger. | ||
1286 | PINFO("External digital trigger.\n"); | ||
1287 | instance->start_mode = ME6000_AO_EXT_TRIG; | ||
1288 | |||
1289 | switch (trigger->iAcqStartTrigEdge) { | ||
1290 | case ME_TRIG_EDGE_RISING: | ||
1291 | PINFO("Set the trigger edge: rising.\n"); | ||
1292 | instance->ctrl_trg = 0x0; | ||
1293 | break; | ||
1294 | |||
1295 | case ME_TRIG_EDGE_FALLING: | ||
1296 | PINFO("Set the trigger edge: falling.\n"); | ||
1297 | // ctrl |= ME6000_AO_CTRL_BIT_EX_TRIG_EDGE; | ||
1298 | instance->ctrl_trg = ME6000_AO_CTRL_BIT_EX_TRIG_EDGE; | ||
1299 | break; | ||
1300 | |||
1301 | case ME_TRIG_EDGE_ANY: | ||
1302 | PINFO("Set the trigger edge: both edges.\n"); | ||
1303 | // ctrl |= ME6000_AO_CTRL_BIT_EX_TRIG_EDGE | ME6000_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH; | ||
1304 | instance->ctrl_trg = | ||
1305 | ME6000_AO_CTRL_BIT_EX_TRIG_EDGE | | ||
1306 | ME6000_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH; | ||
1307 | break; | ||
1308 | } | ||
1309 | } else { | ||
1310 | PINFO("Internal software trigger.\n"); | ||
1311 | instance->start_mode = 0; | ||
1312 | } | ||
1313 | |||
1314 | //Set the stop mode and value. | ||
1315 | if (trigger->iAcqStopTrigType == ME_TRIG_TYPE_COUNT) { //Amount of data | ||
1316 | instance->stop_mode = ME6000_AO_ACQ_STOP_MODE; | ||
1317 | instance->stop_count = trigger->iAcqStopCount; | ||
1318 | } else if (trigger->iScanStopTrigType == ME_TRIG_TYPE_COUNT) { //Amount of 'scans' | ||
1319 | instance->stop_mode = ME6000_AO_SCAN_STOP_MODE; | ||
1320 | instance->stop_count = trigger->iScanStopCount; | ||
1321 | } else { //Infinite | ||
1322 | instance->stop_mode = ME6000_AO_INF_STOP_MODE; | ||
1323 | instance->stop_count = 0; | ||
1324 | } | ||
1325 | |||
1326 | PINFO("Stop count: %d.\n", instance->stop_count); | ||
1327 | |||
1328 | if (trigger->iAcqStartTrigChan == ME_TRIG_CHAN_SYNCHRONOUS) { //Synchronous start | ||
1329 | instance->start_mode |= ME6000_AO_SYNC_HOLD; | ||
1330 | if (trigger->iAcqStartTrigType == ME_TRIG_TYPE_EXT_DIGITAL) { //Externaly triggered | ||
1331 | PINFO("Synchronous start. Externaly trigger active.\n"); | ||
1332 | instance->start_mode |= ME6000_AO_SYNC_EXT_TRIG; | ||
1333 | } | ||
1334 | #ifdef MEDEBUG_INFO | ||
1335 | else { | ||
1336 | PINFO | ||
1337 | ("Synchronous start. Externaly trigger dissabled.\n"); | ||
1338 | } | ||
1339 | #endif | ||
1340 | |||
1341 | } | ||
1342 | //Set speed | ||
1343 | outl(conv_ticks - 2, instance->timer_reg); | ||
1344 | PDEBUG_REG("timer_reg outl(0x%lX+0x%lX)=0x%llx\n", instance->reg_base, | ||
1345 | instance->timer_reg - instance->reg_base, conv_ticks - 2); | ||
1346 | instance->hardware_stop_delay = (int)(conv_ticks * HZ) / ME6000_AO_BASE_FREQUENCY; //<== MUST be with cast! | ||
1347 | |||
1348 | // Write the control word | ||
1349 | outl(ctrl, instance->ctrl_reg); | ||
1350 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
1351 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
1352 | |||
1353 | //Set status. | ||
1354 | instance->status = ao_status_stream_configured; | ||
1355 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
1356 | |||
1357 | ME_SUBDEVICE_EXIT; | ||
1358 | |||
1359 | return err; | ||
1360 | } | ||
1361 | |||
1362 | static int me6000_ao_io_stream_new_values(me_subdevice_t * subdevice, | ||
1363 | struct file *filep, | ||
1364 | int time_out, int *count, int flags) | ||
1365 | { | ||
1366 | me6000_ao_subdevice_t *instance; | ||
1367 | int err = ME_ERRNO_SUCCESS; | ||
1368 | long t = 0; | ||
1369 | long j; | ||
1370 | |||
1371 | instance = (me6000_ao_subdevice_t *) subdevice; | ||
1372 | |||
1373 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
1374 | |||
1375 | if (!(instance->fifo & ME6000_AO_HAS_FIFO)) { | ||
1376 | PERROR("Not a streaming ao.\n"); | ||
1377 | return ME_ERRNO_NOT_SUPPORTED; | ||
1378 | } | ||
1379 | |||
1380 | if (flags) { | ||
1381 | PERROR("Invalid flag specified.\n"); | ||
1382 | return ME_ERRNO_INVALID_FLAGS; | ||
1383 | } | ||
1384 | |||
1385 | if (!instance->circ_buf.buf) { | ||
1386 | PERROR("Circular buffer not exists.\n"); | ||
1387 | return ME_ERRNO_INTERNAL; | ||
1388 | } | ||
1389 | |||
1390 | if (time_out < 0) { | ||
1391 | PERROR("Invalid time_out specified.\n"); | ||
1392 | return ME_ERRNO_INVALID_TIMEOUT; | ||
1393 | } | ||
1394 | |||
1395 | ME_SUBDEVICE_ENTER; | ||
1396 | |||
1397 | if (me_circ_buf_space(&instance->circ_buf)) { //The buffer is NOT full. | ||
1398 | *count = me_circ_buf_space(&instance->circ_buf); | ||
1399 | } else { //The buffer is full. | ||
1400 | if (time_out) { | ||
1401 | t = (time_out * HZ) / 1000; | ||
1402 | |||
1403 | if (t == 0) | ||
1404 | t = 1; | ||
1405 | } else { //Max time. | ||
1406 | t = LONG_MAX; | ||
1407 | } | ||
1408 | |||
1409 | *count = 0; | ||
1410 | |||
1411 | j = jiffies; | ||
1412 | |||
1413 | //Only runing process will interrupt this call. Interrupts are when FIFO HF is signaled. | ||
1414 | wait_event_interruptible_timeout(instance->wait_queue, | ||
1415 | ((me_circ_buf_space | ||
1416 | (&instance->circ_buf)) | ||
1417 | || !(inl(instance->status_reg) | ||
1418 | & | ||
1419 | ME6000_AO_STATUS_BIT_FSM)), | ||
1420 | t); | ||
1421 | |||
1422 | if (!(inl(instance->status_reg) & ME6000_AO_STATUS_BIT_FSM)) { | ||
1423 | PERROR("AO subdevice is not running.\n"); | ||
1424 | err = ME_ERRNO_SUBDEVICE_NOT_RUNNING; | ||
1425 | } else if (signal_pending(current)) { | ||
1426 | PERROR("Wait on values interrupted from signal.\n"); | ||
1427 | instance->status = ao_status_none; | ||
1428 | ao_stop_immediately(instance); | ||
1429 | err = ME_ERRNO_SIGNAL; | ||
1430 | } else if ((jiffies - j) >= t) { | ||
1431 | PERROR("Wait on values timed out.\n"); | ||
1432 | err = ME_ERRNO_TIMEOUT; | ||
1433 | } else { //Uff... all is good. Inform user about empty space. | ||
1434 | *count = me_circ_buf_space(&instance->circ_buf); | ||
1435 | } | ||
1436 | } | ||
1437 | |||
1438 | ME_SUBDEVICE_EXIT; | ||
1439 | |||
1440 | return err; | ||
1441 | } | ||
1442 | |||
1443 | static int me6000_ao_io_stream_start(me_subdevice_t * subdevice, | ||
1444 | struct file *filep, | ||
1445 | int start_mode, int time_out, int flags) | ||
1446 | { | ||
1447 | me6000_ao_subdevice_t *instance; | ||
1448 | int err = ME_ERRNO_SUCCESS; | ||
1449 | unsigned long cpu_flags = 0; | ||
1450 | uint32_t status; | ||
1451 | uint32_t ctrl; | ||
1452 | uint32_t synch; | ||
1453 | int count = 0; | ||
1454 | int circ_buffer_count; | ||
1455 | |||
1456 | unsigned long ref; | ||
1457 | unsigned long delay = 0; | ||
1458 | |||
1459 | instance = (me6000_ao_subdevice_t *) subdevice; | ||
1460 | |||
1461 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
1462 | |||
1463 | if (!(instance->fifo & ME6000_AO_HAS_FIFO)) { | ||
1464 | PERROR("Not a streaming ao.\n"); | ||
1465 | return ME_ERRNO_NOT_SUPPORTED; | ||
1466 | } | ||
1467 | |||
1468 | if (flags & ~ME_IO_STREAM_START_TYPE_TRIG_SYNCHRONOUS) { | ||
1469 | PERROR("Invalid flags.\n"); | ||
1470 | return ME_ERRNO_INVALID_FLAGS; | ||
1471 | } | ||
1472 | |||
1473 | if (time_out < 0) { | ||
1474 | PERROR("Invalid timeout specified.\n"); | ||
1475 | return ME_ERRNO_INVALID_TIMEOUT; | ||
1476 | } | ||
1477 | |||
1478 | if ((start_mode != ME_START_MODE_BLOCKING) | ||
1479 | && (start_mode != ME_START_MODE_NONBLOCKING)) { | ||
1480 | PERROR("Invalid start mode specified.\n"); | ||
1481 | return ME_ERRNO_INVALID_START_MODE; | ||
1482 | } | ||
1483 | |||
1484 | if (time_out) { | ||
1485 | delay = (time_out * HZ) / 1000; | ||
1486 | if (delay == 0) | ||
1487 | delay = 1; | ||
1488 | } | ||
1489 | |||
1490 | switch (instance->status) { //Checking actual mode. | ||
1491 | case ao_status_stream_configured: | ||
1492 | case ao_status_stream_end: | ||
1493 | //Correct modes! | ||
1494 | break; | ||
1495 | |||
1496 | //The device is in wrong mode. | ||
1497 | case ao_status_none: | ||
1498 | case ao_status_single_configured: | ||
1499 | case ao_status_single_run_wait: | ||
1500 | case ao_status_single_run: | ||
1501 | case ao_status_single_end_wait: | ||
1502 | PERROR | ||
1503 | ("Subdevice must be preinitialize correctly for streaming.\n"); | ||
1504 | return ME_ERRNO_PREVIOUS_CONFIG; | ||
1505 | |||
1506 | case ao_status_stream_fifo_error: | ||
1507 | case ao_status_stream_buffer_error: | ||
1508 | case ao_status_stream_error: | ||
1509 | PDEBUG("Before restart broke stream 'STOP' must be caled.\n"); | ||
1510 | return ME_STATUS_ERROR; | ||
1511 | |||
1512 | case ao_status_stream_run_wait: | ||
1513 | case ao_status_stream_run: | ||
1514 | case ao_status_stream_end_wait: | ||
1515 | PDEBUG("Stream is already working.\n"); | ||
1516 | return ME_ERRNO_SUBDEVICE_BUSY; | ||
1517 | |||
1518 | default: | ||
1519 | instance->status = ao_status_stream_error; | ||
1520 | PERROR_CRITICAL("Status is in wrong state!\n"); | ||
1521 | return ME_ERRNO_INTERNAL; | ||
1522 | |||
1523 | } | ||
1524 | |||
1525 | ME_SUBDEVICE_ENTER; | ||
1526 | |||
1527 | if (instance->mode == ME6000_AO_CONTINOUS) { //Continous | ||
1528 | instance->circ_buf.tail += instance->preloaded_count; | ||
1529 | instance->circ_buf.tail &= instance->circ_buf.mask; | ||
1530 | } | ||
1531 | circ_buffer_count = me_circ_buf_values(&instance->circ_buf); | ||
1532 | |||
1533 | if (!circ_buffer_count && !instance->preloaded_count) { //No values in buffer | ||
1534 | ME_SUBDEVICE_EXIT; | ||
1535 | PERROR("No values in buffer!\n"); | ||
1536 | return ME_ERRNO_LACK_OF_RESOURCES; | ||
1537 | } | ||
1538 | |||
1539 | //Cancel control task | ||
1540 | PDEBUG("Cancel control task. idx=%d\n", instance->ao_idx); | ||
1541 | instance->ao_control_task_flag = 0; | ||
1542 | cancel_delayed_work(&instance->ao_control_task); | ||
1543 | |||
1544 | //Stop device | ||
1545 | err = ao_stop_immediately(instance); | ||
1546 | if (err) { | ||
1547 | PERROR_CRITICAL("FSM IS BUSY!\n"); | ||
1548 | ME_SUBDEVICE_EXIT; | ||
1549 | |||
1550 | return ME_ERRNO_SUBDEVICE_BUSY; | ||
1551 | } | ||
1552 | //Set values for single_read() | ||
1553 | instance->single_value = ME6000_AO_MAX_DATA + 1; | ||
1554 | instance->single_value_in_fifo = ME6000_AO_MAX_DATA + 1; | ||
1555 | |||
1556 | //Setting stop points | ||
1557 | if (instance->stop_mode == ME6000_AO_SCAN_STOP_MODE) { | ||
1558 | instance->stop_data_count = | ||
1559 | instance->stop_count * circ_buffer_count; | ||
1560 | } else { | ||
1561 | instance->stop_data_count = instance->stop_count; | ||
1562 | } | ||
1563 | |||
1564 | if ((instance->stop_data_count != 0) | ||
1565 | && (instance->stop_data_count < circ_buffer_count)) { | ||
1566 | PERROR("More data in buffer than previously set limit!\n"); | ||
1567 | } | ||
1568 | |||
1569 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
1570 | ctrl = inl(instance->ctrl_reg); | ||
1571 | //Check FIFO | ||
1572 | if (!(ctrl & ME6000_AO_CTRL_BIT_ENABLE_FIFO)) { //FIFO wasn't enabeled. Do it. <= This should be done by user call with ME_WRITE_MODE_PRELOAD | ||
1573 | PINFO("Enableing FIFO.\n"); | ||
1574 | ctrl |= ME6000_AO_CTRL_BIT_ENABLE_FIFO; | ||
1575 | ctrl &= ~ME6000_AO_CTRL_BIT_ENABLE_IRQ; | ||
1576 | |||
1577 | instance->preloaded_count = 0; | ||
1578 | instance->data_count = 0; | ||
1579 | } else { //Block IRQ | ||
1580 | ctrl &= ~ME6000_AO_CTRL_BIT_ENABLE_IRQ; | ||
1581 | } | ||
1582 | outl(ctrl, instance->ctrl_reg); | ||
1583 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
1584 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
1585 | |||
1586 | //Reset interrupt latch | ||
1587 | inl(instance->irq_reset_reg); | ||
1588 | |||
1589 | //Fill FIFO <= Generaly this should be done by user pre-load call but this is second place to do it. | ||
1590 | status = inl(instance->status_reg); | ||
1591 | if (!(status & ME6000_AO_STATUS_BIT_EF)) { //FIFO empty | ||
1592 | if (instance->stop_data_count != 0) { | ||
1593 | count = ME6000_AO_FIFO_COUNT; | ||
1594 | } else { | ||
1595 | count = | ||
1596 | (ME6000_AO_FIFO_COUNT < | ||
1597 | instance-> | ||
1598 | stop_data_count) ? ME6000_AO_FIFO_COUNT : | ||
1599 | instance->stop_data_count; | ||
1600 | } | ||
1601 | |||
1602 | //Copy data | ||
1603 | count = | ||
1604 | ao_write_data(instance, count, instance->preloaded_count); | ||
1605 | |||
1606 | if (count < 0) { //This should never happend! | ||
1607 | PERROR_CRITICAL("COPY FINISH WITH ERROR!\n"); | ||
1608 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
1609 | cpu_flags); | ||
1610 | ME_SUBDEVICE_EXIT; | ||
1611 | return ME_ERRNO_INTERNAL; | ||
1612 | } | ||
1613 | } | ||
1614 | //Set pre-load features. | ||
1615 | spin_lock(instance->preload_reg_lock); | ||
1616 | synch = inl(instance->preload_reg); | ||
1617 | synch &= | ||
1618 | ~((ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG) << instance-> | ||
1619 | ao_idx); | ||
1620 | synch |= | ||
1621 | (instance->start_mode & ~ME6000_AO_EXT_TRIG) << instance->ao_idx; | ||
1622 | outl(synch, instance->preload_reg); | ||
1623 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
1624 | instance->preload_reg - instance->reg_base, synch); | ||
1625 | spin_unlock(instance->preload_reg_lock); | ||
1626 | |||
1627 | //Default count is '0' | ||
1628 | if (instance->mode == ME6000_AO_CONTINOUS) { //Continous | ||
1629 | instance->preloaded_count = 0; | ||
1630 | instance->circ_buf.tail += count; | ||
1631 | instance->circ_buf.tail &= instance->circ_buf.mask; | ||
1632 | } else { //Wraparound | ||
1633 | instance->preloaded_count += count; | ||
1634 | instance->data_count += count; | ||
1635 | |||
1636 | //Special case: Infinite wraparound with less than FIFO datas always should runs in hardware mode. | ||
1637 | if ((instance->stop_mode == ME6000_AO_INF_STOP_MODE) | ||
1638 | && (circ_buffer_count <= ME6000_AO_FIFO_COUNT)) { //Change to hardware wraparound | ||
1639 | PDEBUG | ||
1640 | ("Changeing mode from software wraparound to hardware wraparound.\n"); | ||
1641 | //Copy all data | ||
1642 | count = | ||
1643 | ao_write_data(instance, circ_buffer_count, | ||
1644 | instance->preloaded_count); | ||
1645 | ctrl &= ~ME6000_AO_CTRL_MODE_MASK; | ||
1646 | ctrl |= ME6000_AO_MODE_WRAPAROUND; | ||
1647 | } | ||
1648 | |||
1649 | if (instance->preloaded_count == me_circ_buf_values(&instance->circ_buf)) { //Reset position indicator. | ||
1650 | instance->preloaded_count = 0; | ||
1651 | } else if (instance->preloaded_count > me_circ_buf_values(&instance->circ_buf)) { //This should never happend! | ||
1652 | PERROR_CRITICAL | ||
1653 | ("PRELOADED MORE VALUES THAN ARE IN BUFFER!\n"); | ||
1654 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
1655 | cpu_flags); | ||
1656 | ME_SUBDEVICE_EXIT; | ||
1657 | return ME_ERRNO_INTERNAL; | ||
1658 | } | ||
1659 | } | ||
1660 | |||
1661 | //Set status to 'wait for start' | ||
1662 | instance->status = ao_status_stream_run_wait; | ||
1663 | |||
1664 | status = inl(instance->status_reg); | ||
1665 | //Start state machine and interrupts | ||
1666 | PINFO("<%s:%d> Start state machine.\n", __FUNCTION__, __LINE__); | ||
1667 | ctrl &= ~(ME6000_AO_CTRL_BIT_STOP | ME6000_AO_CTRL_BIT_IMMEDIATE_STOP); | ||
1668 | if (instance->start_mode == ME6000_AO_EXT_TRIG) { | ||
1669 | PDEBUG("DIGITAL TRIGGER\n"); | ||
1670 | ctrl |= ME6000_AO_CTRL_BIT_ENABLE_EX_TRIG; | ||
1671 | } | ||
1672 | if (!(status & ME6000_AO_STATUS_BIT_HF)) { //More than half! | ||
1673 | if ((ctrl & ME6000_AO_CTRL_MODE_MASK) == ME6000_AO_MODE_CONTINUOUS) { //Enable IRQ only when hardware_continous is set and FIFO is more than half | ||
1674 | PINFO("<%s:%d> Start interrupts.\n", __FUNCTION__, | ||
1675 | __LINE__); | ||
1676 | ctrl |= ME6000_AO_CTRL_BIT_ENABLE_IRQ; | ||
1677 | } | ||
1678 | } | ||
1679 | outl(ctrl, instance->ctrl_reg); | ||
1680 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
1681 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
1682 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
1683 | |||
1684 | //Trigger output | ||
1685 | PINFO("<%s> start mode= 0x%x %s\n", __FUNCTION__, instance->start_mode, | ||
1686 | (flags & ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS) ? "SYNCHRONOUS" : | ||
1687 | ""); | ||
1688 | if (flags & ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS) { //Trigger outputs | ||
1689 | spin_lock(instance->preload_reg_lock); | ||
1690 | synch = inl(instance->preload_reg); | ||
1691 | //Add channel to start list | ||
1692 | outl(synch | (ME6000_AO_SYNC_HOLD << instance->ao_idx), | ||
1693 | instance->preload_reg); | ||
1694 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
1695 | instance->reg_base, | ||
1696 | instance->preload_reg - instance->reg_base, | ||
1697 | synch | (ME6000_AO_SYNC_HOLD << instance->ao_idx)); | ||
1698 | |||
1699 | //Fire | ||
1700 | PINFO | ||
1701 | ("Fired all software synchronous outputs by software trigger.\n"); | ||
1702 | outl(0x8000, instance->single_reg); | ||
1703 | PDEBUG_REG("single_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
1704 | instance->reg_base, | ||
1705 | instance->single_reg - instance->reg_base, 0x8000); | ||
1706 | |||
1707 | //Restore save settings | ||
1708 | outl(synch, instance->preload_reg); | ||
1709 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
1710 | instance->reg_base, | ||
1711 | instance->preload_reg - instance->reg_base, synch); | ||
1712 | spin_unlock(instance->preload_reg_lock); | ||
1713 | } else if (!instance->start_mode) { //Trigger outputs | ||
1714 | /* | ||
1715 | spin_lock(instance->preload_reg_lock); | ||
1716 | synch = inl(instance->preload_reg); | ||
1717 | //Remove channel from start list | ||
1718 | outl(synch & ~(ME6000_AO_SYNC_HOLD << instance->ao_idx), instance->preload_reg); | ||
1719 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, instance->preload_reg - instance->reg_base, synch & ~(ME6000_AO_SYNC_HOLD << instance->ao_idx)); | ||
1720 | */ | ||
1721 | //Fire | ||
1722 | PINFO("Software trigger.\n"); | ||
1723 | outl(0x8000, instance->single_reg); | ||
1724 | PDEBUG_REG("single_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
1725 | instance->reg_base, | ||
1726 | instance->single_reg - instance->reg_base, 0x8000); | ||
1727 | |||
1728 | /* | ||
1729 | //Restore save settings | ||
1730 | outl(synch, instance->preload_reg); | ||
1731 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, instance->preload_reg - instance->reg_base, synch); | ||
1732 | spin_unlock(instance->preload_reg_lock); | ||
1733 | */ | ||
1734 | } | ||
1735 | // Set control task's timeout | ||
1736 | instance->timeout.delay = delay; | ||
1737 | instance->timeout.start_time = jiffies; | ||
1738 | |||
1739 | if (status & ME6000_AO_STATUS_BIT_HF) { //Less than half but not empty! | ||
1740 | PINFO("Less than half.\n"); | ||
1741 | if (instance->stop_data_count == 0) { | ||
1742 | count = ME6000_AO_FIFO_COUNT / 2; | ||
1743 | } else { | ||
1744 | count = | ||
1745 | ((ME6000_AO_FIFO_COUNT / 2) < | ||
1746 | instance->stop_data_count) ? ME6000_AO_FIFO_COUNT / | ||
1747 | 2 : instance->stop_data_count; | ||
1748 | } | ||
1749 | |||
1750 | //Copy data | ||
1751 | count = | ||
1752 | ao_write_data(instance, count, instance->preloaded_count); | ||
1753 | |||
1754 | if (count < 0) { //This should never happend! | ||
1755 | PERROR_CRITICAL("COPY FINISH WITH ERROR!\n"); | ||
1756 | ME_SUBDEVICE_EXIT; | ||
1757 | return ME_ERRNO_INTERNAL; | ||
1758 | } | ||
1759 | |||
1760 | if (instance->mode == ME6000_AO_CONTINOUS) { //Continous | ||
1761 | instance->circ_buf.tail += count; | ||
1762 | instance->circ_buf.tail &= instance->circ_buf.mask; | ||
1763 | } else { //Wraparound | ||
1764 | instance->data_count += count; | ||
1765 | instance->preloaded_count += count; | ||
1766 | |||
1767 | if (instance->preloaded_count == me_circ_buf_values(&instance->circ_buf)) { //Reset position indicator. | ||
1768 | instance->preloaded_count = 0; | ||
1769 | } else if (instance->preloaded_count > me_circ_buf_values(&instance->circ_buf)) { //This should never happend! | ||
1770 | PERROR_CRITICAL | ||
1771 | ("PRELOADED MORE VALUES THAN ARE IN BUFFER!\n"); | ||
1772 | ME_SUBDEVICE_EXIT; | ||
1773 | return ME_ERRNO_INTERNAL; | ||
1774 | } | ||
1775 | } | ||
1776 | |||
1777 | status = inl(instance->status_reg); | ||
1778 | if (!(status & ME6000_AO_STATUS_BIT_HF)) { //More than half! | ||
1779 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
1780 | PINFO("<%s:%d> Start interrupts.\n", __FUNCTION__, | ||
1781 | __LINE__); | ||
1782 | ctrl = inl(instance->ctrl_reg); | ||
1783 | ctrl |= ME6000_AO_CTRL_BIT_ENABLE_IRQ; | ||
1784 | outl(ctrl, instance->ctrl_reg); | ||
1785 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
1786 | instance->reg_base, | ||
1787 | instance->ctrl_reg - instance->reg_base, | ||
1788 | ctrl); | ||
1789 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
1790 | cpu_flags); | ||
1791 | } | ||
1792 | } | ||
1793 | //Special case: Limited wraparound with less than HALF FIFO datas need work around to generate first interrupt. | ||
1794 | if ((instance->stop_mode != ME6000_AO_INF_STOP_MODE) | ||
1795 | && (instance->mode == ME6000_AO_SW_WRAP_MODE) | ||
1796 | && (circ_buffer_count <= (ME6000_AO_FIFO_COUNT / 2))) { //Put more data to FIFO | ||
1797 | PINFO("Limited wraparound with less than HALF FIFO datas.\n"); | ||
1798 | if (instance->preloaded_count) { //This should never happend! | ||
1799 | PERROR_CRITICAL | ||
1800 | ("ERROR WHEN LOADING VALUES FOR WRAPAROUND!\n"); | ||
1801 | ME_SUBDEVICE_EXIT; | ||
1802 | return ME_ERRNO_INTERNAL; | ||
1803 | } | ||
1804 | |||
1805 | while (instance->stop_data_count > instance->data_count) { //Maximum data not set jet. | ||
1806 | //Copy to buffer | ||
1807 | if (circ_buffer_count != ao_write_data(instance, circ_buffer_count, 0)) { //This should never happend! | ||
1808 | PERROR_CRITICAL | ||
1809 | ("ERROR WHEN LOADING VALUES FOR WRAPAROUND!\n"); | ||
1810 | ME_SUBDEVICE_EXIT; | ||
1811 | return ME_ERRNO_INTERNAL; | ||
1812 | } | ||
1813 | instance->data_count += circ_buffer_count; | ||
1814 | |||
1815 | if (!((status = inl(instance->status_reg)) & ME6000_AO_STATUS_BIT_HF)) { //FIFO is more than half. Enable IRQ and end copy. | ||
1816 | //Reset interrupt latch | ||
1817 | inl(instance->irq_reset_reg); | ||
1818 | |||
1819 | spin_lock_irqsave(&instance->subdevice_lock, | ||
1820 | cpu_flags); | ||
1821 | PINFO("<%s:%d> Start interrupts.\n", | ||
1822 | __FUNCTION__, __LINE__); | ||
1823 | ctrl = inl(instance->ctrl_reg); | ||
1824 | ctrl |= ME6000_AO_CTRL_BIT_ENABLE_IRQ; | ||
1825 | outl(ctrl, instance->ctrl_reg); | ||
1826 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
1827 | instance->reg_base, | ||
1828 | instance->ctrl_reg - | ||
1829 | instance->reg_base, ctrl); | ||
1830 | spin_unlock_irqrestore(&instance-> | ||
1831 | subdevice_lock, | ||
1832 | cpu_flags); | ||
1833 | break; | ||
1834 | } | ||
1835 | } | ||
1836 | } | ||
1837 | // Schedule control task | ||
1838 | instance->ao_control_task_flag = 1; | ||
1839 | queue_delayed_work(instance->me6000_workqueue, | ||
1840 | &instance->ao_control_task, 1); | ||
1841 | |||
1842 | if (start_mode == ME_START_MODE_BLOCKING) { //Wait for start. | ||
1843 | ref = jiffies; | ||
1844 | //Only runing process will interrupt this call. Events are signaled when status change. Extra timeout add for safe reason. | ||
1845 | wait_event_interruptible_timeout(instance->wait_queue, | ||
1846 | (instance->status != | ||
1847 | ao_status_stream_run_wait), | ||
1848 | (delay) ? delay + | ||
1849 | 1 : LONG_MAX); | ||
1850 | |||
1851 | if ((instance->status != ao_status_stream_run) | ||
1852 | && (instance->status != ao_status_stream_end)) { | ||
1853 | PDEBUG("Starting stream canceled. %d\n", | ||
1854 | instance->status); | ||
1855 | err = ME_ERRNO_CANCELLED; | ||
1856 | } | ||
1857 | |||
1858 | if (signal_pending(current)) { | ||
1859 | PERROR("Wait on start of state machine interrupted.\n"); | ||
1860 | instance->status = ao_status_none; | ||
1861 | ao_stop_immediately(instance); | ||
1862 | err = ME_ERRNO_SIGNAL; | ||
1863 | } | ||
1864 | |||
1865 | if ((delay) && ((jiffies - ref) >= delay)) { | ||
1866 | if (instance->status != ao_status_stream_run) { | ||
1867 | if (instance->status == ao_status_stream_end) { | ||
1868 | PDEBUG("Timeout reached.\n"); | ||
1869 | } else if ((jiffies - ref) > delay) { | ||
1870 | PERROR | ||
1871 | ("Timeout reached. Not handled by control task!\n"); | ||
1872 | ao_stop_immediately(instance); | ||
1873 | } else { | ||
1874 | PERROR | ||
1875 | ("Timeout reached. Signal come but status is strange: %d\n", | ||
1876 | instance->status); | ||
1877 | ao_stop_immediately(instance); | ||
1878 | } | ||
1879 | |||
1880 | instance->ao_control_task_flag = 0; | ||
1881 | cancel_delayed_work(&instance->ao_control_task); | ||
1882 | instance->status = ao_status_stream_end; | ||
1883 | err = ME_ERRNO_TIMEOUT; | ||
1884 | } | ||
1885 | } | ||
1886 | } | ||
1887 | |||
1888 | ME_SUBDEVICE_EXIT; | ||
1889 | return err; | ||
1890 | } | ||
1891 | |||
1892 | static int me6000_ao_io_stream_status(me_subdevice_t * subdevice, | ||
1893 | struct file *filep, | ||
1894 | int wait, | ||
1895 | int *status, int *values, int flags) | ||
1896 | { | ||
1897 | me6000_ao_subdevice_t *instance; | ||
1898 | int err = ME_ERRNO_SUCCESS; | ||
1899 | |||
1900 | instance = (me6000_ao_subdevice_t *) subdevice; | ||
1901 | |||
1902 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
1903 | |||
1904 | if (!(instance->fifo & ME6000_AO_HAS_FIFO)) { | ||
1905 | PERROR("Not a streaming ao.\n"); | ||
1906 | return ME_ERRNO_NOT_SUPPORTED; | ||
1907 | } | ||
1908 | |||
1909 | if (flags) { | ||
1910 | PERROR("Invalid flag specified.\n"); | ||
1911 | return ME_ERRNO_INVALID_FLAGS; | ||
1912 | } | ||
1913 | |||
1914 | if ((wait != ME_WAIT_NONE) && (wait != ME_WAIT_IDLE)) { | ||
1915 | PERROR("Invalid wait argument specified.\n"); | ||
1916 | *status = ME_STATUS_INVALID; | ||
1917 | return ME_ERRNO_INVALID_WAIT; | ||
1918 | } | ||
1919 | |||
1920 | ME_SUBDEVICE_ENTER; | ||
1921 | |||
1922 | switch (instance->status) { | ||
1923 | case ao_status_single_configured: | ||
1924 | case ao_status_single_end: | ||
1925 | case ao_status_stream_configured: | ||
1926 | case ao_status_stream_end: | ||
1927 | case ao_status_stream_fifo_error: | ||
1928 | case ao_status_stream_buffer_error: | ||
1929 | case ao_status_stream_error: | ||
1930 | *status = ME_STATUS_IDLE; | ||
1931 | break; | ||
1932 | |||
1933 | case ao_status_single_run_wait: | ||
1934 | case ao_status_single_run: | ||
1935 | case ao_status_single_end_wait: | ||
1936 | case ao_status_stream_run_wait: | ||
1937 | case ao_status_stream_run: | ||
1938 | case ao_status_stream_end_wait: | ||
1939 | *status = ME_STATUS_BUSY; | ||
1940 | break; | ||
1941 | |||
1942 | case ao_status_none: | ||
1943 | default: | ||
1944 | *status = | ||
1945 | (inl(instance->status_reg) & ME6000_AO_STATUS_BIT_FSM) ? | ||
1946 | ME_STATUS_BUSY : ME_STATUS_IDLE; | ||
1947 | break; | ||
1948 | } | ||
1949 | |||
1950 | if ((wait == ME_WAIT_IDLE) && (*status == ME_STATUS_BUSY)) { | ||
1951 | //Only runing process will interrupt this call. Events are signaled when status change. Extra timeout add for safe reason. | ||
1952 | wait_event_interruptible_timeout(instance->wait_queue, | ||
1953 | ((instance->status != | ||
1954 | ao_status_single_run_wait) | ||
1955 | && (instance->status != | ||
1956 | ao_status_single_run) | ||
1957 | && (instance->status != | ||
1958 | ao_status_single_end_wait) | ||
1959 | && (instance->status != | ||
1960 | ao_status_stream_run_wait) | ||
1961 | && (instance->status != | ||
1962 | ao_status_stream_run) | ||
1963 | && (instance->status != | ||
1964 | ao_status_stream_end_wait)), | ||
1965 | LONG_MAX); | ||
1966 | |||
1967 | if (instance->status != ao_status_stream_end) { | ||
1968 | PDEBUG("Wait for IDLE canceled. %d\n", | ||
1969 | instance->status); | ||
1970 | err = ME_ERRNO_CANCELLED; | ||
1971 | } | ||
1972 | |||
1973 | if (signal_pending(current)) { | ||
1974 | PERROR("Wait for IDLE interrupted.\n"); | ||
1975 | instance->status = ao_status_none; | ||
1976 | ao_stop_immediately(instance); | ||
1977 | err = ME_ERRNO_SIGNAL; | ||
1978 | } | ||
1979 | |||
1980 | *status = ME_STATUS_IDLE; | ||
1981 | } | ||
1982 | |||
1983 | *values = me_circ_buf_space(&instance->circ_buf); | ||
1984 | |||
1985 | ME_SUBDEVICE_EXIT; | ||
1986 | |||
1987 | return err; | ||
1988 | } | ||
1989 | |||
1990 | static int me6000_ao_io_stream_stop(me_subdevice_t * subdevice, | ||
1991 | struct file *filep, | ||
1992 | int stop_mode, int flags) | ||
1993 | { /// @note Stop work and empty buffer and FIFO | ||
1994 | int err = ME_ERRNO_SUCCESS; | ||
1995 | me6000_ao_subdevice_t *instance; | ||
1996 | unsigned long cpu_flags; | ||
1997 | volatile uint32_t ctrl; | ||
1998 | |||
1999 | instance = (me6000_ao_subdevice_t *) subdevice; | ||
2000 | |||
2001 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
2002 | |||
2003 | if (flags & ~ME_IO_STREAM_STOP_PRESERVE_BUFFERS) { | ||
2004 | PERROR("Invalid flag specified.\n"); | ||
2005 | return ME_ERRNO_INVALID_FLAGS; | ||
2006 | } | ||
2007 | |||
2008 | if ((stop_mode != ME_STOP_MODE_IMMEDIATE) | ||
2009 | && (stop_mode != ME_STOP_MODE_LAST_VALUE)) { | ||
2010 | PERROR("Invalid stop mode specified.\n"); | ||
2011 | return ME_ERRNO_INVALID_STOP_MODE; | ||
2012 | } | ||
2013 | |||
2014 | if (!(instance->fifo & ME6000_AO_HAS_FIFO)) { | ||
2015 | PERROR("Not a streaming ao.\n"); | ||
2016 | return ME_ERRNO_NOT_SUPPORTED; | ||
2017 | } | ||
2018 | |||
2019 | if (instance->status < ao_status_stream_configured) { | ||
2020 | //There is nothing to stop! | ||
2021 | PERROR("Subdevice not in streaming mode. %d\n", | ||
2022 | instance->status); | ||
2023 | return ME_ERRNO_PREVIOUS_CONFIG; | ||
2024 | } | ||
2025 | |||
2026 | ME_SUBDEVICE_ENTER; | ||
2027 | |||
2028 | //Mark as stopping. => Software stop. | ||
2029 | instance->status = ao_status_stream_end_wait; | ||
2030 | |||
2031 | if (stop_mode == ME_STOP_MODE_IMMEDIATE) { //Stopped now! | ||
2032 | err = ao_stop_immediately(instance); | ||
2033 | } else if (stop_mode == ME_STOP_MODE_LAST_VALUE) { | ||
2034 | ctrl = inl(instance->ctrl_reg) & ME6000_AO_CTRL_MODE_MASK; | ||
2035 | if (ctrl == ME6000_AO_MODE_WRAPAROUND) { //Hardware wraparound => Hardware stop. | ||
2036 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
2037 | ctrl = inl(instance->ctrl_reg); | ||
2038 | ctrl |= ME6000_AO_CTRL_BIT_STOP; | ||
2039 | ctrl &= ~ME6000_AO_CTRL_BIT_ENABLE_IRQ; | ||
2040 | outl(ctrl, instance->ctrl_reg); | ||
2041 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2042 | instance->reg_base, | ||
2043 | instance->ctrl_reg - instance->reg_base, | ||
2044 | ctrl); | ||
2045 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
2046 | cpu_flags); | ||
2047 | |||
2048 | //Reset interrupt latch | ||
2049 | inl(instance->irq_reset_reg); | ||
2050 | } | ||
2051 | //Only runing process will interrupt this call. Events are signaled when status change. Extra timeout add for safe reason. | ||
2052 | wait_event_interruptible_timeout(instance->wait_queue, | ||
2053 | (instance->status != | ||
2054 | ao_status_stream_end_wait), | ||
2055 | LONG_MAX); | ||
2056 | |||
2057 | if (instance->status != ao_status_stream_end) { | ||
2058 | PDEBUG("Stopping stream canceled.\n"); | ||
2059 | err = ME_ERRNO_CANCELLED; | ||
2060 | } | ||
2061 | |||
2062 | if (signal_pending(current)) { | ||
2063 | PERROR("Stopping stream interrupted.\n"); | ||
2064 | instance->status = ao_status_none; | ||
2065 | ao_stop_immediately(instance); | ||
2066 | err = ME_ERRNO_SIGNAL; | ||
2067 | } | ||
2068 | } | ||
2069 | |||
2070 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
2071 | ctrl = inl(instance->ctrl_reg); | ||
2072 | ctrl |= ME6000_AO_CTRL_BIT_STOP | ME6000_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
2073 | ctrl &= ~ME6000_AO_CTRL_BIT_ENABLE_IRQ; | ||
2074 | if (!flags) { //Reset FIFO | ||
2075 | ctrl &= ~ME6000_AO_CTRL_BIT_ENABLE_FIFO; | ||
2076 | } | ||
2077 | outl(ctrl, instance->ctrl_reg); | ||
2078 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
2079 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
2080 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
2081 | |||
2082 | //Reset interrupt latch | ||
2083 | inl(instance->irq_reset_reg); | ||
2084 | |||
2085 | if (!flags) { //Reset software buffer | ||
2086 | instance->circ_buf.head = 0; | ||
2087 | instance->circ_buf.tail = 0; | ||
2088 | instance->preloaded_count = 0; | ||
2089 | instance->data_count = 0; | ||
2090 | } | ||
2091 | |||
2092 | ME_SUBDEVICE_EXIT; | ||
2093 | |||
2094 | return err; | ||
2095 | } | ||
2096 | |||
2097 | static int me6000_ao_io_stream_write(me_subdevice_t * subdevice, | ||
2098 | struct file *filep, | ||
2099 | int write_mode, | ||
2100 | int *values, int *count, int flags) | ||
2101 | { | ||
2102 | int err = ME_ERRNO_SUCCESS; | ||
2103 | me6000_ao_subdevice_t *instance; | ||
2104 | unsigned long cpu_flags = 0; | ||
2105 | uint32_t reg_copy; | ||
2106 | |||
2107 | int copied_from_user = 0; | ||
2108 | int left_to_copy_from_user = *count; | ||
2109 | |||
2110 | int copied_values; | ||
2111 | |||
2112 | instance = (me6000_ao_subdevice_t *) subdevice; | ||
2113 | |||
2114 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
2115 | |||
2116 | //Checking arguments | ||
2117 | if (!(instance->fifo & ME6000_AO_HAS_FIFO)) { | ||
2118 | PERROR("Not a streaming ao.\n"); | ||
2119 | return ME_ERRNO_NOT_SUPPORTED; | ||
2120 | } | ||
2121 | |||
2122 | if (flags) { | ||
2123 | PERROR("Invalid flag specified.\n"); | ||
2124 | return ME_ERRNO_INVALID_FLAGS; | ||
2125 | } | ||
2126 | |||
2127 | if (*count <= 0) { | ||
2128 | PERROR("Invalid count of values specified.\n"); | ||
2129 | return ME_ERRNO_INVALID_VALUE_COUNT; | ||
2130 | } | ||
2131 | |||
2132 | if (values == NULL) { | ||
2133 | PERROR("Invalid address of values specified.\n"); | ||
2134 | return ME_ERRNO_INVALID_POINTER; | ||
2135 | } | ||
2136 | |||
2137 | if ((instance->status == ao_status_none) || (instance->status == ao_status_single_configured)) { //The device is in single mode. | ||
2138 | PERROR | ||
2139 | ("Subdevice must be preinitialize correctly for streaming.\n"); | ||
2140 | return ME_ERRNO_PREVIOUS_CONFIG; | ||
2141 | } | ||
2142 | |||
2143 | switch (write_mode) { | ||
2144 | case ME_WRITE_MODE_PRELOAD: | ||
2145 | |||
2146 | //Device must be stopped. | ||
2147 | if ((instance->status != ao_status_stream_configured) | ||
2148 | && (instance->status != ao_status_stream_end)) { | ||
2149 | PERROR | ||
2150 | ("Subdevice mustn't be runing when 'pre-load' mode is used.\n"); | ||
2151 | return ME_ERRNO_PREVIOUS_CONFIG; | ||
2152 | } | ||
2153 | break; | ||
2154 | case ME_WRITE_MODE_NONBLOCKING: | ||
2155 | case ME_WRITE_MODE_BLOCKING: | ||
2156 | /// @note In blocking mode: When device is not runing and there is not enought space call will blocked up! | ||
2157 | /// @note Some other thread must empty buffer by strating engine. | ||
2158 | break; | ||
2159 | |||
2160 | default: | ||
2161 | PERROR("Invalid write mode specified.\n"); | ||
2162 | return ME_ERRNO_INVALID_WRITE_MODE; | ||
2163 | } | ||
2164 | |||
2165 | if (instance->mode & ME6000_AO_WRAP_MODE) { //Wraparound mode. Device must be stopped. | ||
2166 | if ((instance->status != ao_status_stream_configured) | ||
2167 | && (instance->status != ao_status_stream_end)) { | ||
2168 | PERROR | ||
2169 | ("Subdevice mustn't be runing when 'pre-load' mode is used.\n"); | ||
2170 | return ME_ERRNO_INVALID_WRITE_MODE; | ||
2171 | } | ||
2172 | } | ||
2173 | |||
2174 | if ((instance->mode == ME6000_AO_HW_WRAP_MODE) | ||
2175 | && (write_mode != ME_WRITE_MODE_PRELOAD)) { | ||
2176 | /* | ||
2177 | PERROR("Only 'pre-load' write is acceptable in hardware wraparound mode.\n"); | ||
2178 | return ME_ERRNO_PREVIOUS_CONFIG; | ||
2179 | */ | ||
2180 | //This is transparent for user. | ||
2181 | PDEBUG("Changing write_mode to ME_WRITE_MODE_PRELOAD.\n"); | ||
2182 | write_mode = ME_WRITE_MODE_PRELOAD; | ||
2183 | } | ||
2184 | |||
2185 | ME_SUBDEVICE_ENTER; | ||
2186 | |||
2187 | if (write_mode == ME_WRITE_MODE_PRELOAD) { //Init enviroment - preload | ||
2188 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
2189 | reg_copy = inl(instance->ctrl_reg); | ||
2190 | //Check FIFO | ||
2191 | if (!(reg_copy & ME6000_AO_CTRL_BIT_ENABLE_FIFO)) { //FIFO not active. Enable it. | ||
2192 | reg_copy |= ME6000_AO_CTRL_BIT_ENABLE_FIFO; | ||
2193 | outl(reg_copy, instance->ctrl_reg); | ||
2194 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2195 | instance->reg_base, | ||
2196 | instance->ctrl_reg - instance->reg_base, | ||
2197 | reg_copy); | ||
2198 | instance->preloaded_count = 0; | ||
2199 | } | ||
2200 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
2201 | } | ||
2202 | |||
2203 | while (1) { | ||
2204 | //Copy to buffer. This step is common for all modes. | ||
2205 | copied_from_user = | ||
2206 | ao_get_data_from_user(instance, left_to_copy_from_user, | ||
2207 | values + (*count - | ||
2208 | left_to_copy_from_user)); | ||
2209 | left_to_copy_from_user -= copied_from_user; | ||
2210 | |||
2211 | reg_copy = inl(instance->status_reg); | ||
2212 | if ((instance->status == ao_status_stream_run) && !(reg_copy & ME6000_AO_STATUS_BIT_FSM)) { //BROKEN PIPE! The state machine is stoped but logical status show that should be working. | ||
2213 | PERROR("Broken pipe in write.\n"); | ||
2214 | err = ME_ERRNO_SUBDEVICE_NOT_RUNNING; | ||
2215 | break; | ||
2216 | } | ||
2217 | |||
2218 | if ((instance->status == ao_status_stream_run) && (instance->mode == ME6000_AO_CONTINOUS) && (reg_copy & ME6000_AO_STATUS_BIT_HF)) { //Continous mode runing and data are below half! | ||
2219 | |||
2220 | // Block interrupts. | ||
2221 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
2222 | reg_copy = inl(instance->ctrl_reg); | ||
2223 | reg_copy &= ~ME6000_AO_CTRL_BIT_ENABLE_IRQ; | ||
2224 | outl(reg_copy, instance->ctrl_reg); | ||
2225 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2226 | instance->reg_base, | ||
2227 | instance->ctrl_reg - instance->reg_base, | ||
2228 | reg_copy); | ||
2229 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
2230 | cpu_flags); | ||
2231 | |||
2232 | //Fast copy | ||
2233 | copied_values = | ||
2234 | ao_write_data(instance, ME6000_AO_FIFO_COUNT / 2, | ||
2235 | 0); | ||
2236 | if (copied_values > 0) { | ||
2237 | instance->circ_buf.tail += copied_values; | ||
2238 | instance->circ_buf.tail &= | ||
2239 | instance->circ_buf.mask; | ||
2240 | continue; | ||
2241 | } | ||
2242 | //Reset interrupt latch | ||
2243 | inl(instance->irq_reset_reg); | ||
2244 | |||
2245 | // Activate interrupts. | ||
2246 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
2247 | reg_copy = inl(instance->ctrl_reg); | ||
2248 | reg_copy |= ME6000_AO_CTRL_BIT_ENABLE_IRQ; | ||
2249 | outl(reg_copy, instance->ctrl_reg); | ||
2250 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2251 | instance->reg_base, | ||
2252 | instance->ctrl_reg - instance->reg_base, | ||
2253 | reg_copy); | ||
2254 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
2255 | cpu_flags); | ||
2256 | |||
2257 | if (copied_values == 0) { //This was checked and never should happend! | ||
2258 | PERROR_CRITICAL("COPY FINISH WITH 0!\n"); | ||
2259 | } | ||
2260 | |||
2261 | if (copied_values < 0) { //This was checked and never should happend! | ||
2262 | PERROR_CRITICAL("COPY FINISH WITH ERROR!\n"); | ||
2263 | instance->status = ao_status_stream_fifo_error; | ||
2264 | err = ME_ERRNO_FIFO_BUFFER_OVERFLOW; | ||
2265 | break; | ||
2266 | } | ||
2267 | } | ||
2268 | |||
2269 | if (!left_to_copy_from_user) { //All datas were copied. | ||
2270 | break; | ||
2271 | } else { //Not all datas were copied. | ||
2272 | if (instance->mode & ME6000_AO_WRAP_MODE) { //Error too much datas! Wraparound is limited in size! | ||
2273 | PERROR | ||
2274 | ("Too much data for wraparound mode! Exceeded size of %ld.\n", | ||
2275 | ME6000_AO_CIRC_BUF_COUNT - 1); | ||
2276 | err = ME_ERRNO_RING_BUFFER_OVERFLOW; | ||
2277 | break; | ||
2278 | } | ||
2279 | |||
2280 | if (write_mode != ME_WRITE_MODE_BLOCKING) { //Non blocking calls | ||
2281 | break; | ||
2282 | } | ||
2283 | |||
2284 | wait_event_interruptible(instance->wait_queue, | ||
2285 | me_circ_buf_space(&instance-> | ||
2286 | circ_buf)); | ||
2287 | |||
2288 | if (signal_pending(current)) { | ||
2289 | PERROR("Writing interrupted by signal.\n"); | ||
2290 | instance->status = ao_status_none; | ||
2291 | ao_stop_immediately(instance); | ||
2292 | err = ME_ERRNO_SIGNAL; | ||
2293 | break; | ||
2294 | } | ||
2295 | |||
2296 | if (instance->status == ao_status_none) { //Reset | ||
2297 | PERROR("Writing interrupted by reset.\n"); | ||
2298 | err = ME_ERRNO_CANCELLED; | ||
2299 | break; | ||
2300 | } | ||
2301 | } | ||
2302 | } | ||
2303 | |||
2304 | if (write_mode == ME_WRITE_MODE_PRELOAD) { //Copy data to FIFO - preload | ||
2305 | copied_values = | ||
2306 | ao_write_data_pooling(instance, ME6000_AO_FIFO_COUNT, | ||
2307 | instance->preloaded_count); | ||
2308 | instance->preloaded_count += copied_values; | ||
2309 | instance->data_count += copied_values; | ||
2310 | |||
2311 | if ((instance->mode == ME6000_AO_HW_WRAP_MODE) | ||
2312 | && (me_circ_buf_values(&instance->circ_buf) > | ||
2313 | ME6000_AO_FIFO_COUNT)) { | ||
2314 | PERROR | ||
2315 | ("Too much data for hardware wraparound mode! Exceeded size of %d.\n", | ||
2316 | ME6000_AO_FIFO_COUNT); | ||
2317 | err = ME_ERRNO_FIFO_BUFFER_OVERFLOW; | ||
2318 | } | ||
2319 | } | ||
2320 | |||
2321 | *count = *count - left_to_copy_from_user; | ||
2322 | ME_SUBDEVICE_EXIT; | ||
2323 | |||
2324 | return err; | ||
2325 | } | ||
2326 | |||
2327 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) | ||
2328 | static irqreturn_t me6000_ao_isr(int irq, void *dev_id) | ||
2329 | #else | ||
2330 | static irqreturn_t me6000_ao_isr(int irq, void *dev_id, struct pt_regs *regs) | ||
2331 | #endif | ||
2332 | { | ||
2333 | me6000_ao_subdevice_t *instance = dev_id; | ||
2334 | uint32_t irq_status; | ||
2335 | uint32_t ctrl; | ||
2336 | uint32_t status; | ||
2337 | int count = 0; | ||
2338 | |||
2339 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
2340 | |||
2341 | if (irq != instance->irq) { | ||
2342 | PERROR("Incorrect interrupt num: %d.\n", irq); | ||
2343 | return IRQ_NONE; | ||
2344 | } | ||
2345 | |||
2346 | irq_status = inl(instance->irq_status_reg); | ||
2347 | if (!(irq_status & (ME6000_IRQ_STATUS_BIT_AO_HF << instance->ao_idx))) { | ||
2348 | PINFO("%ld Shared interrupt. %s(): ID=%d: status_reg=0x%04X\n", | ||
2349 | jiffies, __FUNCTION__, instance->ao_idx, irq_status); | ||
2350 | return IRQ_NONE; | ||
2351 | } | ||
2352 | |||
2353 | if (!instance->circ_buf.buf) { | ||
2354 | instance->status = ao_status_stream_error; | ||
2355 | PERROR_CRITICAL("CIRCULAR BUFFER NOT EXISTS!\n"); | ||
2356 | //Block interrupts. Stop machine. | ||
2357 | ctrl = inl(instance->ctrl_reg); | ||
2358 | ctrl &= ~ME6000_AO_CTRL_BIT_ENABLE_IRQ; | ||
2359 | ctrl |= | ||
2360 | ME6000_AO_CTRL_BIT_IMMEDIATE_STOP | ME6000_AO_CTRL_BIT_STOP; | ||
2361 | outl(ctrl, instance->ctrl_reg); | ||
2362 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2363 | instance->reg_base, | ||
2364 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
2365 | |||
2366 | //Inform user | ||
2367 | wake_up_interruptible_all(&instance->wait_queue); | ||
2368 | return IRQ_HANDLED; | ||
2369 | } | ||
2370 | |||
2371 | status = inl(instance->status_reg); | ||
2372 | if (!(status & ME6000_AO_STATUS_BIT_FSM)) { //Too late. Not working! END? BROKEN PIPE? | ||
2373 | /// @note Error checking was moved to separate task. | ||
2374 | PDEBUG("Interrupt come but ISM is not working!\n"); | ||
2375 | //Block interrupts. Stop machine. | ||
2376 | ctrl = inl(instance->ctrl_reg); | ||
2377 | ctrl &= ~ME6000_AO_CTRL_BIT_ENABLE_IRQ; | ||
2378 | ctrl |= | ||
2379 | ME6000_AO_CTRL_BIT_STOP | ME6000_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
2380 | outl(ctrl, instance->ctrl_reg); | ||
2381 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2382 | instance->reg_base, | ||
2383 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
2384 | |||
2385 | //Reset interrupt latch | ||
2386 | inl(instance->irq_reset_reg); | ||
2387 | |||
2388 | /// @note User notification was also moved to separate task. | ||
2389 | return IRQ_HANDLED; | ||
2390 | } | ||
2391 | //General procedure. Process more datas. | ||
2392 | |||
2393 | #ifdef MEDEBUG_DEBUG | ||
2394 | if (!me_circ_buf_values(&instance->circ_buf)) { //Buffer is empty! | ||
2395 | PDEBUG("Circular buffer empty!\n"); | ||
2396 | } | ||
2397 | #endif | ||
2398 | |||
2399 | //Check FIFO | ||
2400 | if (status & ME6000_AO_STATUS_BIT_HF) { //OK less than half | ||
2401 | |||
2402 | //Block interrupts | ||
2403 | ctrl = inl(instance->ctrl_reg); | ||
2404 | ctrl &= ~ME6000_AO_CTRL_BIT_ENABLE_IRQ; | ||
2405 | outl(ctrl, instance->ctrl_reg); | ||
2406 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2407 | instance->reg_base, | ||
2408 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
2409 | |||
2410 | do { | ||
2411 | //Calculate how many should be copied. | ||
2412 | count = | ||
2413 | (instance->stop_data_count) ? instance-> | ||
2414 | stop_data_count - | ||
2415 | instance->data_count : ME6000_AO_FIFO_COUNT / 2; | ||
2416 | if (ME6000_AO_FIFO_COUNT / 2 < count) { | ||
2417 | count = ME6000_AO_FIFO_COUNT / 2; | ||
2418 | } | ||
2419 | //Copy data | ||
2420 | if (instance->mode == ME6000_AO_CONTINOUS) { //Continous | ||
2421 | count = ao_write_data(instance, count, 0); | ||
2422 | if (count > 0) { | ||
2423 | instance->circ_buf.tail += count; | ||
2424 | instance->circ_buf.tail &= | ||
2425 | instance->circ_buf.mask; | ||
2426 | instance->data_count += count; | ||
2427 | |||
2428 | if ((instance->status == ao_status_stream_end_wait) && !me_circ_buf_values(&instance->circ_buf)) { //Stoping. Whole buffer was copied. | ||
2429 | break; | ||
2430 | } | ||
2431 | } | ||
2432 | } else if ((instance->mode == ME6000_AO_SW_WRAP_MODE) && ((ctrl & ME6000_AO_CTRL_MODE_MASK) == ME6000_AO_MODE_CONTINUOUS)) { //Wraparound (software) | ||
2433 | if (instance->status == ao_status_stream_end_wait) { //We stoping => Copy to the end of the buffer. | ||
2434 | count = | ||
2435 | ao_write_data(instance, count, 0); | ||
2436 | } else { //Copy in wraparound mode. | ||
2437 | count = | ||
2438 | ao_write_data_wraparound(instance, | ||
2439 | count, | ||
2440 | instance-> | ||
2441 | preloaded_count); | ||
2442 | } | ||
2443 | |||
2444 | if (count > 0) { | ||
2445 | instance->data_count += count; | ||
2446 | instance->preloaded_count += count; | ||
2447 | instance->preloaded_count %= | ||
2448 | me_circ_buf_values(&instance-> | ||
2449 | circ_buf); | ||
2450 | |||
2451 | if ((instance->status == ao_status_stream_end_wait) && !instance->preloaded_count) { //Stoping. Whole buffer was copied. | ||
2452 | break; | ||
2453 | } | ||
2454 | } | ||
2455 | } | ||
2456 | |||
2457 | if ((count <= 0) || (instance->stop_data_count && (instance->stop_data_count <= instance->data_count))) { //End of work. | ||
2458 | break; | ||
2459 | } | ||
2460 | } //Repeat if still is under half fifo | ||
2461 | while ((status = | ||
2462 | inl(instance->status_reg)) & ME6000_AO_STATUS_BIT_HF); | ||
2463 | |||
2464 | //Unblock interrupts | ||
2465 | ctrl = inl(instance->ctrl_reg); | ||
2466 | if (count >= 0) { //Copy was successful. | ||
2467 | if (instance->stop_data_count && (instance->stop_data_count <= instance->data_count)) { //Finishing work. No more interrupts. | ||
2468 | PDEBUG("Finishing work. Interrupt disabled.\n"); | ||
2469 | instance->status = ao_status_stream_end_wait; | ||
2470 | } else if (count > 0) { //Normal work. Enable interrupt. | ||
2471 | PDEBUG("Normal work. Enable interrupt.\n"); | ||
2472 | ctrl |= ME6000_AO_CTRL_BIT_ENABLE_IRQ; | ||
2473 | } else { //Normal work but there are no more data in buffer. Interrupt blocked. stream_write() will unblock it. | ||
2474 | PDEBUG | ||
2475 | ("No data in software buffer. Interrupt blocked.\n"); | ||
2476 | } | ||
2477 | } else { //Error during copy. | ||
2478 | instance->status = ao_status_stream_fifo_error; | ||
2479 | } | ||
2480 | |||
2481 | outl(ctrl, instance->ctrl_reg); | ||
2482 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2483 | instance->reg_base, | ||
2484 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
2485 | } else { //?? more than half | ||
2486 | PDEBUG | ||
2487 | ("Interrupt come but FIFO more than half full! Reset interrupt.\n"); | ||
2488 | } | ||
2489 | |||
2490 | PINFO("ISR: Buffer count: %d.(T:%d H:%d)\n", | ||
2491 | me_circ_buf_values(&instance->circ_buf), instance->circ_buf.tail, | ||
2492 | instance->circ_buf.head); | ||
2493 | PINFO("ISR: Stop count: %d.\n", instance->stop_count); | ||
2494 | PINFO("ISR: Stop data count: %d.\n", instance->stop_data_count); | ||
2495 | PINFO("ISR: Data count: %d.\n", instance->data_count); | ||
2496 | |||
2497 | //Reset interrupt latch | ||
2498 | inl(instance->irq_reset_reg); | ||
2499 | |||
2500 | //Inform user | ||
2501 | wake_up_interruptible_all(&instance->wait_queue); | ||
2502 | |||
2503 | return IRQ_HANDLED; | ||
2504 | } | ||
2505 | |||
2506 | static void me6000_ao_destructor(struct me_subdevice *subdevice) | ||
2507 | { | ||
2508 | me6000_ao_subdevice_t *instance; | ||
2509 | |||
2510 | instance = (me6000_ao_subdevice_t *) subdevice; | ||
2511 | |||
2512 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
2513 | |||
2514 | instance->ao_control_task_flag = 0; | ||
2515 | |||
2516 | // Reset subdevice to asure clean exit. | ||
2517 | me6000_ao_io_reset_subdevice(subdevice, NULL, | ||
2518 | ME_IO_RESET_SUBDEVICE_NO_FLAGS); | ||
2519 | |||
2520 | // Remove any tasks from work queue. This is paranoic because it was done allready in reset(). | ||
2521 | if (!cancel_delayed_work(&instance->ao_control_task)) { //Wait 2 ticks to be sure that control task is removed from queue. | ||
2522 | set_current_state(TASK_INTERRUPTIBLE); | ||
2523 | schedule_timeout(2); | ||
2524 | } | ||
2525 | |||
2526 | if (instance->fifo & ME6000_AO_HAS_FIFO) { | ||
2527 | if (instance->irq) { | ||
2528 | free_irq(instance->irq, instance); | ||
2529 | instance->irq = 0; | ||
2530 | } | ||
2531 | |||
2532 | if (instance->circ_buf.buf) { | ||
2533 | PDEBUG("free circ_buf = %p size=%d", | ||
2534 | instance->circ_buf.buf, | ||
2535 | PAGE_SHIFT << ME6000_AO_CIRC_BUF_SIZE_ORDER); | ||
2536 | free_pages((unsigned long)instance->circ_buf.buf, | ||
2537 | ME6000_AO_CIRC_BUF_SIZE_ORDER); | ||
2538 | } | ||
2539 | instance->circ_buf.buf = NULL; | ||
2540 | } | ||
2541 | |||
2542 | me_subdevice_deinit(&instance->base); | ||
2543 | kfree(instance); | ||
2544 | } | ||
2545 | |||
2546 | me6000_ao_subdevice_t *me6000_ao_constructor(uint32_t reg_base, | ||
2547 | spinlock_t * preload_reg_lock, | ||
2548 | uint32_t * preload_flags, | ||
2549 | uint32_t * triggering_flags, | ||
2550 | int ao_idx, | ||
2551 | int fifo, | ||
2552 | int irq, | ||
2553 | int high_range, | ||
2554 | struct workqueue_struct *me6000_wq) | ||
2555 | { | ||
2556 | me6000_ao_subdevice_t *subdevice; | ||
2557 | int err; | ||
2558 | |||
2559 | PDEBUG("executed ID=%d.\n", ao_idx); | ||
2560 | |||
2561 | /* Allocate memory for subdevice instance */ | ||
2562 | subdevice = kmalloc(sizeof(me6000_ao_subdevice_t), GFP_KERNEL); | ||
2563 | |||
2564 | if (!subdevice) { | ||
2565 | PERROR("Cannot get memory for subdevice instance.\n"); | ||
2566 | return NULL; | ||
2567 | } | ||
2568 | |||
2569 | memset(subdevice, 0, sizeof(me6000_ao_subdevice_t)); | ||
2570 | |||
2571 | /* Initialize subdevice base class */ | ||
2572 | err = me_subdevice_init(&subdevice->base); | ||
2573 | |||
2574 | if (err) { | ||
2575 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
2576 | kfree(subdevice); | ||
2577 | return NULL; | ||
2578 | } | ||
2579 | // Initialize spin locks. | ||
2580 | spin_lock_init(&subdevice->subdevice_lock); | ||
2581 | |||
2582 | subdevice->preload_reg_lock = preload_reg_lock; | ||
2583 | subdevice->preload_flags = preload_flags; | ||
2584 | subdevice->triggering_flags = triggering_flags; | ||
2585 | |||
2586 | /* Store analog output index */ | ||
2587 | subdevice->ao_idx = ao_idx; | ||
2588 | |||
2589 | /* Store if analog output has fifo */ | ||
2590 | subdevice->fifo = fifo; | ||
2591 | |||
2592 | if (subdevice->fifo & ME6000_AO_HAS_FIFO) { | ||
2593 | /* Allocate and initialize circular buffer */ | ||
2594 | subdevice->circ_buf.mask = ME6000_AO_CIRC_BUF_COUNT - 1; | ||
2595 | subdevice->circ_buf.buf = | ||
2596 | (void *)__get_free_pages(GFP_KERNEL, | ||
2597 | ME6000_AO_CIRC_BUF_SIZE_ORDER); | ||
2598 | PDEBUG("circ_buf = %p size=%ld\n", subdevice->circ_buf.buf, | ||
2599 | ME6000_AO_CIRC_BUF_SIZE); | ||
2600 | |||
2601 | if (!subdevice->circ_buf.buf) { | ||
2602 | PERROR | ||
2603 | ("Cannot initialize subdevice base class instance.\n"); | ||
2604 | kfree(subdevice); | ||
2605 | return NULL; | ||
2606 | } | ||
2607 | |||
2608 | memset(subdevice->circ_buf.buf, 0, ME6000_AO_CIRC_BUF_SIZE); | ||
2609 | } else { | ||
2610 | subdevice->circ_buf.mask = 0; | ||
2611 | subdevice->circ_buf.buf = NULL; | ||
2612 | } | ||
2613 | subdevice->circ_buf.head = 0; | ||
2614 | subdevice->circ_buf.tail = 0; | ||
2615 | |||
2616 | subdevice->status = ao_status_none; | ||
2617 | subdevice->ao_control_task_flag = 0; | ||
2618 | subdevice->timeout.delay = 0; | ||
2619 | subdevice->timeout.start_time = jiffies; | ||
2620 | |||
2621 | /* Initialize wait queue */ | ||
2622 | init_waitqueue_head(&subdevice->wait_queue); | ||
2623 | |||
2624 | /* Initialize single value to 0V */ | ||
2625 | subdevice->single_value = 0x8000; | ||
2626 | subdevice->single_value_in_fifo = 0x8000; | ||
2627 | |||
2628 | /* Initialize range boarders */ | ||
2629 | if (high_range) { | ||
2630 | subdevice->min = ME6000_AO_MIN_RANGE_HIGH; | ||
2631 | subdevice->max = ME6000_AO_MAX_RANGE_HIGH; | ||
2632 | } else { | ||
2633 | subdevice->min = ME6000_AO_MIN_RANGE; | ||
2634 | subdevice->max = ME6000_AO_MAX_RANGE; | ||
2635 | } | ||
2636 | |||
2637 | /* Register interrupt service routine */ | ||
2638 | |||
2639 | if (subdevice->fifo & ME6000_AO_HAS_FIFO) { | ||
2640 | subdevice->irq = irq; | ||
2641 | if (request_irq(subdevice->irq, me6000_ao_isr, | ||
2642 | #ifdef IRQF_DISABLED | ||
2643 | IRQF_DISABLED | IRQF_SHARED, | ||
2644 | #else | ||
2645 | SA_INTERRUPT | SA_SHIRQ, | ||
2646 | #endif | ||
2647 | ME6000_NAME, subdevice)) { | ||
2648 | PERROR("Cannot get interrupt line.\n"); | ||
2649 | PDEBUG("free circ_buf = %p size=%d", | ||
2650 | subdevice->circ_buf.buf, | ||
2651 | PAGE_SHIFT << ME6000_AO_CIRC_BUF_SIZE_ORDER); | ||
2652 | free_pages((unsigned long)subdevice->circ_buf.buf, | ||
2653 | ME6000_AO_CIRC_BUF_SIZE_ORDER); | ||
2654 | subdevice->circ_buf.buf = NULL; | ||
2655 | kfree(subdevice); | ||
2656 | return NULL; | ||
2657 | } | ||
2658 | PINFO("Registered irq=%d.\n", subdevice->irq); | ||
2659 | } else { | ||
2660 | subdevice->irq = 0; | ||
2661 | } | ||
2662 | |||
2663 | /* Initialize registers */ | ||
2664 | // Only streamed subdevices support interrupts. For the rest this register has no meaning. | ||
2665 | subdevice->irq_status_reg = reg_base + ME6000_AO_IRQ_STATUS_REG; | ||
2666 | subdevice->preload_reg = reg_base + ME6000_AO_PRELOAD_REG; | ||
2667 | |||
2668 | if (ao_idx == 0) { | ||
2669 | subdevice->ctrl_reg = reg_base + ME6000_AO_00_CTRL_REG; | ||
2670 | subdevice->status_reg = reg_base + ME6000_AO_00_STATUS_REG; | ||
2671 | subdevice->fifo_reg = reg_base + ME6000_AO_00_FIFO_REG; | ||
2672 | subdevice->timer_reg = reg_base + ME6000_AO_00_TIMER_REG; | ||
2673 | subdevice->irq_reset_reg = | ||
2674 | reg_base + ME6000_AO_00_IRQ_RESET_REG; | ||
2675 | subdevice->single_reg = reg_base + ME6000_AO_00_SINGLE_REG; | ||
2676 | } else if (ao_idx == 1) { | ||
2677 | subdevice->ctrl_reg = reg_base + ME6000_AO_01_CTRL_REG; | ||
2678 | subdevice->status_reg = reg_base + ME6000_AO_01_STATUS_REG; | ||
2679 | subdevice->fifo_reg = reg_base + ME6000_AO_01_FIFO_REG; | ||
2680 | subdevice->timer_reg = reg_base + ME6000_AO_01_TIMER_REG; | ||
2681 | subdevice->irq_reset_reg = | ||
2682 | reg_base + ME6000_AO_01_IRQ_RESET_REG; | ||
2683 | subdevice->single_reg = reg_base + ME6000_AO_01_SINGLE_REG; | ||
2684 | } else if (ao_idx == 2) { | ||
2685 | subdevice->ctrl_reg = reg_base + ME6000_AO_02_CTRL_REG; | ||
2686 | subdevice->status_reg = reg_base + ME6000_AO_02_STATUS_REG; | ||
2687 | subdevice->fifo_reg = reg_base + ME6000_AO_02_FIFO_REG; | ||
2688 | subdevice->timer_reg = reg_base + ME6000_AO_02_TIMER_REG; | ||
2689 | subdevice->irq_reset_reg = | ||
2690 | reg_base + ME6000_AO_02_IRQ_RESET_REG; | ||
2691 | subdevice->single_reg = reg_base + ME6000_AO_02_SINGLE_REG; | ||
2692 | } else if (ao_idx == 3) { | ||
2693 | subdevice->ctrl_reg = reg_base + ME6000_AO_03_CTRL_REG; | ||
2694 | subdevice->status_reg = reg_base + ME6000_AO_03_STATUS_REG; | ||
2695 | subdevice->fifo_reg = reg_base + ME6000_AO_03_FIFO_REG; | ||
2696 | subdevice->timer_reg = reg_base + ME6000_AO_03_TIMER_REG; | ||
2697 | subdevice->irq_reset_reg = | ||
2698 | reg_base + ME6000_AO_03_IRQ_RESET_REG; | ||
2699 | subdevice->single_reg = reg_base + ME6000_AO_03_SINGLE_REG; | ||
2700 | } else { | ||
2701 | subdevice->ctrl_reg = reg_base + ME6000_AO_DUMY; | ||
2702 | subdevice->fifo_reg = reg_base + ME6000_AO_DUMY; | ||
2703 | subdevice->timer_reg = reg_base + ME6000_AO_DUMY; | ||
2704 | subdevice->irq_reset_reg = reg_base + ME6000_AO_DUMY; | ||
2705 | subdevice->single_reg = reg_base + ME6000_AO_DUMY; | ||
2706 | |||
2707 | subdevice->status_reg = reg_base + ME6000_AO_SINGLE_STATUS_REG; | ||
2708 | if (ao_idx == 4) { | ||
2709 | subdevice->single_reg = | ||
2710 | reg_base + ME6000_AO_04_SINGLE_REG; | ||
2711 | } else if (ao_idx == 5) { | ||
2712 | subdevice->single_reg = | ||
2713 | reg_base + ME6000_AO_05_SINGLE_REG; | ||
2714 | } else if (ao_idx == 6) { | ||
2715 | subdevice->single_reg = | ||
2716 | reg_base + ME6000_AO_06_SINGLE_REG; | ||
2717 | } else if (ao_idx == 7) { | ||
2718 | subdevice->single_reg = | ||
2719 | reg_base + ME6000_AO_07_SINGLE_REG; | ||
2720 | } else if (ao_idx == 8) { | ||
2721 | subdevice->single_reg = | ||
2722 | reg_base + ME6000_AO_08_SINGLE_REG; | ||
2723 | } else if (ao_idx == 9) { | ||
2724 | subdevice->single_reg = | ||
2725 | reg_base + ME6000_AO_09_SINGLE_REG; | ||
2726 | } else if (ao_idx == 10) { | ||
2727 | subdevice->single_reg = | ||
2728 | reg_base + ME6000_AO_10_SINGLE_REG; | ||
2729 | } else if (ao_idx == 11) { | ||
2730 | subdevice->single_reg = | ||
2731 | reg_base + ME6000_AO_11_SINGLE_REG; | ||
2732 | } else if (ao_idx == 12) { | ||
2733 | subdevice->single_reg = | ||
2734 | reg_base + ME6000_AO_12_SINGLE_REG; | ||
2735 | } else if (ao_idx == 13) { | ||
2736 | subdevice->single_reg = | ||
2737 | reg_base + ME6000_AO_13_SINGLE_REG; | ||
2738 | } else if (ao_idx == 14) { | ||
2739 | subdevice->single_reg = | ||
2740 | reg_base + ME6000_AO_14_SINGLE_REG; | ||
2741 | } else if (ao_idx == 15) { | ||
2742 | subdevice->single_reg = | ||
2743 | reg_base + ME6000_AO_15_SINGLE_REG; | ||
2744 | } else { | ||
2745 | PERROR_CRITICAL("WRONG SUBDEVICE ID=%d!", ao_idx); | ||
2746 | me_subdevice_deinit((me_subdevice_t *) subdevice); | ||
2747 | if (subdevice->fifo) { | ||
2748 | free_pages((unsigned long)subdevice->circ_buf. | ||
2749 | buf, ME6000_AO_CIRC_BUF_SIZE_ORDER); | ||
2750 | } | ||
2751 | subdevice->circ_buf.buf = NULL; | ||
2752 | kfree(subdevice); | ||
2753 | return NULL; | ||
2754 | } | ||
2755 | } | ||
2756 | #ifdef MEDEBUG_DEBUG_REG | ||
2757 | subdevice->reg_base = reg_base; | ||
2758 | #endif | ||
2759 | |||
2760 | /* Override base class methods. */ | ||
2761 | subdevice->base.me_subdevice_destructor = me6000_ao_destructor; | ||
2762 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
2763 | me6000_ao_io_reset_subdevice; | ||
2764 | subdevice->base.me_subdevice_io_single_config = | ||
2765 | me6000_ao_io_single_config; | ||
2766 | subdevice->base.me_subdevice_io_single_read = me6000_ao_io_single_read; | ||
2767 | subdevice->base.me_subdevice_io_single_write = | ||
2768 | me6000_ao_io_single_write; | ||
2769 | subdevice->base.me_subdevice_io_stream_config = | ||
2770 | me6000_ao_io_stream_config; | ||
2771 | subdevice->base.me_subdevice_io_stream_new_values = | ||
2772 | me6000_ao_io_stream_new_values; | ||
2773 | subdevice->base.me_subdevice_io_stream_write = | ||
2774 | me6000_ao_io_stream_write; | ||
2775 | subdevice->base.me_subdevice_io_stream_start = | ||
2776 | me6000_ao_io_stream_start; | ||
2777 | subdevice->base.me_subdevice_io_stream_status = | ||
2778 | me6000_ao_io_stream_status; | ||
2779 | subdevice->base.me_subdevice_io_stream_stop = me6000_ao_io_stream_stop; | ||
2780 | subdevice->base.me_subdevice_query_number_channels = | ||
2781 | me6000_ao_query_number_channels; | ||
2782 | subdevice->base.me_subdevice_query_subdevice_type = | ||
2783 | me6000_ao_query_subdevice_type; | ||
2784 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
2785 | me6000_ao_query_subdevice_caps; | ||
2786 | subdevice->base.me_subdevice_query_subdevice_caps_args = | ||
2787 | me6000_ao_query_subdevice_caps_args; | ||
2788 | subdevice->base.me_subdevice_query_range_by_min_max = | ||
2789 | me6000_ao_query_range_by_min_max; | ||
2790 | subdevice->base.me_subdevice_query_number_ranges = | ||
2791 | me6000_ao_query_number_ranges; | ||
2792 | subdevice->base.me_subdevice_query_range_info = | ||
2793 | me6000_ao_query_range_info; | ||
2794 | subdevice->base.me_subdevice_query_timer = me6000_ao_query_timer; | ||
2795 | |||
2796 | //prepare work queue and work function | ||
2797 | subdevice->me6000_workqueue = me6000_wq; | ||
2798 | |||
2799 | /* workqueue API changed in kernel 2.6.20 */ | ||
2800 | #if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ) | ||
2801 | INIT_WORK(&subdevice->ao_control_task, me6000_ao_work_control_task, | ||
2802 | (void *)subdevice); | ||
2803 | #else | ||
2804 | INIT_DELAYED_WORK(&subdevice->ao_control_task, | ||
2805 | me6000_ao_work_control_task); | ||
2806 | #endif | ||
2807 | |||
2808 | if (subdevice->fifo) { //Set speed | ||
2809 | outl(ME6000_AO_MIN_CHAN_TICKS - 1, subdevice->timer_reg); | ||
2810 | subdevice->hardware_stop_delay = HZ / 10; //100ms | ||
2811 | } | ||
2812 | |||
2813 | return subdevice; | ||
2814 | } | ||
2815 | |||
2816 | /** @brief Stop presentation. Preserve FIFOs. | ||
2817 | * | ||
2818 | * @param instance The subdevice instance (pointer). | ||
2819 | */ | ||
2820 | int inline ao_stop_immediately(me6000_ao_subdevice_t * instance) | ||
2821 | { | ||
2822 | unsigned long cpu_flags; | ||
2823 | uint32_t ctrl; | ||
2824 | int timeout; | ||
2825 | int i; | ||
2826 | uint32_t single_mask; | ||
2827 | |||
2828 | single_mask = | ||
2829 | (instance->ao_idx - ME6000_AO_SINGLE_STATUS_OFFSET < | ||
2830 | 0) ? 0x0000 : (0x0001 << (instance->ao_idx - | ||
2831 | ME6000_AO_SINGLE_STATUS_OFFSET)); | ||
2832 | |||
2833 | timeout = | ||
2834 | (instance->hardware_stop_delay > | ||
2835 | (HZ / 10)) ? instance->hardware_stop_delay : HZ / 10; | ||
2836 | for (i = 0; i <= timeout; i++) { | ||
2837 | if (instance->fifo) { | ||
2838 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
2839 | // Stop all actions. No conditions! Block interrupts. Leave FIFO untouched! | ||
2840 | ctrl = inl(instance->ctrl_reg); | ||
2841 | ctrl |= | ||
2842 | ME6000_AO_CTRL_BIT_STOP | | ||
2843 | ME6000_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
2844 | ctrl &= | ||
2845 | ~(ME6000_AO_CTRL_BIT_ENABLE_IRQ | | ||
2846 | ME6000_AO_CTRL_BIT_ENABLE_EX_TRIG); | ||
2847 | outl(ctrl, instance->ctrl_reg); | ||
2848 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
2849 | instance->reg_base, | ||
2850 | instance->ctrl_reg - instance->reg_base, | ||
2851 | ctrl); | ||
2852 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
2853 | cpu_flags); | ||
2854 | |||
2855 | if (!(inl(instance->status_reg) & ME6000_AO_STATUS_BIT_FSM)) { // Exit. | ||
2856 | break; | ||
2857 | } | ||
2858 | } else { | ||
2859 | if (!(inl(instance->status_reg) & single_mask)) { // Exit. | ||
2860 | break; | ||
2861 | } | ||
2862 | } | ||
2863 | |||
2864 | PINFO("<%s> Wait for stop: %d\n", __FUNCTION__, i); | ||
2865 | |||
2866 | //Still working! | ||
2867 | set_current_state(TASK_INTERRUPTIBLE); | ||
2868 | schedule_timeout(1); | ||
2869 | } | ||
2870 | |||
2871 | if (i > timeout) { | ||
2872 | PERROR_CRITICAL("FSM IS BUSY!\n"); | ||
2873 | return ME_ERRNO_INTERNAL; | ||
2874 | } | ||
2875 | return ME_ERRNO_SUCCESS; | ||
2876 | } | ||
2877 | |||
2878 | /** @brief Copy data from circular buffer to fifo (fast) in wraparound. | ||
2879 | * @note This is time critical function. Checking is done at begining and end only. | ||
2880 | * @note The is not reasonable way to check how many walues was in FIFO at begining. The count must be managed externaly. | ||
2881 | * | ||
2882 | * @param instance The subdevice instance (pointer). | ||
2883 | * @param count Maximum number of copied data. | ||
2884 | * @param start_pos Position of the firs value in buffer. | ||
2885 | * | ||
2886 | * @return On success: Number of copied data. | ||
2887 | * @return On error/success: 0. No datas were copied => no data in buffer. | ||
2888 | * @return On error: -ME_ERRNO_FIFO_BUFFER_OVERFLOW. | ||
2889 | */ | ||
2890 | int inline ao_write_data_wraparound(me6000_ao_subdevice_t * instance, int count, | ||
2891 | int start_pos) | ||
2892 | { /// @note This is time critical function! | ||
2893 | uint32_t status; | ||
2894 | uint32_t value; | ||
2895 | int pos = | ||
2896 | (instance->circ_buf.tail + start_pos) & instance->circ_buf.mask; | ||
2897 | int local_count = count; | ||
2898 | int i = 1; | ||
2899 | |||
2900 | if (count <= 0) { //Wrong count! | ||
2901 | return 0; | ||
2902 | } | ||
2903 | |||
2904 | while (i < local_count) { | ||
2905 | //Get value from buffer | ||
2906 | value = *(instance->circ_buf.buf + pos); | ||
2907 | //Prepare it | ||
2908 | if (instance->ao_idx & 0x1) { | ||
2909 | value <<= 16; | ||
2910 | } | ||
2911 | //Put value to FIFO | ||
2912 | outl(value, instance->fifo_reg); | ||
2913 | //PDEBUG_REG("idx=%d fifo_reg outl(0x%lX+0x%lX)=0x%x\n", instance->ao_idx, instance->reg_base, instance->fifo_reg - instance->reg_base, value); | ||
2914 | |||
2915 | pos++; | ||
2916 | pos &= instance->circ_buf.mask; | ||
2917 | if (pos == instance->circ_buf.head) { | ||
2918 | pos = instance->circ_buf.tail; | ||
2919 | } | ||
2920 | i++; | ||
2921 | } | ||
2922 | |||
2923 | status = inl(instance->status_reg); | ||
2924 | if (!(status & ME6000_AO_STATUS_BIT_FF)) { //FIFO is full before all datas were copied! | ||
2925 | PERROR("idx=%d FIFO is full before all datas were copied!\n", | ||
2926 | instance->ao_idx); | ||
2927 | return -ME_ERRNO_FIFO_BUFFER_OVERFLOW; | ||
2928 | } else { //Add last value | ||
2929 | value = *(instance->circ_buf.buf + pos); | ||
2930 | if (instance->ao_idx & 0x1) { | ||
2931 | value <<= 16; | ||
2932 | } | ||
2933 | //Put value to FIFO | ||
2934 | outl(value, instance->fifo_reg); | ||
2935 | //PDEBUG_REG("idx=%d fifo_reg outl(0x%lX+0x%lX)=0x%x\n", instance->ao_idx, instance->reg_base, instance->fifo_reg - instance->reg_base, value); | ||
2936 | } | ||
2937 | |||
2938 | PINFO("idx=%d WRAPAROUND LOADED %d values\n", instance->ao_idx, | ||
2939 | local_count); | ||
2940 | return local_count; | ||
2941 | } | ||
2942 | |||
2943 | /** @brief Copy data from software buffer to fifo (fast). | ||
2944 | * @note This is time critical function. Checking is done at begining and end only. | ||
2945 | * @note The is not reasonable way to check how many walues was in FIFO at begining. The count must be managed externaly. | ||
2946 | * | ||
2947 | * @param instance The subdevice instance (pointer). | ||
2948 | * @param count Maximum number of copied data. | ||
2949 | * @param start_pos Position of the firs value in buffer. | ||
2950 | * | ||
2951 | * @return On success: Number of copied data. | ||
2952 | * @return On error/success: 0. No datas were copied => no data in buffer. | ||
2953 | * @return On error: -ME_ERRNO_FIFO_BUFFER_OVERFLOW. | ||
2954 | */ | ||
2955 | int inline ao_write_data(me6000_ao_subdevice_t * instance, int count, | ||
2956 | int start_pos) | ||
2957 | { /// @note This is time critical function! | ||
2958 | uint32_t status; | ||
2959 | uint32_t value; | ||
2960 | int pos = | ||
2961 | (instance->circ_buf.tail + start_pos) & instance->circ_buf.mask; | ||
2962 | int local_count = count; | ||
2963 | int max_count; | ||
2964 | int i = 1; | ||
2965 | |||
2966 | if (count <= 0) { //Wrong count! | ||
2967 | return 0; | ||
2968 | } | ||
2969 | |||
2970 | max_count = me_circ_buf_values(&instance->circ_buf) - start_pos; | ||
2971 | if (max_count <= 0) { //No data to copy! | ||
2972 | return 0; | ||
2973 | } | ||
2974 | |||
2975 | if (max_count < count) { | ||
2976 | local_count = max_count; | ||
2977 | } | ||
2978 | |||
2979 | while (i < local_count) { | ||
2980 | //Get value from buffer | ||
2981 | value = *(instance->circ_buf.buf + pos); | ||
2982 | //Prepare it | ||
2983 | if (instance->ao_idx & 0x1) { | ||
2984 | value <<= 16; | ||
2985 | } | ||
2986 | //Put value to FIFO | ||
2987 | outl(value, instance->fifo_reg); | ||
2988 | //PDEBUG_REG("idx=%d fifo_reg outl(0x%lX+0x%lX)=0x%x\n", instance->ao_idx, instance->reg_base, instance->fifo_reg - instance->reg_base, value); | ||
2989 | |||
2990 | pos++; | ||
2991 | pos &= instance->circ_buf.mask; | ||
2992 | i++; | ||
2993 | } | ||
2994 | |||
2995 | status = inl(instance->status_reg); | ||
2996 | if (!(status & ME6000_AO_STATUS_BIT_FF)) { //FIFO is full before all datas were copied! | ||
2997 | PERROR("idx=%d FIFO is full before all datas were copied!\n", | ||
2998 | instance->ao_idx); | ||
2999 | return -ME_ERRNO_FIFO_BUFFER_OVERFLOW; | ||
3000 | } else { //Add last value | ||
3001 | value = *(instance->circ_buf.buf + pos); | ||
3002 | if (instance->ao_idx & 0x1) { | ||
3003 | value <<= 16; | ||
3004 | } | ||
3005 | //Put value to FIFO | ||
3006 | outl(value, instance->fifo_reg); | ||
3007 | //PDEBUG_REG("idx=%d fifo_reg outl(0x%lX+0x%lX)=0x%x\n", instance->ao_idx, instance->reg_base, instance->fifo_reg - instance->reg_base, value); | ||
3008 | } | ||
3009 | |||
3010 | PINFO("idx=%d FAST LOADED %d values\n", instance->ao_idx, local_count); | ||
3011 | return local_count; | ||
3012 | } | ||
3013 | |||
3014 | /** @brief Copy data from software buffer to fifo (slow). | ||
3015 | * @note This is slow function that copy all data from buffer to FIFO with full control. | ||
3016 | * | ||
3017 | * @param instance The subdevice instance (pointer). | ||
3018 | * @param count Maximum number of copied data. | ||
3019 | * @param start_pos Position of the firs value in buffer. | ||
3020 | * | ||
3021 | * @return On success: Number of copied values. | ||
3022 | * @return On error/success: 0. FIFO was full at begining. | ||
3023 | * @return On error: -ME_ERRNO_RING_BUFFER_UNDEFFLOW. | ||
3024 | */ | ||
3025 | int inline ao_write_data_pooling(me6000_ao_subdevice_t * instance, int count, | ||
3026 | int start_pos) | ||
3027 | { /// @note This is slow function! | ||
3028 | uint32_t status; | ||
3029 | uint32_t value; | ||
3030 | int pos = | ||
3031 | (instance->circ_buf.tail + start_pos) & instance->circ_buf.mask; | ||
3032 | int local_count = count; | ||
3033 | int i; | ||
3034 | int max_count; | ||
3035 | |||
3036 | if (count <= 0) { //Wrong count! | ||
3037 | PERROR("idx=%d SLOW LOADED: Wrong count!\n", instance->ao_idx); | ||
3038 | return 0; | ||
3039 | } | ||
3040 | |||
3041 | max_count = me_circ_buf_values(&instance->circ_buf) - start_pos; | ||
3042 | if (max_count <= 0) { //No data to copy! | ||
3043 | PERROR("idx=%d SLOW LOADED: No data to copy!\n", | ||
3044 | instance->ao_idx); | ||
3045 | return 0; | ||
3046 | } | ||
3047 | |||
3048 | if (max_count < count) { | ||
3049 | local_count = max_count; | ||
3050 | } | ||
3051 | |||
3052 | for (i = 0; i < local_count; i++) { | ||
3053 | status = inl(instance->status_reg); | ||
3054 | if (!(status & ME6000_AO_STATUS_BIT_FF)) { //FIFO is full! | ||
3055 | return i; | ||
3056 | } | ||
3057 | //Get value from buffer | ||
3058 | value = *(instance->circ_buf.buf + pos); | ||
3059 | //Prepare it | ||
3060 | if (instance->ao_idx & 0x1) { | ||
3061 | value <<= 16; | ||
3062 | } | ||
3063 | //Put value to FIFO | ||
3064 | outl(value, instance->fifo_reg); | ||
3065 | //PDEBUG_REG("idx=%d fifo_reg outl(0x%lX+0x%lX)=0x%x\n", instance->ao_idx, instance->reg_base, instance->fifo_reg - instance->reg_base, value); | ||
3066 | |||
3067 | pos++; | ||
3068 | pos &= instance->circ_buf.mask; | ||
3069 | } | ||
3070 | |||
3071 | PINFO("idx=%d SLOW LOADED %d values\n", instance->ao_idx, local_count); | ||
3072 | return local_count; | ||
3073 | } | ||
3074 | |||
3075 | /** @brief Copy data from user space to circular buffer. | ||
3076 | * @param instance The subdevice instance (pointer). | ||
3077 | * @param count Number of datas in user space. | ||
3078 | * @param user_values Buffer's pointer. | ||
3079 | * | ||
3080 | * @return On success: Number of copied values. | ||
3081 | * @return On error: -ME_ERRNO_INTERNAL. | ||
3082 | */ | ||
3083 | int inline ao_get_data_from_user(me6000_ao_subdevice_t * instance, int count, | ||
3084 | int *user_values) | ||
3085 | { | ||
3086 | int i, err; | ||
3087 | int empty_space; | ||
3088 | int copied; | ||
3089 | int value; | ||
3090 | |||
3091 | empty_space = me_circ_buf_space(&instance->circ_buf); | ||
3092 | //We have only this space free. | ||
3093 | copied = (count < empty_space) ? count : empty_space; | ||
3094 | for (i = 0; i < copied; i++) { //Copy from user to buffer | ||
3095 | if ((err = get_user(value, (int *)(user_values + i)))) { | ||
3096 | PERROR | ||
3097 | ("idx=%d BUFFER LOADED: get_user(0x%p) return an error: %d\n", | ||
3098 | instance->ao_idx, user_values + i, err); | ||
3099 | return -ME_ERRNO_INTERNAL; | ||
3100 | } | ||
3101 | /// @note The analog output in me6000 series has size of 16 bits. | ||
3102 | *(instance->circ_buf.buf + instance->circ_buf.head) = | ||
3103 | (uint16_t) value; | ||
3104 | instance->circ_buf.head++; | ||
3105 | instance->circ_buf.head &= instance->circ_buf.mask; | ||
3106 | } | ||
3107 | |||
3108 | PINFO("idx=%d BUFFER LOADED %d values\n", instance->ao_idx, copied); | ||
3109 | return copied; | ||
3110 | } | ||
3111 | |||
3112 | static void me6000_ao_work_control_task( | ||
3113 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) | ||
3114 | void *subdevice | ||
3115 | #else | ||
3116 | struct work_struct *work | ||
3117 | #endif | ||
3118 | ) | ||
3119 | { | ||
3120 | me6000_ao_subdevice_t *instance; | ||
3121 | unsigned long cpu_flags = 0; | ||
3122 | uint32_t status; | ||
3123 | uint32_t ctrl; | ||
3124 | uint32_t synch; | ||
3125 | int reschedule = 0; | ||
3126 | int signaling = 0; | ||
3127 | uint32_t single_mask; | ||
3128 | |||
3129 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) | ||
3130 | instance = (me6000_ao_subdevice_t *) subdevice; | ||
3131 | #else | ||
3132 | instance = | ||
3133 | container_of((void *)work, me6000_ao_subdevice_t, ao_control_task); | ||
3134 | #endif | ||
3135 | PINFO("<%s: %ld> executed. idx=%d\n", __FUNCTION__, jiffies, | ||
3136 | instance->ao_idx); | ||
3137 | |||
3138 | status = inl(instance->status_reg); | ||
3139 | PDEBUG_REG("status_reg inl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
3140 | instance->status_reg - instance->reg_base, status); | ||
3141 | |||
3142 | /// @note AO_STATUS_BIT_FSM doesn't work as should be for pure single channels (idx>=4) | ||
3143 | // single_mask = (instance->ao_idx-ME6000_AO_SINGLE_STATUS_OFFSET < 0) ? 0x0000 : (0x0001 << (instance->ao_idx-ME6000_AO_SINGLE_STATUS_OFFSET)); | ||
3144 | single_mask = *instance->triggering_flags & (0x1 << instance->ao_idx); | ||
3145 | |||
3146 | switch (instance->status) { // Checking actual mode. | ||
3147 | |||
3148 | // Not configured for work. | ||
3149 | case ao_status_none: | ||
3150 | break; | ||
3151 | |||
3152 | //This are stable modes. No need to do anything. (?) | ||
3153 | case ao_status_single_configured: | ||
3154 | case ao_status_stream_configured: | ||
3155 | case ao_status_stream_fifo_error: | ||
3156 | case ao_status_stream_buffer_error: | ||
3157 | case ao_status_stream_error: | ||
3158 | PERROR("Shouldn't be running!.\n"); | ||
3159 | break; | ||
3160 | |||
3161 | // Single modes | ||
3162 | case ao_status_single_run_wait: | ||
3163 | case ao_status_single_run: | ||
3164 | case ao_status_single_end_wait: | ||
3165 | if (instance->fifo) { // Extra registers. | ||
3166 | if (!(status & ME6000_AO_STATUS_BIT_FSM)) { // State machine is not working. | ||
3167 | if (((instance->fifo & ME6000_AO_HAS_FIFO) | ||
3168 | && (!(status & ME6000_AO_STATUS_BIT_EF))) | ||
3169 | || (!(instance->fifo & ME6000_AO_HAS_FIFO))) { // Single is in end state. | ||
3170 | PDEBUG | ||
3171 | ("Single call has been complited.\n"); | ||
3172 | |||
3173 | // Set correct value for single_read(); | ||
3174 | instance->single_value = | ||
3175 | instance->single_value_in_fifo; | ||
3176 | |||
3177 | // Set status as 'ao_status_single_end' | ||
3178 | instance->status = ao_status_single_end; | ||
3179 | |||
3180 | spin_lock(instance->preload_reg_lock); | ||
3181 | if ((single_mask) && (*instance->preload_flags & (ME6000_AO_SYNC_HOLD << instance->ao_idx))) { // This is one of synchronous start channels. Set all as triggered. | ||
3182 | *instance->triggering_flags = | ||
3183 | 0x00000000; | ||
3184 | } else { | ||
3185 | //Set this channel as triggered (none active). | ||
3186 | *instance->triggering_flags &= | ||
3187 | ~(0x1 << instance->ao_idx); | ||
3188 | } | ||
3189 | spin_unlock(instance->preload_reg_lock); | ||
3190 | |||
3191 | // Signal the end. | ||
3192 | signaling = 1; | ||
3193 | // Wait for stop ISM. | ||
3194 | reschedule = 1; | ||
3195 | |||
3196 | break; | ||
3197 | } | ||
3198 | } | ||
3199 | // Check timeout. | ||
3200 | if ((instance->timeout.delay) && ((jiffies - instance->timeout.start_time) >= instance->timeout.delay)) { // Timeout | ||
3201 | PDEBUG("Timeout reached.\n"); | ||
3202 | // Stop all actions. No conditions! Block interrupts and trigger. Leave FIFO untouched! | ||
3203 | spin_lock_irqsave(&instance->subdevice_lock, | ||
3204 | cpu_flags); | ||
3205 | ctrl = inl(instance->ctrl_reg); | ||
3206 | ctrl |= | ||
3207 | ME6000_AO_CTRL_BIT_STOP | | ||
3208 | ME6000_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
3209 | ctrl &= | ||
3210 | ~(ME6000_AO_CTRL_BIT_ENABLE_IRQ | | ||
3211 | ME6000_AO_CTRL_BIT_ENABLE_EX_TRIG); | ||
3212 | ctrl &= | ||
3213 | ~(ME6000_AO_CTRL_BIT_EX_TRIG_EDGE | | ||
3214 | ME6000_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH); | ||
3215 | //Disabling FIFO | ||
3216 | ctrl &= ~ME6000_AO_CTRL_BIT_ENABLE_FIFO; | ||
3217 | |||
3218 | outl(ctrl, instance->ctrl_reg); | ||
3219 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3220 | instance->reg_base, | ||
3221 | instance->ctrl_reg - | ||
3222 | instance->reg_base, ctrl); | ||
3223 | spin_unlock_irqrestore(&instance-> | ||
3224 | subdevice_lock, | ||
3225 | cpu_flags); | ||
3226 | |||
3227 | //Reset interrupt latch | ||
3228 | inl(instance->irq_reset_reg); | ||
3229 | |||
3230 | spin_lock(instance->preload_reg_lock); | ||
3231 | //Remove from synchronous start. Block triggering from this output. | ||
3232 | synch = inl(instance->preload_reg); | ||
3233 | synch &= | ||
3234 | ~((ME6000_AO_SYNC_HOLD | | ||
3235 | ME6000_AO_SYNC_EXT_TRIG) << instance-> | ||
3236 | ao_idx); | ||
3237 | if (!(instance->fifo & ME6000_AO_HAS_FIFO)) { // No FIFO - set to single safe mode | ||
3238 | synch |= | ||
3239 | ME6000_AO_SYNC_HOLD << instance-> | ||
3240 | ao_idx; | ||
3241 | } | ||
3242 | outl(synch, instance->preload_reg); | ||
3243 | PDEBUG_REG | ||
3244 | ("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3245 | instance->reg_base, | ||
3246 | instance->preload_reg - instance->reg_base, | ||
3247 | synch); | ||
3248 | //Set this channel as triggered (none active). | ||
3249 | *instance->triggering_flags &= | ||
3250 | ~(0x1 << instance->ao_idx); | ||
3251 | spin_unlock(instance->preload_reg_lock); | ||
3252 | |||
3253 | // Set correct value for single_read(); | ||
3254 | instance->single_value_in_fifo = | ||
3255 | instance->single_value; | ||
3256 | |||
3257 | instance->status = ao_status_single_end; | ||
3258 | |||
3259 | // Signal the end. | ||
3260 | signaling = 1; | ||
3261 | } | ||
3262 | } else { // No extra registers. | ||
3263 | /* | ||
3264 | if (!(status & single_mask)) | ||
3265 | {// State machine is not working. | ||
3266 | PDEBUG("Single call has been complited.\n"); | ||
3267 | |||
3268 | // Set correct value for single_read(); | ||
3269 | instance->single_value = instance->single_value_in_fifo; | ||
3270 | |||
3271 | // Set status as 'ao_status_single_end' | ||
3272 | instance->status = ao_status_single_end; | ||
3273 | |||
3274 | // Signal the end. | ||
3275 | signaling = 1; | ||
3276 | // Wait for stop ISM. | ||
3277 | reschedule = 1; | ||
3278 | |||
3279 | break; | ||
3280 | } | ||
3281 | */ | ||
3282 | if (!single_mask) { // Was triggered. | ||
3283 | PDEBUG("Single call has been complited.\n"); | ||
3284 | |||
3285 | // Set correct value for single_read(); | ||
3286 | instance->single_value = | ||
3287 | instance->single_value_in_fifo; | ||
3288 | |||
3289 | // Set status as 'ao_status_single_end' | ||
3290 | instance->status = ao_status_single_end; | ||
3291 | |||
3292 | // Signal the end. | ||
3293 | signaling = 1; | ||
3294 | |||
3295 | break; | ||
3296 | } | ||
3297 | // Check timeout. | ||
3298 | if ((instance->timeout.delay) && ((jiffies - instance->timeout.start_time) >= instance->timeout.delay)) { // Timeout | ||
3299 | PDEBUG("Timeout reached.\n"); | ||
3300 | |||
3301 | spin_lock(instance->preload_reg_lock); | ||
3302 | //Remove from synchronous start. Block triggering from this output. | ||
3303 | synch = inl(instance->preload_reg); | ||
3304 | synch &= | ||
3305 | ~(ME6000_AO_SYNC_EXT_TRIG << instance-> | ||
3306 | ao_idx); | ||
3307 | synch |= | ||
3308 | ME6000_AO_SYNC_HOLD << instance->ao_idx; | ||
3309 | |||
3310 | outl(synch, instance->preload_reg); | ||
3311 | PDEBUG_REG | ||
3312 | ("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3313 | instance->reg_base, | ||
3314 | instance->preload_reg - instance->reg_base, | ||
3315 | synch); | ||
3316 | //Set this channel as triggered (none active). | ||
3317 | *instance->triggering_flags &= | ||
3318 | ~(0x1 << instance->ao_idx); | ||
3319 | spin_unlock(instance->preload_reg_lock); | ||
3320 | |||
3321 | // Restore old settings. | ||
3322 | PDEBUG("Write old value back to register.\n"); | ||
3323 | outl(instance->single_value, | ||
3324 | instance->single_reg); | ||
3325 | PDEBUG_REG | ||
3326 | ("single_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3327 | instance->reg_base, | ||
3328 | instance->single_reg - instance->reg_base, | ||
3329 | instance->single_value); | ||
3330 | |||
3331 | // Set correct value for single_read(); | ||
3332 | instance->single_value_in_fifo = | ||
3333 | instance->single_value; | ||
3334 | |||
3335 | instance->status = ao_status_single_end; | ||
3336 | |||
3337 | // Signal the end. | ||
3338 | signaling = 1; | ||
3339 | } | ||
3340 | } | ||
3341 | |||
3342 | // Wait for stop. | ||
3343 | reschedule = 1; | ||
3344 | break; | ||
3345 | |||
3346 | case ao_status_stream_end: | ||
3347 | if (!(instance->fifo & ME6000_AO_HAS_FIFO)) { // No FIFO | ||
3348 | PERROR_CRITICAL | ||
3349 | ("Streaming on single device! This feature is not implemented in this version!\n"); | ||
3350 | instance->status = ao_status_stream_error; | ||
3351 | // Signal the end. | ||
3352 | signaling = 1; | ||
3353 | break; | ||
3354 | } | ||
3355 | case ao_status_single_end: | ||
3356 | if (instance->fifo) { // Extra registers. | ||
3357 | if (status & ME6000_AO_STATUS_BIT_FSM) { // State machine is working but the status is set to end. Force stop. | ||
3358 | |||
3359 | // Wait for stop. | ||
3360 | reschedule = 1; | ||
3361 | } | ||
3362 | |||
3363 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
3364 | // Stop all actions. No conditions! Block interrupts and trigger. Leave FIFO untouched! | ||
3365 | ctrl = inl(instance->ctrl_reg); | ||
3366 | ctrl |= | ||
3367 | ME6000_AO_CTRL_BIT_IMMEDIATE_STOP | | ||
3368 | ME6000_AO_CTRL_BIT_STOP; | ||
3369 | ctrl &= | ||
3370 | ~(ME6000_AO_CTRL_BIT_ENABLE_IRQ | | ||
3371 | ME6000_AO_CTRL_BIT_ENABLE_EX_TRIG); | ||
3372 | outl(ctrl, instance->ctrl_reg); | ||
3373 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3374 | instance->reg_base, | ||
3375 | instance->ctrl_reg - instance->reg_base, | ||
3376 | ctrl); | ||
3377 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
3378 | cpu_flags); | ||
3379 | |||
3380 | //Reset interrupt latch | ||
3381 | inl(instance->irq_reset_reg); | ||
3382 | } else { // No extra registers. | ||
3383 | /* | ||
3384 | if (status & single_mask) | ||
3385 | {// State machine is working but the status is set to end. Force stop. | ||
3386 | |||
3387 | // Wait for stop. | ||
3388 | reschedule = 1; | ||
3389 | } | ||
3390 | */ | ||
3391 | } | ||
3392 | break; | ||
3393 | |||
3394 | // Stream modes | ||
3395 | case ao_status_stream_run_wait: | ||
3396 | if (!(instance->fifo & ME6000_AO_HAS_FIFO)) { // No FIFO | ||
3397 | PERROR_CRITICAL | ||
3398 | ("Streaming on single device! This feature is not implemented in this version!\n"); | ||
3399 | instance->status = ao_status_stream_error; | ||
3400 | // Signal the end. | ||
3401 | signaling = 1; | ||
3402 | break; | ||
3403 | } | ||
3404 | |||
3405 | if (status & ME6000_AO_STATUS_BIT_FSM) { // State machine is working. Waiting for start finish. | ||
3406 | instance->status = ao_status_stream_run; | ||
3407 | |||
3408 | // Signal end of this step | ||
3409 | signaling = 1; | ||
3410 | } else { // State machine is not working. | ||
3411 | if (!(status & ME6000_AO_STATUS_BIT_EF)) { // FIFO is empty. Procedure has started and finish already! | ||
3412 | instance->status = ao_status_stream_end; | ||
3413 | |||
3414 | // Signal the end. | ||
3415 | signaling = 1; | ||
3416 | // Wait for stop. | ||
3417 | reschedule = 1; | ||
3418 | break; | ||
3419 | } | ||
3420 | } | ||
3421 | |||
3422 | // Check timeout. | ||
3423 | if ((instance->timeout.delay) && ((jiffies - instance->timeout.start_time) >= instance->timeout.delay)) { // Timeout | ||
3424 | PDEBUG("Timeout reached.\n"); | ||
3425 | // Stop all actions. No conditions! Block interrupts. Leave FIFO untouched! | ||
3426 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
3427 | ctrl = inl(instance->ctrl_reg); | ||
3428 | ctrl |= | ||
3429 | ME6000_AO_CTRL_BIT_STOP | | ||
3430 | ME6000_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
3431 | ctrl &= | ||
3432 | ~(ME6000_AO_CTRL_BIT_ENABLE_IRQ | | ||
3433 | ME6000_AO_CTRL_BIT_ENABLE_EX_TRIG); | ||
3434 | outl(ctrl, instance->ctrl_reg); | ||
3435 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3436 | instance->reg_base, | ||
3437 | instance->ctrl_reg - instance->reg_base, | ||
3438 | ctrl); | ||
3439 | spin_unlock_irqrestore(&instance->subdevice_lock, | ||
3440 | cpu_flags); | ||
3441 | |||
3442 | //Reset interrupt latch | ||
3443 | inl(instance->irq_reset_reg); | ||
3444 | |||
3445 | spin_lock(instance->preload_reg_lock); | ||
3446 | //Remove from synchronous start. Block triggering from this output. | ||
3447 | synch = inl(instance->preload_reg); | ||
3448 | synch &= | ||
3449 | ~((ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG) << | ||
3450 | instance->ao_idx); | ||
3451 | outl(synch, instance->preload_reg); | ||
3452 | PDEBUG_REG("preload_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
3453 | instance->reg_base, | ||
3454 | instance->preload_reg - instance->reg_base, | ||
3455 | synch); | ||
3456 | spin_unlock(instance->preload_reg_lock); | ||
3457 | |||
3458 | instance->status = ao_status_stream_end; | ||
3459 | |||
3460 | // Signal the end. | ||
3461 | signaling = 1; | ||
3462 | } | ||
3463 | // Wait for stop. | ||
3464 | reschedule = 1; | ||
3465 | break; | ||
3466 | |||
3467 | case ao_status_stream_run: | ||
3468 | if (!(instance->fifo & ME6000_AO_HAS_FIFO)) { // No FIFO | ||
3469 | PERROR_CRITICAL | ||
3470 | ("Streaming on single device! This feature is not implemented in this version!\n"); | ||
3471 | instance->status = ao_status_stream_error; | ||
3472 | // Signal the end. | ||
3473 | signaling = 1; | ||
3474 | break; | ||
3475 | } | ||
3476 | |||
3477 | if (!(status & ME6000_AO_STATUS_BIT_FSM)) { // State machine is not working. This is an error. | ||
3478 | // BROKEN PIPE! | ||
3479 | if (!(status & ME6000_AO_STATUS_BIT_EF)) { // FIFO is empty. | ||
3480 | if (me_circ_buf_values(&instance->circ_buf)) { // Software buffer is not empty. | ||
3481 | if (instance->stop_data_count && (instance->stop_data_count <= instance->data_count)) { //Finishing work. Requed data shown. | ||
3482 | PDEBUG | ||
3483 | ("ISM stoped. No data in FIFO. Buffer is not empty.\n"); | ||
3484 | instance->status = | ||
3485 | ao_status_stream_end; | ||
3486 | } else { | ||
3487 | PERROR | ||
3488 | ("Output stream has been broken. ISM stoped. No data in FIFO. Buffer is not empty.\n"); | ||
3489 | instance->status = | ||
3490 | ao_status_stream_buffer_error; | ||
3491 | } | ||
3492 | } else { // Software buffer is empty. | ||
3493 | PDEBUG | ||
3494 | ("ISM stoped. No data in FIFO. Buffer is empty.\n"); | ||
3495 | instance->status = ao_status_stream_end; | ||
3496 | } | ||
3497 | } else { // There are still datas in FIFO. | ||
3498 | if (me_circ_buf_values(&instance->circ_buf)) { // Software buffer is not empty. | ||
3499 | PERROR | ||
3500 | ("Output stream has been broken. ISM stoped but some data in FIFO and buffer.\n"); | ||
3501 | } else { // Software buffer is empty. | ||
3502 | PERROR | ||
3503 | ("Output stream has been broken. ISM stoped but some data in FIFO. Buffer is empty.\n"); | ||
3504 | } | ||
3505 | instance->status = ao_status_stream_fifo_error; | ||
3506 | |||
3507 | } | ||
3508 | |||
3509 | // Signal the failure. | ||
3510 | signaling = 1; | ||
3511 | break; | ||
3512 | } | ||
3513 | // Wait for stop. | ||
3514 | reschedule = 1; | ||
3515 | break; | ||
3516 | |||
3517 | case ao_status_stream_end_wait: | ||
3518 | if (!(instance->fifo & ME6000_AO_HAS_FIFO)) { // No FIFO | ||
3519 | PERROR_CRITICAL | ||
3520 | ("Streaming on single device! This feature is not implemented in this version!\n"); | ||
3521 | instance->status = ao_status_stream_error; | ||
3522 | // Signal the end. | ||
3523 | signaling = 1; | ||
3524 | break; | ||
3525 | } | ||
3526 | |||
3527 | if (!(status & ME6000_AO_STATUS_BIT_FSM)) { // State machine is not working. Waiting for stop finish. | ||
3528 | instance->status = ao_status_stream_end; | ||
3529 | signaling = 1; | ||
3530 | } | ||
3531 | // State machine is working. | ||
3532 | reschedule = 1; | ||
3533 | break; | ||
3534 | |||
3535 | default: | ||
3536 | PERROR_CRITICAL("Status is in wrong state (%d)!\n", | ||
3537 | instance->status); | ||
3538 | instance->status = ao_status_stream_error; | ||
3539 | // Signal the end. | ||
3540 | signaling = 1; | ||
3541 | break; | ||
3542 | |||
3543 | } | ||
3544 | |||
3545 | if (signaling) { //Signal it. | ||
3546 | wake_up_interruptible_all(&instance->wait_queue); | ||
3547 | } | ||
3548 | |||
3549 | if (instance->ao_control_task_flag && reschedule) { // Reschedule task | ||
3550 | queue_delayed_work(instance->me6000_workqueue, | ||
3551 | &instance->ao_control_task, 1); | ||
3552 | } else { | ||
3553 | PINFO("<%s> Ending control task.\n", __FUNCTION__); | ||
3554 | } | ||
3555 | |||
3556 | } | ||
3557 | |||
3558 | static int me6000_ao_query_range_by_min_max(me_subdevice_t * subdevice, | ||
3559 | int unit, | ||
3560 | int *min, | ||
3561 | int *max, int *maxdata, int *range) | ||
3562 | { | ||
3563 | me6000_ao_subdevice_t *instance; | ||
3564 | |||
3565 | instance = (me6000_ao_subdevice_t *) subdevice; | ||
3566 | |||
3567 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
3568 | |||
3569 | if ((*max - *min) < 0) { | ||
3570 | PERROR("Invalid minimum and maximum values specified.\n"); | ||
3571 | return ME_ERRNO_INVALID_MIN_MAX; | ||
3572 | } | ||
3573 | |||
3574 | if ((unit == ME_UNIT_VOLT) || (unit == ME_UNIT_ANY)) { | ||
3575 | if ((*max <= (instance->max + 1000)) && (*min >= instance->min)) { | ||
3576 | *min = instance->min; | ||
3577 | *max = instance->max; | ||
3578 | *maxdata = ME6000_AO_MAX_DATA; | ||
3579 | *range = 0; | ||
3580 | } else { | ||
3581 | PERROR("No matching range available.\n"); | ||
3582 | return ME_ERRNO_NO_RANGE; | ||
3583 | } | ||
3584 | } else { | ||
3585 | PERROR("Invalid physical unit specified.\n"); | ||
3586 | return ME_ERRNO_INVALID_UNIT; | ||
3587 | } | ||
3588 | |||
3589 | return ME_ERRNO_SUCCESS; | ||
3590 | } | ||
3591 | |||
3592 | static int me6000_ao_query_number_ranges(me_subdevice_t * subdevice, | ||
3593 | int unit, int *count) | ||
3594 | { | ||
3595 | me6000_ao_subdevice_t *instance; | ||
3596 | |||
3597 | instance = (me6000_ao_subdevice_t *) subdevice; | ||
3598 | |||
3599 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
3600 | |||
3601 | if ((unit == ME_UNIT_VOLT) || (unit == ME_UNIT_ANY)) { | ||
3602 | *count = 1; | ||
3603 | } else { | ||
3604 | *count = 0; | ||
3605 | } | ||
3606 | |||
3607 | return ME_ERRNO_SUCCESS; | ||
3608 | } | ||
3609 | |||
3610 | static int me6000_ao_query_range_info(me_subdevice_t * subdevice, | ||
3611 | int range, | ||
3612 | int *unit, | ||
3613 | int *min, int *max, int *maxdata) | ||
3614 | { | ||
3615 | me6000_ao_subdevice_t *instance; | ||
3616 | |||
3617 | instance = (me6000_ao_subdevice_t *) subdevice; | ||
3618 | |||
3619 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
3620 | |||
3621 | if (range == 0) { | ||
3622 | *unit = ME_UNIT_VOLT; | ||
3623 | *min = instance->min; | ||
3624 | *max = instance->max; | ||
3625 | *maxdata = ME6000_AO_MAX_DATA; | ||
3626 | } else { | ||
3627 | PERROR("Invalid range number specified.\n"); | ||
3628 | return ME_ERRNO_INVALID_RANGE; | ||
3629 | } | ||
3630 | |||
3631 | return ME_ERRNO_SUCCESS; | ||
3632 | } | ||
3633 | |||
3634 | static int me6000_ao_query_timer(me_subdevice_t * subdevice, | ||
3635 | int timer, | ||
3636 | int *base_frequency, | ||
3637 | long long *min_ticks, long long *max_ticks) | ||
3638 | { | ||
3639 | me6000_ao_subdevice_t *instance; | ||
3640 | |||
3641 | instance = (me6000_ao_subdevice_t *) subdevice; | ||
3642 | |||
3643 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
3644 | |||
3645 | if (instance->fifo) { //Streaming device. | ||
3646 | *base_frequency = ME6000_AO_BASE_FREQUENCY; | ||
3647 | if (timer == ME_TIMER_ACQ_START) { | ||
3648 | *min_ticks = ME6000_AO_MIN_ACQ_TICKS; | ||
3649 | *max_ticks = ME6000_AO_MAX_ACQ_TICKS; | ||
3650 | } else if (timer == ME_TIMER_CONV_START) { | ||
3651 | *min_ticks = ME6000_AO_MIN_CHAN_TICKS; | ||
3652 | *max_ticks = ME6000_AO_MAX_CHAN_TICKS; | ||
3653 | } | ||
3654 | } else { //Not streaming device! | ||
3655 | *base_frequency = 0; | ||
3656 | *min_ticks = 0; | ||
3657 | *max_ticks = 0; | ||
3658 | } | ||
3659 | |||
3660 | return ME_ERRNO_SUCCESS; | ||
3661 | } | ||
3662 | |||
3663 | static int me6000_ao_query_number_channels(me_subdevice_t * subdevice, | ||
3664 | int *number) | ||
3665 | { | ||
3666 | me6000_ao_subdevice_t *instance; | ||
3667 | instance = (me6000_ao_subdevice_t *) subdevice; | ||
3668 | |||
3669 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
3670 | |||
3671 | *number = 1; | ||
3672 | return ME_ERRNO_SUCCESS; | ||
3673 | } | ||
3674 | |||
3675 | static int me6000_ao_query_subdevice_type(me_subdevice_t * subdevice, | ||
3676 | int *type, int *subtype) | ||
3677 | { | ||
3678 | me6000_ao_subdevice_t *instance; | ||
3679 | |||
3680 | instance = (me6000_ao_subdevice_t *) subdevice; | ||
3681 | |||
3682 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
3683 | |||
3684 | *type = ME_TYPE_AO; | ||
3685 | *subtype = | ||
3686 | (instance-> | ||
3687 | fifo & ME6000_AO_HAS_FIFO) ? ME_SUBTYPE_STREAMING : | ||
3688 | ME_SUBTYPE_SINGLE; | ||
3689 | |||
3690 | return ME_ERRNO_SUCCESS; | ||
3691 | } | ||
3692 | |||
3693 | static int me6000_ao_query_subdevice_caps(me_subdevice_t * subdevice, int *caps) | ||
3694 | { | ||
3695 | me6000_ao_subdevice_t *instance; | ||
3696 | instance = (me6000_ao_subdevice_t *) subdevice; | ||
3697 | |||
3698 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
3699 | |||
3700 | *caps = | ||
3701 | ME_CAPS_AO_TRIG_SYNCHRONOUS | ((instance->fifo) ? ME_CAPS_AO_FIFO : | ||
3702 | ME_CAPS_NONE); | ||
3703 | |||
3704 | return ME_ERRNO_SUCCESS; | ||
3705 | } | ||
3706 | |||
3707 | static int me6000_ao_query_subdevice_caps_args(struct me_subdevice *subdevice, | ||
3708 | int cap, int *args, int count) | ||
3709 | { | ||
3710 | me6000_ao_subdevice_t *instance; | ||
3711 | int err = ME_ERRNO_SUCCESS; | ||
3712 | |||
3713 | instance = (me6000_ao_subdevice_t *) subdevice; | ||
3714 | |||
3715 | PDEBUG("executed. idx=%d\n", instance->ao_idx); | ||
3716 | |||
3717 | if (count != 1) { | ||
3718 | PERROR("Invalid capability argument count.\n"); | ||
3719 | return ME_ERRNO_INVALID_CAP_ARG_COUNT; | ||
3720 | } | ||
3721 | |||
3722 | switch (cap) { | ||
3723 | case ME_CAP_AI_FIFO_SIZE: | ||
3724 | args[0] = (instance->fifo) ? ME6000_AO_FIFO_COUNT : 0; | ||
3725 | break; | ||
3726 | |||
3727 | case ME_CAP_AI_BUFFER_SIZE: | ||
3728 | args[0] = | ||
3729 | (instance->circ_buf.buf) ? ME6000_AO_CIRC_BUF_COUNT : 0; | ||
3730 | break; | ||
3731 | |||
3732 | default: | ||
3733 | PERROR("Invalid capability.\n"); | ||
3734 | err = ME_ERRNO_INVALID_CAP; | ||
3735 | args[0] = 0; | ||
3736 | } | ||
3737 | |||
3738 | return err; | ||
3739 | } | ||
diff --git a/drivers/staging/meilhaus/me6000_ao.h b/drivers/staging/meilhaus/me6000_ao.h new file mode 100644 index 000000000000..9629649cd410 --- /dev/null +++ b/drivers/staging/meilhaus/me6000_ao.h | |||
@@ -0,0 +1,200 @@ | |||
1 | /** | ||
2 | * @file me6000_ao.h | ||
3 | * | ||
4 | * @brief Meilhaus ME-6000 analog output subdevice class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME6000_AO_H_ | ||
28 | #define _ME6000_AO_H_ | ||
29 | |||
30 | #include <linux/version.h> | ||
31 | #include "mesubdevice.h" | ||
32 | #include "mecirc_buf.h" | ||
33 | #include "meioctl.h" | ||
34 | |||
35 | #ifdef __KERNEL__ | ||
36 | |||
37 | #define ME6000_AO_MAX_SUBDEVICES 16 | ||
38 | #define ME6000_AO_FIFO_COUNT 8192 | ||
39 | |||
40 | #define ME6000_AO_BASE_FREQUENCY 33000000L | ||
41 | |||
42 | #define ME6000_AO_MIN_ACQ_TICKS 0LL | ||
43 | #define ME6000_AO_MAX_ACQ_TICKS 0LL | ||
44 | |||
45 | #define ME6000_AO_MIN_CHAN_TICKS 66LL | ||
46 | #define ME6000_AO_MAX_CHAN_TICKS 0xFFFFFFFFLL | ||
47 | |||
48 | #define ME6000_AO_MIN_RANGE -10000000 | ||
49 | #define ME6000_AO_MAX_RANGE 9999694 | ||
50 | |||
51 | #define ME6000_AO_MIN_RANGE_HIGH 0 | ||
52 | #define ME6000_AO_MAX_RANGE_HIGH 49999237 | ||
53 | |||
54 | #define ME6000_AO_MAX_DATA 0xFFFF | ||
55 | |||
56 | #ifdef ME_SYNAPSE | ||
57 | # define ME6000_AO_CIRC_BUF_SIZE_ORDER 8 // 2^n PAGES =>> Maximum value of 1MB for Synapse | ||
58 | #else | ||
59 | # define ME6000_AO_CIRC_BUF_SIZE_ORDER 5 // 2^n PAGES =>> 128KB | ||
60 | #endif | ||
61 | #define ME6000_AO_CIRC_BUF_SIZE PAGE_SIZE<<ME6000_AO_CIRC_BUF_SIZE_ORDER // Buffer size in bytes. | ||
62 | |||
63 | # ifdef _CBUFF_32b_t | ||
64 | # define ME6000_AO_CIRC_BUF_COUNT ((ME6000_AO_CIRC_BUF_SIZE) / sizeof(uint32_t)) // Size in values | ||
65 | # else | ||
66 | # define ME6000_AO_CIRC_BUF_COUNT ((ME6000_AO_CIRC_BUF_SIZE) / sizeof(uint16_t)) // Size in values | ||
67 | # endif | ||
68 | |||
69 | # define ME6000_AO_CONTINOUS 0x0 | ||
70 | # define ME6000_AO_WRAP_MODE 0x1 | ||
71 | # define ME6000_AO_HW_MODE 0x2 | ||
72 | |||
73 | # define ME6000_AO_HW_WRAP_MODE (ME6000_AO_WRAP_MODE | ME6000_AO_HW_MODE) | ||
74 | # define ME6000_AO_SW_WRAP_MODE ME6000_AO_WRAP_MODE | ||
75 | |||
76 | # define ME6000_AO_INF_STOP_MODE 0x0 | ||
77 | # define ME6000_AO_ACQ_STOP_MODE 0x1 | ||
78 | # define ME6000_AO_SCAN_STOP_MODE 0x2 | ||
79 | |||
80 | # define ME6000_AO_EXTRA_HARDWARE 0x1 | ||
81 | # define ME6000_AO_HAS_FIFO 0x2 | ||
82 | |||
83 | typedef enum ME6000_AO_STATUS { | ||
84 | ao_status_none = 0, | ||
85 | ao_status_single_configured, | ||
86 | ao_status_single_run_wait, | ||
87 | ao_status_single_run, | ||
88 | ao_status_single_end_wait, | ||
89 | ao_status_single_end, | ||
90 | ao_status_stream_configured, | ||
91 | ao_status_stream_run_wait, | ||
92 | ao_status_stream_run, | ||
93 | ao_status_stream_end_wait, | ||
94 | ao_status_stream_end, | ||
95 | ao_status_stream_fifo_error, | ||
96 | ao_status_stream_buffer_error, | ||
97 | ao_status_stream_error, | ||
98 | ao_status_last | ||
99 | } ME6000_AO_STATUS; | ||
100 | |||
101 | typedef struct me6000_ao_timeout { | ||
102 | unsigned long start_time; | ||
103 | unsigned long delay; | ||
104 | } me6000_ao_timeout_t; | ||
105 | |||
106 | /** | ||
107 | * @brief The ME-6000 analog output subdevice class. | ||
108 | */ | ||
109 | typedef struct me6000_ao_subdevice { | ||
110 | /* Inheritance */ | ||
111 | me_subdevice_t base; /**< The subdevice base class. */ | ||
112 | unsigned int ao_idx; | ||
113 | |||
114 | /* Attributes */ | ||
115 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
116 | spinlock_t *preload_reg_lock; /**< Spin lock to protect preload_reg from concurrent access. */ | ||
117 | |||
118 | uint32_t *preload_flags; | ||
119 | uint32_t *triggering_flags; | ||
120 | |||
121 | /* Hardware feautres */ | ||
122 | unsigned int irq; /**< The interrupt request number assigned by the PCI BIOS. */ | ||
123 | int fifo; /**< If set this device has a FIFO. */ | ||
124 | |||
125 | //Range | ||
126 | int min; | ||
127 | int max; | ||
128 | |||
129 | int single_value; /**< Mirror of the output value in single mode. */ | ||
130 | int single_value_in_fifo; /**< Mirror of the value written in single mode. */ | ||
131 | uint32_t ctrl_trg; /**< Mirror of the trigger settings. */ | ||
132 | |||
133 | volatile int mode; /**< Flags used for storing SW wraparound setup*/ | ||
134 | int stop_mode; /**< The user defined stop condition flag. */ | ||
135 | unsigned int start_mode; | ||
136 | unsigned int stop_count; /**< The user defined dates presentation end count. */ | ||
137 | unsigned int stop_data_count; /**< The stop presentation count. */ | ||
138 | unsigned int data_count; /**< The real presentation count. */ | ||
139 | unsigned int preloaded_count; /**< The next data addres in buffer. <= for wraparound mode. */ | ||
140 | int hardware_stop_delay; /**< The time that stop can take. This is only to not show hardware bug to user. */ | ||
141 | |||
142 | volatile enum ME6000_AO_STATUS status; /**< The current stream status flag. */ | ||
143 | me6000_ao_timeout_t timeout; /**< The timeout for start in blocking and non-blocking mode. */ | ||
144 | |||
145 | /* Registers *//**< All registers are 32 bits long. */ | ||
146 | unsigned long ctrl_reg; | ||
147 | unsigned long status_reg; | ||
148 | unsigned long fifo_reg; | ||
149 | unsigned long single_reg; | ||
150 | unsigned long timer_reg; | ||
151 | unsigned long irq_status_reg; | ||
152 | unsigned long preload_reg; | ||
153 | unsigned long irq_reset_reg; | ||
154 | #ifdef MEDEBUG_DEBUG_REG | ||
155 | unsigned long reg_base; | ||
156 | #endif | ||
157 | |||
158 | /* Software buffer */ | ||
159 | me_circ_buf_t circ_buf; /**< Circular buffer holding measurment data. */ | ||
160 | wait_queue_head_t wait_queue; /**< Wait queue to put on tasks waiting for data to arrive. */ | ||
161 | |||
162 | struct workqueue_struct *me6000_workqueue; | ||
163 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) | ||
164 | struct work_struct ao_control_task; | ||
165 | #else | ||
166 | struct delayed_work ao_control_task; | ||
167 | #endif | ||
168 | |||
169 | volatile int ao_control_task_flag; /**< Flag controling reexecuting of control task */ | ||
170 | |||
171 | } me6000_ao_subdevice_t; | ||
172 | |||
173 | /** | ||
174 | * @brief The constructor to generate a ME-6000 analog output subdevice instance. | ||
175 | * | ||
176 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
177 | * @param ctrl_reg_lock Pointer to spin lock protecting the control register from concurrent access. | ||
178 | * @param preload_flags Pointer to spin lock protecting the hold&trigger register from concurrent access. | ||
179 | * @param ao_idx Subdevice number. | ||
180 | * @param fifo Flag set if subdevice has hardware FIFO. | ||
181 | * @param irq IRQ number. | ||
182 | * @param high_range Flag set if subdevice has high curren output. | ||
183 | * @param me6000_wq Queue for asynchronous task (1 queue for all subdevice on 1 board). | ||
184 | * | ||
185 | * @return Pointer to new instance on success.\n | ||
186 | * NULL on error. | ||
187 | */ | ||
188 | me6000_ao_subdevice_t *me6000_ao_constructor(uint32_t reg_base, | ||
189 | spinlock_t * preload_reg_lock, | ||
190 | uint32_t * preload_flags, | ||
191 | uint32_t * triggering_flags, | ||
192 | int ao_idx, | ||
193 | int fifo, | ||
194 | int irq, | ||
195 | int high_range, | ||
196 | struct workqueue_struct | ||
197 | *me6000_wq); | ||
198 | |||
199 | #endif //__KERNEL__ | ||
200 | #endif //_ME6000_AO_H_ | ||
diff --git a/drivers/staging/meilhaus/me6000_ao_reg.h b/drivers/staging/meilhaus/me6000_ao_reg.h new file mode 100644 index 000000000000..eb8f46e1b75b --- /dev/null +++ b/drivers/staging/meilhaus/me6000_ao_reg.h | |||
@@ -0,0 +1,177 @@ | |||
1 | /** | ||
2 | * @file me6000_ao_reg.h | ||
3 | * | ||
4 | * @brief ME-6000 analog output subdevice register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME6000_AO_REG_H_ | ||
28 | #define _ME6000_AO_REG_H_ | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | // AO | ||
33 | #define ME6000_AO_00_CTRL_REG 0x00 // R/W | ||
34 | #define ME6000_AO_00_STATUS_REG 0x04 // R/_ | ||
35 | #define ME6000_AO_00_FIFO_REG 0x08 // _/W | ||
36 | #define ME6000_AO_00_SINGLE_REG 0x0C // R/W | ||
37 | #define ME6000_AO_00_TIMER_REG 0x10 // _/W | ||
38 | |||
39 | #define ME6000_AO_01_CTRL_REG 0x18 // R/W | ||
40 | #define ME6000_AO_01_STATUS_REG 0x1C // R/_ | ||
41 | #define ME6000_AO_01_FIFO_REG 0x20 // _/W | ||
42 | #define ME6000_AO_01_SINGLE_REG 0x24 // R/W | ||
43 | #define ME6000_AO_01_TIMER_REG 0x28 // _/W | ||
44 | |||
45 | #define ME6000_AO_02_CTRL_REG 0x30 // R/W | ||
46 | #define ME6000_AO_02_STATUS_REG 0x34 // R/_ | ||
47 | #define ME6000_AO_02_FIFO_REG 0x38 // _/W | ||
48 | #define ME6000_AO_02_SINGLE_REG 0x3C // R/W | ||
49 | #define ME6000_AO_02_TIMER_REG 0x40 // _/W | ||
50 | |||
51 | #define ME6000_AO_03_CTRL_REG 0x48 // R/W | ||
52 | #define ME6000_AO_03_STATUS_REG 0x4C // R/_ | ||
53 | #define ME6000_AO_03_FIFO_REG 0x50 // _/W | ||
54 | #define ME6000_AO_03_SINGLE_REG 0x54 // R/W | ||
55 | #define ME6000_AO_03_TIMER_REG 0x58 // _/W | ||
56 | |||
57 | #define ME6000_AO_SINGLE_STATUS_REG 0xA4 // R/_ | ||
58 | #define ME6000_AO_SINGLE_STATUS_OFFSET 4 //The first single subdevice => bit 0 in ME6000_AO_SINGLE_STATUS_REG. | ||
59 | |||
60 | #define ME6000_AO_04_STATUS_REG ME6000_AO_SINGLE_STATUS_REG | ||
61 | #define ME6000_AO_04_SINGLE_REG 0x74 // _/W | ||
62 | |||
63 | #define ME6000_AO_05_STATUS_REG ME6000_AO_SINGLE_STATUS_REG | ||
64 | #define ME6000_AO_05_SINGLE_REG 0x78 // _/W | ||
65 | |||
66 | #define ME6000_AO_06_STATUS_REG ME6000_AO_SINGLE_STATUS_REG | ||
67 | #define ME6000_AO_06_SINGLE_REG 0x7C // _/W | ||
68 | |||
69 | #define ME6000_AO_07_STATUS_REG ME6000_AO_SINGLE_STATUS_REG | ||
70 | #define ME6000_AO_07_SINGLE_REG 0x80 // _/W | ||
71 | |||
72 | #define ME6000_AO_08_STATUS_REG ME6000_AO_SINGLE_STATUS_REG | ||
73 | #define ME6000_AO_08_SINGLE_REG 0x84 // _/W | ||
74 | |||
75 | #define ME6000_AO_09_STATUS_REG ME6000_AO_SINGLE_STATUS_REG | ||
76 | #define ME6000_AO_09_SINGLE_REG 0x88 // _/W | ||
77 | |||
78 | #define ME6000_AO_10_STATUS_REG ME6000_AO_SINGLE_STATUS_REG | ||
79 | #define ME6000_AO_10_SINGLE_REG 0x8C // _/W | ||
80 | |||
81 | #define ME6000_AO_11_STATUS_REG ME6000_AO_SINGLE_STATUS_REG | ||
82 | #define ME6000_AO_11_SINGLE_REG 0x90 // _/W | ||
83 | |||
84 | #define ME6000_AO_12_STATUS_REG ME6000_AO_SINGLE_STATUS_REG | ||
85 | #define ME6000_AO_12_SINGLE_REG 0x94 // _/W | ||
86 | |||
87 | #define ME6000_AO_13_STATUS_REG ME6000_AO_SINGLE_STATUS_REG | ||
88 | #define ME6000_AO_13_SINGLE_REG 0x98 // _/W | ||
89 | |||
90 | #define ME6000_AO_14_STATUS_REG ME6000_AO_SINGLE_STATUS_REG | ||
91 | #define ME6000_AO_14_SINGLE_REG 0x9C // _/W | ||
92 | |||
93 | #define ME6000_AO_15_STATUS_REG ME6000_AO_SINGLE_STATUS_REG | ||
94 | #define ME6000_AO_15_SINGLE_REG 0xA0 // _/W | ||
95 | |||
96 | //ME6000_AO_CTRL_REG | ||
97 | #define ME6000_AO_MODE_SINGLE 0x00 | ||
98 | #define ME6000_AO_MODE_WRAPAROUND 0x01 | ||
99 | #define ME6000_AO_MODE_CONTINUOUS 0x02 | ||
100 | #define ME6000_AO_CTRL_MODE_MASK (ME6000_AO_MODE_WRAPAROUND | ME6000_AO_MODE_CONTINUOUS) | ||
101 | |||
102 | #define ME6000_AO_CTRL_BIT_MODE_WRAPAROUND 0x001 | ||
103 | #define ME6000_AO_CTRL_BIT_MODE_CONTINUOUS 0x002 | ||
104 | #define ME6000_AO_CTRL_BIT_STOP 0x004 | ||
105 | #define ME6000_AO_CTRL_BIT_ENABLE_FIFO 0x008 | ||
106 | #define ME6000_AO_CTRL_BIT_ENABLE_EX_TRIG 0x010 | ||
107 | #define ME6000_AO_CTRL_BIT_EX_TRIG_EDGE 0x020 | ||
108 | #define ME6000_AO_CTRL_BIT_ENABLE_IRQ 0x040 | ||
109 | #define ME6000_AO_CTRL_BIT_IMMEDIATE_STOP 0x080 | ||
110 | #define ME6000_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH 0x800 | ||
111 | |||
112 | //ME6000_AO_STATUS_REG | ||
113 | #define ME6000_AO_STATUS_BIT_FSM 0x01 | ||
114 | #define ME6000_AO_STATUS_BIT_FF 0x02 | ||
115 | #define ME6000_AO_STATUS_BIT_HF 0x04 | ||
116 | #define ME6000_AO_STATUS_BIT_EF 0x08 | ||
117 | |||
118 | #define ME6000_AO_PRELOAD_REG 0xA8 // R/W ///ME6000_AO_SYNC_REG <==> ME6000_AO_PRELOAD_REG | ||
119 | /* | ||
120 | #define ME6000_AO_SYNC_HOLD_0 0x00000001 | ||
121 | #define ME6000_AO_SYNC_HOLD_1 0x00000002 | ||
122 | #define ME6000_AO_SYNC_HOLD_2 0x00000004 | ||
123 | #define ME6000_AO_SYNC_HOLD_3 0x00000008 | ||
124 | #define ME6000_AO_SYNC_HOLD_4 0x00000010 | ||
125 | #define ME6000_AO_SYNC_HOLD_5 0x00000020 | ||
126 | #define ME6000_AO_SYNC_HOLD_6 0x00000040 | ||
127 | #define ME6000_AO_SYNC_HOLD_7 0x00000080 | ||
128 | #define ME6000_AO_SYNC_HOLD_8 0x00000100 | ||
129 | #define ME6000_AO_SYNC_HOLD_9 0x00000200 | ||
130 | #define ME6000_AO_SYNC_HOLD_10 0x00000400 | ||
131 | #define ME6000_AO_SYNC_HOLD_11 0x00000800 | ||
132 | #define ME6000_AO_SYNC_HOLD_12 0x00001000 | ||
133 | #define ME6000_AO_SYNC_HOLD_13 0x00002000 | ||
134 | #define ME6000_AO_SYNC_HOLD_14 0x00004000 | ||
135 | #define ME6000_AO_SYNC_HOLD_15 0x00008000 | ||
136 | */ | ||
137 | #define ME6000_AO_SYNC_HOLD 0x00000001 | ||
138 | /* | ||
139 | #define ME6000_AO_SYNC_EXT_TRIG_0 0x00010000 | ||
140 | #define ME6000_AO_SYNC_EXT_TRIG_1 0x00020000 | ||
141 | #define ME6000_AO_SYNC_EXT_TRIG_2 0x00040000 | ||
142 | #define ME6000_AO_SYNC_EXT_TRIG_3 0x00080000 | ||
143 | #define ME6000_AO_SYNC_EXT_TRIG_4 0x00100000 | ||
144 | #define ME6000_AO_SYNC_EXT_TRIG_5 0x00200000 | ||
145 | #define ME6000_AO_SYNC_EXT_TRIG_6 0x00400000 | ||
146 | #define ME6000_AO_SYNC_EXT_TRIG_7 0x00800000 | ||
147 | #define ME6000_AO_SYNC_EXT_TRIG_8 0x01000000 | ||
148 | #define ME6000_AO_SYNC_EXT_TRIG_9 0x02000000 | ||
149 | #define ME6000_AO_SYNC_EXT_TRIG_10 0x04000000 | ||
150 | #define ME6000_AO_SYNC_EXT_TRIG_11 0x08000000 | ||
151 | #define ME6000_AO_SYNC_EXT_TRIG_12 0x10000000 | ||
152 | #define ME6000_AO_SYNC_EXT_TRIG_13 0x20000000 | ||
153 | #define ME6000_AO_SYNC_EXT_TRIG_14 0x40000000 | ||
154 | #define ME6000_AO_SYNC_EXT_TRIG_15 0x80000000 | ||
155 | */ | ||
156 | #define ME6000_AO_SYNC_EXT_TRIG 0x00010000 | ||
157 | |||
158 | #define ME6000_AO_EXT_TRIG 0x80000000 | ||
159 | |||
160 | // AO-IRQ | ||
161 | #define ME6000_AO_IRQ_STATUS_REG 0x60 // R/_ | ||
162 | #define ME6000_AO_00_IRQ_RESET_REG 0x64 // R/_ | ||
163 | #define ME6000_AO_01_IRQ_RESET_REG 0x68 // R/_ | ||
164 | #define ME6000_AO_02_IRQ_RESET_REG 0x6C // R/_ | ||
165 | #define ME6000_AO_03_IRQ_RESET_REG 0x70 // R/_ | ||
166 | |||
167 | #define ME6000_IRQ_STATUS_BIT_0 0x01 | ||
168 | #define ME6000_IRQ_STATUS_BIT_1 0x02 | ||
169 | #define ME6000_IRQ_STATUS_BIT_2 0x04 | ||
170 | #define ME6000_IRQ_STATUS_BIT_3 0x08 | ||
171 | |||
172 | #define ME6000_IRQ_STATUS_BIT_AO_HF ME6000_IRQ_STATUS_BIT_0 | ||
173 | |||
174 | //DUMY register | ||
175 | #define ME6000_AO_DUMY 0xFC | ||
176 | #endif | ||
177 | #endif | ||
diff --git a/drivers/staging/meilhaus/me6000_device.c b/drivers/staging/meilhaus/me6000_device.c new file mode 100644 index 000000000000..fee4c58b8464 --- /dev/null +++ b/drivers/staging/meilhaus/me6000_device.c | |||
@@ -0,0 +1,211 @@ | |||
1 | /** | ||
2 | * @file me6000_device.c | ||
3 | * | ||
4 | * @brief Device class template 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 "mefirmware.h" | ||
47 | |||
48 | #include "mesubdevice.h" | ||
49 | #include "medebug.h" | ||
50 | #include "medevice.h" | ||
51 | #include "me6000_reg.h" | ||
52 | #include "me6000_device.h" | ||
53 | #include "meplx_reg.h" | ||
54 | #include "me6000_dio.h" | ||
55 | #include "me6000_ao.h" | ||
56 | |||
57 | /** | ||
58 | * @brief Global variable. | ||
59 | * This is working queue for runing a separate atask that will be responsible for work status (start, stop, timeouts). | ||
60 | */ | ||
61 | static struct workqueue_struct *me6000_workqueue; | ||
62 | |||
63 | me_device_t *me6000_pci_constructor(struct pci_dev *pci_device) | ||
64 | { | ||
65 | me6000_device_t *me6000_device; | ||
66 | me_subdevice_t *subdevice; | ||
67 | unsigned int version_idx; | ||
68 | int err; | ||
69 | int i; | ||
70 | int high_range = 0; | ||
71 | int fifo; | ||
72 | |||
73 | PDEBUG("executed.\n"); | ||
74 | |||
75 | // Allocate structure for device instance. | ||
76 | me6000_device = kmalloc(sizeof(me6000_device_t), GFP_KERNEL); | ||
77 | |||
78 | if (!me6000_device) { | ||
79 | PERROR("Cannot get memory for device instance.\n"); | ||
80 | return NULL; | ||
81 | } | ||
82 | |||
83 | memset(me6000_device, 0, sizeof(me6000_device_t)); | ||
84 | |||
85 | // Initialize base class structure. | ||
86 | err = me_device_pci_init((me_device_t *) me6000_device, pci_device); | ||
87 | |||
88 | if (err) { | ||
89 | kfree(me6000_device); | ||
90 | PERROR("Cannot initialize device base class.\n"); | ||
91 | return NULL; | ||
92 | } | ||
93 | |||
94 | /* Download the xilinx firmware */ | ||
95 | err = me_xilinx_download(me6000_device->base.info.pci.reg_bases[1], | ||
96 | me6000_device->base.info.pci.reg_bases[2], | ||
97 | &pci_device->dev, "me6000.bin"); | ||
98 | |||
99 | if (err) { | ||
100 | me_device_deinit((me_device_t *) me6000_device); | ||
101 | kfree(me6000_device); | ||
102 | PERROR("Can't download firmware.\n"); | ||
103 | return NULL; | ||
104 | } | ||
105 | |||
106 | /* Get the index in the device version information table. */ | ||
107 | version_idx = | ||
108 | me6000_versions_get_device_index(me6000_device->base.info.pci. | ||
109 | device_id); | ||
110 | |||
111 | // Initialize spin lock . | ||
112 | spin_lock_init(&me6000_device->preload_reg_lock); | ||
113 | spin_lock_init(&me6000_device->dio_ctrl_reg_lock); | ||
114 | |||
115 | /* Create digital input/output instances. */ | ||
116 | for (i = 0; i < me6000_versions[version_idx].dio_subdevices; i++) { | ||
117 | subdevice = | ||
118 | (me_subdevice_t *) me6000_dio_constructor(me6000_device-> | ||
119 | base.info.pci. | ||
120 | reg_bases[3], i, | ||
121 | &me6000_device-> | ||
122 | dio_ctrl_reg_lock); | ||
123 | |||
124 | if (!subdevice) { | ||
125 | me_device_deinit((me_device_t *) me6000_device); | ||
126 | kfree(me6000_device); | ||
127 | PERROR("Cannot get memory for subdevice.\n"); | ||
128 | return NULL; | ||
129 | } | ||
130 | |||
131 | me_slist_add_subdevice_tail(&me6000_device->base.slist, | ||
132 | subdevice); | ||
133 | } | ||
134 | |||
135 | /* Create analog output instances. */ | ||
136 | for (i = 0; i < me6000_versions[version_idx].ao_subdevices; i++) { | ||
137 | high_range = ((i == 8) | ||
138 | && | ||
139 | ((me6000_device->base.info.pci.device_id == | ||
140 | PCI_DEVICE_ID_MEILHAUS_ME6359) | ||
141 | || (me6000_device->base.info.pci.device_id == | ||
142 | PCI_DEVICE_ID_MEILHAUS_ME6259) | ||
143 | ) | ||
144 | )? 1 : 0; | ||
145 | |||
146 | fifo = | ||
147 | (i < | ||
148 | me6000_versions[version_idx]. | ||
149 | ao_fifo) ? ME6000_AO_HAS_FIFO : 0x0; | ||
150 | fifo |= (i < 4) ? ME6000_AO_EXTRA_HARDWARE : 0x0; | ||
151 | |||
152 | subdevice = | ||
153 | (me_subdevice_t *) me6000_ao_constructor(me6000_device-> | ||
154 | base.info.pci. | ||
155 | reg_bases[2], | ||
156 | &me6000_device-> | ||
157 | preload_reg_lock, | ||
158 | &me6000_device-> | ||
159 | preload_flags, | ||
160 | &me6000_device-> | ||
161 | triggering_flags, | ||
162 | i, fifo, | ||
163 | me6000_device-> | ||
164 | base.irq, | ||
165 | high_range, | ||
166 | me6000_workqueue); | ||
167 | |||
168 | if (!subdevice) { | ||
169 | me_device_deinit((me_device_t *) me6000_device); | ||
170 | kfree(me6000_device); | ||
171 | PERROR("Cannot get memory for subdevice.\n"); | ||
172 | return NULL; | ||
173 | } | ||
174 | |||
175 | me_slist_add_subdevice_tail(&me6000_device->base.slist, | ||
176 | subdevice); | ||
177 | } | ||
178 | |||
179 | return (me_device_t *) me6000_device; | ||
180 | } | ||
181 | |||
182 | // Init and exit of module. | ||
183 | |||
184 | static int __init me6000_init(void) | ||
185 | { | ||
186 | PDEBUG("executed.\n"); | ||
187 | |||
188 | me6000_workqueue = create_singlethread_workqueue("me6000"); | ||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | static void __exit me6000_exit(void) | ||
193 | { | ||
194 | PDEBUG("executed.\n"); | ||
195 | |||
196 | flush_workqueue(me6000_workqueue); | ||
197 | destroy_workqueue(me6000_workqueue); | ||
198 | } | ||
199 | |||
200 | module_init(me6000_init); | ||
201 | module_exit(me6000_exit); | ||
202 | |||
203 | // Administrative stuff for modinfo. | ||
204 | MODULE_AUTHOR | ||
205 | ("Guenter Gebhardt <g.gebhardt@meilhaus.de> & Krzysztof Gantzke <k.gantzke@meilhaus.de>"); | ||
206 | MODULE_DESCRIPTION("Device Driver Module for ME-6000 Device"); | ||
207 | MODULE_SUPPORTED_DEVICE("Meilhaus ME-6000 Devices"); | ||
208 | MODULE_LICENSE("GPL"); | ||
209 | |||
210 | // Export the constructor. | ||
211 | EXPORT_SYMBOL(me6000_pci_constructor); | ||
diff --git a/drivers/staging/meilhaus/me6000_device.h b/drivers/staging/meilhaus/me6000_device.h new file mode 100644 index 000000000000..18cc7d1e14f1 --- /dev/null +++ b/drivers/staging/meilhaus/me6000_device.h | |||
@@ -0,0 +1,149 @@ | |||
1 | /** | ||
2 | * @file me6000_device.h | ||
3 | * | ||
4 | * @brief ME-6000 device class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME6000_DEVICE_H | ||
28 | #define _ME6000_DEVICE_H | ||
29 | |||
30 | #include <linux/pci.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | |||
33 | #include "medevice.h" | ||
34 | |||
35 | #ifdef __KERNEL__ | ||
36 | |||
37 | /** | ||
38 | * @brief Structure holding ME-6000 device capabilities. | ||
39 | */ | ||
40 | typedef struct me6000_version { | ||
41 | uint16_t device_id; | ||
42 | unsigned int dio_subdevices; | ||
43 | unsigned int ao_subdevices; | ||
44 | unsigned int ao_fifo; //How many devices have FIFO | ||
45 | } me6000_version_t; | ||
46 | |||
47 | /** | ||
48 | * @brief ME-6000 device capabilities. | ||
49 | */ | ||
50 | static me6000_version_t me6000_versions[] = { | ||
51 | {PCI_DEVICE_ID_MEILHAUS_ME6004, 0, 4, 0}, | ||
52 | {PCI_DEVICE_ID_MEILHAUS_ME6008, 0, 8, 0}, | ||
53 | {PCI_DEVICE_ID_MEILHAUS_ME600F, 0, 16, 0}, | ||
54 | |||
55 | {PCI_DEVICE_ID_MEILHAUS_ME6014, 0, 4, 0}, | ||
56 | {PCI_DEVICE_ID_MEILHAUS_ME6018, 0, 8, 0}, | ||
57 | {PCI_DEVICE_ID_MEILHAUS_ME601F, 0, 16, 0}, | ||
58 | |||
59 | {PCI_DEVICE_ID_MEILHAUS_ME6034, 0, 4, 0}, | ||
60 | {PCI_DEVICE_ID_MEILHAUS_ME6038, 0, 8, 0}, | ||
61 | {PCI_DEVICE_ID_MEILHAUS_ME603F, 0, 16, 0}, | ||
62 | |||
63 | {PCI_DEVICE_ID_MEILHAUS_ME6104, 0, 4, 4}, | ||
64 | {PCI_DEVICE_ID_MEILHAUS_ME6108, 0, 8, 4}, | ||
65 | {PCI_DEVICE_ID_MEILHAUS_ME610F, 0, 16, 4}, | ||
66 | |||
67 | {PCI_DEVICE_ID_MEILHAUS_ME6114, 0, 4, 4}, | ||
68 | {PCI_DEVICE_ID_MEILHAUS_ME6118, 0, 8, 4}, | ||
69 | {PCI_DEVICE_ID_MEILHAUS_ME611F, 0, 16, 4}, | ||
70 | |||
71 | {PCI_DEVICE_ID_MEILHAUS_ME6134, 0, 4, 4}, | ||
72 | {PCI_DEVICE_ID_MEILHAUS_ME6138, 0, 8, 4}, | ||
73 | {PCI_DEVICE_ID_MEILHAUS_ME613F, 0, 16, 4}, | ||
74 | |||
75 | {PCI_DEVICE_ID_MEILHAUS_ME6044, 2, 4, 0}, | ||
76 | {PCI_DEVICE_ID_MEILHAUS_ME6048, 2, 8, 0}, | ||
77 | {PCI_DEVICE_ID_MEILHAUS_ME604F, 2, 16, 0}, | ||
78 | |||
79 | {PCI_DEVICE_ID_MEILHAUS_ME6054, 2, 4, 0}, | ||
80 | {PCI_DEVICE_ID_MEILHAUS_ME6058, 2, 8, 0}, | ||
81 | {PCI_DEVICE_ID_MEILHAUS_ME605F, 2, 16, 0}, | ||
82 | |||
83 | {PCI_DEVICE_ID_MEILHAUS_ME6074, 2, 4, 0}, | ||
84 | {PCI_DEVICE_ID_MEILHAUS_ME6078, 2, 8, 0}, | ||
85 | {PCI_DEVICE_ID_MEILHAUS_ME607F, 2, 16, 0}, | ||
86 | |||
87 | {PCI_DEVICE_ID_MEILHAUS_ME6144, 2, 4, 4}, | ||
88 | {PCI_DEVICE_ID_MEILHAUS_ME6148, 2, 8, 4}, | ||
89 | {PCI_DEVICE_ID_MEILHAUS_ME614F, 2, 16, 4}, | ||
90 | |||
91 | {PCI_DEVICE_ID_MEILHAUS_ME6154, 2, 4, 4}, | ||
92 | {PCI_DEVICE_ID_MEILHAUS_ME6158, 2, 8, 4}, | ||
93 | {PCI_DEVICE_ID_MEILHAUS_ME615F, 2, 16, 4}, | ||
94 | |||
95 | {PCI_DEVICE_ID_MEILHAUS_ME6174, 2, 4, 4}, | ||
96 | {PCI_DEVICE_ID_MEILHAUS_ME6178, 2, 8, 4}, | ||
97 | {PCI_DEVICE_ID_MEILHAUS_ME617F, 2, 16, 4}, | ||
98 | |||
99 | {PCI_DEVICE_ID_MEILHAUS_ME6259, 2, 9, 0}, | ||
100 | |||
101 | {PCI_DEVICE_ID_MEILHAUS_ME6359, 2, 9, 4}, | ||
102 | |||
103 | {0}, | ||
104 | }; | ||
105 | |||
106 | #define ME6000_DEVICE_VERSIONS (sizeof(me6000_versions) / sizeof(me6000_version_t) - 1) /**< Returns the number of entries in #me6000_versions. */ | ||
107 | |||
108 | /** | ||
109 | * @brief Returns the index of the device entry in #me6000_versions. | ||
110 | * | ||
111 | * @param device_id The PCI device id of the device to query. | ||
112 | * @return The index of the device in #me6000_versions. | ||
113 | */ | ||
114 | static inline unsigned int me6000_versions_get_device_index(uint16_t device_id) | ||
115 | { | ||
116 | unsigned int i; | ||
117 | for (i = 0; i < ME6000_DEVICE_VERSIONS; i++) | ||
118 | if (me6000_versions[i].device_id == device_id) | ||
119 | break; | ||
120 | return i; | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * @brief The ME-6000 device class structure. | ||
125 | */ | ||
126 | typedef struct me6000_device { | ||
127 | me_device_t base; /**< The Meilhaus device base class. */ | ||
128 | |||
129 | /* Child class attributes. */ | ||
130 | spinlock_t preload_reg_lock; /**< Guards the preload register. */ | ||
131 | uint32_t preload_flags; | ||
132 | uint32_t triggering_flags; | ||
133 | |||
134 | spinlock_t dio_ctrl_reg_lock; | ||
135 | } me6000_device_t; | ||
136 | |||
137 | /** | ||
138 | * @brief The ME-6000 device class constructor. | ||
139 | * | ||
140 | * @param pci_device The pci device structure given by the PCI subsystem. | ||
141 | * | ||
142 | * @return On succes a new ME-6000 device instance. \n | ||
143 | * NULL on error. | ||
144 | */ | ||
145 | me_device_t *me6000_pci_constructor(struct pci_dev *pci_device) | ||
146 | __attribute__ ((weak)); | ||
147 | |||
148 | #endif | ||
149 | #endif | ||
diff --git a/drivers/staging/meilhaus/me6000_dio.c b/drivers/staging/meilhaus/me6000_dio.c new file mode 100644 index 000000000000..07f1069f9ac6 --- /dev/null +++ b/drivers/staging/meilhaus/me6000_dio.c | |||
@@ -0,0 +1,415 @@ | |||
1 | /** | ||
2 | * @file me6000_dio.c | ||
3 | * | ||
4 | * @brief ME-6000 digital input/output subdevice instance. | ||
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 | /* | ||
33 | * Includes | ||
34 | */ | ||
35 | #include <linux/module.h> | ||
36 | |||
37 | #include <linux/slab.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | #include <asm/io.h> | ||
40 | #include <linux/types.h> | ||
41 | |||
42 | #include "medefines.h" | ||
43 | #include "meinternal.h" | ||
44 | #include "meerror.h" | ||
45 | |||
46 | #include "medebug.h" | ||
47 | #include "me6000_dio_reg.h" | ||
48 | #include "me6000_dio.h" | ||
49 | |||
50 | /* | ||
51 | * Defines | ||
52 | */ | ||
53 | |||
54 | /* | ||
55 | * Functions | ||
56 | */ | ||
57 | |||
58 | static int me6000_dio_io_reset_subdevice(struct me_subdevice *subdevice, | ||
59 | struct file *filep, int flags) | ||
60 | { | ||
61 | me6000_dio_subdevice_t *instance; | ||
62 | uint8_t mode; | ||
63 | |||
64 | PDEBUG("executed.\n"); | ||
65 | |||
66 | instance = (me6000_dio_subdevice_t *) subdevice; | ||
67 | |||
68 | if (flags) { | ||
69 | PERROR("Invalid flag specified.\n"); | ||
70 | return ME_ERRNO_INVALID_FLAGS; | ||
71 | } | ||
72 | |||
73 | ME_SUBDEVICE_ENTER; | ||
74 | |||
75 | spin_lock(&instance->subdevice_lock); | ||
76 | spin_lock(instance->ctrl_reg_lock); | ||
77 | mode = inb(instance->ctrl_reg); | ||
78 | mode &= ~(0x3 << (instance->dio_idx * 2)); | ||
79 | outb(mode, instance->ctrl_reg); | ||
80 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
81 | instance->ctrl_reg - instance->reg_base, mode); | ||
82 | spin_unlock(instance->ctrl_reg_lock); | ||
83 | |||
84 | outb(0x00, instance->port_reg); | ||
85 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
86 | instance->ctrl_reg - instance->reg_base, 0x00); | ||
87 | spin_unlock(&instance->subdevice_lock); | ||
88 | |||
89 | ME_SUBDEVICE_EXIT; | ||
90 | |||
91 | return ME_ERRNO_SUCCESS; | ||
92 | } | ||
93 | |||
94 | static int me6000_dio_io_single_config(me_subdevice_t * subdevice, | ||
95 | struct file *filep, | ||
96 | int channel, | ||
97 | int single_config, | ||
98 | int ref, | ||
99 | int trig_chan, | ||
100 | int trig_type, int trig_edge, int flags) | ||
101 | { | ||
102 | me6000_dio_subdevice_t *instance; | ||
103 | int err = ME_ERRNO_SUCCESS; | ||
104 | uint8_t mode; | ||
105 | int size = | ||
106 | flags & (ME_IO_SINGLE_CONFIG_DIO_BIT | ME_IO_SINGLE_CONFIG_DIO_BYTE | ||
107 | | ME_IO_SINGLE_CONFIG_DIO_WORD | | ||
108 | ME_IO_SINGLE_CONFIG_DIO_DWORD); | ||
109 | |||
110 | PDEBUG("executed.\n"); | ||
111 | |||
112 | instance = (me6000_dio_subdevice_t *) subdevice; | ||
113 | |||
114 | ME_SUBDEVICE_ENTER spin_lock(&instance->subdevice_lock); | ||
115 | spin_lock(instance->ctrl_reg_lock); | ||
116 | mode = inb(instance->ctrl_reg); | ||
117 | switch (size) { | ||
118 | case ME_IO_SINGLE_CONFIG_NO_FLAGS: | ||
119 | case ME_IO_SINGLE_CONFIG_DIO_BYTE: | ||
120 | if (channel == 0) { | ||
121 | if (single_config == ME_SINGLE_CONFIG_DIO_INPUT) { | ||
122 | mode &= | ||
123 | ~((ME6000_DIO_CTRL_BIT_MODE_0 | | ||
124 | ME6000_DIO_CTRL_BIT_MODE_1) << | ||
125 | (instance->dio_idx * 2)); | ||
126 | } else if (single_config == ME_SINGLE_CONFIG_DIO_OUTPUT) { | ||
127 | mode &= | ||
128 | ~((ME6000_DIO_CTRL_BIT_MODE_0 | | ||
129 | ME6000_DIO_CTRL_BIT_MODE_1) << | ||
130 | (instance->dio_idx * 2)); | ||
131 | mode |= | ||
132 | ME6000_DIO_CTRL_BIT_MODE_0 << (instance-> | ||
133 | dio_idx * 2); | ||
134 | } else { | ||
135 | PERROR | ||
136 | ("Invalid port configuration specified.\n"); | ||
137 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
138 | } | ||
139 | } else { | ||
140 | PERROR("Invalid channel number.\n"); | ||
141 | err = ME_ERRNO_INVALID_CHANNEL; | ||
142 | } | ||
143 | break; | ||
144 | |||
145 | default: | ||
146 | PERROR("Invalid flags.\n"); | ||
147 | err = ME_ERRNO_INVALID_FLAGS; | ||
148 | } | ||
149 | |||
150 | if (!err) { | ||
151 | outb(mode, instance->ctrl_reg); | ||
152 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
153 | instance->reg_base, | ||
154 | instance->ctrl_reg - instance->reg_base, mode); | ||
155 | } | ||
156 | spin_unlock(instance->ctrl_reg_lock); | ||
157 | spin_unlock(&instance->subdevice_lock); | ||
158 | |||
159 | ME_SUBDEVICE_EXIT; | ||
160 | |||
161 | return err; | ||
162 | } | ||
163 | |||
164 | static int me6000_dio_io_single_read(me_subdevice_t * subdevice, | ||
165 | struct file *filep, | ||
166 | int channel, | ||
167 | int *value, int time_out, int flags) | ||
168 | { | ||
169 | me6000_dio_subdevice_t *instance; | ||
170 | int err = ME_ERRNO_SUCCESS; | ||
171 | uint8_t mode; | ||
172 | |||
173 | PDEBUG("executed.\n"); | ||
174 | |||
175 | instance = (me6000_dio_subdevice_t *) subdevice; | ||
176 | |||
177 | ME_SUBDEVICE_ENTER spin_lock(&instance->subdevice_lock); | ||
178 | spin_lock(instance->ctrl_reg_lock); | ||
179 | switch (flags) { | ||
180 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
181 | if ((channel >= 0) && (channel < 8)) { | ||
182 | mode = | ||
183 | inb(instance-> | ||
184 | ctrl_reg) & ((ME6000_DIO_CTRL_BIT_MODE_0 | | ||
185 | ME6000_DIO_CTRL_BIT_MODE_1) << | ||
186 | (instance->dio_idx * 2)); | ||
187 | if ((mode == | ||
188 | (ME6000_DIO_CTRL_BIT_MODE_0 << | ||
189 | (instance->dio_idx * 2))) || !mode) { | ||
190 | *value = | ||
191 | inb(instance->port_reg) & (0x1 << channel); | ||
192 | } else { | ||
193 | PERROR("Port not in output or input mode.\n"); | ||
194 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
195 | } | ||
196 | } else { | ||
197 | PERROR("Invalid bit number specified.\n"); | ||
198 | err = ME_ERRNO_INVALID_CHANNEL; | ||
199 | } | ||
200 | break; | ||
201 | |||
202 | case ME_IO_SINGLE_NO_FLAGS: | ||
203 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
204 | if (channel == 0) { | ||
205 | mode = | ||
206 | inb(instance-> | ||
207 | ctrl_reg) & ((ME6000_DIO_CTRL_BIT_MODE_0 | | ||
208 | ME6000_DIO_CTRL_BIT_MODE_1) << | ||
209 | (instance->dio_idx * 2)); | ||
210 | if ((mode == | ||
211 | (ME6000_DIO_CTRL_BIT_MODE_0 << | ||
212 | (instance->dio_idx * 2))) || !mode) { | ||
213 | *value = inb(instance->port_reg) & 0x00FF; | ||
214 | } else { | ||
215 | PERROR("Port not in output or input mode.\n"); | ||
216 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
217 | } | ||
218 | } else { | ||
219 | PERROR("Invalid byte number specified.\n"); | ||
220 | err = ME_ERRNO_INVALID_CHANNEL; | ||
221 | } | ||
222 | break; | ||
223 | |||
224 | default: | ||
225 | PERROR("Invalid flags specified.\n"); | ||
226 | err = ME_ERRNO_INVALID_FLAGS; | ||
227 | } | ||
228 | spin_unlock(instance->ctrl_reg_lock); | ||
229 | spin_unlock(&instance->subdevice_lock); | ||
230 | |||
231 | ME_SUBDEVICE_EXIT; | ||
232 | |||
233 | return err; | ||
234 | } | ||
235 | |||
236 | static int me6000_dio_io_single_write(me_subdevice_t * subdevice, | ||
237 | struct file *filep, | ||
238 | int channel, | ||
239 | int value, int time_out, int flags) | ||
240 | { | ||
241 | me6000_dio_subdevice_t *instance; | ||
242 | int err = ME_ERRNO_SUCCESS; | ||
243 | uint8_t mode; | ||
244 | uint8_t byte; | ||
245 | |||
246 | PDEBUG("executed.\n"); | ||
247 | |||
248 | instance = (me6000_dio_subdevice_t *) subdevice; | ||
249 | |||
250 | ME_SUBDEVICE_ENTER spin_lock(&instance->subdevice_lock); | ||
251 | spin_lock(instance->ctrl_reg_lock); | ||
252 | switch (flags) { | ||
253 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
254 | if ((channel >= 0) && (channel < 8)) { | ||
255 | mode = | ||
256 | inb(instance-> | ||
257 | ctrl_reg) & ((ME6000_DIO_CTRL_BIT_MODE_0 | | ||
258 | ME6000_DIO_CTRL_BIT_MODE_1) << | ||
259 | (instance->dio_idx * 2)); | ||
260 | |||
261 | if (mode == | ||
262 | (ME6000_DIO_CTRL_BIT_MODE_0 << | ||
263 | (instance->dio_idx * 2))) { | ||
264 | byte = inb(instance->port_reg) & 0x00FF; | ||
265 | |||
266 | if (value) | ||
267 | byte |= 0x1 << channel; | ||
268 | else | ||
269 | byte &= ~(0x1 << channel); | ||
270 | |||
271 | outb(byte, instance->port_reg); | ||
272 | } else { | ||
273 | PERROR("Port not in output or input mode.\n"); | ||
274 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
275 | } | ||
276 | } else { | ||
277 | PERROR("Invalid bit number specified.\n"); | ||
278 | err = ME_ERRNO_INVALID_CHANNEL; | ||
279 | } | ||
280 | break; | ||
281 | |||
282 | case ME_IO_SINGLE_NO_FLAGS: | ||
283 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
284 | if (channel == 0) { | ||
285 | mode = | ||
286 | inb(instance-> | ||
287 | ctrl_reg) & ((ME6000_DIO_CTRL_BIT_MODE_0 | | ||
288 | ME6000_DIO_CTRL_BIT_MODE_1) << | ||
289 | (instance->dio_idx * 2)); | ||
290 | |||
291 | if (mode == | ||
292 | (ME6000_DIO_CTRL_BIT_MODE_0 << | ||
293 | (instance->dio_idx * 2))) { | ||
294 | outb(value, instance->port_reg); | ||
295 | } else { | ||
296 | PERROR("Port not in output or input mode.\n"); | ||
297 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
298 | } | ||
299 | } else { | ||
300 | PERROR("Invalid byte number specified.\n"); | ||
301 | err = ME_ERRNO_INVALID_CHANNEL; | ||
302 | } | ||
303 | break; | ||
304 | |||
305 | default: | ||
306 | PERROR("Invalid flags specified.\n"); | ||
307 | err = ME_ERRNO_INVALID_FLAGS; | ||
308 | } | ||
309 | spin_unlock(instance->ctrl_reg_lock); | ||
310 | spin_unlock(&instance->subdevice_lock); | ||
311 | |||
312 | ME_SUBDEVICE_EXIT; | ||
313 | |||
314 | return err; | ||
315 | } | ||
316 | |||
317 | static int me6000_dio_query_number_channels(me_subdevice_t * subdevice, | ||
318 | int *number) | ||
319 | { | ||
320 | PDEBUG("executed.\n"); | ||
321 | *number = 8; | ||
322 | return ME_ERRNO_SUCCESS; | ||
323 | } | ||
324 | |||
325 | static int me6000_dio_query_subdevice_type(me_subdevice_t * subdevice, | ||
326 | int *type, int *subtype) | ||
327 | { | ||
328 | PDEBUG("executed.\n"); | ||
329 | *type = ME_TYPE_DIO; | ||
330 | *subtype = ME_SUBTYPE_SINGLE; | ||
331 | return ME_ERRNO_SUCCESS; | ||
332 | } | ||
333 | |||
334 | static int me6000_dio_query_subdevice_caps(me_subdevice_t * subdevice, | ||
335 | int *caps) | ||
336 | { | ||
337 | PDEBUG("executed.\n"); | ||
338 | *caps = ME_CAPS_DIO_DIR_BYTE; | ||
339 | return ME_ERRNO_SUCCESS; | ||
340 | } | ||
341 | |||
342 | me6000_dio_subdevice_t *me6000_dio_constructor(uint32_t reg_base, | ||
343 | unsigned int dio_idx, | ||
344 | spinlock_t * ctrl_reg_lock) | ||
345 | { | ||
346 | me6000_dio_subdevice_t *subdevice; | ||
347 | int err; | ||
348 | |||
349 | PDEBUG("executed.\n"); | ||
350 | |||
351 | /* Allocate memory for subdevice instance */ | ||
352 | subdevice = kmalloc(sizeof(me6000_dio_subdevice_t), GFP_KERNEL); | ||
353 | |||
354 | if (!subdevice) { | ||
355 | PERROR("Cannot get memory for subdevice instance.\n"); | ||
356 | return NULL; | ||
357 | } | ||
358 | |||
359 | memset(subdevice, 0, sizeof(me6000_dio_subdevice_t)); | ||
360 | |||
361 | /* Initialize subdevice base class */ | ||
362 | err = me_subdevice_init(&subdevice->base); | ||
363 | if (err) { | ||
364 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
365 | kfree(subdevice); | ||
366 | return NULL; | ||
367 | } | ||
368 | |||
369 | /* Set the subdevice ports */ | ||
370 | subdevice->ctrl_reg = reg_base + ME6000_DIO_CTRL_REG; | ||
371 | switch (dio_idx) { | ||
372 | case 0: | ||
373 | subdevice->port_reg = reg_base + ME6000_DIO_PORT_0_REG; | ||
374 | break; | ||
375 | case 1: | ||
376 | subdevice->port_reg = reg_base + ME6000_DIO_PORT_1_REG; | ||
377 | break; | ||
378 | default: | ||
379 | err = ME_ERRNO_INVALID_SUBDEVICE; | ||
380 | } | ||
381 | |||
382 | if (err) { | ||
383 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
384 | kfree(subdevice); | ||
385 | return NULL; | ||
386 | } | ||
387 | // Initialize spin locks. | ||
388 | spin_lock_init(&subdevice->subdevice_lock); | ||
389 | |||
390 | subdevice->ctrl_reg_lock = ctrl_reg_lock; | ||
391 | |||
392 | /* Save digital i/o index */ | ||
393 | subdevice->dio_idx = dio_idx; | ||
394 | |||
395 | #ifdef MEDEBUG_DEBUG_REG | ||
396 | subdevice->reg_base = reg_base; | ||
397 | #endif | ||
398 | |||
399 | /* Overload base class methods. */ | ||
400 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
401 | me6000_dio_io_reset_subdevice; | ||
402 | subdevice->base.me_subdevice_io_single_config = | ||
403 | me6000_dio_io_single_config; | ||
404 | subdevice->base.me_subdevice_io_single_read = me6000_dio_io_single_read; | ||
405 | subdevice->base.me_subdevice_io_single_write = | ||
406 | me6000_dio_io_single_write; | ||
407 | subdevice->base.me_subdevice_query_number_channels = | ||
408 | me6000_dio_query_number_channels; | ||
409 | subdevice->base.me_subdevice_query_subdevice_type = | ||
410 | me6000_dio_query_subdevice_type; | ||
411 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
412 | me6000_dio_query_subdevice_caps; | ||
413 | |||
414 | return subdevice; | ||
415 | } | ||
diff --git a/drivers/staging/meilhaus/me6000_dio.h b/drivers/staging/meilhaus/me6000_dio.h new file mode 100644 index 000000000000..858bec1c4596 --- /dev/null +++ b/drivers/staging/meilhaus/me6000_dio.h | |||
@@ -0,0 +1,68 @@ | |||
1 | /** | ||
2 | * @file me6000_dio.h | ||
3 | * | ||
4 | * @brief ME-6000 digital input/output subdevice class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME6000_DIO_H_ | ||
28 | #define _ME6000_DIO_H_ | ||
29 | |||
30 | #include "mesubdevice.h" | ||
31 | |||
32 | #ifdef __KERNEL__ | ||
33 | |||
34 | /** | ||
35 | * @brief The template subdevice class. | ||
36 | */ | ||
37 | typedef struct me6000_dio_subdevice { | ||
38 | /* Inheritance */ | ||
39 | me_subdevice_t base; /**< The subdevice base class. */ | ||
40 | |||
41 | /* Attributes */ | ||
42 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
43 | spinlock_t *ctrl_reg_lock; /**< Spin lock to protect #ctrl_reg from concurrent access. */ | ||
44 | unsigned int dio_idx; /**< The index of the digital i/o on the device. */ | ||
45 | |||
46 | unsigned long port_reg; /**< Register holding the port status. */ | ||
47 | unsigned long ctrl_reg; /**< Register to configure the port direction. */ | ||
48 | #ifdef MEDEBUG_DEBUG_REG | ||
49 | unsigned long reg_base; | ||
50 | #endif | ||
51 | } me6000_dio_subdevice_t; | ||
52 | |||
53 | /** | ||
54 | * @brief The constructor to generate a ME-6000 digital input/ouput subdevice instance. | ||
55 | * | ||
56 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
57 | * @param dio_idx The index of the digital i/o port on the device. | ||
58 | * @param ctrl_reg_lock Spin lock protecting the control register. | ||
59 | * | ||
60 | * @return Pointer to new instance on success.\n | ||
61 | * NULL on error. | ||
62 | */ | ||
63 | me6000_dio_subdevice_t *me6000_dio_constructor(uint32_t reg_base, | ||
64 | unsigned int dio_idx, | ||
65 | spinlock_t * ctrl_reg_lock); | ||
66 | |||
67 | #endif | ||
68 | #endif | ||
diff --git a/drivers/staging/meilhaus/me6000_dio_reg.h b/drivers/staging/meilhaus/me6000_dio_reg.h new file mode 100644 index 000000000000..e67a791a1e69 --- /dev/null +++ b/drivers/staging/meilhaus/me6000_dio_reg.h | |||
@@ -0,0 +1,43 @@ | |||
1 | /** | ||
2 | * @file me6000_dio_reg.h | ||
3 | * | ||
4 | * @brief ME-6000 digital input/output subdevice register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME6000_DIO_REG_H_ | ||
28 | #define _ME6000_DIO_REG_H_ | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | #define ME6000_DIO_CTRL_REG 0x00 // R/W | ||
33 | #define ME6000_DIO_PORT_0_REG 0x01 // R/W | ||
34 | #define ME6000_DIO_PORT_1_REG 0x02 // R/W | ||
35 | #define ME6000_DIO_PORT_REG ME6000_DIO_PORT_0_REG // R/W | ||
36 | |||
37 | #define ME6000_DIO_CTRL_BIT_MODE_0 0x01 | ||
38 | #define ME6000_DIO_CTRL_BIT_MODE_1 0x02 | ||
39 | #define ME6000_DIO_CTRL_BIT_MODE_2 0x04 | ||
40 | #define ME6000_DIO_CTRL_BIT_MODE_3 0x08 | ||
41 | |||
42 | #endif | ||
43 | #endif | ||
diff --git a/drivers/staging/meilhaus/me6000_reg.h b/drivers/staging/meilhaus/me6000_reg.h new file mode 100644 index 000000000000..d35273003415 --- /dev/null +++ b/drivers/staging/meilhaus/me6000_reg.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /** | ||
2 | * @file me6000_reg.h | ||
3 | * | ||
4 | * @brief ME-6000 device register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME6000_REG_H_ | ||
28 | #define _ME6000_REG_H_ | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | #define ME6000_INIT_XILINX_REG 0xAC // R/- | ||
33 | |||
34 | #endif | ||
35 | #endif | ||
diff --git a/drivers/staging/meilhaus/me8100_device.c b/drivers/staging/meilhaus/me8100_device.c new file mode 100644 index 000000000000..1fb79e490261 --- /dev/null +++ b/drivers/staging/meilhaus/me8100_device.c | |||
@@ -0,0 +1,187 @@ | |||
1 | /** | ||
2 | * @file me8100_device.c | ||
3 | * | ||
4 | * @brief ME-8100 device class implementation. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef __KERNEL__ | ||
28 | # define __KERNEL__ | ||
29 | #endif | ||
30 | |||
31 | #ifndef MODULE | ||
32 | # define MODULE | ||
33 | #endif | ||
34 | |||
35 | #include <linux/module.h> | ||
36 | |||
37 | #include <linux/pci.h> | ||
38 | #include <linux/slab.h> | ||
39 | |||
40 | #include "meids.h" | ||
41 | #include "meerror.h" | ||
42 | #include "mecommon.h" | ||
43 | #include "meinternal.h" | ||
44 | |||
45 | #include "medebug.h" | ||
46 | #include "medevice.h" | ||
47 | #include "me8100_device.h" | ||
48 | #include "mesubdevice.h" | ||
49 | #include "me8100_di.h" | ||
50 | #include "me8100_do.h" | ||
51 | #include "me8254.h" | ||
52 | |||
53 | me_device_t *me8100_pci_constructor(struct pci_dev *pci_device) | ||
54 | { | ||
55 | me8100_device_t *me8100_device; | ||
56 | me_subdevice_t *subdevice; | ||
57 | unsigned int version_idx; | ||
58 | int err; | ||
59 | int i; | ||
60 | |||
61 | PDEBUG("executed.\n"); | ||
62 | |||
63 | // Allocate structure for device instance. | ||
64 | me8100_device = kmalloc(sizeof(me8100_device_t), GFP_KERNEL); | ||
65 | |||
66 | if (!me8100_device) { | ||
67 | PERROR("Cannot get memory for device instance.\n"); | ||
68 | return NULL; | ||
69 | } | ||
70 | |||
71 | memset(me8100_device, 0, sizeof(me8100_device_t)); | ||
72 | |||
73 | // Initialize base class structure. | ||
74 | err = me_device_pci_init((me_device_t *) me8100_device, pci_device); | ||
75 | |||
76 | if (err) { | ||
77 | kfree(me8100_device); | ||
78 | PERROR("Cannot initialize device base class.\n"); | ||
79 | return NULL; | ||
80 | } | ||
81 | |||
82 | /* Get the index in the device version information table. */ | ||
83 | version_idx = | ||
84 | me8100_versions_get_device_index(me8100_device->base.info.pci. | ||
85 | device_id); | ||
86 | |||
87 | // Initialize spin lock . | ||
88 | spin_lock_init(&me8100_device->dio_ctrl_reg_lock); | ||
89 | spin_lock_init(&me8100_device->ctr_ctrl_reg_lock); | ||
90 | spin_lock_init(&me8100_device->clk_src_reg_lock); | ||
91 | |||
92 | // Create subdevice instances. | ||
93 | |||
94 | for (i = 0; i < me8100_versions[version_idx].di_subdevices; i++) { | ||
95 | subdevice = | ||
96 | (me_subdevice_t *) me8100_di_constructor(me8100_device-> | ||
97 | base.info.pci. | ||
98 | reg_bases[2], | ||
99 | me8100_device-> | ||
100 | base.info.pci. | ||
101 | reg_bases[1], i, | ||
102 | me8100_device-> | ||
103 | base.irq, | ||
104 | &me8100_device-> | ||
105 | dio_ctrl_reg_lock); | ||
106 | |||
107 | if (!subdevice) { | ||
108 | me_device_deinit((me_device_t *) me8100_device); | ||
109 | kfree(me8100_device); | ||
110 | PERROR("Cannot get memory for subdevice.\n"); | ||
111 | return NULL; | ||
112 | } | ||
113 | |||
114 | me_slist_add_subdevice_tail(&me8100_device->base.slist, | ||
115 | subdevice); | ||
116 | } | ||
117 | |||
118 | for (i = 0; i < me8100_versions[version_idx].do_subdevices; i++) { | ||
119 | subdevice = | ||
120 | (me_subdevice_t *) me8100_do_constructor(me8100_device-> | ||
121 | base.info.pci. | ||
122 | reg_bases[2], i, | ||
123 | &me8100_device-> | ||
124 | dio_ctrl_reg_lock); | ||
125 | |||
126 | if (!subdevice) { | ||
127 | me_device_deinit((me_device_t *) me8100_device); | ||
128 | kfree(me8100_device); | ||
129 | PERROR("Cannot get memory for subdevice.\n"); | ||
130 | return NULL; | ||
131 | } | ||
132 | |||
133 | me_slist_add_subdevice_tail(&me8100_device->base.slist, | ||
134 | subdevice); | ||
135 | } | ||
136 | |||
137 | for (i = 0; i < me8100_versions[version_idx].ctr_subdevices; i++) { | ||
138 | subdevice = | ||
139 | (me_subdevice_t *) me8254_constructor(me8100_device->base. | ||
140 | info.pci.device_id, | ||
141 | me8100_device->base. | ||
142 | info.pci.reg_bases[2], | ||
143 | 0, i, | ||
144 | &me8100_device-> | ||
145 | ctr_ctrl_reg_lock, | ||
146 | &me8100_device-> | ||
147 | clk_src_reg_lock); | ||
148 | |||
149 | if (!subdevice) { | ||
150 | me_device_deinit((me_device_t *) me8100_device); | ||
151 | kfree(me8100_device); | ||
152 | PERROR("Cannot get memory for subdevice.\n"); | ||
153 | return NULL; | ||
154 | } | ||
155 | |||
156 | me_slist_add_subdevice_tail(&me8100_device->base.slist, | ||
157 | subdevice); | ||
158 | } | ||
159 | |||
160 | return (me_device_t *) me8100_device; | ||
161 | } | ||
162 | |||
163 | // Init and exit of module. | ||
164 | |||
165 | static int __init me8100_init(void) | ||
166 | { | ||
167 | PDEBUG("executed.\n."); | ||
168 | return ME_ERRNO_SUCCESS; | ||
169 | } | ||
170 | |||
171 | static void __exit me8100_exit(void) | ||
172 | { | ||
173 | PDEBUG("executed.\n."); | ||
174 | } | ||
175 | |||
176 | module_init(me8100_init); | ||
177 | |||
178 | module_exit(me8100_exit); | ||
179 | |||
180 | // Administrative stuff for modinfo. | ||
181 | MODULE_AUTHOR("Guenter Gebhardt <g.gebhardt@meilhaus.de>"); | ||
182 | MODULE_DESCRIPTION("Device Driver Module for Template Device"); | ||
183 | MODULE_SUPPORTED_DEVICE("Meilhaus Template Devices"); | ||
184 | MODULE_LICENSE("GPL"); | ||
185 | |||
186 | // Export the constructor. | ||
187 | EXPORT_SYMBOL(me8100_pci_constructor); | ||
diff --git a/drivers/staging/meilhaus/me8100_device.h b/drivers/staging/meilhaus/me8100_device.h new file mode 100644 index 000000000000..44c42efb04e2 --- /dev/null +++ b/drivers/staging/meilhaus/me8100_device.h | |||
@@ -0,0 +1,97 @@ | |||
1 | /** | ||
2 | * @file me8100_device.h | ||
3 | * | ||
4 | * @brief ME-8100 device class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME8100_DEVICE_H | ||
28 | #define _ME8100_DEVICE_H | ||
29 | |||
30 | #include <linux/pci.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | |||
33 | #include "medevice.h" | ||
34 | |||
35 | #ifdef __KERNEL__ | ||
36 | |||
37 | /** | ||
38 | * @brief Structure holding ME-8100 device capabilities. | ||
39 | */ | ||
40 | typedef struct me8100_version { | ||
41 | uint16_t device_id; | ||
42 | unsigned int di_subdevices; | ||
43 | unsigned int do_subdevices; | ||
44 | unsigned int ctr_subdevices; | ||
45 | } me8100_version_t; | ||
46 | |||
47 | /** | ||
48 | * @brief Device capabilities. | ||
49 | */ | ||
50 | static me8100_version_t me8100_versions[] = { | ||
51 | {PCI_DEVICE_ID_MEILHAUS_ME8100_A, 1, 1, 3}, | ||
52 | {PCI_DEVICE_ID_MEILHAUS_ME8100_B, 2, 2, 3}, | ||
53 | {0}, | ||
54 | }; | ||
55 | |||
56 | #define ME8100_DEVICE_VERSIONS (sizeof(me8100_versions) / sizeof(me8100_version_t) - 1) /**< Returns the number of entries in #me8100_versions. */ | ||
57 | |||
58 | /** | ||
59 | * @brief Returns the index of the device entry in #me8100_versions. | ||
60 | * | ||
61 | * @param device_id The PCI device id of the device to query. | ||
62 | * @return The index of the device in #me8100_versions. | ||
63 | */ | ||
64 | static inline unsigned int me8100_versions_get_device_index(uint16_t device_id) | ||
65 | { | ||
66 | unsigned int i; | ||
67 | for (i = 0; i < ME8100_DEVICE_VERSIONS; i++) | ||
68 | if (me8100_versions[i].device_id == device_id) | ||
69 | break; | ||
70 | return i; | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * @brief The ME-8100 device class structure. | ||
75 | */ | ||
76 | typedef struct me8100_device { | ||
77 | me_device_t base; /**< The Meilhaus device base class. */ | ||
78 | |||
79 | /* Child class attributes. */ | ||
80 | spinlock_t dio_ctrl_reg_lock; | ||
81 | spinlock_t ctr_ctrl_reg_lock; | ||
82 | spinlock_t clk_src_reg_lock; | ||
83 | } me8100_device_t; | ||
84 | |||
85 | /** | ||
86 | * @brief The ME-8100 device class constructor. | ||
87 | * | ||
88 | * @param pci_device The pci device structure given by the PCI subsystem. | ||
89 | * | ||
90 | * @return On succes a new ME-8100 device instance. \n | ||
91 | * NULL on error. | ||
92 | */ | ||
93 | me_device_t *me8100_pci_constructor(struct pci_dev *pci_device) | ||
94 | __attribute__ ((weak)); | ||
95 | |||
96 | #endif | ||
97 | #endif | ||
diff --git a/drivers/staging/meilhaus/me8100_di.c b/drivers/staging/meilhaus/me8100_di.c new file mode 100644 index 000000000000..0f146371b9a0 --- /dev/null +++ b/drivers/staging/meilhaus/me8100_di.c | |||
@@ -0,0 +1,693 @@ | |||
1 | /** | ||
2 | * @file me8100_di.c | ||
3 | * | ||
4 | * @brief ME-8100 digital input subdevice instance. | ||
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 | /* | ||
33 | * Includes | ||
34 | */ | ||
35 | #include <linux/module.h> | ||
36 | |||
37 | #include <linux/slab.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | #include <asm/io.h> | ||
40 | #include <linux/types.h> | ||
41 | #include <linux/interrupt.h> | ||
42 | #include <linux/version.h> | ||
43 | |||
44 | #include "medefines.h" | ||
45 | #include "meerror.h" | ||
46 | |||
47 | #include "meids.h" | ||
48 | #include "medebug.h" | ||
49 | #include "meplx_reg.h" | ||
50 | #include "me8100_reg.h" | ||
51 | #include "me8100_di_reg.h" | ||
52 | #include "me8100_di.h" | ||
53 | |||
54 | /* | ||
55 | * Defines | ||
56 | */ | ||
57 | |||
58 | /* | ||
59 | * Functions | ||
60 | */ | ||
61 | |||
62 | static int me8100_di_io_reset_subdevice(struct me_subdevice *subdevice, | ||
63 | struct file *filep, int flags) | ||
64 | { | ||
65 | me8100_di_subdevice_t *instance; | ||
66 | unsigned short ctrl; | ||
67 | unsigned long cpu_flags; | ||
68 | |||
69 | PDEBUG("executed.\n"); | ||
70 | |||
71 | instance = (me8100_di_subdevice_t *) subdevice; | ||
72 | |||
73 | if (flags) { | ||
74 | PERROR("Invalid flag specified.\n"); | ||
75 | return ME_ERRNO_INVALID_FLAGS; | ||
76 | } | ||
77 | |||
78 | ME_SUBDEVICE_ENTER; | ||
79 | |||
80 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
81 | spin_lock(instance->ctrl_reg_lock); | ||
82 | ctrl = inw(instance->ctrl_reg); | ||
83 | ctrl &= ~(ME8100_DIO_CTRL_BIT_INTB_1 | ME8100_DIO_CTRL_BIT_INTB_0); | ||
84 | outw(ctrl, instance->ctrl_reg); | ||
85 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
86 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
87 | spin_unlock(instance->ctrl_reg_lock); | ||
88 | |||
89 | outw(0, instance->mask_reg); | ||
90 | PDEBUG_REG("mask_reg outw(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
91 | instance->mask_reg - instance->reg_base, 0); | ||
92 | outw(0, instance->pattern_reg); | ||
93 | PDEBUG_REG("pattern_reg outw(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
94 | instance->pattern_reg - instance->reg_base, 0); | ||
95 | instance->rised = -1; | ||
96 | instance->irq_count = 0; | ||
97 | instance->filtering_flag = 0; | ||
98 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
99 | |||
100 | outl(PLX_INTCSR_LOCAL_INT1_EN | | ||
101 | PLX_INTCSR_LOCAL_INT1_POL | | ||
102 | PLX_INTCSR_LOCAL_INT2_EN | | ||
103 | PLX_INTCSR_LOCAL_INT2_POL | | ||
104 | PLX_INTCSR_PCI_INT_EN, instance->irq_status_reg); | ||
105 | PDEBUG_REG("plx:irq_status_reg outl(0x%lX)=0x%x\n", | ||
106 | instance->irq_status_reg, | ||
107 | PLX_INTCSR_LOCAL_INT1_EN | PLX_INTCSR_LOCAL_INT1_POL | | ||
108 | PLX_INTCSR_LOCAL_INT2_EN | PLX_INTCSR_LOCAL_INT2_POL | | ||
109 | PLX_INTCSR_PCI_INT_EN); | ||
110 | |||
111 | wake_up_interruptible_all(&instance->wait_queue); | ||
112 | ME_SUBDEVICE_EXIT; | ||
113 | |||
114 | return ME_ERRNO_SUCCESS; | ||
115 | } | ||
116 | |||
117 | static int me8100_di_io_irq_start(me_subdevice_t * subdevice, | ||
118 | struct file *filep, | ||
119 | int channel, | ||
120 | int irq_source, | ||
121 | int irq_edge, int irq_arg, int flags) | ||
122 | { | ||
123 | me8100_di_subdevice_t *instance; | ||
124 | int err = ME_ERRNO_SUCCESS; | ||
125 | uint16_t ctrl; | ||
126 | unsigned long cpu_flags; | ||
127 | |||
128 | PDEBUG("executed.\n"); | ||
129 | |||
130 | instance = (me8100_di_subdevice_t *) subdevice; | ||
131 | |||
132 | if (irq_source == ME_IRQ_SOURCE_DIO_PATTERN) { | ||
133 | if (flags & | ||
134 | ~(ME_IO_IRQ_START_PATTERN_FILTERING | | ||
135 | ME_IO_IRQ_START_DIO_WORD)) { | ||
136 | PERROR("Invalid flag specified.\n"); | ||
137 | return ME_ERRNO_INVALID_FLAGS; | ||
138 | } | ||
139 | |||
140 | if (irq_edge != ME_IRQ_EDGE_NOT_USED) { | ||
141 | PERROR("Invalid irq edge specified.\n"); | ||
142 | return ME_ERRNO_INVALID_IRQ_EDGE; | ||
143 | } | ||
144 | } else if (irq_source == ME_IRQ_SOURCE_DIO_MASK) { | ||
145 | if (flags & | ||
146 | ~(ME_IO_IRQ_START_EXTENDED_STATUS | | ||
147 | ME_IO_IRQ_START_DIO_WORD)) { | ||
148 | PERROR("Invalid flag specified.\n"); | ||
149 | return ME_ERRNO_INVALID_FLAGS; | ||
150 | } | ||
151 | |||
152 | if (irq_edge != ME_IRQ_EDGE_ANY) { | ||
153 | PERROR("Invalid irq edge specified.\n"); | ||
154 | return ME_ERRNO_INVALID_IRQ_EDGE; | ||
155 | } | ||
156 | |||
157 | if (!(irq_arg & 0xFFFF)) { | ||
158 | PERROR("No mask specified.\n"); | ||
159 | return ME_ERRNO_INVALID_IRQ_ARG; | ||
160 | } | ||
161 | } else { | ||
162 | PERROR("Invalid irq source specified.\n"); | ||
163 | return ME_ERRNO_INVALID_IRQ_SOURCE; | ||
164 | } | ||
165 | |||
166 | if (channel) { | ||
167 | PERROR("Invalid channel specified.\n"); | ||
168 | return ME_ERRNO_INVALID_CHANNEL; | ||
169 | } | ||
170 | |||
171 | ME_SUBDEVICE_ENTER; | ||
172 | |||
173 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
174 | if (irq_source == ME_IRQ_SOURCE_DIO_PATTERN) { | ||
175 | outw(irq_arg, instance->pattern_reg); | ||
176 | instance->compare_value = irq_arg; | ||
177 | instance->filtering_flag = | ||
178 | (flags & ME_IO_IRQ_START_PATTERN_FILTERING) ? 1 : 0; | ||
179 | } | ||
180 | if (irq_source == ME_IRQ_SOURCE_DIO_MASK) { | ||
181 | outw(irq_arg, instance->mask_reg); | ||
182 | } | ||
183 | |||
184 | spin_lock(instance->ctrl_reg_lock); | ||
185 | ctrl = inw(instance->ctrl_reg); | ||
186 | ctrl |= ME8100_DIO_CTRL_BIT_INTB_0; | ||
187 | if (irq_source == ME_IRQ_SOURCE_DIO_PATTERN) { | ||
188 | ctrl &= ~ME8100_DIO_CTRL_BIT_INTB_1; | ||
189 | } | ||
190 | |||
191 | if (irq_source == ME_IRQ_SOURCE_DIO_MASK) { | ||
192 | ctrl |= ME8100_DIO_CTRL_BIT_INTB_1; | ||
193 | } | ||
194 | outw(ctrl, instance->ctrl_reg); | ||
195 | PDEBUG_REG("ctrl_reg outw(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
196 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
197 | spin_unlock(instance->ctrl_reg_lock); | ||
198 | |||
199 | instance->rised = 0; | ||
200 | instance->status_value = 0; | ||
201 | instance->status_value_edges = 0; | ||
202 | instance->line_value = inw(instance->port_reg); | ||
203 | instance->status_flag = flags & ME_IO_IRQ_START_EXTENDED_STATUS; | ||
204 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
205 | |||
206 | ME_SUBDEVICE_EXIT; | ||
207 | |||
208 | return err; | ||
209 | } | ||
210 | |||
211 | static int me8100_di_io_irq_wait(me_subdevice_t * subdevice, | ||
212 | struct file *filep, | ||
213 | int channel, | ||
214 | int *irq_count, | ||
215 | int *value, int time_out, int flags) | ||
216 | { | ||
217 | me8100_di_subdevice_t *instance; | ||
218 | int err = ME_ERRNO_SUCCESS; | ||
219 | long t = 0; | ||
220 | unsigned long cpu_flags; | ||
221 | int count; | ||
222 | |||
223 | PDEBUG("executed.\n"); | ||
224 | PDEVELOP("PID: %d.\n", current->pid); | ||
225 | |||
226 | instance = (me8100_di_subdevice_t *) subdevice; | ||
227 | |||
228 | if (flags & | ||
229 | ~(ME_IO_IRQ_WAIT_NORMAL_STATUS | ME_IO_IRQ_WAIT_EXTENDED_STATUS)) { | ||
230 | PERROR("Invalid flag specified.\n"); | ||
231 | return ME_ERRNO_INVALID_FLAGS; | ||
232 | } | ||
233 | |||
234 | if (channel) { | ||
235 | PERROR("Invalid channel specified.\n"); | ||
236 | return ME_ERRNO_INVALID_CHANNEL; | ||
237 | } | ||
238 | |||
239 | if (time_out < 0) { | ||
240 | PERROR("Invalid time_out specified.\n"); | ||
241 | return ME_ERRNO_INVALID_TIMEOUT; | ||
242 | } | ||
243 | |||
244 | if (time_out) { | ||
245 | t = (time_out * HZ) / 1000; | ||
246 | |||
247 | if (t == 0) | ||
248 | t = 1; | ||
249 | } | ||
250 | |||
251 | ME_SUBDEVICE_ENTER; | ||
252 | |||
253 | if (instance->rised <= 0) { | ||
254 | instance->rised = 0; | ||
255 | count = instance->irq_count; | ||
256 | |||
257 | if (time_out) { | ||
258 | t = wait_event_interruptible_timeout(instance-> | ||
259 | wait_queue, | ||
260 | ((count != | ||
261 | instance-> | ||
262 | irq_count) | ||
263 | || (instance-> | ||
264 | rised < 0)), | ||
265 | t); | ||
266 | // t = wait_event_interruptible_timeout(instance->wait_queue, (instance->rised != 0), t); | ||
267 | if (t == 0) { | ||
268 | PERROR("Wait on interrupt timed out.\n"); | ||
269 | err = ME_ERRNO_TIMEOUT; | ||
270 | } | ||
271 | } else { | ||
272 | wait_event_interruptible(instance->wait_queue, | ||
273 | ((count != instance->irq_count) | ||
274 | || (instance->rised < 0))); | ||
275 | // wait_event_interruptible(instance->wait_queue, (instance->rised != 0)); | ||
276 | } | ||
277 | |||
278 | if (instance->rised < 0) { | ||
279 | PERROR("Wait on interrupt aborted by user.\n"); | ||
280 | err = ME_ERRNO_CANCELLED; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | if (signal_pending(current)) { | ||
285 | PERROR("Wait on interrupt aborted by signal.\n"); | ||
286 | err = ME_ERRNO_SIGNAL; | ||
287 | } | ||
288 | |||
289 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
290 | *irq_count = instance->irq_count; | ||
291 | if (!err) { | ||
292 | if (flags & ME_IO_IRQ_WAIT_NORMAL_STATUS) { | ||
293 | *value = instance->status_value; | ||
294 | } else if (flags & ME_IO_IRQ_WAIT_EXTENDED_STATUS) { | ||
295 | *value = instance->status_value_edges; | ||
296 | } else { // Use default | ||
297 | if (!instance->status_flag) { | ||
298 | *value = instance->status_value; | ||
299 | } else { | ||
300 | *value = instance->status_value_edges; | ||
301 | } | ||
302 | } | ||
303 | instance->rised = 0; | ||
304 | /* | ||
305 | instance->status_value = 0; | ||
306 | instance->status_value_edges = 0; | ||
307 | */ | ||
308 | } else { | ||
309 | *value = 0; | ||
310 | } | ||
311 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
312 | |||
313 | ME_SUBDEVICE_EXIT; | ||
314 | |||
315 | return err; | ||
316 | } | ||
317 | |||
318 | static int me8100_di_io_irq_stop(me_subdevice_t * subdevice, | ||
319 | struct file *filep, int channel, int flags) | ||
320 | { | ||
321 | me8100_di_subdevice_t *instance; | ||
322 | uint16_t ctrl; | ||
323 | unsigned long cpu_flags; | ||
324 | |||
325 | PDEBUG("executed.\n"); | ||
326 | |||
327 | instance = (me8100_di_subdevice_t *) subdevice; | ||
328 | |||
329 | if (flags) { | ||
330 | PERROR("Invalid flag specified.\n"); | ||
331 | return ME_ERRNO_INVALID_FLAGS; | ||
332 | } | ||
333 | |||
334 | if (channel) { | ||
335 | PERROR("Invalid channel specified.\n"); | ||
336 | return ME_ERRNO_INVALID_CHANNEL; | ||
337 | } | ||
338 | |||
339 | ME_SUBDEVICE_ENTER; | ||
340 | |||
341 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
342 | spin_lock(instance->ctrl_reg_lock); | ||
343 | ctrl = inw(instance->ctrl_reg); | ||
344 | ctrl &= ~(ME8100_DIO_CTRL_BIT_INTB_1 | ME8100_DIO_CTRL_BIT_INTB_0); | ||
345 | outw(ctrl, instance->ctrl_reg); | ||
346 | PDEBUG_REG("ctrl_reg outw(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
347 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
348 | spin_unlock(instance->ctrl_reg_lock); | ||
349 | instance->rised = -1; | ||
350 | instance->status_value = 0; | ||
351 | instance->status_value_edges = 0; | ||
352 | instance->filtering_flag = 0; | ||
353 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
354 | wake_up_interruptible_all(&instance->wait_queue); | ||
355 | |||
356 | ME_SUBDEVICE_EXIT; | ||
357 | |||
358 | return ME_ERRNO_SUCCESS; | ||
359 | } | ||
360 | |||
361 | static int me8100_di_io_single_config(me_subdevice_t * subdevice, | ||
362 | struct file *filep, | ||
363 | int channel, | ||
364 | int single_config, | ||
365 | int ref, | ||
366 | int trig_chan, | ||
367 | int trig_type, int trig_edge, int flags) | ||
368 | { | ||
369 | me8100_di_subdevice_t *instance; | ||
370 | int err = ME_ERRNO_SUCCESS; | ||
371 | |||
372 | PDEBUG("executed.\n"); | ||
373 | |||
374 | instance = (me8100_di_subdevice_t *) subdevice; | ||
375 | |||
376 | ME_SUBDEVICE_ENTER; | ||
377 | |||
378 | spin_lock(&instance->subdevice_lock); | ||
379 | |||
380 | switch (flags) { | ||
381 | case ME_IO_SINGLE_CONFIG_NO_FLAGS: | ||
382 | case ME_IO_SINGLE_CONFIG_DIO_WORD: | ||
383 | if (channel == 0) { | ||
384 | if (single_config == ME_SINGLE_CONFIG_DIO_INPUT) { | ||
385 | } else { | ||
386 | PERROR | ||
387 | ("Invalid port configuration specified.\n"); | ||
388 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
389 | } | ||
390 | } else { | ||
391 | PERROR("Invalid channel number.\n"); | ||
392 | err = ME_ERRNO_INVALID_CHANNEL; | ||
393 | } | ||
394 | break; | ||
395 | |||
396 | default: | ||
397 | PERROR("Invalid flags specified.\n"); | ||
398 | err = ME_ERRNO_INVALID_FLAGS; | ||
399 | } | ||
400 | |||
401 | spin_unlock(&instance->subdevice_lock); | ||
402 | |||
403 | ME_SUBDEVICE_EXIT; | ||
404 | |||
405 | return err; | ||
406 | } | ||
407 | |||
408 | static int me8100_di_io_single_read(me_subdevice_t * subdevice, | ||
409 | struct file *filep, | ||
410 | int channel, | ||
411 | int *value, int time_out, int flags) | ||
412 | { | ||
413 | me8100_di_subdevice_t *instance; | ||
414 | int err = ME_ERRNO_SUCCESS; | ||
415 | |||
416 | PDEBUG("executed.\n"); | ||
417 | |||
418 | instance = (me8100_di_subdevice_t *) subdevice; | ||
419 | |||
420 | ME_SUBDEVICE_ENTER; | ||
421 | |||
422 | spin_lock(&instance->subdevice_lock); | ||
423 | |||
424 | switch (flags) { | ||
425 | |||
426 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
427 | if ((channel >= 0) && (channel < 16)) { | ||
428 | *value = inw(instance->port_reg) & (0x1 << channel); | ||
429 | } else { | ||
430 | PERROR("Invalid bit number specified.\n"); | ||
431 | err = ME_ERRNO_INVALID_CHANNEL; | ||
432 | } | ||
433 | break; | ||
434 | |||
435 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
436 | if (channel == 0) { | ||
437 | *value = inw(instance->port_reg) & 0xFF; | ||
438 | } else if (channel == 1) { | ||
439 | *value = (inw(instance->port_reg) >> 8) & 0xFF; | ||
440 | } else { | ||
441 | PERROR("Invalid byte number specified.\n"); | ||
442 | err = ME_ERRNO_INVALID_CHANNEL; | ||
443 | } | ||
444 | break; | ||
445 | |||
446 | case ME_IO_SINGLE_NO_FLAGS: | ||
447 | case ME_IO_SINGLE_TYPE_DIO_WORD: | ||
448 | if (channel == 0) { | ||
449 | *value = inw(instance->port_reg); | ||
450 | } else { | ||
451 | PERROR("Invalid word number specified.\n"); | ||
452 | err = ME_ERRNO_INVALID_CHANNEL; | ||
453 | } | ||
454 | |||
455 | break; | ||
456 | |||
457 | default: | ||
458 | PERROR("Invalid flags specified.\n"); | ||
459 | err = ME_ERRNO_INVALID_FLAGS; | ||
460 | } | ||
461 | |||
462 | spin_unlock(&instance->subdevice_lock); | ||
463 | |||
464 | ME_SUBDEVICE_EXIT; | ||
465 | |||
466 | return err; | ||
467 | } | ||
468 | |||
469 | static int me8100_di_query_number_channels(me_subdevice_t * subdevice, | ||
470 | int *number) | ||
471 | { | ||
472 | PDEBUG("executed.\n"); | ||
473 | *number = 16; | ||
474 | return ME_ERRNO_SUCCESS; | ||
475 | } | ||
476 | |||
477 | static int me8100_di_query_subdevice_type(me_subdevice_t * subdevice, | ||
478 | int *type, int *subtype) | ||
479 | { | ||
480 | PDEBUG("executed.\n"); | ||
481 | *type = ME_TYPE_DI; | ||
482 | *subtype = ME_SUBTYPE_SINGLE; | ||
483 | return ME_ERRNO_SUCCESS; | ||
484 | } | ||
485 | |||
486 | static int me8100_di_query_subdevice_caps(me_subdevice_t * subdevice, int *caps) | ||
487 | { | ||
488 | PDEBUG("executed.\n"); | ||
489 | *caps = ME_CAPS_DIO_BIT_PATTERN_IRQ | ME_CAPS_DIO_BIT_MASK_IRQ_EDGE_ANY; | ||
490 | return ME_ERRNO_SUCCESS; | ||
491 | } | ||
492 | |||
493 | static void me8100_di_destructor(struct me_subdevice *subdevice) | ||
494 | { | ||
495 | me8100_di_subdevice_t *instance; | ||
496 | |||
497 | PDEBUG("executed.\n"); | ||
498 | |||
499 | instance = (me8100_di_subdevice_t *) subdevice; | ||
500 | |||
501 | free_irq(instance->irq, (void *)instance); | ||
502 | me_subdevice_deinit(&instance->base); | ||
503 | kfree(instance); | ||
504 | } | ||
505 | |||
506 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) | ||
507 | static irqreturn_t me8100_isr(int irq, void *dev_id) | ||
508 | #else | ||
509 | static irqreturn_t me8100_isr(int irq, void *dev_id, struct pt_regs *regs) | ||
510 | #endif | ||
511 | { | ||
512 | me8100_di_subdevice_t *instance; | ||
513 | uint32_t icsr; | ||
514 | |||
515 | uint16_t irq_status; | ||
516 | uint16_t line_value = 0; | ||
517 | |||
518 | uint32_t status_val = 0; | ||
519 | |||
520 | PDEBUG("executed.\n"); | ||
521 | |||
522 | instance = (me8100_di_subdevice_t *) dev_id; | ||
523 | |||
524 | if (irq != instance->irq) { | ||
525 | PERROR("Incorrect interrupt num: %d.\n", irq); | ||
526 | return IRQ_NONE; | ||
527 | } | ||
528 | |||
529 | icsr = inl(instance->irq_status_reg); | ||
530 | if (instance->di_idx == 0) { | ||
531 | |||
532 | if ((icsr & | ||
533 | (PLX_INTCSR_LOCAL_INT1_STATE | PLX_INTCSR_PCI_INT_EN | | ||
534 | PLX_INTCSR_LOCAL_INT1_EN)) != | ||
535 | (PLX_INTCSR_LOCAL_INT1_STATE | PLX_INTCSR_PCI_INT_EN | | ||
536 | PLX_INTCSR_LOCAL_INT1_EN)) { | ||
537 | PINFO | ||
538 | ("%ld Shared interrupt. %s(): idx=0 plx:irq_status_reg=0x%04X\n", | ||
539 | jiffies, __FUNCTION__, icsr); | ||
540 | return IRQ_NONE; | ||
541 | } | ||
542 | } else if (instance->di_idx == 1) { | ||
543 | if ((icsr & | ||
544 | (PLX_INTCSR_LOCAL_INT2_STATE | PLX_INTCSR_PCI_INT_EN | | ||
545 | PLX_INTCSR_LOCAL_INT2_EN)) != | ||
546 | (PLX_INTCSR_LOCAL_INT2_STATE | PLX_INTCSR_PCI_INT_EN | | ||
547 | PLX_INTCSR_LOCAL_INT2_EN)) { | ||
548 | PINFO | ||
549 | ("%ld Shared interrupt. %s(): idx=1 plx:irq_status_reg=0x%04X\n", | ||
550 | jiffies, __FUNCTION__, icsr); | ||
551 | return IRQ_NONE; | ||
552 | } | ||
553 | } else { | ||
554 | PERROR("%s():Wrong interrupt idx=%d csr=0x%X.\n", __FUNCTION__, | ||
555 | instance->di_idx, icsr); | ||
556 | return IRQ_NONE; | ||
557 | } | ||
558 | |||
559 | PDEBUG("me8100_isr():Interrupt from idx=%d occured.\n", | ||
560 | instance->di_idx); | ||
561 | spin_lock(&instance->subdevice_lock); | ||
562 | inw(instance->irq_reset_reg); | ||
563 | line_value = inw(instance->port_reg); | ||
564 | |||
565 | irq_status = instance->line_value ^ line_value; | ||
566 | |||
567 | // Make extended information. | ||
568 | status_val |= (0x00FF & (~(uint16_t) instance->line_value & line_value)) << 16; //Raise | ||
569 | status_val |= (0x00FF & ((uint16_t) instance->line_value & ~line_value)); //Fall | ||
570 | |||
571 | instance->line_value = line_value; | ||
572 | |||
573 | if (instance->rised == 0) { | ||
574 | instance->status_value = irq_status; | ||
575 | instance->status_value_edges = status_val; | ||
576 | } else { | ||
577 | instance->status_value |= irq_status; | ||
578 | instance->status_value_edges |= status_val; | ||
579 | } | ||
580 | |||
581 | if (instance->filtering_flag) { // For compare mode only. | ||
582 | if (instance->compare_value == instance->line_value) { | ||
583 | instance->rised = 1; | ||
584 | instance->irq_count++; | ||
585 | } | ||
586 | } else { | ||
587 | instance->rised = 1; | ||
588 | instance->irq_count++; | ||
589 | } | ||
590 | |||
591 | spin_unlock(&instance->subdevice_lock); | ||
592 | wake_up_interruptible_all(&instance->wait_queue); | ||
593 | |||
594 | return IRQ_HANDLED; | ||
595 | } | ||
596 | |||
597 | me8100_di_subdevice_t *me8100_di_constructor(uint32_t me8100_reg_base, | ||
598 | uint32_t plx_reg_base, | ||
599 | unsigned int di_idx, | ||
600 | int irq, | ||
601 | spinlock_t * ctrl_reg_lock) | ||
602 | { | ||
603 | me8100_di_subdevice_t *subdevice; | ||
604 | int err; | ||
605 | |||
606 | PDEBUG("executed.\n"); | ||
607 | |||
608 | /* Allocate memory for subdevice instance */ | ||
609 | subdevice = kmalloc(sizeof(me8100_di_subdevice_t), GFP_KERNEL); | ||
610 | |||
611 | if (!subdevice) { | ||
612 | PERROR("Cannot get memory for subdevice instance.\n"); | ||
613 | return NULL; | ||
614 | } | ||
615 | |||
616 | memset(subdevice, 0, sizeof(me8100_di_subdevice_t)); | ||
617 | |||
618 | /* Initialize subdevice base class */ | ||
619 | err = me_subdevice_init(&subdevice->base); | ||
620 | |||
621 | if (err) { | ||
622 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
623 | kfree(subdevice); | ||
624 | return NULL; | ||
625 | } | ||
626 | // Initialize spin locks. | ||
627 | spin_lock_init(&subdevice->subdevice_lock); | ||
628 | |||
629 | subdevice->ctrl_reg_lock = ctrl_reg_lock; | ||
630 | |||
631 | /* Save the subdevice index. */ | ||
632 | subdevice->di_idx = di_idx; | ||
633 | |||
634 | /* Initialize wait queue */ | ||
635 | init_waitqueue_head(&subdevice->wait_queue); | ||
636 | |||
637 | /* Register interrupt service routine. */ | ||
638 | subdevice->irq = irq; | ||
639 | err = request_irq(subdevice->irq, me8100_isr, | ||
640 | #ifdef IRQF_DISABLED | ||
641 | IRQF_DISABLED | IRQF_SHARED, | ||
642 | #else | ||
643 | SA_INTERRUPT | SA_SHIRQ, | ||
644 | #endif | ||
645 | ME8100_NAME, (void *)subdevice); | ||
646 | |||
647 | if (err) { | ||
648 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
649 | kfree(subdevice); | ||
650 | return NULL; | ||
651 | } | ||
652 | PINFO("Registered irq=%d.\n", subdevice->irq); | ||
653 | |||
654 | /* Initialize the registers */ | ||
655 | subdevice->ctrl_reg = | ||
656 | me8100_reg_base + ME8100_CTRL_REG_A + di_idx * ME8100_REG_OFFSET; | ||
657 | subdevice->port_reg = | ||
658 | me8100_reg_base + ME8100_DI_REG_A + di_idx * ME8100_REG_OFFSET; | ||
659 | subdevice->mask_reg = | ||
660 | me8100_reg_base + ME8100_MASK_REG_A + di_idx * ME8100_REG_OFFSET; | ||
661 | subdevice->pattern_reg = | ||
662 | me8100_reg_base + ME8100_PATTERN_REG_A + di_idx * ME8100_REG_OFFSET; | ||
663 | subdevice->din_int_reg = | ||
664 | me8100_reg_base + ME8100_INT_DI_REG_A + di_idx * ME8100_REG_OFFSET; | ||
665 | subdevice->irq_reset_reg = | ||
666 | me8100_reg_base + ME8100_RES_INT_REG_A + di_idx * ME8100_REG_OFFSET; | ||
667 | subdevice->irq_status_reg = plx_reg_base + PLX_INTCSR; | ||
668 | #ifdef MEDEBUG_DEBUG_REG | ||
669 | subdevice->reg_base = me8100_reg_base; | ||
670 | #endif | ||
671 | |||
672 | /* Overload base class methods. */ | ||
673 | subdevice->base.me_subdevice_io_irq_start = me8100_di_io_irq_start; | ||
674 | subdevice->base.me_subdevice_io_irq_wait = me8100_di_io_irq_wait; | ||
675 | subdevice->base.me_subdevice_io_irq_stop = me8100_di_io_irq_stop; | ||
676 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
677 | me8100_di_io_reset_subdevice; | ||
678 | subdevice->base.me_subdevice_io_single_config = | ||
679 | me8100_di_io_single_config; | ||
680 | subdevice->base.me_subdevice_io_single_read = me8100_di_io_single_read; | ||
681 | subdevice->base.me_subdevice_query_number_channels = | ||
682 | me8100_di_query_number_channels; | ||
683 | subdevice->base.me_subdevice_query_subdevice_type = | ||
684 | me8100_di_query_subdevice_type; | ||
685 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
686 | me8100_di_query_subdevice_caps; | ||
687 | subdevice->base.me_subdevice_destructor = me8100_di_destructor; | ||
688 | |||
689 | subdevice->rised = 0; | ||
690 | subdevice->irq_count = 0; | ||
691 | |||
692 | return subdevice; | ||
693 | } | ||
diff --git a/drivers/staging/meilhaus/me8100_di.h b/drivers/staging/meilhaus/me8100_di.h new file mode 100644 index 000000000000..e1db79129175 --- /dev/null +++ b/drivers/staging/meilhaus/me8100_di.h | |||
@@ -0,0 +1,89 @@ | |||
1 | /** | ||
2 | * @file me8100_di.h | ||
3 | * | ||
4 | * @brief ME-8100 digital input subdevice class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME8100_DI_H_ | ||
28 | #define _ME8100_DI_H_ | ||
29 | |||
30 | #include "mesubdevice.h" | ||
31 | |||
32 | #ifdef __KERNEL__ | ||
33 | |||
34 | /** | ||
35 | * @brief The template subdevice class. | ||
36 | */ | ||
37 | typedef struct me8100_di_subdevice { | ||
38 | // Inheritance | ||
39 | me_subdevice_t base; /**< The subdevice base class. */ | ||
40 | |||
41 | /* Attributes */ | ||
42 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
43 | spinlock_t *ctrl_reg_lock; | ||
44 | |||
45 | unsigned di_idx; | ||
46 | |||
47 | int irq; | ||
48 | volatile int rised; | ||
49 | unsigned int irq_count; | ||
50 | |||
51 | uint status_flag; /**< Default interupt status flag */ | ||
52 | uint status_value; /**< Interupt status */ | ||
53 | uint status_value_edges; /**< Extended interupt status */ | ||
54 | uint line_value; | ||
55 | |||
56 | uint16_t compare_value; | ||
57 | uint8_t filtering_flag; | ||
58 | |||
59 | wait_queue_head_t wait_queue; | ||
60 | |||
61 | unsigned long ctrl_reg; | ||
62 | unsigned long port_reg; | ||
63 | unsigned long mask_reg; | ||
64 | unsigned long pattern_reg; | ||
65 | unsigned long long din_int_reg; | ||
66 | unsigned long irq_reset_reg; | ||
67 | unsigned long irq_status_reg; | ||
68 | #ifdef MEDEBUG_DEBUG_REG | ||
69 | unsigned long reg_base; | ||
70 | #endif | ||
71 | |||
72 | } me8100_di_subdevice_t; | ||
73 | |||
74 | /** | ||
75 | * @brief The constructor to generate a ME-8100 digital input subdevice instance. | ||
76 | * | ||
77 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
78 | * | ||
79 | * @return Pointer to new instance on success.\n | ||
80 | * NULL on error. | ||
81 | */ | ||
82 | me8100_di_subdevice_t *me8100_di_constructor(uint32_t me8100_reg_base, | ||
83 | uint32_t plx_reg_base, | ||
84 | unsigned int di_idx, | ||
85 | int irq, | ||
86 | spinlock_t * ctrl_leg_lock); | ||
87 | |||
88 | #endif | ||
89 | #endif | ||
diff --git a/drivers/staging/meilhaus/me8100_di_reg.h b/drivers/staging/meilhaus/me8100_di_reg.h new file mode 100644 index 000000000000..063bd193709e --- /dev/null +++ b/drivers/staging/meilhaus/me8100_di_reg.h | |||
@@ -0,0 +1,47 @@ | |||
1 | /** | ||
2 | * @file me8100_di_reg.h | ||
3 | * | ||
4 | * @brief ME-8100 digital input subdevice register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME8100_DI_REG_H_ | ||
28 | #define _ME8100_DI_REG_H_ | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | #define ME8100_RES_INT_REG_A 0x02 //(r, ) | ||
33 | #define ME8100_DI_REG_A 0x04 //(r, ) | ||
34 | #define ME8100_PATTERN_REG_A 0x08 //( ,w) | ||
35 | #define ME8100_MASK_REG_A 0x0A //( ,w) | ||
36 | #define ME8100_INT_DI_REG_A 0x0A //(r, ) | ||
37 | |||
38 | #define ME8100_RES_INT_REG_B 0x0E //(r, ) | ||
39 | #define ME8100_DI_REG_B 0x10 //(r, ) | ||
40 | #define ME8100_PATTERN_REG_B 0x14 //( ,w) | ||
41 | #define ME8100_MASK_REG_B 0x16 //( ,w) | ||
42 | #define ME8100_INT_DI_REG_B 0x16 //(r, ) | ||
43 | |||
44 | #define ME8100_REG_OFFSET 0x0C | ||
45 | |||
46 | #endif | ||
47 | #endif | ||
diff --git a/drivers/staging/meilhaus/me8100_do.c b/drivers/staging/meilhaus/me8100_do.c new file mode 100644 index 000000000000..957b9f92f760 --- /dev/null +++ b/drivers/staging/meilhaus/me8100_do.c | |||
@@ -0,0 +1,391 @@ | |||
1 | /** | ||
2 | * @file me8100_do.c | ||
3 | * | ||
4 | * @brief ME-8100 digital output subdevice instance. | ||
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 | /* | ||
33 | * Includes | ||
34 | */ | ||
35 | #include <linux/module.h> | ||
36 | |||
37 | #include <linux/slab.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | #include <asm/io.h> | ||
40 | #include <linux/types.h> | ||
41 | |||
42 | #include "medefines.h" | ||
43 | #include "meinternal.h" | ||
44 | #include "meerror.h" | ||
45 | |||
46 | #include "medebug.h" | ||
47 | #include "me8100_reg.h" | ||
48 | #include "me8100_do_reg.h" | ||
49 | #include "me8100_do.h" | ||
50 | |||
51 | /* | ||
52 | * Defines | ||
53 | */ | ||
54 | |||
55 | /* | ||
56 | * Functions | ||
57 | */ | ||
58 | |||
59 | static int me8100_do_io_reset_subdevice(struct me_subdevice *subdevice, | ||
60 | struct file *filep, int flags) | ||
61 | { | ||
62 | me8100_do_subdevice_t *instance; | ||
63 | uint16_t ctrl; | ||
64 | |||
65 | PDEBUG("executed.\n"); | ||
66 | |||
67 | instance = (me8100_do_subdevice_t *) subdevice; | ||
68 | |||
69 | if (flags) { | ||
70 | PERROR("Invalid flag specified.\n"); | ||
71 | return ME_ERRNO_INVALID_FLAGS; | ||
72 | } | ||
73 | |||
74 | ME_SUBDEVICE_ENTER; | ||
75 | |||
76 | spin_lock(&instance->subdevice_lock); | ||
77 | spin_lock(instance->ctrl_reg_lock); | ||
78 | ctrl = inw(instance->ctrl_reg); | ||
79 | ctrl &= ME8100_DIO_CTRL_BIT_INTB_1 | ME8100_DIO_CTRL_BIT_INTB_0; | ||
80 | outw(ctrl, instance->ctrl_reg); | ||
81 | PDEBUG_REG("ctrl_reg outw(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
82 | instance->ctrl_reg - instance->reg_base, ctrl); | ||
83 | spin_unlock(instance->ctrl_reg_lock); | ||
84 | outw(0, instance->port_reg); | ||
85 | instance->port_reg_mirror = 0; | ||
86 | PDEBUG_REG("port_reg outw(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
87 | instance->port_reg - instance->reg_base, 0); | ||
88 | spin_unlock(&instance->subdevice_lock); | ||
89 | |||
90 | ME_SUBDEVICE_EXIT; | ||
91 | |||
92 | return ME_ERRNO_SUCCESS; | ||
93 | } | ||
94 | |||
95 | static int me8100_do_io_single_config(me_subdevice_t * subdevice, | ||
96 | struct file *filep, | ||
97 | int channel, | ||
98 | int single_config, | ||
99 | int ref, | ||
100 | int trig_chan, | ||
101 | int trig_type, int trig_edge, int flags) | ||
102 | { | ||
103 | me8100_do_subdevice_t *instance; | ||
104 | int err = ME_ERRNO_SUCCESS; | ||
105 | int config; | ||
106 | |||
107 | PDEBUG("executed.\n"); | ||
108 | |||
109 | instance = (me8100_do_subdevice_t *) subdevice; | ||
110 | |||
111 | ME_SUBDEVICE_ENTER; | ||
112 | |||
113 | spin_lock(&instance->subdevice_lock); | ||
114 | spin_lock(instance->ctrl_reg_lock); | ||
115 | config = inw(instance->ctrl_reg); | ||
116 | switch (flags) { | ||
117 | case ME_IO_SINGLE_CONFIG_NO_FLAGS: | ||
118 | case ME_IO_SINGLE_CONFIG_DIO_WORD: | ||
119 | if (channel == 0) { | ||
120 | if (single_config == | ||
121 | ME_SINGLE_CONFIG_DIO_HIGH_IMPEDANCE) { | ||
122 | config &= ~(ME8100_DIO_CTRL_BIT_ENABLE_DIO); | ||
123 | } else if (single_config == ME_SINGLE_CONFIG_DIO_SINK) { | ||
124 | config |= ME8100_DIO_CTRL_BIT_ENABLE_DIO; | ||
125 | config &= ~ME8100_DIO_CTRL_BIT_SOURCE; | ||
126 | } else if (single_config == ME_SINGLE_CONFIG_DIO_SOURCE) { | ||
127 | config |= | ||
128 | ME8100_DIO_CTRL_BIT_ENABLE_DIO | | ||
129 | ME8100_DIO_CTRL_BIT_SOURCE; | ||
130 | } else { | ||
131 | PERROR | ||
132 | ("Invalid port configuration specified.\n"); | ||
133 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
134 | } | ||
135 | } else { | ||
136 | PERROR("Invalid word number specified.\n"); | ||
137 | err = ME_ERRNO_INVALID_CHANNEL; | ||
138 | } | ||
139 | break; | ||
140 | |||
141 | default: | ||
142 | PERROR("Invalid flags specified.\n"); | ||
143 | err = ME_ERRNO_INVALID_FLAGS; | ||
144 | } | ||
145 | |||
146 | if (!err) { | ||
147 | outw(config, instance->ctrl_reg); | ||
148 | PDEBUG_REG("ctrl_reg outw(0x%lX+0x%lX)=0x%x\n", | ||
149 | instance->reg_base, | ||
150 | instance->ctrl_reg - instance->reg_base, config); | ||
151 | } | ||
152 | |||
153 | spin_unlock(instance->ctrl_reg_lock); | ||
154 | spin_unlock(&instance->subdevice_lock); | ||
155 | |||
156 | ME_SUBDEVICE_EXIT; | ||
157 | |||
158 | return err; | ||
159 | } | ||
160 | |||
161 | static int me8100_do_io_single_read(me_subdevice_t * subdevice, | ||
162 | struct file *filep, | ||
163 | int channel, | ||
164 | int *value, int time_out, int flags) | ||
165 | { | ||
166 | me8100_do_subdevice_t *instance; | ||
167 | int err = ME_ERRNO_SUCCESS; | ||
168 | |||
169 | PDEBUG("executed.\n"); | ||
170 | |||
171 | instance = (me8100_do_subdevice_t *) subdevice; | ||
172 | |||
173 | ME_SUBDEVICE_ENTER; | ||
174 | |||
175 | spin_lock(&instance->subdevice_lock); | ||
176 | switch (flags) { | ||
177 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
178 | if ((channel >= 0) && (channel < 16)) { | ||
179 | *value = instance->port_reg_mirror & (0x1 << channel); | ||
180 | } else { | ||
181 | PERROR("Invalid bit number specified.\n"); | ||
182 | err = ME_ERRNO_INVALID_CHANNEL; | ||
183 | } | ||
184 | break; | ||
185 | |||
186 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
187 | if (channel == 0) { | ||
188 | *value = instance->port_reg_mirror & 0xFF; | ||
189 | } else if (channel == 1) { | ||
190 | *value = (instance->port_reg_mirror >> 8) & 0xFF; | ||
191 | } else { | ||
192 | PERROR("Invalid byte number specified.\n"); | ||
193 | err = ME_ERRNO_INVALID_CHANNEL; | ||
194 | } | ||
195 | break; | ||
196 | |||
197 | case ME_IO_SINGLE_NO_FLAGS: | ||
198 | case ME_IO_SINGLE_TYPE_DIO_WORD: | ||
199 | if (channel == 0) { | ||
200 | *value = instance->port_reg_mirror; | ||
201 | } else { | ||
202 | PERROR("Invalid word number specified.\n"); | ||
203 | err = ME_ERRNO_INVALID_CHANNEL; | ||
204 | } | ||
205 | break; | ||
206 | |||
207 | default: | ||
208 | PERROR("Invalid flags specified.\n"); | ||
209 | err = ME_ERRNO_INVALID_FLAGS; | ||
210 | } | ||
211 | spin_unlock(&instance->subdevice_lock); | ||
212 | |||
213 | ME_SUBDEVICE_EXIT; | ||
214 | |||
215 | return err; | ||
216 | } | ||
217 | |||
218 | static int me8100_do_io_single_write(me_subdevice_t * subdevice, | ||
219 | struct file *filep, | ||
220 | int channel, | ||
221 | int value, int time_out, int flags) | ||
222 | { | ||
223 | me8100_do_subdevice_t *instance; | ||
224 | int err = ME_ERRNO_SUCCESS; | ||
225 | |||
226 | PDEBUG("executed.\n"); | ||
227 | |||
228 | instance = (me8100_do_subdevice_t *) subdevice; | ||
229 | |||
230 | ME_SUBDEVICE_ENTER; | ||
231 | |||
232 | spin_lock(&instance->subdevice_lock); | ||
233 | switch (flags) { | ||
234 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
235 | if ((channel >= 0) && (channel < 16)) { | ||
236 | instance->port_reg_mirror = | ||
237 | value ? (instance-> | ||
238 | port_reg_mirror | (0x1 << channel)) | ||
239 | : (instance->port_reg_mirror & ~(0x1 << channel)); | ||
240 | outw(instance->port_reg_mirror, instance->port_reg); | ||
241 | PDEBUG_REG("port_reg outw(0x%lX+0x%lX)=0x%x\n", | ||
242 | instance->reg_base, | ||
243 | instance->port_reg - instance->reg_base, | ||
244 | instance->port_reg_mirror); | ||
245 | } else { | ||
246 | PERROR("Invalid bit number specified.\n"); | ||
247 | err = ME_ERRNO_INVALID_CHANNEL; | ||
248 | } | ||
249 | break; | ||
250 | |||
251 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
252 | if (channel == 0) { | ||
253 | instance->port_reg_mirror &= ~0xFF; | ||
254 | instance->port_reg_mirror |= value & 0xFF; | ||
255 | outw(instance->port_reg_mirror, instance->port_reg); | ||
256 | PDEBUG_REG("port_reg outw(0x%lX+0x%lX)=0x%x\n", | ||
257 | instance->reg_base, | ||
258 | instance->port_reg - instance->reg_base, | ||
259 | instance->port_reg_mirror); | ||
260 | } else if (channel == 1) { | ||
261 | instance->port_reg_mirror &= ~0xFF00; | ||
262 | instance->port_reg_mirror |= (value << 8) & 0xFF00; | ||
263 | outw(instance->port_reg_mirror, instance->port_reg); | ||
264 | PDEBUG_REG("port_reg outw(0x%lX+0x%lX)=0x%x\n", | ||
265 | instance->reg_base, | ||
266 | instance->port_reg - instance->reg_base, | ||
267 | instance->port_reg_mirror); | ||
268 | } else { | ||
269 | PERROR("Invalid byte number specified.\n"); | ||
270 | err = ME_ERRNO_INVALID_CHANNEL; | ||
271 | } | ||
272 | break; | ||
273 | |||
274 | case ME_IO_SINGLE_NO_FLAGS: | ||
275 | case ME_IO_SINGLE_TYPE_DIO_WORD: | ||
276 | if (channel == 0) { | ||
277 | instance->port_reg_mirror = value; | ||
278 | outw(value, instance->port_reg); | ||
279 | PDEBUG_REG("port_reg outw(0x%lX+0x%lX)=0x%x\n", | ||
280 | instance->reg_base, | ||
281 | instance->port_reg - instance->reg_base, | ||
282 | value); | ||
283 | } else { | ||
284 | PERROR("Invalid byte number specified.\n"); | ||
285 | err = ME_ERRNO_INVALID_CHANNEL; | ||
286 | } | ||
287 | break; | ||
288 | |||
289 | default: | ||
290 | PERROR("Invalid flags specified.\n"); | ||
291 | err = ME_ERRNO_INVALID_FLAGS; | ||
292 | } | ||
293 | spin_unlock(&instance->subdevice_lock); | ||
294 | |||
295 | ME_SUBDEVICE_EXIT; | ||
296 | |||
297 | return err; | ||
298 | } | ||
299 | |||
300 | static int me8100_do_query_number_channels(me_subdevice_t * subdevice, | ||
301 | int *number) | ||
302 | { | ||
303 | PDEBUG("executed.\n"); | ||
304 | *number = 16; | ||
305 | return ME_ERRNO_SUCCESS; | ||
306 | } | ||
307 | |||
308 | static int me8100_do_query_subdevice_type(me_subdevice_t * subdevice, | ||
309 | int *type, int *subtype) | ||
310 | { | ||
311 | PDEBUG("executed.\n"); | ||
312 | *type = ME_TYPE_DO; | ||
313 | *subtype = ME_SUBTYPE_SINGLE; | ||
314 | return ME_ERRNO_SUCCESS; | ||
315 | } | ||
316 | |||
317 | static int me8100_do_query_subdevice_caps(me_subdevice_t * subdevice, int *caps) | ||
318 | { | ||
319 | PDEBUG("executed.\n"); | ||
320 | *caps = ME_CAPS_DIO_SINK_SOURCE; | ||
321 | return ME_ERRNO_SUCCESS; | ||
322 | } | ||
323 | |||
324 | me8100_do_subdevice_t *me8100_do_constructor(uint32_t reg_base, | ||
325 | unsigned int do_idx, | ||
326 | spinlock_t * ctrl_reg_lock) | ||
327 | { | ||
328 | me8100_do_subdevice_t *subdevice; | ||
329 | int err; | ||
330 | |||
331 | PDEBUG("executed.\n"); | ||
332 | |||
333 | /* Allocate memory for subdevice instance */ | ||
334 | subdevice = kmalloc(sizeof(me8100_do_subdevice_t), GFP_KERNEL); | ||
335 | |||
336 | if (!subdevice) { | ||
337 | PERROR("Cannot get memory for subdevice instance.\n"); | ||
338 | return NULL; | ||
339 | } | ||
340 | |||
341 | memset(subdevice, 0, sizeof(me8100_do_subdevice_t)); | ||
342 | |||
343 | /* Initialize subdevice base class */ | ||
344 | err = me_subdevice_init(&subdevice->base); | ||
345 | |||
346 | if (err) { | ||
347 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
348 | kfree(subdevice); | ||
349 | return NULL; | ||
350 | } | ||
351 | |||
352 | /* Initialize registers */ | ||
353 | if (do_idx == 0) { | ||
354 | subdevice->port_reg = reg_base + ME8100_DO_REG_A; | ||
355 | subdevice->ctrl_reg = reg_base + ME8100_CTRL_REG_A; | ||
356 | } else if (do_idx == 1) { | ||
357 | subdevice->port_reg = reg_base + ME8100_DO_REG_B; | ||
358 | subdevice->ctrl_reg = reg_base + ME8100_CTRL_REG_B; | ||
359 | } else { | ||
360 | PERROR("Wrong subdevice idx=%d.\n", do_idx); | ||
361 | kfree(subdevice); | ||
362 | return NULL; | ||
363 | } | ||
364 | #ifdef MEDEBUG_DEBUG_REG | ||
365 | subdevice->reg_base = reg_base; | ||
366 | #endif | ||
367 | |||
368 | // Initialize spin locks. | ||
369 | spin_lock_init(&subdevice->subdevice_lock); | ||
370 | subdevice->ctrl_reg_lock = ctrl_reg_lock; | ||
371 | |||
372 | /* Save the subdevice index */ | ||
373 | subdevice->do_idx = do_idx; | ||
374 | |||
375 | /* Overload base class methods. */ | ||
376 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
377 | me8100_do_io_reset_subdevice; | ||
378 | subdevice->base.me_subdevice_io_single_config = | ||
379 | me8100_do_io_single_config; | ||
380 | subdevice->base.me_subdevice_io_single_read = me8100_do_io_single_read; | ||
381 | subdevice->base.me_subdevice_io_single_write = | ||
382 | me8100_do_io_single_write; | ||
383 | subdevice->base.me_subdevice_query_number_channels = | ||
384 | me8100_do_query_number_channels; | ||
385 | subdevice->base.me_subdevice_query_subdevice_type = | ||
386 | me8100_do_query_subdevice_type; | ||
387 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
388 | me8100_do_query_subdevice_caps; | ||
389 | |||
390 | return subdevice; | ||
391 | } | ||
diff --git a/drivers/staging/meilhaus/me8100_do.h b/drivers/staging/meilhaus/me8100_do.h new file mode 100644 index 000000000000..acf880136663 --- /dev/null +++ b/drivers/staging/meilhaus/me8100_do.h | |||
@@ -0,0 +1,70 @@ | |||
1 | /** | ||
2 | * @file me8100_do.h | ||
3 | * | ||
4 | * @brief ME-8100 digital output subdevice class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME8100_DO_H_ | ||
28 | #define _ME8100_DO_H_ | ||
29 | |||
30 | #include "mesubdevice.h" | ||
31 | |||
32 | #ifdef __KERNEL__ | ||
33 | |||
34 | /** | ||
35 | * @brief The template subdevice class. | ||
36 | */ | ||
37 | typedef struct me8100_do_subdevice { | ||
38 | /* Inheritance */ | ||
39 | me_subdevice_t base; /**< The subdevice base class. */ | ||
40 | |||
41 | /* Attributes */ | ||
42 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
43 | spinlock_t *ctrl_reg_lock; /**< Spin lock to protect the #ctrl_reg. */ | ||
44 | |||
45 | unsigned int do_idx; | ||
46 | |||
47 | uint16_t port_reg_mirror; /**< Mirror used to store current port register setting which is write only. */ | ||
48 | |||
49 | unsigned long port_reg; /**< Register holding the port status. */ | ||
50 | unsigned long ctrl_reg; /**< Control register. */ | ||
51 | #ifdef MEDEBUG_DEBUG_REG | ||
52 | unsigned long reg_base; | ||
53 | #endif | ||
54 | } me8100_do_subdevice_t; | ||
55 | |||
56 | /** | ||
57 | * @brief The constructor to generate a ME-8100 digital output subdevice instance. | ||
58 | * | ||
59 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
60 | * @param do_idx The index of the digital output subdevice on this device. | ||
61 | * | ||
62 | * @return Pointer to new instance on success.\n | ||
63 | * NULL on error. | ||
64 | */ | ||
65 | me8100_do_subdevice_t *me8100_do_constructor(uint32_t reg_base, | ||
66 | unsigned int do_idx, | ||
67 | spinlock_t * ctrl_reg_lock); | ||
68 | |||
69 | #endif | ||
70 | #endif | ||
diff --git a/drivers/staging/meilhaus/me8100_do_reg.h b/drivers/staging/meilhaus/me8100_do_reg.h new file mode 100644 index 000000000000..13a23802b31a --- /dev/null +++ b/drivers/staging/meilhaus/me8100_do_reg.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /** | ||
2 | * @file me8100_ao_reg.h | ||
3 | * | ||
4 | * @brief ME-8100 analog output subdevice register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME8100_DO_REG_H_ | ||
28 | #define _ME8100_DO_REG_H_ | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | #define ME8100_DO_REG_A 0x06 //( ,w) | ||
33 | #define ME8100_DO_REG_B 0x12 //( ,w) | ||
34 | |||
35 | #endif | ||
36 | #endif | ||
diff --git a/drivers/staging/meilhaus/me8100_reg.h b/drivers/staging/meilhaus/me8100_reg.h new file mode 100644 index 000000000000..d8c4b1c6b153 --- /dev/null +++ b/drivers/staging/meilhaus/me8100_reg.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /** | ||
2 | * @file me8100_reg.h | ||
3 | * | ||
4 | * @brief ME-8100 register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME8100_REG_H_ | ||
28 | #define _ME8100_REG_H_ | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | #define ME8100_CTRL_REG_A 0x00 //( ,w) | ||
33 | #define ME8100_CTRL_REG_B 0x0C //( ,w) | ||
34 | |||
35 | #define ME8100_DIO_CTRL_BIT_SOURCE 0x10 | ||
36 | #define ME8100_DIO_CTRL_BIT_INTB_1 0x20 | ||
37 | #define ME8100_DIO_CTRL_BIT_INTB_0 0x40 | ||
38 | #define ME8100_DIO_CTRL_BIT_ENABLE_DIO 0x80 | ||
39 | |||
40 | #endif | ||
41 | #endif | ||
diff --git a/drivers/staging/meilhaus/me8200_device.c b/drivers/staging/meilhaus/me8200_device.c new file mode 100644 index 000000000000..261c0cbd9d0a --- /dev/null +++ b/drivers/staging/meilhaus/me8200_device.c | |||
@@ -0,0 +1,194 @@ | |||
1 | /** | ||
2 | * @file me8200_device.c | ||
3 | * | ||
4 | * @brief ME-8200 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 "meplx_reg.h" | ||
48 | #include "medevice.h" | ||
49 | #include "me8200_device.h" | ||
50 | #include "mesubdevice.h" | ||
51 | #include "me8200_di.h" | ||
52 | #include "me8200_do.h" | ||
53 | #include "me8200_dio.h" | ||
54 | |||
55 | me_device_t *me8200_pci_constructor(struct pci_dev *pci_device) | ||
56 | { | ||
57 | me8200_device_t *me8200_device; | ||
58 | me_subdevice_t *subdevice; | ||
59 | unsigned int version_idx; | ||
60 | int err; | ||
61 | int i; | ||
62 | |||
63 | PDEBUG("executed.\n"); | ||
64 | |||
65 | // Allocate structure for device instance. | ||
66 | me8200_device = kmalloc(sizeof(me8200_device_t), GFP_KERNEL); | ||
67 | |||
68 | if (!me8200_device) { | ||
69 | PERROR("Cannot get memory for device instance.\n"); | ||
70 | return NULL; | ||
71 | } | ||
72 | |||
73 | memset(me8200_device, 0, sizeof(me8200_device_t)); | ||
74 | |||
75 | // Initialize base class structure. | ||
76 | err = me_device_pci_init((me_device_t *) me8200_device, pci_device); | ||
77 | |||
78 | if (err) { | ||
79 | kfree(me8200_device); | ||
80 | PERROR("Cannot initialize device base class.\n"); | ||
81 | return NULL; | ||
82 | } | ||
83 | |||
84 | /* Get the index in the device version information table. */ | ||
85 | version_idx = | ||
86 | me8200_versions_get_device_index(me8200_device->base.info.pci. | ||
87 | device_id); | ||
88 | |||
89 | // Initialize spin lock . | ||
90 | spin_lock_init(&me8200_device->irq_ctrl_lock); | ||
91 | spin_lock_init(&me8200_device->irq_mode_lock); | ||
92 | spin_lock_init(&me8200_device->dio_ctrl_lock); | ||
93 | |||
94 | /* Setup the PLX interrupt configuration */ | ||
95 | outl(PLX_INTCSR_LOCAL_INT1_EN | | ||
96 | PLX_INTCSR_LOCAL_INT1_POL | | ||
97 | PLX_INTCSR_LOCAL_INT2_EN | | ||
98 | PLX_INTCSR_LOCAL_INT2_POL | | ||
99 | PLX_INTCSR_PCI_INT_EN, | ||
100 | me8200_device->base.info.pci.reg_bases[1] + PLX_INTCSR); | ||
101 | |||
102 | // Create subdevice instances. | ||
103 | |||
104 | for (i = 0; i < me8200_versions[version_idx].di_subdevices; i++) { | ||
105 | subdevice = | ||
106 | (me_subdevice_t *) me8200_di_constructor(me8200_device-> | ||
107 | base.info.pci. | ||
108 | reg_bases[2], i, | ||
109 | me8200_device-> | ||
110 | base.irq, | ||
111 | &me8200_device-> | ||
112 | irq_ctrl_lock, | ||
113 | &me8200_device-> | ||
114 | irq_mode_lock); | ||
115 | |||
116 | if (!subdevice) { | ||
117 | me_device_deinit((me_device_t *) me8200_device); | ||
118 | kfree(me8200_device); | ||
119 | PERROR("Cannot get memory for subdevice.\n"); | ||
120 | return NULL; | ||
121 | } | ||
122 | |||
123 | me_slist_add_subdevice_tail(&me8200_device->base.slist, | ||
124 | subdevice); | ||
125 | } | ||
126 | |||
127 | for (i = 0; i < me8200_versions[version_idx].do_subdevices; i++) { | ||
128 | subdevice = | ||
129 | (me_subdevice_t *) me8200_do_constructor(me8200_device-> | ||
130 | base.info.pci. | ||
131 | reg_bases[2], i, | ||
132 | me8200_device-> | ||
133 | base.irq, | ||
134 | &me8200_device-> | ||
135 | irq_mode_lock); | ||
136 | |||
137 | if (!subdevice) { | ||
138 | me_device_deinit((me_device_t *) me8200_device); | ||
139 | kfree(me8200_device); | ||
140 | PERROR("Cannot get memory for subdevice.\n"); | ||
141 | return NULL; | ||
142 | } | ||
143 | |||
144 | me_slist_add_subdevice_tail(&me8200_device->base.slist, | ||
145 | subdevice); | ||
146 | } | ||
147 | |||
148 | for (i = 0; i < me8200_versions[version_idx].dio_subdevices; i++) { | ||
149 | subdevice = | ||
150 | (me_subdevice_t *) me8200_dio_constructor(me8200_device-> | ||
151 | base.info.pci. | ||
152 | reg_bases[2], i, | ||
153 | &me8200_device-> | ||
154 | dio_ctrl_lock); | ||
155 | |||
156 | if (!subdevice) { | ||
157 | me_device_deinit((me_device_t *) me8200_device); | ||
158 | kfree(me8200_device); | ||
159 | PERROR("Cannot get memory for subdevice.\n"); | ||
160 | return NULL; | ||
161 | } | ||
162 | |||
163 | me_slist_add_subdevice_tail(&me8200_device->base.slist, | ||
164 | subdevice); | ||
165 | } | ||
166 | |||
167 | return (me_device_t *) me8200_device; | ||
168 | } | ||
169 | |||
170 | // Init and exit of module. | ||
171 | |||
172 | static int __init me8200_init(void) | ||
173 | { | ||
174 | PDEBUG("executed.\n."); | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static void __exit me8200_exit(void) | ||
179 | { | ||
180 | PDEBUG("executed.\n."); | ||
181 | } | ||
182 | |||
183 | module_init(me8200_init); | ||
184 | |||
185 | module_exit(me8200_exit); | ||
186 | |||
187 | // Administrative stuff for modinfo. | ||
188 | MODULE_AUTHOR("Guenter Gebhardt <g.gebhardt@meilhaus.de>"); | ||
189 | MODULE_DESCRIPTION("Device Driver Module for Template Device"); | ||
190 | MODULE_SUPPORTED_DEVICE("Meilhaus Template Devices"); | ||
191 | MODULE_LICENSE("GPL"); | ||
192 | |||
193 | // Export the constructor. | ||
194 | EXPORT_SYMBOL(me8200_pci_constructor); | ||
diff --git a/drivers/staging/meilhaus/me8200_device.h b/drivers/staging/meilhaus/me8200_device.h new file mode 100644 index 000000000000..cbd2a01ddb41 --- /dev/null +++ b/drivers/staging/meilhaus/me8200_device.h | |||
@@ -0,0 +1,97 @@ | |||
1 | /** | ||
2 | * @file me8200_device.h | ||
3 | * | ||
4 | * @brief ME-8200 device class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME8200_DEVICE_H | ||
28 | #define _ME8200_DEVICE_H | ||
29 | |||
30 | #include <linux/pci.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | |||
33 | #include "medevice.h" | ||
34 | |||
35 | #ifdef __KERNEL__ | ||
36 | |||
37 | /** | ||
38 | * @brief Structure holding ME-8200 device capabilities. | ||
39 | */ | ||
40 | typedef struct me8200_version { | ||
41 | uint16_t device_id; | ||
42 | unsigned int di_subdevices; | ||
43 | unsigned int do_subdevices; | ||
44 | unsigned int dio_subdevices; | ||
45 | } me8200_version_t; | ||
46 | |||
47 | /** | ||
48 | * @brief Device capabilities. | ||
49 | */ | ||
50 | static me8200_version_t me8200_versions[] = { | ||
51 | {PCI_DEVICE_ID_MEILHAUS_ME8200_A, 1, 1, 2}, | ||
52 | {PCI_DEVICE_ID_MEILHAUS_ME8200_B, 2, 2, 2}, | ||
53 | {0}, | ||
54 | }; | ||
55 | |||
56 | #define ME8200_DEVICE_VERSIONS (sizeof(me8200_versions) / sizeof(me8200_version_t) - 1) /**< Returns the number of entries in #me8200_versions. */ | ||
57 | |||
58 | /** | ||
59 | * @brief Returns the index of the device entry in #me8200_versions. | ||
60 | * | ||
61 | * @param device_id The PCI device id of the device to query. | ||
62 | * @return The index of the device in #me8200_versions. | ||
63 | */ | ||
64 | static inline unsigned int me8200_versions_get_device_index(uint16_t device_id) | ||
65 | { | ||
66 | unsigned int i; | ||
67 | for (i = 0; i < ME8200_DEVICE_VERSIONS; i++) | ||
68 | if (me8200_versions[i].device_id == device_id) | ||
69 | break; | ||
70 | return i; | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * @brief The ME-8200 device class structure. | ||
75 | */ | ||
76 | typedef struct me8200_device { | ||
77 | me_device_t base; /**< The Meilhaus device base class. */ | ||
78 | |||
79 | /* Child class attributes. */ | ||
80 | spinlock_t irq_ctrl_lock; /**< Lock for the interrupt control register. */ | ||
81 | spinlock_t irq_mode_lock; /**< Lock for the interrupt mode register. */ | ||
82 | spinlock_t dio_ctrl_lock; /**< Lock for the digital i/o control register. */ | ||
83 | } me8200_device_t; | ||
84 | |||
85 | /** | ||
86 | * @brief The ME-8200 device class constructor. | ||
87 | * | ||
88 | * @param pci_device The pci device structure given by the PCI subsystem. | ||
89 | * | ||
90 | * @return On succes a new ME-8200 device instance. \n | ||
91 | * NULL on error. | ||
92 | */ | ||
93 | me_device_t *me8200_pci_constructor(struct pci_dev *pci_device) | ||
94 | __attribute__ ((weak)); | ||
95 | |||
96 | #endif | ||
97 | #endif | ||
diff --git a/drivers/staging/meilhaus/me8200_di.c b/drivers/staging/meilhaus/me8200_di.c new file mode 100644 index 000000000000..0bb4567091cc --- /dev/null +++ b/drivers/staging/meilhaus/me8200_di.c | |||
@@ -0,0 +1,857 @@ | |||
1 | /** | ||
2 | * @file me8200_di.c | ||
3 | * | ||
4 | * @brief ME-8200 digital input subdevice instance. | ||
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 | ///Includes | ||
33 | #include <linux/module.h> | ||
34 | |||
35 | #include <linux/slab.h> | ||
36 | #include <linux/spinlock.h> | ||
37 | #include <asm/io.h> | ||
38 | #include <linux/types.h> | ||
39 | #include <linux/interrupt.h> | ||
40 | #include <linux/version.h> | ||
41 | |||
42 | #include "medefines.h" | ||
43 | #include "meerror.h" | ||
44 | |||
45 | #include "meids.h" | ||
46 | #include "medebug.h" | ||
47 | #include "me8200_reg.h" | ||
48 | #include "me8200_di_reg.h" | ||
49 | #include "me8200_di.h" | ||
50 | |||
51 | /// Defines | ||
52 | static void me8200_di_destructor(struct me_subdevice *subdevice); | ||
53 | static int me8200_di_io_irq_start(me_subdevice_t * subdevice, | ||
54 | struct file *filep, | ||
55 | int channel, | ||
56 | int irq_source, | ||
57 | int irq_edge, int irq_arg, int flags); | ||
58 | static int me8200_di_io_irq_wait(me_subdevice_t * subdevice, | ||
59 | struct file *filep, | ||
60 | int channel, | ||
61 | int *irq_count, | ||
62 | int *value, int time_out, int flags); | ||
63 | static int me8200_di_io_irq_stop(me_subdevice_t * subdevice, | ||
64 | struct file *filep, int channel, int flags); | ||
65 | static int me8200_di_io_single_config(me_subdevice_t * subdevice, | ||
66 | struct file *filep, | ||
67 | int channel, | ||
68 | int single_config, | ||
69 | int ref, | ||
70 | int trig_chan, | ||
71 | int trig_type, int trig_edge, int flags); | ||
72 | static int me8200_di_io_single_read(me_subdevice_t * subdevice, | ||
73 | struct file *filep, | ||
74 | int channel, | ||
75 | int *value, int time_out, int flags); | ||
76 | static int me8200_di_io_reset_subdevice(struct me_subdevice *subdevice, | ||
77 | struct file *filep, int flags); | ||
78 | static int me8200_di_query_number_channels(me_subdevice_t * subdevice, | ||
79 | int *number); | ||
80 | static int me8200_di_query_subdevice_type(me_subdevice_t * subdevice, | ||
81 | int *type, int *subtype); | ||
82 | static int me8200_di_query_subdevice_caps(me_subdevice_t * subdevice, | ||
83 | int *caps); | ||
84 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) | ||
85 | static irqreturn_t me8200_isr(int irq, void *dev_id); | ||
86 | #else | ||
87 | static irqreturn_t me8200_isr(int irq, void *dev_id, struct pt_regs *regs); | ||
88 | #endif | ||
89 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) | ||
90 | static irqreturn_t me8200_isr_EX(int irq, void *dev_id); | ||
91 | #else | ||
92 | static irqreturn_t me8200_isr_EX(int irq, void *dev_id, struct pt_regs *regs); | ||
93 | #endif | ||
94 | static void me8200_di_check_version(me8200_di_subdevice_t * instance, | ||
95 | unsigned long addr); | ||
96 | |||
97 | ///Functions | ||
98 | static int me8200_di_io_irq_start(me_subdevice_t * subdevice, | ||
99 | struct file *filep, | ||
100 | int channel, | ||
101 | int irq_source, | ||
102 | int irq_edge, int irq_arg, int flags) | ||
103 | { | ||
104 | me8200_di_subdevice_t *instance; | ||
105 | int err = ME_ERRNO_SUCCESS; | ||
106 | volatile uint8_t tmp; | ||
107 | unsigned long status; | ||
108 | |||
109 | PDEBUG("executed.\n"); | ||
110 | |||
111 | instance = (me8200_di_subdevice_t *) subdevice; | ||
112 | |||
113 | if (irq_source == ME_IRQ_SOURCE_DIO_PATTERN) { | ||
114 | if (flags & | ||
115 | ~(ME_IO_IRQ_START_PATTERN_FILTERING | | ||
116 | ME_IO_IRQ_START_DIO_BYTE)) { | ||
117 | PERROR("Invalid flag specified.\n"); | ||
118 | return ME_ERRNO_INVALID_FLAGS; | ||
119 | } | ||
120 | |||
121 | if (irq_edge != ME_IRQ_EDGE_NOT_USED) { | ||
122 | PERROR("Invalid irq edge specified.\n"); | ||
123 | return ME_ERRNO_INVALID_IRQ_EDGE; | ||
124 | } | ||
125 | } else if (irq_source == ME_IRQ_SOURCE_DIO_MASK) { | ||
126 | if (flags & | ||
127 | ~(ME_IO_IRQ_START_EXTENDED_STATUS | | ||
128 | ME_IO_IRQ_START_DIO_BYTE)) { | ||
129 | PERROR("Invalid flag specified.\n"); | ||
130 | return ME_ERRNO_INVALID_FLAGS; | ||
131 | } | ||
132 | |||
133 | if ((irq_edge != ME_IRQ_EDGE_RISING) | ||
134 | && (irq_edge != ME_IRQ_EDGE_FALLING) | ||
135 | && (irq_edge != ME_IRQ_EDGE_ANY)) { | ||
136 | PERROR("Invalid irq edge specified.\n"); | ||
137 | return ME_ERRNO_INVALID_IRQ_EDGE; | ||
138 | } | ||
139 | |||
140 | if (!(irq_arg & 0xFF)) { | ||
141 | PERROR("No mask specified.\n"); | ||
142 | return ME_ERRNO_INVALID_IRQ_ARG; | ||
143 | } | ||
144 | } else { | ||
145 | PERROR("Invalid irq source specified.\n"); | ||
146 | return ME_ERRNO_INVALID_IRQ_SOURCE; | ||
147 | } | ||
148 | |||
149 | if (channel) { | ||
150 | PERROR("Invalid channel specified.\n"); | ||
151 | return ME_ERRNO_INVALID_CHANNEL; | ||
152 | } | ||
153 | |||
154 | ME_SUBDEVICE_ENTER; | ||
155 | |||
156 | spin_lock_irqsave(&instance->subdevice_lock, status); | ||
157 | if (irq_source == ME_IRQ_SOURCE_DIO_PATTERN) { | ||
158 | outb(irq_arg, instance->compare_reg); | ||
159 | PDEBUG_REG("compare_reg outb(0x%lX+0x%lX)=0x%x\n", | ||
160 | instance->reg_base, | ||
161 | instance->compare_reg - instance->reg_base, irq_arg); | ||
162 | outb(0xFF, instance->mask_reg); | ||
163 | PDEBUG_REG("mask_reg outb(0x%lX+0x%lX)=0x%x\n", | ||
164 | instance->reg_base, | ||
165 | instance->mask_reg - instance->reg_base, 0xff); | ||
166 | instance->compare_value = irq_arg; | ||
167 | instance->filtering_flag = | ||
168 | (flags & ME_IO_IRQ_START_PATTERN_FILTERING) ? 1 : 0; | ||
169 | } | ||
170 | if (irq_source == ME_IRQ_SOURCE_DIO_MASK) { | ||
171 | outb(irq_arg, instance->mask_reg); | ||
172 | PDEBUG_REG("mask_reg outb(0x%lX+0x%lX)=0x%x\n", | ||
173 | instance->reg_base, | ||
174 | instance->mask_reg - instance->reg_base, irq_arg); | ||
175 | instance->filtering_flag = 0; | ||
176 | } | ||
177 | |||
178 | spin_lock(instance->irq_mode_lock); | ||
179 | tmp = inb(instance->irq_mode_reg); | ||
180 | tmp &= | ||
181 | ~(ME8200_IRQ_MODE_MASK << | ||
182 | (ME8200_IRQ_MODE_DI_SHIFT * instance->di_idx)); | ||
183 | if (irq_source == ME_IRQ_SOURCE_DIO_PATTERN) { | ||
184 | tmp |= | ||
185 | ME8200_IRQ_MODE_MASK_COMPARE << (ME8200_IRQ_MODE_DI_SHIFT * | ||
186 | instance->di_idx); | ||
187 | } | ||
188 | |||
189 | if (irq_source == ME_IRQ_SOURCE_DIO_MASK) { | ||
190 | tmp |= | ||
191 | ME8200_IRQ_MODE_MASK_MASK << (ME8200_IRQ_MODE_DI_SHIFT * | ||
192 | instance->di_idx); | ||
193 | } | ||
194 | outb(tmp, instance->irq_mode_reg); | ||
195 | PDEBUG_REG("irq_mode_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
196 | instance->irq_mode_reg - instance->reg_base, tmp); | ||
197 | spin_unlock(instance->irq_mode_lock); | ||
198 | |||
199 | spin_lock(instance->irq_ctrl_lock); | ||
200 | tmp = inb(instance->irq_ctrl_reg); | ||
201 | tmp |= | ||
202 | (ME8200_DI_IRQ_CTRL_BIT_CLEAR << | ||
203 | (ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx)); | ||
204 | tmp |= | ||
205 | ME8200_DI_IRQ_CTRL_BIT_ENABLE << (ME8200_DI_IRQ_CTRL_SHIFT * | ||
206 | instance->di_idx); | ||
207 | |||
208 | if (irq_source == ME_IRQ_SOURCE_DIO_MASK) { | ||
209 | tmp &= | ||
210 | ~(ME8200_DI_IRQ_CTRL_MASK_EDGE << | ||
211 | (ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx)); | ||
212 | if (irq_edge == ME_IRQ_EDGE_RISING) { | ||
213 | tmp |= | ||
214 | ME8200_DI_IRQ_CTRL_MASK_EDGE_RISING << | ||
215 | (ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx); | ||
216 | } else if (irq_edge == ME_IRQ_EDGE_FALLING) { | ||
217 | tmp |= | ||
218 | ME8200_DI_IRQ_CTRL_MASK_EDGE_FALLING << | ||
219 | (ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx); | ||
220 | } else if (irq_edge == ME_IRQ_EDGE_ANY) { | ||
221 | tmp |= | ||
222 | ME8200_DI_IRQ_CTRL_MASK_EDGE_ANY << | ||
223 | (ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx); | ||
224 | } | ||
225 | } | ||
226 | outb(tmp, instance->irq_ctrl_reg); | ||
227 | PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
228 | instance->irq_ctrl_reg - instance->reg_base, tmp); | ||
229 | tmp &= | ||
230 | ~(ME8200_DI_IRQ_CTRL_BIT_CLEAR << | ||
231 | (ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx)); | ||
232 | outb(tmp, instance->irq_ctrl_reg); | ||
233 | PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
234 | instance->irq_ctrl_reg - instance->reg_base, tmp); | ||
235 | |||
236 | instance->line_value = inb(instance->port_reg); | ||
237 | spin_unlock(instance->irq_ctrl_lock); | ||
238 | |||
239 | instance->rised = 0; | ||
240 | instance->status_value = 0; | ||
241 | instance->status_value_edges = 0; | ||
242 | instance->status_flag = flags & ME_IO_IRQ_START_EXTENDED_STATUS; | ||
243 | spin_unlock_irqrestore(&instance->subdevice_lock, status); | ||
244 | ME_SUBDEVICE_EXIT; | ||
245 | |||
246 | return err; | ||
247 | } | ||
248 | |||
249 | static int me8200_di_io_irq_wait(me_subdevice_t * subdevice, | ||
250 | struct file *filep, | ||
251 | int channel, | ||
252 | int *irq_count, | ||
253 | int *value, int time_out, int flags) | ||
254 | { | ||
255 | me8200_di_subdevice_t *instance; | ||
256 | int err = ME_ERRNO_SUCCESS; | ||
257 | long t = 0; | ||
258 | unsigned long cpu_flags; | ||
259 | int count; | ||
260 | |||
261 | PDEBUG("executed.\n"); | ||
262 | PDEVELOP("PID: %d.\n", current->pid); | ||
263 | |||
264 | instance = (me8200_di_subdevice_t *) subdevice; | ||
265 | |||
266 | if (flags & | ||
267 | ~(ME_IO_IRQ_WAIT_NORMAL_STATUS | ME_IO_IRQ_WAIT_EXTENDED_STATUS)) { | ||
268 | PERROR("Invalid flag specified.\n"); | ||
269 | return ME_ERRNO_INVALID_FLAGS; | ||
270 | } | ||
271 | |||
272 | if (channel) { | ||
273 | PERROR("Invalid channel specified.\n"); | ||
274 | return ME_ERRNO_INVALID_CHANNEL; | ||
275 | } | ||
276 | |||
277 | if (time_out < 0) { | ||
278 | PERROR("Invalid time_out specified.\n"); | ||
279 | return ME_ERRNO_INVALID_TIMEOUT; | ||
280 | } | ||
281 | |||
282 | if (time_out) { | ||
283 | t = (time_out * HZ) / 1000; | ||
284 | |||
285 | if (t == 0) | ||
286 | t = 1; | ||
287 | } | ||
288 | |||
289 | ME_SUBDEVICE_ENTER; | ||
290 | |||
291 | if (instance->rised <= 0) { | ||
292 | instance->rised = 0; | ||
293 | count = instance->count; | ||
294 | |||
295 | if (time_out) { | ||
296 | t = wait_event_interruptible_timeout(instance-> | ||
297 | wait_queue, | ||
298 | ((count != | ||
299 | instance->count) | ||
300 | || (instance-> | ||
301 | rised < 0)), | ||
302 | t); | ||
303 | // t = wait_event_interruptible_timeout(instance->wait_queue, (instance->rised != 0), t); | ||
304 | if (t == 0) { | ||
305 | PERROR("Wait on interrupt timed out.\n"); | ||
306 | err = ME_ERRNO_TIMEOUT; | ||
307 | } | ||
308 | } else { | ||
309 | wait_event_interruptible(instance->wait_queue, | ||
310 | ((count != instance->count) | ||
311 | || (instance->rised < 0))); | ||
312 | // wait_event_interruptible(instance->wait_queue, (instance->rised != 0)); | ||
313 | } | ||
314 | |||
315 | if (instance->rised < 0) { | ||
316 | PERROR("Wait on interrupt aborted by user.\n"); | ||
317 | err = ME_ERRNO_CANCELLED; | ||
318 | } | ||
319 | } | ||
320 | |||
321 | if (signal_pending(current)) { | ||
322 | PERROR("Wait on interrupt aborted by signal.\n"); | ||
323 | err = ME_ERRNO_SIGNAL; | ||
324 | } | ||
325 | |||
326 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
327 | *irq_count = instance->count; | ||
328 | if (!err) { | ||
329 | if (flags & ME_IO_IRQ_WAIT_NORMAL_STATUS) { | ||
330 | *value = instance->status_value; | ||
331 | } else if (flags & ME_IO_IRQ_WAIT_EXTENDED_STATUS) { | ||
332 | *value = instance->status_value_edges; | ||
333 | } else { // Use default | ||
334 | if (!instance->status_flag) { | ||
335 | *value = instance->status_value; | ||
336 | } else { | ||
337 | *value = instance->status_value_edges; | ||
338 | } | ||
339 | } | ||
340 | instance->rised = 0; | ||
341 | /* | ||
342 | instance->status_value = 0; | ||
343 | instance->status_value_edges = 0; | ||
344 | */ | ||
345 | } else { | ||
346 | *value = 0; | ||
347 | } | ||
348 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
349 | |||
350 | ME_SUBDEVICE_EXIT; | ||
351 | |||
352 | return err; | ||
353 | } | ||
354 | |||
355 | static int me8200_di_io_irq_stop(me_subdevice_t * subdevice, | ||
356 | struct file *filep, int channel, int flags) | ||
357 | { | ||
358 | me8200_di_subdevice_t *instance; | ||
359 | uint8_t tmp; | ||
360 | unsigned long status; | ||
361 | |||
362 | PDEBUG("executed.\n"); | ||
363 | |||
364 | instance = (me8200_di_subdevice_t *) subdevice; | ||
365 | |||
366 | if (flags) { | ||
367 | PERROR("Invalid flag specified.\n"); | ||
368 | return ME_ERRNO_INVALID_FLAGS; | ||
369 | } | ||
370 | |||
371 | if (channel) { | ||
372 | PERROR("Invalid channel specified.\n"); | ||
373 | return ME_ERRNO_INVALID_CHANNEL; | ||
374 | } | ||
375 | |||
376 | ME_SUBDEVICE_ENTER spin_lock_irqsave(&instance->subdevice_lock, status); | ||
377 | spin_lock(instance->irq_ctrl_lock); | ||
378 | tmp = inb(instance->irq_ctrl_reg); | ||
379 | tmp |= | ||
380 | (ME8200_DI_IRQ_CTRL_BIT_ENABLE << | ||
381 | (ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx)); | ||
382 | outb(tmp, instance->irq_ctrl_reg); | ||
383 | PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
384 | instance->irq_ctrl_reg - instance->reg_base, tmp); | ||
385 | tmp &= | ||
386 | ~(ME8200_DI_IRQ_CTRL_BIT_ENABLE << | ||
387 | (ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx)); | ||
388 | tmp |= | ||
389 | (ME8200_DI_IRQ_CTRL_BIT_CLEAR << | ||
390 | (ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx)); | ||
391 | // tmp &= ~(ME8200_DI_IRQ_CTRL_BIT_CLEAR << (ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx)); | ||
392 | outb(tmp, instance->irq_ctrl_reg); | ||
393 | PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
394 | instance->irq_ctrl_reg - instance->reg_base, tmp); | ||
395 | spin_unlock(instance->irq_ctrl_lock); | ||
396 | |||
397 | instance->rised = -1; | ||
398 | instance->status_value = 0; | ||
399 | instance->status_value_edges = 0; | ||
400 | instance->filtering_flag = 0; | ||
401 | spin_unlock_irqrestore(&instance->subdevice_lock, status); | ||
402 | wake_up_interruptible_all(&instance->wait_queue); | ||
403 | |||
404 | ME_SUBDEVICE_EXIT; | ||
405 | |||
406 | return ME_ERRNO_SUCCESS; | ||
407 | } | ||
408 | |||
409 | static int me8200_di_io_single_config(me_subdevice_t * subdevice, | ||
410 | struct file *filep, | ||
411 | int channel, | ||
412 | int single_config, | ||
413 | int ref, | ||
414 | int trig_chan, | ||
415 | int trig_type, int trig_edge, int flags) | ||
416 | { | ||
417 | me8200_di_subdevice_t *instance; | ||
418 | int err = ME_ERRNO_SUCCESS; | ||
419 | unsigned long status; | ||
420 | |||
421 | PDEBUG("executed.\n"); | ||
422 | |||
423 | instance = (me8200_di_subdevice_t *) subdevice; | ||
424 | |||
425 | ME_SUBDEVICE_ENTER; | ||
426 | |||
427 | spin_lock_irqsave(&instance->subdevice_lock, status); | ||
428 | |||
429 | switch (flags) { | ||
430 | case ME_IO_SINGLE_CONFIG_NO_FLAGS: | ||
431 | case ME_IO_SINGLE_CONFIG_DIO_BYTE: | ||
432 | if (channel == 0) { | ||
433 | if (single_config == ME_SINGLE_CONFIG_DIO_INPUT) { | ||
434 | } else { | ||
435 | PERROR("Invalid port direction specified.\n"); | ||
436 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
437 | } | ||
438 | } else { | ||
439 | PERROR("Invalid channel number.\n"); | ||
440 | err = ME_ERRNO_INVALID_CHANNEL; | ||
441 | } | ||
442 | break; | ||
443 | |||
444 | default: | ||
445 | PERROR("Invalid flags specified.\n"); | ||
446 | err = ME_ERRNO_INVALID_FLAGS; | ||
447 | } | ||
448 | |||
449 | spin_unlock_irqrestore(&instance->subdevice_lock, status); | ||
450 | |||
451 | ME_SUBDEVICE_EXIT; | ||
452 | |||
453 | return err; | ||
454 | } | ||
455 | |||
456 | static int me8200_di_io_single_read(me_subdevice_t * subdevice, | ||
457 | struct file *filep, | ||
458 | int channel, | ||
459 | int *value, int time_out, int flags) | ||
460 | { | ||
461 | me8200_di_subdevice_t *instance; | ||
462 | int err = ME_ERRNO_SUCCESS; | ||
463 | unsigned long status; | ||
464 | |||
465 | PDEBUG("executed.\n"); | ||
466 | |||
467 | instance = (me8200_di_subdevice_t *) subdevice; | ||
468 | |||
469 | ME_SUBDEVICE_ENTER; | ||
470 | |||
471 | spin_lock_irqsave(&instance->subdevice_lock, status); | ||
472 | |||
473 | switch (flags) { | ||
474 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
475 | if ((channel >= 0) && (channel < 8)) { | ||
476 | *value = inb(instance->port_reg) & (0x1 << channel); | ||
477 | } else { | ||
478 | PERROR("Invalid bit number specified.\n"); | ||
479 | err = ME_ERRNO_INVALID_CHANNEL; | ||
480 | } | ||
481 | break; | ||
482 | |||
483 | case ME_IO_SINGLE_NO_FLAGS: | ||
484 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
485 | if (channel == 0) { | ||
486 | *value = inb(instance->port_reg); | ||
487 | } else { | ||
488 | PERROR("Invalid channel number.\n"); | ||
489 | err = ME_ERRNO_INVALID_CHANNEL; | ||
490 | } | ||
491 | break; | ||
492 | |||
493 | default: | ||
494 | PERROR("Invalid flags specified.\n"); | ||
495 | err = ME_ERRNO_INVALID_FLAGS; | ||
496 | } | ||
497 | |||
498 | spin_unlock_irqrestore(&instance->subdevice_lock, status); | ||
499 | |||
500 | ME_SUBDEVICE_EXIT; | ||
501 | |||
502 | return err; | ||
503 | } | ||
504 | |||
505 | static int me8200_di_io_reset_subdevice(struct me_subdevice *subdevice, | ||
506 | struct file *filep, int flags) | ||
507 | { | ||
508 | me8200_di_subdevice_t *instance = (me8200_di_subdevice_t *) subdevice; | ||
509 | |||
510 | PDEBUG("executed.\n"); | ||
511 | |||
512 | if (flags) { | ||
513 | PERROR("Invalid flag specified.\n"); | ||
514 | return ME_ERRNO_INVALID_FLAGS; | ||
515 | } | ||
516 | |||
517 | instance->count = 0; | ||
518 | return me8200_di_io_irq_stop(subdevice, filep, 0, 0); | ||
519 | } | ||
520 | |||
521 | static int me8200_di_query_number_channels(me_subdevice_t * subdevice, | ||
522 | int *number) | ||
523 | { | ||
524 | PDEBUG("executed.\n"); | ||
525 | *number = 8; | ||
526 | return ME_ERRNO_SUCCESS; | ||
527 | } | ||
528 | |||
529 | static int me8200_di_query_subdevice_type(me_subdevice_t * subdevice, | ||
530 | int *type, int *subtype) | ||
531 | { | ||
532 | PDEBUG("executed.\n"); | ||
533 | *type = ME_TYPE_DI; | ||
534 | *subtype = ME_SUBTYPE_SINGLE; | ||
535 | return ME_ERRNO_SUCCESS; | ||
536 | } | ||
537 | |||
538 | static int me8200_di_query_subdevice_caps(me_subdevice_t * subdevice, int *caps) | ||
539 | { | ||
540 | PDEBUG("executed.\n"); | ||
541 | *caps = | ||
542 | ME_CAPS_DIO_BIT_PATTERN_IRQ | | ||
543 | ME_CAPS_DIO_BIT_MASK_IRQ_EDGE_RISING | | ||
544 | ME_CAPS_DIO_BIT_MASK_IRQ_EDGE_FALLING | | ||
545 | ME_CAPS_DIO_BIT_MASK_IRQ_EDGE_ANY; | ||
546 | return ME_ERRNO_SUCCESS; | ||
547 | } | ||
548 | |||
549 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) | ||
550 | static irqreturn_t me8200_isr(int irq, void *dev_id) | ||
551 | #else | ||
552 | static irqreturn_t me8200_isr(int irq, void *dev_id, struct pt_regs *regs) | ||
553 | #endif | ||
554 | { | ||
555 | me8200_di_subdevice_t *instance; | ||
556 | uint8_t ctrl; | ||
557 | uint8_t irq_status; | ||
558 | uint8_t line_value = 0; | ||
559 | uint8_t line_status = 0; | ||
560 | uint32_t status_val = 0; | ||
561 | |||
562 | instance = (me8200_di_subdevice_t *) dev_id; | ||
563 | |||
564 | if (irq != instance->irq) { | ||
565 | PERROR("Incorrect interrupt num: %d.\n", irq); | ||
566 | return IRQ_NONE; | ||
567 | } | ||
568 | |||
569 | irq_status = inb(instance->irq_status_reg); | ||
570 | if (!irq_status) { | ||
571 | PINFO | ||
572 | ("%ld Shared interrupt. %s(): idx=%d irq_status_reg=0x%04X\n", | ||
573 | jiffies, __FUNCTION__, instance->di_idx, irq_status); | ||
574 | return IRQ_NONE; | ||
575 | } | ||
576 | |||
577 | PDEBUG("executed.\n"); | ||
578 | |||
579 | spin_lock(&instance->subdevice_lock); | ||
580 | spin_lock(instance->irq_ctrl_lock); | ||
581 | ctrl = inb(instance->irq_ctrl_reg); | ||
582 | ctrl |= | ||
583 | ME8200_DI_IRQ_CTRL_BIT_CLEAR << (ME8200_DI_IRQ_CTRL_SHIFT * | ||
584 | instance->di_idx); | ||
585 | outb(ctrl, instance->irq_ctrl_reg); | ||
586 | PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
587 | instance->irq_ctrl_reg - instance->reg_base, ctrl); | ||
588 | ctrl &= | ||
589 | ~(ME8200_DI_IRQ_CTRL_BIT_CLEAR << | ||
590 | (ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx)); | ||
591 | outb(ctrl, instance->irq_ctrl_reg); | ||
592 | PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
593 | instance->irq_ctrl_reg - instance->reg_base, ctrl); | ||
594 | |||
595 | line_value = inb(instance->port_reg); | ||
596 | spin_unlock(instance->irq_ctrl_lock); | ||
597 | |||
598 | line_status = ((uint8_t) instance->line_value ^ line_value); | ||
599 | |||
600 | // Make extended information. | ||
601 | status_val |= (0x00FF & (~(uint8_t) instance->line_value & line_value)) << 16; //Raise | ||
602 | status_val |= (0x00FF & ((uint8_t) instance->line_value & ~line_value)); //Fall | ||
603 | |||
604 | instance->line_value = (int)line_value; | ||
605 | |||
606 | if (instance->rised == 0) { | ||
607 | instance->status_value = irq_status | line_status; | ||
608 | instance->status_value_edges = status_val; | ||
609 | } else { | ||
610 | instance->status_value |= irq_status | line_status; | ||
611 | instance->status_value_edges |= status_val; | ||
612 | } | ||
613 | |||
614 | if (instance->filtering_flag) { // For compare mode only. | ||
615 | if (instance->compare_value == instance->line_value) { | ||
616 | instance->rised = 1; | ||
617 | instance->count++; | ||
618 | } | ||
619 | } else { | ||
620 | instance->rised = 1; | ||
621 | instance->count++; | ||
622 | } | ||
623 | spin_unlock(&instance->subdevice_lock); | ||
624 | |||
625 | spin_unlock(&instance->subdevice_lock); | ||
626 | |||
627 | wake_up_interruptible_all(&instance->wait_queue); | ||
628 | |||
629 | return IRQ_HANDLED; | ||
630 | } | ||
631 | |||
632 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) | ||
633 | static irqreturn_t me8200_isr_EX(int irq, void *dev_id) | ||
634 | #else | ||
635 | static irqreturn_t me8200_isr_EX(int irq, void *dev_id, struct pt_regs *regs) | ||
636 | #endif | ||
637 | { | ||
638 | me8200_di_subdevice_t *instance; | ||
639 | uint8_t irq_status = 0; | ||
640 | uint16_t irq_status_EX = 0; | ||
641 | uint32_t status_val = 0; | ||
642 | int i, j; | ||
643 | |||
644 | instance = (me8200_di_subdevice_t *) dev_id; | ||
645 | |||
646 | if (irq != instance->irq) { | ||
647 | PERROR("Incorrect interrupt num: %d.\n", irq); | ||
648 | return IRQ_NONE; | ||
649 | } | ||
650 | |||
651 | PDEBUG("executed.\n"); | ||
652 | |||
653 | //Reset latches. Copy status to extended registers. | ||
654 | irq_status = inb(instance->irq_status_reg); | ||
655 | PDEBUG_REG("idx=%d irq_status_reg=0x%02X\n", instance->di_idx, | ||
656 | irq_status); | ||
657 | |||
658 | if (!irq_status) { | ||
659 | PINFO | ||
660 | ("%ld Shared interrupt. %s(): idx=%d irq_status_reg=0x%04X\n", | ||
661 | jiffies, __FUNCTION__, instance->di_idx, irq_status); | ||
662 | return IRQ_NONE; | ||
663 | } | ||
664 | |||
665 | irq_status_EX = inb(instance->irq_status_low_reg); | ||
666 | irq_status_EX |= (inb(instance->irq_status_high_reg) << 8); | ||
667 | |||
668 | PDEVELOP("EXTENDED REG: 0x%04x\n", irq_status_EX); | ||
669 | instance->line_value = inb(instance->port_reg); | ||
670 | |||
671 | // Format extended information. | ||
672 | for (i = 0, j = 0; i < 8; i++, j += 2) { | ||
673 | status_val |= ((0x01 << j) & irq_status_EX) >> (j - i); //Fall | ||
674 | status_val |= ((0x01 << (j + 1)) & irq_status_EX) << (15 - j + i); //Raise | ||
675 | } | ||
676 | |||
677 | spin_lock(&instance->subdevice_lock); | ||
678 | if (instance->rised == 0) { | ||
679 | instance->status_value = irq_status; | ||
680 | instance->status_value_edges = status_val; | ||
681 | } else { | ||
682 | instance->status_value |= irq_status; | ||
683 | instance->status_value_edges |= status_val; | ||
684 | } | ||
685 | |||
686 | if (instance->filtering_flag) { // For compare mode only. | ||
687 | if (instance->compare_value == instance->line_value) { | ||
688 | instance->rised = 1; | ||
689 | instance->count++; | ||
690 | } | ||
691 | } else { | ||
692 | instance->rised = 1; | ||
693 | instance->count++; | ||
694 | } | ||
695 | spin_unlock(&instance->subdevice_lock); | ||
696 | |||
697 | wake_up_interruptible_all(&instance->wait_queue); | ||
698 | |||
699 | return IRQ_HANDLED; | ||
700 | } | ||
701 | |||
702 | static void me8200_di_destructor(struct me_subdevice *subdevice) | ||
703 | { | ||
704 | me8200_di_subdevice_t *instance; | ||
705 | |||
706 | PDEBUG("executed.\n"); | ||
707 | |||
708 | instance = (me8200_di_subdevice_t *) subdevice; | ||
709 | |||
710 | free_irq(instance->irq, (void *)instance); | ||
711 | me_subdevice_deinit(&instance->base); | ||
712 | kfree(instance); | ||
713 | } | ||
714 | |||
715 | me8200_di_subdevice_t *me8200_di_constructor(uint32_t me8200_regbase, | ||
716 | unsigned int di_idx, | ||
717 | int irq, | ||
718 | spinlock_t * irq_ctrl_lock, | ||
719 | spinlock_t * irq_mode_lock) | ||
720 | { | ||
721 | me8200_di_subdevice_t *subdevice; | ||
722 | int err; | ||
723 | |||
724 | PDEBUG("executed.\n"); | ||
725 | |||
726 | /* Allocate memory for subdevice instance */ | ||
727 | subdevice = kmalloc(sizeof(me8200_di_subdevice_t), GFP_KERNEL); | ||
728 | |||
729 | if (!subdevice) { | ||
730 | PERROR("Cannot get memory for subdevice instance.\n"); | ||
731 | return NULL; | ||
732 | } | ||
733 | |||
734 | memset(subdevice, 0, sizeof(me8200_di_subdevice_t)); | ||
735 | |||
736 | /* Initialize subdevice base class */ | ||
737 | err = me_subdevice_init(&subdevice->base); | ||
738 | |||
739 | if (err) { | ||
740 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
741 | kfree(subdevice); | ||
742 | return NULL; | ||
743 | } | ||
744 | // Check firmware version. | ||
745 | me8200_di_check_version(subdevice, | ||
746 | me8200_regbase + ME8200_FIRMWARE_VERSION_REG); | ||
747 | |||
748 | // Initialize spin locks. | ||
749 | spin_lock_init(&subdevice->subdevice_lock); | ||
750 | |||
751 | subdevice->irq_ctrl_lock = irq_ctrl_lock; | ||
752 | subdevice->irq_mode_lock = irq_mode_lock; | ||
753 | |||
754 | /* Save the subdevice index. */ | ||
755 | subdevice->di_idx = di_idx; | ||
756 | |||
757 | /* Initialize registers */ | ||
758 | if (di_idx == 0) { | ||
759 | subdevice->port_reg = me8200_regbase + ME8200_DI_PORT_0_REG; | ||
760 | subdevice->mask_reg = me8200_regbase + ME8200_DI_MASK_0_REG; | ||
761 | subdevice->compare_reg = | ||
762 | me8200_regbase + ME8200_DI_COMPARE_0_REG; | ||
763 | subdevice->irq_status_reg = | ||
764 | me8200_regbase + ME8200_DI_CHANGE_0_REG; | ||
765 | |||
766 | subdevice->irq_status_low_reg = | ||
767 | me8200_regbase + ME8200_DI_EXTEND_CHANGE_0_LOW_REG; | ||
768 | subdevice->irq_status_high_reg = | ||
769 | me8200_regbase + ME8200_DI_EXTEND_CHANGE_0_HIGH_REG; | ||
770 | } else if (di_idx == 1) { | ||
771 | subdevice->port_reg = me8200_regbase + ME8200_DI_PORT_1_REG; | ||
772 | subdevice->mask_reg = me8200_regbase + ME8200_DI_MASK_1_REG; | ||
773 | subdevice->compare_reg = | ||
774 | me8200_regbase + ME8200_DI_COMPARE_1_REG; | ||
775 | subdevice->irq_status_reg = | ||
776 | me8200_regbase + ME8200_DI_CHANGE_1_REG; | ||
777 | |||
778 | subdevice->irq_status_low_reg = | ||
779 | me8200_regbase + ME8200_DI_EXTEND_CHANGE_1_LOW_REG; | ||
780 | subdevice->irq_status_high_reg = | ||
781 | me8200_regbase + ME8200_DI_EXTEND_CHANGE_1_HIGH_REG; | ||
782 | } else { | ||
783 | PERROR("Wrong subdevice idx=%d.\n", di_idx); | ||
784 | kfree(subdevice); | ||
785 | return NULL; | ||
786 | } | ||
787 | subdevice->irq_ctrl_reg = me8200_regbase + ME8200_DI_IRQ_CTRL_REG; | ||
788 | subdevice->irq_mode_reg = me8200_regbase + ME8200_IRQ_MODE_REG; | ||
789 | #ifdef MEDEBUG_DEBUG_REG | ||
790 | subdevice->reg_base = me8200_regbase; | ||
791 | #endif | ||
792 | |||
793 | /* Initialize wait queue */ | ||
794 | init_waitqueue_head(&subdevice->wait_queue); | ||
795 | |||
796 | /* Overload base class methods. */ | ||
797 | subdevice->base.me_subdevice_io_irq_start = me8200_di_io_irq_start; | ||
798 | subdevice->base.me_subdevice_io_irq_wait = me8200_di_io_irq_wait; | ||
799 | subdevice->base.me_subdevice_io_irq_stop = me8200_di_io_irq_stop; | ||
800 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
801 | me8200_di_io_reset_subdevice; | ||
802 | subdevice->base.me_subdevice_io_single_config = | ||
803 | me8200_di_io_single_config; | ||
804 | subdevice->base.me_subdevice_io_single_read = me8200_di_io_single_read; | ||
805 | subdevice->base.me_subdevice_query_number_channels = | ||
806 | me8200_di_query_number_channels; | ||
807 | subdevice->base.me_subdevice_query_subdevice_type = | ||
808 | me8200_di_query_subdevice_type; | ||
809 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
810 | me8200_di_query_subdevice_caps; | ||
811 | subdevice->base.me_subdevice_destructor = me8200_di_destructor; | ||
812 | |||
813 | subdevice->rised = 0; | ||
814 | subdevice->count = 0; | ||
815 | |||
816 | /* Register interrupt service routine. */ | ||
817 | subdevice->irq = irq; | ||
818 | if (subdevice->version > 0) { // NEW | ||
819 | err = request_irq(subdevice->irq, me8200_isr_EX, | ||
820 | #ifdef IRQF_DISABLED | ||
821 | IRQF_DISABLED | IRQF_SHARED, | ||
822 | #else | ||
823 | SA_INTERRUPT | SA_SHIRQ, | ||
824 | #endif | ||
825 | ME8200_NAME, (void *)subdevice); | ||
826 | } else { //OLD | ||
827 | err = request_irq(subdevice->irq, me8200_isr, | ||
828 | #ifdef IRQF_DISABLED | ||
829 | IRQF_DISABLED | IRQF_SHARED, | ||
830 | #else | ||
831 | SA_INTERRUPT | SA_SHIRQ, | ||
832 | #endif | ||
833 | ME8200_NAME, (void *)subdevice); | ||
834 | } | ||
835 | |||
836 | if (err) { | ||
837 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
838 | kfree(subdevice); | ||
839 | return NULL; | ||
840 | } | ||
841 | PDEBUG("Registred irq=%d.\n", subdevice->irq); | ||
842 | |||
843 | return subdevice; | ||
844 | } | ||
845 | |||
846 | static void me8200_di_check_version(me8200_di_subdevice_t * instance, | ||
847 | unsigned long addr) | ||
848 | { | ||
849 | |||
850 | PDEBUG("executed.\n"); | ||
851 | instance->version = 0x000000FF & inb(addr); | ||
852 | PDEVELOP("me8200 firmware version: %d\n", instance->version); | ||
853 | |||
854 | /// @note Fix for wrong values in this registry. | ||
855 | if ((instance->version < 0x7) || (instance->version > 0x1F)) | ||
856 | instance->version = 0x0; | ||
857 | } | ||
diff --git a/drivers/staging/meilhaus/me8200_di.h b/drivers/staging/meilhaus/me8200_di.h new file mode 100644 index 000000000000..2a3b005b67d4 --- /dev/null +++ b/drivers/staging/meilhaus/me8200_di.h | |||
@@ -0,0 +1,92 @@ | |||
1 | /** | ||
2 | * @file me8200_di.h | ||
3 | * | ||
4 | * @brief ME-8200 digital input subdevice class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME8200_DI_H_ | ||
28 | #define _ME8200_DI_H_ | ||
29 | |||
30 | #include "mesubdevice.h" | ||
31 | |||
32 | #ifdef __KERNEL__ | ||
33 | |||
34 | /** | ||
35 | * @brief The template subdevice class. | ||
36 | */ | ||
37 | typedef struct me8200_di_subdevice { | ||
38 | /* Inheritance */ | ||
39 | me_subdevice_t base; /**< The subdevice base class. */ | ||
40 | |||
41 | /* Attributes */ | ||
42 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
43 | spinlock_t *ctrl_reg_lock; | ||
44 | spinlock_t *irq_ctrl_lock; | ||
45 | spinlock_t *irq_mode_lock; | ||
46 | |||
47 | unsigned int di_idx; | ||
48 | unsigned int version; | ||
49 | |||
50 | int irq; /**< The number of the interrupt request. */ | ||
51 | volatile int rised; /**< Flag to indicate if an interrupt occured. */ | ||
52 | uint status_flag; /**< Default interupt status flag */ | ||
53 | uint status_value; /**< Interupt status */ | ||
54 | uint status_value_edges; /**< Extended interupt status */ | ||
55 | uint line_value; | ||
56 | int count; /**< Counts the number of interrupts occured. */ | ||
57 | uint8_t compare_value; | ||
58 | uint8_t filtering_flag; | ||
59 | |||
60 | wait_queue_head_t wait_queue; /**< To wait on interrupts. */ | ||
61 | |||
62 | unsigned long port_reg; /**< The digital input port. */ | ||
63 | unsigned long compare_reg; /**< The register to hold the value to compare with. */ | ||
64 | unsigned long mask_reg; /**< The register to hold the mask. */ | ||
65 | unsigned long irq_mode_reg; /**< The interrupt mode register. */ | ||
66 | unsigned long irq_ctrl_reg; /**< The interrupt control register. */ | ||
67 | unsigned long irq_status_reg; /**< The interrupt status register. Also interrupt reseting register (firmware version 7 and later).*/ | ||
68 | #ifdef MEDEBUG_DEBUG_REG | ||
69 | unsigned long reg_base; | ||
70 | #endif | ||
71 | unsigned long firmware_version_reg; /**< The interrupt reseting register. */ | ||
72 | |||
73 | unsigned long irq_status_low_reg; /**< The interrupt extended status register (low part). */ | ||
74 | unsigned long irq_status_high_reg; /**< The interrupt extended status register (high part). */ | ||
75 | } me8200_di_subdevice_t; | ||
76 | |||
77 | /** | ||
78 | * @brief The constructor to generate a ME-8200 digital input subdevice instance. | ||
79 | * | ||
80 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
81 | * | ||
82 | * @return Pointer to new instance on success.\n | ||
83 | * NULL on error. | ||
84 | */ | ||
85 | me8200_di_subdevice_t *me8200_di_constructor(uint32_t me8200_reg_base, | ||
86 | unsigned int di_idx, | ||
87 | int irq, | ||
88 | spinlock_t * irq_ctrl_lock, | ||
89 | spinlock_t * irq_mode_lock); | ||
90 | |||
91 | #endif | ||
92 | #endif | ||
diff --git a/drivers/staging/meilhaus/me8200_di_reg.h b/drivers/staging/meilhaus/me8200_di_reg.h new file mode 100644 index 000000000000..b9a619d31c2c --- /dev/null +++ b/drivers/staging/meilhaus/me8200_di_reg.h | |||
@@ -0,0 +1,75 @@ | |||
1 | /** | ||
2 | * @file me8200_di_reg.h | ||
3 | * | ||
4 | * @brief ME-8200 digital input subdevice register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME8200_DI_REG_H_ | ||
28 | #define _ME8200_DI_REG_H_ | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | // Common registry for whole family. | ||
33 | #define ME8200_DI_PORT_0_REG 0x3 // R | ||
34 | #define ME8200_DI_PORT_1_REG 0x4 // R | ||
35 | |||
36 | #define ME8200_DI_MASK_0_REG 0x5 // R/W | ||
37 | #define ME8200_DI_MASK_1_REG 0x6 // R/W | ||
38 | |||
39 | #define ME8200_DI_COMPARE_0_REG 0xA // R/W | ||
40 | #define ME8200_DI_COMPARE_1_REG 0xB // R/W | ||
41 | |||
42 | #define ME8200_DI_IRQ_CTRL_REG 0xC // R/W | ||
43 | |||
44 | #ifndef ME8200_IRQ_MODE_REG | ||
45 | # define ME8200_IRQ_MODE_REG 0xD // R/W | ||
46 | #endif | ||
47 | |||
48 | // This registry are for all versions | ||
49 | #define ME8200_DI_CHANGE_0_REG 0xE // R | ||
50 | #define ME8200_DI_CHANGE_1_REG 0xF // R | ||
51 | |||
52 | #define ME8200_DI_IRQ_CTRL_BIT_CLEAR 0x4 | ||
53 | #define ME8200_DI_IRQ_CTRL_BIT_ENABLE 0x8 | ||
54 | |||
55 | // This registry are for firmware versions 7 and later | ||
56 | #define ME8200_DI_EXTEND_CHANGE_0_LOW_REG 0x10 // R | ||
57 | #define ME8200_DI_EXTEND_CHANGE_0_HIGH_REG 0x11 // R | ||
58 | #define ME8200_DI_EXTEND_CHANGE_1_LOW_REG 0x12 // R | ||
59 | #define ME8200_DI_EXTEND_CHANGE_1_HIGH_REG 0x13 // R | ||
60 | |||
61 | #ifndef ME8200_FIRMWARE_VERSION_REG | ||
62 | # define ME8200_FIRMWARE_VERSION_REG 0x14 // R | ||
63 | #endif | ||
64 | |||
65 | // Bit definitions | ||
66 | #define ME8200_DI_IRQ_CTRL_MASK_EDGE 0x3 | ||
67 | #define ME8200_DI_IRQ_CTRL_MASK_EDGE_RISING 0x0 | ||
68 | #define ME8200_DI_IRQ_CTRL_MASK_EDGE_FALLING 0x1 | ||
69 | #define ME8200_DI_IRQ_CTRL_MASK_EDGE_ANY 0x3 | ||
70 | |||
71 | // Others | ||
72 | #define ME8200_DI_IRQ_CTRL_SHIFT 4 | ||
73 | |||
74 | #endif | ||
75 | #endif | ||
diff --git a/drivers/staging/meilhaus/me8200_dio.c b/drivers/staging/meilhaus/me8200_dio.c new file mode 100644 index 000000000000..ff8ca1b8b7f3 --- /dev/null +++ b/drivers/staging/meilhaus/me8200_dio.c | |||
@@ -0,0 +1,418 @@ | |||
1 | /** | ||
2 | * @file me8200_dio.c | ||
3 | * | ||
4 | * @brief ME-8200 digital input/output subdevice instance. | ||
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 | /* | ||
33 | * Includes | ||
34 | */ | ||
35 | #include <linux/module.h> | ||
36 | |||
37 | #include <linux/slab.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | #include <asm/io.h> | ||
40 | #include <linux/types.h> | ||
41 | |||
42 | #include "medefines.h" | ||
43 | #include "meinternal.h" | ||
44 | #include "meerror.h" | ||
45 | |||
46 | #include "medebug.h" | ||
47 | #include "me8200_dio_reg.h" | ||
48 | #include "me8200_dio.h" | ||
49 | |||
50 | /* | ||
51 | * Defines | ||
52 | */ | ||
53 | |||
54 | /* | ||
55 | * Functions | ||
56 | */ | ||
57 | |||
58 | static int me8200_dio_io_reset_subdevice(struct me_subdevice *subdevice, | ||
59 | struct file *filep, int flags) | ||
60 | { | ||
61 | me8200_dio_subdevice_t *instance; | ||
62 | uint8_t mode; | ||
63 | |||
64 | PDEBUG("executed.\n"); | ||
65 | |||
66 | if (flags) { | ||
67 | PERROR("Invalid flag specified.\n"); | ||
68 | return ME_ERRNO_INVALID_FLAGS; | ||
69 | } | ||
70 | |||
71 | instance = (me8200_dio_subdevice_t *) subdevice; | ||
72 | |||
73 | ME_SUBDEVICE_ENTER; | ||
74 | |||
75 | spin_lock(&instance->subdevice_lock); | ||
76 | spin_lock(instance->ctrl_reg_lock); | ||
77 | mode = inb(instance->ctrl_reg); | ||
78 | mode &= ~(0x3 << (instance->dio_idx * 2)); | ||
79 | outb(mode, instance->ctrl_reg); | ||
80 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
81 | instance->ctrl_reg - instance->reg_base, mode); | ||
82 | spin_unlock(instance->ctrl_reg_lock); | ||
83 | outb(0x00, instance->port_reg); | ||
84 | PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
85 | instance->port_reg - instance->reg_base, 0x00); | ||
86 | spin_unlock(&instance->subdevice_lock); | ||
87 | |||
88 | ME_SUBDEVICE_EXIT; | ||
89 | |||
90 | return ME_ERRNO_SUCCESS; | ||
91 | } | ||
92 | |||
93 | static int me8200_dio_io_single_config(me_subdevice_t * subdevice, | ||
94 | struct file *filep, | ||
95 | int channel, | ||
96 | int single_config, | ||
97 | int ref, | ||
98 | int trig_chan, | ||
99 | int trig_type, int trig_edge, int flags) | ||
100 | { | ||
101 | me8200_dio_subdevice_t *instance; | ||
102 | int err = ME_ERRNO_SUCCESS; | ||
103 | uint32_t mode; | ||
104 | uint32_t size = | ||
105 | flags & (ME_IO_SINGLE_CONFIG_DIO_BIT | ME_IO_SINGLE_CONFIG_DIO_BYTE | ||
106 | | ME_IO_SINGLE_CONFIG_DIO_WORD | | ||
107 | ME_IO_SINGLE_CONFIG_DIO_DWORD); | ||
108 | |||
109 | PDEBUG("executed.\n"); | ||
110 | |||
111 | instance = (me8200_dio_subdevice_t *) subdevice; | ||
112 | |||
113 | ME_SUBDEVICE_ENTER; | ||
114 | |||
115 | spin_lock(&instance->subdevice_lock); | ||
116 | spin_lock(instance->ctrl_reg_lock); | ||
117 | mode = inb(instance->ctrl_reg); | ||
118 | switch (size) { | ||
119 | case ME_IO_SINGLE_CONFIG_NO_FLAGS: | ||
120 | case ME_IO_SINGLE_CONFIG_DIO_BYTE: | ||
121 | if (channel == 0) { | ||
122 | if (single_config == ME_SINGLE_CONFIG_DIO_INPUT) { | ||
123 | mode &= | ||
124 | ~((ME8200_DIO_CTRL_BIT_MODE_0 | | ||
125 | ME8200_DIO_CTRL_BIT_MODE_1) << | ||
126 | (instance->dio_idx * 2)); | ||
127 | } else if (single_config == ME_SINGLE_CONFIG_DIO_OUTPUT) { | ||
128 | mode &= | ||
129 | ~((ME8200_DIO_CTRL_BIT_MODE_0 | | ||
130 | ME8200_DIO_CTRL_BIT_MODE_1) << | ||
131 | (instance->dio_idx * 2)); | ||
132 | mode |= | ||
133 | ME8200_DIO_CTRL_BIT_MODE_0 << (instance-> | ||
134 | dio_idx * 2); | ||
135 | } else { | ||
136 | PERROR | ||
137 | ("Invalid port configuration specified.\n"); | ||
138 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
139 | } | ||
140 | } else { | ||
141 | PERROR("Invalid channel number.\n"); | ||
142 | err = ME_ERRNO_INVALID_CHANNEL; | ||
143 | } | ||
144 | |||
145 | break; | ||
146 | |||
147 | default: | ||
148 | PERROR("Invalid flags.\n"); | ||
149 | |||
150 | err = ME_ERRNO_INVALID_FLAGS; | ||
151 | } | ||
152 | |||
153 | if (!err) { | ||
154 | outb(mode, instance->ctrl_reg); | ||
155 | PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
156 | instance->reg_base, | ||
157 | instance->ctrl_reg - instance->reg_base, mode); | ||
158 | } | ||
159 | spin_unlock(instance->ctrl_reg_lock); | ||
160 | spin_unlock(&instance->subdevice_lock); | ||
161 | |||
162 | ME_SUBDEVICE_EXIT; | ||
163 | |||
164 | return err; | ||
165 | } | ||
166 | |||
167 | static int me8200_dio_io_single_read(me_subdevice_t * subdevice, | ||
168 | struct file *filep, | ||
169 | int channel, | ||
170 | int *value, int time_out, int flags) | ||
171 | { | ||
172 | me8200_dio_subdevice_t *instance; | ||
173 | int err = ME_ERRNO_SUCCESS; | ||
174 | uint8_t mode; | ||
175 | |||
176 | PDEBUG("executed.\n"); | ||
177 | |||
178 | instance = (me8200_dio_subdevice_t *) subdevice; | ||
179 | |||
180 | ME_SUBDEVICE_ENTER; | ||
181 | |||
182 | spin_lock(&instance->subdevice_lock); | ||
183 | spin_lock(instance->ctrl_reg_lock); | ||
184 | switch (flags) { | ||
185 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
186 | if ((channel >= 0) && (channel < 8)) { | ||
187 | mode = | ||
188 | inb(instance-> | ||
189 | ctrl_reg) & ((ME8200_DIO_CTRL_BIT_MODE_0 | | ||
190 | ME8200_DIO_CTRL_BIT_MODE_1) << | ||
191 | (instance->dio_idx * 2)); | ||
192 | |||
193 | if ((mode == | ||
194 | (ME8200_DIO_CTRL_BIT_MODE_0 << | ||
195 | (instance->dio_idx * 2))) || !mode) { | ||
196 | *value = | ||
197 | inb(instance-> | ||
198 | port_reg) & (0x0001 << channel); | ||
199 | } else { | ||
200 | PERROR("Port not in output or input mode.\n"); | ||
201 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
202 | } | ||
203 | } else { | ||
204 | PERROR("Invalid bit number specified.\n"); | ||
205 | err = ME_ERRNO_INVALID_CHANNEL; | ||
206 | } | ||
207 | break; | ||
208 | |||
209 | case ME_IO_SINGLE_NO_FLAGS: | ||
210 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
211 | if (channel == 0) { | ||
212 | mode = | ||
213 | inb(instance-> | ||
214 | ctrl_reg) & ((ME8200_DIO_CTRL_BIT_MODE_0 | | ||
215 | ME8200_DIO_CTRL_BIT_MODE_1) << | ||
216 | (instance->dio_idx * 2)); | ||
217 | |||
218 | if ((mode == | ||
219 | (ME8200_DIO_CTRL_BIT_MODE_0 << | ||
220 | (instance->dio_idx * 2))) || !mode) { | ||
221 | *value = inb(instance->port_reg) & 0x00FF; | ||
222 | } else { | ||
223 | PERROR("Port not in output or input mode.\n"); | ||
224 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
225 | } | ||
226 | } else { | ||
227 | PERROR("Invalid byte number specified.\n"); | ||
228 | err = ME_ERRNO_INVALID_CHANNEL; | ||
229 | } | ||
230 | break; | ||
231 | |||
232 | default: | ||
233 | PERROR("Invalid flags specified.\n"); | ||
234 | err = ME_ERRNO_INVALID_FLAGS; | ||
235 | } | ||
236 | spin_unlock(instance->ctrl_reg_lock); | ||
237 | spin_unlock(&instance->subdevice_lock); | ||
238 | |||
239 | ME_SUBDEVICE_EXIT; | ||
240 | |||
241 | return err; | ||
242 | } | ||
243 | |||
244 | static int me8200_dio_io_single_write(me_subdevice_t * subdevice, | ||
245 | struct file *filep, | ||
246 | int channel, | ||
247 | int value, int time_out, int flags) | ||
248 | { | ||
249 | me8200_dio_subdevice_t *instance; | ||
250 | int err = ME_ERRNO_SUCCESS; | ||
251 | uint8_t mode; | ||
252 | uint8_t byte; | ||
253 | |||
254 | PDEBUG("executed.\n"); | ||
255 | |||
256 | instance = (me8200_dio_subdevice_t *) subdevice; | ||
257 | |||
258 | ME_SUBDEVICE_ENTER; | ||
259 | |||
260 | spin_lock(&instance->subdevice_lock); | ||
261 | spin_lock(instance->ctrl_reg_lock); | ||
262 | switch (flags) { | ||
263 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
264 | if ((channel >= 0) && (channel < 8)) { | ||
265 | mode = | ||
266 | inb(instance-> | ||
267 | ctrl_reg) & ((ME8200_DIO_CTRL_BIT_MODE_0 | | ||
268 | ME8200_DIO_CTRL_BIT_MODE_1) << | ||
269 | (instance->dio_idx * 2)); | ||
270 | |||
271 | if (mode == | ||
272 | (ME8200_DIO_CTRL_BIT_MODE_0 << | ||
273 | (instance->dio_idx * 2))) { | ||
274 | byte = inb(instance->port_reg); | ||
275 | |||
276 | if (value) | ||
277 | byte |= 0x1 << channel; | ||
278 | else | ||
279 | byte &= ~(0x1 << channel); | ||
280 | |||
281 | outb(byte, instance->port_reg); | ||
282 | PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
283 | instance->reg_base, | ||
284 | instance->port_reg - | ||
285 | instance->reg_base, byte); | ||
286 | } else { | ||
287 | PERROR("Port not in output or input mode.\n"); | ||
288 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
289 | } | ||
290 | } else { | ||
291 | PERROR("Invalid bit number specified.\n"); | ||
292 | err = ME_ERRNO_INVALID_CHANNEL; | ||
293 | } | ||
294 | break; | ||
295 | |||
296 | case ME_IO_SINGLE_NO_FLAGS: | ||
297 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
298 | if (channel == 0) { | ||
299 | mode = | ||
300 | inb(instance-> | ||
301 | ctrl_reg) & ((ME8200_DIO_CTRL_BIT_MODE_0 | | ||
302 | ME8200_DIO_CTRL_BIT_MODE_1) << | ||
303 | (instance->dio_idx * 2)); | ||
304 | |||
305 | if (mode == | ||
306 | (ME8200_DIO_CTRL_BIT_MODE_0 << | ||
307 | (instance->dio_idx * 2))) { | ||
308 | outb(value, instance->port_reg); | ||
309 | PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n", | ||
310 | instance->reg_base, | ||
311 | instance->port_reg - | ||
312 | instance->reg_base, value); | ||
313 | } else { | ||
314 | PERROR("Port not in output or input mode.\n"); | ||
315 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
316 | } | ||
317 | } else { | ||
318 | PERROR("Invalid byte number specified.\n"); | ||
319 | err = ME_ERRNO_INVALID_CHANNEL; | ||
320 | } | ||
321 | break; | ||
322 | |||
323 | default: | ||
324 | PERROR("Invalid flags specified.\n"); | ||
325 | err = ME_ERRNO_INVALID_FLAGS; | ||
326 | } | ||
327 | spin_unlock(instance->ctrl_reg_lock); | ||
328 | spin_unlock(&instance->subdevice_lock); | ||
329 | |||
330 | ME_SUBDEVICE_EXIT; | ||
331 | |||
332 | return err; | ||
333 | } | ||
334 | |||
335 | static int me8200_dio_query_number_channels(me_subdevice_t * subdevice, | ||
336 | int *number) | ||
337 | { | ||
338 | PDEBUG("executed.\n"); | ||
339 | *number = 8; | ||
340 | return ME_ERRNO_SUCCESS; | ||
341 | } | ||
342 | |||
343 | static int me8200_dio_query_subdevice_type(me_subdevice_t * subdevice, | ||
344 | int *type, int *subtype) | ||
345 | { | ||
346 | PDEBUG("executed.\n"); | ||
347 | *type = ME_TYPE_DIO; | ||
348 | *subtype = ME_SUBTYPE_SINGLE; | ||
349 | return ME_ERRNO_SUCCESS; | ||
350 | } | ||
351 | |||
352 | static int me8200_dio_query_subdevice_caps(me_subdevice_t * subdevice, | ||
353 | int *caps) | ||
354 | { | ||
355 | PDEBUG("executed.\n"); | ||
356 | *caps = ME_CAPS_DIO_DIR_BYTE; | ||
357 | return ME_ERRNO_SUCCESS; | ||
358 | } | ||
359 | |||
360 | me8200_dio_subdevice_t *me8200_dio_constructor(uint32_t reg_base, | ||
361 | unsigned int dio_idx, | ||
362 | spinlock_t * ctrl_reg_lock) | ||
363 | { | ||
364 | me8200_dio_subdevice_t *subdevice; | ||
365 | int err; | ||
366 | |||
367 | PDEBUG("executed.\n"); | ||
368 | |||
369 | /* Allocate memory for subdevice instance */ | ||
370 | subdevice = kmalloc(sizeof(me8200_dio_subdevice_t), GFP_KERNEL); | ||
371 | |||
372 | if (!subdevice) { | ||
373 | PERROR("Cannot get memory for subdevice instance.\n"); | ||
374 | return NULL; | ||
375 | } | ||
376 | |||
377 | memset(subdevice, 0, sizeof(me8200_dio_subdevice_t)); | ||
378 | |||
379 | /* Initialize subdevice base class */ | ||
380 | err = me_subdevice_init(&subdevice->base); | ||
381 | |||
382 | if (err) { | ||
383 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
384 | kfree(subdevice); | ||
385 | return NULL; | ||
386 | } | ||
387 | // Initialize spin locks. | ||
388 | spin_lock_init(&subdevice->subdevice_lock); | ||
389 | |||
390 | subdevice->ctrl_reg_lock = ctrl_reg_lock; | ||
391 | |||
392 | /* Save digital i/o index */ | ||
393 | subdevice->dio_idx = dio_idx; | ||
394 | |||
395 | /* Save the subdevice index */ | ||
396 | subdevice->ctrl_reg = reg_base + ME8200_DIO_CTRL_REG; | ||
397 | subdevice->port_reg = reg_base + ME8200_DIO_PORT_REG + dio_idx; | ||
398 | #ifdef MEDEBUG_DEBUG_REG | ||
399 | subdevice->reg_base = reg_base; | ||
400 | #endif | ||
401 | |||
402 | /* Overload base class methods. */ | ||
403 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
404 | me8200_dio_io_reset_subdevice; | ||
405 | subdevice->base.me_subdevice_io_single_config = | ||
406 | me8200_dio_io_single_config; | ||
407 | subdevice->base.me_subdevice_io_single_read = me8200_dio_io_single_read; | ||
408 | subdevice->base.me_subdevice_io_single_write = | ||
409 | me8200_dio_io_single_write; | ||
410 | subdevice->base.me_subdevice_query_number_channels = | ||
411 | me8200_dio_query_number_channels; | ||
412 | subdevice->base.me_subdevice_query_subdevice_type = | ||
413 | me8200_dio_query_subdevice_type; | ||
414 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
415 | me8200_dio_query_subdevice_caps; | ||
416 | |||
417 | return subdevice; | ||
418 | } | ||
diff --git a/drivers/staging/meilhaus/me8200_dio.h b/drivers/staging/meilhaus/me8200_dio.h new file mode 100644 index 000000000000..9ddd93d26f15 --- /dev/null +++ b/drivers/staging/meilhaus/me8200_dio.h | |||
@@ -0,0 +1,68 @@ | |||
1 | /** | ||
2 | * @file me8200_dio.h | ||
3 | * | ||
4 | * @brief ME-8200 digital input/output subdevice class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME8200_DIO_H_ | ||
28 | #define _ME8200_DIO_H_ | ||
29 | |||
30 | #include "mesubdevice.h" | ||
31 | |||
32 | #ifdef __KERNEL__ | ||
33 | |||
34 | /** | ||
35 | * @brief The template subdevice class. | ||
36 | */ | ||
37 | typedef struct me8200_dio_subdevice { | ||
38 | /* Inheritance */ | ||
39 | me_subdevice_t base; /**< The subdevice base class. */ | ||
40 | |||
41 | /* Attributes */ | ||
42 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
43 | spinlock_t *ctrl_reg_lock; /**< Spin lock to protect #ctrl_reg from concurrent access. */ | ||
44 | unsigned int dio_idx; /**< The index of the digital i/o on the device. */ | ||
45 | |||
46 | unsigned long port_reg; /**< Register holding the port status. */ | ||
47 | unsigned long ctrl_reg; /**< Register to configure the port direction. */ | ||
48 | #ifdef MEDEBUG_DEBUG_REG | ||
49 | unsigned long reg_base; | ||
50 | #endif | ||
51 | } me8200_dio_subdevice_t; | ||
52 | |||
53 | /** | ||
54 | * @brief The constructor to generate a ME-8200 digital input/ouput subdevice instance. | ||
55 | * | ||
56 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
57 | * @param dio_idx The index of the digital i/o port on the device. | ||
58 | * @param ctrl_reg_lock Spin lock protecting the control register. | ||
59 | * | ||
60 | * @return Pointer to new instance on success.\n | ||
61 | * NULL on error. | ||
62 | */ | ||
63 | me8200_dio_subdevice_t *me8200_dio_constructor(uint32_t reg_base, | ||
64 | unsigned int dio_idx, | ||
65 | spinlock_t * ctrl_reg_lock); | ||
66 | |||
67 | #endif | ||
68 | #endif | ||
diff --git a/drivers/staging/meilhaus/me8200_dio_reg.h b/drivers/staging/meilhaus/me8200_dio_reg.h new file mode 100644 index 000000000000..ac94a133abaf --- /dev/null +++ b/drivers/staging/meilhaus/me8200_dio_reg.h | |||
@@ -0,0 +1,43 @@ | |||
1 | /** | ||
2 | * @file me8200_dio_reg.h | ||
3 | * | ||
4 | * @brief ME-8200 digital input/output subdevice register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME8200_DIO_REG_H_ | ||
28 | #define _ME8200_DIO_REG_H_ | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | #define ME8200_DIO_CTRL_REG 0x7 // R/W | ||
33 | #define ME8200_DIO_PORT_0_REG 0x8 // R/W | ||
34 | #define ME8200_DIO_PORT_1_REG 0x9 // R/W | ||
35 | #define ME8200_DIO_PORT_REG ME8200_DIO_PORT_0_REG // R/W | ||
36 | |||
37 | #define ME8200_DIO_CTRL_BIT_MODE_0 0x01 | ||
38 | #define ME8200_DIO_CTRL_BIT_MODE_1 0x02 | ||
39 | #define ME8200_DIO_CTRL_BIT_MODE_2 0x04 | ||
40 | #define ME8200_DIO_CTRL_BIT_MODE_3 0x08 | ||
41 | |||
42 | #endif | ||
43 | #endif | ||
diff --git a/drivers/staging/meilhaus/me8200_do.c b/drivers/staging/meilhaus/me8200_do.c new file mode 100644 index 000000000000..5f4ba5dfa860 --- /dev/null +++ b/drivers/staging/meilhaus/me8200_do.c | |||
@@ -0,0 +1,600 @@ | |||
1 | /** | ||
2 | * @file me8200_do.c | ||
3 | * | ||
4 | * @brief ME-8200 digital output subdevice instance. | ||
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 | /* | ||
33 | * Includes | ||
34 | */ | ||
35 | #include <linux/module.h> | ||
36 | |||
37 | #include <linux/slab.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | #include <linux/interrupt.h> | ||
40 | #include <asm/io.h> | ||
41 | #include <linux/types.h> | ||
42 | #include <linux/version.h> | ||
43 | |||
44 | #include "medefines.h" | ||
45 | #include "meinternal.h" | ||
46 | #include "meerror.h" | ||
47 | |||
48 | #include "meids.h" | ||
49 | #include "medebug.h" | ||
50 | #include "me8200_reg.h" | ||
51 | #include "me8200_do_reg.h" | ||
52 | #include "me8200_do.h" | ||
53 | |||
54 | /* | ||
55 | * Defines | ||
56 | */ | ||
57 | |||
58 | /* | ||
59 | * Functions | ||
60 | */ | ||
61 | |||
62 | static int me8200_do_io_irq_start(me_subdevice_t * subdevice, | ||
63 | struct file *filep, | ||
64 | int channel, | ||
65 | int irq_source, | ||
66 | int irq_edge, int irq_arg, int flags) | ||
67 | { | ||
68 | me8200_do_subdevice_t *instance; | ||
69 | int err = ME_ERRNO_SUCCESS; | ||
70 | uint8_t tmp; | ||
71 | unsigned long status; | ||
72 | |||
73 | if (flags & ~ME_IO_IRQ_START_DIO_BYTE) { | ||
74 | PERROR("Invalid flag specified.\n"); | ||
75 | return ME_ERRNO_INVALID_FLAGS; | ||
76 | } | ||
77 | |||
78 | if (channel != 0) { | ||
79 | PERROR("Invalid channel specified.\n"); | ||
80 | return ME_ERRNO_INVALID_CHANNEL; | ||
81 | } | ||
82 | |||
83 | if (irq_source != ME_IRQ_SOURCE_DIO_OVER_TEMP) { | ||
84 | PERROR("Invalid interrupt source specified.\n"); | ||
85 | return ME_ERRNO_INVALID_IRQ_SOURCE; | ||
86 | } | ||
87 | |||
88 | PDEBUG("executed.\n"); | ||
89 | |||
90 | instance = (me8200_do_subdevice_t *) subdevice; | ||
91 | |||
92 | ME_SUBDEVICE_ENTER; | ||
93 | |||
94 | spin_lock_irqsave(&instance->subdevice_lock, status); | ||
95 | spin_lock(instance->irq_mode_lock); | ||
96 | tmp = inb(instance->irq_ctrl_reg); | ||
97 | tmp |= | ||
98 | ME8200_IRQ_MODE_BIT_ENABLE_POWER << (ME8200_IRQ_MODE_POWER_SHIFT * | ||
99 | instance->do_idx); | ||
100 | outb(tmp, instance->irq_ctrl_reg); | ||
101 | PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
102 | instance->irq_ctrl_reg - instance->reg_base, tmp); | ||
103 | spin_unlock(instance->irq_mode_lock); | ||
104 | instance->rised = 0; | ||
105 | spin_unlock_irqrestore(&instance->subdevice_lock, status); | ||
106 | |||
107 | ME_SUBDEVICE_EXIT; | ||
108 | |||
109 | return err; | ||
110 | } | ||
111 | |||
112 | static int me8200_do_io_irq_wait(me_subdevice_t * subdevice, | ||
113 | struct file *filep, | ||
114 | int channel, | ||
115 | int *irq_count, | ||
116 | int *value, int time_out, int flags) | ||
117 | { | ||
118 | me8200_do_subdevice_t *instance; | ||
119 | int err = ME_ERRNO_SUCCESS; | ||
120 | long t = 0; | ||
121 | unsigned long cpu_flags; | ||
122 | |||
123 | PDEBUG("executed.\n"); | ||
124 | |||
125 | instance = (me8200_do_subdevice_t *) subdevice; | ||
126 | |||
127 | if (flags) { | ||
128 | PERROR("Invalid flag specified.\n"); | ||
129 | return ME_ERRNO_INVALID_FLAGS; | ||
130 | } | ||
131 | |||
132 | if (time_out < 0) { | ||
133 | PERROR("Invalid time_out specified.\n"); | ||
134 | return ME_ERRNO_INVALID_TIMEOUT; | ||
135 | } | ||
136 | |||
137 | if (time_out) { | ||
138 | t = (time_out * HZ) / 1000; | ||
139 | |||
140 | if (t == 0) | ||
141 | t = 1; | ||
142 | } | ||
143 | |||
144 | ME_SUBDEVICE_ENTER; | ||
145 | |||
146 | if (instance->rised <= 0) { | ||
147 | instance->rised = 0; | ||
148 | |||
149 | if (time_out) { | ||
150 | t = wait_event_interruptible_timeout(instance-> | ||
151 | wait_queue, | ||
152 | (instance->rised != | ||
153 | 0), t); | ||
154 | |||
155 | if (t == 0) { | ||
156 | PERROR | ||
157 | ("Wait on external interrupt timed out.\n"); | ||
158 | err = ME_ERRNO_TIMEOUT; | ||
159 | } | ||
160 | } else { | ||
161 | wait_event_interruptible(instance->wait_queue, | ||
162 | (instance->rised != 0)); | ||
163 | } | ||
164 | |||
165 | if (instance->rised < 0) { | ||
166 | PERROR("Wait on interrupt aborted by user.\n"); | ||
167 | err = ME_ERRNO_CANCELLED; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | if (signal_pending(current)) { | ||
172 | PERROR("Wait on external interrupt aborted by signal.\n"); | ||
173 | err = ME_ERRNO_SIGNAL; | ||
174 | } | ||
175 | |||
176 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
177 | instance->rised = 0; | ||
178 | *irq_count = instance->count; | ||
179 | *value = 0; | ||
180 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
181 | |||
182 | ME_SUBDEVICE_EXIT; | ||
183 | |||
184 | return err; | ||
185 | } | ||
186 | |||
187 | static int me8200_do_io_irq_stop(me_subdevice_t * subdevice, | ||
188 | struct file *filep, int channel, int flags) | ||
189 | { | ||
190 | me8200_do_subdevice_t *instance; | ||
191 | uint8_t tmp; | ||
192 | unsigned long cpu_flags; | ||
193 | |||
194 | PDEBUG("executed.\n"); | ||
195 | |||
196 | instance = (me8200_do_subdevice_t *) subdevice; | ||
197 | |||
198 | if (flags) { | ||
199 | PERROR("Invalid flag specified.\n"); | ||
200 | return ME_ERRNO_INVALID_FLAGS; | ||
201 | } | ||
202 | |||
203 | ME_SUBDEVICE_ENTER; | ||
204 | |||
205 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
206 | spin_lock(instance->irq_mode_lock); | ||
207 | tmp = inb(instance->irq_ctrl_reg); | ||
208 | tmp &= | ||
209 | ~(ME8200_IRQ_MODE_BIT_ENABLE_POWER << | ||
210 | (ME8200_IRQ_MODE_POWER_SHIFT * instance->do_idx)); | ||
211 | outb(tmp, instance->irq_ctrl_reg); | ||
212 | PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
213 | instance->irq_ctrl_reg - instance->reg_base, tmp); | ||
214 | spin_unlock(instance->irq_mode_lock); | ||
215 | instance->rised = -1; | ||
216 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
217 | wake_up_interruptible_all(&instance->wait_queue); | ||
218 | |||
219 | ME_SUBDEVICE_EXIT; | ||
220 | |||
221 | return ME_ERRNO_SUCCESS; | ||
222 | } | ||
223 | |||
224 | static int me8200_do_io_reset_subdevice(struct me_subdevice *subdevice, | ||
225 | struct file *filep, int flags) | ||
226 | { | ||
227 | me8200_do_subdevice_t *instance; | ||
228 | unsigned long cpu_flags; | ||
229 | uint8_t tmp; | ||
230 | |||
231 | PDEBUG("executed.\n"); | ||
232 | |||
233 | instance = (me8200_do_subdevice_t *) subdevice; | ||
234 | |||
235 | if (flags) { | ||
236 | PERROR("Invalid flag specified.\n"); | ||
237 | return ME_ERRNO_INVALID_FLAGS; | ||
238 | } | ||
239 | |||
240 | ME_SUBDEVICE_ENTER; | ||
241 | |||
242 | spin_lock_irqsave(&instance->subdevice_lock, cpu_flags); | ||
243 | outb(0x00, instance->port_reg); | ||
244 | PDEBUG_REG("port_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
245 | instance->port_reg - instance->reg_base, 0x00); | ||
246 | spin_lock(instance->irq_mode_lock); | ||
247 | tmp = inb(instance->irq_ctrl_reg); | ||
248 | tmp &= | ||
249 | ~(ME8200_IRQ_MODE_BIT_ENABLE_POWER << | ||
250 | (ME8200_IRQ_MODE_POWER_SHIFT * instance->do_idx)); | ||
251 | outb(tmp, instance->irq_ctrl_reg); | ||
252 | PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
253 | instance->irq_ctrl_reg - instance->reg_base, tmp); | ||
254 | spin_unlock(instance->irq_mode_lock); | ||
255 | instance->rised = -1; | ||
256 | instance->count = 0; | ||
257 | spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags); | ||
258 | wake_up_interruptible_all(&instance->wait_queue); | ||
259 | |||
260 | ME_SUBDEVICE_EXIT; | ||
261 | |||
262 | return ME_ERRNO_SUCCESS; | ||
263 | } | ||
264 | |||
265 | static int me8200_do_io_single_config(me_subdevice_t * subdevice, | ||
266 | struct file *filep, | ||
267 | int channel, | ||
268 | int single_config, | ||
269 | int ref, | ||
270 | int trig_chan, | ||
271 | int trig_type, int trig_edge, int flags) | ||
272 | { | ||
273 | me8200_do_subdevice_t *instance; | ||
274 | int err = ME_ERRNO_SUCCESS; | ||
275 | unsigned long status; | ||
276 | |||
277 | PDEBUG("executed.\n"); | ||
278 | |||
279 | instance = (me8200_do_subdevice_t *) subdevice; | ||
280 | |||
281 | ME_SUBDEVICE_ENTER; | ||
282 | |||
283 | spin_lock_irqsave(&instance->subdevice_lock, status); | ||
284 | switch (flags) { | ||
285 | case ME_IO_SINGLE_CONFIG_NO_FLAGS: | ||
286 | case ME_IO_SINGLE_CONFIG_DIO_BYTE: | ||
287 | if (channel == 0) { | ||
288 | if (single_config == ME_SINGLE_CONFIG_DIO_OUTPUT) { | ||
289 | } else { | ||
290 | PERROR("Invalid byte direction specified.\n"); | ||
291 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
292 | } | ||
293 | } else { | ||
294 | PERROR("Invalid byte specified.\n"); | ||
295 | err = ME_ERRNO_INVALID_CHANNEL; | ||
296 | } | ||
297 | break; | ||
298 | |||
299 | default: | ||
300 | PERROR("Invalid flags specified.\n"); | ||
301 | err = ME_ERRNO_INVALID_FLAGS; | ||
302 | } | ||
303 | spin_unlock_irqrestore(&instance->subdevice_lock, status); | ||
304 | |||
305 | ME_SUBDEVICE_EXIT; | ||
306 | |||
307 | return err; | ||
308 | } | ||
309 | |||
310 | static int me8200_do_io_single_read(me_subdevice_t * subdevice, | ||
311 | struct file *filep, | ||
312 | int channel, | ||
313 | int *value, int time_out, int flags) | ||
314 | { | ||
315 | me8200_do_subdevice_t *instance; | ||
316 | int err = ME_ERRNO_SUCCESS; | ||
317 | unsigned long status; | ||
318 | |||
319 | PDEBUG("executed.\n"); | ||
320 | |||
321 | instance = (me8200_do_subdevice_t *) subdevice; | ||
322 | |||
323 | ME_SUBDEVICE_ENTER; | ||
324 | |||
325 | spin_lock_irqsave(&instance->subdevice_lock, status); | ||
326 | switch (flags) { | ||
327 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
328 | if ((channel >= 0) && (channel < 8)) { | ||
329 | *value = inb(instance->port_reg) & (0x1 << channel); | ||
330 | } else { | ||
331 | PERROR("Invalid bit number specified.\n"); | ||
332 | err = ME_ERRNO_INVALID_CHANNEL; | ||
333 | } | ||
334 | break; | ||
335 | |||
336 | case ME_IO_SINGLE_NO_FLAGS: | ||
337 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
338 | if (channel == 0) { | ||
339 | *value = inb(instance->port_reg); | ||
340 | } else { | ||
341 | PERROR("Invalid byte number specified.\n"); | ||
342 | err = ME_ERRNO_INVALID_CHANNEL; | ||
343 | } | ||
344 | break; | ||
345 | |||
346 | default: | ||
347 | PERROR("Invalid flags specified.\n"); | ||
348 | err = ME_ERRNO_INVALID_FLAGS; | ||
349 | } | ||
350 | spin_unlock_irqrestore(&instance->subdevice_lock, status); | ||
351 | |||
352 | ME_SUBDEVICE_EXIT; | ||
353 | |||
354 | return err; | ||
355 | } | ||
356 | |||
357 | static int me8200_do_io_single_write(me_subdevice_t * subdevice, | ||
358 | struct file *filep, | ||
359 | int channel, | ||
360 | int value, int time_out, int flags) | ||
361 | { | ||
362 | me8200_do_subdevice_t *instance; | ||
363 | int err = ME_ERRNO_SUCCESS; | ||
364 | uint8_t state; | ||
365 | unsigned long status; | ||
366 | |||
367 | PDEBUG("executed.\n"); | ||
368 | |||
369 | instance = (me8200_do_subdevice_t *) subdevice; | ||
370 | |||
371 | ME_SUBDEVICE_ENTER; | ||
372 | |||
373 | spin_lock_irqsave(&instance->subdevice_lock, status); | ||
374 | switch (flags) { | ||
375 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
376 | if ((channel >= 0) && (channel < 8)) { | ||
377 | state = inb(instance->port_reg); | ||
378 | state = | ||
379 | value ? (state | (0x1 << channel)) : (state & | ||
380 | ~(0x1 << | ||
381 | channel)); | ||
382 | outb(state, instance->port_reg); | ||
383 | PDEBUG_REG("port_reg outb(0x%lX+0x%lX)=0x%x\n", | ||
384 | instance->reg_base, | ||
385 | instance->port_reg - instance->reg_base, | ||
386 | state); | ||
387 | } else { | ||
388 | PERROR("Invalid bit number specified.\n"); | ||
389 | err = ME_ERRNO_INVALID_CHANNEL; | ||
390 | } | ||
391 | break; | ||
392 | |||
393 | case ME_IO_SINGLE_NO_FLAGS: | ||
394 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
395 | if (channel == 0) { | ||
396 | outb(value, instance->port_reg); | ||
397 | PDEBUG_REG("port_reg outb(0x%lX+0x%lX)=0x%x\n", | ||
398 | instance->reg_base, | ||
399 | instance->port_reg - instance->reg_base, | ||
400 | value); | ||
401 | } else { | ||
402 | PERROR("Invalid byte number specified.\n"); | ||
403 | err = ME_ERRNO_INVALID_CHANNEL; | ||
404 | } | ||
405 | break; | ||
406 | |||
407 | default: | ||
408 | PERROR("Invalid flags specified.\n"); | ||
409 | err = ME_ERRNO_INVALID_FLAGS; | ||
410 | } | ||
411 | spin_unlock_irqrestore(&instance->subdevice_lock, status); | ||
412 | |||
413 | ME_SUBDEVICE_EXIT; | ||
414 | |||
415 | return err; | ||
416 | } | ||
417 | |||
418 | static int me8200_do_query_number_channels(me_subdevice_t * subdevice, | ||
419 | int *number) | ||
420 | { | ||
421 | PDEBUG("executed.\n"); | ||
422 | *number = 8; | ||
423 | return ME_ERRNO_SUCCESS; | ||
424 | } | ||
425 | |||
426 | static int me8200_do_query_subdevice_type(me_subdevice_t * subdevice, | ||
427 | int *type, int *subtype) | ||
428 | { | ||
429 | PDEBUG("executed.\n"); | ||
430 | *type = ME_TYPE_DO; | ||
431 | *subtype = ME_SUBTYPE_SINGLE; | ||
432 | return ME_ERRNO_SUCCESS; | ||
433 | } | ||
434 | |||
435 | static int me8200_do_query_subdevice_caps(me_subdevice_t * subdevice, int *caps) | ||
436 | { | ||
437 | PDEBUG("executed.\n"); | ||
438 | *caps = ME_CAPS_DIO_OVER_TEMP_IRQ; | ||
439 | return ME_ERRNO_SUCCESS; | ||
440 | } | ||
441 | |||
442 | static void me8200_do_destructor(struct me_subdevice *subdevice) | ||
443 | { | ||
444 | me8200_do_subdevice_t *instance; | ||
445 | |||
446 | PDEBUG("executed.\n"); | ||
447 | |||
448 | instance = (me8200_do_subdevice_t *) subdevice; | ||
449 | |||
450 | free_irq(instance->irq, (void *)instance); | ||
451 | me_subdevice_deinit(&instance->base); | ||
452 | kfree(instance); | ||
453 | } | ||
454 | |||
455 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) | ||
456 | static irqreturn_t me8200_do_isr(int irq, void *dev_id) | ||
457 | #else | ||
458 | static irqreturn_t me8200_do_isr(int irq, void *dev_id, struct pt_regs *regs) | ||
459 | #endif | ||
460 | { | ||
461 | me8200_do_subdevice_t *instance; | ||
462 | uint16_t ctrl; | ||
463 | uint8_t irq_status; | ||
464 | |||
465 | instance = (me8200_do_subdevice_t *) dev_id; | ||
466 | |||
467 | if (irq != instance->irq) { | ||
468 | PERROR("Incorrect interrupt num: %d.\n", irq); | ||
469 | return IRQ_NONE; | ||
470 | } | ||
471 | |||
472 | irq_status = inb(instance->irq_status_reg); | ||
473 | if (! | ||
474 | (irq_status & | ||
475 | (ME8200_DO_IRQ_STATUS_BIT_ACTIVE << instance->do_idx))) { | ||
476 | PINFO | ||
477 | ("%ld Shared interrupt. %s(): idx=%d irq_status_reg=0x%04X\n", | ||
478 | jiffies, __FUNCTION__, instance->do_idx, irq_status); | ||
479 | return IRQ_NONE; | ||
480 | } | ||
481 | |||
482 | PDEBUG("executed.\n"); | ||
483 | |||
484 | spin_lock(&instance->subdevice_lock); | ||
485 | instance->rised = 1; | ||
486 | instance->count++; | ||
487 | |||
488 | spin_lock(instance->irq_mode_lock); | ||
489 | ctrl = inw(instance->irq_ctrl_reg); | ||
490 | ctrl |= ME8200_IRQ_MODE_BIT_CLEAR_POWER << instance->do_idx; | ||
491 | outw(ctrl, instance->irq_ctrl_reg); | ||
492 | PDEBUG_REG("irq_ctrl_reg outw(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
493 | instance->irq_ctrl_reg - instance->reg_base, ctrl); | ||
494 | ctrl &= ~(ME8200_IRQ_MODE_BIT_CLEAR_POWER << instance->do_idx); | ||
495 | outw(ctrl, instance->irq_ctrl_reg); | ||
496 | PDEBUG_REG("irq_ctrl_reg outw(0x%lX+0x%lX)=0x%x\n", instance->reg_base, | ||
497 | instance->irq_ctrl_reg - instance->reg_base, ctrl); | ||
498 | spin_unlock(instance->irq_mode_lock); | ||
499 | spin_unlock(&instance->subdevice_lock); | ||
500 | wake_up_interruptible_all(&instance->wait_queue); | ||
501 | |||
502 | return IRQ_HANDLED; | ||
503 | } | ||
504 | |||
505 | me8200_do_subdevice_t *me8200_do_constructor(uint32_t reg_base, | ||
506 | unsigned int do_idx, | ||
507 | int irq, | ||
508 | spinlock_t * irq_mode_lock) | ||
509 | { | ||
510 | me8200_do_subdevice_t *subdevice; | ||
511 | int err; | ||
512 | |||
513 | PDEBUG("executed.\n"); | ||
514 | |||
515 | /* Allocate memory for subdevice instance */ | ||
516 | subdevice = kmalloc(sizeof(me8200_do_subdevice_t), GFP_KERNEL); | ||
517 | |||
518 | if (!subdevice) { | ||
519 | PERROR("Cannot get memory for subdevice instance.\n"); | ||
520 | return NULL; | ||
521 | } | ||
522 | |||
523 | memset(subdevice, 0, sizeof(me8200_do_subdevice_t)); | ||
524 | |||
525 | /* Initialize subdevice base class */ | ||
526 | err = me_subdevice_init(&subdevice->base); | ||
527 | |||
528 | if (err) { | ||
529 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
530 | kfree(subdevice); | ||
531 | return NULL; | ||
532 | } | ||
533 | // Initialize spin locks. | ||
534 | spin_lock_init(&subdevice->subdevice_lock); | ||
535 | |||
536 | subdevice->irq_mode_lock = irq_mode_lock; | ||
537 | |||
538 | /* Save the index of the digital output */ | ||
539 | subdevice->do_idx = do_idx; | ||
540 | subdevice->irq = irq; | ||
541 | |||
542 | /* Initialize the registers */ | ||
543 | if (do_idx == 0) { | ||
544 | subdevice->port_reg = reg_base + ME8200_DO_PORT_0_REG; | ||
545 | } else if (do_idx == 1) { | ||
546 | subdevice->port_reg = reg_base + ME8200_DO_PORT_1_REG; | ||
547 | } else { | ||
548 | PERROR("Wrong subdevice idx=%d.\n", do_idx); | ||
549 | kfree(subdevice); | ||
550 | return NULL; | ||
551 | } | ||
552 | subdevice->irq_ctrl_reg = reg_base + ME8200_IRQ_MODE_REG; | ||
553 | subdevice->irq_status_reg = reg_base + ME8200_DO_IRQ_STATUS_REG; | ||
554 | #ifdef MEDEBUG_DEBUG_REG | ||
555 | subdevice->reg_base = reg_base; | ||
556 | #endif | ||
557 | |||
558 | /* Initialize the wait queue */ | ||
559 | init_waitqueue_head(&subdevice->wait_queue); | ||
560 | |||
561 | /* Request the interrupt line */ | ||
562 | err = request_irq(irq, me8200_do_isr, | ||
563 | #ifdef IRQF_DISABLED | ||
564 | IRQF_DISABLED | IRQF_SHARED, | ||
565 | #else | ||
566 | SA_INTERRUPT | SA_SHIRQ, | ||
567 | #endif | ||
568 | ME8200_NAME, (void *)subdevice); | ||
569 | |||
570 | if (err) { | ||
571 | PERROR("Cannot get interrupt line.\n"); | ||
572 | kfree(subdevice); | ||
573 | return NULL; | ||
574 | } | ||
575 | PINFO("Registered irq=%d.\n", irq); | ||
576 | |||
577 | /* Overload base class methods. */ | ||
578 | subdevice->base.me_subdevice_io_irq_start = me8200_do_io_irq_start; | ||
579 | subdevice->base.me_subdevice_io_irq_wait = me8200_do_io_irq_wait; | ||
580 | subdevice->base.me_subdevice_io_irq_stop = me8200_do_io_irq_stop; | ||
581 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
582 | me8200_do_io_reset_subdevice; | ||
583 | subdevice->base.me_subdevice_io_single_config = | ||
584 | me8200_do_io_single_config; | ||
585 | subdevice->base.me_subdevice_io_single_read = me8200_do_io_single_read; | ||
586 | subdevice->base.me_subdevice_io_single_write = | ||
587 | me8200_do_io_single_write; | ||
588 | subdevice->base.me_subdevice_query_number_channels = | ||
589 | me8200_do_query_number_channels; | ||
590 | subdevice->base.me_subdevice_query_subdevice_type = | ||
591 | me8200_do_query_subdevice_type; | ||
592 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
593 | me8200_do_query_subdevice_caps; | ||
594 | subdevice->base.me_subdevice_destructor = me8200_do_destructor; | ||
595 | |||
596 | subdevice->rised = 0; | ||
597 | subdevice->count = 0; | ||
598 | |||
599 | return subdevice; | ||
600 | } | ||
diff --git a/drivers/staging/meilhaus/me8200_do.h b/drivers/staging/meilhaus/me8200_do.h new file mode 100644 index 000000000000..27581251c847 --- /dev/null +++ b/drivers/staging/meilhaus/me8200_do.h | |||
@@ -0,0 +1,75 @@ | |||
1 | /** | ||
2 | * @file me8200_do.h | ||
3 | * | ||
4 | * @brief ME-8200 digital output subdevice class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME8200_DO_H_ | ||
28 | #define _ME8200_DO_H_ | ||
29 | |||
30 | #include "mesubdevice.h" | ||
31 | |||
32 | #ifdef __KERNEL__ | ||
33 | |||
34 | /** | ||
35 | * @brief The template subdevice class. | ||
36 | */ | ||
37 | typedef struct me8200_do_subdevice { | ||
38 | /* Inheritance */ | ||
39 | me_subdevice_t base; /**< The subdevice base class. */ | ||
40 | |||
41 | /* Attributes */ | ||
42 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
43 | spinlock_t *irq_mode_lock; | ||
44 | |||
45 | int irq; /**< The number of the interrupt request */ | ||
46 | int rised; /**< Flag to indicate if an interrupt occured */ | ||
47 | int count; /**< Counts the number of interrupts occured */ | ||
48 | wait_queue_head_t wait_queue; /**< To wait on interrupts */ | ||
49 | |||
50 | unsigned int do_idx; /**< The number of the digital output */ | ||
51 | |||
52 | unsigned long port_reg; /**< The digital output port */ | ||
53 | unsigned long irq_ctrl_reg; /**< The interrupt control register */ | ||
54 | unsigned long irq_status_reg; /**< The interrupt status register */ | ||
55 | #ifdef MEDEBUG_DEBUG_REG | ||
56 | unsigned long reg_base; | ||
57 | #endif | ||
58 | } me8200_do_subdevice_t; | ||
59 | |||
60 | /** | ||
61 | * @brief The constructor to generate a ME-8200 digital output subdevice instance. | ||
62 | * | ||
63 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
64 | * @param do_idx The index of the digital output subdevice on this device. | ||
65 | * | ||
66 | * @return Pointer to new instance on success.\n | ||
67 | * NULL on error. | ||
68 | */ | ||
69 | me8200_do_subdevice_t *me8200_do_constructor(uint32_t reg_base, | ||
70 | unsigned int do_idx, | ||
71 | int irq, | ||
72 | spinlock_t * irq_mode_lock); | ||
73 | |||
74 | #endif | ||
75 | #endif | ||
diff --git a/drivers/staging/meilhaus/me8200_do_reg.h b/drivers/staging/meilhaus/me8200_do_reg.h new file mode 100644 index 000000000000..41095046037a --- /dev/null +++ b/drivers/staging/meilhaus/me8200_do_reg.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /** | ||
2 | * @file me8200_ao_reg.h | ||
3 | * | ||
4 | * @brief ME-8200 analog output subdevice register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME8200_DO_REG_H_ | ||
28 | #define _ME8200_DO_REG_H_ | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | #define ME8200_DO_IRQ_STATUS_REG 0x0 // R | ||
33 | #define ME8200_DO_PORT_0_REG 0x1 // R/W | ||
34 | #define ME8200_DO_PORT_1_REG 0x2 // R/W | ||
35 | |||
36 | #define ME8200_DO_IRQ_STATUS_BIT_ACTIVE 0x1 | ||
37 | #define ME8200_DO_IRQ_STATUS_SHIFT 1 | ||
38 | |||
39 | #endif | ||
40 | #endif | ||
diff --git a/drivers/staging/meilhaus/me8200_reg.h b/drivers/staging/meilhaus/me8200_reg.h new file mode 100644 index 000000000000..a73fe4d5b0ff --- /dev/null +++ b/drivers/staging/meilhaus/me8200_reg.h | |||
@@ -0,0 +1,46 @@ | |||
1 | /** | ||
2 | * @file me8200_reg.h | ||
3 | * | ||
4 | * @brief ME-8200 register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME8200_REG_H_ | ||
28 | #define _ME8200_REG_H_ | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | #define ME8200_IRQ_MODE_REG 0xD // R/W | ||
33 | |||
34 | #define ME8200_IRQ_MODE_MASK 0x3 | ||
35 | |||
36 | #define ME8200_IRQ_MODE_MASK_MASK 0x0 | ||
37 | #define ME8200_IRQ_MODE_MASK_COMPARE 0x1 | ||
38 | |||
39 | #define ME8200_IRQ_MODE_BIT_ENABLE_POWER 0x10 | ||
40 | #define ME8200_IRQ_MODE_BIT_CLEAR_POWER 0x40 | ||
41 | |||
42 | #define ME8200_IRQ_MODE_DI_SHIFT 2 | ||
43 | #define ME8200_IRQ_MODE_POWER_SHIFT 1 | ||
44 | |||
45 | #endif | ||
46 | #endif | ||
diff --git a/drivers/staging/meilhaus/me8254.c b/drivers/staging/meilhaus/me8254.c new file mode 100644 index 000000000000..6e44c3d7a0c7 --- /dev/null +++ b/drivers/staging/meilhaus/me8254.c | |||
@@ -0,0 +1,1176 @@ | |||
1 | /** | ||
2 | * @file me8254.c | ||
3 | * | ||
4 | * @brief 8254 subdevice instance. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef __KERNEL__ | ||
28 | # define __KERNEL__ | ||
29 | #endif | ||
30 | |||
31 | /* | ||
32 | * Includes | ||
33 | */ | ||
34 | #include <linux/module.h> | ||
35 | |||
36 | #include <linux/slab.h> | ||
37 | #include <linux/spinlock.h> | ||
38 | #include <asm/io.h> | ||
39 | #include <linux/types.h> | ||
40 | |||
41 | #include "medefines.h" | ||
42 | #include "meinternal.h" | ||
43 | #include "meerror.h" | ||
44 | |||
45 | #include "medebug.h" | ||
46 | #include "me8254_reg.h" | ||
47 | #include "me8254.h" | ||
48 | |||
49 | /* | ||
50 | * Defines | ||
51 | */ | ||
52 | #define ME8254_NUMBER_CHANNELS 1 /**< One channel per counter. */ | ||
53 | #define ME8254_CTR_WIDTH 16 /**< One counter has 16 bits. */ | ||
54 | |||
55 | /* | ||
56 | * Functions | ||
57 | */ | ||
58 | |||
59 | static int me8254_io_reset_subdevice(struct me_subdevice *subdevice, | ||
60 | struct file *filep, int flags) | ||
61 | { | ||
62 | me8254_subdevice_t *instance; | ||
63 | uint8_t clk_src; | ||
64 | int err = ME_ERRNO_SUCCESS; | ||
65 | |||
66 | PDEBUG("executed.\n"); | ||
67 | |||
68 | instance = (me8254_subdevice_t *) subdevice; | ||
69 | |||
70 | if (flags) { | ||
71 | PERROR("Invalid flag specified.\n"); | ||
72 | return ME_ERRNO_INVALID_FLAGS; | ||
73 | } | ||
74 | |||
75 | ME_SUBDEVICE_ENTER; | ||
76 | |||
77 | spin_lock(&instance->subdevice_lock); | ||
78 | spin_lock(instance->ctrl_reg_lock); | ||
79 | if (instance->ctr_idx == 0) | ||
80 | outb(ME8254_CTRL_SC0 | ME8254_CTRL_LM | ME8254_CTRL_M0 | | ||
81 | ME8254_CTRL_BIN, instance->ctrl_reg); | ||
82 | else if (instance->ctr_idx == 1) | ||
83 | outb(ME8254_CTRL_SC1 | ME8254_CTRL_LM | ME8254_CTRL_M0 | | ||
84 | ME8254_CTRL_BIN, instance->ctrl_reg); | ||
85 | else | ||
86 | outb(ME8254_CTRL_SC2 | ME8254_CTRL_LM | ME8254_CTRL_M0 | | ||
87 | ME8254_CTRL_BIN, instance->ctrl_reg); | ||
88 | spin_unlock(instance->ctrl_reg_lock); | ||
89 | |||
90 | outb(0x00, instance->val_reg); | ||
91 | outb(0x00, instance->val_reg); | ||
92 | |||
93 | spin_lock(instance->clk_src_reg_lock); | ||
94 | clk_src = inb(instance->clk_src_reg); | ||
95 | |||
96 | switch (instance->device_id) { | ||
97 | case PCI_DEVICE_ID_MEILHAUS_ME1400: | ||
98 | case PCI_DEVICE_ID_MEILHAUS_ME140A: | ||
99 | case PCI_DEVICE_ID_MEILHAUS_ME140B: | ||
100 | case PCI_DEVICE_ID_MEILHAUS_ME14E0: | ||
101 | case PCI_DEVICE_ID_MEILHAUS_ME14EA: | ||
102 | case PCI_DEVICE_ID_MEILHAUS_ME14EB: | ||
103 | if (instance->me8254_idx == 0) { | ||
104 | if (instance->ctr_idx == 0) | ||
105 | clk_src &= | ||
106 | ~(ME1400AB_8254_A_0_CLK_SRC_10MHZ | | ||
107 | ME1400AB_8254_A_0_CLK_SRC_QUARZ); | ||
108 | else if (instance->ctr_idx == 1) | ||
109 | clk_src &= ~(ME1400AB_8254_A_1_CLK_SRC_PREV); | ||
110 | else | ||
111 | clk_src &= ~(ME1400AB_8254_A_2_CLK_SRC_PREV); | ||
112 | } else { | ||
113 | if (instance->ctr_idx == 0) | ||
114 | clk_src &= | ||
115 | ~(ME1400AB_8254_B_0_CLK_SRC_10MHZ | | ||
116 | ME1400AB_8254_B_0_CLK_SRC_QUARZ); | ||
117 | else if (instance->ctr_idx == 1) | ||
118 | clk_src &= ~(ME1400AB_8254_B_1_CLK_SRC_PREV); | ||
119 | else | ||
120 | clk_src &= ~(ME1400AB_8254_B_2_CLK_SRC_PREV); | ||
121 | } | ||
122 | break; | ||
123 | |||
124 | case PCI_DEVICE_ID_MEILHAUS_ME140C: | ||
125 | case PCI_DEVICE_ID_MEILHAUS_ME140D: | ||
126 | switch (instance->me8254_idx) { | ||
127 | case 0: | ||
128 | case 2: | ||
129 | case 4: | ||
130 | case 6: | ||
131 | case 8: | ||
132 | if (instance->ctr_idx == 0) | ||
133 | clk_src &= ~(ME1400CD_8254_ACE_0_CLK_SRC_MASK); | ||
134 | else if (instance->ctr_idx == 1) | ||
135 | clk_src &= ~(ME1400CD_8254_ACE_1_CLK_SRC_MASK); | ||
136 | else | ||
137 | clk_src &= ~(ME1400CD_8254_ACE_2_CLK_SRC_MASK); | ||
138 | break; | ||
139 | |||
140 | default: | ||
141 | if (instance->ctr_idx == 0) | ||
142 | clk_src &= ~(ME1400CD_8254_BD_0_CLK_SRC_MASK); | ||
143 | else if (instance->ctr_idx == 1) | ||
144 | clk_src &= ~(ME1400CD_8254_BD_1_CLK_SRC_MASK); | ||
145 | else | ||
146 | clk_src &= ~(ME1400CD_8254_BD_2_CLK_SRC_MASK); | ||
147 | break; | ||
148 | } | ||
149 | break; | ||
150 | |||
151 | case PCI_DEVICE_ID_MEILHAUS_ME4610: | ||
152 | case PCI_DEVICE_ID_MEILHAUS_ME4660: | ||
153 | case PCI_DEVICE_ID_MEILHAUS_ME4660I: | ||
154 | case PCI_DEVICE_ID_MEILHAUS_ME4660S: | ||
155 | case PCI_DEVICE_ID_MEILHAUS_ME4660IS: | ||
156 | case PCI_DEVICE_ID_MEILHAUS_ME4670: | ||
157 | case PCI_DEVICE_ID_MEILHAUS_ME4670I: | ||
158 | case PCI_DEVICE_ID_MEILHAUS_ME4670S: | ||
159 | case PCI_DEVICE_ID_MEILHAUS_ME4670IS: | ||
160 | case PCI_DEVICE_ID_MEILHAUS_ME4680: | ||
161 | case PCI_DEVICE_ID_MEILHAUS_ME4680I: | ||
162 | case PCI_DEVICE_ID_MEILHAUS_ME4680S: | ||
163 | case PCI_DEVICE_ID_MEILHAUS_ME4680IS: | ||
164 | case PCI_DEVICE_ID_MEILHAUS_ME8100_A: | ||
165 | case PCI_DEVICE_ID_MEILHAUS_ME8100_B: | ||
166 | |||
167 | /* No clock source register available */ | ||
168 | break; | ||
169 | |||
170 | default: | ||
171 | PERROR("Invalid device type.\n"); | ||
172 | err = ME_ERRNO_INTERNAL; | ||
173 | } | ||
174 | |||
175 | if (!err) | ||
176 | outb(clk_src, instance->clk_src_reg); | ||
177 | |||
178 | spin_unlock(instance->clk_src_reg_lock); | ||
179 | spin_unlock(&instance->subdevice_lock); | ||
180 | |||
181 | ME_SUBDEVICE_EXIT; | ||
182 | |||
183 | return err; | ||
184 | } | ||
185 | |||
186 | static int me1400_ab_ref_config(me8254_subdevice_t * instance, int ref) | ||
187 | { | ||
188 | uint8_t clk_src; | ||
189 | |||
190 | spin_lock(instance->clk_src_reg_lock); | ||
191 | clk_src = inb(instance->clk_src_reg); | ||
192 | |||
193 | switch (ref) { | ||
194 | case ME_REF_CTR_EXTERNAL: | ||
195 | if (instance->me8254_idx == 0) { | ||
196 | if (instance->ctr_idx == 0) | ||
197 | clk_src &= ~(ME1400AB_8254_A_0_CLK_SRC_QUARZ); | ||
198 | else if (instance->ctr_idx == 1) | ||
199 | clk_src &= ~(ME1400AB_8254_A_1_CLK_SRC_PREV); | ||
200 | else | ||
201 | clk_src &= ~(ME1400AB_8254_A_2_CLK_SRC_PREV); | ||
202 | } else { | ||
203 | if (instance->ctr_idx == 0) | ||
204 | clk_src &= ~(ME1400AB_8254_B_0_CLK_SRC_QUARZ); | ||
205 | else if (instance->ctr_idx == 1) | ||
206 | clk_src &= ~(ME1400AB_8254_B_1_CLK_SRC_PREV); | ||
207 | else | ||
208 | clk_src &= ~(ME1400AB_8254_B_2_CLK_SRC_PREV); | ||
209 | } | ||
210 | |||
211 | break; | ||
212 | |||
213 | case ME_REF_CTR_PREVIOUS: | ||
214 | if (instance->me8254_idx == 0) { | ||
215 | if (instance->ctr_idx == 0) { | ||
216 | PERROR("Invalid reference.\n"); | ||
217 | spin_unlock(instance->clk_src_reg_lock); | ||
218 | return ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
219 | } else if (instance->ctr_idx == 1) | ||
220 | clk_src |= (ME1400AB_8254_A_1_CLK_SRC_PREV); | ||
221 | else | ||
222 | clk_src |= (ME1400AB_8254_A_2_CLK_SRC_PREV); | ||
223 | } else { | ||
224 | if (instance->ctr_idx == 0) { | ||
225 | PERROR("Invalid reference.\n"); | ||
226 | spin_unlock(instance->clk_src_reg_lock); | ||
227 | return ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
228 | } else if (instance->ctr_idx == 1) | ||
229 | clk_src |= (ME1400AB_8254_B_1_CLK_SRC_PREV); | ||
230 | else | ||
231 | clk_src |= (ME1400AB_8254_B_2_CLK_SRC_PREV); | ||
232 | } | ||
233 | |||
234 | break; | ||
235 | |||
236 | case ME_REF_CTR_INTERNAL_1MHZ: | ||
237 | if (instance->me8254_idx == 0) { | ||
238 | if (instance->ctr_idx == 0) { | ||
239 | clk_src |= (ME1400AB_8254_A_0_CLK_SRC_QUARZ); | ||
240 | clk_src &= ~(ME1400AB_8254_A_0_CLK_SRC_10MHZ); | ||
241 | } else { | ||
242 | PERROR("Invalid reference.\n"); | ||
243 | spin_unlock(instance->clk_src_reg_lock); | ||
244 | return ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
245 | } | ||
246 | } else { | ||
247 | if (instance->ctr_idx == 0) { | ||
248 | clk_src |= (ME1400AB_8254_B_0_CLK_SRC_QUARZ); | ||
249 | clk_src &= ~(ME1400AB_8254_B_0_CLK_SRC_10MHZ); | ||
250 | } else { | ||
251 | PERROR("Invalid reference.\n"); | ||
252 | spin_unlock(instance->clk_src_reg_lock); | ||
253 | return ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | break; | ||
258 | |||
259 | case ME_REF_CTR_INTERNAL_10MHZ: | ||
260 | if (instance->me8254_idx == 0) { | ||
261 | if (instance->ctr_idx == 0) { | ||
262 | clk_src |= (ME1400AB_8254_A_0_CLK_SRC_QUARZ); | ||
263 | clk_src |= (ME1400AB_8254_A_0_CLK_SRC_10MHZ); | ||
264 | } else { | ||
265 | PERROR("Invalid reference.\n"); | ||
266 | spin_unlock(instance->clk_src_reg_lock); | ||
267 | return ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
268 | } | ||
269 | } else { | ||
270 | if (instance->ctr_idx == 0) { | ||
271 | clk_src |= (ME1400AB_8254_A_0_CLK_SRC_QUARZ); | ||
272 | clk_src |= (ME1400AB_8254_A_0_CLK_SRC_10MHZ); | ||
273 | } else { | ||
274 | PERROR("Invalid reference.\n"); | ||
275 | spin_unlock(instance->clk_src_reg_lock); | ||
276 | return ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
277 | } | ||
278 | } | ||
279 | |||
280 | break; | ||
281 | |||
282 | default: | ||
283 | PERROR("Invalid reference.\n"); | ||
284 | spin_unlock(instance->clk_src_reg_lock); | ||
285 | return ME_ERRNO_INVALID_REF; | ||
286 | } | ||
287 | |||
288 | outb(clk_src, instance->clk_src_reg); | ||
289 | spin_unlock(instance->clk_src_reg_lock); | ||
290 | |||
291 | return ME_ERRNO_SUCCESS; | ||
292 | } | ||
293 | |||
294 | static int me1400_cd_ref_config(me8254_subdevice_t * instance, int ref) | ||
295 | { | ||
296 | uint8_t clk_src; | ||
297 | |||
298 | spin_lock(instance->clk_src_reg_lock); | ||
299 | clk_src = inb(instance->clk_src_reg); | ||
300 | |||
301 | switch (ref) { | ||
302 | case ME_REF_CTR_EXTERNAL: | ||
303 | switch (instance->me8254_idx) { | ||
304 | case 0: | ||
305 | case 2: | ||
306 | case 4: | ||
307 | case 6: | ||
308 | case 8: | ||
309 | if (instance->ctr_idx == 0) | ||
310 | clk_src &= ~(ME1400CD_8254_ACE_0_CLK_SRC_MASK); | ||
311 | else if (instance->ctr_idx == 1) | ||
312 | clk_src &= ~(ME1400CD_8254_ACE_1_CLK_SRC_MASK); | ||
313 | else | ||
314 | clk_src &= ~(ME1400CD_8254_ACE_2_CLK_SRC_MASK); | ||
315 | break; | ||
316 | |||
317 | default: | ||
318 | if (instance->ctr_idx == 0) | ||
319 | clk_src &= ~(ME1400CD_8254_BD_0_CLK_SRC_MASK); | ||
320 | else if (instance->ctr_idx == 1) | ||
321 | clk_src &= ~(ME1400CD_8254_BD_1_CLK_SRC_MASK); | ||
322 | else | ||
323 | clk_src &= ~(ME1400CD_8254_BD_2_CLK_SRC_MASK); | ||
324 | break; | ||
325 | } | ||
326 | break; | ||
327 | |||
328 | case ME_REF_CTR_PREVIOUS: | ||
329 | switch (instance->me8254_idx) { | ||
330 | case 0: | ||
331 | case 2: | ||
332 | case 4: | ||
333 | case 6: | ||
334 | case 8: | ||
335 | if (instance->ctr_idx == 0) { | ||
336 | clk_src &= ~(ME1400CD_8254_ACE_0_CLK_SRC_MASK); | ||
337 | clk_src |= (ME1400CD_8254_ACE_0_CLK_SRC_PREV); | ||
338 | } else if (instance->ctr_idx == 1) { | ||
339 | clk_src &= ~(ME1400CD_8254_ACE_1_CLK_SRC_MASK); | ||
340 | clk_src |= (ME1400CD_8254_ACE_1_CLK_SRC_PREV); | ||
341 | } else { | ||
342 | clk_src &= ~(ME1400CD_8254_ACE_2_CLK_SRC_MASK); | ||
343 | clk_src |= (ME1400CD_8254_ACE_2_CLK_SRC_PREV); | ||
344 | } | ||
345 | break; | ||
346 | |||
347 | default: | ||
348 | if (instance->ctr_idx == 0) { | ||
349 | clk_src &= ~(ME1400CD_8254_BD_0_CLK_SRC_MASK); | ||
350 | clk_src |= (ME1400CD_8254_BD_0_CLK_SRC_PREV); | ||
351 | } else if (instance->ctr_idx == 1) { | ||
352 | clk_src &= ~(ME1400CD_8254_BD_1_CLK_SRC_MASK); | ||
353 | clk_src |= (ME1400CD_8254_BD_1_CLK_SRC_PREV); | ||
354 | } else { | ||
355 | clk_src &= ~(ME1400CD_8254_BD_2_CLK_SRC_MASK); | ||
356 | clk_src |= (ME1400CD_8254_BD_2_CLK_SRC_PREV); | ||
357 | } | ||
358 | break; | ||
359 | } | ||
360 | |||
361 | break; | ||
362 | |||
363 | case ME_REF_CTR_INTERNAL_1MHZ: | ||
364 | switch (instance->me8254_idx) { | ||
365 | case 0: | ||
366 | case 2: | ||
367 | case 4: | ||
368 | case 6: | ||
369 | case 8: | ||
370 | if (instance->ctr_idx == 0) { | ||
371 | clk_src &= ~(ME1400CD_8254_ACE_0_CLK_SRC_MASK); | ||
372 | clk_src |= (ME1400CD_8254_ACE_0_CLK_SRC_1MHZ); | ||
373 | } else { | ||
374 | PERROR("Invalid reference.\n"); | ||
375 | spin_unlock(instance->clk_src_reg_lock); | ||
376 | return ME_ERRNO_INVALID_REF; | ||
377 | } | ||
378 | |||
379 | break; | ||
380 | |||
381 | default: | ||
382 | if (instance->ctr_idx == 0) { | ||
383 | clk_src &= ~(ME1400CD_8254_BD_0_CLK_SRC_MASK); | ||
384 | clk_src |= (ME1400CD_8254_BD_0_CLK_SRC_1MHZ); | ||
385 | } else { | ||
386 | PERROR("Invalid reference.\n"); | ||
387 | spin_unlock(instance->clk_src_reg_lock); | ||
388 | return ME_ERRNO_INVALID_REF; | ||
389 | } | ||
390 | break; | ||
391 | } | ||
392 | |||
393 | break; | ||
394 | |||
395 | case ME_REF_CTR_INTERNAL_10MHZ: | ||
396 | switch (instance->me8254_idx) { | ||
397 | case 0: | ||
398 | case 2: | ||
399 | case 4: | ||
400 | case 6: | ||
401 | case 8: | ||
402 | if (instance->ctr_idx == 0) { | ||
403 | clk_src &= ~(ME1400CD_8254_ACE_0_CLK_SRC_MASK); | ||
404 | clk_src |= (ME1400CD_8254_ACE_0_CLK_SRC_10MHZ); | ||
405 | } else { | ||
406 | PERROR("Invalid reference.\n"); | ||
407 | spin_unlock(instance->clk_src_reg_lock); | ||
408 | return ME_ERRNO_INVALID_REF; | ||
409 | } | ||
410 | break; | ||
411 | |||
412 | default: | ||
413 | if (instance->ctr_idx == 0) { | ||
414 | clk_src &= ~(ME1400CD_8254_BD_0_CLK_SRC_MASK); | ||
415 | clk_src |= (ME1400CD_8254_BD_0_CLK_SRC_10MHZ); | ||
416 | } else { | ||
417 | PERROR("Invalid reference.\n"); | ||
418 | spin_unlock(instance->clk_src_reg_lock); | ||
419 | return ME_ERRNO_INVALID_REF; | ||
420 | } | ||
421 | |||
422 | break; | ||
423 | } | ||
424 | |||
425 | break; | ||
426 | |||
427 | default: | ||
428 | PERROR("Invalid reference.\n"); | ||
429 | spin_unlock(instance->clk_src_reg_lock); | ||
430 | return ME_ERRNO_INVALID_REF; | ||
431 | } | ||
432 | |||
433 | outb(clk_src, instance->clk_src_reg); | ||
434 | spin_unlock(instance->clk_src_reg_lock); | ||
435 | |||
436 | return ME_ERRNO_SUCCESS; | ||
437 | } | ||
438 | |||
439 | static int me4600_ref_config(me8254_subdevice_t * instance, int ref) | ||
440 | { | ||
441 | switch (ref) { | ||
442 | |||
443 | case ME_REF_CTR_EXTERNAL: | ||
444 | // Nothing to do | ||
445 | break; | ||
446 | |||
447 | default: | ||
448 | PERROR("Invalid reference.\n"); | ||
449 | // spin_unlock(instance->clk_src_reg_lock); | ||
450 | return ME_ERRNO_INVALID_REF; | ||
451 | } | ||
452 | |||
453 | return ME_ERRNO_SUCCESS; | ||
454 | } | ||
455 | |||
456 | static int me8100_ref_config(me8254_subdevice_t * instance, int ref) | ||
457 | { | ||
458 | switch (ref) { | ||
459 | |||
460 | case ME_REF_CTR_EXTERNAL: | ||
461 | // Nothing to do | ||
462 | break; | ||
463 | |||
464 | default: | ||
465 | PERROR("Invalid reference.\n"); | ||
466 | // spin_unlock(instance->clk_src_reg_lock); | ||
467 | return ME_ERRNO_INVALID_REF; | ||
468 | } | ||
469 | |||
470 | return ME_ERRNO_SUCCESS; | ||
471 | } | ||
472 | |||
473 | static int me8254_io_single_config(struct me_subdevice *subdevice, | ||
474 | struct file *filep, | ||
475 | int channel, | ||
476 | int single_config, | ||
477 | int ref, | ||
478 | int trig_chan, | ||
479 | int trig_type, int trig_edge, int flags) | ||
480 | { | ||
481 | me8254_subdevice_t *instance; | ||
482 | int err; | ||
483 | |||
484 | PDEBUG("executed.\n"); | ||
485 | |||
486 | if (channel) { | ||
487 | PERROR("Invalid channel.\n"); | ||
488 | return ME_ERRNO_INVALID_CHANNEL; | ||
489 | } | ||
490 | |||
491 | instance = (me8254_subdevice_t *) subdevice; | ||
492 | |||
493 | if (flags) { | ||
494 | PERROR("Invalid flag specified.\n"); | ||
495 | return ME_ERRNO_INVALID_FLAGS; | ||
496 | } | ||
497 | |||
498 | ME_SUBDEVICE_ENTER; | ||
499 | |||
500 | spin_lock(&instance->subdevice_lock); | ||
501 | // Configure the counter modes | ||
502 | if (instance->ctr_idx == 0) { | ||
503 | if (single_config == ME_SINGLE_CONFIG_CTR_8254_MODE_0) { | ||
504 | outb(ME8254_CTRL_SC0 | ME8254_CTRL_LM | ME8254_CTRL_M0 | | ||
505 | ME8254_CTRL_BIN, instance->ctrl_reg); | ||
506 | } else if (single_config == ME_SINGLE_CONFIG_CTR_8254_MODE_1) { | ||
507 | outb(ME8254_CTRL_SC0 | ME8254_CTRL_LM | ME8254_CTRL_M1 | | ||
508 | ME8254_CTRL_BIN, instance->ctrl_reg); | ||
509 | } else if (single_config == ME_SINGLE_CONFIG_CTR_8254_MODE_2) { | ||
510 | outb(ME8254_CTRL_SC0 | ME8254_CTRL_LM | ME8254_CTRL_M2 | | ||
511 | ME8254_CTRL_BIN, instance->ctrl_reg); | ||
512 | } else if (single_config == ME_SINGLE_CONFIG_CTR_8254_MODE_3) { | ||
513 | outb(ME8254_CTRL_SC0 | ME8254_CTRL_LM | ME8254_CTRL_M3 | | ||
514 | ME8254_CTRL_BIN, instance->ctrl_reg); | ||
515 | } else if (single_config == ME_SINGLE_CONFIG_CTR_8254_MODE_4) { | ||
516 | outb(ME8254_CTRL_SC0 | ME8254_CTRL_LM | ME8254_CTRL_M4 | | ||
517 | ME8254_CTRL_BIN, instance->ctrl_reg); | ||
518 | } else if (single_config == ME_SINGLE_CONFIG_CTR_8254_MODE_5) { | ||
519 | outb(ME8254_CTRL_SC0 | ME8254_CTRL_LM | ME8254_CTRL_M5 | | ||
520 | ME8254_CTRL_BIN, instance->ctrl_reg); | ||
521 | } else { | ||
522 | PERROR("Invalid single configuration.\n"); | ||
523 | spin_unlock(&instance->subdevice_lock); | ||
524 | return ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
525 | } | ||
526 | } else if (instance->ctr_idx == 1) { | ||
527 | if (single_config == ME_SINGLE_CONFIG_CTR_8254_MODE_0) { | ||
528 | outb(ME8254_CTRL_SC1 | ME8254_CTRL_LM | ME8254_CTRL_M0 | | ||
529 | ME8254_CTRL_BIN, instance->ctrl_reg); | ||
530 | } else if (single_config == ME_SINGLE_CONFIG_CTR_8254_MODE_1) { | ||
531 | outb(ME8254_CTRL_SC1 | ME8254_CTRL_LM | ME8254_CTRL_M1 | | ||
532 | ME8254_CTRL_BIN, instance->ctrl_reg); | ||
533 | } else if (single_config == ME_SINGLE_CONFIG_CTR_8254_MODE_2) { | ||
534 | outb(ME8254_CTRL_SC1 | ME8254_CTRL_LM | ME8254_CTRL_M2 | | ||
535 | ME8254_CTRL_BIN, instance->ctrl_reg); | ||
536 | } else if (single_config == ME_SINGLE_CONFIG_CTR_8254_MODE_3) { | ||
537 | outb(ME8254_CTRL_SC1 | ME8254_CTRL_LM | ME8254_CTRL_M3 | | ||
538 | ME8254_CTRL_BIN, instance->ctrl_reg); | ||
539 | } else if (single_config == ME_SINGLE_CONFIG_CTR_8254_MODE_4) { | ||
540 | outb(ME8254_CTRL_SC1 | ME8254_CTRL_LM | ME8254_CTRL_M4 | | ||
541 | ME8254_CTRL_BIN, instance->ctrl_reg); | ||
542 | } else if (single_config == ME_SINGLE_CONFIG_CTR_8254_MODE_5) { | ||
543 | outb(ME8254_CTRL_SC1 | ME8254_CTRL_LM | ME8254_CTRL_M5 | | ||
544 | ME8254_CTRL_BIN, instance->ctrl_reg); | ||
545 | } else { | ||
546 | PERROR("Invalid single configuration.\n"); | ||
547 | spin_unlock(&instance->subdevice_lock); | ||
548 | return ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
549 | } | ||
550 | } else { | ||
551 | if (single_config == ME_SINGLE_CONFIG_CTR_8254_MODE_0) { | ||
552 | outb(ME8254_CTRL_SC2 | ME8254_CTRL_LM | ME8254_CTRL_M0 | | ||
553 | ME8254_CTRL_BIN, instance->ctrl_reg); | ||
554 | } else if (single_config == ME_SINGLE_CONFIG_CTR_8254_MODE_1) { | ||
555 | outb(ME8254_CTRL_SC2 | ME8254_CTRL_LM | ME8254_CTRL_M1 | | ||
556 | ME8254_CTRL_BIN, instance->ctrl_reg); | ||
557 | } else if (single_config == ME_SINGLE_CONFIG_CTR_8254_MODE_2) { | ||
558 | outb(ME8254_CTRL_SC2 | ME8254_CTRL_LM | ME8254_CTRL_M2 | | ||
559 | ME8254_CTRL_BIN, instance->ctrl_reg); | ||
560 | } else if (single_config == ME_SINGLE_CONFIG_CTR_8254_MODE_3) { | ||
561 | outb(ME8254_CTRL_SC2 | ME8254_CTRL_LM | ME8254_CTRL_M3 | | ||
562 | ME8254_CTRL_BIN, instance->ctrl_reg); | ||
563 | } else if (single_config == ME_SINGLE_CONFIG_CTR_8254_MODE_4) { | ||
564 | outb(ME8254_CTRL_SC2 | ME8254_CTRL_LM | ME8254_CTRL_M4 | | ||
565 | ME8254_CTRL_BIN, instance->ctrl_reg); | ||
566 | } else if (single_config == ME_SINGLE_CONFIG_CTR_8254_MODE_5) { | ||
567 | outb(ME8254_CTRL_SC2 | ME8254_CTRL_LM | ME8254_CTRL_M5 | | ||
568 | ME8254_CTRL_BIN, instance->ctrl_reg); | ||
569 | } else { | ||
570 | PERROR("Invalid single configuration.\n"); | ||
571 | spin_unlock(&instance->subdevice_lock); | ||
572 | return ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
573 | } | ||
574 | } | ||
575 | |||
576 | switch (instance->device_id) { | ||
577 | case PCI_DEVICE_ID_MEILHAUS_ME1400: | ||
578 | case PCI_DEVICE_ID_MEILHAUS_ME14E0: | ||
579 | case PCI_DEVICE_ID_MEILHAUS_ME140A: | ||
580 | case PCI_DEVICE_ID_MEILHAUS_ME14EA: | ||
581 | case PCI_DEVICE_ID_MEILHAUS_ME140B: | ||
582 | case PCI_DEVICE_ID_MEILHAUS_ME14EB: | ||
583 | err = me1400_ab_ref_config(instance, ref); | ||
584 | |||
585 | if (err) { | ||
586 | spin_unlock(&instance->subdevice_lock); | ||
587 | return err; | ||
588 | } | ||
589 | |||
590 | break; | ||
591 | |||
592 | case PCI_DEVICE_ID_MEILHAUS_ME140C: | ||
593 | case PCI_DEVICE_ID_MEILHAUS_ME140D: | ||
594 | err = me1400_cd_ref_config(instance, ref); | ||
595 | |||
596 | if (err) { | ||
597 | spin_unlock(&instance->subdevice_lock); | ||
598 | return err; | ||
599 | } | ||
600 | |||
601 | break; | ||
602 | |||
603 | case PCI_DEVICE_ID_MEILHAUS_ME4610: | ||
604 | case PCI_DEVICE_ID_MEILHAUS_ME4660: | ||
605 | case PCI_DEVICE_ID_MEILHAUS_ME4660I: | ||
606 | case PCI_DEVICE_ID_MEILHAUS_ME4660S: | ||
607 | case PCI_DEVICE_ID_MEILHAUS_ME4660IS: | ||
608 | case PCI_DEVICE_ID_MEILHAUS_ME4670: | ||
609 | case PCI_DEVICE_ID_MEILHAUS_ME4670I: | ||
610 | case PCI_DEVICE_ID_MEILHAUS_ME4670S: | ||
611 | case PCI_DEVICE_ID_MEILHAUS_ME4670IS: | ||
612 | case PCI_DEVICE_ID_MEILHAUS_ME4680: | ||
613 | case PCI_DEVICE_ID_MEILHAUS_ME4680I: | ||
614 | case PCI_DEVICE_ID_MEILHAUS_ME4680S: | ||
615 | case PCI_DEVICE_ID_MEILHAUS_ME4680IS: | ||
616 | err = me4600_ref_config(instance, ref); | ||
617 | |||
618 | if (err) { | ||
619 | spin_unlock(&instance->subdevice_lock); | ||
620 | return err; | ||
621 | } | ||
622 | |||
623 | break; | ||
624 | |||
625 | case PCI_DEVICE_ID_MEILHAUS_ME8100_A: | ||
626 | case PCI_DEVICE_ID_MEILHAUS_ME8100_B: | ||
627 | err = me8100_ref_config(instance, ref); | ||
628 | |||
629 | if (err) { | ||
630 | spin_unlock(&instance->subdevice_lock); | ||
631 | return err; | ||
632 | } | ||
633 | |||
634 | break; | ||
635 | |||
636 | default: | ||
637 | PERROR("Invalid device type.\n"); | ||
638 | |||
639 | spin_unlock(&instance->subdevice_lock); | ||
640 | // spin_unlock(instance->clk_src_reg_lock); | ||
641 | return ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
642 | } | ||
643 | spin_unlock(&instance->subdevice_lock); | ||
644 | |||
645 | ME_SUBDEVICE_EXIT; | ||
646 | |||
647 | return ME_ERRNO_SUCCESS; | ||
648 | } | ||
649 | |||
650 | static int me8254_io_single_read(struct me_subdevice *subdevice, | ||
651 | struct file *filep, | ||
652 | int channel, | ||
653 | int *value, int time_out, int flags) | ||
654 | { | ||
655 | me8254_subdevice_t *instance; | ||
656 | uint16_t lo_byte; | ||
657 | uint16_t hi_byte; | ||
658 | |||
659 | PDEBUG("executed.\n"); | ||
660 | |||
661 | if (channel) { | ||
662 | PERROR("Invalid channel.\n"); | ||
663 | return ME_ERRNO_INVALID_CHANNEL; | ||
664 | } | ||
665 | |||
666 | instance = (me8254_subdevice_t *) subdevice; | ||
667 | |||
668 | if (flags) { | ||
669 | PERROR("Invalid flag specified.\n"); | ||
670 | return ME_ERRNO_INVALID_FLAGS; | ||
671 | } | ||
672 | |||
673 | ME_SUBDEVICE_ENTER; | ||
674 | |||
675 | spin_lock(&instance->subdevice_lock); | ||
676 | spin_lock(instance->ctrl_reg_lock); | ||
677 | if (instance->ctr_idx == 0) | ||
678 | outb(ME8254_CTRL_SC0 | ME8254_CTRL_TLO, instance->ctrl_reg); | ||
679 | else if (instance->ctr_idx == 1) | ||
680 | outb(ME8254_CTRL_SC1 | ME8254_CTRL_TLO, instance->ctrl_reg); | ||
681 | else | ||
682 | outb(ME8254_CTRL_SC2 | ME8254_CTRL_TLO, instance->ctrl_reg); | ||
683 | |||
684 | lo_byte = inb(instance->val_reg); | ||
685 | hi_byte = inb(instance->val_reg); | ||
686 | spin_unlock(instance->ctrl_reg_lock); | ||
687 | |||
688 | *value = lo_byte | (hi_byte << 8); | ||
689 | spin_unlock(&instance->subdevice_lock); | ||
690 | |||
691 | ME_SUBDEVICE_EXIT; | ||
692 | |||
693 | return ME_ERRNO_SUCCESS; | ||
694 | } | ||
695 | |||
696 | static int me8254_io_single_write(struct me_subdevice *subdevice, | ||
697 | struct file *filep, | ||
698 | int channel, | ||
699 | int value, int time_out, int flags) | ||
700 | { | ||
701 | me8254_subdevice_t *instance; | ||
702 | |||
703 | PDEBUG("executed.\n"); | ||
704 | |||
705 | if (channel) { | ||
706 | PERROR("Invalid channel.\n"); | ||
707 | return ME_ERRNO_INVALID_CHANNEL; | ||
708 | } | ||
709 | |||
710 | instance = (me8254_subdevice_t *) subdevice; | ||
711 | |||
712 | if (flags) { | ||
713 | PERROR("Invalid flag specified.\n"); | ||
714 | return ME_ERRNO_INVALID_FLAGS; | ||
715 | } | ||
716 | |||
717 | ME_SUBDEVICE_ENTER; | ||
718 | |||
719 | spin_lock(&instance->subdevice_lock); | ||
720 | outb(value, instance->val_reg); | ||
721 | outb((value >> 8), instance->val_reg); | ||
722 | spin_unlock(&instance->subdevice_lock); | ||
723 | |||
724 | ME_SUBDEVICE_EXIT; | ||
725 | |||
726 | return ME_ERRNO_SUCCESS; | ||
727 | } | ||
728 | |||
729 | static int me8254_query_number_channels(struct me_subdevice *subdevice, | ||
730 | int *number) | ||
731 | { | ||
732 | PDEBUG("executed.\n"); | ||
733 | *number = ME8254_NUMBER_CHANNELS; | ||
734 | return ME_ERRNO_SUCCESS; | ||
735 | } | ||
736 | |||
737 | static int me8254_query_subdevice_type(struct me_subdevice *subdevice, | ||
738 | int *type, int *subtype) | ||
739 | { | ||
740 | PDEBUG("executed.\n"); | ||
741 | *type = ME_TYPE_CTR; | ||
742 | *subtype = ME_SUBTYPE_CTR_8254; | ||
743 | return ME_ERRNO_SUCCESS; | ||
744 | } | ||
745 | |||
746 | static int me8254_query_subdevice_caps(struct me_subdevice *subdevice, | ||
747 | int *caps) | ||
748 | { | ||
749 | me8254_subdevice_t *instance; | ||
750 | PDEBUG("executed.\n"); | ||
751 | instance = (me8254_subdevice_t *) subdevice; | ||
752 | *caps = instance->caps; | ||
753 | return ME_ERRNO_SUCCESS; | ||
754 | } | ||
755 | |||
756 | static int me8254_query_subdevice_caps_args(struct me_subdevice *subdevice, | ||
757 | int cap, int *args, int count) | ||
758 | { | ||
759 | PDEBUG("executed.\n"); | ||
760 | |||
761 | if (count != 1) { | ||
762 | PERROR("Invalid capability argument count.\n"); | ||
763 | return ME_ERRNO_INVALID_CAP_ARG_COUNT; | ||
764 | } | ||
765 | |||
766 | if (cap == ME_CAP_CTR_WIDTH) { | ||
767 | args[0] = ME8254_CTR_WIDTH; | ||
768 | } else { | ||
769 | PERROR("Invalid capability.\n"); | ||
770 | return ME_ERRNO_INVALID_CAP; | ||
771 | } | ||
772 | |||
773 | return ME_ERRNO_SUCCESS; | ||
774 | } | ||
775 | |||
776 | static uint32_t me1400AB_get_val_reg(uint32_t reg_base, unsigned int me8254_idx, | ||
777 | unsigned int ctr_idx) | ||
778 | { | ||
779 | switch (me8254_idx) { | ||
780 | |||
781 | case 0: | ||
782 | return (reg_base + ME1400AB_8254_A_0_VAL_REG + ctr_idx); | ||
783 | |||
784 | default: | ||
785 | return (reg_base + ME1400AB_8254_B_0_VAL_REG + ctr_idx); | ||
786 | } | ||
787 | |||
788 | return 0; | ||
789 | } | ||
790 | |||
791 | static uint32_t me1400AB_get_ctrl_reg(uint32_t reg_base, | ||
792 | unsigned int me8254_idx, | ||
793 | unsigned int ctr_idx) | ||
794 | { | ||
795 | switch (me8254_idx) { | ||
796 | case 0: | ||
797 | return (reg_base + ME1400AB_8254_A_CTRL_REG); | ||
798 | |||
799 | default: | ||
800 | return (reg_base + ME1400AB_8254_B_CTRL_REG); | ||
801 | } | ||
802 | |||
803 | return 0; | ||
804 | } | ||
805 | |||
806 | static uint32_t me1400AB_get_clk_src_reg(uint32_t reg_base, | ||
807 | unsigned int me8254_idx, | ||
808 | unsigned int ctr_idx) | ||
809 | { | ||
810 | switch (me8254_idx) { | ||
811 | case 0: | ||
812 | return (reg_base + ME1400AB_CLK_SRC_REG); | ||
813 | |||
814 | default: | ||
815 | return (reg_base + ME1400AB_CLK_SRC_REG); | ||
816 | } | ||
817 | |||
818 | return 0; | ||
819 | } | ||
820 | |||
821 | static uint32_t me1400CD_get_val_reg(uint32_t reg_base, unsigned int me8254_idx, | ||
822 | unsigned int ctr_idx) | ||
823 | { | ||
824 | switch (me8254_idx) { | ||
825 | case 0: | ||
826 | return (reg_base + ME1400C_8254_A_0_VAL_REG + ctr_idx); | ||
827 | |||
828 | case 1: | ||
829 | return (reg_base + ME1400C_8254_B_0_VAL_REG + ctr_idx); | ||
830 | |||
831 | case 2: | ||
832 | return (reg_base + ME1400C_8254_C_0_VAL_REG + ctr_idx); | ||
833 | |||
834 | case 3: | ||
835 | return (reg_base + ME1400C_8254_D_0_VAL_REG + ctr_idx); | ||
836 | |||
837 | case 4: | ||
838 | return (reg_base + ME1400C_8254_E_0_VAL_REG + ctr_idx); | ||
839 | |||
840 | case 5: | ||
841 | return (reg_base + ME1400D_8254_A_0_VAL_REG + ctr_idx); | ||
842 | |||
843 | case 6: | ||
844 | return (reg_base + ME1400D_8254_B_0_VAL_REG + ctr_idx); | ||
845 | |||
846 | case 7: | ||
847 | return (reg_base + ME1400D_8254_C_0_VAL_REG + ctr_idx); | ||
848 | |||
849 | case 8: | ||
850 | return (reg_base + ME1400D_8254_D_0_VAL_REG + ctr_idx); | ||
851 | |||
852 | default: | ||
853 | return (reg_base + ME1400D_8254_E_0_VAL_REG + ctr_idx); | ||
854 | } | ||
855 | |||
856 | return 0; | ||
857 | } | ||
858 | |||
859 | static uint32_t me1400CD_get_ctrl_reg(uint32_t reg_base, | ||
860 | unsigned int me8254_idx, | ||
861 | unsigned int ctr_idx) | ||
862 | { | ||
863 | switch (me8254_idx) { | ||
864 | case 0: | ||
865 | return (reg_base + ME1400C_8254_A_CTRL_REG); | ||
866 | |||
867 | case 1: | ||
868 | return (reg_base + ME1400C_8254_B_CTRL_REG); | ||
869 | |||
870 | case 2: | ||
871 | return (reg_base + ME1400C_8254_C_CTRL_REG); | ||
872 | |||
873 | case 3: | ||
874 | return (reg_base + ME1400C_8254_D_CTRL_REG); | ||
875 | |||
876 | case 4: | ||
877 | return (reg_base + ME1400C_8254_E_CTRL_REG); | ||
878 | |||
879 | case 5: | ||
880 | return (reg_base + ME1400D_8254_A_CTRL_REG); | ||
881 | |||
882 | case 6: | ||
883 | return (reg_base + ME1400D_8254_B_CTRL_REG); | ||
884 | |||
885 | case 7: | ||
886 | return (reg_base + ME1400D_8254_C_CTRL_REG); | ||
887 | |||
888 | case 8: | ||
889 | return (reg_base + ME1400D_8254_D_CTRL_REG); | ||
890 | |||
891 | default: | ||
892 | return (reg_base + ME1400D_8254_E_CTRL_REG); | ||
893 | } | ||
894 | |||
895 | return 0; | ||
896 | } | ||
897 | |||
898 | static uint32_t me1400CD_get_clk_src_reg(uint32_t reg_base, | ||
899 | unsigned int me8254_idx, | ||
900 | unsigned int ctr_idx) | ||
901 | { | ||
902 | switch (me8254_idx) { | ||
903 | case 0: | ||
904 | return (reg_base + ME1400C_CLK_SRC_0_REG); | ||
905 | |||
906 | case 1: | ||
907 | return (reg_base + ME1400C_CLK_SRC_0_REG); | ||
908 | |||
909 | case 2: | ||
910 | return (reg_base + ME1400C_CLK_SRC_1_REG); | ||
911 | |||
912 | case 3: | ||
913 | return (reg_base + ME1400C_CLK_SRC_1_REG); | ||
914 | |||
915 | case 4: | ||
916 | return (reg_base + ME1400C_CLK_SRC_2_REG); | ||
917 | |||
918 | case 5: | ||
919 | return (reg_base + ME1400D_CLK_SRC_0_REG); | ||
920 | |||
921 | case 6: | ||
922 | return (reg_base + ME1400D_CLK_SRC_0_REG); | ||
923 | |||
924 | case 7: | ||
925 | return (reg_base + ME1400D_CLK_SRC_1_REG); | ||
926 | |||
927 | case 8: | ||
928 | return (reg_base + ME1400D_CLK_SRC_1_REG); | ||
929 | |||
930 | default: | ||
931 | return (reg_base + ME1400D_CLK_SRC_2_REG); | ||
932 | } | ||
933 | |||
934 | return 0; | ||
935 | } | ||
936 | |||
937 | static uint32_t me4600_get_val_reg(uint32_t reg_base, unsigned int me8254_idx, | ||
938 | unsigned int ctr_idx) | ||
939 | { | ||
940 | return (reg_base + ME4600_8254_0_VAL_REG + ctr_idx); | ||
941 | } | ||
942 | |||
943 | static uint32_t me4600_get_ctrl_reg(uint32_t reg_base, unsigned int me8254_idx, | ||
944 | unsigned int ctr_idx) | ||
945 | { | ||
946 | return (reg_base + ME4600_8254_CTRL_REG); | ||
947 | } | ||
948 | |||
949 | static uint32_t me8100_get_val_reg(uint32_t reg_base, unsigned int me8254_idx, | ||
950 | unsigned int ctr_idx) | ||
951 | { | ||
952 | return (reg_base + ME8100_COUNTER_REG_0 + ctr_idx * 2); | ||
953 | } | ||
954 | |||
955 | static uint32_t me8100_get_ctrl_reg(uint32_t reg_base, unsigned int me8254_idx, | ||
956 | unsigned int ctr_idx) | ||
957 | { | ||
958 | return (reg_base + ME8100_COUNTER_CTRL_REG); | ||
959 | } | ||
960 | |||
961 | me8254_subdevice_t *me8254_constructor(uint32_t device_id, | ||
962 | uint32_t reg_base, | ||
963 | unsigned int me8254_idx, | ||
964 | unsigned int ctr_idx, | ||
965 | spinlock_t * ctrl_reg_lock, | ||
966 | spinlock_t * clk_src_reg_lock) | ||
967 | { | ||
968 | me8254_subdevice_t *subdevice; | ||
969 | int err; | ||
970 | |||
971 | PDEBUG("executed.\n"); | ||
972 | |||
973 | // Allocate memory for subdevice instance | ||
974 | subdevice = kmalloc(sizeof(me8254_subdevice_t), GFP_KERNEL); | ||
975 | |||
976 | if (!subdevice) { | ||
977 | PERROR("Cannot get memory for 8254 instance.\n"); | ||
978 | return NULL; | ||
979 | } | ||
980 | |||
981 | memset(subdevice, 0, sizeof(me8254_subdevice_t)); | ||
982 | |||
983 | // Check if counter index is out of range | ||
984 | |||
985 | if (ctr_idx > 2) { | ||
986 | PERROR("Counter index is out of range.\n"); | ||
987 | kfree(subdevice); | ||
988 | return NULL; | ||
989 | } | ||
990 | // Initialize subdevice base class | ||
991 | err = me_subdevice_init(&subdevice->base); | ||
992 | |||
993 | if (err) { | ||
994 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
995 | kfree(subdevice); | ||
996 | return NULL; | ||
997 | } | ||
998 | // Initialize spin locks. | ||
999 | spin_lock_init(&subdevice->subdevice_lock); | ||
1000 | subdevice->ctrl_reg_lock = ctrl_reg_lock; | ||
1001 | subdevice->clk_src_reg_lock = clk_src_reg_lock; | ||
1002 | |||
1003 | // Save type of Meilhaus device | ||
1004 | subdevice->device_id = device_id; | ||
1005 | |||
1006 | // Save the indices | ||
1007 | subdevice->me8254_idx = me8254_idx; | ||
1008 | subdevice->ctr_idx = ctr_idx; | ||
1009 | |||
1010 | // Do device specific initialization | ||
1011 | switch (device_id) { | ||
1012 | |||
1013 | case PCI_DEVICE_ID_MEILHAUS_ME140A: | ||
1014 | case PCI_DEVICE_ID_MEILHAUS_ME14EA: | ||
1015 | // Check if 8254 index is out of range | ||
1016 | if (me8254_idx > 0) { | ||
1017 | PERROR("8254 index is out of range.\n"); | ||
1018 | me_subdevice_deinit(&subdevice->base); | ||
1019 | kfree(subdevice); | ||
1020 | return NULL; | ||
1021 | } | ||
1022 | |||
1023 | case PCI_DEVICE_ID_MEILHAUS_ME140B: // Fall through | ||
1024 | case PCI_DEVICE_ID_MEILHAUS_ME14EB: | ||
1025 | // Check if 8254 index is out of range | ||
1026 | if (me8254_idx > 1) { | ||
1027 | PERROR("8254 index is out of range.\n"); | ||
1028 | me_subdevice_deinit(&subdevice->base); | ||
1029 | kfree(subdevice); | ||
1030 | return NULL; | ||
1031 | } | ||
1032 | // Initialize the counters capabilities | ||
1033 | if (ctr_idx == 0) | ||
1034 | subdevice->caps = | ||
1035 | ME_CAPS_CTR_CLK_INTERNAL_1MHZ | | ||
1036 | ME_CAPS_CTR_CLK_INTERNAL_10MHZ | | ||
1037 | ME_CAPS_CTR_CLK_EXTERNAL; | ||
1038 | else | ||
1039 | subdevice->caps = | ||
1040 | ME_CAPS_CTR_CLK_PREVIOUS | ME_CAPS_CTR_CLK_EXTERNAL; | ||
1041 | |||
1042 | // Get the counters registers | ||
1043 | subdevice->val_reg = | ||
1044 | me1400AB_get_val_reg(reg_base, me8254_idx, ctr_idx); | ||
1045 | subdevice->ctrl_reg = | ||
1046 | me1400AB_get_ctrl_reg(reg_base, me8254_idx, ctr_idx); | ||
1047 | subdevice->clk_src_reg = | ||
1048 | me1400AB_get_clk_src_reg(reg_base, me8254_idx, ctr_idx); | ||
1049 | break; | ||
1050 | |||
1051 | case PCI_DEVICE_ID_MEILHAUS_ME140C: | ||
1052 | // Check if 8254 index is out of range | ||
1053 | if (me8254_idx > 4) { | ||
1054 | PERROR("8254 index is out of range.\n"); | ||
1055 | me_subdevice_deinit(&subdevice->base); | ||
1056 | kfree(subdevice); | ||
1057 | return NULL; | ||
1058 | } | ||
1059 | |||
1060 | case PCI_DEVICE_ID_MEILHAUS_ME140D: | ||
1061 | // Check if 8254 index is out of range | ||
1062 | if (me8254_idx > 9) { | ||
1063 | PERROR("8254 index is out of range.\n"); | ||
1064 | me_subdevice_deinit(&subdevice->base); | ||
1065 | kfree(subdevice); | ||
1066 | return NULL; | ||
1067 | } | ||
1068 | // Initialize the counters capabilities | ||
1069 | if (ctr_idx == 0) { | ||
1070 | if (me8254_idx == 0) | ||
1071 | subdevice->caps = | ||
1072 | ME_CAPS_CTR_CLK_PREVIOUS | | ||
1073 | ME_CAPS_CTR_CLK_INTERNAL_1MHZ | | ||
1074 | ME_CAPS_CTR_CLK_INTERNAL_10MHZ | | ||
1075 | ME_CAPS_CTR_CLK_EXTERNAL; | ||
1076 | else | ||
1077 | subdevice->caps = | ||
1078 | ME_CAPS_CTR_CLK_INTERNAL_1MHZ | | ||
1079 | ME_CAPS_CTR_CLK_INTERNAL_10MHZ | | ||
1080 | ME_CAPS_CTR_CLK_EXTERNAL; | ||
1081 | } else | ||
1082 | subdevice->caps = | ||
1083 | ME_CAPS_CTR_CLK_PREVIOUS | ME_CAPS_CTR_CLK_EXTERNAL; | ||
1084 | |||
1085 | // Get the counters registers | ||
1086 | subdevice->val_reg = | ||
1087 | me1400CD_get_val_reg(reg_base, me8254_idx, ctr_idx); | ||
1088 | subdevice->ctrl_reg = | ||
1089 | me1400CD_get_ctrl_reg(reg_base, me8254_idx, ctr_idx); | ||
1090 | subdevice->clk_src_reg = | ||
1091 | me1400CD_get_clk_src_reg(reg_base, me8254_idx, ctr_idx); | ||
1092 | break; | ||
1093 | |||
1094 | case PCI_DEVICE_ID_MEILHAUS_ME4610: | ||
1095 | case PCI_DEVICE_ID_MEILHAUS_ME4660: | ||
1096 | case PCI_DEVICE_ID_MEILHAUS_ME4660I: | ||
1097 | case PCI_DEVICE_ID_MEILHAUS_ME4660S: | ||
1098 | case PCI_DEVICE_ID_MEILHAUS_ME4660IS: | ||
1099 | case PCI_DEVICE_ID_MEILHAUS_ME4670: | ||
1100 | case PCI_DEVICE_ID_MEILHAUS_ME4670I: | ||
1101 | case PCI_DEVICE_ID_MEILHAUS_ME4670S: | ||
1102 | case PCI_DEVICE_ID_MEILHAUS_ME4670IS: | ||
1103 | case PCI_DEVICE_ID_MEILHAUS_ME4680: | ||
1104 | case PCI_DEVICE_ID_MEILHAUS_ME4680I: | ||
1105 | case PCI_DEVICE_ID_MEILHAUS_ME4680S: | ||
1106 | case PCI_DEVICE_ID_MEILHAUS_ME4680IS: | ||
1107 | // Check if 8254 index is out of range | ||
1108 | if (me8254_idx > 0) { | ||
1109 | PERROR("8254 index is out of range.\n"); | ||
1110 | me_subdevice_deinit(&subdevice->base); | ||
1111 | kfree(subdevice); | ||
1112 | return NULL; | ||
1113 | } | ||
1114 | // Initialize the counters capabilities | ||
1115 | subdevice->caps = ME_CAPS_CTR_CLK_EXTERNAL; | ||
1116 | |||
1117 | // Get the counters registers | ||
1118 | subdevice->val_reg = | ||
1119 | me4600_get_val_reg(reg_base, me8254_idx, ctr_idx); | ||
1120 | subdevice->ctrl_reg = | ||
1121 | me4600_get_ctrl_reg(reg_base, me8254_idx, ctr_idx); | ||
1122 | subdevice->clk_src_reg = 0; // Not used | ||
1123 | break; | ||
1124 | |||
1125 | case PCI_DEVICE_ID_MEILHAUS_ME8100_A: | ||
1126 | case PCI_DEVICE_ID_MEILHAUS_ME8100_B: | ||
1127 | // Check if 8254 index is out of range | ||
1128 | if (me8254_idx > 0) { | ||
1129 | PERROR("8254 index is out of range.\n"); | ||
1130 | me_subdevice_deinit(&subdevice->base); | ||
1131 | kfree(subdevice); | ||
1132 | return NULL; | ||
1133 | } | ||
1134 | // Initialize the counters capabilities | ||
1135 | subdevice->caps = ME_CAPS_CTR_CLK_EXTERNAL; | ||
1136 | |||
1137 | // Get the counters registers | ||
1138 | subdevice->val_reg = | ||
1139 | me8100_get_val_reg(reg_base, me8254_idx, ctr_idx); | ||
1140 | subdevice->ctrl_reg = | ||
1141 | me8100_get_ctrl_reg(reg_base, me8254_idx, ctr_idx); | ||
1142 | subdevice->clk_src_reg = 0; // Not used | ||
1143 | break; | ||
1144 | |||
1145 | case PCI_DEVICE_ID_MEILHAUS_ME4650: | ||
1146 | case PCI_DEVICE_ID_MEILHAUS_ME1400: | ||
1147 | case PCI_DEVICE_ID_MEILHAUS_ME14E0: | ||
1148 | PERROR("No 8254 subdevices available for subdevice device.\n"); | ||
1149 | me_subdevice_deinit(&subdevice->base); | ||
1150 | kfree(subdevice); | ||
1151 | return NULL; | ||
1152 | |||
1153 | default: | ||
1154 | PERROR("Unknown device type.\n"); | ||
1155 | me_subdevice_deinit(&subdevice->base); | ||
1156 | kfree(subdevice); | ||
1157 | return NULL; | ||
1158 | } | ||
1159 | |||
1160 | // Overload subdevice base class methods. | ||
1161 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
1162 | me8254_io_reset_subdevice; | ||
1163 | subdevice->base.me_subdevice_io_single_config = me8254_io_single_config; | ||
1164 | subdevice->base.me_subdevice_io_single_read = me8254_io_single_read; | ||
1165 | subdevice->base.me_subdevice_io_single_write = me8254_io_single_write; | ||
1166 | subdevice->base.me_subdevice_query_number_channels = | ||
1167 | me8254_query_number_channels; | ||
1168 | subdevice->base.me_subdevice_query_subdevice_type = | ||
1169 | me8254_query_subdevice_type; | ||
1170 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
1171 | me8254_query_subdevice_caps; | ||
1172 | subdevice->base.me_subdevice_query_subdevice_caps_args = | ||
1173 | me8254_query_subdevice_caps_args; | ||
1174 | |||
1175 | return subdevice; | ||
1176 | } | ||
diff --git a/drivers/staging/meilhaus/me8254.h b/drivers/staging/meilhaus/me8254.h new file mode 100644 index 000000000000..572b7196d5a8 --- /dev/null +++ b/drivers/staging/meilhaus/me8254.h | |||
@@ -0,0 +1,80 @@ | |||
1 | /** | ||
2 | * @file me8254.h | ||
3 | * | ||
4 | * @brief 8254 counter implementation. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _ME8254_H_ | ||
28 | #define _ME8254_H_ | ||
29 | |||
30 | #include "mesubdevice.h" | ||
31 | #include "meslock.h" | ||
32 | |||
33 | #ifdef __KERNEL__ | ||
34 | |||
35 | /** | ||
36 | * @brief The 8254 subdevice class. | ||
37 | */ | ||
38 | typedef struct me8254_subdevice { | ||
39 | /* Inheritance */ | ||
40 | me_subdevice_t base; /**< The subdevice base class. */ | ||
41 | |||
42 | /* Attributes */ | ||
43 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
44 | |||
45 | spinlock_t *ctrl_reg_lock; /**< Spin lock to protect the control register from concurrent access. */ | ||
46 | spinlock_t *clk_src_reg_lock; /**< Spin lock to protect the clock source register from concurrent access. */ | ||
47 | |||
48 | uint32_t device_id; /**< The Meilhaus device type carrying the 8254 chip. */ | ||
49 | int me8254_idx; /**< The index of the 8254 chip on the device. */ | ||
50 | int ctr_idx; /**< The index of the counter on the 8254 chip. */ | ||
51 | |||
52 | int caps; /**< Holds the device capabilities. */ | ||
53 | |||
54 | unsigned long val_reg; /**< Holds the actual counter value. */ | ||
55 | unsigned long ctrl_reg; /**< Register to configure the 8254 modes. */ | ||
56 | unsigned long clk_src_reg; /**< Register to configure the counter connections. */ | ||
57 | } me8254_subdevice_t; | ||
58 | |||
59 | /** | ||
60 | * @brief The constructor to generate a 8254 instance. | ||
61 | * | ||
62 | * @param device_id The kind of Meilhaus device holding the 8254. | ||
63 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
64 | * @param me8254_idx The index of the 8254 chip on the Meilhaus device. | ||
65 | * @param ctr_idx The index of the counter inside a 8254 chip. | ||
66 | * @param ctrl_reg_lock Pointer to spin lock protecting the 8254 control register from concurrent access. | ||
67 | * @param clk_src_reg_lock Pointer to spin lock protecting the clock source register from concurrent access. | ||
68 | * | ||
69 | * @return Pointer to new instance on success.\n | ||
70 | * NULL on error. | ||
71 | */ | ||
72 | me8254_subdevice_t *me8254_constructor(uint32_t device_id, | ||
73 | uint32_t reg_base, | ||
74 | unsigned int me8254_idx, | ||
75 | unsigned int ctr_idx, | ||
76 | spinlock_t * ctrl_reg_lock, | ||
77 | spinlock_t * clk_src_reg_lock); | ||
78 | |||
79 | #endif | ||
80 | #endif | ||
diff --git a/drivers/staging/meilhaus/me8254_reg.h b/drivers/staging/meilhaus/me8254_reg.h new file mode 100644 index 000000000000..7e2c36b46f56 --- /dev/null +++ b/drivers/staging/meilhaus/me8254_reg.h | |||
@@ -0,0 +1,172 @@ | |||
1 | /** | ||
2 | * @file me8254_reg.h | ||
3 | * | ||
4 | * @brief 8254 counter register definitions. | ||
5 | * @note Copyright (C) 2006 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | #ifndef _ME8254_REG_H_ | ||
10 | #define _ME8254_REG_H_ | ||
11 | |||
12 | #ifdef __KERNEL__ | ||
13 | |||
14 | /* ME1400 A/B register offsets */ | ||
15 | #define ME1400AB_8254_A_0_VAL_REG 0x0004 /**< Offset of 8254 A counter 0 value register. */ | ||
16 | #define ME1400AB_8254_A_1_VAL_REG 0x0005 /**< Offset of 8254 A counter 1 value register. */ | ||
17 | #define ME1400AB_8254_A_2_VAL_REG 0x0006 /**< Offset of 8254 A counter 2 value register. */ | ||
18 | #define ME1400AB_8254_A_CTRL_REG 0x0007 /**< Offset of 8254 A control register. */ | ||
19 | |||
20 | #define ME1400AB_8254_B_0_VAL_REG 0x000C /**< Offset of 8254 B counter 0 value register. */ | ||
21 | #define ME1400AB_8254_B_1_VAL_REG 0x000D /**< Offset of 8254 B counter 1 value register. */ | ||
22 | #define ME1400AB_8254_B_2_VAL_REG 0x000E /**< Offset of 8254 B counter 2 value register. */ | ||
23 | #define ME1400AB_8254_B_CTRL_REG 0x000F /**< Offset of 8254 B control register. */ | ||
24 | |||
25 | #define ME1400AB_CLK_SRC_REG 0x0010 /**< Offset of clock source register. */ | ||
26 | |||
27 | /* ME1400 C register offsets */ | ||
28 | #define ME1400C_8254_A_0_VAL_REG 0x0004 /**< Offset of 8254 A counter 0 value register. */ | ||
29 | #define ME1400C_8254_A_1_VAL_REG 0x0005 /**< Offset of 8254 A counter 0 value register. */ | ||
30 | #define ME1400C_8254_A_2_VAL_REG 0x0006 /**< Offset of 8254 A counter 0 value register. */ | ||
31 | #define ME1400C_8254_A_CTRL_REG 0x0007 /**< Offset of 8254 A control register. */ | ||
32 | |||
33 | #define ME1400C_8254_B_0_VAL_REG 0x000C /**< Offset of 8254 B counter 0 value register. */ | ||
34 | #define ME1400C_8254_B_1_VAL_REG 0x000D /**< Offset of 8254 B counter 0 value register. */ | ||
35 | #define ME1400C_8254_B_2_VAL_REG 0x000E /**< Offset of 8254 B counter 0 value register. */ | ||
36 | #define ME1400C_8254_B_CTRL_REG 0x000F /**< Offset of 8254 B control register. */ | ||
37 | |||
38 | #define ME1400C_8254_C_0_VAL_REG 0x0010 /**< Offset of 8254 C counter 0 value register. */ | ||
39 | #define ME1400C_8254_C_1_VAL_REG 0x0011 /**< Offset of 8254 C counter 0 value register. */ | ||
40 | #define ME1400C_8254_C_2_VAL_REG 0x0012 /**< Offset of 8254 C counter 0 value register. */ | ||
41 | #define ME1400C_8254_C_CTRL_REG 0x0013 /**< Offset of 8254 C control register. */ | ||
42 | |||
43 | #define ME1400C_8254_D_0_VAL_REG 0x0014 /**< Offset of 8254 D counter 0 value register. */ | ||
44 | #define ME1400C_8254_D_1_VAL_REG 0x0015 /**< Offset of 8254 D counter 0 value register. */ | ||
45 | #define ME1400C_8254_D_2_VAL_REG 0x0016 /**< Offset of 8254 D counter 0 value register. */ | ||
46 | #define ME1400C_8254_D_CTRL_REG 0x0017 /**< Offset of 8254 D control register. */ | ||
47 | |||
48 | #define ME1400C_8254_E_0_VAL_REG 0x0018 /**< Offset of 8254 E counter 0 value register. */ | ||
49 | #define ME1400C_8254_E_1_VAL_REG 0x0019 /**< Offset of 8254 E counter 0 value register. */ | ||
50 | #define ME1400C_8254_E_2_VAL_REG 0x001A /**< Offset of 8254 E counter 0 value register. */ | ||
51 | #define ME1400C_8254_E_CTRL_REG 0x001B /**< Offset of 8254 E control register. */ | ||
52 | |||
53 | #define ME1400C_CLK_SRC_0_REG 0x001C /**< Offset of clock source register 0. */ | ||
54 | #define ME1400C_CLK_SRC_1_REG 0x001D /**< Offset of clock source register 1. */ | ||
55 | #define ME1400C_CLK_SRC_2_REG 0x001E /**< Offset of clock source register 2. */ | ||
56 | |||
57 | /* ME1400 D register offsets */ | ||
58 | #define ME1400D_8254_A_0_VAL_REG 0x0044 /**< Offset of 8254 A counter 0 value register. */ | ||
59 | #define ME1400D_8254_A_1_VAL_REG 0x0045 /**< Offset of 8254 A counter 0 value register. */ | ||
60 | #define ME1400D_8254_A_2_VAL_REG 0x0046 /**< Offset of 8254 A counter 0 value register. */ | ||
61 | #define ME1400D_8254_A_CTRL_REG 0x0047 /**< Offset of 8254 A control register. */ | ||
62 | |||
63 | #define ME1400D_8254_B_0_VAL_REG 0x004C /**< Offset of 8254 B counter 0 value register. */ | ||
64 | #define ME1400D_8254_B_1_VAL_REG 0x004D /**< Offset of 8254 B counter 0 value register. */ | ||
65 | #define ME1400D_8254_B_2_VAL_REG 0x004E /**< Offset of 8254 B counter 0 value register. */ | ||
66 | #define ME1400D_8254_B_CTRL_REG 0x004F /**< Offset of 8254 B control register. */ | ||
67 | |||
68 | #define ME1400D_8254_C_0_VAL_REG 0x0050 /**< Offset of 8254 C counter 0 value register. */ | ||
69 | #define ME1400D_8254_C_1_VAL_REG 0x0051 /**< Offset of 8254 C counter 0 value register. */ | ||
70 | #define ME1400D_8254_C_2_VAL_REG 0x0052 /**< Offset of 8254 C counter 0 value register. */ | ||
71 | #define ME1400D_8254_C_CTRL_REG 0x0053 /**< Offset of 8254 C control register. */ | ||
72 | |||
73 | #define ME1400D_8254_D_0_VAL_REG 0x0054 /**< Offset of 8254 D counter 0 value register. */ | ||
74 | #define ME1400D_8254_D_1_VAL_REG 0x0055 /**< Offset of 8254 D counter 0 value register. */ | ||
75 | #define ME1400D_8254_D_2_VAL_REG 0x0056 /**< Offset of 8254 D counter 0 value register. */ | ||
76 | #define ME1400D_8254_D_CTRL_REG 0x0057 /**< Offset of 8254 D control register. */ | ||
77 | |||
78 | #define ME1400D_8254_E_0_VAL_REG 0x0058 /**< Offset of 8254 E counter 0 value register. */ | ||
79 | #define ME1400D_8254_E_1_VAL_REG 0x0059 /**< Offset of 8254 E counter 0 value register. */ | ||
80 | #define ME1400D_8254_E_2_VAL_REG 0x005A /**< Offset of 8254 E counter 0 value register. */ | ||
81 | #define ME1400D_8254_E_CTRL_REG 0x005B /**< Offset of 8254 E control register. */ | ||
82 | |||
83 | #define ME1400D_CLK_SRC_0_REG 0x005C /**< Offset of clock source register 0. */ | ||
84 | #define ME1400D_CLK_SRC_1_REG 0x005D /**< Offset of clock source register 1. */ | ||
85 | #define ME1400D_CLK_SRC_2_REG 0x005E /**< Offset of clock source register 2. */ | ||
86 | |||
87 | /* ME4600 register offsets */ | ||
88 | #define ME4600_8254_0_VAL_REG 0x0000 /**< Offset of 8254 A counter 0 value register. */ | ||
89 | #define ME4600_8254_1_VAL_REG 0x0001 /**< Offset of 8254 A counter 0 value register. */ | ||
90 | #define ME4600_8254_2_VAL_REG 0x0002 /**< Offset of 8254 A counter 0 value register. */ | ||
91 | #define ME4600_8254_CTRL_REG 0x0003 /**< Offset of 8254 A control register. */ | ||
92 | |||
93 | /* Command words for 8254 control register */ | ||
94 | #define ME8254_CTRL_SC0 0x00 /**< Counter 0 selection. */ | ||
95 | #define ME8254_CTRL_SC1 0x40 /**< Counter 1 selection. */ | ||
96 | #define ME8254_CTRL_SC2 0x80 /**< Counter 2 selection. */ | ||
97 | |||
98 | #define ME8254_CTRL_TLO 0x00 /**< Counter latching operation. */ | ||
99 | #define ME8254_CTRL_LSB 0x10 /**< Only read LSB. */ | ||
100 | #define ME8254_CTRL_MSB 0x20 /**< Only read MSB. */ | ||
101 | #define ME8254_CTRL_LM 0x30 /**< First read LSB, then MSB. */ | ||
102 | |||
103 | #define ME8254_CTRL_M0 0x00 /**< Mode 0 selection. */ | ||
104 | #define ME8254_CTRL_M1 0x02 /**< Mode 1 selection. */ | ||
105 | #define ME8254_CTRL_M2 0x04 /**< Mode 2 selection. */ | ||
106 | #define ME8254_CTRL_M3 0x06 /**< Mode 3 selection. */ | ||
107 | #define ME8254_CTRL_M4 0x08 /**< Mode 4 selection. */ | ||
108 | #define ME8254_CTRL_M5 0x0A /**< Mode 5 selection. */ | ||
109 | |||
110 | #define ME8254_CTRL_BIN 0x00 /**< Binary counter. */ | ||
111 | #define ME8254_CTRL_BCD 0x01 /**< BCD counter. */ | ||
112 | |||
113 | /* ME-1400 A/B clock source register bits */ | ||
114 | #define ME1400AB_8254_A_0_CLK_SRC_1MHZ (0 << 7) /**< 1MHz clock. */ | ||
115 | #define ME1400AB_8254_A_0_CLK_SRC_10MHZ (1 << 7) /**< 10MHz clock. */ | ||
116 | #define ME1400AB_8254_A_0_CLK_SRC_PIN (0 << 6) /**< CLK 0 to SUB-D. */ | ||
117 | #define ME1400AB_8254_A_0_CLK_SRC_QUARZ (1 << 6) /**< Connect CLK 0 with quarz. */ | ||
118 | |||
119 | #define ME1400AB_8254_A_1_CLK_SRC_PIN (0 << 5) /**< CLK 1 to SUB-D. */ | ||
120 | #define ME1400AB_8254_A_1_CLK_SRC_PREV (1 << 5) /**< Connect OUT 0 with CLK 1. */ | ||
121 | |||
122 | #define ME1400AB_8254_A_2_CLK_SRC_PIN (0 << 4) /**< CLK 2 to SUB-D. */ | ||
123 | #define ME1400AB_8254_A_2_CLK_SRC_PREV (1 << 4) /**< Connect OUT 1 with CLK 2. */ | ||
124 | |||
125 | #define ME1400AB_8254_B_0_CLK_SRC_1MHZ (0 << 3) /**< 1MHz clock. */ | ||
126 | #define ME1400AB_8254_B_0_CLK_SRC_10MHZ (1 << 3) /**< 10MHz clock. */ | ||
127 | #define ME1400AB_8254_B_0_CLK_SRC_PIN (0 << 2) /**< CLK 0 to SUB-D. */ | ||
128 | #define ME1400AB_8254_B_0_CLK_SRC_QUARZ (1 << 2) /**< Connect CLK 0 with quarz. */ | ||
129 | |||
130 | #define ME1400AB_8254_B_1_CLK_SRC_PIN (0 << 1) /**< CLK 1 to SUB-D. */ | ||
131 | #define ME1400AB_8254_B_1_CLK_SRC_PREV (1 << 1) /**< Connect OUT 0 with CLK 1. */ | ||
132 | |||
133 | #define ME1400AB_8254_B_2_CLK_SRC_PIN (0 << 0) /**< CLK 2 to SUB-D. */ | ||
134 | #define ME1400AB_8254_B_2_CLK_SRC_PREV (1 << 0) /**< Connect OUT 1 with CLK 2. */ | ||
135 | |||
136 | /* ME-1400 C/D clock source registers bits */ | ||
137 | #define ME1400CD_8254_ACE_0_CLK_SRC_MASK 0x03 /**< Masks all CLK source bits. */ | ||
138 | #define ME1400CD_8254_ACE_0_CLK_SRC_PIN 0x00 /**< Connect CLK to SUB-D. */ | ||
139 | #define ME1400CD_8254_ACE_0_CLK_SRC_1MHZ 0x01 /**< Connect CLK to 1MHz. */ | ||
140 | #define ME1400CD_8254_ACE_0_CLK_SRC_10MHZ 0x02 /**< Connect CLK to 10MHz. */ | ||
141 | #define ME1400CD_8254_ACE_0_CLK_SRC_PREV 0x03 /**< Connect CLK to previous counter output on ME-1400 D extension. */ | ||
142 | |||
143 | #define ME1400CD_8254_ACE_1_CLK_SRC_MASK 0x04 /**< Masks all CLK source bits. */ | ||
144 | #define ME1400CD_8254_ACE_1_CLK_SRC_PIN 0x00 /**< Connect CLK to SUB-D. */ | ||
145 | #define ME1400CD_8254_ACE_1_CLK_SRC_PREV 0x04 /**< Connect CLK to previous counter output. */ | ||
146 | |||
147 | #define ME1400CD_8254_ACE_2_CLK_SRC_MASK 0x08 /**< Masks all CLK source bits. */ | ||
148 | #define ME1400CD_8254_ACE_2_CLK_SRC_PIN 0x00 /**< Connect to SUB-D. */ | ||
149 | #define ME1400CD_8254_ACE_2_CLK_SRC_PREV 0x08 /**< Connect CLK to previous counter output. */ | ||
150 | |||
151 | #define ME1400CD_8254_BD_0_CLK_SRC_MASK 0x30 /**< Masks all CLK source bits. */ | ||
152 | #define ME1400CD_8254_BD_0_CLK_SRC_PIN 0x00 /**< Connect CLK to SUB-D. */ | ||
153 | #define ME1400CD_8254_BD_0_CLK_SRC_1MHZ 0x10 /**< Connect CLK to 1MHz. */ | ||
154 | #define ME1400CD_8254_BD_0_CLK_SRC_10MHZ 0x20 /**< Connect CLK to 10MHz. */ | ||
155 | #define ME1400CD_8254_BD_0_CLK_SRC_PREV 0x30 /**< Connect CLK to previous counter output. */ | ||
156 | |||
157 | #define ME1400CD_8254_BD_1_CLK_SRC_MASK 0x40 /**< Masks all CLK source bits. */ | ||
158 | #define ME1400CD_8254_BD_1_CLK_SRC_PIN 0x00 /**< Connect CLK to SUB-D. */ | ||
159 | #define ME1400CD_8254_BD_1_CLK_SRC_PREV 0x40 /**< Connect CLK to previous counter output. */ | ||
160 | |||
161 | #define ME1400CD_8254_BD_2_CLK_SRC_MASK 0x80 /**< Masks all CLK source bits. */ | ||
162 | #define ME1400CD_8254_BD_2_CLK_SRC_PIN 0x00 /**< Connect CLK to SUB-D. */ | ||
163 | #define ME1400CD_8254_BD_2_CLK_SRC_PREV 0x80 /**< Connect CLK to previous counter output. */ | ||
164 | |||
165 | /* ME-8100 counter registers */ | ||
166 | #define ME8100_COUNTER_REG_0 0x18 //(r,w) | ||
167 | #define ME8100_COUNTER_REG_1 0x1A //(r,w) | ||
168 | #define ME8100_COUNTER_REG_2 0x1C //(r,w) | ||
169 | #define ME8100_COUNTER_CTRL_REG 0x1E //(r,w) | ||
170 | |||
171 | #endif | ||
172 | #endif | ||
diff --git a/drivers/staging/meilhaus/me8255.c b/drivers/staging/meilhaus/me8255.c new file mode 100644 index 000000000000..180e7f8d2146 --- /dev/null +++ b/drivers/staging/meilhaus/me8255.c | |||
@@ -0,0 +1,462 @@ | |||
1 | /** | ||
2 | * @file me8255.c | ||
3 | * | ||
4 | * @brief 8255 subdevice instance. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef __KERNEL__ | ||
28 | # define __KERNEL__ | ||
29 | #endif | ||
30 | |||
31 | /* | ||
32 | * Includes | ||
33 | */ | ||
34 | #include <linux/module.h> | ||
35 | |||
36 | #include <linux/slab.h> | ||
37 | #include <linux/spinlock.h> | ||
38 | #include <asm/io.h> | ||
39 | #include <linux/types.h> | ||
40 | |||
41 | #include "medefines.h" | ||
42 | #include "meinternal.h" | ||
43 | #include "meerror.h" | ||
44 | #include "medebug.h" | ||
45 | |||
46 | #include "me8255_reg.h" | ||
47 | #include "me8255.h" | ||
48 | |||
49 | /* | ||
50 | * Defines | ||
51 | */ | ||
52 | |||
53 | /* | ||
54 | * Functions | ||
55 | */ | ||
56 | |||
57 | static uint8_t get_mode_from_mirror(uint32_t mirror) | ||
58 | { | ||
59 | PDEBUG("executed.\n"); | ||
60 | |||
61 | if (mirror & ME8255_PORT_0_OUTPUT) { | ||
62 | if (mirror & ME8255_PORT_1_OUTPUT) { | ||
63 | if (mirror & ME8255_PORT_2_OUTPUT) { | ||
64 | return ME8255_MODE_OOO; | ||
65 | } else { | ||
66 | return ME8255_MODE_IOO; | ||
67 | } | ||
68 | } else { | ||
69 | if (mirror & ME8255_PORT_2_OUTPUT) { | ||
70 | return ME8255_MODE_OIO; | ||
71 | } else { | ||
72 | return ME8255_MODE_IIO; | ||
73 | } | ||
74 | } | ||
75 | } else { | ||
76 | if (mirror & ME8255_PORT_1_OUTPUT) { | ||
77 | if (mirror & ME8255_PORT_2_OUTPUT) { | ||
78 | return ME8255_MODE_OOI; | ||
79 | } else { | ||
80 | return ME8255_MODE_IOI; | ||
81 | } | ||
82 | } else { | ||
83 | if (mirror & ME8255_PORT_2_OUTPUT) { | ||
84 | return ME8255_MODE_OII; | ||
85 | } else { | ||
86 | return ME8255_MODE_III; | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | } | ||
91 | |||
92 | static int me8255_io_reset_subdevice(struct me_subdevice *subdevice, | ||
93 | struct file *filep, int flags) | ||
94 | { | ||
95 | me8255_subdevice_t *instance; | ||
96 | |||
97 | PDEBUG("executed.\n"); | ||
98 | |||
99 | instance = (me8255_subdevice_t *) subdevice; | ||
100 | |||
101 | if (flags) { | ||
102 | PERROR("Invalid flag specified.\n"); | ||
103 | return ME_ERRNO_INVALID_FLAGS; | ||
104 | } | ||
105 | |||
106 | ME_SUBDEVICE_ENTER; | ||
107 | |||
108 | spin_lock(&instance->subdevice_lock); | ||
109 | spin_lock(instance->ctrl_reg_lock); | ||
110 | *instance->ctrl_reg_mirror &= | ||
111 | ~(ME8255_PORT_0_OUTPUT << instance->dio_idx); | ||
112 | outb(get_mode_from_mirror(*instance->ctrl_reg_mirror), | ||
113 | instance->ctrl_reg); | ||
114 | spin_unlock(instance->ctrl_reg_lock); | ||
115 | |||
116 | outb(0, instance->port_reg); | ||
117 | spin_unlock(&instance->subdevice_lock); | ||
118 | |||
119 | ME_SUBDEVICE_EXIT; | ||
120 | |||
121 | return ME_ERRNO_SUCCESS; | ||
122 | } | ||
123 | |||
124 | static int me8255_io_single_config(struct me_subdevice *subdevice, | ||
125 | struct file *filep, | ||
126 | int channel, | ||
127 | int single_config, | ||
128 | int ref, | ||
129 | int trig_chan, | ||
130 | int trig_type, int trig_edge, int flags) | ||
131 | { | ||
132 | me8255_subdevice_t *instance; | ||
133 | int err = ME_ERRNO_SUCCESS; | ||
134 | |||
135 | PDEBUG("executed.\n"); | ||
136 | |||
137 | instance = (me8255_subdevice_t *) subdevice; | ||
138 | |||
139 | if (flags & ~ME_IO_SINGLE_CONFIG_DIO_BYTE) { | ||
140 | PERROR("Invalid flag specified.\n"); | ||
141 | return ME_ERRNO_INVALID_FLAGS; | ||
142 | } | ||
143 | |||
144 | if (channel) { | ||
145 | PERROR("Invalid channel.\n"); | ||
146 | return ME_ERRNO_INVALID_CHANNEL; | ||
147 | } | ||
148 | |||
149 | ME_SUBDEVICE_ENTER; | ||
150 | |||
151 | spin_lock(&instance->subdevice_lock); | ||
152 | if (single_config == ME_SINGLE_CONFIG_DIO_INPUT) { | ||
153 | spin_lock(instance->ctrl_reg_lock); | ||
154 | *instance->ctrl_reg_mirror &= | ||
155 | ~(ME8255_PORT_0_OUTPUT << instance->dio_idx); | ||
156 | outb(get_mode_from_mirror(*instance->ctrl_reg_mirror), | ||
157 | instance->ctrl_reg); | ||
158 | spin_unlock(instance->ctrl_reg_lock); | ||
159 | } else if (single_config == ME_SINGLE_CONFIG_DIO_OUTPUT) { | ||
160 | spin_lock(instance->ctrl_reg_lock); | ||
161 | *instance->ctrl_reg_mirror |= | ||
162 | (ME8255_PORT_0_OUTPUT << instance->dio_idx); | ||
163 | outb(get_mode_from_mirror(*instance->ctrl_reg_mirror), | ||
164 | instance->ctrl_reg); | ||
165 | spin_unlock(instance->ctrl_reg_lock); | ||
166 | } else { | ||
167 | PERROR("Invalid port direction.\n"); | ||
168 | err = ME_ERRNO_INVALID_SINGLE_CONFIG; | ||
169 | } | ||
170 | spin_unlock(&instance->subdevice_lock); | ||
171 | |||
172 | ME_SUBDEVICE_EXIT; | ||
173 | |||
174 | return err; | ||
175 | } | ||
176 | |||
177 | static int me8255_io_single_read(struct me_subdevice *subdevice, | ||
178 | struct file *filep, | ||
179 | int channel, | ||
180 | int *value, int time_out, int flags) | ||
181 | { | ||
182 | me8255_subdevice_t *instance; | ||
183 | int err = ME_ERRNO_SUCCESS; | ||
184 | |||
185 | PDEBUG("executed.\n"); | ||
186 | |||
187 | instance = (me8255_subdevice_t *) subdevice; | ||
188 | |||
189 | ME_SUBDEVICE_ENTER; | ||
190 | |||
191 | spin_lock(&instance->subdevice_lock); | ||
192 | switch (flags) { | ||
193 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
194 | if ((channel >= 0) && (channel < 8)) { | ||
195 | *value = inb(instance->port_reg) & (0x1 << channel); | ||
196 | } else { | ||
197 | PERROR("Invalid bit number.\n"); | ||
198 | err = ME_ERRNO_INVALID_CHANNEL; | ||
199 | } | ||
200 | break; | ||
201 | |||
202 | case ME_IO_SINGLE_NO_FLAGS: | ||
203 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
204 | if (channel == 0) { | ||
205 | *value = inb(instance->port_reg); | ||
206 | } else { | ||
207 | PERROR("Invalid byte number.\n"); | ||
208 | err = ME_ERRNO_INVALID_CHANNEL; | ||
209 | } | ||
210 | break; | ||
211 | |||
212 | default: | ||
213 | PERROR("Invalid flags specified.\n"); | ||
214 | err = ME_ERRNO_INVALID_FLAGS; | ||
215 | } | ||
216 | spin_unlock(&instance->subdevice_lock); | ||
217 | |||
218 | ME_SUBDEVICE_EXIT; | ||
219 | |||
220 | return err; | ||
221 | } | ||
222 | |||
223 | static int me8255_io_single_write(struct me_subdevice *subdevice, | ||
224 | struct file *filep, | ||
225 | int channel, | ||
226 | int value, int time_out, int flags) | ||
227 | { | ||
228 | me8255_subdevice_t *instance; | ||
229 | uint8_t byte; | ||
230 | int err = ME_ERRNO_SUCCESS; | ||
231 | |||
232 | PDEBUG("executed.\n"); | ||
233 | |||
234 | instance = (me8255_subdevice_t *) subdevice; | ||
235 | |||
236 | ME_SUBDEVICE_ENTER; | ||
237 | |||
238 | spin_lock(&instance->subdevice_lock); | ||
239 | switch (flags) { | ||
240 | case ME_IO_SINGLE_TYPE_DIO_BIT: | ||
241 | if ((channel >= 0) && (channel < 8)) { | ||
242 | if (*instance-> | ||
243 | ctrl_reg_mirror & (ME8255_PORT_0_OUTPUT << | ||
244 | instance->dio_idx)) { | ||
245 | byte = inb(instance->port_reg); | ||
246 | |||
247 | if (value) | ||
248 | byte |= 0x1 << channel; | ||
249 | else | ||
250 | byte &= ~(0x1 << channel); | ||
251 | |||
252 | outb(byte, instance->port_reg); | ||
253 | } else { | ||
254 | PERROR("Port not in output mode.\n"); | ||
255 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
256 | } | ||
257 | } else { | ||
258 | PERROR("Invalid bit number.\n"); | ||
259 | err = ME_ERRNO_INVALID_CHANNEL; | ||
260 | } | ||
261 | break; | ||
262 | |||
263 | case ME_IO_SINGLE_NO_FLAGS: | ||
264 | case ME_IO_SINGLE_TYPE_DIO_BYTE: | ||
265 | if (channel == 0) { | ||
266 | if (*instance-> | ||
267 | ctrl_reg_mirror & (ME8255_PORT_0_OUTPUT << | ||
268 | instance->dio_idx)) { | ||
269 | outb(value, instance->port_reg); | ||
270 | } else { | ||
271 | PERROR("Port not in output mode.\n"); | ||
272 | err = ME_ERRNO_PREVIOUS_CONFIG; | ||
273 | } | ||
274 | } else { | ||
275 | PERROR("Invalid byte number.\n"); | ||
276 | err = ME_ERRNO_INVALID_CHANNEL; | ||
277 | } | ||
278 | break; | ||
279 | |||
280 | default: | ||
281 | PERROR("Invalid flags specified.\n"); | ||
282 | err = ME_ERRNO_INVALID_FLAGS; | ||
283 | } | ||
284 | spin_unlock(&instance->subdevice_lock); | ||
285 | |||
286 | ME_SUBDEVICE_EXIT; | ||
287 | |||
288 | return err; | ||
289 | } | ||
290 | |||
291 | static int me8255_query_number_channels(struct me_subdevice *subdevice, | ||
292 | int *number) | ||
293 | { | ||
294 | PDEBUG("executed.\n"); | ||
295 | *number = ME8255_NUMBER_CHANNELS; | ||
296 | return ME_ERRNO_SUCCESS; | ||
297 | } | ||
298 | |||
299 | static int me8255_query_subdevice_type(struct me_subdevice *subdevice, | ||
300 | int *type, int *subtype) | ||
301 | { | ||
302 | PDEBUG("executed.\n"); | ||
303 | *type = ME_TYPE_DIO; | ||
304 | *subtype = ME_SUBTYPE_SINGLE; | ||
305 | return ME_ERRNO_SUCCESS; | ||
306 | } | ||
307 | |||
308 | static int me8255_query_subdevice_caps(struct me_subdevice *subdevice, | ||
309 | int *caps) | ||
310 | { | ||
311 | PDEBUG("executed.\n"); | ||
312 | *caps = ME_CAPS_DIO_DIR_BYTE; | ||
313 | return ME_ERRNO_SUCCESS; | ||
314 | } | ||
315 | |||
316 | me8255_subdevice_t *me8255_constructor(uint32_t device_id, | ||
317 | uint32_t reg_base, | ||
318 | unsigned int me8255_idx, | ||
319 | unsigned int dio_idx, | ||
320 | int *ctrl_reg_mirror, | ||
321 | spinlock_t * ctrl_reg_lock) | ||
322 | { | ||
323 | me8255_subdevice_t *subdevice; | ||
324 | int err; | ||
325 | |||
326 | PDEBUG("executed.\n"); | ||
327 | |||
328 | /* Allocate memory for subdevice instance */ | ||
329 | subdevice = kmalloc(sizeof(me8255_subdevice_t), GFP_KERNEL); | ||
330 | |||
331 | if (!subdevice) { | ||
332 | PERROR("Cannot get memory for 8255 instance.\n"); | ||
333 | return NULL; | ||
334 | } | ||
335 | |||
336 | memset(subdevice, 0, sizeof(me8255_subdevice_t)); | ||
337 | |||
338 | /* Check if counter index is out of range */ | ||
339 | |||
340 | if (dio_idx > 2) { | ||
341 | PERROR("DIO index is out of range.\n"); | ||
342 | kfree(subdevice); | ||
343 | return NULL; | ||
344 | } | ||
345 | |||
346 | /* Initialize subdevice base class */ | ||
347 | err = me_subdevice_init(&subdevice->base); | ||
348 | |||
349 | if (err) { | ||
350 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
351 | kfree(subdevice); | ||
352 | return NULL; | ||
353 | } | ||
354 | // Initialize spin locks. | ||
355 | spin_lock_init(&subdevice->subdevice_lock); | ||
356 | |||
357 | subdevice->ctrl_reg_lock = ctrl_reg_lock; | ||
358 | |||
359 | /* Save the pointer to global port settings */ | ||
360 | subdevice->ctrl_reg_mirror = ctrl_reg_mirror; | ||
361 | |||
362 | /* Save type of Meilhaus device */ | ||
363 | subdevice->device_id = device_id; | ||
364 | |||
365 | /* Save the indices */ | ||
366 | subdevice->me8255_idx = me8255_idx; | ||
367 | subdevice->dio_idx = dio_idx; | ||
368 | |||
369 | /* Do device specific initialization */ | ||
370 | switch (device_id) { | ||
371 | case PCI_DEVICE_ID_MEILHAUS_ME1400: | ||
372 | case PCI_DEVICE_ID_MEILHAUS_ME14E0: | ||
373 | |||
374 | case PCI_DEVICE_ID_MEILHAUS_ME140A: | ||
375 | case PCI_DEVICE_ID_MEILHAUS_ME14EA: | ||
376 | /* Check if 8255 index is out of range */ | ||
377 | if (me8255_idx > 0) { | ||
378 | PERROR("8255 index is out of range.\n"); | ||
379 | me_subdevice_deinit(&subdevice->base); | ||
380 | kfree(subdevice); | ||
381 | return NULL; | ||
382 | } | ||
383 | |||
384 | case PCI_DEVICE_ID_MEILHAUS_ME140B: /* Fall through */ | ||
385 | case PCI_DEVICE_ID_MEILHAUS_ME14EB: | ||
386 | /* Check if 8255 index is out of range */ | ||
387 | if (me8255_idx > 1) { | ||
388 | PERROR("8255 index is out of range.\n"); | ||
389 | me_subdevice_deinit(&subdevice->base); | ||
390 | kfree(subdevice); | ||
391 | return NULL; | ||
392 | } | ||
393 | |||
394 | /* Get the registers */ | ||
395 | if (me8255_idx == 0) { | ||
396 | subdevice->ctrl_reg = reg_base + ME1400AB_PORT_A_CTRL; | ||
397 | subdevice->port_reg = | ||
398 | reg_base + ME1400AB_PORT_A_0 + dio_idx; | ||
399 | } else if (me8255_idx == 1) { | ||
400 | subdevice->ctrl_reg = reg_base + ME1400AB_PORT_B_CTRL; | ||
401 | subdevice->port_reg = | ||
402 | reg_base + ME1400AB_PORT_B_0 + dio_idx; | ||
403 | } | ||
404 | |||
405 | break; | ||
406 | |||
407 | case PCI_DEVICE_ID_MEILHAUS_ME140C: | ||
408 | /* Check if 8255 index is out of range */ | ||
409 | if (me8255_idx > 0) { | ||
410 | PERROR("8255 index is out of range.\n"); | ||
411 | me_subdevice_deinit(&subdevice->base); | ||
412 | kfree(subdevice); | ||
413 | return NULL; | ||
414 | } | ||
415 | |||
416 | case PCI_DEVICE_ID_MEILHAUS_ME140D: /* Fall through */ | ||
417 | /* Check if 8255 index is out of range */ | ||
418 | if (me8255_idx > 1) { | ||
419 | PERROR("8255 index is out of range.\n"); | ||
420 | me_subdevice_deinit(&subdevice->base); | ||
421 | kfree(subdevice); | ||
422 | return NULL; | ||
423 | } | ||
424 | |||
425 | /* Get the registers */ | ||
426 | if (me8255_idx == 0) { | ||
427 | subdevice->ctrl_reg = reg_base + ME1400CD_PORT_A_CTRL; | ||
428 | subdevice->port_reg = | ||
429 | reg_base + ME1400CD_PORT_A_0 + dio_idx; | ||
430 | } else if (me8255_idx == 1) { | ||
431 | subdevice->ctrl_reg = reg_base + ME1400CD_PORT_B_CTRL; | ||
432 | subdevice->port_reg = | ||
433 | reg_base + ME1400CD_PORT_B_0 + dio_idx; | ||
434 | } | ||
435 | |||
436 | break; | ||
437 | |||
438 | default: | ||
439 | PERROR("Unknown device type. dev ID: 0x%04x\n", device_id); | ||
440 | |||
441 | me_subdevice_deinit(&subdevice->base); | ||
442 | |||
443 | kfree(subdevice); | ||
444 | |||
445 | return NULL; | ||
446 | } | ||
447 | |||
448 | /* Overload subdevice base class methods. */ | ||
449 | subdevice->base.me_subdevice_io_reset_subdevice = | ||
450 | me8255_io_reset_subdevice; | ||
451 | subdevice->base.me_subdevice_io_single_config = me8255_io_single_config; | ||
452 | subdevice->base.me_subdevice_io_single_read = me8255_io_single_read; | ||
453 | subdevice->base.me_subdevice_io_single_write = me8255_io_single_write; | ||
454 | subdevice->base.me_subdevice_query_number_channels = | ||
455 | me8255_query_number_channels; | ||
456 | subdevice->base.me_subdevice_query_subdevice_type = | ||
457 | me8255_query_subdevice_type; | ||
458 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
459 | me8255_query_subdevice_caps; | ||
460 | |||
461 | return subdevice; | ||
462 | } | ||
diff --git a/drivers/staging/meilhaus/me8255.h b/drivers/staging/meilhaus/me8255.h new file mode 100644 index 000000000000..338230052b3c --- /dev/null +++ b/drivers/staging/meilhaus/me8255.h | |||
@@ -0,0 +1,59 @@ | |||
1 | /** | ||
2 | * @file me8255.h | ||
3 | * | ||
4 | * @brief Meilhaus PIO 8255 implementation. | ||
5 | * @note Copyright (C) 2006 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | #ifndef _ME8255_H_ | ||
10 | #define _ME8255_H_ | ||
11 | |||
12 | #include "mesubdevice.h" | ||
13 | #include "meslock.h" | ||
14 | |||
15 | #ifdef __KERNEL__ | ||
16 | |||
17 | /** | ||
18 | * @brief The 8255 subdevice class. | ||
19 | */ | ||
20 | typedef struct me8255_subdevice { | ||
21 | /* Inheritance */ | ||
22 | me_subdevice_t base; /**< The subdevice base class. */ | ||
23 | |||
24 | /* Attributes */ | ||
25 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
26 | |||
27 | int *ctrl_reg_mirror; /**< Pointer to mirror of the control register. */ | ||
28 | spinlock_t *ctrl_reg_lock; /**< Spin lock to protect #ctrl_reg and #ctrl_reg_mirror from concurrent access. */ | ||
29 | |||
30 | uint32_t device_id; /**< The PCI device id of the device holding the 8255 chip. */ | ||
31 | int me8255_idx; /**< The index of the 8255 chip on the device. */ | ||
32 | int dio_idx; /**< The index of the DIO port on the 8255 chip. */ | ||
33 | |||
34 | unsigned long port_reg; /**< Register to read or write a value from or to the port respectively. */ | ||
35 | unsigned long ctrl_reg; /**< Register to configure the 8255 modes. */ | ||
36 | } me8255_subdevice_t; | ||
37 | |||
38 | /** | ||
39 | * @brief The constructor to generate a 8255 instance. | ||
40 | * | ||
41 | * @param device_id The kind of Meilhaus device holding the 8255. | ||
42 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
43 | * @param me8255_idx The index of the 8255 chip on the Meilhaus device. | ||
44 | * @param dio_idx The index of the counter inside a 8255 chip. | ||
45 | * @param ctr_reg_mirror Pointer to mirror of control register. | ||
46 | * @param ctrl_reg_lock Pointer to spin lock protecting the 8255 control register and #ctrl_reg_mirror from concurrent access. | ||
47 | * | ||
48 | * @return Pointer to new instance on success.\n | ||
49 | * NULL on error. | ||
50 | */ | ||
51 | me8255_subdevice_t *me8255_constructor(uint32_t device_id, | ||
52 | uint32_t reg_base, | ||
53 | unsigned int me8255_idx, | ||
54 | unsigned int dio_idx, | ||
55 | int *ctrl_reg_mirror, | ||
56 | spinlock_t * ctrl_reg_lock); | ||
57 | |||
58 | #endif | ||
59 | #endif | ||
diff --git a/drivers/staging/meilhaus/me8255_reg.h b/drivers/staging/meilhaus/me8255_reg.h new file mode 100644 index 000000000000..d1dea1a447f6 --- /dev/null +++ b/drivers/staging/meilhaus/me8255_reg.h | |||
@@ -0,0 +1,50 @@ | |||
1 | /** | ||
2 | * @file me8255_reg.h | ||
3 | * | ||
4 | * @brief 8255 counter register definitions. | ||
5 | * @note Copyright (C) 2006 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | #ifndef _ME8255_REG_H_ | ||
10 | #define _ME8255_REG_H_ | ||
11 | |||
12 | #ifdef __KERNEL__ | ||
13 | |||
14 | #define ME8255_NUMBER_CHANNELS 8 /**< The number of channels per 8255 port. */ | ||
15 | |||
16 | #define ME1400AB_PORT_A_0 0x0000 /**< Port 0 offset. */ | ||
17 | #define ME1400AB_PORT_A_1 0x0001 /**< Port 1 offset. */ | ||
18 | #define ME1400AB_PORT_A_2 0x0002 /**< Port 2 offset. */ | ||
19 | #define ME1400AB_PORT_A_CTRL 0x0003 /**< Control register for 8255 A. */ | ||
20 | |||
21 | #define ME1400AB_PORT_B_0 0x0008 /**< Port 0 offset. */ | ||
22 | #define ME1400AB_PORT_B_1 0x0009 /**< Port 1 offset. */ | ||
23 | #define ME1400AB_PORT_B_2 0x000A /**< Port 2 offset. */ | ||
24 | #define ME1400AB_PORT_B_CTRL 0x000B /**< Control register for 8255 B. */ | ||
25 | |||
26 | #define ME1400CD_PORT_A_0 0x0000 /**< Port 0 offset. */ | ||
27 | #define ME1400CD_PORT_A_1 0x0001 /**< Port 1 offset. */ | ||
28 | #define ME1400CD_PORT_A_2 0x0002 /**< Port 2 offset. */ | ||
29 | #define ME1400CD_PORT_A_CTRL 0x0003 /**< Control register for 8255 A. */ | ||
30 | |||
31 | #define ME1400CD_PORT_B_0 0x0040 /**< Port 0 offset. */ | ||
32 | #define ME1400CD_PORT_B_1 0x0041 /**< Port 1 offset. */ | ||
33 | #define ME1400CD_PORT_B_2 0x0042 /**< Port 2 offset. */ | ||
34 | #define ME1400CD_PORT_B_CTRL 0x0043 /**< Control register for 8255 B. */ | ||
35 | |||
36 | #define ME8255_MODE_OOO 0x80 /**< Port 2 = Output, Port 1 = Output, Port 0 = Output */ | ||
37 | #define ME8255_MODE_IOO 0x89 /**< Port 2 = Input, Port 1 = Output, Port 0 = Output */ | ||
38 | #define ME8255_MODE_OIO 0x82 /**< Port 2 = Output, Port 1 = Input, Port 0 = Output */ | ||
39 | #define ME8255_MODE_IIO 0x8B /**< Port 2 = Input, Port 1 = Input, Port 0 = Output */ | ||
40 | #define ME8255_MODE_OOI 0x90 /**< Port 2 = Output, Port 1 = Output, Port 0 = Input */ | ||
41 | #define ME8255_MODE_IOI 0x99 /**< Port 2 = Input, Port 1 = Output, Port 0 = Input */ | ||
42 | #define ME8255_MODE_OII 0x92 /**< Port 2 = Output, Port 1 = Input, Port 0 = Input */ | ||
43 | #define ME8255_MODE_III 0x9B /**< Port 2 = Input, Port 1 = Input, Port 0 = Input */ | ||
44 | |||
45 | #define ME8255_PORT_0_OUTPUT 0x1 /**< If set in mirror then port 0 is in output mode. */ | ||
46 | #define ME8255_PORT_1_OUTPUT 0x2 /**< If set in mirror then port 1 is in output mode. */ | ||
47 | #define ME8255_PORT_2_OUTPUT 0x4 /**< If set in mirror then port 2 is in output mode. */ | ||
48 | |||
49 | #endif | ||
50 | #endif | ||
diff --git a/drivers/staging/meilhaus/mecirc_buf.h b/drivers/staging/meilhaus/mecirc_buf.h new file mode 100644 index 000000000000..e9b591eaa349 --- /dev/null +++ b/drivers/staging/meilhaus/mecirc_buf.h | |||
@@ -0,0 +1,131 @@ | |||
1 | /** | ||
2 | * @file mecirc_buf.h | ||
3 | * | ||
4 | * @brief Meilhaus circular buffer 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 _MECIRC_BUF_H_ | ||
29 | #define _MECIRC_BUF_H_ | ||
30 | |||
31 | # ifdef __KERNEL__ | ||
32 | |||
33 | # ifdef BOSCH | ||
34 | |||
35 | typedef struct me_circ_buf { | ||
36 | unsigned int mask; | ||
37 | // unsigned int count; | ||
38 | uint32_t *buf; | ||
39 | int volatile head; | ||
40 | int volatile tail; | ||
41 | } me_circ_buf_t; | ||
42 | |||
43 | static int inline me_circ_buf_values(me_circ_buf_t * buf) | ||
44 | { | ||
45 | // return ((buf->head - buf->tail) & (buf->count - 1)); | ||
46 | return ((buf->head - buf->tail) & (buf->mask)); | ||
47 | } | ||
48 | |||
49 | static int inline me_circ_buf_space(me_circ_buf_t * buf) | ||
50 | { | ||
51 | // return ((buf->tail - (buf->head + 1)) & (buf->count - 1)); | ||
52 | return ((buf->tail - (buf->head + 1)) & (buf->mask)); | ||
53 | } | ||
54 | |||
55 | static int inline me_circ_buf_values_to_end(me_circ_buf_t * buf) | ||
56 | { | ||
57 | int end; | ||
58 | int n; | ||
59 | // end = buf->count - buf->tail; | ||
60 | // n = (buf->head + end) & (buf->count - 1); | ||
61 | end = buf->mask + 1 - buf->tail; | ||
62 | n = (buf->head + end) & (buf->mask); | ||
63 | return (n < end) ? n : end; | ||
64 | } | ||
65 | |||
66 | static int inline me_circ_buf_space_to_end(me_circ_buf_t * buf) | ||
67 | { | ||
68 | int end; | ||
69 | int n; | ||
70 | |||
71 | // end = buf->count - 1 - buf->head; | ||
72 | // n = (end + buf->tail) & (buf->count - 1); | ||
73 | end = buf->mask - buf->head; | ||
74 | n = (end + buf->tail) & (buf->mask); | ||
75 | return (n <= end) ? n : (end + 1); | ||
76 | } | ||
77 | |||
78 | #define _CBUFF_32b_t | ||
79 | |||
80 | # else //~BOSCH | ||
81 | /// @note buf->mask = buf->count-1 = ME4600_AI_CIRC_BUF_COUNT-1 | ||
82 | |||
83 | # ifdef _CBUFF_32b_t | ||
84 | //32 bit | ||
85 | typedef struct me_circ_buf_32b { | ||
86 | int volatile head; | ||
87 | int volatile tail; | ||
88 | unsigned int mask; //buffor size-1 must be 2^n-1 to work | ||
89 | uint32_t *buf; | ||
90 | } me_circ_buf_t; | ||
91 | # else | ||
92 | //16 bit | ||
93 | typedef struct me_circ_buf_16b { | ||
94 | int volatile head; | ||
95 | int volatile tail; | ||
96 | unsigned int mask; //buffor size-1 must be 2^n-1 to work | ||
97 | uint16_t *buf; | ||
98 | } me_circ_buf_t; | ||
99 | # endif //_CBUFF_32b_t | ||
100 | |||
101 | /** How many values is in buffer */ | ||
102 | static int inline me_circ_buf_values(me_circ_buf_t * buf) | ||
103 | { | ||
104 | return ((buf->head - buf->tail) & (buf->mask)); | ||
105 | } | ||
106 | |||
107 | /** How many space left */ | ||
108 | static int inline me_circ_buf_space(me_circ_buf_t * buf) | ||
109 | { | ||
110 | return ((buf->tail - (buf->head + 1)) & (buf->mask)); | ||
111 | } | ||
112 | |||
113 | /** How many values can be read from buffor in one chunck. */ | ||
114 | static int inline me_circ_buf_values_to_end(me_circ_buf_t * buf) | ||
115 | { | ||
116 | return (buf->tail <= | ||
117 | buf->head) ? (buf->head - buf->tail) : (buf->mask - buf->tail + | ||
118 | 1); | ||
119 | } | ||
120 | |||
121 | /** How many values can be write to buffer in one chunck. */ | ||
122 | static int inline me_circ_buf_space_to_end(me_circ_buf_t * buf) | ||
123 | { | ||
124 | return (buf->tail <= | ||
125 | buf->head) ? (buf->mask - buf->head + 1) : (buf->tail - | ||
126 | buf->head - 1); | ||
127 | } | ||
128 | |||
129 | # endif //BOSCH | ||
130 | # endif //__KERNEL__ | ||
131 | #endif //_MECIRC_BUF_H_ | ||
diff --git a/drivers/staging/meilhaus/mecommon.h b/drivers/staging/meilhaus/mecommon.h new file mode 100644 index 000000000000..ef47c384e018 --- /dev/null +++ b/drivers/staging/meilhaus/mecommon.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
3 | * | ||
4 | * Source File :mecommon.h | ||
5 | * Author :GG (Guenter Gebhardt) <g.gebhardt@meilhaus.de> | ||
6 | * Author :KG (Krzysztof Gantzke) <k.gantzke@meilhaus.de> | ||
7 | */ | ||
8 | |||
9 | #ifndef _MECOMMON_H_ | ||
10 | #define _MECOMMON_H_ | ||
11 | |||
12 | /*================================================================== | ||
13 | The version of this release | ||
14 | ================================================================*/ | ||
15 | |||
16 | #ifndef ME_VERSION_DRIVER | ||
17 | /* Unknown version */ | ||
18 | # define ME_VERSION_DRIVER 0xFFFFFFFF | ||
19 | #endif | ||
20 | |||
21 | #ifndef LIBMEDRIVER_VERSION | ||
22 | /* Unknown version */ | ||
23 | # define LIBMEDRIVER_VERSION 0xFFFFFFFF | ||
24 | #endif | ||
25 | |||
26 | #endif | ||
diff --git a/drivers/staging/meilhaus/medebug.h b/drivers/staging/meilhaus/medebug.h new file mode 100644 index 000000000000..382d00fe311d --- /dev/null +++ b/drivers/staging/meilhaus/medebug.h | |||
@@ -0,0 +1,125 @@ | |||
1 | /** | ||
2 | * @file medebug.h | ||
3 | * | ||
4 | * @brief Debugging defines. | ||
5 | * @note Copyright (C) 2006 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | * @author Krzysztof Gantzke (k.gantzke@meilhaus.de) | ||
8 | */ | ||
9 | |||
10 | #ifndef _MEDEBUG_H_ | ||
11 | #define _MEDEBUG_H_ | ||
12 | |||
13 | #ifdef __KERNEL__ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | |||
17 | //Messages control. | ||
18 | |||
19 | #ifdef MEDEBUG_TEST_ALL /* Switch to enable all info messages. */ | ||
20 | # ifndef MEDEBUG_TEST | ||
21 | # define MEDEBUG_TEST | ||
22 | # endif | ||
23 | # ifndef MEDEBUG_TEST_INFO | ||
24 | # define MEDEBUG_TEST_INFO | ||
25 | # endif | ||
26 | # ifndef MEDEBUG_DEBUG_REG | ||
27 | # define MEDEBUG_DEBUG_REG /* Switch to enable registry access debuging messages. */ | ||
28 | # endif | ||
29 | # ifndef MEDEBUG_DEBUG_LOCKS | ||
30 | # define MEDEBUG_DEBUG_LOCKS /* Switch to enable locking messages. */ | ||
31 | # endif | ||
32 | #endif | ||
33 | |||
34 | #ifdef MEDEBUG_TEST_INFO /* Switch to enable info and test messages. */ | ||
35 | # ifndef MEDEBUG_INFO | ||
36 | # define MEDEBUG_INFO /* Switch to enable info messages. */ | ||
37 | # endif | ||
38 | # ifndef MEDEBUG_TEST | ||
39 | # define MEDEBUG_TEST | ||
40 | # endif | ||
41 | #endif | ||
42 | |||
43 | #ifdef MEDEBUG_TEST /* Switch to enable debug test messages. */ | ||
44 | # ifndef MEDEBUG_DEBUG | ||
45 | # define MEDEBUG_DEBUG /* Switch to enable debug messages. */ | ||
46 | # endif | ||
47 | # ifndef MEDEBUG_ERROR | ||
48 | # define MEDEBUG_ERROR /* Switch to enable error messages. */ | ||
49 | # endif | ||
50 | #endif | ||
51 | |||
52 | #ifdef MEDEBUG_ERROR /* Switch to enable error messages. */ | ||
53 | # ifndef MEDEBUG_ERROR_CRITICAL /* Also critical error messages. */ | ||
54 | # define MEDEBUG_ERROR_CRITICAL /* Switch to enable high importance error messages. */ | ||
55 | # endif | ||
56 | #endif | ||
57 | |||
58 | #undef PDEBUG /* Only to be sure. */ | ||
59 | #undef PINFO /* Only to be sure. */ | ||
60 | #undef PERROR /* Only to be sure. */ | ||
61 | #undef PERROR_CRITICAL /* Only to be sure. */ | ||
62 | #undef PDEBUG_REG /* Only to be sure. */ | ||
63 | #undef PDEBUG_LOCKS /* Only to be sure. */ | ||
64 | #undef PSECURITY /* Only to be sure. */ | ||
65 | #undef PLOG /* Only to be sure. */ | ||
66 | |||
67 | #ifdef MEDEBUG_DEBUG | ||
68 | # define PDEBUG(fmt, args...) \ | ||
69 | printk(KERN_DEBUG"ME_DRV D: <%s> " fmt, __FUNCTION__, ##args) | ||
70 | #else | ||
71 | # define PDEBUG(fmt, args...) | ||
72 | #endif | ||
73 | |||
74 | #ifdef MEDEBUG_DEBUG_LOCKS | ||
75 | # define PDEBUG_LOCKS(fmt, args...) \ | ||
76 | printk(KERN_DEBUG"ME_DRV L: <%s> " fmt, __FUNCTION__, ##args) | ||
77 | #else | ||
78 | # define PDEBUG_LOCKS(fmt, args...) | ||
79 | #endif | ||
80 | |||
81 | #ifdef MEDEBUG_DEBUG_REG | ||
82 | # define PDEBUG_REG(fmt, args...) \ | ||
83 | printk(KERN_DEBUG"ME_DRV R: <%s:%d> REG:" fmt, __FUNCTION__, __LINE__, ##args) | ||
84 | #else | ||
85 | # define PDEBUG_REG(fmt, args...) | ||
86 | #endif | ||
87 | |||
88 | #ifdef MEDEBUG_INFO | ||
89 | # define PINFO(fmt, args...) \ | ||
90 | printk(KERN_INFO"ME_DRV I: " fmt, ##args) | ||
91 | #else | ||
92 | # define PINFO(fmt, args...) | ||
93 | #endif | ||
94 | |||
95 | #ifdef MEDEBUG_ERROR | ||
96 | # define PERROR(fmt, args...) \ | ||
97 | printk(KERN_ERR"ME_DRV E: <%s:%i> " fmt, __FILE__, __LINE__, ##args) | ||
98 | #else | ||
99 | # define PERROR(fmt, args...) | ||
100 | #endif | ||
101 | |||
102 | #ifdef MEDEBUG_ERROR_CRITICAL | ||
103 | # define PERROR_CRITICAL(fmt, args...) \ | ||
104 | printk(KERN_CRIT"ME_DRV C: <%s:%i> " fmt, __FILE__, __LINE__, ##args) | ||
105 | #else | ||
106 | # define PERROR_CRITICAL(fmt, args...) | ||
107 | #endif | ||
108 | |||
109 | //This debug is only to detect logical errors! | ||
110 | # define PSECURITY(fmt, args...) \ | ||
111 | printk(KERN_CRIT"ME_DRV SECURITY: <%s:%s:%i> " fmt, __FILE__, __FUNCTION__, __LINE__, ##args) | ||
112 | //This debug is to keep track in customers' system | ||
113 | # define PLOG(fmt, args...) \ | ||
114 | printk(KERN_INFO"ME_DRV: " fmt, ##args) | ||
115 | |||
116 | //This debug is to check new parts during development | ||
117 | #ifdef MEDEBUG_DEVELOP | ||
118 | # define PDEVELOP(fmt, args...) \ | ||
119 | printk(KERN_CRIT"ME_DRV: <%s:%s:%i> " fmt, __FILE__, __FUNCTION__, __LINE__, ##args) | ||
120 | #else | ||
121 | # define PDEVELOP(fmt, args...) | ||
122 | #endif | ||
123 | |||
124 | #endif //__KERNEL__ | ||
125 | #endif //_MEDEBUG_H_ | ||
diff --git a/drivers/staging/meilhaus/medefines.h b/drivers/staging/meilhaus/medefines.h new file mode 100644 index 000000000000..6158ef5b80e6 --- /dev/null +++ b/drivers/staging/meilhaus/medefines.h | |||
@@ -0,0 +1,449 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
3 | * | ||
4 | * Source File : medefines.h | ||
5 | * Author : GG (Guenter Gebhardt) <g.gebhardt@meilhaus.de> | ||
6 | * Author : KG (Krzysztof Gantzke) <k.gantzke@meilhaus.de> | ||
7 | */ | ||
8 | |||
9 | #ifndef _MEDEFINES_H_ | ||
10 | #define _MEDEFINES_H_ | ||
11 | |||
12 | /*================================================================== | ||
13 | General | ||
14 | ================================================================*/ | ||
15 | |||
16 | #define ME_VALUE_NOT_USED 0x0 | ||
17 | #define ME_VALUE_INVALID ~0x0 | ||
18 | |||
19 | /*================================================================== | ||
20 | Defines common to access functions | ||
21 | ================================================================*/ | ||
22 | |||
23 | #define ME_LOCK_RELEASE 0x00010001 | ||
24 | #define ME_LOCK_SET 0x00010002 | ||
25 | #define ME_LOCK_CHECK 0x00010003 | ||
26 | |||
27 | /*================================================================== | ||
28 | Defines meOpen function | ||
29 | ================================================================*/ | ||
30 | |||
31 | #define ME_OPEN_NO_FLAGS 0x0 | ||
32 | |||
33 | /*================================================================== | ||
34 | Defines meClose function | ||
35 | ================================================================*/ | ||
36 | |||
37 | #define ME_CLOSE_NO_FLAGS 0x0 | ||
38 | |||
39 | /*================================================================== | ||
40 | Defines meLockDriver function | ||
41 | ================================================================*/ | ||
42 | |||
43 | #define ME_LOCK_DRIVER_NO_FLAGS 0x0 | ||
44 | |||
45 | /*================================================================== | ||
46 | Defines meLockDevice function | ||
47 | ================================================================*/ | ||
48 | |||
49 | #define ME_LOCK_DEVICE_NO_FLAGS 0x0 | ||
50 | |||
51 | /*================================================================== | ||
52 | Defines meLockSubdevice function | ||
53 | ================================================================*/ | ||
54 | |||
55 | #define ME_LOCK_SUBDEVICE_NO_FLAGS 0x0 | ||
56 | |||
57 | |||
58 | /*================================================================== | ||
59 | Defines common to error functions | ||
60 | ================================================================*/ | ||
61 | |||
62 | #define ME_ERROR_MSG_MAX_COUNT 256 | ||
63 | |||
64 | #define ME_SWITCH_DISABLE 0x00020001 | ||
65 | #define ME_SWITCH_ENABLE 0x00020002 | ||
66 | |||
67 | /*================================================================== | ||
68 | Defines common to io functions | ||
69 | ================================================================*/ | ||
70 | |||
71 | #define ME_REF_DIO_FIFO_LOW 0x00030001 | ||
72 | #define ME_REF_DIO_FIFO_HIGH 0x00030002 | ||
73 | |||
74 | #define ME_REF_CTR_PREVIOUS 0x00040001 | ||
75 | #define ME_REF_CTR_INTERNAL_1MHZ 0x00040002 | ||
76 | #define ME_REF_CTR_INTERNAL_10MHZ 0x00040003 | ||
77 | #define ME_REF_CTR_EXTERNAL 0x00040004 | ||
78 | |||
79 | #define ME_REF_AI_GROUND 0x00050001 | ||
80 | #define ME_REF_AI_DIFFERENTIAL 0x00050002 | ||
81 | |||
82 | #define ME_REF_AO_GROUND 0x00060001 | ||
83 | |||
84 | #define ME_TRIG_CHAN_DEFAULT 0x00070001 | ||
85 | #define ME_TRIG_CHAN_SYNCHRONOUS 0x00070002 | ||
86 | |||
87 | #define ME_TRIG_TYPE_NONE 0x00000000 | ||
88 | #define ME_TRIG_TYPE_SW 0x00080001 | ||
89 | #define ME_TRIG_TYPE_THRESHOLD 0x00080002 | ||
90 | #define ME_TRIG_TYPE_WINDOW 0x00080003 | ||
91 | #define ME_TRIG_TYPE_EDGE 0x00080004 | ||
92 | #define ME_TRIG_TYPE_SLOPE 0x00080005 | ||
93 | #define ME_TRIG_TYPE_EXT_DIGITAL 0x00080006 | ||
94 | #define ME_TRIG_TYPE_EXT_ANALOG 0x00080007 | ||
95 | #define ME_TRIG_TYPE_PATTERN 0x00080008 | ||
96 | #define ME_TRIG_TYPE_TIMER 0x00080009 | ||
97 | #define ME_TRIG_TYPE_COUNT 0x0008000A | ||
98 | #define ME_TRIG_TYPE_FOLLOW 0x0008000B | ||
99 | |||
100 | #define ME_TRIG_EDGE_NONE 0x00000000 | ||
101 | #define ME_TRIG_EDGE_ABOVE 0x00090001 | ||
102 | #define ME_TRIG_EDGE_BELOW 0x00090002 | ||
103 | #define ME_TRIG_EDGE_ENTRY 0x00090003 | ||
104 | #define ME_TRIG_EDGE_EXIT 0x00090004 | ||
105 | #define ME_TRIG_EDGE_RISING 0x00090005 | ||
106 | #define ME_TRIG_EDGE_FALLING 0x00090006 | ||
107 | #define ME_TRIG_EDGE_ANY 0x00090007 | ||
108 | |||
109 | #define ME_TIMER_ACQ_START 0x000A0001 | ||
110 | #define ME_TIMER_SCAN_START 0x000A0002 | ||
111 | #define ME_TIMER_CONV_START 0x000A0003 | ||
112 | |||
113 | /*================================================================== | ||
114 | Defines for meIOFrequencyToTicks function | ||
115 | ================================================================*/ | ||
116 | |||
117 | #define ME_IO_FREQUENCY_TO_TICKS_NO_FLAGS 0x0 | ||
118 | |||
119 | /*================================================================== | ||
120 | Defines for meIOIrqStart function | ||
121 | ================================================================*/ | ||
122 | |||
123 | #define ME_IRQ_SOURCE_DIO_PATTERN 0x000B0001 | ||
124 | #define ME_IRQ_SOURCE_DIO_MASK 0x000B0002 | ||
125 | #define ME_IRQ_SOURCE_DIO_LINE 0x000B0003 | ||
126 | #define ME_IRQ_SOURCE_DIO_OVER_TEMP 0x000B0004 | ||
127 | |||
128 | #define ME_IRQ_EDGE_NOT_USED 0x00000000 | ||
129 | #define ME_IRQ_EDGE_RISING 0x000C0001 | ||
130 | #define ME_IRQ_EDGE_FALLING 0x000C0002 | ||
131 | #define ME_IRQ_EDGE_ANY 0x000C0003 | ||
132 | |||
133 | /*================================================================== | ||
134 | Defines for meIOIrqStart function | ||
135 | ================================================================*/ | ||
136 | |||
137 | #define ME_IO_IRQ_START_NO_FLAGS 0x000000 | ||
138 | #define ME_IO_IRQ_START_DIO_BIT 0x000001 | ||
139 | #define ME_IO_IRQ_START_DIO_BYTE 0x000002 | ||
140 | #define ME_IO_IRQ_START_DIO_WORD 0x000004 | ||
141 | #define ME_IO_IRQ_START_DIO_DWORD 0x000008 | ||
142 | #define ME_IO_IRQ_START_PATTERN_FILTERING 0x000010 | ||
143 | #define ME_IO_IRQ_START_EXTENDED_STATUS 0x000020 | ||
144 | |||
145 | /*================================================================== | ||
146 | Defines for meIOIrqWait function | ||
147 | ================================================================*/ | ||
148 | |||
149 | #define ME_IO_IRQ_WAIT_NO_FLAGS 0x000000 | ||
150 | #define ME_IO_IRQ_WAIT_NORMAL_STATUS 0x000001 | ||
151 | #define ME_IO_IRQ_WAIT_EXTENDED_STATUS 0x000002 | ||
152 | |||
153 | /*================================================================== | ||
154 | Defines for meIOIrqStop function | ||
155 | ================================================================*/ | ||
156 | |||
157 | #define ME_IO_IRQ_STOP_NO_FLAGS 0x000000 | ||
158 | |||
159 | /*================================================================== | ||
160 | Defines for meIOIrqSetCallback function | ||
161 | ================================================================*/ | ||
162 | |||
163 | #define ME_IO_IRQ_SET_CALLBACK_NO_FLAGS 0x0 | ||
164 | |||
165 | /*================================================================== | ||
166 | Defines for meIOResetDevice function | ||
167 | ================================================================*/ | ||
168 | |||
169 | #define ME_IO_RESET_DEVICE_NO_FLAGS 0x0 | ||
170 | |||
171 | /*================================================================== | ||
172 | Defines for meIOResetSubdevice function | ||
173 | ================================================================*/ | ||
174 | |||
175 | #define ME_IO_RESET_SUBDEVICE_NO_FLAGS 0x0 | ||
176 | |||
177 | /*================================================================== | ||
178 | Defines for meIOSingleConfig function | ||
179 | ================================================================*/ | ||
180 | |||
181 | #define ME_SINGLE_CONFIG_DIO_INPUT 0x000D0001 | ||
182 | #define ME_SINGLE_CONFIG_DIO_OUTPUT 0x000D0002 | ||
183 | #define ME_SINGLE_CONFIG_DIO_HIGH_IMPEDANCE 0x000D0003 | ||
184 | #define ME_SINGLE_CONFIG_DIO_SINK 0x000D0004 | ||
185 | #define ME_SINGLE_CONFIG_DIO_SOURCE 0x000D0005 | ||
186 | #define ME_SINGLE_CONFIG_DIO_MUX32M 0x000D0006 | ||
187 | #define ME_SINGLE_CONFIG_DIO_DEMUX32 0x000D0007 | ||
188 | #define ME_SINGLE_CONFIG_DIO_BIT_PATTERN 0x000D0008 | ||
189 | |||
190 | #define ME_SINGLE_CONFIG_CTR_8254_MODE_0 0x000E0001 | ||
191 | #define ME_SINGLE_CONFIG_CTR_8254_MODE_1 0x000E0002 | ||
192 | #define ME_SINGLE_CONFIG_CTR_8254_MODE_2 0x000E0003 | ||
193 | #define ME_SINGLE_CONFIG_CTR_8254_MODE_3 0x000E0004 | ||
194 | #define ME_SINGLE_CONFIG_CTR_8254_MODE_4 0x000E0005 | ||
195 | #define ME_SINGLE_CONFIG_CTR_8254_MODE_5 0x000E0006 | ||
196 | |||
197 | #define ME_IO_SINGLE_CONFIG_NO_FLAGS 0x00 | ||
198 | #define ME_IO_SINGLE_CONFIG_DIO_BIT 0x01 | ||
199 | #define ME_IO_SINGLE_CONFIG_DIO_BYTE 0x02 | ||
200 | #define ME_IO_SINGLE_CONFIG_DIO_WORD 0x04 | ||
201 | #define ME_IO_SINGLE_CONFIG_DIO_DWORD 0x08 | ||
202 | #define ME_IO_SINGLE_CONFIG_MULTISIG_LED_ON 0x10 | ||
203 | #define ME_IO_SINGLE_CONFIG_MULTISIG_LED_OFF 0x20 | ||
204 | #define ME_IO_SINGLE_CONFIG_AI_RMS 0x40 | ||
205 | #define ME_IO_SINGLE_CONFIG_CONTINUE 0x80 | ||
206 | |||
207 | /*================================================================== | ||
208 | Defines for meIOSingle function | ||
209 | ================================================================*/ | ||
210 | |||
211 | #define ME_IO_SINGLE_NO_FLAGS 0x0 | ||
212 | #define ME_IO_SINGLE_NONBLOCKING 0x20 | ||
213 | |||
214 | #define ME_DIR_INPUT 0x000F0001 | ||
215 | #define ME_DIR_OUTPUT 0x000F0002 | ||
216 | |||
217 | #define ME_IO_SINGLE_TYPE_NO_FLAGS 0x00 | ||
218 | #define ME_IO_SINGLE_TYPE_DIO_BIT 0x01 | ||
219 | #define ME_IO_SINGLE_TYPE_DIO_BYTE 0x02 | ||
220 | #define ME_IO_SINGLE_TYPE_DIO_WORD 0x04 | ||
221 | #define ME_IO_SINGLE_TYPE_DIO_DWORD 0x08 | ||
222 | #define ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS 0x10 | ||
223 | #define ME_IO_SINGLE_TYPE_WRITE_NONBLOCKING 0x20 | ||
224 | |||
225 | /*================================================================== | ||
226 | Defines for meIOStreamConfig function | ||
227 | ================================================================*/ | ||
228 | |||
229 | #define ME_IO_STREAM_CONFIG_NO_FLAGS 0x0 | ||
230 | #define ME_IO_STREAM_CONFIG_BIT_PATTERN 0x1 | ||
231 | #define ME_IO_STREAM_CONFIG_WRAPAROUND 0x2 | ||
232 | #define ME_IO_STREAM_CONFIG_SAMPLE_AND_HOLD 0x4 | ||
233 | #define ME_IO_STREAM_CONFIG_HARDWARE_ONLY 0x8 | ||
234 | |||
235 | #define ME_IO_STREAM_CONFIG_TYPE_NO_FLAGS 0x0 | ||
236 | |||
237 | #define ME_IO_STREAM_TRIGGER_TYPE_NO_FLAGS 0x0 | ||
238 | |||
239 | /*================================================================== | ||
240 | Defines for meIOStreamRead function | ||
241 | ================================================================*/ | ||
242 | |||
243 | #define ME_READ_MODE_BLOCKING 0x00100001 | ||
244 | #define ME_READ_MODE_NONBLOCKING 0x00100002 | ||
245 | |||
246 | #define ME_IO_STREAM_READ_NO_FLAGS 0x0 | ||
247 | #define ME_IO_STREAM_READ_FRAMES 0x1 | ||
248 | |||
249 | /*================================================================== | ||
250 | Defines for meIOStreamWrite function | ||
251 | ================================================================*/ | ||
252 | |||
253 | #define ME_WRITE_MODE_BLOCKING 0x00110001 | ||
254 | #define ME_WRITE_MODE_NONBLOCKING 0x00110002 | ||
255 | #define ME_WRITE_MODE_PRELOAD 0x00110003 | ||
256 | |||
257 | #define ME_IO_STREAM_WRITE_NO_FLAGS 0x00000000 | ||
258 | |||
259 | /*================================================================== | ||
260 | Defines for meIOStreamStart function | ||
261 | ================================================================*/ | ||
262 | |||
263 | #define ME_IO_STREAM_START_NO_FLAGS 0x00000000 | ||
264 | |||
265 | #define ME_START_MODE_BLOCKING 0x00120001 | ||
266 | #define ME_START_MODE_NONBLOCKING 0x00120002 | ||
267 | |||
268 | #define ME_IO_STREAM_START_TYPE_NO_FLAGS 0x0 | ||
269 | #define ME_IO_STREAM_START_TYPE_TRIG_SYNCHRONOUS 0x1 | ||
270 | |||
271 | /*================================================================== | ||
272 | Defines for meIOStreamStop function | ||
273 | ================================================================*/ | ||
274 | |||
275 | #define ME_IO_STREAM_STOP_NO_FLAGS 0x00000000 | ||
276 | #define ME_IO_STREAM_STOP_PRESERVE_BUFFERS 0x00000001 | ||
277 | |||
278 | #define ME_STOP_MODE_IMMEDIATE 0x00130001 | ||
279 | #define ME_STOP_MODE_LAST_VALUE 0x00130002 | ||
280 | |||
281 | #define ME_IO_STREAM_STOP_TYPE_NO_FLAGS 0x00000000 | ||
282 | |||
283 | /*================================================================== | ||
284 | Defines for meIOStreamStatus function | ||
285 | ================================================================*/ | ||
286 | |||
287 | #define ME_WAIT_NONE 0x00140001 | ||
288 | #define ME_WAIT_IDLE 0x00140002 | ||
289 | |||
290 | #define ME_STATUS_INVALID 0x00000000 | ||
291 | #define ME_STATUS_IDLE 0x00150001 | ||
292 | #define ME_STATUS_BUSY 0x00150002 | ||
293 | #define ME_STATUS_ERROR 0x00150003 | ||
294 | |||
295 | #define ME_IO_STREAM_STATUS_NO_FLAGS 0x00000000 | ||
296 | |||
297 | /*================================================================== | ||
298 | Defines for meIOStreamSetCallbacks function | ||
299 | ================================================================*/ | ||
300 | |||
301 | #define ME_IO_STREAM_SET_CALLBACKS_NO_FLAGS 0x00000000 | ||
302 | |||
303 | /*================================================================== | ||
304 | Defines for meIOStreamNewValues function | ||
305 | ================================================================*/ | ||
306 | |||
307 | #define ME_IO_STREAM_NEW_VALUES_NO_FLAGS 0x00000000 | ||
308 | |||
309 | /*================================================================== | ||
310 | Defines for meIOTimeToTicks function | ||
311 | ================================================================*/ | ||
312 | |||
313 | #define ME_IO_STREAM_TIME_TO_TICKS_NO_FLAGS 0x00000000 | ||
314 | |||
315 | /*================================================================== | ||
316 | Defines for module types | ||
317 | ================================================================*/ | ||
318 | |||
319 | #define ME_MODULE_TYPE_MULTISIG_NONE 0x00000000 | ||
320 | #define ME_MODULE_TYPE_MULTISIG_DIFF16_10V 0x00160001 | ||
321 | #define ME_MODULE_TYPE_MULTISIG_DIFF16_20V 0x00160002 | ||
322 | #define ME_MODULE_TYPE_MULTISIG_DIFF16_50V 0x00160003 | ||
323 | #define ME_MODULE_TYPE_MULTISIG_CURRENT16_0_20MA 0x00160004 | ||
324 | #define ME_MODULE_TYPE_MULTISIG_RTD8_PT100 0x00160005 | ||
325 | #define ME_MODULE_TYPE_MULTISIG_RTD8_PT500 0x00160006 | ||
326 | #define ME_MODULE_TYPE_MULTISIG_RTD8_PT1000 0x00160007 | ||
327 | #define ME_MODULE_TYPE_MULTISIG_TE8_TYPE_B 0x00160008 | ||
328 | #define ME_MODULE_TYPE_MULTISIG_TE8_TYPE_E 0x00160009 | ||
329 | #define ME_MODULE_TYPE_MULTISIG_TE8_TYPE_J 0x0016000A | ||
330 | #define ME_MODULE_TYPE_MULTISIG_TE8_TYPE_K 0x0016000B | ||
331 | #define ME_MODULE_TYPE_MULTISIG_TE8_TYPE_N 0x0016000C | ||
332 | #define ME_MODULE_TYPE_MULTISIG_TE8_TYPE_R 0x0016000D | ||
333 | #define ME_MODULE_TYPE_MULTISIG_TE8_TYPE_S 0x0016000E | ||
334 | #define ME_MODULE_TYPE_MULTISIG_TE8_TYPE_T 0x0016000F | ||
335 | #define ME_MODULE_TYPE_MULTISIG_TE8_TEMP_SENSOR 0x00160010 | ||
336 | |||
337 | /*================================================================== | ||
338 | Defines for meQuerySubdeviceCaps function | ||
339 | ================================================================*/ | ||
340 | |||
341 | #define ME_CAPS_NONE 0x00000000 | ||
342 | |||
343 | #define ME_CAPS_DIO_DIR_BIT 0x00000001 | ||
344 | #define ME_CAPS_DIO_DIR_BYTE 0x00000002 | ||
345 | #define ME_CAPS_DIO_DIR_WORD 0x00000004 | ||
346 | #define ME_CAPS_DIO_DIR_DWORD 0x00000008 | ||
347 | #define ME_CAPS_DIO_SINK_SOURCE 0x00000010 | ||
348 | #define ME_CAPS_DIO_BIT_PATTERN_IRQ 0x00000020 | ||
349 | #define ME_CAPS_DIO_BIT_MASK_IRQ_EDGE_RISING 0x00000040 | ||
350 | #define ME_CAPS_DIO_BIT_MASK_IRQ_EDGE_FALLING 0x00000080 | ||
351 | #define ME_CAPS_DIO_BIT_MASK_IRQ_EDGE_ANY 0x00000100 | ||
352 | #define ME_CAPS_DIO_OVER_TEMP_IRQ 0x00000200 | ||
353 | |||
354 | #define ME_CAPS_CTR_CLK_PREVIOUS 0x00000001 | ||
355 | #define ME_CAPS_CTR_CLK_INTERNAL_1MHZ 0x00000002 | ||
356 | #define ME_CAPS_CTR_CLK_INTERNAL_10MHZ 0x00000004 | ||
357 | #define ME_CAPS_CTR_CLK_EXTERNAL 0x00000008 | ||
358 | |||
359 | #define ME_CAPS_AI_TRIG_SYNCHRONOUS 0x00000001 | ||
360 | /// @note Backward compatibility for me1600 in old style. | ||
361 | #define ME_CAPS_AI_TRIG_SIMULTANEOUS ME_CAPS_AI_TRIG_SYNCHRONOUS | ||
362 | #define ME_CAPS_AI_FIFO 0x00000002 | ||
363 | #define ME_CAPS_AI_FIFO_THRESHOLD 0x00000004 | ||
364 | |||
365 | #define ME_CAPS_AO_TRIG_SYNCHRONOUS 0x00000001 | ||
366 | /// @note Backward compatibility for me1600 in old style. | ||
367 | #define ME_CAPS_AO_TRIG_SIMULTANEOUS ME_CAPS_AO_TRIG_SYNCHRONOUS | ||
368 | #define ME_CAPS_AO_FIFO 0x00000002 | ||
369 | #define ME_CAPS_AO_FIFO_THRESHOLD 0x00000004 | ||
370 | |||
371 | #define ME_CAPS_EXT_IRQ_EDGE_RISING 0x00000001 | ||
372 | #define ME_CAPS_EXT_IRQ_EDGE_FALLING 0x00000002 | ||
373 | #define ME_CAPS_EXT_IRQ_EDGE_ANY 0x00000004 | ||
374 | |||
375 | /*================================================================== | ||
376 | Defines for meQuerySubdeviceCapsArgs function | ||
377 | ================================================================*/ | ||
378 | |||
379 | #define ME_CAP_AI_FIFO_SIZE 0x001D0000 | ||
380 | #define ME_CAP_AI_BUFFER_SIZE 0x001D0001 | ||
381 | |||
382 | #define ME_CAP_AO_FIFO_SIZE 0x001F0000 | ||
383 | #define ME_CAP_AO_BUFFER_SIZE 0x001F0001 | ||
384 | |||
385 | #define ME_CAP_CTR_WIDTH 0x00200000 | ||
386 | |||
387 | /*================================================================== | ||
388 | Defines common to query functions | ||
389 | ================================================================*/ | ||
390 | |||
391 | #define ME_UNIT_INVALID 0x00000000 | ||
392 | #define ME_UNIT_VOLT 0x00170001 | ||
393 | #define ME_UNIT_AMPERE 0x00170002 | ||
394 | #define ME_UNIT_ANY 0x00170003 | ||
395 | |||
396 | #define ME_TYPE_INVALID 0x00000000 | ||
397 | #define ME_TYPE_AO 0x00180001 | ||
398 | #define ME_TYPE_AI 0x00180002 | ||
399 | #define ME_TYPE_DIO 0x00180003 | ||
400 | #define ME_TYPE_DO 0x00180004 | ||
401 | #define ME_TYPE_DI 0x00180005 | ||
402 | #define ME_TYPE_CTR 0x00180006 | ||
403 | #define ME_TYPE_EXT_IRQ 0x00180007 | ||
404 | |||
405 | #define ME_SUBTYPE_INVALID 0x00000000 | ||
406 | #define ME_SUBTYPE_SINGLE 0x00190001 | ||
407 | #define ME_SUBTYPE_STREAMING 0x00190002 | ||
408 | #define ME_SUBTYPE_CTR_8254 0x00190003 | ||
409 | #define ME_SUBTYPE_ANY 0x00190004 | ||
410 | |||
411 | #define ME_DEVICE_DRIVER_NAME_MAX_COUNT 64 | ||
412 | #define ME_DEVICE_NAME_MAX_COUNT 64 | ||
413 | |||
414 | #define ME_DEVICE_DESCRIPTION_MAX_COUNT 256 | ||
415 | |||
416 | #define ME_BUS_TYPE_INVALID 0x00000000 | ||
417 | #define ME_BUS_TYPE_PCI 0x001A0001 | ||
418 | #define ME_BUS_TYPE_USB 0x001A0002 | ||
419 | |||
420 | #define ME_PLUGGED_INVALID 0x00000000 | ||
421 | #define ME_PLUGGED_IN 0x001B0001 | ||
422 | #define ME_PLUGGED_OUT 0x001B0002 | ||
423 | |||
424 | #define ME_EXTENSION_TYPE_INVALID 0x00000000 | ||
425 | #define ME_EXTENSION_TYPE_NONE 0x001C0001 | ||
426 | #define ME_EXTENSION_TYPE_MUX32M 0x001C0002 | ||
427 | #define ME_EXTENSION_TYPE_DEMUX32 0x001C0003 | ||
428 | #define ME_EXTENSION_TYPE_MUX32S 0x001C0004 | ||
429 | |||
430 | #define ME_ACCESS_TYPE_INVALID 0x00000000 | ||
431 | #define ME_ACCESS_TYPE_LOCAL 0x001D0001 | ||
432 | #define ME_ACCESS_TYPE_REMOTE 0x001D0002 | ||
433 | |||
434 | /// @note Add by KG | ||
435 | |||
436 | /*================================================================== | ||
437 | Defines for meUtilityPWM | ||
438 | ================================================================*/ | ||
439 | #define ME_PWM_START_CONNECT_INTERNAL 0x00200001 | ||
440 | |||
441 | /* Flags for SingleConfig channels configure */ | ||
442 | #define ME_SINGLE_CHANNEL_NOT_CONFIGURED 0x00 | ||
443 | #define ME_SINGLE_CHANNEL_CONFIGURED 0x01 | ||
444 | |||
445 | /* Define if configuration should be downloaded to driver */ | ||
446 | #define ME_CONFIG_LOAD_NO_FLAGS 0x0 | ||
447 | #define ME_CONFIG_LOAD_TO_DRIVER 0x1 | ||
448 | |||
449 | #endif | ||
diff --git a/drivers/staging/meilhaus/medevice.c b/drivers/staging/meilhaus/medevice.c new file mode 100644 index 000000000000..8f62e16c7a37 --- /dev/null +++ b/drivers/staging/meilhaus/medevice.c | |||
@@ -0,0 +1,1740 @@ | |||
1 | /** | ||
2 | * @file medevice.c | ||
3 | * | ||
4 | * @brief Meilhaus device base class. | ||
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 | #include "mecommon.h" | ||
29 | #include "meinternal.h" | ||
30 | #include "medefines.h" | ||
31 | #include "meerror.h" | ||
32 | |||
33 | #include "medebug.h" | ||
34 | #include "medevice.h" | ||
35 | |||
36 | #ifndef __KERNEL__ | ||
37 | # define __KERNEL__ | ||
38 | #endif | ||
39 | |||
40 | static int me_device_io_irq_start(struct me_device *device, | ||
41 | struct file *filep, | ||
42 | int subdevice, | ||
43 | int channel, | ||
44 | int irq_source, | ||
45 | int irq_edge, int irq_arg, int flags) | ||
46 | { | ||
47 | int err = ME_ERRNO_SUCCESS; | ||
48 | me_subdevice_t *s; | ||
49 | |||
50 | PDEBUG("executed.\n"); | ||
51 | |||
52 | // Check subdevice index. | ||
53 | if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { | ||
54 | PERROR("Invalid subdevice.\n"); | ||
55 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
56 | } | ||
57 | // Enter device. | ||
58 | err = me_dlock_enter(&device->dlock, filep); | ||
59 | |||
60 | if (err) { | ||
61 | PERROR("Cannot enter device.\n"); | ||
62 | return err; | ||
63 | } | ||
64 | // Get subdevice instance. | ||
65 | s = me_slist_get_subdevice(&device->slist, subdevice); | ||
66 | |||
67 | if (s) { | ||
68 | // Call subdevice method. | ||
69 | err = s->me_subdevice_io_irq_start(s, | ||
70 | filep, | ||
71 | channel, | ||
72 | irq_source, | ||
73 | irq_edge, irq_arg, flags); | ||
74 | } else { | ||
75 | // Something really bad happened. | ||
76 | PERROR("Cannot get subdevice instance.\n"); | ||
77 | err = ME_ERRNO_INTERNAL; | ||
78 | } | ||
79 | |||
80 | // Exit device. | ||
81 | me_dlock_exit(&device->dlock, filep); | ||
82 | |||
83 | return err; | ||
84 | } | ||
85 | |||
86 | static int me_device_io_irq_wait(struct me_device *device, | ||
87 | struct file *filep, | ||
88 | int subdevice, | ||
89 | int channel, | ||
90 | int *irq_count, | ||
91 | int *value, int time_out, int flags) | ||
92 | { | ||
93 | int err = ME_ERRNO_SUCCESS; | ||
94 | me_subdevice_t *s; | ||
95 | |||
96 | PDEBUG("executed.\n"); | ||
97 | |||
98 | // Check subdevice index. | ||
99 | if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { | ||
100 | PERROR("Invalid subdevice.\n"); | ||
101 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
102 | } | ||
103 | // Enter device. | ||
104 | err = me_dlock_enter(&device->dlock, filep); | ||
105 | |||
106 | if (err) { | ||
107 | PERROR("Cannot enter device.\n"); | ||
108 | return err; | ||
109 | } | ||
110 | // Get subdevice instance. | ||
111 | s = me_slist_get_subdevice(&device->slist, subdevice); | ||
112 | |||
113 | if (s) { | ||
114 | // Call subdevice method. | ||
115 | err = s->me_subdevice_io_irq_wait(s, | ||
116 | filep, | ||
117 | channel, | ||
118 | irq_count, | ||
119 | value, time_out, flags); | ||
120 | } else { | ||
121 | // Something really bad happened. | ||
122 | PERROR("Cannot get subdevice instance.\n"); | ||
123 | err = ME_ERRNO_INTERNAL; | ||
124 | } | ||
125 | |||
126 | // Exit device. | ||
127 | me_dlock_exit(&device->dlock, filep); | ||
128 | |||
129 | return err; | ||
130 | } | ||
131 | |||
132 | static int me_device_io_irq_stop(struct me_device *device, | ||
133 | struct file *filep, | ||
134 | int subdevice, int channel, int flags) | ||
135 | { | ||
136 | int err = ME_ERRNO_SUCCESS; | ||
137 | me_subdevice_t *s; | ||
138 | |||
139 | PDEBUG("executed.\n"); | ||
140 | |||
141 | // Check subdevice index. | ||
142 | if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { | ||
143 | PERROR("Invalid subdevice.\n"); | ||
144 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
145 | } | ||
146 | // Enter device. | ||
147 | err = me_dlock_enter(&device->dlock, filep); | ||
148 | |||
149 | if (err) { | ||
150 | PERROR("Cannot enter device.\n"); | ||
151 | return err; | ||
152 | } | ||
153 | // Get subdevice instance. | ||
154 | s = me_slist_get_subdevice(&device->slist, subdevice); | ||
155 | |||
156 | if (s) { | ||
157 | // Call subdevice method. | ||
158 | err = s->me_subdevice_io_irq_stop(s, filep, channel, flags); | ||
159 | } else { | ||
160 | // Something really bad happened. | ||
161 | PERROR("Cannot get subdevice instance.\n"); | ||
162 | err = ME_ERRNO_INTERNAL; | ||
163 | } | ||
164 | |||
165 | // Exit device. | ||
166 | me_dlock_exit(&device->dlock, filep); | ||
167 | |||
168 | return err; | ||
169 | } | ||
170 | |||
171 | static int me_device_io_reset_device(struct me_device *device, | ||
172 | struct file *filep, int flags) | ||
173 | { | ||
174 | int err = ME_ERRNO_SUCCESS; | ||
175 | me_subdevice_t *s; | ||
176 | int i, n; | ||
177 | |||
178 | PDEBUG("executed.\n"); | ||
179 | |||
180 | /* Get the number of subdevices. */ | ||
181 | n = me_slist_get_number_subdevices(&device->slist); | ||
182 | |||
183 | // Enter device. | ||
184 | err = me_dlock_enter(&device->dlock, filep); | ||
185 | |||
186 | if (err) { | ||
187 | PERROR("Cannot enter device.\n"); | ||
188 | return err; | ||
189 | } | ||
190 | |||
191 | /* Reset every subdevice in list. */ | ||
192 | for (i = 0; i < n; i++) { | ||
193 | s = me_slist_get_subdevice(&device->slist, i); | ||
194 | err = s->me_subdevice_io_reset_subdevice(s, filep, flags); | ||
195 | |||
196 | if (err) { | ||
197 | PERROR("Cannot reset subdevice.\n"); | ||
198 | break; | ||
199 | } | ||
200 | } | ||
201 | |||
202 | // Exit device. | ||
203 | me_dlock_exit(&device->dlock, filep); | ||
204 | |||
205 | return err; | ||
206 | } | ||
207 | |||
208 | static int me_device_io_reset_subdevice(struct me_device *device, | ||
209 | struct file *filep, | ||
210 | int subdevice, int flags) | ||
211 | { | ||
212 | int err = ME_ERRNO_SUCCESS; | ||
213 | me_subdevice_t *s; | ||
214 | |||
215 | PDEBUG("executed.\n"); | ||
216 | |||
217 | // Check subdevice index. | ||
218 | |||
219 | if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { | ||
220 | PERROR("Invalid subdevice.\n"); | ||
221 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
222 | } | ||
223 | // Enter device. | ||
224 | err = me_dlock_enter(&device->dlock, filep); | ||
225 | |||
226 | if (err) { | ||
227 | PERROR("Cannot enter device.\n"); | ||
228 | return err; | ||
229 | } | ||
230 | // Get subdevice instance. | ||
231 | s = me_slist_get_subdevice(&device->slist, subdevice); | ||
232 | |||
233 | if (s) { | ||
234 | // Call subdevice method. | ||
235 | err = s->me_subdevice_io_reset_subdevice(s, filep, flags); | ||
236 | } else { | ||
237 | // Something really bad happened. | ||
238 | PERROR("Cannot get subdevice instance.\n"); | ||
239 | err = ME_ERRNO_INTERNAL; | ||
240 | } | ||
241 | |||
242 | // Exit device. | ||
243 | me_dlock_exit(&device->dlock, filep); | ||
244 | |||
245 | return err; | ||
246 | } | ||
247 | |||
248 | static int me_device_io_single_config(struct me_device *device, | ||
249 | struct file *filep, | ||
250 | int subdevice, | ||
251 | int channel, | ||
252 | int single_config, | ||
253 | int ref, | ||
254 | int trig_chan, | ||
255 | int trig_type, int trig_edge, int flags) | ||
256 | { | ||
257 | int err = ME_ERRNO_SUCCESS; | ||
258 | me_subdevice_t *s; | ||
259 | |||
260 | PDEBUG("executed.\n"); | ||
261 | |||
262 | // Check subdevice index. | ||
263 | |||
264 | if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { | ||
265 | PERROR("Invalid subdevice.\n"); | ||
266 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
267 | } | ||
268 | // Enter device. | ||
269 | err = me_dlock_enter(&device->dlock, filep); | ||
270 | |||
271 | if (err) { | ||
272 | PERROR("Cannot enter device.\n"); | ||
273 | return err; | ||
274 | } | ||
275 | // Get subdevice instance. | ||
276 | s = me_slist_get_subdevice(&device->slist, subdevice); | ||
277 | |||
278 | if (s) { | ||
279 | // Call subdevice method. | ||
280 | err = s->me_subdevice_io_single_config(s, | ||
281 | filep, | ||
282 | channel, | ||
283 | single_config, | ||
284 | ref, | ||
285 | trig_chan, | ||
286 | trig_type, | ||
287 | trig_edge, flags); | ||
288 | } else { | ||
289 | // Something really bad happened. | ||
290 | PERROR("Cannot get subdevice instance.\n"); | ||
291 | err = ME_ERRNO_INTERNAL; | ||
292 | } | ||
293 | |||
294 | // Exit device. | ||
295 | me_dlock_exit(&device->dlock, filep); | ||
296 | |||
297 | return err; | ||
298 | } | ||
299 | |||
300 | static int me_device_io_single_read(struct me_device *device, | ||
301 | struct file *filep, | ||
302 | int subdevice, | ||
303 | int channel, | ||
304 | int *value, int time_out, int flags) | ||
305 | { | ||
306 | int err = ME_ERRNO_SUCCESS; | ||
307 | me_subdevice_t *s; | ||
308 | |||
309 | PDEBUG("executed.\n"); | ||
310 | |||
311 | // Check subdevice index. | ||
312 | |||
313 | if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { | ||
314 | PERROR("Invalid subdevice.\n"); | ||
315 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
316 | } | ||
317 | // Enter device. | ||
318 | err = me_dlock_enter(&device->dlock, filep); | ||
319 | |||
320 | if (err) { | ||
321 | PERROR("Cannot enter device.\n"); | ||
322 | return err; | ||
323 | } | ||
324 | // Get subdevice instance. | ||
325 | s = me_slist_get_subdevice(&device->slist, subdevice); | ||
326 | |||
327 | if (s) { | ||
328 | // Call subdevice method. | ||
329 | err = s->me_subdevice_io_single_read(s, | ||
330 | filep, | ||
331 | channel, | ||
332 | value, time_out, flags); | ||
333 | } else { | ||
334 | // Something really bad happened. | ||
335 | PERROR("Cannot get subdevice instance.\n"); | ||
336 | err = ME_ERRNO_INTERNAL; | ||
337 | } | ||
338 | |||
339 | // Exit device. | ||
340 | me_dlock_exit(&device->dlock, filep); | ||
341 | |||
342 | return err; | ||
343 | } | ||
344 | |||
345 | static int me_device_io_single_write(struct me_device *device, | ||
346 | struct file *filep, | ||
347 | int subdevice, | ||
348 | int channel, | ||
349 | int value, int time_out, int flags) | ||
350 | { | ||
351 | int err = ME_ERRNO_SUCCESS; | ||
352 | me_subdevice_t *s; | ||
353 | |||
354 | PDEBUG("executed.\n"); | ||
355 | |||
356 | // Check subdevice index. | ||
357 | |||
358 | if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { | ||
359 | PERROR("Invalid subdevice.\n"); | ||
360 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
361 | } | ||
362 | // Enter device. | ||
363 | err = me_dlock_enter(&device->dlock, filep); | ||
364 | |||
365 | if (err) { | ||
366 | PERROR("Cannot enter device.\n"); | ||
367 | return err; | ||
368 | } | ||
369 | // Get subdevice instance. | ||
370 | s = me_slist_get_subdevice(&device->slist, subdevice); | ||
371 | |||
372 | if (s) { | ||
373 | // Call subdevice method. | ||
374 | err = s->me_subdevice_io_single_write(s, | ||
375 | filep, | ||
376 | channel, | ||
377 | value, time_out, flags); | ||
378 | } else { | ||
379 | // Something really bad happened. | ||
380 | PERROR("Cannot get subdevice instance.\n"); | ||
381 | err = ME_ERRNO_INTERNAL; | ||
382 | } | ||
383 | |||
384 | // Exit device. | ||
385 | me_dlock_exit(&device->dlock, filep); | ||
386 | |||
387 | return err; | ||
388 | } | ||
389 | |||
390 | static int me_device_io_stream_config(struct me_device *device, | ||
391 | struct file *filep, | ||
392 | int subdevice, | ||
393 | meIOStreamConfig_t * config_list, | ||
394 | int count, | ||
395 | meIOStreamTrigger_t * trigger, | ||
396 | int fifo_irq_threshold, int flags) | ||
397 | { | ||
398 | int err = ME_ERRNO_SUCCESS; | ||
399 | me_subdevice_t *s; | ||
400 | |||
401 | PDEBUG("executed.\n"); | ||
402 | |||
403 | // Check subdevice index. | ||
404 | |||
405 | if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { | ||
406 | PERROR("Invalid subdevice.\n"); | ||
407 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
408 | } | ||
409 | // Enter device. | ||
410 | err = me_dlock_enter(&device->dlock, filep); | ||
411 | |||
412 | if (err) { | ||
413 | PERROR("Cannot enter device.\n"); | ||
414 | return err; | ||
415 | } | ||
416 | // Get subdevice instance. | ||
417 | s = me_slist_get_subdevice(&device->slist, subdevice); | ||
418 | |||
419 | if (s) { | ||
420 | // Call subdevice method. | ||
421 | err = s->me_subdevice_io_stream_config(s, | ||
422 | filep, | ||
423 | config_list, | ||
424 | count, | ||
425 | trigger, | ||
426 | fifo_irq_threshold, | ||
427 | flags); | ||
428 | } else { | ||
429 | // Something really bad happened. | ||
430 | PERROR("Cannot get subdevice instance.\n"); | ||
431 | err = ME_ERRNO_INTERNAL; | ||
432 | } | ||
433 | |||
434 | // Exit device. | ||
435 | me_dlock_exit(&device->dlock, filep); | ||
436 | |||
437 | return err; | ||
438 | } | ||
439 | |||
440 | static int me_device_io_stream_new_values(struct me_device *device, | ||
441 | struct file *filep, | ||
442 | int subdevice, | ||
443 | int time_out, int *count, int flags) | ||
444 | { | ||
445 | int err = ME_ERRNO_SUCCESS; | ||
446 | me_subdevice_t *s; | ||
447 | |||
448 | PDEBUG("executed.\n"); | ||
449 | |||
450 | // Check subdevice index. | ||
451 | |||
452 | if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { | ||
453 | PERROR("Invalid subdevice.\n"); | ||
454 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
455 | } | ||
456 | // Enter device. | ||
457 | err = me_dlock_enter(&device->dlock, filep); | ||
458 | |||
459 | if (err) { | ||
460 | PERROR("Cannot enter device.\n"); | ||
461 | return err; | ||
462 | } | ||
463 | // Get subdevice instance. | ||
464 | s = me_slist_get_subdevice(&device->slist, subdevice); | ||
465 | |||
466 | if (s) { | ||
467 | // Call subdevice method. | ||
468 | err = s->me_subdevice_io_stream_new_values(s, | ||
469 | filep, | ||
470 | time_out, | ||
471 | count, flags); | ||
472 | } else { | ||
473 | // Something really bad happened. | ||
474 | PERROR("Cannot get subdevice instance.\n"); | ||
475 | err = ME_ERRNO_INTERNAL; | ||
476 | } | ||
477 | |||
478 | // Exit device. | ||
479 | me_dlock_exit(&device->dlock, filep); | ||
480 | |||
481 | return err; | ||
482 | } | ||
483 | |||
484 | static int me_device_io_stream_read(struct me_device *device, | ||
485 | struct file *filep, | ||
486 | int subdevice, | ||
487 | int read_mode, | ||
488 | int *values, int *count, int flags) | ||
489 | { | ||
490 | int err = ME_ERRNO_SUCCESS; | ||
491 | me_subdevice_t *s; | ||
492 | |||
493 | PDEBUG("executed.\n"); | ||
494 | |||
495 | // Check subdevice index. | ||
496 | |||
497 | if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { | ||
498 | PERROR("Invalid subdevice.\n"); | ||
499 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
500 | } | ||
501 | // Enter device. | ||
502 | err = me_dlock_enter(&device->dlock, filep); | ||
503 | |||
504 | if (err) { | ||
505 | PERROR("Cannot enter device.\n"); | ||
506 | return err; | ||
507 | } | ||
508 | // Get subdevice instance. | ||
509 | s = me_slist_get_subdevice(&device->slist, subdevice); | ||
510 | |||
511 | if (s) { | ||
512 | // Call subdevice method. | ||
513 | err = s->me_subdevice_io_stream_read(s, | ||
514 | filep, | ||
515 | read_mode, | ||
516 | values, count, flags); | ||
517 | } else { | ||
518 | // Something really bad happened. | ||
519 | PERROR("Cannot get subdevice instance.\n"); | ||
520 | err = ME_ERRNO_INTERNAL; | ||
521 | } | ||
522 | |||
523 | // Exit device. | ||
524 | me_dlock_exit(&device->dlock, filep); | ||
525 | |||
526 | return err; | ||
527 | } | ||
528 | |||
529 | static int me_device_io_stream_start(struct me_device *device, | ||
530 | struct file *filep, | ||
531 | int subdevice, | ||
532 | int start_mode, int time_out, int flags) | ||
533 | { | ||
534 | int err = ME_ERRNO_SUCCESS; | ||
535 | me_subdevice_t *s; | ||
536 | |||
537 | PDEBUG("executed.\n"); | ||
538 | |||
539 | // Check subdevice index. | ||
540 | |||
541 | if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { | ||
542 | PERROR("Invalid subdevice.\n"); | ||
543 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
544 | } | ||
545 | // Enter device. | ||
546 | err = me_dlock_enter(&device->dlock, filep); | ||
547 | |||
548 | if (err) { | ||
549 | PERROR("Cannot enter device.\n"); | ||
550 | return err; | ||
551 | } | ||
552 | // Get subdevice instance. | ||
553 | s = me_slist_get_subdevice(&device->slist, subdevice); | ||
554 | |||
555 | if (s) { | ||
556 | // Call subdevice method. | ||
557 | err = s->me_subdevice_io_stream_start(s, | ||
558 | filep, | ||
559 | start_mode, | ||
560 | time_out, flags); | ||
561 | } else { | ||
562 | // Something really bad happened. | ||
563 | PERROR("Cannot get subdevice instance.\n"); | ||
564 | err = ME_ERRNO_INTERNAL; | ||
565 | } | ||
566 | |||
567 | // Exit device. | ||
568 | me_dlock_exit(&device->dlock, filep); | ||
569 | |||
570 | return err; | ||
571 | } | ||
572 | |||
573 | static int me_device_io_stream_status(struct me_device *device, | ||
574 | struct file *filep, | ||
575 | int subdevice, | ||
576 | int wait, | ||
577 | int *status, int *count, int flags) | ||
578 | { | ||
579 | int err = ME_ERRNO_SUCCESS; | ||
580 | me_subdevice_t *s; | ||
581 | |||
582 | PDEBUG("executed.\n"); | ||
583 | |||
584 | // Check subdevice index. | ||
585 | |||
586 | if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { | ||
587 | PERROR("Invalid subdevice.\n"); | ||
588 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
589 | } | ||
590 | // Enter device. | ||
591 | err = me_dlock_enter(&device->dlock, filep); | ||
592 | |||
593 | if (err) { | ||
594 | PERROR("Cannot enter device.\n"); | ||
595 | return err; | ||
596 | } | ||
597 | // Get subdevice instance. | ||
598 | s = me_slist_get_subdevice(&device->slist, subdevice); | ||
599 | |||
600 | if (s) { | ||
601 | // Call subdevice method. | ||
602 | err = s->me_subdevice_io_stream_status(s, | ||
603 | filep, | ||
604 | wait, | ||
605 | status, count, flags); | ||
606 | } else { | ||
607 | // Something really bad happened. | ||
608 | PERROR("Cannot get subdevice instance.\n"); | ||
609 | err = ME_ERRNO_INTERNAL; | ||
610 | } | ||
611 | |||
612 | // Exit device. | ||
613 | me_dlock_exit(&device->dlock, filep); | ||
614 | |||
615 | return err; | ||
616 | } | ||
617 | |||
618 | static int me_device_io_stream_stop(struct me_device *device, | ||
619 | struct file *filep, | ||
620 | int subdevice, int stop_mode, int flags) | ||
621 | { | ||
622 | int err = ME_ERRNO_SUCCESS; | ||
623 | me_subdevice_t *s; | ||
624 | |||
625 | PDEBUG("executed.\n"); | ||
626 | |||
627 | // Check subdevice index. | ||
628 | |||
629 | if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { | ||
630 | PERROR("Invalid subdevice.\n"); | ||
631 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
632 | } | ||
633 | // Enter device. | ||
634 | err = me_dlock_enter(&device->dlock, filep); | ||
635 | |||
636 | if (err) { | ||
637 | PERROR("Cannot enter device.\n"); | ||
638 | return err; | ||
639 | } | ||
640 | // Get subdevice instance. | ||
641 | s = me_slist_get_subdevice(&device->slist, subdevice); | ||
642 | |||
643 | if (s) { | ||
644 | // Call subdevice method. | ||
645 | err = s->me_subdevice_io_stream_stop(s, | ||
646 | filep, stop_mode, flags); | ||
647 | } else { | ||
648 | // Something really bad happened. | ||
649 | PERROR("Cannot get subdevice instance.\n"); | ||
650 | err = ME_ERRNO_INTERNAL; | ||
651 | } | ||
652 | |||
653 | // Exit device. | ||
654 | me_dlock_exit(&device->dlock, filep); | ||
655 | |||
656 | return err; | ||
657 | } | ||
658 | |||
659 | static int me_device_io_stream_write(struct me_device *device, | ||
660 | struct file *filep, | ||
661 | int subdevice, | ||
662 | int write_mode, | ||
663 | int *values, int *count, int flags) | ||
664 | { | ||
665 | int err = ME_ERRNO_SUCCESS; | ||
666 | me_subdevice_t *s; | ||
667 | |||
668 | PDEBUG("executed.\n"); | ||
669 | |||
670 | // Check subdevice index. | ||
671 | |||
672 | if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { | ||
673 | PERROR("Invalid subdevice.\n"); | ||
674 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
675 | } | ||
676 | // Enter device. | ||
677 | err = me_dlock_enter(&device->dlock, filep); | ||
678 | |||
679 | if (err) { | ||
680 | PERROR("Cannot enter device.\n"); | ||
681 | return err; | ||
682 | } | ||
683 | // Get subdevice instance. | ||
684 | s = me_slist_get_subdevice(&device->slist, subdevice); | ||
685 | |||
686 | if (s) { | ||
687 | // Call subdevice method. | ||
688 | err = s->me_subdevice_io_stream_write(s, | ||
689 | filep, | ||
690 | write_mode, | ||
691 | values, count, flags); | ||
692 | } else { | ||
693 | // Something really bad happened. | ||
694 | PERROR("Cannot get subdevice instance.\n"); | ||
695 | err = ME_ERRNO_INTERNAL; | ||
696 | } | ||
697 | |||
698 | // Exit device. | ||
699 | me_dlock_exit(&device->dlock, filep); | ||
700 | |||
701 | return err; | ||
702 | } | ||
703 | |||
704 | static int me_device_lock_device(struct me_device *device, | ||
705 | struct file *filep, int lock, int flags) | ||
706 | { | ||
707 | PDEBUG("executed.\n"); | ||
708 | |||
709 | return me_dlock_lock(&device->dlock, | ||
710 | filep, lock, flags, &device->slist); | ||
711 | } | ||
712 | |||
713 | static int me_device_lock_subdevice(struct me_device *device, | ||
714 | struct file *filep, | ||
715 | int subdevice, int lock, int flags) | ||
716 | { | ||
717 | int err = ME_ERRNO_SUCCESS; | ||
718 | me_subdevice_t *s; | ||
719 | |||
720 | PDEBUG("executed.\n"); | ||
721 | |||
722 | // Check subdevice index. | ||
723 | |||
724 | if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { | ||
725 | PERROR("Invalid subdevice.\n"); | ||
726 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
727 | } | ||
728 | // Enter device. | ||
729 | err = me_dlock_enter(&device->dlock, filep); | ||
730 | |||
731 | if (err) { | ||
732 | PERROR("Cannot enter device.\n"); | ||
733 | return err; | ||
734 | } | ||
735 | // Get subdevice instance. | ||
736 | s = me_slist_get_subdevice(&device->slist, subdevice); | ||
737 | |||
738 | if (s) { | ||
739 | // Call subdevice method. | ||
740 | err = s->me_subdevice_lock_subdevice(s, filep, lock, flags); | ||
741 | } else { | ||
742 | // Something really bad happened. | ||
743 | PERROR("Cannot get subdevice instance.\n"); | ||
744 | err = ME_ERRNO_INTERNAL; | ||
745 | } | ||
746 | |||
747 | // Exit device. | ||
748 | me_dlock_exit(&device->dlock, filep); | ||
749 | |||
750 | return err; | ||
751 | } | ||
752 | |||
753 | static int me_device_query_description_device(struct me_device *device, | ||
754 | char **description) | ||
755 | { | ||
756 | PDEBUG("executed.\n"); | ||
757 | *description = device->device_description; | ||
758 | return ME_ERRNO_SUCCESS; | ||
759 | } | ||
760 | |||
761 | static int me_device_query_info_device(struct me_device *device, | ||
762 | int *vendor_id, | ||
763 | int *device_id, | ||
764 | int *serial_no, | ||
765 | int *bus_type, | ||
766 | int *bus_no, | ||
767 | int *dev_no, int *func_no, int *plugged) | ||
768 | { | ||
769 | PDEBUG("executed.\n"); | ||
770 | |||
771 | if (device->bus_type == ME_BUS_TYPE_PCI) { | ||
772 | *vendor_id = device->info.pci.vendor_id; | ||
773 | *device_id = device->info.pci.device_id; | ||
774 | *serial_no = device->info.pci.serial_no; | ||
775 | *bus_type = ME_BUS_TYPE_PCI; | ||
776 | *bus_no = device->info.pci.pci_bus_no; | ||
777 | *dev_no = device->info.pci.pci_dev_no; | ||
778 | *func_no = device->info.pci.pci_func_no; | ||
779 | *plugged = ME_PLUGGED_IN; | ||
780 | } else { | ||
781 | *plugged = ME_PLUGGED_OUT; | ||
782 | } | ||
783 | return ME_ERRNO_SUCCESS; | ||
784 | } | ||
785 | |||
786 | static int me_device_query_name_device(struct me_device *device, char **name) | ||
787 | { | ||
788 | PDEBUG("executed.\n"); | ||
789 | *name = device->device_name; | ||
790 | return ME_ERRNO_SUCCESS; | ||
791 | } | ||
792 | |||
793 | static int me_device_query_name_device_driver(struct me_device *device, | ||
794 | char **name) | ||
795 | { | ||
796 | PDEBUG("executed.\n"); | ||
797 | *name = device->driver_name; | ||
798 | return ME_ERRNO_SUCCESS; | ||
799 | } | ||
800 | |||
801 | static int me_device_query_number_subdevices(struct me_device *device, | ||
802 | int *number) | ||
803 | { | ||
804 | PDEBUG("executed.\n"); | ||
805 | return me_slist_query_number_subdevices(&device->slist, number); | ||
806 | } | ||
807 | |||
808 | static int me_device_query_number_channels(struct me_device *device, | ||
809 | int subdevice, int *number) | ||
810 | { | ||
811 | int err = ME_ERRNO_SUCCESS; | ||
812 | me_subdevice_t *s; | ||
813 | |||
814 | PDEBUG("executed.\n"); | ||
815 | |||
816 | // Check subdevice index. | ||
817 | |||
818 | if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { | ||
819 | PERROR("Invalid subdevice.\n"); | ||
820 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
821 | } | ||
822 | // Get subdevice instance. | ||
823 | s = me_slist_get_subdevice(&device->slist, subdevice); | ||
824 | |||
825 | if (s) { | ||
826 | // Call subdevice method. | ||
827 | err = s->me_subdevice_query_number_channels(s, number); | ||
828 | } else { | ||
829 | // Something really bad happened. | ||
830 | PERROR("Cannot get subdevice instance.\n"); | ||
831 | err = ME_ERRNO_INTERNAL; | ||
832 | } | ||
833 | |||
834 | return err; | ||
835 | } | ||
836 | |||
837 | static int me_device_query_number_ranges(struct me_device *device, | ||
838 | int subdevice, int unit, int *count) | ||
839 | { | ||
840 | int err = ME_ERRNO_SUCCESS; | ||
841 | me_subdevice_t *s; | ||
842 | |||
843 | PDEBUG("executed.\n"); | ||
844 | |||
845 | // Check subdevice index. | ||
846 | |||
847 | if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { | ||
848 | PERROR("Invalid subdevice.\n"); | ||
849 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
850 | } | ||
851 | // Get subdevice instance. | ||
852 | s = me_slist_get_subdevice(&device->slist, subdevice); | ||
853 | |||
854 | if (s) { | ||
855 | // Call subdevice method. | ||
856 | err = s->me_subdevice_query_number_ranges(s, unit, count); | ||
857 | } else { | ||
858 | // Something really bad happened. | ||
859 | PERROR("Cannot get subdevice instance.\n"); | ||
860 | err = ME_ERRNO_INTERNAL; | ||
861 | } | ||
862 | |||
863 | return err; | ||
864 | } | ||
865 | |||
866 | static int me_device_query_range_by_min_max(struct me_device *device, | ||
867 | int subdevice, | ||
868 | int unit, | ||
869 | int *min, | ||
870 | int *max, int *maxdata, int *range) | ||
871 | { | ||
872 | int err = ME_ERRNO_SUCCESS; | ||
873 | me_subdevice_t *s; | ||
874 | |||
875 | PDEBUG("executed.\n"); | ||
876 | |||
877 | // Check subdevice index. | ||
878 | |||
879 | if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { | ||
880 | PERROR("Invalid subdevice.\n"); | ||
881 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
882 | } | ||
883 | // Get subdevice instance. | ||
884 | s = me_slist_get_subdevice(&device->slist, subdevice); | ||
885 | |||
886 | if (s) { | ||
887 | // Call subdevice method. | ||
888 | err = s->me_subdevice_query_range_by_min_max(s, | ||
889 | unit, | ||
890 | min, | ||
891 | max, | ||
892 | maxdata, range); | ||
893 | } else { | ||
894 | // Something really bad happened. | ||
895 | PERROR("Cannot get subdevice instance.\n"); | ||
896 | err = ME_ERRNO_INTERNAL; | ||
897 | } | ||
898 | |||
899 | return err; | ||
900 | } | ||
901 | |||
902 | static int me_device_query_range_info(struct me_device *device, | ||
903 | int subdevice, | ||
904 | int range, | ||
905 | int *unit, | ||
906 | int *min, int *max, int *maxdata) | ||
907 | { | ||
908 | int err = ME_ERRNO_SUCCESS; | ||
909 | me_subdevice_t *s; | ||
910 | |||
911 | PDEBUG("executed.\n"); | ||
912 | |||
913 | // Check subdevice index. | ||
914 | |||
915 | if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { | ||
916 | PERROR("Invalid subdevice.\n"); | ||
917 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
918 | } | ||
919 | // Get subdevice instance. | ||
920 | s = me_slist_get_subdevice(&device->slist, subdevice); | ||
921 | |||
922 | if (s) { | ||
923 | // Call subdevice method. | ||
924 | err = s->me_subdevice_query_range_info(s, | ||
925 | range, | ||
926 | unit, min, max, maxdata); | ||
927 | } else { | ||
928 | // Something really bad happened. | ||
929 | PERROR("Cannot get subdevice instance.\n"); | ||
930 | err = ME_ERRNO_INTERNAL; | ||
931 | } | ||
932 | |||
933 | return err; | ||
934 | } | ||
935 | |||
936 | static int me_device_query_subdevice_by_type(struct me_device *device, | ||
937 | int start_subdevice, | ||
938 | int type, | ||
939 | int subtype, int *subdevice) | ||
940 | { | ||
941 | PDEBUG("executed.\n"); | ||
942 | |||
943 | return me_slist_get_subdevice_by_type(&device->slist, | ||
944 | start_subdevice, | ||
945 | type, subtype, subdevice); | ||
946 | } | ||
947 | |||
948 | static int me_device_query_subdevice_type(struct me_device *device, | ||
949 | int subdevice, | ||
950 | int *type, int *subtype) | ||
951 | { | ||
952 | int err = ME_ERRNO_SUCCESS; | ||
953 | me_subdevice_t *s; | ||
954 | |||
955 | PDEBUG("executed.\n"); | ||
956 | |||
957 | // Check subdevice index. | ||
958 | |||
959 | if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { | ||
960 | PERROR("Invalid subdevice.\n"); | ||
961 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
962 | } | ||
963 | // Get subdevice instance. | ||
964 | s = me_slist_get_subdevice(&device->slist, subdevice); | ||
965 | |||
966 | if (s) { | ||
967 | // Call subdevice method. | ||
968 | err = s->me_subdevice_query_subdevice_type(s, type, subtype); | ||
969 | } else { | ||
970 | // Something really bad happened. | ||
971 | PERROR("Cannot get subdevice instance.\n"); | ||
972 | err = ME_ERRNO_INTERNAL; | ||
973 | } | ||
974 | |||
975 | return err; | ||
976 | } | ||
977 | |||
978 | static int me_device_query_subdevice_caps(struct me_device *device, | ||
979 | int subdevice, int *caps) | ||
980 | { | ||
981 | int err = ME_ERRNO_SUCCESS; | ||
982 | me_subdevice_t *s; | ||
983 | |||
984 | PDEBUG("executed.\n"); | ||
985 | |||
986 | // Check subdevice index. | ||
987 | |||
988 | if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { | ||
989 | PERROR("Invalid subdevice.\n"); | ||
990 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
991 | } | ||
992 | // Get subdevice instance. | ||
993 | s = me_slist_get_subdevice(&device->slist, subdevice); | ||
994 | |||
995 | if (s) { | ||
996 | // Call subdevice method. | ||
997 | err = s->me_subdevice_query_subdevice_caps(s, caps); | ||
998 | } else { | ||
999 | // Something really bad happened. | ||
1000 | PERROR("Cannot get subdevice instance.\n"); | ||
1001 | err = ME_ERRNO_INTERNAL; | ||
1002 | } | ||
1003 | |||
1004 | return err; | ||
1005 | } | ||
1006 | |||
1007 | static int me_device_query_subdevice_caps_args(struct me_device *device, | ||
1008 | int subdevice, | ||
1009 | int cap, int *args, int count) | ||
1010 | { | ||
1011 | int err = ME_ERRNO_SUCCESS; | ||
1012 | me_subdevice_t *s; | ||
1013 | |||
1014 | PDEBUG("executed.\n"); | ||
1015 | |||
1016 | // Check subdevice index. | ||
1017 | |||
1018 | if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { | ||
1019 | PERROR("Invalid subdevice.\n"); | ||
1020 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
1021 | } | ||
1022 | // Get subdevice instance. | ||
1023 | s = me_slist_get_subdevice(&device->slist, subdevice); | ||
1024 | |||
1025 | if (s) { | ||
1026 | // Call subdevice method. | ||
1027 | err = s->me_subdevice_query_subdevice_caps_args(s, | ||
1028 | cap, | ||
1029 | args, count); | ||
1030 | } else { | ||
1031 | // Something really bad happened. | ||
1032 | PERROR("Cannot get subdevice instance.\n"); | ||
1033 | err = ME_ERRNO_INTERNAL; | ||
1034 | } | ||
1035 | |||
1036 | return err; | ||
1037 | } | ||
1038 | |||
1039 | static int me_device_query_timer(struct me_device *device, | ||
1040 | int subdevice, | ||
1041 | int timer, | ||
1042 | int *base_frequency, | ||
1043 | uint64_t * min_ticks, uint64_t * max_ticks) | ||
1044 | { | ||
1045 | int err = ME_ERRNO_SUCCESS; | ||
1046 | me_subdevice_t *s; | ||
1047 | |||
1048 | PDEBUG("executed.\n"); | ||
1049 | |||
1050 | // Check subdevice index. | ||
1051 | |||
1052 | if (subdevice >= me_slist_get_number_subdevices(&device->slist)) { | ||
1053 | PERROR("Invalid subdevice.\n"); | ||
1054 | return ME_ERRNO_INVALID_SUBDEVICE; | ||
1055 | } | ||
1056 | // Get subdevice instance. | ||
1057 | s = me_slist_get_subdevice(&device->slist, subdevice); | ||
1058 | |||
1059 | if (s) { | ||
1060 | // Call subdevice method. | ||
1061 | err = s->me_subdevice_query_timer(s, | ||
1062 | timer, | ||
1063 | base_frequency, | ||
1064 | min_ticks, max_ticks); | ||
1065 | } else { | ||
1066 | // Something really bad happened. | ||
1067 | PERROR("Cannot get subdevice instance.\n"); | ||
1068 | err = ME_ERRNO_INTERNAL; | ||
1069 | } | ||
1070 | |||
1071 | return err; | ||
1072 | } | ||
1073 | |||
1074 | static int me_device_query_version_device_driver(struct me_device *device, | ||
1075 | int *version) | ||
1076 | /** @todo Versions shold be read from driver. I must overwrite this function in each module. Here should be returned an error! | ||
1077 | */ | ||
1078 | { | ||
1079 | PDEBUG("executed.\n"); | ||
1080 | *version = ME_VERSION_DRIVER; | ||
1081 | return ME_ERRNO_SUCCESS; | ||
1082 | } | ||
1083 | |||
1084 | static int me_device_config_load(struct me_device *device, struct file *filep, | ||
1085 | me_cfg_device_entry_t * config) | ||
1086 | { | ||
1087 | PDEBUG("executed.\n"); | ||
1088 | return ME_ERRNO_SUCCESS; //If no need for config return success. | ||
1089 | // return ME_ERRNO_NOT_SUPPORTED; | ||
1090 | } | ||
1091 | |||
1092 | static void me_device_destructor(me_device_t * me_device) | ||
1093 | { | ||
1094 | PDEBUG("executed.\n"); | ||
1095 | me_device_deinit(me_device); | ||
1096 | kfree(me_device); | ||
1097 | } | ||
1098 | |||
1099 | /* //me_device_usb_init | ||
1100 | int me_device_usb_init(me_device_t *me_device, struct usb_interface *interface) | ||
1101 | { | ||
1102 | PDEBUG("executed.\n"); | ||
1103 | return -1; | ||
1104 | } | ||
1105 | */ | ||
1106 | |||
1107 | static int get_device_descriptions(uint16_t device_id, | ||
1108 | char **device_name, | ||
1109 | char **device_description, | ||
1110 | char **driver_name) | ||
1111 | /** @todo This is wrong concept! Static table has too strong limitations! | ||
1112 | * 'device_name' and 'driver_name' should be calculated from 'device_id' | ||
1113 | * 'device_description' should be read from device or moved to user space and handled by library! | ||
1114 | */ | ||
1115 | { | ||
1116 | PDEBUG("executed.\n"); | ||
1117 | |||
1118 | switch (device_id) { | ||
1119 | case PCI_DEVICE_ID_MEILHAUS_ME1000: | ||
1120 | case PCI_DEVICE_ID_MEILHAUS_ME1000_A: | ||
1121 | case PCI_DEVICE_ID_MEILHAUS_ME1000_B: | ||
1122 | *device_name = ME1000_NAME_DEVICE_ME1000; | ||
1123 | *device_description = ME1000_DESCRIPTION_DEVICE_ME1000; | ||
1124 | *driver_name = ME1000_NAME_DRIVER; | ||
1125 | break; | ||
1126 | |||
1127 | case PCI_DEVICE_ID_MEILHAUS_ME1400: | ||
1128 | *device_name = ME1400_NAME_DEVICE_ME1400; | ||
1129 | *device_description = ME1400_DESCRIPTION_DEVICE_ME1400; | ||
1130 | *driver_name = ME1400_NAME_DRIVER; | ||
1131 | break; | ||
1132 | |||
1133 | case PCI_DEVICE_ID_MEILHAUS_ME140A: | ||
1134 | *device_name = ME1400_NAME_DEVICE_ME1400A; | ||
1135 | *device_description = ME1400_DESCRIPTION_DEVICE_ME1400A; | ||
1136 | *driver_name = ME1400_NAME_DRIVER; | ||
1137 | break; | ||
1138 | |||
1139 | case PCI_DEVICE_ID_MEILHAUS_ME140B: | ||
1140 | *device_name = ME1400_NAME_DEVICE_ME1400B; | ||
1141 | *device_description = ME1400_DESCRIPTION_DEVICE_ME1400B; | ||
1142 | *driver_name = ME1400_NAME_DRIVER; | ||
1143 | break; | ||
1144 | |||
1145 | case PCI_DEVICE_ID_MEILHAUS_ME14E0: | ||
1146 | *device_name = ME1400_NAME_DEVICE_ME1400E; | ||
1147 | *device_description = ME1400_DESCRIPTION_DEVICE_ME1400E; | ||
1148 | *driver_name = ME1400_NAME_DRIVER; | ||
1149 | break; | ||
1150 | |||
1151 | case PCI_DEVICE_ID_MEILHAUS_ME14EA: | ||
1152 | *device_name = ME1400_NAME_DEVICE_ME1400EA; | ||
1153 | *device_description = ME1400_DESCRIPTION_DEVICE_ME1400EA; | ||
1154 | *driver_name = ME1400_NAME_DRIVER; | ||
1155 | break; | ||
1156 | |||
1157 | case PCI_DEVICE_ID_MEILHAUS_ME14EB: | ||
1158 | *device_name = ME1400_NAME_DEVICE_ME1400EB; | ||
1159 | *device_description = ME1400_DESCRIPTION_DEVICE_ME1400EB; | ||
1160 | *driver_name = ME1400_NAME_DRIVER; | ||
1161 | break; | ||
1162 | |||
1163 | case PCI_DEVICE_ID_MEILHAUS_ME140C: | ||
1164 | *device_name = ME1400_NAME_DEVICE_ME1400C; | ||
1165 | *device_description = ME1400_DESCRIPTION_DEVICE_ME1400C; | ||
1166 | *driver_name = ME1400_NAME_DRIVER; | ||
1167 | break; | ||
1168 | |||
1169 | case PCI_DEVICE_ID_MEILHAUS_ME140D: | ||
1170 | *device_name = ME1400_NAME_DEVICE_ME1400D; | ||
1171 | *device_description = ME1400_DESCRIPTION_DEVICE_ME1400D; | ||
1172 | *driver_name = ME1400_NAME_DRIVER; | ||
1173 | break; | ||
1174 | |||
1175 | case PCI_DEVICE_ID_MEILHAUS_ME1600_4U: | ||
1176 | *device_name = ME1600_NAME_DEVICE_ME16004U; | ||
1177 | *device_description = ME1600_DESCRIPTION_DEVICE_ME16004U; | ||
1178 | *driver_name = ME1600_NAME_DRIVER; | ||
1179 | break; | ||
1180 | |||
1181 | case PCI_DEVICE_ID_MEILHAUS_ME1600_8U: | ||
1182 | *device_name = ME1600_NAME_DEVICE_ME16008U; | ||
1183 | *device_description = ME1600_DESCRIPTION_DEVICE_ME16008U; | ||
1184 | *driver_name = ME1600_NAME_DRIVER; | ||
1185 | break; | ||
1186 | |||
1187 | case PCI_DEVICE_ID_MEILHAUS_ME1600_12U: | ||
1188 | *device_name = ME1600_NAME_DEVICE_ME160012U; | ||
1189 | *device_description = ME1600_DESCRIPTION_DEVICE_ME160012U; | ||
1190 | *driver_name = ME1600_NAME_DRIVER; | ||
1191 | break; | ||
1192 | |||
1193 | case PCI_DEVICE_ID_MEILHAUS_ME1600_16U: | ||
1194 | *device_name = ME1600_NAME_DEVICE_ME160016U; | ||
1195 | *device_description = ME1600_DESCRIPTION_DEVICE_ME160016U; | ||
1196 | *driver_name = ME1600_NAME_DRIVER; | ||
1197 | break; | ||
1198 | |||
1199 | case PCI_DEVICE_ID_MEILHAUS_ME1600_16U_8I: | ||
1200 | *device_name = ME1600_NAME_DEVICE_ME160016U8I; | ||
1201 | *device_description = ME1600_DESCRIPTION_DEVICE_ME160016U8I; | ||
1202 | *driver_name = ME1600_NAME_DRIVER; | ||
1203 | break; | ||
1204 | |||
1205 | case PCI_DEVICE_ID_MEILHAUS_ME4610: | ||
1206 | *device_name = ME4600_NAME_DEVICE_ME4610; | ||
1207 | *device_description = ME4600_DESCRIPTION_DEVICE_ME4610; | ||
1208 | *driver_name = ME4600_NAME_DRIVER; | ||
1209 | break; | ||
1210 | |||
1211 | case PCI_DEVICE_ID_MEILHAUS_ME4650: | ||
1212 | *device_name = ME4600_NAME_DEVICE_ME4650; | ||
1213 | *device_description = ME4600_DESCRIPTION_DEVICE_ME4650; | ||
1214 | *driver_name = ME4600_NAME_DRIVER; | ||
1215 | break; | ||
1216 | |||
1217 | case PCI_DEVICE_ID_MEILHAUS_ME4660: | ||
1218 | *device_name = ME4600_NAME_DEVICE_ME4660; | ||
1219 | *device_description = ME4600_DESCRIPTION_DEVICE_ME4660; | ||
1220 | *driver_name = ME4600_NAME_DRIVER; | ||
1221 | break; | ||
1222 | |||
1223 | case PCI_DEVICE_ID_MEILHAUS_ME4660I: | ||
1224 | *device_name = ME4600_NAME_DEVICE_ME4660I; | ||
1225 | *device_description = ME4600_DESCRIPTION_DEVICE_ME4660I; | ||
1226 | *driver_name = ME4600_NAME_DRIVER; | ||
1227 | break; | ||
1228 | |||
1229 | case PCI_DEVICE_ID_MEILHAUS_ME4660S: | ||
1230 | *device_name = ME4600_NAME_DEVICE_ME4660S; | ||
1231 | *device_description = ME4600_DESCRIPTION_DEVICE_ME4660S; | ||
1232 | *driver_name = ME4600_NAME_DRIVER; | ||
1233 | break; | ||
1234 | |||
1235 | case PCI_DEVICE_ID_MEILHAUS_ME4660IS: | ||
1236 | *device_name = ME4600_NAME_DEVICE_ME4660IS; | ||
1237 | *device_description = ME4600_DESCRIPTION_DEVICE_ME4660IS; | ||
1238 | *driver_name = ME4600_NAME_DRIVER; | ||
1239 | break; | ||
1240 | |||
1241 | case PCI_DEVICE_ID_MEILHAUS_ME4670: | ||
1242 | *device_name = ME4600_NAME_DEVICE_ME4670; | ||
1243 | *device_description = ME4600_DESCRIPTION_DEVICE_ME4670; | ||
1244 | *driver_name = ME4600_NAME_DRIVER; | ||
1245 | break; | ||
1246 | |||
1247 | case PCI_DEVICE_ID_MEILHAUS_ME4670I: | ||
1248 | *device_name = ME4600_NAME_DEVICE_ME4670I; | ||
1249 | *device_description = ME4600_DESCRIPTION_DEVICE_ME4670I; | ||
1250 | *driver_name = ME4600_NAME_DRIVER; | ||
1251 | break; | ||
1252 | |||
1253 | case PCI_DEVICE_ID_MEILHAUS_ME4670S: | ||
1254 | *device_name = ME4600_NAME_DEVICE_ME4670S; | ||
1255 | *device_description = ME4600_DESCRIPTION_DEVICE_ME4670S; | ||
1256 | *driver_name = ME4600_NAME_DRIVER; | ||
1257 | break; | ||
1258 | |||
1259 | case PCI_DEVICE_ID_MEILHAUS_ME4670IS: | ||
1260 | *device_name = ME4600_NAME_DEVICE_ME4670IS; | ||
1261 | *device_description = ME4600_DESCRIPTION_DEVICE_ME4670IS; | ||
1262 | *driver_name = ME4600_NAME_DRIVER; | ||
1263 | break; | ||
1264 | |||
1265 | case PCI_DEVICE_ID_MEILHAUS_ME4680: | ||
1266 | *device_name = ME4600_NAME_DEVICE_ME4680; | ||
1267 | *device_description = ME4600_DESCRIPTION_DEVICE_ME4680; | ||
1268 | *driver_name = ME4600_NAME_DRIVER; | ||
1269 | break; | ||
1270 | |||
1271 | case PCI_DEVICE_ID_MEILHAUS_ME4680I: | ||
1272 | *device_name = ME4600_NAME_DEVICE_ME4680I; | ||
1273 | *device_description = ME4600_DESCRIPTION_DEVICE_ME4680I; | ||
1274 | *driver_name = ME4600_NAME_DRIVER; | ||
1275 | break; | ||
1276 | |||
1277 | case PCI_DEVICE_ID_MEILHAUS_ME4680S: | ||
1278 | *device_name = ME4600_NAME_DEVICE_ME4680S; | ||
1279 | *device_description = ME4600_DESCRIPTION_DEVICE_ME4680S; | ||
1280 | *driver_name = ME4600_NAME_DRIVER; | ||
1281 | break; | ||
1282 | |||
1283 | case PCI_DEVICE_ID_MEILHAUS_ME4680IS: | ||
1284 | *device_name = ME4600_NAME_DEVICE_ME4680IS; | ||
1285 | *device_description = ME4600_DESCRIPTION_DEVICE_ME4680IS; | ||
1286 | *driver_name = ME4600_NAME_DRIVER; | ||
1287 | break; | ||
1288 | |||
1289 | case PCI_DEVICE_ID_MEILHAUS_ME6004: | ||
1290 | *device_name = ME6000_NAME_DEVICE_ME60004; | ||
1291 | *device_description = ME6000_DESCRIPTION_DEVICE_ME60004; | ||
1292 | *driver_name = ME6000_NAME_DRIVER; | ||
1293 | break; | ||
1294 | |||
1295 | case PCI_DEVICE_ID_MEILHAUS_ME6008: | ||
1296 | *device_name = ME6000_NAME_DEVICE_ME60008; | ||
1297 | *device_description = ME6000_DESCRIPTION_DEVICE_ME60008; | ||
1298 | *driver_name = ME6000_NAME_DRIVER; | ||
1299 | break; | ||
1300 | |||
1301 | case PCI_DEVICE_ID_MEILHAUS_ME600F: | ||
1302 | *device_name = ME6000_NAME_DEVICE_ME600016; | ||
1303 | *device_description = ME6000_DESCRIPTION_DEVICE_ME600016; | ||
1304 | *driver_name = ME6000_NAME_DRIVER; | ||
1305 | break; | ||
1306 | |||
1307 | case PCI_DEVICE_ID_MEILHAUS_ME6014: | ||
1308 | *device_name = ME6000_NAME_DEVICE_ME6000I4; | ||
1309 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6000I4; | ||
1310 | *driver_name = ME6000_NAME_DRIVER; | ||
1311 | break; | ||
1312 | |||
1313 | case PCI_DEVICE_ID_MEILHAUS_ME6018: | ||
1314 | *device_name = ME6000_NAME_DEVICE_ME6000I8; | ||
1315 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6000I8; | ||
1316 | *driver_name = ME6000_NAME_DRIVER; | ||
1317 | break; | ||
1318 | |||
1319 | case PCI_DEVICE_ID_MEILHAUS_ME601F: | ||
1320 | *device_name = ME6000_NAME_DEVICE_ME6000I16; | ||
1321 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6000I16; | ||
1322 | *driver_name = ME6000_NAME_DRIVER; | ||
1323 | break; | ||
1324 | |||
1325 | case PCI_DEVICE_ID_MEILHAUS_ME6034: | ||
1326 | *device_name = ME6000_NAME_DEVICE_ME6000ISLE4; | ||
1327 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6000ISLE4; | ||
1328 | *driver_name = ME6000_NAME_DRIVER; | ||
1329 | break; | ||
1330 | |||
1331 | case PCI_DEVICE_ID_MEILHAUS_ME6038: | ||
1332 | *device_name = ME6000_NAME_DEVICE_ME6000ISLE8; | ||
1333 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6000ISLE8; | ||
1334 | *driver_name = ME6000_NAME_DRIVER; | ||
1335 | break; | ||
1336 | |||
1337 | case PCI_DEVICE_ID_MEILHAUS_ME603F: | ||
1338 | *device_name = ME6000_NAME_DEVICE_ME6000ISLE16; | ||
1339 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6000ISLE16; | ||
1340 | *driver_name = ME6000_NAME_DRIVER; | ||
1341 | break; | ||
1342 | |||
1343 | case PCI_DEVICE_ID_MEILHAUS_ME6104: | ||
1344 | *device_name = ME6000_NAME_DEVICE_ME61004; | ||
1345 | *device_description = ME6000_DESCRIPTION_DEVICE_ME61004; | ||
1346 | *driver_name = ME6000_NAME_DRIVER; | ||
1347 | break; | ||
1348 | |||
1349 | case PCI_DEVICE_ID_MEILHAUS_ME6108: | ||
1350 | *device_name = ME6000_NAME_DEVICE_ME61008; | ||
1351 | *device_description = ME6000_DESCRIPTION_DEVICE_ME61008; | ||
1352 | *driver_name = ME6000_NAME_DRIVER; | ||
1353 | break; | ||
1354 | |||
1355 | case PCI_DEVICE_ID_MEILHAUS_ME610F: | ||
1356 | *device_name = ME6000_NAME_DEVICE_ME610016; | ||
1357 | *device_description = ME6000_DESCRIPTION_DEVICE_ME610016; | ||
1358 | *driver_name = ME6000_NAME_DRIVER; | ||
1359 | break; | ||
1360 | |||
1361 | case PCI_DEVICE_ID_MEILHAUS_ME6114: | ||
1362 | *device_name = ME6000_NAME_DEVICE_ME6100I4; | ||
1363 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6100I4; | ||
1364 | *driver_name = ME6000_NAME_DRIVER; | ||
1365 | break; | ||
1366 | |||
1367 | case PCI_DEVICE_ID_MEILHAUS_ME6118: | ||
1368 | *device_name = ME6000_NAME_DEVICE_ME6100I8; | ||
1369 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6100I8; | ||
1370 | *driver_name = ME6000_NAME_DRIVER; | ||
1371 | break; | ||
1372 | |||
1373 | case PCI_DEVICE_ID_MEILHAUS_ME611F: | ||
1374 | *device_name = ME6000_NAME_DEVICE_ME6100I16; | ||
1375 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6100I16; | ||
1376 | *driver_name = ME6000_NAME_DRIVER; | ||
1377 | break; | ||
1378 | |||
1379 | case PCI_DEVICE_ID_MEILHAUS_ME6134: | ||
1380 | *device_name = ME6000_NAME_DEVICE_ME6100ISLE4; | ||
1381 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6100ISLE4; | ||
1382 | *driver_name = ME6000_NAME_DRIVER; | ||
1383 | break; | ||
1384 | |||
1385 | case PCI_DEVICE_ID_MEILHAUS_ME6138: | ||
1386 | *device_name = ME6000_NAME_DEVICE_ME6100ISLE8; | ||
1387 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6100ISLE8; | ||
1388 | *driver_name = ME6000_NAME_DRIVER; | ||
1389 | break; | ||
1390 | |||
1391 | case PCI_DEVICE_ID_MEILHAUS_ME613F: | ||
1392 | *device_name = ME6000_NAME_DEVICE_ME6100ISLE16; | ||
1393 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6100ISLE16; | ||
1394 | *driver_name = ME6000_NAME_DRIVER; | ||
1395 | break; | ||
1396 | |||
1397 | case PCI_DEVICE_ID_MEILHAUS_ME6044: | ||
1398 | *device_name = ME6000_NAME_DEVICE_ME60004DIO; | ||
1399 | *device_description = ME6000_DESCRIPTION_DEVICE_ME60004DIO; | ||
1400 | *driver_name = ME6000_NAME_DRIVER; | ||
1401 | break; | ||
1402 | |||
1403 | case PCI_DEVICE_ID_MEILHAUS_ME6048: | ||
1404 | *device_name = ME6000_NAME_DEVICE_ME60008DIO; | ||
1405 | *device_description = ME6000_DESCRIPTION_DEVICE_ME60008DIO; | ||
1406 | *driver_name = ME6000_NAME_DRIVER; | ||
1407 | break; | ||
1408 | |||
1409 | case PCI_DEVICE_ID_MEILHAUS_ME604F: | ||
1410 | *device_name = ME6000_NAME_DEVICE_ME600016DIO; | ||
1411 | *device_description = ME6000_DESCRIPTION_DEVICE_ME600016DIO; | ||
1412 | *driver_name = ME6000_NAME_DRIVER; | ||
1413 | break; | ||
1414 | |||
1415 | case PCI_DEVICE_ID_MEILHAUS_ME6054: | ||
1416 | *device_name = ME6000_NAME_DEVICE_ME6000I4DIO; | ||
1417 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6000I4DIO; | ||
1418 | *driver_name = ME6000_NAME_DRIVER; | ||
1419 | break; | ||
1420 | |||
1421 | case PCI_DEVICE_ID_MEILHAUS_ME6058: | ||
1422 | *device_name = ME6000_NAME_DEVICE_ME6000I8DIO; | ||
1423 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6000I8DIO; | ||
1424 | *driver_name = ME6000_NAME_DRIVER; | ||
1425 | break; | ||
1426 | |||
1427 | case PCI_DEVICE_ID_MEILHAUS_ME605F: | ||
1428 | *device_name = ME6000_NAME_DEVICE_ME6000I16DIO; | ||
1429 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6000I16DIO; | ||
1430 | *driver_name = ME6000_NAME_DRIVER; | ||
1431 | break; | ||
1432 | |||
1433 | case PCI_DEVICE_ID_MEILHAUS_ME6074: | ||
1434 | *device_name = ME6000_NAME_DEVICE_ME6000ISLE4DIO; | ||
1435 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6000ISLE4DIO; | ||
1436 | *driver_name = ME6000_NAME_DRIVER; | ||
1437 | break; | ||
1438 | |||
1439 | case PCI_DEVICE_ID_MEILHAUS_ME6078: | ||
1440 | *device_name = ME6000_NAME_DEVICE_ME6000ISLE8DIO; | ||
1441 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6000ISLE8DIO; | ||
1442 | *driver_name = ME6000_NAME_DRIVER; | ||
1443 | break; | ||
1444 | |||
1445 | case PCI_DEVICE_ID_MEILHAUS_ME607F: | ||
1446 | *device_name = ME6000_NAME_DEVICE_ME6000ISLE16DIO; | ||
1447 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6000ISLE16DIO; | ||
1448 | *driver_name = ME6000_NAME_DRIVER; | ||
1449 | break; | ||
1450 | |||
1451 | case PCI_DEVICE_ID_MEILHAUS_ME6144: | ||
1452 | *device_name = ME6000_NAME_DEVICE_ME61004DIO; | ||
1453 | *device_description = ME6000_DESCRIPTION_DEVICE_ME61004DIO; | ||
1454 | *driver_name = ME6000_NAME_DRIVER; | ||
1455 | break; | ||
1456 | |||
1457 | case PCI_DEVICE_ID_MEILHAUS_ME6148: | ||
1458 | *device_name = ME6000_NAME_DEVICE_ME61008DIO; | ||
1459 | *device_description = ME6000_DESCRIPTION_DEVICE_ME61008DIO; | ||
1460 | *driver_name = ME6000_NAME_DRIVER; | ||
1461 | break; | ||
1462 | |||
1463 | case PCI_DEVICE_ID_MEILHAUS_ME614F: | ||
1464 | *device_name = ME6000_NAME_DEVICE_ME610016DIO; | ||
1465 | *device_description = ME6000_DESCRIPTION_DEVICE_ME610016DIO; | ||
1466 | *driver_name = ME6000_NAME_DRIVER; | ||
1467 | break; | ||
1468 | |||
1469 | case PCI_DEVICE_ID_MEILHAUS_ME6154: | ||
1470 | *device_name = ME6000_NAME_DEVICE_ME6100I4DIO; | ||
1471 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6100I4DIO; | ||
1472 | *driver_name = ME6000_NAME_DRIVER; | ||
1473 | break; | ||
1474 | |||
1475 | case PCI_DEVICE_ID_MEILHAUS_ME6158: | ||
1476 | *device_name = ME6000_NAME_DEVICE_ME6100I8DIO; | ||
1477 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6100I8DIO; | ||
1478 | *driver_name = ME6000_NAME_DRIVER; | ||
1479 | break; | ||
1480 | |||
1481 | case PCI_DEVICE_ID_MEILHAUS_ME615F: | ||
1482 | *device_name = ME6000_NAME_DEVICE_ME6100I16DIO; | ||
1483 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6100I16DIO; | ||
1484 | *driver_name = ME6000_NAME_DRIVER; | ||
1485 | break; | ||
1486 | |||
1487 | case PCI_DEVICE_ID_MEILHAUS_ME6174: | ||
1488 | *device_name = ME6000_NAME_DEVICE_ME6100ISLE4DIO; | ||
1489 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6100ISLE4DIO; | ||
1490 | *driver_name = ME6000_NAME_DRIVER; | ||
1491 | break; | ||
1492 | |||
1493 | case PCI_DEVICE_ID_MEILHAUS_ME6178: | ||
1494 | *device_name = ME6000_NAME_DEVICE_ME6100ISLE8DIO; | ||
1495 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6100ISLE8DIO; | ||
1496 | *driver_name = ME6000_NAME_DRIVER; | ||
1497 | break; | ||
1498 | |||
1499 | case PCI_DEVICE_ID_MEILHAUS_ME617F: | ||
1500 | *device_name = ME6000_NAME_DEVICE_ME6100ISLE16DIO; | ||
1501 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6100ISLE16DIO; | ||
1502 | *driver_name = ME6000_NAME_DRIVER; | ||
1503 | break; | ||
1504 | |||
1505 | case PCI_DEVICE_ID_MEILHAUS_ME6259: | ||
1506 | *device_name = ME6000_NAME_DEVICE_ME6200I9DIO; | ||
1507 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6200I9DIO; | ||
1508 | *driver_name = ME6000_NAME_DRIVER; | ||
1509 | break; | ||
1510 | |||
1511 | case PCI_DEVICE_ID_MEILHAUS_ME6359: | ||
1512 | *device_name = ME6000_NAME_DEVICE_ME6300I9DIO; | ||
1513 | *device_description = ME6000_DESCRIPTION_DEVICE_ME6300I9DIO; | ||
1514 | *driver_name = ME6000_NAME_DRIVER; | ||
1515 | break; | ||
1516 | |||
1517 | case PCI_DEVICE_ID_MEILHAUS_ME0630: | ||
1518 | *device_name = ME0600_NAME_DEVICE_ME0630; | ||
1519 | *device_description = ME0600_DESCRIPTION_DEVICE_ME0630; | ||
1520 | *driver_name = ME0600_NAME_DRIVER; | ||
1521 | break; | ||
1522 | |||
1523 | case PCI_DEVICE_ID_MEILHAUS_ME8100_A: | ||
1524 | *device_name = ME8100_NAME_DEVICE_ME8100A; | ||
1525 | *device_description = ME8100_DESCRIPTION_DEVICE_ME8100A; | ||
1526 | *driver_name = ME8100_NAME_DRIVER; | ||
1527 | break; | ||
1528 | |||
1529 | case PCI_DEVICE_ID_MEILHAUS_ME8100_B: | ||
1530 | *device_name = ME8100_NAME_DEVICE_ME8100B; | ||
1531 | *device_description = ME8100_DESCRIPTION_DEVICE_ME8100B; | ||
1532 | *driver_name = ME8100_NAME_DRIVER; | ||
1533 | break; | ||
1534 | |||
1535 | case PCI_DEVICE_ID_MEILHAUS_ME8200_A: | ||
1536 | *device_name = ME8200_NAME_DEVICE_ME8200A; | ||
1537 | *device_description = ME8200_DESCRIPTION_DEVICE_ME8200A; | ||
1538 | *driver_name = ME8200_NAME_DRIVER; | ||
1539 | break; | ||
1540 | |||
1541 | case PCI_DEVICE_ID_MEILHAUS_ME8200_B: | ||
1542 | *device_name = ME8200_NAME_DEVICE_ME8200B; | ||
1543 | *device_description = ME8200_DESCRIPTION_DEVICE_ME8200B; | ||
1544 | *driver_name = ME8200_NAME_DRIVER; | ||
1545 | break; | ||
1546 | |||
1547 | case PCI_DEVICE_ID_MEILHAUS_ME0940: | ||
1548 | *device_name = ME0900_NAME_DEVICE_ME0940; | ||
1549 | *device_description = ME0900_DESCRIPTION_DEVICE_ME0940; | ||
1550 | *driver_name = ME0900_NAME_DRIVER; | ||
1551 | break; | ||
1552 | |||
1553 | case PCI_DEVICE_ID_MEILHAUS_ME0950: | ||
1554 | *device_name = ME0900_NAME_DEVICE_ME0950; | ||
1555 | *device_description = ME0900_DESCRIPTION_DEVICE_ME0950; | ||
1556 | *driver_name = ME0900_NAME_DRIVER; | ||
1557 | break; | ||
1558 | |||
1559 | case PCI_DEVICE_ID_MEILHAUS_ME0960: | ||
1560 | *device_name = ME0900_NAME_DEVICE_ME0960; | ||
1561 | *device_description = ME0900_DESCRIPTION_DEVICE_ME0960; | ||
1562 | *driver_name = ME0900_NAME_DRIVER; | ||
1563 | break; | ||
1564 | /* | ||
1565 | case USB_DEVICE_ID_MEPHISTO_S1: | ||
1566 | *device_name = MEPHISTO_S1_NAME_DEVICE; | ||
1567 | *device_description = MEPHISTO_S1_DESCRIPTION_DEVICE; | ||
1568 | *driver_name = MEPHISTO_S1_NAME_DRIVER; | ||
1569 | break; | ||
1570 | */ | ||
1571 | default: | ||
1572 | *device_name = EMPTY_NAME_DEVICE; | ||
1573 | *device_description = EMPTY_DESCRIPTION_DEVICE; | ||
1574 | *driver_name = EMPTY_NAME_DRIVER; | ||
1575 | |||
1576 | PERROR("Invalid device id.\n"); | ||
1577 | |||
1578 | return 1; | ||
1579 | } | ||
1580 | |||
1581 | return 0; | ||
1582 | } | ||
1583 | |||
1584 | int me_device_pci_init(me_device_t * me_device, struct pci_dev *pci_device) | ||
1585 | { | ||
1586 | int err; | ||
1587 | int i; | ||
1588 | |||
1589 | PDEBUG("executed.\n"); | ||
1590 | |||
1591 | // Initialize device list head. | ||
1592 | INIT_LIST_HEAD(&me_device->list); | ||
1593 | |||
1594 | // Initialize device description strings. | ||
1595 | err = get_device_descriptions(pci_device->device, | ||
1596 | &me_device->device_name, | ||
1597 | &me_device->device_description, | ||
1598 | &me_device->driver_name); | ||
1599 | |||
1600 | if (err) { | ||
1601 | PERROR("Cannot initialize device description strings.\n"); | ||
1602 | return 1; | ||
1603 | } | ||
1604 | // Enable the pci device. | ||
1605 | err = pci_enable_device(pci_device); | ||
1606 | |||
1607 | if (err < 0) { | ||
1608 | PERROR("Cannot enable PCI device.\n"); | ||
1609 | return 1; | ||
1610 | } | ||
1611 | // Request the PCI register regions. | ||
1612 | err = pci_request_regions(pci_device, me_device->device_name); | ||
1613 | |||
1614 | if (err < 0) { | ||
1615 | PERROR("Cannot request PCI regions.\n"); | ||
1616 | goto ERROR_0; | ||
1617 | } | ||
1618 | // The bus carrying the device is a PCI bus. | ||
1619 | me_device->bus_type = ME_BUS_TYPE_PCI; | ||
1620 | |||
1621 | // Store the PCI information for later usage. | ||
1622 | me_device->info.pci.pci_device = pci_device; | ||
1623 | |||
1624 | // Get PCI register bases and sizes. | ||
1625 | for (i = 0; i < 6; i++) { | ||
1626 | me_device->info.pci.reg_bases[i] = | ||
1627 | pci_resource_start(pci_device, i); | ||
1628 | me_device->info.pci.reg_sizes[i] = | ||
1629 | pci_resource_len(pci_device, i); | ||
1630 | } | ||
1631 | |||
1632 | // Get the PCI location. | ||
1633 | me_device->info.pci.pci_bus_no = pci_device->bus->number; | ||
1634 | me_device->info.pci.pci_dev_no = PCI_SLOT(pci_device->devfn); | ||
1635 | me_device->info.pci.pci_func_no = PCI_FUNC(pci_device->devfn); | ||
1636 | |||
1637 | // Get Meilhaus specific device information. | ||
1638 | me_device->info.pci.vendor_id = pci_device->vendor; | ||
1639 | me_device->info.pci.device_id = pci_device->device; | ||
1640 | pci_read_config_byte(pci_device, 0x08, | ||
1641 | &me_device->info.pci.hw_revision); | ||
1642 | pci_read_config_dword(pci_device, 0x2C, &me_device->info.pci.serial_no); | ||
1643 | |||
1644 | // Get the interrupt request number. | ||
1645 | me_device->irq = pci_device->irq; | ||
1646 | |||
1647 | // Initialize device lock instance. | ||
1648 | err = me_dlock_init(&me_device->dlock); | ||
1649 | |||
1650 | if (err) { | ||
1651 | PERROR("Cannot initialize device lock instance.\n"); | ||
1652 | goto ERROR_1; | ||
1653 | } | ||
1654 | // Initialize subdevice list instance. | ||
1655 | me_slist_init(&me_device->slist); | ||
1656 | |||
1657 | if (err) { | ||
1658 | PERROR("Cannot initialize subdevice list instance.\n"); | ||
1659 | goto ERROR_2; | ||
1660 | } | ||
1661 | // Initialize method pointers. | ||
1662 | me_device->me_device_io_irq_start = me_device_io_irq_start; | ||
1663 | me_device->me_device_io_irq_wait = me_device_io_irq_wait; | ||
1664 | me_device->me_device_io_irq_stop = me_device_io_irq_stop; | ||
1665 | me_device->me_device_io_reset_device = me_device_io_reset_device; | ||
1666 | me_device->me_device_io_reset_subdevice = me_device_io_reset_subdevice; | ||
1667 | me_device->me_device_io_single_config = me_device_io_single_config; | ||
1668 | me_device->me_device_io_single_read = me_device_io_single_read; | ||
1669 | me_device->me_device_io_single_write = me_device_io_single_write; | ||
1670 | me_device->me_device_io_stream_config = me_device_io_stream_config; | ||
1671 | me_device->me_device_io_stream_new_values = | ||
1672 | me_device_io_stream_new_values; | ||
1673 | me_device->me_device_io_stream_read = me_device_io_stream_read; | ||
1674 | me_device->me_device_io_stream_start = me_device_io_stream_start; | ||
1675 | me_device->me_device_io_stream_status = me_device_io_stream_status; | ||
1676 | me_device->me_device_io_stream_stop = me_device_io_stream_stop; | ||
1677 | me_device->me_device_io_stream_write = me_device_io_stream_write; | ||
1678 | me_device->me_device_lock_device = me_device_lock_device; | ||
1679 | me_device->me_device_lock_subdevice = me_device_lock_subdevice; | ||
1680 | me_device->me_device_query_description_device = | ||
1681 | me_device_query_description_device; | ||
1682 | me_device->me_device_query_info_device = me_device_query_info_device; | ||
1683 | me_device->me_device_query_name_device = me_device_query_name_device; | ||
1684 | me_device->me_device_query_name_device_driver = | ||
1685 | me_device_query_name_device_driver; | ||
1686 | me_device->me_device_query_number_subdevices = | ||
1687 | me_device_query_number_subdevices; | ||
1688 | me_device->me_device_query_number_channels = | ||
1689 | me_device_query_number_channels; | ||
1690 | me_device->me_device_query_number_ranges = | ||
1691 | me_device_query_number_ranges; | ||
1692 | me_device->me_device_query_range_by_min_max = | ||
1693 | me_device_query_range_by_min_max; | ||
1694 | me_device->me_device_query_range_info = me_device_query_range_info; | ||
1695 | me_device->me_device_query_subdevice_by_type = | ||
1696 | me_device_query_subdevice_by_type; | ||
1697 | me_device->me_device_query_subdevice_type = | ||
1698 | me_device_query_subdevice_type; | ||
1699 | me_device->me_device_query_subdevice_caps = | ||
1700 | me_device_query_subdevice_caps; | ||
1701 | me_device->me_device_query_subdevice_caps_args = | ||
1702 | me_device_query_subdevice_caps_args; | ||
1703 | me_device->me_device_query_timer = me_device_query_timer; | ||
1704 | me_device->me_device_query_version_device_driver = | ||
1705 | me_device_query_version_device_driver; | ||
1706 | me_device->me_device_config_load = me_device_config_load; | ||
1707 | me_device->me_device_destructor = me_device_destructor; | ||
1708 | |||
1709 | return 0; | ||
1710 | |||
1711 | ERROR_0: | ||
1712 | me_dlock_deinit(&me_device->dlock); | ||
1713 | |||
1714 | ERROR_1: | ||
1715 | pci_release_regions(pci_device); | ||
1716 | |||
1717 | ERROR_2: | ||
1718 | pci_disable_device(pci_device); | ||
1719 | |||
1720 | return 1; | ||
1721 | } | ||
1722 | |||
1723 | void me_device_deinit(me_device_t * me_device) | ||
1724 | { | ||
1725 | PDEBUG("executed.\n"); | ||
1726 | |||
1727 | me_slist_deinit(&me_device->slist); | ||
1728 | me_dlock_deinit(&me_device->dlock); | ||
1729 | |||
1730 | if (me_device->bus_type == ME_BUS_TYPE_PCI) { | ||
1731 | pci_release_regions(me_device->info.pci.pci_device); | ||
1732 | pci_disable_device(me_device->info.pci.pci_device); | ||
1733 | } | ||
1734 | /* | ||
1735 | else | ||
1736 | { | ||
1737 | // Must be an USB device. | ||
1738 | } | ||
1739 | */ | ||
1740 | } | ||
diff --git a/drivers/staging/meilhaus/medevice.h b/drivers/staging/meilhaus/medevice.h new file mode 100644 index 000000000000..25da82883e1f --- /dev/null +++ b/drivers/staging/meilhaus/medevice.h | |||
@@ -0,0 +1,304 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
3 | * | ||
4 | * Source File : medevice.h | ||
5 | * Author : GG (Guenter Gebhardt) <support@meilhaus.de> | ||
6 | */ | ||
7 | |||
8 | #ifndef _MEDEVICE_H_ | ||
9 | #define _MEDEVICE_H_ | ||
10 | |||
11 | #ifndef KBUILD_MODNAME | ||
12 | # define KBUILD_MODNAME KBUILD_STR(memain) | ||
13 | #endif | ||
14 | |||
15 | #include <linux/pci.h> | ||
16 | //#include <linux/usb.h> | ||
17 | #include <linux/fs.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | |||
20 | #include "metypes.h" | ||
21 | #include "meslist.h" | ||
22 | #include "medlock.h" | ||
23 | |||
24 | #ifdef __KERNEL__ | ||
25 | |||
26 | /** | ||
27 | * @brief Defines a pointer type to a PCI constructor function. | ||
28 | */ | ||
29 | typedef struct me_device *(*me_pci_constructor_t) (struct pci_dev *); | ||
30 | |||
31 | /** | ||
32 | * @brief Defines a pointer type to a ME-4000 PCI constructor function. | ||
33 | */ | ||
34 | #ifdef BOSCH | ||
35 | typedef struct me_device *(*me_bosch_constructor_t) (struct pci_dev *, | ||
36 | int me_bosch_fw); | ||
37 | #endif | ||
38 | |||
39 | /** | ||
40 | * @brief Defines a pointer type to a USB constructor function. | ||
41 | */ | ||
42 | //typedef struct me_device *(*me_usb_constructor_t)(struct usb_interface *); | ||
43 | |||
44 | /** | ||
45 | * @brief Defines a pointer type to the dummy constructor function. | ||
46 | */ | ||
47 | typedef struct me_device *(*me_dummy_constructor_t) (unsigned short vendor_id, | ||
48 | unsigned short device_id, | ||
49 | unsigned int serial_no, | ||
50 | int bus_type, | ||
51 | int bus_no, | ||
52 | int dev_no, int func_no); | ||
53 | |||
54 | //extern me_usb_constructor_t mephisto_s1_constructor __attribute__ ((weak)); | ||
55 | |||
56 | /** | ||
57 | * @brief Holds the PCI device information. | ||
58 | */ | ||
59 | typedef struct me_pci_info { | ||
60 | struct pci_dev *pci_device; /**< Kernel PCI device structure. */ | ||
61 | uint32_t reg_bases[6]; /**< The base adresses of the PCI bars. */ | ||
62 | uint32_t reg_sizes[6]; /**< The sizes of the PCI bars. */ | ||
63 | |||
64 | uint32_t pci_bus_no; /**< PCI bus number. */ | ||
65 | uint32_t pci_dev_no; /**< PCI device number. */ | ||
66 | uint32_t pci_func_no; /**< PCI function number. */ | ||
67 | |||
68 | uint16_t vendor_id; /**< Meilhaus PCI vendor id. */ | ||
69 | uint16_t device_id; /**< Meilhaus device id. */ | ||
70 | uint8_t hw_revision; /**< Hardware revision of the device. */ | ||
71 | uint32_t serial_no; /**< Serial number of the device. */ | ||
72 | } me_pci_info_t; | ||
73 | |||
74 | /** | ||
75 | * @brief Holds the USB device information. | ||
76 | */ | ||
77 | //typedef struct me_usb_info { | ||
78 | //} me_usb_info_t; | ||
79 | |||
80 | /** | ||
81 | * @brief The Meilhaus device base class structure. | ||
82 | */ | ||
83 | typedef struct me_device { | ||
84 | /* Attributes */ | ||
85 | struct list_head list; /**< Enables the device to be added to a dynamic list. */ | ||
86 | // int magic; /**< The magic number of the structure. */ | ||
87 | |||
88 | int bus_type; /**< The descriminator for the union. */ | ||
89 | union { | ||
90 | me_pci_info_t pci; /**< PCI specific device information. */ | ||
91 | // me_usb_info_t usb; /**< USB specific device information. */ | ||
92 | } info; /**< Holds the device information. */ | ||
93 | |||
94 | int irq; /**< The irq assigned to this device. */ | ||
95 | |||
96 | me_dlock_t dlock; /**< The device locking structure. */ | ||
97 | me_slist_t slist; /**< The container holding all subdevices belonging to this device. */ | ||
98 | |||
99 | char *device_name; /**< The name of the Meilhaus device. */ | ||
100 | char *device_description; /**< The description of the Meilhaus device. */ | ||
101 | char *driver_name; /**< The name of the device driver module supporting the device family. */ | ||
102 | |||
103 | /* Methods */ | ||
104 | int (*me_device_io_irq_start) (struct me_device * device, | ||
105 | struct file * filep, | ||
106 | int subdevice, | ||
107 | int channel, | ||
108 | int irq_source, | ||
109 | int irq_edge, int irq_arg, int flags); | ||
110 | |||
111 | int (*me_device_io_irq_wait) (struct me_device * device, | ||
112 | struct file * filep, | ||
113 | int subdevice, | ||
114 | int channel, | ||
115 | int *irq_count, | ||
116 | int *value, int time_out, int flags); | ||
117 | |||
118 | int (*me_device_io_irq_stop) (struct me_device * device, | ||
119 | struct file * filep, | ||
120 | int subdevice, int channel, int flags); | ||
121 | |||
122 | int (*me_device_io_reset_device) (struct me_device * device, | ||
123 | struct file * filep, int flags); | ||
124 | |||
125 | int (*me_device_io_reset_subdevice) (struct me_device * device, | ||
126 | struct file * filep, | ||
127 | int subdevice, int flags); | ||
128 | |||
129 | int (*me_device_io_single_config) (struct me_device * device, | ||
130 | struct file * filep, | ||
131 | int subdevice, | ||
132 | int channel, | ||
133 | int single_config, | ||
134 | int ref, | ||
135 | int trig_chan, | ||
136 | int trig_type, | ||
137 | int trig_edge, int flags); | ||
138 | |||
139 | int (*me_device_io_single_read) (struct me_device * device, | ||
140 | struct file * filep, | ||
141 | int subdevice, | ||
142 | int channel, | ||
143 | int *value, int time_out, int flags); | ||
144 | |||
145 | int (*me_device_io_single_write) (struct me_device * device, | ||
146 | struct file * filep, | ||
147 | int subdevice, | ||
148 | int channel, | ||
149 | int value, int time_out, int flags); | ||
150 | |||
151 | int (*me_device_io_stream_config) (struct me_device * device, | ||
152 | struct file * filep, | ||
153 | int subdevice, | ||
154 | meIOStreamConfig_t * config_list, | ||
155 | int count, | ||
156 | meIOStreamTrigger_t * trigger, | ||
157 | int fifo_irq_threshold, int flags); | ||
158 | |||
159 | int (*me_device_io_stream_new_values) (struct me_device * device, | ||
160 | struct file * filep, | ||
161 | int subdevice, | ||
162 | int time_out, | ||
163 | int *count, int flags); | ||
164 | |||
165 | int (*me_device_io_stream_read) (struct me_device * device, | ||
166 | struct file * filep, | ||
167 | int subdevice, | ||
168 | int read_mode, | ||
169 | int *values, int *count, int flags); | ||
170 | |||
171 | int (*me_device_io_stream_start) (struct me_device * device, | ||
172 | struct file * filep, | ||
173 | int subdevice, | ||
174 | int start_mode, | ||
175 | int time_out, int flags); | ||
176 | |||
177 | int (*me_device_io_stream_status) (struct me_device * device, | ||
178 | struct file * filep, | ||
179 | int subdevice, | ||
180 | int wait, | ||
181 | int *status, int *count, int flags); | ||
182 | |||
183 | int (*me_device_io_stream_stop) (struct me_device * device, | ||
184 | struct file * filep, | ||
185 | int subdevice, | ||
186 | int stop_mode, int flags); | ||
187 | |||
188 | int (*me_device_io_stream_write) (struct me_device * device, | ||
189 | struct file * filep, | ||
190 | int subdevice, | ||
191 | int write_mode, | ||
192 | int *values, int *count, int flags); | ||
193 | |||
194 | int (*me_device_lock_device) (struct me_device * device, | ||
195 | struct file * filep, int lock, int flags); | ||
196 | |||
197 | int (*me_device_lock_subdevice) (struct me_device * device, | ||
198 | struct file * filep, | ||
199 | int subdevice, int lock, int flags); | ||
200 | |||
201 | int (*me_device_query_description_device) (struct me_device * device, | ||
202 | char **description); | ||
203 | |||
204 | int (*me_device_query_info_device) (struct me_device * device, | ||
205 | int *vendor_id, | ||
206 | int *device_id, | ||
207 | int *serial_no, | ||
208 | int *bus_type, | ||
209 | int *bus_no, | ||
210 | int *dev_no, | ||
211 | int *func_no, int *plugged); | ||
212 | |||
213 | int (*me_device_query_name_device) (struct me_device * device, | ||
214 | char **name); | ||
215 | |||
216 | int (*me_device_query_name_device_driver) (struct me_device * device, | ||
217 | char **name); | ||
218 | |||
219 | int (*me_device_query_number_subdevices) (struct me_device * device, | ||
220 | int *number); | ||
221 | |||
222 | int (*me_device_query_number_channels) (struct me_device * device, | ||
223 | int subdevice, int *number); | ||
224 | |||
225 | int (*me_device_query_number_ranges) (struct me_device * device, | ||
226 | int subdevice, | ||
227 | int unit, int *count); | ||
228 | |||
229 | int (*me_device_query_range_by_min_max) (struct me_device * device, | ||
230 | int subdevice, | ||
231 | int unit, | ||
232 | int *min, | ||
233 | int *max, | ||
234 | int *maxdata, int *range); | ||
235 | |||
236 | int (*me_device_query_range_info) (struct me_device * device, | ||
237 | int subdevice, | ||
238 | int range, | ||
239 | int *unit, | ||
240 | int *min, int *max, int *maxdata); | ||
241 | |||
242 | int (*me_device_query_subdevice_by_type) (struct me_device * device, | ||
243 | int start_subdevice, | ||
244 | int type, | ||
245 | int subtype, int *subdevice); | ||
246 | |||
247 | int (*me_device_query_subdevice_type) (struct me_device * device, | ||
248 | int subdevice, | ||
249 | int *type, int *subtype); | ||
250 | |||
251 | int (*me_device_query_subdevice_caps) (struct me_device * device, | ||
252 | int subdevice, int *caps); | ||
253 | |||
254 | int (*me_device_query_subdevice_caps_args) (struct me_device * device, | ||
255 | int subdevice, | ||
256 | int cap, | ||
257 | int *args, int count); | ||
258 | |||
259 | int (*me_device_query_timer) (struct me_device * device, | ||
260 | int subdevice, | ||
261 | int timer, | ||
262 | int *base_frequency, | ||
263 | uint64_t * min_ticks, | ||
264 | uint64_t * max_ticks); | ||
265 | |||
266 | int (*me_device_query_version_device_driver) (struct me_device * device, | ||
267 | int *version); | ||
268 | |||
269 | int (*me_device_config_load) (struct me_device * device, | ||
270 | struct file * filep, | ||
271 | me_cfg_device_entry_t * config); | ||
272 | |||
273 | void (*me_device_destructor) (struct me_device * device); | ||
274 | } me_device_t; | ||
275 | |||
276 | /** | ||
277 | * @brief Initializes a PCI device base class structure. | ||
278 | * | ||
279 | * @param pci_device The PCI device context as handed over by kernel. | ||
280 | * | ||
281 | * @return 0 on success. | ||
282 | */ | ||
283 | int me_device_pci_init(me_device_t * me_device, struct pci_dev *pci_device); | ||
284 | |||
285 | /** | ||
286 | * @brief Initializes a USB device base class structure. | ||
287 | * | ||
288 | * @param usb_interface The USB device interface as handed over by kernel. | ||
289 | * | ||
290 | * @return 0 on success. | ||
291 | */ | ||
292 | //int me_device_usb_init(me_device_t *me_device, struct usb_interface *interface); | ||
293 | |||
294 | /** | ||
295 | * @brief Deinitializes a device base class structure and frees any previously | ||
296 | * requested resources related with this structure. It also frees any subdevice | ||
297 | * instance hold by the subdevice list. | ||
298 | * | ||
299 | * @param me_device The device class to deinitialize. | ||
300 | */ | ||
301 | void me_device_deinit(me_device_t * me_device); | ||
302 | |||
303 | #endif | ||
304 | #endif | ||
diff --git a/drivers/staging/meilhaus/medlist.c b/drivers/staging/meilhaus/medlist.c new file mode 100644 index 000000000000..ef4e36955dc8 --- /dev/null +++ b/drivers/staging/meilhaus/medlist.c | |||
@@ -0,0 +1,127 @@ | |||
1 | /** | ||
2 | * @file me_dlist.c | ||
3 | * | ||
4 | * @brief Implements the device list class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #include "meerror.h" | ||
28 | #include "medefines.h" | ||
29 | |||
30 | #include "medlist.h" | ||
31 | #include "medebug.h" | ||
32 | |||
33 | int me_dlist_query_number_devices(struct me_dlist *dlist, int *number) | ||
34 | { | ||
35 | PDEBUG_LOCKS("called.\n"); | ||
36 | *number = dlist->n; | ||
37 | return ME_ERRNO_SUCCESS; | ||
38 | } | ||
39 | |||
40 | unsigned int me_dlist_get_number_devices(struct me_dlist *dlist) | ||
41 | { | ||
42 | PDEBUG_LOCKS("called.\n"); | ||
43 | return dlist->n; | ||
44 | } | ||
45 | |||
46 | me_device_t *me_dlist_get_device(struct me_dlist * dlist, unsigned int index) | ||
47 | { | ||
48 | |||
49 | struct list_head *pos; | ||
50 | me_device_t *device = NULL; | ||
51 | unsigned int i = 0; | ||
52 | |||
53 | PDEBUG_LOCKS("called.\n"); | ||
54 | |||
55 | if (index >= dlist->n) { | ||
56 | PERROR("Index out of range.\n"); | ||
57 | return NULL; | ||
58 | } | ||
59 | |||
60 | list_for_each(pos, &dlist->head) { | ||
61 | if (i == index) { | ||
62 | device = list_entry(pos, me_device_t, list); | ||
63 | break; | ||
64 | } | ||
65 | |||
66 | ++i; | ||
67 | } | ||
68 | |||
69 | return device; | ||
70 | } | ||
71 | |||
72 | void me_dlist_add_device_tail(struct me_dlist *dlist, me_device_t * device) | ||
73 | { | ||
74 | PDEBUG_LOCKS("called.\n"); | ||
75 | |||
76 | list_add_tail(&device->list, &dlist->head); | ||
77 | ++dlist->n; | ||
78 | } | ||
79 | |||
80 | me_device_t *me_dlist_del_device_tail(struct me_dlist *dlist) | ||
81 | { | ||
82 | |||
83 | struct list_head *last; | ||
84 | me_device_t *device; | ||
85 | |||
86 | PDEBUG_LOCKS("called.\n"); | ||
87 | |||
88 | if (list_empty(&dlist->head)) | ||
89 | return NULL; | ||
90 | |||
91 | last = dlist->head.prev; | ||
92 | |||
93 | device = list_entry(last, me_device_t, list); | ||
94 | |||
95 | list_del(last); | ||
96 | |||
97 | --dlist->n; | ||
98 | |||
99 | return device; | ||
100 | } | ||
101 | |||
102 | int me_dlist_init(me_dlist_t * dlist) | ||
103 | { | ||
104 | PDEBUG_LOCKS("called.\n"); | ||
105 | |||
106 | INIT_LIST_HEAD(&dlist->head); | ||
107 | dlist->n = 0; | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | void me_dlist_deinit(me_dlist_t * dlist) | ||
112 | { | ||
113 | |||
114 | struct list_head *s; | ||
115 | me_device_t *device; | ||
116 | |||
117 | PDEBUG_LOCKS("called.\n"); | ||
118 | |||
119 | while (!list_empty(&dlist->head)) { | ||
120 | s = dlist->head.next; | ||
121 | list_del(s); | ||
122 | device = list_entry(s, me_device_t, list); | ||
123 | device->me_device_destructor(device); | ||
124 | } | ||
125 | |||
126 | dlist->n = 0; | ||
127 | } | ||
diff --git a/drivers/staging/meilhaus/medlist.h b/drivers/staging/meilhaus/medlist.h new file mode 100644 index 000000000000..091c11e48ed2 --- /dev/null +++ b/drivers/staging/meilhaus/medlist.h | |||
@@ -0,0 +1,91 @@ | |||
1 | /** | ||
2 | * @file me_dlist.h | ||
3 | * | ||
4 | * @brief Provides the device list class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | #ifndef _ME_DLIST_H_ | ||
10 | #define _ME_DLIST_H_ | ||
11 | |||
12 | #include <linux/list.h> | ||
13 | |||
14 | #include "medevice.h" | ||
15 | |||
16 | #ifdef __KERNEL__ | ||
17 | |||
18 | /** | ||
19 | * @brief The device list container. | ||
20 | */ | ||
21 | typedef struct me_dlist { | ||
22 | struct list_head head; /**< The head of the internal list. */ | ||
23 | unsigned int n; /**< The number of devices in the list. */ | ||
24 | } me_dlist_t; | ||
25 | |||
26 | /** | ||
27 | * @brief Queries the number of devices currently inside the list. | ||
28 | * | ||
29 | * @param dlist The device list to query. | ||
30 | * @param[out] number The number of devices. | ||
31 | * | ||
32 | * @return ME-iDS error code. | ||
33 | */ | ||
34 | int me_dlist_query_number_devices(struct me_dlist *dlist, int *number); | ||
35 | |||
36 | /** | ||
37 | * @brief Returns the number of devices currently inside the list. | ||
38 | * | ||
39 | * @param dlist The device list to query. | ||
40 | * | ||
41 | * @return The number of devices in the list. | ||
42 | */ | ||
43 | unsigned int me_dlist_get_number_devices(struct me_dlist *dlist); | ||
44 | |||
45 | /** | ||
46 | * @brief Get a device by index. | ||
47 | * | ||
48 | * @param dlist The device list to query. | ||
49 | * @param index The index of the device to get in the list. | ||
50 | * | ||
51 | * @return The device at index if available.\n | ||
52 | * NULL if the index is out of range. | ||
53 | */ | ||
54 | me_device_t *me_dlist_get_device(struct me_dlist *dlist, unsigned int index); | ||
55 | |||
56 | /** | ||
57 | * @brief Adds a device to the tail of the list. | ||
58 | * | ||
59 | * @param dlist The device list to add a device to. | ||
60 | * @param device The device to add to the list. | ||
61 | */ | ||
62 | void me_dlist_add_device_tail(struct me_dlist *dlist, me_device_t * device); | ||
63 | |||
64 | /** | ||
65 | * @brief Removes a device from the tail of the list. | ||
66 | * | ||
67 | * @param dlist The device list. | ||
68 | * | ||
69 | * @return Pointer to the removed subdeivce.\n | ||
70 | * NULL in cases where the list was empty. | ||
71 | */ | ||
72 | me_device_t *me_dlist_del_device_tail(struct me_dlist *dlist); | ||
73 | |||
74 | /** | ||
75 | * @brief Initializes a device list structure. | ||
76 | * | ||
77 | * @param lock The device list structure to initialize. | ||
78 | * @return 0 on success. | ||
79 | */ | ||
80 | int me_dlist_init(me_dlist_t * dlist); | ||
81 | |||
82 | /** | ||
83 | * @brief Deinitializes a device list structure and destructs every device in it. | ||
84 | * | ||
85 | * @param dlist The device list structure to deinitialize. | ||
86 | * @return 0 on success. | ||
87 | */ | ||
88 | void me_dlist_deinit(me_dlist_t * dlist); | ||
89 | |||
90 | #endif | ||
91 | #endif | ||
diff --git a/drivers/staging/meilhaus/medlock.c b/drivers/staging/meilhaus/medlock.c new file mode 100644 index 000000000000..f649e3da4f05 --- /dev/null +++ b/drivers/staging/meilhaus/medlock.c | |||
@@ -0,0 +1,195 @@ | |||
1 | /** | ||
2 | * @file medlock.c | ||
3 | * | ||
4 | * @brief Implements the device lock class. | ||
5 | * @note Copyright (C) 2006 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #include <linux/spinlock.h> | ||
28 | |||
29 | #include "medefines.h" | ||
30 | #include "meerror.h" | ||
31 | |||
32 | #include "medebug.h" | ||
33 | #include "meslist.h" | ||
34 | #include "mesubdevice.h" | ||
35 | #include "medlock.h" | ||
36 | |||
37 | int me_dlock_enter(struct me_dlock *dlock, struct file *filep) | ||
38 | { | ||
39 | PDEBUG_LOCKS("executed.\n"); | ||
40 | |||
41 | spin_lock(&dlock->spin_lock); | ||
42 | |||
43 | if ((dlock->filep) != NULL && (dlock->filep != filep)) { | ||
44 | PERROR("Device is locked by another process.\n"); | ||
45 | spin_unlock(&dlock->spin_lock); | ||
46 | return ME_ERRNO_LOCKED; | ||
47 | } | ||
48 | |||
49 | dlock->count++; | ||
50 | |||
51 | spin_unlock(&dlock->spin_lock); | ||
52 | |||
53 | return ME_ERRNO_SUCCESS; | ||
54 | } | ||
55 | |||
56 | int me_dlock_exit(struct me_dlock *dlock, struct file *filep) | ||
57 | { | ||
58 | PDEBUG_LOCKS("executed.\n"); | ||
59 | |||
60 | spin_lock(&dlock->spin_lock); | ||
61 | dlock->count--; | ||
62 | spin_unlock(&dlock->spin_lock); | ||
63 | |||
64 | return ME_ERRNO_SUCCESS; | ||
65 | } | ||
66 | |||
67 | int me_dlock_lock(struct me_dlock *dlock, | ||
68 | struct file *filep, int lock, int flags, me_slist_t * slist) | ||
69 | { | ||
70 | int err = ME_ERRNO_SUCCESS; | ||
71 | int i; | ||
72 | me_subdevice_t *subdevice; | ||
73 | |||
74 | PDEBUG_LOCKS("executed.\n"); | ||
75 | |||
76 | spin_lock(&dlock->spin_lock); | ||
77 | |||
78 | switch (lock) { | ||
79 | |||
80 | case ME_LOCK_RELEASE: | ||
81 | if ((dlock->filep == filep) || (dlock->filep == NULL)) { | ||
82 | dlock->filep = NULL; | ||
83 | |||
84 | /* Unlock all possibly locked subdevices. */ | ||
85 | |||
86 | for (i = 0; i < me_slist_get_number_subdevices(slist); | ||
87 | i++) { | ||
88 | subdevice = me_slist_get_subdevice(slist, i); | ||
89 | |||
90 | if (subdevice) | ||
91 | err = | ||
92 | subdevice-> | ||
93 | me_subdevice_lock_subdevice | ||
94 | (subdevice, filep, ME_LOCK_RELEASE, | ||
95 | flags); | ||
96 | else | ||
97 | err = ME_ERRNO_INTERNAL; | ||
98 | } | ||
99 | } | ||
100 | |||
101 | break; | ||
102 | |||
103 | case ME_LOCK_SET: | ||
104 | if (dlock->count) { | ||
105 | PERROR("Device is used by another process.\n"); | ||
106 | err = ME_ERRNO_USED; | ||
107 | } else if ((dlock->filep != NULL) && (dlock->filep != filep)) { | ||
108 | PERROR("Device is locked by another process.\n"); | ||
109 | err = ME_ERRNO_LOCKED; | ||
110 | } else if (dlock->filep == NULL) { | ||
111 | /* Check any subdevice is locked by another process. */ | ||
112 | |||
113 | for (i = 0; i < me_slist_get_number_subdevices(slist); | ||
114 | i++) { | ||
115 | subdevice = me_slist_get_subdevice(slist, i); | ||
116 | |||
117 | if (subdevice) { | ||
118 | if ((err = | ||
119 | subdevice-> | ||
120 | me_subdevice_lock_subdevice | ||
121 | (subdevice, filep, ME_LOCK_CHECK, | ||
122 | flags))) { | ||
123 | PERROR | ||
124 | ("A subdevice is locked by another process.\n"); | ||
125 | break; | ||
126 | } | ||
127 | } else { | ||
128 | err = ME_ERRNO_INTERNAL; | ||
129 | } | ||
130 | } | ||
131 | |||
132 | /* If no subdevices are locked by other processes, | ||
133 | we can take ownership of the device. Otherwise we jump ahead. */ | ||
134 | if (!err) | ||
135 | dlock->filep = filep; | ||
136 | } | ||
137 | |||
138 | break; | ||
139 | |||
140 | case ME_LOCK_CHECK: | ||
141 | if (dlock->count) { | ||
142 | err = ME_ERRNO_USED; | ||
143 | } else if ((dlock->filep != NULL) && (dlock->filep != filep)) { | ||
144 | err = ME_ERRNO_LOCKED; | ||
145 | } else if (dlock->filep == NULL) { | ||
146 | for (i = 0; i < me_slist_get_number_subdevices(slist); | ||
147 | i++) { | ||
148 | subdevice = me_slist_get_subdevice(slist, i); | ||
149 | |||
150 | if (subdevice) { | ||
151 | if ((err = | ||
152 | subdevice-> | ||
153 | me_subdevice_lock_subdevice | ||
154 | (subdevice, filep, ME_LOCK_CHECK, | ||
155 | flags))) { | ||
156 | PERROR | ||
157 | ("A subdevice is locked by another process.\n"); | ||
158 | break; | ||
159 | } | ||
160 | } else { | ||
161 | err = ME_ERRNO_INTERNAL; | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | |||
166 | break; | ||
167 | |||
168 | default: | ||
169 | PERROR("Invalid lock.\n"); | ||
170 | |||
171 | err = ME_ERRNO_INVALID_LOCK; | ||
172 | |||
173 | break; | ||
174 | } | ||
175 | |||
176 | spin_unlock(&dlock->spin_lock); | ||
177 | |||
178 | return err; | ||
179 | } | ||
180 | |||
181 | void me_dlock_deinit(struct me_dlock *dlock) | ||
182 | { | ||
183 | PDEBUG_LOCKS("executed.\n"); | ||
184 | } | ||
185 | |||
186 | int me_dlock_init(me_dlock_t * dlock) | ||
187 | { | ||
188 | PDEBUG_LOCKS("executed.\n"); | ||
189 | |||
190 | dlock->filep = NULL; | ||
191 | dlock->count = 0; | ||
192 | spin_lock_init(&dlock->spin_lock); | ||
193 | |||
194 | return 0; | ||
195 | } | ||
diff --git a/drivers/staging/meilhaus/medlock.h b/drivers/staging/meilhaus/medlock.h new file mode 100644 index 000000000000..4d6ddc8e58a1 --- /dev/null +++ b/drivers/staging/meilhaus/medlock.h | |||
@@ -0,0 +1,76 @@ | |||
1 | /** | ||
2 | * @file medlock.h | ||
3 | * | ||
4 | * @brief Provides the device lock class. | ||
5 | * @note Copyright (C) 2006 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | #ifndef _MEDLOCK_H_ | ||
10 | #define _MEDLOCK_H_ | ||
11 | |||
12 | #include <linux/spinlock.h> | ||
13 | |||
14 | #ifdef __KERNEL__ | ||
15 | |||
16 | /** | ||
17 | * @brief The device lock class. | ||
18 | */ | ||
19 | typedef struct me_dlock { | ||
20 | struct file *filep; /**< Pointer to file structure holding the device. */ | ||
21 | int count; /**< Number of tasks which are inside the device. */ | ||
22 | spinlock_t spin_lock; /**< Spin lock protecting the attributes from concurrent access. */ | ||
23 | } me_dlock_t; | ||
24 | |||
25 | /** | ||
26 | * @brief Tries to enter a device. | ||
27 | * | ||
28 | * @param dlock The device lock instance. | ||
29 | * @param filep The file structure identifying the calling process. | ||
30 | * | ||
31 | * @return 0 on success. | ||
32 | */ | ||
33 | int me_dlock_enter(struct me_dlock *dlock, struct file *filep); | ||
34 | |||
35 | /** | ||
36 | * @brief Exits a device. | ||
37 | * | ||
38 | * @param dlock The device lock instance. | ||
39 | * @param filep The file structure identifying the calling process. | ||
40 | * | ||
41 | * @return 0 on success. | ||
42 | */ | ||
43 | int me_dlock_exit(struct me_dlock *dlock, struct file *filep); | ||
44 | |||
45 | /** | ||
46 | * @brief Tries to perform a locking action on a device. | ||
47 | * | ||
48 | * @param dlock The device lock instance. | ||
49 | * @param filep The file structure identifying the calling process. | ||
50 | * @param The action to be done. | ||
51 | * @param flags Flags from user space. | ||
52 | * @param slist The subdevice list of the device. | ||
53 | * | ||
54 | * @return 0 on success. | ||
55 | */ | ||
56 | int me_dlock_lock(struct me_dlock *dlock, | ||
57 | struct file *filep, int lock, int flags, me_slist_t * slist); | ||
58 | |||
59 | /** | ||
60 | * @brief Initializes a lock structure. | ||
61 | * | ||
62 | * @param dlock The lock structure to initialize. | ||
63 | * @return 0 on success. | ||
64 | */ | ||
65 | int me_dlock_init(me_dlock_t * dlock); | ||
66 | |||
67 | /** | ||
68 | * @brief Deinitializes a lock structure. | ||
69 | * | ||
70 | * @param dlock The lock structure to deinitialize. | ||
71 | * @return 0 on success. | ||
72 | */ | ||
73 | void me_dlock_deinit(me_dlock_t * dlock); | ||
74 | |||
75 | #endif | ||
76 | #endif | ||
diff --git a/drivers/staging/meilhaus/medriver.h b/drivers/staging/meilhaus/medriver.h new file mode 100644 index 000000000000..02e2408ce5f3 --- /dev/null +++ b/drivers/staging/meilhaus/medriver.h | |||
@@ -0,0 +1,350 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
3 | * | ||
4 | * Source File : medriver.h | ||
5 | * Author : GG (Guenter Gebhardt) <g.gebhardt@meilhaus.de> | ||
6 | * Author: Krzysztof Gantzke <k.gantzke@meilhaus.de> | ||
7 | */ | ||
8 | |||
9 | #ifndef _MEDRIVER_H_ | ||
10 | #define _MEDRIVER_H_ | ||
11 | |||
12 | #include "metypes.h" | ||
13 | #include "meerror.h" | ||
14 | #include "medefines.h" | ||
15 | |||
16 | #ifdef __cplusplus | ||
17 | extern "C" { | ||
18 | #endif | ||
19 | |||
20 | /*=========================================================================== | ||
21 | Functions to access the driver system | ||
22 | =========================================================================*/ | ||
23 | |||
24 | int meOpen(int iFlags); | ||
25 | int meClose(int iFlags); | ||
26 | |||
27 | int meLockDriver(int iLock, int iFlags); | ||
28 | int meLockDevice(int iDevice, int iLock, int iFlags); | ||
29 | int meLockSubdevice(int iDevice, int iSubdevice, int iLock, int iFlags); | ||
30 | |||
31 | /*=========================================================================== | ||
32 | Error handling functions | ||
33 | =========================================================================*/ | ||
34 | |||
35 | int meErrorGetLastMessage(char *pcErrorMsg, int iCount); | ||
36 | int meErrorGetMessage(int iErrorCode, char *pcErrorMsg, int iCount); | ||
37 | int meErrorSetDefaultProc(int iSwitch); | ||
38 | int meErrorSetUserProc(meErrorCB_t pErrorProc); | ||
39 | |||
40 | |||
41 | /*=========================================================================== | ||
42 | Functions to perform I/O on a device | ||
43 | =========================================================================*/ | ||
44 | |||
45 | int meIOIrqSetCallback( | ||
46 | int iDevice, | ||
47 | int iSubdevice, | ||
48 | meIOIrqCB_t pCallback, | ||
49 | void *pCallbackContext, | ||
50 | int iFlags); | ||
51 | int meIOIrqStart( | ||
52 | int iDevice, | ||
53 | int iSubdevice, | ||
54 | int iChannel, | ||
55 | int iIrqSource, | ||
56 | int iIrqEdge, | ||
57 | int iIrqArg, | ||
58 | int iFlags); | ||
59 | int meIOIrqStop( | ||
60 | int iDevice, | ||
61 | int iSubdevice, | ||
62 | int iChannel, | ||
63 | int iFlags); | ||
64 | int meIOIrqWait( | ||
65 | int iDevice, | ||
66 | int iSubdevice, | ||
67 | int iChannel, | ||
68 | int *piIrqCount, | ||
69 | int *piValue, | ||
70 | int iTimeOut, | ||
71 | int iFlags); | ||
72 | |||
73 | int meIOResetDevice(int iDevice, int iFlags); | ||
74 | int meIOResetSubdevice(int iDevice, int iSubdevice, int iFlags); | ||
75 | |||
76 | int meIOStreamFrequencyToTicks( | ||
77 | int iDevice, | ||
78 | int iSubdevice, | ||
79 | int iTimer, | ||
80 | double *pdFrequency, | ||
81 | int *piTicksLow, | ||
82 | int *piTicksHigh, | ||
83 | int iFlags); | ||
84 | |||
85 | int meIOSingleConfig( | ||
86 | int iDevice, | ||
87 | int iSubdevice, | ||
88 | int iChannel, | ||
89 | int iSingleConfig, | ||
90 | int iRef, | ||
91 | int iTrigChan, | ||
92 | int iTrigType, | ||
93 | int iTrigEdge, | ||
94 | int iFlags); | ||
95 | int meIOSingle(meIOSingle_t *pSingleList, int iCount, int iFlags); | ||
96 | |||
97 | int meIOStreamConfig( | ||
98 | int iDevice, | ||
99 | int iSubdevice, | ||
100 | meIOStreamConfig_t *pConfigList, | ||
101 | int iCount, | ||
102 | meIOStreamTrigger_t *pTrigger, | ||
103 | int iFifoIrqThreshold, | ||
104 | int iFlags); | ||
105 | int meIOStreamNewValues( | ||
106 | int iDevice, | ||
107 | int iSubdevice, | ||
108 | int iTimeOut, | ||
109 | int *piCount, | ||
110 | int iFlags); | ||
111 | int meIOStreamRead( | ||
112 | int iDevice, | ||
113 | int iSubdevice, | ||
114 | int iReadMode, | ||
115 | int *piValues, | ||
116 | int *piCount, | ||
117 | int iFlags); | ||
118 | int meIOStreamWrite( | ||
119 | int iDevice, | ||
120 | int iSubdevice, | ||
121 | int iWriteMode, | ||
122 | int *piValues, | ||
123 | int *piCount, | ||
124 | int iFlags); | ||
125 | int meIOStreamStart(meIOStreamStart_t *pStartList, int iCount, int iFlags); | ||
126 | int meIOStreamStop(meIOStreamStop_t *pStopList, int iCount, int iFlags); | ||
127 | int meIOStreamStatus( | ||
128 | int iDevice, | ||
129 | int iSubdevice, | ||
130 | int iWait, | ||
131 | int *piStatus, | ||
132 | int *piCount, | ||
133 | int iFlags); | ||
134 | int meIOStreamSetCallbacks( | ||
135 | int iDevice, | ||
136 | int iSubdevice, | ||
137 | meIOStreamCB_t pStartCB, | ||
138 | void *pStartCBContext, | ||
139 | meIOStreamCB_t pNewValuesCB, | ||
140 | void *pNewValuesCBContext, | ||
141 | meIOStreamCB_t pEndCB, | ||
142 | void *pEndCBContext, | ||
143 | int iFlags); | ||
144 | int meIOStreamTimeToTicks( | ||
145 | int iDevice, | ||
146 | int iSubdevice, | ||
147 | int iTimer, | ||
148 | double *pdTime, | ||
149 | int *piTicksLow, | ||
150 | int *piTicksHigh, | ||
151 | int iFlags); | ||
152 | |||
153 | |||
154 | /*=========================================================================== | ||
155 | Functions to query the driver system | ||
156 | =========================================================================*/ | ||
157 | |||
158 | int meQueryDescriptionDevice(int iDevice, char *pcDescription, int iCount); | ||
159 | |||
160 | int meQueryInfoDevice( | ||
161 | int iDevice, | ||
162 | int *piVendorId, | ||
163 | int *piDeviceId, | ||
164 | int *piSerialNo, | ||
165 | int *piBusType, | ||
166 | int *piBusNo, | ||
167 | int *piDevNo, | ||
168 | int *piFuncNo, | ||
169 | int *piPlugged); | ||
170 | |||
171 | int meQueryNameDevice(int iDevice, char *pcName, int iCount); | ||
172 | int meQueryNameDeviceDriver(int iDevice, char *pcName, int iCount); | ||
173 | |||
174 | int meQueryNumberDevices(int *piNumber); | ||
175 | int meQueryNumberSubdevices(int iDevice, int *piNumber); | ||
176 | int meQueryNumberChannels(int iDevice, int iSubdevice, int *piNumber); | ||
177 | int meQueryNumberRanges( | ||
178 | int iDevice, | ||
179 | int iSubdevice, | ||
180 | int iUnit, | ||
181 | int *piNumber); | ||
182 | |||
183 | int meQueryRangeByMinMax( | ||
184 | int iDevice, | ||
185 | int iSubdevice, | ||
186 | int iUnit, | ||
187 | double *pdMin, | ||
188 | double *pdMax, | ||
189 | int *piMaxData, | ||
190 | int *piRange); | ||
191 | int meQueryRangeInfo( | ||
192 | int iDevice, | ||
193 | int iSubdevice, | ||
194 | int iRange, | ||
195 | int *piUnit, | ||
196 | double *pdMin, | ||
197 | double *pdMax, | ||
198 | int *piMaxData); | ||
199 | |||
200 | int meQuerySubdeviceByType( | ||
201 | int iDevice, | ||
202 | int iStartSubdevice, | ||
203 | int iType, | ||
204 | int iSubtype, | ||
205 | int *piSubdevice); | ||
206 | int meQuerySubdeviceType( | ||
207 | int iDevice, | ||
208 | int iSubdevice, | ||
209 | int *piType, | ||
210 | int *piSubtype); | ||
211 | int meQuerySubdeviceCaps( | ||
212 | int iDevice, | ||
213 | int iSubdevice, | ||
214 | int *piCaps); | ||
215 | int meQuerySubdeviceCapsArgs( | ||
216 | int iDevice, | ||
217 | int iSubdevice, | ||
218 | int iCap, | ||
219 | int *piArgs, | ||
220 | int iCount); | ||
221 | |||
222 | int meQueryVersionLibrary(int *piVersion); | ||
223 | int meQueryVersionMainDriver(int *piVersion); | ||
224 | int meQueryVersionDeviceDriver(int iDevice, int *piVersion); | ||
225 | |||
226 | |||
227 | /*=========================================================================== | ||
228 | Common utility functions | ||
229 | =========================================================================*/ | ||
230 | |||
231 | int meUtilityExtractValues( | ||
232 | int iChannel, | ||
233 | int *piAIBuffer, | ||
234 | int iAIBufferCount, | ||
235 | meIOStreamConfig_t *pConfigList, | ||
236 | int iConfigListCount, | ||
237 | int *piChanBuffer, | ||
238 | int *piChanBufferCount); | ||
239 | int meUtilityDigitalToPhysical( | ||
240 | double dMin, | ||
241 | double dMax, | ||
242 | int iMaxData, | ||
243 | int iData, | ||
244 | int iModuleType, | ||
245 | double dRefValue, | ||
246 | double *pdPhysical); | ||
247 | int meUtilityDigitalToPhysicalV( | ||
248 | double dMin, | ||
249 | double dMax, | ||
250 | int iMaxData, | ||
251 | int *piDataBuffer, | ||
252 | int iCount, | ||
253 | int iModuleType, | ||
254 | double dRefValue, | ||
255 | double *pdPhysicalBuffer); | ||
256 | int meUtilityPhysicalToDigital( | ||
257 | double dMin, | ||
258 | double dMax, | ||
259 | int iMaxData, | ||
260 | double dPhysical, | ||
261 | int *piData); | ||
262 | int meUtilityPWMStart( | ||
263 | int iDevice, | ||
264 | int iSubdevice1, | ||
265 | int iSubdevice2, | ||
266 | int iSubdevice3, | ||
267 | int iRef, | ||
268 | int iPrescaler, | ||
269 | int iDutyCycle, | ||
270 | int iFlag); | ||
271 | int meUtilityPWMStop(int iDevice, | ||
272 | int iSubdevice1); | ||
273 | int meUtilityPWMRestart( | ||
274 | int iDevice, | ||
275 | int iSubdevice1, | ||
276 | int iRef, | ||
277 | int iPrescaler); | ||
278 | |||
279 | |||
280 | /*=========================================================================== | ||
281 | Load configuration from file into driver system | ||
282 | =========================================================================*/ | ||
283 | |||
284 | int meConfigLoad(char *pcConfigFile); | ||
285 | |||
286 | |||
287 | /*=========================================================================== | ||
288 | Functions to query a remote driver system | ||
289 | =========================================================================*/ | ||
290 | |||
291 | int meRQueryDescriptionDevice( | ||
292 | char *location, | ||
293 | int iDevice, | ||
294 | char *pcDescription, | ||
295 | int iCount); | ||
296 | |||
297 | int meRQueryInfoDevice( | ||
298 | char *location, | ||
299 | int iDevice, | ||
300 | int *piVendorId, | ||
301 | int *piDeviceId, | ||
302 | int *piSerialNo, | ||
303 | int *piBusType, | ||
304 | int *piBusNo, | ||
305 | int *piDevNo, | ||
306 | int *piFuncNo, | ||
307 | int *piPlugged); | ||
308 | |||
309 | int meRQueryNameDevice( | ||
310 | char *location, | ||
311 | int iDevice, | ||
312 | char *pcName, | ||
313 | int iCount); | ||
314 | |||
315 | int meRQueryNumberDevices(char *location, int *piNumber); | ||
316 | int meRQueryNumberSubdevices(char *location, int iDevice, int *piNumber); | ||
317 | int meRQueryNumberChannels( | ||
318 | char *location, | ||
319 | int iDevice, | ||
320 | int iSubdevice, | ||
321 | int *piNumber); | ||
322 | int meRQueryNumberRanges( | ||
323 | char *location, | ||
324 | int iDevice, | ||
325 | int iSubdevice, | ||
326 | int iUnit, | ||
327 | int *piNumber); | ||
328 | |||
329 | int meRQueryRangeInfo( | ||
330 | char *location, | ||
331 | int iDevice, | ||
332 | int iSubdevice, | ||
333 | int iRange, | ||
334 | int *piUnit, | ||
335 | double *pdMin, | ||
336 | double *pdMax, | ||
337 | int *piMaxData); | ||
338 | |||
339 | int meRQuerySubdeviceType( | ||
340 | char *location, | ||
341 | int iDevice, | ||
342 | int iSubdevice, | ||
343 | int *piType, | ||
344 | int *piSubtype); | ||
345 | |||
346 | #ifdef __cplusplus | ||
347 | } | ||
348 | #endif | ||
349 | |||
350 | #endif | ||
diff --git a/drivers/staging/meilhaus/medummy.c b/drivers/staging/meilhaus/medummy.c new file mode 100644 index 000000000000..6a9f08d50bb1 --- /dev/null +++ b/drivers/staging/meilhaus/medummy.c | |||
@@ -0,0 +1,1266 @@ | |||
1 | /* Device driver for Meilhaus ME-DUMMY devices. | ||
2 | * =========================================== | ||
3 | * | ||
4 | * Copyright (C) 2005 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
5 | * | ||
6 | * This file is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | /* | ||
22 | * User application could also include the kernel header files. But the | ||
23 | * real kernel functions are protected by #ifdef __KERNEL__. | ||
24 | */ | ||
25 | #ifndef __KERNEL__ | ||
26 | # define __KERNEL__ | ||
27 | #endif | ||
28 | |||
29 | /* | ||
30 | * This must be defined before module.h is included. Not needed, when | ||
31 | * it is a built in driver. | ||
32 | */ | ||
33 | #ifndef MODULE | ||
34 | # define MODULE | ||
35 | #endif | ||
36 | |||
37 | #include <linux/module.h> | ||
38 | #include <linux/slab.h> | ||
39 | |||
40 | #include "meerror.h" | ||
41 | #include "meinternal.h" | ||
42 | |||
43 | #include "meids.h" | ||
44 | #include "mecommon.h" | ||
45 | #include "medevice.h" | ||
46 | #include "medebug.h" | ||
47 | |||
48 | #include "medummy.h" | ||
49 | |||
50 | static int medummy_io_irq_start(me_device_t * device, | ||
51 | struct file *filep, | ||
52 | int subdevice, | ||
53 | int channel, | ||
54 | int irq_source, | ||
55 | int irq_edge, int irq_arg, int flags) | ||
56 | { | ||
57 | PDEBUG("executed.\n"); | ||
58 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
59 | } | ||
60 | |||
61 | static int medummy_io_irq_wait(me_device_t * device, | ||
62 | struct file *filep, | ||
63 | int subdevice, | ||
64 | int channel, | ||
65 | int *irq_count, | ||
66 | int *value, int timeout, int flags) | ||
67 | { | ||
68 | PDEBUG("executed.\n"); | ||
69 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
70 | } | ||
71 | |||
72 | static int medummy_io_irq_stop(me_device_t * device, | ||
73 | struct file *filep, | ||
74 | int subdevice, int channel, int flags) | ||
75 | { | ||
76 | PDEBUG("executed.\n"); | ||
77 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
78 | } | ||
79 | |||
80 | static int medummy_io_reset_device(me_device_t * device, | ||
81 | struct file *filep, int flags) | ||
82 | { | ||
83 | PDEBUG("executed.\n"); | ||
84 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
85 | } | ||
86 | |||
87 | static int medummy_io_reset_subdevice(me_device_t * device, | ||
88 | struct file *filep, | ||
89 | int subdevice, int flags) | ||
90 | { | ||
91 | PDEBUG("executed.\n"); | ||
92 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
93 | } | ||
94 | |||
95 | static int medummy_io_single_config(me_device_t * device, | ||
96 | struct file *filep, | ||
97 | int subdevice, | ||
98 | int channel, | ||
99 | int single_config, | ||
100 | int ref, | ||
101 | int trig_chan, | ||
102 | int trig_type, int trig_edge, int flags) | ||
103 | { | ||
104 | PDEBUG("executed.\n"); | ||
105 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
106 | } | ||
107 | |||
108 | static int medummy_io_single_read(me_device_t * device, | ||
109 | struct file *filep, | ||
110 | int subdevice, | ||
111 | int channel, | ||
112 | int *value, int time_out, int flags) | ||
113 | { | ||
114 | PDEBUG("executed.\n"); | ||
115 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
116 | } | ||
117 | |||
118 | static int medummy_io_single_write(me_device_t * device, | ||
119 | struct file *filep, | ||
120 | int subdevice, | ||
121 | int channel, | ||
122 | int value, int time_out, int flags) | ||
123 | { | ||
124 | PDEBUG("executed.\n"); | ||
125 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
126 | } | ||
127 | |||
128 | static int medummy_io_stream_config(me_device_t * device, | ||
129 | struct file *filep, | ||
130 | int subdevice, | ||
131 | meIOStreamConfig_t * config_list, | ||
132 | int count, | ||
133 | meIOStreamTrigger_t * trigger, | ||
134 | int fifo_irq_threshold, int flags) | ||
135 | { | ||
136 | PDEBUG("executed.\n"); | ||
137 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
138 | } | ||
139 | |||
140 | static int medummy_io_stream_new_values(me_device_t * device, | ||
141 | struct file *filep, | ||
142 | int subdevice, | ||
143 | int timeout, int *count, int flags) | ||
144 | { | ||
145 | PDEBUG("executed.\n"); | ||
146 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
147 | } | ||
148 | |||
149 | static int medummy_io_stream_read(me_device_t * device, | ||
150 | struct file *filep, | ||
151 | int subdevice, | ||
152 | int read_mode, | ||
153 | int *values, int *count, int flags) | ||
154 | { | ||
155 | PDEBUG("executed.\n"); | ||
156 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
157 | } | ||
158 | |||
159 | static int medummy_io_stream_start(me_device_t * device, | ||
160 | struct file *filep, | ||
161 | int subdevice, | ||
162 | int start_mode, int time_out, int flags) | ||
163 | { | ||
164 | PDEBUG("executed.\n"); | ||
165 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
166 | } | ||
167 | |||
168 | static int medummy_io_stream_status(me_device_t * device, | ||
169 | struct file *filep, | ||
170 | int subdevice, | ||
171 | int wait, | ||
172 | int *status, int *values, int flags) | ||
173 | { | ||
174 | PDEBUG("executed.\n"); | ||
175 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
176 | } | ||
177 | |||
178 | static int medummy_io_stream_stop(me_device_t * device, | ||
179 | struct file *filep, | ||
180 | int subdevice, int stop_mode, int flags) | ||
181 | { | ||
182 | PDEBUG("executed.\n"); | ||
183 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
184 | } | ||
185 | |||
186 | static int medummy_io_stream_write(me_device_t * device, | ||
187 | struct file *filep, | ||
188 | int subdevice, | ||
189 | int write_mode, | ||
190 | int *values, int *count, int flags) | ||
191 | { | ||
192 | PDEBUG("executed.\n"); | ||
193 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
194 | } | ||
195 | |||
196 | static int medummy_lock_device(me_device_t * device, | ||
197 | struct file *filep, int lock, int flags) | ||
198 | { | ||
199 | PDEBUG("executed.\n"); | ||
200 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
201 | } | ||
202 | |||
203 | static int medummy_lock_subdevice(me_device_t * device, | ||
204 | struct file *filep, | ||
205 | int subdevice, int lock, int flags) | ||
206 | { | ||
207 | PDEBUG("executed.\n"); | ||
208 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
209 | } | ||
210 | |||
211 | static int medummy_query_description_device(me_device_t * device, | ||
212 | char **description) | ||
213 | { | ||
214 | medummy_device_t *instance = (medummy_device_t *) device; | ||
215 | |||
216 | PDEBUG("executed.\n"); | ||
217 | |||
218 | // if (instance->magic != MEDUMMY_MAGIC_NUMBER) | ||
219 | // { | ||
220 | // PERROR("Wrong magic number.\n"); | ||
221 | // return ME_ERRNO_INTERNAL; | ||
222 | // } | ||
223 | |||
224 | switch (instance->device_id) { | ||
225 | |||
226 | case PCI_DEVICE_ID_MEILHAUS_ME1000: | ||
227 | |||
228 | case PCI_DEVICE_ID_MEILHAUS_ME1000_A: | ||
229 | |||
230 | case PCI_DEVICE_ID_MEILHAUS_ME1000_B: | ||
231 | *description = ME1000_DESCRIPTION_DEVICE_ME1000; | ||
232 | |||
233 | break; | ||
234 | |||
235 | case PCI_DEVICE_ID_MEILHAUS_ME1400: | ||
236 | *description = ME1400_DESCRIPTION_DEVICE_ME1400; | ||
237 | |||
238 | break; | ||
239 | |||
240 | case PCI_DEVICE_ID_MEILHAUS_ME140A: | ||
241 | *description = ME1400_DESCRIPTION_DEVICE_ME1400A; | ||
242 | |||
243 | break; | ||
244 | |||
245 | case PCI_DEVICE_ID_MEILHAUS_ME140B: | ||
246 | *description = ME1400_DESCRIPTION_DEVICE_ME1400B; | ||
247 | |||
248 | break; | ||
249 | |||
250 | case PCI_DEVICE_ID_MEILHAUS_ME14E0: | ||
251 | *description = ME1400_DESCRIPTION_DEVICE_ME1400E; | ||
252 | |||
253 | break; | ||
254 | |||
255 | case PCI_DEVICE_ID_MEILHAUS_ME14EA: | ||
256 | *description = ME1400_DESCRIPTION_DEVICE_ME1400EA; | ||
257 | |||
258 | break; | ||
259 | |||
260 | case PCI_DEVICE_ID_MEILHAUS_ME14EB: | ||
261 | *description = ME1400_DESCRIPTION_DEVICE_ME1400EB; | ||
262 | |||
263 | break; | ||
264 | |||
265 | case PCI_DEVICE_ID_MEILHAUS_ME140C: | ||
266 | *description = ME1400_DESCRIPTION_DEVICE_ME1400C; | ||
267 | |||
268 | break; | ||
269 | |||
270 | case PCI_DEVICE_ID_MEILHAUS_ME140D: | ||
271 | *description = ME1400_DESCRIPTION_DEVICE_ME1400D; | ||
272 | |||
273 | break; | ||
274 | |||
275 | case PCI_DEVICE_ID_MEILHAUS_ME1600_4U: | ||
276 | *description = ME1600_DESCRIPTION_DEVICE_ME16004U; | ||
277 | |||
278 | break; | ||
279 | |||
280 | case PCI_DEVICE_ID_MEILHAUS_ME1600_8U: | ||
281 | *description = ME1600_DESCRIPTION_DEVICE_ME16008U; | ||
282 | |||
283 | break; | ||
284 | |||
285 | case PCI_DEVICE_ID_MEILHAUS_ME1600_12U: | ||
286 | *description = ME1600_DESCRIPTION_DEVICE_ME160012U; | ||
287 | |||
288 | break; | ||
289 | |||
290 | case PCI_DEVICE_ID_MEILHAUS_ME1600_16U: | ||
291 | *description = ME1600_DESCRIPTION_DEVICE_ME160016U; | ||
292 | |||
293 | break; | ||
294 | |||
295 | case PCI_DEVICE_ID_MEILHAUS_ME1600_16U_8I: | ||
296 | *description = ME1600_DESCRIPTION_DEVICE_ME160016U8I; | ||
297 | |||
298 | break; | ||
299 | |||
300 | case PCI_DEVICE_ID_MEILHAUS_ME4610: | ||
301 | *description = ME4600_DESCRIPTION_DEVICE_ME4610; | ||
302 | |||
303 | break; | ||
304 | |||
305 | case PCI_DEVICE_ID_MEILHAUS_ME4650: | ||
306 | *description = ME4600_DESCRIPTION_DEVICE_ME4650; | ||
307 | |||
308 | break; | ||
309 | |||
310 | case PCI_DEVICE_ID_MEILHAUS_ME4660: | ||
311 | *description = ME4600_DESCRIPTION_DEVICE_ME4660; | ||
312 | |||
313 | break; | ||
314 | |||
315 | case PCI_DEVICE_ID_MEILHAUS_ME4660I: | ||
316 | *description = ME4600_DESCRIPTION_DEVICE_ME4660I; | ||
317 | |||
318 | break; | ||
319 | |||
320 | case PCI_DEVICE_ID_MEILHAUS_ME4660S: | ||
321 | *description = ME4600_DESCRIPTION_DEVICE_ME4660S; | ||
322 | |||
323 | break; | ||
324 | |||
325 | case PCI_DEVICE_ID_MEILHAUS_ME4660IS: | ||
326 | *description = ME4600_DESCRIPTION_DEVICE_ME4660IS; | ||
327 | |||
328 | break; | ||
329 | |||
330 | case PCI_DEVICE_ID_MEILHAUS_ME4670: | ||
331 | *description = ME4600_DESCRIPTION_DEVICE_ME4670; | ||
332 | |||
333 | break; | ||
334 | |||
335 | case PCI_DEVICE_ID_MEILHAUS_ME4670I: | ||
336 | *description = ME4600_DESCRIPTION_DEVICE_ME4670I; | ||
337 | |||
338 | break; | ||
339 | |||
340 | case PCI_DEVICE_ID_MEILHAUS_ME4670S: | ||
341 | *description = ME4600_DESCRIPTION_DEVICE_ME4670S; | ||
342 | |||
343 | break; | ||
344 | |||
345 | case PCI_DEVICE_ID_MEILHAUS_ME4670IS: | ||
346 | *description = ME4600_DESCRIPTION_DEVICE_ME4670IS; | ||
347 | |||
348 | break; | ||
349 | |||
350 | case PCI_DEVICE_ID_MEILHAUS_ME4680: | ||
351 | *description = ME4600_DESCRIPTION_DEVICE_ME4680; | ||
352 | |||
353 | break; | ||
354 | |||
355 | case PCI_DEVICE_ID_MEILHAUS_ME4680I: | ||
356 | *description = ME4600_DESCRIPTION_DEVICE_ME4680I; | ||
357 | |||
358 | break; | ||
359 | |||
360 | case PCI_DEVICE_ID_MEILHAUS_ME4680S: | ||
361 | *description = ME4600_DESCRIPTION_DEVICE_ME4680S; | ||
362 | |||
363 | break; | ||
364 | |||
365 | case PCI_DEVICE_ID_MEILHAUS_ME4680IS: | ||
366 | *description = ME4600_DESCRIPTION_DEVICE_ME4680IS; | ||
367 | |||
368 | break; | ||
369 | |||
370 | case PCI_DEVICE_ID_MEILHAUS_ME6004: | ||
371 | *description = ME6000_DESCRIPTION_DEVICE_ME60004; | ||
372 | |||
373 | break; | ||
374 | |||
375 | case PCI_DEVICE_ID_MEILHAUS_ME6008: | ||
376 | *description = ME6000_DESCRIPTION_DEVICE_ME60008; | ||
377 | |||
378 | break; | ||
379 | |||
380 | case PCI_DEVICE_ID_MEILHAUS_ME600F: | ||
381 | *description = ME6000_DESCRIPTION_DEVICE_ME600016; | ||
382 | |||
383 | break; | ||
384 | |||
385 | case PCI_DEVICE_ID_MEILHAUS_ME6014: | ||
386 | *description = ME6000_DESCRIPTION_DEVICE_ME6000I4; | ||
387 | |||
388 | break; | ||
389 | |||
390 | case PCI_DEVICE_ID_MEILHAUS_ME6018: | ||
391 | *description = ME6000_DESCRIPTION_DEVICE_ME6000I8; | ||
392 | |||
393 | break; | ||
394 | |||
395 | case PCI_DEVICE_ID_MEILHAUS_ME601F: | ||
396 | *description = ME6000_DESCRIPTION_DEVICE_ME6000I16; | ||
397 | |||
398 | break; | ||
399 | |||
400 | case PCI_DEVICE_ID_MEILHAUS_ME6034: | ||
401 | *description = ME6000_DESCRIPTION_DEVICE_ME6000ISLE4; | ||
402 | |||
403 | break; | ||
404 | |||
405 | case PCI_DEVICE_ID_MEILHAUS_ME6038: | ||
406 | *description = ME6000_DESCRIPTION_DEVICE_ME6000ISLE8; | ||
407 | |||
408 | break; | ||
409 | |||
410 | case PCI_DEVICE_ID_MEILHAUS_ME603F: | ||
411 | *description = ME6000_DESCRIPTION_DEVICE_ME6000ISLE16; | ||
412 | |||
413 | break; | ||
414 | |||
415 | case PCI_DEVICE_ID_MEILHAUS_ME6104: | ||
416 | *description = ME6000_DESCRIPTION_DEVICE_ME61004; | ||
417 | |||
418 | break; | ||
419 | |||
420 | case PCI_DEVICE_ID_MEILHAUS_ME6108: | ||
421 | *description = ME6000_DESCRIPTION_DEVICE_ME61008; | ||
422 | |||
423 | break; | ||
424 | |||
425 | case PCI_DEVICE_ID_MEILHAUS_ME610F: | ||
426 | *description = ME6000_DESCRIPTION_DEVICE_ME610016; | ||
427 | |||
428 | break; | ||
429 | |||
430 | case PCI_DEVICE_ID_MEILHAUS_ME6114: | ||
431 | *description = ME6000_DESCRIPTION_DEVICE_ME6100I4; | ||
432 | |||
433 | break; | ||
434 | |||
435 | case PCI_DEVICE_ID_MEILHAUS_ME6118: | ||
436 | *description = ME6000_DESCRIPTION_DEVICE_ME6100I8; | ||
437 | |||
438 | break; | ||
439 | |||
440 | case PCI_DEVICE_ID_MEILHAUS_ME611F: | ||
441 | *description = ME6000_DESCRIPTION_DEVICE_ME6100I16; | ||
442 | |||
443 | break; | ||
444 | |||
445 | case PCI_DEVICE_ID_MEILHAUS_ME6134: | ||
446 | *description = ME6000_DESCRIPTION_DEVICE_ME6100ISLE4; | ||
447 | |||
448 | break; | ||
449 | |||
450 | case PCI_DEVICE_ID_MEILHAUS_ME6138: | ||
451 | *description = ME6000_DESCRIPTION_DEVICE_ME6100ISLE8; | ||
452 | |||
453 | break; | ||
454 | |||
455 | case PCI_DEVICE_ID_MEILHAUS_ME613F: | ||
456 | *description = ME6000_DESCRIPTION_DEVICE_ME6100ISLE16; | ||
457 | |||
458 | break; | ||
459 | |||
460 | case PCI_DEVICE_ID_MEILHAUS_ME6044: | ||
461 | *description = ME6000_DESCRIPTION_DEVICE_ME60004DIO; | ||
462 | |||
463 | break; | ||
464 | |||
465 | case PCI_DEVICE_ID_MEILHAUS_ME6048: | ||
466 | *description = ME6000_DESCRIPTION_DEVICE_ME60008DIO; | ||
467 | |||
468 | break; | ||
469 | |||
470 | case PCI_DEVICE_ID_MEILHAUS_ME604F: | ||
471 | *description = ME6000_DESCRIPTION_DEVICE_ME600016DIO; | ||
472 | |||
473 | break; | ||
474 | |||
475 | case PCI_DEVICE_ID_MEILHAUS_ME6054: | ||
476 | *description = ME6000_DESCRIPTION_DEVICE_ME6000I4DIO; | ||
477 | |||
478 | break; | ||
479 | |||
480 | case PCI_DEVICE_ID_MEILHAUS_ME6058: | ||
481 | *description = ME6000_DESCRIPTION_DEVICE_ME6000I8DIO; | ||
482 | |||
483 | break; | ||
484 | |||
485 | case PCI_DEVICE_ID_MEILHAUS_ME605F: | ||
486 | *description = ME6000_DESCRIPTION_DEVICE_ME6000I16DIO; | ||
487 | |||
488 | break; | ||
489 | |||
490 | case PCI_DEVICE_ID_MEILHAUS_ME6074: | ||
491 | *description = ME6000_DESCRIPTION_DEVICE_ME6000ISLE4DIO; | ||
492 | |||
493 | break; | ||
494 | |||
495 | case PCI_DEVICE_ID_MEILHAUS_ME6078: | ||
496 | *description = ME6000_DESCRIPTION_DEVICE_ME6000ISLE8DIO; | ||
497 | |||
498 | break; | ||
499 | |||
500 | case PCI_DEVICE_ID_MEILHAUS_ME607F: | ||
501 | *description = ME6000_DESCRIPTION_DEVICE_ME6000ISLE16DIO; | ||
502 | |||
503 | break; | ||
504 | |||
505 | case PCI_DEVICE_ID_MEILHAUS_ME6144: | ||
506 | *description = ME6000_DESCRIPTION_DEVICE_ME61004DIO; | ||
507 | |||
508 | break; | ||
509 | |||
510 | case PCI_DEVICE_ID_MEILHAUS_ME6148: | ||
511 | *description = ME6000_DESCRIPTION_DEVICE_ME61008DIO; | ||
512 | |||
513 | break; | ||
514 | |||
515 | case PCI_DEVICE_ID_MEILHAUS_ME614F: | ||
516 | *description = ME6000_DESCRIPTION_DEVICE_ME610016DIO; | ||
517 | |||
518 | break; | ||
519 | |||
520 | case PCI_DEVICE_ID_MEILHAUS_ME6154: | ||
521 | *description = ME6000_DESCRIPTION_DEVICE_ME6100I4DIO; | ||
522 | |||
523 | break; | ||
524 | |||
525 | case PCI_DEVICE_ID_MEILHAUS_ME6158: | ||
526 | *description = ME6000_DESCRIPTION_DEVICE_ME6100I8DIO; | ||
527 | |||
528 | break; | ||
529 | |||
530 | case PCI_DEVICE_ID_MEILHAUS_ME615F: | ||
531 | *description = ME6000_DESCRIPTION_DEVICE_ME6100I16DIO; | ||
532 | |||
533 | break; | ||
534 | |||
535 | case PCI_DEVICE_ID_MEILHAUS_ME6174: | ||
536 | *description = ME6000_DESCRIPTION_DEVICE_ME6100ISLE4DIO; | ||
537 | |||
538 | break; | ||
539 | |||
540 | case PCI_DEVICE_ID_MEILHAUS_ME6178: | ||
541 | *description = ME6000_DESCRIPTION_DEVICE_ME6100ISLE8DIO; | ||
542 | |||
543 | break; | ||
544 | |||
545 | case PCI_DEVICE_ID_MEILHAUS_ME617F: | ||
546 | *description = ME6000_DESCRIPTION_DEVICE_ME6100ISLE16DIO; | ||
547 | |||
548 | break; | ||
549 | |||
550 | case PCI_DEVICE_ID_MEILHAUS_ME6259: | ||
551 | *description = ME6000_DESCRIPTION_DEVICE_ME6200I9DIO; | ||
552 | |||
553 | break; | ||
554 | |||
555 | case PCI_DEVICE_ID_MEILHAUS_ME6359: | ||
556 | *description = ME6000_DESCRIPTION_DEVICE_ME6300I9DIO; | ||
557 | |||
558 | break; | ||
559 | |||
560 | case PCI_DEVICE_ID_MEILHAUS_ME0630: | ||
561 | *description = ME0600_DESCRIPTION_DEVICE_ME0630; | ||
562 | |||
563 | break; | ||
564 | |||
565 | case PCI_DEVICE_ID_MEILHAUS_ME8100_A: | ||
566 | *description = ME8100_DESCRIPTION_DEVICE_ME8100A; | ||
567 | |||
568 | break; | ||
569 | |||
570 | case PCI_DEVICE_ID_MEILHAUS_ME8100_B: | ||
571 | *description = ME8100_DESCRIPTION_DEVICE_ME8100B; | ||
572 | |||
573 | break; | ||
574 | |||
575 | case PCI_DEVICE_ID_MEILHAUS_ME0940: | ||
576 | *description = ME0900_DESCRIPTION_DEVICE_ME0940; | ||
577 | |||
578 | break; | ||
579 | |||
580 | case PCI_DEVICE_ID_MEILHAUS_ME0950: | ||
581 | *description = ME0900_DESCRIPTION_DEVICE_ME0950; | ||
582 | |||
583 | break; | ||
584 | |||
585 | case PCI_DEVICE_ID_MEILHAUS_ME0960: | ||
586 | *description = ME0900_DESCRIPTION_DEVICE_ME0960; | ||
587 | |||
588 | break; | ||
589 | /* | ||
590 | case USB_DEVICE_ID_MEPHISTO_S1: | ||
591 | *description = MEPHISTO_S1_DESCRIPTION_DEVICE; | ||
592 | |||
593 | break; | ||
594 | */ | ||
595 | default: | ||
596 | *description = EMPTY_DESCRIPTION_DEVICE; | ||
597 | PERROR("Invalid device id in device info.\n"); | ||
598 | |||
599 | return ME_ERRNO_INTERNAL; | ||
600 | } | ||
601 | |||
602 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
603 | } | ||
604 | |||
605 | static int medummy_query_info_device(me_device_t * device, | ||
606 | int *vendor_id, | ||
607 | int *device_id, | ||
608 | int *serial_no, | ||
609 | int *bus_type, | ||
610 | int *bus_no, | ||
611 | int *dev_no, int *func_no, int *plugged) | ||
612 | { | ||
613 | medummy_device_t *instance = (medummy_device_t *) device; | ||
614 | |||
615 | PDEBUG("executed.\n"); | ||
616 | |||
617 | // if (instance->magic != MEDUMMY_MAGIC_NUMBER) | ||
618 | // { | ||
619 | // PERROR("Wrong magic number.\n"); | ||
620 | // return ME_ERRNO_INTERNAL; | ||
621 | // } | ||
622 | |||
623 | *vendor_id = instance->vendor_id; | ||
624 | *device_id = instance->device_id; | ||
625 | *serial_no = instance->serial_no; | ||
626 | *bus_type = instance->bus_type; | ||
627 | *bus_no = instance->bus_no; | ||
628 | *dev_no = instance->dev_no; | ||
629 | *func_no = instance->func_no; | ||
630 | *plugged = ME_PLUGGED_OUT; | ||
631 | |||
632 | return ME_ERRNO_SUCCESS; | ||
633 | } | ||
634 | |||
635 | static int medummy_query_name_device_driver(me_device_t * device, char **name) | ||
636 | { | ||
637 | PDEBUG("executed.\n"); | ||
638 | *name = MEDUMMY_NAME_DRIVER; | ||
639 | return ME_ERRNO_SUCCESS; | ||
640 | } | ||
641 | |||
642 | static int medummy_query_name_device(me_device_t * device, char **name) | ||
643 | { | ||
644 | medummy_device_t *instance = (medummy_device_t *) device; | ||
645 | |||
646 | PDEBUG("executed.\n"); | ||
647 | |||
648 | // // // if (instance->magic != MEDUMMY_MAGIC_NUMBER) | ||
649 | // // // { | ||
650 | // // // PERROR("Wrong magic number.\n"); | ||
651 | // // // return ME_ERRNO_INTERNAL; | ||
652 | // // // } | ||
653 | |||
654 | switch (instance->device_id) { | ||
655 | |||
656 | case PCI_DEVICE_ID_MEILHAUS_ME1000: | ||
657 | |||
658 | case PCI_DEVICE_ID_MEILHAUS_ME1000_A: | ||
659 | |||
660 | case PCI_DEVICE_ID_MEILHAUS_ME1000_B: | ||
661 | *name = ME1000_NAME_DEVICE_ME1000; | ||
662 | |||
663 | break; | ||
664 | |||
665 | case PCI_DEVICE_ID_MEILHAUS_ME1400: | ||
666 | *name = ME1400_NAME_DEVICE_ME1400; | ||
667 | |||
668 | break; | ||
669 | |||
670 | case PCI_DEVICE_ID_MEILHAUS_ME140A: | ||
671 | *name = ME1400_NAME_DEVICE_ME1400A; | ||
672 | |||
673 | break; | ||
674 | |||
675 | case PCI_DEVICE_ID_MEILHAUS_ME140B: | ||
676 | *name = ME1400_NAME_DEVICE_ME1400B; | ||
677 | |||
678 | break; | ||
679 | |||
680 | case PCI_DEVICE_ID_MEILHAUS_ME14E0: | ||
681 | *name = ME1400_NAME_DEVICE_ME1400E; | ||
682 | |||
683 | break; | ||
684 | |||
685 | case PCI_DEVICE_ID_MEILHAUS_ME14EA: | ||
686 | *name = ME1400_NAME_DEVICE_ME1400EA; | ||
687 | |||
688 | break; | ||
689 | |||
690 | case PCI_DEVICE_ID_MEILHAUS_ME14EB: | ||
691 | *name = ME1400_NAME_DEVICE_ME1400EB; | ||
692 | |||
693 | break; | ||
694 | |||
695 | case PCI_DEVICE_ID_MEILHAUS_ME140C: | ||
696 | *name = ME1400_NAME_DEVICE_ME1400C; | ||
697 | |||
698 | break; | ||
699 | |||
700 | case PCI_DEVICE_ID_MEILHAUS_ME140D: | ||
701 | *name = ME1400_NAME_DEVICE_ME1400D; | ||
702 | |||
703 | break; | ||
704 | |||
705 | case PCI_DEVICE_ID_MEILHAUS_ME1600_4U: | ||
706 | *name = ME1600_NAME_DEVICE_ME16004U; | ||
707 | |||
708 | break; | ||
709 | |||
710 | case PCI_DEVICE_ID_MEILHAUS_ME1600_8U: | ||
711 | *name = ME1600_NAME_DEVICE_ME16008U; | ||
712 | |||
713 | break; | ||
714 | |||
715 | case PCI_DEVICE_ID_MEILHAUS_ME1600_12U: | ||
716 | *name = ME1600_NAME_DEVICE_ME160012U; | ||
717 | |||
718 | break; | ||
719 | |||
720 | case PCI_DEVICE_ID_MEILHAUS_ME1600_16U: | ||
721 | *name = ME1600_NAME_DEVICE_ME160016U; | ||
722 | |||
723 | break; | ||
724 | |||
725 | case PCI_DEVICE_ID_MEILHAUS_ME1600_16U_8I: | ||
726 | *name = ME1600_NAME_DEVICE_ME160016U8I; | ||
727 | |||
728 | break; | ||
729 | |||
730 | case PCI_DEVICE_ID_MEILHAUS_ME4610: | ||
731 | *name = ME4600_NAME_DEVICE_ME4610; | ||
732 | |||
733 | break; | ||
734 | |||
735 | case PCI_DEVICE_ID_MEILHAUS_ME4650: | ||
736 | *name = ME4600_NAME_DEVICE_ME4650; | ||
737 | |||
738 | break; | ||
739 | |||
740 | case PCI_DEVICE_ID_MEILHAUS_ME4660: | ||
741 | *name = ME4600_NAME_DEVICE_ME4660; | ||
742 | |||
743 | break; | ||
744 | |||
745 | case PCI_DEVICE_ID_MEILHAUS_ME4660I: | ||
746 | *name = ME4600_NAME_DEVICE_ME4660I; | ||
747 | |||
748 | break; | ||
749 | |||
750 | case PCI_DEVICE_ID_MEILHAUS_ME4670: | ||
751 | *name = ME4600_NAME_DEVICE_ME4670; | ||
752 | |||
753 | break; | ||
754 | |||
755 | case PCI_DEVICE_ID_MEILHAUS_ME4670I: | ||
756 | *name = ME4600_NAME_DEVICE_ME4670I; | ||
757 | |||
758 | break; | ||
759 | |||
760 | case PCI_DEVICE_ID_MEILHAUS_ME4670S: | ||
761 | *name = ME4600_NAME_DEVICE_ME4670S; | ||
762 | |||
763 | break; | ||
764 | |||
765 | case PCI_DEVICE_ID_MEILHAUS_ME4670IS: | ||
766 | *name = ME4600_NAME_DEVICE_ME4670IS; | ||
767 | |||
768 | break; | ||
769 | |||
770 | case PCI_DEVICE_ID_MEILHAUS_ME4680: | ||
771 | *name = ME4600_NAME_DEVICE_ME4680; | ||
772 | |||
773 | break; | ||
774 | |||
775 | case PCI_DEVICE_ID_MEILHAUS_ME4680I: | ||
776 | *name = ME4600_NAME_DEVICE_ME4680I; | ||
777 | |||
778 | break; | ||
779 | |||
780 | case PCI_DEVICE_ID_MEILHAUS_ME4680S: | ||
781 | *name = ME4600_NAME_DEVICE_ME4680S; | ||
782 | |||
783 | break; | ||
784 | |||
785 | case PCI_DEVICE_ID_MEILHAUS_ME4680IS: | ||
786 | *name = ME4600_NAME_DEVICE_ME4680IS; | ||
787 | |||
788 | break; | ||
789 | |||
790 | case PCI_DEVICE_ID_MEILHAUS_ME6004: | ||
791 | *name = ME6000_NAME_DEVICE_ME60004; | ||
792 | |||
793 | break; | ||
794 | |||
795 | case PCI_DEVICE_ID_MEILHAUS_ME6008: | ||
796 | *name = ME6000_NAME_DEVICE_ME60008; | ||
797 | |||
798 | break; | ||
799 | |||
800 | case PCI_DEVICE_ID_MEILHAUS_ME600F: | ||
801 | *name = ME6000_NAME_DEVICE_ME600016; | ||
802 | |||
803 | break; | ||
804 | |||
805 | case PCI_DEVICE_ID_MEILHAUS_ME6014: | ||
806 | *name = ME6000_NAME_DEVICE_ME6000I4; | ||
807 | |||
808 | break; | ||
809 | |||
810 | case PCI_DEVICE_ID_MEILHAUS_ME6018: | ||
811 | *name = ME6000_NAME_DEVICE_ME6000I8; | ||
812 | |||
813 | break; | ||
814 | |||
815 | case PCI_DEVICE_ID_MEILHAUS_ME601F: | ||
816 | *name = ME6000_NAME_DEVICE_ME6000I16; | ||
817 | |||
818 | break; | ||
819 | |||
820 | case PCI_DEVICE_ID_MEILHAUS_ME6034: | ||
821 | *name = ME6000_NAME_DEVICE_ME6000ISLE4; | ||
822 | |||
823 | break; | ||
824 | |||
825 | case PCI_DEVICE_ID_MEILHAUS_ME6038: | ||
826 | *name = ME6000_NAME_DEVICE_ME6000ISLE8; | ||
827 | |||
828 | break; | ||
829 | |||
830 | case PCI_DEVICE_ID_MEILHAUS_ME603F: | ||
831 | *name = ME6000_NAME_DEVICE_ME6000ISLE16; | ||
832 | |||
833 | break; | ||
834 | |||
835 | case PCI_DEVICE_ID_MEILHAUS_ME6104: | ||
836 | *name = ME6000_NAME_DEVICE_ME61004; | ||
837 | |||
838 | break; | ||
839 | |||
840 | case PCI_DEVICE_ID_MEILHAUS_ME6108: | ||
841 | *name = ME6000_NAME_DEVICE_ME61008; | ||
842 | |||
843 | break; | ||
844 | |||
845 | case PCI_DEVICE_ID_MEILHAUS_ME610F: | ||
846 | *name = ME6000_NAME_DEVICE_ME610016; | ||
847 | |||
848 | break; | ||
849 | |||
850 | case PCI_DEVICE_ID_MEILHAUS_ME6114: | ||
851 | *name = ME6000_NAME_DEVICE_ME6100I4; | ||
852 | |||
853 | break; | ||
854 | |||
855 | case PCI_DEVICE_ID_MEILHAUS_ME6118: | ||
856 | *name = ME6000_NAME_DEVICE_ME6100I8; | ||
857 | |||
858 | break; | ||
859 | |||
860 | case PCI_DEVICE_ID_MEILHAUS_ME611F: | ||
861 | *name = ME6000_NAME_DEVICE_ME6100I16; | ||
862 | |||
863 | break; | ||
864 | |||
865 | case PCI_DEVICE_ID_MEILHAUS_ME6134: | ||
866 | *name = ME6000_NAME_DEVICE_ME6100ISLE4; | ||
867 | |||
868 | break; | ||
869 | |||
870 | case PCI_DEVICE_ID_MEILHAUS_ME6138: | ||
871 | *name = ME6000_NAME_DEVICE_ME6100ISLE8; | ||
872 | |||
873 | break; | ||
874 | |||
875 | case PCI_DEVICE_ID_MEILHAUS_ME613F: | ||
876 | *name = ME6000_NAME_DEVICE_ME6100ISLE16; | ||
877 | |||
878 | break; | ||
879 | |||
880 | case PCI_DEVICE_ID_MEILHAUS_ME6044: | ||
881 | *name = ME6000_NAME_DEVICE_ME60004DIO; | ||
882 | |||
883 | break; | ||
884 | |||
885 | case PCI_DEVICE_ID_MEILHAUS_ME6048: | ||
886 | *name = ME6000_NAME_DEVICE_ME60008DIO; | ||
887 | |||
888 | break; | ||
889 | |||
890 | case PCI_DEVICE_ID_MEILHAUS_ME604F: | ||
891 | *name = ME6000_NAME_DEVICE_ME600016DIO; | ||
892 | |||
893 | break; | ||
894 | |||
895 | case PCI_DEVICE_ID_MEILHAUS_ME6054: | ||
896 | *name = ME6000_NAME_DEVICE_ME6000I4DIO; | ||
897 | |||
898 | break; | ||
899 | |||
900 | case PCI_DEVICE_ID_MEILHAUS_ME6058: | ||
901 | *name = ME6000_NAME_DEVICE_ME6000I8DIO; | ||
902 | |||
903 | break; | ||
904 | |||
905 | case PCI_DEVICE_ID_MEILHAUS_ME605F: | ||
906 | *name = ME6000_NAME_DEVICE_ME6000I16DIO; | ||
907 | |||
908 | break; | ||
909 | |||
910 | case PCI_DEVICE_ID_MEILHAUS_ME6074: | ||
911 | *name = ME6000_NAME_DEVICE_ME6000ISLE4DIO; | ||
912 | |||
913 | break; | ||
914 | |||
915 | case PCI_DEVICE_ID_MEILHAUS_ME6078: | ||
916 | *name = ME6000_NAME_DEVICE_ME6000ISLE8DIO; | ||
917 | |||
918 | break; | ||
919 | |||
920 | case PCI_DEVICE_ID_MEILHAUS_ME607F: | ||
921 | *name = ME6000_NAME_DEVICE_ME6000ISLE16DIO; | ||
922 | |||
923 | break; | ||
924 | |||
925 | case PCI_DEVICE_ID_MEILHAUS_ME6144: | ||
926 | *name = ME6000_NAME_DEVICE_ME61004DIO; | ||
927 | |||
928 | break; | ||
929 | |||
930 | case PCI_DEVICE_ID_MEILHAUS_ME6148: | ||
931 | *name = ME6000_NAME_DEVICE_ME61008DIO; | ||
932 | |||
933 | break; | ||
934 | |||
935 | case PCI_DEVICE_ID_MEILHAUS_ME614F: | ||
936 | *name = ME6000_NAME_DEVICE_ME610016DIO; | ||
937 | |||
938 | break; | ||
939 | |||
940 | case PCI_DEVICE_ID_MEILHAUS_ME6154: | ||
941 | *name = ME6000_NAME_DEVICE_ME6100I4DIO; | ||
942 | |||
943 | break; | ||
944 | |||
945 | case PCI_DEVICE_ID_MEILHAUS_ME6158: | ||
946 | *name = ME6000_NAME_DEVICE_ME6100I8DIO; | ||
947 | |||
948 | break; | ||
949 | |||
950 | case PCI_DEVICE_ID_MEILHAUS_ME615F: | ||
951 | *name = ME6000_NAME_DEVICE_ME6100I16DIO; | ||
952 | |||
953 | break; | ||
954 | |||
955 | case PCI_DEVICE_ID_MEILHAUS_ME6174: | ||
956 | *name = ME6000_NAME_DEVICE_ME6100ISLE4DIO; | ||
957 | |||
958 | break; | ||
959 | |||
960 | case PCI_DEVICE_ID_MEILHAUS_ME6178: | ||
961 | *name = ME6000_NAME_DEVICE_ME6100ISLE8DIO; | ||
962 | |||
963 | break; | ||
964 | |||
965 | case PCI_DEVICE_ID_MEILHAUS_ME617F: | ||
966 | *name = ME6000_NAME_DEVICE_ME6100ISLE16DIO; | ||
967 | |||
968 | break; | ||
969 | |||
970 | case PCI_DEVICE_ID_MEILHAUS_ME0630: | ||
971 | *name = ME0600_NAME_DEVICE_ME0630; | ||
972 | |||
973 | break; | ||
974 | |||
975 | case PCI_DEVICE_ID_MEILHAUS_ME8100_A: | ||
976 | *name = ME8100_NAME_DEVICE_ME8100A; | ||
977 | |||
978 | break; | ||
979 | |||
980 | case PCI_DEVICE_ID_MEILHAUS_ME8100_B: | ||
981 | *name = ME8100_NAME_DEVICE_ME8100B; | ||
982 | |||
983 | break; | ||
984 | |||
985 | case PCI_DEVICE_ID_MEILHAUS_ME0940: | ||
986 | *name = ME0900_NAME_DEVICE_ME0940; | ||
987 | |||
988 | break; | ||
989 | |||
990 | case PCI_DEVICE_ID_MEILHAUS_ME0950: | ||
991 | *name = ME0900_NAME_DEVICE_ME0950; | ||
992 | |||
993 | break; | ||
994 | |||
995 | case PCI_DEVICE_ID_MEILHAUS_ME0960: | ||
996 | *name = ME0900_NAME_DEVICE_ME0960; | ||
997 | |||
998 | break; | ||
999 | /* | ||
1000 | case USB_DEVICE_ID_MEPHISTO_S1: | ||
1001 | *name = MEPHISTO_S1_NAME_DEVICE; | ||
1002 | |||
1003 | break; | ||
1004 | */ | ||
1005 | default: | ||
1006 | *name = EMPTY_NAME_DEVICE; | ||
1007 | PERROR("Invalid PCI device id.\n"); | ||
1008 | |||
1009 | return ME_ERRNO_INTERNAL; | ||
1010 | } | ||
1011 | |||
1012 | return ME_ERRNO_SUCCESS; | ||
1013 | } | ||
1014 | |||
1015 | static int medummy_query_number_subdevices(me_device_t * device, int *number) | ||
1016 | { | ||
1017 | PDEBUG("executed.\n"); | ||
1018 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
1019 | } | ||
1020 | |||
1021 | static int medummy_query_number_channels(me_device_t * device, | ||
1022 | int subdevice, int *number) | ||
1023 | { | ||
1024 | PDEBUG("executed.\n"); | ||
1025 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
1026 | } | ||
1027 | |||
1028 | static int medummy_query_number_ranges(me_device_t * device, | ||
1029 | int subdevice, int unit, int *count) | ||
1030 | { | ||
1031 | PDEBUG("executed.\n"); | ||
1032 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
1033 | } | ||
1034 | |||
1035 | static int medummy_query_subdevice_type(me_device_t * device, | ||
1036 | int subdevice, int *type, int *subtype) | ||
1037 | { | ||
1038 | PDEBUG("executed.\n"); | ||
1039 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
1040 | } | ||
1041 | |||
1042 | static int medummy_query_subdevice_caps(me_device_t * device, | ||
1043 | int subdevice, int *caps) | ||
1044 | { | ||
1045 | PDEBUG("executed.\n"); | ||
1046 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
1047 | } | ||
1048 | |||
1049 | static int medummy_query_subdevice_caps_args(me_device_t * device, | ||
1050 | int subdevice, | ||
1051 | int cap, int *args, int count) | ||
1052 | { | ||
1053 | PDEBUG("executed.\n"); | ||
1054 | return ME_ERRNO_NOT_SUPPORTED; | ||
1055 | } | ||
1056 | |||
1057 | static int medummy_query_subdevice_by_type(me_device_t * device, | ||
1058 | int start_subdevice, | ||
1059 | int type, | ||
1060 | int subtype, int *subdevice) | ||
1061 | { | ||
1062 | PDEBUG("executed.\n"); | ||
1063 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
1064 | } | ||
1065 | |||
1066 | static int medummy_query_range_by_min_max(me_device_t * device, | ||
1067 | int subdevice, | ||
1068 | int unit, | ||
1069 | int *min, | ||
1070 | int *max, int *maxdata, int *range) | ||
1071 | { | ||
1072 | PDEBUG("executed.\n"); | ||
1073 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
1074 | } | ||
1075 | |||
1076 | static int medummy_query_range_info(me_device_t * device, | ||
1077 | int subdevice, | ||
1078 | int range, | ||
1079 | int *unit, int *min, int *max, int *maxdata) | ||
1080 | { | ||
1081 | PDEBUG("executed.\n"); | ||
1082 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
1083 | } | ||
1084 | |||
1085 | int medummy_query_timer(me_device_t * device, | ||
1086 | int subdevice, | ||
1087 | int timer, | ||
1088 | int *base_frequency, | ||
1089 | uint64_t * min_ticks, uint64_t * max_ticks) | ||
1090 | { | ||
1091 | PDEBUG("executed.\n"); | ||
1092 | return ME_ERRNO_DEVICE_UNPLUGGED; | ||
1093 | } | ||
1094 | |||
1095 | static int medummy_query_version_device_driver(me_device_t * device, | ||
1096 | int *version) | ||
1097 | { | ||
1098 | PDEBUG("executed.\n"); | ||
1099 | |||
1100 | *version = ME_VERSION_DRIVER; | ||
1101 | return ME_ERRNO_SUCCESS; | ||
1102 | } | ||
1103 | |||
1104 | static void medummy_destructor(me_device_t * device) | ||
1105 | { | ||
1106 | PDEBUG("executed.\n"); | ||
1107 | kfree(device); | ||
1108 | } | ||
1109 | |||
1110 | static int init_device_info(unsigned short vendor_id, | ||
1111 | unsigned short device_id, | ||
1112 | unsigned int serial_no, | ||
1113 | int bus_type, | ||
1114 | int bus_no, | ||
1115 | int dev_no, | ||
1116 | int func_no, medummy_device_t * instance) | ||
1117 | { | ||
1118 | PDEBUG("executed.\n"); | ||
1119 | |||
1120 | // instance->magic = MEDUMMY_MAGIC_NUMBER; | ||
1121 | instance->vendor_id = vendor_id; | ||
1122 | instance->device_id = device_id; | ||
1123 | instance->serial_no = serial_no; | ||
1124 | instance->bus_type = bus_type; | ||
1125 | instance->bus_no = bus_no; | ||
1126 | instance->dev_no = dev_no; | ||
1127 | instance->func_no = func_no; | ||
1128 | |||
1129 | return 0; | ||
1130 | } | ||
1131 | |||
1132 | static int medummy_config_load(me_device_t * device, struct file *filep, | ||
1133 | me_cfg_device_entry_t * config) | ||
1134 | { | ||
1135 | PDEBUG("executed.\n"); | ||
1136 | return ME_ERRNO_SUCCESS; | ||
1137 | } | ||
1138 | |||
1139 | static int init_device_instance(me_device_t * device) | ||
1140 | { | ||
1141 | PDEBUG("executed.\n"); | ||
1142 | |||
1143 | INIT_LIST_HEAD(&device->list); | ||
1144 | |||
1145 | device->me_device_io_irq_start = medummy_io_irq_start; | ||
1146 | device->me_device_io_irq_wait = medummy_io_irq_wait; | ||
1147 | device->me_device_io_irq_stop = medummy_io_irq_stop; | ||
1148 | device->me_device_io_reset_device = medummy_io_reset_device; | ||
1149 | device->me_device_io_reset_subdevice = medummy_io_reset_subdevice; | ||
1150 | device->me_device_io_single_config = medummy_io_single_config; | ||
1151 | device->me_device_io_single_read = medummy_io_single_read; | ||
1152 | device->me_device_io_single_write = medummy_io_single_write; | ||
1153 | device->me_device_io_stream_config = medummy_io_stream_config; | ||
1154 | device->me_device_io_stream_new_values = medummy_io_stream_new_values; | ||
1155 | device->me_device_io_stream_read = medummy_io_stream_read; | ||
1156 | device->me_device_io_stream_start = medummy_io_stream_start; | ||
1157 | device->me_device_io_stream_status = medummy_io_stream_status; | ||
1158 | device->me_device_io_stream_stop = medummy_io_stream_stop; | ||
1159 | device->me_device_io_stream_write = medummy_io_stream_write; | ||
1160 | |||
1161 | device->me_device_lock_device = medummy_lock_device; | ||
1162 | device->me_device_lock_subdevice = medummy_lock_subdevice; | ||
1163 | |||
1164 | device->me_device_query_description_device = | ||
1165 | medummy_query_description_device; | ||
1166 | device->me_device_query_info_device = medummy_query_info_device; | ||
1167 | device->me_device_query_name_device_driver = | ||
1168 | medummy_query_name_device_driver; | ||
1169 | device->me_device_query_name_device = medummy_query_name_device; | ||
1170 | |||
1171 | device->me_device_query_number_subdevices = | ||
1172 | medummy_query_number_subdevices; | ||
1173 | device->me_device_query_number_channels = medummy_query_number_channels; | ||
1174 | device->me_device_query_number_ranges = medummy_query_number_ranges; | ||
1175 | |||
1176 | device->me_device_query_range_by_min_max = | ||
1177 | medummy_query_range_by_min_max; | ||
1178 | device->me_device_query_range_info = medummy_query_range_info; | ||
1179 | |||
1180 | device->me_device_query_subdevice_type = medummy_query_subdevice_type; | ||
1181 | device->me_device_query_subdevice_by_type = | ||
1182 | medummy_query_subdevice_by_type; | ||
1183 | device->me_device_query_subdevice_caps = medummy_query_subdevice_caps; | ||
1184 | device->me_device_query_subdevice_caps_args = | ||
1185 | medummy_query_subdevice_caps_args; | ||
1186 | |||
1187 | device->me_device_query_timer = medummy_query_timer; | ||
1188 | |||
1189 | device->me_device_query_version_device_driver = | ||
1190 | medummy_query_version_device_driver; | ||
1191 | |||
1192 | device->me_device_destructor = medummy_destructor; | ||
1193 | device->me_device_config_load = medummy_config_load; | ||
1194 | return 0; | ||
1195 | } | ||
1196 | |||
1197 | me_device_t *medummy_constructor(unsigned short vendor_id, | ||
1198 | unsigned short device_id, | ||
1199 | unsigned int serial_no, | ||
1200 | int bus_type, | ||
1201 | int bus_no, int dev_no, int func_no) | ||
1202 | { | ||
1203 | int result = 0; | ||
1204 | medummy_device_t *instance; | ||
1205 | |||
1206 | PDEBUG("executed.\n"); | ||
1207 | |||
1208 | /* Allocate structure for device attributes */ | ||
1209 | instance = kmalloc(sizeof(medummy_device_t), GFP_KERNEL); | ||
1210 | |||
1211 | if (!instance) { | ||
1212 | PERROR("Can't get memory for device instance.\n"); | ||
1213 | return NULL; | ||
1214 | } | ||
1215 | |||
1216 | memset(instance, 0, sizeof(medummy_device_t)); | ||
1217 | |||
1218 | /* Initialize device info */ | ||
1219 | result = init_device_info(vendor_id, | ||
1220 | device_id, | ||
1221 | serial_no, | ||
1222 | bus_type, bus_no, dev_no, func_no, instance); | ||
1223 | |||
1224 | if (result) { | ||
1225 | PERROR("Cannot init baord info.\n"); | ||
1226 | kfree(instance); | ||
1227 | return NULL; | ||
1228 | } | ||
1229 | |||
1230 | /* Initialize device instance */ | ||
1231 | result = init_device_instance((me_device_t *) instance); | ||
1232 | |||
1233 | if (result) { | ||
1234 | PERROR("Cannot init baord info.\n"); | ||
1235 | kfree(instance); | ||
1236 | return NULL; | ||
1237 | } | ||
1238 | |||
1239 | return (me_device_t *) instance; | ||
1240 | } | ||
1241 | |||
1242 | // Init and exit of module. | ||
1243 | |||
1244 | static int __init dummy_init(void) | ||
1245 | { | ||
1246 | PDEBUG("executed.\n"); | ||
1247 | return 0; | ||
1248 | } | ||
1249 | |||
1250 | static void __exit dummy_exit(void) | ||
1251 | { | ||
1252 | PDEBUG("executed.\n"); | ||
1253 | } | ||
1254 | |||
1255 | module_init(dummy_init); | ||
1256 | |||
1257 | module_exit(dummy_exit); | ||
1258 | |||
1259 | // Administrative stuff for modinfo. | ||
1260 | MODULE_AUTHOR("Guenter Gebhardt <g.gebhardt@meilhaus.de>"); | ||
1261 | MODULE_DESCRIPTION("Device Driver Module for Meilhaus ME-DUMMY Devices"); | ||
1262 | MODULE_SUPPORTED_DEVICE("Meilhaus ME-DUMMY Devices"); | ||
1263 | MODULE_LICENSE("GPL"); | ||
1264 | |||
1265 | // Export the constructor. | ||
1266 | EXPORT_SYMBOL(medummy_constructor); | ||
diff --git a/drivers/staging/meilhaus/medummy.h b/drivers/staging/meilhaus/medummy.h new file mode 100644 index 000000000000..717000ff6c1c --- /dev/null +++ b/drivers/staging/meilhaus/medummy.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
3 | * | ||
4 | * Source File : medummy.h | ||
5 | * Author : GG (Guenter Gebhardt) <g.gebhardt@meilhaus.de> | ||
6 | */ | ||
7 | |||
8 | #ifndef _MEDUMMY_H_ | ||
9 | #define _MEDUMMY_H_ | ||
10 | |||
11 | #include "metypes.h" | ||
12 | #include "medefines.h" | ||
13 | #include "medevice.h" | ||
14 | |||
15 | #ifdef __KERNEL__ | ||
16 | |||
17 | #define MEDUMMY_MAGIC_NUMBER 0xDDDD | ||
18 | |||
19 | typedef struct medummy_device { | ||
20 | me_device_t base; /**< The Meilhaus device base class. */ | ||
21 | // int magic; /**< The magic number of the structure */ | ||
22 | unsigned short vendor_id; /**< Vendor ID */ | ||
23 | unsigned short device_id; /**< Device ID */ | ||
24 | unsigned int serial_no; /**< Serial number of the device */ | ||
25 | int bus_type; /**< Bus type */ | ||
26 | int bus_no; /**< Bus number */ | ||
27 | int dev_no; /**< Device number */ | ||
28 | int func_no; /**< Function number */ | ||
29 | } medummy_device_t; | ||
30 | |||
31 | me_device_t *medummy_constructor(unsigned short vendor_id, | ||
32 | unsigned short device_id, | ||
33 | unsigned int serial_no, | ||
34 | int bus_type, | ||
35 | int bus_no, | ||
36 | int dev_no, | ||
37 | int func_no) __attribute__ ((weak)); | ||
38 | |||
39 | #endif | ||
40 | #endif | ||
diff --git a/drivers/staging/meilhaus/meerror.h b/drivers/staging/meilhaus/meerror.h new file mode 100644 index 000000000000..9eda4bf907ba --- /dev/null +++ b/drivers/staging/meilhaus/meerror.h | |||
@@ -0,0 +1,100 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
3 | * | ||
4 | * Source File : meerror.h | ||
5 | * Author : GG (Guenter Gebhardt) <g.gebhardt@meilhaus.de> | ||
6 | * Author : KG (Krzysztof Gantzke) <k.gantzke@meilhaus.de> | ||
7 | */ | ||
8 | |||
9 | #ifndef _MEERROR_H_ | ||
10 | #define _MEERROR_H_ | ||
11 | |||
12 | extern char *meErrorMsgTable[]; | ||
13 | |||
14 | #define ME_ERRNO_SUCCESS 0 | ||
15 | #define ME_ERRNO_INVALID_DEVICE 1 | ||
16 | #define ME_ERRNO_INVALID_SUBDEVICE 2 | ||
17 | #define ME_ERRNO_INVALID_CHANNEL 3 | ||
18 | #define ME_ERRNO_INVALID_SINGLE_CONFIG 4 | ||
19 | #define ME_ERRNO_INVALID_REF 5 | ||
20 | #define ME_ERRNO_INVALID_TRIG_CHAN 6 | ||
21 | #define ME_ERRNO_INVALID_TRIG_TYPE 7 | ||
22 | #define ME_ERRNO_INVALID_TRIG_EDGE 8 | ||
23 | #define ME_ERRNO_INVALID_TIMEOUT 9 | ||
24 | #define ME_ERRNO_INVALID_FLAGS 10 | ||
25 | #define ME_ERRNO_OPEN 11 | ||
26 | #define ME_ERRNO_CLOSE 12 | ||
27 | #define ME_ERRNO_NOT_OPEN 13 | ||
28 | #define ME_ERRNO_INVALID_DIR 14 | ||
29 | #define ME_ERRNO_PREVIOUS_CONFIG 15 | ||
30 | #define ME_ERRNO_NOT_SUPPORTED 16 | ||
31 | #define ME_ERRNO_SUBDEVICE_TYPE 17 | ||
32 | #define ME_ERRNO_USER_BUFFER_SIZE 18 | ||
33 | #define ME_ERRNO_LOCKED 19 | ||
34 | #define ME_ERRNO_NOMORE_SUBDEVICE_TYPE 20 | ||
35 | #define ME_ERRNO_TIMEOUT 21 | ||
36 | #define ME_ERRNO_SIGNAL 22 | ||
37 | #define ME_ERRNO_INVALID_IRQ_SOURCE 23 | ||
38 | #define ME_ERRNO_THREAD_RUNNING 24 | ||
39 | #define ME_ERRNO_START_THREAD 25 | ||
40 | #define ME_ERRNO_CANCEL_THREAD 26 | ||
41 | #define ME_ERRNO_NO_CALLBACK 27 | ||
42 | #define ME_ERRNO_USED 28 | ||
43 | #define ME_ERRNO_INVALID_UNIT 29 | ||
44 | #define ME_ERRNO_INVALID_MIN_MAX 30 | ||
45 | #define ME_ERRNO_NO_RANGE 31 | ||
46 | #define ME_ERRNO_INVALID_RANGE 32 | ||
47 | #define ME_ERRNO_SUBDEVICE_BUSY 33 | ||
48 | #define ME_ERRNO_INVALID_LOCK 34 | ||
49 | #define ME_ERRNO_INVALID_SWITCH 35 | ||
50 | #define ME_ERRNO_INVALID_ERROR_MSG_COUNT 36 | ||
51 | #define ME_ERRNO_INVALID_STREAM_CONFIG 37 | ||
52 | #define ME_ERRNO_INVALID_CONFIG_LIST_COUNT 38 | ||
53 | #define ME_ERRNO_INVALID_ACQ_START_TRIG_TYPE 39 | ||
54 | #define ME_ERRNO_INVALID_ACQ_START_TRIG_EDGE 40 | ||
55 | #define ME_ERRNO_INVALID_ACQ_START_TRIG_CHAN 41 | ||
56 | #define ME_ERRNO_INVALID_ACQ_START_TIMEOUT 42 | ||
57 | #define ME_ERRNO_INVALID_ACQ_START_ARG 43 | ||
58 | #define ME_ERRNO_INVALID_SCAN_START_TRIG_TYPE 44 | ||
59 | #define ME_ERRNO_INVALID_SCAN_START_ARG 45 | ||
60 | #define ME_ERRNO_INVALID_CONV_START_TRIG_TYPE 46 | ||
61 | #define ME_ERRNO_INVALID_CONV_START_ARG 47 | ||
62 | #define ME_ERRNO_INVALID_SCAN_STOP_TRIG_TYPE 48 | ||
63 | #define ME_ERRNO_INVALID_SCAN_STOP_ARG 49 | ||
64 | #define ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE 50 | ||
65 | #define ME_ERRNO_INVALID_ACQ_STOP_ARG 51 | ||
66 | #define ME_ERRNO_SUBDEVICE_NOT_RUNNING 52 | ||
67 | #define ME_ERRNO_INVALID_READ_MODE 53 | ||
68 | #define ME_ERRNO_INVALID_VALUE_COUNT 54 | ||
69 | #define ME_ERRNO_INVALID_WRITE_MODE 55 | ||
70 | #define ME_ERRNO_INVALID_TIMER 56 | ||
71 | #define ME_ERRNO_DEVICE_UNPLUGGED 57 | ||
72 | #define ME_ERRNO_USED_INTERNAL 58 | ||
73 | #define ME_ERRNO_INVALID_DUTY_CYCLE 59 | ||
74 | #define ME_ERRNO_INVALID_WAIT 60 | ||
75 | #define ME_ERRNO_CONNECT_REMOTE 61 | ||
76 | #define ME_ERRNO_COMMUNICATION 62 | ||
77 | #define ME_ERRNO_INVALID_SINGLE_LIST 63 | ||
78 | #define ME_ERRNO_INVALID_MODULE_TYPE 64 | ||
79 | #define ME_ERRNO_INVALID_START_MODE 65 | ||
80 | #define ME_ERRNO_INVALID_STOP_MODE 66 | ||
81 | #define ME_ERRNO_INVALID_FIFO_IRQ_THRESHOLD 67 | ||
82 | #define ME_ERRNO_INVALID_POINTER 68 | ||
83 | #define ME_ERRNO_CREATE_EVENT 69 | ||
84 | #define ME_ERRNO_LACK_OF_RESOURCES 70 | ||
85 | #define ME_ERRNO_CANCELLED 71 | ||
86 | #define ME_ERRNO_RING_BUFFER_OVERFLOW 72 | ||
87 | #define ME_ERRNO_RING_BUFFER_UNDEFFLOW 73 | ||
88 | #define ME_ERRNO_INVALID_IRQ_EDGE 74 | ||
89 | #define ME_ERRNO_INVALID_IRQ_ARG 75 | ||
90 | #define ME_ERRNO_INVALID_CAP 76 | ||
91 | #define ME_ERRNO_INVALID_CAP_ARG_COUNT 77 | ||
92 | #define ME_ERRNO_INTERNAL 78 | ||
93 | |||
94 | /** New error for range check */ | ||
95 | #define ME_ERRNO_VALUE_OUT_OF_RANGE 79 | ||
96 | #define ME_ERRNO_FIFO_BUFFER_OVERFLOW 80 | ||
97 | #define ME_ERRNO_FIFO_BUFFER_UNDEFFLOW 81 | ||
98 | |||
99 | #define ME_ERRNO_INVALID_ERROR_NUMBER 82 | ||
100 | #endif | ||
diff --git a/drivers/staging/meilhaus/mefirmware.c b/drivers/staging/meilhaus/mefirmware.c new file mode 100644 index 000000000000..c07d202e8cb5 --- /dev/null +++ b/drivers/staging/meilhaus/mefirmware.c | |||
@@ -0,0 +1,137 @@ | |||
1 | /** | ||
2 | * @file mefirmware.c | ||
3 | * | ||
4 | * @brief Implements the firmware handling. | ||
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 | * Copyright (C) 2007 by Krzysztof Gantzke k.gantzke@meilhaus.de * | ||
13 | * * | ||
14 | * This program is free software; you can redistribute it and/or modify * | ||
15 | * it under the terms of the GNU General Public License as published by * | ||
16 | * the Free Software Foundation; either version 2 of the License, or * | ||
17 | * (at your option) any later version. * | ||
18 | * * | ||
19 | * This program is distributed in the hope that it will be useful, * | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
22 | * GNU General Public License for more details. * | ||
23 | * * | ||
24 | * You should have received a copy of the GNU General Public License * | ||
25 | * along with this program; if not, write to the * | ||
26 | * Free Software Foundation, Inc., * | ||
27 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | ||
28 | ***************************************************************************/ | ||
29 | |||
30 | #ifndef __KERNEL__ | ||
31 | # define __KERNEL__ | ||
32 | #endif | ||
33 | |||
34 | #ifndef KBUILD_MODNAME | ||
35 | # define KBUILD_MODNAME KBUILD_STR(mefirmware) | ||
36 | #endif | ||
37 | |||
38 | #include <linux/pci.h> | ||
39 | #include <linux/delay.h> | ||
40 | |||
41 | #include <linux/firmware.h> | ||
42 | |||
43 | #include "meplx_reg.h" | ||
44 | #include "medebug.h" | ||
45 | |||
46 | #include "mefirmware.h" | ||
47 | |||
48 | int me_xilinx_download(unsigned long register_base_control, | ||
49 | unsigned long register_base_data, | ||
50 | struct device *dev, const char *firmware_name) | ||
51 | { | ||
52 | int err = ME_ERRNO_FIRMWARE; | ||
53 | uint32_t value = 0; | ||
54 | int idx = 0; | ||
55 | |||
56 | const struct firmware *fw; | ||
57 | |||
58 | PDEBUG("executed.\n"); | ||
59 | |||
60 | if (!firmware_name) { | ||
61 | PERROR("Request for firmware failed. No name provided. \n"); | ||
62 | return err; | ||
63 | } | ||
64 | |||
65 | PINFO("Request '%s' firmware.\n", firmware_name); | ||
66 | err = request_firmware(&fw, firmware_name, dev); | ||
67 | |||
68 | if (err) { | ||
69 | PERROR("Request for firmware failed.\n"); | ||
70 | return err; | ||
71 | } | ||
72 | // Set PLX local interrupt 2 polarity to high. | ||
73 | // Interrupt is thrown by init pin of xilinx. | ||
74 | outl(PLX_INTCSR_LOCAL_INT2_POL, register_base_control + PLX_INTCSR); | ||
75 | |||
76 | // Set /CS and /WRITE of the Xilinx | ||
77 | value = inl(register_base_control + PLX_ICR); | ||
78 | value |= ME_FIRMWARE_CS_WRITE; | ||
79 | outl(value, register_base_control + PLX_ICR); | ||
80 | |||
81 | // Init Xilinx with CS1 | ||
82 | inl(register_base_data + ME_XILINX_CS1_REG); | ||
83 | |||
84 | // Wait for init to complete | ||
85 | udelay(20); | ||
86 | |||
87 | // Checkl /INIT pin | ||
88 | if (! | ||
89 | (inl(register_base_control + PLX_INTCSR) & | ||
90 | PLX_INTCSR_LOCAL_INT2_STATE)) { | ||
91 | PERROR("Can't init Xilinx.\n"); | ||
92 | release_firmware(fw); | ||
93 | return -EIO; | ||
94 | } | ||
95 | // Reset /CS and /WRITE of the Xilinx | ||
96 | value = inl(register_base_control + PLX_ICR); | ||
97 | value &= ~ME_FIRMWARE_CS_WRITE; | ||
98 | outl(value, register_base_control + PLX_ICR); | ||
99 | |||
100 | // Download Xilinx firmware | ||
101 | udelay(10); | ||
102 | |||
103 | for (idx = 0; idx < fw->size; idx++) { | ||
104 | outl(fw->data[idx], register_base_data); | ||
105 | #ifdef ME6000_v2_4 | ||
106 | /// This checking only for board's version 2.4 | ||
107 | // Check if BUSY flag is set (low = ready, high = busy) | ||
108 | if (inl(register_base_control + PLX_ICR) & | ||
109 | ME_FIRMWARE_BUSY_FLAG) { | ||
110 | PERROR("Xilinx is still busy (idx = %d)\n", idx); | ||
111 | release_firmware(fw); | ||
112 | return -EIO; | ||
113 | } | ||
114 | #endif //ME6000_v2_4 | ||
115 | } | ||
116 | PDEBUG("Download finished. %d bytes written to PLX.\n", idx); | ||
117 | |||
118 | // If done flag is high download was successful | ||
119 | if (inl(register_base_control + PLX_ICR) & ME_FIRMWARE_DONE_FLAG) { | ||
120 | PDEBUG("SUCCESS. Done flag is set.\n"); | ||
121 | } else { | ||
122 | PERROR("FAILURE. DONE flag is not set.\n"); | ||
123 | release_firmware(fw); | ||
124 | return -EIO; | ||
125 | } | ||
126 | |||
127 | // Set /CS and /WRITE | ||
128 | value = inl(register_base_control + PLX_ICR); | ||
129 | value |= ME_FIRMWARE_CS_WRITE; | ||
130 | outl(value, register_base_control + PLX_ICR); | ||
131 | |||
132 | PDEBUG("Enable interrupts on the PCI interface.\n"); | ||
133 | outl(ME_PLX_PCI_ACTIVATE, register_base_control + PLX_INTCSR); | ||
134 | release_firmware(fw); | ||
135 | |||
136 | return 0; | ||
137 | } | ||
diff --git a/drivers/staging/meilhaus/mefirmware.h b/drivers/staging/meilhaus/mefirmware.h new file mode 100644 index 000000000000..a2685080c97b --- /dev/null +++ b/drivers/staging/meilhaus/mefirmware.h | |||
@@ -0,0 +1,57 @@ | |||
1 | /** | ||
2 | * @file mefirmware.h | ||
3 | * | ||
4 | * @brief Definitions of the firmware handling functions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Krzysztof Gantzke (k.gantzke@meilhaus.de) | ||
7 | */ | ||
8 | |||
9 | /*************************************************************************** | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) * | ||
11 | * Copyright (C) 2007 by Krzysztof Gantzke k.gantzke@meilhaus.de * | ||
12 | * * | ||
13 | * This program 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 * | ||
25 | * Free Software Foundation, Inc., * | ||
26 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | ||
27 | ***************************************************************************/ | ||
28 | |||
29 | #ifndef _MEFIRMWARE_H | ||
30 | # define _MEFIRMWARE_H | ||
31 | |||
32 | # ifdef __KERNEL__ | ||
33 | |||
34 | #define ME_ERRNO_FIRMWARE -1 | ||
35 | |||
36 | /** | ||
37 | * Registry | ||
38 | */ | ||
39 | #define ME_XILINX_CS1_REG 0x00C8 | ||
40 | |||
41 | /** | ||
42 | * Flags (bits) | ||
43 | */ | ||
44 | |||
45 | #define ME_FIRMWARE_BUSY_FLAG 0x00000020 | ||
46 | #define ME_FIRMWARE_DONE_FLAG 0x00000004 | ||
47 | #define ME_FIRMWARE_CS_WRITE 0x00000100 | ||
48 | |||
49 | #define ME_PLX_PCI_ACTIVATE 0x43 | ||
50 | |||
51 | int me_xilinx_download(unsigned long register_base_control, | ||
52 | unsigned long register_base_data, | ||
53 | struct device *dev, const char *firmware_name); | ||
54 | |||
55 | # endif //__KERNEL__ | ||
56 | |||
57 | #endif //_MEFIRMWARE_H | ||
diff --git a/drivers/staging/meilhaus/meids.h b/drivers/staging/meilhaus/meids.h new file mode 100644 index 000000000000..b3e757cbdda6 --- /dev/null +++ b/drivers/staging/meilhaus/meids.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
3 | * | ||
4 | * Source File : meids.h | ||
5 | * Author : GG (Guenter Gebhardt) <g.gebhardt@meilhaus.de> | ||
6 | */ | ||
7 | |||
8 | #ifndef _MEIDS_H_ | ||
9 | #define _MEIDS_H_ | ||
10 | |||
11 | #ifdef __KERNEL__ | ||
12 | |||
13 | /*============================================================================= | ||
14 | Driver names | ||
15 | ===========================================================================*/ | ||
16 | |||
17 | #define MEMAIN_NAME "memain" | ||
18 | #define ME1000_NAME "me1000" | ||
19 | #define ME1400_NAME "me1400" | ||
20 | #define ME1600_NAME "me1600" | ||
21 | #define ME4600_NAME "me4600" | ||
22 | #define ME6000_NAME "me6000" | ||
23 | #define ME0600_NAME "me0600" //"me630" | ||
24 | #define ME8100_NAME "me8100" | ||
25 | #define ME8200_NAME "me8200" | ||
26 | #define ME0900_NAME "me0900" //"me9x" | ||
27 | //#define MEPHISTO_S1_NAME "mephisto_s1" | ||
28 | #define MEDUMMY_NAME "medummy" | ||
29 | |||
30 | #endif | ||
31 | #endif | ||
diff --git a/drivers/staging/meilhaus/meinternal.h b/drivers/staging/meilhaus/meinternal.h new file mode 100644 index 000000000000..8d126b4905a7 --- /dev/null +++ b/drivers/staging/meilhaus/meinternal.h | |||
@@ -0,0 +1,363 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
3 | * | ||
4 | * Source File : meinternal.h | ||
5 | * Author : GG (Guenter Gebhardt) <g.gebhardt@meilhaus.de> | ||
6 | */ | ||
7 | |||
8 | #ifndef _MEINTERNAL_H_ | ||
9 | #define _MEINTERNAL_H_ | ||
10 | |||
11 | /*============================================================================= | ||
12 | PCI Vendor IDs | ||
13 | ===========================================================================*/ | ||
14 | |||
15 | #define PCI_VENDOR_ID_MEILHAUS 0x1402 | ||
16 | |||
17 | /*============================================================================= | ||
18 | PCI Device IDs | ||
19 | ===========================================================================*/ | ||
20 | |||
21 | #define PCI_DEVICE_ID_MEILHAUS_ME1000 0x1000 | ||
22 | #define PCI_DEVICE_ID_MEILHAUS_ME1000_A 0x100A | ||
23 | #define PCI_DEVICE_ID_MEILHAUS_ME1000_B 0x100B | ||
24 | |||
25 | #define PCI_DEVICE_ID_MEILHAUS_ME1400 0x1400 | ||
26 | #define PCI_DEVICE_ID_MEILHAUS_ME140A 0x140A | ||
27 | #define PCI_DEVICE_ID_MEILHAUS_ME140B 0x140B | ||
28 | #define PCI_DEVICE_ID_MEILHAUS_ME14E0 0x14E0 | ||
29 | #define PCI_DEVICE_ID_MEILHAUS_ME14EA 0x14EA | ||
30 | #define PCI_DEVICE_ID_MEILHAUS_ME14EB 0x14EB | ||
31 | #define PCI_DEVICE_ID_MEILHAUS_ME140C 0X140C | ||
32 | #define PCI_DEVICE_ID_MEILHAUS_ME140D 0X140D | ||
33 | |||
34 | #define PCI_DEVICE_ID_MEILHAUS_ME1600_4U 0x1604 // 4 voltage outputs | ||
35 | #define PCI_DEVICE_ID_MEILHAUS_ME1600_8U 0x1608 // 8 voltage outputs | ||
36 | #define PCI_DEVICE_ID_MEILHAUS_ME1600_12U 0x160C // 12 voltage outputs | ||
37 | #define PCI_DEVICE_ID_MEILHAUS_ME1600_16U 0x160F // 16 voltage outputs | ||
38 | #define PCI_DEVICE_ID_MEILHAUS_ME1600_16U_8I 0x168F // 16 voltage/8 current o. | ||
39 | |||
40 | #define PCI_DEVICE_ID_MEILHAUS_ME4610 0x4610 // Jekyll | ||
41 | |||
42 | #define PCI_DEVICE_ID_MEILHAUS_ME4650 0x4650 // Low Cost version | ||
43 | |||
44 | #define PCI_DEVICE_ID_MEILHAUS_ME4660 0x4660 // Standard version | ||
45 | #define PCI_DEVICE_ID_MEILHAUS_ME4660I 0x4661 // Isolated version | ||
46 | #define PCI_DEVICE_ID_MEILHAUS_ME4660S 0x4662 // Standard version with Sample and Hold | ||
47 | #define PCI_DEVICE_ID_MEILHAUS_ME4660IS 0x4663 // Isolated version with Sample and Hold | ||
48 | |||
49 | #define PCI_DEVICE_ID_MEILHAUS_ME4670 0x4670 // Standard version | ||
50 | #define PCI_DEVICE_ID_MEILHAUS_ME4670I 0x4671 // Isolated version | ||
51 | #define PCI_DEVICE_ID_MEILHAUS_ME4670S 0x4672 // Standard version with Sample and Hold | ||
52 | #define PCI_DEVICE_ID_MEILHAUS_ME4670IS 0x4673 // Isolated version with Sample and Hold | ||
53 | |||
54 | #define PCI_DEVICE_ID_MEILHAUS_ME4680 0x4680 // Standard version | ||
55 | #define PCI_DEVICE_ID_MEILHAUS_ME4680I 0x4681 // Isolated version | ||
56 | #define PCI_DEVICE_ID_MEILHAUS_ME4680S 0x4682 // Standard version with Sample and Hold | ||
57 | #define PCI_DEVICE_ID_MEILHAUS_ME4680IS 0x4683 // Isolated version with Sample and Hold | ||
58 | |||
59 | /* ME6000 standard version */ | ||
60 | #define PCI_DEVICE_ID_MEILHAUS_ME6004 0x6004 | ||
61 | #define PCI_DEVICE_ID_MEILHAUS_ME6008 0x6008 | ||
62 | #define PCI_DEVICE_ID_MEILHAUS_ME600F 0x600F | ||
63 | |||
64 | /* ME6000 isolated version */ | ||
65 | #define PCI_DEVICE_ID_MEILHAUS_ME6014 0x6014 | ||
66 | #define PCI_DEVICE_ID_MEILHAUS_ME6018 0x6018 | ||
67 | #define PCI_DEVICE_ID_MEILHAUS_ME601F 0x601F | ||
68 | |||
69 | /* ME6000 isle version */ | ||
70 | #define PCI_DEVICE_ID_MEILHAUS_ME6034 0x6034 | ||
71 | #define PCI_DEVICE_ID_MEILHAUS_ME6038 0x6038 | ||
72 | #define PCI_DEVICE_ID_MEILHAUS_ME603F 0x603F | ||
73 | |||
74 | /* ME6000 standard version with DIO */ | ||
75 | #define PCI_DEVICE_ID_MEILHAUS_ME6044 0x6044 | ||
76 | #define PCI_DEVICE_ID_MEILHAUS_ME6048 0x6048 | ||
77 | #define PCI_DEVICE_ID_MEILHAUS_ME604F 0x604F | ||
78 | |||
79 | /* ME6000 isolated version with DIO */ | ||
80 | #define PCI_DEVICE_ID_MEILHAUS_ME6054 0x6054 | ||
81 | #define PCI_DEVICE_ID_MEILHAUS_ME6058 0x6058 | ||
82 | #define PCI_DEVICE_ID_MEILHAUS_ME605F 0x605F | ||
83 | |||
84 | /* ME6000 isle version with DIO */ | ||
85 | #define PCI_DEVICE_ID_MEILHAUS_ME6074 0x6074 | ||
86 | #define PCI_DEVICE_ID_MEILHAUS_ME6078 0x6078 | ||
87 | #define PCI_DEVICE_ID_MEILHAUS_ME607F 0x607F | ||
88 | |||
89 | /* ME6100 standard version */ | ||
90 | #define PCI_DEVICE_ID_MEILHAUS_ME6104 0x6104 | ||
91 | #define PCI_DEVICE_ID_MEILHAUS_ME6108 0x6108 | ||
92 | #define PCI_DEVICE_ID_MEILHAUS_ME610F 0x610F | ||
93 | |||
94 | /* ME6100 isolated version */ | ||
95 | #define PCI_DEVICE_ID_MEILHAUS_ME6114 0x6114 | ||
96 | #define PCI_DEVICE_ID_MEILHAUS_ME6118 0x6118 | ||
97 | #define PCI_DEVICE_ID_MEILHAUS_ME611F 0x611F | ||
98 | |||
99 | /* ME6100 isle version */ | ||
100 | #define PCI_DEVICE_ID_MEILHAUS_ME6134 0x6134 | ||
101 | #define PCI_DEVICE_ID_MEILHAUS_ME6138 0x6138 | ||
102 | #define PCI_DEVICE_ID_MEILHAUS_ME613F 0x613F | ||
103 | |||
104 | /* ME6100 standard version with DIO */ | ||
105 | #define PCI_DEVICE_ID_MEILHAUS_ME6144 0x6144 | ||
106 | #define PCI_DEVICE_ID_MEILHAUS_ME6148 0x6148 | ||
107 | #define PCI_DEVICE_ID_MEILHAUS_ME614F 0x614F | ||
108 | |||
109 | /* ME6100 isolated version with DIO */ | ||
110 | #define PCI_DEVICE_ID_MEILHAUS_ME6154 0x6154 | ||
111 | #define PCI_DEVICE_ID_MEILHAUS_ME6158 0x6158 | ||
112 | #define PCI_DEVICE_ID_MEILHAUS_ME615F 0x615F | ||
113 | |||
114 | /* ME6100 isle version with DIO */ | ||
115 | #define PCI_DEVICE_ID_MEILHAUS_ME6174 0x6174 | ||
116 | #define PCI_DEVICE_ID_MEILHAUS_ME6178 0x6178 | ||
117 | #define PCI_DEVICE_ID_MEILHAUS_ME617F 0x617F | ||
118 | |||
119 | /* ME6200 isolated version with DIO */ | ||
120 | #define PCI_DEVICE_ID_MEILHAUS_ME6259 0x6259 | ||
121 | |||
122 | /* ME6300 isolated version with DIO */ | ||
123 | #define PCI_DEVICE_ID_MEILHAUS_ME6359 0x6359 | ||
124 | |||
125 | /* ME0630 */ | ||
126 | #define PCI_DEVICE_ID_MEILHAUS_ME0630 0x0630 | ||
127 | |||
128 | /* ME8100 */ | ||
129 | #define PCI_DEVICE_ID_MEILHAUS_ME8100_A 0x810A | ||
130 | #define PCI_DEVICE_ID_MEILHAUS_ME8100_B 0x810B | ||
131 | |||
132 | /* ME8200 */ | ||
133 | #define PCI_DEVICE_ID_MEILHAUS_ME8200_A 0x820A | ||
134 | #define PCI_DEVICE_ID_MEILHAUS_ME8200_B 0x820B | ||
135 | |||
136 | /* ME0900 */ | ||
137 | #define PCI_DEVICE_ID_MEILHAUS_ME0940 0x0940 | ||
138 | #define PCI_DEVICE_ID_MEILHAUS_ME0950 0x0950 | ||
139 | #define PCI_DEVICE_ID_MEILHAUS_ME0960 0x0960 | ||
140 | |||
141 | |||
142 | /*============================================================================= | ||
143 | USB Vendor IDs | ||
144 | ===========================================================================*/ | ||
145 | |||
146 | //#define USB_VENDOR_ID_MEPHISTO_S1 0x0403 | ||
147 | |||
148 | |||
149 | /*============================================================================= | ||
150 | USB Device IDs | ||
151 | ===========================================================================*/ | ||
152 | |||
153 | //#define USB_DEVICE_ID_MEPHISTO_S1 0xDCD0 | ||
154 | |||
155 | |||
156 | /* ME-1000 defines */ | ||
157 | #define ME1000_NAME_DRIVER "ME-1000" | ||
158 | |||
159 | #define ME1000_NAME_DEVICE_ME1000 "ME-1000" | ||
160 | |||
161 | #define ME1000_DESCRIPTION_DEVICE_ME1000 "ME-1000 device, 128 digital i/o lines." | ||
162 | |||
163 | /* ME-1400 defines */ | ||
164 | #define ME1400_NAME_DRIVER "ME-1400" | ||
165 | |||
166 | #define ME1400_NAME_DEVICE_ME1400 "ME-1400" | ||
167 | #define ME1400_NAME_DEVICE_ME1400E "ME-1400E" | ||
168 | #define ME1400_NAME_DEVICE_ME1400A "ME-1400A" | ||
169 | #define ME1400_NAME_DEVICE_ME1400EA "ME-1400EA" | ||
170 | #define ME1400_NAME_DEVICE_ME1400B "ME-1400B" | ||
171 | #define ME1400_NAME_DEVICE_ME1400EB "ME-1400EB" | ||
172 | #define ME1400_NAME_DEVICE_ME1400C "ME-1400C" | ||
173 | #define ME1400_NAME_DEVICE_ME1400D "ME-1400D" | ||
174 | |||
175 | #define ME1400_DESCRIPTION_DEVICE_ME1400 "ME-1400 device, 24 digital i/o lines." | ||
176 | #define ME1400_DESCRIPTION_DEVICE_ME1400E "ME-1400E device, 24 digital i/o lines." | ||
177 | #define ME1400_DESCRIPTION_DEVICE_ME1400A "ME-1400A device, 24 digital i/o lines, 3 counters." | ||
178 | #define ME1400_DESCRIPTION_DEVICE_ME1400EA "ME-1400EA device, 24 digital i/o lines, 3 counters." | ||
179 | #define ME1400_DESCRIPTION_DEVICE_ME1400B "ME-1400B device, 48 digital i/o lines, 6 counters." | ||
180 | #define ME1400_DESCRIPTION_DEVICE_ME1400EB "ME-1400EB device, 48 digital i/o lines, 6 counters." | ||
181 | #define ME1400_DESCRIPTION_DEVICE_ME1400C "ME-1400C device, 24 digital i/o lines, 15 counters." | ||
182 | #define ME1400_DESCRIPTION_DEVICE_ME1400D "ME-1400D device, 48 digital i/o lines, 30 counters." | ||
183 | |||
184 | /* ME-1600 defines */ | ||
185 | #define ME1600_NAME_DRIVER "ME-1600" | ||
186 | |||
187 | #define ME1600_NAME_DEVICE_ME16004U "ME-1600/4U" | ||
188 | #define ME1600_NAME_DEVICE_ME16008U "ME-1600/8U" | ||
189 | #define ME1600_NAME_DEVICE_ME160012U "ME-1600/12U" | ||
190 | #define ME1600_NAME_DEVICE_ME160016U "ME-1600/16U" | ||
191 | #define ME1600_NAME_DEVICE_ME160016U8I "ME-1600/16U8I" | ||
192 | |||
193 | #define ME1600_DESCRIPTION_DEVICE_ME16004U "ME-1600/4U device, 4 voltage outputs." | ||
194 | #define ME1600_DESCRIPTION_DEVICE_ME16008U "ME-1600/8U device, 8 voltage outputs." | ||
195 | #define ME1600_DESCRIPTION_DEVICE_ME160012U "ME-1600/12U device, 12 voltage outputs." | ||
196 | #define ME1600_DESCRIPTION_DEVICE_ME160016U "ME-1600/16U device, 16 voltage outputs." | ||
197 | #define ME1600_DESCRIPTION_DEVICE_ME160016U8I "ME-1600/16U8I device, 16 voltage, 8 current outputs." | ||
198 | |||
199 | /* ME-4000 defines */ | ||
200 | #define ME4600_NAME_DRIVER "ME-4600" | ||
201 | |||
202 | #define ME4600_NAME_DEVICE_ME4610 "ME-4610" | ||
203 | #define ME4600_NAME_DEVICE_ME4650 "ME-4650" | ||
204 | #define ME4600_NAME_DEVICE_ME4660 "ME-4660" | ||
205 | #define ME4600_NAME_DEVICE_ME4660I "ME-4660I" | ||
206 | #define ME4600_NAME_DEVICE_ME4660S "ME-4660S" | ||
207 | #define ME4600_NAME_DEVICE_ME4660IS "ME-4660IS" | ||
208 | #define ME4600_NAME_DEVICE_ME4670 "ME-4670" | ||
209 | #define ME4600_NAME_DEVICE_ME4670I "ME-4670I" | ||
210 | #define ME4600_NAME_DEVICE_ME4670S "ME-4670S" | ||
211 | #define ME4600_NAME_DEVICE_ME4670IS "ME-4670IS" | ||
212 | #define ME4600_NAME_DEVICE_ME4680 "ME-4680" | ||
213 | #define ME4600_NAME_DEVICE_ME4680I "ME-4680I" | ||
214 | #define ME4600_NAME_DEVICE_ME4680S "ME-4680S" | ||
215 | #define ME4600_NAME_DEVICE_ME4680IS "ME-4680IS" | ||
216 | |||
217 | #define ME4600_DESCRIPTION_DEVICE_ME4610 "ME-4610 device, 16 streaming analog inputs, 32 digital i/o lines, 3 counters, 1 external interrupt." | ||
218 | #define ME4600_DESCRIPTION_DEVICE_ME4650 "ME-4650 device, 16 streaming analog inputs, 32 digital i/o lines, 1 external interrupt." | ||
219 | #define ME4600_DESCRIPTION_DEVICE_ME4660 "ME-4660 device, 16 streaming analog inputs, 2 single analog outputs, 32 digital i/o lines, 3 counters, 1 external interrupt." | ||
220 | #define ME4600_DESCRIPTION_DEVICE_ME4660I "ME-4660I opto isolated device, 16 streaming analog inputs, 2 single analog outputs, 32 digital i/o lines, 3 counters, 1 external interrupt." | ||
221 | #define ME4600_DESCRIPTION_DEVICE_ME4660S "ME-4660 device, 16 streaming analog inputs (8 S&H), 2 single analog outputs, 32 digital i/o lines, 3 counters, 1 external interrupt." | ||
222 | #define ME4600_DESCRIPTION_DEVICE_ME4660IS "ME-4660I opto isolated device, 16 streaming analog inputs (8 S&H), 2 single analog outputs, 32 digital i/o lines, 3 counters, 1 external interrupt." | ||
223 | #define ME4600_DESCRIPTION_DEVICE_ME4670 "ME-4670 device, 32 streaming analog inputs, 4 single analog outputs, 32 digital i/o lines, 3 counters, 1 external interrupt." | ||
224 | #define ME4600_DESCRIPTION_DEVICE_ME4670I "ME-4670I opto isolated device, 32 streaming analog inputs, 4 single analog outputs, 32 digital i/o lines, 3 counters, 1 external interrupt." | ||
225 | #define ME4600_DESCRIPTION_DEVICE_ME4670S "ME-4670S device, 32 streaming analog inputs (8 S&H), 4 single analog outputs, 32 digital i/o lines, 3 counters, 1 external interrupt." | ||
226 | #define ME4600_DESCRIPTION_DEVICE_ME4670IS "ME-4670IS opto isolated device, 32 streaming analog inputs (8 S&H), 4 single analog outputs, 32 digital i/o lines, 3 counters, 1 external interrupt." | ||
227 | #define ME4600_DESCRIPTION_DEVICE_ME4680 "ME-4680 device, 32 streaming analog inputs, 4 streaming analog outputs, 32 digital i/o lines, 3 counters, 1 external interrupt." | ||
228 | #define ME4600_DESCRIPTION_DEVICE_ME4680I "ME-4680I opto isolated device, 32 streaming analog inputs, 4 streaming analog outputs, 32 digital i/o lines, 3 counters, 1 external interrupt." | ||
229 | #define ME4600_DESCRIPTION_DEVICE_ME4680S "ME-4680S device, 32 streaming analog inputs, 4 streaming analog outputs, 32 digital i/o lines, 3 counters, 1 external interrupt." | ||
230 | #define ME4600_DESCRIPTION_DEVICE_ME4680IS "ME-4680IS opto isolated device, 32 streaming analog inputs (8 S&H), 4 streaming analog outputs, 32 digital i/o lines, 3 counters, 1 external interrupt." | ||
231 | |||
232 | /* ME-6000 defines */ | ||
233 | #define ME6000_NAME_DRIVER "ME-6000" | ||
234 | |||
235 | #define ME6000_NAME_DEVICE_ME60004 "ME-6000/4" | ||
236 | #define ME6000_NAME_DEVICE_ME60008 "ME-6000/8" | ||
237 | #define ME6000_NAME_DEVICE_ME600016 "ME-6000/16" | ||
238 | #define ME6000_NAME_DEVICE_ME6000I4 "ME-6000I/4" | ||
239 | #define ME6000_NAME_DEVICE_ME6000I8 "ME-6000I/8" | ||
240 | #define ME6000_NAME_DEVICE_ME6000I16 "ME-6000I/16" | ||
241 | #define ME6000_NAME_DEVICE_ME6000ISLE4 "ME-6000ISLE/4" | ||
242 | #define ME6000_NAME_DEVICE_ME6000ISLE8 "ME-6000ISLE/8" | ||
243 | #define ME6000_NAME_DEVICE_ME6000ISLE16 "ME-6000ISLE/16" | ||
244 | #define ME6000_NAME_DEVICE_ME61004 "ME-6100/4" | ||
245 | #define ME6000_NAME_DEVICE_ME61008 "ME-6100/8" | ||
246 | #define ME6000_NAME_DEVICE_ME610016 "ME-6100/16" | ||
247 | #define ME6000_NAME_DEVICE_ME6100I4 "ME-6100I/4" | ||
248 | #define ME6000_NAME_DEVICE_ME6100I8 "ME-6100I/8" | ||
249 | #define ME6000_NAME_DEVICE_ME6100I16 "ME-6100I/16" | ||
250 | #define ME6000_NAME_DEVICE_ME6100ISLE4 "ME-6100ISLE/4" | ||
251 | #define ME6000_NAME_DEVICE_ME6100ISLE8 "ME-6100ISLE/8" | ||
252 | #define ME6000_NAME_DEVICE_ME6100ISLE16 "ME-6100ISLE/16" | ||
253 | #define ME6000_NAME_DEVICE_ME60004DIO "ME-6000/4/DIO" | ||
254 | #define ME6000_NAME_DEVICE_ME60008DIO "ME-6000/8/DIO" | ||
255 | #define ME6000_NAME_DEVICE_ME600016DIO "ME-6000/16/DIO" | ||
256 | #define ME6000_NAME_DEVICE_ME6000I4DIO "ME-6000I/4/DIO" | ||
257 | #define ME6000_NAME_DEVICE_ME6000I8DIO "ME-6000I/8/DIO" | ||
258 | #define ME6000_NAME_DEVICE_ME6000I16DIO "ME-6000I/16/DIO" | ||
259 | #define ME6000_NAME_DEVICE_ME6000ISLE4DIO "ME-6000ISLE/4/DIO" | ||
260 | #define ME6000_NAME_DEVICE_ME6000ISLE8DIO "ME-6000ISLE/8/DIO" | ||
261 | #define ME6000_NAME_DEVICE_ME6000ISLE16DIO "ME-6000ISLE/16/DIO" | ||
262 | #define ME6000_NAME_DEVICE_ME61004DIO "ME-6100/4/DIO" | ||
263 | #define ME6000_NAME_DEVICE_ME61008DIO "ME-6100/8/DIO" | ||
264 | #define ME6000_NAME_DEVICE_ME610016DIO "ME-6100/16/DIO" | ||
265 | #define ME6000_NAME_DEVICE_ME6100I4DIO "ME-6100I/4/DIO" | ||
266 | #define ME6000_NAME_DEVICE_ME6100I8DIO "ME-6100I/8/DIO" | ||
267 | #define ME6000_NAME_DEVICE_ME6100I16DIO "ME-6100I/16/DIO" | ||
268 | #define ME6000_NAME_DEVICE_ME6100ISLE4DIO "ME-6100ISLE/4/DIO" | ||
269 | #define ME6000_NAME_DEVICE_ME6100ISLE8DIO "ME-6100ISLE/8/DIO" | ||
270 | #define ME6000_NAME_DEVICE_ME6100ISLE16DIO "ME-6100ISLE/16/DIO" | ||
271 | #define ME6000_NAME_DEVICE_ME6200I9DIO "ME-6200I/9/DIO" | ||
272 | #define ME6000_NAME_DEVICE_ME6300I9DIO "ME-6300I/9/DIO" | ||
273 | |||
274 | #define ME6000_DESCRIPTION_DEVICE_ME60004 "ME-6000/4 device, 4 single analog outputs." | ||
275 | #define ME6000_DESCRIPTION_DEVICE_ME60008 "ME-6000/8 device, 8 single analog outputs" | ||
276 | #define ME6000_DESCRIPTION_DEVICE_ME600016 "ME-6000/16 device, 16 single analog outputs" | ||
277 | #define ME6000_DESCRIPTION_DEVICE_ME6000I4 "ME-6000I/4 isolated device, 4 single analog outputs" | ||
278 | #define ME6000_DESCRIPTION_DEVICE_ME6000I8 "ME-6000I/8 isolated device, 8 single analog outputs" | ||
279 | #define ME6000_DESCRIPTION_DEVICE_ME6000I16 "ME-6000I/16 isolated device, 16 single analog outputs" | ||
280 | #define ME6000_DESCRIPTION_DEVICE_ME6000ISLE4 "ME-6000ISLE/4 isle device, 4 single analog outputs" | ||
281 | #define ME6000_DESCRIPTION_DEVICE_ME6000ISLE8 "ME-6000ISLE/8 isle device, 8 single analog outputs" | ||
282 | #define ME6000_DESCRIPTION_DEVICE_ME6000ISLE16 "ME-6000ISLE/16 isle device, 16 single analog outputs" | ||
283 | #define ME6000_DESCRIPTION_DEVICE_ME61004 "ME-6100/4 device, 4 streaming analog outputs." | ||
284 | #define ME6000_DESCRIPTION_DEVICE_ME61008 "ME-6100/8 device, 4 streaming, 4 single analog outputs." | ||
285 | #define ME6000_DESCRIPTION_DEVICE_ME610016 "ME-6100/16 device, 4 streaming, 12 single analog outputs." | ||
286 | #define ME6000_DESCRIPTION_DEVICE_ME6100I4 "ME-6100I/4 isolated device, 4 streaming analog outputs." | ||
287 | #define ME6000_DESCRIPTION_DEVICE_ME6100I8 "ME-6100I/8 isolated device, 4 streaming, 4 single analog outputs." | ||
288 | #define ME6000_DESCRIPTION_DEVICE_ME6100I16 "ME-6100I/16 isolated device, 4 streaming, 12 single analog outputs." | ||
289 | #define ME6000_DESCRIPTION_DEVICE_ME6100ISLE4 "ME-6100ISLE/4 isle device, 4 streaming analog outputs." | ||
290 | #define ME6000_DESCRIPTION_DEVICE_ME6100ISLE8 "ME-6100ISLE/8 isle device, 4 streaming, 4 single analog outputs." | ||
291 | #define ME6000_DESCRIPTION_DEVICE_ME6100ISLE16 "ME-6100ISLE/16 isle device, 4 streaming, 12 single analog outputs." | ||
292 | #define ME6000_DESCRIPTION_DEVICE_ME60004DIO "ME-6000/4/DIO device, 4 single analog outputs, 16 digital i/o lines." | ||
293 | #define ME6000_DESCRIPTION_DEVICE_ME60008DIO "ME-6000/8/DIO device, 8 single analog outputs, 16 digital i/o lines." | ||
294 | #define ME6000_DESCRIPTION_DEVICE_ME600016DIO "ME-6000/16/DIO device, 8 single analog outputs, 16 digital i/o lines." | ||
295 | #define ME6000_DESCRIPTION_DEVICE_ME6000I4DIO "ME-6000I/4/DIO isolated device, 4 single analog outputs, 16 digital i/o lines." | ||
296 | #define ME6000_DESCRIPTION_DEVICE_ME6000I8DIO "ME-6000I/8/DIO isolated device, 8 single analog outputs, 16 digital i/o lines." | ||
297 | #define ME6000_DESCRIPTION_DEVICE_ME6000I16DIO "ME-6000I/16/DIO isolated device, 16 single analog outputs, 16 digital i/o lines." | ||
298 | #define ME6000_DESCRIPTION_DEVICE_ME6000ISLE4DIO "ME-6000ISLE/4/DIO isle device, 4 single analog outputs, 16 digital i/o lines." | ||
299 | #define ME6000_DESCRIPTION_DEVICE_ME6000ISLE8DIO "ME-6000ISLE/8/DIO isle device, 8 single analog outputs, 16 digital i/o lines." | ||
300 | #define ME6000_DESCRIPTION_DEVICE_ME6000ISLE16DIO "ME-6000ISLE/16/DIO isle device, 16 single analog outputs, 16 digital i/o lines." | ||
301 | #define ME6000_DESCRIPTION_DEVICE_ME61004DIO "ME-6100/4/DIO device, 4 streaming analog outputs, 16 digital i/o lines." | ||
302 | #define ME6000_DESCRIPTION_DEVICE_ME61008DIO "ME-6100/8/DIO device, 4 streaming, 4 single analog outputs, 16 digital i/o lines." | ||
303 | #define ME6000_DESCRIPTION_DEVICE_ME610016DIO "ME-6100/16/DIO device, 4 streaming, 12 single analog outputs, 16 digital i/o lines." | ||
304 | #define ME6000_DESCRIPTION_DEVICE_ME6100I4DIO "ME-6100I/4/DIO isolated device, 4 streaming analog outputs, 16 digital i/o lines." | ||
305 | #define ME6000_DESCRIPTION_DEVICE_ME6100I8DIO "ME-6100I/8/DIO isolated device, 4 streaming, 4 single analog outputs, 16 digital i/o lines." | ||
306 | #define ME6000_DESCRIPTION_DEVICE_ME6100I16DIO "ME-6100I/16/DIO isolated device, 4 streaming, 12 single analog outputs, 16 digital i/o lines." | ||
307 | #define ME6000_DESCRIPTION_DEVICE_ME6100ISLE4DIO "ME-6100ISLE/4/DIO isle device, 4 streaming analog outputs, 16 digital i/o lines." | ||
308 | #define ME6000_DESCRIPTION_DEVICE_ME6100ISLE8DIO "ME-6100ISLE/8/DIO isle device, 4 streaming, 4 single analog outputs, 16 digital i/o lines." | ||
309 | #define ME6000_DESCRIPTION_DEVICE_ME6100ISLE16DIO "ME-6100ISLE/16/DIO isle device, 4 streaming, 12 single analog outputs, 16 digital i/o lines." | ||
310 | #define ME6000_DESCRIPTION_DEVICE_ME6200I9DIO "ME-6200I/9/DIO isolated device, 9 single analog outputs, 16 digital i/o lines." | ||
311 | #define ME6000_DESCRIPTION_DEVICE_ME6300I9DIO "ME-6300I/9/DIO isolated device, 4 streaming, 5 single analog outputs, 16 digital i/o lines." | ||
312 | |||
313 | /* ME-630 defines */ | ||
314 | #define ME0600_NAME_DRIVER "ME-0600" | ||
315 | |||
316 | #define ME0600_NAME_DEVICE_ME0630 "ME-630" | ||
317 | |||
318 | #define ME0600_DESCRIPTION_DEVICE_ME0630 "ME-630 device, up to 16 relay, 8 digital ttl input lines, 8 isolated digital input lines, 16 digital i/o lines, 2 external interrupts." | ||
319 | |||
320 | /* ME-8100 defines */ | ||
321 | #define ME8100_NAME_DRIVER "ME-8100" | ||
322 | |||
323 | #define ME8100_NAME_DEVICE_ME8100A "ME-8100A" | ||
324 | #define ME8100_NAME_DEVICE_ME8100B "ME-8100B" | ||
325 | |||
326 | #define ME8100_DESCRIPTION_DEVICE_ME8100A "ME-8100A opto isolated device, 16 digital input lines, 16 digital output lines." | ||
327 | #define ME8100_DESCRIPTION_DEVICE_ME8100B "ME-8100B opto isolated device, 32 digital input lines, 32 digital output lines, 3 counters." | ||
328 | |||
329 | /* ME-8200 defines */ | ||
330 | #define ME8200_NAME_DRIVER "ME-8200" | ||
331 | |||
332 | #define ME8200_NAME_DEVICE_ME8200A "ME-8200A" | ||
333 | #define ME8200_NAME_DEVICE_ME8200B "ME-8200B" | ||
334 | |||
335 | #define ME8200_DESCRIPTION_DEVICE_ME8200A "ME-8200A opto isolated device, 8 digital output lines, 8 digital input lines, 16 digital i/o lines." | ||
336 | #define ME8200_DESCRIPTION_DEVICE_ME8200B "ME-8200B opto isolated device, 16 digital output lines, 16 digital input lines, 16 digital i/o lines." | ||
337 | |||
338 | /* ME-0900 defines */ | ||
339 | #define ME0900_NAME_DRIVER "ME-0900" | ||
340 | |||
341 | #define ME0900_NAME_DEVICE_ME0940 "ME-94" | ||
342 | #define ME0900_NAME_DEVICE_ME0950 "ME-95" | ||
343 | #define ME0900_NAME_DEVICE_ME0960 "ME-96" | ||
344 | |||
345 | #define ME0900_DESCRIPTION_DEVICE_ME0940 "ME-94 device, 16 digital input lines, 2 external interrupt lines." | ||
346 | #define ME0900_DESCRIPTION_DEVICE_ME0950 "ME-95 device, 16 digital output lines." | ||
347 | #define ME0900_DESCRIPTION_DEVICE_ME0960 "ME-96 device, 8 digital input lines, 8 digital output lines, 2 external interrupt lines." | ||
348 | |||
349 | /* ME-DUMMY defines */ | ||
350 | #define MEDUMMY_NAME_DRIVER "ME-Dummy" | ||
351 | |||
352 | /* MEPHISTO_S1 defines */ | ||
353 | /* | ||
354 | #define MEPHISTO_S1_NAME_DRIVER "MEphisto Scope 1" | ||
355 | #define MEPHISTO_S1_NAME_DEVICE "MEphisto Scope 1" | ||
356 | #define MEPHISTO_S1_DESCRIPTION_DEVICE "MEphisto Scope 1 device, 2 analog inputs, 24 digital i/o." | ||
357 | */ | ||
358 | /* Error defines */ | ||
359 | #define EMPTY_NAME_DRIVER "ME-???" | ||
360 | #define EMPTY_NAME_DEVICE "ME-???" | ||
361 | #define EMPTY_DESCRIPTION_DEVICE "ME-??? unknown device" | ||
362 | |||
363 | #endif | ||
diff --git a/drivers/staging/meilhaus/meioctl.h b/drivers/staging/meilhaus/meioctl.h new file mode 100644 index 000000000000..6dc719fba57c --- /dev/null +++ b/drivers/staging/meilhaus/meioctl.h | |||
@@ -0,0 +1,515 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
3 | * | ||
4 | * Source File : meioctl.h | ||
5 | * Author : GG (Guenter Gebhardt) <g.gebhardt@meilhaus.de> | ||
6 | */ | ||
7 | |||
8 | #ifndef _MEIOCTL_H_ | ||
9 | #define _MEIOCTL_H_ | ||
10 | |||
11 | |||
12 | /*============================================================================= | ||
13 | Types for the input/output ioctls | ||
14 | ===========================================================================*/ | ||
15 | |||
16 | typedef struct me_io_irq_start { | ||
17 | int device; | ||
18 | int subdevice; | ||
19 | int channel; | ||
20 | int irq_source; | ||
21 | int irq_edge; | ||
22 | int irq_arg; | ||
23 | int flags; | ||
24 | int errno; | ||
25 | } me_io_irq_start_t; | ||
26 | |||
27 | |||
28 | typedef struct me_io_irq_wait { | ||
29 | int device; | ||
30 | int subdevice; | ||
31 | int channel; | ||
32 | int irq_count; | ||
33 | int value; | ||
34 | int time_out; | ||
35 | int flags; | ||
36 | int errno; | ||
37 | } me_io_irq_wait_t; | ||
38 | |||
39 | |||
40 | typedef struct me_io_irq_stop { | ||
41 | int device; | ||
42 | int subdevice; | ||
43 | int channel; | ||
44 | int flags; | ||
45 | int errno; | ||
46 | } me_io_irq_stop_t; | ||
47 | |||
48 | |||
49 | typedef struct me_io_reset_device { | ||
50 | int device; | ||
51 | int flags; | ||
52 | int errno; | ||
53 | } me_io_reset_device_t; | ||
54 | |||
55 | |||
56 | typedef struct me_io_reset_subdevice { | ||
57 | int device; | ||
58 | int subdevice; | ||
59 | int flags; | ||
60 | int errno; | ||
61 | } me_io_reset_subdevice_t; | ||
62 | |||
63 | |||
64 | typedef struct me_io_single_config { | ||
65 | int device; | ||
66 | int subdevice; | ||
67 | int channel; | ||
68 | int single_config; | ||
69 | int ref; | ||
70 | int trig_chan; | ||
71 | int trig_type; | ||
72 | int trig_edge; | ||
73 | int flags; | ||
74 | int errno; | ||
75 | } me_io_single_config_t; | ||
76 | |||
77 | |||
78 | typedef struct me_io_single { | ||
79 | meIOSingle_t *single_list; | ||
80 | int count; | ||
81 | int flags; | ||
82 | int errno; | ||
83 | } me_io_single_t; | ||
84 | |||
85 | |||
86 | typedef struct me_io_stream_config { | ||
87 | int device; | ||
88 | int subdevice; | ||
89 | meIOStreamConfig_t *config_list; | ||
90 | int count; | ||
91 | meIOStreamTrigger_t trigger; | ||
92 | int fifo_irq_threshold; | ||
93 | int flags; | ||
94 | int errno; | ||
95 | } me_io_stream_config_t; | ||
96 | |||
97 | |||
98 | typedef struct me_io_stream_new_values { | ||
99 | int device; | ||
100 | int subdevice; | ||
101 | int time_out; | ||
102 | int count; | ||
103 | int flags; | ||
104 | int errno; | ||
105 | } me_io_stream_new_values_t; | ||
106 | |||
107 | |||
108 | typedef struct me_io_stream_read { | ||
109 | int device; | ||
110 | int subdevice; | ||
111 | int read_mode; | ||
112 | int *values; | ||
113 | int count; | ||
114 | int flags; | ||
115 | int errno; | ||
116 | } me_io_stream_read_t; | ||
117 | |||
118 | |||
119 | typedef struct me_io_stream_start { | ||
120 | meIOStreamStart_t *start_list; | ||
121 | int count; | ||
122 | int flags; | ||
123 | int errno; | ||
124 | } me_io_stream_start_t; | ||
125 | |||
126 | |||
127 | typedef struct me_io_stream_status { | ||
128 | int device; | ||
129 | int subdevice; | ||
130 | int wait; | ||
131 | int status; | ||
132 | int count; | ||
133 | int flags; | ||
134 | int errno; | ||
135 | } me_io_stream_status_t; | ||
136 | |||
137 | |||
138 | typedef struct me_io_stream_stop { | ||
139 | meIOStreamStop_t *stop_list; | ||
140 | int count; | ||
141 | int flags; | ||
142 | int errno; | ||
143 | } me_io_stream_stop_t; | ||
144 | |||
145 | |||
146 | typedef struct me_io_stream_write { | ||
147 | int device; | ||
148 | int subdevice; | ||
149 | int write_mode; | ||
150 | int *values; | ||
151 | int count; | ||
152 | int flags; | ||
153 | int errno; | ||
154 | } me_io_stream_write_t; | ||
155 | |||
156 | |||
157 | /*============================================================================= | ||
158 | Types for the lock ioctls | ||
159 | ===========================================================================*/ | ||
160 | |||
161 | typedef struct me_lock_device { | ||
162 | int device; | ||
163 | int lock; | ||
164 | int flags; | ||
165 | int errno; | ||
166 | } me_lock_device_t; | ||
167 | |||
168 | |||
169 | typedef struct me_lock_driver { | ||
170 | int flags; | ||
171 | int lock; | ||
172 | int errno; | ||
173 | } me_lock_driver_t; | ||
174 | |||
175 | |||
176 | typedef struct me_lock_subdevice { | ||
177 | int device; | ||
178 | int subdevice; | ||
179 | int lock; | ||
180 | int flags; | ||
181 | int errno; | ||
182 | } me_lock_subdevice_t; | ||
183 | |||
184 | |||
185 | /*============================================================================= | ||
186 | Types for the query ioctls | ||
187 | ===========================================================================*/ | ||
188 | |||
189 | typedef struct me_query_info_device { | ||
190 | int device; | ||
191 | int vendor_id; | ||
192 | int device_id; | ||
193 | int serial_no; | ||
194 | int bus_type; | ||
195 | int bus_no; | ||
196 | int dev_no; | ||
197 | int func_no; | ||
198 | int plugged; | ||
199 | int errno; | ||
200 | } me_query_info_device_t; | ||
201 | |||
202 | |||
203 | typedef struct me_query_description_device { | ||
204 | int device; | ||
205 | char *name; | ||
206 | int count; | ||
207 | int errno; | ||
208 | } me_query_description_device_t; | ||
209 | |||
210 | |||
211 | typedef struct me_query_name_device { | ||
212 | int device; | ||
213 | char *name; | ||
214 | int count; | ||
215 | int errno; | ||
216 | } me_query_name_device_t; | ||
217 | |||
218 | |||
219 | typedef struct me_query_name_device_driver { | ||
220 | int device; | ||
221 | char *name; | ||
222 | int count; | ||
223 | int errno; | ||
224 | } me_query_name_device_driver_t; | ||
225 | |||
226 | |||
227 | typedef struct me_query_version_main_driver { | ||
228 | int version; | ||
229 | int errno; | ||
230 | } me_query_version_main_driver_t; | ||
231 | |||
232 | |||
233 | typedef struct me_query_version_device_driver { | ||
234 | int device; | ||
235 | int version; | ||
236 | int errno; | ||
237 | } me_query_version_device_driver_t; | ||
238 | |||
239 | |||
240 | typedef struct me_query_number_devices { | ||
241 | int number; | ||
242 | int errno; | ||
243 | } me_query_number_devices_t; | ||
244 | |||
245 | |||
246 | typedef struct me_query_number_subdevices { | ||
247 | int device; | ||
248 | int number; | ||
249 | int errno; | ||
250 | } me_query_number_subdevices_t; | ||
251 | |||
252 | |||
253 | typedef struct me_query_number_channels { | ||
254 | int device; | ||
255 | int subdevice; | ||
256 | int number; | ||
257 | int errno; | ||
258 | } me_query_number_channels_t; | ||
259 | |||
260 | |||
261 | typedef struct me_query_number_ranges { | ||
262 | int device; | ||
263 | int subdevice; | ||
264 | int channel; | ||
265 | int unit; | ||
266 | int number; | ||
267 | int errno; | ||
268 | } me_query_number_ranges_t; | ||
269 | |||
270 | |||
271 | typedef struct me_query_subdevice_by_type { | ||
272 | int device; | ||
273 | int start_subdevice; | ||
274 | int type; | ||
275 | int subtype; | ||
276 | int subdevice; | ||
277 | int errno; | ||
278 | } me_query_subdevice_by_type_t; | ||
279 | |||
280 | |||
281 | typedef struct me_query_subdevice_type { | ||
282 | int device; | ||
283 | int subdevice; | ||
284 | int type; | ||
285 | int subtype; | ||
286 | int errno; | ||
287 | } me_query_subdevice_type_t; | ||
288 | |||
289 | |||
290 | typedef struct me_query_subdevice_caps { | ||
291 | int device; | ||
292 | int subdevice; | ||
293 | int caps; | ||
294 | int errno; | ||
295 | } me_query_subdevice_caps_t; | ||
296 | |||
297 | |||
298 | typedef struct me_query_subdevice_caps_args { | ||
299 | int device; | ||
300 | int subdevice; | ||
301 | int cap; | ||
302 | int args[8]; | ||
303 | int count; | ||
304 | int errno; | ||
305 | } me_query_subdevice_caps_args_t; | ||
306 | |||
307 | |||
308 | typedef struct me_query_timer { | ||
309 | int device; | ||
310 | int subdevice; | ||
311 | int timer; | ||
312 | int base_frequency; | ||
313 | long long min_ticks; | ||
314 | long long max_ticks; | ||
315 | int errno; | ||
316 | } me_query_timer_t; | ||
317 | |||
318 | |||
319 | typedef struct me_query_range_by_min_max { | ||
320 | int device; | ||
321 | int subdevice; | ||
322 | int channel; | ||
323 | int unit; | ||
324 | int min; | ||
325 | int max; | ||
326 | int max_data; | ||
327 | int range; | ||
328 | int errno; | ||
329 | } me_query_range_by_min_max_t; | ||
330 | |||
331 | |||
332 | typedef struct me_query_range_info { | ||
333 | int device; | ||
334 | int subdevice; | ||
335 | int channel; | ||
336 | int unit; | ||
337 | int range; | ||
338 | int min; | ||
339 | int max; | ||
340 | int max_data; | ||
341 | int errno; | ||
342 | } me_query_range_info_t; | ||
343 | |||
344 | |||
345 | /*============================================================================= | ||
346 | Types for the configuration ioctls | ||
347 | ===========================================================================*/ | ||
348 | |||
349 | typedef struct me_cfg_tcpip_location { | ||
350 | int access_type; | ||
351 | char *remote_host; | ||
352 | int remote_device_number; | ||
353 | } me_cfg_tcpip_location_t; | ||
354 | |||
355 | |||
356 | typedef union me_cfg_tcpip { | ||
357 | int access_type; | ||
358 | me_cfg_tcpip_location_t location; | ||
359 | } me_cfg_tcpip_t; | ||
360 | |||
361 | |||
362 | typedef struct me_cfg_pci_hw_location { | ||
363 | unsigned int bus_type; | ||
364 | unsigned int bus_no; | ||
365 | unsigned int device_no; | ||
366 | unsigned int function_no; | ||
367 | } me_cfg_pci_hw_location_t; | ||
368 | |||
369 | /* | ||
370 | typedef struct me_cfg_usb_hw_location { | ||
371 | unsigned int bus_type; | ||
372 | unsigned int root_hub_no; | ||
373 | } me_cfg_usb_hw_location_t; | ||
374 | */ | ||
375 | |||
376 | typedef union me_cfg_hw_location { | ||
377 | unsigned int bus_type; | ||
378 | me_cfg_pci_hw_location_t pci; | ||
379 | // me_cfg_usb_hw_location_t usb; | ||
380 | } me_cfg_hw_location_t; | ||
381 | |||
382 | |||
383 | typedef struct me_cfg_device_info { | ||
384 | unsigned int vendor_id; | ||
385 | unsigned int device_id; | ||
386 | unsigned int serial_no; | ||
387 | me_cfg_hw_location_t hw_location; | ||
388 | } me_cfg_device_info_t; | ||
389 | |||
390 | |||
391 | typedef struct me_cfg_subdevice_info { | ||
392 | int type; | ||
393 | int sub_type; | ||
394 | unsigned int number_channels; | ||
395 | } me_cfg_subdevice_info_t; | ||
396 | |||
397 | |||
398 | typedef struct me_cfg_range_entry { | ||
399 | int unit; | ||
400 | double min; | ||
401 | double max; | ||
402 | unsigned int max_data; | ||
403 | } me_cfg_range_entry_t; | ||
404 | |||
405 | |||
406 | typedef struct me_cfg_mux32m_device { | ||
407 | int type; | ||
408 | int timed; | ||
409 | unsigned int ai_channel; | ||
410 | unsigned int dio_device; | ||
411 | unsigned int dio_subdevice; | ||
412 | unsigned int timer_device; | ||
413 | unsigned int timer_subdevice; | ||
414 | unsigned int mux32s_count; | ||
415 | } me_cfg_mux32m_device_t; | ||
416 | |||
417 | |||
418 | typedef struct me_cfg_demux32_device { | ||
419 | int type; | ||
420 | int timed; | ||
421 | unsigned int ao_channel; | ||
422 | unsigned int dio_device; | ||
423 | unsigned int dio_subdevice; | ||
424 | unsigned int timer_device; | ||
425 | unsigned int timer_subdevice; | ||
426 | } me_cfg_demux32_device_t; | ||
427 | |||
428 | |||
429 | typedef union me_cfg_external_device { | ||
430 | int type; | ||
431 | me_cfg_mux32m_device_t mux32m; | ||
432 | me_cfg_demux32_device_t demux32; | ||
433 | } me_cfg_external_device_t; | ||
434 | |||
435 | |||
436 | typedef struct me_cfg_subdevice_entry { | ||
437 | me_cfg_subdevice_info_t info; | ||
438 | me_cfg_range_entry_t *range_list; | ||
439 | unsigned int count; | ||
440 | int locked; | ||
441 | me_cfg_external_device_t external_device; | ||
442 | } me_cfg_subdevice_entry_t; | ||
443 | |||
444 | |||
445 | typedef struct me_cfg_device_entry { | ||
446 | me_cfg_tcpip_t tcpip; | ||
447 | me_cfg_device_info_t info; | ||
448 | me_cfg_subdevice_entry_t *subdevice_list; | ||
449 | unsigned int count; | ||
450 | } me_cfg_device_entry_t; | ||
451 | |||
452 | |||
453 | typedef struct me_config_load { | ||
454 | me_cfg_device_entry_t *device_list; | ||
455 | unsigned int count; | ||
456 | int errno; | ||
457 | } me_config_load_t; | ||
458 | |||
459 | |||
460 | /*============================================================================= | ||
461 | The ioctls of the board | ||
462 | ===========================================================================*/ | ||
463 | |||
464 | #define MEMAIN_MAGIC 'y' | ||
465 | |||
466 | #define ME_IO_IRQ_ENABLE _IOR (MEMAIN_MAGIC, 1, me_io_irq_start_t) | ||
467 | #define ME_IO_IRQ_WAIT _IOR (MEMAIN_MAGIC, 2, me_io_irq_wait_t) | ||
468 | #define ME_IO_IRQ_DISABLE _IOR (MEMAIN_MAGIC, 3, me_io_irq_stop_t) | ||
469 | |||
470 | #define ME_IO_RESET_DEVICE _IOW (MEMAIN_MAGIC, 4, me_io_reset_device_t) | ||
471 | #define ME_IO_RESET_SUBDEVICE _IOW (MEMAIN_MAGIC, 5, me_io_reset_subdevice_t) | ||
472 | |||
473 | #define ME_IO_SINGLE _IOWR(MEMAIN_MAGIC, 6, me_io_single_t) | ||
474 | #define ME_IO_SINGLE_CONFIG _IOW (MEMAIN_MAGIC, 7, me_io_single_config_t) | ||
475 | |||
476 | #define ME_IO_STREAM_CONFIG _IOW (MEMAIN_MAGIC, 8, me_io_stream_config_t) | ||
477 | #define ME_IO_STREAM_NEW_VALUES _IOR (MEMAIN_MAGIC, 9, me_io_stream_new_values_t) | ||
478 | #define ME_IO_STREAM_READ _IOR (MEMAIN_MAGIC, 10, me_io_stream_read_t) | ||
479 | #define ME_IO_STREAM_START _IOW (MEMAIN_MAGIC, 11, me_io_stream_start_t) | ||
480 | #define ME_IO_STREAM_STATUS _IOR (MEMAIN_MAGIC, 12, me_io_stream_status_t) | ||
481 | #define ME_IO_STREAM_STOP _IOW (MEMAIN_MAGIC, 13, me_io_stream_stop_t) | ||
482 | #define ME_IO_STREAM_WRITE _IOW (MEMAIN_MAGIC, 14, me_io_stream_write_t) | ||
483 | |||
484 | #define ME_LOCK_DRIVER _IOW (MEMAIN_MAGIC, 15, me_lock_driver_t) | ||
485 | #define ME_LOCK_DEVICE _IOW (MEMAIN_MAGIC, 16, me_lock_device_t) | ||
486 | #define ME_LOCK_SUBDEVICE _IOW (MEMAIN_MAGIC, 17, me_lock_subdevice_t) | ||
487 | |||
488 | #define ME_QUERY_DESCRIPTION_DEVICE _IOR (MEMAIN_MAGIC, 18, me_query_description_device_t) | ||
489 | |||
490 | #define ME_QUERY_INFO_DEVICE _IOR (MEMAIN_MAGIC, 19, me_query_info_device_t) | ||
491 | |||
492 | #define ME_QUERY_NAME_DEVICE _IOR (MEMAIN_MAGIC, 20, me_query_name_device_t) | ||
493 | #define ME_QUERY_NAME_DEVICE_DRIVER _IOR (MEMAIN_MAGIC, 21, me_query_name_device_driver_t) | ||
494 | |||
495 | #define ME_QUERY_NUMBER_DEVICES _IOR (MEMAIN_MAGIC, 22, me_query_number_devices_t) | ||
496 | #define ME_QUERY_NUMBER_SUBDEVICES _IOR (MEMAIN_MAGIC, 23, me_query_number_subdevices_t) | ||
497 | #define ME_QUERY_NUMBER_CHANNELS _IOR (MEMAIN_MAGIC, 24, me_query_number_channels_t) | ||
498 | #define ME_QUERY_NUMBER_RANGES _IOR (MEMAIN_MAGIC, 25, me_query_number_ranges_t) | ||
499 | |||
500 | #define ME_QUERY_RANGE_BY_MIN_MAX _IOR (MEMAIN_MAGIC, 26, me_query_range_by_min_max_t) | ||
501 | #define ME_QUERY_RANGE_INFO _IOR (MEMAIN_MAGIC, 27, me_query_range_info_t) | ||
502 | |||
503 | #define ME_QUERY_SUBDEVICE_BY_TYPE _IOR (MEMAIN_MAGIC, 28, me_query_subdevice_by_type_t) | ||
504 | #define ME_QUERY_SUBDEVICE_TYPE _IOR (MEMAIN_MAGIC, 29, me_query_subdevice_type_t) | ||
505 | #define ME_QUERY_SUBDEVICE_CAPS _IOR (MEMAIN_MAGIC, 29, me_query_subdevice_caps_t) | ||
506 | #define ME_QUERY_SUBDEVICE_CAPS_ARGS _IOR (MEMAIN_MAGIC, 30, me_query_subdevice_caps_args_t) | ||
507 | |||
508 | #define ME_QUERY_TIMER _IOR (MEMAIN_MAGIC, 31, me_query_timer_t) | ||
509 | |||
510 | #define ME_QUERY_VERSION_DEVICE_DRIVER _IOR (MEMAIN_MAGIC, 32, me_query_version_device_driver_t) | ||
511 | #define ME_QUERY_VERSION_MAIN_DRIVER _IOR (MEMAIN_MAGIC, 33, me_query_version_main_driver_t) | ||
512 | |||
513 | #define ME_CONFIG_LOAD _IOWR(MEMAIN_MAGIC, 34, me_config_load_t) | ||
514 | |||
515 | #endif | ||
diff --git a/drivers/staging/meilhaus/memain.c b/drivers/staging/meilhaus/memain.c new file mode 100644 index 000000000000..6cdeb8582453 --- /dev/null +++ b/drivers/staging/meilhaus/memain.c | |||
@@ -0,0 +1,2022 @@ | |||
1 | /** | ||
2 | * @file memain.c | ||
3 | * | ||
4 | * @brief Main Meilhaus device driver. | ||
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 | #include <linux/pci.h> | ||
38 | //#include <linux/usb.h> | ||
39 | #include <linux/errno.h> | ||
40 | #include <asm/uaccess.h> | ||
41 | #include <linux/cdev.h> | ||
42 | #include <linux/rwsem.h> | ||
43 | |||
44 | #include "medefines.h" | ||
45 | #include "metypes.h" | ||
46 | #include "meerror.h" | ||
47 | |||
48 | #include "medebug.h" | ||
49 | #include "memain.h" | ||
50 | #include "medevice.h" | ||
51 | #include "meioctl.h" | ||
52 | #include "mecommon.h" | ||
53 | |||
54 | /* Module parameters | ||
55 | */ | ||
56 | |||
57 | #ifdef BOSCH | ||
58 | static unsigned int me_bosch_fw = 0; | ||
59 | |||
60 | # ifdef module_param | ||
61 | module_param(me_bosch_fw, int, S_IRUGO); | ||
62 | # else | ||
63 | MODULE_PARM(me_bosch_fw, "i"); | ||
64 | # endif | ||
65 | |||
66 | MODULE_PARM_DESC(me_bosch_fw, | ||
67 | "Flags which signals the ME-4600 driver to load the bosch firmware (default = 0)."); | ||
68 | #endif //BOSCH | ||
69 | |||
70 | static unsigned int major = 0; | ||
71 | #ifdef module_param | ||
72 | module_param(major, int, S_IRUGO); | ||
73 | #else | ||
74 | MODULE_PARM(major, "i"); | ||
75 | #endif | ||
76 | |||
77 | /* Global Driver Lock | ||
78 | */ | ||
79 | |||
80 | static struct file *me_filep = NULL; | ||
81 | static int me_count = 0; | ||
82 | static spinlock_t me_lock = SPIN_LOCK_UNLOCKED; | ||
83 | static DECLARE_RWSEM(me_rwsem); | ||
84 | |||
85 | /* Board instances are kept in a global list */ | ||
86 | LIST_HEAD(me_device_list); | ||
87 | |||
88 | /* Prototypes | ||
89 | */ | ||
90 | |||
91 | static int me_probe_pci(struct pci_dev *dev, const struct pci_device_id *id); | ||
92 | static void me_remove_pci(struct pci_dev *dev); | ||
93 | static int insert_to_device_list(me_device_t * n_device); | ||
94 | static int replace_with_dummy(int vendor_id, int device_id, int serial_no); | ||
95 | static void clear_device_list(void); | ||
96 | static int me_open(struct inode *inode_ptr, struct file *filep); | ||
97 | static int me_release(struct inode *, struct file *); | ||
98 | static int me_ioctl(struct inode *, struct file *, unsigned int, unsigned long); | ||
99 | //static int me_probe_usb(struct usb_interface *interface, const struct usb_device_id *id); | ||
100 | //static void me_disconnect_usb(struct usb_interface *interface); | ||
101 | |||
102 | /* Character device structure | ||
103 | */ | ||
104 | |||
105 | static struct cdev *cdevp; | ||
106 | |||
107 | /* File operations provided by the module | ||
108 | */ | ||
109 | |||
110 | static struct file_operations me_file_operations = { | ||
111 | .owner = THIS_MODULE, | ||
112 | .ioctl = me_ioctl, | ||
113 | .open = me_open, | ||
114 | .release = me_release, | ||
115 | }; | ||
116 | |||
117 | struct pci_driver me_pci_driver = { | ||
118 | .name = MEMAIN_NAME, | ||
119 | .id_table = me_pci_table, | ||
120 | .probe = me_probe_pci, | ||
121 | .remove = me_remove_pci | ||
122 | }; | ||
123 | |||
124 | /* //me_usb_driver | ||
125 | static struct usb_driver me_usb_driver = | ||
126 | { | ||
127 | .name = MEMAIN_NAME, | ||
128 | .id_table = me_usb_table, | ||
129 | .probe = me_probe_usb, | ||
130 | .disconnect = me_disconnect_usb | ||
131 | }; | ||
132 | */ | ||
133 | |||
134 | #ifdef ME_LOCK_MULTIPLEX_TEMPLATE | ||
135 | ME_LOCK_MULTIPLEX_TEMPLATE("me_lock_device", | ||
136 | me_lock_device_t, | ||
137 | me_lock_device, | ||
138 | me_device_lock_device, | ||
139 | (device, filep, karg.lock, karg.flags)) | ||
140 | |||
141 | ME_LOCK_MULTIPLEX_TEMPLATE("me_lock_subdevice", | ||
142 | me_lock_subdevice_t, | ||
143 | me_lock_subdevice, | ||
144 | me_device_lock_subdevice, | ||
145 | (device, filep, karg.subdevice, karg.lock, | ||
146 | karg.flags)) | ||
147 | #else | ||
148 | #error macro ME_LOCK_MULTIPLEX_TEMPLATE not defined | ||
149 | #endif | ||
150 | |||
151 | #ifdef ME_IO_MULTIPLEX_TEMPLATE | ||
152 | ME_IO_MULTIPLEX_TEMPLATE("me_io_irq_start", | ||
153 | me_io_irq_start_t, | ||
154 | me_io_irq_start, | ||
155 | me_device_io_irq_start, | ||
156 | (device, | ||
157 | filep, | ||
158 | karg.subdevice, | ||
159 | karg.channel, | ||
160 | karg.irq_source, | ||
161 | karg.irq_edge, karg.irq_arg, karg.flags)) | ||
162 | |||
163 | ME_IO_MULTIPLEX_TEMPLATE("me_io_irq_wait", | ||
164 | me_io_irq_wait_t, | ||
165 | me_io_irq_wait, | ||
166 | me_device_io_irq_wait, | ||
167 | (device, | ||
168 | filep, | ||
169 | karg.subdevice, | ||
170 | karg.channel, | ||
171 | &karg.irq_count, &karg.value, karg.time_out, karg.flags)) | ||
172 | |||
173 | ME_IO_MULTIPLEX_TEMPLATE("me_io_irq_stop", | ||
174 | me_io_irq_stop_t, | ||
175 | me_io_irq_stop, | ||
176 | me_device_io_irq_stop, | ||
177 | (device, | ||
178 | filep, karg.subdevice, karg.channel, karg.flags)) | ||
179 | |||
180 | ME_IO_MULTIPLEX_TEMPLATE("me_io_reset_device", | ||
181 | me_io_reset_device_t, | ||
182 | me_io_reset_device, | ||
183 | me_device_io_reset_device, (device, filep, karg.flags)) | ||
184 | |||
185 | ME_IO_MULTIPLEX_TEMPLATE("me_io_reset_subdevice", | ||
186 | me_io_reset_subdevice_t, | ||
187 | me_io_reset_subdevice, | ||
188 | me_device_io_reset_subdevice, | ||
189 | (device, filep, karg.subdevice, karg.flags)) | ||
190 | |||
191 | ME_IO_MULTIPLEX_TEMPLATE("me_io_single_config", | ||
192 | me_io_single_config_t, | ||
193 | me_io_single_config, | ||
194 | me_device_io_single_config, | ||
195 | (device, | ||
196 | filep, | ||
197 | karg.subdevice, | ||
198 | karg.channel, | ||
199 | karg.single_config, | ||
200 | karg.ref, | ||
201 | karg.trig_chan, | ||
202 | karg.trig_type, karg.trig_edge, karg.flags)) | ||
203 | |||
204 | ME_IO_MULTIPLEX_TEMPLATE("me_io_stream_new_values", | ||
205 | me_io_stream_new_values_t, | ||
206 | me_io_stream_new_values, | ||
207 | me_device_io_stream_new_values, | ||
208 | (device, | ||
209 | filep, | ||
210 | karg.subdevice, karg.time_out, &karg.count, karg.flags)) | ||
211 | |||
212 | ME_IO_MULTIPLEX_TEMPLATE("me_io_stream_read", | ||
213 | me_io_stream_read_t, | ||
214 | me_io_stream_read, | ||
215 | me_device_io_stream_read, | ||
216 | (device, | ||
217 | filep, | ||
218 | karg.subdevice, | ||
219 | karg.read_mode, karg.values, &karg.count, karg.flags)) | ||
220 | |||
221 | ME_IO_MULTIPLEX_TEMPLATE("me_io_stream_status", | ||
222 | me_io_stream_status_t, | ||
223 | me_io_stream_status, | ||
224 | me_device_io_stream_status, | ||
225 | (device, | ||
226 | filep, | ||
227 | karg.subdevice, | ||
228 | karg.wait, &karg.status, &karg.count, karg.flags)) | ||
229 | |||
230 | ME_IO_MULTIPLEX_TEMPLATE("me_io_stream_write", | ||
231 | me_io_stream_write_t, | ||
232 | me_io_stream_write, | ||
233 | me_device_io_stream_write, | ||
234 | (device, | ||
235 | filep, | ||
236 | karg.subdevice, | ||
237 | karg.write_mode, karg.values, &karg.count, karg.flags)) | ||
238 | #else | ||
239 | #error macro ME_IO_MULTIPLEX_TEMPLATE not defined | ||
240 | #endif | ||
241 | |||
242 | #ifdef ME_QUERY_MULTIPLEX_STR_TEMPLATE | ||
243 | ME_QUERY_MULTIPLEX_STR_TEMPLATE("me_query_name_device", | ||
244 | me_query_name_device_t, | ||
245 | me_query_name_device, | ||
246 | me_device_query_name_device, (device, &msg)) | ||
247 | |||
248 | ME_QUERY_MULTIPLEX_STR_TEMPLATE("me_query_name_device_driver", | ||
249 | me_query_name_device_driver_t, | ||
250 | me_query_name_device_driver, | ||
251 | me_device_query_name_device_driver, | ||
252 | (device, &msg)) | ||
253 | |||
254 | ME_QUERY_MULTIPLEX_STR_TEMPLATE("me_query_description_device", | ||
255 | me_query_description_device_t, | ||
256 | me_query_description_device, | ||
257 | me_device_query_description_device, | ||
258 | (device, &msg)) | ||
259 | #else | ||
260 | #error macro ME_QUERY_MULTIPLEX_STR_TEMPLATE not defined | ||
261 | #endif | ||
262 | |||
263 | #ifdef ME_QUERY_MULTIPLEX_TEMPLATE | ||
264 | ME_QUERY_MULTIPLEX_TEMPLATE("me_query_info_device", | ||
265 | me_query_info_device_t, | ||
266 | me_query_info_device, | ||
267 | me_device_query_info_device, | ||
268 | (device, | ||
269 | &karg.vendor_id, | ||
270 | &karg.device_id, | ||
271 | &karg.serial_no, | ||
272 | &karg.bus_type, | ||
273 | &karg.bus_no, | ||
274 | &karg.dev_no, &karg.func_no, &karg.plugged)) | ||
275 | |||
276 | ME_QUERY_MULTIPLEX_TEMPLATE("me_query_number_subdevices", | ||
277 | me_query_number_subdevices_t, | ||
278 | me_query_number_subdevices, | ||
279 | me_device_query_number_subdevices, | ||
280 | (device, &karg.number)) | ||
281 | |||
282 | ME_QUERY_MULTIPLEX_TEMPLATE("me_query_number_channels", | ||
283 | me_query_number_channels_t, | ||
284 | me_query_number_channels, | ||
285 | me_device_query_number_channels, | ||
286 | (device, karg.subdevice, &karg.number)) | ||
287 | |||
288 | ME_QUERY_MULTIPLEX_TEMPLATE("me_query_subdevice_by_type", | ||
289 | me_query_subdevice_by_type_t, | ||
290 | me_query_subdevice_by_type, | ||
291 | me_device_query_subdevice_by_type, | ||
292 | (device, | ||
293 | karg.start_subdevice, | ||
294 | karg.type, karg.subtype, &karg.subdevice)) | ||
295 | |||
296 | ME_QUERY_MULTIPLEX_TEMPLATE("me_query_subdevice_type", | ||
297 | me_query_subdevice_type_t, | ||
298 | me_query_subdevice_type, | ||
299 | me_device_query_subdevice_type, | ||
300 | (device, karg.subdevice, &karg.type, &karg.subtype)) | ||
301 | |||
302 | ME_QUERY_MULTIPLEX_TEMPLATE("me_query_subdevice_caps", | ||
303 | me_query_subdevice_caps_t, | ||
304 | me_query_subdevice_caps, | ||
305 | me_device_query_subdevice_caps, | ||
306 | (device, karg.subdevice, &karg.caps)) | ||
307 | |||
308 | ME_QUERY_MULTIPLEX_TEMPLATE("me_query_subdevice_caps_args", | ||
309 | me_query_subdevice_caps_args_t, | ||
310 | me_query_subdevice_caps_args, | ||
311 | me_device_query_subdevice_caps_args, | ||
312 | (device, karg.subdevice, karg.cap, karg.args, | ||
313 | karg.count)) | ||
314 | |||
315 | ME_QUERY_MULTIPLEX_TEMPLATE("me_query_number_ranges", | ||
316 | me_query_number_ranges_t, | ||
317 | me_query_number_ranges, | ||
318 | me_device_query_number_ranges, | ||
319 | (device, karg.subdevice, karg.unit, &karg.number)) | ||
320 | |||
321 | ME_QUERY_MULTIPLEX_TEMPLATE("me_query_range_by_min_max", | ||
322 | me_query_range_by_min_max_t, | ||
323 | me_query_range_by_min_max, | ||
324 | me_device_query_range_by_min_max, | ||
325 | (device, | ||
326 | karg.subdevice, | ||
327 | karg.unit, | ||
328 | &karg.min, &karg.max, &karg.max_data, &karg.range)) | ||
329 | |||
330 | ME_QUERY_MULTIPLEX_TEMPLATE("me_query_range_info", | ||
331 | me_query_range_info_t, | ||
332 | me_query_range_info, | ||
333 | me_device_query_range_info, | ||
334 | (device, | ||
335 | karg.subdevice, | ||
336 | karg.range, | ||
337 | &karg.unit, &karg.min, &karg.max, &karg.max_data)) | ||
338 | |||
339 | ME_QUERY_MULTIPLEX_TEMPLATE("me_query_timer", | ||
340 | me_query_timer_t, | ||
341 | me_query_timer, | ||
342 | me_device_query_timer, | ||
343 | (device, | ||
344 | karg.subdevice, | ||
345 | karg.timer, | ||
346 | &karg.base_frequency, | ||
347 | &karg.min_ticks, &karg.max_ticks)) | ||
348 | |||
349 | ME_QUERY_MULTIPLEX_TEMPLATE("me_query_version_device_driver", | ||
350 | me_query_version_device_driver_t, | ||
351 | me_query_version_device_driver, | ||
352 | me_device_query_version_device_driver, | ||
353 | (device, &karg.version)) | ||
354 | #else | ||
355 | #error macro ME_QUERY_MULTIPLEX_TEMPLATE not defined | ||
356 | #endif | ||
357 | |||
358 | /** ******************************************************************************** **/ | ||
359 | |||
360 | static me_device_t *get_dummy_instance(unsigned short vendor_id, | ||
361 | unsigned short device_id, | ||
362 | unsigned int serial_no, | ||
363 | int bus_type, | ||
364 | int bus_no, int dev_no, int func_no) | ||
365 | { | ||
366 | int err; | ||
367 | me_dummy_constructor_t constructor = NULL; | ||
368 | me_device_t *instance; | ||
369 | |||
370 | PDEBUG("executed.\n"); | ||
371 | |||
372 | if ((constructor = symbol_get(medummy_constructor)) == NULL) { | ||
373 | err = request_module(MEDUMMY_NAME); | ||
374 | |||
375 | if (err) { | ||
376 | PERROR("Error while request for module %s.\n", | ||
377 | MEDUMMY_NAME); | ||
378 | return NULL; | ||
379 | } | ||
380 | |||
381 | if ((constructor = symbol_get(medummy_constructor)) == NULL) { | ||
382 | PERROR("Can't get %s driver module constructor.\n", | ||
383 | MEDUMMY_NAME); | ||
384 | return NULL; | ||
385 | } | ||
386 | } | ||
387 | |||
388 | if ((instance = (*constructor) (vendor_id, | ||
389 | device_id, | ||
390 | serial_no, | ||
391 | bus_type, | ||
392 | bus_no, dev_no, func_no)) == NULL) | ||
393 | symbol_put(medummy_constructor); | ||
394 | |||
395 | return instance; | ||
396 | } | ||
397 | |||
398 | static int me_probe_pci(struct pci_dev *dev, const struct pci_device_id *id) | ||
399 | { | ||
400 | int err; | ||
401 | me_pci_constructor_t constructor = NULL; | ||
402 | #ifdef BOSCH | ||
403 | me_bosch_constructor_t constructor_bosch = NULL; | ||
404 | #endif | ||
405 | me_device_t *n_device = NULL; | ||
406 | uint32_t device; | ||
407 | |||
408 | char constructor_name[24] = "me0000_pci_constructor"; | ||
409 | char module_name[7] = "me0000"; | ||
410 | |||
411 | PDEBUG("executed.\n"); | ||
412 | device = dev->device; | ||
413 | if ((device & 0xF000) == 0x6000) { // Exceptions: me61xx, me62xx, me63xx are handled by one driver. | ||
414 | device &= 0xF0FF; | ||
415 | } | ||
416 | |||
417 | constructor_name[2] += (char)((device >> 12) & 0x000F); | ||
418 | constructor_name[3] += (char)((device >> 8) & 0x000F); | ||
419 | PDEBUG("constructor_name: %s\n", constructor_name); | ||
420 | module_name[2] += (char)((device >> 12) & 0x000F); | ||
421 | module_name[3] += (char)((device >> 8) & 0x000F); | ||
422 | PDEBUG("module_name: %s\n", module_name); | ||
423 | |||
424 | if ((constructor = | ||
425 | (me_pci_constructor_t) __symbol_get(constructor_name)) == NULL) { | ||
426 | if (request_module(module_name)) { | ||
427 | PERROR("Error while request for module %s.\n", | ||
428 | module_name); | ||
429 | return -ENODEV; | ||
430 | } | ||
431 | |||
432 | if ((constructor = | ||
433 | (me_pci_constructor_t) __symbol_get(constructor_name)) == | ||
434 | NULL) { | ||
435 | PERROR("Can't get %s driver module constructor.\n", | ||
436 | module_name); | ||
437 | return -ENODEV; | ||
438 | } | ||
439 | } | ||
440 | #ifdef BOSCH | ||
441 | if ((device & 0xF000) == 0x4000) { // Bosch build has differnt constructor for me4600. | ||
442 | if ((n_device = | ||
443 | (*constructor_bosch) (dev, me_bosch_fw)) == NULL) { | ||
444 | __symbol_put(constructor_name); | ||
445 | PERROR | ||
446 | ("Can't get device instance of %s driver module.\n", | ||
447 | module_name); | ||
448 | return -ENODEV; | ||
449 | } | ||
450 | } else { | ||
451 | #endif | ||
452 | if ((n_device = (*constructor) (dev)) == NULL) { | ||
453 | __symbol_put(constructor_name); | ||
454 | PERROR | ||
455 | ("Can't get device instance of %s driver module.\n", | ||
456 | module_name); | ||
457 | return -ENODEV; | ||
458 | } | ||
459 | #ifdef BOSCH | ||
460 | } | ||
461 | #endif | ||
462 | |||
463 | insert_to_device_list(n_device); | ||
464 | err = | ||
465 | n_device->me_device_io_reset_device(n_device, NULL, | ||
466 | ME_IO_RESET_DEVICE_NO_FLAGS); | ||
467 | if (err) { | ||
468 | PERROR("Error while reseting device.\n"); | ||
469 | } else { | ||
470 | PDEBUG("Reseting device was sucessful.\n"); | ||
471 | } | ||
472 | return ME_ERRNO_SUCCESS; | ||
473 | } | ||
474 | |||
475 | static void release_instance(me_device_t * device) | ||
476 | { | ||
477 | int vendor_id; | ||
478 | int device_id; | ||
479 | int serial_no; | ||
480 | int bus_type; | ||
481 | int bus_no; | ||
482 | int dev_no; | ||
483 | int func_no; | ||
484 | int plugged; | ||
485 | |||
486 | uint32_t dev_id; | ||
487 | |||
488 | char constructor_name[24] = "me0000_pci_constructor"; | ||
489 | |||
490 | PDEBUG("executed.\n"); | ||
491 | |||
492 | device->me_device_query_info_device(device, | ||
493 | &vendor_id, | ||
494 | &device_id, | ||
495 | &serial_no, | ||
496 | &bus_type, | ||
497 | &bus_no, | ||
498 | &dev_no, &func_no, &plugged); | ||
499 | |||
500 | dev_id = device_id; | ||
501 | device->me_device_destructor(device); | ||
502 | |||
503 | if (plugged != ME_PLUGGED_IN) { | ||
504 | PDEBUG("release: medummy_constructor\n"); | ||
505 | |||
506 | __symbol_put("medummy_constructor"); | ||
507 | } else { | ||
508 | if ((dev_id & 0xF000) == 0x6000) { // Exceptions: me61xx, me62xx, me63xx are handled by one driver. | ||
509 | dev_id &= 0xF0FF; | ||
510 | } | ||
511 | |||
512 | constructor_name[2] += (char)((dev_id >> 12) & 0x000F); | ||
513 | constructor_name[3] += (char)((dev_id >> 8) & 0x000F); | ||
514 | PDEBUG("release: %s\n", constructor_name); | ||
515 | |||
516 | __symbol_put(constructor_name); | ||
517 | } | ||
518 | } | ||
519 | |||
520 | static int insert_to_device_list(me_device_t * n_device) | ||
521 | { | ||
522 | me_device_t *o_device = NULL; | ||
523 | |||
524 | struct list_head *pos; | ||
525 | int n_vendor_id; | ||
526 | int n_device_id; | ||
527 | int n_serial_no; | ||
528 | int n_bus_type; | ||
529 | int n_bus_no; | ||
530 | int n_dev_no; | ||
531 | int n_func_no; | ||
532 | int n_plugged; | ||
533 | int o_vendor_id; | ||
534 | int o_device_id; | ||
535 | int o_serial_no; | ||
536 | int o_bus_type; | ||
537 | int o_bus_no; | ||
538 | int o_dev_no; | ||
539 | int o_func_no; | ||
540 | int o_plugged; | ||
541 | |||
542 | PDEBUG("executed.\n"); | ||
543 | |||
544 | n_device->me_device_query_info_device(n_device, | ||
545 | &n_vendor_id, | ||
546 | &n_device_id, | ||
547 | &n_serial_no, | ||
548 | &n_bus_type, | ||
549 | &n_bus_no, | ||
550 | &n_dev_no, | ||
551 | &n_func_no, &n_plugged); | ||
552 | |||
553 | down_write(&me_rwsem); | ||
554 | |||
555 | list_for_each(pos, &me_device_list) { | ||
556 | o_device = list_entry(pos, me_device_t, list); | ||
557 | o_device->me_device_query_info_device(o_device, | ||
558 | &o_vendor_id, | ||
559 | &o_device_id, | ||
560 | &o_serial_no, | ||
561 | &o_bus_type, | ||
562 | &o_bus_no, | ||
563 | &o_dev_no, | ||
564 | &o_func_no, &o_plugged); | ||
565 | |||
566 | if (o_plugged == ME_PLUGGED_OUT) { | ||
567 | if (((o_vendor_id == n_vendor_id) && | ||
568 | (o_device_id == n_device_id) && | ||
569 | (o_serial_no == n_serial_no) && | ||
570 | (o_bus_type == n_bus_type)) || | ||
571 | ((o_vendor_id == n_vendor_id) && | ||
572 | (o_device_id == n_device_id) && | ||
573 | (o_bus_type == n_bus_type) && | ||
574 | (o_bus_no == n_bus_no) && | ||
575 | (o_dev_no == n_dev_no) && | ||
576 | (o_func_no == n_func_no))) { | ||
577 | n_device->list.prev = pos->prev; | ||
578 | n_device->list.next = pos->next; | ||
579 | pos->prev->next = &n_device->list; | ||
580 | pos->next->prev = &n_device->list; | ||
581 | release_instance(o_device); | ||
582 | break; | ||
583 | } | ||
584 | } | ||
585 | } | ||
586 | |||
587 | if (pos == &me_device_list) { | ||
588 | list_add_tail(&n_device->list, &me_device_list); | ||
589 | } | ||
590 | |||
591 | up_write(&me_rwsem); | ||
592 | |||
593 | return 0; | ||
594 | } | ||
595 | |||
596 | static void me_remove_pci(struct pci_dev *dev) | ||
597 | { | ||
598 | int vendor_id = dev->vendor; | ||
599 | int device_id = dev->device; | ||
600 | int subsystem_vendor = dev->subsystem_vendor; | ||
601 | int subsystem_device = dev->subsystem_device; | ||
602 | int serial_no = (subsystem_device << 16) | subsystem_vendor; | ||
603 | |||
604 | PDEBUG("executed.\n"); | ||
605 | |||
606 | PINFO("Vendor id = 0x%08X\n", vendor_id); | ||
607 | PINFO("Device id = 0x%08X\n", device_id); | ||
608 | PINFO("Serial Number = 0x%08X\n", serial_no); | ||
609 | |||
610 | replace_with_dummy(vendor_id, device_id, serial_no); | ||
611 | } | ||
612 | |||
613 | static int replace_with_dummy(int vendor_id, int device_id, int serial_no) | ||
614 | { | ||
615 | |||
616 | struct list_head *pos; | ||
617 | me_device_t *n_device = NULL; | ||
618 | me_device_t *o_device = NULL; | ||
619 | int o_vendor_id; | ||
620 | int o_device_id; | ||
621 | int o_serial_no; | ||
622 | int o_bus_type; | ||
623 | int o_bus_no; | ||
624 | int o_dev_no; | ||
625 | int o_func_no; | ||
626 | int o_plugged; | ||
627 | |||
628 | PDEBUG("executed.\n"); | ||
629 | |||
630 | down_write(&me_rwsem); | ||
631 | |||
632 | list_for_each(pos, &me_device_list) { | ||
633 | o_device = list_entry(pos, me_device_t, list); | ||
634 | o_device->me_device_query_info_device(o_device, | ||
635 | &o_vendor_id, | ||
636 | &o_device_id, | ||
637 | &o_serial_no, | ||
638 | &o_bus_type, | ||
639 | &o_bus_no, | ||
640 | &o_dev_no, | ||
641 | &o_func_no, &o_plugged); | ||
642 | |||
643 | if (o_plugged == ME_PLUGGED_IN) { | ||
644 | if (((o_vendor_id == vendor_id) && | ||
645 | (o_device_id == device_id) && | ||
646 | (o_serial_no == serial_no))) { | ||
647 | n_device = get_dummy_instance(o_vendor_id, | ||
648 | o_device_id, | ||
649 | o_serial_no, | ||
650 | o_bus_type, | ||
651 | o_bus_no, | ||
652 | o_dev_no, | ||
653 | o_func_no); | ||
654 | |||
655 | if (!n_device) { | ||
656 | up_write(&me_rwsem); | ||
657 | PERROR("Cannot get dummy instance.\n"); | ||
658 | return 1; | ||
659 | } | ||
660 | |||
661 | n_device->list.prev = pos->prev; | ||
662 | |||
663 | n_device->list.next = pos->next; | ||
664 | pos->prev->next = &n_device->list; | ||
665 | pos->next->prev = &n_device->list; | ||
666 | release_instance(o_device); | ||
667 | break; | ||
668 | } | ||
669 | } | ||
670 | } | ||
671 | |||
672 | up_write(&me_rwsem); | ||
673 | |||
674 | return 0; | ||
675 | } | ||
676 | |||
677 | static void clear_device_list(void) | ||
678 | { | ||
679 | |||
680 | struct list_head *entry; | ||
681 | me_device_t *device; | ||
682 | |||
683 | // Clear the device info list . | ||
684 | down_write(&me_rwsem); | ||
685 | |||
686 | while (!list_empty(&me_device_list)) { | ||
687 | entry = me_device_list.next; | ||
688 | device = list_entry(entry, me_device_t, list); | ||
689 | list_del(entry); | ||
690 | release_instance(device); | ||
691 | } | ||
692 | |||
693 | up_write(&me_rwsem); | ||
694 | } | ||
695 | |||
696 | static int lock_driver(struct file *filep, int lock, int flags) | ||
697 | { | ||
698 | int err = ME_ERRNO_SUCCESS; | ||
699 | me_device_t *device; | ||
700 | |||
701 | PDEBUG("executed.\n"); | ||
702 | |||
703 | down_read(&me_rwsem); | ||
704 | |||
705 | spin_lock(&me_lock); | ||
706 | |||
707 | switch (lock) { | ||
708 | |||
709 | case ME_LOCK_SET: | ||
710 | if (me_count) { | ||
711 | PERROR | ||
712 | ("Driver System is currently used by another process.\n"); | ||
713 | err = ME_ERRNO_USED; | ||
714 | } else if ((me_filep != NULL) && (me_filep != filep)) { | ||
715 | PERROR | ||
716 | ("Driver System is already logged by another process.\n"); | ||
717 | err = ME_ERRNO_LOCKED; | ||
718 | } else { | ||
719 | list_for_each_entry(device, &me_device_list, list) { | ||
720 | err = | ||
721 | device->me_device_lock_device(device, filep, | ||
722 | ME_LOCK_CHECK, | ||
723 | flags); | ||
724 | |||
725 | if (err) | ||
726 | break; | ||
727 | } | ||
728 | |||
729 | if (!err) | ||
730 | me_filep = filep; | ||
731 | } | ||
732 | |||
733 | break; | ||
734 | |||
735 | case ME_LOCK_RELEASE: | ||
736 | if ((me_filep != NULL) && (me_filep != filep)) { | ||
737 | err = ME_ERRNO_SUCCESS; | ||
738 | } else { | ||
739 | list_for_each_entry(device, &me_device_list, list) { | ||
740 | device->me_device_lock_device(device, filep, | ||
741 | ME_LOCK_RELEASE, | ||
742 | flags); | ||
743 | } | ||
744 | |||
745 | me_filep = NULL; | ||
746 | } | ||
747 | |||
748 | break; | ||
749 | |||
750 | default: | ||
751 | PERROR("Invalid lock specified.\n"); | ||
752 | |||
753 | err = ME_ERRNO_INVALID_LOCK; | ||
754 | |||
755 | break; | ||
756 | } | ||
757 | |||
758 | spin_unlock(&me_lock); | ||
759 | |||
760 | up_read(&me_rwsem); | ||
761 | |||
762 | return err; | ||
763 | } | ||
764 | |||
765 | static int me_lock_driver(struct file *filep, me_lock_driver_t * arg) | ||
766 | { | ||
767 | int err = 0; | ||
768 | |||
769 | me_lock_driver_t lock; | ||
770 | |||
771 | PDEBUG("executed.\n"); | ||
772 | |||
773 | err = copy_from_user(&lock, arg, sizeof(me_lock_driver_t)); | ||
774 | |||
775 | if (err) { | ||
776 | PERROR("Can't copy arguments to kernel space.\n"); | ||
777 | return -EFAULT; | ||
778 | } | ||
779 | |||
780 | lock.errno = lock_driver(filep, lock.lock, lock.flags); | ||
781 | |||
782 | err = copy_to_user(arg, &lock, sizeof(me_lock_driver_t)); | ||
783 | |||
784 | if (err) { | ||
785 | PERROR("Can't copy query back to user space.\n"); | ||
786 | return -EFAULT; | ||
787 | } | ||
788 | |||
789 | return ME_ERRNO_SUCCESS; | ||
790 | } | ||
791 | |||
792 | static int me_open(struct inode *inode_ptr, struct file *filep) | ||
793 | { | ||
794 | |||
795 | PDEBUG("executed.\n"); | ||
796 | // Nothing to do here. | ||
797 | return 0; | ||
798 | } | ||
799 | |||
800 | static int me_release(struct inode *inode_ptr, struct file *filep) | ||
801 | { | ||
802 | |||
803 | PDEBUG("executed.\n"); | ||
804 | lock_driver(filep, ME_LOCK_RELEASE, ME_LOCK_DRIVER_NO_FLAGS); | ||
805 | |||
806 | return 0; | ||
807 | } | ||
808 | |||
809 | static int me_query_version_main_driver(struct file *filep, | ||
810 | me_query_version_main_driver_t * arg) | ||
811 | { | ||
812 | int err; | ||
813 | me_query_version_main_driver_t karg; | ||
814 | |||
815 | PDEBUG("executed.\n"); | ||
816 | |||
817 | karg.version = ME_VERSION_DRIVER; | ||
818 | karg.errno = ME_ERRNO_SUCCESS; | ||
819 | |||
820 | err = copy_to_user(arg, &karg, sizeof(me_query_version_main_driver_t)); | ||
821 | |||
822 | if (err) { | ||
823 | PERROR("Can't copy query back to user space.\n"); | ||
824 | return -EFAULT; | ||
825 | } | ||
826 | |||
827 | return 0; | ||
828 | } | ||
829 | |||
830 | static int me_config_load_device(struct file *filep, | ||
831 | me_cfg_device_entry_t * karg, int device_no) | ||
832 | { | ||
833 | |||
834 | int err = ME_ERRNO_SUCCESS; | ||
835 | int k = 0; | ||
836 | |||
837 | struct list_head *pos = NULL; | ||
838 | me_device_t *device = NULL; | ||
839 | |||
840 | PDEBUG("executed.\n"); | ||
841 | |||
842 | list_for_each(pos, &me_device_list) { | ||
843 | if (k == device_no) { | ||
844 | device = list_entry(pos, me_device_t, list); | ||
845 | break; | ||
846 | } | ||
847 | |||
848 | k++; | ||
849 | } | ||
850 | |||
851 | if (pos == &me_device_list) { | ||
852 | PERROR("Invalid device number specified.\n"); | ||
853 | return ME_ERRNO_INVALID_DEVICE; | ||
854 | } else { | ||
855 | spin_lock(&me_lock); | ||
856 | |||
857 | if ((me_filep != NULL) && (me_filep != filep)) { | ||
858 | spin_unlock(&me_lock); | ||
859 | PERROR("Resource is locked by another process.\n"); | ||
860 | return ME_ERRNO_LOCKED; | ||
861 | } else { | ||
862 | me_count++; | ||
863 | spin_unlock(&me_lock); | ||
864 | |||
865 | err = | ||
866 | device->me_device_config_load(device, filep, karg); | ||
867 | |||
868 | spin_lock(&me_lock); | ||
869 | me_count--; | ||
870 | spin_unlock(&me_lock); | ||
871 | } | ||
872 | } | ||
873 | |||
874 | return err; | ||
875 | } | ||
876 | |||
877 | static int me_config_load(struct file *filep, me_config_load_t * arg) | ||
878 | { | ||
879 | int err; | ||
880 | int i; | ||
881 | me_config_load_t cfg_setup; | ||
882 | me_config_load_t karg_cfg_setup; | ||
883 | |||
884 | struct list_head *pos = NULL; | ||
885 | |||
886 | struct list_head new_list; | ||
887 | me_device_t *o_device; | ||
888 | me_device_t *n_device; | ||
889 | int o_vendor_id; | ||
890 | int o_device_id; | ||
891 | int o_serial_no; | ||
892 | int o_bus_type; | ||
893 | int o_bus_no; | ||
894 | int o_dev_no; | ||
895 | int o_func_no; | ||
896 | int o_plugged; | ||
897 | |||
898 | PDEBUG("executed.\n"); | ||
899 | |||
900 | // Copy argument to kernel space. | ||
901 | err = copy_from_user(&karg_cfg_setup, arg, sizeof(me_config_load_t)); | ||
902 | |||
903 | if (err) { | ||
904 | PERROR("Can't copy arguments to kernel space.\n"); | ||
905 | return -EFAULT; | ||
906 | } | ||
907 | // Allocate kernel buffer for device list. | ||
908 | cfg_setup.device_list = | ||
909 | kmalloc(sizeof(me_cfg_device_entry_t) * karg_cfg_setup.count, | ||
910 | GFP_KERNEL); | ||
911 | |||
912 | if (!cfg_setup.device_list) { | ||
913 | PERROR("Can't get buffer %li for device list.\n", | ||
914 | sizeof(me_cfg_device_entry_t) * karg_cfg_setup.count); | ||
915 | return -ENOMEM; | ||
916 | } | ||
917 | // Copy device list to kernel space. | ||
918 | err = | ||
919 | copy_from_user(cfg_setup.device_list, karg_cfg_setup.device_list, | ||
920 | sizeof(me_cfg_device_entry_t) * | ||
921 | karg_cfg_setup.count); | ||
922 | |||
923 | if (err) { | ||
924 | PERROR("Can't copy device list to kernel space.\n"); | ||
925 | kfree(cfg_setup.device_list); | ||
926 | return -EFAULT; | ||
927 | } | ||
928 | |||
929 | cfg_setup.count = karg_cfg_setup.count; | ||
930 | |||
931 | INIT_LIST_HEAD(&new_list); | ||
932 | |||
933 | down_write(&me_rwsem); | ||
934 | |||
935 | spin_lock(&me_lock); | ||
936 | |||
937 | if ((me_filep != NULL) && (me_filep != filep)) { | ||
938 | spin_unlock(&me_lock); | ||
939 | PERROR("Driver System is logged by another process.\n"); | ||
940 | karg_cfg_setup.errno = ME_ERRNO_LOCKED; | ||
941 | } else { | ||
942 | me_count++; | ||
943 | spin_unlock(&me_lock); | ||
944 | |||
945 | for (i = 0; i < karg_cfg_setup.count; i++) { | ||
946 | PDEBUG("me_config_load() device=%d.\n", i); | ||
947 | if (cfg_setup.device_list[i].tcpip.access_type == | ||
948 | ME_ACCESS_TYPE_LOCAL) { | ||
949 | list_for_each(pos, &me_device_list) { | ||
950 | o_device = | ||
951 | list_entry(pos, me_device_t, list); | ||
952 | o_device-> | ||
953 | me_device_query_info_device | ||
954 | (o_device, &o_vendor_id, | ||
955 | &o_device_id, &o_serial_no, | ||
956 | &o_bus_type, &o_bus_no, &o_dev_no, | ||
957 | &o_func_no, &o_plugged); | ||
958 | |||
959 | if (cfg_setup.device_list[i].info. | ||
960 | hw_location.bus_type == | ||
961 | ME_BUS_TYPE_PCI) { | ||
962 | if (((o_vendor_id == | ||
963 | cfg_setup.device_list[i]. | ||
964 | info.vendor_id) | ||
965 | && (o_device_id == | ||
966 | cfg_setup. | ||
967 | device_list[i].info. | ||
968 | device_id) | ||
969 | && (o_serial_no == | ||
970 | cfg_setup. | ||
971 | device_list[i].info. | ||
972 | serial_no) | ||
973 | && (o_bus_type == | ||
974 | cfg_setup. | ||
975 | device_list[i].info. | ||
976 | hw_location.bus_type)) | ||
977 | || | ||
978 | ((o_vendor_id == | ||
979 | cfg_setup.device_list[i]. | ||
980 | info.vendor_id) | ||
981 | && (o_device_id == | ||
982 | cfg_setup. | ||
983 | device_list[i].info. | ||
984 | device_id) | ||
985 | && (o_bus_type == | ||
986 | cfg_setup. | ||
987 | device_list[i].info. | ||
988 | hw_location.bus_type) | ||
989 | && (o_bus_no == | ||
990 | cfg_setup. | ||
991 | device_list[i].info. | ||
992 | hw_location.pci.bus_no) | ||
993 | && (o_dev_no == | ||
994 | cfg_setup. | ||
995 | device_list[i].info. | ||
996 | hw_location.pci. | ||
997 | device_no) | ||
998 | && (o_func_no == | ||
999 | cfg_setup. | ||
1000 | device_list[i].info. | ||
1001 | hw_location.pci. | ||
1002 | function_no))) { | ||
1003 | list_move_tail(pos, | ||
1004 | &new_list); | ||
1005 | break; | ||
1006 | } | ||
1007 | } | ||
1008 | /* | ||
1009 | else if (cfg_setup.device_list[i].info.hw_location.bus_type == ME_BUS_TYPE_USB) | ||
1010 | { | ||
1011 | if (((o_vendor_id == cfg_setup.device_list[i].info.vendor_id) && | ||
1012 | (o_device_id == cfg_setup.device_list[i].info.device_id) && | ||
1013 | (o_serial_no == cfg_setup.device_list[i].info.serial_no) && | ||
1014 | (o_bus_type == cfg_setup.device_list[i].info.hw_location.bus_type)) || | ||
1015 | ((o_vendor_id == cfg_setup.device_list[i].info.vendor_id) && | ||
1016 | (o_device_id == cfg_setup.device_list[i].info.device_id) && | ||
1017 | (o_bus_type == cfg_setup.device_list[i].info.hw_location.bus_type) && | ||
1018 | (o_bus_no == cfg_setup.device_list[i].info.hw_location.usb.root_hub_no))) | ||
1019 | { | ||
1020 | list_move_tail(pos, &new_list); | ||
1021 | break; | ||
1022 | } | ||
1023 | } | ||
1024 | */ | ||
1025 | else { | ||
1026 | PERROR("Wrong bus type: %d.\n", | ||
1027 | cfg_setup.device_list[i]. | ||
1028 | info.hw_location. | ||
1029 | bus_type); | ||
1030 | } | ||
1031 | } | ||
1032 | |||
1033 | if (pos == &me_device_list) { // Device is not already in the list | ||
1034 | if (cfg_setup.device_list[i].info. | ||
1035 | hw_location.bus_type == | ||
1036 | ME_BUS_TYPE_PCI) { | ||
1037 | n_device = | ||
1038 | get_dummy_instance | ||
1039 | (cfg_setup.device_list[i]. | ||
1040 | info.vendor_id, | ||
1041 | cfg_setup.device_list[i]. | ||
1042 | info.device_id, | ||
1043 | cfg_setup.device_list[i]. | ||
1044 | info.serial_no, | ||
1045 | cfg_setup.device_list[i]. | ||
1046 | info.hw_location.bus_type, | ||
1047 | cfg_setup.device_list[i]. | ||
1048 | info.hw_location.pci. | ||
1049 | bus_no, | ||
1050 | cfg_setup.device_list[i]. | ||
1051 | info.hw_location.pci. | ||
1052 | device_no, | ||
1053 | cfg_setup.device_list[i]. | ||
1054 | info.hw_location.pci. | ||
1055 | function_no); | ||
1056 | |||
1057 | if (!n_device) { | ||
1058 | PERROR | ||
1059 | ("Can't get dummy instance.\n"); | ||
1060 | kfree(cfg_setup. | ||
1061 | device_list); | ||
1062 | spin_lock(&me_lock); | ||
1063 | me_count--; | ||
1064 | spin_unlock(&me_lock); | ||
1065 | up_write(&me_rwsem); | ||
1066 | return -EFAULT; | ||
1067 | } | ||
1068 | |||
1069 | list_add_tail(&n_device->list, | ||
1070 | &new_list); | ||
1071 | } | ||
1072 | /* | ||
1073 | else if (cfg_setup.device_list[i].info.hw_location.bus_type == ME_BUS_TYPE_USB) | ||
1074 | { | ||
1075 | n_device = get_dummy_instance( | ||
1076 | cfg_setup.device_list[i].info.vendor_id, | ||
1077 | cfg_setup.device_list[i].info.device_id, | ||
1078 | cfg_setup.device_list[i].info.serial_no, | ||
1079 | cfg_setup.device_list[i].info.hw_location.bus_type, | ||
1080 | cfg_setup.device_list[i].info.hw_location.usb.root_hub_no, | ||
1081 | 0, | ||
1082 | 0); | ||
1083 | |||
1084 | if (!n_device) | ||
1085 | { | ||
1086 | PERROR("Can't get dummy instance.\n"); | ||
1087 | kfree(cfg_setup.device_list); | ||
1088 | spin_lock(&me_lock); | ||
1089 | me_count--; | ||
1090 | spin_unlock(&me_lock); | ||
1091 | up_write(&me_rwsem); | ||
1092 | return -EFAULT; | ||
1093 | } | ||
1094 | |||
1095 | list_add_tail(&n_device->list, &new_list); | ||
1096 | } | ||
1097 | */ | ||
1098 | } | ||
1099 | } else { | ||
1100 | n_device = get_dummy_instance(0, | ||
1101 | 0, 0, 0, 0, 0, 0); | ||
1102 | |||
1103 | if (!n_device) { | ||
1104 | PERROR("Can't get dummy instance.\n"); | ||
1105 | kfree(cfg_setup.device_list); | ||
1106 | spin_lock(&me_lock); | ||
1107 | me_count--; | ||
1108 | spin_unlock(&me_lock); | ||
1109 | up_write(&me_rwsem); | ||
1110 | return -EFAULT; | ||
1111 | } | ||
1112 | |||
1113 | list_add_tail(&n_device->list, &new_list); | ||
1114 | } | ||
1115 | } | ||
1116 | |||
1117 | while (!list_empty(&me_device_list)) { | ||
1118 | o_device = | ||
1119 | list_entry(me_device_list.next, me_device_t, list); | ||
1120 | o_device->me_device_query_info_device(o_device, | ||
1121 | &o_vendor_id, | ||
1122 | &o_device_id, | ||
1123 | &o_serial_no, | ||
1124 | &o_bus_type, | ||
1125 | &o_bus_no, | ||
1126 | &o_dev_no, | ||
1127 | &o_func_no, | ||
1128 | &o_plugged); | ||
1129 | |||
1130 | if (o_plugged == ME_PLUGGED_IN) { | ||
1131 | list_move_tail(me_device_list.next, &new_list); | ||
1132 | } else { | ||
1133 | list_del(me_device_list.next); | ||
1134 | release_instance(o_device); | ||
1135 | } | ||
1136 | } | ||
1137 | |||
1138 | // Move temporary new list to global driver list. | ||
1139 | list_splice(&new_list, &me_device_list); | ||
1140 | |||
1141 | karg_cfg_setup.errno = ME_ERRNO_SUCCESS; | ||
1142 | } | ||
1143 | |||
1144 | for (i = 0; i < cfg_setup.count; i++) { | ||
1145 | |||
1146 | karg_cfg_setup.errno = | ||
1147 | me_config_load_device(filep, &cfg_setup.device_list[i], i); | ||
1148 | if (karg_cfg_setup.errno) { | ||
1149 | PERROR("me_config_load_device(%d)=%d\n", i, | ||
1150 | karg_cfg_setup.errno); | ||
1151 | break; | ||
1152 | } | ||
1153 | } | ||
1154 | |||
1155 | spin_lock(&me_lock); | ||
1156 | |||
1157 | me_count--; | ||
1158 | spin_unlock(&me_lock); | ||
1159 | up_write(&me_rwsem); | ||
1160 | |||
1161 | err = copy_to_user(arg, &karg_cfg_setup, sizeof(me_config_load_t)); | ||
1162 | |||
1163 | if (err) { | ||
1164 | PERROR("Can't copy config list to user space.\n"); | ||
1165 | kfree(cfg_setup.device_list); | ||
1166 | return -EFAULT; | ||
1167 | } | ||
1168 | |||
1169 | kfree(cfg_setup.device_list); | ||
1170 | return 0; | ||
1171 | } | ||
1172 | |||
1173 | static int me_io_stream_start(struct file *filep, me_io_stream_start_t * arg) | ||
1174 | { | ||
1175 | int err; | ||
1176 | int i, k; | ||
1177 | |||
1178 | struct list_head *pos; | ||
1179 | me_device_t *device; | ||
1180 | me_io_stream_start_t karg; | ||
1181 | meIOStreamStart_t *list; | ||
1182 | |||
1183 | PDEBUG("executed.\n"); | ||
1184 | |||
1185 | err = copy_from_user(&karg, arg, sizeof(me_io_stream_start_t)); | ||
1186 | |||
1187 | if (err) { | ||
1188 | PERROR("Can't copy arguments to kernel space.\n"); | ||
1189 | return -EFAULT; | ||
1190 | } | ||
1191 | |||
1192 | karg.errno = ME_ERRNO_SUCCESS; | ||
1193 | |||
1194 | list = kmalloc(sizeof(meIOStreamStart_t) * karg.count, GFP_KERNEL); | ||
1195 | |||
1196 | if (!list) { | ||
1197 | PERROR("Can't get buffer for start list.\n"); | ||
1198 | return -ENOMEM; | ||
1199 | } | ||
1200 | |||
1201 | err = | ||
1202 | copy_from_user(list, karg.start_list, | ||
1203 | sizeof(meIOStreamStart_t) * karg.count); | ||
1204 | |||
1205 | if (err) { | ||
1206 | PERROR("Can't copy start list to kernel space.\n"); | ||
1207 | kfree(list); | ||
1208 | return -EFAULT; | ||
1209 | } | ||
1210 | |||
1211 | spin_lock(&me_lock); | ||
1212 | |||
1213 | if ((me_filep != NULL) && (me_filep != filep)) { | ||
1214 | spin_unlock(&me_lock); | ||
1215 | PERROR("Driver System is logged by another process.\n"); | ||
1216 | |||
1217 | for (i = 0; i < karg.count; i++) { | ||
1218 | list[i].iErrno = ME_ERRNO_LOCKED; | ||
1219 | } | ||
1220 | } else { | ||
1221 | me_count++; | ||
1222 | spin_unlock(&me_lock); | ||
1223 | |||
1224 | for (i = 0; i < karg.count; i++) { | ||
1225 | down_read(&me_rwsem); | ||
1226 | k = 0; | ||
1227 | list_for_each(pos, &me_device_list) { | ||
1228 | if (k == list[i].iDevice) { | ||
1229 | device = | ||
1230 | list_entry(pos, me_device_t, list); | ||
1231 | break; | ||
1232 | } | ||
1233 | |||
1234 | k++; | ||
1235 | } | ||
1236 | |||
1237 | if (pos == &me_device_list) { | ||
1238 | up_read(&me_rwsem); | ||
1239 | PERROR("Invalid device number specified.\n"); | ||
1240 | list[i].iErrno = ME_ERRNO_INVALID_DEVICE; | ||
1241 | karg.errno = ME_ERRNO_INVALID_DEVICE; | ||
1242 | break; | ||
1243 | } else { | ||
1244 | list[i].iErrno = | ||
1245 | device->me_device_io_stream_start(device, | ||
1246 | filep, | ||
1247 | list[i]. | ||
1248 | iSubdevice, | ||
1249 | list[i]. | ||
1250 | iStartMode, | ||
1251 | list[i]. | ||
1252 | iTimeOut, | ||
1253 | list[i]. | ||
1254 | iFlags); | ||
1255 | |||
1256 | if (list[i].iErrno) { | ||
1257 | up_read(&me_rwsem); | ||
1258 | karg.errno = list[i].iErrno; | ||
1259 | break; | ||
1260 | } | ||
1261 | } | ||
1262 | |||
1263 | up_read(&me_rwsem); | ||
1264 | } | ||
1265 | |||
1266 | spin_lock(&me_lock); | ||
1267 | |||
1268 | me_count--; | ||
1269 | spin_unlock(&me_lock); | ||
1270 | } | ||
1271 | |||
1272 | err = copy_to_user(arg, &karg, sizeof(me_io_stream_start_t)); | ||
1273 | |||
1274 | if (err) { | ||
1275 | PERROR("Can't copy arguments to user space.\n"); | ||
1276 | kfree(list); | ||
1277 | return -EFAULT; | ||
1278 | } | ||
1279 | |||
1280 | err = | ||
1281 | copy_to_user(karg.start_list, list, | ||
1282 | sizeof(meIOStreamStart_t) * karg.count); | ||
1283 | |||
1284 | if (err) { | ||
1285 | PERROR("Can't copy start list to user space.\n"); | ||
1286 | kfree(list); | ||
1287 | return -EFAULT; | ||
1288 | } | ||
1289 | |||
1290 | kfree(list); | ||
1291 | |||
1292 | return err; | ||
1293 | } | ||
1294 | |||
1295 | static int me_io_single(struct file *filep, me_io_single_t * arg) | ||
1296 | { | ||
1297 | int err; | ||
1298 | int i, k; | ||
1299 | |||
1300 | struct list_head *pos; | ||
1301 | me_device_t *device; | ||
1302 | me_io_single_t karg; | ||
1303 | meIOSingle_t *list; | ||
1304 | |||
1305 | PDEBUG("executed.\n"); | ||
1306 | |||
1307 | err = copy_from_user(&karg, arg, sizeof(me_io_single_t)); | ||
1308 | |||
1309 | if (err) { | ||
1310 | PERROR("Can't copy arguments to kernel space.\n"); | ||
1311 | return -EFAULT; | ||
1312 | } | ||
1313 | |||
1314 | karg.errno = ME_ERRNO_SUCCESS; | ||
1315 | |||
1316 | list = kmalloc(sizeof(meIOSingle_t) * karg.count, GFP_KERNEL); | ||
1317 | |||
1318 | if (!list) { | ||
1319 | PERROR("Can't get buffer for single list.\n"); | ||
1320 | return -ENOMEM; | ||
1321 | } | ||
1322 | |||
1323 | err = | ||
1324 | copy_from_user(list, karg.single_list, | ||
1325 | sizeof(meIOSingle_t) * karg.count); | ||
1326 | |||
1327 | if (err) { | ||
1328 | PERROR("Can't copy single list to kernel space.\n"); | ||
1329 | kfree(list); | ||
1330 | return -EFAULT; | ||
1331 | } | ||
1332 | |||
1333 | spin_lock(&me_lock); | ||
1334 | |||
1335 | if ((me_filep != NULL) && (me_filep != filep)) { | ||
1336 | spin_unlock(&me_lock); | ||
1337 | PERROR("Driver System is logged by another process.\n"); | ||
1338 | |||
1339 | for (i = 0; i < karg.count; i++) { | ||
1340 | list[i].iErrno = ME_ERRNO_LOCKED; | ||
1341 | } | ||
1342 | } else { | ||
1343 | me_count++; | ||
1344 | spin_unlock(&me_lock); | ||
1345 | |||
1346 | for (i = 0; i < karg.count; i++) { | ||
1347 | k = 0; | ||
1348 | |||
1349 | down_read(&me_rwsem); | ||
1350 | |||
1351 | list_for_each(pos, &me_device_list) { | ||
1352 | if (k == list[i].iDevice) { | ||
1353 | device = | ||
1354 | list_entry(pos, me_device_t, list); | ||
1355 | break; | ||
1356 | } | ||
1357 | |||
1358 | k++; | ||
1359 | } | ||
1360 | |||
1361 | if (pos == &me_device_list) { | ||
1362 | up_read(&me_rwsem); | ||
1363 | PERROR("Invalid device number specified.\n"); | ||
1364 | list[i].iErrno = ME_ERRNO_INVALID_DEVICE; | ||
1365 | karg.errno = ME_ERRNO_INVALID_DEVICE; | ||
1366 | break; | ||
1367 | } else { | ||
1368 | if (list[i].iDir == ME_DIR_OUTPUT) { | ||
1369 | list[i].iErrno = | ||
1370 | device-> | ||
1371 | me_device_io_single_write(device, | ||
1372 | filep, | ||
1373 | list[i]. | ||
1374 | iSubdevice, | ||
1375 | list[i]. | ||
1376 | iChannel, | ||
1377 | list[i]. | ||
1378 | iValue, | ||
1379 | list[i]. | ||
1380 | iTimeOut, | ||
1381 | list[i]. | ||
1382 | iFlags); | ||
1383 | |||
1384 | if (list[i].iErrno) { | ||
1385 | up_read(&me_rwsem); | ||
1386 | karg.errno = list[i].iErrno; | ||
1387 | break; | ||
1388 | } | ||
1389 | } else if (list[i].iDir == ME_DIR_INPUT) { | ||
1390 | list[i].iErrno = | ||
1391 | device-> | ||
1392 | me_device_io_single_read(device, | ||
1393 | filep, | ||
1394 | list[i]. | ||
1395 | iSubdevice, | ||
1396 | list[i]. | ||
1397 | iChannel, | ||
1398 | &list[i]. | ||
1399 | iValue, | ||
1400 | list[i]. | ||
1401 | iTimeOut, | ||
1402 | list[i]. | ||
1403 | iFlags); | ||
1404 | |||
1405 | if (list[i].iErrno) { | ||
1406 | up_read(&me_rwsem); | ||
1407 | karg.errno = list[i].iErrno; | ||
1408 | break; | ||
1409 | } | ||
1410 | } else { | ||
1411 | up_read(&me_rwsem); | ||
1412 | PERROR | ||
1413 | ("Invalid single direction specified.\n"); | ||
1414 | list[i].iErrno = ME_ERRNO_INVALID_DIR; | ||
1415 | karg.errno = ME_ERRNO_INVALID_DIR; | ||
1416 | break; | ||
1417 | } | ||
1418 | } | ||
1419 | |||
1420 | up_read(&me_rwsem); | ||
1421 | } | ||
1422 | |||
1423 | spin_lock(&me_lock); | ||
1424 | |||
1425 | me_count--; | ||
1426 | spin_unlock(&me_lock); | ||
1427 | } | ||
1428 | |||
1429 | err = copy_to_user(arg, &karg, sizeof(me_io_single_t)); | ||
1430 | |||
1431 | if (err) { | ||
1432 | PERROR("Can't copy arguments to user space.\n"); | ||
1433 | return -EFAULT; | ||
1434 | } | ||
1435 | |||
1436 | err = | ||
1437 | copy_to_user(karg.single_list, list, | ||
1438 | sizeof(meIOSingle_t) * karg.count); | ||
1439 | |||
1440 | if (err) { | ||
1441 | PERROR("Can't copy single list to user space.\n"); | ||
1442 | kfree(list); | ||
1443 | return -EFAULT; | ||
1444 | } | ||
1445 | |||
1446 | kfree(list); | ||
1447 | |||
1448 | return err; | ||
1449 | } | ||
1450 | |||
1451 | static int me_io_stream_config(struct file *filep, me_io_stream_config_t * arg) | ||
1452 | { | ||
1453 | int err; | ||
1454 | int k = 0; | ||
1455 | |||
1456 | struct list_head *pos; | ||
1457 | me_device_t *device; | ||
1458 | me_io_stream_config_t karg; | ||
1459 | meIOStreamConfig_t *list; | ||
1460 | |||
1461 | PDEBUG("executed.\n"); | ||
1462 | |||
1463 | err = copy_from_user(&karg, arg, sizeof(me_io_stream_config_t)); | ||
1464 | |||
1465 | if (err) { | ||
1466 | PERROR("Can't copy arguments to kernel space.\n"); | ||
1467 | return -EFAULT; | ||
1468 | } | ||
1469 | |||
1470 | list = kmalloc(sizeof(meIOStreamConfig_t) * karg.count, GFP_KERNEL); | ||
1471 | |||
1472 | if (!list) { | ||
1473 | PERROR("Can't get buffer for config list.\n"); | ||
1474 | return -ENOMEM; | ||
1475 | } | ||
1476 | |||
1477 | err = | ||
1478 | copy_from_user(list, karg.config_list, | ||
1479 | sizeof(meIOStreamConfig_t) * karg.count); | ||
1480 | |||
1481 | if (err) { | ||
1482 | PERROR("Can't copy config list to kernel space.\n"); | ||
1483 | kfree(list); | ||
1484 | return -EFAULT; | ||
1485 | } | ||
1486 | |||
1487 | spin_lock(&me_lock); | ||
1488 | |||
1489 | if ((me_filep != NULL) && (me_filep != filep)) { | ||
1490 | spin_unlock(&me_lock); | ||
1491 | PERROR("Driver System is logged by another process.\n"); | ||
1492 | karg.errno = ME_ERRNO_LOCKED; | ||
1493 | } else { | ||
1494 | me_count++; | ||
1495 | spin_unlock(&me_lock); | ||
1496 | |||
1497 | down_read(&me_rwsem); | ||
1498 | |||
1499 | list_for_each(pos, &me_device_list) { | ||
1500 | if (k == karg.device) { | ||
1501 | device = list_entry(pos, me_device_t, list); | ||
1502 | break; | ||
1503 | } | ||
1504 | |||
1505 | k++; | ||
1506 | } | ||
1507 | |||
1508 | if (pos == &me_device_list) { | ||
1509 | PERROR("Invalid device number specified.\n"); | ||
1510 | karg.errno = ME_ERRNO_INVALID_DEVICE; | ||
1511 | } else { | ||
1512 | karg.errno = | ||
1513 | device->me_device_io_stream_config(device, filep, | ||
1514 | karg.subdevice, | ||
1515 | list, karg.count, | ||
1516 | &karg.trigger, | ||
1517 | karg. | ||
1518 | fifo_irq_threshold, | ||
1519 | karg.flags); | ||
1520 | } | ||
1521 | |||
1522 | up_read(&me_rwsem); | ||
1523 | |||
1524 | spin_lock(&me_lock); | ||
1525 | me_count--; | ||
1526 | spin_unlock(&me_lock); | ||
1527 | } | ||
1528 | |||
1529 | err = copy_to_user(arg, &karg, sizeof(me_io_stream_config_t)); | ||
1530 | |||
1531 | if (err) { | ||
1532 | PERROR("Can't copy back to user space.\n"); | ||
1533 | kfree(list); | ||
1534 | return -EFAULT; | ||
1535 | } | ||
1536 | |||
1537 | kfree(list); | ||
1538 | |||
1539 | return err; | ||
1540 | } | ||
1541 | |||
1542 | static int me_query_number_devices(struct file *filep, | ||
1543 | me_query_number_devices_t * arg) | ||
1544 | { | ||
1545 | int err; | ||
1546 | me_query_number_devices_t karg; | ||
1547 | |||
1548 | struct list_head *pos; | ||
1549 | |||
1550 | PDEBUG("executed.\n"); | ||
1551 | |||
1552 | karg.number = 0; | ||
1553 | down_read(&me_rwsem); | ||
1554 | list_for_each(pos, &me_device_list) { | ||
1555 | karg.number++; | ||
1556 | } | ||
1557 | |||
1558 | up_read(&me_rwsem); | ||
1559 | |||
1560 | karg.errno = ME_ERRNO_SUCCESS; | ||
1561 | |||
1562 | err = copy_to_user(arg, &karg, sizeof(me_query_number_devices_t)); | ||
1563 | |||
1564 | if (err) { | ||
1565 | PERROR("Can't copy query back to user space.\n"); | ||
1566 | return -EFAULT; | ||
1567 | } | ||
1568 | |||
1569 | return 0; | ||
1570 | } | ||
1571 | |||
1572 | static int me_io_stream_stop(struct file *filep, me_io_stream_stop_t * arg) | ||
1573 | { | ||
1574 | int err; | ||
1575 | int i, k; | ||
1576 | |||
1577 | struct list_head *pos; | ||
1578 | me_device_t *device; | ||
1579 | me_io_stream_stop_t karg; | ||
1580 | meIOStreamStop_t *list; | ||
1581 | |||
1582 | PDEBUG("executed.\n"); | ||
1583 | |||
1584 | err = copy_from_user(&karg, arg, sizeof(me_io_stream_stop_t)); | ||
1585 | |||
1586 | if (err) { | ||
1587 | PERROR("Can't copy arguments to kernel space.\n"); | ||
1588 | return -EFAULT; | ||
1589 | } | ||
1590 | |||
1591 | karg.errno = ME_ERRNO_SUCCESS; | ||
1592 | |||
1593 | list = kmalloc(sizeof(meIOStreamStop_t) * karg.count, GFP_KERNEL); | ||
1594 | |||
1595 | if (!list) { | ||
1596 | PERROR("Can't get buffer for stop list.\n"); | ||
1597 | return -ENOMEM; | ||
1598 | } | ||
1599 | |||
1600 | err = | ||
1601 | copy_from_user(list, karg.stop_list, | ||
1602 | sizeof(meIOStreamStop_t) * karg.count); | ||
1603 | |||
1604 | if (err) { | ||
1605 | PERROR("Can't copy stop list to kernel space.\n"); | ||
1606 | kfree(list); | ||
1607 | return -EFAULT; | ||
1608 | } | ||
1609 | |||
1610 | spin_lock(&me_lock); | ||
1611 | |||
1612 | if ((me_filep != NULL) && (me_filep != filep)) { | ||
1613 | spin_unlock(&me_lock); | ||
1614 | PERROR("Driver System is logged by another process.\n"); | ||
1615 | |||
1616 | for (i = 0; i < karg.count; i++) { | ||
1617 | list[i].iErrno = ME_ERRNO_LOCKED; | ||
1618 | } | ||
1619 | } else { | ||
1620 | me_count++; | ||
1621 | spin_unlock(&me_lock); | ||
1622 | |||
1623 | for (i = 0; i < karg.count; i++) { | ||
1624 | k = 0; | ||
1625 | down_read(&me_rwsem); | ||
1626 | list_for_each(pos, &me_device_list) { | ||
1627 | if (k == list[i].iDevice) { | ||
1628 | device = | ||
1629 | list_entry(pos, me_device_t, list); | ||
1630 | break; | ||
1631 | } | ||
1632 | |||
1633 | k++; | ||
1634 | } | ||
1635 | |||
1636 | if (pos == &me_device_list) { | ||
1637 | up_read(&me_rwsem); | ||
1638 | PERROR("Invalid device number specified.\n"); | ||
1639 | list[i].iErrno = ME_ERRNO_INVALID_DEVICE; | ||
1640 | karg.errno = ME_ERRNO_INVALID_DEVICE; | ||
1641 | break; | ||
1642 | } else { | ||
1643 | list[i].iErrno = | ||
1644 | device->me_device_io_stream_stop(device, | ||
1645 | filep, | ||
1646 | list[i]. | ||
1647 | iSubdevice, | ||
1648 | list[i]. | ||
1649 | iStopMode, | ||
1650 | list[i]. | ||
1651 | iFlags); | ||
1652 | |||
1653 | if (list[i].iErrno) { | ||
1654 | up_read(&me_rwsem); | ||
1655 | karg.errno = list[i].iErrno; | ||
1656 | break; | ||
1657 | } | ||
1658 | } | ||
1659 | |||
1660 | up_read(&me_rwsem); | ||
1661 | } | ||
1662 | |||
1663 | spin_lock(&me_lock); | ||
1664 | |||
1665 | me_count--; | ||
1666 | spin_unlock(&me_lock); | ||
1667 | } | ||
1668 | |||
1669 | err = copy_to_user(arg, &karg, sizeof(me_io_stream_stop_t)); | ||
1670 | |||
1671 | if (err) { | ||
1672 | PERROR("Can't copy arguments to user space.\n"); | ||
1673 | return -EFAULT; | ||
1674 | } | ||
1675 | |||
1676 | err = | ||
1677 | copy_to_user(karg.stop_list, list, | ||
1678 | sizeof(meIOStreamStop_t) * karg.count); | ||
1679 | |||
1680 | if (err) { | ||
1681 | PERROR("Can't copy stop list to user space.\n"); | ||
1682 | kfree(list); | ||
1683 | return -EFAULT; | ||
1684 | } | ||
1685 | |||
1686 | kfree(list); | ||
1687 | |||
1688 | return err; | ||
1689 | } | ||
1690 | |||
1691 | /* //me_probe_usb | ||
1692 | static int me_probe_usb(struct usb_interface *interface, const struct usb_device_id *id) | ||
1693 | { | ||
1694 | //int err; | ||
1695 | //me_usb_constructor_t *constructor = NULL; | ||
1696 | me_device_t *n_device = NULL; | ||
1697 | |||
1698 | PDEBUG("executed.\n"); | ||
1699 | |||
1700 | switch (id->idProduct) | ||
1701 | { | ||
1702 | case USB_DEVICE_ID_MEPHISTO_S1: | ||
1703 | if((constructor = symbol_get(mephisto_s1_constructor)) == NULL){ | ||
1704 | err = request_module(MEPHISTO_S1_NAME); | ||
1705 | if(err){ | ||
1706 | PERROR("Error while request for module %s.\n", MEPHISTO_S1_NAME); | ||
1707 | return -ENODEV; | ||
1708 | } | ||
1709 | if((constructor = symbol_get(mephisto_s1_constructor)) == NULL){ | ||
1710 | PERROR("Can't get %s driver module constructor.\n", MEPHISTO_S1_NAME); | ||
1711 | return -ENODEV; | ||
1712 | } | ||
1713 | } | ||
1714 | |||
1715 | if((n_device = (*constructor)(interface)) == NULL){ | ||
1716 | symbol_put(mephisto_s1_constructor); | ||
1717 | PERROR("Can't get device instance of %s driver module.\n", MEPHISTO_S1_NAME); | ||
1718 | return -ENODEV; | ||
1719 | } | ||
1720 | |||
1721 | break; | ||
1722 | |||
1723 | default: | ||
1724 | PERROR("Invalid product id.\n"); | ||
1725 | |||
1726 | return -EINVAL; | ||
1727 | } | ||
1728 | |||
1729 | return insert_to_device_list(n_device); | ||
1730 | } | ||
1731 | */ | ||
1732 | |||
1733 | /* //me_disconnect_usb | ||
1734 | static void me_disconnect_usb(struct usb_interface *interface) | ||
1735 | { | ||
1736 | |||
1737 | struct usb_device *device = interface_to_usbdev(interface); | ||
1738 | int vendor_id = device->descriptor.idVendor; | ||
1739 | int device_id = device->descriptor.idProduct; | ||
1740 | int serial_no; | ||
1741 | |||
1742 | sscanf(&device->serial[2], "%x", &serial_no); | ||
1743 | |||
1744 | PDEBUG("executed.\n"); | ||
1745 | |||
1746 | PINFO("Vendor id = 0x%08X\n", vendor_id); | ||
1747 | PINFO("Device id = 0x%08X\n", device_id); | ||
1748 | PINFO("Serial Number = 0x%08X\n", serial_no); | ||
1749 | |||
1750 | replace_with_dummy(vendor_id, device_id, serial_no); | ||
1751 | } | ||
1752 | */ | ||
1753 | |||
1754 | static int me_ioctl(struct inode *inodep, | ||
1755 | struct file *filep, unsigned int service, unsigned long arg) | ||
1756 | { | ||
1757 | |||
1758 | PDEBUG("executed.\n"); | ||
1759 | |||
1760 | if (_IOC_TYPE(service) != MEMAIN_MAGIC) { | ||
1761 | PERROR("Invalid magic number.\n"); | ||
1762 | return -ENOTTY; | ||
1763 | } | ||
1764 | |||
1765 | PDEBUG("service number: 0x%x.\n", service); | ||
1766 | |||
1767 | switch (service) { | ||
1768 | case ME_IO_IRQ_ENABLE: | ||
1769 | return me_io_irq_start(filep, (me_io_irq_start_t *) arg); | ||
1770 | |||
1771 | case ME_IO_IRQ_WAIT: | ||
1772 | return me_io_irq_wait(filep, (me_io_irq_wait_t *) arg); | ||
1773 | |||
1774 | case ME_IO_IRQ_DISABLE: | ||
1775 | return me_io_irq_stop(filep, (me_io_irq_stop_t *) arg); | ||
1776 | |||
1777 | case ME_IO_RESET_DEVICE: | ||
1778 | return me_io_reset_device(filep, (me_io_reset_device_t *) arg); | ||
1779 | |||
1780 | case ME_IO_RESET_SUBDEVICE: | ||
1781 | return me_io_reset_subdevice(filep, | ||
1782 | (me_io_reset_subdevice_t *) arg); | ||
1783 | |||
1784 | case ME_IO_SINGLE_CONFIG: | ||
1785 | return me_io_single_config(filep, | ||
1786 | (me_io_single_config_t *) arg); | ||
1787 | |||
1788 | case ME_IO_SINGLE: | ||
1789 | return me_io_single(filep, (me_io_single_t *) arg); | ||
1790 | |||
1791 | case ME_IO_STREAM_CONFIG: | ||
1792 | return me_io_stream_config(filep, | ||
1793 | (me_io_stream_config_t *) arg); | ||
1794 | |||
1795 | case ME_IO_STREAM_NEW_VALUES: | ||
1796 | return me_io_stream_new_values(filep, | ||
1797 | (me_io_stream_new_values_t *) | ||
1798 | arg); | ||
1799 | |||
1800 | case ME_IO_STREAM_READ: | ||
1801 | return me_io_stream_read(filep, (me_io_stream_read_t *) arg); | ||
1802 | |||
1803 | case ME_IO_STREAM_START: | ||
1804 | return me_io_stream_start(filep, (me_io_stream_start_t *) arg); | ||
1805 | |||
1806 | case ME_IO_STREAM_STATUS: | ||
1807 | return me_io_stream_status(filep, | ||
1808 | (me_io_stream_status_t *) arg); | ||
1809 | |||
1810 | case ME_IO_STREAM_STOP: | ||
1811 | return me_io_stream_stop(filep, (me_io_stream_stop_t *) arg); | ||
1812 | |||
1813 | case ME_IO_STREAM_WRITE: | ||
1814 | return me_io_stream_write(filep, (me_io_stream_write_t *) arg); | ||
1815 | |||
1816 | case ME_LOCK_DRIVER: | ||
1817 | return me_lock_driver(filep, (me_lock_driver_t *) arg); | ||
1818 | |||
1819 | case ME_LOCK_DEVICE: | ||
1820 | return me_lock_device(filep, (me_lock_device_t *) arg); | ||
1821 | |||
1822 | case ME_LOCK_SUBDEVICE: | ||
1823 | return me_lock_subdevice(filep, (me_lock_subdevice_t *) arg); | ||
1824 | |||
1825 | case ME_QUERY_INFO_DEVICE: | ||
1826 | return me_query_info_device(filep, | ||
1827 | (me_query_info_device_t *) arg); | ||
1828 | |||
1829 | case ME_QUERY_DESCRIPTION_DEVICE: | ||
1830 | return me_query_description_device(filep, | ||
1831 | (me_query_description_device_t | ||
1832 | *) arg); | ||
1833 | |||
1834 | case ME_QUERY_NAME_DEVICE: | ||
1835 | return me_query_name_device(filep, | ||
1836 | (me_query_name_device_t *) arg); | ||
1837 | |||
1838 | case ME_QUERY_NAME_DEVICE_DRIVER: | ||
1839 | return me_query_name_device_driver(filep, | ||
1840 | (me_query_name_device_driver_t | ||
1841 | *) arg); | ||
1842 | |||
1843 | case ME_QUERY_NUMBER_DEVICES: | ||
1844 | return me_query_number_devices(filep, | ||
1845 | (me_query_number_devices_t *) | ||
1846 | arg); | ||
1847 | |||
1848 | case ME_QUERY_NUMBER_SUBDEVICES: | ||
1849 | return me_query_number_subdevices(filep, | ||
1850 | (me_query_number_subdevices_t | ||
1851 | *) arg); | ||
1852 | |||
1853 | case ME_QUERY_NUMBER_CHANNELS: | ||
1854 | return me_query_number_channels(filep, | ||
1855 | (me_query_number_channels_t *) | ||
1856 | arg); | ||
1857 | |||
1858 | case ME_QUERY_NUMBER_RANGES: | ||
1859 | return me_query_number_ranges(filep, | ||
1860 | (me_query_number_ranges_t *) arg); | ||
1861 | |||
1862 | case ME_QUERY_RANGE_BY_MIN_MAX: | ||
1863 | return me_query_range_by_min_max(filep, | ||
1864 | (me_query_range_by_min_max_t *) | ||
1865 | arg); | ||
1866 | |||
1867 | case ME_QUERY_RANGE_INFO: | ||
1868 | return me_query_range_info(filep, | ||
1869 | (me_query_range_info_t *) arg); | ||
1870 | |||
1871 | case ME_QUERY_SUBDEVICE_BY_TYPE: | ||
1872 | return me_query_subdevice_by_type(filep, | ||
1873 | (me_query_subdevice_by_type_t | ||
1874 | *) arg); | ||
1875 | |||
1876 | case ME_QUERY_SUBDEVICE_TYPE: | ||
1877 | return me_query_subdevice_type(filep, | ||
1878 | (me_query_subdevice_type_t *) | ||
1879 | arg); | ||
1880 | |||
1881 | case ME_QUERY_SUBDEVICE_CAPS: | ||
1882 | return me_query_subdevice_caps(filep, | ||
1883 | (me_query_subdevice_caps_t *) | ||
1884 | arg); | ||
1885 | |||
1886 | case ME_QUERY_SUBDEVICE_CAPS_ARGS: | ||
1887 | return me_query_subdevice_caps_args(filep, | ||
1888 | (me_query_subdevice_caps_args_t | ||
1889 | *) arg); | ||
1890 | |||
1891 | case ME_QUERY_TIMER: | ||
1892 | return me_query_timer(filep, (me_query_timer_t *) arg); | ||
1893 | |||
1894 | case ME_QUERY_VERSION_MAIN_DRIVER: | ||
1895 | return me_query_version_main_driver(filep, | ||
1896 | (me_query_version_main_driver_t | ||
1897 | *) arg); | ||
1898 | |||
1899 | case ME_QUERY_VERSION_DEVICE_DRIVER: | ||
1900 | return me_query_version_device_driver(filep, | ||
1901 | (me_query_version_device_driver_t | ||
1902 | *) arg); | ||
1903 | |||
1904 | case ME_CONFIG_LOAD: | ||
1905 | return me_config_load(filep, (me_config_load_t *) arg); | ||
1906 | } | ||
1907 | |||
1908 | PERROR("Invalid ioctl number.\n"); | ||
1909 | return -ENOTTY; | ||
1910 | } | ||
1911 | |||
1912 | // Init and exit of module. | ||
1913 | static int memain_init(void) | ||
1914 | { | ||
1915 | int result = 0; | ||
1916 | dev_t dev = MKDEV(major, 0); | ||
1917 | |||
1918 | PDEBUG("executed.\n"); | ||
1919 | |||
1920 | // Register pci driver. This will return 0 if the PCI subsystem is not available. | ||
1921 | result = pci_register_driver(&me_pci_driver); | ||
1922 | |||
1923 | if (result < 0) { | ||
1924 | PERROR("Can't register pci driver.\n"); | ||
1925 | goto INIT_ERROR_1; | ||
1926 | } | ||
1927 | |||
1928 | /* | ||
1929 | // Register usb driver. This will return -ENODEV if no USB subsystem is available. | ||
1930 | result = usb_register(&me_usb_driver); | ||
1931 | |||
1932 | if (result) | ||
1933 | { | ||
1934 | if (result == -ENODEV) | ||
1935 | { | ||
1936 | PERROR("No USB subsystem available.\n"); | ||
1937 | } | ||
1938 | else | ||
1939 | { | ||
1940 | PERROR("Can't register usb driver.\n"); | ||
1941 | goto INIT_ERROR_2; | ||
1942 | } | ||
1943 | } | ||
1944 | */ | ||
1945 | // Register the character device. | ||
1946 | if (major) { | ||
1947 | result = register_chrdev_region(dev, 1, MEMAIN_NAME); | ||
1948 | } else { | ||
1949 | result = alloc_chrdev_region(&dev, 0, 1, MEMAIN_NAME); | ||
1950 | major = MAJOR(dev); | ||
1951 | } | ||
1952 | |||
1953 | if (result < 0) { | ||
1954 | PERROR("Can't get major driver no.\n"); | ||
1955 | goto INIT_ERROR_3; | ||
1956 | } | ||
1957 | |||
1958 | cdevp = cdev_alloc(); | ||
1959 | |||
1960 | if (!cdevp) { | ||
1961 | PERROR("Can't get character device structure.\n"); | ||
1962 | result = -ENOMEM; | ||
1963 | goto INIT_ERROR_4; | ||
1964 | } | ||
1965 | |||
1966 | cdevp->ops = &me_file_operations; | ||
1967 | |||
1968 | cdevp->owner = THIS_MODULE; | ||
1969 | |||
1970 | result = cdev_add(cdevp, dev, 1); | ||
1971 | |||
1972 | if (result < 0) { | ||
1973 | PERROR("Cannot add character device structure.\n"); | ||
1974 | goto INIT_ERROR_5; | ||
1975 | } | ||
1976 | |||
1977 | return 0; | ||
1978 | |||
1979 | INIT_ERROR_5: | ||
1980 | cdev_del(cdevp); | ||
1981 | |||
1982 | INIT_ERROR_4: | ||
1983 | unregister_chrdev_region(dev, 1); | ||
1984 | |||
1985 | INIT_ERROR_3: | ||
1986 | // usb_deregister(&me_usb_driver); | ||
1987 | |||
1988 | //INIT_ERROR_2: | ||
1989 | pci_unregister_driver(&me_pci_driver); | ||
1990 | clear_device_list(); | ||
1991 | |||
1992 | INIT_ERROR_1: | ||
1993 | return result; | ||
1994 | } | ||
1995 | |||
1996 | static void __exit memain_exit(void) | ||
1997 | { | ||
1998 | dev_t dev = MKDEV(major, 0); | ||
1999 | |||
2000 | PDEBUG("executed.\n"); | ||
2001 | |||
2002 | cdev_del(cdevp); | ||
2003 | unregister_chrdev_region(dev, 1); | ||
2004 | pci_unregister_driver(&me_pci_driver); | ||
2005 | // usb_deregister(&me_usb_driver); | ||
2006 | clear_device_list(); | ||
2007 | } | ||
2008 | |||
2009 | module_init(memain_init); | ||
2010 | module_exit(memain_exit); | ||
2011 | |||
2012 | // Administrative stuff for modinfo. | ||
2013 | MODULE_AUTHOR | ||
2014 | ("Guenter Gebhardt <g.gebhardt@meilhaus.de> & Krzysztof Gantzke <k.gantzke@meilhaus.de>"); | ||
2015 | MODULE_DESCRIPTION("Central module for Meilhaus Driver System."); | ||
2016 | MODULE_SUPPORTED_DEVICE("Meilhaus PCI/cPCI boards."); | ||
2017 | MODULE_LICENSE("GPL"); | ||
2018 | |||
2019 | #ifdef BOSCH | ||
2020 | // Export the flag for the BOSCH firmware. | ||
2021 | EXPORT_SYMBOL(me_bosch_fw); | ||
2022 | #endif // BOSCH | ||
diff --git a/drivers/staging/meilhaus/memain.h b/drivers/staging/meilhaus/memain.h new file mode 100644 index 000000000000..7616ff7f65cb --- /dev/null +++ b/drivers/staging/meilhaus/memain.h | |||
@@ -0,0 +1,460 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
3 | * | ||
4 | * Source File : memain.h | ||
5 | * Author : GG (Guenter Gebhardt) <g.gebhardt@meilhaus.de> | ||
6 | */ | ||
7 | |||
8 | #ifndef _MEMAIN_H_ | ||
9 | #define _MEMAIN_H_ | ||
10 | |||
11 | #include "meinternal.h" | ||
12 | |||
13 | #include "meids.h" | ||
14 | #include "medebug.h" | ||
15 | |||
16 | #include "medevice.h" | ||
17 | /*#include "me1000_device.h" | ||
18 | #include "me1400_device.h" | ||
19 | #include "me1600_device.h"*/ | ||
20 | #include "me4600_device.h" | ||
21 | /*#include "me6000_device.h" | ||
22 | #include "me0600_device.h" | ||
23 | #include "me8100_device.h" | ||
24 | #include "me8200_device.h" | ||
25 | #include "me0900_device.h"*/ | ||
26 | #include "medummy.h" | ||
27 | |||
28 | #ifdef __KERNEL__ | ||
29 | |||
30 | /*============================================================================= | ||
31 | PCI device table. | ||
32 | This is used by modprobe to translate PCI IDs to drivers. | ||
33 | ===========================================================================*/ | ||
34 | |||
35 | static struct pci_device_id me_pci_table[] __devinitdata = { | ||
36 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1000, PCI_ANY_ID, | ||
37 | PCI_ANY_ID, 0, 0, 0}, | ||
38 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1000_A, PCI_ANY_ID, | ||
39 | PCI_ANY_ID, 0, 0, 0}, | ||
40 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1000_B, PCI_ANY_ID, | ||
41 | PCI_ANY_ID, 0, 0, 0}, | ||
42 | |||
43 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1400, PCI_ANY_ID, | ||
44 | PCI_ANY_ID, 0, 0, 0}, | ||
45 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME140A, PCI_ANY_ID, | ||
46 | PCI_ANY_ID, 0, 0, 0}, | ||
47 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME140B, PCI_ANY_ID, | ||
48 | PCI_ANY_ID, 0, 0, 0}, | ||
49 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME14E0, PCI_ANY_ID, | ||
50 | PCI_ANY_ID, 0, 0, 0}, | ||
51 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME14EA, PCI_ANY_ID, | ||
52 | PCI_ANY_ID, 0, 0, 0}, | ||
53 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME14EB, PCI_ANY_ID, | ||
54 | PCI_ANY_ID, 0, 0, 0}, | ||
55 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME140C, PCI_ANY_ID, | ||
56 | PCI_ANY_ID, 0, 0, 0}, | ||
57 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME140D, PCI_ANY_ID, | ||
58 | PCI_ANY_ID, 0, 0, 0}, | ||
59 | |||
60 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1600_4U, PCI_ANY_ID, | ||
61 | PCI_ANY_ID, 0, 0, 0}, | ||
62 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1600_8U, PCI_ANY_ID, | ||
63 | PCI_ANY_ID, 0, 0, 0}, | ||
64 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1600_12U, PCI_ANY_ID, | ||
65 | PCI_ANY_ID, 0, 0, 0}, | ||
66 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1600_16U, PCI_ANY_ID, | ||
67 | PCI_ANY_ID, 0, 0, 0}, | ||
68 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1600_16U_8I, | ||
69 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
70 | |||
71 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4610, PCI_ANY_ID, | ||
72 | PCI_ANY_ID, 0, 0, 0}, | ||
73 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4650, PCI_ANY_ID, | ||
74 | PCI_ANY_ID, 0, 0, 0}, | ||
75 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660, PCI_ANY_ID, | ||
76 | PCI_ANY_ID, 0, 0, 0}, | ||
77 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660I, PCI_ANY_ID, | ||
78 | PCI_ANY_ID, 0, 0, 0}, | ||
79 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670, PCI_ANY_ID, | ||
80 | PCI_ANY_ID, 0, 0, 0}, | ||
81 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670I, PCI_ANY_ID, | ||
82 | PCI_ANY_ID, 0, 0, 0}, | ||
83 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670S, PCI_ANY_ID, | ||
84 | PCI_ANY_ID, 0, 0, 0}, | ||
85 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670IS, PCI_ANY_ID, | ||
86 | PCI_ANY_ID, 0, 0, 0}, | ||
87 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680, PCI_ANY_ID, | ||
88 | PCI_ANY_ID, 0, 0, 0}, | ||
89 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680I, PCI_ANY_ID, | ||
90 | PCI_ANY_ID, 0, 0, 0}, | ||
91 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680S, PCI_ANY_ID, | ||
92 | PCI_ANY_ID, 0, 0, 0}, | ||
93 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680IS, PCI_ANY_ID, | ||
94 | PCI_ANY_ID, 0, 0, 0}, | ||
95 | |||
96 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6004, PCI_ANY_ID, | ||
97 | PCI_ANY_ID, 0, 0, 0}, | ||
98 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6008, PCI_ANY_ID, | ||
99 | PCI_ANY_ID, 0, 0, 0}, | ||
100 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME600F, PCI_ANY_ID, | ||
101 | PCI_ANY_ID, 0, 0, 0}, | ||
102 | |||
103 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6014, PCI_ANY_ID, | ||
104 | PCI_ANY_ID, 0, 0, 0}, | ||
105 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6018, PCI_ANY_ID, | ||
106 | PCI_ANY_ID, 0, 0, 0}, | ||
107 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME601F, PCI_ANY_ID, | ||
108 | PCI_ANY_ID, 0, 0, 0}, | ||
109 | |||
110 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6034, PCI_ANY_ID, | ||
111 | PCI_ANY_ID, 0, 0, 0}, | ||
112 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6038, PCI_ANY_ID, | ||
113 | PCI_ANY_ID, 0, 0, 0}, | ||
114 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME603F, PCI_ANY_ID, | ||
115 | PCI_ANY_ID, 0, 0, 0}, | ||
116 | |||
117 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6104, PCI_ANY_ID, | ||
118 | PCI_ANY_ID, 0, 0, 0}, | ||
119 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6108, PCI_ANY_ID, | ||
120 | PCI_ANY_ID, 0, 0, 0}, | ||
121 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME610F, PCI_ANY_ID, | ||
122 | PCI_ANY_ID, 0, 0, 0}, | ||
123 | |||
124 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6114, PCI_ANY_ID, | ||
125 | PCI_ANY_ID, 0, 0, 0}, | ||
126 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6118, PCI_ANY_ID, | ||
127 | PCI_ANY_ID, 0, 0, 0}, | ||
128 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME611F, PCI_ANY_ID, | ||
129 | PCI_ANY_ID, 0, 0, 0}, | ||
130 | |||
131 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6134, PCI_ANY_ID, | ||
132 | PCI_ANY_ID, 0, 0, 0}, | ||
133 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6138, PCI_ANY_ID, | ||
134 | PCI_ANY_ID, 0, 0, 0}, | ||
135 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME613F, PCI_ANY_ID, | ||
136 | PCI_ANY_ID, 0, 0, 0}, | ||
137 | |||
138 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6044, PCI_ANY_ID, | ||
139 | PCI_ANY_ID, 0, 0, 0}, | ||
140 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6048, PCI_ANY_ID, | ||
141 | PCI_ANY_ID, 0, 0, 0}, | ||
142 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME604F, PCI_ANY_ID, | ||
143 | PCI_ANY_ID, 0, 0, 0}, | ||
144 | |||
145 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6054, PCI_ANY_ID, | ||
146 | PCI_ANY_ID, 0, 0, 0}, | ||
147 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6058, PCI_ANY_ID, | ||
148 | PCI_ANY_ID, 0, 0, 0}, | ||
149 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME605F, PCI_ANY_ID, | ||
150 | PCI_ANY_ID, 0, 0, 0}, | ||
151 | |||
152 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6074, PCI_ANY_ID, | ||
153 | PCI_ANY_ID, 0, 0, 0}, | ||
154 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6078, PCI_ANY_ID, | ||
155 | PCI_ANY_ID, 0, 0, 0}, | ||
156 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME607F, PCI_ANY_ID, | ||
157 | PCI_ANY_ID, 0, 0, 0}, | ||
158 | |||
159 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6144, PCI_ANY_ID, | ||
160 | PCI_ANY_ID, 0, 0, 0}, | ||
161 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6148, PCI_ANY_ID, | ||
162 | PCI_ANY_ID, 0, 0, 0}, | ||
163 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME614F, PCI_ANY_ID, | ||
164 | PCI_ANY_ID, 0, 0, 0}, | ||
165 | |||
166 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6154, PCI_ANY_ID, | ||
167 | PCI_ANY_ID, 0, 0, 0}, | ||
168 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6158, PCI_ANY_ID, | ||
169 | PCI_ANY_ID, 0, 0, 0}, | ||
170 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME615F, PCI_ANY_ID, | ||
171 | PCI_ANY_ID, 0, 0, 0}, | ||
172 | |||
173 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6174, PCI_ANY_ID, | ||
174 | PCI_ANY_ID, 0, 0, 0}, | ||
175 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6178, PCI_ANY_ID, | ||
176 | PCI_ANY_ID, 0, 0, 0}, | ||
177 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME617F, PCI_ANY_ID, | ||
178 | PCI_ANY_ID, 0, 0, 0}, | ||
179 | |||
180 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6259, PCI_ANY_ID, | ||
181 | PCI_ANY_ID, 0, 0, 0}, | ||
182 | |||
183 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6359, PCI_ANY_ID, | ||
184 | PCI_ANY_ID, 0, 0, 0}, | ||
185 | |||
186 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME0630, PCI_ANY_ID, | ||
187 | PCI_ANY_ID, 0, 0, 0}, | ||
188 | |||
189 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME8100_A, PCI_ANY_ID, | ||
190 | PCI_ANY_ID, 0, 0, 0}, | ||
191 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME8100_B, PCI_ANY_ID, | ||
192 | PCI_ANY_ID, 0, 0, 0}, | ||
193 | |||
194 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME8200_A, PCI_ANY_ID, | ||
195 | PCI_ANY_ID, 0, 0, 0}, | ||
196 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME8200_B, PCI_ANY_ID, | ||
197 | PCI_ANY_ID, 0, 0, 0}, | ||
198 | |||
199 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME0940, PCI_ANY_ID, | ||
200 | PCI_ANY_ID, 0, 0, 0}, | ||
201 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME0950, PCI_ANY_ID, | ||
202 | PCI_ANY_ID, 0, 0, 0}, | ||
203 | {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME0960, PCI_ANY_ID, | ||
204 | PCI_ANY_ID, 0, 0, 0}, | ||
205 | |||
206 | {0} | ||
207 | }; | ||
208 | |||
209 | MODULE_DEVICE_TABLE(pci, me_pci_table); | ||
210 | |||
211 | /*============================================================================= | ||
212 | USB device table. | ||
213 | This is used by modprobe to translate USB IDs to drivers. | ||
214 | ===========================================================================*/ | ||
215 | /* | ||
216 | static struct usb_device_id me_usb_table[] __devinitdata = { | ||
217 | { USB_DEVICE(USB_VENDOR_ID_MEPHISTO_S1, USB_DEVICE_ID_MEPHISTO_S1) }, | ||
218 | { 0 } | ||
219 | }; | ||
220 | |||
221 | MODULE_DEVICE_TABLE (usb, me_usb_table); | ||
222 | */ | ||
223 | |||
224 | /*============================================================================= | ||
225 | Templates | ||
226 | ===========================================================================*/ | ||
227 | |||
228 | #define ME_LOCK_MULTIPLEX_TEMPLATE(NAME, TYPE, CALL, DEV_CALL, ARGS) \ | ||
229 | static int CALL(struct file *filep, TYPE *arg){ \ | ||
230 | int err = 0; \ | ||
231 | int k = 0; \ | ||
232 | struct list_head *pos; \ | ||
233 | me_device_t *device; \ | ||
234 | TYPE karg; \ | ||
235 | \ | ||
236 | PDEBUG("executed.\n"); \ | ||
237 | \ | ||
238 | err = copy_from_user(&karg, arg, sizeof(TYPE)); \ | ||
239 | if(err){ \ | ||
240 | PERROR("Can't copy arguments to kernel space\n"); \ | ||
241 | return -EFAULT; \ | ||
242 | } \ | ||
243 | \ | ||
244 | down_read(&me_rwsem); \ | ||
245 | \ | ||
246 | list_for_each(pos, &me_device_list){ \ | ||
247 | if(k == karg.device){ \ | ||
248 | device = list_entry(pos, me_device_t, list); \ | ||
249 | break; \ | ||
250 | } \ | ||
251 | k++; \ | ||
252 | } \ | ||
253 | \ | ||
254 | if(pos == &me_device_list){ \ | ||
255 | PERROR("Invalid device number specified\n"); \ | ||
256 | karg.errno = ME_ERRNO_INVALID_DEVICE; \ | ||
257 | } \ | ||
258 | else{ \ | ||
259 | spin_lock(&me_lock); \ | ||
260 | if((me_filep != NULL) && (me_filep != filep)){ \ | ||
261 | spin_unlock(&me_lock); \ | ||
262 | PERROR("Resource is locked by another process\n"); \ | ||
263 | if(karg.lock == ME_LOCK_SET) \ | ||
264 | karg.errno = ME_ERRNO_LOCKED; \ | ||
265 | else if(karg.lock == ME_LOCK_RELEASE) \ | ||
266 | karg.errno = ME_ERRNO_SUCCESS; \ | ||
267 | else{ \ | ||
268 | PERROR("Invalid lock specified\n"); \ | ||
269 | karg.errno = ME_ERRNO_INVALID_LOCK; \ | ||
270 | }\ | ||
271 | } \ | ||
272 | else { \ | ||
273 | me_count++; \ | ||
274 | spin_unlock(&me_lock); \ | ||
275 | \ | ||
276 | karg.errno = device->DEV_CALL ARGS; \ | ||
277 | \ | ||
278 | spin_lock(&me_lock); \ | ||
279 | me_count--; \ | ||
280 | spin_unlock(&me_lock); \ | ||
281 | } \ | ||
282 | } \ | ||
283 | \ | ||
284 | up_read(&me_rwsem); \ | ||
285 | \ | ||
286 | err = copy_to_user(arg, &karg, sizeof(TYPE)); \ | ||
287 | if(err){ \ | ||
288 | PERROR("Can't copy arguments back to user space\n"); \ | ||
289 | return -EFAULT; \ | ||
290 | } \ | ||
291 | \ | ||
292 | return ME_ERRNO_SUCCESS; \ | ||
293 | } | ||
294 | |||
295 | #define ME_IO_MULTIPLEX_TEMPLATE(NAME, TYPE, CALL, DEV_CALL, ARGS) \ | ||
296 | static int CALL(struct file *filep, TYPE *arg){ \ | ||
297 | int err = 0; \ | ||
298 | int k = 0; \ | ||
299 | struct list_head *pos; \ | ||
300 | me_device_t *device; \ | ||
301 | TYPE karg; \ | ||
302 | \ | ||
303 | PDEBUG("executed.\n"); \ | ||
304 | \ | ||
305 | err = copy_from_user(&karg, arg, sizeof(TYPE)); \ | ||
306 | if(err){ \ | ||
307 | PERROR("Can't copy arguments to kernel space\n"); \ | ||
308 | return -EFAULT; \ | ||
309 | } \ | ||
310 | \ | ||
311 | down_read(&me_rwsem); \ | ||
312 | \ | ||
313 | list_for_each(pos, &me_device_list){ \ | ||
314 | if(k == karg.device){ \ | ||
315 | device = list_entry(pos, me_device_t, list); \ | ||
316 | break; \ | ||
317 | } \ | ||
318 | k++; \ | ||
319 | } \ | ||
320 | \ | ||
321 | if(pos == &me_device_list){ \ | ||
322 | PERROR("Invalid device number specified\n"); \ | ||
323 | karg.errno = ME_ERRNO_INVALID_DEVICE; \ | ||
324 | } \ | ||
325 | else{ \ | ||
326 | spin_lock(&me_lock); \ | ||
327 | if((me_filep != NULL) && (me_filep != filep)){ \ | ||
328 | spin_unlock(&me_lock); \ | ||
329 | PERROR("Resource is locked by another process\n"); \ | ||
330 | karg.errno = ME_ERRNO_LOCKED; \ | ||
331 | } \ | ||
332 | else { \ | ||
333 | me_count++; \ | ||
334 | spin_unlock(&me_lock); \ | ||
335 | \ | ||
336 | karg.errno = device->DEV_CALL ARGS; \ | ||
337 | \ | ||
338 | spin_lock(&me_lock); \ | ||
339 | me_count--; \ | ||
340 | spin_unlock(&me_lock); \ | ||
341 | } \ | ||
342 | } \ | ||
343 | \ | ||
344 | up_read(&me_rwsem); \ | ||
345 | \ | ||
346 | err = copy_to_user(arg, &karg, sizeof(TYPE)); \ | ||
347 | if(err){ \ | ||
348 | PERROR("Can't copy arguments back to user space\n"); \ | ||
349 | return -EFAULT; \ | ||
350 | } \ | ||
351 | \ | ||
352 | return ME_ERRNO_SUCCESS; \ | ||
353 | } | ||
354 | |||
355 | #define ME_QUERY_MULTIPLEX_STR_TEMPLATE(NAME, TYPE, CALL, DEV_CALL, ARGS) \ | ||
356 | static int CALL(struct file *filep, TYPE *arg){ \ | ||
357 | int err = 0; \ | ||
358 | int k = 0; \ | ||
359 | struct list_head *pos; \ | ||
360 | me_device_t *device; \ | ||
361 | char *msg = NULL; \ | ||
362 | TYPE karg; \ | ||
363 | \ | ||
364 | PDEBUG("executed.\n"); \ | ||
365 | \ | ||
366 | err = copy_from_user(&karg, arg, sizeof(TYPE)); \ | ||
367 | if(err){ \ | ||
368 | PERROR("Can't copy arguments to kernel space\n"); \ | ||
369 | return -EFAULT; \ | ||
370 | } \ | ||
371 | \ | ||
372 | down_read(&me_rwsem); \ | ||
373 | \ | ||
374 | list_for_each(pos, &me_device_list){ \ | ||
375 | if(k == karg.device){ \ | ||
376 | device = list_entry(pos, me_device_t, list); \ | ||
377 | break; \ | ||
378 | } \ | ||
379 | k++; \ | ||
380 | } \ | ||
381 | \ | ||
382 | if(pos == &me_device_list){ \ | ||
383 | PERROR("Invalid device number specified\n"); \ | ||
384 | karg.errno = ME_ERRNO_INVALID_DEVICE; \ | ||
385 | } \ | ||
386 | else{ \ | ||
387 | karg.errno = device->DEV_CALL ARGS; \ | ||
388 | if(!karg.errno){ \ | ||
389 | if((strlen(msg) + 1) > karg.count){ \ | ||
390 | PERROR("User buffer for device name is to little\n"); \ | ||
391 | karg.errno = ME_ERRNO_USER_BUFFER_SIZE; \ | ||
392 | } \ | ||
393 | else{ \ | ||
394 | err = copy_to_user(karg.name, msg, strlen(msg) + 1); \ | ||
395 | if(err){ \ | ||
396 | PERROR("Can't copy device name to user space\n"); \ | ||
397 | return -EFAULT; \ | ||
398 | } \ | ||
399 | } \ | ||
400 | } \ | ||
401 | } \ | ||
402 | \ | ||
403 | up_read(&me_rwsem); \ | ||
404 | \ | ||
405 | err = copy_to_user(arg, &karg, sizeof(TYPE)); \ | ||
406 | if(err){ \ | ||
407 | PERROR("Can't copy query back to user space\n"); \ | ||
408 | return -EFAULT; \ | ||
409 | } \ | ||
410 | \ | ||
411 | return ME_ERRNO_SUCCESS; \ | ||
412 | } | ||
413 | |||
414 | #define ME_QUERY_MULTIPLEX_TEMPLATE(NAME, TYPE, CALL, DEV_CALL, ARGS) \ | ||
415 | static int CALL(struct file *filep, TYPE *arg){ \ | ||
416 | int err = 0; \ | ||
417 | int k = 0; \ | ||
418 | struct list_head *pos; \ | ||
419 | me_device_t *device; \ | ||
420 | TYPE karg; \ | ||
421 | \ | ||
422 | PDEBUG("executed.\n"); \ | ||
423 | \ | ||
424 | err = copy_from_user(&karg, arg, sizeof(TYPE)); \ | ||
425 | if(err){ \ | ||
426 | PERROR("Can't copy arguments from user space\n"); \ | ||
427 | return -EFAULT; \ | ||
428 | } \ | ||
429 | \ | ||
430 | down_read(&me_rwsem); \ | ||
431 | \ | ||
432 | list_for_each(pos, &me_device_list){ \ | ||
433 | if(k == karg.device){ \ | ||
434 | device = list_entry(pos, me_device_t, list); \ | ||
435 | break; \ | ||
436 | } \ | ||
437 | k++; \ | ||
438 | } \ | ||
439 | \ | ||
440 | if(pos == &me_device_list){ \ | ||
441 | PERROR("Invalid device number specified\n"); \ | ||
442 | karg.errno = ME_ERRNO_INVALID_DEVICE; \ | ||
443 | } \ | ||
444 | else{ \ | ||
445 | karg.errno = device->DEV_CALL ARGS; \ | ||
446 | } \ | ||
447 | \ | ||
448 | up_read(&me_rwsem); \ | ||
449 | \ | ||
450 | err = copy_to_user(arg, &karg, sizeof(TYPE)); \ | ||
451 | if(err){ \ | ||
452 | PERROR("Can't copy arguments to user space\n"); \ | ||
453 | return -EFAULT; \ | ||
454 | } \ | ||
455 | \ | ||
456 | return ME_ERRNO_SUCCESS; \ | ||
457 | } | ||
458 | |||
459 | #endif //__KERNEL__ | ||
460 | #endif | ||
diff --git a/drivers/staging/meilhaus/meplx_reg.h b/drivers/staging/meilhaus/meplx_reg.h new file mode 100644 index 000000000000..1868614dc232 --- /dev/null +++ b/drivers/staging/meilhaus/meplx_reg.h | |||
@@ -0,0 +1,53 @@ | |||
1 | /** | ||
2 | * @file meplx_reg.h | ||
3 | * | ||
4 | * @brief PLX 9052 PCI bridge register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _MEPLX_REG_H_ | ||
28 | #define _MEPLX_REG_H_ | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | #define PLX_INTCSR 0x4C /**< Interrupt control and status register. */ | ||
33 | #define PLX_INTCSR_LOCAL_INT1_EN 0x01 /**< If set, local interrupt 1 is enabled (r/w). */ | ||
34 | #define PLX_INTCSR_LOCAL_INT1_POL 0x02 /**< If set, local interrupt 1 polarity is active high (r/w). */ | ||
35 | #define PLX_INTCSR_LOCAL_INT1_STATE 0x04 /**< If set, local interrupt 1 is active (r/_). */ | ||
36 | #define PLX_INTCSR_LOCAL_INT2_EN 0x08 /**< If set, local interrupt 2 is enabled (r/w). */ | ||
37 | #define PLX_INTCSR_LOCAL_INT2_POL 0x10 /**< If set, local interrupt 2 polarity is active high (r/w). */ | ||
38 | #define PLX_INTCSR_LOCAL_INT2_STATE 0x20 /**< If set, local interrupt 2 is active (r/_). */ | ||
39 | #define PLX_INTCSR_PCI_INT_EN 0x40 /**< If set, PCI interrupt is enabled (r/w). */ | ||
40 | #define PLX_INTCSR_SOFT_INT 0x80 /**< If set, a software interrupt is generated (r/w). */ | ||
41 | |||
42 | #define PLX_ICR 0x50 /**< Initialization control register. */ | ||
43 | #define PLX_ICR_BIT_EEPROM_CLOCK_SET 0x01000000 | ||
44 | #define PLX_ICR_BIT_EEPROM_CHIP_SELECT 0x02000000 | ||
45 | #define PLX_ICR_BIT_EEPROM_WRITE 0x04000000 | ||
46 | #define PLX_ICR_BIT_EEPROM_READ 0x08000000 | ||
47 | #define PLX_ICR_BIT_EEPROM_VALID 0x10000000 | ||
48 | |||
49 | #define PLX_ICR_MASK_EEPROM 0x1F000000 | ||
50 | #define EEPROM_DELAY 1 | ||
51 | |||
52 | #endif | ||
53 | #endif | ||
diff --git a/drivers/staging/meilhaus/meslist.c b/drivers/staging/meilhaus/meslist.c new file mode 100644 index 000000000000..7e8b66c05f7e --- /dev/null +++ b/drivers/staging/meilhaus/meslist.c | |||
@@ -0,0 +1,173 @@ | |||
1 | /** | ||
2 | * @file me_slist.c | ||
3 | * | ||
4 | * @brief Implements the subdevice list class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #include "meerror.h" | ||
28 | #include "medefines.h" | ||
29 | |||
30 | #include "meslist.h" | ||
31 | #include "medebug.h" | ||
32 | |||
33 | int me_slist_query_number_subdevices(struct me_slist *slist, int *number) | ||
34 | { | ||
35 | PDEBUG_LOCKS("called.\n"); | ||
36 | *number = slist->n; | ||
37 | return ME_ERRNO_SUCCESS; | ||
38 | } | ||
39 | |||
40 | unsigned int me_slist_get_number_subdevices(struct me_slist *slist) | ||
41 | { | ||
42 | PDEBUG_LOCKS("called.\n"); | ||
43 | return slist->n; | ||
44 | } | ||
45 | |||
46 | me_subdevice_t *me_slist_get_subdevice(struct me_slist * slist, | ||
47 | unsigned int index) | ||
48 | { | ||
49 | |||
50 | struct list_head *pos; | ||
51 | me_subdevice_t *subdevice = NULL; | ||
52 | unsigned int i = 0; | ||
53 | |||
54 | PDEBUG_LOCKS("called.\n"); | ||
55 | |||
56 | if (index >= slist->n) { | ||
57 | PERROR("Index out of range.\n"); | ||
58 | return NULL; | ||
59 | } | ||
60 | |||
61 | list_for_each(pos, &slist->head) { | ||
62 | if (i == index) { | ||
63 | subdevice = list_entry(pos, me_subdevice_t, list); | ||
64 | break; | ||
65 | } | ||
66 | |||
67 | ++i; | ||
68 | } | ||
69 | |||
70 | return subdevice; | ||
71 | } | ||
72 | |||
73 | int me_slist_get_subdevice_by_type(struct me_slist *slist, | ||
74 | unsigned int start_subdevice, | ||
75 | int type, int subtype, int *subdevice) | ||
76 | { | ||
77 | me_subdevice_t *pos; | ||
78 | int s_type, s_subtype; | ||
79 | unsigned int index = 0; | ||
80 | |||
81 | PDEBUG_LOCKS("called.\n"); | ||
82 | |||
83 | if (start_subdevice >= slist->n) { | ||
84 | PERROR("Start index out of range.\n"); | ||
85 | return ME_ERRNO_NOMORE_SUBDEVICE_TYPE; | ||
86 | } | ||
87 | |||
88 | list_for_each_entry(pos, &slist->head, list) { | ||
89 | if (index < start_subdevice) { // Go forward to start subdevice. | ||
90 | ++index; | ||
91 | continue; | ||
92 | } | ||
93 | |||
94 | pos->me_subdevice_query_subdevice_type(pos, | ||
95 | &s_type, &s_subtype); | ||
96 | |||
97 | if (subtype == ME_SUBTYPE_ANY) { | ||
98 | if (s_type == type) | ||
99 | break; | ||
100 | } else { | ||
101 | if ((s_type == type) && (s_subtype == subtype)) | ||
102 | break; | ||
103 | } | ||
104 | |||
105 | ++index; | ||
106 | } | ||
107 | |||
108 | if (index >= slist->n) { | ||
109 | return ME_ERRNO_NOMORE_SUBDEVICE_TYPE; | ||
110 | } | ||
111 | |||
112 | *subdevice = index; | ||
113 | |||
114 | return ME_ERRNO_SUCCESS; | ||
115 | } | ||
116 | |||
117 | void me_slist_add_subdevice_tail(struct me_slist *slist, | ||
118 | me_subdevice_t * subdevice) | ||
119 | { | ||
120 | PDEBUG_LOCKS("called.\n"); | ||
121 | |||
122 | list_add_tail(&subdevice->list, &slist->head); | ||
123 | ++slist->n; | ||
124 | } | ||
125 | |||
126 | me_subdevice_t *me_slist_del_subdevice_tail(struct me_slist *slist) | ||
127 | { | ||
128 | |||
129 | struct list_head *last; | ||
130 | me_subdevice_t *subdevice; | ||
131 | |||
132 | PDEBUG_LOCKS("called.\n"); | ||
133 | |||
134 | if (list_empty(&slist->head)) | ||
135 | return NULL; | ||
136 | |||
137 | last = slist->head.prev; | ||
138 | |||
139 | subdevice = list_entry(last, me_subdevice_t, list); | ||
140 | |||
141 | list_del(last); | ||
142 | |||
143 | --slist->n; | ||
144 | |||
145 | return subdevice; | ||
146 | } | ||
147 | |||
148 | int me_slist_init(me_slist_t * slist) | ||
149 | { | ||
150 | PDEBUG_LOCKS("called.\n"); | ||
151 | |||
152 | INIT_LIST_HEAD(&slist->head); | ||
153 | slist->n = 0; | ||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | void me_slist_deinit(me_slist_t * slist) | ||
158 | { | ||
159 | |||
160 | struct list_head *s; | ||
161 | me_subdevice_t *subdevice; | ||
162 | |||
163 | PDEBUG_LOCKS("called.\n"); | ||
164 | |||
165 | while (!list_empty(&slist->head)) { | ||
166 | s = slist->head.next; | ||
167 | list_del(s); | ||
168 | subdevice = list_entry(s, me_subdevice_t, list); | ||
169 | subdevice->me_subdevice_destructor(subdevice); | ||
170 | } | ||
171 | |||
172 | slist->n = 0; | ||
173 | } | ||
diff --git a/drivers/staging/meilhaus/meslist.h b/drivers/staging/meilhaus/meslist.h new file mode 100644 index 000000000000..d26c89693d2c --- /dev/null +++ b/drivers/staging/meilhaus/meslist.h | |||
@@ -0,0 +1,108 @@ | |||
1 | /** | ||
2 | * @file me_slist.h | ||
3 | * | ||
4 | * @brief Provides the subdevice list class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | #ifndef _ME_SLIST_H_ | ||
10 | #define _ME_SLIST_H_ | ||
11 | |||
12 | #include <linux/list.h> | ||
13 | |||
14 | #include "mesubdevice.h" | ||
15 | |||
16 | #ifdef __KERNEL__ | ||
17 | |||
18 | /** | ||
19 | * @brief The subdevice list container. | ||
20 | */ | ||
21 | typedef struct me_slist { | ||
22 | struct list_head head; /**< The head of the internal list. */ | ||
23 | unsigned int n; /**< The number of subdevices in the list. */ | ||
24 | } me_slist_t; | ||
25 | |||
26 | /** | ||
27 | * @brief Queries the number of subdevices currently inside the list. | ||
28 | * | ||
29 | * @param slist The subdevice list to query. | ||
30 | * @param[out] number The number of subdevices of the device. | ||
31 | * | ||
32 | * @return ME-iDS error code. | ||
33 | */ | ||
34 | int me_slist_query_number_subdevices(struct me_slist *slist, int *number); | ||
35 | |||
36 | /** | ||
37 | * @brief Returns the number of subdevices currently inside the list. | ||
38 | * | ||
39 | * @param slist The subdevice list to query. | ||
40 | * | ||
41 | * @return The number of subdevices in the list. | ||
42 | */ | ||
43 | unsigned int me_slist_get_number_subdevices(struct me_slist *slist); | ||
44 | |||
45 | /** | ||
46 | * @brief Get a subdevice by index. | ||
47 | * | ||
48 | * @param slist The subdevice list to query. | ||
49 | * @param index The index of the subdevice to get in the list. | ||
50 | * | ||
51 | * @return The subdevice at index if available.\n | ||
52 | * NULL if the index is out of range. | ||
53 | */ | ||
54 | me_subdevice_t *me_slist_get_subdevice(struct me_slist *slist, | ||
55 | unsigned int index); | ||
56 | |||
57 | /** | ||
58 | * @brief Get a subdevice index by type and subtype. | ||
59 | * | ||
60 | * @param slist The subdevice list to query. | ||
61 | * @param start_subdevice The subdevice index at which the start shall begin. | ||
62 | * @param type The type of the subdevice to query. | ||
63 | * @param subtype The subtype of the subdevice to query. | ||
64 | * @param[out] subdevice On success this parameter returns the index of the subdevice matching the requested type. | ||
65 | * | ||
66 | * @return ME_ERRNO_SUCCESS on success. | ||
67 | */ | ||
68 | int me_slist_get_subdevice_by_type(struct me_slist *slist, | ||
69 | unsigned int start_subdevice, | ||
70 | int type, int subtype, int *subdevice); | ||
71 | |||
72 | /** | ||
73 | * @brief Adds a subdevice to the tail of the list. | ||
74 | * | ||
75 | * @param slist The subdevice list to add a subdevice to. | ||
76 | * @param subdevice The subdevice to add to the list. | ||
77 | */ | ||
78 | void me_slist_add_subdevice_tail(struct me_slist *slist, | ||
79 | me_subdevice_t * subdevice); | ||
80 | |||
81 | /** | ||
82 | * @brief Removes a subdevice from the tail of the list. | ||
83 | * | ||
84 | * @param slist The subdevice list. | ||
85 | * | ||
86 | * @return Pointer to the removed subdeivce.\n | ||
87 | * NULL in cases where the list was empty. | ||
88 | */ | ||
89 | me_subdevice_t *me_slist_del_subdevice_tail(struct me_slist *slist); | ||
90 | |||
91 | /** | ||
92 | * @brief Initializes a subdevice list structure. | ||
93 | * | ||
94 | * @param lock The subdevice list structure to initialize. | ||
95 | * @return 0 on success. | ||
96 | */ | ||
97 | int me_slist_init(me_slist_t * slist); | ||
98 | |||
99 | /** | ||
100 | * @brief Deinitializes a subdevice list structure and destructs every subdevice in it. | ||
101 | * | ||
102 | * @param slist The subdevice list structure to deinitialize. | ||
103 | * @return 0 on success. | ||
104 | */ | ||
105 | void me_slist_deinit(me_slist_t * slist); | ||
106 | |||
107 | #endif | ||
108 | #endif | ||
diff --git a/drivers/staging/meilhaus/meslock.c b/drivers/staging/meilhaus/meslock.c new file mode 100644 index 000000000000..5230b89b45b5 --- /dev/null +++ b/drivers/staging/meilhaus/meslock.c | |||
@@ -0,0 +1,136 @@ | |||
1 | /** | ||
2 | * @file meslock.c | ||
3 | * | ||
4 | * @brief Implements the subdevice lock class. | ||
5 | * @note Copyright (C) 2006 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2006 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #include <linux/spinlock.h> | ||
28 | |||
29 | #include "medefines.h" | ||
30 | #include "meerror.h" | ||
31 | |||
32 | #include "medebug.h" | ||
33 | #include "meslock.h" | ||
34 | |||
35 | int me_slock_enter(struct me_slock *slock, struct file *filep) | ||
36 | { | ||
37 | PDEBUG_LOCKS("executed.\n"); | ||
38 | |||
39 | spin_lock(&slock->spin_lock); | ||
40 | |||
41 | if ((slock->filep) != NULL && (slock->filep != filep)) { | ||
42 | PERROR("Subdevice is locked by another process.\n"); | ||
43 | spin_unlock(&slock->spin_lock); | ||
44 | return ME_ERRNO_LOCKED; | ||
45 | } | ||
46 | |||
47 | slock->count++; | ||
48 | |||
49 | spin_unlock(&slock->spin_lock); | ||
50 | |||
51 | return ME_ERRNO_SUCCESS; | ||
52 | } | ||
53 | |||
54 | int me_slock_exit(struct me_slock *slock, struct file *filep) | ||
55 | { | ||
56 | PDEBUG_LOCKS("executed.\n"); | ||
57 | |||
58 | spin_lock(&slock->spin_lock); | ||
59 | slock->count--; | ||
60 | spin_unlock(&slock->spin_lock); | ||
61 | |||
62 | return ME_ERRNO_SUCCESS; | ||
63 | } | ||
64 | |||
65 | int me_slock_lock(struct me_slock *slock, struct file *filep, int lock) | ||
66 | { | ||
67 | PDEBUG_LOCKS("executed.\n"); | ||
68 | |||
69 | switch (lock) { | ||
70 | |||
71 | case ME_LOCK_RELEASE: | ||
72 | spin_lock(&slock->spin_lock); | ||
73 | |||
74 | if (slock->filep == filep) | ||
75 | slock->filep = NULL; | ||
76 | |||
77 | spin_unlock(&slock->spin_lock); | ||
78 | |||
79 | break; | ||
80 | |||
81 | case ME_LOCK_SET: | ||
82 | spin_lock(&slock->spin_lock); | ||
83 | |||
84 | if (slock->count) { | ||
85 | spin_unlock(&slock->spin_lock); | ||
86 | PERROR("Subdevice is used by another process.\n"); | ||
87 | return ME_ERRNO_USED; | ||
88 | } else if (slock->filep == NULL) | ||
89 | slock->filep = filep; | ||
90 | else if (slock->filep != filep) { | ||
91 | spin_unlock(&slock->spin_lock); | ||
92 | PERROR("Subdevice is locked by another process.\n"); | ||
93 | return ME_ERRNO_LOCKED; | ||
94 | } | ||
95 | |||
96 | spin_unlock(&slock->spin_lock); | ||
97 | |||
98 | break; | ||
99 | |||
100 | case ME_LOCK_CHECK: | ||
101 | spin_lock(&slock->spin_lock); | ||
102 | |||
103 | if (slock->count) { | ||
104 | spin_unlock(&slock->spin_lock); | ||
105 | return ME_ERRNO_USED; | ||
106 | } else if ((slock->filep != NULL) && (slock->filep != filep)) { | ||
107 | spin_unlock(&slock->spin_lock); | ||
108 | return ME_ERRNO_LOCKED; | ||
109 | } | ||
110 | |||
111 | spin_unlock(&slock->spin_lock); | ||
112 | |||
113 | break; | ||
114 | |||
115 | default: | ||
116 | break; | ||
117 | } | ||
118 | |||
119 | return ME_ERRNO_SUCCESS; | ||
120 | } | ||
121 | |||
122 | void me_slock_deinit(struct me_slock *slock) | ||
123 | { | ||
124 | PDEBUG_LOCKS("executed.\n"); | ||
125 | } | ||
126 | |||
127 | int me_slock_init(me_slock_t * slock) | ||
128 | { | ||
129 | PDEBUG_LOCKS("executed.\n"); | ||
130 | |||
131 | slock->filep = NULL; | ||
132 | slock->count = 0; | ||
133 | spin_lock_init(&slock->spin_lock); | ||
134 | |||
135 | return 0; | ||
136 | } | ||
diff --git a/drivers/staging/meilhaus/meslock.h b/drivers/staging/meilhaus/meslock.h new file mode 100644 index 000000000000..f42b25c3f622 --- /dev/null +++ b/drivers/staging/meilhaus/meslock.h | |||
@@ -0,0 +1,73 @@ | |||
1 | /** | ||
2 | * @file meslock.h | ||
3 | * | ||
4 | * @brief Provides the subdevice lock class. | ||
5 | * @note Copyright (C) 2006 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | #ifndef _MESLOCK_H_ | ||
10 | #define _MESLOCK_H_ | ||
11 | |||
12 | #include <linux/spinlock.h> | ||
13 | |||
14 | #ifdef __KERNEL__ | ||
15 | |||
16 | /** | ||
17 | * @brief The subdevice lock class. | ||
18 | */ | ||
19 | typedef struct me_slock { | ||
20 | struct file *filep; /**< Pointer to file structure holding the subdevice. */ | ||
21 | int count; /**< Number of tasks which are inside the subdevice. */ | ||
22 | spinlock_t spin_lock; /**< Spin lock protecting the attributes from concurrent access. */ | ||
23 | } me_slock_t; | ||
24 | |||
25 | /** | ||
26 | * @brief Tries to enter a subdevice. | ||
27 | * | ||
28 | * @param slock The subdevice lock instance. | ||
29 | * @param filep The file structure identifying the calling process. | ||
30 | * | ||
31 | * @return 0 on success. | ||
32 | */ | ||
33 | int me_slock_enter(struct me_slock *slock, struct file *filep); | ||
34 | |||
35 | /** | ||
36 | * @brief Exits a subdevice. | ||
37 | * | ||
38 | * @param slock The subdevice lock instance. | ||
39 | * @param filep The file structure identifying the calling process. | ||
40 | * | ||
41 | * @return 0 on success. | ||
42 | */ | ||
43 | int me_slock_exit(struct me_slock *slock, struct file *filep); | ||
44 | |||
45 | /** | ||
46 | * @brief Tries to perform a locking action on a subdevice. | ||
47 | * | ||
48 | * @param slock The subdevice lock instance. | ||
49 | * @param filep The file structure identifying the calling process. | ||
50 | * @param The action to be done. | ||
51 | * | ||
52 | * @return 0 on success. | ||
53 | */ | ||
54 | int me_slock_lock(struct me_slock *slock, struct file *filep, int lock); | ||
55 | |||
56 | /** | ||
57 | * @brief Initializes a lock structure. | ||
58 | * | ||
59 | * @param slock The lock structure to initialize. | ||
60 | * @return 0 on success. | ||
61 | */ | ||
62 | int me_slock_init(me_slock_t * slock); | ||
63 | |||
64 | /** | ||
65 | * @brief Deinitializes a lock structure. | ||
66 | * | ||
67 | * @param slock The lock structure to deinitialize. | ||
68 | * @return 0 on success. | ||
69 | */ | ||
70 | void me_slock_deinit(me_slock_t * slock); | ||
71 | |||
72 | #endif | ||
73 | #endif | ||
diff --git a/drivers/staging/meilhaus/mesubdevice.c b/drivers/staging/meilhaus/mesubdevice.c new file mode 100644 index 000000000000..98d4f1f7a824 --- /dev/null +++ b/drivers/staging/meilhaus/mesubdevice.c | |||
@@ -0,0 +1,317 @@ | |||
1 | /** | ||
2 | * @file mesubdevice.c | ||
3 | * | ||
4 | * @brief Subdevice base class implemention. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * This file is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | */ | ||
24 | |||
25 | #ifndef __KERNEL__ | ||
26 | # define __KERNEL__ | ||
27 | #endif | ||
28 | |||
29 | #include <linux/slab.h> | ||
30 | |||
31 | #include "medefines.h" | ||
32 | #include "meerror.h" | ||
33 | |||
34 | #include "medebug.h" | ||
35 | #include "mesubdevice.h" | ||
36 | |||
37 | static int me_subdevice_io_irq_start(struct me_subdevice *subdevice, | ||
38 | struct file *filep, | ||
39 | int channel, | ||
40 | int irq_source, | ||
41 | int irq_edge, int irq_arg, int flags) | ||
42 | { | ||
43 | PDEBUG("executed.\n"); | ||
44 | return ME_ERRNO_NOT_SUPPORTED; | ||
45 | } | ||
46 | |||
47 | static int me_subdevice_io_irq_wait(struct me_subdevice *subdevice, | ||
48 | struct file *filep, | ||
49 | int channel, | ||
50 | int *irq_count, | ||
51 | int *value, int time_out, int flags) | ||
52 | { | ||
53 | PDEBUG("executed.\n"); | ||
54 | return ME_ERRNO_NOT_SUPPORTED; | ||
55 | } | ||
56 | |||
57 | static int me_subdevice_io_irq_stop(struct me_subdevice *subdevice, | ||
58 | struct file *filep, int channel, int flags) | ||
59 | { | ||
60 | PDEBUG("executed.\n"); | ||
61 | return ME_ERRNO_NOT_SUPPORTED; | ||
62 | } | ||
63 | |||
64 | static int me_subdevice_io_reset_subdevice(struct me_subdevice *subdevice, | ||
65 | struct file *filep, int flags) | ||
66 | { | ||
67 | PDEBUG("executed.\n"); | ||
68 | return ME_ERRNO_NOT_SUPPORTED; | ||
69 | } | ||
70 | |||
71 | static int me_subdevice_io_single_config(struct me_subdevice *subdevice, | ||
72 | struct file *filep, | ||
73 | int channel, | ||
74 | int single_config, | ||
75 | int ref, | ||
76 | int trig_chan, | ||
77 | int trig_type, | ||
78 | int trig_edge, int flags) | ||
79 | { | ||
80 | PDEBUG("executed.\n"); | ||
81 | return ME_ERRNO_NOT_SUPPORTED; | ||
82 | } | ||
83 | |||
84 | static int me_subdevice_io_single_read(struct me_subdevice *subdevice, | ||
85 | struct file *filep, | ||
86 | int channel, | ||
87 | int *value, int time_out, int flags) | ||
88 | { | ||
89 | PDEBUG("executed.\n"); | ||
90 | return ME_ERRNO_NOT_SUPPORTED; | ||
91 | } | ||
92 | |||
93 | static int me_subdevice_io_single_write(struct me_subdevice *subdevice, | ||
94 | struct file *filep, | ||
95 | int channel, | ||
96 | int value, int time_out, int flags) | ||
97 | { | ||
98 | PDEBUG("executed.\n"); | ||
99 | return ME_ERRNO_NOT_SUPPORTED; | ||
100 | } | ||
101 | |||
102 | static int me_subdevice_io_stream_config(struct me_subdevice *subdevice, | ||
103 | struct file *filep, | ||
104 | meIOStreamConfig_t * config_list, | ||
105 | int count, | ||
106 | meIOStreamTrigger_t * trigger, | ||
107 | int fifo_irq_threshold, int flags) | ||
108 | { | ||
109 | PDEBUG("executed.\n"); | ||
110 | return ME_ERRNO_NOT_SUPPORTED; | ||
111 | } | ||
112 | |||
113 | static int me_subdevice_io_stream_new_values(struct me_subdevice *subdevice, | ||
114 | struct file *filep, | ||
115 | int time_out, | ||
116 | int *count, int flags) | ||
117 | { | ||
118 | PDEBUG("executed.\n"); | ||
119 | return ME_ERRNO_NOT_SUPPORTED; | ||
120 | } | ||
121 | |||
122 | static int me_subdevice_io_stream_read(struct me_subdevice *subdevice, | ||
123 | struct file *filep, | ||
124 | int read_mode, | ||
125 | int *values, int *count, int flags) | ||
126 | { | ||
127 | PDEBUG("executed.\n"); | ||
128 | return ME_ERRNO_NOT_SUPPORTED; | ||
129 | } | ||
130 | |||
131 | static int me_subdevice_io_stream_start(struct me_subdevice *subdevice, | ||
132 | struct file *filep, | ||
133 | int start_mode, int time_out, int flags) | ||
134 | { | ||
135 | PDEBUG("executed.\n"); | ||
136 | return ME_ERRNO_NOT_SUPPORTED; | ||
137 | } | ||
138 | |||
139 | static int me_subdevice_io_stream_status(struct me_subdevice *subdevice, | ||
140 | struct file *filep, | ||
141 | int wait, | ||
142 | int *status, int *count, int flags) | ||
143 | { | ||
144 | PDEBUG("executed.\n"); | ||
145 | return ME_ERRNO_NOT_SUPPORTED; | ||
146 | } | ||
147 | |||
148 | static int me_subdevice_io_stream_stop(struct me_subdevice *subdevice, | ||
149 | struct file *filep, | ||
150 | int stop_mode, int flags) | ||
151 | { | ||
152 | PDEBUG("executed.\n"); | ||
153 | return ME_ERRNO_NOT_SUPPORTED; | ||
154 | } | ||
155 | |||
156 | static int me_subdevice_io_stream_write(struct me_subdevice *subdevice, | ||
157 | struct file *filep, | ||
158 | int write_mode, | ||
159 | int *values, int *count, int flags) | ||
160 | { | ||
161 | PDEBUG("executed.\n"); | ||
162 | return ME_ERRNO_NOT_SUPPORTED; | ||
163 | } | ||
164 | |||
165 | static int me_subdevice_lock_subdevice(me_subdevice_t * subdevice, | ||
166 | struct file *filep, int lock, int flags) | ||
167 | { | ||
168 | PDEBUG("executed.\n"); | ||
169 | return me_slock_lock(&subdevice->lock, filep, lock); | ||
170 | } | ||
171 | |||
172 | static int me_subdevice_query_number_channels(struct me_subdevice *subdevice, | ||
173 | int *number) | ||
174 | { | ||
175 | PDEBUG("executed.\n"); | ||
176 | return ME_ERRNO_NOT_SUPPORTED; | ||
177 | } | ||
178 | |||
179 | static int me_subdevice_query_number_ranges(struct me_subdevice *subdevice, | ||
180 | int unit, int *count) | ||
181 | { | ||
182 | PDEBUG("executed.\n"); | ||
183 | return ME_ERRNO_NOT_SUPPORTED; | ||
184 | } | ||
185 | |||
186 | static int me_subdevice_query_range_by_min_max(struct me_subdevice *subdevice, | ||
187 | int unit, | ||
188 | int *min, | ||
189 | int *max, | ||
190 | int *maxdata, int *range) | ||
191 | { | ||
192 | PDEBUG("executed.\n"); | ||
193 | return ME_ERRNO_NOT_SUPPORTED; | ||
194 | } | ||
195 | |||
196 | static int me_subdevice_query_range_info(struct me_subdevice *subdevice, | ||
197 | int range, | ||
198 | int *unit, | ||
199 | int *min, int *max, int *maxdata) | ||
200 | { | ||
201 | PDEBUG("executed.\n"); | ||
202 | return ME_ERRNO_NOT_SUPPORTED; | ||
203 | } | ||
204 | |||
205 | static int me_subdevice_query_subdevice_type(struct me_subdevice *subdevice, | ||
206 | int *type, int *subtype) | ||
207 | { | ||
208 | PDEBUG("executed.\n"); | ||
209 | return ME_ERRNO_NOT_SUPPORTED; | ||
210 | } | ||
211 | |||
212 | static int me_subdevice_query_subdevice_caps(struct me_subdevice *subdevice, | ||
213 | int *caps) | ||
214 | { | ||
215 | PDEBUG("executed.\n"); | ||
216 | *caps = 0; | ||
217 | return ME_ERRNO_SUCCESS; | ||
218 | } | ||
219 | |||
220 | static int me_subdevice_query_subdevice_caps_args(struct me_subdevice | ||
221 | *subdevice, int cap, | ||
222 | int *args, int count) | ||
223 | { | ||
224 | PDEBUG("executed.\n"); | ||
225 | return ME_ERRNO_NOT_SUPPORTED; | ||
226 | } | ||
227 | |||
228 | static int me_subdevice_query_timer(struct me_subdevice *subdevice, | ||
229 | int timer, | ||
230 | int *base_frequency, | ||
231 | long long *min_ticks, long long *max_ticks) | ||
232 | { | ||
233 | PDEBUG("executed.\n"); | ||
234 | return ME_ERRNO_NOT_SUPPORTED; | ||
235 | } | ||
236 | |||
237 | static int me_subdevice_config_load(struct me_subdevice *subdevice, | ||
238 | me_cfg_device_entry_t * config) | ||
239 | { | ||
240 | PDEBUG("executed.\n"); | ||
241 | return ME_ERRNO_SUCCESS; | ||
242 | } | ||
243 | |||
244 | static void me_subdevice_destructor(struct me_subdevice *subdevice) | ||
245 | { | ||
246 | PDEBUG("executed.\n"); | ||
247 | me_subdevice_deinit(subdevice); | ||
248 | kfree(subdevice); | ||
249 | } | ||
250 | |||
251 | int me_subdevice_init(me_subdevice_t * subdevice) | ||
252 | { | ||
253 | int err; | ||
254 | |||
255 | PDEBUG("executed.\n"); | ||
256 | |||
257 | /* Init list head */ | ||
258 | INIT_LIST_HEAD(&subdevice->list); | ||
259 | |||
260 | /* Initialize the subdevice lock instance */ | ||
261 | |||
262 | err = me_slock_init(&subdevice->lock); | ||
263 | |||
264 | if (err) { | ||
265 | PERROR("Cannot initialize subdevice lock instance.\n"); | ||
266 | return 1; | ||
267 | } | ||
268 | |||
269 | /* Subdevice base class methods */ | ||
270 | subdevice->me_subdevice_io_irq_start = me_subdevice_io_irq_start; | ||
271 | subdevice->me_subdevice_io_irq_wait = me_subdevice_io_irq_wait; | ||
272 | subdevice->me_subdevice_io_irq_stop = me_subdevice_io_irq_stop; | ||
273 | subdevice->me_subdevice_io_reset_subdevice = | ||
274 | me_subdevice_io_reset_subdevice; | ||
275 | subdevice->me_subdevice_io_single_config = | ||
276 | me_subdevice_io_single_config; | ||
277 | subdevice->me_subdevice_io_single_read = me_subdevice_io_single_read; | ||
278 | subdevice->me_subdevice_io_single_write = me_subdevice_io_single_write; | ||
279 | subdevice->me_subdevice_io_stream_config = | ||
280 | me_subdevice_io_stream_config; | ||
281 | subdevice->me_subdevice_io_stream_new_values = | ||
282 | me_subdevice_io_stream_new_values; | ||
283 | subdevice->me_subdevice_io_stream_read = me_subdevice_io_stream_read; | ||
284 | subdevice->me_subdevice_io_stream_start = me_subdevice_io_stream_start; | ||
285 | subdevice->me_subdevice_io_stream_status = | ||
286 | me_subdevice_io_stream_status; | ||
287 | subdevice->me_subdevice_io_stream_stop = me_subdevice_io_stream_stop; | ||
288 | subdevice->me_subdevice_io_stream_write = me_subdevice_io_stream_write; | ||
289 | subdevice->me_subdevice_lock_subdevice = me_subdevice_lock_subdevice; | ||
290 | subdevice->me_subdevice_query_number_channels = | ||
291 | me_subdevice_query_number_channels; | ||
292 | subdevice->me_subdevice_query_number_ranges = | ||
293 | me_subdevice_query_number_ranges; | ||
294 | subdevice->me_subdevice_query_range_by_min_max = | ||
295 | me_subdevice_query_range_by_min_max; | ||
296 | subdevice->me_subdevice_query_range_info = | ||
297 | me_subdevice_query_range_info; | ||
298 | subdevice->me_subdevice_query_subdevice_type = | ||
299 | me_subdevice_query_subdevice_type; | ||
300 | subdevice->me_subdevice_query_subdevice_caps = | ||
301 | me_subdevice_query_subdevice_caps; | ||
302 | subdevice->me_subdevice_query_subdevice_caps_args = | ||
303 | me_subdevice_query_subdevice_caps_args; | ||
304 | subdevice->me_subdevice_query_timer = me_subdevice_query_timer; | ||
305 | subdevice->me_subdevice_config_load = me_subdevice_config_load; | ||
306 | subdevice->me_subdevice_destructor = me_subdevice_destructor; | ||
307 | |||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | void me_subdevice_deinit(me_subdevice_t * subdevice) | ||
312 | { | ||
313 | PDEBUG("executed.\n"); | ||
314 | me_subdevice_io_reset_subdevice(subdevice, NULL, | ||
315 | ME_IO_RESET_SUBDEVICE_NO_FLAGS); | ||
316 | me_slock_deinit(&subdevice->lock); | ||
317 | } | ||
diff --git a/drivers/staging/meilhaus/mesubdevice.h b/drivers/staging/meilhaus/mesubdevice.h new file mode 100644 index 000000000000..19ec2b5d96f0 --- /dev/null +++ b/drivers/staging/meilhaus/mesubdevice.h | |||
@@ -0,0 +1,197 @@ | |||
1 | /** | ||
2 | * @file mesubdevice.h | ||
3 | * | ||
4 | * @brief Provides the subdevice base class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | #ifndef _MESUBDEVICE_H_ | ||
10 | #define _MESUBDEVICE_H_ | ||
11 | |||
12 | #include <linux/list.h> | ||
13 | |||
14 | #include "metypes.h" | ||
15 | #include "meioctl.h" | ||
16 | #include "meslock.h" | ||
17 | |||
18 | # include <linux/workqueue.h> | ||
19 | |||
20 | #ifdef __KERNEL__ | ||
21 | |||
22 | /** | ||
23 | * @brief Macro used to enter a subdevice. | ||
24 | */ | ||
25 | #define ME_SUBDEVICE_ENTER \ | ||
26 | { \ | ||
27 | int err; \ | ||
28 | err = me_slock_enter(&instance->base.lock, filep); \ | ||
29 | if(err){ \ | ||
30 | PERROR("Cannot enter subdevice.\n"); \ | ||
31 | return err; \ | ||
32 | } \ | ||
33 | } | ||
34 | |||
35 | /** | ||
36 | * @brief Macro used to exit a subdevice. | ||
37 | */ | ||
38 | #define ME_SUBDEVICE_EXIT \ | ||
39 | {\ | ||
40 | int err; \ | ||
41 | err = me_slock_exit(&instance->base.lock, filep); \ | ||
42 | if(err){ \ | ||
43 | PERROR("Cannot exit subdevice.\n"); \ | ||
44 | return err; \ | ||
45 | } \ | ||
46 | } | ||
47 | |||
48 | /** | ||
49 | * @brief The subdevice base class. | ||
50 | */ | ||
51 | typedef struct me_subdevice { | ||
52 | /* Attributes */ | ||
53 | struct list_head list; /**< Enables the subdevice to be added to a dynamic list. */ | ||
54 | me_slock_t lock; /**< Used by user application in order to lock the subdevice for exclusive usage. */ | ||
55 | |||
56 | /* Methods */ | ||
57 | int (*me_subdevice_io_irq_start) (struct me_subdevice * subdevice, | ||
58 | struct file * filep, | ||
59 | int channel, | ||
60 | int irq_source, | ||
61 | int irq_edge, int irq_arg, int flags); | ||
62 | |||
63 | int (*me_subdevice_io_irq_wait) (struct me_subdevice * subdevice, | ||
64 | struct file * filep, | ||
65 | int channel, | ||
66 | int *irq_count, | ||
67 | int *value, int time_out, int flags); | ||
68 | |||
69 | int (*me_subdevice_io_irq_stop) (struct me_subdevice * subdevice, | ||
70 | struct file * filep, | ||
71 | int channel, int flags); | ||
72 | |||
73 | int (*me_subdevice_io_reset_subdevice) (struct me_subdevice * subdevice, | ||
74 | struct file * filep, int flags); | ||
75 | |||
76 | int (*me_subdevice_io_single_config) (struct me_subdevice * subdevice, | ||
77 | struct file * filep, | ||
78 | int channel, | ||
79 | int single_config, | ||
80 | int ref, | ||
81 | int trig_chan, | ||
82 | int trig_type, | ||
83 | int trig_edge, int flags); | ||
84 | |||
85 | int (*me_subdevice_io_single_read) (struct me_subdevice * subdevice, | ||
86 | struct file * filep, | ||
87 | int channel, | ||
88 | int *value, | ||
89 | int time_out, int flags); | ||
90 | |||
91 | int (*me_subdevice_io_single_write) (struct me_subdevice * subdevice, | ||
92 | struct file * filep, | ||
93 | int channel, | ||
94 | int value, | ||
95 | int time_out, int flags); | ||
96 | |||
97 | int (*me_subdevice_io_stream_config) (struct me_subdevice * subdevice, | ||
98 | struct file * filep, | ||
99 | meIOStreamConfig_t * config_list, | ||
100 | int count, | ||
101 | meIOStreamTrigger_t * trigger, | ||
102 | int fifo_irq_threshold, | ||
103 | int flags); | ||
104 | |||
105 | int (*me_subdevice_io_stream_new_values) (struct me_subdevice * | ||
106 | subdevice, | ||
107 | struct file * filep, | ||
108 | int time_out, int *count, | ||
109 | int flags); | ||
110 | |||
111 | int (*me_subdevice_io_stream_read) (struct me_subdevice * subdevice, | ||
112 | struct file * filep, | ||
113 | int read_mode, | ||
114 | int *values, int *count, int flags); | ||
115 | |||
116 | int (*me_subdevice_io_stream_start) (struct me_subdevice * subdevice, | ||
117 | struct file * filep, | ||
118 | int start_mode, | ||
119 | int time_out, int flags); | ||
120 | |||
121 | int (*me_subdevice_io_stream_status) (struct me_subdevice * subdevice, | ||
122 | struct file * filep, | ||
123 | int wait, | ||
124 | int *status, | ||
125 | int *count, int flags); | ||
126 | |||
127 | int (*me_subdevice_io_stream_stop) (struct me_subdevice * subdevice, | ||
128 | struct file * filep, | ||
129 | int stop_mode, int flags); | ||
130 | |||
131 | int (*me_subdevice_io_stream_write) (struct me_subdevice * subdevice, | ||
132 | struct file * filep, | ||
133 | int write_mode, | ||
134 | int *values, | ||
135 | int *count, int flags); | ||
136 | |||
137 | int (*me_subdevice_lock_subdevice) (struct me_subdevice * subdevice, | ||
138 | struct file * filep, | ||
139 | int lock, int flags); | ||
140 | |||
141 | int (*me_subdevice_query_number_channels) (struct me_subdevice * | ||
142 | subdevice, int *number); | ||
143 | |||
144 | int (*me_subdevice_query_number_ranges) (struct me_subdevice * | ||
145 | subdevice, int unit, | ||
146 | int *count); | ||
147 | |||
148 | int (*me_subdevice_query_range_by_min_max) (struct me_subdevice * | ||
149 | subdevice, int unit, | ||
150 | int *min, int *max, | ||
151 | int *maxdata, int *range); | ||
152 | |||
153 | int (*me_subdevice_query_range_info) (struct me_subdevice * subdevice, | ||
154 | int range, | ||
155 | int *unit, | ||
156 | int *min, int *max, int *maxdata); | ||
157 | |||
158 | int (*me_subdevice_query_subdevice_type) (struct me_subdevice * | ||
159 | subdevice, int *type, | ||
160 | int *subtype); | ||
161 | |||
162 | int (*me_subdevice_query_subdevice_caps) (struct me_subdevice * | ||
163 | subdevice, int *caps); | ||
164 | |||
165 | int (*me_subdevice_query_subdevice_caps_args) (struct me_subdevice * | ||
166 | subdevice, int cap, | ||
167 | int *args, int count); | ||
168 | |||
169 | int (*me_subdevice_query_timer) (struct me_subdevice * subdevice, | ||
170 | int timer, | ||
171 | int *base_frequency, | ||
172 | long long *min_ticks, | ||
173 | long long *max_ticks); | ||
174 | |||
175 | int (*me_subdevice_config_load) (struct me_subdevice * subdevice, | ||
176 | me_cfg_device_entry_t * config); | ||
177 | |||
178 | void (*me_subdevice_destructor) (struct me_subdevice * subdevice); | ||
179 | } me_subdevice_t; | ||
180 | |||
181 | /** | ||
182 | * @brief Initializes a subdevice structure. | ||
183 | * | ||
184 | * @param subdevice The subdevice structure to initialize. | ||
185 | * @return 0 on success. | ||
186 | */ | ||
187 | int me_subdevice_init(me_subdevice_t * subdevice); | ||
188 | |||
189 | /** | ||
190 | * @brief Deinitializes a subdevice structure. | ||
191 | * | ||
192 | * @param subdevice The subdevice structure to initialize. | ||
193 | */ | ||
194 | void me_subdevice_deinit(me_subdevice_t * subdevice); | ||
195 | |||
196 | #endif | ||
197 | #endif | ||
diff --git a/drivers/staging/meilhaus/metempl_device.c b/drivers/staging/meilhaus/metempl_device.c new file mode 100644 index 000000000000..e48632ddc1aa --- /dev/null +++ b/drivers/staging/meilhaus/metempl_device.c | |||
@@ -0,0 +1,137 @@ | |||
1 | /** | ||
2 | * @file metempl_device.c | ||
3 | * | ||
4 | * @brief template device class implementation. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef __KERNEL__ | ||
28 | # define __KERNEL__ | ||
29 | #endif | ||
30 | |||
31 | #ifndef MODULE | ||
32 | # define MODULE | ||
33 | #endif | ||
34 | |||
35 | #include <linux/module.h> | ||
36 | |||
37 | #include <linux/pci.h> | ||
38 | #include <linux/slab.h> | ||
39 | |||
40 | #include <meids.h> | ||
41 | #include "meerror.h" | ||
42 | #include "mecommon.h" | ||
43 | #include "meinternal.h" | ||
44 | |||
45 | #include "medebug.h" | ||
46 | #include "medevice.h" | ||
47 | #include "metempl_device.h" | ||
48 | #include "mesubdevice.h" | ||
49 | #include "metempl_sub.h" | ||
50 | |||
51 | me_device_t *metempl_pci_constructor(struct pci_dev *pci_device) | ||
52 | { | ||
53 | metempl_device_t *metempl_device; | ||
54 | me_subdevice_t *subdevice; | ||
55 | unsigned int version_idx; | ||
56 | int err; | ||
57 | int i; | ||
58 | |||
59 | PDEBUG("executed.\n"); | ||
60 | |||
61 | // Allocate structure for device instance. | ||
62 | metempl_device = kmalloc(sizeof(metempl_device_t), GFP_KERNEL); | ||
63 | |||
64 | if (!metempl_device) { | ||
65 | PERROR("Cannot get memory for device instance.\n"); | ||
66 | return NULL; | ||
67 | } | ||
68 | |||
69 | memset(metempl_device, 0, sizeof(metempl_device_t)); | ||
70 | |||
71 | // Initialize base class structure. | ||
72 | err = me_device_pci_init((me_device_t *) metempl_device, pci_device); | ||
73 | |||
74 | if (err) { | ||
75 | kfree(metempl_device); | ||
76 | PERROR("Cannot initialize device base class.\n"); | ||
77 | return NULL; | ||
78 | } | ||
79 | |||
80 | /* Get the index in the device version information table. */ | ||
81 | version_idx = | ||
82 | metempl_versions_get_device_index(metempl_device->base.info.pci. | ||
83 | device_id); | ||
84 | |||
85 | // Initialize spin lock . | ||
86 | spin_lock_init(&metempl_device->ctrl_reg_lock); | ||
87 | |||
88 | // Create subdevice instances. | ||
89 | for (i = 0; i < metempl_versions[version_idx].subdevices; i++) { | ||
90 | subdevice = | ||
91 | (me_subdevice_t *) metempl_sub_constructor(metempl_device-> | ||
92 | base.info.pci. | ||
93 | reg_bases[2], i, | ||
94 | &metempl_device-> | ||
95 | ctrl_reg_lock); | ||
96 | |||
97 | if (!subdevice) { | ||
98 | me_device_deinit((me_device_t *) metempl_device); | ||
99 | kfree(metempl_device); | ||
100 | PERROR("Cannot get memory for subdevice.\n"); | ||
101 | return NULL; | ||
102 | } | ||
103 | |||
104 | me_slist_add_subdevice_tail(&metempl_device->base.slist, | ||
105 | subdevice); | ||
106 | } | ||
107 | |||
108 | /* Overwrite base class methods if applicable. */ | ||
109 | |||
110 | return (me_device_t *) metempl_device; | ||
111 | } | ||
112 | |||
113 | // Init and exit of module. | ||
114 | |||
115 | static int __init metempl_init(void) | ||
116 | { | ||
117 | PDEBUG("executed.\n."); | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | static void __exit metempl_exit(void) | ||
122 | { | ||
123 | PDEBUG("executed.\n."); | ||
124 | } | ||
125 | |||
126 | module_init(metempl_init); | ||
127 | |||
128 | module_exit(metempl_exit); | ||
129 | |||
130 | // Administrative stuff for modinfo. | ||
131 | MODULE_AUTHOR("Guenter Gebhardt <g.gebhardt@meilhaus.de>"); | ||
132 | MODULE_DESCRIPTION("Device Driver Module for Template Device"); | ||
133 | MODULE_SUPPORTED_DEVICE("Meilhaus Template Devices"); | ||
134 | MODULE_LICENSE("GPL"); | ||
135 | |||
136 | // Export the constructor. | ||
137 | EXPORT_SYMBOL(metempl_pci_constructor); | ||
diff --git a/drivers/staging/meilhaus/metempl_device.h b/drivers/staging/meilhaus/metempl_device.h new file mode 100644 index 000000000000..3c3702cc72eb --- /dev/null +++ b/drivers/staging/meilhaus/metempl_device.h | |||
@@ -0,0 +1,92 @@ | |||
1 | /** | ||
2 | * @file metempl_device.h | ||
3 | * | ||
4 | * @brief template device class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _METEMPL_DEVICE_H | ||
28 | #define _METEMPL_DEVICE_H | ||
29 | |||
30 | #include <linux/pci.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | |||
33 | #include "medevice.h" | ||
34 | |||
35 | #ifdef __KERNEL__ | ||
36 | |||
37 | /** | ||
38 | * @brief Structure holding template device capabilities. | ||
39 | */ | ||
40 | typedef struct metempl_version { | ||
41 | uint16_t device_id; | ||
42 | unsigned int subdevices; | ||
43 | } metempl_version_t; | ||
44 | |||
45 | /** | ||
46 | * @brief Device capabilities. | ||
47 | */ | ||
48 | static metempl_version_t metempl_versions[] = { | ||
49 | {0xDEAD, 1}, | ||
50 | {0}, | ||
51 | }; | ||
52 | |||
53 | #define METEMPL_DEVICE_VERSIONS (sizeof(metempl_versions) / sizeof(metempl_version_t) - 1) /**< Returns the number of entries in #metempl_versions. */ | ||
54 | |||
55 | /** | ||
56 | * @brief Returns the index of the device entry in #metempl_versions. | ||
57 | * | ||
58 | * @param device_id The PCI device id of the device to query. | ||
59 | * @return The index of the device in #metempl_versions. | ||
60 | */ | ||
61 | static inline unsigned int metempl_versions_get_device_index(uint16_t device_id) | ||
62 | { | ||
63 | unsigned int i; | ||
64 | for (i = 0; i < METEMPL_DEVICE_VERSIONS; i++) | ||
65 | if (metempl_versions[i].device_id == device_id) | ||
66 | break; | ||
67 | return i; | ||
68 | } | ||
69 | |||
70 | /** | ||
71 | * @brief The template device class structure. | ||
72 | */ | ||
73 | typedef struct metempl_device { | ||
74 | me_device_t base; /**< The Meilhaus device base class. */ | ||
75 | |||
76 | /* Child class attributes. */ | ||
77 | spinlock_t ctrl_reg_lock; | ||
78 | } metempl_device_t; | ||
79 | |||
80 | /** | ||
81 | * @brief The template device class constructor. | ||
82 | * | ||
83 | * @param pci_device The pci device structure given by the PCI subsystem. | ||
84 | * | ||
85 | * @return On succes a new template device instance. \n | ||
86 | * NULL on error. | ||
87 | */ | ||
88 | me_device_t *metempl_pci_constructor(struct pci_dev *pci_device) | ||
89 | __attribute__ ((weak)); | ||
90 | |||
91 | #endif | ||
92 | #endif | ||
diff --git a/drivers/staging/meilhaus/metempl_sub.c b/drivers/staging/meilhaus/metempl_sub.c new file mode 100644 index 000000000000..f1d65d889e23 --- /dev/null +++ b/drivers/staging/meilhaus/metempl_sub.c | |||
@@ -0,0 +1,149 @@ | |||
1 | /** | ||
2 | * @file metempl_sub.c | ||
3 | * | ||
4 | * @brief Subdevice instance. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef __KERNEL__ | ||
28 | # define __KERNEL__ | ||
29 | #endif | ||
30 | |||
31 | /* | ||
32 | * Includes | ||
33 | */ | ||
34 | #include <linux/module.h> | ||
35 | |||
36 | #include <linux/slab.h> | ||
37 | #include <linux/spinlock.h> | ||
38 | #include <asm/io.h> | ||
39 | #include <linux/types.h> | ||
40 | |||
41 | #include "medefines.h" | ||
42 | #include "meinternal.h" | ||
43 | #include "meerror.h" | ||
44 | |||
45 | #include "medebug.h" | ||
46 | #include "metempl_sub_reg.h" | ||
47 | #include "metempl_sub.h" | ||
48 | |||
49 | /* | ||
50 | * Defines | ||
51 | */ | ||
52 | |||
53 | /* | ||
54 | * Functions | ||
55 | */ | ||
56 | |||
57 | static void metempl_sub_destructor(struct me_subdevice *subdevice) | ||
58 | { | ||
59 | metempl_sub_subdevice_t *instance; | ||
60 | |||
61 | PDEBUG("executed.\n"); | ||
62 | instance = (metempl_sub_subdevice_t *) subdevice; | ||
63 | |||
64 | /* Until there this was the things the default constructor does. | ||
65 | If you do not have any additional things to do you can wipe it out. */ | ||
66 | |||
67 | me_subdevice_deinit(&instance->base); | ||
68 | kfree(instance); | ||
69 | } | ||
70 | |||
71 | static int metempl_sub_query_number_channels(me_subdevice_t * subdevice, | ||
72 | int *number) | ||
73 | { | ||
74 | PDEBUG("executed.\n"); | ||
75 | *number = 0; | ||
76 | return ME_ERRNO_SUCCESS; | ||
77 | } | ||
78 | |||
79 | static int metempl_sub_query_subdevice_type(me_subdevice_t * subdevice, | ||
80 | int *type, int *subtype) | ||
81 | { | ||
82 | PDEBUG("executed.\n"); | ||
83 | *type = 0; | ||
84 | *subtype = 0; | ||
85 | return ME_ERRNO_SUCCESS; | ||
86 | } | ||
87 | |||
88 | static int metempl_sub_query_subdevice_caps(me_subdevice_t * subdevice, | ||
89 | int *caps) | ||
90 | { | ||
91 | PDEBUG("executed.\n"); | ||
92 | *caps = 0; | ||
93 | return ME_ERRNO_SUCCESS; | ||
94 | } | ||
95 | |||
96 | metempl_sub_subdevice_t *metempl_sub_constructor(uint32_t reg_base, | ||
97 | unsigned int sub_idx, | ||
98 | spinlock_t * ctrl_reg_lock) | ||
99 | { | ||
100 | metempl_sub_subdevice_t *subdevice; | ||
101 | int err; | ||
102 | |||
103 | PDEBUG("executed.\n"); | ||
104 | |||
105 | /* Allocate memory for subdevice instance */ | ||
106 | subdevice = kmalloc(sizeof(metempl_sub_subdevice_t), GFP_KERNEL); | ||
107 | |||
108 | if (!subdevice) { | ||
109 | PERROR("Cannot get memory for subdevice instance.\n"); | ||
110 | return NULL; | ||
111 | } | ||
112 | |||
113 | memset(subdevice, 0, sizeof(metempl_sub_subdevice_t)); | ||
114 | |||
115 | /* Check if subdevice index is out of range */ | ||
116 | |||
117 | if (sub_idx >= 2) { | ||
118 | PERROR("Template subdevice index is out of range.\n"); | ||
119 | kfree(subdevice); | ||
120 | return NULL; | ||
121 | } | ||
122 | |||
123 | /* Initialize subdevice base class */ | ||
124 | err = me_subdevice_init(&subdevice->base); | ||
125 | |||
126 | if (err) { | ||
127 | PERROR("Cannot initialize subdevice base class instance.\n"); | ||
128 | kfree(subdevice); | ||
129 | return NULL; | ||
130 | } | ||
131 | // Initialize spin locks. | ||
132 | spin_lock_init(&subdevice->subdevice_lock); | ||
133 | |||
134 | subdevice->ctrl_reg_lock = ctrl_reg_lock; | ||
135 | |||
136 | /* Save the subdevice index */ | ||
137 | subdevice->sub_idx = sub_idx; | ||
138 | |||
139 | /* Override base class methods. */ | ||
140 | subdevice->base.me_subdevice_destructor = metempl_sub_destructor; | ||
141 | subdevice->base.me_subdevice_query_number_channels = | ||
142 | metempl_sub_query_number_channels; | ||
143 | subdevice->base.me_subdevice_query_subdevice_type = | ||
144 | metempl_sub_query_subdevice_type; | ||
145 | subdevice->base.me_subdevice_query_subdevice_caps = | ||
146 | metempl_sub_query_subdevice_caps; | ||
147 | |||
148 | return subdevice; | ||
149 | } | ||
diff --git a/drivers/staging/meilhaus/metempl_sub.h b/drivers/staging/meilhaus/metempl_sub.h new file mode 100644 index 000000000000..80c8af9a8c5a --- /dev/null +++ b/drivers/staging/meilhaus/metempl_sub.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /** | ||
2 | * @file metempl_sub.h | ||
3 | * | ||
4 | * @brief Meilhaus subdevice class. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _METEMPL_SUB_H_ | ||
28 | #define _METEMPL_SUB_H_ | ||
29 | |||
30 | #include "mesubdevice.h" | ||
31 | |||
32 | #ifdef __KERNEL__ | ||
33 | |||
34 | /** | ||
35 | * @brief The subdevice class. | ||
36 | */ | ||
37 | typedef struct metempl_sub_subdevice { | ||
38 | /* Inheritance */ | ||
39 | me_subdevice_t base; /**< The subdevice base class. */ | ||
40 | |||
41 | /* Attributes */ | ||
42 | spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */ | ||
43 | spinlock_t *ctrl_reg_lock; /**< Spin lock to protect #ctrl_reg from concurrent access. */ | ||
44 | int sub_idx; /**< The index of the subdevice on the device. */ | ||
45 | |||
46 | unsigned long ctrl_reg; /**< Register to configure the modes. */ | ||
47 | } metempl_sub_subdevice_t; | ||
48 | |||
49 | /** | ||
50 | * @brief The constructor to generate a subdevice instance. | ||
51 | * | ||
52 | * @param reg_base The register base address of the device as returned by the PCI BIOS. | ||
53 | * @param sub_idx The index of the subdevice on the device. | ||
54 | * @param ctrl_reg_lock Pointer to spin lock protecting the control register from concurrent access. | ||
55 | * | ||
56 | * @return Pointer to new instance on success.\n | ||
57 | * NULL on error. | ||
58 | */ | ||
59 | metempl_sub_subdevice_t *metempl_sub_constructor(uint32_t reg_base, | ||
60 | unsigned int sub_idx, | ||
61 | spinlock_t * ctrl_reg_lock); | ||
62 | |||
63 | #endif | ||
64 | #endif | ||
diff --git a/drivers/staging/meilhaus/metempl_sub_reg.h b/drivers/staging/meilhaus/metempl_sub_reg.h new file mode 100644 index 000000000000..1a2cab778a12 --- /dev/null +++ b/drivers/staging/meilhaus/metempl_sub_reg.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /** | ||
2 | * @file metempl_sub_reg.h | ||
3 | * | ||
4 | * @brief Subdevice register definitions. | ||
5 | * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
6 | * @author Guenter Gebhardt | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
11 | * | ||
12 | * This file is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef _METEMPL_SUB_REG_H_ | ||
28 | #define _METEMPL_SUB_REG_H_ | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | #define METEMPL_PORT_MODE 0x0010 /**< Configuration register. */ | ||
33 | |||
34 | #endif | ||
35 | #endif | ||
diff --git a/drivers/staging/meilhaus/metypes.h b/drivers/staging/meilhaus/metypes.h new file mode 100644 index 000000000000..228ea15753ea --- /dev/null +++ b/drivers/staging/meilhaus/metypes.h | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 Meilhaus Electronic GmbH (support@meilhaus.de) | ||
3 | * | ||
4 | * Source File : metypes.h | ||
5 | * Author : GG (Guenter Gebhardt) <g.gebhardt@meilhaus.de> | ||
6 | */ | ||
7 | |||
8 | #ifndef _METYPES_H_ | ||
9 | #define _METYPES_H_ | ||
10 | |||
11 | |||
12 | typedef int (*meErrorCB_t)(char *pcFunctionName, int iErrorCode); | ||
13 | |||
14 | typedef int (*meIOStreamCB_t)( | ||
15 | int iDevice, | ||
16 | int iSubdevice, | ||
17 | int iCount, | ||
18 | void *pvContext, | ||
19 | int iErrorCode); | ||
20 | |||
21 | typedef int (*meIOIrqCB_t)( | ||
22 | int iDevice, | ||
23 | int iSubdevice, | ||
24 | int iChannel, | ||
25 | int iIrqCount, | ||
26 | int iValue, | ||
27 | void *pvContext, | ||
28 | int iErrorCode); | ||
29 | |||
30 | |||
31 | typedef struct meIOSingle { | ||
32 | int iDevice; | ||
33 | int iSubdevice; | ||
34 | int iChannel; | ||
35 | int iDir; | ||
36 | int iValue; | ||
37 | int iTimeOut; | ||
38 | int iFlags; | ||
39 | int iErrno; | ||
40 | } meIOSingle_t; | ||
41 | |||
42 | |||
43 | typedef struct meIOStreamConfig { | ||
44 | int iChannel; | ||
45 | int iStreamConfig; | ||
46 | int iRef; | ||
47 | int iFlags; | ||
48 | } meIOStreamConfig_t; | ||
49 | |||
50 | |||
51 | typedef struct meIOStreamTrigger { | ||
52 | int iAcqStartTrigType; | ||
53 | int iAcqStartTrigEdge; | ||
54 | int iAcqStartTrigChan; | ||
55 | int iAcqStartTicksLow; | ||
56 | int iAcqStartTicksHigh; | ||
57 | int iAcqStartArgs[10]; | ||
58 | int iScanStartTrigType; | ||
59 | int iScanStartTicksLow; | ||
60 | int iScanStartTicksHigh; | ||
61 | int iScanStartArgs[10]; | ||
62 | int iConvStartTrigType; | ||
63 | int iConvStartTicksLow; | ||
64 | int iConvStartTicksHigh; | ||
65 | int iConvStartArgs[10]; | ||
66 | int iScanStopTrigType; | ||
67 | int iScanStopCount; | ||
68 | int iScanStopArgs[10]; | ||
69 | int iAcqStopTrigType; | ||
70 | int iAcqStopCount; | ||
71 | int iAcqStopArgs[10]; | ||
72 | int iFlags; | ||
73 | } meIOStreamTrigger_t; | ||
74 | |||
75 | |||
76 | typedef struct meIOStreamStart { | ||
77 | int iDevice; | ||
78 | int iSubdevice; | ||
79 | int iStartMode; | ||
80 | int iTimeOut; | ||
81 | int iFlags; | ||
82 | int iErrno; | ||
83 | } meIOStreamStart_t; | ||
84 | |||
85 | |||
86 | typedef struct meIOStreamStop { | ||
87 | int iDevice; | ||
88 | int iSubdevice; | ||
89 | int iStopMode; | ||
90 | int iFlags; | ||
91 | int iErrno; | ||
92 | } meIOStreamStop_t; | ||
93 | |||
94 | |||
95 | #endif | ||