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