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        struct acpi_device *parent_device;
 314        acpi_handle parent;
 315        int ret;
 316
 317        if (acpi_bus_get_device(handle, &device)) {
 318                /*
 319                 * no device created for this object,
 320                 * so we should create one.
 321                 */
 322                acpi_get_parent(handle, &parent);
 323                if (acpi_bus_get_device(parent, &parent_device))
 324                        parent_device = NULL;
 325
 326                ret = acpi_bus_add(&device, parent_device, handle,
 327                        ACPI_BUS_TYPE_DEVICE);
 328                if (ret) {
 329                        pr_debug("error adding bus, %x\n", -ret);
 330                        return NULL;
 331                }
 332        }
 333        return device;
 334}
 335
 336/**
 337 * dock_remove_acpi_device - remove the acpi_device struct from acpi
 338 * @handle - the handle of the device to remove
 339 *
 340 *  Tell acpi to remove the acpi_device.  This should cause any loaded
 341 *  driver to have it's remove routine called.
 342 */
 343static void dock_remove_acpi_device(acpi_handle handle)
 344{
 345        struct acpi_device *device;
 346        int ret;
 347
 348        if (!acpi_bus_get_device(handle, &device)) {
 349                ret = acpi_bus_trim(device, 1);
 350                if (ret)
 351                        pr_debug("error removing bus, %x\n", -ret);
 352        }
 353}
 354
 355/**
 356 * hotplug_dock_devices - insert or remove devices on the dock station
 357 * @ds: the dock station
 358 * @event: either bus check or eject request
 359 *
 360 * Some devices on the dock station need to have drivers called
 361 * to perform hotplug operations after a dock event has occurred.
 362 * Traverse the list of dock devices that have registered a
 363 * hotplug handler, and call the handler.
 364 */
 365static void hotplug_dock_devices(struct dock_station *ds, u32 event)
 366{
 367        struct dock_dependent_device *dd;
 368
 369        mutex_lock(&ds->hp_lock);
 370
 371        /*
 372         * First call driver specific hotplug functions
 373         */
 374        list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list)
 375                if (dd->ops && dd->ops->handler)
 376                        dd->ops->handler(dd->handle, event, dd->context);
 377
 378        /*
 379         * Now make sure that an acpi_device is created for each
 380         * dependent device, or removed if this is an eject request.
 381         * This will cause acpi_drivers to be stopped/started if they
 382         * exist
 383         */
 384        list_for_each_entry(dd, &ds->dependent_devices, list) {
 385                if (event == ACPI_NOTIFY_EJECT_REQUEST)
 386                        dock_remove_acpi_device(dd->handle);
 387                else
 388                        dock_create_acpi_device(dd->handle);
 389        }
 390        mutex_unlock(&ds->hp_lock);
 391}
 392
 393static void dock_event(struct dock_station *ds, u32 event, int num)
 394{
 395        struct device *dev = &ds->dock_device->dev;
 396        char event_string[13];
 397        char *envp[] = { event_string, NULL };
 398        struct dock_dependent_device *dd;
 399
 400        if (num == UNDOCK_EVENT)
 401                sprintf(event_string, "EVENT=undock");
 402        else
 403                sprintf(event_string, "EVENT=dock");
 404
 405        /*
 406         * Indicate that the status of the dock station has
 407         * changed.
 408         */
 409        if (num == DOCK_EVENT)
 410                kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
 411
 412        list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list)
 413                if (dd->ops && dd->ops->uevent)
 414                        dd->ops->uevent(dd->handle, event, dd->context);
 415
 416        if (num != DOCK_EVENT)
 417                kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
 418}
 419
 420/**
 421 * eject_dock - respond to a dock eject request
 422 * @ds: the dock station
 423 *
 424 * This is called after _DCK is called, to execute the dock station's
 425 * _EJ0 method.
 426 */
 427static void eject_dock(struct dock_station *ds)
 428{
 429        struct acpi_object_list arg_list;
 430        union acpi_object arg;
 431        acpi_status status;
 432        acpi_handle tmp;
 433
 434        /* all dock devices should have _EJ0, but check anyway */
 435        status = acpi_get_handle(ds->handle, "_EJ0", &tmp);
 436        if (ACPI_FAILURE(status)) {
 437                pr_debug("No _EJ0 support for dock device\n");
 438                return;
 439        }
 440
 441        arg_list.count = 1;
 442        arg_list.pointer = &arg;
 443        arg.type = ACPI_TYPE_INTEGER;
 444        arg.integer.value = 1;
 445
 446        status = acpi_evaluate_object(ds->handle, "_EJ0", &arg_list, NULL);
 447        if (ACPI_FAILURE(status))
 448                pr_debug("Failed to evaluate _EJ0!\n");
 449}
 450
 451/**
 452 * handle_dock - handle a dock event
 453 * @ds: the dock station
 454 * @dock: to dock, or undock - that is the question
 455 *
 456 * Execute the _DCK method in response to an acpi event
 457 */
 458static void handle_dock(struct dock_station *ds, int dock)
 459{
 460        acpi_status status;
 461        struct acpi_object_list arg_list;
 462        union acpi_object arg;
 463        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 464
 465        acpi_handle_info(ds->handle, "%s\n", dock ? "docking" : "undocking");
 466
 467        /* _DCK method has one argument */
 468        arg_list.count = 1;
 469        arg_list.pointer = &arg;
 470        arg.type = ACPI_TYPE_INTEGER;
 471        arg.integer.value = dock;
 472        status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
 473        if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
 474                acpi_handle_err(ds->handle, "Failed to execute _DCK (0x%x)\n",
 475                                status);
 476
 477        kfree(buffer.pointer);
 478}
 479
 480static inline void dock(struct dock_station *ds)
 481{
 482        handle_dock(ds, 1);
 483}
 484
 485static inline void undock(struct dock_station *ds)
 486{
 487        handle_dock(ds, 0);
 488}
 489
 490static inline void begin_dock(struct dock_station *ds)
 491{
 492        ds->flags |= DOCK_DOCKING;
 493}
 494
 495static inline void complete_dock(struct dock_station *ds)
 496{
 497        ds->flags &= ~(DOCK_DOCKING);
 498        ds->last_dock_time = jiffies;
 499}
 500
 501static inline void begin_undock(struct dock_station *ds)
 502{
 503        ds->flags |= DOCK_UNDOCKING;
 504}
 505
 506static inline void complete_undock(struct dock_station *ds)
 507{
 508        ds->flags &= ~(DOCK_UNDOCKING);
 509}
 510
 511static void dock_lock(struct dock_station *ds, int lock)
 512{
 513        struct acpi_object_list arg_list;
 514        union acpi_object arg;
 515        acpi_status status;
 516
 517        arg_list.count = 1;
 518        arg_list.pointer = &arg;
 519        arg.type = ACPI_TYPE_INTEGER;
 520        arg.integer.value = !!lock;
 521        status = acpi_evaluate_object(ds->handle, "_LCK", &arg_list, NULL);
 522        if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
 523                if (lock)
 524                        acpi_handle_warn(ds->handle,
 525                                "Locking device failed (0x%x)\n", status);
 526                else
 527                        acpi_handle_warn(ds->handle,
 528                                "Unlocking device failed (0x%x)\n", status);
 529        }
 530}
 531
 532/**
 533 * dock_in_progress - see if we are in the middle of handling a dock event
 534 * @ds: the dock station
 535 *
 536 * Sometimes while docking, false dock events can be sent to the driver
 537 * because good connections aren't made or some other reason.  Ignore these
 538 * if we are in the middle of doing something.
 539 */
 540static int dock_in_progress(struct dock_station *ds)
 541{
 542        if ((ds->flags & DOCK_DOCKING) ||
 543            time_before(jiffies, (ds->last_dock_time + HZ)))
 544                return 1;
 545        return 0;
 546}
 547
 548/**
 549 * register_dock_notifier - add yourself to the dock notifier list
 550 * @nb: the callers notifier block
 551 *
 552 * If a driver wishes to be notified about dock events, they can
 553 * use this function to put a notifier block on the dock notifier list.
 554 * this notifier call chain will be called after a dock event, but
 555 * before hotplugging any new devices.
 556 */
 557int register_dock_notifier(struct notifier_block *nb)
 558{
 559        if (!dock_station_count)
 560                return -ENODEV;
 561
 562        return atomic_notifier_chain_register(&dock_notifier_list, nb);
 563}
 564EXPORT_SYMBOL_GPL(register_dock_notifier);
 565
 566/**
 567 * unregister_dock_notifier - remove yourself from the dock notifier list
 568 * @nb: the callers notifier block
 569 */
 570void unregister_dock_notifier(struct notifier_block *nb)
 571{
 572        if (!dock_station_count)
 573                return;
 574
 575        atomic_notifier_chain_unregister(&dock_notifier_list, nb);
 576}
 577EXPORT_SYMBOL_GPL(unregister_dock_notifier);
 578
 579/**
 580 * register_hotplug_dock_device - register a hotplug function
 581 * @handle: the handle of the device
 582 * @ops: handlers to call after docking
 583 * @context: device specific data
 584 *
 585 * If a driver would like to perform a hotplug operation after a dock
 586 * event, they can register an acpi_notifiy_handler to be called by
 587 * the dock driver after _DCK is executed.
 588 */
 589int
 590register_hotplug_dock_device(acpi_handle handle, const struct acpi_dock_ops *ops,
 591                             void *context)
 592{
 593        struct dock_dependent_device *dd;
 594        struct dock_station *dock_station;
 595        int ret = -EINVAL;
 596
 597        if (!dock_station_count)
 598                return -ENODEV;
 599
 600        /*
 601         * make sure this handle is for a device dependent on the dock,
 602         * this would include the dock station itself
 603         */
 604        list_for_each_entry(dock_station, &dock_stations, sibling) {
 605                /*
 606                 * An ATA bay can be in a dock and itself can be ejected
 607                 * separately, so there are two 'dock stations' which need the
 608                 * ops
 609                 */
 610                dd = find_dock_dependent_device(dock_station, handle);
 611                if (dd) {
 612                        dd->ops = ops;
 613                        dd->context = context;
 614                        dock_add_hotplug_device(dock_station, dd);
 615                        ret = 0;
 616                }
 617        }
 618
 619        return ret;
 620}
 621EXPORT_SYMBOL_GPL(register_hotplug_dock_device);
 622
 623/**
 624 * unregister_hotplug_dock_device - remove yourself from the hotplug list
 625 * @handle: the acpi handle of the device
 626 */
 627void unregister_hotplug_dock_device(acpi_handle handle)
 628{
 629        struct dock_dependent_device *dd;
 630        struct dock_station *dock_station;
 631
 632        if (!dock_station_count)
 633                return;
 634
 635        list_for_each_entry(dock_station, &dock_stations, sibling) {
 636                dd = find_dock_dependent_device(dock_station, handle);
 637                if (dd)
 638                        dock_del_hotplug_device(dock_station, dd);
 639        }
 640}
 641EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
 642
 643/**
 644 * handle_eject_request - handle an undock request checking for error conditions
 645 *
 646 * Check to make sure the dock device is still present, then undock and
 647 * hotremove all the devices that may need removing.
 648 */
 649static int handle_eject_request(struct dock_station *ds, u32 event)
 650{
 651        if (dock_in_progress(ds))
 652                return -EBUSY;
 653
 654        /*
 655         * here we need to generate the undock
 656         * event prior to actually doing the undock
 657         * so that the device struct still exists.
 658         * Also, even send the dock event if the
 659         * device is not present anymore
 660         */
 661        dock_event(ds, event, UNDOCK_EVENT);
 662
 663        hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
 664        undock(ds);
 665        dock_lock(ds, 0);
 666        eject_dock(ds);
 667        if (dock_present(ds)) {
 668                acpi_handle_err(ds->handle, "Unable to undock!\n");
 669                return -EBUSY;
 670        }
 671        complete_undock(ds);
 672        return 0;
 673}
 674
 675/**
 676 * dock_notify - act upon an acpi dock notification
 677 * @handle: the dock station handle
 678 * @event: the acpi event
 679 * @data: our driver data struct
 680 *
 681 * If we are notified to dock, then check to see if the dock is
 682 * present and then dock.  Notify all drivers of the dock event,
 683 * and then hotplug and devices that may need hotplugging.
 684 */
 685static void dock_notify(acpi_handle handle, u32 event, void *data)
 686{
 687        struct dock_station *ds = data;
 688        struct acpi_device *tmp;
 689        int surprise_removal = 0;
 690
 691        /*
 692         * According to acpi spec 3.0a, if a DEVICE_CHECK notification
 693         * is sent and _DCK is present, it is assumed to mean an undock
 694         * request.
 695         */
 696        if ((ds->flags & DOCK_IS_DOCK) && event == ACPI_NOTIFY_DEVICE_CHECK)
 697                event = ACPI_NOTIFY_EJECT_REQUEST;
 698
 699        /*
 700         * dock station: BUS_CHECK - docked or surprise removal
 701         *               DEVICE_CHECK - undocked
 702         * other device: BUS_CHECK/DEVICE_CHECK - added or surprise removal
 703         *
 704         * To simplify event handling, dock dependent device handler always
 705         * get ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and
 706         * ACPI_NOTIFY_EJECT_REQUEST for removal
 707         */
 708        switch (event) {
 709        case ACPI_NOTIFY_BUS_CHECK:
 710        case ACPI_NOTIFY_DEVICE_CHECK:
 711                if (!dock_in_progress(ds) && acpi_bus_get_device(ds->handle,
 712                   &tmp)) {
 713                        begin_dock(ds);
 714                        dock(ds);
 715                        if (!dock_present(ds)) {
 716                                acpi_handle_err(handle, "Unable to dock!\n");
 717                                complete_dock(ds);
 718                                break;
 719                        }
 720                        atomic_notifier_call_chain(&dock_notifier_list,
 721                                                   event, NULL);
 722                        hotplug_dock_devices(ds, event);
 723                        complete_dock(ds);
 724                        dock_event(ds, event, DOCK_EVENT);
 725                        dock_lock(ds, 1);
 726                        acpi_update_all_gpes();
 727                        break;
 728                }
 729                if (dock_present(ds) || dock_in_progress(ds))
 730                        break;
 731                /* This is a surprise removal */
 732                surprise_removal = 1;
 733                event = ACPI_NOTIFY_EJECT_REQUEST;
 734                /* Fall back */
 735        case ACPI_NOTIFY_EJECT_REQUEST:
 736                begin_undock(ds);
 737                if ((immediate_undock && !(ds->flags & DOCK_IS_ATA))
 738                   || surprise_removal)
 739                        handle_eject_request(ds, event);
 740                else
 741                        dock_event(ds, event, UNDOCK_EVENT);
 742                break;
 743        default:
 744                acpi_handle_err(handle, "Unknown dock event %d\n", event);
 745        }
 746}
 747
 748struct dock_data {
 749        acpi_handle handle;
 750        unsigned long event;
 751        struct dock_station *ds;
 752};
 753
 754static void acpi_dock_deferred_cb(void *context)
 755{
 756        struct dock_data *data = context;
 757
 758        dock_notify(data->handle, data->event, data->ds);
 759        kfree(data);
 760}
 761
 762static int acpi_dock_notifier_call(struct notifier_block *this,
 763        unsigned long event, void *data)
 764{
 765        struct dock_station *dock_station;
 766        acpi_handle handle = data;
 767
 768        if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
 769           && event != ACPI_NOTIFY_EJECT_REQUEST)
 770                return 0;
 771        list_for_each_entry(dock_station, &dock_stations, sibling) {
 772                if (dock_station->handle == handle) {
 773                        struct dock_data *dd;
 774
 775                        dd = kmalloc(sizeof(*dd), GFP_KERNEL);
 776                        if (!dd)
 777                                return 0;
 778                        dd->handle = handle;
 779                        dd->event = event;
 780                        dd->ds = dock_station;
 781                        acpi_os_hotplug_execute(acpi_dock_deferred_cb, dd);
 782                        return 0 ;
 783                }
 784        }
 785        return 0;
 786}
 787
 788static struct notifier_block dock_acpi_notifier = {
 789        .notifier_call = acpi_dock_notifier_call,
 790};
 791
 792/**
 793 * find_dock_devices - find devices on the dock station
 794 * @handle: the handle of the device we are examining
 795 * @lvl: unused
 796 * @context: the dock station private data
 797 * @rv: unused
 798 *
 799 * This function is called by acpi_walk_namespace.  It will
 800 * check to see if an object has an _EJD method.  If it does, then it
 801 * will see if it is dependent on the dock station.
 802 */
 803static acpi_status
 804find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv)
 805{
 806        acpi_status status;
 807        acpi_handle tmp, parent;
 808        struct dock_station *ds = context;
 809
 810        status = acpi_bus_get_ejd(handle, &tmp);
 811        if (ACPI_FAILURE(status)) {
 812                /* try the parent device as well */
 813                status = acpi_get_parent(handle, &parent);
 814                if (ACPI_FAILURE(status))
 815                        goto fdd_out;
 816                /* see if parent is dependent on dock */
 817                status = acpi_bus_get_ejd(parent, &tmp);
 818                if (ACPI_FAILURE(status))
 819                        goto fdd_out;
 820        }
 821
 822        if (tmp == ds->handle)
 823                add_dock_dependent_device(ds, handle);
 824
 825fdd_out:
 826        return AE_OK;
 827}
 828
 829/*
 830 * show_docked - read method for "docked" file in sysfs
 831 */
 832static ssize_t show_docked(struct device *dev,
 833                           struct device_attribute *attr, char *buf)
 834{
 835        struct acpi_device *tmp;
 836
 837        struct dock_station *dock_station = dev->platform_data;
 838
 839        if (ACPI_SUCCESS(acpi_bus_get_device(dock_station->handle, &tmp)))
 840                return snprintf(buf, PAGE_SIZE, "1\n");
 841        return snprintf(buf, PAGE_SIZE, "0\n");
 842}
 843static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
 844
 845/*
 846 * show_flags - read method for flags file in sysfs
 847 */
 848static ssize_t show_flags(struct device *dev,
 849                          struct device_attribute *attr, char *buf)
 850{
 851        struct dock_station *dock_station = dev->platform_data;
 852        return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);
 853
 854}
 855static DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
 856
 857/*
 858 * write_undock - write method for "undock" file in sysfs
 859 */
 860static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
 861                           const char *buf, size_t count)
 862{
 863        int ret;
 864        struct dock_station *dock_station = dev->platform_data;
 865
 866        if (!count)
 867                return -EINVAL;
 868
 869        begin_undock(dock_station);
 870        ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST);
 871        return ret ? ret: count;
 872}
 873static DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock);
 874
 875/*
 876 * show_dock_uid - read method for "uid" file in sysfs
 877 */
 878static ssize_t show_dock_uid(struct device *dev,
 879                             struct device_attribute *attr, char *buf)
 880{
 881        unsigned long long lbuf;
 882        struct dock_station *dock_station = dev->platform_data;
 883        acpi_status status = acpi_evaluate_integer(dock_station->handle,
 884                                        "_UID", NULL, &lbuf);
 885        if (ACPI_FAILURE(status))
 886            return 0;
 887
 888        return snprintf(buf, PAGE_SIZE, "%llx\n", lbuf);
 889}
 890static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
 891
 892static ssize_t show_dock_type(struct device *dev,
 893                struct device_attribute *attr, char *buf)
 894{
 895        struct dock_station *dock_station = dev->platform_data;
 896        char *type;
 897
 898        if (dock_station->flags & DOCK_IS_DOCK)
 899                type = "dock_station";
 900        else if (dock_station->flags & DOCK_IS_ATA)
 901                type = "ata_bay";
 902        else if (dock_station->flags & DOCK_IS_BAT)
 903                type = "battery_bay";
 904        else
 905                type = "unknown";
 906
 907        return snprintf(buf, PAGE_SIZE, "%s\n", type);
 908}
 909static DEVICE_ATTR(type, S_IRUGO, show_dock_type, NULL);
 910
 911static struct attribute *dock_attributes[] = {
 912        &dev_attr_docked.attr,
 913        &dev_attr_flags.attr,
 914        &dev_attr_undock.attr,
 915        &dev_attr_uid.attr,
 916        &dev_attr_type.attr,
 917        NULL
 918};
 919
 920static struct attribute_group dock_attribute_group = {
 921        .attrs = dock_attributes
 922};
 923
 924/**
 925 * dock_add - add a new dock station
 926 * @handle: the dock station handle
 927 *
 928 * allocated and initialize a new dock station device.  Find all devices
 929 * that are on the dock station, and register for dock event notifications.
 930 */
 931static int __init dock_add(acpi_handle handle)
 932{
 933        int ret, id;
 934        struct dock_station ds, *dock_station;
 935        struct platform_device *dd;
 936
 937        id = dock_station_count;
 938        memset(&ds, 0, sizeof(ds));
 939        dd = platform_device_register_data(NULL, "dock", id, &ds, sizeof(ds));
 940        if (IS_ERR(dd))
 941                return PTR_ERR(dd);
 942
 943        dock_station = dd->dev.platform_data;
 944
 945        dock_station->handle = handle;
 946        dock_station->dock_device = dd;
 947        dock_station->last_dock_time = jiffies - HZ;
 948
 949        mutex_init(&dock_station->hp_lock);
 950        spin_lock_init(&dock_station->dd_lock);
 951        INIT_LIST_HEAD(&dock_station->sibling);
 952        INIT_LIST_HEAD(&dock_station->hotplug_devices);
 953        ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
 954        INIT_LIST_HEAD(&dock_station->dependent_devices);
 955
 956        /* we want the dock device to send uevents */
 957        dev_set_uevent_suppress(&dd->dev, 0);
 958
 959        if (is_dock(handle))
 960                dock_station->flags |= DOCK_IS_DOCK;
 961        if (is_ata(handle))
 962                dock_station->flags |= DOCK_IS_ATA;
 963        if (is_battery(handle))
 964                dock_station->flags |= DOCK_IS_BAT;
 965
 966        ret = sysfs_create_group(&dd->dev.kobj, &dock_attribute_group);
 967        if (ret)
 968                goto err_unregister;
 969
 970        /* Find dependent devices */
 971        acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
 972                            ACPI_UINT32_MAX, find_dock_devices, NULL,
 973                            dock_station, NULL);
 974
 975        /* add the dock station as a device dependent on itself */
 976        ret = add_dock_dependent_device(dock_station, handle);
 977        if (ret)
 978                goto err_rmgroup;
 979
 980        dock_station_count++;
 981        list_add(&dock_station->sibling, &dock_stations);
 982        return 0;
 983
 984err_rmgroup:
 985        sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group);
 986err_unregister:
 987        platform_device_unregister(dd);
 988        acpi_handle_err(handle, "%s encountered error %d\n", __func__, ret);
 989        return ret;
 990}
 991
 992/**
 993 * dock_remove - free up resources related to the dock station
 994 */
 995static int dock_remove(struct dock_station *ds)
 996{
 997        struct dock_dependent_device *dd, *tmp;
 998        struct platform_device *dock_device = ds->dock_device;
 999
1000        if (!dock_station_count)
1001                return 0;
1002
1003        /* remove dependent devices */
1004        list_for_each_entry_safe(dd, tmp, &ds->dependent_devices, list)
1005                kfree(dd);
1006
1007        list_del(&ds->sibling);
1008
1009        /* cleanup sysfs */
1010        sysfs_remove_group(&dock_device->dev.kobj, &dock_attribute_group);
1011        platform_device_unregister(dock_device);
1012
1013        return 0;
1014}
1015
1016/**
1017 * find_dock_and_bay - look for dock stations and bays
1018 * @handle: acpi handle of a device
1019 * @lvl: unused
1020 * @context: unused
1021 * @rv: unused
1022 *
1023 * This is called by acpi_walk_namespace to look for dock stations and bays.
1024 */
1025static __init acpi_status
1026find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
1027{
1028        if (is_dock(handle) || is_ejectable_bay(handle))
1029                dock_add(handle);
1030
1031        return AE_OK;
1032}
1033
1034static int __init dock_init(void)
1035{
1036        if (acpi_disabled)
1037                return 0;
1038
1039        /* look for dock stations and bays */
1040        acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
1041                ACPI_UINT32_MAX, find_dock_and_bay, NULL, NULL, NULL);
1042
1043        if (!dock_station_count) {
1044                pr_info(PREFIX "No dock devices found.\n");
1045                return 0;
1046        }
1047
1048        register_acpi_bus_notifier(&dock_acpi_notifier);
1049        pr_info(PREFIX "%s: %d docks/bays found\n",
1050                ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
1051        return 0;
1052}
1053
1054static void __exit dock_exit(void)
1055{
1056        struct dock_station *tmp, *dock_station;
1057
1058        unregister_acpi_bus_notifier(&dock_acpi_notifier);
1059        list_for_each_entry_safe(dock_station, tmp, &dock_stations, sibling)
1060                dock_remove(dock_station);
1061}
1062
1063/*
1064 * Must be called before drivers of devices in dock, otherwise we can't know
1065 * which devices are in a dock
1066 */
1067subsys_initcall(dock_init);
1068module_exit(dock_exit);
1069
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.