blob: 05ca0628d6ae3e65c13f98ec84e2cfcff5cd17e7 [file] [log] [blame]
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001/****************************************************************************
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
Daniel Krueger9d7164c2008-12-19 11:41:57 -080073// 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
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800105#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
106 // remove ("make invisible") obsolete symbols for kernel versions 2.6
107 // and higher
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800108#define MOD_INC_USE_COUNT
109#define MOD_DEC_USE_COUNT
110#define EXPORT_NO_SYMBOLS
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800111#else
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800112#error "This driver needs a 2.6.x kernel or higher"
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800113#endif
114
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800115/***************************************************************************/
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
124MODULE_LICENSE("Dual BSD/GPL");
125#ifdef MODULE_AUTHOR
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800126MODULE_AUTHOR("Daniel.Krueger@SYSTEC-electronic.com");
127MODULE_DESCRIPTION("EPL API driver");
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800128#endif
129
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800130//---------------------------------------------------------------------------
131// Configuration
132//---------------------------------------------------------------------------
133
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800134#define EPLLIN_DRV_NAME "systec_epl" // used for <register_chrdev>
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800135
136//---------------------------------------------------------------------------
137// Constant definitions
138//---------------------------------------------------------------------------
139
140// TracePoint support for realtime-debugging
141#ifdef _DBG_TRACE_POINTS_
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800142void PUBLIC TgtDbgSignalTracePoint(BYTE bTracePointNumber_p);
143#define TGT_DBG_SIGNAL_TRACE_POINT(p) TgtDbgSignalTracePoint(p)
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800144#else
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800145#define TGT_DBG_SIGNAL_TRACE_POINT(p)
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800146#endif
147
148#define EVENT_STATE_INIT 0
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800149#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
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800152
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
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800158//---------------------------------------------------------------------------
159// Global variables
160//---------------------------------------------------------------------------
161
162#ifdef CONFIG_DEVFS_FS
163
164 // driver major number
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800165static int nDrvMajorNumber_g;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800166
167#else
168
169 // device number (major and minor)
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800170static dev_t nDevNum_g;
171static struct cdev *pEpl_cdev_g;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800172
173#endif
174
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800175static volatile unsigned int uiEplState_g = EPL_STATE_NOTOPEN;
176
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800177static struct semaphore SemaphoreCbEvent_g; // semaphore for EplLinCbEvent
178static wait_queue_head_t WaitQueueCbEvent_g; // wait queue EplLinCbEvent
179static wait_queue_head_t WaitQueueProcess_g; // wait queue for EplApiProcess (user process)
180static wait_queue_head_t WaitQueueRelease_g; // wait queue for EplLinRelease
181static atomic_t AtomicEventState_g = ATOMIC_INIT(EVENT_STATE_INIT);
182static tEplApiEventType EventType_g; // event type (enum)
183static tEplApiEventArg *pEventArg_g; // event argument (union)
184static tEplKernel RetCbEvent_g; // return code from event callback function
185static wait_queue_head_t WaitQueueCbSync_g; // wait queue EplLinCbSync
186static wait_queue_head_t WaitQueuePI_In_g; // wait queue for EplApiProcessImageExchangeIn (user process)
187static atomic_t AtomicSyncState_g = ATOMIC_INIT(EVENT_STATE_INIT);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800188
189//---------------------------------------------------------------------------
190// Local types
191//---------------------------------------------------------------------------
192
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800193typedef struct {
194 void *m_pUserArg;
195 void *m_pData;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800196
197} tEplLinSdoBufHeader;
198
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800199//---------------------------------------------------------------------------
200// Local variables
201//---------------------------------------------------------------------------
202
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800203//---------------------------------------------------------------------------
204// Prototypes of internal functions
205//---------------------------------------------------------------------------
206
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800207tEplKernel PUBLIC EplLinCbEvent(tEplApiEventType EventType_p, // IN: event type (enum)
208 tEplApiEventArg * pEventArg_p, // IN: event argument (union)
209 void GENERIC * pUserArg_p);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800210
211tEplKernel PUBLIC EplLinCbSync(void);
212
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800213static int __init EplLinInit(void);
214static void __exit EplLinExit(void);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800215
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800216static int EplLinOpen(struct inode *pDeviceFile_p, struct file *pInstance_p);
217static int EplLinRelease(struct inode *pDeviceFile_p, struct file *pInstance_p);
218static ssize_t EplLinRead(struct file *pInstance_p, char *pDstBuff_p,
219 size_t BuffSize_p, loff_t * pFileOffs_p);
220static ssize_t EplLinWrite(struct file *pInstance_p, const char *pSrcBuff_p,
221 size_t BuffSize_p, loff_t * pFileOffs_p);
222static int EplLinIoctl(struct inode *pDeviceFile_p, struct file *pInstance_p,
223 unsigned int uiIoctlCmd_p, unsigned long ulArg_p);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800224
225//---------------------------------------------------------------------------
226// Kernel Module specific Data Structures
227//---------------------------------------------------------------------------
228
229EXPORT_NO_SYMBOLS;
230
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800231module_init(EplLinInit);
232module_exit(EplLinExit);
233
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800234static struct file_operations EplLinFileOps_g = {
235 .owner = THIS_MODULE,
236 .open = EplLinOpen,
237 .release = EplLinRelease,
238 .read = EplLinRead,
239 .write = EplLinWrite,
240 .ioctl = EplLinIoctl,
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800241
242};
243
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800244//=========================================================================//
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
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800256static int __init EplLinInit(void)
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800257{
258
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800259 tEplKernel EplRet;
260 int iErr;
261 int iRet;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800262#ifdef CONFIG_DEVFS_FS
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800263 int nMinorNumber;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800264#endif
265
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800266 TRACE0("EPL: + EplLinInit...\n");
267 TRACE2("EPL: Driver build: %s / %s\n", __DATE__, __TIME__);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800268
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800269 iRet = 0;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800270
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800271 // 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);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800277
278#ifdef CONFIG_DEVFS_FS
279
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800280 // 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 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800297
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800298 // 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 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800313
314#else
315
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800316 // 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 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800332
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800333 // 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 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800344#endif
345
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800346 // create device node in PROCFS
347 EplRet = EplLinProcInit();
348 if (EplRet != kEplSuccessful) {
349 goto Exit;
350 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800351
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800352 Exit:
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800353
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800354 TRACE1("EPL: - EplLinInit (iRet=%d)\n", iRet);
355 return (iRet);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800356
357}
358
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800359//---------------------------------------------------------------------------
360// Remove Driver
361//---------------------------------------------------------------------------
362// -> rmmod driver
363//---------------------------------------------------------------------------
364
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800365static void __exit EplLinExit(void)
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800366{
367
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800368 tEplKernel EplRet;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800369
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800370 // delete instance for all modules
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800371// EplRet = EplApiShutdown();
372// printk("EplApiShutdown(): 0x%X\n", EplRet);
373
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800374 // deinitialize proc fs
375 EplRet = EplLinProcFree();
376 printk("EplLinProcFree(): 0x%X\n", EplRet);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800377
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800378 TRACE0("EPL: + EplLinExit...\n");
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800379
380#ifdef CONFIG_DEVFS_FS
381
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800382 // remove device node from DEVFS
383 devfs_remove(EPLLIN_DEV_NAME);
384 TRACE1("EPL: Device node '/dev/%s' removed.\n", EPLLIN_DEV_NAME);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800385
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800386 // unregister character device handler
387 unregister_chrdev(nDrvMajorNumber_g, EPLLIN_DRV_NAME);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800388
389#else
390
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800391 // remove cdev structure
392 cdev_del(pEpl_cdev_g);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800393
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800394 // unregister character device handler
395 unregister_chrdev_region(nDevNum_g, 1);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800396
397#endif
398
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800399 TRACE1("EPL: Driver '%s' removed.\n", EPLLIN_DRV_NAME);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800400
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800401 TRACE0("EPL: - EplLinExit\n");
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800402
403}
404
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800405//---------------------------------------------------------------------------
406// Open Driver
407//---------------------------------------------------------------------------
408// -> open("/dev/driver", O_RDWR)...
409//---------------------------------------------------------------------------
410
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800411static int EplLinOpen(struct inode *pDeviceFile_p, // information about the device to open
412 struct file *pInstance_p) // information about driver instance
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800413{
414
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800415 int iRet;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800416
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800417 TRACE0("EPL: + EplLinOpen...\n");
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800418
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800419 MOD_INC_USE_COUNT;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800420
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800421 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);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800432
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800433 uiEplState_g = EPL_STATE_NOTINIT;
434 iRet = 0;
435 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800436
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800437 TRACE1("EPL: - EplLinOpen (iRet=%d)\n", iRet);
438 return (iRet);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800439
440}
441
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800442//---------------------------------------------------------------------------
443// Close Driver
444//---------------------------------------------------------------------------
445// -> close(device)...
446//---------------------------------------------------------------------------
447
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800448static int EplLinRelease(struct inode *pDeviceFile_p, // information about the device to open
449 struct file *pInstance_p) // information about driver instance
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800450{
451
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800452 tEplKernel EplRet = kEplSuccessful;
453 int iRet;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800454
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800455 TRACE0("EPL: + EplLinRelease...\n");
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800456
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800457 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);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800462
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800463 // pass control to event queue kernel thread
464 atomic_set(&AtomicEventState_g, EVENT_STATE_TERM);
465 wake_up_interruptible(&WaitQueueCbEvent_g);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800466
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800467 if (uiEplState_g == EPL_STATE_RUNNING) { // post NmtEventSwitchOff
468 EplRet = EplApiExecNmtCommand(kEplNmtEventSwitchOff);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800469
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800470 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800471
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800472 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 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800480
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800481 // $$$ d.k.: What if waiting was interrupted by signal?
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800482
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800483 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 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800489
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800490 uiEplState_g = EPL_STATE_NOTOPEN;
491 iRet = 0;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800492
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800493 MOD_DEC_USE_COUNT;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800494
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800495 TRACE1("EPL: - EplLinRelease (iRet=%d)\n", iRet);
496 return (iRet);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800497
498}
499
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800500//---------------------------------------------------------------------------
501// Read Data from Driver
502//---------------------------------------------------------------------------
503// -> read(...)
504//---------------------------------------------------------------------------
505
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800506static 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
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800510{
511
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800512 int iRet;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800513
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800514 TRACE0("EPL: + EplLinRead...\n");
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800515
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800516 TRACE0("EPL: Sorry, this operation isn't supported.\n");
517 iRet = -EINVAL;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800518
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800519 TRACE1("EPL: - EplLinRead (iRet=%d)\n", iRet);
520 return (iRet);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800521
522}
523
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800524//---------------------------------------------------------------------------
525// Write Data to Driver
526//---------------------------------------------------------------------------
527// -> write(...)
528//---------------------------------------------------------------------------
529
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800530static 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
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800534{
535
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800536 int iRet;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800537
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800538 TRACE0("EPL: + EplLinWrite...\n");
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800539
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800540 TRACE0("EPL: Sorry, this operation isn't supported.\n");
541 iRet = -EINVAL;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800542
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800543 TRACE1("EPL: - EplLinWrite (iRet=%d)\n", iRet);
544 return (iRet);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800545
546}
547
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800548//---------------------------------------------------------------------------
549// Generic Access to Driver
550//---------------------------------------------------------------------------
551// -> ioctl(...)
552//---------------------------------------------------------------------------
553
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800554static 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
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800558{
559
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800560 tEplKernel EplRet;
561 int iErr;
562 int iRet;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800563
564// TRACE1("EPL: + EplLinIoctl (uiIoctlCmd_p=%d)...\n", uiIoctlCmd_p);
565
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800566 iRet = -EINVAL;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800567
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800568 switch (uiIoctlCmd_p) {
569 // ----------------------------------------------------------
570 case EPLLIN_CMD_INITIALIZE:
571 {
572 tEplApiInitParam EplApiInitParam;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800573
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800574 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 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800582
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800583 EplApiInitParam.m_pfnCbEvent = EplLinCbEvent;
584 EplApiInitParam.m_pfnCbSync = EplLinCbSync;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800585
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800586 EplRet = EplApiInitialize(&EplApiInitParam);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800587
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800588 uiEplState_g = EPL_STATE_RUNNING;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800589
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800590 iRet = (int)EplRet;
591 break;
592 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800593
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800594 // ----------------------------------------------------------
595 case EPLLIN_CMD_SHUTDOWN:
596 { // shutdown the threads
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800597
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800598 // 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);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800602
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800603 // pass control to event queue kernel thread
604 atomic_set(&AtomicEventState_g, EVENT_STATE_TERM);
605 wake_up_interruptible(&WaitQueueCbEvent_g);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800606
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800607 if (uiEplState_g == EPL_STATE_RUNNING) { // post NmtEventSwitchOff
608 EplRet =
609 EplApiExecNmtCommand(kEplNmtEventSwitchOff);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800610
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800611 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800612
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800613 iRet = 0;
614 break;
615 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800616
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800617 // ----------------------------------------------------------
618 case EPLLIN_CMD_READ_LOCAL_OBJECT:
619 {
620 tEplLinLocalObject LocalObject;
621 void *pData;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800622
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800623 iErr =
624 copy_from_user(&LocalObject, (const void *)ulArg_p,
625 sizeof(LocalObject));
626 if (iErr != 0) {
627 iRet = -EIO;
628 goto Exit;
629 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800630
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800631 if ((LocalObject.m_pData == NULL)
632 || (LocalObject.m_uiSize == 0)) {
633 iRet = (int)kEplApiInvalidParam;
634 goto Exit;
635 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800636
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800637 pData = vmalloc(LocalObject.m_uiSize);
638 if (pData == NULL) { // no memory available
639 iRet = -ENOMEM;
640 goto Exit;
641 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800642
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800643 EplRet =
644 EplApiReadLocalObject(LocalObject.m_uiIndex,
645 LocalObject.m_uiSubindex,
646 pData, &LocalObject.m_uiSize);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800647
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800648 if (EplRet == kEplSuccessful) {
649 iErr =
650 copy_to_user(LocalObject.m_pData, pData,
651 LocalObject.m_uiSize);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800652
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800653 vfree(pData);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800654
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800655 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 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800671
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800672 } else {
673 vfree(pData);
674 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800675
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800676 iRet = (int)EplRet;
677 break;
678 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800679
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800680 // ----------------------------------------------------------
681 case EPLLIN_CMD_WRITE_LOCAL_OBJECT:
682 {
683 tEplLinLocalObject LocalObject;
684 void *pData;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800685
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800686 iErr =
687 copy_from_user(&LocalObject, (const void *)ulArg_p,
688 sizeof(LocalObject));
689 if (iErr != 0) {
690 iRet = -EIO;
691 goto Exit;
692 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800693
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800694 if ((LocalObject.m_pData == NULL)
695 || (LocalObject.m_uiSize == 0)) {
696 iRet = (int)kEplApiInvalidParam;
697 goto Exit;
698 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800699
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800700 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 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800712
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800713 EplRet =
714 EplApiWriteLocalObject(LocalObject.m_uiIndex,
715 LocalObject.m_uiSubindex,
716 pData, LocalObject.m_uiSize);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800717
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800718 vfree(pData);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800719
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800720 iRet = (int)EplRet;
721 break;
722 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800723
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800724 case EPLLIN_CMD_READ_OBJECT:
725 {
726 tEplLinSdoObject SdoObject;
727 void *pData;
728 tEplLinSdoBufHeader *pBufHeader;
729 tEplSdoComConHdl *pSdoComConHdl;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800730
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800731 iErr =
732 copy_from_user(&SdoObject, (const void *)ulArg_p,
733 sizeof(SdoObject));
734 if (iErr != 0) {
735 iRet = -EIO;
736 goto Exit;
737 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800738
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800739 if ((SdoObject.m_le_pData == NULL)
740 || (SdoObject.m_uiSize == 0)) {
741 iRet = (int)kEplApiInvalidParam;
742 goto Exit;
743 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800744
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800745 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);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800757
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800758 if (SdoObject.m_fValidSdoComConHdl != FALSE) {
759 pSdoComConHdl = &SdoObject.m_SdoComConHdl;
760 } else {
761 pSdoComConHdl = NULL;
762 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800763
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800764 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);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800771
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800772 // 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 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800784
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800785 if (EplRet == kEplSuccessful) {
786 iErr =
787 copy_to_user(SdoObject.m_le_pData, pData,
788 SdoObject.m_uiSize);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800789
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800790 vfree(pBufHeader);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800791
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800792 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 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800815
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800816 iRet = (int)EplRet;
817 break;
818 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800819
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800820 case EPLLIN_CMD_WRITE_OBJECT:
821 {
822 tEplLinSdoObject SdoObject;
823 void *pData;
824 tEplLinSdoBufHeader *pBufHeader;
825 tEplSdoComConHdl *pSdoComConHdl;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800826
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800827 iErr =
828 copy_from_user(&SdoObject, (const void *)ulArg_p,
829 sizeof(SdoObject));
830 if (iErr != 0) {
831 iRet = -EIO;
832 goto Exit;
833 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800834
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800835 if ((SdoObject.m_le_pData == NULL)
836 || (SdoObject.m_uiSize == 0)) {
837 iRet = (int)kEplApiInvalidParam;
838 goto Exit;
839 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800840
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800841 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);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800853
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800854 iErr =
855 copy_from_user(pData, SdoObject.m_le_pData,
856 SdoObject.m_uiSize);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800857
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800858 if (iErr != 0) {
859 iRet = -EIO;
860 goto Exit;
861 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800862
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800863 if (SdoObject.m_fValidSdoComConHdl != FALSE) {
864 pSdoComConHdl = &SdoObject.m_SdoComConHdl;
865 } else {
866 pSdoComConHdl = NULL;
867 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800868
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800869 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);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800876
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800877 // 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 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800889
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800890 if (EplRet != kEplApiTaskDeferred) { // succeeded or error ocurred, but task not deferred
891 vfree(pBufHeader);
892 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800893
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800894 iRet = (int)EplRet;
895 break;
896 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800897
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800898 // ----------------------------------------------------------
899 case EPLLIN_CMD_FREE_SDO_CHANNEL:
900 {
901 // forward SDO handle to EPL stack
902 EplRet =
903 EplApiFreeSdoChannel((tEplSdoComConHdl) ulArg_p);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800904
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800905 iRet = (int)EplRet;
906 break;
907 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800908
909#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800910 // ----------------------------------------------------------
911 case EPLLIN_CMD_MN_TRIGGER_STATE_CHANGE:
912 {
913 tEplLinNodeCmdObject NodeCmdObject;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800914
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800915 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 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800923
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800924 EplRet =
925 EplApiMnTriggerStateChange(NodeCmdObject.m_uiNodeId,
926 NodeCmdObject.
927 m_NodeCommand);
928 iRet = (int)EplRet;
929 break;
930 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800931#endif
932
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800933 // ----------------------------------------------------------
934 case EPLLIN_CMD_GET_EVENT:
935 {
936 tEplLinEvent Event;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800937
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800938 // 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;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800948
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800949 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);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800961
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800962 // 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;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800998
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800999 pBufHeader =
1000 (tEplLinSdoBufHeader *) pEventArg_g->m_Sdo.
1001 m_pUserArg;
1002 pData =
1003 pBufHeader + sizeof(tEplLinSdoBufHeader);
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001004
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001005 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 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001022
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001023 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;
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001033
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001034 break;
1035 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001036
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001037 // ----------------------------------------------------------
1038 case EPLLIN_CMD_PI_SETUP:
1039 {
1040 EplRet = EplApiProcessImageSetup();
1041 iRet = (int)EplRet;
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001042
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001043 break;
1044 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001045
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001046 // ----------------------------------------------------------
1047 case EPLLIN_CMD_PI_IN:
1048 {
1049 tEplApiProcessImage ProcessImageIn;
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001050
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001051 // 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);
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001062
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001063 // 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);
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001089
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001090 // return to EplApiProcessImageExchangeIn()
1091 iRet = (int)EplRet;
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001092
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001093 break;
1094 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001095
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001096 // ----------------------------------------------------------
1097 case EPLLIN_CMD_PI_OUT:
1098 {
1099 tEplApiProcessImage ProcessImageOut;
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001100
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001101 // 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 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001110
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001111 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);
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001119
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001120 // pass control to sync kernel thread
1121 atomic_set(&AtomicSyncState_g, EVENT_STATE_TERM);
1122 wake_up_interruptible(&WaitQueueCbSync_g);
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001123
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001124 // return to EplApiProcessImageExchangeout()
1125 iRet = (int)EplRet;
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001126
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001127 break;
1128 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001129
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001130 // ----------------------------------------------------------
1131 case EPLLIN_CMD_NMT_COMMAND:
1132 {
1133 // forward NMT command to EPL stack
1134 EplRet = EplApiExecNmtCommand((tEplNmtEvent) ulArg_p);
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001135
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001136 iRet = (int)EplRet;
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001137
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001138 break;
1139 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001140
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001141 // ----------------------------------------------------------
1142 default:
1143 {
1144 break;
1145 }
1146 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001147
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001148 Exit:
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001149
1150// TRACE1("EPL: - EplLinIoctl (iRet=%d)\n", iRet);
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001151 return (iRet);
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001152
1153}
1154
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001155//=========================================================================//
1156// //
1157// P R I V A T E F U N C T I O N S //
1158// //
1159//=========================================================================//
1160
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001161tEplKernel PUBLIC EplLinCbEvent(tEplApiEventType EventType_p, // IN: event type (enum)
1162 tEplApiEventArg * pEventArg_p, // IN: event argument (union)
1163 void GENERIC * pUserArg_p)
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001164{
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001165 tEplKernel EplRet = kEplSuccessful;
1166 int iErr;
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001167
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001168 // 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;
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001188
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001189 // 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);
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001192
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001193 // now, the application's event callback function processes the event
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001194
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001195 // 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;
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001207
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001208 LeaveCriticalSection:
1209 up(&SemaphoreCbEvent_g);
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001210
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001211 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 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001223
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001224 return EplRet;
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001225}
1226
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001227tEplKernel PUBLIC EplLinCbSync(void)
1228{
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001229 tEplKernel EplRet = kEplSuccessful;
1230 int iErr;
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001231
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001232 // 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);
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001237
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001238 // now, the application processes the sync event
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001239
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001240 // 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 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001254
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001255 TGT_DBG_SIGNAL_TRACE_POINT(1);
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001256
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -08001257 return EplRet;
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001258}
1259
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001260// EOF