diff --git a/include/ecrt.h b/include/ecrt.h index 1df3afac..b33f5010 100644 --- a/include/ecrt.h +++ b/include/ecrt.h @@ -1158,6 +1158,9 @@ EC_PUBLIC_API void ecrt_master_sync_reference_clock( * The reference clock will by synchronized to the time passed in the * sync_time parameter. * + * Has to be called by the application after ecrt_master_activate() + * has returned. + * * \ingroup ApplicationInterfaceRT */ EC_PUBLIC_API void ecrt_master_sync_reference_clock_to( @@ -1169,6 +1172,9 @@ EC_PUBLIC_API void ecrt_master_sync_reference_clock_to( * * All slave clocks synchronized to the reference clock. * + * Has to be called by the application after ecrt_master_activate() + * has returned. + * * \ingroup ApplicationInterfaceRT */ EC_PUBLIC_API void ecrt_master_sync_slave_clocks( diff --git a/master/cdev.c b/master/cdev.c index eb95bfe9..721209fc 100644 --- a/master/cdev.c +++ b/master/cdev.c @@ -191,6 +191,7 @@ int eccdev_release(struct inode *inode, struct file *filp) */ long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { + long result; ec_cdev_priv_t *priv = (ec_cdev_priv_t *) filp->private_data; #if DEBUG @@ -199,7 +200,11 @@ long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) filp, cmd, _IOC_NR(cmd), arg); #endif - return ec_ioctl(priv->cdev->master, &priv->ctx, cmd, (void __user *) arg); + result = ec_ioctl_rt(priv->cdev->master, &priv->ctx, cmd, (void __user *) arg); + if (result == -ENOTTY) { + result = ec_ioctl_nrt(priv->cdev->master, &priv->ctx, cmd, (void __user *) arg); + } + return result; } /****************************************************************************/ diff --git a/master/ioctl.c b/master/ioctl.c index 367442d9..bb4d5d8f 100644 --- a/master/ioctl.c +++ b/master/ioctl.c @@ -4667,16 +4667,328 @@ static ATTRIBUTES int ec_ioctl_slave_soe_write( /** ioctl() function to use. */ #ifdef EC_IOCTL_RTDM -#define EC_IOCTL ec_ioctl_rtdm +#define EC_IOCTL(x) ec_ioctl_rtdm_ ## x #else -#define EC_IOCTL ec_ioctl +#define EC_IOCTL(x) ec_ioctl_ ## x #endif /** Called when an ioctl() command is issued. + * Both RT and nRT context. * * \return ioctl() return code. */ -long EC_IOCTL( +static long EC_IOCTL(both)( + ec_master_t *master, /**< EtherCAT master. */ + ec_ioctl_context_t *ctx, /**< Device context. */ + unsigned int cmd, /**< ioctl() command identifier. */ + void *arg /**< ioctl() argument. */ + ) +{ + int ret; + + switch (cmd) { + case EC_IOCTL_MODULE: + ret = ec_ioctl_module(arg, ctx); + break; + case EC_IOCTL_MASTER_DEBUG: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_master_debug(master, arg); + break; + case EC_IOCTL_MASTER_RESCAN: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_master_rescan(master, arg); + break; + case EC_IOCTL_MASTER_STATE: + ret = ec_ioctl_master_state(master, arg, ctx); + break; + case EC_IOCTL_MASTER_LINK_STATE: + ret = ec_ioctl_master_link_state(master, arg, ctx); + break; + case EC_IOCTL_APP_TIME: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_app_time(master, arg, ctx); + break; + case EC_IOCTL_REF_CLOCK_TIME: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_ref_clock_time(master, arg, ctx); + break; + case EC_IOCTL_SC_EMERG_POP: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_sc_emerg_pop(master, arg, ctx); + break; + case EC_IOCTL_SC_EMERG_CLEAR: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_sc_emerg_clear(master, arg, ctx); + break; + case EC_IOCTL_SC_EMERG_OVERRUNS: + ret = ec_ioctl_sc_emerg_overruns(master, arg, ctx); + break; + case EC_IOCTL_SC_STATE: + ret = ec_ioctl_sc_state(master, arg, ctx); + break; + case EC_IOCTL_DOMAIN_STATE: + ret = ec_ioctl_domain_state(master, arg, ctx); + break; + case EC_IOCTL_SDO_REQUEST_INDEX: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_sdo_request_index(master, arg, ctx); + break; + case EC_IOCTL_SDO_REQUEST_TIMEOUT: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_sdo_request_timeout(master, arg, ctx); + break; + case EC_IOCTL_SDO_REQUEST_STATE: + ret = ec_ioctl_sdo_request_state(master, arg, ctx); + break; + case EC_IOCTL_SDO_REQUEST_READ: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_sdo_request_read(master, arg, ctx); + break; + case EC_IOCTL_SDO_REQUEST_WRITE: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_sdo_request_write(master, arg, ctx); + break; + case EC_IOCTL_SDO_REQUEST_DATA: + ret = ec_ioctl_sdo_request_data(master, arg, ctx); + break; + case EC_IOCTL_SOE_REQUEST_IDN: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_soe_request_index(master, arg, ctx); + break; + case EC_IOCTL_SOE_REQUEST_TIMEOUT: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_soe_request_timeout(master, arg, ctx); + break; + case EC_IOCTL_SOE_REQUEST_STATE: + ret = ec_ioctl_soe_request_state(master, arg, ctx); + break; + case EC_IOCTL_SOE_REQUEST_READ: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_soe_request_read(master, arg, ctx); + break; + case EC_IOCTL_SOE_REQUEST_WRITE: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_soe_request_write(master, arg, ctx); + break; + case EC_IOCTL_SOE_REQUEST_DATA: + ret = ec_ioctl_soe_request_data(master, arg, ctx); + break; + case EC_IOCTL_REG_REQUEST_DATA: + ret = ec_ioctl_reg_request_data(master, arg, ctx); + break; + case EC_IOCTL_REG_REQUEST_STATE: + ret = ec_ioctl_reg_request_state(master, arg, ctx); + break; + case EC_IOCTL_REG_REQUEST_WRITE: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_reg_request_write(master, arg, ctx); + break; + case EC_IOCTL_REG_REQUEST_READ: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_reg_request_read(master, arg, ctx); + break; + case EC_IOCTL_VOE_SEND_HEADER: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_voe_send_header(master, arg, ctx); + break; + case EC_IOCTL_VOE_REC_HEADER: + ret = ec_ioctl_voe_rec_header(master, arg, ctx); + break; + case EC_IOCTL_VOE_READ: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_voe_read(master, arg, ctx); + break; + case EC_IOCTL_VOE_READ_NOSYNC: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_voe_read_nosync(master, arg, ctx); + break; + case EC_IOCTL_VOE_WRITE: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_voe_write(master, arg, ctx); + break; + case EC_IOCTL_VOE_DATA: + ret = ec_ioctl_voe_data(master, arg, ctx); + break; + default: + ret = -ENOTTY; + break; + } + + return ret; +} + +/** Called when an ioctl() command is issued. + * RT only. + * + * \return ioctl() return code. + */ +long EC_IOCTL(rt)( + ec_master_t *master, /**< EtherCAT master. */ + ec_ioctl_context_t *ctx, /**< Device context. */ + unsigned int cmd, /**< ioctl() command identifier. */ + void *arg /**< ioctl() argument. */ + ) +{ +#if DEBUG_LATENCY + cycles_t a = get_cycles(), b; + unsigned int t; +#endif + long ret; + + switch (cmd) { + case EC_IOCTL_SEND: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_send(master, arg, ctx); + break; + case EC_IOCTL_RECEIVE: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_receive(master, arg, ctx); + break; + case EC_IOCTL_SYNC_REF: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_sync_ref(master, arg, ctx); + break; + case EC_IOCTL_SYNC_REF_TO: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_sync_ref_to(master, arg, ctx); + break; + case EC_IOCTL_SYNC_SLAVES: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_sync_slaves(master, arg, ctx); + break; + case EC_IOCTL_SYNC_MON_QUEUE: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_sync_mon_queue(master, arg, ctx); + break; + case EC_IOCTL_SYNC_MON_PROCESS: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_sync_mon_process(master, arg, ctx); + break; + case EC_IOCTL_DOMAIN_PROCESS: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_domain_process(master, arg, ctx); + break; + case EC_IOCTL_DOMAIN_QUEUE: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_domain_queue(master, arg, ctx); + break; + case EC_IOCTL_VOE_EXEC: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_voe_exec(master, arg, ctx); + break; + default: + ret = EC_IOCTL(both)(master, ctx, cmd, arg); + break; + } + +#if DEBUG_LATENCY + b = get_cycles(); + t = (unsigned int) ((b - a) * 1000LL) / cpu_khz; + if (t > 50) { + EC_MASTER_WARN(master, "ioctl(0x%02x) took %u us.\n", + _IOC_NR(cmd), t); + } +#endif + + return ret; +} + +/** Called when an ioctl() command is issued. + * nRT context only. + * + * \return ioctl() return code. + */ +long EC_IOCTL(nrt)( ec_master_t *master, /**< EtherCAT master. */ ec_ioctl_context_t *ctx, /**< Device context. */ unsigned int cmd, /**< ioctl() command identifier. */ @@ -4690,9 +5002,6 @@ long EC_IOCTL( int ret; switch (cmd) { - case EC_IOCTL_MODULE: - ret = ec_ioctl_module(arg, ctx); - break; case EC_IOCTL_MASTER: ret = ec_ioctl_master(master, arg); break; @@ -4717,20 +5026,6 @@ long EC_IOCTL( case EC_IOCTL_DOMAIN_DATA: ret = ec_ioctl_domain_data(master, arg); break; - case EC_IOCTL_MASTER_DEBUG: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_master_debug(master, arg); - break; - case EC_IOCTL_MASTER_RESCAN: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_master_rescan(master, arg); - break; case EC_IOCTL_SLAVE_STATE: if (!ctx->writable) { ret = -EPERM; @@ -4868,75 +5163,6 @@ long EC_IOCTL( } ret = ec_ioctl_deactivate(master, arg, ctx); break; - case EC_IOCTL_SEND: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_send(master, arg, ctx); - break; - case EC_IOCTL_RECEIVE: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_receive(master, arg, ctx); - break; - case EC_IOCTL_MASTER_STATE: - ret = ec_ioctl_master_state(master, arg, ctx); - break; - case EC_IOCTL_MASTER_LINK_STATE: - ret = ec_ioctl_master_link_state(master, arg, ctx); - break; - case EC_IOCTL_APP_TIME: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_app_time(master, arg, ctx); - break; - case EC_IOCTL_SYNC_REF: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_sync_ref(master, arg, ctx); - break; - case EC_IOCTL_SYNC_REF_TO: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_sync_ref_to(master, arg, ctx); - break; - case EC_IOCTL_SYNC_SLAVES: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_sync_slaves(master, arg, ctx); - break; - case EC_IOCTL_REF_CLOCK_TIME: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_ref_clock_time(master, arg, ctx); - break; - case EC_IOCTL_SYNC_MON_QUEUE: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_sync_mon_queue(master, arg, ctx); - break; - case EC_IOCTL_SYNC_MON_PROCESS: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_sync_mon_process(master, arg, ctx); - break; case EC_IOCTL_RESET: if (!ctx->writable) { ret = -EPERM; @@ -5021,23 +5247,6 @@ long EC_IOCTL( } ret = ec_ioctl_sc_emerg_size(master, arg, ctx); break; - case EC_IOCTL_SC_EMERG_POP: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_sc_emerg_pop(master, arg, ctx); - break; - case EC_IOCTL_SC_EMERG_CLEAR: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_sc_emerg_clear(master, arg, ctx); - break; - case EC_IOCTL_SC_EMERG_OVERRUNS: - ret = ec_ioctl_sc_emerg_overruns(master, arg, ctx); - break; case EC_IOCTL_SC_SDO_REQUEST: if (!ctx->writable) { ret = -EPERM; @@ -5066,9 +5275,6 @@ long EC_IOCTL( } ret = ec_ioctl_sc_create_voe_handler(master, arg, ctx); break; - case EC_IOCTL_SC_STATE: - ret = ec_ioctl_sc_state(master, arg, ctx); - break; case EC_IOCTL_SC_IDN: if (!ctx->writable) { ret = -EPERM; @@ -5089,152 +5295,6 @@ long EC_IOCTL( case EC_IOCTL_DOMAIN_OFFSET: ret = ec_ioctl_domain_offset(master, arg, ctx); break; - case EC_IOCTL_DOMAIN_PROCESS: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_domain_process(master, arg, ctx); - break; - case EC_IOCTL_DOMAIN_QUEUE: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_domain_queue(master, arg, ctx); - break; - case EC_IOCTL_DOMAIN_STATE: - ret = ec_ioctl_domain_state(master, arg, ctx); - break; - case EC_IOCTL_SDO_REQUEST_INDEX: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_sdo_request_index(master, arg, ctx); - break; - case EC_IOCTL_SDO_REQUEST_TIMEOUT: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_sdo_request_timeout(master, arg, ctx); - break; - case EC_IOCTL_SDO_REQUEST_STATE: - ret = ec_ioctl_sdo_request_state(master, arg, ctx); - break; - case EC_IOCTL_SDO_REQUEST_READ: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_sdo_request_read(master, arg, ctx); - break; - case EC_IOCTL_SDO_REQUEST_WRITE: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_sdo_request_write(master, arg, ctx); - break; - case EC_IOCTL_SDO_REQUEST_DATA: - ret = ec_ioctl_sdo_request_data(master, arg, ctx); - break; - case EC_IOCTL_SOE_REQUEST_IDN: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_soe_request_index(master, arg, ctx); - break; - case EC_IOCTL_SOE_REQUEST_TIMEOUT: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_soe_request_timeout(master, arg, ctx); - break; - case EC_IOCTL_SOE_REQUEST_STATE: - ret = ec_ioctl_soe_request_state(master, arg, ctx); - break; - case EC_IOCTL_SOE_REQUEST_READ: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_soe_request_read(master, arg, ctx); - break; - case EC_IOCTL_SOE_REQUEST_WRITE: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_soe_request_write(master, arg, ctx); - break; - case EC_IOCTL_SOE_REQUEST_DATA: - ret = ec_ioctl_soe_request_data(master, arg, ctx); - break; - case EC_IOCTL_REG_REQUEST_DATA: - ret = ec_ioctl_reg_request_data(master, arg, ctx); - break; - case EC_IOCTL_REG_REQUEST_STATE: - ret = ec_ioctl_reg_request_state(master, arg, ctx); - break; - case EC_IOCTL_REG_REQUEST_WRITE: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_reg_request_write(master, arg, ctx); - break; - case EC_IOCTL_REG_REQUEST_READ: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_reg_request_read(master, arg, ctx); - break; - case EC_IOCTL_VOE_SEND_HEADER: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_voe_send_header(master, arg, ctx); - break; - case EC_IOCTL_VOE_REC_HEADER: - ret = ec_ioctl_voe_rec_header(master, arg, ctx); - break; - case EC_IOCTL_VOE_READ: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_voe_read(master, arg, ctx); - break; - case EC_IOCTL_VOE_READ_NOSYNC: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_voe_read_nosync(master, arg, ctx); - break; - case EC_IOCTL_VOE_WRITE: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_voe_write(master, arg, ctx); - break; - case EC_IOCTL_VOE_EXEC: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_voe_exec(master, arg, ctx); - break; - case EC_IOCTL_VOE_DATA: - ret = ec_ioctl_voe_data(master, arg, ctx); - break; case EC_IOCTL_SET_SEND_INTERVAL: if (!ctx->writable) { ret = -EPERM; @@ -5243,7 +5303,7 @@ long EC_IOCTL( ret = ec_ioctl_set_send_interval(master, arg, ctx); break; default: - ret = -ENOTTY; + ret = EC_IOCTL(both)(master, ctx, cmd, arg); break; } diff --git a/master/ioctl.h b/master/ioctl.h index 01f75539..9e462d3f 100644 --- a/master/ioctl.h +++ b/master/ioctl.h @@ -838,12 +838,16 @@ typedef struct { size_t process_data_size; /**< Size of the \a process_data. */ } ec_ioctl_context_t; -long ec_ioctl(ec_master_t *, ec_ioctl_context_t *, unsigned int, +long ec_ioctl_rt(ec_master_t *, ec_ioctl_context_t *, unsigned int, + void __user *); +long ec_ioctl_nrt(ec_master_t *, ec_ioctl_context_t *, unsigned int, void __user *); #ifdef EC_RTDM -long ec_ioctl_rtdm(ec_master_t *, ec_ioctl_context_t *, unsigned int, +long ec_ioctl_rtdm_rt(ec_master_t *, ec_ioctl_context_t *, unsigned int, + void __user *); +long ec_ioctl_rtdm_nrt(ec_master_t *, ec_ioctl_context_t *, unsigned int, void __user *); #ifndef EC_RTDM_XENOMAI_V3 diff --git a/master/rtdm.c b/master/rtdm.c index e5e73e09..f9a15b1c 100644 --- a/master/rtdm.c +++ b/master/rtdm.c @@ -41,11 +41,12 @@ /****************************************************************************/ -int ec_rtdm_open(struct rtdm_dev_context *, rtdm_user_info_t *, int); -int ec_rtdm_close(struct rtdm_dev_context *, rtdm_user_info_t *); -int ec_rtdm_ioctl(struct rtdm_dev_context *, rtdm_user_info_t *, +static int ec_rtdm_open(struct rtdm_dev_context *, rtdm_user_info_t *, int); +static int ec_rtdm_close(struct rtdm_dev_context *, rtdm_user_info_t *); +static int ec_rtdm_ioctl_nrt_handler(struct rtdm_dev_context *, rtdm_user_info_t *, + unsigned int, void __user *); +static int ec_rtdm_ioctl_rt_handler(struct rtdm_dev_context *, rtdm_user_info_t *, unsigned int, void __user *); - /****************************************************************************/ /** Initialize an RTDM device. @@ -74,8 +75,8 @@ int ec_rtdm_dev_init( "EtherCAT%u", master->index); rtdm_dev->dev->open_nrt = ec_rtdm_open; rtdm_dev->dev->ops.close_nrt = ec_rtdm_close; - rtdm_dev->dev->ops.ioctl_rt = ec_rtdm_ioctl; - rtdm_dev->dev->ops.ioctl_nrt = ec_rtdm_ioctl; + rtdm_dev->dev->ops.ioctl_rt = ec_rtdm_ioctl_rt_handler; + rtdm_dev->dev->ops.ioctl_nrt = ec_rtdm_ioctl_nrt_handler; rtdm_dev->dev->device_class = RTDM_CLASS_EXPERIMENTAL; rtdm_dev->dev->device_sub_class = 222; rtdm_dev->dev->driver_name = "EtherCAT"; @@ -124,7 +125,7 @@ void ec_rtdm_dev_clear( * * \return Always zero (success). */ -int ec_rtdm_open( +static int ec_rtdm_open( struct rtdm_dev_context *context, /**< Context. */ rtdm_user_info_t *user_info, /**< User data. */ int oflags /**< Open flags. */ @@ -154,7 +155,7 @@ int ec_rtdm_open( * * \return Always zero (success). */ -int ec_rtdm_close( +static int ec_rtdm_close( struct rtdm_dev_context *context, /**< Context. */ rtdm_user_info_t *user_info /**< User data. */ ) @@ -179,7 +180,7 @@ int ec_rtdm_close( * * \return ioctl() return code. */ -int ec_rtdm_ioctl( +static int ec_rtdm_ioctl_nrt_handler( struct rtdm_dev_context *context, /**< Context. */ rtdm_user_info_t *user_info, /**< User data. */ unsigned int request, /**< Request. */ @@ -194,7 +195,32 @@ int ec_rtdm_ioctl( " on RTDM device %s.\n", request, _IOC_NR(request), context->device->device_name); #endif - return ec_ioctl_rtdm(rtdm_dev->master, &ctx->ioctl_ctx, request, arg); + return ec_ioctl_rtdm_nrt(rtdm_dev->master, &ctx->ioctl_ctx, request, arg); +} + +static int ec_rtdm_ioctl_rt_handler( + struct rtdm_dev_context *context, /**< Context. */ + rtdm_user_info_t *user_info, /**< User data. */ + unsigned int request, /**< Request. */ + void __user *arg /**< Argument. */ + ) +{ + int result; + ec_rtdm_context_t *ctx = (ec_rtdm_context_t *) context->dev_private; + ec_rtdm_dev_t *rtdm_dev = (ec_rtdm_dev_t *) context->device->device_data; + +#if DEBUG + EC_MASTER_INFO(rtdm_dev->master, "ioctl(request = %u, ctl = %02x)" + " on RTDM device %s.\n", request, _IOC_NR(request), + context->device->device_name); +#endif + result = ec_ioctl_rtdm_rt(rtdm_dev->master, &ctx->ioctl_ctx, request, arg); + + if (result == -ENOTTY) { + /* Try again with nrt ioctl handler above in secondary mode. */ + return -ENOSYS; + } + return result; } /****************************************************************************/ diff --git a/master/rtdm_xenomai_v3.c b/master/rtdm_xenomai_v3.c index 4a58950a..09a969c1 100644 --- a/master/rtdm_xenomai_v3.c +++ b/master/rtdm_xenomai_v3.c @@ -84,189 +84,31 @@ static void ec_rtdm_close(struct rtdm_fd *fd) #endif } -#if DEBUG_RTDM -struct ec_ioctl_desc { - unsigned int cmd; - const char *name; -}; - -#define EC_IOCTL_DEF(ioctl) \ - [_IOC_NR(ioctl)] = { \ - .cmd = ioctl, \ - .name = #ioctl \ - } - -static const struct ec_ioctl_desc ec_ioctls[] = { - EC_IOCTL_DEF(EC_IOCTL_MODULE), - EC_IOCTL_DEF(EC_IOCTL_MASTER), - EC_IOCTL_DEF(EC_IOCTL_SLAVE), - EC_IOCTL_DEF(EC_IOCTL_SLAVE_SYNC), - EC_IOCTL_DEF(EC_IOCTL_SLAVE_SYNC_PDO), - EC_IOCTL_DEF(EC_IOCTL_SLAVE_SYNC_PDO_ENTRY), - EC_IOCTL_DEF(EC_IOCTL_DOMAIN), - EC_IOCTL_DEF(EC_IOCTL_DOMAIN_FMMU), - EC_IOCTL_DEF(EC_IOCTL_DOMAIN_DATA), - EC_IOCTL_DEF(EC_IOCTL_MASTER_DEBUG), - EC_IOCTL_DEF(EC_IOCTL_MASTER_RESCAN), - EC_IOCTL_DEF(EC_IOCTL_SLAVE_STATE), - EC_IOCTL_DEF(EC_IOCTL_SLAVE_SDO), - EC_IOCTL_DEF(EC_IOCTL_SLAVE_SDO_ENTRY), - EC_IOCTL_DEF(EC_IOCTL_SLAVE_SDO_UPLOAD), - EC_IOCTL_DEF(EC_IOCTL_SLAVE_SDO_DOWNLOAD), - EC_IOCTL_DEF(EC_IOCTL_SLAVE_SII_READ), - EC_IOCTL_DEF(EC_IOCTL_SLAVE_SII_WRITE), - EC_IOCTL_DEF(EC_IOCTL_SLAVE_REG_READ), - EC_IOCTL_DEF(EC_IOCTL_SLAVE_REG_WRITE), - EC_IOCTL_DEF(EC_IOCTL_SLAVE_FOE_READ), - EC_IOCTL_DEF(EC_IOCTL_SLAVE_FOE_WRITE), - EC_IOCTL_DEF(EC_IOCTL_SLAVE_SOE_READ), - EC_IOCTL_DEF(EC_IOCTL_SLAVE_SOE_WRITE), - EC_IOCTL_DEF(EC_IOCTL_SLAVE_EOE_IP_PARAM), - EC_IOCTL_DEF(EC_IOCTL_CONFIG), - EC_IOCTL_DEF(EC_IOCTL_CONFIG_PDO), - EC_IOCTL_DEF(EC_IOCTL_CONFIG_PDO_ENTRY), - EC_IOCTL_DEF(EC_IOCTL_CONFIG_SDO), - EC_IOCTL_DEF(EC_IOCTL_CONFIG_IDN), -#ifdef EC_EOE - EC_IOCTL_DEF(EC_IOCTL_EOE_HANDLER), -#endif - EC_IOCTL_DEF(EC_IOCTL_SLAVE_DICT_UPLOAD), - EC_IOCTL_DEF(EC_IOCTL_REQUEST), - EC_IOCTL_DEF(EC_IOCTL_CREATE_DOMAIN), - EC_IOCTL_DEF(EC_IOCTL_CREATE_SLAVE_CONFIG), - EC_IOCTL_DEF(EC_IOCTL_SELECT_REF_CLOCK), - EC_IOCTL_DEF(EC_IOCTL_ACTIVATE), - EC_IOCTL_DEF(EC_IOCTL_DEACTIVATE), - EC_IOCTL_DEF(EC_IOCTL_SEND), - EC_IOCTL_DEF(EC_IOCTL_RECEIVE), - EC_IOCTL_DEF(EC_IOCTL_MASTER_STATE), - EC_IOCTL_DEF(EC_IOCTL_MASTER_LINK_STATE), - EC_IOCTL_DEF(EC_IOCTL_APP_TIME), - EC_IOCTL_DEF(EC_IOCTL_SYNC_REF), - EC_IOCTL_DEF(EC_IOCTL_SYNC_SLAVES), - EC_IOCTL_DEF(EC_IOCTL_REF_CLOCK_TIME), - EC_IOCTL_DEF(EC_IOCTL_SYNC_MON_QUEUE), - EC_IOCTL_DEF(EC_IOCTL_SYNC_MON_PROCESS), - EC_IOCTL_DEF(EC_IOCTL_RESET), - EC_IOCTL_DEF(EC_IOCTL_SC_SYNC), - EC_IOCTL_DEF(EC_IOCTL_SC_WATCHDOG), - EC_IOCTL_DEF(EC_IOCTL_SC_ADD_PDO), - EC_IOCTL_DEF(EC_IOCTL_SC_CLEAR_PDOS), - EC_IOCTL_DEF(EC_IOCTL_SC_ADD_ENTRY), - EC_IOCTL_DEF(EC_IOCTL_SC_CLEAR_ENTRIES), - EC_IOCTL_DEF(EC_IOCTL_SC_REG_PDO_ENTRY), - EC_IOCTL_DEF(EC_IOCTL_SC_REG_PDO_POS), - EC_IOCTL_DEF(EC_IOCTL_SC_DC), - EC_IOCTL_DEF(EC_IOCTL_SC_SDO), - EC_IOCTL_DEF(EC_IOCTL_SC_EMERG_SIZE), - EC_IOCTL_DEF(EC_IOCTL_SC_EMERG_POP), - EC_IOCTL_DEF(EC_IOCTL_SC_EMERG_CLEAR), - EC_IOCTL_DEF(EC_IOCTL_SC_EMERG_OVERRUNS), - EC_IOCTL_DEF(EC_IOCTL_SC_SDO_REQUEST), - EC_IOCTL_DEF(EC_IOCTL_SC_REG_REQUEST), - EC_IOCTL_DEF(EC_IOCTL_SC_VOE), - EC_IOCTL_DEF(EC_IOCTL_SC_STATE), - EC_IOCTL_DEF(EC_IOCTL_SC_IDN), - EC_IOCTL_DEF(EC_IOCTL_DOMAIN_SIZE), - EC_IOCTL_DEF(EC_IOCTL_DOMAIN_OFFSET), - EC_IOCTL_DEF(EC_IOCTL_DOMAIN_PROCESS), - EC_IOCTL_DEF(EC_IOCTL_DOMAIN_QUEUE), - EC_IOCTL_DEF(EC_IOCTL_DOMAIN_STATE), - EC_IOCTL_DEF(EC_IOCTL_SDO_REQUEST_INDEX), - EC_IOCTL_DEF(EC_IOCTL_SDO_REQUEST_TIMEOUT), - EC_IOCTL_DEF(EC_IOCTL_SDO_REQUEST_STATE), - EC_IOCTL_DEF(EC_IOCTL_SDO_REQUEST_READ), - EC_IOCTL_DEF(EC_IOCTL_SDO_REQUEST_WRITE), - EC_IOCTL_DEF(EC_IOCTL_SDO_REQUEST_DATA), - EC_IOCTL_DEF(EC_IOCTL_REG_REQUEST_DATA), - EC_IOCTL_DEF(EC_IOCTL_REG_REQUEST_STATE), - EC_IOCTL_DEF(EC_IOCTL_REG_REQUEST_WRITE), - EC_IOCTL_DEF(EC_IOCTL_REG_REQUEST_READ), - EC_IOCTL_DEF(EC_IOCTL_VOE_SEND_HEADER), - EC_IOCTL_DEF(EC_IOCTL_VOE_REC_HEADER), - EC_IOCTL_DEF(EC_IOCTL_VOE_READ), - EC_IOCTL_DEF(EC_IOCTL_VOE_READ_NOSYNC), - EC_IOCTL_DEF(EC_IOCTL_VOE_WRITE), - EC_IOCTL_DEF(EC_IOCTL_VOE_EXEC), - EC_IOCTL_DEF(EC_IOCTL_VOE_DATA), - EC_IOCTL_DEF(EC_IOCTL_SET_SEND_INTERVAL), - EC_IOCTL_DEF(EC_IOCTL_SC_OVERLAPPING_IO), - EC_IOCTL_DEF(EC_IOCTL_SLAVE_REBOOT), - EC_IOCTL_DEF(EC_IOCTL_SLAVE_REG_READWRITE), - EC_IOCTL_DEF(EC_IOCTL_REG_REQUEST_READWRITE), - EC_IOCTL_DEF(EC_IOCTL_SETUP_DOMAIN_MEMORY), - EC_IOCTL_DEF(EC_IOCTL_DEACTIVATE_SLAVES), - EC_IOCTL_DEF(EC_IOCTL_64_REF_CLK_TIME_QUEUE), - EC_IOCTL_DEF(EC_IOCTL_64_REF_CLK_TIME), - EC_IOCTL_DEF(EC_IOCTL_SC_FOE_REQUEST), - EC_IOCTL_DEF(EC_IOCTL_FOE_REQUEST_FILE), - EC_IOCTL_DEF(EC_IOCTL_FOE_REQUEST_TIMEOUT), - EC_IOCTL_DEF(EC_IOCTL_FOE_REQUEST_STATE), - EC_IOCTL_DEF(EC_IOCTL_FOE_REQUEST_READ), - EC_IOCTL_DEF(EC_IOCTL_FOE_REQUEST_WRITE), - EC_IOCTL_DEF(EC_IOCTL_FOE_REQUEST_DATA), - EC_IOCTL_DEF(EC_IOCTL_RT_SLAVE_REQUESTS), - EC_IOCTL_DEF(EC_IOCTL_EXEC_SLAVE_REQUESTS), -}; -#endif - -static int ec_rtdm_ioctl_rt(struct rtdm_fd *fd, unsigned int request, +static int ec_rtdm_ioctl_rt_handler(struct rtdm_fd *fd, unsigned int request, void __user *arg) { + int result; struct ec_rtdm_context *ctx = rtdm_fd_to_private(fd); struct rtdm_device *dev = rtdm_fd_device(fd); ec_rtdm_dev_t *rtdm_dev = dev->device_data; -#if DEBUG_RTDM - unsigned int nr = _IOC_NR(request); - const struct ec_ioctl_desc *ioctl = &ec_ioctls[nr]; + result = ec_ioctl_rtdm_rt(rtdm_dev->master, &ctx->ioctl_ctx, request, arg); - EC_MASTER_INFO(rtdm_dev->master, "ioctl_rt(request = %u, ctl = %02x %s)" - " on RTDM device %s.\n", request, _IOC_NR(request),ioctl->name, - dev->name); -#endif - - /* - * FIXME: Execute ioctls from non-rt context except below ioctls to - * avoid any unknown system hanging. - */ - switch (request) { - case EC_IOCTL_SEND: - case EC_IOCTL_RECEIVE: - case EC_IOCTL_MASTER_STATE: - case EC_IOCTL_APP_TIME: - case EC_IOCTL_SYNC_REF: - case EC_IOCTL_SYNC_SLAVES: - case EC_IOCTL_REF_CLOCK_TIME: - case EC_IOCTL_SC_STATE: - case EC_IOCTL_DOMAIN_PROCESS: - case EC_IOCTL_DOMAIN_QUEUE: - case EC_IOCTL_DOMAIN_STATE: - break; - default: + if (result == -ENOTTY) + /* Try again with nrt ioctl handler below in secondary mode. */ return -ENOSYS; - } - return ec_ioctl_rtdm(rtdm_dev->master, &ctx->ioctl_ctx, request, arg); + return result; } -static int ec_rtdm_ioctl(struct rtdm_fd *fd, unsigned int request, +static int ec_rtdm_ioctl_nrt_handler(struct rtdm_fd *fd, unsigned int request, void __user *arg) { struct ec_rtdm_context *ctx = rtdm_fd_to_private(fd); struct rtdm_device *dev = rtdm_fd_device(fd); ec_rtdm_dev_t *rtdm_dev = dev->device_data; -#if DEBUG_RTDM - unsigned int nr = _IOC_NR(request); - const struct ec_ioctl_desc *ioctl = &ec_ioctls[nr]; - - EC_MASTER_INFO(rtdm_dev->master, "ioctl(request = %u, ctl = %02x %s)" - " on RTDM device %s.\n", request, _IOC_NR(request),ioctl->name, - dev->name); -#endif - - return ec_ioctl_rtdm(rtdm_dev->master, &ctx->ioctl_ctx, request, arg); + return ec_ioctl_rtdm_nrt(rtdm_dev->master, &ctx->ioctl_ctx, request, arg); } static int ec_rtdm_mmap(struct rtdm_fd *fd, struct vm_area_struct *vma) @@ -286,8 +128,8 @@ static struct rtdm_driver ec_rtdm_driver = { .ops = { .open = ec_rtdm_open, .close = ec_rtdm_close, - .ioctl_rt = ec_rtdm_ioctl_rt, - .ioctl_nrt = ec_rtdm_ioctl, + .ioctl_rt = ec_rtdm_ioctl_rt_handler, + .ioctl_nrt = ec_rtdm_ioctl_nrt_handler, .mmap = ec_rtdm_mmap, }, };