IgH EtherCAT Master  1.5.2
rtdm_xenomai_v3.c
Go to the documentation of this file.
1 /*****************************************************************************
2  *
3  * $Id$
4  *
5  * Copyright (C) 2009-2010 Moehwald GmbH B. Benner
6  * 2011 IgH Andreas Stewering-Bone
7  * 2012 Florian Pose <fp@igh-essen.com>
8  *
9  * This file is part of the IgH EtherCAT master.
10  *
11  * The IgH EtherCAT master is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License as published
13  * by the Free Software Foundation; version 2 of the License.
14  *
15  * The IgH EtherCAT master is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
18  * Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License along
21  * with the IgH EtherCAT master. If not, see <http://www.gnu.org/licenses/>.
22  *
23  * The license mentioned above concerns the source code only. Using the
24  * EtherCAT technology and brand is only permitted in compliance with the
25  * industrial property and similar rights of Beckhoff Automation GmbH.
26  *
27  ****************************************************************************/
28 
33 #include <linux/module.h>
34 #include <linux/vmalloc.h>
35 #include <rtdm/driver.h>
36 
37 #include "master.h"
38 #include "ioctl.h"
39 #include "rtdm.h"
40 
43 #define DEBUG_RTDM 0
44 
46  struct rtdm_fd *fd;
47  ec_ioctl_context_t ioctl_ctx;
48 };
49 
50 static int ec_rtdm_open(struct rtdm_fd *fd, int oflags)
51 {
52  struct ec_rtdm_context *ctx = rtdm_fd_to_private(fd);
53 #if DEBUG_RTDM
54  struct rtdm_device *dev = rtdm_fd_device(fd);
55  ec_rtdm_dev_t *rtdm_dev = dev->device_data;
56 #endif
57 
58  ctx->fd = fd;
59 
60  ctx->ioctl_ctx.writable = oflags & O_WRONLY || oflags & O_RDWR;
61  ctx->ioctl_ctx.requested = 0;
62  ctx->ioctl_ctx.process_data = NULL;
63  ctx->ioctl_ctx.process_data_size = 0;
64 
65 #if DEBUG_RTDM
66  EC_MASTER_INFO(rtdm_dev->master, "RTDM device %s opened.\n",
67  dev->name);
68 #endif
69 
70  return 0;
71 }
72 
73 static void ec_rtdm_close(struct rtdm_fd *fd)
74 {
75  struct ec_rtdm_context *ctx = rtdm_fd_to_private(fd);
76  struct rtdm_device *dev = rtdm_fd_device(fd);
77  ec_rtdm_dev_t *rtdm_dev = dev->device_data;
78 
79  if (ctx->ioctl_ctx.requested)
80  ecrt_release_master(rtdm_dev->master);
81 
82  if (ctx->ioctl_ctx.process_data)
83  vfree(ctx->ioctl_ctx.process_data);
84 
85 #if DEBUG_RTDM
86  EC_MASTER_INFO(rtdm_dev->master, "RTDM device %s closed.\n",
87  dev->name);
88 #endif
89 }
90 
91 #if DEBUG_RTDM
92 struct ec_ioctl_desc {
93  unsigned int cmd;
94  const char *name;
95 };
96 
97 #define EC_IOCTL_DEF(ioctl) \
98  [_IOC_NR(ioctl)] = { \
99  .cmd = ioctl, \
100  .name = #ioctl \
101  }
102 
103 static const struct ec_ioctl_desc ec_ioctls[] = {
104  EC_IOCTL_DEF(EC_IOCTL_MODULE),
105  EC_IOCTL_DEF(EC_IOCTL_MASTER),
106  EC_IOCTL_DEF(EC_IOCTL_SLAVE),
107  EC_IOCTL_DEF(EC_IOCTL_SLAVE_SYNC),
108  EC_IOCTL_DEF(EC_IOCTL_SLAVE_SYNC_PDO),
109  EC_IOCTL_DEF(EC_IOCTL_SLAVE_SYNC_PDO_ENTRY),
110  EC_IOCTL_DEF(EC_IOCTL_DOMAIN),
111  EC_IOCTL_DEF(EC_IOCTL_DOMAIN_FMMU),
112  EC_IOCTL_DEF(EC_IOCTL_DOMAIN_DATA),
113  EC_IOCTL_DEF(EC_IOCTL_MASTER_DEBUG),
114  EC_IOCTL_DEF(EC_IOCTL_MASTER_RESCAN),
115  EC_IOCTL_DEF(EC_IOCTL_SLAVE_STATE),
116  EC_IOCTL_DEF(EC_IOCTL_SLAVE_SDO),
117  EC_IOCTL_DEF(EC_IOCTL_SLAVE_SDO_ENTRY),
118  EC_IOCTL_DEF(EC_IOCTL_SLAVE_SDO_UPLOAD),
119  EC_IOCTL_DEF(EC_IOCTL_SLAVE_SDO_DOWNLOAD),
120  EC_IOCTL_DEF(EC_IOCTL_SLAVE_SII_READ),
121  EC_IOCTL_DEF(EC_IOCTL_SLAVE_SII_WRITE),
122  EC_IOCTL_DEF(EC_IOCTL_SLAVE_REG_READ),
123  EC_IOCTL_DEF(EC_IOCTL_SLAVE_REG_WRITE),
124  EC_IOCTL_DEF(EC_IOCTL_SLAVE_FOE_READ),
125  EC_IOCTL_DEF(EC_IOCTL_SLAVE_FOE_WRITE),
126  EC_IOCTL_DEF(EC_IOCTL_SLAVE_SOE_READ),
127  EC_IOCTL_DEF(EC_IOCTL_SLAVE_SOE_WRITE),
128  EC_IOCTL_DEF(EC_IOCTL_SLAVE_EOE_IP_PARAM),
129  EC_IOCTL_DEF(EC_IOCTL_CONFIG),
130  EC_IOCTL_DEF(EC_IOCTL_CONFIG_PDO),
131  EC_IOCTL_DEF(EC_IOCTL_CONFIG_PDO_ENTRY),
132  EC_IOCTL_DEF(EC_IOCTL_CONFIG_SDO),
133  EC_IOCTL_DEF(EC_IOCTL_CONFIG_IDN),
134 #ifdef EC_EOE
135  EC_IOCTL_DEF(EC_IOCTL_EOE_HANDLER),
136 #endif
137  EC_IOCTL_DEF(EC_IOCTL_SLAVE_DICT_UPLOAD),
138  EC_IOCTL_DEF(EC_IOCTL_REQUEST),
139  EC_IOCTL_DEF(EC_IOCTL_CREATE_DOMAIN),
140  EC_IOCTL_DEF(EC_IOCTL_CREATE_SLAVE_CONFIG),
141  EC_IOCTL_DEF(EC_IOCTL_SELECT_REF_CLOCK),
142  EC_IOCTL_DEF(EC_IOCTL_ACTIVATE),
143  EC_IOCTL_DEF(EC_IOCTL_DEACTIVATE),
144  EC_IOCTL_DEF(EC_IOCTL_SEND),
145  EC_IOCTL_DEF(EC_IOCTL_RECEIVE),
146  EC_IOCTL_DEF(EC_IOCTL_MASTER_STATE),
147  EC_IOCTL_DEF(EC_IOCTL_MASTER_LINK_STATE),
148  EC_IOCTL_DEF(EC_IOCTL_APP_TIME),
149  EC_IOCTL_DEF(EC_IOCTL_SYNC_REF),
150  EC_IOCTL_DEF(EC_IOCTL_SYNC_SLAVES),
151  EC_IOCTL_DEF(EC_IOCTL_REF_CLOCK_TIME),
152  EC_IOCTL_DEF(EC_IOCTL_SYNC_MON_QUEUE),
153  EC_IOCTL_DEF(EC_IOCTL_SYNC_MON_PROCESS),
154  EC_IOCTL_DEF(EC_IOCTL_RESET),
155  EC_IOCTL_DEF(EC_IOCTL_SC_SYNC),
156  EC_IOCTL_DEF(EC_IOCTL_SC_WATCHDOG),
157  EC_IOCTL_DEF(EC_IOCTL_SC_ADD_PDO),
158  EC_IOCTL_DEF(EC_IOCTL_SC_CLEAR_PDOS),
159  EC_IOCTL_DEF(EC_IOCTL_SC_ADD_ENTRY),
160  EC_IOCTL_DEF(EC_IOCTL_SC_CLEAR_ENTRIES),
161  EC_IOCTL_DEF(EC_IOCTL_SC_REG_PDO_ENTRY),
162  EC_IOCTL_DEF(EC_IOCTL_SC_REG_PDO_POS),
163  EC_IOCTL_DEF(EC_IOCTL_SC_DC),
164  EC_IOCTL_DEF(EC_IOCTL_SC_SDO),
165  EC_IOCTL_DEF(EC_IOCTL_SC_EMERG_SIZE),
166  EC_IOCTL_DEF(EC_IOCTL_SC_EMERG_POP),
167  EC_IOCTL_DEF(EC_IOCTL_SC_EMERG_CLEAR),
168  EC_IOCTL_DEF(EC_IOCTL_SC_EMERG_OVERRUNS),
169  EC_IOCTL_DEF(EC_IOCTL_SC_SDO_REQUEST),
170  EC_IOCTL_DEF(EC_IOCTL_SC_REG_REQUEST),
171  EC_IOCTL_DEF(EC_IOCTL_SC_VOE),
172  EC_IOCTL_DEF(EC_IOCTL_SC_STATE),
173  EC_IOCTL_DEF(EC_IOCTL_SC_IDN),
174  EC_IOCTL_DEF(EC_IOCTL_DOMAIN_SIZE),
175  EC_IOCTL_DEF(EC_IOCTL_DOMAIN_OFFSET),
176  EC_IOCTL_DEF(EC_IOCTL_DOMAIN_PROCESS),
177  EC_IOCTL_DEF(EC_IOCTL_DOMAIN_QUEUE),
178  EC_IOCTL_DEF(EC_IOCTL_DOMAIN_STATE),
179  EC_IOCTL_DEF(EC_IOCTL_SDO_REQUEST_INDEX),
180  EC_IOCTL_DEF(EC_IOCTL_SDO_REQUEST_TIMEOUT),
181  EC_IOCTL_DEF(EC_IOCTL_SDO_REQUEST_STATE),
182  EC_IOCTL_DEF(EC_IOCTL_SDO_REQUEST_READ),
183  EC_IOCTL_DEF(EC_IOCTL_SDO_REQUEST_WRITE),
184  EC_IOCTL_DEF(EC_IOCTL_SDO_REQUEST_DATA),
185  EC_IOCTL_DEF(EC_IOCTL_REG_REQUEST_DATA),
186  EC_IOCTL_DEF(EC_IOCTL_REG_REQUEST_STATE),
187  EC_IOCTL_DEF(EC_IOCTL_REG_REQUEST_WRITE),
188  EC_IOCTL_DEF(EC_IOCTL_REG_REQUEST_READ),
189  EC_IOCTL_DEF(EC_IOCTL_VOE_SEND_HEADER),
190  EC_IOCTL_DEF(EC_IOCTL_VOE_REC_HEADER),
191  EC_IOCTL_DEF(EC_IOCTL_VOE_READ),
192  EC_IOCTL_DEF(EC_IOCTL_VOE_READ_NOSYNC),
193  EC_IOCTL_DEF(EC_IOCTL_VOE_WRITE),
194  EC_IOCTL_DEF(EC_IOCTL_VOE_EXEC),
195  EC_IOCTL_DEF(EC_IOCTL_VOE_DATA),
196  EC_IOCTL_DEF(EC_IOCTL_SET_SEND_INTERVAL),
197  EC_IOCTL_DEF(EC_IOCTL_SC_OVERLAPPING_IO),
198  EC_IOCTL_DEF(EC_IOCTL_SLAVE_REBOOT),
199  EC_IOCTL_DEF(EC_IOCTL_SLAVE_REG_READWRITE),
200  EC_IOCTL_DEF(EC_IOCTL_REG_REQUEST_READWRITE),
201  EC_IOCTL_DEF(EC_IOCTL_SETUP_DOMAIN_MEMORY),
202  EC_IOCTL_DEF(EC_IOCTL_DEACTIVATE_SLAVES),
203  EC_IOCTL_DEF(EC_IOCTL_64_REF_CLK_TIME_QUEUE),
204  EC_IOCTL_DEF(EC_IOCTL_64_REF_CLK_TIME),
205  EC_IOCTL_DEF(EC_IOCTL_SC_FOE_REQUEST),
206  EC_IOCTL_DEF(EC_IOCTL_FOE_REQUEST_FILE),
207  EC_IOCTL_DEF(EC_IOCTL_FOE_REQUEST_TIMEOUT),
208  EC_IOCTL_DEF(EC_IOCTL_FOE_REQUEST_STATE),
209  EC_IOCTL_DEF(EC_IOCTL_FOE_REQUEST_READ),
210  EC_IOCTL_DEF(EC_IOCTL_FOE_REQUEST_WRITE),
211  EC_IOCTL_DEF(EC_IOCTL_FOE_REQUEST_DATA),
212  EC_IOCTL_DEF(EC_IOCTL_RT_SLAVE_REQUESTS),
213  EC_IOCTL_DEF(EC_IOCTL_EXEC_SLAVE_REQUESTS),
214 };
215 #endif
216 
217 static int ec_rtdm_ioctl_rt(struct rtdm_fd *fd, unsigned int request,
218  void __user *arg)
219 {
220  struct ec_rtdm_context *ctx = rtdm_fd_to_private(fd);
221  struct rtdm_device *dev = rtdm_fd_device(fd);
222  ec_rtdm_dev_t *rtdm_dev = dev->device_data;
223 
224 #if DEBUG_RTDM
225  unsigned int nr = _IOC_NR(request);
226  const struct ec_ioctl_desc *ioctl = &ec_ioctls[nr];
227 
228  EC_MASTER_INFO(rtdm_dev->master, "ioctl_rt(request = %u, ctl = %02x %s)"
229  " on RTDM device %s.\n", request, _IOC_NR(request),ioctl->name,
230  dev->name);
231 #endif
232 
233  /*
234  * FIXME: Execute ioctls from non-rt context except below ioctls to
235  * avoid any unknown system hanging.
236  */
237  switch (request) {
238  case EC_IOCTL_SEND:
239  case EC_IOCTL_RECEIVE:
240  case EC_IOCTL_MASTER_STATE:
241  case EC_IOCTL_APP_TIME:
242  case EC_IOCTL_SYNC_REF:
243  case EC_IOCTL_SYNC_SLAVES:
244  case EC_IOCTL_REF_CLOCK_TIME:
245  case EC_IOCTL_SC_STATE:
246  case EC_IOCTL_DOMAIN_PROCESS:
247  case EC_IOCTL_DOMAIN_QUEUE:
248  case EC_IOCTL_DOMAIN_STATE:
249  break;
250  default:
251  return -ENOSYS;
252  }
253 
254  return ec_ioctl_rtdm(rtdm_dev->master, &ctx->ioctl_ctx, request, arg);
255 }
256 
257 static int ec_rtdm_ioctl(struct rtdm_fd *fd, unsigned int request,
258  void __user *arg)
259 {
260  struct ec_rtdm_context *ctx = rtdm_fd_to_private(fd);
261  struct rtdm_device *dev = rtdm_fd_device(fd);
262  ec_rtdm_dev_t *rtdm_dev = dev->device_data;
263 
264 #if DEBUG_RTDM
265  unsigned int nr = _IOC_NR(request);
266  const struct ec_ioctl_desc *ioctl = &ec_ioctls[nr];
267 
268  EC_MASTER_INFO(rtdm_dev->master, "ioctl(request = %u, ctl = %02x %s)"
269  " on RTDM device %s.\n", request, _IOC_NR(request),ioctl->name,
270  dev->name);
271 #endif
272 
273  return ec_ioctl_rtdm(rtdm_dev->master, &ctx->ioctl_ctx, request, arg);
274 }
275 
276 static struct rtdm_driver ec_rtdm_driver = {
277  .profile_info = RTDM_PROFILE_INFO(ec_rtdm,
278  RTDM_CLASS_EXPERIMENTAL,
279  222,
280  0),
281  .device_flags = RTDM_NAMED_DEVICE,
282  .device_count = 1,
283  .context_size = sizeof(struct ec_rtdm_context),
284  .ops = {
285  .open = ec_rtdm_open,
286  .close = ec_rtdm_close,
287  .ioctl_rt = ec_rtdm_ioctl_rt,
288  .ioctl_nrt = ec_rtdm_ioctl,
289  },
290 };
291 
293 {
294  struct rtdm_device *dev;
295  int ret;
296 
297  rtdm_dev->master = master;
298 
299  rtdm_dev->dev = kzalloc(sizeof(struct rtdm_device), GFP_KERNEL);
300  if (!rtdm_dev->dev) {
301  EC_MASTER_ERR(master,
302  "Failed to reserve memory for RTDM device.\n");
303  return -ENOMEM;
304  }
305 
306  dev = rtdm_dev->dev;
307 
308  dev->driver = &ec_rtdm_driver;
309  dev->device_data = rtdm_dev;
310  dev->label = "EtherCAT%u";
311 
312  ret = rtdm_dev_register(dev);
313  if (ret) {
314  EC_MASTER_ERR(master, "Initialization of RTDM interface failed"
315  " (return value %i).\n", ret);
316  kfree(dev);
317  return ret;
318  }
319 
320  EC_MASTER_INFO(master, "Registered RTDM device %s.\n", dev->name);
321 
322  return 0;
323 }
324 
326 {
327  rtdm_dev_unregister(rtdm_dev->dev);
328 
329  EC_MASTER_INFO(rtdm_dev->master, "Unregistered RTDM device %s.\n",
330  rtdm_dev->dev->name);
331 
332  kfree(rtdm_dev->dev);
333 }
334 
335 int ec_rtdm_mmap(ec_ioctl_context_t *ioctl_ctx, void **user_address)
336 {
337  struct ec_rtdm_context *ctx =
338  container_of(ioctl_ctx, struct ec_rtdm_context, ioctl_ctx);
339  int ret;
340 
341  ret = rtdm_mmap_to_user(ctx->fd,
342  ioctl_ctx->process_data, ioctl_ctx->process_data_size,
343  PROT_READ | PROT_WRITE,
344  user_address,
345  NULL, NULL);
346  if (ret < 0)
347  return ret;
348 
349  return 0;
350 }
ec_ioctl_context_t ioctl_ctx
Context structure.
void ecrt_release_master(ec_master_t *master)
Releases a requested EtherCAT master.
Definition: module.c:628
struct rtdm_device * dev
RTDM device.
Definition: rtdm.h:46
ec_master_t * master
Master pointer.
Definition: rtdm.h:45
EtherCAT RTDM device.
Definition: rtdm.h:44
int ec_rtdm_close(struct rtdm_dev_context *, rtdm_user_info_t *)
Driver close.
Definition: rtdm.c:171
EtherCAT master structure.
void ec_rtdm_dev_clear(ec_rtdm_dev_t *rtdm_dev)
Clear an RTDM device.
int ec_rtdm_dev_init(ec_rtdm_dev_t *rtdm_dev, ec_master_t *master)
Initialize an RTDM device.
int ec_rtdm_ioctl(struct rtdm_dev_context *, rtdm_user_info_t *, unsigned int, void __user *)
Driver ioctl.
Definition: rtdm.c:196
#define EC_MASTER_ERR(master, fmt, args...)
Convenience macro for printing master-specific errors to syslog.
Definition: master.h:80
int ec_rtdm_mmap(ec_ioctl_context_t *ioctl_ctx, void **user_address)
Memory-map process data to user space.
Definition: rtdm.c:220
EtherCAT master character device IOCTL commands.
int ec_rtdm_open(struct rtdm_dev_context *, rtdm_user_info_t *, int)
Driver open.
Definition: rtdm.c:141
#define EC_MASTER_INFO(master, fmt, args...)
Convenience macro for printing master-specific information to syslog.
Definition: master.h:68
EtherCAT master.
Definition: master.h:202
RTDM interface.