fp@231: /****************************************************************************** fp@231: * fp@231: * $Id$ fp@231: * fp@1326: * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH fp@231: * fp@231: * This file is part of the IgH EtherCAT Master. fp@231: * fp@1326: * The IgH EtherCAT Master is free software; you can redistribute it and/or fp@1326: * modify it under the terms of the GNU General Public License version 2, as fp@1326: * published by the Free Software Foundation. fp@1326: * fp@1326: * The IgH EtherCAT Master is distributed in the hope that it will be useful, fp@1326: * but WITHOUT ANY WARRANTY; without even the implied warranty of fp@1326: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General fp@1326: * Public License for more details. fp@1326: * fp@1326: * You should have received a copy of the GNU General Public License along fp@1326: * with the IgH EtherCAT Master; if not, write to the Free Software fp@231: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA fp@231: * fp@1363: * --- fp@1363: * fp@1363: * The license mentioned above concerns the source code only. Using the fp@1363: * EtherCAT technology and brand is only permitted in compliance with the fp@1363: * industrial property and similar rights of Beckhoff Automation GmbH. fp@246: * fp@231: *****************************************************************************/ fp@231: fp@231: /** fp@231: \file fp@231: Ethernet interface for debugging purposes. fp@231: */ fp@231: fp@231: /*****************************************************************************/ fp@231: martin@1579: #include fp@294: #include fp@231: #include fp@231: fp@231: #include "globals.h" fp@1921: #include "master.h" fp@231: #include "debug.h" fp@231: fp@231: /*****************************************************************************/ fp@231: fp@231: // net_device functions fp@231: int ec_dbgdev_open(struct net_device *); fp@231: int ec_dbgdev_stop(struct net_device *); fp@471: int ec_dbgdev_tx(struct sk_buff *, struct net_device *); fp@231: struct net_device_stats *ec_dbgdev_stats(struct net_device *); fp@231: martin@1579: #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) fp@1907: /** Device operations for debug interfaces. fp@1907: */ martin@1579: static const struct net_device_ops ec_dbg_netdev_ops = martin@1579: { martin@1579: .ndo_open = ec_dbgdev_open, martin@1579: .ndo_stop = ec_dbgdev_stop, martin@1579: .ndo_start_xmit = ec_dbgdev_tx, martin@1579: .ndo_get_stats = ec_dbgdev_stats, martin@1579: }; martin@1579: #endif martin@1579: fp@231: /*****************************************************************************/ fp@231: fp@1305: /** Debug interface constructor. fp@1305: * fp@1305: * Initializes the debug object, creates a net_device and registeres it. fp@1313: * fp@1313: * \retval 0 Success. fp@1313: * \retval <0 Error code. fp@1305: */ fp@687: int ec_debug_init( fp@1921: ec_debug_t *dbg, /**< Debug object. */ fp@1921: ec_device_t *device, /**< EtherCAT device. */ fp@1921: const char *name /**< Interface name. */ fp@1921: ) fp@1921: { fp@1921: dbg->device = device; fp@1305: dbg->registered = 0; fp@231: dbg->opened = 0; fp@1305: fp@231: memset(&dbg->stats, 0, sizeof(struct net_device_stats)); fp@231: fp@231: if (!(dbg->dev = fp@687: alloc_netdev(sizeof(ec_debug_t *), name, ether_setup))) { fp@1921: EC_MASTER_ERR(device->master, "Unable to allocate net_device" fp@1921: " for debug object!\n"); fp@1313: return -ENODEV; fp@231: } fp@231: fp@231: // initialize net_device martin@1579: #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) martin@1579: dbg->dev->netdev_ops = &ec_dbg_netdev_ops; martin@1579: #else fp@231: dbg->dev->open = ec_dbgdev_open; fp@231: dbg->dev->stop = ec_dbgdev_stop; fp@471: dbg->dev->hard_start_xmit = ec_dbgdev_tx; fp@231: dbg->dev->get_stats = ec_dbgdev_stats; martin@1579: #endif fp@231: fp@231: // initialize private data fp@231: *((ec_debug_t **) netdev_priv(dbg->dev)) = dbg; fp@231: fp@1305: return 0; fp@1305: } fp@1305: fp@1305: /*****************************************************************************/ fp@1305: fp@1305: /** Debug interface destructor. fp@1305: * fp@1305: * Unregisters the net_device and frees allocated memory. fp@1305: */ fp@1305: void ec_debug_clear( fp@1305: ec_debug_t *dbg /**< debug object */ fp@1305: ) fp@1305: { fp@1305: ec_debug_unregister(dbg); fp@1305: free_netdev(dbg->dev); fp@1305: } fp@1305: fp@1305: /*****************************************************************************/ fp@1305: fp@1305: /** Register debug interface. fp@1305: */ fp@1305: void ec_debug_register( fp@1305: ec_debug_t *dbg, /**< debug object */ fp@1305: const struct net_device *net_dev /**< 'Real' Ethernet device. */ fp@1305: ) fp@1305: { fp@1305: int result; fp@1305: fp@1305: ec_debug_unregister(dbg); fp@1305: fp@1305: // use the Ethernet address of the physical device for the debug device fp@1305: memcpy(dbg->dev->dev_addr, net_dev->dev_addr, ETH_ALEN); fp@1305: fp@231: // connect the net_device to the kernel fp@231: if ((result = register_netdev(dbg->dev))) { fp@1921: EC_MASTER_WARN(dbg->device->master, "Unable to register net_device:" fp@1921: " error %i\n", result); fp@1305: } else { fp@1305: dbg->registered = 1; fp@1305: } fp@1305: } fp@1305: fp@1305: /*****************************************************************************/ fp@1305: fp@1305: /** Unregister debug interface. fp@1305: */ fp@1305: void ec_debug_unregister( fp@1305: ec_debug_t *dbg /**< debug object */ fp@1305: ) fp@1305: { fp@1305: if (dbg->registered) { fp@1305: dbg->opened = 0; fp@1305: dbg->registered = 0; fp@231: unregister_netdev(dbg->dev); fp@1305: } fp@1305: } fp@1305: fp@1305: /*****************************************************************************/ fp@1305: fp@1305: /** Sends frame data to the interface. fp@1305: */ fp@1305: void ec_debug_send( fp@1305: ec_debug_t *dbg, /**< debug object */ fp@1305: const uint8_t *data, /**< frame data */ fp@1305: size_t size /**< size of the frame data */ fp@1305: ) fp@231: { fp@231: struct sk_buff *skb; fp@231: fp@1305: if (!dbg->opened) fp@1305: return; fp@231: fp@231: // allocate socket buffer fp@231: if (!(skb = dev_alloc_skb(size))) { fp@231: dbg->stats.rx_dropped++; fp@231: return; fp@231: } fp@231: fp@231: // copy frame contents into socket buffer fp@231: memcpy(skb_put(skb, size), data, size); fp@231: fp@231: // update device statistics fp@231: dbg->stats.rx_packets++; fp@231: dbg->stats.rx_bytes += size; fp@231: fp@231: // pass socket buffer to network stack fp@231: skb->dev = dbg->dev; fp@231: skb->protocol = eth_type_trans(skb, dbg->dev); fp@231: skb->ip_summed = CHECKSUM_UNNECESSARY; fp@231: netif_rx(skb); fp@231: } fp@231: fp@231: /****************************************************************************** fp@231: * NET_DEVICE functions fp@231: *****************************************************************************/ fp@231: fp@1305: /** Opens the virtual network device. fp@2522: * fp@2522: * \return Always zero (success). fp@1305: */ fp@1305: int ec_dbgdev_open( fp@1305: struct net_device *dev /**< debug net_device */ fp@1305: ) fp@231: { fp@231: ec_debug_t *dbg = *((ec_debug_t **) netdev_priv(dev)); fp@231: dbg->opened = 1; fp@1921: EC_MASTER_INFO(dbg->device->master, "Debug interface %s opened.\n", fp@1921: dev->name); fp@231: return 0; fp@231: } fp@231: fp@231: /*****************************************************************************/ fp@231: fp@1305: /** Stops the virtual network device. fp@2522: * fp@2522: * \return Always zero (success). fp@1305: */ fp@1305: int ec_dbgdev_stop( fp@1305: struct net_device *dev /**< debug net_device */ fp@1305: ) fp@231: { fp@231: ec_debug_t *dbg = *((ec_debug_t **) netdev_priv(dev)); fp@231: dbg->opened = 0; fp@1921: EC_MASTER_INFO(dbg->device->master, "Debug interface %s stopped.\n", fp@1921: dev->name); fp@231: return 0; fp@231: } fp@231: fp@231: /*****************************************************************************/ fp@231: fp@1305: /** Transmits data via the virtual network device. fp@2522: * fp@2522: * \return Always zero (success). fp@1305: */ fp@1305: int ec_dbgdev_tx( fp@1305: struct sk_buff *skb, /**< transmit socket buffer */ fp@1305: struct net_device *dev /**< EoE net_device */ fp@1305: ) fp@471: { fp@471: ec_debug_t *dbg = *((ec_debug_t **) netdev_priv(dev)); fp@471: fp@471: dev_kfree_skb(skb); fp@471: dbg->stats.tx_dropped++; fp@471: return 0; fp@471: } fp@471: fp@471: /*****************************************************************************/ fp@471: fp@1305: /** Gets statistics about the virtual network device. fp@2522: * fp@2522: * \return Statistics. fp@1305: */ fp@1305: struct net_device_stats *ec_dbgdev_stats( fp@1305: struct net_device *dev /**< debug net_device */ fp@1305: ) fp@231: { fp@231: ec_debug_t *dbg = *((ec_debug_t **) netdev_priv(dev)); fp@231: return &dbg->stats; fp@231: } fp@231: fp@231: /*****************************************************************************/