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 /*****************************************************************************/ |
|