• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
get_mode_from_mirror(uint32_t mirror)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 
me8255_io_reset_subdevice(struct me_subdevice * subdevice,struct file * filep,int flags)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 
me8255_io_single_config(struct me_subdevice * subdevice,struct file * filep,int channel,int single_config,int ref,int trig_chan,int trig_type,int trig_edge,int flags)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 
me8255_io_single_read(struct me_subdevice * subdevice,struct file * filep,int channel,int * value,int time_out,int flags)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 
me8255_io_single_write(struct me_subdevice * subdevice,struct file * filep,int channel,int value,int time_out,int flags)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 
me8255_query_number_channels(struct me_subdevice * subdevice,int * number)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 
me8255_query_subdevice_type(struct me_subdevice * subdevice,int * type,int * subtype)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 
me8255_query_subdevice_caps(struct me_subdevice * subdevice,int * caps)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 
me8255_constructor(uint32_t device_id,uint32_t reg_base,unsigned int me8255_idx,unsigned int dio_idx,int * ctrl_reg_mirror,spinlock_t * ctrl_reg_lock)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 }
463