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 <linux/module.h>
fp@1014: #include <linux/device.h>
fp@1239: #include <linux/err.h>
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: 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@954: dev_t device_number; /**< Device number for master cdevs. */
fp@1012: struct class *class; /**< Device class. */
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@igh-essen.com>");
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@997:     if (master_count) {
fp@997:         if (alloc_chrdev_region(&device_number, 0, master_count, "EtherCAT")) {
fp@997:             EC_ERR("Failed to obtain device number(s)!\n");
fp@997:             ret = -EBUSY;
fp@997:             goto out_return;
fp@997:         }
fp@922:     }
fp@922: 
fp@1012:     class = class_create(THIS_MODULE, "EtherCAT");
fp@1012:     if (IS_ERR(class)) {
fp@1012:         EC_ERR("Failed to create device class.\n");
fp@1313:         ret = PTR_ERR(class);
fp@1012:         goto out_cdev;
fp@1012:     }
fp@1012: 
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@1313:         ret = ec_mac_parse(macs[i][0], main_devices[i], 0);
fp@1313:         if (ret)
fp@1012:             goto out_class;
fp@573:         
fp@1313:         if (i < backup_count) {
fp@1313:             ret = ec_mac_parse(macs[i][1], backup_devices[i], 1);
fp@1313:             if (ret)
fp@1313:                 goto out_class;
fp@639:         }
fp@639:     }
fp@1279: 
fp@1279:     // initialize static master variables
fp@1279:     ec_master_init_static();
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@1012:             goto out_class;
fp@639:         }
fp@639:     }
fp@639:     
fp@639:     for (i = 0; i < master_count; i++) {
fp@1313:         ret = ec_master_init(&masters[i], i, macs[i][0], macs[i][1],
fp@1313:                     device_number, class);
fp@1313:         if (ret)
fp@639:             goto out_free_masters;
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@997:     for (i--; i >= 0; i--)
fp@997:         ec_master_clear(&masters[i]);
fp@639:     kfree(masters);
fp@1012: out_class:
fp@1012:     class_destroy(class);
fp@922: out_cdev:
fp@1012:     if (master_count)
fp@1012:         unregister_chrdev_region(device_number, master_count);
fp@997: out_return:
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@1012: 
fp@1012:     if (master_count)
fp@639:         kfree(masters);
fp@1012:     
fp@1012:     class_destroy(class);
fp@1012:     
fp@1012:     if (master_count)
fp@997:         unregister_chrdev_region(device_number, master_count);
fp@997:     
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@1011:  * newly created EtherCAT device is returned, else \a NULL is returned.
fp@1011:  *
fp@1011:  * \return Pointer to device, if accepted, or NULL if declined.
fp@806:  * \ingroup DeviceInterface
fp@806:  */
fp@1011: ec_device_t *ecdev_offer(
fp@1011:         struct net_device *net_dev, /**< net_device to offer */
fp@573:         ec_pollfunc_t poll, /**< device poll function */
fp@1011:         struct module *module /**< pointer to the module */
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@1011:             return &master->main_device; // offer accepted
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@1011:     return NULL; // offer declined
fp@497: }
fp@497: 
fp@54: /******************************************************************************
fp@195:  *  Realtime interface
fp@54:  *****************************************************************************/
fp@33: 
fp@1312: /** Request a master.
fp@1312:  *
fp@1312:  * Same as ecrt_request_master(), but with ERR_PTR() return value.
fp@1312:  */
fp@1312: ec_master_t *ecrt_request_master_err(unsigned int master_index)
fp@54: {
fp@1239:     ec_master_t *master, *errptr = NULL;
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@1239:         errptr = ERR_PTR(-EINVAL);
fp@639:         goto out_return;
fp@639:     }
fp@639:     master = &masters[master_index];
fp@178: 
fp@1239:     if (down_interruptible(&master_sem)) {
fp@1239:         errptr = ERR_PTR(-EINTR);
fp@1189:         goto out_return;
fp@1239:     }
fp@1189: 
fp@647:     if (master->reserved) {
fp@647:         up(&master_sem);
fp@647:         EC_ERR("Master %u is already in use!\n", master_index);
fp@1239:         errptr = ERR_PTR(-EBUSY);
fp@191:         goto out_return;
fp@73:     }
fp@647:     master->reserved = 1;
fp@647:     up(&master_sem);
fp@73: 
fp@1239:     if (down_interruptible(&master->device_sem)) {
fp@1239:         errptr = ERR_PTR(-EINTR);
fp@1189:         goto out_release;
fp@1239:     }
fp@648:     
fp@1029:     if (master->phase != EC_IDLE) {
fp@381:         up(&master->device_sem);
fp@647:         EC_ERR("Master %u still waiting for devices!\n", master_index);
fp@1239:         errptr = ERR_PTR(-ENODEV);
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@1239:         errptr = ERR_PTR(-ENODEV);
fp@191:         goto out_release;
fp@191:     }
fp@191: 
fp@381:     up(&master->device_sem);
fp@381: 
fp@1029:     if (ec_master_enter_operation_phase(master)) {
fp@1029:         EC_ERR("Failed to enter OPERATION phase!\n");
fp@1239:         errptr = ERR_PTR(-EIO);
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@1239:     return errptr;
fp@27: }
fp@27: 
fp@39: /*****************************************************************************/
fp@33: 
fp@1312: ec_master_t *ecrt_request_master(unsigned int master_index)
fp@1312: {
fp@1312:     ec_master_t *master = ecrt_request_master_err(master_index);
fp@1312:     return IS_ERR(master) ? NULL : master;
fp@1312: }
fp@1312: 
fp@1312: /*****************************************************************************/
fp@1312: 
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@997:     if (!master->reserved) {
fp@647:         EC_WARN("Master %u was was not requested!\n", master->index);
fp@531:         return;
fp@531:     }
fp@531: 
fp@1029:     ec_master_leave_operation_phase(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@1209: /** Global request state type translation table.
fp@1209:  *
fp@1209:  * Translates an internal request state to an external one.
fp@1209:  */
fp@1209: const ec_request_state_t ec_request_state_translation_table[] = {
fp@1209:     EC_REQUEST_UNUSED,  // EC_INT_REQUEST_INIT,
fp@1209:     EC_REQUEST_BUSY,    // EC_INT_REQUEST_QUEUED,
fp@1209:     EC_REQUEST_BUSY,    // EC_INT_REQUEST_BUSY,
fp@1209:     EC_REQUEST_SUCCESS, // EC_INT_REQUEST_SUCCESS,
fp@1209:     EC_REQUEST_ERROR    // EC_INT_REQUEST_FAILURE
fp@1209: };
fp@1209: 
fp@1209: /*****************************************************************************/
fp@1209: 
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@997: 
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: /*****************************************************************************/