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