scan.c 37.5 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
	struct acpi_hardware_id *id;
49

50
	if (!acpi_dev->flags.hardware_id)
51
52
		return -ENODEV;

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

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

64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
	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);

82
static void acpi_bus_hot_remove_device(void *context)
Linus Torvalds's avatar
Linus Torvalds committed
83
{
84
85
	struct acpi_device *device;
	acpi_handle handle = context;
Linus Torvalds's avatar
Linus Torvalds committed
86
87
88
89
	struct acpi_object_list arg_list;
	union acpi_object arg;
	acpi_status status = AE_OK;

90
	if (acpi_bus_get_device(handle, &device))
91
		return;
92
93

	if (!device)
94
		return;
95
96

	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
97
		"Hot-removing device %s...\n", dev_name(&device->dev)));
98
99

	if (acpi_bus_trim(device, 1)) {
100
101
		printk(KERN_ERR PREFIX
				"Removing device failed\n");
102
		return;
103
	}
Linus Torvalds's avatar
Linus Torvalds committed
104

105
106
107
	/* power off device */
	status = acpi_evaluate_object(handle, "_PS3", NULL, NULL);
	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
108
109
		printk(KERN_WARNING PREFIX
				"Power-off device failed\n");
110
111

	if (device->flags.lockable) {
Linus Torvalds's avatar
Linus Torvalds committed
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
		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);
128
	if (ACPI_FAILURE(status))
129
130
		printk(KERN_WARNING PREFIX
				"Eject device failed\n");
Linus Torvalds's avatar
Linus Torvalds committed
131

132
	return;
Linus Torvalds's avatar
Linus Torvalds committed
133
134
135
}

static ssize_t
136
137
acpi_eject_store(struct device *d, struct device_attribute *attr,
		const char *buf, size_t count)
Linus Torvalds's avatar
Linus Torvalds committed
138
{
Len Brown's avatar
Len Brown committed
139
140
141
	int ret = count;
	acpi_status status;
	acpi_object_type type = 0;
142
	struct acpi_device *acpi_device = to_acpi_device(d);
Linus Torvalds's avatar
Linus Torvalds committed
143
144
145
146
147

	if ((!count) || (buf[0] != '1')) {
		return -EINVAL;
	}
#ifndef FORCE_EJECT
148
	if (acpi_device->driver == NULL) {
Linus Torvalds's avatar
Linus Torvalds committed
149
150
151
152
		ret = -ENODEV;
		goto err;
	}
#endif
153
154
	status = acpi_get_type(acpi_device->handle, &type);
	if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
Linus Torvalds's avatar
Linus Torvalds committed
155
156
157
158
		ret = -ENODEV;
		goto err;
	}

159
	acpi_os_hotplug_execute(acpi_bus_hot_remove_device, acpi_device->handle);
160
err:
Linus Torvalds's avatar
Linus Torvalds committed
161
162
163
	return ret;
}

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

166
167
168
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
169

170
	return sprintf(buf, "%s\n", acpi_device_hid(acpi_dev));
Linus Torvalds's avatar
Linus Torvalds committed
171
}
172
static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
173

174
175
176
177
178
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
179

180
	result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path);
181
	if (result)
182
		goto end;
Linus Torvalds's avatar
Linus Torvalds committed
183

184
185
	result = sprintf(buf, "%s\n", (char*)path.pointer);
	kfree(path.pointer);
186
end:
187
	return result;
Linus Torvalds's avatar
Linus Torvalds committed
188
}
189
static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
190

191
static int acpi_device_setup_files(struct acpi_device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
192
{
193
194
	acpi_status status;
	acpi_handle temp;
195
	int result = 0;
Linus Torvalds's avatar
Linus Torvalds committed
196
197

	/*
198
	 * Devices gotten from FADT don't have a "path" attribute
Linus Torvalds's avatar
Linus Torvalds committed
199
	 */
200
	if (dev->handle) {
201
		result = device_create_file(&dev->dev, &dev_attr_path);
202
		if (result)
203
			goto end;
Linus Torvalds's avatar
Linus Torvalds committed
204
205
	}

206
	if (dev->flags.hardware_id) {
207
		result = device_create_file(&dev->dev, &dev_attr_hid);
208
		if (result)
209
210
			goto end;
	}
Linus Torvalds's avatar
Linus Torvalds committed
211

212
	if (dev->flags.hardware_id) {
213
		result = device_create_file(&dev->dev, &dev_attr_modalias);
214
		if (result)
215
216
217
			goto end;
	}

218
219
220
221
        /*
         * If device has _EJ0, 'eject' file is created that is used to trigger
         * hot-removal function from userland.
         */
222
223
	status = acpi_get_handle(dev->handle, "_EJ0", &temp);
	if (ACPI_SUCCESS(status))
224
		result = device_create_file(&dev->dev, &dev_attr_eject);
225
end:
226
	return result;
Linus Torvalds's avatar
Linus Torvalds committed
227
228
}

229
static void acpi_device_remove_files(struct acpi_device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
230
{
231
232
	acpi_status status;
	acpi_handle temp;
Linus Torvalds's avatar
Linus Torvalds committed
233

234
235
236
237
238
239
240
	/*
	 * 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
241

242
	if (dev->flags.hardware_id)
243
244
		device_remove_file(&dev->dev, &dev_attr_modalias);

245
	if (dev->flags.hardware_id)
246
		device_remove_file(&dev->dev, &dev_attr_hid);
247
	if (dev->handle)
248
		device_remove_file(&dev->dev, &dev_attr_path);
Linus Torvalds's avatar
Linus Torvalds committed
249
250
}
/* --------------------------------------------------------------------------
Zhang Rui's avatar
Zhang Rui committed
251
			ACPI Bus operations
Linus Torvalds's avatar
Linus Torvalds committed
252
   -------------------------------------------------------------------------- */
253
254
255
256
257

int acpi_match_device_ids(struct acpi_device *device,
			  const struct acpi_device_id *ids)
{
	const struct acpi_device_id *id;
258
	struct acpi_hardware_id *hwid;
259

260
261
262
263
264
265
266
	/*
	 * If the device is not present, it is unnecessary to load device
	 * driver for it.
	 */
	if (!device->status.present)
		return -ENODEV;

267
268
269
	for (id = ids; id->id[0]; id++)
		list_for_each_entry(hwid, &device->pnp.ids, list)
			if (!strcmp((char *) id->id, hwid->id))
270
271
272
273
274
275
				return 0;

	return -ENOENT;
}
EXPORT_SYMBOL(acpi_match_device_ids);

276
277
278
279
280
281
282
283
284
285
static void acpi_free_ids(struct acpi_device *device)
{
	struct acpi_hardware_id *id, *tmp;

	list_for_each_entry_safe(id, tmp, &device->pnp.ids, list) {
		kfree(id->id);
		kfree(id);
	}
}

286
static void acpi_device_release(struct device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
287
{
288
	struct acpi_device *acpi_dev = to_acpi_device(dev);
Linus Torvalds's avatar
Linus Torvalds committed
289

290
	acpi_free_ids(acpi_dev);
291
	kfree(acpi_dev);
Linus Torvalds's avatar
Linus Torvalds committed
292
293
}

294
static int acpi_device_suspend(struct device *dev, pm_message_t state)
Linus Torvalds's avatar
Linus Torvalds committed
295
{
296
297
	struct acpi_device *acpi_dev = to_acpi_device(dev);
	struct acpi_driver *acpi_drv = acpi_dev->driver;
Linus Torvalds's avatar
Linus Torvalds committed
298

299
300
	if (acpi_drv && acpi_drv->ops.suspend)
		return acpi_drv->ops.suspend(acpi_dev, state);
Linus Torvalds's avatar
Linus Torvalds committed
301
302
303
	return 0;
}

304
static int acpi_device_resume(struct device *dev)
Zhang Rui's avatar
Zhang Rui committed
305
{
306
307
	struct acpi_device *acpi_dev = to_acpi_device(dev);
	struct acpi_driver *acpi_drv = acpi_dev->driver;
Linus Torvalds's avatar
Linus Torvalds committed
308

309
310
	if (acpi_drv && acpi_drv->ops.resume)
		return acpi_drv->ops.resume(acpi_dev);
311
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
312
313
}

314
static int acpi_bus_match(struct device *dev, struct device_driver *drv)
Zhang Rui's avatar
Zhang Rui committed
315
{
316
317
	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
318

319
	return !acpi_match_device_ids(acpi_dev, acpi_drv->ids);
320
}
Linus Torvalds's avatar
Linus Torvalds committed
321

322
static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
Linus Torvalds's avatar
Linus Torvalds committed
323
{
324
	struct acpi_device *acpi_dev = to_acpi_device(dev);
325
	int len;
326

327
328
329
330
331
332
333
	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
334
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
335
336
}

337
338
339
340
341
342
343
344
345
346
347
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;

348
349
	/* Fixed hardware devices have no handles */
	acpi_device_notify(NULL, ACPI_FIXED_HARDWARE_EVENT, device);
350
351
352
353
354
355
356
	return AE_OK;
}

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

357
	if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
358
359
360
361
		status =
		    acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
						     acpi_device_notify_fixed,
						     device);
362
	else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
		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)
{
380
	if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
381
382
		acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
						acpi_device_notify_fixed);
383
	else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
384
385
386
387
388
389
390
		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);
}

391
392
393
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
394
{
395
396
397
398
399
400
	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) {
401
402
		if (acpi_dev->bus_ops.acpi_op_start)
			acpi_start_single_object(acpi_dev);
403
404
405
406
407
408
409
410
411
412
413

		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;
			}
		}

414
415
416
417
418
419
420
		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
421

422
423
424
425
426
427
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) {
428
429
		if (acpi_drv->ops.notify)
			acpi_device_remove_notify_handler(acpi_dev);
430
		if (acpi_drv->ops.remove)
431
			acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
Linus Torvalds's avatar
Linus Torvalds committed
432
	}
433
	acpi_dev->driver = NULL;
434
	acpi_dev->driver_data = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
435

436
	put_device(dev);
Zhang Rui's avatar
Zhang Rui committed
437
438
	return 0;
}
Linus Torvalds's avatar
Linus Torvalds committed
439

440
struct bus_type acpi_bus_type = {
Zhang Rui's avatar
Zhang Rui committed
441
442
443
	.name		= "acpi",
	.suspend	= acpi_device_suspend,
	.resume		= acpi_device_resume,
444
445
446
447
	.match		= acpi_bus_match,
	.probe		= acpi_device_probe,
	.remove		= acpi_device_remove,
	.uevent		= acpi_device_uevent,
Zhang Rui's avatar
Zhang Rui committed
448
449
};

450
static int acpi_device_register(struct acpi_device *device)
Linus Torvalds's avatar
Linus Torvalds committed
451
{
Len Brown's avatar
Len Brown committed
452
	int result;
453
454
	struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id;
	int found = 0;
455

Zhang Rui's avatar
Zhang Rui committed
456
457
458
459
460
461
462
463
	/*
	 * 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
464

465
466
467
468
	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
469
	}
470

471
	mutex_lock(&acpi_device_lock);
472
473
474
475
476
	/*
	 * 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) {
477
		if (!strcmp(acpi_device_bus_id->bus_id, device->flags.hardware_id ? acpi_device_hid(device) : "device")) {
478
479
480
481
482
			acpi_device_bus_id->instance_no ++;
			found = 1;
			kfree(new_bus_id);
			break;
		}
Linus Torvalds's avatar
Linus Torvalds committed
483
	}
484
	if (!found) {
485
		acpi_device_bus_id = new_bus_id;
486
		strcpy(acpi_device_bus_id->bus_id, device->flags.hardware_id ? acpi_device_hid(device) : "device");
487
488
		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
489
	}
490
	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
491

Len Brown's avatar
Len Brown committed
492
	if (device->parent)
Zhang Rui's avatar
Zhang Rui committed
493
		list_add_tail(&device->node, &device->parent->children);
Len Brown's avatar
Len Brown committed
494

Zhang Rui's avatar
Zhang Rui committed
495
496
	if (device->wakeup.flags.valid)
		list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list);
497
	mutex_unlock(&acpi_device_lock);
Linus Torvalds's avatar
Linus Torvalds committed
498

499
	if (device->parent)
500
		device->dev.parent = &device->parent->dev;
501
502
	device->dev.bus = &acpi_bus_type;
	device->dev.release = &acpi_device_release;
503
	result = device_register(&device->dev);
504
	if (result) {
505
		dev_err(&device->dev, "Error registering device\n");
506
		goto end;
Linus Torvalds's avatar
Linus Torvalds committed
507
508
	}

509
	result = acpi_device_setup_files(device);
510
	if (result)
511
512
		printk(KERN_ERR PREFIX "Error creating sysfs interface for device %s\n",
		       dev_name(&device->dev));
Linus Torvalds's avatar
Linus Torvalds committed
513

514
	device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
Linus Torvalds's avatar
Linus Torvalds committed
515
	return 0;
516
end:
517
	mutex_lock(&acpi_device_lock);
Len Brown's avatar
Len Brown committed
518
	if (device->parent)
519
520
		list_del(&device->node);
	list_del(&device->wakeup_list);
521
	mutex_unlock(&acpi_device_lock);
522
	return result;
Linus Torvalds's avatar
Linus Torvalds committed
523
524
}

Zhang Rui's avatar
Zhang Rui committed
525
526
static void acpi_device_unregister(struct acpi_device *device, int type)
{
527
	mutex_lock(&acpi_device_lock);
Len Brown's avatar
Len Brown committed
528
	if (device->parent)
Zhang Rui's avatar
Zhang Rui committed
529
		list_del(&device->node);
Linus Torvalds's avatar
Linus Torvalds committed
530

Zhang Rui's avatar
Zhang Rui committed
531
	list_del(&device->wakeup_list);
532
	mutex_unlock(&acpi_device_lock);
Linus Torvalds's avatar
Linus Torvalds committed
533

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

536
	acpi_device_remove_files(device);
537
	device_unregister(&device->dev);
Linus Torvalds's avatar
Linus Torvalds committed
538
539
}

Zhang Rui's avatar
Zhang Rui committed
540
541
542
/* --------------------------------------------------------------------------
                                 Driver Management
   -------------------------------------------------------------------------- */
Linus Torvalds's avatar
Linus Torvalds committed
543
/**
544
545
546
547
 * acpi_bus_driver_init - add a device to a driver
 * @device: the device to add and initialize
 * @driver: driver for the device
 *
548
 * Used to initialize a device via its device driver.  Called whenever a
549
 * driver is bound to a device.  Invokes the driver's add() ops.
Linus Torvalds's avatar
Linus Torvalds committed
550
551
 */
static int
Len Brown's avatar
Len Brown committed
552
acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
Linus Torvalds's avatar
Linus Torvalds committed
553
{
Len Brown's avatar
Len Brown committed
554
	int result = 0;
Linus Torvalds's avatar
Linus Torvalds committed
555
556

	if (!device || !driver)
557
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
558
559

	if (!driver->ops.add)
560
		return -ENOSYS;
Linus Torvalds's avatar
Linus Torvalds committed
561
562
563
564

	result = driver->ops.add(device);
	if (result) {
		device->driver = NULL;
565
		device->driver_data = NULL;
566
		return result;
Linus Torvalds's avatar
Linus Torvalds committed
567
568
569
570
571
572
573
574
575
	}

	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
576
577
	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
			  "Driver successfully bound to device\n"));
578
	return 0;
579
580
}

581
static int acpi_start_single_object(struct acpi_device *device)
582
583
584
585
586
587
{
	int result = 0;
	struct acpi_driver *driver;


	if (!(driver = device->driver))
588
		return 0;
589

Linus Torvalds's avatar
Linus Torvalds committed
590
591
592
593
594
595
	if (driver->ops.start) {
		result = driver->ops.start(device);
		if (result && driver->ops.remove)
			driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
	}

596
	return result;
Linus Torvalds's avatar
Linus Torvalds committed
597
598
}

Zhang Rui's avatar
Zhang Rui committed
599
600
601
602
603
604
605
606
607
/**
 * 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
608
{
609
	int ret;
Linus Torvalds's avatar
Linus Torvalds committed
610

Zhang Rui's avatar
Zhang Rui committed
611
612
	if (acpi_disabled)
		return -ENODEV;
613
614
615
	driver->drv.name = driver->name;
	driver->drv.bus = &acpi_bus_type;
	driver->drv.owner = driver->owner;
Linus Torvalds's avatar
Linus Torvalds committed
616

617
618
	ret = driver_register(&driver->drv);
	return ret;
Zhang Rui's avatar
Zhang Rui committed
619
}
Linus Torvalds's avatar
Linus Torvalds committed
620

Zhang Rui's avatar
Zhang Rui committed
621
622
623
624
625
626
627
628
629
630
631
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)
{
632
	driver_unregister(&driver->drv);
Zhang Rui's avatar
Zhang Rui committed
633
634
635
636
637
638
639
}

EXPORT_SYMBOL(acpi_bus_unregister_driver);

/* --------------------------------------------------------------------------
                                 Device Enumeration
   -------------------------------------------------------------------------- */
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
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
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
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;
682
683
		status = acpi_get_handle(ACPI_ROOT_OBJECT, obj->string.pointer,
					 ejd);
Zhang Rui's avatar
Zhang Rui committed
684
685
686
687
688
689
		kfree(buffer.pointer);
	}
	return status;
}
EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);

690
void acpi_bus_data_handler(acpi_handle handle, void *context)
Zhang Rui's avatar
Zhang Rui committed
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
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
{

	/* 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]);
744
		if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
Zhang Rui's avatar
Zhang Rui committed
745
746
747
			return AE_BAD_DATA;

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

	return AE_OK;
Linus Torvalds's avatar
Linus Torvalds committed
751
752
}

Zhang Rui's avatar
Zhang Rui committed
753
static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
Linus Torvalds's avatar
Linus Torvalds committed
754
{
Zhang Rui's avatar
Zhang Rui committed
755
756
757
	acpi_status status = 0;
	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
	union acpi_object *package = NULL;
758
	int psw_error;
Linus Torvalds's avatar
Linus Torvalds committed
759

760
761
762
763
764
765
766
	struct acpi_device_id button_device_ids[] = {
		{"PNP0C0D", 0},
		{"PNP0C0C", 0},
		{"PNP0C0E", 0},
		{"", 0},
	};

Zhang Rui's avatar
Zhang Rui committed
767
768
769
770
771
	/* _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
772
773
	}

Zhang Rui's avatar
Zhang Rui committed
774
775
776
777
778
779
	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
780

Zhang Rui's avatar
Zhang Rui committed
781
	kfree(buffer.pointer);
Linus Torvalds's avatar
Linus Torvalds committed
782

Zhang Rui's avatar
Zhang Rui committed
783
	device->wakeup.flags.valid = 1;
784
	device->wakeup.prepare_count = 0;
785
786
787
788
789
790
	/* 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.
	 */
791
792
793
794
795
	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
796
	/* Power button, Lid switch always enable wakeup */
797
	if (!acpi_match_device_ids(device, button_device_ids))
Zhang Rui's avatar
Zhang Rui committed
798
		device->wakeup.flags.run_wake = 1;
Linus Torvalds's avatar
Linus Torvalds committed
799

800
end:
Zhang Rui's avatar
Zhang Rui committed
801
802
	if (ACPI_FAILURE(status))
		device->flags.wake_capable = 0;
803
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
804
805
}

Zhang Rui's avatar
Zhang Rui committed
806
static int acpi_bus_get_power_flags(struct acpi_device *device)
Linus Torvalds's avatar
Linus Torvalds committed
807
{
Zhang Rui's avatar
Zhang Rui committed
808
809
810
	acpi_status status = 0;
	acpi_handle handle = NULL;
	u32 i = 0;
Bjorn Helgaas's avatar
Bjorn Helgaas committed
811

Len Brown's avatar
Len Brown committed
812

Zhang Rui's avatar
Zhang Rui committed
813
814
815
816
817
818
819
820
821
	/*
	 * 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
822

Zhang Rui's avatar
Zhang Rui committed
823
824
825
826
827
828
	/*
	 * 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
829

Zhang Rui's avatar
Zhang Rui committed
830
831
832
833
834
835
		/* 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
836
837
		}

Zhang Rui's avatar
Zhang Rui committed
838
839
840
841
842
843
		/* 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
844
845
		}

Zhang Rui's avatar
Zhang Rui committed
846
847
848
		/* 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
849

Zhang Rui's avatar
Zhang Rui committed
850
851
852
		ps->power = -1;	/* Unknown - driver assigned */
		ps->latency = -1;	/* Unknown - driver assigned */
	}
Linus Torvalds's avatar
Linus Torvalds committed
853

Zhang Rui's avatar
Zhang Rui committed
854
855
856
857
858
	/* 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;
859

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

Zhang Rui's avatar
Zhang Rui committed
862
	device->power.state = ACPI_STATE_UNKNOWN;
863
	acpi_bus_get_power(device->handle, &(device->power.state));
864

Zhang Rui's avatar
Zhang Rui committed
865
866
	return 0;
}
867

Len Brown's avatar
Len Brown committed
868
static int acpi_bus_get_flags(struct acpi_device *device)
Linus Torvalds's avatar
Linus Torvalds committed
869
{
Len Brown's avatar
Len Brown committed
870
871
	acpi_status status = AE_OK;
	acpi_handle temp = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910


	/* 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 _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
911
	/* TBD: Performance management */
Linus Torvalds's avatar
Linus Torvalds committed
912

913
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
914
915
}

916
static void acpi_device_get_busid(struct acpi_device *device)
Linus Torvalds's avatar
Linus Torvalds committed
917
{
Len Brown's avatar
Len Brown committed
918
919
920
	char bus_id[5] = { '?', 0 };
	struct acpi_buffer buffer = { sizeof(bus_id), bus_id };
	int i = 0;
Linus Torvalds's avatar
Linus Torvalds committed
921
922
923
924
925
926
927

	/*
	 * Bus ID
	 * ------
	 * The device's Bus ID is simply the object name.
	 * TBD: Shouldn't this value be unique (within the ACPI namespace)?
	 */
928
	if (ACPI_IS_ROOT_DEVICE(device)) {
Linus Torvalds's avatar
Linus Torvalds committed
929
		strcpy(device->pnp.bus_id, "ACPI");
930
931
932
933
		return;
	}

	switch (device->device_type) {
Linus Torvalds's avatar
Linus Torvalds committed
934
935
936
937
938
939
940
	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:
941
		acpi_get_name(device->handle, ACPI_SINGLE_NAME, &buffer);
Linus Torvalds's avatar
Linus Torvalds committed
942
943
944
945
946
947
948
949
950
951
952
953
		/* 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;
	}
}

954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
/*
 * 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;
}

990
991
992
993
994
995
996
997
998
/*
 * 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);
}

999
char *acpi_device_hid(struct acpi_device *device)
1000
{
1001
	struct acpi_hardware_id *hid;
1002

1003
1004
1005
1006
	hid = list_first_entry(&device->pnp.ids, struct acpi_hardware_id, list);
	return hid->id;
}
EXPORT_SYMBOL(acpi_device_hid);
1007

1008
1009
1010
static void acpi_add_id(struct acpi_device *device, const char *dev_id)
{
	struct acpi_hardware_id *id;
1011

1012
1013
1014
	id = kmalloc(sizeof(*id), GFP_KERNEL);
	if (!id)
		return;
1015

1016
1017
1018
1019
	id->id = kmalloc(strlen(dev_id) + 1, GFP_KERNEL);
	if (!id->id) {
		kfree(id);
		return;
1020
1021
	}

1022
1023
	strcpy(id->id, dev_id);
	list_add_tail(&id->list, &device->pnp.ids);
1024
1025
}

1026
static void acpi_device_set_id(struct acpi_device *device)
Linus Torvalds's avatar
Linus Torvalds committed
1027
{
1028
	struct acpi_device_info *info = NULL;
Len Brown's avatar
Len Brown committed
1029
1030
	char *hid = NULL;
	char *uid = NULL;
1031
1032
	struct acpica_device_id_list *cid_list = NULL;
	char *cid_add = NULL;
Len Brown's avatar
Len Brown committed
1033
	acpi_status status;
1034
	int i;
Linus Torvalds's avatar
Linus Torvalds committed
1035

1036
	switch (device->device_type) {
Linus Torvalds's avatar
Linus Torvalds committed
1037
	case ACPI_BUS_TYPE_DEVICE:
1038
1039
1040
		if (ACPI_IS_ROOT_DEVICE(device)) {
			hid = ACPI_SYSTEM_HID;
			break;
1041
1042
1043
1044
1045
1046
		} 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;
1047
1048
		}

1049
		status = acpi_get_object_info(device->handle, &info);
Linus Torvalds's avatar
Linus Torvalds committed
1050
		if (ACPI_FAILURE(status)) {
1051
			printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__);
Linus Torvalds's avatar
Linus Torvalds committed
1052
1053
1054
1055
			return;
		}

		if (info->valid & ACPI_VALID_HID)
1056
			hid = info->hardware_id.string;
Linus Torvalds's avatar
Linus Torvalds committed
1057
		if (info->valid & ACPI_VALID_UID)
1058
			uid = info->unique_id.string;
Linus Torvalds's avatar
Linus Torvalds committed
1059
		if (info->valid & ACPI_VALID_CID)
1060
			cid_list = &info->compatible_id_list;
Linus Torvalds's avatar
Linus Torvalds committed
1061
1062
1063
1064
		if (info->valid & ACPI_VALID_ADR) {
			device->pnp.bus_address = info->address;
			device->flags.bus_address = 1;
		}
1065

1066
1067
1068
1069
1070
		/* 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.
		*/
1071
		if (acpi_is_video_device(device))
1072
1073
1074
1075
1076
			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;
1077

Linus Torvalds's avatar
Linus Torvalds committed
1078
1079
1080
1081
1082
		break;
	case ACPI_BUS_TYPE_POWER:
		hid = ACPI_POWER_HID;
		break;
	case ACPI_BUS_TYPE_PROCESSOR:
1083
		hid = ACPI_PROCESSOR_OBJECT_HID;
Linus Torvalds's avatar
Linus Torvalds committed
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
		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;
	}

1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
	/*
	 * We build acpi_devices for some objects that don't have _HID or _CID,
	 * e.g., PCI bridges and slots.  Drivers can't bind to these objects,
	 * but we do use them indirectly by traversing the acpi_device tree.
	 * This generic ID isn't useful for driver binding, but it provides
	 * the useful property that "every acpi_device has an ID."
	 */
	if (!hid && !cid_list && !cid_add)
		hid = "device";

Linus Torvalds's avatar
Linus Torvalds committed
1106
	if (hid) {
1107
1108
		acpi_add_id(device, hid);
		device->flags.hardware_id = 1;
Linus Torvalds's avatar
Linus Torvalds committed
1109
1110
	}
	if (uid) {
1111
1112
1113
1114
1115
		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
1116
	}
1117
1118
	if (!device->flags.unique_id)
		device->pnp.unique_id = "";
1119

1120
1121
1122
	if (cid_list)
		for (i = 0; i < cid_list->count; i++)
			acpi_add_id(device, cid_list->ids[i].string);
1123
	if (cid_add)
1124
		acpi_add_id(device, cid_add);
Linus Torvalds's avatar
Linus Torvalds committed
1125

1126
	kfree(info);
Linus Torvalds's avatar
Linus Torvalds committed
1127
1128
}