fp@627: /******************************************************************************
fp@627:  *
fp@627:  *  $Id$
fp@627:  *
fp@627:  *  Copyright (C) 2006  Florian Pose, Ingenieurgemeinschaft IgH
fp@627:  *
fp@627:  *  This file is part of the IgH EtherCAT Master.
fp@627:  *
fp@627:  *  The IgH EtherCAT Master is free software; you can redistribute it
fp@627:  *  and/or modify it under the terms of the GNU General Public License
fp@627:  *  as published by the Free Software Foundation; either version 2 of the
fp@627:  *  License, or (at your option) any later version.
fp@627:  *
fp@627:  *  The IgH EtherCAT Master is distributed in the hope that it will be
fp@627:  *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
fp@627:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
fp@627:  *  GNU General Public License for more details.
fp@627:  *
fp@627:  *  You should have received a copy of the GNU General Public License
fp@627:  *  along with the IgH EtherCAT Master; if not, write to the Free Software
fp@627:  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
fp@627:  *
fp@627:  *  The right to use EtherCAT Technology is granted and comes free of
fp@627:  *  charge under condition of compatibility of product made by
fp@627:  *  Licensee. People intending to distribute/sell products based on the
fp@627:  *  code, have to sign an agreement to guarantee that products using
fp@627:  *  software based on IgH EtherCAT master stay compatible with the actual
fp@627:  *  EtherCAT specification (which are released themselves as an open
fp@627:  *  standard) as the (only) precondition to have the right to use EtherCAT
fp@627:  *  Technology, IP and trade marks.
fp@627:  *
fp@627:  *****************************************************************************/
fp@627: 
fp@627: /**
fp@627:    \file
fp@627:    EtherCAT process data object methods.
fp@627: */
fp@627: 
fp@627: /*****************************************************************************/
fp@627: 
fp@627: #include <linux/slab.h>
fp@627: 
fp@627: #include "pdo.h"
fp@627: 
fp@627: /*****************************************************************************/
fp@627: 
fp@814: /** Pdo constructor.
fp@792:  */
fp@792: void ec_pdo_init(
fp@814:         ec_pdo_t *pdo /**< EtherCAT Pdo */
fp@792:         )
fp@792: {
fp@792:     pdo->sync_index = -1; // not assigned 
fp@627:     pdo->name = NULL;
fp@627:     INIT_LIST_HEAD(&pdo->entries);
fp@842:     pdo->default_config = 0;
fp@627: }
fp@627: 
fp@627: /*****************************************************************************/
fp@627: 
fp@792: /** Pdo copy constructor.
fp@792:  */
fp@792: int ec_pdo_init_copy(ec_pdo_t *pdo, const ec_pdo_t *other_pdo)
fp@792: {
fp@792:     pdo->dir = other_pdo->dir;
fp@792:     pdo->index = other_pdo->index;
fp@792:     pdo->sync_index = other_pdo->sync_index;
fp@792:     pdo->name = NULL;
fp@792:     INIT_LIST_HEAD(&pdo->entries);
fp@842:     pdo->default_config = other_pdo->default_config;
fp@792: 
fp@792:     if (ec_pdo_set_name(pdo, other_pdo->name))
fp@792:         goto out_return;
fp@792: 
fp@792:     if (ec_pdo_copy_entries(pdo, other_pdo))
fp@792:         goto out_clear;
fp@792: 
fp@792:     return 0;
fp@792: 
fp@792: out_clear:
fp@792:     ec_pdo_clear(pdo);
fp@792: out_return:
fp@792:     return -1;
fp@792: }
fp@792: 
fp@792: /*****************************************************************************/
fp@792: 
fp@814: /** Pdo destructor.
fp@814:  */
fp@842: void ec_pdo_clear(ec_pdo_t *pdo /**< EtherCAT Pdo. */)
fp@627: {
fp@792:     if (pdo->name)
fp@792:         kfree(pdo->name);
fp@792: 
fp@792:     ec_pdo_clear_entries(pdo);
fp@792: }
fp@792: 
fp@792: /*****************************************************************************/
fp@792: 
fp@792: /** Clear Pdo entry list.
fp@792:  */
fp@842: void ec_pdo_clear_entries(ec_pdo_t *pdo /**< EtherCAT Pdo. */)
fp@792: {
fp@627:     ec_pdo_entry_t *entry, *next;
fp@627: 
fp@814:     // free all Pdo entries
fp@627:     list_for_each_entry_safe(entry, next, &pdo->entries, list) {
fp@627:         list_del(&entry->list);
fp@792:         ec_pdo_entry_clear(entry);
fp@627:         kfree(entry);
fp@627:     }
fp@627: }
fp@627: 
fp@627: /*****************************************************************************/
fp@627: 
fp@792: /** Set Pdo name.
fp@792:  */
fp@792: int ec_pdo_set_name(
fp@792:         ec_pdo_t *pdo, /**< Pdo. */
fp@792:         const char *name /**< New name. */
fp@792:         )
fp@792: {
fp@792:     unsigned int len;
fp@792: 
fp@792:     if (pdo->name)
fp@792:         kfree(pdo->name);
fp@792: 
fp@792:     if (name && (len = strlen(name))) {
fp@792:         if (!(pdo->name = (char *) kmalloc(len + 1, GFP_KERNEL))) {
fp@814:             EC_ERR("Failed to allocate Pdo name.\n");
fp@792:             return -1;
fp@792:         }
fp@792:         memcpy(pdo->name, name, len + 1);
fp@792:     } else {
fp@792:         pdo->name = NULL;
fp@792:     }
fp@792: 
fp@792:     return 0;
fp@792: }
fp@792: 
fp@792: /*****************************************************************************/
fp@792: 
fp@842: /** Add a new Pdo entry to the configuration.
fp@842:  */
fp@842: ec_pdo_entry_t *ec_pdo_add_entry(
fp@842:         ec_pdo_t *pdo,
fp@842:         uint16_t index,
fp@842:         uint8_t subindex,
fp@842:         uint8_t bit_length
fp@842:         )
fp@842: {
fp@842:     ec_pdo_entry_t *entry;
fp@842: 
fp@842:     if (!(entry = kmalloc(sizeof(ec_pdo_entry_t), GFP_KERNEL))) {
fp@842:         EC_ERR("Failed to allocate memory for Pdo entry.\n");
fp@842:         return NULL;
fp@842:     }
fp@842: 
fp@842:     ec_pdo_entry_init(entry);
fp@842:     entry->index = index;
fp@842:     entry->subindex = subindex;
fp@842:     entry->bit_length = bit_length;
fp@842:     list_add_tail(&entry->list, &pdo->entries);
fp@842:     return entry;
fp@842: }
fp@842: 
fp@842: /*****************************************************************************/
fp@842: 
fp@792: /** Copy Pdo entries from another Pdo.
fp@792:  */
fp@792: int ec_pdo_copy_entries(ec_pdo_t *pdo, const ec_pdo_t *other)
fp@792: {
fp@792:     ec_pdo_entry_t *entry, *other_entry;
fp@792: 
fp@792:     ec_pdo_clear_entries(pdo);
fp@792: 
fp@792:     list_for_each_entry(other_entry, &other->entries, list) {
fp@627:         if (!(entry = (ec_pdo_entry_t *)
fp@627:                     kmalloc(sizeof(ec_pdo_entry_t), GFP_KERNEL))) {
fp@814:             EC_ERR("Failed to allocate memory for Pdo entry copy.\n");
fp@792:             return -1;
fp@792:         }
fp@792: 
fp@792:         if (ec_pdo_entry_init_copy(entry, other_entry)) {
fp@792:             kfree(entry);
fp@792:             return -1;
fp@792:         }
fp@792: 
fp@627:         list_add_tail(&entry->list, &pdo->entries);
fp@627:     }
fp@627: 
fp@627:     return 0;
fp@792: }
fp@792: 
fp@792: /*****************************************************************************/
fp@792: 
fp@799: /** Compares the entries of two Pdos.
fp@799:  *
fp@799:  * \retval 1 The entries of the given Pdos are equal.
fp@799:  * \retval 0 The entries of the given Pdos differ.
fp@799:  */
fp@799: int ec_pdo_equal_entries(
fp@799:         const ec_pdo_t *pdo1, /**< First Pdo. */
fp@799:         const ec_pdo_t *pdo2 /**< Second Pdo. */
fp@799:         )
fp@799: {
fp@799:     const struct list_head *head1, *head2, *item1, *item2;
fp@799:     const ec_pdo_entry_t *entry1, *entry2;
fp@799: 
fp@799:     head1 = item1 = &pdo1->entries;
fp@799:     head2 = item2 = &pdo2->entries;
fp@799: 
fp@799:     while (1) {
fp@799:         item1 = item1->next;
fp@799:         item2 = item2->next;
fp@799: 
fp@799:         if ((item1 == head1) ^ (item2 == head2)) // unequal lengths
fp@799:             return 0;
fp@826:         if (item1 == head1) // both finished
fp@799:             break;
fp@799: 
fp@799:         entry1 = list_entry(item1, ec_pdo_entry_t, list);
fp@799:         entry2 = list_entry(item2, ec_pdo_entry_t, list);
fp@799:         if (!ec_pdo_entry_equal(entry1, entry2))
fp@799:             return 0;
fp@799:     }
fp@799: 
fp@799:     return 1;
fp@799: }
fp@799: 
fp@799: /*****************************************************************************/
fp@799: 
fp@792: /** Pdo entry constructor.
fp@792:  */
fp@792: void ec_pdo_entry_init(
fp@792:         ec_pdo_entry_t *entry /**< Pdo entry. */
fp@792:         )
fp@792: {
fp@792:     entry->name = NULL;
fp@792: }
fp@792: 
fp@792: /*****************************************************************************/
fp@792: 
fp@792: /** Pdo entry copy constructor.
fp@792:  */
fp@792: int ec_pdo_entry_init_copy(
fp@792:         ec_pdo_entry_t *entry, /**< Pdo entry. */
fp@792:         const ec_pdo_entry_t *other /**< Pdo entry to copy from. */
fp@792:         )
fp@792: {
fp@792:     entry->index = other->index;
fp@792:     entry->subindex = other->subindex;
fp@792:     entry->name = NULL;
fp@792:     entry->bit_length = other->bit_length;
fp@792: 
fp@792:     if (ec_pdo_entry_set_name(entry, other->name))
fp@792:         return -1;
fp@792: 
fp@792:     return 0;
fp@792: }
fp@792: 
fp@792: /*****************************************************************************/
fp@792: 
fp@792: /** Pdo entry destructor.
fp@792:  */
fp@792: void ec_pdo_entry_clear(ec_pdo_entry_t *entry /**< Pdo entry. */)
fp@792: {
fp@792:     if (entry->name)
fp@792:         kfree(entry->name);
fp@792: }
fp@792: 
fp@792: /*****************************************************************************/
fp@792: 
fp@792: /** Set Pdo entry name.
fp@792:  */
fp@792: int ec_pdo_entry_set_name(
fp@792:         ec_pdo_entry_t *entry, /**< Pdo entry. */
fp@792:         const char *name /**< New name. */
fp@792:         )
fp@792: {
fp@792:     unsigned int len;
fp@792: 
fp@792:     if (entry->name)
fp@792:         kfree(entry->name);
fp@792: 
fp@792:     if (name && (len = strlen(name))) {
fp@792:         if (!(entry->name = (char *) kmalloc(len + 1, GFP_KERNEL))) {
fp@814:             EC_ERR("Failed to allocate Pdo entry name.\n");
fp@792:             return -1;
fp@792:         }
fp@792:         memcpy(entry->name, name, len + 1);
fp@792:     } else {
fp@792:         entry->name = NULL;
fp@792:     }
fp@792: 
fp@792:     return 0;
fp@792: }
fp@792: 
fp@792: /*****************************************************************************/
fp@799: 
fp@799: /** Compares two Pdo entries.
fp@799:  *
fp@799:  * \retval 1 The entries are equal.
fp@799:  * \retval 0 The entries differ.
fp@799:  */
fp@799: int ec_pdo_entry_equal(
fp@799:         const ec_pdo_entry_t *entry1, /**< First Pdo entry. */
fp@799:         const ec_pdo_entry_t *entry2 /**< Second Pdo entry. */
fp@799:         )
fp@799: {
fp@799:     return entry1->index == entry2->index
fp@799:         && entry1->subindex == entry2->subindex
fp@799:         && entry1->bit_length == entry2->bit_length;
fp@799: }
fp@799: 
fp@799: /*****************************************************************************/