Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
107MODULE_LICENSE("Dual BSD/GPL");
108#ifdef MODULE_AUTHOR
109MODULE_AUTHOR("Daniel.Krueger@SYSTEC-electronic.com");
110MODULE_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_
125void 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)
146static dev_t nDevNum_g;
147static struct cdev *pEpl_cdev_g;
148
149static volatile unsigned int uiEplState_g = EPL_STATE_NOTOPEN;
150
151static struct semaphore SemaphoreCbEvent_g; // semaphore for EplLinCbEvent
152static wait_queue_head_t WaitQueueCbEvent_g; // wait queue EplLinCbEvent
153static wait_queue_head_t WaitQueueProcess_g; // wait queue for EplApiProcess (user process)
154static wait_queue_head_t WaitQueueRelease_g; // wait queue for EplLinRelease
155static atomic_t AtomicEventState_g = ATOMIC_INIT(EVENT_STATE_INIT);
156static tEplApiEventType EventType_g; // event type (enum)
157static tEplApiEventArg *pEventArg_g; // event argument (union)
158static tEplKernel RetCbEvent_g; // return code from event callback function
159static wait_queue_head_t WaitQueueCbSync_g; // wait queue EplLinCbSync
160static wait_queue_head_t WaitQueuePI_In_g; // wait queue for EplApiProcessImageExchangeIn (user process)
161static atomic_t AtomicSyncState_g = ATOMIC_INIT(EVENT_STATE_INIT);
162
163//---------------------------------------------------------------------------
164// Local types
165//---------------------------------------------------------------------------
166
167typedef 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
181tEplKernel EplLinCbEvent(tEplApiEventType EventType_p, // IN: event type (enum)
182 tEplApiEventArg *pEventArg_p, // IN: event argument (union)
183 void *pUserArg_p);
184
185tEplKernel EplLinCbSync(void);
186
187static int __init EplLinInit(void);
188static void __exit EplLinExit(void);
189
190static int EplLinOpen(struct inode *pDeviceFile_p, struct file *pInstance_p);
191static int EplLinRelease(struct inode *pDeviceFile_p, struct file *pInstance_p);
192static ssize_t EplLinRead(struct file *pInstance_p, char *pDstBuff_p,
193 size_t BuffSize_p, loff_t * pFileOffs_p);
194static ssize_t EplLinWrite(struct file *pInstance_p, const char *pSrcBuff_p,
195 size_t BuffSize_p, loff_t * pFileOffs_p);
196static 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
203module_init(EplLinInit);
204module_exit(EplLinExit);
205
206static 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
228static 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
295static 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
328static 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
363static 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
419static 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
443static 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
467static 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
1074tEplKernel 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
1140tEplKernel 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