• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Generic Counter sysfs interface
4  * Copyright (C) 2020 William Breathitt Gray
5  */
6 #include <linux/counter.h>
7 #include <linux/device.h>
8 #include <linux/err.h>
9 #include <linux/gfp.h>
10 #include <linux/kernel.h>
11 #include <linux/kstrtox.h>
12 #include <linux/list.h>
13 #include <linux/string.h>
14 #include <linux/sysfs.h>
15 #include <linux/types.h>
16 
17 #include "counter-sysfs.h"
18 
19 /**
20  * struct counter_attribute - Counter sysfs attribute
21  * @dev_attr:	device attribute for sysfs
22  * @l:		node to add Counter attribute to attribute group list
23  * @comp:	Counter component callbacks and data
24  * @scope:	Counter scope of the attribute
25  * @parent:	pointer to the parent component
26  */
27 struct counter_attribute {
28 	struct device_attribute dev_attr;
29 	struct list_head l;
30 
31 	struct counter_comp comp;
32 	enum counter_scope scope;
33 	void *parent;
34 };
35 
36 #define to_counter_attribute(_dev_attr) \
37 	container_of(_dev_attr, struct counter_attribute, dev_attr)
38 
39 /**
40  * struct counter_attribute_group - container for attribute group
41  * @name:	name of the attribute group
42  * @attr_list:	list to keep track of created attributes
43  * @num_attr:	number of attributes
44  */
45 struct counter_attribute_group {
46 	const char *name;
47 	struct list_head attr_list;
48 	size_t num_attr;
49 };
50 
51 static const char *const counter_function_str[] = {
52 	[COUNTER_FUNCTION_INCREASE] = "increase",
53 	[COUNTER_FUNCTION_DECREASE] = "decrease",
54 	[COUNTER_FUNCTION_PULSE_DIRECTION] = "pulse-direction",
55 	[COUNTER_FUNCTION_QUADRATURE_X1_A] = "quadrature x1 a",
56 	[COUNTER_FUNCTION_QUADRATURE_X1_B] = "quadrature x1 b",
57 	[COUNTER_FUNCTION_QUADRATURE_X2_A] = "quadrature x2 a",
58 	[COUNTER_FUNCTION_QUADRATURE_X2_B] = "quadrature x2 b",
59 	[COUNTER_FUNCTION_QUADRATURE_X4] = "quadrature x4"
60 };
61 
62 static const char *const counter_signal_value_str[] = {
63 	[COUNTER_SIGNAL_LEVEL_LOW] = "low",
64 	[COUNTER_SIGNAL_LEVEL_HIGH] = "high"
65 };
66 
67 static const char *const counter_synapse_action_str[] = {
68 	[COUNTER_SYNAPSE_ACTION_NONE] = "none",
69 	[COUNTER_SYNAPSE_ACTION_RISING_EDGE] = "rising edge",
70 	[COUNTER_SYNAPSE_ACTION_FALLING_EDGE] = "falling edge",
71 	[COUNTER_SYNAPSE_ACTION_BOTH_EDGES] = "both edges"
72 };
73 
74 static const char *const counter_count_direction_str[] = {
75 	[COUNTER_COUNT_DIRECTION_FORWARD] = "forward",
76 	[COUNTER_COUNT_DIRECTION_BACKWARD] = "backward"
77 };
78 
79 static const char *const counter_count_mode_str[] = {
80 	[COUNTER_COUNT_MODE_NORMAL] = "normal",
81 	[COUNTER_COUNT_MODE_RANGE_LIMIT] = "range limit",
82 	[COUNTER_COUNT_MODE_NON_RECYCLE] = "non-recycle",
83 	[COUNTER_COUNT_MODE_MODULO_N] = "modulo-n"
84 };
85 
counter_comp_u8_show(struct device * dev,struct device_attribute * attr,char * buf)86 static ssize_t counter_comp_u8_show(struct device *dev,
87 				    struct device_attribute *attr, char *buf)
88 {
89 	const struct counter_attribute *const a = to_counter_attribute(attr);
90 	struct counter_device *const counter = dev_get_drvdata(dev);
91 	int err;
92 	u8 data = 0;
93 
94 	switch (a->scope) {
95 	case COUNTER_SCOPE_DEVICE:
96 		err = a->comp.device_u8_read(counter, &data);
97 		break;
98 	case COUNTER_SCOPE_SIGNAL:
99 		err = a->comp.signal_u8_read(counter, a->parent, &data);
100 		break;
101 	case COUNTER_SCOPE_COUNT:
102 		err = a->comp.count_u8_read(counter, a->parent, &data);
103 		break;
104 	default:
105 		return -EINVAL;
106 	}
107 	if (err < 0)
108 		return err;
109 
110 	if (a->comp.type == COUNTER_COMP_BOOL)
111 		/* data should already be boolean but ensure just to be safe */
112 		data = !!data;
113 
114 	return sprintf(buf, "%u\n", (unsigned int)data);
115 }
116 
counter_comp_u8_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)117 static ssize_t counter_comp_u8_store(struct device *dev,
118 				     struct device_attribute *attr,
119 				     const char *buf, size_t len)
120 {
121 	const struct counter_attribute *const a = to_counter_attribute(attr);
122 	struct counter_device *const counter = dev_get_drvdata(dev);
123 	int err;
124 	bool bool_data = 0;
125 	u8 data = 0;
126 
127 	if (a->comp.type == COUNTER_COMP_BOOL) {
128 		err = kstrtobool(buf, &bool_data);
129 		data = bool_data;
130 	} else
131 		err = kstrtou8(buf, 0, &data);
132 	if (err < 0)
133 		return err;
134 
135 	switch (a->scope) {
136 	case COUNTER_SCOPE_DEVICE:
137 		err = a->comp.device_u8_write(counter, data);
138 		break;
139 	case COUNTER_SCOPE_SIGNAL:
140 		err = a->comp.signal_u8_write(counter, a->parent, data);
141 		break;
142 	case COUNTER_SCOPE_COUNT:
143 		err = a->comp.count_u8_write(counter, a->parent, data);
144 		break;
145 	default:
146 		return -EINVAL;
147 	}
148 	if (err < 0)
149 		return err;
150 
151 	return len;
152 }
153 
counter_comp_u32_show(struct device * dev,struct device_attribute * attr,char * buf)154 static ssize_t counter_comp_u32_show(struct device *dev,
155 				     struct device_attribute *attr, char *buf)
156 {
157 	const struct counter_attribute *const a = to_counter_attribute(attr);
158 	struct counter_device *const counter = dev_get_drvdata(dev);
159 	const struct counter_available *const avail = a->comp.priv;
160 	int err;
161 	u32 data = 0;
162 
163 	switch (a->scope) {
164 	case COUNTER_SCOPE_DEVICE:
165 		err = a->comp.device_u32_read(counter, &data);
166 		break;
167 	case COUNTER_SCOPE_SIGNAL:
168 		err = a->comp.signal_u32_read(counter, a->parent, &data);
169 		break;
170 	case COUNTER_SCOPE_COUNT:
171 		if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION)
172 			err = a->comp.action_read(counter, a->parent,
173 						  a->comp.priv, &data);
174 		else
175 			err = a->comp.count_u32_read(counter, a->parent, &data);
176 		break;
177 	default:
178 		return -EINVAL;
179 	}
180 	if (err < 0)
181 		return err;
182 
183 	switch (a->comp.type) {
184 	case COUNTER_COMP_FUNCTION:
185 		return sysfs_emit(buf, "%s\n", counter_function_str[data]);
186 	case COUNTER_COMP_SIGNAL_LEVEL:
187 		return sysfs_emit(buf, "%s\n", counter_signal_value_str[data]);
188 	case COUNTER_COMP_SYNAPSE_ACTION:
189 		return sysfs_emit(buf, "%s\n", counter_synapse_action_str[data]);
190 	case COUNTER_COMP_ENUM:
191 		return sysfs_emit(buf, "%s\n", avail->strs[data]);
192 	case COUNTER_COMP_COUNT_DIRECTION:
193 		return sysfs_emit(buf, "%s\n", counter_count_direction_str[data]);
194 	case COUNTER_COMP_COUNT_MODE:
195 		return sysfs_emit(buf, "%s\n", counter_count_mode_str[data]);
196 	default:
197 		return sprintf(buf, "%u\n", (unsigned int)data);
198 	}
199 }
200 
counter_find_enum(u32 * const enum_item,const u32 * const enums,const size_t num_enums,const char * const buf,const char * const string_array[])201 static int counter_find_enum(u32 *const enum_item, const u32 *const enums,
202 			     const size_t num_enums, const char *const buf,
203 			     const char *const string_array[])
204 {
205 	size_t index;
206 
207 	for (index = 0; index < num_enums; index++) {
208 		*enum_item = enums[index];
209 		if (sysfs_streq(buf, string_array[*enum_item]))
210 			return 0;
211 	}
212 
213 	return -EINVAL;
214 }
215 
counter_comp_u32_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)216 static ssize_t counter_comp_u32_store(struct device *dev,
217 				      struct device_attribute *attr,
218 				      const char *buf, size_t len)
219 {
220 	const struct counter_attribute *const a = to_counter_attribute(attr);
221 	struct counter_device *const counter = dev_get_drvdata(dev);
222 	struct counter_count *const count = a->parent;
223 	struct counter_synapse *const synapse = a->comp.priv;
224 	const struct counter_available *const avail = a->comp.priv;
225 	int err;
226 	u32 data = 0;
227 
228 	switch (a->comp.type) {
229 	case COUNTER_COMP_FUNCTION:
230 		err = counter_find_enum(&data, count->functions_list,
231 					count->num_functions, buf,
232 					counter_function_str);
233 		break;
234 	case COUNTER_COMP_SYNAPSE_ACTION:
235 		err = counter_find_enum(&data, synapse->actions_list,
236 					synapse->num_actions, buf,
237 					counter_synapse_action_str);
238 		break;
239 	case COUNTER_COMP_ENUM:
240 		err = __sysfs_match_string(avail->strs, avail->num_items, buf);
241 		data = err;
242 		break;
243 	case COUNTER_COMP_COUNT_MODE:
244 		err = counter_find_enum(&data, avail->enums, avail->num_items,
245 					buf, counter_count_mode_str);
246 		break;
247 	default:
248 		err = kstrtou32(buf, 0, &data);
249 		break;
250 	}
251 	if (err < 0)
252 		return err;
253 
254 	switch (a->scope) {
255 	case COUNTER_SCOPE_DEVICE:
256 		err = a->comp.device_u32_write(counter, data);
257 		break;
258 	case COUNTER_SCOPE_SIGNAL:
259 		err = a->comp.signal_u32_write(counter, a->parent, data);
260 		break;
261 	case COUNTER_SCOPE_COUNT:
262 		if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION)
263 			err = a->comp.action_write(counter, count, synapse,
264 						   data);
265 		else
266 			err = a->comp.count_u32_write(counter, count, data);
267 		break;
268 	default:
269 		return -EINVAL;
270 	}
271 	if (err < 0)
272 		return err;
273 
274 	return len;
275 }
276 
counter_comp_u64_show(struct device * dev,struct device_attribute * attr,char * buf)277 static ssize_t counter_comp_u64_show(struct device *dev,
278 				     struct device_attribute *attr, char *buf)
279 {
280 	const struct counter_attribute *const a = to_counter_attribute(attr);
281 	struct counter_device *const counter = dev_get_drvdata(dev);
282 	int err;
283 	u64 data = 0;
284 
285 	switch (a->scope) {
286 	case COUNTER_SCOPE_DEVICE:
287 		err = a->comp.device_u64_read(counter, &data);
288 		break;
289 	case COUNTER_SCOPE_SIGNAL:
290 		err = a->comp.signal_u64_read(counter, a->parent, &data);
291 		break;
292 	case COUNTER_SCOPE_COUNT:
293 		err = a->comp.count_u64_read(counter, a->parent, &data);
294 		break;
295 	default:
296 		return -EINVAL;
297 	}
298 	if (err < 0)
299 		return err;
300 
301 	return sprintf(buf, "%llu\n", (unsigned long long)data);
302 }
303 
counter_comp_u64_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)304 static ssize_t counter_comp_u64_store(struct device *dev,
305 				      struct device_attribute *attr,
306 				      const char *buf, size_t len)
307 {
308 	const struct counter_attribute *const a = to_counter_attribute(attr);
309 	struct counter_device *const counter = dev_get_drvdata(dev);
310 	int err;
311 	u64 data = 0;
312 
313 	err = kstrtou64(buf, 0, &data);
314 	if (err < 0)
315 		return err;
316 
317 	switch (a->scope) {
318 	case COUNTER_SCOPE_DEVICE:
319 		err = a->comp.device_u64_write(counter, data);
320 		break;
321 	case COUNTER_SCOPE_SIGNAL:
322 		err = a->comp.signal_u64_write(counter, a->parent, data);
323 		break;
324 	case COUNTER_SCOPE_COUNT:
325 		err = a->comp.count_u64_write(counter, a->parent, data);
326 		break;
327 	default:
328 		return -EINVAL;
329 	}
330 	if (err < 0)
331 		return err;
332 
333 	return len;
334 }
335 
enums_available_show(const u32 * const enums,const size_t num_enums,const char * const strs[],char * buf)336 static ssize_t enums_available_show(const u32 *const enums,
337 				    const size_t num_enums,
338 				    const char *const strs[], char *buf)
339 {
340 	size_t len = 0;
341 	size_t index;
342 
343 	for (index = 0; index < num_enums; index++)
344 		len += sysfs_emit_at(buf, len, "%s\n", strs[enums[index]]);
345 
346 	return len;
347 }
348 
strs_available_show(const struct counter_available * const avail,char * buf)349 static ssize_t strs_available_show(const struct counter_available *const avail,
350 				   char *buf)
351 {
352 	size_t len = 0;
353 	size_t index;
354 
355 	for (index = 0; index < avail->num_items; index++)
356 		len += sysfs_emit_at(buf, len, "%s\n", avail->strs[index]);
357 
358 	return len;
359 }
360 
counter_comp_available_show(struct device * dev,struct device_attribute * attr,char * buf)361 static ssize_t counter_comp_available_show(struct device *dev,
362 					   struct device_attribute *attr,
363 					   char *buf)
364 {
365 	const struct counter_attribute *const a = to_counter_attribute(attr);
366 	const struct counter_count *const count = a->parent;
367 	const struct counter_synapse *const synapse = a->comp.priv;
368 	const struct counter_available *const avail = a->comp.priv;
369 
370 	switch (a->comp.type) {
371 	case COUNTER_COMP_FUNCTION:
372 		return enums_available_show(count->functions_list,
373 					    count->num_functions,
374 					    counter_function_str, buf);
375 	case COUNTER_COMP_SYNAPSE_ACTION:
376 		return enums_available_show(synapse->actions_list,
377 					    synapse->num_actions,
378 					    counter_synapse_action_str, buf);
379 	case COUNTER_COMP_ENUM:
380 		return strs_available_show(avail, buf);
381 	case COUNTER_COMP_COUNT_MODE:
382 		return enums_available_show(avail->enums, avail->num_items,
383 					    counter_count_mode_str, buf);
384 	default:
385 		return -EINVAL;
386 	}
387 }
388 
counter_avail_attr_create(struct device * const dev,struct counter_attribute_group * const group,const struct counter_comp * const comp,void * const parent)389 static int counter_avail_attr_create(struct device *const dev,
390 	struct counter_attribute_group *const group,
391 	const struct counter_comp *const comp, void *const parent)
392 {
393 	struct counter_attribute *counter_attr;
394 	struct device_attribute *dev_attr;
395 
396 	counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
397 	if (!counter_attr)
398 		return -ENOMEM;
399 
400 	/* Configure Counter attribute */
401 	counter_attr->comp.type = comp->type;
402 	counter_attr->comp.priv = comp->priv;
403 	counter_attr->parent = parent;
404 
405 	/* Initialize sysfs attribute */
406 	dev_attr = &counter_attr->dev_attr;
407 	sysfs_attr_init(&dev_attr->attr);
408 
409 	/* Configure device attribute */
410 	dev_attr->attr.name = devm_kasprintf(dev, GFP_KERNEL, "%s_available",
411 					     comp->name);
412 	if (!dev_attr->attr.name)
413 		return -ENOMEM;
414 	dev_attr->attr.mode = 0444;
415 	dev_attr->show = counter_comp_available_show;
416 
417 	/* Store list node */
418 	list_add(&counter_attr->l, &group->attr_list);
419 	group->num_attr++;
420 
421 	return 0;
422 }
423 
counter_attr_create(struct device * const dev,struct counter_attribute_group * const group,const struct counter_comp * const comp,const enum counter_scope scope,void * const parent)424 static int counter_attr_create(struct device *const dev,
425 			       struct counter_attribute_group *const group,
426 			       const struct counter_comp *const comp,
427 			       const enum counter_scope scope,
428 			       void *const parent)
429 {
430 	struct counter_attribute *counter_attr;
431 	struct device_attribute *dev_attr;
432 
433 	counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
434 	if (!counter_attr)
435 		return -ENOMEM;
436 
437 	/* Configure Counter attribute */
438 	counter_attr->comp = *comp;
439 	counter_attr->scope = scope;
440 	counter_attr->parent = parent;
441 
442 	/* Configure device attribute */
443 	dev_attr = &counter_attr->dev_attr;
444 	sysfs_attr_init(&dev_attr->attr);
445 	dev_attr->attr.name = comp->name;
446 	switch (comp->type) {
447 	case COUNTER_COMP_U8:
448 	case COUNTER_COMP_BOOL:
449 		if (comp->device_u8_read) {
450 			dev_attr->attr.mode |= 0444;
451 			dev_attr->show = counter_comp_u8_show;
452 		}
453 		if (comp->device_u8_write) {
454 			dev_attr->attr.mode |= 0200;
455 			dev_attr->store = counter_comp_u8_store;
456 		}
457 		break;
458 	case COUNTER_COMP_SIGNAL_LEVEL:
459 	case COUNTER_COMP_FUNCTION:
460 	case COUNTER_COMP_SYNAPSE_ACTION:
461 	case COUNTER_COMP_ENUM:
462 	case COUNTER_COMP_COUNT_DIRECTION:
463 	case COUNTER_COMP_COUNT_MODE:
464 		if (comp->device_u32_read) {
465 			dev_attr->attr.mode |= 0444;
466 			dev_attr->show = counter_comp_u32_show;
467 		}
468 		if (comp->device_u32_write) {
469 			dev_attr->attr.mode |= 0200;
470 			dev_attr->store = counter_comp_u32_store;
471 		}
472 		break;
473 	case COUNTER_COMP_U64:
474 		if (comp->device_u64_read) {
475 			dev_attr->attr.mode |= 0444;
476 			dev_attr->show = counter_comp_u64_show;
477 		}
478 		if (comp->device_u64_write) {
479 			dev_attr->attr.mode |= 0200;
480 			dev_attr->store = counter_comp_u64_store;
481 		}
482 		break;
483 	default:
484 		return -EINVAL;
485 	}
486 
487 	/* Store list node */
488 	list_add(&counter_attr->l, &group->attr_list);
489 	group->num_attr++;
490 
491 	/* Create "*_available" attribute if needed */
492 	switch (comp->type) {
493 	case COUNTER_COMP_FUNCTION:
494 	case COUNTER_COMP_SYNAPSE_ACTION:
495 	case COUNTER_COMP_ENUM:
496 	case COUNTER_COMP_COUNT_MODE:
497 		return counter_avail_attr_create(dev, group, comp, parent);
498 	default:
499 		return 0;
500 	}
501 }
502 
counter_comp_name_show(struct device * dev,struct device_attribute * attr,char * buf)503 static ssize_t counter_comp_name_show(struct device *dev,
504 				      struct device_attribute *attr, char *buf)
505 {
506 	return sysfs_emit(buf, "%s\n", to_counter_attribute(attr)->comp.name);
507 }
508 
counter_name_attr_create(struct device * const dev,struct counter_attribute_group * const group,const char * const name)509 static int counter_name_attr_create(struct device *const dev,
510 				    struct counter_attribute_group *const group,
511 				    const char *const name)
512 {
513 	struct counter_attribute *counter_attr;
514 
515 	counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
516 	if (!counter_attr)
517 		return -ENOMEM;
518 
519 	/* Configure Counter attribute */
520 	counter_attr->comp.name = name;
521 
522 	/* Configure device attribute */
523 	sysfs_attr_init(&counter_attr->dev_attr.attr);
524 	counter_attr->dev_attr.attr.name = "name";
525 	counter_attr->dev_attr.attr.mode = 0444;
526 	counter_attr->dev_attr.show = counter_comp_name_show;
527 
528 	/* Store list node */
529 	list_add(&counter_attr->l, &group->attr_list);
530 	group->num_attr++;
531 
532 	return 0;
533 }
534 
535 static struct counter_comp counter_signal_comp = {
536 	.type = COUNTER_COMP_SIGNAL_LEVEL,
537 	.name = "signal",
538 };
539 
counter_signal_attrs_create(struct counter_device * const counter,struct counter_attribute_group * const cattr_group,struct counter_signal * const signal)540 static int counter_signal_attrs_create(struct counter_device *const counter,
541 	struct counter_attribute_group *const cattr_group,
542 	struct counter_signal *const signal)
543 {
544 	const enum counter_scope scope = COUNTER_SCOPE_SIGNAL;
545 	struct device *const dev = &counter->dev;
546 	int err;
547 	struct counter_comp comp;
548 	size_t i;
549 
550 	/* Create main Signal attribute */
551 	comp = counter_signal_comp;
552 	comp.signal_u32_read = counter->ops->signal_read;
553 	err = counter_attr_create(dev, cattr_group, &comp, scope, signal);
554 	if (err < 0)
555 		return err;
556 
557 	/* Create Signal name attribute */
558 	err = counter_name_attr_create(dev, cattr_group, signal->name);
559 	if (err < 0)
560 		return err;
561 
562 	/* Create an attribute for each extension */
563 	for (i = 0; i < signal->num_ext; i++) {
564 		err = counter_attr_create(dev, cattr_group, signal->ext + i,
565 					  scope, signal);
566 		if (err < 0)
567 			return err;
568 	}
569 
570 	return 0;
571 }
572 
counter_sysfs_signals_add(struct counter_device * const counter,struct counter_attribute_group * const groups)573 static int counter_sysfs_signals_add(struct counter_device *const counter,
574 	struct counter_attribute_group *const groups)
575 {
576 	size_t i;
577 	int err;
578 
579 	/* Add each Signal */
580 	for (i = 0; i < counter->num_signals; i++) {
581 		/* Generate Signal attribute directory name */
582 		groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL,
583 						"signal%zu", i);
584 		if (!groups[i].name)
585 			return -ENOMEM;
586 
587 		/* Create all attributes associated with Signal */
588 		err = counter_signal_attrs_create(counter, groups + i,
589 						  counter->signals + i);
590 		if (err < 0)
591 			return err;
592 	}
593 
594 	return 0;
595 }
596 
counter_sysfs_synapses_add(struct counter_device * const counter,struct counter_attribute_group * const group,struct counter_count * const count)597 static int counter_sysfs_synapses_add(struct counter_device *const counter,
598 	struct counter_attribute_group *const group,
599 	struct counter_count *const count)
600 {
601 	size_t i;
602 
603 	/* Add each Synapse */
604 	for (i = 0; i < count->num_synapses; i++) {
605 		struct device *const dev = &counter->dev;
606 		struct counter_synapse *synapse;
607 		size_t id;
608 		struct counter_comp comp;
609 		int err;
610 
611 		synapse = count->synapses + i;
612 
613 		/* Generate Synapse action name */
614 		id = synapse->signal - counter->signals;
615 		comp.name = devm_kasprintf(dev, GFP_KERNEL, "signal%zu_action",
616 					   id);
617 		if (!comp.name)
618 			return -ENOMEM;
619 
620 		/* Create action attribute */
621 		comp.type = COUNTER_COMP_SYNAPSE_ACTION;
622 		comp.action_read = counter->ops->action_read;
623 		comp.action_write = counter->ops->action_write;
624 		comp.priv = synapse;
625 		err = counter_attr_create(dev, group, &comp,
626 					  COUNTER_SCOPE_COUNT, count);
627 		if (err < 0)
628 			return err;
629 	}
630 
631 	return 0;
632 }
633 
634 static struct counter_comp counter_count_comp =
635 	COUNTER_COMP_COUNT_U64("count", NULL, NULL);
636 
637 static struct counter_comp counter_function_comp = {
638 	.type = COUNTER_COMP_FUNCTION,
639 	.name = "function",
640 };
641 
counter_count_attrs_create(struct counter_device * const counter,struct counter_attribute_group * const cattr_group,struct counter_count * const count)642 static int counter_count_attrs_create(struct counter_device *const counter,
643 	struct counter_attribute_group *const cattr_group,
644 	struct counter_count *const count)
645 {
646 	const enum counter_scope scope = COUNTER_SCOPE_COUNT;
647 	struct device *const dev = &counter->dev;
648 	int err;
649 	struct counter_comp comp;
650 	size_t i;
651 
652 	/* Create main Count attribute */
653 	comp = counter_count_comp;
654 	comp.count_u64_read = counter->ops->count_read;
655 	comp.count_u64_write = counter->ops->count_write;
656 	err = counter_attr_create(dev, cattr_group, &comp, scope, count);
657 	if (err < 0)
658 		return err;
659 
660 	/* Create Count name attribute */
661 	err = counter_name_attr_create(dev, cattr_group, count->name);
662 	if (err < 0)
663 		return err;
664 
665 	/* Create Count function attribute */
666 	comp = counter_function_comp;
667 	comp.count_u32_read = counter->ops->function_read;
668 	comp.count_u32_write = counter->ops->function_write;
669 	err = counter_attr_create(dev, cattr_group, &comp, scope, count);
670 	if (err < 0)
671 		return err;
672 
673 	/* Create an attribute for each extension */
674 	for (i = 0; i < count->num_ext; i++) {
675 		err = counter_attr_create(dev, cattr_group, count->ext + i,
676 					  scope, count);
677 		if (err < 0)
678 			return err;
679 	}
680 
681 	return 0;
682 }
683 
counter_sysfs_counts_add(struct counter_device * const counter,struct counter_attribute_group * const groups)684 static int counter_sysfs_counts_add(struct counter_device *const counter,
685 	struct counter_attribute_group *const groups)
686 {
687 	size_t i;
688 	struct counter_count *count;
689 	int err;
690 
691 	/* Add each Count */
692 	for (i = 0; i < counter->num_counts; i++) {
693 		count = counter->counts + i;
694 
695 		/* Generate Count attribute directory name */
696 		groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL,
697 						"count%zu", i);
698 		if (!groups[i].name)
699 			return -ENOMEM;
700 
701 		/* Add sysfs attributes of the Synapses */
702 		err = counter_sysfs_synapses_add(counter, groups + i, count);
703 		if (err < 0)
704 			return err;
705 
706 		/* Create all attributes associated with Count */
707 		err = counter_count_attrs_create(counter, groups + i, count);
708 		if (err < 0)
709 			return err;
710 	}
711 
712 	return 0;
713 }
714 
counter_num_signals_read(struct counter_device * counter,u8 * val)715 static int counter_num_signals_read(struct counter_device *counter, u8 *val)
716 {
717 	*val = counter->num_signals;
718 	return 0;
719 }
720 
counter_num_counts_read(struct counter_device * counter,u8 * val)721 static int counter_num_counts_read(struct counter_device *counter, u8 *val)
722 {
723 	*val = counter->num_counts;
724 	return 0;
725 }
726 
727 static struct counter_comp counter_num_signals_comp =
728 	COUNTER_COMP_DEVICE_U8("num_signals", counter_num_signals_read, NULL);
729 
730 static struct counter_comp counter_num_counts_comp =
731 	COUNTER_COMP_DEVICE_U8("num_counts", counter_num_counts_read, NULL);
732 
counter_sysfs_attr_add(struct counter_device * const counter,struct counter_attribute_group * cattr_group)733 static int counter_sysfs_attr_add(struct counter_device *const counter,
734 				  struct counter_attribute_group *cattr_group)
735 {
736 	const enum counter_scope scope = COUNTER_SCOPE_DEVICE;
737 	struct device *const dev = &counter->dev;
738 	int err;
739 	size_t i;
740 
741 	/* Add Signals sysfs attributes */
742 	err = counter_sysfs_signals_add(counter, cattr_group);
743 	if (err < 0)
744 		return err;
745 	cattr_group += counter->num_signals;
746 
747 	/* Add Counts sysfs attributes */
748 	err = counter_sysfs_counts_add(counter, cattr_group);
749 	if (err < 0)
750 		return err;
751 	cattr_group += counter->num_counts;
752 
753 	/* Create name attribute */
754 	err = counter_name_attr_create(dev, cattr_group, counter->name);
755 	if (err < 0)
756 		return err;
757 
758 	/* Create num_signals attribute */
759 	err = counter_attr_create(dev, cattr_group, &counter_num_signals_comp,
760 				  scope, NULL);
761 	if (err < 0)
762 		return err;
763 
764 	/* Create num_counts attribute */
765 	err = counter_attr_create(dev, cattr_group, &counter_num_counts_comp,
766 				  scope, NULL);
767 	if (err < 0)
768 		return err;
769 
770 	/* Create an attribute for each extension */
771 	for (i = 0; i < counter->num_ext; i++) {
772 		err = counter_attr_create(dev, cattr_group, counter->ext + i,
773 					  scope, NULL);
774 		if (err < 0)
775 			return err;
776 	}
777 
778 	return 0;
779 }
780 
781 /**
782  * counter_sysfs_add - Adds Counter sysfs attributes to the device structure
783  * @counter:	Pointer to the Counter device structure
784  *
785  * Counter sysfs attributes are created and added to the respective device
786  * structure for later registration to the system. Resource-managed memory
787  * allocation is performed by this function, and this memory should be freed
788  * when no longer needed (automatically by a device_unregister call, or
789  * manually by a devres_release_all call).
790  */
counter_sysfs_add(struct counter_device * const counter)791 int counter_sysfs_add(struct counter_device *const counter)
792 {
793 	struct device *const dev = &counter->dev;
794 	const size_t num_groups = counter->num_signals + counter->num_counts + 1;
795 	struct counter_attribute_group *cattr_groups;
796 	size_t i, j;
797 	int err;
798 	struct attribute_group *groups;
799 	struct counter_attribute *p;
800 
801 	/* Allocate space for attribute groups (signals, counts, and ext) */
802 	cattr_groups = devm_kcalloc(dev, num_groups, sizeof(*cattr_groups),
803 				    GFP_KERNEL);
804 	if (!cattr_groups)
805 		return -ENOMEM;
806 
807 	/* Initialize attribute lists */
808 	for (i = 0; i < num_groups; i++)
809 		INIT_LIST_HEAD(&cattr_groups[i].attr_list);
810 
811 	/* Add Counter device sysfs attributes */
812 	err = counter_sysfs_attr_add(counter, cattr_groups);
813 	if (err < 0)
814 		return err;
815 
816 	/* Allocate attribute group pointers for association with device */
817 	dev->groups = devm_kcalloc(dev, num_groups + 1, sizeof(*dev->groups),
818 				   GFP_KERNEL);
819 	if (!dev->groups)
820 		return -ENOMEM;
821 
822 	/* Allocate space for attribute groups */
823 	groups = devm_kcalloc(dev, num_groups, sizeof(*groups), GFP_KERNEL);
824 	if (!groups)
825 		return -ENOMEM;
826 
827 	/* Prepare each group of attributes for association */
828 	for (i = 0; i < num_groups; i++) {
829 		groups[i].name = cattr_groups[i].name;
830 
831 		/* Allocate space for attribute pointers */
832 		groups[i].attrs = devm_kcalloc(dev,
833 					       cattr_groups[i].num_attr + 1,
834 					       sizeof(*groups[i].attrs),
835 					       GFP_KERNEL);
836 		if (!groups[i].attrs)
837 			return -ENOMEM;
838 
839 		/* Add attribute pointers to attribute group */
840 		j = 0;
841 		list_for_each_entry(p, &cattr_groups[i].attr_list, l)
842 			groups[i].attrs[j++] = &p->dev_attr.attr;
843 
844 		/* Associate attribute group */
845 		dev->groups[i] = &groups[i];
846 	}
847 
848 	return 0;
849 }
850