aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Renninger <trenn@suse.de>2007-07-23 08:43:51 -0400
committerLen Brown <len.brown@intel.com>2007-07-23 13:56:16 -0400
commit29b71a1ca74491fab9fed09e9d835d840d042690 (patch)
treee46dc9c53e4b6266703dedc21925875cea9e4abc
parent8c8eb78f673c07b60f31751e1e47ac367c60c6b7 (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.c156
-rw-r--r--drivers/pnp/pnpacpi/core.c19
-rw-r--r--include/linux/acpi.h1
-rw-r--r--include/linux/mod_devicetable.h6
-rw-r--r--scripts/mod/file2alias.c12
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");
16extern struct acpi_device *acpi_root; 16extern 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
22static LIST_HEAD(acpi_device_list); 22static 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*/
38int 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
74static ssize_t
75acpi_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}
86static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
87
32static int acpi_eject_operation(acpi_handle handle, int lockable) 88static 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
255int 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}
283EXPORT_SYMBOL(acpi_match_device_ids);
284
189static void acpi_device_release(struct device *dev) 285static 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
225static int acpi_device_uevent(struct device *dev, char **envp, int num_envp, 321static 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
546int 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
565static int acpi_bus_get_perf_flags(struct acpi_device *device) 624static 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
27static int num = 0; 30static 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 */
36static char __initdata excluded_id_list[] = 39static __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
42static inline int is_exclusive_device(struct acpi_device *dev) 47static 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
164struct 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" */
294static 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" */
294static int do_pnp_entry(const char *filename, 302static 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",