domain.c

Go to the documentation of this file.
00001 /******************************************************************************
00002  *
00003  *  $Id: domain.c 490 2006-08-02 12:25:25Z fp $
00004  *
00005  *  Copyright (C) 2006  Florian Pose, Ingenieurgemeinschaft IgH
00006  *
00007  *  This file is part of the IgH EtherCAT Master.
00008  *
00009  *  The IgH EtherCAT Master is free software; you can redistribute it
00010  *  and/or modify it under the terms of the GNU General Public License
00011  *  as published by the Free Software Foundation; either version 2 of the
00012  *  License, or (at your option) any later version.
00013  *
00014  *  The IgH EtherCAT Master is distributed in the hope that it will be
00015  *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  *  GNU General Public License for more details.
00018  *
00019  *  You should have received a copy of the GNU General Public License
00020  *  along with the IgH EtherCAT Master; if not, write to the Free Software
00021  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00022  *
00023  *  The right to use EtherCAT Technology is granted and comes free of
00024  *  charge under condition of compatibility of product made by
00025  *  Licensee. People intending to distribute/sell products based on the
00026  *  code, have to sign an agreement to guarantee that products using
00027  *  software based on IgH EtherCAT master stay compatible with the actual
00028  *  EtherCAT specification (which are released themselves as an open
00029  *  standard) as the (only) precondition to have the right to use EtherCAT
00030  *  Technology, IP and trade marks.
00031  *
00032  *****************************************************************************/
00033 
00039 /*****************************************************************************/
00040 
00041 #include <linux/module.h>
00042 
00043 #include "globals.h"
00044 #include "domain.h"
00045 #include "master.h"
00046 
00047 /*****************************************************************************/
00048 
00049 void ec_domain_clear_field_regs(ec_domain_t *);
00050 ssize_t ec_show_domain_attribute(struct kobject *, struct attribute *, char *);
00051 
00052 /*****************************************************************************/
00053 
00056 EC_SYSFS_READ_ATTR(image_size);
00057 
00058 static struct attribute *def_attrs[] = {
00059     &attr_image_size,
00060     NULL,
00061 };
00062 
00063 static struct sysfs_ops sysfs_ops = {
00064     .show = &ec_show_domain_attribute,
00065     .store = NULL
00066 };
00067 
00068 static struct kobj_type ktype_ec_domain = {
00069     .release = ec_domain_clear,
00070     .sysfs_ops = &sysfs_ops,
00071     .default_attrs = def_attrs
00072 };
00073 
00076 /*****************************************************************************/
00077 
00083 int ec_domain_init(ec_domain_t *domain, 
00084                    ec_master_t *master, 
00085                    unsigned int index 
00086                    )
00087 {
00088     domain->master = master;
00089     domain->index = index;
00090     domain->data_size = 0;
00091     domain->base_address = 0;
00092     domain->response_count = 0xFFFFFFFF;
00093 
00094     INIT_LIST_HEAD(&domain->field_regs);
00095     INIT_LIST_HEAD(&domain->datagrams);
00096 
00097     // init kobject and add it to the hierarchy
00098     memset(&domain->kobj, 0x00, sizeof(struct kobject));
00099     kobject_init(&domain->kobj);
00100     domain->kobj.ktype = &ktype_ec_domain;
00101     domain->kobj.parent = &master->kobj;
00102     if (kobject_set_name(&domain->kobj, "domain%i", index)) {
00103         EC_ERR("Failed to set kobj name.\n");
00104         return -1;
00105     }
00106 
00107     return 0;
00108 }
00109 
00110 /*****************************************************************************/
00111 
00116 void ec_domain_clear(struct kobject *kobj )
00117 {
00118     ec_datagram_t *datagram, *next;
00119     ec_domain_t *domain;
00120 
00121     domain = container_of(kobj, ec_domain_t, kobj);
00122 
00123     EC_INFO("Clearing domain %i.\n", domain->index);
00124 
00125     list_for_each_entry_safe(datagram, next, &domain->datagrams, list) {
00126         ec_datagram_clear(datagram);
00127         kfree(datagram);
00128     }
00129 
00130     ec_domain_clear_field_regs(domain);
00131 
00132     kfree(domain);
00133 }
00134 
00135 /*****************************************************************************/
00136 
00142 int ec_domain_reg_field(ec_domain_t *domain, 
00143                         ec_slave_t *slave, 
00144                         const ec_sync_t *sync, 
00145                         uint32_t field_offset, 
00146                         void **data_ptr 
00148                         )
00149 {
00150     ec_field_reg_t *field_reg;
00151 
00152     if (!(field_reg =
00153           (ec_field_reg_t *) kmalloc(sizeof(ec_field_reg_t), GFP_KERNEL))) {
00154         EC_ERR("Failed to allocate field registration.\n");
00155         return -1;
00156     }
00157 
00158     if (ec_slave_prepare_fmmu(slave, domain, sync)) {
00159         EC_ERR("FMMU configuration failed.\n");
00160         kfree(field_reg);
00161         return -1;
00162     }
00163 
00164     field_reg->slave = slave;
00165     field_reg->sync = sync;
00166     field_reg->field_offset = field_offset;
00167     field_reg->data_ptr = data_ptr;
00168 
00169     list_add_tail(&field_reg->list, &domain->field_regs);
00170     return 0;
00171 }
00172 
00173 /*****************************************************************************/
00174 
00179 void ec_domain_clear_field_regs(ec_domain_t *domain )
00180 {
00181     ec_field_reg_t *field_reg, *next;
00182 
00183     list_for_each_entry_safe(field_reg, next, &domain->field_regs, list) {
00184         list_del(&field_reg->list);
00185         kfree(field_reg);
00186     }
00187 }
00188 
00189 /*****************************************************************************/
00190 
00196 int ec_domain_add_datagram(ec_domain_t *domain, 
00197                            uint32_t offset, 
00198                            size_t data_size 
00199                            )
00200 {
00201     ec_datagram_t *datagram;
00202 
00203     if (!(datagram = kmalloc(sizeof(ec_datagram_t), GFP_KERNEL))) {
00204         EC_ERR("Failed to allocate domain datagram!\n");
00205         return -1;
00206     }
00207 
00208     ec_datagram_init(datagram);
00209 
00210     if (ec_datagram_lrw(datagram, offset, data_size)) {
00211         kfree(datagram);
00212         return -1;
00213     }
00214 
00215     list_add_tail(&datagram->list, &domain->datagrams);
00216     return 0;
00217 }
00218 
00219 /*****************************************************************************/
00220 
00229 int ec_domain_alloc(ec_domain_t *domain, 
00230                     uint32_t base_address 
00231                     )
00232 {
00233     ec_field_reg_t *field_reg;
00234     ec_slave_t *slave;
00235     ec_fmmu_t *fmmu;
00236     unsigned int i, j, cmd_count;
00237     uint32_t field_off, field_off_cmd;
00238     uint32_t cmd_offset;
00239     size_t cmd_data_size, sync_size;
00240     ec_datagram_t *datagram;
00241 
00242     domain->base_address = base_address;
00243 
00244     // calculate size of process data and allocate memory
00245     domain->data_size = 0;
00246     cmd_offset = base_address;
00247     cmd_data_size = 0;
00248     cmd_count = 0;
00249     list_for_each_entry(slave, &domain->master->slaves, list) {
00250         for (j = 0; j < slave->fmmu_count; j++) {
00251             fmmu = &slave->fmmus[j];
00252             if (fmmu->domain == domain) {
00253                 fmmu->logical_start_address = base_address + domain->data_size;
00254                 sync_size = ec_slave_calc_sync_size(slave, fmmu->sync);
00255                 domain->data_size += sync_size;
00256                 if (cmd_data_size + sync_size > EC_MAX_DATA_SIZE) {
00257                     if (ec_domain_add_datagram(domain, cmd_offset,
00258                                                cmd_data_size)) return -1;
00259                     cmd_offset += cmd_data_size;
00260                     cmd_data_size = 0;
00261                     cmd_count++;
00262                 }
00263                 cmd_data_size += sync_size;
00264             }
00265         }
00266     }
00267 
00268     // allocate last datagram
00269     if (cmd_data_size) {
00270         if (ec_domain_add_datagram(domain, cmd_offset, cmd_data_size))
00271             return -1;
00272         cmd_count++;
00273     }
00274 
00275     if (!cmd_count) {
00276         EC_WARN("Domain %i contains no data!\n", domain->index);
00277         ec_domain_clear_field_regs(domain);
00278         return 0;
00279     }
00280 
00281     // set all process data pointers
00282     list_for_each_entry(field_reg, &domain->field_regs, list) {
00283         for (i = 0; i < field_reg->slave->fmmu_count; i++) {
00284             fmmu = &field_reg->slave->fmmus[i];
00285             if (fmmu->domain == domain && fmmu->sync == field_reg->sync) {
00286                 field_off = fmmu->logical_start_address +
00287                     field_reg->field_offset;
00288                 // search datagram
00289                 list_for_each_entry(datagram, &domain->datagrams, list) {
00290                     field_off_cmd = field_off - datagram->address.logical;
00291                     if (field_off >= datagram->address.logical &&
00292                         field_off_cmd < datagram->mem_size) {
00293                         *field_reg->data_ptr = datagram->data + field_off_cmd;
00294                     }
00295                 }
00296                 if (!field_reg->data_ptr) {
00297                     EC_ERR("Failed to assign data pointer!\n");
00298                     return -1;
00299                 }
00300                 break;
00301             }
00302         }
00303     }
00304 
00305     EC_INFO("Domain %i - Allocated %i bytes in %i datagram%s\n",
00306             domain->index, domain->data_size, cmd_count,
00307             cmd_count == 1 ? "" : "s");
00308 
00309     ec_domain_clear_field_regs(domain);
00310 
00311     return 0;
00312 }
00313 
00314 /*****************************************************************************/
00315 
00323 void ec_domain_response_count(ec_domain_t *domain, 
00324                               unsigned int count 
00325                               )
00326 {
00327     if (count != domain->response_count) {
00328         domain->response_count = count;
00329         EC_INFO("Domain %i working counter change: %i\n", domain->index,
00330                 count);
00331     }
00332 }
00333 
00334 /*****************************************************************************/
00335 
00341 ssize_t ec_show_domain_attribute(struct kobject *kobj, 
00342                                  struct attribute *attr, 
00343                                  char *buffer 
00344                                  )
00345 {
00346     ec_domain_t *domain = container_of(kobj, ec_domain_t, kobj);
00347 
00348     if (attr == &attr_image_size) {
00349         return sprintf(buffer, "%i\n", domain->data_size);
00350     }
00351 
00352     return 0;
00353 }
00354 
00355 /******************************************************************************
00356  *  Realtime interface
00357  *****************************************************************************/
00358 
00370 ec_slave_t *ecrt_domain_register_field(ec_domain_t *domain,
00372                                        const char *address,
00375                                        const char *vendor_name,
00377                                        const char *product_name,
00379                                        void **data_ptr,
00382                                        const char *field_name,
00384                                        unsigned int field_index,
00387                                        unsigned int field_count
00390                                        )
00391 {
00392     ec_slave_t *slave;
00393     const ec_slave_type_t *type;
00394     ec_master_t *master;
00395     const ec_sync_t *sync;
00396     const ec_field_t *field;
00397     unsigned int field_counter, i, j, orig_field_index, orig_field_count;
00398     uint32_t field_offset;
00399 
00400     master = domain->master;
00401 
00402     // translate address
00403     if (!(slave = ecrt_master_get_slave(master, address))) return NULL;
00404 
00405     if (!(type = slave->type)) {
00406         EC_ERR("Slave \"%s\" (position %i) has unknown type!\n", address,
00407                slave->ring_position);
00408         return NULL;
00409     }
00410 
00411     if (strcmp(vendor_name, type->vendor_name) ||
00412         strcmp(product_name, type->product_name)) {
00413         EC_ERR("Invalid slave type at position %i - Requested: \"%s %s\","
00414                " found: \"%s %s\".\n", slave->ring_position, vendor_name,
00415                product_name, type->vendor_name, type->product_name);
00416         return NULL;
00417     }
00418 
00419     if (!data_ptr) {
00420         // data_ptr is NULL => mark slave as "registered" (do not warn)
00421         slave->registered = 1;
00422     }
00423 
00424     if (!field_count) field_count = 1;
00425     orig_field_index = field_index;
00426     orig_field_count = field_count;
00427 
00428     field_counter = 0;
00429     for (i = 0; type->sync_managers[i]; i++) {
00430         sync = type->sync_managers[i];
00431         field_offset = 0;
00432         for (j = 0; sync->fields[j]; j++) {
00433             field = sync->fields[j];
00434             if (!strcmp(field->name, field_name)) {
00435                 if (field_counter++ == field_index) {
00436                     if (data_ptr)
00437                         ec_domain_reg_field(domain, slave, sync, field_offset,
00438                                             data_ptr++);
00439                     if (!(--field_count)) return slave;
00440                     field_index++;
00441                 }
00442             }
00443             field_offset += field->size;
00444         }
00445     }
00446 
00447     EC_ERR("Slave %i (\"%s %s\") registration mismatch: Field \"%s\","
00448            " index %i, count %i.\n", slave->ring_position, vendor_name,
00449            product_name, field_name, orig_field_index, orig_field_count);
00450     return NULL;
00451 }
00452 
00453 /*****************************************************************************/
00454 
00462 int ecrt_domain_register_field_list(ec_domain_t *domain,
00464                                     const ec_field_init_t *fields
00466                                     )
00467 {
00468     const ec_field_init_t *field;
00469 
00470     for (field = fields; field->slave_address; field++)
00471         if (!ecrt_domain_register_field(domain, field->slave_address,
00472                                         field->vendor_name,
00473                                         field->product_name, field->data_ptr,
00474                                         field->field_name, field->field_index,
00475                                         field->field_count))
00476             return -1;
00477 
00478     return 0;
00479 }
00480 
00481 /*****************************************************************************/
00482 
00488 void ecrt_domain_queue(ec_domain_t *domain )
00489 {
00490     ec_datagram_t *datagram;
00491 
00492     list_for_each_entry(datagram, &domain->datagrams, list) {
00493         ec_master_queue_datagram(domain->master, datagram);
00494     }
00495 }
00496 
00497 /*****************************************************************************/
00498 
00504 void ecrt_domain_process(ec_domain_t *domain )
00505 {
00506     unsigned int working_counter_sum;
00507     ec_datagram_t *datagram;
00508 
00509     working_counter_sum = 0;
00510 
00511     list_for_each_entry(datagram, &domain->datagrams, list) {
00512         if (datagram->state == EC_CMD_RECEIVED) {
00513             working_counter_sum += datagram->working_counter;
00514         }
00515     }
00516 
00517     ec_domain_response_count(domain, working_counter_sum);
00518 }
00519 
00520 /*****************************************************************************/
00521 
00528 int ecrt_domain_state(ec_domain_t *domain )
00529 {
00530     ec_datagram_t *datagram;
00531 
00532     list_for_each_entry(datagram, &domain->datagrams, list) {
00533         if (datagram->state != EC_CMD_RECEIVED) return -1;
00534     }
00535 
00536     return 0;
00537 }
00538 
00539 /*****************************************************************************/
00540 
00543 EXPORT_SYMBOL(ecrt_domain_register_field);
00544 EXPORT_SYMBOL(ecrt_domain_register_field_list);
00545 EXPORT_SYMBOL(ecrt_domain_queue);
00546 EXPORT_SYMBOL(ecrt_domain_process);
00547 EXPORT_SYMBOL(ecrt_domain_state);
00548 
00551 /*****************************************************************************/

Generated on Wed Aug 2 18:41:43 2006 for IgH EtherCAT master by  doxygen 1.4.6