123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- /*
- * pnpacpi -- PnP ACPI driver
- *
- * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr>
- * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
- #include <linux/config.h>
- #include <linux/acpi.h>
- #include <linux/pnp.h>
- #include <acpi/acpi_bus.h>
- #include "pnpacpi.h"
- static int num = 0;
- /* We need only to blacklist devices that have already an acpi driver that
- * can't use pnp layer. We don't need to blacklist device that are directly
- * used by the kernel (PCI root, ...), as it is harmless and there were
- * already present in pnpbios. But there is an exception for devices that
- * have irqs (PIC, Timer) because we call acpi_register_gsi.
- * Finaly only devices that have a CRS method need to be in this list.
- */
- static char __initdata excluded_id_list[] =
- "PNP0C09," /* EC */
- "PNP0C0F," /* Link device */
- "PNP0000," /* PIC */
- "PNP0100," /* Timer */
- ;
- static inline int is_exclusive_device(struct acpi_device *dev)
- {
- return (!acpi_match_ids(dev, excluded_id_list));
- }
- /*
- * Compatible Device IDs
- */
- #define TEST_HEX(c) \
- if (!(('0' <= (c) && (c) <= '9') || ('A' <= (c) && (c) <= 'F'))) \
- return 0
- #define TEST_ALPHA(c) \
- if (!('@' <= (c) || (c) <= 'Z')) \
- return 0
- static int __init ispnpidacpi(char *id)
- {
- TEST_ALPHA(id[0]);
- TEST_ALPHA(id[1]);
- TEST_ALPHA(id[2]);
- TEST_HEX(id[3]);
- TEST_HEX(id[4]);
- TEST_HEX(id[5]);
- TEST_HEX(id[6]);
- if (id[7] != '\0')
- return 0;
- return 1;
- }
- static void __init pnpidacpi_to_pnpid(char *id, char *str)
- {
- str[0] = id[0];
- str[1] = id[1];
- str[2] = id[2];
- str[3] = tolower(id[3]);
- str[4] = tolower(id[4]);
- str[5] = tolower(id[5]);
- str[6] = tolower(id[6]);
- str[7] = '\0';
- }
- static int pnpacpi_get_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
- {
- acpi_status status;
- status = pnpacpi_parse_allocated_resource((acpi_handle)dev->data,
- &dev->res);
- return ACPI_FAILURE(status) ? -ENODEV : 0;
- }
- static int pnpacpi_set_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
- {
- acpi_handle handle = dev->data;
- struct acpi_buffer buffer;
- int ret = 0;
- acpi_status status;
- ret = pnpacpi_build_resource_template(handle, &buffer);
- if (ret)
- return ret;
- ret = pnpacpi_encode_resources(res, &buffer);
- if (ret) {
- kfree(buffer.pointer);
- return ret;
- }
- status = acpi_set_current_resources(handle, &buffer);
- if (ACPI_FAILURE(status))
- ret = -EINVAL;
- kfree(buffer.pointer);
- return ret;
- }
- static int pnpacpi_disable_resources(struct pnp_dev *dev)
- {
- acpi_status status;
-
- /* acpi_unregister_gsi(pnp_irq(dev, 0)); */
- status = acpi_evaluate_object((acpi_handle)dev->data,
- "_DIS", NULL, NULL);
- return ACPI_FAILURE(status) ? -ENODEV : 0;
- }
- static struct pnp_protocol pnpacpi_protocol = {
- .name = "Plug and Play ACPI",
- .get = pnpacpi_get_resources,
- .set = pnpacpi_set_resources,
- .disable = pnpacpi_disable_resources,
- };
- static int __init pnpacpi_add_device(struct acpi_device *device)
- {
- acpi_handle temp = NULL;
- acpi_status status;
- struct pnp_id *dev_id;
- struct pnp_dev *dev;
- status = acpi_get_handle(device->handle, "_CRS", &temp);
- if (ACPI_FAILURE(status) || !ispnpidacpi(acpi_device_hid(device)) ||
- is_exclusive_device(device))
- return 0;
- pnp_dbg("ACPI device : hid %s", acpi_device_hid(device));
- dev = kcalloc(1, sizeof(struct pnp_dev), GFP_KERNEL);
- if (!dev) {
- pnp_err("Out of memory");
- return -ENOMEM;
- }
- dev->data = device->handle;
- /* .enabled means if the device can decode the resources */
- dev->active = device->status.enabled;
- status = acpi_get_handle(device->handle, "_SRS", &temp);
- if (ACPI_SUCCESS(status))
- dev->capabilities |= PNP_CONFIGURABLE;
- dev->capabilities |= PNP_READ;
- if (device->flags.dynamic_status)
- dev->capabilities |= PNP_WRITE;
- if (device->flags.removable)
- dev->capabilities |= PNP_REMOVABLE;
- status = acpi_get_handle(device->handle, "_DIS", &temp);
- if (ACPI_SUCCESS(status))
- dev->capabilities |= PNP_DISABLE;
- dev->protocol = &pnpacpi_protocol;
- if (strlen(acpi_device_name(device)))
- strncpy(dev->name, acpi_device_name(device), sizeof(dev->name));
- else
- strncpy(dev->name, acpi_device_bid(device), sizeof(dev->name));
- dev->number = num;
-
- /* set the initial values for the PnP device */
- dev_id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
- if (!dev_id)
- goto err;
- pnpidacpi_to_pnpid(acpi_device_hid(device), dev_id->id);
- pnp_add_id(dev_id, dev);
- if(dev->active) {
- /* parse allocated resource */
- status = pnpacpi_parse_allocated_resource(device->handle, &dev->res);
- if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
- pnp_err("PnPACPI: METHOD_NAME__CRS failure for %s", dev_id->id);
- goto err1;
- }
- }
- if(dev->capabilities & PNP_CONFIGURABLE) {
- status = pnpacpi_parse_resource_option_data(device->handle,
- dev);
- if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
- pnp_err("PnPACPI: METHOD_NAME__PRS failure for %s", dev_id->id);
- goto err1;
- }
- }
-
- /* parse compatible ids */
- if (device->flags.compatible_ids) {
- struct acpi_compatible_id_list *cid_list = device->pnp.cid_list;
- int i;
- for (i = 0; i < cid_list->count; i++) {
- if (!ispnpidacpi(cid_list->id[i].value))
- continue;
- dev_id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
- if (!dev_id)
- continue;
- pnpidacpi_to_pnpid(cid_list->id[i].value, dev_id->id);
- pnp_add_id(dev_id, dev);
- }
- }
- /* clear out the damaged flags */
- if (!dev->active)
- pnp_init_resource_table(&dev->res);
- pnp_add_device(dev);
- num ++;
- return AE_OK;
- err1:
- kfree(dev_id);
- err:
- kfree(dev);
- return -EINVAL;
- }
- static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle,
- u32 lvl, void *context, void **rv)
- {
- struct acpi_device *device;
- if (!acpi_bus_get_device(handle, &device))
- pnpacpi_add_device(device);
- else
- return AE_CTRL_DEPTH;
- return AE_OK;
- }
- int pnpacpi_disabled __initdata;
- static int __init pnpacpi_init(void)
- {
- if (acpi_disabled || pnpacpi_disabled) {
- pnp_info("PnP ACPI: disabled");
- return 0;
- }
- pnp_info("PnP ACPI init");
- pnp_register_protocol(&pnpacpi_protocol);
- acpi_get_devices(NULL, pnpacpi_add_device_handler, NULL, NULL);
- pnp_info("PnP ACPI: found %d devices", num);
- return 0;
- }
- subsys_initcall(pnpacpi_init);
- static int __init pnpacpi_setup(char *str)
- {
- if (str == NULL)
- return 1;
- if (!strncmp(str, "off", 3))
- pnpacpi_disabled = 1;
- return 1;
- }
- __setup("pnpacpi=", pnpacpi_setup);
- #if 0
- EXPORT_SYMBOL(pnpacpi_protocol);
- #endif
|