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@792: /** \file fp@792: * EtherCAT master driver module. fp@792: */ fp@199: fp@199: /*****************************************************************************/ fp@199: fp@27: #include fp@27: #include fp@27: #include fp@922: #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@792: #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@806: struct kobject kobj; /**< kobject for master module. */ fp@806: fp@806: static char *main_devices[MAX_MASTERS]; /**< Main devices parameter. */ fp@806: static char *backup_devices[MAX_MASTERS]; /**< Backup devices parameter. */ fp@806: fp@806: static ec_master_t *masters; /**< Array of masters. */ fp@806: static struct semaphore master_sem; /**< Master semaphore. */ fp@806: static unsigned int master_count; /**< Number of masters. */ fp@806: static unsigned int backup_count; /**< Number of backup devices. */ fp@806: fp@922: static dev_t device_number; /**< Device number for cdevs. */ fp@922: fp@806: static uint8_t macs[MAX_MASTERS][2][ETH_ALEN]; /**< MAC addresses. */ fp@806: fp@806: char *ec_master_version_str = EC_MASTER_VERSION; /**< Version string. */ 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@806: module_param_array(main_devices, charp, &master_count, S_IRUGO); fp@806: MODULE_PARM_DESC(main_devices, "MAC addresses of main devices"); fp@806: module_param_array(backup_devices, charp, &backup_count, S_IRUGO); fp@806: MODULE_PARM_DESC(backup_devices, "MAC addresses of backup devices"); fp@195: fp@199: /** \endcond */ fp@199: fp@195: /*****************************************************************************/ fp@195: fp@806: /** Module initialization. fp@806: * fp@922: * Initializes \a master_count masters. fp@639: * \return 0 on success, else < 0 fp@639: */ 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@922: if (alloc_chrdev_region(&device_number, 0, master_count, "EtherCAT")) { fp@922: EC_ERR("Failed to obtain device number(s)!\n"); fp@922: ret = -EBUSY; fp@922: goto out_del; fp@922: } fp@922: 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@806: if (ec_mac_parse(macs[i][0], main_devices[i], 0)) { fp@639: ret = -EINVAL; fp@922: goto out_cdev; fp@639: } fp@573: fp@806: if (i < backup_count && ec_mac_parse(macs[i][1], backup_devices[i], 1)) { fp@639: ret = -EINVAL; fp@922: 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@922: goto out_cdev; fp@639: } fp@639: } fp@639: fp@639: for (i = 0; i < master_count; i++) { fp@922: if (ec_master_init(&masters[i], &kobj, i, macs[i][0], macs[i][1], fp@922: device_number)) { 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@922: out_cdev: fp@922: unregister_chrdev_region(device_number, master_count); 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@806: /** Module cleanup. fp@806: * fp@806: * Clears all master instances. fp@806: */ 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@922: fp@922: unregister_chrdev_region(device_number, master_count); fp@639: 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@758: /** fp@758: * \return true, if two MAC addresses are equal. fp@758: */ fp@840: int ec_mac_equal( fp@840: const uint8_t *mac1, /**< First MAC address. */ fp@840: const uint8_t *mac2 /**< Second MAC address. */ fp@840: ) 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@806: /** Print a MAC address to a buffer. fp@806: * fp@758: * \return number of bytes written. fp@758: */ fp@758: ssize_t ec_mac_print( fp@758: const uint8_t *mac, /**< MAC address */ fp@758: char *buffer /**< target buffer */ fp@758: ) 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@758: /** fp@758: * \return true, if the MAC address is all-zero. fp@758: */ fp@840: int ec_mac_is_zero( fp@840: const uint8_t *mac /**< MAC address. */ fp@840: ) 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@758: /** fp@758: * \return true, if the given MAC address is the broadcast address. fp@758: */ fp@840: int ec_mac_is_broadcast( fp@840: const uint8_t *mac /**< MAC address. */ fp@840: ) fp@700: { fp@700: unsigned int i; fp@700: fp@700: for (i = 0; i < ETH_ALEN; i++) fp@700: if (mac[i] != 0xff) fp@700: return 0; fp@700: fp@700: return 1; fp@700: } fp@700: fp@700: /*****************************************************************************/ fp@700: fp@806: /** Parse a MAC address from a string. fp@806: * fp@758: * The MAC address must follow the regexp fp@758: * "([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}". fp@806: * fp@806: * \return 0 on success, else < 0 fp@806: */ 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@806: /** Outputs frame contents for debugging purposes. fp@806: */ 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@806: /** Outputs frame contents and differences for debugging purposes. fp@806: */ 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@806: /** Prints slave states in clear text. fp@806: */ 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@813: if (states & EC_SLAVE_STATE_SAFEOP) { fp@325: if (!first) off += sprintf(buffer + off, ", "); fp@813: off += sprintf(buffer + off, "SAFEOP"); 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@806: /** Offers an EtherCAT device to a certain master. fp@806: * fp@806: * The master decides, if it wants to use the device for EtherCAT operation, fp@806: * or not. It is important, that the offered net_device is not used by the fp@806: * kernel IP stack. If the master, accepted the offer, the address of the fp@806: * newly created EtherCAT device is written to the ecdev pointer, else the fp@806: * pointer is written to zero. fp@806: * fp@806: * \return 0 on success, else < 0 fp@806: * \ingroup DeviceInterface fp@806: */ 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@700: fp@700: down(&master->device_sem); fp@700: if (master->main_device.dev) { // master already has a device fp@700: up(&master->device_sem); fp@700: continue; fp@700: } fp@700: fp@700: if (ec_mac_equal(master->main_mac, net_dev->dev_addr) fp@700: || ec_mac_is_broadcast(master->main_mac)) { fp@700: ec_mac_print(net_dev->dev_addr, str); fp@578: EC_INFO("Accepting device %s for master %u.\n", fp@578: str, master->index); 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@700: else { fp@700: up(&master->device_sem); fp@700: fp@700: if (master->debug_level) { fp@700: ec_mac_print(net_dev->dev_addr, str); fp@700: EC_DBG("Master %u declined device %s.\n", master->index, str); fp@700: } 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@806: /** Withdraws an EtherCAT device from the master. fp@806: * fp@806: * The device is disconnected from the master and all device ressources fp@806: * are freed. fp@806: * fp@806: * \attention Before calling this function, the ecdev_stop() function has fp@806: * to be called, to be sure that the master does not use the device fp@806: * any more. fp@806: * \ingroup DeviceInterface fp@806: */ 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@700: ec_mac_print(device->dev->dev_addr, str); 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@806: /** Opens the network device and makes the master enter IDLE mode. fp@806: * fp@806: * \return 0 on success, else < 0 fp@806: * \ingroup DeviceInterface fp@806: */ 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@806: /** Makes the master leave IDLE mode and closes the network device. fp@806: * fp@806: * \return 0 on success, else < 0 fp@806: * \ingroup DeviceInterface fp@806: */ 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@792: ec_master_t *ecrt_request_master(unsigned int master_index) 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@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@792: void ecrt_release_master(ec_master_t *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@792: unsigned int ecrt_version_magic(void) fp@792: { fp@792: return ECRT_VERSION_MAGIC; fp@792: } fp@792: fp@792: /*****************************************************************************/ fp@792: 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: /*****************************************************************************/