Merge branches 'fixes', 'cleanups' and 'boards'
[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/version.h>
76 //#include <linux/config.h>
77
78 #include <linux/module.h>
79 #include <linux/fs.h>
80 #include <linux/cdev.h>
81 #include <linux/types.h>
82
83 //#include <linux/module.h>
84 //#include <linux/kernel.h>
85 //#include <linux/init.h>
86 //#include <linux/errno.h>
87
88 // scheduling
89 #include <linux/sched.h>
90
91 // memory access
92 #include <asm/uaccess.h>
93 #include <linux/vmalloc.h>
94
95 #ifdef CONFIG_DEVFS_FS
96 #include <linux/major.h>
97 #include <linux/devfs_fs_kernel.h>
98 #endif
99
100 #include "Epl.h"
101 #include "EplApiLinux.h"
102 //#include "kernel/EplPdokCal.h"
103 #include "proc_fs.h"
104
105 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
106     // remove ("make invisible") obsolete symbols for kernel versions 2.6
107     // and higher
108 #define MOD_INC_USE_COUNT
109 #define MOD_DEC_USE_COUNT
110 #define EXPORT_NO_SYMBOLS
111 #else
112 #error "This driver needs a 2.6.x kernel or higher"
113 #endif
114
115 /***************************************************************************/
116 /*                                                                         */
117 /*                                                                         */
118 /*          G L O B A L   D E F I N I T I O N S                            */
119 /*                                                                         */
120 /*                                                                         */
121 /***************************************************************************/
122
123 // Metainformation
124 MODULE_LICENSE("Dual BSD/GPL");
125 #ifdef MODULE_AUTHOR
126 MODULE_AUTHOR("Daniel.Krueger@SYSTEC-electronic.com");
127 MODULE_DESCRIPTION("EPL API driver");
128 #endif
129
130 //---------------------------------------------------------------------------
131 //  Configuration
132 //---------------------------------------------------------------------------
133
134 #define EPLLIN_DRV_NAME     "systec_epl"        // used for <register_chrdev>
135
136 //---------------------------------------------------------------------------
137 //  Constant definitions
138 //---------------------------------------------------------------------------
139
140 // TracePoint support for realtime-debugging
141 #ifdef _DBG_TRACE_POINTS_
142 void PUBLIC TgtDbgSignalTracePoint(BYTE bTracePointNumber_p);
143 #define TGT_DBG_SIGNAL_TRACE_POINT(p)   TgtDbgSignalTracePoint(p)
144 #else
145 #define TGT_DBG_SIGNAL_TRACE_POINT(p)
146 #endif
147
148 #define EVENT_STATE_INIT        0
149 #define EVENT_STATE_IOCTL       1       // ioctl entered and ready to receive EPL event
150 #define EVENT_STATE_READY       2       // EPL event can be forwarded to user application
151 #define EVENT_STATE_TERM        3       // terminate processing
152
153 #define EPL_STATE_NOTOPEN       0
154 #define EPL_STATE_NOTINIT       1
155 #define EPL_STATE_RUNNING       2
156 #define EPL_STATE_SHUTDOWN      3
157
158 //---------------------------------------------------------------------------
159 //  Global variables
160 //---------------------------------------------------------------------------
161
162 #ifdef CONFIG_DEVFS_FS
163
164     // driver major number
165 static int nDrvMajorNumber_g;
166
167 #else
168
169     // device number (major and minor)
170 static dev_t nDevNum_g;
171 static struct cdev *pEpl_cdev_g;
172
173 #endif
174
175 static volatile unsigned int uiEplState_g = EPL_STATE_NOTOPEN;
176
177 static struct semaphore SemaphoreCbEvent_g;     // semaphore for EplLinCbEvent
178 static wait_queue_head_t WaitQueueCbEvent_g;    // wait queue EplLinCbEvent
179 static wait_queue_head_t WaitQueueProcess_g;    // wait queue for EplApiProcess (user process)
180 static wait_queue_head_t WaitQueueRelease_g;    // wait queue for EplLinRelease
181 static atomic_t AtomicEventState_g = ATOMIC_INIT(EVENT_STATE_INIT);
182 static tEplApiEventType EventType_g;    // event type (enum)
183 static tEplApiEventArg *pEventArg_g;    // event argument (union)
184 static tEplKernel RetCbEvent_g; // return code from event callback function
185 static wait_queue_head_t WaitQueueCbSync_g;     // wait queue EplLinCbSync
186 static wait_queue_head_t WaitQueuePI_In_g;      // wait queue for EplApiProcessImageExchangeIn (user process)
187 static atomic_t AtomicSyncState_g = ATOMIC_INIT(EVENT_STATE_INIT);
188
189 //---------------------------------------------------------------------------
190 //  Local types
191 //---------------------------------------------------------------------------
192
193 typedef struct {
194         void *m_pUserArg;
195         void *m_pData;
196
197 } tEplLinSdoBufHeader;
198
199 //---------------------------------------------------------------------------
200 //  Local variables
201 //---------------------------------------------------------------------------
202
203 //---------------------------------------------------------------------------
204 //  Prototypes of internal functions
205 //---------------------------------------------------------------------------
206
207 tEplKernel PUBLIC EplLinCbEvent(tEplApiEventType EventType_p,   // IN: event type (enum)
208                                 tEplApiEventArg * pEventArg_p,  // IN: event argument (union)
209                                 void GENERIC * pUserArg_p);
210
211 tEplKernel PUBLIC EplLinCbSync(void);
212
213 static int __init EplLinInit(void);
214 static void __exit EplLinExit(void);
215
216 static int EplLinOpen(struct inode *pDeviceFile_p, struct file *pInstance_p);
217 static int EplLinRelease(struct inode *pDeviceFile_p, struct file *pInstance_p);
218 static ssize_t EplLinRead(struct file *pInstance_p, char *pDstBuff_p,
219                           size_t BuffSize_p, loff_t * pFileOffs_p);
220 static ssize_t EplLinWrite(struct file *pInstance_p, const char *pSrcBuff_p,
221                            size_t BuffSize_p, loff_t * pFileOffs_p);
222 static int EplLinIoctl(struct inode *pDeviceFile_p, struct file *pInstance_p,
223                        unsigned int uiIoctlCmd_p, unsigned long ulArg_p);
224
225 //---------------------------------------------------------------------------
226 //  Kernel Module specific Data Structures
227 //---------------------------------------------------------------------------
228
229 EXPORT_NO_SYMBOLS;
230
231 module_init(EplLinInit);
232 module_exit(EplLinExit);
233
234 static struct file_operations EplLinFileOps_g = {
235         .owner = THIS_MODULE,
236         .open = EplLinOpen,
237         .release = EplLinRelease,
238         .read = EplLinRead,
239         .write = EplLinWrite,
240         .ioctl = EplLinIoctl,
241
242 };
243
244 //=========================================================================//
245 //                                                                         //
246 //          P U B L I C   F U N C T I O N S                                //
247 //                                                                         //
248 //=========================================================================//
249
250 //---------------------------------------------------------------------------
251 //  Initailize Driver
252 //---------------------------------------------------------------------------
253 //  -> insmod driver
254 //---------------------------------------------------------------------------
255
256 static int __init EplLinInit(void)
257 {
258
259         tEplKernel EplRet;
260         int iErr;
261         int iRet;
262 #ifdef CONFIG_DEVFS_FS
263         int nMinorNumber;
264 #endif
265
266         TRACE0("EPL: + EplLinInit...\n");
267         TRACE2("EPL:   Driver build: %s / %s\n", __DATE__, __TIME__);
268
269         iRet = 0;
270
271         // initialize global variables
272         atomic_set(&AtomicEventState_g, EVENT_STATE_INIT);
273         sema_init(&SemaphoreCbEvent_g, 1);
274         init_waitqueue_head(&WaitQueueCbEvent_g);
275         init_waitqueue_head(&WaitQueueProcess_g);
276         init_waitqueue_head(&WaitQueueRelease_g);
277
278 #ifdef CONFIG_DEVFS_FS
279
280         // register character device handler
281         TRACE2("EPL:   Installing Driver '%s', Version %s...\n",
282                EPLLIN_DRV_NAME, EPL_PRODUCT_VERSION);
283         TRACE0("EPL:   (using dynamic major number assignment)\n");
284         nDrvMajorNumber_g =
285             register_chrdev(0, EPLLIN_DRV_NAME, &EplLinFileOps_g);
286         if (nDrvMajorNumber_g != 0) {
287                 TRACE2
288                     ("EPL:   Driver '%s' installed successful, assigned MajorNumber=%d\n",
289                      EPLLIN_DRV_NAME, nDrvMajorNumber_g);
290         } else {
291                 TRACE1
292                     ("EPL:   ERROR: Driver '%s' is unable to get a free MajorNumber!\n",
293                      EPLLIN_DRV_NAME);
294                 iRet = -EIO;
295                 goto Exit;
296         }
297
298         // create device node in DEVFS
299         nMinorNumber = 0;
300         TRACE1("EPL:   Creating device node '/dev/%s'...\n", EPLLIN_DEV_NAME);
301         iErr =
302             devfs_mk_cdev(MKDEV(nDrvMajorNumber_g, nMinorNumber),
303                           S_IFCHR | S_IRUGO | S_IWUGO, EPLLIN_DEV_NAME);
304         if (iErr == 0) {
305                 TRACE1("EPL:   Device node '/dev/%s' created successful.\n",
306                        EPLLIN_DEV_NAME);
307         } else {
308                 TRACE1("EPL:   ERROR: unable to create device node '/dev/%s'\n",
309                        EPLLIN_DEV_NAME);
310                 iRet = -EIO;
311                 goto Exit;
312         }
313
314 #else
315
316         // register character device handler
317         // only one Minor required
318         TRACE2("EPL:   Installing Driver '%s', Version %s...\n",
319                EPLLIN_DRV_NAME, EPL_PRODUCT_VERSION);
320         iRet = alloc_chrdev_region(&nDevNum_g, 0, 1, EPLLIN_DRV_NAME);
321         if (iRet == 0) {
322                 TRACE2
323                     ("EPL:   Driver '%s' installed successful, assigned MajorNumber=%d\n",
324                      EPLLIN_DRV_NAME, MAJOR(nDevNum_g));
325         } else {
326                 TRACE1
327                     ("EPL:   ERROR: Driver '%s' is unable to get a free MajorNumber!\n",
328                      EPLLIN_DRV_NAME);
329                 iRet = -EIO;
330                 goto Exit;
331         }
332
333         // register cdev structure
334         pEpl_cdev_g = cdev_alloc();
335         pEpl_cdev_g->ops = &EplLinFileOps_g;
336         pEpl_cdev_g->owner = THIS_MODULE;
337         iErr = cdev_add(pEpl_cdev_g, nDevNum_g, 1);
338         if (iErr) {
339                 TRACE2("EPL:   ERROR %d: Driver '%s' could not be added!\n",
340                        iErr, EPLLIN_DRV_NAME);
341                 iRet = -EIO;
342                 goto Exit;
343         }
344 #endif
345
346         // create device node in PROCFS
347         EplRet = EplLinProcInit();
348         if (EplRet != kEplSuccessful) {
349                 goto Exit;
350         }
351
352       Exit:
353
354         TRACE1("EPL: - EplLinInit (iRet=%d)\n", iRet);
355         return (iRet);
356
357 }
358
359 //---------------------------------------------------------------------------
360 //  Remove Driver
361 //---------------------------------------------------------------------------
362 //  -> rmmod driver
363 //---------------------------------------------------------------------------
364
365 static void __exit EplLinExit(void)
366 {
367
368         tEplKernel EplRet;
369
370         // delete instance for all modules
371 //    EplRet = EplApiShutdown();
372 //    printk("EplApiShutdown():  0x%X\n", EplRet);
373
374         // deinitialize proc fs
375         EplRet = EplLinProcFree();
376         printk("EplLinProcFree():        0x%X\n", EplRet);
377
378         TRACE0("EPL: + EplLinExit...\n");
379
380 #ifdef CONFIG_DEVFS_FS
381
382         // remove device node from DEVFS
383         devfs_remove(EPLLIN_DEV_NAME);
384         TRACE1("EPL:   Device node '/dev/%s' removed.\n", EPLLIN_DEV_NAME);
385
386         // unregister character device handler
387         unregister_chrdev(nDrvMajorNumber_g, EPLLIN_DRV_NAME);
388
389 #else
390
391         // remove cdev structure
392         cdev_del(pEpl_cdev_g);
393
394         // unregister character device handler
395         unregister_chrdev_region(nDevNum_g, 1);
396
397 #endif
398
399         TRACE1("EPL:   Driver '%s' removed.\n", EPLLIN_DRV_NAME);
400
401         TRACE0("EPL: - EplLinExit\n");
402
403 }
404
405 //---------------------------------------------------------------------------
406 //  Open Driver
407 //---------------------------------------------------------------------------
408 //  -> open("/dev/driver", O_RDWR)...
409 //---------------------------------------------------------------------------
410
411 static int EplLinOpen(struct inode *pDeviceFile_p,      // information about the device to open
412                       struct file *pInstance_p) // information about driver instance
413 {
414
415         int iRet;
416
417         TRACE0("EPL: + EplLinOpen...\n");
418
419         MOD_INC_USE_COUNT;
420
421         if (uiEplState_g != EPL_STATE_NOTOPEN) {        // stack already initialized
422                 iRet = -EALREADY;
423         } else {
424                 atomic_set(&AtomicEventState_g, EVENT_STATE_INIT);
425                 sema_init(&SemaphoreCbEvent_g, 1);
426                 init_waitqueue_head(&WaitQueueCbEvent_g);
427                 init_waitqueue_head(&WaitQueueProcess_g);
428                 init_waitqueue_head(&WaitQueueRelease_g);
429                 atomic_set(&AtomicSyncState_g, EVENT_STATE_INIT);
430                 init_waitqueue_head(&WaitQueueCbSync_g);
431                 init_waitqueue_head(&WaitQueuePI_In_g);
432
433                 uiEplState_g = EPL_STATE_NOTINIT;
434                 iRet = 0;
435         }
436
437         TRACE1("EPL: - EplLinOpen (iRet=%d)\n", iRet);
438         return (iRet);
439
440 }
441
442 //---------------------------------------------------------------------------
443 //  Close Driver
444 //---------------------------------------------------------------------------
445 //  -> close(device)...
446 //---------------------------------------------------------------------------
447
448 static int EplLinRelease(struct inode *pDeviceFile_p,   // information about the device to open
449                          struct file *pInstance_p)      // information about driver instance
450 {
451
452         tEplKernel EplRet = kEplSuccessful;
453         int iRet;
454
455         TRACE0("EPL: + EplLinRelease...\n");
456
457         if (uiEplState_g != EPL_STATE_NOTINIT) {
458                 // pass control to sync kernel thread, but signal termination
459                 atomic_set(&AtomicSyncState_g, EVENT_STATE_TERM);
460                 wake_up_interruptible(&WaitQueueCbSync_g);
461                 wake_up_interruptible(&WaitQueuePI_In_g);
462
463                 // pass control to event queue kernel thread
464                 atomic_set(&AtomicEventState_g, EVENT_STATE_TERM);
465                 wake_up_interruptible(&WaitQueueCbEvent_g);
466
467                 if (uiEplState_g == EPL_STATE_RUNNING) {        // post NmtEventSwitchOff
468                         EplRet = EplApiExecNmtCommand(kEplNmtEventSwitchOff);
469
470                 }
471
472                 if (EplRet == kEplSuccessful) {
473                         TRACE0("EPL:   waiting for NMT_GS_OFF\n");
474                         wait_event_interruptible(WaitQueueRelease_g,
475                                                  (uiEplState_g ==
476                                                   EPL_STATE_SHUTDOWN));
477                 } else {        // post NmtEventSwitchOff failed
478                         TRACE0("EPL:   event post failed\n");
479                 }
480
481                 // $$$ d.k.: What if waiting was interrupted by signal?
482
483                 TRACE0("EPL:   call EplApiShutdown()\n");
484                 // EPL stack can be safely shut down
485                 // delete instance for all EPL modules
486                 EplRet = EplApiShutdown();
487                 printk("EplApiShutdown():  0x%X\n", EplRet);
488         }
489
490         uiEplState_g = EPL_STATE_NOTOPEN;
491         iRet = 0;
492
493         MOD_DEC_USE_COUNT;
494
495         TRACE1("EPL: - EplLinRelease (iRet=%d)\n", iRet);
496         return (iRet);
497
498 }
499
500 //---------------------------------------------------------------------------
501 //  Read Data from Driver
502 //---------------------------------------------------------------------------
503 //  -> read(...)
504 //---------------------------------------------------------------------------
505
506 static ssize_t EplLinRead(struct file *pInstance_p,     // information about driver instance
507                           char *pDstBuff_p,     // address of buffer to fill with data
508                           size_t BuffSize_p,    // length of the buffer
509                           loff_t * pFileOffs_p) // offset in the file
510 {
511
512         int iRet;
513
514         TRACE0("EPL: + EplLinRead...\n");
515
516         TRACE0("EPL:   Sorry, this operation isn't supported.\n");
517         iRet = -EINVAL;
518
519         TRACE1("EPL: - EplLinRead (iRet=%d)\n", iRet);
520         return (iRet);
521
522 }
523
524 //---------------------------------------------------------------------------
525 //  Write Data to Driver
526 //---------------------------------------------------------------------------
527 //  -> write(...)
528 //---------------------------------------------------------------------------
529
530 static ssize_t EplLinWrite(struct file *pInstance_p,    // information about driver instance
531                            const char *pSrcBuff_p,      // address of buffer to get data from
532                            size_t BuffSize_p,   // length of the buffer
533                            loff_t * pFileOffs_p)        // offset in the file
534 {
535
536         int iRet;
537
538         TRACE0("EPL: + EplLinWrite...\n");
539
540         TRACE0("EPL:   Sorry, this operation isn't supported.\n");
541         iRet = -EINVAL;
542
543         TRACE1("EPL: - EplLinWrite (iRet=%d)\n", iRet);
544         return (iRet);
545
546 }
547
548 //---------------------------------------------------------------------------
549 //  Generic Access to Driver
550 //---------------------------------------------------------------------------
551 //  -> ioctl(...)
552 //---------------------------------------------------------------------------
553
554 static int EplLinIoctl(struct inode *pDeviceFile_p,     // information about the device to open
555                        struct file *pInstance_p,        // information about driver instance
556                        unsigned int uiIoctlCmd_p,       // Ioctl command to execute
557                        unsigned long ulArg_p)   // Ioctl command specific argument/parameter
558 {
559
560         tEplKernel EplRet;
561         int iErr;
562         int iRet;
563
564 //    TRACE1("EPL: + EplLinIoctl (uiIoctlCmd_p=%d)...\n", uiIoctlCmd_p);
565
566         iRet = -EINVAL;
567
568         switch (uiIoctlCmd_p) {
569                 // ----------------------------------------------------------
570         case EPLLIN_CMD_INITIALIZE:
571                 {
572                         tEplApiInitParam EplApiInitParam;
573
574                         iErr =
575                             copy_from_user(&EplApiInitParam,
576                                            (const void *)ulArg_p,
577                                            sizeof(EplApiInitParam));
578                         if (iErr != 0) {
579                                 iRet = -EIO;
580                                 goto Exit;
581                         }
582
583                         EplApiInitParam.m_pfnCbEvent = EplLinCbEvent;
584                         EplApiInitParam.m_pfnCbSync = EplLinCbSync;
585
586                         EplRet = EplApiInitialize(&EplApiInitParam);
587
588                         uiEplState_g = EPL_STATE_RUNNING;
589
590                         iRet = (int)EplRet;
591                         break;
592                 }
593
594                 // ----------------------------------------------------------
595         case EPLLIN_CMD_SHUTDOWN:
596                 {               // shutdown the threads
597
598                         // pass control to sync kernel thread, but signal termination
599                         atomic_set(&AtomicSyncState_g, EVENT_STATE_TERM);
600                         wake_up_interruptible(&WaitQueueCbSync_g);
601                         wake_up_interruptible(&WaitQueuePI_In_g);
602
603                         // pass control to event queue kernel thread
604                         atomic_set(&AtomicEventState_g, EVENT_STATE_TERM);
605                         wake_up_interruptible(&WaitQueueCbEvent_g);
606
607                         if (uiEplState_g == EPL_STATE_RUNNING) {        // post NmtEventSwitchOff
608                                 EplRet =
609                                     EplApiExecNmtCommand(kEplNmtEventSwitchOff);
610
611                         }
612
613                         iRet = 0;
614                         break;
615                 }
616
617                 // ----------------------------------------------------------
618         case EPLLIN_CMD_READ_LOCAL_OBJECT:
619                 {
620                         tEplLinLocalObject LocalObject;
621                         void *pData;
622
623                         iErr =
624                             copy_from_user(&LocalObject, (const void *)ulArg_p,
625                                            sizeof(LocalObject));
626                         if (iErr != 0) {
627                                 iRet = -EIO;
628                                 goto Exit;
629                         }
630
631                         if ((LocalObject.m_pData == NULL)
632                             || (LocalObject.m_uiSize == 0)) {
633                                 iRet = (int)kEplApiInvalidParam;
634                                 goto Exit;
635                         }
636
637                         pData = vmalloc(LocalObject.m_uiSize);
638                         if (pData == NULL) {    // no memory available
639                                 iRet = -ENOMEM;
640                                 goto Exit;
641                         }
642
643                         EplRet =
644                             EplApiReadLocalObject(LocalObject.m_uiIndex,
645                                                   LocalObject.m_uiSubindex,
646                                                   pData, &LocalObject.m_uiSize);
647
648                         if (EplRet == kEplSuccessful) {
649                                 iErr =
650                                     copy_to_user(LocalObject.m_pData, pData,
651                                                  LocalObject.m_uiSize);
652
653                                 vfree(pData);
654
655                                 if (iErr != 0) {
656                                         iRet = -EIO;
657                                         goto Exit;
658                                 }
659                                 // return actual size (LocalObject.m_uiSize)
660                                 iErr = put_user(LocalObject.m_uiSize,
661                                                 (unsigned int *)(ulArg_p +
662                                                                  (unsigned long)
663                                                                  &LocalObject.
664                                                                  m_uiSize -
665                                                                  (unsigned long)
666                                                                  &LocalObject));
667                                 if (iErr != 0) {
668                                         iRet = -EIO;
669                                         goto Exit;
670                                 }
671
672                         } else {
673                                 vfree(pData);
674                         }
675
676                         iRet = (int)EplRet;
677                         break;
678                 }
679
680                 // ----------------------------------------------------------
681         case EPLLIN_CMD_WRITE_LOCAL_OBJECT:
682                 {
683                         tEplLinLocalObject LocalObject;
684                         void *pData;
685
686                         iErr =
687                             copy_from_user(&LocalObject, (const void *)ulArg_p,
688                                            sizeof(LocalObject));
689                         if (iErr != 0) {
690                                 iRet = -EIO;
691                                 goto Exit;
692                         }
693
694                         if ((LocalObject.m_pData == NULL)
695                             || (LocalObject.m_uiSize == 0)) {
696                                 iRet = (int)kEplApiInvalidParam;
697                                 goto Exit;
698                         }
699
700                         pData = vmalloc(LocalObject.m_uiSize);
701                         if (pData == NULL) {    // no memory available
702                                 iRet = -ENOMEM;
703                                 goto Exit;
704                         }
705                         iErr =
706                             copy_from_user(pData, LocalObject.m_pData,
707                                            LocalObject.m_uiSize);
708                         if (iErr != 0) {
709                                 iRet = -EIO;
710                                 goto Exit;
711                         }
712
713                         EplRet =
714                             EplApiWriteLocalObject(LocalObject.m_uiIndex,
715                                                    LocalObject.m_uiSubindex,
716                                                    pData, LocalObject.m_uiSize);
717
718                         vfree(pData);
719
720                         iRet = (int)EplRet;
721                         break;
722                 }
723
724         case EPLLIN_CMD_READ_OBJECT:
725                 {
726                         tEplLinSdoObject SdoObject;
727                         void *pData;
728                         tEplLinSdoBufHeader *pBufHeader;
729                         tEplSdoComConHdl *pSdoComConHdl;
730
731                         iErr =
732                             copy_from_user(&SdoObject, (const void *)ulArg_p,
733                                            sizeof(SdoObject));
734                         if (iErr != 0) {
735                                 iRet = -EIO;
736                                 goto Exit;
737                         }
738
739                         if ((SdoObject.m_le_pData == NULL)
740                             || (SdoObject.m_uiSize == 0)) {
741                                 iRet = (int)kEplApiInvalidParam;
742                                 goto Exit;
743                         }
744
745                         pBufHeader =
746                             (tEplLinSdoBufHeader *)
747                             vmalloc(sizeof(tEplLinSdoBufHeader) +
748                                     SdoObject.m_uiSize);
749                         if (pBufHeader == NULL) {       // no memory available
750                                 iRet = -ENOMEM;
751                                 goto Exit;
752                         }
753                         // initiate temporary buffer
754                         pBufHeader->m_pUserArg = SdoObject.m_pUserArg;  // original user argument pointer
755                         pBufHeader->m_pData = SdoObject.m_le_pData;     // original data pointer from app
756                         pData = pBufHeader + sizeof(tEplLinSdoBufHeader);
757
758                         if (SdoObject.m_fValidSdoComConHdl != FALSE) {
759                                 pSdoComConHdl = &SdoObject.m_SdoComConHdl;
760                         } else {
761                                 pSdoComConHdl = NULL;
762                         }
763
764                         EplRet =
765                             EplApiReadObject(pSdoComConHdl,
766                                              SdoObject.m_uiNodeId,
767                                              SdoObject.m_uiIndex,
768                                              SdoObject.m_uiSubindex, pData,
769                                              &SdoObject.m_uiSize,
770                                              SdoObject.m_SdoType, pBufHeader);
771
772                         // return actual SDO handle (SdoObject.m_SdoComConHdl)
773                         iErr = put_user(SdoObject.m_SdoComConHdl,
774                                         (unsigned int *)(ulArg_p +
775                                                          (unsigned long)
776                                                          &SdoObject.
777                                                          m_SdoComConHdl -
778                                                          (unsigned long)
779                                                          &SdoObject));
780                         if (iErr != 0) {
781                                 iRet = -EIO;
782                                 goto Exit;
783                         }
784
785                         if (EplRet == kEplSuccessful) {
786                                 iErr =
787                                     copy_to_user(SdoObject.m_le_pData, pData,
788                                                  SdoObject.m_uiSize);
789
790                                 vfree(pBufHeader);
791
792                                 if (iErr != 0) {
793                                         iRet = -EIO;
794                                         goto Exit;
795                                 }
796                                 // return actual size (SdoObject.m_uiSize)
797                                 iErr = put_user(SdoObject.m_uiSize,
798                                                 (unsigned int *)(ulArg_p +
799                                                                  (unsigned long)
800                                                                  &SdoObject.
801                                                                  m_uiSize -
802                                                                  (unsigned long)
803                                                                  &SdoObject));
804                                 if (iErr != 0) {
805                                         iRet = -EIO;
806                                         goto Exit;
807                                 }
808                         } else if (EplRet != kEplApiTaskDeferred) {     // error ocurred
809                                 vfree(pBufHeader);
810                                 if (iErr != 0) {
811                                         iRet = -EIO;
812                                         goto Exit;
813                                 }
814                         }
815
816                         iRet = (int)EplRet;
817                         break;
818                 }
819
820         case EPLLIN_CMD_WRITE_OBJECT:
821                 {
822                         tEplLinSdoObject SdoObject;
823                         void *pData;
824                         tEplLinSdoBufHeader *pBufHeader;
825                         tEplSdoComConHdl *pSdoComConHdl;
826
827                         iErr =
828                             copy_from_user(&SdoObject, (const void *)ulArg_p,
829                                            sizeof(SdoObject));
830                         if (iErr != 0) {
831                                 iRet = -EIO;
832                                 goto Exit;
833                         }
834
835                         if ((SdoObject.m_le_pData == NULL)
836                             || (SdoObject.m_uiSize == 0)) {
837                                 iRet = (int)kEplApiInvalidParam;
838                                 goto Exit;
839                         }
840
841                         pBufHeader =
842                             (tEplLinSdoBufHeader *)
843                             vmalloc(sizeof(tEplLinSdoBufHeader) +
844                                     SdoObject.m_uiSize);
845                         if (pBufHeader == NULL) {       // no memory available
846                                 iRet = -ENOMEM;
847                                 goto Exit;
848                         }
849                         // initiate temporary buffer
850                         pBufHeader->m_pUserArg = SdoObject.m_pUserArg;  // original user argument pointer
851                         pBufHeader->m_pData = SdoObject.m_le_pData;     // original data pointer from app
852                         pData = pBufHeader + sizeof(tEplLinSdoBufHeader);
853
854                         iErr =
855                             copy_from_user(pData, SdoObject.m_le_pData,
856                                            SdoObject.m_uiSize);
857
858                         if (iErr != 0) {
859                                 iRet = -EIO;
860                                 goto Exit;
861                         }
862
863                         if (SdoObject.m_fValidSdoComConHdl != FALSE) {
864                                 pSdoComConHdl = &SdoObject.m_SdoComConHdl;
865                         } else {
866                                 pSdoComConHdl = NULL;
867                         }
868
869                         EplRet =
870                             EplApiWriteObject(pSdoComConHdl,
871                                               SdoObject.m_uiNodeId,
872                                               SdoObject.m_uiIndex,
873                                               SdoObject.m_uiSubindex, pData,
874                                               SdoObject.m_uiSize,
875                                               SdoObject.m_SdoType, pBufHeader);
876
877                         // return actual SDO handle (SdoObject.m_SdoComConHdl)
878                         iErr = put_user(SdoObject.m_SdoComConHdl,
879                                         (unsigned int *)(ulArg_p +
880                                                          (unsigned long)
881                                                          &SdoObject.
882                                                          m_SdoComConHdl -
883                                                          (unsigned long)
884                                                          &SdoObject));
885                         if (iErr != 0) {
886                                 iRet = -EIO;
887                                 goto Exit;
888                         }
889
890                         if (EplRet != kEplApiTaskDeferred) {    // succeeded or error ocurred, but task not deferred
891                                 vfree(pBufHeader);
892                         }
893
894                         iRet = (int)EplRet;
895                         break;
896                 }
897
898                 // ----------------------------------------------------------
899         case EPLLIN_CMD_FREE_SDO_CHANNEL:
900                 {
901                         // forward SDO handle to EPL stack
902                         EplRet =
903                             EplApiFreeSdoChannel((tEplSdoComConHdl) ulArg_p);
904
905                         iRet = (int)EplRet;
906                         break;
907                 }
908
909 #if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
910                 // ----------------------------------------------------------
911         case EPLLIN_CMD_MN_TRIGGER_STATE_CHANGE:
912                 {
913                         tEplLinNodeCmdObject NodeCmdObject;
914
915                         iErr =
916                             copy_from_user(&NodeCmdObject,
917                                            (const void *)ulArg_p,
918                                            sizeof(NodeCmdObject));
919                         if (iErr != 0) {
920                                 iRet = -EIO;
921                                 goto Exit;
922                         }
923
924                         EplRet =
925                             EplApiMnTriggerStateChange(NodeCmdObject.m_uiNodeId,
926                                                        NodeCmdObject.
927                                                        m_NodeCommand);
928                         iRet = (int)EplRet;
929                         break;
930                 }
931 #endif
932
933                 // ----------------------------------------------------------
934         case EPLLIN_CMD_GET_EVENT:
935                 {
936                         tEplLinEvent Event;
937
938                         // save event structure
939                         iErr =
940                             copy_from_user(&Event, (const void *)ulArg_p,
941                                            sizeof(Event));
942                         if (iErr != 0) {
943                                 iRet = -EIO;
944                                 goto Exit;
945                         }
946                         // save return code from application's event callback function
947                         RetCbEvent_g = Event.m_RetCbEvent;
948
949                         if (RetCbEvent_g == kEplShutdown) {
950                                 // pass control to event queue kernel thread, but signal termination
951                                 atomic_set(&AtomicEventState_g,
952                                            EVENT_STATE_TERM);
953                                 wake_up_interruptible(&WaitQueueCbEvent_g);
954                                 // exit with error -> EplApiProcess() will leave the infinite loop
955                                 iRet = 1;
956                                 goto Exit;
957                         }
958                         // pass control to event queue kernel thread
959                         atomic_set(&AtomicEventState_g, EVENT_STATE_IOCTL);
960                         wake_up_interruptible(&WaitQueueCbEvent_g);
961
962                         // fall asleep itself in own wait queue
963                         iErr = wait_event_interruptible(WaitQueueProcess_g,
964                                                         (atomic_read
965                                                          (&AtomicEventState_g)
966                                                          == EVENT_STATE_READY)
967                                                         ||
968                                                         (atomic_read
969                                                          (&AtomicEventState_g)
970                                                          == EVENT_STATE_TERM));
971                         if (iErr != 0) {        // waiting was interrupted by signal
972                                 // pass control to event queue kernel thread, but signal termination
973                                 atomic_set(&AtomicEventState_g,
974                                            EVENT_STATE_TERM);
975                                 wake_up_interruptible(&WaitQueueCbEvent_g);
976                                 // exit with this error -> EplApiProcess() will leave the infinite loop
977                                 iRet = iErr;
978                                 goto Exit;
979                         } else if (atomic_read(&AtomicEventState_g) == EVENT_STATE_TERM) {      // termination in progress
980                                 // pass control to event queue kernel thread, but signal termination
981                                 wake_up_interruptible(&WaitQueueCbEvent_g);
982                                 // exit with this error -> EplApiProcess() will leave the infinite loop
983                                 iRet = 1;
984                                 goto Exit;
985                         }
986                         // copy event to user space
987                         iErr =
988                             copy_to_user(Event.m_pEventType, &EventType_g,
989                                          sizeof(EventType_g));
990                         if (iErr != 0) {        // not all data could be copied
991                                 iRet = -EIO;
992                                 goto Exit;
993                         }
994                         // $$$ d.k. perform SDO event processing
995                         if (EventType_g == kEplApiEventSdo) {
996                                 void *pData;
997                                 tEplLinSdoBufHeader *pBufHeader;
998
999                                 pBufHeader =
1000                                     (tEplLinSdoBufHeader *) pEventArg_g->m_Sdo.
1001                                     m_pUserArg;
1002                                 pData =
1003                                     pBufHeader + sizeof(tEplLinSdoBufHeader);
1004
1005                                 if (pEventArg_g->m_Sdo.m_SdoAccessType ==
1006                                     kEplSdoAccessTypeRead) {
1007                                         // copy read data to user space
1008                                         iErr =
1009                                             copy_to_user(pBufHeader->m_pData,
1010                                                          pData,
1011                                                          pEventArg_g->m_Sdo.
1012                                                          m_uiTransferredByte);
1013                                         if (iErr != 0) {        // not all data could be copied
1014                                                 iRet = -EIO;
1015                                                 goto Exit;
1016                                         }
1017                                 }
1018                                 pEventArg_g->m_Sdo.m_pUserArg =
1019                                     pBufHeader->m_pUserArg;
1020                                 vfree(pBufHeader);
1021                         }
1022
1023                         iErr =
1024                             copy_to_user(Event.m_pEventArg, pEventArg_g,
1025                                          min(sizeof(tEplApiEventArg),
1026                                              Event.m_uiEventArgSize));
1027                         if (iErr != 0) {        // not all data could be copied
1028                                 iRet = -EIO;
1029                                 goto Exit;
1030                         }
1031                         // return to EplApiProcess(), which will call the application's event callback function
1032                         iRet = 0;
1033
1034                         break;
1035                 }
1036
1037                 // ----------------------------------------------------------
1038         case EPLLIN_CMD_PI_SETUP:
1039                 {
1040                         EplRet = EplApiProcessImageSetup();
1041                         iRet = (int)EplRet;
1042
1043                         break;
1044                 }
1045
1046                 // ----------------------------------------------------------
1047         case EPLLIN_CMD_PI_IN:
1048                 {
1049                         tEplApiProcessImage ProcessImageIn;
1050
1051                         // save process image structure
1052                         iErr =
1053                             copy_from_user(&ProcessImageIn,
1054                                            (const void *)ulArg_p,
1055                                            sizeof(ProcessImageIn));
1056                         if (iErr != 0) {
1057                                 iRet = -EIO;
1058                                 goto Exit;
1059                         }
1060                         // pass control to event queue kernel thread
1061                         atomic_set(&AtomicSyncState_g, EVENT_STATE_IOCTL);
1062
1063                         // fall asleep itself in own wait queue
1064                         iErr = wait_event_interruptible(WaitQueuePI_In_g,
1065                                                         (atomic_read
1066                                                          (&AtomicSyncState_g) ==
1067                                                          EVENT_STATE_READY)
1068                                                         ||
1069                                                         (atomic_read
1070                                                          (&AtomicSyncState_g) ==
1071                                                          EVENT_STATE_TERM));
1072                         if (iErr != 0) {        // waiting was interrupted by signal
1073                                 // pass control to sync kernel thread, but signal termination
1074                                 atomic_set(&AtomicSyncState_g,
1075                                            EVENT_STATE_TERM);
1076                                 wake_up_interruptible(&WaitQueueCbSync_g);
1077                                 // exit with this error -> application will leave the infinite loop
1078                                 iRet = iErr;
1079                                 goto Exit;
1080                         } else if (atomic_read(&AtomicSyncState_g) == EVENT_STATE_TERM) {       // termination in progress
1081                                 // pass control to sync kernel thread, but signal termination
1082                                 wake_up_interruptible(&WaitQueueCbSync_g);
1083                                 // exit with this error -> application will leave the infinite loop
1084                                 iRet = 1;
1085                                 goto Exit;
1086                         }
1087                         // exchange process image
1088                         EplRet = EplApiProcessImageExchangeIn(&ProcessImageIn);
1089
1090                         // return to EplApiProcessImageExchangeIn()
1091                         iRet = (int)EplRet;
1092
1093                         break;
1094                 }
1095
1096                 // ----------------------------------------------------------
1097         case EPLLIN_CMD_PI_OUT:
1098                 {
1099                         tEplApiProcessImage ProcessImageOut;
1100
1101                         // save process image structure
1102                         iErr =
1103                             copy_from_user(&ProcessImageOut,
1104                                            (const void *)ulArg_p,
1105                                            sizeof(ProcessImageOut));
1106                         if (iErr != 0) {
1107                                 iRet = -EIO;
1108                                 goto Exit;
1109                         }
1110
1111                         if (atomic_read(&AtomicSyncState_g) !=
1112                             EVENT_STATE_READY) {
1113                                 iRet = (int)kEplInvalidOperation;
1114                                 goto Exit;
1115                         }
1116                         // exchange process image
1117                         EplRet =
1118                             EplApiProcessImageExchangeOut(&ProcessImageOut);
1119
1120                         // pass control to sync kernel thread
1121                         atomic_set(&AtomicSyncState_g, EVENT_STATE_TERM);
1122                         wake_up_interruptible(&WaitQueueCbSync_g);
1123
1124                         // return to EplApiProcessImageExchangeout()
1125                         iRet = (int)EplRet;
1126
1127                         break;
1128                 }
1129
1130                 // ----------------------------------------------------------
1131         case EPLLIN_CMD_NMT_COMMAND:
1132                 {
1133                         // forward NMT command to EPL stack
1134                         EplRet = EplApiExecNmtCommand((tEplNmtEvent) ulArg_p);
1135
1136                         iRet = (int)EplRet;
1137
1138                         break;
1139                 }
1140
1141                 // ----------------------------------------------------------
1142         default:
1143                 {
1144                         break;
1145                 }
1146         }
1147
1148       Exit:
1149
1150 //    TRACE1("EPL: - EplLinIoctl (iRet=%d)\n", iRet);
1151         return (iRet);
1152
1153 }
1154
1155 //=========================================================================//
1156 //                                                                         //
1157 //          P R I V A T E   F U N C T I O N S                              //
1158 //                                                                         //
1159 //=========================================================================//
1160
1161 tEplKernel PUBLIC EplLinCbEvent(tEplApiEventType EventType_p,   // IN: event type (enum)
1162                                 tEplApiEventArg * pEventArg_p,  // IN: event argument (union)
1163                                 void GENERIC * pUserArg_p)
1164 {
1165         tEplKernel EplRet = kEplSuccessful;
1166         int iErr;
1167
1168         // block any further call to this function, i.e. enter critical section
1169         iErr = down_interruptible(&SemaphoreCbEvent_g);
1170         if (iErr != 0) {        // waiting was interrupted by signal
1171                 EplRet = kEplShutdown;
1172                 goto Exit;
1173         }
1174         // wait for EplApiProcess() to call ioctl
1175         // normally it should be waiting already for us to pass a new event
1176         iErr = wait_event_interruptible(WaitQueueCbEvent_g,
1177                                         (atomic_read(&AtomicEventState_g) ==
1178                                          EVENT_STATE_IOCTL)
1179                                         || (atomic_read(&AtomicEventState_g) ==
1180                                             EVENT_STATE_TERM));
1181         if ((iErr != 0) || (atomic_read(&AtomicEventState_g) == EVENT_STATE_TERM)) {    // waiting was interrupted by signal
1182                 EplRet = kEplShutdown;
1183                 goto LeaveCriticalSection;
1184         }
1185         // save event information for ioctl
1186         EventType_g = EventType_p;
1187         pEventArg_g = pEventArg_p;
1188
1189         // pass control to application's event callback function, i.e. EplApiProcess()
1190         atomic_set(&AtomicEventState_g, EVENT_STATE_READY);
1191         wake_up_interruptible(&WaitQueueProcess_g);
1192
1193         // now, the application's event callback function processes the event
1194
1195         // wait for completion of application's event callback function, i.e. EplApiProcess() calls ioctl again
1196         iErr = wait_event_interruptible(WaitQueueCbEvent_g,
1197                                         (atomic_read(&AtomicEventState_g) ==
1198                                          EVENT_STATE_IOCTL)
1199                                         || (atomic_read(&AtomicEventState_g) ==
1200                                             EVENT_STATE_TERM));
1201         if ((iErr != 0) || (atomic_read(&AtomicEventState_g) == EVENT_STATE_TERM)) {    // waiting was interrupted by signal
1202                 EplRet = kEplShutdown;
1203                 goto LeaveCriticalSection;
1204         }
1205         // read return code from application's event callback function
1206         EplRet = RetCbEvent_g;
1207
1208       LeaveCriticalSection:
1209         up(&SemaphoreCbEvent_g);
1210
1211       Exit:
1212         // check if NMT_GS_OFF is reached
1213         if (EventType_p == kEplApiEventNmtStateChange) {
1214                 if (pEventArg_p->m_NmtStateChange.m_NewNmtState == kEplNmtGsOff) {      // NMT state machine was shut down
1215                         TRACE0("EPL:   EplLinCbEvent(NMT_GS_OFF)\n");
1216                         uiEplState_g = EPL_STATE_SHUTDOWN;
1217                         atomic_set(&AtomicEventState_g, EVENT_STATE_TERM);
1218                         wake_up(&WaitQueueRelease_g);
1219                 } else {        // NMT state machine is running
1220                         uiEplState_g = EPL_STATE_RUNNING;
1221                 }
1222         }
1223
1224         return EplRet;
1225 }
1226
1227 tEplKernel PUBLIC EplLinCbSync(void)
1228 {
1229         tEplKernel EplRet = kEplSuccessful;
1230         int iErr;
1231
1232         // check if user process waits for sync
1233         if (atomic_read(&AtomicSyncState_g) == EVENT_STATE_IOCTL) {
1234                 // pass control to application, i.e. EplApiProcessImageExchangeIn()
1235                 atomic_set(&AtomicSyncState_g, EVENT_STATE_READY);
1236                 wake_up_interruptible(&WaitQueuePI_In_g);
1237
1238                 // now, the application processes the sync event
1239
1240                 // wait for call of EplApiProcessImageExchangeOut()
1241                 iErr = wait_event_interruptible(WaitQueueCbSync_g,
1242                                                 (atomic_read(&AtomicSyncState_g)
1243                                                  == EVENT_STATE_IOCTL)
1244                                                 ||
1245                                                 (atomic_read(&AtomicSyncState_g)
1246                                                  == EVENT_STATE_TERM));
1247                 if ((iErr != 0) || (atomic_read(&AtomicEventState_g) == EVENT_STATE_IOCTL)) {   // waiting was interrupted by signal or application called wrong function
1248                         EplRet = kEplShutdown;
1249                 }
1250         } else {                // application is currently not waiting for sync
1251                 // continue without interruption
1252                 // TPDO are set valid by caller (i.e. EplEventkProcess())
1253         }
1254
1255         TGT_DBG_SIGNAL_TRACE_POINT(1);
1256
1257         return EplRet;
1258 }
1259
1260 // EOF