Devices as array; lock all device modules with module_get(). redundancy
authorFlorian Pose <fp@igh-essen.com>
Thu, 12 Jan 2012 12:14:33 +0100
branchredundancy
changeset 2267 2d36f36a433c
parent 2160 e3bf5adad75f
child 2268 5e1d3c9430e0
Devices as array; lock all device modules with module_get().
master/cdev.c
master/device.c
master/ethernet.c
master/fsm_master.c
master/globals.h
master/ioctl.h
master/master.c
master/master.h
master/module.c
--- a/master/cdev.c	Wed Nov 09 17:07:33 2011 +0100
+++ b/master/cdev.c	Thu Jan 12 12:14:33 2012 +0100
@@ -184,10 +184,11 @@
         )
 {
     ec_ioctl_master_t data;
-    unsigned int i;
-
-    if (down_interruptible(&master->master_sem))
-        return -EINTR;
+    unsigned int i, j;
+
+    if (down_interruptible(&master->master_sem))
+        return -EINTR;
+
     data.slave_count = master->slave_count;
     data.config_count = ec_master_config_count(master);
     data.domain_count = ec_master_domain_count(master);
@@ -197,57 +198,38 @@
     data.phase = (uint8_t) master->phase;
     data.active = (uint8_t) master->active;
     data.scan_busy = master->scan_busy;
+
     up(&master->master_sem);
 
     if (down_interruptible(&master->device_sem))
         return -EINTR;
 
-    if (master->main_device.dev) {
-        memcpy(data.devices[0].address,
-                master->main_device.dev->dev_addr, ETH_ALEN);
-    } else {
-        memcpy(data.devices[0].address, master->main_mac, ETH_ALEN); 
-    }
-    data.devices[0].attached = master->main_device.dev ? 1 : 0;
-    data.devices[0].link_state = master->main_device.link_state ? 1 : 0;
-    data.devices[0].tx_count = master->main_device.tx_count;
-    data.devices[0].rx_count = master->main_device.rx_count;
-    data.devices[0].tx_bytes = master->main_device.tx_bytes;
-    data.devices[0].rx_bytes = master->main_device.rx_bytes;
-    data.devices[0].tx_errors = master->main_device.tx_errors;
-    for (i = 0; i < EC_RATE_COUNT; i++) {
-        data.devices[0].tx_frame_rates[i] =
-            master->main_device.tx_frame_rates[i];
-        data.devices[0].rx_frame_rates[i] =
-            master->main_device.rx_frame_rates[i];
-        data.devices[0].tx_byte_rates[i] =
-            master->main_device.tx_byte_rates[i];
-        data.devices[0].rx_byte_rates[i] =
-            master->main_device.rx_byte_rates[i];
-    }
-
-    if (master->backup_device.dev) {
-        memcpy(data.devices[1].address,
-                master->backup_device.dev->dev_addr, ETH_ALEN); 
-    } else {
-        memcpy(data.devices[1].address, master->backup_mac, ETH_ALEN); 
-    }
-    data.devices[1].attached = master->backup_device.dev ? 1 : 0;
-    data.devices[1].link_state = master->backup_device.link_state ? 1 : 0;
-    data.devices[1].tx_count = master->backup_device.tx_count;
-    data.devices[1].rx_count = master->backup_device.rx_count;
-    data.devices[1].tx_bytes = master->backup_device.tx_bytes;
-    data.devices[1].rx_bytes = master->backup_device.rx_bytes;
-    data.devices[1].tx_errors = master->backup_device.tx_errors;
-    for (i = 0; i < EC_RATE_COUNT; i++) {
-        data.devices[1].tx_frame_rates[i] =
-            master->backup_device.tx_frame_rates[i];
-        data.devices[1].rx_frame_rates[i] =
-            master->backup_device.rx_frame_rates[i];
-        data.devices[1].tx_byte_rates[i] =
-            master->backup_device.tx_byte_rates[i];
-        data.devices[1].rx_byte_rates[i] =
-            master->backup_device.rx_byte_rates[i];
+    for (i = 0; i < EC_NUM_DEVICES; i++) {
+        ec_device_t *device = &master->devices[i];
+
+        if (device->dev) {
+            memcpy(data.devices[i].address,
+                    device->dev->dev_addr, ETH_ALEN);
+        } else {
+            memcpy(data.devices[i].address, master->macs[i], ETH_ALEN);
+        }
+        data.devices[i].attached = device->dev ? 1 : 0;
+        data.devices[i].link_state = device->link_state ? 1 : 0;
+        data.devices[i].tx_count = device->tx_count;
+        data.devices[i].rx_count = device->rx_count;
+        data.devices[i].tx_bytes = device->tx_bytes;
+        data.devices[i].rx_bytes = device->rx_bytes;
+        data.devices[i].tx_errors = device->tx_errors;
+        for (j = 0; j < EC_RATE_COUNT; j++) {
+            data.devices[i].tx_frame_rates[j] =
+                device->tx_frame_rates[j];
+            data.devices[i].rx_frame_rates[j] =
+                device->rx_frame_rates[j];
+            data.devices[i].tx_byte_rates[j] =
+                device->tx_byte_rates[j];
+            data.devices[i].rx_byte_rates[j] =
+                device->rx_byte_rates[j];
+        }
     }
 
     data.tx_count = master->device_stats.tx_count;
--- a/master/device.c	Wed Nov 09 17:07:33 2011 +0100
+++ b/master/device.c	Thu Jan 12 12:14:33 2012 +0100
@@ -513,9 +513,9 @@
 
     ec_mac_print(device->dev->dev_addr, mac_str);
 
-    if (device == &master->main_device) {
+    if (device == &master->devices[EC_DEVICE_MAIN]) {
         sprintf(dev_str, "main");
-    } else if (device == &master->backup_device) {
+    } else if (device == &master->devices[EC_DEVICE_BACKUP]) {
         sprintf(dev_str, "backup");
     } else {
         EC_MASTER_WARN(master, "%s() called with unknown device %s!\n",
@@ -548,9 +548,9 @@
         return ret;
     }
 
-    if (master->main_device.open &&
-            (ec_mac_is_zero(master->backup_mac) ||
-             master->backup_device.open)) {
+    if (master->devices[EC_DEVICE_MAIN].open &&
+            (ec_mac_is_zero(master->macs[EC_DEVICE_BACKUP]) ||
+             master->devices[EC_DEVICE_BACKUP].open)) {
         ret = ec_master_enter_idle_phase(device->master);
         if (ret) {
             EC_MASTER_ERR(device->master, "Failed to enter IDLE phase!\n");
--- a/master/ethernet.c	Wed Nov 09 17:07:33 2011 +0100
+++ b/master/ethernet.c	Thu Jan 12 12:14:33 2012 +0100
@@ -384,11 +384,13 @@
  *
  * Starts a new receiving sequence by queueing a datagram that checks the
  * slave's mailbox for a new EoE datagram.
+ *
+ * \fixme Use both devices.
  */
 void ec_eoe_state_rx_start(ec_eoe_t *eoe /**< EoE handler */)
 {
     if (eoe->slave->error_flag ||
-            !eoe->slave->master->main_device.link_state) {
+            !eoe->slave->master->devices[EC_DEVICE_MAIN].link_state) {
         eoe->rx_idle = 1;
         eoe->tx_idle = 1;
         return;
@@ -606,6 +608,8 @@
  *
  * Starts a new transmit sequence. If no data is available, a new receive
  * sequence is started instead.
+ *
+ * \fixme Use both devices.
  */
 void ec_eoe_state_tx_start(ec_eoe_t *eoe /**< EoE handler */)
 {
@@ -614,7 +618,7 @@
 #endif
 
     if (eoe->slave->error_flag ||
-            !eoe->slave->master->main_device.link_state) {
+            !eoe->slave->master->devices[EC_DEVICE_MAIN].link_state) {
         eoe->rx_idle = 1;
         eoe->tx_idle = 1;
         return;
--- a/master/fsm_master.c	Wed Nov 09 17:07:33 2011 +0100
+++ b/master/fsm_master.c	Thu Jan 12 12:14:33 2012 +0100
@@ -207,7 +207,7 @@
                 fsm->slaves_responding);
     }
 
-    if (fsm->link_state && !master->main_device.link_state) {
+    if (fsm->link_state && !master->devices[EC_DEVICE_MAIN].link_state) {
         // link went down
         EC_MASTER_DBG(master, 1, "Master state machine detected "
                 "link down. Clearing slave list.\n");
@@ -219,7 +219,7 @@
         ec_master_clear_slaves(master);
         fsm->slave_states = 0x00;
     }
-    fsm->link_state = master->main_device.link_state;
+    fsm->link_state = master->devices[EC_DEVICE_MAIN].link_state;
 
     if (datagram->state != EC_DATAGRAM_RECEIVED) {
         ec_fsm_master_restart(fsm);
--- a/master/globals.h	Wed Nov 09 17:07:33 2011 +0100
+++ b/master/globals.h	Thu Jan 12 12:14:33 2012 +0100
@@ -216,6 +216,14 @@
     EC_SDO_ENTRY_ACCESS_COUNT /**< Number of states. */
 };
 
+/** Master devices.
+ */
+enum {
+    EC_DEVICE_MAIN, /**< Main device. */
+    EC_DEVICE_BACKUP, /**< Backup device */
+    EC_NUM_DEVICES /**< Number of devices. */
+};
+
 /*****************************************************************************/
 
 /** Convenience macro for printing EtherCAT-specific information to syslog.
--- a/master/ioctl.h	Wed Nov 09 17:07:33 2011 +0100
+++ b/master/ioctl.h	Thu Jan 12 12:14:33 2012 +0100
@@ -174,7 +174,7 @@
         uint32_t rx_frame_rates[EC_RATE_COUNT];
         uint32_t tx_byte_rates[EC_RATE_COUNT];
         uint32_t rx_byte_rates[EC_RATE_COUNT];
-    } devices[2];
+    } devices[EC_NUM_DEVICES];
     uint64_t tx_count;
     uint64_t rx_count;
     uint64_t tx_bytes;
--- a/master/master.c	Wed Nov 09 17:07:33 2011 +0100
+++ b/master/master.c	Thu Jan 12 12:14:33 2012 +0100
@@ -109,11 +109,13 @@
 {
 #ifdef EC_HAVE_CYCLES
     timeout_cycles = (cycles_t) EC_IO_TIMEOUT /* us */ * (cpu_khz / 1000);
-    ext_injection_timeout_cycles = (cycles_t) EC_SDO_INJECTION_TIMEOUT /* us */ * (cpu_khz / 1000);
+    ext_injection_timeout_cycles =
+        (cycles_t) EC_SDO_INJECTION_TIMEOUT /* us */ * (cpu_khz / 1000);
 #else
     // one jiffy may always elapse between time measurement
     timeout_jiffies = max(EC_IO_TIMEOUT * HZ / 1000000, 1);
-    ext_injection_timeout_jiffies = max(EC_SDO_INJECTION_TIMEOUT * HZ / 1000000, 1);
+    ext_injection_timeout_jiffies =
+        max(EC_SDO_INJECTION_TIMEOUT * HZ / 1000000, 1);
 #endif
 }
 
@@ -140,8 +142,8 @@
 
     sema_init(&master->master_sem, 1);
 
-    master->main_mac = main_mac;
-    master->backup_mac = backup_mac;
+    master->macs[EC_DEVICE_MAIN] = main_mac;
+    master->macs[EC_DEVICE_BACKUP] = backup_mac;
     ec_master_clear_device_stats(master);
 
     sema_init(&master->device_sem, 1);
@@ -211,11 +213,11 @@
     init_waitqueue_head(&master->reg_queue);
 
     // init devices
-    ret = ec_device_init(&master->main_device, master);
+    ret = ec_device_init(&master->devices[EC_DEVICE_MAIN], master);
     if (ret < 0)
         goto out_return;
 
-    ret = ec_device_init(&master->backup_device, master);
+    ret = ec_device_init(&master->devices[EC_DEVICE_BACKUP], master);
     if (ret < 0)
         goto out_clear_main;
 
@@ -234,7 +236,8 @@
 
     // init reference sync datagram
     ec_datagram_init(&master->ref_sync_datagram);
-    snprintf(master->ref_sync_datagram.name, EC_DATAGRAM_NAME_SIZE, "refsync");
+    snprintf(master->ref_sync_datagram.name, EC_DATAGRAM_NAME_SIZE,
+            "refsync");
     ret = ec_datagram_apwr(&master->ref_sync_datagram, 0, 0x0910, 8);
     if (ret < 0) {
         ec_datagram_clear(&master->ref_sync_datagram);
@@ -256,7 +259,8 @@
 
     // init sync monitor datagram
     ec_datagram_init(&master->sync_mon_datagram);
-    snprintf(master->sync_mon_datagram.name, EC_DATAGRAM_NAME_SIZE, "syncmon");
+    snprintf(master->sync_mon_datagram.name, EC_DATAGRAM_NAME_SIZE,
+            "syncmon");
     ret = ec_datagram_brd(&master->sync_mon_datagram, 0x092c, 4);
     if (ret < 0) {
         ec_datagram_clear(&master->sync_mon_datagram);
@@ -309,9 +313,9 @@
     ec_fsm_master_clear(&master->fsm);
     ec_datagram_clear(&master->fsm_datagram);
 out_clear_backup:
-    ec_device_clear(&master->backup_device);
+    ec_device_clear(&master->devices[EC_DEVICE_BACKUP]);
 out_clear_main:
-    ec_device_clear(&master->main_device);
+    ec_device_clear(&master->devices[EC_DEVICE_MAIN]);
 out_return:
     return ret;
 }
@@ -344,8 +348,8 @@
     ec_datagram_clear(&master->ref_sync_datagram);
     ec_fsm_master_clear(&master->fsm);
     ec_datagram_clear(&master->fsm_datagram);
-    ec_device_clear(&master->backup_device);
-    ec_device_clear(&master->main_device);
+    ec_device_clear(&master->devices[EC_DEVICE_BACKUP]);
+    ec_device_clear(&master->devices[EC_DEVICE_MAIN]);
 }
 
 /*****************************************************************************/
@@ -591,7 +595,9 @@
 
 /** Transition function from IDLE to OPERATION phase.
  */
-int ec_master_enter_operation_phase(ec_master_t *master /**< EtherCAT master */)
+int ec_master_enter_operation_phase(
+        ec_master_t *master /**< EtherCAT master */
+        )
 {
     int ret = 0;
     ec_slave_t *slave;
@@ -628,7 +634,8 @@
         up(&master->scan_sem);
 
         // wait for slave scan to complete
-        ret = wait_event_interruptible(master->scan_queue, !master->scan_busy);
+        ret = wait_event_interruptible(master->scan_queue,
+                !master->scan_busy);
         if (ret) {
             EC_MASTER_INFO(master, "Waiting for slave scan"
                     " interrupted by signal.\n");
@@ -908,7 +915,7 @@
 
     do {
         // fetch pointer to transmit socket buffer
-        frame_data = ec_device_tx_data(&master->main_device);
+        frame_data = ec_device_tx_data(&master->devices[EC_DEVICE_MAIN]);
         cur_data = frame_data + EC_FRAME_HEADER_SIZE;
         follows_word = NULL;
         more_datagrams_waiting = 0;
@@ -933,7 +940,8 @@
 
             // set "datagram following" flag in previous frame
             if (follows_word)
-                EC_WRITE_U16(follows_word, EC_READ_U16(follows_word) | 0x8000);
+                EC_WRITE_U16(follows_word,
+                        EC_READ_U16(follows_word) | 0x8000);
 
             // EtherCAT datagram header
             EC_WRITE_U8 (cur_data,     datagram->type);
@@ -960,7 +968,7 @@
 
         // EtherCAT frame header
         EC_WRITE_U16(frame_data, ((cur_data - frame_data
-                                   - EC_FRAME_HEADER_SIZE) & 0x7FF) | 0x1000);
+                        - EC_FRAME_HEADER_SIZE) & 0x7FF) | 0x1000);
 
         // pad frame
         while (cur_data - frame_data < ETH_ZLEN - ETH_HLEN)
@@ -969,7 +977,8 @@
         EC_MASTER_DBG(master, 2, "frame size: %zu\n", cur_data - frame_data);
 
         // send frame
-        ec_device_send(&master->main_device, cur_data - frame_data);
+        ec_device_send(&master->devices[EC_DEVICE_MAIN],
+                cur_data - frame_data);
 #ifdef EC_HAVE_CYCLES
         cycles_sent = get_cycles();
 #endif
@@ -1092,7 +1101,7 @@
                         EC_DATAGRAM_HEADER_SIZE + data_size
                         + EC_DATAGRAM_FOOTER_SIZE);
 #ifdef EC_DEBUG_RING
-                ec_device_debug_ring_print(&master->main_device);
+                ec_device_debug_ring_print(&master->devices[EC_DEVICE_MAIN]);
 #endif
             }
 
@@ -1117,9 +1126,11 @@
         // dequeue the received datagram
         datagram->state = EC_DATAGRAM_RECEIVED;
 #ifdef EC_HAVE_CYCLES
-        datagram->cycles_received = master->main_device.cycles_poll;
-#endif
-        datagram->jiffies_received = master->main_device.jiffies_poll;
+        datagram->cycles_received =
+            master->devices[EC_DEVICE_MAIN].cycles_poll;
+#endif
+        datagram->jiffies_received =
+            master->devices[EC_DEVICE_MAIN].jiffies_poll;
         list_del_init(&datagram->queue);
     }
 }
@@ -1230,8 +1241,8 @@
     s->last_tx_bytes = s->tx_bytes;
     s->last_rx_bytes = s->rx_bytes;
 
-    ec_device_update_stats(&master->main_device);
-    ec_device_update_stats(&master->backup_device);
+    ec_device_update_stats(&master->devices[EC_DEVICE_MAIN]);
+    ec_device_update_stats(&master->devices[EC_DEVICE_BACKUP]);
 
     s->jiffies = jiffies;
 }
@@ -1356,8 +1367,8 @@
         }
         ec_master_inject_external_datagrams(master);
         ecrt_master_send(master);
-        sent_bytes = master->main_device.tx_skb[
-            master->main_device.tx_ring_index]->len;
+        sent_bytes = master->devices[EC_DEVICE_MAIN].tx_skb[
+            master->devices[EC_DEVICE_MAIN].tx_ring_index]->len;
         up(&master->io_sem);
 
         if (ec_fsm_master_idle(&master->fsm)) {
@@ -2000,7 +2011,8 @@
     EC_MASTER_DBG(master, 1, "ecrt_master_create_domain(master = 0x%p)\n",
             master);
 
-    if (!(domain = (ec_domain_t *) kmalloc(sizeof(ec_domain_t), GFP_KERNEL))) {
+    if (!(domain =
+                (ec_domain_t *) kmalloc(sizeof(ec_domain_t), GFP_KERNEL))) {
         EC_MASTER_ERR(master, "Error allocating domain memory!\n");
         return ERR_PTR(-ENOMEM);
     }
@@ -2186,18 +2198,19 @@
     }
     ec_master_inject_external_datagrams(master);
 
-    if (unlikely(!master->main_device.link_state)) {
+    if (unlikely(!master->devices[EC_DEVICE_MAIN].link_state)) {
         // link is down, no datagram can be sent
-        list_for_each_entry_safe(datagram, n, &master->datagram_queue, queue) {
+        list_for_each_entry_safe(datagram, n,
+                &master->datagram_queue, queue) {
             datagram->state = EC_DATAGRAM_ERROR;
             list_del_init(&datagram->queue);
         }
 
         // query link state
-        ec_device_poll(&master->main_device);
+        ec_device_poll(&master->devices[EC_DEVICE_MAIN]);
 
         // clear frame statistics
-        ec_device_clear_stats(&master->main_device);
+        ec_device_clear_stats(&master->devices[EC_DEVICE_MAIN]);
         return;
     }
 
@@ -2212,9 +2225,9 @@
     ec_datagram_t *datagram, *next;
 
     // receive datagrams
-    ec_device_poll(&master->main_device);
-    if (master->backup_device.dev) {
-        ec_device_poll(&master->backup_device);
+    ec_device_poll(&master->devices[EC_DEVICE_MAIN]);
+    if (master->devices[EC_DEVICE_BACKUP].dev) {
+        ec_device_poll(&master->devices[EC_DEVICE_BACKUP]);
     }
     ec_master_update_device_stats(master);
 
@@ -2223,11 +2236,11 @@
         if (datagram->state != EC_DATAGRAM_SENT) continue;
 
 #ifdef EC_HAVE_CYCLES
-        if (master->main_device.cycles_poll - datagram->cycles_sent
-                > timeout_cycles) {
+        if (master->devices[EC_DEVICE_MAIN].cycles_poll -
+                datagram->cycles_sent > timeout_cycles) {
 #else
-        if (master->main_device.jiffies_poll - datagram->jiffies_sent
-                > timeout_jiffies) {
+        if (master->devices[EC_DEVICE_MAIN].jiffies_poll -
+                datagram->jiffies_sent > timeout_jiffies) {
 #endif
             list_del_init(&datagram->queue);
             datagram->state = EC_DATAGRAM_TIMED_OUT;
@@ -2237,10 +2250,12 @@
             if (unlikely(master->debug_level > 0)) {
                 unsigned int time_us;
 #ifdef EC_HAVE_CYCLES
-                time_us = (unsigned int) (master->main_device.cycles_poll -
+                time_us = (unsigned int)
+                    (master->devices[EC_DEVICE_MAIN].cycles_poll -
                         datagram->cycles_sent) * 1000 / cpu_khz;
 #else
-                time_us = (unsigned int) ((master->main_device.jiffies_poll -
+                time_us = (unsigned int)
+                    ((master->devices[EC_DEVICE_MAIN].jiffies_poll -
                             datagram->jiffies_sent) * 1000000 / HZ);
 #endif
                 EC_MASTER_DBG(master, 0, "TIMED OUT datagram %p,"
@@ -2345,7 +2360,7 @@
             " master_info = 0x%p)\n", master, master_info);
 
     master_info->slave_count = master->slave_count;
-    master_info->link_up = master->main_device.link_state;
+    master_info->link_up = master->devices[EC_DEVICE_MAIN].link_state;
     master_info->scan_busy = master->scan_busy;
     master_info->app_time = master->app_time;
     return 0;
@@ -2406,7 +2421,7 @@
 {
     state->slaves_responding = master->fsm.slaves_responding;
     state->al_states = master->fsm.slave_states;
-    state->link_up = master->main_device.link_state;
+    state->link_up = master->devices[EC_DEVICE_MAIN].link_state;
 }
 
 /*****************************************************************************/
--- a/master/master.h	Wed Nov 09 17:07:33 2011 +0100
+++ b/master/master.h	Thu Jan 12 12:14:33 2012 +0100
@@ -187,10 +187,8 @@
 
     struct semaphore master_sem; /**< Master semaphore. */
 
-    ec_device_t main_device; /**< EtherCAT main device. */
-    const uint8_t *main_mac; /**< MAC address of main device. */
-    ec_device_t backup_device; /**< EtherCAT backup device. */
-    const uint8_t *backup_mac; /**< MAC address of backup device. */
+    ec_device_t devices[EC_NUM_DEVICES]; /**< EtherCAT devices. */
+    const uint8_t *macs[EC_NUM_DEVICES]; /**< Device MAC addresses. */
     struct semaphore device_sem; /**< Device semaphore. */
     ec_device_stats_t device_stats; /**< Device statistics. */
 
--- a/master/module.c	Wed Nov 09 17:07:33 2011 +0100
+++ b/master/module.c	Thu Jan 12 12:14:33 2012 +0100
@@ -229,13 +229,19 @@
                 
 /*****************************************************************************/
 
+/** Maximum MAC string size.
+ */
+#define EC_MAX_MAC_STRING_SIZE (3 * ETH_ALEN)
+
 /** Print a MAC address to a buffer.
  *
+ * The buffer size must be at least EC_MAX_MAC_STRING_SIZE.
+ *
  * \return number of bytes written.
  */
 ssize_t ec_mac_print(
         const uint8_t *mac, /**< MAC address */
-        char *buffer /**< target buffer */
+        char *buffer /**< Target buffer. */
         )
 {
     off_t off = 0;
@@ -445,6 +451,13 @@
  *  Device interface
  *****************************************************************************/
 
+/** Device names.
+ */
+static const char *ec_device_names[EC_NUM_DEVICES] = {
+    "main",
+    "backup"
+};
+
 /** Offers an EtherCAT device to a certain master.
  *
  * The master decides, if it wants to use the device for EtherCAT operation,
@@ -462,8 +475,8 @@
         )
 {
     ec_master_t *master;
-    char str[20];
-    unsigned int i;
+    char str[EC_MAX_MAC_STRING_SIZE];
+    unsigned int i, j;
 
     for (i = 0; i < master_count; i++) {
         master = &masters[i];
@@ -471,39 +484,27 @@
 
         down(&master->device_sem);
 
-        if (!master->main_device.dev
-                && (ec_mac_equal(master->main_mac, net_dev->dev_addr)
-                    || ec_mac_is_broadcast(master->main_mac))) {
-
-            EC_INFO("Accepting %s as main device for master %u.\n",
-                    str, master->index);
-
-            ec_device_attach(&master->main_device, net_dev, poll, module);
-            up(&master->device_sem);
-
-            snprintf(net_dev->name, IFNAMSIZ, "ecm%u", master->index);
-
-            return &master->main_device; // offer accepted
-
-        } else if (!master->backup_device.dev
-                && ec_mac_equal(master->backup_mac, net_dev->dev_addr)) {
-
-            EC_INFO("Accepting %s as backup device for master %u.\n",
-                    str, master->index);
-
-            ec_device_attach(&master->backup_device, net_dev, poll, module);
-            up(&master->device_sem);
-
-            snprintf(net_dev->name, IFNAMSIZ, "ecb%u", master->index);
-
-            return &master->backup_device; // offer accepted
-
-        } else {
-
-            up(&master->device_sem);
-
-            EC_MASTER_DBG(master, 1, "Master declined device %s.\n", str);
-        }
+        for (j = 0; j < EC_NUM_DEVICES; j++) {
+            if (!master->devices[j].dev
+                && (ec_mac_equal(master->macs[j], net_dev->dev_addr)
+                    || ec_mac_is_broadcast(master->macs[j]))) {
+
+                EC_INFO("Accepting %s as %s device for master %u.\n",
+                        str, ec_device_names[j], master->index);
+
+                ec_device_attach(&master->devices[j], net_dev, poll, module);
+                up(&master->device_sem);
+
+                snprintf(net_dev->name, IFNAMSIZ, "ec%c%u",
+                        ec_device_names[j][0], master->index);
+
+                return &master->devices[j]; // offer accepted
+            }
+        }
+
+        up(&master->device_sem);
+
+        EC_MASTER_DBG(master, 1, "Master declined device %s.\n", str);
     }
 
     return NULL; // offer declined
@@ -522,6 +523,7 @@
         )
 {
     ec_master_t *master, *errptr = NULL;
+    unsigned int i, got_modules = 0;
 
     EC_INFO("Requesting master %u...\n", master_index);
 
@@ -558,11 +560,17 @@
         goto out_release;
     }
 
-    if (!try_module_get(master->main_device.module)) {
-        up(&master->device_sem);
-        EC_ERR("Device module is unloading!\n");
-        errptr = ERR_PTR(-ENODEV);
-        goto out_release;
+    for (i = 0; i < EC_NUM_DEVICES; i++) {
+        ec_device_t *device = &master->devices[i];
+        if (device->dev) {
+            if (!try_module_get(device->module)) {
+                up(&master->device_sem);
+                EC_MASTER_ERR(master, "Device module is unloading!\n");
+                errptr = ERR_PTR(-ENODEV);
+                goto out_module_put;
+            }
+        }
+        got_modules++;
     }
 
     up(&master->device_sem);
@@ -577,7 +585,12 @@
     return master;
 
  out_module_put:
-    module_put(master->main_device.module);
+    for (; got_modules > 0; got_modules--) {
+        ec_device_t *device = &master->devices[i - 1];
+        if (device->dev) {
+            module_put(device->module);
+        }
+    }
  out_release:
     master->reserved = 0;
  out_return:
@@ -596,6 +609,8 @@
 
 void ecrt_release_master(ec_master_t *master)
 {
+    unsigned int i;
+
     EC_MASTER_INFO(master, "Releasing master...\n");
 
     if (!master->reserved) {
@@ -606,7 +621,12 @@
 
     ec_master_leave_operation_phase(master);
 
-    module_put(master->main_device.module);
+    for (i = 0; i < EC_NUM_DEVICES; i++) {
+        if (master->devices[i].dev) {
+            module_put(master->devices[i].module);
+        }
+    }
+
     master->reserved = 0;
 
     EC_MASTER_INFO(master, "Released.\n");