me8100.c
changeset 0 c9b8efdb5369
child 3 fc24e3b47731
--- /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");
+  }
+}