aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/epl/EplApiLinuxKernel.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/epl/EplApiLinuxKernel.c')
-rw-r--r--drivers/staging/epl/EplApiLinuxKernel.c1260
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 000000000000..05ca0628d6ae
--- /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