LCOV - code coverage report
Current view: top level - drivers/pnp - driver.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 64 143 44.8 %
Date: 2022-04-01 14:17:54 Functions: 7 16 43.8 %
Branches: 36 128 28.1 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * driver.c - device id matching, driver model, etc.
       4                 :            :  *
       5                 :            :  * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
       6                 :            :  */
       7                 :            : 
       8                 :            : #include <linux/string.h>
       9                 :            : #include <linux/list.h>
      10                 :            : #include <linux/module.h>
      11                 :            : #include <linux/ctype.h>
      12                 :            : #include <linux/slab.h>
      13                 :            : #include <linux/pnp.h>
      14                 :            : #include "base.h"
      15                 :            : 
      16                 :       3443 : static int compare_func(const char *ida, const char *idb)
      17                 :            : {
      18                 :       3443 :         int i;
      19                 :            : 
      20                 :            :         /* we only need to compare the last 4 chars */
      21         [ +  + ]:       6127 :         for (i = 3; i < 7; i++) {
      22         [ +  - ]:       6028 :                 if (ida[i] != 'X' &&
      23   [ +  -  +  +  :       7854 :                     idb[i] != 'X' && toupper(ida[i]) != toupper(idb[i]))
             +  +  +  + ]
      24                 :            :                         return 0;
      25                 :            :         }
      26                 :            :         return 1;
      27                 :            : }
      28                 :            : 
      29                 :      13475 : int compare_pnp_id(struct pnp_id *pos, const char *id)
      30                 :            : {
      31   [ +  -  +  - ]:      13475 :         if (!pos || !id || (strlen(id) != 7))
      32                 :            :                 return 0;
      33         [ +  - ]:      13475 :         if (memcmp(id, "ANYDEVS", 7) == 0)
      34                 :            :                 return 1;
      35         [ +  + ]:      26851 :         while (pos) {
      36         [ +  + ]:      13475 :                 if (memcmp(pos->id, id, 3) == 0)
      37         [ +  + ]:       3443 :                         if (compare_func(pos->id, id) == 1)
      38                 :            :                                 return 1;
      39                 :      13376 :                 pos = pos->next;
      40                 :            :         }
      41                 :            :         return 0;
      42                 :            : }
      43                 :            : 
      44                 :            : static const struct pnp_device_id *match_device(struct pnp_driver *drv,
      45                 :            :                                                 struct pnp_dev *dev)
      46                 :            : {
      47                 :            :         const struct pnp_device_id *drv_id = drv->id_table;
      48                 :            : 
      49                 :            :         if (!drv_id)
      50                 :            :                 return NULL;
      51                 :            : 
      52                 :            :         while (*drv_id->id) {
      53                 :            :                 if (compare_pnp_id(dev->id, drv_id->id))
      54                 :            :                         return drv_id;
      55                 :            :                 drv_id++;
      56                 :            :         }
      57                 :            :         return NULL;
      58                 :            : }
      59                 :            : 
      60                 :         44 : int pnp_device_attach(struct pnp_dev *pnp_dev)
      61                 :            : {
      62                 :         44 :         mutex_lock(&pnp_lock);
      63         [ -  + ]:         44 :         if (pnp_dev->status != PNP_READY) {
      64                 :          0 :                 mutex_unlock(&pnp_lock);
      65                 :          0 :                 return -EBUSY;
      66                 :            :         }
      67                 :         44 :         pnp_dev->status = PNP_ATTACHED;
      68                 :         44 :         mutex_unlock(&pnp_lock);
      69                 :         44 :         return 0;
      70                 :            : }
      71                 :            : 
      72                 :          0 : void pnp_device_detach(struct pnp_dev *pnp_dev)
      73                 :            : {
      74                 :          0 :         mutex_lock(&pnp_lock);
      75         [ #  # ]:          0 :         if (pnp_dev->status == PNP_ATTACHED)
      76                 :          0 :                 pnp_dev->status = PNP_READY;
      77                 :          0 :         mutex_unlock(&pnp_lock);
      78                 :          0 : }
      79                 :            : 
      80                 :         44 : static int pnp_device_probe(struct device *dev)
      81                 :            : {
      82                 :         44 :         int error;
      83                 :         44 :         struct pnp_driver *pnp_drv;
      84                 :         44 :         struct pnp_dev *pnp_dev;
      85                 :         44 :         const struct pnp_device_id *dev_id = NULL;
      86                 :         44 :         pnp_dev = to_pnp_dev(dev);
      87                 :         44 :         pnp_drv = to_pnp_driver(dev->driver);
      88                 :            : 
      89                 :         44 :         error = pnp_device_attach(pnp_dev);
      90         [ +  - ]:         44 :         if (error < 0)
      91                 :            :                 return error;
      92                 :            : 
      93         [ -  + ]:         44 :         if (pnp_dev->active == 0) {
      94         [ #  # ]:          0 :                 if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)) {
      95                 :          0 :                         error = pnp_activate_dev(pnp_dev);
      96         [ #  # ]:          0 :                         if (error < 0)
      97                 :            :                                 return error;
      98                 :            :                 }
      99         [ -  + ]:         44 :         } else if ((pnp_drv->flags & PNP_DRIVER_RES_DISABLE)
     100                 :            :                    == PNP_DRIVER_RES_DISABLE) {
     101                 :          0 :                 error = pnp_disable_dev(pnp_dev);
     102         [ #  # ]:          0 :                 if (error < 0)
     103                 :            :                         return error;
     104                 :            :         }
     105                 :         44 :         error = 0;
     106         [ +  - ]:         44 :         if (pnp_drv->probe) {
     107                 :         44 :                 dev_id = match_device(pnp_drv, pnp_dev);
     108         [ +  - ]:         44 :                 if (dev_id != NULL)
     109                 :         44 :                         error = pnp_drv->probe(pnp_dev, dev_id);
     110                 :            :         }
     111         [ +  - ]:         44 :         if (error >= 0) {
     112                 :         44 :                 pnp_dev->driver = pnp_drv;
     113                 :         44 :                 error = 0;
     114                 :            :         } else
     115                 :          0 :                 goto fail;
     116                 :            : 
     117                 :         44 :         return error;
     118                 :            : 
     119                 :            : fail:
     120                 :          0 :         pnp_device_detach(pnp_dev);
     121                 :          0 :         return error;
     122                 :            : }
     123                 :            : 
     124                 :          0 : static int pnp_device_remove(struct device *dev)
     125                 :            : {
     126                 :          0 :         struct pnp_dev *pnp_dev = to_pnp_dev(dev);
     127                 :          0 :         struct pnp_driver *drv = pnp_dev->driver;
     128                 :            : 
     129         [ #  # ]:          0 :         if (drv) {
     130         [ #  # ]:          0 :                 if (drv->remove)
     131                 :          0 :                         drv->remove(pnp_dev);
     132                 :          0 :                 pnp_dev->driver = NULL;
     133                 :            :         }
     134                 :            : 
     135   [ #  #  #  # ]:          0 :         if (pnp_dev->active &&
     136         [ #  # ]:          0 :             (!drv || !(drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)))
     137                 :          0 :                 pnp_disable_dev(pnp_dev);
     138                 :            : 
     139                 :          0 :         pnp_device_detach(pnp_dev);
     140                 :          0 :         return 0;
     141                 :            : }
     142                 :            : 
     143                 :          0 : static void pnp_device_shutdown(struct device *dev)
     144                 :            : {
     145                 :          0 :         struct pnp_dev *pnp_dev = to_pnp_dev(dev);
     146                 :          0 :         struct pnp_driver *drv = pnp_dev->driver;
     147                 :            : 
     148   [ #  #  #  # ]:          0 :         if (drv && drv->shutdown)
     149                 :          0 :                 drv->shutdown(pnp_dev);
     150                 :          0 : }
     151                 :            : 
     152                 :        330 : static int pnp_bus_match(struct device *dev, struct device_driver *drv)
     153                 :            : {
     154                 :        330 :         struct pnp_dev *pnp_dev = to_pnp_dev(dev);
     155                 :        330 :         struct pnp_driver *pnp_drv = to_pnp_driver(drv);
     156                 :            : 
     157         [ +  + ]:        330 :         if (match_device(pnp_drv, pnp_dev) == NULL)
     158                 :        286 :                 return 0;
     159                 :            :         return 1;
     160                 :            : }
     161                 :            : 
     162                 :          0 : static int __pnp_bus_suspend(struct device *dev, pm_message_t state)
     163                 :            : {
     164                 :          0 :         struct pnp_dev *pnp_dev = to_pnp_dev(dev);
     165                 :          0 :         struct pnp_driver *pnp_drv = pnp_dev->driver;
     166                 :          0 :         int error;
     167                 :            : 
     168         [ #  # ]:          0 :         if (!pnp_drv)
     169                 :            :                 return 0;
     170                 :            : 
     171   [ #  #  #  # ]:          0 :         if (pnp_drv->driver.pm && pnp_drv->driver.pm->suspend) {
     172                 :          0 :                 error = pnp_drv->driver.pm->suspend(dev);
     173                 :          0 :                 suspend_report_result(pnp_drv->driver.pm->suspend, error);
     174         [ #  # ]:          0 :                 if (error)
     175                 :            :                         return error;
     176                 :            :         }
     177                 :            : 
     178         [ #  # ]:          0 :         if (pnp_drv->suspend) {
     179                 :          0 :                 error = pnp_drv->suspend(pnp_dev, state);
     180         [ #  # ]:          0 :                 if (error)
     181                 :            :                         return error;
     182                 :            :         }
     183                 :            : 
     184   [ #  #  #  #  :          0 :         if (pnp_can_disable(pnp_dev)) {
             #  #  #  # ]
     185                 :          0 :                 error = pnp_stop_dev(pnp_dev);
     186         [ #  # ]:          0 :                 if (error)
     187                 :            :                         return error;
     188                 :            :         }
     189                 :            : 
     190   [ #  #  #  #  :          0 :         if (pnp_can_suspend(pnp_dev))
                   #  # ]
     191                 :          0 :                 pnp_dev->protocol->suspend(pnp_dev, state);
     192                 :            :         return 0;
     193                 :            : }
     194                 :            : 
     195                 :          0 : static int pnp_bus_suspend(struct device *dev)
     196                 :            : {
     197                 :          0 :         return __pnp_bus_suspend(dev, PMSG_SUSPEND);
     198                 :            : }
     199                 :            : 
     200                 :          0 : static int pnp_bus_freeze(struct device *dev)
     201                 :            : {
     202                 :          0 :         return __pnp_bus_suspend(dev, PMSG_FREEZE);
     203                 :            : }
     204                 :            : 
     205                 :          0 : static int pnp_bus_poweroff(struct device *dev)
     206                 :            : {
     207                 :          0 :         return __pnp_bus_suspend(dev, PMSG_HIBERNATE);
     208                 :            : }
     209                 :            : 
     210                 :          0 : static int pnp_bus_resume(struct device *dev)
     211                 :            : {
     212                 :          0 :         struct pnp_dev *pnp_dev = to_pnp_dev(dev);
     213                 :          0 :         struct pnp_driver *pnp_drv = pnp_dev->driver;
     214                 :          0 :         int error;
     215                 :            : 
     216         [ #  # ]:          0 :         if (!pnp_drv)
     217                 :            :                 return 0;
     218                 :            : 
     219         [ #  # ]:          0 :         if (pnp_dev->protocol->resume) {
     220                 :          0 :                 error = pnp_dev->protocol->resume(pnp_dev);
     221         [ #  # ]:          0 :                 if (error)
     222                 :            :                         return error;
     223                 :            :         }
     224                 :            : 
     225   [ #  #  #  # ]:          0 :         if (pnp_can_write(pnp_dev)) {
     226                 :          0 :                 error = pnp_start_dev(pnp_dev);
     227         [ #  # ]:          0 :                 if (error)
     228                 :            :                         return error;
     229                 :            :         }
     230                 :            : 
     231   [ #  #  #  # ]:          0 :         if (pnp_drv->driver.pm && pnp_drv->driver.pm->resume) {
     232                 :          0 :                 error = pnp_drv->driver.pm->resume(dev);
     233         [ #  # ]:          0 :                 if (error)
     234                 :            :                         return error;
     235                 :            :         }
     236                 :            : 
     237         [ #  # ]:          0 :         if (pnp_drv->resume) {
     238                 :          0 :                 error = pnp_drv->resume(pnp_dev);
     239         [ #  # ]:          0 :                 if (error)
     240                 :          0 :                         return error;
     241                 :            :         }
     242                 :            : 
     243                 :            :         return 0;
     244                 :            : }
     245                 :            : 
     246                 :            : static const struct dev_pm_ops pnp_bus_dev_pm_ops = {
     247                 :            :         /* Suspend callbacks */
     248                 :            :         .suspend = pnp_bus_suspend,
     249                 :            :         .resume = pnp_bus_resume,
     250                 :            :         /* Hibernate callbacks */
     251                 :            :         .freeze = pnp_bus_freeze,
     252                 :            :         .thaw = pnp_bus_resume,
     253                 :            :         .poweroff = pnp_bus_poweroff,
     254                 :            :         .restore = pnp_bus_resume,
     255                 :            : };
     256                 :            : 
     257                 :            : struct bus_type pnp_bus_type = {
     258                 :            :         .name    = "pnp",
     259                 :            :         .match   = pnp_bus_match,
     260                 :            :         .probe   = pnp_device_probe,
     261                 :            :         .remove  = pnp_device_remove,
     262                 :            :         .shutdown = pnp_device_shutdown,
     263                 :            :         .pm      = &pnp_bus_dev_pm_ops,
     264                 :            :         .dev_groups = pnp_dev_groups,
     265                 :            : };
     266                 :            : 
     267                 :         55 : int pnp_register_driver(struct pnp_driver *drv)
     268                 :            : {
     269                 :         55 :         drv->driver.name = drv->name;
     270                 :         55 :         drv->driver.bus = &pnp_bus_type;
     271                 :            : 
     272                 :         55 :         return driver_register(&drv->driver);
     273                 :            : }
     274                 :            : 
     275                 :          0 : void pnp_unregister_driver(struct pnp_driver *drv)
     276                 :            : {
     277                 :          0 :         driver_unregister(&drv->driver);
     278                 :          0 : }
     279                 :            : 
     280                 :            : /**
     281                 :            :  * pnp_add_id - adds an EISA id to the specified device
     282                 :            :  * @dev: pointer to the desired device
     283                 :            :  * @id: pointer to an EISA id string
     284                 :            :  */
     285                 :         66 : struct pnp_id *pnp_add_id(struct pnp_dev *dev, const char *id)
     286                 :            : {
     287                 :         66 :         struct pnp_id *dev_id, *ptr;
     288                 :            : 
     289                 :         66 :         dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
     290         [ +  - ]:         66 :         if (!dev_id)
     291                 :            :                 return NULL;
     292                 :            : 
     293                 :         66 :         dev_id->id[0] = id[0];
     294                 :         66 :         dev_id->id[1] = id[1];
     295                 :         66 :         dev_id->id[2] = id[2];
     296         [ -  + ]:         66 :         dev_id->id[3] = tolower(id[3]);
     297         [ +  + ]:         66 :         dev_id->id[4] = tolower(id[4]);
     298         [ -  + ]:         66 :         dev_id->id[5] = tolower(id[5]);
     299         [ -  + ]:         66 :         dev_id->id[6] = tolower(id[6]);
     300                 :         66 :         dev_id->id[7] = '\0';
     301                 :            : 
     302                 :         66 :         dev_id->next = NULL;
     303                 :         66 :         ptr = dev->id;
     304   [ -  +  -  - ]:         66 :         while (ptr && ptr->next)
     305                 :            :                 ptr = ptr->next;
     306         [ -  + ]:         66 :         if (ptr)
     307                 :          0 :                 ptr->next = dev_id;
     308                 :            :         else
     309                 :         66 :                 dev->id = dev_id;
     310                 :            : 
     311                 :            :         return dev_id;
     312                 :            : }
     313                 :            : 
     314                 :            : EXPORT_SYMBOL(pnp_register_driver);
     315                 :            : EXPORT_SYMBOL(pnp_unregister_driver);
     316                 :            : EXPORT_SYMBOL(pnp_device_attach);
     317                 :            : EXPORT_SYMBOL(pnp_device_detach);

Generated by: LCOV version 1.14