master/device_id.c
changeset 639 aa23c48dca2d
parent 638 b0994b4e3b37
child 640 16e9ad7d8e12
equal deleted inserted replaced
638:b0994b4e3b37 639:aa23c48dca2d
     1 /******************************************************************************
       
     2  *
       
     3  *  $Id$
       
     4  *
       
     5  *  Copyright (C) 2006  Florian Pose, Ingenieurgemeinschaft IgH
       
     6  *
       
     7  *  This file is part of the IgH EtherCAT Master.
       
     8  *
       
     9  *  The IgH EtherCAT Master is free software; you can redistribute it
       
    10  *  and/or modify it under the terms of the GNU General Public License
       
    11  *  as published by the Free Software Foundation; either version 2 of the
       
    12  *  License, or (at your option) any later version.
       
    13  *
       
    14  *  The IgH EtherCAT Master is distributed in the hope that it will be
       
    15  *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    17  *  GNU General Public License for more details.
       
    18  *
       
    19  *  You should have received a copy of the GNU General Public License
       
    20  *  along with the IgH EtherCAT Master; if not, write to the Free Software
       
    21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
       
    22  *
       
    23  *  The right to use EtherCAT Technology is granted and comes free of
       
    24  *  charge under condition of compatibility of product made by
       
    25  *  Licensee. People intending to distribute/sell products based on the
       
    26  *  code, have to sign an agreement to guarantee that products using
       
    27  *  software based on IgH EtherCAT master stay compatible with the actual
       
    28  *  EtherCAT specification (which are released themselves as an open
       
    29  *  standard) as the (only) precondition to have the right to use EtherCAT
       
    30  *  Technology, IP and trade marks.
       
    31  *
       
    32  *****************************************************************************/
       
    33 
       
    34 /**
       
    35    \file
       
    36    EtherCAT device ID.
       
    37 */
       
    38 
       
    39 /*****************************************************************************/
       
    40 
       
    41 #include <linux/list.h>
       
    42 #include <linux/netdevice.h>
       
    43 
       
    44 #include "globals.h"
       
    45 #include "device_id.h"
       
    46 
       
    47 /*****************************************************************************/
       
    48 
       
    49 static int ec_device_id_parse_mac(ec_device_id_t *dev_id,
       
    50         const char *src, const char **remainder)
       
    51 {
       
    52     unsigned int i, value;
       
    53     char *rem;
       
    54 
       
    55     for (i = 0; i < ETH_ALEN; i++) {
       
    56         value = simple_strtoul(src, &rem, 16);
       
    57         if (rem != src + 2
       
    58                 || value > 0xFF
       
    59                 || (i < ETH_ALEN - 1 && *rem != ':')) {
       
    60             return -1;
       
    61         }
       
    62         dev_id->octets[i] = value;
       
    63         if (i < ETH_ALEN - 1)
       
    64             src = rem + 1;
       
    65     }
       
    66 
       
    67     dev_id->type = ec_device_id_mac;
       
    68     *remainder = rem;
       
    69     return 0;
       
    70 }
       
    71 
       
    72 /*****************************************************************************/
       
    73 
       
    74 void ec_device_id_clear_list(struct list_head *ids)
       
    75 {
       
    76     ec_device_id_t *dev_id, *next_dev_id;
       
    77     
       
    78     list_for_each_entry_safe(dev_id, next_dev_id, ids, list) {
       
    79         list_del(&dev_id->list);
       
    80         kfree(dev_id);
       
    81     }
       
    82 }
       
    83 
       
    84 /*****************************************************************************/
       
    85 
       
    86 static int ec_device_id_create_list(struct list_head *ids, const char *src)
       
    87 {
       
    88     const char *rem;
       
    89     ec_device_id_t *dev_id;
       
    90     unsigned int index = 0;
       
    91 
       
    92     while (*src) {
       
    93         // allocate new device ID
       
    94         if (!(dev_id = kmalloc(sizeof(ec_device_id_t), GFP_KERNEL))) {
       
    95             EC_ERR("Out of memory!\n");
       
    96             goto out_free;
       
    97         }
       
    98         
       
    99         if (*src == ';') { // empty device ID
       
   100             dev_id->type = ec_device_id_empty;
       
   101         }
       
   102         else if (*src == 'M') {
       
   103             src++;
       
   104             if (ec_device_id_parse_mac(dev_id, src, &rem)) {
       
   105                 EC_ERR("Device ID %u: Invalid MAC syntax!\n", index);
       
   106                 kfree(dev_id);
       
   107                 goto out_free;
       
   108             }
       
   109             src = rem;
       
   110         }
       
   111         else {
       
   112             EC_ERR("Device ID %u: Unknown format \'%c\'!\n", index, *src);
       
   113             kfree(dev_id);
       
   114             goto out_free;
       
   115         }
       
   116         
       
   117         list_add_tail(&dev_id->list, ids); 
       
   118 
       
   119         if (*src) {
       
   120             if (*src != ';') {
       
   121                 EC_ERR("Invalid delimiter '%c' after device ID %i!\n",
       
   122                         *src, index);
       
   123                 goto out_free;
       
   124             }
       
   125             src++; // skip delimiter
       
   126         }
       
   127         index++;
       
   128     }
       
   129 
       
   130     return 0;
       
   131 
       
   132 out_free:
       
   133     ec_device_id_clear_list(ids);
       
   134     return -1;
       
   135 }
       
   136 
       
   137 /*****************************************************************************/
       
   138 
       
   139 int ec_device_id_process_params(const char *main, const char *backup,
       
   140         struct list_head *main_ids, struct list_head *backup_ids)
       
   141 {
       
   142     ec_device_id_t *id;
       
   143     unsigned int main_count = 0, backup_count = 0;
       
   144     
       
   145     if (ec_device_id_create_list(main_ids, main))
       
   146         return -1;
       
   147 
       
   148     if (ec_device_id_create_list(backup_ids, backup))
       
   149         return -1;
       
   150 
       
   151     // count main device IDs and check for empty ones
       
   152     list_for_each_entry(id, main_ids, list) {
       
   153         if (id->type == ec_device_id_empty) {
       
   154             EC_ERR("Main device IDs may not be empty!\n");
       
   155             return -1;
       
   156         }
       
   157         main_count++;
       
   158     }
       
   159 
       
   160     // count backup device IDs
       
   161     list_for_each_entry(id, backup_ids, list) {
       
   162         backup_count++;
       
   163     }
       
   164 
       
   165     // fill up backup device IDs
       
   166     while (backup_count < main_count) {
       
   167         if (!(id = kmalloc(sizeof(ec_device_id_t), GFP_KERNEL))) {
       
   168             EC_ERR("Out of memory!\n");
       
   169             return -1;
       
   170         }
       
   171         
       
   172         id->type = ec_device_id_empty;
       
   173         list_add_tail(&id->list, backup_ids);
       
   174         backup_count++;
       
   175     }
       
   176 
       
   177     return 0;
       
   178 }
       
   179 
       
   180 /*****************************************************************************/
       
   181 
       
   182 int ec_device_id_check(const ec_device_id_t *dev_id,
       
   183         const struct net_device *dev, const char *driver_name,
       
   184         unsigned int device_index)
       
   185 {
       
   186     unsigned int i;
       
   187     
       
   188     switch (dev_id->type) {
       
   189         case ec_device_id_mac:
       
   190             for (i = 0; i < ETH_ALEN; i++)
       
   191                 if (dev->dev_addr[i] != dev_id->octets[i])
       
   192                     return 0;
       
   193             return 1;
       
   194         default:
       
   195             return 0;
       
   196     }
       
   197 }
       
   198                 
       
   199 /*****************************************************************************/
       
   200 
       
   201 ssize_t ec_device_id_print(const ec_device_id_t *dev_id, char *buffer)
       
   202 {
       
   203     off_t off = 0;
       
   204     unsigned int i;
       
   205     
       
   206     switch (dev_id->type) {
       
   207         case ec_device_id_empty:
       
   208             off += sprintf(buffer + off, "none");
       
   209             break;
       
   210         case ec_device_id_mac:
       
   211             off += sprintf(buffer + off, "MAC ");
       
   212             for (i = 0; i < ETH_ALEN; i++) {
       
   213                 off += sprintf(buffer + off, "%02X", dev_id->octets[i]);
       
   214                 if (i < ETH_ALEN - 1) off += sprintf(buffer + off, ":");
       
   215             }
       
   216             break;
       
   217     }
       
   218 
       
   219     return off;
       
   220 }
       
   221                 
       
   222 /*****************************************************************************/