1 /****************************************************************************
3 (c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29
4 www.systec-electronic.com
8 Description: Linux kernel module as wrapper of EPL API layer,
9 i.e. counterpart to a Linux application
13 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions
17 1. Redistributions of source code must retain the above copyright
18 notice, this list of conditions and the following disclaimer.
20 2. Redistributions in binary form must reproduce the above copyright
21 notice, this list of conditions and the following disclaimer in the
22 documentation and/or other materials provided with the distribution.
24 3. Neither the name of SYSTEC electronic GmbH nor the names of its
25 contributors may be used to endorse or promote products derived
26 from this software without prior written permission. For written
27 permission, please contact info@systec-electronic.com.
29 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
32 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
33 COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
34 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
35 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
36 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
37 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
39 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
40 POSSIBILITY OF SUCH DAMAGE.
44 If a provision of this License is or becomes illegal, invalid or
45 unenforceable in any jurisdiction, that shall not affect:
46 1. the validity or enforceability in that jurisdiction of any other
47 provision of this License; or
48 2. the validity or enforceability in other jurisdictions of that or
49 any other provision of this License.
51 -------------------------------------------------------------------------
53 $RCSfile: EplApiLinuxKernel.c,v $
57 $Revision: 1.9 $ $Date: 2008/11/21 09:00:38 $
64 -------------------------------------------------------------------------
68 2006/10/11 d.k.: Initial Version
69 2008/04/10 m.u.: Changed to new char driver init
71 ****************************************************************************/
73 // kernel modul and driver
75 //#include <linux/version.h>
76 //#include <linux/config.h>
78 #include <linux/module.h>
80 #include <linux/cdev.h>
81 #include <linux/types.h>
83 //#include <linux/module.h>
84 //#include <linux/kernel.h>
85 //#include <linux/init.h>
86 //#include <linux/errno.h>
89 #include <linux/sched.h>
92 #include <asm/uaccess.h>
93 #include <linux/vmalloc.h>
95 #ifdef CONFIG_DEVFS_FS
96 #include <linux/major.h>
97 #include <linux/devfs_fs_kernel.h>
101 #include "EplApiLinux.h"
102 //#include "kernel/EplPdokCal.h"
105 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
106 // remove ("make invisible") obsolete symbols for kernel versions 2.6
108 #define MOD_INC_USE_COUNT
109 #define MOD_DEC_USE_COUNT
110 #define EXPORT_NO_SYMBOLS
112 #error "This driver needs a 2.6.x kernel or higher"
115 /***************************************************************************/
118 /* G L O B A L D E F I N I T I O N S */
121 /***************************************************************************/
124 MODULE_LICENSE("Dual BSD/GPL");
126 MODULE_AUTHOR("Daniel.Krueger@SYSTEC-electronic.com");
127 MODULE_DESCRIPTION("EPL API driver");
130 //---------------------------------------------------------------------------
132 //---------------------------------------------------------------------------
134 #define EPLLIN_DRV_NAME "systec_epl" // used for <register_chrdev>
136 //---------------------------------------------------------------------------
137 // Constant definitions
138 //---------------------------------------------------------------------------
140 // TracePoint support for realtime-debugging
141 #ifdef _DBG_TRACE_POINTS_
142 void PUBLIC TgtDbgSignalTracePoint(BYTE bTracePointNumber_p);
143 #define TGT_DBG_SIGNAL_TRACE_POINT(p) TgtDbgSignalTracePoint(p)
145 #define TGT_DBG_SIGNAL_TRACE_POINT(p)
148 #define EVENT_STATE_INIT 0
149 #define EVENT_STATE_IOCTL 1 // ioctl entered and ready to receive EPL event
150 #define EVENT_STATE_READY 2 // EPL event can be forwarded to user application
151 #define EVENT_STATE_TERM 3 // terminate processing
153 #define EPL_STATE_NOTOPEN 0
154 #define EPL_STATE_NOTINIT 1
155 #define EPL_STATE_RUNNING 2
156 #define EPL_STATE_SHUTDOWN 3
158 //---------------------------------------------------------------------------
160 //---------------------------------------------------------------------------
162 #ifdef CONFIG_DEVFS_FS
164 // driver major number
165 static int nDrvMajorNumber_g;
169 // device number (major and minor)
170 static dev_t nDevNum_g;
171 static struct cdev *pEpl_cdev_g;
175 static volatile unsigned int uiEplState_g = EPL_STATE_NOTOPEN;
177 static struct semaphore SemaphoreCbEvent_g; // semaphore for EplLinCbEvent
178 static wait_queue_head_t WaitQueueCbEvent_g; // wait queue EplLinCbEvent
179 static wait_queue_head_t WaitQueueProcess_g; // wait queue for EplApiProcess (user process)
180 static wait_queue_head_t WaitQueueRelease_g; // wait queue for EplLinRelease
181 static atomic_t AtomicEventState_g = ATOMIC_INIT(EVENT_STATE_INIT);
182 static tEplApiEventType EventType_g; // event type (enum)
183 static tEplApiEventArg *pEventArg_g; // event argument (union)
184 static tEplKernel RetCbEvent_g; // return code from event callback function
185 static wait_queue_head_t WaitQueueCbSync_g; // wait queue EplLinCbSync
186 static wait_queue_head_t WaitQueuePI_In_g; // wait queue for EplApiProcessImageExchangeIn (user process)
187 static atomic_t AtomicSyncState_g = ATOMIC_INIT(EVENT_STATE_INIT);
189 //---------------------------------------------------------------------------
191 //---------------------------------------------------------------------------
197 } tEplLinSdoBufHeader;
199 //---------------------------------------------------------------------------
201 //---------------------------------------------------------------------------
203 //---------------------------------------------------------------------------
204 // Prototypes of internal functions
205 //---------------------------------------------------------------------------
207 tEplKernel PUBLIC EplLinCbEvent(tEplApiEventType EventType_p, // IN: event type (enum)
208 tEplApiEventArg * pEventArg_p, // IN: event argument (union)
209 void GENERIC * pUserArg_p);
211 tEplKernel PUBLIC EplLinCbSync(void);
213 static int __init EplLinInit(void);
214 static void __exit EplLinExit(void);
216 static int EplLinOpen(struct inode *pDeviceFile_p, struct file *pInstance_p);
217 static int EplLinRelease(struct inode *pDeviceFile_p, struct file *pInstance_p);
218 static ssize_t EplLinRead(struct file *pInstance_p, char *pDstBuff_p,
219 size_t BuffSize_p, loff_t * pFileOffs_p);
220 static ssize_t EplLinWrite(struct file *pInstance_p, const char *pSrcBuff_p,
221 size_t BuffSize_p, loff_t * pFileOffs_p);
222 static int EplLinIoctl(struct inode *pDeviceFile_p, struct file *pInstance_p,
223 unsigned int uiIoctlCmd_p, unsigned long ulArg_p);
225 //---------------------------------------------------------------------------
226 // Kernel Module specific Data Structures
227 //---------------------------------------------------------------------------
231 module_init(EplLinInit);
232 module_exit(EplLinExit);
234 static struct file_operations EplLinFileOps_g = {
235 .owner = THIS_MODULE,
237 .release = EplLinRelease,
239 .write = EplLinWrite,
240 .ioctl = EplLinIoctl,
244 //=========================================================================//
246 // P U B L I C F U N C T I O N S //
248 //=========================================================================//
250 //---------------------------------------------------------------------------
252 //---------------------------------------------------------------------------
254 //---------------------------------------------------------------------------
256 static int __init EplLinInit(void)
262 #ifdef CONFIG_DEVFS_FS
266 TRACE0("EPL: + EplLinInit...\n");
267 TRACE2("EPL: Driver build: %s / %s\n", __DATE__, __TIME__);
271 // initialize global variables
272 atomic_set(&AtomicEventState_g, EVENT_STATE_INIT);
273 sema_init(&SemaphoreCbEvent_g, 1);
274 init_waitqueue_head(&WaitQueueCbEvent_g);
275 init_waitqueue_head(&WaitQueueProcess_g);
276 init_waitqueue_head(&WaitQueueRelease_g);
278 #ifdef CONFIG_DEVFS_FS
280 // register character device handler
281 TRACE2("EPL: Installing Driver '%s', Version %s...\n",
282 EPLLIN_DRV_NAME, EPL_PRODUCT_VERSION);
283 TRACE0("EPL: (using dynamic major number assignment)\n");
285 register_chrdev(0, EPLLIN_DRV_NAME, &EplLinFileOps_g);
286 if (nDrvMajorNumber_g != 0) {
288 ("EPL: Driver '%s' installed successful, assigned MajorNumber=%d\n",
289 EPLLIN_DRV_NAME, nDrvMajorNumber_g);
292 ("EPL: ERROR: Driver '%s' is unable to get a free MajorNumber!\n",
298 // create device node in DEVFS
300 TRACE1("EPL: Creating device node '/dev/%s'...\n", EPLLIN_DEV_NAME);
302 devfs_mk_cdev(MKDEV(nDrvMajorNumber_g, nMinorNumber),
303 S_IFCHR | S_IRUGO | S_IWUGO, EPLLIN_DEV_NAME);
305 TRACE1("EPL: Device node '/dev/%s' created successful.\n",
308 TRACE1("EPL: ERROR: unable to create device node '/dev/%s'\n",
316 // register character device handler
317 // only one Minor required
318 TRACE2("EPL: Installing Driver '%s', Version %s...\n",
319 EPLLIN_DRV_NAME, EPL_PRODUCT_VERSION);
320 iRet = alloc_chrdev_region(&nDevNum_g, 0, 1, EPLLIN_DRV_NAME);
323 ("EPL: Driver '%s' installed successful, assigned MajorNumber=%d\n",
324 EPLLIN_DRV_NAME, MAJOR(nDevNum_g));
327 ("EPL: ERROR: Driver '%s' is unable to get a free MajorNumber!\n",
333 // register cdev structure
334 pEpl_cdev_g = cdev_alloc();
335 pEpl_cdev_g->ops = &EplLinFileOps_g;
336 pEpl_cdev_g->owner = THIS_MODULE;
337 iErr = cdev_add(pEpl_cdev_g, nDevNum_g, 1);
339 TRACE2("EPL: ERROR %d: Driver '%s' could not be added!\n",
340 iErr, EPLLIN_DRV_NAME);
346 // create device node in PROCFS
347 EplRet = EplLinProcInit();
348 if (EplRet != kEplSuccessful) {
354 TRACE1("EPL: - EplLinInit (iRet=%d)\n", iRet);
359 //---------------------------------------------------------------------------
361 //---------------------------------------------------------------------------
363 //---------------------------------------------------------------------------
365 static void __exit EplLinExit(void)
370 // delete instance for all modules
371 // EplRet = EplApiShutdown();
372 // printk("EplApiShutdown(): 0x%X\n", EplRet);
374 // deinitialize proc fs
375 EplRet = EplLinProcFree();
376 printk("EplLinProcFree(): 0x%X\n", EplRet);
378 TRACE0("EPL: + EplLinExit...\n");
380 #ifdef CONFIG_DEVFS_FS
382 // remove device node from DEVFS
383 devfs_remove(EPLLIN_DEV_NAME);
384 TRACE1("EPL: Device node '/dev/%s' removed.\n", EPLLIN_DEV_NAME);
386 // unregister character device handler
387 unregister_chrdev(nDrvMajorNumber_g, EPLLIN_DRV_NAME);
391 // remove cdev structure
392 cdev_del(pEpl_cdev_g);
394 // unregister character device handler
395 unregister_chrdev_region(nDevNum_g, 1);
399 TRACE1("EPL: Driver '%s' removed.\n", EPLLIN_DRV_NAME);
401 TRACE0("EPL: - EplLinExit\n");
405 //---------------------------------------------------------------------------
407 //---------------------------------------------------------------------------
408 // -> open("/dev/driver", O_RDWR)...
409 //---------------------------------------------------------------------------
411 static int EplLinOpen(struct inode *pDeviceFile_p, // information about the device to open
412 struct file *pInstance_p) // information about driver instance
417 TRACE0("EPL: + EplLinOpen...\n");
421 if (uiEplState_g != EPL_STATE_NOTOPEN) { // stack already initialized
424 atomic_set(&AtomicEventState_g, EVENT_STATE_INIT);
425 sema_init(&SemaphoreCbEvent_g, 1);
426 init_waitqueue_head(&WaitQueueCbEvent_g);
427 init_waitqueue_head(&WaitQueueProcess_g);
428 init_waitqueue_head(&WaitQueueRelease_g);
429 atomic_set(&AtomicSyncState_g, EVENT_STATE_INIT);
430 init_waitqueue_head(&WaitQueueCbSync_g);
431 init_waitqueue_head(&WaitQueuePI_In_g);
433 uiEplState_g = EPL_STATE_NOTINIT;
437 TRACE1("EPL: - EplLinOpen (iRet=%d)\n", iRet);
442 //---------------------------------------------------------------------------
444 //---------------------------------------------------------------------------
445 // -> close(device)...
446 //---------------------------------------------------------------------------
448 static int EplLinRelease(struct inode *pDeviceFile_p, // information about the device to open
449 struct file *pInstance_p) // information about driver instance
452 tEplKernel EplRet = kEplSuccessful;
455 TRACE0("EPL: + EplLinRelease...\n");
457 if (uiEplState_g != EPL_STATE_NOTINIT) {
458 // pass control to sync kernel thread, but signal termination
459 atomic_set(&AtomicSyncState_g, EVENT_STATE_TERM);
460 wake_up_interruptible(&WaitQueueCbSync_g);
461 wake_up_interruptible(&WaitQueuePI_In_g);
463 // pass control to event queue kernel thread
464 atomic_set(&AtomicEventState_g, EVENT_STATE_TERM);
465 wake_up_interruptible(&WaitQueueCbEvent_g);
467 if (uiEplState_g == EPL_STATE_RUNNING) { // post NmtEventSwitchOff
468 EplRet = EplApiExecNmtCommand(kEplNmtEventSwitchOff);
472 if (EplRet == kEplSuccessful) {
473 TRACE0("EPL: waiting for NMT_GS_OFF\n");
474 wait_event_interruptible(WaitQueueRelease_g,
476 EPL_STATE_SHUTDOWN));
477 } else { // post NmtEventSwitchOff failed
478 TRACE0("EPL: event post failed\n");
481 // $$$ d.k.: What if waiting was interrupted by signal?
483 TRACE0("EPL: call EplApiShutdown()\n");
484 // EPL stack can be safely shut down
485 // delete instance for all EPL modules
486 EplRet = EplApiShutdown();
487 printk("EplApiShutdown(): 0x%X\n", EplRet);
490 uiEplState_g = EPL_STATE_NOTOPEN;
495 TRACE1("EPL: - EplLinRelease (iRet=%d)\n", iRet);
500 //---------------------------------------------------------------------------
501 // Read Data from Driver
502 //---------------------------------------------------------------------------
504 //---------------------------------------------------------------------------
506 static ssize_t EplLinRead(struct file *pInstance_p, // information about driver instance
507 char *pDstBuff_p, // address of buffer to fill with data
508 size_t BuffSize_p, // length of the buffer
509 loff_t * pFileOffs_p) // offset in the file
514 TRACE0("EPL: + EplLinRead...\n");
516 TRACE0("EPL: Sorry, this operation isn't supported.\n");
519 TRACE1("EPL: - EplLinRead (iRet=%d)\n", iRet);
524 //---------------------------------------------------------------------------
525 // Write Data to Driver
526 //---------------------------------------------------------------------------
528 //---------------------------------------------------------------------------
530 static ssize_t EplLinWrite(struct file *pInstance_p, // information about driver instance
531 const char *pSrcBuff_p, // address of buffer to get data from
532 size_t BuffSize_p, // length of the buffer
533 loff_t * pFileOffs_p) // offset in the file
538 TRACE0("EPL: + EplLinWrite...\n");
540 TRACE0("EPL: Sorry, this operation isn't supported.\n");
543 TRACE1("EPL: - EplLinWrite (iRet=%d)\n", iRet);
548 //---------------------------------------------------------------------------
549 // Generic Access to Driver
550 //---------------------------------------------------------------------------
552 //---------------------------------------------------------------------------
554 static int EplLinIoctl(struct inode *pDeviceFile_p, // information about the device to open
555 struct file *pInstance_p, // information about driver instance
556 unsigned int uiIoctlCmd_p, // Ioctl command to execute
557 unsigned long ulArg_p) // Ioctl command specific argument/parameter
564 // TRACE1("EPL: + EplLinIoctl (uiIoctlCmd_p=%d)...\n", uiIoctlCmd_p);
568 switch (uiIoctlCmd_p) {
569 // ----------------------------------------------------------
570 case EPLLIN_CMD_INITIALIZE:
572 tEplApiInitParam EplApiInitParam;
575 copy_from_user(&EplApiInitParam,
576 (const void *)ulArg_p,
577 sizeof(EplApiInitParam));
583 EplApiInitParam.m_pfnCbEvent = EplLinCbEvent;
584 EplApiInitParam.m_pfnCbSync = EplLinCbSync;
586 EplRet = EplApiInitialize(&EplApiInitParam);
588 uiEplState_g = EPL_STATE_RUNNING;
594 // ----------------------------------------------------------
595 case EPLLIN_CMD_SHUTDOWN:
596 { // shutdown the threads
598 // pass control to sync kernel thread, but signal termination
599 atomic_set(&AtomicSyncState_g, EVENT_STATE_TERM);
600 wake_up_interruptible(&WaitQueueCbSync_g);
601 wake_up_interruptible(&WaitQueuePI_In_g);
603 // pass control to event queue kernel thread
604 atomic_set(&AtomicEventState_g, EVENT_STATE_TERM);
605 wake_up_interruptible(&WaitQueueCbEvent_g);
607 if (uiEplState_g == EPL_STATE_RUNNING) { // post NmtEventSwitchOff
609 EplApiExecNmtCommand(kEplNmtEventSwitchOff);
617 // ----------------------------------------------------------
618 case EPLLIN_CMD_READ_LOCAL_OBJECT:
620 tEplLinLocalObject LocalObject;
624 copy_from_user(&LocalObject, (const void *)ulArg_p,
625 sizeof(LocalObject));
631 if ((LocalObject.m_pData == NULL)
632 || (LocalObject.m_uiSize == 0)) {
633 iRet = (int)kEplApiInvalidParam;
637 pData = vmalloc(LocalObject.m_uiSize);
638 if (pData == NULL) { // no memory available
644 EplApiReadLocalObject(LocalObject.m_uiIndex,
645 LocalObject.m_uiSubindex,
646 pData, &LocalObject.m_uiSize);
648 if (EplRet == kEplSuccessful) {
650 copy_to_user(LocalObject.m_pData, pData,
651 LocalObject.m_uiSize);
659 // return actual size (LocalObject.m_uiSize)
660 iErr = put_user(LocalObject.m_uiSize,
661 (unsigned int *)(ulArg_p +
680 // ----------------------------------------------------------
681 case EPLLIN_CMD_WRITE_LOCAL_OBJECT:
683 tEplLinLocalObject LocalObject;
687 copy_from_user(&LocalObject, (const void *)ulArg_p,
688 sizeof(LocalObject));
694 if ((LocalObject.m_pData == NULL)
695 || (LocalObject.m_uiSize == 0)) {
696 iRet = (int)kEplApiInvalidParam;
700 pData = vmalloc(LocalObject.m_uiSize);
701 if (pData == NULL) { // no memory available
706 copy_from_user(pData, LocalObject.m_pData,
707 LocalObject.m_uiSize);
714 EplApiWriteLocalObject(LocalObject.m_uiIndex,
715 LocalObject.m_uiSubindex,
716 pData, LocalObject.m_uiSize);
724 case EPLLIN_CMD_READ_OBJECT:
726 tEplLinSdoObject SdoObject;
728 tEplLinSdoBufHeader *pBufHeader;
729 tEplSdoComConHdl *pSdoComConHdl;
732 copy_from_user(&SdoObject, (const void *)ulArg_p,
739 if ((SdoObject.m_le_pData == NULL)
740 || (SdoObject.m_uiSize == 0)) {
741 iRet = (int)kEplApiInvalidParam;
746 (tEplLinSdoBufHeader *)
747 vmalloc(sizeof(tEplLinSdoBufHeader) +
749 if (pBufHeader == NULL) { // no memory available
753 // initiate temporary buffer
754 pBufHeader->m_pUserArg = SdoObject.m_pUserArg; // original user argument pointer
755 pBufHeader->m_pData = SdoObject.m_le_pData; // original data pointer from app
756 pData = pBufHeader + sizeof(tEplLinSdoBufHeader);
758 if (SdoObject.m_fValidSdoComConHdl != FALSE) {
759 pSdoComConHdl = &SdoObject.m_SdoComConHdl;
761 pSdoComConHdl = NULL;
765 EplApiReadObject(pSdoComConHdl,
766 SdoObject.m_uiNodeId,
768 SdoObject.m_uiSubindex, pData,
770 SdoObject.m_SdoType, pBufHeader);
772 // return actual SDO handle (SdoObject.m_SdoComConHdl)
773 iErr = put_user(SdoObject.m_SdoComConHdl,
774 (unsigned int *)(ulArg_p +
785 if (EplRet == kEplSuccessful) {
787 copy_to_user(SdoObject.m_le_pData, pData,
796 // return actual size (SdoObject.m_uiSize)
797 iErr = put_user(SdoObject.m_uiSize,
798 (unsigned int *)(ulArg_p +
808 } else if (EplRet != kEplApiTaskDeferred) { // error ocurred
820 case EPLLIN_CMD_WRITE_OBJECT:
822 tEplLinSdoObject SdoObject;
824 tEplLinSdoBufHeader *pBufHeader;
825 tEplSdoComConHdl *pSdoComConHdl;
828 copy_from_user(&SdoObject, (const void *)ulArg_p,
835 if ((SdoObject.m_le_pData == NULL)
836 || (SdoObject.m_uiSize == 0)) {
837 iRet = (int)kEplApiInvalidParam;
842 (tEplLinSdoBufHeader *)
843 vmalloc(sizeof(tEplLinSdoBufHeader) +
845 if (pBufHeader == NULL) { // no memory available
849 // initiate temporary buffer
850 pBufHeader->m_pUserArg = SdoObject.m_pUserArg; // original user argument pointer
851 pBufHeader->m_pData = SdoObject.m_le_pData; // original data pointer from app
852 pData = pBufHeader + sizeof(tEplLinSdoBufHeader);
855 copy_from_user(pData, SdoObject.m_le_pData,
863 if (SdoObject.m_fValidSdoComConHdl != FALSE) {
864 pSdoComConHdl = &SdoObject.m_SdoComConHdl;
866 pSdoComConHdl = NULL;
870 EplApiWriteObject(pSdoComConHdl,
871 SdoObject.m_uiNodeId,
873 SdoObject.m_uiSubindex, pData,
875 SdoObject.m_SdoType, pBufHeader);
877 // return actual SDO handle (SdoObject.m_SdoComConHdl)
878 iErr = put_user(SdoObject.m_SdoComConHdl,
879 (unsigned int *)(ulArg_p +
890 if (EplRet != kEplApiTaskDeferred) { // succeeded or error ocurred, but task not deferred
898 // ----------------------------------------------------------
899 case EPLLIN_CMD_FREE_SDO_CHANNEL:
901 // forward SDO handle to EPL stack
903 EplApiFreeSdoChannel((tEplSdoComConHdl) ulArg_p);
909 #if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
910 // ----------------------------------------------------------
911 case EPLLIN_CMD_MN_TRIGGER_STATE_CHANGE:
913 tEplLinNodeCmdObject NodeCmdObject;
916 copy_from_user(&NodeCmdObject,
917 (const void *)ulArg_p,
918 sizeof(NodeCmdObject));
925 EplApiMnTriggerStateChange(NodeCmdObject.m_uiNodeId,
933 // ----------------------------------------------------------
934 case EPLLIN_CMD_GET_EVENT:
938 // save event structure
940 copy_from_user(&Event, (const void *)ulArg_p,
946 // save return code from application's event callback function
947 RetCbEvent_g = Event.m_RetCbEvent;
949 if (RetCbEvent_g == kEplShutdown) {
950 // pass control to event queue kernel thread, but signal termination
951 atomic_set(&AtomicEventState_g,
953 wake_up_interruptible(&WaitQueueCbEvent_g);
954 // exit with error -> EplApiProcess() will leave the infinite loop
958 // pass control to event queue kernel thread
959 atomic_set(&AtomicEventState_g, EVENT_STATE_IOCTL);
960 wake_up_interruptible(&WaitQueueCbEvent_g);
962 // fall asleep itself in own wait queue
963 iErr = wait_event_interruptible(WaitQueueProcess_g,
965 (&AtomicEventState_g)
966 == EVENT_STATE_READY)
969 (&AtomicEventState_g)
970 == EVENT_STATE_TERM));
971 if (iErr != 0) { // waiting was interrupted by signal
972 // pass control to event queue kernel thread, but signal termination
973 atomic_set(&AtomicEventState_g,
975 wake_up_interruptible(&WaitQueueCbEvent_g);
976 // exit with this error -> EplApiProcess() will leave the infinite loop
979 } else if (atomic_read(&AtomicEventState_g) == EVENT_STATE_TERM) { // termination in progress
980 // pass control to event queue kernel thread, but signal termination
981 wake_up_interruptible(&WaitQueueCbEvent_g);
982 // exit with this error -> EplApiProcess() will leave the infinite loop
986 // copy event to user space
988 copy_to_user(Event.m_pEventType, &EventType_g,
989 sizeof(EventType_g));
990 if (iErr != 0) { // not all data could be copied
994 // $$$ d.k. perform SDO event processing
995 if (EventType_g == kEplApiEventSdo) {
997 tEplLinSdoBufHeader *pBufHeader;
1000 (tEplLinSdoBufHeader *) pEventArg_g->m_Sdo.
1003 pBufHeader + sizeof(tEplLinSdoBufHeader);
1005 if (pEventArg_g->m_Sdo.m_SdoAccessType ==
1006 kEplSdoAccessTypeRead) {
1007 // copy read data to user space
1009 copy_to_user(pBufHeader->m_pData,
1012 m_uiTransferredByte);
1013 if (iErr != 0) { // not all data could be copied
1018 pEventArg_g->m_Sdo.m_pUserArg =
1019 pBufHeader->m_pUserArg;
1024 copy_to_user(Event.m_pEventArg, pEventArg_g,
1025 min(sizeof(tEplApiEventArg),
1026 Event.m_uiEventArgSize));
1027 if (iErr != 0) { // not all data could be copied
1031 // return to EplApiProcess(), which will call the application's event callback function
1037 // ----------------------------------------------------------
1038 case EPLLIN_CMD_PI_SETUP:
1040 EplRet = EplApiProcessImageSetup();
1046 // ----------------------------------------------------------
1047 case EPLLIN_CMD_PI_IN:
1049 tEplApiProcessImage ProcessImageIn;
1051 // save process image structure
1053 copy_from_user(&ProcessImageIn,
1054 (const void *)ulArg_p,
1055 sizeof(ProcessImageIn));
1060 // pass control to event queue kernel thread
1061 atomic_set(&AtomicSyncState_g, EVENT_STATE_IOCTL);
1063 // fall asleep itself in own wait queue
1064 iErr = wait_event_interruptible(WaitQueuePI_In_g,
1066 (&AtomicSyncState_g) ==
1070 (&AtomicSyncState_g) ==
1072 if (iErr != 0) { // waiting was interrupted by signal
1073 // pass control to sync kernel thread, but signal termination
1074 atomic_set(&AtomicSyncState_g,
1076 wake_up_interruptible(&WaitQueueCbSync_g);
1077 // exit with this error -> application will leave the infinite loop
1080 } else if (atomic_read(&AtomicSyncState_g) == EVENT_STATE_TERM) { // termination in progress
1081 // pass control to sync kernel thread, but signal termination
1082 wake_up_interruptible(&WaitQueueCbSync_g);
1083 // exit with this error -> application will leave the infinite loop
1087 // exchange process image
1088 EplRet = EplApiProcessImageExchangeIn(&ProcessImageIn);
1090 // return to EplApiProcessImageExchangeIn()
1096 // ----------------------------------------------------------
1097 case EPLLIN_CMD_PI_OUT:
1099 tEplApiProcessImage ProcessImageOut;
1101 // save process image structure
1103 copy_from_user(&ProcessImageOut,
1104 (const void *)ulArg_p,
1105 sizeof(ProcessImageOut));
1111 if (atomic_read(&AtomicSyncState_g) !=
1112 EVENT_STATE_READY) {
1113 iRet = (int)kEplInvalidOperation;
1116 // exchange process image
1118 EplApiProcessImageExchangeOut(&ProcessImageOut);
1120 // pass control to sync kernel thread
1121 atomic_set(&AtomicSyncState_g, EVENT_STATE_TERM);
1122 wake_up_interruptible(&WaitQueueCbSync_g);
1124 // return to EplApiProcessImageExchangeout()
1130 // ----------------------------------------------------------
1131 case EPLLIN_CMD_NMT_COMMAND:
1133 // forward NMT command to EPL stack
1134 EplRet = EplApiExecNmtCommand((tEplNmtEvent) ulArg_p);
1141 // ----------------------------------------------------------
1150 // TRACE1("EPL: - EplLinIoctl (iRet=%d)\n", iRet);
1155 //=========================================================================//
1157 // P R I V A T E F U N C T I O N S //
1159 //=========================================================================//
1161 tEplKernel PUBLIC EplLinCbEvent(tEplApiEventType EventType_p, // IN: event type (enum)
1162 tEplApiEventArg * pEventArg_p, // IN: event argument (union)
1163 void GENERIC * pUserArg_p)
1165 tEplKernel EplRet = kEplSuccessful;
1168 // block any further call to this function, i.e. enter critical section
1169 iErr = down_interruptible(&SemaphoreCbEvent_g);
1170 if (iErr != 0) { // waiting was interrupted by signal
1171 EplRet = kEplShutdown;
1174 // wait for EplApiProcess() to call ioctl
1175 // normally it should be waiting already for us to pass a new event
1176 iErr = wait_event_interruptible(WaitQueueCbEvent_g,
1177 (atomic_read(&AtomicEventState_g) ==
1179 || (atomic_read(&AtomicEventState_g) ==
1181 if ((iErr != 0) || (atomic_read(&AtomicEventState_g) == EVENT_STATE_TERM)) { // waiting was interrupted by signal
1182 EplRet = kEplShutdown;
1183 goto LeaveCriticalSection;
1185 // save event information for ioctl
1186 EventType_g = EventType_p;
1187 pEventArg_g = pEventArg_p;
1189 // pass control to application's event callback function, i.e. EplApiProcess()
1190 atomic_set(&AtomicEventState_g, EVENT_STATE_READY);
1191 wake_up_interruptible(&WaitQueueProcess_g);
1193 // now, the application's event callback function processes the event
1195 // wait for completion of application's event callback function, i.e. EplApiProcess() calls ioctl again
1196 iErr = wait_event_interruptible(WaitQueueCbEvent_g,
1197 (atomic_read(&AtomicEventState_g) ==
1199 || (atomic_read(&AtomicEventState_g) ==
1201 if ((iErr != 0) || (atomic_read(&AtomicEventState_g) == EVENT_STATE_TERM)) { // waiting was interrupted by signal
1202 EplRet = kEplShutdown;
1203 goto LeaveCriticalSection;
1205 // read return code from application's event callback function
1206 EplRet = RetCbEvent_g;
1208 LeaveCriticalSection:
1209 up(&SemaphoreCbEvent_g);
1212 // check if NMT_GS_OFF is reached
1213 if (EventType_p == kEplApiEventNmtStateChange) {
1214 if (pEventArg_p->m_NmtStateChange.m_NewNmtState == kEplNmtGsOff) { // NMT state machine was shut down
1215 TRACE0("EPL: EplLinCbEvent(NMT_GS_OFF)\n");
1216 uiEplState_g = EPL_STATE_SHUTDOWN;
1217 atomic_set(&AtomicEventState_g, EVENT_STATE_TERM);
1218 wake_up(&WaitQueueRelease_g);
1219 } else { // NMT state machine is running
1220 uiEplState_g = EPL_STATE_RUNNING;
1227 tEplKernel PUBLIC EplLinCbSync(void)
1229 tEplKernel EplRet = kEplSuccessful;
1232 // check if user process waits for sync
1233 if (atomic_read(&AtomicSyncState_g) == EVENT_STATE_IOCTL) {
1234 // pass control to application, i.e. EplApiProcessImageExchangeIn()
1235 atomic_set(&AtomicSyncState_g, EVENT_STATE_READY);
1236 wake_up_interruptible(&WaitQueuePI_In_g);
1238 // now, the application processes the sync event
1240 // wait for call of EplApiProcessImageExchangeOut()
1241 iErr = wait_event_interruptible(WaitQueueCbSync_g,
1242 (atomic_read(&AtomicSyncState_g)
1243 == EVENT_STATE_IOCTL)
1245 (atomic_read(&AtomicSyncState_g)
1246 == EVENT_STATE_TERM));
1247 if ((iErr != 0) || (atomic_read(&AtomicEventState_g) == EVENT_STATE_IOCTL)) { // waiting was interrupted by signal or application called wrong function
1248 EplRet = kEplShutdown;
1250 } else { // application is currently not waiting for sync
1251 // continue without interruption
1252 // TPDO are set valid by caller (i.e. EplEventkProcess())
1255 TGT_DBG_SIGNAL_TRACE_POINT(1);