diff -r 000000000000 -r c9b8efdb5369 me8100.c --- /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 +#ifdef CONFIG_SMP +# define __SMP__ +#endif + + +/* + * Basic facilities for modules. + * Defines __module_kernel_version. + * Includes (UTS_RELEASE, LINUX_VERSION_CODE, ...) + */ +#include + +/* + * Needed for the registration of I/O and MEMORY regions. + * (request_region, ...) + */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include + + +/* 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"); + } +}