Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux...
[linux-2.6] / drivers / staging / meilhaus / me0600_relay.c
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 }