md: tidy up status_resync to handle large arrays.
[linux-2.6] / drivers / staging / epl / EplApiLinuxKernel.c
1 /****************************************************************************
2
3   (c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29
4       www.systec-electronic.com
5
6   Project:      openPOWERLINK
7
8   Description:  Linux kernel module as wrapper of EPL API layer,
9                 i.e. counterpart to a Linux application
10
11   License:
12
13     Redistribution and use in source and binary forms, with or without
14     modification, are permitted provided that the following conditions
15     are met:
16
17     1. Redistributions of source code must retain the above copyright
18        notice, this list of conditions and the following disclaimer.
19
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.
23
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.
28
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.
41
42     Severability Clause:
43
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.
50
51   -------------------------------------------------------------------------
52
53                 $RCSfile: EplApiLinuxKernel.c,v $
54
55                 $Author: D.Krueger $
56
57                 $Revision: 1.9 $  $Date: 2008/11/21 09:00:38 $
58
59                 $State: Exp $
60
61                 Build Environment:
62                 GNU-Compiler for m68k
63
64   -------------------------------------------------------------------------
65
66   Revision History:
67
68   2006/10/11 d.k.:  Initial Version
69   2008/04/10 m.u.:  Changed to new char driver init
70
71 ****************************************************************************/
72
73 // kernel modul and driver
74
75 #include <linux/module.h>
76 #include <linux/fs.h>
77 #include <linux/cdev.h>
78 #include <linux/types.h>
79
80 //#include <linux/module.h>
81 //#include <linux/kernel.h>
82 //#include <linux/init.h>
83 //#include <linux/errno.h>
84
85 // scheduling
86 #include <linux/sched.h>
87
88 // memory access
89 #include <asm/uaccess.h>
90 #include <linux/vmalloc.h>
91
92 #include "Epl.h"
93 #include "EplApiLinux.h"
94 //#include "kernel/EplPdokCal.h"
95 #include "proc_fs.h"
96
97
98 /***************************************************************************/
99 /*                                                                         */
100 /*                                                                         */
101 /*          G L O B A L   D E F I N I T I O N S                            */
102 /*                                                                         */
103 /*                                                                         */
104 /***************************************************************************/
105
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
112
113 //---------------------------------------------------------------------------
114 //  Configuration
115 //---------------------------------------------------------------------------
116
117 #define EPLLIN_DRV_NAME     "systec_epl"        // used for <register_chrdev>
118
119 //---------------------------------------------------------------------------
120 //  Constant definitions
121 //---------------------------------------------------------------------------
122
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
130
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
135
136 #define EPL_STATE_NOTOPEN       0
137 #define EPL_STATE_NOTINIT       1
138 #define EPL_STATE_RUNNING       2
139 #define EPL_STATE_SHUTDOWN      3
140
141 //---------------------------------------------------------------------------
142 //  Global variables
143 //---------------------------------------------------------------------------
144
145     // device number (major and minor)
146 static dev_t nDevNum_g;
147 static struct cdev *pEpl_cdev_g;
148
149 static volatile unsigned int uiEplState_g = EPL_STATE_NOTOPEN;
150
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);
162
163 //---------------------------------------------------------------------------
164 //  Local types
165 //---------------------------------------------------------------------------
166
167 typedef struct {
168         void *m_pUserArg;
169         void *m_pData;
170
171 } tEplLinSdoBufHeader;
172
173 //---------------------------------------------------------------------------
174 //  Local variables
175 //---------------------------------------------------------------------------
176
177 //---------------------------------------------------------------------------
178 //  Prototypes of internal functions
179 //---------------------------------------------------------------------------
180
181 tEplKernel EplLinCbEvent(tEplApiEventType EventType_p,  // IN: event type (enum)
182                          tEplApiEventArg *pEventArg_p,  // IN: event argument (union)
183                          void *pUserArg_p);
184
185 tEplKernel EplLinCbSync(void);
186
187 static int __init EplLinInit(void);
188 static void __exit EplLinExit(void);
189
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);
198
199 //---------------------------------------------------------------------------
200 //  Kernel Module specific Data Structures
201 //---------------------------------------------------------------------------
202
203 module_init(EplLinInit);
204 module_exit(EplLinExit);
205
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,
213
214 };
215
216 //=========================================================================//
217 //                                                                         //
218 //          P U B L I C   F U N C T I O N S                                //
219 //                                                                         //
220 //=========================================================================//
221
222 //---------------------------------------------------------------------------
223 //  Initailize Driver
224 //---------------------------------------------------------------------------
225 //  -> insmod driver
226 //---------------------------------------------------------------------------
227
228 static int __init EplLinInit(void)
229 {
230
231         tEplKernel EplRet;
232         int iErr;
233         int iRet;
234
235         TRACE0("EPL: + EplLinInit...\n");
236         TRACE2("EPL:   Driver build: %s / %s\n", __DATE__, __TIME__);
237
238         iRet = 0;
239
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);
246
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;
262         }
263
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;
274         }
275
276         // create device node in PROCFS
277         EplRet = EplLinProcInit();
278         if (EplRet != kEplSuccessful) {
279                 goto Exit;
280         }
281
282       Exit:
283
284         TRACE1("EPL: - EplLinInit (iRet=%d)\n", iRet);
285         return (iRet);
286
287 }
288
289 //---------------------------------------------------------------------------
290 //  Remove Driver
291 //---------------------------------------------------------------------------
292 //  -> rmmod driver
293 //---------------------------------------------------------------------------
294
295 static void __exit EplLinExit(void)
296 {
297
298         tEplKernel EplRet;
299
300         // delete instance for all modules
301 //    EplRet = EplApiShutdown();
302 //    printk("EplApiShutdown():  0x%X\n", EplRet);
303
304         // deinitialize proc fs
305         EplRet = EplLinProcFree();
306         printk("EplLinProcFree():        0x%X\n", EplRet);
307
308         TRACE0("EPL: + EplLinExit...\n");
309
310         // remove cdev structure
311         cdev_del(pEpl_cdev_g);
312
313         // unregister character device handler
314         unregister_chrdev_region(nDevNum_g, 1);
315
316         TRACE1("EPL:   Driver '%s' removed.\n", EPLLIN_DRV_NAME);
317
318         TRACE0("EPL: - EplLinExit\n");
319
320 }
321
322 //---------------------------------------------------------------------------
323 //  Open Driver
324 //---------------------------------------------------------------------------
325 //  -> open("/dev/driver", O_RDWR)...
326 //---------------------------------------------------------------------------
327
328 static int EplLinOpen(struct inode *pDeviceFile_p,      // information about the device to open
329                       struct file *pInstance_p) // information about driver instance
330 {
331
332         int iRet;
333
334         TRACE0("EPL: + EplLinOpen...\n");
335
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);
347
348                 uiEplState_g = EPL_STATE_NOTINIT;
349                 iRet = 0;
350         }
351
352         TRACE1("EPL: - EplLinOpen (iRet=%d)\n", iRet);
353         return (iRet);
354
355 }
356
357 //---------------------------------------------------------------------------
358 //  Close Driver
359 //---------------------------------------------------------------------------
360 //  -> close(device)...
361 //---------------------------------------------------------------------------
362
363 static int EplLinRelease(struct inode *pDeviceFile_p,   // information about the device to open
364                          struct file *pInstance_p)      // information about driver instance
365 {
366
367         tEplKernel EplRet = kEplSuccessful;
368         int iRet;
369
370         TRACE0("EPL: + EplLinRelease...\n");
371
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);
377
378                 // pass control to event queue kernel thread
379                 atomic_set(&AtomicEventState_g, EVENT_STATE_TERM);
380                 wake_up_interruptible(&WaitQueueCbEvent_g);
381
382                 if (uiEplState_g == EPL_STATE_RUNNING) {        // post NmtEventSwitchOff
383                         EplRet = EplApiExecNmtCommand(kEplNmtEventSwitchOff);
384
385                 }
386
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");
394                 }
395
396                 // $$$ d.k.: What if waiting was interrupted by signal?
397
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);
403         }
404
405         uiEplState_g = EPL_STATE_NOTOPEN;
406         iRet = 0;
407
408         TRACE1("EPL: - EplLinRelease (iRet=%d)\n", iRet);
409         return (iRet);
410
411 }
412
413 //---------------------------------------------------------------------------
414 //  Read Data from Driver
415 //---------------------------------------------------------------------------
416 //  -> read(...)
417 //---------------------------------------------------------------------------
418
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
423 {
424
425         int iRet;
426
427         TRACE0("EPL: + EplLinRead...\n");
428
429         TRACE0("EPL:   Sorry, this operation isn't supported.\n");
430         iRet = -EINVAL;
431
432         TRACE1("EPL: - EplLinRead (iRet=%d)\n", iRet);
433         return (iRet);
434
435 }
436
437 //---------------------------------------------------------------------------
438 //  Write Data to Driver
439 //---------------------------------------------------------------------------
440 //  -> write(...)
441 //---------------------------------------------------------------------------
442
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
447 {
448
449         int iRet;
450
451         TRACE0("EPL: + EplLinWrite...\n");
452
453         TRACE0("EPL:   Sorry, this operation isn't supported.\n");
454         iRet = -EINVAL;
455
456         TRACE1("EPL: - EplLinWrite (iRet=%d)\n", iRet);
457         return (iRet);
458
459 }
460
461 //---------------------------------------------------------------------------
462 //  Generic Access to Driver
463 //---------------------------------------------------------------------------
464 //  -> ioctl(...)
465 //---------------------------------------------------------------------------
466
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
471 {
472
473         tEplKernel EplRet;
474         int iErr;
475         int iRet;
476
477 //    TRACE1("EPL: + EplLinIoctl (uiIoctlCmd_p=%d)...\n", uiIoctlCmd_p);
478
479         iRet = -EINVAL;
480
481         switch (uiIoctlCmd_p) {
482                 // ----------------------------------------------------------
483         case EPLLIN_CMD_INITIALIZE:
484                 {
485                         tEplApiInitParam EplApiInitParam;
486
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;
494                         }
495
496                         EplApiInitParam.m_pfnCbEvent = EplLinCbEvent;
497                         EplApiInitParam.m_pfnCbSync = EplLinCbSync;
498
499                         EplRet = EplApiInitialize(&EplApiInitParam);
500
501                         uiEplState_g = EPL_STATE_RUNNING;
502
503                         iRet = (int)EplRet;
504                         break;
505                 }
506
507                 // ----------------------------------------------------------
508         case EPLLIN_CMD_SHUTDOWN:
509                 {               // shutdown the threads
510
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);
515
516                         // pass control to event queue kernel thread
517                         atomic_set(&AtomicEventState_g, EVENT_STATE_TERM);
518                         wake_up_interruptible(&WaitQueueCbEvent_g);
519
520                         if (uiEplState_g == EPL_STATE_RUNNING) {        // post NmtEventSwitchOff
521                                 EplRet =
522                                     EplApiExecNmtCommand(kEplNmtEventSwitchOff);
523
524                         }
525
526                         iRet = 0;
527                         break;
528                 }
529
530                 // ----------------------------------------------------------
531         case EPLLIN_CMD_READ_LOCAL_OBJECT:
532                 {
533                         tEplLinLocalObject LocalObject;
534                         void *pData;
535
536                         iErr =
537                             copy_from_user(&LocalObject, (const void *)ulArg_p,
538                                            sizeof(LocalObject));
539                         if (iErr != 0) {
540                                 iRet = -EIO;
541                                 goto Exit;
542                         }
543
544                         if ((LocalObject.m_pData == NULL)
545                             || (LocalObject.m_uiSize == 0)) {
546                                 iRet = (int)kEplApiInvalidParam;
547                                 goto Exit;
548                         }
549
550                         pData = vmalloc(LocalObject.m_uiSize);
551                         if (pData == NULL) {    // no memory available
552                                 iRet = -ENOMEM;
553                                 goto Exit;
554                         }
555
556                         EplRet =
557                             EplApiReadLocalObject(LocalObject.m_uiIndex,
558                                                   LocalObject.m_uiSubindex,
559                                                   pData, &LocalObject.m_uiSize);
560
561                         if (EplRet == kEplSuccessful) {
562                                 iErr =
563                                     copy_to_user(LocalObject.m_pData, pData,
564                                                  LocalObject.m_uiSize);
565
566                                 vfree(pData);
567
568                                 if (iErr != 0) {
569                                         iRet = -EIO;
570                                         goto Exit;
571                                 }
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;
583                                 }
584
585                         } else {
586                                 vfree(pData);
587                         }
588
589                         iRet = (int)EplRet;
590                         break;
591                 }
592
593                 // ----------------------------------------------------------
594         case EPLLIN_CMD_WRITE_LOCAL_OBJECT:
595                 {
596                         tEplLinLocalObject LocalObject;
597                         void *pData;
598
599                         iErr =
600                             copy_from_user(&LocalObject, (const void *)ulArg_p,
601                                            sizeof(LocalObject));
602                         if (iErr != 0) {
603                                 iRet = -EIO;
604                                 goto Exit;
605                         }
606
607                         if ((LocalObject.m_pData == NULL)
608                             || (LocalObject.m_uiSize == 0)) {
609                                 iRet = (int)kEplApiInvalidParam;
610                                 goto Exit;
611                         }
612
613                         pData = vmalloc(LocalObject.m_uiSize);
614                         if (pData == NULL) {    // no memory available
615                                 iRet = -ENOMEM;
616                                 goto Exit;
617                         }
618                         iErr =
619                             copy_from_user(pData, LocalObject.m_pData,
620                                            LocalObject.m_uiSize);
621                         if (iErr != 0) {
622                                 iRet = -EIO;
623                                 goto Exit;
624                         }
625
626                         EplRet =
627                             EplApiWriteLocalObject(LocalObject.m_uiIndex,
628                                                    LocalObject.m_uiSubindex,
629                                                    pData, LocalObject.m_uiSize);
630
631                         vfree(pData);
632
633                         iRet = (int)EplRet;
634                         break;
635                 }
636
637         case EPLLIN_CMD_READ_OBJECT:
638                 {
639                         tEplLinSdoObject SdoObject;
640                         void *pData;
641                         tEplLinSdoBufHeader *pBufHeader;
642                         tEplSdoComConHdl *pSdoComConHdl;
643
644                         iErr =
645                             copy_from_user(&SdoObject, (const void *)ulArg_p,
646                                            sizeof(SdoObject));
647                         if (iErr != 0) {
648                                 iRet = -EIO;
649                                 goto Exit;
650                         }
651
652                         if ((SdoObject.m_le_pData == NULL)
653                             || (SdoObject.m_uiSize == 0)) {
654                                 iRet = (int)kEplApiInvalidParam;
655                                 goto Exit;
656                         }
657
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;
665                         }
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);
670
671                         if (SdoObject.m_fValidSdoComConHdl != FALSE) {
672                                 pSdoComConHdl = &SdoObject.m_SdoComConHdl;
673                         } else {
674                                 pSdoComConHdl = NULL;
675                         }
676
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);
684
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;
696                         }
697
698                         if (EplRet == kEplSuccessful) {
699                                 iErr =
700                                     copy_to_user(SdoObject.m_le_pData, pData,
701                                                  SdoObject.m_uiSize);
702
703                                 vfree(pBufHeader);
704
705                                 if (iErr != 0) {
706                                         iRet = -EIO;
707                                         goto Exit;
708                                 }
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;
720                                 }
721                         } else if (EplRet != kEplApiTaskDeferred) {     // error ocurred
722                                 vfree(pBufHeader);
723                                 if (iErr != 0) {
724                                         iRet = -EIO;
725                                         goto Exit;
726                                 }
727                         }
728
729                         iRet = (int)EplRet;
730                         break;
731                 }
732
733         case EPLLIN_CMD_WRITE_OBJECT:
734                 {
735                         tEplLinSdoObject SdoObject;
736                         void *pData;
737                         tEplLinSdoBufHeader *pBufHeader;
738                         tEplSdoComConHdl *pSdoComConHdl;
739
740                         iErr =
741                             copy_from_user(&SdoObject, (const void *)ulArg_p,
742                                            sizeof(SdoObject));
743                         if (iErr != 0) {
744                                 iRet = -EIO;
745                                 goto Exit;
746                         }
747
748                         if ((SdoObject.m_le_pData == NULL)
749                             || (SdoObject.m_uiSize == 0)) {
750                                 iRet = (int)kEplApiInvalidParam;
751                                 goto Exit;
752                         }
753
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;
761                         }
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);
766
767                         iErr =
768                             copy_from_user(pData, SdoObject.m_le_pData,
769                                            SdoObject.m_uiSize);
770
771                         if (iErr != 0) {
772                                 iRet = -EIO;
773                                 goto Exit;
774                         }
775
776                         if (SdoObject.m_fValidSdoComConHdl != FALSE) {
777                                 pSdoComConHdl = &SdoObject.m_SdoComConHdl;
778                         } else {
779                                 pSdoComConHdl = NULL;
780                         }
781
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);
789
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;
801                         }
802
803                         if (EplRet != kEplApiTaskDeferred) {    // succeeded or error ocurred, but task not deferred
804                                 vfree(pBufHeader);
805                         }
806
807                         iRet = (int)EplRet;
808                         break;
809                 }
810
811                 // ----------------------------------------------------------
812         case EPLLIN_CMD_FREE_SDO_CHANNEL:
813                 {
814                         // forward SDO handle to EPL stack
815                         EplRet =
816                             EplApiFreeSdoChannel((tEplSdoComConHdl) ulArg_p);
817
818                         iRet = (int)EplRet;
819                         break;
820                 }
821
822 #if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
823                 // ----------------------------------------------------------
824         case EPLLIN_CMD_MN_TRIGGER_STATE_CHANGE:
825                 {
826                         tEplLinNodeCmdObject NodeCmdObject;
827
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;
835                         }
836
837                         EplRet =
838                             EplApiMnTriggerStateChange(NodeCmdObject.m_uiNodeId,
839                                                        NodeCmdObject.
840                                                        m_NodeCommand);
841                         iRet = (int)EplRet;
842                         break;
843                 }
844 #endif
845
846                 // ----------------------------------------------------------
847         case EPLLIN_CMD_GET_EVENT:
848                 {
849                         tEplLinEvent Event;
850
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;
858                         }
859                         // save return code from application's event callback function
860                         RetCbEvent_g = Event.m_RetCbEvent;
861
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;
870                         }
871                         // pass control to event queue kernel thread
872                         atomic_set(&AtomicEventState_g, EVENT_STATE_IOCTL);
873                         wake_up_interruptible(&WaitQueueCbEvent_g);
874
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)
880                                                         ||
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;
898                         }
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;
906                         }
907                         // $$$ d.k. perform SDO event processing
908                         if (EventType_g == kEplApiEventSdo) {
909                                 void *pData;
910                                 tEplLinSdoBufHeader *pBufHeader;
911
912                                 pBufHeader =
913                                     (tEplLinSdoBufHeader *) pEventArg_g->m_Sdo.
914                                     m_pUserArg;
915                                 pData =
916                                     pBufHeader + sizeof(tEplLinSdoBufHeader);
917
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;
929                                         }
930                                 }
931                                 pEventArg_g->m_Sdo.m_pUserArg =
932                                     pBufHeader->m_pUserArg;
933                                 vfree(pBufHeader);
934                         }
935
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;
943                         }
944                         // return to EplApiProcess(), which will call the application's event callback function
945                         iRet = 0;
946
947                         break;
948                 }
949
950                 // ----------------------------------------------------------
951         case EPLLIN_CMD_PI_SETUP:
952                 {
953                         EplRet = EplApiProcessImageSetup();
954                         iRet = (int)EplRet;
955
956                         break;
957                 }
958
959                 // ----------------------------------------------------------
960         case EPLLIN_CMD_PI_IN:
961                 {
962                         tEplApiProcessImage ProcessImageIn;
963
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;
972                         }
973                         // pass control to event queue kernel thread
974                         atomic_set(&AtomicSyncState_g, EVENT_STATE_IOCTL);
975
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)
981                                                         ||
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;
999                         }
1000                         // exchange process image
1001                         EplRet = EplApiProcessImageExchangeIn(&ProcessImageIn);
1002
1003                         // return to EplApiProcessImageExchangeIn()
1004                         iRet = (int)EplRet;
1005
1006                         break;
1007                 }
1008
1009                 // ----------------------------------------------------------
1010         case EPLLIN_CMD_PI_OUT:
1011                 {
1012                         tEplApiProcessImage ProcessImageOut;
1013
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;
1022                         }
1023
1024                         if (atomic_read(&AtomicSyncState_g) !=
1025                             EVENT_STATE_READY) {
1026                                 iRet = (int)kEplInvalidOperation;
1027                                 goto Exit;
1028                         }
1029                         // exchange process image
1030                         EplRet =
1031                             EplApiProcessImageExchangeOut(&ProcessImageOut);
1032
1033                         // pass control to sync kernel thread
1034                         atomic_set(&AtomicSyncState_g, EVENT_STATE_TERM);
1035                         wake_up_interruptible(&WaitQueueCbSync_g);
1036
1037                         // return to EplApiProcessImageExchangeout()
1038                         iRet = (int)EplRet;
1039
1040                         break;
1041                 }
1042
1043                 // ----------------------------------------------------------
1044         case EPLLIN_CMD_NMT_COMMAND:
1045                 {
1046                         // forward NMT command to EPL stack
1047                         EplRet = EplApiExecNmtCommand((tEplNmtEvent) ulArg_p);
1048
1049                         iRet = (int)EplRet;
1050
1051                         break;
1052                 }
1053
1054                 // ----------------------------------------------------------
1055         default:
1056                 {
1057                         break;
1058                 }
1059         }
1060
1061       Exit:
1062
1063 //    TRACE1("EPL: - EplLinIoctl (iRet=%d)\n", iRet);
1064         return (iRet);
1065
1066 }
1067
1068 //=========================================================================//
1069 //                                                                         //
1070 //          P R I V A T E   F U N C T I O N S                              //
1071 //                                                                         //
1072 //=========================================================================//
1073
1074 tEplKernel EplLinCbEvent(tEplApiEventType EventType_p,  // IN: event type (enum)
1075                          tEplApiEventArg *pEventArg_p,  // IN: event argument (union)
1076                          void *pUserArg_p)
1077 {
1078         tEplKernel EplRet = kEplSuccessful;
1079         int iErr;
1080
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;
1086         }
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;
1097         }
1098         // save event information for ioctl
1099         EventType_g = EventType_p;
1100         pEventArg_g = pEventArg_p;
1101
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);
1105
1106         // now, the application's event callback function processes the event
1107
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;
1117         }
1118         // read return code from application's event callback function
1119         EplRet = RetCbEvent_g;
1120
1121       LeaveCriticalSection:
1122         up(&SemaphoreCbEvent_g);
1123
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;
1134                 }
1135         }
1136
1137         return EplRet;
1138 }
1139
1140 tEplKernel EplLinCbSync(void)
1141 {
1142         tEplKernel EplRet = kEplSuccessful;
1143         int iErr;
1144
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);
1150
1151                 // now, the application processes the sync event
1152
1153                 // wait for call of EplApiProcessImageExchangeOut()
1154                 iErr = wait_event_interruptible(WaitQueueCbSync_g,
1155                                                 (atomic_read(&AtomicSyncState_g)
1156                                                  == EVENT_STATE_IOCTL)
1157                                                 ||
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;
1162                 }
1163         } else {                // application is currently not waiting for sync
1164                 // continue without interruption
1165                 // TPDO are set valid by caller (i.e. EplEventkProcess())
1166         }
1167
1168         TGT_DBG_SIGNAL_TRACE_POINT(1);
1169
1170         return EplRet;
1171 }
1172
1173 // EOF