fp@27: /****************************************************************************** fp@27: * fp@27: * $Id$ fp@27: * fp@1618: * Copyright (C) 2006 Florian Pose, Ingenieurgemeinschaft IgH fp@1618: * fp@1618: * This file is part of the IgH EtherCAT Master. fp@1618: * fp@1618: * The IgH EtherCAT Master is free software; you can redistribute it fp@1618: * and/or modify it under the terms of the GNU General Public License fp@1619: * as published by the Free Software Foundation; either version 2 of the fp@1619: * License, or (at your option) any later version. fp@1618: * fp@1618: * The IgH EtherCAT Master is distributed in the hope that it will be fp@1618: * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of fp@1618: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the fp@1618: * GNU General Public License for more details. fp@1618: * fp@1618: * You should have received a copy of the GNU General Public License fp@1618: * along with the IgH EtherCAT Master; if not, write to the Free Software fp@1618: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA fp@27: * fp@1619: * The right to use EtherCAT Technology is granted and comes free of fp@1619: * charge under condition of compatibility of product made by fp@1619: * Licensee. People intending to distribute/sell products based on the fp@1619: * code, have to sign an agreement to guarantee that products using fp@1619: * software based on IgH EtherCAT master stay compatible with the actual fp@1619: * EtherCAT specification (which are released themselves as an open fp@1619: * standard) as the (only) precondition to have the right to use EtherCAT fp@1619: * Technology, IP and trade marks. fp@1619: * fp@39: *****************************************************************************/ fp@27: fp@1618: /** fp@1618: \file fp@1618: EtherCAT master driver module. fp@1618: */ fp@1618: fp@1618: /*****************************************************************************/ fp@1618: fp@27: #include fp@27: #include fp@27: #include fp@27: fp@184: #include "globals.h" fp@54: #include "master.h" fp@54: #include "device.h" fp@54: fp@54: /*****************************************************************************/ fp@54: fp@54: int __init ec_init_module(void); fp@54: void __exit ec_cleanup_module(void); fp@52: fp@39: /*****************************************************************************/ fp@39: fp@1618: /** fp@1618: Compile version info. fp@1618: */ fp@1618: fp@1617: #define COMPILE_INFO EC_STR(EC_MASTER_VERSION_MAIN) \ fp@1617: "." EC_STR(EC_MASTER_VERSION_SUB) \ fp@1617: " (" EC_MASTER_VERSION_EXTRA ")" \ fp@1617: " - rev. " EC_STR(SVNREV) \ fp@98: ", compiled by " EC_STR(USER) \ fp@98: " at " __DATE__ " " __TIME__ fp@39: fp@39: /*****************************************************************************/ fp@27: fp@1623: static int ec_master_count = 1; /**< parameter value, number of masters */ fp@1624: static int ec_eoeif_count = 0; /**< parameter value, number of EoE interf. */ fp@1623: static struct list_head ec_masters; /**< list of masters */ fp@27: fp@39: /*****************************************************************************/ fp@39: fp@1618: /** \cond */ fp@1618: fp@1619: module_param(ec_master_count, int, S_IRUGO); fp@1624: module_param(ec_eoeif_count, int, S_IRUGO); fp@1619: fp@1619: MODULE_AUTHOR("Florian Pose "); fp@1619: MODULE_DESCRIPTION("EtherCAT master driver module"); fp@27: MODULE_LICENSE("GPL"); fp@34: MODULE_VERSION(COMPILE_INFO); fp@195: MODULE_PARM_DESC(ec_master_count, "number of EtherCAT masters to initialize"); fp@1624: MODULE_PARM_DESC(ec_eoeif_count, "number of EoE interfaces per master"); fp@195: fp@1618: /** \endcond */ fp@1618: fp@195: /*****************************************************************************/ fp@195: fp@195: /** fp@195: Module initialization. fp@195: Initializes \a ec_master_count masters. fp@195: \return 0 on success, else < 0 fp@54: */ fp@54: fp@54: int __init ec_init_module(void) fp@27: { fp@73: unsigned int i; fp@178: ec_master_t *master, *next; fp@73: fp@84: EC_INFO("Master driver, %s\n", COMPILE_INFO); fp@73: fp@73: if (ec_master_count < 1) { fp@111: EC_ERR("Error - Invalid ec_master_count: %i\n", ec_master_count); fp@127: goto out_return; fp@73: } fp@73: fp@84: EC_INFO("Initializing %i EtherCAT master(s)...\n", ec_master_count); fp@84: fp@178: INIT_LIST_HEAD(&ec_masters); fp@73: fp@73: for (i = 0; i < ec_master_count; i++) { fp@178: if (!(master = fp@178: (ec_master_t *) kmalloc(sizeof(ec_master_t), GFP_KERNEL))) { fp@178: EC_ERR("Failed to allocate memory for EtherCAT master %i.\n", i); fp@178: goto out_free; fp@178: } fp@178: fp@1624: if (ec_master_init(master, i, ec_eoeif_count)) fp@178: goto out_free; fp@178: fp@178: if (kobject_add(&master->kobj)) { fp@178: EC_ERR("Failed to add kobj.\n"); fp@178: kobject_put(&master->kobj); // free master fp@178: goto out_free; fp@178: } fp@178: fp@178: list_add_tail(&master->list, &ec_masters); fp@73: } fp@73: fp@84: EC_INFO("Master driver initialized.\n"); fp@73: return 0; fp@127: fp@178: out_free: fp@178: list_for_each_entry_safe(master, next, &ec_masters, list) { fp@178: list_del(&master->list); fp@178: kobject_del(&master->kobj); fp@178: kobject_put(&master->kobj); fp@178: } fp@127: out_return: fp@127: return -1; fp@27: } fp@27: fp@39: /*****************************************************************************/ fp@27: fp@27: /** fp@195: Module cleanup. fp@195: Clears all master instances. fp@27: */ fp@27: fp@54: void __exit ec_cleanup_module(void) fp@27: { fp@178: ec_master_t *master, *next; fp@73: fp@84: EC_INFO("Cleaning up master driver...\n"); fp@73: fp@178: list_for_each_entry_safe(master, next, &ec_masters, list) { fp@178: list_del(&master->list); fp@178: kobject_del(&master->kobj); fp@178: kobject_put(&master->kobj); // free master fp@178: } fp@73: fp@84: EC_INFO("Master driver cleaned up.\n"); fp@27: } fp@27: fp@178: /*****************************************************************************/ fp@178: fp@178: /** fp@178: Gets a handle to a certain master. fp@178: \returns pointer to master fp@178: */ fp@178: fp@195: ec_master_t *ec_find_master(unsigned int master_index /**< master index */) fp@178: { fp@178: ec_master_t *master; fp@178: fp@178: list_for_each_entry(master, &ec_masters, list) { fp@178: if (master->index == master_index) return master; fp@178: } fp@178: fp@178: EC_ERR("Master %i does not exist!\n", master_index); fp@178: return NULL; fp@178: } fp@178: fp@1617: /*****************************************************************************/ fp@1617: fp@1617: /** fp@1617: Outputs frame contents for debugging purposes. fp@1617: */ fp@1617: fp@1617: void ec_print_data(const uint8_t *data, /**< pointer to data */ fp@1617: size_t size /**< number of bytes to output */ fp@1617: ) fp@1617: { fp@1617: unsigned int i; fp@1617: fp@1617: EC_DBG(""); fp@1617: for (i = 0; i < size; i++) { fp@1617: printk("%02X ", data[i]); fp@1617: if ((i + 1) % 16 == 0) { fp@1617: printk("\n"); fp@1617: EC_DBG(""); fp@1617: } fp@1617: } fp@1617: printk("\n"); fp@1617: } fp@1617: fp@1617: /*****************************************************************************/ fp@1617: fp@1617: /** fp@1617: Outputs frame contents and differences for debugging purposes. fp@1617: */ fp@1617: fp@1617: void ec_print_data_diff(const uint8_t *d1, /**< first data */ fp@1617: const uint8_t *d2, /**< second data */ fp@1617: size_t size /** number of bytes to output */ fp@1617: ) fp@1617: { fp@1617: unsigned int i; fp@1617: fp@1617: EC_DBG(""); fp@1617: for (i = 0; i < size; i++) { fp@1617: if (d1[i] == d2[i]) printk(".. "); fp@1617: else printk("%02X ", d2[i]); fp@1617: if ((i + 1) % 16 == 0) { fp@1617: printk("\n"); fp@1617: EC_DBG(""); fp@1617: } fp@1617: } fp@1617: printk("\n"); fp@1617: } fp@1617: fp@1619: /*****************************************************************************/ fp@1619: fp@1619: /** fp@1619: Prints slave states in clear text. fp@1619: */ fp@1619: fp@1619: void ec_print_states(const uint8_t states /**< slave states */) fp@1619: { fp@1619: unsigned int first = 1; fp@1619: fp@1619: if (!states) { fp@1619: printk("(unknown)"); fp@1619: return; fp@1619: } fp@1619: fp@1619: if (states & EC_SLAVE_STATE_INIT) { fp@1619: printk("INIT"); fp@1619: first = 0; fp@1619: } fp@1619: if (states & EC_SLAVE_STATE_PREOP) { fp@1619: if (!first) printk(", "); fp@1619: printk("PREOP"); fp@1619: first = 0; fp@1619: } fp@1619: if (states & EC_SLAVE_STATE_SAVEOP) { fp@1619: if (!first) printk(", "); fp@1619: printk("SAVEOP"); fp@1619: first = 0; fp@1619: } fp@1619: if (states & EC_SLAVE_STATE_OP) { fp@1619: if (!first) printk(", "); fp@1619: printk("OP"); fp@1619: } fp@1619: } fp@1619: fp@54: /****************************************************************************** fp@195: * Device interface fp@54: *****************************************************************************/ fp@33: fp@33: /** fp@1618: Connects an EtherCAT device to a certain master. fp@1618: The master will use the device for sending and receiving frames. It is fp@1618: required that no other instance (for example the kernel IP stack) uses fp@1618: the device. fp@195: \return 0 on success, else < 0 fp@1618: \ingroup DeviceInterface fp@195: */ fp@195: fp@195: ec_device_t *ecdev_register(unsigned int master_index, /**< master index */ fp@195: struct net_device *net_dev, /**< net_device of fp@195: the device */ fp@195: ec_isr_t isr, /**< interrupt service routine */ fp@195: struct module *module /**< pointer to the module */ fp@104: ) fp@91: { fp@73: ec_master_t *master; fp@73: fp@178: if (!(master = ec_find_master(master_index))) return NULL; fp@178: fp@98: if (master->device) { fp@84: EC_ERR("Master %i already has a device!\n", master_index); fp@191: goto out_return; fp@73: } fp@73: fp@178: if (!(master->device = fp@178: (ec_device_t *) kmalloc(sizeof(ec_device_t), GFP_KERNEL))) { fp@161: EC_ERR("Failed to allocate device!\n"); fp@191: goto out_return; fp@98: } fp@98: fp@127: if (ec_device_init(master->device, master, net_dev, isr, module)) { fp@191: EC_ERR("Failed to init device!\n"); fp@191: goto out_free; fp@127: } fp@98: fp@98: return master->device; fp@191: fp@191: out_free: fp@191: kfree(master->device); fp@191: master->device = NULL; fp@191: out_return: fp@191: return NULL; fp@91: } fp@91: fp@91: /*****************************************************************************/ fp@91: fp@91: /** fp@1618: Disconnect an EtherCAT device from the master. fp@1618: The device is disconnected from the master and all device ressources fp@1618: are freed. fp@1618: \attention Before calling this function, the ecdev_stop() function has fp@1618: to be called, to be sure that the master does not use the device any more. fp@1618: \ingroup DeviceInterface fp@195: */ fp@195: fp@195: void ecdev_unregister(unsigned int master_index, /**< master index */ fp@195: ec_device_t *device /**< EtherCAT device */ fp@104: ) fp@55: { fp@73: ec_master_t *master; fp@73: fp@178: if (!(master = ec_find_master(master_index))) return; fp@73: fp@98: if (!master->device || master->device != device) { fp@84: EC_WARN("Unable to unregister device!\n"); fp@73: return; fp@73: } fp@73: fp@98: ec_device_clear(master->device); fp@98: kfree(master->device); fp@98: master->device = NULL; fp@54: } fp@54: fp@191: /*****************************************************************************/ fp@191: fp@191: /** fp@195: Starts the master associated with the device. fp@1618: This function has to be called by the network device driver to tell the fp@1618: master that the device is ready to send and receive data. The master fp@1624: will enter the idle mode then. fp@1618: \ingroup DeviceInterface fp@195: */ fp@195: fp@195: int ecdev_start(unsigned int master_index /**< master index */) fp@191: { fp@191: ec_master_t *master; fp@191: if (!(master = ec_find_master(master_index))) return -1; fp@191: fp@191: if (ec_device_open(master->device)) { fp@191: EC_ERR("Failed to open device!\n"); fp@191: return -1; fp@191: } fp@191: fp@1624: ec_master_idle_start(master); fp@191: return 0; fp@191: } fp@191: fp@191: /*****************************************************************************/ fp@191: fp@191: /** fp@195: Stops the master associated with the device. fp@1618: Tells the master to stop using the device for frame IO. Has to be called fp@1618: before unregistering the device. fp@1618: \ingroup DeviceInterface fp@195: */ fp@195: fp@195: void ecdev_stop(unsigned int master_index /**< master index */) fp@191: { fp@191: ec_master_t *master; fp@191: if (!(master = ec_find_master(master_index))) return; fp@191: fp@1624: ec_master_idle_stop(master); fp@191: fp@191: if (ec_device_close(master->device)) fp@191: EC_WARN("Failed to close device!\n"); fp@191: } fp@191: fp@54: /****************************************************************************** fp@195: * Realtime interface fp@54: *****************************************************************************/ fp@33: fp@33: /** fp@195: Reserves an EtherCAT master for realtime operation. fp@195: \return pointer to reserved master, or NULL on error fp@1618: \ingroup RealtimeInterface fp@91: */ fp@91: fp@178: ec_master_t *ecrt_request_master(unsigned int master_index fp@195: /**< master index */ fp@104: ) fp@54: { fp@73: ec_master_t *master; fp@73: fp@178: EC_INFO("Requesting master %i...\n", master_index); fp@178: fp@191: if (!(master = ec_find_master(master_index))) goto out_return; fp@178: fp@178: if (master->reserved) { fp@178: EC_ERR("Master %i is already in use!\n", master_index); fp@191: goto out_return; fp@73: } fp@178: master->reserved = 1; fp@73: fp@98: if (!master->device) { fp@178: EC_ERR("Master %i has no assigned device!\n", master_index); fp@191: goto out_release; fp@73: } fp@73: fp@98: if (!try_module_get(master->device->module)) { fp@84: EC_ERR("Failed to reserve device module!\n"); fp@191: goto out_release; fp@191: } fp@191: fp@1624: ec_master_idle_stop(master); fp@191: ec_master_reset(master); fp@191: master->mode = EC_MASTER_MODE_RUNNING; fp@73: fp@178: if (!master->device->link_state) EC_WARN("Link is DOWN.\n"); fp@178: fp@178: if (ec_master_bus_scan(master)) { fp@84: EC_ERR("Bus scan failed!\n"); fp@191: goto out_module_put; fp@73: } fp@73: fp@178: EC_INFO("Master %i is ready.\n", master_index); fp@73: return master; fp@54: fp@191: out_module_put: fp@98: module_put(master->device->module); fp@85: ec_master_reset(master); fp@1624: ec_master_idle_start(master); fp@191: out_release: fp@178: master->reserved = 0; fp@191: out_return: fp@178: EC_ERR("Failed requesting master %i.\n", master_index); fp@73: return NULL; fp@27: } fp@27: fp@39: /*****************************************************************************/ fp@33: fp@33: /** fp@195: Releases a reserved EtherCAT master. fp@1618: \ingroup RealtimeInterface fp@195: */ fp@195: fp@195: void ecrt_release_master(ec_master_t *master /**< EtherCAT master */) fp@33: { fp@178: EC_INFO("Releasing master %i...\n", master->index); fp@178: fp@178: if (!master->reserved) { fp@178: EC_ERR("Master %i was never requested!\n", master->index); fp@88: return; fp@88: } fp@88: fp@88: ec_master_reset(master); fp@1624: ec_master_idle_start(master); fp@151: fp@98: module_put(master->device->module); fp@178: master->reserved = 0; fp@178: fp@178: EC_INFO("Released master %i.\n", master->index); fp@88: return; fp@33: } fp@33: fp@39: /*****************************************************************************/ fp@54: fp@1618: /** \cond */ fp@1618: fp@54: module_init(ec_init_module); fp@54: module_exit(ec_cleanup_module); fp@54: fp@104: EXPORT_SYMBOL(ecdev_register); fp@104: EXPORT_SYMBOL(ecdev_unregister); fp@191: EXPORT_SYMBOL(ecdev_start); fp@191: EXPORT_SYMBOL(ecdev_stop); fp@104: EXPORT_SYMBOL(ecrt_request_master); fp@104: EXPORT_SYMBOL(ecrt_release_master); fp@54: fp@1618: /** \endcond */ fp@1618: fp@1618: /*****************************************************************************/