IgH EtherCAT Master  1.7.0
mailbox.c
Go to the documentation of this file.
1 /*****************************************************************************
2  *
3  * Copyright (C) 2006-2008 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 
27 /****************************************************************************/
28 
29 #include <linux/slab.h>
30 #include <linux/delay.h>
31 
32 #include "mailbox.h"
33 #include "datagram.h"
34 #include "master.h"
35 
36 /****************************************************************************/
37 
41  ec_mbox_data_t *mbox_data
42  )
43 {
44  mbox_data->data = NULL;
45  mbox_data->data_size = 0;
46  mbox_data->payload_size = 0;
47 }
48 
49 /****************************************************************************/
50 
54  ec_mbox_data_t *mbox_data
55  )
56 {
57  if (mbox_data->data) {
58  kfree(mbox_data->data);
59  mbox_data->data = NULL;
60  mbox_data->data_size = 0;
61  }
62 }
63 
64 /****************************************************************************/
65 
71  ec_mbox_data_t *mbox_data,
72  size_t size
73  )
74 {
75  if (mbox_data->data) {
76  // never re-allocate, the receive path may be writing to the buffer
77  return 0;
78  }
79 
80  if (!(mbox_data->data = kmalloc(size, GFP_KERNEL))) {
81  EC_ERR("Failed to allocate %zu bytes of mailbox data memory!\n",
82  size);
83  return -ENOMEM;
84  }
85  mbox_data->data_size = size;
86  return 0;
87 }
88 
89 /****************************************************************************/
90 
101  ec_slave_t *slave
102  )
103 {
104  uint16_t protocols = slave->sii.mailbox_protocols;
105  size_t size = slave->configured_tx_mailbox_size;
106 
107  size = max_t(size_t, size, slave->sii.std_tx_mailbox_size);
108  size = max_t(size_t, size, slave->sii.boot_tx_mailbox_size);
109  if (slave->sii.sync_count >= 2) {
110  size = max_t(size_t, size, slave->sii.syncs[1].default_length);
111  }
112 
113  if (!size || size > EC_MAX_DATA_SIZE) {
114  size = EC_MAX_DATA_SIZE;
115  }
116 
117 #ifdef EC_EOE
118  if (protocols & EC_MBOX_EOE) {
119  ec_mbox_data_prealloc(&slave->mbox_eoe_data, size);
120  }
121 #endif
122  if (protocols & EC_MBOX_COE) {
123  ec_mbox_data_prealloc(&slave->mbox_coe_data, size);
124  }
125  if (protocols & EC_MBOX_FOE) {
126  ec_mbox_data_prealloc(&slave->mbox_foe_data, size);
127  }
128  if (protocols & EC_MBOX_SOE) {
129  ec_mbox_data_prealloc(&slave->mbox_soe_data, size);
130  }
131  if (protocols & EC_MBOX_VOE) {
132  ec_mbox_data_prealloc(&slave->mbox_voe_data, size);
133  }
134 }
135 
136 /****************************************************************************/
137 
143 uint8_t *ec_slave_mbox_prepare_send(const ec_slave_t *slave,
144  ec_datagram_t *datagram,
145  uint8_t type,
146  size_t size
147  )
148 {
149  size_t total_size;
150  int ret;
151 
152  if (unlikely(!slave->sii.mailbox_protocols)) {
153  EC_SLAVE_ERR(slave, "Slave does not support mailbox"
154  " communication!\n");
155  return ERR_PTR(-EPROTONOSUPPORT);
156  }
157 
158  total_size = EC_MBOX_HEADER_SIZE + size;
159 
160  if (unlikely(total_size > slave->configured_rx_mailbox_size)) {
161  EC_SLAVE_ERR(slave, "Data size (%zu) does not fit in mailbox (%u)!\n",
162  total_size, slave->configured_rx_mailbox_size);
163  return ERR_PTR(-ENOBUFS);
164  }
165 
166  ret = ec_datagram_fpwr(datagram, slave->station_address,
169  if (ret)
170  return ERR_PTR(ret);
171 
172  EC_WRITE_U16(datagram->data, size); // mailbox service data length
173  EC_WRITE_U16(datagram->data + 2, slave->station_address); // station addr.
174  EC_WRITE_U8 (datagram->data + 4, 0x00); // channel & priority
175  EC_WRITE_U8 (datagram->data + 5, type); // underlying protocol type
176 
177  return datagram->data + EC_MBOX_HEADER_SIZE;
178 }
179 
180 /****************************************************************************/
181 
189  ec_datagram_t *datagram
190  )
191 {
192  int ret = ec_datagram_fprd(datagram, slave->station_address, 0x808, 8);
193  if (ret)
194  return ret;
195 
196  ec_datagram_zero(datagram);
197  return 0;
198 }
199 
200 /****************************************************************************/
201 
207 int ec_slave_mbox_check(const ec_datagram_t *datagram )
208 {
209  return EC_READ_U8(datagram->data + 5) & 8 ? 1 : 0;
210 }
211 
212 /****************************************************************************/
213 
220  ec_datagram_t *datagram
221  )
222 {
223  int ret = ec_datagram_fprd(datagram, slave->station_address,
226  if (ret)
227  return ret;
228 
229  ec_datagram_zero(datagram);
230  return 0;
231 }
232 
233 /****************************************************************************/
234 
247  ec_mbox_data_t *mbox_data,
248  const ec_datagram_t *datagram
249  )
250 {
251  if (datagram->working_counter != 1 ||
252  datagram->data_size < EC_MBOX_HEADER_SIZE ||
253  !EC_READ_U16(datagram->data) || // length
254  (EC_READ_U8(datagram->data + 5) & 0x0F) != 0x00) { // type
255  return;
256  }
257 
258  if (mbox_data->data && datagram->data_size <= mbox_data->data_size) {
259  memcpy(mbox_data->data, datagram->data, datagram->data_size);
260  smp_store_release(&mbox_data->payload_size, datagram->data_size);
261  }
262 }
263 
264 /****************************************************************************/
265 
271  {0x00000001, "MBXERR_SYNTAX"},
272  {0x00000002, "MBXERR_UNSUPPORTEDPROTOCOL"},
273  {0x00000003, "MBXERR_INVAILDCHANNEL"},
274  {0x00000004, "MBXERR_SERVICENOTSUPPORTED"},
275  {0x00000005, "MBXERR_INVALIDHEADER"},
276  {0x00000006, "MBXERR_SIZETOOSHORT"},
277  {0x00000007, "MBXERR_NOMOREMEMORY"},
278  {0x00000008, "MBXERR_INVALIDSIZE"},
279  {}
280 };
281 
282 /****************************************************************************/
283 
290 uint8_t *ec_slave_mbox_fetch(const ec_slave_t *slave,
291  ec_mbox_data_t *response_data,
292  uint8_t *type,
293  size_t *size
294  )
295 {
296  size_t data_size;
297 
298  if (!response_data->data) {
299  EC_SLAVE_ERR(slave, "No mailbox response data received!\n");
300  return ERR_PTR(-EPROTO);
301  }
302 
303  response_data->payload_size = 0;
304  data_size = EC_READ_U16(response_data->data);
305 
306  if (data_size + EC_MBOX_HEADER_SIZE > slave->configured_tx_mailbox_size) {
307  EC_SLAVE_ERR(slave, "Corrupt mailbox response received!\n");
308  ec_print_data(response_data->data, slave->configured_tx_mailbox_size);
309  return ERR_PTR(-EPROTO);
310  }
311 
312  *type = EC_READ_U8(response_data->data + 5) & 0x0F;
313  *size = data_size;
314 
315  if (*type == 0x00) {
316  const ec_code_msg_t *mbox_msg;
317  uint16_t code = EC_READ_U16(response_data->data + 8);
318 
319  EC_SLAVE_ERR(slave, "Mailbox error response received - ");
320 
321  for (mbox_msg = mbox_error_messages; mbox_msg->code; mbox_msg++) {
322  if (mbox_msg->code != code)
323  continue;
324  printk(KERN_CONT "Code 0x%04X: \"%s\".\n",
325  mbox_msg->code, mbox_msg->message);
326  break;
327  }
328 
329  if (!mbox_msg->code) {
330  printk(KERN_CONT "Unknown error reply code 0x%04X.\n", code);
331  }
332 
333  if (slave->master->debug_level)
334  ec_print_data(response_data->data + EC_MBOX_HEADER_SIZE,
335  data_size);
336 
337  return ERR_PTR(-EPROTO);
338  }
339 
340  return response_data->data + EC_MBOX_HEADER_SIZE;
341 }
342 
343 /****************************************************************************/
uint8_t * data
Mailbox response data.
Definition: mailbox.h:59
CANopen over EtherCAT.
Definition: globals.h:152
uint8_t * ec_slave_mbox_prepare_send(const ec_slave_t *slave, ec_datagram_t *datagram, uint8_t type, size_t size)
Prepares a mailbox-send datagram.
Definition: mailbox.c:143
ec_sii_t sii
Extracted SII data.
Definition: slave.h:218
size_t data_size
Size of the data in data.
Definition: datagram.h:94
uint16_t configured_tx_mailbox_size
Configured send mailbox size.
Definition: slave.h:195
void ec_mbox_data_clear(ec_mbox_data_t *mbox_data)
Free internal memory for mailbox response data.
Definition: mailbox.c:53
uint16_t configured_tx_mailbox_offset
Configured send mailbox offset.
Definition: slave.h:193
ec_mbox_data_t mbox_foe_data
Received mailbox data for FoE.
Definition: slave.h:239
int ec_slave_mbox_prepare_fetch(const ec_slave_t *slave, ec_datagram_t *datagram)
Prepares a datagram to fetch mailbox data.
Definition: mailbox.c:219
uint32_t code
Code.
Definition: globals.h:281
Servo-Profile over EtherCAT.
Definition: globals.h:154
EtherCAT mailbox response data.
Definition: mailbox.h:58
EtherCAT datagram.
Definition: datagram.h:81
void ec_slave_mbox_prealloc(ec_slave_t *slave)
Allocates the mailbox response buffers of a slave.
Definition: mailbox.c:100
#define EC_WRITE_U8(DATA, VAL)
Write an 8-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3353
ec_mbox_data_t mbox_eoe_data
Received mailbox data for EoE.
Definition: slave.h:236
uint8_t * ec_slave_mbox_fetch(const ec_slave_t *slave, ec_mbox_data_t *response_data, uint8_t *type, size_t *size)
Processes received mailbox data.
Definition: mailbox.c:290
uint16_t working_counter
Working counter.
Definition: datagram.h:96
uint16_t boot_tx_mailbox_size
Bootstrap transmit mailbox size.
Definition: slave.h:136
uint16_t station_address
Configured station address.
Definition: slave.h:178
const char * message
Message belonging to code.
Definition: globals.h:282
unsigned int sync_count
Number of sync managers.
Definition: slave.h:160
EtherCAT master structure.
void ec_slave_mbox_take_error(ec_mbox_data_t *mbox_data, const ec_datagram_t *datagram)
Takes over a mailbox error response from a mailbox fetch datagram.
Definition: mailbox.c:246
EtherCAT slave.
Definition: slave.h:170
void ec_datagram_zero(ec_datagram_t *datagram)
Fills the datagram payload memory with zeros.
Definition: datagram.c:178
Code/Message pair.
Definition: globals.h:280
static int ec_mbox_data_prealloc(ec_mbox_data_t *mbox_data, size_t size)
Allocates internal memory for mailbox response data.
Definition: mailbox.c:70
Ethernet over EtherCAT.
Definition: globals.h:151
uint16_t mailbox_protocols
Supported mailbox protocols.
Definition: slave.h:141
size_t data_size
Size of the mailbox response data buffer.
Definition: mailbox.h:60
unsigned int debug_level
Master debug level.
Definition: master.h:284
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition: slave.h:70
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3370
uint16_t configured_rx_mailbox_offset
Configured receive mailbox offset.
Definition: slave.h:189
File-Access over EtherCAT.
Definition: globals.h:153
ec_master_t * master
Master owning the slave.
Definition: slave.h:172
int ec_datagram_fpwr(ec_datagram_t *datagram, uint16_t configured_address, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT FPWR datagram.
Definition: datagram.c:298
int ec_datagram_fprd(ec_datagram_t *datagram, uint16_t configured_address, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT FPRD datagram.
Definition: datagram.c:273
EtherCAT datagram structure.
const ec_code_msg_t mbox_error_messages[]
Mailbox error codes.
Definition: mailbox.c:270
#define EC_MBOX_HEADER_SIZE
Mailbox header size.
Definition: globals.h:83
void ec_print_data(const uint8_t *, size_t)
Outputs frame contents for debugging purposes.
Definition: module.c:348
int ec_slave_mbox_prepare_check(const ec_slave_t *slave, ec_datagram_t *datagram)
Prepares a datagram for checking the mailbox state.
Definition: mailbox.c:188
#define EC_READ_U16(DATA)
Read a 16-bit unsigned value from EtherCAT data.
Definition: ecrt.h:3261
Mailbox functionality.
#define EC_ERR(fmt, args...)
Convenience macro for printing EtherCAT-specific errors to syslog.
Definition: globals.h:229
ec_mbox_data_t mbox_voe_data
Received mailbox data for VoE.
Definition: slave.h:241
uint16_t configured_rx_mailbox_size
Configured receive mailbox size.
Definition: slave.h:191
uint8_t * data
Datagram payload.
Definition: datagram.h:91
#define EC_READ_U8(DATA)
Read an 8-bit unsigned value from EtherCAT data.
Definition: ecrt.h:3245
void ec_mbox_data_init(ec_mbox_data_t *mbox_data)
Initialize mailbox response data.
Definition: mailbox.c:40
uint16_t default_length
Data length in bytes.
Definition: sync.h:42
ec_sync_t * syncs
SYNC MANAGER categories.
Definition: slave.h:159
uint16_t std_tx_mailbox_size
Standard transmit mailbox size.
Definition: slave.h:140
Vendor specific.
Definition: globals.h:155
ec_mbox_data_t mbox_coe_data
Received mailbox data for CoE.
Definition: slave.h:238
ec_mbox_data_t mbox_soe_data
Received mailbox data for SoE.
Definition: slave.h:240
size_t payload_size
Size of the mailbox response payload data.
Definition: mailbox.h:61
int ec_slave_mbox_check(const ec_datagram_t *datagram)
Processes a mailbox state checking datagram.
Definition: mailbox.c:207
#define EC_MAX_DATA_SIZE
Resulting maximum data size of a single datagram in a frame.
Definition: globals.h:79