master/slave.c
changeset 872 d4e0380d63b3
parent 871 5a8959f77854
child 873 ec01ba291896
equal deleted inserted replaced
871:5a8959f77854 872:d4e0380d63b3
    65 
    65 
    66 /** \cond */
    66 /** \cond */
    67 
    67 
    68 EC_SYSFS_READ_ATTR(info);
    68 EC_SYSFS_READ_ATTR(info);
    69 EC_SYSFS_READ_WRITE_ATTR(state);
    69 EC_SYSFS_READ_WRITE_ATTR(state);
    70 EC_SYSFS_READ_WRITE_ATTR(eeprom);
    70 EC_SYSFS_READ_WRITE_ATTR(sii);
    71 EC_SYSFS_READ_WRITE_ATTR(alias);
    71 EC_SYSFS_READ_WRITE_ATTR(alias);
    72 
    72 
    73 static struct attribute *def_attrs[] = {
    73 static struct attribute *def_attrs[] = {
    74     &attr_info,
    74     &attr_info,
    75     &attr_state,
    75     &attr_state,
    76     &attr_eeprom,
    76     &attr_sii,
    77     &attr_alias,
    77     &attr_alias,
    78     NULL,
    78     NULL,
    79 };
    79 };
    80 
    80 
    81 static struct sysfs_ops sysfs_ops = {
    81 static struct sysfs_ops sysfs_ops = {
   125     slave->base_type = 0;
   125     slave->base_type = 0;
   126     slave->base_revision = 0;
   126     slave->base_revision = 0;
   127     slave->base_build = 0;
   127     slave->base_build = 0;
   128     slave->base_fmmu_count = 0;
   128     slave->base_fmmu_count = 0;
   129 
   129 
   130     slave->eeprom_data = NULL;
   130     slave->sii_data = NULL;
   131     slave->eeprom_size = 0;
   131     slave->sii_size = 0;
   132 
   132 
   133     slave->sii.alias = 0;
   133     slave->sii.alias = 0;
   134     slave->sii.vendor_id = 0;
   134     slave->sii.vendor_id = 0;
   135     slave->sii.product_code = 0;
   135     slave->sii.product_code = 0;
   136     slave->sii.revision_number = 0;
   136     slave->sii.revision_number = 0;
   268         list_del(&pdo->list);
   268         list_del(&pdo->list);
   269         ec_pdo_clear(pdo);
   269         ec_pdo_clear(pdo);
   270         kfree(pdo);
   270         kfree(pdo);
   271     }
   271     }
   272 
   272 
   273     if (slave->eeprom_data) kfree(slave->eeprom_data);
   273     if (slave->sii_data)
       
   274         kfree(slave->sii_data);
   274 
   275 
   275     kfree(slave);
   276     kfree(slave);
   276 }
   277 }
   277 
   278 
   278 /*****************************************************************************/
   279 /*****************************************************************************/
   859 }
   860 }
   860 
   861 
   861 /*****************************************************************************/
   862 /*****************************************************************************/
   862 
   863 
   863 /**
   864 /**
   864  * Schedules an EEPROM write request.
   865  * Schedules an SII write request.
   865  * \return 0 case of success, otherwise error code.
   866  * \return 0 case of success, otherwise error code.
   866  */
   867  */
   867 
   868 
   868 int ec_slave_schedule_eeprom_writing(
   869 int ec_slave_schedule_sii_writing(
   869         ec_eeprom_write_request_t *request /**< EEPROM write request */
   870         ec_sii_write_request_t *request /**< SII write request */
   870         )
   871         )
   871 {
   872 {
   872     ec_master_t *master = request->slave->master;
   873     ec_master_t *master = request->slave->master;
   873 
   874 
   874     request->state = EC_REQUEST_QUEUED;
   875     request->state = EC_REQUEST_QUEUED;
   875 
   876 
   876     // schedule EEPROM write request.
   877     // schedule SII write request.
   877     down(&master->eeprom_sem);
   878     down(&master->sii_sem);
   878     list_add_tail(&request->list, &master->eeprom_requests);
   879     list_add_tail(&request->list, &master->sii_requests);
   879     up(&master->eeprom_sem);
   880     up(&master->sii_sem);
   880 
   881 
   881     // wait for processing through FSM
   882     // wait for processing through FSM
   882     if (wait_event_interruptible(master->eeprom_queue,
   883     if (wait_event_interruptible(master->sii_queue,
   883                 request->state != EC_REQUEST_QUEUED)) {
   884                 request->state != EC_REQUEST_QUEUED)) {
   884         // interrupted by signal
   885         // interrupted by signal
   885         down(&master->eeprom_sem);
   886         down(&master->sii_sem);
   886         if (request->state == EC_REQUEST_QUEUED) {
   887         if (request->state == EC_REQUEST_QUEUED) {
   887             list_del(&request->list);
   888             list_del(&request->list);
   888             up(&master->eeprom_sem);
   889             up(&master->sii_sem);
   889             return -EINTR;
   890             return -EINTR;
   890         }
   891         }
   891         // request already processing: interrupt not possible.
   892         // request already processing: interrupt not possible.
   892         up(&master->eeprom_sem);
   893         up(&master->sii_sem);
   893     }
   894     }
   894 
   895 
   895     // wait until master FSM has finished processing
   896     // wait until master FSM has finished processing
   896     wait_event(master->eeprom_queue,
   897     wait_event(master->sii_queue,
   897             request->state != EC_REQUEST_BUSY);
   898             request->state != EC_REQUEST_BUSY);
   898 
   899 
   899     return request->state == EC_REQUEST_SUCCESS ? 0 : -EIO;
   900     return request->state == EC_REQUEST_SUCCESS ? 0 : -EIO;
   900 }
   901 }
   901 
   902 
   902 /*****************************************************************************/
   903 /*****************************************************************************/
   903 
   904 
   904 /**
   905 /**
   905  * Calculates the EEPROM checksum field.
   906  * Calculates the SII checksum field.
   906  *
   907  *
   907  * The checksum is generated with the polynom x^8+x^2+x+1 (0x07) and an
   908  * The checksum is generated with the polynom x^8+x^2+x+1 (0x07) and an
   908  * initial value of 0xff (see IEC 61158-6-12 ch. 5.4).
   909  * initial value of 0xff (see IEC 61158-6-12 ch. 5.4).
   909  *
   910  *
   910  * The below code was originally generated with PYCRC
   911  * The below code was originally generated with PYCRC
   914  *   --reflect-out=0 --xor-out=0 --generate c --algorithm=bit-by-bit
   915  *   --reflect-out=0 --xor-out=0 --generate c --algorithm=bit-by-bit
   915  *
   916  *
   916  * \return CRC8
   917  * \return CRC8
   917  */
   918  */
   918 
   919 
   919 uint8_t ec_slave_eeprom_crc(
   920 uint8_t ec_slave_sii_crc(
   920         const uint8_t *data, /**< pointer to data */
   921         const uint8_t *data, /**< pointer to data */
   921         size_t length /**< number of bytes in \a data */
   922         size_t length /**< number of bytes in \a data */
   922         )
   923         )
   923 {
   924 {
   924     unsigned int i;
   925     unsigned int i;
   943 }
   944 }
   944 
   945 
   945 /*****************************************************************************/
   946 /*****************************************************************************/
   946 
   947 
   947 /**
   948 /**
   948  * Writes complete EEPROM contents to a slave.
   949  * Writes complete SII contents to a slave.
   949  * \return data size written in case of success, otherwise error code.
   950  * \return data size written in case of success, otherwise error code.
   950  */
   951  */
   951 
   952 
   952 ssize_t ec_slave_write_eeprom(ec_slave_t *slave, /**< EtherCAT slave */
   953 ssize_t ec_slave_write_sii(ec_slave_t *slave, /**< EtherCAT slave */
   953         const uint8_t *data, /**< new EEPROM data */
   954         const uint8_t *data, /**< new SII data */
   954         size_t size /**< size of data in bytes */
   955         size_t size /**< size of data in bytes */
   955         )
   956         )
   956 {
   957 {
   957     ec_eeprom_write_request_t request;
   958     ec_sii_write_request_t request;
   958     const uint16_t *cat_header;
   959     const uint16_t *cat_header;
   959     uint16_t cat_type, cat_size;
   960     uint16_t cat_type, cat_size;
   960     int ret;
   961     int ret;
   961     uint8_t crc;
   962     uint8_t crc;
   962 
   963 
   963     if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME
   964     if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME
   964         EC_ERR("Writing EEPROMs only allowed in idle mode!\n");
   965         EC_ERR("Writing SIIs only allowed in idle mode!\n");
   965         return -EBUSY;
   966         return -EBUSY;
   966     }
   967     }
   967 
   968 
   968     if (size % 2) {
   969     if (size % 2) {
   969         EC_ERR("EEPROM data size is odd (%u bytes)! SII data must be"
   970         EC_ERR("SII data size is odd (%u bytes)! SII data must be"
   970                 " word-aligned. Dropping.\n", size);
   971                 " word-aligned. Dropping.\n", size);
   971         return -EINVAL;
   972         return -EINVAL;
   972     }
   973     }
   973 
   974 
   974     // init EEPROM write request
   975     // init SII write request
   975     INIT_LIST_HEAD(&request.list);
   976     INIT_LIST_HEAD(&request.list);
   976     request.slave = slave;
   977     request.slave = slave;
   977     request.data = data;
   978     request.data = data;
   978     request.word_offset = 0;
   979     request.word_offset = 0;
   979     request.word_size = size / 2;
   980     request.word_size = size / 2;
   980 
   981 
   981     if (request.word_size < 0x0041) {
   982     if (request.word_size < 0x0041) {
   982         EC_ERR("EEPROM data too short (%u words)! Mimimum is"
   983         EC_ERR("SII data too short (%u words)! Mimimum is"
   983                 " 40 fixed words + 1 delimiter. Dropping.\n",
   984                 " 40 fixed words + 1 delimiter. Dropping.\n",
   984                 request.word_size);
   985                 request.word_size);
   985         return -EINVAL;
   986         return -EINVAL;
   986     }
   987     }
   987 
   988 
   988     // calculate checksum
   989     // calculate checksum
   989     crc = ec_slave_eeprom_crc(data, 14); // CRC over words 0 to 6
   990     crc = ec_slave_sii_crc(data, 14); // CRC over words 0 to 6
   990     if (crc != data[14]) {
   991     if (crc != data[14]) {
   991         EC_WARN("EEPROM CRC incorrect. Must be 0x%02x.\n", crc);
   992         EC_WARN("SII CRC incorrect. Must be 0x%02x.\n", crc);
   992     }
   993     }
   993 
   994 
   994     cat_header = (const uint16_t *) request.data
   995     cat_header = (const uint16_t *) request.data
   995 		+ EC_FIRST_EEPROM_CATEGORY_OFFSET;
   996 		+ EC_FIRST_SII_CATEGORY_OFFSET;
   996     cat_type = EC_READ_U16(cat_header);
   997     cat_type = EC_READ_U16(cat_header);
   997     while (cat_type != 0xFFFF) { // cycle through categories
   998     while (cat_type != 0xFFFF) { // cycle through categories
   998         if (cat_header + 1 >
   999         if (cat_header + 1 >
   999 				(const uint16_t *) request.data + request.word_size) {
  1000 				(const uint16_t *) request.data + request.word_size) {
  1000             EC_ERR("EEPROM data corrupted! Dropping.\n");
  1001             EC_ERR("SII data corrupted! Dropping.\n");
  1001             return -EINVAL;
  1002             return -EINVAL;
  1002         }
  1003         }
  1003         cat_size = EC_READ_U16(cat_header + 1);
  1004         cat_size = EC_READ_U16(cat_header + 1);
  1004         if (cat_header + cat_size + 2 >
  1005         if (cat_header + cat_size + 2 >
  1005 				(const uint16_t *) request.data + request.word_size) {
  1006 				(const uint16_t *) request.data + request.word_size) {
  1006             EC_ERR("EEPROM data corrupted! Dropping.\n");
  1007             EC_ERR("SII data corrupted! Dropping.\n");
  1007             return -EINVAL;
  1008             return -EINVAL;
  1008         }
  1009         }
  1009         cat_header += cat_size + 2;
  1010         cat_header += cat_size + 2;
  1010         cat_type = EC_READ_U16(cat_header);
  1011         cat_type = EC_READ_U16(cat_header);
  1011     }
  1012     }
  1012 
  1013 
  1013     // EEPROM data ok. schedule writing.
  1014     // SII data ok. schedule writing.
  1014     if ((ret = ec_slave_schedule_eeprom_writing(&request)))
  1015     if ((ret = ec_slave_schedule_sii_writing(&request)))
  1015         return ret; // error code
  1016         return ret; // error code
  1016 
  1017 
  1017     return size; // success
  1018     return size; // success
  1018 }
  1019 }
  1019 
  1020 
  1020 /*****************************************************************************/
  1021 /*****************************************************************************/
  1021 
  1022 
  1022 /**
  1023 /**
  1023  * Writes the Secondary slave address (alias) to the slave's EEPROM.
  1024  * Writes the Secondary slave address (alias) to the slave's SII.
  1024  * \return data size written in case of success, otherwise error code.
  1025  * \return data size written in case of success, otherwise error code.
  1025  */
  1026  */
  1026 
  1027 
  1027 ssize_t ec_slave_write_alias(ec_slave_t *slave, /**< EtherCAT slave */
  1028 ssize_t ec_slave_write_alias(ec_slave_t *slave, /**< EtherCAT slave */
  1028         const uint8_t *data, /**< alias string */
  1029         const uint8_t *data, /**< alias string */
  1029         size_t size /**< size of data in bytes */
  1030         size_t size /**< size of data in bytes */
  1030         )
  1031         )
  1031 {
  1032 {
  1032     ec_eeprom_write_request_t request;
  1033     ec_sii_write_request_t request;
  1033     char *remainder;
  1034     char *remainder;
  1034     uint16_t alias;
  1035     uint16_t alias;
  1035     int ret;
  1036     int ret;
  1036     uint8_t eeprom_data[16], crc;
  1037     uint8_t sii_data[16], crc;
  1037 
  1038 
  1038     if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME
  1039     if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME
  1039         EC_ERR("Writing to EEPROM is only allowed in idle mode!\n");
  1040         EC_ERR("Writing to SII is only allowed in idle mode!\n");
  1040         return -EBUSY;
  1041         return -EBUSY;
  1041     }
  1042     }
  1042 
  1043 
  1043     alias = simple_strtoul(data, &remainder, 0);
  1044     alias = simple_strtoul(data, &remainder, 0);
  1044     if (remainder == (char *) data || (*remainder && *remainder != '\n')) {
  1045     if (remainder == (char *) data || (*remainder && *remainder != '\n')) {
  1045         EC_ERR("Invalid alias value! Dropping.\n");
  1046         EC_ERR("Invalid alias value! Dropping.\n");
  1046         return -EINVAL;
  1047         return -EINVAL;
  1047     }
  1048     }
  1048 
  1049 
  1049     if (!slave->eeprom_data || slave->eeprom_size < 16) {
  1050     if (!slave->sii_data || slave->sii_size < 16) {
  1050         EC_ERR("Failed to read EEPROM contents from slave %u.\n",
  1051         EC_ERR("Failed to read SII contents from slave %u.\n",
  1051                 slave->ring_position);
  1052                 slave->ring_position);
  1052         return -EINVAL;
  1053         return -EINVAL;
  1053     }
  1054     }
  1054 
  1055 
  1055     // copy first 7 words of recent EEPROM contents
  1056     // copy first 7 words of recent SII contents
  1056     memcpy(eeprom_data, slave->eeprom_data, 14);
  1057     memcpy(sii_data, slave->sii_data, 14);
  1057     
  1058     
  1058     // write new alias address in word 4
  1059     // write new alias address in word 4
  1059     EC_WRITE_U16(eeprom_data + 8, alias);
  1060     EC_WRITE_U16(sii_data + 8, alias);
  1060 
  1061 
  1061     // calculate new checksum over words 0 to 6
  1062     // calculate new checksum over words 0 to 6
  1062     crc = ec_slave_eeprom_crc(eeprom_data, 14);
  1063     crc = ec_slave_sii_crc(sii_data, 14);
  1063     EC_WRITE_U16(eeprom_data + 14, crc);
  1064     EC_WRITE_U16(sii_data + 14, crc);
  1064 
  1065 
  1065     // init EEPROM write request
  1066     // init SII write request
  1066     INIT_LIST_HEAD(&request.list);
  1067     INIT_LIST_HEAD(&request.list);
  1067     request.slave = slave;
  1068     request.slave = slave;
  1068     request.data = eeprom_data;
  1069     request.data = sii_data;
  1069     request.word_offset = 0x0000;
  1070     request.word_offset = 0x0000;
  1070     request.word_size = 8;
  1071     request.word_size = 8;
  1071 
  1072 
  1072     if ((ret = ec_slave_schedule_eeprom_writing(&request)))
  1073     if ((ret = ec_slave_schedule_sii_writing(&request)))
  1073         return ret; // error code
  1074         return ret; // error code
  1074 
  1075 
  1075     slave->sii.alias = alias; // FIXME: do this in state machine
  1076     slave->sii.alias = alias; // FIXME: do this in state machine
  1076 
  1077 
  1077     return size; // success
  1078     return size; // success
  1106                 return sprintf(buffer, "OP\n");
  1107                 return sprintf(buffer, "OP\n");
  1107             default:
  1108             default:
  1108                 return sprintf(buffer, "UNKNOWN\n");
  1109                 return sprintf(buffer, "UNKNOWN\n");
  1109         }
  1110         }
  1110     }
  1111     }
  1111     else if (attr == &attr_eeprom) {
  1112     else if (attr == &attr_sii) {
  1112         if (slave->eeprom_data) {
  1113         if (slave->sii_data) {
  1113             if (slave->eeprom_size > PAGE_SIZE) {
  1114             if (slave->sii_size > PAGE_SIZE) {
  1114                 EC_ERR("EEPROM contents of slave %u exceed 1 page (%u/%u).\n",
  1115                 EC_ERR("SII contents of slave %u exceed 1 page (%u/%u).\n",
  1115                        slave->ring_position, slave->eeprom_size,
  1116                        slave->ring_position, slave->sii_size,
  1116                        (int) PAGE_SIZE);
  1117                        (int) PAGE_SIZE);
  1117             }
  1118             }
  1118             else {
  1119             else {
  1119                 memcpy(buffer, slave->eeprom_data, slave->eeprom_size);
  1120                 memcpy(buffer, slave->sii_data, slave->sii_size);
  1120                 return slave->eeprom_size;
  1121                 return slave->sii_size;
  1121             }
  1122             }
  1122         }
  1123         }
  1123     }
  1124     }
  1124     else if (attr == &attr_alias) {
  1125     else if (attr == &attr_alias) {
  1125         return sprintf(buffer, "%u\n", slave->sii.alias);
  1126         return sprintf(buffer, "%u\n", slave->sii.alias);
  1161         ec_state_string(slave->requested_state, state);
  1162         ec_state_string(slave->requested_state, state);
  1162         EC_INFO("Accepted new state %s for slave %u.\n",
  1163         EC_INFO("Accepted new state %s for slave %u.\n",
  1163                 state, slave->ring_position);
  1164                 state, slave->ring_position);
  1164         return size;
  1165         return size;
  1165     }
  1166     }
  1166     else if (attr == &attr_eeprom) {
  1167     else if (attr == &attr_sii) {
  1167         return ec_slave_write_eeprom(slave, buffer, size);
  1168         return ec_slave_write_sii(slave, buffer, size);
  1168     }
  1169     }
  1169     else if (attr == &attr_alias) {
  1170     else if (attr == &attr_alias) {
  1170         return ec_slave_write_alias(slave, buffer, size);
  1171         return ec_slave_write_alias(slave, buffer, size);
  1171     }
  1172     }
  1172 
  1173