blob: 180e7f8d21467f9f5ead556b496ec4facc8456ec [file] [log] [blame]
David Kiliani3fedd142008-11-01 00:39:12 +01001/**
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
57static 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
92static 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
124static 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
177static 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
223static 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
291static 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
299static 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
308static 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
316me8255_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}