00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
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_data_regs(ec_domain_t *);
00066 ssize_t ec_show_domain_attribute(struct kobject *, struct attribute *, char *);
00067
00068
00069
00072 EC_SYSFS_READ_ATTR(image_size);
00073
00074 static struct attribute *def_attrs[] = {
00075 &attr_image_size,
00076 NULL,
00077 };
00078
00079 static struct sysfs_ops sysfs_ops = {
00080 .show = &ec_show_domain_attribute,
00081 .store = NULL
00082 };
00083
00084 static struct kobj_type ktype_ec_domain = {
00085 .release = ec_domain_clear,
00086 .sysfs_ops = &sysfs_ops,
00087 .default_attrs = def_attrs
00088 };
00089
00092
00093
00099 int ec_domain_init(ec_domain_t *domain,
00100 ec_master_t *master,
00101 unsigned int index
00102 )
00103 {
00104 domain->master = master;
00105 domain->index = index;
00106 domain->data_size = 0;
00107 domain->base_address = 0;
00108 domain->response_count = 0xFFFFFFFF;
00109 domain->notify_jiffies = 0;
00110 domain->working_counter_changes = 0;
00111
00112 INIT_LIST_HEAD(&domain->data_regs);
00113 INIT_LIST_HEAD(&domain->datagrams);
00114
00115
00116 memset(&domain->kobj, 0x00, sizeof(struct kobject));
00117 kobject_init(&domain->kobj);
00118 domain->kobj.ktype = &ktype_ec_domain;
00119 domain->kobj.parent = &master->kobj;
00120 if (kobject_set_name(&domain->kobj, "domain%i", index)) {
00121 EC_ERR("Failed to set kobj name.\n");
00122 return -1;
00123 }
00124
00125 return 0;
00126 }
00127
00128
00129
00134 void ec_domain_clear(struct kobject *kobj )
00135 {
00136 ec_datagram_t *datagram, *next;
00137 ec_domain_t *domain;
00138
00139 domain = container_of(kobj, ec_domain_t, kobj);
00140
00141 EC_INFO("Clearing domain %i.\n", domain->index);
00142
00143 list_for_each_entry_safe(datagram, next, &domain->datagrams, list) {
00144 ec_datagram_clear(datagram);
00145 kfree(datagram);
00146 }
00147
00148 ec_domain_clear_data_regs(domain);
00149
00150 kfree(domain);
00151 }
00152
00153
00154
00160 int ec_domain_reg_pdo_entry(ec_domain_t *domain,
00161 ec_slave_t *slave,
00162 const ec_sii_pdo_t *pdo,
00163 const ec_sii_pdo_entry_t *entry,
00165 void **data_ptr
00167 )
00168 {
00169 ec_data_reg_t *data_reg;
00170 const ec_sii_sync_t *sync;
00171 const ec_sii_pdo_t *other_pdo;
00172 const ec_sii_pdo_entry_t *other_entry;
00173 unsigned int bit_offset, byte_offset, sync_found;
00174
00175
00176 sync_found = 0;
00177 list_for_each_entry(sync, &slave->sii_syncs, list) {
00178 if (sync->index == pdo->sync_index) {
00179 sync_found = 1;
00180 break;
00181 }
00182 }
00183
00184 if (!sync_found) {
00185 EC_ERR("No sync manager for PDO 0x%04X:%i.",
00186 pdo->index, entry->subindex);
00187 return -1;
00188 }
00189
00190
00191 bit_offset = 0;
00192 byte_offset = 0;
00193 list_for_each_entry(other_pdo, &slave->sii_pdos, list) {
00194 if (other_pdo->sync_index != sync->index) continue;
00195
00196 list_for_each_entry(other_entry, &other_pdo->entries, list) {
00197 if (other_entry == entry) {
00198 byte_offset = bit_offset / 8;
00199 break;
00200 }
00201 bit_offset += other_entry->bit_length;
00202 }
00203 }
00204
00205
00206 if (!(data_reg =
00207 (ec_data_reg_t *) kmalloc(sizeof(ec_data_reg_t), GFP_KERNEL))) {
00208 EC_ERR("Failed to allocate data registration.\n");
00209 return -1;
00210 }
00211
00212 if (ec_slave_prepare_fmmu(slave, domain, sync)) {
00213 EC_ERR("FMMU configuration failed.\n");
00214 kfree(data_reg);
00215 return -1;
00216 }
00217
00218 data_reg->slave = slave;
00219 data_reg->sync = sync;
00220 data_reg->sync_offset = byte_offset;
00221 data_reg->data_ptr = data_ptr;
00222
00223 list_add_tail(&data_reg->list, &domain->data_regs);
00224 return 0;
00225 }
00226
00227
00228
00233 void ec_domain_clear_data_regs(ec_domain_t *domain )
00234 {
00235 ec_data_reg_t *data_reg, *next;
00236
00237 list_for_each_entry_safe(data_reg, next, &domain->data_regs, list) {
00238 list_del(&data_reg->list);
00239 kfree(data_reg);
00240 }
00241 }
00242
00243
00244
00250 int ec_domain_add_datagram(ec_domain_t *domain,
00251 uint32_t offset,
00252 size_t data_size
00253 )
00254 {
00255 ec_datagram_t *datagram;
00256
00257 if (!(datagram = kmalloc(sizeof(ec_datagram_t), GFP_KERNEL))) {
00258 EC_ERR("Failed to allocate domain datagram!\n");
00259 return -1;
00260 }
00261
00262 ec_datagram_init(datagram);
00263
00264 if (ec_datagram_lrw(datagram, offset, data_size)) {
00265 kfree(datagram);
00266 return -1;
00267 }
00268
00269 list_add_tail(&datagram->list, &domain->datagrams);
00270 return 0;
00271 }
00272
00273
00274
00283 int ec_domain_alloc(ec_domain_t *domain,
00284 uint32_t base_address
00285 )
00286 {
00287 ec_data_reg_t *data_reg;
00288 ec_slave_t *slave;
00289 ec_fmmu_t *fmmu;
00290 unsigned int i, j, datagram_count;
00291 uint32_t pdo_off, pdo_off_datagram;
00292 uint32_t datagram_offset;
00293 size_t datagram_data_size, sync_size;
00294 ec_datagram_t *datagram;
00295
00296 domain->base_address = base_address;
00297
00298
00299 domain->data_size = 0;
00300 datagram_offset = base_address;
00301 datagram_data_size = 0;
00302 datagram_count = 0;
00303 list_for_each_entry(slave, &domain->master->slaves, list) {
00304 for (j = 0; j < slave->fmmu_count; j++) {
00305 fmmu = &slave->fmmus[j];
00306 if (fmmu->domain == domain) {
00307 fmmu->logical_start_address = base_address + domain->data_size;
00308 sync_size = ec_slave_calc_sync_size(slave, fmmu->sync);
00309 domain->data_size += sync_size;
00310 if (datagram_data_size + sync_size > EC_MAX_DATA_SIZE) {
00311 if (ec_domain_add_datagram(domain, datagram_offset,
00312 datagram_data_size)) return -1;
00313 datagram_offset += datagram_data_size;
00314 datagram_data_size = 0;
00315 datagram_count++;
00316 }
00317 datagram_data_size += sync_size;
00318 }
00319 }
00320 }
00321
00322
00323 if (datagram_data_size) {
00324 if (ec_domain_add_datagram(domain, datagram_offset,
00325 datagram_data_size))
00326 return -1;
00327 datagram_count++;
00328 }
00329
00330 if (!datagram_count) {
00331 EC_WARN("Domain %i contains no data!\n", domain->index);
00332 ec_domain_clear_data_regs(domain);
00333 return 0;
00334 }
00335
00336
00337 list_for_each_entry(data_reg, &domain->data_regs, list) {
00338 for (i = 0; i < data_reg->slave->fmmu_count; i++) {
00339 fmmu = &data_reg->slave->fmmus[i];
00340 if (fmmu->domain == domain && fmmu->sync == data_reg->sync) {
00341 pdo_off = fmmu->logical_start_address + data_reg->sync_offset;
00342
00343 list_for_each_entry(datagram, &domain->datagrams, list) {
00344 pdo_off_datagram = pdo_off - datagram->address.logical;
00345 if (pdo_off >= datagram->address.logical &&
00346 pdo_off_datagram < datagram->mem_size) {
00347 *data_reg->data_ptr = datagram->data +
00348 pdo_off_datagram;
00349 }
00350 }
00351 if (!data_reg->data_ptr) {
00352 EC_ERR("Failed to assign data pointer!\n");
00353 return -1;
00354 }
00355 break;
00356 }
00357 }
00358 }
00359
00360 EC_INFO("Domain %i - Allocated %i bytes in %i datagram%s\n",
00361 domain->index, domain->data_size, datagram_count,
00362 datagram_count == 1 ? "" : "s");
00363
00364 ec_domain_clear_data_regs(domain);
00365
00366 return 0;
00367 }
00368
00369
00370
00375 void ec_domain_queue(ec_domain_t *domain )
00376 {
00377 ec_datagram_t *datagram;
00378
00379 list_for_each_entry(datagram, &domain->datagrams, list) {
00380 ec_master_queue_datagram(domain->master, datagram);
00381 }
00382 }
00383
00384
00385
00391 ssize_t ec_show_domain_attribute(struct kobject *kobj,
00392 struct attribute *attr,
00393 char *buffer
00394 )
00395 {
00396 ec_domain_t *domain = container_of(kobj, ec_domain_t, kobj);
00397
00398 if (attr == &attr_image_size) {
00399 return sprintf(buffer, "%i\n", domain->data_size);
00400 }
00401
00402 return 0;
00403 }
00404
00405
00406
00407
00408
00416 ec_slave_t *ecrt_domain_register_pdo(ec_domain_t *domain,
00418 const char *address,
00421 uint32_t vendor_id,
00423 uint32_t product_code,
00425 uint16_t pdo_index,
00427 uint8_t pdo_subindex,
00429 void **data_ptr
00432 )
00433 {
00434 ec_slave_t *slave;
00435 ec_master_t *master;
00436 const ec_sii_pdo_t *pdo;
00437 const ec_sii_pdo_entry_t *entry;
00438
00439 master = domain->master;
00440
00441
00442 if (!(slave = ecrt_master_get_slave(master, address))) return NULL;
00443
00444 if (vendor_id != slave->sii_vendor_id ||
00445 product_code != slave->sii_product_code) {
00446 EC_ERR("Invalid slave type at position %i - Requested: 0x%08X 0x%08X,"
00447 " found: 0x%08X 0x%08X\".\n", slave->ring_position, vendor_id,
00448 product_code, slave->sii_vendor_id, slave->sii_product_code);
00449 return NULL;
00450 }
00451
00452 if (!data_ptr) {
00453
00454 slave->registered = 1;
00455 }
00456
00457 list_for_each_entry(pdo, &slave->sii_pdos, list) {
00458 list_for_each_entry(entry, &pdo->entries, list) {
00459 if (entry->index != pdo_index
00460 || entry->subindex != pdo_subindex) continue;
00461
00462 if (data_ptr) {
00463 ec_domain_reg_pdo_entry(domain, slave, pdo, entry, data_ptr);
00464 }
00465
00466 return slave;
00467 }
00468 }
00469
00470 EC_ERR("Slave %i does not provide PDO 0x%04X:%i.\n",
00471 slave->ring_position, pdo_index, pdo_subindex);
00472 slave->registered = 0;
00473 return NULL;
00474 }
00475
00476
00477
00485 int ecrt_domain_register_pdo_list(ec_domain_t *domain,
00487 const ec_pdo_reg_t *pdos
00489 )
00490 {
00491 const ec_pdo_reg_t *pdo;
00492
00493 for (pdo = pdos; pdo->slave_address; pdo++)
00494 if (!ecrt_domain_register_pdo(domain, pdo->slave_address,
00495 pdo->vendor_id,
00496 pdo->product_code,
00497 pdo->pdo_index,
00498 pdo->pdo_subindex,
00499 pdo->data_ptr))
00500 return -1;
00501
00502 return 0;
00503 }
00504
00505
00506
00512 void ecrt_domain_process(ec_domain_t *domain )
00513 {
00514 unsigned int working_counter_sum;
00515 ec_datagram_t *datagram;
00516
00517 working_counter_sum = 0;
00518 list_for_each_entry(datagram, &domain->datagrams, list) {
00519 if (datagram->state == EC_DATAGRAM_RECEIVED) {
00520 working_counter_sum += datagram->working_counter;
00521 }
00522 }
00523
00524 if (working_counter_sum != domain->response_count) {
00525 domain->working_counter_changes++;
00526 domain->response_count = working_counter_sum;
00527 }
00528
00529 if (domain->working_counter_changes &&
00530 jiffies - domain->notify_jiffies > HZ) {
00531 domain->notify_jiffies = jiffies;
00532 if (domain->working_counter_changes == 1) {
00533 EC_INFO("Domain %i working counter change: %i\n", domain->index,
00534 domain->response_count);
00535 }
00536 else {
00537 EC_INFO("Domain %i: %u WC changes. Current response count: %i\n",
00538 domain->index, domain->working_counter_changes,
00539 domain->response_count);
00540 }
00541 domain->working_counter_changes = 0;
00542 }
00543
00544 ec_domain_queue(domain);
00545 }
00546
00547
00548
00555 int ecrt_domain_state(const ec_domain_t *domain )
00556 {
00557 ec_datagram_t *datagram;
00558
00559 list_for_each_entry(datagram, &domain->datagrams, list) {
00560 if (datagram->state != EC_DATAGRAM_RECEIVED) return -1;
00561 }
00562
00563 return 0;
00564 }
00565
00566
00567
00570 EXPORT_SYMBOL(ecrt_domain_register_pdo);
00571 EXPORT_SYMBOL(ecrt_domain_register_pdo_list);
00572 EXPORT_SYMBOL(ecrt_domain_process);
00573 EXPORT_SYMBOL(ecrt_domain_state);
00574
00577