• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Generic Counter interface
4  * Copyright (C) 2018 William Breathitt Gray
5  */
6 #include <linux/counter.h>
7 #include <linux/device.h>
8 #include <linux/err.h>
9 #include <linux/export.h>
10 #include <linux/fs.h>
11 #include <linux/gfp.h>
12 #include <linux/idr.h>
13 #include <linux/init.h>
14 #include <linux/kernel.h>
15 #include <linux/list.h>
16 #include <linux/module.h>
17 #include <linux/printk.h>
18 #include <linux/slab.h>
19 #include <linux/string.h>
20 #include <linux/sysfs.h>
21 #include <linux/types.h>
22 
23 const char *const counter_count_direction_str[2] = {
24 	[COUNTER_COUNT_DIRECTION_FORWARD] = "forward",
25 	[COUNTER_COUNT_DIRECTION_BACKWARD] = "backward"
26 };
27 EXPORT_SYMBOL_GPL(counter_count_direction_str);
28 
29 const char *const counter_count_mode_str[4] = {
30 	[COUNTER_COUNT_MODE_NORMAL] = "normal",
31 	[COUNTER_COUNT_MODE_RANGE_LIMIT] = "range limit",
32 	[COUNTER_COUNT_MODE_NON_RECYCLE] = "non-recycle",
33 	[COUNTER_COUNT_MODE_MODULO_N] = "modulo-n"
34 };
35 EXPORT_SYMBOL_GPL(counter_count_mode_str);
36 
counter_signal_enum_read(struct counter_device * counter,struct counter_signal * signal,void * priv,char * buf)37 ssize_t counter_signal_enum_read(struct counter_device *counter,
38 				 struct counter_signal *signal, void *priv,
39 				 char *buf)
40 {
41 	const struct counter_signal_enum_ext *const e = priv;
42 	int err;
43 	size_t index;
44 
45 	if (!e->get)
46 		return -EINVAL;
47 
48 	err = e->get(counter, signal, &index);
49 	if (err)
50 		return err;
51 
52 	if (index >= e->num_items)
53 		return -EINVAL;
54 
55 	return sprintf(buf, "%s\n", e->items[index]);
56 }
57 EXPORT_SYMBOL_GPL(counter_signal_enum_read);
58 
counter_signal_enum_write(struct counter_device * counter,struct counter_signal * signal,void * priv,const char * buf,size_t len)59 ssize_t counter_signal_enum_write(struct counter_device *counter,
60 				  struct counter_signal *signal, void *priv,
61 				  const char *buf, size_t len)
62 {
63 	const struct counter_signal_enum_ext *const e = priv;
64 	ssize_t index;
65 	int err;
66 
67 	if (!e->set)
68 		return -EINVAL;
69 
70 	index = __sysfs_match_string(e->items, e->num_items, buf);
71 	if (index < 0)
72 		return index;
73 
74 	err = e->set(counter, signal, index);
75 	if (err)
76 		return err;
77 
78 	return len;
79 }
80 EXPORT_SYMBOL_GPL(counter_signal_enum_write);
81 
counter_signal_enum_available_read(struct counter_device * counter,struct counter_signal * signal,void * priv,char * buf)82 ssize_t counter_signal_enum_available_read(struct counter_device *counter,
83 					   struct counter_signal *signal,
84 					   void *priv, char *buf)
85 {
86 	const struct counter_signal_enum_ext *const e = priv;
87 	size_t i;
88 	size_t len = 0;
89 
90 	if (!e->num_items)
91 		return 0;
92 
93 	for (i = 0; i < e->num_items; i++)
94 		len += sprintf(buf + len, "%s\n", e->items[i]);
95 
96 	return len;
97 }
98 EXPORT_SYMBOL_GPL(counter_signal_enum_available_read);
99 
counter_count_enum_read(struct counter_device * counter,struct counter_count * count,void * priv,char * buf)100 ssize_t counter_count_enum_read(struct counter_device *counter,
101 				struct counter_count *count, void *priv,
102 				char *buf)
103 {
104 	const struct counter_count_enum_ext *const e = priv;
105 	int err;
106 	size_t index;
107 
108 	if (!e->get)
109 		return -EINVAL;
110 
111 	err = e->get(counter, count, &index);
112 	if (err)
113 		return err;
114 
115 	if (index >= e->num_items)
116 		return -EINVAL;
117 
118 	return sprintf(buf, "%s\n", e->items[index]);
119 }
120 EXPORT_SYMBOL_GPL(counter_count_enum_read);
121 
counter_count_enum_write(struct counter_device * counter,struct counter_count * count,void * priv,const char * buf,size_t len)122 ssize_t counter_count_enum_write(struct counter_device *counter,
123 				 struct counter_count *count, void *priv,
124 				 const char *buf, size_t len)
125 {
126 	const struct counter_count_enum_ext *const e = priv;
127 	ssize_t index;
128 	int err;
129 
130 	if (!e->set)
131 		return -EINVAL;
132 
133 	index = __sysfs_match_string(e->items, e->num_items, buf);
134 	if (index < 0)
135 		return index;
136 
137 	err = e->set(counter, count, index);
138 	if (err)
139 		return err;
140 
141 	return len;
142 }
143 EXPORT_SYMBOL_GPL(counter_count_enum_write);
144 
counter_count_enum_available_read(struct counter_device * counter,struct counter_count * count,void * priv,char * buf)145 ssize_t counter_count_enum_available_read(struct counter_device *counter,
146 					  struct counter_count *count,
147 					  void *priv, char *buf)
148 {
149 	const struct counter_count_enum_ext *const e = priv;
150 	size_t i;
151 	size_t len = 0;
152 
153 	if (!e->num_items)
154 		return 0;
155 
156 	for (i = 0; i < e->num_items; i++)
157 		len += sprintf(buf + len, "%s\n", e->items[i]);
158 
159 	return len;
160 }
161 EXPORT_SYMBOL_GPL(counter_count_enum_available_read);
162 
counter_device_enum_read(struct counter_device * counter,void * priv,char * buf)163 ssize_t counter_device_enum_read(struct counter_device *counter, void *priv,
164 				 char *buf)
165 {
166 	const struct counter_device_enum_ext *const e = priv;
167 	int err;
168 	size_t index;
169 
170 	if (!e->get)
171 		return -EINVAL;
172 
173 	err = e->get(counter, &index);
174 	if (err)
175 		return err;
176 
177 	if (index >= e->num_items)
178 		return -EINVAL;
179 
180 	return sprintf(buf, "%s\n", e->items[index]);
181 }
182 EXPORT_SYMBOL_GPL(counter_device_enum_read);
183 
counter_device_enum_write(struct counter_device * counter,void * priv,const char * buf,size_t len)184 ssize_t counter_device_enum_write(struct counter_device *counter, void *priv,
185 				  const char *buf, size_t len)
186 {
187 	const struct counter_device_enum_ext *const e = priv;
188 	ssize_t index;
189 	int err;
190 
191 	if (!e->set)
192 		return -EINVAL;
193 
194 	index = __sysfs_match_string(e->items, e->num_items, buf);
195 	if (index < 0)
196 		return index;
197 
198 	err = e->set(counter, index);
199 	if (err)
200 		return err;
201 
202 	return len;
203 }
204 EXPORT_SYMBOL_GPL(counter_device_enum_write);
205 
counter_device_enum_available_read(struct counter_device * counter,void * priv,char * buf)206 ssize_t counter_device_enum_available_read(struct counter_device *counter,
207 					   void *priv, char *buf)
208 {
209 	const struct counter_device_enum_ext *const e = priv;
210 	size_t i;
211 	size_t len = 0;
212 
213 	if (!e->num_items)
214 		return 0;
215 
216 	for (i = 0; i < e->num_items; i++)
217 		len += sprintf(buf + len, "%s\n", e->items[i]);
218 
219 	return len;
220 }
221 EXPORT_SYMBOL_GPL(counter_device_enum_available_read);
222 
223 static const char *const counter_signal_level_str[] = {
224 	[COUNTER_SIGNAL_LEVEL_LOW] = "low",
225 	[COUNTER_SIGNAL_LEVEL_HIGH] = "high"
226 };
227 
228 /**
229  * counter_signal_read_value_set - set counter_signal_read_value data
230  * @val:	counter_signal_read_value structure to set
231  * @type:	property Signal data represents
232  * @data:	Signal data
233  *
234  * This function sets an opaque counter_signal_read_value structure with the
235  * provided Signal data.
236  */
counter_signal_read_value_set(struct counter_signal_read_value * const val,const enum counter_signal_value_type type,void * const data)237 void counter_signal_read_value_set(struct counter_signal_read_value *const val,
238 				   const enum counter_signal_value_type type,
239 				   void *const data)
240 {
241 	if (type == COUNTER_SIGNAL_LEVEL)
242 		val->len = sprintf(val->buf, "%s\n",
243 				   counter_signal_level_str[*(enum counter_signal_level *)data]);
244 	else
245 		val->len = 0;
246 }
247 EXPORT_SYMBOL_GPL(counter_signal_read_value_set);
248 
249 /**
250  * counter_count_read_value_set - set counter_count_read_value data
251  * @val:	counter_count_read_value structure to set
252  * @type:	property Count data represents
253  * @data:	Count data
254  *
255  * This function sets an opaque counter_count_read_value structure with the
256  * provided Count data.
257  */
counter_count_read_value_set(struct counter_count_read_value * const val,const enum counter_count_value_type type,void * const data)258 void counter_count_read_value_set(struct counter_count_read_value *const val,
259 				  const enum counter_count_value_type type,
260 				  void *const data)
261 {
262 	switch (type) {
263 	case COUNTER_COUNT_POSITION:
264 		val->len = sprintf(val->buf, "%lu\n", *(unsigned long *)data);
265 		break;
266 	default:
267 		val->len = 0;
268 	}
269 }
270 EXPORT_SYMBOL_GPL(counter_count_read_value_set);
271 
272 /**
273  * counter_count_write_value_get - get counter_count_write_value data
274  * @data:	Count data
275  * @type:	property Count data represents
276  * @val:	counter_count_write_value structure containing data
277  *
278  * This function extracts Count data from the provided opaque
279  * counter_count_write_value structure and stores it at the address provided by
280  * @data.
281  *
282  * RETURNS:
283  * 0 on success, negative error number on failure.
284  */
counter_count_write_value_get(void * const data,const enum counter_count_value_type type,const struct counter_count_write_value * const val)285 int counter_count_write_value_get(void *const data,
286 				  const enum counter_count_value_type type,
287 				  const struct counter_count_write_value *const val)
288 {
289 	int err;
290 
291 	switch (type) {
292 	case COUNTER_COUNT_POSITION:
293 		err = kstrtoul(val->buf, 0, data);
294 		if (err)
295 			return err;
296 		break;
297 	}
298 
299 	return 0;
300 }
301 EXPORT_SYMBOL_GPL(counter_count_write_value_get);
302 
303 struct counter_attr_parm {
304 	struct counter_device_attr_group *group;
305 	const char *prefix;
306 	const char *name;
307 	ssize_t (*show)(struct device *dev, struct device_attribute *attr,
308 			char *buf);
309 	ssize_t (*store)(struct device *dev, struct device_attribute *attr,
310 			 const char *buf, size_t len);
311 	void *component;
312 };
313 
314 struct counter_device_attr {
315 	struct device_attribute dev_attr;
316 	struct list_head l;
317 	void *component;
318 };
319 
counter_attribute_create(const struct counter_attr_parm * const parm)320 static int counter_attribute_create(const struct counter_attr_parm *const parm)
321 {
322 	struct counter_device_attr *counter_attr;
323 	struct device_attribute *dev_attr;
324 	int err;
325 	struct list_head *const attr_list = &parm->group->attr_list;
326 
327 	/* Allocate a Counter device attribute */
328 	counter_attr = kzalloc(sizeof(*counter_attr), GFP_KERNEL);
329 	if (!counter_attr)
330 		return -ENOMEM;
331 	dev_attr = &counter_attr->dev_attr;
332 
333 	sysfs_attr_init(&dev_attr->attr);
334 
335 	/* Configure device attribute */
336 	dev_attr->attr.name = kasprintf(GFP_KERNEL, "%s%s", parm->prefix,
337 					parm->name);
338 	if (!dev_attr->attr.name) {
339 		err = -ENOMEM;
340 		goto err_free_counter_attr;
341 	}
342 	if (parm->show) {
343 		dev_attr->attr.mode |= 0444;
344 		dev_attr->show = parm->show;
345 	}
346 	if (parm->store) {
347 		dev_attr->attr.mode |= 0200;
348 		dev_attr->store = parm->store;
349 	}
350 
351 	/* Store associated Counter component with attribute */
352 	counter_attr->component = parm->component;
353 
354 	/* Keep track of the attribute for later cleanup */
355 	list_add(&counter_attr->l, attr_list);
356 	parm->group->num_attr++;
357 
358 	return 0;
359 
360 err_free_counter_attr:
361 	kfree(counter_attr);
362 	return err;
363 }
364 
365 #define to_counter_attr(_dev_attr) \
366 	container_of(_dev_attr, struct counter_device_attr, dev_attr)
367 
368 struct counter_signal_unit {
369 	struct counter_signal *signal;
370 };
371 
counter_signal_show(struct device * dev,struct device_attribute * attr,char * buf)372 static ssize_t counter_signal_show(struct device *dev,
373 				   struct device_attribute *attr, char *buf)
374 {
375 	struct counter_device *const counter = dev_get_drvdata(dev);
376 	const struct counter_device_attr *const devattr = to_counter_attr(attr);
377 	const struct counter_signal_unit *const component = devattr->component;
378 	struct counter_signal *const signal = component->signal;
379 	int err;
380 	struct counter_signal_read_value val = { .buf = buf };
381 
382 	err = counter->ops->signal_read(counter, signal, &val);
383 	if (err)
384 		return err;
385 
386 	return val.len;
387 }
388 
389 struct counter_name_unit {
390 	const char *name;
391 };
392 
counter_device_attr_name_show(struct device * dev,struct device_attribute * attr,char * buf)393 static ssize_t counter_device_attr_name_show(struct device *dev,
394 					     struct device_attribute *attr,
395 					     char *buf)
396 {
397 	const struct counter_name_unit *const comp = to_counter_attr(attr)->component;
398 
399 	return sprintf(buf, "%s\n", comp->name);
400 }
401 
counter_name_attribute_create(struct counter_device_attr_group * const group,const char * const name)402 static int counter_name_attribute_create(
403 	struct counter_device_attr_group *const group,
404 	const char *const name)
405 {
406 	struct counter_name_unit *name_comp;
407 	struct counter_attr_parm parm;
408 	int err;
409 
410 	/* Skip if no name */
411 	if (!name)
412 		return 0;
413 
414 	/* Allocate name attribute component */
415 	name_comp = kmalloc(sizeof(*name_comp), GFP_KERNEL);
416 	if (!name_comp)
417 		return -ENOMEM;
418 	name_comp->name = name;
419 
420 	/* Allocate Signal name attribute */
421 	parm.group = group;
422 	parm.prefix = "";
423 	parm.name = "name";
424 	parm.show = counter_device_attr_name_show;
425 	parm.store = NULL;
426 	parm.component = name_comp;
427 	err = counter_attribute_create(&parm);
428 	if (err)
429 		goto err_free_name_comp;
430 
431 	return 0;
432 
433 err_free_name_comp:
434 	kfree(name_comp);
435 	return err;
436 }
437 
438 struct counter_signal_ext_unit {
439 	struct counter_signal *signal;
440 	const struct counter_signal_ext *ext;
441 };
442 
counter_signal_ext_show(struct device * dev,struct device_attribute * attr,char * buf)443 static ssize_t counter_signal_ext_show(struct device *dev,
444 				       struct device_attribute *attr, char *buf)
445 {
446 	const struct counter_device_attr *const devattr = to_counter_attr(attr);
447 	const struct counter_signal_ext_unit *const comp = devattr->component;
448 	const struct counter_signal_ext *const ext = comp->ext;
449 
450 	return ext->read(dev_get_drvdata(dev), comp->signal, ext->priv, buf);
451 }
452 
counter_signal_ext_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)453 static ssize_t counter_signal_ext_store(struct device *dev,
454 					struct device_attribute *attr,
455 					const char *buf, size_t len)
456 {
457 	const struct counter_device_attr *const devattr = to_counter_attr(attr);
458 	const struct counter_signal_ext_unit *const comp = devattr->component;
459 	const struct counter_signal_ext *const ext = comp->ext;
460 
461 	return ext->write(dev_get_drvdata(dev), comp->signal, ext->priv, buf,
462 		len);
463 }
464 
counter_device_attr_list_free(struct list_head * attr_list)465 static void counter_device_attr_list_free(struct list_head *attr_list)
466 {
467 	struct counter_device_attr *p, *n;
468 
469 	list_for_each_entry_safe(p, n, attr_list, l) {
470 		/* free attribute name and associated component memory */
471 		kfree(p->dev_attr.attr.name);
472 		kfree(p->component);
473 		list_del(&p->l);
474 		kfree(p);
475 	}
476 }
477 
counter_signal_ext_register(struct counter_device_attr_group * const group,struct counter_signal * const signal)478 static int counter_signal_ext_register(
479 	struct counter_device_attr_group *const group,
480 	struct counter_signal *const signal)
481 {
482 	const size_t num_ext = signal->num_ext;
483 	size_t i;
484 	const struct counter_signal_ext *ext;
485 	struct counter_signal_ext_unit *signal_ext_comp;
486 	struct counter_attr_parm parm;
487 	int err;
488 
489 	/* Create an attribute for each extension */
490 	for (i = 0 ; i < num_ext; i++) {
491 		ext = signal->ext + i;
492 
493 		/* Allocate signal_ext attribute component */
494 		signal_ext_comp = kmalloc(sizeof(*signal_ext_comp), GFP_KERNEL);
495 		if (!signal_ext_comp) {
496 			err = -ENOMEM;
497 			goto err_free_attr_list;
498 		}
499 		signal_ext_comp->signal = signal;
500 		signal_ext_comp->ext = ext;
501 
502 		/* Allocate a Counter device attribute */
503 		parm.group = group;
504 		parm.prefix = "";
505 		parm.name = ext->name;
506 		parm.show = (ext->read) ? counter_signal_ext_show : NULL;
507 		parm.store = (ext->write) ? counter_signal_ext_store : NULL;
508 		parm.component = signal_ext_comp;
509 		err = counter_attribute_create(&parm);
510 		if (err) {
511 			kfree(signal_ext_comp);
512 			goto err_free_attr_list;
513 		}
514 	}
515 
516 	return 0;
517 
518 err_free_attr_list:
519 	counter_device_attr_list_free(&group->attr_list);
520 	return err;
521 }
522 
counter_signal_attributes_create(struct counter_device_attr_group * const group,const struct counter_device * const counter,struct counter_signal * const signal)523 static int counter_signal_attributes_create(
524 	struct counter_device_attr_group *const group,
525 	const struct counter_device *const counter,
526 	struct counter_signal *const signal)
527 {
528 	struct counter_signal_unit *signal_comp;
529 	struct counter_attr_parm parm;
530 	int err;
531 
532 	/* Allocate Signal attribute component */
533 	signal_comp = kmalloc(sizeof(*signal_comp), GFP_KERNEL);
534 	if (!signal_comp)
535 		return -ENOMEM;
536 	signal_comp->signal = signal;
537 
538 	/* Create main Signal attribute */
539 	parm.group = group;
540 	parm.prefix = "";
541 	parm.name = "signal";
542 	parm.show = (counter->ops->signal_read) ? counter_signal_show : NULL;
543 	parm.store = NULL;
544 	parm.component = signal_comp;
545 	err = counter_attribute_create(&parm);
546 	if (err) {
547 		kfree(signal_comp);
548 		return err;
549 	}
550 
551 	/* Create Signal name attribute */
552 	err = counter_name_attribute_create(group, signal->name);
553 	if (err)
554 		goto err_free_attr_list;
555 
556 	/* Register Signal extension attributes */
557 	err = counter_signal_ext_register(group, signal);
558 	if (err)
559 		goto err_free_attr_list;
560 
561 	return 0;
562 
563 err_free_attr_list:
564 	counter_device_attr_list_free(&group->attr_list);
565 	return err;
566 }
567 
counter_signals_register(struct counter_device_attr_group * const groups_list,const struct counter_device * const counter)568 static int counter_signals_register(
569 	struct counter_device_attr_group *const groups_list,
570 	const struct counter_device *const counter)
571 {
572 	const size_t num_signals = counter->num_signals;
573 	size_t i;
574 	struct counter_signal *signal;
575 	const char *name;
576 	int err;
577 
578 	/* Register each Signal */
579 	for (i = 0; i < num_signals; i++) {
580 		signal = counter->signals + i;
581 
582 		/* Generate Signal attribute directory name */
583 		name = kasprintf(GFP_KERNEL, "signal%d", signal->id);
584 		if (!name) {
585 			err = -ENOMEM;
586 			goto err_free_attr_groups;
587 		}
588 		groups_list[i].attr_group.name = name;
589 
590 		/* Create all attributes associated with Signal */
591 		err = counter_signal_attributes_create(groups_list + i, counter,
592 						       signal);
593 		if (err)
594 			goto err_free_attr_groups;
595 	}
596 
597 	return 0;
598 
599 err_free_attr_groups:
600 	do {
601 		kfree(groups_list[i].attr_group.name);
602 		counter_device_attr_list_free(&groups_list[i].attr_list);
603 	} while (i--);
604 	return err;
605 }
606 
607 static const char *const counter_synapse_action_str[] = {
608 	[COUNTER_SYNAPSE_ACTION_NONE] = "none",
609 	[COUNTER_SYNAPSE_ACTION_RISING_EDGE] = "rising edge",
610 	[COUNTER_SYNAPSE_ACTION_FALLING_EDGE] = "falling edge",
611 	[COUNTER_SYNAPSE_ACTION_BOTH_EDGES] = "both edges"
612 };
613 
614 struct counter_action_unit {
615 	struct counter_synapse *synapse;
616 	struct counter_count *count;
617 };
618 
counter_action_show(struct device * dev,struct device_attribute * attr,char * buf)619 static ssize_t counter_action_show(struct device *dev,
620 				   struct device_attribute *attr, char *buf)
621 {
622 	const struct counter_device_attr *const devattr = to_counter_attr(attr);
623 	int err;
624 	struct counter_device *const counter = dev_get_drvdata(dev);
625 	const struct counter_action_unit *const component = devattr->component;
626 	struct counter_count *const count = component->count;
627 	struct counter_synapse *const synapse = component->synapse;
628 	size_t action_index;
629 	enum counter_synapse_action action;
630 
631 	err = counter->ops->action_get(counter, count, synapse, &action_index);
632 	if (err)
633 		return err;
634 
635 	synapse->action = action_index;
636 
637 	action = synapse->actions_list[action_index];
638 	return sprintf(buf, "%s\n", counter_synapse_action_str[action]);
639 }
640 
counter_action_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)641 static ssize_t counter_action_store(struct device *dev,
642 				    struct device_attribute *attr,
643 				    const char *buf, size_t len)
644 {
645 	const struct counter_device_attr *const devattr = to_counter_attr(attr);
646 	const struct counter_action_unit *const component = devattr->component;
647 	struct counter_synapse *const synapse = component->synapse;
648 	size_t action_index;
649 	const size_t num_actions = synapse->num_actions;
650 	enum counter_synapse_action action;
651 	int err;
652 	struct counter_device *const counter = dev_get_drvdata(dev);
653 	struct counter_count *const count = component->count;
654 
655 	/* Find requested action mode */
656 	for (action_index = 0; action_index < num_actions; action_index++) {
657 		action = synapse->actions_list[action_index];
658 		if (sysfs_streq(buf, counter_synapse_action_str[action]))
659 			break;
660 	}
661 	/* If requested action mode not found */
662 	if (action_index >= num_actions)
663 		return -EINVAL;
664 
665 	err = counter->ops->action_set(counter, count, synapse, action_index);
666 	if (err)
667 		return err;
668 
669 	synapse->action = action_index;
670 
671 	return len;
672 }
673 
674 struct counter_action_avail_unit {
675 	const enum counter_synapse_action *actions_list;
676 	size_t num_actions;
677 };
678 
counter_synapse_action_available_show(struct device * dev,struct device_attribute * attr,char * buf)679 static ssize_t counter_synapse_action_available_show(struct device *dev,
680 	struct device_attribute *attr, char *buf)
681 {
682 	const struct counter_device_attr *const devattr = to_counter_attr(attr);
683 	const struct counter_action_avail_unit *const component = devattr->component;
684 	size_t i;
685 	enum counter_synapse_action action;
686 	ssize_t len = 0;
687 
688 	for (i = 0; i < component->num_actions; i++) {
689 		action = component->actions_list[i];
690 		len += sprintf(buf + len, "%s\n",
691 			       counter_synapse_action_str[action]);
692 	}
693 
694 	return len;
695 }
696 
counter_synapses_register(struct counter_device_attr_group * const group,const struct counter_device * const counter,struct counter_count * const count,const char * const count_attr_name)697 static int counter_synapses_register(
698 	struct counter_device_attr_group *const group,
699 	const struct counter_device *const counter,
700 	struct counter_count *const count, const char *const count_attr_name)
701 {
702 	size_t i;
703 	struct counter_synapse *synapse;
704 	const char *prefix;
705 	struct counter_action_unit *action_comp;
706 	struct counter_attr_parm parm;
707 	int err;
708 	struct counter_action_avail_unit *avail_comp;
709 
710 	/* Register each Synapse */
711 	for (i = 0; i < count->num_synapses; i++) {
712 		synapse = count->synapses + i;
713 
714 		/* Generate attribute prefix */
715 		prefix = kasprintf(GFP_KERNEL, "signal%d_",
716 				   synapse->signal->id);
717 		if (!prefix) {
718 			err = -ENOMEM;
719 			goto err_free_attr_list;
720 		}
721 
722 		/* Allocate action attribute component */
723 		action_comp = kmalloc(sizeof(*action_comp), GFP_KERNEL);
724 		if (!action_comp) {
725 			err = -ENOMEM;
726 			goto err_free_prefix;
727 		}
728 		action_comp->synapse = synapse;
729 		action_comp->count = count;
730 
731 		/* Create action attribute */
732 		parm.group = group;
733 		parm.prefix = prefix;
734 		parm.name = "action";
735 		parm.show = (counter->ops->action_get) ? counter_action_show : NULL;
736 		parm.store = (counter->ops->action_set) ? counter_action_store : NULL;
737 		parm.component = action_comp;
738 		err = counter_attribute_create(&parm);
739 		if (err) {
740 			kfree(action_comp);
741 			goto err_free_prefix;
742 		}
743 
744 		/* Allocate action available attribute component */
745 		avail_comp = kmalloc(sizeof(*avail_comp), GFP_KERNEL);
746 		if (!avail_comp) {
747 			err = -ENOMEM;
748 			goto err_free_prefix;
749 		}
750 		avail_comp->actions_list = synapse->actions_list;
751 		avail_comp->num_actions = synapse->num_actions;
752 
753 		/* Create action_available attribute */
754 		parm.group = group;
755 		parm.prefix = prefix;
756 		parm.name = "action_available";
757 		parm.show = counter_synapse_action_available_show;
758 		parm.store = NULL;
759 		parm.component = avail_comp;
760 		err = counter_attribute_create(&parm);
761 		if (err) {
762 			kfree(avail_comp);
763 			goto err_free_prefix;
764 		}
765 
766 		kfree(prefix);
767 	}
768 
769 	return 0;
770 
771 err_free_prefix:
772 	kfree(prefix);
773 err_free_attr_list:
774 	counter_device_attr_list_free(&group->attr_list);
775 	return err;
776 }
777 
778 struct counter_count_unit {
779 	struct counter_count *count;
780 };
781 
counter_count_show(struct device * dev,struct device_attribute * attr,char * buf)782 static ssize_t counter_count_show(struct device *dev,
783 				  struct device_attribute *attr,
784 				  char *buf)
785 {
786 	struct counter_device *const counter = dev_get_drvdata(dev);
787 	const struct counter_device_attr *const devattr = to_counter_attr(attr);
788 	const struct counter_count_unit *const component = devattr->component;
789 	struct counter_count *const count = component->count;
790 	int err;
791 	struct counter_count_read_value val = { .buf = buf };
792 
793 	err = counter->ops->count_read(counter, count, &val);
794 	if (err)
795 		return err;
796 
797 	return val.len;
798 }
799 
counter_count_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)800 static ssize_t counter_count_store(struct device *dev,
801 				   struct device_attribute *attr,
802 				   const char *buf, size_t len)
803 {
804 	struct counter_device *const counter = dev_get_drvdata(dev);
805 	const struct counter_device_attr *const devattr = to_counter_attr(attr);
806 	const struct counter_count_unit *const component = devattr->component;
807 	struct counter_count *const count = component->count;
808 	int err;
809 	struct counter_count_write_value val = { .buf = buf };
810 
811 	err = counter->ops->count_write(counter, count, &val);
812 	if (err)
813 		return err;
814 
815 	return len;
816 }
817 
818 static const char *const counter_count_function_str[] = {
819 	[COUNTER_COUNT_FUNCTION_INCREASE] = "increase",
820 	[COUNTER_COUNT_FUNCTION_DECREASE] = "decrease",
821 	[COUNTER_COUNT_FUNCTION_PULSE_DIRECTION] = "pulse-direction",
822 	[COUNTER_COUNT_FUNCTION_QUADRATURE_X1_A] = "quadrature x1 a",
823 	[COUNTER_COUNT_FUNCTION_QUADRATURE_X1_B] = "quadrature x1 b",
824 	[COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A] = "quadrature x2 a",
825 	[COUNTER_COUNT_FUNCTION_QUADRATURE_X2_B] = "quadrature x2 b",
826 	[COUNTER_COUNT_FUNCTION_QUADRATURE_X4] = "quadrature x4"
827 };
828 
counter_function_show(struct device * dev,struct device_attribute * attr,char * buf)829 static ssize_t counter_function_show(struct device *dev,
830 				     struct device_attribute *attr, char *buf)
831 {
832 	int err;
833 	struct counter_device *const counter = dev_get_drvdata(dev);
834 	const struct counter_device_attr *const devattr = to_counter_attr(attr);
835 	const struct counter_count_unit *const component = devattr->component;
836 	struct counter_count *const count = component->count;
837 	size_t func_index;
838 	enum counter_count_function function;
839 
840 	err = counter->ops->function_get(counter, count, &func_index);
841 	if (err)
842 		return err;
843 
844 	count->function = func_index;
845 
846 	function = count->functions_list[func_index];
847 	return sprintf(buf, "%s\n", counter_count_function_str[function]);
848 }
849 
counter_function_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)850 static ssize_t counter_function_store(struct device *dev,
851 				      struct device_attribute *attr,
852 				      const char *buf, size_t len)
853 {
854 	const struct counter_device_attr *const devattr = to_counter_attr(attr);
855 	const struct counter_count_unit *const component = devattr->component;
856 	struct counter_count *const count = component->count;
857 	const size_t num_functions = count->num_functions;
858 	size_t func_index;
859 	enum counter_count_function function;
860 	int err;
861 	struct counter_device *const counter = dev_get_drvdata(dev);
862 
863 	/* Find requested Count function mode */
864 	for (func_index = 0; func_index < num_functions; func_index++) {
865 		function = count->functions_list[func_index];
866 		if (sysfs_streq(buf, counter_count_function_str[function]))
867 			break;
868 	}
869 	/* Return error if requested Count function mode not found */
870 	if (func_index >= num_functions)
871 		return -EINVAL;
872 
873 	err = counter->ops->function_set(counter, count, func_index);
874 	if (err)
875 		return err;
876 
877 	count->function = func_index;
878 
879 	return len;
880 }
881 
882 struct counter_count_ext_unit {
883 	struct counter_count *count;
884 	const struct counter_count_ext *ext;
885 };
886 
counter_count_ext_show(struct device * dev,struct device_attribute * attr,char * buf)887 static ssize_t counter_count_ext_show(struct device *dev,
888 				      struct device_attribute *attr, char *buf)
889 {
890 	const struct counter_device_attr *const devattr = to_counter_attr(attr);
891 	const struct counter_count_ext_unit *const comp = devattr->component;
892 	const struct counter_count_ext *const ext = comp->ext;
893 
894 	return ext->read(dev_get_drvdata(dev), comp->count, ext->priv, buf);
895 }
896 
counter_count_ext_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)897 static ssize_t counter_count_ext_store(struct device *dev,
898 				       struct device_attribute *attr,
899 				       const char *buf, size_t len)
900 {
901 	const struct counter_device_attr *const devattr = to_counter_attr(attr);
902 	const struct counter_count_ext_unit *const comp = devattr->component;
903 	const struct counter_count_ext *const ext = comp->ext;
904 
905 	return ext->write(dev_get_drvdata(dev), comp->count, ext->priv, buf,
906 		len);
907 }
908 
counter_count_ext_register(struct counter_device_attr_group * const group,struct counter_count * const count)909 static int counter_count_ext_register(
910 	struct counter_device_attr_group *const group,
911 	struct counter_count *const count)
912 {
913 	size_t i;
914 	const struct counter_count_ext *ext;
915 	struct counter_count_ext_unit *count_ext_comp;
916 	struct counter_attr_parm parm;
917 	int err;
918 
919 	/* Create an attribute for each extension */
920 	for (i = 0 ; i < count->num_ext; i++) {
921 		ext = count->ext + i;
922 
923 		/* Allocate count_ext attribute component */
924 		count_ext_comp = kmalloc(sizeof(*count_ext_comp), GFP_KERNEL);
925 		if (!count_ext_comp) {
926 			err = -ENOMEM;
927 			goto err_free_attr_list;
928 		}
929 		count_ext_comp->count = count;
930 		count_ext_comp->ext = ext;
931 
932 		/* Allocate count_ext attribute */
933 		parm.group = group;
934 		parm.prefix = "";
935 		parm.name = ext->name;
936 		parm.show = (ext->read) ? counter_count_ext_show : NULL;
937 		parm.store = (ext->write) ? counter_count_ext_store : NULL;
938 		parm.component = count_ext_comp;
939 		err = counter_attribute_create(&parm);
940 		if (err) {
941 			kfree(count_ext_comp);
942 			goto err_free_attr_list;
943 		}
944 	}
945 
946 	return 0;
947 
948 err_free_attr_list:
949 	counter_device_attr_list_free(&group->attr_list);
950 	return err;
951 }
952 
953 struct counter_func_avail_unit {
954 	const enum counter_count_function *functions_list;
955 	size_t num_functions;
956 };
957 
counter_count_function_available_show(struct device * dev,struct device_attribute * attr,char * buf)958 static ssize_t counter_count_function_available_show(struct device *dev,
959 	struct device_attribute *attr, char *buf)
960 {
961 	const struct counter_device_attr *const devattr = to_counter_attr(attr);
962 	const struct counter_func_avail_unit *const component = devattr->component;
963 	const enum counter_count_function *const func_list = component->functions_list;
964 	const size_t num_functions = component->num_functions;
965 	size_t i;
966 	enum counter_count_function function;
967 	ssize_t len = 0;
968 
969 	for (i = 0; i < num_functions; i++) {
970 		function = func_list[i];
971 		len += sprintf(buf + len, "%s\n",
972 			       counter_count_function_str[function]);
973 	}
974 
975 	return len;
976 }
977 
counter_count_attributes_create(struct counter_device_attr_group * const group,const struct counter_device * const counter,struct counter_count * const count)978 static int counter_count_attributes_create(
979 	struct counter_device_attr_group *const group,
980 	const struct counter_device *const counter,
981 	struct counter_count *const count)
982 {
983 	struct counter_count_unit *count_comp;
984 	struct counter_attr_parm parm;
985 	int err;
986 	struct counter_count_unit *func_comp;
987 	struct counter_func_avail_unit *avail_comp;
988 
989 	/* Allocate count attribute component */
990 	count_comp = kmalloc(sizeof(*count_comp), GFP_KERNEL);
991 	if (!count_comp)
992 		return -ENOMEM;
993 	count_comp->count = count;
994 
995 	/* Create main Count attribute */
996 	parm.group = group;
997 	parm.prefix = "";
998 	parm.name = "count";
999 	parm.show = (counter->ops->count_read) ? counter_count_show : NULL;
1000 	parm.store = (counter->ops->count_write) ? counter_count_store : NULL;
1001 	parm.component = count_comp;
1002 	err = counter_attribute_create(&parm);
1003 	if (err) {
1004 		kfree(count_comp);
1005 		return err;
1006 	}
1007 
1008 	/* Allocate function attribute component */
1009 	func_comp = kmalloc(sizeof(*func_comp), GFP_KERNEL);
1010 	if (!func_comp) {
1011 		err = -ENOMEM;
1012 		goto err_free_attr_list;
1013 	}
1014 	func_comp->count = count;
1015 
1016 	/* Create Count function attribute */
1017 	parm.group = group;
1018 	parm.prefix = "";
1019 	parm.name = "function";
1020 	parm.show = (counter->ops->function_get) ? counter_function_show : NULL;
1021 	parm.store = (counter->ops->function_set) ? counter_function_store : NULL;
1022 	parm.component = func_comp;
1023 	err = counter_attribute_create(&parm);
1024 	if (err) {
1025 		kfree(func_comp);
1026 		goto err_free_attr_list;
1027 	}
1028 
1029 	/* Allocate function available attribute component */
1030 	avail_comp = kmalloc(sizeof(*avail_comp), GFP_KERNEL);
1031 	if (!avail_comp) {
1032 		err = -ENOMEM;
1033 		goto err_free_attr_list;
1034 	}
1035 	avail_comp->functions_list = count->functions_list;
1036 	avail_comp->num_functions = count->num_functions;
1037 
1038 	/* Create Count function_available attribute */
1039 	parm.group = group;
1040 	parm.prefix = "";
1041 	parm.name = "function_available";
1042 	parm.show = counter_count_function_available_show;
1043 	parm.store = NULL;
1044 	parm.component = avail_comp;
1045 	err = counter_attribute_create(&parm);
1046 	if (err) {
1047 		kfree(avail_comp);
1048 		goto err_free_attr_list;
1049 	}
1050 
1051 	/* Create Count name attribute */
1052 	err = counter_name_attribute_create(group, count->name);
1053 	if (err)
1054 		goto err_free_attr_list;
1055 
1056 	/* Register Count extension attributes */
1057 	err = counter_count_ext_register(group, count);
1058 	if (err)
1059 		goto err_free_attr_list;
1060 
1061 	return 0;
1062 
1063 err_free_attr_list:
1064 	counter_device_attr_list_free(&group->attr_list);
1065 	return err;
1066 }
1067 
counter_counts_register(struct counter_device_attr_group * const groups_list,const struct counter_device * const counter)1068 static int counter_counts_register(
1069 	struct counter_device_attr_group *const groups_list,
1070 	const struct counter_device *const counter)
1071 {
1072 	size_t i;
1073 	struct counter_count *count;
1074 	const char *name;
1075 	int err;
1076 
1077 	/* Register each Count */
1078 	for (i = 0; i < counter->num_counts; i++) {
1079 		count = counter->counts + i;
1080 
1081 		/* Generate Count attribute directory name */
1082 		name = kasprintf(GFP_KERNEL, "count%d", count->id);
1083 		if (!name) {
1084 			err = -ENOMEM;
1085 			goto err_free_attr_groups;
1086 		}
1087 		groups_list[i].attr_group.name = name;
1088 
1089 		/* Register the Synapses associated with each Count */
1090 		err = counter_synapses_register(groups_list + i, counter, count,
1091 						name);
1092 		if (err)
1093 			goto err_free_attr_groups;
1094 
1095 		/* Create all attributes associated with Count */
1096 		err = counter_count_attributes_create(groups_list + i, counter,
1097 						      count);
1098 		if (err)
1099 			goto err_free_attr_groups;
1100 	}
1101 
1102 	return 0;
1103 
1104 err_free_attr_groups:
1105 	do {
1106 		kfree(groups_list[i].attr_group.name);
1107 		counter_device_attr_list_free(&groups_list[i].attr_list);
1108 	} while (i--);
1109 	return err;
1110 }
1111 
1112 struct counter_size_unit {
1113 	size_t size;
1114 };
1115 
counter_device_attr_size_show(struct device * dev,struct device_attribute * attr,char * buf)1116 static ssize_t counter_device_attr_size_show(struct device *dev,
1117 					     struct device_attribute *attr,
1118 					     char *buf)
1119 {
1120 	const struct counter_size_unit *const comp = to_counter_attr(attr)->component;
1121 
1122 	return sprintf(buf, "%zu\n", comp->size);
1123 }
1124 
counter_size_attribute_create(struct counter_device_attr_group * const group,const size_t size,const char * const name)1125 static int counter_size_attribute_create(
1126 	struct counter_device_attr_group *const group,
1127 	const size_t size, const char *const name)
1128 {
1129 	struct counter_size_unit *size_comp;
1130 	struct counter_attr_parm parm;
1131 	int err;
1132 
1133 	/* Allocate size attribute component */
1134 	size_comp = kmalloc(sizeof(*size_comp), GFP_KERNEL);
1135 	if (!size_comp)
1136 		return -ENOMEM;
1137 	size_comp->size = size;
1138 
1139 	parm.group = group;
1140 	parm.prefix = "";
1141 	parm.name = name;
1142 	parm.show = counter_device_attr_size_show;
1143 	parm.store = NULL;
1144 	parm.component = size_comp;
1145 	err = counter_attribute_create(&parm);
1146 	if (err)
1147 		goto err_free_size_comp;
1148 
1149 	return 0;
1150 
1151 err_free_size_comp:
1152 	kfree(size_comp);
1153 	return err;
1154 }
1155 
1156 struct counter_ext_unit {
1157 	const struct counter_device_ext *ext;
1158 };
1159 
counter_device_ext_show(struct device * dev,struct device_attribute * attr,char * buf)1160 static ssize_t counter_device_ext_show(struct device *dev,
1161 				       struct device_attribute *attr, char *buf)
1162 {
1163 	const struct counter_device_attr *const devattr = to_counter_attr(attr);
1164 	const struct counter_ext_unit *const component = devattr->component;
1165 	const struct counter_device_ext *const ext = component->ext;
1166 
1167 	return ext->read(dev_get_drvdata(dev), ext->priv, buf);
1168 }
1169 
counter_device_ext_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)1170 static ssize_t counter_device_ext_store(struct device *dev,
1171 					struct device_attribute *attr,
1172 					const char *buf, size_t len)
1173 {
1174 	const struct counter_device_attr *const devattr = to_counter_attr(attr);
1175 	const struct counter_ext_unit *const component = devattr->component;
1176 	const struct counter_device_ext *const ext = component->ext;
1177 
1178 	return ext->write(dev_get_drvdata(dev), ext->priv, buf, len);
1179 }
1180 
counter_device_ext_register(struct counter_device_attr_group * const group,struct counter_device * const counter)1181 static int counter_device_ext_register(
1182 	struct counter_device_attr_group *const group,
1183 	struct counter_device *const counter)
1184 {
1185 	size_t i;
1186 	struct counter_ext_unit *ext_comp;
1187 	struct counter_attr_parm parm;
1188 	int err;
1189 
1190 	/* Create an attribute for each extension */
1191 	for (i = 0 ; i < counter->num_ext; i++) {
1192 		/* Allocate extension attribute component */
1193 		ext_comp = kmalloc(sizeof(*ext_comp), GFP_KERNEL);
1194 		if (!ext_comp) {
1195 			err = -ENOMEM;
1196 			goto err_free_attr_list;
1197 		}
1198 
1199 		ext_comp->ext = counter->ext + i;
1200 
1201 		/* Allocate extension attribute */
1202 		parm.group = group;
1203 		parm.prefix = "";
1204 		parm.name = counter->ext[i].name;
1205 		parm.show = (counter->ext[i].read) ? counter_device_ext_show : NULL;
1206 		parm.store = (counter->ext[i].write) ? counter_device_ext_store : NULL;
1207 		parm.component = ext_comp;
1208 		err = counter_attribute_create(&parm);
1209 		if (err) {
1210 			kfree(ext_comp);
1211 			goto err_free_attr_list;
1212 		}
1213 	}
1214 
1215 	return 0;
1216 
1217 err_free_attr_list:
1218 	counter_device_attr_list_free(&group->attr_list);
1219 	return err;
1220 }
1221 
counter_global_attr_register(struct counter_device_attr_group * const group,struct counter_device * const counter)1222 static int counter_global_attr_register(
1223 	struct counter_device_attr_group *const group,
1224 	struct counter_device *const counter)
1225 {
1226 	int err;
1227 
1228 	/* Create name attribute */
1229 	err = counter_name_attribute_create(group, counter->name);
1230 	if (err)
1231 		return err;
1232 
1233 	/* Create num_counts attribute */
1234 	err = counter_size_attribute_create(group, counter->num_counts,
1235 					    "num_counts");
1236 	if (err)
1237 		goto err_free_attr_list;
1238 
1239 	/* Create num_signals attribute */
1240 	err = counter_size_attribute_create(group, counter->num_signals,
1241 					    "num_signals");
1242 	if (err)
1243 		goto err_free_attr_list;
1244 
1245 	/* Register Counter device extension attributes */
1246 	err = counter_device_ext_register(group, counter);
1247 	if (err)
1248 		goto err_free_attr_list;
1249 
1250 	return 0;
1251 
1252 err_free_attr_list:
1253 	counter_device_attr_list_free(&group->attr_list);
1254 	return err;
1255 }
1256 
counter_device_groups_list_free(struct counter_device_attr_group * const groups_list,const size_t num_groups)1257 static void counter_device_groups_list_free(
1258 	struct counter_device_attr_group *const groups_list,
1259 	const size_t num_groups)
1260 {
1261 	struct counter_device_attr_group *group;
1262 	size_t i;
1263 
1264 	/* loop through all attribute groups (signals, counts, global, etc.) */
1265 	for (i = 0; i < num_groups; i++) {
1266 		group = groups_list + i;
1267 
1268 		/* free all attribute group and associated attributes memory */
1269 		kfree(group->attr_group.name);
1270 		kfree(group->attr_group.attrs);
1271 		counter_device_attr_list_free(&group->attr_list);
1272 	}
1273 
1274 	kfree(groups_list);
1275 }
1276 
counter_device_groups_list_prepare(struct counter_device * const counter)1277 static int counter_device_groups_list_prepare(
1278 	struct counter_device *const counter)
1279 {
1280 	const size_t total_num_groups =
1281 		counter->num_signals + counter->num_counts + 1;
1282 	struct counter_device_attr_group *groups_list;
1283 	size_t i;
1284 	int err;
1285 	size_t num_groups = 0;
1286 
1287 	/* Allocate space for attribute groups (signals, counts, and ext) */
1288 	groups_list = kcalloc(total_num_groups, sizeof(*groups_list),
1289 			      GFP_KERNEL);
1290 	if (!groups_list)
1291 		return -ENOMEM;
1292 
1293 	/* Initialize attribute lists */
1294 	for (i = 0; i < total_num_groups; i++)
1295 		INIT_LIST_HEAD(&groups_list[i].attr_list);
1296 
1297 	/* Register Signals */
1298 	err = counter_signals_register(groups_list, counter);
1299 	if (err)
1300 		goto err_free_groups_list;
1301 	num_groups += counter->num_signals;
1302 
1303 	/* Register Counts and respective Synapses */
1304 	err = counter_counts_register(groups_list + num_groups, counter);
1305 	if (err)
1306 		goto err_free_groups_list;
1307 	num_groups += counter->num_counts;
1308 
1309 	/* Register Counter global attributes */
1310 	err = counter_global_attr_register(groups_list + num_groups, counter);
1311 	if (err)
1312 		goto err_free_groups_list;
1313 	num_groups++;
1314 
1315 	/* Store groups_list in device_state */
1316 	counter->device_state->groups_list = groups_list;
1317 	counter->device_state->num_groups = num_groups;
1318 
1319 	return 0;
1320 
1321 err_free_groups_list:
1322 	counter_device_groups_list_free(groups_list, num_groups);
1323 	return err;
1324 }
1325 
counter_device_groups_prepare(struct counter_device_state * const device_state)1326 static int counter_device_groups_prepare(
1327 	struct counter_device_state *const device_state)
1328 {
1329 	size_t i, j;
1330 	struct counter_device_attr_group *group;
1331 	int err;
1332 	struct counter_device_attr *p;
1333 
1334 	/* Allocate attribute groups for association with device */
1335 	device_state->groups = kcalloc(device_state->num_groups + 1,
1336 				       sizeof(*device_state->groups),
1337 				       GFP_KERNEL);
1338 	if (!device_state->groups)
1339 		return -ENOMEM;
1340 
1341 	/* Prepare each group of attributes for association */
1342 	for (i = 0; i < device_state->num_groups; i++) {
1343 		group = device_state->groups_list + i;
1344 
1345 		/* Allocate space for attribute pointers in attribute group */
1346 		group->attr_group.attrs = kcalloc(group->num_attr + 1,
1347 			sizeof(*group->attr_group.attrs), GFP_KERNEL);
1348 		if (!group->attr_group.attrs) {
1349 			err = -ENOMEM;
1350 			goto err_free_groups;
1351 		}
1352 
1353 		/* Add attribute pointers to attribute group */
1354 		j = 0;
1355 		list_for_each_entry(p, &group->attr_list, l)
1356 			group->attr_group.attrs[j++] = &p->dev_attr.attr;
1357 
1358 		/* Group attributes in attribute group */
1359 		device_state->groups[i] = &group->attr_group;
1360 	}
1361 	/* Associate attributes with device */
1362 	device_state->dev.groups = device_state->groups;
1363 
1364 	return 0;
1365 
1366 err_free_groups:
1367 	do {
1368 		group = device_state->groups_list + i;
1369 		kfree(group->attr_group.attrs);
1370 		group->attr_group.attrs = NULL;
1371 	} while (i--);
1372 	kfree(device_state->groups);
1373 	return err;
1374 }
1375 
1376 /* Provides a unique ID for each counter device */
1377 static DEFINE_IDA(counter_ida);
1378 
counter_device_release(struct device * dev)1379 static void counter_device_release(struct device *dev)
1380 {
1381 	struct counter_device *const counter = dev_get_drvdata(dev);
1382 	struct counter_device_state *const device_state = counter->device_state;
1383 
1384 	kfree(device_state->groups);
1385 	counter_device_groups_list_free(device_state->groups_list,
1386 					device_state->num_groups);
1387 	ida_simple_remove(&counter_ida, device_state->id);
1388 	kfree(device_state);
1389 }
1390 
1391 static struct device_type counter_device_type = {
1392 	.name = "counter_device",
1393 	.release = counter_device_release
1394 };
1395 
1396 static struct bus_type counter_bus_type = {
1397 	.name = "counter"
1398 };
1399 
1400 /**
1401  * counter_register - register Counter to the system
1402  * @counter:	pointer to Counter to register
1403  *
1404  * This function registers a Counter to the system. A sysfs "counter" directory
1405  * will be created and populated with sysfs attributes correlating with the
1406  * Counter Signals, Synapses, and Counts respectively.
1407  */
counter_register(struct counter_device * const counter)1408 int counter_register(struct counter_device *const counter)
1409 {
1410 	struct counter_device_state *device_state;
1411 	int err;
1412 
1413 	/* Allocate internal state container for Counter device */
1414 	device_state = kzalloc(sizeof(*device_state), GFP_KERNEL);
1415 	if (!device_state)
1416 		return -ENOMEM;
1417 	counter->device_state = device_state;
1418 
1419 	/* Acquire unique ID */
1420 	device_state->id = ida_simple_get(&counter_ida, 0, 0, GFP_KERNEL);
1421 	if (device_state->id < 0) {
1422 		err = device_state->id;
1423 		goto err_free_device_state;
1424 	}
1425 
1426 	/* Configure device structure for Counter */
1427 	device_state->dev.type = &counter_device_type;
1428 	device_state->dev.bus = &counter_bus_type;
1429 	if (counter->parent) {
1430 		device_state->dev.parent = counter->parent;
1431 		device_state->dev.of_node = counter->parent->of_node;
1432 	}
1433 	dev_set_name(&device_state->dev, "counter%d", device_state->id);
1434 	device_initialize(&device_state->dev);
1435 	dev_set_drvdata(&device_state->dev, counter);
1436 
1437 	/* Prepare device attributes */
1438 	err = counter_device_groups_list_prepare(counter);
1439 	if (err)
1440 		goto err_free_id;
1441 
1442 	/* Organize device attributes to groups and match to device */
1443 	err = counter_device_groups_prepare(device_state);
1444 	if (err)
1445 		goto err_free_groups_list;
1446 
1447 	/* Add device to system */
1448 	err = device_add(&device_state->dev);
1449 	if (err)
1450 		goto err_free_groups;
1451 
1452 	return 0;
1453 
1454 err_free_groups:
1455 	kfree(device_state->groups);
1456 err_free_groups_list:
1457 	counter_device_groups_list_free(device_state->groups_list,
1458 					device_state->num_groups);
1459 err_free_id:
1460 	ida_simple_remove(&counter_ida, device_state->id);
1461 err_free_device_state:
1462 	kfree(device_state);
1463 	return err;
1464 }
1465 EXPORT_SYMBOL_GPL(counter_register);
1466 
1467 /**
1468  * counter_unregister - unregister Counter from the system
1469  * @counter:	pointer to Counter to unregister
1470  *
1471  * The Counter is unregistered from the system; all allocated memory is freed.
1472  */
counter_unregister(struct counter_device * const counter)1473 void counter_unregister(struct counter_device *const counter)
1474 {
1475 	if (counter)
1476 		device_del(&counter->device_state->dev);
1477 }
1478 EXPORT_SYMBOL_GPL(counter_unregister);
1479 
devm_counter_unreg(struct device * dev,void * res)1480 static void devm_counter_unreg(struct device *dev, void *res)
1481 {
1482 	counter_unregister(*(struct counter_device **)res);
1483 }
1484 
1485 /**
1486  * devm_counter_register - Resource-managed counter_register
1487  * @dev:	device to allocate counter_device for
1488  * @counter:	pointer to Counter to register
1489  *
1490  * Managed counter_register. The Counter registered with this function is
1491  * automatically unregistered on driver detach. This function calls
1492  * counter_register internally. Refer to that function for more information.
1493  *
1494  * If an Counter registered with this function needs to be unregistered
1495  * separately, devm_counter_unregister must be used.
1496  *
1497  * RETURNS:
1498  * 0 on success, negative error number on failure.
1499  */
devm_counter_register(struct device * dev,struct counter_device * const counter)1500 int devm_counter_register(struct device *dev,
1501 			  struct counter_device *const counter)
1502 {
1503 	struct counter_device **ptr;
1504 	int ret;
1505 
1506 	ptr = devres_alloc(devm_counter_unreg, sizeof(*ptr), GFP_KERNEL);
1507 	if (!ptr)
1508 		return -ENOMEM;
1509 
1510 	ret = counter_register(counter);
1511 	if (!ret) {
1512 		*ptr = counter;
1513 		devres_add(dev, ptr);
1514 	} else {
1515 		devres_free(ptr);
1516 	}
1517 
1518 	return ret;
1519 }
1520 EXPORT_SYMBOL_GPL(devm_counter_register);
1521 
devm_counter_match(struct device * dev,void * res,void * data)1522 static int devm_counter_match(struct device *dev, void *res, void *data)
1523 {
1524 	struct counter_device **r = res;
1525 
1526 	if (!r || !*r) {
1527 		WARN_ON(!r || !*r);
1528 		return 0;
1529 	}
1530 
1531 	return *r == data;
1532 }
1533 
1534 /**
1535  * devm_counter_unregister - Resource-managed counter_unregister
1536  * @dev:	device this counter_device belongs to
1537  * @counter:	pointer to Counter associated with the device
1538  *
1539  * Unregister Counter registered with devm_counter_register.
1540  */
devm_counter_unregister(struct device * dev,struct counter_device * const counter)1541 void devm_counter_unregister(struct device *dev,
1542 			     struct counter_device *const counter)
1543 {
1544 	int rc;
1545 
1546 	rc = devres_release(dev, devm_counter_unreg, devm_counter_match,
1547 			    counter);
1548 	WARN_ON(rc);
1549 }
1550 EXPORT_SYMBOL_GPL(devm_counter_unregister);
1551 
counter_init(void)1552 static int __init counter_init(void)
1553 {
1554 	return bus_register(&counter_bus_type);
1555 }
1556 
counter_exit(void)1557 static void __exit counter_exit(void)
1558 {
1559 	bus_unregister(&counter_bus_type);
1560 }
1561 
1562 subsys_initcall(counter_init);
1563 module_exit(counter_exit);
1564 
1565 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
1566 MODULE_DESCRIPTION("Generic Counter interface");
1567 MODULE_LICENSE("GPL v2");
1568