aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/scan.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/scan.c')
-rw-r--r--drivers/acpi/scan.c118
1 files changed, 109 insertions, 9 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 9efe3e9dbf21..769e54bc9226 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -21,9 +21,15 @@ extern struct acpi_device *acpi_root;
21#define ACPI_BUS_DEVICE_NAME "System Bus" 21#define ACPI_BUS_DEVICE_NAME "System Bus"
22 22
23static LIST_HEAD(acpi_device_list); 23static LIST_HEAD(acpi_device_list);
24static LIST_HEAD(acpi_bus_id_list);
24DEFINE_SPINLOCK(acpi_device_lock); 25DEFINE_SPINLOCK(acpi_device_lock);
25LIST_HEAD(acpi_wakeup_device_list); 26LIST_HEAD(acpi_wakeup_device_list);
26 27
28struct acpi_device_bus_id{
29 char bus_id[9];
30 unsigned int instance_no;
31 struct list_head node;
32};
27static int acpi_eject_operation(acpi_handle handle, int lockable) 33static int acpi_eject_operation(acpi_handle handle, int lockable)
28{ 34{
29 struct acpi_object_list arg_list; 35 struct acpi_object_list arg_list;
@@ -103,18 +109,61 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
103 109
104static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store); 110static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
105 111
106static void acpi_device_setup_files(struct acpi_device *dev) 112static ssize_t
113acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) {
114 struct acpi_device *acpi_dev = to_acpi_device(dev);
115
116 return sprintf(buf, "%s\n", acpi_dev->pnp.hardware_id);
117}
118static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL);
119
120static ssize_t
121acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) {
122 struct acpi_device *acpi_dev = to_acpi_device(dev);
123 struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
124 int result;
125
126 result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path);
127 if(result)
128 goto end;
129
130 result = sprintf(buf, "%s\n", (char*)path.pointer);
131 kfree(path.pointer);
132 end:
133 return result;
134}
135static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL);
136
137static int acpi_device_setup_files(struct acpi_device *dev)
107{ 138{
108 acpi_status status; 139 acpi_status status;
109 acpi_handle temp; 140 acpi_handle temp;
141 int result = 0;
110 142
111 /* 143 /*
112 * If device has _EJ0, 'eject' file is created that is used to trigger 144 * Devices gotten from FADT don't have a "path" attribute
113 * hot-removal function from userland.
114 */ 145 */
146 if(dev->handle) {
147 result = device_create_file(&dev->dev, &dev_attr_path);
148 if(result)
149 goto end;
150 }
151
152 if(dev->flags.hardware_id) {
153 result = device_create_file(&dev->dev, &dev_attr_hid);
154 if(result)
155 goto end;
156 }
157
158 /*
159 * If device has _EJ0, 'eject' file is created that is used to trigger
160 * hot-removal function from userland.
161 */
115 status = acpi_get_handle(dev->handle, "_EJ0", &temp); 162 status = acpi_get_handle(dev->handle, "_EJ0", &temp);
116 if (ACPI_SUCCESS(status)) 163 if (ACPI_SUCCESS(status))
117 device_create_file(&dev->dev, &dev_attr_eject); 164 result = device_create_file(&dev->dev, &dev_attr_eject);
165 end:
166 return result;
118} 167}
119 168
120static void acpi_device_remove_files(struct acpi_device *dev) 169static void acpi_device_remove_files(struct acpi_device *dev)
@@ -129,6 +178,11 @@ static void acpi_device_remove_files(struct acpi_device *dev)
129 status = acpi_get_handle(dev->handle, "_EJ0", &temp); 178 status = acpi_get_handle(dev->handle, "_EJ0", &temp);
130 if (ACPI_SUCCESS(status)) 179 if (ACPI_SUCCESS(status))
131 device_remove_file(&dev->dev, &dev_attr_eject); 180 device_remove_file(&dev->dev, &dev_attr_eject);
181
182 if(dev->flags.hardware_id)
183 device_remove_file(&dev->dev, &dev_attr_hid);
184 if(dev->handle)
185 device_remove_file(&dev->dev, &dev_attr_path);
132} 186}
133/* -------------------------------------------------------------------------- 187/* --------------------------------------------------------------------------
134 ACPI Bus operations 188 ACPI Bus operations
@@ -260,9 +314,12 @@ static struct bus_type acpi_bus_type = {
260 .uevent = acpi_device_uevent, 314 .uevent = acpi_device_uevent,
261}; 315};
262 316
263static void acpi_device_register(struct acpi_device *device, 317static int acpi_device_register(struct acpi_device *device,
264 struct acpi_device *parent) 318 struct acpi_device *parent)
265{ 319{
320 int result;
321 struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id;
322 int found = 0;
266 /* 323 /*
267 * Linkage 324 * Linkage
268 * ------- 325 * -------
@@ -273,7 +330,33 @@ static void acpi_device_register(struct acpi_device *device,
273 INIT_LIST_HEAD(&device->g_list); 330 INIT_LIST_HEAD(&device->g_list);
274 INIT_LIST_HEAD(&device->wakeup_list); 331 INIT_LIST_HEAD(&device->wakeup_list);
275 332
333 new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL);
334 if (!new_bus_id) {
335 printk(KERN_ERR PREFIX "Memory allocation error\n");
336 return -ENOMEM;
337 }
338
276 spin_lock(&acpi_device_lock); 339 spin_lock(&acpi_device_lock);
340 /*
341 * Find suitable bus_id and instance number in acpi_bus_id_list
342 * If failed, create one and link it into acpi_bus_id_list
343 */
344 list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) {
345 if(!strcmp(acpi_device_bus_id->bus_id, device->flags.hardware_id? device->pnp.hardware_id : "PNPIDNON")) {
346 acpi_device_bus_id->instance_no ++;
347 found = 1;
348 kfree(new_bus_id);
349 break;
350 }
351 }
352 if(!found) {
353 acpi_device_bus_id = new_bus_id;
354 strcpy(acpi_device_bus_id->bus_id, device->flags.hardware_id ? device->pnp.hardware_id : "PNPIDNON");
355 acpi_device_bus_id->instance_no = 0;
356 list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list);
357 }
358 sprintf(device->dev.bus_id, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no);
359
277 if (device->parent) { 360 if (device->parent) {
278 list_add_tail(&device->node, &device->parent->children); 361 list_add_tail(&device->node, &device->parent->children);
279 list_add_tail(&device->g_list, &device->parent->g_list); 362 list_add_tail(&device->g_list, &device->parent->g_list);
@@ -287,12 +370,29 @@ static void acpi_device_register(struct acpi_device *device,
287 device->dev.parent = &parent->dev; 370 device->dev.parent = &parent->dev;
288 device->dev.bus = &acpi_bus_type; 371 device->dev.bus = &acpi_bus_type;
289 device_initialize(&device->dev); 372 device_initialize(&device->dev);
290 sprintf(device->dev.bus_id, "%s", device->pnp.bus_id);
291 device->dev.release = &acpi_device_release; 373 device->dev.release = &acpi_device_release;
292 device_add(&device->dev); 374 result = device_add(&device->dev);
375 if(result) {
376 printk("Error adding device %s", device->dev.bus_id);
377 goto end;
378 }
379
380 result = acpi_device_setup_files(device);
381 if(result)
382 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error creating sysfs interface for device %s\n", device->dev.bus_id));
293 383
294 acpi_device_setup_files(device);
295 device->removal_type = ACPI_BUS_REMOVAL_NORMAL; 384 device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
385 return 0;
386 end:
387 spin_lock(&acpi_device_lock);
388 if (device->parent) {
389 list_del(&device->node);
390 list_del(&device->g_list);
391 } else
392 list_del(&device->g_list);
393 list_del(&device->wakeup_list);
394 spin_unlock(&acpi_device_lock);
395 return result;
296} 396}
297 397
298static void acpi_device_unregister(struct acpi_device *device, int type) 398static void acpi_device_unregister(struct acpi_device *device, int type)
@@ -1035,7 +1135,7 @@ acpi_add_single_object(struct acpi_device **child,
1035 1135
1036 acpi_device_get_debug_info(device, handle, type); 1136 acpi_device_get_debug_info(device, handle, type);
1037 1137
1038 acpi_device_register(device, parent); 1138 result = acpi_device_register(device, parent);
1039 1139
1040 end: 1140 end:
1041 if (!result) 1141 if (!result)