156 list_for_each_entry_safe(datagram, next, &domain->datagrams, list) { |
159 list_for_each_entry_safe(datagram, next, &domain->datagrams, list) { |
157 ec_datagram_clear(datagram); |
160 ec_datagram_clear(datagram); |
158 kfree(datagram); |
161 kfree(datagram); |
159 } |
162 } |
160 |
163 |
|
164 ec_domain_clear_data(domain); |
|
165 |
161 kfree(domain); |
166 kfree(domain); |
|
167 } |
|
168 |
|
169 /*****************************************************************************/ |
|
170 |
|
171 /** Frees internally allocated memory. |
|
172 */ |
|
173 void ec_domain_clear_data( |
|
174 ec_domain_t *domain /**< EtherCAT domain. */ |
|
175 ) |
|
176 { |
|
177 if (domain->data_origin == EC_ORIG_INTERNAL && domain->data) |
|
178 kfree(domain->data); |
|
179 domain->data = NULL; |
|
180 domain->data_origin = EC_ORIG_INTERNAL; |
162 } |
181 } |
163 |
182 |
164 /*****************************************************************************/ |
183 /*****************************************************************************/ |
165 |
184 |
166 /** Allocates a domain datagram and appends it to the list. |
185 /** Allocates a domain datagram and appends it to the list. |
167 * |
186 * |
168 * \return 0 in case of success, else < 0 |
187 * \return 0 in case of success, else < 0 |
169 */ |
188 */ |
170 int ec_domain_add_datagram( |
189 int ec_domain_add_datagram( |
171 ec_domain_t *domain, /**< EtherCAT domain. */ |
190 ec_domain_t *domain, /**< EtherCAT domain. */ |
172 uint32_t offset, /**< Logical offset. */ |
191 uint32_t logical_offset, /**< Logical offset. */ |
173 size_t data_size /**< Size of the data. */ |
192 size_t data_size, /**< Size of the data. */ |
|
193 uint8_t *data /**< Process data. */ |
174 ) |
194 ) |
175 { |
195 { |
176 ec_datagram_t *datagram; |
196 ec_datagram_t *datagram; |
177 |
197 |
178 if (!(datagram = kmalloc(sizeof(ec_datagram_t), GFP_KERNEL))) { |
198 if (!(datagram = kmalloc(sizeof(ec_datagram_t), GFP_KERNEL))) { |
197 |
217 |
198 /** Finishes a domain. |
218 /** Finishes a domain. |
199 * |
219 * |
200 * This allocates the necessary datagrams and writes the correct logical |
220 * This allocates the necessary datagrams and writes the correct logical |
201 * addresses to every configured FMMU. |
221 * addresses to every configured FMMU. |
|
222 * |
|
223 * \todo Check for FMMUs that do not fit into any datagram. |
202 * |
224 * |
203 * \retval 0 in case of success |
225 * \retval 0 in case of success |
204 * \retval <0 on failure. |
226 * \retval <0 on failure. |
205 */ |
227 */ |
206 int ec_domain_finish( |
228 int ec_domain_finish( |
207 ec_domain_t *domain, /**< EtherCAT domain. */ |
229 ec_domain_t *domain, /**< EtherCAT domain. */ |
208 uint32_t base_address /**< Logical base address. */ |
230 uint32_t base_address /**< Logical base address. */ |
209 ) |
231 ) |
210 { |
232 { |
211 uint32_t datagram_offset; |
233 uint32_t datagram_offset; |
212 size_t datagram_data_size; |
234 size_t datagram_size; |
213 unsigned int datagram_count, i; |
235 unsigned int datagram_count, i; |
214 ec_slave_config_t *sc; |
236 ec_slave_config_t *sc; |
215 ec_fmmu_config_t *fmmu; |
237 ec_fmmu_config_t *fmmu; |
216 |
238 |
217 domain->base_address = base_address; |
239 domain->logical_base_address = base_address; |
218 |
240 |
219 // Cycle through all domain FMMUS, add the logical base address and assign |
241 if (domain->data_size && domain->data_origin == EC_ORIG_INTERNAL) { |
220 // as many PDO entries as possible to the datagrams. |
242 if (!(domain->data = |
221 datagram_offset = base_address; |
243 (uint8_t *) kmalloc(domain->data_size, GFP_KERNEL))) { |
222 datagram_data_size = 0; |
244 EC_ERR("Failed to allocate %u bytes internal memory for" |
|
245 " domain %u!\n", domain->data_size, domain->index); |
|
246 return -1; |
|
247 } |
|
248 } |
|
249 |
|
250 // Cycle through all domain FMMUS, correct the logical base addresses and |
|
251 // set up the datagrams to carry the process data. |
|
252 datagram_offset = 0; |
|
253 datagram_size = 0; |
223 datagram_count = 0; |
254 datagram_count = 0; |
224 list_for_each_entry(sc, &domain->master->configs, list) { |
255 list_for_each_entry(sc, &domain->master->configs, list) { |
225 for (i = 0; i < sc->used_fmmus; i++) { |
256 for (i = 0; i < sc->used_fmmus; i++) { |
226 fmmu = &sc->fmmu_configs[i]; |
257 fmmu = &sc->fmmu_configs[i]; |
227 if (fmmu->domain != domain) |
258 if (fmmu->domain != domain) |
228 continue; |
259 continue; |
229 |
260 |
|
261 // Correct logical FMMU address |
230 fmmu->logical_start_address += base_address; |
262 fmmu->logical_start_address += base_address; |
231 if (datagram_data_size + fmmu->data_size > EC_MAX_DATA_SIZE) { |
263 |
232 if (ec_domain_add_datagram(domain, datagram_offset, |
264 // If the current FMMU's data do not fit in the current datagram, |
233 datagram_data_size)) return -1; |
265 // allocate a new one. |
234 datagram_offset += datagram_data_size; |
266 if (datagram_size + fmmu->data_size > EC_MAX_DATA_SIZE) { |
235 datagram_data_size = 0; |
267 if (ec_domain_add_datagram(domain, |
|
268 domain->logical_base_address + datagram_offset, |
|
269 datagram_size, domain->data + datagram_offset)) |
|
270 return -1; |
|
271 datagram_offset += datagram_size; |
|
272 datagram_size = 0; |
236 datagram_count++; |
273 datagram_count++; |
237 } |
274 } |
238 datagram_data_size += fmmu->data_size; |
275 |
239 } |
276 datagram_size += fmmu->data_size; |
240 } |
277 } |
241 |
278 } |
242 // allocate last datagram |
279 |
243 if (datagram_data_size) { |
280 // allocate last datagram, if data are left |
244 if (ec_domain_add_datagram(domain, datagram_offset, |
281 if (datagram_size) { |
245 datagram_data_size)) |
282 if (ec_domain_add_datagram(domain, |
|
283 domain->logical_base_address + datagram_offset, |
|
284 datagram_size, domain->data + datagram_offset)) |
246 return -1; |
285 return -1; |
247 datagram_count++; |
286 datagram_count++; |
248 } |
287 } |
249 |
288 |
250 EC_INFO("Domain %u with logical offset %u contains %u bytes in %u" |
289 EC_INFO("Domain %u with logical offset %u contains %u bytes in %u" |
251 " datagram%s.\n", domain->index, domain->base_address, |
290 " datagram%s.\n", domain->index, domain->logical_base_address, |
252 domain->data_size, datagram_count, datagram_count == 1 ? "" : "s"); |
291 domain->data_size, datagram_count, datagram_count == 1 ? "" : "s"); |
253 return 0; |
292 return 0; |
254 } |
293 } |
255 |
294 |
256 /*****************************************************************************/ |
295 /*****************************************************************************/ |