55 void ec_slave_clear(struct kobject *); |
55 void ec_slave_clear(struct kobject *); |
56 void ec_slave_sdos_clear(struct kobject *); |
56 void ec_slave_sdos_clear(struct kobject *); |
57 ssize_t ec_show_slave_attribute(struct kobject *, struct attribute *, char *); |
57 ssize_t ec_show_slave_attribute(struct kobject *, struct attribute *, char *); |
58 ssize_t ec_store_slave_attribute(struct kobject *, struct attribute *, |
58 ssize_t ec_store_slave_attribute(struct kobject *, struct attribute *, |
59 const char *, size_t); |
59 const char *, size_t); |
|
60 char *ec_slave_sii_string(ec_slave_t *, unsigned int); |
60 |
61 |
61 /*****************************************************************************/ |
62 /*****************************************************************************/ |
62 |
63 |
63 /** \cond */ |
64 /** \cond */ |
64 |
65 |
65 EC_SYSFS_READ_ATTR(info); |
66 EC_SYSFS_READ_ATTR(info); |
66 EC_SYSFS_READ_WRITE_ATTR(state); |
67 EC_SYSFS_READ_WRITE_ATTR(state); |
67 EC_SYSFS_READ_WRITE_ATTR(eeprom); |
68 EC_SYSFS_READ_WRITE_ATTR(eeprom); |
|
69 EC_SYSFS_READ_WRITE_ATTR(alias); |
68 |
70 |
69 static struct attribute *def_attrs[] = { |
71 static struct attribute *def_attrs[] = { |
70 &attr_info, |
72 &attr_info, |
71 &attr_state, |
73 &attr_state, |
72 &attr_eeprom, |
74 &attr_eeprom, |
|
75 &attr_alias, |
73 NULL, |
76 NULL, |
74 }; |
77 }; |
75 |
78 |
76 static struct sysfs_ops sysfs_ops = { |
79 static struct sysfs_ops sysfs_ops = { |
77 .show = ec_show_slave_attribute, |
80 .show = ec_show_slave_attribute, |
108 slave->ring_position = ring_position; |
111 slave->ring_position = ring_position; |
109 slave->station_address = station_address; |
112 slave->station_address = station_address; |
110 |
113 |
111 slave->master = master; |
114 slave->master = master; |
112 |
115 |
113 slave->requested_state = EC_SLAVE_STATE_UNKNOWN; |
116 slave->requested_state = EC_SLAVE_STATE_PREOP; |
114 slave->current_state = EC_SLAVE_STATE_UNKNOWN; |
117 slave->current_state = EC_SLAVE_STATE_UNKNOWN; |
115 slave->self_configured = 0; |
118 slave->self_configured = 0; |
116 slave->error_flag = 0; |
119 slave->error_flag = 0; |
117 slave->online = 1; |
120 slave->online_state = EC_SLAVE_ONLINE; |
118 slave->fmmu_count = 0; |
121 slave->fmmu_count = 0; |
119 |
122 slave->pdos_registered = 0; |
120 slave->coupler_index = 0; |
|
121 slave->coupler_subindex = 0xFFFF; |
|
122 |
123 |
123 slave->base_type = 0; |
124 slave->base_type = 0; |
124 slave->base_revision = 0; |
125 slave->base_revision = 0; |
125 slave->base_build = 0; |
126 slave->base_build = 0; |
126 slave->base_fmmu_count = 0; |
127 slave->base_fmmu_count = 0; |
127 slave->base_sync_count = 0; |
|
128 |
128 |
129 slave->eeprom_data = NULL; |
129 slave->eeprom_data = NULL; |
130 slave->eeprom_size = 0; |
130 slave->eeprom_size = 0; |
131 slave->new_eeprom_data = NULL; |
|
132 slave->new_eeprom_size = 0; |
|
133 |
131 |
134 slave->sii_alias = 0; |
132 slave->sii_alias = 0; |
135 slave->sii_vendor_id = 0; |
133 slave->sii_vendor_id = 0; |
136 slave->sii_product_code = 0; |
134 slave->sii_product_code = 0; |
137 slave->sii_revision_number = 0; |
135 slave->sii_revision_number = 0; |
236 */ |
236 */ |
237 |
237 |
238 void ec_slave_clear(struct kobject *kobj /**< kobject of the slave */) |
238 void ec_slave_clear(struct kobject *kobj /**< kobject of the slave */) |
239 { |
239 { |
240 ec_slave_t *slave; |
240 ec_slave_t *slave; |
241 ec_sii_string_t *string, *next_str; |
241 ec_pdo_t *pdo, *next_pdo; |
242 ec_sii_sync_t *sync, *next_sync; |
|
243 ec_sii_pdo_t *pdo, *next_pdo; |
|
244 ec_sii_pdo_entry_t *entry, *next_ent; |
|
245 ec_sdo_data_t *sdodata, *next_sdodata; |
242 ec_sdo_data_t *sdodata, *next_sdodata; |
|
243 unsigned int i; |
246 |
244 |
247 slave = container_of(kobj, ec_slave_t, kobj); |
245 slave = container_of(kobj, ec_slave_t, kobj); |
248 |
246 |
249 // free all string objects |
247 // free all strings |
250 list_for_each_entry_safe(string, next_str, &slave->sii_strings, list) { |
248 if (slave->sii_strings) { |
251 list_del(&string->list); |
249 for (i = 0; i < slave->sii_string_count; i++) |
252 kfree(string); |
250 kfree(slave->sii_strings[i]); |
|
251 kfree(slave->sii_strings); |
253 } |
252 } |
254 |
253 |
255 // free all sync managers |
254 // free all sync managers |
256 list_for_each_entry_safe(sync, next_sync, &slave->sii_syncs, list) { |
255 if (slave->sii_syncs) { |
257 list_del(&sync->list); |
256 for (i = 0; i < slave->sii_sync_count; i++) { |
258 kfree(sync); |
257 ec_sync_clear(&slave->sii_syncs[i]); |
259 } |
258 } |
260 |
259 kfree(slave->sii_syncs); |
261 // free all PDOs |
260 } |
|
261 |
|
262 // free all SII PDOs |
262 list_for_each_entry_safe(pdo, next_pdo, &slave->sii_pdos, list) { |
263 list_for_each_entry_safe(pdo, next_pdo, &slave->sii_pdos, list) { |
263 list_del(&pdo->list); |
264 list_del(&pdo->list); |
264 if (pdo->name) kfree(pdo->name); |
265 ec_pdo_clear(pdo); |
265 |
|
266 // free all PDO entries |
|
267 list_for_each_entry_safe(entry, next_ent, &pdo->entries, list) { |
|
268 list_del(&entry->list); |
|
269 if (entry->name) kfree(entry->name); |
|
270 kfree(entry); |
|
271 } |
|
272 |
|
273 kfree(pdo); |
266 kfree(pdo); |
274 } |
267 } |
275 |
|
276 if (slave->sii_group) kfree(slave->sii_group); |
|
277 if (slave->sii_image) kfree(slave->sii_image); |
|
278 if (slave->sii_order) kfree(slave->sii_order); |
|
279 if (slave->sii_name) kfree(slave->sii_name); |
|
280 |
268 |
281 // free all SDO configurations |
269 // free all SDO configurations |
282 list_for_each_entry_safe(sdodata, next_sdodata, &slave->sdo_confs, list) { |
270 list_for_each_entry_safe(sdodata, next_sdodata, &slave->sdo_confs, list) { |
283 list_del(&sdodata->list); |
271 list_del(&sdodata->list); |
284 kfree(sdodata->data); |
272 kfree(sdodata->data); |
285 kfree(sdodata); |
273 kfree(sdodata); |
286 } |
274 } |
287 |
275 |
288 if (slave->eeprom_data) kfree(slave->eeprom_data); |
276 if (slave->eeprom_data) kfree(slave->eeprom_data); |
289 if (slave->new_eeprom_data) kfree(slave->new_eeprom_data); |
|
290 |
277 |
291 kfree(slave); |
278 kfree(slave); |
292 } |
279 } |
293 |
280 |
294 /*****************************************************************************/ |
281 /*****************************************************************************/ |
307 */ |
294 */ |
308 |
295 |
309 void ec_slave_reset(ec_slave_t *slave /**< EtherCAT slave */) |
296 void ec_slave_reset(ec_slave_t *slave /**< EtherCAT slave */) |
310 { |
297 { |
311 ec_sdo_data_t *sdodata, *next_sdodata; |
298 ec_sdo_data_t *sdodata, *next_sdodata; |
312 ec_sii_sync_t *sync; |
299 unsigned int i; |
313 |
300 |
314 // remove FMMU configurations |
|
315 slave->fmmu_count = 0; |
301 slave->fmmu_count = 0; |
|
302 slave->pdos_registered = 0; |
316 |
303 |
317 // free all SDO configurations |
304 // free all SDO configurations |
318 list_for_each_entry_safe(sdodata, next_sdodata, &slave->sdo_confs, list) { |
305 list_for_each_entry_safe(sdodata, next_sdodata, &slave->sdo_confs, list) { |
319 list_del(&sdodata->list); |
306 list_del(&sdodata->list); |
320 kfree(sdodata->data); |
307 kfree(sdodata->data); |
321 kfree(sdodata); |
308 kfree(sdodata); |
322 } |
309 } |
323 |
310 |
324 // remove estimated sync manager sizes |
311 // remove estimated sync manager sizes |
325 list_for_each_entry(sync, &slave->sii_syncs, list) { |
312 for (i = 0; i < slave->sii_sync_count; i++) { |
326 sync->est_length = 0; |
313 slave->sii_syncs[i].est_length = 0; |
327 } |
314 } |
328 } |
315 } |
329 |
316 |
330 /*****************************************************************************/ |
317 /*****************************************************************************/ |
331 |
318 |
332 /** |
319 /** |
|
320 * Sets the application state of a slave. |
333 */ |
321 */ |
334 |
322 |
335 void ec_slave_request_state(ec_slave_t *slave, /**< ETherCAT slave */ |
323 void ec_slave_set_state(ec_slave_t *slave, /**< EtherCAT slave */ |
|
324 ec_slave_state_t new_state /**< new application state */ |
|
325 ) |
|
326 { |
|
327 if (new_state != slave->current_state) { |
|
328 if (slave->master->debug_level) { |
|
329 char old_state[EC_STATE_STRING_SIZE], |
|
330 cur_state[EC_STATE_STRING_SIZE]; |
|
331 ec_state_string(slave->current_state, old_state); |
|
332 ec_state_string(new_state, cur_state); |
|
333 EC_DBG("Slave %i: %s -> %s.\n", |
|
334 slave->ring_position, old_state, cur_state); |
|
335 } |
|
336 slave->current_state = new_state; |
|
337 } |
|
338 } |
|
339 |
|
340 /*****************************************************************************/ |
|
341 |
|
342 /** |
|
343 * Sets the online state of a slave. |
|
344 */ |
|
345 |
|
346 void ec_slave_set_online_state(ec_slave_t *slave, /**< EtherCAT slave */ |
|
347 ec_slave_online_state_t new_state /**< new online state */ |
|
348 ) |
|
349 { |
|
350 if (new_state == EC_SLAVE_OFFLINE && |
|
351 slave->online_state == EC_SLAVE_ONLINE) { |
|
352 if (slave->pdos_registered) |
|
353 slave->master->pdo_slaves_offline++; |
|
354 if (slave->master->debug_level) |
|
355 EC_DBG("Slave %i: offline.\n", slave->ring_position); |
|
356 } |
|
357 else if (new_state == EC_SLAVE_ONLINE && |
|
358 slave->online_state == EC_SLAVE_OFFLINE) { |
|
359 slave->error_flag = 0; // clear error flag |
|
360 if (slave->pdos_registered) |
|
361 slave->master->pdo_slaves_offline--; |
|
362 if (slave->master->debug_level) { |
|
363 char cur_state[EC_STATE_STRING_SIZE]; |
|
364 ec_state_string(slave->current_state, cur_state); |
|
365 EC_DBG("Slave %i: online (%s).\n", |
|
366 slave->ring_position, cur_state); |
|
367 } |
|
368 } |
|
369 |
|
370 slave->online_state = new_state; |
|
371 } |
|
372 |
|
373 /*****************************************************************************/ |
|
374 |
|
375 /** |
|
376 */ |
|
377 |
|
378 void ec_slave_request_state(ec_slave_t *slave, /**< EtherCAT slave */ |
336 ec_slave_state_t state /**< new state */ |
379 ec_slave_state_t state /**< new state */ |
337 ) |
380 ) |
338 { |
381 { |
339 slave->requested_state = state; |
382 slave->requested_state = state; |
340 slave->error_flag = 0; |
383 slave->error_flag = 0; |
345 /** |
388 /** |
346 Fetches data from a STRING category. |
389 Fetches data from a STRING category. |
347 \return 0 in case of success, else < 0 |
390 \return 0 in case of success, else < 0 |
348 */ |
391 */ |
349 |
392 |
350 int ec_slave_fetch_strings(ec_slave_t *slave, /**< EtherCAT slave */ |
393 int ec_slave_fetch_sii_strings( |
351 const uint8_t *data /**< category data */ |
394 ec_slave_t *slave, /**< EtherCAT slave */ |
352 ) |
395 const uint8_t *data /**< category data */ |
353 { |
396 ) |
354 unsigned int string_count, i; |
397 { |
|
398 int i; |
355 size_t size; |
399 size_t size; |
356 off_t offset; |
400 off_t offset; |
357 ec_sii_string_t *string; |
401 |
358 |
402 slave->sii_string_count = data[0]; |
359 string_count = data[0]; |
403 |
|
404 if (!slave->sii_string_count) |
|
405 return 0; |
|
406 |
|
407 if (!(slave->sii_strings = |
|
408 kmalloc(sizeof(char *) * slave->sii_string_count, |
|
409 GFP_KERNEL))) { |
|
410 EC_ERR("Failed to allocate string array memory.\n"); |
|
411 goto out_zero; |
|
412 } |
|
413 |
360 offset = 1; |
414 offset = 1; |
361 for (i = 0; i < string_count; i++) { |
415 for (i = 0; i < slave->sii_string_count; i++) { |
362 size = data[offset]; |
416 size = data[offset]; |
363 // allocate memory for string structure and data at a single blow |
417 // allocate memory for string structure and data at a single blow |
364 if (!(string = (ec_sii_string_t *) |
418 if (!(slave->sii_strings[i] = |
365 kmalloc(sizeof(ec_sii_string_t) + size + 1, GFP_ATOMIC))) { |
419 kmalloc(sizeof(char) * size + 1, GFP_KERNEL))) { |
366 EC_ERR("Failed to allocate string memory.\n"); |
420 EC_ERR("Failed to allocate string memory.\n"); |
367 return -1; |
421 goto out_free; |
368 } |
422 } |
369 string->size = size; |
423 memcpy(slave->sii_strings[i], data + offset + 1, size); |
370 // string memory appended to string structure |
424 slave->sii_strings[i][size] = 0x00; // append binary zero |
371 string->data = (char *) string + sizeof(ec_sii_string_t); |
|
372 memcpy(string->data, data + offset + 1, size); |
|
373 string->data[size] = 0x00; |
|
374 list_add_tail(&string->list, &slave->sii_strings); |
|
375 offset += 1 + size; |
425 offset += 1 + size; |
376 } |
426 } |
377 |
427 |
378 return 0; |
428 return 0; |
|
429 |
|
430 out_free: |
|
431 for (i--; i >= 0; i--) kfree(slave->sii_strings[i]); |
|
432 kfree(slave->sii_strings); |
|
433 slave->sii_strings = NULL; |
|
434 out_zero: |
|
435 slave->sii_string_count = 0; |
|
436 return -1; |
379 } |
437 } |
380 |
438 |
381 /*****************************************************************************/ |
439 /*****************************************************************************/ |
382 |
440 |
383 /** |
441 /** |
384 Fetches data from a GENERAL category. |
442 Fetches data from a GENERAL category. |
385 \return 0 in case of success, else < 0 |
443 \return 0 in case of success, else < 0 |
386 */ |
444 */ |
387 |
445 |
388 void ec_slave_fetch_general(ec_slave_t *slave, /**< EtherCAT slave */ |
446 void ec_slave_fetch_sii_general( |
389 const uint8_t *data /**< category data */ |
447 ec_slave_t *slave, /**< EtherCAT slave */ |
390 ) |
448 const uint8_t *data /**< category data */ |
|
449 ) |
391 { |
450 { |
392 unsigned int i; |
451 unsigned int i; |
393 |
452 |
394 ec_slave_locate_string(slave, data[0], &slave->sii_group); |
453 slave->sii_group = ec_slave_sii_string(slave, data[0]); |
395 ec_slave_locate_string(slave, data[1], &slave->sii_image); |
454 slave->sii_image = ec_slave_sii_string(slave, data[1]); |
396 ec_slave_locate_string(slave, data[2], &slave->sii_order); |
455 slave->sii_order = ec_slave_sii_string(slave, data[2]); |
397 ec_slave_locate_string(slave, data[3], &slave->sii_name); |
456 slave->sii_name = ec_slave_sii_string(slave, data[3]); |
398 |
457 |
399 for (i = 0; i < 4; i++) |
458 for (i = 0; i < 4; i++) |
400 slave->sii_physical_layer[i] = |
459 slave->sii_physical_layer[i] = |
401 (data[4] & (0x03 << (i * 2))) >> (i * 2); |
460 (data[4] & (0x03 << (i * 2))) >> (i * 2); |
402 |
461 |
408 /** |
467 /** |
409 Fetches data from a SYNC MANAGER category. |
468 Fetches data from a SYNC MANAGER category. |
410 \return 0 in case of success, else < 0 |
469 \return 0 in case of success, else < 0 |
411 */ |
470 */ |
412 |
471 |
413 int ec_slave_fetch_sync(ec_slave_t *slave, /**< EtherCAT slave */ |
472 int ec_slave_fetch_sii_syncs( |
414 const uint8_t *data, /**< category data */ |
473 ec_slave_t *slave, /**< EtherCAT slave */ |
415 size_t word_count /**< number of words */ |
474 const uint8_t *data, /**< category data */ |
416 ) |
475 size_t word_count /**< number of words */ |
417 { |
476 ) |
418 unsigned int sync_count, i; |
477 { |
419 ec_sii_sync_t *sync; |
478 unsigned int i; |
420 |
479 ec_sync_t *sync; |
421 sync_count = word_count / 4; // sync manager struct is 4 words long |
480 |
422 |
481 // sync manager struct is 4 words long |
423 for (i = 0; i < sync_count; i++, data += 8) { |
482 slave->sii_sync_count = word_count / 4; |
424 if (!(sync = (ec_sii_sync_t *) |
483 |
425 kmalloc(sizeof(ec_sii_sync_t), GFP_ATOMIC))) { |
484 if (!(slave->sii_syncs = |
426 EC_ERR("Failed to allocate Sync-Manager memory.\n"); |
485 kmalloc(sizeof(ec_sync_t) * slave->sii_sync_count, |
427 return -1; |
486 GFP_KERNEL))) { |
428 } |
487 EC_ERR("Failed to allocate memory for sync managers.\n"); |
429 |
488 slave->sii_sync_count = 0; |
430 sync->index = i; |
489 return -1; |
|
490 } |
|
491 |
|
492 for (i = 0; i < slave->sii_sync_count; i++, data += 8) { |
|
493 sync = &slave->sii_syncs[i]; |
|
494 |
|
495 ec_sync_init(sync, slave, i); |
431 sync->physical_start_address = EC_READ_U16(data); |
496 sync->physical_start_address = EC_READ_U16(data); |
432 sync->length = EC_READ_U16(data + 2); |
497 sync->length = EC_READ_U16(data + 2); |
433 sync->control_register = EC_READ_U8 (data + 4); |
498 sync->control_register = EC_READ_U8 (data + 4); |
434 sync->enable = EC_READ_U8 (data + 6); |
499 sync->enable = EC_READ_U8 (data + 6); |
435 |
|
436 sync->est_length = 0; |
|
437 |
|
438 list_add_tail(&sync->list, &slave->sii_syncs); |
|
439 } |
500 } |
440 |
501 |
441 return 0; |
502 return 0; |
442 } |
503 } |
443 |
504 |
446 /** |
507 /** |
447 Fetches data from a [RT]XPDO category. |
508 Fetches data from a [RT]XPDO category. |
448 \return 0 in case of success, else < 0 |
509 \return 0 in case of success, else < 0 |
449 */ |
510 */ |
450 |
511 |
451 int ec_slave_fetch_pdo(ec_slave_t *slave, /**< EtherCAT slave */ |
512 int ec_slave_fetch_sii_pdos( |
452 const uint8_t *data, /**< category data */ |
513 ec_slave_t *slave, /**< EtherCAT slave */ |
453 size_t word_count, /**< number of words */ |
514 const uint8_t *data, /**< category data */ |
454 ec_sii_pdo_type_t pdo_type /**< PDO type */ |
515 size_t word_count, /**< number of words */ |
455 ) |
516 ec_pdo_type_t pdo_type /**< PDO type */ |
456 { |
517 ) |
457 ec_sii_pdo_t *pdo; |
518 { |
458 ec_sii_pdo_entry_t *entry; |
519 ec_pdo_t *pdo; |
|
520 ec_pdo_entry_t *entry; |
459 unsigned int entry_count, i; |
521 unsigned int entry_count, i; |
460 |
522 |
461 while (word_count >= 4) { |
523 while (word_count >= 4) { |
462 if (!(pdo = (ec_sii_pdo_t *) |
524 if (!(pdo = kmalloc(sizeof(ec_pdo_t), GFP_KERNEL))) { |
463 kmalloc(sizeof(ec_sii_pdo_t), GFP_ATOMIC))) { |
|
464 EC_ERR("Failed to allocate PDO memory.\n"); |
525 EC_ERR("Failed to allocate PDO memory.\n"); |
465 return -1; |
526 return -1; |
466 } |
527 } |
467 |
528 |
468 INIT_LIST_HEAD(&pdo->entries); |
529 ec_pdo_init(pdo); |
469 pdo->type = pdo_type; |
530 pdo->type = pdo_type; |
470 |
|
471 pdo->index = EC_READ_U16(data); |
531 pdo->index = EC_READ_U16(data); |
472 entry_count = EC_READ_U8(data + 2); |
532 entry_count = EC_READ_U8(data + 2); |
473 pdo->sync_index = EC_READ_U8(data + 3); |
533 pdo->sync_index = EC_READ_U8(data + 3); |
474 pdo->name = NULL; |
534 pdo->name = ec_slave_sii_string(slave, EC_READ_U8(data + 5)); |
475 ec_slave_locate_string(slave, EC_READ_U8(data + 5), &pdo->name); |
|
476 |
|
477 list_add_tail(&pdo->list, &slave->sii_pdos); |
535 list_add_tail(&pdo->list, &slave->sii_pdos); |
478 |
536 |
479 word_count -= 4; |
537 word_count -= 4; |
480 data += 8; |
538 data += 8; |
481 |
539 |
482 for (i = 0; i < entry_count; i++) { |
540 for (i = 0; i < entry_count; i++) { |
483 if (!(entry = (ec_sii_pdo_entry_t *) |
541 if (!(entry = kmalloc(sizeof(ec_pdo_entry_t), GFP_KERNEL))) { |
484 kmalloc(sizeof(ec_sii_pdo_entry_t), GFP_ATOMIC))) { |
|
485 EC_ERR("Failed to allocate PDO entry memory.\n"); |
542 EC_ERR("Failed to allocate PDO entry memory.\n"); |
486 return -1; |
543 return -1; |
487 } |
544 } |
488 |
545 |
489 entry->index = EC_READ_U16(data); |
546 entry->index = EC_READ_U16(data); |
490 entry->subindex = EC_READ_U8(data + 2); |
547 entry->subindex = EC_READ_U8(data + 2); |
491 entry->name = NULL; |
548 entry->name = ec_slave_sii_string(slave, EC_READ_U8(data + 3)); |
492 ec_slave_locate_string(slave, EC_READ_U8(data + 3), &entry->name); |
|
493 entry->bit_length = EC_READ_U8(data + 5); |
549 entry->bit_length = EC_READ_U8(data + 5); |
494 |
|
495 list_add_tail(&entry->list, &pdo->entries); |
550 list_add_tail(&entry->list, &pdo->entries); |
496 |
551 |
497 word_count -= 4; |
552 word_count -= 4; |
498 data += 8; |
553 data += 8; |
|
554 } |
|
555 |
|
556 // if sync manager index is positive, the PDO is mapped by default |
|
557 if (pdo->sync_index >= 0) { |
|
558 ec_pdo_t *mapped_pdo; |
|
559 |
|
560 if (pdo->sync_index >= slave->sii_sync_count) { |
|
561 EC_ERR("Invalid SM index %i for PDO 0x%04X in slave %u.", |
|
562 pdo->sync_index, pdo->index, slave->ring_position); |
|
563 return -1; |
|
564 } |
|
565 |
|
566 if (!(mapped_pdo = kmalloc(sizeof(ec_pdo_t), GFP_KERNEL))) { |
|
567 EC_ERR("Failed to allocate PDO memory.\n"); |
|
568 return -1; |
|
569 } |
|
570 |
|
571 if (ec_pdo_copy(mapped_pdo, pdo)) { |
|
572 EC_ERR("Failed to copy PDO.\n"); |
|
573 kfree(mapped_pdo); |
|
574 return -1; |
|
575 } |
|
576 |
|
577 list_add_tail(&mapped_pdo->list, |
|
578 &slave->sii_syncs[pdo->sync_index].pdos); |
499 } |
579 } |
500 } |
580 } |
501 |
581 |
502 return 0; |
582 return 0; |
503 } |
583 } |
508 Searches the string list for an index and allocates a new string. |
588 Searches the string list for an index and allocates a new string. |
509 \return 0 in case of success, else < 0 |
589 \return 0 in case of success, else < 0 |
510 \todo documentation |
590 \todo documentation |
511 */ |
591 */ |
512 |
592 |
513 int ec_slave_locate_string(ec_slave_t *slave, /**< EtherCAT slave */ |
593 char *ec_slave_sii_string( |
514 unsigned int index, /**< string index */ |
594 ec_slave_t *slave, /**< EtherCAT slave */ |
515 char **ptr /**< Address of the string pointer */ |
595 unsigned int index /**< string index */ |
516 ) |
596 ) |
517 { |
597 { |
518 ec_sii_string_t *string; |
598 if (!index--) |
519 char *err_string; |
599 return NULL; |
520 |
600 |
521 // Erst alten Speicher freigeben |
601 if (index >= slave->sii_string_count) { |
522 if (*ptr) { |
602 if (slave->master->debug_level) |
523 kfree(*ptr); |
603 EC_WARN("String %i not found in slave %i.\n", |
524 *ptr = NULL; |
604 index, slave->ring_position); |
525 } |
605 return NULL; |
526 |
606 } |
527 // Index 0 bedeutet "nicht belegt" |
607 |
528 if (!index) return 0; |
608 return slave->sii_strings[index]; |
529 |
609 } |
530 // EEPROM-String mit Index finden und kopieren |
610 |
531 list_for_each_entry(string, &slave->sii_strings, list) { |
611 /*****************************************************************************/ |
532 if (--index) continue; |
612 |
533 |
613 /** |
534 if (!(*ptr = (char *) kmalloc(string->size + 1, GFP_ATOMIC))) { |
614 * Prepares an FMMU configuration. |
535 EC_ERR("Unable to allocate string memory.\n"); |
615 * Configuration data for the FMMU is saved in the slave structure and is |
536 return -1; |
616 * written to the slave in ecrt_master_activate(). |
537 } |
617 * The FMMU configuration is done in a way, that the complete data range |
538 memcpy(*ptr, string->data, string->size + 1); |
618 * of the corresponding sync manager is covered. Seperate FMMUs are configured |
539 return 0; |
619 * for each domain. |
540 } |
620 * If the FMMU configuration is already prepared, the function returns with |
541 |
621 * success. |
542 if (slave->master->debug_level) |
622 * \return 0 in case of success, else < 0 |
543 EC_WARN("String %i not found in slave %i.\n", |
623 */ |
544 index, slave->ring_position); |
624 |
545 |
625 int ec_slave_prepare_fmmu( |
546 err_string = "(string not found)"; |
626 ec_slave_t *slave, /**< EtherCAT slave */ |
547 |
627 const ec_domain_t *domain, /**< domain */ |
548 if (!(*ptr = (char *) kmalloc(strlen(err_string) + 1, GFP_ATOMIC))) { |
628 const ec_sync_t *sync /**< sync manager */ |
549 EC_WARN("Unable to allocate string memory.\n"); |
629 ) |
550 return -1; |
|
551 } |
|
552 |
|
553 memcpy(*ptr, err_string, strlen(err_string) + 1); |
|
554 return 0; |
|
555 } |
|
556 |
|
557 /*****************************************************************************/ |
|
558 |
|
559 /** |
|
560 Prepares an FMMU configuration. |
|
561 Configuration data for the FMMU is saved in the slave structure and is |
|
562 written to the slave in ecrt_master_activate(). |
|
563 The FMMU configuration is done in a way, that the complete data range |
|
564 of the corresponding sync manager is covered. Seperate FMMUs are configured |
|
565 for each domain. |
|
566 If the FMMU configuration is already prepared, the function returns with |
|
567 success. |
|
568 \return 0 in case of success, else < 0 |
|
569 */ |
|
570 |
|
571 int ec_slave_prepare_fmmu(ec_slave_t *slave, /**< EtherCAT slave */ |
|
572 const ec_domain_t *domain, /**< domain */ |
|
573 const ec_sii_sync_t *sync /**< sync manager */ |
|
574 ) |
|
575 { |
630 { |
576 unsigned int i; |
631 unsigned int i; |
577 ec_fmmu_t *fmmu; |
632 ec_fmmu_t *fmmu; |
578 |
633 |
579 // FMMU configuration already prepared? |
634 // FMMU configuration already prepared? |
633 off += sprintf(buffer + off, "State: "); |
690 off += sprintf(buffer + off, "State: "); |
634 off += ec_state_string(slave->current_state, buffer + off); |
691 off += ec_state_string(slave->current_state, buffer + off); |
635 off += sprintf(buffer + off, " ("); |
692 off += sprintf(buffer + off, " ("); |
636 off += ec_state_string(slave->requested_state, buffer + off); |
693 off += ec_state_string(slave->requested_state, buffer + off); |
637 off += sprintf(buffer + off, ")\nFlags: %s, %s\n", |
694 off += sprintf(buffer + off, ")\nFlags: %s, %s\n", |
638 slave->online ? "online" : "OFFLINE", |
695 slave->online_state == EC_SLAVE_ONLINE ? "online" : "OFFLINE", |
639 slave->error_flag ? "ERROR" : "ok"); |
696 slave->error_flag ? "ERROR" : "ok"); |
640 off += sprintf(buffer + off, "Ring position: %i\n", |
697 off += sprintf(buffer + off, "Ring position: %i\n", |
641 slave->ring_position); |
698 slave->ring_position); |
642 off += sprintf(buffer + off, "Advanced position: %i:%i\n", |
|
643 slave->coupler_index, slave->coupler_subindex); |
|
644 off += sprintf(buffer + off, "Coupler: %s\n", |
|
645 ec_slave_is_coupler(slave) ? "yes" : "no"); |
|
646 off += sprintf(buffer + off, "Current consumption: %i mA\n\n", |
699 off += sprintf(buffer + off, "Current consumption: %i mA\n\n", |
647 slave->sii_current_on_ebus); |
700 slave->sii_current_on_ebus); |
648 |
701 |
649 off += sprintf(buffer + off, "Data link status:\n"); |
702 off += sprintf(buffer + off, "Data link status:\n"); |
650 for (i = 0; i < 4; i++) { |
703 for (i = 0; i < 4; i++) { |
723 if (slave->sii_image) |
776 if (slave->sii_image) |
724 off += sprintf(buffer + off, " Image: %s\n", slave->sii_image); |
777 off += sprintf(buffer + off, " Image: %s\n", slave->sii_image); |
725 if (slave->sii_order) |
778 if (slave->sii_order) |
726 off += sprintf(buffer + off, " Order number: %s\n", slave->sii_order); |
779 off += sprintf(buffer + off, " Order number: %s\n", slave->sii_order); |
727 |
780 |
728 if (!list_empty(&slave->sii_syncs)) |
781 if (slave->sii_sync_count) |
729 off += sprintf(buffer + off, "\nSync-Managers:\n"); |
782 off += sprintf(buffer + off, "\nSync managers / PDO mapping:\n"); |
730 |
783 |
731 list_for_each_entry(sync, &slave->sii_syncs, list) { |
784 for (i = 0; i < slave->sii_sync_count; i++) { |
732 off += sprintf(buffer + off, " %i: 0x%04X, length %i," |
785 sync = &slave->sii_syncs[i]; |
733 " control 0x%02X, %s\n", |
786 off += sprintf(buffer + off, |
734 sync->index, sync->physical_start_address, |
787 " SM%u: addr 0x%04X, size %i, control 0x%02X, %s\n", |
735 sync->length, sync->control_register, |
788 sync->index, sync->physical_start_address, |
736 sync->enable ? "enable" : "disable"); |
789 ec_sync_size(sync), sync->control_register, |
|
790 sync->enable ? "enable" : "disable"); |
|
791 |
|
792 if (list_empty(&sync->pdos)) |
|
793 off += sprintf(buffer + off, " No PDOs mapped.\n"); |
|
794 |
|
795 list_for_each_entry(pdo, &sync->pdos, list) { |
|
796 off += sprintf(buffer + off, " %s 0x%04X \"%s\"\n", |
|
797 pdo->type == EC_RX_PDO ? "RXPDO" : "TXPDO", |
|
798 pdo->index, pdo->name ? pdo->name : "???"); |
|
799 |
|
800 list_for_each_entry(pdo_entry, &pdo->entries, list) { |
|
801 off += sprintf(buffer + off, |
|
802 " 0x%04X:%X \"%s\", %i bit\n", |
|
803 pdo_entry->index, pdo_entry->subindex, |
|
804 pdo_entry->name ? pdo_entry->name : "???", |
|
805 pdo_entry->bit_length); |
|
806 } |
|
807 } |
737 } |
808 } |
738 |
809 |
739 if (!list_empty(&slave->sii_pdos)) |
810 if (!list_empty(&slave->sii_pdos)) |
740 off += sprintf(buffer + off, "\nPDOs:\n"); |
811 off += sprintf(buffer + off, "\nAvailable PDOs:\n"); |
741 |
812 |
742 list_for_each_entry(pdo, &slave->sii_pdos, list) { |
813 list_for_each_entry(pdo, &slave->sii_pdos, list) { |
743 off += sprintf(buffer + off, |
814 off += sprintf(buffer + off, " %s 0x%04X \"%s\"", |
744 " %s \"%s\" (0x%04X), Sync-Manager %i\n", |
|
745 pdo->type == EC_RX_PDO ? "RXPDO" : "TXPDO", |
815 pdo->type == EC_RX_PDO ? "RXPDO" : "TXPDO", |
746 pdo->name ? pdo->name : "???", |
816 pdo->index, pdo->name ? pdo->name : "???"); |
747 pdo->index, pdo->sync_index); |
817 if (pdo->sync_index >= 0) |
|
818 off += sprintf(buffer + off, ", default mapping: SM%u.\n", |
|
819 pdo->sync_index); |
|
820 else |
|
821 off += sprintf(buffer + off, ", no default mapping.\n"); |
748 |
822 |
749 list_for_each_entry(pdo_entry, &pdo->entries, list) { |
823 list_for_each_entry(pdo_entry, &pdo->entries, list) { |
750 off += sprintf(buffer + off, " \"%s\" 0x%04X:%X, %i bit\n", |
824 off += sprintf(buffer + off, " 0x%04X:%X \"%s\", %i bit\n", |
|
825 pdo_entry->index, pdo_entry->subindex, |
751 pdo_entry->name ? pdo_entry->name : "???", |
826 pdo_entry->name ? pdo_entry->name : "???", |
752 pdo_entry->index, pdo_entry->subindex, |
|
753 pdo_entry->bit_length); |
827 pdo_entry->bit_length); |
754 } |
828 } |
755 } |
829 } |
756 |
830 |
757 if (!list_empty(&slave->sdo_confs)) |
831 if (!list_empty(&slave->sdo_confs)) |
774 } |
848 } |
775 |
849 |
776 /*****************************************************************************/ |
850 /*****************************************************************************/ |
777 |
851 |
778 /** |
852 /** |
779 Schedules an EEPROM write operation. |
853 * Schedules an EEPROM write request. |
780 \return 0 in case of success, else < 0 |
854 * \return 0 case of success, otherwise error code. |
781 */ |
855 */ |
|
856 |
|
857 int ec_slave_schedule_eeprom_writing(ec_eeprom_write_request_t *request) |
|
858 { |
|
859 ec_master_t *master = request->slave->master; |
|
860 |
|
861 request->state = EC_REQUEST_QUEUED; |
|
862 |
|
863 // schedule EEPROM write request. |
|
864 down(&master->eeprom_sem); |
|
865 list_add_tail(&request->list, &master->eeprom_requests); |
|
866 up(&master->eeprom_sem); |
|
867 |
|
868 // wait for processing through FSM |
|
869 if (wait_event_interruptible(master->eeprom_queue, |
|
870 request->state != EC_REQUEST_QUEUED)) { |
|
871 // interrupted by signal |
|
872 down(&master->eeprom_sem); |
|
873 if (request->state == EC_REQUEST_QUEUED) { |
|
874 list_del(&request->list); |
|
875 up(&master->eeprom_sem); |
|
876 return -EINTR; |
|
877 } |
|
878 // request already processing: interrupt not possible. |
|
879 up(&master->eeprom_sem); |
|
880 } |
|
881 |
|
882 // wait until master FSM has finished processing |
|
883 wait_event(master->eeprom_queue, |
|
884 request->state != EC_REQUEST_IN_PROGRESS); |
|
885 |
|
886 return request->state == EC_REQUEST_COMPLETE ? 0 : -EIO; |
|
887 } |
|
888 |
|
889 /*****************************************************************************/ |
|
890 |
|
891 /** |
|
892 * Writes complete EEPROM contents to a slave. |
|
893 * \return data size written in case of success, otherwise error code. |
|
894 */ |
782 |
895 |
783 ssize_t ec_slave_write_eeprom(ec_slave_t *slave, /**< EtherCAT slave */ |
896 ssize_t ec_slave_write_eeprom(ec_slave_t *slave, /**< EtherCAT slave */ |
784 const uint8_t *data, /**< new EEPROM data */ |
897 const uint8_t *data, /**< new EEPROM data */ |
785 size_t size /**< size of data in bytes */ |
898 size_t size /**< size of data in bytes */ |
786 ) |
899 ) |
787 { |
900 { |
788 uint16_t word_size, cat_type, cat_size; |
901 ec_eeprom_write_request_t request; |
789 const uint16_t *data_words, *next_header; |
902 const uint16_t *cat_header; |
790 uint16_t *new_data; |
903 uint16_t cat_type, cat_size; |
791 |
904 int ret; |
792 if (!slave->master->eeprom_write_enable) { |
905 |
793 EC_ERR("Writing EEPROMs not allowed! Enable via" |
906 if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME |
794 " eeprom_write_enable SysFS entry.\n"); |
|
795 return -1; |
|
796 } |
|
797 |
|
798 if (slave->master->mode != EC_MASTER_MODE_IDLE) { |
|
799 EC_ERR("Writing EEPROMs only allowed in idle mode!\n"); |
907 EC_ERR("Writing EEPROMs only allowed in idle mode!\n"); |
800 return -1; |
908 return -EBUSY; |
801 } |
909 } |
802 |
|
803 if (slave->new_eeprom_data) { |
|
804 EC_ERR("Slave %i already has a pending EEPROM write operation!\n", |
|
805 slave->ring_position); |
|
806 return -1; |
|
807 } |
|
808 |
|
809 // coarse check of the data |
|
810 |
910 |
811 if (size % 2) { |
911 if (size % 2) { |
812 EC_ERR("EEPROM size is odd! Dropping.\n"); |
912 EC_ERR("EEPROM data size is odd! Dropping.\n"); |
813 return -1; |
913 return -EINVAL; |
814 } |
914 } |
815 |
915 |
816 data_words = (const uint16_t *) data; |
916 // init EEPROM write request |
817 word_size = size / 2; |
917 INIT_LIST_HEAD(&request.list); |
818 |
918 request.slave = slave; |
819 if (word_size < 0x0041) { |
919 request.words = (const uint16_t *) data; |
|
920 request.offset = 0; |
|
921 request.size = size / 2; |
|
922 |
|
923 if (request.size < 0x0041) { |
820 EC_ERR("EEPROM data too short! Dropping.\n"); |
924 EC_ERR("EEPROM data too short! Dropping.\n"); |
821 return -1; |
925 return -EINVAL; |
822 } |
926 } |
823 |
927 |
824 next_header = data_words + 0x0040; |
928 cat_header = request.words + EC_FIRST_EEPROM_CATEGORY_OFFSET; |
825 cat_type = EC_READ_U16(next_header); |
929 cat_type = EC_READ_U16(cat_header); |
826 while (cat_type != 0xFFFF) { |
930 while (cat_type != 0xFFFF) { // cycle through categories |
827 cat_type = EC_READ_U16(next_header); |
931 if (cat_header + 1 > request.words + request.size) { |
828 cat_size = EC_READ_U16(next_header + 1); |
932 EC_ERR("EEPROM data corrupted! Dropping.\n"); |
829 if ((next_header + cat_size + 2) - data_words >= word_size) { |
933 return -EINVAL; |
830 EC_ERR("EEPROM data seems to be corrupted! Dropping.\n"); |
934 } |
831 return -1; |
935 cat_size = EC_READ_U16(cat_header + 1); |
832 } |
936 if (cat_header + cat_size + 2 > request.words + request.size) { |
833 next_header += cat_size + 2; |
937 EC_ERR("EEPROM data corrupted! Dropping.\n"); |
834 cat_type = EC_READ_U16(next_header); |
938 return -EINVAL; |
835 } |
939 } |
836 |
940 cat_header += cat_size + 2; |
837 // data ok! |
941 cat_type = EC_READ_U16(cat_header); |
838 |
942 } |
839 if (!(new_data = (uint16_t *) kmalloc(word_size * 2, GFP_KERNEL))) { |
943 |
840 EC_ERR("Unable to allocate memory for new EEPROM data!\n"); |
944 // EEPROM data ok. schedule writing. |
841 return -1; |
945 if ((ret = ec_slave_schedule_eeprom_writing(&request))) |
842 } |
946 return ret; // error code |
843 memcpy(new_data, data, size); |
947 |
844 |
948 return size; // success |
845 slave->new_eeprom_size = word_size; |
949 } |
846 slave->new_eeprom_data = new_data; |
950 |
847 |
951 /*****************************************************************************/ |
848 EC_INFO("EEPROM writing scheduled for slave %i, %i words.\n", |
952 |
849 slave->ring_position, word_size); |
953 /** |
850 return 0; |
954 * Writes the Secondary slave address (alias) to the slave's EEPROM. |
851 } |
955 * \return data size written in case of success, otherwise error code. |
|
956 */ |
|
957 |
|
958 ssize_t ec_slave_write_alias(ec_slave_t *slave, /**< EtherCAT slave */ |
|
959 const uint8_t *data, /**< alias string */ |
|
960 size_t size /**< size of data in bytes */ |
|
961 ) |
|
962 { |
|
963 ec_eeprom_write_request_t request; |
|
964 char *remainder; |
|
965 uint16_t alias, word; |
|
966 int ret; |
|
967 |
|
968 if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME |
|
969 EC_ERR("Writing EEPROMs only allowed in idle mode!\n"); |
|
970 return -EBUSY; |
|
971 } |
|
972 |
|
973 alias = simple_strtoul(data, &remainder, 0); |
|
974 if (remainder == (char *) data || (*remainder && *remainder != '\n')) { |
|
975 EC_ERR("Invalid alias value! Dropping.\n"); |
|
976 return -EINVAL; |
|
977 } |
|
978 |
|
979 // correct endianess |
|
980 EC_WRITE_U16(&word, alias); |
|
981 |
|
982 // init EEPROM write request |
|
983 INIT_LIST_HEAD(&request.list); |
|
984 request.slave = slave; |
|
985 request.words = &word; |
|
986 request.offset = 0x0004; |
|
987 request.size = 1; |
|
988 |
|
989 if ((ret = ec_slave_schedule_eeprom_writing(&request))) |
|
990 return ret; // error code |
|
991 |
|
992 slave->sii_alias = alias; // FIXME: do this in state machine |
|
993 |
|
994 return size; // success |
|
995 } |
|
996 |
852 |
997 |
853 /*****************************************************************************/ |
998 /*****************************************************************************/ |
854 |
999 |
855 /** |
1000 /** |
856 Formats attribute data for SysFS read access. |
1001 Formats attribute data for SysFS read access. |
932 EC_INFO("Accepted new state %s for slave %i.\n", |
1080 EC_INFO("Accepted new state %s for slave %i.\n", |
933 state, slave->ring_position); |
1081 state, slave->ring_position); |
934 return size; |
1082 return size; |
935 } |
1083 } |
936 else if (attr == &attr_eeprom) { |
1084 else if (attr == &attr_eeprom) { |
937 if (!ec_slave_write_eeprom(slave, buffer, size)) |
1085 return ec_slave_write_eeprom(slave, buffer, size); |
938 return size; |
1086 } |
939 } |
1087 else if (attr == &attr_alias) { |
940 |
1088 return ec_slave_write_alias(slave, buffer, size); |
941 return -EINVAL; |
1089 } |
942 } |
1090 |
943 |
1091 return -EIO; |
944 /*****************************************************************************/ |
1092 } |
945 |
1093 |
946 /** |
1094 /*****************************************************************************/ |
947 Calculates the size of a sync manager by evaluating PDO sizes. |
1095 |
948 \return sync manager size |
1096 /** |
949 */ |
1097 */ |
950 |
1098 |
951 uint16_t ec_slave_calc_sync_size(const ec_slave_t *slave, |
1099 ec_sync_t *ec_slave_get_pdo_sync( |
952 /**< EtherCAT slave */ |
1100 ec_slave_t *slave, /**< EtherCAT slave */ |
953 const ec_sii_sync_t *sync |
1101 ec_direction_t dir /**< input or output */ |
954 /**< sync manager */ |
|
955 ) |
|
956 { |
|
957 ec_sii_pdo_t *pdo; |
|
958 ec_sii_pdo_entry_t *pdo_entry; |
|
959 unsigned int bit_size, byte_size; |
|
960 |
|
961 if (sync->length) return sync->length; |
|
962 if (sync->est_length) return sync->est_length; |
|
963 |
|
964 bit_size = 0; |
|
965 list_for_each_entry(pdo, &slave->sii_pdos, list) { |
|
966 if (pdo->sync_index != sync->index) continue; |
|
967 |
|
968 list_for_each_entry(pdo_entry, &pdo->entries, list) { |
|
969 bit_size += pdo_entry->bit_length; |
|
970 } |
|
971 } |
|
972 |
|
973 if (bit_size % 8) // round up to full bytes |
|
974 byte_size = bit_size / 8 + 1; |
|
975 else |
|
976 byte_size = bit_size / 8; |
|
977 |
|
978 return byte_size; |
|
979 } |
|
980 |
|
981 /*****************************************************************************/ |
|
982 |
|
983 /** |
|
984 Initializes a sync manager configuration page with EEPROM data. |
|
985 The referenced memory (\a data) must be at least EC_SYNC_SIZE bytes. |
|
986 */ |
|
987 |
|
988 void ec_slave_sync_config(const ec_slave_t *slave, /**< EtherCAT slave */ |
|
989 const ec_sii_sync_t *sync, /**< sync manager */ |
|
990 uint8_t *data /**> configuration memory */ |
|
991 ) |
1102 ) |
992 { |
1103 { |
993 size_t sync_size; |
1104 unsigned int sync_index; |
994 |
1105 |
995 sync_size = ec_slave_calc_sync_size(slave, sync); |
1106 if (dir != EC_DIR_INPUT && dir != EC_DIR_OUTPUT) { |
996 |
1107 EC_ERR("Invalid direction!\n"); |
997 if (slave->master->debug_level) { |
1108 return NULL; |
998 EC_DBG("Slave %3i, SM %i: Addr 0x%04X, Size %3i, Ctrl 0x%02X, En %i\n", |
1109 } |
999 slave->ring_position, sync->index, sync->physical_start_address, |
1110 |
1000 sync_size, sync->control_register, sync->enable); |
1111 sync_index = (unsigned int) dir; |
1001 } |
1112 if (slave->sii_mailbox_protocols) sync_index += 2; |
1002 |
1113 |
1003 EC_WRITE_U16(data, sync->physical_start_address); |
1114 if (sync_index >= slave->sii_sync_count) |
1004 EC_WRITE_U16(data + 2, sync_size); |
1115 return NULL; |
1005 EC_WRITE_U8 (data + 4, sync->control_register); |
1116 |
1006 EC_WRITE_U8 (data + 5, 0x00); // status byte (read only) |
1117 return &slave->sii_syncs[sync_index]; |
1007 EC_WRITE_U16(data + 6, sync->enable ? 0x0001 : 0x0000); // enable |
|
1008 } |
|
1009 |
|
1010 /*****************************************************************************/ |
|
1011 |
|
1012 /** |
|
1013 Initializes an FMMU configuration page. |
|
1014 The referenced memory (\a data) must be at least EC_FMMU_SIZE bytes. |
|
1015 */ |
|
1016 |
|
1017 void ec_slave_fmmu_config(const ec_slave_t *slave, /**< EtherCAT slave */ |
|
1018 const ec_fmmu_t *fmmu, /**< FMMU */ |
|
1019 uint8_t *data /**> configuration memory */ |
|
1020 ) |
|
1021 { |
|
1022 size_t sync_size; |
|
1023 |
|
1024 sync_size = ec_slave_calc_sync_size(slave, fmmu->sync); |
|
1025 |
|
1026 if (slave->master->debug_level) { |
|
1027 EC_DBG("Slave %3i, FMMU %2i:" |
|
1028 " LogAddr 0x%08X, Size %3i, PhysAddr 0x%04X, Dir %s\n", |
|
1029 slave->ring_position, fmmu->index, fmmu->logical_start_address, |
|
1030 sync_size, fmmu->sync->physical_start_address, |
|
1031 ((fmmu->sync->control_register & 0x04) ? "out" : "in")); |
|
1032 } |
|
1033 |
|
1034 EC_WRITE_U32(data, fmmu->logical_start_address); |
|
1035 EC_WRITE_U16(data + 4, sync_size); // size of fmmu |
|
1036 EC_WRITE_U8 (data + 6, 0x00); // logical start bit |
|
1037 EC_WRITE_U8 (data + 7, 0x07); // logical end bit |
|
1038 EC_WRITE_U16(data + 8, fmmu->sync->physical_start_address); |
|
1039 EC_WRITE_U8 (data + 10, 0x00); // physical start bit |
|
1040 EC_WRITE_U8 (data + 11, ((fmmu->sync->control_register & 0x04) |
|
1041 ? 0x02 : 0x01)); |
|
1042 EC_WRITE_U16(data + 12, 0x0001); // enable |
|
1043 EC_WRITE_U16(data + 14, 0x0000); // reserved |
|
1044 } |
|
1045 |
|
1046 /*****************************************************************************/ |
|
1047 |
|
1048 /** |
|
1049 \return non-zero if slave is a bus coupler |
|
1050 */ |
|
1051 |
|
1052 int ec_slave_is_coupler(const ec_slave_t *slave /**< EtherCAT slave */) |
|
1053 { |
|
1054 // TODO: Better bus coupler criterion |
|
1055 return slave->sii_vendor_id == 0x00000002 |
|
1056 && slave->sii_product_code == 0x044C2C52; |
|
1057 } |
|
1058 |
|
1059 /*****************************************************************************/ |
|
1060 |
|
1061 /** |
|
1062 \return non-zero if slave is a bus coupler |
|
1063 */ |
|
1064 |
|
1065 int ec_slave_has_subbus(const ec_slave_t *slave /**< EtherCAT slave */) |
|
1066 { |
|
1067 return slave->sii_vendor_id == 0x00000002 |
|
1068 && slave->sii_product_code == 0x04602c22; |
|
1069 } |
1118 } |
1070 |
1119 |
1071 /*****************************************************************************/ |
1120 /*****************************************************************************/ |
1072 |
1121 |
1073 /** |
1122 /** |
1213 return ec_slave_conf_sdo(slave, sdo_index, sdo_subindex, data, 4); |
1263 return ec_slave_conf_sdo(slave, sdo_index, sdo_subindex, data, 4); |
1214 } |
1264 } |
1215 |
1265 |
1216 /*****************************************************************************/ |
1266 /*****************************************************************************/ |
1217 |
1267 |
1218 /** |
1268 void ecrt_slave_pdo_mapping_clear( |
1219 \return 0 in case of success, else < 0 |
1269 ec_slave_t *slave, /**< EtherCAT slave */ |
1220 \ingroup RealtimeInterface |
1270 ec_direction_t dir /**< output/input */ |
1221 */ |
1271 ) |
1222 |
1272 { |
1223 int ecrt_slave_pdo_size(ec_slave_t *slave, /**< EtherCAT slave */ |
1273 ec_sync_t *sync; |
1224 uint16_t pdo_index, /**< PDO index */ |
1274 |
1225 uint8_t pdo_subindex, /**< PDO subindex */ |
1275 if (!(slave->sii_mailbox_protocols & EC_MBOX_COE)) { |
1226 size_t size /**< new PDO size */ |
1276 EC_ERR("Slave %i does not support CoE!\n", slave->ring_position); |
1227 ) |
1277 return; |
1228 { |
1278 } |
1229 EC_WARN("ecrt_slave_pdo_size() currently not available.\n"); |
1279 |
1230 return -1; |
1280 if (!(sync = ec_slave_get_pdo_sync(slave, dir))) |
1231 |
1281 return; |
1232 #if 0 |
1282 |
1233 unsigned int i, j, field_counter; |
1283 ec_sync_clear_pdos(sync); |
1234 const ec_sii_sync_t *sync; |
1284 } |
1235 const ec_pdo_t *pdo; |
1285 |
1236 ec_varsize_t *var; |
1286 /*****************************************************************************/ |
1237 |
1287 |
1238 if (!slave->type) { |
1288 int ecrt_slave_pdo_mapping_add( |
1239 EC_ERR("Slave %i has no type information!\n", slave->ring_position); |
1289 ec_slave_t *slave, /**< EtherCAT slave */ |
|
1290 ec_direction_t dir, /**< input/output */ |
|
1291 uint16_t pdo_index /**< Index of PDO mapping list */) |
|
1292 { |
|
1293 ec_pdo_t *pdo; |
|
1294 ec_sync_t *sync; |
|
1295 unsigned int not_found = 1; |
|
1296 |
|
1297 if (!(slave->sii_mailbox_protocols & EC_MBOX_COE)) { |
|
1298 EC_ERR("Slave %u does not support CoE!\n", slave->ring_position); |
1240 return -1; |
1299 return -1; |
1241 } |
1300 } |
1242 |
1301 |
1243 field_counter = 0; |
1302 // does the slave provide the PDO list? |
1244 for (i = 0; (sync = slave->type->sync_managers[i]); i++) { |
1303 list_for_each_entry(pdo, &slave->sii_pdos, list) { |
1245 for (j = 0; (field = sync->fields[j]); j++) { |
1304 if (pdo->index == pdo_index) { |
1246 if (!strcmp(field->name, field_name)) { |
1305 not_found = 0; |
1247 if (field_counter++ == field_index) { |
1306 break; |
1248 // is the size of this field variable? |
1307 } |
1249 if (field->size) { |
1308 } |
1250 EC_ERR("Field \"%s\"[%i] of slave %i has no variable" |
1309 |
1251 " size!\n", field->name, field_index, |
1310 if (not_found) { |
1252 slave->ring_position); |
1311 EC_ERR("Slave %u does not provide PDO 0x%04X!\n", |
1253 return -1; |
1312 slave->ring_position, pdo_index); |
1254 } |
1313 return -1; |
1255 // does a size specification already exist? |
1314 } |
1256 list_for_each_entry(var, &slave->varsize_fields, list) { |
1315 |
1257 if (var->field == field) { |
1316 // check direction |
1258 EC_WARN("Resizing field \"%s\"[%i] of slave %i.\n", |
1317 if ((pdo->type == EC_TX_PDO && dir == EC_DIR_OUTPUT) || |
1259 field->name, field_index, |
1318 (pdo->type == EC_RX_PDO && dir == EC_DIR_INPUT)) { |
1260 slave->ring_position); |
1319 EC_ERR("Invalid direction for PDO 0x%04X.\n", pdo_index); |
1261 var->size = size; |
1320 return -1; |
1262 return 0; |
1321 } |
1263 } |
1322 |
1264 } |
1323 |
1265 // create a new size specification... |
1324 if (!(sync = ec_slave_get_pdo_sync(slave, dir))) { |
1266 if (!(var = kmalloc(sizeof(ec_varsize_t), GFP_KERNEL))) { |
1325 EC_ERR("Failed to obtain sync manager for PDO mapping of slave %u!\n", |
1267 EC_ERR("Failed to allocate memory for varsize_t!\n"); |
1326 slave->ring_position); |
1268 return -1; |
1327 return -1; |
1269 } |
1328 } |
1270 var->field = field; |
1329 |
1271 var->size = size; |
1330 return ec_sync_add_pdo(sync, pdo); |
1272 list_add_tail(&var->list, &slave->varsize_fields); |
1331 } |
1273 return 0; |
1332 |
1274 } |
1333 /*****************************************************************************/ |
1275 } |
1334 |
1276 } |
1335 int ecrt_slave_pdo_mapping(ec_slave_t *slave, /**< EtherCAT slave */ |
1277 } |
1336 ec_direction_t dir, /**< input/output */ |
1278 |
1337 unsigned int num_args, /**< Number of following arguments */ |
1279 EC_ERR("Slave %i (\"%s %s\") has no field \"%s\"[%i]!\n", |
1338 ... /**< PDO indices to map */ |
1280 slave->ring_position, slave->type->vendor_name, |
1339 ) |
1281 slave->type->product_name, field_name, field_index); |
1340 { |
1282 return -1; |
1341 va_list ap; |
1283 #endif |
1342 |
1284 } |
1343 ecrt_slave_pdo_mapping_clear(slave, dir); |
|
1344 |
|
1345 va_start(ap, num_args); |
|
1346 |
|
1347 for (; num_args; num_args--) { |
|
1348 if (ecrt_slave_pdo_mapping_add( |
|
1349 slave, dir, (uint16_t) va_arg(ap, int))) { |
|
1350 return -1; |
|
1351 } |
|
1352 } |
|
1353 |
|
1354 va_end(ap); |
|
1355 return 0; |
|
1356 } |
|
1357 |
1285 |
1358 |
1286 /*****************************************************************************/ |
1359 /*****************************************************************************/ |
1287 |
1360 |
1288 /** \cond */ |
1361 /** \cond */ |
1289 |
1362 |
1290 EXPORT_SYMBOL(ecrt_slave_conf_sdo8); |
1363 EXPORT_SYMBOL(ecrt_slave_conf_sdo8); |
1291 EXPORT_SYMBOL(ecrt_slave_conf_sdo16); |
1364 EXPORT_SYMBOL(ecrt_slave_conf_sdo16); |
1292 EXPORT_SYMBOL(ecrt_slave_conf_sdo32); |
1365 EXPORT_SYMBOL(ecrt_slave_conf_sdo32); |
1293 EXPORT_SYMBOL(ecrt_slave_pdo_size); |
1366 EXPORT_SYMBOL(ecrt_slave_pdo_mapping_clear); |
|
1367 EXPORT_SYMBOL(ecrt_slave_pdo_mapping_add); |
|
1368 EXPORT_SYMBOL(ecrt_slave_pdo_mapping); |
1294 |
1369 |
1295 /** \endcond */ |
1370 /** \endcond */ |
1296 |
1371 |
1297 /*****************************************************************************/ |
1372 /*****************************************************************************/ |