--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/me8100.c Wed Jan 16 14:01:55 2002 +0100
@@ -0,0 +1,2079 @@
+/* me8100.c */
+/* Device driver for Meilhaus me8100 board.
+ * ========================================
+ *
+ * Copyright (C) 2001 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.
+ */
+
+
+
+/*
+ * Source File : me8100.c
+ * Destination : me8100.o
+ * Author : GG (Guenter Gebhardt)
+ *
+ * File History: Version Date Editor Action
+ *---------------------------------------------------------------------
+ * 1.00.00 01.01.10 GG first release
+ *
+ * 1.00.01 01.02.14 GG Add new ioctls:
+ * get_board_info
+ * get_int count
+ *
+ * 1.01.00 01.10.08 GG Port to Kernel 2.4
+ *---------------------------------------------------------------------
+ *
+ * Description:
+ *
+ * Contains the entire driver-module code for the
+ * Meilhaus ME-8100 board. However, the definitions and type
+ * declarations are kept in the headerfile called me8100.h.
+ *
+ */
+
+
+/*
+ * User application could also include the kernel header files. But the
+ * real kernel functions are protected by #ifdef __KERNEL__.
+ */
+#ifndef __KERNEL__
+# define __KERNEL__
+#endif
+
+
+/*
+ * This must be defined before module.h is included. Not needed, when
+ * it is a built in driver.
+ */
+#define MODULE
+
+
+/*
+ * If we are compiling for a multiprocessor system,
+ * we have to define this.
+ */
+#include <linux/config.h>
+#ifdef CONFIG_SMP
+# define __SMP__
+#endif
+
+
+/*
+ * Basic facilities for modules.
+ * Defines __module_kernel_version.
+ * Includes <linux/version.h> (UTS_RELEASE, LINUX_VERSION_CODE, ...)
+ */
+#include <linux/module.h>
+
+/*
+ * Needed for the registration of I/O and MEMORY regions.
+ * (request_region, ...)
+ */
+#include <linux/ioport.h>
+
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/malloc.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/poll.h>
+#include <linux/vmalloc.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+
+
+/* Compatibility file for kernels from 2.0 up to 2.4 */
+#include "sysdep.h"
+
+
+/* Include-File for the Meilhaus ME-8100 I/O board */
+#include "me8100.h"
+
+
+/* Board specific data are kept global */
+static me8100_info_type info_vec[SORT_COUNT * ME8100_MAX_DEVICES];
+
+
+/* Number of boards, detected from the BIOS */
+static int me8100_board_count;
+
+
+/* Major Device Number. 0 means to get it automatically from the System */
+static unsigned int major = 0;
+
+
+/* Prototypes */
+static int me8100_open(struct inode *, struct file *);
+static int me8100_release(struct inode *, struct file *);
+static int me8100_ioctl(struct inode *, struct file *,
+ unsigned int , unsigned long );
+static int me8100_fasync(int, struct file *, int);
+static void me8100_isr(int, void *, struct pt_regs *);
+
+static int me8100_init_board(me8100_info_type *, struct pci_dev *);
+static int me8100_reset_board(me8100_info_type *);
+
+static int me8100_read_id_a(unsigned short *, me8100_info_type *);
+static int me8100_write_ctrl_a(unsigned short *, me8100_info_type *);
+static int me8100_res_int_a(me8100_info_type *);
+static int me8100_read_di_a(unsigned short *, me8100_info_type *);
+static int me8100_write_do_a(unsigned short *, me8100_info_type *);
+static int me8100_write_pattern_a(unsigned short *, me8100_info_type *);
+static int me8100_write_mask_a(unsigned short *, me8100_info_type *);
+static int me8100_read_int_di_a(unsigned short *, me8100_info_type *);
+
+static int me8100_read_id_b(unsigned short *, me8100_info_type *);
+static int me8100_write_ctrl_b(unsigned short *, me8100_info_type *);
+static int me8100_res_int_b(me8100_info_type *);
+static int me8100_read_di_b(unsigned short *, me8100_info_type *);
+static int me8100_write_do_b(unsigned short *, me8100_info_type *);
+static int me8100_write_pattern_b(unsigned short *, me8100_info_type *);
+static int me8100_write_mask_b(unsigned short *, me8100_info_type *);
+static int me8100_read_int_di_b(unsigned short *, me8100_info_type *);
+
+static int me8100_write_counter_0(unsigned char *, me8100_info_type *);
+static int me8100_write_counter_1(unsigned char *, me8100_info_type *);
+static int me8100_write_counter_2(unsigned char *, me8100_info_type *);
+static int me8100_read_counter_0(unsigned char *, me8100_info_type *);
+static int me8100_read_counter_1(unsigned char *, me8100_info_type *);
+static int me8100_read_counter_2(unsigned char *, me8100_info_type *);
+static int me8100_setup_counter(unsigned char *, me8100_info_type *);
+
+static int me8100_get_serial(unsigned int *, me8100_info_type *);
+static int me8100_get_name(me8100_version_enum_type *, me8100_info_type *);
+static int me8100_int_occur(me8100_int_occur_type *, me8100_info_type *);
+static int me8100_setup_icsr(unsigned char *, me8100_info_type *);
+static int me8100_read_icsr(unsigned char *, me8100_info_type *);
+static int me8100_get_board_info(me8100_info_type *, me8100_info_type *);
+static int me8100_get_int_count(me8100_int_occur_type *, me8100_info_type *);
+
+
+/* File operations provided by the driver */
+static struct file_operations me8100_file_operations = {
+#ifdef LINUX_24
+ THIS_MODULE, /* owner */
+#endif
+ NULL, /* lseek() */
+ NULL, /* read() */
+ NULL, /* write() */
+ NULL, /* readdir() */
+ NULL, /* poll() */
+ me8100_ioctl, /* ioctl() */
+ NULL, /* mmap() */
+ me8100_open, /* open() */
+ NULL, /* flush() */
+ me8100_release, /* release() */
+ NULL, /* fsync() */
+ me8100_fasync, /* fasync() */
+ NULL, /* check_media_change()*/
+ NULL, /* revalidate() */
+ NULL /* lock() */
+};
+
+
+
+/*
+ * Routine:
+ * init_module
+ *
+ * Description:
+ * This function is executed from the system, when the driver is loaded.
+ * Actions performed:
+ * - Searches for PCI hardware.
+ * - Initializes detected ME8100 boards with me8100_init_board().
+ * - Installs the driver in the system with register_chrdev().
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+#ifdef CONFIG_PCI
+int init_module(void){
+ int result;
+ unsigned short board_count = 0;
+ unsigned short sort_count;
+ struct pci_dev *pci_dev_ptr = NULL;
+
+ PDEBUG("init_module() is executed\n");
+
+ /* Set the board context to 0 */
+ memset(&info_vec, 0, sizeof(info_vec));
+
+ if (pci_present()){
+ /* Search for ME8100_A boards */
+ for(sort_count = 0;
+ sort_count < ME8100_MAX_DEVICES;
+ sort_count++, board_count++){
+ pci_dev_ptr = pci_find_device(PCI_VENDOR_ID_MEILHAUS,
+ PCI_DEVICE_ID_MEILHAUS_ME8100_A,
+ pci_dev_ptr);
+ if(!pci_dev_ptr)
+ break;
+
+ PDEBUG("init_module():ME8100_A found\n");
+ info_vec[board_count].version = ME8100_A;
+ info_vec[board_count].board_count = board_count;
+
+ result = me8100_init_board(&info_vec[board_count], pci_dev_ptr);
+ if (result){
+ printk(KERN_ERR"ME8100:init_module():Can't init board\n");
+ return result;
+ }
+ }
+
+ /* Search for ME8100_B boards */
+ for(sort_count = 0;
+ sort_count < ME8100_MAX_DEVICES;
+ sort_count++, board_count++){
+ pci_dev_ptr = pci_find_device(PCI_VENDOR_ID_MEILHAUS,
+ PCI_DEVICE_ID_MEILHAUS_ME8100_B,
+ pci_dev_ptr);
+ if(!pci_dev_ptr)
+ break;
+
+ PDEBUG("init_module():ME8100_B found\n");
+ info_vec[board_count].version = ME8100_B;
+ info_vec[board_count].board_count = board_count;
+
+ result = me8100_init_board(&info_vec[board_count], pci_dev_ptr);
+ if (result){
+ printk(KERN_ERR"ME8100:init_module():Can't init board\n");
+ return result;
+ }
+ }
+
+ if (board_count == 0){
+ printk(KERN_ERR"ME8100:init_module():No PCI-Devices found\n");
+ return -ENODEV;
+ }
+
+ me8100_board_count = board_count;
+ PDEBUG("init_module(): %d Boards found\n", me8100_board_count);
+
+ /*
+ * Register the driver in the system with major number = 0.
+ * This means that the major number is automatically assigned
+ * from the kernel and returned as result from register_chrdev().
+ */
+ result = register_chrdev(major, ME8100_NAME, &me8100_file_operations);
+ if (result < 0){
+ printk(KERN_ERR"ME8100:init_module():Can't get major no\n");
+ return result;
+ }
+ else{
+ major = result;
+ PDEBUG("init_module():Major = %d\n", major);
+ }
+ }
+ else{
+ printk(KERN_ERR"ME8100:init_module():No PCI-BIOS present !\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+#else
+return -ENODEV
+#endif
+
+
+
+/*
+ * Routine:
+ * me8100_init_board
+ *
+ * Description:
+ * This function initializes the detected me8100 boards.
+ * Actions performed:
+ * - Get the baseaddresses of the PLX and the ME8100.
+ * - If PLX bug detected, start workaround.
+ * - Initializes the device info structure.
+ * - Resets the board with me8100_reset_board().
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *pci_dev_ptr struct pci_dev read List with all pci devices.
+ * *info me8100_info_type read Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ *
+ * Modification:
+ * 01.09.14 Don't get baseaddresses from struct pci_dev,
+ * for compatibility. (GG)
+ *
+ */
+static int me8100_init_board(me8100_info_type *info,
+ struct pci_dev *pci_dev_ptr){
+ int result = 0;
+ unsigned int plx_regbase_tmp;
+ unsigned int me8100_regbase_tmp;
+ unsigned int swap_regbase_tmp;
+ unsigned int regbase_tmp;
+
+ PDEBUG("me8100_init_board() is executed\n");
+
+
+ /*--------------------------- plx regbase ---------------------------------*/
+
+ result = pci_read_config_dword(pci_dev_ptr,
+ PCI_BASE_ADDRESS_1,
+ &plx_regbase_tmp);
+ if(result != PCIBIOS_SUCCESSFUL){
+ printk(KERN_ERR"ME8100:Can't get PCI_BASE_ADDRESS_1\n");
+ return result;
+ }
+ PDEBUG("me8100_init_board():PCI base 0 = 0x%04X\n", plx_regbase_tmp);
+
+ result = pci_read_config_dword(pci_dev_ptr,
+ PCI_BASE_ADDRESS_5,
+ &swap_regbase_tmp);
+ if(result != PCIBIOS_SUCCESSFUL){
+ printk(KERN_ERR"ME8100:Can't get PCI_BASE_ADDRESS_5\n");
+ return result;
+ }
+ PDEBUG("me8100_init_board():PCI base 5 = 0x%04X\n", swap_regbase_tmp);
+
+ if(!swap_regbase_tmp){
+ printk(KERN_WARNING"ME8100:me8100_init_board:Swap not present\n");
+ }
+
+ /*
+ * This is the PLX bug workaround.
+ * If bit 7 is set in the plx_regbase,
+ * the plx registers maybe not readable.
+ */
+ if(plx_regbase_tmp & 0x0080){
+ printk(KERN_WARNING"ME8100:me8100_init_board():PLX-BUG detected\n");
+
+ if(PLX_WORKAROUND_ENABLE){
+ if(swap_regbase_tmp){
+ regbase_tmp = plx_regbase_tmp;
+ plx_regbase_tmp = swap_regbase_tmp;
+ swap_regbase_tmp = regbase_tmp;
+ result = pci_write_config_dword(pci_dev_ptr,
+ PCI_BASE_ADDRESS_1,
+ plx_regbase_tmp);
+ if(result != PCIBIOS_SUCCESSFUL)
+ return result;
+
+ result = pci_write_config_dword(pci_dev_ptr,
+ PCI_BASE_ADDRESS_5,
+ swap_regbase_tmp);
+ if(result != PCIBIOS_SUCCESSFUL)
+ return result;
+ }
+ else{
+ plx_regbase_tmp -= 0x80;
+ result = pci_write_config_dword(pci_dev_ptr,
+ PCI_BASE_ADDRESS_1,
+ plx_regbase_tmp);
+ if(result != PCIBIOS_SUCCESSFUL)
+ return result;
+ }
+ }
+ }
+
+ if(!(plx_regbase_tmp & PCI_BASE_ADDRESS_SPACE)){
+ printk(KERN_ERR"ME8100:me8100_init_board():PLX space is not MEM\n");
+ return -EIO;
+ }
+ info->plx_regbase_size = PLX_BASE_SIZE;
+ info->plx_regbase = plx_regbase_tmp & PCI_BASE_ADDRESS_IO_MASK;
+ PDEBUG("me8100_init_board():IO at 0x%04X\n", info->plx_regbase);
+
+
+ /*--------------------------- me8100 regbase ------------------------------*/
+
+ result = pci_read_config_dword(pci_dev_ptr,
+ PCI_BASE_ADDRESS_2,
+ &me8100_regbase_tmp);
+ if(result != PCIBIOS_SUCCESSFUL){
+ printk(KERN_ERR"ME8100:Can't get PCI_BASE_ADDRESS_2\n");
+ return result;
+ }
+ PDEBUG("me8100_init_board():PCI base 2 = 0x%04X\n", me8100_regbase_tmp);
+
+ if(!(me8100_regbase_tmp & PCI_BASE_ADDRESS_SPACE)){
+ printk(KERN_ERR"ME8100:me8100_init_board():ME8100 space is not IO\n");
+ return -EIO;
+ }
+ info->me8100_regbase_size = ME8100_BASE_SIZE;
+ info->me8100_regbase = me8100_regbase_tmp & PCI_BASE_ADDRESS_IO_MASK;
+ PDEBUG("me8100_init_board():IO at 0x%04X\n", info->me8100_regbase);
+
+
+ /*--------------------------- init device info ----------------------------*/
+
+ result = pci_read_config_dword(pci_dev_ptr, 0x2C, &info->serial_no);
+ if(result != PCIBIOS_SUCCESSFUL){
+ printk(KERN_ERR"ME8100:me8100_init_board:Can't get serial_no\n");
+ return result;
+ }
+ PDEBUG("me8100_init_board():serial_no = 0x%08X\n", info->serial_no);
+
+ result = pci_read_config_byte(pci_dev_ptr, 0x08, &info->hw_revision);
+ if(result != PCIBIOS_SUCCESSFUL){
+ printk(KERN_ERR"ME8100:me8100_init_board():Can't get hw_revision\n");
+ return result;
+ }
+ PDEBUG("me8100_init_board():hw_revision = 0x%02X\n", info->hw_revision);
+
+ info->vendor_id = pci_dev_ptr->vendor;
+ PDEBUG("me8100_init_board():vendor_id = 0x%04X\n", info->vendor_id);
+
+ info->device_id = pci_dev_ptr->device;
+ PDEBUG("me8100_init_board():device_id = 0x%04X\n", info->device_id);
+
+ info->pci_dev_no = PCI_SLOT(pci_dev_ptr->devfn);
+ PDEBUG("me8100_init_board():pci_dev_no = 0x%02X\n", info->pci_dev_no);
+
+ info->pci_func_no = PCI_FUNC(pci_dev_ptr->devfn);
+ PDEBUG("me8100_init_board():pci_func_no = 0x%02X\n", info->pci_func_no);
+
+ info->pci_bus_no = pci_dev_ptr->bus->number;
+ PDEBUG("me8100_init_board():pci_bus_no = 0x%02X\n", info->pci_bus_no);
+
+ info->int_line = pci_dev_ptr->irq;
+ PDEBUG("me8100_init_board():int_line = %d\n", info->int_line);
+
+ info->int_count_1 = 0;
+ info->int_count_2 = 0;
+ info->int1 = 0;
+ info->int2 = 0;
+ info->file_ptr = NULL;
+ info->board_in_use = 0;
+ spin_lock_init(&info->use_lock);
+
+
+ /*--------------------------- Reset the board -----------------------------*/
+
+ result = me8100_reset_board(info);
+ if(result){
+ printk(KERN_ERR"ME8100:me8100_init_board():Can't reset board\n");
+ return result;
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * Routine:
+ * me8100_reset_board
+ *
+ * Description:
+ * This function resets the ME-81000 board.
+ * Actions performed:
+ * - Disables the interruptlogic of the plx.
+ * - Disables the interrupts on the ME-8100.
+ * - Sets the digital I/O to high impedance.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * board_count int read Index of the detected board
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_reset_board(me8100_info_type *info){
+ unsigned char icsr = 0x12;
+
+ PDEBUG("me8100_reset_board() is executed\n");
+
+ /* Disable the Interrupt logic of the plx */
+ PDEBUG("me8100_reset_board(): plx_mode = 0x%X\n", icsr);
+ outb(icsr, info->plx_regbase + PLX_ICSR);
+
+ /* Ports to high impedance, interrupts deactivated */
+ outw(0x00, info->me8100_regbase + ME8100_CTRL_REG_A);
+ outw(0x0000, info->me8100_regbase + ME8100_CTRL_REG_B);
+
+ /* Reset any pending interrupt */
+ inw(info->me8100_regbase + ME8100_RES_INT_REG_A);
+ inw(info->me8100_regbase + ME8100_RES_INT_REG_B);
+
+ return 0;
+}
+
+
+
+/*
+ * Routine:
+ * me8100_open
+ *
+ * Description:
+ * Function, which is executed, when a userprogramm makes the syscall
+ * open.
+ * Actions performed:
+ * - It installs the drivers interrupt service routine
+ * me8100_isr in the system.
+ * - It remarks the board as used in the global data structure.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *inode_ptr struct inode read Pointer to device inode.
+ * *file_ptr struct file read Ponnter to file structure.
+ *
+ *--------------------------------------------------------------------------
+ *
+ * Result:
+ * On success the return value is 0 else failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ * 01.10.04 Guard board_in_use with spin_lock, cause of race condition
+ * when compiling for SMP.
+ */
+static int me8100_open(struct inode *inode_ptr, struct file *file_ptr){
+ int minor = 0;
+ int err = 0;
+
+ PDEBUG("me8100_open() is executed\n");
+
+ minor = MINOR(inode_ptr->i_rdev);
+
+ if(minor >= me8100_board_count){
+ printk(KERN_ERR"ME8100:me8100_open():Board %d doesn't exist\n", minor);
+ return -ENODEV;
+ }
+
+ spin_lock(&info_vec[minor].use_lock);
+ if(info_vec[minor].board_in_use){
+ printk(KERN_ERR"ME8100:me8100_open():Board %d already in use\n", minor);
+ spin_unlock(&info_vec[minor].use_lock);
+ return -EBUSY;
+ }
+ info_vec[minor].board_in_use = 1;
+ spin_unlock(&info_vec[minor].use_lock);
+
+ info_vec[minor].file_ptr = file_ptr;
+
+ err = request_irq(info_vec[minor].int_line,
+ me8100_isr,
+ SA_INTERRUPT | SA_SHIRQ,
+ ME8100_NAME,
+ (void *)&info_vec[minor]);
+ if(err){
+ printk(KERN_ERR"ME8100:me8100_open():Can't get interrupt line");
+ return err;
+ }
+
+ MOD_INC_USE_COUNT;
+
+ return 0;
+}
+
+
+
+/*
+ * Routine:
+ * me8100_release
+ *
+ * Description:
+ * Function, which is executed, when the userprogramm makes the syscall
+ * close. First it resets the board and marks the board as unused in the
+ * global info_vec. Then it frees the Interrupt requested
+ * in me8100_open. After that the fasync queue probably installed is
+ * deleted.
+ * At last the usecount of the path is decremented.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * inode_ptr struct inode * read pointer to the inode structure of
+ * the system
+ * file_ptr struct file * read pointer to the file structure of
+ * the system
+ *
+ * Result:
+ * On success the return value is 0, else is failure
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_release(struct inode *inode_ptr, struct file *file_ptr){
+ int minor = 0;
+ int err = 0;
+
+ PDEBUG("me8100_release() is executed\n");
+
+ minor = MINOR(inode_ptr->i_rdev);
+
+ err = me8100_reset_board(&info_vec[minor]);
+ if(err){
+ printk(KERN_ERR"ME8100:me8100_release():Can't reset");
+ return err;
+ }
+
+ free_irq(info_vec[minor].int_line, (void *) &info_vec[minor]);
+
+ /* Delete the fasync structure and free memory */
+ me8100_fasync(0, file_ptr, 0);
+
+ info_vec[minor].board_in_use = 0;
+
+ MOD_DEC_USE_COUNT;
+ PDEBUG("me8100_release() is leaved\n");
+ return 0;
+}
+
+
+
+/*
+ * Routine:
+ * me8100_ioctl
+ *
+ * Description:
+ * Function, which prvides the functionality of the ME8100 board. This
+ * function is executed, when a user program executes the systemcall
+ * ioctl. It checks if the service requested is valid and calls the
+ * appropriate routine to handle the request.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * inode_ptr struct inode * read pointer to the inode structure of
+ * the system
+ * file_ptr struct file * read pointer to the file structure of
+ * the system
+ * service unsigned int read requested service
+ * arg unsigned long r/w address of the structure with
+ * user data and parameters
+ *
+ * Result:
+ * On success the return value is 0, else is failure
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ * 01.02.14 GG Add new ioctls:
+ * get_board_info
+ * get_int count
+ */
+static int me8100_ioctl(struct inode * inode_ptr,
+ struct file *file_ptr,
+ unsigned int service,
+ unsigned long arg){
+
+ int minor = 0;
+
+ PDEBUG("me8100_ioctl() is executed\n");
+
+ minor = MINOR(inode_ptr->i_rdev);
+
+ if(_IOC_TYPE(service) != ME8100_MAGIC){
+ printk(KERN_ERR"ME8100:Invalid ME8100_MAGIC\n");
+ return -EINVAL;
+ }
+ if(_IOC_NR(service) > ME8100_IOCTL_MAXNR){
+ printk(KERN_ERR"ME8100:Service number ME8100 to high\n");
+ return -EINVAL;
+ }
+
+ switch(service){
+ case ME8100_READ_ID_A:
+ return me8100_read_id_a((unsigned short *) arg, &info_vec[minor]);
+ case ME8100_WRITE_CTRL_A:
+ return me8100_write_ctrl_a((unsigned short *) arg, &info_vec[minor]);
+ case ME8100_RES_INT_A:
+ return me8100_res_int_a(&info_vec[minor]);
+ case ME8100_READ_DI_A:
+ return me8100_read_di_a((unsigned short *) arg, &info_vec[minor]);
+ case ME8100_WRITE_DO_A:
+ return me8100_write_do_a((unsigned short *) arg, &info_vec[minor]);
+ case ME8100_WRITE_PATTERN_A:
+ return me8100_write_pattern_a((unsigned short *) arg, &info_vec[minor]);
+ case ME8100_WRITE_MASK_A:
+ return me8100_write_mask_a((unsigned short *) arg, &info_vec[minor]);
+ case ME8100_READ_INT_DI_A:
+ return me8100_read_int_di_a((unsigned short *) arg, &info_vec[minor]);
+ case ME8100_READ_ID_B:
+ return me8100_read_id_b((unsigned short *) arg, &info_vec[minor]);
+ case ME8100_WRITE_CTRL_B:
+ return me8100_write_ctrl_b((unsigned short *) arg, &info_vec[minor]);
+ case ME8100_RES_INT_B:
+ return me8100_res_int_b(&info_vec[minor]);
+ case ME8100_READ_DI_B:
+ return me8100_read_di_b((unsigned short *) arg, &info_vec[minor]);
+ case ME8100_WRITE_DO_B:
+ return me8100_write_do_b((unsigned short *) arg, &info_vec[minor]);
+ case ME8100_WRITE_PATTERN_B:
+ return me8100_write_pattern_b((unsigned short *) arg, &info_vec[minor]);
+ case ME8100_WRITE_MASK_B:
+ return me8100_write_mask_b((unsigned short *) arg, &info_vec[minor]);
+ case ME8100_READ_INT_DI_B:
+ return me8100_read_int_di_b((unsigned short *) arg, &info_vec[minor]);
+ case ME8100_WRITE_COUNTER_0:
+ return me8100_write_counter_0((unsigned char *) arg, &info_vec[minor]);
+ case ME8100_WRITE_COUNTER_1:
+ return me8100_write_counter_1((unsigned char *) arg, &info_vec[minor]);
+ case ME8100_WRITE_COUNTER_2:
+ return me8100_write_counter_2((unsigned char *) arg, &info_vec[minor]);
+ case ME8100_READ_COUNTER_0:
+ return me8100_read_counter_0((unsigned char *) arg, &info_vec[minor]);
+ case ME8100_READ_COUNTER_1:
+ return me8100_read_counter_1((unsigned char *) arg, &info_vec[minor]);
+ case ME8100_READ_COUNTER_2:
+ return me8100_read_counter_2((unsigned char *) arg, &info_vec[minor]);
+ case ME8100_SETUP_COUNTER:
+ return me8100_setup_counter((unsigned char *) arg, &info_vec[minor]);
+ case ME8100_GET_SERIAL:
+ return me8100_get_serial((unsigned int *) arg, &info_vec[minor]);
+ case ME8100_GET_NAME:
+ return me8100_get_name((me8100_version_enum_type *) arg, &info_vec[minor]);
+ case ME8100_INT_OCCUR:
+ return me8100_int_occur((me8100_int_occur_type *) arg, &info_vec[minor]);
+ case ME8100_SETUP_ICSR:
+ return me8100_setup_icsr((unsigned char *) arg, &info_vec[minor]);
+ case ME8100_READ_ICSR:
+ return me8100_read_icsr((unsigned char *) arg, &info_vec[minor]);
+ case ME8100_GET_BOARD_INFO:
+ return me8100_get_board_info((me8100_info_type *)arg, &info_vec[minor]);
+ case ME8100_GET_INT_COUNT:
+ return me8100_get_int_count((me8100_int_occur_type *)arg,&info_vec[minor]);
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+
+
+/*
+ * Routine:
+ * me8100_fasync
+ *
+ * Description:
+ * This function is executed, when a user program executes the systemcall
+ * fcntl. It remarks the processes who want to be informed asynchronous
+ * in a fasync structure and saves the pointer to this structure in the
+ * file structure of the path.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * fd int read File descriptor of the open path.
+ * file_ptr struct file * read Pointer to the file structure of
+ * the system.
+ * mode int read Requested operation,
+ * passed to the fasync_helper.
+ *
+ * Result:
+ * All < 0 marks a failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modufication:
+ */
+static int me8100_fasync(int fd, struct file *file_ptr, int mode){
+ int val = 0;
+ struct fasync_struct *fasync_ptr;
+
+ fasync_ptr = file_ptr->private_data;
+
+ PDEBUG("me8100_fasync() is executed\n");
+
+ val = fasync_helper(fd, file_ptr, mode, &fasync_ptr);
+ file_ptr->private_data = fasync_ptr;
+ return val;
+}
+
+
+
+
+/*
+ * Routine:
+ * me8100_get_board_info
+ *
+ * Description:
+ * This function is called by me8100_ioctl, in order to get the global
+ * variables for a specific board from the info_vec.
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg me8100_info_type w Carries the value to user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_get_board_info(me8100_info_type *arg,
+ me8100_info_type *info){
+
+ PDEBUG("me8100_get_board_info() is executed\n");
+
+ if(copy_to_user(arg, info, sizeof(me8100_info_type)))
+ return -EFAULT;
+ return 0;
+}
+
+
+
+
+/*
+ * Routine:
+ * me8100_read_id_a
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to read the
+ * function id register a.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned short w Carries the value to user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_read_id_a(unsigned short *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned short id_a;
+
+ PDEBUG("me8100_read_id_a() is executed\n");
+
+ id_a = inw(info->me8100_regbase + ME8100_ID_REG_A);
+ err = copy_to_user(arg, &id_a, sizeof(id_a));
+ if(err)
+ return err;
+
+ return 0;
+}
+
+
+
+
+
+/*
+ * Routine:
+ * me8100_write_ctrl_a
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to setup the
+ * CTRL register a.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned short r Carries the value from user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_write_ctrl_a(unsigned short *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned short ctrl_a = 0;
+
+ PDEBUG("me8100_write_ctrl_a() is executed\n");
+
+ err = copy_from_user(&ctrl_a, arg, sizeof(ctrl_a));
+ if(err)
+ return err;
+
+ PDEBUG("me8100_write_ctrl_a:ctrl_a=0x%04X\n", ctrl_a);
+ PDEBUG("me8100_write_ctrl_a:To offset=0x%02X\n", ME8100_CTRL_REG_A);
+ outw(ctrl_a, info->me8100_regbase + ME8100_CTRL_REG_A);
+
+ return 0;
+}
+
+
+
+
+/*
+ * Routine:
+ * me8100_res_int_a
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to reset the
+ * INTR bit a.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_res_int_a(me8100_info_type *info){
+
+ PDEBUG("me8100_res_int_a() is executed\n");
+
+ inw(info->me8100_regbase + ME8100_RES_INT_REG_A);
+
+ return 0;
+}
+
+
+
+
+/*
+ * Routine:
+ * me8100_read_di_a
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to read a value
+ * from the digital input a.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned short w Carries the value to user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_read_di_a(unsigned short *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned short di_a;
+
+ PDEBUG("me8100_read_di_a() is executed\n");
+
+ di_a = inw(info->me8100_regbase + ME8100_DI_REG_A);
+ err = copy_to_user(arg, &di_a, sizeof(di_a));
+ if(err)
+ return err;
+
+ return 0;
+}
+
+
+
+
+/*
+ * Routine:
+ * me8100_write_do_a
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to write a value
+ * to the digital output a.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned short r Carries the value from user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_write_do_a(unsigned short *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned short do_a = 0;
+
+ PDEBUG("me8100_write_do_a() is executed\n");
+
+ err = copy_from_user(&do_a, arg, sizeof(do_a));
+ if(err)
+ return err;
+
+ PDEBUG("me8100_write_do_a:do_a=0x%04X\n", do_a);
+ PDEBUG("me8100_write_do_a:To offset=0x%02X\n", ME8100_DO_REG_A);
+ outw(do_a, info->me8100_regbase + ME8100_DO_REG_A);
+
+ return 0;
+}
+
+
+
+/*
+ * Routine:
+ * me8100_write_pattern_a
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to setup the
+ * pattern register a.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned short r Carries the value from user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_write_pattern_a(unsigned short *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned short pattern_a = 0;
+
+ PDEBUG("me8100_write_pattern_a() is executed\n");
+
+ err = copy_from_user(&pattern_a, arg, sizeof(pattern_a));
+ if(err)
+ return err;
+
+ PDEBUG("me8100_write_pattern_a:pattern_a=0x%04X\n", pattern_a);
+ PDEBUG("me8100_write_pattern_a:To offset=0x%02X\n",
+ ME8100_PATTERN_REG_A);
+ outw(pattern_a, info->me8100_regbase + ME8100_PATTERN_REG_A);
+
+ return 0;
+}
+
+
+
+/*
+ * Routine:
+ * me8100_write_mask_a
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to setup the
+ * mask register a.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned short r Carries the value from user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_write_mask_a(unsigned short *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned short mask_a = 0;
+
+ PDEBUG("me8100_write_mask_a() is executed\n");
+
+ err = copy_from_user(&mask_a, arg, sizeof(mask_a));
+ if(err)
+ return err;
+
+ PDEBUG("me8100_write_mask_a:mask_a=0x%04X\n", mask_a);
+ PDEBUG("me8100_write_mask_a:To offset=0x%02X\n", ME8100_MASK_REG_A);
+ outw(mask_a, info->me8100_regbase + ME8100_MASK_REG_A);
+
+ return 0;
+}
+
+
+
+
+/*
+ * Routine:
+ * me8100_read_int_di_a
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to read the
+ * word from the digital input a, beeing actual at this moment the
+ * Interrupt rises.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned short w Carries the value to user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_read_int_di_a(unsigned short *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned short int_di_a;
+
+ PDEBUG("me8100_read_int_di_a() is executed\n");
+
+ int_di_a = inw(info->me8100_regbase + ME8100_INT_DI_REG_A);
+ err = copy_to_user(arg, &int_di_a, sizeof(int_di_a));
+ if(err){
+ PDEBUG("me8100_read_int_di_a:Failed to copy data\n");
+ return err;
+ }
+ return 0;
+}
+
+
+
+
+
+/*
+ * Routine:
+ * me8100_read_id_b
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to read the
+ * function id register b.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned short w Carries the value to user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_read_id_b(unsigned short *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned short id_b;
+
+ PDEBUG("me8100_read_id_b() is executed\n");
+
+ id_b = inw(info->me8100_regbase + ME8100_ID_REG_B);
+ err = copy_to_user(arg, &id_b, sizeof(id_b));
+ if(err)
+ return err;
+
+ return 0;
+}
+
+
+
+
+
+/*
+ * Routine:
+ * me8100_write_ctrl_b
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to setup the
+ * CTRL register b.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * arg unsigned short * r carries the value from user
+ * minor int r specifies the board
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_write_ctrl_b(unsigned short *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned short ctrl_b = 0;
+
+ PDEBUG("me8100_write_ctrl_b() is executed\n");
+
+ err = copy_from_user(&ctrl_b, arg, sizeof(ctrl_b));
+ if(err)
+ return err;
+
+ PDEBUG("me8100_write_ctrl_b:ctrl_b=0x%04X\n", ctrl_b);
+ PDEBUG("me8100_write_ctrl_b:To offset=0x%02X\n", ME8100_CTRL_REG_B);
+ outw(ctrl_b, info->me8100_regbase + ME8100_CTRL_REG_B);
+
+ return 0;
+}
+
+
+
+
+/*
+ * Routine:
+ * me8100_res_int_b
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to reset the
+ * INTR bit b.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_res_int_b(me8100_info_type *info){
+
+ PDEBUG("me8100_res_int_b() is executed\n");
+ inw(info->me8100_regbase + ME8100_RES_INT_REG_B);
+
+ return 0;
+}
+
+
+
+
+/*
+ * Routine:
+ * me8100_read_di_b
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to read a value
+ * from the digital input b.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned short w Carries the value to user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_read_di_b(unsigned short *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned short di_b;
+
+ PDEBUG("me8100_read_di_b() is executed\n");
+
+ di_b = inw(info->me8100_regbase + ME8100_DI_REG_B);
+ err = copy_to_user(arg, &di_b, sizeof(di_b));
+ if(err)
+ return err;
+
+ return 0;
+}
+
+
+
+
+/*
+ * Routine:
+ * me8100_write_do_b
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to write a value
+ * to the digital output b.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned short r Carries the value from user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_write_do_b(unsigned short *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned short do_b = 0;
+
+ PDEBUG("me8100_write_do_b() is executed\n");
+
+ err = copy_from_user(&do_b, arg, sizeof(do_b));
+ if(err)
+ return err;
+
+ PDEBUG("me8100_write_do_b:do_b=0x%04X\n", do_b);
+ PDEBUG("me8100_write_do_b:To offset=0x%02X\n", ME8100_DO_REG_B);
+ outw(do_b, info->me8100_regbase + ME8100_DO_REG_B);
+
+ return 0;
+}
+
+
+
+/*
+ * Routine:
+ * me8100_write_pattern_b
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to setup the
+ * pattern register b.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned short r Carries the value from user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_write_pattern_b(unsigned short *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned short pattern_b = 0;
+
+ PDEBUG("me8100_write_pattern_b() is executed\n");
+
+ err = copy_from_user(&pattern_b, arg, sizeof(pattern_b));
+ if(err)
+ return err;
+
+ PDEBUG("me8100_write_pattern_b:pattern_b=0x%04X\n", pattern_b);
+ PDEBUG("me8100_write_pattern_b:To offset=0x%02X\n",
+ ME8100_PATTERN_REG_B);
+ outw(pattern_b, info->me8100_regbase + ME8100_PATTERN_REG_B);
+
+ return 0;
+}
+
+
+
+/*
+ * Routine:
+ * me8100_write_mask_b
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to setup the
+ * mask register b.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned short r Carries the value from user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_write_mask_b(unsigned short *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned short mask_b = 0;
+
+ PDEBUG("me8100_write_mask_b() is executed\n");
+
+ err = copy_from_user(&mask_b, arg, sizeof(mask_b));
+ if(err)
+ return err;
+
+ PDEBUG("me8100_write_mask_b:mask_b=0x%04X\n", mask_b);
+ PDEBUG("me8100_write_mask_b:To offset=0x%02X\n", ME8100_MASK_REG_B);
+ outw(mask_b, info->me8100_regbase + ME8100_MASK_REG_B);
+
+ return 0;
+}
+
+
+
+
+/*
+ * Routine:
+ * me8100_read_int_di_b
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to read the
+ * word from the digital input b, beeing actual at the moment the
+ * Interrupt rises.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned short w Carries the value to user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_read_int_di_b(unsigned short *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned short int_di_b;
+
+ PDEBUG("me8100_read_int_di_b() is executed\n");
+
+ int_di_b = inw(info->me8100_regbase + ME8100_INT_DI_REG_B);
+ err = copy_to_user(arg, &int_di_b, sizeof(int_di_b));
+ if(err){
+ PDEBUG("me8100_read_int_di_b:Failed to copy data\n");
+ return err;
+ }
+ return 0;
+}
+
+
+
+
+
+/*
+ * Routine:
+ * me8100_write_counter_0
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to write a byte
+ * to the counter 0
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned char r Carries the value from user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_write_counter_0(unsigned char *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned char value = 0;
+
+ PDEBUG("me8100_write_counter_0() is executed\n");
+
+ err = copy_from_user(&value, arg, sizeof(value));
+ if(err)
+ return err;
+
+ PDEBUG("me8100_write_counter_0:counter_0=0x%02X\n", value);
+ PDEBUG("me8100_write_counter_0:To offset=0x%02X\n",
+ ME8100_COUNTER_REG_0);
+ outb(value, info->me8100_regbase + ME8100_COUNTER_REG_0);
+
+ return 0;
+}
+
+
+
+
+
+/*
+ * Routine:
+ * me8100_write_counter_1
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to write a byte
+ * to the counter 1
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned char r Carries the value from user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_write_counter_1(unsigned char *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned char value = 0;
+
+ PDEBUG("me8100_write_counter_1() is executed\n");
+
+ err = copy_from_user(&value, arg, sizeof(value));
+ if(err)
+ return err;
+
+ PDEBUG("me8100_write_counter_1:counter_1=0x%02X\n", value);
+ PDEBUG("me8100_write_counter_1:To offset=0x%02X\n",
+ ME8100_COUNTER_REG_1);
+ outb(value, info->me8100_regbase + ME8100_COUNTER_REG_1);
+
+ return 0;
+}
+
+
+
+
+
+/*
+ * Routine:
+ * me8100_write_counter_2
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to write a byte
+ * to the counter 2
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned char r Carries the value from user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_write_counter_2(unsigned char *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned char value = 0;
+
+ PDEBUG("me8100_write_counter_2() is executed\n");
+
+ err = copy_from_user(&value, arg, sizeof(value));
+ if(err)
+ return err;
+
+ PDEBUG("me8100_write_counter_2:counter_2=0x%02X\n", value);
+ PDEBUG("me8100_write_counter_2:To offset=0x%02X\n",
+ ME8100_COUNTER_REG_2);
+ outb(value, info->me8100_regbase + ME8100_COUNTER_REG_2);
+
+ return 0;
+}
+
+
+
+
+/*
+ * Routine:
+ * me8100_read_counter_0
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to read a byte
+ * from the counter 0
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned char r Carries the value to user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_read_counter_0(unsigned char *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned char value;
+
+ PDEBUG("me8100_read_counter_0() is executed\n");
+
+ value = inb(info->me8100_regbase + ME8100_COUNTER_REG_0);
+ err = copy_to_user(arg, &value, sizeof(value));
+ if(err)
+ return err;
+
+ return 0;
+}
+
+
+
+
+
+/*
+ * Routine:
+ * me8100_read_counter_1
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to read a byte
+ * from the counter 1
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned char r Carries the value to user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_read_counter_1(unsigned char *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned char value;
+
+ PDEBUG("me8100_read_counter_1() is executed\n");
+
+ value = inb(info->me8100_regbase + ME8100_COUNTER_REG_1);
+ err = copy_to_user(arg, &value, sizeof(value));
+ if(err)
+ return err;
+
+ return 0;
+}
+
+
+
+
+
+/*
+ * Routine:
+ * me8100_read_counter_2
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to read a byte
+ * from the counter 2
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned char r Carries the value to user.
+ * minor int r specifies the board
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_read_counter_2(unsigned char *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned char value;
+
+ PDEBUG("me8100_read_counter_2() is executed\n");
+
+ value = inb(info->me8100_regbase + ME8100_COUNTER_REG_2);
+ err = copy_to_user(arg, &value, sizeof(value));
+ if(err)
+ return err;
+
+ return 0;
+}
+
+
+
+/*
+ * Routine:
+ * me8100_setup_counter
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to setup the
+ * the counter.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned char r Carries the value from user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_setup_counter(unsigned char *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned char value = 0;
+
+ PDEBUG("me8100_setup_counter() is executed\n");
+
+ err = copy_from_user(&value, arg, sizeof(value));
+ if(err)
+ return err;
+
+ PDEBUG("me8100_setup_counter_0:ctrl=0x%02X\n", value);
+ PDEBUG("me8100_setup_counter_0():To offset=0x%02X\n",
+ ME8100_COUNTER_CTRL_REG);
+ outb(value, info->me8100_regbase + ME8100_COUNTER_CTRL_REG);
+
+ return 0;
+}
+
+
+
+/*
+ * Routine:
+ * me8100_get_serial
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to get the
+ * serial number of the board.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned int w Carries the value to user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_get_serial(unsigned int *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned int value;
+
+ PDEBUG("me8100_get_serial() is executed\n");
+
+ value = info->serial_no;
+ err = copy_to_user(arg, &value, sizeof(value));
+ if(err)
+ return err;
+
+ return 0;
+}
+
+
+
+
+/*
+ * Routine:
+ * me8100_get_name
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to get the
+ * name of the board.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned int w Carries the value to user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_get_name(me8100_version_enum_type *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned int value;
+
+ PDEBUG("me8100_get_name() is executed\n");
+
+ value = info->version;
+ err = copy_to_user(arg, &value, sizeof(value));
+ if(err)
+ return err;
+
+ return 0;
+}
+
+
+
+
+/*
+ * Routine:
+ * me8100_int_occur
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to find out,
+ * which interrupt input rised the last interrupt on a me8100 board.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg me8100_int_occur_type w Carries the value to user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_int_occur(me8100_int_occur_type *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned long flags;
+ me8100_int_occur_type int_occur;
+
+ PDEBUG("me8100_read_int_occur() is executed\n");
+
+ save_flags(flags);
+ cli();
+ int_occur.int1 = info->int1;
+ int_occur.int2 = info->int2;
+ restore_flags(flags);
+
+ err = copy_to_user(arg, &int_occur, sizeof(int_occur));
+ if(err)
+ return err;
+ return 0;
+}
+
+
+
+
+/*
+ * Routine:
+ * me8100_setup_icsr
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to write a value
+ * to the plx icsr (offset 0x4C)
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned char r Carries the value from user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_setup_icsr(unsigned char *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned char value = 0;
+
+ PDEBUG("me8100_setup_icsr() is executed\n");
+
+ err = copy_from_user(&value, arg, sizeof(value));
+ if(err)
+ return err;
+
+ PDEBUG("me8100_setup_icsr:icsr=0x%02X\n", value);
+ PDEBUG("me8100_setup_icsr:To offset=0x%02X\n",
+ PLX_ICSR);
+ outb(value, info->plx_regbase + PLX_ICSR);
+
+ return 0;
+}
+
+
+
+/*
+ * Routine:
+ * me8100_read_icsr
+ *
+ * Description:
+ * This function is called by the me8100_ioctl, in order to read the
+ * the plx icsr (offset 0x4C)
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg unsigned char w Carries the value to user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_read_icsr(unsigned char *arg, me8100_info_type *info){
+ int err = 0;
+ unsigned char value;
+
+ PDEBUG("me8100_read_icsr() is executed\n");
+
+ value = inb(info->plx_regbase + PLX_ICSR);
+ err = copy_to_user(arg, &value, sizeof(value));
+ if(err)
+ return err;
+
+ return 0;
+}
+
+
+
+/*
+ * Routine:
+ * me8100_get_int_count
+ *
+ * Description:
+ * This function is called by me8100_ioctl, in order to get the count of
+ * interrupts occoured since the module was loaded.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * *arg int w Carries the value to user.
+ * *info me8100_info_type r Global board context.
+ *
+ * Result:
+ * On success the return value is 0, else is failure.
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static int me8100_get_int_count(me8100_int_occur_type *arg,
+ me8100_info_type *info){
+ me8100_int_occur_type int_count;
+ unsigned long flags;
+
+ PDEBUG("me8100_get_int_count() is executed\n");
+
+ save_flags(flags);
+ cli();
+ int_count.int1 = info->int_count_1;
+ int_count.int2 = info->int_count_2;
+ restore_flags(flags);
+
+ if(copy_to_user(arg, &int_count, sizeof(int_count)))
+ return -EFAULT;
+ return 0;
+}
+
+
+
+
+/*
+ * Routine:
+ * me8100_isr
+ *
+ * Description:
+ * This is the interrupt service routine of the ME8100 board. This
+ * function is called, when the interrupt logic of the plx and the board
+ * is enabled and an extarnal interrupt occures. First it checks if the
+ * interrupt number is right and if this board rises the interrupt by
+ * reading the interrupt status register of the PLX. It remarks the input
+ * (Int1 or Int2) which rises the interrupt in the global
+ * info_vec. Then it informs the process, probably remarked in
+ * the fasync structure.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ * irq int read number of interrupt occured
+ * dev_id void* read pointer to board specific
+ * informations
+ * regs struct pt_regs * read pointer to cpu register
+ *
+ * Result:
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+static void me8100_isr(int irq, void *dev_id, struct pt_regs *regs){
+ unsigned char icsr = 0;
+ unsigned short dummy = 0;
+ me8100_info_type *board_context;
+ struct fasync_struct *fasync_ptr;
+
+ PDEBUG("me8100_isr() is executed\n");
+
+ board_context = (me8100_info_type *) dev_id;
+
+ fasync_ptr = board_context->file_ptr->private_data;
+
+ if(irq != board_context->int_line){
+ PDEBUG("me8100_isr():incorrect interrupt num: %d\n", irq);
+ return;
+ }
+
+ board_context->int1 = 0;
+ board_context->int2 = 0;
+
+ icsr = inb(board_context->plx_regbase + PLX_ICSR);
+
+ if((icsr & 0x04)&&(icsr & 0x40)&&(icsr & 0x01)){
+ PDEBUG("me8100_isr():Int1 occured\n");
+ board_context->int1 = 1;
+ board_context->int_count_1++;
+ dummy = inw(board_context->me8100_regbase + ME8100_RES_INT_REG_A);
+ }
+
+ if((icsr & 0x20)&&(icsr & 0x40)&&(icsr & 0x08)){
+ PDEBUG("me8100_isr():Int2 occured\n");
+ board_context->int2 = 1;
+ board_context->int_count_2++;
+ dummy = inw(board_context->me8100_regbase + ME8100_RES_INT_REG_B);
+ }
+
+ if(!(board_context->int1 || board_context->int2)){
+ PDEBUG("me8100_isr():Not this Board\n");
+ return;
+ }
+
+ if(fasync_ptr){
+ PDEBUG("me8100_isr():send signal to process\n");
+ kill_fasync(&fasync_ptr, SIGIO, POLL_IN);
+ }
+}
+
+
+
+
+/*
+ * Routine:
+ * cleanup_module
+ *
+ * Description:
+ * This routine is called, when the module is removed from the kernel.
+ * It unregisters the module on the system.
+ *
+ * Parameter list:
+ * Name Type Access Description
+ *--------------------------------------------------------------------------
+ *
+ * Result:
+ *--------------------------------------------------------------------------
+ * Author: GG
+ * Modification:
+ */
+void cleanup_module(void){
+ extern unsigned int major;
+ int err;
+
+ PDEBUG("cleanup_module() is executed\n");
+
+ if(major){
+ err = unregister_chrdev(major, ME8100_NAME);
+ if(err)
+ printk(KERN_WARNING"ME8100:cleanup_module():cannot unregister major\n");
+ }
+}