root/drivers/counter/counter.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. counter_signal_enum_read
  2. counter_signal_enum_write
  3. counter_signal_enum_available_read
  4. counter_count_enum_read
  5. counter_count_enum_write
  6. counter_count_enum_available_read
  7. counter_device_enum_read
  8. counter_device_enum_write
  9. counter_device_enum_available_read
  10. counter_signal_read_value_set
  11. counter_count_read_value_set
  12. counter_count_write_value_get
  13. counter_attribute_create
  14. counter_signal_show
  15. counter_device_attr_name_show
  16. counter_name_attribute_create
  17. counter_signal_ext_show
  18. counter_signal_ext_store
  19. counter_device_attr_list_free
  20. counter_signal_ext_register
  21. counter_signal_attributes_create
  22. counter_signals_register
  23. counter_action_show
  24. counter_action_store
  25. counter_synapse_action_available_show
  26. counter_synapses_register
  27. counter_count_show
  28. counter_count_store
  29. counter_function_show
  30. counter_function_store
  31. counter_count_ext_show
  32. counter_count_ext_store
  33. counter_count_ext_register
  34. counter_count_function_available_show
  35. counter_count_attributes_create
  36. counter_counts_register
  37. counter_device_attr_size_show
  38. counter_size_attribute_create
  39. counter_device_ext_show
  40. counter_device_ext_store
  41. counter_device_ext_register
  42. counter_global_attr_register
  43. counter_device_groups_list_free
  44. counter_device_groups_list_prepare
  45. counter_device_groups_prepare
  46. counter_device_release
  47. counter_register
  48. counter_unregister
  49. devm_counter_unreg
  50. devm_counter_register
  51. devm_counter_match
  52. devm_counter_unregister
  53. counter_init
  54. counter_exit

   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");

/* [<][>][^][v][top][bottom][index][help] */