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(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
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
00147 list_for_each_entry(datagram, &domain->datagrams, list) {
00148 if (!list_empty(&datagram->queue))
00149 list_del_init(&datagram->queue);
00150 }
00151
00152
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
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
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
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
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
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
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
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
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
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
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
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
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
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