Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  dock.c - ACPI dock station driver
0004  *
0005  *  Copyright (C) 2006, 2014, Intel Corp.
0006  *  Author: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
0007  *          Rafael J. Wysocki <rafael.j.wysocki@intel.com>
0008  */
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/moduleparam.h>
0012 #include <linux/slab.h>
0013 #include <linux/init.h>
0014 #include <linux/types.h>
0015 #include <linux/notifier.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/jiffies.h>
0018 #include <linux/stddef.h>
0019 #include <linux/acpi.h>
0020 
0021 #include "internal.h"
0022 
0023 static bool immediate_undock = 1;
0024 module_param(immediate_undock, bool, 0644);
0025 MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to "
0026     "undock immediately when the undock button is pressed, 0 will cause"
0027     " the driver to wait for userspace to write the undock sysfs file "
0028     " before undocking");
0029 
0030 struct dock_station {
0031     acpi_handle handle;
0032     unsigned long last_dock_time;
0033     u32 flags;
0034     struct list_head dependent_devices;
0035 
0036     struct list_head sibling;
0037     struct platform_device *dock_device;
0038 };
0039 static LIST_HEAD(dock_stations);
0040 static int dock_station_count;
0041 
0042 struct dock_dependent_device {
0043     struct list_head list;
0044     struct acpi_device *adev;
0045 };
0046 
0047 #define DOCK_DOCKING    0x00000001
0048 #define DOCK_UNDOCKING  0x00000002
0049 #define DOCK_IS_DOCK    0x00000010
0050 #define DOCK_IS_ATA 0x00000020
0051 #define DOCK_IS_BAT 0x00000040
0052 #define DOCK_EVENT  3
0053 #define UNDOCK_EVENT    2
0054 
0055 enum dock_callback_type {
0056     DOCK_CALL_HANDLER,
0057     DOCK_CALL_FIXUP,
0058     DOCK_CALL_UEVENT,
0059 };
0060 
0061 /*****************************************************************************
0062  *                         Dock Dependent device functions                   *
0063  *****************************************************************************/
0064 /**
0065  * add_dock_dependent_device - associate a device with the dock station
0066  * @ds: Dock station.
0067  * @adev: Dependent ACPI device object.
0068  *
0069  * Add the dependent device to the dock's dependent device list.
0070  */
0071 static int add_dock_dependent_device(struct dock_station *ds,
0072                      struct acpi_device *adev)
0073 {
0074     struct dock_dependent_device *dd;
0075 
0076     dd = kzalloc(sizeof(*dd), GFP_KERNEL);
0077     if (!dd)
0078         return -ENOMEM;
0079 
0080     dd->adev = adev;
0081     INIT_LIST_HEAD(&dd->list);
0082     list_add_tail(&dd->list, &ds->dependent_devices);
0083 
0084     return 0;
0085 }
0086 
0087 static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
0088                    enum dock_callback_type cb_type)
0089 {
0090     struct acpi_device *adev = dd->adev;
0091 
0092     acpi_lock_hp_context();
0093 
0094     if (!adev->hp)
0095         goto out;
0096 
0097     if (cb_type == DOCK_CALL_FIXUP) {
0098         void (*fixup)(struct acpi_device *);
0099 
0100         fixup = adev->hp->fixup;
0101         if (fixup) {
0102             acpi_unlock_hp_context();
0103             fixup(adev);
0104             return;
0105         }
0106     } else if (cb_type == DOCK_CALL_UEVENT) {
0107         void (*uevent)(struct acpi_device *, u32);
0108 
0109         uevent = adev->hp->uevent;
0110         if (uevent) {
0111             acpi_unlock_hp_context();
0112             uevent(adev, event);
0113             return;
0114         }
0115     } else {
0116         int (*notify)(struct acpi_device *, u32);
0117 
0118         notify = adev->hp->notify;
0119         if (notify) {
0120             acpi_unlock_hp_context();
0121             notify(adev, event);
0122             return;
0123         }
0124     }
0125 
0126  out:
0127     acpi_unlock_hp_context();
0128 }
0129 
0130 static struct dock_station *find_dock_station(acpi_handle handle)
0131 {
0132     struct dock_station *ds;
0133 
0134     list_for_each_entry(ds, &dock_stations, sibling)
0135         if (ds->handle == handle)
0136             return ds;
0137 
0138     return NULL;
0139 }
0140 
0141 /**
0142  * find_dock_dependent_device - get a device dependent on this dock
0143  * @ds: the dock station
0144  * @adev: ACPI device object to find.
0145  *
0146  * iterate over the dependent device list for this dock.  If the
0147  * dependent device matches the handle, return.
0148  */
0149 static struct dock_dependent_device *
0150 find_dock_dependent_device(struct dock_station *ds, struct acpi_device *adev)
0151 {
0152     struct dock_dependent_device *dd;
0153 
0154     list_for_each_entry(dd, &ds->dependent_devices, list)
0155         if (adev == dd->adev)
0156             return dd;
0157 
0158     return NULL;
0159 }
0160 
0161 void register_dock_dependent_device(struct acpi_device *adev,
0162                     acpi_handle dshandle)
0163 {
0164     struct dock_station *ds = find_dock_station(dshandle);
0165 
0166     if (ds && !find_dock_dependent_device(ds, adev))
0167         add_dock_dependent_device(ds, adev);
0168 }
0169 
0170 /*****************************************************************************
0171  *                         Dock functions                                    *
0172  *****************************************************************************/
0173 
0174 /**
0175  * is_dock_device - see if a device is on a dock station
0176  * @adev: ACPI device object to check.
0177  *
0178  * If this device is either the dock station itself,
0179  * or is a device dependent on the dock station, then it
0180  * is a dock device
0181  */
0182 int is_dock_device(struct acpi_device *adev)
0183 {
0184     struct dock_station *dock_station;
0185 
0186     if (!dock_station_count)
0187         return 0;
0188 
0189     if (acpi_dock_match(adev->handle))
0190         return 1;
0191 
0192     list_for_each_entry(dock_station, &dock_stations, sibling)
0193         if (find_dock_dependent_device(dock_station, adev))
0194             return 1;
0195 
0196     return 0;
0197 }
0198 EXPORT_SYMBOL_GPL(is_dock_device);
0199 
0200 /**
0201  * dock_present - see if the dock station is present.
0202  * @ds: the dock station
0203  *
0204  * execute the _STA method.  note that present does not
0205  * imply that we are docked.
0206  */
0207 static int dock_present(struct dock_station *ds)
0208 {
0209     unsigned long long sta;
0210     acpi_status status;
0211 
0212     if (ds) {
0213         status = acpi_evaluate_integer(ds->handle, "_STA", NULL, &sta);
0214         if (ACPI_SUCCESS(status) && sta)
0215             return 1;
0216     }
0217     return 0;
0218 }
0219 
0220 /**
0221  * hot_remove_dock_devices - Remove dock station devices.
0222  * @ds: Dock station.
0223  */
0224 static void hot_remove_dock_devices(struct dock_station *ds)
0225 {
0226     struct dock_dependent_device *dd;
0227 
0228     /*
0229      * Walk the list in reverse order so that devices that have been added
0230      * last are removed first (in case there are some indirect dependencies
0231      * between them).
0232      */
0233     list_for_each_entry_reverse(dd, &ds->dependent_devices, list)
0234         dock_hotplug_event(dd, ACPI_NOTIFY_EJECT_REQUEST,
0235                    DOCK_CALL_HANDLER);
0236 
0237     list_for_each_entry_reverse(dd, &ds->dependent_devices, list)
0238         acpi_bus_trim(dd->adev);
0239 }
0240 
0241 /**
0242  * hotplug_dock_devices - Insert devices on a dock station.
0243  * @ds: the dock station
0244  * @event: either bus check or device check request
0245  *
0246  * Some devices on the dock station need to have drivers called
0247  * to perform hotplug operations after a dock event has occurred.
0248  * Traverse the list of dock devices that have registered a
0249  * hotplug handler, and call the handler.
0250  */
0251 static void hotplug_dock_devices(struct dock_station *ds, u32 event)
0252 {
0253     struct dock_dependent_device *dd;
0254 
0255     /* Call driver specific post-dock fixups. */
0256     list_for_each_entry(dd, &ds->dependent_devices, list)
0257         dock_hotplug_event(dd, event, DOCK_CALL_FIXUP);
0258 
0259     /* Call driver specific hotplug functions. */
0260     list_for_each_entry(dd, &ds->dependent_devices, list)
0261         dock_hotplug_event(dd, event, DOCK_CALL_HANDLER);
0262 
0263     /*
0264      * Check if all devices have been enumerated already.  If not, run
0265      * acpi_bus_scan() for them and that will cause scan handlers to be
0266      * attached to device objects or acpi_drivers to be stopped/started if
0267      * they are present.
0268      */
0269     list_for_each_entry(dd, &ds->dependent_devices, list) {
0270         struct acpi_device *adev = dd->adev;
0271 
0272         if (!acpi_device_enumerated(adev)) {
0273             int ret = acpi_bus_scan(adev->handle);
0274 
0275             if (ret)
0276                 dev_dbg(&adev->dev, "scan error %d\n", -ret);
0277         }
0278     }
0279 }
0280 
0281 static void dock_event(struct dock_station *ds, u32 event, int num)
0282 {
0283     struct device *dev = &ds->dock_device->dev;
0284     char event_string[13];
0285     char *envp[] = { event_string, NULL };
0286     struct dock_dependent_device *dd;
0287 
0288     if (num == UNDOCK_EVENT)
0289         sprintf(event_string, "EVENT=undock");
0290     else
0291         sprintf(event_string, "EVENT=dock");
0292 
0293     /*
0294      * Indicate that the status of the dock station has
0295      * changed.
0296      */
0297     if (num == DOCK_EVENT)
0298         kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
0299 
0300     list_for_each_entry(dd, &ds->dependent_devices, list)
0301         dock_hotplug_event(dd, event, DOCK_CALL_UEVENT);
0302 
0303     if (num != DOCK_EVENT)
0304         kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
0305 }
0306 
0307 /**
0308  * handle_dock - handle a dock event
0309  * @ds: the dock station
0310  * @dock: to dock, or undock - that is the question
0311  *
0312  * Execute the _DCK method in response to an acpi event
0313  */
0314 static void handle_dock(struct dock_station *ds, int dock)
0315 {
0316     acpi_status status;
0317     struct acpi_object_list arg_list;
0318     union acpi_object arg;
0319     unsigned long long value;
0320 
0321     acpi_handle_info(ds->handle, "%s\n", dock ? "docking" : "undocking");
0322 
0323     /* _DCK method has one argument */
0324     arg_list.count = 1;
0325     arg_list.pointer = &arg;
0326     arg.type = ACPI_TYPE_INTEGER;
0327     arg.integer.value = dock;
0328     status = acpi_evaluate_integer(ds->handle, "_DCK", &arg_list, &value);
0329     if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
0330         acpi_handle_err(ds->handle, "Failed to execute _DCK (0x%x)\n",
0331                 status);
0332 }
0333 
0334 static inline void dock(struct dock_station *ds)
0335 {
0336     handle_dock(ds, 1);
0337 }
0338 
0339 static inline void undock(struct dock_station *ds)
0340 {
0341     handle_dock(ds, 0);
0342 }
0343 
0344 static inline void begin_dock(struct dock_station *ds)
0345 {
0346     ds->flags |= DOCK_DOCKING;
0347 }
0348 
0349 static inline void complete_dock(struct dock_station *ds)
0350 {
0351     ds->flags &= ~(DOCK_DOCKING);
0352     ds->last_dock_time = jiffies;
0353 }
0354 
0355 static inline void begin_undock(struct dock_station *ds)
0356 {
0357     ds->flags |= DOCK_UNDOCKING;
0358 }
0359 
0360 static inline void complete_undock(struct dock_station *ds)
0361 {
0362     ds->flags &= ~(DOCK_UNDOCKING);
0363 }
0364 
0365 /**
0366  * dock_in_progress - see if we are in the middle of handling a dock event
0367  * @ds: the dock station
0368  *
0369  * Sometimes while docking, false dock events can be sent to the driver
0370  * because good connections aren't made or some other reason.  Ignore these
0371  * if we are in the middle of doing something.
0372  */
0373 static int dock_in_progress(struct dock_station *ds)
0374 {
0375     if ((ds->flags & DOCK_DOCKING) ||
0376         time_before(jiffies, (ds->last_dock_time + HZ)))
0377         return 1;
0378     return 0;
0379 }
0380 
0381 /**
0382  * handle_eject_request - handle an undock request checking for error conditions
0383  *
0384  * Check to make sure the dock device is still present, then undock and
0385  * hotremove all the devices that may need removing.
0386  */
0387 static int handle_eject_request(struct dock_station *ds, u32 event)
0388 {
0389     if (dock_in_progress(ds))
0390         return -EBUSY;
0391 
0392     /*
0393      * here we need to generate the undock
0394      * event prior to actually doing the undock
0395      * so that the device struct still exists.
0396      * Also, even send the dock event if the
0397      * device is not present anymore
0398      */
0399     dock_event(ds, event, UNDOCK_EVENT);
0400 
0401     hot_remove_dock_devices(ds);
0402     undock(ds);
0403     acpi_evaluate_lck(ds->handle, 0);
0404     acpi_evaluate_ej0(ds->handle);
0405     if (dock_present(ds)) {
0406         acpi_handle_err(ds->handle, "Unable to undock!\n");
0407         return -EBUSY;
0408     }
0409     complete_undock(ds);
0410     return 0;
0411 }
0412 
0413 /**
0414  * dock_notify - Handle ACPI dock notification.
0415  * @adev: Dock station's ACPI device object.
0416  * @event: Event code.
0417  *
0418  * If we are notified to dock, then check to see if the dock is
0419  * present and then dock.  Notify all drivers of the dock event,
0420  * and then hotplug and devices that may need hotplugging.
0421  */
0422 int dock_notify(struct acpi_device *adev, u32 event)
0423 {
0424     acpi_handle handle = adev->handle;
0425     struct dock_station *ds = find_dock_station(handle);
0426     int surprise_removal = 0;
0427 
0428     if (!ds)
0429         return -ENODEV;
0430 
0431     /*
0432      * According to acpi spec 3.0a, if a DEVICE_CHECK notification
0433      * is sent and _DCK is present, it is assumed to mean an undock
0434      * request.
0435      */
0436     if ((ds->flags & DOCK_IS_DOCK) && event == ACPI_NOTIFY_DEVICE_CHECK)
0437         event = ACPI_NOTIFY_EJECT_REQUEST;
0438 
0439     /*
0440      * dock station: BUS_CHECK - docked or surprise removal
0441      *       DEVICE_CHECK - undocked
0442      * other device: BUS_CHECK/DEVICE_CHECK - added or surprise removal
0443      *
0444      * To simplify event handling, dock dependent device handler always
0445      * get ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and
0446      * ACPI_NOTIFY_EJECT_REQUEST for removal
0447      */
0448     switch (event) {
0449     case ACPI_NOTIFY_BUS_CHECK:
0450     case ACPI_NOTIFY_DEVICE_CHECK:
0451         if (!dock_in_progress(ds) && !acpi_device_enumerated(adev)) {
0452             begin_dock(ds);
0453             dock(ds);
0454             if (!dock_present(ds)) {
0455                 acpi_handle_err(handle, "Unable to dock!\n");
0456                 complete_dock(ds);
0457                 break;
0458             }
0459             hotplug_dock_devices(ds, event);
0460             complete_dock(ds);
0461             dock_event(ds, event, DOCK_EVENT);
0462             acpi_evaluate_lck(ds->handle, 1);
0463             acpi_update_all_gpes();
0464             break;
0465         }
0466         if (dock_present(ds) || dock_in_progress(ds))
0467             break;
0468         /* This is a surprise removal */
0469         surprise_removal = 1;
0470         event = ACPI_NOTIFY_EJECT_REQUEST;
0471         /* Fall back */
0472         fallthrough;
0473     case ACPI_NOTIFY_EJECT_REQUEST:
0474         begin_undock(ds);
0475         if ((immediate_undock && !(ds->flags & DOCK_IS_ATA))
0476            || surprise_removal)
0477             handle_eject_request(ds, event);
0478         else
0479             dock_event(ds, event, UNDOCK_EVENT);
0480         break;
0481     }
0482     return 0;
0483 }
0484 
0485 /*
0486  * show_docked - read method for "docked" file in sysfs
0487  */
0488 static ssize_t docked_show(struct device *dev,
0489                struct device_attribute *attr, char *buf)
0490 {
0491     struct dock_station *dock_station = dev->platform_data;
0492     struct acpi_device *adev = acpi_fetch_acpi_dev(dock_station->handle);
0493 
0494     return sysfs_emit(buf, "%u\n", acpi_device_enumerated(adev));
0495 }
0496 static DEVICE_ATTR_RO(docked);
0497 
0498 /*
0499  * show_flags - read method for flags file in sysfs
0500  */
0501 static ssize_t flags_show(struct device *dev,
0502               struct device_attribute *attr, char *buf)
0503 {
0504     struct dock_station *dock_station = dev->platform_data;
0505 
0506     return sysfs_emit(buf, "%d\n", dock_station->flags);
0507 
0508 }
0509 static DEVICE_ATTR_RO(flags);
0510 
0511 /*
0512  * write_undock - write method for "undock" file in sysfs
0513  */
0514 static ssize_t undock_store(struct device *dev, struct device_attribute *attr,
0515                 const char *buf, size_t count)
0516 {
0517     int ret;
0518     struct dock_station *dock_station = dev->platform_data;
0519 
0520     if (!count)
0521         return -EINVAL;
0522 
0523     acpi_scan_lock_acquire();
0524     begin_undock(dock_station);
0525     ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST);
0526     acpi_scan_lock_release();
0527     return ret ? ret : count;
0528 }
0529 static DEVICE_ATTR_WO(undock);
0530 
0531 /*
0532  * show_dock_uid - read method for "uid" file in sysfs
0533  */
0534 static ssize_t uid_show(struct device *dev,
0535             struct device_attribute *attr, char *buf)
0536 {
0537     unsigned long long lbuf;
0538     struct dock_station *dock_station = dev->platform_data;
0539 
0540     acpi_status status = acpi_evaluate_integer(dock_station->handle,
0541                     "_UID", NULL, &lbuf);
0542     if (ACPI_FAILURE(status))
0543         return 0;
0544 
0545     return sysfs_emit(buf, "%llx\n", lbuf);
0546 }
0547 static DEVICE_ATTR_RO(uid);
0548 
0549 static ssize_t type_show(struct device *dev,
0550              struct device_attribute *attr, char *buf)
0551 {
0552     struct dock_station *dock_station = dev->platform_data;
0553     char *type;
0554 
0555     if (dock_station->flags & DOCK_IS_DOCK)
0556         type = "dock_station";
0557     else if (dock_station->flags & DOCK_IS_ATA)
0558         type = "ata_bay";
0559     else if (dock_station->flags & DOCK_IS_BAT)
0560         type = "battery_bay";
0561     else
0562         type = "unknown";
0563 
0564     return sysfs_emit(buf, "%s\n", type);
0565 }
0566 static DEVICE_ATTR_RO(type);
0567 
0568 static struct attribute *dock_attributes[] = {
0569     &dev_attr_docked.attr,
0570     &dev_attr_flags.attr,
0571     &dev_attr_undock.attr,
0572     &dev_attr_uid.attr,
0573     &dev_attr_type.attr,
0574     NULL
0575 };
0576 
0577 static const struct attribute_group dock_attribute_group = {
0578     .attrs = dock_attributes
0579 };
0580 
0581 /**
0582  * acpi_dock_add - Add a new dock station
0583  * @adev: Dock station ACPI device object.
0584  *
0585  * allocated and initialize a new dock station device.
0586  */
0587 void acpi_dock_add(struct acpi_device *adev)
0588 {
0589     struct dock_station *dock_station, ds = { NULL, };
0590     struct platform_device_info pdevinfo;
0591     acpi_handle handle = adev->handle;
0592     struct platform_device *dd;
0593     int ret;
0594 
0595     memset(&pdevinfo, 0, sizeof(pdevinfo));
0596     pdevinfo.name = "dock";
0597     pdevinfo.id = dock_station_count;
0598     pdevinfo.fwnode = acpi_fwnode_handle(adev);
0599     pdevinfo.data = &ds;
0600     pdevinfo.size_data = sizeof(ds);
0601     dd = platform_device_register_full(&pdevinfo);
0602     if (IS_ERR(dd))
0603         return;
0604 
0605     dock_station = dd->dev.platform_data;
0606 
0607     dock_station->handle = handle;
0608     dock_station->dock_device = dd;
0609     dock_station->last_dock_time = jiffies - HZ;
0610 
0611     INIT_LIST_HEAD(&dock_station->sibling);
0612     INIT_LIST_HEAD(&dock_station->dependent_devices);
0613 
0614     /* we want the dock device to send uevents */
0615     dev_set_uevent_suppress(&dd->dev, 0);
0616 
0617     if (acpi_dock_match(handle))
0618         dock_station->flags |= DOCK_IS_DOCK;
0619     if (acpi_ata_match(handle))
0620         dock_station->flags |= DOCK_IS_ATA;
0621     if (acpi_device_is_battery(adev))
0622         dock_station->flags |= DOCK_IS_BAT;
0623 
0624     ret = sysfs_create_group(&dd->dev.kobj, &dock_attribute_group);
0625     if (ret)
0626         goto err_unregister;
0627 
0628     /* add the dock station as a device dependent on itself */
0629     ret = add_dock_dependent_device(dock_station, adev);
0630     if (ret)
0631         goto err_rmgroup;
0632 
0633     dock_station_count++;
0634     list_add(&dock_station->sibling, &dock_stations);
0635     adev->flags.is_dock_station = true;
0636     dev_info(&adev->dev, "ACPI dock station (docks/bays count: %d)\n",
0637          dock_station_count);
0638     return;
0639 
0640 err_rmgroup:
0641     sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group);
0642 
0643 err_unregister:
0644     platform_device_unregister(dd);
0645     acpi_handle_err(handle, "%s encountered error %d\n", __func__, ret);
0646 }