IgH EtherCAT Master  1.7.0
module.c
Go to the documentation of this file.
1 /*****************************************************************************
2  *
3  * Copyright (C) 2006-2026 Florian Pose, Ingenieurgemeinschaft IgH
4  *
5  * This file is part of the IgH EtherCAT Master.
6  *
7  * The IgH EtherCAT Master is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License version 2, as
9  * published by the Free Software Foundation.
10  *
11  * The IgH EtherCAT Master is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
14  * Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with the IgH EtherCAT Master; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  *
20  ****************************************************************************/
21 
26 /****************************************************************************/
27 
28 #include <linux/module.h>
29 #include <linux/device.h>
30 #include <linux/err.h>
31 
32 #include "globals.h"
33 #include "master.h"
34 #include "device.h"
35 
36 /****************************************************************************/
37 
38 /****************************************************************************/
39 
40 int __init ec_init_module(void);
41 void __exit ec_cleanup_module(void);
42 
43 static int ec_mac_parse(uint8_t *, const char *, int);
44 
45 // prototypes for private functions
46 int ec_mac_equal(const uint8_t *, const uint8_t *);
47 int ec_mac_is_broadcast(const uint8_t *);
48 
49 /****************************************************************************/
50 
52 static unsigned int master_count;
54 static unsigned int backup_count;
55 static unsigned int debug_level;
56 static unsigned int run_on_cpu = 0xffffffff;
59 static unsigned int sii_caching;
62 static struct semaphore master_sem;
65 struct class *class;
67 static uint8_t macs[EC_MAX_MASTERS][2][ETH_ALEN];
69 char *ec_master_version_str = EC_MASTER_VERSION;
71 /****************************************************************************/
72 
75 MODULE_AUTHOR("Florian Pose <fp@igh.de>");
76 MODULE_DESCRIPTION("EtherCAT master driver module");
77 MODULE_LICENSE("GPL");
78 MODULE_VERSION(EC_MASTER_VERSION);
79 
80 module_param_array(main_devices, charp, &master_count, S_IRUGO);
81 MODULE_PARM_DESC(main_devices, "MAC addresses of main devices");
82 module_param_array(backup_devices, charp, &backup_count, S_IRUGO);
83 MODULE_PARM_DESC(backup_devices, "MAC addresses of backup devices");
84 module_param(debug_level, uint, S_IRUGO);
85 MODULE_PARM_DESC(debug_level, "Debug level");
86 module_param(run_on_cpu, uint, S_IRUGO);
87 MODULE_PARM_DESC(run_on_cpu, "Bind kthreads to a specific cpu");
88 module_param(sii_caching, uint, S_IRUGO);
89 MODULE_PARM_DESC(sii_caching, "SII caching mode (default=0=off)");
90 
93 /****************************************************************************/
94 
100 int __init ec_init_module(void)
101 {
102  int i, ret = 0;
103 
104  EC_INFO("Master driver %s\n", EC_MASTER_VERSION);
105 
106  sema_init(&master_sem, 1);
107 
108  if (master_count) {
109  if (alloc_chrdev_region(&device_number,
110  0, master_count, "EtherCAT")) {
111  EC_ERR("Failed to obtain device number(s)!\n");
112  ret = -EBUSY;
113  goto out_return;
114  }
115  }
116 
117 #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0)
118  class = class_create(THIS_MODULE, "EtherCAT");
119 #else
120  class = class_create("EtherCAT");
121 #endif
122  if (IS_ERR(class)) {
123  EC_ERR("Failed to create device class.\n");
124  ret = PTR_ERR(class);
125  goto out_cdev;
126  }
127 
128  // zero MAC addresses
129  memset(macs, 0x00, sizeof(uint8_t) * EC_MAX_MASTERS * 2 * ETH_ALEN);
130 
131  // process MAC parameters
132  for (i = 0; i < master_count; i++) {
133  ret = ec_mac_parse(macs[i][0], main_devices[i], 0);
134  if (ret)
135  goto out_class;
136 
137  if (i < backup_count) {
138  ret = ec_mac_parse(macs[i][1], backup_devices[i], 1);
139  if (ret)
140  goto out_class;
141  }
142  }
143 
144  // initialize static master variables
146 
147  if (master_count) {
148  if (!(masters = kmalloc(sizeof(ec_master_t) * master_count,
149  GFP_KERNEL))) {
150  EC_ERR("Failed to allocate memory"
151  " for EtherCAT masters.\n");
152  ret = -ENOMEM;
153  goto out_class;
154  }
155  }
156 
157  for (i = 0; i < master_count; i++) {
158  ret = ec_master_init(&masters[i], i, macs[i][0], macs[i][1],
160  sii_caching);
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  EC_INFO("Accepting %s as %s device for master %u.\n",
509  str, ec_device_names[dev_idx != 0], master->index);
510 
511  ec_device_attach(&master->devices[dev_idx],
512  net_dev, poll, module);
513  up(&master->device_sem);
514 
515  snprintf(net_dev->name, IFNAMSIZ, "ec%c%u",
516  ec_device_names[dev_idx != 0][0], master->index);
517 
518  return &master->devices[dev_idx]; // offer accepted
519  }
520  }
521 
522  up(&master->device_sem);
523 
524  EC_MASTER_DBG(master, 1, "Master declined device %s.\n", str);
525  }
526 
527  return NULL; // offer declined
528 }
529 
530 /*****************************************************************************
531  * Application interface
532  ****************************************************************************/
533 
541  unsigned int master_index
542  )
543 {
544  ec_master_t *master, *errptr = NULL;
545  unsigned int dev_idx = EC_DEVICE_MAIN;
546 
547  EC_INFO("Requesting master %u...\n", master_index);
548 
549  if (master_index >= master_count) {
550  EC_ERR("Invalid master index %u.\n", master_index);
551  errptr = ERR_PTR(-EINVAL);
552  goto out_return;
553  }
554  master = &masters[master_index];
555 
556  if (down_interruptible(&master_sem)) {
557  errptr = ERR_PTR(-EINTR);
558  goto out_return;
559  }
560 
561  if (master->reserved) {
562  up(&master_sem);
563  EC_MASTER_ERR(master, "Master already in use!\n");
564  errptr = ERR_PTR(-EBUSY);
565  goto out_return;
566  }
567  master->reserved = 1;
568  up(&master_sem);
569 
570  if (down_interruptible(&master->device_sem)) {
571  errptr = ERR_PTR(-EINTR);
572  goto out_release;
573  }
574 
575  if (master->phase != EC_IDLE) {
576  up(&master->device_sem);
577  EC_MASTER_ERR(master, "Master still waiting for devices!\n");
578  errptr = ERR_PTR(-ENODEV);
579  goto out_release;
580  }
581 
582  for (; dev_idx < ec_master_num_devices(master); dev_idx++) {
583  ec_device_t *device = &master->devices[dev_idx];
584  if (!try_module_get(device->module)) {
585  up(&master->device_sem);
586  EC_MASTER_ERR(master, "Device module is unloading!\n");
587  errptr = ERR_PTR(-ENODEV);
588  goto out_module_put;
589  }
590  }
591 
592  up(&master->device_sem);
593 
594  if (ec_master_enter_operation_phase(master)) {
595  EC_MASTER_ERR(master, "Failed to enter OPERATION phase!\n");
596  errptr = ERR_PTR(-EIO);
597  goto out_module_put;
598  }
599 
600  EC_INFO("Successfully requested master %u.\n", master_index);
601  return master;
602 
603  out_module_put:
604  for (; dev_idx > 0; dev_idx--) {
605  ec_device_t *device = &master->devices[dev_idx - 1];
606  module_put(device->module);
607  }
608  out_release:
609  master->reserved = 0;
610  out_return:
611  return errptr;
612 }
613 
614 /****************************************************************************/
615 
616 ec_master_t *ecrt_request_master(unsigned int master_index)
617 {
618  ec_master_t *master = ecrt_request_master_err(master_index);
619  return IS_ERR(master) ? NULL : master;
620 }
621 
622 /****************************************************************************/
623 
625 {
626  unsigned int dev_idx;
627 
628  EC_MASTER_INFO(master, "Releasing master...\n");
629 
630  if (!master->reserved) {
631  EC_MASTER_WARN(master, "%s(): Master was was not requested!\n",
632  __func__);
633  return;
634  }
635 
637 
638  for (dev_idx = EC_DEVICE_MAIN; dev_idx < ec_master_num_devices(master);
639  dev_idx++) {
640  module_put(master->devices[dev_idx].module);
641  }
642 
643  master->reserved = 0;
644 
645  EC_MASTER_INFO(master, "Released.\n");
646 }
647 
648 /****************************************************************************/
649 
650 unsigned int ecrt_version_magic(void)
651 {
652  return ECRT_VERSION_MAGIC;
653 }
654 
655 /****************************************************************************/
656 
662  EC_REQUEST_UNUSED, // EC_INT_REQUEST_INIT,
663  EC_REQUEST_BUSY, // EC_INT_REQUEST_QUEUED,
664  EC_REQUEST_BUSY, // EC_INT_REQUEST_BUSY,
665  EC_REQUEST_SUCCESS, // EC_INT_REQUEST_SUCCESS,
666  EC_REQUEST_ERROR // EC_INT_REQUEST_FAILURE
667 };
668 
669 /****************************************************************************/
670 
673 module_init(ec_init_module);
674 module_exit(ec_cleanup_module);
675 
676 EXPORT_SYMBOL(ecdev_offer);
677 
678 EXPORT_SYMBOL(ecrt_request_master);
679 EXPORT_SYMBOL(ecrt_release_master);
680 EXPORT_SYMBOL(ecrt_version_magic);
681 
684 /****************************************************************************/
unsigned int reserved
True, if the master is in use.
Definition: master.h:189
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:123
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 *)
Definition: module.c:288
static char * backup_devices[EC_MAX_MASTERS]
Backup devices parameter.
Definition: module.c:53
void ec_master_clear(ec_master_t *master)
Destructor.
Definition: master.c:415
OP (mailbox communication and input/output update)
Definition: globals.h:138
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:807
#define ec_master_num_devices(MASTER)
Number of Ethernet devices.
Definition: master.h:326
#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:83
static unsigned int sii_caching
SII Caching mode.
Definition: module.c:59
dev_t device_number
Device number for master cdevs.
Definition: module.c:64
static char * main_devices[EC_MAX_MASTERS]
Main devices parameter.
Definition: module.c:51
Bootstrap state (mailbox communication, firmware update)
Definition: globals.h:134
int ec_mac_is_zero(const uint8_t *mac)
Definition: module.c:270
static ec_master_t * masters
Array of masters.
Definition: module.c:61
char * ec_master_version_str
Version string.
Definition: module.c:69
Acknowledge/Error bit (no actual state)
Definition: globals.h:140
static unsigned int debug_level
Debug level parameter.
Definition: module.c:55
const uint8_t * macs[EC_MAX_NUM_DEVICES]
Device MAC addresses.
Definition: master.h:201
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
ec_master_t * ecrt_request_master_err(unsigned int master_index)
Request a master.
Definition: module.c:540
Global definitions and macros.
unsigned int ecrt_version_magic(void)
Returns the version magic of the realtime interface.
Definition: module.c:650
EtherCAT master structure.
void __exit ec_cleanup_module(void)
Module cleanup.
Definition: module.c:188
SAFEOP (mailbox communication and input update)
Definition: globals.h:136
Not requested.
Definition: ecrt.h:659
#define EC_MASTER_DBG(master, level, fmt, args...)
Convenience macro for printing master-specific debug messages to syslog.
Definition: master.h:100
Request is being processed.
Definition: ecrt.h:660
ec_master_phase_t phase
Master phase.
Definition: master.h:212
static unsigned int master_count
Number of masters.
Definition: module.c:52
void(* ec_pollfunc_t)(struct net_device *)
Device poll function type.
Definition: ecdev.h:49
struct semaphore device_sem
Device semaphore.
Definition: master.h:207
EtherCAT device.
Definition: device.h:78
int __init ec_init_module(void)
Module initialization.
Definition: module.c:100
Main device.
Definition: globals.h:204
static uint8_t macs[EC_MAX_MASTERS][2][ETH_ALEN]
MAC addresses.
Definition: module.c:67
#define EC_MASTER_WARN(master, fmt, args...)
Convenience macro for printing master-specific warnings to syslog.
Definition: master.h:86
int ec_master_enter_operation_phase(ec_master_t *master)
Transition function from IDLE to OPERATION phase.
Definition: master.c:736
struct class * class
Device class.
Definition: module.c:65
#define EC_MASTER_ERR(master, fmt, args...)
Convenience macro for printing master-specific errors to syslog.
Definition: master.h:74
int ec_mac_equal(const uint8_t *, const uint8_t *)
Definition: module.c:223
INIT state (no mailbox communication, no IO)
Definition: globals.h:130
Idle phase.
Definition: master.h:126
#define EC_DBG(fmt, args...)
Convenience macro for printing EtherCAT debug messages to syslog.
Definition: globals.h:249
static unsigned int run_on_cpu
Bind created kernel threads to a cpu.
Definition: module.c:56
ec_master_t * ecrt_request_master(unsigned int master_index)
Requests an EtherCAT master for realtime operation.
Definition: module.c:616
#define EC_INFO(fmt, args...)
Convenience macro for printing EtherCAT-specific information to syslog.
Definition: globals.h:219
#define EC_ERR(fmt, args...)
Convenience macro for printing EtherCAT-specific errors to syslog.
Definition: globals.h:229
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
#define EC_MAX_MASTERS
Maximum number of masters.
Definition: master.h:117
static struct semaphore master_sem
Master semaphore.
Definition: module.c:62
const ec_request_state_t ec_request_state_translation_table[]
Global request state type translation table.
Definition: module.c:661
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:194
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:81
Request was processed successfully.
Definition: ecrt.h:661
static unsigned int backup_count
Number of backup devices.
Definition: module.c:54
ec_request_state_t
Request state.
Definition: ecrt.h:658
unsigned int index
Index.
Definition: master.h:188
PREOP state (mailbox communication, no IO)
Definition: globals.h:132
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, unsigned int sii_caching)
Master constructor.
Definition: master.c:169
#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
Request processing failed.
Definition: ecrt.h:662
ec_device_t devices[EC_MAX_NUM_DEVICES]
EtherCAT devices.
Definition: master.h:200
void ecrt_release_master(ec_master_t *master)
Releases a requested EtherCAT master.
Definition: module.c:624
void ec_master_init_static(void)
Static variables initializer.
Definition: master.c:148
#define ECRT_VERSION_MAGIC
EtherCAT realtime interface version word.
Definition: ecrt.h:181
const char * ec_device_names[2]
Device names.
Definition: module.c:469