Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c64eefd4 authored by Dmitry Torokhov's avatar Dmitry Torokhov Committed by Matthew Garrett
Browse files

WMI: embed struct device directly into wmi_block



Instead of creating wmi_blocks and then register corresponding devices
on a separate pass do it all in one shot, since lifetime rules for both
objects are the same. This also takes care of leaking devices when
device_create fails for one of them.

Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
Signed-off-by: default avatarMatthew Garrett <mjg@redhat.com>
parent 614ef432
Loading
Loading
Loading
Loading
+65 −111
Original line number Original line Diff line number Diff line
@@ -68,7 +68,7 @@ struct wmi_block {
	acpi_handle handle;
	acpi_handle handle;
	wmi_notify_handler handler;
	wmi_notify_handler handler;
	void *handler_data;
	void *handler_data;
	struct device *dev;
	struct device dev;
};
};




@@ -693,7 +693,9 @@ static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)


static void wmi_dev_free(struct device *dev)
static void wmi_dev_free(struct device *dev)
{
{
	kfree(dev);
	struct wmi_block *wmi_block = container_of(dev, struct wmi_block, dev);

	kfree(wmi_block);
}
}


static struct class wmi_class = {
static struct class wmi_class = {
@@ -703,104 +705,60 @@ static struct class wmi_class = {
	.dev_attrs = wmi_dev_attrs,
	.dev_attrs = wmi_dev_attrs,
};
};


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

	/* Create devices for all the GUIDs */
	list_for_each(p, &wmi_block_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;
	wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
	if (!wblock) {
		error = -ENOMEM;
		goto err_out;
	}


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


		gblock = &wblock->gblock;
	wblock->dev.class = &wmi_class;


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

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

	return 0;
}


static void wmi_remove_devs(void)
	dev_set_drvdata(&wblock->dev, wblock);
{
	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_block_list) {
		wblock = list_entry(p, struct wmi_block, list);


		guid_dev = wblock->dev;
	error = device_register(&wblock->dev);
		gblock = &wblock->gblock;
	if (error)
		goto err_free;


		device_unregister(guid_dev);
	list_add_tail(&wblock->list, &wmi_block_list);
	}
	return wblock;
}


static void wmi_class_exit(void)
err_free:
{
	kfree(wblock);
	wmi_remove_devs();
err_out:
	class_unregister(&wmi_class);
	return ERR_PTR(error);
}
}


static int wmi_class_init(void)
static void wmi_free_devices(void)
{
{
	int ret;
	struct wmi_block *wblock, *next;

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

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


	return ret;
	/* Delete devices for all the GUIDs */
	list_for_each_entry_safe(wblock, next, &wmi_block_list, list)
		device_unregister(&wblock->dev);
}
}


static bool guid_already_parsed(const char *guid_string)
static bool guid_already_parsed(const char *guid_string)
{
{
	struct guid_block *gblock;
	struct wmi_block *wblock;
	struct wmi_block *wblock;
	struct list_head *p;

	list_for_each(p, &wmi_block_list) {
		wblock = list_entry(p, struct wmi_block, list);
		gblock = &wblock->gblock;


		if (strncmp(gblock->guid, guid_string, 16) == 0)
	list_for_each_entry(wblock, &wmi_block_list, list)
		if (strncmp(wblock->gblock.guid, guid_string, 16) == 0)
			return true;
			return true;
	}
	return false;
}

static void free_wmi_blocks(void)
{
	struct wmi_block *wblock, *next;


	list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
	return false;
		list_del(&wblock->list);
		kfree(wblock);
	}
}
}


/*
/*
@@ -814,19 +772,19 @@ static acpi_status parse_wdg(acpi_handle handle)
	struct wmi_block *wblock;
	struct wmi_block *wblock;
	char guid_string[37];
	char guid_string[37];
	acpi_status status;
	acpi_status status;
	int retval;
	u32 i, total;
	u32 i, total;


	status = acpi_evaluate_object(handle, "_WDG", NULL, &out);
	status = acpi_evaluate_object(handle, "_WDG", NULL, &out);

	if (ACPI_FAILURE(status))
	if (ACPI_FAILURE(status))
		return status;
		return -ENXIO;


	obj = (union acpi_object *) out.pointer;
	obj = (union acpi_object *) out.pointer;
	if (!obj)
	if (!obj)
		return AE_ERROR;
		return -ENXIO;


	if (obj->type != ACPI_TYPE_BUFFER) {
	if (obj->type != ACPI_TYPE_BUFFER) {
		status = AE_ERROR;
		retval = -ENXIO;
		goto out_free_pointer;
		goto out_free_pointer;
	}
	}


@@ -846,31 +804,29 @@ static acpi_status parse_wdg(acpi_handle handle)
			pr_info("Skipping duplicate GUID %s\n", guid_string);
			pr_info("Skipping duplicate GUID %s\n", guid_string);
			continue;
			continue;
		}
		}

		if (debug_dump_wdg)
		if (debug_dump_wdg)
			wmi_dump_wdg(&gblock[i]);
			wmi_dump_wdg(&gblock[i]);


		wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
		wblock = wmi_create_device(&gblock[i], handle);
		if (!wblock) {
		if (IS_ERR(wblock)) {
			status = AE_NO_MEMORY;
			retval = PTR_ERR(wblock);
			goto out_free_pointer;
			wmi_free_devices();
			break;
		}
		}


		wblock->gblock = gblock[i];
		wblock->handle = handle;
		if (debug_event) {
		if (debug_event) {
			wblock->handler = wmi_notify_debug;
			wblock->handler = wmi_notify_debug;
			wmi_method_enable(wblock, 1);
			wmi_method_enable(wblock, 1);
		}
		}
		list_add_tail(&wblock->list, &wmi_block_list);
	}
	}


	retval = 0;

out_free_pointer:
out_free_pointer:
	kfree(out.pointer);
	kfree(out.pointer);


	if (ACPI_FAILURE(status))
	return retval;
		free_wmi_blocks();

	return status;
}
}


/*
/*
@@ -949,6 +905,7 @@ static int acpi_wmi_remove(struct acpi_device *device, int type)
{
{
	acpi_remove_address_space_handler(device->handle,
	acpi_remove_address_space_handler(device->handle,
				ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
				ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
	wmi_free_devices();


	return 0;
	return 0;
}
}
@@ -956,7 +913,7 @@ static int acpi_wmi_remove(struct acpi_device *device, int type)
static int acpi_wmi_add(struct acpi_device *device)
static int acpi_wmi_add(struct acpi_device *device)
{
{
	acpi_status status;
	acpi_status status;
	int result = 0;
	int error;


	status = acpi_install_address_space_handler(device->handle,
	status = acpi_install_address_space_handler(device->handle,
						    ACPI_ADR_SPACE_EC,
						    ACPI_ADR_SPACE_EC,
@@ -967,47 +924,44 @@ static int acpi_wmi_add(struct acpi_device *device)
		return -ENODEV;
		return -ENODEV;
	}
	}


	status = parse_wdg(device->handle);
	error = parse_wdg(device->handle);
	if (ACPI_FAILURE(status)) {
	if (error) {
		acpi_remove_address_space_handler(device->handle,
		acpi_remove_address_space_handler(device->handle,
						  ACPI_ADR_SPACE_EC,
						  ACPI_ADR_SPACE_EC,
						  &acpi_wmi_ec_space_handler);
						  &acpi_wmi_ec_space_handler);
		pr_err("Failed to parse WDG method\n");
		pr_err("Failed to parse WDG method\n");
		return -ENODEV;
		return error;
	}
	}


	return result;
	return 0;
}
}


static int __init acpi_wmi_init(void)
static int __init acpi_wmi_init(void)
{
{
	int result;
	int error;


	if (acpi_disabled)
	if (acpi_disabled)
		return -ENODEV;
		return -ENODEV;


	result = acpi_bus_register_driver(&acpi_wmi_driver);
	error = class_register(&wmi_class);
	if (result < 0) {
	if (error)
		pr_err("Error loading mapper\n");
		return error;
		return -ENODEV;
	}


	result = wmi_class_init();
	error = acpi_bus_register_driver(&acpi_wmi_driver);
	if (result) {
	if (error) {
		acpi_bus_unregister_driver(&acpi_wmi_driver);
		pr_err("Error loading mapper\n");
		return result;
		class_unregister(&wmi_class);
		return error;
	}
	}


	pr_info("Mapper loaded\n");
	pr_info("Mapper loaded\n");

	return 0;
	return 0;
}
}


static void __exit acpi_wmi_exit(void)
static void __exit acpi_wmi_exit(void)
{
{
	wmi_class_exit();
	acpi_bus_unregister_driver(&acpi_wmi_driver);
	acpi_bus_unregister_driver(&acpi_wmi_driver);
	free_wmi_blocks();
	class_unregister(&wmi_class);


	pr_info("Mapper unloaded\n");
	pr_info("Mapper unloaded\n");
}
}