Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * pnpacpi -- PnP ACPI driver
0004  *
0005  * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr>
0006  * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com>
0007  */
0008 
0009 #include <linux/export.h>
0010 #include <linux/acpi.h>
0011 #include <linux/pnp.h>
0012 #include <linux/slab.h>
0013 #include <linux/mod_devicetable.h>
0014 
0015 #include "../base.h"
0016 #include "pnpacpi.h"
0017 
0018 static int num;
0019 
0020 /*
0021  * Compatible Device IDs
0022  */
0023 #define TEST_HEX(c) \
0024     if (!(('0' <= (c) && (c) <= '9') || ('A' <= (c) && (c) <= 'F'))) \
0025         return 0
0026 #define TEST_ALPHA(c) \
0027     if (!('A' <= (c) && (c) <= 'Z')) \
0028         return 0
0029 static int __init ispnpidacpi(const char *id)
0030 {
0031     TEST_ALPHA(id[0]);
0032     TEST_ALPHA(id[1]);
0033     TEST_ALPHA(id[2]);
0034     TEST_HEX(id[3]);
0035     TEST_HEX(id[4]);
0036     TEST_HEX(id[5]);
0037     TEST_HEX(id[6]);
0038     if (id[7] != '\0')
0039         return 0;
0040     return 1;
0041 }
0042 
0043 static int pnpacpi_get_resources(struct pnp_dev *dev)
0044 {
0045     pnp_dbg(&dev->dev, "get resources\n");
0046     return pnpacpi_parse_allocated_resource(dev);
0047 }
0048 
0049 static int pnpacpi_set_resources(struct pnp_dev *dev)
0050 {
0051     struct acpi_device *acpi_dev;
0052     acpi_handle handle;
0053     int ret = 0;
0054 
0055     pnp_dbg(&dev->dev, "set resources\n");
0056 
0057     acpi_dev = ACPI_COMPANION(&dev->dev);
0058     if (!acpi_dev) {
0059         dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
0060         return -ENODEV;
0061     }
0062 
0063     if (WARN_ON_ONCE(acpi_dev != dev->data))
0064         dev->data = acpi_dev;
0065 
0066     handle = acpi_dev->handle;
0067     if (acpi_has_method(handle, METHOD_NAME__SRS)) {
0068         struct acpi_buffer buffer;
0069 
0070         ret = pnpacpi_build_resource_template(dev, &buffer);
0071         if (ret)
0072             return ret;
0073 
0074         ret = pnpacpi_encode_resources(dev, &buffer);
0075         if (!ret) {
0076             acpi_status status;
0077 
0078             status = acpi_set_current_resources(handle, &buffer);
0079             if (ACPI_FAILURE(status))
0080                 ret = -EIO;
0081         }
0082         kfree(buffer.pointer);
0083     }
0084     if (!ret && acpi_device_power_manageable(acpi_dev))
0085         ret = acpi_device_set_power(acpi_dev, ACPI_STATE_D0);
0086 
0087     return ret;
0088 }
0089 
0090 static int pnpacpi_disable_resources(struct pnp_dev *dev)
0091 {
0092     struct acpi_device *acpi_dev;
0093     acpi_status status;
0094 
0095     dev_dbg(&dev->dev, "disable resources\n");
0096 
0097     acpi_dev = ACPI_COMPANION(&dev->dev);
0098     if (!acpi_dev) {
0099         dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
0100         return 0;
0101     }
0102 
0103     /* acpi_unregister_gsi(pnp_irq(dev, 0)); */
0104     if (acpi_device_power_manageable(acpi_dev))
0105         acpi_device_set_power(acpi_dev, ACPI_STATE_D3_COLD);
0106 
0107     /* continue even if acpi_device_set_power() fails */
0108     status = acpi_evaluate_object(acpi_dev->handle, "_DIS", NULL, NULL);
0109     if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
0110         return -ENODEV;
0111 
0112     return 0;
0113 }
0114 
0115 #ifdef CONFIG_ACPI_SLEEP
0116 static bool pnpacpi_can_wakeup(struct pnp_dev *dev)
0117 {
0118     struct acpi_device *acpi_dev = ACPI_COMPANION(&dev->dev);
0119 
0120     if (!acpi_dev) {
0121         dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
0122         return false;
0123     }
0124 
0125     return acpi_bus_can_wakeup(acpi_dev->handle);
0126 }
0127 
0128 static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state)
0129 {
0130     struct acpi_device *acpi_dev = ACPI_COMPANION(&dev->dev);
0131     int error = 0;
0132 
0133     if (!acpi_dev) {
0134         dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
0135         return 0;
0136     }
0137 
0138     if (device_can_wakeup(&dev->dev)) {
0139         error = acpi_pm_set_device_wakeup(&dev->dev,
0140                           device_may_wakeup(&dev->dev));
0141         if (error)
0142             return error;
0143     }
0144 
0145     if (acpi_device_power_manageable(acpi_dev)) {
0146         int power_state = acpi_pm_device_sleep_state(&dev->dev, NULL,
0147                             ACPI_STATE_D3_COLD);
0148         if (power_state < 0)
0149             power_state = (state.event == PM_EVENT_ON) ?
0150                     ACPI_STATE_D0 : ACPI_STATE_D3_COLD;
0151 
0152         /*
0153          * acpi_device_set_power() can fail (keyboard port can't be
0154          * powered-down?), and in any case, our return value is ignored
0155          * by pnp_bus_suspend().  Hence we don't revert the wakeup
0156          * setting if the set_power fails.
0157          */
0158         error = acpi_device_set_power(acpi_dev, power_state);
0159     }
0160 
0161     return error;
0162 }
0163 
0164 static int pnpacpi_resume(struct pnp_dev *dev)
0165 {
0166     struct acpi_device *acpi_dev = ACPI_COMPANION(&dev->dev);
0167     int error = 0;
0168 
0169     if (!acpi_dev) {
0170         dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
0171         return -ENODEV;
0172     }
0173 
0174     if (device_may_wakeup(&dev->dev))
0175         acpi_pm_set_device_wakeup(&dev->dev, false);
0176 
0177     if (acpi_device_power_manageable(acpi_dev))
0178         error = acpi_device_set_power(acpi_dev, ACPI_STATE_D0);
0179 
0180     return error;
0181 }
0182 #endif
0183 
0184 struct pnp_protocol pnpacpi_protocol = {
0185     .name    = "Plug and Play ACPI",
0186     .get     = pnpacpi_get_resources,
0187     .set     = pnpacpi_set_resources,
0188     .disable = pnpacpi_disable_resources,
0189 #ifdef CONFIG_ACPI_SLEEP
0190     .can_wakeup = pnpacpi_can_wakeup,
0191     .suspend = pnpacpi_suspend,
0192     .resume = pnpacpi_resume,
0193 #endif
0194 };
0195 EXPORT_SYMBOL(pnpacpi_protocol);
0196 
0197 static const char *__init pnpacpi_get_id(struct acpi_device *device)
0198 {
0199     struct acpi_hardware_id *id;
0200 
0201     list_for_each_entry(id, &device->pnp.ids, list) {
0202         if (ispnpidacpi(id->id))
0203             return id->id;
0204     }
0205 
0206     return NULL;
0207 }
0208 
0209 static int __init pnpacpi_add_device(struct acpi_device *device)
0210 {
0211     struct pnp_dev *dev;
0212     const char *pnpid;
0213     struct acpi_hardware_id *id;
0214     int error;
0215 
0216     /* Skip devices that are already bound */
0217     if (device->physical_node_count)
0218         return 0;
0219 
0220     /*
0221      * If a PnPacpi device is not present , the device
0222      * driver should not be loaded.
0223      */
0224     if (!acpi_has_method(device->handle, "_CRS"))
0225         return 0;
0226 
0227     pnpid = pnpacpi_get_id(device);
0228     if (!pnpid)
0229         return 0;
0230 
0231     if (!device->status.present)
0232         return 0;
0233 
0234     dev = pnp_alloc_dev(&pnpacpi_protocol, num, pnpid);
0235     if (!dev)
0236         return -ENOMEM;
0237 
0238     ACPI_COMPANION_SET(&dev->dev, device);
0239     dev->data = device;
0240     /* .enabled means the device can decode the resources */
0241     dev->active = device->status.enabled;
0242     if (acpi_has_method(device->handle, "_SRS"))
0243         dev->capabilities |= PNP_CONFIGURABLE;
0244     dev->capabilities |= PNP_READ;
0245     if (device->flags.dynamic_status && (dev->capabilities & PNP_CONFIGURABLE))
0246         dev->capabilities |= PNP_WRITE;
0247     if (device->flags.removable)
0248         dev->capabilities |= PNP_REMOVABLE;
0249     if (acpi_has_method(device->handle, "_DIS"))
0250         dev->capabilities |= PNP_DISABLE;
0251 
0252     if (strlen(acpi_device_name(device)))
0253         strncpy(dev->name, acpi_device_name(device), sizeof(dev->name));
0254     else
0255         strncpy(dev->name, acpi_device_bid(device), sizeof(dev->name));
0256 
0257     if (dev->active)
0258         pnpacpi_parse_allocated_resource(dev);
0259 
0260     if (dev->capabilities & PNP_CONFIGURABLE)
0261         pnpacpi_parse_resource_option_data(dev);
0262 
0263     list_for_each_entry(id, &device->pnp.ids, list) {
0264         if (!strcmp(id->id, pnpid))
0265             continue;
0266         if (!ispnpidacpi(id->id))
0267             continue;
0268         pnp_add_id(dev, id->id);
0269     }
0270 
0271     /* clear out the damaged flags */
0272     if (!dev->active)
0273         pnp_init_resources(dev);
0274 
0275     error = pnp_add_device(dev);
0276     if (error) {
0277         put_device(&dev->dev);
0278         return error;
0279     }
0280 
0281     num++;
0282 
0283     return 0;
0284 }
0285 
0286 static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle,
0287                              u32 lvl, void *context,
0288                              void **rv)
0289 {
0290     struct acpi_device *device = acpi_fetch_acpi_dev(handle);
0291 
0292     if (!device)
0293         return AE_CTRL_DEPTH;
0294     if (acpi_is_pnp_device(device))
0295         pnpacpi_add_device(device);
0296     return AE_OK;
0297 }
0298 
0299 int pnpacpi_disabled __initdata;
0300 static int __init pnpacpi_init(void)
0301 {
0302     if (acpi_disabled || pnpacpi_disabled) {
0303         printk(KERN_INFO "pnp: PnP ACPI: disabled\n");
0304         return 0;
0305     }
0306     printk(KERN_INFO "pnp: PnP ACPI init\n");
0307     pnp_register_protocol(&pnpacpi_protocol);
0308     acpi_get_devices(NULL, pnpacpi_add_device_handler, NULL, NULL);
0309     printk(KERN_INFO "pnp: PnP ACPI: found %d devices\n", num);
0310     pnp_platform_devices = 1;
0311     return 0;
0312 }
0313 
0314 fs_initcall(pnpacpi_init);
0315 
0316 static int __init pnpacpi_setup(char *str)
0317 {
0318     if (str == NULL)
0319         return 1;
0320     if (!strncmp(str, "off", 3))
0321         pnpacpi_disabled = 1;
0322     return 1;
0323 }
0324 
0325 __setup("pnpacpi=", pnpacpi_setup);