LCOV - code coverage report
Current view: top level - drivers/pnp/pnpacpi - core.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 64 142 45.1 %
Date: 2022-04-01 14:17:54 Functions: 6 12 50.0 %
Branches: 37 132 28.0 %

           Branch data     Line data    Source code
       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                 :         66 : static int __init ispnpidacpi(const char *id)
      30                 :            : {
      31         [ +  - ]:         66 :         TEST_ALPHA(id[0]);
      32         [ +  - ]:         66 :         TEST_ALPHA(id[1]);
      33         [ +  - ]:         66 :         TEST_ALPHA(id[2]);
      34         [ +  - ]:         66 :         TEST_HEX(id[3]);
      35         [ +  - ]:         66 :         TEST_HEX(id[4]);
      36         [ +  - ]:         66 :         TEST_HEX(id[5]);
      37         [ +  - ]:         66 :         TEST_HEX(id[6]);
      38         [ -  + ]:         66 :         if (id[7] != '\0')
      39                 :          0 :                 return 0;
      40                 :            :         return 1;
      41                 :            : }
      42                 :            : 
      43                 :          0 : static int pnpacpi_get_resources(struct pnp_dev *dev)
      44                 :            : {
      45         [ #  # ]:          0 :         pnp_dbg(&dev->dev, "get resources\n");
      46                 :          0 :         return pnpacpi_parse_allocated_resource(dev);
      47                 :            : }
      48                 :            : 
      49                 :          0 : static int pnpacpi_set_resources(struct pnp_dev *dev)
      50                 :            : {
      51                 :          0 :         struct acpi_device *acpi_dev;
      52                 :          0 :         acpi_handle handle;
      53                 :          0 :         int ret = 0;
      54                 :            : 
      55         [ #  # ]:          0 :         pnp_dbg(&dev->dev, "set resources\n");
      56                 :            : 
      57         [ #  # ]:          0 :         acpi_dev = ACPI_COMPANION(&dev->dev);
      58         [ #  # ]:          0 :         if (!acpi_dev) {
      59                 :            :                 dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
      60                 :            :                 return -ENODEV;
      61                 :            :         }
      62                 :            : 
      63   [ #  #  #  # ]:          0 :         if (WARN_ON_ONCE(acpi_dev != dev->data))
      64                 :          0 :                 dev->data = acpi_dev;
      65                 :            : 
      66                 :          0 :         handle = acpi_dev->handle;
      67         [ #  # ]:          0 :         if (acpi_has_method(handle, METHOD_NAME__SRS)) {
      68                 :          0 :                 struct acpi_buffer buffer;
      69                 :            : 
      70                 :          0 :                 ret = pnpacpi_build_resource_template(dev, &buffer);
      71         [ #  # ]:          0 :                 if (ret)
      72                 :          0 :                         return ret;
      73                 :            : 
      74                 :          0 :                 ret = pnpacpi_encode_resources(dev, &buffer);
      75         [ #  # ]:          0 :                 if (!ret) {
      76                 :          0 :                         acpi_status status;
      77                 :            : 
      78                 :          0 :                         status = acpi_set_current_resources(handle, &buffer);
      79         [ #  # ]:          0 :                         if (ACPI_FAILURE(status))
      80                 :          0 :                                 ret = -EIO;
      81                 :            :                 }
      82                 :          0 :                 kfree(buffer.pointer);
      83                 :            :         }
      84   [ #  #  #  # ]:          0 :         if (!ret && acpi_device_power_manageable(acpi_dev))
      85                 :          0 :                 ret = acpi_device_set_power(acpi_dev, ACPI_STATE_D0);
      86                 :            : 
      87                 :            :         return ret;
      88                 :            : }
      89                 :            : 
      90                 :          0 : static int pnpacpi_disable_resources(struct pnp_dev *dev)
      91                 :            : {
      92                 :          0 :         struct acpi_device *acpi_dev;
      93                 :          0 :         acpi_status status;
      94                 :            : 
      95                 :          0 :         dev_dbg(&dev->dev, "disable resources\n");
      96                 :            : 
      97         [ #  # ]:          0 :         acpi_dev = ACPI_COMPANION(&dev->dev);
      98         [ #  # ]:          0 :         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         [ #  # ]:          0 :         if (acpi_device_power_manageable(acpi_dev))
     105                 :          0 :                 acpi_device_set_power(acpi_dev, ACPI_STATE_D3_COLD);
     106                 :            : 
     107                 :            :         /* continue even if acpi_device_set_power() fails */
     108                 :          0 :         status = acpi_evaluate_object(acpi_dev->handle, "_DIS", NULL, NULL);
     109         [ #  # ]:          0 :         if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
     110                 :          0 :                 return -ENODEV;
     111                 :            : 
     112                 :            :         return 0;
     113                 :            : }
     114                 :            : 
     115                 :            : #ifdef CONFIG_ACPI_SLEEP
     116                 :         66 : static bool pnpacpi_can_wakeup(struct pnp_dev *dev)
     117                 :            : {
     118         [ +  - ]:         66 :         struct acpi_device *acpi_dev = ACPI_COMPANION(&dev->dev);
     119                 :            : 
     120         [ +  - ]:         66 :         if (!acpi_dev) {
     121                 :            :                 dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
     122                 :            :                 return false;
     123                 :            :         }
     124                 :            : 
     125                 :         66 :         return acpi_bus_can_wakeup(acpi_dev->handle);
     126                 :            : }
     127                 :            : 
     128                 :          0 : static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state)
     129                 :            : {
     130         [ #  # ]:          0 :         struct acpi_device *acpi_dev = ACPI_COMPANION(&dev->dev);
     131                 :          0 :         int error = 0;
     132                 :            : 
     133         [ #  # ]:          0 :         if (!acpi_dev) {
     134                 :            :                 dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
     135                 :            :                 return 0;
     136                 :            :         }
     137                 :            : 
     138         [ #  # ]:          0 :         if (device_can_wakeup(&dev->dev)) {
     139         [ #  # ]:          0 :                 error = acpi_pm_set_device_wakeup(&dev->dev,
     140                 :            :                                               device_may_wakeup(&dev->dev));
     141         [ #  # ]:          0 :                 if (error)
     142                 :            :                         return error;
     143                 :            :         }
     144                 :            : 
     145         [ #  # ]:          0 :         if (acpi_device_power_manageable(acpi_dev)) {
     146                 :          0 :                 int power_state = acpi_pm_device_sleep_state(&dev->dev, NULL,
     147                 :            :                                                         ACPI_STATE_D3_COLD);
     148         [ #  # ]:          0 :                 if (power_state < 0)
     149                 :          0 :                         power_state = (state.event == PM_EVENT_ON) ?
     150         [ #  # ]:          0 :                                         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                 :          0 :                 error = acpi_device_set_power(acpi_dev, power_state);
     159                 :            :         }
     160                 :            : 
     161                 :            :         return error;
     162                 :            : }
     163                 :            : 
     164                 :          0 : static int pnpacpi_resume(struct pnp_dev *dev)
     165                 :            : {
     166         [ #  # ]:          0 :         struct acpi_device *acpi_dev = ACPI_COMPANION(&dev->dev);
     167                 :          0 :         int error = 0;
     168                 :            : 
     169         [ #  # ]:          0 :         if (!acpi_dev) {
     170                 :            :                 dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
     171                 :            :                 return -ENODEV;
     172                 :            :         }
     173                 :            : 
     174   [ #  #  #  # ]:          0 :         if (device_may_wakeup(&dev->dev))
     175                 :          0 :                 acpi_pm_set_device_wakeup(&dev->dev, false);
     176                 :            : 
     177         [ #  # ]:          0 :         if (acpi_device_power_manageable(acpi_dev))
     178                 :          0 :                 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                 :         66 : static const char *__init pnpacpi_get_id(struct acpi_device *device)
     198                 :            : {
     199                 :         66 :         struct acpi_hardware_id *id;
     200                 :            : 
     201         [ +  - ]:         66 :         list_for_each_entry(id, &device->pnp.ids, list) {
     202         [ +  - ]:         66 :                 if (ispnpidacpi(id->id))
     203                 :         66 :                         return id->id;
     204                 :            :         }
     205                 :            : 
     206                 :            :         return NULL;
     207                 :            : }
     208                 :            : 
     209                 :         66 : static int __init pnpacpi_add_device(struct acpi_device *device)
     210                 :            : {
     211                 :         66 :         struct pnp_dev *dev;
     212                 :         66 :         const char *pnpid;
     213                 :         66 :         struct acpi_hardware_id *id;
     214                 :         66 :         int error;
     215                 :            : 
     216                 :            :         /* Skip devices that are already bound */
     217         [ +  - ]:         66 :         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         [ +  - ]:         66 :         if (!acpi_has_method(device->handle, "_CRS"))
     225                 :            :                 return 0;
     226                 :            : 
     227                 :         66 :         pnpid = pnpacpi_get_id(device);
     228         [ +  - ]:         66 :         if (!pnpid)
     229                 :            :                 return 0;
     230                 :            : 
     231         [ +  - ]:         66 :         if (!device->status.present)
     232                 :            :                 return 0;
     233                 :            : 
     234                 :         66 :         dev = pnp_alloc_dev(&pnpacpi_protocol, num, pnpid);
     235         [ +  - ]:         66 :         if (!dev)
     236                 :            :                 return -ENOMEM;
     237                 :            : 
     238         [ +  - ]:        132 :         ACPI_COMPANION_SET(&dev->dev, device);
     239                 :         66 :         dev->data = device;
     240                 :            :         /* .enabled means the device can decode the resources */
     241                 :         66 :         dev->active = device->status.enabled;
     242         [ -  + ]:         66 :         if (acpi_has_method(device->handle, "_SRS"))
     243                 :          0 :                 dev->capabilities |= PNP_CONFIGURABLE;
     244                 :         66 :         dev->capabilities |= PNP_READ;
     245   [ +  +  -  + ]:         66 :         if (device->flags.dynamic_status && (dev->capabilities & PNP_CONFIGURABLE))
     246                 :          0 :                 dev->capabilities |= PNP_WRITE;
     247         [ -  + ]:         66 :         if (device->flags.removable)
     248                 :          0 :                 dev->capabilities |= PNP_REMOVABLE;
     249         [ -  + ]:         66 :         if (acpi_has_method(device->handle, "_DIS"))
     250                 :          0 :                 dev->capabilities |= PNP_DISABLE;
     251                 :            : 
     252         [ -  + ]:         66 :         if (strlen(acpi_device_name(device)))
     253                 :          0 :                 strncpy(dev->name, acpi_device_name(device), sizeof(dev->name));
     254                 :            :         else
     255                 :         66 :                 strncpy(dev->name, acpi_device_bid(device), sizeof(dev->name));
     256                 :            : 
     257         [ +  - ]:         66 :         if (dev->active)
     258                 :         66 :                 pnpacpi_parse_allocated_resource(dev);
     259                 :            : 
     260         [ -  + ]:         66 :         if (dev->capabilities & PNP_CONFIGURABLE)
     261                 :          0 :                 pnpacpi_parse_resource_option_data(dev);
     262                 :            : 
     263         [ +  + ]:        132 :         list_for_each_entry(id, &device->pnp.ids, list) {
     264         [ +  - ]:         66 :                 if (!strcmp(id->id, pnpid))
     265                 :         66 :                         continue;
     266         [ #  # ]:          0 :                 if (!ispnpidacpi(id->id))
     267                 :          0 :                         continue;
     268                 :          0 :                 pnp_add_id(dev, id->id);
     269                 :            :         }
     270                 :            : 
     271                 :            :         /* clear out the damaged flags */
     272         [ -  + ]:         66 :         if (!dev->active)
     273                 :          0 :                 pnp_init_resources(dev);
     274                 :            : 
     275                 :         66 :         error = pnp_add_device(dev);
     276         [ -  + ]:         66 :         if (error) {
     277                 :          0 :                 put_device(&dev->dev);
     278                 :          0 :                 return error;
     279                 :            :         }
     280                 :            : 
     281                 :         66 :         num++;
     282                 :            : 
     283                 :         66 :         return 0;
     284                 :            : }
     285                 :            : 
     286                 :        594 : static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle,
     287                 :            :                                                      u32 lvl, void *context,
     288                 :            :                                                      void **rv)
     289                 :            : {
     290                 :        594 :         struct acpi_device *device;
     291                 :            : 
     292         [ +  - ]:        594 :         if (acpi_bus_get_device(handle, &device))
     293                 :            :                 return AE_CTRL_DEPTH;
     294         [ +  + ]:        594 :         if (acpi_is_pnp_device(device))
     295                 :         66 :                 pnpacpi_add_device(device);
     296                 :            :         return AE_OK;
     297                 :            : }
     298                 :            : 
     299                 :            : int pnpacpi_disabled __initdata;
     300                 :         11 : static int __init pnpacpi_init(void)
     301                 :            : {
     302   [ +  -  -  + ]:         11 :         if (acpi_disabled || pnpacpi_disabled) {
     303                 :          0 :                 printk(KERN_INFO "pnp: PnP ACPI: disabled\n");
     304                 :          0 :                 return 0;
     305                 :            :         }
     306                 :         11 :         printk(KERN_INFO "pnp: PnP ACPI init\n");
     307                 :         11 :         pnp_register_protocol(&pnpacpi_protocol);
     308                 :         11 :         acpi_get_devices(NULL, pnpacpi_add_device_handler, NULL, NULL);
     309                 :         11 :         printk(KERN_INFO "pnp: PnP ACPI: found %d devices\n", num);
     310                 :         11 :         pnp_platform_devices = 1;
     311                 :         11 :         return 0;
     312                 :            : }
     313                 :            : 
     314                 :            : fs_initcall(pnpacpi_init);
     315                 :            : 
     316                 :          0 : static int __init pnpacpi_setup(char *str)
     317                 :            : {
     318         [ #  # ]:          0 :         if (str == NULL)
     319                 :            :                 return 1;
     320         [ #  # ]:          0 :         if (!strncmp(str, "off", 3))
     321                 :          0 :                 pnpacpi_disabled = 1;
     322                 :            :         return 1;
     323                 :            : }
     324                 :            : 
     325                 :            : __setup("pnpacpi=", pnpacpi_setup);

Generated by: LCOV version 1.14