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