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@1541: #define ETH_P_ETHERCAT 0x88A4 fp@1541: fp@1558: #define EC_GEN_RX_BUF_SIZE 1600 fp@1558: 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@1612: struct net_device *used_netdev; fp@1612: struct socket *socket; fp@1540: ec_device_t *ecdev; fp@1558: uint8_t *rx_buf; fp@1540: } ec_gen_device_t; fp@1540: fp@1557: typedef struct { fp@1557: struct list_head list; fp@1612: struct net_device *netdev; fp@1612: char name[IFNAMSIZ]; fp@1557: int ifindex; fp@1557: uint8_t dev_addr[ETH_ALEN]; fp@1557: } ec_gen_interface_desc_t; fp@1557: 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@1542: void ec_gen_device_poll(ec_gen_device_t *); 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@1542: ec_gen_device_t *gendev = *((ec_gen_device_t **) netdev_priv(dev)); fp@1542: ec_gen_device_poll(gendev); fp@1540: } fp@1540: fp@1540: /*****************************************************************************/ fp@1540: fp@1555: #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) fp@1540: static const struct net_device_ops ec_gen_netdev_ops = { fp@1555: .ndo_open = ec_gen_netdev_open, fp@1555: .ndo_stop = ec_gen_netdev_stop, fp@1555: .ndo_start_xmit = ec_gen_netdev_start_xmit, fp@1540: }; fp@1555: #endif fp@1540: fp@1540: /*****************************************************************************/ fp@1540: fp@1540: /** Init generic device. fp@1540: */ fp@1540: int ec_gen_device_init( fp@1557: ec_gen_device_t *dev fp@1540: ) fp@1540: { fp@1540: ec_gen_device_t **priv; fp@1540: char null = 0x00; fp@1540: fp@1540: dev->ecdev = NULL; fp@1541: dev->socket = NULL; fp@1558: dev->rx_buf = NULL; fp@1540: fp@2631: #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0) fp@2631: dev->netdev = alloc_netdev(sizeof(ec_gen_device_t *), &null, fp@2631: NET_NAME_UNKNOWN, ether_setup); fp@2631: #else fp@1555: dev->netdev = alloc_netdev(sizeof(ec_gen_device_t *), &null, ether_setup); fp@2631: #endif fp@1555: if (!dev->netdev) { fp@1555: return -ENOMEM; fp@1555: } fp@1555: fp@1555: #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) fp@1540: dev->netdev->netdev_ops = &ec_gen_netdev_ops; fp@1555: #else fp@1555: dev->netdev->open = ec_gen_netdev_open; fp@1555: dev->netdev->stop = ec_gen_netdev_stop; fp@1555: dev->netdev->hard_start_xmit = ec_gen_netdev_start_xmit; fp@1555: #endif fp@1555: 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@1541: if (dev->socket) { fp@1541: sock_release(dev->socket); fp@1541: } fp@1540: free_netdev(dev->netdev); fp@1558: fp@1558: if (dev->rx_buf) { fp@1558: kfree(dev->rx_buf); fp@1558: } fp@1540: } fp@1540: fp@1540: /*****************************************************************************/ fp@1540: fp@1541: /** Creates a network socket. fp@1541: */ fp@1541: int ec_gen_device_create_socket( fp@1541: ec_gen_device_t *dev, fp@1557: ec_gen_interface_desc_t *desc fp@1541: ) fp@1541: { fp@1541: int ret; fp@1541: struct sockaddr_ll sa; fp@1541: fp@1612: dev->rx_buf = kmalloc(EC_GEN_RX_BUF_SIZE, GFP_KERNEL); fp@1558: if (!dev->rx_buf) { fp@1558: return -ENOMEM; fp@1558: } fp@1558: fp@2662: #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) fp@2662: ret = sock_create_kern(&init_net, PF_PACKET, SOCK_RAW, fp@2662: htons(ETH_P_ETHERCAT), &dev->socket); fp@2662: #else fp@2170: ret = sock_create_kern(PF_PACKET, SOCK_RAW, htons(ETH_P_ETHERCAT), fp@2170: &dev->socket); fp@2662: #endif fp@1541: if (ret) { fp@2170: printk(KERN_ERR PFX "Failed to create socket (ret = %i).\n", ret); fp@1541: return ret; fp@1541: } fp@1541: fp@1541: printk(KERN_ERR PFX "Binding socket to interface %i (%s).\n", fp@1557: desc->ifindex, desc->name); fp@1541: fp@1541: memset(&sa, 0x00, sizeof(sa)); fp@1541: sa.sll_family = AF_PACKET; fp@1541: sa.sll_protocol = htons(ETH_P_ETHERCAT); fp@1557: sa.sll_ifindex = desc->ifindex; fp@1541: ret = kernel_bind(dev->socket, (struct sockaddr *) &sa, sizeof(sa)); fp@1541: if (ret) { fp@2170: printk(KERN_ERR PFX "Failed to bind() socket to interface" fp@2170: " (ret = %i).\n", ret); fp@1541: sock_release(dev->socket); fp@1541: dev->socket = NULL; fp@1541: return ret; fp@1541: } fp@1541: fp@1541: return 0; fp@1541: } fp@1541: fp@1541: /*****************************************************************************/ fp@1541: fp@1540: /** Offer generic device to master. fp@1540: */ fp@1540: int ec_gen_device_offer( fp@1541: ec_gen_device_t *dev, fp@1557: ec_gen_interface_desc_t *desc fp@1540: ) fp@1540: { fp@1540: int ret = 0; fp@1540: fp@1612: dev->used_netdev = desc->netdev; fp@1612: memcpy(dev->netdev->dev_addr, desc->dev_addr, ETH_ALEN); fp@1557: fp@1555: dev->ecdev = ecdev_offer(dev->netdev, ec_gen_poll, THIS_MODULE); fp@1540: if (dev->ecdev) { fp@1557: if (ec_gen_device_create_socket(dev, desc)) { fp@1541: ecdev_withdraw(dev->ecdev); fp@1541: dev->ecdev = NULL; fp@1541: } else if (ecdev_open(dev->ecdev)) { fp@1540: ecdev_withdraw(dev->ecdev); fp@1540: dev->ecdev = NULL; fp@1540: } else { fp@1612: ecdev_set_link(dev->ecdev, netif_carrier_ok(dev->used_netdev)); // FIXME 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@1541: return 0; 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@1541: return 0; 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@1541: struct msghdr msg; fp@1541: struct kvec iov; fp@1541: size_t len = skb->len; fp@1541: int ret; fp@1541: fp@1612: ecdev_set_link(dev->ecdev, netif_carrier_ok(dev->used_netdev)); martin@1607: fp@1541: iov.iov_base = skb->data; fp@1541: iov.iov_len = len; fp@1541: memset(&msg, 0, sizeof(msg)); fp@1541: fp@1541: ret = kernel_sendmsg(dev->socket, &msg, &iov, 1, len); fp@1541: fp@1541: return ret == len ? NETDEV_TX_OK : NETDEV_TX_BUSY; fp@1540: } fp@1540: fp@1540: /*****************************************************************************/ fp@1540: fp@1542: /** Polls the device. fp@1542: */ fp@1542: void ec_gen_device_poll( fp@1542: ec_gen_device_t *dev fp@1542: ) fp@1542: { fp@1542: struct msghdr msg; fp@1542: struct kvec iov; fp@1542: int ret, budget = 10; // FIXME fp@1542: fp@1612: ecdev_set_link(dev->ecdev, netif_carrier_ok(dev->used_netdev)); fp@1612: fp@1612: do { fp@1559: iov.iov_base = dev->rx_buf; fp@1559: iov.iov_len = EC_GEN_RX_BUF_SIZE; fp@1559: memset(&msg, 0, sizeof(msg)); fp@1559: fp@1542: ret = kernel_recvmsg(dev->socket, &msg, &iov, 1, iov.iov_len, fp@1542: MSG_DONTWAIT); fp@1542: if (ret > 0) { fp@1558: ecdev_receive(dev->ecdev, dev->rx_buf, ret); fp@1542: } else if (ret < 0) { fp@1542: break; fp@1542: } fp@1542: budget--; fp@1542: } while (budget); fp@1542: } fp@1542: fp@1542: /*****************************************************************************/ fp@1542: fp@1540: /** Offer device. fp@1540: */ fp@1540: int offer_device( fp@1557: ec_gen_interface_desc_t *desc 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@1557: ret = ec_gen_device_init(gendev); fp@1540: if (ret) { fp@1540: kfree(gendev); fp@1540: return ret; fp@1540: } fp@1540: fp@1557: if (ec_gen_device_offer(gendev, desc)) { 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@1557: struct list_head descs; fp@1540: struct net_device *netdev; fp@1557: ec_gen_interface_desc_t *desc, *next; 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@1557: INIT_LIST_HEAD(&descs); 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@1833: desc = kmalloc(sizeof(ec_gen_interface_desc_t), GFP_ATOMIC); fp@1557: if (!desc) { fp@1557: ret = -ENOMEM; fp@1540: read_unlock(&dev_base_lock); fp@1540: goto out_err; fp@1540: } fp@1557: strncpy(desc->name, netdev->name, IFNAMSIZ); fp@1612: desc->netdev = netdev; fp@1557: desc->ifindex = netdev->ifindex; fp@1557: memcpy(desc->dev_addr, netdev->dev_addr, ETH_ALEN); fp@1557: list_add_tail(&desc->list, &descs); fp@1540: } fp@1540: read_unlock(&dev_base_lock); fp@1557: fp@1557: list_for_each_entry_safe(desc, next, &descs, list) { fp@1557: ret = offer_device(desc); fp@1557: if (ret) { fp@1557: goto out_err; fp@1557: } fp@1557: kfree(desc); fp@1557: } fp@1540: return ret; fp@1540: fp@1540: out_err: fp@1557: list_for_each_entry_safe(desc, next, &descs, list) { fp@1557: list_del(&desc->list); fp@1557: kfree(desc); fp@1557: } 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: /*****************************************************************************/