IgH EtherCAT Master  1.6.9
rtdm.c
Go to the documentation of this file.
1/*****************************************************************************
2 *
3 * Copyright (C) 2009-2010 Moehwald GmbH B. Benner
4 * 2011 IgH Andreas Stewering-Bone
5 * 2012 Florian Pose <fp@igh.de>
6 *
7 * This file is part of the IgH EtherCAT master.
8 *
9 * The IgH EtherCAT master is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as published
11 * by the Free Software Foundation; version 2 of the License.
12 *
13 * The IgH EtherCAT master is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16 * Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with the IgH EtherCAT master. If not, see <http://www.gnu.org/licenses/>.
20 *
21 ****************************************************************************/
22
26
27#include <linux/module.h>
28#include <linux/slab.h>
29#include <linux/mman.h>
30
31
32#include "master.h"
33#include "ioctl.h"
34#include "rtdm.h"
35#include "rtdm_details.h"
36
37/* include last because it does some redefinitions */
38#include <rtdm/rtdm_driver.h>
39
42#define DEBUG 0
43
44/****************************************************************************/
45
46static int ec_rtdm_open(struct rtdm_dev_context *, rtdm_user_info_t *, int);
47static int ec_rtdm_close(struct rtdm_dev_context *, rtdm_user_info_t *);
48static int ec_rtdm_ioctl_nrt_handler(struct rtdm_dev_context *,
49 rtdm_user_info_t *, unsigned int, void __user *);
50static int ec_rtdm_ioctl_rt_handler(struct rtdm_dev_context *,
51 rtdm_user_info_t *, unsigned int, void __user *);
52
53/****************************************************************************/
54
60 ec_rtdm_dev_t *rtdm_dev,
61 ec_master_t *master
62 )
63{
64 int ret;
65
66 rtdm_dev->master = master;
67
68 rtdm_dev->dev = kzalloc(sizeof(struct rtdm_device), GFP_KERNEL);
69 if (!rtdm_dev->dev) {
70 EC_MASTER_ERR(master, "Failed to reserve memory for RTDM device.\n");
71 return -ENOMEM;
72 }
73
74 rtdm_dev->dev->struct_version = RTDM_DEVICE_STRUCT_VER;
75 rtdm_dev->dev->device_flags = RTDM_NAMED_DEVICE;
76 rtdm_dev->dev->context_size = sizeof(ec_rtdm_context_t);
77 snprintf(rtdm_dev->dev->device_name, RTDM_MAX_DEVNAME_LEN,
78 "EtherCAT%u", master->index);
79 rtdm_dev->dev->open_nrt = ec_rtdm_open;
80 rtdm_dev->dev->ops.close_nrt = ec_rtdm_close;
81 rtdm_dev->dev->ops.ioctl_rt = ec_rtdm_ioctl_rt_handler;
82 rtdm_dev->dev->ops.ioctl_nrt = ec_rtdm_ioctl_nrt_handler;
83 rtdm_dev->dev->device_class = RTDM_CLASS_EXPERIMENTAL;
84 rtdm_dev->dev->device_sub_class = 222;
85 rtdm_dev->dev->driver_name = "EtherCAT";
86 rtdm_dev->dev->driver_version = RTDM_DRIVER_VER(1, 0, 2);
87 rtdm_dev->dev->peripheral_name = rtdm_dev->dev->device_name;
88 rtdm_dev->dev->provider_name = "EtherLab Community";
89 rtdm_dev->dev->proc_name = rtdm_dev->dev->device_name;
90 rtdm_dev->dev->device_data = rtdm_dev; /* pointer to parent */
91
92 EC_MASTER_INFO(master, "Registering RTDM device %s.\n",
93 rtdm_dev->dev->driver_name);
94 ret = rtdm_dev_register(rtdm_dev->dev);
95 if (ret) {
96 EC_MASTER_ERR(master, "Initialization of RTDM interface failed"
97 " (return value %i).\n", ret);
98 kfree(rtdm_dev->dev);
99 }
100
101 return ret;
102}
103
104/****************************************************************************/
105
109 ec_rtdm_dev_t *rtdm_dev
110 )
111{
112 int ret;
113
114 EC_MASTER_INFO(rtdm_dev->master, "Unregistering RTDM device %s.\n",
115 rtdm_dev->dev->driver_name);
116 ret = rtdm_dev_unregister(rtdm_dev->dev, 1000 /* poll delay [ms] */);
117 if (ret < 0) {
118 EC_MASTER_WARN(rtdm_dev->master,
119 "Failed to unregister RTDM device (code %i).\n", ret);
120 }
121
122 kfree(rtdm_dev->dev);
123}
124
125/****************************************************************************/
126
131static int ec_rtdm_open(
132 struct rtdm_dev_context *context,
133 rtdm_user_info_t *user_info,
134 int oflags
135 )
136{
137 ec_rtdm_context_t *ctx = (ec_rtdm_context_t *) context->dev_private;
138#if DEBUG
139 ec_rtdm_dev_t *rtdm_dev = (ec_rtdm_dev_t *) context->device->device_data;
140#endif
141
142 ctx->user_fd = user_info;
143 ctx->ioctl_ctx.writable = oflags & O_WRONLY || oflags & O_RDWR;
144 ctx->ioctl_ctx.requested = 0;
145 ctx->ioctl_ctx.process_data = NULL;
146 ctx->ioctl_ctx.process_data_size = 0;
147
148#if DEBUG
149 EC_MASTER_INFO(rtdm_dev->master, "RTDM device %s opened.\n",
150 context->device->device_name);
151#endif
152 return 0;
153}
154
155/****************************************************************************/
156
161static int ec_rtdm_close(
162 struct rtdm_dev_context *context,
163 rtdm_user_info_t *user_info
164 )
165{
166 ec_rtdm_context_t *ctx = (ec_rtdm_context_t *) context->dev_private;
167 ec_rtdm_dev_t *rtdm_dev = (ec_rtdm_dev_t *) context->device->device_data;
168
169 if (ctx->ioctl_ctx.requested) {
170 ecrt_release_master(rtdm_dev->master);
171 }
172
173#if DEBUG
174 EC_MASTER_INFO(rtdm_dev->master, "RTDM device %s closed.\n",
175 context->device->device_name);
176#endif
177 return 0;
178}
179
180/****************************************************************************/
181
187 struct rtdm_dev_context *context,
188 rtdm_user_info_t *user_info,
189 unsigned int request,
190 void __user *arg
191 )
192{
193 ec_rtdm_context_t *ctx = (ec_rtdm_context_t *) context->dev_private;
194 ec_rtdm_dev_t *rtdm_dev = (ec_rtdm_dev_t *) context->device->device_data;
195
196#if DEBUG
197 EC_MASTER_INFO(rtdm_dev->master, "ioctl(request = %u, ctl = %02x)"
198 " on RTDM device %s.\n", request, _IOC_NR(request),
199 context->device->device_name);
200#endif
201 return ec_ioctl_rtdm_nrt(rtdm_dev->master, &ctx->ioctl_ctx, request, arg);
202}
203
204/****************************************************************************/
205
207 struct rtdm_dev_context *context,
208 rtdm_user_info_t *user_info,
209 unsigned int request,
210 void __user *arg
211 )
212{
213 int result;
214 ec_rtdm_context_t *ctx = (ec_rtdm_context_t *) context->dev_private;
215 ec_rtdm_dev_t *rtdm_dev = (ec_rtdm_dev_t *) context->device->device_data;
216
217#if DEBUG
218 EC_MASTER_INFO(rtdm_dev->master, "ioctl(request = %u, ctl = %02x)"
219 " on RTDM device %s.\n", request, _IOC_NR(request),
220 context->device->device_name);
221#endif
222 result =
223 ec_ioctl_rtdm_rt(rtdm_dev->master, &ctx->ioctl_ctx, request, arg);
224
225 if (result == -ENOTTY) {
226 /* Try again with nrt ioctl handler above in secondary mode. */
227 return -ENOSYS;
228 }
229 return result;
230}
231
232/****************************************************************************/
233
239 ec_ioctl_context_t *ioctl_ctx,
240 void **user_address
241 )
242{
243 ec_rtdm_context_t *ctx =
244 container_of(ioctl_ctx, ec_rtdm_context_t, ioctl_ctx);
245 int ret;
246
247 ret = rtdm_mmap_to_user(ctx->user_fd,
248 ioctl_ctx->process_data, ioctl_ctx->process_data_size,
249 PROT_READ | PROT_WRITE,
250 user_address,
251 NULL, NULL);
252 if (ret < 0) {
253 return ret;
254 }
255
256 return 0;
257}
258
259/****************************************************************************/
void ecrt_release_master(ec_master_t *master)
Releases a requested EtherCAT master.
Definition module.c:621
struct ec_master ec_master_t
Definition ecrt.h:300
EtherCAT master character device IOCTL commands.
EtherCAT master structure.
#define EC_MASTER_INFO(master, fmt, args...)
Convenience macro for printing master-specific information to syslog.
Definition master.h:62
#define EC_MASTER_ERR(master, fmt, args...)
Convenience macro for printing master-specific errors to syslog.
Definition master.h:74
#define EC_MASTER_WARN(master, fmt, args...)
Convenience macro for printing master-specific warnings to syslog.
Definition master.h:86
int ec_rtdm_mmap(ec_ioctl_context_t *ioctl_ctx, void **user_address)
Memory-map process data to user space.
Definition rtdm.c:238
void ec_rtdm_dev_clear(ec_rtdm_dev_t *rtdm_dev)
Clear an RTDM device.
Definition rtdm.c:108
int ec_rtdm_dev_init(ec_rtdm_dev_t *rtdm_dev, ec_master_t *master)
Initialize an RTDM device.
Definition rtdm.c:59
static int ec_rtdm_close(struct rtdm_dev_context *, rtdm_user_info_t *)
Driver close.
Definition rtdm.c:161
static int ec_rtdm_ioctl_nrt_handler(struct rtdm_dev_context *, rtdm_user_info_t *, unsigned int, void __user *)
Driver ioctl.
Definition rtdm.c:186
static int ec_rtdm_open(struct rtdm_dev_context *, rtdm_user_info_t *, int)
Driver open.
Definition rtdm.c:131
static int ec_rtdm_ioctl_rt_handler(struct rtdm_dev_context *, rtdm_user_info_t *, unsigned int, void __user *)
Definition rtdm.c:206
RTDM interface.
struct ec_rtdm_dev ec_rtdm_dev_t
EtherCAT RTDM device.
unsigned int index
Index.
Definition master.h:188
ec_ioctl_context_t ioctl_ctx
Context structure.
EC_RTDM_USERFD_T * user_fd
RTDM user data.
ec_master_t * master
Master pointer.
Definition rtdm.h:39
struct rtdm_device * dev
RTDM device.
Definition rtdm.h:40