|
1 /****************************************************************************** |
|
2 * |
|
3 * $Id$ |
|
4 * |
|
5 * Copyright (C) 2006-2008 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 and/or |
|
10 * modify it under the terms of the GNU General Public License version 2, as |
|
11 * published by the Free Software Foundation. |
|
12 * |
|
13 * The IgH EtherCAT Master is distributed in the hope that it will be useful, |
|
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
|
16 * Public License for more details. |
|
17 * |
|
18 * You should have received a copy of the GNU General Public License along |
|
19 * with the IgH EtherCAT Master; if not, write to the Free Software |
|
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
|
21 * |
|
22 * --- |
|
23 * |
|
24 * The license mentioned above concerns the source code only. Using the |
|
25 * EtherCAT technology and brand is only permitted in compliance with the |
|
26 * industrial property and similar rights of Beckhoff Automation GmbH. |
|
27 * |
|
28 *****************************************************************************/ |
|
29 |
|
30 /** \file |
|
31 * EtherCAT generic Ethernet device module. |
|
32 */ |
|
33 |
|
34 /*****************************************************************************/ |
|
35 |
|
36 #include <linux/module.h> |
|
37 #include <linux/device.h> |
|
38 #include <linux/err.h> |
|
39 #include <linux/version.h> |
|
40 #include <linux/if_arp.h> /* ARPHRD_ETHER */ |
|
41 #include <linux/etherdevice.h> |
|
42 |
|
43 #include "../globals.h" |
|
44 #include "ecdev.h" |
|
45 |
|
46 #define PFX "ec_generic: " |
|
47 |
|
48 /*****************************************************************************/ |
|
49 |
|
50 int __init ec_gen_init_module(void); |
|
51 void __exit ec_gen_cleanup_module(void); |
|
52 |
|
53 /*****************************************************************************/ |
|
54 |
|
55 /** \cond */ |
|
56 |
|
57 MODULE_AUTHOR("Florian Pose <fp@igh-essen.com>"); |
|
58 MODULE_DESCRIPTION("EtherCAT master generic Ethernet device module"); |
|
59 MODULE_LICENSE("GPL"); |
|
60 MODULE_VERSION(EC_MASTER_VERSION); |
|
61 |
|
62 /** \endcond */ |
|
63 |
|
64 struct list_head generic_devices; |
|
65 |
|
66 typedef struct { |
|
67 struct list_head list; |
|
68 struct net_device *netdev; |
|
69 #if 0 |
|
70 struct net_device *real_netdev; |
|
71 #endif |
|
72 ec_device_t *ecdev; |
|
73 } ec_gen_device_t; |
|
74 |
|
75 int ec_gen_device_open(ec_gen_device_t *); |
|
76 int ec_gen_device_stop(ec_gen_device_t *); |
|
77 int ec_gen_device_start_xmit(ec_gen_device_t *, struct sk_buff *); |
|
78 |
|
79 /*****************************************************************************/ |
|
80 |
|
81 static int ec_gen_netdev_open(struct net_device *dev) |
|
82 { |
|
83 ec_gen_device_t *gendev = *((ec_gen_device_t **) netdev_priv(dev)); |
|
84 return ec_gen_device_open(gendev); |
|
85 } |
|
86 |
|
87 /*****************************************************************************/ |
|
88 |
|
89 static int ec_gen_netdev_stop(struct net_device *dev) |
|
90 { |
|
91 ec_gen_device_t *gendev = *((ec_gen_device_t **) netdev_priv(dev)); |
|
92 return ec_gen_device_stop(gendev); |
|
93 } |
|
94 |
|
95 /*****************************************************************************/ |
|
96 |
|
97 static int ec_gen_netdev_start_xmit( |
|
98 struct sk_buff *skb, |
|
99 struct net_device *dev |
|
100 ) |
|
101 { |
|
102 ec_gen_device_t *gendev = *((ec_gen_device_t **) netdev_priv(dev)); |
|
103 return ec_gen_device_start_xmit(gendev, skb); |
|
104 } |
|
105 |
|
106 /*****************************************************************************/ |
|
107 |
|
108 void ec_gen_poll(struct net_device *dev) |
|
109 { |
|
110 } |
|
111 |
|
112 /*****************************************************************************/ |
|
113 |
|
114 static const struct net_device_ops ec_gen_netdev_ops = { |
|
115 .ndo_open = ec_gen_netdev_open, |
|
116 .ndo_stop = ec_gen_netdev_stop, |
|
117 .ndo_start_xmit = ec_gen_netdev_start_xmit, |
|
118 }; |
|
119 |
|
120 /*****************************************************************************/ |
|
121 |
|
122 /** Init generic device. |
|
123 */ |
|
124 int ec_gen_device_init( |
|
125 ec_gen_device_t *dev, |
|
126 struct net_device *real_netdev |
|
127 ) |
|
128 { |
|
129 ec_gen_device_t **priv; |
|
130 char null = 0x00; |
|
131 |
|
132 dev->ecdev = NULL; |
|
133 #if 0 |
|
134 dev->real_netdev = real_netdev; |
|
135 #endif |
|
136 |
|
137 dev->netdev = alloc_netdev(sizeof(ec_gen_device_t *), &null, ether_setup); |
|
138 if (!dev->netdev) { |
|
139 return -ENOMEM; |
|
140 } |
|
141 memcpy(dev->netdev->dev_addr, real_netdev->dev_addr, ETH_ALEN); |
|
142 dev->netdev->netdev_ops = &ec_gen_netdev_ops; |
|
143 priv = netdev_priv(dev->netdev); |
|
144 *priv = dev; |
|
145 |
|
146 return 0; |
|
147 } |
|
148 |
|
149 /*****************************************************************************/ |
|
150 |
|
151 /** Clear generic device. |
|
152 */ |
|
153 void ec_gen_device_clear( |
|
154 ec_gen_device_t *dev |
|
155 ) |
|
156 { |
|
157 if (dev->ecdev) { |
|
158 ecdev_close(dev->ecdev); |
|
159 ecdev_withdraw(dev->ecdev); |
|
160 } |
|
161 free_netdev(dev->netdev); |
|
162 } |
|
163 |
|
164 /*****************************************************************************/ |
|
165 |
|
166 /** Offer generic device to master. |
|
167 */ |
|
168 int ec_gen_device_offer( |
|
169 ec_gen_device_t *dev |
|
170 ) |
|
171 { |
|
172 int ret = 0; |
|
173 |
|
174 dev->ecdev = ecdev_offer(dev->netdev, ec_gen_poll, THIS_MODULE); |
|
175 if (dev->ecdev) { |
|
176 if (ecdev_open(dev->ecdev)) { |
|
177 ecdev_withdraw(dev->ecdev); |
|
178 dev->ecdev = NULL; |
|
179 } else { |
|
180 ret = 1; |
|
181 } |
|
182 } |
|
183 |
|
184 return ret; |
|
185 } |
|
186 |
|
187 /*****************************************************************************/ |
|
188 |
|
189 /** Open the device. |
|
190 */ |
|
191 int ec_gen_device_open( |
|
192 ec_gen_device_t *dev |
|
193 ) |
|
194 { |
|
195 int ret = 0; |
|
196 |
|
197 #if 0 |
|
198 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) |
|
199 ret = dev->real_netdev->netdev_ops->ndo_open(dev->real_netdev); |
|
200 #else |
|
201 ret = dev->real_netdev->open(dev->real_netdev); |
|
202 #endif |
|
203 #endif |
|
204 |
|
205 return ret; |
|
206 } |
|
207 |
|
208 /*****************************************************************************/ |
|
209 |
|
210 /** Stop the device. |
|
211 */ |
|
212 int ec_gen_device_stop( |
|
213 ec_gen_device_t *dev |
|
214 ) |
|
215 { |
|
216 int ret = 0; |
|
217 |
|
218 #if 0 |
|
219 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) |
|
220 ret = dev->real_netdev->netdev_ops->ndo_stop(dev->real_netdev); |
|
221 #else |
|
222 ret = dev->real_netdev->stop(dev->real_netdev); |
|
223 #endif |
|
224 #endif |
|
225 |
|
226 return ret; |
|
227 } |
|
228 |
|
229 /*****************************************************************************/ |
|
230 |
|
231 int ec_gen_device_start_xmit( |
|
232 ec_gen_device_t *dev, |
|
233 struct sk_buff *skb |
|
234 ) |
|
235 { |
|
236 return 0; |
|
237 } |
|
238 |
|
239 /*****************************************************************************/ |
|
240 |
|
241 /** Offer device. |
|
242 */ |
|
243 int offer_device( |
|
244 struct net_device *netdev |
|
245 ) |
|
246 { |
|
247 ec_gen_device_t *gendev; |
|
248 int ret = 0; |
|
249 |
|
250 gendev = kmalloc(sizeof(ec_gen_device_t), GFP_KERNEL); |
|
251 if (!gendev) { |
|
252 return -ENOMEM; |
|
253 } |
|
254 |
|
255 ret = ec_gen_device_init(gendev, netdev); |
|
256 if (ret) { |
|
257 kfree(gendev); |
|
258 return ret; |
|
259 } |
|
260 |
|
261 if (ec_gen_device_offer(gendev)) { |
|
262 list_add_tail(&gendev->list, &generic_devices); |
|
263 } else { |
|
264 ec_gen_device_clear(gendev); |
|
265 kfree(gendev); |
|
266 } |
|
267 |
|
268 return ret; |
|
269 } |
|
270 |
|
271 /*****************************************************************************/ |
|
272 |
|
273 /** Clear devices. |
|
274 */ |
|
275 void clear_devices(void) |
|
276 { |
|
277 ec_gen_device_t *gendev, *next; |
|
278 |
|
279 list_for_each_entry_safe(gendev, next, &generic_devices, list) { |
|
280 list_del(&gendev->list); |
|
281 ec_gen_device_clear(gendev); |
|
282 kfree(gendev); |
|
283 } |
|
284 } |
|
285 |
|
286 /*****************************************************************************/ |
|
287 |
|
288 /** Module initialization. |
|
289 * |
|
290 * Initializes \a master_count masters. |
|
291 * \return 0 on success, else < 0 |
|
292 */ |
|
293 int __init ec_gen_init_module(void) |
|
294 { |
|
295 int ret = 0; |
|
296 struct net_device *netdev; |
|
297 |
|
298 printk(KERN_INFO PFX "EtherCAT master generic Ethernet device module %s\n", |
|
299 EC_MASTER_VERSION); |
|
300 |
|
301 INIT_LIST_HEAD(&generic_devices); |
|
302 |
|
303 read_lock(&dev_base_lock); |
|
304 for_each_netdev(&init_net, netdev) { |
|
305 if (netdev->type != ARPHRD_ETHER) |
|
306 continue; |
|
307 ret = offer_device(netdev); |
|
308 if (ret) { |
|
309 read_unlock(&dev_base_lock); |
|
310 goto out_err; |
|
311 } |
|
312 } |
|
313 read_unlock(&dev_base_lock); |
|
314 return ret; |
|
315 |
|
316 out_err: |
|
317 clear_devices(); |
|
318 return ret; |
|
319 } |
|
320 |
|
321 /*****************************************************************************/ |
|
322 |
|
323 /** Module cleanup. |
|
324 * |
|
325 * Clears all master instances. |
|
326 */ |
|
327 void __exit ec_gen_cleanup_module(void) |
|
328 { |
|
329 clear_devices(); |
|
330 printk(KERN_INFO PFX "Unloading.\n"); |
|
331 } |
|
332 |
|
333 /*****************************************************************************/ |
|
334 |
|
335 /** \cond */ |
|
336 |
|
337 module_init(ec_gen_init_module); |
|
338 module_exit(ec_gen_cleanup_module); |
|
339 |
|
340 /** \endcond */ |
|
341 |
|
342 /*****************************************************************************/ |