scan.c 39.4 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
5
6
/*
 * scan.c - support for transforming the ACPI namespace into individual objects
 */

#include <linux/module.h>
#include <linux/init.h>
7
#include <linux/kernel.h>
Linus Torvalds's avatar
Linus Torvalds committed
8
#include <linux/acpi.h>
9
10
#include <linux/signal.h>
#include <linux/kthread.h>
Linus Torvalds's avatar
Linus Torvalds committed
11
12
13

#include <acpi/acpi_drivers.h>

14
15
#include "internal.h"

Linus Torvalds's avatar
Linus Torvalds committed
16
#define _COMPONENT		ACPI_BUS_COMPONENT
17
ACPI_MODULE_NAME("scan");
Linus Torvalds's avatar
Linus Torvalds committed
18
#define STRUCT_TO_INT(s)	(*((int*)&s))
Len Brown's avatar
Len Brown committed
19
extern struct acpi_device *acpi_root;
Linus Torvalds's avatar
Linus Torvalds committed
20
21

#define ACPI_BUS_CLASS			"system_bus"
22
#define ACPI_BUS_HID			"LNXSYBUS"
Linus Torvalds's avatar
Linus Torvalds committed
23
24
#define ACPI_BUS_DEVICE_NAME		"System Bus"

25
26
#define ACPI_IS_ROOT_DEVICE(device)    (!(device)->parent)

Linus Torvalds's avatar
Linus Torvalds committed
27
static LIST_HEAD(acpi_device_list);
28
static LIST_HEAD(acpi_bus_id_list);
29
DEFINE_MUTEX(acpi_device_lock);
Linus Torvalds's avatar
Linus Torvalds committed
30
31
LIST_HEAD(acpi_wakeup_device_list);

32
struct acpi_device_bus_id{
33
	char bus_id[15];
34
35
	unsigned int instance_no;
	struct list_head node;
Linus Torvalds's avatar
Linus Torvalds committed
36
};
37
38
39
40
41
42

/*
 * Creates hid/cid(s) string needed for modalias and uevent
 * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
 * char *modalias: "acpi:IBM0001:ACPI0001"
*/
43
44
45
static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
			   int size)
{
46
	int len;
47
	int count;
48

49
	if (!acpi_dev->flags.hardware_id && !acpi_dev->flags.compatible_ids)
50
51
		return -ENODEV;

52
	len = snprintf(modalias, size, "acpi:");
53
54
	size -= len;

55
56
57
58
59
60
61
62
63
	if (acpi_dev->flags.hardware_id) {
		count = snprintf(&modalias[len], size, "%s:",
				 acpi_dev->pnp.hardware_id);
		if (count < 0 || count >= size)
			return -EINVAL;
		len += count;
		size -= count;
	}

64
	if (acpi_dev->flags.compatible_ids) {
65
		struct acpica_device_id_list *cid_list;
66
67
68
69
70
		int i;

		cid_list = acpi_dev->pnp.cid_list;
		for (i = 0; i < cid_list->count; i++) {
			count = snprintf(&modalias[len], size, "%s:",
71
					 cid_list->ids[i].string);
72
			if (count < 0 || count >= size) {
73
				printk(KERN_ERR PREFIX "%s cid[%i] exceeds event buffer size",
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
				       acpi_dev->pnp.device_name, i);
				break;
			}
			len += count;
			size -= count;
		}
	}

	modalias[len] = '\0';
	return len;
}

static ssize_t
acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) {
	struct acpi_device *acpi_dev = to_acpi_device(dev);
	int len;

	/* Device has no HID and no CID or string is >1024 */
	len = create_modalias(acpi_dev, buf, 1024);
	if (len <= 0)
		return 0;
	buf[len++] = '\n';
	return len;
}
static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);

100
static void acpi_bus_hot_remove_device(void *context)
Linus Torvalds's avatar
Linus Torvalds committed
101
{
102
103
	struct acpi_device *device;
	acpi_handle handle = context;
Linus Torvalds's avatar
Linus Torvalds committed
104
105
106
107
	struct acpi_object_list arg_list;
	union acpi_object arg;
	acpi_status status = AE_OK;

108
	if (acpi_bus_get_device(handle, &device))
109
		return;
110
111

	if (!device)
112
		return;
113
114

	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
115
		"Hot-removing device %s...\n", dev_name(&device->dev)));
116
117

	if (acpi_bus_trim(device, 1)) {
118
119
		printk(KERN_ERR PREFIX
				"Removing device failed\n");
120
		return;
121
	}
Linus Torvalds's avatar
Linus Torvalds committed
122

123
124
125
	/* power off device */
	status = acpi_evaluate_object(handle, "_PS3", NULL, NULL);
	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
126
127
		printk(KERN_WARNING PREFIX
				"Power-off device failed\n");
128
129

	if (device->flags.lockable) {
Linus Torvalds's avatar
Linus Torvalds committed
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
		arg_list.count = 1;
		arg_list.pointer = &arg;
		arg.type = ACPI_TYPE_INTEGER;
		arg.integer.value = 0;
		acpi_evaluate_object(handle, "_LCK", &arg_list, NULL);
	}

	arg_list.count = 1;
	arg_list.pointer = &arg;
	arg.type = ACPI_TYPE_INTEGER;
	arg.integer.value = 1;

	/*
	 * TBD: _EJD support.
	 */
	status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
146
	if (ACPI_FAILURE(status))
147
148
		printk(KERN_WARNING PREFIX
				"Eject device failed\n");
Linus Torvalds's avatar
Linus Torvalds committed
149

150
	return;
Linus Torvalds's avatar
Linus Torvalds committed
151
152
153
}

static ssize_t
154
155
acpi_eject_store(struct device *d, struct device_attribute *attr,
		const char *buf, size_t count)
Linus Torvalds's avatar
Linus Torvalds committed
156
{
Len Brown's avatar
Len Brown committed
157
158
159
	int ret = count;
	acpi_status status;
	acpi_object_type type = 0;
160
	struct acpi_device *acpi_device = to_acpi_device(d);
Linus Torvalds's avatar
Linus Torvalds committed
161
162
163
164
165

	if ((!count) || (buf[0] != '1')) {
		return -EINVAL;
	}
#ifndef FORCE_EJECT
166
	if (acpi_device->driver == NULL) {
Linus Torvalds's avatar
Linus Torvalds committed
167
168
169
170
		ret = -ENODEV;
		goto err;
	}
#endif
171
172
	status = acpi_get_type(acpi_device->handle, &type);
	if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
Linus Torvalds's avatar
Linus Torvalds committed
173
174
175
176
		ret = -ENODEV;
		goto err;
	}

177
	acpi_os_hotplug_execute(acpi_bus_hot_remove_device, acpi_device->handle);
178
err:
Linus Torvalds's avatar
Linus Torvalds committed
179
180
181
	return ret;
}

182
static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
Linus Torvalds's avatar
Linus Torvalds committed
183

184
185
186
static ssize_t
acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) {
	struct acpi_device *acpi_dev = to_acpi_device(dev);
Linus Torvalds's avatar
Linus Torvalds committed
187

188
	return sprintf(buf, "%s\n", acpi_device_hid(acpi_dev));
Linus Torvalds's avatar
Linus Torvalds committed
189
}
190
static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
191

192
193
194
195
196
static ssize_t
acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) {
	struct acpi_device *acpi_dev = to_acpi_device(dev);
	struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
	int result;
Linus Torvalds's avatar
Linus Torvalds committed
197

198
	result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path);
199
	if (result)
200
		goto end;
Linus Torvalds's avatar
Linus Torvalds committed
201

202
203
	result = sprintf(buf, "%s\n", (char*)path.pointer);
	kfree(path.pointer);
204
end:
205
	return result;
Linus Torvalds's avatar
Linus Torvalds committed
206
}
207
static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
208

209
static int acpi_device_setup_files(struct acpi_device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
210
{
211
212
	acpi_status status;
	acpi_handle temp;
213
	int result = 0;
Linus Torvalds's avatar
Linus Torvalds committed
214
215

	/*
216
	 * Devices gotten from FADT don't have a "path" attribute
Linus Torvalds's avatar
Linus Torvalds committed
217
	 */
218
	if (dev->handle) {
219
		result = device_create_file(&dev->dev, &dev_attr_path);
220
		if (result)
221
			goto end;
Linus Torvalds's avatar
Linus Torvalds committed
222
223
	}

224
	if (dev->flags.hardware_id) {
225
		result = device_create_file(&dev->dev, &dev_attr_hid);
226
		if (result)
227
228
			goto end;
	}
Linus Torvalds's avatar
Linus Torvalds committed
229

230
	if (dev->flags.hardware_id || dev->flags.compatible_ids) {
231
		result = device_create_file(&dev->dev, &dev_attr_modalias);
232
		if (result)
233
234
235
			goto end;
	}

236
237
238
239
        /*
         * If device has _EJ0, 'eject' file is created that is used to trigger
         * hot-removal function from userland.
         */
240
241
	status = acpi_get_handle(dev->handle, "_EJ0", &temp);
	if (ACPI_SUCCESS(status))
242
		result = device_create_file(&dev->dev, &dev_attr_eject);
243
end:
244
	return result;
Linus Torvalds's avatar
Linus Torvalds committed
245
246
}

247
static void acpi_device_remove_files(struct acpi_device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
248
{
249
250
	acpi_status status;
	acpi_handle temp;
Linus Torvalds's avatar
Linus Torvalds committed
251

252
253
254
255
256
257
258
	/*
	 * If device has _EJ0, 'eject' file is created that is used to trigger
	 * hot-removal function from userland.
	 */
	status = acpi_get_handle(dev->handle, "_EJ0", &temp);
	if (ACPI_SUCCESS(status))
		device_remove_file(&dev->dev, &dev_attr_eject);
Linus Torvalds's avatar
Linus Torvalds committed
259

260
261
262
	if (dev->flags.hardware_id || dev->flags.compatible_ids)
		device_remove_file(&dev->dev, &dev_attr_modalias);

263
	if (dev->flags.hardware_id)
264
		device_remove_file(&dev->dev, &dev_attr_hid);
265
	if (dev->handle)
266
		device_remove_file(&dev->dev, &dev_attr_path);
Linus Torvalds's avatar
Linus Torvalds committed
267
268
}
/* --------------------------------------------------------------------------
Zhang Rui's avatar
Zhang Rui committed
269
			ACPI Bus operations
Linus Torvalds's avatar
Linus Torvalds committed
270
   -------------------------------------------------------------------------- */
271
272
273
274
275
276

int acpi_match_device_ids(struct acpi_device *device,
			  const struct acpi_device_id *ids)
{
	const struct acpi_device_id *id;

277
278
279
280
281
282
283
	/*
	 * If the device is not present, it is unnecessary to load device
	 * driver for it.
	 */
	if (!device->status.present)
		return -ENODEV;

284
285
286
287
288
289
290
291
	if (device->flags.hardware_id) {
		for (id = ids; id->id[0]; id++) {
			if (!strcmp((char*)id->id, device->pnp.hardware_id))
				return 0;
		}
	}

	if (device->flags.compatible_ids) {
292
		struct acpica_device_id_list *cid_list = device->pnp.cid_list;
293
294
295
296
297
298
		int i;

		for (id = ids; id->id[0]; id++) {
			/* compare multiple _CID entries against driver ids */
			for (i = 0; i < cid_list->count; i++) {
				if (!strcmp((char*)id->id,
299
					    cid_list->ids[i].string))
300
301
302
303
304
305
306
307
308
					return 0;
			}
		}
	}

	return -ENOENT;
}
EXPORT_SYMBOL(acpi_match_device_ids);

309
static void acpi_device_release(struct device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
310
{
311
	struct acpi_device *acpi_dev = to_acpi_device(dev);
Linus Torvalds's avatar
Linus Torvalds committed
312

313
	kfree(acpi_dev->pnp.cid_list);
314
315
316
317
	if (acpi_dev->flags.hardware_id)
		kfree(acpi_dev->pnp.hardware_id);
	if (acpi_dev->flags.unique_id)
		kfree(acpi_dev->pnp.unique_id);
318
	kfree(acpi_dev);
Linus Torvalds's avatar
Linus Torvalds committed
319
320
}

321
static int acpi_device_suspend(struct device *dev, pm_message_t state)
Linus Torvalds's avatar
Linus Torvalds committed
322
{
323
324
	struct acpi_device *acpi_dev = to_acpi_device(dev);
	struct acpi_driver *acpi_drv = acpi_dev->driver;
Linus Torvalds's avatar
Linus Torvalds committed
325

326
327
	if (acpi_drv && acpi_drv->ops.suspend)
		return acpi_drv->ops.suspend(acpi_dev, state);
Linus Torvalds's avatar
Linus Torvalds committed
328
329
330
	return 0;
}

331
static int acpi_device_resume(struct device *dev)
Zhang Rui's avatar
Zhang Rui committed
332
{
333
334
	struct acpi_device *acpi_dev = to_acpi_device(dev);
	struct acpi_driver *acpi_drv = acpi_dev->driver;
Linus Torvalds's avatar
Linus Torvalds committed
335

336
337
	if (acpi_drv && acpi_drv->ops.resume)
		return acpi_drv->ops.resume(acpi_dev);
338
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
339
340
}

341
static int acpi_bus_match(struct device *dev, struct device_driver *drv)
Zhang Rui's avatar
Zhang Rui committed
342
{
343
344
	struct acpi_device *acpi_dev = to_acpi_device(dev);
	struct acpi_driver *acpi_drv = to_acpi_driver(drv);
Linus Torvalds's avatar
Linus Torvalds committed
345

346
	return !acpi_match_device_ids(acpi_dev, acpi_drv->ids);
347
}
Linus Torvalds's avatar
Linus Torvalds committed
348

349
static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
Linus Torvalds's avatar
Linus Torvalds committed
350
{
351
	struct acpi_device *acpi_dev = to_acpi_device(dev);
352
	int len;
353

354
355
356
357
358
359
360
	if (add_uevent_var(env, "MODALIAS="))
		return -ENOMEM;
	len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
			      sizeof(env->buf) - env->buflen);
	if (len >= (sizeof(env->buf) - env->buflen))
		return -ENOMEM;
	env->buflen += len;
Zhang Rui's avatar
Zhang Rui committed
361
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
362
363
}

364
365
366
367
368
369
370
371
372
373
374
static void acpi_device_notify(acpi_handle handle, u32 event, void *data)
{
	struct acpi_device *device = data;

	device->driver->ops.notify(device, event);
}

static acpi_status acpi_device_notify_fixed(void *data)
{
	struct acpi_device *device = data;

375
376
	/* Fixed hardware devices have no handles */
	acpi_device_notify(NULL, ACPI_FIXED_HARDWARE_EVENT, device);
377
378
379
380
381
382
383
	return AE_OK;
}

static int acpi_device_install_notify_handler(struct acpi_device *device)
{
	acpi_status status;

384
	if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
385
386
387
388
		status =
		    acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
						     acpi_device_notify_fixed,
						     device);
389
	else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
		status =
		    acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
						     acpi_device_notify_fixed,
						     device);
	else
		status = acpi_install_notify_handler(device->handle,
						     ACPI_DEVICE_NOTIFY,
						     acpi_device_notify,
						     device);

	if (ACPI_FAILURE(status))
		return -EINVAL;
	return 0;
}

static void acpi_device_remove_notify_handler(struct acpi_device *device)
{
407
	if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
408
409
		acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
						acpi_device_notify_fixed);
410
	else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
411
412
413
414
415
416
417
		acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
						acpi_device_notify_fixed);
	else
		acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
					   acpi_device_notify);
}

418
419
420
static int acpi_bus_driver_init(struct acpi_device *, struct acpi_driver *);
static int acpi_start_single_object(struct acpi_device *);
static int acpi_device_probe(struct device * dev)
Linus Torvalds's avatar
Linus Torvalds committed
421
{
422
423
424
425
426
427
	struct acpi_device *acpi_dev = to_acpi_device(dev);
	struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver);
	int ret;

	ret = acpi_bus_driver_init(acpi_dev, acpi_drv);
	if (!ret) {
428
429
		if (acpi_dev->bus_ops.acpi_op_start)
			acpi_start_single_object(acpi_dev);
430
431
432
433
434
435
436
437
438
439
440

		if (acpi_drv->ops.notify) {
			ret = acpi_device_install_notify_handler(acpi_dev);
			if (ret) {
				if (acpi_drv->ops.remove)
					acpi_drv->ops.remove(acpi_dev,
						     acpi_dev->removal_type);
				return ret;
			}
		}

441
442
443
444
445
446
447
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
			"Found driver [%s] for device [%s]\n",
			acpi_drv->name, acpi_dev->pnp.bus_id));
		get_device(dev);
	}
	return ret;
}
Linus Torvalds's avatar
Linus Torvalds committed
448

449
450
451
452
453
454
static int acpi_device_remove(struct device * dev)
{
	struct acpi_device *acpi_dev = to_acpi_device(dev);
	struct acpi_driver *acpi_drv = acpi_dev->driver;

	if (acpi_drv) {
455
456
		if (acpi_drv->ops.notify)
			acpi_device_remove_notify_handler(acpi_dev);
457
		if (acpi_drv->ops.remove)
458
			acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
Linus Torvalds's avatar
Linus Torvalds committed
459
	}
460
	acpi_dev->driver = NULL;
461
	acpi_dev->driver_data = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
462

463
	put_device(dev);
Zhang Rui's avatar
Zhang Rui committed
464
465
	return 0;
}
Linus Torvalds's avatar
Linus Torvalds committed
466

467
struct bus_type acpi_bus_type = {
Zhang Rui's avatar
Zhang Rui committed
468
469
470
	.name		= "acpi",
	.suspend	= acpi_device_suspend,
	.resume		= acpi_device_resume,
471
472
473
474
	.match		= acpi_bus_match,
	.probe		= acpi_device_probe,
	.remove		= acpi_device_remove,
	.uevent		= acpi_device_uevent,
Zhang Rui's avatar
Zhang Rui committed
475
476
};

477
static int acpi_device_register(struct acpi_device *device)
Linus Torvalds's avatar
Linus Torvalds committed
478
{
Len Brown's avatar
Len Brown committed
479
	int result;
480
481
	struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id;
	int found = 0;
482

Zhang Rui's avatar
Zhang Rui committed
483
484
485
486
487
488
489
490
	/*
	 * Linkage
	 * -------
	 * Link this device to its parent and siblings.
	 */
	INIT_LIST_HEAD(&device->children);
	INIT_LIST_HEAD(&device->node);
	INIT_LIST_HEAD(&device->wakeup_list);
Linus Torvalds's avatar
Linus Torvalds committed
491

492
493
494
495
	new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL);
	if (!new_bus_id) {
		printk(KERN_ERR PREFIX "Memory allocation error\n");
		return -ENOMEM;
Linus Torvalds's avatar
Linus Torvalds committed
496
	}
497

498
	mutex_lock(&acpi_device_lock);
499
500
501
502
503
	/*
	 * Find suitable bus_id and instance number in acpi_bus_id_list
	 * If failed, create one and link it into acpi_bus_id_list
	 */
	list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) {
504
		if (!strcmp(acpi_device_bus_id->bus_id, device->flags.hardware_id ? acpi_device_hid(device) : "device")) {
505
506
507
508
509
			acpi_device_bus_id->instance_no ++;
			found = 1;
			kfree(new_bus_id);
			break;
		}
Linus Torvalds's avatar
Linus Torvalds committed
510
	}
511
	if (!found) {
512
		acpi_device_bus_id = new_bus_id;
513
		strcpy(acpi_device_bus_id->bus_id, device->flags.hardware_id ? acpi_device_hid(device) : "device");
514
515
		acpi_device_bus_id->instance_no = 0;
		list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list);
Linus Torvalds's avatar
Linus Torvalds committed
516
	}
517
	dev_set_name(&device->dev, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no);
Linus Torvalds's avatar
Linus Torvalds committed
518

Len Brown's avatar
Len Brown committed
519
	if (device->parent)
Zhang Rui's avatar
Zhang Rui committed
520
		list_add_tail(&device->node, &device->parent->children);
Len Brown's avatar
Len Brown committed
521

Zhang Rui's avatar
Zhang Rui committed
522
523
	if (device->wakeup.flags.valid)
		list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list);
524
	mutex_unlock(&acpi_device_lock);
Linus Torvalds's avatar
Linus Torvalds committed
525

526
	if (device->parent)
527
		device->dev.parent = &device->parent->dev;
528
529
	device->dev.bus = &acpi_bus_type;
	device->dev.release = &acpi_device_release;
530
	result = device_register(&device->dev);
531
	if (result) {
532
		dev_err(&device->dev, "Error registering device\n");
533
		goto end;
Linus Torvalds's avatar
Linus Torvalds committed
534
535
	}

536
	result = acpi_device_setup_files(device);
537
	if (result)
538
539
		printk(KERN_ERR PREFIX "Error creating sysfs interface for device %s\n",
		       dev_name(&device->dev));
Linus Torvalds's avatar
Linus Torvalds committed
540

541
	device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
Linus Torvalds's avatar
Linus Torvalds committed
542
	return 0;
543
end:
544
	mutex_lock(&acpi_device_lock);
Len Brown's avatar
Len Brown committed
545
	if (device->parent)
546
547
		list_del(&device->node);
	list_del(&device->wakeup_list);
548
	mutex_unlock(&acpi_device_lock);
549
	return result;
Linus Torvalds's avatar
Linus Torvalds committed
550
551
}

Zhang Rui's avatar
Zhang Rui committed
552
553
static void acpi_device_unregister(struct acpi_device *device, int type)
{
554
	mutex_lock(&acpi_device_lock);
Len Brown's avatar
Len Brown committed
555
	if (device->parent)
Zhang Rui's avatar
Zhang Rui committed
556
		list_del(&device->node);
Linus Torvalds's avatar
Linus Torvalds committed
557

Zhang Rui's avatar
Zhang Rui committed
558
	list_del(&device->wakeup_list);
559
	mutex_unlock(&acpi_device_lock);
Linus Torvalds's avatar
Linus Torvalds committed
560

Zhang Rui's avatar
Zhang Rui committed
561
	acpi_detach_data(device->handle, acpi_bus_data_handler);
562

563
	acpi_device_remove_files(device);
564
	device_unregister(&device->dev);
Linus Torvalds's avatar
Linus Torvalds committed
565
566
}

Zhang Rui's avatar
Zhang Rui committed
567
568
569
/* --------------------------------------------------------------------------
                                 Driver Management
   -------------------------------------------------------------------------- */
Linus Torvalds's avatar
Linus Torvalds committed
570
/**
571
572
573
574
 * acpi_bus_driver_init - add a device to a driver
 * @device: the device to add and initialize
 * @driver: driver for the device
 *
575
 * Used to initialize a device via its device driver.  Called whenever a
576
 * driver is bound to a device.  Invokes the driver's add() ops.
Linus Torvalds's avatar
Linus Torvalds committed
577
578
 */
static int
Len Brown's avatar
Len Brown committed
579
acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
Linus Torvalds's avatar
Linus Torvalds committed
580
{
Len Brown's avatar
Len Brown committed
581
	int result = 0;
Linus Torvalds's avatar
Linus Torvalds committed
582
583

	if (!device || !driver)
584
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
585
586

	if (!driver->ops.add)
587
		return -ENOSYS;
Linus Torvalds's avatar
Linus Torvalds committed
588
589
590
591

	result = driver->ops.add(device);
	if (result) {
		device->driver = NULL;
592
		device->driver_data = NULL;
593
		return result;
Linus Torvalds's avatar
Linus Torvalds committed
594
595
596
597
598
599
600
601
602
	}

	device->driver = driver;

	/*
	 * TBD - Configuration Management: Assign resources to device based
	 * upon possible configuration and currently allocated resources.
	 */

Len Brown's avatar
Len Brown committed
603
604
	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
			  "Driver successfully bound to device\n"));
605
	return 0;
606
607
}

608
static int acpi_start_single_object(struct acpi_device *device)
609
610
611
612
613
614
{
	int result = 0;
	struct acpi_driver *driver;


	if (!(driver = device->driver))
615
		return 0;
616

Linus Torvalds's avatar
Linus Torvalds committed
617
618
619
620
621
622
	if (driver->ops.start) {
		result = driver->ops.start(device);
		if (result && driver->ops.remove)
			driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
	}

623
	return result;
Linus Torvalds's avatar
Linus Torvalds committed
624
625
}

Zhang Rui's avatar
Zhang Rui committed
626
627
628
629
630
631
632
633
634
/**
 * acpi_bus_register_driver - register a driver with the ACPI bus
 * @driver: driver being registered
 *
 * Registers a driver with the ACPI bus.  Searches the namespace for all
 * devices that match the driver's criteria and binds.  Returns zero for
 * success or a negative error status for failure.
 */
int acpi_bus_register_driver(struct acpi_driver *driver)
Linus Torvalds's avatar
Linus Torvalds committed
635
{
636
	int ret;
Linus Torvalds's avatar
Linus Torvalds committed
637

Zhang Rui's avatar
Zhang Rui committed
638
639
	if (acpi_disabled)
		return -ENODEV;
640
641
642
	driver->drv.name = driver->name;
	driver->drv.bus = &acpi_bus_type;
	driver->drv.owner = driver->owner;
Linus Torvalds's avatar
Linus Torvalds committed
643

644
645
	ret = driver_register(&driver->drv);
	return ret;
Zhang Rui's avatar
Zhang Rui committed
646
}
Linus Torvalds's avatar
Linus Torvalds committed
647

Zhang Rui's avatar
Zhang Rui committed
648
649
650
651
652
653
654
655
656
657
658
EXPORT_SYMBOL(acpi_bus_register_driver);

/**
 * acpi_bus_unregister_driver - unregisters a driver with the APIC bus
 * @driver: driver to unregister
 *
 * Unregisters a driver with the ACPI bus.  Searches the namespace for all
 * devices that match the driver's criteria and unbinds.
 */
void acpi_bus_unregister_driver(struct acpi_driver *driver)
{
659
	driver_unregister(&driver->drv);
Zhang Rui's avatar
Zhang Rui committed
660
661
662
663
664
665
666
}

EXPORT_SYMBOL(acpi_bus_unregister_driver);

/* --------------------------------------------------------------------------
                                 Device Enumeration
   -------------------------------------------------------------------------- */
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
static struct acpi_device *acpi_bus_get_parent(acpi_handle handle)
{
	acpi_status status;
	int ret;
	struct acpi_device *device;

	/*
	 * Fixed hardware devices do not appear in the namespace and do not
	 * have handles, but we fabricate acpi_devices for them, so we have
	 * to deal with them specially.
	 */
	if (handle == NULL)
		return acpi_root;

	do {
		status = acpi_get_parent(handle, &handle);
		if (status == AE_NULL_ENTRY)
			return NULL;
		if (ACPI_FAILURE(status))
			return acpi_root;

		ret = acpi_bus_get_device(handle, &device);
		if (ret == 0)
			return device;
	} while (1);
}

Zhang Rui's avatar
Zhang Rui committed
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
acpi_status
acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)
{
	acpi_status status;
	acpi_handle tmp;
	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
	union acpi_object *obj;

	status = acpi_get_handle(handle, "_EJD", &tmp);
	if (ACPI_FAILURE(status))
		return status;

	status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer);
	if (ACPI_SUCCESS(status)) {
		obj = buffer.pointer;
709
710
		status = acpi_get_handle(ACPI_ROOT_OBJECT, obj->string.pointer,
					 ejd);
Zhang Rui's avatar
Zhang Rui committed
711
712
713
714
715
716
		kfree(buffer.pointer);
	}
	return status;
}
EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);

717
void acpi_bus_data_handler(acpi_handle handle, void *context)
Zhang Rui's avatar
Zhang Rui committed
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
{

	/* TBD */

	return;
}

static int acpi_bus_get_perf_flags(struct acpi_device *device)
{
	device->performance.state = ACPI_STATE_UNKNOWN;
	return 0;
}

static acpi_status
acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device,
					     union acpi_object *package)
{
	int i = 0;
	union acpi_object *element = NULL;

	if (!device || !package || (package->package.count < 2))
		return AE_BAD_PARAMETER;

	element = &(package->package.elements[0]);
	if (!element)
		return AE_BAD_PARAMETER;
	if (element->type == ACPI_TYPE_PACKAGE) {
		if ((element->package.count < 2) ||
		    (element->package.elements[0].type !=
		     ACPI_TYPE_LOCAL_REFERENCE)
		    || (element->package.elements[1].type != ACPI_TYPE_INTEGER))
			return AE_BAD_DATA;
		device->wakeup.gpe_device =
		    element->package.elements[0].reference.handle;
		device->wakeup.gpe_number =
		    (u32) element->package.elements[1].integer.value;
	} else if (element->type == ACPI_TYPE_INTEGER) {
		device->wakeup.gpe_number = element->integer.value;
	} else
		return AE_BAD_DATA;

	element = &(package->package.elements[1]);
	if (element->type != ACPI_TYPE_INTEGER) {
		return AE_BAD_DATA;
	}
	device->wakeup.sleep_state = element->integer.value;

	if ((package->package.count - 2) > ACPI_MAX_HANDLES) {
		return AE_NO_MEMORY;
	}
	device->wakeup.resources.count = package->package.count - 2;
	for (i = 0; i < device->wakeup.resources.count; i++) {
		element = &(package->package.elements[i + 2]);
771
		if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
Zhang Rui's avatar
Zhang Rui committed
772
773
774
			return AE_BAD_DATA;

		device->wakeup.resources.handles[i] = element->reference.handle;
Linus Torvalds's avatar
Linus Torvalds committed
775
	}
Zhang Rui's avatar
Zhang Rui committed
776
777

	return AE_OK;
Linus Torvalds's avatar
Linus Torvalds committed
778
779
}

Zhang Rui's avatar
Zhang Rui committed
780
static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
Linus Torvalds's avatar
Linus Torvalds committed
781
{
Zhang Rui's avatar
Zhang Rui committed
782
783
784
	acpi_status status = 0;
	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
	union acpi_object *package = NULL;
785
	int psw_error;
Linus Torvalds's avatar
Linus Torvalds committed
786

787
788
789
790
791
792
793
	struct acpi_device_id button_device_ids[] = {
		{"PNP0C0D", 0},
		{"PNP0C0C", 0},
		{"PNP0C0E", 0},
		{"", 0},
	};

Zhang Rui's avatar
Zhang Rui committed
794
795
796
797
798
	/* _PRW */
	status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer);
	if (ACPI_FAILURE(status)) {
		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW"));
		goto end;
Linus Torvalds's avatar
Linus Torvalds committed
799
800
	}

Zhang Rui's avatar
Zhang Rui committed
801
802
803
804
805
806
	package = (union acpi_object *)buffer.pointer;
	status = acpi_bus_extract_wakeup_device_power_package(device, package);
	if (ACPI_FAILURE(status)) {
		ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package"));
		goto end;
	}
Linus Torvalds's avatar
Linus Torvalds committed
807

Zhang Rui's avatar
Zhang Rui committed
808
	kfree(buffer.pointer);
Linus Torvalds's avatar
Linus Torvalds committed
809

Zhang Rui's avatar
Zhang Rui committed
810
	device->wakeup.flags.valid = 1;
811
	device->wakeup.prepare_count = 0;
812
813
814
815
816
817
	/* Call _PSW/_DSW object to disable its ability to wake the sleeping
	 * system for the ACPI device with the _PRW object.
	 * The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW.
	 * So it is necessary to call _DSW object first. Only when it is not
	 * present will the _PSW object used.
	 */
818
819
820
821
822
	psw_error = acpi_device_sleep_wake(device, 0, 0, 0);
	if (psw_error)
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				"error in _DSW or _PSW evaluation\n"));

Zhang Rui's avatar
Zhang Rui committed
823
	/* Power button, Lid switch always enable wakeup */
824
	if (!acpi_match_device_ids(device, button_device_ids))
Zhang Rui's avatar
Zhang Rui committed
825
		device->wakeup.flags.run_wake = 1;
Linus Torvalds's avatar
Linus Torvalds committed
826

827
end:
Zhang Rui's avatar
Zhang Rui committed
828
829
	if (ACPI_FAILURE(status))
		device->flags.wake_capable = 0;
830
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
831
832
}

Zhang Rui's avatar
Zhang Rui committed
833
static int acpi_bus_get_power_flags(struct acpi_device *device)
Linus Torvalds's avatar
Linus Torvalds committed
834
{
Zhang Rui's avatar
Zhang Rui committed
835
836
837
	acpi_status status = 0;
	acpi_handle handle = NULL;
	u32 i = 0;
Bjorn Helgaas's avatar
Bjorn Helgaas committed
838

Len Brown's avatar
Len Brown committed
839

Zhang Rui's avatar
Zhang Rui committed
840
841
842
843
844
845
846
847
848
	/*
	 * Power Management Flags
	 */
	status = acpi_get_handle(device->handle, "_PSC", &handle);
	if (ACPI_SUCCESS(status))
		device->power.flags.explicit_get = 1;
	status = acpi_get_handle(device->handle, "_IRC", &handle);
	if (ACPI_SUCCESS(status))
		device->power.flags.inrush_current = 1;
Linus Torvalds's avatar
Linus Torvalds committed
849

Zhang Rui's avatar
Zhang Rui committed
850
851
852
853
854
855
	/*
	 * Enumerate supported power management states
	 */
	for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) {
		struct acpi_device_power_state *ps = &device->power.states[i];
		char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' };
Linus Torvalds's avatar
Linus Torvalds committed
856

Zhang Rui's avatar
Zhang Rui committed
857
858
859
860
861
862
		/* Evaluate "_PRx" to se if power resources are referenced */
		acpi_evaluate_reference(device->handle, object_name, NULL,
					&ps->resources);
		if (ps->resources.count) {
			device->power.flags.power_resources = 1;
			ps->flags.valid = 1;
Linus Torvalds's avatar
Linus Torvalds committed
863
864
		}

Zhang Rui's avatar
Zhang Rui committed
865
866
867
868
869
870
		/* Evaluate "_PSx" to see if we can do explicit sets */
		object_name[2] = 'S';
		status = acpi_get_handle(device->handle, object_name, &handle);
		if (ACPI_SUCCESS(status)) {
			ps->flags.explicit_set = 1;
			ps->flags.valid = 1;
Linus Torvalds's avatar
Linus Torvalds committed
871
872
		}

Zhang Rui's avatar
Zhang Rui committed
873
874
875
		/* State is valid if we have some power control */
		if (ps->resources.count || ps->flags.explicit_set)
			ps->flags.valid = 1;
Linus Torvalds's avatar
Linus Torvalds committed
876

Zhang Rui's avatar
Zhang Rui committed
877
878
879
		ps->power = -1;	/* Unknown - driver assigned */
		ps->latency = -1;	/* Unknown - driver assigned */
	}
Linus Torvalds's avatar
Linus Torvalds committed
880

Zhang Rui's avatar
Zhang Rui committed
881
882
883
884
885
	/* Set defaults for D0 and D3 states (always valid) */
	device->power.states[ACPI_STATE_D0].flags.valid = 1;
	device->power.states[ACPI_STATE_D0].power = 100;
	device->power.states[ACPI_STATE_D3].flags.valid = 1;
	device->power.states[ACPI_STATE_D3].power = 0;
886

Zhang Rui's avatar
Zhang Rui committed
887
	/* TBD: System wake support and resource requirements. */
888

Zhang Rui's avatar
Zhang Rui committed
889
	device->power.state = ACPI_STATE_UNKNOWN;
890
	acpi_bus_get_power(device->handle, &(device->power.state));
891

Zhang Rui's avatar
Zhang Rui committed
892
893
	return 0;
}
894

Len Brown's avatar
Len Brown committed
895
static int acpi_bus_get_flags(struct acpi_device *device)
Linus Torvalds's avatar
Linus Torvalds committed
896
{
Len Brown's avatar
Len Brown committed
897
898
	acpi_status status = AE_OK;
	acpi_handle temp = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942


	/* Presence of _STA indicates 'dynamic_status' */
	status = acpi_get_handle(device->handle, "_STA", &temp);
	if (ACPI_SUCCESS(status))
		device->flags.dynamic_status = 1;

	/* Presence of _CID indicates 'compatible_ids' */
	status = acpi_get_handle(device->handle, "_CID", &temp);
	if (ACPI_SUCCESS(status))
		device->flags.compatible_ids = 1;

	/* Presence of _RMV indicates 'removable' */
	status = acpi_get_handle(device->handle, "_RMV", &temp);
	if (ACPI_SUCCESS(status))
		device->flags.removable = 1;

	/* Presence of _EJD|_EJ0 indicates 'ejectable' */
	status = acpi_get_handle(device->handle, "_EJD", &temp);
	if (ACPI_SUCCESS(status))
		device->flags.ejectable = 1;
	else {
		status = acpi_get_handle(device->handle, "_EJ0", &temp);
		if (ACPI_SUCCESS(status))
			device->flags.ejectable = 1;
	}

	/* Presence of _LCK indicates 'lockable' */
	status = acpi_get_handle(device->handle, "_LCK", &temp);
	if (ACPI_SUCCESS(status))
		device->flags.lockable = 1;

	/* Presence of _PS0|_PR0 indicates 'power manageable' */
	status = acpi_get_handle(device->handle, "_PS0", &temp);
	if (ACPI_FAILURE(status))
		status = acpi_get_handle(device->handle, "_PR0", &temp);
	if (ACPI_SUCCESS(status))
		device->flags.power_manageable = 1;

	/* Presence of _PRW indicates wake capable */
	status = acpi_get_handle(device->handle, "_PRW", &temp);
	if (ACPI_SUCCESS(status))
		device->flags.wake_capable = 1;

Joe Perches's avatar
Joe Perches committed
943
	/* TBD: Performance management */
Linus Torvalds's avatar
Linus Torvalds committed
944

945
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
946
947
}

948
static void acpi_device_get_busid(struct acpi_device *device)
Linus Torvalds's avatar
Linus Torvalds committed
949
{
Len Brown's avatar
Len Brown committed
950
951
952
	char bus_id[5] = { '?', 0 };
	struct acpi_buffer buffer = { sizeof(bus_id), bus_id };
	int i = 0;
Linus Torvalds's avatar
Linus Torvalds committed
953
954
955
956
957
958
959

	/*
	 * Bus ID
	 * ------
	 * The device's Bus ID is simply the object name.
	 * TBD: Shouldn't this value be unique (within the ACPI namespace)?
	 */
960
	if (ACPI_IS_ROOT_DEVICE(device)) {
Linus Torvalds's avatar
Linus Torvalds committed
961
		strcpy(device->pnp.bus_id, "ACPI");
962
963
964
965
		return;
	}

	switch (device->device_type) {
Linus Torvalds's avatar
Linus Torvalds committed
966
967
968
969
970
971
972
	case ACPI_BUS_TYPE_POWER_BUTTON:
		strcpy(device->pnp.bus_id, "PWRF");
		break;
	case ACPI_BUS_TYPE_SLEEP_BUTTON:
		strcpy(device->pnp.bus_id, "SLPF");
		break;
	default:
973
		acpi_get_name(device->handle, ACPI_SINGLE_NAME, &buffer);
Linus Torvalds's avatar
Linus Torvalds committed
974
975
976
977
978
979
980
981
982
983
984
985
		/* Clean up trailing underscores (if any) */
		for (i = 3; i > 1; i--) {
			if (bus_id[i] == '_')
				bus_id[i] = '\0';
			else
				break;
		}
		strcpy(device->pnp.bus_id, bus_id);
		break;
	}
}

986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
/*
 * acpi_bay_match - see if a device is an ejectable driver bay
 *
 * If an acpi object is ejectable and has one of the ACPI ATA methods defined,
 * then we can safely call it an ejectable drive bay
 */
static int acpi_bay_match(struct acpi_device *device){
	acpi_status status;
	acpi_handle handle;
	acpi_handle tmp;
	acpi_handle phandle;

	handle = device->handle;

	status = acpi_get_handle(handle, "_EJ0", &tmp);
	if (ACPI_FAILURE(status))
		return -ENODEV;

	if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
		(ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
		(ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
		(ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
		return 0;

	if (acpi_get_parent(handle, &phandle))
		return -ENODEV;

        if ((ACPI_SUCCESS(acpi_get_handle(phandle, "_GTF", &tmp))) ||
                (ACPI_SUCCESS(acpi_get_handle(phandle, "_GTM", &tmp))) ||
                (ACPI_SUCCESS(acpi_get_handle(phandle, "_STM", &tmp))) ||
                (ACPI_SUCCESS(acpi_get_handle(phandle, "_SDD", &tmp))))
                return 0;

	return -ENODEV;
}

1022
1023
1024
1025
1026
1027
1028
1029
1030
/*
 * acpi_dock_match - see if a device has a _DCK method
 */
static int acpi_dock_match(struct acpi_device *device)
{
	acpi_handle tmp;
	return acpi_get_handle(device->handle, "_DCK", &tmp);
}

1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
static struct acpica_device_id_list*
acpi_add_cid(
	struct acpi_device_info         *info,
	struct acpica_device_id         *new_cid)
{
	struct acpica_device_id_list    *cid;
	char                            *next_id_string;
	acpi_size                       cid_length;
	acpi_size                       new_cid_length;
	u32                             i;


	/* Allocate new CID list with room for the new CID */

	if (!new_cid)
		new_cid_length = info->compatible_id_list.list_size;
	else if (info->compatible_id_list.list_size)
		new_cid_length = info->compatible_id_list.list_size +
			new_cid->length + sizeof(struct acpica_device_id);
	else
		new_cid_length = sizeof(struct acpica_device_id_list) + new_cid->length;

	cid = ACPI_ALLOCATE_ZEROED(new_cid_length);
	if (!cid) {
		return NULL;
	}

	cid->list_size = new_cid_length;
	cid->count = info->compatible_id_list.count;
	if (new_cid)
		cid->count++;
	next_id_string = (char *) cid->ids + (cid->count * sizeof(struct acpica_device_id));

	/* Copy all existing CIDs */

	for (i = 0; i < info->compatible_id_list.count; i++) {
		cid_length = info->compatible_id_list.ids[i].length;
		cid->ids[i].string = next_id_string;
		cid->ids[i].length = cid_length;

		ACPI_MEMCPY(next_id_string, info->compatible_id_list.ids[i].string,
			cid_length);

		next_id_string += cid_length;
	}

	/* Append the new CID */

	if (new_cid) {
		cid->ids[i].string = next_id_string;
		cid->ids[i].length = new_cid->length;

		ACPI_MEMCPY(next_id_string, new_cid->string, new_cid->length);
	}

	return cid;
}

1089
static void acpi_device_set_id(struct acpi_device *device)
Linus Torvalds's avatar
Linus Torvalds committed
1090
{
1091
	struct acpi_device_info *info = NULL;
Len Brown's avatar
Len Brown committed
1092
1093
	char *hid = NULL;
	char *uid = NULL;
1094
1095
	struct acpica_device_id_list *cid_list = NULL;
	char *cid_add = NULL;
Len Brown's avatar
Len Brown committed
1096
	acpi_status status;
Linus Torvalds's avatar
Linus Torvalds committed
1097

1098
	switch (device->device_type) {
Linus Torvalds's avatar
Linus Torvalds committed
1099
	case ACPI_BUS_TYPE_DEVICE:
1100
1101
1102
		if (ACPI_IS_ROOT_DEVICE(device)) {
			hid = ACPI_SYSTEM_HID;
			break;
1103
1104
1105
1106
1107
1108
		} else if (ACPI_IS_ROOT_DEVICE(device->parent)) {
			/* \_SB_, the only root-level namespace device */
			hid = ACPI_BUS_HID;
			strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME);
			strcpy(device->pnp.device_class, ACPI_BUS_CLASS);
			break;
1109
1110
		}

1111
		status = acpi_get_object_info(device->handle, &info);
Linus Torvalds's avatar
Linus Torvalds committed
1112
		if (ACPI_FAILURE(status)) {
1113
			printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__);
Linus Torvalds's avatar
Linus Torvalds committed
1114
1115
1116
1117
			return;
		}

		if (info->valid & ACPI_VALID_HID)
1118
			hid = info->hardware_id.string;
Linus Torvalds's avatar
Linus Torvalds committed
1119
		if (info->valid & ACPI_VALID_UID)
1120
			uid = info->unique_id.string;
Linus Torvalds's avatar
Linus Torvalds committed
1121
		if (info->valid & ACPI_VALID_CID)
1122
			cid_list = &info->compatible_id_list;
Linus Torvalds's avatar
Linus Torvalds committed
1123
1124
1125
1126
		if (info->valid & ACPI_VALID_ADR) {
			device->pnp.bus_address = info->address;
			device->flags.bus_address = 1;
		}
1127

1128
1129
1130
1131
1132
		/* If we have a video/bay/dock device, add our selfdefined
		   HID to the CID list. Like that the video/bay/dock drivers
		   will get autoloaded and the device might still match
		   against another driver.
		*/
1133
		if (acpi_is_video_device(device))
1134
1135
1136
1137
1138
			cid_add = ACPI_VIDEO_HID;
		else if (ACPI_SUCCESS(acpi_bay_match(device)))
			cid_add = ACPI_BAY_HID;
		else if (ACPI_SUCCESS(acpi_dock_match(device)))
			cid_add = ACPI_DOCK_HID;
1139

Linus Torvalds's avatar
Linus Torvalds committed
1140
1141
1142
1143
1144
		break;
	case ACPI_BUS_TYPE_POWER:
		hid = ACPI_POWER_HID;
		break;
	case ACPI_BUS_TYPE_PROCESSOR:
1145
		hid = ACPI_PROCESSOR_OBJECT_HID;
Linus Torvalds's avatar
Linus Torvalds committed
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
		break;
	case ACPI_BUS_TYPE_THERMAL:
		hid = ACPI_THERMAL_HID;
		break;
	case ACPI_BUS_TYPE_POWER_BUTTON:
		hid = ACPI_BUTTON_HID_POWERF;
		break;
	case ACPI_BUS_TYPE_SLEEP_BUTTON:
		hid = ACPI_BUTTON_HID_SLEEPF;
		break;
	}

	if (hid) {
1159
1160
1161
1162
1163
		device->pnp.hardware_id = ACPI_ALLOCATE_ZEROED(strlen (hid) + 1);
		if (device->pnp.hardware_id) {
			strcpy(device->pnp.hardware_id, hid);
			device->flags.hardware_id = 1;
		}
Linus Torvalds's avatar
Linus Torvalds committed
1164
	}
1165
1166
	if (!device->flags.hardware_id)
		device->pnp.hardware_id = "";
1167

Linus Torvalds's avatar
Linus Torvalds committed
1168
	if (uid) {
1169
1170
1171
1172
1173
		device->pnp.unique_id = ACPI_ALLOCATE_ZEROED(strlen (uid) + 1);
		if (device->pnp.unique_id) {
			strcpy(device->pnp.unique_id, uid);
			device->flags.unique_id = 1;
		}
Linus Torvalds's avatar
Linus Torvalds committed
1174
	}
1175
1176
	if (!device->flags.unique_id)
		device->pnp.unique_id = "";
1177

1178
	if (cid_list || cid_add) {