fp@145: /****************************************************************************** fp@145: * fp@145: * $Id$ fp@145: * fp@197: * Copyright (C) 2006 Florian Pose, Ingenieurgemeinschaft IgH fp@197: * fp@197: * This file is part of the IgH EtherCAT Master. fp@197: * fp@197: * The IgH EtherCAT Master is free software; you can redistribute it fp@197: * and/or modify it under the terms of the GNU General Public License fp@197: * as published by the Free Software Foundation; version 2 of the License. fp@197: * fp@197: * The IgH EtherCAT Master is distributed in the hope that it will be fp@197: * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of fp@197: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the fp@197: * GNU General Public License for more details. fp@197: * fp@197: * You should have received a copy of the GNU General Public License fp@197: * along with the IgH EtherCAT Master; if not, write to the Free Software fp@197: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA fp@197: * fp@145: *****************************************************************************/ fp@145: fp@199: /** fp@199: \file fp@199: Ethernet-over-EtherCAT (EoE). fp@199: */ fp@199: fp@199: /*****************************************************************************/ fp@199: fp@210: #include fp@210: fp@145: #include "../include/ecrt.h" fp@145: #include "globals.h" fp@145: #include "master.h" fp@145: #include "slave.h" fp@145: #include "mailbox.h" fp@145: #include "ethernet.h" fp@145: fp@145: /*****************************************************************************/ fp@145: fp@197: /** fp@203: Contains the private data of an EoE net_device. fp@203: */ fp@203: fp@203: typedef struct fp@203: { fp@203: struct net_device_stats stats; /**< device statistics */ fp@203: ec_eoe_t *eoe; /**< pointer to parent eoe object */ fp@203: } fp@203: ec_eoedev_priv_t; fp@203: fp@203: /*****************************************************************************/ fp@203: fp@203: void ec_eoedev_init(struct net_device *); fp@203: int ec_eoedev_open(struct net_device *); fp@203: int ec_eoedev_stop(struct net_device *); fp@203: int ec_eoedev_tx(struct sk_buff *, struct net_device *); fp@203: struct net_device_stats *ec_eoedev_stats(struct net_device *); fp@210: void ec_eoedev_rx(struct net_device *, const uint8_t *, size_t); fp@203: fp@203: /*****************************************************************************/ fp@203: fp@203: /** fp@199: EoE constructor. fp@197: */ fp@197: fp@203: int ec_eoe_init(ec_eoe_t *eoe, ec_slave_t *slave) fp@203: { fp@203: ec_eoedev_priv_t *priv; fp@203: int result; fp@203: fp@145: eoe->slave = slave; fp@145: eoe->rx_state = EC_EOE_IDLE; fp@210: eoe->opened = 0; fp@203: fp@203: if (!(eoe->dev = fp@203: alloc_netdev(sizeof(ec_eoedev_priv_t), "eoe%d", ec_eoedev_init))) { fp@203: EC_ERR("Unable to allocate net_device for EoE object!\n"); fp@203: goto out_return; fp@203: } fp@203: fp@203: // set EoE object reference fp@203: priv = netdev_priv(eoe->dev); fp@203: priv->eoe = eoe; fp@203: fp@203: // connect the net_device to the kernel fp@203: if ((result = register_netdev(eoe->dev))) { fp@203: EC_ERR("Unable to register net_device: error %i\n", result); fp@203: goto out_free; fp@203: } fp@203: fp@203: return 0; fp@203: fp@203: out_free: fp@203: free_netdev(eoe->dev); fp@203: eoe->dev = NULL; fp@203: out_return: fp@203: return -1; fp@145: } fp@145: fp@145: /*****************************************************************************/ fp@145: fp@197: /** fp@199: EoE destructor. fp@197: */ fp@197: fp@145: void ec_eoe_clear(ec_eoe_t *eoe) fp@145: { fp@203: if (eoe->dev) { fp@203: unregister_netdev(eoe->dev); fp@203: free_netdev(eoe->dev); fp@203: } fp@145: } fp@145: fp@145: /*****************************************************************************/ fp@145: fp@197: /** fp@199: Runs the EoE state machine. fp@197: */ fp@197: fp@145: void ec_eoe_run(ec_eoe_t *eoe) fp@145: { fp@145: uint8_t *data; fp@145: ec_master_t *master; fp@145: size_t rec_size; fp@210: uint8_t fragment_number, frame_number, last_fragment, time_appended; fp@210: uint8_t fragment_offset, frame_type; fp@210: fp@210: if (!eoe->opened) return; fp@145: fp@145: master = eoe->slave->master; fp@145: fp@145: if (eoe->rx_state == EC_EOE_IDLE) { fp@145: ec_slave_mbox_prepare_check(eoe->slave); fp@145: ec_master_queue_command(master, &eoe->slave->mbox_command); fp@145: eoe->rx_state = EC_EOE_CHECKING; fp@145: return; fp@145: } fp@145: fp@145: if (eoe->rx_state == EC_EOE_CHECKING) { fp@145: if (eoe->slave->mbox_command.state != EC_CMD_RECEIVED) { fp@145: master->stats.eoe_errors++; fp@145: eoe->rx_state = EC_EOE_IDLE; fp@145: return; fp@145: } fp@145: if (!ec_slave_mbox_check(eoe->slave)) { fp@145: eoe->rx_state = EC_EOE_IDLE; fp@145: return; fp@145: } fp@145: ec_slave_mbox_prepare_fetch(eoe->slave); fp@145: ec_master_queue_command(master, &eoe->slave->mbox_command); fp@145: eoe->rx_state = EC_EOE_FETCHING; fp@145: return; fp@145: } fp@145: fp@145: if (eoe->rx_state == EC_EOE_FETCHING) { fp@145: if (eoe->slave->mbox_command.state != EC_CMD_RECEIVED) { fp@145: master->stats.eoe_errors++; fp@145: eoe->rx_state = EC_EOE_IDLE; fp@145: return; fp@145: } fp@145: if (!(data = ec_slave_mbox_fetch(eoe->slave, 0x02, &rec_size))) { fp@145: master->stats.eoe_errors++; fp@145: eoe->rx_state = EC_EOE_IDLE; fp@145: return; fp@145: } fp@146: fp@210: frame_type = EC_READ_U16(data) & 0x000F; fp@210: fp@210: if (frame_type == 0x00) { // EoE Fragment Request fp@210: last_fragment = (EC_READ_U16(data) >> 8) & 0x0001; fp@210: time_appended = (EC_READ_U16(data) >> 9) & 0x0001; fp@210: fragment_number = EC_READ_U16(data + 2) & 0x003F; fp@210: fragment_offset = (EC_READ_U16(data + 2) >> 6) & 0x003F; fp@210: frame_number = (EC_READ_U16(data + 2) >> 12) & 0x000F; fp@210: fp@210: #if 0 fp@210: EC_DBG("EOE fragment req received, fragment: %i, offset: %i," fp@210: " frame %i%s%s, %i bytes\n", fragment_number, fp@210: fragment_offset, frame_number, fp@210: last_fragment ? ", last fragment" : "", fp@210: time_appended ? ", + timestamp" : "", fp@210: time_appended ? rec_size - 8 : rec_size - 4); fp@210: fp@210: #if 0 fp@210: EC_DBG(""); fp@210: for (i = 0; i < rec_size - 4; i++) { fp@210: printk("%02X ", data[i + 4]); fp@210: if ((i + 1) % 16 == 0) { fp@210: printk("\n"); fp@210: EC_DBG(""); fp@210: } fp@146: } fp@210: printk("\n"); fp@210: #endif fp@210: #endif fp@210: fp@210: ec_eoedev_rx(eoe->dev, data + 4, fp@210: time_appended ? rec_size - 8 : rec_size - 4); fp@210: } fp@210: else { fp@210: #if 1 fp@210: EC_DBG("other frame received.\n"); fp@210: #endif fp@210: } fp@146: fp@145: eoe->rx_state = EC_EOE_IDLE; fp@145: return; fp@145: } fp@145: } fp@145: fp@145: /*****************************************************************************/ fp@145: fp@197: /** fp@199: Prints EoE object information. fp@197: */ fp@197: fp@145: void ec_eoe_print(const ec_eoe_t *eoe) fp@145: { fp@145: EC_INFO(" EoE slave %i\n", eoe->slave->ring_position); fp@145: EC_INFO(" RX State %i\n", eoe->rx_state); fp@210: EC_INFO(" Assigned device: %s (%s)\n", eoe->dev->name, fp@210: eoe->opened ? "opened" : "closed"); fp@145: } fp@145: fp@145: /*****************************************************************************/ fp@203: fp@203: /** fp@203: Initializes a net_device structure for an EoE object. fp@203: */ fp@203: fp@203: void ec_eoedev_init(struct net_device *dev /**< pointer to the net_device */) fp@203: { fp@203: ec_eoedev_priv_t *priv; fp@210: unsigned int i; fp@203: fp@203: // initialize net_device fp@203: ether_setup(dev); fp@203: dev->open = ec_eoedev_open; fp@203: dev->stop = ec_eoedev_stop; fp@203: dev->hard_start_xmit = ec_eoedev_tx; fp@203: dev->get_stats = ec_eoedev_stats; fp@203: fp@210: for (i = 0; i < 6; i++) dev->dev_addr[i] = (i + 1) | (i + 1) << 4; fp@210: fp@203: // initialize private data fp@203: priv = netdev_priv(dev); fp@203: memset(priv, 0, sizeof(ec_eoedev_priv_t)); fp@203: } fp@203: fp@203: /*****************************************************************************/ fp@203: fp@203: /** fp@203: Opens the virtual network device. fp@203: */ fp@203: fp@203: int ec_eoedev_open(struct net_device *dev /**< EoE net_device */) fp@203: { fp@203: ec_eoedev_priv_t *priv = netdev_priv(dev); fp@210: priv->eoe->opened = 1; fp@203: netif_start_queue(dev); fp@203: EC_INFO("%s (slave %i) opened.\n", dev->name, fp@203: priv->eoe->slave->ring_position); fp@203: return 0; fp@203: } fp@203: fp@203: /*****************************************************************************/ fp@203: fp@203: /** fp@203: Stops the virtual network device. fp@203: */ fp@203: fp@203: int ec_eoedev_stop(struct net_device *dev /**< EoE net_device */) fp@203: { fp@203: ec_eoedev_priv_t *priv = netdev_priv(dev); fp@203: netif_stop_queue(dev); fp@210: priv->eoe->opened = 0; fp@203: EC_INFO("%s (slave %i) stopped.\n", dev->name, fp@203: priv->eoe->slave->ring_position); fp@203: return 0; fp@203: } fp@203: fp@203: /*****************************************************************************/ fp@203: fp@203: /** fp@203: Transmits data via the virtual network device. fp@203: */ fp@203: fp@203: int ec_eoedev_tx(struct sk_buff *skb, /**< transmit socket buffer */ fp@203: struct net_device *dev /**< EoE net_device */ fp@203: ) fp@203: { fp@203: ec_eoedev_priv_t *priv = netdev_priv(dev); fp@203: priv->stats.tx_packets++; fp@203: dev_kfree_skb(skb); fp@203: EC_INFO("EoE device sent %i octets.\n", skb->len); fp@203: return 0; fp@203: } fp@203: fp@203: /*****************************************************************************/ fp@203: fp@203: /** fp@210: Receives data from the bus and passes it to the network stack. fp@210: */ fp@210: fp@210: void ec_eoedev_rx(struct net_device *dev, /**< EoE net_device */ fp@210: const uint8_t *data, /**< pointer to the data */ fp@210: size_t size /**< size of the received data */ fp@210: ) fp@210: { fp@210: ec_eoedev_priv_t *priv = netdev_priv(dev); fp@210: struct sk_buff *skb; fp@210: fp@210: // allocate socket buffer fp@210: if (!(skb = dev_alloc_skb(size + 2))) { fp@210: if (printk_ratelimit()) fp@210: EC_WARN("EoE RX: low on mem. frame dropped.\n"); fp@210: priv->stats.rx_dropped++; fp@210: return; fp@210: } fp@210: fp@210: // copy received data to socket buffer fp@210: memcpy(skb_put(skb, size), data, size); fp@210: fp@210: // set socket buffer fields fp@210: skb->dev = dev; fp@210: skb->protocol = eth_type_trans(skb, dev); fp@210: skb->ip_summed = CHECKSUM_UNNECESSARY; fp@210: fp@210: // update statistics fp@210: priv->stats.rx_packets++; fp@210: priv->stats.rx_bytes += size; fp@210: fp@210: // pass socket buffer to network stack fp@210: netif_rx(skb); fp@210: } fp@210: fp@210: /*****************************************************************************/ fp@210: fp@210: /** fp@203: Gets statistics about the virtual network device. fp@203: */ fp@203: fp@203: struct net_device_stats *ec_eoedev_stats(struct net_device *dev fp@203: /**< EoE net_device */) fp@203: { fp@203: ec_eoedev_priv_t *priv = netdev_priv(dev); fp@203: return &priv->stats; fp@203: } fp@203: fp@203: /*****************************************************************************/