IgH EtherCAT Master  1.5.3
module.c
Go to the documentation of this file.
1 /******************************************************************************
2  *
3  * $Id$
4  *
5  * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
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 version 2, as
11  * published by the Free Software Foundation.
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, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21  *
22  * ---
23  *
24  * The license mentioned above concerns the source code only. Using the
25  * EtherCAT technology and brand is only permitted in compliance with the
26  * industrial property and similar rights of Beckhoff Automation GmbH.
27  *
28  *****************************************************************************/
29 
34 /*****************************************************************************/
35 
36 #include <linux/module.h>
37 #include <linux/device.h>
38 #include <linux/err.h>
39 
40 #include "globals.h"
41 #include "master.h"
42 #include "device.h"
43 
44 /*****************************************************************************/
45 
46 #define MAX_MASTERS 32
48 /*****************************************************************************/
49 
50 int __init ec_init_module(void);
51 void __exit ec_cleanup_module(void);
52 
53 static int ec_mac_parse(uint8_t *, const char *, int);
54 
55 /*****************************************************************************/
56 
57 static char *main_devices[MAX_MASTERS];
58 static unsigned int master_count;
59 static char *backup_devices[MAX_MASTERS];
60 static unsigned int backup_count;
61 static unsigned int debug_level;
62 static unsigned int run_on_cpu = 0xffffffff;
65 static struct semaphore master_sem;
68 struct class *class;
70 static uint8_t macs[MAX_MASTERS][2][ETH_ALEN];
72 char *ec_master_version_str = EC_MASTER_VERSION;
74 /*****************************************************************************/
75 
78 MODULE_AUTHOR("Florian Pose <fp@igh-essen.com>");
79 MODULE_DESCRIPTION("EtherCAT master driver module");
80 MODULE_LICENSE("GPL");
81 MODULE_VERSION(EC_MASTER_VERSION);
82 
83 module_param_array(main_devices, charp, &master_count, S_IRUGO);
84 MODULE_PARM_DESC(main_devices, "MAC addresses of main devices");
85 module_param_array(backup_devices, charp, &backup_count, S_IRUGO);
86 MODULE_PARM_DESC(backup_devices, "MAC addresses of backup devices");
87 module_param_named(debug_level, debug_level, uint, S_IRUGO);
88 MODULE_PARM_DESC(debug_level, "Debug level");
89 module_param_named(run_on_cpu, run_on_cpu, uint, S_IRUGO);
90 MODULE_PARM_DESC(run_on_cpu, "Bind kthreads to a specific cpu");
91 
94 /*****************************************************************************/
95 
101 int __init ec_init_module(void)
102 {
103  int i, ret = 0;
104 
105  EC_INFO("Master driver %s\n", EC_MASTER_VERSION);
106 
107  sema_init(&master_sem, 1);
108 
109  if (master_count) {
110  if (alloc_chrdev_region(&device_number,
111  0, master_count, "EtherCAT")) {
112  EC_ERR("Failed to obtain device number(s)!\n");
113  ret = -EBUSY;
114  goto out_return;
115  }
116  }
117 
118 #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0)
119  class = class_create(THIS_MODULE, "EtherCAT");
120 #else
121  class = class_create("EtherCAT");
122 #endif
123  if (IS_ERR(class)) {
124  EC_ERR("Failed to create device class.\n");
125  ret = PTR_ERR(class);
126  goto out_cdev;
127  }
128 
129  // zero MAC addresses
130  memset(macs, 0x00, sizeof(uint8_t) * MAX_MASTERS * 2 * ETH_ALEN);
131 
132  // process MAC parameters
133  for (i = 0; i < master_count; i++) {
134  ret = ec_mac_parse(macs[i][0], main_devices[i], 0);
135  if (ret)
136  goto out_class;
137 
138  if (i < backup_count) {
139  ret = ec_mac_parse(macs[i][1], backup_devices[i], 1);
140  if (ret)
141  goto out_class;
142  }
143  }
144 
145  // initialize static master variables
147 
148  if (master_count) {
149  if (!(masters = kmalloc(sizeof(ec_master_t) * master_count,
150  GFP_KERNEL))) {
151  EC_ERR("Failed to allocate memory"
152  " for EtherCAT masters.\n");
153  ret = -ENOMEM;
154  goto out_class;
155  }
156  }
157 
158  for (i = 0; i < master_count; i++) {
159  ret = ec_master_init(&masters[i], i, macs[i][0], macs[i][1],
161  if (ret)
162  goto out_free_masters;
163  }
164 
165  EC_INFO("%u master%s waiting for devices.\n",
166  master_count, (master_count == 1 ? "" : "s"));
167  return ret;
168 
169 out_free_masters:
170  for (i--; i >= 0; i--)
172  kfree(masters);
173 out_class:
174  class_destroy(class);
175 out_cdev:
176  if (master_count)
177  unregister_chrdev_region(device_number, master_count);
178 out_return:
179  return ret;
180 }
181 
182 /*****************************************************************************/
183 
188 void __exit ec_cleanup_module(void)
189 {
190  unsigned int i;
191 
192  for (i = 0; i < master_count; i++) {
194  }
195 
196  if (master_count)
197  kfree(masters);
198 
199  class_destroy(class);
200 
201  if (master_count)
202  unregister_chrdev_region(device_number, master_count);
203 
204  EC_INFO("Master module cleaned up.\n");
205 }
206 
207 /*****************************************************************************/
208 
211 unsigned int ec_master_count(void)
212 {
213  return master_count;
214 }
215 
216 /*****************************************************************************
217  * MAC address functions
218  ****************************************************************************/
219 
224  const uint8_t *mac1,
225  const uint8_t *mac2
226  )
227 {
228  unsigned int i;
229 
230  for (i = 0; i < ETH_ALEN; i++)
231  if (mac1[i] != mac2[i])
232  return 0;
233 
234  return 1;
235 }
236 
237 /*****************************************************************************/
238 
241 #define EC_MAX_MAC_STRING_SIZE (3 * ETH_ALEN)
242 
249 ssize_t ec_mac_print(
250  const uint8_t *mac,
251  char *buffer
252  )
253 {
254  off_t off = 0;
255  unsigned int i;
256 
257  for (i = 0; i < ETH_ALEN; i++) {
258  off += sprintf(buffer + off, "%02X", mac[i]);
259  if (i < ETH_ALEN - 1) off += sprintf(buffer + off, ":");
260  }
261 
262  return off;
263 }
264 
265 /*****************************************************************************/
266 
271  const uint8_t *mac
272  )
273 {
274  unsigned int i;
275 
276  for (i = 0; i < ETH_ALEN; i++)
277  if (mac[i])
278  return 0;
279 
280  return 1;
281 }
282 
283 /*****************************************************************************/
284 
289  const uint8_t *mac
290  )
291 {
292  unsigned int i;
293 
294  for (i = 0; i < ETH_ALEN; i++)
295  if (mac[i] != 0xff)
296  return 0;
297 
298  return 1;
299 }
300 
301 /*****************************************************************************/
302 
310 static int ec_mac_parse(uint8_t *mac, const char *src, int allow_empty)
311 {
312  unsigned int i, value;
313  const char *orig = src;
314  char *rem;
315 
316  if (!strlen(src)) {
317  if (allow_empty){
318  return 0;
319  } else {
320  EC_ERR("MAC address may not be empty.\n");
321  return -EINVAL;
322  }
323  }
324 
325  for (i = 0; i < ETH_ALEN; i++) {
326  value = simple_strtoul(src, &rem, 16);
327  if (rem != src + 2
328  || value > 0xFF
329  || (i < ETH_ALEN - 1 && *rem != ':')) {
330  EC_ERR("Invalid MAC address \"%s\".\n", orig);
331  return -EINVAL;
332  }
333  mac[i] = value;
334  if (i < ETH_ALEN - 1) {
335  src = rem + 1; // skip colon
336  }
337  }
338 
339  return 0;
340 }
341 
342 /*****************************************************************************/
343 
348 void ec_print_data(const uint8_t *data,
349  size_t size
350  )
351 {
352  unsigned int i;
353 
354  EC_DBG("");
355  for (i = 0; i < size; i++) {
356  printk(KERN_CONT "%02X ", data[i]);
357 
358  if ((i + 1) % 16 == 0 && i < size - 1) {
359  printk(KERN_CONT "\n");
360  EC_DBG("");
361  }
362 
363  if (i + 1 == 128 && size > 256) {
364  printk(KERN_CONT "dropped %zu bytes\n", size - 128 - i);
365  i = size - 128;
366  EC_DBG("");
367  }
368  }
369  printk(KERN_CONT "\n");
370 }
371 
372 /*****************************************************************************/
373 
376 void ec_print_data_diff(const uint8_t *d1,
377  const uint8_t *d2,
378  size_t size
379  )
380 {
381  unsigned int i;
382 
383  EC_DBG("");
384  for (i = 0; i < size; i++) {
385  if (d1[i] == d2[i]) {
386  printk(KERN_CONT ".. ");
387  }
388  else {
389  printk(KERN_CONT "%02X ", d2[i]);
390  }
391  if ((i + 1) % 16 == 0) {
392  printk(KERN_CONT "\n");
393  EC_DBG("");
394  }
395  }
396  printk(KERN_CONT "\n");
397 }
398 
399 /*****************************************************************************/
400 
405 size_t ec_state_string(uint8_t states,
406  char *buffer,
408  uint8_t multi
409  )
410 {
411  off_t off = 0;
412  unsigned int first = 1;
413 
414  if (!states) {
415  off += sprintf(buffer + off, "(unknown)");
416  return off;
417  }
418 
419  if (multi) { // multiple slaves
420  if (states & EC_SLAVE_STATE_INIT) {
421  off += sprintf(buffer + off, "INIT");
422  first = 0;
423  }
424  if (states & EC_SLAVE_STATE_PREOP) {
425  if (!first) off += sprintf(buffer + off, ", ");
426  off += sprintf(buffer + off, "PREOP");
427  first = 0;
428  }
429  if (states & EC_SLAVE_STATE_SAFEOP) {
430  if (!first) off += sprintf(buffer + off, ", ");
431  off += sprintf(buffer + off, "SAFEOP");
432  first = 0;
433  }
434  if (states & EC_SLAVE_STATE_OP) {
435  if (!first) off += sprintf(buffer + off, ", ");
436  off += sprintf(buffer + off, "OP");
437  }
438  } else { // single slave
439  if ((states & EC_SLAVE_STATE_MASK) == EC_SLAVE_STATE_INIT) {
440  off += sprintf(buffer + off, "INIT");
441  } else if ((states & EC_SLAVE_STATE_MASK) == EC_SLAVE_STATE_PREOP) {
442  off += sprintf(buffer + off, "PREOP");
443  } else if ((states & EC_SLAVE_STATE_MASK) == EC_SLAVE_STATE_BOOT) {
444  off += sprintf(buffer + off, "BOOT");
445  } else if ((states & EC_SLAVE_STATE_MASK) == EC_SLAVE_STATE_SAFEOP) {
446  off += sprintf(buffer + off, "SAFEOP");
447  } else if ((states & EC_SLAVE_STATE_MASK) == EC_SLAVE_STATE_OP) {
448  off += sprintf(buffer + off, "OP");
449  } else {
450  off += sprintf(buffer + off, "(invalid)");
451  }
452  first = 0;
453  }
454 
455  if (states & EC_SLAVE_STATE_ACK_ERR) {
456  if (!first) off += sprintf(buffer + off, " + ");
457  off += sprintf(buffer + off, "ERROR");
458  }
459 
460  return off;
461 }
462 
463 /******************************************************************************
464  * Device interface
465  *****************************************************************************/
466 
469 const char *ec_device_names[2] = {
470  "main",
471  "backup"
472 };
473 
485  struct net_device *net_dev,
486  ec_pollfunc_t poll,
487  struct module *module
488  )
489 {
490  ec_master_t *master;
491  char str[EC_MAX_MAC_STRING_SIZE];
492  unsigned int i, dev_idx;
493 
494  for (i = 0; i < master_count; i++) {
495  master = &masters[i];
496  ec_mac_print(net_dev->dev_addr, str);
497 
498  if (down_interruptible(&master->device_sem)) {
499  EC_MASTER_WARN(master, "%s() interrupted!\n", __func__);
500  return NULL;
501  }
502 
503  for (dev_idx = EC_DEVICE_MAIN;
504  dev_idx < ec_master_num_devices(master); dev_idx++) {
505  if (!master->devices[dev_idx].dev
506  && (ec_mac_equal(master->macs[dev_idx], net_dev->dev_addr)
507  || ec_mac_is_broadcast(master->macs[dev_idx]))) {
508 
509  EC_INFO("Accepting %s as %s device for master %u.\n",
510  str, ec_device_names[dev_idx != 0], master->index);
511 
512  ec_device_attach(&master->devices[dev_idx],
513  net_dev, poll, module);
514  up(&master->device_sem);
515 
516  snprintf(net_dev->name, IFNAMSIZ, "ec%c%u",
517  ec_device_names[dev_idx != 0][0], master->index);
518 
519  return &master->devices[dev_idx]; // offer accepted
520  }
521  }
522 
523  up(&master->device_sem);
524 
525  EC_MASTER_DBG(master, 1, "Master declined device %s.\n", str);
526  }
527 
528  return NULL; // offer declined
529 }
530 
531 /******************************************************************************
532  * Application interface
533  *****************************************************************************/
534 
542  unsigned int master_index
543  )
544 {
545  ec_master_t *master, *errptr = NULL;
546  unsigned int dev_idx = EC_DEVICE_MAIN;
547 
548  EC_INFO("Requesting master %u...\n", master_index);
549 
550  if (master_index >= master_count) {
551  EC_ERR("Invalid master index %u.\n", master_index);
552  errptr = ERR_PTR(-EINVAL);
553  goto out_return;
554  }
555  master = &masters[master_index];
556 
557  if (down_interruptible(&master_sem)) {
558  errptr = ERR_PTR(-EINTR);
559  goto out_return;
560  }
561 
562  if (master->reserved) {
563  up(&master_sem);
564  EC_MASTER_ERR(master, "Master already in use!\n");
565  errptr = ERR_PTR(-EBUSY);
566  goto out_return;
567  }
568  master->reserved = 1;
569  up(&master_sem);
570 
571  if (down_interruptible(&master->device_sem)) {
572  errptr = ERR_PTR(-EINTR);
573  goto out_release;
574  }
575 
576  if (master->phase != EC_IDLE) {
577  up(&master->device_sem);
578  EC_MASTER_ERR(master, "Master still waiting for devices!\n");
579  errptr = ERR_PTR(-ENODEV);
580  goto out_release;
581  }
582 
583  for (; dev_idx < ec_master_num_devices(master); dev_idx++) {
584  ec_device_t *device = &master->devices[dev_idx];
585  if (!try_module_get(device->module)) {
586  up(&master->device_sem);
587  EC_MASTER_ERR(master, "Device module is unloading!\n");
588  errptr = ERR_PTR(-ENODEV);
589  goto out_module_put;
590  }
591  }
592 
593  up(&master->device_sem);
594 
595  if (ec_master_enter_operation_phase(master)) {
596  EC_MASTER_ERR(master, "Failed to enter OPERATION phase!\n");
597  errptr = ERR_PTR(-EIO);
598  goto out_module_put;
599  }
600 
601  EC_INFO("Successfully requested master %u.\n", master_index);
602  return master;
603 
604  out_module_put:
605  for (; dev_idx > 0; dev_idx--) {
606  ec_device_t *device = &master->devices[dev_idx - 1];
607  module_put(device->module);
608  }
609  out_release:
610  master->reserved = 0;
611  out_return:
612  return errptr;
613 }
614 
615 /*****************************************************************************/
616 
617 ec_master_t *ecrt_request_master(unsigned int master_index)
618 {
619  ec_master_t *master = ecrt_request_master_err(master_index);
620  return IS_ERR(master) ? NULL : master;
621 }
622 
623 /*****************************************************************************/
624 
626 {
627  unsigned int dev_idx;
628 
629  EC_MASTER_INFO(master, "Releasing master...\n");
630 
631  if (!master->reserved) {
632  EC_MASTER_WARN(master, "%s(): Master was was not requested!\n",
633  __func__);
634  return;
635  }
636 
638 
639  for (dev_idx = EC_DEVICE_MAIN; dev_idx < ec_master_num_devices(master);
640  dev_idx++) {
641  module_put(master->devices[dev_idx].module);
642  }
643 
644  master->reserved = 0;
645 
646  EC_MASTER_INFO(master, "Released.\n");
647 }
648 
649 /*****************************************************************************/
650 
651 unsigned int ecrt_version_magic(void)
652 {
653  return ECRT_VERSION_MAGIC;
654 }
655 
656 /*****************************************************************************/
657 
663  EC_REQUEST_UNUSED, // EC_INT_REQUEST_INIT,
664  EC_REQUEST_BUSY, // EC_INT_REQUEST_QUEUED,
665  EC_REQUEST_BUSY, // EC_INT_REQUEST_BUSY,
666  EC_REQUEST_SUCCESS, // EC_INT_REQUEST_SUCCESS,
667  EC_REQUEST_ERROR // EC_INT_REQUEST_FAILURE
668 };
669 
670 /*****************************************************************************/
671 
674 module_init(ec_init_module);
675 module_exit(ec_cleanup_module);
676 
677 EXPORT_SYMBOL(ecdev_offer);
678 
679 EXPORT_SYMBOL(ecrt_request_master);
680 EXPORT_SYMBOL(ecrt_release_master);
681 EXPORT_SYMBOL(ecrt_version_magic);
682 
685 /*****************************************************************************/
unsigned int reserved
True, if the master is in use.
Definition: master.h:196
void ec_print_data(const uint8_t *data, size_t size)
Outputs frame contents for debugging purposes.
Definition: module.c:348
#define EC_SLAVE_STATE_MASK
Slave state mask.
Definition: globals.h:111
static char * backup_devices[MAX_MASTERS]
Backup devices parameter.
Definition: module.c:59
size_t ec_state_string(uint8_t states, char *buffer, uint8_t multi)
Prints slave states in clear text.
Definition: module.c:405
int ec_mac_is_broadcast(const uint8_t *mac)
Definition: module.c:288
void ecrt_release_master(ec_master_t *master)
Releases a requested EtherCAT master.
Definition: module.c:625
void ec_master_clear(ec_master_t *master)
Destructor.
Definition: master.c:395
OP (mailbox communication and input/output update)
Definition: globals.h:126
ssize_t ec_mac_print(const uint8_t *mac, char *buffer)
Print a MAC address to a buffer.
Definition: module.c:249
void ec_master_leave_operation_phase(ec_master_t *master)
Transition function from OPERATION to IDLE phase.
Definition: master.c:780
#define ec_master_num_devices(MASTER)
Number of Ethernet devices.
Definition: master.h:328
#define EC_MAX_MAC_STRING_SIZE
Maximum MAC string size.
Definition: module.c:241
struct module * module
pointer to the device&#39;s owning module
Definition: device.h:86
dev_t device_number
Device number for master cdevs.
Definition: module.c:67
Bootstrap state (mailbox communication, firmware update)
Definition: globals.h:122
int ec_mac_is_zero(const uint8_t *mac)
Definition: module.c:270
#define MAX_MASTERS
Maximum number of masters.
Definition: module.c:46
static ec_master_t * masters
Array of masters.
Definition: module.c:64
char * ec_master_version_str
Version string.
Definition: module.c:72
Acknowledge/Error bit (no actual state)
Definition: globals.h:128
static unsigned int debug_level
Debug level parameter.
Definition: module.c:61
const uint8_t * macs[EC_MAX_NUM_DEVICES]
Device MAC addresses.
Definition: master.h:212
void ec_print_data_diff(const uint8_t *d1, const uint8_t *d2, size_t size)
Outputs frame contents and differences for debugging purposes.
Definition: module.c:376
int ec_master_init(ec_master_t *master, unsigned int index, const uint8_t *main_mac, const uint8_t *backup_mac, dev_t device_number, struct class *class, unsigned int debug_level, unsigned int run_on_cpu)
Master constructor.
Definition: master.c:142
ec_master_t * ecrt_request_master_err(unsigned int master_index)
Request a master.
Definition: module.c:541
Global definitions and macros.
EtherCAT master structure.
void __exit ec_cleanup_module(void)
Module cleanup.
Definition: module.c:188
SAFEOP (mailbox communication and input update)
Definition: globals.h:124
Not requested.
Definition: ecrt.h:547
#define EC_MASTER_DBG(master, level, fmt, args...)
Convenience macro for printing master-specific debug messages to syslog.
Definition: master.h:111
ec_master_t * ecrt_request_master(unsigned int master_index)
Requests an EtherCAT master for realtime operation.
Definition: module.c:617
Request is being processed.
Definition: ecrt.h:548
static uint8_t macs[MAX_MASTERS][2][ETH_ALEN]
MAC addresses.
Definition: module.c:70
ec_master_phase_t phase
Master phase.
Definition: master.h:223
static unsigned int master_count
Number of masters.
Definition: module.c:58
void(* ec_pollfunc_t)(struct net_device *)
Device poll function type.
Definition: ecdev.h:57
struct semaphore device_sem
Device semaphore.
Definition: master.h:218
EtherCAT device.
Definition: device.h:81
int __init ec_init_module(void)
Module initialization.
Definition: module.c:101
Main device.
Definition: globals.h:190
unsigned int ecrt_version_magic(void)
Returns the version magic of the realtime interface.
Definition: module.c:651
#define EC_MASTER_WARN(master, fmt, args...)
Convenience macro for printing master-specific warnings to syslog.
Definition: master.h:97
int ec_master_enter_operation_phase(ec_master_t *master)
Transition function from IDLE to OPERATION phase.
Definition: master.c:698
struct class * class
Device class.
Definition: module.c:68
#define EC_MASTER_ERR(master, fmt, args...)
Convenience macro for printing master-specific errors to syslog.
Definition: master.h:85
int ec_mac_equal(const uint8_t *mac1, const uint8_t *mac2)
Definition: module.c:223
INIT state (no mailbox communication, no IO)
Definition: globals.h:118
Idle phase.
Definition: master.h:133
#define EC_DBG(fmt, args...)
Convenience macro for printing EtherCAT debug messages to syslog.
Definition: globals.h:235
static unsigned int run_on_cpu
Bind created kernel threads to a cpu.
Definition: module.c:62
#define EC_INFO(fmt, args...)
Convenience macro for printing EtherCAT-specific information to syslog.
Definition: globals.h:205
#define EC_ERR(fmt, args...)
Convenience macro for printing EtherCAT-specific errors to syslog.
Definition: globals.h:215
ec_device_t * ecdev_offer(struct net_device *net_dev, ec_pollfunc_t poll, struct module *module)
Offers an EtherCAT device to a certain master.
Definition: module.c:484
unsigned int ec_master_count(void)
Get the number of masters.
Definition: module.c:211
static struct semaphore master_sem
Master semaphore.
Definition: module.c:65
const ec_request_state_t ec_request_state_translation_table[]
Global request state type translation table.
Definition: module.c:662
void ec_device_attach(ec_device_t *device, struct net_device *net_dev, ec_pollfunc_t poll, struct module *module)
Associate with net_device.
Definition: device.c:187
EtherCAT device structure.
static int ec_mac_parse(uint8_t *, const char *, int)
Parse a MAC address from a string.
Definition: module.c:310
struct net_device * dev
pointer to the assigned net_device
Definition: device.h:84
Request was processed successfully.
Definition: ecrt.h:549
static unsigned int backup_count
Number of backup devices.
Definition: module.c:60
ec_request_state_t
Request state.
Definition: ecrt.h:546
unsigned int index
Index.
Definition: master.h:195
PREOP state (mailbox communication, no IO)
Definition: globals.h:120
#define EC_MASTER_INFO(master, fmt, args...)
Convenience macro for printing master-specific information to syslog.
Definition: master.h:73
static char * main_devices[MAX_MASTERS]
Main devices parameter.
Definition: module.c:57
EtherCAT master.
Definition: master.h:194
Request processing failed.
Definition: ecrt.h:550
ec_device_t devices[EC_MAX_NUM_DEVICES]
EtherCAT devices.
Definition: master.h:211
void ec_master_init_static(void)
Static variables initializer.
Definition: master.c:121
#define ECRT_VERSION_MAGIC
EtherCAT realtime interface version word.
Definition: ecrt.h:161
const char * ec_device_names[2]
Device names.
Definition: module.c:469