Commit b6202832 authored by Len Brown's avatar Len Brown
Browse files

Merge branch 'wmi' into release

parents 1a544d28 1caab3c1
Loading
Loading
Loading
Loading
+173 −2
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/device.h>
#include <linux/list.h>
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
@@ -65,6 +66,7 @@ struct wmi_block {
	acpi_handle handle;
	wmi_notify_handler handler;
	void *handler_data;
	struct device *dev;
};

static struct wmi_block wmi_blocks;
@@ -195,6 +197,34 @@ static bool wmi_parse_guid(const u8 *src, u8 *dest)
	return true;
}

/*
 * Convert a raw GUID to the ACII string representation
 */
static int wmi_gtoa(const char *in, char *out)
{
	int i;

	for (i = 3; i >= 0; i--)
		out += sprintf(out, "%02X", in[i] & 0xFF);

	out += sprintf(out, "-");
	out += sprintf(out, "%02X", in[5] & 0xFF);
	out += sprintf(out, "%02X", in[4] & 0xFF);
	out += sprintf(out, "-");
	out += sprintf(out, "%02X", in[7] & 0xFF);
	out += sprintf(out, "%02X", in[6] & 0xFF);
	out += sprintf(out, "-");
	out += sprintf(out, "%02X", in[8] & 0xFF);
	out += sprintf(out, "%02X", in[9] & 0xFF);
	out += sprintf(out, "-");

	for (i = 10; i <= 15; i++)
		out += sprintf(out, "%02X", in[i] & 0xFF);

	out = '\0';
	return 0;
}

static bool find_guid(const char *guid_string, struct wmi_block **out)
{
	char tmp[16], guid_input[16];
@@ -554,6 +584,138 @@ bool wmi_has_guid(const char *guid_string)
}
EXPORT_SYMBOL_GPL(wmi_has_guid);

/*
 * sysfs interface
 */
static ssize_t show_modalias(struct device *dev, struct device_attribute *attr,
			     char *buf)
{
	char guid_string[37];
	struct wmi_block *wblock;

	wblock = dev_get_drvdata(dev);
	if (!wblock)
		return -ENOMEM;

	wmi_gtoa(wblock->gblock.guid, guid_string);

	return sprintf(buf, "wmi:%s\n", guid_string);
}
static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);

static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
{
	char guid_string[37];

	struct wmi_block *wblock;

	if (add_uevent_var(env, "MODALIAS="))
		return -ENOMEM;

	wblock = dev_get_drvdata(dev);
	if (!wblock)
		return -ENOMEM;

	wmi_gtoa(wblock->gblock.guid, guid_string);

	strcpy(&env->buf[env->buflen - 1], "wmi:");
	memcpy(&env->buf[env->buflen - 1 + 4], guid_string, 36);
	env->buflen += 40;

	return 0;
}

static void wmi_dev_free(struct device *dev)
{
	kfree(dev);
}

static struct class wmi_class = {
	.name = "wmi",
	.dev_release = wmi_dev_free,
	.dev_uevent = wmi_dev_uevent,
};

static int wmi_create_devs(void)
{
	int result;
	char guid_string[37];
	struct guid_block *gblock;
	struct wmi_block *wblock;
	struct list_head *p;
	struct device *guid_dev;

	/* Create devices for all the GUIDs */
	list_for_each(p, &wmi_blocks.list) {
		wblock = list_entry(p, struct wmi_block, list);

		guid_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
		if (!guid_dev)
			return -ENOMEM;

		wblock->dev = guid_dev;

		guid_dev->class = &wmi_class;
		dev_set_drvdata(guid_dev, wblock);

		gblock = &wblock->gblock;

		wmi_gtoa(gblock->guid, guid_string);
		dev_set_name(guid_dev, guid_string);

		result = device_register(guid_dev);
		if (result)
			return result;

		result = device_create_file(guid_dev, &dev_attr_modalias);
		if (result)
			return result;
	}

	return 0;
}

static void wmi_remove_devs(void)
{
	struct guid_block *gblock;
	struct wmi_block *wblock;
	struct list_head *p;
	struct device *guid_dev;

	/* Delete devices for all the GUIDs */
	list_for_each(p, &wmi_blocks.list) {
		wblock = list_entry(p, struct wmi_block, list);

		guid_dev = wblock->dev;
		gblock = &wblock->gblock;

		device_remove_file(guid_dev, &dev_attr_modalias);

		device_unregister(guid_dev);
	}
}

static void wmi_class_exit(void)
{
	wmi_remove_devs();
	class_unregister(&wmi_class);
}

static int wmi_class_init(void)
{
	int ret;

	ret = class_register(&wmi_class);
	if (ret)
		return ret;

	ret = wmi_create_devs();
	if (ret)
		wmi_class_exit();

	return ret;
}

/*
 * Parse the _WDG method for the GUID data blocks
 */
@@ -709,10 +871,17 @@ static int __init acpi_wmi_init(void)

	if (result < 0) {
		printk(KERN_INFO PREFIX "Error loading mapper\n");
	} else {
		printk(KERN_INFO PREFIX "Mapper loaded\n");
		return -ENODEV;
	}

	result = wmi_class_init();
	if (result) {
		acpi_bus_unregister_driver(&acpi_wmi_driver);
		return result;
	}

	printk(KERN_INFO PREFIX "Mapper loaded\n");

	return result;
}

@@ -721,6 +890,8 @@ static void __exit acpi_wmi_exit(void)
	struct list_head *p, *tmp;
	struct wmi_block *wblock;

	wmi_class_exit();

	acpi_bus_unregister_driver(&acpi_wmi_driver);

	list_for_each_safe(p, tmp, &wmi_blocks.list) {