summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaulo Alcantara <pcacjr@zytor.com>2017-07-30 08:47:55 -0400
committerAndy Shevchenko <andriy.shevchenko@linux.intel.com>2017-08-13 08:17:24 -0400
commitfbcb4a578bc29cfad82f838247ff1c2869433759 (patch)
treec917238bb34050b69f6cc9806f9c07c12eb40ce6
parentc801603e6d0c1bf87930402462d2e4185b1e9264 (diff)
platform/x86: hp-wmi: Correctly determine method id in WMI calls
The WMI queries are performed by evaluating the WMPV() method from ACPI DSDT tables, and it takes three arguments: instance index, method id and input data (buffer). Currently the method id is hard-coded to 0x3 in hp_wmi_perform_query() which means that it will perform WMI calls that expect an output data of size 0x80 (128). The output size is usually OK for the WMI queries we perform, however it would be better to pick the correct one before evaluating the WMI method. Which correct method id to choose can be figured out by looking at the following ASL code from WVPI() method: ... Name (PVSZ, Package (0x05) { Zero, 0x04, 0x80, 0x0400, 0x1000 }) Store (Zero, Local0) If (LAnd (LGreaterEqual (Arg1, One), LLessEqual (Arg1, 0x05))) { Store (DerefOf (Index (PVSZ, Subtract (Arg1, One))), Local0) } ... Arg1 is the method id and PVSZ is the package used to index the corresponding output size; 1 -> 0, 2 -> 4, 3 -> 128, 4 -> 1024, 5 -> 4096. This patch maps the output size passed in hp_wmi_perform_query() to the correct method id before evaluating the WMI method. Signed-off-by: Paulo Alcantara <pcacjr@zytor.com> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
-rw-r--r--drivers/platform/x86/hp-wmi.c23
1 files changed, 22 insertions, 1 deletions
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 0df4209648d1..c2ca5c22f8d2 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -188,6 +188,22 @@ struct rfkill2_device {
188static int rfkill2_count; 188static int rfkill2_count;
189static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES]; 189static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES];
190 190
191/* map output size to the corresponding WMI method id */
192static inline int encode_outsize_for_pvsz(int outsize)
193{
194 if (outsize > 4096)
195 return -EINVAL;
196 if (outsize > 1024)
197 return 5;
198 if (outsize > 128)
199 return 4;
200 if (outsize > 4)
201 return 3;
202 if (outsize > 0)
203 return 2;
204 return 1;
205}
206
191/* 207/*
192 * hp_wmi_perform_query 208 * hp_wmi_perform_query
193 * 209 *
@@ -211,6 +227,7 @@ static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES];
211static int hp_wmi_perform_query(int query, enum hp_wmi_command command, 227static int hp_wmi_perform_query(int query, enum hp_wmi_command command,
212 void *buffer, int insize, int outsize) 228 void *buffer, int insize, int outsize)
213{ 229{
230 int mid;
214 struct bios_return *bios_return; 231 struct bios_return *bios_return;
215 int actual_outsize; 232 int actual_outsize;
216 union acpi_object *obj; 233 union acpi_object *obj;
@@ -225,11 +242,15 @@ static int hp_wmi_perform_query(int query, enum hp_wmi_command command,
225 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 242 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
226 int ret = 0; 243 int ret = 0;
227 244
245 mid = encode_outsize_for_pvsz(outsize);
246 if (WARN_ON(mid < 0))
247 return mid;
248
228 if (WARN_ON(insize > sizeof(args.data))) 249 if (WARN_ON(insize > sizeof(args.data)))
229 return -EINVAL; 250 return -EINVAL;
230 memcpy(&args.data, buffer, insize); 251 memcpy(&args.data, buffer, insize);
231 252
232 wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output); 253 wmi_evaluate_method(HPWMI_BIOS_GUID, 0, mid, &input, &output);
233 254
234 obj = output.pointer; 255 obj = output.pointer;
235 256