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",
92 [COUNTER_COUNT_MODE_INTERRUPT_ON_TERMINAL_COUNT] = "interrupt on terminal count",
93 [COUNTER_COUNT_MODE_HARDWARE_RETRIGGERABLE_ONESHOT] = "hardware retriggerable one-shot",
94 [COUNTER_COUNT_MODE_RATE_GENERATOR] = "rate generator",
95 [COUNTER_COUNT_MODE_SQUARE_WAVE_MODE] = "square wave mode",
96 [COUNTER_COUNT_MODE_SOFTWARE_TRIGGERED_STROBE] = "software triggered strobe",
97 [COUNTER_COUNT_MODE_HARDWARE_TRIGGERED_STROBE] = "hardware triggered strobe",
100 static const char *const counter_signal_polarity_str[] = {
101 [COUNTER_SIGNAL_POLARITY_POSITIVE] = "positive",
102 [COUNTER_SIGNAL_POLARITY_NEGATIVE] = "negative"
105 static ssize_t counter_comp_u8_show(struct device *dev,
106 struct device_attribute *attr, char *buf)
108 const struct counter_attribute *const a = to_counter_attribute(attr);
109 struct counter_device *const counter = counter_from_dev(dev);
114 case COUNTER_SCOPE_DEVICE:
115 err = a->comp.device_u8_read(counter, &data);
117 case COUNTER_SCOPE_SIGNAL:
118 err = a->comp.signal_u8_read(counter, a->parent, &data);
120 case COUNTER_SCOPE_COUNT:
121 err = a->comp.count_u8_read(counter, a->parent, &data);
129 if (a->comp.type == COUNTER_COMP_BOOL)
130 /* data should already be boolean but ensure just to be safe */
133 return sysfs_emit(buf, "%u\n", (unsigned int)data);
136 static ssize_t counter_comp_u8_store(struct device *dev,
137 struct device_attribute *attr,
138 const char *buf, size_t len)
140 const struct counter_attribute *const a = to_counter_attribute(attr);
141 struct counter_device *const counter = counter_from_dev(dev);
146 if (a->comp.type == COUNTER_COMP_BOOL) {
147 err = kstrtobool(buf, &bool_data);
150 err = kstrtou8(buf, 0, &data);
155 case COUNTER_SCOPE_DEVICE:
156 err = a->comp.device_u8_write(counter, data);
158 case COUNTER_SCOPE_SIGNAL:
159 err = a->comp.signal_u8_write(counter, a->parent, data);
161 case COUNTER_SCOPE_COUNT:
162 err = a->comp.count_u8_write(counter, a->parent, data);
173 static ssize_t counter_comp_u32_show(struct device *dev,
174 struct device_attribute *attr, char *buf)
176 const struct counter_attribute *const a = to_counter_attribute(attr);
177 struct counter_device *const counter = counter_from_dev(dev);
178 const struct counter_available *const avail = a->comp.priv;
183 case COUNTER_SCOPE_DEVICE:
184 err = a->comp.device_u32_read(counter, &data);
186 case COUNTER_SCOPE_SIGNAL:
187 err = a->comp.signal_u32_read(counter, a->parent, &data);
189 case COUNTER_SCOPE_COUNT:
190 if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION)
191 err = a->comp.action_read(counter, a->parent,
192 a->comp.priv, &data);
194 err = a->comp.count_u32_read(counter, a->parent, &data);
202 switch (a->comp.type) {
203 case COUNTER_COMP_FUNCTION:
204 return sysfs_emit(buf, "%s\n", counter_function_str[data]);
205 case COUNTER_COMP_SIGNAL_LEVEL:
206 return sysfs_emit(buf, "%s\n", counter_signal_value_str[data]);
207 case COUNTER_COMP_SYNAPSE_ACTION:
208 return sysfs_emit(buf, "%s\n", counter_synapse_action_str[data]);
209 case COUNTER_COMP_ENUM:
210 return sysfs_emit(buf, "%s\n", avail->strs[data]);
211 case COUNTER_COMP_COUNT_DIRECTION:
212 return sysfs_emit(buf, "%s\n", counter_count_direction_str[data]);
213 case COUNTER_COMP_COUNT_MODE:
214 return sysfs_emit(buf, "%s\n", counter_count_mode_str[data]);
215 case COUNTER_COMP_SIGNAL_POLARITY:
216 return sysfs_emit(buf, "%s\n", counter_signal_polarity_str[data]);
218 return sysfs_emit(buf, "%u\n", (unsigned int)data);
222 static int counter_find_enum(u32 *const enum_item, const u32 *const enums,
223 const size_t num_enums, const char *const buf,
224 const char *const string_array[])
228 for (index = 0; index < num_enums; index++) {
229 *enum_item = enums[index];
230 if (sysfs_streq(buf, string_array[*enum_item]))
237 static ssize_t counter_comp_u32_store(struct device *dev,
238 struct device_attribute *attr,
239 const char *buf, size_t len)
241 const struct counter_attribute *const a = to_counter_attribute(attr);
242 struct counter_device *const counter = counter_from_dev(dev);
243 struct counter_count *const count = a->parent;
244 struct counter_synapse *const synapse = a->comp.priv;
245 const struct counter_available *const avail = a->comp.priv;
249 switch (a->comp.type) {
250 case COUNTER_COMP_FUNCTION:
251 err = counter_find_enum(&data, count->functions_list,
252 count->num_functions, buf,
253 counter_function_str);
255 case COUNTER_COMP_SYNAPSE_ACTION:
256 err = counter_find_enum(&data, synapse->actions_list,
257 synapse->num_actions, buf,
258 counter_synapse_action_str);
260 case COUNTER_COMP_ENUM:
261 err = __sysfs_match_string(avail->strs, avail->num_items, buf);
264 case COUNTER_COMP_COUNT_MODE:
265 err = counter_find_enum(&data, avail->enums, avail->num_items,
266 buf, counter_count_mode_str);
268 case COUNTER_COMP_SIGNAL_POLARITY:
269 err = counter_find_enum(&data, avail->enums, avail->num_items,
270 buf, counter_signal_polarity_str);
273 err = kstrtou32(buf, 0, &data);
280 case COUNTER_SCOPE_DEVICE:
281 err = a->comp.device_u32_write(counter, data);
283 case COUNTER_SCOPE_SIGNAL:
284 err = a->comp.signal_u32_write(counter, a->parent, data);
286 case COUNTER_SCOPE_COUNT:
287 if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION)
288 err = a->comp.action_write(counter, count, synapse,
291 err = a->comp.count_u32_write(counter, count, data);
302 static ssize_t counter_comp_u64_show(struct device *dev,
303 struct device_attribute *attr, char *buf)
305 const struct counter_attribute *const a = to_counter_attribute(attr);
306 struct counter_device *const counter = counter_from_dev(dev);
311 case COUNTER_SCOPE_DEVICE:
312 err = a->comp.device_u64_read(counter, &data);
314 case COUNTER_SCOPE_SIGNAL:
315 err = a->comp.signal_u64_read(counter, a->parent, &data);
317 case COUNTER_SCOPE_COUNT:
318 err = a->comp.count_u64_read(counter, a->parent, &data);
326 return sysfs_emit(buf, "%llu\n", (unsigned long long)data);
329 static ssize_t counter_comp_u64_store(struct device *dev,
330 struct device_attribute *attr,
331 const char *buf, size_t len)
333 const struct counter_attribute *const a = to_counter_attribute(attr);
334 struct counter_device *const counter = counter_from_dev(dev);
338 err = kstrtou64(buf, 0, &data);
343 case COUNTER_SCOPE_DEVICE:
344 err = a->comp.device_u64_write(counter, data);
346 case COUNTER_SCOPE_SIGNAL:
347 err = a->comp.signal_u64_write(counter, a->parent, data);
349 case COUNTER_SCOPE_COUNT:
350 err = a->comp.count_u64_write(counter, a->parent, data);
361 static ssize_t counter_comp_array_u32_show(struct device *dev,
362 struct device_attribute *attr,
365 const struct counter_attribute *const a = to_counter_attribute(attr);
366 struct counter_device *const counter = counter_from_dev(dev);
367 const struct counter_array *const element = a->comp.priv;
371 if (a->scope != COUNTER_SCOPE_SIGNAL ||
372 element->type != COUNTER_COMP_SIGNAL_POLARITY)
375 err = a->comp.signal_array_u32_read(counter, a->parent, element->idx,
380 return sysfs_emit(buf, "%s\n", counter_signal_polarity_str[data]);
383 static ssize_t counter_comp_array_u32_store(struct device *dev,
384 struct device_attribute *attr,
385 const char *buf, size_t len)
387 const struct counter_attribute *const a = to_counter_attribute(attr);
388 struct counter_device *const counter = counter_from_dev(dev);
389 const struct counter_array *const element = a->comp.priv;
393 if (element->type != COUNTER_COMP_SIGNAL_POLARITY ||
394 a->scope != COUNTER_SCOPE_SIGNAL)
397 err = counter_find_enum(&data, element->avail->enums,
398 element->avail->num_items, buf,
399 counter_signal_polarity_str);
403 err = a->comp.signal_array_u32_write(counter, a->parent, element->idx,
411 static ssize_t counter_comp_array_u64_show(struct device *dev,
412 struct device_attribute *attr,
415 const struct counter_attribute *const a = to_counter_attribute(attr);
416 struct counter_device *const counter = counter_from_dev(dev);
417 const struct counter_array *const element = a->comp.priv;
422 case COUNTER_SCOPE_DEVICE:
423 err = a->comp.device_array_u64_read(counter, element->idx,
426 case COUNTER_SCOPE_SIGNAL:
427 err = a->comp.signal_array_u64_read(counter, a->parent,
428 element->idx, &data);
430 case COUNTER_SCOPE_COUNT:
431 err = a->comp.count_array_u64_read(counter, a->parent,
432 element->idx, &data);
440 return sysfs_emit(buf, "%llu\n", (unsigned long long)data);
443 static ssize_t counter_comp_array_u64_store(struct device *dev,
444 struct device_attribute *attr,
445 const char *buf, size_t len)
447 const struct counter_attribute *const a = to_counter_attribute(attr);
448 struct counter_device *const counter = counter_from_dev(dev);
449 const struct counter_array *const element = a->comp.priv;
453 err = kstrtou64(buf, 0, &data);
458 case COUNTER_SCOPE_DEVICE:
459 err = a->comp.device_array_u64_write(counter, element->idx,
462 case COUNTER_SCOPE_SIGNAL:
463 err = a->comp.signal_array_u64_write(counter, a->parent,
466 case COUNTER_SCOPE_COUNT:
467 err = a->comp.count_array_u64_write(counter, a->parent,
479 static ssize_t enums_available_show(const u32 *const enums,
480 const size_t num_enums,
481 const char *const strs[], char *buf)
486 for (index = 0; index < num_enums; index++)
487 len += sysfs_emit_at(buf, len, "%s\n", strs[enums[index]]);
492 static ssize_t strs_available_show(const struct counter_available *const avail,
498 for (index = 0; index < avail->num_items; index++)
499 len += sysfs_emit_at(buf, len, "%s\n", avail->strs[index]);
504 static ssize_t counter_comp_available_show(struct device *dev,
505 struct device_attribute *attr,
508 const struct counter_attribute *const a = to_counter_attribute(attr);
509 const struct counter_count *const count = a->parent;
510 const struct counter_synapse *const synapse = a->comp.priv;
511 const struct counter_available *const avail = a->comp.priv;
513 switch (a->comp.type) {
514 case COUNTER_COMP_FUNCTION:
515 return enums_available_show(count->functions_list,
516 count->num_functions,
517 counter_function_str, buf);
518 case COUNTER_COMP_SYNAPSE_ACTION:
519 return enums_available_show(synapse->actions_list,
520 synapse->num_actions,
521 counter_synapse_action_str, buf);
522 case COUNTER_COMP_ENUM:
523 return strs_available_show(avail, buf);
524 case COUNTER_COMP_COUNT_MODE:
525 return enums_available_show(avail->enums, avail->num_items,
526 counter_count_mode_str, buf);
532 static int counter_avail_attr_create(struct device *const dev,
533 struct counter_attribute_group *const group,
534 const struct counter_comp *const comp, void *const parent)
536 struct counter_attribute *counter_attr;
537 struct device_attribute *dev_attr;
539 counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
543 /* Configure Counter attribute */
544 counter_attr->comp.type = comp->type;
545 counter_attr->comp.priv = comp->priv;
546 counter_attr->parent = parent;
548 /* Initialize sysfs attribute */
549 dev_attr = &counter_attr->dev_attr;
550 sysfs_attr_init(&dev_attr->attr);
552 /* Configure device attribute */
553 dev_attr->attr.name = devm_kasprintf(dev, GFP_KERNEL, "%s_available",
555 if (!dev_attr->attr.name)
557 dev_attr->attr.mode = 0444;
558 dev_attr->show = counter_comp_available_show;
560 /* Store list node */
561 list_add(&counter_attr->l, &group->attr_list);
567 static int counter_attr_create(struct device *const dev,
568 struct counter_attribute_group *const group,
569 const struct counter_comp *const comp,
570 const enum counter_scope scope,
573 const struct counter_array *const array = comp->priv;
574 struct counter_attribute *counter_attr;
575 struct device_attribute *dev_attr;
577 counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
581 /* Configure Counter attribute */
582 counter_attr->comp = *comp;
583 counter_attr->scope = scope;
584 counter_attr->parent = parent;
586 /* Configure device attribute */
587 dev_attr = &counter_attr->dev_attr;
588 sysfs_attr_init(&dev_attr->attr);
589 dev_attr->attr.name = comp->name;
590 switch (comp->type) {
591 case COUNTER_COMP_U8:
592 case COUNTER_COMP_BOOL:
593 if (comp->device_u8_read) {
594 dev_attr->attr.mode |= 0444;
595 dev_attr->show = counter_comp_u8_show;
597 if (comp->device_u8_write) {
598 dev_attr->attr.mode |= 0200;
599 dev_attr->store = counter_comp_u8_store;
602 case COUNTER_COMP_SIGNAL_LEVEL:
603 case COUNTER_COMP_FUNCTION:
604 case COUNTER_COMP_SYNAPSE_ACTION:
605 case COUNTER_COMP_ENUM:
606 case COUNTER_COMP_COUNT_DIRECTION:
607 case COUNTER_COMP_COUNT_MODE:
608 case COUNTER_COMP_SIGNAL_POLARITY:
609 if (comp->device_u32_read) {
610 dev_attr->attr.mode |= 0444;
611 dev_attr->show = counter_comp_u32_show;
613 if (comp->device_u32_write) {
614 dev_attr->attr.mode |= 0200;
615 dev_attr->store = counter_comp_u32_store;
618 case COUNTER_COMP_U64:
619 if (comp->device_u64_read) {
620 dev_attr->attr.mode |= 0444;
621 dev_attr->show = counter_comp_u64_show;
623 if (comp->device_u64_write) {
624 dev_attr->attr.mode |= 0200;
625 dev_attr->store = counter_comp_u64_store;
628 case COUNTER_COMP_ARRAY:
629 switch (array->type) {
630 case COUNTER_COMP_SIGNAL_POLARITY:
631 if (comp->signal_array_u32_read) {
632 dev_attr->attr.mode |= 0444;
633 dev_attr->show = counter_comp_array_u32_show;
635 if (comp->signal_array_u32_write) {
636 dev_attr->attr.mode |= 0200;
637 dev_attr->store = counter_comp_array_u32_store;
640 case COUNTER_COMP_U64:
641 if (comp->device_array_u64_read) {
642 dev_attr->attr.mode |= 0444;
643 dev_attr->show = counter_comp_array_u64_show;
645 if (comp->device_array_u64_write) {
646 dev_attr->attr.mode |= 0200;
647 dev_attr->store = counter_comp_array_u64_store;
658 /* Store list node */
659 list_add(&counter_attr->l, &group->attr_list);
662 /* Create "*_available" attribute if needed */
663 switch (comp->type) {
664 case COUNTER_COMP_FUNCTION:
665 case COUNTER_COMP_SYNAPSE_ACTION:
666 case COUNTER_COMP_ENUM:
667 case COUNTER_COMP_COUNT_MODE:
668 return counter_avail_attr_create(dev, group, comp, parent);
674 static ssize_t counter_comp_name_show(struct device *dev,
675 struct device_attribute *attr, char *buf)
677 return sysfs_emit(buf, "%s\n", to_counter_attribute(attr)->comp.name);
680 static int counter_name_attr_create(struct device *const dev,
681 struct counter_attribute_group *const group,
682 const char *const name)
684 struct counter_attribute *counter_attr;
686 counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
690 /* Configure Counter attribute */
691 counter_attr->comp.name = name;
693 /* Configure device attribute */
694 sysfs_attr_init(&counter_attr->dev_attr.attr);
695 counter_attr->dev_attr.attr.name = "name";
696 counter_attr->dev_attr.attr.mode = 0444;
697 counter_attr->dev_attr.show = counter_comp_name_show;
699 /* Store list node */
700 list_add(&counter_attr->l, &group->attr_list);
706 static ssize_t counter_comp_id_show(struct device *dev,
707 struct device_attribute *attr, char *buf)
709 const size_t id = (size_t)to_counter_attribute(attr)->comp.priv;
711 return sysfs_emit(buf, "%zu\n", id);
714 static int counter_comp_id_attr_create(struct device *const dev,
715 struct counter_attribute_group *const group,
716 const char *name, const size_t id)
718 struct counter_attribute *counter_attr;
720 /* Allocate Counter attribute */
721 counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
725 /* Generate component ID name */
726 name = devm_kasprintf(dev, GFP_KERNEL, "%s_component_id", name);
730 /* Configure Counter attribute */
731 counter_attr->comp.priv = (void *)id;
733 /* Configure device attribute */
734 sysfs_attr_init(&counter_attr->dev_attr.attr);
735 counter_attr->dev_attr.attr.name = name;
736 counter_attr->dev_attr.attr.mode = 0444;
737 counter_attr->dev_attr.show = counter_comp_id_show;
739 /* Store list node */
740 list_add(&counter_attr->l, &group->attr_list);
746 static int counter_ext_attrs_create(struct device *const dev,
747 struct counter_attribute_group *const group,
748 const struct counter_comp *const ext,
749 const enum counter_scope scope,
750 void *const parent, const size_t id)
754 /* Create main extension attribute */
755 err = counter_attr_create(dev, group, ext, scope, parent);
759 /* Create extension id attribute */
760 return counter_comp_id_attr_create(dev, group, ext->name, id);
763 static int counter_array_attrs_create(struct device *const dev,
764 struct counter_attribute_group *const group,
765 const struct counter_comp *const comp,
766 const enum counter_scope scope,
767 void *const parent, const size_t id)
769 const struct counter_array *const array = comp->priv;
770 struct counter_comp ext = *comp;
771 struct counter_array *element;
775 /* Create an attribute for each array element */
776 for (idx = 0; idx < array->length; idx++) {
777 /* Generate array element attribute name */
778 ext.name = devm_kasprintf(dev, GFP_KERNEL, "%s%zu", comp->name,
783 /* Allocate and configure array element */
784 element = devm_kzalloc(dev, sizeof(*element), GFP_KERNEL);
787 element->type = array->type;
788 element->avail = array->avail;
792 /* Create all attributes associated with the array element */
793 err = counter_ext_attrs_create(dev, group, &ext, scope, parent,
802 static int counter_sysfs_exts_add(struct device *const dev,
803 struct counter_attribute_group *const group,
804 const struct counter_comp *const exts,
805 const size_t num_ext,
806 const enum counter_scope scope,
810 const struct counter_comp *ext;
813 const struct counter_array *array;
815 /* Create attributes for each extension */
816 for (i = 0; i < num_ext; i++) {
818 if (ext->type == COUNTER_COMP_ARRAY) {
819 err = counter_array_attrs_create(dev, group, ext, scope,
824 err = counter_ext_attrs_create(dev, group, ext, scope,
835 static struct counter_comp counter_signal_comp = {
836 .type = COUNTER_COMP_SIGNAL_LEVEL,
840 static int counter_signal_attrs_create(struct counter_device *const counter,
841 struct counter_attribute_group *const cattr_group,
842 struct counter_signal *const signal)
844 const enum counter_scope scope = COUNTER_SCOPE_SIGNAL;
845 struct device *const dev = &counter->dev;
847 struct counter_comp comp;
849 /* Create main Signal attribute */
850 comp = counter_signal_comp;
851 comp.signal_u32_read = counter->ops->signal_read;
852 err = counter_attr_create(dev, cattr_group, &comp, scope, signal);
856 /* Create Signal name attribute */
857 err = counter_name_attr_create(dev, cattr_group, signal->name);
861 /* Add Signal extensions */
862 return counter_sysfs_exts_add(dev, cattr_group, signal->ext,
863 signal->num_ext, scope, signal);
866 static int counter_sysfs_signals_add(struct counter_device *const counter,
867 struct counter_attribute_group *const groups)
872 /* Add each Signal */
873 for (i = 0; i < counter->num_signals; i++) {
874 /* Generate Signal attribute directory name */
875 groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL,
880 /* Create all attributes associated with Signal */
881 err = counter_signal_attrs_create(counter, groups + i,
882 counter->signals + i);
890 static int counter_sysfs_synapses_add(struct counter_device *const counter,
891 struct counter_attribute_group *const group,
892 struct counter_count *const count)
896 /* Add each Synapse */
897 for (i = 0; i < count->num_synapses; i++) {
898 struct device *const dev = &counter->dev;
899 struct counter_synapse *synapse;
901 struct counter_comp comp;
904 synapse = count->synapses + i;
906 /* Generate Synapse action name */
907 id = synapse->signal - counter->signals;
908 comp.name = devm_kasprintf(dev, GFP_KERNEL, "signal%zu_action",
913 /* Create action attribute */
914 comp.type = COUNTER_COMP_SYNAPSE_ACTION;
915 comp.action_read = counter->ops->action_read;
916 comp.action_write = counter->ops->action_write;
918 err = counter_attr_create(dev, group, &comp,
919 COUNTER_SCOPE_COUNT, count);
923 /* Create Synapse component ID attribute */
924 err = counter_comp_id_attr_create(dev, group, comp.name, i);
932 static struct counter_comp counter_count_comp =
933 COUNTER_COMP_COUNT_U64("count", NULL, NULL);
935 static struct counter_comp counter_function_comp = {
936 .type = COUNTER_COMP_FUNCTION,
940 static int counter_count_attrs_create(struct counter_device *const counter,
941 struct counter_attribute_group *const cattr_group,
942 struct counter_count *const count)
944 const enum counter_scope scope = COUNTER_SCOPE_COUNT;
945 struct device *const dev = &counter->dev;
947 struct counter_comp comp;
949 /* Create main Count attribute */
950 comp = counter_count_comp;
951 comp.count_u64_read = counter->ops->count_read;
952 comp.count_u64_write = counter->ops->count_write;
953 err = counter_attr_create(dev, cattr_group, &comp, scope, count);
957 /* Create Count name attribute */
958 err = counter_name_attr_create(dev, cattr_group, count->name);
962 /* Create Count function attribute */
963 comp = counter_function_comp;
964 comp.count_u32_read = counter->ops->function_read;
965 comp.count_u32_write = counter->ops->function_write;
966 err = counter_attr_create(dev, cattr_group, &comp, scope, count);
970 /* Add Count extensions */
971 return counter_sysfs_exts_add(dev, cattr_group, count->ext,
972 count->num_ext, scope, count);
975 static int counter_sysfs_counts_add(struct counter_device *const counter,
976 struct counter_attribute_group *const groups)
979 struct counter_count *count;
983 for (i = 0; i < counter->num_counts; i++) {
984 count = counter->counts + i;
986 /* Generate Count attribute directory name */
987 groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL,
992 /* Add sysfs attributes of the Synapses */
993 err = counter_sysfs_synapses_add(counter, groups + i, count);
997 /* Create all attributes associated with Count */
998 err = counter_count_attrs_create(counter, groups + i, count);
1006 static int counter_num_signals_read(struct counter_device *counter, u8 *val)
1008 *val = counter->num_signals;
1012 static int counter_num_counts_read(struct counter_device *counter, u8 *val)
1014 *val = counter->num_counts;
1018 static int counter_events_queue_size_read(struct counter_device *counter,
1021 *val = kfifo_size(&counter->events);
1025 static int counter_events_queue_size_write(struct counter_device *counter,
1028 DECLARE_KFIFO_PTR(events, struct counter_event);
1030 unsigned long flags;
1032 /* Allocate new events queue */
1033 err = kfifo_alloc(&events, val, GFP_KERNEL);
1037 /* Swap in new events queue */
1038 mutex_lock(&counter->events_out_lock);
1039 spin_lock_irqsave(&counter->events_in_lock, flags);
1040 kfifo_free(&counter->events);
1041 counter->events.kfifo = events.kfifo;
1042 spin_unlock_irqrestore(&counter->events_in_lock, flags);
1043 mutex_unlock(&counter->events_out_lock);
1048 static struct counter_comp counter_num_signals_comp =
1049 COUNTER_COMP_DEVICE_U8("num_signals", counter_num_signals_read, NULL);
1051 static struct counter_comp counter_num_counts_comp =
1052 COUNTER_COMP_DEVICE_U8("num_counts", counter_num_counts_read, NULL);
1054 static struct counter_comp counter_events_queue_size_comp =
1055 COUNTER_COMP_DEVICE_U64("events_queue_size",
1056 counter_events_queue_size_read,
1057 counter_events_queue_size_write);
1059 static int counter_sysfs_attr_add(struct counter_device *const counter,
1060 struct counter_attribute_group *cattr_group)
1062 const enum counter_scope scope = COUNTER_SCOPE_DEVICE;
1063 struct device *const dev = &counter->dev;
1066 /* Add Signals sysfs attributes */
1067 err = counter_sysfs_signals_add(counter, cattr_group);
1070 cattr_group += counter->num_signals;
1072 /* Add Counts sysfs attributes */
1073 err = counter_sysfs_counts_add(counter, cattr_group);
1076 cattr_group += counter->num_counts;
1078 /* Create name attribute */
1079 err = counter_name_attr_create(dev, cattr_group, counter->name);
1083 /* Create num_signals attribute */
1084 err = counter_attr_create(dev, cattr_group, &counter_num_signals_comp,
1089 /* Create num_counts attribute */
1090 err = counter_attr_create(dev, cattr_group, &counter_num_counts_comp,
1095 /* Create events_queue_size attribute */
1096 err = counter_attr_create(dev, cattr_group,
1097 &counter_events_queue_size_comp, scope, NULL);
1101 /* Add device extensions */
1102 return counter_sysfs_exts_add(dev, cattr_group, counter->ext,
1103 counter->num_ext, scope, NULL);
1109 * counter_sysfs_add - Adds Counter sysfs attributes to the device structure
1110 * @counter: Pointer to the Counter device structure
1112 * Counter sysfs attributes are created and added to the respective device
1113 * structure for later registration to the system. Resource-managed memory
1114 * allocation is performed by this function, and this memory should be freed
1115 * when no longer needed (automatically by a device_unregister call, or
1116 * manually by a devres_release_all call).
1118 int counter_sysfs_add(struct counter_device *const counter)
1120 struct device *const dev = &counter->dev;
1121 const size_t num_groups = counter->num_signals + counter->num_counts + 1;
1122 struct counter_attribute_group *cattr_groups;
1125 struct attribute_group *groups;
1126 struct counter_attribute *p;
1128 /* Allocate space for attribute groups (signals, counts, and ext) */
1129 cattr_groups = devm_kcalloc(dev, num_groups, sizeof(*cattr_groups),
1134 /* Initialize attribute lists */
1135 for (i = 0; i < num_groups; i++)
1136 INIT_LIST_HEAD(&cattr_groups[i].attr_list);
1138 /* Add Counter device sysfs attributes */
1139 err = counter_sysfs_attr_add(counter, cattr_groups);
1143 /* Allocate attribute group pointers for association with device */
1144 dev->groups = devm_kcalloc(dev, num_groups + 1, sizeof(*dev->groups),
1149 /* Allocate space for attribute groups */
1150 groups = devm_kcalloc(dev, num_groups, sizeof(*groups), GFP_KERNEL);
1154 /* Prepare each group of attributes for association */
1155 for (i = 0; i < num_groups; i++) {
1156 groups[i].name = cattr_groups[i].name;
1158 /* Allocate space for attribute pointers */
1159 groups[i].attrs = devm_kcalloc(dev,
1160 cattr_groups[i].num_attr + 1,
1161 sizeof(*groups[i].attrs),
1163 if (!groups[i].attrs)
1166 /* Add attribute pointers to attribute group */
1168 list_for_each_entry(p, &cattr_groups[i].attr_list, l)
1169 groups[i].attrs[j++] = &p->dev_attr.attr;
1171 /* Associate attribute group */
1172 dev->groups[i] = &groups[i];