glue.c 8.6 KB
Newer Older
1 2 3 4 5 6 7 8
/*
 * Link physical devices with ACPI devices support
 *
 * Copyright (c) 2005 David Shaohua Li <shaohua.li@intel.com>
 * Copyright (c) 2005 Intel Corp.
 *
 * This file is released under the GPLv2.
 */
9
#include <linux/export.h>
10 11 12
#include <linux/init.h>
#include <linux/list.h>
#include <linux/device.h>
13
#include <linux/slab.h>
14 15 16
#include <linux/rwsem.h>
#include <linux/acpi.h>

17 18
#include "internal.h"

19 20
#define ACPI_GLUE_DEBUG	0
#if ACPI_GLUE_DEBUG
21 22
#define DBG(fmt, ...)						\
	printk(KERN_DEBUG PREFIX fmt, ##__VA_ARGS__)
23
#else
24 25 26 27 28
#define DBG(fmt, ...)						\
do {								\
	if (0)							\
		printk(KERN_DEBUG PREFIX fmt, ##__VA_ARGS__);	\
} while (0)
29 30 31 32
#endif
static LIST_HEAD(bus_type_list);
static DECLARE_RWSEM(bus_type_sem);

33
#define PHYSICAL_NODE_STRING "physical_node"
34
#define PHYSICAL_NODE_NAME_SIZE (sizeof(PHYSICAL_NODE_STRING) + 10)
35

36 37 38 39
int register_acpi_bus_type(struct acpi_bus_type *type)
{
	if (acpi_disabled)
		return -ENODEV;
40
	if (type && type->match && type->find_device) {
41 42 43
		down_write(&bus_type_sem);
		list_add_tail(&type->list, &bus_type_list);
		up_write(&bus_type_sem);
44
		printk(KERN_INFO PREFIX "bus type %s registered\n", type->name);
45 46 47 48
		return 0;
	}
	return -ENODEV;
}
49
EXPORT_SYMBOL_GPL(register_acpi_bus_type);
50 51 52 53 54 55 56 57 58

int unregister_acpi_bus_type(struct acpi_bus_type *type)
{
	if (acpi_disabled)
		return 0;
	if (type) {
		down_write(&bus_type_sem);
		list_del_init(&type->list);
		up_write(&bus_type_sem);
59 60
		printk(KERN_INFO PREFIX "bus type %s unregistered\n",
		       type->name);
61 62 63 64
		return 0;
	}
	return -ENODEV;
}
65
EXPORT_SYMBOL_GPL(unregister_acpi_bus_type);
66

67
static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
68 69 70 71 72
{
	struct acpi_bus_type *tmp, *ret = NULL;

	down_read(&bus_type_sem);
	list_for_each_entry(tmp, &bus_type_list, list) {
73
		if (tmp->match(dev)) {
74 75 76 77 78 79 80 81
			ret = tmp;
			break;
		}
	}
	up_read(&bus_type_sem);
	return ret;
}

82 83 84
#define FIND_CHILD_MIN_SCORE	1
#define FIND_CHILD_MAX_SCORE	2

85
static int find_child_checks(struct acpi_device *adev, bool check_children)
86
{
87
	bool sta_present = true;
88 89 90
	unsigned long long sta;
	acpi_status status;

91
	status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta);
92 93 94 95
	if (status == AE_NOT_FOUND)
		sta_present = false;
	else if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED))
		return -ENODEV;
96

97 98
	if (check_children && list_empty(&adev->children))
		return -ENODEV;
99

100
	return sta_present ? FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE;
101 102
}

103 104
struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
					   u64 address, bool check_children)
105
{
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
	struct acpi_device *adev, *ret = NULL;
	int ret_score = 0;

	list_for_each_entry(adev, &parent->children, node) {
		unsigned long long addr;
		acpi_status status;
		int score;

		status = acpi_evaluate_integer(adev->handle, METHOD_NAME__ADR,
					       NULL, &addr);
		if (ACPI_FAILURE(status) || addr != address)
			continue;

		if (!ret) {
			/* This is the first matching object.  Save it. */
			ret = adev;
			continue;
		}
		/*
		 * There is more than one matching device object with the same
		 * _ADR value.  That really is unexpected, so we are kind of
		 * beyond the scope of the spec here.  We have to choose which
		 * one to return, though.
		 *
		 * First, check if the previously found object is good enough
		 * and return it if so.  Second, do the same for the object that
		 * we've just found.
		 */
		if (!ret_score) {
			ret_score = find_child_checks(ret, check_children);
			if (ret_score == FIND_CHILD_MAX_SCORE)
				return ret;
		}
		score = find_child_checks(adev, check_children);
		if (score == FIND_CHILD_MAX_SCORE) {
			return adev;
		} else if (score > ret_score) {
			ret = adev;
			ret_score = score;
		}
146
	}
147
	return ret;
148 149
}

150
acpi_handle acpi_find_child(acpi_handle handle, u64 addr, bool is_bridge)
151
{
152 153 154 155 156 157 158
	struct acpi_device *adev;

	if (!handle || acpi_bus_get_device(handle, &adev))
		return NULL;

	adev = acpi_find_child_device(adev, addr, is_bridge);
	return adev ? adev->handle : NULL;
159
}
160
EXPORT_SYMBOL_GPL(acpi_find_child);
161

162 163 164 165 166 167 168 169 170
static void acpi_physnode_link_name(char *buf, unsigned int node_id)
{
	if (node_id > 0)
		snprintf(buf, PHYSICAL_NODE_NAME_SIZE,
			 PHYSICAL_NODE_STRING "%u", node_id);
	else
		strcpy(buf, PHYSICAL_NODE_STRING);
}

171
int acpi_bind_one(struct device *dev, acpi_handle handle)
172
{
173
	struct acpi_device *acpi_dev = NULL;
174
	struct acpi_device_physical_node *physical_node, *pn;
175 176 177
	char physical_node_name[PHYSICAL_NODE_NAME_SIZE];
	struct list_head *physnode_list;
	unsigned int node_id;
178
	int retval = -EINVAL;
179

180
	if (ACPI_COMPANION(dev)) {
181
		if (handle) {
182
			dev_warn(dev, "ACPI companion already set\n");
183 184
			return -EINVAL;
		} else {
185
			acpi_dev = ACPI_COMPANION(dev);
186
		}
187 188
	} else {
		acpi_bus_get_device(handle, &acpi_dev);
189
	}
190
	if (!acpi_dev)
191
		return -EINVAL;
192

193
	get_device(&acpi_dev->dev);
194
	get_device(dev);
195
	physical_node = kzalloc(sizeof(*physical_node), GFP_KERNEL);
196 197 198
	if (!physical_node) {
		retval = -ENOMEM;
		goto err;
199 200
	}

201
	mutex_lock(&acpi_dev->physical_node_lock);
202

203 204 205 206 207 208 209 210
	/*
	 * Keep the list sorted by node_id so that the IDs of removed nodes can
	 * be recycled easily.
	 */
	physnode_list = &acpi_dev->physical_node_list;
	node_id = 0;
	list_for_each_entry(pn, &acpi_dev->physical_node_list, node) {
		/* Sanity check. */
211
		if (pn->dev == dev) {
212 213
			mutex_unlock(&acpi_dev->physical_node_lock);

214
			dev_warn(dev, "Already associated with ACPI node\n");
215
			kfree(physical_node);
216
			if (ACPI_COMPANION(dev) != acpi_dev)
217
				goto err;
218

219
			put_device(dev);
220
			put_device(&acpi_dev->dev);
221
			return 0;
222
		}
223 224 225 226
		if (pn->node_id == node_id) {
			physnode_list = &pn->node;
			node_id++;
		}
227 228
	}

229
	physical_node->node_id = node_id;
230
	physical_node->dev = dev;
231
	list_add(&physical_node->node, physnode_list);
232
	acpi_dev->physical_node_count++;
233

234 235
	if (!ACPI_COMPANION(dev))
		ACPI_COMPANION_SET(dev, acpi_dev);
236

237
	acpi_physnode_link_name(physical_node_name, node_id);
238
	retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
239
				   physical_node_name);
240 241 242 243
	if (retval)
		dev_err(&acpi_dev->dev, "Failed to create link %s (%d)\n",
			physical_node_name, retval);

244
	retval = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj,
245
				   "firmware_node");
246 247 248
	if (retval)
		dev_err(dev, "Failed to create link firmware_node (%d)\n",
			retval);
249

250 251
	mutex_unlock(&acpi_dev->physical_node_lock);

252 253 254
	if (acpi_dev->wakeup.flags.valid)
		device_set_wakeup_capable(dev, true);

255
	return 0;
256 257

 err:
258
	ACPI_COMPANION_SET(dev, NULL);
259
	put_device(dev);
260
	put_device(&acpi_dev->dev);
261
	return retval;
262
}
263
EXPORT_SYMBOL_GPL(acpi_bind_one);
264

265
int acpi_unbind_one(struct device *dev)
266
{
267
	struct acpi_device *acpi_dev = ACPI_COMPANION(dev);
268 269
	struct acpi_device_physical_node *entry;

270
	if (!acpi_dev)
271
		return 0;
272

273
	mutex_lock(&acpi_dev->physical_node_lock);
274 275 276 277 278 279 280 281 282 283 284

	list_for_each_entry(entry, &acpi_dev->physical_node_list, node)
		if (entry->dev == dev) {
			char physnode_name[PHYSICAL_NODE_NAME_SIZE];

			list_del(&entry->node);
			acpi_dev->physical_node_count--;

			acpi_physnode_link_name(physnode_name, entry->node_id);
			sysfs_remove_link(&acpi_dev->dev.kobj, physnode_name);
			sysfs_remove_link(&dev->kobj, "firmware_node");
285
			ACPI_COMPANION_SET(dev, NULL);
286
			/* Drop references taken by acpi_bind_one(). */
287
			put_device(dev);
288
			put_device(&acpi_dev->dev);
289 290 291 292
			kfree(entry);
			break;
		}

293
	mutex_unlock(&acpi_dev->physical_node_lock);
294 295
	return 0;
}
296
EXPORT_SYMBOL_GPL(acpi_unbind_one);
297

298 299 300 301 302 303 304 305 306
void acpi_preset_companion(struct device *dev, acpi_handle parent, u64 addr)
{
	struct acpi_device *adev;

	if (!acpi_bus_get_device(acpi_get_child(parent, addr), &adev))
		ACPI_COMPANION_SET(dev, adev);
}
EXPORT_SYMBOL_GPL(acpi_preset_companion);

307 308
static int acpi_platform_notify(struct device *dev)
{
309
	struct acpi_bus_type *type = acpi_get_bus_type(dev);
310
	acpi_handle handle;
311
	int ret;
312

313
	ret = acpi_bind_one(dev, NULL);
314
	if (ret && type) {
315 316 317 318 319 320 321 322
		ret = type->find_device(dev, &handle);
		if (ret) {
			DBG("Unable to get handle for %s\n", dev_name(dev));
			goto out;
		}
		ret = acpi_bind_one(dev, handle);
		if (ret)
			goto out;
323
	}
324 325 326

	if (type && type->setup)
		type->setup(dev);
327

328
 out:
329 330 331 332
#if ACPI_GLUE_DEBUG
	if (!ret) {
		struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };

333
		acpi_get_name(ACPI_HANDLE(dev), ACPI_FULL_PATHNAME, &buffer);
334
		DBG("Device %s -> %s\n", dev_name(dev), (char *)buffer.pointer);
335
		kfree(buffer.pointer);
336
	} else
337
		DBG("Device %s -> No ACPI support\n", dev_name(dev));
338 339 340 341 342 343 344
#endif

	return ret;
}

static int acpi_platform_notify_remove(struct device *dev)
{
345 346
	struct acpi_bus_type *type;

347
	type = acpi_get_bus_type(dev);
348 349 350
	if (type && type->cleanup)
		type->cleanup(dev);

351 352 353 354
	acpi_unbind_one(dev);
	return 0;
}

355
int __init init_acpi_device_notify(void)
356 357 358 359 360 361 362 363 364
{
	if (platform_notify || platform_notify_remove) {
		printk(KERN_ERR PREFIX "Can't use platform_notify\n");
		return 0;
	}
	platform_notify = acpi_platform_notify;
	platform_notify_remove = acpi_platform_notify_remove;
	return 0;
}