diff options
Diffstat (limited to 'drivers/staging/epl/EplApiLinuxKernel.c')
-rw-r--r-- | drivers/staging/epl/EplApiLinuxKernel.c | 1317 |
1 files changed, 1317 insertions, 0 deletions
diff --git a/drivers/staging/epl/EplApiLinuxKernel.c b/drivers/staging/epl/EplApiLinuxKernel.c new file mode 100644 index 00000000000..4941760c66f --- /dev/null +++ b/drivers/staging/epl/EplApiLinuxKernel.c @@ -0,0 +1,1317 @@ +/**************************************************************************** + + (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 + |