Commit | Line | Data |
---|---|---|
9d7164cf DK |
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 | ||
9d7164cf DK |
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 | ||
9d7164cf DK |
105 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) |
106 | // remove ("make invisible") obsolete symbols for kernel versions 2.6 | |
107 | // and higher | |
833dfbe7 GKH |
108 | #define MOD_INC_USE_COUNT |
109 | #define MOD_DEC_USE_COUNT | |
110 | #define EXPORT_NO_SYMBOLS | |
9d7164cf | 111 | #else |
833dfbe7 | 112 | #error "This driver needs a 2.6.x kernel or higher" |
9d7164cf DK |
113 | #endif |
114 | ||
9d7164cf DK |
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 | |
833dfbe7 GKH |
126 | MODULE_AUTHOR("Daniel.Krueger@SYSTEC-electronic.com"); |
127 | MODULE_DESCRIPTION("EPL API driver"); | |
9d7164cf DK |
128 | #endif |
129 | ||
9d7164cf DK |
130 | //--------------------------------------------------------------------------- |
131 | // Configuration | |
132 | //--------------------------------------------------------------------------- | |
133 | ||
833dfbe7 | 134 | #define EPLLIN_DRV_NAME "systec_epl" // used for <register_chrdev> |
9d7164cf DK |
135 | |
136 | //--------------------------------------------------------------------------- | |
137 | // Constant definitions | |
138 | //--------------------------------------------------------------------------- | |
139 | ||
140 | // TracePoint support for realtime-debugging | |
141 | #ifdef _DBG_TRACE_POINTS_ | |
833dfbe7 GKH |
142 | void PUBLIC TgtDbgSignalTracePoint(BYTE bTracePointNumber_p); |
143 | #define TGT_DBG_SIGNAL_TRACE_POINT(p) TgtDbgSignalTracePoint(p) | |
9d7164cf | 144 | #else |
833dfbe7 | 145 | #define TGT_DBG_SIGNAL_TRACE_POINT(p) |
9d7164cf DK |
146 | #endif |
147 | ||
148 | #define EVENT_STATE_INIT 0 | |
833dfbe7 GKH |
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 | |
9d7164cf DK |
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 | ||
9d7164cf DK |
158 | //--------------------------------------------------------------------------- |
159 | // Global variables | |
160 | //--------------------------------------------------------------------------- | |
161 | ||
162 | #ifdef CONFIG_DEVFS_FS | |
163 | ||
164 | // driver major number | |
833dfbe7 | 165 | static int nDrvMajorNumber_g; |
9d7164cf DK |
166 | |
167 | #else | |
168 | ||
169 | // device number (major and minor) | |
833dfbe7 GKH |
170 | static dev_t nDevNum_g; |
171 | static struct cdev *pEpl_cdev_g; | |
9d7164cf DK |
172 | |
173 | #endif | |
174 | ||
9d7164cf DK |
175 | static volatile unsigned int uiEplState_g = EPL_STATE_NOTOPEN; |
176 | ||
833dfbe7 GKH |
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); | |
9d7164cf DK |
188 | |
189 | //--------------------------------------------------------------------------- | |
190 | // Local types | |
191 | //--------------------------------------------------------------------------- | |
192 | ||
833dfbe7 GKH |
193 | typedef struct { |
194 | void *m_pUserArg; | |
195 | void *m_pData; | |
9d7164cf DK |
196 | |
197 | } tEplLinSdoBufHeader; | |
198 | ||
9d7164cf DK |
199 | //--------------------------------------------------------------------------- |
200 | // Local variables | |
201 | //--------------------------------------------------------------------------- | |
202 | ||
9d7164cf DK |
203 | //--------------------------------------------------------------------------- |
204 | // Prototypes of internal functions | |
205 | //--------------------------------------------------------------------------- | |
206 | ||
833dfbe7 GKH |
207 | tEplKernel PUBLIC EplLinCbEvent(tEplApiEventType EventType_p, // IN: event type (enum) |
208 | tEplApiEventArg * pEventArg_p, // IN: event argument (union) | |
209 | void GENERIC * pUserArg_p); | |
9d7164cf DK |
210 | |
211 | tEplKernel PUBLIC EplLinCbSync(void); | |
212 | ||
833dfbe7 GKH |
213 | static int __init EplLinInit(void); |
214 | static void __exit EplLinExit(void); | |
9d7164cf | 215 | |
833dfbe7 GKH |
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); | |
9d7164cf DK |
224 | |
225 | //--------------------------------------------------------------------------- | |
226 | // Kernel Module specific Data Structures | |
227 | //--------------------------------------------------------------------------- | |
228 | ||
229 | EXPORT_NO_SYMBOLS; | |
230 | ||
9d7164cf DK |
231 | module_init(EplLinInit); |
232 | module_exit(EplLinExit); | |
233 | ||
833dfbe7 GKH |
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, | |
9d7164cf DK |
241 | |
242 | }; | |
243 | ||
9d7164cf DK |
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 | ||
833dfbe7 | 256 | static int __init EplLinInit(void) |
9d7164cf DK |
257 | { |
258 | ||
833dfbe7 GKH |
259 | tEplKernel EplRet; |
260 | int iErr; | |
261 | int iRet; | |
9d7164cf | 262 | #ifdef CONFIG_DEVFS_FS |
833dfbe7 | 263 | int nMinorNumber; |
9d7164cf DK |
264 | #endif |
265 | ||
833dfbe7 GKH |
266 | TRACE0("EPL: + EplLinInit...\n"); |
267 | TRACE2("EPL: Driver build: %s / %s\n", __DATE__, __TIME__); | |
9d7164cf | 268 | |
833dfbe7 | 269 | iRet = 0; |
9d7164cf | 270 | |
833dfbe7 GKH |
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); | |
9d7164cf DK |
277 | |
278 | #ifdef CONFIG_DEVFS_FS | |
279 | ||
833dfbe7 GKH |
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 | } | |
9d7164cf DK |
313 | |
314 | #else | |
315 | ||
833dfbe7 GKH |
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 | } | |
9d7164cf DK |
344 | #endif |
345 | ||
833dfbe7 GKH |
346 | // create device node in PROCFS |
347 | EplRet = EplLinProcInit(); | |
348 | if (EplRet != kEplSuccessful) { | |
349 | goto Exit; | |
350 | } | |
9d7164cf | 351 | |
833dfbe7 | 352 | Exit: |
9d7164cf | 353 | |
833dfbe7 GKH |
354 | TRACE1("EPL: - EplLinInit (iRet=%d)\n", iRet); |
355 | return (iRet); | |
9d7164cf DK |
356 | |
357 | } | |
358 | ||
9d7164cf DK |
359 | //--------------------------------------------------------------------------- |
360 | // Remove Driver | |
361 | //--------------------------------------------------------------------------- | |
362 | // -> rmmod driver | |
363 | //--------------------------------------------------------------------------- | |
364 | ||
833dfbe7 | 365 | static void __exit EplLinExit(void) |
9d7164cf DK |
366 | { |
367 | ||
833dfbe7 | 368 | tEplKernel EplRet; |
9d7164cf | 369 | |
833dfbe7 | 370 | // delete instance for all modules |
9d7164cf DK |
371 | // EplRet = EplApiShutdown(); |
372 | // printk("EplApiShutdown(): 0x%X\n", EplRet); | |
373 | ||
833dfbe7 GKH |
374 | // deinitialize proc fs |
375 | EplRet = EplLinProcFree(); | |
376 | printk("EplLinProcFree(): 0x%X\n", EplRet); | |
9d7164cf | 377 | |
833dfbe7 | 378 | TRACE0("EPL: + EplLinExit...\n"); |
9d7164cf DK |
379 | |
380 | #ifdef CONFIG_DEVFS_FS | |
381 | ||
833dfbe7 GKH |
382 | // remove device node from DEVFS |
383 | devfs_remove(EPLLIN_DEV_NAME); | |
384 | TRACE1("EPL: Device node '/dev/%s' removed.\n", EPLLIN_DEV_NAME); | |
9d7164cf | 385 | |
833dfbe7 GKH |
386 | // unregister character device handler |
387 | unregister_chrdev(nDrvMajorNumber_g, EPLLIN_DRV_NAME); | |
9d7164cf DK |
388 | |
389 | #else | |
390 | ||
833dfbe7 GKH |
391 | // remove cdev structure |
392 | cdev_del(pEpl_cdev_g); | |
9d7164cf | 393 | |
833dfbe7 GKH |
394 | // unregister character device handler |
395 | unregister_chrdev_region(nDevNum_g, 1); | |
9d7164cf DK |
396 | |
397 | #endif | |
398 | ||
833dfbe7 | 399 | TRACE1("EPL: Driver '%s' removed.\n", EPLLIN_DRV_NAME); |
9d7164cf | 400 | |
833dfbe7 | 401 | TRACE0("EPL: - EplLinExit\n"); |
9d7164cf DK |
402 | |
403 | } | |
404 | ||
9d7164cf DK |
405 | //--------------------------------------------------------------------------- |
406 | // Open Driver | |
407 | //--------------------------------------------------------------------------- | |
408 | // -> open("/dev/driver", O_RDWR)... | |
409 | //--------------------------------------------------------------------------- | |
410 | ||
833dfbe7 GKH |
411 | static int EplLinOpen(struct inode *pDeviceFile_p, // information about the device to open |
412 | struct file *pInstance_p) // information about driver instance | |
9d7164cf DK |
413 | { |
414 | ||
833dfbe7 | 415 | int iRet; |
9d7164cf | 416 | |
833dfbe7 | 417 | TRACE0("EPL: + EplLinOpen...\n"); |
9d7164cf | 418 | |
833dfbe7 | 419 | MOD_INC_USE_COUNT; |
9d7164cf | 420 | |
833dfbe7 GKH |
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); | |
9d7164cf | 432 | |
833dfbe7 GKH |
433 | uiEplState_g = EPL_STATE_NOTINIT; |
434 | iRet = 0; | |
435 | } | |
9d7164cf | 436 | |
833dfbe7 GKH |
437 | TRACE1("EPL: - EplLinOpen (iRet=%d)\n", iRet); |
438 | return (iRet); | |
9d7164cf DK |
439 | |
440 | } | |
441 | ||
9d7164cf DK |
442 | //--------------------------------------------------------------------------- |
443 | // Close Driver | |
444 | //--------------------------------------------------------------------------- | |
445 | // -> close(device)... | |
446 | //--------------------------------------------------------------------------- | |
447 | ||
833dfbe7 GKH |
448 | static int EplLinRelease(struct inode *pDeviceFile_p, // information about the device to open |
449 | struct file *pInstance_p) // information about driver instance | |
9d7164cf DK |
450 | { |
451 | ||
833dfbe7 GKH |
452 | tEplKernel EplRet = kEplSuccessful; |
453 | int iRet; | |
9d7164cf | 454 | |
833dfbe7 | 455 | TRACE0("EPL: + EplLinRelease...\n"); |
9d7164cf | 456 | |
833dfbe7 GKH |
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); | |
9d7164cf | 462 | |
833dfbe7 GKH |
463 | // pass control to event queue kernel thread |
464 | atomic_set(&AtomicEventState_g, EVENT_STATE_TERM); | |
465 | wake_up_interruptible(&WaitQueueCbEvent_g); | |
9d7164cf | 466 | |
833dfbe7 GKH |
467 | if (uiEplState_g == EPL_STATE_RUNNING) { // post NmtEventSwitchOff |
468 | EplRet = EplApiExecNmtCommand(kEplNmtEventSwitchOff); | |
9d7164cf | 469 | |
833dfbe7 | 470 | } |
9d7164cf | 471 | |
833dfbe7 GKH |
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 | } | |
9d7164cf | 480 | |
833dfbe7 | 481 | // $$$ d.k.: What if waiting was interrupted by signal? |
9d7164cf | 482 | |
833dfbe7 GKH |
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 | } | |
9d7164cf | 489 | |
833dfbe7 GKH |
490 | uiEplState_g = EPL_STATE_NOTOPEN; |
491 | iRet = 0; | |
9d7164cf | 492 | |
833dfbe7 | 493 | MOD_DEC_USE_COUNT; |
9d7164cf | 494 | |
833dfbe7 GKH |
495 | TRACE1("EPL: - EplLinRelease (iRet=%d)\n", iRet); |
496 | return (iRet); | |
9d7164cf DK |
497 | |
498 | } | |
499 | ||
9d7164cf DK |
500 | //--------------------------------------------------------------------------- |
501 | // Read Data from Driver | |
502 | //--------------------------------------------------------------------------- | |
503 | // -> read(...) | |
504 | //--------------------------------------------------------------------------- | |
505 | ||
833dfbe7 GKH |
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 | |
9d7164cf DK |
510 | { |
511 | ||
833dfbe7 | 512 | int iRet; |
9d7164cf | 513 | |
833dfbe7 | 514 | TRACE0("EPL: + EplLinRead...\n"); |
9d7164cf | 515 | |
833dfbe7 GKH |
516 | TRACE0("EPL: Sorry, this operation isn't supported.\n"); |
517 | iRet = -EINVAL; | |
9d7164cf | 518 | |
833dfbe7 GKH |
519 | TRACE1("EPL: - EplLinRead (iRet=%d)\n", iRet); |
520 | return (iRet); | |
9d7164cf DK |
521 | |
522 | } | |
523 | ||
9d7164cf DK |
524 | //--------------------------------------------------------------------------- |
525 | // Write Data to Driver | |
526 | //--------------------------------------------------------------------------- | |
527 | // -> write(...) | |
528 | //--------------------------------------------------------------------------- | |
529 | ||
833dfbe7 GKH |
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 | |
9d7164cf DK |
534 | { |
535 | ||
833dfbe7 | 536 | int iRet; |
9d7164cf | 537 | |
833dfbe7 | 538 | TRACE0("EPL: + EplLinWrite...\n"); |
9d7164cf | 539 | |
833dfbe7 GKH |
540 | TRACE0("EPL: Sorry, this operation isn't supported.\n"); |
541 | iRet = -EINVAL; | |
9d7164cf | 542 | |
833dfbe7 GKH |
543 | TRACE1("EPL: - EplLinWrite (iRet=%d)\n", iRet); |
544 | return (iRet); | |
9d7164cf DK |
545 | |
546 | } | |
547 | ||
9d7164cf DK |
548 | //--------------------------------------------------------------------------- |
549 | // Generic Access to Driver | |
550 | //--------------------------------------------------------------------------- | |
551 | // -> ioctl(...) | |
552 | //--------------------------------------------------------------------------- | |
553 | ||
833dfbe7 GKH |
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 | |
9d7164cf DK |
558 | { |
559 | ||
833dfbe7 GKH |
560 | tEplKernel EplRet; |
561 | int iErr; | |
562 | int iRet; | |
9d7164cf DK |
563 | |
564 | // TRACE1("EPL: + EplLinIoctl (uiIoctlCmd_p=%d)...\n", uiIoctlCmd_p); | |
565 | ||
833dfbe7 GKH |
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 | } | |
9d7164cf DK |
908 | |
909 | #if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0) | |
833dfbe7 GKH |
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 | } | |
9d7164cf DK |
931 | #endif |
932 | ||
833dfbe7 GKH |
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: | |
9d7164cf DK |
1149 | |
1150 | // TRACE1("EPL: - EplLinIoctl (iRet=%d)\n", iRet); | |
833dfbe7 | 1151 | return (iRet); |
9d7164cf DK |
1152 | |
1153 | } | |
1154 | ||
9d7164cf DK |
1155 | //=========================================================================// |
1156 | // // | |
1157 | // P R I V A T E F U N C T I O N S // | |
1158 | // // | |
1159 | //=========================================================================// | |
1160 | ||
833dfbe7 GKH |
1161 | tEplKernel PUBLIC EplLinCbEvent(tEplApiEventType EventType_p, // IN: event type (enum) |
1162 | tEplApiEventArg * pEventArg_p, // IN: event argument (union) | |
1163 | void GENERIC * pUserArg_p) | |
9d7164cf | 1164 | { |
833dfbe7 GKH |
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; | |
9d7164cf DK |
1225 | } |
1226 | ||
9d7164cf DK |
1227 | tEplKernel PUBLIC EplLinCbSync(void) |
1228 | { | |
833dfbe7 GKH |
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; | |
9d7164cf DK |
1258 | } |
1259 | ||
9d7164cf | 1260 | // EOF |