157 slave->dl_link[i] = 0; |
128 slave->dl_link[i] = 0; |
158 slave->dl_loop[i] = 0; |
129 slave->dl_loop[i] = 0; |
159 slave->dl_signal[i] = 0; |
130 slave->dl_signal[i] = 0; |
160 slave->sii.physical_layer[i] = 0xFF; |
131 slave->sii.physical_layer[i] = 0xFF; |
161 } |
132 } |
162 |
|
163 // init kobject and add it to the hierarchy |
|
164 memset(&slave->kobj, 0x00, sizeof(struct kobject)); |
|
165 kobject_init(&slave->kobj); |
|
166 slave->kobj.ktype = &ktype_ec_slave; |
|
167 slave->kobj.parent = &master->kobj; |
|
168 if (kobject_set_name(&slave->kobj, "slave%03i", slave->ring_position)) { |
|
169 EC_ERR("Failed to set kobject name.\n"); |
|
170 goto out_slave_put; |
|
171 } |
|
172 if (kobject_add(&slave->kobj)) { |
|
173 EC_ERR("Failed to add slave's kobject.\n"); |
|
174 goto out_slave_put; |
|
175 } |
|
176 |
|
177 // init Sdo kobject and add it to the hierarchy |
|
178 memset(&slave->sdo_kobj, 0x00, sizeof(struct kobject)); |
|
179 kobject_init(&slave->sdo_kobj); |
|
180 slave->sdo_kobj.ktype = &ktype_ec_slave_sdos; |
|
181 slave->sdo_kobj.parent = &slave->kobj; |
|
182 if (kobject_set_name(&slave->sdo_kobj, "sdos")) { |
|
183 EC_ERR("Failed to set kobject name.\n"); |
|
184 goto out_sdo_put; |
|
185 } |
|
186 if (kobject_add(&slave->sdo_kobj)) { |
|
187 EC_ERR("Failed to add Sdos kobject.\n"); |
|
188 goto out_sdo_put; |
|
189 } |
|
190 |
|
191 return 0; |
|
192 |
|
193 out_sdo_put: |
|
194 kobject_put(&slave->sdo_kobj); |
|
195 kobject_del(&slave->kobj); |
|
196 out_slave_put: |
|
197 kobject_put(&slave->kobj); |
|
198 return -1; |
|
199 } |
133 } |
200 |
134 |
201 /*****************************************************************************/ |
135 /*****************************************************************************/ |
202 |
136 |
203 /** |
137 /** |
204 Slave destructor. |
138 Slave destructor. |
205 Clears and frees a slave object. |
139 Clears and frees a slave object. |
206 */ |
140 */ |
207 |
141 |
208 void ec_slave_destroy(ec_slave_t *slave /**< EtherCAT slave */) |
142 void ec_slave_clear(ec_slave_t *slave /**< EtherCAT slave */) |
209 { |
143 { |
210 ec_sdo_t *sdo, *next_sdo; |
144 ec_sdo_t *sdo, *next_sdo; |
|
145 unsigned int i; |
|
146 ec_pdo_t *pdo, *next_pdo; |
211 |
147 |
212 if (slave->config) |
148 if (slave->config) |
213 ec_slave_config_detach(slave->config); |
149 ec_slave_config_detach(slave->config); |
214 |
150 |
215 // free all Sdos |
151 // free all Sdos |
216 list_for_each_entry_safe(sdo, next_sdo, &slave->sdo_dictionary, list) { |
152 list_for_each_entry_safe(sdo, next_sdo, &slave->sdo_dictionary, list) { |
217 list_del(&sdo->list); |
153 list_del(&sdo->list); |
218 ec_sdo_destroy(sdo); |
154 ec_sdo_clear(sdo); |
219 } |
155 kfree(sdo); |
220 |
156 } |
221 // free Sdo kobject |
|
222 kobject_del(&slave->sdo_kobj); |
|
223 kobject_put(&slave->sdo_kobj); |
|
224 |
|
225 // destroy self |
|
226 kobject_del(&slave->kobj); |
|
227 kobject_put(&slave->kobj); |
|
228 } |
|
229 |
|
230 /*****************************************************************************/ |
|
231 |
|
232 /** |
|
233 Clear and free slave. |
|
234 This method is called by the kobject, |
|
235 once there are no more references to it. |
|
236 */ |
|
237 |
|
238 void ec_slave_clear(struct kobject *kobj /**< kobject of the slave */) |
|
239 { |
|
240 ec_slave_t *slave; |
|
241 ec_pdo_t *pdo, *next_pdo; |
|
242 unsigned int i; |
|
243 |
|
244 slave = container_of(kobj, ec_slave_t, kobj); |
|
245 |
157 |
246 // free all strings |
158 // free all strings |
247 if (slave->sii.strings) { |
159 if (slave->sii.strings) { |
248 for (i = 0; i < slave->sii.string_count; i++) |
160 for (i = 0; i < slave->sii.string_count; i++) |
249 kfree(slave->sii.strings[i]); |
161 kfree(slave->sii.strings[i]); |
605 return slave->sii.strings[index]; |
505 return slave->sii.strings[index]; |
606 } |
506 } |
607 |
507 |
608 /*****************************************************************************/ |
508 /*****************************************************************************/ |
609 |
509 |
610 /** Outputs all information about a certain slave. |
|
611 */ |
|
612 ssize_t ec_slave_info(const ec_slave_t *slave, /**< EtherCAT slave */ |
|
613 char *buffer /**< Output buffer */ |
|
614 ) |
|
615 { |
|
616 const ec_sync_t *sync; |
|
617 const ec_pdo_t *pdo; |
|
618 const ec_pdo_entry_t *pdo_entry; |
|
619 int first, i; |
|
620 char *large_buffer, *buf; |
|
621 unsigned int size; |
|
622 |
|
623 if (!(large_buffer = (char *) kmalloc(PAGE_SIZE * 2, GFP_KERNEL))) { |
|
624 return -ENOMEM; |
|
625 } |
|
626 |
|
627 buf = large_buffer; |
|
628 |
|
629 buf += sprintf(buf, "Ring position: %u\n", |
|
630 slave->ring_position); |
|
631 buf += sprintf(buf, "State: "); |
|
632 buf += ec_state_string(slave->current_state, buf); |
|
633 buf += sprintf(buf, " ("); |
|
634 buf += ec_state_string(slave->requested_state, buf); |
|
635 buf += sprintf(buf, ")\n"); |
|
636 buf += sprintf(buf, "Flags: %s\n\n", slave->error_flag ? "ERROR" : "ok"); |
|
637 |
|
638 buf += sprintf(buf, "Data link status:\n"); |
|
639 for (i = 0; i < 4; i++) { |
|
640 buf += sprintf(buf, " Port %u: Phy %u (", |
|
641 i, slave->sii.physical_layer[i]); |
|
642 switch (slave->sii.physical_layer[i]) { |
|
643 case 0x00: |
|
644 buf += sprintf(buf, "EBUS"); |
|
645 break; |
|
646 case 0x01: |
|
647 buf += sprintf(buf, "100BASE-TX"); |
|
648 break; |
|
649 case 0x02: |
|
650 buf += sprintf(buf, "100BASE-FX"); |
|
651 break; |
|
652 default: |
|
653 buf += sprintf(buf, "unknown"); |
|
654 } |
|
655 buf += sprintf(buf, "), Link %s, Loop %s, %s\n", |
|
656 slave->dl_link[i] ? "up" : "down", |
|
657 slave->dl_loop[i] ? "closed" : "open", |
|
658 slave->dl_signal[i] ? "Signal detected" : "No signal"); |
|
659 } |
|
660 buf += sprintf(buf, "\n"); |
|
661 |
|
662 if (slave->sii.alias) |
|
663 buf += sprintf(buf, "Configured station alias:" |
|
664 " 0x%04X (%u)\n\n", slave->sii.alias, slave->sii.alias); |
|
665 |
|
666 buf += sprintf(buf, "Identity:\n"); |
|
667 buf += sprintf(buf, " Vendor ID: 0x%08X (%u)\n", |
|
668 slave->sii.vendor_id, slave->sii.vendor_id); |
|
669 buf += sprintf(buf, " Product code: 0x%08X (%u)\n", |
|
670 slave->sii.product_code, slave->sii.product_code); |
|
671 buf += sprintf(buf, " Revision number: 0x%08X (%u)\n", |
|
672 slave->sii.revision_number, slave->sii.revision_number); |
|
673 buf += sprintf(buf, " Serial number: 0x%08X (%u)\n\n", |
|
674 slave->sii.serial_number, slave->sii.serial_number); |
|
675 |
|
676 if (slave->sii.mailbox_protocols) { |
|
677 buf += sprintf(buf, "Mailboxes:\n"); |
|
678 buf += sprintf(buf, " RX: 0x%04X/%u, TX: 0x%04X/%u\n", |
|
679 slave->sii.rx_mailbox_offset, slave->sii.rx_mailbox_size, |
|
680 slave->sii.tx_mailbox_offset, slave->sii.tx_mailbox_size); |
|
681 buf += sprintf(buf, " Supported protocols: "); |
|
682 |
|
683 first = 1; |
|
684 if (slave->sii.mailbox_protocols & EC_MBOX_AOE) { |
|
685 buf += sprintf(buf, "AoE"); |
|
686 first = 0; |
|
687 } |
|
688 if (slave->sii.mailbox_protocols & EC_MBOX_EOE) { |
|
689 if (!first) buf += sprintf(buf, ", "); |
|
690 buf += sprintf(buf, "EoE"); |
|
691 first = 0; |
|
692 } |
|
693 if (slave->sii.mailbox_protocols & EC_MBOX_COE) { |
|
694 if (!first) buf += sprintf(buf, ", "); |
|
695 buf += sprintf(buf, "CoE"); |
|
696 first = 0; |
|
697 } |
|
698 if (slave->sii.mailbox_protocols & EC_MBOX_FOE) { |
|
699 if (!first) buf += sprintf(buf, ", "); |
|
700 buf += sprintf(buf, "FoE"); |
|
701 first = 0; |
|
702 } |
|
703 if (slave->sii.mailbox_protocols & EC_MBOX_SOE) { |
|
704 if (!first) buf += sprintf(buf, ", "); |
|
705 buf += sprintf(buf, "SoE"); |
|
706 first = 0; |
|
707 } |
|
708 if (slave->sii.mailbox_protocols & EC_MBOX_VOE) { |
|
709 if (!first) buf += sprintf(buf, ", "); |
|
710 buf += sprintf(buf, "VoE"); |
|
711 } |
|
712 buf += sprintf(buf, "\n\n"); |
|
713 } |
|
714 |
|
715 if (slave->sii.has_general) { |
|
716 buf += sprintf(buf, "General:\n"); |
|
717 |
|
718 if (slave->sii.group) |
|
719 buf += sprintf(buf, " Group: %s\n", slave->sii.group); |
|
720 if (slave->sii.image) |
|
721 buf += sprintf(buf, " Image: %s\n", slave->sii.image); |
|
722 if (slave->sii.order) |
|
723 buf += sprintf(buf, " Order number: %s\n", |
|
724 slave->sii.order); |
|
725 if (slave->sii.name) |
|
726 buf += sprintf(buf, " Name: %s\n", slave->sii.name); |
|
727 if (slave->sii.mailbox_protocols & EC_MBOX_COE) { |
|
728 buf += sprintf(buf, " CoE details:\n"); |
|
729 buf += sprintf(buf, " Enable Sdo: %s\n", |
|
730 slave->sii.coe_details.enable_sdo ? "yes" : "no"); |
|
731 buf += sprintf(buf, " Enable Sdo Info: %s\n", |
|
732 slave->sii.coe_details.enable_sdo_info ? "yes" : "no"); |
|
733 buf += sprintf(buf, " Enable Pdo Assign: %s\n", |
|
734 slave->sii.coe_details.enable_pdo_assign ? "yes" : "no"); |
|
735 buf += sprintf(buf, " Enable Pdo Configuration: %s\n", |
|
736 slave->sii.coe_details.enable_pdo_configuration ? |
|
737 "yes" : "no"); |
|
738 buf += sprintf(buf, " Enable Upload at startup: %s\n", |
|
739 slave->sii.coe_details.enable_upload_at_startup ? |
|
740 "yes" : "no"); |
|
741 buf += sprintf(buf, " Enable Sdo complete access: %s\n", |
|
742 slave->sii.coe_details.enable_sdo_complete_access |
|
743 ? "yes" : "no"); |
|
744 } |
|
745 |
|
746 buf += sprintf(buf, " Flags:\n"); |
|
747 buf += sprintf(buf, " Enable SafeOp: %s\n", |
|
748 slave->sii.general_flags.enable_safeop ? "yes" : "no"); |
|
749 buf += sprintf(buf, " Enable notLRW: %s\n", |
|
750 slave->sii.general_flags.enable_not_lrw ? "yes" : "no"); |
|
751 buf += sprintf(buf, " Current consumption: %i mA\n\n", |
|
752 slave->sii.current_on_ebus); |
|
753 } |
|
754 |
|
755 if (slave->sii.sync_count) { |
|
756 buf += sprintf(buf, "Sync managers / assigned Pdos:\n"); |
|
757 |
|
758 for (i = 0; i < slave->sii.sync_count; i++) { |
|
759 sync = &slave->sii.syncs[i]; |
|
760 buf += sprintf(buf, |
|
761 " SM%u: addr 0x%04X, size %u, control 0x%02X, %s\n", |
|
762 sync->index, sync->physical_start_address, |
|
763 sync->length, sync->control_register, |
|
764 sync->enable ? "enable" : "disable"); |
|
765 |
|
766 if (list_empty(&sync->pdos.list)) { |
|
767 buf += sprintf(buf, " No Pdos assigned.\n"); |
|
768 } else if (sync->assign_source != EC_ASSIGN_NONE) { |
|
769 buf += sprintf(buf, " Pdo assignment from "); |
|
770 switch (sync->assign_source) { |
|
771 case EC_ASSIGN_SII: |
|
772 buf += sprintf(buf, "SII"); |
|
773 break; |
|
774 case EC_ASSIGN_COE: |
|
775 buf += sprintf(buf, "CoE"); |
|
776 break; |
|
777 case EC_ASSIGN_CUSTOM: |
|
778 buf += sprintf(buf, "application"); |
|
779 break; |
|
780 default: |
|
781 buf += sprintf(buf, "?"); |
|
782 break; |
|
783 } |
|
784 buf += sprintf(buf, ".\n"); |
|
785 } |
|
786 |
|
787 list_for_each_entry(pdo, &sync->pdos.list, list) { |
|
788 buf += sprintf(buf, " %s 0x%04X \"%s\"\n", |
|
789 pdo->dir == EC_DIR_OUTPUT ? "RxPdo" : "TxPdo", |
|
790 pdo->index, pdo->name ? pdo->name : "???"); |
|
791 |
|
792 list_for_each_entry(pdo_entry, &pdo->entries, list) { |
|
793 buf += sprintf(buf, |
|
794 " 0x%04X:%02X, %u bit, \"%s\"\n", |
|
795 pdo_entry->index, pdo_entry->subindex, |
|
796 pdo_entry->bit_length, |
|
797 pdo_entry->name ? pdo_entry->name : "???"); |
|
798 } |
|
799 } |
|
800 } |
|
801 buf += sprintf(buf, "\n"); |
|
802 } |
|
803 |
|
804 // type-cast to avoid warnings on some compilers |
|
805 if (!list_empty((struct list_head *) &slave->sii.pdos)) { |
|
806 buf += sprintf(buf, "Available Pdos from SII:\n"); |
|
807 |
|
808 list_for_each_entry(pdo, &slave->sii.pdos, list) { |
|
809 buf += sprintf(buf, " %s 0x%04X \"%s\"", |
|
810 pdo->dir == EC_DIR_OUTPUT ? "RxPdo" : "TxPdo", |
|
811 pdo->index, pdo->name ? pdo->name : "???"); |
|
812 if (pdo->sync_index >= 0) |
|
813 buf += sprintf(buf, ", default assignment: SM%u.\n", |
|
814 pdo->sync_index); |
|
815 else |
|
816 buf += sprintf(buf, ", no default assignment.\n"); |
|
817 |
|
818 list_for_each_entry(pdo_entry, &pdo->entries, list) { |
|
819 buf += sprintf(buf, " 0x%04X:%02X, %u bit, \"%s\"\n", |
|
820 pdo_entry->index, pdo_entry->subindex, |
|
821 pdo_entry->bit_length, |
|
822 pdo_entry->name ? pdo_entry->name : "???"); |
|
823 } |
|
824 } |
|
825 buf += sprintf(buf, "\n"); |
|
826 } |
|
827 |
|
828 size = buf - large_buffer; |
|
829 if (size >= PAGE_SIZE) { |
|
830 const char trunc[] = "\n---TRUNCATED---\n"; |
|
831 unsigned int len = strlen(trunc); |
|
832 memcpy(large_buffer + PAGE_SIZE - len, trunc, len); |
|
833 } |
|
834 |
|
835 size = min(size, (unsigned int) PAGE_SIZE); |
|
836 memcpy(buffer, large_buffer, size); |
|
837 kfree(large_buffer); |
|
838 return size; |
|
839 } |
|
840 |
|
841 /*****************************************************************************/ |
|
842 |
|
843 /** |
510 /** |
844 * Writes SII contents to a slave. |
511 * Writes SII contents to a slave. |
845 * \return Zero on success, otherwise error code. |
512 * \return Zero on success, otherwise error code. |
846 */ |
513 */ |
847 |
514 |