linux/drivers/acpi/dock.c
<<
>>
Prefs
   1/*
   2 *  dock.c - ACPI dock station driver
   3 *
   4 *  Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@intel.com>
   5 *
   6 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   7 *
   8 *  This program is free software; you can redistribute it and/or modify
   9 *  it under the terms of the GNU General Public License as published by
  10 *  the Free Software Foundation; either version 2 of the License, or (at
  11 *  your option) any later version.
  12 *
  13 *  This program is distributed in the hope that it will be useful, but
  14 *  WITHOUT ANY WARRANTY; without even the implied warranty of
  15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16 *  General Public License for more details.
  17 *
  18 *  You should have received a copy of the GNU General Public License along
  19 *  with this program; if not, write to the Free Software Foundation, Inc.,
  20 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  21 *
  22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  23 */
  24
  25#include <linux/kernel.h>
  26#include <linux/module.h>
  27#include <linux/init.h>
  28#include <linux/types.h>
  29#include <linux/notifier.h>
  30#include <linux/platform_device.h>
  31#include <linux/jiffies.h>
  32#include <linux/stddef.h>
  33#include <acpi/acpi_bus.h>
  34#include <acpi/acpi_drivers.h>
  35
  36#define PREFIX "ACPI: "
  37
  38#define ACPI_DOCK_DRIVER_DESCRIPTION "ACPI Dock Station Driver"
  39
  40ACPI_MODULE_NAME("dock");
  41MODULE_AUTHOR("Kristen Carlson Accardi");
  42MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION);
  43MODULE_LICENSE("GPL");
  44
  45static int immediate_undock = 1;
  46module_param(immediate_undock, bool, 0644);
  47MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to "
  48        "undock immediately when the undock button is pressed, 0 will cause"
  49        " the driver to wait for userspace to write the undock sysfs file "
  50        " before undocking");
  51
  52static struct atomic_notifier_head dock_notifier_list;
  53static char dock_device_name[] = "dock";
  54
  55static const struct acpi_device_id dock_device_ids[] = {
  56        {"LNXDOCK", 0},
  57        {"", 0},
  58};
  59MODULE_DEVICE_TABLE(acpi, dock_device_ids);
  60
  61struct dock_station {
  62        acpi_handle handle;
  63        unsigned long last_dock_time;
  64        u32 flags;
  65        spinlock_t dd_lock;
  66        struct mutex hp_lock;
  67        struct list_head dependent_devices;
  68        struct list_head hotplug_devices;
  69
  70        struct list_head sibling;
  71        struct platform_device *dock_device;
  72};
  73static LIST_HEAD(dock_stations);
  74static int dock_station_count;
  75
  76struct dock_dependent_device {
  77        struct list_head list;
  78        struct list_head hotplug_list;
  79        acpi_handle handle;
  80        struct acpi_dock_ops *ops;
  81        void *context;
  82};
  83
  84#define DOCK_DOCKING    0x00000001
  85#define DOCK_UNDOCKING  0x00000002
  86#define DOCK_IS_DOCK    0x00000010
  87#define DOCK_IS_ATA     0x00000020
  88#define DOCK_IS_BAT     0x00000040
  89#define DOCK_EVENT      3
  90#define UNDOCK_EVENT    2
  91
  92/*****************************************************************************
  93 *                         Dock Dependent device functions                   *
  94 *****************************************************************************/
  95/**
  96 *  alloc_dock_dependent_device - allocate and init a dependent device
  97 *  @handle: the acpi_handle of the dependent device
  98 *
  99 *  Allocate memory for a dependent device structure for a device referenced
 100 *  by the acpi handle
 101 */
 102static struct dock_dependent_device *
 103alloc_dock_dependent_device(acpi_handle handle)
 104{
 105        struct dock_dependent_device *dd;
 106
 107        dd = kzalloc(sizeof(*dd), GFP_KERNEL);
 108        if (dd) {
 109                dd->handle = handle;
 110                INIT_LIST_HEAD(&dd->list);
 111                INIT_LIST_HEAD(&dd->hotplug_list);
 112        }
 113        return dd;
 114}
 115
 116/**
 117 * add_dock_dependent_device - associate a device with the dock station
 118 * @ds: The dock station
 119 * @dd: The dependent device
 120 *
 121 * Add the dependent device to the dock's dependent device list.
 122 */
 123static void
 124add_dock_dependent_device(struct dock_station *ds,
 125                          struct dock_dependent_device *dd)
 126{
 127        spin_lock(&ds->dd_lock);
 128        list_add_tail(&dd->list, &ds->dependent_devices);
 129        spin_unlock(&ds->dd_lock);
 130}
 131
 132/**
 133 * dock_add_hotplug_device - associate a hotplug handler with the dock station
 134 * @ds: The dock station
 135 * @dd: The dependent device struct
 136 *
 137 * Add the dependent device to the dock's hotplug device list
 138 */
 139static void
 140dock_add_hotplug_device(struct dock_station *ds,
 141                        struct dock_dependent_device *dd)
 142{
 143        mutex_lock(&ds->hp_lock);
 144        list_add_tail(&dd->hotplug_list, &ds->hotplug_devices);
 145        mutex_unlock(&ds->hp_lock);
 146}
 147
 148/**
 149 * dock_del_hotplug_device - remove a hotplug handler from the dock station
 150 * @ds: The dock station
 151 * @dd: the dependent device struct
 152 *
 153 * Delete the dependent device from the dock's hotplug device list
 154 */
 155static void
 156dock_del_hotplug_device(struct dock_station *ds,
 157                        struct dock_dependent_device *dd)
 158{
 159        mutex_lock(&ds->hp_lock);
 160        list_del(&dd->hotplug_list);
 161        mutex_unlock(&ds->hp_lock);
 162}
 163
 164/**
 165 * find_dock_dependent_device - get a device dependent on this dock
 166 * @ds: the dock station
 167 * @handle: the acpi_handle of the device we want
 168 *
 169 * iterate over the dependent device list for this dock.  If the
 170 * dependent device matches the handle, return.
 171 */
 172static struct dock_dependent_device *
 173find_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
 174{
 175        struct dock_dependent_device *dd;
 176
 177        spin_lock(&ds->dd_lock);
 178        list_for_each_entry(dd, &ds->dependent_devices, list) {
 179                if (handle == dd->handle) {
 180                        spin_unlock(&ds->dd_lock);
 181                        return dd;
 182                }
 183        }
 184        spin_unlock(&ds->dd_lock);
 185        return NULL;
 186}
 187
 188/*****************************************************************************
 189 *                         Dock functions                                    *
 190 *****************************************************************************/
 191/**
 192 * is_dock - see if a device is a dock station
 193 * @handle: acpi handle of the device
 194 *
 195 * If an acpi object has a _DCK method, then it is by definition a dock
 196 * station, so return true.
 197 */
 198static int is_dock(acpi_handle handle)
 199{
 200        acpi_status status;
 201        acpi_handle tmp;
 202
 203        status = acpi_get_handle(handle, "_DCK", &tmp);
 204        if (ACPI_FAILURE(status))
 205                return 0;
 206        return 1;
 207}
 208
 209static int is_ejectable(acpi_handle handle)
 210{
 211        acpi_status status;
 212        acpi_handle tmp;
 213
 214        status = acpi_get_handle(handle, "_EJ0", &tmp);
 215        if (ACPI_FAILURE(status))
 216                return 0;
 217        return 1;
 218}
 219
 220static int is_ata(acpi_handle handle)
 221{
 222        acpi_handle tmp;
 223
 224        if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
 225           (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
 226           (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
 227           (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
 228                return 1;
 229
 230        return 0;
 231}
 232
 233static int is_battery(acpi_handle handle)
 234{
 235        struct acpi_device_info *info;
 236        int ret = 1;
 237
 238        if (!ACPI_SUCCESS(acpi_get_object_info(handle, &info)))
 239                return 0;
 240        if (!(info->valid & ACPI_VALID_HID))
 241                ret = 0;
 242        else
 243                ret = !strcmp("PNP0C0A", info->hardware_id.string);
 244
 245        kfree(info);
 246        return ret;
 247}
 248
 249static int is_ejectable_bay(acpi_handle handle)
 250{
 251        acpi_handle phandle;
 252        if (!is_ejectable(handle))
 253                return 0;
 254        if (is_battery(handle) || is_ata(handle))
 255                return 1;
 256        if (!acpi_get_parent(handle, &phandle) && is_ata(phandle))
 257                return 1;
 258        return 0;
 259}
 260
 261/**
 262 * is_dock_device - see if a device is on a dock station
 263 * @handle: acpi handle of the device
 264 *
 265 * If this device is either the dock station itself,
 266 * or is a device dependent on the dock station, then it
 267 * is a dock device
 268 */
 269int is_dock_device(acpi_handle handle)
 270{
 271        struct dock_station *dock_station;
 272
 273        if (!dock_station_count)
 274                return 0;
 275
 276        if (is_dock(handle))
 277                return 1;
 278        list_for_each_entry(dock_station, &dock_stations, sibling) {
 279                if (find_dock_dependent_device(dock_station, handle))
 280                        return 1;
 281        }
 282
 283        return 0;
 284}
 285
 286EXPORT_SYMBOL_GPL(is_dock_device);
 287
 288/**
 289 * dock_present - see if the dock station is present.
 290 * @ds: the dock station
 291 *
 292 * execute the _STA method.  note that present does not
 293 * imply that we are docked.
 294 */
 295static int dock_present(struct dock_station *ds)
 296{
 297        unsigned long long sta;
 298        acpi_status status;
 299
 300        if (ds) {
 301                status = acpi_evaluate_integer(ds->handle, "_STA", NULL, &sta);
 302                if (ACPI_SUCCESS(status) && sta)
 303                        return 1;
 304        }
 305        return 0;
 306}
 307
 308
 309
 310/**
 311 * dock_create_acpi_device - add new devices to acpi
 312 * @handle - handle of the device to add
 313 *
 314 *  This function will create a new acpi_device for the given
 315 *  handle if one does not exist already.  This should cause
 316 *  acpi to scan for drivers for the given devices, and call
 317 *  matching driver's add routine.
 318 *
 319 *  Returns a pointer to the acpi_device corresponding to the handle.
 320 */
 321static struct acpi_device * dock_create_acpi_device(acpi_handle handle)
 322{
 323        struct acpi_device *device = NULL;
 324        struct acpi_device *parent_device;
 325        acpi_handle parent;
 326        int ret;
 327
 328        if (acpi_bus_get_device(handle, &device)) {
 329                /*
 330                 * no device created for this object,
 331                 * so we should create one.
 332                 */
 333                acpi_get_parent(handle, &parent);
 334                if (acpi_bus_get_device(parent, &parent_device))
 335                        parent_device = NULL;
 336
 337                ret = acpi_bus_add(&device, parent_device, handle,
 338                        ACPI_BUS_TYPE_DEVICE);
 339                if (ret) {
 340                        pr_debug("error adding bus, %x\n",
 341                                -ret);
 342                        return NULL;
 343                }
 344        }
 345        return device;
 346}
 347
 348/**
 349 * dock_remove_acpi_device - remove the acpi_device struct from acpi
 350 * @handle - the handle of the device to remove
 351 *
 352 *  Tell acpi to remove the acpi_device.  This should cause any loaded
 353 *  driver to have it's remove routine called.
 354 */
 355static void dock_remove_acpi_device(acpi_handle handle)
 356{
 357        struct acpi_device *device;
 358        int ret;
 359
 360        if (!acpi_bus_get_device(handle, &device)) {
 361                ret = acpi_bus_trim(device, 1);
 362                if (ret)
 363                        pr_debug("error removing bus, %x\n", -ret);
 364        }
 365}
 366
 367
 368/**
 369 * hotplug_dock_devices - insert or remove devices on the dock station
 370 * @ds: the dock station
 371 * @event: either bus check or eject request
 372 *
 373 * Some devices on the dock station need to have drivers called
 374 * to perform hotplug operations after a dock event has occurred.
 375 * Traverse the list of dock devices that have registered a
 376 * hotplug handler, and call the handler.
 377 */
 378static void hotplug_dock_devices(struct dock_station *ds, u32 event)
 379{
 380        struct dock_dependent_device *dd;
 381
 382        mutex_lock(&ds->hp_lock);
 383
 384        /*
 385         * First call driver specific hotplug functions
 386         */
 387        list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) {
 388                if (dd->ops && dd->ops->handler)
 389                        dd->ops->handler(dd->handle, event, dd->context);
 390        }
 391
 392        /*
 393         * Now make sure that an acpi_device is created for each
 394         * dependent device, or removed if this is an eject request.
 395         * This will cause acpi_drivers to be stopped/started if they
 396         * exist
 397         */
 398        list_for_each_entry(dd, &ds->dependent_devices, list) {
 399                if (event == ACPI_NOTIFY_EJECT_REQUEST)
 400                        dock_remove_acpi_device(dd->handle);
 401                else
 402                        dock_create_acpi_device(dd->handle);
 403        }
 404        mutex_unlock(&ds->hp_lock);
 405}
 406
 407static void dock_event(struct dock_station *ds, u32 event, int num)
 408{
 409        struct device *dev = &ds->dock_device->dev;
 410        char event_string[13];
 411        char *envp[] = { event_string, NULL };
 412        struct dock_dependent_device *dd;
 413
 414        if (num == UNDOCK_EVENT)
 415                sprintf(event_string, "EVENT=undock");
 416        else
 417                sprintf(event_string, "EVENT=dock");
 418
 419        /*
 420         * Indicate that the status of the dock station has
 421         * changed.
 422         */
 423        if (num == DOCK_EVENT)
 424                kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
 425
 426        list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list)
 427                if (dd->ops && dd->ops->uevent)
 428                        dd->ops->uevent(dd->handle, event, dd->context);
 429        if (num != DOCK_EVENT)
 430                kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
 431}
 432
 433/**
 434 * eject_dock - respond to a dock eject request
 435 * @ds: the dock station
 436 *
 437 * This is called after _DCK is called, to execute the dock station's
 438 * _EJ0 method.
 439 */
 440static void eject_dock(struct dock_station *ds)
 441{
 442        struct acpi_object_list arg_list;
 443        union acpi_object arg;
 444        acpi_status status;
 445        acpi_handle tmp;
 446
 447        /* all dock devices should have _EJ0, but check anyway */
 448        status = acpi_get_handle(ds->handle, "_EJ0", &tmp);
 449        if (ACPI_FAILURE(status)) {
 450                pr_debug("No _EJ0 support for dock device\n");
 451                return;
 452        }
 453
 454        arg_list.count = 1;
 455        arg_list.pointer = &arg;
 456        arg.type = ACPI_TYPE_INTEGER;
 457        arg.integer.value = 1;
 458
 459        if (ACPI_FAILURE(acpi_evaluate_object(ds->handle, "_EJ0",
 460                                              &arg_list, NULL)))
 461                pr_debug("Failed to evaluate _EJ0!\n");
 462}
 463
 464/**
 465 * handle_dock - handle a dock event
 466 * @ds: the dock station
 467 * @dock: to dock, or undock - that is the question
 468 *
 469 * Execute the _DCK method in response to an acpi event
 470 */
 471static void handle_dock(struct dock_station *ds, int dock)
 472{
 473        acpi_status status;
 474        struct acpi_object_list arg_list;
 475        union acpi_object arg;
 476        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 477        struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 478
 479        acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer);
 480
 481        printk(KERN_INFO PREFIX "%s - %s\n",
 482                (char *)name_buffer.pointer, dock ? "docking" : "undocking");
 483
 484        /* _DCK method has one argument */
 485        arg_list.count = 1;
 486        arg_list.pointer = &arg;
 487        arg.type = ACPI_TYPE_INTEGER;
 488        arg.integer.value = dock;
 489        status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
 490        if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
 491                ACPI_EXCEPTION((AE_INFO, status, "%s - failed to execute"
 492                        " _DCK\n", (char *)name_buffer.pointer));
 493
 494        kfree(buffer.pointer);
 495        kfree(name_buffer.pointer);
 496}
 497
 498static inline void dock(struct dock_station *ds)
 499{
 500        handle_dock(ds, 1);
 501}
 502
 503static inline void undock(struct dock_station *ds)
 504{
 505        handle_dock(ds, 0);
 506}
 507
 508static inline void begin_dock(struct dock_station *ds)
 509{
 510        ds->flags |= DOCK_DOCKING;
 511}
 512
 513static inline void complete_dock(struct dock_station *ds)
 514{
 515        ds->flags &= ~(DOCK_DOCKING);
 516        ds->last_dock_time = jiffies;
 517}
 518
 519static inline void begin_undock(struct dock_station *ds)
 520{
 521        ds->flags |= DOCK_UNDOCKING;
 522}
 523
 524static inline void complete_undock(struct dock_station *ds)
 525{
 526        ds->flags &= ~(DOCK_UNDOCKING);
 527}
 528
 529static void dock_lock(struct dock_station *ds, int lock)
 530{
 531        struct acpi_object_list arg_list;
 532        union acpi_object arg;
 533        acpi_status status;
 534
 535        arg_list.count = 1;
 536        arg_list.pointer = &arg;
 537        arg.type = ACPI_TYPE_INTEGER;
 538        arg.integer.value = !!lock;
 539        status = acpi_evaluate_object(ds->handle, "_LCK", &arg_list, NULL);
 540        if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
 541                if (lock)
 542                        printk(KERN_WARNING PREFIX "Locking device failed\n");
 543                else
 544                        printk(KERN_WARNING PREFIX "Unlocking device failed\n");
 545        }
 546}
 547
 548/**
 549 * dock_in_progress - see if we are in the middle of handling a dock event
 550 * @ds: the dock station
 551 *
 552 * Sometimes while docking, false dock events can be sent to the driver
 553 * because good connections aren't made or some other reason.  Ignore these
 554 * if we are in the middle of doing something.
 555 */
 556static int dock_in_progress(struct dock_station *ds)
 557{
 558        if ((ds->flags & DOCK_DOCKING) ||
 559            time_before(jiffies, (ds->last_dock_time + HZ)))
 560                return 1;
 561        return 0;
 562}
 563
 564/**
 565 * register_dock_notifier - add yourself to the dock notifier list
 566 * @nb: the callers notifier block
 567 *
 568 * If a driver wishes to be notified about dock events, they can
 569 * use this function to put a notifier block on the dock notifier list.
 570 * this notifier call chain will be called after a dock event, but
 571 * before hotplugging any new devices.
 572 */
 573int register_dock_notifier(struct notifier_block *nb)
 574{
 575        if (!dock_station_count)
 576                return -ENODEV;
 577
 578        return atomic_notifier_chain_register(&dock_notifier_list, nb);
 579}
 580
 581EXPORT_SYMBOL_GPL(register_dock_notifier);
 582
 583/**
 584 * unregister_dock_notifier - remove yourself from the dock notifier list
 585 * @nb: the callers notifier block
 586 */
 587void unregister_dock_notifier(struct notifier_block *nb)
 588{
 589        if (!dock_station_count)
 590                return;
 591
 592        atomic_notifier_chain_unregister(&dock_notifier_list, nb);
 593}
 594
 595EXPORT_SYMBOL_GPL(unregister_dock_notifier);
 596
 597/**
 598 * register_hotplug_dock_device - register a hotplug function
 599 * @handle: the handle of the device
 600 * @ops: handlers to call after docking
 601 * @context: device specific data
 602 *
 603 * If a driver would like to perform a hotplug operation after a dock
 604 * event, they can register an acpi_notifiy_handler to be called by
 605 * the dock driver after _DCK is executed.
 606 */
 607int
 608register_hotplug_dock_device(acpi_handle handle, struct acpi_dock_ops *ops,
 609                             void *context)
 610{
 611        struct dock_dependent_device *dd;
 612        struct dock_station *dock_station;
 613        int ret = -EINVAL;
 614
 615        if (!dock_station_count)
 616                return -ENODEV;
 617
 618        /*
 619         * make sure this handle is for a device dependent on the dock,
 620         * this would include the dock station itself
 621         */
 622        list_for_each_entry(dock_station, &dock_stations, sibling) {
 623                /*
 624                 * An ATA bay can be in a dock and itself can be ejected
 625                 * seperately, so there are two 'dock stations' which need the
 626                 * ops
 627                 */
 628                dd = find_dock_dependent_device(dock_station, handle);
 629                if (dd) {
 630                        dd->ops = ops;
 631                        dd->context = context;
 632                        dock_add_hotplug_device(dock_station, dd);
 633                        ret = 0;
 634                }
 635        }
 636
 637        return ret;
 638}
 639
 640EXPORT_SYMBOL_GPL(register_hotplug_dock_device);
 641
 642/**
 643 * unregister_hotplug_dock_device - remove yourself from the hotplug list
 644 * @handle: the acpi handle of the device
 645 */
 646void unregister_hotplug_dock_device(acpi_handle handle)
 647{
 648        struct dock_dependent_device *dd;
 649        struct dock_station *dock_station;
 650
 651        if (!dock_station_count)
 652                return;
 653
 654        list_for_each_entry(dock_station, &dock_stations, sibling) {
 655                dd = find_dock_dependent_device(dock_station, handle);
 656                if (dd)
 657                        dock_del_hotplug_device(dock_station, dd);
 658        }
 659}
 660
 661EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
 662
 663/**
 664 * handle_eject_request - handle an undock request checking for error conditions
 665 *
 666 * Check to make sure the dock device is still present, then undock and
 667 * hotremove all the devices that may need removing.
 668 */
 669static int handle_eject_request(struct dock_station *ds, u32 event)
 670{
 671        if (dock_in_progress(ds))
 672                return -EBUSY;
 673
 674        /*
 675         * here we need to generate the undock
 676         * event prior to actually doing the undock
 677         * so that the device struct still exists.
 678         * Also, even send the dock event if the
 679         * device is not present anymore
 680         */
 681        dock_event(ds, event, UNDOCK_EVENT);
 682
 683        hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
 684        undock(ds);
 685        dock_lock(ds, 0);
 686        eject_dock(ds);
 687        if (dock_present(ds)) {
 688                printk(KERN_ERR PREFIX "Unable to undock!\n");
 689                return -EBUSY;
 690        }
 691        complete_undock(ds);
 692        return 0;
 693}
 694
 695/**
 696 * dock_notify - act upon an acpi dock notification
 697 * @handle: the dock station handle
 698 * @event: the acpi event
 699 * @data: our driver data struct
 700 *
 701 * If we are notified to dock, then check to see if the dock is
 702 * present and then dock.  Notify all drivers of the dock event,
 703 * and then hotplug and devices that may need hotplugging.
 704 */
 705static void dock_notify(acpi_handle handle, u32 event, void *data)
 706{
 707        struct dock_station *ds = data;
 708        struct acpi_device *tmp;
 709        int surprise_removal = 0;
 710
 711        /*
 712         * According to acpi spec 3.0a, if a DEVICE_CHECK notification
 713         * is sent and _DCK is present, it is assumed to mean an undock
 714         * request.
 715         */
 716        if ((ds->flags & DOCK_IS_DOCK) && event == ACPI_NOTIFY_DEVICE_CHECK)
 717                event = ACPI_NOTIFY_EJECT_REQUEST;
 718
 719        /*
 720         * dock station: BUS_CHECK - docked or surprise removal
 721         *               DEVICE_CHECK - undocked
 722         * other device: BUS_CHECK/DEVICE_CHECK - added or surprise removal
 723         *
 724         * To simplify event handling, dock dependent device handler always
 725         * get ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and
 726         * ACPI_NOTIFY_EJECT_REQUEST for removal
 727         */
 728        switch (event) {
 729        case ACPI_NOTIFY_BUS_CHECK:
 730        case ACPI_NOTIFY_DEVICE_CHECK:
 731                if (!dock_in_progress(ds) && acpi_bus_get_device(ds->handle,
 732                   &tmp)) {
 733                        begin_dock(ds);
 734                        dock(ds);
 735                        if (!dock_present(ds)) {
 736                                printk(KERN_ERR PREFIX "Unable to dock!\n");
 737                                complete_dock(ds);
 738                                break;
 739                        }
 740                        atomic_notifier_call_chain(&dock_notifier_list,
 741                                                   event, NULL);
 742                        hotplug_dock_devices(ds, event);
 743                        complete_dock(ds);
 744                        dock_event(ds, event, DOCK_EVENT);
 745                        dock_lock(ds, 1);
 746                        break;
 747                }
 748                if (dock_present(ds) || dock_in_progress(ds))
 749                        break;
 750                /* This is a surprise removal */
 751                surprise_removal = 1;
 752                event = ACPI_NOTIFY_EJECT_REQUEST;
 753                /* Fall back */
 754        case ACPI_NOTIFY_EJECT_REQUEST:
 755                begin_undock(ds);
 756                if ((immediate_undock && !(ds->flags & DOCK_IS_ATA))
 757                   || surprise_removal)
 758                        handle_eject_request(ds, event);
 759                else
 760                        dock_event(ds, event, UNDOCK_EVENT);
 761                break;
 762        default:
 763                printk(KERN_ERR PREFIX "Unknown dock event %d\n", event);
 764        }
 765}
 766
 767struct dock_data {
 768        acpi_handle handle;
 769        unsigned long event;
 770        struct dock_station *ds;
 771};
 772
 773static void acpi_dock_deferred_cb(void *context)
 774{
 775        struct dock_data *data = (struct dock_data *)context;
 776
 777        dock_notify(data->handle, data->event, data->ds);
 778        kfree(data);
 779}
 780
 781static int acpi_dock_notifier_call(struct notifier_block *this,
 782        unsigned long event, void *data)
 783{
 784        struct dock_station *dock_station;
 785        acpi_handle handle = (acpi_handle)data;
 786
 787        if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
 788           && event != ACPI_NOTIFY_EJECT_REQUEST)
 789                return 0;
 790        list_for_each_entry(dock_station, &dock_stations, sibling) {
 791                if (dock_station->handle == handle) {
 792                        struct dock_data *dock_data;
 793
 794                        dock_data = kmalloc(sizeof(*dock_data), GFP_KERNEL);
 795                        if (!dock_data)
 796                                return 0;
 797                        dock_data->handle = handle;
 798                        dock_data->event = event;
 799                        dock_data->ds = dock_station;
 800                        acpi_os_hotplug_execute(acpi_dock_deferred_cb,
 801                                dock_data);
 802                        return 0 ;
 803                }
 804        }
 805        return 0;
 806}
 807
 808static struct notifier_block dock_acpi_notifier = {
 809        .notifier_call = acpi_dock_notifier_call,
 810};
 811
 812/**
 813 * find_dock_devices - find devices on the dock station
 814 * @handle: the handle of the device we are examining
 815 * @lvl: unused
 816 * @context: the dock station private data
 817 * @rv: unused
 818 *
 819 * This function is called by acpi_walk_namespace.  It will
 820 * check to see if an object has an _EJD method.  If it does, then it
 821 * will see if it is dependent on the dock station.
 822 */
 823static acpi_status
 824find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv)
 825{
 826        acpi_status status;
 827        acpi_handle tmp, parent;
 828        struct dock_station *ds = context;
 829        struct dock_dependent_device *dd;
 830
 831        status = acpi_bus_get_ejd(handle, &tmp);
 832        if (ACPI_FAILURE(status)) {
 833                /* try the parent device as well */
 834                status = acpi_get_parent(handle, &parent);
 835                if (ACPI_FAILURE(status))
 836                        goto fdd_out;
 837                /* see if parent is dependent on dock */
 838                status = acpi_bus_get_ejd(parent, &tmp);
 839                if (ACPI_FAILURE(status))
 840                        goto fdd_out;
 841        }
 842
 843        if (tmp == ds->handle) {
 844                dd = alloc_dock_dependent_device(handle);
 845                if (dd)
 846                        add_dock_dependent_device(ds, dd);
 847        }
 848fdd_out:
 849        return AE_OK;
 850}
 851
 852/*
 853 * show_docked - read method for "docked" file in sysfs
 854 */
 855static ssize_t show_docked(struct device *dev,
 856                           struct device_attribute *attr, char *buf)
 857{
 858        struct acpi_device *tmp;
 859
 860        struct dock_station *dock_station = *((struct dock_station **)
 861                dev->platform_data);
 862
 863        if (ACPI_SUCCESS(acpi_bus_get_device(dock_station->handle, &tmp)))
 864                return snprintf(buf, PAGE_SIZE, "1\n");
 865        return snprintf(buf, PAGE_SIZE, "0\n");
 866}
 867static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
 868
 869/*
 870 * show_flags - read method for flags file in sysfs
 871 */
 872static ssize_t show_flags(struct device *dev,
 873                          struct device_attribute *attr, char *buf)
 874{
 875        struct dock_station *dock_station = *((struct dock_station **)
 876                dev->platform_data);
 877        return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);
 878
 879}
 880static DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
 881
 882/*
 883 * write_undock - write method for "undock" file in sysfs
 884 */
 885static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
 886                           const char *buf, size_t count)
 887{
 888        int ret;
 889        struct dock_station *dock_station = *((struct dock_station **)
 890                dev->platform_data);
 891
 892        if (!count)
 893                return -EINVAL;
 894
 895        begin_undock(dock_station);
 896        ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST);
 897        return ret ? ret: count;
 898}
 899static DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock);
 900
 901/*
 902 * show_dock_uid - read method for "uid" file in sysfs
 903 */
 904static ssize_t show_dock_uid(struct device *dev,
 905                             struct device_attribute *attr, char *buf)
 906{
 907        unsigned long long lbuf;
 908        struct dock_station *dock_station = *((struct dock_station **)
 909                dev->platform_data);
 910        acpi_status status = acpi_evaluate_integer(dock_station->handle,
 911                                        "_UID", NULL, &lbuf);
 912        if (ACPI_FAILURE(status))
 913            return 0;
 914
 915        return snprintf(buf, PAGE_SIZE, "%llx\n", lbuf);
 916}
 917static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
 918
 919static ssize_t show_dock_type(struct device *dev,
 920                struct device_attribute *attr, char *buf)
 921{
 922        struct dock_station *dock_station = *((struct dock_station **)
 923                dev->platform_data);
 924        char *type;
 925
 926        if (dock_station->flags & DOCK_IS_DOCK)
 927                type = "dock_station";
 928        else if (dock_station->flags & DOCK_IS_ATA)
 929                type = "ata_bay";
 930        else if (dock_station->flags & DOCK_IS_BAT)
 931                type = "battery_bay";
 932        else
 933                type = "unknown";
 934
 935        return snprintf(buf, PAGE_SIZE, "%s\n", type);
 936}
 937static DEVICE_ATTR(type, S_IRUGO, show_dock_type, NULL);
 938
 939/**
 940 * dock_add - add a new dock station
 941 * @handle: the dock station handle
 942 *
 943 * allocated and initialize a new dock station device.  Find all devices
 944 * that are on the dock station, and register for dock event notifications.
 945 */
 946static int dock_add(acpi_handle handle)
 947{
 948        int ret;
 949        struct dock_dependent_device *dd;
 950        struct dock_station *dock_station;
 951        struct platform_device *dock_device;
 952
 953        /* allocate & initialize the dock_station private data */
 954        dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL);
 955        if (!dock_station)
 956                return -ENOMEM;
 957        dock_station->handle = handle;
 958        dock_station->last_dock_time = jiffies - HZ;
 959        INIT_LIST_HEAD(&dock_station->dependent_devices);
 960        INIT_LIST_HEAD(&dock_station->hotplug_devices);
 961        INIT_LIST_HEAD(&dock_station->sibling);
 962        spin_lock_init(&dock_station->dd_lock);
 963        mutex_init(&dock_station->hp_lock);
 964        ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
 965
 966        /* initialize platform device stuff */
 967        dock_station->dock_device =
 968                platform_device_register_simple(dock_device_name,
 969                        dock_station_count, NULL, 0);
 970        dock_device = dock_station->dock_device;
 971        if (IS_ERR(dock_device)) {
 972                kfree(dock_station);
 973                dock_station = NULL;
 974                return PTR_ERR(dock_device);
 975        }
 976        platform_device_add_data(dock_device, &dock_station,
 977                sizeof(struct dock_station *));
 978
 979        /* we want the dock device to send uevents */
 980        dev_set_uevent_suppress(&dock_device->dev, 0);
 981
 982        if (is_dock(handle))
 983                dock_station->flags |= DOCK_IS_DOCK;
 984        if (is_ata(handle))
 985                dock_station->flags |= DOCK_IS_ATA;
 986        if (is_battery(handle))
 987                dock_station->flags |= DOCK_IS_BAT;
 988
 989        ret = device_create_file(&dock_device->dev, &dev_attr_docked);
 990        if (ret) {
 991                printk(KERN_ERR "Error %d adding sysfs file\n", ret);
 992                platform_device_unregister(dock_device);
 993                kfree(dock_station);
 994                dock_station = NULL;
 995                return ret;
 996        }
 997        ret = device_create_file(&dock_device->dev, &dev_attr_undock);
 998        if (ret) {
 999                printk(KERN_ERR "Error %d adding sysfs file\n", ret);
1000                device_remove_file(&dock_device->dev, &dev_attr_docked);
1001                platform_device_unregister(dock_device);
1002                kfree(dock_station);
1003                dock_station = NULL;
1004                return ret;
1005        }
1006        ret = device_create_file(&dock_device->dev, &dev_attr_uid);
1007        if (ret) {
1008                printk(KERN_ERR "Error %d adding sysfs file\n", ret);
1009                device_remove_file(&dock_device->dev, &dev_attr_docked);
1010                device_remove_file(&dock_device->dev, &dev_attr_undock);
1011                platform_device_unregister(dock_device);
1012                kfree(dock_station);
1013                dock_station = NULL;
1014                return ret;
1015        }
1016        ret = device_create_file(&dock_device->dev, &dev_attr_flags);
1017        if (ret) {
1018                printk(KERN_ERR "Error %d adding sysfs file\n", ret);
1019                device_remove_file(&dock_device->dev, &dev_attr_docked);
1020                device_remove_file(&dock_device->dev, &dev_attr_undock);
1021                device_remove_file(&dock_device->dev, &dev_attr_uid);
1022                platform_device_unregister(dock_device);
1023                kfree(dock_station);
1024                dock_station = NULL;
1025                return ret;
1026        }
1027        ret = device_create_file(&dock_device->dev, &dev_attr_type);
1028        if (ret)
1029                printk(KERN_ERR"Error %d adding sysfs file\n", ret);
1030
1031        /* Find dependent devices */
1032        acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
1033                            ACPI_UINT32_MAX, find_dock_devices, dock_station,
1034                            NULL);
1035
1036        /* add the dock station as a device dependent on itself */
1037        dd = alloc_dock_dependent_device(handle);
1038        if (!dd) {
1039                kfree(dock_station);
1040                dock_station = NULL;
1041                ret = -ENOMEM;
1042                goto dock_add_err_unregister;
1043        }
1044        add_dock_dependent_device(dock_station, dd);
1045
1046        dock_station_count++;
1047        list_add(&dock_station->sibling, &dock_stations);
1048        return 0;
1049
1050dock_add_err_unregister:
1051        device_remove_file(&dock_device->dev, &dev_attr_type);
1052        device_remove_file(&dock_device->dev, &dev_attr_docked);
1053        device_remove_file(&dock_device->dev, &dev_attr_undock);
1054        device_remove_file(&dock_device->dev, &dev_attr_uid);
1055        device_remove_file(&dock_device->dev, &dev_attr_flags);
1056        platform_device_unregister(dock_device);
1057        kfree(dock_station);
1058        dock_station = NULL;
1059        return ret;
1060}
1061
1062/**
1063 * dock_remove - free up resources related to the dock station
1064 */
1065static int dock_remove(struct dock_station *dock_station)
1066{
1067        struct dock_dependent_device *dd, *tmp;
1068        struct platform_device *dock_device = dock_station->dock_device;
1069
1070        if (!dock_station_count)
1071                return 0;
1072
1073        /* remove dependent devices */
1074        list_for_each_entry_safe(dd, tmp, &dock_station->dependent_devices,
1075                                 list)
1076            kfree(dd);
1077
1078        /* cleanup sysfs */
1079        device_remove_file(&dock_device->dev, &dev_attr_type);
1080        device_remove_file(&dock_device->dev, &dev_attr_docked);
1081        device_remove_file(&dock_device->dev, &dev_attr_undock);
1082        device_remove_file(&dock_device->dev, &dev_attr_uid);
1083        device_remove_file(&dock_device->dev, &dev_attr_flags);
1084        platform_device_unregister(dock_device);
1085
1086        /* free dock station memory */
1087        kfree(dock_station);
1088        dock_station = NULL;
1089        return 0;
1090}
1091
1092/**
1093 * find_dock - look for a dock station
1094 * @handle: acpi handle of a device
1095 * @lvl: unused
1096 * @context: counter of dock stations found
1097 * @rv: unused
1098 *
1099 * This is called by acpi_walk_namespace to look for dock stations.
1100 */
1101static acpi_status
1102find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
1103{
1104        acpi_status status = AE_OK;
1105
1106        if (is_dock(handle)) {
1107                if (dock_add(handle) >= 0) {
1108                        status = AE_CTRL_TERMINATE;
1109                }
1110        }
1111        return status;
1112}
1113
1114static acpi_status
1115find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
1116{
1117        /* If bay is a dock, it's already handled */
1118        if (is_ejectable_bay(handle) && !is_dock(handle))
1119                dock_add(handle);
1120        return AE_OK;
1121}
1122
1123static int __init dock_init(void)
1124{
1125        if (acpi_disabled)
1126                return 0;
1127
1128        /* look for a dock station */
1129        acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
1130                            ACPI_UINT32_MAX, find_dock, NULL, NULL);
1131
1132        /* look for bay */
1133        acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
1134                        ACPI_UINT32_MAX, find_bay, NULL, NULL);
1135        if (!dock_station_count) {
1136                printk(KERN_INFO PREFIX "No dock devices found.\n");
1137                return 0;
1138        }
1139
1140        register_acpi_bus_notifier(&dock_acpi_notifier);
1141        printk(KERN_INFO PREFIX "%s: %d docks/bays found\n",
1142                ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
1143        return 0;
1144}
1145
1146static void __exit dock_exit(void)
1147{
1148        struct dock_station *dock_station;
1149        struct dock_station *tmp;
1150
1151        unregister_acpi_bus_notifier(&dock_acpi_notifier);
1152        list_for_each_entry_safe(dock_station, tmp, &dock_stations, sibling)
1153                dock_remove(dock_station);
1154}
1155
1156/*
1157 * Must be called before drivers of devices in dock, otherwise we can't know
1158 * which devices are in a dock
1159 */
1160subsys_initcall(dock_init);
1161module_exit(dock_exit);
1162