WMI patches for acpi-test
Subsystems (2)
cover WMI patches for acpi-test
Len,
Can you please review, and hopefully apply, at least the first two patches in this series, as I would like to get them into acpi-test (then -mm and eventually 2.6.26-rc1).
It's a little late now to put these into 2.6.25-rc1, and I don't want to miss another merge window - so the sooner these are looked at by you, the sooner I can address any concerns and we can have these ready for the 2.6.26-rc1 window.
-Carlos
===
Patch #1: (WMI - driver and in kernel interface) - Minor clean up
Replace leftover occurences of 'x == NULL' with '!x'
Len: For you to review and to be applied to acpi-test.
====
Patch #2: (acer-wmi) - New DMI entry, mail LED detection fix, mismatch fix
* Don't fail if we can't detect a mail LED on AMW0 systems
* Add an EC quirk for the Acer Aspire 9110
* Fix section mismatch warnings
Len: For you to review and to be applied to acpi-test.
====
Patch #3: (tc1100-wmi) - No Change
RFC only, needs actual testing on the hardware, and probably very broken. Waiting on Matthew Garrett to get some free time to test this.
====
Patch #4: (WMI sysfs interface) - No Change
RFC only (see patch #5 for reason and discussion). Adds interface under /sys/devices/virtual/wmi
Also adds a function to return the (virtual) device associated with a GUID for use by other parts of the kernel that want to set a parent device.
Len: To review (but not to apply yet, unless you want to apply patch #5 as well)
====
Patch #5: (WMI sysfs workaround) - No Change
Temporary hack, needed to get patch #4 working, due to a limitation on bus_id length (Kay Sievers is apparently working on this, ref Greg KH[1]).
Len:
Apparently, the necessary fixes _might_ go into 2.6.25 as well, or worst case scenario is 2.6.26[2]. So we can either:
1) Hold off on patch #4 until the necessary fixes go in (this might be 2.6.25 if we're lucky, or we end up putting off WMI sysfs support until 2.6.26)
or
2) Apply patch #4, and #5 on top as a temporary hack, and then revert #5 as soon as the necessary changes go in. (For bisection purposes, #4 and #5 should be merged if we go ahead with this).
I don't know what would be the best solution here.
[1] http://lkml.org/lkml/2007/12/4/30
[2] http://www.nabble.com/Re:-Fix-Firmware-class-name-collision-p14352966.html
---
Carlos Corbacho (5):
[WIP] ACPI: WMI: Limit size of device string to 19 characters [RFC] ACPI: WMI: Add sysfs userspace interface [RFC] tc1100-wmi: Add driver for HP Compaq TC1100 Tablets
acer-wmi: Add driver for newer Acer laptops
ACPI: WMI: Add ACPI-WMI mapping driver
MAINTAINERS | 7 drivers/acpi/Kconfig | 11 drivers/acpi/Makefile | 1 drivers/acpi/wmi.c | 1190 +++++++++++++++++++++++++++++++++++++++++++++ drivers/misc/Kconfig | 25 + drivers/misc/Makefile | 2 drivers/misc/acer-wmi.c | 1109 ++++++++++++++++++++++++++++++++++++++++++ drivers/misc/tc1100-wmi.c | 290 +++++++++++ include/linux/acpi.h | 21 + 9 files changed, 2656 insertions(+), 0 deletions(-) create mode 100644 drivers/acpi/wmi.c create mode 100644 drivers/misc/acer-wmi.c create mode 100644 drivers/misc/tc1100-wmi.c
PATCH 1/5 ACPI: WMI: Add ACPI-WMI mapping driver
The following is an implementation of the Windows Management Instrumentation (WMI) ACPI interface mapper (PNP0C14).
What it does:
Parses the _WDG method and exports functions to process WMI method calls, data block query/ set commands (both based on GUID) and does basic event handling.
How: WMI presents an in kernel interface here (essentially, a minimal wrapper around ACPI)
(const char *guid assume the 36 character ASCII representation of a GUID - e.g. 67C3371D-95A3-4C37-BB61-DD47B491DAAB)
wmi_evaluate_method(const char *guid, u8 instance, u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
wmi_query_block(const char *guid, u8 instance,
struct acpi_buffer *out)
wmi_set_block(const char *guid, u38 instance,
const struct acpi_buffer *in)
wmi_install_notify_handler(acpi_notify_handler handler);
wmi_remove_notify_handler(void);
wmi_get_event_data(u32 event, struct acpi_buffer *out)
wmi_has_guid(const char guid*)
wmi_has_guid() is a helper function to find if a GUID exists or not on the system (a quick and easy way for WMI dependant drivers to see if the the method/ block they want exists, since GUIDs are supposed to be unique).
Event handling - allow a WMI based driver to register a notifier handler for each GUID with WMI. When a notification is sent to a GUID in WMI, the handler registered with WMI is then called (it is left to the caller to ask for the WMI event data associated with the GUID, if needed).
What it won't do:
Unicode - The MS article[1] calls for converting between ASCII and Unicode (or vice versa) if a GUID is marked as "string". This is left up to the calling driver.
Handle a MOF[1] - the WMI mapper just exports methods, data and events to userspace. MOF handling is down to userspace.
Userspace interface - this will be added later.
[1] http://www.microsoft.com/whdc/system/pnppwr/wmi/wmi-acpi.mspx
===
ChangeLog
==
v1 (2007-10-02):
* Initial release
v2 (2007-10-05):
* Cleaned up code - split up super "wmi_evaluate_block" -> each external symbol now handles its own ACPI calls, rather than handing off to a "super" method (and in turn, is a lot simpler to read)
* Added a find_guid() symbol - return true if a given GUID exists on the system
* wmi_* functions now return type acpi_status (since they are just fancy wrappers around acpi_evaluate_object())
* Removed extra debug code
v3 (2007-10-27)
* More code clean up - now passes checkpatch.pl
* Change data block calls - ref MS spec, method ID is not required for them, so drop it from the function parameters.
* Const'ify guid in the function call parameters.
* Fix _WDG buffer handling - copy the data to our own private structure.
* Change WMI from tristate to bool - otherwise the external functions are not exported in linux/acpi.h if you try to build WMI as a module.
* Fix more flag comparisons.
* Add a maintainers entry - since I wrote this, I should take the blame for it.
v4 (2007-10-30)
* Add missing brace from after fixing checkpatch errors.
* Rewrote event handling - allow external drivers to register with WMI to handle WMI events
* Clean up flags and sanitise flag handling
v5 (2007-11-03)
* Add sysfs interface for userspace. Export events over netlink again.
* Remove module left overs, fully convert to built-in driver.
* Tweak in-kernel API to use u8 for instance, since this is what the GUID blocks use (so instance cannot be greater than u8).
* Export wmi_get_event_data() for in kernel WMI drivers.
v6 (2007-11-07)
* Split out userspace into a different patch
v7 (2007-11-20)
* Fix driver to handle multiple PNP0C14 devices - store all GUIDs using the kernel's built in list functions, and just keep adding to the list every time we handle a PNP0C14 devices - GUIDs will always be unique, and WMI callers do not know or care about different devices.
* Change WMI event handler registration to use its' own event handling struct; we should not pass an acpi_handle down to any WMI based drivers
- they should be able to function with only the calls provided in WMI.
* Update my e-mail address
v8 (2007-11-28)
* Convert back to a module.
* Update Kconfig to default to building as a module.
* Remove an erroneous printk.
* Simply comments for string flag (since we now leave the handling to the caller).
v9 (2007-12-07)
* Add back missing MODULE_DEVICE_TABLE for autoloading
* Checkpatch fixes
v10 (2007-12-12)
* Workaround broken GUIDs declared expensive without a WCxx method.
* Minor cleanups
v11 (2007-12-17)
* More fixing for broken GUIDs declared expensive without a WCxx method.
* Add basic EmbeddedControl region handling.
v12 (2007-12-18)
* Changed EC region handling code, as per Alexey's comments.
v13 (2007-12-27)
* Changed event handling so that we can have one event handler registered per GUID, as per Matthew Garrett's suggestion.
v14 (2008-01-12)
* Remove ACPI debug statements
v15 (2008-02-01)
* Replace two remaining 'x == NULL' type tests with '!x'
---
MAINTAINERS | 7 drivers/acpi/Kconfig | 11 + drivers/acpi/Makefile | 1 drivers/acpi/wmi.c | 710 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/acpi.h | 20 + 5 files changed, 749 insertions(+), 0 deletions(-) create mode 100644 drivers/acpi/wmi.c
MAINTAINERS +7 -0
@@ -259,6 +259,13 @@ L: [email protected] W: http://acpi.sourceforge.net/ S: Supported +ACPI WMI DRIVER +P: Carlos Corbacho +M: [email protected] +L: [email protected] +W: http://www.lesswatts.org/projects/acpi/ +S: Supported + ADM1025 HARDWARE MONITOR DRIVER P: Jean Delvare M: [email protected]
drivers/acpi/Kconfig +11 -0
@@ -202,6 +202,17 @@ config ACPI_NUMA depends on (X86 || IA64) default y if IA64_GENERIC || IA64_SGI_SN2 +config ACPI_WMI + tristate "WMI (EXPERIMENTAL)" + depends on EXPERIMENTAL + default m + help + This driver adds support for the ACPI-WMI mapper device (PNP0C14) + found on some systems. + + NOTE: You will need another driver or userspace application on top of + this to actually use anything defined in the ACPI-WMI mapper. + config ACPI_ASUS tristate "ASUS/Medion Laptop Extras" depends on X86
drivers/acpi/Makefile +1 -0
@@ -55,6 +55,7 @@ obj-$(CONFIG_ACPI_THERMAL) += thermal.o obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o obj-$(CONFIG_ACPI_DEBUG) += debug.o obj-$(CONFIG_ACPI_NUMA) += numa.o +obj-$(CONFIG_ACPI_WMI) += wmi.o obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
drivers/acpi/wmi.c new file +710 -0
710 lines not on this page · raw message
include/linux/acpi.h +20 -0
@@ -177,6 +177,26 @@ extern int ec_transaction(u8 command,#endif /*CONFIG_ACPI_EC*/ +#if defined(CONFIG_ACPI_WMI ) || defined(CONFIG_ACPI_WMI_MODULE ) + +typedef void (*wmi_notify_handler ) (u32 value,void *context); + +extern acpi_status wmi_evaluate_method (const char *guid,u8 instance, +u32 method_id, +const struct acpi_buffer *in, +struct acpi_buffer *out); +extern acpi_status wmi_query_block (const char *guid,u8 instance, +struct acpi_buffer *out); +extern acpi_status wmi_set_block (const char *guid,u8 instance, +const struct acpi_buffer *in); +extern acpi_status wmi_install_notify_handler (const char *guid, +wmi_notify_handler handler,void *data); +extern acpi_status wmi_remove_notify_handler (const char *guid); +extern acpi_status wmi_get_event_data (u32 event,struct acpi_buffer *out); +extern bool wmi_has_guid (const char *guid); + +#endif /* CONFIG_ACPI_WMI */ +extern int acpi_blacklisted (void );#ifdef CONFIG_DMI extern void acpi_dmi_osi_linux (int enable,const struct dmi_system_id *d);
PATCH 2/5 acer-wmi: Add driver for newer Acer laptops
In reply to Carlos CorbachoThis is a driver for newer Acer (and Wistron) laptops. It adds wireless radio and bluetooth control, and on some laptops, exposes the mail LED and LCD backlight.
v1:
* Initial release
v2:
* Replace left over ACPI references with WMI
* Add GUID based autoloading (depends on future work to WMI)
* Add DMI based autoloading (backup solution until WMI sysfs/ class work is available)
* Checkpatch fixes
v3:
* Add new EC quirks for Aspire 3100 & 5100, and Extensa 5220
v4:
* Simplified internal handling of WMID and AMW0 devices
* Add autodetection for bluetooth and maximum brightness on AMW0 V2 and WMID laptops.
v5:
* Add EC quirk for Medion MD 98000
* Add autodetection for AMW0, and mail LED on AMW0 and AMW0 V2.
* Improve error handling
* Fix AMW0 V2 bluetooth and wireless, by using both WMID and AMW0 methods to ensure that the correct value is always set.
v6:
* Fix 'use before initialisation' bug with quirks.
v7
* Fix bug on AMW0 where acer-wmi would exit if a mail LED was not detected.
* Add Acer Aspire 9110 mail LED support
* Fix section mismatch warnings
---
drivers/misc/Kconfig | 16 + drivers/misc/Makefile | 1 drivers/misc/acer-wmi.c | 1109 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1126 insertions(+), 0 deletions(-) create mode 100644 drivers/misc/acer-wmi.c
drivers/misc/Kconfig +16 -0
@@ -92,6 +92,22 @@ config TIFM_7XX1 To compile this driver as a module, choose M here: the module will be called tifm_7xx1. +config ACER_WMI + tristate "Acer Laptop WMI-ACPI Extras (EXPERIMENTAL)" + depends on X86 + depends on EXPERIMENTAL + depends on ACPI + depends on ACPI_WMI + depends on LEDS_CLASS + depends on BACKLIGHT_CLASS_DEVICE + ---help--- + This is a driver for newer Acer (and Wistron) laptops. It adds + wireless radio and bluetooth control, and on some laptops, + exposes the mail LED and LCD backlight. + + If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M + here. + config ASUS_LAPTOP tristate "Asus Laptop Extras (EXPERIMENTAL)" depends on X86
drivers/misc/Makefile +1 -0
@@ -6,6 +6,7 @@ obj- := misc.o # Dummy rule to force built-in.o to be made obj-$(CONFIG_IBM_ASM) += ibmasm/ obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o +obj-$(CONFIG_ACER_WMI) += acer-wmi.o obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o obj-$(CONFIG_LKDTM) += lkdtm.o
drivers/misc/acer-wmi.c new file +1109 -0
1,109 lines not on this page · raw message
PATCH 5/5 ACPI: WMI: Limit size of device string to 19 characters
In reply to Carlos CorbachoUntil Kay Sievers bus_id variable length code goes in, this is a temporary workaround.
---
drivers/acpi/wmi.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/acpi/wmi.c +1 -1
@@ -885,7 +885,7 @@ static int wmi_create_devs(void) gblock = &wblock->gblock;wmi_gtoa (gblock->guid, guid_string); -memcpy (guid_dev->bus_id, guid_string,36 ); +memcpy (guid_dev->bus_id, guid_string,19 ); result =device_register (guid_dev);if (result)
RFC PATCH 4/5 ACPI: WMI: Add sysfs userspace interface
In reply to Carlos CorbachoCreate a 'wmi' class, and populate it with a virtual device for each GUID. This also allows us to autoload WMI drivers based on GUID
via MODULE_ALIAS.
Under each GUID are a set of files that can be read and written to from userspace (these will be fully documented in a later patch).
v1 (2007-11-03)
* Initial release
v2 (2007-11-07)
* Split out into a separate patch
v3 (2007-11-20)
* Convert kobject storage to using kernel list structures.
* Change instance handling - store input data on a per instance basis, rather than a per GUID.
* Add locking to methods - method_id (write) and data (read & write) should all be mutually exclusive - we do not want the input data to change when we are trying to execute a method.
* Change method calling semantics: when input is written to 'data', store it, but don't execute the method until 'data' is read. This is due to the fact that it is perfectly acceptable to have a WMI method that does not take any input (and it is easier to trigger an execute on reading the file, and not return anything if there is nothing to return, rather than trying to write values that aren't required, or may cause ACPI evaluation to fail on the method).
* Do not try and convert String's from ASCII to Unicode - instead, only handle ASCII (as per ACPI), and leave it up to userspace to convert to/ from whatever encoding they wish to use.
v4 (2007-11-28)
* Add code to remove sysfs files on module removal
v5 (2007-12-08)
* Convert to a class device, instead of trying to manually create and manipulate kobject's - this allows us to add module autoloading for WMI based drivers, and will (hopefully) be less likely to break with the latest round of kobject changes.
* Convert GUIDs to use a 'flat' structure - add two new files:
instance and instance_count, and use these to provide the instance to call for a given GUID (while still communicating the maximum number of instances available - for now, we will always respect instance_count when setting instance - so any instance > instance_count will be discarded).
v6 (2007-12-12)
* Add string file - this reports back if the GUID has the string flag set.
v8 (2008-010-18)
* Add new in kernel function, wmi_get_device(), to take advantage of the class and virtual devices, and return the virtual device for a GUID.
---
drivers/acpi/wmi.c | 484 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/acpi.h | 1 2 files changed, 483 insertions(+), 2 deletions(-)
drivers/acpi/wmi.c +482 -2
@@ -30,6 +30,8 @@#include <linux/kernel.h> #include <linux/init.h> #include <linux/types.h> +#include <linux/device.h> +#include <linux/mutex.h> #include <linux/list.h> #include <linux/acpi.h> #include <acpi/acpi_bus.h>
@@ -66,6 +68,11 @@ struct wmi_block {acpi_handle handle;wmi_notify_handler handler;void *handler_data; +struct device dev; +u8 instance; +u32 method_id; +void *pointer; +acpi_size length; };static struct wmi_block wmi_blocks;
@@ -194,6 +201,33 @@ 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 ); + +return 0 ; +} +static bool find_guid (const char *guid_string,struct wmi_block **out) {char tmp[16 ], guid_input[16 ];
@@ -516,6 +550,442 @@ bool wmi_has_guid(const char *guid_string) }EXPORT_SYMBOL_GPL (wmi_has_guid); +/** +* wmi_get_device - Get the virtual device associated with a GUID +* @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba +* @dev: Pointer to pointer to the device +* +* Return a pointer to a pointer to virtual device associated with a GUID +*/ +int wmi_get_device (const char *guid_string,struct device **dev) +{ +struct wmi_block *block; +bool ret; + + ret =find_guid (guid_string, &block); +if (!ret) +return -ENODEV ; + + *dev = &block->dev; +return 0 ; +} +EXPORT_SYMBOL_GPL (wmi_get_device); + +/* +* sysfs interface +*/ +static ssize_t wmi_data_read (struct kobject *kobj,struct bin_attribute + *bin_attr,char *buf,loff_t offset,size_t count) { +u8 instance; +const char *guid; +struct acpi_buffer in; +struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER ,NULL }; +acpi_status status; +union acpi_object *obj; +struct wmi_block *block; +struct device *dev; + + dev = container_of(kobj, struct device, kobj); +if (!dev) +return -ENODEV ; + + block = container_of(dev, struct wmi_block, dev); +if (!block) +return -EINVAL ; + + guid = block->gblock.guid; +if (!guid) +return -EINVAL ; + + instance = block->instance; + +if (block->gblock.flags &ACPI_WMI_METHOD ) { +mutex_lock (&wmi_data_lock); +if (block->pointer) { + in.pointer = block->pointer; + in.length = block->length; + status =wmi_evaluate_method (guid, instance, + block->method_id, &in, &out); + }else { + status =wmi_evaluate_method (guid, instance, + block->method_id,NULL , &out); + } +mutex_unlock (&wmi_data_lock); + }else { + status =wmi_query_block (guid, instance, &out); + } + + obj = (union acpi_object *) out.pointer; + +switch (obj->type) { +case (ACPI_TYPE_STRING ): +case (ACPI_TYPE_BUFFER ): + buf = obj->buffer.pointer; +break ; +default : +return -EIO ; + } + +return 0 ; +} + +static ssize_t wmi_data_write (struct kobject *kobj,struct bin_attribute + *bin_attr,char *buf,loff_t offset,size_t count){ +struct wmi_block *block; +struct acpi_buffer in; +acpi_status status; +struct device *dev; +char guid_string[37 ]; + + dev = container_of(kobj, struct device, kobj); +if (!dev) +return -ENODEV ; + + block = container_of(dev, struct wmi_block, dev); +if (!block) +return -EINVAL ; + +if (count ==0 ) +return count; + +if (block->gblock.flags &ACPI_WMI_METHOD ) { + block->pointer =kzalloc (count,GFP_KERNEL ); +if (!block->pointer) +return count; + +memcpy (block->pointer, buf, count); + block->length = count; + }else { + in.pointer = buf; + in.length = count; +wmi_gtoa (block->gblock.guid, guid_string); + status =wmi_set_block (guid_string, block->instance, &in); + } + +return count; +} + +static struct bin_attribute wmi_attr_data = { + .attr = { + .name ="data" , + .mode =0600 + }, + .size =0 , + .read = wmi_data_read, + .write = wmi_data_write, +}; + +static ssize_t wmi_event_data_read (struct kobject *kobj,struct bin_attribute + *bin_attr,char *buf,loff_t offset,size_t count) { +struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER ,NULL }; +union acpi_object *obj; +struct wmi_block *block; +struct device *dev; + + dev = container_of(kobj, struct device, kobj); +if (!dev) +return -ENODEV ; + + block = container_of(dev, struct wmi_block, dev); +if (!block) +return -EINVAL ; + +wmi_get_event_data (block->gblock.notify_id, &out); + + obj = (union acpi_object *) out.pointer; + buf = obj->buffer.pointer; + +return 0 ; +} + +static struct bin_attribute wmi_attr_event_data = { + .attr = { + .name ="data" , + .mode =0400 + }, + .size =0 , + .read = wmi_event_data_read, +}; + +static ssize_t show_type (struct device *dev, +struct device_attribute *attr,char *buf) +{ +struct guid_block *block; +struct wmi_block *wblock; + + wblock = container_of(dev, struct wmi_block, dev); +if (!wblock) +return sprintf (buf,"Error\n" ); + + block = &wblock->gblock; + +if (block->flags &ACPI_WMI_METHOD ) { +return sprintf (buf,"method\n" ); + }else if (block->flags &ACPI_WMI_EVENT ) { +return sprintf (buf,"event\n" ); + }else { +return sprintf (buf,"data\n" ); + } +} +static DEVICE_ATTR(type, S_IRUGO, show_type, NULL); + +static ssize_t show_instance_count (struct device *dev, +struct device_attribute *attr,char *buf) +{ +struct wmi_block *block; + + block = container_of(dev, struct wmi_block, dev); +if (!block) +return sprintf (buf,"Error\n" ); + +return sprintf (buf,"%d\n" , block->gblock.instance_count); +} +static DEVICE_ATTR(instance_count, S_IRUGO, show_instance_count, NULL); + +static ssize_t show_instance (struct device *dev, +struct device_attribute *attr,char *buf) +{ +struct wmi_block *block; + + block = container_of(dev, struct wmi_block, dev); +if (!block) +return sprintf (buf,"Error\n" ); + +return sprintf (buf,"%d\n" , block->instance); +} + +static ssize_t set_instance (struct device *dev, +struct device_attribute *attr,const char *buf,size_t count) +{ +struct wmi_block *block; +u8 instance; + + instance =simple_strtoul (buf,NULL ,10 ); + + block = container_of(dev, struct wmi_block, dev); +if (!block) +return -EINVAL ; + +if (instance <= block->gblock.instance_count) { + block->instance = instance; + }else { +return -EINVAL ; + } + +return count; +} +static DEVICE_ATTR(instance, S_IWUGO | S_IRUGO, show_instance, set_instance); + +static ssize_t show_method_id (struct device *dev, +struct device_attribute *attr,char *buf) +{ +struct wmi_block *block; + + block = container_of(dev, struct wmi_block, dev); +if (!block) +return sprintf (buf,"Error\n" ); + +return sprintf (buf,"%d\n" , block->method_id); +} + +static ssize_t set_method_id (struct device *dev, +struct device_attribute *attr,const char *buf,size_t count) +{ +struct wmi_block *block; +u8 method_id; + + method_id =simple_strtoul (buf,NULL ,10 ); + +mutex_lock (&wmi_data_lock); + + block = container_of(dev, struct wmi_block, dev); +if (!block) { +mutex_unlock (&wmi_data_lock); +return -EINVAL ; + } + + block->method_id = method_id; +mutex_unlock (&wmi_data_lock); + +return count; +} +static DEVICE_ATTR(method_id, S_IWUGO | S_IRUGO, show_method_id, + set_method_id); + +static ssize_t show_event_notification (struct device *dev, +struct device_attribute *attr,char *buf) +{ +struct wmi_block *block; +struct guid_block *gblock; + + block = container_of(dev, struct wmi_block, dev); + gblock = &block->gblock; + +return sprintf (buf,"%d\n" , gblock->notify_id &0xFF ); +} +static DEVICE_ATTR(notification, S_IRUGO, show_event_notification, NULL); + +static ssize_t show_string (struct device *dev, +struct device_attribute *attr,char *buf) +{ +struct wmi_block *block; +struct guid_block *gblock; + + block = container_of(dev, struct wmi_block, dev); + gblock = &block->gblock; + +return sprintf (buf,"%d\n" , (gblock->flags &ACPI_WMI_STRING ) >>2 ); +} +static DEVICE_ATTR(string, S_IRUGO, show_string, 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 = container_of(dev, struct wmi_block, 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 struct class wmi_class = { + .name ="wmi" , + .dev_release = (void (*)(struct device *)) kfree, + .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 = &wblock->dev; + guid_dev->class = &wmi_class; + + gblock = &wblock->gblock; + +wmi_gtoa (gblock->guid, guid_string); +memcpy (guid_dev->bus_id, guid_string,36 ); + + result =device_register (guid_dev); +if (result) +return result; + + result =device_create_file (guid_dev, &dev_attr_type); +if (result) +return result; + + result =device_create_file (guid_dev, &dev_attr_string); +if (result) +return result; + +if (gblock->flags &ACPI_WMI_EVENT ) { + result =device_create_file (guid_dev, + &dev_attr_notification); +if (result) +return result; + + result =device_create_bin_file (guid_dev, + &wmi_attr_event_data); +if (result) +return result; +break ; + } + + result =device_create_file (guid_dev, &dev_attr_instance_count); +if (result) +return result; + + result =device_create_file (guid_dev, &dev_attr_instance); +if (result) +return result; + + result =device_create_bin_file (guid_dev, &wmi_attr_data); +if (result) +return result; + +if (gblock->flags &ACPI_WMI_METHOD ) { + result =device_create_file (guid_dev, + &dev_attr_method_id); +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_type); +device_remove_file (guid_dev, &dev_attr_string); + +if (gblock->flags &ACPI_WMI_EVENT ) { +device_remove_file (guid_dev, &dev_attr_notification); +device_remove_bin_file (guid_dev, &wmi_attr_event_data); + }else { +device_remove_file (guid_dev, &dev_attr_instance_count); +device_remove_file (guid_dev, &dev_attr_instance); +device_remove_bin_file (guid_dev, &wmi_attr_data); + +if (gblock->flags &ACPI_WMI_METHOD ) { +device_remove_file (guid_dev, + &dev_attr_method_id); + } + } +device_unregister (guid_dev); + } +} + +static int wmi_class_init (void ) +{ +int ret; + + ret =class_register (&wmi_class); +if (ret) +return ret; + +return wmi_create_devs (); +} + +static void wmi_class_exit (void ) +{ +wmi_remove_devs (); +class_unregister (&wmi_class); +} +/* * Parse the _WDG method for the GUID data blocks */
@@ -671,6 +1141,7 @@ static int __init acpi_wmi_add(struct acpi_device *device)static int __init acpi_wmi_init (void ) { +int ret;acpi_status result;if (acpi_disabled)
@@ -682,10 +1153,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 ; + } + + ret =wmi_class_init (); +if (ret) { +acpi_bus_unregister_driver (&acpi_wmi_driver); +return ret; } + printk(KERN_INFO PREFIX "Mapper loaded\n"); +return result; }
@@ -694,6 +1172,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) {
include/linux/acpi.h +1 -0
@@ -194,6 +194,7 @@ extern acpi_status wmi_install_notify_handler(const char *guid,extern acpi_status wmi_remove_notify_handler (const char *guid);extern acpi_status wmi_get_event_data (u32 event,struct acpi_buffer *out);extern bool wmi_has_guid (const char *guid); +extern int wmi_get_device (const char *guid,struct device **dev);#endif /* CONFIG_ACPI_WMI */
RFC PATCH 3/5 tc1100-wmi: Add driver for HP Compaq TC1100 Tablets
In reply to Carlos CorbachoThis is based on the 2004 out-of-tree work of Jamey Hicks, to add support via WMI for controlling the jog dial and wireless on these tablets.
v1:
Original release
v2:
As per Joshua Wise's comments, change bluetooth to jogdial (an error from the original driver).
---
drivers/misc/Kconfig | 9 + drivers/misc/Makefile | 1 drivers/misc/tc1100-wmi.c | 290 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 300 insertions(+), 0 deletions(-) create mode 100644 drivers/misc/tc1100-wmi.c
drivers/misc/Kconfig +9 -0
@@ -142,6 +142,15 @@ config FUJITSU_LAPTOP If you have a Fujitsu laptop, say Y or M here. +config TC1100_WMI + tristate "HP Compaq TC1100 Tablet WMI Extras" + depends on X86 && !X86_64 + depends on ACPI + depends on ACPI_WMI + ---help--- + This is a driver for the WMI extensions (wireless and bluetooth power + control) of the HP Compaq TC1100 tablet. + config MSI_LAPTOP tristate "MSI Laptop Extras" depends on X86
drivers/misc/Makefile +1 -0
@@ -9,6 +9,7 @@ obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o obj-$(CONFIG_ACER_WMI) += acer-wmi.o obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o +obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o obj-$(CONFIG_LKDTM) += lkdtm.o obj-$(CONFIG_TIFM_CORE) += tifm_core.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
drivers/misc/tc1100-wmi.c new file +290 -0
290 lines not on this page · raw message
Len Brown
reviewerHi Carlos,
Thanks for your persistence.
I've included this patch series to the acpi-test branch.
I think the indication of success of this effort will be other people writing drivers to do useful things with the WMI hooks you are exposing. So we certainly want to get the base driver out there sooner to support that.
I don't know if it would be better to ship a prototype sysfs user interface in the hopes it encourages adopters and get feedback to make it better, or to bake it more out of tree in the hopes of shipping something more final in the first shot.
I'm inclined to ship an EXPERIMENTAL API because
the more eyes on it sooner the better. One option
would be to have the sysfs I/F be a sub-config option
that is default N -- indeed, you can call it a DEBUGGING
or DEVELOPMENT I/F to scare people away from the the wrong impression:-)
Review
Quoted 11 lines
Patch #1: (WMI - driver and in kernel interface) - Minor clean up
Replace leftover occurences of 'x == NULL' with '!x'
Len: For you to review and to be applied to acpi-test.
(quoted diff) +4
-0+config ACPI_WMI + tristate "WMI (EXPERIMENTAL)" + depends on EXPERIMENTAL + default m
I deleted the "default m" line when i checked in this patch. So if you revise/resend this patch in the future, please do the same.
Quoted 9 lines
====
Patch #2: (acer-wmi) - New DMI entry, mail LED detection fix, mismatch fix
* Don't fail if we can't detect a mail LED on AMW0 systems
* Add an EC quirk for the Acer Aspire 9110
* Fix section mismatch warningsLen: For you to review and to be applied to acpi-test.
acer-wmi needs a MAINTAINER
Quoted 5 lines
Patch #3: (tc1100-wmi) - No Change
RFC only, needs actual testing on the hardware, and probably very broken. Waiting on Matthew Garrett to get some free time to test this.
tc1100-wmi needs a MAINTAINER
Quoted 9 lines
Patch #4: (WMI sysfs interface) - No Change
RFC only (see patch #5 for reason and discussion). Adds interface under
/sys/devices/virtual/wmiAlso adds a function to return the (virtual) device associated with a GUID for use by other parts of the kernel that want to set a parent device.
Len: To review (but not to apply yet, unless you want to apply patch #5 as well)
I don't understand the WMI user/kernel sysfs API.
I guess i had originally expected it to live in /sys/firmware/wmi, but I see that they put dmi a subset of DMI under /sys/class/dmi, so i guess there is precident... I got my main wish, which was to have not _not_ be under some ACPI specific directory:-)
Quoted 14 lines
Patch #5: (WMI sysfs workaround) - No Change
Temporary hack, needed to get patch #4 working, due to a limitation on
bus_idlength (Kay Sievers is apparently working on this, ref Greg KH[1]).Len:
Apparently, the necessary fixes _might_ go into 2.6.25 as well, or worst case scenario is 2.6.26[2]. So we can either:
1) Hold off on patch #4 until the necessary fixes go in (this might be 2.6.25 if we're lucky, or we end up putting off WMI sysfs support until 2.6.26) or
Quoted 5 lines
2) Apply patch #4, and #5 on top as a temporary hack, and then revert #5 as soon as the necessary changes go in. (For bisection purposes, #4 and #5 should be merged if we go ahead with this).
I don't know what would be the best solution here.
#2 is the better route -- move forward using workaround, and revert the workaround when it is no longer needed. The risk is if somebody in user-space starts actually programming to 19-character GUIDS.
Quoted 2 lines
[1] http://lkml.org/lkml/2007/12/4/30
[2] http://www.nabble.com/Re:-Fix-Firmware-class-name-collision-p14352966.html
I loaded this driver on an HP nx6325 as well as a Lenovo T61.
just for kicks i tried to dump the data attributes, but on both machines I found that some of them oops in wmi_data_read like below.
thanks,
-Len
Feb 2 22:05:55 t61 kernel: BUG: unable to handle kernel NULL pointer dereference at 0000000000000000 Feb 2 22:05:55 t61 kernel: IP: [<ffffffff8808bcce>] :wmi:wmi_data_read+0xc2/0xe0 Feb 2 22:05:55 t61 kernel: PGD 7bcdc067 PUD 719b9067 PMD 0 Feb 2 22:05:55 t61 kernel: Oops: 0000 [1] SMP Feb 2 22:05:55 t61 kernel: CPU 0 Feb 2 22:05:55 t61 kernel: Modules linked in: acpi_cpufreq pcmcia yenta_socket rsrc_nonstatic wmi ac battery video thermal iwl4965 mac80211 cfg80211 e1000e thinkpad_acpi backlight nvram Feb 2 22:05:55 t61 kernel: Pid: 3875, comm: cat Not tainted 2.6.24-06933-g9b85450-dirty #112 Feb 2 22:05:55 t61 kernel: RIP: 0010:[<ffffffff8808bcce>] [<ffffffff8808bcce>] :wmi:wmi_data_read+0xc2/0xe0 Feb 2 22:05:55 t61 kernel: RSP: 0018:ffff810071851e68 EFLAGS: 00010296 Feb 2 22:05:55 t61 kernel: RAX: 0000000000000000 RBX: ffff81007b4a6118 RCX: 0000000000000010 Feb 2 22:05:55 t61 kernel: RDX: 00000000ffffffcb RSI: ffff810071851d78 RDI: ffff81007b4a6d70 Feb 2 22:05:55 t61 kernel: RBP: ffff810071851ea8 R08: 0000000000001000 R09: ffff81007b83c9b0 Feb 2 22:05:55 t61 kernel: R10: ffff810071851d88 R11: 0000000000000246 R12: 0000000000001000 Feb 2 22:05:55 t61 kernel: R13: ffff81007b4a6128 R14: 0000000000000000 R15: ffffffff8808d7e0 Feb 2 22:05:55 t61 kernel: FS: 00007f7b4130d6f0(0000) GS:ffffffff80777000(0000) knlGS:0000000000000000 Feb 2 22:05:55 t61 kernel: CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b Feb 2 22:05:55 t61 kernel: CR2: 0000000000000000 CR3: 00000000719b0000 CR4: 00000000000006e0 Feb 2 22:05:55 t61 kernel: DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 Feb 2 22:05:55 t61 kernel: DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Feb 2 22:05:55 t61 kernel: Process cat (pid: 3875, threadinfo ffff810071850000, task ffff81007b45a280) Feb 2 22:05:55 t61 kernel: Stack: ffffffffffffffff 0000000000000000 0000000000000000 0000000147a52f6e Feb 2 22:05:55 t61 kernel: ffff810071851ea8 ffff81007ac61dd0 0000000000001000 00000000ffffffed Feb 2 22:05:55 t61 kernel: ffff810071851f08 ffffffff802c8b83 ffff810071851f48 0000000000abf000 Feb 2 22:05:55 t61 kernel: Call Trace: Feb 2 22:05:55 t61 kernel: [<ffffffff802c8b83>] read+0xc8/0x137 Feb 2 22:05:55 t61 kernel: [<ffffffff80287583>] vfs_read+0xab/0x134 Feb 2 22:05:55 t61 kernel: [<ffffffff80287948>] sys_read+0x47/0x6f Feb 2 22:05:55 t61 kernel: [<ffffffff8020b16b>] system_call_after_swapgs+0x7b/0x80 Feb 2 22:05:55 t61 kernel: Feb 2 22:05:55 t61 kernel: Feb 2 22:05:55 t61 kernel: Code: c9 4c 89 ef e8 5b fe ff ff 48 c7 c7 50 d8 08 88 e8 47 f9 4e f8 eb 10 48 8d 55 c0 41 0f b6 f4 4c 89 ef e8 f7 fc ff ff 48 8b 45 c8 <8b> 00 83 e8 02 83 f8 02 48 19 c0 48 f7 d0 48 83 e0 fb 48 83 c4 Feb 2 22:05:55 t61 kernel: RIP [<ffffffff8808bcce>] :wmi:wmi_data_read+0xc2/0xe0 Feb 2 22:05:55 t61 kernel: RSP <ffff810071851e68> Feb 2 22:05:55 t61 kernel: CR2: 0000000000000000 Feb 2 22:05:55 t61 kernel: ---[ end trace 0d56088a35d7a80e ]---
Quoted 4 lines · On Sunday 03 February 2008 03:44:22 Len Brown wrote:
I think the indication of success of this effort will be other people writing drivers to do useful things with the WMI hooks you are exposing. So we certainly want to get the base driver out there sooner to support that.
Matthew already has an input driver for HP laptops in progress, so I think that's a good sign.
Quoted 5 lines
I don't know if it would be better to ship a prototype sysfs user interface in the hopes it encourages adopters and get feedback to make it better, or to bake it more out of tree in the hopes of shipping something more final in the first shot.
The main problem with the sysfs interface is that, unlike the kernel one, there are no real users yet.
I have a hacked together test application which does some basic read/ write to sysfs, but that's about it.
Quoted 5 lines
I'm inclined to ship an EXPERIMENTAL API because
the more eyes on it sooner the better. One option
would be to have the sysfs I/F be a sub-config option
that is default N -- indeed, you can call it a DEBUGGING
or DEVELOPMENT I/F to scare people away from the the wrong impression:-)
Yes, that would be a better idea.
Quoted 7 lines
Review
Quoted 4 lines
(quoted diff) +4
-0+config ACPI_WMI + tristate "WMI (EXPERIMENTAL)" + depends on EXPERIMENTAL + default mI deleted the "default m" line when i checked in this patch. So if you revise/resend this patch in the future, please do the same.
Will do.
For future patches - do you want me to resend them, or send you incremental patches against what is currently in your tree?
Quoted 1 line
acer-wmi needs a MAINTAINER
Oversight on my part - will do.
Quoted 1 line
tc1100-wmi needs a MAINTAINER
I'll add myself for now; but if anyone else wants the job, I don't mind.
Quoted 1 line
I don't understand the WMI user/kernel sysfs API.
I did have some documentation on this - I'll refresh it and send another patch.
Quoted 4 lines
I guess i had originally expected it to live in
/sys/firmware/wmi, but I see that they put dmi a subset of DMI under/sys/class/dmi, so i guess there is precident... I got my main wish, which was to have not _not_ be under some ACPI specific directory:-)
I can probably put a symlink in for /sys/firmware/wmi, if you like?
The /sys/class is done simply because using a class and virtual devices is far simpler, and appears less prone to the sysfs-rework-of-the-week (and makes autoload support based on a GUID trivial to implement).
Quoted 4 lines
#2 is the better route -- move forward using workaround, and revert the workaround when it is no longer needed. The risk is if somebody in user-space starts actually programming to 19-character GUIDS.
Ok.
Quoted 1 line
I loaded this driver on an HP nx6325 as well as a Lenovo T61.
Interesting - do Lenovo actually use WMI for anything? I thought they had their own custom HID's supported by thinkpad-acpi?
Quoted 3 lines
just for kicks i tried to dump the data attributes, but on both machines I found that some of them oops in
wmi_data_readlike below.
Hmm - I'll look into this and see if I can see what's going wrong.
-Carlos
Signature · 3 lines
E-Mail: [email protected] Web: strangeworlds.co.uk GPG Key ID: 0x23EE722D
Len Brown
reviewerQuoted 3 lines
For future patches - do you want me to resend them, or send you incremental patches against what is currently in your tree?
I can handle either way,
but if they are revisions of the existing patches rather than adding additional logically independent changes, then it is cleaner to re-send the series.
Quoted 4 lines
Quoted 1 line
acer-wmi needs a MAINTAINER
Oversight on my part - will do.
Quoted 8 lines
Quoted 1 line
tc1100-wmi needs a MAINTAINER
I'll add myself for now; but if anyone else wants the job, I don't mind.
Quoted 1 line
I don't understand the WMI user/kernel sysfs API.
I did have some documentation on this - I'll refresh it and send another patch.
okay, good.
Quoted 6 lines
Quoted 4 lines
I guess i had originally expected it to live in
/sys/firmware/wmi, but I see that they put dmi a subset of DMI under/sys/class/dmi, so i guess there is precident... I got my main wish, which was to have not _not_ be under some ACPI specific directory:-)I can probably put a symlink in for
/sys/firmware/wmi, if you like?
No, don't bother.
Quoted 9 lines
The
/sys/classis done simply because using a class and virtual devices is far simpler, and appears less prone to the sysfs-rework-of-the-week (and makes autoload support based on a GUID trivial to implement).Quoted 4 lines
#2 is the better route -- move forward using workaround, and revert the workaround when it is no longer needed. The risk is if somebody in user-space starts actually programming to 19-character GUIDS.
Quoted 6 lines
Ok.
Quoted 1 line
I loaded this driver on an HP nx6325 as well as a Lenovo T61.
Interesting - do Lenovo actually use WMI for anything? I thought they had their own custom HID's supported by thinkpad-acpi?
Apparently they do.
The T61 also has IBM and LENOVO HIDs.
No, I don't know why the '*' is in "*pnp0c14", but we've run into that before so we ignore it.
[lenb@d975xbx2 t61]$ grep _HID DSDT.dsl
Name (_HID, EisaId ("PNP0C0F"))
Name (_HID, EisaId ("PNP0C0F"))
Name (_HID, EisaId ("PNP0C0F"))
Name (_HID, EisaId ("PNP0C0F"))
Name (_HID, EisaId ("PNP0C0F"))
Name (_HID, EisaId ("PNP0C0F"))
Name (_HID, EisaId ("PNP0C0F"))
Name (_HID, EisaId ("PNP0C0F"))
Name (_HID, EisaId ("PNP0C01"))
Name (_HID, EisaId ("PNP0C0D"))
Name (_HID, EisaId ("PNP0C0E"))
Name (_HID, EisaId ("PNP0C02"))
Name (_HID, EisaId ("PNP0000"))
Name (_HID, EisaId ("PNP0100"))
Name (_HID, EisaId ("PNP0103"))
Name (_HID, EisaId ("PNP0200"))
Name (_HID, EisaId ("PNP0800"))
Name (_HID, EisaId ("PNP0C04"))
Name (_HID, EisaId ("PNP0B00"))
Name (_HID, EisaId ("PNP0303"))
Name (_HID, EisaId ("IBM3780"))
Store (0x80374D24, _HID)
Store (0x57004D24, _HID)
Name (_HID, EisaId ("PNP0700"))
Name (_HID, EisaId ("PNP0501"))
Name (_HID, EisaId ("PNP0501"))
Name (_HID, EisaId ("PNP0400"))
Name (_HID, EisaId ("PNP0400"))
Name (_HID, EisaId ("PNP0401"))
Name (_HID, EisaId ("PNP0401"))
Name (_HID, EisaId ("ATM1200"))
Name (_HID, EisaId ("PNP0C09"))
Name (_HID, EisaId ("PNP0C0A"))
Name (_HID, EisaId ("PNP0C0A"))
Name (_HID, "ACPI0003")
Name (_HID, EisaId ("IBM0068"))
Name (_HID, EisaId ("PNP0A08"))
Name (_HID, "*pnp0c14")
Name (_HID, EisaId ("IBM0069"))
Store (\_SB.PCI0.LPC.FDC._HID, Index (XPCK, 0x02))
Store (\_SB.PCI0.LPC.EC.BAT1._HID, Index (XPCK, 0x02))
Name (_HID, EisaId ("IBM0079"))
Name (_HID, EisaId ("LEN0001"))Quoted 5 lines
Quoted 3 lines
just for kicks i tried to dump the data attributes, but on both machines I found that some of them oops in
wmi_data_readlike below.Hmm - I'll look into this and see if I can see what's going wrong.
thanks. Let me know if you need help testing.
cheers,
-Len
ps. note that your code shipped in 2.6.24-mm1