提交 a8fcffbd 编写于 作者: G Greg Kroah-Hartman

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: NGreg Kroah-Hartman <gregkh@suse.de>
上级 06bf27dd
......@@ -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/
......
#
# 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
#
# Makefile for Meilhaus linux driver system
#
obj-$(CONFIG_MEILHAUS) += memain.o
obj-$(CONFIG_ME1600) += me1600.o
obj-$(CONFIG_ME1000) += me1000.o
obj-$(CONFIG_ME1400) += me1400.o
obj-$(CONFIG_ME4600) += me4600.o
obj-$(CONFIG_ME6000) += me6000.o
obj-$(CONFIG_ME0600) += me0600.o
obj-$(CONFIG_ME8100) += me8100.o
obj-$(CONFIG_ME8200) += me8200.o
obj-$(CONFIG_ME0900) += me0900.o
obj-$(CONFIG_MEDUMMY) += medummy.o
me1600-objs := medevice.o medlist.o medlock.o me1600_device.o
me1600-objs += mesubdevice.o meslist.o meslock.o me1600_ao.o
me1000-objs := medevice.o medlist.o medlock.o me1000_device.o
me1000-objs += mesubdevice.o meslist.o meslock.o me1000_dio.o
me1400-objs := medevice.o medlist.o medlock.o me1400_device.o
me1400-objs += mesubdevice.o meslist.o meslock.o me8254.o me8255.o me1400_ext_irq.o
me4600-objs := medevice.o medlist.o medlock.o mefirmware.o me4600_device.o
me4600-objs += mesubdevice.o meslist.o meslock.o me4600_do.o me4600_di.o me4600_dio.o me8254.o me4600_ai.o me4600_ao.o me4600_ext_irq.o
me6000-objs := medevice.o medlist.o medlock.o mefirmware.o me6000_device.o
me6000-objs += mesubdevice.o meslist.o meslock.o me6000_dio.o me6000_ao.o
me0600-objs := medevice.o medlist.o medlock.o me0600_device.o
me0600-objs += mesubdevice.o meslist.o meslock.o me0600_relay.o me0600_ttli.o me0600_optoi.o me0600_dio.o me0600_ext_irq.o
me8100-objs := medevice.o medlist.o medlock.o me8100_device.o
me8100-objs += mesubdevice.o meslist.o meslock.o me8100_di.o me8100_do.o me8254.o
me8200-objs := medevice.o medlist.o medlock.o me8200_device.o
me8200-objs += mesubdevice.o meslist.o meslock.o me8200_di.o me8200_do.o me8200_dio.o
me0900-objs := medevice.o medlist.o medlock.o me0900_device.o
me0900-objs += mesubdevice.o meslist.o meslock.o me0900_do.o me0900_di.o
TODO:
- checkpatch.pl cleanups
- sparse issues
- Lindent
- audit userspace interface
- handle firmware properly
- possible comedi merge
Please send cleanup patches to Greg Kroah-Hartman <greg@kroah.com>
and CC: David Kiliani <mail@davidkiliani.de> and Meilhaus Support <support@meilhaus.de>
/**
* @file me0600_device.c
*
* @brief ME-630 device class implementation.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
* @author Krzysztof Gantzke (k.gantzke@meilhaus.de)
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif
#ifndef MODULE
# define MODULE
#endif
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include "meids.h"
#include "meerror.h"
#include "mecommon.h"
#include "meinternal.h"
#include "medebug.h"
#include "medevice.h"
#include "me0600_device.h"
#include "mesubdevice.h"
#include "me0600_relay.h"
#include "me0600_ttli.h"
#include "me0600_optoi.h"
#include "me0600_dio.h"
#include "me0600_ext_irq.h"
me_device_t *me0600_pci_constructor(struct pci_dev *pci_device)
{
me0600_device_t *me0600_device;
me_subdevice_t *subdevice;
unsigned int version_idx;
int err;
int i;
PDEBUG("executed.\n");
// Allocate structure for device instance.
me0600_device = kmalloc(sizeof(me0600_device_t), GFP_KERNEL);
if (!me0600_device) {
PERROR("Cannot get memory for device instance.\n");
return NULL;
}
memset(me0600_device, 0, sizeof(me0600_device_t));
// Initialize base class structure.
err = me_device_pci_init((me_device_t *) me0600_device, pci_device);
if (err) {
kfree(me0600_device);
PERROR("Cannot initialize device base class.\n");
return NULL;
}
/* Get the index in the device version information table. */
version_idx =
me0600_versions_get_device_index(me0600_device->base.info.pci.
device_id);
// Initialize spin lock .
spin_lock_init(&me0600_device->dio_ctrl_reg_lock);
spin_lock_init(&me0600_device->intcsr_lock);
// Create subdevice instances.
for (i = 0; i < me0600_versions[version_idx].optoi_subdevices; i++) {
subdevice =
(me_subdevice_t *) me0600_optoi_constructor(me0600_device->
base.info.pci.
reg_bases[2]);
if (!subdevice) {
me_device_deinit((me_device_t *) me0600_device);
kfree(me0600_device);
PERROR("Cannot get memory for subdevice.\n");
return NULL;
}
me_slist_add_subdevice_tail(&me0600_device->base.slist,
subdevice);
}
for (i = 0; i < me0600_versions[version_idx].relay_subdevices; i++) {
subdevice =
(me_subdevice_t *) me0600_relay_constructor(me0600_device->
base.info.pci.
reg_bases[2]);
if (!subdevice) {
me_device_deinit((me_device_t *) me0600_device);
kfree(me0600_device);
PERROR("Cannot get memory for subdevice.\n");
return NULL;
}
me_slist_add_subdevice_tail(&me0600_device->base.slist,
subdevice);
}
for (i = 0; i < me0600_versions[version_idx].ttli_subdevices; i++) {
subdevice =
(me_subdevice_t *) me0600_ttli_constructor(me0600_device->
base.info.pci.
reg_bases[2]);
if (!subdevice) {
me_device_deinit((me_device_t *) me0600_device);
kfree(me0600_device);
PERROR("Cannot get memory for subdevice.\n");
return NULL;
}
me_slist_add_subdevice_tail(&me0600_device->base.slist,
subdevice);
}
for (i = 0; i < me0600_versions[version_idx].dio_subdevices; i++) {
subdevice =
(me_subdevice_t *) me0600_dio_constructor(me0600_device->
base.info.pci.
reg_bases[2], i,
&me0600_device->
dio_ctrl_reg_lock);
if (!subdevice) {
me_device_deinit((me_device_t *) me0600_device);
kfree(me0600_device);
PERROR("Cannot get memory for subdevice.\n");
return NULL;
}
me_slist_add_subdevice_tail(&me0600_device->base.slist,
subdevice);
}
for (i = 0; i < me0600_versions[version_idx].ext_irq_subdevices; i++) {
subdevice =
(me_subdevice_t *)
me0600_ext_irq_constructor(me0600_device->base.info.pci.
reg_bases[1],
me0600_device->base.info.pci.
reg_bases[2],
&me0600_device->intcsr_lock, i,
me0600_device->base.irq);
if (!subdevice) {
me_device_deinit((me_device_t *) me0600_device);
kfree(me0600_device);
PERROR("Cannot get memory for subdevice.\n");
return NULL;
}
me_slist_add_subdevice_tail(&me0600_device->base.slist,
subdevice);
}
return (me_device_t *) me0600_device;
}
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");
/**
* @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
/**
* @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;
}
/**
* @file me0600_dio.h
*
* @brief ME-630 digital input/output subdevice class.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0600_DIO_H_
#define _ME0600_DIO_H_
#include "mesubdevice.h"
#ifdef __KERNEL__
/**
* @brief The template subdevice class.
*/
typedef struct me0600_dio_subdevice {
/* Inheritance */
me_subdevice_t base; /**< The subdevice base class. */
/* Attributes */
spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */
spinlock_t *ctrl_reg_lock; /**< Spin lock to protect #ctrl_reg from concurrent access. */
unsigned int dio_idx; /**< The index of the digital i/o on the device. */
unsigned long port_reg; /**< Register holding the port status. */
unsigned long ctrl_reg; /**< Register to configure the port direction. */
#ifdef MEDEBUG_DEBUG_REG
unsigned long reg_base;
#endif
} me0600_dio_subdevice_t;
/**
* @brief The constructor to generate a ME-630 digital input/ouput subdevice instance.
*
* @param reg_base The register base address of the device as returned by the PCI BIOS.
* @param dio_idx The index of the digital i/o port on the device.
* @param ctrl_reg_lock Spin lock protecting the control register.
*
* @return Pointer to new instance on success.\n
* NULL on error.
*/
me0600_dio_subdevice_t *me0600_dio_constructor(uint32_t reg_base,
unsigned int dio_idx,
spinlock_t * ctrl_reg_lock);
#endif
#endif
/**
* @file me0600_dio_reg.h
*
* @brief ME-630 digital input/output subdevice register definitions.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0600_DIO_REG_H_
#define _ME0600_DIO_REG_H_
#ifdef __KERNEL__
#define ME0600_DIO_CONFIG_REG 0x0007
#define ME0600_DIO_PORT_0_REG 0x0008
#define ME0600_DIO_PORT_1_REG 0x0009
#define ME0600_DIO_PORT_REG ME0600_DIO_PORT_0_REG
#define ME0600_DIO_CONFIG_BIT_OUT_0 0x0001
#define ME0600_DIO_CONFIG_BIT_OUT_1 0x0004
#endif
#endif
/**
* @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;
}
/**
* @file me0600_ext_irq.h
*
* @brief ME-630 external interrupt implementation.
* @note Copyright (C) 2006 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
#ifndef _ME0600_EXT_IRQ_H_
#define _ME0600_EXT_IRQ_H_
#include <linux/sched.h>
#include "mesubdevice.h"
#include "meslock.h"
#ifdef __KERNEL__
/**
* @brief The ME-630 external interrupt subdevice class.
*/
typedef struct me0600_ext_irq_subdevice {
/* Inheritance */
me_subdevice_t base; /**< The subdevice base class. */
/* Attributes */
spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */
spinlock_t *intcsr_lock; /**< Spin lock to protect #intcsr. */
wait_queue_head_t wait_queue; /**< Queue to put on threads waiting for an interrupt. */
int irq; /**< The irq number assigned by PCI BIOS. */
int rised; /**< If true an interrupt has occured. */
unsigned int n; /**< The number of interrupt since the driver was loaded. */
unsigned int lintno; /**< The number of the local PCI interrupt. */
uint32_t intcsr; /**< The PLX interrupt control and status register. */
uint32_t reset_reg; /**< The control register. */
} me0600_ext_irq_subdevice_t;
/**
* @brief The constructor to generate a ME-630 external interrupt instance.
*
* @param plx_reg_base The register base address of the PLX chip as returned by the PCI BIOS.
* @param me0600_reg_base The register base address of the ME-630 device as returned by the PCI BIOS.
* @param irq The irq assigned by the PCI BIOS.
*
* @return Pointer to new instance on success.\n
* NULL on error.
*/
me0600_ext_irq_subdevice_t *me0600_ext_irq_constructor(uint32_t plx_reg_base,
uint32_t me0600_reg_base,
spinlock_t * intcsr_lock,
unsigned int ext_irq_idx,
int irq);
#endif
#endif
/**
* @file me0600_ext_irq_reg.h
*
* @brief ME-630 external interrupt register definitions.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
#ifndef _ME0600_EXT_IRQ_REG_H_
#define _ME0600_EXT_IRQ_REG_H_
#ifdef __KERNEL__
#define ME0600_INT_0_RESET_REG 0x0005
#define ME0600_INT_1_RESET_REG 0x0006
#endif
#endif
/**
* @file me0600_optoi.c
*
* @brief ME-630 Optoisolated input subdevice instance.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
* @author Krzysztof Gantzke (k.gantzke@meilhaus.de)
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif
/*
* Includes
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <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;
}
/**
* @file me0600_optoi.h
*
* @brief ME-630 Optoisolated input subdevice class.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0600_OPTOI_H_
#define _ME0600_OPTOI_H_
#include "mesubdevice.h"
#ifdef __KERNEL__
/**
* @brief The template subdevice class.
*/
typedef struct me0600_optoi_subdevice {
/* Inheritance */
me_subdevice_t base; /**< The subdevice base class. */
/* Attributes */
spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */
uint32_t port_reg; /**< Register holding the port status. */
} me0600_optoi_subdevice_t;
/**
* @brief The constructor to generate a ME-630 Optoisolated input subdevice instance.
*
* @param reg_base The register base address of the device as returned by the PCI BIOS.
*
* @return Pointer to new instance on success.\n
* NULL on error.
*/
me0600_optoi_subdevice_t *me0600_optoi_constructor(uint32_t reg_base);
#endif
#endif
/**
* @file me0600_optoi_reg.h
*
* @brief ME-630 Optoisolated input subdevice register definitions.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0600_OPTOI_REG_H_
#define _ME0600_OPTOI_REG_H_
#ifdef __KERNEL__
#define ME0600_OPTO_INPUT_REG 0x0004
#endif
#endif
/**
* @file me0600_relay.c
*
* @brief ME-630 relay subdevice instance.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
* @author Krzysztof Gantzke (k.gantzke@meilhaus.de)
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif
/*
* Includes
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <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;
}
/**
* @file me0600_relay.h
*
* @brief ME-630 relay subdevice class.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0600_RELAY_H_
#define _ME0600_RELAY_H_
#include "mesubdevice.h"
#ifdef __KERNEL__
/**
* @brief The template subdevice class.
*/
typedef struct me0600_relay_subdevice {
/* Inheritance */
me_subdevice_t base; /**< The subdevice base class. */
/* Attributes */
spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */
unsigned long port_0_reg; /**< Register holding the port status. */
unsigned long port_1_reg; /**< Register holding the port status. */
#ifdef MEDEBUG_DEBUG_REG
unsigned long reg_base;
#endif
} me0600_relay_subdevice_t;
/**
* @brief The constructor to generate a ME-630 relay subdevice instance.
*
* @param reg_base The register base address of the device as returned by the PCI BIOS.
* @param ctrl_reg_lock Spin lock protecting the control register.
*
* @return Pointer to new instance on success.\n
* NULL on error.
*/
me0600_relay_subdevice_t *me0600_relay_constructor(uint32_t reg_base);
#endif
#endif
/**
* @file me0600_relay_reg.h
*
* @brief ME-630 relay subdevice register definitions.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0600_RELAY_REG_H_
#define _ME0600_RELAY_REG_H_
#ifdef __KERNEL__
#define ME0600_RELAIS_0_REG 0x0001
#define ME0600_RELAIS_1_REG 0x0002
#endif
#endif
/**
* @file me0600_ttli.c
*
* @brief ME-630 TTL input subdevice instance.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
* @author Krzysztof Gantzke (k.gantzke@meilhaus.de)
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif
/*
* Includes
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <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;
}
/**
* @file me0600_ttli.h
*
* @brief ME-630 TTL input subdevice class.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0600_TTLI_H_
#define _ME0600_TTLI_H_
#include "mesubdevice.h"
#ifdef __KERNEL__
/**
* @brief The template subdevice class.
*/
typedef struct me0600_ttli_subdevice {
/* Inheritance */
me_subdevice_t base; /**< The subdevice base class. */
/* Attributes */
spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */
uint32_t port_reg; /**< Register holding the port status. */
} me0600_ttli_subdevice_t;
/**
* @brief The constructor to generate a ME-630 TTL input subdevice instance.
*
* @param reg_base The register base address of the device as returned by the PCI BIOS.
*
* @return Pointer to new instance on success.\n
* NULL on error.
*/
me0600_ttli_subdevice_t *me0600_ttli_constructor(uint32_t reg_base);
#endif
#endif
/**
* @file me0600_ttli_reg.h
*
* @brief ME-630 TTL input subdevice register definitions.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0600_TTLI_REG_H_
#define _ME0600_TTLI_REG_H_
#ifdef __KERNEL__
#define ME0600_TTL_INPUT_REG 0x0003
#endif
#endif
/**
* @file me0900_device.c
*
* @brief ME-9x device class implementation.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
* @author Krzysztof Gantzke (k.gantzke@meilhaus.de)
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif
#ifndef MODULE
# define MODULE
#endif
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include "meids.h"
#include "meerror.h"
#include "mecommon.h"
#include "meinternal.h"
#include "medebug.h"
#include "medevice.h"
#include "me0900_device.h"
#include "me0900_reg.h"
#include "mesubdevice.h"
#include "me0900_do.h"
#include "me0900_di.h"
me_device_t *me0900_pci_constructor(struct pci_dev *pci_device)
{
me0900_device_t *me0900_device;
me_subdevice_t *subdevice;
unsigned int version_idx;
int err;
int i;
int port_shift;
PDEBUG("executed.\n");
// Allocate structure for device instance.
me0900_device = kmalloc(sizeof(me0900_device_t), GFP_KERNEL);
if (!me0900_device) {
PERROR("Cannot get memory for device instance.\n");
return NULL;
}
memset(me0900_device, 0, sizeof(me0900_device_t));
// Initialize base class structure.
err = me_device_pci_init((me_device_t *) me0900_device, pci_device);
if (err) {
kfree(me0900_device);
PERROR("Cannot initialize device base class.\n");
return NULL;
}
/* Get the index in the device version information table. */
version_idx =
me0900_versions_get_device_index(me0900_device->base.info.pci.
device_id);
/* Initialize 8255 chip to desired mode */
if (me0900_device->base.info.pci.device_id ==
PCI_DEVICE_ID_MEILHAUS_ME0940) {
outb(0x9B,
me0900_device->base.info.pci.reg_bases[2] +
ME0900_CTRL_REG);
} else if (me0900_device->base.info.pci.device_id ==
PCI_DEVICE_ID_MEILHAUS_ME0950) {
outb(0x89,
me0900_device->base.info.pci.reg_bases[2] +
ME0900_CTRL_REG);
outb(0x00,
me0900_device->base.info.pci.reg_bases[2] +
ME0900_WRITE_ENABLE_REG);
} else if (me0900_device->base.info.pci.device_id ==
PCI_DEVICE_ID_MEILHAUS_ME0960) {
outb(0x8B,
me0900_device->base.info.pci.reg_bases[2] +
ME0900_CTRL_REG);
outb(0x00,
me0900_device->base.info.pci.reg_bases[2] +
ME0900_WRITE_ENABLE_REG);
}
port_shift =
(me0900_device->base.info.pci.device_id ==
PCI_DEVICE_ID_MEILHAUS_ME0960) ? 1 : 0;
// Create subdevice instances.
for (i = 0; i < me0900_versions[version_idx].di_subdevices; i++) {
subdevice =
(me_subdevice_t *) me0900_di_constructor(me0900_device->
base.info.pci.
reg_bases[2],
i + port_shift);
if (!subdevice) {
me_device_deinit((me_device_t *) me0900_device);
kfree(me0900_device);
PERROR("Cannot get memory for subdevice.\n");
return NULL;
}
me_slist_add_subdevice_tail(&me0900_device->base.slist,
subdevice);
}
for (i = 0; i < me0900_versions[version_idx].do_subdevices; i++) {
subdevice =
(me_subdevice_t *) me0900_do_constructor(me0900_device->
base.info.pci.
reg_bases[2], i);
if (!subdevice) {
me_device_deinit((me_device_t *) me0900_device);
kfree(me0900_device);
PERROR("Cannot get memory for subdevice.\n");
return NULL;
}
me_slist_add_subdevice_tail(&me0900_device->base.slist,
subdevice);
}
return (me_device_t *) me0900_device;
}
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");
/**
* @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
/**
* @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;
}
/**
* @file me0900_di.h
*
* @brief ME-9x digital input subdevice class.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0900_DI_H_
#define _ME0900_DI_H_
#include "mesubdevice.h"
#ifdef __KERNEL__
/**
* @brief The template subdevice class.
*/
typedef struct me0900_di_subdevice {
/* Inheritance */
me_subdevice_t base; /**< The subdevice base class. */
/* Attributes */
spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */
unsigned int di_idx;
unsigned long ctrl_reg;
unsigned long port_reg;
#ifdef MEDEBUG_DEBUG_REG
unsigned long reg_base;
#endif
} me0900_di_subdevice_t;
/**
* @brief The constructor to generate a ME-9x digital input subdevice instance.
*
* @param reg_base The register base address of the device as returned by the PCI BIOS.
*
* @return Pointer to new instance on success.\n
* NULL on error.
*/
me0900_di_subdevice_t *me0900_di_constructor(uint32_t me0900_reg_base,
unsigned int di_idx);
#endif
#endif
/**
* @file me0900_do.c
*
* @brief ME-9x digital output subdevice instance.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif
/*
* Includes
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <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;
}
/**
* @file me0900_do.h
*
* @brief ME-9x digital output subdevice class.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0900_DO_H_
#define _ME0900_DO_H_
#include "mesubdevice.h"
#ifdef __KERNEL__
/**
* @brief The template subdevice class.
*/
typedef struct me0900_do_subdevice {
/* Inheritance */
me_subdevice_t base; /**< The subdevice base class. */
/* Attributes */
spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */
unsigned int do_idx;
unsigned long ctrl_reg;
unsigned long port_reg;
unsigned long enable_reg;
unsigned long disable_reg;
#ifdef MEDEBUG_DEBUG_REG
unsigned long reg_base;
#endif
} me0900_do_subdevice_t;
/**
* @brief The constructor to generate a ME-9x digital output subdevice instance.
*
* @param reg_base The register base address of the device as returned by the PCI BIOS.
* @param do_idx The index of the digital output subdevice on this device.
*
* @return Pointer to new instance on success.\n
* NULL on error.
*/
me0900_do_subdevice_t *me0900_do_constructor(uint32_t reg_base,
unsigned int do_idx);
#endif
#endif
/**
* @file me0900_reg.h
*
* @brief ME-9x register definitions.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME0900_REG_H_
#define _ME0900_REG_H_
#ifdef __KERNEL__
#define ME0900_PORT_A_REG 0x00
#define ME0900_PORT_B_REG 0x01
#define ME0900_PORT_C_REG 0x02
#define ME0900_CTRL_REG 0x03 // ( ,w)
#define ME0900_WRITE_ENABLE_REG 0x04 // (r,w)
#define ME0900_WRITE_DISABLE_REG 0x08 // (r,w)
#endif
#endif
/**
* @file me1000_device.c
*
* @brief ME-1000 device class implementation.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
* @author Krzysztof Gantzke (k.gantzke@meilhaus.de)
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif
#ifndef MODULE
# define MODULE
#endif
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include "meids.h"
#include "meerror.h"
#include "mecommon.h"
#include "meinternal.h"
#include "medebug.h"
#include "medevice.h"
#include "me1000_device.h"
#include "mesubdevice.h"
#include "me1000_dio.h"
static int me1000_config_load(me_device_t *me_device, struct file *filep,
me_cfg_device_entry_t *config)
{
me1000_device_t *me1000_device;
me1000_dio_subdevice_t *dio;
PDEBUG("executed.\n");
me1000_device = (me1000_device_t *) me_device;
if (config->count == 2) {
if (me_slist_get_number_subdevices(&me1000_device->base.slist)
== 2) {
// Nothing to do.
} else {
// Remove 2 extra subdevices
dio =
(me1000_dio_subdevice_t *)
me_slist_del_subdevice_tail(&me1000_device->base.
slist);
if (dio)
dio->base.
me_subdevice_destructor((me_subdevice_t *)
dio);
dio =
(me1000_dio_subdevice_t *)
me_slist_del_subdevice_tail(&me1000_device->base.
slist);
if (dio)
dio->base.
me_subdevice_destructor((me_subdevice_t *)
dio);
}
} else if (config->count == 4) {
//Add 2 subdevices
if (me_slist_get_number_subdevices(&me1000_device->base.slist)
== 2) {
dio =
me1000_dio_constructor(me1000_device->base.info.pci.
reg_bases[2], 2,
&me1000_device->ctrl_lock);
if (!dio) {
PERROR("Cannot create dio subdevice.\n");
return ME_ERRNO_INTERNAL;
}
me_slist_add_subdevice_tail(&me1000_device->base.slist,
(me_subdevice_t *) dio);
dio =
me1000_dio_constructor(me1000_device->base.info.pci.
reg_bases[2], 3,
&me1000_device->ctrl_lock);
if (!dio) {
dio =
(me1000_dio_subdevice_t *)
me_slist_del_subdevice_tail(&me1000_device->
base.slist);
if (dio)
dio->base.
me_subdevice_destructor((me_subdevice_t *) dio);
PERROR("Cannot create dio subdevice.\n");
return ME_ERRNO_INTERNAL;
}
me_slist_add_subdevice_tail(&me1000_device->base.slist,
(me_subdevice_t *) dio);
} else {
// Nothing to do.
}
} else {
PERROR("Invalid configuration.\n");
return ME_ERRNO_INTERNAL;
}
return ME_ERRNO_SUCCESS;
}
me_device_t *me1000_pci_constructor(struct pci_dev * pci_device)
{
me1000_device_t *me1000_device;
me_subdevice_t *subdevice;
int err;
int i;
PDEBUG("executed.\n");
// Allocate structure for device instance.
me1000_device = kmalloc(sizeof(me1000_device_t), GFP_KERNEL);
if (!me1000_device) {
PERROR("Cannot get memory for ME-1000 device instance.\n");
return NULL;
}
memset(me1000_device, 0, sizeof(me1000_device_t));
// Initialize base class structure.
err = me_device_pci_init((me_device_t *) me1000_device, pci_device);
if (err) {
kfree(me1000_device);
PERROR("Cannot initialize device base class.\n");
return NULL;
}
// Initialize spin lock .
spin_lock_init(&me1000_device->ctrl_lock);
for (i = 0; i < 4; i++) {
subdevice =
(me_subdevice_t *) me1000_dio_constructor(me1000_device->
base.info.pci.
reg_bases[2], i,
&me1000_device->
ctrl_lock);
if (!subdevice) {
me_device_deinit((me_device_t *) me1000_device);
kfree(me1000_device);
PERROR("Cannot get memory for subdevice.\n");
return NULL;
}
me_slist_add_subdevice_tail(&me1000_device->base.slist,
subdevice);
}
// Overwrite base class methods.
me1000_device->base.me_device_config_load = me1000_config_load;
return (me_device_t *) me1000_device;
}
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");
/**
* @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
/**
* @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;
}
/**
* @file me1000_dio.h
*
* @brief Meilhaus ME-1000 digital i/o implementation.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME1000_DIO_H_
#define _ME1000_DIO_H_
#include "mesubdevice.h"
#include "meslock.h"
#ifdef __KERNEL__
/**
* @brief The ME-1000 DIO subdevice class.
*/
typedef struct me1000_dio_subdevice {
/* Inheritance */
me_subdevice_t base; /**< The subdevice base class. */
/* Attributes */
// uint32_t magic; /**< The magic number unique for this structure. */
spinlock_t subdevice_lock; /**< Spin lock to protect the subdevice from concurrent access. */
spinlock_t *ctrl_reg_lock; /**< Spin lock to protect #ctrl_reg and #ctrl_reg_mirror from concurrent access. */
int dio_idx; /**< The index of the DIO port on the device. */
unsigned long port_reg; /**< Register to read or write a value from or to the port respectively. */
unsigned long ctrl_reg; /**< Register to configure the DIO modes. */
#ifdef MEDEBUG_DEBUG_REG
unsigned long reg_base;
#endif
} me1000_dio_subdevice_t;
/**
* @brief The constructor to generate a ME-1000 DIO instance.
*
* @param reg_base The register base address of the device as returned by the PCI BIOS.
* @param dio_idx The index of the DIO on the device.
* @param ctrl_reg_lock Pointer to spin lock protecting the control register and from concurrent access.
*
* @return Pointer to new instance on success.\n
* NULL on error.
*/
me1000_dio_subdevice_t *me1000_dio_constructor(uint32_t reg_base,
unsigned int dio_idx,
spinlock_t * ctrl_reg_lock);
#endif
#endif
/**
* @file me1000_dio_reg.h
*
* @brief ME-1000 digital i/o register definitions.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
* @author Krzysztof Gantzke (k.gantzke@meilhaus.de)
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _ME1000_DIO_REG_H_
# define _ME1000_DIO_REG_H_
# ifdef __KERNEL__
# define ME1000_DIO_NUMBER_CHANNELS 32 /**< The number of channels per DIO port. */
# define ME1000_DIO_NUMBER_PORTS 4 /**< The number of ports per ME-1000. */
// # define ME1000_PORT_A 0x0000 /**< Port A base register offset. */
// # define ME1000_PORT_B 0x0004 /**< Port B base register offset. */
// # define ME1000_PORT_C 0x0008 /**< Port C base register offset. */
// # define ME1000_PORT_D 0x000C /**< Port D base register offset. */
# define ME1000_PORT 0x0000 /**< Base for port's register. */
# define ME1000_PORT_STEP 4 /**< Distance between port's register. */
# define ME1000_PORT_MODE 0x0010 /**< Configuration register to switch the port direction. */
// # define ME1000_PORT_MODE_OUTPUT_A (1 << 0) /**< If set, port A is in output, otherwise in input mode. */
// # define ME1000_PORT_MODE_OUTPUT_B (1 << 1) /**< If set, port B is in output, otherwise in input mode. */
// # define ME1000_PORT_MODE_OUTPUT_C (1 << 2) /**< If set, port C is in output, otherwise in input mode. */
// # define ME1000_PORT_MODE_OUTPUT_D (1 << 3) /**< If set, port D is in output, otherwise in input mode. */
# endif //__KERNEL__
#endif //_ME1000_DIO_REG_H_
/**
* @file me1400_device.c
*
* @brief ME-1400 device instance.
* @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
* @author Guenter Gebhardt
* @author Krzysztof Gantzke (k.gantzke@meilhaus.de)
*/
/*
* Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* User application could also include the kernel header files. But the
* real kernel functions are protected by #ifdef __KERNEL__.
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif
/*
* This must be defined before module.h is included. Not needed, when
* it is a built in driver.
*/
#ifndef MODULE
# define MODULE
#endif
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include "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");
/**
* @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
此差异已折叠。
/**
* @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
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
/**
* @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
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册