2 * pnpacpi -- PnP ACPI driver
4 * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr>
5 * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com>
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
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.
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
22 #include <linux/acpi.h>
23 #include <linux/pnp.h>
24 #include <acpi/acpi_bus.h>
29 static char __initdata excluded_id_list[] =
30 "PNP0C0A," /* Battery */
31 "PNP0C0C,PNP0C0E,PNP0C0D," /* Button */
34 "PNP0A03," /* PCI root */
35 "PNP0C0F," /* Link device */
37 "PNP0100," /* Timer */
39 static inline int is_exclusive_device(struct acpi_device *dev)
41 return (!acpi_match_ids(dev, excluded_id_list));
45 * Compatible Device IDs
48 if (!(('0' <= (c) && (c) <= '9') || ('A' <= (c) && (c) <= 'F'))) \
50 #define TEST_ALPHA(c) \
51 if (!('@' <= (c) || (c) <= 'Z')) \
53 static int __init ispnpidacpi(char *id)
67 static void __init pnpidacpi_to_pnpid(char *id, char *str)
72 str[3] = tolower(id[3]);
73 str[4] = tolower(id[4]);
74 str[5] = tolower(id[5]);
75 str[6] = tolower(id[6]);
79 static int pnpacpi_get_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
82 status = pnpacpi_parse_allocated_resource((acpi_handle)dev->data,
84 return ACPI_FAILURE(status) ? -ENODEV : 0;
87 static int pnpacpi_set_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
89 acpi_handle handle = dev->data;
90 struct acpi_buffer buffer;
94 ret = pnpacpi_build_resource_template(handle, &buffer);
97 ret = pnpacpi_encode_resources(res, &buffer);
99 kfree(buffer.pointer);
102 status = acpi_set_current_resources(handle, &buffer);
103 if (ACPI_FAILURE(status))
105 kfree(buffer.pointer);
109 static int pnpacpi_disable_resources(struct pnp_dev *dev)
113 /* acpi_unregister_gsi(pnp_irq(dev, 0)); */
114 status = acpi_evaluate_object((acpi_handle)dev->data,
116 return ACPI_FAILURE(status) ? -ENODEV : 0;
119 struct pnp_protocol pnpacpi_protocol = {
120 .name = "Plug and Play ACPI",
121 .get = pnpacpi_get_resources,
122 .set = pnpacpi_set_resources,
123 .disable = pnpacpi_disable_resources,
126 static int __init pnpacpi_add_device(struct acpi_device *device)
128 acpi_handle temp = NULL;
130 struct pnp_id *dev_id;
133 if (!ispnpidacpi(acpi_device_hid(device)) ||
134 is_exclusive_device(device))
137 pnp_dbg("ACPI device : hid %s", acpi_device_hid(device));
138 dev = kcalloc(1, sizeof(struct pnp_dev), GFP_KERNEL);
140 pnp_err("Out of memory");
143 dev->data = device->handle;
144 /* .enabled means if the device can decode the resources */
145 dev->active = device->status.enabled;
146 status = acpi_get_handle(device->handle, "_SRS", &temp);
147 if (ACPI_SUCCESS(status))
148 dev->capabilities |= PNP_CONFIGURABLE;
149 dev->capabilities |= PNP_READ;
150 if (device->flags.dynamic_status)
151 dev->capabilities |= PNP_WRITE;
152 if (device->flags.removable)
153 dev->capabilities |= PNP_REMOVABLE;
154 status = acpi_get_handle(device->handle, "_DIS", &temp);
155 if (ACPI_SUCCESS(status))
156 dev->capabilities |= PNP_DISABLE;
158 dev->protocol = &pnpacpi_protocol;
160 if (strlen(acpi_device_name(device)))
161 strncpy(dev->name, acpi_device_name(device), sizeof(dev->name));
163 strncpy(dev->name, acpi_device_bid(device), sizeof(dev->name));
167 /* set the initial values for the PnP device */
168 dev_id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
171 pnpidacpi_to_pnpid(acpi_device_hid(device), dev_id->id);
172 pnp_add_id(dev_id, dev);
175 /* parse allocated resource */
176 status = pnpacpi_parse_allocated_resource(device->handle, &dev->res);
177 if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
178 pnp_err("PnPACPI: METHOD_NAME__CRS failure for %s", dev_id->id);
183 if(dev->capabilities & PNP_CONFIGURABLE) {
184 status = pnpacpi_parse_resource_option_data(device->handle,
186 if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
187 pnp_err("PnPACPI: METHOD_NAME__PRS failure for %s", dev_id->id);
192 /* parse compatible ids */
193 if (device->flags.compatible_ids) {
194 struct acpi_compatible_id_list *cid_list = device->pnp.cid_list;
197 for (i = 0; i < cid_list->count; i++) {
198 if (!ispnpidacpi(cid_list->id[i].value))
200 dev_id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
204 pnpidacpi_to_pnpid(cid_list->id[i].value, dev_id->id);
205 pnp_add_id(dev_id, dev);
209 /* clear out the damaged flags */
211 pnp_init_resource_table(&dev->res);
223 static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle,
224 u32 lvl, void *context, void **rv)
226 struct acpi_device *device;
228 if (!acpi_bus_get_device(handle, &device))
229 pnpacpi_add_device(device);
231 return AE_CTRL_DEPTH;
235 int pnpacpi_disabled __initdata;
236 int __init pnpacpi_init(void)
238 if (acpi_disabled || pnpacpi_disabled) {
239 pnp_info("PnP ACPI: disabled");
242 pnp_info("PnP ACPI init");
243 pnp_register_protocol(&pnpacpi_protocol);
244 acpi_get_devices(NULL, pnpacpi_add_device_handler, NULL, NULL);
245 pnp_info("PnP ACPI: found %d devices", num);
248 subsys_initcall(pnpacpi_init);
250 static int __init pnpacpi_setup(char *str)
254 if (!strncmp(str, "off", 3))
255 pnpacpi_disabled = 1;
258 __setup("pnpacpi=", pnpacpi_setup);
260 EXPORT_SYMBOL(pnpacpi_protocol);