aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86/hp-wmi.c
diff options
context:
space:
mode:
authorThomas Renninger <trenn@suse.de>2010-05-21 10:42:40 -0400
committerMatthew Garrett <mjg@redhat.com>2010-08-03 09:48:43 -0400
commit6d96e00cef35036c513d342c4676d210b842880d (patch)
treebf33f323ac9011331c60172501e9d92b44acd443 /drivers/platform/x86/hp-wmi.c
parent8dda6b0410cfc64642b2ed5b37987292f6321d0f (diff)
X86 platform: hp-wmi Better match the HP WMI query interface
- Improve error handling, by explictly return zero for success, error otherwise - WMI query command can have arbitrary input sized params - WMI query command can have specific output sized params (0, 4, 128,..) byte I like to go on here, but this is a rather intrusive change that should be looked at first. I am sure the one or other thing can be done better or there might be typo/bug somewhere. This did not get any testing yet, only compile tested. Next steps could be: - Eventually introduce hp_wmi_perform_{read,write}_query macros - Introduce new wireless query interface (0x1B) - more Signed-off-by: Thomas Renninger <trenn@suse.de> Signed-off-by: Matthew Garrett <mjg@redhat.com> CC: linux-acpi@vger.kernel.org CC: platform-driver-x86@vger.kernel.org
Diffstat (limited to 'drivers/platform/x86/hp-wmi.c')
-rw-r--r--drivers/platform/x86/hp-wmi.c137
1 files changed, 107 insertions, 30 deletions
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 7ebe46fe396e..d81f4cf70afc 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -80,13 +80,12 @@ struct bios_args {
80 u32 command; 80 u32 command;
81 u32 commandtype; 81 u32 commandtype;
82 u32 datasize; 82 u32 datasize;
83 u32 data; 83 char *data;
84}; 84};
85 85
86struct bios_return { 86struct bios_return {
87 u32 sigpass; 87 u32 sigpass;
88 u32 return_code; 88 u32 return_code;
89 u32 value;
90}; 89};
91 90
92struct key_entry { 91struct key_entry {
@@ -131,7 +130,27 @@ static struct platform_driver hp_wmi_driver = {
131 .remove = hp_wmi_bios_remove, 130 .remove = hp_wmi_bios_remove,
132}; 131};
133 132
134static int hp_wmi_perform_query(int query, int write, int value) 133/*
134 * hp_wmi_perform_query
135 *
136 * query: The commandtype -> What should be queried
137 * write: The command -> 0 read, 1 write, 3 ODM specific
138 * buffer: Buffer used as input and/or output
139 * buffersize: Size of buffer
140 *
141 * returns zero on success
142 * an HP WMI query specific error code (which is positive)
143 * -EINVAL if the query was not successful at all
144 * -EINVAL if the output buffer size exceeds buffersize
145 *
146 * Note: The buffersize must at least be the maximum of the input and output
147 * size. E.g. Battery info query (0x7) is defined to have 1 byte input
148 * and 128 byte output. The caller would do:
149 * buffer = kzalloc(128, GFP_KERNEL);
150 * ret = hp_wmi_perform_query(0x7, 0, buffer, 128)
151 */
152static int hp_wmi_perform_query(int query, int write, char *buffer,
153 int buffersize)
135{ 154{
136 struct bios_return bios_return; 155 struct bios_return bios_return;
137 acpi_status status; 156 acpi_status status;
@@ -140,8 +159,8 @@ static int hp_wmi_perform_query(int query, int write, int value)
140 .signature = 0x55434553, 159 .signature = 0x55434553,
141 .command = write ? 0x2 : 0x1, 160 .command = write ? 0x2 : 0x1,
142 .commandtype = query, 161 .commandtype = query,
143 .datasize = write ? 0x4 : 0, 162 .datasize = buffersize,
144 .data = value, 163 .data = buffer,
145 }; 164 };
146 struct acpi_buffer input = { sizeof(struct bios_args), &args }; 165 struct acpi_buffer input = { sizeof(struct bios_args), &args };
147 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 166 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -158,54 +177,90 @@ static int hp_wmi_perform_query(int query, int write, int value)
158 } 177 }
159 178
160 bios_return = *((struct bios_return *)obj->buffer.pointer); 179 bios_return = *((struct bios_return *)obj->buffer.pointer);
180
181 if (bios_return.return_code) {
182 printk(KERN_WARNING PREFIX "Query %d returned %d\n", query,
183 bios_return.return_code);
184 kfree(obj);
185 return bios_return.return_code;
186 }
187 if (obj->buffer.length - sizeof(bios_return) > buffersize) {
188 kfree(obj);
189 return -EINVAL;
190 }
191
192 memset(buffer, 0, buffersize);
193 memcpy(buffer,
194 ((char *)obj->buffer.pointer) + sizeof(struct bios_return),
195 obj->buffer.length - sizeof(bios_return));
161 kfree(obj); 196 kfree(obj);
162 if (bios_return.return_code > 0) 197 return 0;
163 return bios_return.return_code * -1;
164 else
165 return bios_return.value;
166} 198}
167 199
168static int hp_wmi_display_state(void) 200static int hp_wmi_display_state(void)
169{ 201{
170 return hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, 0); 202 int state;
203 int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, (char *)&state,
204 sizeof(state));
205 if (ret)
206 return -EINVAL;
207 return state;
171} 208}
172 209
173static int hp_wmi_hddtemp_state(void) 210static int hp_wmi_hddtemp_state(void)
174{ 211{
175 return hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, 0); 212 int state;
213 int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, (char *)&state,
214 sizeof(state));
215 if (ret)
216 return -EINVAL;
217 return state;
176} 218}
177 219
178static int hp_wmi_als_state(void) 220static int hp_wmi_als_state(void)
179{ 221{
180 return hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, 0); 222 int state;
223 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, (char *)&state,
224 sizeof(state));
225 if (ret)
226 return -EINVAL;
227 return state;
181} 228}
182 229
183static int hp_wmi_dock_state(void) 230static int hp_wmi_dock_state(void)
184{ 231{
185 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, 0); 232 int state;
233 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, (char *)&state,
234 sizeof(state));
186 235
187 if (ret < 0) 236 if (ret)
188 return ret; 237 return -EINVAL;
189 238
190 return ret & 0x1; 239 return state & 0x1;
191} 240}
192 241
193static int hp_wmi_tablet_state(void) 242static int hp_wmi_tablet_state(void)
194{ 243{
195 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, 0); 244 int state;
196 245 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, (char *)&state,
197 if (ret < 0) 246 sizeof(state));
247 if (ret)
198 return ret; 248 return ret;
199 249
200 return (ret & 0x4) ? 1 : 0; 250 return (state & 0x4) ? 1 : 0;
201} 251}
202 252
203static int hp_wmi_set_block(void *data, bool blocked) 253static int hp_wmi_set_block(void *data, bool blocked)
204{ 254{
205 enum hp_wmi_radio r = (enum hp_wmi_radio) data; 255 enum hp_wmi_radio r = (enum hp_wmi_radio) data;
206 int query = BIT(r + 8) | ((!blocked) << r); 256 int query = BIT(r + 8) | ((!blocked) << r);
257 int ret;
207 258
208 return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query); 259 ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1,
260 (char *)&query, sizeof(query));
261 if (ret)
262 return -EINVAL;
263 return 0;
209} 264}
210 265
211static const struct rfkill_ops hp_wmi_rfkill_ops = { 266static const struct rfkill_ops hp_wmi_rfkill_ops = {
@@ -214,8 +269,13 @@ static const struct rfkill_ops hp_wmi_rfkill_ops = {
214 269
215static bool hp_wmi_get_sw_state(enum hp_wmi_radio r) 270static bool hp_wmi_get_sw_state(enum hp_wmi_radio r)
216{ 271{
217 int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); 272 int wireless;
218 int mask = 0x200 << (r * 8); 273 int mask;
274 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
275 (char *)&wireless, sizeof(wireless));
276 /* TBD: Pass error */
277
278 mask = 0x200 << (r * 8);
219 279
220 if (wireless & mask) 280 if (wireless & mask)
221 return false; 281 return false;
@@ -225,8 +285,13 @@ static bool hp_wmi_get_sw_state(enum hp_wmi_radio r)
225 285
226static bool hp_wmi_get_hw_state(enum hp_wmi_radio r) 286static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
227{ 287{
228 int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); 288 int wireless;
229 int mask = 0x800 << (r * 8); 289 int mask;
290 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
291 (char *)&wireless, sizeof(wireless));
292 /* TBD: Pass error */
293
294 mask = 0x800 << (r * 8);
230 295
231 if (wireless & mask) 296 if (wireless & mask)
232 return false; 297 return false;
@@ -283,7 +348,11 @@ static ssize_t set_als(struct device *dev, struct device_attribute *attr,
283 const char *buf, size_t count) 348 const char *buf, size_t count)
284{ 349{
285 u32 tmp = simple_strtoul(buf, NULL, 10); 350 u32 tmp = simple_strtoul(buf, NULL, 10);
286 hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, tmp); 351 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, (char *)&tmp,
352 sizeof(tmp));
353 if (ret)
354 return -EINVAL;
355
287 return count; 356 return count;
288} 357}
289 358
@@ -353,7 +422,7 @@ static void hp_wmi_notify(u32 value, void *context)
353 static struct key_entry *key; 422 static struct key_entry *key;
354 union acpi_object *obj; 423 union acpi_object *obj;
355 u32 event_id, event_data; 424 u32 event_id, event_data;
356 int key_code; 425 int key_code, ret;
357 u32 *location; 426 u32 *location;
358 acpi_status status; 427 acpi_status status;
359 428
@@ -404,8 +473,11 @@ static void hp_wmi_notify(u32 value, void *context)
404 case HPWMI_SMART_ADAPTER: 473 case HPWMI_SMART_ADAPTER:
405 break; 474 break;
406 case HPWMI_BEZEL_BUTTON: 475 case HPWMI_BEZEL_BUTTON:
407 key_code = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, 476 ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
408 0); 477 (char *)&key_code,
478 sizeof(key_code));
479 if (ret)
480 break;
409 key = hp_wmi_get_entry_by_scancode(key_code); 481 key = hp_wmi_get_entry_by_scancode(key_code);
410 if (key) { 482 if (key) {
411 switch (key->type) { 483 switch (key->type) {
@@ -503,7 +575,12 @@ static void cleanup_sysfs(struct platform_device *device)
503static int __devinit hp_wmi_bios_setup(struct platform_device *device) 575static int __devinit hp_wmi_bios_setup(struct platform_device *device)
504{ 576{
505 int err; 577 int err;
506 int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); 578 int wireless;
579
580 err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, (char *)&wireless,
581 sizeof(wireless));
582 if (err)
583 return err;
507 584
508 err = device_create_file(&device->dev, &dev_attr_display); 585 err = device_create_file(&device->dev, &dev_attr_display);
509 if (err) 586 if (err)