Staging: meilhaus: remove the drivers
The comedi drivers should be used instead, no need to have these in here as well. Cc: David Kiliani <mail@davidkiliani.de> Cc: Meilhaus Support <support@meilhaus.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
06bf27ddaa
commit
a8fcffbde4
|
@ -47,8 +47,6 @@ source "drivers/staging/slicoss/Kconfig"
|
|||
|
||||
source "drivers/staging/sxg/Kconfig"
|
||||
|
||||
source "drivers/staging/meilhaus/Kconfig"
|
||||
|
||||
source "drivers/staging/go7007/Kconfig"
|
||||
|
||||
source "drivers/staging/usbip/Kconfig"
|
||||
|
|
|
@ -6,7 +6,6 @@ obj-$(CONFIG_STAGING) += staging.o
|
|||
obj-$(CONFIG_ET131X) += et131x/
|
||||
obj-$(CONFIG_SLICOSS) += slicoss/
|
||||
obj-$(CONFIG_SXG) += sxg/
|
||||
obj-$(CONFIG_MEILHAUS) += meilhaus/
|
||||
obj-$(CONFIG_VIDEO_GO7007) += go7007/
|
||||
obj-$(CONFIG_USB_IP_COMMON) += usbip/
|
||||
obj-$(CONFIG_W35UND) += winbond/
|
||||
|
|
|
@ -1,128 +0,0 @@
|
|||
#
|
||||
# Meilhaus configuration
|
||||
#
|
||||
|
||||
menuconfig MEILHAUS
|
||||
tristate "Meilhaus support"
|
||||
depends on m
|
||||
---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 && m
|
||||
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 && m
|
||||
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 && m
|
||||
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 && m
|
||||
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 && m
|
||||
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 && m
|
||||
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 && m
|
||||
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 && m
|
||||
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 && m
|
||||
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 && m
|
||||
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
|
|
@ -1,43 +0,0 @@
|
|||
#
|
||||
# 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
|
|
@ -1,10 +0,0 @@
|
|||
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> and Meilhaus Support <support@meilhaus.de>
|
|
@ -1,213 +0,0 @@
|
|||
/**
|
||||
* @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;
|
||||
}
|
||||
EXPORT_SYMBOL(me0600_pci_constructor);
|
||||
|
||||
// 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");
|
|
@ -1,97 +0,0 @@
|
|||
/**
|
||||
* @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 (ARRAY_SIZE(me0600_versions) - 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
|
|
@ -1,415 +0,0 @@
|
|||
/**
|
||||
* @file me0600_dio.c
|
||||
*
|
||||
* @brief ME-630 digital input/output 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 <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "medefines.h"
|
||||
#include "meinternal.h"
|
||||
#include "meerror.h"
|
||||
|
||||
#include "medebug.h"
|
||||
#include "me0600_dio_reg.h"
|
||||
#include "me0600_dio.h"
|
||||
|
||||
/*
|
||||
* Defines
|
||||
*/
|
||||
|
||||
/*
|
||||
* Functions
|
||||
*/
|
||||
|
||||
static int me0600_dio_io_reset_subdevice(struct me_subdevice *subdevice,
|
||||
struct file *filep, int flags)
|
||||
{
|
||||
me0600_dio_subdevice_t *instance;
|
||||
uint8_t mode;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me0600_dio_subdevice_t *) subdevice;
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
mode = inb(instance->ctrl_reg);
|
||||
mode &= ~(0x3 << (instance->dio_idx * 2));
|
||||
outb(mode, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, mode);
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
|
||||
outb(0x00, instance->port_reg);
|
||||
PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->port_reg - instance->reg_base, 0x00);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me0600_dio_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_dio_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
uint8_t mode;
|
||||
int size =
|
||||
flags & (ME_IO_SINGLE_CONFIG_DIO_BIT | ME_IO_SINGLE_CONFIG_DIO_BYTE
|
||||
| ME_IO_SINGLE_CONFIG_DIO_WORD |
|
||||
ME_IO_SINGLE_CONFIG_DIO_DWORD);
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me0600_dio_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
mode = inb(instance->ctrl_reg);
|
||||
switch (size) {
|
||||
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) {
|
||||
mode &=
|
||||
~((ME0600_DIO_CONFIG_BIT_OUT_0) <<
|
||||
(instance->dio_idx * 2));
|
||||
} else if (single_config == ME_SINGLE_CONFIG_DIO_OUTPUT) {
|
||||
mode &=
|
||||
~((ME0600_DIO_CONFIG_BIT_OUT_0) <<
|
||||
(instance->dio_idx * 2));
|
||||
mode |=
|
||||
ME0600_DIO_CONFIG_BIT_OUT_0 << (instance->
|
||||
dio_idx *
|
||||
2);
|
||||
} else {
|
||||
PERROR
|
||||
("Invalid port configuration specified.\n");
|
||||
err = ME_ERRNO_INVALID_SINGLE_CONFIG;
|
||||
}
|
||||
} else {
|
||||
PERROR("Invalid channel number.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
PERROR("Invalid flags.\n");
|
||||
err = ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
outb(mode, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, mode);
|
||||
}
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me0600_dio_io_single_read(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int *value, int time_out, int flags)
|
||||
{
|
||||
me0600_dio_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
uint8_t mode;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me0600_dio_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
switch (flags) {
|
||||
case ME_IO_SINGLE_TYPE_DIO_BIT:
|
||||
if ((channel >= 0) && (channel < 8)) {
|
||||
mode =
|
||||
inb(instance->
|
||||
ctrl_reg) & ((ME0600_DIO_CONFIG_BIT_OUT_0) <<
|
||||
(instance->dio_idx * 2));
|
||||
|
||||
if ((mode ==
|
||||
(ME0600_DIO_CONFIG_BIT_OUT_0 <<
|
||||
(instance->dio_idx * 2))) || !mode) {
|
||||
*value =
|
||||
inb(instance->
|
||||
port_reg) & (0x0001 << channel);
|
||||
} else {
|
||||
PERROR("Port not in output or input mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_CONFIG;
|
||||
}
|
||||
} 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) {
|
||||
mode =
|
||||
inb(instance->
|
||||
ctrl_reg) & ((ME0600_DIO_CONFIG_BIT_OUT_0) <<
|
||||
(instance->dio_idx * 2));
|
||||
|
||||
if ((mode ==
|
||||
(ME0600_DIO_CONFIG_BIT_OUT_0 <<
|
||||
(instance->dio_idx * 2))) || !mode) {
|
||||
*value = inb(instance->port_reg) & 0x00FF;
|
||||
} else {
|
||||
PERROR("Port not in output or input mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_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;
|
||||
|
||||
break;
|
||||
}
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me0600_dio_io_single_write(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int value, int time_out, int flags)
|
||||
{
|
||||
me0600_dio_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
uint8_t mode;
|
||||
uint8_t byte;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me0600_dio_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
switch (flags) {
|
||||
|
||||
case ME_IO_SINGLE_TYPE_DIO_BIT:
|
||||
if ((channel >= 0) && (channel < 8)) {
|
||||
mode =
|
||||
inb(instance->
|
||||
ctrl_reg) & ((ME0600_DIO_CONFIG_BIT_OUT_0) <<
|
||||
(instance->dio_idx * 2));
|
||||
|
||||
if (mode ==
|
||||
(ME0600_DIO_CONFIG_BIT_OUT_0 <<
|
||||
(instance->dio_idx * 2))) {
|
||||
byte = inb(instance->port_reg);
|
||||
|
||||
if (value)
|
||||
byte |= 0x1 << channel;
|
||||
else
|
||||
byte &= ~(0x1 << channel);
|
||||
|
||||
outb(byte, instance->port_reg);
|
||||
} else {
|
||||
PERROR("Port not in output or input mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_CONFIG;
|
||||
}
|
||||
} 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) {
|
||||
mode =
|
||||
inb(instance->
|
||||
ctrl_reg) & ((ME0600_DIO_CONFIG_BIT_OUT_0) <<
|
||||
(instance->dio_idx * 2));
|
||||
|
||||
if (mode ==
|
||||
(ME0600_DIO_CONFIG_BIT_OUT_0 <<
|
||||
(instance->dio_idx * 2))) {
|
||||
outb(value, instance->port_reg);
|
||||
} else {
|
||||
PERROR("Port not in output or input mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_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;
|
||||
|
||||
break;
|
||||
}
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me0600_dio_query_number_channels(me_subdevice_t *subdevice,
|
||||
int *number)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*number = 8;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me0600_dio_query_subdevice_type(me_subdevice_t *subdevice,
|
||||
int *type, int *subtype)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*type = ME_TYPE_DIO;
|
||||
*subtype = ME_SUBTYPE_SINGLE;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me0600_dio_query_subdevice_caps(me_subdevice_t *subdevice,
|
||||
int *caps)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*caps = ME_CAPS_DIO_DIR_BYTE;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
me0600_dio_subdevice_t *me0600_dio_constructor(uint32_t reg_base,
|
||||
unsigned int dio_idx,
|
||||
spinlock_t *ctrl_reg_lock)
|
||||
{
|
||||
me0600_dio_subdevice_t *subdevice;
|
||||
int err;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
/* Allocate memory for subdevice instance */
|
||||
subdevice = kmalloc(sizeof(me0600_dio_subdevice_t), GFP_KERNEL);
|
||||
|
||||
if (!subdevice) {
|
||||
PERROR("Cannot get memory for subdevice instance.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(subdevice, 0, sizeof(me0600_dio_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);
|
||||
|
||||
subdevice->ctrl_reg_lock = ctrl_reg_lock;
|
||||
|
||||
/* Save digital i/o index */
|
||||
subdevice->dio_idx = dio_idx;
|
||||
|
||||
/* Save the subdevice index */
|
||||
subdevice->ctrl_reg = reg_base + ME0600_DIO_CONFIG_REG;
|
||||
subdevice->port_reg = reg_base + ME0600_DIO_PORT_REG + dio_idx;
|
||||
#ifdef MEDEBUG_DEBUG_REG
|
||||
subdevice->reg_base = reg_base;
|
||||
#endif
|
||||
|
||||
/* Overload base class methods. */
|
||||
subdevice->base.me_subdevice_io_reset_subdevice =
|
||||
me0600_dio_io_reset_subdevice;
|
||||
subdevice->base.me_subdevice_io_single_config =
|
||||
me0600_dio_io_single_config;
|
||||
subdevice->base.me_subdevice_io_single_read = me0600_dio_io_single_read;
|
||||
subdevice->base.me_subdevice_io_single_write =
|
||||
me0600_dio_io_single_write;
|
||||
subdevice->base.me_subdevice_query_number_channels =
|
||||
me0600_dio_query_number_channels;
|
||||
subdevice->base.me_subdevice_query_subdevice_type =
|
||||
me0600_dio_query_subdevice_type;
|
||||
subdevice->base.me_subdevice_query_subdevice_caps =
|
||||
me0600_dio_query_subdevice_caps;
|
||||
|
||||
return subdevice;
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
/**
|
||||
* @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
|
|
@ -1,41 +0,0 @@
|
|||
/**
|
||||
* @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
|
|
@ -1,469 +0,0 @@
|
|||
/**
|
||||
* @file me0600_ext_irq.c
|
||||
*
|
||||
* @brief ME-630 external interrupt 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 <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "medefines.h"
|
||||
#include "meinternal.h"
|
||||
#include "meerror.h"
|
||||
#include "meids.h"
|
||||
#include "medebug.h"
|
||||
|
||||
#include "meplx_reg.h"
|
||||
#include "me0600_ext_irq_reg.h"
|
||||
#include "me0600_ext_irq.h"
|
||||
|
||||
/*
|
||||
* Functions
|
||||
*/
|
||||
|
||||
static int me0600_ext_irq_io_irq_start(struct me_subdevice *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int irq_source,
|
||||
int irq_edge, int irq_arg, int flags)
|
||||
{
|
||||
me0600_ext_irq_subdevice_t *instance;
|
||||
uint32_t tmp;
|
||||
unsigned long cpu_flags;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me0600_ext_irq_subdevice_t *) subdevice;
|
||||
|
||||
if (flags & ~ME_IO_IRQ_START_DIO_BIT) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (instance->lintno > 1) {
|
||||
PERROR("Wrong idx=%d.\n", instance->lintno);
|
||||
return ME_ERRNO_INVALID_SUBDEVICE;
|
||||
}
|
||||
|
||||
if (channel) {
|
||||
PERROR("Invalid channel specified.\n");
|
||||
return ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
|
||||
if (irq_source != ME_IRQ_SOURCE_DIO_LINE) {
|
||||
PERROR("Invalid irq source specified.\n");
|
||||
return ME_ERRNO_INVALID_IRQ_SOURCE;
|
||||
}
|
||||
|
||||
if (irq_edge != ME_IRQ_EDGE_RISING) {
|
||||
PERROR("Invalid irq edge specified.\n");
|
||||
return ME_ERRNO_INVALID_IRQ_EDGE;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
|
||||
spin_lock(instance->intcsr_lock);
|
||||
tmp = inl(instance->intcsr);
|
||||
switch (instance->lintno) {
|
||||
case 0:
|
||||
tmp |=
|
||||
PLX_INTCSR_LOCAL_INT1_EN | PLX_INTCSR_LOCAL_INT1_POL |
|
||||
PLX_INTCSR_PCI_INT_EN;
|
||||
break;
|
||||
case 1:
|
||||
tmp |=
|
||||
PLX_INTCSR_LOCAL_INT2_EN | PLX_INTCSR_LOCAL_INT2_POL |
|
||||
PLX_INTCSR_PCI_INT_EN;
|
||||
break;
|
||||
}
|
||||
outl(tmp, instance->intcsr);
|
||||
PDEBUG_REG("intcsr outl(plx:0x%X)=0x%x\n", instance->intcsr, tmp);
|
||||
spin_unlock(instance->intcsr_lock);
|
||||
instance->rised = 0;
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me0600_ext_irq_io_irq_wait(struct me_subdevice *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int *irq_count,
|
||||
int *value, int time_out, int flags)
|
||||
{
|
||||
me0600_ext_irq_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
long t = 0;
|
||||
unsigned long cpu_flags;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me0600_ext_irq_subdevice_t *) subdevice;
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (channel) {
|
||||
PERROR("Invalid channel specified.\n");
|
||||
return ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
|
||||
if (time_out < 0) {
|
||||
PERROR("Invalid time_out specified.\n");
|
||||
return ME_ERRNO_INVALID_TIMEOUT;
|
||||
}
|
||||
|
||||
if (time_out) {
|
||||
t = (time_out * HZ) / 1000;
|
||||
|
||||
if (t == 0)
|
||||
t = 1;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
if (instance->rised <= 0) {
|
||||
instance->rised = 0;
|
||||
|
||||
if (time_out) {
|
||||
t = wait_event_interruptible_timeout(instance->
|
||||
wait_queue,
|
||||
(instance->rised !=
|
||||
0), t);
|
||||
|
||||
if (t == 0) {
|
||||
PERROR("Wait on interrupt timed out.\n");
|
||||
err = ME_ERRNO_TIMEOUT;
|
||||
}
|
||||
} else {
|
||||
wait_event_interruptible(instance->wait_queue,
|
||||
(instance->rised != 0));
|
||||
}
|
||||
|
||||
if (instance->rised < 0) {
|
||||
PERROR("Wait on interrupt aborted by user.\n");
|
||||
err = ME_ERRNO_CANCELLED;
|
||||
}
|
||||
}
|
||||
|
||||
if (signal_pending(current)) {
|
||||
PERROR("Wait on interrupt aborted by signal.\n");
|
||||
err = ME_ERRNO_SIGNAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
|
||||
instance->rised = 0;
|
||||
*irq_count = instance->n;
|
||||
*value = 1;
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me0600_ext_irq_io_irq_stop(struct me_subdevice *subdevice,
|
||||
struct file *filep,
|
||||
int channel, int flags)
|
||||
{
|
||||
me0600_ext_irq_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
uint32_t tmp;
|
||||
unsigned long cpu_flags;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me0600_ext_irq_subdevice_t *) subdevice;
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (instance->lintno > 1) {
|
||||
PERROR("Wrong idx=%d.\n", instance->lintno);
|
||||
return ME_ERRNO_INVALID_SUBDEVICE;
|
||||
}
|
||||
|
||||
if (channel) {
|
||||
PERROR("Invalid channel specified.\n");
|
||||
return ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
|
||||
spin_lock(instance->intcsr_lock);
|
||||
tmp = inl(instance->intcsr);
|
||||
switch (instance->lintno) {
|
||||
case 0:
|
||||
tmp &= ~PLX_INTCSR_LOCAL_INT1_EN;
|
||||
break;
|
||||
case 1:
|
||||
tmp &= ~PLX_INTCSR_LOCAL_INT2_EN;
|
||||
break;
|
||||
}
|
||||
outl(tmp, instance->intcsr);
|
||||
PDEBUG_REG("intcsr outl(plx:0x%X)=0x%x\n", instance->intcsr, tmp);
|
||||
spin_unlock(instance->intcsr_lock);
|
||||
instance->rised = -1;
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
|
||||
wake_up_interruptible_all(&instance->wait_queue);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me0600_ext_irq_io_reset_subdevice(struct me_subdevice *subdevice,
|
||||
struct file *filep, int flags)
|
||||
{
|
||||
me0600_ext_irq_subdevice_t *instance;
|
||||
uint32_t tmp;
|
||||
unsigned long cpu_flags;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me0600_ext_irq_subdevice_t *) subdevice;
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
|
||||
spin_lock(instance->intcsr_lock);
|
||||
tmp = inl(instance->intcsr);
|
||||
switch (instance->lintno) {
|
||||
case 0:
|
||||
tmp |= PLX_INTCSR_LOCAL_INT1_POL | PLX_INTCSR_PCI_INT_EN;
|
||||
tmp &= ~PLX_INTCSR_LOCAL_INT1_EN;
|
||||
break;
|
||||
case 1:
|
||||
tmp |= PLX_INTCSR_LOCAL_INT2_POL | PLX_INTCSR_PCI_INT_EN;
|
||||
tmp &= ~PLX_INTCSR_LOCAL_INT2_EN;
|
||||
break;
|
||||
}
|
||||
outl(tmp, instance->intcsr);
|
||||
PDEBUG_REG("intcsr outl(plx:0x%X)=0x%x\n", instance->intcsr, tmp);
|
||||
spin_unlock(instance->intcsr_lock);
|
||||
|
||||
instance->rised = -1;
|
||||
instance->n = 0;
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
|
||||
wake_up_interruptible_all(&instance->wait_queue);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me0600_ext_irq_query_number_channels(struct me_subdevice *subdevice,
|
||||
int *number)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*number = 1;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me0600_ext_irq_query_subdevice_type(struct me_subdevice *subdevice,
|
||||
int *type, int *subtype)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*type = ME_TYPE_EXT_IRQ;
|
||||
*subtype = ME_SUBTYPE_SINGLE;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me0600_ext_irq_query_subdevice_caps(struct me_subdevice *subdevice,
|
||||
int *caps)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*caps = ME_CAPS_EXT_IRQ_EDGE_RISING;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static void me0600_ext_irq_destructor(struct me_subdevice *subdevice)
|
||||
{
|
||||
me0600_ext_irq_subdevice_t *instance;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me0600_ext_irq_subdevice_t *) subdevice;
|
||||
|
||||
free_irq(instance->irq, (void *)instance);
|
||||
me_subdevice_deinit(&instance->base);
|
||||
kfree(instance);
|
||||
}
|
||||
|
||||
static irqreturn_t me0600_isr(int irq, void *dev_id)
|
||||
{
|
||||
me0600_ext_irq_subdevice_t *instance;
|
||||
uint32_t status;
|
||||
uint32_t mask = PLX_INTCSR_PCI_INT_EN;
|
||||
irqreturn_t ret = IRQ_HANDLED;
|
||||
|
||||
instance = (me0600_ext_irq_subdevice_t *) dev_id;
|
||||
|
||||
if (irq != instance->irq) {
|
||||
PERROR("Incorrect interrupt num: %d.\n", irq);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
if (instance->lintno > 1) {
|
||||
PERROR_CRITICAL
|
||||
("%s():Wrong subdevice index=%d plx:irq_status_reg=0x%04X.\n",
|
||||
__func__, instance->lintno, inl(instance->intcsr));
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->intcsr_lock);
|
||||
status = inl(instance->intcsr);
|
||||
switch (instance->lintno) {
|
||||
case 0:
|
||||
mask |= PLX_INTCSR_LOCAL_INT1_STATE | PLX_INTCSR_LOCAL_INT1_EN;
|
||||
break;
|
||||
case 1:
|
||||
mask |= PLX_INTCSR_LOCAL_INT2_STATE | PLX_INTCSR_LOCAL_INT2_EN;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((status & mask) == mask) {
|
||||
instance->rised = 1;
|
||||
instance->n++;
|
||||
inb(instance->reset_reg);
|
||||
PDEBUG("Interrupt detected.\n");
|
||||
} else {
|
||||
PINFO
|
||||
("%ld Shared interrupt. %s(): idx=0 plx:irq_status_reg=0x%04X\n",
|
||||
jiffies, __func__, status);
|
||||
ret = IRQ_NONE;
|
||||
}
|
||||
spin_unlock(instance->intcsr_lock);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
wake_up_interruptible_all(&instance->wait_queue);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
me0600_ext_irq_subdevice_t *me0600_ext_irq_constructor(uint32_t plx_reg_base,
|
||||
uint32_t me0600_reg_base,
|
||||
spinlock_t *intcsr_lock,
|
||||
unsigned ext_irq_idx,
|
||||
int irq)
|
||||
{
|
||||
me0600_ext_irq_subdevice_t *subdevice;
|
||||
int err;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
/* Allocate memory for subdevice instance */
|
||||
subdevice = kmalloc(sizeof(me0600_ext_irq_subdevice_t), GFP_KERNEL);
|
||||
|
||||
if (!subdevice) {
|
||||
PERROR("Cannot get memory for 630_ext_irq instance.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(subdevice, 0, sizeof(me0600_ext_irq_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);
|
||||
|
||||
subdevice->intcsr_lock = intcsr_lock;
|
||||
|
||||
/* Initialize wait queue */
|
||||
init_waitqueue_head(&subdevice->wait_queue);
|
||||
|
||||
subdevice->lintno = ext_irq_idx;
|
||||
|
||||
/* Request interrupt line */
|
||||
subdevice->irq = irq;
|
||||
|
||||
err = request_irq(subdevice->irq, me0600_isr,
|
||||
IRQF_DISABLED | IRQF_SHARED,
|
||||
ME0600_NAME, (void *)subdevice);
|
||||
|
||||
if (err) {
|
||||
PERROR("Cannot get interrupt line.\n");
|
||||
kfree(subdevice);
|
||||
return NULL;
|
||||
}
|
||||
PINFO("Registered irq=%d.\n", subdevice->irq);
|
||||
|
||||
/* Initialize registers */
|
||||
subdevice->intcsr = plx_reg_base + PLX_INTCSR;
|
||||
subdevice->reset_reg =
|
||||
me0600_reg_base + ME0600_INT_0_RESET_REG + ext_irq_idx;
|
||||
|
||||
/* Initialize the subdevice methods */
|
||||
subdevice->base.me_subdevice_io_irq_start = me0600_ext_irq_io_irq_start;
|
||||
subdevice->base.me_subdevice_io_irq_wait = me0600_ext_irq_io_irq_wait;
|
||||
subdevice->base.me_subdevice_io_irq_stop = me0600_ext_irq_io_irq_stop;
|
||||
subdevice->base.me_subdevice_io_reset_subdevice =
|
||||
me0600_ext_irq_io_reset_subdevice;
|
||||
subdevice->base.me_subdevice_query_number_channels =
|
||||
me0600_ext_irq_query_number_channels;
|
||||
subdevice->base.me_subdevice_query_subdevice_type =
|
||||
me0600_ext_irq_query_subdevice_type;
|
||||
subdevice->base.me_subdevice_query_subdevice_caps =
|
||||
me0600_ext_irq_query_subdevice_caps;
|
||||
subdevice->base.me_subdevice_destructor = me0600_ext_irq_destructor;
|
||||
|
||||
subdevice->rised = 0;
|
||||
subdevice->n = 0;
|
||||
|
||||
return subdevice;
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/**
|
||||
* @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
|
|
@ -1,18 +0,0 @@
|
|||
/**
|
||||
* @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
|
|
@ -1,243 +0,0 @@
|
|||
/**
|
||||
* @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 <linux/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;
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/**
|
||||
* @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
|
|
@ -1,35 +0,0 @@
|
|||
/**
|
||||
* @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
|
|
@ -1,359 +0,0 @@
|
|||
/**
|
||||
* @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 <linux/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;
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
/**
|
||||
* @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
|
|
@ -1,36 +0,0 @@
|
|||
/**
|
||||
* @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
|
|
@ -1,238 +0,0 @@
|
|||
/**
|
||||
* @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 <linux/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;
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/**
|
||||
* @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
|
|
@ -1,35 +0,0 @@
|
|||
/**
|
||||
* @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
|
|
@ -1,178 +0,0 @@
|
|||
/**
|
||||
* @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;
|
||||
}
|
||||
EXPORT_SYMBOL(me0900_pci_constructor);
|
||||
|
||||
// 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");
|
|
@ -1,92 +0,0 @@
|
|||
/**
|
||||
* @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 (ARRAY_SIZE(me0900_versions) - 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
|
|
@ -1,245 +0,0 @@
|
|||
/**
|
||||
* @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 <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.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;
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/**
|
||||
* @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
|
|
@ -1,314 +0,0 @@
|
|||
/**
|
||||
* @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 <linux/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;
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
/**
|
||||
* @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
|
|
@ -1,40 +0,0 @@
|
|||
/**
|
||||
* @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
|
|
@ -1,206 +0,0 @@
|
|||
/**
|
||||
* @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;
|
||||
}
|
||||
EXPORT_SYMBOL(me1000_pci_constructor);
|
||||
|
||||
// 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");
|
|
@ -1,59 +0,0 @@
|
|||
/**
|
||||
* @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
|
|
@ -1,438 +0,0 @@
|
|||
/**
|
||||
* @file me1000_dio.c
|
||||
*
|
||||
* @brief ME-1000 DIO subdevice instance.
|
||||
* @note Copyright (C) 2006 Meilhaus Electronic GmbH (support@meilhaus.de)
|
||||
* @author Guenter Gebhardt
|
||||
* @author Krzysztof Gantzke (k.gantzke@meilhaus.de)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 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 <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "medefines.h"
|
||||
#include "meinternal.h"
|
||||
#include "meerror.h"
|
||||
#include "medebug.h"
|
||||
|
||||
#include "me1000_dio_reg.h"
|
||||
#include "me1000_dio.h"
|
||||
|
||||
/*
|
||||
* Defines
|
||||
*/
|
||||
#define ME1000_DIO_MAGIC_NUMBER 0x1000 /**< The magic number of the class structure. */
|
||||
|
||||
/*
|
||||
* Functions
|
||||
*/
|
||||
|
||||
static int me1000_dio_io_reset_subdevice(struct me_subdevice *subdevice,
|
||||
struct file *filep, int flags)
|
||||
{
|
||||
me1000_dio_subdevice_t *instance;
|
||||
uint32_t tmp;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me1000_dio_subdevice_t *) subdevice;
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
tmp = inl(instance->ctrl_reg);
|
||||
tmp &= ~(0x1 << instance->dio_idx);
|
||||
outl(tmp, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, tmp);
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
|
||||
outl(0x00000000, instance->port_reg);
|
||||
PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, 0);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me1000_dio_io_single_config(struct me_subdevice *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int single_config,
|
||||
int ref,
|
||||
int trig_chan,
|
||||
int trig_type, int trig_edge, int flags)
|
||||
{
|
||||
me1000_dio_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
int ctrl;
|
||||
int size =
|
||||
flags & (ME_IO_SINGLE_CONFIG_DIO_BIT | ME_IO_SINGLE_CONFIG_DIO_BYTE
|
||||
| ME_IO_SINGLE_CONFIG_DIO_WORD |
|
||||
ME_IO_SINGLE_CONFIG_DIO_DWORD);
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me1000_dio_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
ctrl = inl(instance->ctrl_reg);
|
||||
|
||||
switch (size) {
|
||||
case ME_IO_SINGLE_CONFIG_NO_FLAGS:
|
||||
case ME_IO_SINGLE_CONFIG_DIO_DWORD:
|
||||
if (channel == 0) {
|
||||
if (single_config == ME_SINGLE_CONFIG_DIO_INPUT) {
|
||||
ctrl &= ~(0x1 << instance->dio_idx);
|
||||
} else if (single_config == ME_SINGLE_CONFIG_DIO_OUTPUT) {
|
||||
ctrl |= 0x1 << instance->dio_idx;
|
||||
} else {
|
||||
PERROR("Invalid port direction.\n");
|
||||
err = ME_ERRNO_INVALID_SINGLE_CONFIG;
|
||||
}
|
||||
} else {
|
||||
PERROR("Invalid channel number.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
PERROR("Invalid flags.\n");
|
||||
err = ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
outl(ctrl, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, ctrl);
|
||||
}
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me1000_dio_io_single_read(struct me_subdevice *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int *value, int time_out, int flags)
|
||||
{
|
||||
me1000_dio_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me1000_dio_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
switch (flags) {
|
||||
case ME_IO_SINGLE_TYPE_DIO_BIT:
|
||||
if ((channel >= 0) && (channel < 32)) {
|
||||
*value = inl(instance->port_reg) & (0x1 << channel);
|
||||
} else {
|
||||
PERROR("Invalid bit number.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
break;
|
||||
|
||||
case ME_IO_SINGLE_TYPE_DIO_BYTE:
|
||||
if ((channel >= 0) && (channel < 4)) {
|
||||
*value =
|
||||
(inl(instance->port_reg) >> (channel * 8)) & 0xFF;
|
||||
} else {
|
||||
PERROR("Invalid byte number.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
break;
|
||||
|
||||
case ME_IO_SINGLE_TYPE_DIO_WORD:
|
||||
if ((channel >= 0) && (channel < 2)) {
|
||||
*value =
|
||||
(inl(instance->port_reg) >> (channel * 16)) &
|
||||
0xFFFF;
|
||||
} else {
|
||||
PERROR("Invalid word number.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
break;
|
||||
|
||||
case ME_IO_SINGLE_NO_FLAGS:
|
||||
case ME_IO_SINGLE_TYPE_DIO_DWORD:
|
||||
if (channel == 0) {
|
||||
*value = inl(instance->port_reg);
|
||||
} else {
|
||||
PERROR("Invalid dword number.\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 me1000_dio_io_single_write(struct me_subdevice *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int value, int time_out, int flags)
|
||||
{
|
||||
me1000_dio_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
uint32_t config;
|
||||
uint32_t state;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me1000_dio_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
config = inl(instance->ctrl_reg) & (0x1 << instance->dio_idx);
|
||||
switch (flags) {
|
||||
case ME_IO_SINGLE_TYPE_DIO_BIT:
|
||||
if ((channel >= 0) && (channel < 32)) {
|
||||
if (config) {
|
||||
state = inl(instance->port_reg);
|
||||
state =
|
||||
value ? (state | (0x1 << channel)) : (state
|
||||
&
|
||||
~(0x1
|
||||
<<
|
||||
channel));
|
||||
outl(state, instance->port_reg);
|
||||
PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->port_reg -
|
||||
instance->reg_base, state);
|
||||
} else {
|
||||
PERROR("Port is not in output mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_CONFIG;
|
||||
}
|
||||
} else {
|
||||
PERROR("Invalid bit number.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
break;
|
||||
|
||||
case ME_IO_SINGLE_TYPE_DIO_BYTE:
|
||||
if ((channel >= 0) && (channel < 4)) {
|
||||
if (config) {
|
||||
state = inl(instance->port_reg);
|
||||
state &= ~(0xFF << (channel * 8));
|
||||
state |= (value & 0xFF) << (channel * 8);
|
||||
outl(state, instance->port_reg);
|
||||
PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->port_reg -
|
||||
instance->reg_base, state);
|
||||
} else {
|
||||
PERROR("Port is not in output mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_CONFIG;
|
||||
}
|
||||
} else {
|
||||
PERROR("Invalid byte number.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
break;
|
||||
|
||||
case ME_IO_SINGLE_TYPE_DIO_WORD:
|
||||
if ((channel >= 0) && (channel < 2)) {
|
||||
if (config) {
|
||||
state = inl(instance->port_reg);
|
||||
state &= ~(0xFFFF << (channel * 16));
|
||||
state |= (value & 0xFFFF) << (channel * 16);
|
||||
outl(state, instance->port_reg);
|
||||
PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->port_reg -
|
||||
instance->reg_base, state);
|
||||
} else {
|
||||
PERROR("Port is not in output mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_CONFIG;
|
||||
}
|
||||
} else {
|
||||
PERROR("Invalid word number.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
break;
|
||||
|
||||
case ME_IO_SINGLE_NO_FLAGS:
|
||||
case ME_IO_SINGLE_TYPE_DIO_DWORD:
|
||||
if (channel == 0) {
|
||||
if (config) {
|
||||
outl(value, instance->port_reg);
|
||||
PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->port_reg -
|
||||
instance->reg_base, value);
|
||||
} else {
|
||||
PERROR("Port is not in output mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_CONFIG;
|
||||
}
|
||||
} else {
|
||||
PERROR("Invalid dword number.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
PERROR("Invalid flags specified.\n");
|
||||
err = ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me1000_dio_query_number_channels(struct me_subdevice *subdevice,
|
||||
int *number)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*number = ME1000_DIO_NUMBER_CHANNELS;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me1000_dio_query_subdevice_type(struct me_subdevice *subdevice,
|
||||
int *type, int *subtype)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*type = ME_TYPE_DIO;
|
||||
*subtype = ME_SUBTYPE_SINGLE;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me1000_dio_query_subdevice_caps(struct me_subdevice *subdevice,
|
||||
int *caps)
|
||||
{
|
||||
me1000_dio_subdevice_t *instance;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me1000_dio_subdevice_t *) subdevice;
|
||||
|
||||
*caps = ME_CAPS_DIO_DIR_DWORD;
|
||||
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
me1000_dio_subdevice_t *me1000_dio_constructor(uint32_t reg_base,
|
||||
unsigned int dio_idx,
|
||||
spinlock_t *ctrl_reg_lock)
|
||||
{
|
||||
me1000_dio_subdevice_t *subdevice;
|
||||
int err;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
/* Allocate memory for subdevice instance */
|
||||
subdevice = kmalloc(sizeof(me1000_dio_subdevice_t), GFP_KERNEL);
|
||||
|
||||
if (!subdevice) {
|
||||
PERROR("Cannot get memory for ME-1000 DIO instance.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(subdevice, 0, sizeof(me1000_dio_subdevice_t));
|
||||
|
||||
/* Check if counter index is out of range */
|
||||
|
||||
if (dio_idx >= ME1000_DIO_NUMBER_PORTS) {
|
||||
PERROR("DIO index is out of range.\n");
|
||||
kfree(subdevice);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
subdevice->ctrl_reg_lock = ctrl_reg_lock;
|
||||
|
||||
/* Save the DIO index */
|
||||
subdevice->dio_idx = dio_idx;
|
||||
|
||||
/* Initialize registers. */
|
||||
#ifdef MEDEBUG_DEBUG_REG
|
||||
subdevice->reg_base = reg_base;
|
||||
#endif
|
||||
subdevice->ctrl_reg = reg_base + ME1000_PORT_MODE;
|
||||
subdevice->port_reg =
|
||||
reg_base + ME1000_PORT + (dio_idx * ME1000_PORT_STEP);
|
||||
|
||||
/* Override base class methods. */
|
||||
subdevice->base.me_subdevice_io_reset_subdevice =
|
||||
me1000_dio_io_reset_subdevice;
|
||||
subdevice->base.me_subdevice_io_single_config =
|
||||
me1000_dio_io_single_config;
|
||||
subdevice->base.me_subdevice_io_single_read = me1000_dio_io_single_read;
|
||||
subdevice->base.me_subdevice_io_single_write =
|
||||
me1000_dio_io_single_write;
|
||||
subdevice->base.me_subdevice_query_number_channels =
|
||||
me1000_dio_query_number_channels;
|
||||
subdevice->base.me_subdevice_query_subdevice_type =
|
||||
me1000_dio_query_subdevice_type;
|
||||
subdevice->base.me_subdevice_query_subdevice_caps =
|
||||
me1000_dio_query_subdevice_caps;
|
||||
|
||||
return subdevice;
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
/**
|
||||
* @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
|
|
@ -1,50 +0,0 @@
|
|||
/**
|
||||
* @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_
|
|
@ -1,253 +0,0 @@
|
|||
/**
|
||||
* @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 "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;
|
||||
}
|
||||
EXPORT_SYMBOL(me1400_pci_constructor);
|
||||
|
||||
// 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");
|
|
@ -1,108 +0,0 @@
|
|||
/**
|
||||
* @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 (ARRAY_SIZE(me1400_versions) - 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
|
|
@ -1,507 +0,0 @@
|
|||
/**
|
||||
* @file me1400_ext_irq.c
|
||||
*
|
||||
* @brief ME-1400 external interrupt 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 <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "medefines.h"
|
||||
#include "meinternal.h"
|
||||
#include "meerror.h"
|
||||
#include "medebug.h"
|
||||
#include "meids.h"
|
||||
|
||||
#include "me1400_ext_irq.h"
|
||||
#include "me1400_ext_irq_reg.h"
|
||||
|
||||
/*
|
||||
* Defines
|
||||
*/
|
||||
#define ME1400_EXT_IRQ_MAGIC_NUMBER 0x1401 /**< The magic number of the class structure. */
|
||||
#define ME1400_EXT_IRQ_NUMBER_CHANNELS 1 /**< One channel per counter. */
|
||||
|
||||
/*
|
||||
* Functions
|
||||
*/
|
||||
|
||||
static int me1400_ext_irq_io_irq_start(struct me_subdevice *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int irq_source,
|
||||
int irq_edge, int irq_arg, int flags)
|
||||
{
|
||||
me1400_ext_irq_subdevice_t *instance;
|
||||
unsigned long cpu_flags;
|
||||
uint8_t tmp;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me1400_ext_irq_subdevice_t *) subdevice;
|
||||
|
||||
if (flags & ~ME_IO_IRQ_START_DIO_BIT) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (channel) {
|
||||
PERROR("Invalid channel.\n");
|
||||
return ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
|
||||
if (irq_source != ME_IRQ_SOURCE_DIO_LINE) {
|
||||
PERROR("Invalid irq source.\n");
|
||||
return ME_ERRNO_INVALID_IRQ_SOURCE;
|
||||
}
|
||||
|
||||
if (irq_edge != ME_IRQ_EDGE_RISING) {
|
||||
PERROR("Invalid irq edge.\n");
|
||||
return ME_ERRNO_INVALID_IRQ_EDGE;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
|
||||
|
||||
spin_lock(instance->clk_src_reg_lock);
|
||||
// // Enable IRQ on PLX
|
||||
// tmp = inb(instance->plx_intcs_reg) | (PLX_LOCAL_INT1_EN | PLX_LOCAL_INT1_POL | PLX_PCI_INT_EN);
|
||||
// outb(tmp, instance->plx_intcs_reg);
|
||||
// PDEBUG_REG("ctrl_reg outb(PLX:0x%lX)=0x%x\n", instance->plx_intcs_reg, tmp);
|
||||
|
||||
// Enable IRQ
|
||||
switch (instance->device_id) {
|
||||
case PCI_DEVICE_ID_MEILHAUS_ME140C:
|
||||
case PCI_DEVICE_ID_MEILHAUS_ME140D:
|
||||
tmp = inb(instance->ctrl_reg);
|
||||
tmp |= ME1400CD_EXT_IRQ_CLK_EN;
|
||||
outb(tmp, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, tmp);
|
||||
break;
|
||||
|
||||
default:
|
||||
outb(ME1400AB_EXT_IRQ_IRQ_EN, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base,
|
||||
ME1400AB_EXT_IRQ_IRQ_EN);
|
||||
break;
|
||||
}
|
||||
spin_unlock(instance->clk_src_reg_lock);
|
||||
instance->rised = 0;
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me1400_ext_irq_io_irq_wait(struct me_subdevice *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int *irq_count,
|
||||
int *value, int time_out, int flags)
|
||||
{
|
||||
me1400_ext_irq_subdevice_t *instance;
|
||||
unsigned long cpu_flags;
|
||||
long t = 0;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me1400_ext_irq_subdevice_t *) subdevice;
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (channel) {
|
||||
PERROR("Invalid channel.\n");
|
||||
return ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
|
||||
if (time_out < 0) {
|
||||
PERROR("Invalid time out.\n");
|
||||
return ME_ERRNO_INVALID_TIMEOUT;
|
||||
}
|
||||
|
||||
if (time_out) {
|
||||
/* Convert to ticks */
|
||||
t = (time_out * HZ) / 1000;
|
||||
|
||||
if (t == 0)
|
||||
t = 1;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
if (instance->rised <= 0) {
|
||||
instance->rised = 0;
|
||||
if (time_out) {
|
||||
t = wait_event_interruptible_timeout(instance->
|
||||
wait_queue,
|
||||
(instance->rised !=
|
||||
0), t);
|
||||
|
||||
if (t == 0) {
|
||||
PERROR("Wait on interrupt timed out.\n");
|
||||
err = ME_ERRNO_TIMEOUT;
|
||||
}
|
||||
} else {
|
||||
wait_event_interruptible(instance->wait_queue,
|
||||
(instance->rised != 0));
|
||||
}
|
||||
|
||||
if (instance->rised < 0) {
|
||||
PERROR("Wait on interrupt aborted by user.\n");
|
||||
err = ME_ERRNO_CANCELLED;
|
||||
}
|
||||
}
|
||||
|
||||
if (signal_pending(current)) {
|
||||
PERROR("Wait on interrupt aborted by signal.\n");
|
||||
err = ME_ERRNO_SIGNAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
|
||||
instance->rised = 0;
|
||||
*irq_count = instance->n;
|
||||
*value = 1;
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me1400_ext_irq_io_irq_stop(struct me_subdevice *subdevice,
|
||||
struct file *filep,
|
||||
int channel, int flags)
|
||||
{
|
||||
me1400_ext_irq_subdevice_t *instance;
|
||||
unsigned long cpu_flags;
|
||||
uint8_t tmp;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me1400_ext_irq_subdevice_t *) subdevice;
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (channel) {
|
||||
PERROR("Invalid channel.\n");
|
||||
return ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
|
||||
spin_lock(instance->clk_src_reg_lock);
|
||||
// // Disable IRQ on PLX
|
||||
// tmp = inb(instance->plx_intcs_reg) & ( ~(PLX_LOCAL_INT1_EN | PLX_LOCAL_INT1_POL | PLX_PCI_INT_EN));
|
||||
// outb(tmp, instance->plx_intcs_reg);
|
||||
// PDEBUG_REG("ctrl_reg outb(PLX:0x%lX)=0x%x\n", instance->plx_intcs_reg, tmp);
|
||||
|
||||
switch (instance->device_id) {
|
||||
case PCI_DEVICE_ID_MEILHAUS_ME140C:
|
||||
case PCI_DEVICE_ID_MEILHAUS_ME140D:
|
||||
tmp = inb(instance->ctrl_reg);
|
||||
tmp &= ~ME1400CD_EXT_IRQ_CLK_EN;
|
||||
outb(tmp, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, tmp);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
outb(0x00, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, 0x00);
|
||||
break;
|
||||
}
|
||||
spin_unlock(instance->clk_src_reg_lock);
|
||||
instance->rised = -1;
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
|
||||
wake_up_interruptible_all(&instance->wait_queue);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me1400_ext_irq_io_reset_subdevice(struct me_subdevice *subdevice,
|
||||
struct file *filep, int flags)
|
||||
{
|
||||
me1400_ext_irq_subdevice_t *instance =
|
||||
(me1400_ext_irq_subdevice_t *) subdevice;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
instance->n = 0;
|
||||
return me1400_ext_irq_io_irq_stop(subdevice, filep, 0, flags);
|
||||
}
|
||||
|
||||
static int me1400_ext_irq_query_number_channels(struct me_subdevice *subdevice,
|
||||
int *number)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*number = ME1400_EXT_IRQ_NUMBER_CHANNELS;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me1400_ext_irq_query_subdevice_type(struct me_subdevice *subdevice,
|
||||
int *type, int *subtype)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*type = ME_TYPE_EXT_IRQ;
|
||||
*subtype = ME_SUBTYPE_SINGLE;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me1400_ext_irq_query_subdevice_caps(struct me_subdevice *subdevice,
|
||||
int *caps)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*caps = ME_CAPS_EXT_IRQ_EDGE_RISING;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me1400_ext_irq_query_subdevice_caps_args(struct me_subdevice
|
||||
*subdevice, int cap,
|
||||
int *args, int count)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
return ME_ERRNO_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static irqreturn_t me1400_ext_irq_isr(int irq, void *dev_id)
|
||||
{
|
||||
me1400_ext_irq_subdevice_t *instance;
|
||||
uint32_t status;
|
||||
uint8_t tmp;
|
||||
|
||||
instance = (me1400_ext_irq_subdevice_t *) dev_id;
|
||||
|
||||
if (irq != instance->irq) {
|
||||
PERROR("Incorrect interrupt num: %d.\n", irq);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
status = inl(instance->plx_intcs_reg);
|
||||
// if (!((status & PLX_LOCAL_INT1_STATE) && (status & PLX_LOCAL_INT1_EN) && (status & PLX_PCI_INT_EN)))
|
||||
if ((status &
|
||||
(PLX_LOCAL_INT1_STATE | PLX_LOCAL_INT1_EN | PLX_PCI_INT_EN)) !=
|
||||
(PLX_LOCAL_INT1_STATE | PLX_LOCAL_INT1_EN | PLX_PCI_INT_EN)) {
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
PINFO("%ld Shared interrupt. %s(): irq_status_reg=0x%04X\n",
|
||||
jiffies, __func__, status);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
inl(instance->ctrl_reg);
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance->n++;
|
||||
instance->rised = 1;
|
||||
|
||||
switch (instance->device_id) {
|
||||
|
||||
case PCI_DEVICE_ID_MEILHAUS_ME140C:
|
||||
case PCI_DEVICE_ID_MEILHAUS_ME140D:
|
||||
spin_lock(instance->clk_src_reg_lock);
|
||||
tmp = inb(instance->ctrl_reg);
|
||||
tmp &= ~ME1400CD_EXT_IRQ_CLK_EN;
|
||||
outb(tmp, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outb(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, tmp);
|
||||
tmp |= ME1400CD_EXT_IRQ_CLK_EN;
|
||||
outb(tmp, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outb(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, tmp);
|
||||
spin_unlock(instance->clk_src_reg_lock);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
outb(0, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outb(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, 0);
|
||||
outb(ME1400AB_EXT_IRQ_IRQ_EN, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outb(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base,
|
||||
ME1400AB_EXT_IRQ_IRQ_EN);
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
wake_up_interruptible_all(&instance->wait_queue);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void me1400_ext_irq_destructor(struct me_subdevice *subdevice)
|
||||
{
|
||||
me1400_ext_irq_subdevice_t *instance;
|
||||
uint8_t tmp;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me1400_ext_irq_subdevice_t *) subdevice;
|
||||
|
||||
// Disable IRQ on PLX
|
||||
tmp =
|
||||
inb(instance->
|
||||
plx_intcs_reg) & (~(PLX_LOCAL_INT1_EN | PLX_LOCAL_INT1_POL |
|
||||
PLX_PCI_INT_EN));
|
||||
outb(tmp, instance->plx_intcs_reg);
|
||||
PDEBUG_REG("ctrl_reg outb(plx:0x%lX)=0x%x\n", instance->plx_intcs_reg,
|
||||
tmp);
|
||||
|
||||
free_irq(instance->irq, (void *)instance);
|
||||
me_subdevice_deinit(&instance->base);
|
||||
kfree(instance);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
me1400_ext_irq_subdevice_t *subdevice;
|
||||
int err;
|
||||
uint8_t tmp;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
/* Allocate memory for subdevice instance */
|
||||
subdevice = kmalloc(sizeof(me1400_ext_irq_subdevice_t), GFP_KERNEL);
|
||||
|
||||
if (!subdevice) {
|
||||
PERROR("Cannot get memory for 1400_ext_irq instance.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(subdevice, 0, sizeof(me1400_ext_irq_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);
|
||||
subdevice->clk_src_reg_lock = clk_src_reg_lock;
|
||||
|
||||
/* Initialize wait queue */
|
||||
init_waitqueue_head(&subdevice->wait_queue);
|
||||
|
||||
subdevice->irq = irq;
|
||||
|
||||
err = request_irq(irq, me1400_ext_irq_isr,
|
||||
IRQF_DISABLED | IRQF_SHARED,
|
||||
ME1400_NAME, (void *)subdevice);
|
||||
|
||||
if (err) {
|
||||
PERROR("Can't get irq.\n");
|
||||
me_subdevice_deinit(&subdevice->base);
|
||||
kfree(subdevice);
|
||||
return NULL;
|
||||
}
|
||||
PINFO("Registered irq=%d.\n", subdevice->irq);
|
||||
|
||||
/* Initialize registers */
|
||||
subdevice->plx_intcs_reg = plx_reg_base + PLX_INTCSR_REG;
|
||||
subdevice->ctrl_reg = me1400_reg_base + ME1400AB_EXT_IRQ_CTRL_REG;
|
||||
#ifdef MEDEBUG_DEBUG_REG
|
||||
subdevice->reg_base = me1400_reg_base;
|
||||
#endif
|
||||
|
||||
// Enable IRQ on PLX
|
||||
tmp =
|
||||
inb(subdevice->
|
||||
plx_intcs_reg) | (PLX_LOCAL_INT1_EN | PLX_LOCAL_INT1_POL |
|
||||
PLX_PCI_INT_EN);
|
||||
outb(tmp, subdevice->plx_intcs_reg);
|
||||
PDEBUG_REG("ctrl_reg outb(Pplx:0x%lX)=0x%x\n", subdevice->plx_intcs_reg,
|
||||
tmp);
|
||||
|
||||
/* Initialize the subdevice methods */
|
||||
subdevice->base.me_subdevice_io_irq_start = me1400_ext_irq_io_irq_start;
|
||||
subdevice->base.me_subdevice_io_irq_wait = me1400_ext_irq_io_irq_wait;
|
||||
subdevice->base.me_subdevice_io_irq_stop = me1400_ext_irq_io_irq_stop;
|
||||
subdevice->base.me_subdevice_io_reset_subdevice =
|
||||
me1400_ext_irq_io_reset_subdevice;
|
||||
subdevice->base.me_subdevice_query_number_channels =
|
||||
me1400_ext_irq_query_number_channels;
|
||||
subdevice->base.me_subdevice_query_subdevice_type =
|
||||
me1400_ext_irq_query_subdevice_type;
|
||||
subdevice->base.me_subdevice_query_subdevice_caps =
|
||||
me1400_ext_irq_query_subdevice_caps;
|
||||
subdevice->base.me_subdevice_query_subdevice_caps_args =
|
||||
me1400_ext_irq_query_subdevice_caps_args;
|
||||
subdevice->base.me_subdevice_destructor = me1400_ext_irq_destructor;
|
||||
|
||||
subdevice->rised = 0;
|
||||
subdevice->n = 0;
|
||||
|
||||
return subdevice;
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
/**
|
||||
* @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
|
|
@ -1,56 +0,0 @@
|
|||
/**
|
||||
* @file me1400_ext_irq_reg.h
|
||||
*
|
||||
* @brief ME-1400 external interrupt 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 _ME1400_EXT_IRQ_REG_H_
|
||||
# define _ME1400_EXT_IRQ_REG_H_
|
||||
|
||||
# ifdef __KERNEL__
|
||||
|
||||
# define PLX_INTCSR_REG 0x4C /**< The PLX interrupt control and status register offset. */
|
||||
# define PLX_ICR_REG 0x50 /**< The PLX initialization control register offset. */
|
||||
|
||||
# define PLX_LOCAL_INT1_EN 0x01 /**< If set the local interrupt 1 is enabled. */
|
||||
# define PLX_LOCAL_INT1_POL 0x02 /**< If set the local interrupt 1 polarity is high active. */
|
||||
# define PLX_LOCAL_INT1_STATE 0x04 /**< If set the local interrupt 1 is activ. */
|
||||
# define PLX_LOCAL_INT2_EN 0x08 /**< If set the local interrupt 2 is enabled. */
|
||||
# define PLX_LOCAL_INT2_POL 0x10 /**< If set the local interrupt 2 polarity is high active. */
|
||||
# define PLX_LOCAL_INT2_STATE 0x20 /**< If set the local interrupt 2 is activ. */
|
||||
# define PLX_PCI_INT_EN 0x40 /**< If set the PCI interrupt is enabled. */
|
||||
# define PLX_SOFT_INT 0x80 /**< If set an interrupt is generated. */
|
||||
|
||||
# define ME1400AB_EXT_IRQ_CTRL_REG 0x11 /**< The external interrupt control register offset. */
|
||||
|
||||
# define ME1400AB_EXT_IRQ_CLK_EN 0x01 /**< If this bit is set, the clock output is enabled. */
|
||||
# define ME1400AB_EXT_IRQ_IRQ_EN 0x02 /**< If set the external interrupt is enabled. Clearing this bit clears a pending interrupt. */
|
||||
|
||||
# define ME1400CD_EXT_IRQ_CTRL_REG 0x11 /**< The external interrupt control register offset. */
|
||||
|
||||
# define ME1400CD_EXT_IRQ_CLK_EN 0x10 /**< If set the external interrupt is enabled. Clearing this bit clears a pending interrupt.*/
|
||||
|
||||
# endif //__KERNEL__
|
||||
|
||||
#endif //_ME1400_EXT_IRQ_REG_H_
|
File diff suppressed because it is too large
Load Diff
|
@ -1,128 +0,0 @@
|
|||
/**
|
||||
* @file me1600_ao.h
|
||||
*
|
||||
* @brief Meilhaus ME-1600 analog 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 _ME1600_AO_H_
|
||||
#define _ME1600_AO_H_
|
||||
|
||||
# include <linux/version.h>
|
||||
# include "mesubdevice.h"
|
||||
|
||||
# ifdef __KERNEL__
|
||||
|
||||
# define ME1600_MAX_RANGES 2 /**< Specifies the maximum number of ranges in me1600_ao_subdevice_t::u_ranges und me1600_ao_subdevice_t::i_ranges. */
|
||||
|
||||
/**
|
||||
* @brief Defines a entry in the range table.
|
||||
*/
|
||||
typedef struct me1600_ao_range_entry {
|
||||
int32_t min;
|
||||
int32_t max;
|
||||
} me1600_ao_range_entry_t;
|
||||
|
||||
typedef struct me1600_ao_timeout {
|
||||
unsigned long start_time;
|
||||
unsigned long delay;
|
||||
} me1600_ao_timeout_t;
|
||||
|
||||
typedef struct me1600_ao_shadow {
|
||||
int count;
|
||||
unsigned long *registry;
|
||||
uint16_t *shadow;
|
||||
uint16_t *mirror;
|
||||
uint16_t synchronous; /**< Synchronization list. */
|
||||
uint16_t trigger; /**< Synchronization flag. */
|
||||
} me1600_ao_shadow_t;
|
||||
|
||||
typedef enum ME1600_AO_STATUS {
|
||||
ao_status_none = 0,
|
||||
ao_status_single_configured,
|
||||
ao_status_single_run,
|
||||
ao_status_single_end,
|
||||
ao_status_last
|
||||
} ME1600_AO_STATUS;
|
||||
|
||||
/**
|
||||
* @brief The ME-1600 analog output subdevice class.
|
||||
*/
|
||||
typedef struct me1600_ao_subdevice {
|
||||
/* Inheritance */
|
||||
me_subdevice_t base; /**< The subdevice base class. */
|
||||
|
||||
/* Attributes */
|
||||
int ao_idx; /**< The index of the analog output subdevice on the device. */
|
||||
|
||||
spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */
|
||||
spinlock_t *config_regs_lock; /**< Spin lock to protect configuration registers from concurrent access. */
|
||||
|
||||
int u_ranges_count; /**< The number of voltage ranges available on this subdevice. */
|
||||
me1600_ao_range_entry_t u_ranges[ME1600_MAX_RANGES]; /**< Array holding the voltage ranges on this subdevice. */
|
||||
int i_ranges_count; /**< The number of current ranges available on this subdevice. */
|
||||
me1600_ao_range_entry_t i_ranges[ME1600_MAX_RANGES]; /**< Array holding the current ranges on this subdevice. */
|
||||
|
||||
/* Registers */
|
||||
unsigned long uni_bi_reg; /**< Register for switching between unipoar and bipolar output mode. */
|
||||
unsigned long i_range_reg; /**< Register for switching between ranges. */
|
||||
unsigned long sim_output_reg; /**< Register used in order to update all channels simultaneously. */
|
||||
unsigned long current_on_reg; /**< Register enabling current output on the fourth subdevice. */
|
||||
# ifdef PDEBUG_REG
|
||||
unsigned long reg_base;
|
||||
# endif
|
||||
|
||||
ME1600_AO_STATUS status;
|
||||
me1600_ao_shadow_t *ao_regs_shadows; /**< Addresses and shadows of output's registers. */
|
||||
spinlock_t *ao_shadows_lock; /**< Protects the shadow's struct. */
|
||||
int mode; /**< Mode in witch output should works. */
|
||||
wait_queue_head_t wait_queue; /**< Wait queue to put on tasks waiting for data to arrive. */
|
||||
me1600_ao_timeout_t timeout; /**< The timeout for start in blocking and non-blocking mode. */
|
||||
struct workqueue_struct *me1600_workqueue;
|
||||
struct delayed_work ao_control_task;
|
||||
|
||||
volatile int ao_control_task_flag; /**< Flag controling reexecuting of control task */
|
||||
} me1600_ao_subdevice_t;
|
||||
|
||||
/**
|
||||
* @brief The constructor to generate a subdevice template instance.
|
||||
*
|
||||
* @param reg_base The register base address of the device as returned by the PCI BIOS.
|
||||
* @param ao_idx The index of the analog output subdevice on the device.
|
||||
* @param current Flag indicating that analog output with #ao_idx of 3 is capable of current output.
|
||||
* @param config_regs_lock Pointer to spin lock protecting the configuration registers and from concurrent access.
|
||||
*
|
||||
* @return Pointer to new instance on success.\n
|
||||
* NULL on error.
|
||||
*/
|
||||
me1600_ao_subdevice_t *me1600_ao_constructor(uint32_t reg_base,
|
||||
unsigned int ao_idx,
|
||||
int curr,
|
||||
spinlock_t * config_regs_lock,
|
||||
spinlock_t * ao_shadows_lock,
|
||||
me1600_ao_shadow_t *
|
||||
ao_regs_shadows,
|
||||
struct workqueue_struct
|
||||
*me1600_wq);
|
||||
|
||||
# endif //__KERNEL__
|
||||
#endif //_ME1600_AO_H_
|
|
@ -1,66 +0,0 @@
|
|||
/**
|
||||
* @file me1600_ao_reg.h
|
||||
*
|
||||
* @brief ME-1600 analog 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 _ME1600_AO_REG_H_
|
||||
#define _ME1600_AO_REG_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define ME1600_CHANNEL_0_REG 0x00 /**< Register to set a digital value on channel 0. */
|
||||
#define ME1600_CHANNEL_1_REG 0x02 /**< Register to set a digital value on channel 1. */
|
||||
#define ME1600_CHANNEL_2_REG 0x04 /**< Register to set a digital value on channel 2. */
|
||||
#define ME1600_CHANNEL_3_REG 0x06 /**< Register to set a digital value on channel 3. */
|
||||
#define ME1600_CHANNEL_4_REG 0x08 /**< Register to set a digital value on channel 4. */
|
||||
#define ME1600_CHANNEL_5_REG 0x0A /**< Register to set a digital value on channel 5. */
|
||||
#define ME1600_CHANNEL_6_REG 0x0C /**< Register to set a digital value on channel 6. */
|
||||
#define ME1600_CHANNEL_7_REG 0x0E /**< Register to set a digital value on channel 7. */
|
||||
#define ME1600_CHANNEL_8_REG 0x10 /**< Register to set a digital value on channel 8. */
|
||||
#define ME1600_CHANNEL_9_REG 0x12 /**< Register to set a digital value on channel 9. */
|
||||
#define ME1600_CHANNEL_10_REG 0x14 /**< Register to set a digital value on channel 10. */
|
||||
#define ME1600_CHANNEL_11_REG 0x16 /**< Register to set a digital value on channel 11. */
|
||||
#define ME1600_CHANNEL_12_REG 0x18 /**< Register to set a digital value on channel 12. */
|
||||
#define ME1600_CHANNEL_13_REG 0x1A /**< Register to set a digital value on channel 13. */
|
||||
#define ME1600_CHANNEL_14_REG 0x1C /**< Register to set a digital value on channel 14. */
|
||||
#define ME1600_CHANNEL_15_REG 0x1E /**< Register to set a digital value on channel 15. */
|
||||
|
||||
/* Every channel one bit: bipolar = 0, unipolar = 1 */
|
||||
#define ME1600_UNI_BI_REG 0x20 /**< Register to switch between unipolar and bipolar. */
|
||||
|
||||
/* Every channel one bit (only lower 8 Bits): 0..20mA = 0, 4..20mA = 1 */
|
||||
#define ME1600_020_420_REG 0x22 /**< Register to switch between the two current ranges. */
|
||||
|
||||
/* If a bit is set, the corresponding DAC (4 ports each) is
|
||||
not set at the moment you write to an output of it.
|
||||
Clearing the bit updates the port. */
|
||||
#define ME1600_SIM_OUTPUT_REG 0x24 /**< Register to update all channels of a subdevice simultaneously. */
|
||||
|
||||
/* Current on/off (only lower 8 bits): off = 0, on = 1 */
|
||||
#define ME1600_CURRENT_ON_REG 0x26 /**< Register to swicht between voltage and current output. */
|
||||
|
||||
#define ME1600_AO_MAX_DATA 0x0FFF /**< The maximum digital data accepted by an analog output channel. */
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,259 +0,0 @@
|
|||
/**
|
||||
* @file me1600_device.c
|
||||
*
|
||||
* @brief ME-1600 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 "mesubdevice.h"
|
||||
#include "me1600_device.h"
|
||||
|
||||
static void me1600_set_registry(me1600_device_t *subdevice, uint32_t reg_base);
|
||||
static void me1600_destructor(struct me_device *device);
|
||||
|
||||
/**
|
||||
* @brief Global variable.
|
||||
* This is working queue for runing a separate atask that will be responsible for work status (start, stop, timeouts).
|
||||
*/
|
||||
static struct workqueue_struct *me1600_workqueue;
|
||||
|
||||
me_device_t *me1600_pci_constructor(struct pci_dev *pci_device)
|
||||
{
|
||||
int err;
|
||||
me1600_device_t *me1600_device;
|
||||
me_subdevice_t *subdevice;
|
||||
unsigned int chip_idx;
|
||||
int i;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
// Allocate structure for device instance.
|
||||
me1600_device = kmalloc(sizeof(me1600_device_t), GFP_KERNEL);
|
||||
|
||||
if (!me1600_device) {
|
||||
PERROR("Cannot get memory for device instance.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(me1600_device, 0, sizeof(me1600_device_t));
|
||||
|
||||
// Initialize base class structure.
|
||||
err = me_device_pci_init((me_device_t *) me1600_device, pci_device);
|
||||
|
||||
if (err) {
|
||||
kfree(me1600_device);
|
||||
PERROR("Cannot initialize device base class.\n");
|
||||
return NULL;
|
||||
}
|
||||
// Initialize spin lock .
|
||||
spin_lock_init(&me1600_device->config_regs_lock);
|
||||
spin_lock_init(&me1600_device->ao_shadows_lock);
|
||||
|
||||
// Get the number of analog output subdevices.
|
||||
chip_idx =
|
||||
me1600_versions_get_device_index(me1600_device->base.info.pci.
|
||||
device_id);
|
||||
|
||||
// Create shadow instance.
|
||||
me1600_device->ao_regs_shadows.count =
|
||||
me1600_versions[chip_idx].ao_chips;
|
||||
me1600_device->ao_regs_shadows.registry =
|
||||
kmalloc(me1600_versions[chip_idx].ao_chips * sizeof(unsigned long),
|
||||
GFP_KERNEL);
|
||||
me1600_set_registry(me1600_device,
|
||||
me1600_device->base.info.pci.reg_bases[2]);
|
||||
me1600_device->ao_regs_shadows.shadow =
|
||||
kmalloc(me1600_versions[chip_idx].ao_chips * sizeof(uint16_t),
|
||||
GFP_KERNEL);
|
||||
me1600_device->ao_regs_shadows.mirror =
|
||||
kmalloc(me1600_versions[chip_idx].ao_chips * sizeof(uint16_t),
|
||||
GFP_KERNEL);
|
||||
|
||||
// Create subdevice instances.
|
||||
for (i = 0; i < me1600_versions[chip_idx].ao_chips; i++) {
|
||||
subdevice =
|
||||
(me_subdevice_t *) me1600_ao_constructor(me1600_device->
|
||||
base.info.pci.
|
||||
reg_bases[2], i,
|
||||
((me1600_versions
|
||||
[chip_idx].curr >
|
||||
i) ? 1 : 0),
|
||||
&me1600_device->
|
||||
config_regs_lock,
|
||||
&me1600_device->
|
||||
ao_shadows_lock,
|
||||
&me1600_device->
|
||||
ao_regs_shadows,
|
||||
me1600_workqueue);
|
||||
|
||||
if (!subdevice) {
|
||||
me_device_deinit((me_device_t *) me1600_device);
|
||||
kfree(me1600_device);
|
||||
PERROR("Cannot get memory for subdevice.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
me_slist_add_subdevice_tail(&me1600_device->base.slist,
|
||||
subdevice);
|
||||
}
|
||||
|
||||
// Overwrite base class methods.
|
||||
me1600_device->base.me_device_destructor = me1600_destructor;
|
||||
|
||||
return (me_device_t *) me1600_device;
|
||||
}
|
||||
EXPORT_SYMBOL(me1600_pci_constructor);
|
||||
|
||||
static void me1600_destructor(struct me_device *device)
|
||||
{
|
||||
me1600_device_t *me1600_device = (me1600_device_t *) device;
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
// Destroy shadow instance.
|
||||
kfree(me1600_device->ao_regs_shadows.registry);
|
||||
kfree(me1600_device->ao_regs_shadows.shadow);
|
||||
kfree(me1600_device->ao_regs_shadows.mirror);
|
||||
|
||||
me_device_deinit((me_device_t *) me1600_device);
|
||||
kfree(me1600_device);
|
||||
}
|
||||
|
||||
static void me1600_set_registry(me1600_device_t *subdevice, uint32_t reg_base)
|
||||
{ // Create shadow structure.
|
||||
if (subdevice->ao_regs_shadows.count >= 1) {
|
||||
subdevice->ao_regs_shadows.registry[0] =
|
||||
(unsigned long)(reg_base + ME1600_CHANNEL_0_REG);
|
||||
}
|
||||
if (subdevice->ao_regs_shadows.count >= 2) {
|
||||
subdevice->ao_regs_shadows.registry[1] =
|
||||
(unsigned long)(reg_base + ME1600_CHANNEL_1_REG);
|
||||
}
|
||||
if (subdevice->ao_regs_shadows.count >= 3) {
|
||||
subdevice->ao_regs_shadows.registry[2] =
|
||||
(unsigned long)(reg_base + ME1600_CHANNEL_2_REG);
|
||||
}
|
||||
if (subdevice->ao_regs_shadows.count >= 4) {
|
||||
subdevice->ao_regs_shadows.registry[3] =
|
||||
(unsigned long)(reg_base + ME1600_CHANNEL_3_REG);
|
||||
}
|
||||
if (subdevice->ao_regs_shadows.count >= 5) {
|
||||
subdevice->ao_regs_shadows.registry[4] =
|
||||
(unsigned long)(reg_base + ME1600_CHANNEL_4_REG);
|
||||
}
|
||||
if (subdevice->ao_regs_shadows.count >= 6) {
|
||||
subdevice->ao_regs_shadows.registry[5] =
|
||||
(unsigned long)(reg_base + ME1600_CHANNEL_5_REG);
|
||||
}
|
||||
if (subdevice->ao_regs_shadows.count >= 7) {
|
||||
subdevice->ao_regs_shadows.registry[6] =
|
||||
(unsigned long)(reg_base + ME1600_CHANNEL_6_REG);
|
||||
}
|
||||
if (subdevice->ao_regs_shadows.count >= 8) {
|
||||
subdevice->ao_regs_shadows.registry[7] =
|
||||
(unsigned long)(reg_base + ME1600_CHANNEL_7_REG);
|
||||
}
|
||||
if (subdevice->ao_regs_shadows.count >= 9) {
|
||||
subdevice->ao_regs_shadows.registry[8] =
|
||||
(unsigned long)(reg_base + ME1600_CHANNEL_8_REG);
|
||||
}
|
||||
if (subdevice->ao_regs_shadows.count >= 10) {
|
||||
subdevice->ao_regs_shadows.registry[9] =
|
||||
(unsigned long)(reg_base + ME1600_CHANNEL_9_REG);
|
||||
}
|
||||
if (subdevice->ao_regs_shadows.count >= 11) {
|
||||
subdevice->ao_regs_shadows.registry[10] =
|
||||
(unsigned long)(reg_base + ME1600_CHANNEL_10_REG);
|
||||
}
|
||||
if (subdevice->ao_regs_shadows.count >= 12) {
|
||||
subdevice->ao_regs_shadows.registry[11] =
|
||||
(unsigned long)(reg_base + ME1600_CHANNEL_11_REG);
|
||||
}
|
||||
if (subdevice->ao_regs_shadows.count >= 13) {
|
||||
subdevice->ao_regs_shadows.registry[12] =
|
||||
(unsigned long)(reg_base + ME1600_CHANNEL_12_REG);
|
||||
}
|
||||
if (subdevice->ao_regs_shadows.count >= 14) {
|
||||
subdevice->ao_regs_shadows.registry[13] =
|
||||
(unsigned long)(reg_base + ME1600_CHANNEL_13_REG);
|
||||
}
|
||||
if (subdevice->ao_regs_shadows.count >= 15) {
|
||||
subdevice->ao_regs_shadows.registry[14] =
|
||||
(unsigned long)(reg_base + ME1600_CHANNEL_14_REG);
|
||||
}
|
||||
if (subdevice->ao_regs_shadows.count >= 16) {
|
||||
subdevice->ao_regs_shadows.registry[15] =
|
||||
(unsigned long)(reg_base + ME1600_CHANNEL_15_REG);
|
||||
}
|
||||
if (subdevice->ao_regs_shadows.count > 16) {
|
||||
PERROR("More than 16 outputs! (%d)\n",
|
||||
subdevice->ao_regs_shadows.count);
|
||||
}
|
||||
}
|
||||
|
||||
// Init and exit of module.
|
||||
|
||||
static int __init me1600_init(void)
|
||||
{
|
||||
PDEBUG("executed\n.");
|
||||
|
||||
me1600_workqueue = create_singlethread_workqueue("me1600");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit me1600_exit(void)
|
||||
{
|
||||
PDEBUG("executed\n.");
|
||||
|
||||
flush_workqueue(me1600_workqueue);
|
||||
destroy_workqueue(me1600_workqueue);
|
||||
}
|
||||
|
||||
module_init(me1600_init);
|
||||
module_exit(me1600_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-1600 Device");
|
||||
MODULE_SUPPORTED_DEVICE("Meilhaus ME-1600 Devices");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,101 +0,0 @@
|
|||
/**
|
||||
* @file me1600_device.h
|
||||
*
|
||||
* @brief ME-1600 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 _ME1600_H
|
||||
#define _ME1600_H
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include "medevice.h"
|
||||
#include "me1600_ao.h"
|
||||
#include "me1600_ao_reg.h"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/**
|
||||
* @brief Structure to store device capabilities.
|
||||
*/
|
||||
typedef struct me1600_version {
|
||||
uint16_t device_id; /**< The PCI device id of the device. */
|
||||
unsigned int ao_chips; /**< The number of analog outputs on the device. */
|
||||
int curr; /**< Flag to identify amounts of current output. */
|
||||
} me1600_version_t;
|
||||
|
||||
/**
|
||||
* @brief Defines for each ME-1600 device version its capabilities.
|
||||
*/
|
||||
static me1600_version_t me1600_versions[] = {
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME1600_4U, 4, 0},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME1600_8U, 8, 0},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME1600_12U, 12, 0},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME1600_16U, 16, 0},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME1600_16U_8I, 16, 8},
|
||||
{0}
|
||||
};
|
||||
|
||||
/**< Returns the number of entries in #me1600_versions. */
|
||||
#define ME1600_DEVICE_VERSIONS (ARRAY_SIZE(me1600_versions) - 1)
|
||||
|
||||
/**
|
||||
* @brief Returns the index of the device entry in #me1600_versions.
|
||||
*
|
||||
* @param device_id The PCI device id of the device to query.
|
||||
* @return The index of the device in #me1600_versions.
|
||||
*/
|
||||
static inline unsigned int me1600_versions_get_device_index(uint16_t device_id)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < ME1600_DEVICE_VERSIONS; i++)
|
||||
if (me1600_versions[i].device_id == device_id)
|
||||
break;
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The ME-1600 device class structure.
|
||||
*/
|
||||
typedef struct me1600_device {
|
||||
me_device_t base; /**< The Meilhaus device base class. */
|
||||
spinlock_t config_regs_lock; /**< Protects the configuration registers. */
|
||||
|
||||
me1600_ao_shadow_t ao_regs_shadows; /**< Addresses and shadows of output's registers. */
|
||||
spinlock_t ao_shadows_lock; /**< Protects the shadow's struct. */
|
||||
} me1600_device_t;
|
||||
|
||||
/**
|
||||
* @brief The ME-1600 device class constructor.
|
||||
*
|
||||
* @param pci_device The pci device structure given by the PCI subsystem.
|
||||
*
|
||||
* @return On succes a new ME-1600 device instance. \n
|
||||
* NULL on error.
|
||||
*/
|
||||
me_device_t *me1600_pci_constructor(struct pci_dev *pci_device)
|
||||
__attribute__ ((weak));
|
||||
|
||||
#endif
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,175 +0,0 @@
|
|||
/**
|
||||
* @file me4600_ai.h
|
||||
*
|
||||
* @brief Meilhaus ME-4000 analog input subdevice class.
|
||||
* @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 _ME4600_AI_H_
|
||||
#define _ME4600_AI_H_
|
||||
|
||||
#include "mesubdevice.h"
|
||||
#include "meioctl.h"
|
||||
#include "mecirc_buf.h"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define ME4600_AI_MAX_DATA 0xFFFF
|
||||
|
||||
#ifdef ME_SYNAPSE
|
||||
# define ME4600_AI_CIRC_BUF_SIZE_ORDER 8 // 2^n PAGES =>> Maximum value of 1MB for Synapse
|
||||
#else
|
||||
# define ME4600_AI_CIRC_BUF_SIZE_ORDER 5 // 2^n PAGES =>> 128KB
|
||||
#endif
|
||||
#define ME4600_AI_CIRC_BUF_SIZE PAGE_SIZE<<ME4600_AI_CIRC_BUF_SIZE_ORDER // Buffer size in bytes.
|
||||
|
||||
#ifdef _CBUFF_32b_t
|
||||
# define ME4600_AI_CIRC_BUF_COUNT ((ME4600_AI_CIRC_BUF_SIZE) / sizeof(uint32_t)) // Size in values
|
||||
#else
|
||||
# define ME4600_AI_CIRC_BUF_COUNT ((ME4600_AI_CIRC_BUF_SIZE) / sizeof(uint16_t)) // Size in values
|
||||
#endif
|
||||
|
||||
#define ME4600_AI_FIFO_HALF 1024 //ME4600_AI_FIFO_COUNT/2 //1024
|
||||
#define ME4600_AI_FIFO_MAX_SC 1352 //0.66*ME4600_AI_FIFO_COUNT //1352
|
||||
|
||||
typedef enum ME4600_AI_STATUS {
|
||||
ai_status_none = 0,
|
||||
ai_status_single_configured,
|
||||
ai_status_stream_configured,
|
||||
ai_status_stream_run_wait,
|
||||
ai_status_stream_run,
|
||||
ai_status_stream_end_wait,
|
||||
ai_status_stream_end,
|
||||
ai_status_stream_fifo_error,
|
||||
ai_status_stream_buffer_error,
|
||||
ai_status_stream_error,
|
||||
ai_status_last
|
||||
} ME4600_AI_STATUS;
|
||||
|
||||
typedef struct me4600_single_config_entry {
|
||||
unsigned short status;
|
||||
uint32_t entry;
|
||||
uint32_t ctrl;
|
||||
} me4600_single_config_entry_t;
|
||||
|
||||
typedef struct me4600_range_entry {
|
||||
int min;
|
||||
int max;
|
||||
} me4600_range_entry_t;
|
||||
|
||||
typedef struct me4600_ai_ISM {
|
||||
volatile unsigned int global_read; /**< The number of data read in total. */
|
||||
volatile unsigned int read; /**< The number of data read for this chunck. */
|
||||
volatile unsigned int next; /**< The number of data request by user. */
|
||||
} me4600_ai_ISM_t;
|
||||
|
||||
typedef struct me4600_ai_timeout {
|
||||
unsigned long start_time;
|
||||
unsigned long delay;
|
||||
} me4600_ai_timeout_t;
|
||||
|
||||
/**
|
||||
* @brief The ME-4000 analog input subdevice class.
|
||||
*/
|
||||
typedef struct me4600_ai_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. */
|
||||
|
||||
/* Hardware feautres */
|
||||
unsigned int irq; /**< The interrupt request number assigned by the PCI BIOS. */
|
||||
int isolated; /**< Marks if this subdevice is on an optoisolated device. */
|
||||
int sh; /**< Marks if this subdevice has sample and hold devices. */
|
||||
|
||||
unsigned int channels; /**< The number of channels available on this subdevice. */
|
||||
me4600_single_config_entry_t single_config[32]; /**< The configuration set for single acquisition. */
|
||||
|
||||
unsigned int data_required; /**< The number of data request by user. */
|
||||
unsigned int fifo_irq_threshold; /**< The user adjusted FIFO high water interrupt level. */
|
||||
unsigned int chan_list_len; /**< The length of the user defined channel list. */
|
||||
|
||||
me4600_ai_ISM_t ISM; /**< The information request by Interrupt-State-Machine. */
|
||||
volatile enum ME4600_AI_STATUS status; /**< The current stream status flag. */
|
||||
me4600_ai_timeout_t timeout; /**< The timeout for start in blocking and non-blocking mode. */
|
||||
|
||||
/* Registers *//**< All registers are 32 bits long. */
|
||||
unsigned long ctrl_reg;
|
||||
unsigned long status_reg;
|
||||
unsigned long channel_list_reg;
|
||||
unsigned long data_reg;
|
||||
unsigned long chan_timer_reg;
|
||||
unsigned long chan_pre_timer_reg;
|
||||
unsigned long scan_timer_low_reg;
|
||||
unsigned long scan_timer_high_reg;
|
||||
unsigned long scan_pre_timer_low_reg;
|
||||
unsigned long scan_pre_timer_high_reg;
|
||||
unsigned long start_reg;
|
||||
unsigned long irq_status_reg;
|
||||
unsigned long sample_counter_reg;
|
||||
|
||||
unsigned int ranges_len;
|
||||
me4600_range_entry_t ranges[4]; /**< The ranges available on this subdevice. */
|
||||
|
||||
/* Software buffer */
|
||||
me_circ_buf_t circ_buf; /**< Circular buffer holding measurment data. */
|
||||
wait_queue_head_t wait_queue; /**< Wait queue to put on tasks waiting for data to arrive. */
|
||||
|
||||
struct workqueue_struct *me4600_workqueue;
|
||||
struct delayed_work ai_control_task;
|
||||
|
||||
volatile int ai_control_task_flag; /**< Flag controling reexecuting of control task */
|
||||
|
||||
#ifdef MEDEBUG_DEBUG_REG
|
||||
unsigned long reg_base;
|
||||
#endif
|
||||
} me4600_ai_subdevice_t;
|
||||
|
||||
/**
|
||||
* @brief The constructor to generate a ME-4000 analog input subdevice instance.
|
||||
*
|
||||
* @param reg_base The register base address of the device as returned by the PCI BIOS.
|
||||
* @param channels The number of analog input channels available on this subdevice.
|
||||
* @param channels The number of analog input ranges available on this subdevice.
|
||||
* @param isolated Flag indicating if this device is opto isolated.
|
||||
* @param sh Flag indicating if sample and hold devices are available.
|
||||
* @param irq The irq number assigned by PCI BIOS.
|
||||
* @param ctrl_reg_lock Pointer to spin lock protecting the control register from concurrent access.
|
||||
*
|
||||
* @return Pointer to new instance on success.\n
|
||||
* NULL on error.
|
||||
*/
|
||||
me4600_ai_subdevice_t *me4600_ai_constructor(uint32_t reg_base,
|
||||
unsigned int channels,
|
||||
unsigned int ranges,
|
||||
int isolated,
|
||||
int sh,
|
||||
int irq,
|
||||
spinlock_t * ctrl_reg_lock,
|
||||
struct workqueue_struct
|
||||
*me4600_wq);
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,107 +0,0 @@
|
|||
/**
|
||||
* @file me4600_ai_reg.h
|
||||
*
|
||||
* @brief ME-4000 analog 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 _ME4600_AI_REG_H_
|
||||
#define _ME4600_AI_REG_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define ME4600_AI_CTRL_REG 0x74 // _/W
|
||||
#define ME4600_AI_STATUS_REG 0x74 // R/_
|
||||
#define ME4600_AI_CHANNEL_LIST_REG 0x78 // _/W
|
||||
#define ME4600_AI_DATA_REG 0x7C // R/_
|
||||
#define ME4600_AI_CHAN_TIMER_REG 0x80 // _/W
|
||||
#define ME4600_AI_CHAN_PRE_TIMER_REG 0x84 // _/W
|
||||
#define ME4600_AI_SCAN_TIMER_LOW_REG 0x88 // _/W
|
||||
#define ME4600_AI_SCAN_TIMER_HIGH_REG 0x8C // _/W
|
||||
#define ME4600_AI_SCAN_PRE_TIMER_LOW_REG 0x90 // _/W
|
||||
#define ME4600_AI_SCAN_PRE_TIMER_HIGH_REG 0x94 // _/W
|
||||
#define ME4600_AI_START_REG 0x98 // R/_
|
||||
|
||||
#define ME4600_AI_SAMPLE_COUNTER_REG 0xC0 // _/W
|
||||
|
||||
#define ME4600_AI_CTRL_BIT_MODE_0 0x00000001
|
||||
#define ME4600_AI_CTRL_BIT_MODE_1 0x00000002
|
||||
#define ME4600_AI_CTRL_BIT_MODE_2 0x00000004
|
||||
#define ME4600_AI_CTRL_BIT_SAMPLE_HOLD 0x00000008
|
||||
#define ME4600_AI_CTRL_BIT_IMMEDIATE_STOP 0x00000010
|
||||
#define ME4600_AI_CTRL_BIT_STOP 0x00000020
|
||||
#define ME4600_AI_CTRL_BIT_CHANNEL_FIFO 0x00000040
|
||||
#define ME4600_AI_CTRL_BIT_DATA_FIFO 0x00000080
|
||||
#define ME4600_AI_CTRL_BIT_FULLSCALE 0x00000100
|
||||
#define ME4600_AI_CTRL_BIT_OFFSET 0x00000200
|
||||
#define ME4600_AI_CTRL_BIT_EX_TRIG_ANALOG 0x00000400
|
||||
#define ME4600_AI_CTRL_BIT_EX_TRIG 0x00000800
|
||||
#define ME4600_AI_CTRL_BIT_EX_TRIG_FALLING 0x00001000
|
||||
#define ME4600_AI_CTRL_BIT_EX_IRQ 0x00002000
|
||||
#define ME4600_AI_CTRL_BIT_EX_IRQ_RESET 0x00004000
|
||||
#define ME4600_AI_CTRL_BIT_LE_IRQ 0x00008000
|
||||
#define ME4600_AI_CTRL_BIT_LE_IRQ_RESET 0x00010000
|
||||
#define ME4600_AI_CTRL_BIT_HF_IRQ 0x00020000
|
||||
#define ME4600_AI_CTRL_BIT_HF_IRQ_RESET 0x00040000
|
||||
#define ME4600_AI_CTRL_BIT_SC_IRQ 0x00080000
|
||||
#define ME4600_AI_CTRL_BIT_SC_IRQ_RESET 0x00100000
|
||||
#define ME4600_AI_CTRL_BIT_SC_RELOAD 0x00200000
|
||||
#define ME4600_AI_CTRL_BIT_EX_TRIG_BOTH 0x80000000
|
||||
|
||||
#define ME4600_AI_STATUS_BIT_EF_CHANNEL 0x00400000
|
||||
#define ME4600_AI_STATUS_BIT_HF_CHANNEL 0x00800000
|
||||
#define ME4600_AI_STATUS_BIT_FF_CHANNEL 0x01000000
|
||||
#define ME4600_AI_STATUS_BIT_EF_DATA 0x02000000
|
||||
#define ME4600_AI_STATUS_BIT_HF_DATA 0x04000000
|
||||
#define ME4600_AI_STATUS_BIT_FF_DATA 0x08000000
|
||||
#define ME4600_AI_STATUS_BIT_LE 0x10000000
|
||||
#define ME4600_AI_STATUS_BIT_FSM 0x20000000
|
||||
|
||||
#define ME4600_AI_CTRL_RPCI_FIFO 0x40000000 //Always set to zero!
|
||||
|
||||
#define ME4600_AI_BASE_FREQUENCY 33E6
|
||||
|
||||
#define ME4600_AI_MIN_ACQ_TICKS 66LL
|
||||
#define ME4600_AI_MAX_ACQ_TICKS 0xFFFFFFFFLL
|
||||
|
||||
#define ME4600_AI_MIN_SCAN_TICKS 66LL
|
||||
#define ME4600_AI_MAX_SCAN_TICKS 0xFFFFFFFFFLL
|
||||
|
||||
#define ME4600_AI_MIN_CHAN_TICKS 66LL
|
||||
#define ME4600_AI_MAX_CHAN_TICKS 0xFFFFFFFFLL
|
||||
|
||||
#define ME4600_AI_FIFO_COUNT 2048
|
||||
|
||||
#define ME4600_AI_LIST_COUNT 1024
|
||||
|
||||
#define ME4600_AI_LIST_INPUT_SINGLE_ENDED 0x000
|
||||
#define ME4600_AI_LIST_INPUT_DIFFERENTIAL 0x020
|
||||
|
||||
#define ME4600_AI_LIST_RANGE_BIPOLAR_10 0x000
|
||||
#define ME4600_AI_LIST_RANGE_BIPOLAR_2_5 0x040
|
||||
#define ME4600_AI_LIST_RANGE_UNIPOLAR_10 0x080
|
||||
#define ME4600_AI_LIST_RANGE_UNIPOLAR_2_5 0x0C0
|
||||
|
||||
#define ME4600_AI_LIST_LAST_ENTRY 0x100
|
||||
|
||||
#endif
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,259 +0,0 @@
|
|||
/**
|
||||
* @file me4600_ao.h
|
||||
*
|
||||
* @brief Meilhaus ME-4000 analog 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 _ME4600_AO_H_
|
||||
# define _ME4600_AO_H_
|
||||
|
||||
# include <linux/version.h>
|
||||
# include "mesubdevice.h"
|
||||
# include "mecirc_buf.h"
|
||||
# include "meioctl.h"
|
||||
|
||||
# ifdef __KERNEL__
|
||||
|
||||
# ifdef BOSCH
|
||||
# undef ME_SYNAPSE
|
||||
# ifndef _CBUFF_32b_t
|
||||
# define _CBUFF_32b_t
|
||||
# endif //_CBUFF_32b_t
|
||||
# endif //BOSCH
|
||||
|
||||
# define ME4600_AO_MAX_SUBDEVICES 4
|
||||
# define ME4600_AO_FIFO_COUNT 4096
|
||||
|
||||
# define ME4600_AO_BASE_FREQUENCY 33000000LL
|
||||
|
||||
# define ME4600_AO_MIN_ACQ_TICKS 0LL
|
||||
# define ME4600_AO_MAX_ACQ_TICKS 0LL
|
||||
|
||||
# define ME4600_AO_MIN_CHAN_TICKS 66LL
|
||||
# define ME4600_AO_MAX_CHAN_TICKS 0xFFFFFFFFLL
|
||||
|
||||
# define ME4600_AO_MIN_RANGE -10000000
|
||||
# define ME4600_AO_MAX_RANGE 9999694
|
||||
|
||||
# define ME4600_AO_MAX_DATA 0xFFFF
|
||||
|
||||
# ifdef ME_SYNAPSE
|
||||
# define ME4600_AO_CIRC_BUF_SIZE_ORDER 8 // 2^n PAGES =>> Maximum value of 1MB for Synapse
|
||||
# else
|
||||
# define ME4600_AO_CIRC_BUF_SIZE_ORDER 5 // 2^n PAGES =>> 128KB
|
||||
# endif
|
||||
# define ME4600_AO_CIRC_BUF_SIZE PAGE_SIZE<<ME4600_AO_CIRC_BUF_SIZE_ORDER // Buffer size in bytes.
|
||||
|
||||
# ifdef _CBUFF_32b_t
|
||||
# define ME4600_AO_CIRC_BUF_COUNT ((ME4600_AO_CIRC_BUF_SIZE) / sizeof(uint32_t)) // Size in values
|
||||
# else
|
||||
# define ME4600_AO_CIRC_BUF_COUNT ((ME4600_AO_CIRC_BUF_SIZE) / sizeof(uint16_t)) // Size in values
|
||||
# endif
|
||||
|
||||
# define ME4600_AO_CONTINOUS 0x0
|
||||
# define ME4600_AO_WRAP_MODE 0x1
|
||||
# define ME4600_AO_HW_MODE 0x2
|
||||
|
||||
# define ME4600_AO_HW_WRAP_MODE (ME4600_AO_WRAP_MODE | ME4600_AO_HW_MODE)
|
||||
# define ME4600_AO_SW_WRAP_MODE ME4600_AO_WRAP_MODE
|
||||
|
||||
# define ME4600_AO_INF_STOP_MODE 0x0
|
||||
# define ME4600_AO_ACQ_STOP_MODE 0x1
|
||||
# define ME4600_AO_SCAN_STOP_MODE 0x2
|
||||
|
||||
# ifdef BOSCH //SPECIAL BUILD FOR BOSCH
|
||||
|
||||
/* Bits for flags attribute. */
|
||||
# define ME4600_AO_FLAGS_BROKEN_PIPE 0x1
|
||||
# define ME4600_AO_FLAGS_SW_WRAP_MODE_0 0x2
|
||||
# define ME4600_AO_FLAGS_SW_WRAP_MODE_1 0x4
|
||||
# define ME4600_AO_FLAGS_SW_WRAP_MODE_MASK (ME4600_AO_FLAGS_SW_WRAP_MODE_0 | ME4600_AO_FLAGS_SW_WRAP_MODE_1)
|
||||
|
||||
# define ME4600_AO_FLAGS_SW_WRAP_MODE_NONE 0x0
|
||||
# define ME4600_AO_FLAGS_SW_WRAP_MODE_INF 0x2
|
||||
# define ME4600_AO_FLAGS_SW_WRAP_MODE_FIN 0x4
|
||||
|
||||
/**
|
||||
* @brief The ME-4000 analog output subdevice class.
|
||||
*/
|
||||
typedef struct me4600_ao_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 *preload_reg_lock; /**< Spin lock to protect #preload_reg from concurrent access. */
|
||||
uint32_t *preload_flags;
|
||||
|
||||
unsigned int irq; /**< The interrupt request number assigned by the PCI BIOS. */
|
||||
me_circ_buf_t circ_buf; /**< Circular buffer holding measurment data. */
|
||||
wait_queue_head_t wait_queue; /**< Wait queue to put on tasks waiting for data to arrive. */
|
||||
|
||||
int single_value; /**< Mirror of the value written in single mode. */
|
||||
|
||||
int volatile flags; /**< Flags used for storing SW wraparound setup and error signalling from ISR. */
|
||||
unsigned int wrap_count; /**< The user defined wraparound cycle count. */
|
||||
unsigned int wrap_remaining; /**< The wraparound cycle down counter used by a running conversion. */
|
||||
unsigned int ao_idx; /**< The index of this analog output on this device. */
|
||||
int fifo; /**< If set this device has a FIFO. */
|
||||
|
||||
int bosch_fw; /**< If set the bosch firmware is in PROM. */
|
||||
|
||||
/* Registers */
|
||||
uint32_t ctrl_reg;
|
||||
uint32_t status_reg;
|
||||
uint32_t fifo_reg;
|
||||
uint32_t single_reg;
|
||||
uint32_t timer_reg;
|
||||
uint32_t irq_status_reg;
|
||||
uint32_t preload_reg;
|
||||
uint32_t reg_base;
|
||||
} me4600_ao_subdevice_t;
|
||||
|
||||
/**
|
||||
* @brief The constructor to generate a ME-4000 analog output subdevice instance for BOSCH project.
|
||||
*
|
||||
* @param reg_base The register base address of the device as returned by the PCI BIOS.
|
||||
* @param ctrl_reg_lock Pointer to spin lock protecting the control register from concurrent access.
|
||||
* @param preload_flags Pointer to spin lock protecting the hold&trigger register from concurrent access.
|
||||
* @param ao_idx Subdevice number.
|
||||
* @param fifo Flag set if subdevice has hardware FIFO.
|
||||
* @param irq IRQ number.
|
||||
*
|
||||
* @return Pointer to new instance on success.\n
|
||||
* NULL on error.
|
||||
*/
|
||||
me4600_ao_subdevice_t *me4600_ao_constructor(uint32_t reg_base,
|
||||
spinlock_t * preload_reg_lock,
|
||||
uint32_t * preload_flags,
|
||||
int ao_idx, int fifo, int irq);
|
||||
|
||||
# else //~BOSCH
|
||||
|
||||
//ME4600_AO_FLAGS_BROKEN_PIPE is OBSOLETE => Now problems are reported in status.
|
||||
|
||||
typedef enum ME4600_AO_STATUS {
|
||||
ao_status_none = 0,
|
||||
ao_status_single_configured,
|
||||
ao_status_single_run_wait,
|
||||
ao_status_single_run,
|
||||
ao_status_single_end_wait,
|
||||
ao_status_single_end,
|
||||
ao_status_stream_configured,
|
||||
ao_status_stream_run_wait,
|
||||
ao_status_stream_run,
|
||||
ao_status_stream_end_wait,
|
||||
ao_status_stream_end,
|
||||
ao_status_stream_fifo_error,
|
||||
ao_status_stream_buffer_error,
|
||||
ao_status_stream_error,
|
||||
ao_status_last
|
||||
} ME4600_AO_STATUS;
|
||||
|
||||
typedef struct me4600_ao_timeout {
|
||||
unsigned long start_time;
|
||||
unsigned long delay;
|
||||
} me4600_ao_timeout_t;
|
||||
|
||||
/**
|
||||
* @brief The ME-4600 analog output subdevice class.
|
||||
*/
|
||||
typedef struct me4600_ao_subdevice {
|
||||
/* Inheritance */
|
||||
me_subdevice_t base; /**< The subdevice base class. */
|
||||
unsigned int ao_idx; /**< The index of this analog output on this device. */
|
||||
|
||||
/* Attributes */
|
||||
spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */
|
||||
spinlock_t *preload_reg_lock; /**< Spin lock to protect preload_reg from concurrent access. */
|
||||
|
||||
uint32_t *preload_flags;
|
||||
|
||||
/* Hardware feautres */
|
||||
unsigned int irq; /**< The interrupt request number assigned by the PCI BIOS. */
|
||||
int fifo; /**< If set this device has a FIFO. */
|
||||
int bitpattern; /**< If set this device use bitpattern. */
|
||||
|
||||
int single_value; /**< Mirror of the output value in single mode. */
|
||||
int single_value_in_fifo; /**< Mirror of the value written in single mode. */
|
||||
uint32_t ctrl_trg; /**< Mirror of the trigger settings. */
|
||||
|
||||
volatile int mode; /**< Flags used for storing SW wraparound setup*/
|
||||
int stop_mode; /**< The user defined stop condition flag. */
|
||||
unsigned int start_mode;
|
||||
unsigned int stop_count; /**< The user defined dates presentation end count. */
|
||||
unsigned int stop_data_count; /**< The stop presentation count. */
|
||||
unsigned int data_count; /**< The real presentation count. */
|
||||
unsigned int preloaded_count; /**< The next data addres in buffer. <= for wraparound mode. */
|
||||
int hardware_stop_delay; /**< The time that stop can take. This is only to not show hardware bug to user. */
|
||||
|
||||
volatile enum ME4600_AO_STATUS status; /**< The current stream status flag. */
|
||||
me4600_ao_timeout_t timeout; /**< The timeout for start in blocking and non-blocking mode. */
|
||||
|
||||
/* Registers *//**< All registers are 32 bits long. */
|
||||
unsigned long ctrl_reg;
|
||||
unsigned long status_reg;
|
||||
unsigned long fifo_reg;
|
||||
unsigned long single_reg;
|
||||
unsigned long timer_reg;
|
||||
unsigned long irq_status_reg;
|
||||
unsigned long preload_reg;
|
||||
unsigned long reg_base;
|
||||
|
||||
/* Software buffer */
|
||||
me_circ_buf_t circ_buf; /**< Circular buffer holding measurment data. 32 bit long */
|
||||
wait_queue_head_t wait_queue; /**< Wait queue to put on tasks waiting for data to arrive. */
|
||||
|
||||
struct workqueue_struct *me4600_workqueue;
|
||||
struct delayed_work ao_control_task;
|
||||
|
||||
volatile int ao_control_task_flag; /**< Flag controling reexecuting of control task */
|
||||
|
||||
} me4600_ao_subdevice_t;
|
||||
|
||||
/**
|
||||
* @brief The constructor to generate a ME-4600 analog output subdevice instance.
|
||||
*
|
||||
* @param reg_base The register base address of the device as returned by the PCI BIOS.
|
||||
* @param ctrl_reg_lock Pointer to spin lock protecting the control register from concurrent access.
|
||||
* @param preload_flags Pointer to spin lock protecting the hold&trigger register from concurrent access.
|
||||
* @param ao_idx Subdevice number.
|
||||
* @param fifo Flag set if subdevice has hardware FIFO.
|
||||
* @param irq IRQ number.
|
||||
* @param me4600_wq Queue for asynchronous task (1 queue for all subdevice on 1 board).
|
||||
*
|
||||
* @return Pointer to new instance on success.\n
|
||||
* NULL on error.
|
||||
*/
|
||||
me4600_ao_subdevice_t *me4600_ao_constructor(uint32_t reg_base,
|
||||
spinlock_t * preload_reg_lock,
|
||||
uint32_t * preload_flags,
|
||||
int ao_idx,
|
||||
int fifo,
|
||||
int irq,
|
||||
struct workqueue_struct
|
||||
*me4600_wq);
|
||||
|
||||
# endif //BOSCH
|
||||
# endif //__KERNEL__
|
||||
#endif // ~_ME4600_AO_H_
|
|
@ -1,113 +0,0 @@
|
|||
/**
|
||||
* @file me4600_ao_reg.h
|
||||
*
|
||||
* @brief ME-4000 analog 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 _ME4600_AO_REG_H_
|
||||
#define _ME4600_AO_REG_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define ME4600_AO_00_CTRL_REG 0x00 // R/W
|
||||
#define ME4600_AO_00_STATUS_REG 0x04 // R/_
|
||||
#define ME4600_AO_00_FIFO_REG 0x08 // _/W
|
||||
#define ME4600_AO_00_SINGLE_REG 0x0C // R/W
|
||||
#define ME4600_AO_00_TIMER_REG 0x10 // _/W
|
||||
|
||||
#define ME4600_AO_01_CTRL_REG 0x18 // R/W
|
||||
#define ME4600_AO_01_STATUS_REG 0x1C // R/_
|
||||
#define ME4600_AO_01_FIFO_REG 0x20 // _/W
|
||||
#define ME4600_AO_01_SINGLE_REG 0x24 // R/W
|
||||
#define ME4600_AO_01_TIMER_REG 0x28 // _/W
|
||||
|
||||
#define ME4600_AO_02_CTRL_REG 0x30 // R/W
|
||||
#define ME4600_AO_02_STATUS_REG 0x34 // R/_
|
||||
#define ME4600_AO_02_FIFO_REG 0x38 // _/W
|
||||
#define ME4600_AO_02_SINGLE_REG 0x3C // R/W
|
||||
#define ME4600_AO_02_TIMER_REG 0x40 // _/W
|
||||
|
||||
#define ME4600_AO_03_CTRL_REG 0x48 // R/W
|
||||
#define ME4600_AO_03_STATUS_REG 0x4C // R/_
|
||||
#define ME4600_AO_03_FIFO_REG 0x50 // _/W
|
||||
#define ME4600_AO_03_SINGLE_REG 0x54 // R/W
|
||||
#define ME4600_AO_03_TIMER_REG 0x58 // _/W
|
||||
|
||||
#define ME4600_AO_DEMUX_ADJUST_REG 0xBC // -/W
|
||||
#define ME4600_AO_DEMUX_ADJUST_VALUE 0x4C
|
||||
|
||||
#ifdef BOSCH
|
||||
# define ME4600_AO_BOSCH_REG 0xC4
|
||||
|
||||
# define ME4600_AO_LOADSETREG_XX 0xB4 // R/W
|
||||
|
||||
# define ME4600_AO_CTRL_BIT_MODE_0 0x001
|
||||
# define ME4600_AO_CTRL_BIT_MODE_1 0x002
|
||||
# define ME4600_AO_CTRL_MASK_MODE 0x003
|
||||
|
||||
#else //~BOSCH
|
||||
|
||||
#define ME4600_AO_SYNC_REG 0xB4 // R/W ///ME4600_AO_SYNC_REG <==> ME4600_AO_PRELOAD_REG <==> ME4600_AO_LOADSETREG_XX
|
||||
|
||||
# define ME4600_AO_MODE_SINGLE 0x00000000
|
||||
# define ME4600_AO_MODE_WRAPAROUND 0x00000001
|
||||
# define ME4600_AO_MODE_CONTINUOUS 0x00000002
|
||||
# define ME4600_AO_CTRL_MODE_MASK (ME4600_AO_MODE_WRAPAROUND | ME4600_AO_MODE_CONTINUOUS)
|
||||
#endif //BOSCH
|
||||
|
||||
#define ME4600_AO_CTRL_BIT_MODE_WRAPAROUND ME4600_AO_MODE_WRAPAROUND
|
||||
#define ME4600_AO_CTRL_BIT_MODE_CONTINOUS ME4600_AO_MODE_CONTINUOUS
|
||||
#define ME4600_AO_CTRL_BIT_STOP 0x00000004
|
||||
#define ME4600_AO_CTRL_BIT_ENABLE_FIFO 0x00000008
|
||||
#define ME4600_AO_CTRL_BIT_ENABLE_EX_TRIG 0x00000010
|
||||
#define ME4600_AO_CTRL_BIT_EX_TRIG_EDGE 0x00000020
|
||||
#define ME4600_AO_CTRL_BIT_IMMEDIATE_STOP 0x00000080
|
||||
#define ME4600_AO_CTRL_BIT_ENABLE_DO 0x00000100
|
||||
#define ME4600_AO_CTRL_BIT_ENABLE_IRQ 0x00000200
|
||||
#define ME4600_AO_CTRL_BIT_RESET_IRQ 0x00000400
|
||||
#define ME4600_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH 0x00000800
|
||||
/*
|
||||
#define ME4600_AO_SYNC_HOLD_0 0x00000001
|
||||
#define ME4600_AO_SYNC_HOLD_1 0x00000002
|
||||
#define ME4600_AO_SYNC_HOLD_2 0x00000004
|
||||
#define ME4600_AO_SYNC_HOLD_3 0x00000008
|
||||
*/
|
||||
#define ME4600_AO_SYNC_HOLD 0x00000001
|
||||
|
||||
/*
|
||||
#define ME4600_AO_SYNC_EXT_TRIG_0 0x00010000
|
||||
#define ME4600_AO_SYNC_EXT_TRIG_1 0x00020000
|
||||
#define ME4600_AO_SYNC_EXT_TRIG_2 0x00040000
|
||||
#define ME4600_AO_SYNC_EXT_TRIG_3 0x00080000
|
||||
*/
|
||||
#define ME4600_AO_SYNC_EXT_TRIG 0x00010000
|
||||
|
||||
#define ME4600_AO_EXT_TRIG 0x80000000
|
||||
|
||||
#define ME4600_AO_STATUS_BIT_FSM 0x00000001
|
||||
#define ME4600_AO_STATUS_BIT_FF 0x00000002
|
||||
#define ME4600_AO_STATUS_BIT_HF 0x00000004
|
||||
#define ME4600_AO_STATUS_BIT_EF 0x00000008
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,371 +0,0 @@
|
|||
/**
|
||||
* @file me4600_device.c
|
||||
*
|
||||
* @brief ME-4600 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 "me4600_device.h"
|
||||
#include "meplx_reg.h"
|
||||
|
||||
#include "mefirmware.h"
|
||||
|
||||
#include "mesubdevice.h"
|
||||
#include "me4600_do.h"
|
||||
#include "me4600_di.h"
|
||||
#include "me4600_dio.h"
|
||||
#include "me8254.h"
|
||||
#include "me4600_ai.h"
|
||||
#include "me4600_ao.h"
|
||||
#include "me4600_ext_irq.h"
|
||||
|
||||
/**
|
||||
* @brief Global variable.
|
||||
* This is working queue for runing a separate atask that will be responsible for work status (start, stop, timeouts).
|
||||
*/
|
||||
static struct workqueue_struct *me4600_workqueue;
|
||||
|
||||
#ifdef BOSCH
|
||||
me_device_t *me4600_pci_constructor(struct pci_dev *pci_device, int me_bosch_fw)
|
||||
#else //~BOSCH
|
||||
me_device_t *me4600_pci_constructor(struct pci_dev *pci_device)
|
||||
#endif //BOSCH
|
||||
{
|
||||
me4600_device_t *me4600_device;
|
||||
me_subdevice_t *subdevice;
|
||||
unsigned int version_idx;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
// Allocate structure for device instance.
|
||||
me4600_device = kmalloc(sizeof(me4600_device_t), GFP_KERNEL);
|
||||
|
||||
if (!me4600_device) {
|
||||
PERROR("Cannot get memory for ME-4600 device instance.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(me4600_device, 0, sizeof(me4600_device_t));
|
||||
|
||||
// Initialize base class structure.
|
||||
err = me_device_pci_init((me_device_t *) me4600_device, pci_device);
|
||||
|
||||
if (err) {
|
||||
kfree(me4600_device);
|
||||
PERROR("Cannot initialize device base class.\n");
|
||||
return NULL;
|
||||
}
|
||||
// Download the xilinx firmware.
|
||||
if (me4600_device->base.info.pci.device_id == PCI_DEVICE_ID_MEILHAUS_ME4610) { //Jekyll <=> me4610
|
||||
err =
|
||||
me_xilinx_download(me4600_device->base.info.pci.
|
||||
reg_bases[1],
|
||||
me4600_device->base.info.pci.
|
||||
reg_bases[5], &pci_device->dev,
|
||||
"me4610.bin");
|
||||
} else { // General me4600 firmware
|
||||
#ifdef BOSCH
|
||||
err =
|
||||
me_xilinx_download(me4600_device->base.info.pci.
|
||||
reg_bases[1],
|
||||
me4600_device->base.info.pci.
|
||||
reg_bases[5], &pci_device->dev,
|
||||
(me_bosch_fw) ? "me4600_bosch.bin" :
|
||||
"me4600.bin");
|
||||
#else //~BOSCH
|
||||
err =
|
||||
me_xilinx_download(me4600_device->base.info.pci.
|
||||
reg_bases[1],
|
||||
me4600_device->base.info.pci.
|
||||
reg_bases[5], &pci_device->dev,
|
||||
"me4600.bin");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (err) {
|
||||
me_device_deinit((me_device_t *) me4600_device);
|
||||
kfree(me4600_device);
|
||||
PERROR("Cannot download firmware.\n");
|
||||
return NULL;
|
||||
}
|
||||
// Get the index in the device version information table.
|
||||
version_idx =
|
||||
me4600_versions_get_device_index(me4600_device->base.info.pci.
|
||||
device_id);
|
||||
|
||||
// Initialize spin locks.
|
||||
spin_lock_init(&me4600_device->preload_reg_lock);
|
||||
|
||||
me4600_device->preload_flags = 0;
|
||||
|
||||
spin_lock_init(&me4600_device->dio_lock);
|
||||
spin_lock_init(&me4600_device->ai_ctrl_lock);
|
||||
spin_lock_init(&me4600_device->ctr_ctrl_reg_lock);
|
||||
spin_lock_init(&me4600_device->ctr_clk_src_reg_lock);
|
||||
|
||||
// Create digital input instances.
|
||||
for (i = 0; i < me4600_versions[version_idx].di_subdevices; i++) {
|
||||
subdevice =
|
||||
(me_subdevice_t *) me4600_di_constructor(me4600_device->
|
||||
base.info.pci.
|
||||
reg_bases[2],
|
||||
&me4600_device->
|
||||
dio_lock);
|
||||
|
||||
if (!subdevice) {
|
||||
me_device_deinit((me_device_t *) me4600_device);
|
||||
kfree(me4600_device);
|
||||
PERROR("Cannot get memory for subdevice.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
me_slist_add_subdevice_tail(&me4600_device->base.slist,
|
||||
subdevice);
|
||||
}
|
||||
|
||||
// Create digital output instances.
|
||||
for (i = 0; i < me4600_versions[version_idx].do_subdevices; i++) {
|
||||
subdevice =
|
||||
(me_subdevice_t *) me4600_do_constructor(me4600_device->
|
||||
base.info.pci.
|
||||
reg_bases[2],
|
||||
&me4600_device->
|
||||
dio_lock);
|
||||
|
||||
if (!subdevice) {
|
||||
me_device_deinit((me_device_t *) me4600_device);
|
||||
kfree(me4600_device);
|
||||
PERROR("Cannot get memory for subdevice.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
me_slist_add_subdevice_tail(&me4600_device->base.slist,
|
||||
subdevice);
|
||||
}
|
||||
|
||||
// Create digital input/output instances.
|
||||
for (i = 0; i < me4600_versions[version_idx].dio_subdevices; i++) {
|
||||
subdevice =
|
||||
(me_subdevice_t *) me4600_dio_constructor(me4600_device->
|
||||
base.info.pci.
|
||||
reg_bases[2],
|
||||
me4600_versions
|
||||
[version_idx].
|
||||
do_subdevices +
|
||||
me4600_versions
|
||||
[version_idx].
|
||||
di_subdevices + i,
|
||||
&me4600_device->
|
||||
dio_lock);
|
||||
|
||||
if (!subdevice) {
|
||||
me_device_deinit((me_device_t *) me4600_device);
|
||||
kfree(me4600_device);
|
||||
PERROR("Cannot get memory for subdevice.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
me_slist_add_subdevice_tail(&me4600_device->base.slist,
|
||||
subdevice);
|
||||
}
|
||||
|
||||
// Create analog input instances.
|
||||
for (i = 0; i < me4600_versions[version_idx].ai_subdevices; i++) {
|
||||
subdevice =
|
||||
(me_subdevice_t *) me4600_ai_constructor(me4600_device->
|
||||
base.info.pci.
|
||||
reg_bases[2],
|
||||
me4600_versions
|
||||
[version_idx].
|
||||
ai_channels,
|
||||
me4600_versions
|
||||
[version_idx].
|
||||
ai_ranges,
|
||||
me4600_versions
|
||||
[version_idx].
|
||||
ai_isolated,
|
||||
me4600_versions
|
||||
[version_idx].
|
||||
ai_sh,
|
||||
me4600_device->
|
||||
base.irq,
|
||||
&me4600_device->
|
||||
ai_ctrl_lock,
|
||||
me4600_workqueue);
|
||||
|
||||
if (!subdevice) {
|
||||
me_device_deinit((me_device_t *) me4600_device);
|
||||
kfree(me4600_device);
|
||||
PERROR("Cannot get memory for subdevice.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
me_slist_add_subdevice_tail(&me4600_device->base.slist,
|
||||
subdevice);
|
||||
}
|
||||
|
||||
// Create analog output instances.
|
||||
for (i = 0; i < me4600_versions[version_idx].ao_subdevices; i++) {
|
||||
#ifdef BOSCH
|
||||
subdevice =
|
||||
(me_subdevice_t *) me4600_ao_constructor(me4600_device->
|
||||
base.info.pci.
|
||||
reg_bases[2],
|
||||
&me4600_device->
|
||||
preload_reg_lock,
|
||||
&me4600_device->
|
||||
preload_flags, i,
|
||||
me4600_versions
|
||||
[version_idx].
|
||||
ao_fifo,
|
||||
me4600_device->
|
||||
base.irq);
|
||||
#else //~BOSCH
|
||||
subdevice =
|
||||
(me_subdevice_t *) me4600_ao_constructor(me4600_device->
|
||||
base.info.pci.
|
||||
reg_bases[2],
|
||||
&me4600_device->
|
||||
preload_reg_lock,
|
||||
&me4600_device->
|
||||
preload_flags, i,
|
||||
me4600_versions
|
||||
[version_idx].
|
||||
ao_fifo,
|
||||
me4600_device->
|
||||
base.irq,
|
||||
me4600_workqueue);
|
||||
#endif
|
||||
|
||||
if (!subdevice) {
|
||||
me_device_deinit((me_device_t *) me4600_device);
|
||||
kfree(me4600_device);
|
||||
PERROR("Cannot get memory for subdevice.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
me_slist_add_subdevice_tail(&me4600_device->base.slist,
|
||||
subdevice);
|
||||
}
|
||||
|
||||
// Create counter instances.
|
||||
for (i = 0; i < me4600_versions[version_idx].ctr_subdevices; i++) {
|
||||
subdevice =
|
||||
(me_subdevice_t *) me8254_constructor(me4600_device->base.
|
||||
info.pci.device_id,
|
||||
me4600_device->base.
|
||||
info.pci.reg_bases[3],
|
||||
0, i,
|
||||
&me4600_device->
|
||||
ctr_ctrl_reg_lock,
|
||||
&me4600_device->
|
||||
ctr_clk_src_reg_lock);
|
||||
|
||||
if (!subdevice) {
|
||||
me_device_deinit((me_device_t *) me4600_device);
|
||||
kfree(me4600_device);
|
||||
PERROR("Cannot get memory for subdevice.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
me_slist_add_subdevice_tail(&me4600_device->base.slist,
|
||||
subdevice);
|
||||
}
|
||||
|
||||
// Create external interrupt instances.
|
||||
for (i = 0; i < me4600_versions[version_idx].ext_irq_subdevices; i++) {
|
||||
subdevice =
|
||||
(me_subdevice_t *)
|
||||
me4600_ext_irq_constructor(me4600_device->base.info.pci.
|
||||
reg_bases[2],
|
||||
me4600_device->base.irq,
|
||||
&me4600_device->ai_ctrl_lock);
|
||||
|
||||
if (!subdevice) {
|
||||
me_device_deinit((me_device_t *) me4600_device);
|
||||
kfree(me4600_device);
|
||||
PERROR("Cannot get memory for subdevice.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
me_slist_add_subdevice_tail(&me4600_device->base.slist,
|
||||
subdevice);
|
||||
}
|
||||
|
||||
return (me_device_t *) me4600_device;
|
||||
}
|
||||
EXPORT_SYMBOL(me4600_pci_constructor);
|
||||
|
||||
// Init and exit of module.
|
||||
|
||||
static int __init me4600_init(void)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
#ifndef BOSCH
|
||||
me4600_workqueue = create_singlethread_workqueue("me4600");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit me4600_exit(void)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
#ifndef BOSCH
|
||||
flush_workqueue(me4600_workqueue);
|
||||
destroy_workqueue(me4600_workqueue);
|
||||
#endif
|
||||
}
|
||||
|
||||
module_init(me4600_init);
|
||||
module_exit(me4600_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-46xx Devices");
|
||||
MODULE_SUPPORTED_DEVICE("Meilhaus ME-46xx Devices");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,151 +0,0 @@
|
|||
/**
|
||||
* @file me4600_device.h
|
||||
*
|
||||
* @brief ME-4600 device class.
|
||||
* @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 _ME4600_DEVICE_H
|
||||
#define _ME4600_DEVICE_H
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include "medevice.h"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/**
|
||||
* @brief Structure holding ME-4600 device capabilities.
|
||||
*/
|
||||
typedef struct me4600_version {
|
||||
uint16_t device_id;
|
||||
unsigned int do_subdevices;
|
||||
unsigned int di_subdevices;
|
||||
unsigned int dio_subdevices;
|
||||
unsigned int ctr_subdevices;
|
||||
unsigned int ai_subdevices;
|
||||
unsigned int ai_channels;
|
||||
unsigned int ai_ranges;
|
||||
unsigned int ai_isolated;
|
||||
unsigned int ai_sh;
|
||||
unsigned int ao_subdevices;
|
||||
unsigned int ao_fifo; //How many devices have FIFO
|
||||
unsigned int ext_irq_subdevices;
|
||||
} me4600_version_t;
|
||||
|
||||
/**
|
||||
* @brief ME-4600 device capabilities.
|
||||
*/
|
||||
static me4600_version_t me4600_versions[] = {
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME4610, 0, 0, 4, 3, 1, 16, 1, 0, 0, 0, 0, 1},
|
||||
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME4650, 0, 0, 4, 0, 1, 16, 4, 0, 0, 0, 0, 1},
|
||||
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME4660, 0, 0, 4, 3, 1, 16, 4, 0, 0, 2, 0, 1},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME4660I, 1, 1, 2, 3, 1, 16, 4, 1, 0, 2, 0, 1},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME4660S, 0, 0, 4, 3, 1, 16, 4, 0, 1, 2, 0, 1},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME4660IS, 1, 1, 2, 3, 1, 16, 4, 1, 1, 2, 0, 1},
|
||||
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME4670, 0, 0, 4, 3, 1, 32, 4, 0, 0, 4, 0, 1},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME4670I, 1, 1, 2, 3, 1, 32, 4, 1, 0, 4, 0, 1},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME4670S, 0, 0, 4, 3, 1, 32, 4, 0, 1, 4, 0, 1},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME4670IS, 1, 1, 2, 3, 1, 32, 4, 1, 1, 4, 0, 1},
|
||||
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME4680, 0, 0, 4, 3, 1, 32, 4, 0, 0, 4, 4, 1},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME4680I, 1, 1, 2, 3, 1, 32, 4, 1, 0, 4, 4, 1},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME4680S, 0, 0, 4, 3, 1, 32, 4, 0, 1, 4, 4, 1},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME4680IS, 1, 1, 2, 3, 1, 32, 4, 1, 1, 4, 4, 1},
|
||||
|
||||
{0},
|
||||
};
|
||||
|
||||
#define ME4600_DEVICE_VERSIONS (ARRAY_SIZE(me4600_versions) - 1) /**< Returns the number of entries in #me4600_versions. */
|
||||
|
||||
/**
|
||||
* @brief Returns the index of the device entry in #me4600_versions.
|
||||
*
|
||||
* @param device_id The PCI device id of the device to query.
|
||||
* @return The index of the device in #me4600_versions.
|
||||
*/
|
||||
static inline unsigned int me4600_versions_get_device_index(uint16_t device_id)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < ME4600_DEVICE_VERSIONS; i++)
|
||||
if (me4600_versions[i].device_id == device_id)
|
||||
break;
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The ME-4600 device class structure.
|
||||
*/
|
||||
typedef struct me4600_device {
|
||||
me_device_t base; /**< The Meilhaus device base class. */
|
||||
|
||||
/* Child class attributes. */
|
||||
spinlock_t preload_reg_lock; /**< Guards the preload register of the anaolog output devices. */
|
||||
unsigned int preload_flags; /**< Used in conjunction with #preload_reg_lock. */
|
||||
spinlock_t dio_lock; /**< Locks the control register of the digital input/output subdevices. */
|
||||
spinlock_t ai_ctrl_lock; /**< Locks the control register of the analog input subdevice. */
|
||||
spinlock_t ctr_ctrl_reg_lock; /**< Locks the counter control register. */
|
||||
spinlock_t ctr_clk_src_reg_lock; /**< Not used on this device but needed for the me8254 subdevice constructor call. */
|
||||
} me4600_device_t;
|
||||
|
||||
/**
|
||||
* @brief The ME-4600 device class constructor.
|
||||
*
|
||||
* @param pci_device The pci device structure given by the PCI subsystem.
|
||||
* @param me_bosch_fw If set the device shall use the bosch firmware. (Only for special BOSCH build)
|
||||
*
|
||||
* @return On succes a new ME-4600 device instance. \n
|
||||
* NULL on error.
|
||||
*/
|
||||
|
||||
#ifdef BOSCH
|
||||
/**
|
||||
* @brief The ME-4600 device class constructor.
|
||||
*
|
||||
* @param pci_device The pci device structure given by the PCI subsystem.
|
||||
* @param me_bosch_fw If set the device shall use the bosch firmware.
|
||||
*
|
||||
* @return On succes a new ME-4600 device instance. \n
|
||||
* NULL on error.
|
||||
*/
|
||||
me_device_t *me4600_pci_constructor(struct pci_dev *pci_device, int me_bosch_fw)
|
||||
__attribute__ ((weak));
|
||||
#else //~BOSCH
|
||||
/**
|
||||
* @brief The ME-4600 device class constructor.
|
||||
*
|
||||
* @param pci_device The pci device structure given by the PCI subsystem.
|
||||
*
|
||||
* @return On succes a new ME-4600 device instance. \n
|
||||
* NULL on error.
|
||||
*/
|
||||
me_device_t *me4600_pci_constructor(struct pci_dev *pci_device)
|
||||
__attribute__ ((weak));
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,256 +0,0 @@
|
|||
/**
|
||||
* @file me4600_di.c
|
||||
*
|
||||
* @brief ME-4000 digital 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 <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "medefines.h"
|
||||
#include "meinternal.h"
|
||||
#include "meerror.h"
|
||||
|
||||
#include "medebug.h"
|
||||
#include "me4600_dio_reg.h"
|
||||
#include "me4600_di.h"
|
||||
|
||||
/*
|
||||
* Defines
|
||||
*/
|
||||
|
||||
/*
|
||||
* Functions
|
||||
*/
|
||||
|
||||
static int me4600_di_io_reset_subdevice(struct me_subdevice *subdevice,
|
||||
struct file *filep, int flags)
|
||||
{
|
||||
me4600_di_subdevice_t *instance;
|
||||
uint32_t mode;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me4600_di_subdevice_t *) subdevice;
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
mode = inl(instance->ctrl_reg);
|
||||
mode &= ~(ME4600_DIO_CTRL_BIT_MODE_2 | ME4600_DIO_CTRL_BIT_MODE_3); //0xFFF3
|
||||
outl(mode, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, mode);
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
|
||||
outl(0, instance->port_reg);
|
||||
PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->port_reg - instance->reg_base, 0);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me4600_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)
|
||||
{
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
me4600_di_subdevice_t *instance;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me4600_di_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
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) {
|
||||
} else {
|
||||
PERROR("Invalid port direction specified.\n");
|
||||
err = ME_ERRNO_INVALID_SINGLE_CONFIG;
|
||||
}
|
||||
} else {
|
||||
PERROR("Invalid channel number.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
PERROR("Invalid flags specified.\n");
|
||||
err = ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me4600_di_io_single_read(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int *value, int time_out, int flags)
|
||||
{
|
||||
me4600_di_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me4600_di_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
switch (flags) {
|
||||
case ME_IO_SINGLE_TYPE_DIO_BIT:
|
||||
if ((channel >= 0) && (channel < 8)) {
|
||||
*value = inl(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 = inl(instance->port_reg) & 0xFF;
|
||||
} else {
|
||||
PERROR("Invalid byte number specified.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
PERROR("Invalid flags specified.\n");
|
||||
err = ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me4600_di_query_number_channels(me_subdevice_t *subdevice,
|
||||
int *number)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*number = 8;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me4600_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 me4600_di_query_subdevice_caps(me_subdevice_t *subdevice, int *caps)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*caps = 0;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
me4600_di_subdevice_t *me4600_di_constructor(uint32_t reg_base,
|
||||
spinlock_t *ctrl_reg_lock)
|
||||
{
|
||||
me4600_di_subdevice_t *subdevice;
|
||||
int err;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
/* Allocate memory for subdevice instance */
|
||||
subdevice = kmalloc(sizeof(me4600_di_subdevice_t), GFP_KERNEL);
|
||||
|
||||
if (!subdevice) {
|
||||
PERROR("Cannot get memory for subdevice instance.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(subdevice, 0, sizeof(me4600_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);
|
||||
|
||||
subdevice->ctrl_reg_lock = ctrl_reg_lock;
|
||||
|
||||
/* Save the subdevice index */
|
||||
subdevice->port_reg = reg_base + ME4600_DIO_PORT_1_REG;
|
||||
subdevice->ctrl_reg = reg_base + ME4600_DIO_CTRL_REG;
|
||||
#ifdef MEDEBUG_DEBUG_REG
|
||||
subdevice->reg_base = reg_base;
|
||||
#endif
|
||||
|
||||
/* Overload base class methods. */
|
||||
subdevice->base.me_subdevice_io_reset_subdevice =
|
||||
me4600_di_io_reset_subdevice;
|
||||
subdevice->base.me_subdevice_io_single_config =
|
||||
me4600_di_io_single_config;
|
||||
subdevice->base.me_subdevice_io_single_read = me4600_di_io_single_read;
|
||||
subdevice->base.me_subdevice_query_number_channels =
|
||||
me4600_di_query_number_channels;
|
||||
subdevice->base.me_subdevice_query_subdevice_type =
|
||||
me4600_di_query_subdevice_type;
|
||||
subdevice->base.me_subdevice_query_subdevice_caps =
|
||||
me4600_di_query_subdevice_caps;
|
||||
|
||||
return subdevice;
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/**
|
||||
* @file me4600_di.h
|
||||
*
|
||||
* @brief ME-4000 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 _ME4600_DI_H_
|
||||
#define _ME4600_DI_H_
|
||||
|
||||
#include "mesubdevice.h"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/**
|
||||
* @brief The template subdevice class.
|
||||
*/
|
||||
typedef struct me4600_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. */
|
||||
spinlock_t *ctrl_reg_lock; /**< Spin lock to protect #ctrl_reg from concurrent access. */
|
||||
|
||||
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
|
||||
} me4600_di_subdevice_t;
|
||||
|
||||
/**
|
||||
* @brief The constructor to generate a ME-4000 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.
|
||||
*/
|
||||
me4600_di_subdevice_t *me4600_di_constructor(uint32_t reg_base,
|
||||
spinlock_t * ctrl_reg_lock);
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,510 +0,0 @@
|
|||
/**
|
||||
* @file me4600_dio.c
|
||||
*
|
||||
* @brief ME-4000 digital input/output 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 <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "medefines.h"
|
||||
#include "meinternal.h"
|
||||
#include "meerror.h"
|
||||
|
||||
#include "medebug.h"
|
||||
#include "me4600_dio_reg.h"
|
||||
#include "me4600_dio.h"
|
||||
|
||||
/*
|
||||
* Defines
|
||||
*/
|
||||
|
||||
/*
|
||||
* Functions
|
||||
*/
|
||||
|
||||
static int me4600_dio_io_reset_subdevice(struct me_subdevice *subdevice,
|
||||
struct file *filep, int flags)
|
||||
{
|
||||
me4600_dio_subdevice_t *instance;
|
||||
uint32_t mode;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me4600_dio_subdevice_t *) subdevice;
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
/* Set port to input mode */
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
mode = inl(instance->ctrl_reg);
|
||||
mode &=
|
||||
~((ME4600_DIO_CTRL_BIT_MODE_0 | ME4600_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2));
|
||||
outl(mode, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, mode);
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
|
||||
outl(0, instance->port_reg);
|
||||
PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->port_reg - instance->reg_base, 0);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me4600_dio_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)
|
||||
{
|
||||
me4600_dio_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
uint32_t mode;
|
||||
uint32_t size =
|
||||
flags & (ME_IO_SINGLE_CONFIG_DIO_BIT | ME_IO_SINGLE_CONFIG_DIO_BYTE
|
||||
| ME_IO_SINGLE_CONFIG_DIO_WORD |
|
||||
ME_IO_SINGLE_CONFIG_DIO_DWORD);
|
||||
uint32_t mask;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me4600_dio_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
mode = inl(instance->ctrl_reg);
|
||||
switch (size) {
|
||||
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) {
|
||||
mode &=
|
||||
~((ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2));
|
||||
} else if (single_config == ME_SINGLE_CONFIG_DIO_OUTPUT) {
|
||||
mode &=
|
||||
~((ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2));
|
||||
mode |=
|
||||
ME4600_DIO_CTRL_BIT_MODE_0 << (instance->
|
||||
dio_idx * 2);
|
||||
} else if (single_config == ME_SINGLE_CONFIG_DIO_MUX32M) {
|
||||
mask =
|
||||
(ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1) << (instance->
|
||||
dio_idx *
|
||||
2);
|
||||
mask |=
|
||||
ME4600_DIO_CTRL_BIT_FUNCTION_0 |
|
||||
ME4600_DIO_CTRL_BIT_FUNCTION_1;
|
||||
mask |=
|
||||
ME4600_DIO_CTRL_BIT_FIFO_HIGH_0 <<
|
||||
instance->dio_idx;
|
||||
mode &= ~mask;
|
||||
|
||||
if (ref == ME_REF_DIO_FIFO_LOW) {
|
||||
mode |=
|
||||
(ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2);
|
||||
mode |= ME4600_DIO_CTRL_BIT_FUNCTION_1;
|
||||
} else if (ref == ME_REF_DIO_FIFO_HIGH) {
|
||||
mode |=
|
||||
(ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2);
|
||||
mode |= ME4600_DIO_CTRL_BIT_FUNCTION_1;
|
||||
mode |=
|
||||
ME4600_DIO_CTRL_BIT_FIFO_HIGH_0 <<
|
||||
instance->dio_idx;
|
||||
} else {
|
||||
PERROR
|
||||
("Invalid port reference specified.\n");
|
||||
err = ME_ERRNO_INVALID_SINGLE_CONFIG;
|
||||
}
|
||||
} else if (single_config ==
|
||||
ME_SINGLE_CONFIG_DIO_DEMUX32) {
|
||||
mask =
|
||||
(ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1) << (instance->
|
||||
dio_idx *
|
||||
2);
|
||||
mask |=
|
||||
ME4600_DIO_CTRL_BIT_FUNCTION_0 |
|
||||
ME4600_DIO_CTRL_BIT_FUNCTION_1;
|
||||
mask |=
|
||||
ME4600_DIO_CTRL_BIT_FIFO_HIGH_0 <<
|
||||
instance->dio_idx;
|
||||
mode &= ~mask;
|
||||
|
||||
if (ref == ME_REF_DIO_FIFO_LOW) {
|
||||
mode |=
|
||||
(ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2);
|
||||
mode |= ME4600_DIO_CTRL_BIT_FUNCTION_0;
|
||||
} else if (ref == ME_REF_DIO_FIFO_HIGH) {
|
||||
mode |=
|
||||
(ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2);
|
||||
mode |= ME4600_DIO_CTRL_BIT_FUNCTION_0;
|
||||
mode |=
|
||||
ME4600_DIO_CTRL_BIT_FIFO_HIGH_0 <<
|
||||
instance->dio_idx;
|
||||
} else {
|
||||
PERROR
|
||||
("Invalid port reference specified.\n");
|
||||
err = ME_ERRNO_INVALID_SINGLE_CONFIG;
|
||||
}
|
||||
} else if (single_config ==
|
||||
ME_SINGLE_CONFIG_DIO_BIT_PATTERN) {
|
||||
mask =
|
||||
(ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1) << (instance->
|
||||
dio_idx *
|
||||
2);
|
||||
mask |=
|
||||
ME4600_DIO_CTRL_BIT_FUNCTION_0 |
|
||||
ME4600_DIO_CTRL_BIT_FUNCTION_1;
|
||||
mask |=
|
||||
ME4600_DIO_CTRL_BIT_FIFO_HIGH_0 <<
|
||||
instance->dio_idx;
|
||||
mode &= ~mask;
|
||||
|
||||
if (ref == ME_REF_DIO_FIFO_LOW) {
|
||||
mode |=
|
||||
(ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2);
|
||||
} else if (ref == ME_REF_DIO_FIFO_HIGH) {
|
||||
mode |=
|
||||
(ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2);
|
||||
mode |=
|
||||
ME4600_DIO_CTRL_BIT_FIFO_HIGH_0 <<
|
||||
instance->dio_idx;
|
||||
} else {
|
||||
PERROR
|
||||
("Invalid port reference specified.\n");
|
||||
err = ME_ERRNO_INVALID_SINGLE_CONFIG;
|
||||
}
|
||||
} else {
|
||||
PERROR
|
||||
("Invalid port configuration specified.\n");
|
||||
err = ME_ERRNO_INVALID_SINGLE_CONFIG;
|
||||
}
|
||||
} else {
|
||||
PERROR("Invalid channel number.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
PERROR("Invalid flags.\n");
|
||||
err = ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
outl(mode, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, mode);
|
||||
}
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me4600_dio_io_single_read(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int *value, int time_out, int flags)
|
||||
{
|
||||
me4600_dio_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
uint32_t mode;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me4600_dio_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
switch (flags) {
|
||||
case ME_IO_SINGLE_TYPE_DIO_BIT:
|
||||
if ((channel >= 0) && (channel < 8)) {
|
||||
mode =
|
||||
inl(instance->
|
||||
ctrl_reg) & ((ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2));
|
||||
if ((mode ==
|
||||
(ME4600_DIO_CTRL_BIT_MODE_0 <<
|
||||
(instance->dio_idx * 2))) || !mode) {
|
||||
*value =
|
||||
inl(instance->port_reg) & (0x1 << channel);
|
||||
} else {
|
||||
PERROR("Port not in output or input mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_CONFIG;
|
||||
}
|
||||
} 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) {
|
||||
mode =
|
||||
inl(instance->
|
||||
ctrl_reg) & ((ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2));
|
||||
if ((mode ==
|
||||
(ME4600_DIO_CTRL_BIT_MODE_0 <<
|
||||
(instance->dio_idx * 2))) || !mode) {
|
||||
*value = inl(instance->port_reg) & 0xFF;
|
||||
} else {
|
||||
PERROR("Port not in output or input mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_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->ctrl_reg_lock);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me4600_dio_io_single_write(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int value, int time_out, int flags)
|
||||
{
|
||||
me4600_dio_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
uint32_t mode;
|
||||
uint32_t byte;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me4600_dio_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
switch (flags) {
|
||||
case ME_IO_SINGLE_TYPE_DIO_BIT:
|
||||
if ((channel >= 0) && (channel < 8)) {
|
||||
mode =
|
||||
inl(instance->
|
||||
ctrl_reg) & ((ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2));
|
||||
|
||||
if (mode ==
|
||||
(ME4600_DIO_CTRL_BIT_MODE_0 <<
|
||||
(instance->dio_idx * 2))) {
|
||||
byte = inl(instance->port_reg) & 0xFF;
|
||||
|
||||
if (value)
|
||||
byte |= 0x1 << channel;
|
||||
else
|
||||
byte &= ~(0x1 << channel);
|
||||
|
||||
outl(byte, instance->port_reg);
|
||||
} else {
|
||||
PERROR("Port not in output or input mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_CONFIG;
|
||||
}
|
||||
} 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) {
|
||||
mode =
|
||||
inl(instance->
|
||||
ctrl_reg) & ((ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2));
|
||||
|
||||
if (mode ==
|
||||
(ME4600_DIO_CTRL_BIT_MODE_0 <<
|
||||
(instance->dio_idx * 2))) {
|
||||
outl(value, instance->port_reg);
|
||||
} else {
|
||||
PERROR("Port not in output or input mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_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->ctrl_reg_lock);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me4600_dio_query_number_channels(me_subdevice_t *subdevice,
|
||||
int *number)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*number = 8;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me4600_dio_query_subdevice_type(me_subdevice_t *subdevice,
|
||||
int *type, int *subtype)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*type = ME_TYPE_DIO;
|
||||
*subtype = ME_SUBTYPE_SINGLE;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me4600_dio_query_subdevice_caps(me_subdevice_t *subdevice,
|
||||
int *caps)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*caps = ME_CAPS_DIO_DIR_BYTE;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
me4600_dio_subdevice_t *me4600_dio_constructor(uint32_t reg_base,
|
||||
unsigned int dio_idx,
|
||||
spinlock_t *ctrl_reg_lock)
|
||||
{
|
||||
me4600_dio_subdevice_t *subdevice;
|
||||
int err;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
/* Allocate memory for subdevice instance */
|
||||
subdevice = kmalloc(sizeof(me4600_dio_subdevice_t), GFP_KERNEL);
|
||||
|
||||
if (!subdevice) {
|
||||
PERROR("Cannot get memory for subdevice instance.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(subdevice, 0, sizeof(me4600_dio_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);
|
||||
subdevice->ctrl_reg_lock = ctrl_reg_lock;
|
||||
|
||||
/* Save digital i/o index */
|
||||
subdevice->dio_idx = dio_idx;
|
||||
|
||||
/* Save the subdevice index */
|
||||
subdevice->ctrl_reg = reg_base + ME4600_DIO_CTRL_REG;
|
||||
subdevice->port_reg = reg_base + ME4600_DIO_PORT_REG + (dio_idx * 4);
|
||||
#ifdef MEDEBUG_DEBUG_REG
|
||||
subdevice->reg_base = reg_base;
|
||||
#endif
|
||||
|
||||
/* Overload base class methods. */
|
||||
subdevice->base.me_subdevice_io_reset_subdevice =
|
||||
me4600_dio_io_reset_subdevice;
|
||||
subdevice->base.me_subdevice_io_single_config =
|
||||
me4600_dio_io_single_config;
|
||||
subdevice->base.me_subdevice_io_single_read = me4600_dio_io_single_read;
|
||||
subdevice->base.me_subdevice_io_single_write =
|
||||
me4600_dio_io_single_write;
|
||||
subdevice->base.me_subdevice_query_number_channels =
|
||||
me4600_dio_query_number_channels;
|
||||
subdevice->base.me_subdevice_query_subdevice_type =
|
||||
me4600_dio_query_subdevice_type;
|
||||
subdevice->base.me_subdevice_query_subdevice_caps =
|
||||
me4600_dio_query_subdevice_caps;
|
||||
|
||||
return subdevice;
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
/**
|
||||
* @file me4600_dio.h
|
||||
*
|
||||
* @brief ME-4000 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 _ME4600_DIO_H_
|
||||
#define _ME4600_DIO_H_
|
||||
|
||||
#include "mesubdevice.h"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/**
|
||||
* @brief The template subdevice class.
|
||||
*/
|
||||
typedef struct me4600_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. */
|
||||
|
||||
/* Registers */
|
||||
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
|
||||
} me4600_dio_subdevice_t;
|
||||
|
||||
/**
|
||||
* @brief The constructor to generate a ME-4000 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.
|
||||
*/
|
||||
me4600_dio_subdevice_t *me4600_dio_constructor(uint32_t reg_base,
|
||||
unsigned int dio_idx,
|
||||
spinlock_t * ctrl_reg_lock);
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,63 +0,0 @@
|
|||
/**
|
||||
* @file me4600_dio_reg.h
|
||||
*
|
||||
* @brief ME-4000 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 _ME4600_DIO_REG_H_
|
||||
#define _ME4600_DIO_REG_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define ME4600_DIO_PORT_0_REG 0xA0 /**< Port 0 register. */
|
||||
#define ME4600_DIO_PORT_1_REG 0xA4 /**< Port 1 register. */
|
||||
#define ME4600_DIO_PORT_2_REG 0xA8 /**< Port 2 register. */
|
||||
#define ME4600_DIO_PORT_3_REG 0xAC /**< Port 3 register. */
|
||||
|
||||
#define ME4600_DIO_DIR_REG 0xB0 /**< Direction register. */
|
||||
#define ME4600_DIO_PORT_REG ME4600_DIO_PORT_0_REG /**< Base for port's register. */
|
||||
|
||||
#define ME4600_DIO_CTRL_REG 0xB8 /**< Control register. */
|
||||
/** Port A - DO */
|
||||
#define ME4600_DIO_CTRL_BIT_MODE_0 0x0001
|
||||
#define ME4600_DIO_CTRL_BIT_MODE_1 0x0002
|
||||
/** Port B - DI */
|
||||
#define ME4600_DIO_CTRL_BIT_MODE_2 0x0004
|
||||
#define ME4600_DIO_CTRL_BIT_MODE_3 0x0008
|
||||
/** Port C - DIO */
|
||||
#define ME4600_DIO_CTRL_BIT_MODE_4 0x0010
|
||||
#define ME4600_DIO_CTRL_BIT_MODE_5 0x0020
|
||||
/** Port D - DIO */
|
||||
#define ME4600_DIO_CTRL_BIT_MODE_6 0x0040
|
||||
#define ME4600_DIO_CTRL_BIT_MODE_7 0x0080
|
||||
|
||||
#define ME4600_DIO_CTRL_BIT_FUNCTION_0 0x0100
|
||||
#define ME4600_DIO_CTRL_BIT_FUNCTION_1 0x0200
|
||||
|
||||
#define ME4600_DIO_CTRL_BIT_FIFO_HIGH_0 0x0400
|
||||
#define ME4600_DIO_CTRL_BIT_FIFO_HIGH_1 0x0800
|
||||
#define ME4600_DIO_CTRL_BIT_FIFO_HIGH_2 0x1000
|
||||
#define ME4600_DIO_CTRL_BIT_FIFO_HIGH_3 0x2000
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,433 +0,0 @@
|
|||
/**
|
||||
* @file me4600_do.c
|
||||
*
|
||||
* @brief ME-4000 digital output 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 <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "medefines.h"
|
||||
#include "meinternal.h"
|
||||
#include "meerror.h"
|
||||
|
||||
#include "medebug.h"
|
||||
#include "me4600_dio_reg.h"
|
||||
#include "me4600_do.h"
|
||||
|
||||
/*
|
||||
* Defines
|
||||
*/
|
||||
|
||||
/*
|
||||
* Functions
|
||||
*/
|
||||
|
||||
static int me4600_do_io_reset_subdevice(struct me_subdevice *subdevice,
|
||||
struct file *filep, int flags)
|
||||
{
|
||||
me4600_do_subdevice_t *instance;
|
||||
uint32_t mode;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me4600_do_subdevice_t *) subdevice;
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
/* Set port to output mode */
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
mode = inl(instance->ctrl_reg);
|
||||
mode &= ~ME4600_DIO_CTRL_BIT_MODE_1; //0xFFFD
|
||||
mode |= ME4600_DIO_CTRL_BIT_MODE_0; //0x1
|
||||
outl(mode, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, mode);
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
|
||||
outl(0, instance->port_reg);
|
||||
PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->port_reg - instance->reg_base, 0);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me4600_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)
|
||||
{
|
||||
me4600_do_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
uint32_t mode;
|
||||
int size =
|
||||
flags & (ME_IO_SINGLE_CONFIG_DIO_BIT | ME_IO_SINGLE_CONFIG_DIO_BYTE
|
||||
| ME_IO_SINGLE_CONFIG_DIO_WORD |
|
||||
ME_IO_SINGLE_CONFIG_DIO_DWORD);
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me4600_do_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
mode = inl(instance->ctrl_reg);
|
||||
|
||||
switch (size) {
|
||||
case ME_IO_SINGLE_CONFIG_NO_FLAGS:
|
||||
case ME_IO_SINGLE_CONFIG_DIO_BYTE:
|
||||
if (channel == 0) {
|
||||
if (single_config == ME_SINGLE_CONFIG_DIO_OUTPUT) {
|
||||
mode &= ~(ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1);
|
||||
mode |= (ME4600_DIO_CTRL_BIT_MODE_0);
|
||||
} else if (single_config == ME_SINGLE_CONFIG_DIO_MUX32M) {
|
||||
mode &= ~(ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1 |
|
||||
ME4600_DIO_CTRL_BIT_FUNCTION_0 |
|
||||
ME4600_DIO_CTRL_BIT_FUNCTION_1 |
|
||||
ME4600_DIO_CTRL_BIT_FIFO_HIGH_0);
|
||||
|
||||
if (ref == ME_REF_DIO_FIFO_LOW) {
|
||||
mode |= (ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1 |
|
||||
ME4600_DIO_CTRL_BIT_FUNCTION_1);
|
||||
} else if (ref == ME_REF_DIO_FIFO_HIGH) {
|
||||
mode |= (ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1 |
|
||||
ME4600_DIO_CTRL_BIT_FUNCTION_1
|
||||
|
|
||||
ME4600_DIO_CTRL_BIT_FIFO_HIGH_0);
|
||||
} else {
|
||||
PERROR
|
||||
("Invalid port reference specified.\n");
|
||||
err = ME_ERRNO_INVALID_SINGLE_CONFIG;
|
||||
}
|
||||
} else if (single_config ==
|
||||
ME_SINGLE_CONFIG_DIO_DEMUX32) {
|
||||
mode &=
|
||||
~(ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1 |
|
||||
ME4600_DIO_CTRL_BIT_FUNCTION_0 |
|
||||
ME4600_DIO_CTRL_BIT_FUNCTION_1 |
|
||||
ME4600_DIO_CTRL_BIT_FIFO_HIGH_0);
|
||||
|
||||
if (ref == ME_REF_DIO_FIFO_LOW) {
|
||||
mode |= (ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1 |
|
||||
ME4600_DIO_CTRL_BIT_FUNCTION_0);
|
||||
} else if (ref == ME_REF_DIO_FIFO_HIGH) {
|
||||
mode |= (ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1 |
|
||||
ME4600_DIO_CTRL_BIT_FUNCTION_0
|
||||
|
|
||||
ME4600_DIO_CTRL_BIT_FIFO_HIGH_0);
|
||||
} else {
|
||||
PERROR
|
||||
("Invalid port reference specified.\n");
|
||||
err = ME_ERRNO_INVALID_SINGLE_CONFIG;
|
||||
}
|
||||
} else if (single_config ==
|
||||
ME_SINGLE_CONFIG_DIO_BIT_PATTERN) {
|
||||
mode &=
|
||||
~(ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1 |
|
||||
ME4600_DIO_CTRL_BIT_FUNCTION_0 |
|
||||
ME4600_DIO_CTRL_BIT_FUNCTION_1 |
|
||||
ME4600_DIO_CTRL_BIT_FIFO_HIGH_0);
|
||||
|
||||
if (ref == ME_REF_DIO_FIFO_LOW) {
|
||||
mode |= (ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1);
|
||||
} else if (ref == ME_REF_DIO_FIFO_HIGH) {
|
||||
mode |= (ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1 |
|
||||
ME4600_DIO_CTRL_BIT_FIFO_HIGH_0);
|
||||
} else {
|
||||
PERROR
|
||||
("Invalid port reference specified.\n");
|
||||
err = ME_ERRNO_INVALID_SINGLE_CONFIG;
|
||||
}
|
||||
} else {
|
||||
PERROR("Invalid port direction specified.\n");
|
||||
err = ME_ERRNO_INVALID_SINGLE_CONFIG;
|
||||
}
|
||||
} else {
|
||||
PERROR("Invalid channel number.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
PERROR("Invalid flags specified.\n");
|
||||
err = ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
outl(mode, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, mode);
|
||||
}
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me4600_do_io_single_read(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int *value, int time_out, int flags)
|
||||
{
|
||||
me4600_do_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
uint32_t mode;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me4600_do_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
mode =
|
||||
inl(instance->
|
||||
ctrl_reg) & (ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1);
|
||||
|
||||
if (mode == ME4600_DIO_CTRL_BIT_MODE_0) {
|
||||
switch (flags) {
|
||||
case ME_IO_SINGLE_TYPE_DIO_BIT:
|
||||
if ((channel >= 0) && (channel < 8)) {
|
||||
*value =
|
||||
inl(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 = inl(instance->port_reg) & 0xFF;
|
||||
} else {
|
||||
PERROR("Invalid byte number specified.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
PERROR("Invalid flags specified.\n");
|
||||
err = ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
} else {
|
||||
PERROR("Port not in output mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_CONFIG;
|
||||
}
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me4600_do_io_single_write(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int value, int time_out, int flags)
|
||||
{
|
||||
me4600_do_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
uint32_t byte;
|
||||
uint32_t mode;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me4600_do_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
mode =
|
||||
inl(instance->
|
||||
ctrl_reg) & (ME4600_DIO_CTRL_BIT_MODE_0 |
|
||||
ME4600_DIO_CTRL_BIT_MODE_1);
|
||||
|
||||
if (mode == ME4600_DIO_CTRL_BIT_MODE_0) {
|
||||
switch (flags) {
|
||||
|
||||
case ME_IO_SINGLE_TYPE_DIO_BIT:
|
||||
if ((channel >= 0) && (channel < 8)) {
|
||||
byte = inl(instance->port_reg) & 0xFF;
|
||||
|
||||
if (value)
|
||||
byte |= 0x1 << channel;
|
||||
else
|
||||
byte &= ~(0x1 << channel);
|
||||
|
||||
outl(byte, 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) {
|
||||
outl(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;
|
||||
}
|
||||
} else {
|
||||
PERROR("Port not in output mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_CONFIG;
|
||||
}
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me4600_do_query_number_channels(me_subdevice_t *subdevice,
|
||||
int *number)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*number = 8;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me4600_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 me4600_do_query_subdevice_caps(me_subdevice_t *subdevice, int *caps)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*caps = 0;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
me4600_do_subdevice_t *me4600_do_constructor(uint32_t reg_base,
|
||||
spinlock_t *ctrl_reg_lock)
|
||||
{
|
||||
me4600_do_subdevice_t *subdevice;
|
||||
int err;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
/* Allocate memory for subdevice instance */
|
||||
subdevice = kmalloc(sizeof(me4600_do_subdevice_t), GFP_KERNEL);
|
||||
|
||||
if (!subdevice) {
|
||||
PERROR("Cannot get memory for subdevice instance.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(subdevice, 0, sizeof(me4600_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);
|
||||
|
||||
subdevice->ctrl_reg_lock = ctrl_reg_lock;
|
||||
|
||||
/* Save the subdevice index */
|
||||
subdevice->ctrl_reg = reg_base + ME4600_DIO_CTRL_REG;
|
||||
subdevice->port_reg = reg_base + ME4600_DIO_PORT_0_REG;
|
||||
#ifdef MEDEBUG_DEBUG_REG
|
||||
subdevice->reg_base = reg_base;
|
||||
#endif
|
||||
|
||||
/* Overload base class methods. */
|
||||
subdevice->base.me_subdevice_io_reset_subdevice =
|
||||
me4600_do_io_reset_subdevice;
|
||||
subdevice->base.me_subdevice_io_single_config =
|
||||
me4600_do_io_single_config;
|
||||
subdevice->base.me_subdevice_io_single_read = me4600_do_io_single_read;
|
||||
subdevice->base.me_subdevice_io_single_write =
|
||||
me4600_do_io_single_write;
|
||||
subdevice->base.me_subdevice_query_number_channels =
|
||||
me4600_do_query_number_channels;
|
||||
subdevice->base.me_subdevice_query_subdevice_type =
|
||||
me4600_do_query_subdevice_type;
|
||||
subdevice->base.me_subdevice_query_subdevice_caps =
|
||||
me4600_do_query_subdevice_caps;
|
||||
|
||||
return subdevice;
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/**
|
||||
* @file me4600_do.h
|
||||
*
|
||||
* @brief ME-4000 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 _ME4600_DO_H_
|
||||
#define _ME4600_DO_H_
|
||||
|
||||
#include "mesubdevice.h"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/**
|
||||
* @brief The template subdevice class.
|
||||
*/
|
||||
typedef struct me4600_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. */
|
||||
spinlock_t *ctrl_reg_lock; /**< Spin lock to protect #ctrl_reg from concurrent access. */
|
||||
|
||||
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
|
||||
} me4600_do_subdevice_t;
|
||||
|
||||
/**
|
||||
* @brief The constructor to generate a ME-4000 digital output 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.
|
||||
*/
|
||||
me4600_do_subdevice_t *me4600_do_constructor(uint32_t reg_base,
|
||||
spinlock_t * ctrl_reg_lock);
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,457 +0,0 @@
|
|||
/**
|
||||
* @file me4600_ext_irq.c
|
||||
*
|
||||
* @brief ME-4000 external interrupt 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 <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "medefines.h"
|
||||
#include "meinternal.h"
|
||||
#include "meerror.h"
|
||||
|
||||
#include "medebug.h"
|
||||
#include "meids.h"
|
||||
#include "me4600_reg.h"
|
||||
#include "me4600_ai_reg.h"
|
||||
#include "me4600_ext_irq_reg.h"
|
||||
#include "me4600_ext_irq.h"
|
||||
|
||||
/*
|
||||
* Defines
|
||||
*/
|
||||
|
||||
/*
|
||||
* Functions
|
||||
*/
|
||||
|
||||
static int me4600_ext_irq_io_irq_start(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int irq_source,
|
||||
int irq_edge, int irq_arg, int flags)
|
||||
{
|
||||
me4600_ext_irq_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
unsigned long cpu_flags;
|
||||
uint32_t tmp;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me4600_ext_irq_subdevice_t *) subdevice;
|
||||
|
||||
if (flags & ~ME_IO_IRQ_START_DIO_BIT) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if ((irq_edge != ME_IRQ_EDGE_RISING)
|
||||
&& (irq_edge != ME_IRQ_EDGE_FALLING)
|
||||
&& (irq_edge != ME_IRQ_EDGE_ANY)
|
||||
) {
|
||||
PERROR("Invalid irq edge specified.\n");
|
||||
return ME_ERRNO_INVALID_IRQ_EDGE;
|
||||
}
|
||||
|
||||
if (irq_source != ME_IRQ_SOURCE_DIO_LINE) {
|
||||
PERROR("Invalid irq source specified.\n");
|
||||
return ME_ERRNO_INVALID_IRQ_SOURCE;
|
||||
}
|
||||
|
||||
if (channel) {
|
||||
PERROR("Invalid channel specified.\n");
|
||||
return ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
tmp = 0x0; //inl(instance->ext_irq_config_reg);
|
||||
|
||||
if (irq_edge == ME_IRQ_EDGE_RISING) {
|
||||
//tmp &= ~ME4600_EXT_IRQ_CONFIG_MASK;
|
||||
//tmp |= ME4600_EXT_IRQ_CONFIG_MASK_RISING;
|
||||
} else if (irq_edge == ME_IRQ_EDGE_FALLING) {
|
||||
//tmp &= ~ME4600_EXT_IRQ_CONFIG_MASK;
|
||||
//tmp |= ME4600_EXT_IRQ_CONFIG_MASK_FALLING;
|
||||
tmp = ME4600_EXT_IRQ_CONFIG_MASK_FALLING;
|
||||
} else if (irq_edge == ME_IRQ_EDGE_ANY) {
|
||||
//tmp &= ~ME4600_EXT_IRQ_CONFIG_MASK;
|
||||
//tmp |= ME4600_EXT_IRQ_CONFIG_MASK_ANY;
|
||||
tmp = ME4600_EXT_IRQ_CONFIG_MASK_ANY;
|
||||
}
|
||||
|
||||
outl(tmp, instance->ext_irq_config_reg);
|
||||
PDEBUG_REG("ext_irq_config_reg outl(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->ext_irq_config_reg - instance->reg_base, tmp);
|
||||
|
||||
spin_lock_irqsave(instance->ctrl_reg_lock, cpu_flags);
|
||||
tmp = inl(instance->ctrl_reg);
|
||||
tmp &= ~(ME4600_AI_CTRL_BIT_EX_IRQ | ME4600_AI_CTRL_BIT_EX_IRQ_RESET);
|
||||
tmp |= ME4600_AI_CTRL_BIT_EX_IRQ;
|
||||
outl(tmp, instance->ctrl_reg);
|
||||
spin_unlock_irqrestore(instance->ctrl_reg_lock, cpu_flags);
|
||||
instance->rised = 0;
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me4600_ext_irq_io_irq_wait(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int *irq_count,
|
||||
int *value, int time_out, int flags)
|
||||
{
|
||||
me4600_ext_irq_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
long t = 0;
|
||||
unsigned long cpu_flags;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me4600_ext_irq_subdevice_t *) subdevice;
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (channel) {
|
||||
PERROR("Invalid channel specified.\n");
|
||||
return ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
|
||||
if (time_out < 0) {
|
||||
PERROR("Invalid time_out specified.\n");
|
||||
return ME_ERRNO_INVALID_TIMEOUT;
|
||||
}
|
||||
|
||||
if (time_out) {
|
||||
t = (time_out * HZ) / 1000;
|
||||
|
||||
if (t == 0)
|
||||
t = 1;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
if (instance->rised <= 0) {
|
||||
instance->rised = 0;
|
||||
if (time_out) {
|
||||
t = wait_event_interruptible_timeout(instance->
|
||||
wait_queue,
|
||||
(instance->rised !=
|
||||
0), t);
|
||||
|
||||
if (t == 0) {
|
||||
PERROR
|
||||
("Wait on external interrupt timed out.\n");
|
||||
err = ME_ERRNO_TIMEOUT;
|
||||
}
|
||||
} else {
|
||||
wait_event_interruptible(instance->wait_queue,
|
||||
(instance->rised != 0));
|
||||
}
|
||||
|
||||
if (instance->rised < 0) {
|
||||
PERROR("Wait on interrupt aborted by user.\n");
|
||||
err = ME_ERRNO_CANCELLED;
|
||||
}
|
||||
}
|
||||
|
||||
if (signal_pending(current)) {
|
||||
PERROR("Wait on external interrupt aborted by signal.\n");
|
||||
err = ME_ERRNO_SIGNAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
|
||||
instance->rised = 0;
|
||||
*irq_count = instance->count;
|
||||
*value = instance->value;
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me4600_ext_irq_io_irq_stop(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel, int flags)
|
||||
{
|
||||
me4600_ext_irq_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
unsigned long cpu_flags;
|
||||
uint32_t tmp;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me4600_ext_irq_subdevice_t *) subdevice;
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (channel) {
|
||||
PERROR("Invalid channel specified.\n");
|
||||
return ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
tmp = inl(instance->ctrl_reg);
|
||||
tmp &= ~(ME4600_AI_CTRL_BIT_EX_IRQ | ME4600_AI_CTRL_BIT_EX_IRQ_RESET);
|
||||
outl(tmp, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_regv outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, tmp);
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
instance->rised = -1;
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
|
||||
wake_up_interruptible_all(&instance->wait_queue);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me4600_ext_irq_io_reset_subdevice(me_subdevice_t *subdevice,
|
||||
struct file *filep, int flags)
|
||||
{
|
||||
me4600_ext_irq_subdevice_t *instance;
|
||||
unsigned long cpu_flags;
|
||||
uint32_t tmp;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me4600_ext_irq_subdevice_t *) subdevice;
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
tmp = inl(instance->ctrl_reg);
|
||||
tmp &= ~(ME4600_AI_CTRL_BIT_EX_IRQ | ME4600_AI_CTRL_BIT_EX_IRQ_RESET);
|
||||
outl(tmp, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_regv outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, tmp);
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
instance->rised = -1;
|
||||
instance->count = 0;
|
||||
outl(ME4600_EXT_IRQ_CONFIG_MASK_ANY, instance->ext_irq_config_reg);
|
||||
PDEBUG_REG("ext_irq_config_reg outl(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->ext_irq_config_reg - instance->reg_base,
|
||||
ME4600_EXT_IRQ_CONFIG_MASK_ANY);
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
|
||||
wake_up_interruptible_all(&instance->wait_queue);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static void me4600_ext_irq_destructor(struct me_subdevice *subdevice)
|
||||
{
|
||||
me4600_ext_irq_subdevice_t *instance;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
instance = (me4600_ext_irq_subdevice_t *) subdevice;
|
||||
me_subdevice_deinit(&instance->base);
|
||||
free_irq(instance->irq, instance);
|
||||
kfree(instance);
|
||||
}
|
||||
|
||||
static int me4600_ext_irq_query_number_channels(me_subdevice_t *subdevice,
|
||||
int *number)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*number = 1;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me4600_ext_irq_query_subdevice_type(me_subdevice_t *subdevice,
|
||||
int *type, int *subtype)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*type = ME_TYPE_EXT_IRQ;
|
||||
*subtype = ME_SUBTYPE_SINGLE;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me4600_ext_irq_query_subdevice_caps(me_subdevice_t *subdevice,
|
||||
int *caps)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*caps =
|
||||
ME_CAPS_EXT_IRQ_EDGE_RISING | ME_CAPS_EXT_IRQ_EDGE_FALLING |
|
||||
ME_CAPS_EXT_IRQ_EDGE_ANY;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static irqreturn_t me4600_ext_irq_isr(int irq, void *dev_id)
|
||||
{
|
||||
me4600_ext_irq_subdevice_t *instance;
|
||||
uint32_t ctrl;
|
||||
uint32_t irq_status;
|
||||
|
||||
instance = (me4600_ext_irq_subdevice_t *) dev_id;
|
||||
|
||||
if (irq != instance->irq) {
|
||||
PERROR("Incorrect interrupt num: %d.\n", irq);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
irq_status = inl(instance->irq_status_reg);
|
||||
if (!(irq_status & ME4600_IRQ_STATUS_BIT_EX)) {
|
||||
PINFO("%ld Shared interrupt. %s(): irq_status_reg=0x%04X\n",
|
||||
jiffies, __func__, irq_status);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
instance->rised = 1;
|
||||
instance->value = inl(instance->ext_irq_value_reg);
|
||||
instance->count++;
|
||||
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
ctrl = inl(instance->ctrl_reg);
|
||||
ctrl |= ME4600_AI_CTRL_BIT_EX_IRQ_RESET;
|
||||
outl(ctrl, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, ctrl);
|
||||
ctrl &= ~ME4600_AI_CTRL_BIT_EX_IRQ_RESET;
|
||||
outl(ctrl, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, ctrl);
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
wake_up_interruptible_all(&instance->wait_queue);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
me4600_ext_irq_subdevice_t *me4600_ext_irq_constructor(uint32_t reg_base,
|
||||
int irq,
|
||||
spinlock_t *
|
||||
ctrl_reg_lock)
|
||||
{
|
||||
me4600_ext_irq_subdevice_t *subdevice;
|
||||
int err;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
/* Allocate memory for subdevice instance */
|
||||
subdevice = kmalloc(sizeof(me4600_ext_irq_subdevice_t), GFP_KERNEL);
|
||||
|
||||
if (!subdevice) {
|
||||
PERROR("Cannot get memory for subdevice instance.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(subdevice, 0, sizeof(me4600_ext_irq_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);
|
||||
|
||||
subdevice->ctrl_reg_lock = ctrl_reg_lock;
|
||||
|
||||
/* Initialize wait queue */
|
||||
init_waitqueue_head(&subdevice->wait_queue);
|
||||
|
||||
/* Register interrupt */
|
||||
subdevice->irq = irq;
|
||||
|
||||
if (request_irq(subdevice->irq, me4600_ext_irq_isr,
|
||||
IRQF_DISABLED | IRQF_SHARED,
|
||||
ME4600_NAME, subdevice)) {
|
||||
PERROR("Cannot register interrupt.\n");
|
||||
kfree(subdevice);
|
||||
return NULL;
|
||||
}
|
||||
PINFO("Registered irq=%d.\n", subdevice->irq);
|
||||
|
||||
/* Initialize registers */
|
||||
subdevice->irq_status_reg = reg_base + ME4600_IRQ_STATUS_REG;
|
||||
subdevice->ctrl_reg = reg_base + ME4600_AI_CTRL_REG;
|
||||
subdevice->ext_irq_config_reg = reg_base + ME4600_EXT_IRQ_CONFIG_REG;
|
||||
subdevice->ext_irq_value_reg = reg_base + ME4600_EXT_IRQ_VALUE_REG;
|
||||
#ifdef MEDEBUG_DEBUG_REG
|
||||
subdevice->reg_base = reg_base;
|
||||
#endif
|
||||
|
||||
/* Override base class methods. */
|
||||
subdevice->base.me_subdevice_destructor = me4600_ext_irq_destructor;
|
||||
subdevice->base.me_subdevice_io_reset_subdevice =
|
||||
me4600_ext_irq_io_reset_subdevice;
|
||||
subdevice->base.me_subdevice_io_irq_start = me4600_ext_irq_io_irq_start;
|
||||
subdevice->base.me_subdevice_io_irq_wait = me4600_ext_irq_io_irq_wait;
|
||||
subdevice->base.me_subdevice_io_irq_stop = me4600_ext_irq_io_irq_stop;
|
||||
subdevice->base.me_subdevice_query_number_channels =
|
||||
me4600_ext_irq_query_number_channels;
|
||||
subdevice->base.me_subdevice_query_subdevice_type =
|
||||
me4600_ext_irq_query_subdevice_type;
|
||||
subdevice->base.me_subdevice_query_subdevice_caps =
|
||||
me4600_ext_irq_query_subdevice_caps;
|
||||
|
||||
subdevice->rised = 0;
|
||||
subdevice->count = 0;
|
||||
|
||||
return subdevice;
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
/**
|
||||
* @file me4600_ext_irq.h
|
||||
*
|
||||
* @brief Meilhaus ME-4000 external interrupt 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 _ME4600_EXT_IRQ_H_
|
||||
#define _ME4600_EXT_IRQ_H_
|
||||
|
||||
#include "mesubdevice.h"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/**
|
||||
* @brief The subdevice class.
|
||||
*/
|
||||
typedef struct me4600_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 *ctrl_reg_lock; /**< Spin lock to protect #ctrl_reg from concurrent access. */
|
||||
|
||||
wait_queue_head_t wait_queue;
|
||||
|
||||
int irq;
|
||||
|
||||
int rised;
|
||||
int value;
|
||||
int count;
|
||||
|
||||
unsigned long ctrl_reg;
|
||||
unsigned long irq_status_reg;
|
||||
unsigned long ext_irq_config_reg;
|
||||
unsigned long ext_irq_value_reg;
|
||||
#ifdef MEDEBUG_DEBUG_REG
|
||||
unsigned long reg_base;
|
||||
#endif
|
||||
} me4600_ext_irq_subdevice_t;
|
||||
|
||||
/**
|
||||
* @brief The constructor to generate a external interrupt subdevice instance.
|
||||
*
|
||||
* @param reg_base The register base address of the device as returned by the PCI BIOS.
|
||||
* @param irq The interrupt number assigned by the PCI BIOS.
|
||||
* @param ctrl_reg_lock Pointer to spin lock protecting the control register from concurrent access.
|
||||
*
|
||||
* @return Pointer to new instance on success.\n
|
||||
* NULL on error.
|
||||
*/
|
||||
me4600_ext_irq_subdevice_t *me4600_ext_irq_constructor(uint32_t reg_base,
|
||||
int irq,
|
||||
spinlock_t *
|
||||
ctrl_reg_lock);
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,41 +0,0 @@
|
|||
/**
|
||||
* @file me4600_ext_irq_reg.h
|
||||
*
|
||||
* @brief ME-4000 external interrupt 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 _ME4600_EXT_IRQ_REG_H_
|
||||
#define _ME4600_EXT_IRQ_REG_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define ME4600_EXT_IRQ_CONFIG_REG 0xCC // R/_
|
||||
#define ME4600_EXT_IRQ_VALUE_REG 0xD0 // R/_
|
||||
|
||||
#define ME4600_EXT_IRQ_CONFIG_MASK_RISING 0x0
|
||||
#define ME4600_EXT_IRQ_CONFIG_MASK_FALLING 0x1
|
||||
#define ME4600_EXT_IRQ_CONFIG_MASK_ANY 0x3
|
||||
#define ME4600_EXT_IRQ_CONFIG_MASK 0x3
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,46 +0,0 @@
|
|||
/**
|
||||
* @file me4600_reg.h
|
||||
*
|
||||
* @brief ME-4000 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 _ME4600_REG_H_
|
||||
#define _ME4600_REG_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define ME4600_IRQ_STATUS_REG 0x9C // R/_
|
||||
|
||||
#define ME4600_IRQ_STATUS_BIT_EX 0x01
|
||||
#define ME4600_IRQ_STATUS_BIT_LE 0x02
|
||||
#define ME4600_IRQ_STATUS_BIT_AI_HF 0x04
|
||||
#define ME4600_IRQ_STATUS_BIT_AO_0_HF 0x08
|
||||
#define ME4600_IRQ_STATUS_BIT_AO_1_HF 0x10
|
||||
#define ME4600_IRQ_STATUS_BIT_AO_2_HF 0x20
|
||||
#define ME4600_IRQ_STATUS_BIT_AO_3_HF 0x40
|
||||
#define ME4600_IRQ_STATUS_BIT_SC 0x80
|
||||
|
||||
#define ME4600_IRQ_STATUS_BIT_AO_HF ME4600_IRQ_STATUS_BIT_AO_0_HF
|
||||
|
||||
#endif
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,195 +0,0 @@
|
|||
/**
|
||||
* @file me6000_ao.h
|
||||
*
|
||||
* @brief Meilhaus ME-6000 analog 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 _ME6000_AO_H_
|
||||
#define _ME6000_AO_H_
|
||||
|
||||
#include "mesubdevice.h"
|
||||
#include "mecirc_buf.h"
|
||||
#include "meioctl.h"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define ME6000_AO_MAX_SUBDEVICES 16
|
||||
#define ME6000_AO_FIFO_COUNT 8192
|
||||
|
||||
#define ME6000_AO_BASE_FREQUENCY 33000000L
|
||||
|
||||
#define ME6000_AO_MIN_ACQ_TICKS 0LL
|
||||
#define ME6000_AO_MAX_ACQ_TICKS 0LL
|
||||
|
||||
#define ME6000_AO_MIN_CHAN_TICKS 66LL
|
||||
#define ME6000_AO_MAX_CHAN_TICKS 0xFFFFFFFFLL
|
||||
|
||||
#define ME6000_AO_MIN_RANGE -10000000
|
||||
#define ME6000_AO_MAX_RANGE 9999694
|
||||
|
||||
#define ME6000_AO_MIN_RANGE_HIGH 0
|
||||
#define ME6000_AO_MAX_RANGE_HIGH 49999237
|
||||
|
||||
#define ME6000_AO_MAX_DATA 0xFFFF
|
||||
|
||||
#ifdef ME_SYNAPSE
|
||||
# define ME6000_AO_CIRC_BUF_SIZE_ORDER 8 // 2^n PAGES =>> Maximum value of 1MB for Synapse
|
||||
#else
|
||||
# define ME6000_AO_CIRC_BUF_SIZE_ORDER 5 // 2^n PAGES =>> 128KB
|
||||
#endif
|
||||
#define ME6000_AO_CIRC_BUF_SIZE PAGE_SIZE<<ME6000_AO_CIRC_BUF_SIZE_ORDER // Buffer size in bytes.
|
||||
|
||||
# ifdef _CBUFF_32b_t
|
||||
# define ME6000_AO_CIRC_BUF_COUNT ((ME6000_AO_CIRC_BUF_SIZE) / sizeof(uint32_t)) // Size in values
|
||||
# else
|
||||
# define ME6000_AO_CIRC_BUF_COUNT ((ME6000_AO_CIRC_BUF_SIZE) / sizeof(uint16_t)) // Size in values
|
||||
# endif
|
||||
|
||||
# define ME6000_AO_CONTINOUS 0x0
|
||||
# define ME6000_AO_WRAP_MODE 0x1
|
||||
# define ME6000_AO_HW_MODE 0x2
|
||||
|
||||
# define ME6000_AO_HW_WRAP_MODE (ME6000_AO_WRAP_MODE | ME6000_AO_HW_MODE)
|
||||
# define ME6000_AO_SW_WRAP_MODE ME6000_AO_WRAP_MODE
|
||||
|
||||
# define ME6000_AO_INF_STOP_MODE 0x0
|
||||
# define ME6000_AO_ACQ_STOP_MODE 0x1
|
||||
# define ME6000_AO_SCAN_STOP_MODE 0x2
|
||||
|
||||
# define ME6000_AO_EXTRA_HARDWARE 0x1
|
||||
# define ME6000_AO_HAS_FIFO 0x2
|
||||
|
||||
typedef enum ME6000_AO_STATUS {
|
||||
ao_status_none = 0,
|
||||
ao_status_single_configured,
|
||||
ao_status_single_run_wait,
|
||||
ao_status_single_run,
|
||||
ao_status_single_end_wait,
|
||||
ao_status_single_end,
|
||||
ao_status_stream_configured,
|
||||
ao_status_stream_run_wait,
|
||||
ao_status_stream_run,
|
||||
ao_status_stream_end_wait,
|
||||
ao_status_stream_end,
|
||||
ao_status_stream_fifo_error,
|
||||
ao_status_stream_buffer_error,
|
||||
ao_status_stream_error,
|
||||
ao_status_last
|
||||
} ME6000_AO_STATUS;
|
||||
|
||||
typedef struct me6000_ao_timeout {
|
||||
unsigned long start_time;
|
||||
unsigned long delay;
|
||||
} me6000_ao_timeout_t;
|
||||
|
||||
/**
|
||||
* @brief The ME-6000 analog output subdevice class.
|
||||
*/
|
||||
typedef struct me6000_ao_subdevice {
|
||||
/* Inheritance */
|
||||
me_subdevice_t base; /**< The subdevice base class. */
|
||||
unsigned int ao_idx;
|
||||
|
||||
/* Attributes */
|
||||
spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */
|
||||
spinlock_t *preload_reg_lock; /**< Spin lock to protect preload_reg from concurrent access. */
|
||||
|
||||
uint32_t *preload_flags;
|
||||
uint32_t *triggering_flags;
|
||||
|
||||
/* Hardware feautres */
|
||||
unsigned int irq; /**< The interrupt request number assigned by the PCI BIOS. */
|
||||
int fifo; /**< If set this device has a FIFO. */
|
||||
|
||||
//Range
|
||||
int min;
|
||||
int max;
|
||||
|
||||
int single_value; /**< Mirror of the output value in single mode. */
|
||||
int single_value_in_fifo; /**< Mirror of the value written in single mode. */
|
||||
uint32_t ctrl_trg; /**< Mirror of the trigger settings. */
|
||||
|
||||
volatile int mode; /**< Flags used for storing SW wraparound setup*/
|
||||
int stop_mode; /**< The user defined stop condition flag. */
|
||||
unsigned int start_mode;
|
||||
unsigned int stop_count; /**< The user defined dates presentation end count. */
|
||||
unsigned int stop_data_count; /**< The stop presentation count. */
|
||||
unsigned int data_count; /**< The real presentation count. */
|
||||
unsigned int preloaded_count; /**< The next data addres in buffer. <= for wraparound mode. */
|
||||
int hardware_stop_delay; /**< The time that stop can take. This is only to not show hardware bug to user. */
|
||||
|
||||
volatile enum ME6000_AO_STATUS status; /**< The current stream status flag. */
|
||||
me6000_ao_timeout_t timeout; /**< The timeout for start in blocking and non-blocking mode. */
|
||||
|
||||
/* Registers *//**< All registers are 32 bits long. */
|
||||
unsigned long ctrl_reg;
|
||||
unsigned long status_reg;
|
||||
unsigned long fifo_reg;
|
||||
unsigned long single_reg;
|
||||
unsigned long timer_reg;
|
||||
unsigned long irq_status_reg;
|
||||
unsigned long preload_reg;
|
||||
unsigned long irq_reset_reg;
|
||||
#ifdef MEDEBUG_DEBUG_REG
|
||||
unsigned long reg_base;
|
||||
#endif
|
||||
|
||||
/* Software buffer */
|
||||
me_circ_buf_t circ_buf; /**< Circular buffer holding measurment data. */
|
||||
wait_queue_head_t wait_queue; /**< Wait queue to put on tasks waiting for data to arrive. */
|
||||
|
||||
struct workqueue_struct *me6000_workqueue;
|
||||
struct delayed_work ao_control_task;
|
||||
|
||||
volatile int ao_control_task_flag; /**< Flag controling reexecuting of control task */
|
||||
|
||||
} me6000_ao_subdevice_t;
|
||||
|
||||
/**
|
||||
* @brief The constructor to generate a ME-6000 analog output subdevice instance.
|
||||
*
|
||||
* @param reg_base The register base address of the device as returned by the PCI BIOS.
|
||||
* @param ctrl_reg_lock Pointer to spin lock protecting the control register from concurrent access.
|
||||
* @param preload_flags Pointer to spin lock protecting the hold&trigger register from concurrent access.
|
||||
* @param ao_idx Subdevice number.
|
||||
* @param fifo Flag set if subdevice has hardware FIFO.
|
||||
* @param irq IRQ number.
|
||||
* @param high_range Flag set if subdevice has high curren output.
|
||||
* @param me6000_wq Queue for asynchronous task (1 queue for all subdevice on 1 board).
|
||||
*
|
||||
* @return Pointer to new instance on success.\n
|
||||
* NULL on error.
|
||||
*/
|
||||
me6000_ao_subdevice_t *me6000_ao_constructor(uint32_t reg_base,
|
||||
spinlock_t * preload_reg_lock,
|
||||
uint32_t * preload_flags,
|
||||
uint32_t * triggering_flags,
|
||||
int ao_idx,
|
||||
int fifo,
|
||||
int irq,
|
||||
int high_range,
|
||||
struct workqueue_struct
|
||||
*me6000_wq);
|
||||
|
||||
#endif //__KERNEL__
|
||||
#endif //_ME6000_AO_H_
|
|
@ -1,177 +0,0 @@
|
|||
/**
|
||||
* @file me6000_ao_reg.h
|
||||
*
|
||||
* @brief ME-6000 analog 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 _ME6000_AO_REG_H_
|
||||
#define _ME6000_AO_REG_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
// AO
|
||||
#define ME6000_AO_00_CTRL_REG 0x00 // R/W
|
||||
#define ME6000_AO_00_STATUS_REG 0x04 // R/_
|
||||
#define ME6000_AO_00_FIFO_REG 0x08 // _/W
|
||||
#define ME6000_AO_00_SINGLE_REG 0x0C // R/W
|
||||
#define ME6000_AO_00_TIMER_REG 0x10 // _/W
|
||||
|
||||
#define ME6000_AO_01_CTRL_REG 0x18 // R/W
|
||||
#define ME6000_AO_01_STATUS_REG 0x1C // R/_
|
||||
#define ME6000_AO_01_FIFO_REG 0x20 // _/W
|
||||
#define ME6000_AO_01_SINGLE_REG 0x24 // R/W
|
||||
#define ME6000_AO_01_TIMER_REG 0x28 // _/W
|
||||
|
||||
#define ME6000_AO_02_CTRL_REG 0x30 // R/W
|
||||
#define ME6000_AO_02_STATUS_REG 0x34 // R/_
|
||||
#define ME6000_AO_02_FIFO_REG 0x38 // _/W
|
||||
#define ME6000_AO_02_SINGLE_REG 0x3C // R/W
|
||||
#define ME6000_AO_02_TIMER_REG 0x40 // _/W
|
||||
|
||||
#define ME6000_AO_03_CTRL_REG 0x48 // R/W
|
||||
#define ME6000_AO_03_STATUS_REG 0x4C // R/_
|
||||
#define ME6000_AO_03_FIFO_REG 0x50 // _/W
|
||||
#define ME6000_AO_03_SINGLE_REG 0x54 // R/W
|
||||
#define ME6000_AO_03_TIMER_REG 0x58 // _/W
|
||||
|
||||
#define ME6000_AO_SINGLE_STATUS_REG 0xA4 // R/_
|
||||
#define ME6000_AO_SINGLE_STATUS_OFFSET 4 //The first single subdevice => bit 0 in ME6000_AO_SINGLE_STATUS_REG.
|
||||
|
||||
#define ME6000_AO_04_STATUS_REG ME6000_AO_SINGLE_STATUS_REG
|
||||
#define ME6000_AO_04_SINGLE_REG 0x74 // _/W
|
||||
|
||||
#define ME6000_AO_05_STATUS_REG ME6000_AO_SINGLE_STATUS_REG
|
||||
#define ME6000_AO_05_SINGLE_REG 0x78 // _/W
|
||||
|
||||
#define ME6000_AO_06_STATUS_REG ME6000_AO_SINGLE_STATUS_REG
|
||||
#define ME6000_AO_06_SINGLE_REG 0x7C // _/W
|
||||
|
||||
#define ME6000_AO_07_STATUS_REG ME6000_AO_SINGLE_STATUS_REG
|
||||
#define ME6000_AO_07_SINGLE_REG 0x80 // _/W
|
||||
|
||||
#define ME6000_AO_08_STATUS_REG ME6000_AO_SINGLE_STATUS_REG
|
||||
#define ME6000_AO_08_SINGLE_REG 0x84 // _/W
|
||||
|
||||
#define ME6000_AO_09_STATUS_REG ME6000_AO_SINGLE_STATUS_REG
|
||||
#define ME6000_AO_09_SINGLE_REG 0x88 // _/W
|
||||
|
||||
#define ME6000_AO_10_STATUS_REG ME6000_AO_SINGLE_STATUS_REG
|
||||
#define ME6000_AO_10_SINGLE_REG 0x8C // _/W
|
||||
|
||||
#define ME6000_AO_11_STATUS_REG ME6000_AO_SINGLE_STATUS_REG
|
||||
#define ME6000_AO_11_SINGLE_REG 0x90 // _/W
|
||||
|
||||
#define ME6000_AO_12_STATUS_REG ME6000_AO_SINGLE_STATUS_REG
|
||||
#define ME6000_AO_12_SINGLE_REG 0x94 // _/W
|
||||
|
||||
#define ME6000_AO_13_STATUS_REG ME6000_AO_SINGLE_STATUS_REG
|
||||
#define ME6000_AO_13_SINGLE_REG 0x98 // _/W
|
||||
|
||||
#define ME6000_AO_14_STATUS_REG ME6000_AO_SINGLE_STATUS_REG
|
||||
#define ME6000_AO_14_SINGLE_REG 0x9C // _/W
|
||||
|
||||
#define ME6000_AO_15_STATUS_REG ME6000_AO_SINGLE_STATUS_REG
|
||||
#define ME6000_AO_15_SINGLE_REG 0xA0 // _/W
|
||||
|
||||
//ME6000_AO_CTRL_REG
|
||||
#define ME6000_AO_MODE_SINGLE 0x00
|
||||
#define ME6000_AO_MODE_WRAPAROUND 0x01
|
||||
#define ME6000_AO_MODE_CONTINUOUS 0x02
|
||||
#define ME6000_AO_CTRL_MODE_MASK (ME6000_AO_MODE_WRAPAROUND | ME6000_AO_MODE_CONTINUOUS)
|
||||
|
||||
#define ME6000_AO_CTRL_BIT_MODE_WRAPAROUND 0x001
|
||||
#define ME6000_AO_CTRL_BIT_MODE_CONTINUOUS 0x002
|
||||
#define ME6000_AO_CTRL_BIT_STOP 0x004
|
||||
#define ME6000_AO_CTRL_BIT_ENABLE_FIFO 0x008
|
||||
#define ME6000_AO_CTRL_BIT_ENABLE_EX_TRIG 0x010
|
||||
#define ME6000_AO_CTRL_BIT_EX_TRIG_EDGE 0x020
|
||||
#define ME6000_AO_CTRL_BIT_ENABLE_IRQ 0x040
|
||||
#define ME6000_AO_CTRL_BIT_IMMEDIATE_STOP 0x080
|
||||
#define ME6000_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH 0x800
|
||||
|
||||
//ME6000_AO_STATUS_REG
|
||||
#define ME6000_AO_STATUS_BIT_FSM 0x01
|
||||
#define ME6000_AO_STATUS_BIT_FF 0x02
|
||||
#define ME6000_AO_STATUS_BIT_HF 0x04
|
||||
#define ME6000_AO_STATUS_BIT_EF 0x08
|
||||
|
||||
#define ME6000_AO_PRELOAD_REG 0xA8 // R/W ///ME6000_AO_SYNC_REG <==> ME6000_AO_PRELOAD_REG
|
||||
/*
|
||||
#define ME6000_AO_SYNC_HOLD_0 0x00000001
|
||||
#define ME6000_AO_SYNC_HOLD_1 0x00000002
|
||||
#define ME6000_AO_SYNC_HOLD_2 0x00000004
|
||||
#define ME6000_AO_SYNC_HOLD_3 0x00000008
|
||||
#define ME6000_AO_SYNC_HOLD_4 0x00000010
|
||||
#define ME6000_AO_SYNC_HOLD_5 0x00000020
|
||||
#define ME6000_AO_SYNC_HOLD_6 0x00000040
|
||||
#define ME6000_AO_SYNC_HOLD_7 0x00000080
|
||||
#define ME6000_AO_SYNC_HOLD_8 0x00000100
|
||||
#define ME6000_AO_SYNC_HOLD_9 0x00000200
|
||||
#define ME6000_AO_SYNC_HOLD_10 0x00000400
|
||||
#define ME6000_AO_SYNC_HOLD_11 0x00000800
|
||||
#define ME6000_AO_SYNC_HOLD_12 0x00001000
|
||||
#define ME6000_AO_SYNC_HOLD_13 0x00002000
|
||||
#define ME6000_AO_SYNC_HOLD_14 0x00004000
|
||||
#define ME6000_AO_SYNC_HOLD_15 0x00008000
|
||||
*/
|
||||
#define ME6000_AO_SYNC_HOLD 0x00000001
|
||||
/*
|
||||
#define ME6000_AO_SYNC_EXT_TRIG_0 0x00010000
|
||||
#define ME6000_AO_SYNC_EXT_TRIG_1 0x00020000
|
||||
#define ME6000_AO_SYNC_EXT_TRIG_2 0x00040000
|
||||
#define ME6000_AO_SYNC_EXT_TRIG_3 0x00080000
|
||||
#define ME6000_AO_SYNC_EXT_TRIG_4 0x00100000
|
||||
#define ME6000_AO_SYNC_EXT_TRIG_5 0x00200000
|
||||
#define ME6000_AO_SYNC_EXT_TRIG_6 0x00400000
|
||||
#define ME6000_AO_SYNC_EXT_TRIG_7 0x00800000
|
||||
#define ME6000_AO_SYNC_EXT_TRIG_8 0x01000000
|
||||
#define ME6000_AO_SYNC_EXT_TRIG_9 0x02000000
|
||||
#define ME6000_AO_SYNC_EXT_TRIG_10 0x04000000
|
||||
#define ME6000_AO_SYNC_EXT_TRIG_11 0x08000000
|
||||
#define ME6000_AO_SYNC_EXT_TRIG_12 0x10000000
|
||||
#define ME6000_AO_SYNC_EXT_TRIG_13 0x20000000
|
||||
#define ME6000_AO_SYNC_EXT_TRIG_14 0x40000000
|
||||
#define ME6000_AO_SYNC_EXT_TRIG_15 0x80000000
|
||||
*/
|
||||
#define ME6000_AO_SYNC_EXT_TRIG 0x00010000
|
||||
|
||||
#define ME6000_AO_EXT_TRIG 0x80000000
|
||||
|
||||
// AO-IRQ
|
||||
#define ME6000_AO_IRQ_STATUS_REG 0x60 // R/_
|
||||
#define ME6000_AO_00_IRQ_RESET_REG 0x64 // R/_
|
||||
#define ME6000_AO_01_IRQ_RESET_REG 0x68 // R/_
|
||||
#define ME6000_AO_02_IRQ_RESET_REG 0x6C // R/_
|
||||
#define ME6000_AO_03_IRQ_RESET_REG 0x70 // R/_
|
||||
|
||||
#define ME6000_IRQ_STATUS_BIT_0 0x01
|
||||
#define ME6000_IRQ_STATUS_BIT_1 0x02
|
||||
#define ME6000_IRQ_STATUS_BIT_2 0x04
|
||||
#define ME6000_IRQ_STATUS_BIT_3 0x08
|
||||
|
||||
#define ME6000_IRQ_STATUS_BIT_AO_HF ME6000_IRQ_STATUS_BIT_0
|
||||
|
||||
//DUMY register
|
||||
#define ME6000_AO_DUMY 0xFC
|
||||
#endif
|
||||
#endif
|
|
@ -1,209 +0,0 @@
|
|||
/**
|
||||
* @file me6000_device.c
|
||||
*
|
||||
* @brief Device class template 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 "mefirmware.h"
|
||||
|
||||
#include "mesubdevice.h"
|
||||
#include "medebug.h"
|
||||
#include "medevice.h"
|
||||
#include "me6000_reg.h"
|
||||
#include "me6000_device.h"
|
||||
#include "meplx_reg.h"
|
||||
#include "me6000_dio.h"
|
||||
#include "me6000_ao.h"
|
||||
|
||||
/**
|
||||
* @brief Global variable.
|
||||
* This is working queue for runing a separate atask that will be responsible for work status (start, stop, timeouts).
|
||||
*/
|
||||
static struct workqueue_struct *me6000_workqueue;
|
||||
|
||||
me_device_t *me6000_pci_constructor(struct pci_dev *pci_device)
|
||||
{
|
||||
me6000_device_t *me6000_device;
|
||||
me_subdevice_t *subdevice;
|
||||
unsigned int version_idx;
|
||||
int err;
|
||||
int i;
|
||||
int high_range = 0;
|
||||
int fifo;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
// Allocate structure for device instance.
|
||||
me6000_device = kmalloc(sizeof(me6000_device_t), GFP_KERNEL);
|
||||
|
||||
if (!me6000_device) {
|
||||
PERROR("Cannot get memory for device instance.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(me6000_device, 0, sizeof(me6000_device_t));
|
||||
|
||||
// Initialize base class structure.
|
||||
err = me_device_pci_init((me_device_t *) me6000_device, pci_device);
|
||||
|
||||
if (err) {
|
||||
kfree(me6000_device);
|
||||
PERROR("Cannot initialize device base class.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Download the xilinx firmware */
|
||||
err = me_xilinx_download(me6000_device->base.info.pci.reg_bases[1],
|
||||
me6000_device->base.info.pci.reg_bases[2],
|
||||
&pci_device->dev, "me6000.bin");
|
||||
|
||||
if (err) {
|
||||
me_device_deinit((me_device_t *) me6000_device);
|
||||
kfree(me6000_device);
|
||||
PERROR("Can't download firmware.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get the index in the device version information table. */
|
||||
version_idx =
|
||||
me6000_versions_get_device_index(me6000_device->base.info.pci.
|
||||
device_id);
|
||||
|
||||
// Initialize spin lock .
|
||||
spin_lock_init(&me6000_device->preload_reg_lock);
|
||||
spin_lock_init(&me6000_device->dio_ctrl_reg_lock);
|
||||
|
||||
/* Create digital input/output instances. */
|
||||
for (i = 0; i < me6000_versions[version_idx].dio_subdevices; i++) {
|
||||
subdevice =
|
||||
(me_subdevice_t *) me6000_dio_constructor(me6000_device->
|
||||
base.info.pci.
|
||||
reg_bases[3], i,
|
||||
&me6000_device->
|
||||
dio_ctrl_reg_lock);
|
||||
|
||||
if (!subdevice) {
|
||||
me_device_deinit((me_device_t *) me6000_device);
|
||||
kfree(me6000_device);
|
||||
PERROR("Cannot get memory for subdevice.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
me_slist_add_subdevice_tail(&me6000_device->base.slist,
|
||||
subdevice);
|
||||
}
|
||||
|
||||
/* Create analog output instances. */
|
||||
for (i = 0; i < me6000_versions[version_idx].ao_subdevices; i++) {
|
||||
high_range = ((i == 8)
|
||||
&&
|
||||
((me6000_device->base.info.pci.device_id ==
|
||||
PCI_DEVICE_ID_MEILHAUS_ME6359)
|
||||
|| (me6000_device->base.info.pci.device_id ==
|
||||
PCI_DEVICE_ID_MEILHAUS_ME6259)
|
||||
)
|
||||
)? 1 : 0;
|
||||
|
||||
fifo =
|
||||
(i <
|
||||
me6000_versions[version_idx].
|
||||
ao_fifo) ? ME6000_AO_HAS_FIFO : 0x0;
|
||||
fifo |= (i < 4) ? ME6000_AO_EXTRA_HARDWARE : 0x0;
|
||||
|
||||
subdevice =
|
||||
(me_subdevice_t *) me6000_ao_constructor(me6000_device->
|
||||
base.info.pci.
|
||||
reg_bases[2],
|
||||
&me6000_device->
|
||||
preload_reg_lock,
|
||||
&me6000_device->
|
||||
preload_flags,
|
||||
&me6000_device->
|
||||
triggering_flags,
|
||||
i, fifo,
|
||||
me6000_device->
|
||||
base.irq,
|
||||
high_range,
|
||||
me6000_workqueue);
|
||||
|
||||
if (!subdevice) {
|
||||
me_device_deinit((me_device_t *) me6000_device);
|
||||
kfree(me6000_device);
|
||||
PERROR("Cannot get memory for subdevice.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
me_slist_add_subdevice_tail(&me6000_device->base.slist,
|
||||
subdevice);
|
||||
}
|
||||
|
||||
return (me_device_t *) me6000_device;
|
||||
}
|
||||
EXPORT_SYMBOL(me6000_pci_constructor);
|
||||
|
||||
// Init and exit of module.
|
||||
|
||||
static int __init me6000_init(void)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
me6000_workqueue = create_singlethread_workqueue("me6000");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit me6000_exit(void)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
flush_workqueue(me6000_workqueue);
|
||||
destroy_workqueue(me6000_workqueue);
|
||||
}
|
||||
|
||||
module_init(me6000_init);
|
||||
module_exit(me6000_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-6000 Device");
|
||||
MODULE_SUPPORTED_DEVICE("Meilhaus ME-6000 Devices");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,149 +0,0 @@
|
|||
/**
|
||||
* @file me6000_device.h
|
||||
*
|
||||
* @brief ME-6000 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 _ME6000_DEVICE_H
|
||||
#define _ME6000_DEVICE_H
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include "medevice.h"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/**
|
||||
* @brief Structure holding ME-6000 device capabilities.
|
||||
*/
|
||||
typedef struct me6000_version {
|
||||
uint16_t device_id;
|
||||
unsigned int dio_subdevices;
|
||||
unsigned int ao_subdevices;
|
||||
unsigned int ao_fifo; //How many devices have FIFO
|
||||
} me6000_version_t;
|
||||
|
||||
/**
|
||||
* @brief ME-6000 device capabilities.
|
||||
*/
|
||||
static me6000_version_t me6000_versions[] = {
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6004, 0, 4, 0},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6008, 0, 8, 0},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME600F, 0, 16, 0},
|
||||
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6014, 0, 4, 0},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6018, 0, 8, 0},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME601F, 0, 16, 0},
|
||||
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6034, 0, 4, 0},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6038, 0, 8, 0},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME603F, 0, 16, 0},
|
||||
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6104, 0, 4, 4},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6108, 0, 8, 4},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME610F, 0, 16, 4},
|
||||
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6114, 0, 4, 4},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6118, 0, 8, 4},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME611F, 0, 16, 4},
|
||||
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6134, 0, 4, 4},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6138, 0, 8, 4},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME613F, 0, 16, 4},
|
||||
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6044, 2, 4, 0},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6048, 2, 8, 0},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME604F, 2, 16, 0},
|
||||
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6054, 2, 4, 0},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6058, 2, 8, 0},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME605F, 2, 16, 0},
|
||||
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6074, 2, 4, 0},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6078, 2, 8, 0},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME607F, 2, 16, 0},
|
||||
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6144, 2, 4, 4},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6148, 2, 8, 4},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME614F, 2, 16, 4},
|
||||
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6154, 2, 4, 4},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6158, 2, 8, 4},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME615F, 2, 16, 4},
|
||||
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6174, 2, 4, 4},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6178, 2, 8, 4},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME617F, 2, 16, 4},
|
||||
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6259, 2, 9, 0},
|
||||
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME6359, 2, 9, 4},
|
||||
|
||||
{0},
|
||||
};
|
||||
|
||||
#define ME6000_DEVICE_VERSIONS (ARRAY_SIZE(me6000_versions) - 1) /**< Returns the number of entries in #me6000_versions. */
|
||||
|
||||
/**
|
||||
* @brief Returns the index of the device entry in #me6000_versions.
|
||||
*
|
||||
* @param device_id The PCI device id of the device to query.
|
||||
* @return The index of the device in #me6000_versions.
|
||||
*/
|
||||
static inline unsigned int me6000_versions_get_device_index(uint16_t device_id)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < ME6000_DEVICE_VERSIONS; i++)
|
||||
if (me6000_versions[i].device_id == device_id)
|
||||
break;
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The ME-6000 device class structure.
|
||||
*/
|
||||
typedef struct me6000_device {
|
||||
me_device_t base; /**< The Meilhaus device base class. */
|
||||
|
||||
/* Child class attributes. */
|
||||
spinlock_t preload_reg_lock; /**< Guards the preload register. */
|
||||
uint32_t preload_flags;
|
||||
uint32_t triggering_flags;
|
||||
|
||||
spinlock_t dio_ctrl_reg_lock;
|
||||
} me6000_device_t;
|
||||
|
||||
/**
|
||||
* @brief The ME-6000 device class constructor.
|
||||
*
|
||||
* @param pci_device The pci device structure given by the PCI subsystem.
|
||||
*
|
||||
* @return On succes a new ME-6000 device instance. \n
|
||||
* NULL on error.
|
||||
*/
|
||||
me_device_t *me6000_pci_constructor(struct pci_dev *pci_device)
|
||||
__attribute__ ((weak));
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,415 +0,0 @@
|
|||
/**
|
||||
* @file me6000_dio.c
|
||||
*
|
||||
* @brief ME-6000 digital input/output 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 <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "medefines.h"
|
||||
#include "meinternal.h"
|
||||
#include "meerror.h"
|
||||
|
||||
#include "medebug.h"
|
||||
#include "me6000_dio_reg.h"
|
||||
#include "me6000_dio.h"
|
||||
|
||||
/*
|
||||
* Defines
|
||||
*/
|
||||
|
||||
/*
|
||||
* Functions
|
||||
*/
|
||||
|
||||
static int me6000_dio_io_reset_subdevice(struct me_subdevice *subdevice,
|
||||
struct file *filep, int flags)
|
||||
{
|
||||
me6000_dio_subdevice_t *instance;
|
||||
uint8_t mode;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me6000_dio_subdevice_t *) subdevice;
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
mode = inb(instance->ctrl_reg);
|
||||
mode &= ~(0x3 << (instance->dio_idx * 2));
|
||||
outb(mode, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, mode);
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
|
||||
outb(0x00, instance->port_reg);
|
||||
PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, 0x00);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me6000_dio_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)
|
||||
{
|
||||
me6000_dio_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
uint8_t mode;
|
||||
int size =
|
||||
flags & (ME_IO_SINGLE_CONFIG_DIO_BIT | ME_IO_SINGLE_CONFIG_DIO_BYTE
|
||||
| ME_IO_SINGLE_CONFIG_DIO_WORD |
|
||||
ME_IO_SINGLE_CONFIG_DIO_DWORD);
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me6000_dio_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
mode = inb(instance->ctrl_reg);
|
||||
switch (size) {
|
||||
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) {
|
||||
mode &=
|
||||
~((ME6000_DIO_CTRL_BIT_MODE_0 |
|
||||
ME6000_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2));
|
||||
} else if (single_config == ME_SINGLE_CONFIG_DIO_OUTPUT) {
|
||||
mode &=
|
||||
~((ME6000_DIO_CTRL_BIT_MODE_0 |
|
||||
ME6000_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2));
|
||||
mode |=
|
||||
ME6000_DIO_CTRL_BIT_MODE_0 << (instance->
|
||||
dio_idx * 2);
|
||||
} else {
|
||||
PERROR
|
||||
("Invalid port configuration specified.\n");
|
||||
err = ME_ERRNO_INVALID_SINGLE_CONFIG;
|
||||
}
|
||||
} else {
|
||||
PERROR("Invalid channel number.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
PERROR("Invalid flags.\n");
|
||||
err = ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
outb(mode, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, mode);
|
||||
}
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me6000_dio_io_single_read(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int *value, int time_out, int flags)
|
||||
{
|
||||
me6000_dio_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
uint8_t mode;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me6000_dio_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
switch (flags) {
|
||||
case ME_IO_SINGLE_TYPE_DIO_BIT:
|
||||
if ((channel >= 0) && (channel < 8)) {
|
||||
mode =
|
||||
inb(instance->
|
||||
ctrl_reg) & ((ME6000_DIO_CTRL_BIT_MODE_0 |
|
||||
ME6000_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2));
|
||||
if ((mode ==
|
||||
(ME6000_DIO_CTRL_BIT_MODE_0 <<
|
||||
(instance->dio_idx * 2))) || !mode) {
|
||||
*value =
|
||||
inb(instance->port_reg) & (0x1 << channel);
|
||||
} else {
|
||||
PERROR("Port not in output or input mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_CONFIG;
|
||||
}
|
||||
} 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) {
|
||||
mode =
|
||||
inb(instance->
|
||||
ctrl_reg) & ((ME6000_DIO_CTRL_BIT_MODE_0 |
|
||||
ME6000_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2));
|
||||
if ((mode ==
|
||||
(ME6000_DIO_CTRL_BIT_MODE_0 <<
|
||||
(instance->dio_idx * 2))) || !mode) {
|
||||
*value = inb(instance->port_reg) & 0x00FF;
|
||||
} else {
|
||||
PERROR("Port not in output or input mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_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->ctrl_reg_lock);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me6000_dio_io_single_write(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int value, int time_out, int flags)
|
||||
{
|
||||
me6000_dio_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
uint8_t mode;
|
||||
uint8_t byte;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me6000_dio_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
switch (flags) {
|
||||
case ME_IO_SINGLE_TYPE_DIO_BIT:
|
||||
if ((channel >= 0) && (channel < 8)) {
|
||||
mode =
|
||||
inb(instance->
|
||||
ctrl_reg) & ((ME6000_DIO_CTRL_BIT_MODE_0 |
|
||||
ME6000_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2));
|
||||
|
||||
if (mode ==
|
||||
(ME6000_DIO_CTRL_BIT_MODE_0 <<
|
||||
(instance->dio_idx * 2))) {
|
||||
byte = inb(instance->port_reg) & 0x00FF;
|
||||
|
||||
if (value)
|
||||
byte |= 0x1 << channel;
|
||||
else
|
||||
byte &= ~(0x1 << channel);
|
||||
|
||||
outb(byte, instance->port_reg);
|
||||
} else {
|
||||
PERROR("Port not in output or input mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_CONFIG;
|
||||
}
|
||||
} 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) {
|
||||
mode =
|
||||
inb(instance->
|
||||
ctrl_reg) & ((ME6000_DIO_CTRL_BIT_MODE_0 |
|
||||
ME6000_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2));
|
||||
|
||||
if (mode ==
|
||||
(ME6000_DIO_CTRL_BIT_MODE_0 <<
|
||||
(instance->dio_idx * 2))) {
|
||||
outb(value, instance->port_reg);
|
||||
} else {
|
||||
PERROR("Port not in output or input mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_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->ctrl_reg_lock);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me6000_dio_query_number_channels(me_subdevice_t *subdevice,
|
||||
int *number)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*number = 8;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me6000_dio_query_subdevice_type(me_subdevice_t *subdevice,
|
||||
int *type, int *subtype)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*type = ME_TYPE_DIO;
|
||||
*subtype = ME_SUBTYPE_SINGLE;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me6000_dio_query_subdevice_caps(me_subdevice_t *subdevice,
|
||||
int *caps)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*caps = ME_CAPS_DIO_DIR_BYTE;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
me6000_dio_subdevice_t *me6000_dio_constructor(uint32_t reg_base,
|
||||
unsigned int dio_idx,
|
||||
spinlock_t *ctrl_reg_lock)
|
||||
{
|
||||
me6000_dio_subdevice_t *subdevice;
|
||||
int err;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
/* Allocate memory for subdevice instance */
|
||||
subdevice = kmalloc(sizeof(me6000_dio_subdevice_t), GFP_KERNEL);
|
||||
|
||||
if (!subdevice) {
|
||||
PERROR("Cannot get memory for subdevice instance.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(subdevice, 0, sizeof(me6000_dio_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;
|
||||
}
|
||||
|
||||
/* Set the subdevice ports */
|
||||
subdevice->ctrl_reg = reg_base + ME6000_DIO_CTRL_REG;
|
||||
switch (dio_idx) {
|
||||
case 0:
|
||||
subdevice->port_reg = reg_base + ME6000_DIO_PORT_0_REG;
|
||||
break;
|
||||
case 1:
|
||||
subdevice->port_reg = reg_base + ME6000_DIO_PORT_1_REG;
|
||||
break;
|
||||
default:
|
||||
err = ME_ERRNO_INVALID_SUBDEVICE;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
PERROR("Cannot initialize subdevice base class instance.\n");
|
||||
kfree(subdevice);
|
||||
return NULL;
|
||||
}
|
||||
// Initialize spin locks.
|
||||
spin_lock_init(&subdevice->subdevice_lock);
|
||||
|
||||
subdevice->ctrl_reg_lock = ctrl_reg_lock;
|
||||
|
||||
/* Save digital i/o index */
|
||||
subdevice->dio_idx = dio_idx;
|
||||
|
||||
#ifdef MEDEBUG_DEBUG_REG
|
||||
subdevice->reg_base = reg_base;
|
||||
#endif
|
||||
|
||||
/* Overload base class methods. */
|
||||
subdevice->base.me_subdevice_io_reset_subdevice =
|
||||
me6000_dio_io_reset_subdevice;
|
||||
subdevice->base.me_subdevice_io_single_config =
|
||||
me6000_dio_io_single_config;
|
||||
subdevice->base.me_subdevice_io_single_read = me6000_dio_io_single_read;
|
||||
subdevice->base.me_subdevice_io_single_write =
|
||||
me6000_dio_io_single_write;
|
||||
subdevice->base.me_subdevice_query_number_channels =
|
||||
me6000_dio_query_number_channels;
|
||||
subdevice->base.me_subdevice_query_subdevice_type =
|
||||
me6000_dio_query_subdevice_type;
|
||||
subdevice->base.me_subdevice_query_subdevice_caps =
|
||||
me6000_dio_query_subdevice_caps;
|
||||
|
||||
return subdevice;
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
/**
|
||||
* @file me6000_dio.h
|
||||
*
|
||||
* @brief ME-6000 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 _ME6000_DIO_H_
|
||||
#define _ME6000_DIO_H_
|
||||
|
||||
#include "mesubdevice.h"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/**
|
||||
* @brief The template subdevice class.
|
||||
*/
|
||||
typedef struct me6000_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
|
||||
} me6000_dio_subdevice_t;
|
||||
|
||||
/**
|
||||
* @brief The constructor to generate a ME-6000 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.
|
||||
*/
|
||||
me6000_dio_subdevice_t *me6000_dio_constructor(uint32_t reg_base,
|
||||
unsigned int dio_idx,
|
||||
spinlock_t * ctrl_reg_lock);
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,43 +0,0 @@
|
|||
/**
|
||||
* @file me6000_dio_reg.h
|
||||
*
|
||||
* @brief ME-6000 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 _ME6000_DIO_REG_H_
|
||||
#define _ME6000_DIO_REG_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define ME6000_DIO_CTRL_REG 0x00 // R/W
|
||||
#define ME6000_DIO_PORT_0_REG 0x01 // R/W
|
||||
#define ME6000_DIO_PORT_1_REG 0x02 // R/W
|
||||
#define ME6000_DIO_PORT_REG ME6000_DIO_PORT_0_REG // R/W
|
||||
|
||||
#define ME6000_DIO_CTRL_BIT_MODE_0 0x01
|
||||
#define ME6000_DIO_CTRL_BIT_MODE_1 0x02
|
||||
#define ME6000_DIO_CTRL_BIT_MODE_2 0x04
|
||||
#define ME6000_DIO_CTRL_BIT_MODE_3 0x08
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,35 +0,0 @@
|
|||
/**
|
||||
* @file me6000_reg.h
|
||||
*
|
||||
* @brief ME-6000 device 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 _ME6000_REG_H_
|
||||
#define _ME6000_REG_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define ME6000_INIT_XILINX_REG 0xAC // R/-
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,185 +0,0 @@
|
|||
/**
|
||||
* @file me8100_device.c
|
||||
*
|
||||
* @brief ME-8100 device class 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 __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 "me8100_device.h"
|
||||
#include "mesubdevice.h"
|
||||
#include "me8100_di.h"
|
||||
#include "me8100_do.h"
|
||||
#include "me8254.h"
|
||||
|
||||
me_device_t *me8100_pci_constructor(struct pci_dev *pci_device)
|
||||
{
|
||||
me8100_device_t *me8100_device;
|
||||
me_subdevice_t *subdevice;
|
||||
unsigned int version_idx;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
// Allocate structure for device instance.
|
||||
me8100_device = kmalloc(sizeof(me8100_device_t), GFP_KERNEL);
|
||||
|
||||
if (!me8100_device) {
|
||||
PERROR("Cannot get memory for device instance.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(me8100_device, 0, sizeof(me8100_device_t));
|
||||
|
||||
// Initialize base class structure.
|
||||
err = me_device_pci_init((me_device_t *) me8100_device, pci_device);
|
||||
|
||||
if (err) {
|
||||
kfree(me8100_device);
|
||||
PERROR("Cannot initialize device base class.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get the index in the device version information table. */
|
||||
version_idx =
|
||||
me8100_versions_get_device_index(me8100_device->base.info.pci.
|
||||
device_id);
|
||||
|
||||
// Initialize spin lock .
|
||||
spin_lock_init(&me8100_device->dio_ctrl_reg_lock);
|
||||
spin_lock_init(&me8100_device->ctr_ctrl_reg_lock);
|
||||
spin_lock_init(&me8100_device->clk_src_reg_lock);
|
||||
|
||||
// Create subdevice instances.
|
||||
|
||||
for (i = 0; i < me8100_versions[version_idx].di_subdevices; i++) {
|
||||
subdevice =
|
||||
(me_subdevice_t *) me8100_di_constructor(me8100_device->
|
||||
base.info.pci.
|
||||
reg_bases[2],
|
||||
me8100_device->
|
||||
base.info.pci.
|
||||
reg_bases[1], i,
|
||||
me8100_device->
|
||||
base.irq,
|
||||
&me8100_device->
|
||||
dio_ctrl_reg_lock);
|
||||
|
||||
if (!subdevice) {
|
||||
me_device_deinit((me_device_t *) me8100_device);
|
||||
kfree(me8100_device);
|
||||
PERROR("Cannot get memory for subdevice.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
me_slist_add_subdevice_tail(&me8100_device->base.slist,
|
||||
subdevice);
|
||||
}
|
||||
|
||||
for (i = 0; i < me8100_versions[version_idx].do_subdevices; i++) {
|
||||
subdevice =
|
||||
(me_subdevice_t *) me8100_do_constructor(me8100_device->
|
||||
base.info.pci.
|
||||
reg_bases[2], i,
|
||||
&me8100_device->
|
||||
dio_ctrl_reg_lock);
|
||||
|
||||
if (!subdevice) {
|
||||
me_device_deinit((me_device_t *) me8100_device);
|
||||
kfree(me8100_device);
|
||||
PERROR("Cannot get memory for subdevice.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
me_slist_add_subdevice_tail(&me8100_device->base.slist,
|
||||
subdevice);
|
||||
}
|
||||
|
||||
for (i = 0; i < me8100_versions[version_idx].ctr_subdevices; i++) {
|
||||
subdevice =
|
||||
(me_subdevice_t *) me8254_constructor(me8100_device->base.
|
||||
info.pci.device_id,
|
||||
me8100_device->base.
|
||||
info.pci.reg_bases[2],
|
||||
0, i,
|
||||
&me8100_device->
|
||||
ctr_ctrl_reg_lock,
|
||||
&me8100_device->
|
||||
clk_src_reg_lock);
|
||||
|
||||
if (!subdevice) {
|
||||
me_device_deinit((me_device_t *) me8100_device);
|
||||
kfree(me8100_device);
|
||||
PERROR("Cannot get memory for subdevice.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
me_slist_add_subdevice_tail(&me8100_device->base.slist,
|
||||
subdevice);
|
||||
}
|
||||
|
||||
return (me_device_t *) me8100_device;
|
||||
}
|
||||
EXPORT_SYMBOL(me8100_pci_constructor);
|
||||
|
||||
// Init and exit of module.
|
||||
|
||||
static int __init me8100_init(void)
|
||||
{
|
||||
PDEBUG("executed.\n.");
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static void __exit me8100_exit(void)
|
||||
{
|
||||
PDEBUG("executed.\n.");
|
||||
}
|
||||
|
||||
module_init(me8100_init);
|
||||
|
||||
module_exit(me8100_exit);
|
||||
|
||||
// Administrative stuff for modinfo.
|
||||
MODULE_AUTHOR("Guenter Gebhardt <g.gebhardt@meilhaus.de>");
|
||||
MODULE_DESCRIPTION("Device Driver Module for Template Device");
|
||||
MODULE_SUPPORTED_DEVICE("Meilhaus Template Devices");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,97 +0,0 @@
|
|||
/**
|
||||
* @file me8100_device.h
|
||||
*
|
||||
* @brief ME-8100 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 _ME8100_DEVICE_H
|
||||
#define _ME8100_DEVICE_H
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include "medevice.h"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/**
|
||||
* @brief Structure holding ME-8100 device capabilities.
|
||||
*/
|
||||
typedef struct me8100_version {
|
||||
uint16_t device_id;
|
||||
unsigned int di_subdevices;
|
||||
unsigned int do_subdevices;
|
||||
unsigned int ctr_subdevices;
|
||||
} me8100_version_t;
|
||||
|
||||
/**
|
||||
* @brief Device capabilities.
|
||||
*/
|
||||
static me8100_version_t me8100_versions[] = {
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME8100_A, 1, 1, 3},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME8100_B, 2, 2, 3},
|
||||
{0},
|
||||
};
|
||||
|
||||
#define ME8100_DEVICE_VERSIONS (ARRAY_SIZE(me8100_versions) - 1) /**< Returns the number of entries in #me8100_versions. */
|
||||
|
||||
/**
|
||||
* @brief Returns the index of the device entry in #me8100_versions.
|
||||
*
|
||||
* @param device_id The PCI device id of the device to query.
|
||||
* @return The index of the device in #me8100_versions.
|
||||
*/
|
||||
static inline unsigned int me8100_versions_get_device_index(uint16_t device_id)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < ME8100_DEVICE_VERSIONS; i++)
|
||||
if (me8100_versions[i].device_id == device_id)
|
||||
break;
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The ME-8100 device class structure.
|
||||
*/
|
||||
typedef struct me8100_device {
|
||||
me_device_t base; /**< The Meilhaus device base class. */
|
||||
|
||||
/* Child class attributes. */
|
||||
spinlock_t dio_ctrl_reg_lock;
|
||||
spinlock_t ctr_ctrl_reg_lock;
|
||||
spinlock_t clk_src_reg_lock;
|
||||
} me8100_device_t;
|
||||
|
||||
/**
|
||||
* @brief The ME-8100 device class constructor.
|
||||
*
|
||||
* @param pci_device The pci device structure given by the PCI subsystem.
|
||||
*
|
||||
* @return On succes a new ME-8100 device instance. \n
|
||||
* NULL on error.
|
||||
*/
|
||||
me_device_t *me8100_pci_constructor(struct pci_dev *pci_device)
|
||||
__attribute__ ((weak));
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,684 +0,0 @@
|
|||
/**
|
||||
* @file me8100_di.c
|
||||
*
|
||||
* @brief ME-8100 digital 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 <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "medefines.h"
|
||||
#include "meerror.h"
|
||||
|
||||
#include "meids.h"
|
||||
#include "medebug.h"
|
||||
#include "meplx_reg.h"
|
||||
#include "me8100_reg.h"
|
||||
#include "me8100_di_reg.h"
|
||||
#include "me8100_di.h"
|
||||
|
||||
/*
|
||||
* Defines
|
||||
*/
|
||||
|
||||
/*
|
||||
* Functions
|
||||
*/
|
||||
|
||||
static int me8100_di_io_reset_subdevice(struct me_subdevice *subdevice,
|
||||
struct file *filep, int flags)
|
||||
{
|
||||
me8100_di_subdevice_t *instance;
|
||||
unsigned short ctrl;
|
||||
unsigned long cpu_flags;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8100_di_subdevice_t *) subdevice;
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
ctrl = inw(instance->ctrl_reg);
|
||||
ctrl &= ~(ME8100_DIO_CTRL_BIT_INTB_1 | ME8100_DIO_CTRL_BIT_INTB_0);
|
||||
outw(ctrl, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, ctrl);
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
|
||||
outw(0, instance->mask_reg);
|
||||
PDEBUG_REG("mask_reg outw(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->mask_reg - instance->reg_base, 0);
|
||||
outw(0, instance->pattern_reg);
|
||||
PDEBUG_REG("pattern_reg outw(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->pattern_reg - instance->reg_base, 0);
|
||||
instance->rised = -1;
|
||||
instance->irq_count = 0;
|
||||
instance->filtering_flag = 0;
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
|
||||
|
||||
outl(PLX_INTCSR_LOCAL_INT1_EN |
|
||||
PLX_INTCSR_LOCAL_INT1_POL |
|
||||
PLX_INTCSR_LOCAL_INT2_EN |
|
||||
PLX_INTCSR_LOCAL_INT2_POL |
|
||||
PLX_INTCSR_PCI_INT_EN, instance->irq_status_reg);
|
||||
PDEBUG_REG("plx:irq_status_reg outl(0x%lX)=0x%x\n",
|
||||
instance->irq_status_reg,
|
||||
PLX_INTCSR_LOCAL_INT1_EN | PLX_INTCSR_LOCAL_INT1_POL |
|
||||
PLX_INTCSR_LOCAL_INT2_EN | PLX_INTCSR_LOCAL_INT2_POL |
|
||||
PLX_INTCSR_PCI_INT_EN);
|
||||
|
||||
wake_up_interruptible_all(&instance->wait_queue);
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me8100_di_io_irq_start(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int irq_source,
|
||||
int irq_edge, int irq_arg, int flags)
|
||||
{
|
||||
me8100_di_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
uint16_t ctrl;
|
||||
unsigned long cpu_flags;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8100_di_subdevice_t *) subdevice;
|
||||
|
||||
if (irq_source == ME_IRQ_SOURCE_DIO_PATTERN) {
|
||||
if (flags &
|
||||
~(ME_IO_IRQ_START_PATTERN_FILTERING |
|
||||
ME_IO_IRQ_START_DIO_WORD)) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (irq_edge != ME_IRQ_EDGE_NOT_USED) {
|
||||
PERROR("Invalid irq edge specified.\n");
|
||||
return ME_ERRNO_INVALID_IRQ_EDGE;
|
||||
}
|
||||
} else if (irq_source == ME_IRQ_SOURCE_DIO_MASK) {
|
||||
if (flags &
|
||||
~(ME_IO_IRQ_START_EXTENDED_STATUS |
|
||||
ME_IO_IRQ_START_DIO_WORD)) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (irq_edge != ME_IRQ_EDGE_ANY) {
|
||||
PERROR("Invalid irq edge specified.\n");
|
||||
return ME_ERRNO_INVALID_IRQ_EDGE;
|
||||
}
|
||||
|
||||
if (!(irq_arg & 0xFFFF)) {
|
||||
PERROR("No mask specified.\n");
|
||||
return ME_ERRNO_INVALID_IRQ_ARG;
|
||||
}
|
||||
} else {
|
||||
PERROR("Invalid irq source specified.\n");
|
||||
return ME_ERRNO_INVALID_IRQ_SOURCE;
|
||||
}
|
||||
|
||||
if (channel) {
|
||||
PERROR("Invalid channel specified.\n");
|
||||
return ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
|
||||
if (irq_source == ME_IRQ_SOURCE_DIO_PATTERN) {
|
||||
outw(irq_arg, instance->pattern_reg);
|
||||
instance->compare_value = irq_arg;
|
||||
instance->filtering_flag =
|
||||
(flags & ME_IO_IRQ_START_PATTERN_FILTERING) ? 1 : 0;
|
||||
}
|
||||
if (irq_source == ME_IRQ_SOURCE_DIO_MASK) {
|
||||
outw(irq_arg, instance->mask_reg);
|
||||
}
|
||||
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
ctrl = inw(instance->ctrl_reg);
|
||||
ctrl |= ME8100_DIO_CTRL_BIT_INTB_0;
|
||||
if (irq_source == ME_IRQ_SOURCE_DIO_PATTERN) {
|
||||
ctrl &= ~ME8100_DIO_CTRL_BIT_INTB_1;
|
||||
}
|
||||
|
||||
if (irq_source == ME_IRQ_SOURCE_DIO_MASK) {
|
||||
ctrl |= ME8100_DIO_CTRL_BIT_INTB_1;
|
||||
}
|
||||
outw(ctrl, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outw(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, ctrl);
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
|
||||
instance->rised = 0;
|
||||
instance->status_value = 0;
|
||||
instance->status_value_edges = 0;
|
||||
instance->line_value = inw(instance->port_reg);
|
||||
instance->status_flag = flags & ME_IO_IRQ_START_EXTENDED_STATUS;
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me8100_di_io_irq_wait(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int *irq_count,
|
||||
int *value, int time_out, int flags)
|
||||
{
|
||||
me8100_di_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
long t = 0;
|
||||
unsigned long cpu_flags;
|
||||
int count;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
PDEVELOP("PID: %d.\n", current->pid);
|
||||
|
||||
instance = (me8100_di_subdevice_t *) subdevice;
|
||||
|
||||
if (flags &
|
||||
~(ME_IO_IRQ_WAIT_NORMAL_STATUS | ME_IO_IRQ_WAIT_EXTENDED_STATUS)) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (channel) {
|
||||
PERROR("Invalid channel specified.\n");
|
||||
return ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
|
||||
if (time_out < 0) {
|
||||
PERROR("Invalid time_out specified.\n");
|
||||
return ME_ERRNO_INVALID_TIMEOUT;
|
||||
}
|
||||
|
||||
if (time_out) {
|
||||
t = (time_out * HZ) / 1000;
|
||||
|
||||
if (t == 0)
|
||||
t = 1;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
if (instance->rised <= 0) {
|
||||
instance->rised = 0;
|
||||
count = instance->irq_count;
|
||||
|
||||
if (time_out) {
|
||||
t = wait_event_interruptible_timeout(instance->
|
||||
wait_queue,
|
||||
((count !=
|
||||
instance->
|
||||
irq_count)
|
||||
|| (instance->
|
||||
rised < 0)),
|
||||
t);
|
||||
// t = wait_event_interruptible_timeout(instance->wait_queue, (instance->rised != 0), t);
|
||||
if (t == 0) {
|
||||
PERROR("Wait on interrupt timed out.\n");
|
||||
err = ME_ERRNO_TIMEOUT;
|
||||
}
|
||||
} else {
|
||||
wait_event_interruptible(instance->wait_queue,
|
||||
((count != instance->irq_count)
|
||||
|| (instance->rised < 0)));
|
||||
// wait_event_interruptible(instance->wait_queue, (instance->rised != 0));
|
||||
}
|
||||
|
||||
if (instance->rised < 0) {
|
||||
PERROR("Wait on interrupt aborted by user.\n");
|
||||
err = ME_ERRNO_CANCELLED;
|
||||
}
|
||||
}
|
||||
|
||||
if (signal_pending(current)) {
|
||||
PERROR("Wait on interrupt aborted by signal.\n");
|
||||
err = ME_ERRNO_SIGNAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
|
||||
*irq_count = instance->irq_count;
|
||||
if (!err) {
|
||||
if (flags & ME_IO_IRQ_WAIT_NORMAL_STATUS) {
|
||||
*value = instance->status_value;
|
||||
} else if (flags & ME_IO_IRQ_WAIT_EXTENDED_STATUS) {
|
||||
*value = instance->status_value_edges;
|
||||
} else { // Use default
|
||||
if (!instance->status_flag) {
|
||||
*value = instance->status_value;
|
||||
} else {
|
||||
*value = instance->status_value_edges;
|
||||
}
|
||||
}
|
||||
instance->rised = 0;
|
||||
/*
|
||||
instance->status_value = 0;
|
||||
instance->status_value_edges = 0;
|
||||
*/
|
||||
} else {
|
||||
*value = 0;
|
||||
}
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me8100_di_io_irq_stop(me_subdevice_t *subdevice,
|
||||
struct file *filep, int channel, int flags)
|
||||
{
|
||||
me8100_di_subdevice_t *instance;
|
||||
uint16_t ctrl;
|
||||
unsigned long cpu_flags;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8100_di_subdevice_t *) subdevice;
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (channel) {
|
||||
PERROR("Invalid channel specified.\n");
|
||||
return ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
ctrl = inw(instance->ctrl_reg);
|
||||
ctrl &= ~(ME8100_DIO_CTRL_BIT_INTB_1 | ME8100_DIO_CTRL_BIT_INTB_0);
|
||||
outw(ctrl, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outw(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, ctrl);
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
instance->rised = -1;
|
||||
instance->status_value = 0;
|
||||
instance->status_value_edges = 0;
|
||||
instance->filtering_flag = 0;
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
|
||||
wake_up_interruptible_all(&instance->wait_queue);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me8100_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)
|
||||
{
|
||||
me8100_di_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8100_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_CONFIG_DIO_WORD:
|
||||
if (channel == 0) {
|
||||
if (single_config == ME_SINGLE_CONFIG_DIO_INPUT) {
|
||||
} else {
|
||||
PERROR
|
||||
("Invalid port configuration specified.\n");
|
||||
err = ME_ERRNO_INVALID_SINGLE_CONFIG;
|
||||
}
|
||||
} else {
|
||||
PERROR("Invalid channel number.\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 me8100_di_io_single_read(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int *value, int time_out, int flags)
|
||||
{
|
||||
me8100_di_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8100_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 < 16)) {
|
||||
*value = inw(instance->port_reg) & (0x1 << channel);
|
||||
} else {
|
||||
PERROR("Invalid bit number specified.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
break;
|
||||
|
||||
case ME_IO_SINGLE_TYPE_DIO_BYTE:
|
||||
if (channel == 0) {
|
||||
*value = inw(instance->port_reg) & 0xFF;
|
||||
} else if (channel == 1) {
|
||||
*value = (inw(instance->port_reg) >> 8) & 0xFF;
|
||||
} 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 = inw(instance->port_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 me8100_di_query_number_channels(me_subdevice_t *subdevice,
|
||||
int *number)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*number = 16;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me8100_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 me8100_di_query_subdevice_caps(me_subdevice_t *subdevice, int *caps)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*caps = ME_CAPS_DIO_BIT_PATTERN_IRQ | ME_CAPS_DIO_BIT_MASK_IRQ_EDGE_ANY;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static void me8100_di_destructor(struct me_subdevice *subdevice)
|
||||
{
|
||||
me8100_di_subdevice_t *instance;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8100_di_subdevice_t *) subdevice;
|
||||
|
||||
free_irq(instance->irq, (void *)instance);
|
||||
me_subdevice_deinit(&instance->base);
|
||||
kfree(instance);
|
||||
}
|
||||
|
||||
static irqreturn_t me8100_isr(int irq, void *dev_id)
|
||||
{
|
||||
me8100_di_subdevice_t *instance;
|
||||
uint32_t icsr;
|
||||
|
||||
uint16_t irq_status;
|
||||
uint16_t line_value = 0;
|
||||
|
||||
uint32_t status_val = 0;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8100_di_subdevice_t *) dev_id;
|
||||
|
||||
if (irq != instance->irq) {
|
||||
PERROR("Incorrect interrupt num: %d.\n", irq);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
icsr = inl(instance->irq_status_reg);
|
||||
if (instance->di_idx == 0) {
|
||||
|
||||
if ((icsr &
|
||||
(PLX_INTCSR_LOCAL_INT1_STATE | PLX_INTCSR_PCI_INT_EN |
|
||||
PLX_INTCSR_LOCAL_INT1_EN)) !=
|
||||
(PLX_INTCSR_LOCAL_INT1_STATE | PLX_INTCSR_PCI_INT_EN |
|
||||
PLX_INTCSR_LOCAL_INT1_EN)) {
|
||||
PINFO
|
||||
("%ld Shared interrupt. %s(): idx=0 plx:irq_status_reg=0x%04X\n",
|
||||
jiffies, __func__, icsr);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
} else if (instance->di_idx == 1) {
|
||||
if ((icsr &
|
||||
(PLX_INTCSR_LOCAL_INT2_STATE | PLX_INTCSR_PCI_INT_EN |
|
||||
PLX_INTCSR_LOCAL_INT2_EN)) !=
|
||||
(PLX_INTCSR_LOCAL_INT2_STATE | PLX_INTCSR_PCI_INT_EN |
|
||||
PLX_INTCSR_LOCAL_INT2_EN)) {
|
||||
PINFO
|
||||
("%ld Shared interrupt. %s(): idx=1 plx:irq_status_reg=0x%04X\n",
|
||||
jiffies, __func__, icsr);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
} else {
|
||||
PERROR("%s():Wrong interrupt idx=%d csr=0x%X.\n", __func__,
|
||||
instance->di_idx, icsr);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
PDEBUG("me8100_isr():Interrupt from idx=%d occured.\n",
|
||||
instance->di_idx);
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
inw(instance->irq_reset_reg);
|
||||
line_value = inw(instance->port_reg);
|
||||
|
||||
irq_status = instance->line_value ^ line_value;
|
||||
|
||||
// Make extended information.
|
||||
status_val |= (0x00FF & (~(uint16_t) instance->line_value & line_value)) << 16; //Raise
|
||||
status_val |= (0x00FF & ((uint16_t) instance->line_value & ~line_value)); //Fall
|
||||
|
||||
instance->line_value = line_value;
|
||||
|
||||
if (instance->rised == 0) {
|
||||
instance->status_value = irq_status;
|
||||
instance->status_value_edges = status_val;
|
||||
} else {
|
||||
instance->status_value |= irq_status;
|
||||
instance->status_value_edges |= status_val;
|
||||
}
|
||||
|
||||
if (instance->filtering_flag) { // For compare mode only.
|
||||
if (instance->compare_value == instance->line_value) {
|
||||
instance->rised = 1;
|
||||
instance->irq_count++;
|
||||
}
|
||||
} else {
|
||||
instance->rised = 1;
|
||||
instance->irq_count++;
|
||||
}
|
||||
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
wake_up_interruptible_all(&instance->wait_queue);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
me8100_di_subdevice_t *me8100_di_constructor(uint32_t me8100_reg_base,
|
||||
uint32_t plx_reg_base,
|
||||
unsigned int di_idx,
|
||||
int irq,
|
||||
spinlock_t *ctrl_reg_lock)
|
||||
{
|
||||
me8100_di_subdevice_t *subdevice;
|
||||
int err;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
/* Allocate memory for subdevice instance */
|
||||
subdevice = kmalloc(sizeof(me8100_di_subdevice_t), GFP_KERNEL);
|
||||
|
||||
if (!subdevice) {
|
||||
PERROR("Cannot get memory for subdevice instance.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(subdevice, 0, sizeof(me8100_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);
|
||||
|
||||
subdevice->ctrl_reg_lock = ctrl_reg_lock;
|
||||
|
||||
/* Save the subdevice index. */
|
||||
subdevice->di_idx = di_idx;
|
||||
|
||||
/* Initialize wait queue */
|
||||
init_waitqueue_head(&subdevice->wait_queue);
|
||||
|
||||
/* Register interrupt service routine. */
|
||||
subdevice->irq = irq;
|
||||
err = request_irq(subdevice->irq, me8100_isr,
|
||||
IRQF_DISABLED | IRQF_SHARED,
|
||||
ME8100_NAME, (void *)subdevice);
|
||||
|
||||
if (err) {
|
||||
PERROR("Cannot initialize subdevice base class instance.\n");
|
||||
kfree(subdevice);
|
||||
return NULL;
|
||||
}
|
||||
PINFO("Registered irq=%d.\n", subdevice->irq);
|
||||
|
||||
/* Initialize the registers */
|
||||
subdevice->ctrl_reg =
|
||||
me8100_reg_base + ME8100_CTRL_REG_A + di_idx * ME8100_REG_OFFSET;
|
||||
subdevice->port_reg =
|
||||
me8100_reg_base + ME8100_DI_REG_A + di_idx * ME8100_REG_OFFSET;
|
||||
subdevice->mask_reg =
|
||||
me8100_reg_base + ME8100_MASK_REG_A + di_idx * ME8100_REG_OFFSET;
|
||||
subdevice->pattern_reg =
|
||||
me8100_reg_base + ME8100_PATTERN_REG_A + di_idx * ME8100_REG_OFFSET;
|
||||
subdevice->din_int_reg =
|
||||
me8100_reg_base + ME8100_INT_DI_REG_A + di_idx * ME8100_REG_OFFSET;
|
||||
subdevice->irq_reset_reg =
|
||||
me8100_reg_base + ME8100_RES_INT_REG_A + di_idx * ME8100_REG_OFFSET;
|
||||
subdevice->irq_status_reg = plx_reg_base + PLX_INTCSR;
|
||||
#ifdef MEDEBUG_DEBUG_REG
|
||||
subdevice->reg_base = me8100_reg_base;
|
||||
#endif
|
||||
|
||||
/* Overload base class methods. */
|
||||
subdevice->base.me_subdevice_io_irq_start = me8100_di_io_irq_start;
|
||||
subdevice->base.me_subdevice_io_irq_wait = me8100_di_io_irq_wait;
|
||||
subdevice->base.me_subdevice_io_irq_stop = me8100_di_io_irq_stop;
|
||||
subdevice->base.me_subdevice_io_reset_subdevice =
|
||||
me8100_di_io_reset_subdevice;
|
||||
subdevice->base.me_subdevice_io_single_config =
|
||||
me8100_di_io_single_config;
|
||||
subdevice->base.me_subdevice_io_single_read = me8100_di_io_single_read;
|
||||
subdevice->base.me_subdevice_query_number_channels =
|
||||
me8100_di_query_number_channels;
|
||||
subdevice->base.me_subdevice_query_subdevice_type =
|
||||
me8100_di_query_subdevice_type;
|
||||
subdevice->base.me_subdevice_query_subdevice_caps =
|
||||
me8100_di_query_subdevice_caps;
|
||||
subdevice->base.me_subdevice_destructor = me8100_di_destructor;
|
||||
|
||||
subdevice->rised = 0;
|
||||
subdevice->irq_count = 0;
|
||||
|
||||
return subdevice;
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
/**
|
||||
* @file me8100_di.h
|
||||
*
|
||||
* @brief ME-8100 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 _ME8100_DI_H_
|
||||
#define _ME8100_DI_H_
|
||||
|
||||
#include "mesubdevice.h"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/**
|
||||
* @brief The template subdevice class.
|
||||
*/
|
||||
typedef struct me8100_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. */
|
||||
spinlock_t *ctrl_reg_lock;
|
||||
|
||||
unsigned di_idx;
|
||||
|
||||
int irq;
|
||||
volatile int rised;
|
||||
unsigned int irq_count;
|
||||
|
||||
uint status_flag; /**< Default interupt status flag */
|
||||
uint status_value; /**< Interupt status */
|
||||
uint status_value_edges; /**< Extended interupt status */
|
||||
uint line_value;
|
||||
|
||||
uint16_t compare_value;
|
||||
uint8_t filtering_flag;
|
||||
|
||||
wait_queue_head_t wait_queue;
|
||||
|
||||
unsigned long ctrl_reg;
|
||||
unsigned long port_reg;
|
||||
unsigned long mask_reg;
|
||||
unsigned long pattern_reg;
|
||||
unsigned long long din_int_reg;
|
||||
unsigned long irq_reset_reg;
|
||||
unsigned long irq_status_reg;
|
||||
#ifdef MEDEBUG_DEBUG_REG
|
||||
unsigned long reg_base;
|
||||
#endif
|
||||
|
||||
} me8100_di_subdevice_t;
|
||||
|
||||
/**
|
||||
* @brief The constructor to generate a ME-8100 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.
|
||||
*/
|
||||
me8100_di_subdevice_t *me8100_di_constructor(uint32_t me8100_reg_base,
|
||||
uint32_t plx_reg_base,
|
||||
unsigned int di_idx,
|
||||
int irq,
|
||||
spinlock_t * ctrl_leg_lock);
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,47 +0,0 @@
|
|||
/**
|
||||
* @file me8100_di_reg.h
|
||||
*
|
||||
* @brief ME-8100 digital 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 _ME8100_DI_REG_H_
|
||||
#define _ME8100_DI_REG_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define ME8100_RES_INT_REG_A 0x02 //(r, )
|
||||
#define ME8100_DI_REG_A 0x04 //(r, )
|
||||
#define ME8100_PATTERN_REG_A 0x08 //( ,w)
|
||||
#define ME8100_MASK_REG_A 0x0A //( ,w)
|
||||
#define ME8100_INT_DI_REG_A 0x0A //(r, )
|
||||
|
||||
#define ME8100_RES_INT_REG_B 0x0E //(r, )
|
||||
#define ME8100_DI_REG_B 0x10 //(r, )
|
||||
#define ME8100_PATTERN_REG_B 0x14 //( ,w)
|
||||
#define ME8100_MASK_REG_B 0x16 //( ,w)
|
||||
#define ME8100_INT_DI_REG_B 0x16 //(r, )
|
||||
|
||||
#define ME8100_REG_OFFSET 0x0C
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,391 +0,0 @@
|
|||
/**
|
||||
* @file me8100_do.c
|
||||
*
|
||||
* @brief ME-8100 digital output 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 <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "medefines.h"
|
||||
#include "meinternal.h"
|
||||
#include "meerror.h"
|
||||
|
||||
#include "medebug.h"
|
||||
#include "me8100_reg.h"
|
||||
#include "me8100_do_reg.h"
|
||||
#include "me8100_do.h"
|
||||
|
||||
/*
|
||||
* Defines
|
||||
*/
|
||||
|
||||
/*
|
||||
* Functions
|
||||
*/
|
||||
|
||||
static int me8100_do_io_reset_subdevice(struct me_subdevice *subdevice,
|
||||
struct file *filep, int flags)
|
||||
{
|
||||
me8100_do_subdevice_t *instance;
|
||||
uint16_t ctrl;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8100_do_subdevice_t *) subdevice;
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
ctrl = inw(instance->ctrl_reg);
|
||||
ctrl &= ME8100_DIO_CTRL_BIT_INTB_1 | ME8100_DIO_CTRL_BIT_INTB_0;
|
||||
outw(ctrl, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outw(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, ctrl);
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
outw(0, instance->port_reg);
|
||||
instance->port_reg_mirror = 0;
|
||||
PDEBUG_REG("port_reg outw(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->port_reg - instance->reg_base, 0);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me8100_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)
|
||||
{
|
||||
me8100_do_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
int config;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8100_do_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
config = inw(instance->ctrl_reg);
|
||||
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_HIGH_IMPEDANCE) {
|
||||
config &= ~(ME8100_DIO_CTRL_BIT_ENABLE_DIO);
|
||||
} else if (single_config == ME_SINGLE_CONFIG_DIO_SINK) {
|
||||
config |= ME8100_DIO_CTRL_BIT_ENABLE_DIO;
|
||||
config &= ~ME8100_DIO_CTRL_BIT_SOURCE;
|
||||
} else if (single_config == ME_SINGLE_CONFIG_DIO_SOURCE) {
|
||||
config |=
|
||||
ME8100_DIO_CTRL_BIT_ENABLE_DIO |
|
||||
ME8100_DIO_CTRL_BIT_SOURCE;
|
||||
} else {
|
||||
PERROR
|
||||
("Invalid port configuration specified.\n");
|
||||
err = ME_ERRNO_INVALID_SINGLE_CONFIG;
|
||||
}
|
||||
} else {
|
||||
PERROR("Invalid word number specified.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
PERROR("Invalid flags specified.\n");
|
||||
err = ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
outw(config, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outw(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, config);
|
||||
}
|
||||
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me8100_do_io_single_read(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int *value, int time_out, int flags)
|
||||
{
|
||||
me8100_do_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8100_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 < 16)) {
|
||||
*value = instance->port_reg_mirror & (0x1 << channel);
|
||||
} else {
|
||||
PERROR("Invalid bit number specified.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
break;
|
||||
|
||||
case ME_IO_SINGLE_TYPE_DIO_BYTE:
|
||||
if (channel == 0) {
|
||||
*value = instance->port_reg_mirror & 0xFF;
|
||||
} else if (channel == 1) {
|
||||
*value = (instance->port_reg_mirror >> 8) & 0xFF;
|
||||
} 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 = instance->port_reg_mirror;
|
||||
} 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 me8100_do_io_single_write(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int value, int time_out, int flags)
|
||||
{
|
||||
me8100_do_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8100_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 < 16)) {
|
||||
instance->port_reg_mirror =
|
||||
value ? (instance->
|
||||
port_reg_mirror | (0x1 << channel))
|
||||
: (instance->port_reg_mirror & ~(0x1 << channel));
|
||||
outw(instance->port_reg_mirror, instance->port_reg);
|
||||
PDEBUG_REG("port_reg outw(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->port_reg - instance->reg_base,
|
||||
instance->port_reg_mirror);
|
||||
} else {
|
||||
PERROR("Invalid bit number specified.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
break;
|
||||
|
||||
case ME_IO_SINGLE_TYPE_DIO_BYTE:
|
||||
if (channel == 0) {
|
||||
instance->port_reg_mirror &= ~0xFF;
|
||||
instance->port_reg_mirror |= value & 0xFF;
|
||||
outw(instance->port_reg_mirror, instance->port_reg);
|
||||
PDEBUG_REG("port_reg outw(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->port_reg - instance->reg_base,
|
||||
instance->port_reg_mirror);
|
||||
} else if (channel == 1) {
|
||||
instance->port_reg_mirror &= ~0xFF00;
|
||||
instance->port_reg_mirror |= (value << 8) & 0xFF00;
|
||||
outw(instance->port_reg_mirror, instance->port_reg);
|
||||
PDEBUG_REG("port_reg outw(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->port_reg - instance->reg_base,
|
||||
instance->port_reg_mirror);
|
||||
} 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) {
|
||||
instance->port_reg_mirror = value;
|
||||
outw(value, instance->port_reg);
|
||||
PDEBUG_REG("port_reg outw(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->port_reg - instance->reg_base,
|
||||
value);
|
||||
} 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 me8100_do_query_number_channels(me_subdevice_t *subdevice,
|
||||
int *number)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*number = 16;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me8100_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 me8100_do_query_subdevice_caps(me_subdevice_t *subdevice, int *caps)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*caps = ME_CAPS_DIO_SINK_SOURCE;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
me8100_do_subdevice_t *me8100_do_constructor(uint32_t reg_base,
|
||||
unsigned int do_idx,
|
||||
spinlock_t *ctrl_reg_lock)
|
||||
{
|
||||
me8100_do_subdevice_t *subdevice;
|
||||
int err;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
/* Allocate memory for subdevice instance */
|
||||
subdevice = kmalloc(sizeof(me8100_do_subdevice_t), GFP_KERNEL);
|
||||
|
||||
if (!subdevice) {
|
||||
PERROR("Cannot get memory for subdevice instance.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(subdevice, 0, sizeof(me8100_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 registers */
|
||||
if (do_idx == 0) {
|
||||
subdevice->port_reg = reg_base + ME8100_DO_REG_A;
|
||||
subdevice->ctrl_reg = reg_base + ME8100_CTRL_REG_A;
|
||||
} else if (do_idx == 1) {
|
||||
subdevice->port_reg = reg_base + ME8100_DO_REG_B;
|
||||
subdevice->ctrl_reg = reg_base + ME8100_CTRL_REG_B;
|
||||
} else {
|
||||
PERROR("Wrong subdevice idx=%d.\n", do_idx);
|
||||
kfree(subdevice);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef MEDEBUG_DEBUG_REG
|
||||
subdevice->reg_base = reg_base;
|
||||
#endif
|
||||
|
||||
// Initialize spin locks.
|
||||
spin_lock_init(&subdevice->subdevice_lock);
|
||||
subdevice->ctrl_reg_lock = ctrl_reg_lock;
|
||||
|
||||
/* Save the subdevice index */
|
||||
subdevice->do_idx = do_idx;
|
||||
|
||||
/* Overload base class methods. */
|
||||
subdevice->base.me_subdevice_io_reset_subdevice =
|
||||
me8100_do_io_reset_subdevice;
|
||||
subdevice->base.me_subdevice_io_single_config =
|
||||
me8100_do_io_single_config;
|
||||
subdevice->base.me_subdevice_io_single_read = me8100_do_io_single_read;
|
||||
subdevice->base.me_subdevice_io_single_write =
|
||||
me8100_do_io_single_write;
|
||||
subdevice->base.me_subdevice_query_number_channels =
|
||||
me8100_do_query_number_channels;
|
||||
subdevice->base.me_subdevice_query_subdevice_type =
|
||||
me8100_do_query_subdevice_type;
|
||||
subdevice->base.me_subdevice_query_subdevice_caps =
|
||||
me8100_do_query_subdevice_caps;
|
||||
|
||||
return subdevice;
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
/**
|
||||
* @file me8100_do.h
|
||||
*
|
||||
* @brief ME-8100 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 _ME8100_DO_H_
|
||||
#define _ME8100_DO_H_
|
||||
|
||||
#include "mesubdevice.h"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/**
|
||||
* @brief The template subdevice class.
|
||||
*/
|
||||
typedef struct me8100_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. */
|
||||
spinlock_t *ctrl_reg_lock; /**< Spin lock to protect the #ctrl_reg. */
|
||||
|
||||
unsigned int do_idx;
|
||||
|
||||
uint16_t port_reg_mirror; /**< Mirror used to store current port register setting which is write only. */
|
||||
|
||||
unsigned long port_reg; /**< Register holding the port status. */
|
||||
unsigned long ctrl_reg; /**< Control register. */
|
||||
#ifdef MEDEBUG_DEBUG_REG
|
||||
unsigned long reg_base;
|
||||
#endif
|
||||
} me8100_do_subdevice_t;
|
||||
|
||||
/**
|
||||
* @brief The constructor to generate a ME-8100 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.
|
||||
*/
|
||||
me8100_do_subdevice_t *me8100_do_constructor(uint32_t reg_base,
|
||||
unsigned int do_idx,
|
||||
spinlock_t * ctrl_reg_lock);
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,36 +0,0 @@
|
|||
/**
|
||||
* @file me8100_ao_reg.h
|
||||
*
|
||||
* @brief ME-8100 analog 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 _ME8100_DO_REG_H_
|
||||
#define _ME8100_DO_REG_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define ME8100_DO_REG_A 0x06 //( ,w)
|
||||
#define ME8100_DO_REG_B 0x12 //( ,w)
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,41 +0,0 @@
|
|||
/**
|
||||
* @file me8100_reg.h
|
||||
*
|
||||
* @brief ME-8100 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 _ME8100_REG_H_
|
||||
#define _ME8100_REG_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define ME8100_CTRL_REG_A 0x00 //( ,w)
|
||||
#define ME8100_CTRL_REG_B 0x0C //( ,w)
|
||||
|
||||
#define ME8100_DIO_CTRL_BIT_SOURCE 0x10
|
||||
#define ME8100_DIO_CTRL_BIT_INTB_1 0x20
|
||||
#define ME8100_DIO_CTRL_BIT_INTB_0 0x40
|
||||
#define ME8100_DIO_CTRL_BIT_ENABLE_DIO 0x80
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,192 +0,0 @@
|
|||
/**
|
||||
* @file me8200_device.c
|
||||
*
|
||||
* @brief ME-8200 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 "meplx_reg.h"
|
||||
#include "medevice.h"
|
||||
#include "me8200_device.h"
|
||||
#include "mesubdevice.h"
|
||||
#include "me8200_di.h"
|
||||
#include "me8200_do.h"
|
||||
#include "me8200_dio.h"
|
||||
|
||||
me_device_t *me8200_pci_constructor(struct pci_dev *pci_device)
|
||||
{
|
||||
me8200_device_t *me8200_device;
|
||||
me_subdevice_t *subdevice;
|
||||
unsigned int version_idx;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
// Allocate structure for device instance.
|
||||
me8200_device = kmalloc(sizeof(me8200_device_t), GFP_KERNEL);
|
||||
|
||||
if (!me8200_device) {
|
||||
PERROR("Cannot get memory for device instance.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(me8200_device, 0, sizeof(me8200_device_t));
|
||||
|
||||
// Initialize base class structure.
|
||||
err = me_device_pci_init((me_device_t *) me8200_device, pci_device);
|
||||
|
||||
if (err) {
|
||||
kfree(me8200_device);
|
||||
PERROR("Cannot initialize device base class.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get the index in the device version information table. */
|
||||
version_idx =
|
||||
me8200_versions_get_device_index(me8200_device->base.info.pci.
|
||||
device_id);
|
||||
|
||||
// Initialize spin lock .
|
||||
spin_lock_init(&me8200_device->irq_ctrl_lock);
|
||||
spin_lock_init(&me8200_device->irq_mode_lock);
|
||||
spin_lock_init(&me8200_device->dio_ctrl_lock);
|
||||
|
||||
/* Setup the PLX interrupt configuration */
|
||||
outl(PLX_INTCSR_LOCAL_INT1_EN |
|
||||
PLX_INTCSR_LOCAL_INT1_POL |
|
||||
PLX_INTCSR_LOCAL_INT2_EN |
|
||||
PLX_INTCSR_LOCAL_INT2_POL |
|
||||
PLX_INTCSR_PCI_INT_EN,
|
||||
me8200_device->base.info.pci.reg_bases[1] + PLX_INTCSR);
|
||||
|
||||
// Create subdevice instances.
|
||||
|
||||
for (i = 0; i < me8200_versions[version_idx].di_subdevices; i++) {
|
||||
subdevice =
|
||||
(me_subdevice_t *) me8200_di_constructor(me8200_device->
|
||||
base.info.pci.
|
||||
reg_bases[2], i,
|
||||
me8200_device->
|
||||
base.irq,
|
||||
&me8200_device->
|
||||
irq_ctrl_lock,
|
||||
&me8200_device->
|
||||
irq_mode_lock);
|
||||
|
||||
if (!subdevice) {
|
||||
me_device_deinit((me_device_t *) me8200_device);
|
||||
kfree(me8200_device);
|
||||
PERROR("Cannot get memory for subdevice.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
me_slist_add_subdevice_tail(&me8200_device->base.slist,
|
||||
subdevice);
|
||||
}
|
||||
|
||||
for (i = 0; i < me8200_versions[version_idx].do_subdevices; i++) {
|
||||
subdevice =
|
||||
(me_subdevice_t *) me8200_do_constructor(me8200_device->
|
||||
base.info.pci.
|
||||
reg_bases[2], i,
|
||||
me8200_device->
|
||||
base.irq,
|
||||
&me8200_device->
|
||||
irq_mode_lock);
|
||||
|
||||
if (!subdevice) {
|
||||
me_device_deinit((me_device_t *) me8200_device);
|
||||
kfree(me8200_device);
|
||||
PERROR("Cannot get memory for subdevice.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
me_slist_add_subdevice_tail(&me8200_device->base.slist,
|
||||
subdevice);
|
||||
}
|
||||
|
||||
for (i = 0; i < me8200_versions[version_idx].dio_subdevices; i++) {
|
||||
subdevice =
|
||||
(me_subdevice_t *) me8200_dio_constructor(me8200_device->
|
||||
base.info.pci.
|
||||
reg_bases[2], i,
|
||||
&me8200_device->
|
||||
dio_ctrl_lock);
|
||||
|
||||
if (!subdevice) {
|
||||
me_device_deinit((me_device_t *) me8200_device);
|
||||
kfree(me8200_device);
|
||||
PERROR("Cannot get memory for subdevice.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
me_slist_add_subdevice_tail(&me8200_device->base.slist,
|
||||
subdevice);
|
||||
}
|
||||
|
||||
return (me_device_t *) me8200_device;
|
||||
}
|
||||
EXPORT_SYMBOL(me8200_pci_constructor);
|
||||
|
||||
// Init and exit of module.
|
||||
|
||||
static int __init me8200_init(void)
|
||||
{
|
||||
PDEBUG("executed.\n.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit me8200_exit(void)
|
||||
{
|
||||
PDEBUG("executed.\n.");
|
||||
}
|
||||
|
||||
module_init(me8200_init);
|
||||
|
||||
module_exit(me8200_exit);
|
||||
|
||||
// Administrative stuff for modinfo.
|
||||
MODULE_AUTHOR("Guenter Gebhardt <g.gebhardt@meilhaus.de>");
|
||||
MODULE_DESCRIPTION("Device Driver Module for Template Device");
|
||||
MODULE_SUPPORTED_DEVICE("Meilhaus Template Devices");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,97 +0,0 @@
|
|||
/**
|
||||
* @file me8200_device.h
|
||||
*
|
||||
* @brief ME-8200 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 _ME8200_DEVICE_H
|
||||
#define _ME8200_DEVICE_H
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include "medevice.h"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/**
|
||||
* @brief Structure holding ME-8200 device capabilities.
|
||||
*/
|
||||
typedef struct me8200_version {
|
||||
uint16_t device_id;
|
||||
unsigned int di_subdevices;
|
||||
unsigned int do_subdevices;
|
||||
unsigned int dio_subdevices;
|
||||
} me8200_version_t;
|
||||
|
||||
/**
|
||||
* @brief Device capabilities.
|
||||
*/
|
||||
static me8200_version_t me8200_versions[] = {
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME8200_A, 1, 1, 2},
|
||||
{PCI_DEVICE_ID_MEILHAUS_ME8200_B, 2, 2, 2},
|
||||
{0},
|
||||
};
|
||||
|
||||
#define ME8200_DEVICE_VERSIONS (ARRAY_SIZE(me8200_versions) - 1) /**< Returns the number of entries in #me8200_versions. */
|
||||
|
||||
/**
|
||||
* @brief Returns the index of the device entry in #me8200_versions.
|
||||
*
|
||||
* @param device_id The PCI device id of the device to query.
|
||||
* @return The index of the device in #me8200_versions.
|
||||
*/
|
||||
static inline unsigned int me8200_versions_get_device_index(uint16_t device_id)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < ME8200_DEVICE_VERSIONS; i++)
|
||||
if (me8200_versions[i].device_id == device_id)
|
||||
break;
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The ME-8200 device class structure.
|
||||
*/
|
||||
typedef struct me8200_device {
|
||||
me_device_t base; /**< The Meilhaus device base class. */
|
||||
|
||||
/* Child class attributes. */
|
||||
spinlock_t irq_ctrl_lock; /**< Lock for the interrupt control register. */
|
||||
spinlock_t irq_mode_lock; /**< Lock for the interrupt mode register. */
|
||||
spinlock_t dio_ctrl_lock; /**< Lock for the digital i/o control register. */
|
||||
} me8200_device_t;
|
||||
|
||||
/**
|
||||
* @brief The ME-8200 device class constructor.
|
||||
*
|
||||
* @param pci_device The pci device structure given by the PCI subsystem.
|
||||
*
|
||||
* @return On succes a new ME-8200 device instance. \n
|
||||
* NULL on error.
|
||||
*/
|
||||
me_device_t *me8200_pci_constructor(struct pci_dev *pci_device)
|
||||
__attribute__ ((weak));
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,832 +0,0 @@
|
|||
/**
|
||||
* @file me8200_di.c
|
||||
*
|
||||
* @brief ME-8200 digital 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 <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "medefines.h"
|
||||
#include "meerror.h"
|
||||
|
||||
#include "meids.h"
|
||||
#include "medebug.h"
|
||||
#include "me8200_reg.h"
|
||||
#include "me8200_di_reg.h"
|
||||
#include "me8200_di.h"
|
||||
|
||||
/// Defines
|
||||
static void me8200_di_destructor(struct me_subdevice *subdevice);
|
||||
static int me8200_di_io_irq_start(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int irq_source,
|
||||
int irq_edge, int irq_arg, int flags);
|
||||
static int me8200_di_io_irq_wait(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int *irq_count,
|
||||
int *value, int time_out, int flags);
|
||||
static int me8200_di_io_irq_stop(me_subdevice_t *subdevice,
|
||||
struct file *filep, int channel, int flags);
|
||||
static int me8200_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);
|
||||
static int me8200_di_io_single_read(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int *value, int time_out, int flags);
|
||||
static int me8200_di_io_reset_subdevice(struct me_subdevice *subdevice,
|
||||
struct file *filep, int flags);
|
||||
static int me8200_di_query_number_channels(me_subdevice_t *subdevice,
|
||||
int *number);
|
||||
static int me8200_di_query_subdevice_type(me_subdevice_t *subdevice,
|
||||
int *type, int *subtype);
|
||||
static int me8200_di_query_subdevice_caps(me_subdevice_t *subdevice,
|
||||
int *caps);
|
||||
static irqreturn_t me8200_isr(int irq, void *dev_id);
|
||||
static irqreturn_t me8200_isr_EX(int irq, void *dev_id);
|
||||
static void me8200_di_check_version(me8200_di_subdevice_t *instance,
|
||||
unsigned long addr);
|
||||
|
||||
///Functions
|
||||
static int me8200_di_io_irq_start(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int irq_source,
|
||||
int irq_edge, int irq_arg, int flags)
|
||||
{
|
||||
me8200_di_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
volatile uint8_t tmp;
|
||||
unsigned long status;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8200_di_subdevice_t *) subdevice;
|
||||
|
||||
if (irq_source == ME_IRQ_SOURCE_DIO_PATTERN) {
|
||||
if (flags &
|
||||
~(ME_IO_IRQ_START_PATTERN_FILTERING |
|
||||
ME_IO_IRQ_START_DIO_BYTE)) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (irq_edge != ME_IRQ_EDGE_NOT_USED) {
|
||||
PERROR("Invalid irq edge specified.\n");
|
||||
return ME_ERRNO_INVALID_IRQ_EDGE;
|
||||
}
|
||||
} else if (irq_source == ME_IRQ_SOURCE_DIO_MASK) {
|
||||
if (flags &
|
||||
~(ME_IO_IRQ_START_EXTENDED_STATUS |
|
||||
ME_IO_IRQ_START_DIO_BYTE)) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if ((irq_edge != ME_IRQ_EDGE_RISING)
|
||||
&& (irq_edge != ME_IRQ_EDGE_FALLING)
|
||||
&& (irq_edge != ME_IRQ_EDGE_ANY)) {
|
||||
PERROR("Invalid irq edge specified.\n");
|
||||
return ME_ERRNO_INVALID_IRQ_EDGE;
|
||||
}
|
||||
|
||||
if (!(irq_arg & 0xFF)) {
|
||||
PERROR("No mask specified.\n");
|
||||
return ME_ERRNO_INVALID_IRQ_ARG;
|
||||
}
|
||||
} else {
|
||||
PERROR("Invalid irq source specified.\n");
|
||||
return ME_ERRNO_INVALID_IRQ_SOURCE;
|
||||
}
|
||||
|
||||
if (channel) {
|
||||
PERROR("Invalid channel specified.\n");
|
||||
return ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, status);
|
||||
if (irq_source == ME_IRQ_SOURCE_DIO_PATTERN) {
|
||||
outb(irq_arg, instance->compare_reg);
|
||||
PDEBUG_REG("compare_reg outb(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->compare_reg - instance->reg_base, irq_arg);
|
||||
outb(0xFF, instance->mask_reg);
|
||||
PDEBUG_REG("mask_reg outb(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->mask_reg - instance->reg_base, 0xff);
|
||||
instance->compare_value = irq_arg;
|
||||
instance->filtering_flag =
|
||||
(flags & ME_IO_IRQ_START_PATTERN_FILTERING) ? 1 : 0;
|
||||
}
|
||||
if (irq_source == ME_IRQ_SOURCE_DIO_MASK) {
|
||||
outb(irq_arg, instance->mask_reg);
|
||||
PDEBUG_REG("mask_reg outb(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->mask_reg - instance->reg_base, irq_arg);
|
||||
instance->filtering_flag = 0;
|
||||
}
|
||||
|
||||
spin_lock(instance->irq_mode_lock);
|
||||
tmp = inb(instance->irq_mode_reg);
|
||||
tmp &=
|
||||
~(ME8200_IRQ_MODE_MASK <<
|
||||
(ME8200_IRQ_MODE_DI_SHIFT * instance->di_idx));
|
||||
if (irq_source == ME_IRQ_SOURCE_DIO_PATTERN) {
|
||||
tmp |=
|
||||
ME8200_IRQ_MODE_MASK_COMPARE << (ME8200_IRQ_MODE_DI_SHIFT *
|
||||
instance->di_idx);
|
||||
}
|
||||
|
||||
if (irq_source == ME_IRQ_SOURCE_DIO_MASK) {
|
||||
tmp |=
|
||||
ME8200_IRQ_MODE_MASK_MASK << (ME8200_IRQ_MODE_DI_SHIFT *
|
||||
instance->di_idx);
|
||||
}
|
||||
outb(tmp, instance->irq_mode_reg);
|
||||
PDEBUG_REG("irq_mode_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->irq_mode_reg - instance->reg_base, tmp);
|
||||
spin_unlock(instance->irq_mode_lock);
|
||||
|
||||
spin_lock(instance->irq_ctrl_lock);
|
||||
tmp = inb(instance->irq_ctrl_reg);
|
||||
tmp |=
|
||||
(ME8200_DI_IRQ_CTRL_BIT_CLEAR <<
|
||||
(ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx));
|
||||
tmp |=
|
||||
ME8200_DI_IRQ_CTRL_BIT_ENABLE << (ME8200_DI_IRQ_CTRL_SHIFT *
|
||||
instance->di_idx);
|
||||
|
||||
if (irq_source == ME_IRQ_SOURCE_DIO_MASK) {
|
||||
tmp &=
|
||||
~(ME8200_DI_IRQ_CTRL_MASK_EDGE <<
|
||||
(ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx));
|
||||
if (irq_edge == ME_IRQ_EDGE_RISING) {
|
||||
tmp |=
|
||||
ME8200_DI_IRQ_CTRL_MASK_EDGE_RISING <<
|
||||
(ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx);
|
||||
} else if (irq_edge == ME_IRQ_EDGE_FALLING) {
|
||||
tmp |=
|
||||
ME8200_DI_IRQ_CTRL_MASK_EDGE_FALLING <<
|
||||
(ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx);
|
||||
} else if (irq_edge == ME_IRQ_EDGE_ANY) {
|
||||
tmp |=
|
||||
ME8200_DI_IRQ_CTRL_MASK_EDGE_ANY <<
|
||||
(ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx);
|
||||
}
|
||||
}
|
||||
outb(tmp, instance->irq_ctrl_reg);
|
||||
PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->irq_ctrl_reg - instance->reg_base, tmp);
|
||||
tmp &=
|
||||
~(ME8200_DI_IRQ_CTRL_BIT_CLEAR <<
|
||||
(ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx));
|
||||
outb(tmp, instance->irq_ctrl_reg);
|
||||
PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->irq_ctrl_reg - instance->reg_base, tmp);
|
||||
|
||||
instance->line_value = inb(instance->port_reg);
|
||||
spin_unlock(instance->irq_ctrl_lock);
|
||||
|
||||
instance->rised = 0;
|
||||
instance->status_value = 0;
|
||||
instance->status_value_edges = 0;
|
||||
instance->status_flag = flags & ME_IO_IRQ_START_EXTENDED_STATUS;
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, status);
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me8200_di_io_irq_wait(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int *irq_count,
|
||||
int *value, int time_out, int flags)
|
||||
{
|
||||
me8200_di_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
long t = 0;
|
||||
unsigned long cpu_flags;
|
||||
int count;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
PDEVELOP("PID: %d.\n", current->pid);
|
||||
|
||||
instance = (me8200_di_subdevice_t *) subdevice;
|
||||
|
||||
if (flags &
|
||||
~(ME_IO_IRQ_WAIT_NORMAL_STATUS | ME_IO_IRQ_WAIT_EXTENDED_STATUS)) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (channel) {
|
||||
PERROR("Invalid channel specified.\n");
|
||||
return ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
|
||||
if (time_out < 0) {
|
||||
PERROR("Invalid time_out specified.\n");
|
||||
return ME_ERRNO_INVALID_TIMEOUT;
|
||||
}
|
||||
|
||||
if (time_out) {
|
||||
t = (time_out * HZ) / 1000;
|
||||
|
||||
if (t == 0)
|
||||
t = 1;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
if (instance->rised <= 0) {
|
||||
instance->rised = 0;
|
||||
count = instance->count;
|
||||
|
||||
if (time_out) {
|
||||
t = wait_event_interruptible_timeout(instance->
|
||||
wait_queue,
|
||||
((count !=
|
||||
instance->count)
|
||||
|| (instance->
|
||||
rised < 0)),
|
||||
t);
|
||||
// t = wait_event_interruptible_timeout(instance->wait_queue, (instance->rised != 0), t);
|
||||
if (t == 0) {
|
||||
PERROR("Wait on interrupt timed out.\n");
|
||||
err = ME_ERRNO_TIMEOUT;
|
||||
}
|
||||
} else {
|
||||
wait_event_interruptible(instance->wait_queue,
|
||||
((count != instance->count)
|
||||
|| (instance->rised < 0)));
|
||||
// wait_event_interruptible(instance->wait_queue, (instance->rised != 0));
|
||||
}
|
||||
|
||||
if (instance->rised < 0) {
|
||||
PERROR("Wait on interrupt aborted by user.\n");
|
||||
err = ME_ERRNO_CANCELLED;
|
||||
}
|
||||
}
|
||||
|
||||
if (signal_pending(current)) {
|
||||
PERROR("Wait on interrupt aborted by signal.\n");
|
||||
err = ME_ERRNO_SIGNAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
|
||||
*irq_count = instance->count;
|
||||
if (!err) {
|
||||
if (flags & ME_IO_IRQ_WAIT_NORMAL_STATUS) {
|
||||
*value = instance->status_value;
|
||||
} else if (flags & ME_IO_IRQ_WAIT_EXTENDED_STATUS) {
|
||||
*value = instance->status_value_edges;
|
||||
} else { // Use default
|
||||
if (!instance->status_flag) {
|
||||
*value = instance->status_value;
|
||||
} else {
|
||||
*value = instance->status_value_edges;
|
||||
}
|
||||
}
|
||||
instance->rised = 0;
|
||||
/*
|
||||
instance->status_value = 0;
|
||||
instance->status_value_edges = 0;
|
||||
*/
|
||||
} else {
|
||||
*value = 0;
|
||||
}
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me8200_di_io_irq_stop(me_subdevice_t *subdevice,
|
||||
struct file *filep, int channel, int flags)
|
||||
{
|
||||
me8200_di_subdevice_t *instance;
|
||||
uint8_t tmp;
|
||||
unsigned long status;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8200_di_subdevice_t *) subdevice;
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (channel) {
|
||||
PERROR("Invalid channel specified.\n");
|
||||
return ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER spin_lock_irqsave(&instance->subdevice_lock, status);
|
||||
spin_lock(instance->irq_ctrl_lock);
|
||||
tmp = inb(instance->irq_ctrl_reg);
|
||||
tmp |=
|
||||
(ME8200_DI_IRQ_CTRL_BIT_ENABLE <<
|
||||
(ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx));
|
||||
outb(tmp, instance->irq_ctrl_reg);
|
||||
PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->irq_ctrl_reg - instance->reg_base, tmp);
|
||||
tmp &=
|
||||
~(ME8200_DI_IRQ_CTRL_BIT_ENABLE <<
|
||||
(ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx));
|
||||
tmp |=
|
||||
(ME8200_DI_IRQ_CTRL_BIT_CLEAR <<
|
||||
(ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx));
|
||||
// tmp &= ~(ME8200_DI_IRQ_CTRL_BIT_CLEAR << (ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx));
|
||||
outb(tmp, instance->irq_ctrl_reg);
|
||||
PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->irq_ctrl_reg - instance->reg_base, tmp);
|
||||
spin_unlock(instance->irq_ctrl_lock);
|
||||
|
||||
instance->rised = -1;
|
||||
instance->status_value = 0;
|
||||
instance->status_value_edges = 0;
|
||||
instance->filtering_flag = 0;
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, status);
|
||||
wake_up_interruptible_all(&instance->wait_queue);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me8200_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)
|
||||
{
|
||||
me8200_di_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
unsigned long status;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8200_di_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, status);
|
||||
|
||||
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) {
|
||||
} else {
|
||||
PERROR("Invalid port direction specified.\n");
|
||||
err = ME_ERRNO_INVALID_SINGLE_CONFIG;
|
||||
}
|
||||
} else {
|
||||
PERROR("Invalid channel number.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
PERROR("Invalid flags specified.\n");
|
||||
err = ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, status);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me8200_di_io_single_read(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int *value, int time_out, int flags)
|
||||
{
|
||||
me8200_di_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
unsigned long status;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8200_di_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, status);
|
||||
|
||||
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 channel number.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
PERROR("Invalid flags specified.\n");
|
||||
err = ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, status);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me8200_di_io_reset_subdevice(struct me_subdevice *subdevice,
|
||||
struct file *filep, int flags)
|
||||
{
|
||||
me8200_di_subdevice_t *instance = (me8200_di_subdevice_t *) subdevice;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
instance->count = 0;
|
||||
return me8200_di_io_irq_stop(subdevice, filep, 0, 0);
|
||||
}
|
||||
|
||||
static int me8200_di_query_number_channels(me_subdevice_t *subdevice,
|
||||
int *number)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*number = 8;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me8200_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 me8200_di_query_subdevice_caps(me_subdevice_t *subdevice, int *caps)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*caps =
|
||||
ME_CAPS_DIO_BIT_PATTERN_IRQ |
|
||||
ME_CAPS_DIO_BIT_MASK_IRQ_EDGE_RISING |
|
||||
ME_CAPS_DIO_BIT_MASK_IRQ_EDGE_FALLING |
|
||||
ME_CAPS_DIO_BIT_MASK_IRQ_EDGE_ANY;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static irqreturn_t me8200_isr(int irq, void *dev_id)
|
||||
{
|
||||
me8200_di_subdevice_t *instance;
|
||||
uint8_t ctrl;
|
||||
uint8_t irq_status;
|
||||
uint8_t line_value = 0;
|
||||
uint8_t line_status = 0;
|
||||
uint32_t status_val = 0;
|
||||
|
||||
instance = (me8200_di_subdevice_t *) dev_id;
|
||||
|
||||
if (irq != instance->irq) {
|
||||
PERROR("Incorrect interrupt num: %d.\n", irq);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
irq_status = inb(instance->irq_status_reg);
|
||||
if (!irq_status) {
|
||||
PINFO
|
||||
("%ld Shared interrupt. %s(): idx=%d irq_status_reg=0x%04X\n",
|
||||
jiffies, __func__, instance->di_idx, irq_status);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->irq_ctrl_lock);
|
||||
ctrl = inb(instance->irq_ctrl_reg);
|
||||
ctrl |=
|
||||
ME8200_DI_IRQ_CTRL_BIT_CLEAR << (ME8200_DI_IRQ_CTRL_SHIFT *
|
||||
instance->di_idx);
|
||||
outb(ctrl, instance->irq_ctrl_reg);
|
||||
PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->irq_ctrl_reg - instance->reg_base, ctrl);
|
||||
ctrl &=
|
||||
~(ME8200_DI_IRQ_CTRL_BIT_CLEAR <<
|
||||
(ME8200_DI_IRQ_CTRL_SHIFT * instance->di_idx));
|
||||
outb(ctrl, instance->irq_ctrl_reg);
|
||||
PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->irq_ctrl_reg - instance->reg_base, ctrl);
|
||||
|
||||
line_value = inb(instance->port_reg);
|
||||
spin_unlock(instance->irq_ctrl_lock);
|
||||
|
||||
line_status = ((uint8_t) instance->line_value ^ line_value);
|
||||
|
||||
// Make extended information.
|
||||
status_val |= (0x00FF & (~(uint8_t) instance->line_value & line_value)) << 16; //Raise
|
||||
status_val |= (0x00FF & ((uint8_t) instance->line_value & ~line_value)); //Fall
|
||||
|
||||
instance->line_value = (int)line_value;
|
||||
|
||||
if (instance->rised == 0) {
|
||||
instance->status_value = irq_status | line_status;
|
||||
instance->status_value_edges = status_val;
|
||||
} else {
|
||||
instance->status_value |= irq_status | line_status;
|
||||
instance->status_value_edges |= status_val;
|
||||
}
|
||||
|
||||
if (instance->filtering_flag) { // For compare mode only.
|
||||
if (instance->compare_value == instance->line_value) {
|
||||
instance->rised = 1;
|
||||
instance->count++;
|
||||
}
|
||||
} else {
|
||||
instance->rised = 1;
|
||||
instance->count++;
|
||||
}
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
wake_up_interruptible_all(&instance->wait_queue);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t me8200_isr_EX(int irq, void *dev_id)
|
||||
{
|
||||
me8200_di_subdevice_t *instance;
|
||||
uint8_t irq_status = 0;
|
||||
uint16_t irq_status_EX = 0;
|
||||
uint32_t status_val = 0;
|
||||
int i, j;
|
||||
|
||||
instance = (me8200_di_subdevice_t *) dev_id;
|
||||
|
||||
if (irq != instance->irq) {
|
||||
PERROR("Incorrect interrupt num: %d.\n", irq);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
//Reset latches. Copy status to extended registers.
|
||||
irq_status = inb(instance->irq_status_reg);
|
||||
PDEBUG_REG("idx=%d irq_status_reg=0x%02X\n", instance->di_idx,
|
||||
irq_status);
|
||||
|
||||
if (!irq_status) {
|
||||
PINFO
|
||||
("%ld Shared interrupt. %s(): idx=%d irq_status_reg=0x%04X\n",
|
||||
jiffies, __func__, instance->di_idx, irq_status);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
irq_status_EX = inb(instance->irq_status_low_reg);
|
||||
irq_status_EX |= (inb(instance->irq_status_high_reg) << 8);
|
||||
|
||||
PDEVELOP("EXTENDED REG: 0x%04x\n", irq_status_EX);
|
||||
instance->line_value = inb(instance->port_reg);
|
||||
|
||||
// Format extended information.
|
||||
for (i = 0, j = 0; i < 8; i++, j += 2) {
|
||||
status_val |= ((0x01 << j) & irq_status_EX) >> (j - i); //Fall
|
||||
status_val |= ((0x01 << (j + 1)) & irq_status_EX) << (15 - j + i); //Raise
|
||||
}
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
if (instance->rised == 0) {
|
||||
instance->status_value = irq_status;
|
||||
instance->status_value_edges = status_val;
|
||||
} else {
|
||||
instance->status_value |= irq_status;
|
||||
instance->status_value_edges |= status_val;
|
||||
}
|
||||
|
||||
if (instance->filtering_flag) { // For compare mode only.
|
||||
if (instance->compare_value == instance->line_value) {
|
||||
instance->rised = 1;
|
||||
instance->count++;
|
||||
}
|
||||
} else {
|
||||
instance->rised = 1;
|
||||
instance->count++;
|
||||
}
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
wake_up_interruptible_all(&instance->wait_queue);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void me8200_di_destructor(struct me_subdevice *subdevice)
|
||||
{
|
||||
me8200_di_subdevice_t *instance;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8200_di_subdevice_t *) subdevice;
|
||||
|
||||
free_irq(instance->irq, (void *)instance);
|
||||
me_subdevice_deinit(&instance->base);
|
||||
kfree(instance);
|
||||
}
|
||||
|
||||
me8200_di_subdevice_t *me8200_di_constructor(uint32_t me8200_regbase,
|
||||
unsigned int di_idx,
|
||||
int irq,
|
||||
spinlock_t *irq_ctrl_lock,
|
||||
spinlock_t *irq_mode_lock)
|
||||
{
|
||||
me8200_di_subdevice_t *subdevice;
|
||||
int err;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
/* Allocate memory for subdevice instance */
|
||||
subdevice = kmalloc(sizeof(me8200_di_subdevice_t), GFP_KERNEL);
|
||||
|
||||
if (!subdevice) {
|
||||
PERROR("Cannot get memory for subdevice instance.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(subdevice, 0, sizeof(me8200_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;
|
||||
}
|
||||
// Check firmware version.
|
||||
me8200_di_check_version(subdevice,
|
||||
me8200_regbase + ME8200_FIRMWARE_VERSION_REG);
|
||||
|
||||
// Initialize spin locks.
|
||||
spin_lock_init(&subdevice->subdevice_lock);
|
||||
|
||||
subdevice->irq_ctrl_lock = irq_ctrl_lock;
|
||||
subdevice->irq_mode_lock = irq_mode_lock;
|
||||
|
||||
/* Save the subdevice index. */
|
||||
subdevice->di_idx = di_idx;
|
||||
|
||||
/* Initialize registers */
|
||||
if (di_idx == 0) {
|
||||
subdevice->port_reg = me8200_regbase + ME8200_DI_PORT_0_REG;
|
||||
subdevice->mask_reg = me8200_regbase + ME8200_DI_MASK_0_REG;
|
||||
subdevice->compare_reg =
|
||||
me8200_regbase + ME8200_DI_COMPARE_0_REG;
|
||||
subdevice->irq_status_reg =
|
||||
me8200_regbase + ME8200_DI_CHANGE_0_REG;
|
||||
|
||||
subdevice->irq_status_low_reg =
|
||||
me8200_regbase + ME8200_DI_EXTEND_CHANGE_0_LOW_REG;
|
||||
subdevice->irq_status_high_reg =
|
||||
me8200_regbase + ME8200_DI_EXTEND_CHANGE_0_HIGH_REG;
|
||||
} else if (di_idx == 1) {
|
||||
subdevice->port_reg = me8200_regbase + ME8200_DI_PORT_1_REG;
|
||||
subdevice->mask_reg = me8200_regbase + ME8200_DI_MASK_1_REG;
|
||||
subdevice->compare_reg =
|
||||
me8200_regbase + ME8200_DI_COMPARE_1_REG;
|
||||
subdevice->irq_status_reg =
|
||||
me8200_regbase + ME8200_DI_CHANGE_1_REG;
|
||||
|
||||
subdevice->irq_status_low_reg =
|
||||
me8200_regbase + ME8200_DI_EXTEND_CHANGE_1_LOW_REG;
|
||||
subdevice->irq_status_high_reg =
|
||||
me8200_regbase + ME8200_DI_EXTEND_CHANGE_1_HIGH_REG;
|
||||
} else {
|
||||
PERROR("Wrong subdevice idx=%d.\n", di_idx);
|
||||
kfree(subdevice);
|
||||
return NULL;
|
||||
}
|
||||
subdevice->irq_ctrl_reg = me8200_regbase + ME8200_DI_IRQ_CTRL_REG;
|
||||
subdevice->irq_mode_reg = me8200_regbase + ME8200_IRQ_MODE_REG;
|
||||
#ifdef MEDEBUG_DEBUG_REG
|
||||
subdevice->reg_base = me8200_regbase;
|
||||
#endif
|
||||
|
||||
/* Initialize wait queue */
|
||||
init_waitqueue_head(&subdevice->wait_queue);
|
||||
|
||||
/* Overload base class methods. */
|
||||
subdevice->base.me_subdevice_io_irq_start = me8200_di_io_irq_start;
|
||||
subdevice->base.me_subdevice_io_irq_wait = me8200_di_io_irq_wait;
|
||||
subdevice->base.me_subdevice_io_irq_stop = me8200_di_io_irq_stop;
|
||||
subdevice->base.me_subdevice_io_reset_subdevice =
|
||||
me8200_di_io_reset_subdevice;
|
||||
subdevice->base.me_subdevice_io_single_config =
|
||||
me8200_di_io_single_config;
|
||||
subdevice->base.me_subdevice_io_single_read = me8200_di_io_single_read;
|
||||
subdevice->base.me_subdevice_query_number_channels =
|
||||
me8200_di_query_number_channels;
|
||||
subdevice->base.me_subdevice_query_subdevice_type =
|
||||
me8200_di_query_subdevice_type;
|
||||
subdevice->base.me_subdevice_query_subdevice_caps =
|
||||
me8200_di_query_subdevice_caps;
|
||||
subdevice->base.me_subdevice_destructor = me8200_di_destructor;
|
||||
|
||||
subdevice->rised = 0;
|
||||
subdevice->count = 0;
|
||||
|
||||
/* Register interrupt service routine. */
|
||||
subdevice->irq = irq;
|
||||
if (subdevice->version > 0) { // NEW
|
||||
err = request_irq(subdevice->irq, me8200_isr_EX,
|
||||
IRQF_DISABLED | IRQF_SHARED,
|
||||
ME8200_NAME, (void *)subdevice);
|
||||
} else { //OLD
|
||||
err = request_irq(subdevice->irq, me8200_isr,
|
||||
IRQF_DISABLED | IRQF_SHARED,
|
||||
ME8200_NAME, (void *)subdevice);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
PERROR("Cannot initialize subdevice base class instance.\n");
|
||||
kfree(subdevice);
|
||||
return NULL;
|
||||
}
|
||||
PDEBUG("Registred irq=%d.\n", subdevice->irq);
|
||||
|
||||
return subdevice;
|
||||
}
|
||||
|
||||
static void me8200_di_check_version(me8200_di_subdevice_t *instance,
|
||||
unsigned long addr)
|
||||
{
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
instance->version = 0x000000FF & inb(addr);
|
||||
PDEVELOP("me8200 firmware version: %d\n", instance->version);
|
||||
|
||||
/// @note Fix for wrong values in this registry.
|
||||
if ((instance->version < 0x7) || (instance->version > 0x1F))
|
||||
instance->version = 0x0;
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
/**
|
||||
* @file me8200_di.h
|
||||
*
|
||||
* @brief ME-8200 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 _ME8200_DI_H_
|
||||
#define _ME8200_DI_H_
|
||||
|
||||
#include "mesubdevice.h"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/**
|
||||
* @brief The template subdevice class.
|
||||
*/
|
||||
typedef struct me8200_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. */
|
||||
spinlock_t *ctrl_reg_lock;
|
||||
spinlock_t *irq_ctrl_lock;
|
||||
spinlock_t *irq_mode_lock;
|
||||
|
||||
unsigned int di_idx;
|
||||
unsigned int version;
|
||||
|
||||
int irq; /**< The number of the interrupt request. */
|
||||
volatile int rised; /**< Flag to indicate if an interrupt occured. */
|
||||
uint status_flag; /**< Default interupt status flag */
|
||||
uint status_value; /**< Interupt status */
|
||||
uint status_value_edges; /**< Extended interupt status */
|
||||
uint line_value;
|
||||
int count; /**< Counts the number of interrupts occured. */
|
||||
uint8_t compare_value;
|
||||
uint8_t filtering_flag;
|
||||
|
||||
wait_queue_head_t wait_queue; /**< To wait on interrupts. */
|
||||
|
||||
unsigned long port_reg; /**< The digital input port. */
|
||||
unsigned long compare_reg; /**< The register to hold the value to compare with. */
|
||||
unsigned long mask_reg; /**< The register to hold the mask. */
|
||||
unsigned long irq_mode_reg; /**< The interrupt mode register. */
|
||||
unsigned long irq_ctrl_reg; /**< The interrupt control register. */
|
||||
unsigned long irq_status_reg; /**< The interrupt status register. Also interrupt reseting register (firmware version 7 and later).*/
|
||||
#ifdef MEDEBUG_DEBUG_REG
|
||||
unsigned long reg_base;
|
||||
#endif
|
||||
unsigned long firmware_version_reg; /**< The interrupt reseting register. */
|
||||
|
||||
unsigned long irq_status_low_reg; /**< The interrupt extended status register (low part). */
|
||||
unsigned long irq_status_high_reg; /**< The interrupt extended status register (high part). */
|
||||
} me8200_di_subdevice_t;
|
||||
|
||||
/**
|
||||
* @brief The constructor to generate a ME-8200 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.
|
||||
*/
|
||||
me8200_di_subdevice_t *me8200_di_constructor(uint32_t me8200_reg_base,
|
||||
unsigned int di_idx,
|
||||
int irq,
|
||||
spinlock_t * irq_ctrl_lock,
|
||||
spinlock_t * irq_mode_lock);
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,75 +0,0 @@
|
|||
/**
|
||||
* @file me8200_di_reg.h
|
||||
*
|
||||
* @brief ME-8200 digital 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 _ME8200_DI_REG_H_
|
||||
#define _ME8200_DI_REG_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
// Common registry for whole family.
|
||||
#define ME8200_DI_PORT_0_REG 0x3 // R
|
||||
#define ME8200_DI_PORT_1_REG 0x4 // R
|
||||
|
||||
#define ME8200_DI_MASK_0_REG 0x5 // R/W
|
||||
#define ME8200_DI_MASK_1_REG 0x6 // R/W
|
||||
|
||||
#define ME8200_DI_COMPARE_0_REG 0xA // R/W
|
||||
#define ME8200_DI_COMPARE_1_REG 0xB // R/W
|
||||
|
||||
#define ME8200_DI_IRQ_CTRL_REG 0xC // R/W
|
||||
|
||||
#ifndef ME8200_IRQ_MODE_REG
|
||||
# define ME8200_IRQ_MODE_REG 0xD // R/W
|
||||
#endif
|
||||
|
||||
// This registry are for all versions
|
||||
#define ME8200_DI_CHANGE_0_REG 0xE // R
|
||||
#define ME8200_DI_CHANGE_1_REG 0xF // R
|
||||
|
||||
#define ME8200_DI_IRQ_CTRL_BIT_CLEAR 0x4
|
||||
#define ME8200_DI_IRQ_CTRL_BIT_ENABLE 0x8
|
||||
|
||||
// This registry are for firmware versions 7 and later
|
||||
#define ME8200_DI_EXTEND_CHANGE_0_LOW_REG 0x10 // R
|
||||
#define ME8200_DI_EXTEND_CHANGE_0_HIGH_REG 0x11 // R
|
||||
#define ME8200_DI_EXTEND_CHANGE_1_LOW_REG 0x12 // R
|
||||
#define ME8200_DI_EXTEND_CHANGE_1_HIGH_REG 0x13 // R
|
||||
|
||||
#ifndef ME8200_FIRMWARE_VERSION_REG
|
||||
# define ME8200_FIRMWARE_VERSION_REG 0x14 // R
|
||||
#endif
|
||||
|
||||
// Bit definitions
|
||||
#define ME8200_DI_IRQ_CTRL_MASK_EDGE 0x3
|
||||
#define ME8200_DI_IRQ_CTRL_MASK_EDGE_RISING 0x0
|
||||
#define ME8200_DI_IRQ_CTRL_MASK_EDGE_FALLING 0x1
|
||||
#define ME8200_DI_IRQ_CTRL_MASK_EDGE_ANY 0x3
|
||||
|
||||
// Others
|
||||
#define ME8200_DI_IRQ_CTRL_SHIFT 4
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,418 +0,0 @@
|
|||
/**
|
||||
* @file me8200_dio.c
|
||||
*
|
||||
* @brief ME-8200 digital input/output 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 <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "medefines.h"
|
||||
#include "meinternal.h"
|
||||
#include "meerror.h"
|
||||
|
||||
#include "medebug.h"
|
||||
#include "me8200_dio_reg.h"
|
||||
#include "me8200_dio.h"
|
||||
|
||||
/*
|
||||
* Defines
|
||||
*/
|
||||
|
||||
/*
|
||||
* Functions
|
||||
*/
|
||||
|
||||
static int me8200_dio_io_reset_subdevice(struct me_subdevice *subdevice,
|
||||
struct file *filep, int flags)
|
||||
{
|
||||
me8200_dio_subdevice_t *instance;
|
||||
uint8_t mode;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
instance = (me8200_dio_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
mode = inb(instance->ctrl_reg);
|
||||
mode &= ~(0x3 << (instance->dio_idx * 2));
|
||||
outb(mode, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, mode);
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
outb(0x00, instance->port_reg);
|
||||
PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->port_reg - instance->reg_base, 0x00);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me8200_dio_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)
|
||||
{
|
||||
me8200_dio_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
uint32_t mode;
|
||||
uint32_t size =
|
||||
flags & (ME_IO_SINGLE_CONFIG_DIO_BIT | ME_IO_SINGLE_CONFIG_DIO_BYTE
|
||||
| ME_IO_SINGLE_CONFIG_DIO_WORD |
|
||||
ME_IO_SINGLE_CONFIG_DIO_DWORD);
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8200_dio_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
mode = inb(instance->ctrl_reg);
|
||||
switch (size) {
|
||||
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) {
|
||||
mode &=
|
||||
~((ME8200_DIO_CTRL_BIT_MODE_0 |
|
||||
ME8200_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2));
|
||||
} else if (single_config == ME_SINGLE_CONFIG_DIO_OUTPUT) {
|
||||
mode &=
|
||||
~((ME8200_DIO_CTRL_BIT_MODE_0 |
|
||||
ME8200_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2));
|
||||
mode |=
|
||||
ME8200_DIO_CTRL_BIT_MODE_0 << (instance->
|
||||
dio_idx * 2);
|
||||
} else {
|
||||
PERROR
|
||||
("Invalid port configuration specified.\n");
|
||||
err = ME_ERRNO_INVALID_SINGLE_CONFIG;
|
||||
}
|
||||
} else {
|
||||
PERROR("Invalid channel number.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
PERROR("Invalid flags.\n");
|
||||
|
||||
err = ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
outb(mode, instance->ctrl_reg);
|
||||
PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->ctrl_reg - instance->reg_base, mode);
|
||||
}
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me8200_dio_io_single_read(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int *value, int time_out, int flags)
|
||||
{
|
||||
me8200_dio_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
uint8_t mode;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8200_dio_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
switch (flags) {
|
||||
case ME_IO_SINGLE_TYPE_DIO_BIT:
|
||||
if ((channel >= 0) && (channel < 8)) {
|
||||
mode =
|
||||
inb(instance->
|
||||
ctrl_reg) & ((ME8200_DIO_CTRL_BIT_MODE_0 |
|
||||
ME8200_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2));
|
||||
|
||||
if ((mode ==
|
||||
(ME8200_DIO_CTRL_BIT_MODE_0 <<
|
||||
(instance->dio_idx * 2))) || !mode) {
|
||||
*value =
|
||||
inb(instance->
|
||||
port_reg) & (0x0001 << channel);
|
||||
} else {
|
||||
PERROR("Port not in output or input mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_CONFIG;
|
||||
}
|
||||
} 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) {
|
||||
mode =
|
||||
inb(instance->
|
||||
ctrl_reg) & ((ME8200_DIO_CTRL_BIT_MODE_0 |
|
||||
ME8200_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2));
|
||||
|
||||
if ((mode ==
|
||||
(ME8200_DIO_CTRL_BIT_MODE_0 <<
|
||||
(instance->dio_idx * 2))) || !mode) {
|
||||
*value = inb(instance->port_reg) & 0x00FF;
|
||||
} else {
|
||||
PERROR("Port not in output or input mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_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->ctrl_reg_lock);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me8200_dio_io_single_write(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int value, int time_out, int flags)
|
||||
{
|
||||
me8200_dio_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
uint8_t mode;
|
||||
uint8_t byte;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8200_dio_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
switch (flags) {
|
||||
case ME_IO_SINGLE_TYPE_DIO_BIT:
|
||||
if ((channel >= 0) && (channel < 8)) {
|
||||
mode =
|
||||
inb(instance->
|
||||
ctrl_reg) & ((ME8200_DIO_CTRL_BIT_MODE_0 |
|
||||
ME8200_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2));
|
||||
|
||||
if (mode ==
|
||||
(ME8200_DIO_CTRL_BIT_MODE_0 <<
|
||||
(instance->dio_idx * 2))) {
|
||||
byte = inb(instance->port_reg);
|
||||
|
||||
if (value)
|
||||
byte |= 0x1 << channel;
|
||||
else
|
||||
byte &= ~(0x1 << channel);
|
||||
|
||||
outb(byte, instance->port_reg);
|
||||
PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->port_reg -
|
||||
instance->reg_base, byte);
|
||||
} else {
|
||||
PERROR("Port not in output or input mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_CONFIG;
|
||||
}
|
||||
} 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) {
|
||||
mode =
|
||||
inb(instance->
|
||||
ctrl_reg) & ((ME8200_DIO_CTRL_BIT_MODE_0 |
|
||||
ME8200_DIO_CTRL_BIT_MODE_1) <<
|
||||
(instance->dio_idx * 2));
|
||||
|
||||
if (mode ==
|
||||
(ME8200_DIO_CTRL_BIT_MODE_0 <<
|
||||
(instance->dio_idx * 2))) {
|
||||
outb(value, instance->port_reg);
|
||||
PDEBUG_REG("port_reg outl(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->port_reg -
|
||||
instance->reg_base, value);
|
||||
} else {
|
||||
PERROR("Port not in output or input mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_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->ctrl_reg_lock);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me8200_dio_query_number_channels(me_subdevice_t *subdevice,
|
||||
int *number)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*number = 8;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me8200_dio_query_subdevice_type(me_subdevice_t *subdevice,
|
||||
int *type, int *subtype)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*type = ME_TYPE_DIO;
|
||||
*subtype = ME_SUBTYPE_SINGLE;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me8200_dio_query_subdevice_caps(me_subdevice_t *subdevice,
|
||||
int *caps)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*caps = ME_CAPS_DIO_DIR_BYTE;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
me8200_dio_subdevice_t *me8200_dio_constructor(uint32_t reg_base,
|
||||
unsigned int dio_idx,
|
||||
spinlock_t *ctrl_reg_lock)
|
||||
{
|
||||
me8200_dio_subdevice_t *subdevice;
|
||||
int err;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
/* Allocate memory for subdevice instance */
|
||||
subdevice = kmalloc(sizeof(me8200_dio_subdevice_t), GFP_KERNEL);
|
||||
|
||||
if (!subdevice) {
|
||||
PERROR("Cannot get memory for subdevice instance.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(subdevice, 0, sizeof(me8200_dio_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);
|
||||
|
||||
subdevice->ctrl_reg_lock = ctrl_reg_lock;
|
||||
|
||||
/* Save digital i/o index */
|
||||
subdevice->dio_idx = dio_idx;
|
||||
|
||||
/* Save the subdevice index */
|
||||
subdevice->ctrl_reg = reg_base + ME8200_DIO_CTRL_REG;
|
||||
subdevice->port_reg = reg_base + ME8200_DIO_PORT_REG + dio_idx;
|
||||
#ifdef MEDEBUG_DEBUG_REG
|
||||
subdevice->reg_base = reg_base;
|
||||
#endif
|
||||
|
||||
/* Overload base class methods. */
|
||||
subdevice->base.me_subdevice_io_reset_subdevice =
|
||||
me8200_dio_io_reset_subdevice;
|
||||
subdevice->base.me_subdevice_io_single_config =
|
||||
me8200_dio_io_single_config;
|
||||
subdevice->base.me_subdevice_io_single_read = me8200_dio_io_single_read;
|
||||
subdevice->base.me_subdevice_io_single_write =
|
||||
me8200_dio_io_single_write;
|
||||
subdevice->base.me_subdevice_query_number_channels =
|
||||
me8200_dio_query_number_channels;
|
||||
subdevice->base.me_subdevice_query_subdevice_type =
|
||||
me8200_dio_query_subdevice_type;
|
||||
subdevice->base.me_subdevice_query_subdevice_caps =
|
||||
me8200_dio_query_subdevice_caps;
|
||||
|
||||
return subdevice;
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
/**
|
||||
* @file me8200_dio.h
|
||||
*
|
||||
* @brief ME-8200 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 _ME8200_DIO_H_
|
||||
#define _ME8200_DIO_H_
|
||||
|
||||
#include "mesubdevice.h"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/**
|
||||
* @brief The template subdevice class.
|
||||
*/
|
||||
typedef struct me8200_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
|
||||
} me8200_dio_subdevice_t;
|
||||
|
||||
/**
|
||||
* @brief The constructor to generate a ME-8200 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.
|
||||
*/
|
||||
me8200_dio_subdevice_t *me8200_dio_constructor(uint32_t reg_base,
|
||||
unsigned int dio_idx,
|
||||
spinlock_t * ctrl_reg_lock);
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,43 +0,0 @@
|
|||
/**
|
||||
* @file me8200_dio_reg.h
|
||||
*
|
||||
* @brief ME-8200 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 _ME8200_DIO_REG_H_
|
||||
#define _ME8200_DIO_REG_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define ME8200_DIO_CTRL_REG 0x7 // R/W
|
||||
#define ME8200_DIO_PORT_0_REG 0x8 // R/W
|
||||
#define ME8200_DIO_PORT_1_REG 0x9 // R/W
|
||||
#define ME8200_DIO_PORT_REG ME8200_DIO_PORT_0_REG // R/W
|
||||
|
||||
#define ME8200_DIO_CTRL_BIT_MODE_0 0x01
|
||||
#define ME8200_DIO_CTRL_BIT_MODE_1 0x02
|
||||
#define ME8200_DIO_CTRL_BIT_MODE_2 0x04
|
||||
#define ME8200_DIO_CTRL_BIT_MODE_3 0x08
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,591 +0,0 @@
|
|||
/**
|
||||
* @file me8200_do.c
|
||||
*
|
||||
* @brief ME-8200 digital output 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 <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "medefines.h"
|
||||
#include "meinternal.h"
|
||||
#include "meerror.h"
|
||||
|
||||
#include "meids.h"
|
||||
#include "medebug.h"
|
||||
#include "me8200_reg.h"
|
||||
#include "me8200_do_reg.h"
|
||||
#include "me8200_do.h"
|
||||
|
||||
/*
|
||||
* Defines
|
||||
*/
|
||||
|
||||
/*
|
||||
* Functions
|
||||
*/
|
||||
|
||||
static int me8200_do_io_irq_start(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int irq_source,
|
||||
int irq_edge, int irq_arg, int flags)
|
||||
{
|
||||
me8200_do_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
uint8_t tmp;
|
||||
unsigned long status;
|
||||
|
||||
if (flags & ~ME_IO_IRQ_START_DIO_BYTE) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (channel != 0) {
|
||||
PERROR("Invalid channel specified.\n");
|
||||
return ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
|
||||
if (irq_source != ME_IRQ_SOURCE_DIO_OVER_TEMP) {
|
||||
PERROR("Invalid interrupt source specified.\n");
|
||||
return ME_ERRNO_INVALID_IRQ_SOURCE;
|
||||
}
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8200_do_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, status);
|
||||
spin_lock(instance->irq_mode_lock);
|
||||
tmp = inb(instance->irq_ctrl_reg);
|
||||
tmp |=
|
||||
ME8200_IRQ_MODE_BIT_ENABLE_POWER << (ME8200_IRQ_MODE_POWER_SHIFT *
|
||||
instance->do_idx);
|
||||
outb(tmp, instance->irq_ctrl_reg);
|
||||
PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->irq_ctrl_reg - instance->reg_base, tmp);
|
||||
spin_unlock(instance->irq_mode_lock);
|
||||
instance->rised = 0;
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, status);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me8200_do_io_irq_wait(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int *irq_count,
|
||||
int *value, int time_out, int flags)
|
||||
{
|
||||
me8200_do_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
long t = 0;
|
||||
unsigned long cpu_flags;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8200_do_subdevice_t *) subdevice;
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (time_out < 0) {
|
||||
PERROR("Invalid time_out specified.\n");
|
||||
return ME_ERRNO_INVALID_TIMEOUT;
|
||||
}
|
||||
|
||||
if (time_out) {
|
||||
t = (time_out * HZ) / 1000;
|
||||
|
||||
if (t == 0)
|
||||
t = 1;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
if (instance->rised <= 0) {
|
||||
instance->rised = 0;
|
||||
|
||||
if (time_out) {
|
||||
t = wait_event_interruptible_timeout(instance->
|
||||
wait_queue,
|
||||
(instance->rised !=
|
||||
0), t);
|
||||
|
||||
if (t == 0) {
|
||||
PERROR
|
||||
("Wait on external interrupt timed out.\n");
|
||||
err = ME_ERRNO_TIMEOUT;
|
||||
}
|
||||
} else {
|
||||
wait_event_interruptible(instance->wait_queue,
|
||||
(instance->rised != 0));
|
||||
}
|
||||
|
||||
if (instance->rised < 0) {
|
||||
PERROR("Wait on interrupt aborted by user.\n");
|
||||
err = ME_ERRNO_CANCELLED;
|
||||
}
|
||||
}
|
||||
|
||||
if (signal_pending(current)) {
|
||||
PERROR("Wait on external interrupt aborted by signal.\n");
|
||||
err = ME_ERRNO_SIGNAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
|
||||
instance->rised = 0;
|
||||
*irq_count = instance->count;
|
||||
*value = 0;
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me8200_do_io_irq_stop(me_subdevice_t *subdevice,
|
||||
struct file *filep, int channel, int flags)
|
||||
{
|
||||
me8200_do_subdevice_t *instance;
|
||||
uint8_t tmp;
|
||||
unsigned long cpu_flags;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8200_do_subdevice_t *) subdevice;
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
|
||||
spin_lock(instance->irq_mode_lock);
|
||||
tmp = inb(instance->irq_ctrl_reg);
|
||||
tmp &=
|
||||
~(ME8200_IRQ_MODE_BIT_ENABLE_POWER <<
|
||||
(ME8200_IRQ_MODE_POWER_SHIFT * instance->do_idx));
|
||||
outb(tmp, instance->irq_ctrl_reg);
|
||||
PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->irq_ctrl_reg - instance->reg_base, tmp);
|
||||
spin_unlock(instance->irq_mode_lock);
|
||||
instance->rised = -1;
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
|
||||
wake_up_interruptible_all(&instance->wait_queue);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me8200_do_io_reset_subdevice(struct me_subdevice *subdevice,
|
||||
struct file *filep, int flags)
|
||||
{
|
||||
me8200_do_subdevice_t *instance;
|
||||
unsigned long cpu_flags;
|
||||
uint8_t tmp;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8200_do_subdevice_t *) subdevice;
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
|
||||
outb(0x00, instance->port_reg);
|
||||
PDEBUG_REG("port_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->port_reg - instance->reg_base, 0x00);
|
||||
spin_lock(instance->irq_mode_lock);
|
||||
tmp = inb(instance->irq_ctrl_reg);
|
||||
tmp &=
|
||||
~(ME8200_IRQ_MODE_BIT_ENABLE_POWER <<
|
||||
(ME8200_IRQ_MODE_POWER_SHIFT * instance->do_idx));
|
||||
outb(tmp, instance->irq_ctrl_reg);
|
||||
PDEBUG_REG("irq_ctrl_reg outb(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->irq_ctrl_reg - instance->reg_base, tmp);
|
||||
spin_unlock(instance->irq_mode_lock);
|
||||
instance->rised = -1;
|
||||
instance->count = 0;
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
|
||||
wake_up_interruptible_all(&instance->wait_queue);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me8200_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)
|
||||
{
|
||||
me8200_do_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
unsigned long status;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8200_do_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, status);
|
||||
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_OUTPUT) {
|
||||
} else {
|
||||
PERROR("Invalid byte direction specified.\n");
|
||||
err = ME_ERRNO_INVALID_SINGLE_CONFIG;
|
||||
}
|
||||
} else {
|
||||
PERROR("Invalid byte specified.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
PERROR("Invalid flags specified.\n");
|
||||
err = ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
spin_unlock_irqrestore(&instance->subdevice_lock, status);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me8200_do_io_single_read(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int *value, int time_out, int flags)
|
||||
{
|
||||
me8200_do_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
unsigned long status;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8200_do_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, status);
|
||||
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_irqrestore(&instance->subdevice_lock, status);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me8200_do_io_single_write(me_subdevice_t *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int value, int time_out, int flags)
|
||||
{
|
||||
me8200_do_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
uint8_t state;
|
||||
unsigned long status;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8200_do_subdevice_t *) subdevice;
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock_irqsave(&instance->subdevice_lock, status);
|
||||
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);
|
||||
PDEBUG_REG("port_reg outb(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->port_reg - instance->reg_base,
|
||||
state);
|
||||
} 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);
|
||||
PDEBUG_REG("port_reg outb(0x%lX+0x%lX)=0x%x\n",
|
||||
instance->reg_base,
|
||||
instance->port_reg - instance->reg_base,
|
||||
value);
|
||||
} 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_irqrestore(&instance->subdevice_lock, status);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me8200_do_query_number_channels(me_subdevice_t *subdevice,
|
||||
int *number)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*number = 8;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me8200_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 me8200_do_query_subdevice_caps(me_subdevice_t *subdevice, int *caps)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*caps = ME_CAPS_DIO_OVER_TEMP_IRQ;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static void me8200_do_destructor(struct me_subdevice *subdevice)
|
||||
{
|
||||
me8200_do_subdevice_t *instance;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8200_do_subdevice_t *) subdevice;
|
||||
|
||||
free_irq(instance->irq, (void *)instance);
|
||||
me_subdevice_deinit(&instance->base);
|
||||
kfree(instance);
|
||||
}
|
||||
|
||||
static irqreturn_t me8200_do_isr(int irq, void *dev_id)
|
||||
{
|
||||
me8200_do_subdevice_t *instance;
|
||||
uint16_t ctrl;
|
||||
uint8_t irq_status;
|
||||
|
||||
instance = (me8200_do_subdevice_t *) dev_id;
|
||||
|
||||
if (irq != instance->irq) {
|
||||
PERROR("Incorrect interrupt num: %d.\n", irq);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
irq_status = inb(instance->irq_status_reg);
|
||||
if (!
|
||||
(irq_status &
|
||||
(ME8200_DO_IRQ_STATUS_BIT_ACTIVE << instance->do_idx))) {
|
||||
PINFO
|
||||
("%ld Shared interrupt. %s(): idx=%d irq_status_reg=0x%04X\n",
|
||||
jiffies, __func__, instance->do_idx, irq_status);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
instance->rised = 1;
|
||||
instance->count++;
|
||||
|
||||
spin_lock(instance->irq_mode_lock);
|
||||
ctrl = inw(instance->irq_ctrl_reg);
|
||||
ctrl |= ME8200_IRQ_MODE_BIT_CLEAR_POWER << instance->do_idx;
|
||||
outw(ctrl, instance->irq_ctrl_reg);
|
||||
PDEBUG_REG("irq_ctrl_reg outw(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->irq_ctrl_reg - instance->reg_base, ctrl);
|
||||
ctrl &= ~(ME8200_IRQ_MODE_BIT_CLEAR_POWER << instance->do_idx);
|
||||
outw(ctrl, instance->irq_ctrl_reg);
|
||||
PDEBUG_REG("irq_ctrl_reg outw(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
|
||||
instance->irq_ctrl_reg - instance->reg_base, ctrl);
|
||||
spin_unlock(instance->irq_mode_lock);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
wake_up_interruptible_all(&instance->wait_queue);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
me8200_do_subdevice_t *me8200_do_constructor(uint32_t reg_base,
|
||||
unsigned int do_idx,
|
||||
int irq,
|
||||
spinlock_t *irq_mode_lock)
|
||||
{
|
||||
me8200_do_subdevice_t *subdevice;
|
||||
int err;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
/* Allocate memory for subdevice instance */
|
||||
subdevice = kmalloc(sizeof(me8200_do_subdevice_t), GFP_KERNEL);
|
||||
|
||||
if (!subdevice) {
|
||||
PERROR("Cannot get memory for subdevice instance.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(subdevice, 0, sizeof(me8200_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);
|
||||
|
||||
subdevice->irq_mode_lock = irq_mode_lock;
|
||||
|
||||
/* Save the index of the digital output */
|
||||
subdevice->do_idx = do_idx;
|
||||
subdevice->irq = irq;
|
||||
|
||||
/* Initialize the registers */
|
||||
if (do_idx == 0) {
|
||||
subdevice->port_reg = reg_base + ME8200_DO_PORT_0_REG;
|
||||
} else if (do_idx == 1) {
|
||||
subdevice->port_reg = reg_base + ME8200_DO_PORT_1_REG;
|
||||
} else {
|
||||
PERROR("Wrong subdevice idx=%d.\n", do_idx);
|
||||
kfree(subdevice);
|
||||
return NULL;
|
||||
}
|
||||
subdevice->irq_ctrl_reg = reg_base + ME8200_IRQ_MODE_REG;
|
||||
subdevice->irq_status_reg = reg_base + ME8200_DO_IRQ_STATUS_REG;
|
||||
#ifdef MEDEBUG_DEBUG_REG
|
||||
subdevice->reg_base = reg_base;
|
||||
#endif
|
||||
|
||||
/* Initialize the wait queue */
|
||||
init_waitqueue_head(&subdevice->wait_queue);
|
||||
|
||||
/* Request the interrupt line */
|
||||
err = request_irq(irq, me8200_do_isr,
|
||||
IRQF_DISABLED | IRQF_SHARED,
|
||||
ME8200_NAME, (void *)subdevice);
|
||||
|
||||
if (err) {
|
||||
PERROR("Cannot get interrupt line.\n");
|
||||
kfree(subdevice);
|
||||
return NULL;
|
||||
}
|
||||
PINFO("Registered irq=%d.\n", irq);
|
||||
|
||||
/* Overload base class methods. */
|
||||
subdevice->base.me_subdevice_io_irq_start = me8200_do_io_irq_start;
|
||||
subdevice->base.me_subdevice_io_irq_wait = me8200_do_io_irq_wait;
|
||||
subdevice->base.me_subdevice_io_irq_stop = me8200_do_io_irq_stop;
|
||||
subdevice->base.me_subdevice_io_reset_subdevice =
|
||||
me8200_do_io_reset_subdevice;
|
||||
subdevice->base.me_subdevice_io_single_config =
|
||||
me8200_do_io_single_config;
|
||||
subdevice->base.me_subdevice_io_single_read = me8200_do_io_single_read;
|
||||
subdevice->base.me_subdevice_io_single_write =
|
||||
me8200_do_io_single_write;
|
||||
subdevice->base.me_subdevice_query_number_channels =
|
||||
me8200_do_query_number_channels;
|
||||
subdevice->base.me_subdevice_query_subdevice_type =
|
||||
me8200_do_query_subdevice_type;
|
||||
subdevice->base.me_subdevice_query_subdevice_caps =
|
||||
me8200_do_query_subdevice_caps;
|
||||
subdevice->base.me_subdevice_destructor = me8200_do_destructor;
|
||||
|
||||
subdevice->rised = 0;
|
||||
subdevice->count = 0;
|
||||
|
||||
return subdevice;
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
/**
|
||||
* @file me8200_do.h
|
||||
*
|
||||
* @brief ME-8200 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 _ME8200_DO_H_
|
||||
#define _ME8200_DO_H_
|
||||
|
||||
#include "mesubdevice.h"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/**
|
||||
* @brief The template subdevice class.
|
||||
*/
|
||||
typedef struct me8200_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. */
|
||||
spinlock_t *irq_mode_lock;
|
||||
|
||||
int irq; /**< The number of the interrupt request */
|
||||
int rised; /**< Flag to indicate if an interrupt occured */
|
||||
int count; /**< Counts the number of interrupts occured */
|
||||
wait_queue_head_t wait_queue; /**< To wait on interrupts */
|
||||
|
||||
unsigned int do_idx; /**< The number of the digital output */
|
||||
|
||||
unsigned long port_reg; /**< The digital output port */
|
||||
unsigned long irq_ctrl_reg; /**< The interrupt control register */
|
||||
unsigned long irq_status_reg; /**< The interrupt status register */
|
||||
#ifdef MEDEBUG_DEBUG_REG
|
||||
unsigned long reg_base;
|
||||
#endif
|
||||
} me8200_do_subdevice_t;
|
||||
|
||||
/**
|
||||
* @brief The constructor to generate a ME-8200 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.
|
||||
*/
|
||||
me8200_do_subdevice_t *me8200_do_constructor(uint32_t reg_base,
|
||||
unsigned int do_idx,
|
||||
int irq,
|
||||
spinlock_t * irq_mode_lock);
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,40 +0,0 @@
|
|||
/**
|
||||
* @file me8200_ao_reg.h
|
||||
*
|
||||
* @brief ME-8200 analog 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 _ME8200_DO_REG_H_
|
||||
#define _ME8200_DO_REG_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define ME8200_DO_IRQ_STATUS_REG 0x0 // R
|
||||
#define ME8200_DO_PORT_0_REG 0x1 // R/W
|
||||
#define ME8200_DO_PORT_1_REG 0x2 // R/W
|
||||
|
||||
#define ME8200_DO_IRQ_STATUS_BIT_ACTIVE 0x1
|
||||
#define ME8200_DO_IRQ_STATUS_SHIFT 1
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,46 +0,0 @@
|
|||
/**
|
||||
* @file me8200_reg.h
|
||||
*
|
||||
* @brief ME-8200 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 _ME8200_REG_H_
|
||||
#define _ME8200_REG_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define ME8200_IRQ_MODE_REG 0xD // R/W
|
||||
|
||||
#define ME8200_IRQ_MODE_MASK 0x3
|
||||
|
||||
#define ME8200_IRQ_MODE_MASK_MASK 0x0
|
||||
#define ME8200_IRQ_MODE_MASK_COMPARE 0x1
|
||||
|
||||
#define ME8200_IRQ_MODE_BIT_ENABLE_POWER 0x10
|
||||
#define ME8200_IRQ_MODE_BIT_CLEAR_POWER 0x40
|
||||
|
||||
#define ME8200_IRQ_MODE_DI_SHIFT 2
|
||||
#define ME8200_IRQ_MODE_POWER_SHIFT 1
|
||||
|
||||
#endif
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,80 +0,0 @@
|
|||
/**
|
||||
* @file me8254.h
|
||||
*
|
||||
* @brief 8254 counter 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 _ME8254_H_
|
||||
#define _ME8254_H_
|
||||
|
||||
#include "mesubdevice.h"
|
||||
#include "meslock.h"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/**
|
||||
* @brief The 8254 subdevice class.
|
||||
*/
|
||||
typedef struct me8254_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 the control register from concurrent access. */
|
||||
spinlock_t *clk_src_reg_lock; /**< Spin lock to protect the clock source register from concurrent access. */
|
||||
|
||||
uint32_t device_id; /**< The Meilhaus device type carrying the 8254 chip. */
|
||||
int me8254_idx; /**< The index of the 8254 chip on the device. */
|
||||
int ctr_idx; /**< The index of the counter on the 8254 chip. */
|
||||
|
||||
int caps; /**< Holds the device capabilities. */
|
||||
|
||||
unsigned long val_reg; /**< Holds the actual counter value. */
|
||||
unsigned long ctrl_reg; /**< Register to configure the 8254 modes. */
|
||||
unsigned long clk_src_reg; /**< Register to configure the counter connections. */
|
||||
} me8254_subdevice_t;
|
||||
|
||||
/**
|
||||
* @brief The constructor to generate a 8254 instance.
|
||||
*
|
||||
* @param device_id The kind of Meilhaus device holding the 8254.
|
||||
* @param reg_base The register base address of the device as returned by the PCI BIOS.
|
||||
* @param me8254_idx The index of the 8254 chip on the Meilhaus device.
|
||||
* @param ctr_idx The index of the counter inside a 8254 chip.
|
||||
* @param ctrl_reg_lock Pointer to spin lock protecting the 8254 control register from concurrent access.
|
||||
* @param clk_src_reg_lock Pointer to spin lock protecting the clock source register from concurrent access.
|
||||
*
|
||||
* @return Pointer to new instance on success.\n
|
||||
* NULL on error.
|
||||
*/
|
||||
me8254_subdevice_t *me8254_constructor(uint32_t device_id,
|
||||
uint32_t reg_base,
|
||||
unsigned int me8254_idx,
|
||||
unsigned int ctr_idx,
|
||||
spinlock_t * ctrl_reg_lock,
|
||||
spinlock_t * clk_src_reg_lock);
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,172 +0,0 @@
|
|||
/**
|
||||
* @file me8254_reg.h
|
||||
*
|
||||
* @brief 8254 counter register definitions.
|
||||
* @note Copyright (C) 2006 Meilhaus Electronic GmbH (support@meilhaus.de)
|
||||
* @author Guenter Gebhardt
|
||||
*/
|
||||
|
||||
#ifndef _ME8254_REG_H_
|
||||
#define _ME8254_REG_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/* ME1400 A/B register offsets */
|
||||
#define ME1400AB_8254_A_0_VAL_REG 0x0004 /**< Offset of 8254 A counter 0 value register. */
|
||||
#define ME1400AB_8254_A_1_VAL_REG 0x0005 /**< Offset of 8254 A counter 1 value register. */
|
||||
#define ME1400AB_8254_A_2_VAL_REG 0x0006 /**< Offset of 8254 A counter 2 value register. */
|
||||
#define ME1400AB_8254_A_CTRL_REG 0x0007 /**< Offset of 8254 A control register. */
|
||||
|
||||
#define ME1400AB_8254_B_0_VAL_REG 0x000C /**< Offset of 8254 B counter 0 value register. */
|
||||
#define ME1400AB_8254_B_1_VAL_REG 0x000D /**< Offset of 8254 B counter 1 value register. */
|
||||
#define ME1400AB_8254_B_2_VAL_REG 0x000E /**< Offset of 8254 B counter 2 value register. */
|
||||
#define ME1400AB_8254_B_CTRL_REG 0x000F /**< Offset of 8254 B control register. */
|
||||
|
||||
#define ME1400AB_CLK_SRC_REG 0x0010 /**< Offset of clock source register. */
|
||||
|
||||
/* ME1400 C register offsets */
|
||||
#define ME1400C_8254_A_0_VAL_REG 0x0004 /**< Offset of 8254 A counter 0 value register. */
|
||||
#define ME1400C_8254_A_1_VAL_REG 0x0005 /**< Offset of 8254 A counter 0 value register. */
|
||||
#define ME1400C_8254_A_2_VAL_REG 0x0006 /**< Offset of 8254 A counter 0 value register. */
|
||||
#define ME1400C_8254_A_CTRL_REG 0x0007 /**< Offset of 8254 A control register. */
|
||||
|
||||
#define ME1400C_8254_B_0_VAL_REG 0x000C /**< Offset of 8254 B counter 0 value register. */
|
||||
#define ME1400C_8254_B_1_VAL_REG 0x000D /**< Offset of 8254 B counter 0 value register. */
|
||||
#define ME1400C_8254_B_2_VAL_REG 0x000E /**< Offset of 8254 B counter 0 value register. */
|
||||
#define ME1400C_8254_B_CTRL_REG 0x000F /**< Offset of 8254 B control register. */
|
||||
|
||||
#define ME1400C_8254_C_0_VAL_REG 0x0010 /**< Offset of 8254 C counter 0 value register. */
|
||||
#define ME1400C_8254_C_1_VAL_REG 0x0011 /**< Offset of 8254 C counter 0 value register. */
|
||||
#define ME1400C_8254_C_2_VAL_REG 0x0012 /**< Offset of 8254 C counter 0 value register. */
|
||||
#define ME1400C_8254_C_CTRL_REG 0x0013 /**< Offset of 8254 C control register. */
|
||||
|
||||
#define ME1400C_8254_D_0_VAL_REG 0x0014 /**< Offset of 8254 D counter 0 value register. */
|
||||
#define ME1400C_8254_D_1_VAL_REG 0x0015 /**< Offset of 8254 D counter 0 value register. */
|
||||
#define ME1400C_8254_D_2_VAL_REG 0x0016 /**< Offset of 8254 D counter 0 value register. */
|
||||
#define ME1400C_8254_D_CTRL_REG 0x0017 /**< Offset of 8254 D control register. */
|
||||
|
||||
#define ME1400C_8254_E_0_VAL_REG 0x0018 /**< Offset of 8254 E counter 0 value register. */
|
||||
#define ME1400C_8254_E_1_VAL_REG 0x0019 /**< Offset of 8254 E counter 0 value register. */
|
||||
#define ME1400C_8254_E_2_VAL_REG 0x001A /**< Offset of 8254 E counter 0 value register. */
|
||||
#define ME1400C_8254_E_CTRL_REG 0x001B /**< Offset of 8254 E control register. */
|
||||
|
||||
#define ME1400C_CLK_SRC_0_REG 0x001C /**< Offset of clock source register 0. */
|
||||
#define ME1400C_CLK_SRC_1_REG 0x001D /**< Offset of clock source register 1. */
|
||||
#define ME1400C_CLK_SRC_2_REG 0x001E /**< Offset of clock source register 2. */
|
||||
|
||||
/* ME1400 D register offsets */
|
||||
#define ME1400D_8254_A_0_VAL_REG 0x0044 /**< Offset of 8254 A counter 0 value register. */
|
||||
#define ME1400D_8254_A_1_VAL_REG 0x0045 /**< Offset of 8254 A counter 0 value register. */
|
||||
#define ME1400D_8254_A_2_VAL_REG 0x0046 /**< Offset of 8254 A counter 0 value register. */
|
||||
#define ME1400D_8254_A_CTRL_REG 0x0047 /**< Offset of 8254 A control register. */
|
||||
|
||||
#define ME1400D_8254_B_0_VAL_REG 0x004C /**< Offset of 8254 B counter 0 value register. */
|
||||
#define ME1400D_8254_B_1_VAL_REG 0x004D /**< Offset of 8254 B counter 0 value register. */
|
||||
#define ME1400D_8254_B_2_VAL_REG 0x004E /**< Offset of 8254 B counter 0 value register. */
|
||||
#define ME1400D_8254_B_CTRL_REG 0x004F /**< Offset of 8254 B control register. */
|
||||
|
||||
#define ME1400D_8254_C_0_VAL_REG 0x0050 /**< Offset of 8254 C counter 0 value register. */
|
||||
#define ME1400D_8254_C_1_VAL_REG 0x0051 /**< Offset of 8254 C counter 0 value register. */
|
||||
#define ME1400D_8254_C_2_VAL_REG 0x0052 /**< Offset of 8254 C counter 0 value register. */
|
||||
#define ME1400D_8254_C_CTRL_REG 0x0053 /**< Offset of 8254 C control register. */
|
||||
|
||||
#define ME1400D_8254_D_0_VAL_REG 0x0054 /**< Offset of 8254 D counter 0 value register. */
|
||||
#define ME1400D_8254_D_1_VAL_REG 0x0055 /**< Offset of 8254 D counter 0 value register. */
|
||||
#define ME1400D_8254_D_2_VAL_REG 0x0056 /**< Offset of 8254 D counter 0 value register. */
|
||||
#define ME1400D_8254_D_CTRL_REG 0x0057 /**< Offset of 8254 D control register. */
|
||||
|
||||
#define ME1400D_8254_E_0_VAL_REG 0x0058 /**< Offset of 8254 E counter 0 value register. */
|
||||
#define ME1400D_8254_E_1_VAL_REG 0x0059 /**< Offset of 8254 E counter 0 value register. */
|
||||
#define ME1400D_8254_E_2_VAL_REG 0x005A /**< Offset of 8254 E counter 0 value register. */
|
||||
#define ME1400D_8254_E_CTRL_REG 0x005B /**< Offset of 8254 E control register. */
|
||||
|
||||
#define ME1400D_CLK_SRC_0_REG 0x005C /**< Offset of clock source register 0. */
|
||||
#define ME1400D_CLK_SRC_1_REG 0x005D /**< Offset of clock source register 1. */
|
||||
#define ME1400D_CLK_SRC_2_REG 0x005E /**< Offset of clock source register 2. */
|
||||
|
||||
/* ME4600 register offsets */
|
||||
#define ME4600_8254_0_VAL_REG 0x0000 /**< Offset of 8254 A counter 0 value register. */
|
||||
#define ME4600_8254_1_VAL_REG 0x0001 /**< Offset of 8254 A counter 0 value register. */
|
||||
#define ME4600_8254_2_VAL_REG 0x0002 /**< Offset of 8254 A counter 0 value register. */
|
||||
#define ME4600_8254_CTRL_REG 0x0003 /**< Offset of 8254 A control register. */
|
||||
|
||||
/* Command words for 8254 control register */
|
||||
#define ME8254_CTRL_SC0 0x00 /**< Counter 0 selection. */
|
||||
#define ME8254_CTRL_SC1 0x40 /**< Counter 1 selection. */
|
||||
#define ME8254_CTRL_SC2 0x80 /**< Counter 2 selection. */
|
||||
|
||||
#define ME8254_CTRL_TLO 0x00 /**< Counter latching operation. */
|
||||
#define ME8254_CTRL_LSB 0x10 /**< Only read LSB. */
|
||||
#define ME8254_CTRL_MSB 0x20 /**< Only read MSB. */
|
||||
#define ME8254_CTRL_LM 0x30 /**< First read LSB, then MSB. */
|
||||
|
||||
#define ME8254_CTRL_M0 0x00 /**< Mode 0 selection. */
|
||||
#define ME8254_CTRL_M1 0x02 /**< Mode 1 selection. */
|
||||
#define ME8254_CTRL_M2 0x04 /**< Mode 2 selection. */
|
||||
#define ME8254_CTRL_M3 0x06 /**< Mode 3 selection. */
|
||||
#define ME8254_CTRL_M4 0x08 /**< Mode 4 selection. */
|
||||
#define ME8254_CTRL_M5 0x0A /**< Mode 5 selection. */
|
||||
|
||||
#define ME8254_CTRL_BIN 0x00 /**< Binary counter. */
|
||||
#define ME8254_CTRL_BCD 0x01 /**< BCD counter. */
|
||||
|
||||
/* ME-1400 A/B clock source register bits */
|
||||
#define ME1400AB_8254_A_0_CLK_SRC_1MHZ (0 << 7) /**< 1MHz clock. */
|
||||
#define ME1400AB_8254_A_0_CLK_SRC_10MHZ (1 << 7) /**< 10MHz clock. */
|
||||
#define ME1400AB_8254_A_0_CLK_SRC_PIN (0 << 6) /**< CLK 0 to SUB-D. */
|
||||
#define ME1400AB_8254_A_0_CLK_SRC_QUARZ (1 << 6) /**< Connect CLK 0 with quarz. */
|
||||
|
||||
#define ME1400AB_8254_A_1_CLK_SRC_PIN (0 << 5) /**< CLK 1 to SUB-D. */
|
||||
#define ME1400AB_8254_A_1_CLK_SRC_PREV (1 << 5) /**< Connect OUT 0 with CLK 1. */
|
||||
|
||||
#define ME1400AB_8254_A_2_CLK_SRC_PIN (0 << 4) /**< CLK 2 to SUB-D. */
|
||||
#define ME1400AB_8254_A_2_CLK_SRC_PREV (1 << 4) /**< Connect OUT 1 with CLK 2. */
|
||||
|
||||
#define ME1400AB_8254_B_0_CLK_SRC_1MHZ (0 << 3) /**< 1MHz clock. */
|
||||
#define ME1400AB_8254_B_0_CLK_SRC_10MHZ (1 << 3) /**< 10MHz clock. */
|
||||
#define ME1400AB_8254_B_0_CLK_SRC_PIN (0 << 2) /**< CLK 0 to SUB-D. */
|
||||
#define ME1400AB_8254_B_0_CLK_SRC_QUARZ (1 << 2) /**< Connect CLK 0 with quarz. */
|
||||
|
||||
#define ME1400AB_8254_B_1_CLK_SRC_PIN (0 << 1) /**< CLK 1 to SUB-D. */
|
||||
#define ME1400AB_8254_B_1_CLK_SRC_PREV (1 << 1) /**< Connect OUT 0 with CLK 1. */
|
||||
|
||||
#define ME1400AB_8254_B_2_CLK_SRC_PIN (0 << 0) /**< CLK 2 to SUB-D. */
|
||||
#define ME1400AB_8254_B_2_CLK_SRC_PREV (1 << 0) /**< Connect OUT 1 with CLK 2. */
|
||||
|
||||
/* ME-1400 C/D clock source registers bits */
|
||||
#define ME1400CD_8254_ACE_0_CLK_SRC_MASK 0x03 /**< Masks all CLK source bits. */
|
||||
#define ME1400CD_8254_ACE_0_CLK_SRC_PIN 0x00 /**< Connect CLK to SUB-D. */
|
||||
#define ME1400CD_8254_ACE_0_CLK_SRC_1MHZ 0x01 /**< Connect CLK to 1MHz. */
|
||||
#define ME1400CD_8254_ACE_0_CLK_SRC_10MHZ 0x02 /**< Connect CLK to 10MHz. */
|
||||
#define ME1400CD_8254_ACE_0_CLK_SRC_PREV 0x03 /**< Connect CLK to previous counter output on ME-1400 D extension. */
|
||||
|
||||
#define ME1400CD_8254_ACE_1_CLK_SRC_MASK 0x04 /**< Masks all CLK source bits. */
|
||||
#define ME1400CD_8254_ACE_1_CLK_SRC_PIN 0x00 /**< Connect CLK to SUB-D. */
|
||||
#define ME1400CD_8254_ACE_1_CLK_SRC_PREV 0x04 /**< Connect CLK to previous counter output. */
|
||||
|
||||
#define ME1400CD_8254_ACE_2_CLK_SRC_MASK 0x08 /**< Masks all CLK source bits. */
|
||||
#define ME1400CD_8254_ACE_2_CLK_SRC_PIN 0x00 /**< Connect to SUB-D. */
|
||||
#define ME1400CD_8254_ACE_2_CLK_SRC_PREV 0x08 /**< Connect CLK to previous counter output. */
|
||||
|
||||
#define ME1400CD_8254_BD_0_CLK_SRC_MASK 0x30 /**< Masks all CLK source bits. */
|
||||
#define ME1400CD_8254_BD_0_CLK_SRC_PIN 0x00 /**< Connect CLK to SUB-D. */
|
||||
#define ME1400CD_8254_BD_0_CLK_SRC_1MHZ 0x10 /**< Connect CLK to 1MHz. */
|
||||
#define ME1400CD_8254_BD_0_CLK_SRC_10MHZ 0x20 /**< Connect CLK to 10MHz. */
|
||||
#define ME1400CD_8254_BD_0_CLK_SRC_PREV 0x30 /**< Connect CLK to previous counter output. */
|
||||
|
||||
#define ME1400CD_8254_BD_1_CLK_SRC_MASK 0x40 /**< Masks all CLK source bits. */
|
||||
#define ME1400CD_8254_BD_1_CLK_SRC_PIN 0x00 /**< Connect CLK to SUB-D. */
|
||||
#define ME1400CD_8254_BD_1_CLK_SRC_PREV 0x40 /**< Connect CLK to previous counter output. */
|
||||
|
||||
#define ME1400CD_8254_BD_2_CLK_SRC_MASK 0x80 /**< Masks all CLK source bits. */
|
||||
#define ME1400CD_8254_BD_2_CLK_SRC_PIN 0x00 /**< Connect CLK to SUB-D. */
|
||||
#define ME1400CD_8254_BD_2_CLK_SRC_PREV 0x80 /**< Connect CLK to previous counter output. */
|
||||
|
||||
/* ME-8100 counter registers */
|
||||
#define ME8100_COUNTER_REG_0 0x18 //(r,w)
|
||||
#define ME8100_COUNTER_REG_1 0x1A //(r,w)
|
||||
#define ME8100_COUNTER_REG_2 0x1C //(r,w)
|
||||
#define ME8100_COUNTER_CTRL_REG 0x1E //(r,w)
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,462 +0,0 @@
|
|||
/**
|
||||
* @file me8255.c
|
||||
*
|
||||
* @brief 8255 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 <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "medefines.h"
|
||||
#include "meinternal.h"
|
||||
#include "meerror.h"
|
||||
#include "medebug.h"
|
||||
|
||||
#include "me8255_reg.h"
|
||||
#include "me8255.h"
|
||||
|
||||
/*
|
||||
* Defines
|
||||
*/
|
||||
|
||||
/*
|
||||
* Functions
|
||||
*/
|
||||
|
||||
static uint8_t get_mode_from_mirror(uint32_t mirror)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
if (mirror & ME8255_PORT_0_OUTPUT) {
|
||||
if (mirror & ME8255_PORT_1_OUTPUT) {
|
||||
if (mirror & ME8255_PORT_2_OUTPUT) {
|
||||
return ME8255_MODE_OOO;
|
||||
} else {
|
||||
return ME8255_MODE_IOO;
|
||||
}
|
||||
} else {
|
||||
if (mirror & ME8255_PORT_2_OUTPUT) {
|
||||
return ME8255_MODE_OIO;
|
||||
} else {
|
||||
return ME8255_MODE_IIO;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (mirror & ME8255_PORT_1_OUTPUT) {
|
||||
if (mirror & ME8255_PORT_2_OUTPUT) {
|
||||
return ME8255_MODE_OOI;
|
||||
} else {
|
||||
return ME8255_MODE_IOI;
|
||||
}
|
||||
} else {
|
||||
if (mirror & ME8255_PORT_2_OUTPUT) {
|
||||
return ME8255_MODE_OII;
|
||||
} else {
|
||||
return ME8255_MODE_III;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int me8255_io_reset_subdevice(struct me_subdevice *subdevice,
|
||||
struct file *filep, int flags)
|
||||
{
|
||||
me8255_subdevice_t *instance;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8255_subdevice_t *) subdevice;
|
||||
|
||||
if (flags) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
*instance->ctrl_reg_mirror &=
|
||||
~(ME8255_PORT_0_OUTPUT << instance->dio_idx);
|
||||
outb(get_mode_from_mirror(*instance->ctrl_reg_mirror),
|
||||
instance->ctrl_reg);
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
|
||||
outb(0, instance->port_reg);
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me8255_io_single_config(struct me_subdevice *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int single_config,
|
||||
int ref,
|
||||
int trig_chan,
|
||||
int trig_type, int trig_edge, int flags)
|
||||
{
|
||||
me8255_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8255_subdevice_t *) subdevice;
|
||||
|
||||
if (flags & ~ME_IO_SINGLE_CONFIG_DIO_BYTE) {
|
||||
PERROR("Invalid flag specified.\n");
|
||||
return ME_ERRNO_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
if (channel) {
|
||||
PERROR("Invalid channel.\n");
|
||||
return ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
|
||||
ME_SUBDEVICE_ENTER;
|
||||
|
||||
spin_lock(&instance->subdevice_lock);
|
||||
if (single_config == ME_SINGLE_CONFIG_DIO_INPUT) {
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
*instance->ctrl_reg_mirror &=
|
||||
~(ME8255_PORT_0_OUTPUT << instance->dio_idx);
|
||||
outb(get_mode_from_mirror(*instance->ctrl_reg_mirror),
|
||||
instance->ctrl_reg);
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
} else if (single_config == ME_SINGLE_CONFIG_DIO_OUTPUT) {
|
||||
spin_lock(instance->ctrl_reg_lock);
|
||||
*instance->ctrl_reg_mirror |=
|
||||
(ME8255_PORT_0_OUTPUT << instance->dio_idx);
|
||||
outb(get_mode_from_mirror(*instance->ctrl_reg_mirror),
|
||||
instance->ctrl_reg);
|
||||
spin_unlock(instance->ctrl_reg_lock);
|
||||
} else {
|
||||
PERROR("Invalid port direction.\n");
|
||||
err = ME_ERRNO_INVALID_SINGLE_CONFIG;
|
||||
}
|
||||
spin_unlock(&instance->subdevice_lock);
|
||||
|
||||
ME_SUBDEVICE_EXIT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int me8255_io_single_read(struct me_subdevice *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int *value, int time_out, int flags)
|
||||
{
|
||||
me8255_subdevice_t *instance;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8255_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.\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.\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 me8255_io_single_write(struct me_subdevice *subdevice,
|
||||
struct file *filep,
|
||||
int channel,
|
||||
int value, int time_out, int flags)
|
||||
{
|
||||
me8255_subdevice_t *instance;
|
||||
uint8_t byte;
|
||||
int err = ME_ERRNO_SUCCESS;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
instance = (me8255_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)) {
|
||||
if (*instance->
|
||||
ctrl_reg_mirror & (ME8255_PORT_0_OUTPUT <<
|
||||
instance->dio_idx)) {
|
||||
byte = inb(instance->port_reg);
|
||||
|
||||
if (value)
|
||||
byte |= 0x1 << channel;
|
||||
else
|
||||
byte &= ~(0x1 << channel);
|
||||
|
||||
outb(byte, instance->port_reg);
|
||||
} else {
|
||||
PERROR("Port not in output mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_CONFIG;
|
||||
}
|
||||
} else {
|
||||
PERROR("Invalid bit number.\n");
|
||||
err = ME_ERRNO_INVALID_CHANNEL;
|
||||
}
|
||||
break;
|
||||
|
||||
case ME_IO_SINGLE_NO_FLAGS:
|
||||
case ME_IO_SINGLE_TYPE_DIO_BYTE:
|
||||
if (channel == 0) {
|
||||
if (*instance->
|
||||
ctrl_reg_mirror & (ME8255_PORT_0_OUTPUT <<
|
||||
instance->dio_idx)) {
|
||||
outb(value, instance->port_reg);
|
||||
} else {
|
||||
PERROR("Port not in output mode.\n");
|
||||
err = ME_ERRNO_PREVIOUS_CONFIG;
|
||||
}
|
||||
} else {
|
||||
PERROR("Invalid byte number.\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 me8255_query_number_channels(struct me_subdevice *subdevice,
|
||||
int *number)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*number = ME8255_NUMBER_CHANNELS;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me8255_query_subdevice_type(struct me_subdevice *subdevice,
|
||||
int *type, int *subtype)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*type = ME_TYPE_DIO;
|
||||
*subtype = ME_SUBTYPE_SINGLE;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static int me8255_query_subdevice_caps(struct me_subdevice *subdevice,
|
||||
int *caps)
|
||||
{
|
||||
PDEBUG("executed.\n");
|
||||
*caps = ME_CAPS_DIO_DIR_BYTE;
|
||||
return ME_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
me8255_subdevice_t *me8255_constructor(uint32_t device_id,
|
||||
uint32_t reg_base,
|
||||
unsigned int me8255_idx,
|
||||
unsigned int dio_idx,
|
||||
int *ctrl_reg_mirror,
|
||||
spinlock_t *ctrl_reg_lock)
|
||||
{
|
||||
me8255_subdevice_t *subdevice;
|
||||
int err;
|
||||
|
||||
PDEBUG("executed.\n");
|
||||
|
||||
/* Allocate memory for subdevice instance */
|
||||
subdevice = kmalloc(sizeof(me8255_subdevice_t), GFP_KERNEL);
|
||||
|
||||
if (!subdevice) {
|
||||
PERROR("Cannot get memory for 8255 instance.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(subdevice, 0, sizeof(me8255_subdevice_t));
|
||||
|
||||
/* Check if counter index is out of range */
|
||||
|
||||
if (dio_idx > 2) {
|
||||
PERROR("DIO index is out of range.\n");
|
||||
kfree(subdevice);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
subdevice->ctrl_reg_lock = ctrl_reg_lock;
|
||||
|
||||
/* Save the pointer to global port settings */
|
||||
subdevice->ctrl_reg_mirror = ctrl_reg_mirror;
|
||||
|
||||
/* Save type of Meilhaus device */
|
||||
subdevice->device_id = device_id;
|
||||
|
||||
/* Save the indices */
|
||||
subdevice->me8255_idx = me8255_idx;
|
||||
subdevice->dio_idx = dio_idx;
|
||||
|
||||
/* Do device specific initialization */
|
||||
switch (device_id) {
|
||||
case PCI_DEVICE_ID_MEILHAUS_ME1400:
|
||||
case PCI_DEVICE_ID_MEILHAUS_ME14E0:
|
||||
|
||||
case PCI_DEVICE_ID_MEILHAUS_ME140A:
|
||||
case PCI_DEVICE_ID_MEILHAUS_ME14EA:
|
||||
/* Check if 8255 index is out of range */
|
||||
if (me8255_idx > 0) {
|
||||
PERROR("8255 index is out of range.\n");
|
||||
me_subdevice_deinit(&subdevice->base);
|
||||
kfree(subdevice);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
case PCI_DEVICE_ID_MEILHAUS_ME140B: /* Fall through */
|
||||
case PCI_DEVICE_ID_MEILHAUS_ME14EB:
|
||||
/* Check if 8255 index is out of range */
|
||||
if (me8255_idx > 1) {
|
||||
PERROR("8255 index is out of range.\n");
|
||||
me_subdevice_deinit(&subdevice->base);
|
||||
kfree(subdevice);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get the registers */
|
||||
if (me8255_idx == 0) {
|
||||
subdevice->ctrl_reg = reg_base + ME1400AB_PORT_A_CTRL;
|
||||
subdevice->port_reg =
|
||||
reg_base + ME1400AB_PORT_A_0 + dio_idx;
|
||||
} else if (me8255_idx == 1) {
|
||||
subdevice->ctrl_reg = reg_base + ME1400AB_PORT_B_CTRL;
|
||||
subdevice->port_reg =
|
||||
reg_base + ME1400AB_PORT_B_0 + dio_idx;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PCI_DEVICE_ID_MEILHAUS_ME140C:
|
||||
/* Check if 8255 index is out of range */
|
||||
if (me8255_idx > 0) {
|
||||
PERROR("8255 index is out of range.\n");
|
||||
me_subdevice_deinit(&subdevice->base);
|
||||
kfree(subdevice);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
case PCI_DEVICE_ID_MEILHAUS_ME140D: /* Fall through */
|
||||
/* Check if 8255 index is out of range */
|
||||
if (me8255_idx > 1) {
|
||||
PERROR("8255 index is out of range.\n");
|
||||
me_subdevice_deinit(&subdevice->base);
|
||||
kfree(subdevice);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get the registers */
|
||||
if (me8255_idx == 0) {
|
||||
subdevice->ctrl_reg = reg_base + ME1400CD_PORT_A_CTRL;
|
||||
subdevice->port_reg =
|
||||
reg_base + ME1400CD_PORT_A_0 + dio_idx;
|
||||
} else if (me8255_idx == 1) {
|
||||
subdevice->ctrl_reg = reg_base + ME1400CD_PORT_B_CTRL;
|
||||
subdevice->port_reg =
|
||||
reg_base + ME1400CD_PORT_B_0 + dio_idx;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
PERROR("Unknown device type. dev ID: 0x%04x\n", device_id);
|
||||
|
||||
me_subdevice_deinit(&subdevice->base);
|
||||
|
||||
kfree(subdevice);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Overload subdevice base class methods. */
|
||||
subdevice->base.me_subdevice_io_reset_subdevice =
|
||||
me8255_io_reset_subdevice;
|
||||
subdevice->base.me_subdevice_io_single_config = me8255_io_single_config;
|
||||
subdevice->base.me_subdevice_io_single_read = me8255_io_single_read;
|
||||
subdevice->base.me_subdevice_io_single_write = me8255_io_single_write;
|
||||
subdevice->base.me_subdevice_query_number_channels =
|
||||
me8255_query_number_channels;
|
||||
subdevice->base.me_subdevice_query_subdevice_type =
|
||||
me8255_query_subdevice_type;
|
||||
subdevice->base.me_subdevice_query_subdevice_caps =
|
||||
me8255_query_subdevice_caps;
|
||||
|
||||
return subdevice;
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
/**
|
||||
* @file me8255.h
|
||||
*
|
||||
* @brief Meilhaus PIO 8255 implementation.
|
||||
* @note Copyright (C) 2006 Meilhaus Electronic GmbH (support@meilhaus.de)
|
||||
* @author Guenter Gebhardt
|
||||
*/
|
||||
|
||||
#ifndef _ME8255_H_
|
||||
#define _ME8255_H_
|
||||
|
||||
#include "mesubdevice.h"
|
||||
#include "meslock.h"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/**
|
||||
* @brief The 8255 subdevice class.
|
||||
*/
|
||||
typedef struct me8255_subdevice {
|
||||
/* Inheritance */
|
||||
me_subdevice_t base; /**< The subdevice base class. */
|
||||
|
||||
/* Attributes */
|
||||
spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */
|
||||
|
||||
int *ctrl_reg_mirror; /**< Pointer to mirror of the control register. */
|
||||
spinlock_t *ctrl_reg_lock; /**< Spin lock to protect #ctrl_reg and #ctrl_reg_mirror from concurrent access. */
|
||||
|
||||
uint32_t device_id; /**< The PCI device id of the device holding the 8255 chip. */
|
||||
int me8255_idx; /**< The index of the 8255 chip on the device. */
|
||||
int dio_idx; /**< The index of the DIO port on the 8255 chip. */
|
||||
|
||||
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 8255 modes. */
|
||||
} me8255_subdevice_t;
|
||||
|
||||
/**
|
||||
* @brief The constructor to generate a 8255 instance.
|
||||
*
|
||||
* @param device_id The kind of Meilhaus device holding the 8255.
|
||||
* @param reg_base The register base address of the device as returned by the PCI BIOS.
|
||||
* @param me8255_idx The index of the 8255 chip on the Meilhaus device.
|
||||
* @param dio_idx The index of the counter inside a 8255 chip.
|
||||
* @param ctr_reg_mirror Pointer to mirror of control register.
|
||||
* @param ctrl_reg_lock Pointer to spin lock protecting the 8255 control register and #ctrl_reg_mirror from concurrent access.
|
||||
*
|
||||
* @return Pointer to new instance on success.\n
|
||||
* NULL on error.
|
||||
*/
|
||||
me8255_subdevice_t *me8255_constructor(uint32_t device_id,
|
||||
uint32_t reg_base,
|
||||
unsigned int me8255_idx,
|
||||
unsigned int dio_idx,
|
||||
int *ctrl_reg_mirror,
|
||||
spinlock_t * ctrl_reg_lock);
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,50 +0,0 @@
|
|||
/**
|
||||
* @file me8255_reg.h
|
||||
*
|
||||
* @brief 8255 counter register definitions.
|
||||
* @note Copyright (C) 2006 Meilhaus Electronic GmbH (support@meilhaus.de)
|
||||
* @author Guenter Gebhardt
|
||||
*/
|
||||
|
||||
#ifndef _ME8255_REG_H_
|
||||
#define _ME8255_REG_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define ME8255_NUMBER_CHANNELS 8 /**< The number of channels per 8255 port. */
|
||||
|
||||
#define ME1400AB_PORT_A_0 0x0000 /**< Port 0 offset. */
|
||||
#define ME1400AB_PORT_A_1 0x0001 /**< Port 1 offset. */
|
||||
#define ME1400AB_PORT_A_2 0x0002 /**< Port 2 offset. */
|
||||
#define ME1400AB_PORT_A_CTRL 0x0003 /**< Control register for 8255 A. */
|
||||
|
||||
#define ME1400AB_PORT_B_0 0x0008 /**< Port 0 offset. */
|
||||
#define ME1400AB_PORT_B_1 0x0009 /**< Port 1 offset. */
|
||||
#define ME1400AB_PORT_B_2 0x000A /**< Port 2 offset. */
|
||||
#define ME1400AB_PORT_B_CTRL 0x000B /**< Control register for 8255 B. */
|
||||
|
||||
#define ME1400CD_PORT_A_0 0x0000 /**< Port 0 offset. */
|
||||
#define ME1400CD_PORT_A_1 0x0001 /**< Port 1 offset. */
|
||||
#define ME1400CD_PORT_A_2 0x0002 /**< Port 2 offset. */
|
||||
#define ME1400CD_PORT_A_CTRL 0x0003 /**< Control register for 8255 A. */
|
||||
|
||||
#define ME1400CD_PORT_B_0 0x0040 /**< Port 0 offset. */
|
||||
#define ME1400CD_PORT_B_1 0x0041 /**< Port 1 offset. */
|
||||
#define ME1400CD_PORT_B_2 0x0042 /**< Port 2 offset. */
|
||||
#define ME1400CD_PORT_B_CTRL 0x0043 /**< Control register for 8255 B. */
|
||||
|
||||
#define ME8255_MODE_OOO 0x80 /**< Port 2 = Output, Port 1 = Output, Port 0 = Output */
|
||||
#define ME8255_MODE_IOO 0x89 /**< Port 2 = Input, Port 1 = Output, Port 0 = Output */
|
||||
#define ME8255_MODE_OIO 0x82 /**< Port 2 = Output, Port 1 = Input, Port 0 = Output */
|
||||
#define ME8255_MODE_IIO 0x8B /**< Port 2 = Input, Port 1 = Input, Port 0 = Output */
|
||||
#define ME8255_MODE_OOI 0x90 /**< Port 2 = Output, Port 1 = Output, Port 0 = Input */
|
||||
#define ME8255_MODE_IOI 0x99 /**< Port 2 = Input, Port 1 = Output, Port 0 = Input */
|
||||
#define ME8255_MODE_OII 0x92 /**< Port 2 = Output, Port 1 = Input, Port 0 = Input */
|
||||
#define ME8255_MODE_III 0x9B /**< Port 2 = Input, Port 1 = Input, Port 0 = Input */
|
||||
|
||||
#define ME8255_PORT_0_OUTPUT 0x1 /**< If set in mirror then port 0 is in output mode. */
|
||||
#define ME8255_PORT_1_OUTPUT 0x2 /**< If set in mirror then port 1 is in output mode. */
|
||||
#define ME8255_PORT_2_OUTPUT 0x4 /**< If set in mirror then port 2 is in output mode. */
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,131 +0,0 @@
|
|||
/**
|
||||
* @file mecirc_buf.h
|
||||
*
|
||||
* @brief Meilhaus circular buffer 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 _MECIRC_BUF_H_
|
||||
#define _MECIRC_BUF_H_
|
||||
|
||||
# ifdef __KERNEL__
|
||||
|
||||
# ifdef BOSCH
|
||||
|
||||
typedef struct me_circ_buf {
|
||||
unsigned int mask;
|
||||
// unsigned int count;
|
||||
uint32_t *buf;
|
||||
int volatile head;
|
||||
int volatile tail;
|
||||
} me_circ_buf_t;
|
||||
|
||||
static inline int me_circ_buf_values(me_circ_buf_t * buf)
|
||||
{
|
||||
// return ((buf->head - buf->tail) & (buf->count - 1));
|
||||
return ((buf->head - buf->tail) & (buf->mask));
|
||||
}
|
||||
|
||||
static inline int me_circ_buf_space(me_circ_buf_t * buf)
|
||||
{
|
||||
// return ((buf->tail - (buf->head + 1)) & (buf->count - 1));
|
||||
return ((buf->tail - (buf->head + 1)) & (buf->mask));
|
||||
}
|
||||
|
||||
static inline int me_circ_buf_values_to_end(me_circ_buf_t * buf)
|
||||
{
|
||||
int end;
|
||||
int n;
|
||||
// end = buf->count - buf->tail;
|
||||
// n = (buf->head + end) & (buf->count - 1);
|
||||
end = buf->mask + 1 - buf->tail;
|
||||
n = (buf->head + end) & (buf->mask);
|
||||
return (n < end) ? n : end;
|
||||
}
|
||||
|
||||
static inline int me_circ_buf_space_to_end(me_circ_buf_t * buf)
|
||||
{
|
||||
int end;
|
||||
int n;
|
||||
|
||||
// end = buf->count - 1 - buf->head;
|
||||
// n = (end + buf->tail) & (buf->count - 1);
|
||||
end = buf->mask - buf->head;
|
||||
n = (end + buf->tail) & (buf->mask);
|
||||
return (n <= end) ? n : (end + 1);
|
||||
}
|
||||
|
||||
#define _CBUFF_32b_t
|
||||
|
||||
# else //~BOSCH
|
||||
/// @note buf->mask = buf->count-1 = ME4600_AI_CIRC_BUF_COUNT-1
|
||||
|
||||
# ifdef _CBUFF_32b_t
|
||||
//32 bit
|
||||
typedef struct me_circ_buf_32b {
|
||||
int volatile head;
|
||||
int volatile tail;
|
||||
unsigned int mask; //buffor size-1 must be 2^n-1 to work
|
||||
uint32_t *buf;
|
||||
} me_circ_buf_t;
|
||||
# else
|
||||
//16 bit
|
||||
typedef struct me_circ_buf_16b {
|
||||
int volatile head;
|
||||
int volatile tail;
|
||||
unsigned int mask; //buffor size-1 must be 2^n-1 to work
|
||||
uint16_t *buf;
|
||||
} me_circ_buf_t;
|
||||
# endif //_CBUFF_32b_t
|
||||
|
||||
/** How many values is in buffer */
|
||||
static inline int me_circ_buf_values(me_circ_buf_t * buf)
|
||||
{
|
||||
return ((buf->head - buf->tail) & (buf->mask));
|
||||
}
|
||||
|
||||
/** How many space left */
|
||||
static inline int me_circ_buf_space(me_circ_buf_t * buf)
|
||||
{
|
||||
return ((buf->tail - (buf->head + 1)) & (buf->mask));
|
||||
}
|
||||
|
||||
/** How many values can be read from buffor in one chunck. */
|
||||
static inline int me_circ_buf_values_to_end(me_circ_buf_t * buf)
|
||||
{
|
||||
return (buf->tail <=
|
||||
buf->head) ? (buf->head - buf->tail) : (buf->mask - buf->tail +
|
||||
1);
|
||||
}
|
||||
|
||||
/** How many values can be write to buffer in one chunck. */
|
||||
static inline int me_circ_buf_space_to_end(me_circ_buf_t * buf)
|
||||
{
|
||||
return (buf->tail <=
|
||||
buf->head) ? (buf->mask - buf->head + 1) : (buf->tail -
|
||||
buf->head - 1);
|
||||
}
|
||||
|
||||
# endif //BOSCH
|
||||
# endif //__KERNEL__
|
||||
#endif //_MECIRC_BUF_H_
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue