Basic generic Ethernet device module.
authorFlorian Pose <fp@igh-essen.com>
Tue, 13 Oct 2009 17:56:32 +0200
changeset 1540 49430a3fe73d
parent 1539 f16c834600d4
child 1541 26ac1c611100
Basic generic Ethernet device module.
configure.ac
devices/Kbuild.in
devices/Makefile.am
devices/generic.c
--- a/configure.ac	Tue Oct 13 16:52:56 2009 +0200
+++ b/configure.ac	Tue Oct 13 17:56:32 2009 +0200
@@ -102,6 +102,29 @@
 AC_MSG_RESULT([$LINUX_SOURCE_DIR (Kernel $LINUX_KERNEL_RELEASE)])
 
 #------------------------------------------------------------------------------
+# Generic Ethernet driver
+#------------------------------------------------------------------------------
+
+AC_ARG_ENABLE([generic],
+    AS_HELP_STRING([--enable-generic],
+                   [Enable generic Ethernet driver]),
+    [
+        case "${enableval}" in
+            yes) enablegeneric=1
+                ;;
+            no) enablegeneric=0
+                ;;
+            *) AC_MSG_ERROR([Invalid value for --enable-generic])
+                ;;
+        esac
+    ],
+    [enablegeneric=0]
+)
+
+AM_CONDITIONAL(ENABLE_GENERIC, test "x$enablegeneric" = "x1")
+AC_SUBST(ENABLE_GENERIC,[$enablegeneric])
+
+#------------------------------------------------------------------------------
 # 8139too driver
 #------------------------------------------------------------------------------
 
--- a/devices/Kbuild.in	Tue Oct 13 16:52:56 2009 +0200
+++ b/devices/Kbuild.in	Tue Oct 13 17:56:32 2009 +0200
@@ -37,6 +37,13 @@
 		hg id -i $(src)/.. 2>/dev/null || echo "unknown"; \
 	fi)
 
+ifeq (@ENABLE_GENERIC@,1)
+	EC_GENERIC_OBJ := generic.o
+	obj-m += ec_generic.o
+	ec_generic-objs := $(EC_GENERIC_OBJ)
+	CFLAGS_$(EC_GENERIC_OBJ) = -DREV=$(REV)
+endif
+
 ifeq (@ENABLE_8139TOO@,1)
 	EC_8139TOO_OBJ := 8139too-@KERNEL_8139TOO@-ethercat.o
 	obj-m += ec_8139too.o
--- a/devices/Makefile.am	Tue Oct 13 16:52:56 2009 +0200
+++ b/devices/Makefile.am	Tue Oct 13 17:56:32 2009 +0200
@@ -68,6 +68,7 @@
 	e100-2.6.29-ethercat.c \
 	e100-2.6.29-orig.c \
 	ecdev.h \
+	generic.c \
 	r8169-2.6.24-ethercat.c \
 	r8169-2.6.24-orig.c \
 	r8169-2.6.28-ethercat.c \
@@ -86,6 +87,9 @@
 
 modules_install:
 	mkdir -p $(DESTDIR)$(LINUX_MOD_PATH)
+if ENABLE_GENERIC
+	cp $(srcdir)/ec_generic.ko $(DESTDIR)$(LINUX_MOD_PATH)
+endif
 if ENABLE_8139TOO
 	cp $(srcdir)/ec_8139too.ko $(DESTDIR)$(LINUX_MOD_PATH)
 endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/devices/generic.c	Tue Oct 13 17:56:32 2009 +0200
@@ -0,0 +1,342 @@
+/******************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006-2008  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License version 2, as
+ *  published by the Free Software Foundation.
+ *
+ *  The IgH EtherCAT Master is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+ *  Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  ---
+ *
+ *  The license mentioned above concerns the source code only. Using the
+ *  EtherCAT technology and brand is only permitted in compliance with the
+ *  industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ *****************************************************************************/
+
+/** \file
+ * EtherCAT generic Ethernet device module.
+ */
+
+/*****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/version.h>
+#include <linux/if_arp.h> /* ARPHRD_ETHER */
+#include <linux/etherdevice.h>
+
+#include "../globals.h"
+#include "ecdev.h"
+
+#define PFX "ec_generic: "
+
+/*****************************************************************************/
+
+int __init ec_gen_init_module(void);
+void __exit ec_gen_cleanup_module(void);
+
+/*****************************************************************************/
+
+/** \cond */
+
+MODULE_AUTHOR("Florian Pose <fp@igh-essen.com>");
+MODULE_DESCRIPTION("EtherCAT master generic Ethernet device module");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(EC_MASTER_VERSION);
+
+/** \endcond */
+
+struct list_head generic_devices;
+
+typedef struct {
+    struct list_head list;
+    struct net_device *netdev;
+#if 0
+    struct net_device *real_netdev;
+#endif
+    ec_device_t *ecdev;
+} ec_gen_device_t;
+
+int ec_gen_device_open(ec_gen_device_t *);
+int ec_gen_device_stop(ec_gen_device_t *);
+int ec_gen_device_start_xmit(ec_gen_device_t *, struct sk_buff *);
+
+/*****************************************************************************/
+
+static int ec_gen_netdev_open(struct net_device *dev)
+{
+    ec_gen_device_t *gendev = *((ec_gen_device_t **) netdev_priv(dev));
+    return ec_gen_device_open(gendev);
+}
+
+/*****************************************************************************/
+
+static int ec_gen_netdev_stop(struct net_device *dev)
+{
+    ec_gen_device_t *gendev = *((ec_gen_device_t **) netdev_priv(dev));
+    return ec_gen_device_stop(gendev);
+}
+
+/*****************************************************************************/
+
+static int ec_gen_netdev_start_xmit(
+        struct sk_buff *skb,
+        struct net_device *dev
+        )
+{
+    ec_gen_device_t *gendev = *((ec_gen_device_t **) netdev_priv(dev));
+    return ec_gen_device_start_xmit(gendev, skb);
+}
+
+/*****************************************************************************/
+
+void ec_gen_poll(struct net_device *dev)
+{
+}
+
+/*****************************************************************************/
+
+static const struct net_device_ops ec_gen_netdev_ops = {
+	.ndo_open		= ec_gen_netdev_open,
+	.ndo_stop		= ec_gen_netdev_stop,
+	.ndo_start_xmit	= ec_gen_netdev_start_xmit,
+};
+
+/*****************************************************************************/
+
+/** Init generic device.
+ */
+int ec_gen_device_init(
+        ec_gen_device_t *dev,
+        struct net_device *real_netdev
+        )
+{
+    ec_gen_device_t **priv;
+    char null = 0x00;
+
+    dev->ecdev = NULL;
+#if 0
+    dev->real_netdev = real_netdev;
+#endif
+
+	dev->netdev = alloc_netdev(sizeof(ec_gen_device_t *), &null, ether_setup);
+	if (!dev->netdev) {
+		return -ENOMEM;
+	}
+    memcpy(dev->netdev->dev_addr, real_netdev->dev_addr, ETH_ALEN);
+    dev->netdev->netdev_ops = &ec_gen_netdev_ops;
+    priv = netdev_priv(dev->netdev);
+    *priv = dev;
+
+    return 0;
+}
+
+/*****************************************************************************/
+
+/** Clear generic device.
+ */
+void ec_gen_device_clear(
+        ec_gen_device_t *dev
+        )
+{
+    if (dev->ecdev) {
+        ecdev_close(dev->ecdev);
+        ecdev_withdraw(dev->ecdev);
+    }
+    free_netdev(dev->netdev);
+}
+
+/*****************************************************************************/
+
+/** Offer generic device to master.
+ */
+int ec_gen_device_offer(
+        ec_gen_device_t *dev
+        )
+{
+    int ret = 0;
+
+	dev->ecdev = ecdev_offer(dev->netdev, ec_gen_poll, THIS_MODULE);
+    if (dev->ecdev) {
+        if (ecdev_open(dev->ecdev)) {
+            ecdev_withdraw(dev->ecdev);
+            dev->ecdev = NULL;
+        } else {
+            ret = 1;
+        }
+    }
+
+    return ret;
+}
+
+/*****************************************************************************/
+
+/** Open the device.
+ */
+int ec_gen_device_open(
+        ec_gen_device_t *dev
+        )
+{
+    int ret = 0;
+
+#if 0
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
+    ret = dev->real_netdev->netdev_ops->ndo_open(dev->real_netdev);
+#else
+    ret = dev->real_netdev->open(dev->real_netdev);
+#endif
+#endif
+
+    return ret;
+}
+
+/*****************************************************************************/
+
+/** Stop the device.
+ */
+int ec_gen_device_stop(
+        ec_gen_device_t *dev
+        )
+{
+    int ret = 0;
+
+#if 0
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
+    ret = dev->real_netdev->netdev_ops->ndo_stop(dev->real_netdev);
+#else
+    ret = dev->real_netdev->stop(dev->real_netdev);
+#endif
+#endif
+
+    return ret;
+}
+
+/*****************************************************************************/
+
+int ec_gen_device_start_xmit(
+        ec_gen_device_t *dev,
+        struct sk_buff *skb
+        )
+{
+    return 0;
+}
+
+/*****************************************************************************/
+
+/** Offer device.
+ */
+int offer_device(
+        struct net_device *netdev
+        )
+{
+    ec_gen_device_t *gendev;
+    int ret = 0;
+
+    gendev = kmalloc(sizeof(ec_gen_device_t), GFP_KERNEL);
+    if (!gendev) {
+        return -ENOMEM;
+    }
+
+    ret = ec_gen_device_init(gendev, netdev);
+    if (ret) {
+        kfree(gendev);
+        return ret;
+    }
+
+    if (ec_gen_device_offer(gendev)) {
+        list_add_tail(&gendev->list, &generic_devices);
+    } else {
+        ec_gen_device_clear(gendev);
+        kfree(gendev);
+    }
+
+    return ret;
+}
+
+/*****************************************************************************/
+
+/** Clear devices.
+ */
+void clear_devices(void)
+{
+    ec_gen_device_t *gendev, *next;
+
+    list_for_each_entry_safe(gendev, next, &generic_devices, list) {
+        list_del(&gendev->list);
+        ec_gen_device_clear(gendev);
+        kfree(gendev);
+    }
+}
+
+/*****************************************************************************/
+
+/** Module initialization.
+ *
+ * Initializes \a master_count masters.
+ * \return 0 on success, else < 0
+ */
+int __init ec_gen_init_module(void)
+{
+    int ret = 0;
+    struct net_device *netdev;
+
+    printk(KERN_INFO PFX "EtherCAT master generic Ethernet device module %s\n",
+            EC_MASTER_VERSION);
+
+    INIT_LIST_HEAD(&generic_devices);
+
+    read_lock(&dev_base_lock);
+    for_each_netdev(&init_net, netdev) {
+        if (netdev->type != ARPHRD_ETHER)
+            continue;
+        ret = offer_device(netdev);
+        if (ret) {
+            read_unlock(&dev_base_lock);
+            goto out_err;
+        }
+    }
+    read_unlock(&dev_base_lock);
+    return ret;
+
+out_err:
+    clear_devices();
+    return ret;
+}
+
+/*****************************************************************************/
+
+/** Module cleanup.
+ *
+ * Clears all master instances.
+ */
+void __exit ec_gen_cleanup_module(void)
+{
+    clear_devices();
+    printk(KERN_INFO PFX "Unloading.\n");
+}
+
+/*****************************************************************************/
+
+/** \cond */
+
+module_init(ec_gen_init_module);
+module_exit(ec_gen_cleanup_module);
+
+/** \endcond */
+
+/*****************************************************************************/