root/drivers/pnp/pnpacpi/core.c

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

DEFINITIONS

This source file includes following definitions.
  1. ispnpidacpi
  2. pnpacpi_get_resources
  3. pnpacpi_set_resources
  4. pnpacpi_disable_resources
  5. pnpacpi_can_wakeup
  6. pnpacpi_suspend
  7. pnpacpi_resume
  8. pnpacpi_get_id
  9. pnpacpi_add_device
  10. pnpacpi_add_device_handler
  11. pnpacpi_init
  12. pnpacpi_setup

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * pnpacpi -- PnP ACPI driver
   4  *
   5  * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr>
   6  * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com>
   7  */
   8 
   9 #include <linux/export.h>
  10 #include <linux/acpi.h>
  11 #include <linux/pnp.h>
  12 #include <linux/slab.h>
  13 #include <linux/mod_devicetable.h>
  14 
  15 #include "../base.h"
  16 #include "pnpacpi.h"
  17 
  18 static int num;
  19 
  20 /*
  21  * Compatible Device IDs
  22  */
  23 #define TEST_HEX(c) \
  24         if (!(('0' <= (c) && (c) <= '9') || ('A' <= (c) && (c) <= 'F'))) \
  25                 return 0
  26 #define TEST_ALPHA(c) \
  27         if (!('A' <= (c) && (c) <= 'Z')) \
  28                 return 0
  29 static int __init ispnpidacpi(const char *id)
  30 {
  31         TEST_ALPHA(id[0]);
  32         TEST_ALPHA(id[1]);
  33         TEST_ALPHA(id[2]);
  34         TEST_HEX(id[3]);
  35         TEST_HEX(id[4]);
  36         TEST_HEX(id[5]);
  37         TEST_HEX(id[6]);
  38         if (id[7] != '\0')
  39                 return 0;
  40         return 1;
  41 }
  42 
  43 static int pnpacpi_get_resources(struct pnp_dev *dev)
  44 {
  45         pnp_dbg(&dev->dev, "get resources\n");
  46         return pnpacpi_parse_allocated_resource(dev);
  47 }
  48 
  49 static int pnpacpi_set_resources(struct pnp_dev *dev)
  50 {
  51         struct acpi_device *acpi_dev;
  52         acpi_handle handle;
  53         int ret = 0;
  54 
  55         pnp_dbg(&dev->dev, "set resources\n");
  56 
  57         acpi_dev = ACPI_COMPANION(&dev->dev);
  58         if (!acpi_dev) {
  59                 dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
  60                 return -ENODEV;
  61         }
  62 
  63         if (WARN_ON_ONCE(acpi_dev != dev->data))
  64                 dev->data = acpi_dev;
  65 
  66         handle = acpi_dev->handle;
  67         if (acpi_has_method(handle, METHOD_NAME__SRS)) {
  68                 struct acpi_buffer buffer;
  69 
  70                 ret = pnpacpi_build_resource_template(dev, &buffer);
  71                 if (ret)
  72                         return ret;
  73 
  74                 ret = pnpacpi_encode_resources(dev, &buffer);
  75                 if (!ret) {
  76                         acpi_status status;
  77 
  78                         status = acpi_set_current_resources(handle, &buffer);
  79                         if (ACPI_FAILURE(status))
  80                                 ret = -EIO;
  81                 }
  82                 kfree(buffer.pointer);
  83         }
  84         if (!ret && acpi_device_power_manageable(acpi_dev))
  85                 ret = acpi_device_set_power(acpi_dev, ACPI_STATE_D0);
  86 
  87         return ret;
  88 }
  89 
  90 static int pnpacpi_disable_resources(struct pnp_dev *dev)
  91 {
  92         struct acpi_device *acpi_dev;
  93         acpi_status status;
  94 
  95         dev_dbg(&dev->dev, "disable resources\n");
  96 
  97         acpi_dev = ACPI_COMPANION(&dev->dev);
  98         if (!acpi_dev) {
  99                 dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
 100                 return 0;
 101         }
 102 
 103         /* acpi_unregister_gsi(pnp_irq(dev, 0)); */
 104         if (acpi_device_power_manageable(acpi_dev))
 105                 acpi_device_set_power(acpi_dev, ACPI_STATE_D3_COLD);
 106 
 107         /* continue even if acpi_device_set_power() fails */
 108         status = acpi_evaluate_object(acpi_dev->handle, "_DIS", NULL, NULL);
 109         if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
 110                 return -ENODEV;
 111 
 112         return 0;
 113 }
 114 
 115 #ifdef CONFIG_ACPI_SLEEP
 116 static bool pnpacpi_can_wakeup(struct pnp_dev *dev)
 117 {
 118         struct acpi_device *acpi_dev = ACPI_COMPANION(&dev->dev);
 119 
 120         if (!acpi_dev) {
 121                 dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
 122                 return false;
 123         }
 124 
 125         return acpi_bus_can_wakeup(acpi_dev->handle);
 126 }
 127 
 128 static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state)
 129 {
 130         struct acpi_device *acpi_dev = ACPI_COMPANION(&dev->dev);
 131         int error = 0;
 132 
 133         if (!acpi_dev) {
 134                 dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
 135                 return 0;
 136         }
 137 
 138         if (device_can_wakeup(&dev->dev)) {
 139                 error = acpi_pm_set_device_wakeup(&dev->dev,
 140                                               device_may_wakeup(&dev->dev));
 141                 if (error)
 142                         return error;
 143         }
 144 
 145         if (acpi_device_power_manageable(acpi_dev)) {
 146                 int power_state = acpi_pm_device_sleep_state(&dev->dev, NULL,
 147                                                         ACPI_STATE_D3_COLD);
 148                 if (power_state < 0)
 149                         power_state = (state.event == PM_EVENT_ON) ?
 150                                         ACPI_STATE_D0 : ACPI_STATE_D3_COLD;
 151 
 152                 /*
 153                  * acpi_device_set_power() can fail (keyboard port can't be
 154                  * powered-down?), and in any case, our return value is ignored
 155                  * by pnp_bus_suspend().  Hence we don't revert the wakeup
 156                  * setting if the set_power fails.
 157                  */
 158                 error = acpi_device_set_power(acpi_dev, power_state);
 159         }
 160 
 161         return error;
 162 }
 163 
 164 static int pnpacpi_resume(struct pnp_dev *dev)
 165 {
 166         struct acpi_device *acpi_dev = ACPI_COMPANION(&dev->dev);
 167         int error = 0;
 168 
 169         if (!acpi_dev) {
 170                 dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
 171                 return -ENODEV;
 172         }
 173 
 174         if (device_may_wakeup(&dev->dev))
 175                 acpi_pm_set_device_wakeup(&dev->dev, false);
 176 
 177         if (acpi_device_power_manageable(acpi_dev))
 178                 error = acpi_device_set_power(acpi_dev, ACPI_STATE_D0);
 179 
 180         return error;
 181 }
 182 #endif
 183 
 184 struct pnp_protocol pnpacpi_protocol = {
 185         .name    = "Plug and Play ACPI",
 186         .get     = pnpacpi_get_resources,
 187         .set     = pnpacpi_set_resources,
 188         .disable = pnpacpi_disable_resources,
 189 #ifdef CONFIG_ACPI_SLEEP
 190         .can_wakeup = pnpacpi_can_wakeup,
 191         .suspend = pnpacpi_suspend,
 192         .resume = pnpacpi_resume,
 193 #endif
 194 };
 195 EXPORT_SYMBOL(pnpacpi_protocol);
 196 
 197 static const char *__init pnpacpi_get_id(struct acpi_device *device)
 198 {
 199         struct acpi_hardware_id *id;
 200 
 201         list_for_each_entry(id, &device->pnp.ids, list) {
 202                 if (ispnpidacpi(id->id))
 203                         return id->id;
 204         }
 205 
 206         return NULL;
 207 }
 208 
 209 static int __init pnpacpi_add_device(struct acpi_device *device)
 210 {
 211         struct pnp_dev *dev;
 212         const char *pnpid;
 213         struct acpi_hardware_id *id;
 214         int error;
 215 
 216         /* Skip devices that are already bound */
 217         if (device->physical_node_count)
 218                 return 0;
 219 
 220         /*
 221          * If a PnPacpi device is not present , the device
 222          * driver should not be loaded.
 223          */
 224         if (!acpi_has_method(device->handle, "_CRS"))
 225                 return 0;
 226 
 227         pnpid = pnpacpi_get_id(device);
 228         if (!pnpid)
 229                 return 0;
 230 
 231         if (!device->status.present)
 232                 return 0;
 233 
 234         dev = pnp_alloc_dev(&pnpacpi_protocol, num, pnpid);
 235         if (!dev)
 236                 return -ENOMEM;
 237 
 238         ACPI_COMPANION_SET(&dev->dev, device);
 239         dev->data = device;
 240         /* .enabled means the device can decode the resources */
 241         dev->active = device->status.enabled;
 242         if (acpi_has_method(device->handle, "_SRS"))
 243                 dev->capabilities |= PNP_CONFIGURABLE;
 244         dev->capabilities |= PNP_READ;
 245         if (device->flags.dynamic_status && (dev->capabilities & PNP_CONFIGURABLE))
 246                 dev->capabilities |= PNP_WRITE;
 247         if (device->flags.removable)
 248                 dev->capabilities |= PNP_REMOVABLE;
 249         if (acpi_has_method(device->handle, "_DIS"))
 250                 dev->capabilities |= PNP_DISABLE;
 251 
 252         if (strlen(acpi_device_name(device)))
 253                 strncpy(dev->name, acpi_device_name(device), sizeof(dev->name));
 254         else
 255                 strncpy(dev->name, acpi_device_bid(device), sizeof(dev->name));
 256 
 257         if (dev->active)
 258                 pnpacpi_parse_allocated_resource(dev);
 259 
 260         if (dev->capabilities & PNP_CONFIGURABLE)
 261                 pnpacpi_parse_resource_option_data(dev);
 262 
 263         list_for_each_entry(id, &device->pnp.ids, list) {
 264                 if (!strcmp(id->id, pnpid))
 265                         continue;
 266                 if (!ispnpidacpi(id->id))
 267                         continue;
 268                 pnp_add_id(dev, id->id);
 269         }
 270 
 271         /* clear out the damaged flags */
 272         if (!dev->active)
 273                 pnp_init_resources(dev);
 274 
 275         error = pnp_add_device(dev);
 276         if (error) {
 277                 put_device(&dev->dev);
 278                 return error;
 279         }
 280 
 281         num++;
 282 
 283         return 0;
 284 }
 285 
 286 static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle,
 287                                                      u32 lvl, void *context,
 288                                                      void **rv)
 289 {
 290         struct acpi_device *device;
 291 
 292         if (acpi_bus_get_device(handle, &device))
 293                 return AE_CTRL_DEPTH;
 294         if (acpi_is_pnp_device(device))
 295                 pnpacpi_add_device(device);
 296         return AE_OK;
 297 }
 298 
 299 int pnpacpi_disabled __initdata;
 300 static int __init pnpacpi_init(void)
 301 {
 302         if (acpi_disabled || pnpacpi_disabled) {
 303                 printk(KERN_INFO "pnp: PnP ACPI: disabled\n");
 304                 return 0;
 305         }
 306         printk(KERN_INFO "pnp: PnP ACPI init\n");
 307         pnp_register_protocol(&pnpacpi_protocol);
 308         acpi_get_devices(NULL, pnpacpi_add_device_handler, NULL, NULL);
 309         printk(KERN_INFO "pnp: PnP ACPI: found %d devices\n", num);
 310         pnp_platform_devices = 1;
 311         return 0;
 312 }
 313 
 314 fs_initcall(pnpacpi_init);
 315 
 316 static int __init pnpacpi_setup(char *str)
 317 {
 318         if (str == NULL)
 319                 return 1;
 320         if (!strncmp(str, "off", 3))
 321                 pnpacpi_disabled = 1;
 322         return 1;
 323 }
 324 
 325 __setup("pnpacpi=", pnpacpi_setup);

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