1 /* 2 * driver.c - device id matching, driver model, etc. 3 * 4 * Copyright 2002 Adam Belay <ambx1@neo.rr.com> 5 * 6 */ 7 8 #include <linux/config.h> 9 #include <linux/string.h> 10 #include <linux/list.h> 11 #include <linux/module.h> 12 #include <linux/ctype.h> 13 #include <linux/slab.h> 14 #include <linux/pnp.h> 15 #include "base.h" 16 17 static int compare_func(const char *ida, const char *idb) 18 { 19 int i; 20 /* we only need to compare the last 4 chars */ 21 for (i=3; i<7; i++) 22 { 23 if (ida[i] != 'X' && 24 idb[i] != 'X' && 25 toupper(ida[i]) != toupper(idb[i])) 26 return 0; 27 } 28 return 1; 29 } 30 31 int compare_pnp_id(struct pnp_id *pos, const char *id) 32 { 33 if (!pos || !id || (strlen(id) != 7)) 34 return 0; 35 if (memcmp(id,"ANYDEVS",7)==0) 36 return 1; 37 while (pos){ 38 if (memcmp(pos->id,id,3)==0) 39 if (compare_func(pos->id,id)==1) 40 return 1; 41 pos = pos->next; 42 } 43 return 0; 44 } 45 46 static const struct pnp_device_id * match_device(struct pnp_driver *drv, struct pnp_dev *dev) 47 { 48 const struct pnp_device_id *drv_id = drv->id_table; 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 spin_lock(&pnp_lock); 63 if(pnp_dev->status != PNP_READY){ 64 spin_unlock(&pnp_lock); 65 return -EBUSY; 66 } 67 pnp_dev->status = PNP_ATTACHED; 68 spin_unlock(&pnp_lock); 69 return 0; 70 } 71 72 void pnp_device_detach(struct pnp_dev *pnp_dev) 73 { 74 spin_lock(&pnp_lock); 75 if (pnp_dev->status == PNP_ATTACHED) 76 pnp_dev->status = PNP_READY; 77 spin_unlock(&pnp_lock); 78 pnp_disable_dev(pnp_dev); 79 } 80 81 static int pnp_device_probe(struct device *dev) 82 { 83 int error; 84 struct pnp_driver *pnp_drv; 85 struct pnp_dev *pnp_dev; 86 const struct pnp_device_id *dev_id = NULL; 87 pnp_dev = to_pnp_dev(dev); 88 pnp_drv = to_pnp_driver(dev->driver); 89 90 pnp_dbg("match found with the PnP device '%s' and the driver '%s'", dev->bus_id,pnp_drv->name); 91 92 error = pnp_device_attach(pnp_dev); 93 if (error < 0) 94 return error; 95 96 if (pnp_dev->active == 0) { 97 if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)) { 98 error = pnp_activate_dev(pnp_dev); 99 if (error < 0) 100 return error; 101 } 102 } else if ((pnp_drv->flags & PNP_DRIVER_RES_DISABLE) 103 == PNP_DRIVER_RES_DISABLE) { 104 error = pnp_disable_dev(pnp_dev); 105 if (error < 0) 106 return error; 107 } 108 error = 0; 109 if (pnp_drv->probe) { 110 dev_id = match_device(pnp_drv, pnp_dev); 111 if (dev_id != NULL) 112 error = pnp_drv->probe(pnp_dev, dev_id); 113 } 114 if (error >= 0){ 115 pnp_dev->driver = pnp_drv; 116 error = 0; 117 } else 118 goto fail; 119 return error; 120 121 fail: 122 pnp_device_detach(pnp_dev); 123 return error; 124 } 125 126 static int pnp_device_remove(struct device *dev) 127 { 128 struct pnp_dev * pnp_dev = to_pnp_dev(dev); 129 struct pnp_driver * drv = pnp_dev->driver; 130 131 if (drv) { 132 if (drv->remove) 133 drv->remove(pnp_dev); 134 pnp_dev->driver = NULL; 135 } 136 pnp_device_detach(pnp_dev); 137 return 0; 138 } 139 140 static int pnp_bus_match(struct device *dev, struct device_driver *drv) 141 { 142 struct pnp_dev * pnp_dev = to_pnp_dev(dev); 143 struct pnp_driver * pnp_drv = to_pnp_driver(drv); 144 if (match_device(pnp_drv, pnp_dev) == NULL) 145 return 0; 146 return 1; 147 } 148 149 static int pnp_bus_suspend(struct device *dev, pm_message_t state) 150 { 151 struct pnp_dev * pnp_dev = to_pnp_dev(dev); 152 struct pnp_driver * pnp_drv = pnp_dev->driver; 153 int error; 154 155 if (!pnp_drv) 156 return 0; 157 158 if (pnp_drv->suspend) { 159 error = pnp_drv->suspend(pnp_dev, state); 160 if (error) 161 return error; 162 } 163 164 if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE) && 165 pnp_can_disable(pnp_dev)) { 166 error = pnp_stop_dev(pnp_dev); 167 if (error) 168 return error; 169 } 170 171 return 0; 172 } 173 174 static int pnp_bus_resume(struct device *dev) 175 { 176 struct pnp_dev * pnp_dev = to_pnp_dev(dev); 177 struct pnp_driver * pnp_drv = pnp_dev->driver; 178 int error; 179 180 if (!pnp_drv) 181 return 0; 182 183 if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)) { 184 error = pnp_start_dev(pnp_dev); 185 if (error) 186 return error; 187 } 188 189 if (pnp_drv->resume) 190 return pnp_drv->resume(pnp_dev); 191 192 return 0; 193 } 194 195 struct bus_type pnp_bus_type = { 196 .name = "pnp", 197 .match = pnp_bus_match, 198 .suspend = pnp_bus_suspend, 199 .resume = pnp_bus_resume, 200 }; 201 202 203 static int count_devices(struct device * dev, void * c) 204 { 205 int * count = c; 206 (*count)++; 207 return 0; 208 } 209 210 int pnp_register_driver(struct pnp_driver *drv) 211 { 212 int count; 213 214 pnp_dbg("the driver '%s' has been registered", drv->name); 215 216 drv->driver.name = drv->name; 217 drv->driver.bus = &pnp_bus_type; 218 drv->driver.probe = pnp_device_probe; 219 drv->driver.remove = pnp_device_remove; 220 221 count = driver_register(&drv->driver); 222 223 /* get the number of initial matches */ 224 if (count >= 0){ 225 count = 0; 226 driver_for_each_device(&drv->driver, NULL, &count, count_devices); 227 } 228 return count; 229 } 230 231 void pnp_unregister_driver(struct pnp_driver *drv) 232 { 233 driver_unregister(&drv->driver); 234 pnp_dbg("the driver '%s' has been unregistered", drv->name); 235 } 236 237 /** 238 * pnp_add_id - adds an EISA id to the specified device 239 * @id: pointer to a pnp_id structure 240 * @dev: pointer to the desired device 241 * 242 */ 243 244 int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev) 245 { 246 struct pnp_id *ptr; 247 if (!id) 248 return -EINVAL; 249 if (!dev) 250 return -EINVAL; 251 id->next = NULL; 252 ptr = dev->id; 253 while (ptr && ptr->next) 254 ptr = ptr->next; 255 if (ptr) 256 ptr->next = id; 257 else 258 dev->id = id; 259 return 0; 260 } 261 262 EXPORT_SYMBOL(pnp_register_driver); 263 EXPORT_SYMBOL(pnp_unregister_driver); 264 #if 0 265 EXPORT_SYMBOL(pnp_add_id); 266 #endif 267 EXPORT_SYMBOL(pnp_device_attach); 268 EXPORT_SYMBOL(pnp_device_detach); 269