--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rtdm/module.c Thu May 12 16:45:02 2011 +0200
@@ -0,0 +1,795 @@
+/******************************************************************************
+ *
+ * $Id$
+ *
+ * ec_rtdm.c Copyright (C) 2009-2010 Moehwald GmbH B.Benner
+ * 2011 IgH Andreas Stewering-Bone
+ *
+ *
+ * This file is part of the IgH EtherCAT master
+ *
+ * The IgH EtherCAT master is free software; you can
+ * redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation; version 2.1
+ * of the License.
+ *
+ * The IgH EtherCAT master userspace library is distributed in the hope that
+ * it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the IgH EtherCAT master userspace library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * The license mentioned above concerns the source code only. Using the
+ * EtherCAT technology and brand is only permitted in compliance with the
+ * industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ *****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/mman.h>
+
+
+#ifdef ENABLE_XENOMAI
+#include <native/task.h>
+#include <native/sem.h>
+#include <native/mutex.h>
+#include <native/timer.h>
+#endif
+
+#ifdef ENABLE_RTAI
+#include <rtai_sched.h>
+#include <rtai_sem.h>
+#endif
+
+
+#include <rtdm/rtdm_driver.h>
+
+#include "../include/ecrt.h"
+#include "../include/ec_rtdm.h"
+
+#ifdef ENABLE_XENOMAI
+#define my_mutex_create(X,Y) rt_mutex_create(X, Y)
+#define my_mutex_acquire(X,Y) rt_mutex_acquire(X,Y)
+#define my_mutex_release(X) rt_mutex_release(X)
+#define my_mutex_delete(X) rt_mutex_delete(X)
+#endif
+
+#ifdef ENABLE_RTAI
+#define my_mutex_create(X,Y) rt_sem_init(X, 1)
+#define my_mutex_acquire(X,Y) rt_sem_wait(X)
+#define my_mutex_release(X) rt_sem_signal(X)
+#define my_mutex_delete(X) rt_sem_delete(X)
+#define TM_INFINITE
+#endif
+
+
+
+
+#define EC_RTDM_MAX_MASTERS 5 /**< Maximum number of masters. */
+
+#define EC_RTDM_GINFO(fmt, args...) \
+ rtdm_printk(KERN_INFO "EtherCATrtdm: " fmt, ##args)
+
+#define EC_RTDM_GERR(fmt, args...) \
+ rtdm_printk(KERN_ERR "EtherCATrtdm ERROR: " fmt, ##args)
+
+#define EC_RTDM_GWARN(fmt, args...) \
+ rtdm_printk(KERN_WARNING "EtherCATrtdm WARNING: " fmt, ##args)
+
+
+#define EC_RTDM_INFO(devno, fmt, args...) \
+ rtdm_printk(KERN_INFO "EtherCATrtdm %u: " fmt, devno, ##args)
+
+#define EC_RTDM_ERR(devno, fmt, args...) \
+ rtdm_printk(KERN_ERR "EtherCATrtdm %u ERROR: " fmt, devno, ##args)
+
+#define EC_RTDM_WARN(devno, fmt, args...) \
+ rtdm_printk(KERN_WARNING "EtherCATrtdm %u WARNING: " fmt, devno, ##args)
+
+
+
+
+typedef struct _EC_RTDM_DRV_STRUCT {
+ unsigned int isattached;
+ ec_master_t * master;
+ ec_domain_t * domain;
+#ifdef ENABLE_XENOMAI
+ RT_MUTEX masterlock;
+#endif
+#ifdef ENABLE_RTAI
+ SEM masterlock;
+#endif
+ unsigned int sendcnt;
+ unsigned int reccnt;
+ unsigned int sendcntlv;
+ unsigned int reccntlv;
+ char mutexname[64];
+ unsigned int masterno;
+} EC_RTDM_DRV_STRUCT;
+
+
+static EC_RTDM_DRV_STRUCT ec_rtdm_masterintf[EC_RTDM_MAX_MASTERS];
+
+
+/* import from ethercat */
+ec_master_t *ecrt_attach_master(unsigned int master_index /**< Index of the master to request. */
+ );
+
+// driver context struct: used for storing various information
+typedef struct _EC_RTDM_DRV_CONTEXT {
+ int dev_id;
+ EC_RTDM_DRV_STRUCT* pdrvstruc;
+} EC_RTDM_DRV_CONTEXT;
+
+
+
+/**********************************************************/
+/* Utilities */
+/**********************************************************/
+
+static int _atoi(const char* text)
+{
+ char b;
+ int wd=-1;
+ int nfak=1;
+
+ wd=0;
+
+ while ((*text==' ') || (*text=='\t')) text++;
+ if (*text=='-')
+ {
+ nfak=-1;
+ text++;
+ }
+ if (*text=='+')
+ {
+ text++;
+ }
+ while (*text!=0)
+ {
+ b = *text;
+
+ if ( (b>='0') && (b<='9') )
+ {
+ b=b-'0';
+ wd=wd*10+b;
+ }
+ text++;
+ }
+ return (nfak*wd);
+}
+
+
+/**********************************************************/
+/* DRIVER sendcallback */
+/**********************************************************/
+void send_callback(void *cb_data)
+{
+ EC_RTDM_DRV_STRUCT * pdrvstruc;
+
+ pdrvstruc = (EC_RTDM_DRV_STRUCT*)cb_data;
+ if (pdrvstruc->master)
+ {
+ my_mutex_acquire(&pdrvstruc->masterlock,TM_INFINITE);
+ ecrt_master_send_ext(pdrvstruc->master);
+ my_mutex_release(&pdrvstruc->masterlock);
+ }
+}
+
+/*****************************************************************************/
+
+void receive_callback(void *cb_data)
+{
+ EC_RTDM_DRV_STRUCT * pdrvstruc;
+
+ pdrvstruc = (EC_RTDM_DRV_STRUCT*)cb_data;
+ if (pdrvstruc->master)
+ {
+ my_mutex_acquire(&pdrvstruc->masterlock,TM_INFINITE);
+ ecrt_master_receive(pdrvstruc->master);
+ my_mutex_release(&pdrvstruc->masterlock);
+ }
+}
+
+
+
+
+void detach_master(EC_RTDM_DRV_STRUCT * pdrvstruc)
+{
+
+ if (pdrvstruc->isattached)
+ {
+ EC_RTDM_INFO(pdrvstruc->masterno,"reseting callbacks!\n");
+ ecrt_master_callbacks(pdrvstruc->master,NULL,NULL,NULL);
+ EC_RTDM_INFO(pdrvstruc->masterno,"deleting mutex!\n");
+ my_mutex_delete(&pdrvstruc->masterlock);
+ pdrvstruc->master = NULL;
+ pdrvstruc->isattached=0;
+ EC_RTDM_INFO(pdrvstruc->masterno,"master detach done!\n");
+ }
+}
+
+
+
+
+/**********************************************************/
+/* DRIVER OPEN */
+/**********************************************************/
+int ec_rtdm_open_rt(struct rtdm_dev_context *context,
+ rtdm_user_info_t *user_info,
+ int oflags)
+{
+ EC_RTDM_DRV_CONTEXT* my_context;
+ EC_RTDM_DRV_STRUCT * pdrvstruc;
+ const char * p;
+ int dev_no;
+ unsigned int namelen;
+
+ //int ret;
+ int dev_id;
+
+ // get the context for our driver - used to store driver info
+ my_context = (EC_RTDM_DRV_CONTEXT*)context->dev_private;
+
+ dev_no = -1;
+ namelen = strlen(context->device->driver_name);
+ p = &context->device->driver_name[namelen-1];
+ if (p!=&context->device->driver_name[0])
+ {
+ while ((*p>='0') && (*p<='9'))
+ {
+ p--;
+ if (p==&context->device->driver_name[0]) break;
+ }
+ dev_no=_atoi(p);
+ if ((dev_no!=-1) && (dev_no<EC_RTDM_MAX_MASTERS))
+ {
+ dev_id = context->device->device_id;
+ pdrvstruc = (EC_RTDM_DRV_STRUCT*)&ec_rtdm_masterintf[dev_no];
+
+ my_context->dev_id = dev_id;
+ my_context->pdrvstruc = pdrvstruc;
+
+ // enable interrupt in RTDM
+ return 0;
+ }
+ }
+ EC_RTDM_GERR("open - Cannot detect master device no\n");
+ return -EFAULT;
+}
+
+/**********************************************************/
+/* DRIVER CLOSE */
+/**********************************************************/
+int ec_rtdm_close_rt(struct rtdm_dev_context *context,
+ rtdm_user_info_t *user_info)
+{
+ EC_RTDM_DRV_CONTEXT* my_context;
+ EC_RTDM_DRV_STRUCT * pdrvstruc;
+
+ // get the context
+ my_context = (EC_RTDM_DRV_CONTEXT*)context->dev_private;
+
+ pdrvstruc = my_context->pdrvstruc;
+ EC_RTDM_INFO(pdrvstruc->masterno,"close called!\n");
+ detach_master(pdrvstruc);
+ return 0;
+
+}
+
+/**********************************************************/
+/* DRIVER IOCTL */
+/**********************************************************/
+int ec_rtdm_ioctl_rt(struct rtdm_dev_context *context,
+ rtdm_user_info_t *user_info,
+ int request,
+ void *arg)
+{
+ EC_RTDM_DRV_CONTEXT* my_context;
+ EC_RTDM_DRV_STRUCT * pdrvstruc;
+ int ret;
+ unsigned int l_ioctlvalue[]={0,0,0,0,0,0,0,0};
+ ec_domain_state_t ds;
+ ec_master_state_t ms;
+ uint64_t app_time;
+
+
+ ret = 0;
+
+ // get the context
+ my_context = (EC_RTDM_DRV_CONTEXT*)context->dev_private;
+ pdrvstruc = my_context->pdrvstruc;
+
+ switch (request) {
+ case EC_RTDM_MASTERSTATE:
+ {
+ if (!pdrvstruc->isattached)
+ {
+ return -EFAULT;
+ }
+ if (pdrvstruc->master)
+ {
+ my_mutex_acquire(&pdrvstruc->masterlock,TM_INFINITE);
+
+ ecrt_master_state(pdrvstruc->master, &ms);
+
+ my_mutex_release(&pdrvstruc->masterlock);
+
+ }
+ if (rtdm_rw_user_ok(user_info, arg, sizeof(ms)))
+ {
+ // copy data to user
+ if (rtdm_copy_to_user(user_info, arg, &ms,sizeof(ms)))
+ {
+ return -EFAULT;
+ }
+ }
+
+ }
+ break;
+ case EC_RTDM_DOMAINSTATE:
+ {
+ if (!pdrvstruc->isattached)
+ {
+ return -EFAULT;
+ }
+ if (pdrvstruc->domain)
+ {
+ my_mutex_acquire(&pdrvstruc->masterlock,TM_INFINITE);
+
+ ecrt_domain_state(pdrvstruc->domain, &ds);
+
+ my_mutex_release(&pdrvstruc->masterlock);
+ }
+ if (rtdm_rw_user_ok(user_info, arg, sizeof(ds)))
+ {
+ // copy data to user
+ if (rtdm_copy_to_user(user_info, arg, &ds,sizeof(ds)))
+ {
+ return -EFAULT;
+ }
+ }
+ }
+ break;
+ case EC_RTDM_MASTER_RECEIVE:
+ {
+ if (pdrvstruc->isattached)
+ {
+ if (pdrvstruc->master)
+ {
+ my_mutex_acquire(&pdrvstruc->masterlock,TM_INFINITE);
+ ecrt_master_receive(pdrvstruc->master);
+ pdrvstruc->reccnt++;
+ my_mutex_release(&pdrvstruc->masterlock);
+ }
+ }
+ }
+ break;
+ case EC_RTDM_DOMAIN_PROCESS:
+ {
+ if (pdrvstruc->isattached)
+ {
+ my_mutex_acquire(&pdrvstruc->masterlock,TM_INFINITE);
+ ecrt_domain_process(pdrvstruc->domain);
+ my_mutex_release(&pdrvstruc->masterlock);
+ }
+ }
+ break;
+ case EC_RTDM_MASTER_SEND:
+ {
+
+ if (pdrvstruc->isattached)
+ {
+ if (pdrvstruc->master)
+ {
+ my_mutex_acquire(&pdrvstruc->masterlock,TM_INFINITE);
+ ecrt_master_send(pdrvstruc->master);
+ pdrvstruc->sendcnt++;
+ my_mutex_release(&pdrvstruc->masterlock);
+ }
+ }
+ }
+ break;
+ case EC_RTDM_DOMAIN_QUEQUE:
+ {
+ if (pdrvstruc->isattached)
+ {
+ my_mutex_acquire(&pdrvstruc->masterlock,TM_INFINITE);
+ ecrt_domain_queue(pdrvstruc->domain);
+ my_mutex_release(&pdrvstruc->masterlock);
+ }
+ }
+ break;
+
+ case EC_RTDM_MASTER_APP_TIME:
+ {
+ if (!pdrvstruc->isattached)
+ {
+ rtdm_printk("ERROR : No Master attached\n");
+ return -EFAULT;
+ }
+ if (rtdm_safe_copy_from_user(user_info, &app_time, arg, sizeof(app_time)))
+ {
+ rtdm_printk("ERROR : can't copy data to driver\n");
+ return -EFAULT;
+ }
+
+ if (pdrvstruc->master)
+ {
+ my_mutex_acquire(&pdrvstruc->masterlock,TM_INFINITE);
+
+ ecrt_master_application_time(pdrvstruc->master, app_time);
+ my_mutex_release(&pdrvstruc->masterlock);
+
+ }
+ }
+ break;
+ case EC_RTDM_SYNC_REF_CLOCK:
+ {
+ if (!pdrvstruc->isattached)
+ {
+ return -EFAULT;
+ }
+ if (pdrvstruc->master)
+ {
+ my_mutex_acquire(&pdrvstruc->masterlock,TM_INFINITE);
+
+ ecrt_master_sync_reference_clock(pdrvstruc->master);
+
+ my_mutex_release(&pdrvstruc->masterlock);
+
+ }
+ }
+ break;
+ case EC_RTDM_SYNC_SLAVE_CLOCK:
+ {
+ if (!pdrvstruc->isattached)
+ {
+ return -EFAULT;
+ }
+ if (pdrvstruc->master)
+ {
+ my_mutex_acquire(&pdrvstruc->masterlock,TM_INFINITE);
+
+ ecrt_master_sync_slave_clocks(pdrvstruc->master);
+
+ my_mutex_release(&pdrvstruc->masterlock);
+
+ }
+ }
+ break;
+ case EC_RTDM_MASTER_SYNC_MONITOR_QUEQUE:
+ {
+ if (!pdrvstruc->isattached)
+ {
+ return -EFAULT;
+ }
+ if (pdrvstruc->master)
+ {
+ my_mutex_acquire(&pdrvstruc->masterlock,TM_INFINITE);
+ ecrt_master_sync_monitor_queue(pdrvstruc->master);
+ my_mutex_release(&pdrvstruc->masterlock);
+ }
+ }
+ break;
+ case EC_RTDM_MASTER_SYNC_MONITOR_PROCESS:
+ {
+ uint32_t ret;
+ if (!pdrvstruc->isattached)
+ {
+ return -EFAULT;
+ }
+ if (pdrvstruc->master)
+ {
+ my_mutex_acquire(&pdrvstruc->masterlock,TM_INFINITE);
+ ret = ecrt_master_sync_monitor_process(pdrvstruc->master);
+ my_mutex_release(&pdrvstruc->masterlock);
+ if (rtdm_safe_copy_to_user(user_info, arg, &ret, sizeof(ret)))
+ {
+ EC_RTDM_ERR(pdrvstruc->masterno,"copy to user param failed!\n");
+ ret=-EFAULT;
+ }
+ }
+ }
+ break;
+ case EC_RTDM_MSTRATTACH:
+ {
+ unsigned int mstridx;
+
+ mstridx = 0;
+ ret = 0;
+
+ EC_RTDM_INFO(pdrvstruc->masterno,"Master attach start!\n");
+ if (user_info)
+ {
+ if (rtdm_read_user_ok(user_info, arg, sizeof(unsigned int)))
+ {
+ if (rtdm_copy_from_user(user_info, &l_ioctlvalue[0], arg,sizeof(unsigned int))==0)
+ {
+ pdrvstruc->domain = (ec_domain_t*)l_ioctlvalue[0];
+ }
+ else
+ {
+ EC_RTDM_ERR(pdrvstruc->masterno,"copy user param failed!\n");
+ ret=-EFAULT;
+ }
+ }
+ else
+ {
+ EC_RTDM_ERR(pdrvstruc->masterno,"user parameter domain missing!\n");
+ ret=-EFAULT;
+ }
+ }
+ if (ret!=0)
+ {
+ return ret;
+ }
+
+ if ( (pdrvstruc->master) && (pdrvstruc->isattached))
+ // master is allready attached
+ {
+ // master is allready attached
+ EC_RTDM_ERR(pdrvstruc->masterno,"Master is allready attached!\n");
+ ret = -EFAULT;
+ }
+ else
+ {
+ //mstr=ecrt_request_master(0);
+ mstridx = pdrvstruc->masterno;
+
+ pdrvstruc->master=ecrt_attach_master(mstridx);
+
+ if (pdrvstruc->master)
+ {
+ // Ok
+ EC_RTDM_INFO(pdrvstruc->masterno,"Master searching for domain!\n");
+ pdrvstruc->domain = ecrt_master_find_domain(pdrvstruc->master,l_ioctlvalue[0]);
+ if (!pdrvstruc->domain)
+ {
+ //
+ EC_RTDM_ERR(pdrvstruc->masterno,"Cannot find domain from index %u!\n",l_ioctlvalue[0]);
+ ret = -EFAULT;
+ }
+ else
+ {
+
+ // set device name
+ snprintf(&pdrvstruc->mutexname[0],sizeof(pdrvstruc->mutexname)-1,"ETHrtdmLOCK%d",pdrvstruc->masterno);
+ EC_RTDM_INFO(pdrvstruc->masterno,"Creating Master mutex %s!\n",&pdrvstruc->mutexname[0]);
+ my_mutex_create(&pdrvstruc->masterlock,&pdrvstruc->mutexname[0]);
+ //ecrt_release_master(mstr);
+ ecrt_master_callbacks(pdrvstruc->master, send_callback, receive_callback, pdrvstruc);
+ EC_RTDM_INFO(pdrvstruc->masterno,"MSTR ATTACH done domain=%u!\n",(unsigned int)pdrvstruc->domain);
+ pdrvstruc->isattached=1;
+ ret = 0;
+ }
+
+ }
+ else
+ {
+ EC_RTDM_ERR(pdrvstruc->masterno,"Master attach failed!\n");
+ pdrvstruc->master = NULL;
+ ret = -EFAULT;
+ }
+ }
+ }
+ break;
+ default:
+ ret = -ENOTTY;
+ }
+ return ret;
+}
+
+
+/**********************************************************/
+/* DRIVER READ */
+/**********************************************************/
+int ec_rtdm_read_rt(struct rtdm_dev_context *context,
+ rtdm_user_info_t *user_info, void *buf, size_t nbyte)
+{
+ int ret;
+#if defined(USE_THIS)
+ EC_RTDM_DRV_CONTEXT* my_context;
+ char *out_pos;
+ int dev_id;
+ rtdm_toseq_t timeout_seq;
+ int ret;
+
+ out_pos = (char *)buf;
+
+ my_context = (EC_RTDM_DRV_CONTEXT*)context->dev_private;
+
+ // zero bytes requested ? return!
+ if (nbyte == 0)
+ return 0;
+
+ // check if R/W actions to user-space are allowed
+ if (user_info && !rtdm_rw_user_ok(user_info, buf, nbyte))
+ return -EFAULT;
+
+ dev_id = my_context->dev_id;
+
+ // in case we need to check if reading is allowed (locking)
+/* if (test_and_set_bit(0, &ctx->in_lock))
+ return -EBUSY;
+*/
+/* // if we need to do some stuff with preemption disabled:
+ rtdm_lock_get_irqsave(&ctx->lock, lock_ctx);
+ // stuff here
+ rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
+*/
+
+ // wait: if ctx->timeout = 0, it will block infintely until
+ // rtdm_event_signal(&ctx->irq_event); is called from our
+ // interrupt routine
+ //ret = rtdm_event_timedwait(&ctx->irq_event, ctx->timeout, &timeout_seq);
+
+ // now write the requested stuff to user-space
+ if (rtdm_copy_to_user(user_info, out_pos,
+ dummy_buffer, BUFSIZE) != 0) {
+ ret = -EFAULT;
+ } else {
+ ret = BUFSIZE;
+ }
+#else
+ ret = -EFAULT;
+#endif
+ return ret;
+}
+
+/**********************************************************/
+/* DRIVER WRITE */
+/**********************************************************/
+int ec_rtdm_write_rt(struct rtdm_dev_context *context,
+ rtdm_user_info_t *user_info,
+ const void *buf, size_t nbyte)
+{
+ int ret;
+
+#if defined(USE_THIS)
+ int dev_id;
+ char *in_pos = (char *)buf;
+
+ EC_RTDM_DRV_CONTEXT* my_context;
+
+
+ my_context = (EC_RTDM_DRV_CONTEXT*)context->dev_private;
+
+
+ if (nbyte == 0)
+ return 0;
+ if (user_info && !rtdm_read_user_ok(user_info, buf, nbyte))
+ return -EFAULT;
+
+ dev_id = my_context->dev_id;
+
+ if (rtdm_copy_from_user(user_info, dummy_buffer,
+ in_pos, BUFSIZE) != 0) {
+ ret = -EFAULT;
+ } else {
+ ret = BUFSIZE;
+ }
+#else
+ ret = -EFAULT;
+#endif
+ // used when it is atomic
+// rtdm_mutex_unlock(&ctx->out_lock);
+ return ret;
+}
+
+/**********************************************************/
+/* DRIVER OPERATIONS */
+/**********************************************************/
+
+// Template
+
+static struct rtdm_device ec_rtdm_device_t = {
+ struct_version: RTDM_DEVICE_STRUCT_VER,
+
+ device_flags: RTDM_NAMED_DEVICE,
+ context_size: sizeof(EC_RTDM_DRV_CONTEXT),
+ device_name: EC_RTDM_DEV_FILE_NAME,
+
+/* open and close functions are not real-time safe due kmalloc
+ and kfree. If you do not use kmalloc and kfree, and you made
+ sure that there is no syscall in the open/close handler, you
+ can declare the open_rt and close_rt handler.
+*/
+ open_rt: NULL,
+ open_nrt: ec_rtdm_open_rt,
+
+ ops: {
+ close_rt: NULL,
+ close_nrt: ec_rtdm_close_rt,
+
+ ioctl_rt: ec_rtdm_ioctl_rt,
+ ioctl_nrt: ec_rtdm_ioctl_rt, // rtdm_mmap_to_user is not RT safe
+
+ read_rt: ec_rtdm_read_rt,
+ read_nrt: NULL,
+
+ write_rt: ec_rtdm_write_rt,
+ write_nrt: NULL,
+
+ recvmsg_rt: NULL,
+ recvmsg_nrt: NULL,
+
+ sendmsg_rt: NULL,
+ sendmsg_nrt: NULL,
+ },
+
+ device_class: RTDM_CLASS_EXPERIMENTAL,
+ device_sub_class: 222,
+ driver_name: EC_RTDM_DEV_FILE_NAME,
+ driver_version: RTDM_DRIVER_VER(1,0,1),
+ peripheral_name: EC_RTDM_DEV_FILE_NAME,
+ provider_name: "EtherLab Community",
+// proc_name: ethcatrtdm_device.device_name,
+};
+
+
+static struct rtdm_device ec_rtdm_devices[EC_RTDM_MAX_MASTERS];
+
+
+/**********************************************************/
+/* INIT DRIVER */
+/**********************************************************/
+int init_module(void)
+{
+ unsigned int i;
+ int ret;
+
+ ret = 0;
+
+ EC_RTDM_GINFO("Initlializing EtherCAT RTDM Interface to Igh EtherCAT Master\n");
+ memset(&ec_rtdm_masterintf[0],0,sizeof(ec_rtdm_masterintf));
+ for (i=0;( (i<EC_RTDM_MAX_MASTERS) && (ret==0) ) ;i++)
+ {
+ // master no to struct
+ ec_rtdm_masterintf[i].masterno = i;
+ // copy from template
+ memcpy(&ec_rtdm_devices[i],&ec_rtdm_device_t,sizeof(ec_rtdm_devices[0]));
+
+ // set device name
+ snprintf(&ec_rtdm_devices[i].device_name[0],RTDM_MAX_DEVNAME_LEN,"%s%d",EC_RTDM_DEV_FILE_NAME,i);
+ // set proc_name
+ ec_rtdm_devices[i].proc_name = &ec_rtdm_devices[i].device_name[0];
+ ec_rtdm_devices[i].driver_name = &ec_rtdm_devices[i].device_name[0];
+ ec_rtdm_devices[i].peripheral_name = &ec_rtdm_devices[i].device_name[0];
+
+ EC_RTDM_GINFO("Registering device %s!\n",ec_rtdm_devices[i].driver_name);
+ ret = rtdm_dev_register(&ec_rtdm_devices[i]);
+
+ }
+ if (ret!=0)
+ {
+ // register m
+ EC_RTDM_GERR("Initialization of EtherCAT RTDM Interface failed\n");
+ }
+ return ret;
+}
+
+/**********************************************************/
+/* CLEANUP DRIVER */
+/**********************************************************/
+void cleanup_module(void)
+{
+ unsigned int i;
+
+ EC_RTDM_GINFO("Cleanup EtherCAT RTDM Interface \n");
+ for (i=0;i<EC_RTDM_MAX_MASTERS;i++)
+ {
+ if (ec_rtdm_masterintf[i].isattached)
+ {
+ detach_master(&ec_rtdm_masterintf[i]);
+ }
+ EC_RTDM_GINFO("Unregistering device %s!\n",ec_rtdm_devices[i].driver_name);
+ rtdm_dev_unregister(&ec_rtdm_devices[i],1000);
+ }
+}
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("EtherCAT RTDM Interface");