diff options
| author | Thomas Renninger <trenn@suse.de> | 2007-07-23 08:43:51 -0400 |
|---|---|---|
| committer | Len Brown <len.brown@intel.com> | 2007-07-23 13:56:16 -0400 |
| commit | 29b71a1ca74491fab9fed09e9d835d840d042690 (patch) | |
| tree | e46dc9c53e4b6266703dedc21925875cea9e4abc | |
| parent | 8c8eb78f673c07b60f31751e1e47ac367c60c6b7 (diff) | |
ACPI: autoload modules - Create ACPI alias interface
Modify modpost (file2alias.c) to add acpi*:XYZ0001: alias in modules.alias
like:
grep acpi /lib/modules/2.6.22-rc4-default/modules.alias
alias acpi*:SNY5001:* sony_laptop
alias acpi*:SNY6001:* sony_laptop
for e.g. the sony_laptop module.
This module matches against all ACPI devices with a HID or CID of SNY5001
or SNY6001
Export an uevent and modalias sysfs file containing the string:
[MODALIAS=]acpi:PNP0C0C:
additional CIDs are concatenated at the end.
Signed-off-by: Thomas Renninger <trenn@suse.de>
Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
Signed-off-by: Len Brown <len.brown@intel.com>
| -rw-r--r-- | drivers/acpi/scan.c | 156 | ||||
| -rw-r--r-- | drivers/pnp/pnpacpi/core.c | 19 | ||||
| -rw-r--r-- | include/linux/acpi.h | 1 | ||||
| -rw-r--r-- | include/linux/mod_devicetable.h | 6 | ||||
| -rw-r--r-- | scripts/mod/file2alias.c | 12 |
5 files changed, 142 insertions, 52 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 6b3b8a522476..be74347d1354 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
| @@ -16,7 +16,7 @@ ACPI_MODULE_NAME("scan"); | |||
| 16 | extern struct acpi_device *acpi_root; | 16 | extern struct acpi_device *acpi_root; |
| 17 | 17 | ||
| 18 | #define ACPI_BUS_CLASS "system_bus" | 18 | #define ACPI_BUS_CLASS "system_bus" |
| 19 | #define ACPI_BUS_HID "ACPI_BUS" | 19 | #define ACPI_BUS_HID "LNXSYBUS" |
| 20 | #define ACPI_BUS_DEVICE_NAME "System Bus" | 20 | #define ACPI_BUS_DEVICE_NAME "System Bus" |
| 21 | 21 | ||
| 22 | static LIST_HEAD(acpi_device_list); | 22 | static LIST_HEAD(acpi_device_list); |
| @@ -29,6 +29,62 @@ struct acpi_device_bus_id{ | |||
| 29 | unsigned int instance_no; | 29 | unsigned int instance_no; |
| 30 | struct list_head node; | 30 | struct list_head node; |
| 31 | }; | 31 | }; |
| 32 | |||
| 33 | /* | ||
| 34 | * Creates hid/cid(s) string needed for modalias and uevent | ||
| 35 | * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get: | ||
| 36 | * char *modalias: "acpi:IBM0001:ACPI0001" | ||
| 37 | */ | ||
| 38 | int create_modalias(struct acpi_device *acpi_dev, char *modalias, int size){ | ||
| 39 | |||
| 40 | int len; | ||
| 41 | |||
| 42 | if (!acpi_dev->flags.hardware_id) | ||
| 43 | return -ENODEV; | ||
| 44 | |||
| 45 | len = snprintf(modalias, size, "acpi:%s:", | ||
| 46 | acpi_dev->pnp.hardware_id); | ||
| 47 | if (len < 0 || len >= size) | ||
| 48 | return -EINVAL; | ||
| 49 | size -= len; | ||
| 50 | |||
| 51 | if (acpi_dev->flags.compatible_ids) { | ||
| 52 | struct acpi_compatible_id_list *cid_list; | ||
| 53 | int i; | ||
| 54 | int count; | ||
| 55 | |||
| 56 | cid_list = acpi_dev->pnp.cid_list; | ||
| 57 | for (i = 0; i < cid_list->count; i++) { | ||
| 58 | count = snprintf(&modalias[len], size, "%s:", | ||
| 59 | cid_list->id[i].value); | ||
| 60 | if (count < 0 || count >= size) { | ||
| 61 | printk(KERN_ERR "acpi: %s cid[%i] exceeds event buffer size", | ||
| 62 | acpi_dev->pnp.device_name, i); | ||
| 63 | break; | ||
| 64 | } | ||
| 65 | len += count; | ||
| 66 | size -= count; | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | modalias[len] = '\0'; | ||
| 71 | return len; | ||
| 72 | } | ||
| 73 | |||
| 74 | static ssize_t | ||
| 75 | acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { | ||
| 76 | struct acpi_device *acpi_dev = to_acpi_device(dev); | ||
| 77 | int len; | ||
| 78 | |||
| 79 | /* Device has no HID and no CID or string is >1024 */ | ||
| 80 | len = create_modalias(acpi_dev, buf, 1024); | ||
| 81 | if (len <= 0) | ||
| 82 | return 0; | ||
| 83 | buf[len++] = '\n'; | ||
| 84 | return len; | ||
| 85 | } | ||
| 86 | static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); | ||
| 87 | |||
| 32 | static int acpi_eject_operation(acpi_handle handle, int lockable) | 88 | static int acpi_eject_operation(acpi_handle handle, int lockable) |
| 33 | { | 89 | { |
| 34 | struct acpi_object_list arg_list; | 90 | struct acpi_object_list arg_list; |
| @@ -154,6 +210,12 @@ static int acpi_device_setup_files(struct acpi_device *dev) | |||
| 154 | goto end; | 210 | goto end; |
| 155 | } | 211 | } |
| 156 | 212 | ||
| 213 | if (dev->flags.hardware_id || dev->flags.compatible_ids){ | ||
| 214 | result = device_create_file(&dev->dev, &dev_attr_modalias); | ||
| 215 | if(result) | ||
| 216 | goto end; | ||
| 217 | } | ||
| 218 | |||
| 157 | /* | 219 | /* |
| 158 | * If device has _EJ0, 'eject' file is created that is used to trigger | 220 | * If device has _EJ0, 'eject' file is created that is used to trigger |
| 159 | * hot-removal function from userland. | 221 | * hot-removal function from userland. |
| @@ -178,6 +240,9 @@ static void acpi_device_remove_files(struct acpi_device *dev) | |||
| 178 | if (ACPI_SUCCESS(status)) | 240 | if (ACPI_SUCCESS(status)) |
| 179 | device_remove_file(&dev->dev, &dev_attr_eject); | 241 | device_remove_file(&dev->dev, &dev_attr_eject); |
| 180 | 242 | ||
| 243 | if (dev->flags.hardware_id || dev->flags.compatible_ids) | ||
| 244 | device_remove_file(&dev->dev, &dev_attr_modalias); | ||
| 245 | |||
| 181 | if(dev->flags.hardware_id) | 246 | if(dev->flags.hardware_id) |
| 182 | device_remove_file(&dev->dev, &dev_attr_hid); | 247 | device_remove_file(&dev->dev, &dev_attr_hid); |
| 183 | if(dev->handle) | 248 | if(dev->handle) |
| @@ -186,6 +251,37 @@ static void acpi_device_remove_files(struct acpi_device *dev) | |||
| 186 | /* -------------------------------------------------------------------------- | 251 | /* -------------------------------------------------------------------------- |
| 187 | ACPI Bus operations | 252 | ACPI Bus operations |
| 188 | -------------------------------------------------------------------------- */ | 253 | -------------------------------------------------------------------------- */ |
| 254 | |||
| 255 | int acpi_match_device_ids(struct acpi_device *device, | ||
| 256 | const struct acpi_device_id *ids) | ||
| 257 | { | ||
| 258 | const struct acpi_device_id *id; | ||
| 259 | |||
| 260 | if (device->flags.hardware_id) { | ||
| 261 | for (id = ids; id->id[0]; id++) { | ||
| 262 | if (!strcmp((char*)id->id, device->pnp.hardware_id)) | ||
| 263 | return 0; | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | if (device->flags.compatible_ids) { | ||
| 268 | struct acpi_compatible_id_list *cid_list = device->pnp.cid_list; | ||
| 269 | int i; | ||
| 270 | |||
| 271 | for (id = ids; id->id[0]; id++) { | ||
| 272 | /* compare multiple _CID entries against driver ids */ | ||
| 273 | for (i = 0; i < cid_list->count; i++) { | ||
| 274 | if (!strcmp((char*)id->id, | ||
| 275 | cid_list->id[i].value)) | ||
| 276 | return 0; | ||
| 277 | } | ||
| 278 | } | ||
| 279 | } | ||
| 280 | |||
| 281 | return -ENOENT; | ||
| 282 | } | ||
| 283 | EXPORT_SYMBOL(acpi_match_device_ids); | ||
| 284 | |||
| 189 | static void acpi_device_release(struct device *dev) | 285 | static void acpi_device_release(struct device *dev) |
| 190 | { | 286 | { |
| 191 | struct acpi_device *acpi_dev = to_acpi_device(dev); | 287 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
| @@ -219,37 +315,19 @@ static int acpi_bus_match(struct device *dev, struct device_driver *drv) | |||
| 219 | struct acpi_device *acpi_dev = to_acpi_device(dev); | 315 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
| 220 | struct acpi_driver *acpi_drv = to_acpi_driver(drv); | 316 | struct acpi_driver *acpi_drv = to_acpi_driver(drv); |
| 221 | 317 | ||
| 222 | return !acpi_match_ids(acpi_dev, acpi_drv->ids); | 318 | return !acpi_match_device_ids(acpi_dev, acpi_drv->ids); |
| 223 | } | 319 | } |
| 224 | 320 | ||
| 225 | static int acpi_device_uevent(struct device *dev, char **envp, int num_envp, | 321 | static int acpi_device_uevent(struct device *dev, char **envp, int num_envp, |
| 226 | char *buffer, int buffer_size) | 322 | char *buffer, int buffer_size) |
| 227 | { | 323 | { |
| 228 | struct acpi_device *acpi_dev = to_acpi_device(dev); | 324 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
| 229 | int i = 0, length = 0, ret = 0; | ||
| 230 | |||
| 231 | if (acpi_dev->flags.hardware_id) | ||
| 232 | ret = add_uevent_var(envp, num_envp, &i, | ||
| 233 | buffer, buffer_size, &length, | ||
| 234 | "HWID=%s", acpi_dev->pnp.hardware_id); | ||
| 235 | if (ret) | ||
| 236 | return -ENOMEM; | ||
| 237 | if (acpi_dev->flags.compatible_ids) { | ||
| 238 | int j; | ||
| 239 | struct acpi_compatible_id_list *cid_list; | ||
| 240 | 325 | ||
| 241 | cid_list = acpi_dev->pnp.cid_list; | 326 | strcpy(buffer, "MODALIAS="); |
| 242 | 327 | if (create_modalias(acpi_dev, buffer + 9, buffer_size - 9) > 0) { | |
| 243 | for (j = 0; j < cid_list->count; j++) { | 328 | envp[0] = buffer; |
| 244 | ret = add_uevent_var(envp, num_envp, &i, buffer, | 329 | envp[1] = NULL; |
| 245 | buffer_size, &length, "COMPTID=%s", | ||
| 246 | cid_list->id[j].value); | ||
| 247 | if (ret) | ||
| 248 | return -ENOMEM; | ||
| 249 | } | ||
| 250 | } | 330 | } |
| 251 | |||
| 252 | envp[i] = NULL; | ||
| 253 | return 0; | 331 | return 0; |
| 254 | } | 332 | } |
| 255 | 333 | ||
| @@ -543,25 +621,6 @@ void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context) | |||
| 543 | return; | 621 | return; |
| 544 | } | 622 | } |
| 545 | 623 | ||
| 546 | int acpi_match_ids(struct acpi_device *device, char *ids) | ||
| 547 | { | ||
| 548 | if (device->flags.hardware_id) | ||
| 549 | if (strstr(ids, device->pnp.hardware_id)) | ||
| 550 | return 0; | ||
| 551 | |||
| 552 | if (device->flags.compatible_ids) { | ||
| 553 | struct acpi_compatible_id_list *cid_list = device->pnp.cid_list; | ||
| 554 | int i; | ||
| 555 | |||
| 556 | /* compare multiple _CID entries against driver ids */ | ||
| 557 | for (i = 0; i < cid_list->count; i++) { | ||
| 558 | if (strstr(ids, cid_list->id[i].value)) | ||
| 559 | return 0; | ||
| 560 | } | ||
| 561 | } | ||
| 562 | return -ENOENT; | ||
| 563 | } | ||
| 564 | |||
| 565 | static int acpi_bus_get_perf_flags(struct acpi_device *device) | 624 | static int acpi_bus_get_perf_flags(struct acpi_device *device) |
| 566 | { | 625 | { |
| 567 | device->performance.state = ACPI_STATE_UNKNOWN; | 626 | device->performance.state = ACPI_STATE_UNKNOWN; |
| @@ -624,6 +683,13 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) | |||
| 624 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 683 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
| 625 | union acpi_object *package = NULL; | 684 | union acpi_object *package = NULL; |
| 626 | 685 | ||
| 686 | struct acpi_device_id button_device_ids[] = { | ||
| 687 | {"PNP0C0D", 0}, | ||
| 688 | {"PNP0C0C", 0}, | ||
| 689 | {"PNP0C0E", 0}, | ||
| 690 | {"", 0}, | ||
| 691 | }; | ||
| 692 | |||
| 627 | 693 | ||
| 628 | /* _PRW */ | 694 | /* _PRW */ |
| 629 | status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer); | 695 | status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer); |
| @@ -643,7 +709,7 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) | |||
| 643 | 709 | ||
| 644 | device->wakeup.flags.valid = 1; | 710 | device->wakeup.flags.valid = 1; |
| 645 | /* Power button, Lid switch always enable wakeup */ | 711 | /* Power button, Lid switch always enable wakeup */ |
| 646 | if (!acpi_match_ids(device, "PNP0C0D,PNP0C0C,PNP0C0E")) | 712 | if (!acpi_match_device_ids(device, button_device_ids)) |
| 647 | device->wakeup.flags.run_wake = 1; | 713 | device->wakeup.flags.run_wake = 1; |
| 648 | 714 | ||
| 649 | end: | 715 | end: |
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index a00548799e98..0bc889144e6f 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c | |||
| @@ -21,7 +21,10 @@ | |||
| 21 | 21 | ||
| 22 | #include <linux/acpi.h> | 22 | #include <linux/acpi.h> |
| 23 | #include <linux/pnp.h> | 23 | #include <linux/pnp.h> |
| 24 | #include <linux/mod_devicetable.h> | ||
| 24 | #include <acpi/acpi_bus.h> | 25 | #include <acpi/acpi_bus.h> |
| 26 | #include <acpi/actypes.h> | ||
| 27 | |||
| 25 | #include "pnpacpi.h" | 28 | #include "pnpacpi.h" |
| 26 | 29 | ||
| 27 | static int num = 0; | 30 | static int num = 0; |
| @@ -33,15 +36,17 @@ static int num = 0; | |||
| 33 | * have irqs (PIC, Timer) because we call acpi_register_gsi. | 36 | * have irqs (PIC, Timer) because we call acpi_register_gsi. |
| 34 | * Finaly only devices that have a CRS method need to be in this list. | 37 | * Finaly only devices that have a CRS method need to be in this list. |
| 35 | */ | 38 | */ |
| 36 | static char __initdata excluded_id_list[] = | 39 | static __initdata struct acpi_device_id excluded_id_list[] ={ |
| 37 | "PNP0C09," /* EC */ | 40 | {"PNP0C09", 0}, /* EC */ |
| 38 | "PNP0C0F," /* Link device */ | 41 | {"PNP0C0F", 0}, /* Link device */ |
| 39 | "PNP0000," /* PIC */ | 42 | {"PNP0000", 0}, /* PIC */ |
| 40 | "PNP0100," /* Timer */ | 43 | {"PNP0100", 0}, /* Timer */ |
| 41 | ; | 44 | {"", 0}, |
| 45 | }; | ||
| 46 | |||
| 42 | static inline int is_exclusive_device(struct acpi_device *dev) | 47 | static inline int is_exclusive_device(struct acpi_device *dev) |
| 43 | { | 48 | { |
| 44 | return (!acpi_match_ids(dev, excluded_id_list)); | 49 | return (!acpi_match_device_ids(dev, excluded_id_list)); |
| 45 | } | 50 | } |
| 46 | 51 | ||
| 47 | /* | 52 | /* |
diff --git a/include/linux/acpi.h b/include/linux/acpi.h index d5680cd7746a..bf5e0009de75 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h | |||
| @@ -33,6 +33,7 @@ | |||
| 33 | #endif | 33 | #endif |
| 34 | 34 | ||
| 35 | #include <linux/list.h> | 35 | #include <linux/list.h> |
| 36 | #include <linux/mod_devicetable.h> | ||
| 36 | 37 | ||
| 37 | #include <acpi/acpi.h> | 38 | #include <acpi/acpi.h> |
| 38 | #include <acpi/acpi_bus.h> | 39 | #include <acpi/acpi_bus.h> |
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index af04a555b52c..2ada8ee316b3 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h | |||
| @@ -159,6 +159,12 @@ struct ap_device_id { | |||
| 159 | 159 | ||
| 160 | #define AP_DEVICE_ID_MATCH_DEVICE_TYPE 0x01 | 160 | #define AP_DEVICE_ID_MATCH_DEVICE_TYPE 0x01 |
| 161 | 161 | ||
| 162 | #define ACPI_ID_LEN 9 | ||
| 163 | |||
| 164 | struct acpi_device_id { | ||
| 165 | __u8 id[ACPI_ID_LEN]; | ||
| 166 | kernel_ulong_t driver_data; | ||
| 167 | }; | ||
| 162 | 168 | ||
| 163 | #define PNP_ID_LEN 8 | 169 | #define PNP_ID_LEN 8 |
| 164 | #define PNP_MAX_DEVICES 8 | 170 | #define PNP_MAX_DEVICES 8 |
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index f646381dc015..8a09021d8c59 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c | |||
| @@ -290,6 +290,14 @@ static int do_serio_entry(const char *filename, | |||
| 290 | return 1; | 290 | return 1; |
| 291 | } | 291 | } |
| 292 | 292 | ||
| 293 | /* looks like: "acpi:ACPI0003 or acpi:PNP0C0B" or "acpi:LNXVIDEO" */ | ||
| 294 | static int do_acpi_entry(const char *filename, | ||
| 295 | struct acpi_device_id *id, char *alias) | ||
| 296 | { | ||
| 297 | sprintf(alias, "acpi*:%s:", id->id); | ||
| 298 | return 1; | ||
| 299 | } | ||
| 300 | |||
| 293 | /* looks like: "pnp:dD" */ | 301 | /* looks like: "pnp:dD" */ |
| 294 | static int do_pnp_entry(const char *filename, | 302 | static int do_pnp_entry(const char *filename, |
| 295 | struct pnp_device_id *id, char *alias) | 303 | struct pnp_device_id *id, char *alias) |
| @@ -551,6 +559,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, | |||
| 551 | do_table(symval, sym->st_size, | 559 | do_table(symval, sym->st_size, |
| 552 | sizeof(struct serio_device_id), "serio", | 560 | sizeof(struct serio_device_id), "serio", |
| 553 | do_serio_entry, mod); | 561 | do_serio_entry, mod); |
| 562 | else if (sym_is(symname, "__mod_acpi_device_table")) | ||
| 563 | do_table(symval, sym->st_size, | ||
| 564 | sizeof(struct acpi_device_id), "acpi", | ||
| 565 | do_acpi_entry, mod); | ||
| 554 | else if (sym_is(symname, "__mod_pnp_device_table")) | 566 | else if (sym_is(symname, "__mod_pnp_device_table")) |
| 555 | do_table(symval, sym->st_size, | 567 | do_table(symval, sym->st_size, |
| 556 | sizeof(struct pnp_device_id), "pnp", | 568 | sizeof(struct pnp_device_id), "pnp", |
