--- 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;
}
/******************************************************************************
--- 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 <linux/list.h>
+#include <linux/kobject.h>
#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: ***
*/
--- 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;
}
/*****************************************************************************/
--- 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 <linux/list.h>
+#include <linux/sysfs.h>
#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 *);
/*****************************************************************************/
--- 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;
}