diff -r f16c834600d4 -r 49430a3fe73d devices/generic.c --- /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 +#include +#include +#include +#include /* ARPHRD_ETHER */ +#include + +#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 "); +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 */ + +/*****************************************************************************/