diff --git a/master/master.c b/master/master.c index 37a3e7c33eedb155e23939c1acd58faca086d1a6..b96bd190dc780d49844bb06d7967e8a9cb564430 100644 --- a/master/master.c +++ b/master/master.c @@ -109,6 +109,7 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */ master->index = index; master->device = NULL; + init_MUTEX(&master->device_sem); atomic_set(&master->available, 1); INIT_LIST_HEAD(&master->slaves); INIT_LIST_HEAD(&master->datagram_queue); diff --git a/master/master.h b/master/master.h index 31caa5b8ce9d4d9675ed102ab994e39bb7c35e94..e706089f9333724054fa6646870d958ab509ac29 100644 --- a/master/master.h +++ b/master/master.h @@ -45,6 +45,7 @@ #include <linux/sysfs.h> #include <linux/timer.h> #include <asm/atomic.h> +#include <asm/semaphore.h> #include "device.h" #include "domain.h" @@ -99,6 +100,7 @@ struct ec_master struct kobject kobj; /**< kobject */ ec_device_t *device; /**< EtherCAT device */ + struct semaphore device_sem; /**< device semaphore */ ec_xmldev_t xmldev; /**< XML character device */ diff --git a/master/module.c b/master/module.c index 47996cf36ba3eedf3bb7a41a504a551ab8c476f5..a78db34594e2244a0baa4e80f81fb78ff5e2e50f 100644 --- a/master/module.c +++ b/master/module.c @@ -290,15 +290,20 @@ ec_device_t *ecdev_register(unsigned int master_index, /**< master index */ if (!(master = ec_find_master(master_index))) return NULL; + if (down_interruptible(&master->device_sem)) { + EC_ERR("Interrupted while waiting for device!\n"); + goto out_return; + } + if (master->device) { EC_ERR("Master %i already has a device!\n", master_index); - goto out_return; + goto out_up; } if (!(master->device = (ec_device_t *) kmalloc(sizeof(ec_device_t), GFP_KERNEL))) { EC_ERR("Failed to allocate device!\n"); - goto out_return; + goto out_up; } if (ec_device_init(master->device, master, net_dev, isr, module)) { @@ -306,11 +311,14 @@ ec_device_t *ecdev_register(unsigned int master_index, /**< master index */ goto out_free; } + up(&master->device_sem); return master->device; out_free: kfree(master->device); master->device = NULL; + out_up: + up(&master->device_sem); out_return: return NULL; } @@ -334,7 +342,10 @@ void ecdev_unregister(unsigned int master_index, /**< master index */ if (!(master = ec_find_master(master_index))) return; + down(&master->device_sem); + if (!master->device || master->device != device) { + up(&master->device_sem); EC_WARN("Unable to unregister device!\n"); return; } @@ -342,6 +353,8 @@ void ecdev_unregister(unsigned int master_index, /**< master index */ ec_device_clear(master->device); kfree(master->device); master->device = NULL; + + up(&master->device_sem); } /*****************************************************************************/ @@ -415,16 +428,25 @@ ec_master_t *ecrt_request_master(unsigned int master_index goto out_return; } + if (down_interruptible(&master->device_sem)) { + EC_ERR("Interrupted while waiting for device!\n"); + goto out_release; + } + if (!master->device) { + up(&master->device_sem); EC_ERR("Master %i has no assigned device!\n", master_index); goto out_release; } - if (!try_module_get(master->device->module)) { // possible race? - EC_ERR("Failed to reserve device module!\n"); + if (!try_module_get(master->device->module)) { + up(&master->device_sem); + EC_ERR("Device module is unloading!\n"); goto out_release; } + up(&master->device_sem); + if (!master->device->link_state) { EC_ERR("Link is DOWN.\n"); goto out_module_put;