root/drivers/pnp/driver.c

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

DEFINITIONS

This source file includes following definitions.
  1. compare_func
  2. compare_pnp_id
  3. match_device
  4. pnp_device_attach
  5. pnp_device_detach
  6. pnp_device_probe
  7. pnp_device_remove
  8. pnp_device_shutdown
  9. pnp_bus_match
  10. __pnp_bus_suspend
  11. pnp_bus_suspend
  12. pnp_bus_freeze
  13. pnp_bus_poweroff
  14. pnp_bus_resume
  15. pnp_register_driver
  16. pnp_unregister_driver
  17. pnp_add_id

   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 static int compare_func(const char *ida, const char *idb)
  17 {
  18         int i;
  19 
  20         /* we only need to compare the last 4 chars */
  21         for (i = 3; i < 7; i++) {
  22                 if (ida[i] != 'X' &&
  23                     idb[i] != 'X' && toupper(ida[i]) != toupper(idb[i]))
  24                         return 0;
  25         }
  26         return 1;
  27 }
  28 
  29 int compare_pnp_id(struct pnp_id *pos, const char *id)
  30 {
  31         if (!pos || !id || (strlen(id) != 7))
  32                 return 0;
  33         if (memcmp(id, "ANYDEVS", 7) == 0)
  34                 return 1;
  35         while (pos) {
  36                 if (memcmp(pos->id, id, 3) == 0)
  37                         if (compare_func(pos->id, id) == 1)
  38                                 return 1;
  39                 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 int pnp_device_attach(struct pnp_dev *pnp_dev)
  61 {
  62         mutex_lock(&pnp_lock);
  63         if (pnp_dev->status != PNP_READY) {
  64                 mutex_unlock(&pnp_lock);
  65                 return -EBUSY;
  66         }
  67         pnp_dev->status = PNP_ATTACHED;
  68         mutex_unlock(&pnp_lock);
  69         return 0;
  70 }
  71 
  72 void pnp_device_detach(struct pnp_dev *pnp_dev)
  73 {
  74         mutex_lock(&pnp_lock);
  75         if (pnp_dev->status == PNP_ATTACHED)
  76                 pnp_dev->status = PNP_READY;
  77         mutex_unlock(&pnp_lock);
  78 }
  79 
  80 static int pnp_device_probe(struct device *dev)
  81 {
  82         int error;
  83         struct pnp_driver *pnp_drv;
  84         struct pnp_dev *pnp_dev;
  85         const struct pnp_device_id *dev_id = NULL;
  86         pnp_dev = to_pnp_dev(dev);
  87         pnp_drv = to_pnp_driver(dev->driver);
  88 
  89         error = pnp_device_attach(pnp_dev);
  90         if (error < 0)
  91                 return error;
  92 
  93         if (pnp_dev->active == 0) {
  94                 if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)) {
  95                         error = pnp_activate_dev(pnp_dev);
  96                         if (error < 0)
  97                                 return error;
  98                 }
  99         } else if ((pnp_drv->flags & PNP_DRIVER_RES_DISABLE)
 100                    == PNP_DRIVER_RES_DISABLE) {
 101                 error = pnp_disable_dev(pnp_dev);
 102                 if (error < 0)
 103                         return error;
 104         }
 105         error = 0;
 106         if (pnp_drv->probe) {
 107                 dev_id = match_device(pnp_drv, pnp_dev);
 108                 if (dev_id != NULL)
 109                         error = pnp_drv->probe(pnp_dev, dev_id);
 110         }
 111         if (error >= 0) {
 112                 pnp_dev->driver = pnp_drv;
 113                 error = 0;
 114         } else
 115                 goto fail;
 116 
 117         return error;
 118 
 119 fail:
 120         pnp_device_detach(pnp_dev);
 121         return error;
 122 }
 123 
 124 static int pnp_device_remove(struct device *dev)
 125 {
 126         struct pnp_dev *pnp_dev = to_pnp_dev(dev);
 127         struct pnp_driver *drv = pnp_dev->driver;
 128 
 129         if (drv) {
 130                 if (drv->remove)
 131                         drv->remove(pnp_dev);
 132                 pnp_dev->driver = NULL;
 133         }
 134 
 135         if (pnp_dev->active &&
 136             (!drv || !(drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)))
 137                 pnp_disable_dev(pnp_dev);
 138 
 139         pnp_device_detach(pnp_dev);
 140         return 0;
 141 }
 142 
 143 static void pnp_device_shutdown(struct device *dev)
 144 {
 145         struct pnp_dev *pnp_dev = to_pnp_dev(dev);
 146         struct pnp_driver *drv = pnp_dev->driver;
 147 
 148         if (drv && drv->shutdown)
 149                 drv->shutdown(pnp_dev);
 150 }
 151 
 152 static int pnp_bus_match(struct device *dev, struct device_driver *drv)
 153 {
 154         struct pnp_dev *pnp_dev = to_pnp_dev(dev);
 155         struct pnp_driver *pnp_drv = to_pnp_driver(drv);
 156 
 157         if (match_device(pnp_drv, pnp_dev) == NULL)
 158                 return 0;
 159         return 1;
 160 }
 161 
 162 static int __pnp_bus_suspend(struct device *dev, pm_message_t state)
 163 {
 164         struct pnp_dev *pnp_dev = to_pnp_dev(dev);
 165         struct pnp_driver *pnp_drv = pnp_dev->driver;
 166         int error;
 167 
 168         if (!pnp_drv)
 169                 return 0;
 170 
 171         if (pnp_drv->driver.pm && pnp_drv->driver.pm->suspend) {
 172                 error = pnp_drv->driver.pm->suspend(dev);
 173                 suspend_report_result(pnp_drv->driver.pm->suspend, error);
 174                 if (error)
 175                         return error;
 176         }
 177 
 178         if (pnp_drv->suspend) {
 179                 error = pnp_drv->suspend(pnp_dev, state);
 180                 if (error)
 181                         return error;
 182         }
 183 
 184         if (pnp_can_disable(pnp_dev)) {
 185                 error = pnp_stop_dev(pnp_dev);
 186                 if (error)
 187                         return error;
 188         }
 189 
 190         if (pnp_can_suspend(pnp_dev))
 191                 pnp_dev->protocol->suspend(pnp_dev, state);
 192         return 0;
 193 }
 194 
 195 static int pnp_bus_suspend(struct device *dev)
 196 {
 197         return __pnp_bus_suspend(dev, PMSG_SUSPEND);
 198 }
 199 
 200 static int pnp_bus_freeze(struct device *dev)
 201 {
 202         return __pnp_bus_suspend(dev, PMSG_FREEZE);
 203 }
 204 
 205 static int pnp_bus_poweroff(struct device *dev)
 206 {
 207         return __pnp_bus_suspend(dev, PMSG_HIBERNATE);
 208 }
 209 
 210 static int pnp_bus_resume(struct device *dev)
 211 {
 212         struct pnp_dev *pnp_dev = to_pnp_dev(dev);
 213         struct pnp_driver *pnp_drv = pnp_dev->driver;
 214         int error;
 215 
 216         if (!pnp_drv)
 217                 return 0;
 218 
 219         if (pnp_dev->protocol->resume) {
 220                 error = pnp_dev->protocol->resume(pnp_dev);
 221                 if (error)
 222                         return error;
 223         }
 224 
 225         if (pnp_can_write(pnp_dev)) {
 226                 error = pnp_start_dev(pnp_dev);
 227                 if (error)
 228                         return error;
 229         }
 230 
 231         if (pnp_drv->driver.pm && pnp_drv->driver.pm->resume) {
 232                 error = pnp_drv->driver.pm->resume(dev);
 233                 if (error)
 234                         return error;
 235         }
 236 
 237         if (pnp_drv->resume) {
 238                 error = pnp_drv->resume(pnp_dev);
 239                 if (error)
 240                         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 int pnp_register_driver(struct pnp_driver *drv)
 268 {
 269         drv->driver.name = drv->name;
 270         drv->driver.bus = &pnp_bus_type;
 271 
 272         return driver_register(&drv->driver);
 273 }
 274 
 275 void pnp_unregister_driver(struct pnp_driver *drv)
 276 {
 277         driver_unregister(&drv->driver);
 278 }
 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 struct pnp_id *pnp_add_id(struct pnp_dev *dev, const char *id)
 286 {
 287         struct pnp_id *dev_id, *ptr;
 288 
 289         dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
 290         if (!dev_id)
 291                 return NULL;
 292 
 293         dev_id->id[0] = id[0];
 294         dev_id->id[1] = id[1];
 295         dev_id->id[2] = id[2];
 296         dev_id->id[3] = tolower(id[3]);
 297         dev_id->id[4] = tolower(id[4]);
 298         dev_id->id[5] = tolower(id[5]);
 299         dev_id->id[6] = tolower(id[6]);
 300         dev_id->id[7] = '\0';
 301 
 302         dev_id->next = NULL;
 303         ptr = dev->id;
 304         while (ptr && ptr->next)
 305                 ptr = ptr->next;
 306         if (ptr)
 307                 ptr->next = dev_id;
 308         else
 309                 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);

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