aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86/hp-wmi.c
diff options
context:
space:
mode:
authorAnssi Hannula <anssi.hannula@iki.fi>2011-02-20 13:07:22 -0500
committerMatthew Garrett <mjg@redhat.com>2011-03-28 06:07:18 -0400
commitc3021ea1beeeb1aa8a92fa6946a6e25fc55f171d (patch)
tree11fd3dd2fa1c100fcbf639d76a22386f825984b5 /drivers/platform/x86/hp-wmi.c
parent25bb067a08c5db70cd8bcf9e160ac81718ea075c (diff)
hp-wmi: allow setting input and output buffer sizes separately
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 later when such larger buffers become needed. Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi> Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform/x86/hp-wmi.c')
-rw-r--r--drivers/platform/x86/hp-wmi.c63
1 files changed, 39 insertions, 24 deletions
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 8e27c27900a3..5c8ae65950d4 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -86,7 +86,6 @@ struct bios_args {
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
92enum hp_return_value { 91enum hp_return_value {
@@ -136,7 +135,8 @@ static struct platform_driver hp_wmi_driver = {
136 * query: The commandtype -> What should be queried 135 * query: The commandtype -> What should be queried
137 * write: The command -> 0 read, 1 write, 3 ODM specific 136 * write: The command -> 0 read, 1 write, 3 ODM specific
138 * buffer: Buffer used as input and/or output 137 * buffer: Buffer used as input and/or output
139 * buffersize: Size of buffer 138 * insize: Size of input buffer
139 * outsize: Size of output buffer
140 * 140 *
141 * returns zero on success 141 * returns zero on success
142 * an HP WMI query specific error code (which is positive) 142 * an HP WMI query specific error code (which is positive)
@@ -147,23 +147,28 @@ static struct platform_driver hp_wmi_driver = {
147 * size. E.g. Battery info query (0x7) is defined to have 1 byte input 147 * size. E.g. Battery info query (0x7) is defined to have 1 byte input
148 * and 128 byte output. The caller would do: 148 * and 128 byte output. The caller would do:
149 * buffer = kzalloc(128, GFP_KERNEL); 149 * buffer = kzalloc(128, GFP_KERNEL);
150 * ret = hp_wmi_perform_query(0x7, 0, buffer, 128) 150 * ret = hp_wmi_perform_query(0x7, 0, buffer, 1, 128)
151 */ 151 */
152static int hp_wmi_perform_query(int query, int write, u32 *buffer, 152static int hp_wmi_perform_query(int query, int write, void *buffer,
153 int buffersize) 153 int insize, int outsize)
154{ 154{
155 struct bios_return bios_return; 155 struct bios_return *bios_return;
156 int actual_outsize;
156 union acpi_object *obj; 157 union acpi_object *obj;
157 struct bios_args args = { 158 struct bios_args args = {
158 .signature = 0x55434553, 159 .signature = 0x55434553,
159 .command = write ? 0x2 : 0x1, 160 .command = write ? 0x2 : 0x1,
160 .commandtype = query, 161 .commandtype = query,
161 .datasize = buffersize, 162 .datasize = insize,
162 .data = *buffer, 163 .data = 0,
163 }; 164 };
164 struct acpi_buffer input = { sizeof(struct bios_args), &args }; 165 struct acpi_buffer input = { sizeof(struct bios_args), &args };
165 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 166 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
166 167
168 if (WARN_ON(insize > sizeof(args.data)))
169 return -EINVAL;
170 memcpy(&args.data, buffer, insize);
171
167 wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output); 172 wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output);
168 173
169 obj = output.pointer; 174 obj = output.pointer;
@@ -175,19 +180,26 @@ static int hp_wmi_perform_query(int query, int write, u32 *buffer,
175 return -EINVAL; 180 return -EINVAL;
176 } 181 }
177 182
178 bios_return = *((struct bios_return *)obj->buffer.pointer); 183 bios_return = (struct bios_return *)obj->buffer.pointer;
179 184
180 if (bios_return.return_code) { 185 if (bios_return->return_code) {
181 if (bios_return.return_code != HPWMI_RET_UNKNOWN_CMDTYPE) 186 if (bios_return->return_code != HPWMI_RET_UNKNOWN_CMDTYPE)
182 printk(KERN_WARNING PREFIX "query 0x%x returned " 187 printk(KERN_WARNING PREFIX "query 0x%x returned "
183 "error 0x%x\n", 188 "error 0x%x\n",
184 query, bios_return.return_code); 189 query, bios_return->return_code);
185 kfree(obj); 190 kfree(obj);
186 return bios_return.return_code; 191 return bios_return->return_code;
187 } 192 }
188 193
189 memcpy(buffer, &bios_return.value, sizeof(bios_return.value)); 194 if (!outsize) {
195 /* ignore output data */
196 kfree(obj);
197 return 0;
198 }
190 199
200 actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return)));
201 memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize);
202 memset(buffer + actual_outsize, 0, outsize - actual_outsize);
191 kfree(obj); 203 kfree(obj);
192 return 0; 204 return 0;
193} 205}
@@ -196,7 +208,7 @@ static int hp_wmi_display_state(void)
196{ 208{
197 int state = 0; 209 int state = 0;
198 int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state, 210 int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state,
199 sizeof(state)); 211 sizeof(state), sizeof(state));
200 if (ret) 212 if (ret)
201 return -EINVAL; 213 return -EINVAL;
202 return state; 214 return state;
@@ -206,7 +218,7 @@ static int hp_wmi_hddtemp_state(void)
206{ 218{
207 int state = 0; 219 int state = 0;
208 int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state, 220 int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state,
209 sizeof(state)); 221 sizeof(state), sizeof(state));
210 if (ret) 222 if (ret)
211 return -EINVAL; 223 return -EINVAL;
212 return state; 224 return state;
@@ -216,7 +228,7 @@ static int hp_wmi_als_state(void)
216{ 228{
217 int state = 0; 229 int state = 0;
218 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state, 230 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state,
219 sizeof(state)); 231 sizeof(state), sizeof(state));
220 if (ret) 232 if (ret)
221 return -EINVAL; 233 return -EINVAL;
222 return state; 234 return state;
@@ -226,7 +238,7 @@ static int hp_wmi_dock_state(void)
226{ 238{
227 int state = 0; 239 int state = 0;
228 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, 240 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state,
229 sizeof(state)); 241 sizeof(state), sizeof(state));
230 242
231 if (ret) 243 if (ret)
232 return -EINVAL; 244 return -EINVAL;
@@ -238,7 +250,7 @@ static int hp_wmi_tablet_state(void)
238{ 250{
239 int state = 0; 251 int state = 0;
240 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, 252 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state,
241 sizeof(state)); 253 sizeof(state), sizeof(state));
242 if (ret) 254 if (ret)
243 return ret; 255 return ret;
244 256
@@ -252,7 +264,7 @@ static int hp_wmi_set_block(void *data, bool blocked)
252 int ret; 264 int ret;
253 265
254 ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 266 ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1,
255 &query, sizeof(query)); 267 &query, sizeof(query), 0);
256 if (ret) 268 if (ret)
257 return -EINVAL; 269 return -EINVAL;
258 return 0; 270 return 0;
@@ -267,7 +279,8 @@ static bool hp_wmi_get_sw_state(enum hp_wmi_radio r)
267 int wireless = 0; 279 int wireless = 0;
268 int mask; 280 int mask;
269 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 281 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
270 &wireless, sizeof(wireless)); 282 &wireless, sizeof(wireless),
283 sizeof(wireless));
271 /* TBD: Pass error */ 284 /* TBD: Pass error */
272 285
273 mask = 0x200 << (r * 8); 286 mask = 0x200 << (r * 8);
@@ -283,7 +296,8 @@ static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
283 int wireless = 0; 296 int wireless = 0;
284 int mask; 297 int mask;
285 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 298 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
286 &wireless, sizeof(wireless)); 299 &wireless, sizeof(wireless),
300 sizeof(wireless));
287 /* TBD: Pass error */ 301 /* TBD: Pass error */
288 302
289 mask = 0x800 << (r * 8); 303 mask = 0x800 << (r * 8);
@@ -344,7 +358,7 @@ static ssize_t set_als(struct device *dev, struct device_attribute *attr,
344{ 358{
345 u32 tmp = simple_strtoul(buf, NULL, 10); 359 u32 tmp = simple_strtoul(buf, NULL, 10);
346 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp, 360 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp,
347 sizeof(tmp)); 361 sizeof(tmp), sizeof(tmp));
348 if (ret) 362 if (ret)
349 return -EINVAL; 363 return -EINVAL;
350 364
@@ -417,6 +431,7 @@ static void hp_wmi_notify(u32 value, void *context)
417 case HPWMI_BEZEL_BUTTON: 431 case HPWMI_BEZEL_BUTTON:
418 ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, 432 ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
419 &key_code, 433 &key_code,
434 sizeof(key_code),
420 sizeof(key_code)); 435 sizeof(key_code));
421 if (ret) 436 if (ret)
422 break; 437 break;
@@ -523,7 +538,7 @@ static int __devinit hp_wmi_bios_setup(struct platform_device *device)
523 int wireless = 0; 538 int wireless = 0;
524 539
525 err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless, 540 err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless,
526 sizeof(wireless)); 541 sizeof(wireless), sizeof(wireless));
527 if (err) 542 if (err)
528 return err; 543 return err;
529 544