* [PATCH 0/7] hp-wmi: various patches and 0x1b rfkill support
@ 2011-02-20 17:01 Anssi Hannula
2011-02-20 17:01 ` [PATCH 1/7] hp-wmi: check query return value in hp_wmi_perform_query Anssi Hannula
` (7 more replies)
0 siblings, 8 replies; 11+ messages in thread
From: Anssi Hannula @ 2011-02-20 17:01 UTC (permalink / raw)
To: Matthew Garrett; +Cc: platform-driver-x86
Hi all!
Here are some patches for the hp-wmi platform driver. The most
interesting bit is support for the wireless query 0x1b, allowing rfkill
to be used on laptops where it is used.
Anssi Hannula (7):
hp-wmi: check query return value in hp_wmi_perform_query
hp-wmi: remove a variable that is never read
hp-wmi: allow setting input and output buffer sizes separately
hp-wmi: split rfkill initialization out of hp_wmi_bios_setup
hp-wmi: clear rfkill device pointers when appropriate
hp-wmi: make rfkill initialization failure non-fatal
hp-wmi: add rfkill support for wireless query 0x1b
---
drivers/platform/x86/hp-wmi.c | 312 +++++++++++++++++++++++++++++++++++-----
1 files changed, 273 insertions(+), 39 deletions(-)
--
Anssi Hannula
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/7] hp-wmi: check query return value in hp_wmi_perform_query
2011-02-20 17:01 [PATCH 0/7] hp-wmi: various patches and 0x1b rfkill support Anssi Hannula
@ 2011-02-20 17:01 ` Anssi Hannula
2011-02-20 17:01 ` [PATCH 2/7] hp-wmi: remove a variable that is never read Anssi Hannula
` (6 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Anssi Hannula @ 2011-02-20 17:01 UTC (permalink / raw)
To: Matthew Garrett; +Cc: platform-driver-x86
---
drivers/platform/x86/hp-wmi.c | 16 ++++++++++++++++
1 files changed, 16 insertions(+), 0 deletions(-)
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 9e05af9..87dfb24 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -89,6 +89,13 @@ struct bios_return {
u32 value;
};
+enum hp_return_value {
+ HPWMI_RET_WRONG_SIGNATURE = 0x02,
+ HPWMI_RET_UNKNOWN_COMMAND = 0x03,
+ HPWMI_RET_UNKNOWN_CMDTYPE = 0x04,
+ HPWMI_RET_INVALID_PARAMETERS = 0x05,
+};
+
static const struct key_entry hp_wmi_keymap[] = {
{ KE_KEY, 0x02, { KEY_BRIGHTNESSUP } },
{ KE_KEY, 0x03, { KEY_BRIGHTNESSDOWN } },
@@ -171,6 +178,15 @@ static int hp_wmi_perform_query(int query, int write, u32 *buffer,
bios_return = *((struct bios_return *)obj->buffer.pointer);
+ if (bios_return.return_code) {
+ if (bios_return.return_code != HPWMI_RET_UNKNOWN_CMDTYPE)
+ printk(KERN_WARNING PREFIX "query 0x%x returned "
+ "error 0x%x\n",
+ query, bios_return.return_code);
+ kfree(obj);
+ return bios_return.return_code;
+ }
+
memcpy(buffer, &bios_return.value, sizeof(bios_return.value));
kfree(obj);
--
1.7.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/7] hp-wmi: remove a variable that is never read
2011-02-20 17:01 [PATCH 0/7] hp-wmi: various patches and 0x1b rfkill support Anssi Hannula
2011-02-20 17:01 ` [PATCH 1/7] hp-wmi: check query return value in hp_wmi_perform_query Anssi Hannula
@ 2011-02-20 17:01 ` Anssi Hannula
2011-02-20 17:01 ` [PATCH 3/7] hp-wmi: allow setting input and output buffer sizes separately Anssi Hannula
` (5 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Anssi Hannula @ 2011-02-20 17:01 UTC (permalink / raw)
To: Matthew Garrett; +Cc: platform-driver-x86
---
drivers/platform/x86/hp-wmi.c | 3 +--
1 files changed, 1 insertions(+), 2 deletions(-)
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 87dfb24..8e27c27 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -153,7 +153,6 @@ static int hp_wmi_perform_query(int query, int write, u32 *buffer,
int buffersize)
{
struct bios_return bios_return;
- acpi_status status;
union acpi_object *obj;
struct bios_args args = {
.signature = 0x55434553,
@@ -165,7 +164,7 @@ static int hp_wmi_perform_query(int query, int write, u32 *buffer,
struct acpi_buffer input = { sizeof(struct bios_args), &args };
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
- status = wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output);
+ wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output);
obj = output.pointer;
--
1.7.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 3/7] hp-wmi: allow setting input and output buffer sizes separately
2011-02-20 17:01 [PATCH 0/7] hp-wmi: various patches and 0x1b rfkill support Anssi Hannula
2011-02-20 17:01 ` [PATCH 1/7] hp-wmi: check query return value in hp_wmi_perform_query Anssi Hannula
2011-02-20 17:01 ` [PATCH 2/7] hp-wmi: remove a variable that is never read Anssi Hannula
@ 2011-02-20 17:01 ` Anssi Hannula
2011-02-20 17:01 ` [PATCH 4/7] hp-wmi: split rfkill initialization out of hp_wmi_bios_setup Anssi Hannula
` (4 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Anssi Hannula @ 2011-02-20 17:01 UTC (permalink / raw)
To: Matthew Garrett; +Cc: platform-driver-x86
Split buffersize parameter of hp_wmi_perform_query to insize and
outsize. Existing callers are changed to use the same value for insize
and outsize to avoid any regressions, with the exception of
hp_wmi_set_block where the output buffer is unused and therefore outsize
is set to 0 (this change is not seen by BIOS code).
The maximum input buffer size is kept at 4 bytes as per struct
bios_args. Some commands exist that take longer buffers, but they
haven't been implemented. The data portion of bios_args can be trivially
made dynamically allocated when such larger buffers become needed.
---
drivers/platform/x86/hp-wmi.c | 63 +++++++++++++++++++++++++---------------
1 files changed, 39 insertions(+), 24 deletions(-)
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 8e27c27..5c8ae65 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -86,7 +86,6 @@ struct bios_args {
struct bios_return {
u32 sigpass;
u32 return_code;
- u32 value;
};
enum hp_return_value {
@@ -136,7 +135,8 @@ static struct platform_driver hp_wmi_driver = {
* query: The commandtype -> What should be queried
* write: The command -> 0 read, 1 write, 3 ODM specific
* buffer: Buffer used as input and/or output
- * buffersize: Size of buffer
+ * insize: Size of input buffer
+ * outsize: Size of output buffer
*
* returns zero on success
* an HP WMI query specific error code (which is positive)
@@ -147,23 +147,28 @@ static struct platform_driver hp_wmi_driver = {
* size. E.g. Battery info query (0x7) is defined to have 1 byte input
* and 128 byte output. The caller would do:
* buffer = kzalloc(128, GFP_KERNEL);
- * ret = hp_wmi_perform_query(0x7, 0, buffer, 128)
+ * ret = hp_wmi_perform_query(0x7, 0, buffer, 1, 128)
*/
-static int hp_wmi_perform_query(int query, int write, u32 *buffer,
- int buffersize)
+static int hp_wmi_perform_query(int query, int write, void *buffer,
+ int insize, int outsize)
{
- struct bios_return bios_return;
+ struct bios_return *bios_return;
+ int actual_outsize;
union acpi_object *obj;
struct bios_args args = {
.signature = 0x55434553,
.command = write ? 0x2 : 0x1,
.commandtype = query,
- .datasize = buffersize,
- .data = *buffer,
+ .datasize = insize,
+ .data = 0,
};
struct acpi_buffer input = { sizeof(struct bios_args), &args };
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ if (WARN_ON(insize > sizeof(args.data)))
+ return -EINVAL;
+ memcpy(&args.data, buffer, insize);
+
wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output);
obj = output.pointer;
@@ -175,19 +180,26 @@ static int hp_wmi_perform_query(int query, int write, u32 *buffer,
return -EINVAL;
}
- bios_return = *((struct bios_return *)obj->buffer.pointer);
+ bios_return = (struct bios_return *)obj->buffer.pointer;
- if (bios_return.return_code) {
- if (bios_return.return_code != HPWMI_RET_UNKNOWN_CMDTYPE)
+ if (bios_return->return_code) {
+ if (bios_return->return_code != HPWMI_RET_UNKNOWN_CMDTYPE)
printk(KERN_WARNING PREFIX "query 0x%x returned "
"error 0x%x\n",
- query, bios_return.return_code);
+ query, bios_return->return_code);
kfree(obj);
- return bios_return.return_code;
+ return bios_return->return_code;
}
- memcpy(buffer, &bios_return.value, sizeof(bios_return.value));
+ if (!outsize) {
+ /* ignore output data */
+ kfree(obj);
+ return 0;
+ }
+ actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return)));
+ memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize);
+ memset(buffer + actual_outsize, 0, outsize - actual_outsize);
kfree(obj);
return 0;
}
@@ -196,7 +208,7 @@ static int hp_wmi_display_state(void)
{
int state = 0;
int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state,
- sizeof(state));
+ sizeof(state), sizeof(state));
if (ret)
return -EINVAL;
return state;
@@ -206,7 +218,7 @@ static int hp_wmi_hddtemp_state(void)
{
int state = 0;
int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state,
- sizeof(state));
+ sizeof(state), sizeof(state));
if (ret)
return -EINVAL;
return state;
@@ -216,7 +228,7 @@ static int hp_wmi_als_state(void)
{
int state = 0;
int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state,
- sizeof(state));
+ sizeof(state), sizeof(state));
if (ret)
return -EINVAL;
return state;
@@ -226,7 +238,7 @@ static int hp_wmi_dock_state(void)
{
int state = 0;
int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state,
- sizeof(state));
+ sizeof(state), sizeof(state));
if (ret)
return -EINVAL;
@@ -238,7 +250,7 @@ static int hp_wmi_tablet_state(void)
{
int state = 0;
int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state,
- sizeof(state));
+ sizeof(state), sizeof(state));
if (ret)
return ret;
@@ -252,7 +264,7 @@ static int hp_wmi_set_block(void *data, bool blocked)
int ret;
ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1,
- &query, sizeof(query));
+ &query, sizeof(query), 0);
if (ret)
return -EINVAL;
return 0;
@@ -267,7 +279,8 @@ static bool hp_wmi_get_sw_state(enum hp_wmi_radio r)
int wireless = 0;
int mask;
hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
- &wireless, sizeof(wireless));
+ &wireless, sizeof(wireless),
+ sizeof(wireless));
/* TBD: Pass error */
mask = 0x200 << (r * 8);
@@ -283,7 +296,8 @@ static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
int wireless = 0;
int mask;
hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
- &wireless, sizeof(wireless));
+ &wireless, sizeof(wireless),
+ sizeof(wireless));
/* TBD: Pass error */
mask = 0x800 << (r * 8);
@@ -344,7 +358,7 @@ static ssize_t set_als(struct device *dev, struct device_attribute *attr,
{
u32 tmp = simple_strtoul(buf, NULL, 10);
int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp,
- sizeof(tmp));
+ sizeof(tmp), sizeof(tmp));
if (ret)
return -EINVAL;
@@ -417,6 +431,7 @@ static void hp_wmi_notify(u32 value, void *context)
case HPWMI_BEZEL_BUTTON:
ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
&key_code,
+ sizeof(key_code),
sizeof(key_code));
if (ret)
break;
@@ -523,7 +538,7 @@ static int __devinit hp_wmi_bios_setup(struct platform_device *device)
int wireless = 0;
err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless,
- sizeof(wireless));
+ sizeof(wireless), sizeof(wireless));
if (err)
return err;
--
1.7.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 4/7] hp-wmi: split rfkill initialization out of hp_wmi_bios_setup
2011-02-20 17:01 [PATCH 0/7] hp-wmi: various patches and 0x1b rfkill support Anssi Hannula
` (2 preceding siblings ...)
2011-02-20 17:01 ` [PATCH 3/7] hp-wmi: allow setting input and output buffer sizes separately Anssi Hannula
@ 2011-02-20 17:01 ` Anssi Hannula
2011-02-20 17:01 ` [PATCH 5/7] hp-wmi: clear rfkill device pointers when appropriate Anssi Hannula
` (3 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Anssi Hannula @ 2011-02-20 17:01 UTC (permalink / raw)
To: Matthew Garrett; +Cc: platform-driver-x86
---
drivers/platform/x86/hp-wmi.c | 46 +++++++++++++++++++++++++---------------
1 files changed, 29 insertions(+), 17 deletions(-)
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 5c8ae65..f6a1c37 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -532,7 +532,7 @@ static void cleanup_sysfs(struct platform_device *device)
device_remove_file(&device->dev, &dev_attr_tablet);
}
-static int __devinit hp_wmi_bios_setup(struct platform_device *device)
+static int __devinit hp_wmi_rfkill_setup(struct platform_device *device)
{
int err;
int wireless = 0;
@@ -542,22 +542,6 @@ static int __devinit hp_wmi_bios_setup(struct platform_device *device)
if (err)
return err;
- err = device_create_file(&device->dev, &dev_attr_display);
- if (err)
- goto add_sysfs_error;
- err = device_create_file(&device->dev, &dev_attr_hddtemp);
- if (err)
- goto add_sysfs_error;
- err = device_create_file(&device->dev, &dev_attr_als);
- if (err)
- goto add_sysfs_error;
- err = device_create_file(&device->dev, &dev_attr_dock);
- if (err)
- goto add_sysfs_error;
- err = device_create_file(&device->dev, &dev_attr_tablet);
- if (err)
- goto add_sysfs_error;
-
if (wireless & 0x1) {
wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
RFKILL_TYPE_WLAN,
@@ -611,6 +595,34 @@ register_bluetooth_error:
rfkill_unregister(wifi_rfkill);
register_wifi_error:
rfkill_destroy(wifi_rfkill);
+ return err;
+}
+
+static int __devinit hp_wmi_bios_setup(struct platform_device *device)
+{
+ int err;
+
+ err = hp_wmi_rfkill_setup(device);
+ if (err)
+ return err;
+
+ err = device_create_file(&device->dev, &dev_attr_display);
+ if (err)
+ goto add_sysfs_error;
+ err = device_create_file(&device->dev, &dev_attr_hddtemp);
+ if (err)
+ goto add_sysfs_error;
+ err = device_create_file(&device->dev, &dev_attr_als);
+ if (err)
+ goto add_sysfs_error;
+ err = device_create_file(&device->dev, &dev_attr_dock);
+ if (err)
+ goto add_sysfs_error;
+ err = device_create_file(&device->dev, &dev_attr_tablet);
+ if (err)
+ goto add_sysfs_error;
+ return 0;
+
add_sysfs_error:
cleanup_sysfs(device);
return err;
--
1.7.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 5/7] hp-wmi: clear rfkill device pointers when appropriate
2011-02-20 17:01 [PATCH 0/7] hp-wmi: various patches and 0x1b rfkill support Anssi Hannula
` (3 preceding siblings ...)
2011-02-20 17:01 ` [PATCH 4/7] hp-wmi: split rfkill initialization out of hp_wmi_bios_setup Anssi Hannula
@ 2011-02-20 17:01 ` Anssi Hannula
2011-02-20 17:01 ` [PATCH 6/7] hp-wmi: make rfkill initialization failure non-fatal Anssi Hannula
` (2 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Anssi Hannula @ 2011-02-20 17:01 UTC (permalink / raw)
To: Matthew Garrett; +Cc: platform-driver-x86
NULLify rfkill pointers during initialization. This prevents dereference
of invalid pointer in case the driver is rebound and some rfkill device
isn't detected anymore. Clear them also in hp_wmi_rfkill_setup failure
path so that rfkill initialization failure doesn't need to be fatal for
the whole driver.
---
drivers/platform/x86/hp-wmi.c | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index f6a1c37..45b2bbe 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -587,14 +587,17 @@ static int __devinit hp_wmi_rfkill_setup(struct platform_device *device)
return 0;
register_wwan_err:
rfkill_destroy(wwan_rfkill);
+ wwan_rfkill = NULL;
if (bluetooth_rfkill)
rfkill_unregister(bluetooth_rfkill);
register_bluetooth_error:
rfkill_destroy(bluetooth_rfkill);
+ bluetooth_rfkill = NULL;
if (wifi_rfkill)
rfkill_unregister(wifi_rfkill);
register_wifi_error:
rfkill_destroy(wifi_rfkill);
+ wifi_rfkill = NULL;
return err;
}
@@ -602,6 +605,11 @@ static int __devinit hp_wmi_bios_setup(struct platform_device *device)
{
int err;
+ /* clear detected rfkill devices */
+ wifi_rfkill = NULL;
+ bluetooth_rfkill = NULL;
+ wwan_rfkill = NULL;
+
err = hp_wmi_rfkill_setup(device);
if (err)
return err;
--
1.7.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 6/7] hp-wmi: make rfkill initialization failure non-fatal
2011-02-20 17:01 [PATCH 0/7] hp-wmi: various patches and 0x1b rfkill support Anssi Hannula
` (4 preceding siblings ...)
2011-02-20 17:01 ` [PATCH 5/7] hp-wmi: clear rfkill device pointers when appropriate Anssi Hannula
@ 2011-02-20 17:01 ` Anssi Hannula
2011-02-20 17:01 ` [PATCH 7/7] hp-wmi: add rfkill support for wireless query 0x1b Anssi Hannula
2011-02-20 17:34 ` [PATCH 0/7] hp-wmi: various patches and 0x1b rfkill support Matthew Garrett
7 siblings, 0 replies; 11+ messages in thread
From: Anssi Hannula @ 2011-02-20 17:01 UTC (permalink / raw)
To: Matthew Garrett; +Cc: platform-driver-x86
hp_wmi_rfkill_setup cleans up after itself now, so failing completely is
no longer necessary.
---
drivers/platform/x86/hp-wmi.c | 4 +---
1 files changed, 1 insertions(+), 3 deletions(-)
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 45b2bbe..524ffab 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -610,9 +610,7 @@ static int __devinit hp_wmi_bios_setup(struct platform_device *device)
bluetooth_rfkill = NULL;
wwan_rfkill = NULL;
- err = hp_wmi_rfkill_setup(device);
- if (err)
- return err;
+ hp_wmi_rfkill_setup(device);
err = device_create_file(&device->dev, &dev_attr_display);
if (err)
--
1.7.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 7/7] hp-wmi: add rfkill support for wireless query 0x1b
2011-02-20 17:01 [PATCH 0/7] hp-wmi: various patches and 0x1b rfkill support Anssi Hannula
` (5 preceding siblings ...)
2011-02-20 17:01 ` [PATCH 6/7] hp-wmi: make rfkill initialization failure non-fatal Anssi Hannula
@ 2011-02-20 17:01 ` Anssi Hannula
2011-02-20 17:34 ` [PATCH 0/7] hp-wmi: various patches and 0x1b rfkill support Matthew Garrett
7 siblings, 0 replies; 11+ messages in thread
From: Anssi Hannula @ 2011-02-20 17:01 UTC (permalink / raw)
To: Matthew Garrett; +Cc: platform-driver-x86
HP Mini 5102 and other recent HP laptops use a new wireless query
command type 0x1b.
Add support for it.
---
drivers/platform/x86/hp-wmi.c | 188 ++++++++++++++++++++++++++++++++++++++++-
1 files changed, 187 insertions(+), 1 deletions(-)
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 524ffab..1bc4a75 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -2,6 +2,7 @@
* HP WMI hotkeys
*
* Copyright (C) 2008 Red Hat <mjg@redhat.com>
+ * Copyright (C) 2010, 2011 Anssi Hannula <anssi.hannula@iki.fi>
*
* Portions based on wistron_btns.c:
* Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
@@ -51,6 +52,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
#define HPWMI_HARDWARE_QUERY 0x4
#define HPWMI_WIRELESS_QUERY 0x5
#define HPWMI_HOTKEY_QUERY 0xc
+#define HPWMI_WIRELESS2_QUERY 0x1b
#define PREFIX "HP WMI: "
#define UNIMP "Unimplemented "
@@ -95,6 +97,39 @@ enum hp_return_value {
HPWMI_RET_INVALID_PARAMETERS = 0x05,
};
+enum hp_wireless2_bits {
+ HPWMI_POWER_STATE = 0x01,
+ HPWMI_POWER_SOFT = 0x02,
+ HPWMI_POWER_BIOS = 0x04,
+ HPWMI_POWER_HARD = 0x08,
+};
+
+#define IS_HWBLOCKED(x) ((x & (HPWMI_POWER_BIOS | HPWMI_POWER_HARD)) \
+ != (HPWMI_POWER_BIOS | HPWMI_POWER_HARD))
+#define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT)
+
+struct bios_rfkill2_device_state {
+ u8 radio_type;
+ u8 bus_type;
+ u16 vendor_id;
+ u16 product_id;
+ u16 subsys_vendor_id;
+ u16 subsys_product_id;
+ u8 rfkill_id;
+ u8 power;
+ u8 unknown[4];
+};
+
+/* 7 devices fit into the 128 byte buffer */
+#define HPWMI_MAX_RFKILL2_DEVICES 7
+
+struct bios_rfkill2_state {
+ u8 unknown[7];
+ u8 count;
+ u8 pad[8];
+ struct bios_rfkill2_device_state device[HPWMI_MAX_RFKILL2_DEVICES];
+};
+
static const struct key_entry hp_wmi_keymap[] = {
{ KE_KEY, 0x02, { KEY_BRIGHTNESSUP } },
{ KE_KEY, 0x03, { KEY_BRIGHTNESSDOWN } },
@@ -114,6 +149,15 @@ static struct rfkill *wifi_rfkill;
static struct rfkill *bluetooth_rfkill;
static struct rfkill *wwan_rfkill;
+struct rfkill2_device {
+ u8 id;
+ int num;
+ struct rfkill *rfkill;
+};
+
+static int rfkill2_count;
+static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES];
+
static const struct dev_pm_ops hp_wmi_pm_ops = {
.resume = hp_wmi_resume_handler,
.restore = hp_wmi_resume_handler,
@@ -308,6 +352,51 @@ static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
return true;
}
+static int hp_wmi_rfkill2_set_block(void *data, bool blocked)
+{
+ int rfkill_id = (int)(long)data;
+ char buffer[4] = { 0x01, 0x00, rfkill_id, !blocked };
+
+ if (hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 1,
+ buffer, sizeof(buffer), 0))
+ return -EINVAL;
+ return 0;
+}
+
+static const struct rfkill_ops hp_wmi_rfkill2_ops = {
+ .set_block = hp_wmi_rfkill2_set_block,
+};
+
+static int hp_wmi_rfkill2_refresh(void)
+{
+ int err, i;
+ struct bios_rfkill2_state state;
+
+ err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state,
+ 0, sizeof(state));
+ if (err)
+ return err;
+
+ for (i = 0; i < rfkill2_count; i++) {
+ int num = rfkill2[i].num;
+ struct bios_rfkill2_device_state *devstate;
+ devstate = &state.device[num];
+
+ if (num >= state.count ||
+ devstate->rfkill_id != rfkill2[i].id) {
+ printk(KERN_WARNING PREFIX "power configuration of "
+ "the wireless devices unexpectedly changed\n");
+ continue;
+ }
+
+ rfkill_set_states(rfkill2[i].rfkill,
+ IS_SWBLOCKED(devstate->power),
+ IS_HWBLOCKED(devstate->power));
+ }
+
+ return 0;
+}
+
static ssize_t show_display(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -442,6 +531,11 @@ static void hp_wmi_notify(u32 value, void *context)
key_code);
break;
case HPWMI_WIRELESS:
+ if (rfkill2_count) {
+ hp_wmi_rfkill2_refresh();
+ break;
+ }
+
if (wifi_rfkill)
rfkill_set_states(wifi_rfkill,
hp_wmi_get_sw_state(HPWMI_WIFI),
@@ -601,6 +695,87 @@ register_wifi_error:
return err;
}
+static int __devinit hp_wmi_rfkill2_setup(struct platform_device *device)
+{
+ int err, i;
+ struct bios_rfkill2_state state;
+ err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state,
+ 0, sizeof(state));
+ if (err)
+ return err;
+
+ if (state.count > HPWMI_MAX_RFKILL2_DEVICES) {
+ printk(KERN_WARNING PREFIX "unable to parse 0x1b query output\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < state.count; i++) {
+ struct rfkill *rfkill;
+ enum rfkill_type type;
+ char *name;
+ switch (state.device[i].radio_type) {
+ case HPWMI_WIFI:
+ type = RFKILL_TYPE_WLAN;
+ name = "hp-wifi";
+ break;
+ case HPWMI_BLUETOOTH:
+ type = RFKILL_TYPE_BLUETOOTH;
+ name = "hp-bluetooth";
+ break;
+ case HPWMI_WWAN:
+ type = RFKILL_TYPE_WWAN;
+ name = "hp-wwan";
+ break;
+ default:
+ printk(KERN_WARNING PREFIX "unknown device type 0x%x\n",
+ state.device[i].radio_type);
+ continue;
+ }
+
+ if (!state.device[i].vendor_id) {
+ printk(KERN_WARNING PREFIX "zero device %d while %d "
+ "reported\n", i, state.count);
+ continue;
+ }
+
+ rfkill = rfkill_alloc(name, &device->dev, type,
+ &hp_wmi_rfkill2_ops, (void *)(long)i);
+ if (!rfkill) {
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ rfkill2[rfkill2_count].id = state.device[i].rfkill_id;
+ rfkill2[rfkill2_count].num = i;
+ rfkill2[rfkill2_count].rfkill = rfkill;
+
+ rfkill_init_sw_state(rfkill,
+ IS_SWBLOCKED(state.device[i].power));
+ rfkill_set_hw_state(rfkill,
+ IS_HWBLOCKED(state.device[i].power));
+
+ if (!(state.device[i].power & HPWMI_POWER_BIOS))
+ printk(KERN_INFO PREFIX "device %s blocked by BIOS\n",
+ name);
+
+ err = rfkill_register(rfkill);
+ if (err) {
+ rfkill_destroy(rfkill);
+ goto fail;
+ }
+
+ rfkill2_count++;
+ }
+
+ return 0;
+fail:
+ for (; rfkill2_count > 0; rfkill2_count--) {
+ rfkill_unregister(rfkill2[rfkill2_count - 1].rfkill);
+ rfkill_destroy(rfkill2[rfkill2_count - 1].rfkill);
+ }
+ return err;
+}
+
static int __devinit hp_wmi_bios_setup(struct platform_device *device)
{
int err;
@@ -609,8 +784,10 @@ static int __devinit hp_wmi_bios_setup(struct platform_device *device)
wifi_rfkill = NULL;
bluetooth_rfkill = NULL;
wwan_rfkill = NULL;
+ rfkill2_count = 0;
- hp_wmi_rfkill_setup(device);
+ if (hp_wmi_rfkill_setup(device))
+ hp_wmi_rfkill2_setup(device);
err = device_create_file(&device->dev, &dev_attr_display);
if (err)
@@ -636,8 +813,14 @@ add_sysfs_error:
static int __exit hp_wmi_bios_remove(struct platform_device *device)
{
+ int i;
cleanup_sysfs(device);
+ for (i = 0; i < rfkill2_count; i++) {
+ rfkill_unregister(rfkill2[i].rfkill);
+ rfkill_destroy(rfkill2[i].rfkill);
+ }
+
if (wifi_rfkill) {
rfkill_unregister(wifi_rfkill);
rfkill_destroy(wifi_rfkill);
@@ -670,6 +853,9 @@ static int hp_wmi_resume_handler(struct device *device)
input_sync(hp_wmi_input_dev);
}
+ if (rfkill2_count)
+ hp_wmi_rfkill2_refresh();
+
if (wifi_rfkill)
rfkill_set_states(wifi_rfkill,
hp_wmi_get_sw_state(HPWMI_WIFI),
--
1.7.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 0/7] hp-wmi: various patches and 0x1b rfkill support
2011-02-20 17:01 [PATCH 0/7] hp-wmi: various patches and 0x1b rfkill support Anssi Hannula
` (6 preceding siblings ...)
2011-02-20 17:01 ` [PATCH 7/7] hp-wmi: add rfkill support for wireless query 0x1b Anssi Hannula
@ 2011-02-20 17:34 ` Matthew Garrett
2011-02-20 17:50 ` Anssi Hannula
7 siblings, 1 reply; 11+ messages in thread
From: Matthew Garrett @ 2011-02-20 17:34 UTC (permalink / raw)
To: Anssi Hannula; +Cc: platform-driver-x86
Awesome, but any chance you can resend these with Signed-off-by:s ? :)
I'd slightly prefer it if you could give a brief comment in the patches
that don't currently have a description either. But thank you very much
for working on this!
--
Matthew Garrett | mjg59@srcf.ucam.org
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 0/7] hp-wmi: various patches and 0x1b rfkill support
2011-02-20 17:34 ` [PATCH 0/7] hp-wmi: various patches and 0x1b rfkill support Matthew Garrett
@ 2011-02-20 17:50 ` Anssi Hannula
0 siblings, 0 replies; 11+ messages in thread
From: Anssi Hannula @ 2011-02-20 17:50 UTC (permalink / raw)
To: Matthew Garrett; +Cc: platform-driver-x86
On 20.02.2011 19:34, Matthew Garrett wrote:
> Awesome, but any chance you can resend these with Signed-off-by:s ? :)
> I'd slightly prefer it if you could give a brief comment in the patches
> that don't currently have a description either. But thank you very much
> for working on this!
Ah, seems I've sent too many patchsets to other projects recently :)
I'll resend these in a moment, and I can also add some more detailed
messages.
--
Anssi Hannula
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/7] hp-wmi: check query return value in hp_wmi_perform_query
2011-02-20 18:07 [PATCH 0/7] hp-wmi: various patches and 0x1b rfkill support (resend) Anssi Hannula
@ 2011-02-20 18:07 ` Anssi Hannula
0 siblings, 0 replies; 11+ messages in thread
From: Anssi Hannula @ 2011-02-20 18:07 UTC (permalink / raw)
To: Matthew Garrett; +Cc: platform-driver-x86
Check BIOS provided return value code in hp_wmi_perform_query and print
a warning on error. Printing is suppressed for HPWMI_RET_UNKNOWN_CMDTYPE
which is returned when the command type is unsupported.
Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi>
---
drivers/platform/x86/hp-wmi.c | 16 ++++++++++++++++
1 files changed, 16 insertions(+), 0 deletions(-)
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 9e05af9..87dfb24 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -89,6 +89,13 @@ struct bios_return {
u32 value;
};
+enum hp_return_value {
+ HPWMI_RET_WRONG_SIGNATURE = 0x02,
+ HPWMI_RET_UNKNOWN_COMMAND = 0x03,
+ HPWMI_RET_UNKNOWN_CMDTYPE = 0x04,
+ HPWMI_RET_INVALID_PARAMETERS = 0x05,
+};
+
static const struct key_entry hp_wmi_keymap[] = {
{ KE_KEY, 0x02, { KEY_BRIGHTNESSUP } },
{ KE_KEY, 0x03, { KEY_BRIGHTNESSDOWN } },
@@ -171,6 +178,15 @@ static int hp_wmi_perform_query(int query, int write, u32 *buffer,
bios_return = *((struct bios_return *)obj->buffer.pointer);
+ if (bios_return.return_code) {
+ if (bios_return.return_code != HPWMI_RET_UNKNOWN_CMDTYPE)
+ printk(KERN_WARNING PREFIX "query 0x%x returned "
+ "error 0x%x\n",
+ query, bios_return.return_code);
+ kfree(obj);
+ return bios_return.return_code;
+ }
+
memcpy(buffer, &bios_return.value, sizeof(bios_return.value));
kfree(obj);
--
1.7.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
end of thread, other threads:[~2011-02-20 18:07 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-02-20 17:01 [PATCH 0/7] hp-wmi: various patches and 0x1b rfkill support Anssi Hannula
2011-02-20 17:01 ` [PATCH 1/7] hp-wmi: check query return value in hp_wmi_perform_query Anssi Hannula
2011-02-20 17:01 ` [PATCH 2/7] hp-wmi: remove a variable that is never read Anssi Hannula
2011-02-20 17:01 ` [PATCH 3/7] hp-wmi: allow setting input and output buffer sizes separately Anssi Hannula
2011-02-20 17:01 ` [PATCH 4/7] hp-wmi: split rfkill initialization out of hp_wmi_bios_setup Anssi Hannula
2011-02-20 17:01 ` [PATCH 5/7] hp-wmi: clear rfkill device pointers when appropriate Anssi Hannula
2011-02-20 17:01 ` [PATCH 6/7] hp-wmi: make rfkill initialization failure non-fatal Anssi Hannula
2011-02-20 17:01 ` [PATCH 7/7] hp-wmi: add rfkill support for wireless query 0x1b Anssi Hannula
2011-02-20 17:34 ` [PATCH 0/7] hp-wmi: various patches and 0x1b rfkill support Matthew Garrett
2011-02-20 17:50 ` Anssi Hannula
2011-02-20 18:07 [PATCH 0/7] hp-wmi: various patches and 0x1b rfkill support (resend) Anssi Hannula
2011-02-20 18:07 ` [PATCH 1/7] hp-wmi: check query return value in hp_wmi_perform_query Anssi Hannula
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.