linux/drivers/misc/enclosure.c
<<
>>
Prefs
   1/*
   2 * Enclosure Services
   3 *
   4 * Copyright (C) 2008 James Bottomley <James.Bottomley@HansenPartnership.com>
   5 *
   6**-----------------------------------------------------------------------------
   7**
   8**  This program is free software; you can redistribute it and/or
   9**  modify it under the terms of the GNU General Public License
  10**  version 2 as published by the Free Software Foundation.
  11**
  12**  This program is distributed in the hope that it will be useful,
  13**  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15**  GNU General Public License for more details.
  16**
  17**  You should have received a copy of the GNU General Public License
  18**  along with this program; if not, write to the Free Software
  19**  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20**
  21**-----------------------------------------------------------------------------
  22*/
  23#include <linux/device.h>
  24#include <linux/enclosure.h>
  25#include <linux/err.h>
  26#include <linux/list.h>
  27#include <linux/kernel.h>
  28#include <linux/module.h>
  29#include <linux/mutex.h>
  30#include <linux/slab.h>
  31
  32static LIST_HEAD(container_list);
  33static DEFINE_MUTEX(container_list_lock);
  34static struct class enclosure_class;
  35
  36/**
  37 * enclosure_find - find an enclosure given a parent device
  38 * @dev:        the parent to match against
  39 * @start:      Optional enclosure device to start from (NULL if none)
  40 *
  41 * Looks through the list of registered enclosures to find all those
  42 * with @dev as a parent.  Returns NULL if no enclosure is
  43 * found. @start can be used as a starting point to obtain multiple
  44 * enclosures per parent (should begin with NULL and then be set to
  45 * each returned enclosure device). Obtains a reference to the
  46 * enclosure class device which must be released with device_put().
  47 * If @start is not NULL, a reference must be taken on it which is
  48 * released before returning (this allows a loop through all
  49 * enclosures to exit with only the reference on the enclosure of
  50 * interest held).  Note that the @dev may correspond to the actual
  51 * device housing the enclosure, in which case no iteration via @start
  52 * is required.
  53 */
  54struct enclosure_device *enclosure_find(struct device *dev,
  55                                        struct enclosure_device *start)
  56{
  57        struct enclosure_device *edev;
  58
  59        mutex_lock(&container_list_lock);
  60        edev = list_prepare_entry(start, &container_list, node);
  61        if (start)
  62                put_device(&start->edev);
  63
  64        list_for_each_entry_continue(edev, &container_list, node) {
  65                struct device *parent = edev->edev.parent;
  66                /* parent might not be immediate, so iterate up to
  67                 * the root of the tree if necessary */
  68                while (parent) {
  69                        if (parent == dev) {
  70                                get_device(&edev->edev);
  71                                mutex_unlock(&container_list_lock);
  72                                return edev;
  73                        }
  74                        parent = parent->parent;
  75                }
  76        }
  77        mutex_unlock(&container_list_lock);
  78
  79        return NULL;
  80}
  81EXPORT_SYMBOL_GPL(enclosure_find);
  82
  83/**
  84 * enclosure_for_each_device - calls a function for each enclosure
  85 * @fn:         the function to call
  86 * @data:       the data to pass to each call
  87 *
  88 * Loops over all the enclosures calling the function.
  89 *
  90 * Note, this function uses a mutex which will be held across calls to
  91 * @fn, so it must have non atomic context, and @fn may (although it
  92 * should not) sleep or otherwise cause the mutex to be held for
  93 * indefinite periods
  94 */
  95int enclosure_for_each_device(int (*fn)(struct enclosure_device *, void *),
  96                              void *data)
  97{
  98        int error = 0;
  99        struct enclosure_device *edev;
 100
 101        mutex_lock(&container_list_lock);
 102        list_for_each_entry(edev, &container_list, node) {
 103                error = fn(edev, data);
 104                if (error)
 105                        break;
 106        }
 107        mutex_unlock(&container_list_lock);
 108
 109        return error;
 110}
 111EXPORT_SYMBOL_GPL(enclosure_for_each_device);
 112
 113/**
 114 * enclosure_register - register device as an enclosure
 115 *
 116 * @dev:        device containing the enclosure
 117 * @components: number of components in the enclosure
 118 *
 119 * This sets up the device for being an enclosure.  Note that @dev does
 120 * not have to be a dedicated enclosure device.  It may be some other type
 121 * of device that additionally responds to enclosure services
 122 */
 123struct enclosure_device *
 124enclosure_register(struct device *dev, const char *name, int components,
 125                   struct enclosure_component_callbacks *cb)
 126{
 127        struct enclosure_device *edev =
 128                kzalloc(sizeof(struct enclosure_device) +
 129                        sizeof(struct enclosure_component)*components,
 130                        GFP_KERNEL);
 131        int err, i;
 132
 133        BUG_ON(!cb);
 134
 135        if (!edev)
 136                return ERR_PTR(-ENOMEM);
 137
 138        edev->components = components;
 139
 140        edev->edev.class = &enclosure_class;
 141        edev->edev.parent = get_device(dev);
 142        edev->cb = cb;
 143        dev_set_name(&edev->edev, "%s", name);
 144        err = device_register(&edev->edev);
 145        if (err)
 146                goto err;
 147
 148        for (i = 0; i < components; i++) {
 149                edev->component[i].number = -1;
 150                edev->component[i].slot = -1;
 151                edev->component[i].power_status = 1;
 152        }
 153
 154        mutex_lock(&container_list_lock);
 155        list_add_tail(&edev->node, &container_list);
 156        mutex_unlock(&container_list_lock);
 157
 158        return edev;
 159
 160 err:
 161        put_device(edev->edev.parent);
 162        kfree(edev);
 163        return ERR_PTR(err);
 164}
 165EXPORT_SYMBOL_GPL(enclosure_register);
 166
 167static struct enclosure_component_callbacks enclosure_null_callbacks;
 168
 169/**
 170 * enclosure_unregister - remove an enclosure
 171 *
 172 * @edev:       the registered enclosure to remove;
 173 */
 174void enclosure_unregister(struct enclosure_device *edev)
 175{
 176        int i;
 177
 178        mutex_lock(&container_list_lock);
 179        list_del(&edev->node);
 180        mutex_unlock(&container_list_lock);
 181
 182        for (i = 0; i < edev->components; i++)
 183                if (edev->component[i].number != -1)
 184                        device_unregister(&edev->component[i].cdev);
 185
 186        /* prevent any callbacks into service user */
 187        edev->cb = &enclosure_null_callbacks;
 188        device_unregister(&edev->edev);
 189}
 190EXPORT_SYMBOL_GPL(enclosure_unregister);
 191
 192#define ENCLOSURE_NAME_SIZE     64
 193#define COMPONENT_NAME_SIZE     64
 194
 195static void enclosure_link_name(struct enclosure_component *cdev, char *name)
 196{
 197        strcpy(name, "enclosure_device:");
 198        strcat(name, dev_name(&cdev->cdev));
 199}
 200
 201static void enclosure_remove_links(struct enclosure_component *cdev)
 202{
 203        char name[ENCLOSURE_NAME_SIZE];
 204
 205        enclosure_link_name(cdev, name);
 206
 207        /*
 208         * In odd circumstances, like multipath devices, something else may
 209         * already have removed the links, so check for this condition first.
 210         */
 211        if (cdev->dev->kobj.sd)
 212                sysfs_remove_link(&cdev->dev->kobj, name);
 213
 214        if (cdev->cdev.kobj.sd)
 215                sysfs_remove_link(&cdev->cdev.kobj, "device");
 216}
 217
 218static int enclosure_add_links(struct enclosure_component *cdev)
 219{
 220        int error;
 221        char name[ENCLOSURE_NAME_SIZE];
 222
 223        error = sysfs_create_link(&cdev->cdev.kobj, &cdev->dev->kobj, "device");
 224        if (error)
 225                return error;
 226
 227        enclosure_link_name(cdev, name);
 228        error = sysfs_create_link(&cdev->dev->kobj, &cdev->cdev.kobj, name);
 229        if (error)
 230                sysfs_remove_link(&cdev->cdev.kobj, "device");
 231
 232        return error;
 233}
 234
 235static void enclosure_release(struct device *cdev)
 236{
 237        struct enclosure_device *edev = to_enclosure_device(cdev);
 238
 239        put_device(cdev->parent);
 240        kfree(edev);
 241}
 242
 243static void enclosure_component_release(struct device *dev)
 244{
 245        struct enclosure_component *cdev = to_enclosure_component(dev);
 246
 247        if (cdev->dev) {
 248                enclosure_remove_links(cdev);
 249                put_device(cdev->dev);
 250        }
 251        put_device(dev->parent);
 252}
 253
 254static struct enclosure_component *
 255enclosure_component_find_by_name(struct enclosure_device *edev,
 256                                const char *name)
 257{
 258        int i;
 259        const char *cname;
 260        struct enclosure_component *ecomp;
 261
 262        if (!edev || !name || !name[0])
 263                return NULL;
 264
 265        for (i = 0; i < edev->components; i++) {
 266                ecomp = &edev->component[i];
 267                cname = dev_name(&ecomp->cdev);
 268                if (ecomp->number != -1 &&
 269                    cname && cname[0] &&
 270                    !strcmp(cname, name))
 271                        return ecomp;
 272        }
 273
 274        return NULL;
 275}
 276
 277static const struct attribute_group *enclosure_component_groups[];
 278
 279/**
 280 * enclosure_component_alloc - prepare a new enclosure component
 281 * @edev:       the enclosure to add the component
 282 * @num:        the device number
 283 * @type:       the type of component being added
 284 * @name:       an optional name to appear in sysfs (leave NULL if none)
 285 *
 286 * The name is optional for enclosures that give their components a unique
 287 * name.  If not, leave the field NULL and a name will be assigned.
 288 *
 289 * Returns a pointer to the enclosure component or an error.
 290 */
 291struct enclosure_component *
 292enclosure_component_alloc(struct enclosure_device *edev,
 293                          unsigned int number,
 294                          enum enclosure_component_type type,
 295                          const char *name)
 296{
 297        struct enclosure_component *ecomp;
 298        struct device *cdev;
 299        int i;
 300        char newname[COMPONENT_NAME_SIZE];
 301
 302        if (number >= edev->components)
 303                return ERR_PTR(-EINVAL);
 304
 305        ecomp = &edev->component[number];
 306
 307        if (ecomp->number != -1)
 308                return ERR_PTR(-EINVAL);
 309
 310        ecomp->type = type;
 311        ecomp->number = number;
 312        cdev = &ecomp->cdev;
 313        cdev->parent = get_device(&edev->edev);
 314
 315        if (name && name[0]) {
 316                /* Some hardware (e.g. enclosure in RX300 S6) has components
 317                 * with non unique names. Registering duplicates in sysfs
 318                 * will lead to warnings during bootup. So make the names
 319                 * unique by appending consecutive numbers -1, -2, ... */
 320                i = 1;
 321                snprintf(newname, COMPONENT_NAME_SIZE,
 322                         "%s", name);
 323                while (enclosure_component_find_by_name(edev, newname))
 324                        snprintf(newname, COMPONENT_NAME_SIZE,
 325                                 "%s-%i", name, i++);
 326                dev_set_name(cdev, "%s", newname);
 327        } else
 328                dev_set_name(cdev, "%u", number);
 329
 330        cdev->release = enclosure_component_release;
 331        cdev->groups = enclosure_component_groups;
 332
 333        return ecomp;
 334}
 335EXPORT_SYMBOL_GPL(enclosure_component_alloc);
 336
 337/**
 338 * enclosure_component_register - publishes an initialized enclosure component
 339 * @ecomp:      component to add
 340 *
 341 * Returns 0 on successful registration, releases the component otherwise
 342 */
 343int enclosure_component_register(struct enclosure_component *ecomp)
 344{
 345        struct device *cdev;
 346        int err;
 347
 348        cdev = &ecomp->cdev;
 349        err = device_register(cdev);
 350        if (err) {
 351                ecomp->number = -1;
 352                put_device(cdev);
 353                return err;
 354        }
 355
 356        return 0;
 357}
 358EXPORT_SYMBOL_GPL(enclosure_component_register);
 359
 360/**
 361 * enclosure_add_device - add a device as being part of an enclosure
 362 * @edev:       the enclosure device being added to.
 363 * @num:        the number of the component
 364 * @dev:        the device being added
 365 *
 366 * Declares a real device to reside in slot (or identifier) @num of an
 367 * enclosure.  This will cause the relevant sysfs links to appear.
 368 * This function may also be used to change a device associated with
 369 * an enclosure without having to call enclosure_remove_device() in
 370 * between.
 371 *
 372 * Returns zero on success or an error.
 373 */
 374int enclosure_add_device(struct enclosure_device *edev, int component,
 375                         struct device *dev)
 376{
 377        struct enclosure_component *cdev;
 378
 379        if (!edev || component >= edev->components)
 380                return -EINVAL;
 381
 382        cdev = &edev->component[component];
 383
 384        if (cdev->dev == dev)
 385                return -EEXIST;
 386
 387        if (cdev->dev)
 388                enclosure_remove_links(cdev);
 389
 390        put_device(cdev->dev);
 391        cdev->dev = get_device(dev);
 392        return enclosure_add_links(cdev);
 393}
 394EXPORT_SYMBOL_GPL(enclosure_add_device);
 395
 396/**
 397 * enclosure_remove_device - remove a device from an enclosure
 398 * @edev:       the enclosure device
 399 * @num:        the number of the component to remove
 400 *
 401 * Returns zero on success or an error.
 402 *
 403 */
 404int enclosure_remove_device(struct enclosure_device *edev, struct device *dev)
 405{
 406        struct enclosure_component *cdev;
 407        int i;
 408
 409        if (!edev || !dev)
 410                return -EINVAL;
 411
 412        for (i = 0; i < edev->components; i++) {
 413                cdev = &edev->component[i];
 414                if (cdev->dev == dev) {
 415                        enclosure_remove_links(cdev);
 416                        device_del(&cdev->cdev);
 417                        put_device(dev);
 418                        cdev->dev = NULL;
 419                        return device_add(&cdev->cdev);
 420                }
 421        }
 422        return -ENODEV;
 423}
 424EXPORT_SYMBOL_GPL(enclosure_remove_device);
 425
 426/*
 427 * sysfs pieces below
 428 */
 429
 430static ssize_t components_show(struct device *cdev,
 431                               struct device_attribute *attr, char *buf)
 432{
 433        struct enclosure_device *edev = to_enclosure_device(cdev);
 434
 435        return snprintf(buf, 40, "%d\n", edev->components);
 436}
 437static DEVICE_ATTR_RO(components);
 438
 439static ssize_t id_show(struct device *cdev,
 440                                 struct device_attribute *attr,
 441                                 char *buf)
 442{
 443        struct enclosure_device *edev = to_enclosure_device(cdev);
 444
 445        if (edev->cb->show_id)
 446                return edev->cb->show_id(edev, buf);
 447        return -EINVAL;
 448}
 449static DEVICE_ATTR_RO(id);
 450
 451static struct attribute *enclosure_class_attrs[] = {
 452        &dev_attr_components.attr,
 453        &dev_attr_id.attr,
 454        NULL,
 455};
 456ATTRIBUTE_GROUPS(enclosure_class);
 457
 458static struct class enclosure_class = {
 459        .name                   = "enclosure",
 460        .owner                  = THIS_MODULE,
 461        .dev_release            = enclosure_release,
 462        .dev_groups             = enclosure_class_groups,
 463};
 464
 465static const char *const enclosure_status [] = {
 466        [ENCLOSURE_STATUS_UNSUPPORTED] = "unsupported",
 467        [ENCLOSURE_STATUS_OK] = "OK",
 468        [ENCLOSURE_STATUS_CRITICAL] = "critical",
 469        [ENCLOSURE_STATUS_NON_CRITICAL] = "non-critical",
 470        [ENCLOSURE_STATUS_UNRECOVERABLE] = "unrecoverable",
 471        [ENCLOSURE_STATUS_NOT_INSTALLED] = "not installed",
 472        [ENCLOSURE_STATUS_UNKNOWN] = "unknown",
 473        [ENCLOSURE_STATUS_UNAVAILABLE] = "unavailable",
 474        [ENCLOSURE_STATUS_MAX] = NULL,
 475};
 476
 477static const char *const enclosure_type [] = {
 478        [ENCLOSURE_COMPONENT_DEVICE] = "device",
 479        [ENCLOSURE_COMPONENT_ARRAY_DEVICE] = "array device",
 480};
 481
 482static ssize_t get_component_fault(struct device *cdev,
 483                                   struct device_attribute *attr, char *buf)
 484{
 485        struct enclosure_device *edev = to_enclosure_device(cdev->parent);
 486        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 487
 488        if (edev->cb->get_fault)
 489                edev->cb->get_fault(edev, ecomp);
 490        return snprintf(buf, 40, "%d\n", ecomp->fault);
 491}
 492
 493static ssize_t set_component_fault(struct device *cdev,
 494                                   struct device_attribute *attr,
 495                                   const char *buf, size_t count)
 496{
 497        struct enclosure_device *edev = to_enclosure_device(cdev->parent);
 498        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 499        int val = simple_strtoul(buf, NULL, 0);
 500
 501        if (edev->cb->set_fault)
 502                edev->cb->set_fault(edev, ecomp, val);
 503        return count;
 504}
 505
 506static ssize_t get_component_status(struct device *cdev,
 507                                    struct device_attribute *attr,char *buf)
 508{
 509        struct enclosure_device *edev = to_enclosure_device(cdev->parent);
 510        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 511
 512        if (edev->cb->get_status)
 513                edev->cb->get_status(edev, ecomp);
 514        return snprintf(buf, 40, "%s\n", enclosure_status[ecomp->status]);
 515}
 516
 517static ssize_t set_component_status(struct device *cdev,
 518                                    struct device_attribute *attr,
 519                                    const char *buf, size_t count)
 520{
 521        struct enclosure_device *edev = to_enclosure_device(cdev->parent);
 522        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 523        int i;
 524
 525        for (i = 0; enclosure_status[i]; i++) {
 526                if (strncmp(buf, enclosure_status[i],
 527                            strlen(enclosure_status[i])) == 0 &&
 528                    (buf[strlen(enclosure_status[i])] == '\n' ||
 529                     buf[strlen(enclosure_status[i])] == '\0'))
 530                        break;
 531        }
 532
 533        if (enclosure_status[i] && edev->cb->set_status) {
 534                edev->cb->set_status(edev, ecomp, i);
 535                return count;
 536        } else
 537                return -EINVAL;
 538}
 539
 540static ssize_t get_component_active(struct device *cdev,
 541                                    struct device_attribute *attr, char *buf)
 542{
 543        struct enclosure_device *edev = to_enclosure_device(cdev->parent);
 544        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 545
 546        if (edev->cb->get_active)
 547                edev->cb->get_active(edev, ecomp);
 548        return snprintf(buf, 40, "%d\n", ecomp->active);
 549}
 550
 551static ssize_t set_component_active(struct device *cdev,
 552                                    struct device_attribute *attr,
 553                                    const char *buf, size_t count)
 554{
 555        struct enclosure_device *edev = to_enclosure_device(cdev->parent);
 556        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 557        int val = simple_strtoul(buf, NULL, 0);
 558
 559        if (edev->cb->set_active)
 560                edev->cb->set_active(edev, ecomp, val);
 561        return count;
 562}
 563
 564static ssize_t get_component_locate(struct device *cdev,
 565                                    struct device_attribute *attr, char *buf)
 566{
 567        struct enclosure_device *edev = to_enclosure_device(cdev->parent);
 568        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 569
 570        if (edev->cb->get_locate)
 571                edev->cb->get_locate(edev, ecomp);
 572        return snprintf(buf, 40, "%d\n", ecomp->locate);
 573}
 574
 575static ssize_t set_component_locate(struct device *cdev,
 576                                    struct device_attribute *attr,
 577                                    const char *buf, size_t count)
 578{
 579        struct enclosure_device *edev = to_enclosure_device(cdev->parent);
 580        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 581        int val = simple_strtoul(buf, NULL, 0);
 582
 583        if (edev->cb->set_locate)
 584                edev->cb->set_locate(edev, ecomp, val);
 585        return count;
 586}
 587
 588static ssize_t get_component_power_status(struct device *cdev,
 589                                          struct device_attribute *attr,
 590                                          char *buf)
 591{
 592        struct enclosure_device *edev = to_enclosure_device(cdev->parent);
 593        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 594
 595        if (edev->cb->get_power_status)
 596                edev->cb->get_power_status(edev, ecomp);
 597        return snprintf(buf, 40, "%s\n", ecomp->power_status ? "on" : "off");
 598}
 599
 600static ssize_t set_component_power_status(struct device *cdev,
 601                                          struct device_attribute *attr,
 602                                          const char *buf, size_t count)
 603{
 604        struct enclosure_device *edev = to_enclosure_device(cdev->parent);
 605        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 606        int val;
 607
 608        if (strncmp(buf, "on", 2) == 0 &&
 609            (buf[2] == '\n' || buf[2] == '\0'))
 610                val = 1;
 611        else if (strncmp(buf, "off", 3) == 0 &&
 612            (buf[3] == '\n' || buf[3] == '\0'))
 613                val = 0;
 614        else
 615                return -EINVAL;
 616
 617        if (edev->cb->set_power_status)
 618                edev->cb->set_power_status(edev, ecomp, val);
 619        return count;
 620}
 621
 622static ssize_t get_component_type(struct device *cdev,
 623                                  struct device_attribute *attr, char *buf)
 624{
 625        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 626
 627        return snprintf(buf, 40, "%s\n", enclosure_type[ecomp->type]);
 628}
 629
 630static ssize_t get_component_slot(struct device *cdev,
 631                                  struct device_attribute *attr, char *buf)
 632{
 633        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 634        int slot;
 635
 636        /* if the enclosure does not override then use 'number' as a stand-in */
 637        if (ecomp->slot >= 0)
 638                slot = ecomp->slot;
 639        else
 640                slot = ecomp->number;
 641
 642        return snprintf(buf, 40, "%d\n", slot);
 643}
 644
 645static DEVICE_ATTR(fault, S_IRUGO | S_IWUSR, get_component_fault,
 646                    set_component_fault);
 647static DEVICE_ATTR(status, S_IRUGO | S_IWUSR, get_component_status,
 648                   set_component_status);
 649static DEVICE_ATTR(active, S_IRUGO | S_IWUSR, get_component_active,
 650                   set_component_active);
 651static DEVICE_ATTR(locate, S_IRUGO | S_IWUSR, get_component_locate,
 652                   set_component_locate);
 653static DEVICE_ATTR(power_status, S_IRUGO | S_IWUSR, get_component_power_status,
 654                   set_component_power_status);
 655static DEVICE_ATTR(type, S_IRUGO, get_component_type, NULL);
 656static DEVICE_ATTR(slot, S_IRUGO, get_component_slot, NULL);
 657
 658static struct attribute *enclosure_component_attrs[] = {
 659        &dev_attr_fault.attr,
 660        &dev_attr_status.attr,
 661        &dev_attr_active.attr,
 662        &dev_attr_locate.attr,
 663        &dev_attr_power_status.attr,
 664        &dev_attr_type.attr,
 665        &dev_attr_slot.attr,
 666        NULL
 667};
 668ATTRIBUTE_GROUPS(enclosure_component);
 669
 670static int __init enclosure_init(void)
 671{
 672        int err;
 673
 674        err = class_register(&enclosure_class);
 675        if (err)
 676                return err;
 677
 678        return 0;
 679}
 680
 681static void __exit enclosure_exit(void)
 682{
 683        class_unregister(&enclosure_class);
 684}
 685
 686module_init(enclosure_init);
 687module_exit(enclosure_exit);
 688
 689MODULE_AUTHOR("James Bottomley");
 690MODULE_DESCRIPTION("Enclosure Services");
 691MODULE_LICENSE("GPL v2");
 692