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

Staging: add me4000 pci data collection driver

Originally written by Guenter Gebhardt <g.gebhardt@meilhaus.de>

TODO:
	- checkpatch.pl cleanups
	- sparse cleanups
	- possible /proc interaction cleanups
	- more info needed for Kconfig entry
	- real device id?
	- module parameter cleanup

Cc: Wolfgang Beiter <w.beiter@aon.at>
Cc: Guenter Gebhardt <g.gebhardt@meilhaus.de>
Signed-off-by: NGreg Kroah-Hartman <gregkh@suse.de>
上级 cff338a9
......@@ -29,4 +29,6 @@ source "drivers/staging/slicoss/Kconfig"
source "drivers/staging/sxg/Kconfig"
source "drivers/staging/me4000/Kconfig"
endif # STAGING
......@@ -3,3 +3,4 @@
obj-$(CONFIG_ET131X) += et131x/
obj-$(CONFIG_SLICOSS) += slicoss/
obj-$(CONFIG_SXG) += sxg/
obj-$(CONFIG_ME4000) += me4000/
config ME4000
tristate "Meilhaus ME-4000 support"
default n
depends on PCI
help
This driver supports the Meilhaus ME-4000 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 me4000.
obj-$(CONFIG_ME4000) += me4000.o
TODO:
- checkpatch.pl cleanups
- sparse cleanups
- possible /proc interaction cleanups
- more info needed for Kconfig entry
- real device id?
- module parameter cleanup
Please send patches to Greg Kroah-Hartman <gregkh@suse.de>
and Cc: Wolfgang Beiter <w.beiter@aon.at> and
Guenter Gebhardt <g.gebhardt@meilhaus.de>
/* Device driver for Meilhaus ME-4000 board family.
* ================================================
*
* Copyright (C) 2003 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.
*
* Author: Guenter Gebhardt <g.gebhardt@meilhaus.de>
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/unistd.h>
#include <linux/list.h>
#include <linux/proc_fs.h>
#include <linux/poll.h>
#include <linux/vmalloc.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
#include <linux/types.h>
#include <linux/slab.h>
/* Include-File for the Meilhaus ME-4000 I/O board */
#include "me4000.h"
#include "me4000_firmware.h"
#include "me4610_firmware.h"
/* Administrative stuff for modinfo */
MODULE_AUTHOR("Guenter Gebhardt <g.gebhardt@meilhaus.de>");
MODULE_DESCRIPTION
("Device Driver Module for Meilhaus ME-4000 boards version 1.0.5");
MODULE_SUPPORTED_DEVICE("Meilhaus ME-4000 Multi I/O boards");
MODULE_LICENSE("GPL");
/* Board specific data are kept in a global list */
LIST_HEAD(me4000_board_info_list);
/* Major Device Numbers. 0 means to get it automatically from the System */
static int me4000_ao_major_driver_no = 0;
static int me4000_ai_major_driver_no = 0;
static int me4000_dio_major_driver_no = 0;
static int me4000_cnt_major_driver_no = 0;
static int me4000_ext_int_major_driver_no = 0;
/* Let the user specify a custom major driver number */
module_param(me4000_ao_major_driver_no, int, 0);
MODULE_PARM_DESC(me4000_ao_major_driver_no,
"Major driver number for analog output (default 0)");
module_param(me4000_ai_major_driver_no, int, 0);
MODULE_PARM_DESC(me4000_ai_major_driver_no,
"Major driver number for analog input (default 0)");
module_param(me4000_dio_major_driver_no, int, 0);
MODULE_PARM_DESC(me4000_dio_major_driver_no,
"Major driver number digital I/O (default 0)");
module_param(me4000_cnt_major_driver_no, int, 0);
MODULE_PARM_DESC(me4000_cnt_major_driver_no,
"Major driver number for counter (default 0)");
module_param(me4000_ext_int_major_driver_no, int, 0);
MODULE_PARM_DESC(me4000_ext_int_major_driver_no,
"Major driver number for external interrupt (default 0)");
/*-----------------------------------------------------------------------------
Module stuff
---------------------------------------------------------------------------*/
int init_module(void);
void cleanup_module(void);
/*-----------------------------------------------------------------------------
Board detection and initialization
---------------------------------------------------------------------------*/
static int me4000_probe(struct pci_dev *dev, const struct pci_device_id *id);
static int me4000_xilinx_download(me4000_info_t *);
static int me4000_reset_board(me4000_info_t *);
static void clear_board_info_list(void);
static int get_registers(struct pci_dev *dev, me4000_info_t * info);
static int init_board_info(struct pci_dev *dev, me4000_info_t * board_info);
static int alloc_ao_contexts(me4000_info_t * info);
static void release_ao_contexts(me4000_info_t * board_info);
static int alloc_ai_context(me4000_info_t * info);
static int alloc_dio_context(me4000_info_t * info);
static int alloc_cnt_context(me4000_info_t * info);
static int alloc_ext_int_context(me4000_info_t * info);
/*-----------------------------------------------------------------------------
Stuff used by all device parts
---------------------------------------------------------------------------*/
static int me4000_open(struct inode *, struct file *);
static int me4000_release(struct inode *, struct file *);
static int me4000_get_user_info(me4000_user_info_t *,
me4000_info_t * board_info);
static int me4000_read_procmem(char *, char **, off_t, int, int *, void *);
/*-----------------------------------------------------------------------------
Analog output stuff
---------------------------------------------------------------------------*/
static ssize_t me4000_ao_write_sing(struct file *, const char *, size_t,
loff_t *);
static ssize_t me4000_ao_write_wrap(struct file *, const char *, size_t,
loff_t *);
static ssize_t me4000_ao_write_cont(struct file *, const char *, size_t,
loff_t *);
static int me4000_ao_ioctl_sing(struct inode *, struct file *, unsigned int,
unsigned long);
static int me4000_ao_ioctl_wrap(struct inode *, struct file *, unsigned int,
unsigned long);
static int me4000_ao_ioctl_cont(struct inode *, struct file *, unsigned int,
unsigned long);
static unsigned int me4000_ao_poll_cont(struct file *, poll_table *);
static int me4000_ao_fsync_cont(struct file *, struct dentry *, int);
static int me4000_ao_start(unsigned long *, me4000_ao_context_t *);
static int me4000_ao_stop(me4000_ao_context_t *);
static int me4000_ao_immediate_stop(me4000_ao_context_t *);
static int me4000_ao_timer_set_divisor(u32 *, me4000_ao_context_t *);
static int me4000_ao_preload(me4000_ao_context_t *);
static int me4000_ao_preload_update(me4000_ao_context_t *);
static int me4000_ao_ex_trig_set_edge(int *, me4000_ao_context_t *);
static int me4000_ao_ex_trig_enable(me4000_ao_context_t *);
static int me4000_ao_ex_trig_disable(me4000_ao_context_t *);
static int me4000_ao_prepare(me4000_ao_context_t * ao_info);
static int me4000_ao_reset(me4000_ao_context_t * ao_info);
static int me4000_ao_enable_do(me4000_ao_context_t *);
static int me4000_ao_disable_do(me4000_ao_context_t *);
static int me4000_ao_fsm_state(int *, me4000_ao_context_t *);
static int me4000_ao_simultaneous_ex_trig(me4000_ao_context_t * ao_context);
static int me4000_ao_simultaneous_sw(me4000_ao_context_t * ao_context);
static int me4000_ao_simultaneous_disable(me4000_ao_context_t * ao_context);
static int me4000_ao_simultaneous_update(me4000_ao_channel_list_t * channels,
me4000_ao_context_t * ao_context);
static int me4000_ao_synchronous_ex_trig(me4000_ao_context_t * ao_context);
static int me4000_ao_synchronous_sw(me4000_ao_context_t * ao_context);
static int me4000_ao_synchronous_disable(me4000_ao_context_t * ao_context);
static int me4000_ao_ex_trig_timeout(unsigned long *arg,
me4000_ao_context_t * ao_context);
static int me4000_ao_get_free_buffer(unsigned long *arg,
me4000_ao_context_t * ao_context);
/*-----------------------------------------------------------------------------
Analog input stuff
---------------------------------------------------------------------------*/
static int me4000_ai_single(me4000_ai_single_t *, me4000_ai_context_t *);
static int me4000_ai_ioctl_sing(struct inode *, struct file *, unsigned int,
unsigned long);
static ssize_t me4000_ai_read(struct file *, char *, size_t, loff_t *);
static int me4000_ai_ioctl_sw(struct inode *, struct file *, unsigned int,
unsigned long);
static unsigned int me4000_ai_poll(struct file *, poll_table *);
static int me4000_ai_fasync(int fd, struct file *file_p, int mode);
static int me4000_ai_ioctl_ext(struct inode *, struct file *, unsigned int,
unsigned long);
static int me4000_ai_prepare(me4000_ai_context_t * ai_context);
static int me4000_ai_reset(me4000_ai_context_t * ai_context);
static int me4000_ai_config(me4000_ai_config_t *, me4000_ai_context_t *);
static int me4000_ai_start(me4000_ai_context_t *);
static int me4000_ai_start_ex(unsigned long *, me4000_ai_context_t *);
static int me4000_ai_stop(me4000_ai_context_t *);
static int me4000_ai_immediate_stop(me4000_ai_context_t *);
static int me4000_ai_ex_trig_enable(me4000_ai_context_t *);
static int me4000_ai_ex_trig_disable(me4000_ai_context_t *);
static int me4000_ai_ex_trig_setup(me4000_ai_trigger_t *,
me4000_ai_context_t *);
static int me4000_ai_sc_setup(me4000_ai_sc_t * arg,
me4000_ai_context_t * ai_context);
static int me4000_ai_offset_enable(me4000_ai_context_t * ai_context);
static int me4000_ai_offset_disable(me4000_ai_context_t * ai_context);
static int me4000_ai_fullscale_enable(me4000_ai_context_t * ai_context);
static int me4000_ai_fullscale_disable(me4000_ai_context_t * ai_context);
static int me4000_ai_fsm_state(int *arg, me4000_ai_context_t * ai_context);
static int me4000_ai_get_count_buffer(unsigned long *arg,
me4000_ai_context_t * ai_context);
/*-----------------------------------------------------------------------------
EEPROM stuff
---------------------------------------------------------------------------*/
static int me4000_eeprom_read(me4000_eeprom_t * arg,
me4000_ai_context_t * ai_context);
static int me4000_eeprom_write(me4000_eeprom_t * arg,
me4000_ai_context_t * ai_context);
static unsigned short eeprom_read_cmd(me4000_ai_context_t * ai_context,
unsigned long cmd, int length);
static int eeprom_write_cmd(me4000_ai_context_t * ai_context, unsigned long cmd,
int length);
/*-----------------------------------------------------------------------------
Digital I/O stuff
---------------------------------------------------------------------------*/
static int me4000_dio_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);
static int me4000_dio_config(me4000_dio_config_t *, me4000_dio_context_t *);
static int me4000_dio_get_byte(me4000_dio_byte_t *, me4000_dio_context_t *);
static int me4000_dio_set_byte(me4000_dio_byte_t *, me4000_dio_context_t *);
static int me4000_dio_reset(me4000_dio_context_t *);
/*-----------------------------------------------------------------------------
Counter stuff
---------------------------------------------------------------------------*/
static int me4000_cnt_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);
static int me4000_cnt_config(me4000_cnt_config_t *, me4000_cnt_context_t *);
static int me4000_cnt_read(me4000_cnt_t *, me4000_cnt_context_t *);
static int me4000_cnt_write(me4000_cnt_t *, me4000_cnt_context_t *);
static int me4000_cnt_reset(me4000_cnt_context_t *);
/*-----------------------------------------------------------------------------
External interrupt routines
---------------------------------------------------------------------------*/
static int me4000_ext_int_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);
static int me4000_ext_int_enable(me4000_ext_int_context_t *);
static int me4000_ext_int_disable(me4000_ext_int_context_t *);
static int me4000_ext_int_count(unsigned long *arg,
me4000_ext_int_context_t * ext_int_context);
static int me4000_ext_int_fasync(int fd, struct file *file_ptr, int mode);
/*-----------------------------------------------------------------------------
The interrupt service routines
---------------------------------------------------------------------------*/
static irqreturn_t me4000_ao_isr(int, void *);
static irqreturn_t me4000_ai_isr(int, void *);
static irqreturn_t me4000_ext_int_isr(int, void *);
/*-----------------------------------------------------------------------------
Inline functions
---------------------------------------------------------------------------*/
static int inline me4000_buf_count(me4000_circ_buf_t, int);
static int inline me4000_buf_space(me4000_circ_buf_t, int);
static int inline me4000_space_to_end(me4000_circ_buf_t, int);
static int inline me4000_values_to_end(me4000_circ_buf_t, int);
static void inline me4000_outb(unsigned char value, unsigned long port);
static void inline me4000_outl(unsigned long value, unsigned long port);
static unsigned long inline me4000_inl(unsigned long port);
static unsigned char inline me4000_inb(unsigned long port);
static int me4000_buf_count(me4000_circ_buf_t buf, int size)
{
return ((buf.head - buf.tail) & (size - 1));
}
static int me4000_buf_space(me4000_circ_buf_t buf, int size)
{
return ((buf.tail - (buf.head + 1)) & (size - 1));
}
static int me4000_values_to_end(me4000_circ_buf_t buf, int size)
{
int end;
int n;
end = size - buf.tail;
n = (buf.head + end) & (size - 1);
return (n < end) ? n : end;
}
static int me4000_space_to_end(me4000_circ_buf_t buf, int size)
{
int end;
int n;
end = size - 1 - buf.head;
n = (end + buf.tail) & (size - 1);
return (n <= end) ? n : (end + 1);
}
static void me4000_outb(unsigned char value, unsigned long port)
{
PORT_PDEBUG("--> 0x%02X port 0x%04lX\n", value, port);
outb(value, port);
}
static void me4000_outl(unsigned long value, unsigned long port)
{
PORT_PDEBUG("--> 0x%08lX port 0x%04lX\n", value, port);
outl(value, port);
}
static unsigned long me4000_inl(unsigned long port)
{
unsigned long value;
value = inl(port);
PORT_PDEBUG("<-- 0x%08lX port 0x%04lX\n", value, port);
return value;
}
static unsigned char me4000_inb(unsigned long port)
{
unsigned char value;
value = inb(port);
PORT_PDEBUG("<-- 0x%08X port 0x%04lX\n", value, port);
return value;
}
struct pci_driver me4000_driver = {
.name = ME4000_NAME,
.id_table = me4000_pci_table,
.probe = me4000_probe
};
static struct file_operations me4000_ao_fops_sing = {
owner:THIS_MODULE,
write:me4000_ao_write_sing,
ioctl:me4000_ao_ioctl_sing,
open:me4000_open,
release:me4000_release,
};
static struct file_operations me4000_ao_fops_wrap = {
owner:THIS_MODULE,
write:me4000_ao_write_wrap,
ioctl:me4000_ao_ioctl_wrap,
open:me4000_open,
release:me4000_release,
};
static struct file_operations me4000_ao_fops_cont = {
owner:THIS_MODULE,
write:me4000_ao_write_cont,
poll:me4000_ao_poll_cont,
ioctl:me4000_ao_ioctl_cont,
open:me4000_open,
release:me4000_release,
fsync:me4000_ao_fsync_cont,
};
static struct file_operations me4000_ai_fops_sing = {
owner:THIS_MODULE,
ioctl:me4000_ai_ioctl_sing,
open:me4000_open,
release:me4000_release,
};
static struct file_operations me4000_ai_fops_cont_sw = {
owner:THIS_MODULE,
read:me4000_ai_read,
poll:me4000_ai_poll,
ioctl:me4000_ai_ioctl_sw,
open:me4000_open,
release:me4000_release,
fasync:me4000_ai_fasync,
};
static struct file_operations me4000_ai_fops_cont_et = {
owner:THIS_MODULE,
read:me4000_ai_read,
poll:me4000_ai_poll,
ioctl:me4000_ai_ioctl_ext,
open:me4000_open,
release:me4000_release,
};
static struct file_operations me4000_ai_fops_cont_et_value = {
owner:THIS_MODULE,
read:me4000_ai_read,
poll:me4000_ai_poll,
ioctl:me4000_ai_ioctl_ext,
open:me4000_open,
release:me4000_release,
};
static struct file_operations me4000_ai_fops_cont_et_chanlist = {
owner:THIS_MODULE,
read:me4000_ai_read,
poll:me4000_ai_poll,
ioctl:me4000_ai_ioctl_ext,
open:me4000_open,
release:me4000_release,
};
static struct file_operations me4000_dio_fops = {
owner:THIS_MODULE,
ioctl:me4000_dio_ioctl,
open:me4000_open,
release:me4000_release,
};
static struct file_operations me4000_cnt_fops = {
owner:THIS_MODULE,
ioctl:me4000_cnt_ioctl,
open:me4000_open,
release:me4000_release,
};
static struct file_operations me4000_ext_int_fops = {
owner:THIS_MODULE,
ioctl:me4000_ext_int_ioctl,
open:me4000_open,
release:me4000_release,
fasync:me4000_ext_int_fasync,
};
static struct file_operations *me4000_ao_fops_array[] = {
&me4000_ao_fops_sing, // single operations
&me4000_ao_fops_wrap, // wraparound operations
&me4000_ao_fops_cont, // continous operations
};
static struct file_operations *me4000_ai_fops_array[] = {
&me4000_ai_fops_sing, // single operations
&me4000_ai_fops_cont_sw, // continuous operations with software start
&me4000_ai_fops_cont_et, // continous operations with external trigger
&me4000_ai_fops_cont_et_value, // sample values by external trigger
&me4000_ai_fops_cont_et_chanlist, // work through one channel list by external trigger
};
int __init me4000_init_module(void)
{
int result = 0;
CALL_PDEBUG("init_module() is executed\n");
/* Register driver capabilities */
result = pci_register_driver(&me4000_driver);
PDEBUG("init_module():%d devices detected\n", result);
if (result < 0) {
printk(KERN_ERR "ME4000:init_module():Can't register driver\n");
goto INIT_ERROR_1;
}
/* Allocate major number for analog output */
result =
register_chrdev(me4000_ao_major_driver_no, ME4000_AO_NAME,
&me4000_ao_fops_sing);
if (result < 0) {
printk(KERN_ERR "ME4000:init_module():Can't get AO major no\n");
goto INIT_ERROR_2;
} else {
me4000_ao_major_driver_no = result;
}
PDEBUG("init_module():Major driver number for AO = %ld\n",
me4000_ao_major_driver_no);
/* Allocate major number for analog input */
result =
register_chrdev(me4000_ai_major_driver_no, ME4000_AI_NAME,
&me4000_ai_fops_sing);
if (result < 0) {
printk(KERN_ERR "ME4000:init_module():Can't get AI major no\n");
goto INIT_ERROR_3;
} else {
me4000_ai_major_driver_no = result;
}
PDEBUG("init_module():Major driver number for AI = %ld\n",
me4000_ai_major_driver_no);
/* Allocate major number for digital I/O */
result =
register_chrdev(me4000_dio_major_driver_no, ME4000_DIO_NAME,
&me4000_dio_fops);
if (result < 0) {
printk(KERN_ERR
"ME4000:init_module():Can't get DIO major no\n");
goto INIT_ERROR_4;
} else {
me4000_dio_major_driver_no = result;
}
PDEBUG("init_module():Major driver number for DIO = %ld\n",
me4000_dio_major_driver_no);
/* Allocate major number for counter */
result =
register_chrdev(me4000_cnt_major_driver_no, ME4000_CNT_NAME,
&me4000_cnt_fops);
if (result < 0) {
printk(KERN_ERR
"ME4000:init_module():Can't get CNT major no\n");
goto INIT_ERROR_5;
} else {
me4000_cnt_major_driver_no = result;
}
PDEBUG("init_module():Major driver number for CNT = %ld\n",
me4000_cnt_major_driver_no);
/* Allocate major number for external interrupt */
result =
register_chrdev(me4000_ext_int_major_driver_no, ME4000_EXT_INT_NAME,
&me4000_ext_int_fops);
if (result < 0) {
printk(KERN_ERR
"ME4000:init_module():Can't get major no for external interrupt\n");
goto INIT_ERROR_6;
} else {
me4000_ext_int_major_driver_no = result;
}
PDEBUG
("init_module():Major driver number for external interrupt = %ld\n",
me4000_ext_int_major_driver_no);
/* Create the /proc/me4000 entry */
if (!create_proc_read_entry
("me4000", 0, NULL, me4000_read_procmem, NULL)) {
result = -ENODEV;
printk(KERN_ERR
"ME4000:init_module():Can't create proc entry\n");
goto INIT_ERROR_7;
}
return 0;
INIT_ERROR_7:
unregister_chrdev(me4000_ext_int_major_driver_no, ME4000_EXT_INT_NAME);
INIT_ERROR_6:
unregister_chrdev(me4000_cnt_major_driver_no, ME4000_CNT_NAME);
INIT_ERROR_5:
unregister_chrdev(me4000_dio_major_driver_no, ME4000_DIO_NAME);
INIT_ERROR_4:
unregister_chrdev(me4000_ai_major_driver_no, ME4000_AI_NAME);
INIT_ERROR_3:
unregister_chrdev(me4000_ao_major_driver_no, ME4000_AO_NAME);
INIT_ERROR_2:
pci_unregister_driver(&me4000_driver);
clear_board_info_list();
INIT_ERROR_1:
return result;
}
module_init(me4000_init_module);
static void clear_board_info_list(void)
{
struct list_head *board_p;
struct list_head *dac_p;
me4000_info_t *board_info;
me4000_ao_context_t *ao_context;
/* Clear context lists */
for (board_p = me4000_board_info_list.next;
board_p != &me4000_board_info_list; board_p = board_p->next) {
board_info = list_entry(board_p, me4000_info_t, list);
/* Clear analog output context list */
while (!list_empty(&board_info->ao_context_list)) {
dac_p = board_info->ao_context_list.next;
ao_context =
list_entry(dac_p, me4000_ao_context_t, list);
me4000_ao_reset(ao_context);
free_irq(ao_context->irq, ao_context);
if (ao_context->circ_buf.buf)
kfree(ao_context->circ_buf.buf);
list_del(dac_p);
kfree(ao_context);
}
/* Clear analog input context */
if (board_info->ai_context->circ_buf.buf)
kfree(board_info->ai_context->circ_buf.buf);
kfree(board_info->ai_context);
/* Clear digital I/O context */
kfree(board_info->dio_context);
/* Clear counter context */
kfree(board_info->cnt_context);
/* Clear external interrupt context */
kfree(board_info->ext_int_context);
}
/* Clear the board info list */
while (!list_empty(&me4000_board_info_list)) {
board_p = me4000_board_info_list.next;
board_info = list_entry(board_p, me4000_info_t, list);
pci_release_regions(board_info->pci_dev_p);
list_del(board_p);
kfree(board_info);
}
}
static int get_registers(struct pci_dev *dev, me4000_info_t * board_info)
{
/*--------------------------- plx regbase ---------------------------------*/
board_info->plx_regbase = pci_resource_start(dev, 1);
if (board_info->plx_regbase == 0) {
printk(KERN_ERR
"ME4000:get_registers():PCI base address 1 is not available\n");
return -ENODEV;
}
board_info->plx_regbase_size = pci_resource_len(dev, 1);
PDEBUG
("get_registers():PLX configuration registers at address 0x%4lX [0x%4lX]\n",
board_info->plx_regbase, board_info->plx_regbase_size);
/*--------------------------- me4000 regbase ------------------------------*/
board_info->me4000_regbase = pci_resource_start(dev, 2);
if (board_info->me4000_regbase == 0) {
printk(KERN_ERR
"ME4000:get_registers():PCI base address 2 is not available\n");
return -ENODEV;
}
board_info->me4000_regbase_size = pci_resource_len(dev, 2);
PDEBUG("get_registers():ME4000 registers at address 0x%4lX [0x%4lX]\n",
board_info->me4000_regbase, board_info->me4000_regbase_size);
/*--------------------------- timer regbase ------------------------------*/
board_info->timer_regbase = pci_resource_start(dev, 3);
if (board_info->timer_regbase == 0) {
printk(KERN_ERR
"ME4000:get_registers():PCI base address 3 is not available\n");
return -ENODEV;
}
board_info->timer_regbase_size = pci_resource_len(dev, 3);
PDEBUG("get_registers():Timer registers at address 0x%4lX [0x%4lX]\n",
board_info->timer_regbase, board_info->timer_regbase_size);
/*--------------------------- program regbase ------------------------------*/
board_info->program_regbase = pci_resource_start(dev, 5);
if (board_info->program_regbase == 0) {
printk(KERN_ERR
"get_registers():ME4000:PCI base address 5 is not available\n");
return -ENODEV;
}
board_info->program_regbase_size = pci_resource_len(dev, 5);
PDEBUG("get_registers():Program registers at address 0x%4lX [0x%4lX]\n",
board_info->program_regbase, board_info->program_regbase_size);
return 0;
}
static int init_board_info(struct pci_dev *pci_dev_p,
me4000_info_t * board_info)
{
int i;
int result;
struct list_head *board_p;
board_info->pci_dev_p = pci_dev_p;
for (i = 0; i < ME4000_BOARD_VERSIONS; i++) {
if (me4000_boards[i].device_id == pci_dev_p->device) {
board_info->board_p = &me4000_boards[i];
break;
}
}
if (i == ME4000_BOARD_VERSIONS) {
printk(KERN_ERR
"ME4000:init_board_info():Device ID not valid\n");
return -ENODEV;
}
/* Get the index of the board in the global list */
for (board_p = me4000_board_info_list.next, i = 0;
board_p != &me4000_board_info_list; board_p = board_p->next, i++) {
if (board_p == &board_info->list) {
board_info->board_count = i;
break;
}
}
if (board_p == &me4000_board_info_list) {
printk(KERN_ERR
"ME4000:init_board_info():Cannot get index of baord\n");
return -ENODEV;
}
/* Init list head for analog output contexts */
INIT_LIST_HEAD(&board_info->ao_context_list);
/* Init spin locks */
spin_lock_init(&board_info->preload_lock);
spin_lock_init(&board_info->ai_ctrl_lock);
/* Get the serial number */
result = pci_read_config_dword(pci_dev_p, 0x2C, &board_info->serial_no);
if (result != PCIBIOS_SUCCESSFUL) {
printk(KERN_WARNING
"ME4000:init_board_info: Can't get serial_no\n");
return result;
}
PDEBUG("init_board_info():serial_no = 0x%x\n", board_info->serial_no);
/* Get the hardware revision */
result =
pci_read_config_byte(pci_dev_p, 0x08, &board_info->hw_revision);
if (result != PCIBIOS_SUCCESSFUL) {
printk(KERN_WARNING
"ME4000:init_board_info():Can't get hw_revision\n");
return result;
}
PDEBUG("init_board_info():hw_revision = 0x%x\n",
board_info->hw_revision);
/* Get the vendor id */
board_info->vendor_id = pci_dev_p->vendor;
PDEBUG("init_board_info():vendor_id = 0x%x\n", board_info->vendor_id);
/* Get the device id */
board_info->device_id = pci_dev_p->device;
PDEBUG("init_board_info():device_id = 0x%x\n", board_info->device_id);
/* Get the pci device number */
board_info->pci_dev_no = PCI_FUNC(pci_dev_p->devfn);
PDEBUG("init_board_info():pci_func_no = 0x%x\n",
board_info->pci_func_no);
/* Get the pci slot number */
board_info->pci_dev_no = PCI_SLOT(pci_dev_p->devfn);
PDEBUG("init_board_info():pci_dev_no = 0x%x\n", board_info->pci_dev_no);
/* Get the pci bus number */
board_info->pci_bus_no = pci_dev_p->bus->number;
PDEBUG("init_board_info():pci_bus_no = 0x%x\n", board_info->pci_bus_no);
/* Get the irq assigned to the board */
board_info->irq = pci_dev_p->irq;
PDEBUG("init_board_info():irq = %d\n", board_info->irq);
return 0;
}
static int alloc_ao_contexts(me4000_info_t * info)
{
int i;
int err;
me4000_ao_context_t *ao_context;
for (i = 0; i < info->board_p->ao.count; i++) {
ao_context = kmalloc(sizeof(me4000_ao_context_t), GFP_KERNEL);
if (!ao_context) {
printk(KERN_ERR
"alloc_ao_contexts():Can't get memory for ao context\n");
release_ao_contexts(info);
return -ENOMEM;
}
memset(ao_context, 0, sizeof(me4000_ao_context_t));
spin_lock_init(&ao_context->use_lock);
spin_lock_init(&ao_context->int_lock);
ao_context->irq = info->irq;
init_waitqueue_head(&ao_context->wait_queue);
ao_context->board_info = info;
if (info->board_p->ao.fifo_count) {
/* Allocate circular buffer */
ao_context->circ_buf.buf =
kmalloc(ME4000_AO_BUFFER_SIZE, GFP_KERNEL);
if (!ao_context->circ_buf.buf) {
printk(KERN_ERR
"alloc_ao_contexts():Can't get circular buffer\n");
release_ao_contexts(info);
return -ENOMEM;
}
memset(ao_context->circ_buf.buf, 0,
ME4000_AO_BUFFER_SIZE);
/* Clear the circular buffer */
ao_context->circ_buf.head = 0;
ao_context->circ_buf.tail = 0;
}
switch (i) {
case 0:
ao_context->ctrl_reg =
info->me4000_regbase + ME4000_AO_00_CTRL_REG;
ao_context->status_reg =
info->me4000_regbase + ME4000_AO_00_STATUS_REG;
ao_context->fifo_reg =
info->me4000_regbase + ME4000_AO_00_FIFO_REG;
ao_context->single_reg =
info->me4000_regbase + ME4000_AO_00_SINGLE_REG;
ao_context->timer_reg =
info->me4000_regbase + ME4000_AO_00_TIMER_REG;
ao_context->irq_status_reg =
info->me4000_regbase + ME4000_IRQ_STATUS_REG;
ao_context->preload_reg =
info->me4000_regbase + ME4000_AO_LOADSETREG_XX;
break;
case 1:
ao_context->ctrl_reg =
info->me4000_regbase + ME4000_AO_01_CTRL_REG;
ao_context->status_reg =
info->me4000_regbase + ME4000_AO_01_STATUS_REG;
ao_context->fifo_reg =
info->me4000_regbase + ME4000_AO_01_FIFO_REG;
ao_context->single_reg =
info->me4000_regbase + ME4000_AO_01_SINGLE_REG;
ao_context->timer_reg =
info->me4000_regbase + ME4000_AO_01_TIMER_REG;
ao_context->irq_status_reg =
info->me4000_regbase + ME4000_IRQ_STATUS_REG;
ao_context->preload_reg =
info->me4000_regbase + ME4000_AO_LOADSETREG_XX;
break;
case 2:
ao_context->ctrl_reg =
info->me4000_regbase + ME4000_AO_02_CTRL_REG;
ao_context->status_reg =
info->me4000_regbase + ME4000_AO_02_STATUS_REG;
ao_context->fifo_reg =
info->me4000_regbase + ME4000_AO_02_FIFO_REG;
ao_context->single_reg =
info->me4000_regbase + ME4000_AO_02_SINGLE_REG;
ao_context->timer_reg =
info->me4000_regbase + ME4000_AO_02_TIMER_REG;
ao_context->irq_status_reg =
info->me4000_regbase + ME4000_IRQ_STATUS_REG;
ao_context->preload_reg =
info->me4000_regbase + ME4000_AO_LOADSETREG_XX;
break;
case 3:
ao_context->ctrl_reg =
info->me4000_regbase + ME4000_AO_03_CTRL_REG;
ao_context->status_reg =
info->me4000_regbase + ME4000_AO_03_STATUS_REG;
ao_context->fifo_reg =
info->me4000_regbase + ME4000_AO_03_FIFO_REG;
ao_context->single_reg =
info->me4000_regbase + ME4000_AO_03_SINGLE_REG;
ao_context->timer_reg =
info->me4000_regbase + ME4000_AO_03_TIMER_REG;
ao_context->irq_status_reg =
info->me4000_regbase + ME4000_IRQ_STATUS_REG;
ao_context->preload_reg =
info->me4000_regbase + ME4000_AO_LOADSETREG_XX;
break;
default:
break;
}
if (info->board_p->ao.fifo_count) {
/* Request the interrupt line */
err =
request_irq(ao_context->irq, me4000_ao_isr,
IRQF_DISABLED | IRQF_SHARED,
ME4000_NAME, ao_context);
if (err) {
printk(KERN_ERR
"alloc_ao_contexts():Can't get interrupt line");
if (ao_context->circ_buf.buf)
kfree(ao_context->circ_buf.buf);
kfree(ao_context);
release_ao_contexts(info);
return -ENODEV;
}
}
list_add_tail(&ao_context->list, &info->ao_context_list);
ao_context->index = i;
}
return 0;
}
static void release_ao_contexts(me4000_info_t * board_info)
{
struct list_head *dac_p;
me4000_ao_context_t *ao_context;
/* Clear analog output context list */
while (!list_empty(&board_info->ao_context_list)) {
dac_p = board_info->ao_context_list.next;
ao_context = list_entry(dac_p, me4000_ao_context_t, list);
free_irq(ao_context->irq, ao_context);
if (ao_context->circ_buf.buf)
kfree(ao_context->circ_buf.buf);
list_del(dac_p);
kfree(ao_context);
}
}
static int alloc_ai_context(me4000_info_t * info)
{
me4000_ai_context_t *ai_context;
if (info->board_p->ai.count) {
ai_context = kmalloc(sizeof(me4000_ai_context_t), GFP_KERNEL);
if (!ai_context) {
printk(KERN_ERR
"ME4000:alloc_ai_context():Can't get memory for ai context\n");
return -ENOMEM;
}
memset(ai_context, 0, sizeof(me4000_ai_context_t));
info->ai_context = ai_context;
spin_lock_init(&ai_context->use_lock);
spin_lock_init(&ai_context->int_lock);
ai_context->number = 0;
ai_context->irq = info->irq;
init_waitqueue_head(&ai_context->wait_queue);
ai_context->board_info = info;
ai_context->ctrl_reg =
info->me4000_regbase + ME4000_AI_CTRL_REG;
ai_context->status_reg =
info->me4000_regbase + ME4000_AI_STATUS_REG;
ai_context->channel_list_reg =
info->me4000_regbase + ME4000_AI_CHANNEL_LIST_REG;
ai_context->data_reg =
info->me4000_regbase + ME4000_AI_DATA_REG;
ai_context->chan_timer_reg =
info->me4000_regbase + ME4000_AI_CHAN_TIMER_REG;
ai_context->chan_pre_timer_reg =
info->me4000_regbase + ME4000_AI_CHAN_PRE_TIMER_REG;
ai_context->scan_timer_low_reg =
info->me4000_regbase + ME4000_AI_SCAN_TIMER_LOW_REG;
ai_context->scan_timer_high_reg =
info->me4000_regbase + ME4000_AI_SCAN_TIMER_HIGH_REG;
ai_context->scan_pre_timer_low_reg =
info->me4000_regbase + ME4000_AI_SCAN_PRE_TIMER_LOW_REG;
ai_context->scan_pre_timer_high_reg =
info->me4000_regbase + ME4000_AI_SCAN_PRE_TIMER_HIGH_REG;
ai_context->start_reg =
info->me4000_regbase + ME4000_AI_START_REG;
ai_context->irq_status_reg =
info->me4000_regbase + ME4000_IRQ_STATUS_REG;
ai_context->sample_counter_reg =
info->me4000_regbase + ME4000_AI_SAMPLE_COUNTER_REG;
}
return 0;
}
static int alloc_dio_context(me4000_info_t * info)
{
me4000_dio_context_t *dio_context;
if (info->board_p->dio.count) {
dio_context = kmalloc(sizeof(me4000_dio_context_t), GFP_KERNEL);
if (!dio_context) {
printk(KERN_ERR
"ME4000:alloc_dio_context():Can't get memory for dio context\n");
return -ENOMEM;
}
memset(dio_context, 0, sizeof(me4000_dio_context_t));
info->dio_context = dio_context;
spin_lock_init(&dio_context->use_lock);
dio_context->board_info = info;
dio_context->dio_count = info->board_p->dio.count;
dio_context->dir_reg =
info->me4000_regbase + ME4000_DIO_DIR_REG;
dio_context->ctrl_reg =
info->me4000_regbase + ME4000_DIO_CTRL_REG;
dio_context->port_0_reg =
info->me4000_regbase + ME4000_DIO_PORT_0_REG;
dio_context->port_1_reg =
info->me4000_regbase + ME4000_DIO_PORT_1_REG;
dio_context->port_2_reg =
info->me4000_regbase + ME4000_DIO_PORT_2_REG;
dio_context->port_3_reg =
info->me4000_regbase + ME4000_DIO_PORT_3_REG;
}
return 0;
}
static int alloc_cnt_context(me4000_info_t * info)
{
me4000_cnt_context_t *cnt_context;
if (info->board_p->cnt.count) {
cnt_context = kmalloc(sizeof(me4000_cnt_context_t), GFP_KERNEL);
if (!cnt_context) {
printk(KERN_ERR
"ME4000:alloc_cnt_context():Can't get memory for cnt context\n");
return -ENOMEM;
}
memset(cnt_context, 0, sizeof(me4000_cnt_context_t));
info->cnt_context = cnt_context;
spin_lock_init(&cnt_context->use_lock);
cnt_context->board_info = info;
cnt_context->ctrl_reg =
info->timer_regbase + ME4000_CNT_CTRL_REG;
cnt_context->counter_0_reg =
info->timer_regbase + ME4000_CNT_COUNTER_0_REG;
cnt_context->counter_1_reg =
info->timer_regbase + ME4000_CNT_COUNTER_1_REG;
cnt_context->counter_2_reg =
info->timer_regbase + ME4000_CNT_COUNTER_2_REG;
}
return 0;
}
static int alloc_ext_int_context(me4000_info_t * info)
{
me4000_ext_int_context_t *ext_int_context;
if (info->board_p->cnt.count) {
ext_int_context =
kmalloc(sizeof(me4000_ext_int_context_t), GFP_KERNEL);
if (!ext_int_context) {
printk(KERN_ERR
"ME4000:alloc_ext_int_context():Can't get memory for cnt context\n");
return -ENOMEM;
}
memset(ext_int_context, 0, sizeof(me4000_ext_int_context_t));
info->ext_int_context = ext_int_context;
spin_lock_init(&ext_int_context->use_lock);
ext_int_context->board_info = info;
ext_int_context->fasync_ptr = NULL;
ext_int_context->irq = info->irq;
ext_int_context->ctrl_reg =
info->me4000_regbase + ME4000_AI_CTRL_REG;
ext_int_context->irq_status_reg =
info->me4000_regbase + ME4000_IRQ_STATUS_REG;
}
return 0;
}
static int me4000_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
int result = 0;
me4000_info_t *board_info;
CALL_PDEBUG("me4000_probe() is executed\n");
/* Allocate structure for board context */
board_info = kmalloc(sizeof(me4000_info_t), GFP_KERNEL);
if (!board_info) {
printk(KERN_ERR
"ME4000:Can't get memory for board info structure\n");
result = -ENOMEM;
goto PROBE_ERROR_1;
}
memset(board_info, 0, sizeof(me4000_info_t));
/* Add to global linked list */
list_add_tail(&board_info->list, &me4000_board_info_list);
/* Get the PCI base registers */
result = get_registers(dev, board_info);
if (result) {
printk(KERN_ERR "me4000_probe():Cannot get registers\n");
goto PROBE_ERROR_2;
}
/* Enable the device */
result = pci_enable_device(dev);
if (result < 0) {
printk(KERN_ERR "me4000_probe():Cannot enable PCI device\n");
goto PROBE_ERROR_2;
}
/* Request the PCI register regions */
result = pci_request_regions(dev, ME4000_NAME);
if (result < 0) {
printk(KERN_ERR "me4000_probe():Cannot request I/O regions\n");
goto PROBE_ERROR_2;
}
/* Initialize board info */
result = init_board_info(dev, board_info);
if (result) {
printk(KERN_ERR "me4000_probe():Cannot init baord info\n");
goto PROBE_ERROR_3;
}
/* Download the xilinx firmware */
result = me4000_xilinx_download(board_info);
if (result) {
printk(KERN_ERR "me4000_probe:Can't download firmware\n");
goto PROBE_ERROR_3;
}
/* Make a hardware reset */
result = me4000_reset_board(board_info);
if (result) {
printk(KERN_ERR "me4000_probe:Can't reset board\n");
goto PROBE_ERROR_3;
}
/* Allocate analog output context structures */
result = alloc_ao_contexts(board_info);
if (result) {
printk(KERN_ERR "me4000_probe():Cannot allocate ao contexts\n");
goto PROBE_ERROR_3;
}
/* Allocate analog input context */
result = alloc_ai_context(board_info);
if (result) {
printk(KERN_ERR "me4000_probe():Cannot allocate ai context\n");
goto PROBE_ERROR_4;
}
/* Allocate digital I/O context */
result = alloc_dio_context(board_info);
if (result) {
printk(KERN_ERR "me4000_probe():Cannot allocate dio context\n");
goto PROBE_ERROR_5;
}
/* Allocate counter context */
result = alloc_cnt_context(board_info);
if (result) {
printk(KERN_ERR "me4000_probe():Cannot allocate cnt context\n");
goto PROBE_ERROR_6;
}
/* Allocate external interrupt context */
result = alloc_ext_int_context(board_info);
if (result) {
printk(KERN_ERR
"me4000_probe():Cannot allocate ext_int context\n");
goto PROBE_ERROR_7;
}
return 0;
PROBE_ERROR_7:
kfree(board_info->cnt_context);
PROBE_ERROR_6:
kfree(board_info->dio_context);
PROBE_ERROR_5:
kfree(board_info->ai_context);
PROBE_ERROR_4:
release_ao_contexts(board_info);
PROBE_ERROR_3:
pci_release_regions(dev);
PROBE_ERROR_2:
list_del(&board_info->list);
kfree(board_info);
PROBE_ERROR_1:
return result;
}
static int me4000_xilinx_download(me4000_info_t * info)
{
int size = 0;
u32 value = 0;
int idx = 0;
unsigned char *firm;
wait_queue_head_t queue;
CALL_PDEBUG("me4000_xilinx_download() is executed\n");
init_waitqueue_head(&queue);
firm = (info->device_id == 0x4610) ? xilinx_firm_4610 : xilinx_firm;
/*
* Set PLX local interrupt 2 polarity to high.
* Interrupt is thrown by init pin of xilinx.
*/
outl(0x10, info->plx_regbase + PLX_INTCSR);
/* Set /CS and /WRITE of the Xilinx */
value = inl(info->plx_regbase + PLX_ICR);
value |= 0x100;
outl(value, info->plx_regbase + PLX_ICR);
/* Init Xilinx with CS1 */
inb(info->program_regbase + 0xC8);
/* Wait until /INIT pin is set */
udelay(20);
if (!inl(info->plx_regbase + PLX_INTCSR) & 0x20) {
printk(KERN_ERR "me4000_xilinx_download():Can't init Xilinx\n");
return -EIO;
}
/* Reset /CS and /WRITE of the Xilinx */
value = inl(info->plx_regbase + PLX_ICR);
value &= ~0x100;
outl(value, info->plx_regbase + PLX_ICR);
/* Download Xilinx firmware */
size = (firm[0] << 24) + (firm[1] << 16) + (firm[2] << 8) + firm[3];
udelay(10);
for (idx = 0; idx < size; idx++) {
outb(firm[16 + idx], info->program_regbase);
udelay(10);
/* Check if BUSY flag is low */
if (inl(info->plx_regbase + PLX_ICR) & 0x20) {
printk(KERN_ERR
"me4000_xilinx_download():Xilinx is still busy (idx = %d)\n",
idx);
return -EIO;
}
}
PDEBUG("me4000_xilinx_download():%d bytes written\n", idx);
/* If done flag is high download was successful */
if (inl(info->plx_regbase + PLX_ICR) & 0x4) {
PDEBUG("me4000_xilinx_download():Done flag is set\n");
PDEBUG("me4000_xilinx_download():Download was successful\n");
} else {
printk(KERN_ERR
"ME4000:me4000_xilinx_download():DONE flag is not set\n");
printk(KERN_ERR
"ME4000:me4000_xilinx_download():Download not succesful\n");
return -EIO;
}
/* Set /CS and /WRITE */
value = inl(info->plx_regbase + PLX_ICR);
value |= 0x100;
outl(value, info->plx_regbase + PLX_ICR);
return 0;
}
static int me4000_reset_board(me4000_info_t * info)
{
unsigned long icr;
CALL_PDEBUG("me4000_reset_board() is executed\n");
/* Make a hardware reset */
icr = me4000_inl(info->plx_regbase + PLX_ICR);
icr |= 0x40000000;
me4000_outl(icr, info->plx_regbase + PLX_ICR);
icr &= ~0x40000000;
me4000_outl(icr, info->plx_regbase + PLX_ICR);
/* Set both stop bits in the analog input control register */
me4000_outl(ME4000_AI_CTRL_BIT_IMMEDIATE_STOP | ME4000_AI_CTRL_BIT_STOP,
info->me4000_regbase + ME4000_AI_CTRL_REG);
/* Set both stop bits in the analog output control register */
me4000_outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
info->me4000_regbase + ME4000_AO_00_CTRL_REG);
me4000_outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
info->me4000_regbase + ME4000_AO_01_CTRL_REG);
me4000_outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
info->me4000_regbase + ME4000_AO_02_CTRL_REG);
me4000_outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
info->me4000_regbase + ME4000_AO_03_CTRL_REG);
/* 0x8000 to the DACs means an output voltage of 0V */
me4000_outl(0x8000, info->me4000_regbase + ME4000_AO_00_SINGLE_REG);
me4000_outl(0x8000, info->me4000_regbase + ME4000_AO_01_SINGLE_REG);
me4000_outl(0x8000, info->me4000_regbase + ME4000_AO_02_SINGLE_REG);
me4000_outl(0x8000, info->me4000_regbase + ME4000_AO_03_SINGLE_REG);
/* Enable interrupts on the PLX */
me4000_outl(0x43, info->plx_regbase + PLX_INTCSR);
/* Set the adustment register for AO demux */
me4000_outl(ME4000_AO_DEMUX_ADJUST_VALUE,
info->me4000_regbase + ME4000_AO_DEMUX_ADJUST_REG);
/* Set digital I/O direction for port 0 to output on isolated versions */
if (!(me4000_inl(info->me4000_regbase + ME4000_DIO_DIR_REG) & 0x1)) {
me4000_outl(0x1, info->me4000_regbase + ME4000_DIO_CTRL_REG);
}
return 0;
}
static int me4000_open(struct inode *inode_p, struct file *file_p)
{
int board, dev, mode;
int err = 0;
int i;
struct list_head *ptr;
me4000_info_t *board_info = NULL;
me4000_ao_context_t *ao_context = NULL;
me4000_ai_context_t *ai_context = NULL;
me4000_dio_context_t *dio_context = NULL;
me4000_cnt_context_t *cnt_context = NULL;
me4000_ext_int_context_t *ext_int_context = NULL;
CALL_PDEBUG("me4000_open() is executed\n");
/* Analog output */
if (MAJOR(inode_p->i_rdev) == me4000_ao_major_driver_no) {
board = AO_BOARD(inode_p->i_rdev);
dev = AO_PORT(inode_p->i_rdev);
mode = AO_MODE(inode_p->i_rdev);
PDEBUG("me4000_open():board = %d ao = %d mode = %d\n", board,
dev, mode);
/* Search for the board context */
for (ptr = me4000_board_info_list.next, i = 0;
ptr != &me4000_board_info_list; ptr = ptr->next, i++) {
board_info = list_entry(ptr, me4000_info_t, list);
if (i == board)
break;
}
if (ptr == &me4000_board_info_list) {
printk(KERN_ERR
"ME4000:me4000_open():Board %d not in device list\n",
board);
return -ENODEV;
}
/* Search for the dac context */
for (ptr = board_info->ao_context_list.next, i = 0;
ptr != &board_info->ao_context_list;
ptr = ptr->next, i++) {
ao_context = list_entry(ptr, me4000_ao_context_t, list);
if (i == dev)
break;
}
if (ptr == &board_info->ao_context_list) {
printk(KERN_ERR
"ME4000:me4000_open():Device %d not in device list\n",
dev);
return -ENODEV;
}
/* Check if mode is valid */
if (mode > 2) {
printk(KERN_ERR
"ME4000:me4000_open():Mode is not valid\n");
return -ENODEV;
}
/* Check if mode is valid for this AO */
if ((mode != ME4000_AO_CONV_MODE_SINGLE)
&& (dev >= board_info->board_p->ao.fifo_count)) {
printk(KERN_ERR
"ME4000:me4000_open():AO %d only in single mode available\n",
dev);
return -ENODEV;
}
/* Check if already opened */
spin_lock(&ao_context->use_lock);
if (ao_context->dac_in_use) {
printk(KERN_ERR
"ME4000:me4000_open():AO %d already in use\n",
dev);
spin_unlock(&ao_context->use_lock);
return -EBUSY;
}
ao_context->dac_in_use = 1;
spin_unlock(&ao_context->use_lock);
ao_context->mode = mode;
/* Hold the context in private data */
file_p->private_data = ao_context;
/* Set file operations pointer */
file_p->f_op = me4000_ao_fops_array[mode];
err = me4000_ao_prepare(ao_context);
if (err) {
ao_context->dac_in_use = 0;
return 1;
}
}
/* Analog input */
else if (MAJOR(inode_p->i_rdev) == me4000_ai_major_driver_no) {
board = AI_BOARD(inode_p->i_rdev);
mode = AI_MODE(inode_p->i_rdev);
PDEBUG("me4000_open():ai board = %d mode = %d\n", board, mode);
/* Search for the board context */
for (ptr = me4000_board_info_list.next, i = 0;
ptr != &me4000_board_info_list; ptr = ptr->next, i++) {
board_info = list_entry(ptr, me4000_info_t, list);
if (i == board)
break;
}
if (ptr == &me4000_board_info_list) {
printk(KERN_ERR
"ME4000:me4000_open():Board %d not in device list\n",
board);
return -ENODEV;
}
ai_context = board_info->ai_context;
/* Check if mode is valid */
if (mode > 5) {
printk(KERN_ERR
"ME4000:me4000_open():Mode is not valid\n");
return -EINVAL;
}
/* Check if already opened */
spin_lock(&ai_context->use_lock);
if (ai_context->in_use) {
printk(KERN_ERR
"ME4000:me4000_open():AI already in use\n");
spin_unlock(&ai_context->use_lock);
return -EBUSY;
}
ai_context->in_use = 1;
spin_unlock(&ai_context->use_lock);
ai_context->mode = mode;
/* Hold the context in private data */
file_p->private_data = ai_context;
/* Set file operations pointer */
file_p->f_op = me4000_ai_fops_array[mode];
/* Prepare analog input */
me4000_ai_prepare(ai_context);
}
/* Digital I/O */
else if (MAJOR(inode_p->i_rdev) == me4000_dio_major_driver_no) {
board = DIO_BOARD(inode_p->i_rdev);
dev = 0;
mode = 0;
PDEBUG("me4000_open():board = %d\n", board);
/* Search for the board context */
for (ptr = me4000_board_info_list.next;
ptr != &me4000_board_info_list; ptr = ptr->next) {
board_info = list_entry(ptr, me4000_info_t, list);
if (board_info->board_count == board)
break;
}
if (ptr == &me4000_board_info_list) {
printk(KERN_ERR
"ME4000:me4000_open():Board %d not in device list\n",
board);
return -ENODEV;
}
/* Search for the dio context */
dio_context = board_info->dio_context;
/* Check if already opened */
spin_lock(&dio_context->use_lock);
if (dio_context->in_use) {
printk(KERN_ERR
"ME4000:me4000_open():DIO already in use\n");
spin_unlock(&dio_context->use_lock);
return -EBUSY;
}
dio_context->in_use = 1;
spin_unlock(&dio_context->use_lock);
/* Hold the context in private data */
file_p->private_data = dio_context;
/* Set file operations pointer to single functions */
file_p->f_op = &me4000_dio_fops;
//me4000_dio_reset(dio_context);
}
/* Counters */
else if (MAJOR(inode_p->i_rdev) == me4000_cnt_major_driver_no) {
board = CNT_BOARD(inode_p->i_rdev);
dev = 0;
mode = 0;
PDEBUG("me4000_open():board = %d\n", board);
/* Search for the board context */
for (ptr = me4000_board_info_list.next;
ptr != &me4000_board_info_list; ptr = ptr->next) {
board_info = list_entry(ptr, me4000_info_t, list);
if (board_info->board_count == board)
break;
}
if (ptr == &me4000_board_info_list) {
printk(KERN_ERR
"ME4000:me4000_open():Board %d not in device list\n",
board);
return -ENODEV;
}
/* Get the cnt context */
cnt_context = board_info->cnt_context;
/* Check if already opened */
spin_lock(&cnt_context->use_lock);
if (cnt_context->in_use) {
printk(KERN_ERR
"ME4000:me4000_open():CNT already in use\n");
spin_unlock(&cnt_context->use_lock);
return -EBUSY;
}
cnt_context->in_use = 1;
spin_unlock(&cnt_context->use_lock);
/* Hold the context in private data */
file_p->private_data = cnt_context;
/* Set file operations pointer to single functions */
file_p->f_op = &me4000_cnt_fops;
}
/* External Interrupt */
else if (MAJOR(inode_p->i_rdev) == me4000_ext_int_major_driver_no) {
board = EXT_INT_BOARD(inode_p->i_rdev);
dev = 0;
mode = 0;
PDEBUG("me4000_open():board = %d\n", board);
/* Search for the board context */
for (ptr = me4000_board_info_list.next;
ptr != &me4000_board_info_list; ptr = ptr->next) {
board_info = list_entry(ptr, me4000_info_t, list);
if (board_info->board_count == board)
break;
}
if (ptr == &me4000_board_info_list) {
printk(KERN_ERR
"ME4000:me4000_open():Board %d not in device list\n",
board);
return -ENODEV;
}
/* Get the external interrupt context */
ext_int_context = board_info->ext_int_context;
/* Check if already opened */
spin_lock(&cnt_context->use_lock);
if (ext_int_context->in_use) {
printk(KERN_ERR
"ME4000:me4000_open():External interrupt already in use\n");
spin_unlock(&ext_int_context->use_lock);
return -EBUSY;
}
ext_int_context->in_use = 1;
spin_unlock(&ext_int_context->use_lock);
/* Hold the context in private data */
file_p->private_data = ext_int_context;
/* Set file operations pointer to single functions */
file_p->f_op = &me4000_ext_int_fops;
/* Request the interrupt line */
err =
request_irq(ext_int_context->irq, me4000_ext_int_isr,
IRQF_DISABLED | IRQF_SHARED, ME4000_NAME,
ext_int_context);
if (err) {
printk(KERN_ERR
"ME4000:me4000_open():Can't get interrupt line");
ext_int_context->in_use = 0;
return -ENODEV;
}
/* Reset the counter */
me4000_ext_int_disable(ext_int_context);
} else {
printk(KERN_ERR "ME4000:me4000_open():Major number unknown\n");
return -EINVAL;
}
return 0;
}
static int me4000_release(struct inode *inode_p, struct file *file_p)
{
me4000_ao_context_t *ao_context;
me4000_ai_context_t *ai_context;
me4000_dio_context_t *dio_context;
me4000_cnt_context_t *cnt_context;
me4000_ext_int_context_t *ext_int_context;
CALL_PDEBUG("me4000_release() is executed\n");
if (MAJOR(inode_p->i_rdev) == me4000_ao_major_driver_no) {
ao_context = file_p->private_data;
/* Mark DAC as unused */
ao_context->dac_in_use = 0;
} else if (MAJOR(inode_p->i_rdev) == me4000_ai_major_driver_no) {
ai_context = file_p->private_data;
/* Reset the analog input */
me4000_ai_reset(ai_context);
/* Free the interrupt and the circular buffer */
if (ai_context->mode) {
free_irq(ai_context->irq, ai_context);
kfree(ai_context->circ_buf.buf);
ai_context->circ_buf.buf = NULL;
ai_context->circ_buf.head = 0;
ai_context->circ_buf.tail = 0;
}
/* Mark AI as unused */
ai_context->in_use = 0;
} else if (MAJOR(inode_p->i_rdev) == me4000_dio_major_driver_no) {
dio_context = file_p->private_data;
/* Mark digital I/O as unused */
dio_context->in_use = 0;
} else if (MAJOR(inode_p->i_rdev) == me4000_cnt_major_driver_no) {
cnt_context = file_p->private_data;
/* Mark counters as unused */
cnt_context->in_use = 0;
} else if (MAJOR(inode_p->i_rdev) == me4000_ext_int_major_driver_no) {
ext_int_context = file_p->private_data;
/* Disable the externel interrupt */
me4000_ext_int_disable(ext_int_context);
free_irq(ext_int_context->irq, ext_int_context);
/* Delete the fasync structure and free memory */
me4000_ext_int_fasync(0, file_p, 0);
/* Mark as unused */
ext_int_context->in_use = 0;
} else {
printk(KERN_ERR
"ME4000:me4000_release():Major number unknown\n");
return -EINVAL;
}
return 0;
}
/*------------------------------- Analog output stuff --------------------------------------*/
static int me4000_ao_prepare(me4000_ao_context_t * ao_context)
{
unsigned long flags;
CALL_PDEBUG("me4000_ao_prepare() is executed\n");
if (ao_context->mode == ME4000_AO_CONV_MODE_CONTINUOUS) {
/* Only do anything if not already in the correct mode */
unsigned long mode = me4000_inl(ao_context->ctrl_reg);
if ((mode & ME4000_AO_CONV_MODE_CONTINUOUS)
&& (mode & ME4000_AO_CTRL_BIT_ENABLE_FIFO)) {
return 0;
}
/* Stop any conversion */
me4000_ao_immediate_stop(ao_context);
/* Set the control register to default state */
spin_lock_irqsave(&ao_context->int_lock, flags);
me4000_outl(ME4000_AO_CONV_MODE_CONTINUOUS |
ME4000_AO_CTRL_BIT_ENABLE_FIFO |
ME4000_AO_CTRL_BIT_STOP |
ME4000_AO_CTRL_BIT_IMMEDIATE_STOP,
ao_context->ctrl_reg);
spin_unlock_irqrestore(&ao_context->int_lock, flags);
/* Set to fastest sample rate */
me4000_outl(65, ao_context->timer_reg);
} else if (ao_context->mode == ME4000_AO_CONV_MODE_WRAPAROUND) {
/* Only do anything if not already in the correct mode */
unsigned long mode = me4000_inl(ao_context->ctrl_reg);
if ((mode & ME4000_AO_CONV_MODE_WRAPAROUND)
&& (mode & ME4000_AO_CTRL_BIT_ENABLE_FIFO)) {
return 0;
}
/* Stop any conversion */
me4000_ao_immediate_stop(ao_context);
/* Set the control register to default state */
spin_lock_irqsave(&ao_context->int_lock, flags);
me4000_outl(ME4000_AO_CONV_MODE_WRAPAROUND |
ME4000_AO_CTRL_BIT_ENABLE_FIFO |
ME4000_AO_CTRL_BIT_STOP |
ME4000_AO_CTRL_BIT_IMMEDIATE_STOP,
ao_context->ctrl_reg);
spin_unlock_irqrestore(&ao_context->int_lock, flags);
/* Set to fastest sample rate */
me4000_outl(65, ao_context->timer_reg);
} else if (ao_context->mode == ME4000_AO_CONV_MODE_SINGLE) {
/* Only do anything if not already in the correct mode */
unsigned long mode = me4000_inl(ao_context->ctrl_reg);
if (!
(mode &
(ME4000_AO_CONV_MODE_WRAPAROUND |
ME4000_AO_CONV_MODE_CONTINUOUS))) {
return 0;
}
/* Stop any conversion */
me4000_ao_immediate_stop(ao_context);
/* Clear the control register */
spin_lock_irqsave(&ao_context->int_lock, flags);
me4000_outl(0x0, ao_context->ctrl_reg);
spin_unlock_irqrestore(&ao_context->int_lock, flags);
/* Set voltage to 0V */
me4000_outl(0x8000, ao_context->single_reg);
} else {
printk(KERN_ERR
"ME4000:me4000_ao_prepare():Invalid mode specified\n");
return -EINVAL;
}
return 0;
}
static int me4000_ao_reset(me4000_ao_context_t * ao_context)
{
u32 tmp;
wait_queue_head_t queue;
unsigned long flags;
CALL_PDEBUG("me4000_ao_reset() is executed\n");
init_waitqueue_head(&queue);
if (ao_context->mode == ME4000_AO_CONV_MODE_WRAPAROUND) {
/*
* First stop conversion of the DAC before reconfigure.
* This is essantial, cause of the state machine.
* If not stopped before configuring mode, it could
* walk in a undefined state.
*/
tmp = me4000_inl(ao_context->ctrl_reg);
tmp |= ME4000_AO_CTRL_BIT_IMMEDIATE_STOP;
me4000_outl(tmp, ao_context->ctrl_reg);
while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) {
sleep_on_timeout(&queue, 1);
}
/* Set to transparent mode */
me4000_ao_simultaneous_disable(ao_context);
/* Set to single mode in order to set default voltage */
me4000_outl(0x0, ao_context->ctrl_reg);
/* Set voltage to 0V */
me4000_outl(0x8000, ao_context->single_reg);
/* Set to fastest sample rate */
me4000_outl(65, ao_context->timer_reg);
/* Set the original mode and enable FIFO */
me4000_outl(ME4000_AO_CONV_MODE_WRAPAROUND |
ME4000_AO_CTRL_BIT_ENABLE_FIFO |
ME4000_AO_CTRL_BIT_STOP |
ME4000_AO_CTRL_BIT_IMMEDIATE_STOP,
ao_context->ctrl_reg);
} else if (ao_context->mode == ME4000_AO_CONV_MODE_CONTINUOUS) {
/*
* First stop conversion of the DAC before reconfigure.
* This is essantial, cause of the state machine.
* If not stopped before configuring mode, it could
* walk in a undefined state.
*/
spin_lock_irqsave(&ao_context->int_lock, flags);
tmp = me4000_inl(ao_context->ctrl_reg);
tmp |= ME4000_AO_CTRL_BIT_STOP;
me4000_outl(tmp, ao_context->ctrl_reg);
spin_unlock_irqrestore(&ao_context->int_lock, flags);
while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) {
sleep_on_timeout(&queue, 1);
}
/* Clear the circular buffer */
ao_context->circ_buf.head = 0;
ao_context->circ_buf.tail = 0;
/* Set to transparent mode */
me4000_ao_simultaneous_disable(ao_context);
/* Set to single mode in order to set default voltage */
spin_lock_irqsave(&ao_context->int_lock, flags);
tmp = me4000_inl(ao_context->ctrl_reg);
me4000_outl(0x0, ao_context->ctrl_reg);
/* Set voltage to 0V */
me4000_outl(0x8000, ao_context->single_reg);
/* Set to fastest sample rate */
me4000_outl(65, ao_context->timer_reg);
/* Set the original mode and enable FIFO */
me4000_outl(ME4000_AO_CONV_MODE_CONTINUOUS |
ME4000_AO_CTRL_BIT_ENABLE_FIFO |
ME4000_AO_CTRL_BIT_STOP |
ME4000_AO_CTRL_BIT_IMMEDIATE_STOP,
ao_context->ctrl_reg);
spin_unlock_irqrestore(&ao_context->int_lock, flags);
} else {
/* Set to transparent mode */
me4000_ao_simultaneous_disable(ao_context);
/* Set voltage to 0V */
me4000_outl(0x8000, ao_context->single_reg);
}
return 0;
}
static ssize_t me4000_ao_write_sing(struct file *filep, const char *buff,
size_t cnt, loff_t * offp)
{
me4000_ao_context_t *ao_context = filep->private_data;
u32 value;
const u16 *buffer = (const u16 *)buff;
CALL_PDEBUG("me4000_ao_write_sing() is executed\n");
if (cnt != 2) {
printk(KERN_ERR
"me4000_ao_write_sing():Write count is not 2\n");
return -EINVAL;
}
if (get_user(value, buffer)) {
printk(KERN_ERR
"me4000_ao_write_sing():Cannot copy data from user\n");
return -EFAULT;
}
me4000_outl(value, ao_context->single_reg);
return 2;
}
static ssize_t me4000_ao_write_wrap(struct file *filep, const char *buff,
size_t cnt, loff_t * offp)
{
me4000_ao_context_t *ao_context = filep->private_data;
size_t i;
u32 value;
u32 tmp;
const u16 *buffer = (const u16 *)buff;
size_t count = cnt / 2;
CALL_PDEBUG("me4000_ao_write_wrap() is executed\n");
/* Check if a conversion is already running */
if (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) {
printk(KERN_ERR
"ME4000:me4000_ao_write_wrap():There is already a conversion running\n");
return -EBUSY;
}
if (count > ME4000_AO_FIFO_COUNT) {
printk(KERN_ERR
"me4000_ao_write_wrap():Can't load more than %d values\n",
ME4000_AO_FIFO_COUNT);
return -ENOSPC;
}
/* Reset the FIFO */
tmp = inl(ao_context->ctrl_reg);
tmp &= ~ME4000_AO_CTRL_BIT_ENABLE_FIFO;
outl(tmp, ao_context->ctrl_reg);
tmp |= ME4000_AO_CTRL_BIT_ENABLE_FIFO;
outl(tmp, ao_context->ctrl_reg);
for (i = 0; i < count; i++) {
if (get_user(value, buffer + i)) {
printk(KERN_ERR
"me4000_ao_write_single():Cannot copy data from user\n");
return -EFAULT;
}
if (((ao_context->fifo_reg & 0xFF) == ME4000_AO_01_FIFO_REG)
|| ((ao_context->fifo_reg & 0xFF) == ME4000_AO_03_FIFO_REG))
value = value << 16;
outl(value, ao_context->fifo_reg);
}
CALL_PDEBUG("me4000_ao_write_wrap() is leaved with %d\n", i * 2);
return i * 2;
}
static ssize_t me4000_ao_write_cont(struct file *filep, const char *buff,
size_t cnt, loff_t * offp)
{
me4000_ao_context_t *ao_context = filep->private_data;
const u16 *buffer = (const u16 *)buff;
size_t count = cnt / 2;
unsigned long flags;
u32 tmp;
int c = 0;
int k = 0;
int ret = 0;
u16 svalue;
u32 lvalue;
int i;
wait_queue_head_t queue;
CALL_PDEBUG("me4000_ao_write_cont() is executed\n");
init_waitqueue_head(&queue);
/* Check count */
if (count <= 0) {
PDEBUG("me4000_ao_write_cont():Count is 0\n");
return 0;
}
if (filep->f_flags & O_APPEND) {
PDEBUG("me4000_ao_write_cont():Append data to data stream\n");
while (count > 0) {
if (filep->f_flags & O_NONBLOCK) {
if (ao_context->pipe_flag) {
printk(KERN_ERR
"ME4000:me4000_ao_write_cont():Broken pipe in nonblocking write\n");
return -EPIPE;
}
c = me4000_space_to_end(ao_context->circ_buf,
ME4000_AO_BUFFER_COUNT);
if (!c) {
PDEBUG
("me4000_ao_write_cont():Returning from nonblocking write\n");
break;
}
} else {
wait_event_interruptible(ao_context->wait_queue,
(c =
me4000_space_to_end
(ao_context->circ_buf,
ME4000_AO_BUFFER_COUNT)));
if (ao_context->pipe_flag) {
printk(KERN_ERR
"me4000_ao_write_cont():Broken pipe in blocking write\n");
return -EPIPE;
}
if (signal_pending(current)) {
printk(KERN_ERR
"me4000_ao_write_cont():Wait for free buffer interrupted from signal\n");
return -EINTR;
}
}
PDEBUG("me4000_ao_write_cont():Space to end = %d\n", c);
/* Only able to write size of free buffer or size of count */
if (count < c)
c = count;
k = 2 * c;
k -= copy_from_user(ao_context->circ_buf.buf +
ao_context->circ_buf.head, buffer,
k);
c = k / 2;
PDEBUG
("me4000_ao_write_cont():Copy %d values from user space\n",
c);
if (!c)
return -EFAULT;
ao_context->circ_buf.head =
(ao_context->circ_buf.head +
c) & (ME4000_AO_BUFFER_COUNT - 1);
buffer += c;
count -= c;
ret += c;
/* Values are now available so enable interrupts */
spin_lock_irqsave(&ao_context->int_lock, flags);
if (me4000_buf_count
(ao_context->circ_buf, ME4000_AO_BUFFER_COUNT)) {
tmp = me4000_inl(ao_context->ctrl_reg);
tmp |= ME4000_AO_CTRL_BIT_ENABLE_IRQ;
me4000_outl(tmp, ao_context->ctrl_reg);
}
spin_unlock_irqrestore(&ao_context->int_lock, flags);
}
/* Wait until the state machine is stopped if O_SYNC is set */
if (filep->f_flags & O_SYNC) {
while (inl(ao_context->status_reg) &
ME4000_AO_STATUS_BIT_FSM) {
interruptible_sleep_on_timeout(&queue, 1);
if (ao_context->pipe_flag) {
PDEBUG
("me4000_ao_write_cont():Broken pipe detected after sync\n");
return -EPIPE;
}
if (signal_pending(current)) {
printk(KERN_ERR
"me4000_ao_write_cont():Wait on state machine after sync interrupted\n");
return -EINTR;
}
}
}
} else {
PDEBUG("me4000_ao_write_cont():Preload DAC FIFO\n");
if ((me4000_inl(ao_context->status_reg) &
ME4000_AO_STATUS_BIT_FSM)) {
printk(KERN_ERR
"me4000_ao_write_cont():Can't Preload DAC FIFO while conversion is running\n");
return -EBUSY;
}
/* Clear the FIFO */
spin_lock_irqsave(&ao_context->int_lock, flags);
tmp = me4000_inl(ao_context->ctrl_reg);
tmp &=
~(ME4000_AO_CTRL_BIT_ENABLE_FIFO |
ME4000_AO_CTRL_BIT_ENABLE_IRQ);
me4000_outl(tmp, ao_context->ctrl_reg);
tmp |= ME4000_AO_CTRL_BIT_ENABLE_FIFO;
me4000_outl(tmp, ao_context->ctrl_reg);
spin_unlock_irqrestore(&ao_context->int_lock, flags);
/* Clear the circular buffer */
ao_context->circ_buf.head = 0;
ao_context->circ_buf.tail = 0;
/* Reset the broken pipe flag */
ao_context->pipe_flag = 0;
/* Only able to write size of fifo or count */
c = ME4000_AO_FIFO_COUNT;
if (count < c)
c = count;
PDEBUG
("me4000_ao_write_cont():Write %d values to DAC on 0x%lX\n",
c, ao_context->fifo_reg);
/* Write values to the fifo */
for (i = 0; i < c; i++) {
if (get_user(svalue, buffer))
return -EFAULT;
if (((ao_context->fifo_reg & 0xFF) ==
ME4000_AO_01_FIFO_REG)
|| ((ao_context->fifo_reg & 0xFF) ==
ME4000_AO_03_FIFO_REG)) {
lvalue = ((u32) svalue) << 16;
} else
lvalue = (u32) svalue;
outl(lvalue, ao_context->fifo_reg);
buffer++;
}
count -= c;
ret += c;
while (1) {
/* Get free buffer */
c = me4000_space_to_end(ao_context->circ_buf,
ME4000_AO_BUFFER_COUNT);
if (c == 0)
return (2 * ret);
/* Only able to write size of free buffer or size of count */
if (count < c)
c = count;
/* If count = 0 return to user */
if (c <= 0) {
PDEBUG
("me4000_ao_write_cont():Count reached 0\n");
break;
}
k = 2 * c;
k -= copy_from_user(ao_context->circ_buf.buf +
ao_context->circ_buf.head, buffer,
k);
c = k / 2;
PDEBUG
("me4000_ao_write_cont():Wrote %d values to buffer\n",
c);
if (!c)
return -EFAULT;
ao_context->circ_buf.head =
(ao_context->circ_buf.head +
c) & (ME4000_AO_BUFFER_COUNT - 1);
buffer += c;
count -= c;
ret += c;
/* If values in the buffer are available so enable interrupts */
spin_lock_irqsave(&ao_context->int_lock, flags);
if (me4000_buf_count
(ao_context->circ_buf, ME4000_AO_BUFFER_COUNT)) {
PDEBUG
("me4000_ao_write_cont():Enable Interrupts\n");
tmp = me4000_inl(ao_context->ctrl_reg);
tmp |= ME4000_AO_CTRL_BIT_ENABLE_IRQ;
me4000_outl(tmp, ao_context->ctrl_reg);
}
spin_unlock_irqrestore(&ao_context->int_lock, flags);
}
}
if (filep->f_flags & O_NONBLOCK) {
return (ret == 0) ? -EAGAIN : 2 * ret;
}
return 2 * ret;
}
static unsigned int me4000_ao_poll_cont(struct file *file_p, poll_table * wait)
{
me4000_ao_context_t *ao_context;
unsigned long mask = 0;
CALL_PDEBUG("me4000_ao_poll_cont() is executed\n");
ao_context = file_p->private_data;
poll_wait(file_p, &ao_context->wait_queue, wait);
/* Get free buffer */
if (me4000_space_to_end(ao_context->circ_buf, ME4000_AO_BUFFER_COUNT))
mask |= POLLOUT | POLLWRNORM;
CALL_PDEBUG("me4000_ao_poll_cont():Return mask %lX\n", mask);
return mask;
}
static int me4000_ao_fsync_cont(struct file *file_p, struct dentry *dentry_p,
int datasync)
{
me4000_ao_context_t *ao_context;
wait_queue_head_t queue;
CALL_PDEBUG("me4000_ao_fsync_cont() is executed\n");
ao_context = file_p->private_data;
init_waitqueue_head(&queue);
while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) {
interruptible_sleep_on_timeout(&queue, 1);
if (ao_context->pipe_flag) {
printk(KERN_ERR
"me4000_ao_fsync_cont():Broken pipe detected\n");
return -EPIPE;
}
if (signal_pending(current)) {
printk(KERN_ERR
"me4000_ao_fsync_cont():Wait on state machine interrupted\n");
return -EINTR;
}
}
return 0;
}
static int me4000_ao_ioctl_sing(struct inode *inode_p, struct file *file_p,
unsigned int service, unsigned long arg)
{
me4000_ao_context_t *ao_context;
CALL_PDEBUG("me4000_ao_ioctl_sing() is executed\n");
ao_context = file_p->private_data;
if (_IOC_TYPE(service) != ME4000_MAGIC) {
return -ENOTTY;
PDEBUG("me4000_ao_ioctl_sing():Wrong magic number\n");
}
switch (service) {
case ME4000_AO_EX_TRIG_SETUP:
return me4000_ao_ex_trig_set_edge((int *)arg, ao_context);
case ME4000_AO_EX_TRIG_ENABLE:
return me4000_ao_ex_trig_enable(ao_context);
case ME4000_AO_EX_TRIG_DISABLE:
return me4000_ao_ex_trig_disable(ao_context);
case ME4000_AO_PRELOAD:
return me4000_ao_preload(ao_context);
case ME4000_AO_PRELOAD_UPDATE:
return me4000_ao_preload_update(ao_context);
case ME4000_GET_USER_INFO:
return me4000_get_user_info((me4000_user_info_t *) arg,
ao_context->board_info);
case ME4000_AO_SIMULTANEOUS_EX_TRIG:
return me4000_ao_simultaneous_ex_trig(ao_context);
case ME4000_AO_SIMULTANEOUS_SW:
return me4000_ao_simultaneous_sw(ao_context);
case ME4000_AO_SIMULTANEOUS_DISABLE:
return me4000_ao_simultaneous_disable(ao_context);
case ME4000_AO_SIMULTANEOUS_UPDATE:
return
me4000_ao_simultaneous_update((me4000_ao_channel_list_t *)
arg, ao_context);
case ME4000_AO_EX_TRIG_TIMEOUT:
return me4000_ao_ex_trig_timeout((unsigned long *)arg,
ao_context);
case ME4000_AO_DISABLE_DO:
return me4000_ao_disable_do(ao_context);
default:
printk(KERN_ERR
"me4000_ao_ioctl_sing():Service number invalid\n");
return -ENOTTY;
}
return 0;
}
static int me4000_ao_ioctl_wrap(struct inode *inode_p, struct file *file_p,
unsigned int service, unsigned long arg)
{
me4000_ao_context_t *ao_context;
CALL_PDEBUG("me4000_ao_ioctl_wrap() is executed\n");
ao_context = file_p->private_data;
if (_IOC_TYPE(service) != ME4000_MAGIC) {
return -ENOTTY;
PDEBUG("me4000_ao_ioctl_wrap():Wrong magic number\n");
}
switch (service) {
case ME4000_AO_START:
return me4000_ao_start((unsigned long *)arg, ao_context);
case ME4000_AO_STOP:
return me4000_ao_stop(ao_context);
case ME4000_AO_IMMEDIATE_STOP:
return me4000_ao_immediate_stop(ao_context);
case ME4000_AO_RESET:
return me4000_ao_reset(ao_context);
case ME4000_AO_TIMER_SET_DIVISOR:
return me4000_ao_timer_set_divisor((u32 *) arg, ao_context);
case ME4000_AO_EX_TRIG_SETUP:
return me4000_ao_ex_trig_set_edge((int *)arg, ao_context);
case ME4000_AO_EX_TRIG_ENABLE:
return me4000_ao_ex_trig_enable(ao_context);
case ME4000_AO_EX_TRIG_DISABLE:
return me4000_ao_ex_trig_disable(ao_context);
case ME4000_GET_USER_INFO:
return me4000_get_user_info((me4000_user_info_t *) arg,
ao_context->board_info);
case ME4000_AO_FSM_STATE:
return me4000_ao_fsm_state((int *)arg, ao_context);
case ME4000_AO_ENABLE_DO:
return me4000_ao_enable_do(ao_context);
case ME4000_AO_DISABLE_DO:
return me4000_ao_disable_do(ao_context);
case ME4000_AO_SYNCHRONOUS_EX_TRIG:
return me4000_ao_synchronous_ex_trig(ao_context);
case ME4000_AO_SYNCHRONOUS_SW:
return me4000_ao_synchronous_sw(ao_context);
case ME4000_AO_SYNCHRONOUS_DISABLE:
return me4000_ao_synchronous_disable(ao_context);
default:
return -ENOTTY;
}
return 0;
}
static int me4000_ao_ioctl_cont(struct inode *inode_p, struct file *file_p,
unsigned int service, unsigned long arg)
{
me4000_ao_context_t *ao_context;
CALL_PDEBUG("me4000_ao_ioctl_cont() is executed\n");
ao_context = file_p->private_data;
if (_IOC_TYPE(service) != ME4000_MAGIC) {
return -ENOTTY;
PDEBUG("me4000_ao_ioctl_cont():Wrong magic number\n");
}
switch (service) {
case ME4000_AO_START:
return me4000_ao_start((unsigned long *)arg, ao_context);
case ME4000_AO_STOP:
return me4000_ao_stop(ao_context);
case ME4000_AO_IMMEDIATE_STOP:
return me4000_ao_immediate_stop(ao_context);
case ME4000_AO_RESET:
return me4000_ao_reset(ao_context);
case ME4000_AO_TIMER_SET_DIVISOR:
return me4000_ao_timer_set_divisor((u32 *) arg, ao_context);
case ME4000_AO_EX_TRIG_SETUP:
return me4000_ao_ex_trig_set_edge((int *)arg, ao_context);
case ME4000_AO_EX_TRIG_ENABLE:
return me4000_ao_ex_trig_enable(ao_context);
case ME4000_AO_EX_TRIG_DISABLE:
return me4000_ao_ex_trig_disable(ao_context);
case ME4000_AO_ENABLE_DO:
return me4000_ao_enable_do(ao_context);
case ME4000_AO_DISABLE_DO:
return me4000_ao_disable_do(ao_context);
case ME4000_AO_FSM_STATE:
return me4000_ao_fsm_state((int *)arg, ao_context);
case ME4000_GET_USER_INFO:
return me4000_get_user_info((me4000_user_info_t *) arg,
ao_context->board_info);
case ME4000_AO_SYNCHRONOUS_EX_TRIG:
return me4000_ao_synchronous_ex_trig(ao_context);
case ME4000_AO_SYNCHRONOUS_SW:
return me4000_ao_synchronous_sw(ao_context);
case ME4000_AO_SYNCHRONOUS_DISABLE:
return me4000_ao_synchronous_disable(ao_context);
case ME4000_AO_GET_FREE_BUFFER:
return me4000_ao_get_free_buffer((unsigned long *)arg,
ao_context);
default:
return -ENOTTY;
}
return 0;
}
static int me4000_ao_start(unsigned long *arg, me4000_ao_context_t * ao_context)
{
u32 tmp;
wait_queue_head_t queue;
unsigned long ref;
unsigned long timeout;
unsigned long flags;
CALL_PDEBUG("me4000_ao_start() is executed\n");
if (get_user(timeout, arg)) {
printk(KERN_ERR
"me4000_ao_start():Cannot copy data from user\n");
return -EFAULT;
}
init_waitqueue_head(&queue);
spin_lock_irqsave(&ao_context->int_lock, flags);
tmp = inl(ao_context->ctrl_reg);
tmp &= ~(ME4000_AO_CTRL_BIT_STOP | ME4000_AO_CTRL_BIT_IMMEDIATE_STOP);
me4000_outl(tmp, ao_context->ctrl_reg);
spin_unlock_irqrestore(&ao_context->int_lock, flags);
if ((tmp & ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG)) {
if (timeout) {
ref = jiffies;
while (!
(inl(ao_context->status_reg) &
ME4000_AO_STATUS_BIT_FSM)) {
interruptible_sleep_on_timeout(&queue, 1);
if (signal_pending(current)) {
printk(KERN_ERR
"ME4000:me4000_ao_start():Wait on start of state machine interrupted\n");
return -EINTR;
}
if (((jiffies - ref) > (timeout * HZ / USER_HZ))) { // 2.6 has diffrent definitions for HZ in user and kernel space
printk(KERN_ERR
"ME4000:me4000_ao_start():Timeout reached\n");
return -EIO;
}
}
}
} else {
me4000_outl(0x8000, ao_context->single_reg);
}
return 0;
}
static int me4000_ao_stop(me4000_ao_context_t * ao_context)
{
u32 tmp;
wait_queue_head_t queue;
unsigned long flags;
init_waitqueue_head(&queue);
CALL_PDEBUG("me4000_ao_stop() is executed\n");
/* Set the stop bit */
spin_lock_irqsave(&ao_context->int_lock, flags);
tmp = inl(ao_context->ctrl_reg);
tmp |= ME4000_AO_CTRL_BIT_STOP;
me4000_outl(tmp, ao_context->ctrl_reg);
spin_unlock_irqrestore(&ao_context->int_lock, flags);
while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) {
interruptible_sleep_on_timeout(&queue, 1);
if (signal_pending(current)) {
printk(KERN_ERR
"me4000_ao_stop():Wait on state machine after stop interrupted\n");
return -EINTR;
}
}
/* Clear the stop bit */
//tmp &= ~ME4000_AO_CTRL_BIT_STOP;
//me4000_outl(tmp, ao_context->ctrl_reg);
return 0;
}
static int me4000_ao_immediate_stop(me4000_ao_context_t * ao_context)
{
u32 tmp;
wait_queue_head_t queue;
unsigned long flags;
init_waitqueue_head(&queue);
CALL_PDEBUG("me4000_ao_immediate_stop() is executed\n");
spin_lock_irqsave(&ao_context->int_lock, flags);
tmp = inl(ao_context->ctrl_reg);
tmp |= ME4000_AO_CTRL_BIT_STOP | ME4000_AO_CTRL_BIT_IMMEDIATE_STOP;
me4000_outl(tmp, ao_context->ctrl_reg);
spin_unlock_irqrestore(&ao_context->int_lock, flags);
while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) {
interruptible_sleep_on_timeout(&queue, 1);
if (signal_pending(current)) {
printk(KERN_ERR
"me4000_ao_immediate_stop():Wait on state machine after stop interrupted\n");
return -EINTR;
}
}
/* Clear the stop bits */
//tmp &= ~(ME4000_AO_CTRL_BIT_STOP | ME4000_AO_CTRL_BIT_IMMEDIATE_STOP);
//me4000_outl(tmp, ao_context->ctrl_reg);
return 0;
}
static int me4000_ao_timer_set_divisor(u32 * arg,
me4000_ao_context_t * ao_context)
{
u32 divisor;
u32 tmp;
CALL_PDEBUG("me4000_ao_timer set_divisor() is executed\n");
if (get_user(divisor, arg))
return -EFAULT;
/* Check if the state machine is stopped */
tmp = me4000_inl(ao_context->status_reg);
if (tmp & ME4000_AO_STATUS_BIT_FSM) {
printk(KERN_ERR
"me4000_ao_timer_set_divisor():Can't set timer while DAC is running\n");
return -EBUSY;
}
PDEBUG("me4000_ao_timer set_divisor():Divisor from user = %d\n",
divisor);
/* Check if the divisor is right. ME4000_AO_MIN_TICKS is the lowest */
if (divisor < ME4000_AO_MIN_TICKS) {
printk(KERN_ERR
"ME4000:me4000_ao_timer set_divisor():Divisor to low\n");
return -EINVAL;
}
/* Fix bug in Firmware */
divisor -= 2;
PDEBUG("me4000_ao_timer set_divisor():Divisor to HW = %d\n", divisor);
/* Write the divisor */
me4000_outl(divisor, ao_context->timer_reg);
return 0;
}
static int me4000_ao_ex_trig_set_edge(int *arg,
me4000_ao_context_t * ao_context)
{
int mode;
u32 tmp;
unsigned long flags;
CALL_PDEBUG("me4000_ao_ex_trig_set_edge() is executed\n");
if (get_user(mode, arg))
return -EFAULT;
/* Check if the state machine is stopped */
tmp = me4000_inl(ao_context->status_reg);
if (tmp & ME4000_AO_STATUS_BIT_FSM) {
printk(KERN_ERR
"me4000_ao_ex_trig_set_edge():Can't set trigger while DAC is running\n");
return -EBUSY;
}
if (mode == ME4000_AO_TRIGGER_EXT_EDGE_RISING) {
spin_lock_irqsave(&ao_context->int_lock, flags);
tmp = me4000_inl(ao_context->ctrl_reg);
tmp &=
~(ME4000_AO_CTRL_BIT_EX_TRIG_EDGE |
ME4000_AO_CTRL_BIT_EX_TRIG_BOTH);
me4000_outl(tmp, ao_context->ctrl_reg);
spin_unlock_irqrestore(&ao_context->int_lock, flags);
} else if (mode == ME4000_AO_TRIGGER_EXT_EDGE_FALLING) {
spin_lock_irqsave(&ao_context->int_lock, flags);
tmp = me4000_inl(ao_context->ctrl_reg);
tmp &= ~ME4000_AO_CTRL_BIT_EX_TRIG_BOTH;
tmp |= ME4000_AO_CTRL_BIT_EX_TRIG_EDGE;
me4000_outl(tmp, ao_context->ctrl_reg);
spin_unlock_irqrestore(&ao_context->int_lock, flags);
} else if (mode == ME4000_AO_TRIGGER_EXT_EDGE_BOTH) {
spin_lock_irqsave(&ao_context->int_lock, flags);
tmp = me4000_inl(ao_context->ctrl_reg);
tmp |=
ME4000_AO_CTRL_BIT_EX_TRIG_EDGE |
ME4000_AO_CTRL_BIT_EX_TRIG_BOTH;
me4000_outl(tmp, ao_context->ctrl_reg);
spin_unlock_irqrestore(&ao_context->int_lock, flags);
} else {
printk(KERN_ERR
"me4000_ao_ex_trig_set_edge():Invalid trigger mode\n");
return -EINVAL;
}
return 0;
}
static int me4000_ao_ex_trig_enable(me4000_ao_context_t * ao_context)
{
u32 tmp;
unsigned long flags;
CALL_PDEBUG("me4000_ao_ex_trig_enable() is executed\n");
/* Check if the state machine is stopped */
tmp = me4000_inl(ao_context->status_reg);
if (tmp & ME4000_AO_STATUS_BIT_FSM) {
printk(KERN_ERR
"me4000_ao_ex_trig_enable():Can't enable trigger while DAC is running\n");
return -EBUSY;
}
spin_lock_irqsave(&ao_context->int_lock, flags);
tmp = me4000_inl(ao_context->ctrl_reg);
tmp |= ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG;
me4000_outl(tmp, ao_context->ctrl_reg);
spin_unlock_irqrestore(&ao_context->int_lock, flags);
return 0;
}
static int me4000_ao_ex_trig_disable(me4000_ao_context_t * ao_context)
{
u32 tmp;
unsigned long flags;
CALL_PDEBUG("me4000_ao_ex_trig_disable() is executed\n");
/* Check if the state machine is stopped */
tmp = me4000_inl(ao_context->status_reg);
if (tmp & ME4000_AO_STATUS_BIT_FSM) {
printk(KERN_ERR
"me4000_ao_ex_trig_disable():Can't disable trigger while DAC is running\n");
return -EBUSY;
}
spin_lock_irqsave(&ao_context->int_lock, flags);
tmp = me4000_inl(ao_context->ctrl_reg);
tmp &= ~ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG;
me4000_outl(tmp, ao_context->ctrl_reg);
spin_unlock_irqrestore(&ao_context->int_lock, flags);
return 0;
}
static int me4000_ao_simultaneous_disable(me4000_ao_context_t * ao_context)
{
u32 tmp;
CALL_PDEBUG("me4000_ao_simultaneous_disable() is executed\n");
/* Check if the state machine is stopped */
/* Be careful here because this function is called from
me4000_ao_synchronous disable */
tmp = me4000_inl(ao_context->status_reg);
if (tmp & ME4000_AO_STATUS_BIT_FSM) {
printk(KERN_ERR
"me4000_ao_simultaneous_disable():Can't disable while DAC is running\n");
return -EBUSY;
}
spin_lock(&ao_context->board_info->preload_lock);
tmp = me4000_inl(ao_context->preload_reg);
tmp &= ~(0x1 << ao_context->index); // Disable preload bit
tmp &= ~(0x1 << (ao_context->index + 16)); // Disable hw simultaneous bit
me4000_outl(tmp, ao_context->preload_reg);
spin_unlock(&ao_context->board_info->preload_lock);
return 0;
}
static int me4000_ao_simultaneous_ex_trig(me4000_ao_context_t * ao_context)
{
u32 tmp;
CALL_PDEBUG("me4000_ao_simultaneous_ex_trig() is executed\n");
spin_lock(&ao_context->board_info->preload_lock);
tmp = me4000_inl(ao_context->preload_reg);
tmp |= (0x1 << ao_context->index); // Enable preload bit
tmp |= (0x1 << (ao_context->index + 16)); // Enable hw simultaneous bit
me4000_outl(tmp, ao_context->preload_reg);
spin_unlock(&ao_context->board_info->preload_lock);
return 0;
}
static int me4000_ao_simultaneous_sw(me4000_ao_context_t * ao_context)
{
u32 tmp;
CALL_PDEBUG("me4000_ao_simultaneous_sw() is executed\n");
spin_lock(&ao_context->board_info->preload_lock);
tmp = me4000_inl(ao_context->preload_reg);
tmp |= (0x1 << ao_context->index); // Enable preload bit
tmp &= ~(0x1 << (ao_context->index + 16)); // Disable hw simultaneous bit
me4000_outl(tmp, ao_context->preload_reg);
spin_unlock(&ao_context->board_info->preload_lock);
return 0;
}
static int me4000_ao_preload(me4000_ao_context_t * ao_context)
{
CALL_PDEBUG("me4000_ao_preload() is executed\n");
return me4000_ao_simultaneous_sw(ao_context);
}
static int me4000_ao_preload_update(me4000_ao_context_t * ao_context)
{
u32 tmp;
u32 ctrl;
struct list_head *entry;
CALL_PDEBUG("me4000_ao_preload_update() is executed\n");
spin_lock(&ao_context->board_info->preload_lock);
tmp = me4000_inl(ao_context->preload_reg);
list_for_each(entry, &ao_context->board_info->ao_context_list) {
/* The channels we update must be in the following state :
- Mode A
- Hardware trigger is disabled
- Corresponding simultaneous bit is reset
*/
ctrl = me4000_inl(ao_context->ctrl_reg);
if (!
(ctrl &
(ME4000_AO_CTRL_BIT_MODE_0 | ME4000_AO_CTRL_BIT_MODE_1 |
ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG))) {
if (!
(tmp &
(0x1 <<
(((me4000_ao_context_t *) entry)->index + 16)))) {
tmp &=
~(0x1 <<
(((me4000_ao_context_t *) entry)->index));
}
}
}
me4000_outl(tmp, ao_context->preload_reg);
spin_unlock(&ao_context->board_info->preload_lock);
return 0;
}
static int me4000_ao_simultaneous_update(me4000_ao_channel_list_t * arg,
me4000_ao_context_t * ao_context)
{
int err;
int i;
u32 tmp;
me4000_ao_channel_list_t channels;
CALL_PDEBUG("me4000_ao_simultaneous_update() is executed\n");
/* Copy data from user */
err = copy_from_user(&channels, arg, sizeof(me4000_ao_channel_list_t));
if (err) {
printk(KERN_ERR
"ME4000:me4000_ao_simultaneous_update():Can't copy command\n");
return -EFAULT;
}
channels.list =
kmalloc(sizeof(unsigned long) * channels.count, GFP_KERNEL);
if (!channels.list) {
printk(KERN_ERR
"ME4000:me4000_ao_simultaneous_update():Can't get buffer\n");
return -ENOMEM;
}
memset(channels.list, 0, sizeof(unsigned long) * channels.count);
/* Copy channel list from user */
err =
copy_from_user(channels.list, arg->list,
sizeof(unsigned long) * channels.count);
if (err) {
printk(KERN_ERR
"ME4000:me4000_ao_simultaneous_update():Can't copy list\n");
kfree(channels.list);
return -EFAULT;
}
spin_lock(&ao_context->board_info->preload_lock);
tmp = me4000_inl(ao_context->preload_reg);
for (i = 0; i < channels.count; i++) {
if (channels.list[i] >
ao_context->board_info->board_p->ao.count) {
spin_unlock(&ao_context->board_info->preload_lock);
kfree(channels.list);
printk(KERN_ERR
"ME4000:me4000_ao_simultaneous_update():Invalid board number specified\n");
return -EFAULT;
}
tmp &= ~(0x1 << channels.list[i]); // Clear the preload bit
tmp &= ~(0x1 << (channels.list[i] + 16)); // Clear the hw simultaneous bit
}
me4000_outl(tmp, ao_context->preload_reg);
spin_unlock(&ao_context->board_info->preload_lock);
kfree(channels.list);
return 0;
}
static int me4000_ao_synchronous_ex_trig(me4000_ao_context_t * ao_context)
{
u32 tmp;
unsigned long flags;
CALL_PDEBUG("me4000_ao_synchronous_ex_trig() is executed\n");
/* Check if the state machine is stopped */
tmp = me4000_inl(ao_context->status_reg);
if (tmp & ME4000_AO_STATUS_BIT_FSM) {
printk(KERN_ERR
"me4000_ao_synchronous_ex_trig(): DAC is running\n");
return -EBUSY;
}
spin_lock(&ao_context->board_info->preload_lock);
tmp = me4000_inl(ao_context->preload_reg);
tmp &= ~(0x1 << ao_context->index); // Disable synchronous sw bit
tmp |= 0x1 << (ao_context->index + 16); // Enable synchronous hw bit
me4000_outl(tmp, ao_context->preload_reg);
spin_unlock(&ao_context->board_info->preload_lock);
/* Make runnable */
spin_lock_irqsave(&ao_context->int_lock, flags);
tmp = me4000_inl(ao_context->ctrl_reg);
if (tmp & (ME4000_AO_CTRL_BIT_MODE_0 | ME4000_AO_CTRL_BIT_MODE_1)) {
tmp &=
~(ME4000_AO_CTRL_BIT_STOP |
ME4000_AO_CTRL_BIT_IMMEDIATE_STOP);
me4000_outl(tmp, ao_context->ctrl_reg);
}
spin_unlock_irqrestore(&ao_context->int_lock, flags);
return 0;
}
static int me4000_ao_synchronous_sw(me4000_ao_context_t * ao_context)
{
u32 tmp;
unsigned long flags;
CALL_PDEBUG("me4000_ao_synchronous_sw() is executed\n");
/* Check if the state machine is stopped */
tmp = me4000_inl(ao_context->status_reg);
if (tmp & ME4000_AO_STATUS_BIT_FSM) {
printk(KERN_ERR "me4000_ao_synchronous_sw(): DAC is running\n");
return -EBUSY;
}
spin_lock(&ao_context->board_info->preload_lock);
tmp = me4000_inl(ao_context->preload_reg);
tmp |= 0x1 << ao_context->index; // Enable synchronous sw bit
tmp &= ~(0x1 << (ao_context->index + 16)); // Disable synchronous hw bit
me4000_outl(tmp, ao_context->preload_reg);
spin_unlock(&ao_context->board_info->preload_lock);
/* Make runnable */
spin_lock_irqsave(&ao_context->int_lock, flags);
tmp = me4000_inl(ao_context->ctrl_reg);
if (tmp & (ME4000_AO_CTRL_BIT_MODE_0 | ME4000_AO_CTRL_BIT_MODE_1)) {
tmp &=
~(ME4000_AO_CTRL_BIT_STOP |
ME4000_AO_CTRL_BIT_IMMEDIATE_STOP);
me4000_outl(tmp, ao_context->ctrl_reg);
}
spin_unlock_irqrestore(&ao_context->int_lock, flags);
return 0;
}
static int me4000_ao_synchronous_disable(me4000_ao_context_t * ao_context)
{
return me4000_ao_simultaneous_disable(ao_context);
}
static int me4000_ao_get_free_buffer(unsigned long *arg,
me4000_ao_context_t * ao_context)
{
unsigned long c;
int err;
c = me4000_buf_space(ao_context->circ_buf, ME4000_AO_BUFFER_COUNT);
err = copy_to_user(arg, &c, sizeof(unsigned long));
if (err) {
printk(KERN_ERR
"ME4000:me4000_ao_get_free_buffer():Can't copy to user space\n");
return -EFAULT;
}
return 0;
}
static int me4000_ao_ex_trig_timeout(unsigned long *arg,
me4000_ao_context_t * ao_context)
{
u32 tmp;
wait_queue_head_t queue;
unsigned long ref;
unsigned long timeout;
CALL_PDEBUG("me4000_ao_ex_trig_timeout() is executed\n");
if (get_user(timeout, arg)) {
printk(KERN_ERR
"me4000_ao_ex_trig_timeout():Cannot copy data from user\n");
return -EFAULT;
}
init_waitqueue_head(&queue);
tmp = inl(ao_context->ctrl_reg);
if ((tmp & ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG)) {
if (timeout) {
ref = jiffies;
while ((inl(ao_context->status_reg) &
ME4000_AO_STATUS_BIT_FSM)) {
interruptible_sleep_on_timeout(&queue, 1);
if (signal_pending(current)) {
printk(KERN_ERR
"ME4000:me4000_ao_ex_trig_timeout():Wait on start of state machine interrupted\n");
return -EINTR;
}
if (((jiffies - ref) > (timeout * HZ / USER_HZ))) { // 2.6 has diffrent definitions for HZ in user and kernel space
printk(KERN_ERR
"ME4000:me4000_ao_ex_trig_timeout():Timeout reached\n");
return -EIO;
}
}
} else {
while ((inl(ao_context->status_reg) &
ME4000_AO_STATUS_BIT_FSM)) {
interruptible_sleep_on_timeout(&queue, 1);
if (signal_pending(current)) {
printk(KERN_ERR
"ME4000:me4000_ao_ex_trig_timeout():Wait on start of state machine interrupted\n");
return -EINTR;
}
}
}
} else {
printk(KERN_ERR
"ME4000:me4000_ao_ex_trig_timeout():External Trigger is not enabled\n");
return -EINVAL;
}
return 0;
}
static int me4000_ao_enable_do(me4000_ao_context_t * ao_context)
{
u32 tmp;
unsigned long flags;
CALL_PDEBUG("me4000_ao_enable_do() is executed\n");
/* Only available for analog output 3 */
if (ao_context->index != 3) {
printk(KERN_ERR
"me4000_ao_enable_do():Only available for analog output 3\n");
return -ENOTTY;
}
/* Check if the state machine is stopped */
tmp = me4000_inl(ao_context->status_reg);
if (tmp & ME4000_AO_STATUS_BIT_FSM) {
printk(KERN_ERR "me4000_ao_enable_do(): DAC is running\n");
return -EBUSY;
}
/* Set the stop bit */
spin_lock_irqsave(&ao_context->int_lock, flags);
tmp = inl(ao_context->ctrl_reg);
tmp |= ME4000_AO_CTRL_BIT_ENABLE_DO;
me4000_outl(tmp, ao_context->ctrl_reg);
spin_unlock_irqrestore(&ao_context->int_lock, flags);
return 0;
}
static int me4000_ao_disable_do(me4000_ao_context_t * ao_context)
{
u32 tmp;
unsigned long flags;
CALL_PDEBUG("me4000_ao_disable_do() is executed\n");
/* Only available for analog output 3 */
if (ao_context->index != 3) {
printk(KERN_ERR
"me4000_ao_disable():Only available for analog output 3\n");
return -ENOTTY;
}
/* Check if the state machine is stopped */
tmp = me4000_inl(ao_context->status_reg);
if (tmp & ME4000_AO_STATUS_BIT_FSM) {
printk(KERN_ERR "me4000_ao_disable_do(): DAC is running\n");
return -EBUSY;
}
spin_lock_irqsave(&ao_context->int_lock, flags);
tmp = inl(ao_context->ctrl_reg);
tmp &= ~(ME4000_AO_CTRL_BIT_ENABLE_DO);
me4000_outl(tmp, ao_context->ctrl_reg);
spin_unlock_irqrestore(&ao_context->int_lock, flags);
return 0;
}
static int me4000_ao_fsm_state(int *arg, me4000_ao_context_t * ao_context)
{
unsigned long tmp;
CALL_PDEBUG("me4000_ao_fsm_state() is executed\n");
tmp =
(me4000_inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) ? 1
: 0;
if (ao_context->pipe_flag) {
printk(KERN_ERR "me4000_ao_fsm_state():Broken pipe detected\n");
return -EPIPE;
}
if (put_user(tmp, arg)) {
printk(KERN_ERR "me4000_ao_fsm_state():Cannot copy to user\n");
return -EFAULT;
}
return 0;
}
/*------------------------------- Analog input stuff --------------------------------------*/
static int me4000_ai_prepare(me4000_ai_context_t * ai_context)
{
wait_queue_head_t queue;
int err;
CALL_PDEBUG("me4000_ai_prepare() is executed\n");
init_waitqueue_head(&queue);
/* Set the new mode and stop bits */
me4000_outl(ai_context->
mode | ME4000_AI_CTRL_BIT_STOP |
ME4000_AI_CTRL_BIT_IMMEDIATE_STOP, ai_context->ctrl_reg);
/* Set the timer registers */
ai_context->chan_timer = 66;
ai_context->chan_pre_timer = 66;
ai_context->scan_timer_low = 0;
ai_context->scan_timer_high = 0;
me4000_outl(65, ai_context->chan_timer_reg);
me4000_outl(65, ai_context->chan_pre_timer_reg);
me4000_outl(0, ai_context->scan_timer_low_reg);
me4000_outl(0, ai_context->scan_timer_high_reg);
me4000_outl(0, ai_context->scan_pre_timer_low_reg);
me4000_outl(0, ai_context->scan_pre_timer_high_reg);
ai_context->channel_list_count = 0;
if (ai_context->mode) {
/* Request the interrupt line */
err =
request_irq(ai_context->irq, me4000_ai_isr,
IRQF_DISABLED | IRQF_SHARED, ME4000_NAME,
ai_context);
if (err) {
printk(KERN_ERR
"ME4000:me4000_ai_prepare():Can't get interrupt line");
return -ENODEV;
}
/* Allocate circular buffer */
ai_context->circ_buf.buf =
kmalloc(ME4000_AI_BUFFER_SIZE, GFP_KERNEL);
if (!ai_context->circ_buf.buf) {
printk(KERN_ERR
"ME4000:me4000_ai_prepare():Can't get circular buffer\n");
free_irq(ai_context->irq, ai_context);
return -ENOMEM;
}
memset(ai_context->circ_buf.buf, 0, ME4000_AI_BUFFER_SIZE);
/* Clear the circular buffer */
ai_context->circ_buf.head = 0;
ai_context->circ_buf.tail = 0;
}
return 0;
}
static int me4000_ai_reset(me4000_ai_context_t * ai_context)
{
wait_queue_head_t queue;
u32 tmp;
unsigned long flags;
CALL_PDEBUG("me4000_ai_reset() is executed\n");
init_waitqueue_head(&queue);
/*
* First stop conversion of the state machine before reconfigure.
* If not stopped before configuring mode, it could
* walk in a undefined state.
*/
spin_lock_irqsave(&ai_context->int_lock, flags);
tmp = me4000_inl(ai_context->ctrl_reg);
tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
me4000_outl(tmp, ai_context->ctrl_reg);
spin_unlock_irqrestore(&ai_context->int_lock, flags);
while (inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM) {
interruptible_sleep_on_timeout(&queue, 1);
if (signal_pending(current)) {
printk(KERN_ERR
"me4000_ai_reset():Wait on state machine after stop interrupted\n");
return -EINTR;
}
}
/* Clear the control register and set the stop bits */
spin_lock_irqsave(&ai_context->int_lock, flags);
tmp = me4000_inl(ai_context->ctrl_reg);
me4000_outl(ME4000_AI_CTRL_BIT_IMMEDIATE_STOP | ME4000_AI_CTRL_BIT_STOP,
ai_context->ctrl_reg);
spin_unlock_irqrestore(&ai_context->int_lock, flags);
/* Reset timer registers */
ai_context->chan_timer = 66;
ai_context->chan_pre_timer = 66;
ai_context->scan_timer_low = 0;
ai_context->scan_timer_high = 0;
ai_context->sample_counter = 0;
ai_context->sample_counter_reload = 0;
me4000_outl(65, ai_context->chan_timer_reg);
me4000_outl(65, ai_context->chan_pre_timer_reg);
me4000_outl(0, ai_context->scan_timer_low_reg);
me4000_outl(0, ai_context->scan_timer_high_reg);
me4000_outl(0, ai_context->scan_pre_timer_low_reg);
me4000_outl(0, ai_context->scan_pre_timer_high_reg);
me4000_outl(0, ai_context->sample_counter_reg);
ai_context->channel_list_count = 0;
/* Clear the circular buffer */
ai_context->circ_buf.head = 0;
ai_context->circ_buf.tail = 0;
return 0;
}
static int me4000_ai_ioctl_sing(struct inode *inode_p, struct file *file_p,
unsigned int service, unsigned long arg)
{
me4000_ai_context_t *ai_context;
CALL_PDEBUG("me4000_ai_ioctl_sing() is executed\n");
ai_context = file_p->private_data;
if (_IOC_TYPE(service) != ME4000_MAGIC) {
printk(KERN_ERR "me4000_ai_ioctl_sing():Wrong magic number\n");
return -ENOTTY;
}
if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) {
printk(KERN_ERR
"me4000_ai_ioctl_sing():Service number to high\n");
return -ENOTTY;
}
switch (service) {
case ME4000_AI_SINGLE:
return me4000_ai_single((me4000_ai_single_t *) arg, ai_context);
case ME4000_AI_EX_TRIG_ENABLE:
return me4000_ai_ex_trig_enable(ai_context);
case ME4000_AI_EX_TRIG_DISABLE:
return me4000_ai_ex_trig_disable(ai_context);
case ME4000_AI_EX_TRIG_SETUP:
return me4000_ai_ex_trig_setup((me4000_ai_trigger_t *) arg,
ai_context);
case ME4000_GET_USER_INFO:
return me4000_get_user_info((me4000_user_info_t *) arg,
ai_context->board_info);
case ME4000_AI_OFFSET_ENABLE:
return me4000_ai_offset_enable(ai_context);
case ME4000_AI_OFFSET_DISABLE:
return me4000_ai_offset_disable(ai_context);
case ME4000_AI_FULLSCALE_ENABLE:
return me4000_ai_fullscale_enable(ai_context);
case ME4000_AI_FULLSCALE_DISABLE:
return me4000_ai_fullscale_disable(ai_context);
case ME4000_AI_EEPROM_READ:
return me4000_eeprom_read((me4000_eeprom_t *) arg, ai_context);
case ME4000_AI_EEPROM_WRITE:
return me4000_eeprom_write((me4000_eeprom_t *) arg, ai_context);
default:
printk(KERN_ERR
"me4000_ai_ioctl_sing():Invalid service number\n");
return -ENOTTY;
}
return 0;
}
static int me4000_ai_single(me4000_ai_single_t * arg,
me4000_ai_context_t * ai_context)
{
me4000_ai_single_t cmd;
int err;
u32 tmp;
wait_queue_head_t queue;
unsigned long jiffy;
CALL_PDEBUG("me4000_ai_single() is executed\n");
init_waitqueue_head(&queue);
/* Copy data from user */
err = copy_from_user(&cmd, arg, sizeof(me4000_ai_single_t));
if (err) {
printk(KERN_ERR
"ME4000:me4000_ai_single():Can't copy from user space\n");
return -EFAULT;
}
/* Check range parameter */
switch (cmd.range) {
case ME4000_AI_LIST_RANGE_BIPOLAR_10:
case ME4000_AI_LIST_RANGE_BIPOLAR_2_5:
case ME4000_AI_LIST_RANGE_UNIPOLAR_10:
case ME4000_AI_LIST_RANGE_UNIPOLAR_2_5:
break;
default:
printk(KERN_ERR
"ME4000:me4000_ai_single():Invalid range specified\n");
return -EINVAL;
}
/* Check mode and channel number */
switch (cmd.mode) {
case ME4000_AI_LIST_INPUT_SINGLE_ENDED:
if (cmd.channel >= ai_context->board_info->board_p->ai.count) {
printk(KERN_ERR
"ME4000:me4000_ai_single():Analog input is not available\n");
return -EINVAL;
}
break;
case ME4000_AI_LIST_INPUT_DIFFERENTIAL:
if (cmd.channel >=
ai_context->board_info->board_p->ai.diff_count) {
printk(KERN_ERR
"ME4000:me4000_ai_single():Analog input is not available in differential mode\n");
return -EINVAL;
}
break;
default:
printk(KERN_ERR
"ME4000:me4000_ai_single():Invalid mode specified\n");
return -EINVAL;
}
/* Clear channel list, data fifo and both stop bits */
tmp = me4000_inl(ai_context->ctrl_reg);
tmp &=
~(ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_DATA_FIFO |
ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP);
me4000_outl(tmp, ai_context->ctrl_reg);
/* Enable channel list and data fifo */
tmp |= ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_DATA_FIFO;
me4000_outl(tmp, ai_context->ctrl_reg);
/* Generate channel list entry */
me4000_outl(cmd.channel | cmd.range | cmd.
mode | ME4000_AI_LIST_LAST_ENTRY,
ai_context->channel_list_reg);
/* Set the timer to maximum */
me4000_outl(66, ai_context->chan_timer_reg);
me4000_outl(66, ai_context->chan_pre_timer_reg);
if (tmp & ME4000_AI_CTRL_BIT_EX_TRIG) {
jiffy = jiffies;
while (!
(me4000_inl(ai_context->status_reg) &
ME4000_AI_STATUS_BIT_EF_DATA)) {
interruptible_sleep_on_timeout(&queue, 1);
if (signal_pending(current)) {
printk(KERN_ERR
"ME4000:me4000_ai_single():Wait on start of state machine interrupted\n");
return -EINTR;
}
if (((jiffies - jiffy) > (cmd.timeout * HZ / USER_HZ)) && cmd.timeout) { // 2.6 has diffrent definitions for HZ in user and kernel space
printk(KERN_ERR
"ME4000:me4000_ai_single():Timeout reached\n");
return -EIO;
}
}
} else {
/* Start conversion */
me4000_inl(ai_context->start_reg);
/* Wait until ready */
udelay(10);
if (!
(me4000_inl(ai_context->status_reg) &
ME4000_AI_STATUS_BIT_EF_DATA)) {
printk(KERN_ERR
"ME4000:me4000_ai_single():Value not available after wait\n");
return -EIO;
}
}
/* Read value from data fifo */
cmd.value = me4000_inl(ai_context->data_reg) & 0xFFFF;
/* Copy result back to user */
err = copy_to_user(arg, &cmd, sizeof(me4000_ai_single_t));
if (err) {
printk(KERN_ERR
"ME4000:me4000_ai_single():Can't copy to user space\n");
return -EFAULT;
}
return 0;
}
static int me4000_ai_ioctl_sw(struct inode *inode_p, struct file *file_p,
unsigned int service, unsigned long arg)
{
me4000_ai_context_t *ai_context;
CALL_PDEBUG("me4000_ai_ioctl_sw() is executed\n");
ai_context = file_p->private_data;
if (_IOC_TYPE(service) != ME4000_MAGIC) {
printk(KERN_ERR "me4000_ai_ioctl_sw():Wrong magic number\n");
return -ENOTTY;
}
if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) {
printk(KERN_ERR
"me4000_ai_ioctl_sw():Service number to high\n");
return -ENOTTY;
}
switch (service) {
case ME4000_AI_SC_SETUP:
return me4000_ai_sc_setup((me4000_ai_sc_t *) arg, ai_context);
case ME4000_AI_CONFIG:
return me4000_ai_config((me4000_ai_config_t *) arg, ai_context);
case ME4000_AI_START:
return me4000_ai_start(ai_context);
case ME4000_AI_STOP:
return me4000_ai_stop(ai_context);
case ME4000_AI_IMMEDIATE_STOP:
return me4000_ai_immediate_stop(ai_context);
case ME4000_AI_FSM_STATE:
return me4000_ai_fsm_state((int *)arg, ai_context);
case ME4000_GET_USER_INFO:
return me4000_get_user_info((me4000_user_info_t *) arg,
ai_context->board_info);
case ME4000_AI_EEPROM_READ:
return me4000_eeprom_read((me4000_eeprom_t *) arg, ai_context);
case ME4000_AI_EEPROM_WRITE:
return me4000_eeprom_write((me4000_eeprom_t *) arg, ai_context);
case ME4000_AI_GET_COUNT_BUFFER:
return me4000_ai_get_count_buffer((unsigned long *)arg,
ai_context);
default:
printk(KERN_ERR
"ME4000:me4000_ai_ioctl_sw():Invalid service number %d\n",
service);
return -ENOTTY;
}
return 0;
}
static int me4000_ai_ioctl_ext(struct inode *inode_p, struct file *file_p,
unsigned int service, unsigned long arg)
{
me4000_ai_context_t *ai_context;
CALL_PDEBUG("me4000_ai_ioctl_ext() is executed\n");
ai_context = file_p->private_data;
if (_IOC_TYPE(service) != ME4000_MAGIC) {
printk(KERN_ERR "me4000_ai_ioctl_ext():Wrong magic number\n");
return -ENOTTY;
}
if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) {
printk(KERN_ERR
"me4000_ai_ioctl_ext():Service number to high\n");
return -ENOTTY;
}
switch (service) {
case ME4000_AI_SC_SETUP:
return me4000_ai_sc_setup((me4000_ai_sc_t *) arg, ai_context);
case ME4000_AI_CONFIG:
return me4000_ai_config((me4000_ai_config_t *) arg, ai_context);
case ME4000_AI_START:
return me4000_ai_start_ex((unsigned long *)arg, ai_context);
case ME4000_AI_STOP:
return me4000_ai_stop(ai_context);
case ME4000_AI_IMMEDIATE_STOP:
return me4000_ai_immediate_stop(ai_context);
case ME4000_AI_EX_TRIG_ENABLE:
return me4000_ai_ex_trig_enable(ai_context);
case ME4000_AI_EX_TRIG_DISABLE:
return me4000_ai_ex_trig_disable(ai_context);
case ME4000_AI_EX_TRIG_SETUP:
return me4000_ai_ex_trig_setup((me4000_ai_trigger_t *) arg,
ai_context);
case ME4000_AI_FSM_STATE:
return me4000_ai_fsm_state((int *)arg, ai_context);
case ME4000_GET_USER_INFO:
return me4000_get_user_info((me4000_user_info_t *) arg,
ai_context->board_info);
case ME4000_AI_GET_COUNT_BUFFER:
return me4000_ai_get_count_buffer((unsigned long *)arg,
ai_context);
default:
printk(KERN_ERR
"ME4000:me4000_ai_ioctl_ext():Invalid service number %d\n",
service);
return -ENOTTY;
}
return 0;
}
static int me4000_ai_fasync(int fd, struct file *file_p, int mode)
{
me4000_ai_context_t *ai_context;
CALL_PDEBUG("me4000_ao_fasync_cont() is executed\n");
ai_context = file_p->private_data;
return fasync_helper(fd, file_p, mode, &ai_context->fasync_p);
}
static int me4000_ai_config(me4000_ai_config_t * arg,
me4000_ai_context_t * ai_context)
{
me4000_ai_config_t cmd;
u32 *list = NULL;
u32 mode;
int i;
int err;
wait_queue_head_t queue;
u64 scan;
u32 tmp;
CALL_PDEBUG("me4000_ai_config() is executed\n");
init_waitqueue_head(&queue);
/* Check if conversion is stopped */
if (inl(ai_context->ctrl_reg) & ME4000_AI_STATUS_BIT_FSM) {
printk(KERN_ERR
"ME4000:me4000_ai_config():Conversion is not stopped\n");
err = -EBUSY;
goto AI_CONFIG_ERR;
}
/* Copy data from user */
err = copy_from_user(&cmd, arg, sizeof(me4000_ai_config_t));
if (err) {
printk(KERN_ERR
"ME4000:me4000_ai_config():Can't copy from user space\n");
err = -EFAULT;
goto AI_CONFIG_ERR;
}
PDEBUG
("me4000_ai_config():chan = %ld, pre_chan = %ld, scan_low = %ld, scan_high = %ld, count = %ld\n",
cmd.timer.chan, cmd.timer.pre_chan, cmd.timer.scan_low,
cmd.timer.scan_high, cmd.channel_list.count);
/* Check whether sample and hold is available for this board */
if (cmd.sh) {
if (!ai_context->board_info->board_p->ai.sh_count) {
printk(KERN_ERR
"ME4000:me4000_ai_config():Sample and Hold is not available for this board\n");
err = -ENODEV;
goto AI_CONFIG_ERR;
}
}
/* Check the channel list size */
if (cmd.channel_list.count > ME4000_AI_CHANNEL_LIST_COUNT) {
printk(KERN_ERR
"me4000_ai_config():Channel list is to large\n");
err = -EINVAL;
goto AI_CONFIG_ERR;
}
/* Copy channel list from user */
list = kmalloc(sizeof(u32) * cmd.channel_list.count, GFP_KERNEL);
if (!list) {
printk(KERN_ERR
"ME4000:me4000_ai_config():Can't get memory for channel list\n");
err = -ENOMEM;
goto AI_CONFIG_ERR;
}
err =
copy_from_user(list, cmd.channel_list.list,
sizeof(u32) * cmd.channel_list.count);
if (err) {
printk(KERN_ERR
"ME4000:me4000_ai_config():Can't copy from user space\n");
err = -EFAULT;
goto AI_CONFIG_ERR;
}
/* Check if last entry bit is set */
if (!(list[cmd.channel_list.count - 1] & ME4000_AI_LIST_LAST_ENTRY)) {
printk(KERN_WARNING
"me4000_ai_config():Last entry bit is not set\n");
list[cmd.channel_list.count - 1] |= ME4000_AI_LIST_LAST_ENTRY;
}
/* Check whether mode is equal for all entries */
mode = list[0] & 0x20;
for (i = 0; i < cmd.channel_list.count; i++) {
if ((list[i] & 0x20) != mode) {
printk(KERN_ERR
"ME4000:me4000_ai_config():Mode is not equal for all entries\n");
err = -EINVAL;
goto AI_CONFIG_ERR;
}
}
/* Check whether channels are available for this mode */
if (mode == ME4000_AI_LIST_INPUT_SINGLE_ENDED) {
for (i = 0; i < cmd.channel_list.count; i++) {
if ((list[i] & 0x1F) >=
ai_context->board_info->board_p->ai.count) {
printk(KERN_ERR
"ME4000:me4000_ai_config():Channel is not available for single ended\n");
err = -EINVAL;
goto AI_CONFIG_ERR;
}
}
} else if (mode == ME4000_AI_LIST_INPUT_DIFFERENTIAL) {
for (i = 0; i < cmd.channel_list.count; i++) {
if ((list[i] & 0x1F) >=
ai_context->board_info->board_p->ai.diff_count) {
printk(KERN_ERR
"ME4000:me4000_ai_config():Channel is not available for differential\n");
err = -EINVAL;
goto AI_CONFIG_ERR;
}
}
}
/* Check if bipolar is set for all entries when in differential mode */
if (mode == ME4000_AI_LIST_INPUT_DIFFERENTIAL) {
for (i = 0; i < cmd.channel_list.count; i++) {
if ((list[i] & 0xC0) != ME4000_AI_LIST_RANGE_BIPOLAR_10
&& (list[i] & 0xC0) !=
ME4000_AI_LIST_RANGE_BIPOLAR_2_5) {
printk(KERN_ERR
"ME4000:me4000_ai_config():Bipolar is not selected in differential mode\n");
err = -EINVAL;
goto AI_CONFIG_ERR;
}
}
}
if (ai_context->mode != ME4000_AI_ACQ_MODE_EXT_SINGLE_VALUE) {
/* Check for minimum channel divisor */
if (cmd.timer.chan < ME4000_AI_MIN_TICKS) {
printk(KERN_ERR
"ME4000:me4000_ai_config():Channel timer divisor is to low\n");
err = -EINVAL;
goto AI_CONFIG_ERR;
}
/* Check if minimum channel divisor is adjusted when sample and hold is activated */
if ((cmd.sh) && (cmd.timer.chan != ME4000_AI_MIN_TICKS)) {
printk(KERN_ERR
"ME4000:me4000_ai_config():Channel timer divisor must be at minimum when sample and hold is activated\n");
err = -EINVAL;
goto AI_CONFIG_ERR;
}
/* Check for minimum channel pre divisor */
if (cmd.timer.pre_chan < ME4000_AI_MIN_TICKS) {
printk(KERN_ERR
"ME4000:me4000_ai_config():Channel pre timer divisor is to low\n");
err = -EINVAL;
goto AI_CONFIG_ERR;
}
/* Write the channel timers */
me4000_outl(cmd.timer.chan - 1, ai_context->chan_timer_reg);
me4000_outl(cmd.timer.pre_chan - 1,
ai_context->chan_pre_timer_reg);
/* Save the timer values in the board context */
ai_context->chan_timer = cmd.timer.chan;
ai_context->chan_pre_timer = cmd.timer.pre_chan;
if (ai_context->mode != ME4000_AI_ACQ_MODE_EXT_SINGLE_CHANLIST) {
/* Check for scan timer divisor */
scan =
(u64) cmd.timer.scan_low | ((u64) cmd.timer.
scan_high << 32);
if (scan != 0) {
if (scan <
cmd.channel_list.count * cmd.timer.chan +
1) {
printk(KERN_ERR
"ME4000:me4000_ai_config():Scan timer divisor is to low\n");
err = -EINVAL;
goto AI_CONFIG_ERR;
}
}
/* Write the scan timers */
if (scan != 0) {
scan--;
tmp = (u32) (scan & 0xFFFFFFFF);
me4000_outl(tmp,
ai_context->scan_timer_low_reg);
tmp = (u32) ((scan >> 32) & 0xFFFFFFFF);
me4000_outl(tmp,
ai_context->scan_timer_high_reg);
scan =
scan - (cmd.timer.chan - 1) +
(cmd.timer.pre_chan - 1);
tmp = (u32) (scan & 0xFFFFFFFF);
me4000_outl(tmp,
ai_context->scan_pre_timer_low_reg);
tmp = (u32) ((scan >> 32) & 0xFFFFFFFF);
me4000_outl(tmp,
ai_context->
scan_pre_timer_high_reg);
} else {
me4000_outl(0x0,
ai_context->scan_timer_low_reg);
me4000_outl(0x0,
ai_context->scan_timer_high_reg);
me4000_outl(0x0,
ai_context->scan_pre_timer_low_reg);
me4000_outl(0x0,
ai_context->
scan_pre_timer_high_reg);
}
ai_context->scan_timer_low = cmd.timer.scan_low;
ai_context->scan_timer_high = cmd.timer.scan_high;
}
}
/* Clear the channel list */
tmp = me4000_inl(ai_context->ctrl_reg);
tmp &= ~ME4000_AI_CTRL_BIT_CHANNEL_FIFO;
me4000_outl(tmp, ai_context->ctrl_reg);
tmp |= ME4000_AI_CTRL_BIT_CHANNEL_FIFO;
me4000_outl(tmp, ai_context->ctrl_reg);
/* Write the channel list */
for (i = 0; i < cmd.channel_list.count; i++) {
me4000_outl(list[i], ai_context->channel_list_reg);
}
/* Setup sample and hold */
if (cmd.sh) {
tmp |= ME4000_AI_CTRL_BIT_SAMPLE_HOLD;
me4000_outl(tmp, ai_context->ctrl_reg);
} else {
tmp &= ~ME4000_AI_CTRL_BIT_SAMPLE_HOLD;
me4000_outl(tmp, ai_context->ctrl_reg);
}
/* Save the channel list size in the board context */
ai_context->channel_list_count = cmd.channel_list.count;
kfree(list);
return 0;
AI_CONFIG_ERR:
/* Reset the timers */
ai_context->chan_timer = 66;
ai_context->chan_pre_timer = 66;
ai_context->scan_timer_low = 0;
ai_context->scan_timer_high = 0;
me4000_outl(65, ai_context->chan_timer_reg);
me4000_outl(65, ai_context->chan_pre_timer_reg);
me4000_outl(0, ai_context->scan_timer_high_reg);
me4000_outl(0, ai_context->scan_timer_low_reg);
me4000_outl(0, ai_context->scan_pre_timer_high_reg);
me4000_outl(0, ai_context->scan_pre_timer_low_reg);
ai_context->channel_list_count = 0;
tmp = me4000_inl(ai_context->ctrl_reg);
tmp &=
~(ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_SAMPLE_HOLD);
if (list)
kfree(list);
return err;
}
static int ai_common_start(me4000_ai_context_t * ai_context)
{
u32 tmp;
CALL_PDEBUG("ai_common_start() is executed\n");
tmp = me4000_inl(ai_context->ctrl_reg);
/* Check if conversion is stopped */
if (tmp & ME4000_AI_STATUS_BIT_FSM) {
printk(KERN_ERR
"ME4000:ai_common_start():Conversion is not stopped\n");
return -EBUSY;
}
/* Clear data fifo, disable all interrupts, clear sample counter reload */
tmp &= ~(ME4000_AI_CTRL_BIT_DATA_FIFO | ME4000_AI_CTRL_BIT_LE_IRQ |
ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ |
ME4000_AI_CTRL_BIT_SC_RELOAD);
me4000_outl(tmp, ai_context->ctrl_reg);
/* Clear circular buffer */
ai_context->circ_buf.head = 0;
ai_context->circ_buf.tail = 0;
/* Enable data fifo */
tmp |= ME4000_AI_CTRL_BIT_DATA_FIFO;
/* Determine interrupt setup */
if (ai_context->sample_counter && !ai_context->sample_counter_reload) {
/* Enable Half Full Interrupt and Sample Counter Interrupt */
tmp |= ME4000_AI_CTRL_BIT_SC_IRQ | ME4000_AI_CTRL_BIT_HF_IRQ;
} else if (ai_context->sample_counter
&& ai_context->sample_counter_reload) {
if (ai_context->sample_counter <= ME4000_AI_FIFO_COUNT / 2) {
/* Enable only Sample Counter Interrupt */
tmp |=
ME4000_AI_CTRL_BIT_SC_IRQ |
ME4000_AI_CTRL_BIT_SC_RELOAD;
} else {
/* Enable Half Full Interrupt and Sample Counter Interrupt */
tmp |=
ME4000_AI_CTRL_BIT_SC_IRQ |
ME4000_AI_CTRL_BIT_HF_IRQ |
ME4000_AI_CTRL_BIT_SC_RELOAD;
}
} else {
/* Enable only Half Full Interrupt */
tmp |= ME4000_AI_CTRL_BIT_HF_IRQ;
}
/* Clear the stop bits */
tmp &= ~(ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP);
/* Write setup to hardware */
me4000_outl(tmp, ai_context->ctrl_reg);
/* Write sample counter */
me4000_outl(ai_context->sample_counter, ai_context->sample_counter_reg);
return 0;
}
static int me4000_ai_start(me4000_ai_context_t * ai_context)
{
int err;
CALL_PDEBUG("me4000_ai_start() is executed\n");
/* Prepare Hardware */
err = ai_common_start(ai_context);
if (err)
return err;
/* Start conversion by dummy read */
me4000_inl(ai_context->start_reg);
return 0;
}
static int me4000_ai_start_ex(unsigned long *arg,
me4000_ai_context_t * ai_context)
{
int err;
wait_queue_head_t queue;
unsigned long ref;
unsigned long timeout;
CALL_PDEBUG("me4000_ai_start_ex() is executed\n");
if (get_user(timeout, arg)) {
printk(KERN_ERR
"me4000_ai_start_ex():Cannot copy data from user\n");
return -EFAULT;
}
init_waitqueue_head(&queue);
/* Prepare Hardware */
err = ai_common_start(ai_context);
if (err)
return err;
if (timeout) {
ref = jiffies;
while (!
(inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM))
{
interruptible_sleep_on_timeout(&queue, 1);
if (signal_pending(current)) {
printk(KERN_ERR
"ME4000:me4000_ai_start_ex():Wait on start of state machine interrupted\n");
return -EINTR;
}
if (((jiffies - ref) > (timeout * HZ / USER_HZ))) { // 2.6 has diffrent definitions for HZ in user and kernel space
printk(KERN_ERR
"ME4000:me4000_ai_start_ex():Timeout reached\n");
return -EIO;
}
}
} else {
while (!
(inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM))
{
interruptible_sleep_on_timeout(&queue, 1);
if (signal_pending(current)) {
printk(KERN_ERR
"ME4000:me4000_ai_start_ex():Wait on start of state machine interrupted\n");
return -EINTR;
}
}
}
return 0;
}
static int me4000_ai_stop(me4000_ai_context_t * ai_context)
{
wait_queue_head_t queue;
u32 tmp;
unsigned long flags;
CALL_PDEBUG("me4000_ai_stop() is executed\n");
init_waitqueue_head(&queue);
/* Disable irqs and clear data fifo */
spin_lock_irqsave(&ai_context->int_lock, flags);
tmp = me4000_inl(ai_context->ctrl_reg);
tmp &=
~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ |
ME4000_AI_CTRL_BIT_DATA_FIFO);
/* Stop conversion of the state machine */
tmp |= ME4000_AI_CTRL_BIT_STOP;
me4000_outl(tmp, ai_context->ctrl_reg);
spin_unlock_irqrestore(&ai_context->int_lock, flags);
/* Clear circular buffer */
ai_context->circ_buf.head = 0;
ai_context->circ_buf.tail = 0;
while (inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM) {
interruptible_sleep_on_timeout(&queue, 1);
if (signal_pending(current)) {
printk(KERN_ERR
"ME4000:me4000_ai_stop():Wait on state machine after stop interrupted\n");
return -EINTR;
}
}
return 0;
}
static int me4000_ai_immediate_stop(me4000_ai_context_t * ai_context)
{
wait_queue_head_t queue;
u32 tmp;
unsigned long flags;
CALL_PDEBUG("me4000_ai_stop() is executed\n");
init_waitqueue_head(&queue);
/* Disable irqs and clear data fifo */
spin_lock_irqsave(&ai_context->int_lock, flags);
tmp = me4000_inl(ai_context->ctrl_reg);
tmp &=
~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ |
ME4000_AI_CTRL_BIT_DATA_FIFO);
/* Stop conversion of the state machine */
tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
me4000_outl(tmp, ai_context->ctrl_reg);
spin_unlock_irqrestore(&ai_context->int_lock, flags);
/* Clear circular buffer */
ai_context->circ_buf.head = 0;
ai_context->circ_buf.tail = 0;
while (inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM) {
interruptible_sleep_on_timeout(&queue, 1);
if (signal_pending(current)) {
printk(KERN_ERR
"ME4000:me4000_ai_stop():Wait on state machine after stop interrupted\n");
return -EINTR;
}
}
return 0;
}
static int me4000_ai_ex_trig_enable(me4000_ai_context_t * ai_context)
{
u32 tmp;
unsigned long flags;
CALL_PDEBUG("me4000_ai_ex_trig_enable() is executed\n");
spin_lock_irqsave(&ai_context->int_lock, flags);
tmp = me4000_inl(ai_context->ctrl_reg);
tmp |= ME4000_AI_CTRL_BIT_EX_TRIG;
me4000_outl(tmp, ai_context->ctrl_reg);
spin_unlock_irqrestore(&ai_context->int_lock, flags);
return 0;
}
static int me4000_ai_ex_trig_disable(me4000_ai_context_t * ai_context)
{
u32 tmp;
unsigned long flags;
CALL_PDEBUG("me4000_ai_ex_trig_disable() is executed\n");
spin_lock_irqsave(&ai_context->int_lock, flags);
tmp = me4000_inl(ai_context->ctrl_reg);
tmp &= ~ME4000_AI_CTRL_BIT_EX_TRIG;
me4000_outl(tmp, ai_context->ctrl_reg);
spin_unlock_irqrestore(&ai_context->int_lock, flags);
return 0;
}
static int me4000_ai_ex_trig_setup(me4000_ai_trigger_t * arg,
me4000_ai_context_t * ai_context)
{
me4000_ai_trigger_t cmd;
int err;
u32 tmp;
unsigned long flags;
CALL_PDEBUG("me4000_ai_ex_trig_setup() is executed\n");
/* Copy data from user */
err = copy_from_user(&cmd, arg, sizeof(me4000_ai_trigger_t));
if (err) {
printk(KERN_ERR
"ME4000:me4000_ai_ex_trig_setup():Can't copy from user space\n");
return -EFAULT;
}
spin_lock_irqsave(&ai_context->int_lock, flags);
tmp = me4000_inl(ai_context->ctrl_reg);
if (cmd.mode == ME4000_AI_TRIGGER_EXT_DIGITAL) {
tmp &= ~ME4000_AI_CTRL_BIT_EX_TRIG_ANALOG;
} else if (cmd.mode == ME4000_AI_TRIGGER_EXT_ANALOG) {
if (!ai_context->board_info->board_p->ai.ex_trig_analog) {
printk(KERN_ERR
"ME4000:me4000_ai_ex_trig_setup():No analog trigger available\n");
return -EINVAL;
}
tmp |= ME4000_AI_CTRL_BIT_EX_TRIG_ANALOG;
} else {
spin_unlock_irqrestore(&ai_context->int_lock, flags);
printk(KERN_ERR
"ME4000:me4000_ai_ex_trig_setup():Invalid trigger mode specified\n");
return -EINVAL;
}
if (cmd.edge == ME4000_AI_TRIGGER_EXT_EDGE_RISING) {
tmp &=
~(ME4000_AI_CTRL_BIT_EX_TRIG_BOTH |
ME4000_AI_CTRL_BIT_EX_TRIG_FALLING);
} else if (cmd.edge == ME4000_AI_TRIGGER_EXT_EDGE_FALLING) {
tmp |= ME4000_AI_CTRL_BIT_EX_TRIG_FALLING;
tmp &= ~ME4000_AI_CTRL_BIT_EX_TRIG_BOTH;
} else if (cmd.edge == ME4000_AI_TRIGGER_EXT_EDGE_BOTH) {
tmp |=
ME4000_AI_CTRL_BIT_EX_TRIG_BOTH |
ME4000_AI_CTRL_BIT_EX_TRIG_FALLING;
} else {
spin_unlock_irqrestore(&ai_context->int_lock, flags);
printk(KERN_ERR
"ME4000:me4000_ai_ex_trig_setup():Invalid trigger edge specified\n");
return -EINVAL;
}
me4000_outl(tmp, ai_context->ctrl_reg);
spin_unlock_irqrestore(&ai_context->int_lock, flags);
return 0;
}
static int me4000_ai_sc_setup(me4000_ai_sc_t * arg,
me4000_ai_context_t * ai_context)
{
me4000_ai_sc_t cmd;
int err;
CALL_PDEBUG("me4000_ai_sc_setup() is executed\n");
/* Copy data from user */
err = copy_from_user(&cmd, arg, sizeof(me4000_ai_sc_t));
if (err) {
printk(KERN_ERR
"ME4000:me4000_ai_sc_setup():Can't copy from user space\n");
return -EFAULT;
}
ai_context->sample_counter = cmd.value;
ai_context->sample_counter_reload = cmd.reload;
return 0;
}
static ssize_t me4000_ai_read(struct file *filep, char *buff, size_t cnt,
loff_t * offp)
{
me4000_ai_context_t *ai_context = filep->private_data;
s16 *buffer = (s16 *) buff;
size_t count = cnt / 2;
unsigned long flags;
int tmp;
int c = 0;
int k = 0;
int ret = 0;
wait_queue_t wait;
CALL_PDEBUG("me4000_ai_read() is executed\n");
init_waitqueue_entry(&wait, current);
/* Check count */
if (count <= 0) {
PDEBUG("me4000_ai_read():Count is 0\n");
return 0;
}
while (count > 0) {
if (filep->f_flags & O_NONBLOCK) {
c = me4000_values_to_end(ai_context->circ_buf,
ME4000_AI_BUFFER_COUNT);
if (!c) {
PDEBUG
("me4000_ai_read():Returning from nonblocking read\n");
break;
}
} else {
/* Check if conversion is still running */
if (!
(me4000_inl(ai_context->status_reg) &
ME4000_AI_STATUS_BIT_FSM)) {
printk(KERN_ERR
"ME4000:me4000_ai_read():Conversion interrupted\n");
return -EPIPE;
}
wait_event_interruptible(ai_context->wait_queue,
(me4000_values_to_end
(ai_context->circ_buf,
ME4000_AI_BUFFER_COUNT)));
if (signal_pending(current)) {
printk(KERN_ERR
"ME4000:me4000_ai_read():Wait on values interrupted from signal\n");
return -EINTR;
}
}
/* Only read count values or as much as available */
c = me4000_values_to_end(ai_context->circ_buf,
ME4000_AI_BUFFER_COUNT);
PDEBUG("me4000_ai_read():%d values to end\n", c);
if (count < c)
c = count;
PDEBUG("me4000_ai_read():Copy %d values to user space\n", c);
k = 2 * c;
k -= copy_to_user(buffer,
ai_context->circ_buf.buf +
ai_context->circ_buf.tail, k);
c = k / 2;
if (!c) {
printk(KERN_ERR
"ME4000:me4000_ai_read():Cannot copy new values to user\n");
return -EFAULT;
}
ai_context->circ_buf.tail =
(ai_context->circ_buf.tail + c) & (ME4000_AI_BUFFER_COUNT -
1);
buffer += c;
count -= c;
ret += c;
spin_lock_irqsave(&ai_context->int_lock, flags);
if (me4000_buf_space
(ai_context->circ_buf, ME4000_AI_BUFFER_COUNT)) {
tmp = me4000_inl(ai_context->ctrl_reg);
/* Determine interrupt setup */
if (ai_context->sample_counter
&& !ai_context->sample_counter_reload) {
/* Enable Half Full Interrupt and Sample Counter Interrupt */
tmp |=
ME4000_AI_CTRL_BIT_SC_IRQ |
ME4000_AI_CTRL_BIT_HF_IRQ;
} else if (ai_context->sample_counter
&& ai_context->sample_counter_reload) {
if (ai_context->sample_counter <
ME4000_AI_FIFO_COUNT / 2) {
/* Enable only Sample Counter Interrupt */
tmp |= ME4000_AI_CTRL_BIT_SC_IRQ;
} else {
/* Enable Half Full Interrupt and Sample Counter Interrupt */
tmp |=
ME4000_AI_CTRL_BIT_SC_IRQ |
ME4000_AI_CTRL_BIT_HF_IRQ;
}
} else {
/* Enable only Half Full Interrupt */
tmp |= ME4000_AI_CTRL_BIT_HF_IRQ;
}
me4000_outl(tmp, ai_context->ctrl_reg);
}
spin_unlock_irqrestore(&ai_context->int_lock, flags);
}
/* Check if conversion is still running */
if (!(me4000_inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM)) {
printk(KERN_ERR
"ME4000:me4000_ai_read():Conversion not running after complete read\n");
return -EPIPE;
}
if (filep->f_flags & O_NONBLOCK) {
return (k == 0) ? -EAGAIN : 2 * ret;
}
CALL_PDEBUG("me4000_ai_read() is leaved\n");
return ret * 2;
}
static unsigned int me4000_ai_poll(struct file *file_p, poll_table * wait)
{
me4000_ai_context_t *ai_context;
unsigned long mask = 0;
CALL_PDEBUG("me4000_ai_poll() is executed\n");
ai_context = file_p->private_data;
/* Register wait queue */
poll_wait(file_p, &ai_context->wait_queue, wait);
/* Get available values */
if (me4000_values_to_end(ai_context->circ_buf, ME4000_AI_BUFFER_COUNT))
mask |= POLLIN | POLLRDNORM;
PDEBUG("me4000_ai_poll():Return mask %lX\n", mask);
return mask;
}
static int me4000_ai_offset_enable(me4000_ai_context_t * ai_context)
{
unsigned long tmp;
CALL_PDEBUG("me4000_ai_offset_enable() is executed\n");
tmp = me4000_inl(ai_context->ctrl_reg);
tmp |= ME4000_AI_CTRL_BIT_OFFSET;
me4000_outl(tmp, ai_context->ctrl_reg);
return 0;
}
static int me4000_ai_offset_disable(me4000_ai_context_t * ai_context)
{
unsigned long tmp;
CALL_PDEBUG("me4000_ai_offset_disable() is executed\n");
tmp = me4000_inl(ai_context->ctrl_reg);
tmp &= ~ME4000_AI_CTRL_BIT_OFFSET;
me4000_outl(tmp, ai_context->ctrl_reg);
return 0;
}
static int me4000_ai_fullscale_enable(me4000_ai_context_t * ai_context)
{
unsigned long tmp;
CALL_PDEBUG("me4000_ai_fullscale_enable() is executed\n");
tmp = me4000_inl(ai_context->ctrl_reg);
tmp |= ME4000_AI_CTRL_BIT_FULLSCALE;
me4000_outl(tmp, ai_context->ctrl_reg);
return 0;
}
static int me4000_ai_fullscale_disable(me4000_ai_context_t * ai_context)
{
unsigned long tmp;
CALL_PDEBUG("me4000_ai_fullscale_disable() is executed\n");
tmp = me4000_inl(ai_context->ctrl_reg);
tmp &= ~ME4000_AI_CTRL_BIT_FULLSCALE;
me4000_outl(tmp, ai_context->ctrl_reg);
return 0;
}
static int me4000_ai_fsm_state(int *arg, me4000_ai_context_t * ai_context)
{
unsigned long tmp;
CALL_PDEBUG("me4000_ai_fsm_state() is executed\n");
tmp =
(me4000_inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM) ? 1
: 0;
if (put_user(tmp, arg)) {
printk(KERN_ERR "me4000_ai_fsm_state():Cannot copy to user\n");
return -EFAULT;
}
return 0;
}
static int me4000_ai_get_count_buffer(unsigned long *arg,
me4000_ai_context_t * ai_context)
{
unsigned long c;
int err;
c = me4000_buf_count(ai_context->circ_buf, ME4000_AI_BUFFER_COUNT);
err = copy_to_user(arg, &c, sizeof(unsigned long));
if (err) {
printk(KERN_ERR
"ME4000:me4000_ai_get_count_buffer():Can't copy to user space\n");
return -EFAULT;
}
return 0;
}
/*---------------------------------- EEPROM stuff ---------------------------*/
static int eeprom_write_cmd(me4000_ai_context_t * ai_context, unsigned long cmd,
int length)
{
int i;
unsigned long value;
CALL_PDEBUG("eeprom_write_cmd() is executed\n");
PDEBUG("eeprom_write_cmd():Write command 0x%08lX with length = %d\n",
cmd, length);
/* Get the ICR register and clear the related bits */
value = me4000_inl(ai_context->board_info->plx_regbase + PLX_ICR);
value &= ~(PLX_ICR_MASK_EEPROM);
me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR);
/* Raise the chip select */
value |= PLX_ICR_BIT_EEPROM_CHIP_SELECT;
me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR);
udelay(EEPROM_DELAY);
for (i = 0; i < length; i++) {
if (cmd & ((0x1 << (length - 1)) >> i)) {
value |= PLX_ICR_BIT_EEPROM_WRITE;
} else {
value &= ~PLX_ICR_BIT_EEPROM_WRITE;
}
/* Write to EEPROM */
me4000_outl(value,
ai_context->board_info->plx_regbase + PLX_ICR);
udelay(EEPROM_DELAY);
/* Raising edge of the clock */
value |= PLX_ICR_BIT_EEPROM_CLOCK_SET;
me4000_outl(value,
ai_context->board_info->plx_regbase + PLX_ICR);
udelay(EEPROM_DELAY);
/* Falling edge of the clock */
value &= ~PLX_ICR_BIT_EEPROM_CLOCK_SET;
me4000_outl(value,
ai_context->board_info->plx_regbase + PLX_ICR);
udelay(EEPROM_DELAY);
}
/* Clear the chip select */
value &= ~PLX_ICR_BIT_EEPROM_CHIP_SELECT;
me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR);
udelay(EEPROM_DELAY);
/* Wait until hardware is ready for sure */
mdelay(10);
return 0;
}
static unsigned short eeprom_read_cmd(me4000_ai_context_t * ai_context,
unsigned long cmd, int length)
{
int i;
unsigned long value;
unsigned short id = 0;
CALL_PDEBUG("eeprom_read_cmd() is executed\n");
PDEBUG("eeprom_read_cmd():Read command 0x%08lX with length = %d\n", cmd,
length);
/* Get the ICR register and clear the related bits */
value = me4000_inl(ai_context->board_info->plx_regbase + PLX_ICR);
value &= ~(PLX_ICR_MASK_EEPROM);
me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR);
/* Raise the chip select */
value |= PLX_ICR_BIT_EEPROM_CHIP_SELECT;
me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR);
udelay(EEPROM_DELAY);
/* Write the read command to the eeprom */
for (i = 0; i < length; i++) {
if (cmd & ((0x1 << (length - 1)) >> i)) {
value |= PLX_ICR_BIT_EEPROM_WRITE;
} else {
value &= ~PLX_ICR_BIT_EEPROM_WRITE;
}
me4000_outl(value,
ai_context->board_info->plx_regbase + PLX_ICR);
udelay(EEPROM_DELAY);
/* Raising edge of the clock */
value |= PLX_ICR_BIT_EEPROM_CLOCK_SET;
me4000_outl(value,
ai_context->board_info->plx_regbase + PLX_ICR);
udelay(EEPROM_DELAY);
/* Falling edge of the clock */
value &= ~PLX_ICR_BIT_EEPROM_CLOCK_SET;
me4000_outl(value,
ai_context->board_info->plx_regbase + PLX_ICR);
udelay(EEPROM_DELAY);
}
/* Read the value from the eeprom */
for (i = 0; i < 16; i++) {
/* Raising edge of the clock */
value |= PLX_ICR_BIT_EEPROM_CLOCK_SET;
me4000_outl(value,
ai_context->board_info->plx_regbase + PLX_ICR);
udelay(EEPROM_DELAY);
if (me4000_inl(ai_context->board_info->plx_regbase + PLX_ICR) &
PLX_ICR_BIT_EEPROM_READ) {
id |= (0x8000 >> i);
PDEBUG("eeprom_read_cmd():OR with 0x%04X\n",
(0x8000 >> i));
} else {
PDEBUG("eeprom_read_cmd():Dont't OR\n");
}
/* Falling edge of the clock */
value &= ~PLX_ICR_BIT_EEPROM_CLOCK_SET;
me4000_outl(value,
ai_context->board_info->plx_regbase + PLX_ICR);
udelay(EEPROM_DELAY);
}
/* Clear the chip select */
value &= ~PLX_ICR_BIT_EEPROM_CHIP_SELECT;
me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR);
udelay(EEPROM_DELAY);
return id;
}
static int me4000_eeprom_write(me4000_eeprom_t * arg,
me4000_ai_context_t * ai_context)
{
int err;
me4000_eeprom_t setup;
unsigned long cmd;
unsigned long date_high;
unsigned long date_low;
CALL_PDEBUG("me4000_eeprom_write() is executed\n");
err = copy_from_user(&setup, arg, sizeof(setup));
if (err) {
printk(KERN_ERR
"ME4000:me4000_eeprom_write():Cannot copy from user\n");
return err;
}
/* Enable writing */
eeprom_write_cmd(ai_context, ME4000_EEPROM_CMD_WRITE_ENABLE,
ME4000_EEPROM_CMD_LENGTH_WRITE_ENABLE);
/* Command for date */
date_high = (setup.date & 0xFFFF0000) >> 16;
date_low = (setup.date & 0x0000FFFF);
cmd =
ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_DATE_HIGH <<
ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
(unsigned
long)
date_high);
err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
if (err)
return err;
cmd =
ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_DATE_LOW <<
ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
(unsigned
long)
date_low);
err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
if (err)
return err;
/* Command for unipolar 10V offset */
cmd =
ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_UNI_OFFSET <<
ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
(unsigned
long)
setup.
uni_10_offset);
err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
if (err)
return err;
/* Command for unipolar 10V fullscale */
cmd =
ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_UNI_FULLSCALE <<
ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
(unsigned
long)
setup.
uni_10_fullscale);
err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
if (err)
return err;
/* Command for unipolar 2,5V offset */
cmd =
ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_UNI_OFFSET <<
ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
(unsigned
long)
setup.
uni_2_5_offset);
err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
if (err)
return err;
/* Command for unipolar 2,5V fullscale */
cmd =
ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_UNI_FULLSCALE <<
ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
(unsigned
long)
setup.
uni_2_5_fullscale);
err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
if (err)
return err;
/* Command for bipolar 10V offset */
cmd =
ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_BI_OFFSET <<
ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
(unsigned
long)
setup.
bi_10_offset);
err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
if (err)
return err;
/* Command for bipolar 10V fullscale */
cmd =
ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_BI_FULLSCALE <<
ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
(unsigned
long)
setup.
bi_10_fullscale);
err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
if (err)
return err;
/* Command for bipolar 2,5V offset */
cmd =
ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_BI_OFFSET <<
ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
(unsigned
long)
setup.
bi_2_5_offset);
err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
if (err)
return err;
/* Command for bipolar 2,5V fullscale */
cmd =
ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_BI_FULLSCALE <<
ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
(unsigned
long)
setup.
bi_2_5_fullscale);
err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
if (err)
return err;
/* Command for differential 10V offset */
cmd =
ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_DIFF_OFFSET <<
ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
(unsigned
long)
setup.
diff_10_offset);
err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
if (err)
return err;
/* Command for differential 10V fullscale */
cmd =
ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_DIFF_FULLSCALE
<< ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
(unsigned
long)
setup.
diff_10_fullscale);
err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
if (err)
return err;
/* Command for differential 2,5V offset */
cmd =
ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_DIFF_OFFSET <<
ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
(unsigned
long)
setup.
diff_2_5_offset);
err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
if (err)
return err;
/* Command for differential 2,5V fullscale */
cmd =
ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_DIFF_FULLSCALE
<< ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
(unsigned
long)
setup.
diff_2_5_fullscale);
err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
if (err)
return err;
/* Disable writing */
eeprom_write_cmd(ai_context, ME4000_EEPROM_CMD_WRITE_DISABLE,
ME4000_EEPROM_CMD_LENGTH_WRITE_DISABLE);
return 0;
}
static int me4000_eeprom_read(me4000_eeprom_t * arg,
me4000_ai_context_t * ai_context)
{
int err;
unsigned long cmd;
me4000_eeprom_t setup;
CALL_PDEBUG("me4000_eeprom_read() is executed\n");
/* Command for date */
cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_DATE_HIGH;
setup.date =
eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
setup.date <<= 16;
cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_DATE_LOW;
setup.date |=
eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
/* Command for unipolar 10V offset */
cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_UNI_OFFSET;
setup.uni_10_offset =
eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
/* Command for unipolar 10V fullscale */
cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_UNI_FULLSCALE;
setup.uni_10_fullscale =
eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
/* Command for unipolar 2,5V offset */
cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_UNI_OFFSET;
setup.uni_2_5_offset =
eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
/* Command for unipolar 2,5V fullscale */
cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_UNI_FULLSCALE;
setup.uni_2_5_fullscale =
eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
/* Command for bipolar 10V offset */
cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_BI_OFFSET;
setup.bi_10_offset =
eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
/* Command for bipolar 10V fullscale */
cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_BI_FULLSCALE;
setup.bi_10_fullscale =
eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
/* Command for bipolar 2,5V offset */
cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_BI_OFFSET;
setup.bi_2_5_offset =
eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
/* Command for bipolar 2,5V fullscale */
cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_BI_FULLSCALE;
setup.bi_2_5_fullscale =
eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
/* Command for differntial 10V offset */
cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_DIFF_OFFSET;
setup.diff_10_offset =
eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
/* Command for differential 10V fullscale */
cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_DIFF_FULLSCALE;
setup.diff_10_fullscale =
eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
/* Command for differntial 2,5V offset */
cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_DIFF_OFFSET;
setup.diff_2_5_offset =
eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
/* Command for differential 2,5V fullscale */
cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_DIFF_FULLSCALE;
setup.diff_2_5_fullscale =
eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
err = copy_to_user(arg, &setup, sizeof(setup));
if (err) {
printk(KERN_ERR
"ME4000:me4000_eeprom_read():Cannot copy to user\n");
return err;
}
return 0;
}
/*------------------------------------ DIO stuff ----------------------------------------------*/
static int me4000_dio_ioctl(struct inode *inode_p, struct file *file_p,
unsigned int service, unsigned long arg)
{
me4000_dio_context_t *dio_context;
CALL_PDEBUG("me4000_dio_ioctl() is executed\n");
dio_context = file_p->private_data;
if (_IOC_TYPE(service) != ME4000_MAGIC) {
printk(KERN_ERR "me4000_dio_ioctl():Wrong magic number\n");
return -ENOTTY;
}
if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) {
printk(KERN_ERR "me4000_dio_ioctl():Service number to high\n");
return -ENOTTY;
}
switch (service) {
case ME4000_DIO_CONFIG:
return me4000_dio_config((me4000_dio_config_t *) arg,
dio_context);
case ME4000_DIO_SET_BYTE:
return me4000_dio_set_byte((me4000_dio_byte_t *) arg,
dio_context);
case ME4000_DIO_GET_BYTE:
return me4000_dio_get_byte((me4000_dio_byte_t *) arg,
dio_context);
case ME4000_DIO_RESET:
return me4000_dio_reset(dio_context);
default:
printk(KERN_ERR
"ME4000:me4000_dio_ioctl():Invalid service number %d\n",
service);
return -ENOTTY;
}
return 0;
}
static int me4000_dio_config(me4000_dio_config_t * arg,
me4000_dio_context_t * dio_context)
{
me4000_dio_config_t cmd;
u32 tmp;
int err;
CALL_PDEBUG("me4000_dio_config() is executed\n");
/* Copy data from user */
err = copy_from_user(&cmd, arg, sizeof(me4000_dio_config_t));
if (err) {
printk(KERN_ERR
"ME4000:me4000_dio_config():Can't copy from user space\n");
return -EFAULT;
}
/* Check port parameter */
if (cmd.port >= dio_context->dio_count) {
printk(KERN_ERR
"ME4000:me4000_dio_config():Port %d is not available\n",
cmd.port);
return -EINVAL;
}
PDEBUG("me4000_dio_config(): port %d, mode %d, function %d\n", cmd.port,
cmd.mode, cmd.function);
if (cmd.port == ME4000_DIO_PORT_A) {
if (cmd.mode == ME4000_DIO_PORT_INPUT) {
/* Check if opto isolated version */
if (!(me4000_inl(dio_context->dir_reg) & 0x1)) {
printk(KERN_ERR
"ME4000:me4000_dio_config():Cannot set to input on opto isolated versions\n");
return -EIO;
}
tmp = me4000_inl(dio_context->ctrl_reg);
tmp &=
~(ME4000_DIO_CTRL_BIT_MODE_0 |
ME4000_DIO_CTRL_BIT_MODE_1);
me4000_outl(tmp, dio_context->ctrl_reg);
} else if (cmd.mode == ME4000_DIO_PORT_OUTPUT) {
tmp = me4000_inl(dio_context->ctrl_reg);
tmp &=
~(ME4000_DIO_CTRL_BIT_MODE_0 |
ME4000_DIO_CTRL_BIT_MODE_1);
tmp |= ME4000_DIO_CTRL_BIT_MODE_0;
me4000_outl(tmp, dio_context->ctrl_reg);
} else if (cmd.mode == ME4000_DIO_FIFO_LOW) {
tmp = me4000_inl(dio_context->ctrl_reg);
tmp &=
~(ME4000_DIO_CTRL_BIT_MODE_0 |
ME4000_DIO_CTRL_BIT_MODE_1 |
ME4000_DIO_CTRL_BIT_FIFO_HIGH_0);
tmp |=
ME4000_DIO_CTRL_BIT_MODE_0 |
ME4000_DIO_CTRL_BIT_MODE_1;
me4000_outl(tmp, dio_context->ctrl_reg);
} else if (cmd.mode == ME4000_DIO_FIFO_HIGH) {
tmp = me4000_inl(dio_context->ctrl_reg);
tmp |=
ME4000_DIO_CTRL_BIT_MODE_0 |
ME4000_DIO_CTRL_BIT_MODE_1 |
ME4000_DIO_CTRL_BIT_FIFO_HIGH_0;
me4000_outl(tmp, dio_context->ctrl_reg);
} else {
printk(KERN_ERR
"ME4000:me4000_dio_config():Mode %d is not available\n",
cmd.mode);
return -EINVAL;
}
} else if (cmd.port == ME4000_DIO_PORT_B) {
if (cmd.mode == ME4000_DIO_PORT_INPUT) {
/* Only do anything when TTL version is installed */
if ((me4000_inl(dio_context->dir_reg) & 0x1)) {
tmp = me4000_inl(dio_context->ctrl_reg);
tmp &=
~(ME4000_DIO_CTRL_BIT_MODE_2 |
ME4000_DIO_CTRL_BIT_MODE_3);
me4000_outl(tmp, dio_context->ctrl_reg);
}
} else if (cmd.mode == ME4000_DIO_PORT_OUTPUT) {
/* Check if opto isolated version */
if (!(me4000_inl(dio_context->dir_reg) & 0x1)) {
printk(KERN_ERR
"ME4000:me4000_dio_config():Cannot set to output on opto isolated versions\n");
return -EIO;
}
tmp = me4000_inl(dio_context->ctrl_reg);
tmp &=
~(ME4000_DIO_CTRL_BIT_MODE_2 |
ME4000_DIO_CTRL_BIT_MODE_3);
tmp |= ME4000_DIO_CTRL_BIT_MODE_2;
me4000_outl(tmp, dio_context->ctrl_reg);
} else if (cmd.mode == ME4000_DIO_FIFO_LOW) {
/* Check if opto isolated version */
if (!(me4000_inl(dio_context->dir_reg) & 0x1)) {
printk(KERN_ERR
"ME4000:me4000_dio_config():Cannot set to FIFO low output on opto isolated versions\n");
return -EIO;
}
tmp = me4000_inl(dio_context->ctrl_reg);
tmp &=
~(ME4000_DIO_CTRL_BIT_MODE_2 |
ME4000_DIO_CTRL_BIT_MODE_3 |
ME4000_DIO_CTRL_BIT_FIFO_HIGH_1);
tmp |=
ME4000_DIO_CTRL_BIT_MODE_2 |
ME4000_DIO_CTRL_BIT_MODE_3;
me4000_outl(tmp, dio_context->ctrl_reg);
} else if (cmd.mode == ME4000_DIO_FIFO_HIGH) {
/* Check if opto isolated version */
if (!(me4000_inl(dio_context->dir_reg) & 0x1)) {
printk(KERN_ERR
"ME4000:me4000_dio_config():Cannot set to FIFO high output on opto isolated versions\n");
return -EIO;
}
tmp = me4000_inl(dio_context->ctrl_reg);
tmp |=
ME4000_DIO_CTRL_BIT_MODE_2 |
ME4000_DIO_CTRL_BIT_MODE_3 |
ME4000_DIO_CTRL_BIT_FIFO_HIGH_1;
me4000_outl(tmp, dio_context->ctrl_reg);
} else {
printk(KERN_ERR
"ME4000:me4000_dio_config():Mode %d is not available\n",
cmd.mode);
return -EINVAL;
}
} else if (cmd.port == ME4000_DIO_PORT_C) {
if (cmd.mode == ME4000_DIO_PORT_INPUT) {
tmp = me4000_inl(dio_context->ctrl_reg);
tmp &=
~(ME4000_DIO_CTRL_BIT_MODE_4 |
ME4000_DIO_CTRL_BIT_MODE_5);
me4000_outl(tmp, dio_context->ctrl_reg);
} else if (cmd.mode == ME4000_DIO_PORT_OUTPUT) {
tmp = me4000_inl(dio_context->ctrl_reg);
tmp &=
~(ME4000_DIO_CTRL_BIT_MODE_4 |
ME4000_DIO_CTRL_BIT_MODE_5);
tmp |= ME4000_DIO_CTRL_BIT_MODE_4;
me4000_outl(tmp, dio_context->ctrl_reg);
} else if (cmd.mode == ME4000_DIO_FIFO_LOW) {
tmp = me4000_inl(dio_context->ctrl_reg);
tmp &=
~(ME4000_DIO_CTRL_BIT_MODE_4 |
ME4000_DIO_CTRL_BIT_MODE_5 |
ME4000_DIO_CTRL_BIT_FIFO_HIGH_2);
tmp |=
ME4000_DIO_CTRL_BIT_MODE_4 |
ME4000_DIO_CTRL_BIT_MODE_5;
me4000_outl(tmp, dio_context->ctrl_reg);
} else if (cmd.mode == ME4000_DIO_FIFO_HIGH) {
tmp = me4000_inl(dio_context->ctrl_reg);
tmp |=
ME4000_DIO_CTRL_BIT_MODE_4 |
ME4000_DIO_CTRL_BIT_MODE_5 |
ME4000_DIO_CTRL_BIT_FIFO_HIGH_2;
me4000_outl(tmp, dio_context->ctrl_reg);
} else {
printk(KERN_ERR
"ME4000:me4000_dio_config():Mode %d is not available\n",
cmd.mode);
return -EINVAL;
}
} else if (cmd.port == ME4000_DIO_PORT_D) {
if (cmd.mode == ME4000_DIO_PORT_INPUT) {
tmp = me4000_inl(dio_context->ctrl_reg);
tmp &=
~(ME4000_DIO_CTRL_BIT_MODE_6 |
ME4000_DIO_CTRL_BIT_MODE_7);
me4000_outl(tmp, dio_context->ctrl_reg);
} else if (cmd.mode == ME4000_DIO_PORT_OUTPUT) {
tmp = me4000_inl(dio_context->ctrl_reg);
tmp &=
~(ME4000_DIO_CTRL_BIT_MODE_6 |
ME4000_DIO_CTRL_BIT_MODE_7);
tmp |= ME4000_DIO_CTRL_BIT_MODE_6;
me4000_outl(tmp, dio_context->ctrl_reg);
} else if (cmd.mode == ME4000_DIO_FIFO_LOW) {
tmp = me4000_inl(dio_context->ctrl_reg);
tmp &=
~(ME4000_DIO_CTRL_BIT_MODE_6 |
ME4000_DIO_CTRL_BIT_MODE_7 |
ME4000_DIO_CTRL_BIT_FIFO_HIGH_3);
tmp |=
ME4000_DIO_CTRL_BIT_MODE_6 |
ME4000_DIO_CTRL_BIT_MODE_7;
me4000_outl(tmp, dio_context->ctrl_reg);
} else if (cmd.mode == ME4000_DIO_FIFO_HIGH) {
tmp = me4000_inl(dio_context->ctrl_reg);
tmp |=
ME4000_DIO_CTRL_BIT_MODE_6 |
ME4000_DIO_CTRL_BIT_MODE_7 |
ME4000_DIO_CTRL_BIT_FIFO_HIGH_3;
me4000_outl(tmp, dio_context->ctrl_reg);
} else {
printk(KERN_ERR
"ME4000:me4000_dio_config():Mode %d is not available\n",
cmd.mode);
return -EINVAL;
}
} else {
printk(KERN_ERR
"ME4000:me4000_dio_config():Port %d is not available\n",
cmd.port);
return -EINVAL;
}
PDEBUG("me4000_dio_config(): port %d, mode %d, function %d\n", cmd.port,
cmd.mode, cmd.function);
if ((cmd.mode == ME4000_DIO_FIFO_HIGH)
|| (cmd.mode == ME4000_DIO_FIFO_LOW)) {
tmp = me4000_inl(dio_context->ctrl_reg);
tmp &=
~(ME4000_DIO_CTRL_BIT_FUNCTION_0 |
ME4000_DIO_CTRL_BIT_FUNCTION_1);
if (cmd.function == ME4000_DIO_FUNCTION_PATTERN) {
me4000_outl(tmp, dio_context->ctrl_reg);
} else if (cmd.function == ME4000_DIO_FUNCTION_DEMUX) {
tmp |= ME4000_DIO_CTRL_BIT_FUNCTION_0;
me4000_outl(tmp, dio_context->ctrl_reg);
} else if (cmd.function == ME4000_DIO_FUNCTION_MUX) {
tmp |= ME4000_DIO_CTRL_BIT_FUNCTION_1;
me4000_outl(tmp, dio_context->ctrl_reg);
} else {
printk(KERN_ERR
"ME4000:me4000_dio_config():Invalid port function specified\n");
return -EINVAL;
}
}
return 0;
}
static int me4000_dio_set_byte(me4000_dio_byte_t * arg,
me4000_dio_context_t * dio_context)
{
me4000_dio_byte_t cmd;
int err;
CALL_PDEBUG("me4000_dio_set_byte() is executed\n");
/* Copy data from user */
err = copy_from_user(&cmd, arg, sizeof(me4000_dio_byte_t));
if (err) {
printk(KERN_ERR
"ME4000:me4000_dio_set_byte():Can't copy from user space\n");
return -EFAULT;
}
/* Check port parameter */
if (cmd.port >= dio_context->dio_count) {
printk(KERN_ERR
"ME4000:me4000_dio_set_byte():Port %d is not available\n",
cmd.port);
return -EINVAL;
}
if (cmd.port == ME4000_DIO_PORT_A) {
if ((me4000_inl(dio_context->ctrl_reg) & 0x3) != 0x1) {
printk(KERN_ERR
"ME4000:me4000_dio_set_byte():Port %d is not in output mode\n",
cmd.port);
return -EIO;
}
me4000_outl(cmd.byte, dio_context->port_0_reg);
} else if (cmd.port == ME4000_DIO_PORT_B) {
if ((me4000_inl(dio_context->ctrl_reg) & 0xC) != 0x4) {
printk(KERN_ERR
"ME4000:me4000_dio_set_byte():Port %d is not in output mode\n",
cmd.port);
return -EIO;
}
me4000_outl(cmd.byte, dio_context->port_1_reg);
} else if (cmd.port == ME4000_DIO_PORT_C) {
if ((me4000_inl(dio_context->ctrl_reg) & 0x30) != 0x10) {
printk(KERN_ERR
"ME4000:me4000_dio_set_byte():Port %d is not in output mode\n",
cmd.port);
return -EIO;
}
me4000_outl(cmd.byte, dio_context->port_2_reg);
} else if (cmd.port == ME4000_DIO_PORT_D) {
if ((me4000_inl(dio_context->ctrl_reg) & 0xC0) != 0x40) {
printk(KERN_ERR
"ME4000:me4000_dio_set_byte():Port %d is not in output mode\n",
cmd.port);
return -EIO;
}
me4000_outl(cmd.byte, dio_context->port_3_reg);
} else {
printk(KERN_ERR
"ME4000:me4000_dio_set_byte():Port %d is not available\n",
cmd.port);
return -EINVAL;
}
return 0;
}
static int me4000_dio_get_byte(me4000_dio_byte_t * arg,
me4000_dio_context_t * dio_context)
{
me4000_dio_byte_t cmd;
int err;
CALL_PDEBUG("me4000_dio_get_byte() is executed\n");
/* Copy data from user */
err = copy_from_user(&cmd, arg, sizeof(me4000_dio_byte_t));
if (err) {
printk(KERN_ERR
"ME4000:me4000_dio_get_byte():Can't copy from user space\n");
return -EFAULT;
}
/* Check port parameter */
if (cmd.port >= dio_context->dio_count) {
printk(KERN_ERR
"ME4000:me4000_dio_get_byte():Port %d is not available\n",
cmd.port);
return -EINVAL;
}
if (cmd.port == ME4000_DIO_PORT_A) {
cmd.byte = me4000_inl(dio_context->port_0_reg) & 0xFF;
} else if (cmd.port == ME4000_DIO_PORT_B) {
cmd.byte = me4000_inl(dio_context->port_1_reg) & 0xFF;
} else if (cmd.port == ME4000_DIO_PORT_C) {
cmd.byte = me4000_inl(dio_context->port_2_reg) & 0xFF;
} else if (cmd.port == ME4000_DIO_PORT_D) {
cmd.byte = me4000_inl(dio_context->port_3_reg) & 0xFF;
} else {
printk(KERN_ERR
"ME4000:me4000_dio_get_byte():Port %d is not available\n",
cmd.port);
return -EINVAL;
}
/* Copy result back to user */
err = copy_to_user(arg, &cmd, sizeof(me4000_dio_byte_t));
if (err) {
printk(KERN_ERR
"ME4000:me4000_dio_get_byte():Can't copy to user space\n");
return -EFAULT;
}
return 0;
}
static int me4000_dio_reset(me4000_dio_context_t * dio_context)
{
CALL_PDEBUG("me4000_dio_reset() is executed\n");
/* Clear the control register */
me4000_outl(0, dio_context->ctrl_reg);
/* Check for opto isolated version */
if (!(me4000_inl(dio_context->dir_reg) & 0x1)) {
me4000_outl(0x1, dio_context->ctrl_reg);
me4000_outl(0x0, dio_context->port_0_reg);
}
return 0;
}
/*------------------------------------ COUNTER STUFF ------------------------------------*/
static int me4000_cnt_ioctl(struct inode *inode_p, struct file *file_p,
unsigned int service, unsigned long arg)
{
me4000_cnt_context_t *cnt_context;
CALL_PDEBUG("me4000_cnt_ioctl() is executed\n");
cnt_context = file_p->private_data;
if (_IOC_TYPE(service) != ME4000_MAGIC) {
printk(KERN_ERR "me4000_dio_ioctl():Wrong magic number\n");
return -ENOTTY;
}
if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) {
printk(KERN_ERR "me4000_dio_ioctl():Service number to high\n");
return -ENOTTY;
}
switch (service) {
case ME4000_CNT_READ:
return me4000_cnt_read((me4000_cnt_t *) arg, cnt_context);
case ME4000_CNT_WRITE:
return me4000_cnt_write((me4000_cnt_t *) arg, cnt_context);
case ME4000_CNT_CONFIG:
return me4000_cnt_config((me4000_cnt_config_t *) arg,
cnt_context);
case ME4000_CNT_RESET:
return me4000_cnt_reset(cnt_context);
default:
printk(KERN_ERR
"ME4000:me4000_dio_ioctl():Invalid service number %d\n",
service);
return -ENOTTY;
}
return 0;
}
static int me4000_cnt_config(me4000_cnt_config_t * arg,
me4000_cnt_context_t * cnt_context)
{
me4000_cnt_config_t cmd;
u8 counter;
u8 mode;
int err;
CALL_PDEBUG("me4000_cnt_config() is executed\n");
/* Copy data from user */
err = copy_from_user(&cmd, arg, sizeof(me4000_cnt_config_t));
if (err) {
printk(KERN_ERR
"ME4000:me4000_cnt_config():Can't copy from user space\n");
return -EFAULT;
}
/* Check counter parameter */
switch (cmd.counter) {
case ME4000_CNT_COUNTER_0:
counter = ME4000_CNT_CTRL_BIT_COUNTER_0;
break;
case ME4000_CNT_COUNTER_1:
counter = ME4000_CNT_CTRL_BIT_COUNTER_1;
break;
case ME4000_CNT_COUNTER_2:
counter = ME4000_CNT_CTRL_BIT_COUNTER_2;
break;
default:
printk(KERN_ERR
"ME4000:me4000_cnt_config():Counter %d is not available\n",
cmd.counter);
return -EINVAL;
}
/* Check mode parameter */
switch (cmd.mode) {
case ME4000_CNT_MODE_0:
mode = ME4000_CNT_CTRL_BIT_MODE_0;
break;
case ME4000_CNT_MODE_1:
mode = ME4000_CNT_CTRL_BIT_MODE_1;
break;
case ME4000_CNT_MODE_2:
mode = ME4000_CNT_CTRL_BIT_MODE_2;
break;
case ME4000_CNT_MODE_3:
mode = ME4000_CNT_CTRL_BIT_MODE_3;
break;
case ME4000_CNT_MODE_4:
mode = ME4000_CNT_CTRL_BIT_MODE_4;
break;
case ME4000_CNT_MODE_5:
mode = ME4000_CNT_CTRL_BIT_MODE_5;
break;
default:
printk(KERN_ERR
"ME4000:me4000_cnt_config():Mode %d is not available\n",
cmd.mode);
return -EINVAL;
}
/* Write the control word */
me4000_outb((counter | mode | 0x30), cnt_context->ctrl_reg);
return 0;
}
static int me4000_cnt_read(me4000_cnt_t * arg,
me4000_cnt_context_t * cnt_context)
{
me4000_cnt_t cmd;
u8 tmp;
int err;
CALL_PDEBUG("me4000_cnt_read() is executed\n");
/* Copy data from user */
err = copy_from_user(&cmd, arg, sizeof(me4000_cnt_t));
if (err) {
printk(KERN_ERR
"ME4000:me4000_cnt_read():Can't copy from user space\n");
return -EFAULT;
}
/* Read counter */
switch (cmd.counter) {
case ME4000_CNT_COUNTER_0:
tmp = me4000_inb(cnt_context->counter_0_reg);
cmd.value = tmp;
tmp = me4000_inb(cnt_context->counter_0_reg);
cmd.value |= ((u16) tmp) << 8;
break;
case ME4000_CNT_COUNTER_1:
tmp = me4000_inb(cnt_context->counter_1_reg);
cmd.value = tmp;
tmp = me4000_inb(cnt_context->counter_1_reg);
cmd.value |= ((u16) tmp) << 8;
break;
case ME4000_CNT_COUNTER_2:
tmp = me4000_inb(cnt_context->counter_2_reg);
cmd.value = tmp;
tmp = me4000_inb(cnt_context->counter_2_reg);
cmd.value |= ((u16) tmp) << 8;
break;
default:
printk(KERN_ERR
"ME4000:me4000_cnt_read():Counter %d is not available\n",
cmd.counter);
return -EINVAL;
}
/* Copy result back to user */
err = copy_to_user(arg, &cmd, sizeof(me4000_cnt_t));
if (err) {
printk(KERN_ERR
"ME4000:me4000_cnt_read():Can't copy to user space\n");
return -EFAULT;
}
return 0;
}
static int me4000_cnt_write(me4000_cnt_t * arg,
me4000_cnt_context_t * cnt_context)
{
me4000_cnt_t cmd;
u8 tmp;
int err;
CALL_PDEBUG("me4000_cnt_write() is executed\n");
/* Copy data from user */
err = copy_from_user(&cmd, arg, sizeof(me4000_cnt_t));
if (err) {
printk(KERN_ERR
"ME4000:me4000_cnt_write():Can't copy from user space\n");
return -EFAULT;
}
/* Write counter */
switch (cmd.counter) {
case ME4000_CNT_COUNTER_0:
tmp = cmd.value & 0xFF;
me4000_outb(tmp, cnt_context->counter_0_reg);
tmp = (cmd.value >> 8) & 0xFF;
me4000_outb(tmp, cnt_context->counter_0_reg);
break;
case ME4000_CNT_COUNTER_1:
tmp = cmd.value & 0xFF;
me4000_outb(tmp, cnt_context->counter_1_reg);
tmp = (cmd.value >> 8) & 0xFF;
me4000_outb(tmp, cnt_context->counter_1_reg);
break;
case ME4000_CNT_COUNTER_2:
tmp = cmd.value & 0xFF;
me4000_outb(tmp, cnt_context->counter_2_reg);
tmp = (cmd.value >> 8) & 0xFF;
me4000_outb(tmp, cnt_context->counter_2_reg);
break;
default:
printk(KERN_ERR
"ME4000:me4000_cnt_write():Counter %d is not available\n",
cmd.counter);
return -EINVAL;
}
return 0;
}
static int me4000_cnt_reset(me4000_cnt_context_t * cnt_context)
{
CALL_PDEBUG("me4000_cnt_reset() is executed\n");
/* Set the mode and value for counter 0 */
me4000_outb(0x30, cnt_context->ctrl_reg);
me4000_outb(0x00, cnt_context->counter_0_reg);
me4000_outb(0x00, cnt_context->counter_0_reg);
/* Set the mode and value for counter 1 */
me4000_outb(0x70, cnt_context->ctrl_reg);
me4000_outb(0x00, cnt_context->counter_1_reg);
me4000_outb(0x00, cnt_context->counter_1_reg);
/* Set the mode and value for counter 2 */
me4000_outb(0xB0, cnt_context->ctrl_reg);
me4000_outb(0x00, cnt_context->counter_2_reg);
me4000_outb(0x00, cnt_context->counter_2_reg);
return 0;
}
/*------------------------------------ External Interrupt stuff ------------------------------------*/
static int me4000_ext_int_ioctl(struct inode *inode_p, struct file *file_p,
unsigned int service, unsigned long arg)
{
me4000_ext_int_context_t *ext_int_context;
CALL_PDEBUG("me4000_ext_int_ioctl() is executed\n");
ext_int_context = file_p->private_data;
if (_IOC_TYPE(service) != ME4000_MAGIC) {
printk(KERN_ERR "me4000_ext_int_ioctl():Wrong magic number\n");
return -ENOTTY;
}
if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) {
printk(KERN_ERR
"me4000_ext_int_ioctl():Service number to high\n");
return -ENOTTY;
}
switch (service) {
case ME4000_EXT_INT_ENABLE:
return me4000_ext_int_enable(ext_int_context);
case ME4000_EXT_INT_DISABLE:
return me4000_ext_int_disable(ext_int_context);
case ME4000_EXT_INT_COUNT:
return me4000_ext_int_count((unsigned long *)arg,
ext_int_context);
default:
printk(KERN_ERR
"ME4000:me4000_ext_int_ioctl():Invalid service number %d\n",
service);
return -ENOTTY;
}
return 0;
}
static int me4000_ext_int_enable(me4000_ext_int_context_t * ext_int_context)
{
unsigned long tmp;
CALL_PDEBUG("me4000_ext_int_enable() is executed\n");
tmp = me4000_inl(ext_int_context->ctrl_reg);
tmp |= ME4000_AI_CTRL_BIT_EX_IRQ;
me4000_outl(tmp, ext_int_context->ctrl_reg);
return 0;
}
static int me4000_ext_int_disable(me4000_ext_int_context_t * ext_int_context)
{
unsigned long tmp;
CALL_PDEBUG("me4000_ext_int_disable() is executed\n");
tmp = me4000_inl(ext_int_context->ctrl_reg);
tmp &= ~ME4000_AI_CTRL_BIT_EX_IRQ;
me4000_outl(tmp, ext_int_context->ctrl_reg);
return 0;
}
static int me4000_ext_int_count(unsigned long *arg,
me4000_ext_int_context_t * ext_int_context)
{
CALL_PDEBUG("me4000_ext_int_count() is executed\n");
put_user(ext_int_context->int_count, arg);
return 0;
}
/*------------------------------------ General stuff ------------------------------------*/
static int me4000_get_user_info(me4000_user_info_t * arg,
me4000_info_t * board_info)
{
me4000_user_info_t user_info;
CALL_PDEBUG("me4000_get_user_info() is executed\n");
user_info.board_count = board_info->board_count;
user_info.plx_regbase = board_info->plx_regbase;
user_info.plx_regbase_size = board_info->plx_regbase_size;
user_info.me4000_regbase = board_info->me4000_regbase;
user_info.me4000_regbase_size = board_info->me4000_regbase_size;
user_info.serial_no = board_info->serial_no;
user_info.hw_revision = board_info->hw_revision;
user_info.vendor_id = board_info->vendor_id;
user_info.device_id = board_info->device_id;
user_info.pci_bus_no = board_info->pci_bus_no;
user_info.pci_dev_no = board_info->pci_dev_no;
user_info.pci_func_no = board_info->pci_func_no;
user_info.irq = board_info->irq;
user_info.irq_count = board_info->irq_count;
user_info.driver_version = ME4000_DRIVER_VERSION;
user_info.ao_count = board_info->board_p->ao.count;
user_info.ao_fifo_count = board_info->board_p->ao.fifo_count;
user_info.ai_count = board_info->board_p->ai.count;
user_info.ai_sh_count = board_info->board_p->ai.sh_count;
user_info.ai_ex_trig_analog = board_info->board_p->ai.ex_trig_analog;
user_info.dio_count = board_info->board_p->dio.count;
user_info.cnt_count = board_info->board_p->cnt.count;
if (copy_to_user(arg, &user_info, sizeof(me4000_user_info_t)))
return -EFAULT;
return 0;
}
/*------------------------------------ ISR STUFF ------------------------------------*/
static int me4000_ext_int_fasync(int fd, struct file *file_ptr, int mode)
{
int result = 0;
me4000_ext_int_context_t *ext_int_context;
CALL_PDEBUG("me4000_ext_int_fasync() is executed\n");
ext_int_context = file_ptr->private_data;
result =
fasync_helper(fd, file_ptr, mode, &ext_int_context->fasync_ptr);
CALL_PDEBUG("me4000_ext_int_fasync() is leaved\n");
return result;
}
static irqreturn_t me4000_ao_isr(int irq, void *dev_id)
{
u32 tmp;
u32 value;
me4000_ao_context_t *ao_context;
int i;
int c = 0;
int c1 = 0;
//unsigned long before;
//unsigned long after;
ISR_PDEBUG("me4000_ao_isr() is executed\n");
ao_context = dev_id;
/* Check if irq number is right */
if (irq != ao_context->irq) {
ISR_PDEBUG("me4000_ao_isr():incorrect interrupt num: %d\n",
irq);
return IRQ_NONE;
}
/* Check if this DAC rised an interrupt */
if (!
((0x1 << (ao_context->index + 3)) &
me4000_inl(ao_context->irq_status_reg))) {
ISR_PDEBUG("me4000_ao_isr():Not this DAC\n");
return IRQ_NONE;
}
/* Read status register to find out what happened */
tmp = me4000_inl(ao_context->status_reg);
if (!(tmp & ME4000_AO_STATUS_BIT_EF) && (tmp & ME4000_AO_STATUS_BIT_HF)
&& (tmp & ME4000_AO_STATUS_BIT_HF)) {
c = ME4000_AO_FIFO_COUNT;
ISR_PDEBUG("me4000_ao_isr():Fifo empty\n");
} else if ((tmp & ME4000_AO_STATUS_BIT_EF)
&& (tmp & ME4000_AO_STATUS_BIT_HF)
&& (tmp & ME4000_AO_STATUS_BIT_HF)) {
c = ME4000_AO_FIFO_COUNT / 2;
ISR_PDEBUG("me4000_ao_isr():Fifo under half full\n");
} else {
c = 0;
ISR_PDEBUG("me4000_ao_isr():Fifo full\n");
}
ISR_PDEBUG("me4000_ao_isr():Try to write 0x%04X values\n", c);
while (1) {
c1 = me4000_values_to_end(ao_context->circ_buf,
ME4000_AO_BUFFER_COUNT);
ISR_PDEBUG("me4000_ao_isr():Values to end = %d\n", c1);
if (c1 > c)
c1 = c;
if (c1 <= 0) {
ISR_PDEBUG
("me4000_ao_isr():Work done or buffer empty\n");
break;
}
//rdtscl(before);
if (((ao_context->fifo_reg & 0xFF) == ME4000_AO_01_FIFO_REG) ||
((ao_context->fifo_reg & 0xFF) == ME4000_AO_03_FIFO_REG)) {
for (i = 0; i < c1; i++) {
value =
((u32)
(*
(ao_context->circ_buf.buf +
ao_context->circ_buf.tail + i))) << 16;
outl(value, ao_context->fifo_reg);
}
} else
outsw(ao_context->fifo_reg,
ao_context->circ_buf.buf +
ao_context->circ_buf.tail, c1);
//rdtscl(after);
//printk(KERN_ERR"ME4000:me4000_ao_isr():Time lapse = %lu\n", after - before);
ao_context->circ_buf.tail =
(ao_context->circ_buf.tail + c1) & (ME4000_AO_BUFFER_COUNT -
1);
ISR_PDEBUG("me4000_ao_isr():%d values wrote to port 0x%04X\n",
c1, ao_context->fifo_reg);
c -= c1;
}
/* If there are no values left in the buffer, disable interrupts */
spin_lock(&ao_context->int_lock);
if (!me4000_buf_count(ao_context->circ_buf, ME4000_AO_BUFFER_COUNT)) {
ISR_PDEBUG
("me4000_ao_isr():Disable Interrupt because no values left in buffer\n");
tmp = me4000_inl(ao_context->ctrl_reg);
tmp &= ~ME4000_AO_CTRL_BIT_ENABLE_IRQ;
me4000_outl(tmp, ao_context->ctrl_reg);
}
spin_unlock(&ao_context->int_lock);
/* Reset the interrupt */
spin_lock(&ao_context->int_lock);
tmp = me4000_inl(ao_context->ctrl_reg);
tmp |= ME4000_AO_CTRL_BIT_RESET_IRQ;
me4000_outl(tmp, ao_context->ctrl_reg);
tmp &= ~ME4000_AO_CTRL_BIT_RESET_IRQ;
me4000_outl(tmp, ao_context->ctrl_reg);
/* If state machine is stopped, flow was interrupted */
if (!(me4000_inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM)) {
printk(KERN_ERR "ME4000:me4000_ao_isr():Broken pipe\n");
ao_context->pipe_flag = 1; // Set flag in order to inform write routine
tmp &= ~ME4000_AO_CTRL_BIT_ENABLE_IRQ; // Disable interrupt
}
me4000_outl(tmp, ao_context->ctrl_reg);
spin_unlock(&ao_context->int_lock);
/* Wake up waiting process */
wake_up_interruptible(&(ao_context->wait_queue));
/* Count the interrupt */
ao_context->board_info->irq_count++;
return IRQ_HANDLED;
}
static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
{
u32 tmp;
me4000_ai_context_t *ai_context;
int i;
int c = 0;
int c1 = 0;
#ifdef ME4000_ISR_DEBUG
unsigned long before;
unsigned long after;
#endif
ISR_PDEBUG("me4000_ai_isr() is executed\n");
#ifdef ME4000_ISR_DEBUG
rdtscl(before);
#endif
ai_context = dev_id;
/* Check if irq number is right */
if (irq != ai_context->irq) {
ISR_PDEBUG("me4000_ai_isr():incorrect interrupt num: %d\n",
irq);
return IRQ_NONE;
}
if (me4000_inl(ai_context->irq_status_reg) &
ME4000_IRQ_STATUS_BIT_AI_HF) {
ISR_PDEBUG
("me4000_ai_isr():Fifo half full interrupt occured\n");
/* Read status register to find out what happened */
tmp = me4000_inl(ai_context->ctrl_reg);
if (!(tmp & ME4000_AI_STATUS_BIT_FF_DATA) &&
!(tmp & ME4000_AI_STATUS_BIT_HF_DATA)
&& (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) {
ISR_PDEBUG("me4000_ai_isr():Fifo full\n");
c = ME4000_AI_FIFO_COUNT;
/* FIFO overflow, so stop conversion and disable all interrupts */
spin_lock(&ai_context->int_lock);
tmp = me4000_inl(ai_context->ctrl_reg);
tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
tmp &=
~(ME4000_AI_CTRL_BIT_HF_IRQ |
ME4000_AI_CTRL_BIT_SC_IRQ);
outl(tmp, ai_context->ctrl_reg);
spin_unlock(&ai_context->int_lock);
} else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA) &&
!(tmp & ME4000_AI_STATUS_BIT_HF_DATA)
&& (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) {
ISR_PDEBUG("me4000_ai_isr():Fifo half full\n");
c = ME4000_AI_FIFO_COUNT / 2;
} else {
c = 0;
ISR_PDEBUG
("me4000_ai_isr():Can't determine state of fifo\n");
}
ISR_PDEBUG("me4000_ai_isr():Try to read %d values\n", c);
while (1) {
c1 = me4000_space_to_end(ai_context->circ_buf,
ME4000_AI_BUFFER_COUNT);
ISR_PDEBUG("me4000_ai_isr():Space to end = %d\n", c1);
if (c1 > c)
c1 = c;
if (c1 <= 0) {
ISR_PDEBUG
("me4000_ai_isr():Work done or buffer full\n");
break;
}
insw(ai_context->data_reg,
ai_context->circ_buf.buf +
ai_context->circ_buf.head, c1);
ai_context->circ_buf.head =
(ai_context->circ_buf.head +
c1) & (ME4000_AI_BUFFER_COUNT - 1);
c -= c1;
}
/* Work is done, so reset the interrupt */
ISR_PDEBUG
("me4000_ai_isr():reset interrupt fifo half full interrupt\n");
spin_lock(&ai_context->int_lock);
tmp = me4000_inl(ai_context->ctrl_reg);
tmp |= ME4000_AI_CTRL_BIT_HF_IRQ_RESET;
me4000_outl(tmp, ai_context->ctrl_reg);
tmp &= ~ME4000_AI_CTRL_BIT_HF_IRQ_RESET;
me4000_outl(tmp, ai_context->ctrl_reg);
spin_unlock(&ai_context->int_lock);
}
if (me4000_inl(ai_context->irq_status_reg) & ME4000_IRQ_STATUS_BIT_SC) {
ISR_PDEBUG
("me4000_ai_isr():Sample counter interrupt occured\n");
if (!ai_context->sample_counter_reload) {
ISR_PDEBUG
("me4000_ai_isr():Single data block available\n");
/* Poll data until fifo empty */
for (i = 0;
(i < ME4000_AI_FIFO_COUNT / 2)
&& (inl(ai_context->ctrl_reg) &
ME4000_AI_STATUS_BIT_EF_DATA); i++) {
if (me4000_space_to_end
(ai_context->circ_buf,
ME4000_AI_BUFFER_COUNT)) {
*(ai_context->circ_buf.buf +
ai_context->circ_buf.head) =
inw(ai_context->data_reg);
ai_context->circ_buf.head =
(ai_context->circ_buf.head +
1) & (ME4000_AI_BUFFER_COUNT - 1);
} else
break;
}
ISR_PDEBUG("me4000_ai_isr():%d values read\n", i);
} else {
if (ai_context->sample_counter <=
ME4000_AI_FIFO_COUNT / 2) {
ISR_PDEBUG
("me4000_ai_isr():Interrupt from adjustable half full threshold\n");
/* Read status register to find out what happened */
tmp = me4000_inl(ai_context->ctrl_reg);
if (!(tmp & ME4000_AI_STATUS_BIT_FF_DATA) &&
!(tmp & ME4000_AI_STATUS_BIT_HF_DATA)
&& (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) {
ISR_PDEBUG
("me4000_ai_isr():Fifo full\n");
c = ME4000_AI_FIFO_COUNT;
/* FIFO overflow, so stop conversion */
spin_lock(&ai_context->int_lock);
tmp = me4000_inl(ai_context->ctrl_reg);
tmp |=
ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
outl(tmp, ai_context->ctrl_reg);
spin_unlock(&ai_context->int_lock);
} else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA)
&& !(tmp &
ME4000_AI_STATUS_BIT_HF_DATA)
&& (tmp &
ME4000_AI_STATUS_BIT_EF_DATA)) {
ISR_PDEBUG
("me4000_ai_isr():Fifo half full\n");
c = ME4000_AI_FIFO_COUNT / 2;
} else {
c = ai_context->sample_counter;
ISR_PDEBUG
("me4000_ai_isr():Sample count values\n");
}
ISR_PDEBUG
("me4000_ai_isr():Try to read %d values\n",
c);
while (1) {
c1 = me4000_space_to_end(ai_context->
circ_buf,
ME4000_AI_BUFFER_COUNT);
ISR_PDEBUG
("me4000_ai_isr():Space to end = %d\n",
c1);
if (c1 > c)
c1 = c;
if (c1 <= 0) {
ISR_PDEBUG
("me4000_ai_isr():Work done or buffer full\n");
break;
}
insw(ai_context->data_reg,
ai_context->circ_buf.buf +
ai_context->circ_buf.head, c1);
ai_context->circ_buf.head =
(ai_context->circ_buf.head +
c1) & (ME4000_AI_BUFFER_COUNT - 1);
c -= c1;
}
} else {
ISR_PDEBUG
("me4000_ai_isr():Multiple data block available\n");
/* Read status register to find out what happened */
tmp = me4000_inl(ai_context->ctrl_reg);
if (!(tmp & ME4000_AI_STATUS_BIT_FF_DATA) &&
!(tmp & ME4000_AI_STATUS_BIT_HF_DATA)
&& (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) {
ISR_PDEBUG
("me4000_ai_isr():Fifo full\n");
c = ME4000_AI_FIFO_COUNT;
/* FIFO overflow, so stop conversion */
spin_lock(&ai_context->int_lock);
tmp = me4000_inl(ai_context->ctrl_reg);
tmp |=
ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
outl(tmp, ai_context->ctrl_reg);
spin_unlock(&ai_context->int_lock);
while (1) {
c1 = me4000_space_to_end
(ai_context->circ_buf,
ME4000_AI_BUFFER_COUNT);
ISR_PDEBUG
("me4000_ai_isr():Space to end = %d\n",
c1);
if (c1 > c)
c1 = c;
if (c1 <= 0) {
ISR_PDEBUG
("me4000_ai_isr():Work done or buffer full\n");
break;
}
insw(ai_context->data_reg,
ai_context->circ_buf.buf +
ai_context->circ_buf.head,
c1);
ai_context->circ_buf.head =
(ai_context->circ_buf.head +
c1) &
(ME4000_AI_BUFFER_COUNT -
1);
c -= c1;
}
} else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA)
&& !(tmp &
ME4000_AI_STATUS_BIT_HF_DATA)
&& (tmp &
ME4000_AI_STATUS_BIT_EF_DATA)) {
ISR_PDEBUG
("me4000_ai_isr():Fifo half full\n");
c = ME4000_AI_FIFO_COUNT / 2;
while (1) {
c1 = me4000_space_to_end
(ai_context->circ_buf,
ME4000_AI_BUFFER_COUNT);
ISR_PDEBUG
("me4000_ai_isr():Space to end = %d\n",
c1);
if (c1 > c)
c1 = c;
if (c1 <= 0) {
ISR_PDEBUG
("me4000_ai_isr():Work done or buffer full\n");
break;
}
insw(ai_context->data_reg,
ai_context->circ_buf.buf +
ai_context->circ_buf.head,
c1);
ai_context->circ_buf.head =
(ai_context->circ_buf.head +
c1) &
(ME4000_AI_BUFFER_COUNT -
1);
c -= c1;
}
} else {
/* Poll data until fifo empty */
for (i = 0;
(i < ME4000_AI_FIFO_COUNT / 2)
&& (inl(ai_context->ctrl_reg) &
ME4000_AI_STATUS_BIT_EF_DATA);
i++) {
if (me4000_space_to_end
(ai_context->circ_buf,
ME4000_AI_BUFFER_COUNT)) {
*(ai_context->circ_buf.
buf +
ai_context->circ_buf.
head) =
inw(ai_context->data_reg);
ai_context->circ_buf.
head =
(ai_context->
circ_buf.head +
1) &
(ME4000_AI_BUFFER_COUNT
- 1);
} else
break;
}
ISR_PDEBUG
("me4000_ai_isr():%d values read\n",
i);
}
}
}
/* Work is done, so reset the interrupt */
ISR_PDEBUG
("me4000_ai_isr():reset interrupt from sample counter\n");
spin_lock(&ai_context->int_lock);
tmp = me4000_inl(ai_context->ctrl_reg);
tmp |= ME4000_AI_CTRL_BIT_SC_IRQ_RESET;
me4000_outl(tmp, ai_context->ctrl_reg);
tmp &= ~ME4000_AI_CTRL_BIT_SC_IRQ_RESET;
me4000_outl(tmp, ai_context->ctrl_reg);
spin_unlock(&ai_context->int_lock);
}
/* Values are now available, so wake up waiting process */
if (me4000_buf_count(ai_context->circ_buf, ME4000_AI_BUFFER_COUNT)) {
ISR_PDEBUG("me4000_ai_isr():Wake up waiting process\n");
wake_up_interruptible(&(ai_context->wait_queue));
}
/* If there is no space left in the buffer, disable interrupts */
spin_lock(&ai_context->int_lock);
if (!me4000_buf_space(ai_context->circ_buf, ME4000_AI_BUFFER_COUNT)) {
ISR_PDEBUG
("me4000_ai_isr():Disable Interrupt because no space left in buffer\n");
tmp = me4000_inl(ai_context->ctrl_reg);
tmp &=
~(ME4000_AI_CTRL_BIT_SC_IRQ | ME4000_AI_CTRL_BIT_HF_IRQ |
ME4000_AI_CTRL_BIT_LE_IRQ);
me4000_outl(tmp, ai_context->ctrl_reg);
}
spin_unlock(&ai_context->int_lock);
#ifdef ME4000_ISR_DEBUG
rdtscl(after);
printk(KERN_ERR "ME4000:me4000_ai_isr():Time lapse = %lu\n",
after - before);
#endif
return IRQ_HANDLED;
}
static irqreturn_t me4000_ext_int_isr(int irq, void *dev_id)
{
me4000_ext_int_context_t *ext_int_context;
unsigned long tmp;
ISR_PDEBUG("me4000_ext_int_isr() is executed\n");
ext_int_context = dev_id;
/* Check if irq number is right */
if (irq != ext_int_context->irq) {
ISR_PDEBUG("me4000_ext_int_isr():incorrect interrupt num: %d\n",
irq);
return IRQ_NONE;
}
if (me4000_inl(ext_int_context->irq_status_reg) &
ME4000_IRQ_STATUS_BIT_EX) {
ISR_PDEBUG("me4000_ext_int_isr():External interrupt occured\n");
tmp = me4000_inl(ext_int_context->ctrl_reg);
tmp |= ME4000_AI_CTRL_BIT_EX_IRQ_RESET;
me4000_outl(tmp, ext_int_context->ctrl_reg);
tmp &= ~ME4000_AI_CTRL_BIT_EX_IRQ_RESET;
me4000_outl(tmp, ext_int_context->ctrl_reg);
ext_int_context->int_count++;
if (ext_int_context->fasync_ptr) {
ISR_PDEBUG
("me2600_ext_int_isr():Send signal to process\n");
kill_fasync(&ext_int_context->fasync_ptr, SIGIO,
POLL_IN);
}
}
return IRQ_HANDLED;
}
void __exit me4000_module_exit(void)
{
struct list_head *board_p;
me4000_info_t *board_info;
CALL_PDEBUG("cleanup_module() is executed\n");
unregister_chrdev(me4000_ext_int_major_driver_no, ME4000_EXT_INT_NAME);
unregister_chrdev(me4000_cnt_major_driver_no, ME4000_CNT_NAME);
unregister_chrdev(me4000_dio_major_driver_no, ME4000_DIO_NAME);
unregister_chrdev(me4000_ai_major_driver_no, ME4000_AI_NAME);
unregister_chrdev(me4000_ao_major_driver_no, ME4000_AO_NAME);
remove_proc_entry("me4000", NULL);
pci_unregister_driver(&me4000_driver);
/* Reset the boards */
for (board_p = me4000_board_info_list.next;
board_p != &me4000_board_info_list; board_p = board_p->next) {
board_info = list_entry(board_p, me4000_info_t, list);
me4000_reset_board(board_info);
}
clear_board_info_list();
}
module_exit(me4000_module_exit);
static int me4000_read_procmem(char *buf, char **start, off_t offset, int count,
int *eof, void *data)
{
int len = 0;
int limit = count - 1000;
me4000_info_t *board_info;
struct list_head *ptr;
len += sprintf(buf + len, "\nME4000 DRIVER VERSION %X.%X.%X\n\n",
(ME4000_DRIVER_VERSION & 0xFF0000) >> 16,
(ME4000_DRIVER_VERSION & 0xFF00) >> 8,
(ME4000_DRIVER_VERSION & 0xFF));
/* Search for the board context */
for (ptr = me4000_board_info_list.next;
(ptr != &me4000_board_info_list) && (len < limit);
ptr = ptr->next) {
board_info = list_entry(ptr, me4000_info_t, list);
len +=
sprintf(buf + len, "Board number %d:\n",
board_info->board_count);
len += sprintf(buf + len, "---------------\n");
len +=
sprintf(buf + len, "PLX base register = 0x%lX\n",
board_info->plx_regbase);
len +=
sprintf(buf + len, "PLX base register size = 0x%lX\n",
board_info->plx_regbase_size);
len +=
sprintf(buf + len, "ME4000 base register = 0x%lX\n",
board_info->me4000_regbase);
len +=
sprintf(buf + len, "ME4000 base register size = 0x%lX\n",
board_info->me4000_regbase_size);
len +=
sprintf(buf + len, "Serial number = 0x%X\n",
board_info->serial_no);
len +=
sprintf(buf + len, "Hardware revision = 0x%X\n",
board_info->hw_revision);
len +=
sprintf(buf + len, "Vendor id = 0x%X\n",
board_info->vendor_id);
len +=
sprintf(buf + len, "Device id = 0x%X\n",
board_info->device_id);
len +=
sprintf(buf + len, "PCI bus number = %d\n",
board_info->pci_bus_no);
len +=
sprintf(buf + len, "PCI device number = %d\n",
board_info->pci_dev_no);
len +=
sprintf(buf + len, "PCI function number = %d\n",
board_info->pci_func_no);
len += sprintf(buf + len, "IRQ = %u\n", board_info->irq);
len +=
sprintf(buf + len,
"Count of interrupts since module was loaded = %d\n",
board_info->irq_count);
len +=
sprintf(buf + len, "Count of analog outputs = %d\n",
board_info->board_p->ao.count);
len +=
sprintf(buf + len, "Count of analog output fifos = %d\n",
board_info->board_p->ao.fifo_count);
len +=
sprintf(buf + len, "Count of analog inputs = %d\n",
board_info->board_p->ai.count);
len +=
sprintf(buf + len,
"Count of sample and hold devices for analog input = %d\n",
board_info->board_p->ai.sh_count);
len +=
sprintf(buf + len,
"Analog external trigger available for analog input = %d\n",
board_info->board_p->ai.ex_trig_analog);
len +=
sprintf(buf + len, "Count of digital ports = %d\n",
board_info->board_p->dio.count);
len +=
sprintf(buf + len, "Count of counter devices = %d\n",
board_info->board_p->cnt.count);
len +=
sprintf(buf + len, "AI control register = 0x%08X\n",
inl(board_info->me4000_regbase +
ME4000_AI_CTRL_REG));
len += sprintf(buf + len, "AO 0 control register = 0x%08X\n",
inl(board_info->me4000_regbase +
ME4000_AO_00_CTRL_REG));
len +=
sprintf(buf + len, "AO 0 status register = 0x%08X\n",
inl(board_info->me4000_regbase +
ME4000_AO_00_STATUS_REG));
len +=
sprintf(buf + len, "AO 1 control register = 0x%08X\n",
inl(board_info->me4000_regbase +
ME4000_AO_01_CTRL_REG));
len +=
sprintf(buf + len, "AO 1 status register = 0x%08X\n",
inl(board_info->me4000_regbase +
ME4000_AO_01_STATUS_REG));
len +=
sprintf(buf + len, "AO 2 control register = 0x%08X\n",
inl(board_info->me4000_regbase +
ME4000_AO_02_CTRL_REG));
len +=
sprintf(buf + len, "AO 2 status register = 0x%08X\n",
inl(board_info->me4000_regbase +
ME4000_AO_02_STATUS_REG));
len +=
sprintf(buf + len, "AO 3 control register = 0x%08X\n",
inl(board_info->me4000_regbase +
ME4000_AO_03_CTRL_REG));
len +=
sprintf(buf + len, "AO 3 status register = 0x%08X\n",
inl(board_info->me4000_regbase +
ME4000_AO_03_STATUS_REG));
}
*eof = 1;
return len;
}
/*
* Copyright (C) 2003 Meilhaus Electronic GmbH (support@meilhaus.de)
*
* Source File : me4000.h
* Author : GG (Guenter Gebhardt) <g.gebhardt@meilhaus.de>
*/
#ifndef _ME4000_H_
#define _ME4000_H_
#ifdef __KERNEL__
/*=============================================================================
The version of the driver release
===========================================================================*/
#define ME4000_DRIVER_VERSION 0x10009 // Version 1.00.09
/*=============================================================================
Debug section
===========================================================================*/
#undef ME4000_CALL_DEBUG // Debug function entry and exit
#undef ME4000_ISR_DEBUG // Debug the interrupt service routine
#undef ME4000_PORT_DEBUG // Debug port access
#undef ME4000_DEBUG // General purpose debug masseges
#ifdef ME4000_CALL_DEBUG
#undef CALL_PDEBUG
#define CALL_PDEBUG(fmt, args...) printk(KERN_DEBUG"ME4000:" fmt, ##args)
#else
# define CALL_PDEBUG(fmt, args...) // no debugging, do nothing
#endif
#ifdef ME4000_ISR_DEBUG
#undef ISR_PDEBUG
#define ISR_PDEBUG(fmt, args...) printk(KERN_DEBUG"ME4000:" fmt, ##args)
#else
#define ISR_PDEBUG(fmt, args...) // no debugging, do nothing
#endif
#ifdef ME4000_PORT_DEBUG
#undef PORT_PDEBUG
#define PORT_PDEBUG(fmt, args...) printk(KERN_DEBUG"ME4000:" fmt, ##args)
#else
#define PORT_PDEBUG(fmt, args...) // no debugging, do nothing
#endif
#ifdef ME4000_DEBUG
#undef PDEBUG
#define PDEBUG(fmt, args...) printk(KERN_DEBUG"ME4000:" fmt, ##args)
#else
#define PDEBUG(fmt, args...) // no debugging, do nothing
#endif
/*=============================================================================
PCI vendor and device IDs
===========================================================================*/
#define PCI_VENDOR_ID_MEILHAUS 0x1402
#define PCI_DEVICE_ID_MEILHAUS_ME4650 0x4650 // Low Cost version
#define PCI_DEVICE_ID_MEILHAUS_ME4660 0x4660 // Standard version
#define PCI_DEVICE_ID_MEILHAUS_ME4660I 0x4661 // Isolated version
#define PCI_DEVICE_ID_MEILHAUS_ME4660S 0x4662 // Standard version with Sample and Hold
#define PCI_DEVICE_ID_MEILHAUS_ME4660IS 0x4663 // Isolated version with Sample and Hold
#define PCI_DEVICE_ID_MEILHAUS_ME4670 0x4670 // Standard version
#define PCI_DEVICE_ID_MEILHAUS_ME4670I 0x4671 // Isolated version
#define PCI_DEVICE_ID_MEILHAUS_ME4670S 0x4672 // Standard version with Sample and Hold
#define PCI_DEVICE_ID_MEILHAUS_ME4670IS 0x4673 // Isolated version with Sample and Hold
#define PCI_DEVICE_ID_MEILHAUS_ME4680 0x4680 // Standard version
#define PCI_DEVICE_ID_MEILHAUS_ME4680I 0x4681 // Isolated version
#define PCI_DEVICE_ID_MEILHAUS_ME4680S 0x4682 // Standard version with Sample and Hold
#define PCI_DEVICE_ID_MEILHAUS_ME4680IS 0x4683 // Isolated version with Sample and Hold
/*=============================================================================
Device names, for entries in /proc/..
===========================================================================*/
#define ME4000_NAME "me4000"
#define ME4000_AO_NAME "me4000_ao"
#define ME4000_AI_NAME "me4000_ai"
#define ME4000_DIO_NAME "me4000_dio"
#define ME4000_CNT_NAME "me4000_cnt"
#define ME4000_EXT_INT_NAME "me4000_ext_int"
/*=============================================================================
ME-4000 base register offsets
===========================================================================*/
#define ME4000_AO_00_CTRL_REG 0x00 // R/W
#define ME4000_AO_00_STATUS_REG 0x04 // R/_
#define ME4000_AO_00_FIFO_REG 0x08 // _/W
#define ME4000_AO_00_SINGLE_REG 0x0C // R/W
#define ME4000_AO_00_TIMER_REG 0x10 // _/W
#define ME4000_AO_01_CTRL_REG 0x18 // R/W
#define ME4000_AO_01_STATUS_REG 0x1C // R/_
#define ME4000_AO_01_FIFO_REG 0x20 // _/W
#define ME4000_AO_01_SINGLE_REG 0x24 // R/W
#define ME4000_AO_01_TIMER_REG 0x28 // _/W
#define ME4000_AO_02_CTRL_REG 0x30 // R/W
#define ME4000_AO_02_STATUS_REG 0x34 // R/_
#define ME4000_AO_02_FIFO_REG 0x38 // _/W
#define ME4000_AO_02_SINGLE_REG 0x3C // R/W
#define ME4000_AO_02_TIMER_REG 0x40 // _/W
#define ME4000_AO_03_CTRL_REG 0x48 // R/W
#define ME4000_AO_03_STATUS_REG 0x4C // R/_
#define ME4000_AO_03_FIFO_REG 0x50 // _/W
#define ME4000_AO_03_SINGLE_REG 0x54 // R/W
#define ME4000_AO_03_TIMER_REG 0x58 // _/W
#define ME4000_AI_CTRL_REG 0x74 // _/W
#define ME4000_AI_STATUS_REG 0x74 // R/_
#define ME4000_AI_CHANNEL_LIST_REG 0x78 // _/W
#define ME4000_AI_DATA_REG 0x7C // R/_
#define ME4000_AI_CHAN_TIMER_REG 0x80 // _/W
#define ME4000_AI_CHAN_PRE_TIMER_REG 0x84 // _/W
#define ME4000_AI_SCAN_TIMER_LOW_REG 0x88 // _/W
#define ME4000_AI_SCAN_TIMER_HIGH_REG 0x8C // _/W
#define ME4000_AI_SCAN_PRE_TIMER_LOW_REG 0x90 // _/W
#define ME4000_AI_SCAN_PRE_TIMER_HIGH_REG 0x94 // _/W
#define ME4000_AI_START_REG 0x98 // R/_
#define ME4000_IRQ_STATUS_REG 0x9C // R/_
#define ME4000_DIO_PORT_0_REG 0xA0 // R/W
#define ME4000_DIO_PORT_1_REG 0xA4 // R/W
#define ME4000_DIO_PORT_2_REG 0xA8 // R/W
#define ME4000_DIO_PORT_3_REG 0xAC // R/W
#define ME4000_DIO_DIR_REG 0xB0 // R/W
#define ME4000_AO_LOADSETREG_XX 0xB4 // R/W
#define ME4000_DIO_CTRL_REG 0xB8 // R/W
#define ME4000_AO_DEMUX_ADJUST_REG 0xBC // -/W
#define ME4000_AI_SAMPLE_COUNTER_REG 0xC0 // _/W
/*=============================================================================
Value to adjust Demux
===========================================================================*/
#define ME4000_AO_DEMUX_ADJUST_VALUE 0x4C
/*=============================================================================
Counter base register offsets
===========================================================================*/
#define ME4000_CNT_COUNTER_0_REG 0x00
#define ME4000_CNT_COUNTER_1_REG 0x01
#define ME4000_CNT_COUNTER_2_REG 0x02
#define ME4000_CNT_CTRL_REG 0x03
/*=============================================================================
PLX base register offsets
===========================================================================*/
#define PLX_INTCSR 0x4C // Interrupt control and status register
#define PLX_ICR 0x50 // Initialization control register
/*=============================================================================
Bits for the PLX_ICSR register
===========================================================================*/
#define PLX_INTCSR_LOCAL_INT1_EN 0x01 // If set, local interrupt 1 is enabled (r/w)
#define PLX_INTCSR_LOCAL_INT1_POL 0x02 // If set, local interrupt 1 polarity is active high (r/w)
#define PLX_INTCSR_LOCAL_INT1_STATE 0x04 // If set, local interrupt 1 is active (r/_)
#define PLX_INTCSR_LOCAL_INT2_EN 0x08 // If set, local interrupt 2 is enabled (r/w)
#define PLX_INTCSR_LOCAL_INT2_POL 0x10 // If set, local interrupt 2 polarity is active high (r/w)
#define PLX_INTCSR_LOCAL_INT2_STATE 0x20 // If set, local interrupt 2 is active (r/_)
#define PLX_INTCSR_PCI_INT_EN 0x40 // If set, PCI interrupt is enabled (r/w)
#define PLX_INTCSR_SOFT_INT 0x80 // If set, a software interrupt is generated (r/w)
/*=============================================================================
Bits for the PLX_ICR register
===========================================================================*/
#define PLX_ICR_BIT_EEPROM_CLOCK_SET 0x01000000
#define PLX_ICR_BIT_EEPROM_CHIP_SELECT 0x02000000
#define PLX_ICR_BIT_EEPROM_WRITE 0x04000000
#define PLX_ICR_BIT_EEPROM_READ 0x08000000
#define PLX_ICR_BIT_EEPROM_VALID 0x10000000
#define PLX_ICR_MASK_EEPROM 0x1F000000
#define EEPROM_DELAY 1
/*=============================================================================
Bits for the ME4000_AO_CTRL_REG register
===========================================================================*/
#define ME4000_AO_CTRL_BIT_MODE_0 0x001
#define ME4000_AO_CTRL_BIT_MODE_1 0x002
#define ME4000_AO_CTRL_MASK_MODE 0x003
#define ME4000_AO_CTRL_BIT_STOP 0x004
#define ME4000_AO_CTRL_BIT_ENABLE_FIFO 0x008
#define ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG 0x010
#define ME4000_AO_CTRL_BIT_EX_TRIG_EDGE 0x020
#define ME4000_AO_CTRL_BIT_IMMEDIATE_STOP 0x080
#define ME4000_AO_CTRL_BIT_ENABLE_DO 0x100
#define ME4000_AO_CTRL_BIT_ENABLE_IRQ 0x200
#define ME4000_AO_CTRL_BIT_RESET_IRQ 0x400
#define ME4000_AO_CTRL_BIT_EX_TRIG_BOTH 0x800
/*=============================================================================
Bits for the ME4000_AO_STATUS_REG register
===========================================================================*/
#define ME4000_AO_STATUS_BIT_FSM 0x01
#define ME4000_AO_STATUS_BIT_FF 0x02
#define ME4000_AO_STATUS_BIT_HF 0x04
#define ME4000_AO_STATUS_BIT_EF 0x08
/*=============================================================================
Bits for the ME4000_AI_CTRL_REG register
===========================================================================*/
#define ME4000_AI_CTRL_BIT_MODE_0 0x00000001
#define ME4000_AI_CTRL_BIT_MODE_1 0x00000002
#define ME4000_AI_CTRL_BIT_MODE_2 0x00000004
#define ME4000_AI_CTRL_BIT_SAMPLE_HOLD 0x00000008
#define ME4000_AI_CTRL_BIT_IMMEDIATE_STOP 0x00000010
#define ME4000_AI_CTRL_BIT_STOP 0x00000020
#define ME4000_AI_CTRL_BIT_CHANNEL_FIFO 0x00000040
#define ME4000_AI_CTRL_BIT_DATA_FIFO 0x00000080
#define ME4000_AI_CTRL_BIT_FULLSCALE 0x00000100
#define ME4000_AI_CTRL_BIT_OFFSET 0x00000200
#define ME4000_AI_CTRL_BIT_EX_TRIG_ANALOG 0x00000400
#define ME4000_AI_CTRL_BIT_EX_TRIG 0x00000800
#define ME4000_AI_CTRL_BIT_EX_TRIG_FALLING 0x00001000
#define ME4000_AI_CTRL_BIT_EX_IRQ 0x00002000
#define ME4000_AI_CTRL_BIT_EX_IRQ_RESET 0x00004000
#define ME4000_AI_CTRL_BIT_LE_IRQ 0x00008000
#define ME4000_AI_CTRL_BIT_LE_IRQ_RESET 0x00010000
#define ME4000_AI_CTRL_BIT_HF_IRQ 0x00020000
#define ME4000_AI_CTRL_BIT_HF_IRQ_RESET 0x00040000
#define ME4000_AI_CTRL_BIT_SC_IRQ 0x00080000
#define ME4000_AI_CTRL_BIT_SC_IRQ_RESET 0x00100000
#define ME4000_AI_CTRL_BIT_SC_RELOAD 0x00200000
#define ME4000_AI_CTRL_BIT_EX_TRIG_BOTH 0x80000000
/*=============================================================================
Bits for the ME4000_AI_STATUS_REG register
===========================================================================*/
#define ME4000_AI_STATUS_BIT_EF_CHANNEL 0x00400000
#define ME4000_AI_STATUS_BIT_HF_CHANNEL 0x00800000
#define ME4000_AI_STATUS_BIT_FF_CHANNEL 0x01000000
#define ME4000_AI_STATUS_BIT_EF_DATA 0x02000000
#define ME4000_AI_STATUS_BIT_HF_DATA 0x04000000
#define ME4000_AI_STATUS_BIT_FF_DATA 0x08000000
#define ME4000_AI_STATUS_BIT_LE 0x10000000
#define ME4000_AI_STATUS_BIT_FSM 0x20000000
/*=============================================================================
Bits for the ME4000_IRQ_STATUS_REG register
===========================================================================*/
#define ME4000_IRQ_STATUS_BIT_EX 0x01
#define ME4000_IRQ_STATUS_BIT_LE 0x02
#define ME4000_IRQ_STATUS_BIT_AI_HF 0x04
#define ME4000_IRQ_STATUS_BIT_AO_0_HF 0x08
#define ME4000_IRQ_STATUS_BIT_AO_1_HF 0x10
#define ME4000_IRQ_STATUS_BIT_AO_2_HF 0x20
#define ME4000_IRQ_STATUS_BIT_AO_3_HF 0x40
#define ME4000_IRQ_STATUS_BIT_SC 0x80
/*=============================================================================
Bits for the ME4000_DIO_CTRL_REG register
===========================================================================*/
#define ME4000_DIO_CTRL_BIT_MODE_0 0X0001
#define ME4000_DIO_CTRL_BIT_MODE_1 0X0002
#define ME4000_DIO_CTRL_BIT_MODE_2 0X0004
#define ME4000_DIO_CTRL_BIT_MODE_3 0X0008
#define ME4000_DIO_CTRL_BIT_MODE_4 0X0010
#define ME4000_DIO_CTRL_BIT_MODE_5 0X0020
#define ME4000_DIO_CTRL_BIT_MODE_6 0X0040
#define ME4000_DIO_CTRL_BIT_MODE_7 0X0080
#define ME4000_DIO_CTRL_BIT_FUNCTION_0 0X0100
#define ME4000_DIO_CTRL_BIT_FUNCTION_1 0X0200
#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_0 0X0400
#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_1 0X0800
#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_2 0X1000
#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_3 0X2000
/*=============================================================================
Bits for the ME4000_CNT_CTRL_REG register
===========================================================================*/
#define ME4000_CNT_CTRL_BIT_COUNTER_0 0x00
#define ME4000_CNT_CTRL_BIT_COUNTER_1 0x40
#define ME4000_CNT_CTRL_BIT_COUNTER_2 0x80
#define ME4000_CNT_CTRL_BIT_MODE_0 0x00 // Change state if zero crossing
#define ME4000_CNT_CTRL_BIT_MODE_1 0x02 // Retriggerable One-Shot
#define ME4000_CNT_CTRL_BIT_MODE_2 0x04 // Asymmetrical divider
#define ME4000_CNT_CTRL_BIT_MODE_3 0x06 // Symmetrical divider
#define ME4000_CNT_CTRL_BIT_MODE_4 0x08 // Counter start by software trigger
#define ME4000_CNT_CTRL_BIT_MODE_5 0x0A // Counter start by hardware trigger
/*=============================================================================
Extract information from minor device number
===========================================================================*/
#define AO_BOARD(dev) ((MINOR(dev) >> 6) & 0x3)
#define AO_PORT(dev) ((MINOR(dev) >> 2) & 0xF)
#define AO_MODE(dev) (MINOR(dev) & 0x3)
#define AI_BOARD(dev) ((MINOR(dev) >> 3) & 0x1F)
#define AI_MODE(dev) (MINOR(dev) & 0x7)
#define DIO_BOARD(dev) (MINOR(dev))
#define CNT_BOARD(dev) (MINOR(dev))
#define EXT_INT_BOARD(dev) (MINOR(dev))
/*=============================================================================
Circular buffer used for analog input/output reads/writes.
===========================================================================*/
typedef struct me4000_circ_buf {
s16 *buf;
int volatile head;
int volatile tail;
} me4000_circ_buf_t;
/*=============================================================================
Information about the hardware capabilities
===========================================================================*/
typedef struct me4000_ao_info {
int count;
int fifo_count;
} me4000_ao_info_t;
typedef struct me4000_ai_info {
int count;
int sh_count;
int diff_count;
int ex_trig_analog;
} me4000_ai_info_t;
typedef struct me4000_dio_info {
int count;
} me4000_dio_info_t;
typedef struct me4000_cnt_info {
int count;
} me4000_cnt_info_t;
typedef struct me4000_board {
u16 vendor_id;
u16 device_id;
me4000_ao_info_t ao;
me4000_ai_info_t ai;
me4000_dio_info_t dio;
me4000_cnt_info_t cnt;
} me4000_board_t;
static me4000_board_t me4000_boards[] = {
{PCI_VENDOR_ID_MEILHAUS, 0x4610, {0, 0}, {16, 0, 0, 0}, {4}, {3}},
{PCI_VENDOR_ID_MEILHAUS, 0x4650, {0, 0}, {16, 0, 0, 0}, {4}, {0}},
{PCI_VENDOR_ID_MEILHAUS, 0x4660, {2, 0}, {16, 0, 0, 0}, {4}, {3}},
{PCI_VENDOR_ID_MEILHAUS, 0x4661, {2, 0}, {16, 0, 0, 0}, {4}, {3}},
{PCI_VENDOR_ID_MEILHAUS, 0x4662, {2, 0}, {16, 8, 0, 0}, {4}, {3}},
{PCI_VENDOR_ID_MEILHAUS, 0x4663, {2, 0}, {16, 8, 0, 0}, {4}, {3}},
{PCI_VENDOR_ID_MEILHAUS, 0x4670, {4, 0}, {32, 0, 16, 1}, {4}, {3}},
{PCI_VENDOR_ID_MEILHAUS, 0x4671, {4, 0}, {32, 0, 16, 1}, {4}, {3}},
{PCI_VENDOR_ID_MEILHAUS, 0x4672, {4, 0}, {32, 8, 16, 1}, {4}, {3}},
{PCI_VENDOR_ID_MEILHAUS, 0x4673, {4, 0}, {32, 8, 16, 1}, {4}, {3}},
{PCI_VENDOR_ID_MEILHAUS, 0x4680, {4, 4}, {32, 0, 16, 1}, {4}, {3}},
{PCI_VENDOR_ID_MEILHAUS, 0x4681, {4, 4}, {32, 0, 16, 1}, {4}, {3}},
{PCI_VENDOR_ID_MEILHAUS, 0x4682, {4, 4}, {32, 8, 16, 1}, {4}, {3}},
{PCI_VENDOR_ID_MEILHAUS, 0x4683, {4, 4}, {32, 8, 16, 1}, {4}, {3}},
{0},
};
#define ME4000_BOARD_VERSIONS (sizeof(me4000_boards) / sizeof(me4000_board_t) - 1)
/*=============================================================================
PCI device table.
This is used by modprobe to translate PCI IDs to drivers.
===========================================================================*/
static struct pci_device_id me4000_pci_table[] __devinitdata = {
{PCI_VENDOR_ID_MEILHAUS, 0x4610, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_MEILHAUS, 0x4650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_MEILHAUS, 0x4660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_MEILHAUS, 0x4661, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_MEILHAUS, 0x4662, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_MEILHAUS, 0x4663, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_MEILHAUS, 0x4670, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_MEILHAUS, 0x4671, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_MEILHAUS, 0x4672, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_MEILHAUS, 0x4673, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_MEILHAUS, 0x4680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_MEILHAUS, 0x4681, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_MEILHAUS, 0x4682, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_MEILHAUS, 0x4683, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0}
};
MODULE_DEVICE_TABLE(pci, me4000_pci_table);
/*=============================================================================
Global board and subdevice information structures
===========================================================================*/
typedef struct me4000_info {
struct list_head list; // List of all detected boards
int board_count; // Index of the board after detection
unsigned long plx_regbase; // PLX configuration space base address
unsigned long me4000_regbase; // Base address of the ME4000
unsigned long timer_regbase; // Base address of the timer circuit
unsigned long program_regbase; // Base address to set the program pin for the xilinx
unsigned long plx_regbase_size; // PLX register set space
unsigned long me4000_regbase_size; // ME4000 register set space
unsigned long timer_regbase_size; // Timer circuit register set space
unsigned long program_regbase_size; // Size of program base address of the ME4000
unsigned int serial_no; // Serial number of the board
unsigned char hw_revision; // Hardware revision of the board
unsigned short vendor_id; // Meilhaus vendor id (0x1402)
unsigned short device_id; // Device ID
int pci_bus_no; // PCI bus number
int pci_dev_no; // PCI device number
int pci_func_no; // PCI function number
struct pci_dev *pci_dev_p; // General PCI information
me4000_board_t *board_p; // Holds the board capabilities
unsigned int irq; // IRQ assigned from the PCI BIOS
unsigned int irq_count; // Count of external interrupts
spinlock_t preload_lock; // Guards the analog output preload register
spinlock_t ai_ctrl_lock; // Guards the analog input control register
struct list_head ao_context_list; // List with analog output specific context
struct me4000_ai_context *ai_context; // Analog input specific context
struct me4000_dio_context *dio_context; // Digital I/O specific context
struct me4000_cnt_context *cnt_context; // Counter specific context
struct me4000_ext_int_context *ext_int_context; // External interrupt specific context
} me4000_info_t;
typedef struct me4000_ao_context {
struct list_head list; // linked list of me4000_ao_context_t
int index; // Index in the list
int mode; // Indicates mode (0 = single, 1 = wraparound, 2 = continous)
int dac_in_use; // Indicates if already opend
spinlock_t use_lock; // Guards in_use
spinlock_t int_lock; // Used when locking out interrupts
me4000_circ_buf_t circ_buf; // Circular buffer
wait_queue_head_t wait_queue; // Wait queue to sleep while blocking write
me4000_info_t *board_info;
unsigned int irq; // The irq associated with this ADC
int volatile pipe_flag; // Indicates broken pipe set from me4000_ao_isr()
unsigned long ctrl_reg;
unsigned long status_reg;
unsigned long fifo_reg;
unsigned long single_reg;
unsigned long timer_reg;
unsigned long irq_status_reg;
unsigned long preload_reg;
struct fasync_struct *fasync_p; // Queue for asynchronous notification
} me4000_ao_context_t;
typedef struct me4000_ai_context {
struct list_head list; // linked list of me4000_ai_info_t
int mode; // Indicates mode
int in_use; // Indicates if already opend
spinlock_t use_lock; // Guards in_use
spinlock_t int_lock; // Used when locking out interrupts
int number; // Number of the DAC
unsigned int irq; // The irq associated with this ADC
me4000_circ_buf_t circ_buf; // Circular buffer
wait_queue_head_t wait_queue; // Wait queue to sleep while blocking read
me4000_info_t *board_info;
struct fasync_struct *fasync_p; // Queue for asynchronous notification
unsigned long ctrl_reg;
unsigned long status_reg;
unsigned long channel_list_reg;
unsigned long data_reg;
unsigned long chan_timer_reg;
unsigned long chan_pre_timer_reg;
unsigned long scan_timer_low_reg;
unsigned long scan_timer_high_reg;
unsigned long scan_pre_timer_low_reg;
unsigned long scan_pre_timer_high_reg;
unsigned long start_reg;
unsigned long irq_status_reg;
unsigned long sample_counter_reg;
unsigned long chan_timer;
unsigned long chan_pre_timer;
unsigned long scan_timer_low;
unsigned long scan_timer_high;
unsigned long channel_list_count;
unsigned long sample_counter;
int sample_counter_reload;
} me4000_ai_context_t;
typedef struct me4000_dio_context {
struct list_head list; // linked list of me4000_dio_context_t
int in_use; // Indicates if already opend
spinlock_t use_lock; // Guards in_use
int number;
int dio_count;
me4000_info_t *board_info;
unsigned long dir_reg;
unsigned long ctrl_reg;
unsigned long port_0_reg;
unsigned long port_1_reg;
unsigned long port_2_reg;
unsigned long port_3_reg;
} me4000_dio_context_t;
typedef struct me4000_cnt_context {
struct list_head list; // linked list of me4000_dio_context_t
int in_use; // Indicates if already opend
spinlock_t use_lock; // Guards in_use
int number;
int cnt_count;
me4000_info_t *board_info;
unsigned long ctrl_reg;
unsigned long counter_0_reg;
unsigned long counter_1_reg;
unsigned long counter_2_reg;
} me4000_cnt_context_t;
typedef struct me4000_ext_int_context {
struct list_head list; // linked list of me4000_dio_context_t
int in_use; // Indicates if already opend
spinlock_t use_lock; // Guards in_use
int number;
me4000_info_t *board_info;
unsigned int irq;
unsigned long int_count;
struct fasync_struct *fasync_ptr;
unsigned long ctrl_reg;
unsigned long irq_status_reg;
} me4000_ext_int_context_t;
#endif
/*=============================================================================
Application include section starts here
===========================================================================*/
/*-----------------------------------------------------------------------------
Defines for analog input
----------------------------------------------------------------------------*/
/* General stuff */
#define ME4000_AI_FIFO_COUNT 2048
#define ME4000_AI_MIN_TICKS 66
#define ME4000_AI_MAX_SCAN_TICKS 0xFFFFFFFFFFLL
#define ME4000_AI_BUFFER_SIZE (32 * 1024) // Size in bytes
#define ME4000_AI_BUFFER_COUNT ((ME4000_AI_BUFFER_SIZE) / 2) // Size in values
/* Channel list defines and masks */
#define ME4000_AI_CHANNEL_LIST_COUNT 1024
#define ME4000_AI_LIST_INPUT_SINGLE_ENDED 0x000
#define ME4000_AI_LIST_INPUT_DIFFERENTIAL 0x020
#define ME4000_AI_LIST_RANGE_BIPOLAR_10 0x000
#define ME4000_AI_LIST_RANGE_BIPOLAR_2_5 0x040
#define ME4000_AI_LIST_RANGE_UNIPOLAR_10 0x080
#define ME4000_AI_LIST_RANGE_UNIPOLAR_2_5 0x0C0
#define ME4000_AI_LIST_LAST_ENTRY 0x100
/* External trigger defines */
#define ME4000_AI_TRIGGER_SOFTWARE 0x0 // Use only with API
#define ME4000_AI_TRIGGER_EXT_DIGITAL 0x1
#define ME4000_AI_TRIGGER_EXT_ANALOG 0x2
#define ME4000_AI_TRIGGER_EXT_EDGE_RISING 0x0
#define ME4000_AI_TRIGGER_EXT_EDGE_FALLING 0x1
#define ME4000_AI_TRIGGER_EXT_EDGE_BOTH 0x2
/* Sample and Hold */
#define ME4000_AI_SIMULTANEOUS_DISABLE 0x0
#define ME4000_AI_SIMULTANEOUS_ENABLE 0x1
/* Defines for the Sample Counter */
#define ME4000_AI_SC_RELOAD 0x0
#define ME4000_AI_SC_ONCE 0x1
/* Modes for analog input */
#define ME4000_AI_ACQ_MODE_SINGLE 0x00 // Catch one single value
#define ME4000_AI_ACQ_MODE_SOFTWARE 0x01 // Continous sampling with software start
#define ME4000_AI_ACQ_MODE_EXT 0x02 // Continous sampling with external trigger start
#define ME4000_AI_ACQ_MODE_EXT_SINGLE_VALUE 0x03 // Sample one value by external trigger
#define ME4000_AI_ACQ_MODE_EXT_SINGLE_CHANLIST 0x04 // Sample one channel list by external trigger
/* Staus of AI FSM */
#define ME4000_AI_STATUS_IDLE 0x0
#define ME4000_AI_STATUS_BUSY 0x1
/* Voltages for calibration */
#define ME4000_AI_GAIN_1_UNI_OFFSET 10.0E-3
#define ME4000_AI_GAIN_1_UNI_FULLSCALE 9950.0E-3
#define ME4000_AI_GAIN_1_BI_OFFSET 0.0
#define ME4000_AI_GAIN_1_BI_FULLSCALE 9950.0E-3
#define ME4000_AI_GAIN_4_UNI_OFFSET 10.0E-3
#define ME4000_AI_GAIN_4_UNI_FULLSCALE 2450.0E-3
#define ME4000_AI_GAIN_4_BI_OFFSET 0.0
#define ME4000_AI_GAIN_4_BI_FULLSCALE 2450.0E-3
/* Ideal digits for calibration */
#define ME4000_AI_GAIN_1_UNI_OFFSET_DIGITS (-32702)
#define ME4000_AI_GAIN_1_UNI_FULLSCALE_DIGITS 32440
#define ME4000_AI_GAIN_1_BI_OFFSET_DIGITS 0
#define ME4000_AI_GAIN_1_BI_FULLSCALE_DIGITS 32604
#define ME4000_AI_GAIN_4_UNI_OFFSET_DIGITS (-32505)
#define ME4000_AI_GAIN_4_UNI_FULLSCALE_DIGITS 31457
#define ME4000_AI_GAIN_4_BI_OFFSET_DIGITS 0
#define ME4000_AI_GAIN_4_BI_FULLSCALE_DIGITS 32113
/*-----------------------------------------------------------------------------
Defines for analog output
----------------------------------------------------------------------------*/
/* General stuff */
#define ME4000_AO_FIFO_COUNT (4 * 1024)
#define ME4000_AO_MIN_TICKS 66
#define ME4000_AO_BUFFER_SIZE (32 * 1024) // Size in bytes
#define ME4000_AO_BUFFER_COUNT ((ME4000_AO_BUFFER_SIZE) / 2) // Size in values
/* Conversion modes for analog output */
#define ME4000_AO_CONV_MODE_SINGLE 0x0
#define ME4000_AO_CONV_MODE_WRAPAROUND 0x1
#define ME4000_AO_CONV_MODE_CONTINUOUS 0x2
/* Trigger setup */
#define ME4000_AO_TRIGGER_EXT_EDGE_RISING 0x0
#define ME4000_AO_TRIGGER_EXT_EDGE_FALLING 0x1
#define ME4000_AO_TRIGGER_EXT_EDGE_BOTH 0x2
/* Status of AO FSM */
#define ME4000_AO_STATUS_IDLE 0x0
#define ME4000_AO_STATUS_BUSY 0x1
/*-----------------------------------------------------------------------------
Defines for eeprom
----------------------------------------------------------------------------*/
#define ME4000_EEPROM_CMD_READ 0x180
#define ME4000_EEPROM_CMD_WRITE_ENABLE 0x130
#define ME4000_EEPROM_CMD_WRITE_DISABLE 0x100
#define ME4000_EEPROM_CMD_WRITE 0x1400000
#define ME4000_EEPROM_CMD_LENGTH_READ 9
#define ME4000_EEPROM_CMD_LENGTH_WRITE_ENABLE 9
#define ME4000_EEPROM_CMD_LENGTH_WRITE_DISABLE 9
#define ME4000_EEPROM_CMD_LENGTH_WRITE 25
#define ME4000_EEPROM_ADR_DATE_HIGH 0x32
#define ME4000_EEPROM_ADR_DATE_LOW 0x33
#define ME4000_EEPROM_ADR_GAIN_1_UNI_OFFSET 0x34
#define ME4000_EEPROM_ADR_GAIN_1_UNI_FULLSCALE 0x35
#define ME4000_EEPROM_ADR_GAIN_1_BI_OFFSET 0x36
#define ME4000_EEPROM_ADR_GAIN_1_BI_FULLSCALE 0x37
#define ME4000_EEPROM_ADR_GAIN_1_DIFF_OFFSET 0x38
#define ME4000_EEPROM_ADR_GAIN_1_DIFF_FULLSCALE 0x39
#define ME4000_EEPROM_ADR_GAIN_4_UNI_OFFSET 0x3A
#define ME4000_EEPROM_ADR_GAIN_4_UNI_FULLSCALE 0x3B
#define ME4000_EEPROM_ADR_GAIN_4_BI_OFFSET 0x3C
#define ME4000_EEPROM_ADR_GAIN_4_BI_FULLSCALE 0x3D
#define ME4000_EEPROM_ADR_GAIN_4_DIFF_OFFSET 0x3E
#define ME4000_EEPROM_ADR_GAIN_4_DIFF_FULLSCALE 0x3F
#define ME4000_EEPROM_ADR_LENGTH 6
#define ME4000_EEPROM_DATA_LENGTH 16
/*-----------------------------------------------------------------------------
Defines for digital I/O
----------------------------------------------------------------------------*/
#define ME4000_DIO_PORT_A 0x0
#define ME4000_DIO_PORT_B 0x1
#define ME4000_DIO_PORT_C 0x2
#define ME4000_DIO_PORT_D 0x3
#define ME4000_DIO_PORT_INPUT 0x0
#define ME4000_DIO_PORT_OUTPUT 0x1
#define ME4000_DIO_FIFO_LOW 0x2
#define ME4000_DIO_FIFO_HIGH 0x3
#define ME4000_DIO_FUNCTION_PATTERN 0x0
#define ME4000_DIO_FUNCTION_DEMUX 0x1
#define ME4000_DIO_FUNCTION_MUX 0x2
/*-----------------------------------------------------------------------------
Defines for counters
----------------------------------------------------------------------------*/
#define ME4000_CNT_COUNTER_0 0
#define ME4000_CNT_COUNTER_1 1
#define ME4000_CNT_COUNTER_2 2
#define ME4000_CNT_MODE_0 0 // Change state if zero crossing
#define ME4000_CNT_MODE_1 1 // Retriggerable One-Shot
#define ME4000_CNT_MODE_2 2 // Asymmetrical divider
#define ME4000_CNT_MODE_3 3 // Symmetrical divider
#define ME4000_CNT_MODE_4 4 // Counter start by software trigger
#define ME4000_CNT_MODE_5 5 // Counter start by hardware trigger
/*-----------------------------------------------------------------------------
General type definitions
----------------------------------------------------------------------------*/
typedef struct me4000_user_info {
int board_count; // Index of the board after detection
unsigned long plx_regbase; // PLX configuration space base address
unsigned long me4000_regbase; // Base address of the ME4000
unsigned long plx_regbase_size; // PLX register set space
unsigned long me4000_regbase_size; // ME4000 register set space
unsigned long serial_no; // Serial number of the board
unsigned char hw_revision; // Hardware revision of the board
unsigned short vendor_id; // Meilhaus vendor id (0x1402)
unsigned short device_id; // Device ID
int pci_bus_no; // PCI bus number
int pci_dev_no; // PCI device number
int pci_func_no; // PCI function number
char irq; // IRQ assigned from the PCI BIOS
int irq_count; // Count of external interrupts
int driver_version; // Version of the driver release
int ao_count; // Count of analog output channels
int ao_fifo_count; // Count fo analog output fifos
int ai_count; // Count of analog input channels
int ai_sh_count; // Count of sample and hold devices
int ai_ex_trig_analog; // Flag to indicate if analogous external trigger is available
int dio_count; // Count of digital I/O ports
int cnt_count; // Count of counters
} me4000_user_info_t;
/*-----------------------------------------------------------------------------
Type definitions for analog output
----------------------------------------------------------------------------*/
typedef struct me4000_ao_channel_list {
unsigned long count;
unsigned long *list;
} me4000_ao_channel_list_t;
/*-----------------------------------------------------------------------------
Type definitions for analog input
----------------------------------------------------------------------------*/
typedef struct me4000_ai_channel_list {
unsigned long count;
unsigned long *list;
} me4000_ai_channel_list_t;
typedef struct me4000_ai_timer {
unsigned long pre_chan;
unsigned long chan;
unsigned long scan_low;
unsigned long scan_high;
} me4000_ai_timer_t;
typedef struct me4000_ai_config {
me4000_ai_timer_t timer;
me4000_ai_channel_list_t channel_list;
int sh;
} me4000_ai_config_t;
typedef struct me4000_ai_single {
int channel;
int range;
int mode;
short value;
unsigned long timeout;
} me4000_ai_single_t;
typedef struct me4000_ai_trigger {
int mode;
int edge;
} me4000_ai_trigger_t;
typedef struct me4000_ai_sc {
unsigned long value;
int reload;
} me4000_ai_sc_t;
/*-----------------------------------------------------------------------------
Type definitions for eeprom
----------------------------------------------------------------------------*/
typedef struct me4000_eeprom {
unsigned long date;
short uni_10_offset;
short uni_10_fullscale;
short uni_2_5_offset;
short uni_2_5_fullscale;
short bi_10_offset;
short bi_10_fullscale;
short bi_2_5_offset;
short bi_2_5_fullscale;
short diff_10_offset;
short diff_10_fullscale;
short diff_2_5_offset;
short diff_2_5_fullscale;
} me4000_eeprom_t;
/*-----------------------------------------------------------------------------
Type definitions for digital I/O
----------------------------------------------------------------------------*/
typedef struct me4000_dio_config {
int port;
int mode;
int function;
} me4000_dio_config_t;
typedef struct me4000_dio_byte {
int port;
unsigned char byte;
} me4000_dio_byte_t;
/*-----------------------------------------------------------------------------
Type definitions for counters
----------------------------------------------------------------------------*/
typedef struct me4000_cnt {
int counter;
unsigned short value;
} me4000_cnt_t;
typedef struct me4000_cnt_config {
int counter;
int mode;
} me4000_cnt_config_t;
/*-----------------------------------------------------------------------------
Type definitions for external interrupt
----------------------------------------------------------------------------*/
typedef struct {
int int1_count;
int int2_count;
} me4000_int_type;
/*-----------------------------------------------------------------------------
The ioctls of the board
----------------------------------------------------------------------------*/
#define ME4000_IOCTL_MAXNR 50
#define ME4000_MAGIC 'y'
#define ME4000_GET_USER_INFO _IOR (ME4000_MAGIC, 0, me4000_user_info_t)
#define ME4000_AO_START _IOW (ME4000_MAGIC, 1, unsigned long)
#define ME4000_AO_STOP _IO (ME4000_MAGIC, 2)
#define ME4000_AO_IMMEDIATE_STOP _IO (ME4000_MAGIC, 3)
#define ME4000_AO_RESET _IO (ME4000_MAGIC, 4)
#define ME4000_AO_PRELOAD _IO (ME4000_MAGIC, 5)
#define ME4000_AO_PRELOAD_UPDATE _IO (ME4000_MAGIC, 6)
#define ME4000_AO_EX_TRIG_ENABLE _IO (ME4000_MAGIC, 7)
#define ME4000_AO_EX_TRIG_DISABLE _IO (ME4000_MAGIC, 8)
#define ME4000_AO_EX_TRIG_SETUP _IOW (ME4000_MAGIC, 9, int)
#define ME4000_AO_TIMER_SET_DIVISOR _IOW (ME4000_MAGIC, 10, unsigned long)
#define ME4000_AO_ENABLE_DO _IO (ME4000_MAGIC, 11)
#define ME4000_AO_DISABLE_DO _IO (ME4000_MAGIC, 12)
#define ME4000_AO_FSM_STATE _IOR (ME4000_MAGIC, 13, int)
#define ME4000_AI_SINGLE _IOR (ME4000_MAGIC, 14, me4000_ai_single_t)
#define ME4000_AI_START _IOW (ME4000_MAGIC, 15, unsigned long)
#define ME4000_AI_STOP _IO (ME4000_MAGIC, 16)
#define ME4000_AI_IMMEDIATE_STOP _IO (ME4000_MAGIC, 17)
#define ME4000_AI_EX_TRIG_ENABLE _IO (ME4000_MAGIC, 18)
#define ME4000_AI_EX_TRIG_DISABLE _IO (ME4000_MAGIC, 19)
#define ME4000_AI_EX_TRIG_SETUP _IOW (ME4000_MAGIC, 20, me4000_ai_trigger_t)
#define ME4000_AI_CONFIG _IOW (ME4000_MAGIC, 21, me4000_ai_config_t)
#define ME4000_AI_SC_SETUP _IOW (ME4000_MAGIC, 22, me4000_ai_sc_t)
#define ME4000_AI_FSM_STATE _IOR (ME4000_MAGIC, 23, int)
#define ME4000_DIO_CONFIG _IOW (ME4000_MAGIC, 24, me4000_dio_config_t)
#define ME4000_DIO_GET_BYTE _IOR (ME4000_MAGIC, 25, me4000_dio_byte_t)
#define ME4000_DIO_SET_BYTE _IOW (ME4000_MAGIC, 26, me4000_dio_byte_t)
#define ME4000_DIO_RESET _IO (ME4000_MAGIC, 27)
#define ME4000_CNT_READ _IOR (ME4000_MAGIC, 28, me4000_cnt_t)
#define ME4000_CNT_WRITE _IOW (ME4000_MAGIC, 29, me4000_cnt_t)
#define ME4000_CNT_CONFIG _IOW (ME4000_MAGIC, 30, me4000_cnt_config_t)
#define ME4000_CNT_RESET _IO (ME4000_MAGIC, 31)
#define ME4000_EXT_INT_DISABLE _IO (ME4000_MAGIC, 32)
#define ME4000_EXT_INT_ENABLE _IO (ME4000_MAGIC, 33)
#define ME4000_EXT_INT_COUNT _IOR (ME4000_MAGIC, 34, int)
#define ME4000_AI_OFFSET_ENABLE _IO (ME4000_MAGIC, 35)
#define ME4000_AI_OFFSET_DISABLE _IO (ME4000_MAGIC, 36)
#define ME4000_AI_FULLSCALE_ENABLE _IO (ME4000_MAGIC, 37)
#define ME4000_AI_FULLSCALE_DISABLE _IO (ME4000_MAGIC, 38)
#define ME4000_AI_EEPROM_READ _IOR (ME4000_MAGIC, 39, me4000_eeprom_t)
#define ME4000_AI_EEPROM_WRITE _IOW (ME4000_MAGIC, 40, me4000_eeprom_t)
#define ME4000_AO_SIMULTANEOUS_EX_TRIG _IO (ME4000_MAGIC, 41)
#define ME4000_AO_SIMULTANEOUS_SW _IO (ME4000_MAGIC, 42)
#define ME4000_AO_SIMULTANEOUS_DISABLE _IO (ME4000_MAGIC, 43)
#define ME4000_AO_SIMULTANEOUS_UPDATE _IOW (ME4000_MAGIC, 44, me4000_ao_channel_list_t)
#define ME4000_AO_SYNCHRONOUS_EX_TRIG _IO (ME4000_MAGIC, 45)
#define ME4000_AO_SYNCHRONOUS_SW _IO (ME4000_MAGIC, 46)
#define ME4000_AO_SYNCHRONOUS_DISABLE _IO (ME4000_MAGIC, 47)
#define ME4000_AO_EX_TRIG_TIMEOUT _IOW (ME4000_MAGIC, 48, unsigned long)
#define ME4000_AO_GET_FREE_BUFFER _IOR (ME4000_MAGIC, 49, unsigned long)
#define ME4000_AI_GET_COUNT_BUFFER _IOR (ME4000_MAGIC, 50, unsigned long)
#endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册