fp@27: /****************************************************************************** fp@27: * fp@27: * $Id$ fp@27: * 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@246: * as published by the Free Software Foundation; either version 2 of the fp@246: * License, or (at your option) any later version. 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@27: * fp@246: * The right to use EtherCAT Technology is granted and comes free of fp@246: * charge under condition of compatibility of product made by fp@246: * Licensee. People intending to distribute/sell products based on the fp@246: * code, have to sign an agreement to guarantee that products using fp@246: * software based on IgH EtherCAT master stay compatible with the actual fp@246: * EtherCAT specification (which are released themselves as an open fp@246: * standard) as the (only) precondition to have the right to use EtherCAT fp@246: * Technology, IP and trade marks. fp@246: * fp@39: *****************************************************************************/ fp@27: fp@199: /** fp@199: \file fp@199: EtherCAT master driver module. fp@199: */ fp@199: fp@199: /*****************************************************************************/ fp@199: 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@571: #include "xmldev.h" fp@54: fp@54: /*****************************************************************************/ fp@54: fp@639: #define MAX_MASTERS 5 /**< maximum number of masters */ fp@639: fp@639: /*****************************************************************************/ fp@639: fp@54: int __init ec_init_module(void); fp@54: void __exit ec_cleanup_module(void); fp@52: fp@639: static int ec_mac_parse(uint8_t *, const char *, int); fp@639: fp@639: /*****************************************************************************/ fp@639: fp@639: struct kobject kobj; /**< kobject for master module */ fp@639: fp@639: static char *main[MAX_MASTERS]; /**< main devices parameter */ fp@639: static char *backup[MAX_MASTERS]; /**< backup devices parameter */ fp@639: fp@639: static ec_master_t *masters; /**< master array */ fp@647: static struct semaphore master_sem; /**< master semaphore */ fp@639: static unsigned int master_count; /**< number of masters */ fp@639: static unsigned int backup_count; /**< number of backup devices */ fp@639: fp@639: static uint8_t macs[MAX_MASTERS][2][ETH_ALEN]; /**< MAC addresses */ fp@639: fp@571: static dev_t device_number; /**< XML character device number */ fp@571: ec_xmldev_t xmldev; /**< XML character device */ fp@27: fp@444: char *ec_master_version_str = EC_MASTER_VERSION; fp@444: fp@39: /*****************************************************************************/ fp@39: fp@199: /** \cond */ fp@199: fp@251: MODULE_AUTHOR("Florian Pose "); fp@251: MODULE_DESCRIPTION("EtherCAT master driver module"); fp@27: MODULE_LICENSE("GPL"); fp@382: MODULE_VERSION(EC_MASTER_VERSION); fp@573: fp@639: module_param_array(main, charp, &master_count, S_IRUGO); fp@639: MODULE_PARM_DESC(main, "MAC addresses of main devices"); fp@639: module_param_array(backup, charp, &backup_count, S_IRUGO); fp@639: MODULE_PARM_DESC(backup, "MAC addresses of backup devices"); fp@195: fp@199: /** \endcond */ fp@199: fp@195: /*****************************************************************************/ fp@195: fp@195: /** fp@639: * Module initialization. fp@639: * Initializes \a ec_master_count masters. fp@639: * \return 0 on success, else < 0 fp@639: */ fp@54: fp@54: int __init ec_init_module(void) fp@27: { fp@639: int i, ret = 0; fp@73: fp@382: EC_INFO("Master driver %s\n", EC_MASTER_VERSION); fp@73: fp@653: init_MUTEX(&master_sem); fp@653: fp@576: // init kobject and add it to the hierarchy fp@639: memset(&kobj, 0x00, sizeof(struct kobject)); fp@639: kobject_init(&kobj); // no ktype fp@639: fp@639: if (kobject_set_name(&kobj, "ethercat")) { fp@576: EC_ERR("Failed to set module kobject name.\n"); fp@639: ret = -ENOMEM; fp@576: goto out_put; fp@576: } fp@576: fp@639: if (kobject_add(&kobj)) { fp@576: EC_ERR("Failed to add module kobject.\n"); fp@639: ret = -EEXIST; fp@576: goto out_put; fp@576: } fp@576: fp@573: if (alloc_chrdev_region(&device_number, 0, 1, "EtherCAT")) { fp@573: EC_ERR("Failed to obtain device number!\n"); fp@639: ret = -EBUSY; fp@576: goto out_del; fp@361: } fp@361: fp@639: // zero MAC addresses fp@639: memset(macs, 0x00, sizeof(uint8_t) * MAX_MASTERS * 2 * ETH_ALEN); fp@639: fp@639: // process MAC parameters fp@639: for (i = 0; i < master_count; i++) { fp@639: if (ec_mac_parse(macs[i][0], main[i], 0)) { fp@639: ret = -EINVAL; fp@639: goto out_cdev; fp@639: } fp@573: fp@639: if (i < backup_count && ec_mac_parse(macs[i][1], backup[i], 1)) { fp@639: ret = -EINVAL; fp@639: goto out_cdev; fp@639: } fp@639: } fp@639: fp@639: if (master_count) { fp@639: if (!(masters = kmalloc(sizeof(ec_master_t) * master_count, fp@639: GFP_KERNEL))) { fp@639: EC_ERR("Failed to allocate memory for EtherCAT masters.\n"); fp@639: ret = -ENOMEM; fp@639: goto out_cdev; fp@639: } fp@639: } fp@639: fp@639: for (i = 0; i < master_count; i++) { fp@639: if (ec_master_init(&masters[i], &kobj, i, macs[i][0], macs[i][1])) { fp@639: ret = -EIO; fp@639: goto out_free_masters; fp@573: } fp@573: } fp@573: fp@573: EC_INFO("%u master%s waiting for devices.\n", fp@639: master_count, (master_count == 1 ? "" : "s")); fp@639: return ret; fp@127: fp@573: out_free_masters: fp@639: for (i--; i >= 0; i--) ec_master_clear(&masters[i]); fp@639: kfree(masters); fp@575: out_cdev: fp@573: unregister_chrdev_region(device_number, 1); fp@576: out_del: fp@639: kobject_del(&kobj); fp@576: out_put: fp@639: kobject_put(&kobj); fp@639: return ret; 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@639: unsigned int i; fp@639: fp@639: for (i = 0; i < master_count; i++) { fp@639: ec_master_clear(&masters[i]); fp@639: } fp@639: if (master_count) fp@639: kfree(masters); fp@639: fp@573: unregister_chrdev_region(device_number, 1); fp@639: kobject_del(&kobj); fp@639: kobject_put(&kobj); fp@361: fp@575: EC_INFO("Master module cleaned up.\n"); fp@27: } fp@27: fp@639: /***************************************************************************** fp@639: * MAC address functions fp@639: ****************************************************************************/ fp@639: fp@639: int ec_mac_equal(const uint8_t *mac1, const uint8_t *mac2) fp@639: { fp@639: unsigned int i; fp@639: fp@639: for (i = 0; i < ETH_ALEN; i++) fp@639: if (mac1[i] != mac2[i]) fp@639: return 0; fp@639: fp@639: return 1; fp@639: } fp@639: fp@639: /*****************************************************************************/ fp@639: fp@639: ssize_t ec_mac_print(const uint8_t *mac, char *buffer) fp@639: { fp@639: off_t off = 0; fp@639: unsigned int i; fp@639: fp@639: for (i = 0; i < ETH_ALEN; i++) { fp@639: off += sprintf(buffer + off, "%02X", mac[i]); fp@639: if (i < ETH_ALEN - 1) off += sprintf(buffer + off, ":"); fp@639: } fp@639: fp@639: return off; fp@639: } fp@639: fp@639: /*****************************************************************************/ fp@639: fp@639: int ec_mac_is_zero(const uint8_t *mac) fp@639: { fp@639: unsigned int i; fp@639: fp@639: for (i = 0; i < ETH_ALEN; i++) fp@639: if (mac[i]) fp@639: return 0; fp@639: fp@639: return 1; fp@639: } fp@639: fp@639: /*****************************************************************************/ fp@639: fp@639: static int ec_mac_parse(uint8_t *mac, const char *src, int allow_empty) fp@639: { fp@639: unsigned int i, value; fp@639: const char *orig = src; fp@639: char *rem; fp@639: fp@639: if (!strlen(src)) { fp@639: if (allow_empty){ fp@639: return 0; fp@639: } fp@639: else { fp@639: EC_ERR("MAC address may not be empty.\n"); fp@639: return -EINVAL; fp@639: } fp@639: } fp@639: fp@639: for (i = 0; i < ETH_ALEN; i++) { fp@639: value = simple_strtoul(src, &rem, 16); fp@639: if (rem != src + 2 fp@639: || value > 0xFF fp@639: || (i < ETH_ALEN - 1 && *rem != ':')) { fp@639: EC_ERR("Invalid MAC address \"%s\".\n", orig); fp@639: return -EINVAL; fp@639: } fp@639: mac[i] = value; fp@639: if (i < ETH_ALEN - 1) fp@639: src = rem + 1; // skip colon fp@639: } fp@639: fp@639: return 0; fp@178: } fp@178: fp@196: /*****************************************************************************/ fp@196: fp@196: /** fp@196: Outputs frame contents for debugging purposes. fp@196: */ fp@196: fp@196: void ec_print_data(const uint8_t *data, /**< pointer to data */ fp@196: size_t size /**< number of bytes to output */ fp@196: ) fp@196: { fp@196: unsigned int i; fp@196: fp@196: EC_DBG(""); fp@196: for (i = 0; i < size; i++) { fp@196: printk("%02X ", data[i]); fp@196: if ((i + 1) % 16 == 0) { fp@196: printk("\n"); fp@196: EC_DBG(""); fp@196: } fp@196: } fp@196: printk("\n"); fp@196: } fp@196: fp@196: /*****************************************************************************/ fp@196: fp@196: /** fp@196: Outputs frame contents and differences for debugging purposes. fp@196: */ fp@196: fp@196: void ec_print_data_diff(const uint8_t *d1, /**< first data */ fp@196: const uint8_t *d2, /**< second data */ fp@196: size_t size /** number of bytes to output */ fp@196: ) fp@196: { fp@196: unsigned int i; fp@196: fp@196: EC_DBG(""); fp@196: for (i = 0; i < size; i++) { fp@196: if (d1[i] == d2[i]) printk(".. "); fp@196: else printk("%02X ", d2[i]); fp@196: if ((i + 1) % 16 == 0) { fp@196: printk("\n"); fp@196: EC_DBG(""); fp@196: } fp@196: } fp@196: printk("\n"); fp@196: } fp@196: fp@251: /*****************************************************************************/ fp@251: fp@251: /** fp@251: Prints slave states in clear text. fp@251: */ fp@251: fp@325: size_t ec_state_string(uint8_t states, /**< slave states */ fp@403: char *buffer /**< target buffer fp@403: (min. EC_STATE_STRING_SIZE bytes) */ fp@325: ) fp@325: { fp@325: off_t off = 0; fp@251: unsigned int first = 1; fp@251: fp@251: if (!states) { fp@325: off += sprintf(buffer + off, "(unknown)"); fp@325: return off; fp@251: } fp@251: fp@251: if (states & EC_SLAVE_STATE_INIT) { fp@325: off += sprintf(buffer + off, "INIT"); fp@251: first = 0; fp@251: } fp@251: if (states & EC_SLAVE_STATE_PREOP) { fp@325: if (!first) off += sprintf(buffer + off, ", "); fp@325: off += sprintf(buffer + off, "PREOP"); fp@251: first = 0; fp@251: } fp@251: if (states & EC_SLAVE_STATE_SAVEOP) { fp@325: if (!first) off += sprintf(buffer + off, ", "); fp@325: off += sprintf(buffer + off, "SAVEOP"); fp@251: first = 0; fp@251: } fp@251: if (states & EC_SLAVE_STATE_OP) { fp@325: if (!first) off += sprintf(buffer + off, ", "); fp@325: off += sprintf(buffer + off, "OP"); fp@325: } fp@403: if (states & EC_SLAVE_STATE_ACK_ERR) { fp@453: if (!first) off += sprintf(buffer + off, " + "); fp@453: off += sprintf(buffer + off, "ERROR"); fp@403: } fp@325: fp@325: return off; fp@251: } fp@251: fp@54: /****************************************************************************** fp@195: * Device interface fp@54: *****************************************************************************/ fp@33: fp@33: /** fp@573: Offers an EtherCAT device to a certain master. fp@573: The master decides, if it wants to use the device for EtherCAT operation, fp@573: or not. It is important, that the offered net_device is not used by fp@573: the kernel IP stack. If the master, accepted the offer, the address of fp@573: the newly created EtherCAT device is written to the ecdev pointer, else fp@573: the pointer is written to zero. fp@195: \return 0 on success, else < 0 fp@199: \ingroup DeviceInterface fp@195: */ fp@195: fp@573: int ecdev_offer(struct net_device *net_dev, /**< net_device to offer */ fp@573: ec_pollfunc_t poll, /**< device poll function */ fp@639: struct module *module, /**< pointer to the module */ fp@639: ec_device_t **ecdev /**< pointer to store a device on success */ fp@573: ) fp@91: { fp@73: ec_master_t *master; fp@639: char str[20]; fp@639: unsigned int i; fp@639: fp@639: for (i = 0; i < master_count; i++) { fp@639: master = &masters[i]; fp@639: if (ec_mac_equal(master->main_mac, net_dev->dev_addr)) { fp@639: ec_mac_print(master->main_mac, str); fp@578: EC_INFO("Accepting device %s for master %u.\n", fp@578: str, master->index); fp@573: fp@648: down(&master->device_sem); fp@579: if (master->main_device.dev) { fp@579: EC_ERR("Master %u already has a device attached.\n", fp@579: master->index); fp@579: up(&master->device_sem); fp@579: return -1; fp@573: } fp@573: fp@579: ec_device_attach(&master->main_device, net_dev, poll, module); fp@573: up(&master->device_sem); fp@579: fp@573: sprintf(net_dev->name, "ec%u", master->index); fp@579: *ecdev = &master->main_device; // offer accepted fp@573: return 0; // no error fp@573: } fp@639: else if (master->debug_level) { fp@639: ec_mac_print(master->main_mac, str); fp@639: EC_DBG("Master %u declined device %s.\n", master->index, str); fp@639: } fp@573: } fp@573: fp@573: *ecdev = NULL; // offer declined fp@573: return 0; // no error fp@573: } fp@573: fp@573: /*****************************************************************************/ fp@573: fp@573: /** fp@573: Withdraws an EtherCAT device from the master. fp@199: The device is disconnected from the master and all device ressources fp@199: are freed. fp@199: \attention Before calling this function, the ecdev_stop() function has fp@199: to be called, to be sure that the master does not use the device any more. fp@199: \ingroup DeviceInterface fp@195: */ fp@195: fp@573: void ecdev_withdraw(ec_device_t *device /**< EtherCAT device */) fp@573: { fp@573: ec_master_t *master = device->master; fp@639: char str[20]; fp@639: fp@639: ec_mac_print(master->main_mac, str); fp@578: fp@578: EC_INFO("Master %u releasing main device %s.\n", master->index, str); fp@578: fp@381: down(&master->device_sem); fp@579: ec_device_detach(device); fp@381: up(&master->device_sem); fp@54: } fp@54: fp@497: /*****************************************************************************/ fp@497: fp@497: /** fp@497: Opens the network device and makes the master enter IDLE mode. fp@497: \return 0 on success, else < 0 fp@497: \ingroup DeviceInterface fp@497: */ fp@497: fp@497: int ecdev_open(ec_device_t *device /**< EtherCAT device */) fp@497: { fp@497: if (ec_device_open(device)) { fp@497: EC_ERR("Failed to open device!\n"); fp@497: return -1; fp@497: } fp@497: fp@525: if (ec_master_enter_idle_mode(device->master)) { fp@525: EC_ERR("Failed to enter idle mode!\n"); fp@525: return -1; fp@525: } fp@525: fp@497: return 0; fp@497: } fp@497: fp@497: /*****************************************************************************/ fp@497: fp@497: /** fp@497: Makes the master leave IDLE mode and closes the network device. fp@497: \return 0 on success, else < 0 fp@497: \ingroup DeviceInterface fp@497: */ fp@497: fp@497: void ecdev_close(ec_device_t *device /**< EtherCAT device */) fp@497: { fp@497: ec_master_leave_idle_mode(device->master); fp@497: fp@497: if (ec_device_close(device)) fp@497: EC_WARN("Failed to close device!\n"); fp@497: } fp@497: fp@54: /****************************************************************************** fp@195: * Realtime interface fp@54: *****************************************************************************/ fp@33: fp@33: /** fp@541: * Returns the version magic of the realtime interface. fp@541: * \return ECRT version magic. fp@541: * \ingroup RealtimeInterface fp@541: */ fp@541: fp@541: unsigned int ecrt_version_magic(void) fp@541: { fp@541: return ECRT_VERSION_MAGIC; fp@541: } fp@541: fp@541: /*****************************************************************************/ fp@541: fp@541: /** fp@195: Reserves an EtherCAT master for realtime operation. fp@195: \return pointer to reserved master, or NULL on error fp@199: \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@647: EC_INFO("Requesting master %u...\n", master_index); fp@178: fp@639: if (master_index >= master_count) { fp@639: EC_ERR("Invalid master index %u.\n", master_index); fp@639: goto out_return; fp@639: } fp@639: master = &masters[master_index]; fp@178: fp@647: down(&master_sem); fp@647: if (master->reserved) { fp@647: up(&master_sem); fp@647: EC_ERR("Master %u is already in use!\n", master_index); fp@191: goto out_return; fp@73: } fp@647: master->reserved = 1; fp@647: up(&master_sem); fp@73: fp@648: down(&master->device_sem); fp@648: fp@579: if (master->mode != EC_MASTER_MODE_IDLE) { fp@381: up(&master->device_sem); fp@647: EC_ERR("Master %u still waiting for devices!\n", master_index); fp@191: goto out_release; fp@73: } fp@73: fp@579: if (!try_module_get(master->main_device.module)) { fp@381: up(&master->device_sem); fp@381: EC_ERR("Device module is unloading!\n"); fp@191: goto out_release; fp@191: } fp@191: fp@381: up(&master->device_sem); fp@381: fp@579: if (!master->main_device.link_state) { fp@377: EC_ERR("Link is DOWN.\n"); fp@377: goto out_module_put; fp@377: } fp@377: fp@446: if (ec_master_enter_operation_mode(master)) { fp@446: EC_ERR("Failed to enter OPERATION mode!\n"); fp@446: goto out_module_put; fp@377: } fp@377: fp@647: EC_INFO("Successfully requested master %u.\n", master_index); fp@73: return master; fp@54: fp@191: out_module_put: fp@579: module_put(master->main_device.module); fp@191: out_release: fp@647: master->reserved = 0; fp@191: out_return: fp@73: return NULL; fp@27: } fp@27: fp@39: /*****************************************************************************/ fp@33: fp@33: /** fp@195: Releases a reserved EtherCAT master. fp@199: \ingroup RealtimeInterface fp@195: */ fp@195: fp@195: void ecrt_release_master(ec_master_t *master /**< EtherCAT master */) fp@33: { fp@647: EC_INFO("Releasing master %u...\n", master->index); fp@531: fp@531: if (master->mode != EC_MASTER_MODE_OPERATION) { fp@647: EC_WARN("Master %u was was not requested!\n", master->index); fp@531: return; fp@531: } fp@531: fp@446: ec_master_leave_operation_mode(master); fp@151: fp@579: module_put(master->main_device.module); fp@647: master->reserved = 0; fp@647: fp@647: EC_INFO("Released master %u.\n", master->index); fp@33: } fp@33: fp@39: /*****************************************************************************/ fp@54: fp@199: /** \cond */ fp@199: fp@54: module_init(ec_init_module); fp@54: module_exit(ec_cleanup_module); fp@54: fp@573: EXPORT_SYMBOL(ecdev_offer); fp@573: EXPORT_SYMBOL(ecdev_withdraw); fp@497: EXPORT_SYMBOL(ecdev_open); fp@497: EXPORT_SYMBOL(ecdev_close); fp@104: EXPORT_SYMBOL(ecrt_request_master); fp@104: EXPORT_SYMBOL(ecrt_release_master); fp@545: EXPORT_SYMBOL(ecrt_version_magic); fp@54: fp@199: /** \endcond */ fp@199: fp@199: /*****************************************************************************/