Commit c3021ea1beeeb1aa8a92fa6946a6e25fc55f171d

Authored by Anssi Hannula
Committed by Matthew Garrett
1 parent 25bb067a08

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>

Showing 1 changed file with 39 additions and 24 deletions Side-by-side Diff

drivers/platform/x86/hp-wmi.c
... ... @@ -86,7 +86,6 @@
86 86 struct bios_return {
87 87 u32 sigpass;
88 88 u32 return_code;
89   - u32 value;
90 89 };
91 90  
92 91 enum hp_return_value {
... ... @@ -136,7 +135,8 @@
136 135 * query: The commandtype -> What should be queried
137 136 * write: The command -> 0 read, 1 write, 3 ODM specific
138 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 141 * returns zero on success
142 142 * an HP WMI query specific error code (which is positive)
143 143  
144 144  
145 145  
146 146  
... ... @@ -147,23 +147,28 @@
147 147 * size. E.g. Battery info query (0x7) is defined to have 1 byte input
148 148 * and 128 byte output. The caller would do:
149 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 */
152   -static int hp_wmi_perform_query(int query, int write, u32 *buffer,
153   - int buffersize)
  152 +static int hp_wmi_perform_query(int query, int write, void *buffer,
  153 + int insize, int outsize)
154 154 {
155   - struct bios_return bios_return;
  155 + struct bios_return *bios_return;
  156 + int actual_outsize;
156 157 union acpi_object *obj;
157 158 struct bios_args args = {
158 159 .signature = 0x55434553,
159 160 .command = write ? 0x2 : 0x1,
160 161 .commandtype = query,
161   - .datasize = buffersize,
162   - .data = *buffer,
  162 + .datasize = insize,
  163 + .data = 0,
163 164 };
164 165 struct acpi_buffer input = { sizeof(struct bios_args), &args };
165 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 172 wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output);
168 173  
169 174 obj = output.pointer;
170 175  
171 176  
172 177  
173 178  
174 179  
... ... @@ -175,19 +180,26 @@
175 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) {
181   - if (bios_return.return_code != HPWMI_RET_UNKNOWN_CMDTYPE)
  185 + if (bios_return->return_code) {
  186 + if (bios_return->return_code != HPWMI_RET_UNKNOWN_CMDTYPE)
182 187 printk(KERN_WARNING PREFIX "query 0x%x returned "
183 188 "error 0x%x\n",
184   - query, bios_return.return_code);
  189 + query, bios_return->return_code);
185 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 203 kfree(obj);
192 204 return 0;
193 205 }
... ... @@ -196,7 +208,7 @@
196 208 {
197 209 int state = 0;
198 210 int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state,
199   - sizeof(state));
  211 + sizeof(state), sizeof(state));
200 212 if (ret)
201 213 return -EINVAL;
202 214 return state;
... ... @@ -206,7 +218,7 @@
206 218 {
207 219 int state = 0;
208 220 int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state,
209   - sizeof(state));
  221 + sizeof(state), sizeof(state));
210 222 if (ret)
211 223 return -EINVAL;
212 224 return state;
... ... @@ -216,7 +228,7 @@
216 228 {
217 229 int state = 0;
218 230 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state,
219   - sizeof(state));
  231 + sizeof(state), sizeof(state));
220 232 if (ret)
221 233 return -EINVAL;
222 234 return state;
... ... @@ -226,7 +238,7 @@
226 238 {
227 239 int state = 0;
228 240 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state,
229   - sizeof(state));
  241 + sizeof(state), sizeof(state));
230 242  
231 243 if (ret)
232 244 return -EINVAL;
... ... @@ -238,7 +250,7 @@
238 250 {
239 251 int state = 0;
240 252 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state,
241   - sizeof(state));
  253 + sizeof(state), sizeof(state));
242 254 if (ret)
243 255 return ret;
244 256  
... ... @@ -252,7 +264,7 @@
252 264 int ret;
253 265  
254 266 ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1,
255   - &query, sizeof(query));
  267 + &query, sizeof(query), 0);
256 268 if (ret)
257 269 return -EINVAL;
258 270 return 0;
... ... @@ -267,7 +279,8 @@
267 279 int wireless = 0;
268 280 int mask;
269 281 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
270   - &wireless, sizeof(wireless));
  282 + &wireless, sizeof(wireless),
  283 + sizeof(wireless));
271 284 /* TBD: Pass error */
272 285  
273 286 mask = 0x200 << (r * 8);
... ... @@ -283,7 +296,8 @@
283 296 int wireless = 0;
284 297 int mask;
285 298 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
286   - &wireless, sizeof(wireless));
  299 + &wireless, sizeof(wireless),
  300 + sizeof(wireless));
287 301 /* TBD: Pass error */
288 302  
289 303 mask = 0x800 << (r * 8);
... ... @@ -344,7 +358,7 @@
344 358 {
345 359 u32 tmp = simple_strtoul(buf, NULL, 10);
346 360 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp,
347   - sizeof(tmp));
  361 + sizeof(tmp), sizeof(tmp));
348 362 if (ret)
349 363 return -EINVAL;
350 364  
... ... @@ -417,6 +431,7 @@
417 431 case HPWMI_BEZEL_BUTTON:
418 432 ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
419 433 &key_code,
  434 + sizeof(key_code),
420 435 sizeof(key_code));
421 436 if (ret)
422 437 break;
... ... @@ -523,7 +538,7 @@
523 538 int wireless = 0;
524 539  
525 540 err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless,
526   - sizeof(wireless));
  541 + sizeof(wireless), sizeof(wireless));
527 542 if (err)
528 543 return err;
529 544