Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Generic Counter sysfs interface
   4 * Copyright (C) 2020 William Breathitt Gray
   5 */
   6#include <linux/counter.h>
   7#include <linux/device.h>
   8#include <linux/err.h>
   9#include <linux/gfp.h>
  10#include <linux/kernel.h>
  11#include <linux/kfifo.h>
  12#include <linux/kstrtox.h>
  13#include <linux/list.h>
  14#include <linux/mutex.h>
  15#include <linux/spinlock.h>
  16#include <linux/string.h>
  17#include <linux/sysfs.h>
  18#include <linux/types.h>
  19
  20#include "counter-sysfs.h"
  21
  22static inline struct counter_device *counter_from_dev(struct device *dev)
  23{
  24	return container_of(dev, struct counter_device, dev);
  25}
  26
  27/**
  28 * struct counter_attribute - Counter sysfs attribute
  29 * @dev_attr:	device attribute for sysfs
  30 * @l:		node to add Counter attribute to attribute group list
  31 * @comp:	Counter component callbacks and data
  32 * @scope:	Counter scope of the attribute
  33 * @parent:	pointer to the parent component
  34 */
  35struct counter_attribute {
  36	struct device_attribute dev_attr;
  37	struct list_head l;
  38
  39	struct counter_comp comp;
  40	enum counter_scope scope;
  41	void *parent;
  42};
  43
  44#define to_counter_attribute(_dev_attr) \
  45	container_of(_dev_attr, struct counter_attribute, dev_attr)
  46
  47/**
  48 * struct counter_attribute_group - container for attribute group
  49 * @name:	name of the attribute group
  50 * @attr_list:	list to keep track of created attributes
  51 * @num_attr:	number of attributes
  52 */
  53struct counter_attribute_group {
  54	const char *name;
  55	struct list_head attr_list;
  56	size_t num_attr;
  57};
  58
  59static const char *const counter_function_str[] = {
  60	[COUNTER_FUNCTION_INCREASE] = "increase",
  61	[COUNTER_FUNCTION_DECREASE] = "decrease",
  62	[COUNTER_FUNCTION_PULSE_DIRECTION] = "pulse-direction",
  63	[COUNTER_FUNCTION_QUADRATURE_X1_A] = "quadrature x1 a",
  64	[COUNTER_FUNCTION_QUADRATURE_X1_B] = "quadrature x1 b",
  65	[COUNTER_FUNCTION_QUADRATURE_X2_A] = "quadrature x2 a",
  66	[COUNTER_FUNCTION_QUADRATURE_X2_B] = "quadrature x2 b",
  67	[COUNTER_FUNCTION_QUADRATURE_X4] = "quadrature x4"
  68};
  69
  70static const char *const counter_signal_value_str[] = {
  71	[COUNTER_SIGNAL_LEVEL_LOW] = "low",
  72	[COUNTER_SIGNAL_LEVEL_HIGH] = "high"
  73};
  74
  75static const char *const counter_synapse_action_str[] = {
  76	[COUNTER_SYNAPSE_ACTION_NONE] = "none",
  77	[COUNTER_SYNAPSE_ACTION_RISING_EDGE] = "rising edge",
  78	[COUNTER_SYNAPSE_ACTION_FALLING_EDGE] = "falling edge",
  79	[COUNTER_SYNAPSE_ACTION_BOTH_EDGES] = "both edges"
  80};
  81
  82static const char *const counter_count_direction_str[] = {
  83	[COUNTER_COUNT_DIRECTION_FORWARD] = "forward",
  84	[COUNTER_COUNT_DIRECTION_BACKWARD] = "backward"
  85};
  86
  87static const char *const counter_count_mode_str[] = {
  88	[COUNTER_COUNT_MODE_NORMAL] = "normal",
  89	[COUNTER_COUNT_MODE_RANGE_LIMIT] = "range limit",
  90	[COUNTER_COUNT_MODE_NON_RECYCLE] = "non-recycle",
  91	[COUNTER_COUNT_MODE_MODULO_N] = "modulo-n",
  92	[COUNTER_COUNT_MODE_INTERRUPT_ON_TERMINAL_COUNT] = "interrupt on terminal count",
  93	[COUNTER_COUNT_MODE_HARDWARE_RETRIGGERABLE_ONESHOT] = "hardware retriggerable one-shot",
  94	[COUNTER_COUNT_MODE_RATE_GENERATOR] = "rate generator",
  95	[COUNTER_COUNT_MODE_SQUARE_WAVE_MODE] = "square wave mode",
  96	[COUNTER_COUNT_MODE_SOFTWARE_TRIGGERED_STROBE] = "software triggered strobe",
  97	[COUNTER_COUNT_MODE_HARDWARE_TRIGGERED_STROBE] = "hardware triggered strobe",
  98};
  99
 100static const char *const counter_signal_polarity_str[] = {
 101	[COUNTER_SIGNAL_POLARITY_POSITIVE] = "positive",
 102	[COUNTER_SIGNAL_POLARITY_NEGATIVE] = "negative"
 103};
 104
 105static ssize_t counter_comp_u8_show(struct device *dev,
 106				    struct device_attribute *attr, char *buf)
 107{
 108	const struct counter_attribute *const a = to_counter_attribute(attr);
 109	struct counter_device *const counter = counter_from_dev(dev);
 110	int err;
 111	u8 data = 0;
 112
 113	switch (a->scope) {
 114	case COUNTER_SCOPE_DEVICE:
 115		err = a->comp.device_u8_read(counter, &data);
 116		break;
 117	case COUNTER_SCOPE_SIGNAL:
 118		err = a->comp.signal_u8_read(counter, a->parent, &data);
 119		break;
 120	case COUNTER_SCOPE_COUNT:
 121		err = a->comp.count_u8_read(counter, a->parent, &data);
 122		break;
 123	default:
 124		return -EINVAL;
 125	}
 126	if (err < 0)
 127		return err;
 128
 129	if (a->comp.type == COUNTER_COMP_BOOL)
 130		/* data should already be boolean but ensure just to be safe */
 131		data = !!data;
 132
 133	return sysfs_emit(buf, "%u\n", (unsigned int)data);
 134}
 135
 136static ssize_t counter_comp_u8_store(struct device *dev,
 137				     struct device_attribute *attr,
 138				     const char *buf, size_t len)
 139{
 140	const struct counter_attribute *const a = to_counter_attribute(attr);
 141	struct counter_device *const counter = counter_from_dev(dev);
 142	int err;
 143	bool bool_data = 0;
 144	u8 data = 0;
 145
 146	if (a->comp.type == COUNTER_COMP_BOOL) {
 147		err = kstrtobool(buf, &bool_data);
 148		data = bool_data;
 149	} else
 150		err = kstrtou8(buf, 0, &data);
 151	if (err < 0)
 152		return err;
 153
 154	switch (a->scope) {
 155	case COUNTER_SCOPE_DEVICE:
 156		err = a->comp.device_u8_write(counter, data);
 157		break;
 158	case COUNTER_SCOPE_SIGNAL:
 159		err = a->comp.signal_u8_write(counter, a->parent, data);
 160		break;
 161	case COUNTER_SCOPE_COUNT:
 162		err = a->comp.count_u8_write(counter, a->parent, data);
 163		break;
 164	default:
 165		return -EINVAL;
 166	}
 167	if (err < 0)
 168		return err;
 169
 170	return len;
 171}
 172
 173static ssize_t counter_comp_u32_show(struct device *dev,
 174				     struct device_attribute *attr, char *buf)
 175{
 176	const struct counter_attribute *const a = to_counter_attribute(attr);
 177	struct counter_device *const counter = counter_from_dev(dev);
 178	const struct counter_available *const avail = a->comp.priv;
 179	int err;
 180	u32 data = 0;
 181
 182	switch (a->scope) {
 183	case COUNTER_SCOPE_DEVICE:
 184		err = a->comp.device_u32_read(counter, &data);
 185		break;
 186	case COUNTER_SCOPE_SIGNAL:
 187		err = a->comp.signal_u32_read(counter, a->parent, &data);
 188		break;
 189	case COUNTER_SCOPE_COUNT:
 190		if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION)
 191			err = a->comp.action_read(counter, a->parent,
 192						  a->comp.priv, &data);
 193		else
 194			err = a->comp.count_u32_read(counter, a->parent, &data);
 195		break;
 196	default:
 197		return -EINVAL;
 198	}
 199	if (err < 0)
 200		return err;
 201
 202	switch (a->comp.type) {
 203	case COUNTER_COMP_FUNCTION:
 204		return sysfs_emit(buf, "%s\n", counter_function_str[data]);
 205	case COUNTER_COMP_SIGNAL_LEVEL:
 206		return sysfs_emit(buf, "%s\n", counter_signal_value_str[data]);
 207	case COUNTER_COMP_SYNAPSE_ACTION:
 208		return sysfs_emit(buf, "%s\n", counter_synapse_action_str[data]);
 209	case COUNTER_COMP_ENUM:
 210		return sysfs_emit(buf, "%s\n", avail->strs[data]);
 211	case COUNTER_COMP_COUNT_DIRECTION:
 212		return sysfs_emit(buf, "%s\n", counter_count_direction_str[data]);
 213	case COUNTER_COMP_COUNT_MODE:
 214		return sysfs_emit(buf, "%s\n", counter_count_mode_str[data]);
 215	case COUNTER_COMP_SIGNAL_POLARITY:
 216		return sysfs_emit(buf, "%s\n", counter_signal_polarity_str[data]);
 217	default:
 218		return sysfs_emit(buf, "%u\n", (unsigned int)data);
 219	}
 220}
 221
 222static int counter_find_enum(u32 *const enum_item, const u32 *const enums,
 223			     const size_t num_enums, const char *const buf,
 224			     const char *const string_array[])
 225{
 226	size_t index;
 227
 228	for (index = 0; index < num_enums; index++) {
 229		*enum_item = enums[index];
 230		if (sysfs_streq(buf, string_array[*enum_item]))
 231			return 0;
 232	}
 233
 234	return -EINVAL;
 235}
 236
 237static ssize_t counter_comp_u32_store(struct device *dev,
 238				      struct device_attribute *attr,
 239				      const char *buf, size_t len)
 240{
 241	const struct counter_attribute *const a = to_counter_attribute(attr);
 242	struct counter_device *const counter = counter_from_dev(dev);
 243	struct counter_count *const count = a->parent;
 244	struct counter_synapse *const synapse = a->comp.priv;
 245	const struct counter_available *const avail = a->comp.priv;
 246	int err;
 247	u32 data = 0;
 248
 249	switch (a->comp.type) {
 250	case COUNTER_COMP_FUNCTION:
 251		err = counter_find_enum(&data, count->functions_list,
 252					count->num_functions, buf,
 253					counter_function_str);
 254		break;
 255	case COUNTER_COMP_SYNAPSE_ACTION:
 256		err = counter_find_enum(&data, synapse->actions_list,
 257					synapse->num_actions, buf,
 258					counter_synapse_action_str);
 259		break;
 260	case COUNTER_COMP_ENUM:
 261		err = __sysfs_match_string(avail->strs, avail->num_items, buf);
 262		data = err;
 263		break;
 264	case COUNTER_COMP_COUNT_MODE:
 265		err = counter_find_enum(&data, avail->enums, avail->num_items,
 266					buf, counter_count_mode_str);
 267		break;
 268	case COUNTER_COMP_SIGNAL_POLARITY:
 269		err = counter_find_enum(&data, avail->enums, avail->num_items,
 270					buf, counter_signal_polarity_str);
 271		break;
 272	default:
 273		err = kstrtou32(buf, 0, &data);
 274		break;
 275	}
 276	if (err < 0)
 277		return err;
 278
 279	switch (a->scope) {
 280	case COUNTER_SCOPE_DEVICE:
 281		err = a->comp.device_u32_write(counter, data);
 282		break;
 283	case COUNTER_SCOPE_SIGNAL:
 284		err = a->comp.signal_u32_write(counter, a->parent, data);
 285		break;
 286	case COUNTER_SCOPE_COUNT:
 287		if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION)
 288			err = a->comp.action_write(counter, count, synapse,
 289						   data);
 290		else
 291			err = a->comp.count_u32_write(counter, count, data);
 292		break;
 293	default:
 294		return -EINVAL;
 295	}
 296	if (err < 0)
 297		return err;
 298
 299	return len;
 300}
 301
 302static ssize_t counter_comp_u64_show(struct device *dev,
 303				     struct device_attribute *attr, char *buf)
 304{
 305	const struct counter_attribute *const a = to_counter_attribute(attr);
 306	struct counter_device *const counter = counter_from_dev(dev);
 307	int err;
 308	u64 data = 0;
 309
 310	switch (a->scope) {
 311	case COUNTER_SCOPE_DEVICE:
 312		err = a->comp.device_u64_read(counter, &data);
 313		break;
 314	case COUNTER_SCOPE_SIGNAL:
 315		err = a->comp.signal_u64_read(counter, a->parent, &data);
 316		break;
 317	case COUNTER_SCOPE_COUNT:
 318		err = a->comp.count_u64_read(counter, a->parent, &data);
 319		break;
 320	default:
 321		return -EINVAL;
 322	}
 323	if (err < 0)
 324		return err;
 325
 326	return sysfs_emit(buf, "%llu\n", (unsigned long long)data);
 327}
 328
 329static ssize_t counter_comp_u64_store(struct device *dev,
 330				      struct device_attribute *attr,
 331				      const char *buf, size_t len)
 332{
 333	const struct counter_attribute *const a = to_counter_attribute(attr);
 334	struct counter_device *const counter = counter_from_dev(dev);
 335	int err;
 336	u64 data = 0;
 337
 338	err = kstrtou64(buf, 0, &data);
 339	if (err < 0)
 340		return err;
 341
 342	switch (a->scope) {
 343	case COUNTER_SCOPE_DEVICE:
 344		err = a->comp.device_u64_write(counter, data);
 345		break;
 346	case COUNTER_SCOPE_SIGNAL:
 347		err = a->comp.signal_u64_write(counter, a->parent, data);
 348		break;
 349	case COUNTER_SCOPE_COUNT:
 350		err = a->comp.count_u64_write(counter, a->parent, data);
 351		break;
 352	default:
 353		return -EINVAL;
 354	}
 355	if (err < 0)
 356		return err;
 357
 358	return len;
 359}
 360
 361static ssize_t counter_comp_array_u32_show(struct device *dev,
 362					   struct device_attribute *attr,
 363					   char *buf)
 364{
 365	const struct counter_attribute *const a = to_counter_attribute(attr);
 366	struct counter_device *const counter = counter_from_dev(dev);
 367	const struct counter_array *const element = a->comp.priv;
 368	int err;
 369	u32 data = 0;
 370
 371	if (a->scope != COUNTER_SCOPE_SIGNAL ||
 372	    element->type != COUNTER_COMP_SIGNAL_POLARITY)
 373		return -EINVAL;
 374
 375	err = a->comp.signal_array_u32_read(counter, a->parent, element->idx,
 376					    &data);
 377	if (err < 0)
 378		return err;
 379
 380	return sysfs_emit(buf, "%s\n", counter_signal_polarity_str[data]);
 381}
 382
 383static ssize_t counter_comp_array_u32_store(struct device *dev,
 384					    struct device_attribute *attr,
 385					    const char *buf, size_t len)
 386{
 387	const struct counter_attribute *const a = to_counter_attribute(attr);
 388	struct counter_device *const counter = counter_from_dev(dev);
 389	const struct counter_array *const element = a->comp.priv;
 390	int err;
 391	u32 data = 0;
 392
 393	if (element->type != COUNTER_COMP_SIGNAL_POLARITY ||
 394	    a->scope != COUNTER_SCOPE_SIGNAL)
 395		return -EINVAL;
 396
 397	err = counter_find_enum(&data, element->avail->enums,
 398				element->avail->num_items, buf,
 399				counter_signal_polarity_str);
 400	if (err < 0)
 401		return err;
 402
 403	err = a->comp.signal_array_u32_write(counter, a->parent, element->idx,
 404					     data);
 405	if (err < 0)
 406		return err;
 407
 408	return len;
 409}
 410
 411static ssize_t counter_comp_array_u64_show(struct device *dev,
 412					   struct device_attribute *attr,
 413					   char *buf)
 414{
 415	const struct counter_attribute *const a = to_counter_attribute(attr);
 416	struct counter_device *const counter = counter_from_dev(dev);
 417	const struct counter_array *const element = a->comp.priv;
 418	int err;
 419	u64 data = 0;
 420
 421	switch (a->scope) {
 422	case COUNTER_SCOPE_DEVICE:
 423		err = a->comp.device_array_u64_read(counter, element->idx,
 424						    &data);
 425		break;
 426	case COUNTER_SCOPE_SIGNAL:
 427		err = a->comp.signal_array_u64_read(counter, a->parent,
 428						    element->idx, &data);
 429		break;
 430	case COUNTER_SCOPE_COUNT:
 431		err = a->comp.count_array_u64_read(counter, a->parent,
 432						   element->idx, &data);
 433		break;
 434	default:
 435		return -EINVAL;
 436	}
 437	if (err < 0)
 438		return err;
 439
 440	return sysfs_emit(buf, "%llu\n", (unsigned long long)data);
 441}
 442
 443static ssize_t counter_comp_array_u64_store(struct device *dev,
 444					    struct device_attribute *attr,
 445					    const char *buf, size_t len)
 446{
 447	const struct counter_attribute *const a = to_counter_attribute(attr);
 448	struct counter_device *const counter = counter_from_dev(dev);
 449	const struct counter_array *const element = a->comp.priv;
 450	int err;
 451	u64 data = 0;
 452
 453	err = kstrtou64(buf, 0, &data);
 454	if (err < 0)
 455		return err;
 456
 457	switch (a->scope) {
 458	case COUNTER_SCOPE_DEVICE:
 459		err = a->comp.device_array_u64_write(counter, element->idx,
 460						     data);
 461		break;
 462	case COUNTER_SCOPE_SIGNAL:
 463		err = a->comp.signal_array_u64_write(counter, a->parent,
 464						     element->idx, data);
 465		break;
 466	case COUNTER_SCOPE_COUNT:
 467		err = a->comp.count_array_u64_write(counter, a->parent,
 468						    element->idx, data);
 469		break;
 470	default:
 471		return -EINVAL;
 472	}
 473	if (err < 0)
 474		return err;
 475
 476	return len;
 477}
 478
 479static ssize_t enums_available_show(const u32 *const enums,
 480				    const size_t num_enums,
 481				    const char *const strs[], char *buf)
 482{
 483	size_t len = 0;
 484	size_t index;
 485
 486	for (index = 0; index < num_enums; index++)
 487		len += sysfs_emit_at(buf, len, "%s\n", strs[enums[index]]);
 488
 489	return len;
 490}
 491
 492static ssize_t strs_available_show(const struct counter_available *const avail,
 493				   char *buf)
 494{
 495	size_t len = 0;
 496	size_t index;
 497
 498	for (index = 0; index < avail->num_items; index++)
 499		len += sysfs_emit_at(buf, len, "%s\n", avail->strs[index]);
 500
 501	return len;
 502}
 503
 504static ssize_t counter_comp_available_show(struct device *dev,
 505					   struct device_attribute *attr,
 506					   char *buf)
 507{
 508	const struct counter_attribute *const a = to_counter_attribute(attr);
 509	const struct counter_count *const count = a->parent;
 510	const struct counter_synapse *const synapse = a->comp.priv;
 511	const struct counter_available *const avail = a->comp.priv;
 512
 513	switch (a->comp.type) {
 514	case COUNTER_COMP_FUNCTION:
 515		return enums_available_show(count->functions_list,
 516					    count->num_functions,
 517					    counter_function_str, buf);
 518	case COUNTER_COMP_SYNAPSE_ACTION:
 519		return enums_available_show(synapse->actions_list,
 520					    synapse->num_actions,
 521					    counter_synapse_action_str, buf);
 522	case COUNTER_COMP_ENUM:
 523		return strs_available_show(avail, buf);
 524	case COUNTER_COMP_COUNT_MODE:
 525		return enums_available_show(avail->enums, avail->num_items,
 526					    counter_count_mode_str, buf);
 527	default:
 528		return -EINVAL;
 529	}
 530}
 531
 532static int counter_avail_attr_create(struct device *const dev,
 533	struct counter_attribute_group *const group,
 534	const struct counter_comp *const comp, void *const parent)
 535{
 536	struct counter_attribute *counter_attr;
 537	struct device_attribute *dev_attr;
 538
 539	counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
 540	if (!counter_attr)
 541		return -ENOMEM;
 542
 543	/* Configure Counter attribute */
 544	counter_attr->comp.type = comp->type;
 545	counter_attr->comp.priv = comp->priv;
 546	counter_attr->parent = parent;
 547
 548	/* Initialize sysfs attribute */
 549	dev_attr = &counter_attr->dev_attr;
 550	sysfs_attr_init(&dev_attr->attr);
 551
 552	/* Configure device attribute */
 553	dev_attr->attr.name = devm_kasprintf(dev, GFP_KERNEL, "%s_available",
 554					     comp->name);
 555	if (!dev_attr->attr.name)
 556		return -ENOMEM;
 557	dev_attr->attr.mode = 0444;
 558	dev_attr->show = counter_comp_available_show;
 559
 560	/* Store list node */
 561	list_add(&counter_attr->l, &group->attr_list);
 562	group->num_attr++;
 563
 564	return 0;
 565}
 566
 567static int counter_attr_create(struct device *const dev,
 568			       struct counter_attribute_group *const group,
 569			       const struct counter_comp *const comp,
 570			       const enum counter_scope scope,
 571			       void *const parent)
 572{
 573	const struct counter_array *const array = comp->priv;
 574	struct counter_attribute *counter_attr;
 575	struct device_attribute *dev_attr;
 576
 577	counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
 578	if (!counter_attr)
 579		return -ENOMEM;
 580
 581	/* Configure Counter attribute */
 582	counter_attr->comp = *comp;
 583	counter_attr->scope = scope;
 584	counter_attr->parent = parent;
 585
 586	/* Configure device attribute */
 587	dev_attr = &counter_attr->dev_attr;
 588	sysfs_attr_init(&dev_attr->attr);
 589	dev_attr->attr.name = comp->name;
 590	switch (comp->type) {
 591	case COUNTER_COMP_U8:
 592	case COUNTER_COMP_BOOL:
 593		if (comp->device_u8_read) {
 594			dev_attr->attr.mode |= 0444;
 595			dev_attr->show = counter_comp_u8_show;
 596		}
 597		if (comp->device_u8_write) {
 598			dev_attr->attr.mode |= 0200;
 599			dev_attr->store = counter_comp_u8_store;
 600		}
 601		break;
 602	case COUNTER_COMP_SIGNAL_LEVEL:
 603	case COUNTER_COMP_FUNCTION:
 604	case COUNTER_COMP_SYNAPSE_ACTION:
 605	case COUNTER_COMP_ENUM:
 606	case COUNTER_COMP_COUNT_DIRECTION:
 607	case COUNTER_COMP_COUNT_MODE:
 608	case COUNTER_COMP_SIGNAL_POLARITY:
 609		if (comp->device_u32_read) {
 610			dev_attr->attr.mode |= 0444;
 611			dev_attr->show = counter_comp_u32_show;
 612		}
 613		if (comp->device_u32_write) {
 614			dev_attr->attr.mode |= 0200;
 615			dev_attr->store = counter_comp_u32_store;
 616		}
 617		break;
 618	case COUNTER_COMP_U64:
 619		if (comp->device_u64_read) {
 620			dev_attr->attr.mode |= 0444;
 621			dev_attr->show = counter_comp_u64_show;
 622		}
 623		if (comp->device_u64_write) {
 624			dev_attr->attr.mode |= 0200;
 625			dev_attr->store = counter_comp_u64_store;
 626		}
 627		break;
 628	case COUNTER_COMP_ARRAY:
 629		switch (array->type) {
 630		case COUNTER_COMP_SIGNAL_POLARITY:
 631			if (comp->signal_array_u32_read) {
 632				dev_attr->attr.mode |= 0444;
 633				dev_attr->show = counter_comp_array_u32_show;
 634			}
 635			if (comp->signal_array_u32_write) {
 636				dev_attr->attr.mode |= 0200;
 637				dev_attr->store = counter_comp_array_u32_store;
 638			}
 639			break;
 640		case COUNTER_COMP_U64:
 641			if (comp->device_array_u64_read) {
 642				dev_attr->attr.mode |= 0444;
 643				dev_attr->show = counter_comp_array_u64_show;
 644			}
 645			if (comp->device_array_u64_write) {
 646				dev_attr->attr.mode |= 0200;
 647				dev_attr->store = counter_comp_array_u64_store;
 648			}
 649			break;
 650		default:
 651			return -EINVAL;
 652		}
 653		break;
 654	default:
 655		return -EINVAL;
 656	}
 657
 658	/* Store list node */
 659	list_add(&counter_attr->l, &group->attr_list);
 660	group->num_attr++;
 661
 662	/* Create "*_available" attribute if needed */
 663	switch (comp->type) {
 664	case COUNTER_COMP_FUNCTION:
 665	case COUNTER_COMP_SYNAPSE_ACTION:
 666	case COUNTER_COMP_ENUM:
 667	case COUNTER_COMP_COUNT_MODE:
 668		return counter_avail_attr_create(dev, group, comp, parent);
 669	default:
 670		return 0;
 671	}
 672}
 673
 674static ssize_t counter_comp_name_show(struct device *dev,
 675				      struct device_attribute *attr, char *buf)
 676{
 677	return sysfs_emit(buf, "%s\n", to_counter_attribute(attr)->comp.name);
 678}
 679
 680static int counter_name_attr_create(struct device *const dev,
 681				    struct counter_attribute_group *const group,
 682				    const char *const name)
 683{
 684	struct counter_attribute *counter_attr;
 685
 686	counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
 687	if (!counter_attr)
 688		return -ENOMEM;
 689
 690	/* Configure Counter attribute */
 691	counter_attr->comp.name = name;
 692
 693	/* Configure device attribute */
 694	sysfs_attr_init(&counter_attr->dev_attr.attr);
 695	counter_attr->dev_attr.attr.name = "name";
 696	counter_attr->dev_attr.attr.mode = 0444;
 697	counter_attr->dev_attr.show = counter_comp_name_show;
 698
 699	/* Store list node */
 700	list_add(&counter_attr->l, &group->attr_list);
 701	group->num_attr++;
 702
 703	return 0;
 704}
 705
 706static ssize_t counter_comp_id_show(struct device *dev,
 707				    struct device_attribute *attr, char *buf)
 708{
 709	const size_t id = (size_t)to_counter_attribute(attr)->comp.priv;
 710
 711	return sysfs_emit(buf, "%zu\n", id);
 712}
 713
 714static int counter_comp_id_attr_create(struct device *const dev,
 715				       struct counter_attribute_group *const group,
 716				       const char *name, const size_t id)
 717{
 718	struct counter_attribute *counter_attr;
 719
 720	/* Allocate Counter attribute */
 721	counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
 722	if (!counter_attr)
 723		return -ENOMEM;
 724
 725	/* Generate component ID name */
 726	name = devm_kasprintf(dev, GFP_KERNEL, "%s_component_id", name);
 727	if (!name)
 728		return -ENOMEM;
 729
 730	/* Configure Counter attribute */
 731	counter_attr->comp.priv = (void *)id;
 732
 733	/* Configure device attribute */
 734	sysfs_attr_init(&counter_attr->dev_attr.attr);
 735	counter_attr->dev_attr.attr.name = name;
 736	counter_attr->dev_attr.attr.mode = 0444;
 737	counter_attr->dev_attr.show = counter_comp_id_show;
 738
 739	/* Store list node */
 740	list_add(&counter_attr->l, &group->attr_list);
 741	group->num_attr++;
 742
 743	return 0;
 744}
 745
 746static int counter_ext_attrs_create(struct device *const dev,
 747				    struct counter_attribute_group *const group,
 748				    const struct counter_comp *const ext,
 749				    const enum counter_scope scope,
 750				    void *const parent, const size_t id)
 751{
 752	int err;
 753
 754	/* Create main extension attribute */
 755	err = counter_attr_create(dev, group, ext, scope, parent);
 756	if (err < 0)
 757		return err;
 758
 759	/* Create extension id attribute */
 760	return counter_comp_id_attr_create(dev, group, ext->name, id);
 761}
 762
 763static int counter_array_attrs_create(struct device *const dev,
 764				      struct counter_attribute_group *const group,
 765				      const struct counter_comp *const comp,
 766				      const enum counter_scope scope,
 767				      void *const parent, const size_t id)
 768{
 769	const struct counter_array *const array = comp->priv;
 770	struct counter_comp ext = *comp;
 771	struct counter_array *element;
 772	size_t idx;
 773	int err;
 774
 775	/* Create an attribute for each array element */
 776	for (idx = 0; idx < array->length; idx++) {
 777		/* Generate array element attribute name */
 778		ext.name = devm_kasprintf(dev, GFP_KERNEL, "%s%zu", comp->name,
 779					  idx);
 780		if (!ext.name)
 781			return -ENOMEM;
 782
 783		/* Allocate and configure array element */
 784		element = devm_kzalloc(dev, sizeof(*element), GFP_KERNEL);
 785		if (!element)
 786			return -ENOMEM;
 787		element->type = array->type;
 788		element->avail = array->avail;
 789		element->idx = idx;
 790		ext.priv = element;
 791
 792		/* Create all attributes associated with the array element */
 793		err = counter_ext_attrs_create(dev, group, &ext, scope, parent,
 794					       id + idx);
 795		if (err < 0)
 796			return err;
 797	}
 798
 799	return 0;
 800}
 801
 802static int counter_sysfs_exts_add(struct device *const dev,
 803				  struct counter_attribute_group *const group,
 804				  const struct counter_comp *const exts,
 805				  const size_t num_ext,
 806				  const enum counter_scope scope,
 807				  void *const parent)
 808{
 809	size_t i;
 810	const struct counter_comp *ext;
 811	int err;
 812	size_t id = 0;
 813	const struct counter_array *array;
 814
 815	/* Create attributes for each extension */
 816	for (i = 0; i < num_ext; i++) {
 817		ext = &exts[i];
 818		if (ext->type == COUNTER_COMP_ARRAY) {
 819			err = counter_array_attrs_create(dev, group, ext, scope,
 820							 parent, id);
 821			array = ext->priv;
 822			id += array->length;
 823		} else {
 824			err = counter_ext_attrs_create(dev, group, ext, scope,
 825						       parent, id);
 826			id++;
 827		}
 828		if (err < 0)
 829			return err;
 830	}
 831
 832	return 0;
 833}
 834
 835static struct counter_comp counter_signal_comp = {
 836	.type = COUNTER_COMP_SIGNAL_LEVEL,
 837	.name = "signal",
 838};
 839
 840static int counter_signal_attrs_create(struct counter_device *const counter,
 841	struct counter_attribute_group *const cattr_group,
 842	struct counter_signal *const signal)
 843{
 844	const enum counter_scope scope = COUNTER_SCOPE_SIGNAL;
 845	struct device *const dev = &counter->dev;
 846	int err;
 847	struct counter_comp comp;
 848
 849	/* Create main Signal attribute */
 850	comp = counter_signal_comp;
 851	comp.signal_u32_read = counter->ops->signal_read;
 852	err = counter_attr_create(dev, cattr_group, &comp, scope, signal);
 853	if (err < 0)
 854		return err;
 855
 856	/* Create Signal name attribute */
 857	err = counter_name_attr_create(dev, cattr_group, signal->name);
 858	if (err < 0)
 859		return err;
 860
 861	/* Add Signal extensions */
 862	return counter_sysfs_exts_add(dev, cattr_group, signal->ext,
 863				      signal->num_ext, scope, signal);
 864}
 865
 866static int counter_sysfs_signals_add(struct counter_device *const counter,
 867	struct counter_attribute_group *const groups)
 868{
 869	size_t i;
 870	int err;
 871
 872	/* Add each Signal */
 873	for (i = 0; i < counter->num_signals; i++) {
 874		/* Generate Signal attribute directory name */
 875		groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL,
 876						"signal%zu", i);
 877		if (!groups[i].name)
 878			return -ENOMEM;
 879
 880		/* Create all attributes associated with Signal */
 881		err = counter_signal_attrs_create(counter, groups + i,
 882						  counter->signals + i);
 883		if (err < 0)
 884			return err;
 885	}
 886
 887	return 0;
 888}
 889
 890static int counter_sysfs_synapses_add(struct counter_device *const counter,
 891	struct counter_attribute_group *const group,
 892	struct counter_count *const count)
 893{
 894	size_t i;
 895
 896	/* Add each Synapse */
 897	for (i = 0; i < count->num_synapses; i++) {
 898		struct device *const dev = &counter->dev;
 899		struct counter_synapse *synapse;
 900		size_t id;
 901		struct counter_comp comp;
 902		int err;
 903
 904		synapse = count->synapses + i;
 905
 906		/* Generate Synapse action name */
 907		id = synapse->signal - counter->signals;
 908		comp.name = devm_kasprintf(dev, GFP_KERNEL, "signal%zu_action",
 909					   id);
 910		if (!comp.name)
 911			return -ENOMEM;
 912
 913		/* Create action attribute */
 914		comp.type = COUNTER_COMP_SYNAPSE_ACTION;
 915		comp.action_read = counter->ops->action_read;
 916		comp.action_write = counter->ops->action_write;
 917		comp.priv = synapse;
 918		err = counter_attr_create(dev, group, &comp,
 919					  COUNTER_SCOPE_COUNT, count);
 920		if (err < 0)
 921			return err;
 922
 923		/* Create Synapse component ID attribute */
 924		err = counter_comp_id_attr_create(dev, group, comp.name, i);
 925		if (err < 0)
 926			return err;
 927	}
 928
 929	return 0;
 930}
 931
 932static struct counter_comp counter_count_comp =
 933	COUNTER_COMP_COUNT_U64("count", NULL, NULL);
 934
 935static struct counter_comp counter_function_comp = {
 936	.type = COUNTER_COMP_FUNCTION,
 937	.name = "function",
 938};
 939
 940static int counter_count_attrs_create(struct counter_device *const counter,
 941	struct counter_attribute_group *const cattr_group,
 942	struct counter_count *const count)
 943{
 944	const enum counter_scope scope = COUNTER_SCOPE_COUNT;
 945	struct device *const dev = &counter->dev;
 946	int err;
 947	struct counter_comp comp;
 948
 949	/* Create main Count attribute */
 950	comp = counter_count_comp;
 951	comp.count_u64_read = counter->ops->count_read;
 952	comp.count_u64_write = counter->ops->count_write;
 953	err = counter_attr_create(dev, cattr_group, &comp, scope, count);
 954	if (err < 0)
 955		return err;
 956
 957	/* Create Count name attribute */
 958	err = counter_name_attr_create(dev, cattr_group, count->name);
 959	if (err < 0)
 960		return err;
 961
 962	/* Create Count function attribute */
 963	comp = counter_function_comp;
 964	comp.count_u32_read = counter->ops->function_read;
 965	comp.count_u32_write = counter->ops->function_write;
 966	err = counter_attr_create(dev, cattr_group, &comp, scope, count);
 967	if (err < 0)
 968		return err;
 969
 970	/* Add Count extensions */
 971	return counter_sysfs_exts_add(dev, cattr_group, count->ext,
 972				      count->num_ext, scope, count);
 973}
 974
 975static int counter_sysfs_counts_add(struct counter_device *const counter,
 976	struct counter_attribute_group *const groups)
 977{
 978	size_t i;
 979	struct counter_count *count;
 980	int err;
 981
 982	/* Add each Count */
 983	for (i = 0; i < counter->num_counts; i++) {
 984		count = counter->counts + i;
 985
 986		/* Generate Count attribute directory name */
 987		groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL,
 988						"count%zu", i);
 989		if (!groups[i].name)
 990			return -ENOMEM;
 991
 992		/* Add sysfs attributes of the Synapses */
 993		err = counter_sysfs_synapses_add(counter, groups + i, count);
 994		if (err < 0)
 995			return err;
 996
 997		/* Create all attributes associated with Count */
 998		err = counter_count_attrs_create(counter, groups + i, count);
 999		if (err < 0)
1000			return err;
1001	}
1002
1003	return 0;
1004}
1005
1006static int counter_num_signals_read(struct counter_device *counter, u8 *val)
1007{
1008	*val = counter->num_signals;
1009	return 0;
1010}
1011
1012static int counter_num_counts_read(struct counter_device *counter, u8 *val)
1013{
1014	*val = counter->num_counts;
1015	return 0;
1016}
1017
1018static int counter_events_queue_size_read(struct counter_device *counter,
1019					  u64 *val)
1020{
1021	*val = kfifo_size(&counter->events);
1022	return 0;
1023}
1024
1025static int counter_events_queue_size_write(struct counter_device *counter,
1026					   u64 val)
1027{
1028	DECLARE_KFIFO_PTR(events, struct counter_event);
1029	int err;
1030	unsigned long flags;
1031
1032	/* Allocate new events queue */
1033	err = kfifo_alloc(&events, val, GFP_KERNEL);
1034	if (err)
1035		return err;
1036
1037	/* Swap in new events queue */
1038	mutex_lock(&counter->events_out_lock);
1039	spin_lock_irqsave(&counter->events_in_lock, flags);
1040	kfifo_free(&counter->events);
1041	counter->events.kfifo = events.kfifo;
1042	spin_unlock_irqrestore(&counter->events_in_lock, flags);
1043	mutex_unlock(&counter->events_out_lock);
1044
1045	return 0;
1046}
1047
1048static struct counter_comp counter_num_signals_comp =
1049	COUNTER_COMP_DEVICE_U8("num_signals", counter_num_signals_read, NULL);
1050
1051static struct counter_comp counter_num_counts_comp =
1052	COUNTER_COMP_DEVICE_U8("num_counts", counter_num_counts_read, NULL);
1053
1054static struct counter_comp counter_events_queue_size_comp =
1055	COUNTER_COMP_DEVICE_U64("events_queue_size",
1056				counter_events_queue_size_read,
1057				counter_events_queue_size_write);
1058
1059static int counter_sysfs_attr_add(struct counter_device *const counter,
1060				  struct counter_attribute_group *cattr_group)
1061{
1062	const enum counter_scope scope = COUNTER_SCOPE_DEVICE;
1063	struct device *const dev = &counter->dev;
1064	int err;
1065
1066	/* Add Signals sysfs attributes */
1067	err = counter_sysfs_signals_add(counter, cattr_group);
1068	if (err < 0)
1069		return err;
1070	cattr_group += counter->num_signals;
1071
1072	/* Add Counts sysfs attributes */
1073	err = counter_sysfs_counts_add(counter, cattr_group);
1074	if (err < 0)
1075		return err;
1076	cattr_group += counter->num_counts;
1077
1078	/* Create name attribute */
1079	err = counter_name_attr_create(dev, cattr_group, counter->name);
1080	if (err < 0)
1081		return err;
1082
1083	/* Create num_signals attribute */
1084	err = counter_attr_create(dev, cattr_group, &counter_num_signals_comp,
1085				  scope, NULL);
1086	if (err < 0)
1087		return err;
1088
1089	/* Create num_counts attribute */
1090	err = counter_attr_create(dev, cattr_group, &counter_num_counts_comp,
1091				  scope, NULL);
1092	if (err < 0)
1093		return err;
1094
1095	/* Create events_queue_size attribute */
1096	err = counter_attr_create(dev, cattr_group,
1097				  &counter_events_queue_size_comp, scope, NULL);
1098	if (err < 0)
1099		return err;
1100
1101	/* Add device extensions */
1102	return counter_sysfs_exts_add(dev, cattr_group, counter->ext,
1103				      counter->num_ext, scope, NULL);
1104
1105	return 0;
1106}
1107
1108/**
1109 * counter_sysfs_add - Adds Counter sysfs attributes to the device structure
1110 * @counter:	Pointer to the Counter device structure
1111 *
1112 * Counter sysfs attributes are created and added to the respective device
1113 * structure for later registration to the system. Resource-managed memory
1114 * allocation is performed by this function, and this memory should be freed
1115 * when no longer needed (automatically by a device_unregister call, or
1116 * manually by a devres_release_all call).
1117 */
1118int counter_sysfs_add(struct counter_device *const counter)
1119{
1120	struct device *const dev = &counter->dev;
1121	const size_t num_groups = counter->num_signals + counter->num_counts + 1;
1122	struct counter_attribute_group *cattr_groups;
1123	size_t i, j;
1124	int err;
1125	struct attribute_group *groups;
1126	struct counter_attribute *p;
1127
1128	/* Allocate space for attribute groups (signals, counts, and ext) */
1129	cattr_groups = devm_kcalloc(dev, num_groups, sizeof(*cattr_groups),
1130				    GFP_KERNEL);
1131	if (!cattr_groups)
1132		return -ENOMEM;
1133
1134	/* Initialize attribute lists */
1135	for (i = 0; i < num_groups; i++)
1136		INIT_LIST_HEAD(&cattr_groups[i].attr_list);
1137
1138	/* Add Counter device sysfs attributes */
1139	err = counter_sysfs_attr_add(counter, cattr_groups);
1140	if (err < 0)
1141		return err;
1142
1143	/* Allocate attribute group pointers for association with device */
1144	dev->groups = devm_kcalloc(dev, num_groups + 1, sizeof(*dev->groups),
1145				   GFP_KERNEL);
1146	if (!dev->groups)
1147		return -ENOMEM;
1148
1149	/* Allocate space for attribute groups */
1150	groups = devm_kcalloc(dev, num_groups, sizeof(*groups), GFP_KERNEL);
1151	if (!groups)
1152		return -ENOMEM;
1153
1154	/* Prepare each group of attributes for association */
1155	for (i = 0; i < num_groups; i++) {
1156		groups[i].name = cattr_groups[i].name;
1157
1158		/* Allocate space for attribute pointers */
1159		groups[i].attrs = devm_kcalloc(dev,
1160					       cattr_groups[i].num_attr + 1,
1161					       sizeof(*groups[i].attrs),
1162					       GFP_KERNEL);
1163		if (!groups[i].attrs)
1164			return -ENOMEM;
1165
1166		/* Add attribute pointers to attribute group */
1167		j = 0;
1168		list_for_each_entry(p, &cattr_groups[i].attr_list, l)
1169			groups[i].attrs[j++] = &p->dev_attr.attr;
1170
1171		/* Associate attribute group */
1172		dev->groups[i] = &groups[i];
1173	}
1174
1175	return 0;
1176}