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