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