Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
   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
  23const char *const counter_count_direction_str[2] = {
  24	[COUNTER_COUNT_DIRECTION_FORWARD] = "forward",
  25	[COUNTER_COUNT_DIRECTION_BACKWARD] = "backward"
  26};
  27EXPORT_SYMBOL_GPL(counter_count_direction_str);
  28
  29const 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};
  35EXPORT_SYMBOL_GPL(counter_count_mode_str);
  36
  37ssize_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}
  57EXPORT_SYMBOL_GPL(counter_signal_enum_read);
  58
  59ssize_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}
  80EXPORT_SYMBOL_GPL(counter_signal_enum_write);
  81
  82ssize_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}
  98EXPORT_SYMBOL_GPL(counter_signal_enum_available_read);
  99
 100ssize_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}
 120EXPORT_SYMBOL_GPL(counter_count_enum_read);
 121
 122ssize_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}
 143EXPORT_SYMBOL_GPL(counter_count_enum_write);
 144
 145ssize_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}
 161EXPORT_SYMBOL_GPL(counter_count_enum_available_read);
 162
 163ssize_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}
 182EXPORT_SYMBOL_GPL(counter_device_enum_read);
 183
 184ssize_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}
 204EXPORT_SYMBOL_GPL(counter_device_enum_write);
 205
 206ssize_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}
 221EXPORT_SYMBOL_GPL(counter_device_enum_available_read);
 222
 223struct 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
 234struct counter_device_attr {
 235	struct device_attribute dev_attr;
 236	struct list_head l;
 237	void *component;
 238};
 239
 240static 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
 280err_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
 288struct counter_signal_unit {
 289	struct counter_signal *signal;
 290};
 291
 292static const char *const counter_signal_value_str[] = {
 293	[COUNTER_SIGNAL_LOW] = "low",
 294	[COUNTER_SIGNAL_HIGH] = "high"
 295};
 296
 297static 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
 314struct counter_name_unit {
 315	const char *name;
 316};
 317
 318static 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
 327static 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
 358err_free_name_comp:
 359	kfree(name_comp);
 360	return err;
 361}
 362
 363struct counter_signal_ext_unit {
 364	struct counter_signal *signal;
 365	const struct counter_signal_ext *ext;
 366};
 367
 368static 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
 378static 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
 390static 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
 403static 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
 443err_free_attr_list:
 444	counter_device_attr_list_free(&group->attr_list);
 445	return err;
 446}
 447
 448static 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
 488err_free_attr_list:
 489	counter_device_attr_list_free(&group->attr_list);
 490	return err;
 491}
 492
 493static 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
 524err_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
 532static 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
 539struct counter_action_unit {
 540	struct counter_synapse *synapse;
 541	struct counter_count *count;
 542};
 543
 544static 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
 566static 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
 599struct counter_action_avail_unit {
 600	const enum counter_synapse_action *actions_list;
 601	size_t num_actions;
 602};
 603
 604static 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
 622static 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
 696err_free_prefix:
 697	kfree(prefix);
 698err_free_attr_list:
 699	counter_device_attr_list_free(&group->attr_list);
 700	return err;
 701}
 702
 703struct counter_count_unit {
 704	struct counter_count *count;
 705};
 706
 707static 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
 725static 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
 747static 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
 758static 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
 779static 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
 811struct counter_count_ext_unit {
 812	struct counter_count *count;
 813	const struct counter_count_ext *ext;
 814};
 815
 816static 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
 826static 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
 838static 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
 877err_free_attr_list:
 878	counter_device_attr_list_free(&group->attr_list);
 879	return err;
 880}
 881
 882struct counter_func_avail_unit {
 883	const enum counter_count_function *functions_list;
 884	size_t num_functions;
 885};
 886
 887static 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
 907static 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
 992err_free_attr_list:
 993	counter_device_attr_list_free(&group->attr_list);
 994	return err;
 995}
 996
 997static 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
1033err_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
1041struct counter_size_unit {
1042	size_t size;
1043};
1044
1045static 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
1054static 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
1080err_free_size_comp:
1081	kfree(size_comp);
1082	return err;
1083}
1084
1085struct counter_ext_unit {
1086	const struct counter_device_ext *ext;
1087};
1088
1089static 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
1099static 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
1110static 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
1146err_free_attr_list:
1147	counter_device_attr_list_free(&group->attr_list);
1148	return err;
1149}
1150
1151static 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
1181err_free_attr_list:
1182	counter_device_attr_list_free(&group->attr_list);
1183	return err;
1184}
1185
1186static 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
1206static 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
1250err_free_groups_list:
1251	counter_device_groups_list_free(groups_list, num_groups);
1252	return err;
1253}
1254
1255static 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
1295err_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 */
1306static DEFINE_IDA(counter_ida);
1307
1308static 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
1320static struct device_type counter_device_type = {
1321	.name = "counter_device",
1322	.release = counter_device_release
1323};
1324
1325static 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 */
1337int 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
1383err_free_groups:
1384	kfree(device_state->groups);
1385err_free_groups_list:
1386	counter_device_groups_list_free(device_state->groups_list,
1387					device_state->num_groups);
1388err_free_id:
1389	ida_simple_remove(&counter_ida, device_state->id);
1390err_free_device_state:
1391	kfree(device_state);
1392	return err;
1393}
1394EXPORT_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 */
1402void counter_unregister(struct counter_device *const counter)
1403{
1404	if (counter)
1405		device_del(&counter->device_state->dev);
1406}
1407EXPORT_SYMBOL_GPL(counter_unregister);
1408
1409static 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 */
1429int 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}
1449EXPORT_SYMBOL_GPL(devm_counter_register);
1450
1451static 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 */
1470void 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}
1479EXPORT_SYMBOL_GPL(devm_counter_unregister);
1480
1481static int __init counter_init(void)
1482{
1483	return bus_register(&counter_bus_type);
1484}
1485
1486static void __exit counter_exit(void)
1487{
1488	bus_unregister(&counter_bus_type);
1489}
1490
1491subsys_initcall(counter_init);
1492module_exit(counter_exit);
1493
1494MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
1495MODULE_DESCRIPTION("Generic Counter interface");
1496MODULE_LICENSE("GPL v2");