diff options
author | Thomas Renninger <trenn@suse.de> | 2010-05-21 10:42:40 -0400 |
---|---|---|
committer | Matthew Garrett <mjg@redhat.com> | 2010-08-03 09:48:43 -0400 |
commit | 6d96e00cef35036c513d342c4676d210b842880d (patch) | |
tree | bf33f323ac9011331c60172501e9d92b44acd443 /drivers/platform/x86/hp-wmi.c | |
parent | 8dda6b0410cfc64642b2ed5b37987292f6321d0f (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.c | 137 |
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 | ||
86 | struct bios_return { | 86 | struct bios_return { |
87 | u32 sigpass; | 87 | u32 sigpass; |
88 | u32 return_code; | 88 | u32 return_code; |
89 | u32 value; | ||
90 | }; | 89 | }; |
91 | 90 | ||
92 | struct key_entry { | 91 | struct 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 | ||
134 | static 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 | */ | ||
152 | static 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 | ||
168 | static int hp_wmi_display_state(void) | 200 | static 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 | ||
173 | static int hp_wmi_hddtemp_state(void) | 210 | static 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 | ||
178 | static int hp_wmi_als_state(void) | 220 | static 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 | ||
183 | static int hp_wmi_dock_state(void) | 230 | static 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 | ||
193 | static int hp_wmi_tablet_state(void) | 242 | static 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 | ||
203 | static int hp_wmi_set_block(void *data, bool blocked) | 253 | static 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 | ||
211 | static const struct rfkill_ops hp_wmi_rfkill_ops = { | 266 | static const struct rfkill_ops hp_wmi_rfkill_ops = { |
@@ -214,8 +269,13 @@ static const struct rfkill_ops hp_wmi_rfkill_ops = { | |||
214 | 269 | ||
215 | static bool hp_wmi_get_sw_state(enum hp_wmi_radio r) | 270 | static 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 | ||
226 | static bool hp_wmi_get_hw_state(enum hp_wmi_radio r) | 286 | static 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) | |||
503 | static int __devinit hp_wmi_bios_setup(struct platform_device *device) | 575 | static 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) |