IgH EtherCAT Master  1.6.1
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 
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 
46 static int ec_rtdm_open(struct rtdm_dev_context *, rtdm_user_info_t *, int);
47 static int ec_rtdm_close(struct rtdm_dev_context *, rtdm_user_info_t *);
48 static int ec_rtdm_ioctl_nrt_handler(struct rtdm_dev_context *,
49  rtdm_user_info_t *, unsigned int, void __user *);
50 static 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 
131 static 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 
161 static 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 /****************************************************************************/
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
int ec_rtdm_dev_init(ec_rtdm_dev_t *rtdm_dev, ec_master_t *master)
Initialize an RTDM device.
Definition: rtdm.c:59
ec_ioctl_context_t ioctl_ctx
Context structure.
Definition: rtdm_details.h:48
static int ec_rtdm_close(struct rtdm_dev_context *, rtdm_user_info_t *)
Driver close.
Definition: rtdm.c:161
struct rtdm_device * dev
RTDM device.
Definition: rtdm.h:40
static int ec_rtdm_open(struct rtdm_dev_context *, rtdm_user_info_t *, int)
Driver open.
Definition: rtdm.c:131
ec_master_t * master
Master pointer.
Definition: rtdm.h:39
EtherCAT RTDM device.
Definition: rtdm.h:38
Context structure for an open RTDM file handle.
Definition: rtdm_details.h:46
#define DEBUG
Set to 1 to enable device operations debugging.
Definition: rtdm.c:42
EtherCAT master structure.
EC_RTDM_USERFD_T * user_fd
RTDM user data.
Definition: rtdm_details.h:47
#define EC_MASTER_WARN(master, fmt, args...)
Convenience macro for printing master-specific warnings to syslog.
Definition: master.h:86
#define EC_MASTER_ERR(master, fmt, args...)
Convenience macro for printing master-specific errors to syslog.
Definition: master.h:74
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
static int ec_rtdm_ioctl_rt_handler(struct rtdm_dev_context *, rtdm_user_info_t *, unsigned int, void __user *)
Definition: rtdm.c:206
EtherCAT master character device IOCTL commands.
unsigned int index
Index.
Definition: master.h:188
#define EC_MASTER_INFO(master, fmt, args...)
Convenience macro for printing master-specific information to syslog.
Definition: master.h:62
EtherCAT master.
Definition: master.h:187
void ecrt_release_master(ec_master_t *master)
Releases a requested EtherCAT master.
Definition: module.c:621
RTDM interface.