# HG changeset patch # User Florian Pose # Date 1144679102 0 # Node ID b84f69db8566b9470cfa525875a8b5e99fdfc8b5 # Parent 482200a0659fc14b6240cd02896121eb97cafc97 MERGE branches/sysfs -> trunk (whole SysFS implementation) diff -r 482200a0659f -r b84f69db8566 master/domain.c --- a/master/domain.c Mon Apr 10 11:18:52 2006 +0000 +++ b/master/domain.c Mon Apr 10 14:25:02 2006 +0000 @@ -12,25 +12,65 @@ #include "domain.h" #include "master.h" +/*****************************************************************************/ + void ec_domain_clear_field_regs(ec_domain_t *); /*****************************************************************************/ +static struct attribute attr_data_size = { + .name = "data_size", + .owner = THIS_MODULE, + .mode = S_IRUGO +}; + +static struct attribute *def_attrs[] = { + &attr_data_size, + NULL, +}; + +static struct sysfs_ops sysfs_ops = { + .show = &ec_show_domain_attribute, + .store = NULL +}; + +static struct kobj_type ktype_ec_domain = { + .release = ec_domain_clear, + .sysfs_ops = &sysfs_ops, + .default_attrs = def_attrs +}; + +/*****************************************************************************/ + /** Konstruktor einer EtherCAT-Domäne. */ -void ec_domain_init(ec_domain_t *domain, /**< Domäne */ - ec_master_t *master /**< Zugehöriger Master */ - ) +int ec_domain_init(ec_domain_t *domain, /**< Domäne */ + ec_master_t *master, /**< Zugehöriger Master */ + unsigned int index /**< Domänen-Index */ + ) { domain->master = master; + domain->index = index; domain->data_size = 0; domain->base_address = 0; domain->response_count = 0xFFFFFFFF; INIT_LIST_HEAD(&domain->field_regs); INIT_LIST_HEAD(&domain->commands); + + // Init kobject and add it to the hierarchy + memset(&domain->kobj, 0x00, sizeof(struct kobject)); + kobject_init(&domain->kobj); + domain->kobj.ktype = &ktype_ec_domain; + domain->kobj.parent = &master->kobj; + if (kobject_set_name(&domain->kobj, "domain%i", index)) { + EC_ERR("Failed to set kobj name.\n"); + return -1; + } + + return 0; } /*****************************************************************************/ @@ -39,9 +79,14 @@ Destruktor einer EtherCAT-Domäne. */ -void ec_domain_clear(ec_domain_t *domain /**< Domäne */) +void ec_domain_clear(struct kobject *kobj /**< Kobject der Domäne */) { ec_command_t *command, *next; + ec_domain_t *domain; + + domain = container_of(kobj, ec_domain_t, kobj); + + EC_INFO("Clearing domain %i.\n", domain->index); list_for_each_entry_safe(command, next, &domain->commands, list) { ec_command_clear(command); @@ -49,6 +94,8 @@ } ec_domain_clear_field_regs(domain); + + kfree(domain); } /*****************************************************************************/ @@ -192,7 +239,7 @@ } if (!cmd_count) { - EC_WARN("Domain 0x%08X contains no data!\n", (u32) domain); + EC_WARN("Domain %i contains no data!\n", domain->index); ec_domain_clear_field_regs(domain); return 0; } @@ -221,8 +268,9 @@ } } - EC_INFO("Domain %X - Allocated %i bytes in %i command(s)\n", - (u32) domain, domain->data_size, cmd_count); + EC_INFO("Domain %i - Allocated %i bytes in %i command%s\n", + domain->index, domain->data_size, cmd_count, + cmd_count == 1 ? "" : "s"); ec_domain_clear_field_regs(domain); @@ -241,9 +289,30 @@ { if (count != domain->response_count) { domain->response_count = count; - EC_INFO("Domain 0x%08X working counter change: %i\n", - (u32) domain, count); - } + EC_INFO("Domain %i working counter change: %i\n", domain->index, count); + } +} + +/*****************************************************************************/ + +/** + Formatiert Attribut-Daten für lesenden Zugriff im SysFS + + \return Anzahl Bytes im Speicher +*/ + +ssize_t ec_show_domain_attribute(struct kobject *kobj, /**< KObject */ + struct attribute *attr, /**< Attribut */ + char *buffer /**< Speicher für die Daten */ + ) +{ + ec_domain_t *domain = container_of(kobj, ec_domain_t, kobj); + + if (attr == &attr_data_size) { + return sprintf(buffer, "%i\n", domain->data_size); + } + + return 0; } /****************************************************************************** diff -r 482200a0659f -r b84f69db8566 master/domain.h --- a/master/domain.h Mon Apr 10 11:18:52 2006 +0000 +++ b/master/domain.h Mon Apr 10 14:25:02 2006 +0000 @@ -12,6 +12,7 @@ #define _EC_DOMAIN_H_ #include +#include #include "globals.h" #include "slave.h" @@ -44,7 +45,9 @@ struct ec_domain { + struct kobject kobj; /**< Kobject der Domäne */ struct list_head list; /**< Listenkopf */ + unsigned int index; /**< Domänen-Index */ ec_master_t *master; /**< EtherCAT-Master, zu der die Domäne gehört. */ size_t data_size; /**< Größe der Prozessdaten */ struct list_head commands; /**< EtherCAT-Kommandos für die Prozessdaten */ @@ -55,16 +58,18 @@ /*****************************************************************************/ -void ec_domain_init(ec_domain_t *, ec_master_t *); -void ec_domain_clear(ec_domain_t *); +int ec_domain_init(ec_domain_t *, ec_master_t *, unsigned int); +void ec_domain_clear(struct kobject *); int ec_domain_alloc(ec_domain_t *, uint32_t); +ssize_t ec_show_domain_attribute(struct kobject *, struct attribute *, char *); + /*****************************************************************************/ #endif /* Emacs-Konfiguration - ;;; Local Variables: *** - ;;; c-basic-offset:4 *** +;;; Local Variables: *** +;;; c-basic-offset:4 *** ;;; End: *** */ diff -r 482200a0659f -r b84f69db8566 master/master.c --- a/master/master.c Mon Apr 10 11:18:52 2006 +0000 +++ b/master/master.c Mon Apr 10 14:25:02 2006 +0000 @@ -25,23 +25,64 @@ /*****************************************************************************/ +static struct attribute attr_slave_count = { + .name = "slave_count", + .owner = THIS_MODULE, + .mode = S_IRUGO +}; + +static struct attribute *ec_def_attrs[] = { + &attr_slave_count, + NULL, +}; + +static struct sysfs_ops ec_sysfs_ops = { + .show = &ec_show_master_attribute, + .store = NULL +}; + +static struct kobj_type ktype_ec_master = { + .release = ec_master_clear, + .sysfs_ops = &ec_sysfs_ops, + .default_attrs = ec_def_attrs +}; + +/*****************************************************************************/ + /** Konstruktor des EtherCAT-Masters. */ -void ec_master_init(ec_master_t *master /**< EtherCAT-Master */) -{ +int ec_master_init(ec_master_t *master, /**< EtherCAT-Master */ + unsigned int index /**< Master-Index */ + ) +{ + EC_INFO("Initializing master %i.\n", index); + + master->index = index; master->slaves = NULL; master->device = NULL; + master->reserved = 0; INIT_LIST_HEAD(&master->command_queue); INIT_LIST_HEAD(&master->domains); INIT_LIST_HEAD(&master->eoe_slaves); + // Init kobject and add it to the hierarchy + memset(&master->kobj, 0x00, sizeof(struct kobject)); + kobject_init(&master->kobj); + master->kobj.ktype = &ktype_ec_master; + if (kobject_set_name(&master->kobj, "ethercat%i", index)) { + EC_ERR("Failed to set kobj name.\n"); + kobject_put(&master->kobj); + return -1; + } + ec_command_init(&master->simple_command); ec_command_init(&master->watch_command); ec_master_reset(master); + return 0; } /*****************************************************************************/ @@ -53,8 +94,12 @@ auf das Slave-Array und gibt die Prozessdaten frei. */ -void ec_master_clear(ec_master_t *master /**< EtherCAT-Master */) -{ +void ec_master_clear(struct kobject *kobj /**< KObject des Masters */) +{ + ec_master_t *master = container_of(kobj, ec_master_t, kobj); + + EC_INFO("Clearing master %i...\n", master->index); + ec_master_reset(master); if (master->device) { @@ -64,6 +109,8 @@ ec_command_clear(&master->simple_command); ec_command_clear(&master->watch_command); + + EC_INFO("Master %i cleared.\n", master->index); } /*****************************************************************************/ @@ -102,8 +149,8 @@ // Domain-Liste leeren list_for_each_entry_safe(domain, next_d, &master->domains, list) { list_del(&domain->list); - ec_domain_clear(domain); - kfree(domain); + kobject_del(&domain->kobj); + kobject_put(&domain->kobj); } // EOE-Liste leeren @@ -709,6 +756,28 @@ /*****************************************************************************/ /** + Formatiert Attribut-Daten für lesenden Zugriff im SysFS + + \return Anzahl Bytes im Speicher +*/ + +ssize_t ec_show_master_attribute(struct kobject *kobj, /**< KObject */ + struct attribute *attr, /**< Attribut */ + char *buffer /**< Speicher für die Daten */ + ) +{ + ec_master_t *master = container_of(kobj, ec_master_t, kobj); + + if (attr == &attr_slave_count) { + return sprintf(buffer, "%i\n", master->slave_count); + } + + return 0; +} + +/*****************************************************************************/ + +/** Gibt Überwachungsinformationen aus. */ @@ -767,17 +836,37 @@ ec_domain_t *ecrt_master_create_domain(ec_master_t *master /**< Master */) { - ec_domain_t *domain; + ec_domain_t *domain, *last_domain; + unsigned int index; if (!(domain = (ec_domain_t *) kmalloc(sizeof(ec_domain_t), GFP_KERNEL))) { EC_ERR("Error allocating domain memory!\n"); - return NULL; - } - - ec_domain_init(domain, master); + goto out_return; + } + + if (list_empty(&master->domains)) index = 0; + else { + last_domain = list_entry(master->domains.prev, ec_domain_t, list); + index = last_domain->index + 1; + } + + if (ec_domain_init(domain, master, index)) { + EC_ERR("Failed to init domain.\n"); + goto out_return; + } + + if (kobject_add(&domain->kobj)) { + EC_ERR("Failed to add domain kobject.\n"); + goto out_put; + } + list_add_tail(&domain->list, &master->domains); - return domain; + + out_put: + kobject_put(&domain->kobj); + out_return: + return NULL; } /*****************************************************************************/ diff -r 482200a0659f -r b84f69db8566 master/master.h --- a/master/master.h Mon Apr 10 11:18:52 2006 +0000 +++ b/master/master.h Mon Apr 10 14:25:02 2006 +0000 @@ -12,6 +12,7 @@ #define _EC_MASTER_H_ #include +#include #include "device.h" #include "slave.h" @@ -45,6 +46,9 @@ struct ec_master { + struct list_head list; /**< Noetig fuer Master-Liste */ + struct kobject kobj; /**< Kernel-Object */ + unsigned int index; /**< Master-Index */ ec_slave_t *slaves; /**< Array von Slaves auf dem Bus */ unsigned int slave_count; /**< Anzahl Slaves auf dem Bus */ ec_device_t *device; /**< EtherCAT-Gerät */ @@ -59,13 +63,14 @@ ec_stats_t stats; /**< Rahmen-Statistiken */ unsigned int timeout; /**< Timeout für synchronen Datenaustausch */ struct list_head eoe_slaves; /**< Ethernet over EtherCAT Slaves */ + unsigned int reserved; /**< Master durch Echtzeitprozess reserviert */ }; /*****************************************************************************/ // Master creation and deletion -void ec_master_init(ec_master_t *); -void ec_master_clear(ec_master_t *); +int ec_master_init(ec_master_t *, unsigned int); +void ec_master_clear(struct kobject *); void ec_master_reset(ec_master_t *); // IO @@ -79,8 +84,8 @@ // Misc void ec_master_debug(const ec_master_t *); void ec_master_output_stats(ec_master_t *); - void ec_master_run_eoe(ec_master_t *); +ssize_t ec_show_master_attribute(struct kobject *, struct attribute *, char *); /*****************************************************************************/ diff -r 482200a0659f -r b84f69db8566 master/module.c --- a/master/module.c Mon Apr 10 11:18:52 2006 +0000 +++ b/master/module.c Mon Apr 10 14:25:02 2006 +0000 @@ -41,9 +41,8 @@ /*****************************************************************************/ -int ec_master_count = 1; -ec_master_t *ec_masters = NULL; -unsigned int *ec_masters_reserved = NULL; +static int ec_master_count = 1; +static struct list_head ec_masters; /*****************************************************************************/ @@ -70,6 +69,7 @@ int __init ec_init_module(void) { unsigned int i; + ec_master_t *master, *next; EC_INFO("Master driver, %s\n", COMPILE_INFO); @@ -80,28 +80,36 @@ EC_INFO("Initializing %i EtherCAT master(s)...\n", ec_master_count); - if (!(ec_masters = (ec_master_t *) - kmalloc(sizeof(ec_master_t) * ec_master_count, GFP_KERNEL))) { - EC_ERR("Failed to allocate master(s)!\n"); - goto out_return; - } - - if (!(ec_masters_reserved = (unsigned int *) - kmalloc(sizeof(int) * ec_master_count, GFP_KERNEL))) { - EC_ERR("Failed to allocate reservation flags!\n"); - goto out_free_masters; - } + INIT_LIST_HEAD(&ec_masters); for (i = 0; i < ec_master_count; i++) { - ec_master_init(ec_masters + i); - ec_masters_reserved[i] = 0; + if (!(master = + (ec_master_t *) kmalloc(sizeof(ec_master_t), GFP_KERNEL))) { + EC_ERR("Failed to allocate memory for EtherCAT master %i.\n", i); + goto out_free; + } + + if (ec_master_init(master, i)) // kobject_put is done inside... + goto out_free; + + if (kobject_add(&master->kobj)) { + EC_ERR("Failed to add kobj.\n"); + kobject_put(&master->kobj); // free master + goto out_free; + } + + list_add_tail(&master->list, &ec_masters); } EC_INFO("Master driver initialized.\n"); return 0; - out_free_masters: - kfree(ec_masters); + out_free: + list_for_each_entry_safe(master, next, &ec_masters, list) { + list_del(&master->list); + kobject_del(&master->kobj); + kobject_put(&master->kobj); + } out_return: return -1; } @@ -116,22 +124,38 @@ void __exit ec_cleanup_module(void) { - unsigned int i; + ec_master_t *master, *next; EC_INFO("Cleaning up master driver...\n"); - for (i = 0; i < ec_master_count; i++) { - if (ec_masters_reserved[i]) - EC_WARN("Master %i is still in use!\n", i); - ec_master_clear(&ec_masters[i]); - } - - kfree(ec_masters); - kfree(ec_masters_reserved); + 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_INFO("Master driver cleaned up.\n"); } +/*****************************************************************************/ + +/** + Gets a handle to a certain master. + \returns pointer to master +*/ + +ec_master_t *ec_find_master(unsigned int master_index) +{ + ec_master_t *master; + + list_for_each_entry(master, &ec_masters, list) { + if (master->index == master_index) return master; + } + + EC_ERR("Master %i does not exist!\n", master_index); + return NULL; +} + /****************************************************************************** * * Treiberschnittstelle @@ -162,23 +186,20 @@ return NULL; } - if (master_index >= ec_master_count) { - EC_ERR("Master %i does not exist!\n", master_index); - return NULL; - } - - master = ec_masters + master_index; - + if (!(master = ec_find_master(master_index))) return NULL; + + // critical section start if (master->device) { EC_ERR("Master %i already has a device!\n", master_index); return NULL; } - if (!(master->device = (ec_device_t *) - kmalloc(sizeof(ec_device_t), GFP_KERNEL))) { + if (!(master->device = + (ec_device_t *) kmalloc(sizeof(ec_device_t), GFP_KERNEL))) { EC_ERR("Failed to allocate device!\n"); return NULL; } + // critical section end if (ec_device_init(master->device, master, net_dev, isr, module)) { kfree(master->device); @@ -208,7 +229,7 @@ return; } - master = ec_masters + master_index; + if (!(master = ec_find_master(master_index))) return; if (!master->device || master->device != device) { EC_WARN("Unable to unregister device!\n"); @@ -234,29 +255,26 @@ \return Zeiger auf EtherCAT-Master oder NULL, wenn Parameter ungueltig. */ -ec_master_t *ecrt_request_master(unsigned int index +ec_master_t *ecrt_request_master(unsigned int master_index /**< EtherCAT-Master-Index */ ) { ec_master_t *master; - EC_INFO("Requesting master %i...\n", index); - - if (index < 0 || index >= ec_master_count) { - EC_ERR("Master %i does not exist!\n", index); + EC_INFO("Requesting master %i...\n", master_index); + + if (!(master = ec_find_master(master_index))) goto req_return; + + // begin critical section + if (master->reserved) { + EC_ERR("Master %i is already in use!\n", master_index); goto req_return; } - - if (ec_masters_reserved[index]) { - EC_ERR("Master %i is already in use!\n", index); - goto req_return; - } - - ec_masters_reserved[index] = 1; - master = &ec_masters[index]; + master->reserved = 1; + // end critical section if (!master->device) { - EC_ERR("Master %i has no assigned device!\n", index); + EC_ERR("Master %i has no assigned device!\n", master_index); goto req_release; } @@ -270,15 +288,14 @@ goto req_module_put; } - if (!master->device->link_state) - EC_WARN("Link is DOWN.\n"); - - if (ec_master_bus_scan(master) != 0) { + if (!master->device->link_state) EC_WARN("Link is DOWN.\n"); + + if (ec_master_bus_scan(master)) { EC_ERR("Bus scan failed!\n"); goto req_close; } - EC_INFO("Master %i is ready.\n", index); + EC_INFO("Master %i is ready.\n", master_index); return master; req_close: @@ -288,9 +305,9 @@ module_put(master->device->module); ec_master_reset(master); req_release: - ec_masters_reserved[index] = 0; + master->reserved = 0; req_return: - EC_ERR("Failed requesting master %i.\n", index); + EC_ERR("Failed requesting master %i.\n", master_index); return NULL; } @@ -302,32 +319,22 @@ void ecrt_release_master(ec_master_t *master /**< EtherCAT-Master */) { - unsigned int i, found; - - found = 0; - for (i = 0; i < ec_master_count; i++) { - if (&ec_masters[i] == master) { - found = 1; - break; - } - } - - if (!found) { - EC_WARN("Master 0x%08X was never requested!\n", (u32) master); + EC_INFO("Releasing master %i...\n", master->index); + + if (!master->reserved) { + EC_ERR("Master %i was never requested!\n", master->index); return; } - EC_INFO("Releasing master %i...\n", i); - ec_master_reset(master); if (ec_device_close(master->device)) EC_WARN("Warning - Failed to close device!\n"); module_put(master->device->module); - ec_masters_reserved[i] = 0; - - EC_INFO("Released master %i.\n", i); + master->reserved = 0; + + EC_INFO("Released master %i.\n", master->index); return; }