Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
2
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
833dfbe
Documentation
arch
block
crypto
drivers
accessibility
acpi
amba
ata
atm
auxdisplay
base
block
bluetooth
cdrom
char
clocksource
connector
cpufreq
cpuidle
crypto
dca
dio
dma
edac
eisa
firewire
firmware
gpio
gpu
hid
hwmon
i2c
ide
idle
ieee1394
infiniband
input
isdn
leds
lguest
macintosh
mca
md
media
memstick
message
mfd
misc
mmc
mtd
net
nubus
of
oprofile
parisc
parport
pci
pcmcia
pnp
power
ps3
rapidio
regulator
rtc
s390
sbus
scsi
serial
sh
sn
spi
ssb
staging
agnx
altpciechdma
asus_oled
at76_usb
benet
comedi
echo
epl
kernel
user
Benchmark.h
Debug.h
Edrv8139.c
EdrvFec.h
EdrvFec5282.h
EdrvSim.h
Epl.h
EplAmi.h
EplApiGeneric.c
EplApiLinux.h
EplApiLinuxKernel.c
EplApiProcessImage.c
EplCfg.h
EplDef.h
EplDll.h
EplDllCal.h
EplDllk.c
EplDllkCal.c
EplDlluCal.c
EplErrDef.h
EplErrorHandlerk.c
EplEvent.h
EplEventk.c
EplEventu.c
EplFrame.h
EplIdentu.c
EplInc.h
EplInstDef.h
EplLed.h
EplNmt.h
EplNmtCnu.c
EplNmtMnu.c
EplNmtk.c
EplNmtkCal.c
EplNmtu.c
EplNmtuCal.c
EplObd.c
EplObd.h
EplObdMacro.h
EplObdkCal.c
EplObdu.c
EplObduCal.c
EplObjDef.h
EplPdo.h
EplPdok.c
EplPdokCal.c
EplPdou.c
EplSdo.h
EplSdoAc.h
EplSdoAsndu.c
EplSdoAsySequ.c
EplSdoComu.c
EplSdoUdpu.c
EplStatusu.c
EplTarget.h
EplTimer.h
EplTimeruLinuxKernel.c
EplTimeruNull.c
EplTimeruWin32.c
EplVersion.h
Kconfig
Makefile
SharedBuff.c
SharedBuff.h
ShbIpc-LinuxKernel.c
ShbIpc-Win32.c
ShbIpc.h
ShbLinuxKernel.h
SocketLinuxKernel.c
SocketLinuxKernel.h
TimerHighReskX86.c
VirtualEthernetLinux.c
amix86.c
demo_main.c
edrv.h
global.h
proc_fs.c
proc_fs.h
et131x
frontier
go7007
me4000
meilhaus
mimio
otus
panel
poch
rspiusb
rt2860
rt2870
rtl8187se
slicoss
sxg
usbip
winbond
wlan-ng
Kconfig
Makefile
staging.c
tc
telephony
thermal
uio
usb
uwb
video
virtio
w1
watchdog
xen
zorro
Kconfig
Makefile
firmware
fs
include
init
ipc
kernel
lib
mm
net
samples
scripts
security
sound
usr
virt
.gitignore
.mailmap
COPYING
CREDITS
Kbuild
MAINTAINERS
Makefile
README
REPORTING-BUGS
Breadcrumbs
linux
/
drivers
/
staging
/
epl
/
EplApiLinuxKernel.c
Copy path
Blame
Blame
Latest commit
History
History
1260 lines (1024 loc) · 35.7 KB
Breadcrumbs
linux
/
drivers
/
staging
/
epl
/
EplApiLinuxKernel.c
Top
File metadata and controls
Code
Blame
1260 lines (1024 loc) · 35.7 KB
Raw
/**************************************************************************** (c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29 www.systec-electronic.com Project: openPOWERLINK Description: Linux kernel module as wrapper of EPL API layer, i.e. counterpart to a Linux application License: Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of SYSTEC electronic GmbH nor the names of its contributors may be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact info@systec-electronic.com. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Severability Clause: If a provision of this License is or becomes illegal, invalid or unenforceable in any jurisdiction, that shall not affect: 1. the validity or enforceability in that jurisdiction of any other provision of this License; or 2. the validity or enforceability in other jurisdictions of that or any other provision of this License. ------------------------------------------------------------------------- $RCSfile: EplApiLinuxKernel.c,v $ $Author: D.Krueger $ $Revision: 1.9 $ $Date: 2008/11/21 09:00:38 $ $State: Exp $ Build Environment: GNU-Compiler for m68k ------------------------------------------------------------------------- Revision History: 2006/10/11 d.k.: Initial Version 2008/04/10 m.u.: Changed to new char driver init ****************************************************************************/ // kernel modul and driver //#include <linux/version.h> //#include <linux/config.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/types.h> //#include <linux/module.h> //#include <linux/kernel.h> //#include <linux/init.h> //#include <linux/errno.h> // scheduling #include <linux/sched.h> // memory access #include <asm/uaccess.h> #include <linux/vmalloc.h> #ifdef CONFIG_DEVFS_FS #include <linux/major.h> #include <linux/devfs_fs_kernel.h> #endif #include "Epl.h" #include "EplApiLinux.h" //#include "kernel/EplPdokCal.h" #include "proc_fs.h" #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) // remove ("make invisible") obsolete symbols for kernel versions 2.6 // and higher #define MOD_INC_USE_COUNT #define MOD_DEC_USE_COUNT #define EXPORT_NO_SYMBOLS #else #error "This driver needs a 2.6.x kernel or higher" #endif /***************************************************************************/ /* */ /* */ /* G L O B A L D E F I N I T I O N S */ /* */ /* */ /***************************************************************************/ // Metainformation MODULE_LICENSE("Dual BSD/GPL"); #ifdef MODULE_AUTHOR MODULE_AUTHOR("Daniel.Krueger@SYSTEC-electronic.com"); MODULE_DESCRIPTION("EPL API driver"); #endif //--------------------------------------------------------------------------- // Configuration //--------------------------------------------------------------------------- #define EPLLIN_DRV_NAME "systec_epl" // used for <register_chrdev> //--------------------------------------------------------------------------- // Constant definitions //--------------------------------------------------------------------------- // TracePoint support for realtime-debugging #ifdef _DBG_TRACE_POINTS_ void PUBLIC TgtDbgSignalTracePoint(BYTE bTracePointNumber_p); #define TGT_DBG_SIGNAL_TRACE_POINT(p) TgtDbgSignalTracePoint(p) #else #define TGT_DBG_SIGNAL_TRACE_POINT(p) #endif #define EVENT_STATE_INIT 0 #define EVENT_STATE_IOCTL 1 // ioctl entered and ready to receive EPL event #define EVENT_STATE_READY 2 // EPL event can be forwarded to user application #define EVENT_STATE_TERM 3 // terminate processing #define EPL_STATE_NOTOPEN 0 #define EPL_STATE_NOTINIT 1 #define EPL_STATE_RUNNING 2 #define EPL_STATE_SHUTDOWN 3 //--------------------------------------------------------------------------- // Global variables //--------------------------------------------------------------------------- #ifdef CONFIG_DEVFS_FS // driver major number static int nDrvMajorNumber_g; #else // device number (major and minor) static dev_t nDevNum_g; static struct cdev *pEpl_cdev_g; #endif static volatile unsigned int uiEplState_g = EPL_STATE_NOTOPEN; static struct semaphore SemaphoreCbEvent_g; // semaphore for EplLinCbEvent static wait_queue_head_t WaitQueueCbEvent_g; // wait queue EplLinCbEvent static wait_queue_head_t WaitQueueProcess_g; // wait queue for EplApiProcess (user process) static wait_queue_head_t WaitQueueRelease_g; // wait queue for EplLinRelease static atomic_t AtomicEventState_g = ATOMIC_INIT(EVENT_STATE_INIT); static tEplApiEventType EventType_g; // event type (enum) static tEplApiEventArg *pEventArg_g; // event argument (union) static tEplKernel RetCbEvent_g; // return code from event callback function static wait_queue_head_t WaitQueueCbSync_g; // wait queue EplLinCbSync static wait_queue_head_t WaitQueuePI_In_g; // wait queue for EplApiProcessImageExchangeIn (user process) static atomic_t AtomicSyncState_g = ATOMIC_INIT(EVENT_STATE_INIT); //--------------------------------------------------------------------------- // Local types //--------------------------------------------------------------------------- typedef struct { void *m_pUserArg; void *m_pData; } tEplLinSdoBufHeader; //--------------------------------------------------------------------------- // Local variables //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- // Prototypes of internal functions //--------------------------------------------------------------------------- tEplKernel PUBLIC EplLinCbEvent(tEplApiEventType EventType_p, // IN: event type (enum) tEplApiEventArg * pEventArg_p, // IN: event argument (union) void GENERIC * pUserArg_p); tEplKernel PUBLIC EplLinCbSync(void); static int __init EplLinInit(void); static void __exit EplLinExit(void); static int EplLinOpen(struct inode *pDeviceFile_p, struct file *pInstance_p); static int EplLinRelease(struct inode *pDeviceFile_p, struct file *pInstance_p); static ssize_t EplLinRead(struct file *pInstance_p, char *pDstBuff_p, size_t BuffSize_p, loff_t * pFileOffs_p); static ssize_t EplLinWrite(struct file *pInstance_p, const char *pSrcBuff_p, size_t BuffSize_p, loff_t * pFileOffs_p); static int EplLinIoctl(struct inode *pDeviceFile_p, struct file *pInstance_p, unsigned int uiIoctlCmd_p, unsigned long ulArg_p); //--------------------------------------------------------------------------- // Kernel Module specific Data Structures //--------------------------------------------------------------------------- EXPORT_NO_SYMBOLS; module_init(EplLinInit); module_exit(EplLinExit); static struct file_operations EplLinFileOps_g = { .owner = THIS_MODULE, .open = EplLinOpen, .release = EplLinRelease, .read = EplLinRead, .write = EplLinWrite, .ioctl = EplLinIoctl, }; //=========================================================================// // // // P U B L I C F U N C T I O N S // // // //=========================================================================// //--------------------------------------------------------------------------- // Initailize Driver //--------------------------------------------------------------------------- // -> insmod driver //--------------------------------------------------------------------------- static int __init EplLinInit(void) { tEplKernel EplRet; int iErr; int iRet; #ifdef CONFIG_DEVFS_FS int nMinorNumber; #endif TRACE0("EPL: + EplLinInit...\n"); TRACE2("EPL: Driver build: %s / %s\n", __DATE__, __TIME__); iRet = 0; // initialize global variables atomic_set(&AtomicEventState_g, EVENT_STATE_INIT); sema_init(&SemaphoreCbEvent_g, 1); init_waitqueue_head(&WaitQueueCbEvent_g); init_waitqueue_head(&WaitQueueProcess_g); init_waitqueue_head(&WaitQueueRelease_g); #ifdef CONFIG_DEVFS_FS // register character device handler TRACE2("EPL: Installing Driver '%s', Version %s...\n", EPLLIN_DRV_NAME, EPL_PRODUCT_VERSION); TRACE0("EPL: (using dynamic major number assignment)\n"); nDrvMajorNumber_g = register_chrdev(0, EPLLIN_DRV_NAME, &EplLinFileOps_g); if (nDrvMajorNumber_g != 0) { TRACE2 ("EPL: Driver '%s' installed successful, assigned MajorNumber=%d\n", EPLLIN_DRV_NAME, nDrvMajorNumber_g); } else { TRACE1 ("EPL: ERROR: Driver '%s' is unable to get a free MajorNumber!\n", EPLLIN_DRV_NAME); iRet = -EIO; goto Exit; } // create device node in DEVFS nMinorNumber = 0; TRACE1("EPL: Creating device node '/dev/%s'...\n", EPLLIN_DEV_NAME); iErr = devfs_mk_cdev(MKDEV(nDrvMajorNumber_g, nMinorNumber), S_IFCHR | S_IRUGO | S_IWUGO, EPLLIN_DEV_NAME); if (iErr == 0) { TRACE1("EPL: Device node '/dev/%s' created successful.\n", EPLLIN_DEV_NAME); } else { TRACE1("EPL: ERROR: unable to create device node '/dev/%s'\n", EPLLIN_DEV_NAME); iRet = -EIO; goto Exit; } #else // register character device handler // only one Minor required TRACE2("EPL: Installing Driver '%s', Version %s...\n", EPLLIN_DRV_NAME, EPL_PRODUCT_VERSION); iRet = alloc_chrdev_region(&nDevNum_g, 0, 1, EPLLIN_DRV_NAME); if (iRet == 0) { TRACE2 ("EPL: Driver '%s' installed successful, assigned MajorNumber=%d\n", EPLLIN_DRV_NAME, MAJOR(nDevNum_g)); } else { TRACE1 ("EPL: ERROR: Driver '%s' is unable to get a free MajorNumber!\n", EPLLIN_DRV_NAME); iRet = -EIO; goto Exit; } // register cdev structure pEpl_cdev_g = cdev_alloc(); pEpl_cdev_g->ops = &EplLinFileOps_g; pEpl_cdev_g->owner = THIS_MODULE; iErr = cdev_add(pEpl_cdev_g, nDevNum_g, 1); if (iErr) { TRACE2("EPL: ERROR %d: Driver '%s' could not be added!\n", iErr, EPLLIN_DRV_NAME); iRet = -EIO; goto Exit; } #endif // create device node in PROCFS EplRet = EplLinProcInit(); if (EplRet != kEplSuccessful) { goto Exit; } Exit: TRACE1("EPL: - EplLinInit (iRet=%d)\n", iRet); return (iRet); } //--------------------------------------------------------------------------- // Remove Driver //--------------------------------------------------------------------------- // -> rmmod driver //--------------------------------------------------------------------------- static void __exit EplLinExit(void) { tEplKernel EplRet; // delete instance for all modules // EplRet = EplApiShutdown(); // printk("EplApiShutdown(): 0x%X\n", EplRet); // deinitialize proc fs EplRet = EplLinProcFree(); printk("EplLinProcFree(): 0x%X\n", EplRet); TRACE0("EPL: + EplLinExit...\n"); #ifdef CONFIG_DEVFS_FS // remove device node from DEVFS devfs_remove(EPLLIN_DEV_NAME); TRACE1("EPL: Device node '/dev/%s' removed.\n", EPLLIN_DEV_NAME); // unregister character device handler unregister_chrdev(nDrvMajorNumber_g, EPLLIN_DRV_NAME); #else // remove cdev structure cdev_del(pEpl_cdev_g); // unregister character device handler unregister_chrdev_region(nDevNum_g, 1); #endif TRACE1("EPL: Driver '%s' removed.\n", EPLLIN_DRV_NAME); TRACE0("EPL: - EplLinExit\n"); } //--------------------------------------------------------------------------- // Open Driver //--------------------------------------------------------------------------- // -> open("/dev/driver", O_RDWR)... //--------------------------------------------------------------------------- static int EplLinOpen(struct inode *pDeviceFile_p, // information about the device to open struct file *pInstance_p) // information about driver instance { int iRet; TRACE0("EPL: + EplLinOpen...\n"); MOD_INC_USE_COUNT; if (uiEplState_g != EPL_STATE_NOTOPEN) { // stack already initialized iRet = -EALREADY; } else { atomic_set(&AtomicEventState_g, EVENT_STATE_INIT); sema_init(&SemaphoreCbEvent_g, 1); init_waitqueue_head(&WaitQueueCbEvent_g); init_waitqueue_head(&WaitQueueProcess_g); init_waitqueue_head(&WaitQueueRelease_g); atomic_set(&AtomicSyncState_g, EVENT_STATE_INIT); init_waitqueue_head(&WaitQueueCbSync_g); init_waitqueue_head(&WaitQueuePI_In_g); uiEplState_g = EPL_STATE_NOTINIT; iRet = 0; } TRACE1("EPL: - EplLinOpen (iRet=%d)\n", iRet); return (iRet); } //--------------------------------------------------------------------------- // Close Driver //--------------------------------------------------------------------------- // -> close(device)... //--------------------------------------------------------------------------- static int EplLinRelease(struct inode *pDeviceFile_p, // information about the device to open struct file *pInstance_p) // information about driver instance { tEplKernel EplRet = kEplSuccessful; int iRet; TRACE0("EPL: + EplLinRelease...\n"); if (uiEplState_g != EPL_STATE_NOTINIT) { // pass control to sync kernel thread, but signal termination atomic_set(&AtomicSyncState_g, EVENT_STATE_TERM); wake_up_interruptible(&WaitQueueCbSync_g); wake_up_interruptible(&WaitQueuePI_In_g); // pass control to event queue kernel thread atomic_set(&AtomicEventState_g, EVENT_STATE_TERM); wake_up_interruptible(&WaitQueueCbEvent_g); if (uiEplState_g == EPL_STATE_RUNNING) { // post NmtEventSwitchOff EplRet = EplApiExecNmtCommand(kEplNmtEventSwitchOff); } if (EplRet == kEplSuccessful) { TRACE0("EPL: waiting for NMT_GS_OFF\n"); wait_event_interruptible(WaitQueueRelease_g, (uiEplState_g == EPL_STATE_SHUTDOWN)); } else { // post NmtEventSwitchOff failed TRACE0("EPL: event post failed\n"); } // $$$ d.k.: What if waiting was interrupted by signal? TRACE0("EPL: call EplApiShutdown()\n"); // EPL stack can be safely shut down // delete instance for all EPL modules EplRet = EplApiShutdown(); printk("EplApiShutdown(): 0x%X\n", EplRet); } uiEplState_g = EPL_STATE_NOTOPEN; iRet = 0; MOD_DEC_USE_COUNT; TRACE1("EPL: - EplLinRelease (iRet=%d)\n", iRet); return (iRet); } //--------------------------------------------------------------------------- // Read Data from Driver //--------------------------------------------------------------------------- // -> read(...) //--------------------------------------------------------------------------- static ssize_t EplLinRead(struct file *pInstance_p, // information about driver instance char *pDstBuff_p, // address of buffer to fill with data size_t BuffSize_p, // length of the buffer loff_t * pFileOffs_p) // offset in the file { int iRet; TRACE0("EPL: + EplLinRead...\n"); TRACE0("EPL: Sorry, this operation isn't supported.\n"); iRet = -EINVAL; TRACE1("EPL: - EplLinRead (iRet=%d)\n", iRet); return (iRet); } //--------------------------------------------------------------------------- // Write Data to Driver //--------------------------------------------------------------------------- // -> write(...) //--------------------------------------------------------------------------- static ssize_t EplLinWrite(struct file *pInstance_p, // information about driver instance const char *pSrcBuff_p, // address of buffer to get data from size_t BuffSize_p, // length of the buffer loff_t * pFileOffs_p) // offset in the file { int iRet; TRACE0("EPL: + EplLinWrite...\n"); TRACE0("EPL: Sorry, this operation isn't supported.\n"); iRet = -EINVAL; TRACE1("EPL: - EplLinWrite (iRet=%d)\n", iRet); return (iRet); } //--------------------------------------------------------------------------- // Generic Access to Driver //--------------------------------------------------------------------------- // -> ioctl(...) //--------------------------------------------------------------------------- static int EplLinIoctl(struct inode *pDeviceFile_p, // information about the device to open struct file *pInstance_p, // information about driver instance unsigned int uiIoctlCmd_p, // Ioctl command to execute unsigned long ulArg_p) // Ioctl command specific argument/parameter { tEplKernel EplRet; int iErr; int iRet; // TRACE1("EPL: + EplLinIoctl (uiIoctlCmd_p=%d)...\n", uiIoctlCmd_p); iRet = -EINVAL; switch (uiIoctlCmd_p) { // ---------------------------------------------------------- case EPLLIN_CMD_INITIALIZE: { tEplApiInitParam EplApiInitParam; iErr = copy_from_user(&EplApiInitParam, (const void *)ulArg_p, sizeof(EplApiInitParam)); if (iErr != 0) { iRet = -EIO; goto Exit; } EplApiInitParam.m_pfnCbEvent = EplLinCbEvent; EplApiInitParam.m_pfnCbSync = EplLinCbSync; EplRet = EplApiInitialize(&EplApiInitParam); uiEplState_g = EPL_STATE_RUNNING; iRet = (int)EplRet; break; } // ---------------------------------------------------------- case EPLLIN_CMD_SHUTDOWN: { // shutdown the threads // pass control to sync kernel thread, but signal termination atomic_set(&AtomicSyncState_g, EVENT_STATE_TERM); wake_up_interruptible(&WaitQueueCbSync_g); wake_up_interruptible(&WaitQueuePI_In_g); // pass control to event queue kernel thread atomic_set(&AtomicEventState_g, EVENT_STATE_TERM); wake_up_interruptible(&WaitQueueCbEvent_g); if (uiEplState_g == EPL_STATE_RUNNING) { // post NmtEventSwitchOff EplRet = EplApiExecNmtCommand(kEplNmtEventSwitchOff); } iRet = 0; break; } // ---------------------------------------------------------- case EPLLIN_CMD_READ_LOCAL_OBJECT: { tEplLinLocalObject LocalObject; void *pData; iErr = copy_from_user(&LocalObject, (const void *)ulArg_p, sizeof(LocalObject)); if (iErr != 0) { iRet = -EIO; goto Exit; } if ((LocalObject.m_pData == NULL) || (LocalObject.m_uiSize == 0)) { iRet = (int)kEplApiInvalidParam; goto Exit; } pData = vmalloc(LocalObject.m_uiSize); if (pData == NULL) { // no memory available iRet = -ENOMEM; goto Exit; } EplRet = EplApiReadLocalObject(LocalObject.m_uiIndex, LocalObject.m_uiSubindex, pData, &LocalObject.m_uiSize); if (EplRet == kEplSuccessful) { iErr = copy_to_user(LocalObject.m_pData, pData, LocalObject.m_uiSize); vfree(pData); if (iErr != 0) { iRet = -EIO; goto Exit; } // return actual size (LocalObject.m_uiSize) iErr = put_user(LocalObject.m_uiSize, (unsigned int *)(ulArg_p + (unsigned long) &LocalObject. m_uiSize - (unsigned long) &LocalObject)); if (iErr != 0) { iRet = -EIO; goto Exit; } } else { vfree(pData); } iRet = (int)EplRet; break; } // ---------------------------------------------------------- case EPLLIN_CMD_WRITE_LOCAL_OBJECT: { tEplLinLocalObject LocalObject; void *pData; iErr = copy_from_user(&LocalObject, (const void *)ulArg_p, sizeof(LocalObject)); if (iErr != 0) { iRet = -EIO; goto Exit; } if ((LocalObject.m_pData == NULL) || (LocalObject.m_uiSize == 0)) { iRet = (int)kEplApiInvalidParam; goto Exit; } pData = vmalloc(LocalObject.m_uiSize); if (pData == NULL) { // no memory available iRet = -ENOMEM; goto Exit; } iErr = copy_from_user(pData, LocalObject.m_pData, LocalObject.m_uiSize); if (iErr != 0) { iRet = -EIO; goto Exit; } EplRet = EplApiWriteLocalObject(LocalObject.m_uiIndex, LocalObject.m_uiSubindex, pData, LocalObject.m_uiSize); vfree(pData); iRet = (int)EplRet; break; } case EPLLIN_CMD_READ_OBJECT: { tEplLinSdoObject SdoObject; void *pData; tEplLinSdoBufHeader *pBufHeader; tEplSdoComConHdl *pSdoComConHdl; iErr = copy_from_user(&SdoObject, (const void *)ulArg_p, sizeof(SdoObject)); if (iErr != 0) { iRet = -EIO; goto Exit; } if ((SdoObject.m_le_pData == NULL) || (SdoObject.m_uiSize == 0)) { iRet = (int)kEplApiInvalidParam; goto Exit; } pBufHeader = (tEplLinSdoBufHeader *) vmalloc(sizeof(tEplLinSdoBufHeader) + SdoObject.m_uiSize); if (pBufHeader == NULL) { // no memory available iRet = -ENOMEM; goto Exit; } // initiate temporary buffer pBufHeader->m_pUserArg = SdoObject.m_pUserArg; // original user argument pointer pBufHeader->m_pData = SdoObject.m_le_pData; // original data pointer from app pData = pBufHeader + sizeof(tEplLinSdoBufHeader); if (SdoObject.m_fValidSdoComConHdl != FALSE) { pSdoComConHdl = &SdoObject.m_SdoComConHdl; } else { pSdoComConHdl = NULL; } EplRet = EplApiReadObject(pSdoComConHdl, SdoObject.m_uiNodeId, SdoObject.m_uiIndex, SdoObject.m_uiSubindex, pData, &SdoObject.m_uiSize, SdoObject.m_SdoType, pBufHeader); // return actual SDO handle (SdoObject.m_SdoComConHdl) iErr = put_user(SdoObject.m_SdoComConHdl, (unsigned int *)(ulArg_p + (unsigned long) &SdoObject. m_SdoComConHdl - (unsigned long) &SdoObject)); if (iErr != 0) { iRet = -EIO; goto Exit; } if (EplRet == kEplSuccessful) { iErr = copy_to_user(SdoObject.m_le_pData, pData, SdoObject.m_uiSize); vfree(pBufHeader); if (iErr != 0) { iRet = -EIO; goto Exit; } // return actual size (SdoObject.m_uiSize) iErr = put_user(SdoObject.m_uiSize, (unsigned int *)(ulArg_p + (unsigned long) &SdoObject. m_uiSize - (unsigned long) &SdoObject)); if (iErr != 0) { iRet = -EIO; goto Exit; } } else if (EplRet != kEplApiTaskDeferred) { // error ocurred vfree(pBufHeader); if (iErr != 0) { iRet = -EIO; goto Exit; } } iRet = (int)EplRet; break; } case EPLLIN_CMD_WRITE_OBJECT: { tEplLinSdoObject SdoObject; void *pData; tEplLinSdoBufHeader *pBufHeader; tEplSdoComConHdl *pSdoComConHdl; iErr = copy_from_user(&SdoObject, (const void *)ulArg_p, sizeof(SdoObject)); if (iErr != 0) { iRet = -EIO; goto Exit; } if ((SdoObject.m_le_pData == NULL) || (SdoObject.m_uiSize == 0)) { iRet = (int)kEplApiInvalidParam; goto Exit; } pBufHeader = (tEplLinSdoBufHeader *) vmalloc(sizeof(tEplLinSdoBufHeader) + SdoObject.m_uiSize); if (pBufHeader == NULL) { // no memory available iRet = -ENOMEM; goto Exit; } // initiate temporary buffer pBufHeader->m_pUserArg = SdoObject.m_pUserArg; // original user argument pointer pBufHeader->m_pData = SdoObject.m_le_pData; // original data pointer from app pData = pBufHeader + sizeof(tEplLinSdoBufHeader); iErr = copy_from_user(pData, SdoObject.m_le_pData, SdoObject.m_uiSize); if (iErr != 0) { iRet = -EIO; goto Exit; } if (SdoObject.m_fValidSdoComConHdl != FALSE) { pSdoComConHdl = &SdoObject.m_SdoComConHdl; } else { pSdoComConHdl = NULL; } EplRet = EplApiWriteObject(pSdoComConHdl, SdoObject.m_uiNodeId, SdoObject.m_uiIndex, SdoObject.m_uiSubindex, pData, SdoObject.m_uiSize, SdoObject.m_SdoType, pBufHeader); // return actual SDO handle (SdoObject.m_SdoComConHdl) iErr = put_user(SdoObject.m_SdoComConHdl, (unsigned int *)(ulArg_p + (unsigned long) &SdoObject. m_SdoComConHdl - (unsigned long) &SdoObject)); if (iErr != 0) { iRet = -EIO; goto Exit; } if (EplRet != kEplApiTaskDeferred) { // succeeded or error ocurred, but task not deferred vfree(pBufHeader); } iRet = (int)EplRet; break; } // ---------------------------------------------------------- case EPLLIN_CMD_FREE_SDO_CHANNEL: { // forward SDO handle to EPL stack EplRet = EplApiFreeSdoChannel((tEplSdoComConHdl) ulArg_p); iRet = (int)EplRet; break; } #if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0) // ---------------------------------------------------------- case EPLLIN_CMD_MN_TRIGGER_STATE_CHANGE: { tEplLinNodeCmdObject NodeCmdObject; iErr = copy_from_user(&NodeCmdObject, (const void *)ulArg_p, sizeof(NodeCmdObject)); if (iErr != 0) { iRet = -EIO; goto Exit; } EplRet = EplApiMnTriggerStateChange(NodeCmdObject.m_uiNodeId, NodeCmdObject. m_NodeCommand); iRet = (int)EplRet; break; } #endif // ---------------------------------------------------------- case EPLLIN_CMD_GET_EVENT: { tEplLinEvent Event; // save event structure iErr = copy_from_user(&Event, (const void *)ulArg_p, sizeof(Event)); if (iErr != 0) { iRet = -EIO; goto Exit; } // save return code from application's event callback function RetCbEvent_g = Event.m_RetCbEvent; if (RetCbEvent_g == kEplShutdown) { // pass control to event queue kernel thread, but signal termination atomic_set(&AtomicEventState_g, EVENT_STATE_TERM); wake_up_interruptible(&WaitQueueCbEvent_g); // exit with error -> EplApiProcess() will leave the infinite loop iRet = 1; goto Exit; } // pass control to event queue kernel thread atomic_set(&AtomicEventState_g, EVENT_STATE_IOCTL); wake_up_interruptible(&WaitQueueCbEvent_g); // fall asleep itself in own wait queue iErr = wait_event_interruptible(WaitQueueProcess_g, (atomic_read (&AtomicEventState_g) == EVENT_STATE_READY) || (atomic_read (&AtomicEventState_g) == EVENT_STATE_TERM)); if (iErr != 0) { // waiting was interrupted by signal // pass control to event queue kernel thread, but signal termination atomic_set(&AtomicEventState_g, EVENT_STATE_TERM); wake_up_interruptible(&WaitQueueCbEvent_g); // exit with this error -> EplApiProcess() will leave the infinite loop iRet = iErr; goto Exit; } else if (atomic_read(&AtomicEventState_g) == EVENT_STATE_TERM) { // termination in progress // pass control to event queue kernel thread, but signal termination wake_up_interruptible(&WaitQueueCbEvent_g); // exit with this error -> EplApiProcess() will leave the infinite loop iRet = 1; goto Exit; } // copy event to user space iErr = copy_to_user(Event.m_pEventType, &EventType_g, sizeof(EventType_g)); if (iErr != 0) { // not all data could be copied iRet = -EIO; goto Exit; } // $$$ d.k. perform SDO event processing if (EventType_g == kEplApiEventSdo) { void *pData; tEplLinSdoBufHeader *pBufHeader; pBufHeader = (tEplLinSdoBufHeader *) pEventArg_g->m_Sdo. m_pUserArg; pData = pBufHeader + sizeof(tEplLinSdoBufHeader); if (pEventArg_g->m_Sdo.m_SdoAccessType == kEplSdoAccessTypeRead) { // copy read data to user space iErr = copy_to_user(pBufHeader->m_pData, pData, pEventArg_g->m_Sdo. m_uiTransferredByte); if (iErr != 0) { // not all data could be copied iRet = -EIO; goto Exit; } } pEventArg_g->m_Sdo.m_pUserArg = pBufHeader->m_pUserArg; vfree(pBufHeader); } iErr = copy_to_user(Event.m_pEventArg, pEventArg_g, min(sizeof(tEplApiEventArg), Event.m_uiEventArgSize)); if (iErr != 0) { // not all data could be copied iRet = -EIO; goto Exit; } // return to EplApiProcess(), which will call the application's event callback function iRet = 0; break; } // ---------------------------------------------------------- case EPLLIN_CMD_PI_SETUP: { EplRet = EplApiProcessImageSetup(); iRet = (int)EplRet; break; } // ---------------------------------------------------------- case EPLLIN_CMD_PI_IN: { tEplApiProcessImage ProcessImageIn; // save process image structure iErr = copy_from_user(&ProcessImageIn, (const void *)ulArg_p, sizeof(ProcessImageIn)); if (iErr != 0) { iRet = -EIO; goto Exit; } // pass control to event queue kernel thread atomic_set(&AtomicSyncState_g, EVENT_STATE_IOCTL); // fall asleep itself in own wait queue iErr = wait_event_interruptible(WaitQueuePI_In_g, (atomic_read (&AtomicSyncState_g) == EVENT_STATE_READY) || (atomic_read (&AtomicSyncState_g) == EVENT_STATE_TERM)); if (iErr != 0) { // waiting was interrupted by signal // pass control to sync kernel thread, but signal termination atomic_set(&AtomicSyncState_g, EVENT_STATE_TERM); wake_up_interruptible(&WaitQueueCbSync_g); // exit with this error -> application will leave the infinite loop iRet = iErr; goto Exit; } else if (atomic_read(&AtomicSyncState_g) == EVENT_STATE_TERM) { // termination in progress // pass control to sync kernel thread, but signal termination wake_up_interruptible(&WaitQueueCbSync_g); // exit with this error -> application will leave the infinite loop iRet = 1; goto Exit; } // exchange process image EplRet = EplApiProcessImageExchangeIn(&ProcessImageIn); // return to EplApiProcessImageExchangeIn() iRet = (int)EplRet; break; } // ---------------------------------------------------------- case EPLLIN_CMD_PI_OUT: { tEplApiProcessImage ProcessImageOut; // save process image structure iErr = copy_from_user(&ProcessImageOut, (const void *)ulArg_p, sizeof(ProcessImageOut)); if (iErr != 0) { iRet = -EIO; goto Exit; } if (atomic_read(&AtomicSyncState_g) != EVENT_STATE_READY) { iRet = (int)kEplInvalidOperation; goto Exit; } // exchange process image EplRet = EplApiProcessImageExchangeOut(&ProcessImageOut); // pass control to sync kernel thread atomic_set(&AtomicSyncState_g, EVENT_STATE_TERM); wake_up_interruptible(&WaitQueueCbSync_g); // return to EplApiProcessImageExchangeout() iRet = (int)EplRet; break; } // ---------------------------------------------------------- case EPLLIN_CMD_NMT_COMMAND: { // forward NMT command to EPL stack EplRet = EplApiExecNmtCommand((tEplNmtEvent) ulArg_p); iRet = (int)EplRet; break; } // ---------------------------------------------------------- default: { break; } } Exit: // TRACE1("EPL: - EplLinIoctl (iRet=%d)\n", iRet); return (iRet); } //=========================================================================// // // // P R I V A T E F U N C T I O N S // // // //=========================================================================// tEplKernel PUBLIC EplLinCbEvent(tEplApiEventType EventType_p, // IN: event type (enum) tEplApiEventArg * pEventArg_p, // IN: event argument (union) void GENERIC * pUserArg_p) { tEplKernel EplRet = kEplSuccessful; int iErr; // block any further call to this function, i.e. enter critical section iErr = down_interruptible(&SemaphoreCbEvent_g); if (iErr != 0) { // waiting was interrupted by signal EplRet = kEplShutdown; goto Exit; } // wait for EplApiProcess() to call ioctl // normally it should be waiting already for us to pass a new event iErr = wait_event_interruptible(WaitQueueCbEvent_g, (atomic_read(&AtomicEventState_g) == EVENT_STATE_IOCTL) || (atomic_read(&AtomicEventState_g) == EVENT_STATE_TERM)); if ((iErr != 0) || (atomic_read(&AtomicEventState_g) == EVENT_STATE_TERM)) { // waiting was interrupted by signal EplRet = kEplShutdown; goto LeaveCriticalSection; } // save event information for ioctl EventType_g = EventType_p; pEventArg_g = pEventArg_p; // pass control to application's event callback function, i.e. EplApiProcess() atomic_set(&AtomicEventState_g, EVENT_STATE_READY); wake_up_interruptible(&WaitQueueProcess_g); // now, the application's event callback function processes the event // wait for completion of application's event callback function, i.e. EplApiProcess() calls ioctl again iErr = wait_event_interruptible(WaitQueueCbEvent_g, (atomic_read(&AtomicEventState_g) == EVENT_STATE_IOCTL) || (atomic_read(&AtomicEventState_g) == EVENT_STATE_TERM)); if ((iErr != 0) || (atomic_read(&AtomicEventState_g) == EVENT_STATE_TERM)) { // waiting was interrupted by signal EplRet = kEplShutdown; goto LeaveCriticalSection; } // read return code from application's event callback function EplRet = RetCbEvent_g; LeaveCriticalSection: up(&SemaphoreCbEvent_g); Exit: // check if NMT_GS_OFF is reached if (EventType_p == kEplApiEventNmtStateChange) { if (pEventArg_p->m_NmtStateChange.m_NewNmtState == kEplNmtGsOff) { // NMT state machine was shut down TRACE0("EPL: EplLinCbEvent(NMT_GS_OFF)\n"); uiEplState_g = EPL_STATE_SHUTDOWN; atomic_set(&AtomicEventState_g, EVENT_STATE_TERM); wake_up(&WaitQueueRelease_g); } else { // NMT state machine is running uiEplState_g = EPL_STATE_RUNNING; } } return EplRet; } tEplKernel PUBLIC EplLinCbSync(void) { tEplKernel EplRet = kEplSuccessful; int iErr; // check if user process waits for sync if (atomic_read(&AtomicSyncState_g) == EVENT_STATE_IOCTL) { // pass control to application, i.e. EplApiProcessImageExchangeIn() atomic_set(&AtomicSyncState_g, EVENT_STATE_READY); wake_up_interruptible(&WaitQueuePI_In_g); // now, the application processes the sync event // wait for call of EplApiProcessImageExchangeOut() iErr = wait_event_interruptible(WaitQueueCbSync_g, (atomic_read(&AtomicSyncState_g) == EVENT_STATE_IOCTL) || (atomic_read(&AtomicSyncState_g) == EVENT_STATE_TERM)); if ((iErr != 0) || (atomic_read(&AtomicEventState_g) == EVENT_STATE_IOCTL)) { // waiting was interrupted by signal or application called wrong function EplRet = kEplShutdown; } } else { // application is currently not waiting for sync // continue without interruption // TPDO are set valid by caller (i.e. EplEventkProcess()) } TGT_DBG_SIGNAL_TRACE_POINT(1); return EplRet; } // EOF
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
You can’t perform that action at this time.