Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

domain.c

Go to the documentation of this file.
00001 /******************************************************************************
00002  *
00003  *  $Id: domain.c 682 2006-11-07 12:13:30Z 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 
00053 typedef struct
00054 {
00055     struct list_head list; 
00056     ec_slave_t *slave; 
00057     const ec_sii_sync_t *sync; 
00058     off_t sync_offset; 
00059     void **data_ptr; 
00060 }
00061 ec_data_reg_t;
00062 
00063 /*****************************************************************************/
00064 
00065 void ec_domain_clear(struct kobject *);
00066 void ec_domain_clear_data_regs(ec_domain_t *);
00067 ssize_t ec_show_domain_attribute(struct kobject *, struct attribute *, char *);
00068 
00069 /*****************************************************************************/
00070 
00073 EC_SYSFS_READ_ATTR(image_size);
00074 
00075 static struct attribute *def_attrs[] = {
00076     &attr_image_size,
00077     NULL,
00078 };
00079 
00080 static struct sysfs_ops sysfs_ops = {
00081     .show = &ec_show_domain_attribute,
00082     .store = NULL
00083 };
00084 
00085 static struct kobj_type ktype_ec_domain = {
00086     .release = ec_domain_clear,
00087     .sysfs_ops = &sysfs_ops,
00088     .default_attrs = def_attrs
00089 };
00090 
00093 /*****************************************************************************/
00094 
00100 int ec_domain_init(ec_domain_t *domain, 
00101                    ec_master_t *master, 
00102                    unsigned int index 
00103                    )
00104 {
00105     domain->master = master;
00106     domain->index = index;
00107     domain->data_size = 0;
00108     domain->base_address = 0;
00109     domain->response_count = 0xFFFFFFFF;
00110     domain->notify_jiffies = 0;
00111     domain->working_counter_changes = 0;
00112 
00113     INIT_LIST_HEAD(&domain->data_regs);
00114     INIT_LIST_HEAD(&domain->datagrams);
00115 
00116     // init kobject and add it to the hierarchy
00117     memset(&domain->kobj, 0x00, sizeof(struct kobject));
00118     kobject_init(&domain->kobj);
00119     domain->kobj.ktype = &ktype_ec_domain;
00120     domain->kobj.parent = &master->kobj;
00121     if (kobject_set_name(&domain->kobj, "domain%i", index)) {
00122         EC_ERR("Failed to set kobj name.\n");
00123         kobject_put(&domain->kobj);
00124         return -1;
00125     }
00126     if (kobject_add(&domain->kobj)) {
00127         EC_ERR("Failed to add domain kobject.\n");
00128         kobject_put(&domain->kobj);
00129         return -1;
00130     }
00131 
00132     return 0;
00133 }
00134 
00135 /*****************************************************************************/
00136 
00142 void ec_domain_destroy(ec_domain_t *domain )
00143 {
00144     ec_datagram_t *datagram;
00145 
00146     // dequeue datagrams
00147     list_for_each_entry(datagram, &domain->datagrams, list) {
00148         if (!list_empty(&datagram->queue)) // datagram queued?
00149             list_del_init(&datagram->queue);
00150     }
00151 
00152     // destroy self
00153     kobject_del(&domain->kobj);
00154     kobject_put(&domain->kobj);
00155 }
00156 
00157 /*****************************************************************************/
00158 
00165 void ec_domain_clear(struct kobject *kobj )
00166 {
00167     ec_datagram_t *datagram, *next;
00168     ec_domain_t *domain;
00169 
00170     domain = container_of(kobj, ec_domain_t, kobj);
00171 
00172     list_for_each_entry_safe(datagram, next, &domain->datagrams, list) {
00173         ec_datagram_clear(datagram);
00174         kfree(datagram);
00175     }
00176 
00177     ec_domain_clear_data_regs(domain);
00178 
00179     kfree(domain);
00180 }
00181 
00182 /*****************************************************************************/
00183 
00189 int ec_domain_reg_pdo_entry(ec_domain_t *domain, 
00190                             ec_slave_t *slave, 
00191                             const ec_sii_pdo_t *pdo, 
00192                             const ec_sii_pdo_entry_t *entry,
00194                             void **data_ptr 
00196                             )
00197 {
00198     ec_data_reg_t *data_reg;
00199     const ec_sii_sync_t *sync;
00200     const ec_sii_pdo_t *other_pdo;
00201     const ec_sii_pdo_entry_t *other_entry;
00202     unsigned int bit_offset, byte_offset, sync_found;
00203 
00204     // Find sync manager for PDO
00205     sync_found = 0;
00206     list_for_each_entry(sync, &slave->sii_syncs, list) {
00207         if (sync->index == pdo->sync_index) {
00208             sync_found = 1;
00209             break;
00210         }
00211     }
00212 
00213     if (!sync_found) {
00214         EC_ERR("No sync manager for PDO 0x%04X:%i.",
00215                pdo->index, entry->subindex);
00216         return -1;
00217     }
00218 
00219     // Calculate offset (in sync manager) for process data pointer
00220     bit_offset = 0;
00221     byte_offset = 0;
00222     list_for_each_entry(other_pdo, &slave->sii_pdos, list) {
00223         if (other_pdo->sync_index != sync->index) continue;
00224 
00225         list_for_each_entry(other_entry, &other_pdo->entries, list) {
00226             if (other_entry == entry) {
00227                 byte_offset = bit_offset / 8;
00228                 break;
00229             }
00230             bit_offset += other_entry->bit_length;
00231         }
00232     }
00233 
00234     // Allocate memory for data registration object
00235     if (!(data_reg =
00236           (ec_data_reg_t *) kmalloc(sizeof(ec_data_reg_t), GFP_KERNEL))) {
00237         EC_ERR("Failed to allocate data registration.\n");
00238         return -1;
00239     }
00240 
00241     if (ec_slave_prepare_fmmu(slave, domain, sync)) {
00242         EC_ERR("FMMU configuration failed.\n");
00243         kfree(data_reg);
00244         return -1;
00245     }
00246 
00247     data_reg->slave = slave;
00248     data_reg->sync = sync;
00249     data_reg->sync_offset = byte_offset;
00250     data_reg->data_ptr = data_ptr;
00251 
00252     list_add_tail(&data_reg->list, &domain->data_regs);
00253 
00254     ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
00255 
00256     return 0;
00257 }
00258 
00259 /*****************************************************************************/
00260 
00266 int ec_domain_reg_pdo_range(ec_domain_t *domain, 
00267                             ec_slave_t *slave, 
00268                             ec_direction_t dir, 
00269                             uint16_t offset, 
00270                             uint16_t length, 
00271                             void **data_ptr 
00273                             )
00274 {
00275     ec_data_reg_t *data_reg;
00276     ec_sii_sync_t *sync;
00277     unsigned int sync_found, sync_index;
00278     uint16_t sync_length;
00279 
00280     switch (dir) {
00281         case EC_DIR_OUTPUT: sync_index = 2; break;
00282         case EC_DIR_INPUT:  sync_index = 3; break;
00283         default:
00284             EC_ERR("Invalid direction!\n");
00285             return -1;
00286     }
00287 
00288     // Find sync manager
00289     sync_found = 0;
00290     list_for_each_entry(sync, &slave->sii_syncs, list) {
00291         if (sync->index == sync_index) {
00292             sync_found = 1;
00293             break;
00294         }
00295     }
00296 
00297     if (!sync_found) {
00298         EC_ERR("No sync manager found for PDO range.\n");
00299         return -1;
00300     }
00301 
00302      // Allocate memory for data registration object
00303     if (!(data_reg =
00304           (ec_data_reg_t *) kmalloc(sizeof(ec_data_reg_t), GFP_KERNEL))) {
00305         EC_ERR("Failed to allocate data registration.\n");
00306         return -1;
00307     }
00308 
00309     if (ec_slave_prepare_fmmu(slave, domain, sync)) {
00310         EC_ERR("FMMU configuration failed.\n");
00311         kfree(data_reg);
00312         return -1;
00313     }
00314 
00315     data_reg->slave = slave;
00316     data_reg->sync = sync;
00317     data_reg->sync_offset = offset;
00318     data_reg->data_ptr = data_ptr;
00319 
00320     // estimate sync manager length
00321     sync_length = offset + length;
00322     if (sync->est_length < sync_length) {
00323         sync->est_length = sync_length;
00324         if (domain->master->debug_level) {
00325             EC_DBG("Estimating length of sync manager %i of slave %i to %i.\n",
00326                    sync->index, slave->ring_position, sync_length);
00327         }
00328     }
00329 
00330     list_add_tail(&data_reg->list, &domain->data_regs);
00331 
00332     ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
00333 
00334     return 0;
00335 }
00336 
00337 /*****************************************************************************/
00338 
00343 void ec_domain_clear_data_regs(ec_domain_t *domain )
00344 {
00345     ec_data_reg_t *data_reg, *next;
00346 
00347     list_for_each_entry_safe(data_reg, next, &domain->data_regs, list) {
00348         list_del(&data_reg->list);
00349         kfree(data_reg);
00350     }
00351 }
00352 
00353 /*****************************************************************************/
00354 
00360 int ec_domain_add_datagram(ec_domain_t *domain, 
00361                            uint32_t offset, 
00362                            size_t data_size 
00363                            )
00364 {
00365     ec_datagram_t *datagram;
00366 
00367     if (!(datagram = kmalloc(sizeof(ec_datagram_t), GFP_KERNEL))) {
00368         EC_ERR("Failed to allocate domain datagram!\n");
00369         return -1;
00370     }
00371 
00372     ec_datagram_init(datagram);
00373 
00374     if (ec_datagram_lrw(datagram, offset, data_size)) {
00375         kfree(datagram);
00376         return -1;
00377     }
00378 
00379     list_add_tail(&datagram->list, &domain->datagrams);
00380     return 0;
00381 }
00382 
00383 /*****************************************************************************/
00384 
00393 int ec_domain_alloc(ec_domain_t *domain, 
00394                     uint32_t base_address 
00395                     )
00396 {
00397     ec_data_reg_t *data_reg;
00398     ec_slave_t *slave;
00399     ec_fmmu_t *fmmu;
00400     unsigned int i, j, datagram_count;
00401     uint32_t pdo_off, pdo_off_datagram;
00402     uint32_t datagram_offset;
00403     size_t datagram_data_size, sync_size;
00404     ec_datagram_t *datagram;
00405 
00406     domain->base_address = base_address;
00407 
00408     // calculate size of process data and allocate memory
00409     domain->data_size = 0;
00410     datagram_offset = base_address;
00411     datagram_data_size = 0;
00412     datagram_count = 0;
00413     list_for_each_entry(slave, &domain->master->slaves, list) {
00414         for (j = 0; j < slave->fmmu_count; j++) {
00415             fmmu = &slave->fmmus[j];
00416             if (fmmu->domain == domain) {
00417                 fmmu->logical_start_address = base_address + domain->data_size;
00418                 sync_size = ec_slave_calc_sync_size(slave, fmmu->sync);
00419                 domain->data_size += sync_size;
00420                 if (datagram_data_size + sync_size > EC_MAX_DATA_SIZE) {
00421                     if (ec_domain_add_datagram(domain, datagram_offset,
00422                                                datagram_data_size)) return -1;
00423                     datagram_offset += datagram_data_size;
00424                     datagram_data_size = 0;
00425                     datagram_count++;
00426                 }
00427                 datagram_data_size += sync_size;
00428             }
00429         }
00430     }
00431 
00432     // allocate last datagram
00433     if (datagram_data_size) {
00434         if (ec_domain_add_datagram(domain, datagram_offset,
00435                                    datagram_data_size))
00436             return -1;
00437         datagram_count++;
00438     }
00439 
00440     if (!datagram_count) {
00441         EC_WARN("Domain %i contains no data!\n", domain->index);
00442         ec_domain_clear_data_regs(domain);
00443         return 0;
00444     }
00445 
00446     // set all process data pointers
00447     list_for_each_entry(data_reg, &domain->data_regs, list) {
00448         for (i = 0; i < data_reg->slave->fmmu_count; i++) {
00449             fmmu = &data_reg->slave->fmmus[i];
00450             if (fmmu->domain == domain && fmmu->sync == data_reg->sync) {
00451                 pdo_off = fmmu->logical_start_address + data_reg->sync_offset;
00452                 // search datagram
00453                 list_for_each_entry(datagram, &domain->datagrams, list) {
00454                     pdo_off_datagram = pdo_off - datagram->address.logical;
00455                     if (pdo_off >= datagram->address.logical &&
00456                         pdo_off_datagram < datagram->mem_size) {
00457                         *data_reg->data_ptr = datagram->data +
00458                             pdo_off_datagram;
00459                     }
00460                 }
00461                 if (!data_reg->data_ptr) {
00462                     EC_ERR("Failed to assign data pointer!\n");
00463                     return -1;
00464                 }
00465                 break;
00466             }
00467         }
00468     }
00469 
00470     EC_INFO("Domain %i - Allocated %i bytes in %i datagram%s.\n",
00471             domain->index, domain->data_size, datagram_count,
00472             datagram_count == 1 ? "" : "s");
00473 
00474     ec_domain_clear_data_regs(domain);
00475 
00476     return 0;
00477 }
00478 
00479 /*****************************************************************************/
00480 
00485 void ec_domain_queue_datagrams(ec_domain_t *domain )
00486 {
00487     ec_datagram_t *datagram;
00488 
00489     list_for_each_entry(datagram, &domain->datagrams, list) {
00490         ec_master_queue_datagram(domain->master, datagram);
00491     }
00492 }
00493 
00494 /*****************************************************************************/
00495 
00501 ssize_t ec_show_domain_attribute(struct kobject *kobj, 
00502                                  struct attribute *attr, 
00503                                  char *buffer 
00504                                  )
00505 {
00506     ec_domain_t *domain = container_of(kobj, ec_domain_t, kobj);
00507 
00508     if (attr == &attr_image_size) {
00509         return sprintf(buffer, "%i\n", domain->data_size);
00510     }
00511 
00512     return 0;
00513 }
00514 
00515 /******************************************************************************
00516  *  Realtime interface
00517  *****************************************************************************/
00518 
00526 ec_slave_t *ecrt_domain_register_pdo(ec_domain_t *domain,
00528                                      const char *address,
00531                                      uint32_t vendor_id,
00533                                      uint32_t product_code,
00535                                      uint16_t pdo_index,
00537                                      uint8_t pdo_subindex,
00539                                      void **data_ptr
00542                                      )
00543 {
00544     ec_slave_t *slave;
00545     ec_master_t *master;
00546     const ec_sii_pdo_t *pdo;
00547     const ec_sii_pdo_entry_t *entry;
00548 
00549     master = domain->master;
00550 
00551     // translate address and validate slave
00552     if (!(slave = ecrt_master_get_slave(master, address))) return NULL;
00553     if (ec_slave_validate(slave, vendor_id, product_code)) return NULL;
00554 
00555     if (!data_ptr) return slave;
00556 
00557     list_for_each_entry(pdo, &slave->sii_pdos, list) {
00558         list_for_each_entry(entry, &pdo->entries, list) {
00559             if (entry->index != pdo_index
00560                 || entry->subindex != pdo_subindex) continue;
00561 
00562             if (ec_domain_reg_pdo_entry(domain, slave, pdo, entry, data_ptr)) {
00563                 return NULL;
00564             }
00565 
00566             return slave;
00567         }
00568     }
00569 
00570     EC_ERR("Slave %i does not provide PDO 0x%04X:%i.\n",
00571            slave->ring_position, pdo_index, pdo_subindex);
00572     return NULL;
00573 }
00574 
00575 /*****************************************************************************/
00576 
00584 int ecrt_domain_register_pdo_list(ec_domain_t *domain,
00586                                   const ec_pdo_reg_t *pdos
00588                                   )
00589 {
00590     const ec_pdo_reg_t *pdo;
00591 
00592     for (pdo = pdos; pdo->slave_address; pdo++)
00593         if (!ecrt_domain_register_pdo(domain, pdo->slave_address,
00594                                       pdo->vendor_id,
00595                                       pdo->product_code,
00596                                       pdo->pdo_index,
00597                                       pdo->pdo_subindex,
00598                                       pdo->data_ptr))
00599             return -1;
00600 
00601     return 0;
00602 }
00603 
00604 /*****************************************************************************/
00605 
00613 ec_slave_t *ecrt_domain_register_pdo_range(ec_domain_t *domain,
00615                                            const char *address,
00618                                            uint32_t vendor_id,
00620                                            uint32_t product_code,
00622                                            ec_direction_t direction,
00624                                            uint16_t offset,
00626                                            uint16_t length,
00628                                            void **data_ptr
00631                                            )
00632 {
00633     ec_slave_t *slave;
00634     ec_master_t *master;
00635 
00636     master = domain->master;
00637 
00638     // translate address and validate slave
00639     if (!(slave = ecrt_master_get_slave(master, address))) return NULL;
00640     if (ec_slave_validate(slave, vendor_id, product_code)) return NULL;
00641 
00642     if (!data_ptr) return slave;
00643 
00644     if (ec_domain_reg_pdo_range(domain, slave,
00645                                 direction, offset, length, data_ptr)) {
00646         return NULL;
00647     }
00648 
00649     return slave;
00650 }
00651 
00652 /*****************************************************************************/
00653 
00659 void ecrt_domain_process(ec_domain_t *domain )
00660 {
00661     unsigned int working_counter_sum;
00662     ec_datagram_t *datagram;
00663 
00664     working_counter_sum = 0;
00665     domain->state = 0;
00666     list_for_each_entry(datagram, &domain->datagrams, list) {
00667         if (datagram->state == EC_DATAGRAM_RECEIVED) {
00668             working_counter_sum += datagram->working_counter;
00669         }
00670         else {
00671             domain->state = -1;
00672         }
00673     }
00674 
00675     if (working_counter_sum != domain->response_count) {
00676         domain->working_counter_changes++;
00677         domain->response_count = working_counter_sum;
00678     }
00679 
00680     if (domain->working_counter_changes &&
00681         jiffies - domain->notify_jiffies > HZ) {
00682         domain->notify_jiffies = jiffies;
00683         if (domain->working_counter_changes == 1) {
00684             EC_INFO("Domain %i working counter change: %i\n", domain->index,
00685                     domain->response_count);
00686         }
00687         else {
00688             EC_INFO("Domain %i: %u WC changes. Current response count: %i\n",
00689                     domain->index, domain->working_counter_changes,
00690                     domain->response_count);
00691         }
00692         domain->working_counter_changes = 0;
00693     }
00694 
00695     ec_domain_queue_datagrams(domain);
00696 }
00697 
00698 /*****************************************************************************/
00699 
00706 int ecrt_domain_state(const ec_domain_t *domain )
00707 {
00708     return domain->state;
00709 }
00710 
00711 /*****************************************************************************/
00712 
00715 EXPORT_SYMBOL(ecrt_domain_register_pdo);
00716 EXPORT_SYMBOL(ecrt_domain_register_pdo_list);
00717 EXPORT_SYMBOL(ecrt_domain_register_pdo_range);
00718 EXPORT_SYMBOL(ecrt_domain_process);
00719 EXPORT_SYMBOL(ecrt_domain_state);
00720 
00723 /*****************************************************************************/

Generated on Tue Nov 7 15:03:35 2006 for IgH EtherCAT master by  doxygen 1.4.4