diff --git a/master/canopen.c b/master/canopen.c index 6c726c222475efaf1a37096576da5720d7a75428..ad144d8b9500e9b29f0e63fff94651c9b62a1ce1 100644 --- a/master/canopen.c +++ b/master/canopen.c @@ -132,20 +132,36 @@ int ec_sdo_init(ec_sdo_t *sdo, /**< SDO */ /** SDO destructor. + Clears and frees an SDO object. */ -void ec_sdo_clear(struct kobject *kobj /**< SDO's kobject */) +void ec_sdo_destroy(ec_sdo_t *sdo /**< SDO */) { - ec_sdo_t *sdo = container_of(kobj, ec_sdo_t, kobj); ec_sdo_entry_t *entry, *next; // free all entries list_for_each_entry_safe(entry, next, &sdo->entries, list) { list_del(&entry->list); - kobject_del(&entry->kobj); - kobject_put(&entry->kobj); + ec_sdo_entry_destroy(entry); } + // destroy self + kobject_del(&sdo->kobj); + kobject_put(&sdo->kobj); +} + +/*****************************************************************************/ + +/** + Clear and free SDO. + This method is called by the kobject, + once there are no more references to it. +*/ + +void ec_sdo_clear(struct kobject *kobj /**< SDO's kobject */) +{ + ec_sdo_t *sdo = container_of(kobj, ec_sdo_t, kobj); + if (sdo->name) kfree(sdo->name); kfree(sdo); @@ -215,7 +231,23 @@ int ec_sdo_entry_init(ec_sdo_entry_t *entry, /**< SDO entry */ /*****************************************************************************/ /** - SDO destructor. + SDO entry destructor. + Clears and frees an SDO entry object. +*/ + +void ec_sdo_entry_destroy(ec_sdo_entry_t *entry /**< SDO entry */) +{ + // destroy self + kobject_del(&entry->kobj); + kobject_put(&entry->kobj); +} + +/*****************************************************************************/ + +/** + Clear and free SDO entry. + This method is called by the kobject, + once there are no more references to it. */ void ec_sdo_entry_clear(struct kobject *kobj /**< SDO entry's kobject */) diff --git a/master/canopen.h b/master/canopen.h index 3720abde865ef88255cf249312d6e6605a129021..ec78e84dfc93b97c89603e9cca8a5718eae4c9c3 100644 --- a/master/canopen.h +++ b/master/canopen.h @@ -120,7 +120,10 @@ ec_sdo_request_t; /*****************************************************************************/ int ec_sdo_init(ec_sdo_t *, uint16_t, ec_slave_t *); +void ec_sdo_destroy(ec_sdo_t *); + int ec_sdo_entry_init(ec_sdo_entry_t *, uint8_t, ec_sdo_t *); +void ec_sdo_entry_destroy(ec_sdo_entry_t *); /*****************************************************************************/ diff --git a/master/domain.c b/master/domain.c index 0776939fd36b6fcdcb9d3160f5d737bf950ff939..f15fcf6bf38209df44387bdd664709d701ef2b52 100644 --- a/master/domain.c +++ b/master/domain.c @@ -130,6 +130,30 @@ int ec_domain_init(ec_domain_t *domain, /**< EtherCAT domain */ /** Domain destructor. + Clears and frees a domain object. +*/ + +void ec_domain_destroy(ec_domain_t *domain /**< EtherCAT domain */) +{ + ec_datagram_t *datagram; + + // dequeue datagrams + list_for_each_entry(datagram, &domain->datagrams, list) { + if (!list_empty(&datagram->queue)) // datagram queued? + list_del_init(&datagram->queue); + } + + // destroy self + kobject_del(&domain->kobj); + kobject_put(&domain->kobj); +} + +/*****************************************************************************/ + +/** + Clear and free domain. + This method is called by the kobject, + once there are no more references to it. */ void ec_domain_clear(struct kobject *kobj /**< kobject of the domain */) @@ -463,22 +487,6 @@ void ec_domain_queue_datagrams(ec_domain_t *domain /**< EtherCAT domain */) /*****************************************************************************/ -/** - Dequeues all datagrams from the masters datagram queue. -*/ - -void ec_domain_dequeue_datagrams(ec_domain_t *domain /**< EtherCAT domain */) -{ - ec_datagram_t *datagram; - - list_for_each_entry(datagram, &domain->datagrams, list) { - if (!list_empty(&datagram->queue)) // datagram queued? - list_del_init(&datagram->queue); - } -} - -/*****************************************************************************/ - /** Formats attribute data for SysFS reading. \return number of bytes to read diff --git a/master/domain.h b/master/domain.h index fc4d79296838eb40efaa99d94f1d17d4704e577d..d6a5cdf1f909fc311e5c273b5ed5f4bd03f8c5a8 100644 --- a/master/domain.h +++ b/master/domain.h @@ -76,11 +76,10 @@ struct ec_domain /*****************************************************************************/ int ec_domain_init(ec_domain_t *, ec_master_t *, unsigned int); +void ec_domain_destroy(ec_domain_t *); int ec_domain_alloc(ec_domain_t *, uint32_t); - void ec_domain_queue_datagrams(ec_domain_t *); -void ec_domain_dequeue_datagrams(ec_domain_t *); /*****************************************************************************/ diff --git a/master/fsm.c b/master/fsm.c index 461f4726ae72745eae243a5121c96c052b0df02c..b5aff0817b26b573622447061289456667843378 100644 --- a/master/fsm.c +++ b/master/fsm.c @@ -226,7 +226,7 @@ void ec_fsm_master_broadcast(ec_fsm_t *fsm /**< finite state machine */) if (topology_change && master->mode == EC_MASTER_MODE_IDLE) { ec_master_eoe_stop(master); - ec_master_clear_slaves(master); + ec_master_destroy_slaves(master); master->slave_count = datagram->working_counter; @@ -241,14 +241,14 @@ void ec_fsm_master_broadcast(ec_fsm_t *fsm /**< finite state machine */) if (!(slave = (ec_slave_t *) kmalloc(sizeof(ec_slave_t), GFP_ATOMIC))) { EC_ERR("Failed to allocate slave %i!\n", i); - ec_master_clear_slaves(master); + ec_master_destroy_slaves(master); fsm->master_state = ec_fsm_master_error; return; } if (ec_slave_init(slave, master, i, i + 1)) { // freeing of "slave" already done - ec_master_clear_slaves(master); + ec_master_destroy_slaves(master); fsm->master_state = ec_fsm_master_error; return; } @@ -256,7 +256,7 @@ void ec_fsm_master_broadcast(ec_fsm_t *fsm /**< finite state machine */) if (kobject_add(&slave->kobj)) { EC_ERR("Failed to add kobject.\n"); kobject_put(&slave->kobj); // free - ec_master_clear_slaves(master); + ec_master_destroy_slaves(master); fsm->master_state = ec_fsm_master_error; return; } diff --git a/master/master.c b/master/master.c index 1072ca6a8dfc0579978ca68462f8b579593be905..388118d0387b419e8664c81e80529d92bfe58e8c 100644 --- a/master/master.c +++ b/master/master.c @@ -55,6 +55,7 @@ /*****************************************************************************/ void ec_master_clear(struct kobject *); +void ec_master_destroy_domains(ec_master_t *); void ec_master_sync_io(ec_master_t *); void ec_master_idle_run(void *); void ec_master_eoe_run(unsigned long); @@ -222,8 +223,25 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */ /** Master destructor. - Removes all pending datagrams, clears the slave list, clears all domains - and frees the device. + Clears the kobj-hierarchy bottom up and frees the master. +*/ + +void ec_master_destroy(ec_master_t *master /**< EtherCAT master */) +{ + ec_master_destroy_slaves(master); + ec_master_destroy_domains(master); + + // destroy self + kobject_del(&master->kobj); + kobject_put(&master->kobj); // free master +} + +/*****************************************************************************/ + +/** + Clear and free master. + This method is called by the kobject, + once there are no more references to it. */ void ec_master_clear(struct kobject *kobj /**< kobject of the master */) @@ -232,8 +250,6 @@ void ec_master_clear(struct kobject *kobj /**< kobject of the master */) ec_eoe_t *eoe, *next_eoe; ec_datagram_t *datagram, *next_c; - ec_master_clear_slaves(master); - // empty datagram queue list_for_each_entry_safe(datagram, next_c, &master->datagram_queue, queue) { @@ -252,7 +268,7 @@ void ec_master_clear(struct kobject *kobj /**< kobject of the master */) kfree(eoe); } - EC_INFO("Master %i cleared.\n", master->index); + EC_INFO("Master %i freed.\n", master->index); kfree(master); } @@ -260,17 +276,16 @@ void ec_master_clear(struct kobject *kobj /**< kobject of the master */) /*****************************************************************************/ /** - Clears all slaves. + Destroy all slaves. */ -void ec_master_clear_slaves(ec_master_t *master) +void ec_master_destroy_slaves(ec_master_t *master) { ec_slave_t *slave, *next_slave; list_for_each_entry_safe(slave, next_slave, &master->slaves, list) { list_del(&slave->list); - kobject_del(&slave->kobj); - kobject_put(&slave->kobj); + ec_slave_destroy(slave); } master->slave_count = 0; @@ -278,6 +293,22 @@ void ec_master_clear_slaves(ec_master_t *master) /*****************************************************************************/ +/** + Destroy all domains. +*/ + +void ec_master_destroy_domains(ec_master_t *master) +{ + ec_domain_t *domain, *next_d; + + list_for_each_entry_safe(domain, next_d, &master->domains, list) { + list_del(&domain->list); + ec_domain_destroy(domain); + } +} + +/*****************************************************************************/ + /** Flushes the SDO request queue. */ @@ -386,15 +417,8 @@ void ec_master_leave_operation_mode(ec_master_t *master /**< EtherCAT master */) { ec_slave_t *slave; - ec_domain_t *domain, *next_d; - // clear domains - list_for_each_entry_safe(domain, next_d, &master->domains, list) { - ec_domain_dequeue_datagrams(domain); - list_del(&domain->list); - kobject_del(&domain->kobj); - kobject_put(&domain->kobj); - } + ec_master_destroy_domains(master); master->request_cb = NULL; master->release_cb = NULL; diff --git a/master/master.h b/master/master.h index 946a4f046ba07004f533e68a5516ce8603278f02..a27154d5a020c9073ee89729c91cddab47d1e80b 100644 --- a/master/master.h +++ b/master/master.h @@ -148,8 +148,9 @@ struct ec_master /*****************************************************************************/ -// master creation +// master creation/deletion int ec_master_init(ec_master_t *, unsigned int, unsigned int, dev_t); +void ec_master_destroy(ec_master_t *); // mode transitions int ec_master_enter_idle_mode(ec_master_t *); @@ -167,7 +168,7 @@ void ec_master_queue_datagram(ec_master_t *, ec_datagram_t *); // misc. void ec_master_output_stats(ec_master_t *); -void ec_master_clear_slaves(ec_master_t *); +void ec_master_destroy_slaves(ec_master_t *); void ec_master_calc_addressing(ec_master_t *); // helper functions diff --git a/master/module.c b/master/module.c index b5d5a63f0833274d2534f9378f22cc26521fc80a..9f115684ae305c5ab21e3bd7f4abbebbe010a8e8 100644 --- a/master/module.c +++ b/master/module.c @@ -152,8 +152,7 @@ void __exit ec_cleanup_module(void) list_for_each_entry_safe(master, next, &ec_masters, list) { list_del(&master->list); - kobject_del(&master->kobj); - kobject_put(&master->kobj); // free master + ec_master_destroy(master); } unregister_chrdev_region(device_number, ec_master_count); diff --git a/master/slave.c b/master/slave.c index e27d00a61d5584fbb06490d6c2afe100039a48d3..038f0d603b4a647a04e9ba62b2637d0be4d06c78 100644 --- a/master/slave.c +++ b/master/slave.c @@ -189,6 +189,34 @@ int ec_slave_init(ec_slave_t *slave, /**< EtherCAT slave */ /** Slave destructor. + Clears and frees a slave object. +*/ + +void ec_slave_destroy(ec_slave_t *slave /**< EtherCAT slave */) +{ + ec_sdo_t *sdo, *next_sdo; + + // free all SDOs + list_for_each_entry_safe(sdo, next_sdo, &slave->sdo_dictionary, list) { + list_del(&sdo->list); + ec_sdo_destroy(sdo); + } + + // free SDO kobject + if (slave->sdo_dictionary_fetched) kobject_del(&slave->sdo_kobj); + kobject_put(&slave->sdo_kobj); + + // destroy self + kobject_del(&slave->kobj); + kobject_put(&slave->kobj); +} + +/*****************************************************************************/ + +/** + Clear and free slave. + This method is called by the kobject, + once there are no more references to it. */ void ec_slave_clear(struct kobject *kobj /**< kobject of the slave */) @@ -198,7 +226,6 @@ void ec_slave_clear(struct kobject *kobj /**< kobject of the slave */) ec_sii_sync_t *sync, *next_sync; ec_sii_pdo_t *pdo, *next_pdo; ec_sii_pdo_entry_t *entry, *next_ent; - ec_sdo_t *sdo, *next_sdo; ec_sdo_data_t *sdodata, *next_sdodata; slave = container_of(kobj, ec_slave_t, kobj); @@ -235,17 +262,6 @@ void ec_slave_clear(struct kobject *kobj /**< kobject of the slave */) if (slave->sii_order) kfree(slave->sii_order); if (slave->sii_name) kfree(slave->sii_name); - // free all SDOs - list_for_each_entry_safe(sdo, next_sdo, &slave->sdo_dictionary, list) { - list_del(&sdo->list); - kobject_del(&sdo->kobj); - kobject_put(&sdo->kobj); - } - - // free SDO kobject FIXME - if (slave->sdo_dictionary_fetched) kobject_del(&slave->sdo_kobj); - kobject_put(&slave->sdo_kobj); - // free all SDO configurations list_for_each_entry_safe(sdodata, next_sdodata, &slave->sdo_confs, list) { list_del(&sdodata->list); diff --git a/master/slave.h b/master/slave.h index 43dab899b217670b7d070dbf277245572a6b263d..58543da6fc75c310111557cc8a4eb655ef4b3b3c 100644 --- a/master/slave.h +++ b/master/slave.h @@ -259,6 +259,7 @@ struct ec_slave // slave construction/destruction int ec_slave_init(ec_slave_t *, ec_master_t *, uint16_t, uint16_t); +void ec_slave_destroy(ec_slave_t *); void ec_slave_reset(ec_slave_t *);