Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

counter: Introduce the Generic Counter interface

This patch introduces the Generic Counter interface for supporting
counter devices.

In the context of the Generic Counter interface, a counter is defined as
a device that reports one or more "counts" based on the state changes of
one or more "signals" as evaluated by a defined "count function."

Driver callbacks should be provided to communicate with the device: to
read and write various Signals and Counts, and to set and get the
"action mode" and "count function" for various Synapses and Counts
respectively.

To support a counter device, a driver must first allocate the available
Counter Signals via counter_signal structures. These Signals should
be stored as an array and set to the signals array member of an
allocated counter_device structure before the Counter is registered to
the system.

Counter Counts may be allocated via counter_count structures, and
respective Counter Signal associations (Synapses) made via
counter_synapse structures. Associated counter_synapse structures are
stored as an array and set to the the synapses array member of the
respective counter_count structure. These counter_count structures are
set to the counts array member of an allocated counter_device structure
before the Counter is registered to the system.

A counter device is registered to the system by passing the respective
initialized counter_device structure to the counter_register function;
similarly, the counter_unregister function unregisters the respective
Counter. The devm_counter_register and devm_counter_unregister functions
serve as device memory-managed versions of the counter_register and
counter_unregister functions respectively.

Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

William Breathitt Gray and committed by
Greg Kroah-Hartman
0040a390 7df95299

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