fp@39: /****************************************************************************** fp@0: * fp@39: * $Id$ fp@0: * fp@1326: * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH fp@197: * fp@197: * This file is part of the IgH EtherCAT Master. fp@197: * 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@197: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA fp@197: * 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@39: *****************************************************************************/ fp@0: fp@199: /** fp@199: \file fp@199: EtherCAT device methods. fp@199: */ fp@199: fp@199: /*****************************************************************************/ fp@199: fp@24: #include fp@0: #include fp@0: #include fp@0: #include fp@0: fp@54: #include "device.h" fp@78: #include "master.h" fp@0: fp@692: #ifdef EC_DEBUG_RING fp@692: #define timersub(a, b, result) \ fp@692: do { \ fp@692: (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ fp@692: (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ fp@692: if ((result)->tv_usec < 0) { \ fp@692: --(result)->tv_sec; \ fp@692: (result)->tv_usec += 1000000; \ fp@692: } \ fp@692: } while (0) fp@692: #endif fp@692: fp@39: /*****************************************************************************/ fp@0: fp@1011: /** Constructor. fp@2421: * fp@1011: * \return 0 in case of success, else < 0 fp@1011: */ fp@1011: int ec_device_init( fp@1011: ec_device_t *device, /**< EtherCAT device */ fp@579: ec_master_t *master /**< master owning the device */ fp@579: ) fp@579: { fp@1313: int ret; fp@693: unsigned int i; fp@693: struct ethhdr *eth; fp@687: #ifdef EC_DEBUG_IF fp@687: char ifname[10]; fp@687: char mb = 'x'; fp@687: #endif fp@2451: fp@2451: device->master = master; fp@2451: device->dev = NULL; fp@2451: device->poll = NULL; fp@2451: device->module = NULL; fp@2451: device->open = 0; fp@2451: device->link_state = 0; fp@2451: for (i = 0; i < EC_TX_RING_SIZE; i++) { fp@2451: device->tx_skb[i] = NULL; fp@2451: } fp@2451: device->tx_ring_index = 0; fp@2451: #ifdef EC_HAVE_CYCLES fp@2451: device->cycles_poll = 0; fp@2451: #endif fp@2451: #ifdef EC_DEBUG_RING fp@2451: device->timeval_poll.tv_sec = 0; fp@2451: device->timeval_poll.tv_usec = 0; fp@2451: #endif fp@2451: device->jiffies_poll = 0; fp@2451: fp@2451: ec_device_clear_stats(device); fp@2451: fp@2451: #ifdef EC_DEBUG_RING fp@2451: for (i = 0; i < EC_DEBUG_RING_SIZE; i++) { fp@2451: ec_debug_frame_t *df = &device->debug_frames[i]; fp@2451: df->dir = TX; fp@2451: df->t.tv_sec = 0; fp@2451: df->t.tv_usec = 0; fp@2451: memset(df->data, 0, EC_MAX_DATA_SIZE); fp@2451: df->data_size = 0; fp@2451: } fp@2451: #endif fp@692: #ifdef EC_DEBUG_RING fp@692: device->debug_frame_index = 0; fp@692: device->debug_frame_count = 0; fp@692: #endif fp@687: fp@679: #ifdef EC_DEBUG_IF fp@2451: if (device == &master->devices[EC_DEVICE_MAIN]) { fp@687: mb = 'm'; fp@2451: } fp@2453: else { fp@687: mb = 'b'; fp@2451: } fp@687: fp@687: sprintf(ifname, "ecdbg%c%u", mb, master->index); fp@687: fp@1921: ret = ec_debug_init(&device->dbg, device, ifname); fp@1313: if (ret < 0) { fp@1921: EC_MASTER_ERR(master, "Failed to init debug device!\n"); fp@579: goto out_return; fp@579: } fp@579: #endif fp@579: fp@693: for (i = 0; i < EC_TX_RING_SIZE; i++) { fp@693: if (!(device->tx_skb[i] = dev_alloc_skb(ETH_FRAME_LEN))) { fp@1921: EC_MASTER_ERR(master, "Error allocating device socket buffer!\n"); fp@1313: ret = -ENOMEM; fp@693: goto out_tx_ring; fp@693: } fp@693: fp@693: // add Ethernet-II-header fp@693: skb_reserve(device->tx_skb[i], ETH_HLEN); fp@693: eth = (struct ethhdr *) skb_push(device->tx_skb[i], ETH_HLEN); fp@693: eth->h_proto = htons(0x88A4); fp@693: memset(eth->h_dest, 0xFF, ETH_ALEN); fp@693: } fp@579: fp@579: return 0; fp@579: fp@693: out_tx_ring: fp@2451: for (i = 0; i < EC_TX_RING_SIZE; i++) { fp@2451: if (device->tx_skb[i]) { fp@693: dev_kfree_skb(device->tx_skb[i]); fp@2451: } fp@2451: } fp@693: #ifdef EC_DEBUG_IF fp@579: ec_debug_clear(&device->dbg); fp@693: out_return: fp@693: #endif fp@1313: return ret; fp@1313: } fp@1313: fp@1313: /*****************************************************************************/ fp@1313: fp@1313: /** Destructor. fp@1011: */ fp@1011: void ec_device_clear( fp@1011: ec_device_t *device /**< EtherCAT device */ fp@1011: ) fp@579: { fp@693: unsigned int i; fp@693: fp@2453: if (device->open) { fp@2453: ec_device_close(device); fp@2453: } fp@693: for (i = 0; i < EC_TX_RING_SIZE; i++) fp@693: dev_kfree_skb(device->tx_skb[i]); fp@679: #ifdef EC_DEBUG_IF fp@579: ec_debug_clear(&device->dbg); fp@579: #endif fp@579: } fp@579: fp@579: /*****************************************************************************/ fp@579: fp@1011: /** Associate with net_device. fp@1011: */ fp@1011: void ec_device_attach( fp@1011: ec_device_t *device, /**< EtherCAT device */ fp@579: struct net_device *net_dev, /**< net_device structure */ fp@579: ec_pollfunc_t poll, /**< pointer to device's poll function */ fp@579: struct module *module /**< the device's module */ fp@579: ) fp@579: { fp@693: unsigned int i; fp@693: struct ethhdr *eth; fp@693: fp@579: ec_device_detach(device); // resets fields fp@579: fp@98: device->dev = net_dev; fp@533: device->poll = poll; fp@539: device->module = module; fp@98: fp@693: for (i = 0; i < EC_TX_RING_SIZE; i++) { fp@693: device->tx_skb[i]->dev = net_dev; fp@759: eth = (struct ethhdr *) (device->tx_skb[i]->data); fp@693: memcpy(eth->h_source, net_dev->dev_addr, ETH_ALEN); fp@693: } fp@1305: fp@1305: #ifdef EC_DEBUG_IF fp@1305: ec_debug_register(&device->dbg, net_dev); fp@1305: #endif fp@579: } fp@579: fp@579: /*****************************************************************************/ fp@579: fp@1011: /** Disconnect from net_device. fp@1011: */ fp@1011: void ec_device_detach( fp@1011: ec_device_t *device /**< EtherCAT device */ fp@1011: ) fp@579: { fp@693: unsigned int i; fp@693: fp@1305: #ifdef EC_DEBUG_IF fp@1305: ec_debug_unregister(&device->dbg); fp@1305: #endif fp@1305: fp@579: device->dev = NULL; fp@579: device->poll = NULL; fp@579: device->module = NULL; fp@78: device->open = 0; fp@96: device->link_state = 0; // down fp@1857: fp@1857: ec_device_clear_stats(device); fp@1857: fp@2451: for (i = 0; i < EC_TX_RING_SIZE; i++) { fp@693: device->tx_skb[i]->dev = NULL; fp@2451: } fp@0: } fp@0: fp@39: /*****************************************************************************/ fp@0: fp@1011: /** Opens the EtherCAT device. fp@1011: * fp@1011: * \return 0 in case of success, else < 0 fp@1011: */ fp@1011: int ec_device_open( fp@1011: ec_device_t *device /**< EtherCAT device */ fp@1011: ) fp@0: { fp@1313: int ret; fp@1313: fp@78: if (!device->dev) { fp@1921: EC_MASTER_ERR(device->master, "No net_device to open!\n"); fp@1313: return -ENODEV; fp@73: } fp@73: fp@78: if (device->open) { fp@1921: EC_MASTER_WARN(device->master, "Device already opened!\n"); fp@91: return 0; fp@91: } fp@91: fp@96: device->link_state = 0; fp@1857: fp@1857: ec_device_clear_stats(device); fp@91: fp@1476: #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) fp@1476: ret = device->dev->netdev_ops->ndo_open(device->dev); fp@1476: #else fp@1313: ret = device->dev->open(device->dev); fp@1476: #endif fp@1313: if (!ret) fp@1313: device->open = 1; fp@1313: fp@1313: return ret; fp@0: } fp@0: fp@39: /*****************************************************************************/ fp@0: fp@1011: /** Stops the EtherCAT device. fp@1011: * fp@1011: * \return 0 in case of success, else < 0 fp@1011: */ fp@1011: int ec_device_close( fp@1011: ec_device_t *device /**< EtherCAT device */ fp@1011: ) fp@78: { fp@1313: int ret; fp@1313: fp@78: if (!device->dev) { fp@1921: EC_MASTER_ERR(device->master, "No device to close!\n"); fp@1313: return -ENODEV; fp@73: } fp@73: fp@78: if (!device->open) { fp@1921: EC_MASTER_WARN(device->master, "Device already closed!\n"); fp@98: return 0; fp@98: } fp@98: fp@1476: #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) fp@1476: ret = device->dev->netdev_ops->ndo_stop(device->dev); fp@1476: #else fp@1313: ret = device->dev->stop(device->dev); fp@1476: #endif fp@1313: if (!ret) fp@1313: device->open = 0; fp@1313: fp@1313: return ret; fp@73: } fp@73: fp@73: /*****************************************************************************/ fp@73: fp@1011: /** Returns a pointer to the device's transmit memory. fp@1011: * fp@1011: * \return pointer to the TX socket buffer fp@1011: */ fp@1011: uint8_t *ec_device_tx_data( fp@1011: ec_device_t *device /**< EtherCAT device */ fp@1011: ) fp@98: { fp@693: /* cycle through socket buffers, because otherwise there is a race fp@693: * condition, if multiple frames are sent and the DMA is not scheduled in fp@693: * between. */ fp@693: device->tx_ring_index++; fp@693: device->tx_ring_index %= EC_TX_RING_SIZE; fp@693: return device->tx_skb[device->tx_ring_index]->data + ETH_HLEN; fp@0: } fp@0: fp@39: /*****************************************************************************/ fp@0: fp@1011: /** Sends the content of the transmit socket buffer. fp@1011: * fp@1011: * Cuts the socket buffer content to the (now known) size, and calls the fp@1011: * start_xmit() function of the assigned net_device. fp@1011: */ fp@1011: void ec_device_send( fp@1011: ec_device_t *device, /**< EtherCAT device */ fp@1011: size_t size /**< number of bytes to send */ fp@1011: ) fp@73: { fp@693: struct sk_buff *skb = device->tx_skb[device->tx_ring_index]; fp@693: fp@195: // set the right length for the data fp@693: skb->len = ETH_HLEN + size; fp@78: fp@78: if (unlikely(device->master->debug_level > 1)) { fp@1921: EC_MASTER_DBG(device->master, 2, "Sending frame:\n"); fp@1554: ec_print_data(skb->data, ETH_HLEN + size); fp@693: } fp@693: fp@195: // start sending fp@1476: #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) fp@1554: if (device->dev->netdev_ops->ndo_start_xmit(skb, device->dev) == fp@1554: NETDEV_TX_OK) fp@1476: #else fp@1554: if (device->dev->hard_start_xmit(skb, device->dev) == NETDEV_TX_OK) fp@1554: #endif fp@1554: { fp@1507: device->tx_count++; fp@2158: device->master->device_stats.tx_count++; fp@1857: device->tx_bytes += ETH_HLEN + size; fp@2158: device->master->device_stats.tx_bytes += ETH_HLEN + size; fp@1507: #ifdef EC_DEBUG_IF fp@1507: ec_debug_send(&device->dbg, skb->data, ETH_HLEN + size); fp@725: #endif fp@725: #ifdef EC_DEBUG_RING fp@1507: ec_device_debug_ring_append( fp@1507: device, TX, skb->data + ETH_HLEN, size); fp@1507: #endif fp@1857: } else { fp@1857: device->tx_errors++; fp@1507: } fp@73: } fp@73: fp@73: /*****************************************************************************/ fp@73: fp@1856: /** Clears the frame statistics. fp@1856: */ fp@1856: void ec_device_clear_stats( fp@1856: ec_device_t *device /**< EtherCAT device */ fp@1856: ) fp@1856: { fp@1856: unsigned int i; fp@1856: fp@1856: // zero frame statistics fp@1856: device->tx_count = 0; fp@2158: device->last_tx_count = 0; fp@1856: device->rx_count = 0; fp@2158: device->last_rx_count = 0; fp@2158: device->tx_bytes = 0; fp@2158: device->last_tx_bytes = 0; fp@2158: device->rx_bytes = 0; fp@2158: device->last_rx_bytes = 0; fp@1857: device->tx_errors = 0; fp@2158: fp@1856: for (i = 0; i < EC_RATE_COUNT; i++) { fp@1857: device->tx_frame_rates[i] = 0; fp@2158: device->rx_frame_rates[i] = 0; fp@1857: device->tx_byte_rates[i] = 0; fp@2158: device->rx_byte_rates[i] = 0; fp@1856: } fp@1856: } fp@1856: fp@1856: /*****************************************************************************/ fp@1856: fp@692: #ifdef EC_DEBUG_RING fp@1011: /** Appends frame data to the debug ring. fp@1011: */ fp@692: void ec_device_debug_ring_append( fp@692: ec_device_t *device, /**< EtherCAT device */ fp@692: ec_debug_frame_dir_t dir, /**< direction */ fp@692: const void *data, /**< frame data */ fp@692: size_t size /**< data size */ fp@692: ) fp@692: { fp@692: ec_debug_frame_t *df = &device->debug_frames[device->debug_frame_index]; fp@692: fp@692: df->dir = dir; fp@2451: if (dir == TX) { fp@692: do_gettimeofday(&df->t); fp@2451: } fp@2451: else { fp@692: df->t = device->timeval_poll; fp@2451: } fp@692: memcpy(df->data, data, size); fp@692: df->data_size = size; fp@692: fp@692: device->debug_frame_index++; fp@692: device->debug_frame_index %= EC_DEBUG_RING_SIZE; fp@692: if (unlikely(device->debug_frame_count < EC_DEBUG_RING_SIZE)) fp@692: device->debug_frame_count++; fp@692: } fp@692: fp@692: /*****************************************************************************/ fp@692: fp@1011: /** Outputs the debug ring. fp@1011: */ fp@692: void ec_device_debug_ring_print( fp@692: const ec_device_t *device /**< EtherCAT device */ fp@692: ) fp@692: { fp@692: int i; fp@692: unsigned int ring_index; fp@692: const ec_debug_frame_t *df; fp@692: struct timeval t0, diff; fp@692: fp@692: // calculate index of the newest frame in the ring to get its time fp@692: ring_index = (device->debug_frame_index + EC_DEBUG_RING_SIZE - 1) fp@692: % EC_DEBUG_RING_SIZE; fp@692: t0 = device->debug_frames[ring_index].t; fp@692: fp@1921: EC_MASTER_DBG(device->master, 1, "Debug ring %u:\n", ring_index); fp@692: fp@692: // calculate index of the oldest frame in the ring fp@692: ring_index = (device->debug_frame_index + EC_DEBUG_RING_SIZE fp@692: - device->debug_frame_count) % EC_DEBUG_RING_SIZE; fp@692: fp@692: for (i = 0; i < device->debug_frame_count; i++) { fp@692: df = &device->debug_frames[ring_index]; fp@692: timersub(&t0, &df->t, &diff); fp@692: fp@1921: EC_MASTER_DBG(device->master, 1, "Frame %u, dt=%u.%06u s, %s:\n", fp@692: i + 1 - device->debug_frame_count, fp@692: (unsigned int) diff.tv_sec, fp@692: (unsigned int) diff.tv_usec, fp@692: (df->dir == TX) ? "TX" : "RX"); fp@692: ec_print_data(df->data, df->data_size); fp@692: fp@692: ring_index++; fp@692: ring_index %= EC_DEBUG_RING_SIZE; fp@692: } fp@692: } fp@692: #endif fp@692: fp@692: /*****************************************************************************/ fp@692: fp@1011: /** Calls the poll function of the assigned net_device. fp@1011: * fp@1011: * The master itself works without using interrupts. Therefore the processing fp@1011: * of received data and status changes of the network device has to be fp@1011: * done by the master calling the ISR "manually". fp@1011: */ fp@1011: void ec_device_poll( fp@1011: ec_device_t *device /**< EtherCAT device */ fp@1011: ) fp@533: { fp@1040: #ifdef EC_HAVE_CYCLES fp@533: device->cycles_poll = get_cycles(); fp@1040: #endif fp@533: device->jiffies_poll = jiffies; fp@692: #ifdef EC_DEBUG_RING fp@692: do_gettimeofday(&device->timeval_poll); fp@692: #endif fp@533: device->poll(device->dev); fp@39: } fp@39: fp@2158: /*****************************************************************************/ fp@2158: fp@2158: /** Update device statistics. fp@2158: */ fp@2158: void ec_device_update_stats( fp@2158: ec_device_t *device /**< EtherCAT device */ fp@2158: ) fp@2158: { fp@2158: unsigned int i; fp@2158: fp@2372: s32 tx_frame_rate = (device->tx_count - device->last_tx_count) * 1000; fp@2372: s32 rx_frame_rate = (device->rx_count - device->last_rx_count) * 1000; fp@2372: s32 tx_byte_rate = (device->tx_bytes - device->last_tx_bytes); fp@2372: s32 rx_byte_rate = (device->rx_bytes - device->last_rx_bytes); fp@2372: fp@2372: /* Low-pass filter: fp@2372: * Y_n = y_(n - 1) + T / tau * (x - y_(n - 1)) | T = 1 fp@2372: * -> Y_n += (x - y_(n - 1)) / tau fp@2372: */ fp@2158: for (i = 0; i < EC_RATE_COUNT; i++) { fp@2372: s32 n = rate_intervals[i]; fp@2372: device->tx_frame_rates[i] += fp@2372: (tx_frame_rate - device->tx_frame_rates[i]) / n; fp@2372: device->rx_frame_rates[i] += fp@2372: (rx_frame_rate - device->rx_frame_rates[i]) / n; fp@2372: device->tx_byte_rates[i] += fp@2372: (tx_byte_rate - device->tx_byte_rates[i]) / n; fp@2372: device->rx_byte_rates[i] += fp@2372: (rx_byte_rate - device->rx_byte_rates[i]) / n; fp@2158: } fp@2158: fp@2158: device->last_tx_count = device->tx_count; fp@2158: device->last_rx_count = device->rx_count; fp@2158: device->last_tx_bytes = device->tx_bytes; fp@2158: device->last_rx_bytes = device->rx_bytes; fp@2158: } fp@2158: fp@54: /****************************************************************************** fp@195: * Device interface fp@54: *****************************************************************************/ fp@54: fp@1011: /** Withdraws an EtherCAT device from the master. fp@1011: * fp@1011: * The device is disconnected from the master and all device ressources fp@1011: * are freed. fp@1011: * fp@1011: * \attention Before calling this function, the ecdev_stop() function has fp@1011: * to be called, to be sure that the master does not use the device fp@1011: * any more. fp@1011: * \ingroup DeviceInterface fp@1011: */ fp@1011: void ecdev_withdraw(ec_device_t *device /**< EtherCAT device */) fp@1011: { fp@1011: ec_master_t *master = device->master; fp@2156: char dev_str[20], mac_str[20]; fp@2156: fp@2156: ec_mac_print(device->dev->dev_addr, mac_str); fp@2156: fp@2267: if (device == &master->devices[EC_DEVICE_MAIN]) { fp@2156: sprintf(dev_str, "main"); fp@2267: } else if (device == &master->devices[EC_DEVICE_BACKUP]) { fp@2156: sprintf(dev_str, "backup"); fp@2156: } else { fp@2156: EC_MASTER_WARN(master, "%s() called with unknown device %s!\n", fp@2156: __func__, mac_str); fp@2156: sprintf(dev_str, "UNKNOWN"); fp@2156: } fp@2156: fp@2156: EC_MASTER_INFO(master, "Releasing %s device %s.\n", dev_str, mac_str); fp@2421: fp@1011: down(&master->device_sem); fp@1011: ec_device_detach(device); fp@1011: up(&master->device_sem); fp@1011: } fp@1011: fp@1011: /*****************************************************************************/ fp@1011: fp@1029: /** Opens the network device and makes the master enter IDLE phase. fp@1011: * fp@1011: * \return 0 on success, else < 0 fp@1011: * \ingroup DeviceInterface fp@1011: */ fp@1011: int ecdev_open(ec_device_t *device /**< EtherCAT device */) fp@1011: { fp@1313: int ret; fp@2156: ec_master_t *master = device->master; fp@2453: unsigned int all_open = 1, dev_idx; fp@1313: fp@1313: ret = ec_device_open(device); fp@1313: if (ret) { fp@2156: EC_MASTER_ERR(master, "Failed to open device!\n"); fp@1313: return ret; fp@1313: } fp@1313: fp@2453: for (dev_idx = EC_DEVICE_MAIN; fp@2453: dev_idx < ec_master_num_devices(device->master); dev_idx++) { fp@2453: if (!master->devices[dev_idx].open) { fp@2453: all_open = 0; fp@2453: break; fp@2453: } fp@2453: } fp@2453: fp@2453: if (all_open) { fp@2156: ret = ec_master_enter_idle_phase(device->master); fp@2156: if (ret) { fp@2156: EC_MASTER_ERR(device->master, "Failed to enter IDLE phase!\n"); fp@2156: return ret; fp@2156: } fp@1011: } fp@1011: fp@1011: return 0; fp@1011: } fp@1011: fp@1011: /*****************************************************************************/ fp@1011: fp@1029: /** Makes the master leave IDLE phase and closes the network device. fp@1011: * fp@1011: * \return 0 on success, else < 0 fp@1011: * \ingroup DeviceInterface fp@1011: */ fp@1011: void ecdev_close(ec_device_t *device /**< EtherCAT device */) fp@1011: { fp@2156: ec_master_t *master = device->master; fp@2156: fp@2156: if (master->phase == EC_IDLE) { fp@2156: ec_master_leave_idle_phase(master); fp@2156: } fp@2156: fp@2156: if (ec_device_close(device)) { fp@2156: EC_MASTER_WARN(master, "Failed to close device!\n"); fp@2156: } fp@1011: } fp@1011: fp@1011: /*****************************************************************************/ fp@1011: fp@1011: /** Accepts a received frame. fp@1011: * fp@1011: * Forwards the received data to the master. The master will analyze the frame fp@1011: * and dispatch the received commands to the sending instances. fp@2421: * fp@2687: * The data have to begin with the Ethernet header (target MAC address). fp@2687: * fp@1011: * \ingroup DeviceInterface fp@1011: */ fp@1011: void ecdev_receive( fp@1011: ec_device_t *device, /**< EtherCAT device */ fp@1011: const void *data, /**< pointer to received data */ fp@1011: size_t size /**< number of bytes received */ fp@1011: ) fp@73: { fp@692: const void *ec_data = data + ETH_HLEN; fp@692: size_t ec_size = size - ETH_HLEN; fp@1521: fp@1521: if (unlikely(!data)) { fp@1921: EC_MASTER_WARN(device->master, "%s() called with NULL data.\n", fp@1921: __func__); fp@1521: return; fp@1521: } fp@1521: fp@493: device->rx_count++; fp@2158: device->master->device_stats.rx_count++; fp@2158: device->rx_bytes += size; fp@2158: device->master->device_stats.rx_bytes += size; fp@493: fp@78: if (unlikely(device->master->debug_level > 1)) { fp@1921: EC_MASTER_DBG(device->master, 2, "Received frame:\n"); fp@1554: ec_print_data(data, size); fp@231: } fp@231: fp@679: #ifdef EC_DEBUG_IF fp@231: ec_debug_send(&device->dbg, data, size); fp@392: #endif fp@692: #ifdef EC_DEBUG_RING fp@692: ec_device_debug_ring_append(device, RX, ec_data, ec_size); fp@692: #endif fp@692: fp@2530: ec_master_receive_datagrams(device->master, device, ec_data, ec_size); fp@54: } fp@54: fp@54: /*****************************************************************************/ fp@54: fp@1011: /** Sets a new link state. fp@1011: * fp@1011: * If the device notifies the master about the link being down, the master fp@1011: * will not try to send frames using this device. fp@2421: * fp@1011: * \ingroup DeviceInterface fp@1011: */ fp@1011: void ecdev_set_link( fp@1011: ec_device_t *device, /**< EtherCAT device */ fp@670: uint8_t state /**< new link state */ fp@670: ) fp@104: { fp@191: if (unlikely(!device)) { fp@2160: EC_WARN("ecdev_set_link() called with null device!\n"); fp@191: return; fp@191: } fp@191: fp@104: if (likely(state != device->link_state)) { fp@96: device->link_state = state; fp@1921: EC_MASTER_INFO(device->master, fp@2160: "Link state of %s changed to %s.\n", fp@2160: device->dev->name, (state ? "UP" : "DOWN")); fp@96: } fp@96: } fp@96: fp@96: /*****************************************************************************/ fp@96: fp@1011: /** Reads the link state. fp@1011: * fp@1011: * \ingroup DeviceInterface fp@2522: * fp@2522: * \return Link state. fp@1011: */ fp@1011: uint8_t ecdev_get_link( fp@1011: const ec_device_t *device /**< EtherCAT device */ fp@1011: ) fp@670: { fp@670: if (unlikely(!device)) { fp@2160: EC_WARN("ecdev_get_link() called with null device!\n"); fp@670: return 0; fp@670: } fp@670: fp@670: return device->link_state; fp@670: } fp@670: fp@670: /*****************************************************************************/ fp@670: fp@199: /** \cond */ fp@199: fp@1011: EXPORT_SYMBOL(ecdev_withdraw); fp@1011: EXPORT_SYMBOL(ecdev_open); fp@1011: EXPORT_SYMBOL(ecdev_close); fp@104: EXPORT_SYMBOL(ecdev_receive); fp@670: EXPORT_SYMBOL(ecdev_get_link); fp@670: EXPORT_SYMBOL(ecdev_set_link); fp@27: fp@199: /** \endcond */ fp@199: fp@199: /*****************************************************************************/