brintos

brintos / linux-shallow public Read only

0
0
Text · 33.1 KiB · 3cbe180 Raw
1348 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  ACPI-WMI mapping driver4 *5 *  Copyright (C) 2007-2008 Carlos Corbacho <carlos@strangeworlds.co.uk>6 *7 *  GUID parsing code from ldm.c is:8 *   Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>9 *   Copyright (c) 2001-2007 Anton Altaparmakov10 *   Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>11 *12 *  WMI bus infrastructure by Andrew Lutomirski and Darren Hart:13 *    Copyright (C) 2015 Andrew Lutomirski14 *    Copyright (C) 2017 VMware, Inc. All Rights Reserved.15 */16 17#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt18 19#include <linux/acpi.h>20#include <linux/bits.h>21#include <linux/build_bug.h>22#include <linux/device.h>23#include <linux/init.h>24#include <linux/kernel.h>25#include <linux/list.h>26#include <linux/module.h>27#include <linux/platform_device.h>28#include <linux/rwsem.h>29#include <linux/slab.h>30#include <linux/sysfs.h>31#include <linux/types.h>32#include <linux/uuid.h>33#include <linux/wmi.h>34#include <linux/fs.h>35 36MODULE_AUTHOR("Carlos Corbacho");37MODULE_DESCRIPTION("ACPI-WMI Mapping Driver");38MODULE_LICENSE("GPL");39 40static LIST_HEAD(wmi_block_list);41 42struct guid_block {43	guid_t guid;44	union {45		char object_id[2];46		struct {47			unsigned char notify_id;48			unsigned char reserved;49		};50	};51	u8 instance_count;52	u8 flags;53} __packed;54static_assert(sizeof(typeof_member(struct guid_block, guid)) == 16);55static_assert(sizeof(struct guid_block) == 20);56static_assert(__alignof__(struct guid_block) == 1);57 58enum {	/* wmi_block flags */59	WMI_READ_TAKES_NO_ARGS,60	WMI_GUID_DUPLICATED,61	WMI_NO_EVENT_DATA,62};63 64struct wmi_block {65	struct wmi_device dev;66	struct list_head list;67	struct guid_block gblock;68	struct acpi_device *acpi_device;69	struct rw_semaphore notify_lock;	/* Protects notify callback add/remove */70	wmi_notify_handler handler;71	void *handler_data;72	bool driver_ready;73	unsigned long flags;74};75 76 77/*78 * If the GUID data block is marked as expensive, we must enable and79 * explicitily disable data collection.80 */81#define ACPI_WMI_EXPENSIVE   BIT(0)82#define ACPI_WMI_METHOD      BIT(1)	/* GUID is a method */83#define ACPI_WMI_STRING      BIT(2)	/* GUID takes & returns a string */84#define ACPI_WMI_EVENT       BIT(3)	/* GUID is an event */85 86static const struct acpi_device_id wmi_device_ids[] = {87	{"PNP0C14", 0},88	{"pnp0c14", 0},89	{ }90};91MODULE_DEVICE_TABLE(acpi, wmi_device_ids);92 93#define dev_to_wblock(__dev)	container_of_const(__dev, struct wmi_block, dev.dev)94#define dev_to_wdev(__dev)	container_of_const(__dev, struct wmi_device, dev)95 96/*97 * GUID parsing functions98 */99 100static bool guid_parse_and_compare(const char *string, const guid_t *guid)101{102	guid_t guid_input;103 104	if (guid_parse(string, &guid_input))105		return false;106 107	return guid_equal(&guid_input, guid);108}109 110static const void *find_guid_context(struct wmi_block *wblock,111				     struct wmi_driver *wdriver)112{113	const struct wmi_device_id *id;114 115	id = wdriver->id_table;116	if (!id)117		return NULL;118 119	while (*id->guid_string) {120		if (guid_parse_and_compare(id->guid_string, &wblock->gblock.guid))121			return id->context;122		id++;123	}124	return NULL;125}126 127static acpi_status wmi_method_enable(struct wmi_block *wblock, bool enable)128{129	struct guid_block *block;130	char method[5];131	acpi_status status;132	acpi_handle handle;133 134	block = &wblock->gblock;135	handle = wblock->acpi_device->handle;136 137	snprintf(method, 5, "WE%02X", block->notify_id);138	status = acpi_execute_simple_method(handle, method, enable);139	if (status == AE_NOT_FOUND)140		return AE_OK;141 142	return status;143}144 145#define WMI_ACPI_METHOD_NAME_SIZE 5146 147static inline void get_acpi_method_name(const struct wmi_block *wblock,148					const char method,149					char buffer[static WMI_ACPI_METHOD_NAME_SIZE])150{151	static_assert(ARRAY_SIZE(wblock->gblock.object_id) == 2);152	static_assert(WMI_ACPI_METHOD_NAME_SIZE >= 5);153 154	buffer[0] = 'W';155	buffer[1] = method;156	buffer[2] = wblock->gblock.object_id[0];157	buffer[3] = wblock->gblock.object_id[1];158	buffer[4] = '\0';159}160 161static inline acpi_object_type get_param_acpi_type(const struct wmi_block *wblock)162{163	if (wblock->gblock.flags & ACPI_WMI_STRING)164		return ACPI_TYPE_STRING;165	else166		return ACPI_TYPE_BUFFER;167}168 169static int wmidev_match_guid(struct device *dev, const void *data)170{171	struct wmi_block *wblock = dev_to_wblock(dev);172	const guid_t *guid = data;173 174	/* Legacy GUID-based functions are restricted to only see175	 * a single WMI device for each GUID.176	 */177	if (test_bit(WMI_GUID_DUPLICATED, &wblock->flags))178		return 0;179 180	if (guid_equal(guid, &wblock->gblock.guid))181		return 1;182 183	return 0;184}185 186static const struct bus_type wmi_bus_type;187 188static struct wmi_device *wmi_find_device_by_guid(const char *guid_string)189{190	struct device *dev;191	guid_t guid;192	int ret;193 194	ret = guid_parse(guid_string, &guid);195	if (ret < 0)196		return ERR_PTR(ret);197 198	dev = bus_find_device(&wmi_bus_type, NULL, &guid, wmidev_match_guid);199	if (!dev)200		return ERR_PTR(-ENODEV);201 202	return dev_to_wdev(dev);203}204 205static void wmi_device_put(struct wmi_device *wdev)206{207	put_device(&wdev->dev);208}209 210/*211 * Exported WMI functions212 */213 214/**215 * wmi_instance_count - Get number of WMI object instances216 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba217 *218 * Get the number of WMI object instances.219 *220 * Returns: Number of WMI object instances or negative error code.221 */222int wmi_instance_count(const char *guid_string)223{224	struct wmi_device *wdev;225	int ret;226 227	wdev = wmi_find_device_by_guid(guid_string);228	if (IS_ERR(wdev))229		return PTR_ERR(wdev);230 231	ret = wmidev_instance_count(wdev);232	wmi_device_put(wdev);233 234	return ret;235}236EXPORT_SYMBOL_GPL(wmi_instance_count);237 238/**239 * wmidev_instance_count - Get number of WMI object instances240 * @wdev: A wmi bus device from a driver241 *242 * Get the number of WMI object instances.243 *244 * Returns: Number of WMI object instances.245 */246u8 wmidev_instance_count(struct wmi_device *wdev)247{248	struct wmi_block *wblock = container_of(wdev, struct wmi_block, dev);249 250	return wblock->gblock.instance_count;251}252EXPORT_SYMBOL_GPL(wmidev_instance_count);253 254/**255 * wmi_evaluate_method - Evaluate a WMI method (deprecated)256 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba257 * @instance: Instance index258 * @method_id: Method ID to call259 * @in: Mandatory buffer containing input for the method call260 * @out: Empty buffer to return the method results261 *262 * Call an ACPI-WMI method, the caller must free @out.263 *264 * Return: acpi_status signaling success or error.265 */266acpi_status wmi_evaluate_method(const char *guid_string, u8 instance, u32 method_id,267				const struct acpi_buffer *in, struct acpi_buffer *out)268{269	struct wmi_device *wdev;270	acpi_status status;271 272	wdev = wmi_find_device_by_guid(guid_string);273	if (IS_ERR(wdev))274		return AE_ERROR;275 276	status = wmidev_evaluate_method(wdev, instance, method_id, in, out);277 278	wmi_device_put(wdev);279 280	return status;281}282EXPORT_SYMBOL_GPL(wmi_evaluate_method);283 284/**285 * wmidev_evaluate_method - Evaluate a WMI method286 * @wdev: A wmi bus device from a driver287 * @instance: Instance index288 * @method_id: Method ID to call289 * @in: Mandatory buffer containing input for the method call290 * @out: Empty buffer to return the method results291 *292 * Call an ACPI-WMI method, the caller must free @out.293 *294 * Return: acpi_status signaling success or error.295 */296acpi_status wmidev_evaluate_method(struct wmi_device *wdev, u8 instance, u32 method_id,297				   const struct acpi_buffer *in, struct acpi_buffer *out)298{299	struct guid_block *block;300	struct wmi_block *wblock;301	acpi_handle handle;302	struct acpi_object_list input;303	union acpi_object params[3];304	char method[WMI_ACPI_METHOD_NAME_SIZE];305 306	wblock = container_of(wdev, struct wmi_block, dev);307	block = &wblock->gblock;308	handle = wblock->acpi_device->handle;309 310	if (!in)311		return AE_BAD_DATA;312 313	if (!(block->flags & ACPI_WMI_METHOD))314		return AE_BAD_DATA;315 316	if (block->instance_count <= instance)317		return AE_BAD_PARAMETER;318 319	input.count = 3;320	input.pointer = params;321 322	params[0].type = ACPI_TYPE_INTEGER;323	params[0].integer.value = instance;324	params[1].type = ACPI_TYPE_INTEGER;325	params[1].integer.value = method_id;326	params[2].type = get_param_acpi_type(wblock);327	params[2].buffer.length = in->length;328	params[2].buffer.pointer = in->pointer;329 330	get_acpi_method_name(wblock, 'M', method);331 332	return acpi_evaluate_object(handle, method, &input, out);333}334EXPORT_SYMBOL_GPL(wmidev_evaluate_method);335 336static acpi_status __query_block(struct wmi_block *wblock, u8 instance,337				 struct acpi_buffer *out)338{339	struct guid_block *block;340	acpi_handle handle;341	acpi_status status, wc_status = AE_ERROR;342	struct acpi_object_list input;343	union acpi_object wq_params[1];344	char wc_method[WMI_ACPI_METHOD_NAME_SIZE];345	char method[WMI_ACPI_METHOD_NAME_SIZE];346 347	if (!out)348		return AE_BAD_PARAMETER;349 350	block = &wblock->gblock;351	handle = wblock->acpi_device->handle;352 353	if (block->instance_count <= instance)354		return AE_BAD_PARAMETER;355 356	/* Check GUID is a data block */357	if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))358		return AE_ERROR;359 360	input.count = 1;361	input.pointer = wq_params;362	wq_params[0].type = ACPI_TYPE_INTEGER;363	wq_params[0].integer.value = instance;364 365	if (instance == 0 && test_bit(WMI_READ_TAKES_NO_ARGS, &wblock->flags))366		input.count = 0;367 368	/*369	 * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to370	 * enable collection.371	 */372	if (block->flags & ACPI_WMI_EXPENSIVE) {373		get_acpi_method_name(wblock, 'C', wc_method);374 375		/*376		 * Some GUIDs break the specification by declaring themselves377		 * expensive, but have no corresponding WCxx method. So we378		 * should not fail if this happens.379		 */380		wc_status = acpi_execute_simple_method(handle, wc_method, 1);381	}382 383	get_acpi_method_name(wblock, 'Q', method);384	status = acpi_evaluate_object(handle, method, &input, out);385 386	/*387	 * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if388	 * the WQxx method failed - we should disable collection anyway.389	 */390	if ((block->flags & ACPI_WMI_EXPENSIVE) && ACPI_SUCCESS(wc_status)) {391		/*392		 * Ignore whether this WCxx call succeeds or not since393		 * the previously executed WQxx method call might have394		 * succeeded, and returning the failing status code395		 * of this call would throw away the result of the WQxx396		 * call, potentially leaking memory.397		 */398		acpi_execute_simple_method(handle, wc_method, 0);399	}400 401	return status;402}403 404/**405 * wmi_query_block - Return contents of a WMI block (deprecated)406 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba407 * @instance: Instance index408 * @out: Empty buffer to return the contents of the data block to409 *410 * Query a ACPI-WMI block, the caller must free @out.411 *412 * Return: ACPI object containing the content of the WMI block.413 */414acpi_status wmi_query_block(const char *guid_string, u8 instance,415			    struct acpi_buffer *out)416{417	struct wmi_block *wblock;418	struct wmi_device *wdev;419	acpi_status status;420 421	wdev = wmi_find_device_by_guid(guid_string);422	if (IS_ERR(wdev))423		return AE_ERROR;424 425	wblock = container_of(wdev, struct wmi_block, dev);426	status = __query_block(wblock, instance, out);427 428	wmi_device_put(wdev);429 430	return status;431}432EXPORT_SYMBOL_GPL(wmi_query_block);433 434/**435 * wmidev_block_query - Return contents of a WMI block436 * @wdev: A wmi bus device from a driver437 * @instance: Instance index438 *439 * Query an ACPI-WMI block, the caller must free the result.440 *441 * Return: ACPI object containing the content of the WMI block.442 */443union acpi_object *wmidev_block_query(struct wmi_device *wdev, u8 instance)444{445	struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };446	struct wmi_block *wblock = container_of(wdev, struct wmi_block, dev);447 448	if (ACPI_FAILURE(__query_block(wblock, instance, &out)))449		return NULL;450 451	return out.pointer;452}453EXPORT_SYMBOL_GPL(wmidev_block_query);454 455/**456 * wmi_set_block - Write to a WMI block (deprecated)457 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba458 * @instance: Instance index459 * @in: Buffer containing new values for the data block460 *461 * Write the contents of the input buffer to an ACPI-WMI data block.462 *463 * Return: acpi_status signaling success or error.464 */465acpi_status wmi_set_block(const char *guid_string, u8 instance, const struct acpi_buffer *in)466{467	struct wmi_device *wdev;468	acpi_status status;469 470	wdev = wmi_find_device_by_guid(guid_string);471	if (IS_ERR(wdev))472		return AE_ERROR;473 474	status =  wmidev_block_set(wdev, instance, in);475	wmi_device_put(wdev);476 477	return status;478}479EXPORT_SYMBOL_GPL(wmi_set_block);480 481/**482 * wmidev_block_set - Write to a WMI block483 * @wdev: A wmi bus device from a driver484 * @instance: Instance index485 * @in: Buffer containing new values for the data block486 *487 * Write contents of the input buffer to an ACPI-WMI data block.488 *489 * Return: acpi_status signaling success or error.490 */491acpi_status wmidev_block_set(struct wmi_device *wdev, u8 instance, const struct acpi_buffer *in)492{493	struct wmi_block *wblock = container_of(wdev, struct wmi_block, dev);494	acpi_handle handle = wblock->acpi_device->handle;495	struct guid_block *block = &wblock->gblock;496	char method[WMI_ACPI_METHOD_NAME_SIZE];497	struct acpi_object_list input;498	union acpi_object params[2];499 500	if (!in)501		return AE_BAD_DATA;502 503	if (block->instance_count <= instance)504		return AE_BAD_PARAMETER;505 506	/* Check GUID is a data block */507	if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))508		return AE_ERROR;509 510	input.count = 2;511	input.pointer = params;512	params[0].type = ACPI_TYPE_INTEGER;513	params[0].integer.value = instance;514	params[1].type = get_param_acpi_type(wblock);515	params[1].buffer.length = in->length;516	params[1].buffer.pointer = in->pointer;517 518	get_acpi_method_name(wblock, 'S', method);519 520	return acpi_evaluate_object(handle, method, &input, NULL);521}522EXPORT_SYMBOL_GPL(wmidev_block_set);523 524/**525 * wmi_install_notify_handler - Register handler for WMI events (deprecated)526 * @guid: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba527 * @handler: Function to handle notifications528 * @data: Data to be returned to handler when event is fired529 *530 * Register a handler for events sent to the ACPI-WMI mapper device.531 *532 * Return: acpi_status signaling success or error.533 */534acpi_status wmi_install_notify_handler(const char *guid,535				       wmi_notify_handler handler,536				       void *data)537{538	struct wmi_block *wblock;539	struct wmi_device *wdev;540	acpi_status status;541 542	wdev = wmi_find_device_by_guid(guid);543	if (IS_ERR(wdev))544		return AE_ERROR;545 546	wblock = container_of(wdev, struct wmi_block, dev);547 548	down_write(&wblock->notify_lock);549	if (wblock->handler) {550		status = AE_ALREADY_ACQUIRED;551	} else {552		wblock->handler = handler;553		wblock->handler_data = data;554 555		if (ACPI_FAILURE(wmi_method_enable(wblock, true)))556			dev_warn(&wblock->dev.dev, "Failed to enable device\n");557 558		status = AE_OK;559	}560	up_write(&wblock->notify_lock);561 562	wmi_device_put(wdev);563 564	return status;565}566EXPORT_SYMBOL_GPL(wmi_install_notify_handler);567 568/**569 * wmi_remove_notify_handler - Unregister handler for WMI events (deprecated)570 * @guid: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba571 *572 * Unregister handler for events sent to the ACPI-WMI mapper device.573 *574 * Return: acpi_status signaling success or error.575 */576acpi_status wmi_remove_notify_handler(const char *guid)577{578	struct wmi_block *wblock;579	struct wmi_device *wdev;580	acpi_status status;581 582	wdev = wmi_find_device_by_guid(guid);583	if (IS_ERR(wdev))584		return AE_ERROR;585 586	wblock = container_of(wdev, struct wmi_block, dev);587 588	down_write(&wblock->notify_lock);589	if (!wblock->handler) {590		status = AE_NULL_ENTRY;591	} else {592		if (ACPI_FAILURE(wmi_method_enable(wblock, false)))593			dev_warn(&wblock->dev.dev, "Failed to disable device\n");594 595		wblock->handler = NULL;596		wblock->handler_data = NULL;597 598		status = AE_OK;599	}600	up_write(&wblock->notify_lock);601 602	wmi_device_put(wdev);603 604	return status;605}606EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);607 608/**609 * wmi_has_guid - Check if a GUID is available610 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba611 *612 * Check if a given GUID is defined by _WDG.613 *614 * Return: True if GUID is available, false otherwise.615 */616bool wmi_has_guid(const char *guid_string)617{618	struct wmi_device *wdev;619 620	wdev = wmi_find_device_by_guid(guid_string);621	if (IS_ERR(wdev))622		return false;623 624	wmi_device_put(wdev);625 626	return true;627}628EXPORT_SYMBOL_GPL(wmi_has_guid);629 630/**631 * wmi_get_acpi_device_uid() - Get _UID name of ACPI device that defines GUID (deprecated)632 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba633 *634 * Find the _UID of ACPI device associated with this WMI GUID.635 *636 * Return: The ACPI _UID field value or NULL if the WMI GUID was not found.637 */638char *wmi_get_acpi_device_uid(const char *guid_string)639{640	struct wmi_block *wblock;641	struct wmi_device *wdev;642	char *uid;643 644	wdev = wmi_find_device_by_guid(guid_string);645	if (IS_ERR(wdev))646		return NULL;647 648	wblock = container_of(wdev, struct wmi_block, dev);649	uid = acpi_device_uid(wblock->acpi_device);650 651	wmi_device_put(wdev);652 653	return uid;654}655EXPORT_SYMBOL_GPL(wmi_get_acpi_device_uid);656 657#define drv_to_wdrv(__drv)	container_of_const(__drv, struct wmi_driver, driver)658 659/*660 * sysfs interface661 */662static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,663			     char *buf)664{665	struct wmi_block *wblock = dev_to_wblock(dev);666 667	return sysfs_emit(buf, "wmi:%pUL\n", &wblock->gblock.guid);668}669static DEVICE_ATTR_RO(modalias);670 671static ssize_t guid_show(struct device *dev, struct device_attribute *attr,672			 char *buf)673{674	struct wmi_block *wblock = dev_to_wblock(dev);675 676	return sysfs_emit(buf, "%pUL\n", &wblock->gblock.guid);677}678static DEVICE_ATTR_RO(guid);679 680static ssize_t instance_count_show(struct device *dev,681				   struct device_attribute *attr, char *buf)682{683	struct wmi_block *wblock = dev_to_wblock(dev);684 685	return sysfs_emit(buf, "%d\n", (int)wblock->gblock.instance_count);686}687static DEVICE_ATTR_RO(instance_count);688 689static ssize_t expensive_show(struct device *dev,690			      struct device_attribute *attr, char *buf)691{692	struct wmi_block *wblock = dev_to_wblock(dev);693 694	return sysfs_emit(buf, "%d\n",695			  (wblock->gblock.flags & ACPI_WMI_EXPENSIVE) != 0);696}697static DEVICE_ATTR_RO(expensive);698 699static ssize_t driver_override_show(struct device *dev, struct device_attribute *attr,700				    char *buf)701{702	struct wmi_device *wdev = to_wmi_device(dev);703	ssize_t ret;704 705	device_lock(dev);706	ret = sysfs_emit(buf, "%s\n", wdev->driver_override);707	device_unlock(dev);708 709	return ret;710}711 712static ssize_t driver_override_store(struct device *dev, struct device_attribute *attr,713				     const char *buf, size_t count)714{715	struct wmi_device *wdev = to_wmi_device(dev);716	int ret;717 718	ret = driver_set_override(dev, &wdev->driver_override, buf, count);719	if (ret < 0)720		return ret;721 722	return count;723}724static DEVICE_ATTR_RW(driver_override);725 726static struct attribute *wmi_attrs[] = {727	&dev_attr_modalias.attr,728	&dev_attr_guid.attr,729	&dev_attr_instance_count.attr,730	&dev_attr_expensive.attr,731	&dev_attr_driver_override.attr,732	NULL733};734ATTRIBUTE_GROUPS(wmi);735 736static ssize_t notify_id_show(struct device *dev, struct device_attribute *attr,737			      char *buf)738{739	struct wmi_block *wblock = dev_to_wblock(dev);740 741	return sysfs_emit(buf, "%02X\n", (unsigned int)wblock->gblock.notify_id);742}743static DEVICE_ATTR_RO(notify_id);744 745static struct attribute *wmi_event_attrs[] = {746	&dev_attr_notify_id.attr,747	NULL748};749ATTRIBUTE_GROUPS(wmi_event);750 751static ssize_t object_id_show(struct device *dev, struct device_attribute *attr,752			      char *buf)753{754	struct wmi_block *wblock = dev_to_wblock(dev);755 756	return sysfs_emit(buf, "%c%c\n", wblock->gblock.object_id[0],757			  wblock->gblock.object_id[1]);758}759static DEVICE_ATTR_RO(object_id);760 761static ssize_t setable_show(struct device *dev, struct device_attribute *attr,762			    char *buf)763{764	struct wmi_device *wdev = dev_to_wdev(dev);765 766	return sysfs_emit(buf, "%d\n", (int)wdev->setable);767}768static DEVICE_ATTR_RO(setable);769 770static struct attribute *wmi_data_attrs[] = {771	&dev_attr_object_id.attr,772	&dev_attr_setable.attr,773	NULL774};775ATTRIBUTE_GROUPS(wmi_data);776 777static struct attribute *wmi_method_attrs[] = {778	&dev_attr_object_id.attr,779	NULL780};781ATTRIBUTE_GROUPS(wmi_method);782 783static int wmi_dev_uevent(const struct device *dev, struct kobj_uevent_env *env)784{785	const struct wmi_block *wblock = dev_to_wblock(dev);786 787	if (add_uevent_var(env, "MODALIAS=wmi:%pUL", &wblock->gblock.guid))788		return -ENOMEM;789 790	if (add_uevent_var(env, "WMI_GUID=%pUL", &wblock->gblock.guid))791		return -ENOMEM;792 793	return 0;794}795 796static void wmi_dev_release(struct device *dev)797{798	struct wmi_block *wblock = dev_to_wblock(dev);799 800	kfree(wblock->dev.driver_override);801	kfree(wblock);802}803 804static int wmi_dev_match(struct device *dev, const struct device_driver *driver)805{806	const struct wmi_driver *wmi_driver = drv_to_wdrv(driver);807	struct wmi_block *wblock = dev_to_wblock(dev);808	const struct wmi_device_id *id = wmi_driver->id_table;809 810	/* When driver_override is set, only bind to the matching driver */811	if (wblock->dev.driver_override)812		return !strcmp(wblock->dev.driver_override, driver->name);813 814	if (id == NULL)815		return 0;816 817	while (*id->guid_string) {818		if (guid_parse_and_compare(id->guid_string, &wblock->gblock.guid))819			return 1;820 821		id++;822	}823 824	return 0;825}826 827static int wmi_dev_probe(struct device *dev)828{829	struct wmi_block *wblock = dev_to_wblock(dev);830	struct wmi_driver *wdriver = drv_to_wdrv(dev->driver);831	int ret = 0;832 833	/* Some older WMI drivers will break if instantiated multiple times,834	 * so they are blocked from probing WMI devices with a duplicated GUID.835	 *836	 * New WMI drivers should support being instantiated multiple times.837	 */838	if (test_bit(WMI_GUID_DUPLICATED, &wblock->flags) && !wdriver->no_singleton) {839		dev_warn(dev, "Legacy driver %s cannot be instantiated multiple times\n",840			 dev->driver->name);841 842		return -ENODEV;843	}844 845	if (wdriver->notify) {846		if (test_bit(WMI_NO_EVENT_DATA, &wblock->flags) && !wdriver->no_notify_data)847			return -ENODEV;848	}849 850	if (ACPI_FAILURE(wmi_method_enable(wblock, true)))851		dev_warn(dev, "failed to enable device -- probing anyway\n");852 853	if (wdriver->probe) {854		ret = wdriver->probe(dev_to_wdev(dev),855				find_guid_context(wblock, wdriver));856		if (ret) {857			if (ACPI_FAILURE(wmi_method_enable(wblock, false)))858				dev_warn(dev, "Failed to disable device\n");859 860			return ret;861		}862	}863 864	down_write(&wblock->notify_lock);865	wblock->driver_ready = true;866	up_write(&wblock->notify_lock);867 868	return 0;869}870 871static void wmi_dev_remove(struct device *dev)872{873	struct wmi_block *wblock = dev_to_wblock(dev);874	struct wmi_driver *wdriver = drv_to_wdrv(dev->driver);875 876	down_write(&wblock->notify_lock);877	wblock->driver_ready = false;878	up_write(&wblock->notify_lock);879 880	if (wdriver->remove)881		wdriver->remove(dev_to_wdev(dev));882 883	if (ACPI_FAILURE(wmi_method_enable(wblock, false)))884		dev_warn(dev, "failed to disable device\n");885}886 887static struct class wmi_bus_class = {888	.name = "wmi_bus",889};890 891static const struct bus_type wmi_bus_type = {892	.name = "wmi",893	.dev_groups = wmi_groups,894	.match = wmi_dev_match,895	.uevent = wmi_dev_uevent,896	.probe = wmi_dev_probe,897	.remove = wmi_dev_remove,898};899 900static const struct device_type wmi_type_event = {901	.name = "event",902	.groups = wmi_event_groups,903	.release = wmi_dev_release,904};905 906static const struct device_type wmi_type_method = {907	.name = "method",908	.groups = wmi_method_groups,909	.release = wmi_dev_release,910};911 912static const struct device_type wmi_type_data = {913	.name = "data",914	.groups = wmi_data_groups,915	.release = wmi_dev_release,916};917 918/*919 * _WDG is a static list that is only parsed at startup,920 * so it's safe to count entries without extra protection.921 */922static int guid_count(const guid_t *guid)923{924	struct wmi_block *wblock;925	int count = 0;926 927	list_for_each_entry(wblock, &wmi_block_list, list) {928		if (guid_equal(&wblock->gblock.guid, guid))929			count++;930	}931 932	return count;933}934 935static int wmi_create_device(struct device *wmi_bus_dev,936			     struct wmi_block *wblock,937			     struct acpi_device *device)938{939	char method[WMI_ACPI_METHOD_NAME_SIZE];940	struct acpi_device_info *info;941	acpi_handle method_handle;942	acpi_status status;943	uint count;944 945	if (wblock->gblock.flags & ACPI_WMI_EVENT) {946		wblock->dev.dev.type = &wmi_type_event;947		goto out_init;948	}949 950	if (wblock->gblock.flags & ACPI_WMI_METHOD) {951		get_acpi_method_name(wblock, 'M', method);952		if (!acpi_has_method(device->handle, method)) {953			dev_warn(wmi_bus_dev,954				 FW_BUG "%s method block execution control method not found\n",955				 method);956 957			return -ENXIO;958		}959 960		wblock->dev.dev.type = &wmi_type_method;961		goto out_init;962	}963 964	/*965	 * Data Block Query Control Method (WQxx by convention) is966	 * required per the WMI documentation. If it is not present,967	 * we ignore this data block.968	 */969	get_acpi_method_name(wblock, 'Q', method);970	status = acpi_get_handle(device->handle, method, &method_handle);971	if (ACPI_FAILURE(status)) {972		dev_warn(wmi_bus_dev,973			 FW_BUG "%s data block query control method not found\n",974			 method);975 976		return -ENXIO;977	}978 979	status = acpi_get_object_info(method_handle, &info);980	if (ACPI_FAILURE(status))981		return -EIO;982 983	wblock->dev.dev.type = &wmi_type_data;984 985	/*986	 * The Microsoft documentation specifically states:987	 *988	 *   Data blocks registered with only a single instance989	 *   can ignore the parameter.990	 *991	 * ACPICA will get mad at us if we call the method with the wrong number992	 * of arguments, so check what our method expects.  (On some Dell993	 * laptops, WQxx may not be a method at all.)994	 */995	if (info->type != ACPI_TYPE_METHOD || info->param_count == 0)996		set_bit(WMI_READ_TAKES_NO_ARGS, &wblock->flags);997 998	kfree(info);999 1000	get_acpi_method_name(wblock, 'S', method);1001	if (acpi_has_method(device->handle, method))1002		wblock->dev.setable = true;1003 1004 out_init:1005	init_rwsem(&wblock->notify_lock);1006	wblock->driver_ready = false;1007	wblock->dev.dev.bus = &wmi_bus_type;1008	wblock->dev.dev.parent = wmi_bus_dev;1009 1010	count = guid_count(&wblock->gblock.guid);1011	if (count) {1012		dev_set_name(&wblock->dev.dev, "%pUL-%d", &wblock->gblock.guid, count);1013		set_bit(WMI_GUID_DUPLICATED, &wblock->flags);1014	} else {1015		dev_set_name(&wblock->dev.dev, "%pUL", &wblock->gblock.guid);1016	}1017 1018	device_initialize(&wblock->dev.dev);1019 1020	return 0;1021}1022 1023static int wmi_add_device(struct platform_device *pdev, struct wmi_device *wdev)1024{1025	struct device_link *link;1026 1027	/*1028	 * Many aggregate WMI drivers do not use -EPROBE_DEFER when they1029	 * are unable to find a WMI device during probe, instead they require1030	 * all WMI devices associated with an platform device to become available1031	 * at once. This device link thus prevents WMI drivers from probing until1032	 * the associated platform device has finished probing (and has registered1033	 * all discovered WMI devices).1034	 */1035 1036	link = device_link_add(&wdev->dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER);1037	if (!link)1038		return -EINVAL;1039 1040	return device_add(&wdev->dev);1041}1042 1043/*1044 * Parse the _WDG method for the GUID data blocks1045 */1046static int parse_wdg(struct device *wmi_bus_dev, struct platform_device *pdev)1047{1048	struct acpi_device *device = ACPI_COMPANION(&pdev->dev);1049	struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};1050	const struct guid_block *gblock;1051	bool event_data_available;1052	struct wmi_block *wblock;1053	union acpi_object *obj;1054	acpi_status status;1055	u32 i, total;1056	int retval;1057 1058	status = acpi_evaluate_object(device->handle, "_WDG", NULL, &out);1059	if (ACPI_FAILURE(status))1060		return -ENXIO;1061 1062	obj = out.pointer;1063	if (!obj)1064		return -ENXIO;1065 1066	if (obj->type != ACPI_TYPE_BUFFER) {1067		kfree(obj);1068		return -ENXIO;1069	}1070 1071	event_data_available = acpi_has_method(device->handle, "_WED");1072	gblock = (const struct guid_block *)obj->buffer.pointer;1073	total = obj->buffer.length / sizeof(struct guid_block);1074 1075	for (i = 0; i < total; i++) {1076		if (!gblock[i].instance_count) {1077			dev_info(wmi_bus_dev, FW_INFO "%pUL has zero instances\n", &gblock[i].guid);1078			continue;1079		}1080 1081		wblock = kzalloc(sizeof(*wblock), GFP_KERNEL);1082		if (!wblock)1083			continue;1084 1085		wblock->acpi_device = device;1086		wblock->gblock = gblock[i];1087		if (gblock[i].flags & ACPI_WMI_EVENT && !event_data_available)1088			set_bit(WMI_NO_EVENT_DATA, &wblock->flags);1089 1090		retval = wmi_create_device(wmi_bus_dev, wblock, device);1091		if (retval) {1092			kfree(wblock);1093			continue;1094		}1095 1096		list_add_tail(&wblock->list, &wmi_block_list);1097 1098		retval = wmi_add_device(pdev, &wblock->dev);1099		if (retval) {1100			dev_err(wmi_bus_dev, "failed to register %pUL\n",1101				&wblock->gblock.guid);1102 1103			list_del(&wblock->list);1104			put_device(&wblock->dev.dev);1105		}1106	}1107 1108	kfree(obj);1109 1110	return 0;1111}1112 1113static int wmi_get_notify_data(struct wmi_block *wblock, union acpi_object **obj)1114{1115	struct acpi_buffer data = { ACPI_ALLOCATE_BUFFER, NULL };1116	union acpi_object param = {1117		.integer = {1118			.type = ACPI_TYPE_INTEGER,1119			.value = wblock->gblock.notify_id,1120		}1121	};1122	struct acpi_object_list input = {1123		.count = 1,1124		.pointer = &param,1125	};1126	acpi_status status;1127 1128	status = acpi_evaluate_object(wblock->acpi_device->handle, "_WED", &input, &data);1129	if (ACPI_FAILURE(status)) {1130		dev_warn(&wblock->dev.dev, "Failed to get event data\n");1131		return -EIO;1132	}1133 1134	*obj = data.pointer;1135 1136	return 0;1137}1138 1139static void wmi_notify_driver(struct wmi_block *wblock, union acpi_object *obj)1140{1141	struct wmi_driver *driver = drv_to_wdrv(wblock->dev.dev.driver);1142 1143	if (!obj && !driver->no_notify_data) {1144		dev_warn(&wblock->dev.dev, "Event contains no event data\n");1145		return;1146	}1147 1148	if (driver->notify)1149		driver->notify(&wblock->dev, obj);1150}1151 1152static int wmi_notify_device(struct device *dev, void *data)1153{1154	struct wmi_block *wblock = dev_to_wblock(dev);1155	union acpi_object *obj = NULL;1156	u32 *event = data;1157	int ret;1158 1159	if (!(wblock->gblock.flags & ACPI_WMI_EVENT && wblock->gblock.notify_id == *event))1160		return 0;1161 1162	/* The ACPI WMI specification says that _WED should be1163	 * evaluated every time an notification is received, even1164	 * if no consumers are present.1165	 *1166	 * Some firmware implementations actually depend on this1167	 * by using a queue for events which will fill up if the1168	 * WMI driver core stops evaluating _WED due to missing1169	 * WMI event consumers.1170	 */1171	if (!test_bit(WMI_NO_EVENT_DATA, &wblock->flags)) {1172		ret = wmi_get_notify_data(wblock, &obj);1173		if (ret < 0)1174			return -EIO;1175	}1176 1177	down_read(&wblock->notify_lock);1178 1179	if (wblock->dev.dev.driver && wblock->driver_ready)1180		wmi_notify_driver(wblock, obj);1181 1182	if (wblock->handler)1183		wblock->handler(obj, wblock->handler_data);1184 1185	up_read(&wblock->notify_lock);1186 1187	kfree(obj);1188 1189	acpi_bus_generate_netlink_event("wmi", acpi_dev_name(wblock->acpi_device), *event, 0);1190 1191	return -EBUSY;1192}1193 1194static void acpi_wmi_notify_handler(acpi_handle handle, u32 event, void *context)1195{1196	struct device *wmi_bus_dev = context;1197 1198	device_for_each_child(wmi_bus_dev, &event, wmi_notify_device);1199}1200 1201static int wmi_remove_device(struct device *dev, void *data)1202{1203	struct wmi_block *wblock = dev_to_wblock(dev);1204 1205	list_del(&wblock->list);1206	device_unregister(dev);1207 1208	return 0;1209}1210 1211static void acpi_wmi_remove(struct platform_device *device)1212{1213	struct device *wmi_bus_device = dev_get_drvdata(&device->dev);1214 1215	device_for_each_child_reverse(wmi_bus_device, NULL, wmi_remove_device);1216}1217 1218static void acpi_wmi_remove_notify_handler(void *data)1219{1220	struct acpi_device *acpi_device = data;1221 1222	acpi_remove_notify_handler(acpi_device->handle, ACPI_ALL_NOTIFY, acpi_wmi_notify_handler);1223}1224 1225static void acpi_wmi_remove_bus_device(void *data)1226{1227	struct device *wmi_bus_dev = data;1228 1229	device_unregister(wmi_bus_dev);1230}1231 1232static int acpi_wmi_probe(struct platform_device *device)1233{1234	struct acpi_device *acpi_device;1235	struct device *wmi_bus_dev;1236	acpi_status status;1237	int error;1238 1239	acpi_device = ACPI_COMPANION(&device->dev);1240	if (!acpi_device) {1241		dev_err(&device->dev, "ACPI companion is missing\n");1242		return -ENODEV;1243	}1244 1245	wmi_bus_dev = device_create(&wmi_bus_class, &device->dev, MKDEV(0, 0), NULL, "wmi_bus-%s",1246				    dev_name(&device->dev));1247	if (IS_ERR(wmi_bus_dev))1248		return PTR_ERR(wmi_bus_dev);1249 1250	error = devm_add_action_or_reset(&device->dev, acpi_wmi_remove_bus_device, wmi_bus_dev);1251	if (error < 0)1252		return error;1253 1254	dev_set_drvdata(&device->dev, wmi_bus_dev);1255 1256	status = acpi_install_notify_handler(acpi_device->handle, ACPI_ALL_NOTIFY,1257					     acpi_wmi_notify_handler, wmi_bus_dev);1258	if (ACPI_FAILURE(status)) {1259		dev_err(&device->dev, "Error installing notify handler\n");1260		return -ENODEV;1261	}1262	error = devm_add_action_or_reset(&device->dev, acpi_wmi_remove_notify_handler,1263					 acpi_device);1264	if (error < 0)1265		return error;1266 1267	error = parse_wdg(wmi_bus_dev, device);1268	if (error) {1269		dev_err(&device->dev, "Failed to parse _WDG method\n");1270		return error;1271	}1272 1273	return 0;1274}1275 1276int __must_check __wmi_driver_register(struct wmi_driver *driver,1277				       struct module *owner)1278{1279	driver->driver.owner = owner;1280	driver->driver.bus = &wmi_bus_type;1281 1282	return driver_register(&driver->driver);1283}1284EXPORT_SYMBOL(__wmi_driver_register);1285 1286/**1287 * wmi_driver_unregister() - Unregister a WMI driver1288 * @driver: WMI driver to unregister1289 *1290 * Unregisters a WMI driver from the WMI bus.1291 */1292void wmi_driver_unregister(struct wmi_driver *driver)1293{1294	driver_unregister(&driver->driver);1295}1296EXPORT_SYMBOL(wmi_driver_unregister);1297 1298static struct platform_driver acpi_wmi_driver = {1299	.driver = {1300		.name = "acpi-wmi",1301		.acpi_match_table = wmi_device_ids,1302	},1303	.probe = acpi_wmi_probe,1304	.remove_new = acpi_wmi_remove,1305};1306 1307static int __init acpi_wmi_init(void)1308{1309	int error;1310 1311	if (acpi_disabled)1312		return -ENODEV;1313 1314	error = class_register(&wmi_bus_class);1315	if (error)1316		return error;1317 1318	error = bus_register(&wmi_bus_type);1319	if (error)1320		goto err_unreg_class;1321 1322	error = platform_driver_register(&acpi_wmi_driver);1323	if (error) {1324		pr_err("Error loading mapper\n");1325		goto err_unreg_bus;1326	}1327 1328	return 0;1329 1330err_unreg_bus:1331	bus_unregister(&wmi_bus_type);1332 1333err_unreg_class:1334	class_unregister(&wmi_bus_class);1335 1336	return error;1337}1338 1339static void __exit acpi_wmi_exit(void)1340{1341	platform_driver_unregister(&acpi_wmi_driver);1342	bus_unregister(&wmi_bus_type);1343	class_unregister(&wmi_bus_class);1344}1345 1346subsys_initcall_sync(acpi_wmi_init);1347module_exit(acpi_wmi_exit);1348