diff options
author | Patrick Mochel <mochel@linux.intel.com> | 2006-12-07 07:56:38 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2006-12-15 23:38:34 -0500 |
commit | f883d9db008deb20d4969c26475100cec2b7f6f8 (patch) | |
tree | 4d66f2bf9f0a6142685870177e26837fc510f9e1 /drivers/acpi/scan.c | |
parent | a7178df5e7e5730e5daa6cf6d8b8bf73adbe75c0 (diff) |
ACPI: convert to sysfs framework
Setup new sysfs framework
1. Remove /sys/firmware/acpi
2. Add ACPI device in device tree.
File "eject" for every device that has _EJ0 method is moved from
/sys/firmware to /sys/devices.
Operation on this file is exactly the same as before.
i.e. echo 1 to "eject" will cause hot removal of this device.
Corresponding changes should be made in userspace for hot removal.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Zhang Rui<rui.zhang@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/scan.c')
-rw-r--r-- | drivers/acpi/scan.c | 187 |
1 files changed, 41 insertions, 146 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index b616e17de522..97f6bbd6ef3c 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -24,126 +24,6 @@ static LIST_HEAD(acpi_device_list); | |||
24 | DEFINE_SPINLOCK(acpi_device_lock); | 24 | DEFINE_SPINLOCK(acpi_device_lock); |
25 | LIST_HEAD(acpi_wakeup_device_list); | 25 | LIST_HEAD(acpi_wakeup_device_list); |
26 | 26 | ||
27 | |||
28 | static void acpi_device_release_legacy(struct kobject *kobj) | ||
29 | { | ||
30 | struct acpi_device *dev = container_of(kobj, struct acpi_device, kobj); | ||
31 | kfree(dev->pnp.cid_list); | ||
32 | kfree(dev); | ||
33 | } | ||
34 | |||
35 | struct acpi_device_attribute { | ||
36 | struct attribute attr; | ||
37 | ssize_t(*show) (struct acpi_device *, char *); | ||
38 | ssize_t(*store) (struct acpi_device *, const char *, size_t); | ||
39 | }; | ||
40 | |||
41 | typedef void acpi_device_sysfs_files(struct kobject *, | ||
42 | const struct attribute *); | ||
43 | |||
44 | static void setup_sys_fs_device_files(struct acpi_device *dev, | ||
45 | acpi_device_sysfs_files * func); | ||
46 | |||
47 | #define create_sysfs_device_files(dev) \ | ||
48 | setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_create_file) | ||
49 | #define remove_sysfs_device_files(dev) \ | ||
50 | setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_remove_file) | ||
51 | |||
52 | #define to_acpi_dev(n) container_of(n, struct acpi_device, kobj) | ||
53 | #define to_handle_attr(n) container_of(n, struct acpi_device_attribute, attr); | ||
54 | |||
55 | static ssize_t acpi_device_attr_show(struct kobject *kobj, | ||
56 | struct attribute *attr, char *buf) | ||
57 | { | ||
58 | struct acpi_device *device = to_acpi_dev(kobj); | ||
59 | struct acpi_device_attribute *attribute = to_handle_attr(attr); | ||
60 | return attribute->show ? attribute->show(device, buf) : -EIO; | ||
61 | } | ||
62 | static ssize_t acpi_device_attr_store(struct kobject *kobj, | ||
63 | struct attribute *attr, const char *buf, | ||
64 | size_t len) | ||
65 | { | ||
66 | struct acpi_device *device = to_acpi_dev(kobj); | ||
67 | struct acpi_device_attribute *attribute = to_handle_attr(attr); | ||
68 | return attribute->store ? attribute->store(device, buf, len) : -EIO; | ||
69 | } | ||
70 | |||
71 | static struct sysfs_ops acpi_device_sysfs_ops = { | ||
72 | .show = acpi_device_attr_show, | ||
73 | .store = acpi_device_attr_store, | ||
74 | }; | ||
75 | |||
76 | static struct kobj_type ktype_acpi_ns = { | ||
77 | .sysfs_ops = &acpi_device_sysfs_ops, | ||
78 | .release = acpi_device_release_legacy, | ||
79 | }; | ||
80 | |||
81 | static int namespace_uevent(struct kset *kset, struct kobject *kobj, | ||
82 | char **envp, int num_envp, char *buffer, | ||
83 | int buffer_size) | ||
84 | { | ||
85 | struct acpi_device *dev = to_acpi_dev(kobj); | ||
86 | int i = 0; | ||
87 | int len = 0; | ||
88 | |||
89 | if (!dev->driver) | ||
90 | return 0; | ||
91 | |||
92 | if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, | ||
93 | "PHYSDEVDRIVER=%s", dev->driver->name)) | ||
94 | return -ENOMEM; | ||
95 | |||
96 | envp[i] = NULL; | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static struct kset_uevent_ops namespace_uevent_ops = { | ||
102 | .uevent = &namespace_uevent, | ||
103 | }; | ||
104 | |||
105 | static struct kset acpi_namespace_kset = { | ||
106 | .kobj = { | ||
107 | .name = "namespace", | ||
108 | }, | ||
109 | .subsys = &acpi_subsys, | ||
110 | .ktype = &ktype_acpi_ns, | ||
111 | .uevent_ops = &namespace_uevent_ops, | ||
112 | }; | ||
113 | |||
114 | /* -------------------------------------------------------------------------- | ||
115 | ACPI sysfs device file support | ||
116 | -------------------------------------------------------------------------- */ | ||
117 | static ssize_t acpi_eject_store(struct acpi_device *device, | ||
118 | const char *buf, size_t count); | ||
119 | |||
120 | #define ACPI_DEVICE_ATTR(_name,_mode,_show,_store) \ | ||
121 | static struct acpi_device_attribute acpi_device_attr_##_name = \ | ||
122 | __ATTR(_name, _mode, _show, _store) | ||
123 | |||
124 | ACPI_DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store); | ||
125 | |||
126 | /** | ||
127 | * setup_sys_fs_device_files - sets up the device files under device namespace | ||
128 | * @dev: acpi_device object | ||
129 | * @func: function pointer to create or destroy the device file | ||
130 | */ | ||
131 | static void | ||
132 | setup_sys_fs_device_files(struct acpi_device *dev, | ||
133 | acpi_device_sysfs_files * func) | ||
134 | { | ||
135 | acpi_status status; | ||
136 | acpi_handle temp = NULL; | ||
137 | |||
138 | /* | ||
139 | * If device has _EJ0, 'eject' file is created that is used to trigger | ||
140 | * hot-removal function from userland. | ||
141 | */ | ||
142 | status = acpi_get_handle(dev->handle, "_EJ0", &temp); | ||
143 | if (ACPI_SUCCESS(status)) | ||
144 | (*(func)) (&dev->kobj, &acpi_device_attr_eject.attr); | ||
145 | } | ||
146 | |||
147 | static int acpi_eject_operation(acpi_handle handle, int lockable) | 27 | static int acpi_eject_operation(acpi_handle handle, int lockable) |
148 | { | 28 | { |
149 | struct acpi_object_list arg_list; | 29 | struct acpi_object_list arg_list; |
@@ -180,7 +60,8 @@ static int acpi_eject_operation(acpi_handle handle, int lockable) | |||
180 | } | 60 | } |
181 | 61 | ||
182 | static ssize_t | 62 | static ssize_t |
183 | acpi_eject_store(struct acpi_device *device, const char *buf, size_t count) | 63 | acpi_eject_store(struct device *d, struct device_attribute *attr, |
64 | const char *buf, size_t count) | ||
184 | { | 65 | { |
185 | int result; | 66 | int result; |
186 | int ret = count; | 67 | int ret = count; |
@@ -188,26 +69,27 @@ acpi_eject_store(struct acpi_device *device, const char *buf, size_t count) | |||
188 | acpi_status status; | 69 | acpi_status status; |
189 | acpi_handle handle; | 70 | acpi_handle handle; |
190 | acpi_object_type type = 0; | 71 | acpi_object_type type = 0; |
72 | struct acpi_device *acpi_device = to_acpi_device(d); | ||
191 | 73 | ||
192 | if ((!count) || (buf[0] != '1')) { | 74 | if ((!count) || (buf[0] != '1')) { |
193 | return -EINVAL; | 75 | return -EINVAL; |
194 | } | 76 | } |
195 | #ifndef FORCE_EJECT | 77 | #ifndef FORCE_EJECT |
196 | if (device->driver == NULL) { | 78 | if (acpi_device->driver == NULL) { |
197 | ret = -ENODEV; | 79 | ret = -ENODEV; |
198 | goto err; | 80 | goto err; |
199 | } | 81 | } |
200 | #endif | 82 | #endif |
201 | status = acpi_get_type(device->handle, &type); | 83 | status = acpi_get_type(acpi_device->handle, &type); |
202 | if (ACPI_FAILURE(status) || (!device->flags.ejectable)) { | 84 | if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) { |
203 | ret = -ENODEV; | 85 | ret = -ENODEV; |
204 | goto err; | 86 | goto err; |
205 | } | 87 | } |
206 | 88 | ||
207 | islockable = device->flags.lockable; | 89 | islockable = acpi_device->flags.lockable; |
208 | handle = device->handle; | 90 | handle = acpi_device->handle; |
209 | 91 | ||
210 | result = acpi_bus_trim(device, 1); | 92 | result = acpi_bus_trim(acpi_device, 1); |
211 | 93 | ||
212 | if (!result) | 94 | if (!result) |
213 | result = acpi_eject_operation(handle, islockable); | 95 | result = acpi_eject_operation(handle, islockable); |
@@ -219,6 +101,35 @@ acpi_eject_store(struct acpi_device *device, const char *buf, size_t count) | |||
219 | return ret; | 101 | return ret; |
220 | } | 102 | } |
221 | 103 | ||
104 | static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store); | ||
105 | |||
106 | static void acpi_device_setup_files(struct acpi_device *dev) | ||
107 | { | ||
108 | acpi_status status; | ||
109 | acpi_handle temp; | ||
110 | |||
111 | /* | ||
112 | * If device has _EJ0, 'eject' file is created that is used to trigger | ||
113 | * hot-removal function from userland. | ||
114 | */ | ||
115 | status = acpi_get_handle(dev->handle, "_EJ0", &temp); | ||
116 | if (ACPI_SUCCESS(status)) | ||
117 | device_create_file(&dev->dev, &dev_attr_eject); | ||
118 | } | ||
119 | |||
120 | static void acpi_device_remove_files(struct acpi_device *dev) | ||
121 | { | ||
122 | acpi_status status; | ||
123 | acpi_handle temp; | ||
124 | |||
125 | /* | ||
126 | * If device has _EJ0, 'eject' file is created that is used to trigger | ||
127 | * hot-removal function from userland. | ||
128 | */ | ||
129 | status = acpi_get_handle(dev->handle, "_EJ0", &temp); | ||
130 | if (ACPI_SUCCESS(status)) | ||
131 | device_remove_file(&dev->dev, &dev_attr_eject); | ||
132 | } | ||
222 | /* -------------------------------------------------------------------------- | 133 | /* -------------------------------------------------------------------------- |
223 | ACPI Bus operations | 134 | ACPI Bus operations |
224 | -------------------------------------------------------------------------- */ | 135 | -------------------------------------------------------------------------- */ |
@@ -353,8 +264,6 @@ static struct bus_type acpi_bus_type = { | |||
353 | static void acpi_device_register(struct acpi_device *device, | 264 | static void acpi_device_register(struct acpi_device *device, |
354 | struct acpi_device *parent) | 265 | struct acpi_device *parent) |
355 | { | 266 | { |
356 | int err; | ||
357 | |||
358 | /* | 267 | /* |
359 | * Linkage | 268 | * Linkage |
360 | * ------- | 269 | * ------- |
@@ -375,17 +284,6 @@ static void acpi_device_register(struct acpi_device *device, | |||
375 | list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list); | 284 | list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list); |
376 | spin_unlock(&acpi_device_lock); | 285 | spin_unlock(&acpi_device_lock); |
377 | 286 | ||
378 | strlcpy(device->kobj.name, device->pnp.bus_id, KOBJ_NAME_LEN); | ||
379 | if (parent) | ||
380 | device->kobj.parent = &parent->kobj; | ||
381 | device->kobj.ktype = &ktype_acpi_ns; | ||
382 | device->kobj.kset = &acpi_namespace_kset; | ||
383 | err = kobject_register(&device->kobj); | ||
384 | if (err < 0) | ||
385 | printk(KERN_WARNING "%s: kobject_register error: %d\n", | ||
386 | __FUNCTION__, err); | ||
387 | create_sysfs_device_files(device); | ||
388 | |||
389 | if (device->parent) | 287 | if (device->parent) |
390 | device->dev.parent = &parent->dev; | 288 | device->dev.parent = &parent->dev; |
391 | device->dev.bus = &acpi_bus_type; | 289 | device->dev.bus = &acpi_bus_type; |
@@ -393,6 +291,8 @@ static void acpi_device_register(struct acpi_device *device, | |||
393 | sprintf(device->dev.bus_id, "%s", device->pnp.bus_id); | 291 | sprintf(device->dev.bus_id, "%s", device->pnp.bus_id); |
394 | device->dev.release = &acpi_device_release; | 292 | device->dev.release = &acpi_device_release; |
395 | device_add(&device->dev); | 293 | device_add(&device->dev); |
294 | |||
295 | acpi_device_setup_files(device); | ||
396 | } | 296 | } |
397 | 297 | ||
398 | static void acpi_device_unregister(struct acpi_device *device, int type) | 298 | static void acpi_device_unregister(struct acpi_device *device, int type) |
@@ -409,9 +309,8 @@ static void acpi_device_unregister(struct acpi_device *device, int type) | |||
409 | spin_unlock(&acpi_device_lock); | 309 | spin_unlock(&acpi_device_lock); |
410 | 310 | ||
411 | acpi_detach_data(device->handle, acpi_bus_data_handler); | 311 | acpi_detach_data(device->handle, acpi_bus_data_handler); |
412 | remove_sysfs_device_files(device); | ||
413 | kobject_unregister(&device->kobj); | ||
414 | 312 | ||
313 | acpi_device_remove_files(device); | ||
415 | device_unregister(&device->dev); | 314 | device_unregister(&device->dev); |
416 | } | 315 | } |
417 | 316 | ||
@@ -1353,10 +1252,6 @@ static int __init acpi_scan_init(void) | |||
1353 | if (acpi_disabled) | 1252 | if (acpi_disabled) |
1354 | return 0; | 1253 | return 0; |
1355 | 1254 | ||
1356 | result = kset_register(&acpi_namespace_kset); | ||
1357 | if (result < 0) | ||
1358 | printk(KERN_ERR PREFIX "kset_register error: %d\n", result); | ||
1359 | |||
1360 | result = bus_register(&acpi_bus_type); | 1255 | result = bus_register(&acpi_bus_type); |
1361 | if (result) { | 1256 | if (result) { |
1362 | /* We don't want to quit even if we failed to add suspend/resume */ | 1257 | /* We don't want to quit even if we failed to add suspend/resume */ |