Commit 3fedd148 authored by David Kiliani's avatar David Kiliani Committed by Greg Kroah-Hartman

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: default avatarDavid Kiliani <mail@davidkiliani.de>
Cc: Guenter Gebhardt <g.gebhardt@meilhaus.de>
Cc: Krzysztof Gantzke <k.gantzke@meilhaus.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 5ec5ec78
......@@ -49,6 +49,8 @@ source "drivers/staging/sxg/Kconfig"
source "drivers/staging/me4000/Kconfig"
source "drivers/staging/meilhaus/Kconfig"
source "drivers/staging/go7007/Kconfig"
source "drivers/staging/usbip/Kconfig"
......
......@@ -7,6 +7,7 @@ obj-$(CONFIG_ET131X) += et131x/
obj-$(CONFIG_SLICOSS) += slicoss/
obj-$(CONFIG_SXG) += sxg/
obj-$(CONFIG_ME4000) += me4000/
obj-$(CONFIG_MEILHAUS) += meilhaus/
obj-$(CONFIG_VIDEO_GO7007) += go7007/
obj-$(CONFIG_USB_IP_COMMON) += usbip/
obj-$(CONFIG_W35UND) += winbond/
......
#
# Meilhaus configuration
#
menuconfig MEILHAUS
tristate "Meilhaus support"
---help---
If you have a Meilhaus card, say Y (or M) here.
You need both this driver, and the driver for the particular
data collection card.
To compile this driver as a module, choose M here. The module will
be called memain.
if MEILHAUS
config ME0600
tristate "Meilhaus ME-600 support"
default n
depends on PCI
help
This driver supports the Meilhaus ME-600 family of boards
that do data collection and multipurpose I/O.
To compile this driver as a module, choose M here: the module
will be called me0600.
config ME0900
tristate "Meilhaus ME-900 support"
default n
depends on PCI
help
This driver supports the Meilhaus ME-900 family of boards
that do data collection and multipurpose I/O.
To compile this driver as a module, choose M here: the module
will be called me0900.
config ME1000
tristate "Meilhaus ME-1000 support"
default n
depends on PCI
help
This driver supports the Meilhaus ME-1000 family of boards
that do data collection and multipurpose I/O.
To compile this driver as a module, choose M here: the module
will be called me1000.
config ME1400
tristate "Meilhaus ME-1400 support"
default n
depends on PCI
help
This driver supports the Meilhaus ME-1400 family of boards
that do data collection and multipurpose I/O.
To compile this driver as a module, choose M here: the module
will be called me1400.
config ME1600
tristate "Meilhaus ME-1600 support"
default n
depends on PCI
help
This driver supports the Meilhaus ME-1600 family of boards
that do data collection and multipurpose I/O.
To compile this driver as a module, choose M here: the module
will be called me1600.
config ME4600
tristate "Meilhaus ME-4600 support"
default n
depends on PCI
help
This driver supports the Meilhaus ME-4600 family of boards
that do data collection and multipurpose I/O.
To compile this driver as a module, choose M here: the module
will be called me4600.
config ME6000
tristate "Meilhaus ME-6000 support"
default n
depends on PCI
help
This driver supports the Meilhaus ME-6000 family of boards
that do data collection and multipurpose I/O.
To compile this driver as a module, choose M here: the module
will be called me6000.
config ME8100
tristate "Meilhaus ME-8100 support"
default n
depends on PCI
help
This driver supports the Meilhaus ME-8100 family of boards
that do data collection and multipurpose I/O.
To compile this driver as a module, choose M here: the module
will be called me8100.
config ME8200
tristate "Meilhaus ME-8200 support"
default n
depends on PCI
help
This driver supports the Meilhaus ME-8200 family of boards
that do data collection and multipurpose I/O.
To compile this driver as a module, choose M here: the module
will be called me8200.
config MEDUMMY
tristate "Meilhaus dummy driver"
default n
depends on PCI
help
This provides a dummy driver for the Meilhaus driver package
To compile this driver as a module, choose M here: the module
will be called medummy.
endif # MEILHAUS
#
# Makefile for Meilhaus linux driver system
#
obj-$(CONFIG_MEILHAUS) += memain.o
obj-$(CONFIG_ME1600) += me1600.o
obj-$(CONFIG_ME1000) += me1000.o
obj-$(CONFIG_ME1400) += me1400.o
obj-$(CONFIG_ME4600) += me4600.o
obj-$(CONFIG_ME6000) += me6000.o
obj-$(CONFIG_ME0600) += me0600.o
obj-$(CONFIG_ME8100) += me8100.o
obj-$(CONFIG_ME8200) += me8200.o
obj-$(CONFIG_ME0900) += me0900.o
obj-$(CONFIG_MEDUMMY) += medummy.o
me1600-objs := medevice.o medlist.o medlock.o me1600_device.o
me1600-objs += mesubdevice.o meslist.o meslock.o me1600_ao.o
me1000-objs := medevice.o medlist.o medlock.o me1000_device.o
me1000-objs += mesubdevice.o meslist.o meslock.o me1000_dio.o
me1400-objs := medevice.o medlist.o medlock.o me1400_device.o
me1400-objs += mesubdevice.o meslist.o meslock.o me8254.o me8255.o me1400_ext_irq.o
me4600-objs := medevice.o medlist.o medlock.o mefirmware.o me4600_device.o
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
me6000-objs := medevice.o medlist.o medlock.o mefirmware.o me6000_device.o
me6000-objs += mesubdevice.o meslist.o meslock.o me6000_dio.o me6000_ao.o
me0600-objs := medevice.o medlist.o medlock.o me0600_device.o
me0600-objs += mesubdevice.o meslist.o meslock.o me0600_relay.o me0600_ttli.o me0600_optoi.o me0600_dio.o me0600_ext_irq.o
me8100-objs := medevice.o medlist.o medlock.o me8100_device.o
me8100-objs += mesubdevice.o meslist.o meslock.o me8100_di.o me8100_do.o me8254.o
me8200-objs := medevice.o medlist.o medlock.o me8200_device.o
me8200-objs += mesubdevice.o meslist.o meslock.o me8200_di.o me8200_do.o me8200_dio.o
me0900-objs := medevice.o medlist.o medlock.o me0900_device.o
me0900-objs += mesubdevice.o meslist.o meslock.o me0900_do.o me0900_di.o
TODO:
- checkpatch.pl cleanups
- sparse issues
- Lindent
- audit userspace interface
- handle firmware properly
- possible comedi merge
Please send cleanup patches to Greg Kroah-Hartman <greg@kroah.com>
and CC: David Kiliani <mail@davidkiliani.de>
/**
* @file me0600_device.c
*
* @brief ME-630 device class implementation.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
* @author Krzysztof Gantzke (k.gantzke@meilhaus.de)
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif
#ifndef MODULE
# define MODULE
#endif
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include "meids.h"
#include "meerror.h"
#include "mecommon.h"
#include "meinternal.h"
#include "medebug.h"
#include "medevice.h"
#include "me0600_device.h"
#include "mesubdevice.h"
#include "me0600_relay.h"
#include "me0600_ttli.h"
#include "me0600_optoi.h"
#include "me0600_dio.h"
#include "me0600_ext_irq.h"
me_device_t *me0600_pci_constructor(struct pci_dev *pci_device)
{
me0600_device_t *me0600_device;
me_subdevice_t *subdevice;
unsigned int version_idx;
int err;
int i;
PDEBUG("executed.\n");
// Allocate structure for device instance.
me0600_device = kmalloc(sizeof(me0600_device_t), GFP_KERNEL);
if (!me0600_device) {
PERROR("Cannot get memory for device instance.\n");
return NULL;
}
memset(me0600_device, 0, sizeof(me0600_device_t));
// Initialize base class structure.
err = me_device_pci_init((me_device_t *) me0600_device, pci_device);
if (err) {
kfree(me0600_device);
PERROR("Cannot initialize device base class.\n");
return NULL;
}
/* Get the index in the device version information table. */
version_idx =
me0600_versions_get_device_index(me0600_device->base.info.pci.
device_id);
// Initialize spin lock .
spin_lock_init(&me0600_device->dio_ctrl_reg_lock);
spin_lock_init(&me0600_device->intcsr_lock);
// Create subdevice instances.
for (i = 0; i < me0600_versions[version_idx].optoi_subdevices; i++) {
subdevice =
(me_subdevice_t *) me0600_optoi_constructor(me0600_device->
base.info.pci.
reg_bases[2]);
if (!subdevice) {
me_device_deinit((me_device_t *) me0600_device);
kfree(me0600_device);
PERROR("Cannot get memory for subdevice.\n");
return NULL;
}
me_slist_add_subdevice_tail(&me0600_device->base.slist,
subdevice);
}
for (i = 0; i < me0600_versions[version_idx].relay_subdevices; i++) {
subdevice =
(me_subdevice_t *) me0600_relay_constructor(me0600_device->
base.info.pci.
reg_bases[2]);
if (!subdevice) {
me_device_deinit((me_device_t *) me0600_device);
kfree(me0600_device);
PERROR("Cannot get memory for subdevice.\n");
return NULL;
}
me_slist_add_subdevice_tail(&me0600_device->base.slist,
subdevice);
}
for (i = 0; i < me0600_versions[version_idx].ttli_subdevices; i++) {
subdevice =
(me_subdevice_t *) me0600_ttli_constructor(me0600_device->
base.info.pci.
reg_bases[2]);
if (!subdevice) {
me_device_deinit((me_device_t *) me0600_device);
kfree(me0600_device);
PERROR("Cannot get memory for subdevice.\n");
return NULL;
}
me_slist_add_subdevice_tail(&me0600_device->base.slist,
subdevice);
}
for (i = 0; i < me0600_versions[version_idx].dio_subdevices; i++) {
subdevice =
(me_subdevice_t *) me0600_dio_constructor(me0600_device->
base.info.pci.
reg_bases[2], i,
&me0600_device->
dio_ctrl_reg_lock);
if (!subdevice) {
me_device_deinit((me_device_t *) me0600_device);
kfree(me0600_device);
PERROR("Cannot get memory for subdevice.\n");
return NULL;
}
me_slist_add_subdevice_tail(&me0600_device->base.slist,
subdevice);
}
for (i = 0; i < me0600_versions[version_idx].ext_irq_subdevices; i++) {
subdevice =
(me_subdevice_t *)
me0600_ext_irq_constructor(me0600_device->base.info.pci.
reg_bases[1],
me0600_device->base.info.pci.
reg_bases[2],
&me0600_device->intcsr_lock, i,
me0600_device->base.irq);
if (!subdevice) {
me_device_deinit((me_device_t *) me0600_device);
kfree(me0600_device);
PERROR("Cannot get memory for subdevice.\n");
return NULL;
}
me_slist_add_subdevice_tail(&me0600_device->base.slist,
subdevice);
}
return (me_device_t *) me0600_device;
}
// Init and exit of module.
static int __init me0600_init(void)
{
PDEBUG("executed.\n");
return 0;
}
static void __exit me0600_exit(void)
{
PDEBUG("executed.\n");
}
module_init(me0600_init);
module_exit(me0600_exit);
// Administrative stuff for modinfo.
MODULE_AUTHOR
("Guenter Gebhardt <g.gebhardt@meilhaus.de> & Krzysztof Gantzke <k.gantzke@meilhaus.de>");
MODULE_DESCRIPTION("Device Driver Module for ME-6xx Device");
MODULE_SUPPORTED_DEVICE("Meilhaus ME-6xx Devices");
MODULE_LICENSE("GPL");
// Export the constructor.
EXPORT_SYMBOL(me0600_pci_constructor);
/**
* @file me0600_device.h
*
* @brief ME-630 device class.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0600_DEVICE_H
#define _ME0600_DEVICE_H
#include <linux/pci.h>
#include <linux/spinlock.h>
#include "medevice.h"
#ifdef __KERNEL__
/**
* @brief Structure holding ME-630 device capabilities.
*/
typedef struct me0600_version {
uint16_t device_id;
unsigned int relay_subdevices;
unsigned int ttli_subdevices;
unsigned int optoi_subdevices;
unsigned int dio_subdevices;
unsigned int ext_irq_subdevices;
} me0600_version_t;
/**
* @brief Device capabilities.
*/
static me0600_version_t me0600_versions[] = {
{PCI_DEVICE_ID_MEILHAUS_ME0630, 1, 1, 1, 2, 2},
{0},
};
#define ME0600_DEVICE_VERSIONS (sizeof(me0600_versions) / sizeof(me0600_version_t) - 1) /**< Returns the number of entries in #me0600_versions. */
/**
* @brief Returns the index of the device entry in #me0600_versions.
*
* @param device_id The PCI device id of the device to query.
* @return The index of the device in #me0600_versions.
*/
static inline unsigned int me0600_versions_get_device_index(uint16_t device_id)
{
unsigned int i;
for (i = 0; i < ME0600_DEVICE_VERSIONS; i++)
if (me0600_versions[i].device_id == device_id)
break;
return i;
}
/**
* @brief The ME-630 device class structure.
*/
typedef struct me0600_device {
me_device_t base; /**< The Meilhaus device base class. */
/* Child class attributes. */
spinlock_t dio_ctrl_reg_lock;
spinlock_t intcsr_lock;
} me0600_device_t;
/**
* @brief The ME-630 device class constructor.
*
* @param pci_device The pci device structure given by the PCI subsystem.
*
* @return On succes a new ME-630 device instance. \n
* NULL on error.
*/
me_device_t *me0600_pci_constructor(struct pci_dev *pci_device)
__attribute__ ((weak));
#endif
#endif
This diff is collapsed.
/**
* @file me0600_dio.h
*
* @brief ME-630 digital input/output subdevice class.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0600_DIO_H_
#define _ME0600_DIO_H_
#include "mesubdevice.h"
#ifdef __KERNEL__
/**
* @brief The template subdevice class.
*/
typedef struct me0600_dio_subdevice {
/* Inheritance */
me_subdevice_t base; /**< The subdevice base class. */
/* Attributes */
spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */
spinlock_t *ctrl_reg_lock; /**< Spin lock to protect #ctrl_reg from concurrent access. */
unsigned int dio_idx; /**< The index of the digital i/o on the device. */
unsigned long port_reg; /**< Register holding the port status. */
unsigned long ctrl_reg; /**< Register to configure the port direction. */
#ifdef MEDEBUG_DEBUG_REG
unsigned long reg_base;
#endif
} me0600_dio_subdevice_t;
/**
* @brief The constructor to generate a ME-630 digital input/ouput subdevice instance.
*
* @param reg_base The register base address of the device as returned by the PCI BIOS.
* @param dio_idx The index of the digital i/o port on the device.
* @param ctrl_reg_lock Spin lock protecting the control register.
*
* @return Pointer to new instance on success.\n
* NULL on error.
*/
me0600_dio_subdevice_t *me0600_dio_constructor(uint32_t reg_base,
unsigned int dio_idx,
spinlock_t * ctrl_reg_lock);
#endif
#endif
/**
* @file me0600_dio_reg.h
*
* @brief ME-630 digital input/output subdevice register definitions.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0600_DIO_REG_H_
#define _ME0600_DIO_REG_H_
#ifdef __KERNEL__
#define ME0600_DIO_CONFIG_REG 0x0007
#define ME0600_DIO_PORT_0_REG 0x0008
#define ME0600_DIO_PORT_1_REG 0x0009
#define ME0600_DIO_PORT_REG ME0600_DIO_PORT_0_REG
#define ME0600_DIO_CONFIG_BIT_OUT_0 0x0001
#define ME0600_DIO_CONFIG_BIT_OUT_1 0x0004
#endif
#endif
This diff is collapsed.
/**
* @file me0600_ext_irq.h
*
* @brief ME-630 external interrupt implementation.
* @note Copyright (C) 2006 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
#ifndef _ME0600_EXT_IRQ_H_
#define _ME0600_EXT_IRQ_H_
#include <linux/sched.h>
#include "mesubdevice.h"
#include "meslock.h"
#ifdef __KERNEL__
/**
* @brief The ME-630 external interrupt subdevice class.
*/
typedef struct me0600_ext_irq_subdevice {
/* Inheritance */
me_subdevice_t base; /**< The subdevice base class. */
/* Attributes */
spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */
spinlock_t *intcsr_lock; /**< Spin lock to protect #intcsr. */
wait_queue_head_t wait_queue; /**< Queue to put on threads waiting for an interrupt. */
int irq; /**< The irq number assigned by PCI BIOS. */
int rised; /**< If true an interrupt has occured. */
unsigned int n; /**< The number of interrupt since the driver was loaded. */
unsigned int lintno; /**< The number of the local PCI interrupt. */
uint32_t intcsr; /**< The PLX interrupt control and status register. */
uint32_t reset_reg; /**< The control register. */
} me0600_ext_irq_subdevice_t;
/**
* @brief The constructor to generate a ME-630 external interrupt instance.
*
* @param plx_reg_base The register base address of the PLX chip as returned by the PCI BIOS.
* @param me0600_reg_base The register base address of the ME-630 device as returned by the PCI BIOS.
* @param irq The irq assigned by the PCI BIOS.
*
* @return Pointer to new instance on success.\n
* NULL on error.
*/
me0600_ext_irq_subdevice_t *me0600_ext_irq_constructor(uint32_t plx_reg_base,
uint32_t me0600_reg_base,
spinlock_t * intcsr_lock,
unsigned int ext_irq_idx,
int irq);
#endif
#endif
/**
* @file me0600_ext_irq_reg.h
*
* @brief ME-630 external interrupt register definitions.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
#ifndef _ME0600_EXT_IRQ_REG_H_
#define _ME0600_EXT_IRQ_REG_H_
#ifdef __KERNEL__
#define ME0600_INT_0_RESET_REG 0x0005
#define ME0600_INT_1_RESET_REG 0x0006
#endif
#endif
/**
* @file me0600_optoi.c
*
* @brief ME-630 Optoisolated input subdevice instance.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
* @author Krzysztof Gantzke (k.gantzke@meilhaus.de)
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif
/*
* Includes
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <asm/io.h>
#include <linux/types.h>
#include "medefines.h"
#include "meinternal.h"
#include "meerror.h"
#include "medebug.h"
#include "me0600_optoi_reg.h"
#include "me0600_optoi.h"
/*
* Defines
*/
/*
* Functions
*/
static int me0600_optoi_io_reset_subdevice(struct me_subdevice *subdevice,
struct file *filep, int flags)
{
if (flags) {
PERROR("Invalid flag specified.\n");
return ME_ERRNO_INVALID_FLAGS;
}
PDEBUG("executed.\n");
return ME_ERRNO_SUCCESS;
}
static int me0600_optoi_io_single_config(me_subdevice_t * subdevice,
struct file *filep,
int channel,
int single_config,
int ref,
int trig_chan,
int trig_type,
int trig_edge, int flags)
{
me0600_optoi_subdevice_t *instance;
int err = ME_ERRNO_SUCCESS;
PDEBUG("executed.\n");
instance = (me0600_optoi_subdevice_t *) subdevice;
ME_SUBDEVICE_ENTER;
spin_lock(&instance->subdevice_lock);
switch (flags) {
case ME_IO_SINGLE_CONFIG_NO_FLAGS:
case ME_IO_SINGLE_CONFIG_DIO_BYTE:
if (channel == 0) {
if (single_config != ME_SINGLE_CONFIG_DIO_INPUT) {
PERROR("Invalid port direction specified.\n");
err = ME_ERRNO_INVALID_SINGLE_CONFIG;
}
} else {
PERROR("Invalid channel specified.\n");
err = ME_ERRNO_INVALID_CHANNEL;
}
break;
default:
PERROR("Invalid flags specified.\n");
err = ME_ERRNO_INVALID_FLAGS;
break;
}
spin_unlock(&instance->subdevice_lock);
ME_SUBDEVICE_EXIT;
return err;
}
static int me0600_optoi_io_single_read(me_subdevice_t * subdevice,
struct file *filep,
int channel,
int *value, int time_out, int flags)
{
me0600_optoi_subdevice_t *instance;
int err = ME_ERRNO_SUCCESS;
PDEBUG("executed.\n");
instance = (me0600_optoi_subdevice_t *) subdevice;
ME_SUBDEVICE_ENTER;
spin_lock(&instance->subdevice_lock);
switch (flags) {
case ME_IO_SINGLE_TYPE_DIO_BIT:
if ((channel >= 0) && (channel < 8)) {
*value = inb(instance->port_reg) & (0x1 << channel);
} else {
PERROR("Invalid bit number specified.\n");
err = ME_ERRNO_INVALID_CHANNEL;
}
break;
case ME_IO_SINGLE_NO_FLAGS:
case ME_IO_SINGLE_TYPE_DIO_BYTE:
if (channel == 0) {
*value = inb(instance->port_reg);
} else {
PERROR("Invalid byte number specified.\n");
err = ME_ERRNO_INVALID_CHANNEL;
}
break;
default:
PERROR("Invalid flags specified.\n");
err = ME_ERRNO_INVALID_FLAGS;
}
spin_unlock(&instance->subdevice_lock);
ME_SUBDEVICE_EXIT;
return err;
}
static int me0600_optoi_query_number_channels(me_subdevice_t * subdevice,
int *number)
{
PDEBUG("executed.\n");
*number = 8;
return ME_ERRNO_SUCCESS;
}
static int me0600_optoi_query_subdevice_type(me_subdevice_t * subdevice,
int *type, int *subtype)
{
PDEBUG("executed.\n");
*type = ME_TYPE_DI;
*subtype = ME_SUBTYPE_SINGLE;
return ME_ERRNO_SUCCESS;
}
static int me0600_optoi_query_subdevice_caps(me_subdevice_t * subdevice,
int *caps)
{
PDEBUG("executed.\n");
*caps = 0;
return ME_ERRNO_SUCCESS;
}
me0600_optoi_subdevice_t *me0600_optoi_constructor(uint32_t reg_base)
{
me0600_optoi_subdevice_t *subdevice;
int err;
PDEBUG("executed.\n");
/* Allocate memory for subdevice instance */
subdevice = kmalloc(sizeof(me0600_optoi_subdevice_t), GFP_KERNEL);
if (!subdevice) {
PERROR("Cannot get memory for subdevice instance.\n");
return NULL;
}
memset(subdevice, 0, sizeof(me0600_optoi_subdevice_t));
/* Initialize subdevice base class */
err = me_subdevice_init(&subdevice->base);
if (err) {
PERROR("Cannot initialize subdevice base class instance.\n");
kfree(subdevice);
return NULL;
}
// Initialize spin locks.
spin_lock_init(&subdevice->subdevice_lock);
/* Save the subdevice index */
subdevice->port_reg = reg_base + ME0600_OPTO_INPUT_REG;
/* Overload base class methods. */
subdevice->base.me_subdevice_io_reset_subdevice =
me0600_optoi_io_reset_subdevice;
subdevice->base.me_subdevice_io_single_config =
me0600_optoi_io_single_config;
subdevice->base.me_subdevice_io_single_read =
me0600_optoi_io_single_read;
subdevice->base.me_subdevice_query_number_channels =
me0600_optoi_query_number_channels;
subdevice->base.me_subdevice_query_subdevice_type =
me0600_optoi_query_subdevice_type;
subdevice->base.me_subdevice_query_subdevice_caps =
me0600_optoi_query_subdevice_caps;
return subdevice;
}
/**
* @file me0600_optoi.h
*
* @brief ME-630 Optoisolated input subdevice class.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0600_OPTOI_H_
#define _ME0600_OPTOI_H_
#include "mesubdevice.h"
#ifdef __KERNEL__
/**
* @brief The template subdevice class.
*/
typedef struct me0600_optoi_subdevice {
/* Inheritance */
me_subdevice_t base; /**< The subdevice base class. */
/* Attributes */
spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */
uint32_t port_reg; /**< Register holding the port status. */
} me0600_optoi_subdevice_t;
/**
* @brief The constructor to generate a ME-630 Optoisolated input subdevice instance.
*
* @param reg_base The register base address of the device as returned by the PCI BIOS.
*
* @return Pointer to new instance on success.\n
* NULL on error.
*/
me0600_optoi_subdevice_t *me0600_optoi_constructor(uint32_t reg_base);
#endif
#endif
/**
* @file me0600_optoi_reg.h
*
* @brief ME-630 Optoisolated input subdevice register definitions.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0600_OPTOI_REG_H_
#define _ME0600_OPTOI_REG_H_
#ifdef __KERNEL__
#define ME0600_OPTO_INPUT_REG 0x0004
#endif
#endif
/**
* @file me0600_relay.c
*
* @brief ME-630 relay subdevice instance.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
* @author Krzysztof Gantzke (k.gantzke@meilhaus.de)
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif
/*
* Includes
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <asm/io.h>
#include <linux/types.h>
#include "medefines.h"
#include "meinternal.h"
#include "meerror.h"
#include "medebug.h"
#include "me0600_relay_reg.h"
#include "me0600_relay.h"
/*
* Defines
*/
/*
* Functions
*/
static int me0600_relay_io_reset_subdevice(struct me_subdevice *subdevice,
struct file *filep, int flags)
{
me0600_relay_subdevice_t *instance;
PDEBUG("executed.\n");
instance = (me0600_relay_subdevice_t *) subdevice;
if (flags) {
PERROR("Invalid flag specified.\n");
return ME_ERRNO_INVALID_FLAGS;
}
ME_SUBDEVICE_ENTER;
spin_lock(&instance->subdevice_lock);
outb(0x0, instance->port_0_reg);
PDEBUG_REG("port_0_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
instance->port_0_reg - instance->reg_base, 0);
outb(0x0, instance->port_1_reg);
PDEBUG_REG("port_1_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
instance->port_1_reg - instance->reg_base, 0);
spin_unlock(&instance->subdevice_lock);
ME_SUBDEVICE_EXIT;
return ME_ERRNO_SUCCESS;
}
static int me0600_relay_io_single_config(me_subdevice_t * subdevice,
struct file *filep,
int channel,
int single_config,
int ref,
int trig_chan,
int trig_type,
int trig_edge, int flags)
{
me0600_relay_subdevice_t *instance;
int err = ME_ERRNO_SUCCESS;
PDEBUG("executed.\n");
instance = (me0600_relay_subdevice_t *) subdevice;
ME_SUBDEVICE_ENTER;
spin_lock(&instance->subdevice_lock);
switch (flags) {
case ME_IO_SINGLE_CONFIG_NO_FLAGS:
case ME_IO_SINGLE_CONFIG_DIO_WORD:
if (channel == 0) {
if (single_config != ME_SINGLE_CONFIG_DIO_OUTPUT) {
PERROR("Invalid word direction specified.\n");
err = ME_ERRNO_INVALID_SINGLE_CONFIG;
}
} else {
PERROR("Invalid channel specified.\n");
err = ME_ERRNO_INVALID_CHANNEL;
}
break;
default:
PERROR("Invalid flags specified.\n");
err = ME_ERRNO_INVALID_FLAGS;
break;
}
spin_unlock(&instance->subdevice_lock);
ME_SUBDEVICE_EXIT;
return err;
}
static int me0600_relay_io_single_read(me_subdevice_t * subdevice,
struct file *filep,
int channel,
int *value, int time_out, int flags)
{
me0600_relay_subdevice_t *instance;
int err = ME_ERRNO_SUCCESS;
PDEBUG("executed.\n");
instance = (me0600_relay_subdevice_t *) subdevice;
ME_SUBDEVICE_ENTER;
spin_lock(&instance->subdevice_lock);
switch (flags) {
case ME_IO_SINGLE_TYPE_DIO_BIT:
if ((channel >= 0) && (channel < 8)) {
*value = inb(instance->port_0_reg) & (0x1 << channel);
} else if ((channel >= 8) && (channel < 16)) {
*value =
inb(instance->port_1_reg) & (0x1 << (channel - 8));
} else {
PERROR("Invalid bit number specified.\n");
err = ME_ERRNO_INVALID_CHANNEL;
}
break;
case ME_IO_SINGLE_TYPE_DIO_BYTE:
if (channel == 0) {
*value = inb(instance->port_0_reg);
} else if (channel == 1) {
*value = inb(instance->port_1_reg);
} else {
PERROR("Invalid byte number specified.\n");
err = ME_ERRNO_INVALID_CHANNEL;
}
break;
case ME_IO_SINGLE_NO_FLAGS:
case ME_IO_SINGLE_TYPE_DIO_WORD:
if (channel == 0) {
*value = (uint32_t) inb(instance->port_1_reg) << 8;
*value |= inb(instance->port_0_reg);
} else {
PERROR("Invalid word number specified.\n");
err = ME_ERRNO_INVALID_CHANNEL;
}
break;
default:
PERROR("Invalid flags specified.\n");
err = ME_ERRNO_INVALID_FLAGS;
}
spin_unlock(&instance->subdevice_lock);
ME_SUBDEVICE_EXIT;
return err;
}
static int me0600_relay_io_single_write(me_subdevice_t * subdevice,
struct file *filep,
int channel,
int value, int time_out, int flags)
{
me0600_relay_subdevice_t *instance;
int err = ME_ERRNO_SUCCESS;
uint8_t state;
PDEBUG("executed.\n");
instance = (me0600_relay_subdevice_t *) subdevice;
ME_SUBDEVICE_ENTER;
spin_lock(&instance->subdevice_lock);
switch (flags) {
case ME_IO_SINGLE_TYPE_DIO_BIT:
if ((channel >= 0) && (channel < 8)) {
state = inb(instance->port_0_reg);
state =
value ? (state | (0x1 << channel)) : (state &
~(0x1 <<
channel));
outb(state, instance->port_0_reg);
} else if ((channel >= 8) && (channel < 16)) {
state = inb(instance->port_1_reg);
state =
value ? (state | (0x1 << (channel - 8))) : (state &
~(0x1 <<
(channel
-
8)));
outb(state, instance->port_1_reg);
} else {
PERROR("Invalid bit number specified.\n");
err = ME_ERRNO_INVALID_CHANNEL;
}
break;
case ME_IO_SINGLE_TYPE_DIO_BYTE:
if (channel == 0) {
outb(value, instance->port_0_reg);
} else if (channel == 1) {
outb(value, instance->port_1_reg);
} else {
PERROR("Invalid byte number specified.\n");
err = ME_ERRNO_INVALID_CHANNEL;
}
break;
case ME_IO_SINGLE_NO_FLAGS:
case ME_IO_SINGLE_TYPE_DIO_WORD:
if (channel == 0) {
outb(value, instance->port_0_reg);
outb(value >> 8, instance->port_1_reg);
} else {
PERROR("Invalid word number specified.\n");
err = ME_ERRNO_INVALID_CHANNEL;
}
break;
default:
PERROR("Invalid flags specified.\n");
err = ME_ERRNO_INVALID_FLAGS;
break;
}
spin_unlock(&instance->subdevice_lock);
ME_SUBDEVICE_EXIT;
return err;
}
static int me0600_relay_query_number_channels(me_subdevice_t * subdevice,
int *number)
{
PDEBUG("executed.\n");
*number = 16;
return ME_ERRNO_SUCCESS;
}
static int me0600_relay_query_subdevice_type(me_subdevice_t * subdevice,
int *type, int *subtype)
{
PDEBUG("executed.\n");
*type = ME_TYPE_DO;
*subtype = ME_SUBTYPE_SINGLE;
return ME_ERRNO_SUCCESS;
}
static int me0600_relay_query_subdevice_caps(me_subdevice_t * subdevice,
int *caps)
{
PDEBUG("executed.\n");
*caps = 0;
return ME_ERRNO_SUCCESS;
}
me0600_relay_subdevice_t *me0600_relay_constructor(uint32_t reg_base)
{
me0600_relay_subdevice_t *subdevice;
int err;
PDEBUG("executed.\n");
/* Allocate memory for subdevice instance */
subdevice = kmalloc(sizeof(me0600_relay_subdevice_t), GFP_KERNEL);
if (!subdevice) {
PERROR("Cannot get memory for subdevice instance.\n");
return NULL;
}
memset(subdevice, 0, sizeof(me0600_relay_subdevice_t));
/* Initialize subdevice base class */
err = me_subdevice_init(&subdevice->base);
if (err) {
PERROR("Cannot initialize subdevice base class instance.\n");
kfree(subdevice);
return NULL;
}
// Initialize spin locks.
spin_lock_init(&subdevice->subdevice_lock);
/* Save the subdevice index */
subdevice->port_0_reg = reg_base + ME0600_RELAIS_0_REG;
subdevice->port_1_reg = reg_base + ME0600_RELAIS_1_REG;
#ifdef MEDEBUG_DEBUG_REG
subdevice->reg_base = reg_base;
#endif
/* Overload base class methods. */
subdevice->base.me_subdevice_io_reset_subdevice =
me0600_relay_io_reset_subdevice;
subdevice->base.me_subdevice_io_single_config =
me0600_relay_io_single_config;
subdevice->base.me_subdevice_io_single_read =
me0600_relay_io_single_read;
subdevice->base.me_subdevice_io_single_write =
me0600_relay_io_single_write;
subdevice->base.me_subdevice_query_number_channels =
me0600_relay_query_number_channels;
subdevice->base.me_subdevice_query_subdevice_type =
me0600_relay_query_subdevice_type;
subdevice->base.me_subdevice_query_subdevice_caps =
me0600_relay_query_subdevice_caps;
return subdevice;
}
/**
* @file me0600_relay.h
*
* @brief ME-630 relay subdevice class.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0600_RELAY_H_
#define _ME0600_RELAY_H_
#include "mesubdevice.h"
#ifdef __KERNEL__
/**
* @brief The template subdevice class.
*/
typedef struct me0600_relay_subdevice {
/* Inheritance */
me_subdevice_t base; /**< The subdevice base class. */
/* Attributes */
spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */
unsigned long port_0_reg; /**< Register holding the port status. */
unsigned long port_1_reg; /**< Register holding the port status. */
#ifdef MEDEBUG_DEBUG_REG
unsigned long reg_base;
#endif
} me0600_relay_subdevice_t;
/**
* @brief The constructor to generate a ME-630 relay subdevice instance.
*
* @param reg_base The register base address of the device as returned by the PCI BIOS.
* @param ctrl_reg_lock Spin lock protecting the control register.
*
* @return Pointer to new instance on success.\n
* NULL on error.
*/
me0600_relay_subdevice_t *me0600_relay_constructor(uint32_t reg_base);
#endif
#endif
/**
* @file me0600_relay_reg.h
*
* @brief ME-630 relay subdevice register definitions.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0600_RELAY_REG_H_
#define _ME0600_RELAY_REG_H_
#ifdef __KERNEL__
#define ME0600_RELAIS_0_REG 0x0001
#define ME0600_RELAIS_1_REG 0x0002
#endif
#endif
/**
* @file me0600_ttli.c
*
* @brief ME-630 TTL input subdevice instance.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
* @author Krzysztof Gantzke (k.gantzke@meilhaus.de)
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif
/*
* Includes
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <asm/io.h>
#include <linux/types.h>
#include "medefines.h"
#include "meinternal.h"
#include "meerror.h"
#include "medebug.h"
#include "me0600_ttli_reg.h"
#include "me0600_ttli.h"
/*
* Defines
*/
/*
* Functions
*/
static int me0600_ttli_io_reset_subdevice(struct me_subdevice *subdevice,
struct file *filep, int flags)
{
if (flags) {
PERROR("Invalid flag specified.\n");
return ME_ERRNO_INVALID_FLAGS;
}
PDEBUG("executed.\n");
return ME_ERRNO_SUCCESS;
}
static int me0600_ttli_io_single_config(me_subdevice_t * subdevice,
struct file *filep,
int channel,
int single_config,
int ref,
int trig_chan,
int trig_type, int trig_edge, int flags)
{
me0600_ttli_subdevice_t *instance;
int err = ME_ERRNO_SUCCESS;
PDEBUG("executed.\n");
instance = (me0600_ttli_subdevice_t *) subdevice;
ME_SUBDEVICE_ENTER;
spin_lock(&instance->subdevice_lock);
switch (flags) {
case ME_IO_SINGLE_CONFIG_NO_FLAGS:
case ME_IO_SINGLE_CONFIG_DIO_BYTE:
if (channel == 0) {
if (single_config != ME_SINGLE_CONFIG_DIO_INPUT) {
PERROR("Invalid port direction specified.\n");
err = ME_ERRNO_INVALID_SINGLE_CONFIG;
}
} else {
PERROR("Invalid channel specified.\n");
err = ME_ERRNO_INVALID_CHANNEL;
}
break;
default:
PERROR("Invalid flags specified.\n");
err = ME_ERRNO_INVALID_FLAGS;
break;
}
spin_unlock(&instance->subdevice_lock);
ME_SUBDEVICE_EXIT;
return err;
}
static int me0600_ttli_io_single_read(me_subdevice_t * subdevice,
struct file *filep,
int channel,
int *value, int time_out, int flags)
{
me0600_ttli_subdevice_t *instance;
int err = ME_ERRNO_SUCCESS;
PDEBUG("executed.\n");
instance = (me0600_ttli_subdevice_t *) subdevice;
ME_SUBDEVICE_ENTER;
spin_lock(&instance->subdevice_lock);
switch (flags) {
case ME_IO_SINGLE_TYPE_DIO_BIT:
if ((channel >= 0) && (channel < 8)) {
*value = inb(instance->port_reg) & (0x1 << channel);
} else {
PERROR("Invalid bit number specified.\n");
err = ME_ERRNO_INVALID_CHANNEL;
}
break;
case ME_IO_SINGLE_NO_FLAGS:
case ME_IO_SINGLE_TYPE_DIO_BYTE:
if (channel == 0) {
*value = inb(instance->port_reg);
} else {
PERROR("Invalid byte number specified.\n");
err = ME_ERRNO_INVALID_CHANNEL;
}
break;
default:
PERROR("Invalid flags specified.\n");
err = ME_ERRNO_INVALID_FLAGS;
}
spin_unlock(&instance->subdevice_lock);
ME_SUBDEVICE_EXIT;
return err;
}
static int me0600_ttli_query_number_channels(me_subdevice_t * subdevice,
int *number)
{
PDEBUG("executed.\n");
*number = 8;
return ME_ERRNO_SUCCESS;
}
static int me0600_ttli_query_subdevice_type(me_subdevice_t * subdevice,
int *type, int *subtype)
{
PDEBUG("executed.\n");
*type = ME_TYPE_DI;
*subtype = ME_SUBTYPE_SINGLE;
return ME_ERRNO_SUCCESS;
}
static int me0600_ttli_query_subdevice_caps(me_subdevice_t * subdevice,
int *caps)
{
PDEBUG("executed.\n");
*caps = 0;
return ME_ERRNO_SUCCESS;
}
me0600_ttli_subdevice_t *me0600_ttli_constructor(uint32_t reg_base)
{
me0600_ttli_subdevice_t *subdevice;
int err;
PDEBUG("executed.\n");
/* Allocate memory for subdevice instance */
subdevice = kmalloc(sizeof(me0600_ttli_subdevice_t), GFP_KERNEL);
if (!subdevice) {
PERROR("Cannot get memory for subdevice instance.\n");
return NULL;
}
memset(subdevice, 0, sizeof(me0600_ttli_subdevice_t));
/* Initialize subdevice base class */
err = me_subdevice_init(&subdevice->base);
if (err) {
PERROR("Cannot initialize subdevice base class instance.\n");
kfree(subdevice);
return NULL;
}
// Initialize spin locks.
spin_lock_init(&subdevice->subdevice_lock);
/* Save the subdevice index */
subdevice->port_reg = reg_base + ME0600_TTL_INPUT_REG;
/* Overload base class methods. */
subdevice->base.me_subdevice_io_reset_subdevice =
me0600_ttli_io_reset_subdevice;
subdevice->base.me_subdevice_io_single_config =
me0600_ttli_io_single_config;
subdevice->base.me_subdevice_io_single_read =
me0600_ttli_io_single_read;
subdevice->base.me_subdevice_query_number_channels =
me0600_ttli_query_number_channels;
subdevice->base.me_subdevice_query_subdevice_type =
me0600_ttli_query_subdevice_type;
subdevice->base.me_subdevice_query_subdevice_caps =
me0600_ttli_query_subdevice_caps;
return subdevice;
}
/**
* @file me0600_ttli.h
*
* @brief ME-630 TTL input subdevice class.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0600_TTLI_H_
#define _ME0600_TTLI_H_
#include "mesubdevice.h"
#ifdef __KERNEL__
/**
* @brief The template subdevice class.
*/
typedef struct me0600_ttli_subdevice {
/* Inheritance */
me_subdevice_t base; /**< The subdevice base class. */
/* Attributes */
spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */
uint32_t port_reg; /**< Register holding the port status. */
} me0600_ttli_subdevice_t;
/**
* @brief The constructor to generate a ME-630 TTL input subdevice instance.
*
* @param reg_base The register base address of the device as returned by the PCI BIOS.
*
* @return Pointer to new instance on success.\n
* NULL on error.
*/
me0600_ttli_subdevice_t *me0600_ttli_constructor(uint32_t reg_base);
#endif
#endif
/**
* @file me0600_ttli_reg.h
*
* @brief ME-630 TTL input subdevice register definitions.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0600_TTLI_REG_H_
#define _ME0600_TTLI_REG_H_
#ifdef __KERNEL__
#define ME0600_TTL_INPUT_REG 0x0003
#endif
#endif
/**
* @file me0900_device.c
*
* @brief ME-9x device class implementation.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
* @author Krzysztof Gantzke (k.gantzke@meilhaus.de)
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif
#ifndef MODULE
# define MODULE
#endif
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include "meids.h"
#include "meerror.h"
#include "mecommon.h"
#include "meinternal.h"
#include "medebug.h"
#include "medevice.h"
#include "me0900_device.h"
#include "me0900_reg.h"
#include "mesubdevice.h"
#include "me0900_do.h"
#include "me0900_di.h"
me_device_t *me0900_pci_constructor(struct pci_dev *pci_device)
{
me0900_device_t *me0900_device;
me_subdevice_t *subdevice;
unsigned int version_idx;
int err;
int i;
int port_shift;
PDEBUG("executed.\n");
// Allocate structure for device instance.
me0900_device = kmalloc(sizeof(me0900_device_t), GFP_KERNEL);
if (!me0900_device) {
PERROR("Cannot get memory for device instance.\n");
return NULL;
}
memset(me0900_device, 0, sizeof(me0900_device_t));
// Initialize base class structure.
err = me_device_pci_init((me_device_t *) me0900_device, pci_device);
if (err) {
kfree(me0900_device);
PERROR("Cannot initialize device base class.\n");
return NULL;
}
/* Get the index in the device version information table. */
version_idx =
me0900_versions_get_device_index(me0900_device->base.info.pci.
device_id);
/* Initialize 8255 chip to desired mode */
if (me0900_device->base.info.pci.device_id ==
PCI_DEVICE_ID_MEILHAUS_ME0940) {
outb(0x9B,
me0900_device->base.info.pci.reg_bases[2] +
ME0900_CTRL_REG);
} else if (me0900_device->base.info.pci.device_id ==
PCI_DEVICE_ID_MEILHAUS_ME0950) {
outb(0x89,
me0900_device->base.info.pci.reg_bases[2] +
ME0900_CTRL_REG);
outb(0x00,
me0900_device->base.info.pci.reg_bases[2] +
ME0900_WRITE_ENABLE_REG);
} else if (me0900_device->base.info.pci.device_id ==
PCI_DEVICE_ID_MEILHAUS_ME0960) {
outb(0x8B,
me0900_device->base.info.pci.reg_bases[2] +
ME0900_CTRL_REG);
outb(0x00,
me0900_device->base.info.pci.reg_bases[2] +
ME0900_WRITE_ENABLE_REG);
}
port_shift =
(me0900_device->base.info.pci.device_id ==
PCI_DEVICE_ID_MEILHAUS_ME0960) ? 1 : 0;
// Create subdevice instances.
for (i = 0; i < me0900_versions[version_idx].di_subdevices; i++) {
subdevice =
(me_subdevice_t *) me0900_di_constructor(me0900_device->
base.info.pci.
reg_bases[2],
i + port_shift);
if (!subdevice) {
me_device_deinit((me_device_t *) me0900_device);
kfree(me0900_device);
PERROR("Cannot get memory for subdevice.\n");
return NULL;
}
me_slist_add_subdevice_tail(&me0900_device->base.slist,
subdevice);
}
for (i = 0; i < me0900_versions[version_idx].do_subdevices; i++) {
subdevice =
(me_subdevice_t *) me0900_do_constructor(me0900_device->
base.info.pci.
reg_bases[2], i);
if (!subdevice) {
me_device_deinit((me_device_t *) me0900_device);
kfree(me0900_device);
PERROR("Cannot get memory for subdevice.\n");
return NULL;
}
me_slist_add_subdevice_tail(&me0900_device->base.slist,
subdevice);
}
return (me_device_t *) me0900_device;
}
// Init and exit of module.
static int __init me0900_init(void)
{
PDEBUG("executed.\n.");
return 0;
}
static void __exit me0900_exit(void)
{
PDEBUG("executed.\n.");
}
module_init(me0900_init);
module_exit(me0900_exit);
// Administrative stuff for modinfo.
MODULE_AUTHOR
("Guenter Gebhardt <g.gebhardt@meilhaus.de> & Krzysztof Gantzke <k.gantzke@meilhaus.de>");
MODULE_DESCRIPTION("Device Driver Module for ME-9x Device");
MODULE_SUPPORTED_DEVICE("Meilhaus ME-9x Devices");
MODULE_LICENSE("GPL");
// Export the constructor.
EXPORT_SYMBOL(me0900_pci_constructor);
/**
* @file me0900_device.h
*
* @brief ME-0900 (ME-9x) device class.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0900_DEVICE_H
#define _ME0900_DEVICE_H
#include <linux/pci.h>
#include <linux/spinlock.h>
#include "medevice.h"
#ifdef __KERNEL__
/**
* @brief Structure holding ME-0900 (ME-9x) device capabilities.
*/
typedef struct me0900_version {
uint16_t device_id;
unsigned int di_subdevices;
unsigned int do_subdevices;
} me0900_version_t;
/**
* @brief Device capabilities.
*/
static me0900_version_t me0900_versions[] = {
{PCI_DEVICE_ID_MEILHAUS_ME0940, 2, 0},
{PCI_DEVICE_ID_MEILHAUS_ME0950, 0, 2},
{PCI_DEVICE_ID_MEILHAUS_ME0960, 1, 1},
{0},
};
#define ME0900_DEVICE_VERSIONS (sizeof(me0900_versions) / sizeof(me0900_version_t) - 1) /**< Returns the number of entries in #me0900_versions. */
/**
* @brief Returns the index of the device entry in #me0900_versions.
*
* @param device_id The PCI device id of the device to query.
* @return The index of the device in #me0900_versions.
*/
static inline unsigned int me0900_versions_get_device_index(uint16_t device_id)
{
unsigned int i;
for (i = 0; i < ME0900_DEVICE_VERSIONS; i++)
if (me0900_versions[i].device_id == device_id)
break;
return i;
}
/**
* @brief The ME-0900 (ME-9x) device class structure.
*/
typedef struct me0900_device {
me_device_t base; /**< The Meilhaus device base class. */
} me0900_device_t;
/**
* @brief The ME-9x device class constructor.
*
* @param pci_device The pci device structure given by the PCI subsystem.
*
* @return On succes a new ME-0900 (ME-9x) device instance. \n
* NULL on error.
*/
me_device_t *me0900_pci_constructor(struct pci_dev *pci_device)
__attribute__ ((weak));
#endif
#endif
/**
* @file me0900_di.c
*
* @brief ME-9x digital input subdevice instance.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif
/*
* Includes
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <asm/io.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/version.h>
#include "medefines.h"
#include "meinternal.h"
#include "meerror.h"
#include "meids.h"
#include "medebug.h"
#include "meplx_reg.h"
#include "me0900_reg.h"
#include "me0900_di.h"
/*
* Defines
*/
/*
* Functions
*/
static int me0900_di_io_reset_subdevice(struct me_subdevice *subdevice,
struct file *filep, int flags)
{
PDEBUG("executed.\n");
if (flags) {
PERROR("Invalid flag specified.\n");
return ME_ERRNO_INVALID_FLAGS;
}
return ME_ERRNO_SUCCESS;
}
static int me0900_di_io_single_config(me_subdevice_t * subdevice,
struct file *filep,
int channel,
int single_config,
int ref,
int trig_chan,
int trig_type, int trig_edge, int flags)
{
me0900_di_subdevice_t *instance;
int err = ME_ERRNO_SUCCESS;
PDEBUG("executed.\n");
instance = (me0900_di_subdevice_t *) subdevice;
ME_SUBDEVICE_ENTER;
spin_lock(&instance->subdevice_lock);
switch (flags) {
case ME_IO_SINGLE_CONFIG_NO_FLAGS:
case ME_IO_SINGLE_TYPE_DIO_BYTE:
if (channel == 0) {
if (single_config == ME_SINGLE_CONFIG_DIO_INPUT) {
} else {
PERROR("Invalid byte direction specified.\n");
err = ME_ERRNO_INVALID_SINGLE_CONFIG;
}
} else {
PERROR("Invalid byte number specified.\n");
err = ME_ERRNO_INVALID_CHANNEL;
}
break;
default:
PERROR("Invalid flags specified.\n");
err = ME_ERRNO_INVALID_FLAGS;
}
spin_unlock(&instance->subdevice_lock);
ME_SUBDEVICE_EXIT;
return err;
}
static int me0900_di_io_single_read(me_subdevice_t * subdevice,
struct file *filep,
int channel,
int *value, int time_out, int flags)
{
me0900_di_subdevice_t *instance;
int err = ME_ERRNO_SUCCESS;
PDEBUG("executed.\n");
instance = (me0900_di_subdevice_t *) subdevice;
ME_SUBDEVICE_ENTER;
spin_lock(&instance->subdevice_lock);
switch (flags) {
case ME_IO_SINGLE_TYPE_DIO_BIT:
if ((channel >= 0) && (channel < 8)) {
*value = (~inb(instance->port_reg)) & (0x1 << channel);
} else {
PERROR("Invalid bit number specified.\n");
err = ME_ERRNO_INVALID_CHANNEL;
}
break;
case ME_IO_SINGLE_NO_FLAGS:
case ME_IO_SINGLE_TYPE_DIO_BYTE:
if (channel == 0) {
*value = ~inb(instance->port_reg);
} else {
PERROR("Invalid byte number specified.\n");
err = ME_ERRNO_INVALID_CHANNEL;
}
break;
default:
PERROR("Invalid flags specified.\n");
err = ME_ERRNO_INVALID_FLAGS;
}
spin_unlock(&instance->subdevice_lock);
ME_SUBDEVICE_EXIT;
return err;
}
static int me0900_di_query_number_channels(me_subdevice_t * subdevice,
int *number)
{
PDEBUG("executed.\n");
*number = 8;
return ME_ERRNO_SUCCESS;
}
static int me0900_di_query_subdevice_type(me_subdevice_t * subdevice,
int *type, int *subtype)
{
PDEBUG("executed.\n");
*type = ME_TYPE_DI;
*subtype = ME_SUBTYPE_SINGLE;
return ME_ERRNO_SUCCESS;
}
static int me0900_di_query_subdevice_caps(me_subdevice_t * subdevice, int *caps)
{
PDEBUG("executed.\n");
*caps = 0;
return ME_ERRNO_SUCCESS;
}
me0900_di_subdevice_t *me0900_di_constructor(uint32_t reg_base,
unsigned int di_idx)
{
me0900_di_subdevice_t *subdevice;
int err;
PDEBUG("executed.\n");
/* Allocate memory for subdevice instance */
subdevice = kmalloc(sizeof(me0900_di_subdevice_t), GFP_KERNEL);
if (!subdevice) {
PERROR("Cannot get memory for subdevice instance.\n");
return NULL;
}
memset(subdevice, 0, sizeof(me0900_di_subdevice_t));
/* Initialize subdevice base class */
err = me_subdevice_init(&subdevice->base);
if (err) {
PERROR("Cannot initialize subdevice base class instance.\n");
kfree(subdevice);
return NULL;
}
// Initialize spin locks.
spin_lock_init(&subdevice->subdevice_lock);
/* Save the subdevice index. */
subdevice->di_idx = di_idx;
/* Initialize registers */
if (di_idx == 0) {
subdevice->ctrl_reg = reg_base + ME0900_CTRL_REG;
subdevice->port_reg = reg_base + ME0900_PORT_A_REG;
} else {
subdevice->ctrl_reg = reg_base + ME0900_CTRL_REG;
subdevice->port_reg = reg_base + ME0900_PORT_B_REG;
}
#ifdef MEDEBUG_DEBUG_REG
subdevice->reg_base = reg_base;
#endif
/* Overload base class methods. */
subdevice->base.me_subdevice_io_reset_subdevice =
me0900_di_io_reset_subdevice;
subdevice->base.me_subdevice_io_single_config =
me0900_di_io_single_config;
subdevice->base.me_subdevice_io_single_read = me0900_di_io_single_read;
subdevice->base.me_subdevice_query_number_channels =
me0900_di_query_number_channels;
subdevice->base.me_subdevice_query_subdevice_type =
me0900_di_query_subdevice_type;
subdevice->base.me_subdevice_query_subdevice_caps =
me0900_di_query_subdevice_caps;
return subdevice;
}
/**
* @file me0900_di.h
*
* @brief ME-9x digital input subdevice class.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0900_DI_H_
#define _ME0900_DI_H_
#include "mesubdevice.h"
#ifdef __KERNEL__
/**
* @brief The template subdevice class.
*/
typedef struct me0900_di_subdevice {
/* Inheritance */
me_subdevice_t base; /**< The subdevice base class. */
/* Attributes */
spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */
unsigned int di_idx;
unsigned long ctrl_reg;
unsigned long port_reg;
#ifdef MEDEBUG_DEBUG_REG
unsigned long reg_base;
#endif
} me0900_di_subdevice_t;
/**
* @brief The constructor to generate a ME-9x digital input subdevice instance.
*
* @param reg_base The register base address of the device as returned by the PCI BIOS.
*
* @return Pointer to new instance on success.\n
* NULL on error.
*/
me0900_di_subdevice_t *me0900_di_constructor(uint32_t me0900_reg_base,
unsigned int di_idx);
#endif
#endif
/**
* @file me0900_do.c
*
* @brief ME-9x digital output subdevice instance.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif
/*
* Includes
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <asm/io.h>
#include <linux/types.h>
#include "medefines.h"
#include "meinternal.h"
#include "meerror.h"
#include "medebug.h"
#include "me0900_reg.h"
#include "me0900_do.h"
/*
* Defines
*/
/*
* Functions
*/
static int me0900_do_io_reset_subdevice(struct me_subdevice *subdevice,
struct file *filep, int flags)
{
me0900_do_subdevice_t *instance;
PDEBUG("executed.\n");
instance = (me0900_do_subdevice_t *) subdevice;
if (flags) {
PERROR("Invalid flag specified.\n");
return ME_ERRNO_INVALID_FLAGS;
}
ME_SUBDEVICE_ENTER;
spin_lock(&instance->subdevice_lock);
outb(0xFF, instance->port_reg);
PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
instance->port_reg - instance->reg_base, 0xff);
spin_unlock(&instance->subdevice_lock);
ME_SUBDEVICE_EXIT;
return ME_ERRNO_SUCCESS;
}
static int me0900_do_io_single_config(me_subdevice_t * subdevice,
struct file *filep,
int channel,
int single_config,
int ref,
int trig_chan,
int trig_type, int trig_edge, int flags)
{
me0900_do_subdevice_t *instance;
int err = ME_ERRNO_SUCCESS;
PDEBUG("executed.\n");
instance = (me0900_do_subdevice_t *) subdevice;
ME_SUBDEVICE_ENTER;
spin_lock(&instance->subdevice_lock);
switch (flags) {
case ME_IO_SINGLE_CONFIG_NO_FLAGS:
case ME_IO_SINGLE_TYPE_DIO_BYTE:
if (channel == 0) {
if (single_config == ME_SINGLE_CONFIG_DIO_OUTPUT) {
} else {
PERROR("Invalid byte direction specified.\n");
err = ME_ERRNO_INVALID_SINGLE_CONFIG;
}
} else {
PERROR("Invalid byte number specified.\n");
err = ME_ERRNO_INVALID_CHANNEL;
}
break;
default:
PERROR("Invalid flags specified.\n");
err = ME_ERRNO_INVALID_FLAGS;
}
spin_unlock(&instance->subdevice_lock);
ME_SUBDEVICE_EXIT;
return err;
}
static int me0900_do_io_single_read(me_subdevice_t * subdevice,
struct file *filep,
int channel,
int *value, int time_out, int flags)
{
me0900_do_subdevice_t *instance;
int err = ME_ERRNO_SUCCESS;
PDEBUG("executed.\n");
instance = (me0900_do_subdevice_t *) subdevice;
ME_SUBDEVICE_ENTER;
spin_lock(&instance->subdevice_lock);
switch (flags) {
case ME_IO_SINGLE_TYPE_DIO_BIT:
if ((channel >= 0) && (channel < 8)) {
*value = (~inb(instance->port_reg)) & (0x1 << channel);
} else {
PERROR("Invalid bit number specified.\n");
err = ME_ERRNO_INVALID_CHANNEL;
}
break;
case ME_IO_SINGLE_NO_FLAGS:
case ME_IO_SINGLE_TYPE_DIO_BYTE:
if (channel == 0) {
*value = ~inb(instance->port_reg);
} else {
PERROR("Invalid byte number specified.\n");
err = ME_ERRNO_INVALID_CHANNEL;
}
break;
default:
PERROR("Invalid flags specified.\n");
err = ME_ERRNO_INVALID_FLAGS;
}
spin_unlock(&instance->subdevice_lock);
ME_SUBDEVICE_EXIT;
return err;
}
static int me0900_do_io_single_write(me_subdevice_t * subdevice,
struct file *filep,
int channel,
int value, int time_out, int flags)
{
me0900_do_subdevice_t *instance;
int err = ME_ERRNO_SUCCESS;
unsigned long state;
PDEBUG("executed.\n");
instance = (me0900_do_subdevice_t *) subdevice;
ME_SUBDEVICE_ENTER;
spin_lock(&instance->subdevice_lock);
switch (flags) {
case ME_IO_SINGLE_TYPE_DIO_BIT:
if ((channel >= 0) && (channel < 8)) {
state = inb(instance->port_reg);
state =
(!value) ? (state | (0x1 << channel)) : (state &
~(0x1 <<
channel));
outb(state, instance->port_reg);
} else {
PERROR("Invalid bit number specified.\n");
err = ME_ERRNO_INVALID_CHANNEL;
}
break;
case ME_IO_SINGLE_NO_FLAGS:
case ME_IO_SINGLE_TYPE_DIO_BYTE:
if (channel == 0) {
outb(~(value), instance->port_reg);
} else {
PERROR("Invalid byte number specified.\n");
err = ME_ERRNO_INVALID_CHANNEL;
}
break;
default:
PERROR("Invalid flags specified.\n");
err = ME_ERRNO_INVALID_FLAGS;
}
spin_unlock(&instance->subdevice_lock);
ME_SUBDEVICE_EXIT;
return err;
}
static int me0900_do_query_number_channels(me_subdevice_t * subdevice,
int *number)
{
PDEBUG("executed.\n");
*number = 8;
return ME_ERRNO_SUCCESS;
}
static int me0900_do_query_subdevice_type(me_subdevice_t * subdevice,
int *type, int *subtype)
{
PDEBUG("executed.\n");
*type = ME_TYPE_DO;
*subtype = ME_SUBTYPE_SINGLE;
return ME_ERRNO_SUCCESS;
}
static int me0900_do_query_subdevice_caps(me_subdevice_t * subdevice, int *caps)
{
PDEBUG("executed.\n");
*caps = 0;
return ME_ERRNO_SUCCESS;
}
me0900_do_subdevice_t *me0900_do_constructor(uint32_t reg_base,
unsigned int do_idx)
{
me0900_do_subdevice_t *subdevice;
int err;
PDEBUG("executed.\n");
/* Allocate memory for subdevice instance */
subdevice = kmalloc(sizeof(me0900_do_subdevice_t), GFP_KERNEL);
if (!subdevice) {
PERROR("Cannot get memory for subdevice instance.\n");
return NULL;
}
memset(subdevice, 0, sizeof(me0900_do_subdevice_t));
/* Initialize subdevice base class */
err = me_subdevice_init(&subdevice->base);
if (err) {
PERROR("Cannot initialize subdevice base class instance.\n");
kfree(subdevice);
return NULL;
}
// Initialize spin locks.
spin_lock_init(&subdevice->subdevice_lock);
/* Save the subdevice index */
subdevice->do_idx = do_idx;
/* Initialize registers */
if (do_idx == 0) {
subdevice->ctrl_reg = reg_base + ME0900_CTRL_REG;
subdevice->port_reg = reg_base + ME0900_PORT_A_REG;
subdevice->enable_reg = reg_base + ME0900_WRITE_ENABLE_REG;
subdevice->disable_reg = reg_base + ME0900_WRITE_DISABLE_REG;
} else {
subdevice->ctrl_reg = reg_base + ME0900_CTRL_REG;
subdevice->port_reg = reg_base + ME0900_PORT_B_REG;
subdevice->enable_reg = reg_base + ME0900_WRITE_ENABLE_REG;
subdevice->disable_reg = reg_base + ME0900_WRITE_DISABLE_REG;
}
#ifdef MEDEBUG_DEBUG_REG
subdevice->reg_base = reg_base;
#endif
/* Overload base class methods. */
subdevice->base.me_subdevice_io_reset_subdevice =
me0900_do_io_reset_subdevice;
subdevice->base.me_subdevice_io_single_config =
me0900_do_io_single_config;
subdevice->base.me_subdevice_io_single_read = me0900_do_io_single_read;
subdevice->base.me_subdevice_io_single_write =
me0900_do_io_single_write;
subdevice->base.me_subdevice_query_number_channels =
me0900_do_query_number_channels;
subdevice->base.me_subdevice_query_subdevice_type =
me0900_do_query_subdevice_type;
subdevice->base.me_subdevice_query_subdevice_caps =
me0900_do_query_subdevice_caps;
return subdevice;
}
/**
* @file me0900_do.h
*
* @brief ME-9x digital output subdevice class.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0900_DO_H_
#define _ME0900_DO_H_
#include "mesubdevice.h"
#ifdef __KERNEL__
/**
* @brief The template subdevice class.
*/
typedef struct me0900_do_subdevice {
/* Inheritance */
me_subdevice_t base; /**< The subdevice base class. */
/* Attributes */
spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */
unsigned int do_idx;
unsigned long ctrl_reg;
unsigned long port_reg;
unsigned long enable_reg;
unsigned long disable_reg;
#ifdef MEDEBUG_DEBUG_REG
unsigned long reg_base;
#endif
} me0900_do_subdevice_t;
/**
* @brief The constructor to generate a ME-9x digital output subdevice instance.
*
* @param reg_base The register base address of the device as returned by the PCI BIOS.
* @param do_idx The index of the digital output subdevice on this device.
*
* @return Pointer to new instance on success.\n
* NULL on error.
*/
me0900_do_subdevice_t *me0900_do_constructor(uint32_t reg_base,
unsigned int do_idx);
#endif
#endif
/**
* @file me0900_reg.h
*
* @brief ME-9x register definitions.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0900_REG_H_
#define _ME0900_REG_H_
#ifdef __KERNEL__
#define ME0900_PORT_A_REG 0x00
#define ME0900_PORT_B_REG 0x01
#define ME0900_PORT_C_REG 0x02
#define ME0900_CTRL_REG 0x03 // ( ,w)
#define ME0900_WRITE_ENABLE_REG 0x04 // (r,w)
#define ME0900_WRITE_DISABLE_REG 0x08 // (r,w)
#endif
#endif
/**
* @file me1000_device.c
*
* @brief ME-1000 device class implementation.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
* @author Krzysztof Gantzke (k.gantzke@meilhaus.de)
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif
#ifndef MODULE
# define MODULE
#endif
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include "meids.h"
#include "meerror.h"
#include "mecommon.h"
#include "meinternal.h"
#include "medebug.h"
#include "medevice.h"
#include "me1000_device.h"
#include "mesubdevice.h"
#include "me1000_dio.h"
static int me1000_config_load(me_device_t * me_device, struct file *filep,
me_cfg_device_entry_t * config)
{
me1000_device_t *me1000_device;
me1000_dio_subdevice_t *dio;
PDEBUG("executed.\n");
me1000_device = (me1000_device_t *) me_device;
if (config->count == 2) {
if (me_slist_get_number_subdevices(&me1000_device->base.slist)
== 2) {
// Nothing to do.
} else {
// Remove 2 extra subdevices
dio =
(me1000_dio_subdevice_t *)
me_slist_del_subdevice_tail(&me1000_device->base.
slist);
if (dio)
dio->base.
me_subdevice_destructor((me_subdevice_t *)
dio);
dio =
(me1000_dio_subdevice_t *)
me_slist_del_subdevice_tail(&me1000_device->base.
slist);
if (dio)
dio->base.
me_subdevice_destructor((me_subdevice_t *)
dio);
}
} else if (config->count == 4) {
//Add 2 subdevices
if (me_slist_get_number_subdevices(&me1000_device->base.slist)
== 2) {
dio =
me1000_dio_constructor(me1000_device->base.info.pci.
reg_bases[2], 2,
&me1000_device->ctrl_lock);
if (!dio) {
PERROR("Cannot create dio subdevice.\n");
return ME_ERRNO_INTERNAL;
}
me_slist_add_subdevice_tail(&me1000_device->base.slist,
(me_subdevice_t *) dio);
dio =
me1000_dio_constructor(me1000_device->base.info.pci.
reg_bases[2], 3,
&me1000_device->ctrl_lock);
if (!dio) {
dio =
(me1000_dio_subdevice_t *)
me_slist_del_subdevice_tail(&me1000_device->
base.slist);
if (dio)
dio->base.
me_subdevice_destructor((me_subdevice_t *) dio);
PERROR("Cannot create dio subdevice.\n");
return ME_ERRNO_INTERNAL;
}
me_slist_add_subdevice_tail(&me1000_device->base.slist,
(me_subdevice_t *) dio);
} else {
// Nothing to do.
}
} else {
PERROR("Invalid configuration.\n");
return ME_ERRNO_INTERNAL;
}
return ME_ERRNO_SUCCESS;
}
me_device_t *me1000_pci_constructor(struct pci_dev * pci_device)
{
me1000_device_t *me1000_device;
me_subdevice_t *subdevice;
int err;
int i;
PDEBUG("executed.\n");
// Allocate structure for device instance.
me1000_device = kmalloc(sizeof(me1000_device_t), GFP_KERNEL);
if (!me1000_device) {
PERROR("Cannot get memory for ME-1000 device instance.\n");
return NULL;
}
memset(me1000_device, 0, sizeof(me1000_device_t));
// Initialize base class structure.
err = me_device_pci_init((me_device_t *) me1000_device, pci_device);
if (err) {
kfree(me1000_device);
PERROR("Cannot initialize device base class.\n");
return NULL;
}
// Initialize spin lock .
spin_lock_init(&me1000_device->ctrl_lock);
for (i = 0; i < 4; i++) {
subdevice =
(me_subdevice_t *) me1000_dio_constructor(me1000_device->
base.info.pci.
reg_bases[2], i,
&me1000_device->
ctrl_lock);
if (!subdevice) {
me_device_deinit((me_device_t *) me1000_device);
kfree(me1000_device);
PERROR("Cannot get memory for subdevice.\n");
return NULL;
}
me_slist_add_subdevice_tail(&me1000_device->base.slist,
subdevice);
}
// Overwrite base class methods.
me1000_device->base.me_device_config_load = me1000_config_load;
return (me_device_t *) me1000_device;
}
// Init and exit of module.
static int __init me1000_init(void)
{
PDEBUG("executed.\n");
return 0;
}
static void __exit me1000_exit(void)
{
PDEBUG("executed.\n");
}
module_init(me1000_init);
module_exit(me1000_exit);
// Administrative stuff for modinfo.
MODULE_AUTHOR
("Guenter Gebhardt <g.gebhardt@meilhaus.de> & Krzysztof Gantzke <k.gantzke@meilhaus.de>");
MODULE_DESCRIPTION("Device Driver Module for Meilhaus ME-1000 Devices");
MODULE_SUPPORTED_DEVICE("Meilhaus ME-1000 Digital I/O Devices");
MODULE_LICENSE("GPL");
// Export the constructor.
EXPORT_SYMBOL(me1000_pci_constructor);
/**
* @file me1000_device.h
*
* @brief ME-1000 device class instance.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME1000_H_
#define _ME1000_H_
#include <linux/pci.h>
#include <linux/spinlock.h>
#include "medevice.h"
#ifdef __KERNEL__
#define ME1000_MAGIC_NUMBER 1000
/**
* @brief The ME-1000 device class structure.
*/
typedef struct me1000_device {
me_device_t base; /**< The Meilhaus device base class. */
spinlock_t ctrl_lock; /**< Guards the DIO mode register. */
} me1000_device_t;
/**
* @brief The ME-1000 device class constructor.
*
* @param pci_device The pci device structure given by the PCI subsystem.
*
* @return On succes a new ME-1000 device instance. \n
* NULL on error.
*/
me_device_t *me1000_pci_constructor(struct pci_dev *pci_device)
__attribute__ ((weak));
#endif
#endif
This diff is collapsed.
/**
* @file me1000_dio.h
*
* @brief Meilhaus ME-1000 digital i/o implementation.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME1000_DIO_H_
#define _ME1000_DIO_H_
#include "mesubdevice.h"
#include "meslock.h"
#ifdef __KERNEL__
/**
* @brief The ME-1000 DIO subdevice class.
*/
typedef struct me1000_dio_subdevice {
/* Inheritance */
me_subdevice_t base; /**< The subdevice base class. */
/* Attributes */
// uint32_t magic; /**< The magic number unique for this structure. */
spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */
spinlock_t *ctrl_reg_lock; /**< Spin lock to protect #ctrl_reg and #ctrl_reg_mirror from concurrent access. */
int dio_idx; /**< The index of the DIO port on the device. */
unsigned long port_reg; /**< Register to read or write a value from or to the port respectively. */
unsigned long ctrl_reg; /**< Register to configure the DIO modes. */
#ifdef MEDEBUG_DEBUG_REG
unsigned long reg_base;
#endif
} me1000_dio_subdevice_t;
/**
* @brief The constructor to generate a ME-1000 DIO instance.
*
* @param reg_base The register base address of the device as returned by the PCI BIOS.
* @param dio_idx The index of the DIO on the device.
* @param ctrl_reg_lock Pointer to spin lock protecting the control register and from concurrent access.
*
* @return Pointer to new instance on success.\n
* NULL on error.
*/
me1000_dio_subdevice_t *me1000_dio_constructor(uint32_t reg_base,
unsigned int dio_idx,
spinlock_t * ctrl_reg_lock);
#endif
#endif
/**
* @file me1000_dio_reg.h
*
* @brief ME-1000 digital i/o register definitions.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
* @author Krzysztof Gantzke (k.gantzke@meilhaus.de)
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME1000_DIO_REG_H_
# define _ME1000_DIO_REG_H_
# ifdef __KERNEL__
# define ME1000_DIO_NUMBER_CHANNELS 32 /**< The number of channels per DIO port. */
# define ME1000_DIO_NUMBER_PORTS 4 /**< The number of ports per ME-1000. */
// # define ME1000_PORT_A 0x0000 /**< Port A base register offset. */
// # define ME1000_PORT_B 0x0004 /**< Port B base register offset. */
// # define ME1000_PORT_C 0x0008 /**< Port C base register offset. */
// # define ME1000_PORT_D 0x000C /**< Port D base register offset. */
# define ME1000_PORT 0x0000 /**< Base for port's register. */
# define ME1000_PORT_STEP 4 /**< Distance between port's register. */
# define ME1000_PORT_MODE 0x0010 /**< Configuration register to switch the port direction. */
// # define ME1000_PORT_MODE_OUTPUT_A (1 << 0) /**< If set, port A is in output, otherwise in input mode. */
// # define ME1000_PORT_MODE_OUTPUT_B (1 << 1) /**< If set, port B is in output, otherwise in input mode. */
// # define ME1000_PORT_MODE_OUTPUT_C (1 << 2) /**< If set, port C is in output, otherwise in input mode. */
// # define ME1000_PORT_MODE_OUTPUT_D (1 << 3) /**< If set, port D is in output, otherwise in input mode. */
# endif //__KERNEL__
#endif //_ME1000_DIO_REG_H_
/**
* @file me1400_device.c
*
* @brief ME-1400 device instance.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
* @author Krzysztof Gantzke (k.gantzke@meilhaus.de)
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* User application could also include the kernel header files. But the
* real kernel functions are protected by #ifdef __KERNEL__.
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif
/*
* This must be defined before module.h is included. Not needed, when
* it is a built in driver.
*/
#ifndef MODULE
# define MODULE
#endif
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/version.h>
#include "meids.h"
#include "meerror.h"
#include "mecommon.h"
#include "meinternal.h"
#include "medebug.h"
#include "me1400_device.h"
#include "me8254.h"
#include "me8254_reg.h"
#include "me8255.h"
#include "me1400_ext_irq.h"
me_device_t *me1400_pci_constructor(struct pci_dev *pci_device)
{
int err;
me1400_device_t *me1400_device;
me_subdevice_t *subdevice;
unsigned int version_idx;
unsigned int me8255_idx;
unsigned int dio_idx;
unsigned int me8254_idx;
unsigned int ctr_idx;
unsigned int ext_irq_idx;
PDEBUG("executed.\n");
// Allocate structure for device instance.
me1400_device = kmalloc(sizeof(me1400_device_t), GFP_KERNEL);
if (!me1400_device) {
PERROR("Cannot get memory for 1400ate device instance.\n");
return NULL;
}
memset(me1400_device, 0, sizeof(me1400_device_t));
// Initialize base class structure.
err = me_device_pci_init((me_device_t *) me1400_device, pci_device);
if (err) {
kfree(me1400_device);
PERROR("Cannot initialize device base class.\n");
return NULL;
}
/* Check for ME1400 extension device. If detected we fake a ME-1400 D device id. */
if (me1400_device->base.info.pci.device_id ==
PCI_DEVICE_ID_MEILHAUS_ME140C) {
uint8_t ctrl;
ctrl =
inb(me1400_device->base.info.pci.reg_bases[2] +
ME1400D_CLK_SRC_2_REG);
PDEBUG_REG("xxx_reg inb(0x%X+0x%X)=0x%x\n",
me1400_device->base.info.pci.reg_bases[2],
ME1400D_CLK_SRC_2_REG, ctrl);
outb(ctrl | 0xF0,
me1400_device->base.info.pci.reg_bases[2] +
ME1400D_CLK_SRC_2_REG);
PDEBUG_REG("xxx_reg outb(0x%X+0x%X)=0x%x\n",
me1400_device->base.info.pci.reg_bases[2],
ME1400D_CLK_SRC_2_REG, ctrl | 0xF0);
ctrl =
inb(me1400_device->base.info.pci.reg_bases[2] +
ME1400D_CLK_SRC_2_REG);
PDEBUG_REG("xxx_reg inb(0x%X+0x%X)=0x%x\n",
me1400_device->base.info.pci.reg_bases[2],
ME1400D_CLK_SRC_2_REG, ctrl);
if ((ctrl & 0xF0) == 0xF0) {
PINFO("ME1400 D detected.\n");
me1400_device->base.info.pci.device_id =
PCI_DEVICE_ID_MEILHAUS_ME140D;
}
}
/* Initialize global stuff of digital i/o subdevices. */
for (me8255_idx = 0; me8255_idx < ME1400_MAX_8255; me8255_idx++) {
me1400_device->dio_current_mode[me8255_idx] = 0;
spin_lock_init(&me1400_device->dio_ctrl_reg_lock[me8255_idx]);
}
/* Initialize global stuff of counter subdevices. */
spin_lock_init(&me1400_device->clk_src_reg_lock);
for (me8254_idx = 0; me8254_idx < ME1400_MAX_8254; me8254_idx++)
spin_lock_init(&me1400_device->ctr_ctrl_reg_lock[me8254_idx]);
/* Get the index in the device version information table. */
version_idx =
me1400_versions_get_device_index(me1400_device->base.info.pci.
device_id);
/* Generate DIO subdevice instances. */
for (me8255_idx = 0;
me8255_idx < me1400_versions[version_idx].dio_chips;
me8255_idx++) {
for (dio_idx = 0; dio_idx < 3; dio_idx++) {
subdevice =
(me_subdevice_t *)
me8255_constructor(me1400_versions[version_idx].
device_id,
me1400_device->base.info.pci.
reg_bases[2], me8255_idx,
dio_idx,
&me1400_device->
dio_current_mode[me8255_idx],
&me1400_device->
dio_ctrl_reg_lock[me8255_idx]);
if (!subdevice) {
me_device_deinit((me_device_t *) me1400_device);
kfree(me1400_device);
PERROR("Cannot get memory for subdevice.\n");
return NULL;
}
me_slist_add_subdevice_tail(&me1400_device->base.slist,
subdevice);
}
}
/* Generate counter subdevice instances. */
for (me8254_idx = 0;
me8254_idx < me1400_versions[version_idx].ctr_chips;
me8254_idx++) {
for (ctr_idx = 0; ctr_idx < 3; ctr_idx++) {
subdevice =
(me_subdevice_t *)
me8254_constructor(me1400_device->base.info.pci.
device_id,
me1400_device->base.info.pci.
reg_bases[2], me8254_idx,
ctr_idx,
&me1400_device->
ctr_ctrl_reg_lock[me8254_idx],
&me1400_device->
clk_src_reg_lock);
if (!subdevice) {
me_device_deinit((me_device_t *) me1400_device);
kfree(me1400_device);
PERROR("Cannot get memory for subdevice.\n");
return NULL;
}
me_slist_add_subdevice_tail(&me1400_device->base.slist,
subdevice);
}
}
/* Generate external interrupt subdevice instances. */
for (ext_irq_idx = 0;
ext_irq_idx < me1400_versions[version_idx].ext_irq_subdevices;
ext_irq_idx++) {
subdevice =
(me_subdevice_t *)
me1400_ext_irq_constructor(me1400_device->base.info.pci.
device_id,
me1400_device->base.info.pci.
reg_bases[1],
me1400_device->base.info.pci.
reg_bases[2],
&me1400_device->clk_src_reg_lock,
me1400_device->base.irq);
if (!subdevice) {
me_device_deinit((me_device_t *) me1400_device);
kfree(me1400_device);
PERROR("Cannot get memory for subdevice.\n");
return NULL;
}
me_slist_add_subdevice_tail(&me1400_device->base.slist,
subdevice);
}
return (me_device_t *) me1400_device;
}
// Init and exit of module.
static int __init me1400_init(void)
{
PDEBUG("executed.\n");
return 0;
}
static void __exit me1400_exit(void)
{
PDEBUG("executed.\n");
}
module_init(me1400_init);
module_exit(me1400_exit);
// Administrative stuff for modinfo.
MODULE_AUTHOR
("Guenter Gebhardt <g.gebhardt@meilhaus.de> & Krzysztof Gantzke <k.gantzke@meilhaus.de>");
MODULE_DESCRIPTION("Device Driver Module for Meilhaus ME-14xx devices");
MODULE_SUPPORTED_DEVICE("Meilhaus ME-14xx MIO devices");
MODULE_LICENSE("GPL");
// Export the constructor.
EXPORT_SYMBOL(me1400_pci_constructor);
/**
* @file me1400_device.c
*
* @brief ME-1400 device family instance.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME1400_DEVICE_H_
#define _ME1400_DEVICE_H_
#include "metypes.h"
#include "medefines.h"
#include "meinternal.h"
#include "medevice.h"
#ifdef __KERNEL__
/**
* @brief Structure to store device capabilities.
*/
typedef struct me1400_version {
uint16_t device_id; /**< The PCI device id of the device. */
unsigned int dio_chips; /**< The number of 8255 chips on the device. */
unsigned int ctr_chips; /**< The number of 8254 chips on the device. */
unsigned int ext_irq_subdevices; /**< The number of external interrupt inputs on the device. */
} me1400_version_t;
/**
* @brief Defines for each ME-1400 device version its capabilities.
*/
static me1400_version_t me1400_versions[] = {
{PCI_DEVICE_ID_MEILHAUS_ME1400, 1, 0, 0},
{PCI_DEVICE_ID_MEILHAUS_ME140A, 1, 1, 1},
{PCI_DEVICE_ID_MEILHAUS_ME140B, 2, 2, 1},
{PCI_DEVICE_ID_MEILHAUS_ME14E0, 1, 0, 0},
{PCI_DEVICE_ID_MEILHAUS_ME14EA, 1, 1, 1},
{PCI_DEVICE_ID_MEILHAUS_ME14EB, 2, 2, 1},
{PCI_DEVICE_ID_MEILHAUS_ME140C, 1, 5, 1},
{PCI_DEVICE_ID_MEILHAUS_ME140D, 2, 10, 1},
{0}
};
#define ME1400_DEVICE_VERSIONS (sizeof(me1400_versions) / sizeof(me1400_version_t) - 1) /**< Returns the number of entries in #me1400_versions. */
/**
* @brief Returns the index of the device entry in #me1400_versions.
*
* @param device_id The PCI device id of the device to query.
* @return The index of the device in #me1400_versions.
*/
static inline unsigned int me1400_versions_get_device_index(uint16_t device_id)
{
unsigned int i;
for (i = 0; i < ME1400_DEVICE_VERSIONS; i++)
if (me1400_versions[i].device_id == device_id)
break;
return i;
}
#define ME1400_MAX_8254 10 /**< The maximum number of 8254 counter subdevices available on any ME-1400 device. */
#define ME1400_MAX_8255 2 /**< The maximum number of 8255 digital i/o subdevices available on any ME-1400 device. */
/**
* @brief The ME-1400 device class.
*/
typedef struct me1400_device {
me_device_t base; /**< The Meilhaus device base class. */
spinlock_t clk_src_reg_lock; /**< Guards the 8254 clock source registers. */
spinlock_t ctr_ctrl_reg_lock[ME1400_MAX_8254]; /**< Guards the 8254 ctrl registers. */
int dio_current_mode[ME1400_MAX_8255]; /**< Saves the current mode setting of a single 8255 DIO chip. */
spinlock_t dio_ctrl_reg_lock[ME1400_MAX_8255]; /**< Guards the 8255 ctrl register and #dio_current_mode. */
} me1400_device_t;
/**
* @brief The ME-1400 device class constructor.
*
* @param pci_device The pci device structure given by the PCI subsystem.
*
* @return On succes a new ME-1400 device instance. \n
* NULL on error.
*/
me_device_t *me1400_pci_constructor(struct pci_dev *pci_device)
__attribute__ ((weak));
#endif
#endif
This diff is collapsed.
/**
* @file me1400_ext_irq.h
*
* @brief ME-1400 external interrupt implementation.
* @note Copyright (C) 2006 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
#ifndef _ME1400_EXT_IRQ_H_
#define _ME1400_EXT_IRQ_H_
#include <linux/sched.h>
#include "mesubdevice.h"
#include "meslock.h"
#ifdef __KERNEL__
/**
* @brief The ME-1400 external interrupt subdevice class.
*/
typedef struct me1400_ext_irq_subdevice {
/* Inheritance */
me_subdevice_t base; /**< The subdevice base class. */
/* Attributes */
spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */
spinlock_t *clk_src_reg_lock; /**< Lock protecting the clock control register. */
wait_queue_head_t wait_queue; /**< Queue to put on threads waiting for an interrupt. */
uint32_t device_id; /**< The device id of the device holding the subdevice. */
int irq; /**< The irq number assigned by PCI BIOS. */
int rised; /**< If true an interrupt has occured. */
unsigned int n; /**< The number of interrupt since the driver was loaded. */
unsigned long plx_intcs_reg; /**< The PLX interrupt control and status register. */
unsigned long ctrl_reg; /**< The control register. */
#ifdef MEDEBUG_DEBUG_REG
unsigned long reg_base;
#endif
} me1400_ext_irq_subdevice_t;
/**
* @brief The constructor to generate a ME-1400 external interrupt instance.
*
* @param plx_reg_base The register base address of the PLX chip as returned by the PCI BIOS.
* @param me1400_reg_base The register base address of the ME-1400 device as returned by the PCI BIOS.
* @param irq The irq assigned by the PCI BIOS.
*
* @return Pointer to new instance on success.\n
* NULL on error.
*/
me1400_ext_irq_subdevice_t *me1400_ext_irq_constructor(uint32_t device_id,
uint32_t plx_reg_base,
uint32_t me1400_reg_base,
spinlock_t *
clk_src_reg_lock,
int irq);
#endif
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment