merge -c1619 branches/1.4-foe: Implemented going to bootstrap state BOOT.
authorFlorian Pose <fp@igh-essen.com>
Mon, 26 Jan 2009 13:22:05 +0000
changeset 1337 0253c74d0940
parent 1336 e27b37e80a99
child 1338 eb31b5a135da
merge -c1619 branches/1.4-foe: Implemented going to bootstrap state BOOT.
NEWS
master/cdev.c
master/ethernet.c
master/fsm_change.c
master/fsm_coe.c
master/fsm_foe.c
master/fsm_master.c
master/fsm_slave_config.c
master/fsm_slave_scan.c
master/globals.h
master/ioctl.h
master/mailbox.c
master/module.c
master/slave.c
master/slave.h
tool/Command.cpp
tool/CommandSlaves.cpp
tool/CommandStates.cpp
--- a/NEWS	Mon Jan 26 13:09:27 2009 +0000
+++ b/NEWS	Mon Jan 26 13:22:05 2009 +0000
@@ -19,6 +19,9 @@
   physical device.
 * Improved error case return codes of many functions.
 * Added 8139too driver for 2.6.25.
+* Implemented the File Access over EtherCAT (FoE) mailbox protocol.
+* Going to the Bootstrap state is now supported by the state machines and the
+  command-line tool.
 
 Changes in 1.4.0:
 
--- a/master/cdev.c	Mon Jan 26 13:09:27 2009 +0000
+++ b/master/cdev.c	Mon Jan 26 13:22:05 2009 +0000
@@ -226,10 +226,14 @@
     data.revision_number = slave->sii.revision_number;
     data.serial_number = slave->sii.serial_number;
     data.alias = slave->sii.alias;
-    data.rx_mailbox_offset = slave->sii.rx_mailbox_offset;
-    data.rx_mailbox_size = slave->sii.rx_mailbox_size;
-    data.tx_mailbox_offset = slave->sii.tx_mailbox_offset;
-    data.tx_mailbox_size = slave->sii.tx_mailbox_size;
+    data.boot_rx_mailbox_offset = slave->sii.boot_rx_mailbox_offset;
+    data.boot_rx_mailbox_size = slave->sii.boot_rx_mailbox_size;
+    data.boot_tx_mailbox_offset = slave->sii.boot_tx_mailbox_offset;
+    data.boot_tx_mailbox_size = slave->sii.boot_tx_mailbox_size;
+    data.std_rx_mailbox_offset = slave->sii.std_rx_mailbox_offset;
+    data.std_rx_mailbox_size = slave->sii.std_rx_mailbox_size;
+    data.std_tx_mailbox_offset = slave->sii.std_tx_mailbox_offset;
+    data.std_tx_mailbox_size = slave->sii.std_tx_mailbox_size;
     data.mailbox_protocols = slave->sii.mailbox_protocols;
     data.has_general_category = slave->sii.has_general;
     data.coe_details = slave->sii.coe_details;
--- a/master/ethernet.c	Mon Jan 26 13:09:27 2009 +0000
+++ b/master/ethernet.c	Mon Jan 26 13:22:05 2009 +0000
@@ -218,6 +218,7 @@
 
 /**
    Sends a frame or the next fragment.
+   \todo bootstrap mailboxes / use configured mailbox sizes
 */
 
 int ec_eoe_send(ec_eoe_t *eoe /**< EoE handler */)
@@ -231,12 +232,11 @@
 
     remaining_size = eoe->tx_frame->skb->len - eoe->tx_offset;
 
-    if (remaining_size <= eoe->slave->sii.tx_mailbox_size - 10) {
+    if (remaining_size <= eoe->slave->sii.std_tx_mailbox_size - 10) {
         current_size = remaining_size;
         last_fragment = 1;
-    }
-    else {
-        current_size = ((eoe->slave->sii.tx_mailbox_size - 10) / 32) * 32;
+    } else {
+        current_size = ((eoe->slave->sii.std_tx_mailbox_size - 10) / 32) * 32;
         last_fragment = 0;
     }
 
--- a/master/fsm_change.c	Mon Jan 26 13:09:27 2009 +0000
+++ b/master/fsm_change.c	Mon Jan 26 13:22:05 2009 +0000
@@ -187,7 +187,7 @@
     if (datagram->working_counter == 0) {
         if (datagram->jiffies_received - fsm->jiffies_start >= 3 * HZ) {
             char state_str[EC_STATE_STRING_SIZE];
-            ec_state_string(fsm->requested_state, state_str);
+            ec_state_string(fsm->requested_state, state_str, 0);
             fsm->state = ec_fsm_change_state_error;
             EC_ERR("Failed to set state %s on slave %u: ",
                     state_str, fsm->slave->ring_position);
@@ -204,7 +204,7 @@
 
     if (unlikely(datagram->working_counter > 1)) {
         char state_str[EC_STATE_STRING_SIZE];
-        ec_state_string(fsm->requested_state, state_str);
+        ec_state_string(fsm->requested_state, state_str, 0);
         fsm->state = ec_fsm_change_state_error;
         EC_ERR("Failed to set state %s on slave %u: ",
                 state_str, fsm->slave->ring_position);
@@ -247,7 +247,7 @@
 
     if (datagram->working_counter != 1) {
         char req_state[EC_STATE_STRING_SIZE];
-        ec_state_string(fsm->requested_state, req_state);
+        ec_state_string(fsm->requested_state, req_state, 0);
         fsm->state = ec_fsm_change_state_error;
         EC_ERR("Failed to check state %s on slave %u: ",
                req_state, slave->ring_position);
@@ -271,7 +271,7 @@
     if (slave->current_state != fsm->old_state) { // state changed
         char req_state[EC_STATE_STRING_SIZE], cur_state[EC_STATE_STRING_SIZE];
 
-        ec_state_string(slave->current_state, cur_state);
+        ec_state_string(slave->current_state, cur_state, 0);
 
         if ((slave->current_state & 0x0F) != (fsm->old_state & 0x0F)) {
             // Slave spontaneously changed its state just before the new state
@@ -287,7 +287,7 @@
         // state change error
 
         slave->error_flag = 1;
-        ec_state_string(fsm->requested_state, req_state);
+        ec_state_string(fsm->requested_state, req_state, 0);
 
         EC_ERR("Failed to set %s state, slave %u refused state change (%s).\n",
                req_state, slave->ring_position, cur_state);
@@ -304,7 +304,7 @@
     if (datagram->jiffies_received - fsm->jiffies_start >= HZ) { // 1s
         // timeout while checking
         char state_str[EC_STATE_STRING_SIZE];
-        ec_state_string(fsm->requested_state, state_str);
+        ec_state_string(fsm->requested_state, state_str, 0);
         fsm->state = ec_fsm_change_state_error;
         EC_ERR("Timeout while setting state %s on slave %u.\n",
                 state_str, slave->ring_position);
@@ -326,7 +326,7 @@
 
 const ec_code_msg_t al_status_messages[] = {
     {0x0001, "Unspecified error"},
-    {0x0011, "Invalud requested state change"},
+    {0x0011, "Invalid requested state change"},
     {0x0012, "Unknown requested state"},
     {0x0013, "Bootstrap not supported"},
     {0x0014, "No valid firmware"},
@@ -498,7 +498,7 @@
 
     if (!(slave->current_state & EC_SLAVE_STATE_ACK_ERR)) {
         char state_str[EC_STATE_STRING_SIZE];
-        ec_state_string(slave->current_state, state_str);
+        ec_state_string(slave->current_state, state_str, 0);
         if (fsm->mode == EC_FSM_CHANGE_MODE_FULL) {
             fsm->state = ec_fsm_change_state_error;
         }
@@ -513,7 +513,7 @@
     if (datagram->jiffies_received - fsm->jiffies_start >= HZ) { // 1s
         // timeout while checking
         char state_str[EC_STATE_STRING_SIZE];
-        ec_state_string(slave->current_state, state_str);
+        ec_state_string(slave->current_state, state_str, 0);
         fsm->state = ec_fsm_change_state_error;
         EC_ERR("Timeout while acknowledging state %s on slave %u.\n",
                state_str, slave->ring_position);
--- a/master/fsm_coe.c	Mon Jan 26 13:09:27 2009 +0000
+++ b/master/fsm_coe.c	Mon Jan 26 13:22:05 2009 +0000
@@ -1095,7 +1095,7 @@
         }
 	}
     else { // request->data_size > 4, use normal transfer type
-	    if (slave->sii.rx_mailbox_size < 6 + 10 + request->data_size) {
+	    if (slave->sii.std_rx_mailbox_size < 6 + 10 + request->data_size) {
 	        EC_ERR("SDO fragmenting not supported yet!\n");
 	        fsm->state = ec_fsm_coe_error;
 	        return;
--- a/master/fsm_foe.c	Mon Jan 26 13:09:27 2009 +0000
+++ b/master/fsm_foe.c	Mon Jan 26 13:22:05 2009 +0000
@@ -214,12 +214,13 @@
 
     remaining_size = fsm->tx_buffer_size - fsm->tx_buffer_offset;
 
-    if (remaining_size < fsm->slave->sii.tx_mailbox_size - EC_MBOX_HEADER_SIZE - EC_FOE_HEADER_SIZE) {
+    if (remaining_size < fsm->slave->sii.std_tx_mailbox_size
+            - EC_MBOX_HEADER_SIZE - EC_FOE_HEADER_SIZE) {
         current_size = remaining_size;
         fsm->tx_last_packet = 1;
-    }
-    else {
-        current_size = fsm->slave->sii.tx_mailbox_size - EC_MBOX_HEADER_SIZE - EC_FOE_HEADER_SIZE;
+    } else {
+        current_size = fsm->slave->sii.std_tx_mailbox_size
+            - EC_MBOX_HEADER_SIZE - EC_FOE_HEADER_SIZE;
     }
 
     if (!(data = ec_slave_mbox_prepare_send(fsm->slave, fsm->datagram,
@@ -788,12 +789,12 @@
 
     fsm->rx_last_packet =
         (rec_size + EC_MBOX_HEADER_SIZE + EC_FOE_HEADER_SIZE
-         != fsm->slave->sii.rx_mailbox_size);
+         != fsm->slave->sii.std_rx_mailbox_size);
 
     if (fsm->rx_last_packet ||
-    	(slave->sii.rx_mailbox_size - EC_MBOX_HEADER_SIZE
-         - EC_FOE_HEADER_SIZE + fsm->rx_buffer_offset) <= fsm->rx_buffer_size) {
-    	// either it was the last packet or a new packet will fit into the delivered buffer
+            (slave->sii.std_rx_mailbox_size - EC_MBOX_HEADER_SIZE
+             - EC_FOE_HEADER_SIZE + fsm->rx_buffer_offset) <= fsm->rx_buffer_size) {
+        // either it was the last packet or a new packet will fit into the delivered buffer
 #ifdef	myDEBUG
     	printk ("last_packet=true\n");
 #endif
@@ -811,7 +812,7 @@
     	printk ("       rx_buffer_size  = %d\n", fsm->rx_buffer_size);
     	printk ("       rx_buffer_offset= %d\n", fsm->rx_buffer_offset);
     	printk ("       rec_size        = %d\n", rec_size);
-    	printk ("       rx_mailbox_size = %d\n", slave->sii.rx_mailbox_size);
+    	printk ("       rx_mailbox_size = %d\n", slave->sii.std_rx_mailbox_size);
     	printk ("       rx_last_packet  = %d\n", fsm->rx_last_packet);
 //    	fsm->state = ec_fsm_state_wait_next_read;
     	fsm->request->result = FOE_READY;
--- a/master/fsm_master.c	Mon Jan 26 13:09:27 2009 +0000
+++ b/master/fsm_master.c	Mon Jan 26 13:22:05 2009 +0000
@@ -201,7 +201,7 @@
         if (states != fsm->slave_states) { // slave states changed?
             char state_str[EC_STATE_STRING_SIZE];
             fsm->slave_states = states;
-            ec_state_string(fsm->slave_states, state_str);
+            ec_state_string(fsm->slave_states, state_str, 1);
             EC_INFO("Slave states: %s.\n", state_str);
         }
     } else {
@@ -622,8 +622,8 @@
             if (master->debug_level) {
                 char old_state[EC_STATE_STRING_SIZE],
                      new_state[EC_STATE_STRING_SIZE];
-                ec_state_string(slave->current_state, old_state);
-                ec_state_string(slave->requested_state, new_state);
+                ec_state_string(slave->current_state, old_state, 0);
+                ec_state_string(slave->requested_state, new_state, 0);
                 EC_DBG("Changing state of slave %u from %s to %s%s.\n",
                         slave->ring_position, old_state, new_state,
                         slave->force_config ? " (forced)" : "");
--- a/master/fsm_slave_config.c	Mon Jan 26 13:09:27 2009 +0000
+++ b/master/fsm_slave_config.c	Mon Jan 26 13:22:05 2009 +0000
@@ -43,7 +43,7 @@
 void ec_fsm_slave_config_state_init(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_state_clear_fmmus(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_state_mbox_sync(ec_fsm_slave_config_t *);
-void ec_fsm_slave_config_state_preop(ec_fsm_slave_config_t *);
+void ec_fsm_slave_config_state_boot_preop(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_state_sdo_conf(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_state_pdo_sync(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_state_pdo_conf(ec_fsm_slave_config_t *);
@@ -53,7 +53,7 @@
 
 void ec_fsm_slave_config_enter_init(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_enter_mbox_sync(ec_fsm_slave_config_t *);
-void ec_fsm_slave_config_enter_preop(ec_fsm_slave_config_t *);
+void ec_fsm_slave_config_enter_boot_preop(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_enter_sdo_conf(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_enter_pdo_conf(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_enter_pdo_sync(ec_fsm_slave_config_t *);
@@ -289,7 +289,7 @@
         if (master->debug_level)
             EC_DBG("Slave %u does not support mailbox communication.\n",
                     slave->ring_position);
-        ec_fsm_slave_config_enter_preop(fsm);
+        ec_fsm_slave_config_enter_boot_preop(fsm);
         return;
     }
 
@@ -298,7 +298,29 @@
                slave->ring_position);
     }
 
-    if (slave->sii.sync_count >= 2) { // mailbox configuration provided
+    if (slave->requested_state == EC_SLAVE_STATE_BOOT) {
+        ec_sync_t sync;
+
+        ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
+                EC_SYNC_PAGE_SIZE * 2);
+        memset(datagram->data, 0x00, EC_SYNC_PAGE_SIZE * 2);
+
+        ec_sync_init(&sync, slave);
+        sync.physical_start_address = slave->sii.boot_rx_mailbox_offset;
+        sync.control_register = 0x26;
+        sync.enable = 1;
+        ec_sync_page(&sync, 0, slave->sii.boot_rx_mailbox_size,
+                EC_DIR_INVALID, // use default direction
+                datagram->data);
+
+        ec_sync_init(&sync, slave);
+        sync.physical_start_address = slave->sii.boot_tx_mailbox_offset;
+        sync.control_register = 0x22;
+        sync.enable = 1;
+        ec_sync_page(&sync, 1, slave->sii.boot_tx_mailbox_size,
+                EC_DIR_INVALID, // use default direction
+                datagram->data + EC_SYNC_PAGE_SIZE);
+    } else if (slave->sii.sync_count >= 2) { // mailbox configuration provided
         ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
                 EC_SYNC_PAGE_SIZE * slave->sii.sync_count);
         ec_datagram_zero(datagram);
@@ -322,18 +344,18 @@
         ec_datagram_zero(datagram);
 
         ec_sync_init(&sync, slave);
-        sync.physical_start_address = slave->sii.rx_mailbox_offset;
+        sync.physical_start_address = slave->sii.std_rx_mailbox_offset;
         sync.control_register = 0x26;
         sync.enable = 1;
-        ec_sync_page(&sync, 0, slave->sii.rx_mailbox_size,
+        ec_sync_page(&sync, 0, slave->sii.std_rx_mailbox_size,
                 EC_DIR_INVALID, // use default direction
                 datagram->data);
 
         ec_sync_init(&sync, slave);
-        sync.physical_start_address = slave->sii.tx_mailbox_offset;
+        sync.physical_start_address = slave->sii.std_tx_mailbox_offset;
         sync.control_register = 0x22;
         sync.enable = 1;
-        ec_sync_page(&sync, 1, slave->sii.tx_mailbox_size,
+        ec_sync_page(&sync, 1, slave->sii.std_tx_mailbox_size,
                 EC_DIR_INVALID, // use default direction
                 datagram->data + EC_SYNC_PAGE_SIZE);
     }
@@ -373,27 +395,33 @@
         return;
     }
 
-    ec_fsm_slave_config_enter_preop(fsm);
+    ec_fsm_slave_config_enter_boot_preop(fsm);
 }
 
 /*****************************************************************************/
 
 /** Request PREOP state.
  */
-void ec_fsm_slave_config_enter_preop(
-        ec_fsm_slave_config_t *fsm /**< slave state machine */
-        )
-{
-    fsm->state = ec_fsm_slave_config_state_preop;
-    ec_fsm_change_start(fsm->fsm_change, fsm->slave, EC_SLAVE_STATE_PREOP);
+void ec_fsm_slave_config_enter_boot_preop(
+        ec_fsm_slave_config_t *fsm /**< slave state machine */
+        )
+{
+    fsm->state = ec_fsm_slave_config_state_boot_preop;
+
+    if (fsm->slave->requested_state != EC_SLAVE_STATE_BOOT) {
+        ec_fsm_change_start(fsm->fsm_change, fsm->slave, EC_SLAVE_STATE_PREOP);
+    } else { // BOOT
+        ec_fsm_change_start(fsm->fsm_change, fsm->slave, EC_SLAVE_STATE_BOOT);
+    }
+
     ec_fsm_change_exec(fsm->fsm_change); // execute immediately
 }
 
 /*****************************************************************************/
 
-/** Slave configuration state: PREOP.
- */
-void ec_fsm_slave_config_state_preop(
+/** Slave configuration state: BOOT/PREOP.
+ */
+void ec_fsm_slave_config_state_boot_preop(
         ec_fsm_slave_config_t *fsm /**< slave state machine */
         )
 {
@@ -409,11 +437,13 @@
         return;
     }
 
-    // slave is now in PREOP
+    // slave is now in BOOT/PREOP
     slave->jiffies_preop = fsm->datagram->jiffies_received;
 
     if (master->debug_level) {
-        EC_DBG("Slave %u is now in PREOP.\n", slave->ring_position);
+        EC_DBG("Slave %u is now in %s.\n", slave->ring_position,
+                slave->requested_state != EC_SLAVE_STATE_BOOT
+                ? "PREOP" : "BOOT");
     }
 
     if (slave->current_state == slave->requested_state) {
--- a/master/fsm_slave_scan.c	Mon Jan 26 13:09:27 2009 +0000
+++ b/master/fsm_slave_scan.c	Mon Jan 26 13:22:05 2009 +0000
@@ -237,7 +237,7 @@
     slave->current_state = EC_READ_U8(datagram->data);
     if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) {
         char state_str[EC_STATE_STRING_SIZE];
-        ec_state_string(slave->current_state, state_str);
+        ec_state_string(slave->current_state, state_str, 0);
         EC_WARN("Slave %u has state error bit set (%s)!\n",
                 slave->ring_position, state_str);
     }
@@ -469,13 +469,21 @@
         EC_READ_U32(slave->sii_words + 0x000C);
     slave->sii.serial_number =
         EC_READ_U32(slave->sii_words + 0x000E);
-    slave->sii.rx_mailbox_offset =
+    slave->sii.boot_rx_mailbox_offset =
+        EC_READ_U16(slave->sii_words + 0x0014);
+    slave->sii.boot_rx_mailbox_size =
+        EC_READ_U16(slave->sii_words + 0x0015);
+    slave->sii.boot_tx_mailbox_offset =
+        EC_READ_U16(slave->sii_words + 0x0016);
+    slave->sii.boot_tx_mailbox_size =
+        EC_READ_U16(slave->sii_words + 0x0017);
+    slave->sii.std_rx_mailbox_offset =
         EC_READ_U16(slave->sii_words + 0x0018);
-    slave->sii.rx_mailbox_size =
+    slave->sii.std_rx_mailbox_size =
         EC_READ_U16(slave->sii_words + 0x0019);
-    slave->sii.tx_mailbox_offset =
+    slave->sii.std_tx_mailbox_offset =
         EC_READ_U16(slave->sii_words + 0x001A);
-    slave->sii.tx_mailbox_size =
+    slave->sii.std_tx_mailbox_size =
         EC_READ_U16(slave->sii_words + 0x001B);
     slave->sii.mailbox_protocols =
         EC_READ_U16(slave->sii_words + 0x001C);
--- a/master/globals.h	Mon Jan 26 13:09:27 2009 +0000
+++ b/master/globals.h	Mon Jan 26 13:22:05 2009 +0000
@@ -115,6 +115,8 @@
     /**< INIT state (no mailbox communication, no IO) */
     EC_SLAVE_STATE_PREOP = 0x02,
     /**< PREOP state (mailbox communication, no IO) */
+    EC_SLAVE_STATE_BOOT = 0x03,
+    /**< Bootstrap state (mailbox communication, firmware update) */
     EC_SLAVE_STATE_SAFEOP = 0x04,
     /**< SAFEOP (mailbox communication and input update) */
     EC_SLAVE_STATE_OP = 0x08,
@@ -226,7 +228,7 @@
 
 void ec_print_data(const uint8_t *, size_t);
 void ec_print_data_diff(const uint8_t *, const uint8_t *, size_t);
-size_t ec_state_string(uint8_t, char *);
+size_t ec_state_string(uint8_t, char *, uint8_t);
 ssize_t ec_mac_print(const uint8_t *, char *);
 int ec_mac_is_zero(const uint8_t *);
 
--- a/master/ioctl.h	Mon Jan 26 13:09:27 2009 +0000
+++ b/master/ioctl.h	Mon Jan 26 13:22:05 2009 +0000
@@ -135,10 +135,14 @@
     uint32_t revision_number;
     uint32_t serial_number;
     uint16_t alias;
-    uint16_t rx_mailbox_offset;
-    uint16_t rx_mailbox_size;
-    uint16_t tx_mailbox_offset;
-    uint16_t tx_mailbox_size;
+    uint16_t boot_rx_mailbox_offset;
+    uint16_t boot_rx_mailbox_size;
+    uint16_t boot_tx_mailbox_offset;
+    uint16_t boot_tx_mailbox_size;
+    uint16_t std_rx_mailbox_offset;
+    uint16_t std_rx_mailbox_size;
+    uint16_t std_tx_mailbox_offset;
+    uint16_t std_tx_mailbox_size;
     uint16_t mailbox_protocols;
     uint8_t has_general_category;
     ec_sii_coe_details_t coe_details;
--- a/master/mailbox.c	Mon Jan 26 13:09:27 2009 +0000
+++ b/master/mailbox.c	Mon Jan 26 13:22:05 2009 +0000
@@ -53,6 +53,7 @@
 {
     size_t total_size;
     int ret;
+    uint16_t mailbox_offset, mailbox_size;
 
     if (unlikely(!slave->sii.mailbox_protocols)) {
         EC_ERR("Slave %u does not support mailbox communication!\n",
@@ -61,14 +62,22 @@
     }
 
     total_size = EC_MBOX_HEADER_SIZE + size;
-    if (unlikely(total_size > slave->sii.rx_mailbox_size)) {
+
+    if (slave->current_state != EC_SLAVE_STATE_BOOT) {
+        mailbox_offset = slave->sii.std_rx_mailbox_offset;
+        mailbox_size = slave->sii.std_rx_mailbox_size;
+    } else {
+        mailbox_offset = slave->sii.boot_rx_mailbox_offset;
+        mailbox_size = slave->sii.boot_rx_mailbox_size;
+    }
+
+    if (unlikely(total_size > mailbox_size)) {
         EC_ERR("Data size does not fit in mailbox!\n");
         return ERR_PTR(-EOVERFLOW);
     }
 
     ret = ec_datagram_fpwr(datagram, slave->station_address,
-                         slave->sii.rx_mailbox_offset,
-                         slave->sii.rx_mailbox_size);
+            mailbox_offset, mailbox_size);
     if (ret)
         return ERR_PTR(ret);
 
@@ -123,9 +132,19 @@
                                 ec_datagram_t *datagram /**< datagram */
                                 )
 {
-    int ret = ec_datagram_fprd(datagram, slave->station_address,
-                         slave->sii.tx_mailbox_offset,
-                         slave->sii.tx_mailbox_size);
+    int ret;
+    uint16_t mailbox_offset, mailbox_size;
+
+    if (slave->current_state != EC_SLAVE_STATE_BOOT) {
+        mailbox_offset = slave->sii.std_tx_mailbox_offset;
+        mailbox_size = slave->sii.std_tx_mailbox_size;
+    } else {
+        mailbox_offset = slave->sii.boot_tx_mailbox_offset;
+        mailbox_size = slave->sii.boot_tx_mailbox_size;
+    }
+
+    ret = ec_datagram_fprd(datagram, slave->station_address,
+            mailbox_offset, mailbox_size);
     if (ret)
         return ret;
 
@@ -164,13 +183,22 @@
                              )
 {
     size_t data_size;
+    uint16_t mailbox_offset, mailbox_size;
+
+    if (slave->current_state != EC_SLAVE_STATE_BOOT) {
+        mailbox_offset = slave->sii.std_tx_mailbox_offset;
+        mailbox_size = slave->sii.std_tx_mailbox_size;
+    } else {
+        mailbox_offset = slave->sii.boot_tx_mailbox_offset;
+        mailbox_size = slave->sii.boot_tx_mailbox_size;
+    }
 
     data_size = EC_READ_U16(datagram->data);
 
-    if (data_size + EC_MBOX_HEADER_SIZE > slave->sii.tx_mailbox_size) {
+    if (data_size + EC_MBOX_HEADER_SIZE > mailbox_size) {
         EC_ERR("Corrupt mailbox response received from slave %u!\n",
-               slave->ring_position);
-        ec_print_data(datagram->data, slave->sii.tx_mailbox_size);
+                slave->ring_position);
+        ec_print_data(datagram->data, mailbox_size);
         return ERR_PTR(-EPROTO);
     }
 
@@ -185,9 +213,10 @@
                 slave->ring_position);
 
         for (mbox_msg = mbox_error_messages; mbox_msg->code; mbox_msg++) {
-            if (mbox_msg->code != code) continue;
+            if (mbox_msg->code != code)
+                continue;
             printk("Code 0x%04X: \"%s\".\n",
-                   mbox_msg->code, mbox_msg->message);
+                    mbox_msg->code, mbox_msg->message);
             break;
         }
 
--- a/master/module.c	Mon Jan 26 13:09:27 2009 +0000
+++ b/master/module.c	Mon Jan 26 13:22:05 2009 +0000
@@ -358,8 +358,9 @@
 /** Prints slave states in clear text.
  */
 size_t ec_state_string(uint8_t states, /**< slave states */
-                       char *buffer /**< target buffer
+                       char *buffer, /**< target buffer
                                        (min. EC_STATE_STRING_SIZE bytes) */
+                       uint8_t multi /**< Show multi-state mask. */
                        )
 {
     off_t off = 0;
@@ -370,24 +371,42 @@
         return off;
     }
 
-    if (states & EC_SLAVE_STATE_INIT) {
-        off += sprintf(buffer + off, "INIT");
+    if (multi) { // multiple slaves
+        if (states & EC_SLAVE_STATE_INIT) {
+            off += sprintf(buffer + off, "INIT");
+            first = 0;
+        }
+        if (states & EC_SLAVE_STATE_PREOP) {
+            if (!first) off += sprintf(buffer + off, ", ");
+            off += sprintf(buffer + off, "PREOP");
+            first = 0;
+        }
+        if (states & EC_SLAVE_STATE_SAFEOP) {
+            if (!first) off += sprintf(buffer + off, ", ");
+            off += sprintf(buffer + off, "SAFEOP");
+            first = 0;
+        }
+        if (states & EC_SLAVE_STATE_OP) {
+            if (!first) off += sprintf(buffer + off, ", ");
+            off += sprintf(buffer + off, "OP");
+        }
+    } else { // single slave
+        if ((states & EC_SLAVE_STATE_MASK) == EC_SLAVE_STATE_INIT) {
+            off += sprintf(buffer + off, "INIT");
+        } else if ((states & EC_SLAVE_STATE_MASK) == EC_SLAVE_STATE_PREOP) {
+            off += sprintf(buffer + off, "PREOP");
+        } else if ((states & EC_SLAVE_STATE_MASK) == EC_SLAVE_STATE_BOOT) {
+            off += sprintf(buffer + off, "BOOT");
+        } else if ((states & EC_SLAVE_STATE_MASK) == EC_SLAVE_STATE_SAFEOP) {
+            off += sprintf(buffer + off, "SAFEOP");
+        } else if ((states & EC_SLAVE_STATE_MASK) == EC_SLAVE_STATE_OP) {
+            off += sprintf(buffer + off, "OP");
+        } else {
+            off += sprintf(buffer + off, "(invalid)");
+        }
         first = 0;
     }
-    if (states & EC_SLAVE_STATE_PREOP) {
-        if (!first) off += sprintf(buffer + off, ", ");
-        off += sprintf(buffer + off, "PREOP");
-        first = 0;
-    }
-    if (states & EC_SLAVE_STATE_SAFEOP) {
-        if (!first) off += sprintf(buffer + off, ", ");
-        off += sprintf(buffer + off, "SAFEOP");
-        first = 0;
-    }
-    if (states & EC_SLAVE_STATE_OP) {
-        if (!first) off += sprintf(buffer + off, ", ");
-        off += sprintf(buffer + off, "OP");
-    }
+
     if (states & EC_SLAVE_STATE_ACK_ERR) {
         if (!first) off += sprintf(buffer + off, " + ");
         off += sprintf(buffer + off, "ERROR");
--- a/master/slave.c	Mon Jan 26 13:09:27 2009 +0000
+++ b/master/slave.c	Mon Jan 26 13:22:05 2009 +0000
@@ -90,15 +90,19 @@
     slave->sii_words = NULL;
     slave->sii_nwords = 0;
 
-    slave->sii.alias = 0;
-    slave->sii.vendor_id = 0;
-    slave->sii.product_code = 0;
-    slave->sii.revision_number = 0;
-    slave->sii.serial_number = 0;
-    slave->sii.rx_mailbox_offset = 0;
-    slave->sii.rx_mailbox_size = 0;
-    slave->sii.tx_mailbox_offset = 0;
-    slave->sii.tx_mailbox_size = 0;
+    slave->sii.alias = 0x0000;
+    slave->sii.vendor_id = 0x00000000;
+    slave->sii.product_code = 0x00000000;
+    slave->sii.revision_number = 0x00000000;
+    slave->sii.serial_number = 0x00000000;
+    slave->sii.boot_rx_mailbox_offset = 0x0000;
+    slave->sii.boot_rx_mailbox_size = 0x0000;
+    slave->sii.boot_tx_mailbox_offset = 0x0000;
+    slave->sii.boot_tx_mailbox_size = 0x0000;
+    slave->sii.std_rx_mailbox_offset = 0x0000;
+    slave->sii.std_rx_mailbox_size = 0x0000;
+    slave->sii.std_tx_mailbox_offset = 0x0000;
+    slave->sii.std_tx_mailbox_size = 0x0000;
     slave->sii.mailbox_protocols = 0;
 
     slave->sii.strings = NULL;
@@ -199,8 +203,8 @@
         if (slave->master->debug_level) {
             char old_state[EC_STATE_STRING_SIZE],
                 cur_state[EC_STATE_STRING_SIZE];
-            ec_state_string(slave->current_state, old_state);
-            ec_state_string(new_state, cur_state);
+            ec_state_string(slave->current_state, old_state, 0);
+            ec_state_string(new_state, cur_state, 0);
             EC_DBG("Slave %u: %s -> %s.\n",
                    slave->ring_position, old_state, cur_state);
         }
--- a/master/slave.h	Mon Jan 26 13:09:27 2009 +0000
+++ b/master/slave.h	Mon Jan 26 13:22:05 2009 +0000
@@ -54,10 +54,14 @@
     uint32_t product_code; /**< Vendor-specific product code. */
     uint32_t revision_number; /**< Revision number. */
     uint32_t serial_number; /**< Serial number. */
-    uint16_t rx_mailbox_offset; /**< Mailbox address (master to slave). */
-    uint16_t rx_mailbox_size; /**< Mailbox size (master to slave). */
-    uint16_t tx_mailbox_offset; /**< Mailbox address (slave to master). */
-    uint16_t tx_mailbox_size; /**< Mailbox size (slave to master). */
+    uint16_t boot_rx_mailbox_offset; /**< Bootstrap receive mailbox address. */
+    uint16_t boot_rx_mailbox_size; /**< Bootstrap receive mailbox size. */
+    uint16_t boot_tx_mailbox_offset; /**< Bootstrap transmit mailbox address. */
+    uint16_t boot_tx_mailbox_size; /**< Bootstrap transmit mailbox size. */
+    uint16_t std_rx_mailbox_offset; /**< Standard receive mailbox address. */
+    uint16_t std_rx_mailbox_size; /**< Standard receive mailbox size. */
+    uint16_t std_tx_mailbox_offset; /**< Standard transmit mailbox address. */
+    uint16_t std_tx_mailbox_size; /**< Standard transmit mailbox size. */
     uint16_t mailbox_protocols; /**< Supported mailbox protocols. */
 
     // Strings
--- a/tool/Command.cpp	Mon Jan 26 13:09:27 2009 +0000
+++ b/tool/Command.cpp	Mon Jan 26 13:22:05 2009 +0000
@@ -284,6 +284,7 @@
     switch (state) {
         case 1: return "INIT";
         case 2: return "PREOP";
+        case 3: return "BOOT";
         case 4: return "SAFEOP";
         case 8: return "OP";
         default: return "???";
--- a/tool/CommandSlaves.cpp	Mon Jan 26 13:09:27 2009 +0000
+++ b/tool/CommandSlaves.cpp	Mon Jan 26 13:22:05 2009 +0000
@@ -216,12 +216,18 @@
             list<string>::const_iterator protoIter;
 
             cout << "Mailboxes:" << endl
-                << "  RX: 0x"
-                << hex << setw(4) << si->rx_mailbox_offset << "/"
-                << dec << si->rx_mailbox_size
+               << "  Bootstrap RX: 0x"
+                << hex << setw(4) << si->boot_rx_mailbox_offset << "/"
+                << dec << si->boot_rx_mailbox_size
                 << ", TX: 0x"
-                << hex << setw(4) << si->tx_mailbox_offset << "/"
-                << dec << si->tx_mailbox_size << endl
+                << hex << setw(4) << si->boot_tx_mailbox_offset << "/"
+                << dec << si->boot_tx_mailbox_size << endl
+                << "  Standard  RX: 0x"
+                << hex << setw(4) << si->std_rx_mailbox_offset << "/"
+                << dec << si->std_rx_mailbox_size
+                << ", TX: 0x"
+                << hex << setw(4) << si->std_tx_mailbox_offset << "/"
+                << dec << si->std_tx_mailbox_size << endl
                 << "  Supported protocols: ";
 
             if (si->mailbox_protocols & EC_MBOX_AOE) {
--- a/tool/CommandStates.cpp	Mon Jan 26 13:09:27 2009 +0000
+++ b/tool/CommandStates.cpp	Mon Jan 26 13:22:05 2009 +0000
@@ -28,7 +28,7 @@
         << getBriefDescription() << endl
         << endl
         << "Arguments:" << endl
-        << "  STATE can be 'INIT', 'PREOP', 'SAFEOP', or 'OP'." << endl
+        << "  STATE can be 'INIT', 'PREOP', 'BOOT', 'SAFEOP', or 'OP'." << endl
         << endl
         << "Command-specific options:" << endl
         << "  --alias    -a <alias>" << endl
@@ -63,6 +63,8 @@
         state = 0x01;
     } else if (stateStr == "PREOP") {
         state = 0x02;
+    } else if (stateStr == "BOOT") {
+        state = 0x03;
     } else if (stateStr == "SAFEOP") {
         state = 0x04;
     } else if (stateStr == "OP") {