diff options
author | merge <null@invalid> | 2009-01-22 13:55:32 +0000 |
---|---|---|
committer | Andy Green <agreen@octopus.localdomain> | 2009-01-22 13:55:32 +0000 |
commit | aa6f5ffbdba45aa8e19e5048648fc6c7b25376d3 (patch) | |
tree | fbb786d0ac6f8a774fd834e9ce951197e60fbffa /drivers/staging/epl/EplApiLinuxKernel.c | |
parent | f2d78193eae5dccd3d588d2c8ea0866efc368332 (diff) |
MERGE-via-pending-tracking-hist-MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040-1232632141
pending-tracking-hist top was MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040-1232632141 / fdf777a63bcb59e0dfd78bfe2c6242e01f6d4eb9 ... parent commitmessage:
From: merge <null@invalid>
MERGE-via-stable-tracking-hist-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040
stable-tracking-hist top was MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040 / 90463bfd2d5a3c8b52f6e6d71024a00e052b0ced ... parent commitmessage:
From: merge <null@invalid>
MERGE-via-mokopatches-tracking-hist-fix-stray-endmenu-patch
mokopatches-tracking-hist top was fix-stray-endmenu-patch / 3630e0be570de8057e7f8d2fe501ed353cdf34e6 ... parent commitmessage:
From: Andy Green <andy@openmoko.com>
fix-stray-endmenu.patch
Signed-off-by: Andy Green <andy@openmoko.com>
Diffstat (limited to 'drivers/staging/epl/EplApiLinuxKernel.c')
-rw-r--r-- | drivers/staging/epl/EplApiLinuxKernel.c | 1260 |
1 files changed, 1260 insertions, 0 deletions
diff --git a/drivers/staging/epl/EplApiLinuxKernel.c b/drivers/staging/epl/EplApiLinuxKernel.c new file mode 100644 index 00000000000..05ca0628d6a --- /dev/null +++ b/drivers/staging/epl/EplApiLinuxKernel.c @@ -0,0 +1,1260 @@ +/**************************************************************************** + + (c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29 + www.systec-electronic.com + + Project: openPOWERLINK + + Description: Linux kernel module as wrapper of EPL API layer, + i.e. counterpart to a Linux application + + License: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of SYSTEC electronic GmbH nor the names of its + contributors may be used to endorse or promote products derived + from this software without prior written permission. For written + permission, please contact info@systec-electronic.com. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Severability Clause: + + If a provision of this License is or becomes illegal, invalid or + unenforceable in any jurisdiction, that shall not affect: + 1. the validity or enforceability in that jurisdiction of any other + provision of this License; or + 2. the validity or enforceability in other jurisdictions of that or + any other provision of this License. + + ------------------------------------------------------------------------- + + $RCSfile: EplApiLinuxKernel.c,v $ + + $Author: D.Krueger $ + + $Revision: 1.9 $ $Date: 2008/11/21 09:00:38 $ + + $State: Exp $ + + Build Environment: + GNU-Compiler for m68k + + ------------------------------------------------------------------------- + + Revision History: + + 2006/10/11 d.k.: Initial Version + 2008/04/10 m.u.: Changed to new char driver init + +****************************************************************************/ + +// kernel modul and driver + +//#include <linux/version.h> +//#include <linux/config.h> + +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/cdev.h> +#include <linux/types.h> + +//#include <linux/module.h> +//#include <linux/kernel.h> +//#include <linux/init.h> +//#include <linux/errno.h> + +// scheduling +#include <linux/sched.h> + +// memory access +#include <asm/uaccess.h> +#include <linux/vmalloc.h> + +#ifdef CONFIG_DEVFS_FS +#include <linux/major.h> +#include <linux/devfs_fs_kernel.h> +#endif + +#include "Epl.h" +#include "EplApiLinux.h" +//#include "kernel/EplPdokCal.h" +#include "proc_fs.h" + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + // remove ("make invisible") obsolete symbols for kernel versions 2.6 + // and higher +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#define EXPORT_NO_SYMBOLS +#else +#error "This driver needs a 2.6.x kernel or higher" +#endif + +/***************************************************************************/ +/* */ +/* */ +/* G L O B A L D E F I N I T I O N S */ +/* */ +/* */ +/***************************************************************************/ + +// Metainformation +MODULE_LICENSE("Dual BSD/GPL"); +#ifdef MODULE_AUTHOR +MODULE_AUTHOR("Daniel.Krueger@SYSTEC-electronic.com"); +MODULE_DESCRIPTION("EPL API driver"); +#endif + +//--------------------------------------------------------------------------- +// Configuration +//--------------------------------------------------------------------------- + +#define EPLLIN_DRV_NAME "systec_epl" // used for <register_chrdev> + +//--------------------------------------------------------------------------- +// Constant definitions +//--------------------------------------------------------------------------- + +// TracePoint support for realtime-debugging +#ifdef _DBG_TRACE_POINTS_ +void PUBLIC TgtDbgSignalTracePoint(BYTE bTracePointNumber_p); +#define TGT_DBG_SIGNAL_TRACE_POINT(p) TgtDbgSignalTracePoint(p) +#else +#define TGT_DBG_SIGNAL_TRACE_POINT(p) +#endif + +#define EVENT_STATE_INIT 0 +#define EVENT_STATE_IOCTL 1 // ioctl entered and ready to receive EPL event +#define EVENT_STATE_READY 2 // EPL event can be forwarded to user application +#define EVENT_STATE_TERM 3 // terminate processing + +#define EPL_STATE_NOTOPEN 0 +#define EPL_STATE_NOTINIT 1 +#define EPL_STATE_RUNNING 2 +#define EPL_STATE_SHUTDOWN 3 + +//--------------------------------------------------------------------------- +// Global variables +//--------------------------------------------------------------------------- + +#ifdef CONFIG_DEVFS_FS + + // driver major number +static int nDrvMajorNumber_g; + +#else + + // device number (major and minor) +static dev_t nDevNum_g; +static struct cdev *pEpl_cdev_g; + +#endif + +static volatile unsigned int uiEplState_g = EPL_STATE_NOTOPEN; + +static struct semaphore SemaphoreCbEvent_g; // semaphore for EplLinCbEvent +static wait_queue_head_t WaitQueueCbEvent_g; // wait queue EplLinCbEvent +static wait_queue_head_t WaitQueueProcess_g; // wait queue for EplApiProcess (user process) +static wait_queue_head_t WaitQueueRelease_g; // wait queue for EplLinRelease +static atomic_t AtomicEventState_g = ATOMIC_INIT(EVENT_STATE_INIT); +static tEplApiEventType EventType_g; // event type (enum) +static tEplApiEventArg *pEventArg_g; // event argument (union) +static tEplKernel RetCbEvent_g; // return code from event callback function +static wait_queue_head_t WaitQueueCbSync_g; // wait queue EplLinCbSync +static wait_queue_head_t WaitQueuePI_In_g; // wait queue for EplApiProcessImageExchangeIn (user process) +static atomic_t AtomicSyncState_g = ATOMIC_INIT(EVENT_STATE_INIT); + +//--------------------------------------------------------------------------- +// Local types +//--------------------------------------------------------------------------- + +typedef struct { + void *m_pUserArg; + void *m_pData; + +} tEplLinSdoBufHeader; + +//--------------------------------------------------------------------------- +// Local variables +//--------------------------------------------------------------------------- + +//--------------------------------------------------------------------------- +// Prototypes of internal functions +//--------------------------------------------------------------------------- + +tEplKernel PUBLIC EplLinCbEvent(tEplApiEventType EventType_p, // IN: event type (enum) + tEplApiEventArg * pEventArg_p, // IN: event argument (union) + void GENERIC * pUserArg_p); + +tEplKernel PUBLIC EplLinCbSync(void); + +static int __init EplLinInit(void); +static void __exit EplLinExit(void); + +static int EplLinOpen(struct inode *pDeviceFile_p, struct file *pInstance_p); +static int EplLinRelease(struct inode *pDeviceFile_p, struct file *pInstance_p); +static ssize_t EplLinRead(struct file *pInstance_p, char *pDstBuff_p, + size_t BuffSize_p, loff_t * pFileOffs_p); +static ssize_t EplLinWrite(struct file *pInstance_p, const char *pSrcBuff_p, + size_t BuffSize_p, loff_t * pFileOffs_p); +static int EplLinIoctl(struct inode *pDeviceFile_p, struct file *pInstance_p, + unsigned int uiIoctlCmd_p, unsigned long ulArg_p); + +//--------------------------------------------------------------------------- +// Kernel Module specific Data Structures +//--------------------------------------------------------------------------- + +EXPORT_NO_SYMBOLS; + +module_init(EplLinInit); +module_exit(EplLinExit); + +static struct file_operations EplLinFileOps_g = { + .owner = THIS_MODULE, + .open = EplLinOpen, + .release = EplLinRelease, + .read = EplLinRead, + .write = EplLinWrite, + .ioctl = EplLinIoctl, + +}; + +//=========================================================================// +// // +// P U B L I C F U N C T I O N S // +// // +//=========================================================================// + +//--------------------------------------------------------------------------- +// Initailize Driver +//--------------------------------------------------------------------------- +// -> insmod driver +//--------------------------------------------------------------------------- + +static int __init EplLinInit(void) +{ + + tEplKernel EplRet; + int iErr; + int iRet; +#ifdef CONFIG_DEVFS_FS + int nMinorNumber; +#endif + + TRACE0("EPL: + EplLinInit...\n"); + TRACE2("EPL: Driver build: %s / %s\n", __DATE__, __TIME__); + + iRet = 0; + + // initialize global variables + atomic_set(&AtomicEventState_g, EVENT_STATE_INIT); + sema_init(&SemaphoreCbEvent_g, 1); + init_waitqueue_head(&WaitQueueCbEvent_g); + init_waitqueue_head(&WaitQueueProcess_g); + init_waitqueue_head(&WaitQueueRelease_g); + +#ifdef CONFIG_DEVFS_FS + + // register character device handler + TRACE2("EPL: Installing Driver '%s', Version %s...\n", + EPLLIN_DRV_NAME, EPL_PRODUCT_VERSION); + TRACE0("EPL: (using dynamic major number assignment)\n"); + nDrvMajorNumber_g = + register_chrdev(0, EPLLIN_DRV_NAME, &EplLinFileOps_g); + if (nDrvMajorNumber_g != 0) { + TRACE2 + ("EPL: Driver '%s' installed successful, assigned MajorNumber=%d\n", + EPLLIN_DRV_NAME, nDrvMajorNumber_g); + } else { + TRACE1 + ("EPL: ERROR: Driver '%s' is unable to get a free MajorNumber!\n", + EPLLIN_DRV_NAME); + iRet = -EIO; + goto Exit; + } + + // create device node in DEVFS + nMinorNumber = 0; + TRACE1("EPL: Creating device node '/dev/%s'...\n", EPLLIN_DEV_NAME); + iErr = + devfs_mk_cdev(MKDEV(nDrvMajorNumber_g, nMinorNumber), + S_IFCHR | S_IRUGO | S_IWUGO, EPLLIN_DEV_NAME); + if (iErr == 0) { + TRACE1("EPL: Device node '/dev/%s' created successful.\n", + EPLLIN_DEV_NAME); + } else { + TRACE1("EPL: ERROR: unable to create device node '/dev/%s'\n", + EPLLIN_DEV_NAME); + iRet = -EIO; + goto Exit; + } + +#else + + // register character device handler + // only one Minor required + TRACE2("EPL: Installing Driver '%s', Version %s...\n", + EPLLIN_DRV_NAME, EPL_PRODUCT_VERSION); + iRet = alloc_chrdev_region(&nDevNum_g, 0, 1, EPLLIN_DRV_NAME); + if (iRet == 0) { + TRACE2 + ("EPL: Driver '%s' installed successful, assigned MajorNumber=%d\n", + EPLLIN_DRV_NAME, MAJOR(nDevNum_g)); + } else { + TRACE1 + ("EPL: ERROR: Driver '%s' is unable to get a free MajorNumber!\n", + EPLLIN_DRV_NAME); + iRet = -EIO; + goto Exit; + } + + // register cdev structure + pEpl_cdev_g = cdev_alloc(); + pEpl_cdev_g->ops = &EplLinFileOps_g; + pEpl_cdev_g->owner = THIS_MODULE; + iErr = cdev_add(pEpl_cdev_g, nDevNum_g, 1); + if (iErr) { + TRACE2("EPL: ERROR %d: Driver '%s' could not be added!\n", + iErr, EPLLIN_DRV_NAME); + iRet = -EIO; + goto Exit; + } +#endif + + // create device node in PROCFS + EplRet = EplLinProcInit(); + if (EplRet != kEplSuccessful) { + goto Exit; + } + + Exit: + + TRACE1("EPL: - EplLinInit (iRet=%d)\n", iRet); + return (iRet); + +} + +//--------------------------------------------------------------------------- +// Remove Driver +//--------------------------------------------------------------------------- +// -> rmmod driver +//--------------------------------------------------------------------------- + +static void __exit EplLinExit(void) +{ + + tEplKernel EplRet; + + // delete instance for all modules +// EplRet = EplApiShutdown(); +// printk("EplApiShutdown(): 0x%X\n", EplRet); + + // deinitialize proc fs + EplRet = EplLinProcFree(); + printk("EplLinProcFree(): 0x%X\n", EplRet); + + TRACE0("EPL: + EplLinExit...\n"); + +#ifdef CONFIG_DEVFS_FS + + // remove device node from DEVFS + devfs_remove(EPLLIN_DEV_NAME); + TRACE1("EPL: Device node '/dev/%s' removed.\n", EPLLIN_DEV_NAME); + + // unregister character device handler + unregister_chrdev(nDrvMajorNumber_g, EPLLIN_DRV_NAME); + +#else + + // remove cdev structure + cdev_del(pEpl_cdev_g); + + // unregister character device handler + unregister_chrdev_region(nDevNum_g, 1); + +#endif + + TRACE1("EPL: Driver '%s' removed.\n", EPLLIN_DRV_NAME); + + TRACE0("EPL: - EplLinExit\n"); + +} + +//--------------------------------------------------------------------------- +// Open Driver +//--------------------------------------------------------------------------- +// -> open("/dev/driver", O_RDWR)... +//--------------------------------------------------------------------------- + +static int EplLinOpen(struct inode *pDeviceFile_p, // information about the device to open + struct file *pInstance_p) // information about driver instance +{ + + int iRet; + + TRACE0("EPL: + EplLinOpen...\n"); + + MOD_INC_USE_COUNT; + + if (uiEplState_g != EPL_STATE_NOTOPEN) { // stack already initialized + iRet = -EALREADY; + } else { + atomic_set(&AtomicEventState_g, EVENT_STATE_INIT); + sema_init(&SemaphoreCbEvent_g, 1); + init_waitqueue_head(&WaitQueueCbEvent_g); + init_waitqueue_head(&WaitQueueProcess_g); + init_waitqueue_head(&WaitQueueRelease_g); + atomic_set(&AtomicSyncState_g, EVENT_STATE_INIT); + init_waitqueue_head(&WaitQueueCbSync_g); + init_waitqueue_head(&WaitQueuePI_In_g); + + uiEplState_g = EPL_STATE_NOTINIT; + iRet = 0; + } + + TRACE1("EPL: - EplLinOpen (iRet=%d)\n", iRet); + return (iRet); + +} + +//--------------------------------------------------------------------------- +// Close Driver +//--------------------------------------------------------------------------- +// -> close(device)... +//--------------------------------------------------------------------------- + +static int EplLinRelease(struct inode *pDeviceFile_p, // information about the device to open + struct file *pInstance_p) // information about driver instance +{ + + tEplKernel EplRet = kEplSuccessful; + int iRet; + + TRACE0("EPL: + EplLinRelease...\n"); + + if (uiEplState_g != EPL_STATE_NOTINIT) { + // pass control to sync kernel thread, but signal termination + atomic_set(&AtomicSyncState_g, EVENT_STATE_TERM); + wake_up_interruptible(&WaitQueueCbSync_g); + wake_up_interruptible(&WaitQueuePI_In_g); + + // pass control to event queue kernel thread + atomic_set(&AtomicEventState_g, EVENT_STATE_TERM); + wake_up_interruptible(&WaitQueueCbEvent_g); + + if (uiEplState_g == EPL_STATE_RUNNING) { // post NmtEventSwitchOff + EplRet = EplApiExecNmtCommand(kEplNmtEventSwitchOff); + + } + + if (EplRet == kEplSuccessful) { + TRACE0("EPL: waiting for NMT_GS_OFF\n"); + wait_event_interruptible(WaitQueueRelease_g, + (uiEplState_g == + EPL_STATE_SHUTDOWN)); + } else { // post NmtEventSwitchOff failed + TRACE0("EPL: event post failed\n"); + } + + // $$$ d.k.: What if waiting was interrupted by signal? + + TRACE0("EPL: call EplApiShutdown()\n"); + // EPL stack can be safely shut down + // delete instance for all EPL modules + EplRet = EplApiShutdown(); + printk("EplApiShutdown(): 0x%X\n", EplRet); + } + + uiEplState_g = EPL_STATE_NOTOPEN; + iRet = 0; + + MOD_DEC_USE_COUNT; + + TRACE1("EPL: - EplLinRelease (iRet=%d)\n", iRet); + return (iRet); + +} + +//--------------------------------------------------------------------------- +// Read Data from Driver +//--------------------------------------------------------------------------- +// -> read(...) +//--------------------------------------------------------------------------- + +static ssize_t EplLinRead(struct file *pInstance_p, // information about driver instance + char *pDstBuff_p, // address of buffer to fill with data + size_t BuffSize_p, // length of the buffer + loff_t * pFileOffs_p) // offset in the file +{ + + int iRet; + + TRACE0("EPL: + EplLinRead...\n"); + + TRACE0("EPL: Sorry, this operation isn't supported.\n"); + iRet = -EINVAL; + + TRACE1("EPL: - EplLinRead (iRet=%d)\n", iRet); + return (iRet); + +} + +//--------------------------------------------------------------------------- +// Write Data to Driver +//--------------------------------------------------------------------------- +// -> write(...) +//--------------------------------------------------------------------------- + +static ssize_t EplLinWrite(struct file *pInstance_p, // information about driver instance + const char *pSrcBuff_p, // address of buffer to get data from + size_t BuffSize_p, // length of the buffer + loff_t * pFileOffs_p) // offset in the file +{ + + int iRet; + + TRACE0("EPL: + EplLinWrite...\n"); + + TRACE0("EPL: Sorry, this operation isn't supported.\n"); + iRet = -EINVAL; + + TRACE1("EPL: - EplLinWrite (iRet=%d)\n", iRet); + return (iRet); + +} + +//--------------------------------------------------------------------------- +// Generic Access to Driver +//--------------------------------------------------------------------------- +// -> ioctl(...) +//--------------------------------------------------------------------------- + +static int EplLinIoctl(struct inode *pDeviceFile_p, // information about the device to open + struct file *pInstance_p, // information about driver instance + unsigned int uiIoctlCmd_p, // Ioctl command to execute + unsigned long ulArg_p) // Ioctl command specific argument/parameter +{ + + tEplKernel EplRet; + int iErr; + int iRet; + +// TRACE1("EPL: + EplLinIoctl (uiIoctlCmd_p=%d)...\n", uiIoctlCmd_p); + + iRet = -EINVAL; + + switch (uiIoctlCmd_p) { + // ---------------------------------------------------------- + case EPLLIN_CMD_INITIALIZE: + { + tEplApiInitParam EplApiInitParam; + + iErr = + copy_from_user(&EplApiInitParam, + (const void *)ulArg_p, + sizeof(EplApiInitParam)); + if (iErr != 0) { + iRet = -EIO; + goto Exit; + } + + EplApiInitParam.m_pfnCbEvent = EplLinCbEvent; + EplApiInitParam.m_pfnCbSync = EplLinCbSync; + + EplRet = EplApiInitialize(&EplApiInitParam); + + uiEplState_g = EPL_STATE_RUNNING; + + iRet = (int)EplRet; + break; + } + + // ---------------------------------------------------------- + case EPLLIN_CMD_SHUTDOWN: + { // shutdown the threads + + // pass control to sync kernel thread, but signal termination + atomic_set(&AtomicSyncState_g, EVENT_STATE_TERM); + wake_up_interruptible(&WaitQueueCbSync_g); + wake_up_interruptible(&WaitQueuePI_In_g); + + // pass control to event queue kernel thread + atomic_set(&AtomicEventState_g, EVENT_STATE_TERM); + wake_up_interruptible(&WaitQueueCbEvent_g); + + if (uiEplState_g == EPL_STATE_RUNNING) { // post NmtEventSwitchOff + EplRet = + EplApiExecNmtCommand(kEplNmtEventSwitchOff); + + } + + iRet = 0; + break; + } + + // ---------------------------------------------------------- + case EPLLIN_CMD_READ_LOCAL_OBJECT: + { + tEplLinLocalObject LocalObject; + void *pData; + + iErr = + copy_from_user(&LocalObject, (const void *)ulArg_p, + sizeof(LocalObject)); + if (iErr != 0) { + iRet = -EIO; + goto Exit; + } + + if ((LocalObject.m_pData == NULL) + || (LocalObject.m_uiSize == 0)) { + iRet = (int)kEplApiInvalidParam; + goto Exit; + } + + pData = vmalloc(LocalObject.m_uiSize); + if (pData == NULL) { // no memory available + iRet = -ENOMEM; + goto Exit; + } + + EplRet = + EplApiReadLocalObject(LocalObject.m_uiIndex, + LocalObject.m_uiSubindex, + pData, &LocalObject.m_uiSize); + + if (EplRet == kEplSuccessful) { + iErr = + copy_to_user(LocalObject.m_pData, pData, + LocalObject.m_uiSize); + + vfree(pData); + + if (iErr != 0) { + iRet = -EIO; + goto Exit; + } + // return actual size (LocalObject.m_uiSize) + iErr = put_user(LocalObject.m_uiSize, + (unsigned int *)(ulArg_p + + (unsigned long) + &LocalObject. + m_uiSize - + (unsigned long) + &LocalObject)); + if (iErr != 0) { + iRet = -EIO; + goto Exit; + } + + } else { + vfree(pData); + } + + iRet = (int)EplRet; + break; + } + + // ---------------------------------------------------------- + case EPLLIN_CMD_WRITE_LOCAL_OBJECT: + { + tEplLinLocalObject LocalObject; + void *pData; + + iErr = + copy_from_user(&LocalObject, (const void *)ulArg_p, + sizeof(LocalObject)); + if (iErr != 0) { + iRet = -EIO; + goto Exit; + } + + if ((LocalObject.m_pData == NULL) + || (LocalObject.m_uiSize == 0)) { + iRet = (int)kEplApiInvalidParam; + goto Exit; + } + + pData = vmalloc(LocalObject.m_uiSize); + if (pData == NULL) { // no memory available + iRet = -ENOMEM; + goto Exit; + } + iErr = + copy_from_user(pData, LocalObject.m_pData, + LocalObject.m_uiSize); + if (iErr != 0) { + iRet = -EIO; + goto Exit; + } + + EplRet = + EplApiWriteLocalObject(LocalObject.m_uiIndex, + LocalObject.m_uiSubindex, + pData, LocalObject.m_uiSize); + + vfree(pData); + + iRet = (int)EplRet; + break; + } + + case EPLLIN_CMD_READ_OBJECT: + { + tEplLinSdoObject SdoObject; + void *pData; + tEplLinSdoBufHeader *pBufHeader; + tEplSdoComConHdl *pSdoComConHdl; + + iErr = + copy_from_user(&SdoObject, (const void *)ulArg_p, + sizeof(SdoObject)); + if (iErr != 0) { + iRet = -EIO; + goto Exit; + } + + if ((SdoObject.m_le_pData == NULL) + || (SdoObject.m_uiSize == 0)) { + iRet = (int)kEplApiInvalidParam; + goto Exit; + } + + pBufHeader = + (tEplLinSdoBufHeader *) + vmalloc(sizeof(tEplLinSdoBufHeader) + + SdoObject.m_uiSize); + if (pBufHeader == NULL) { // no memory available + iRet = -ENOMEM; + goto Exit; + } + // initiate temporary buffer + pBufHeader->m_pUserArg = SdoObject.m_pUserArg; // original user argument pointer + pBufHeader->m_pData = SdoObject.m_le_pData; // original data pointer from app + pData = pBufHeader + sizeof(tEplLinSdoBufHeader); + + if (SdoObject.m_fValidSdoComConHdl != FALSE) { + pSdoComConHdl = &SdoObject.m_SdoComConHdl; + } else { + pSdoComConHdl = NULL; + } + + EplRet = + EplApiReadObject(pSdoComConHdl, + SdoObject.m_uiNodeId, + SdoObject.m_uiIndex, + SdoObject.m_uiSubindex, pData, + &SdoObject.m_uiSize, + SdoObject.m_SdoType, pBufHeader); + + // return actual SDO handle (SdoObject.m_SdoComConHdl) + iErr = put_user(SdoObject.m_SdoComConHdl, + (unsigned int *)(ulArg_p + + (unsigned long) + &SdoObject. + m_SdoComConHdl - + (unsigned long) + &SdoObject)); + if (iErr != 0) { + iRet = -EIO; + goto Exit; + } + + if (EplRet == kEplSuccessful) { + iErr = + copy_to_user(SdoObject.m_le_pData, pData, + SdoObject.m_uiSize); + + vfree(pBufHeader); + + if (iErr != 0) { + iRet = -EIO; + goto Exit; + } + // return actual size (SdoObject.m_uiSize) + iErr = put_user(SdoObject.m_uiSize, + (unsigned int *)(ulArg_p + + (unsigned long) + &SdoObject. + m_uiSize - + (unsigned long) + &SdoObject)); + if (iErr != 0) { + iRet = -EIO; + goto Exit; + } + } else if (EplRet != kEplApiTaskDeferred) { // error ocurred + vfree(pBufHeader); + if (iErr != 0) { + iRet = -EIO; + goto Exit; + } + } + + iRet = (int)EplRet; + break; + } + + case EPLLIN_CMD_WRITE_OBJECT: + { + tEplLinSdoObject SdoObject; + void *pData; + tEplLinSdoBufHeader *pBufHeader; + tEplSdoComConHdl *pSdoComConHdl; + + iErr = + copy_from_user(&SdoObject, (const void *)ulArg_p, + sizeof(SdoObject)); + if (iErr != 0) { + iRet = -EIO; + goto Exit; + } + + if ((SdoObject.m_le_pData == NULL) + || (SdoObject.m_uiSize == 0)) { + iRet = (int)kEplApiInvalidParam; + goto Exit; + } + + pBufHeader = + (tEplLinSdoBufHeader *) + vmalloc(sizeof(tEplLinSdoBufHeader) + + SdoObject.m_uiSize); + if (pBufHeader == NULL) { // no memory available + iRet = -ENOMEM; + goto Exit; + } + // initiate temporary buffer + pBufHeader->m_pUserArg = SdoObject.m_pUserArg; // original user argument pointer + pBufHeader->m_pData = SdoObject.m_le_pData; // original data pointer from app + pData = pBufHeader + sizeof(tEplLinSdoBufHeader); + + iErr = + copy_from_user(pData, SdoObject.m_le_pData, + SdoObject.m_uiSize); + + if (iErr != 0) { + iRet = -EIO; + goto Exit; + } + + if (SdoObject.m_fValidSdoComConHdl != FALSE) { + pSdoComConHdl = &SdoObject.m_SdoComConHdl; + } else { + pSdoComConHdl = NULL; + } + + EplRet = + EplApiWriteObject(pSdoComConHdl, + SdoObject.m_uiNodeId, + SdoObject.m_uiIndex, + SdoObject.m_uiSubindex, pData, + SdoObject.m_uiSize, + SdoObject.m_SdoType, pBufHeader); + + // return actual SDO handle (SdoObject.m_SdoComConHdl) + iErr = put_user(SdoObject.m_SdoComConHdl, + (unsigned int *)(ulArg_p + + (unsigned long) + &SdoObject. + m_SdoComConHdl - + (unsigned long) + &SdoObject)); + if (iErr != 0) { + iRet = -EIO; + goto Exit; + } + + if (EplRet != kEplApiTaskDeferred) { // succeeded or error ocurred, but task not deferred + vfree(pBufHeader); + } + + iRet = (int)EplRet; + break; + } + + // ---------------------------------------------------------- + case EPLLIN_CMD_FREE_SDO_CHANNEL: + { + // forward SDO handle to EPL stack + EplRet = + EplApiFreeSdoChannel((tEplSdoComConHdl) ulArg_p); + + iRet = (int)EplRet; + break; + } + +#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0) + // ---------------------------------------------------------- + case EPLLIN_CMD_MN_TRIGGER_STATE_CHANGE: + { + tEplLinNodeCmdObject NodeCmdObject; + + iErr = + copy_from_user(&NodeCmdObject, + (const void *)ulArg_p, + sizeof(NodeCmdObject)); + if (iErr != 0) { + iRet = -EIO; + goto Exit; + } + + EplRet = + EplApiMnTriggerStateChange(NodeCmdObject.m_uiNodeId, + NodeCmdObject. + m_NodeCommand); + iRet = (int)EplRet; + break; + } +#endif + + // ---------------------------------------------------------- + case EPLLIN_CMD_GET_EVENT: + { + tEplLinEvent Event; + + // save event structure + iErr = + copy_from_user(&Event, (const void *)ulArg_p, + sizeof(Event)); + if (iErr != 0) { + iRet = -EIO; + goto Exit; + } + // save return code from application's event callback function + RetCbEvent_g = Event.m_RetCbEvent; + + if (RetCbEvent_g == kEplShutdown) { + // pass control to event queue kernel thread, but signal termination + atomic_set(&AtomicEventState_g, + EVENT_STATE_TERM); + wake_up_interruptible(&WaitQueueCbEvent_g); + // exit with error -> EplApiProcess() will leave the infinite loop + iRet = 1; + goto Exit; + } + // pass control to event queue kernel thread + atomic_set(&AtomicEventState_g, EVENT_STATE_IOCTL); + wake_up_interruptible(&WaitQueueCbEvent_g); + + // fall asleep itself in own wait queue + iErr = wait_event_interruptible(WaitQueueProcess_g, + (atomic_read + (&AtomicEventState_g) + == EVENT_STATE_READY) + || + (atomic_read + (&AtomicEventState_g) + == EVENT_STATE_TERM)); + if (iErr != 0) { // waiting was interrupted by signal + // pass control to event queue kernel thread, but signal termination + atomic_set(&AtomicEventState_g, + EVENT_STATE_TERM); + wake_up_interruptible(&WaitQueueCbEvent_g); + // exit with this error -> EplApiProcess() will leave the infinite loop + iRet = iErr; + goto Exit; + } else if (atomic_read(&AtomicEventState_g) == EVENT_STATE_TERM) { // termination in progress + // pass control to event queue kernel thread, but signal termination + wake_up_interruptible(&WaitQueueCbEvent_g); + // exit with this error -> EplApiProcess() will leave the infinite loop + iRet = 1; + goto Exit; + } + // copy event to user space + iErr = + copy_to_user(Event.m_pEventType, &EventType_g, + sizeof(EventType_g)); + if (iErr != 0) { // not all data could be copied + iRet = -EIO; + goto Exit; + } + // $$$ d.k. perform SDO event processing + if (EventType_g == kEplApiEventSdo) { + void *pData; + tEplLinSdoBufHeader *pBufHeader; + + pBufHeader = + (tEplLinSdoBufHeader *) pEventArg_g->m_Sdo. + m_pUserArg; + pData = + pBufHeader + sizeof(tEplLinSdoBufHeader); + + if (pEventArg_g->m_Sdo.m_SdoAccessType == + kEplSdoAccessTypeRead) { + // copy read data to user space + iErr = + copy_to_user(pBufHeader->m_pData, + pData, + pEventArg_g->m_Sdo. + m_uiTransferredByte); + if (iErr != 0) { // not all data could be copied + iRet = -EIO; + goto Exit; + } + } + pEventArg_g->m_Sdo.m_pUserArg = + pBufHeader->m_pUserArg; + vfree(pBufHeader); + } + + iErr = + copy_to_user(Event.m_pEventArg, pEventArg_g, + min(sizeof(tEplApiEventArg), + Event.m_uiEventArgSize)); + if (iErr != 0) { // not all data could be copied + iRet = -EIO; + goto Exit; + } + // return to EplApiProcess(), which will call the application's event callback function + iRet = 0; + + break; + } + + // ---------------------------------------------------------- + case EPLLIN_CMD_PI_SETUP: + { + EplRet = EplApiProcessImageSetup(); + iRet = (int)EplRet; + + break; + } + + // ---------------------------------------------------------- + case EPLLIN_CMD_PI_IN: + { + tEplApiProcessImage ProcessImageIn; + + // save process image structure + iErr = + copy_from_user(&ProcessImageIn, + (const void *)ulArg_p, + sizeof(ProcessImageIn)); + if (iErr != 0) { + iRet = -EIO; + goto Exit; + } + // pass control to event queue kernel thread + atomic_set(&AtomicSyncState_g, EVENT_STATE_IOCTL); + + // fall asleep itself in own wait queue + iErr = wait_event_interruptible(WaitQueuePI_In_g, + (atomic_read + (&AtomicSyncState_g) == + EVENT_STATE_READY) + || + (atomic_read + (&AtomicSyncState_g) == + EVENT_STATE_TERM)); + if (iErr != 0) { // waiting was interrupted by signal + // pass control to sync kernel thread, but signal termination + atomic_set(&AtomicSyncState_g, + EVENT_STATE_TERM); + wake_up_interruptible(&WaitQueueCbSync_g); + // exit with this error -> application will leave the infinite loop + iRet = iErr; + goto Exit; + } else if (atomic_read(&AtomicSyncState_g) == EVENT_STATE_TERM) { // termination in progress + // pass control to sync kernel thread, but signal termination + wake_up_interruptible(&WaitQueueCbSync_g); + // exit with this error -> application will leave the infinite loop + iRet = 1; + goto Exit; + } + // exchange process image + EplRet = EplApiProcessImageExchangeIn(&ProcessImageIn); + + // return to EplApiProcessImageExchangeIn() + iRet = (int)EplRet; + + break; + } + + // ---------------------------------------------------------- + case EPLLIN_CMD_PI_OUT: + { + tEplApiProcessImage ProcessImageOut; + + // save process image structure + iErr = + copy_from_user(&ProcessImageOut, + (const void *)ulArg_p, + sizeof(ProcessImageOut)); + if (iErr != 0) { + iRet = -EIO; + goto Exit; + } + + if (atomic_read(&AtomicSyncState_g) != + EVENT_STATE_READY) { + iRet = (int)kEplInvalidOperation; + goto Exit; + } + // exchange process image + EplRet = + EplApiProcessImageExchangeOut(&ProcessImageOut); + + // pass control to sync kernel thread + atomic_set(&AtomicSyncState_g, EVENT_STATE_TERM); + wake_up_interruptible(&WaitQueueCbSync_g); + + // return to EplApiProcessImageExchangeout() + iRet = (int)EplRet; + + break; + } + + // ---------------------------------------------------------- + case EPLLIN_CMD_NMT_COMMAND: + { + // forward NMT command to EPL stack + EplRet = EplApiExecNmtCommand((tEplNmtEvent) ulArg_p); + + iRet = (int)EplRet; + + break; + } + + // ---------------------------------------------------------- + default: + { + break; + } + } + + Exit: + +// TRACE1("EPL: - EplLinIoctl (iRet=%d)\n", iRet); + return (iRet); + +} + +//=========================================================================// +// // +// P R I V A T E F U N C T I O N S // +// // +//=========================================================================// + +tEplKernel PUBLIC EplLinCbEvent(tEplApiEventType EventType_p, // IN: event type (enum) + tEplApiEventArg * pEventArg_p, // IN: event argument (union) + void GENERIC * pUserArg_p) +{ + tEplKernel EplRet = kEplSuccessful; + int iErr; + + // block any further call to this function, i.e. enter critical section + iErr = down_interruptible(&SemaphoreCbEvent_g); + if (iErr != 0) { // waiting was interrupted by signal + EplRet = kEplShutdown; + goto Exit; + } + // wait for EplApiProcess() to call ioctl + // normally it should be waiting already for us to pass a new event + iErr = wait_event_interruptible(WaitQueueCbEvent_g, + (atomic_read(&AtomicEventState_g) == + EVENT_STATE_IOCTL) + || (atomic_read(&AtomicEventState_g) == + EVENT_STATE_TERM)); + if ((iErr != 0) || (atomic_read(&AtomicEventState_g) == EVENT_STATE_TERM)) { // waiting was interrupted by signal + EplRet = kEplShutdown; + goto LeaveCriticalSection; + } + // save event information for ioctl + EventType_g = EventType_p; + pEventArg_g = pEventArg_p; + + // pass control to application's event callback function, i.e. EplApiProcess() + atomic_set(&AtomicEventState_g, EVENT_STATE_READY); + wake_up_interruptible(&WaitQueueProcess_g); + + // now, the application's event callback function processes the event + + // wait for completion of application's event callback function, i.e. EplApiProcess() calls ioctl again + iErr = wait_event_interruptible(WaitQueueCbEvent_g, + (atomic_read(&AtomicEventState_g) == + EVENT_STATE_IOCTL) + || (atomic_read(&AtomicEventState_g) == + EVENT_STATE_TERM)); + if ((iErr != 0) || (atomic_read(&AtomicEventState_g) == EVENT_STATE_TERM)) { // waiting was interrupted by signal + EplRet = kEplShutdown; + goto LeaveCriticalSection; + } + // read return code from application's event callback function + EplRet = RetCbEvent_g; + + LeaveCriticalSection: + up(&SemaphoreCbEvent_g); + + Exit: + // check if NMT_GS_OFF is reached + if (EventType_p == kEplApiEventNmtStateChange) { + if (pEventArg_p->m_NmtStateChange.m_NewNmtState == kEplNmtGsOff) { // NMT state machine was shut down + TRACE0("EPL: EplLinCbEvent(NMT_GS_OFF)\n"); + uiEplState_g = EPL_STATE_SHUTDOWN; + atomic_set(&AtomicEventState_g, EVENT_STATE_TERM); + wake_up(&WaitQueueRelease_g); + } else { // NMT state machine is running + uiEplState_g = EPL_STATE_RUNNING; + } + } + + return EplRet; +} + +tEplKernel PUBLIC EplLinCbSync(void) +{ + tEplKernel EplRet = kEplSuccessful; + int iErr; + + // check if user process waits for sync + if (atomic_read(&AtomicSyncState_g) == EVENT_STATE_IOCTL) { + // pass control to application, i.e. EplApiProcessImageExchangeIn() + atomic_set(&AtomicSyncState_g, EVENT_STATE_READY); + wake_up_interruptible(&WaitQueuePI_In_g); + + // now, the application processes the sync event + + // wait for call of EplApiProcessImageExchangeOut() + iErr = wait_event_interruptible(WaitQueueCbSync_g, + (atomic_read(&AtomicSyncState_g) + == EVENT_STATE_IOCTL) + || + (atomic_read(&AtomicSyncState_g) + == EVENT_STATE_TERM)); + if ((iErr != 0) || (atomic_read(&AtomicEventState_g) == EVENT_STATE_IOCTL)) { // waiting was interrupted by signal or application called wrong function + EplRet = kEplShutdown; + } + } else { // application is currently not waiting for sync + // continue without interruption + // TPDO are set valid by caller (i.e. EplEventkProcess()) + } + + TGT_DBG_SIGNAL_TRACE_POINT(1); + + return EplRet; +} + +// EOF |