342 slave->dl_link[i] = dl_status & (1 << (4 + i)) ? 1 : 0; |
342 slave->dl_link[i] = dl_status & (1 << (4 + i)) ? 1 : 0; |
343 slave->dl_loop[i] = dl_status & (1 << (8 + i * 2)) ? 1 : 0; |
343 slave->dl_loop[i] = dl_status & (1 << (8 + i * 2)) ? 1 : 0; |
344 slave->dl_signal[i] = dl_status & (1 << (9 + i * 2)) ? 1 : 0; |
344 slave->dl_signal[i] = dl_status & (1 << (9 + i * 2)) ? 1 : 0; |
345 } |
345 } |
346 |
346 |
347 // Start fetching EEPROM size |
347 // Start fetching SII size |
348 |
348 |
349 fsm->sii_offset = EC_FIRST_EEPROM_CATEGORY_OFFSET; // first category header |
349 fsm->sii_offset = EC_FIRST_SII_CATEGORY_OFFSET; // first category header |
350 ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset, |
350 ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset, |
351 EC_FSM_SII_USE_CONFIGURED_ADDRESS); |
351 EC_FSM_SII_USE_CONFIGURED_ADDRESS); |
352 fsm->state = ec_fsm_slave_scan_state_eeprom_size; |
352 fsm->state = ec_fsm_slave_scan_state_sii_size; |
353 fsm->state(fsm); // execute state immediately |
353 fsm->state(fsm); // execute state immediately |
354 } |
354 } |
355 |
355 |
356 /*****************************************************************************/ |
356 /*****************************************************************************/ |
357 |
357 |
358 /** |
358 /** |
359 Slave scan state: EEPROM SIZE. |
359 Slave scan state: SII SIZE. |
360 */ |
360 */ |
361 |
361 |
362 void ec_fsm_slave_scan_state_eeprom_size(ec_fsm_slave_scan_t *fsm /**< slave state machine */) |
362 void ec_fsm_slave_scan_state_sii_size(ec_fsm_slave_scan_t *fsm /**< slave state machine */) |
363 { |
363 { |
364 ec_slave_t *slave = fsm->slave; |
364 ec_slave_t *slave = fsm->slave; |
365 uint16_t cat_type, cat_size; |
365 uint16_t cat_type, cat_size; |
366 |
366 |
367 if (ec_fsm_sii_exec(&fsm->fsm_sii)) return; |
367 if (ec_fsm_sii_exec(&fsm->fsm_sii)) return; |
368 |
368 |
369 if (!ec_fsm_sii_success(&fsm->fsm_sii)) { |
369 if (!ec_fsm_sii_success(&fsm->fsm_sii)) { |
370 fsm->slave->error_flag = 1; |
370 fsm->slave->error_flag = 1; |
371 fsm->state = ec_fsm_slave_scan_state_error; |
371 fsm->state = ec_fsm_slave_scan_state_error; |
372 EC_ERR("Failed to read EEPROM size of slave %i.\n", |
372 EC_ERR("Failed to read SII size of slave %i.\n", |
373 slave->ring_position); |
373 slave->ring_position); |
374 return; |
374 return; |
375 } |
375 } |
376 |
376 |
377 cat_type = EC_READ_U16(fsm->fsm_sii.value); |
377 cat_type = EC_READ_U16(fsm->fsm_sii.value); |
378 cat_size = EC_READ_U16(fsm->fsm_sii.value + 2); |
378 cat_size = EC_READ_U16(fsm->fsm_sii.value + 2); |
379 |
379 |
380 if (cat_type != 0xFFFF) { // not the last category |
380 if (cat_type != 0xFFFF) { // not the last category |
381 off_t next_offset = 2UL + fsm->sii_offset + cat_size; |
381 off_t next_offset = 2UL + fsm->sii_offset + cat_size; |
382 if (next_offset >= EC_MAX_EEPROM_SIZE) { |
382 if (next_offset >= EC_MAX_SII_SIZE) { |
383 EC_WARN("EEPROM size of slave %i exceeds" |
383 EC_WARN("SII size of slave %i exceeds" |
384 " %u words (0xffff limiter missing?).\n", |
384 " %u words (0xffff limiter missing?).\n", |
385 slave->ring_position, EC_MAX_EEPROM_SIZE); |
385 slave->ring_position, EC_MAX_SII_SIZE); |
386 // cut off category data... |
386 // cut off category data... |
387 slave->eeprom_size = EC_FIRST_EEPROM_CATEGORY_OFFSET * 2; |
387 slave->sii_size = EC_FIRST_SII_CATEGORY_OFFSET * 2; |
388 goto alloc_eeprom; |
388 goto alloc_sii; |
389 } |
389 } |
390 fsm->sii_offset = next_offset; |
390 fsm->sii_offset = next_offset; |
391 ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset, |
391 ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset, |
392 EC_FSM_SII_USE_CONFIGURED_ADDRESS); |
392 EC_FSM_SII_USE_CONFIGURED_ADDRESS); |
393 ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately |
393 ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately |
394 return; |
394 return; |
395 } |
395 } |
396 |
396 |
397 slave->eeprom_size = (fsm->sii_offset + 1) * 2; |
397 slave->sii_size = (fsm->sii_offset + 1) * 2; |
398 |
398 |
399 alloc_eeprom: |
399 alloc_sii: |
400 if (slave->eeprom_data) { |
400 if (slave->sii_data) { |
401 EC_WARN("Freeing old EEPROM data on slave %i...\n", |
401 EC_WARN("Freeing old SII data on slave %i...\n", |
402 slave->ring_position); |
402 slave->ring_position); |
403 kfree(slave->eeprom_data); |
403 kfree(slave->sii_data); |
404 } |
404 } |
405 |
405 |
406 if (!(slave->eeprom_data = |
406 if (!(slave->sii_data = |
407 (uint8_t *) kmalloc(slave->eeprom_size, GFP_ATOMIC))) { |
407 (uint8_t *) kmalloc(slave->sii_size, GFP_ATOMIC))) { |
408 EC_ERR("Failed to allocate %u bytes of EEPROM data for slave %u.\n", |
408 EC_ERR("Failed to allocate %u bytes of SII data for slave %u.\n", |
409 slave->eeprom_size, slave->ring_position); |
409 slave->sii_size, slave->ring_position); |
410 slave->eeprom_size = 0; |
410 slave->sii_size = 0; |
411 slave->error_flag = 1; |
411 slave->error_flag = 1; |
412 fsm->state = ec_fsm_slave_scan_state_error; |
412 fsm->state = ec_fsm_slave_scan_state_error; |
413 return; |
413 return; |
414 } |
414 } |
415 |
415 |
416 // Start fetching EEPROM contents |
416 // Start fetching SII contents |
417 |
417 |
418 fsm->state = ec_fsm_slave_scan_state_eeprom_data; |
418 fsm->state = ec_fsm_slave_scan_state_sii_data; |
419 fsm->sii_offset = 0x0000; |
419 fsm->sii_offset = 0x0000; |
420 ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset, |
420 ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset, |
421 EC_FSM_SII_USE_CONFIGURED_ADDRESS); |
421 EC_FSM_SII_USE_CONFIGURED_ADDRESS); |
422 ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately |
422 ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately |
423 } |
423 } |
424 |
424 |
425 /*****************************************************************************/ |
425 /*****************************************************************************/ |
426 |
426 |
427 /** |
427 /** |
428 Slave scan state: EEPROM DATA. |
428 Slave scan state: SII DATA. |
429 */ |
429 */ |
430 |
430 |
431 void ec_fsm_slave_scan_state_eeprom_data(ec_fsm_slave_scan_t *fsm /**< slave state machine */) |
431 void ec_fsm_slave_scan_state_sii_data(ec_fsm_slave_scan_t *fsm /**< slave state machine */) |
432 { |
432 { |
433 ec_slave_t *slave = fsm->slave; |
433 ec_slave_t *slave = fsm->slave; |
434 uint16_t *cat_word, cat_type, cat_size, eeprom_word_size = slave->eeprom_size / 2; |
434 uint16_t *cat_word, cat_type, cat_size, sii_word_size = slave->sii_size / 2; |
435 |
435 |
436 if (ec_fsm_sii_exec(&fsm->fsm_sii)) return; |
436 if (ec_fsm_sii_exec(&fsm->fsm_sii)) return; |
437 |
437 |
438 if (!ec_fsm_sii_success(&fsm->fsm_sii)) { |
438 if (!ec_fsm_sii_success(&fsm->fsm_sii)) { |
439 fsm->slave->error_flag = 1; |
439 fsm->slave->error_flag = 1; |
440 fsm->state = ec_fsm_slave_scan_state_error; |
440 fsm->state = ec_fsm_slave_scan_state_error; |
441 EC_ERR("Failed to fetch EEPROM contents of slave %i.\n", |
441 EC_ERR("Failed to fetch SII contents of slave %i.\n", |
442 slave->ring_position); |
442 slave->ring_position); |
443 return; |
443 return; |
444 } |
444 } |
445 |
445 |
446 // 2 words fetched |
446 // 2 words fetched |
447 |
447 |
448 if (fsm->sii_offset + 2 <= eeprom_word_size) { // 2 words fit |
448 if (fsm->sii_offset + 2 <= sii_word_size) { // 2 words fit |
449 memcpy(slave->eeprom_data + fsm->sii_offset * 2, |
449 memcpy(slave->sii_data + fsm->sii_offset * 2, |
450 fsm->fsm_sii.value, 4); |
450 fsm->fsm_sii.value, 4); |
451 } |
451 } |
452 else { // copy the last word |
452 else { // copy the last word |
453 memcpy(slave->eeprom_data + fsm->sii_offset * 2, |
453 memcpy(slave->sii_data + fsm->sii_offset * 2, |
454 fsm->fsm_sii.value, 2); |
454 fsm->fsm_sii.value, 2); |
455 } |
455 } |
456 |
456 |
457 if (fsm->sii_offset + 2 < eeprom_word_size) { |
457 if (fsm->sii_offset + 2 < sii_word_size) { |
458 // fetch the next 2 words |
458 // fetch the next 2 words |
459 fsm->sii_offset += 2; |
459 fsm->sii_offset += 2; |
460 ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset, |
460 ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset, |
461 EC_FSM_SII_USE_CONFIGURED_ADDRESS); |
461 EC_FSM_SII_USE_CONFIGURED_ADDRESS); |
462 ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately |
462 ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately |
463 return; |
463 return; |
464 } |
464 } |
465 |
465 |
466 // Evaluate EEPROM contents |
466 // Evaluate SII contents |
467 |
467 |
468 ec_slave_clear_sync_managers(slave); |
468 ec_slave_clear_sync_managers(slave); |
469 |
469 |
470 slave->sii.alias = |
470 slave->sii.alias = |
471 EC_READ_U16(slave->eeprom_data + 2 * 0x0004); |
471 EC_READ_U16(slave->sii_data + 2 * 0x0004); |
472 slave->sii.vendor_id = |
472 slave->sii.vendor_id = |
473 EC_READ_U32(slave->eeprom_data + 2 * 0x0008); |
473 EC_READ_U32(slave->sii_data + 2 * 0x0008); |
474 slave->sii.product_code = |
474 slave->sii.product_code = |
475 EC_READ_U32(slave->eeprom_data + 2 * 0x000A); |
475 EC_READ_U32(slave->sii_data + 2 * 0x000A); |
476 slave->sii.revision_number = |
476 slave->sii.revision_number = |
477 EC_READ_U32(slave->eeprom_data + 2 * 0x000C); |
477 EC_READ_U32(slave->sii_data + 2 * 0x000C); |
478 slave->sii.serial_number = |
478 slave->sii.serial_number = |
479 EC_READ_U32(slave->eeprom_data + 2 * 0x000E); |
479 EC_READ_U32(slave->sii_data + 2 * 0x000E); |
480 slave->sii.rx_mailbox_offset = |
480 slave->sii.rx_mailbox_offset = |
481 EC_READ_U16(slave->eeprom_data + 2 * 0x0018); |
481 EC_READ_U16(slave->sii_data + 2 * 0x0018); |
482 slave->sii.rx_mailbox_size = |
482 slave->sii.rx_mailbox_size = |
483 EC_READ_U16(slave->eeprom_data + 2 * 0x0019); |
483 EC_READ_U16(slave->sii_data + 2 * 0x0019); |
484 slave->sii.tx_mailbox_offset = |
484 slave->sii.tx_mailbox_offset = |
485 EC_READ_U16(slave->eeprom_data + 2 * 0x001A); |
485 EC_READ_U16(slave->sii_data + 2 * 0x001A); |
486 slave->sii.tx_mailbox_size = |
486 slave->sii.tx_mailbox_size = |
487 EC_READ_U16(slave->eeprom_data + 2 * 0x001B); |
487 EC_READ_U16(slave->sii_data + 2 * 0x001B); |
488 slave->sii.mailbox_protocols = |
488 slave->sii.mailbox_protocols = |
489 EC_READ_U16(slave->eeprom_data + 2 * 0x001C); |
489 EC_READ_U16(slave->sii_data + 2 * 0x001C); |
490 |
490 |
491 if (eeprom_word_size == EC_FIRST_EEPROM_CATEGORY_OFFSET) { |
491 if (sii_word_size == EC_FIRST_SII_CATEGORY_OFFSET) { |
492 // eeprom does not contain category data |
492 // sii does not contain category data |
493 fsm->state = ec_fsm_slave_scan_state_end; |
493 fsm->state = ec_fsm_slave_scan_state_end; |
494 return; |
494 return; |
495 } |
495 } |
496 |
496 |
497 if (eeprom_word_size < EC_FIRST_EEPROM_CATEGORY_OFFSET + 1) { |
497 if (sii_word_size < EC_FIRST_SII_CATEGORY_OFFSET + 1) { |
498 EC_ERR("Unexpected end of EEPROM data in slave %u:" |
498 EC_ERR("Unexpected end of SII data in slave %u:" |
499 " First category header missing.\n", |
499 " First category header missing.\n", |
500 slave->ring_position); |
500 slave->ring_position); |
501 goto end; |
501 goto end; |
502 } |
502 } |
503 |
503 |
504 // evaluate category data |
504 // evaluate category data |
505 cat_word = |
505 cat_word = |
506 (uint16_t *) slave->eeprom_data + EC_FIRST_EEPROM_CATEGORY_OFFSET; |
506 (uint16_t *) slave->sii_data + EC_FIRST_SII_CATEGORY_OFFSET; |
507 while (EC_READ_U16(cat_word) != 0xFFFF) { |
507 while (EC_READ_U16(cat_word) != 0xFFFF) { |
508 |
508 |
509 // type and size words must fit |
509 // type and size words must fit |
510 if (cat_word + 2 - (uint16_t *) slave->eeprom_data |
510 if (cat_word + 2 - (uint16_t *) slave->sii_data |
511 > eeprom_word_size) { |
511 > sii_word_size) { |
512 EC_ERR("Unexpected end of EEPROM data in slave %u:" |
512 EC_ERR("Unexpected end of SII data in slave %u:" |
513 " Category header incomplete.\n", |
513 " Category header incomplete.\n", |
514 slave->ring_position); |
514 slave->ring_position); |
515 goto end; |
515 goto end; |
516 } |
516 } |
517 |
517 |
518 cat_type = EC_READ_U16(cat_word) & 0x7FFF; |
518 cat_type = EC_READ_U16(cat_word) & 0x7FFF; |
519 cat_size = EC_READ_U16(cat_word + 1); |
519 cat_size = EC_READ_U16(cat_word + 1); |
520 cat_word += 2; |
520 cat_word += 2; |
521 |
521 |
522 if (cat_word + cat_size - (uint16_t *) slave->eeprom_data |
522 if (cat_word + cat_size - (uint16_t *) slave->sii_data |
523 > eeprom_word_size) { |
523 > sii_word_size) { |
524 EC_WARN("Unexpected end of EEPROM data in slave %u:" |
524 EC_WARN("Unexpected end of SII data in slave %u:" |
525 " Category data incomplete.\n", |
525 " Category data incomplete.\n", |
526 slave->ring_position); |
526 slave->ring_position); |
527 goto end; |
527 goto end; |
528 } |
528 } |
529 |
529 |