1 /* 2 * pnpacpi -- PnP ACPI driver 3 * 4 * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr> 5 * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the 9 * Free Software Foundation; either version 2, or (at your option) any 10 * later version. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 22 #include <linux/acpi.h> 23 #include <linux/pnp.h> 24 #include <linux/mod_devicetable.h> 25 #include <acpi/acpi_bus.h> 26 #include <acpi/actypes.h> 27 28 #include "pnpacpi.h" 29 30 static int num = 0; 31 32 /* We need only to blacklist devices that have already an acpi driver that 33 * can't use pnp layer. We don't need to blacklist device that are directly 34 * used by the kernel (PCI root, ...), as it is harmless and there were 35 * already present in pnpbios. But there is an exception for devices that 36 * have irqs (PIC, Timer) because we call acpi_register_gsi. 37 * Finally, only devices that have a CRS method need to be in this list. 38 */ 39 static struct acpi_device_id excluded_id_list[] __initdata = { 40 {"PNP0C09", 0}, /* EC */ 41 {"PNP0C0F", 0}, /* Link device */ 42 {"PNP0000", 0}, /* PIC */ 43 {"PNP0100", 0}, /* Timer */ 44 {"", 0}, 45 }; 46 47 static inline int is_exclusive_device(struct acpi_device *dev) 48 { 49 return (!acpi_match_device_ids(dev, excluded_id_list)); 50 } 51 52 /* 53 * Compatible Device IDs 54 */ 55 #define TEST_HEX(c) \ 56 if (!(('0' <= (c) && (c) <= '9') || ('A' <= (c) && (c) <= 'F'))) \ 57 return 0 58 #define TEST_ALPHA(c) \ 59 if (!('@' <= (c) || (c) <= 'Z')) \ 60 return 0 61 static int __init ispnpidacpi(char *id) 62 { 63 TEST_ALPHA(id[0]); 64 TEST_ALPHA(id[1]); 65 TEST_ALPHA(id[2]); 66 TEST_HEX(id[3]); 67 TEST_HEX(id[4]); 68 TEST_HEX(id[5]); 69 TEST_HEX(id[6]); 70 if (id[7] != '\0') 71 return 0; 72 return 1; 73 } 74 75 static void __init pnpidacpi_to_pnpid(char *id, char *str) 76 { 77 str[0] = id[0]; 78 str[1] = id[1]; 79 str[2] = id[2]; 80 str[3] = tolower(id[3]); 81 str[4] = tolower(id[4]); 82 str[5] = tolower(id[5]); 83 str[6] = tolower(id[6]); 84 str[7] = '\0'; 85 } 86 87 static int pnpacpi_get_resources(struct pnp_dev *dev, 88 struct pnp_resource_table *res) 89 { 90 acpi_status status; 91 92 status = pnpacpi_parse_allocated_resource((acpi_handle) dev->data, 93 &dev->res); 94 return ACPI_FAILURE(status) ? -ENODEV : 0; 95 } 96 97 static int pnpacpi_set_resources(struct pnp_dev *dev, 98 struct pnp_resource_table *res) 99 { 100 acpi_handle handle = dev->data; 101 struct acpi_buffer buffer; 102 int ret = 0; 103 acpi_status status; 104 105 ret = pnpacpi_build_resource_template(handle, &buffer); 106 if (ret) 107 return ret; 108 ret = pnpacpi_encode_resources(res, &buffer); 109 if (ret) { 110 kfree(buffer.pointer); 111 return ret; 112 } 113 status = acpi_set_current_resources(handle, &buffer); 114 if (ACPI_FAILURE(status)) 115 ret = -EINVAL; 116 kfree(buffer.pointer); 117 return ret; 118 } 119 120 static int pnpacpi_disable_resources(struct pnp_dev *dev) 121 { 122 acpi_status status; 123 124 /* acpi_unregister_gsi(pnp_irq(dev, 0)); */ 125 status = acpi_evaluate_object((acpi_handle) dev->data, 126 "_DIS", NULL, NULL); 127 return ACPI_FAILURE(status) ? -ENODEV : 0; 128 } 129 130 #ifdef CONFIG_ACPI_SLEEP 131 static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state) 132 { 133 int power_state; 134 135 power_state = acpi_pm_device_sleep_state(&dev->dev, 136 device_may_wakeup(&dev->dev), 137 NULL); 138 if (power_state < 0) 139 power_state = (state.event == PM_EVENT_ON) ? 140 ACPI_STATE_D0 : ACPI_STATE_D3; 141 142 return acpi_bus_set_power((acpi_handle) dev->data, power_state); 143 } 144 145 static int pnpacpi_resume(struct pnp_dev *dev) 146 { 147 return acpi_bus_set_power((acpi_handle) dev->data, ACPI_STATE_D0); 148 } 149 #endif 150 151 static struct pnp_protocol pnpacpi_protocol = { 152 .name = "Plug and Play ACPI", 153 .get = pnpacpi_get_resources, 154 .set = pnpacpi_set_resources, 155 .disable = pnpacpi_disable_resources, 156 #ifdef CONFIG_ACPI_SLEEP 157 .suspend = pnpacpi_suspend, 158 .resume = pnpacpi_resume, 159 #endif 160 }; 161 162 static int __init pnpacpi_add_device(struct acpi_device *device) 163 { 164 acpi_handle temp = NULL; 165 acpi_status status; 166 struct pnp_id *dev_id; 167 struct pnp_dev *dev; 168 169 status = acpi_get_handle(device->handle, "_CRS", &temp); 170 if (ACPI_FAILURE(status) || !ispnpidacpi(acpi_device_hid(device)) || 171 is_exclusive_device(device)) 172 return 0; 173 174 dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL); 175 if (!dev) { 176 pnp_err("Out of memory"); 177 return -ENOMEM; 178 } 179 dev->data = device->handle; 180 /* .enabled means the device can decode the resources */ 181 dev->active = device->status.enabled; 182 status = acpi_get_handle(device->handle, "_SRS", &temp); 183 if (ACPI_SUCCESS(status)) 184 dev->capabilities |= PNP_CONFIGURABLE; 185 dev->capabilities |= PNP_READ; 186 if (device->flags.dynamic_status && (dev->capabilities & PNP_CONFIGURABLE)) 187 dev->capabilities |= PNP_WRITE; 188 if (device->flags.removable) 189 dev->capabilities |= PNP_REMOVABLE; 190 status = acpi_get_handle(device->handle, "_DIS", &temp); 191 if (ACPI_SUCCESS(status)) 192 dev->capabilities |= PNP_DISABLE; 193 194 dev->protocol = &pnpacpi_protocol; 195 196 if (strlen(acpi_device_name(device))) 197 strncpy(dev->name, acpi_device_name(device), sizeof(dev->name)); 198 else 199 strncpy(dev->name, acpi_device_bid(device), sizeof(dev->name)); 200 201 dev->number = num; 202 203 /* set the initial values for the PnP device */ 204 dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL); 205 if (!dev_id) 206 goto err; 207 pnpidacpi_to_pnpid(acpi_device_hid(device), dev_id->id); 208 pnp_add_id(dev_id, dev); 209 210 if (dev->active) { 211 /* parse allocated resource */ 212 status = pnpacpi_parse_allocated_resource(device->handle, 213 &dev->res); 214 if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { 215 pnp_err("PnPACPI: METHOD_NAME__CRS failure for %s", 216 dev_id->id); 217 goto err1; 218 } 219 } 220 221 if (dev->capabilities & PNP_CONFIGURABLE) { 222 status = pnpacpi_parse_resource_option_data(device->handle, 223 dev); 224 if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { 225 pnp_err("PnPACPI: METHOD_NAME__PRS failure for %s", 226 dev_id->id); 227 goto err1; 228 } 229 } 230 231 /* parse compatible ids */ 232 if (device->flags.compatible_ids) { 233 struct acpi_compatible_id_list *cid_list = device->pnp.cid_list; 234 int i; 235 236 for (i = 0; i < cid_list->count; i++) { 237 if (!ispnpidacpi(cid_list->id[i].value)) 238 continue; 239 dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL); 240 if (!dev_id) 241 continue; 242 243 pnpidacpi_to_pnpid(cid_list->id[i].value, dev_id->id); 244 pnp_add_id(dev_id, dev); 245 } 246 } 247 248 /* clear out the damaged flags */ 249 if (!dev->active) 250 pnp_init_resource_table(&dev->res); 251 pnp_add_device(dev); 252 num++; 253 254 return AE_OK; 255 err1: 256 kfree(dev_id); 257 err: 258 kfree(dev); 259 return -EINVAL; 260 } 261 262 static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle, 263 u32 lvl, void *context, 264 void **rv) 265 { 266 struct acpi_device *device; 267 268 if (!acpi_bus_get_device(handle, &device)) 269 pnpacpi_add_device(device); 270 else 271 return AE_CTRL_DEPTH; 272 return AE_OK; 273 } 274 275 static int __init acpi_pnp_match(struct device *dev, void *_pnp) 276 { 277 struct acpi_device *acpi = to_acpi_device(dev); 278 struct pnp_dev *pnp = _pnp; 279 280 /* true means it matched */ 281 return acpi->flags.hardware_id 282 && !acpi_get_physical_device(acpi->handle) 283 && compare_pnp_id(pnp->id, acpi->pnp.hardware_id); 284 } 285 286 static int __init acpi_pnp_find_device(struct device *dev, acpi_handle * handle) 287 { 288 struct device *adev; 289 struct acpi_device *acpi; 290 291 adev = bus_find_device(&acpi_bus_type, NULL, 292 to_pnp_dev(dev), acpi_pnp_match); 293 if (!adev) 294 return -ENODEV; 295 296 acpi = to_acpi_device(adev); 297 *handle = acpi->handle; 298 put_device(adev); 299 return 0; 300 } 301 302 /* complete initialization of a PNPACPI device includes having 303 * pnpdev->dev.archdata.acpi_handle point to its ACPI sibling. 304 */ 305 static struct acpi_bus_type __initdata acpi_pnp_bus = { 306 .bus = &pnp_bus_type, 307 .find_device = acpi_pnp_find_device, 308 }; 309 310 int pnpacpi_disabled __initdata; 311 static int __init pnpacpi_init(void) 312 { 313 if (acpi_disabled || pnpacpi_disabled) { 314 pnp_info("PnP ACPI: disabled"); 315 return 0; 316 } 317 pnp_info("PnP ACPI init"); 318 pnp_register_protocol(&pnpacpi_protocol); 319 register_acpi_bus_type(&acpi_pnp_bus); 320 acpi_get_devices(NULL, pnpacpi_add_device_handler, NULL, NULL); 321 pnp_info("PnP ACPI: found %d devices", num); 322 unregister_acpi_bus_type(&acpi_pnp_bus); 323 pnp_platform_devices = 1; 324 return 0; 325 } 326 327 subsys_initcall(pnpacpi_init); 328 329 static int __init pnpacpi_setup(char *str) 330 { 331 if (str == NULL) 332 return 1; 333 if (!strncmp(str, "off", 3)) 334 pnpacpi_disabled = 1; 335 return 1; 336 } 337 338 __setup("pnpacpi=", pnpacpi_setup); 339