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/module.h>
77 #include <linux/cdev.h>
78 #include <linux/types.h>
80 //#include <linux/module.h>
81 //#include <linux/kernel.h>
82 //#include <linux/init.h>
83 //#include <linux/errno.h>
86 #include <linux/sched.h>
89 #include <asm/uaccess.h>
90 #include <linux/vmalloc.h>
93 #include "EplApiLinux.h"
94 //#include "kernel/EplPdokCal.h"
98 /***************************************************************************/
101 /* G L O B A L D E F I N I T I O N S */
104 /***************************************************************************/
107 MODULE_LICENSE("Dual BSD/GPL");
109 MODULE_AUTHOR("Daniel.Krueger@SYSTEC-electronic.com");
110 MODULE_DESCRIPTION("EPL API driver");
113 //---------------------------------------------------------------------------
115 //---------------------------------------------------------------------------
117 #define EPLLIN_DRV_NAME "systec_epl" // used for <register_chrdev>
119 //---------------------------------------------------------------------------
120 // Constant definitions
121 //---------------------------------------------------------------------------
123 // TracePoint support for realtime-debugging
124 #ifdef _DBG_TRACE_POINTS_
125 void TgtDbgSignalTracePoint(u8 bTracePointNumber_p);
126 #define TGT_DBG_SIGNAL_TRACE_POINT(p) TgtDbgSignalTracePoint(p)
128 #define TGT_DBG_SIGNAL_TRACE_POINT(p)
131 #define EVENT_STATE_INIT 0
132 #define EVENT_STATE_IOCTL 1 // ioctl entered and ready to receive EPL event
133 #define EVENT_STATE_READY 2 // EPL event can be forwarded to user application
134 #define EVENT_STATE_TERM 3 // terminate processing
136 #define EPL_STATE_NOTOPEN 0
137 #define EPL_STATE_NOTINIT 1
138 #define EPL_STATE_RUNNING 2
139 #define EPL_STATE_SHUTDOWN 3
141 //---------------------------------------------------------------------------
143 //---------------------------------------------------------------------------
145 // device number (major and minor)
146 static dev_t nDevNum_g;
147 static struct cdev *pEpl_cdev_g;
149 static volatile unsigned int uiEplState_g = EPL_STATE_NOTOPEN;
151 static struct semaphore SemaphoreCbEvent_g; // semaphore for EplLinCbEvent
152 static wait_queue_head_t WaitQueueCbEvent_g; // wait queue EplLinCbEvent
153 static wait_queue_head_t WaitQueueProcess_g; // wait queue for EplApiProcess (user process)
154 static wait_queue_head_t WaitQueueRelease_g; // wait queue for EplLinRelease
155 static atomic_t AtomicEventState_g = ATOMIC_INIT(EVENT_STATE_INIT);
156 static tEplApiEventType EventType_g; // event type (enum)
157 static tEplApiEventArg *pEventArg_g; // event argument (union)
158 static tEplKernel RetCbEvent_g; // return code from event callback function
159 static wait_queue_head_t WaitQueueCbSync_g; // wait queue EplLinCbSync
160 static wait_queue_head_t WaitQueuePI_In_g; // wait queue for EplApiProcessImageExchangeIn (user process)
161 static atomic_t AtomicSyncState_g = ATOMIC_INIT(EVENT_STATE_INIT);
163 //---------------------------------------------------------------------------
165 //---------------------------------------------------------------------------
171 } tEplLinSdoBufHeader;
173 //---------------------------------------------------------------------------
175 //---------------------------------------------------------------------------
177 //---------------------------------------------------------------------------
178 // Prototypes of internal functions
179 //---------------------------------------------------------------------------
181 tEplKernel EplLinCbEvent(tEplApiEventType EventType_p, // IN: event type (enum)
182 tEplApiEventArg *pEventArg_p, // IN: event argument (union)
185 tEplKernel EplLinCbSync(void);
187 static int __init EplLinInit(void);
188 static void __exit EplLinExit(void);
190 static int EplLinOpen(struct inode *pDeviceFile_p, struct file *pInstance_p);
191 static int EplLinRelease(struct inode *pDeviceFile_p, struct file *pInstance_p);
192 static ssize_t EplLinRead(struct file *pInstance_p, char *pDstBuff_p,
193 size_t BuffSize_p, loff_t * pFileOffs_p);
194 static ssize_t EplLinWrite(struct file *pInstance_p, const char *pSrcBuff_p,
195 size_t BuffSize_p, loff_t * pFileOffs_p);
196 static int EplLinIoctl(struct inode *pDeviceFile_p, struct file *pInstance_p,
197 unsigned int uiIoctlCmd_p, unsigned long ulArg_p);
199 //---------------------------------------------------------------------------
200 // Kernel Module specific Data Structures
201 //---------------------------------------------------------------------------
203 module_init(EplLinInit);
204 module_exit(EplLinExit);
206 static struct file_operations EplLinFileOps_g = {
207 .owner = THIS_MODULE,
209 .release = EplLinRelease,
211 .write = EplLinWrite,
212 .ioctl = EplLinIoctl,
216 //=========================================================================//
218 // P U B L I C F U N C T I O N S //
220 //=========================================================================//
222 //---------------------------------------------------------------------------
224 //---------------------------------------------------------------------------
226 //---------------------------------------------------------------------------
228 static int __init EplLinInit(void)
235 TRACE0("EPL: + EplLinInit...\n");
236 TRACE2("EPL: Driver build: %s / %s\n", __DATE__, __TIME__);
240 // initialize global variables
241 atomic_set(&AtomicEventState_g, EVENT_STATE_INIT);
242 sema_init(&SemaphoreCbEvent_g, 1);
243 init_waitqueue_head(&WaitQueueCbEvent_g);
244 init_waitqueue_head(&WaitQueueProcess_g);
245 init_waitqueue_head(&WaitQueueRelease_g);
247 // register character device handler
248 // only one Minor required
249 TRACE2("EPL: Installing Driver '%s', Version %s...\n",
250 EPLLIN_DRV_NAME, EPL_PRODUCT_VERSION);
251 iRet = alloc_chrdev_region(&nDevNum_g, 0, 1, EPLLIN_DRV_NAME);
254 ("EPL: Driver '%s' installed successful, assigned MajorNumber=%d\n",
255 EPLLIN_DRV_NAME, MAJOR(nDevNum_g));
258 ("EPL: ERROR: Driver '%s' is unable to get a free MajorNumber!\n",
264 // register cdev structure
265 pEpl_cdev_g = cdev_alloc();
266 pEpl_cdev_g->ops = &EplLinFileOps_g;
267 pEpl_cdev_g->owner = THIS_MODULE;
268 iErr = cdev_add(pEpl_cdev_g, nDevNum_g, 1);
270 TRACE2("EPL: ERROR %d: Driver '%s' could not be added!\n",
271 iErr, EPLLIN_DRV_NAME);
276 // create device node in PROCFS
277 EplRet = EplLinProcInit();
278 if (EplRet != kEplSuccessful) {
284 TRACE1("EPL: - EplLinInit (iRet=%d)\n", iRet);
289 //---------------------------------------------------------------------------
291 //---------------------------------------------------------------------------
293 //---------------------------------------------------------------------------
295 static void __exit EplLinExit(void)
300 // delete instance for all modules
301 // EplRet = EplApiShutdown();
302 // printk("EplApiShutdown(): 0x%X\n", EplRet);
304 // deinitialize proc fs
305 EplRet = EplLinProcFree();
306 printk("EplLinProcFree(): 0x%X\n", EplRet);
308 TRACE0("EPL: + EplLinExit...\n");
310 // remove cdev structure
311 cdev_del(pEpl_cdev_g);
313 // unregister character device handler
314 unregister_chrdev_region(nDevNum_g, 1);
316 TRACE1("EPL: Driver '%s' removed.\n", EPLLIN_DRV_NAME);
318 TRACE0("EPL: - EplLinExit\n");
322 //---------------------------------------------------------------------------
324 //---------------------------------------------------------------------------
325 // -> open("/dev/driver", O_RDWR)...
326 //---------------------------------------------------------------------------
328 static int EplLinOpen(struct inode *pDeviceFile_p, // information about the device to open
329 struct file *pInstance_p) // information about driver instance
334 TRACE0("EPL: + EplLinOpen...\n");
336 if (uiEplState_g != EPL_STATE_NOTOPEN) { // stack already initialized
339 atomic_set(&AtomicEventState_g, EVENT_STATE_INIT);
340 sema_init(&SemaphoreCbEvent_g, 1);
341 init_waitqueue_head(&WaitQueueCbEvent_g);
342 init_waitqueue_head(&WaitQueueProcess_g);
343 init_waitqueue_head(&WaitQueueRelease_g);
344 atomic_set(&AtomicSyncState_g, EVENT_STATE_INIT);
345 init_waitqueue_head(&WaitQueueCbSync_g);
346 init_waitqueue_head(&WaitQueuePI_In_g);
348 uiEplState_g = EPL_STATE_NOTINIT;
352 TRACE1("EPL: - EplLinOpen (iRet=%d)\n", iRet);
357 //---------------------------------------------------------------------------
359 //---------------------------------------------------------------------------
360 // -> close(device)...
361 //---------------------------------------------------------------------------
363 static int EplLinRelease(struct inode *pDeviceFile_p, // information about the device to open
364 struct file *pInstance_p) // information about driver instance
367 tEplKernel EplRet = kEplSuccessful;
370 TRACE0("EPL: + EplLinRelease...\n");
372 if (uiEplState_g != EPL_STATE_NOTINIT) {
373 // pass control to sync kernel thread, but signal termination
374 atomic_set(&AtomicSyncState_g, EVENT_STATE_TERM);
375 wake_up_interruptible(&WaitQueueCbSync_g);
376 wake_up_interruptible(&WaitQueuePI_In_g);
378 // pass control to event queue kernel thread
379 atomic_set(&AtomicEventState_g, EVENT_STATE_TERM);
380 wake_up_interruptible(&WaitQueueCbEvent_g);
382 if (uiEplState_g == EPL_STATE_RUNNING) { // post NmtEventSwitchOff
383 EplRet = EplApiExecNmtCommand(kEplNmtEventSwitchOff);
387 if (EplRet == kEplSuccessful) {
388 TRACE0("EPL: waiting for NMT_GS_OFF\n");
389 wait_event_interruptible(WaitQueueRelease_g,
391 EPL_STATE_SHUTDOWN));
392 } else { // post NmtEventSwitchOff failed
393 TRACE0("EPL: event post failed\n");
396 // $$$ d.k.: What if waiting was interrupted by signal?
398 TRACE0("EPL: call EplApiShutdown()\n");
399 // EPL stack can be safely shut down
400 // delete instance for all EPL modules
401 EplRet = EplApiShutdown();
402 printk("EplApiShutdown(): 0x%X\n", EplRet);
405 uiEplState_g = EPL_STATE_NOTOPEN;
408 TRACE1("EPL: - EplLinRelease (iRet=%d)\n", iRet);
413 //---------------------------------------------------------------------------
414 // Read Data from Driver
415 //---------------------------------------------------------------------------
417 //---------------------------------------------------------------------------
419 static ssize_t EplLinRead(struct file *pInstance_p, // information about driver instance
420 char *pDstBuff_p, // address of buffer to fill with data
421 size_t BuffSize_p, // length of the buffer
422 loff_t * pFileOffs_p) // offset in the file
427 TRACE0("EPL: + EplLinRead...\n");
429 TRACE0("EPL: Sorry, this operation isn't supported.\n");
432 TRACE1("EPL: - EplLinRead (iRet=%d)\n", iRet);
437 //---------------------------------------------------------------------------
438 // Write Data to Driver
439 //---------------------------------------------------------------------------
441 //---------------------------------------------------------------------------
443 static ssize_t EplLinWrite(struct file *pInstance_p, // information about driver instance
444 const char *pSrcBuff_p, // address of buffer to get data from
445 size_t BuffSize_p, // length of the buffer
446 loff_t * pFileOffs_p) // offset in the file
451 TRACE0("EPL: + EplLinWrite...\n");
453 TRACE0("EPL: Sorry, this operation isn't supported.\n");
456 TRACE1("EPL: - EplLinWrite (iRet=%d)\n", iRet);
461 //---------------------------------------------------------------------------
462 // Generic Access to Driver
463 //---------------------------------------------------------------------------
465 //---------------------------------------------------------------------------
467 static int EplLinIoctl(struct inode *pDeviceFile_p, // information about the device to open
468 struct file *pInstance_p, // information about driver instance
469 unsigned int uiIoctlCmd_p, // Ioctl command to execute
470 unsigned long ulArg_p) // Ioctl command specific argument/parameter
477 // TRACE1("EPL: + EplLinIoctl (uiIoctlCmd_p=%d)...\n", uiIoctlCmd_p);
481 switch (uiIoctlCmd_p) {
482 // ----------------------------------------------------------
483 case EPLLIN_CMD_INITIALIZE:
485 tEplApiInitParam EplApiInitParam;
488 copy_from_user(&EplApiInitParam,
489 (const void *)ulArg_p,
490 sizeof(EplApiInitParam));
496 EplApiInitParam.m_pfnCbEvent = EplLinCbEvent;
497 EplApiInitParam.m_pfnCbSync = EplLinCbSync;
499 EplRet = EplApiInitialize(&EplApiInitParam);
501 uiEplState_g = EPL_STATE_RUNNING;
507 // ----------------------------------------------------------
508 case EPLLIN_CMD_SHUTDOWN:
509 { // shutdown the threads
511 // pass control to sync kernel thread, but signal termination
512 atomic_set(&AtomicSyncState_g, EVENT_STATE_TERM);
513 wake_up_interruptible(&WaitQueueCbSync_g);
514 wake_up_interruptible(&WaitQueuePI_In_g);
516 // pass control to event queue kernel thread
517 atomic_set(&AtomicEventState_g, EVENT_STATE_TERM);
518 wake_up_interruptible(&WaitQueueCbEvent_g);
520 if (uiEplState_g == EPL_STATE_RUNNING) { // post NmtEventSwitchOff
522 EplApiExecNmtCommand(kEplNmtEventSwitchOff);
530 // ----------------------------------------------------------
531 case EPLLIN_CMD_READ_LOCAL_OBJECT:
533 tEplLinLocalObject LocalObject;
537 copy_from_user(&LocalObject, (const void *)ulArg_p,
538 sizeof(LocalObject));
544 if ((LocalObject.m_pData == NULL)
545 || (LocalObject.m_uiSize == 0)) {
546 iRet = (int)kEplApiInvalidParam;
550 pData = vmalloc(LocalObject.m_uiSize);
551 if (pData == NULL) { // no memory available
557 EplApiReadLocalObject(LocalObject.m_uiIndex,
558 LocalObject.m_uiSubindex,
559 pData, &LocalObject.m_uiSize);
561 if (EplRet == kEplSuccessful) {
563 copy_to_user(LocalObject.m_pData, pData,
564 LocalObject.m_uiSize);
572 // return actual size (LocalObject.m_uiSize)
573 iErr = put_user(LocalObject.m_uiSize,
574 (unsigned int *)(ulArg_p +
593 // ----------------------------------------------------------
594 case EPLLIN_CMD_WRITE_LOCAL_OBJECT:
596 tEplLinLocalObject LocalObject;
600 copy_from_user(&LocalObject, (const void *)ulArg_p,
601 sizeof(LocalObject));
607 if ((LocalObject.m_pData == NULL)
608 || (LocalObject.m_uiSize == 0)) {
609 iRet = (int)kEplApiInvalidParam;
613 pData = vmalloc(LocalObject.m_uiSize);
614 if (pData == NULL) { // no memory available
619 copy_from_user(pData, LocalObject.m_pData,
620 LocalObject.m_uiSize);
627 EplApiWriteLocalObject(LocalObject.m_uiIndex,
628 LocalObject.m_uiSubindex,
629 pData, LocalObject.m_uiSize);
637 case EPLLIN_CMD_READ_OBJECT:
639 tEplLinSdoObject SdoObject;
641 tEplLinSdoBufHeader *pBufHeader;
642 tEplSdoComConHdl *pSdoComConHdl;
645 copy_from_user(&SdoObject, (const void *)ulArg_p,
652 if ((SdoObject.m_le_pData == NULL)
653 || (SdoObject.m_uiSize == 0)) {
654 iRet = (int)kEplApiInvalidParam;
659 (tEplLinSdoBufHeader *)
660 vmalloc(sizeof(tEplLinSdoBufHeader) +
662 if (pBufHeader == NULL) { // no memory available
666 // initiate temporary buffer
667 pBufHeader->m_pUserArg = SdoObject.m_pUserArg; // original user argument pointer
668 pBufHeader->m_pData = SdoObject.m_le_pData; // original data pointer from app
669 pData = pBufHeader + sizeof(tEplLinSdoBufHeader);
671 if (SdoObject.m_fValidSdoComConHdl != FALSE) {
672 pSdoComConHdl = &SdoObject.m_SdoComConHdl;
674 pSdoComConHdl = NULL;
678 EplApiReadObject(pSdoComConHdl,
679 SdoObject.m_uiNodeId,
681 SdoObject.m_uiSubindex, pData,
683 SdoObject.m_SdoType, pBufHeader);
685 // return actual SDO handle (SdoObject.m_SdoComConHdl)
686 iErr = put_user(SdoObject.m_SdoComConHdl,
687 (unsigned int *)(ulArg_p +
698 if (EplRet == kEplSuccessful) {
700 copy_to_user(SdoObject.m_le_pData, pData,
709 // return actual size (SdoObject.m_uiSize)
710 iErr = put_user(SdoObject.m_uiSize,
711 (unsigned int *)(ulArg_p +
721 } else if (EplRet != kEplApiTaskDeferred) { // error ocurred
733 case EPLLIN_CMD_WRITE_OBJECT:
735 tEplLinSdoObject SdoObject;
737 tEplLinSdoBufHeader *pBufHeader;
738 tEplSdoComConHdl *pSdoComConHdl;
741 copy_from_user(&SdoObject, (const void *)ulArg_p,
748 if ((SdoObject.m_le_pData == NULL)
749 || (SdoObject.m_uiSize == 0)) {
750 iRet = (int)kEplApiInvalidParam;
755 (tEplLinSdoBufHeader *)
756 vmalloc(sizeof(tEplLinSdoBufHeader) +
758 if (pBufHeader == NULL) { // no memory available
762 // initiate temporary buffer
763 pBufHeader->m_pUserArg = SdoObject.m_pUserArg; // original user argument pointer
764 pBufHeader->m_pData = SdoObject.m_le_pData; // original data pointer from app
765 pData = pBufHeader + sizeof(tEplLinSdoBufHeader);
768 copy_from_user(pData, SdoObject.m_le_pData,
776 if (SdoObject.m_fValidSdoComConHdl != FALSE) {
777 pSdoComConHdl = &SdoObject.m_SdoComConHdl;
779 pSdoComConHdl = NULL;
783 EplApiWriteObject(pSdoComConHdl,
784 SdoObject.m_uiNodeId,
786 SdoObject.m_uiSubindex, pData,
788 SdoObject.m_SdoType, pBufHeader);
790 // return actual SDO handle (SdoObject.m_SdoComConHdl)
791 iErr = put_user(SdoObject.m_SdoComConHdl,
792 (unsigned int *)(ulArg_p +
803 if (EplRet != kEplApiTaskDeferred) { // succeeded or error ocurred, but task not deferred
811 // ----------------------------------------------------------
812 case EPLLIN_CMD_FREE_SDO_CHANNEL:
814 // forward SDO handle to EPL stack
816 EplApiFreeSdoChannel((tEplSdoComConHdl) ulArg_p);
822 #if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
823 // ----------------------------------------------------------
824 case EPLLIN_CMD_MN_TRIGGER_STATE_CHANGE:
826 tEplLinNodeCmdObject NodeCmdObject;
829 copy_from_user(&NodeCmdObject,
830 (const void *)ulArg_p,
831 sizeof(NodeCmdObject));
838 EplApiMnTriggerStateChange(NodeCmdObject.m_uiNodeId,
846 // ----------------------------------------------------------
847 case EPLLIN_CMD_GET_EVENT:
851 // save event structure
853 copy_from_user(&Event, (const void *)ulArg_p,
859 // save return code from application's event callback function
860 RetCbEvent_g = Event.m_RetCbEvent;
862 if (RetCbEvent_g == kEplShutdown) {
863 // pass control to event queue kernel thread, but signal termination
864 atomic_set(&AtomicEventState_g,
866 wake_up_interruptible(&WaitQueueCbEvent_g);
867 // exit with error -> EplApiProcess() will leave the infinite loop
871 // pass control to event queue kernel thread
872 atomic_set(&AtomicEventState_g, EVENT_STATE_IOCTL);
873 wake_up_interruptible(&WaitQueueCbEvent_g);
875 // fall asleep itself in own wait queue
876 iErr = wait_event_interruptible(WaitQueueProcess_g,
878 (&AtomicEventState_g)
879 == EVENT_STATE_READY)
882 (&AtomicEventState_g)
883 == EVENT_STATE_TERM));
884 if (iErr != 0) { // waiting was interrupted by signal
885 // pass control to event queue kernel thread, but signal termination
886 atomic_set(&AtomicEventState_g,
888 wake_up_interruptible(&WaitQueueCbEvent_g);
889 // exit with this error -> EplApiProcess() will leave the infinite loop
892 } else if (atomic_read(&AtomicEventState_g) == EVENT_STATE_TERM) { // termination in progress
893 // pass control to event queue kernel thread, but signal termination
894 wake_up_interruptible(&WaitQueueCbEvent_g);
895 // exit with this error -> EplApiProcess() will leave the infinite loop
899 // copy event to user space
901 copy_to_user(Event.m_pEventType, &EventType_g,
902 sizeof(EventType_g));
903 if (iErr != 0) { // not all data could be copied
907 // $$$ d.k. perform SDO event processing
908 if (EventType_g == kEplApiEventSdo) {
910 tEplLinSdoBufHeader *pBufHeader;
913 (tEplLinSdoBufHeader *) pEventArg_g->m_Sdo.
916 pBufHeader + sizeof(tEplLinSdoBufHeader);
918 if (pEventArg_g->m_Sdo.m_SdoAccessType ==
919 kEplSdoAccessTypeRead) {
920 // copy read data to user space
922 copy_to_user(pBufHeader->m_pData,
925 m_uiTransferredByte);
926 if (iErr != 0) { // not all data could be copied
931 pEventArg_g->m_Sdo.m_pUserArg =
932 pBufHeader->m_pUserArg;
937 copy_to_user(Event.m_pEventArg, pEventArg_g,
938 min(sizeof(tEplApiEventArg),
939 Event.m_uiEventArgSize));
940 if (iErr != 0) { // not all data could be copied
944 // return to EplApiProcess(), which will call the application's event callback function
950 // ----------------------------------------------------------
951 case EPLLIN_CMD_PI_SETUP:
953 EplRet = EplApiProcessImageSetup();
959 // ----------------------------------------------------------
960 case EPLLIN_CMD_PI_IN:
962 tEplApiProcessImage ProcessImageIn;
964 // save process image structure
966 copy_from_user(&ProcessImageIn,
967 (const void *)ulArg_p,
968 sizeof(ProcessImageIn));
973 // pass control to event queue kernel thread
974 atomic_set(&AtomicSyncState_g, EVENT_STATE_IOCTL);
976 // fall asleep itself in own wait queue
977 iErr = wait_event_interruptible(WaitQueuePI_In_g,
979 (&AtomicSyncState_g) ==
983 (&AtomicSyncState_g) ==
985 if (iErr != 0) { // waiting was interrupted by signal
986 // pass control to sync kernel thread, but signal termination
987 atomic_set(&AtomicSyncState_g,
989 wake_up_interruptible(&WaitQueueCbSync_g);
990 // exit with this error -> application will leave the infinite loop
993 } else if (atomic_read(&AtomicSyncState_g) == EVENT_STATE_TERM) { // termination in progress
994 // pass control to sync kernel thread, but signal termination
995 wake_up_interruptible(&WaitQueueCbSync_g);
996 // exit with this error -> application will leave the infinite loop
1000 // exchange process image
1001 EplRet = EplApiProcessImageExchangeIn(&ProcessImageIn);
1003 // return to EplApiProcessImageExchangeIn()
1009 // ----------------------------------------------------------
1010 case EPLLIN_CMD_PI_OUT:
1012 tEplApiProcessImage ProcessImageOut;
1014 // save process image structure
1016 copy_from_user(&ProcessImageOut,
1017 (const void *)ulArg_p,
1018 sizeof(ProcessImageOut));
1024 if (atomic_read(&AtomicSyncState_g) !=
1025 EVENT_STATE_READY) {
1026 iRet = (int)kEplInvalidOperation;
1029 // exchange process image
1031 EplApiProcessImageExchangeOut(&ProcessImageOut);
1033 // pass control to sync kernel thread
1034 atomic_set(&AtomicSyncState_g, EVENT_STATE_TERM);
1035 wake_up_interruptible(&WaitQueueCbSync_g);
1037 // return to EplApiProcessImageExchangeout()
1043 // ----------------------------------------------------------
1044 case EPLLIN_CMD_NMT_COMMAND:
1046 // forward NMT command to EPL stack
1047 EplRet = EplApiExecNmtCommand((tEplNmtEvent) ulArg_p);
1054 // ----------------------------------------------------------
1063 // TRACE1("EPL: - EplLinIoctl (iRet=%d)\n", iRet);
1068 //=========================================================================//
1070 // P R I V A T E F U N C T I O N S //
1072 //=========================================================================//
1074 tEplKernel EplLinCbEvent(tEplApiEventType EventType_p, // IN: event type (enum)
1075 tEplApiEventArg *pEventArg_p, // IN: event argument (union)
1078 tEplKernel EplRet = kEplSuccessful;
1081 // block any further call to this function, i.e. enter critical section
1082 iErr = down_interruptible(&SemaphoreCbEvent_g);
1083 if (iErr != 0) { // waiting was interrupted by signal
1084 EplRet = kEplShutdown;
1087 // wait for EplApiProcess() to call ioctl
1088 // normally it should be waiting already for us to pass a new event
1089 iErr = wait_event_interruptible(WaitQueueCbEvent_g,
1090 (atomic_read(&AtomicEventState_g) ==
1092 || (atomic_read(&AtomicEventState_g) ==
1094 if ((iErr != 0) || (atomic_read(&AtomicEventState_g) == EVENT_STATE_TERM)) { // waiting was interrupted by signal
1095 EplRet = kEplShutdown;
1096 goto LeaveCriticalSection;
1098 // save event information for ioctl
1099 EventType_g = EventType_p;
1100 pEventArg_g = pEventArg_p;
1102 // pass control to application's event callback function, i.e. EplApiProcess()
1103 atomic_set(&AtomicEventState_g, EVENT_STATE_READY);
1104 wake_up_interruptible(&WaitQueueProcess_g);
1106 // now, the application's event callback function processes the event
1108 // wait for completion of application's event callback function, i.e. EplApiProcess() calls ioctl again
1109 iErr = wait_event_interruptible(WaitQueueCbEvent_g,
1110 (atomic_read(&AtomicEventState_g) ==
1112 || (atomic_read(&AtomicEventState_g) ==
1114 if ((iErr != 0) || (atomic_read(&AtomicEventState_g) == EVENT_STATE_TERM)) { // waiting was interrupted by signal
1115 EplRet = kEplShutdown;
1116 goto LeaveCriticalSection;
1118 // read return code from application's event callback function
1119 EplRet = RetCbEvent_g;
1121 LeaveCriticalSection:
1122 up(&SemaphoreCbEvent_g);
1125 // check if NMT_GS_OFF is reached
1126 if (EventType_p == kEplApiEventNmtStateChange) {
1127 if (pEventArg_p->m_NmtStateChange.m_NewNmtState == kEplNmtGsOff) { // NMT state machine was shut down
1128 TRACE0("EPL: EplLinCbEvent(NMT_GS_OFF)\n");
1129 uiEplState_g = EPL_STATE_SHUTDOWN;
1130 atomic_set(&AtomicEventState_g, EVENT_STATE_TERM);
1131 wake_up(&WaitQueueRelease_g);
1132 } else { // NMT state machine is running
1133 uiEplState_g = EPL_STATE_RUNNING;
1140 tEplKernel EplLinCbSync(void)
1142 tEplKernel EplRet = kEplSuccessful;
1145 // check if user process waits for sync
1146 if (atomic_read(&AtomicSyncState_g) == EVENT_STATE_IOCTL) {
1147 // pass control to application, i.e. EplApiProcessImageExchangeIn()
1148 atomic_set(&AtomicSyncState_g, EVENT_STATE_READY);
1149 wake_up_interruptible(&WaitQueuePI_In_g);
1151 // now, the application processes the sync event
1153 // wait for call of EplApiProcessImageExchangeOut()
1154 iErr = wait_event_interruptible(WaitQueueCbSync_g,
1155 (atomic_read(&AtomicSyncState_g)
1156 == EVENT_STATE_IOCTL)
1158 (atomic_read(&AtomicSyncState_g)
1159 == EVENT_STATE_TERM));
1160 if ((iErr != 0) || (atomic_read(&AtomicEventState_g) == EVENT_STATE_IOCTL)) { // waiting was interrupted by signal or application called wrong function
1161 EplRet = kEplShutdown;
1163 } else { // application is currently not waiting for sync
1164 // continue without interruption
1165 // TPDO are set valid by caller (i.e. EplEventkProcess())
1168 TGT_DBG_SIGNAL_TRACE_POINT(1);