root/drivers/acpi/dock.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. add_dock_dependent_device
  2. dock_hotplug_event
  3. find_dock_station
  4. find_dock_dependent_device
  5. register_dock_dependent_device
  6. is_dock_device
  7. dock_present
  8. hot_remove_dock_devices
  9. hotplug_dock_devices
  10. dock_event
  11. handle_dock
  12. dock
  13. undock
  14. begin_dock
  15. complete_dock
  16. begin_undock
  17. complete_undock
  18. dock_in_progress
  19. handle_eject_request
  20. dock_notify
  21. show_docked
  22. show_flags
  23. write_undock
  24. show_dock_uid
  25. show_dock_type
  26. acpi_dock_add

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  dock.c - ACPI dock station driver
   4  *
   5  *  Copyright (C) 2006, 2014, Intel Corp.
   6  *  Author: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
   7  *          Rafael J. Wysocki <rafael.j.wysocki@intel.com>
   8  */
   9 
  10 #include <linux/kernel.h>
  11 #include <linux/moduleparam.h>
  12 #include <linux/slab.h>
  13 #include <linux/init.h>
  14 #include <linux/types.h>
  15 #include <linux/notifier.h>
  16 #include <linux/platform_device.h>
  17 #include <linux/jiffies.h>
  18 #include <linux/stddef.h>
  19 #include <linux/acpi.h>
  20 
  21 #include "internal.h"
  22 
  23 ACPI_MODULE_NAME("dock");
  24 
  25 static bool immediate_undock = 1;
  26 module_param(immediate_undock, bool, 0644);
  27 MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to "
  28         "undock immediately when the undock button is pressed, 0 will cause"
  29         " the driver to wait for userspace to write the undock sysfs file "
  30         " before undocking");
  31 
  32 struct dock_station {
  33         acpi_handle handle;
  34         unsigned long last_dock_time;
  35         u32 flags;
  36         struct list_head dependent_devices;
  37 
  38         struct list_head sibling;
  39         struct platform_device *dock_device;
  40 };
  41 static LIST_HEAD(dock_stations);
  42 static int dock_station_count;
  43 
  44 struct dock_dependent_device {
  45         struct list_head list;
  46         struct acpi_device *adev;
  47 };
  48 
  49 #define DOCK_DOCKING    0x00000001
  50 #define DOCK_UNDOCKING  0x00000002
  51 #define DOCK_IS_DOCK    0x00000010
  52 #define DOCK_IS_ATA     0x00000020
  53 #define DOCK_IS_BAT     0x00000040
  54 #define DOCK_EVENT      3
  55 #define UNDOCK_EVENT    2
  56 
  57 enum dock_callback_type {
  58         DOCK_CALL_HANDLER,
  59         DOCK_CALL_FIXUP,
  60         DOCK_CALL_UEVENT,
  61 };
  62 
  63 /*****************************************************************************
  64  *                         Dock Dependent device functions                   *
  65  *****************************************************************************/
  66 /**
  67  * add_dock_dependent_device - associate a device with the dock station
  68  * @ds: Dock station.
  69  * @adev: Dependent ACPI device object.
  70  *
  71  * Add the dependent device to the dock's dependent device list.
  72  */
  73 static int add_dock_dependent_device(struct dock_station *ds,
  74                                      struct acpi_device *adev)
  75 {
  76         struct dock_dependent_device *dd;
  77 
  78         dd = kzalloc(sizeof(*dd), GFP_KERNEL);
  79         if (!dd)
  80                 return -ENOMEM;
  81 
  82         dd->adev = adev;
  83         INIT_LIST_HEAD(&dd->list);
  84         list_add_tail(&dd->list, &ds->dependent_devices);
  85 
  86         return 0;
  87 }
  88 
  89 static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
  90                                enum dock_callback_type cb_type)
  91 {
  92         struct acpi_device *adev = dd->adev;
  93 
  94         acpi_lock_hp_context();
  95 
  96         if (!adev->hp)
  97                 goto out;
  98 
  99         if (cb_type == DOCK_CALL_FIXUP) {
 100                 void (*fixup)(struct acpi_device *);
 101 
 102                 fixup = adev->hp->fixup;
 103                 if (fixup) {
 104                         acpi_unlock_hp_context();
 105                         fixup(adev);
 106                         return;
 107                 }
 108         } else if (cb_type == DOCK_CALL_UEVENT) {
 109                 void (*uevent)(struct acpi_device *, u32);
 110 
 111                 uevent = adev->hp->uevent;
 112                 if (uevent) {
 113                         acpi_unlock_hp_context();
 114                         uevent(adev, event);
 115                         return;
 116                 }
 117         } else {
 118                 int (*notify)(struct acpi_device *, u32);
 119 
 120                 notify = adev->hp->notify;
 121                 if (notify) {
 122                         acpi_unlock_hp_context();
 123                         notify(adev, event);
 124                         return;
 125                 }
 126         }
 127 
 128  out:
 129         acpi_unlock_hp_context();
 130 }
 131 
 132 static struct dock_station *find_dock_station(acpi_handle handle)
 133 {
 134         struct dock_station *ds;
 135 
 136         list_for_each_entry(ds, &dock_stations, sibling)
 137                 if (ds->handle == handle)
 138                         return ds;
 139 
 140         return NULL;
 141 }
 142 
 143 /**
 144  * find_dock_dependent_device - get a device dependent on this dock
 145  * @ds: the dock station
 146  * @adev: ACPI device object to find.
 147  *
 148  * iterate over the dependent device list for this dock.  If the
 149  * dependent device matches the handle, return.
 150  */
 151 static struct dock_dependent_device *
 152 find_dock_dependent_device(struct dock_station *ds, struct acpi_device *adev)
 153 {
 154         struct dock_dependent_device *dd;
 155 
 156         list_for_each_entry(dd, &ds->dependent_devices, list)
 157                 if (adev == dd->adev)
 158                         return dd;
 159 
 160         return NULL;
 161 }
 162 
 163 void register_dock_dependent_device(struct acpi_device *adev,
 164                                     acpi_handle dshandle)
 165 {
 166         struct dock_station *ds = find_dock_station(dshandle);
 167 
 168         if (ds && !find_dock_dependent_device(ds, adev))
 169                 add_dock_dependent_device(ds, adev);
 170 }
 171 
 172 /*****************************************************************************
 173  *                         Dock functions                                    *
 174  *****************************************************************************/
 175 
 176 /**
 177  * is_dock_device - see if a device is on a dock station
 178  * @adev: ACPI device object to check.
 179  *
 180  * If this device is either the dock station itself,
 181  * or is a device dependent on the dock station, then it
 182  * is a dock device
 183  */
 184 int is_dock_device(struct acpi_device *adev)
 185 {
 186         struct dock_station *dock_station;
 187 
 188         if (!dock_station_count)
 189                 return 0;
 190 
 191         if (acpi_dock_match(adev->handle))
 192                 return 1;
 193 
 194         list_for_each_entry(dock_station, &dock_stations, sibling)
 195                 if (find_dock_dependent_device(dock_station, adev))
 196                         return 1;
 197 
 198         return 0;
 199 }
 200 EXPORT_SYMBOL_GPL(is_dock_device);
 201 
 202 /**
 203  * dock_present - see if the dock station is present.
 204  * @ds: the dock station
 205  *
 206  * execute the _STA method.  note that present does not
 207  * imply that we are docked.
 208  */
 209 static int dock_present(struct dock_station *ds)
 210 {
 211         unsigned long long sta;
 212         acpi_status status;
 213 
 214         if (ds) {
 215                 status = acpi_evaluate_integer(ds->handle, "_STA", NULL, &sta);
 216                 if (ACPI_SUCCESS(status) && sta)
 217                         return 1;
 218         }
 219         return 0;
 220 }
 221 
 222 /**
 223  * hot_remove_dock_devices - Remove dock station devices.
 224  * @ds: Dock station.
 225  */
 226 static void hot_remove_dock_devices(struct dock_station *ds)
 227 {
 228         struct dock_dependent_device *dd;
 229 
 230         /*
 231          * Walk the list in reverse order so that devices that have been added
 232          * last are removed first (in case there are some indirect dependencies
 233          * between them).
 234          */
 235         list_for_each_entry_reverse(dd, &ds->dependent_devices, list)
 236                 dock_hotplug_event(dd, ACPI_NOTIFY_EJECT_REQUEST, false);
 237 
 238         list_for_each_entry_reverse(dd, &ds->dependent_devices, list)
 239                 acpi_bus_trim(dd->adev);
 240 }
 241 
 242 /**
 243  * hotplug_dock_devices - Insert devices on a dock station.
 244  * @ds: the dock station
 245  * @event: either bus check or device check request
 246  *
 247  * Some devices on the dock station need to have drivers called
 248  * to perform hotplug operations after a dock event has occurred.
 249  * Traverse the list of dock devices that have registered a
 250  * hotplug handler, and call the handler.
 251  */
 252 static void hotplug_dock_devices(struct dock_station *ds, u32 event)
 253 {
 254         struct dock_dependent_device *dd;
 255 
 256         /* Call driver specific post-dock fixups. */
 257         list_for_each_entry(dd, &ds->dependent_devices, list)
 258                 dock_hotplug_event(dd, event, DOCK_CALL_FIXUP);
 259 
 260         /* Call driver specific hotplug functions. */
 261         list_for_each_entry(dd, &ds->dependent_devices, list)
 262                 dock_hotplug_event(dd, event, DOCK_CALL_HANDLER);
 263 
 264         /*
 265          * Check if all devices have been enumerated already.  If not, run
 266          * acpi_bus_scan() for them and that will cause scan handlers to be
 267          * attached to device objects or acpi_drivers to be stopped/started if
 268          * they are present.
 269          */
 270         list_for_each_entry(dd, &ds->dependent_devices, list) {
 271                 struct acpi_device *adev = dd->adev;
 272 
 273                 if (!acpi_device_enumerated(adev)) {
 274                         int ret = acpi_bus_scan(adev->handle);
 275                         if (ret)
 276                                 dev_dbg(&adev->dev, "scan error %d\n", -ret);
 277                 }
 278         }
 279 }
 280 
 281 static void dock_event(struct dock_station *ds, u32 event, int num)
 282 {
 283         struct device *dev = &ds->dock_device->dev;
 284         char event_string[13];
 285         char *envp[] = { event_string, NULL };
 286         struct dock_dependent_device *dd;
 287 
 288         if (num == UNDOCK_EVENT)
 289                 sprintf(event_string, "EVENT=undock");
 290         else
 291                 sprintf(event_string, "EVENT=dock");
 292 
 293         /*
 294          * Indicate that the status of the dock station has
 295          * changed.
 296          */
 297         if (num == DOCK_EVENT)
 298                 kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
 299 
 300         list_for_each_entry(dd, &ds->dependent_devices, list)
 301                 dock_hotplug_event(dd, event, DOCK_CALL_UEVENT);
 302 
 303         if (num != DOCK_EVENT)
 304                 kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
 305 }
 306 
 307 /**
 308  * handle_dock - handle a dock event
 309  * @ds: the dock station
 310  * @dock: to dock, or undock - that is the question
 311  *
 312  * Execute the _DCK method in response to an acpi event
 313  */
 314 static void handle_dock(struct dock_station *ds, int dock)
 315 {
 316         acpi_status status;
 317         struct acpi_object_list arg_list;
 318         union acpi_object arg;
 319         unsigned long long value;
 320 
 321         acpi_handle_info(ds->handle, "%s\n", dock ? "docking" : "undocking");
 322 
 323         /* _DCK method has one argument */
 324         arg_list.count = 1;
 325         arg_list.pointer = &arg;
 326         arg.type = ACPI_TYPE_INTEGER;
 327         arg.integer.value = dock;
 328         status = acpi_evaluate_integer(ds->handle, "_DCK", &arg_list, &value);
 329         if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
 330                 acpi_handle_err(ds->handle, "Failed to execute _DCK (0x%x)\n",
 331                                 status);
 332 }
 333 
 334 static inline void dock(struct dock_station *ds)
 335 {
 336         handle_dock(ds, 1);
 337 }
 338 
 339 static inline void undock(struct dock_station *ds)
 340 {
 341         handle_dock(ds, 0);
 342 }
 343 
 344 static inline void begin_dock(struct dock_station *ds)
 345 {
 346         ds->flags |= DOCK_DOCKING;
 347 }
 348 
 349 static inline void complete_dock(struct dock_station *ds)
 350 {
 351         ds->flags &= ~(DOCK_DOCKING);
 352         ds->last_dock_time = jiffies;
 353 }
 354 
 355 static inline void begin_undock(struct dock_station *ds)
 356 {
 357         ds->flags |= DOCK_UNDOCKING;
 358 }
 359 
 360 static inline void complete_undock(struct dock_station *ds)
 361 {
 362         ds->flags &= ~(DOCK_UNDOCKING);
 363 }
 364 
 365 /**
 366  * dock_in_progress - see if we are in the middle of handling a dock event
 367  * @ds: the dock station
 368  *
 369  * Sometimes while docking, false dock events can be sent to the driver
 370  * because good connections aren't made or some other reason.  Ignore these
 371  * if we are in the middle of doing something.
 372  */
 373 static int dock_in_progress(struct dock_station *ds)
 374 {
 375         if ((ds->flags & DOCK_DOCKING) ||
 376             time_before(jiffies, (ds->last_dock_time + HZ)))
 377                 return 1;
 378         return 0;
 379 }
 380 
 381 /**
 382  * handle_eject_request - handle an undock request checking for error conditions
 383  *
 384  * Check to make sure the dock device is still present, then undock and
 385  * hotremove all the devices that may need removing.
 386  */
 387 static int handle_eject_request(struct dock_station *ds, u32 event)
 388 {
 389         if (dock_in_progress(ds))
 390                 return -EBUSY;
 391 
 392         /*
 393          * here we need to generate the undock
 394          * event prior to actually doing the undock
 395          * so that the device struct still exists.
 396          * Also, even send the dock event if the
 397          * device is not present anymore
 398          */
 399         dock_event(ds, event, UNDOCK_EVENT);
 400 
 401         hot_remove_dock_devices(ds);
 402         undock(ds);
 403         acpi_evaluate_lck(ds->handle, 0);
 404         acpi_evaluate_ej0(ds->handle);
 405         if (dock_present(ds)) {
 406                 acpi_handle_err(ds->handle, "Unable to undock!\n");
 407                 return -EBUSY;
 408         }
 409         complete_undock(ds);
 410         return 0;
 411 }
 412 
 413 /**
 414  * dock_notify - Handle ACPI dock notification.
 415  * @adev: Dock station's ACPI device object.
 416  * @event: Event code.
 417  *
 418  * If we are notified to dock, then check to see if the dock is
 419  * present and then dock.  Notify all drivers of the dock event,
 420  * and then hotplug and devices that may need hotplugging.
 421  */
 422 int dock_notify(struct acpi_device *adev, u32 event)
 423 {
 424         acpi_handle handle = adev->handle;
 425         struct dock_station *ds = find_dock_station(handle);
 426         int surprise_removal = 0;
 427 
 428         if (!ds)
 429                 return -ENODEV;
 430 
 431         /*
 432          * According to acpi spec 3.0a, if a DEVICE_CHECK notification
 433          * is sent and _DCK is present, it is assumed to mean an undock
 434          * request.
 435          */
 436         if ((ds->flags & DOCK_IS_DOCK) && event == ACPI_NOTIFY_DEVICE_CHECK)
 437                 event = ACPI_NOTIFY_EJECT_REQUEST;
 438 
 439         /*
 440          * dock station: BUS_CHECK - docked or surprise removal
 441          *               DEVICE_CHECK - undocked
 442          * other device: BUS_CHECK/DEVICE_CHECK - added or surprise removal
 443          *
 444          * To simplify event handling, dock dependent device handler always
 445          * get ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and
 446          * ACPI_NOTIFY_EJECT_REQUEST for removal
 447          */
 448         switch (event) {
 449         case ACPI_NOTIFY_BUS_CHECK:
 450         case ACPI_NOTIFY_DEVICE_CHECK:
 451                 if (!dock_in_progress(ds) && !acpi_device_enumerated(adev)) {
 452                         begin_dock(ds);
 453                         dock(ds);
 454                         if (!dock_present(ds)) {
 455                                 acpi_handle_err(handle, "Unable to dock!\n");
 456                                 complete_dock(ds);
 457                                 break;
 458                         }
 459                         hotplug_dock_devices(ds, event);
 460                         complete_dock(ds);
 461                         dock_event(ds, event, DOCK_EVENT);
 462                         acpi_evaluate_lck(ds->handle, 1);
 463                         acpi_update_all_gpes();
 464                         break;
 465                 }
 466                 if (dock_present(ds) || dock_in_progress(ds))
 467                         break;
 468                 /* This is a surprise removal */
 469                 surprise_removal = 1;
 470                 event = ACPI_NOTIFY_EJECT_REQUEST;
 471                 /* Fall back */
 472                 /* fall through */
 473         case ACPI_NOTIFY_EJECT_REQUEST:
 474                 begin_undock(ds);
 475                 if ((immediate_undock && !(ds->flags & DOCK_IS_ATA))
 476                    || surprise_removal)
 477                         handle_eject_request(ds, event);
 478                 else
 479                         dock_event(ds, event, UNDOCK_EVENT);
 480                 break;
 481         }
 482         return 0;
 483 }
 484 
 485 /*
 486  * show_docked - read method for "docked" file in sysfs
 487  */
 488 static ssize_t show_docked(struct device *dev,
 489                            struct device_attribute *attr, char *buf)
 490 {
 491         struct dock_station *dock_station = dev->platform_data;
 492         struct acpi_device *adev = NULL;
 493 
 494         acpi_bus_get_device(dock_station->handle, &adev);
 495         return snprintf(buf, PAGE_SIZE, "%u\n", acpi_device_enumerated(adev));
 496 }
 497 static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
 498 
 499 /*
 500  * show_flags - read method for flags file in sysfs
 501  */
 502 static ssize_t show_flags(struct device *dev,
 503                           struct device_attribute *attr, char *buf)
 504 {
 505         struct dock_station *dock_station = dev->platform_data;
 506         return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);
 507 
 508 }
 509 static DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
 510 
 511 /*
 512  * write_undock - write method for "undock" file in sysfs
 513  */
 514 static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
 515                            const char *buf, size_t count)
 516 {
 517         int ret;
 518         struct dock_station *dock_station = dev->platform_data;
 519 
 520         if (!count)
 521                 return -EINVAL;
 522 
 523         acpi_scan_lock_acquire();
 524         begin_undock(dock_station);
 525         ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST);
 526         acpi_scan_lock_release();
 527         return ret ? ret: count;
 528 }
 529 static DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock);
 530 
 531 /*
 532  * show_dock_uid - read method for "uid" file in sysfs
 533  */
 534 static ssize_t show_dock_uid(struct device *dev,
 535                              struct device_attribute *attr, char *buf)
 536 {
 537         unsigned long long lbuf;
 538         struct dock_station *dock_station = dev->platform_data;
 539         acpi_status status = acpi_evaluate_integer(dock_station->handle,
 540                                         "_UID", NULL, &lbuf);
 541         if (ACPI_FAILURE(status))
 542             return 0;
 543 
 544         return snprintf(buf, PAGE_SIZE, "%llx\n", lbuf);
 545 }
 546 static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
 547 
 548 static ssize_t show_dock_type(struct device *dev,
 549                 struct device_attribute *attr, char *buf)
 550 {
 551         struct dock_station *dock_station = dev->platform_data;
 552         char *type;
 553 
 554         if (dock_station->flags & DOCK_IS_DOCK)
 555                 type = "dock_station";
 556         else if (dock_station->flags & DOCK_IS_ATA)
 557                 type = "ata_bay";
 558         else if (dock_station->flags & DOCK_IS_BAT)
 559                 type = "battery_bay";
 560         else
 561                 type = "unknown";
 562 
 563         return snprintf(buf, PAGE_SIZE, "%s\n", type);
 564 }
 565 static DEVICE_ATTR(type, S_IRUGO, show_dock_type, NULL);
 566 
 567 static struct attribute *dock_attributes[] = {
 568         &dev_attr_docked.attr,
 569         &dev_attr_flags.attr,
 570         &dev_attr_undock.attr,
 571         &dev_attr_uid.attr,
 572         &dev_attr_type.attr,
 573         NULL
 574 };
 575 
 576 static const struct attribute_group dock_attribute_group = {
 577         .attrs = dock_attributes
 578 };
 579 
 580 /**
 581  * acpi_dock_add - Add a new dock station
 582  * @adev: Dock station ACPI device object.
 583  *
 584  * allocated and initialize a new dock station device.
 585  */
 586 void acpi_dock_add(struct acpi_device *adev)
 587 {
 588         struct dock_station *dock_station, ds = { NULL, };
 589         struct platform_device_info pdevinfo;
 590         acpi_handle handle = adev->handle;
 591         struct platform_device *dd;
 592         int ret;
 593 
 594         memset(&pdevinfo, 0, sizeof(pdevinfo));
 595         pdevinfo.name = "dock";
 596         pdevinfo.id = dock_station_count;
 597         pdevinfo.fwnode = acpi_fwnode_handle(adev);
 598         pdevinfo.data = &ds;
 599         pdevinfo.size_data = sizeof(ds);
 600         dd = platform_device_register_full(&pdevinfo);
 601         if (IS_ERR(dd))
 602                 return;
 603 
 604         dock_station = dd->dev.platform_data;
 605 
 606         dock_station->handle = handle;
 607         dock_station->dock_device = dd;
 608         dock_station->last_dock_time = jiffies - HZ;
 609 
 610         INIT_LIST_HEAD(&dock_station->sibling);
 611         INIT_LIST_HEAD(&dock_station->dependent_devices);
 612 
 613         /* we want the dock device to send uevents */
 614         dev_set_uevent_suppress(&dd->dev, 0);
 615 
 616         if (acpi_dock_match(handle))
 617                 dock_station->flags |= DOCK_IS_DOCK;
 618         if (acpi_ata_match(handle))
 619                 dock_station->flags |= DOCK_IS_ATA;
 620         if (acpi_device_is_battery(adev))
 621                 dock_station->flags |= DOCK_IS_BAT;
 622 
 623         ret = sysfs_create_group(&dd->dev.kobj, &dock_attribute_group);
 624         if (ret)
 625                 goto err_unregister;
 626 
 627         /* add the dock station as a device dependent on itself */
 628         ret = add_dock_dependent_device(dock_station, adev);
 629         if (ret)
 630                 goto err_rmgroup;
 631 
 632         dock_station_count++;
 633         list_add(&dock_station->sibling, &dock_stations);
 634         adev->flags.is_dock_station = true;
 635         dev_info(&adev->dev, "ACPI dock station (docks/bays count: %d)\n",
 636                  dock_station_count);
 637         return;
 638 
 639 err_rmgroup:
 640         sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group);
 641 
 642 err_unregister:
 643         platform_device_unregister(dd);
 644         acpi_handle_err(handle, "%s encountered error %d\n", __func__, ret);
 645 }

/* [<][>][^][v][top][bottom][index][help] */