fp@1540: /****************************************************************************** fp@1540: * fp@1540: * $Id$ fp@1540: * fp@1540: * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH fp@1540: * fp@1540: * This file is part of the IgH EtherCAT Master. fp@1540: * fp@1540: * The IgH EtherCAT Master is free software; you can redistribute it and/or fp@1540: * modify it under the terms of the GNU General Public License version 2, as fp@1540: * published by the Free Software Foundation. fp@1540: * fp@1540: * The IgH EtherCAT Master is distributed in the hope that it will be useful, fp@1540: * but WITHOUT ANY WARRANTY; without even the implied warranty of fp@1540: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General fp@1540: * Public License for more details. fp@1540: * fp@1540: * You should have received a copy of the GNU General Public License along fp@1540: * with the IgH EtherCAT Master; if not, write to the Free Software fp@1540: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA fp@1540: * fp@1540: * --- fp@1540: * fp@1540: * The license mentioned above concerns the source code only. Using the fp@1540: * EtherCAT technology and brand is only permitted in compliance with the fp@1540: * industrial property and similar rights of Beckhoff Automation GmbH. fp@1540: * fp@1540: *****************************************************************************/ fp@1540: fp@1540: /** \file fp@1540: * EtherCAT generic Ethernet device module. fp@1540: */ fp@1540: fp@1540: /*****************************************************************************/ fp@1540: fp@1540: #include fp@1540: #include fp@1540: #include fp@1540: #include fp@1540: #include /* ARPHRD_ETHER */ fp@1540: #include fp@1540: fp@1540: #include "../globals.h" fp@1540: #include "ecdev.h" fp@1540: fp@1540: #define PFX "ec_generic: " fp@1540: fp@1540: /*****************************************************************************/ fp@1540: fp@1540: int __init ec_gen_init_module(void); fp@1540: void __exit ec_gen_cleanup_module(void); fp@1540: fp@1540: /*****************************************************************************/ fp@1540: fp@1540: /** \cond */ fp@1540: fp@1540: MODULE_AUTHOR("Florian Pose "); fp@1540: MODULE_DESCRIPTION("EtherCAT master generic Ethernet device module"); fp@1540: MODULE_LICENSE("GPL"); fp@1540: MODULE_VERSION(EC_MASTER_VERSION); fp@1540: fp@1540: /** \endcond */ fp@1540: fp@1540: struct list_head generic_devices; fp@1540: fp@1540: typedef struct { fp@1540: struct list_head list; fp@1540: struct net_device *netdev; fp@1540: #if 0 fp@1540: struct net_device *real_netdev; fp@1540: #endif fp@1540: ec_device_t *ecdev; fp@1540: } ec_gen_device_t; fp@1540: fp@1540: int ec_gen_device_open(ec_gen_device_t *); fp@1540: int ec_gen_device_stop(ec_gen_device_t *); fp@1540: int ec_gen_device_start_xmit(ec_gen_device_t *, struct sk_buff *); fp@1540: fp@1540: /*****************************************************************************/ fp@1540: fp@1540: static int ec_gen_netdev_open(struct net_device *dev) fp@1540: { fp@1540: ec_gen_device_t *gendev = *((ec_gen_device_t **) netdev_priv(dev)); fp@1540: return ec_gen_device_open(gendev); fp@1540: } fp@1540: fp@1540: /*****************************************************************************/ fp@1540: fp@1540: static int ec_gen_netdev_stop(struct net_device *dev) fp@1540: { fp@1540: ec_gen_device_t *gendev = *((ec_gen_device_t **) netdev_priv(dev)); fp@1540: return ec_gen_device_stop(gendev); fp@1540: } fp@1540: fp@1540: /*****************************************************************************/ fp@1540: fp@1540: static int ec_gen_netdev_start_xmit( fp@1540: struct sk_buff *skb, fp@1540: struct net_device *dev fp@1540: ) fp@1540: { fp@1540: ec_gen_device_t *gendev = *((ec_gen_device_t **) netdev_priv(dev)); fp@1540: return ec_gen_device_start_xmit(gendev, skb); fp@1540: } fp@1540: fp@1540: /*****************************************************************************/ fp@1540: fp@1540: void ec_gen_poll(struct net_device *dev) fp@1540: { fp@1540: } fp@1540: fp@1540: /*****************************************************************************/ fp@1540: fp@1540: static const struct net_device_ops ec_gen_netdev_ops = { fp@1540: .ndo_open = ec_gen_netdev_open, fp@1540: .ndo_stop = ec_gen_netdev_stop, fp@1540: .ndo_start_xmit = ec_gen_netdev_start_xmit, fp@1540: }; fp@1540: fp@1540: /*****************************************************************************/ fp@1540: fp@1540: /** Init generic device. fp@1540: */ fp@1540: int ec_gen_device_init( fp@1540: ec_gen_device_t *dev, fp@1540: struct net_device *real_netdev fp@1540: ) fp@1540: { fp@1540: ec_gen_device_t **priv; fp@1540: char null = 0x00; fp@1540: fp@1540: dev->ecdev = NULL; fp@1540: #if 0 fp@1540: dev->real_netdev = real_netdev; fp@1540: #endif fp@1540: fp@1540: dev->netdev = alloc_netdev(sizeof(ec_gen_device_t *), &null, ether_setup); fp@1540: if (!dev->netdev) { fp@1540: return -ENOMEM; fp@1540: } fp@1540: memcpy(dev->netdev->dev_addr, real_netdev->dev_addr, ETH_ALEN); fp@1540: dev->netdev->netdev_ops = &ec_gen_netdev_ops; fp@1540: priv = netdev_priv(dev->netdev); fp@1540: *priv = dev; fp@1540: fp@1540: return 0; fp@1540: } fp@1540: fp@1540: /*****************************************************************************/ fp@1540: fp@1540: /** Clear generic device. fp@1540: */ fp@1540: void ec_gen_device_clear( fp@1540: ec_gen_device_t *dev fp@1540: ) fp@1540: { fp@1540: if (dev->ecdev) { fp@1540: ecdev_close(dev->ecdev); fp@1540: ecdev_withdraw(dev->ecdev); fp@1540: } fp@1540: free_netdev(dev->netdev); fp@1540: } fp@1540: fp@1540: /*****************************************************************************/ fp@1540: fp@1540: /** Offer generic device to master. fp@1540: */ fp@1540: int ec_gen_device_offer( fp@1540: ec_gen_device_t *dev fp@1540: ) fp@1540: { fp@1540: int ret = 0; fp@1540: fp@1540: dev->ecdev = ecdev_offer(dev->netdev, ec_gen_poll, THIS_MODULE); fp@1540: if (dev->ecdev) { fp@1540: if (ecdev_open(dev->ecdev)) { fp@1540: ecdev_withdraw(dev->ecdev); fp@1540: dev->ecdev = NULL; fp@1540: } else { fp@1540: ret = 1; fp@1540: } fp@1540: } fp@1540: fp@1540: return ret; fp@1540: } fp@1540: fp@1540: /*****************************************************************************/ fp@1540: fp@1540: /** Open the device. fp@1540: */ fp@1540: int ec_gen_device_open( fp@1540: ec_gen_device_t *dev fp@1540: ) fp@1540: { fp@1540: int ret = 0; fp@1540: fp@1540: #if 0 fp@1540: #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) fp@1540: ret = dev->real_netdev->netdev_ops->ndo_open(dev->real_netdev); fp@1540: #else fp@1540: ret = dev->real_netdev->open(dev->real_netdev); fp@1540: #endif fp@1540: #endif fp@1540: fp@1540: return ret; fp@1540: } fp@1540: fp@1540: /*****************************************************************************/ fp@1540: fp@1540: /** Stop the device. fp@1540: */ fp@1540: int ec_gen_device_stop( fp@1540: ec_gen_device_t *dev fp@1540: ) fp@1540: { fp@1540: int ret = 0; fp@1540: fp@1540: #if 0 fp@1540: #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) fp@1540: ret = dev->real_netdev->netdev_ops->ndo_stop(dev->real_netdev); fp@1540: #else fp@1540: ret = dev->real_netdev->stop(dev->real_netdev); fp@1540: #endif fp@1540: #endif fp@1540: fp@1540: return ret; fp@1540: } fp@1540: fp@1540: /*****************************************************************************/ fp@1540: fp@1540: int ec_gen_device_start_xmit( fp@1540: ec_gen_device_t *dev, fp@1540: struct sk_buff *skb fp@1540: ) fp@1540: { fp@1540: return 0; fp@1540: } fp@1540: fp@1540: /*****************************************************************************/ fp@1540: fp@1540: /** Offer device. fp@1540: */ fp@1540: int offer_device( fp@1540: struct net_device *netdev fp@1540: ) fp@1540: { fp@1540: ec_gen_device_t *gendev; fp@1540: int ret = 0; fp@1540: fp@1540: gendev = kmalloc(sizeof(ec_gen_device_t), GFP_KERNEL); fp@1540: if (!gendev) { fp@1540: return -ENOMEM; fp@1540: } fp@1540: fp@1540: ret = ec_gen_device_init(gendev, netdev); fp@1540: if (ret) { fp@1540: kfree(gendev); fp@1540: return ret; fp@1540: } fp@1540: fp@1540: if (ec_gen_device_offer(gendev)) { fp@1540: list_add_tail(&gendev->list, &generic_devices); fp@1540: } else { fp@1540: ec_gen_device_clear(gendev); fp@1540: kfree(gendev); fp@1540: } fp@1540: fp@1540: return ret; fp@1540: } fp@1540: fp@1540: /*****************************************************************************/ fp@1540: fp@1540: /** Clear devices. fp@1540: */ fp@1540: void clear_devices(void) fp@1540: { fp@1540: ec_gen_device_t *gendev, *next; fp@1540: fp@1540: list_for_each_entry_safe(gendev, next, &generic_devices, list) { fp@1540: list_del(&gendev->list); fp@1540: ec_gen_device_clear(gendev); fp@1540: kfree(gendev); fp@1540: } fp@1540: } fp@1540: fp@1540: /*****************************************************************************/ fp@1540: fp@1540: /** Module initialization. fp@1540: * fp@1540: * Initializes \a master_count masters. fp@1540: * \return 0 on success, else < 0 fp@1540: */ fp@1540: int __init ec_gen_init_module(void) fp@1540: { fp@1540: int ret = 0; fp@1540: struct net_device *netdev; fp@1540: fp@1540: printk(KERN_INFO PFX "EtherCAT master generic Ethernet device module %s\n", fp@1540: EC_MASTER_VERSION); fp@1540: fp@1540: INIT_LIST_HEAD(&generic_devices); fp@1540: fp@1540: read_lock(&dev_base_lock); fp@1540: for_each_netdev(&init_net, netdev) { fp@1540: if (netdev->type != ARPHRD_ETHER) fp@1540: continue; fp@1540: ret = offer_device(netdev); fp@1540: if (ret) { fp@1540: read_unlock(&dev_base_lock); fp@1540: goto out_err; fp@1540: } fp@1540: } fp@1540: read_unlock(&dev_base_lock); fp@1540: return ret; fp@1540: fp@1540: out_err: fp@1540: clear_devices(); fp@1540: return ret; fp@1540: } fp@1540: fp@1540: /*****************************************************************************/ fp@1540: fp@1540: /** Module cleanup. fp@1540: * fp@1540: * Clears all master instances. fp@1540: */ fp@1540: void __exit ec_gen_cleanup_module(void) fp@1540: { fp@1540: clear_devices(); fp@1540: printk(KERN_INFO PFX "Unloading.\n"); fp@1540: } fp@1540: fp@1540: /*****************************************************************************/ fp@1540: fp@1540: /** \cond */ fp@1540: fp@1540: module_init(ec_gen_init_module); fp@1540: module_exit(ec_gen_cleanup_module); fp@1540: fp@1540: /** \endcond */ fp@1540: fp@1540: /*****************************************************************************/