Merge branch 'core-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6/x86.git] / drivers / staging / epl / EplApiLinuxKernel.c
blobcb3e275e3aadc4ed5adf1bcf23be4167c5885a0a
1 /****************************************************************************
3 (c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29
4 www.systec-electronic.com
6 Project: openPOWERLINK
8 Description: Linux kernel module as wrapper of EPL API layer,
9 i.e. counterpart to a Linux application
11 License:
13 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions
15 are met:
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.
42 Severability Clause:
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 $
55 $Author: D.Krueger $
57 $Revision: 1.9 $ $Date: 2008/11/21 09:00:38 $
59 $State: Exp $
61 Build Environment:
62 GNU-Compiler for m68k
64 -------------------------------------------------------------------------
66 Revision History:
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>
76 #include <linux/fs.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>
85 // scheduling
86 #include <linux/sched.h>
88 // memory access
89 #include <asm/uaccess.h>
90 #include <linux/vmalloc.h>
92 #include "Epl.h"
93 #include "EplApiLinux.h"
94 //#include "kernel/EplPdokCal.h"
95 #include "proc_fs.h"
98 /***************************************************************************/
99 /* */
100 /* */
101 /* G L O B A L D E F I N I T I O N S */
102 /* */
103 /* */
104 /***************************************************************************/
106 // Metainformation
107 MODULE_LICENSE("Dual BSD/GPL");
108 #ifdef MODULE_AUTHOR
109 MODULE_AUTHOR("Daniel.Krueger@SYSTEC-electronic.com");
110 MODULE_DESCRIPTION("EPL API driver");
111 #endif
113 //---------------------------------------------------------------------------
114 // Configuration
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)
127 #else
128 #define TGT_DBG_SIGNAL_TRACE_POINT(p)
129 #endif
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 //---------------------------------------------------------------------------
142 // Global variables
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 //---------------------------------------------------------------------------
164 // Local types
165 //---------------------------------------------------------------------------
167 typedef struct {
168 void *m_pUserArg;
169 void *m_pData;
171 } tEplLinSdoBufHeader;
173 //---------------------------------------------------------------------------
174 // Local variables
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)
183 void *pUserArg_p);
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,
208 .open = EplLinOpen,
209 .release = EplLinRelease,
210 .read = EplLinRead,
211 .write = EplLinWrite,
212 .ioctl = EplLinIoctl,
216 //=========================================================================//
217 // //
218 // P U B L I C F U N C T I O N S //
219 // //
220 //=========================================================================//
222 //---------------------------------------------------------------------------
223 // Initailize Driver
224 //---------------------------------------------------------------------------
225 // -> insmod driver
226 //---------------------------------------------------------------------------
228 static int __init EplLinInit(void)
231 tEplKernel EplRet;
232 int iErr;
233 int iRet;
235 TRACE0("EPL: + EplLinInit...\n");
236 TRACE2("EPL: Driver build: %s / %s\n", __DATE__, __TIME__);
238 iRet = 0;
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);
252 if (iRet == 0) {
253 TRACE2
254 ("EPL: Driver '%s' installed successful, assigned MajorNumber=%d\n",
255 EPLLIN_DRV_NAME, MAJOR(nDevNum_g));
256 } else {
257 TRACE1
258 ("EPL: ERROR: Driver '%s' is unable to get a free MajorNumber!\n",
259 EPLLIN_DRV_NAME);
260 iRet = -EIO;
261 goto Exit;
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);
269 if (iErr) {
270 TRACE2("EPL: ERROR %d: Driver '%s' could not be added!\n",
271 iErr, EPLLIN_DRV_NAME);
272 iRet = -EIO;
273 goto Exit;
276 // create device node in PROCFS
277 EplRet = EplLinProcInit();
278 if (EplRet != kEplSuccessful) {
279 goto Exit;
282 Exit:
284 TRACE1("EPL: - EplLinInit (iRet=%d)\n", iRet);
285 return (iRet);
289 //---------------------------------------------------------------------------
290 // Remove Driver
291 //---------------------------------------------------------------------------
292 // -> rmmod driver
293 //---------------------------------------------------------------------------
295 static void __exit EplLinExit(void)
298 tEplKernel EplRet;
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 //---------------------------------------------------------------------------
323 // Open Driver
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
332 int iRet;
334 TRACE0("EPL: + EplLinOpen...\n");
336 if (uiEplState_g != EPL_STATE_NOTOPEN) { // stack already initialized
337 iRet = -EALREADY;
338 } else {
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;
349 iRet = 0;
352 TRACE1("EPL: - EplLinOpen (iRet=%d)\n", iRet);
353 return (iRet);
357 //---------------------------------------------------------------------------
358 // Close Driver
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;
368 int iRet;
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,
390 (uiEplState_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;
406 iRet = 0;
408 TRACE1("EPL: - EplLinRelease (iRet=%d)\n", iRet);
409 return (iRet);
413 //---------------------------------------------------------------------------
414 // Read Data from Driver
415 //---------------------------------------------------------------------------
416 // -> read(...)
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
425 int iRet;
427 TRACE0("EPL: + EplLinRead...\n");
429 TRACE0("EPL: Sorry, this operation isn't supported.\n");
430 iRet = -EINVAL;
432 TRACE1("EPL: - EplLinRead (iRet=%d)\n", iRet);
433 return (iRet);
437 //---------------------------------------------------------------------------
438 // Write Data to Driver
439 //---------------------------------------------------------------------------
440 // -> write(...)
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
449 int iRet;
451 TRACE0("EPL: + EplLinWrite...\n");
453 TRACE0("EPL: Sorry, this operation isn't supported.\n");
454 iRet = -EINVAL;
456 TRACE1("EPL: - EplLinWrite (iRet=%d)\n", iRet);
457 return (iRet);
461 //---------------------------------------------------------------------------
462 // Generic Access to Driver
463 //---------------------------------------------------------------------------
464 // -> ioctl(...)
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
473 tEplKernel EplRet;
474 int iErr;
475 int iRet;
477 // TRACE1("EPL: + EplLinIoctl (uiIoctlCmd_p=%d)...\n", uiIoctlCmd_p);
479 iRet = -EINVAL;
481 switch (uiIoctlCmd_p) {
482 // ----------------------------------------------------------
483 case EPLLIN_CMD_INITIALIZE:
485 tEplApiInitParam EplApiInitParam;
487 iErr =
488 copy_from_user(&EplApiInitParam,
489 (const void *)ulArg_p,
490 sizeof(EplApiInitParam));
491 if (iErr != 0) {
492 iRet = -EIO;
493 goto Exit;
496 EplApiInitParam.m_pfnCbEvent = EplLinCbEvent;
497 EplApiInitParam.m_pfnCbSync = EplLinCbSync;
499 EplRet = EplApiInitialize(&EplApiInitParam);
501 uiEplState_g = EPL_STATE_RUNNING;
503 iRet = (int)EplRet;
504 break;
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
521 EplRet =
522 EplApiExecNmtCommand(kEplNmtEventSwitchOff);
526 iRet = 0;
527 break;
530 // ----------------------------------------------------------
531 case EPLLIN_CMD_READ_LOCAL_OBJECT:
533 tEplLinLocalObject LocalObject;
534 void *pData;
536 iErr =
537 copy_from_user(&LocalObject, (const void *)ulArg_p,
538 sizeof(LocalObject));
539 if (iErr != 0) {
540 iRet = -EIO;
541 goto Exit;
544 if ((LocalObject.m_pData == NULL)
545 || (LocalObject.m_uiSize == 0)) {
546 iRet = (int)kEplApiInvalidParam;
547 goto Exit;
550 pData = vmalloc(LocalObject.m_uiSize);
551 if (pData == NULL) { // no memory available
552 iRet = -ENOMEM;
553 goto Exit;
556 EplRet =
557 EplApiReadLocalObject(LocalObject.m_uiIndex,
558 LocalObject.m_uiSubindex,
559 pData, &LocalObject.m_uiSize);
561 if (EplRet == kEplSuccessful) {
562 iErr =
563 copy_to_user(LocalObject.m_pData, pData,
564 LocalObject.m_uiSize);
566 vfree(pData);
568 if (iErr != 0) {
569 iRet = -EIO;
570 goto Exit;
572 // return actual size (LocalObject.m_uiSize)
573 iErr = put_user(LocalObject.m_uiSize,
574 (unsigned int *)(ulArg_p +
575 (unsigned long)
576 &LocalObject.
577 m_uiSize -
578 (unsigned long)
579 &LocalObject));
580 if (iErr != 0) {
581 iRet = -EIO;
582 goto Exit;
585 } else {
586 vfree(pData);
589 iRet = (int)EplRet;
590 break;
593 // ----------------------------------------------------------
594 case EPLLIN_CMD_WRITE_LOCAL_OBJECT:
596 tEplLinLocalObject LocalObject;
597 void *pData;
599 iErr =
600 copy_from_user(&LocalObject, (const void *)ulArg_p,
601 sizeof(LocalObject));
602 if (iErr != 0) {
603 iRet = -EIO;
604 goto Exit;
607 if ((LocalObject.m_pData == NULL)
608 || (LocalObject.m_uiSize == 0)) {
609 iRet = (int)kEplApiInvalidParam;
610 goto Exit;
613 pData = vmalloc(LocalObject.m_uiSize);
614 if (pData == NULL) { // no memory available
615 iRet = -ENOMEM;
616 goto Exit;
618 iErr =
619 copy_from_user(pData, LocalObject.m_pData,
620 LocalObject.m_uiSize);
621 if (iErr != 0) {
622 iRet = -EIO;
623 goto Exit;
626 EplRet =
627 EplApiWriteLocalObject(LocalObject.m_uiIndex,
628 LocalObject.m_uiSubindex,
629 pData, LocalObject.m_uiSize);
631 vfree(pData);
633 iRet = (int)EplRet;
634 break;
637 case EPLLIN_CMD_READ_OBJECT:
639 tEplLinSdoObject SdoObject;
640 void *pData;
641 tEplLinSdoBufHeader *pBufHeader;
642 tEplSdoComConHdl *pSdoComConHdl;
644 iErr =
645 copy_from_user(&SdoObject, (const void *)ulArg_p,
646 sizeof(SdoObject));
647 if (iErr != 0) {
648 iRet = -EIO;
649 goto Exit;
652 if ((SdoObject.m_le_pData == NULL)
653 || (SdoObject.m_uiSize == 0)) {
654 iRet = (int)kEplApiInvalidParam;
655 goto Exit;
658 pBufHeader =
659 (tEplLinSdoBufHeader *)
660 vmalloc(sizeof(tEplLinSdoBufHeader) +
661 SdoObject.m_uiSize);
662 if (pBufHeader == NULL) { // no memory available
663 iRet = -ENOMEM;
664 goto Exit;
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;
673 } else {
674 pSdoComConHdl = NULL;
677 EplRet =
678 EplApiReadObject(pSdoComConHdl,
679 SdoObject.m_uiNodeId,
680 SdoObject.m_uiIndex,
681 SdoObject.m_uiSubindex, pData,
682 &SdoObject.m_uiSize,
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 +
688 (unsigned long)
689 &SdoObject.
690 m_SdoComConHdl -
691 (unsigned long)
692 &SdoObject));
693 if (iErr != 0) {
694 iRet = -EIO;
695 goto Exit;
698 if (EplRet == kEplSuccessful) {
699 iErr =
700 copy_to_user(SdoObject.m_le_pData, pData,
701 SdoObject.m_uiSize);
703 vfree(pBufHeader);
705 if (iErr != 0) {
706 iRet = -EIO;
707 goto Exit;
709 // return actual size (SdoObject.m_uiSize)
710 iErr = put_user(SdoObject.m_uiSize,
711 (unsigned int *)(ulArg_p +
712 (unsigned long)
713 &SdoObject.
714 m_uiSize -
715 (unsigned long)
716 &SdoObject));
717 if (iErr != 0) {
718 iRet = -EIO;
719 goto Exit;
721 } else if (EplRet != kEplApiTaskDeferred) { // error ocurred
722 vfree(pBufHeader);
723 if (iErr != 0) {
724 iRet = -EIO;
725 goto Exit;
729 iRet = (int)EplRet;
730 break;
733 case EPLLIN_CMD_WRITE_OBJECT:
735 tEplLinSdoObject SdoObject;
736 void *pData;
737 tEplLinSdoBufHeader *pBufHeader;
738 tEplSdoComConHdl *pSdoComConHdl;
740 iErr =
741 copy_from_user(&SdoObject, (const void *)ulArg_p,
742 sizeof(SdoObject));
743 if (iErr != 0) {
744 iRet = -EIO;
745 goto Exit;
748 if ((SdoObject.m_le_pData == NULL)
749 || (SdoObject.m_uiSize == 0)) {
750 iRet = (int)kEplApiInvalidParam;
751 goto Exit;
754 pBufHeader =
755 (tEplLinSdoBufHeader *)
756 vmalloc(sizeof(tEplLinSdoBufHeader) +
757 SdoObject.m_uiSize);
758 if (pBufHeader == NULL) { // no memory available
759 iRet = -ENOMEM;
760 goto Exit;
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);
767 iErr =
768 copy_from_user(pData, SdoObject.m_le_pData,
769 SdoObject.m_uiSize);
771 if (iErr != 0) {
772 iRet = -EIO;
773 goto Exit;
776 if (SdoObject.m_fValidSdoComConHdl != FALSE) {
777 pSdoComConHdl = &SdoObject.m_SdoComConHdl;
778 } else {
779 pSdoComConHdl = NULL;
782 EplRet =
783 EplApiWriteObject(pSdoComConHdl,
784 SdoObject.m_uiNodeId,
785 SdoObject.m_uiIndex,
786 SdoObject.m_uiSubindex, pData,
787 SdoObject.m_uiSize,
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 +
793 (unsigned long)
794 &SdoObject.
795 m_SdoComConHdl -
796 (unsigned long)
797 &SdoObject));
798 if (iErr != 0) {
799 iRet = -EIO;
800 goto Exit;
803 if (EplRet != kEplApiTaskDeferred) { // succeeded or error ocurred, but task not deferred
804 vfree(pBufHeader);
807 iRet = (int)EplRet;
808 break;
811 // ----------------------------------------------------------
812 case EPLLIN_CMD_FREE_SDO_CHANNEL:
814 // forward SDO handle to EPL stack
815 EplRet =
816 EplApiFreeSdoChannel((tEplSdoComConHdl) ulArg_p);
818 iRet = (int)EplRet;
819 break;
822 #if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
823 // ----------------------------------------------------------
824 case EPLLIN_CMD_MN_TRIGGER_STATE_CHANGE:
826 tEplLinNodeCmdObject NodeCmdObject;
828 iErr =
829 copy_from_user(&NodeCmdObject,
830 (const void *)ulArg_p,
831 sizeof(NodeCmdObject));
832 if (iErr != 0) {
833 iRet = -EIO;
834 goto Exit;
837 EplRet =
838 EplApiMnTriggerStateChange(NodeCmdObject.m_uiNodeId,
839 NodeCmdObject.
840 m_NodeCommand);
841 iRet = (int)EplRet;
842 break;
844 #endif
846 // ----------------------------------------------------------
847 case EPLLIN_CMD_GET_EVENT:
849 tEplLinEvent Event;
851 // save event structure
852 iErr =
853 copy_from_user(&Event, (const void *)ulArg_p,
854 sizeof(Event));
855 if (iErr != 0) {
856 iRet = -EIO;
857 goto Exit;
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,
865 EVENT_STATE_TERM);
866 wake_up_interruptible(&WaitQueueCbEvent_g);
867 // exit with error -> EplApiProcess() will leave the infinite loop
868 iRet = 1;
869 goto Exit;
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,
877 (atomic_read
878 (&AtomicEventState_g)
879 == EVENT_STATE_READY)
881 (atomic_read
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,
887 EVENT_STATE_TERM);
888 wake_up_interruptible(&WaitQueueCbEvent_g);
889 // exit with this error -> EplApiProcess() will leave the infinite loop
890 iRet = iErr;
891 goto Exit;
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
896 iRet = 1;
897 goto Exit;
899 // copy event to user space
900 iErr =
901 copy_to_user(Event.m_pEventType, &EventType_g,
902 sizeof(EventType_g));
903 if (iErr != 0) { // not all data could be copied
904 iRet = -EIO;
905 goto Exit;
907 // $$$ d.k. perform SDO event processing
908 if (EventType_g == kEplApiEventSdo) {
909 void *pData;
910 tEplLinSdoBufHeader *pBufHeader;
912 pBufHeader =
913 (tEplLinSdoBufHeader *) pEventArg_g->m_Sdo.
914 m_pUserArg;
915 pData =
916 pBufHeader + sizeof(tEplLinSdoBufHeader);
918 if (pEventArg_g->m_Sdo.m_SdoAccessType ==
919 kEplSdoAccessTypeRead) {
920 // copy read data to user space
921 iErr =
922 copy_to_user(pBufHeader->m_pData,
923 pData,
924 pEventArg_g->m_Sdo.
925 m_uiTransferredByte);
926 if (iErr != 0) { // not all data could be copied
927 iRet = -EIO;
928 goto Exit;
931 pEventArg_g->m_Sdo.m_pUserArg =
932 pBufHeader->m_pUserArg;
933 vfree(pBufHeader);
936 iErr =
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
941 iRet = -EIO;
942 goto Exit;
944 // return to EplApiProcess(), which will call the application's event callback function
945 iRet = 0;
947 break;
950 // ----------------------------------------------------------
951 case EPLLIN_CMD_PI_SETUP:
953 EplRet = EplApiProcessImageSetup();
954 iRet = (int)EplRet;
956 break;
959 // ----------------------------------------------------------
960 case EPLLIN_CMD_PI_IN:
962 tEplApiProcessImage ProcessImageIn;
964 // save process image structure
965 iErr =
966 copy_from_user(&ProcessImageIn,
967 (const void *)ulArg_p,
968 sizeof(ProcessImageIn));
969 if (iErr != 0) {
970 iRet = -EIO;
971 goto Exit;
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,
978 (atomic_read
979 (&AtomicSyncState_g) ==
980 EVENT_STATE_READY)
982 (atomic_read
983 (&AtomicSyncState_g) ==
984 EVENT_STATE_TERM));
985 if (iErr != 0) { // waiting was interrupted by signal
986 // pass control to sync kernel thread, but signal termination
987 atomic_set(&AtomicSyncState_g,
988 EVENT_STATE_TERM);
989 wake_up_interruptible(&WaitQueueCbSync_g);
990 // exit with this error -> application will leave the infinite loop
991 iRet = iErr;
992 goto Exit;
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
997 iRet = 1;
998 goto Exit;
1000 // exchange process image
1001 EplRet = EplApiProcessImageExchangeIn(&ProcessImageIn);
1003 // return to EplApiProcessImageExchangeIn()
1004 iRet = (int)EplRet;
1006 break;
1009 // ----------------------------------------------------------
1010 case EPLLIN_CMD_PI_OUT:
1012 tEplApiProcessImage ProcessImageOut;
1014 // save process image structure
1015 iErr =
1016 copy_from_user(&ProcessImageOut,
1017 (const void *)ulArg_p,
1018 sizeof(ProcessImageOut));
1019 if (iErr != 0) {
1020 iRet = -EIO;
1021 goto Exit;
1024 if (atomic_read(&AtomicSyncState_g) !=
1025 EVENT_STATE_READY) {
1026 iRet = (int)kEplInvalidOperation;
1027 goto Exit;
1029 // exchange process image
1030 EplRet =
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()
1038 iRet = (int)EplRet;
1040 break;
1043 // ----------------------------------------------------------
1044 case EPLLIN_CMD_NMT_COMMAND:
1046 // forward NMT command to EPL stack
1047 EplRet = EplApiExecNmtCommand((tEplNmtEvent) ulArg_p);
1049 iRet = (int)EplRet;
1051 break;
1054 // ----------------------------------------------------------
1055 default:
1057 break;
1061 Exit:
1063 // TRACE1("EPL: - EplLinIoctl (iRet=%d)\n", iRet);
1064 return (iRet);
1068 //=========================================================================//
1069 // //
1070 // P R I V A T E F U N C T I O N S //
1071 // //
1072 //=========================================================================//
1074 tEplKernel EplLinCbEvent(tEplApiEventType EventType_p, // IN: event type (enum)
1075 tEplApiEventArg *pEventArg_p, // IN: event argument (union)
1076 void *pUserArg_p)
1078 tEplKernel EplRet = kEplSuccessful;
1079 int iErr;
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;
1085 goto Exit;
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) ==
1091 EVENT_STATE_IOCTL)
1092 || (atomic_read(&AtomicEventState_g) ==
1093 EVENT_STATE_TERM));
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) ==
1111 EVENT_STATE_IOCTL)
1112 || (atomic_read(&AtomicEventState_g) ==
1113 EVENT_STATE_TERM));
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);
1124 Exit:
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;
1137 return EplRet;
1140 tEplKernel EplLinCbSync(void)
1142 tEplKernel EplRet = kEplSuccessful;
1143 int iErr;
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);
1170 return EplRet;
1173 // EOF