linux/drivers/counter/counter.c
<<
>>
Prefs
   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_level_str[] = {
 293        [COUNTER_SIGNAL_LEVEL_LOW] = "low",
 294        [COUNTER_SIGNAL_LEVEL_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_level level;
 306
 307        err = counter->ops->signal_read(counter, signal, &level);
 308        if (err)
 309                return err;
 310
 311        return sprintf(buf, "%s\n", counter_signal_level_str[level]);
 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_function_str[] = {
 748        [COUNTER_FUNCTION_INCREASE] = "increase",
 749        [COUNTER_FUNCTION_DECREASE] = "decrease",
 750        [COUNTER_FUNCTION_PULSE_DIRECTION] = "pulse-direction",
 751        [COUNTER_FUNCTION_QUADRATURE_X1_A] = "quadrature x1 a",
 752        [COUNTER_FUNCTION_QUADRATURE_X1_B] = "quadrature x1 b",
 753        [COUNTER_FUNCTION_QUADRATURE_X2_A] = "quadrature x2 a",
 754        [COUNTER_FUNCTION_QUADRATURE_X2_B] = "quadrature x2 b",
 755        [COUNTER_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_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_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_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_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_function *functions_list;
 884        size_t num_functions;
 885};
 886
 887static ssize_t counter_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_function *const func_list = component->functions_list;
 893        const size_t num_functions = component->num_functions;
 894        size_t i;
 895        enum counter_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_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_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");
1497