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
#include <linux/rwsem.h>
#include <linux/acpi.h>
16
#include <linux/dma-mapping.h>
17

18 19
#include "internal.h"

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

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

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

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);
60 61
		printk(KERN_INFO PREFIX "bus type %s unregistered\n",
		       type->name);
62 63 64 65
		return 0;
	}
	return -ENODEV;
}
66
EXPORT_SYMBOL_GPL(unregister_acpi_bus_type);
67

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

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

83 84 85
#define FIND_CHILD_MIN_SCORE	1
#define FIND_CHILD_MAX_SCORE	2

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

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

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

101
	return sta_present ? FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE;
102 103
}

104 105
struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
					   u64 address, bool check_children)
106
{
107 108 109
	struct acpi_device *adev, *ret = NULL;
	int ret_score = 0;

110 111 112
	if (!parent)
		return NULL;

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 146 147 148 149
	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;
		}
150
	}
151
	return ret;
152
}
153
EXPORT_SYMBOL_GPL(acpi_find_child_device);
154

155 156 157 158 159 160 161 162 163
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);
}

164
int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
165
{
166
	struct acpi_device_physical_node *physical_node, *pn;
167 168 169
	char physical_node_name[PHYSICAL_NODE_NAME_SIZE];
	struct list_head *physnode_list;
	unsigned int node_id;
170
	int retval = -EINVAL;
171
	bool coherent;
172

173
	if (has_acpi_companion(dev)) {
174
		if (acpi_dev) {
175
			dev_warn(dev, "ACPI companion already set\n");
176 177
			return -EINVAL;
		} else {
178
			acpi_dev = ACPI_COMPANION(dev);
179
		}
180
	}
181
	if (!acpi_dev)
182
		return -EINVAL;
183

184
	get_device(&acpi_dev->dev);
185
	get_device(dev);
186
	physical_node = kzalloc(sizeof(*physical_node), GFP_KERNEL);
187 188 189
	if (!physical_node) {
		retval = -ENOMEM;
		goto err;
190 191
	}

192
	mutex_lock(&acpi_dev->physical_node_lock);
193

194 195 196 197 198 199 200 201
	/*
	 * 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. */
202
		if (pn->dev == dev) {
203 204
			mutex_unlock(&acpi_dev->physical_node_lock);

205
			dev_warn(dev, "Already associated with ACPI node\n");
206
			kfree(physical_node);
207
			if (ACPI_COMPANION(dev) != acpi_dev)
208
				goto err;
209

210
			put_device(dev);
211
			put_device(&acpi_dev->dev);
212
			return 0;
213
		}
214 215 216 217
		if (pn->node_id == node_id) {
			physnode_list = &pn->node;
			node_id++;
		}
218 219
	}

220
	physical_node->node_id = node_id;
221
	physical_node->dev = dev;
222
	list_add(&physical_node->node, physnode_list);
223
	acpi_dev->physical_node_count++;
224

225
	if (!has_acpi_companion(dev))
226
		ACPI_COMPANION_SET(dev, acpi_dev);
227

228 229 230
	if (acpi_check_dma(acpi_dev, &coherent))
		arch_setup_dma_ops(dev, 0, 0, NULL, coherent);

231
	acpi_physnode_link_name(physical_node_name, node_id);
232
	retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
233
				   physical_node_name);
234 235 236 237
	if (retval)
		dev_err(&acpi_dev->dev, "Failed to create link %s (%d)\n",
			physical_node_name, retval);

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

244 245
	mutex_unlock(&acpi_dev->physical_node_lock);

246 247 248
	if (acpi_dev->wakeup.flags.valid)
		device_set_wakeup_capable(dev, true);

249
	return 0;
250 251

 err:
252
	ACPI_COMPANION_SET(dev, NULL);
253
	put_device(dev);
254
	put_device(&acpi_dev->dev);
255
	return retval;
256
}
257
EXPORT_SYMBOL_GPL(acpi_bind_one);
258

259
int acpi_unbind_one(struct device *dev)
260
{
261
	struct acpi_device *acpi_dev = ACPI_COMPANION(dev);
262 263
	struct acpi_device_physical_node *entry;

264
	if (!acpi_dev)
265
		return 0;
266

267
	mutex_lock(&acpi_dev->physical_node_lock);
268 269 270 271 272 273 274 275 276 277 278

	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");
279
			ACPI_COMPANION_SET(dev, NULL);
280
			/* Drop references taken by acpi_bind_one(). */
281
			put_device(dev);
282
			put_device(&acpi_dev->dev);
283 284 285 286
			kfree(entry);
			break;
		}

287
	mutex_unlock(&acpi_dev->physical_node_lock);
288 289
	return 0;
}
290
EXPORT_SYMBOL_GPL(acpi_unbind_one);
291 292 293

static int acpi_platform_notify(struct device *dev)
{
294
	struct acpi_bus_type *type = acpi_get_bus_type(dev);
295
	struct acpi_device *adev;
296
	int ret;
297

298
	ret = acpi_bind_one(dev, NULL);
299
	if (ret && type) {
300 301 302 303
		struct acpi_device *adev;

		adev = type->find_companion(dev);
		if (!adev) {
304
			DBG("Unable to get handle for %s\n", dev_name(dev));
305
			ret = -ENODEV;
306 307
			goto out;
		}
308
		ret = acpi_bind_one(dev, adev);
309 310
		if (ret)
			goto out;
311
	}
312 313 314
	adev = ACPI_COMPANION(dev);
	if (!adev)
		goto out;
315 316 317

	if (type && type->setup)
		type->setup(dev);
318 319
	else if (adev->handler && adev->handler->bind)
		adev->handler->bind(dev);
320

321
 out:
322 323 324 325
#if ACPI_GLUE_DEBUG
	if (!ret) {
		struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };

326
		acpi_get_name(ACPI_HANDLE(dev), ACPI_FULL_PATHNAME, &buffer);
327
		DBG("Device %s -> %s\n", dev_name(dev), (char *)buffer.pointer);
328
		kfree(buffer.pointer);
329
	} else
330
		DBG("Device %s -> No ACPI support\n", dev_name(dev));
331 332 333 334 335 336 337
#endif

	return ret;
}

static int acpi_platform_notify_remove(struct device *dev)
{
338
	struct acpi_device *adev = ACPI_COMPANION(dev);
339 340
	struct acpi_bus_type *type;

341 342 343
	if (!adev)
		return 0;

344
	type = acpi_get_bus_type(dev);
345 346
	if (type && type->cleanup)
		type->cleanup(dev);
347 348
	else if (adev->handler && adev->handler->unbind)
		adev->handler->unbind(dev);
349

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

354
int __init init_acpi_device_notify(void)
355 356 357 358 359 360 361 362 363
{
	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;
}