1 // SPDX-License-Identifier: GPL-2.0
3 * Generic Counter sysfs interface
4 * Copyright (C) 2020 William Breathitt Gray
6 #include <linux/counter.h>
7 #include <linux/device.h>
10 #include <linux/kernel.h>
11 #include <linux/kfifo.h>
12 #include <linux/kstrtox.h>
13 #include <linux/list.h>
14 #include <linux/mutex.h>
15 #include <linux/spinlock.h>
16 #include <linux/string.h>
17 #include <linux/sysfs.h>
18 #include <linux/types.h>
20 #include "counter-sysfs.h"
22 static inline struct counter_device *counter_from_dev(struct device *dev)
24 return container_of(dev, struct counter_device, dev);
28 * struct counter_attribute - Counter sysfs attribute
29 * @dev_attr: device attribute for sysfs
30 * @l: node to add Counter attribute to attribute group list
31 * @comp: Counter component callbacks and data
32 * @scope: Counter scope of the attribute
33 * @parent: pointer to the parent component
35 struct counter_attribute {
36 struct device_attribute dev_attr;
39 struct counter_comp comp;
40 enum counter_scope scope;
44 #define to_counter_attribute(_dev_attr) \
45 container_of(_dev_attr, struct counter_attribute, dev_attr)
48 * struct counter_attribute_group - container for attribute group
49 * @name: name of the attribute group
50 * @attr_list: list to keep track of created attributes
51 * @num_attr: number of attributes
53 struct counter_attribute_group {
55 struct list_head attr_list;
59 static const char *const counter_function_str[] = {
60 [COUNTER_FUNCTION_INCREASE] = "increase",
61 [COUNTER_FUNCTION_DECREASE] = "decrease",
62 [COUNTER_FUNCTION_PULSE_DIRECTION] = "pulse-direction",
63 [COUNTER_FUNCTION_QUADRATURE_X1_A] = "quadrature x1 a",
64 [COUNTER_FUNCTION_QUADRATURE_X1_B] = "quadrature x1 b",
65 [COUNTER_FUNCTION_QUADRATURE_X2_A] = "quadrature x2 a",
66 [COUNTER_FUNCTION_QUADRATURE_X2_B] = "quadrature x2 b",
67 [COUNTER_FUNCTION_QUADRATURE_X4] = "quadrature x4"
70 static const char *const counter_signal_value_str[] = {
71 [COUNTER_SIGNAL_LEVEL_LOW] = "low",
72 [COUNTER_SIGNAL_LEVEL_HIGH] = "high"
75 static const char *const counter_synapse_action_str[] = {
76 [COUNTER_SYNAPSE_ACTION_NONE] = "none",
77 [COUNTER_SYNAPSE_ACTION_RISING_EDGE] = "rising edge",
78 [COUNTER_SYNAPSE_ACTION_FALLING_EDGE] = "falling edge",
79 [COUNTER_SYNAPSE_ACTION_BOTH_EDGES] = "both edges"
82 static const char *const counter_count_direction_str[] = {
83 [COUNTER_COUNT_DIRECTION_FORWARD] = "forward",
84 [COUNTER_COUNT_DIRECTION_BACKWARD] = "backward"
87 static const char *const counter_count_mode_str[] = {
88 [COUNTER_COUNT_MODE_NORMAL] = "normal",
89 [COUNTER_COUNT_MODE_RANGE_LIMIT] = "range limit",
90 [COUNTER_COUNT_MODE_NON_RECYCLE] = "non-recycle",
91 [COUNTER_COUNT_MODE_MODULO_N] = "modulo-n"
94 static const char *const counter_signal_polarity_str[] = {
95 [COUNTER_SIGNAL_POLARITY_POSITIVE] = "positive",
96 [COUNTER_SIGNAL_POLARITY_NEGATIVE] = "negative"
99 static ssize_t counter_comp_u8_show(struct device *dev,
100 struct device_attribute *attr, char *buf)
102 const struct counter_attribute *const a = to_counter_attribute(attr);
103 struct counter_device *const counter = counter_from_dev(dev);
108 case COUNTER_SCOPE_DEVICE:
109 err = a->comp.device_u8_read(counter, &data);
111 case COUNTER_SCOPE_SIGNAL:
112 err = a->comp.signal_u8_read(counter, a->parent, &data);
114 case COUNTER_SCOPE_COUNT:
115 err = a->comp.count_u8_read(counter, a->parent, &data);
123 if (a->comp.type == COUNTER_COMP_BOOL)
124 /* data should already be boolean but ensure just to be safe */
127 return sysfs_emit(buf, "%u\n", (unsigned int)data);
130 static ssize_t counter_comp_u8_store(struct device *dev,
131 struct device_attribute *attr,
132 const char *buf, size_t len)
134 const struct counter_attribute *const a = to_counter_attribute(attr);
135 struct counter_device *const counter = counter_from_dev(dev);
140 if (a->comp.type == COUNTER_COMP_BOOL) {
141 err = kstrtobool(buf, &bool_data);
144 err = kstrtou8(buf, 0, &data);
149 case COUNTER_SCOPE_DEVICE:
150 err = a->comp.device_u8_write(counter, data);
152 case COUNTER_SCOPE_SIGNAL:
153 err = a->comp.signal_u8_write(counter, a->parent, data);
155 case COUNTER_SCOPE_COUNT:
156 err = a->comp.count_u8_write(counter, a->parent, data);
167 static ssize_t counter_comp_u32_show(struct device *dev,
168 struct device_attribute *attr, char *buf)
170 const struct counter_attribute *const a = to_counter_attribute(attr);
171 struct counter_device *const counter = counter_from_dev(dev);
172 const struct counter_available *const avail = a->comp.priv;
177 case COUNTER_SCOPE_DEVICE:
178 err = a->comp.device_u32_read(counter, &data);
180 case COUNTER_SCOPE_SIGNAL:
181 err = a->comp.signal_u32_read(counter, a->parent, &data);
183 case COUNTER_SCOPE_COUNT:
184 if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION)
185 err = a->comp.action_read(counter, a->parent,
186 a->comp.priv, &data);
188 err = a->comp.count_u32_read(counter, a->parent, &data);
196 switch (a->comp.type) {
197 case COUNTER_COMP_FUNCTION:
198 return sysfs_emit(buf, "%s\n", counter_function_str[data]);
199 case COUNTER_COMP_SIGNAL_LEVEL:
200 return sysfs_emit(buf, "%s\n", counter_signal_value_str[data]);
201 case COUNTER_COMP_SYNAPSE_ACTION:
202 return sysfs_emit(buf, "%s\n", counter_synapse_action_str[data]);
203 case COUNTER_COMP_ENUM:
204 return sysfs_emit(buf, "%s\n", avail->strs[data]);
205 case COUNTER_COMP_COUNT_DIRECTION:
206 return sysfs_emit(buf, "%s\n", counter_count_direction_str[data]);
207 case COUNTER_COMP_COUNT_MODE:
208 return sysfs_emit(buf, "%s\n", counter_count_mode_str[data]);
209 case COUNTER_COMP_SIGNAL_POLARITY:
210 return sysfs_emit(buf, "%s\n", counter_signal_polarity_str[data]);
212 return sysfs_emit(buf, "%u\n", (unsigned int)data);
216 static int counter_find_enum(u32 *const enum_item, const u32 *const enums,
217 const size_t num_enums, const char *const buf,
218 const char *const string_array[])
222 for (index = 0; index < num_enums; index++) {
223 *enum_item = enums[index];
224 if (sysfs_streq(buf, string_array[*enum_item]))
231 static ssize_t counter_comp_u32_store(struct device *dev,
232 struct device_attribute *attr,
233 const char *buf, size_t len)
235 const struct counter_attribute *const a = to_counter_attribute(attr);
236 struct counter_device *const counter = counter_from_dev(dev);
237 struct counter_count *const count = a->parent;
238 struct counter_synapse *const synapse = a->comp.priv;
239 const struct counter_available *const avail = a->comp.priv;
243 switch (a->comp.type) {
244 case COUNTER_COMP_FUNCTION:
245 err = counter_find_enum(&data, count->functions_list,
246 count->num_functions, buf,
247 counter_function_str);
249 case COUNTER_COMP_SYNAPSE_ACTION:
250 err = counter_find_enum(&data, synapse->actions_list,
251 synapse->num_actions, buf,
252 counter_synapse_action_str);
254 case COUNTER_COMP_ENUM:
255 err = __sysfs_match_string(avail->strs, avail->num_items, buf);
258 case COUNTER_COMP_COUNT_MODE:
259 err = counter_find_enum(&data, avail->enums, avail->num_items,
260 buf, counter_count_mode_str);
262 case COUNTER_COMP_SIGNAL_POLARITY:
263 err = counter_find_enum(&data, avail->enums, avail->num_items,
264 buf, counter_signal_polarity_str);
267 err = kstrtou32(buf, 0, &data);
274 case COUNTER_SCOPE_DEVICE:
275 err = a->comp.device_u32_write(counter, data);
277 case COUNTER_SCOPE_SIGNAL:
278 err = a->comp.signal_u32_write(counter, a->parent, data);
280 case COUNTER_SCOPE_COUNT:
281 if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION)
282 err = a->comp.action_write(counter, count, synapse,
285 err = a->comp.count_u32_write(counter, count, data);
296 static ssize_t counter_comp_u64_show(struct device *dev,
297 struct device_attribute *attr, char *buf)
299 const struct counter_attribute *const a = to_counter_attribute(attr);
300 struct counter_device *const counter = counter_from_dev(dev);
305 case COUNTER_SCOPE_DEVICE:
306 err = a->comp.device_u64_read(counter, &data);
308 case COUNTER_SCOPE_SIGNAL:
309 err = a->comp.signal_u64_read(counter, a->parent, &data);
311 case COUNTER_SCOPE_COUNT:
312 err = a->comp.count_u64_read(counter, a->parent, &data);
320 return sysfs_emit(buf, "%llu\n", (unsigned long long)data);
323 static ssize_t counter_comp_u64_store(struct device *dev,
324 struct device_attribute *attr,
325 const char *buf, size_t len)
327 const struct counter_attribute *const a = to_counter_attribute(attr);
328 struct counter_device *const counter = counter_from_dev(dev);
332 err = kstrtou64(buf, 0, &data);
337 case COUNTER_SCOPE_DEVICE:
338 err = a->comp.device_u64_write(counter, data);
340 case COUNTER_SCOPE_SIGNAL:
341 err = a->comp.signal_u64_write(counter, a->parent, data);
343 case COUNTER_SCOPE_COUNT:
344 err = a->comp.count_u64_write(counter, a->parent, data);
355 static ssize_t counter_comp_array_u32_show(struct device *dev,
356 struct device_attribute *attr,
359 const struct counter_attribute *const a = to_counter_attribute(attr);
360 struct counter_device *const counter = counter_from_dev(dev);
361 const struct counter_array *const element = a->comp.priv;
365 if (a->scope != COUNTER_SCOPE_SIGNAL ||
366 element->type != COUNTER_COMP_SIGNAL_POLARITY)
369 err = a->comp.signal_array_u32_read(counter, a->parent, element->idx,
374 return sysfs_emit(buf, "%s\n", counter_signal_polarity_str[data]);
377 static ssize_t counter_comp_array_u32_store(struct device *dev,
378 struct device_attribute *attr,
379 const char *buf, size_t len)
381 const struct counter_attribute *const a = to_counter_attribute(attr);
382 struct counter_device *const counter = counter_from_dev(dev);
383 const struct counter_array *const element = a->comp.priv;
387 if (element->type != COUNTER_COMP_SIGNAL_POLARITY ||
388 a->scope != COUNTER_SCOPE_SIGNAL)
391 err = counter_find_enum(&data, element->avail->enums,
392 element->avail->num_items, buf,
393 counter_signal_polarity_str);
397 err = a->comp.signal_array_u32_write(counter, a->parent, element->idx,
405 static ssize_t counter_comp_array_u64_show(struct device *dev,
406 struct device_attribute *attr,
409 const struct counter_attribute *const a = to_counter_attribute(attr);
410 struct counter_device *const counter = counter_from_dev(dev);
411 const struct counter_array *const element = a->comp.priv;
416 case COUNTER_SCOPE_DEVICE:
417 err = a->comp.device_array_u64_read(counter, element->idx,
420 case COUNTER_SCOPE_SIGNAL:
421 err = a->comp.signal_array_u64_read(counter, a->parent,
422 element->idx, &data);
424 case COUNTER_SCOPE_COUNT:
425 err = a->comp.count_array_u64_read(counter, a->parent,
426 element->idx, &data);
434 return sysfs_emit(buf, "%llu\n", (unsigned long long)data);
437 static ssize_t counter_comp_array_u64_store(struct device *dev,
438 struct device_attribute *attr,
439 const char *buf, size_t len)
441 const struct counter_attribute *const a = to_counter_attribute(attr);
442 struct counter_device *const counter = counter_from_dev(dev);
443 const struct counter_array *const element = a->comp.priv;
447 err = kstrtou64(buf, 0, &data);
452 case COUNTER_SCOPE_DEVICE:
453 err = a->comp.device_array_u64_write(counter, element->idx,
456 case COUNTER_SCOPE_SIGNAL:
457 err = a->comp.signal_array_u64_write(counter, a->parent,
460 case COUNTER_SCOPE_COUNT:
461 err = a->comp.count_array_u64_write(counter, a->parent,
473 static ssize_t enums_available_show(const u32 *const enums,
474 const size_t num_enums,
475 const char *const strs[], char *buf)
480 for (index = 0; index < num_enums; index++)
481 len += sysfs_emit_at(buf, len, "%s\n", strs[enums[index]]);
486 static ssize_t strs_available_show(const struct counter_available *const avail,
492 for (index = 0; index < avail->num_items; index++)
493 len += sysfs_emit_at(buf, len, "%s\n", avail->strs[index]);
498 static ssize_t counter_comp_available_show(struct device *dev,
499 struct device_attribute *attr,
502 const struct counter_attribute *const a = to_counter_attribute(attr);
503 const struct counter_count *const count = a->parent;
504 const struct counter_synapse *const synapse = a->comp.priv;
505 const struct counter_available *const avail = a->comp.priv;
507 switch (a->comp.type) {
508 case COUNTER_COMP_FUNCTION:
509 return enums_available_show(count->functions_list,
510 count->num_functions,
511 counter_function_str, buf);
512 case COUNTER_COMP_SYNAPSE_ACTION:
513 return enums_available_show(synapse->actions_list,
514 synapse->num_actions,
515 counter_synapse_action_str, buf);
516 case COUNTER_COMP_ENUM:
517 return strs_available_show(avail, buf);
518 case COUNTER_COMP_COUNT_MODE:
519 return enums_available_show(avail->enums, avail->num_items,
520 counter_count_mode_str, buf);
526 static int counter_avail_attr_create(struct device *const dev,
527 struct counter_attribute_group *const group,
528 const struct counter_comp *const comp, void *const parent)
530 struct counter_attribute *counter_attr;
531 struct device_attribute *dev_attr;
533 counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
537 /* Configure Counter attribute */
538 counter_attr->comp.type = comp->type;
539 counter_attr->comp.priv = comp->priv;
540 counter_attr->parent = parent;
542 /* Initialize sysfs attribute */
543 dev_attr = &counter_attr->dev_attr;
544 sysfs_attr_init(&dev_attr->attr);
546 /* Configure device attribute */
547 dev_attr->attr.name = devm_kasprintf(dev, GFP_KERNEL, "%s_available",
549 if (!dev_attr->attr.name)
551 dev_attr->attr.mode = 0444;
552 dev_attr->show = counter_comp_available_show;
554 /* Store list node */
555 list_add(&counter_attr->l, &group->attr_list);
561 static int counter_attr_create(struct device *const dev,
562 struct counter_attribute_group *const group,
563 const struct counter_comp *const comp,
564 const enum counter_scope scope,
567 const struct counter_array *const array = comp->priv;
568 struct counter_attribute *counter_attr;
569 struct device_attribute *dev_attr;
571 counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
575 /* Configure Counter attribute */
576 counter_attr->comp = *comp;
577 counter_attr->scope = scope;
578 counter_attr->parent = parent;
580 /* Configure device attribute */
581 dev_attr = &counter_attr->dev_attr;
582 sysfs_attr_init(&dev_attr->attr);
583 dev_attr->attr.name = comp->name;
584 switch (comp->type) {
585 case COUNTER_COMP_U8:
586 case COUNTER_COMP_BOOL:
587 if (comp->device_u8_read) {
588 dev_attr->attr.mode |= 0444;
589 dev_attr->show = counter_comp_u8_show;
591 if (comp->device_u8_write) {
592 dev_attr->attr.mode |= 0200;
593 dev_attr->store = counter_comp_u8_store;
596 case COUNTER_COMP_SIGNAL_LEVEL:
597 case COUNTER_COMP_FUNCTION:
598 case COUNTER_COMP_SYNAPSE_ACTION:
599 case COUNTER_COMP_ENUM:
600 case COUNTER_COMP_COUNT_DIRECTION:
601 case COUNTER_COMP_COUNT_MODE:
602 case COUNTER_COMP_SIGNAL_POLARITY:
603 if (comp->device_u32_read) {
604 dev_attr->attr.mode |= 0444;
605 dev_attr->show = counter_comp_u32_show;
607 if (comp->device_u32_write) {
608 dev_attr->attr.mode |= 0200;
609 dev_attr->store = counter_comp_u32_store;
612 case COUNTER_COMP_U64:
613 if (comp->device_u64_read) {
614 dev_attr->attr.mode |= 0444;
615 dev_attr->show = counter_comp_u64_show;
617 if (comp->device_u64_write) {
618 dev_attr->attr.mode |= 0200;
619 dev_attr->store = counter_comp_u64_store;
622 case COUNTER_COMP_ARRAY:
623 switch (array->type) {
624 case COUNTER_COMP_SIGNAL_POLARITY:
625 if (comp->signal_array_u32_read) {
626 dev_attr->attr.mode |= 0444;
627 dev_attr->show = counter_comp_array_u32_show;
629 if (comp->signal_array_u32_write) {
630 dev_attr->attr.mode |= 0200;
631 dev_attr->store = counter_comp_array_u32_store;
634 case COUNTER_COMP_U64:
635 if (comp->device_array_u64_read) {
636 dev_attr->attr.mode |= 0444;
637 dev_attr->show = counter_comp_array_u64_show;
639 if (comp->device_array_u64_write) {
640 dev_attr->attr.mode |= 0200;
641 dev_attr->store = counter_comp_array_u64_store;
652 /* Store list node */
653 list_add(&counter_attr->l, &group->attr_list);
656 /* Create "*_available" attribute if needed */
657 switch (comp->type) {
658 case COUNTER_COMP_FUNCTION:
659 case COUNTER_COMP_SYNAPSE_ACTION:
660 case COUNTER_COMP_ENUM:
661 case COUNTER_COMP_COUNT_MODE:
662 return counter_avail_attr_create(dev, group, comp, parent);
668 static ssize_t counter_comp_name_show(struct device *dev,
669 struct device_attribute *attr, char *buf)
671 return sysfs_emit(buf, "%s\n", to_counter_attribute(attr)->comp.name);
674 static int counter_name_attr_create(struct device *const dev,
675 struct counter_attribute_group *const group,
676 const char *const name)
678 struct counter_attribute *counter_attr;
680 counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
684 /* Configure Counter attribute */
685 counter_attr->comp.name = name;
687 /* Configure device attribute */
688 sysfs_attr_init(&counter_attr->dev_attr.attr);
689 counter_attr->dev_attr.attr.name = "name";
690 counter_attr->dev_attr.attr.mode = 0444;
691 counter_attr->dev_attr.show = counter_comp_name_show;
693 /* Store list node */
694 list_add(&counter_attr->l, &group->attr_list);
700 static ssize_t counter_comp_id_show(struct device *dev,
701 struct device_attribute *attr, char *buf)
703 const size_t id = (size_t)to_counter_attribute(attr)->comp.priv;
705 return sysfs_emit(buf, "%zu\n", id);
708 static int counter_comp_id_attr_create(struct device *const dev,
709 struct counter_attribute_group *const group,
710 const char *name, const size_t id)
712 struct counter_attribute *counter_attr;
714 /* Allocate Counter attribute */
715 counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
719 /* Generate component ID name */
720 name = devm_kasprintf(dev, GFP_KERNEL, "%s_component_id", name);
724 /* Configure Counter attribute */
725 counter_attr->comp.priv = (void *)id;
727 /* Configure device attribute */
728 sysfs_attr_init(&counter_attr->dev_attr.attr);
729 counter_attr->dev_attr.attr.name = name;
730 counter_attr->dev_attr.attr.mode = 0444;
731 counter_attr->dev_attr.show = counter_comp_id_show;
733 /* Store list node */
734 list_add(&counter_attr->l, &group->attr_list);
740 static int counter_ext_attrs_create(struct device *const dev,
741 struct counter_attribute_group *const group,
742 const struct counter_comp *const ext,
743 const enum counter_scope scope,
744 void *const parent, const size_t id)
748 /* Create main extension attribute */
749 err = counter_attr_create(dev, group, ext, scope, parent);
753 /* Create extension id attribute */
754 return counter_comp_id_attr_create(dev, group, ext->name, id);
757 static int counter_array_attrs_create(struct device *const dev,
758 struct counter_attribute_group *const group,
759 const struct counter_comp *const comp,
760 const enum counter_scope scope,
761 void *const parent, const size_t id)
763 const struct counter_array *const array = comp->priv;
764 struct counter_comp ext = *comp;
765 struct counter_array *element;
769 /* Create an attribute for each array element */
770 for (idx = 0; idx < array->length; idx++) {
771 /* Generate array element attribute name */
772 ext.name = devm_kasprintf(dev, GFP_KERNEL, "%s%zu", comp->name,
777 /* Allocate and configure array element */
778 element = devm_kzalloc(dev, sizeof(*element), GFP_KERNEL);
781 element->type = array->type;
782 element->avail = array->avail;
786 /* Create all attributes associated with the array element */
787 err = counter_ext_attrs_create(dev, group, &ext, scope, parent,
796 static int counter_sysfs_exts_add(struct device *const dev,
797 struct counter_attribute_group *const group,
798 const struct counter_comp *const exts,
799 const size_t num_ext,
800 const enum counter_scope scope,
804 const struct counter_comp *ext;
807 const struct counter_array *array;
809 /* Create attributes for each extension */
810 for (i = 0; i < num_ext; i++) {
812 if (ext->type == COUNTER_COMP_ARRAY) {
813 err = counter_array_attrs_create(dev, group, ext, scope,
818 err = counter_ext_attrs_create(dev, group, ext, scope,
829 static struct counter_comp counter_signal_comp = {
830 .type = COUNTER_COMP_SIGNAL_LEVEL,
834 static int counter_signal_attrs_create(struct counter_device *const counter,
835 struct counter_attribute_group *const cattr_group,
836 struct counter_signal *const signal)
838 const enum counter_scope scope = COUNTER_SCOPE_SIGNAL;
839 struct device *const dev = &counter->dev;
841 struct counter_comp comp;
843 /* Create main Signal attribute */
844 comp = counter_signal_comp;
845 comp.signal_u32_read = counter->ops->signal_read;
846 err = counter_attr_create(dev, cattr_group, &comp, scope, signal);
850 /* Create Signal name attribute */
851 err = counter_name_attr_create(dev, cattr_group, signal->name);
855 /* Add Signal extensions */
856 return counter_sysfs_exts_add(dev, cattr_group, signal->ext,
857 signal->num_ext, scope, signal);
860 static int counter_sysfs_signals_add(struct counter_device *const counter,
861 struct counter_attribute_group *const groups)
866 /* Add each Signal */
867 for (i = 0; i < counter->num_signals; i++) {
868 /* Generate Signal attribute directory name */
869 groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL,
874 /* Create all attributes associated with Signal */
875 err = counter_signal_attrs_create(counter, groups + i,
876 counter->signals + i);
884 static int counter_sysfs_synapses_add(struct counter_device *const counter,
885 struct counter_attribute_group *const group,
886 struct counter_count *const count)
890 /* Add each Synapse */
891 for (i = 0; i < count->num_synapses; i++) {
892 struct device *const dev = &counter->dev;
893 struct counter_synapse *synapse;
895 struct counter_comp comp;
898 synapse = count->synapses + i;
900 /* Generate Synapse action name */
901 id = synapse->signal - counter->signals;
902 comp.name = devm_kasprintf(dev, GFP_KERNEL, "signal%zu_action",
907 /* Create action attribute */
908 comp.type = COUNTER_COMP_SYNAPSE_ACTION;
909 comp.action_read = counter->ops->action_read;
910 comp.action_write = counter->ops->action_write;
912 err = counter_attr_create(dev, group, &comp,
913 COUNTER_SCOPE_COUNT, count);
917 /* Create Synapse component ID attribute */
918 err = counter_comp_id_attr_create(dev, group, comp.name, i);
926 static struct counter_comp counter_count_comp =
927 COUNTER_COMP_COUNT_U64("count", NULL, NULL);
929 static struct counter_comp counter_function_comp = {
930 .type = COUNTER_COMP_FUNCTION,
934 static int counter_count_attrs_create(struct counter_device *const counter,
935 struct counter_attribute_group *const cattr_group,
936 struct counter_count *const count)
938 const enum counter_scope scope = COUNTER_SCOPE_COUNT;
939 struct device *const dev = &counter->dev;
941 struct counter_comp comp;
943 /* Create main Count attribute */
944 comp = counter_count_comp;
945 comp.count_u64_read = counter->ops->count_read;
946 comp.count_u64_write = counter->ops->count_write;
947 err = counter_attr_create(dev, cattr_group, &comp, scope, count);
951 /* Create Count name attribute */
952 err = counter_name_attr_create(dev, cattr_group, count->name);
956 /* Create Count function attribute */
957 comp = counter_function_comp;
958 comp.count_u32_read = counter->ops->function_read;
959 comp.count_u32_write = counter->ops->function_write;
960 err = counter_attr_create(dev, cattr_group, &comp, scope, count);
964 /* Add Count extensions */
965 return counter_sysfs_exts_add(dev, cattr_group, count->ext,
966 count->num_ext, scope, count);
969 static int counter_sysfs_counts_add(struct counter_device *const counter,
970 struct counter_attribute_group *const groups)
973 struct counter_count *count;
977 for (i = 0; i < counter->num_counts; i++) {
978 count = counter->counts + i;
980 /* Generate Count attribute directory name */
981 groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL,
986 /* Add sysfs attributes of the Synapses */
987 err = counter_sysfs_synapses_add(counter, groups + i, count);
991 /* Create all attributes associated with Count */
992 err = counter_count_attrs_create(counter, groups + i, count);
1000 static int counter_num_signals_read(struct counter_device *counter, u8 *val)
1002 *val = counter->num_signals;
1006 static int counter_num_counts_read(struct counter_device *counter, u8 *val)
1008 *val = counter->num_counts;
1012 static int counter_events_queue_size_read(struct counter_device *counter,
1015 *val = kfifo_size(&counter->events);
1019 static int counter_events_queue_size_write(struct counter_device *counter,
1022 DECLARE_KFIFO_PTR(events, struct counter_event);
1024 unsigned long flags;
1026 /* Allocate new events queue */
1027 err = kfifo_alloc(&events, val, GFP_KERNEL);
1031 /* Swap in new events queue */
1032 mutex_lock(&counter->events_out_lock);
1033 spin_lock_irqsave(&counter->events_in_lock, flags);
1034 kfifo_free(&counter->events);
1035 counter->events.kfifo = events.kfifo;
1036 spin_unlock_irqrestore(&counter->events_in_lock, flags);
1037 mutex_unlock(&counter->events_out_lock);
1042 static struct counter_comp counter_num_signals_comp =
1043 COUNTER_COMP_DEVICE_U8("num_signals", counter_num_signals_read, NULL);
1045 static struct counter_comp counter_num_counts_comp =
1046 COUNTER_COMP_DEVICE_U8("num_counts", counter_num_counts_read, NULL);
1048 static struct counter_comp counter_events_queue_size_comp =
1049 COUNTER_COMP_DEVICE_U64("events_queue_size",
1050 counter_events_queue_size_read,
1051 counter_events_queue_size_write);
1053 static int counter_sysfs_attr_add(struct counter_device *const counter,
1054 struct counter_attribute_group *cattr_group)
1056 const enum counter_scope scope = COUNTER_SCOPE_DEVICE;
1057 struct device *const dev = &counter->dev;
1060 /* Add Signals sysfs attributes */
1061 err = counter_sysfs_signals_add(counter, cattr_group);
1064 cattr_group += counter->num_signals;
1066 /* Add Counts sysfs attributes */
1067 err = counter_sysfs_counts_add(counter, cattr_group);
1070 cattr_group += counter->num_counts;
1072 /* Create name attribute */
1073 err = counter_name_attr_create(dev, cattr_group, counter->name);
1077 /* Create num_signals attribute */
1078 err = counter_attr_create(dev, cattr_group, &counter_num_signals_comp,
1083 /* Create num_counts attribute */
1084 err = counter_attr_create(dev, cattr_group, &counter_num_counts_comp,
1089 /* Create events_queue_size attribute */
1090 err = counter_attr_create(dev, cattr_group,
1091 &counter_events_queue_size_comp, scope, NULL);
1095 /* Add device extensions */
1096 return counter_sysfs_exts_add(dev, cattr_group, counter->ext,
1097 counter->num_ext, scope, NULL);
1103 * counter_sysfs_add - Adds Counter sysfs attributes to the device structure
1104 * @counter: Pointer to the Counter device structure
1106 * Counter sysfs attributes are created and added to the respective device
1107 * structure for later registration to the system. Resource-managed memory
1108 * allocation is performed by this function, and this memory should be freed
1109 * when no longer needed (automatically by a device_unregister call, or
1110 * manually by a devres_release_all call).
1112 int counter_sysfs_add(struct counter_device *const counter)
1114 struct device *const dev = &counter->dev;
1115 const size_t num_groups = counter->num_signals + counter->num_counts + 1;
1116 struct counter_attribute_group *cattr_groups;
1119 struct attribute_group *groups;
1120 struct counter_attribute *p;
1122 /* Allocate space for attribute groups (signals, counts, and ext) */
1123 cattr_groups = devm_kcalloc(dev, num_groups, sizeof(*cattr_groups),
1128 /* Initialize attribute lists */
1129 for (i = 0; i < num_groups; i++)
1130 INIT_LIST_HEAD(&cattr_groups[i].attr_list);
1132 /* Add Counter device sysfs attributes */
1133 err = counter_sysfs_attr_add(counter, cattr_groups);
1137 /* Allocate attribute group pointers for association with device */
1138 dev->groups = devm_kcalloc(dev, num_groups + 1, sizeof(*dev->groups),
1143 /* Allocate space for attribute groups */
1144 groups = devm_kcalloc(dev, num_groups, sizeof(*groups), GFP_KERNEL);
1148 /* Prepare each group of attributes for association */
1149 for (i = 0; i < num_groups; i++) {
1150 groups[i].name = cattr_groups[i].name;
1152 /* Allocate space for attribute pointers */
1153 groups[i].attrs = devm_kcalloc(dev,
1154 cattr_groups[i].num_attr + 1,
1155 sizeof(*groups[i].attrs),
1157 if (!groups[i].attrs)
1160 /* Add attribute pointers to attribute group */
1162 list_for_each_entry(p, &cattr_groups[i].attr_list, l)
1163 groups[i].attrs[j++] = &p->dev_attr.attr;
1165 /* Associate attribute group */
1166 dev->groups[i] = &groups[i];