linux/drivers/extcon/extcon-class.c
<<
>>
Prefs
   1/*
   2 *  drivers/extcon/extcon_class.c
   3 *
   4 *  External connector (extcon) class driver
   5 *
   6 * Copyright (C) 2012 Samsung Electronics
   7 * Author: Donggeun Kim <dg77.kim@samsung.com>
   8 * Author: MyungJoo Ham <myungjoo.ham@samsung.com>
   9 *
  10 * based on android/drivers/switch/switch_class.c
  11 * Copyright (C) 2008 Google, Inc.
  12 * Author: Mike Lockwood <lockwood@android.com>
  13 *
  14 * This software is licensed under the terms of the GNU General Public
  15 * License version 2, as published by the Free Software Foundation, and
  16 * may be copied, distributed, and modified under those terms.
  17 *
  18 * This program is distributed in the hope that it will be useful,
  19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21 * GNU General Public License for more details.
  22 *
  23*/
  24
  25#include <linux/module.h>
  26#include <linux/types.h>
  27#include <linux/init.h>
  28#include <linux/device.h>
  29#include <linux/fs.h>
  30#include <linux/err.h>
  31#include <linux/extcon.h>
  32#include <linux/slab.h>
  33#include <linux/sysfs.h>
  34
  35/*
  36 * extcon_cable_name suggests the standard cable names for commonly used
  37 * cable types.
  38 *
  39 * However, please do not use extcon_cable_name directly for extcon_dev
  40 * struct's supported_cable pointer unless your device really supports
  41 * every single port-type of the following cable names. Please choose cable
  42 * names that are actually used in your extcon device.
  43 */
  44const char extcon_cable_name[][CABLE_NAME_MAX + 1] = {
  45        [EXTCON_USB]            = "USB",
  46        [EXTCON_USB_HOST]       = "USB-Host",
  47        [EXTCON_TA]             = "TA",
  48        [EXTCON_FAST_CHARGER]   = "Fast-charger",
  49        [EXTCON_SLOW_CHARGER]   = "Slow-charger",
  50        [EXTCON_CHARGE_DOWNSTREAM]      = "Charge-downstream",
  51        [EXTCON_HDMI]           = "HDMI",
  52        [EXTCON_MHL]            = "MHL",
  53        [EXTCON_DVI]            = "DVI",
  54        [EXTCON_VGA]            = "VGA",
  55        [EXTCON_DOCK]           = "Dock",
  56        [EXTCON_LINE_IN]        = "Line-in",
  57        [EXTCON_LINE_OUT]       = "Line-out",
  58        [EXTCON_MIC_IN]         = "Microphone",
  59        [EXTCON_HEADPHONE_OUT]  = "Headphone",
  60        [EXTCON_SPDIF_IN]       = "SPDIF-in",
  61        [EXTCON_SPDIF_OUT]      = "SPDIF-out",
  62        [EXTCON_VIDEO_IN]       = "Video-in",
  63        [EXTCON_VIDEO_OUT]      = "Video-out",
  64        [EXTCON_MECHANICAL]     = "Mechanical",
  65};
  66
  67static struct class *extcon_class;
  68#if defined(CONFIG_ANDROID)
  69static struct class_compat *switch_class;
  70#endif /* CONFIG_ANDROID */
  71
  72static LIST_HEAD(extcon_dev_list);
  73static DEFINE_MUTEX(extcon_dev_list_lock);
  74
  75/**
  76 * check_mutually_exclusive - Check if new_state violates mutually_exclusive
  77 *                            condition.
  78 * @edev:       the extcon device
  79 * @new_state:  new cable attach status for @edev
  80 *
  81 * Returns 0 if nothing violates. Returns the index + 1 for the first
  82 * violated condition.
  83 */
  84static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state)
  85{
  86        int i = 0;
  87
  88        if (!edev->mutually_exclusive)
  89                return 0;
  90
  91        for (i = 0; edev->mutually_exclusive[i]; i++) {
  92                int weight;
  93                u32 correspondants = new_state & edev->mutually_exclusive[i];
  94
  95                /* calculate the total number of bits set */
  96                weight = hweight32(correspondants);
  97                if (weight > 1)
  98                        return i + 1;
  99        }
 100
 101        return 0;
 102}
 103
 104static ssize_t state_show(struct device *dev, struct device_attribute *attr,
 105                          char *buf)
 106{
 107        int i, count = 0;
 108        struct extcon_dev *edev = dev_get_drvdata(dev);
 109
 110        if (edev->print_state) {
 111                int ret = edev->print_state(edev, buf);
 112
 113                if (ret >= 0)
 114                        return ret;
 115                /* Use default if failed */
 116        }
 117
 118        if (edev->max_supported == 0)
 119                return sprintf(buf, "%u\n", edev->state);
 120
 121        for (i = 0; i < SUPPORTED_CABLE_MAX; i++) {
 122                if (!edev->supported_cable[i])
 123                        break;
 124                count += sprintf(buf + count, "%s=%d\n",
 125                                 edev->supported_cable[i],
 126                                 !!(edev->state & (1 << i)));
 127        }
 128
 129        return count;
 130}
 131
 132static ssize_t state_store(struct device *dev, struct device_attribute *attr,
 133                           const char *buf, size_t count)
 134{
 135        u32 state;
 136        ssize_t ret = 0;
 137        struct extcon_dev *edev = dev_get_drvdata(dev);
 138
 139        ret = sscanf(buf, "0x%x", &state);
 140        if (ret == 0)
 141                ret = -EINVAL;
 142        else
 143                ret = extcon_set_state(edev, state);
 144
 145        if (ret < 0)
 146                return ret;
 147
 148        return count;
 149}
 150static DEVICE_ATTR_RW(state);
 151
 152static ssize_t name_show(struct device *dev, struct device_attribute *attr,
 153                char *buf)
 154{
 155        struct extcon_dev *edev = dev_get_drvdata(dev);
 156
 157        /* Optional callback given by the user */
 158        if (edev->print_name) {
 159                int ret = edev->print_name(edev, buf);
 160                if (ret >= 0)
 161                        return ret;
 162        }
 163
 164        return sprintf(buf, "%s\n", dev_name(&edev->dev));
 165}
 166static DEVICE_ATTR_RO(name);
 167
 168static ssize_t cable_name_show(struct device *dev,
 169                               struct device_attribute *attr, char *buf)
 170{
 171        struct extcon_cable *cable = container_of(attr, struct extcon_cable,
 172                                                  attr_name);
 173
 174        return sprintf(buf, "%s\n",
 175                       cable->edev->supported_cable[cable->cable_index]);
 176}
 177
 178static ssize_t cable_state_show(struct device *dev,
 179                                struct device_attribute *attr, char *buf)
 180{
 181        struct extcon_cable *cable = container_of(attr, struct extcon_cable,
 182                                                  attr_state);
 183
 184        return sprintf(buf, "%d\n",
 185                       extcon_get_cable_state_(cable->edev,
 186                                               cable->cable_index));
 187}
 188
 189/**
 190 * extcon_update_state() - Update the cable attach states of the extcon device
 191 *                         only for the masked bits.
 192 * @edev:       the extcon device
 193 * @mask:       the bit mask to designate updated bits.
 194 * @state:      new cable attach status for @edev
 195 *
 196 * Changing the state sends uevent with environment variable containing
 197 * the name of extcon device (envp[0]) and the state output (envp[1]).
 198 * Tizen uses this format for extcon device to get events from ports.
 199 * Android uses this format as well.
 200 *
 201 * Note that the notifier provides which bits are changed in the state
 202 * variable with the val parameter (second) to the callback.
 203 */
 204int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
 205{
 206        char name_buf[120];
 207        char state_buf[120];
 208        char *prop_buf;
 209        char *envp[3];
 210        int env_offset = 0;
 211        int length;
 212        unsigned long flags;
 213
 214        spin_lock_irqsave(&edev->lock, flags);
 215
 216        if (edev->state != ((edev->state & ~mask) | (state & mask))) {
 217                u32 old_state = edev->state;
 218
 219                if (check_mutually_exclusive(edev, (edev->state & ~mask) |
 220                                                   (state & mask))) {
 221                        spin_unlock_irqrestore(&edev->lock, flags);
 222                        return -EPERM;
 223                }
 224
 225                edev->state &= ~mask;
 226                edev->state |= state & mask;
 227
 228                raw_notifier_call_chain(&edev->nh, old_state, edev);
 229                /* This could be in interrupt handler */
 230                prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
 231                if (prop_buf) {
 232                        length = name_show(&edev->dev, NULL, prop_buf);
 233                        if (length > 0) {
 234                                if (prop_buf[length - 1] == '\n')
 235                                        prop_buf[length - 1] = 0;
 236                                snprintf(name_buf, sizeof(name_buf),
 237                                        "NAME=%s", prop_buf);
 238                                envp[env_offset++] = name_buf;
 239                        }
 240                        length = state_show(&edev->dev, NULL, prop_buf);
 241                        if (length > 0) {
 242                                if (prop_buf[length - 1] == '\n')
 243                                        prop_buf[length - 1] = 0;
 244                                snprintf(state_buf, sizeof(state_buf),
 245                                        "STATE=%s", prop_buf);
 246                                envp[env_offset++] = state_buf;
 247                        }
 248                        envp[env_offset] = NULL;
 249                        /* Unlock early before uevent */
 250                        spin_unlock_irqrestore(&edev->lock, flags);
 251
 252                        kobject_uevent_env(&edev->dev.kobj, KOBJ_CHANGE, envp);
 253                        free_page((unsigned long)prop_buf);
 254                } else {
 255                        /* Unlock early before uevent */
 256                        spin_unlock_irqrestore(&edev->lock, flags);
 257
 258                        dev_err(&edev->dev, "out of memory in extcon_set_state\n");
 259                        kobject_uevent(&edev->dev.kobj, KOBJ_CHANGE);
 260                }
 261        } else {
 262                /* No changes */
 263                spin_unlock_irqrestore(&edev->lock, flags);
 264        }
 265
 266        return 0;
 267}
 268EXPORT_SYMBOL_GPL(extcon_update_state);
 269
 270/**
 271 * extcon_set_state() - Set the cable attach states of the extcon device.
 272 * @edev:       the extcon device
 273 * @state:      new cable attach status for @edev
 274 *
 275 * Note that notifier provides which bits are changed in the state
 276 * variable with the val parameter (second) to the callback.
 277 */
 278int extcon_set_state(struct extcon_dev *edev, u32 state)
 279{
 280        return extcon_update_state(edev, 0xffffffff, state);
 281}
 282EXPORT_SYMBOL_GPL(extcon_set_state);
 283
 284/**
 285 * extcon_find_cable_index() - Get the cable index based on the cable name.
 286 * @edev:       the extcon device that has the cable.
 287 * @cable_name: cable name to be searched.
 288 *
 289 * Note that accessing a cable state based on cable_index is faster than
 290 * cable_name because using cable_name induces a loop with strncmp().
 291 * Thus, when get/set_cable_state is repeatedly used, using cable_index
 292 * is recommended.
 293 */
 294int extcon_find_cable_index(struct extcon_dev *edev, const char *cable_name)
 295{
 296        int i;
 297
 298        if (edev->supported_cable) {
 299                for (i = 0; edev->supported_cable[i]; i++) {
 300                        if (!strncmp(edev->supported_cable[i],
 301                                cable_name, CABLE_NAME_MAX))
 302                                return i;
 303                }
 304        }
 305
 306        return -EINVAL;
 307}
 308EXPORT_SYMBOL_GPL(extcon_find_cable_index);
 309
 310/**
 311 * extcon_get_cable_state_() - Get the status of a specific cable.
 312 * @edev:       the extcon device that has the cable.
 313 * @index:      cable index that can be retrieved by extcon_find_cable_index().
 314 */
 315int extcon_get_cable_state_(struct extcon_dev *edev, int index)
 316{
 317        if (index < 0 || (edev->max_supported && edev->max_supported <= index))
 318                return -EINVAL;
 319
 320        return !!(edev->state & (1 << index));
 321}
 322EXPORT_SYMBOL_GPL(extcon_get_cable_state_);
 323
 324/**
 325 * extcon_get_cable_state() - Get the status of a specific cable.
 326 * @edev:       the extcon device that has the cable.
 327 * @cable_name: cable name.
 328 *
 329 * Note that this is slower than extcon_get_cable_state_.
 330 */
 331int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name)
 332{
 333        return extcon_get_cable_state_(edev, extcon_find_cable_index
 334                                                (edev, cable_name));
 335}
 336EXPORT_SYMBOL_GPL(extcon_get_cable_state);
 337
 338/**
 339 * extcon_set_cable_state_() - Set the status of a specific cable.
 340 * @edev:               the extcon device that has the cable.
 341 * @index:              cable index that can be retrieved by
 342 *                      extcon_find_cable_index().
 343 * @cable_state:        the new cable status. The default semantics is
 344 *                      true: attached / false: detached.
 345 */
 346int extcon_set_cable_state_(struct extcon_dev *edev,
 347                        int index, bool cable_state)
 348{
 349        u32 state;
 350
 351        if (index < 0 || (edev->max_supported && edev->max_supported <= index))
 352                return -EINVAL;
 353
 354        state = cable_state ? (1 << index) : 0;
 355        return extcon_update_state(edev, 1 << index, state);
 356}
 357EXPORT_SYMBOL_GPL(extcon_set_cable_state_);
 358
 359/**
 360 * extcon_set_cable_state() - Set the status of a specific cable.
 361 * @edev:               the extcon device that has the cable.
 362 * @cable_name:         cable name.
 363 * @cable_state:        the new cable status. The default semantics is
 364 *                      true: attached / false: detached.
 365 *
 366 * Note that this is slower than extcon_set_cable_state_.
 367 */
 368int extcon_set_cable_state(struct extcon_dev *edev,
 369                        const char *cable_name, bool cable_state)
 370{
 371        return extcon_set_cable_state_(edev, extcon_find_cable_index
 372                                        (edev, cable_name), cable_state);
 373}
 374EXPORT_SYMBOL_GPL(extcon_set_cable_state);
 375
 376/**
 377 * extcon_get_extcon_dev() - Get the extcon device instance from the name
 378 * @extcon_name:        The extcon name provided with extcon_dev_register()
 379 */
 380struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
 381{
 382        struct extcon_dev *sd;
 383
 384        mutex_lock(&extcon_dev_list_lock);
 385        list_for_each_entry(sd, &extcon_dev_list, entry) {
 386                if (!strcmp(sd->name, extcon_name))
 387                        goto out;
 388        }
 389        sd = NULL;
 390out:
 391        mutex_unlock(&extcon_dev_list_lock);
 392        return sd;
 393}
 394EXPORT_SYMBOL_GPL(extcon_get_extcon_dev);
 395
 396static int _call_per_cable(struct notifier_block *nb, unsigned long val,
 397                           void *ptr)
 398{
 399        struct extcon_specific_cable_nb *obj = container_of(nb,
 400                        struct extcon_specific_cable_nb, internal_nb);
 401        struct extcon_dev *edev = ptr;
 402
 403        if ((val & (1 << obj->cable_index)) !=
 404            (edev->state & (1 << obj->cable_index))) {
 405                bool cable_state = true;
 406
 407                obj->previous_value = val;
 408
 409                if (val & (1 << obj->cable_index))
 410                        cable_state = false;
 411
 412                return obj->user_nb->notifier_call(obj->user_nb,
 413                                cable_state, ptr);
 414        }
 415
 416        return NOTIFY_OK;
 417}
 418
 419/**
 420 * extcon_register_interest() - Register a notifier for a state change of a
 421 *                              specific cable, not an entier set of cables of a
 422 *                              extcon device.
 423 * @obj:                an empty extcon_specific_cable_nb object to be returned.
 424 * @extcon_name:        the name of extcon device.
 425 *                      if NULL, extcon_register_interest will register
 426 *                      every cable with the target cable_name given.
 427 * @cable_name:         the target cable name.
 428 * @nb:                 the notifier block to get notified.
 429 *
 430 * Provide an empty extcon_specific_cable_nb. extcon_register_interest() sets
 431 * the struct for you.
 432 *
 433 * extcon_register_interest is a helper function for those who want to get
 434 * notification for a single specific cable's status change. If a user wants
 435 * to get notification for any changes of all cables of a extcon device,
 436 * he/she should use the general extcon_register_notifier().
 437 *
 438 * Note that the second parameter given to the callback of nb (val) is
 439 * "old_state", not the current state. The current state can be retrieved
 440 * by looking at the third pameter (edev pointer)'s state value.
 441 */
 442int extcon_register_interest(struct extcon_specific_cable_nb *obj,
 443                             const char *extcon_name, const char *cable_name,
 444                             struct notifier_block *nb)
 445{
 446        if (!obj || !cable_name || !nb)
 447                return -EINVAL;
 448
 449        if (extcon_name) {
 450                obj->edev = extcon_get_extcon_dev(extcon_name);
 451                if (!obj->edev)
 452                        return -ENODEV;
 453
 454                obj->cable_index = extcon_find_cable_index(obj->edev,
 455                                                          cable_name);
 456                if (obj->cable_index < 0)
 457                        return obj->cable_index;
 458
 459                obj->user_nb = nb;
 460
 461                obj->internal_nb.notifier_call = _call_per_cable;
 462
 463                return raw_notifier_chain_register(&obj->edev->nh,
 464                                                  &obj->internal_nb);
 465        } else {
 466                struct class_dev_iter iter;
 467                struct extcon_dev *extd;
 468                struct device *dev;
 469
 470                if (!extcon_class)
 471                        return -ENODEV;
 472                class_dev_iter_init(&iter, extcon_class, NULL, NULL);
 473                while ((dev = class_dev_iter_next(&iter))) {
 474                        extd = dev_get_drvdata(dev);
 475
 476                        if (extcon_find_cable_index(extd, cable_name) < 0)
 477                                continue;
 478
 479                        class_dev_iter_exit(&iter);
 480                        return extcon_register_interest(obj, extd->name,
 481                                                cable_name, nb);
 482                }
 483
 484                return -ENODEV;
 485        }
 486}
 487EXPORT_SYMBOL_GPL(extcon_register_interest);
 488
 489/**
 490 * extcon_unregister_interest() - Unregister the notifier registered by
 491 *                                extcon_register_interest().
 492 * @obj:        the extcon_specific_cable_nb object returned by
 493 *              extcon_register_interest().
 494 */
 495int extcon_unregister_interest(struct extcon_specific_cable_nb *obj)
 496{
 497        if (!obj)
 498                return -EINVAL;
 499
 500        return raw_notifier_chain_unregister(&obj->edev->nh, &obj->internal_nb);
 501}
 502EXPORT_SYMBOL_GPL(extcon_unregister_interest);
 503
 504/**
 505 * extcon_register_notifier() - Register a notifiee to get notified by
 506 *                              any attach status changes from the extcon.
 507 * @edev:       the extcon device.
 508 * @nb:         a notifier block to be registered.
 509 *
 510 * Note that the second parameter given to the callback of nb (val) is
 511 * "old_state", not the current state. The current state can be retrieved
 512 * by looking at the third pameter (edev pointer)'s state value.
 513 */
 514int extcon_register_notifier(struct extcon_dev *edev,
 515                        struct notifier_block *nb)
 516{
 517        return raw_notifier_chain_register(&edev->nh, nb);
 518}
 519EXPORT_SYMBOL_GPL(extcon_register_notifier);
 520
 521/**
 522 * extcon_unregister_notifier() - Unregister a notifiee from the extcon device.
 523 * @edev:       the extcon device.
 524 * @nb:         a registered notifier block to be unregistered.
 525 */
 526int extcon_unregister_notifier(struct extcon_dev *edev,
 527                        struct notifier_block *nb)
 528{
 529        return raw_notifier_chain_unregister(&edev->nh, nb);
 530}
 531EXPORT_SYMBOL_GPL(extcon_unregister_notifier);
 532
 533static struct attribute *extcon_attrs[] = {
 534        &dev_attr_state.attr,
 535        &dev_attr_name.attr,
 536        NULL,
 537};
 538ATTRIBUTE_GROUPS(extcon);
 539
 540static int create_extcon_class(void)
 541{
 542        if (!extcon_class) {
 543                extcon_class = class_create(THIS_MODULE, "extcon");
 544                if (IS_ERR(extcon_class))
 545                        return PTR_ERR(extcon_class);
 546                extcon_class->dev_groups = extcon_groups;
 547
 548#if defined(CONFIG_ANDROID)
 549                switch_class = class_compat_register("switch");
 550                if (WARN(!switch_class, "cannot allocate"))
 551                        return -ENOMEM;
 552#endif /* CONFIG_ANDROID */
 553        }
 554
 555        return 0;
 556}
 557
 558static void extcon_dev_release(struct device *dev)
 559{
 560}
 561
 562static const char *muex_name = "mutually_exclusive";
 563static void dummy_sysfs_dev_release(struct device *dev)
 564{
 565}
 566
 567/**
 568 * extcon_dev_register() - Register a new extcon device
 569 * @edev        : the new extcon device (should be allocated before calling)
 570 *
 571 * Among the members of edev struct, please set the "user initializing data"
 572 * in any case and set the "optional callbacks" if required. However, please
 573 * do not set the values of "internal data", which are initialized by
 574 * this function.
 575 */
 576int extcon_dev_register(struct extcon_dev *edev)
 577{
 578        int ret, index = 0;
 579
 580        if (!extcon_class) {
 581                ret = create_extcon_class();
 582                if (ret < 0)
 583                        return ret;
 584        }
 585
 586        if (edev->supported_cable) {
 587                /* Get size of array */
 588                for (index = 0; edev->supported_cable[index]; index++)
 589                        ;
 590                edev->max_supported = index;
 591        } else {
 592                edev->max_supported = 0;
 593        }
 594
 595        if (index > SUPPORTED_CABLE_MAX) {
 596                dev_err(&edev->dev, "extcon: maximum number of supported cables exceeded.\n");
 597                return -EINVAL;
 598        }
 599
 600        edev->dev.class = extcon_class;
 601        edev->dev.release = extcon_dev_release;
 602
 603        edev->name = edev->name ? edev->name : dev_name(edev->dev.parent);
 604        if (IS_ERR_OR_NULL(edev->name)) {
 605                dev_err(&edev->dev,
 606                        "extcon device name is null\n");
 607                return -EINVAL;
 608        }
 609        dev_set_name(&edev->dev, "%s", edev->name);
 610
 611        if (edev->max_supported) {
 612                char buf[10];
 613                char *str;
 614                struct extcon_cable *cable;
 615
 616                edev->cables = kzalloc(sizeof(struct extcon_cable) *
 617                                       edev->max_supported, GFP_KERNEL);
 618                if (!edev->cables) {
 619                        ret = -ENOMEM;
 620                        goto err_sysfs_alloc;
 621                }
 622                for (index = 0; index < edev->max_supported; index++) {
 623                        cable = &edev->cables[index];
 624
 625                        snprintf(buf, 10, "cable.%d", index);
 626                        str = kzalloc(sizeof(char) * (strlen(buf) + 1),
 627                                      GFP_KERNEL);
 628                        if (!str) {
 629                                for (index--; index >= 0; index--) {
 630                                        cable = &edev->cables[index];
 631                                        kfree(cable->attr_g.name);
 632                                }
 633                                ret = -ENOMEM;
 634
 635                                goto err_alloc_cables;
 636                        }
 637                        strcpy(str, buf);
 638
 639                        cable->edev = edev;
 640                        cable->cable_index = index;
 641                        cable->attrs[0] = &cable->attr_name.attr;
 642                        cable->attrs[1] = &cable->attr_state.attr;
 643                        cable->attrs[2] = NULL;
 644                        cable->attr_g.name = str;
 645                        cable->attr_g.attrs = cable->attrs;
 646
 647                        sysfs_attr_init(&cable->attr_name.attr);
 648                        cable->attr_name.attr.name = "name";
 649                        cable->attr_name.attr.mode = 0444;
 650                        cable->attr_name.show = cable_name_show;
 651
 652                        sysfs_attr_init(&cable->attr_state.attr);
 653                        cable->attr_state.attr.name = "state";
 654                        cable->attr_state.attr.mode = 0444;
 655                        cable->attr_state.show = cable_state_show;
 656                }
 657        }
 658
 659        if (edev->max_supported && edev->mutually_exclusive) {
 660                char buf[80];
 661                char *name;
 662
 663                /* Count the size of mutually_exclusive array */
 664                for (index = 0; edev->mutually_exclusive[index]; index++)
 665                        ;
 666
 667                edev->attrs_muex = kzalloc(sizeof(struct attribute *) *
 668                                           (index + 1), GFP_KERNEL);
 669                if (!edev->attrs_muex) {
 670                        ret = -ENOMEM;
 671                        goto err_muex;
 672                }
 673
 674                edev->d_attrs_muex = kzalloc(sizeof(struct device_attribute) *
 675                                             index, GFP_KERNEL);
 676                if (!edev->d_attrs_muex) {
 677                        ret = -ENOMEM;
 678                        kfree(edev->attrs_muex);
 679                        goto err_muex;
 680                }
 681
 682                for (index = 0; edev->mutually_exclusive[index]; index++) {
 683                        sprintf(buf, "0x%x", edev->mutually_exclusive[index]);
 684                        name = kzalloc(sizeof(char) * (strlen(buf) + 1),
 685                                       GFP_KERNEL);
 686                        if (!name) {
 687                                for (index--; index >= 0; index--) {
 688                                        kfree(edev->d_attrs_muex[index].attr.
 689                                              name);
 690                                }
 691                                kfree(edev->d_attrs_muex);
 692                                kfree(edev->attrs_muex);
 693                                ret = -ENOMEM;
 694                                goto err_muex;
 695                        }
 696                        strcpy(name, buf);
 697                        sysfs_attr_init(&edev->d_attrs_muex[index].attr);
 698                        edev->d_attrs_muex[index].attr.name = name;
 699                        edev->d_attrs_muex[index].attr.mode = 0000;
 700                        edev->attrs_muex[index] = &edev->d_attrs_muex[index]
 701                                                        .attr;
 702                }
 703                edev->attr_g_muex.name = muex_name;
 704                edev->attr_g_muex.attrs = edev->attrs_muex;
 705
 706        }
 707
 708        if (edev->max_supported) {
 709                edev->extcon_dev_type.groups =
 710                        kzalloc(sizeof(struct attribute_group *) *
 711                                (edev->max_supported + 2), GFP_KERNEL);
 712                if (!edev->extcon_dev_type.groups) {
 713                        ret = -ENOMEM;
 714                        goto err_alloc_groups;
 715                }
 716
 717                edev->extcon_dev_type.name = dev_name(&edev->dev);
 718                edev->extcon_dev_type.release = dummy_sysfs_dev_release;
 719
 720                for (index = 0; index < edev->max_supported; index++)
 721                        edev->extcon_dev_type.groups[index] =
 722                                &edev->cables[index].attr_g;
 723                if (edev->mutually_exclusive)
 724                        edev->extcon_dev_type.groups[index] =
 725                                &edev->attr_g_muex;
 726
 727                edev->dev.type = &edev->extcon_dev_type;
 728        }
 729
 730        ret = device_register(&edev->dev);
 731        if (ret) {
 732                put_device(&edev->dev);
 733                goto err_dev;
 734        }
 735#if defined(CONFIG_ANDROID)
 736        if (switch_class)
 737                ret = class_compat_create_link(switch_class, &edev->dev, NULL);
 738#endif /* CONFIG_ANDROID */
 739
 740        spin_lock_init(&edev->lock);
 741
 742        RAW_INIT_NOTIFIER_HEAD(&edev->nh);
 743
 744        dev_set_drvdata(&edev->dev, edev);
 745        edev->state = 0;
 746
 747        mutex_lock(&extcon_dev_list_lock);
 748        list_add(&edev->entry, &extcon_dev_list);
 749        mutex_unlock(&extcon_dev_list_lock);
 750
 751        return 0;
 752
 753err_dev:
 754        if (edev->max_supported)
 755                kfree(edev->extcon_dev_type.groups);
 756err_alloc_groups:
 757        if (edev->max_supported && edev->mutually_exclusive) {
 758                for (index = 0; edev->mutually_exclusive[index]; index++)
 759                        kfree(edev->d_attrs_muex[index].attr.name);
 760                kfree(edev->d_attrs_muex);
 761                kfree(edev->attrs_muex);
 762        }
 763err_muex:
 764        for (index = 0; index < edev->max_supported; index++)
 765                kfree(edev->cables[index].attr_g.name);
 766err_alloc_cables:
 767        if (edev->max_supported)
 768                kfree(edev->cables);
 769err_sysfs_alloc:
 770        return ret;
 771}
 772EXPORT_SYMBOL_GPL(extcon_dev_register);
 773
 774/**
 775 * extcon_dev_unregister() - Unregister the extcon device.
 776 * @edev:       the extcon device instance to be unregistered.
 777 *
 778 * Note that this does not call kfree(edev) because edev was not allocated
 779 * by this class.
 780 */
 781void extcon_dev_unregister(struct extcon_dev *edev)
 782{
 783        int index;
 784
 785        mutex_lock(&extcon_dev_list_lock);
 786        list_del(&edev->entry);
 787        mutex_unlock(&extcon_dev_list_lock);
 788
 789        if (IS_ERR_OR_NULL(get_device(&edev->dev))) {
 790                dev_err(&edev->dev, "Failed to unregister extcon_dev (%s)\n",
 791                                dev_name(&edev->dev));
 792                return;
 793        }
 794
 795        device_unregister(&edev->dev);
 796
 797        if (edev->mutually_exclusive && edev->max_supported) {
 798                for (index = 0; edev->mutually_exclusive[index];
 799                                index++)
 800                        kfree(edev->d_attrs_muex[index].attr.name);
 801                kfree(edev->d_attrs_muex);
 802                kfree(edev->attrs_muex);
 803        }
 804
 805        for (index = 0; index < edev->max_supported; index++)
 806                kfree(edev->cables[index].attr_g.name);
 807
 808        if (edev->max_supported) {
 809                kfree(edev->extcon_dev_type.groups);
 810                kfree(edev->cables);
 811        }
 812
 813#if defined(CONFIG_ANDROID)
 814        if (switch_class)
 815                class_compat_remove_link(switch_class, &edev->dev, NULL);
 816#endif
 817        put_device(&edev->dev);
 818}
 819EXPORT_SYMBOL_GPL(extcon_dev_unregister);
 820
 821static int __init extcon_class_init(void)
 822{
 823        return create_extcon_class();
 824}
 825module_init(extcon_class_init);
 826
 827static void __exit extcon_class_exit(void)
 828{
 829#if defined(CONFIG_ANDROID)
 830        class_compat_unregister(switch_class);
 831#endif
 832        class_destroy(extcon_class);
 833}
 834module_exit(extcon_class_exit);
 835
 836MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
 837MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
 838MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
 839MODULE_DESCRIPTION("External connector (extcon) class driver");
 840MODULE_LICENSE("GPL");
 841