Showing error 1641

User: Jiri Slaby
Error type: Invalid Pointer Dereference
Error type description: A pointer which is invalid is being dereferenced
File location: drivers/misc/hp-wmi.c
Line in file: 370
Project: Linux Kernel
Project version: 2.6.28
Tools: Smatch (1.59)
Entered: 2013-09-10 07:54:05 UTC


Source:

  1/*
  2 * HP WMI hotkeys
  3 *
  4 * Copyright (C) 2008 Red Hat <mjg@redhat.com>
  5 *
  6 * Portions based on wistron_btns.c:
  7 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
  8 * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
  9 * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
 10 *
 11 *  This program is free software; you can redistribute it and/or modify
 12 *  it under the terms of the GNU General Public License as published by
 13 *  the Free Software Foundation; either version 2 of the License, or
 14 *  (at your option) any later version.
 15 *
 16 *  This program is distributed in the hope that it will be useful,
 17 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 18 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 19 *  GNU General Public License for more details.
 20 *
 21 *  You should have received a copy of the GNU General Public License
 22 *  along with this program; if not, write to the Free Software
 23 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 24 */
 25
 26#include <linux/kernel.h>
 27#include <linux/module.h>
 28#include <linux/init.h>
 29#include <linux/types.h>
 30#include <linux/input.h>
 31#include <acpi/acpi_drivers.h>
 32#include <linux/platform_device.h>
 33#include <linux/acpi.h>
 34#include <linux/rfkill.h>
 35#include <linux/string.h>
 36
 37MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
 38MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
 39MODULE_LICENSE("GPL");
 40
 41MODULE_ALIAS("wmi:95F24279-4D7B-4334-9387-ACCDC67EF61C");
 42MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
 43
 44#define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C"
 45#define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4"
 46
 47#define HPWMI_DISPLAY_QUERY 0x1
 48#define HPWMI_HDDTEMP_QUERY 0x2
 49#define HPWMI_ALS_QUERY 0x3
 50#define HPWMI_DOCK_QUERY 0x4
 51#define HPWMI_WIRELESS_QUERY 0x5
 52#define HPWMI_HOTKEY_QUERY 0xc
 53
 54static int __init hp_wmi_bios_setup(struct platform_device *device);
 55static int __exit hp_wmi_bios_remove(struct platform_device *device);
 56
 57struct bios_args {
 58        u32 signature;
 59        u32 command;
 60        u32 commandtype;
 61        u32 datasize;
 62        u32 data;
 63};
 64
 65struct bios_return {
 66        u32 sigpass;
 67        u32 return_code;
 68        u32 value;
 69};
 70
 71struct key_entry {
 72        char type;                /* See KE_* below */
 73        u16 code;
 74        u16 keycode;
 75};
 76
 77enum { KE_KEY, KE_SW, KE_END };
 78
 79static struct key_entry hp_wmi_keymap[] = {
 80        {KE_SW, 0x01, SW_DOCK},
 81        {KE_KEY, 0x02, KEY_BRIGHTNESSUP},
 82        {KE_KEY, 0x03, KEY_BRIGHTNESSDOWN},
 83        {KE_KEY, 0x20e6, KEY_PROG1},
 84        {KE_KEY, 0x2142, KEY_MEDIA},
 85        {KE_KEY, 0x213b, KEY_INFO},
 86        {KE_KEY, 0x231b, KEY_HELP},
 87        {KE_END, 0}
 88};
 89
 90static struct input_dev *hp_wmi_input_dev;
 91static struct platform_device *hp_wmi_platform_dev;
 92
 93static struct rfkill *wifi_rfkill;
 94static struct rfkill *bluetooth_rfkill;
 95static struct rfkill *wwan_rfkill;
 96
 97static struct platform_driver hp_wmi_driver = {
 98        .driver = {
 99                   .name = "hp-wmi",
100                   .owner = THIS_MODULE,
101        },
102        .probe = hp_wmi_bios_setup,
103        .remove = hp_wmi_bios_remove,
104};
105
106static int hp_wmi_perform_query(int query, int write, int value)
107{
108        struct bios_return bios_return;
109        acpi_status status;
110        union acpi_object *obj;
111        struct bios_args args = {
112                .signature = 0x55434553,
113                .command = write ? 0x2 : 0x1,
114                .commandtype = query,
115                .datasize = write ? 0x4 : 0,
116                .data = value,
117        };
118        struct acpi_buffer input = { sizeof(struct bios_args), &args };
119        struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
120
121        status = wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output);
122
123        obj = output.pointer;
124
125        if (!obj || obj->type != ACPI_TYPE_BUFFER)
126                return -EINVAL;
127
128        bios_return = *((struct bios_return *)obj->buffer.pointer);
129        if (bios_return.return_code > 0)
130                return bios_return.return_code * -1;
131        else
132                return bios_return.value;
133}
134
135static int hp_wmi_display_state(void)
136{
137        return hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, 0);
138}
139
140static int hp_wmi_hddtemp_state(void)
141{
142        return hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, 0);
143}
144
145static int hp_wmi_als_state(void)
146{
147        return hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, 0);
148}
149
150static int hp_wmi_dock_state(void)
151{
152        return hp_wmi_perform_query(HPWMI_DOCK_QUERY, 0, 0);
153}
154
155static int hp_wmi_wifi_set(void *data, enum rfkill_state state)
156{
157        if (state)
158                return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x101);
159        else
160                return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x100);
161}
162
163static int hp_wmi_bluetooth_set(void *data, enum rfkill_state state)
164{
165        if (state)
166                return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x202);
167        else
168                return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x200);
169}
170
171static int hp_wmi_wwan_set(void *data, enum rfkill_state state)
172{
173        if (state)
174                return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x404);
175        else
176                return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x400);
177}
178
179static int hp_wmi_wifi_state(void)
180{
181        int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
182
183        if (wireless & 0x100)
184                return RFKILL_STATE_UNBLOCKED;
185        else
186                return RFKILL_STATE_SOFT_BLOCKED;
187}
188
189static int hp_wmi_bluetooth_state(void)
190{
191        int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
192
193        if (wireless & 0x10000)
194                return RFKILL_STATE_UNBLOCKED;
195        else
196                return RFKILL_STATE_SOFT_BLOCKED;
197}
198
199static int hp_wmi_wwan_state(void)
200{
201        int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
202
203        if (wireless & 0x1000000)
204                return RFKILL_STATE_UNBLOCKED;
205        else
206                return RFKILL_STATE_SOFT_BLOCKED;
207}
208
209static ssize_t show_display(struct device *dev, struct device_attribute *attr,
210                            char *buf)
211{
212        int value = hp_wmi_display_state();
213        if (value < 0)
214                return -EINVAL;
215        return sprintf(buf, "%d\n", value);
216}
217
218static ssize_t show_hddtemp(struct device *dev, struct device_attribute *attr,
219                            char *buf)
220{
221        int value = hp_wmi_hddtemp_state();
222        if (value < 0)
223                return -EINVAL;
224        return sprintf(buf, "%d\n", value);
225}
226
227static ssize_t show_als(struct device *dev, struct device_attribute *attr,
228                        char *buf)
229{
230        int value = hp_wmi_als_state();
231        if (value < 0)
232                return -EINVAL;
233        return sprintf(buf, "%d\n", value);
234}
235
236static ssize_t show_dock(struct device *dev, struct device_attribute *attr,
237                         char *buf)
238{
239        int value = hp_wmi_dock_state();
240        if (value < 0)
241                return -EINVAL;
242        return sprintf(buf, "%d\n", value);
243}
244
245static ssize_t set_als(struct device *dev, struct device_attribute *attr,
246                       const char *buf, size_t count)
247{
248        u32 tmp = simple_strtoul(buf, NULL, 10);
249        hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, tmp);
250        return count;
251}
252
253static DEVICE_ATTR(display, S_IRUGO, show_display, NULL);
254static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL);
255static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als);
256static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL);
257
258static struct key_entry *hp_wmi_get_entry_by_scancode(int code)
259{
260        struct key_entry *key;
261
262        for (key = hp_wmi_keymap; key->type != KE_END; key++)
263                if (code == key->code)
264                        return key;
265
266        return NULL;
267}
268
269static struct key_entry *hp_wmi_get_entry_by_keycode(int keycode)
270{
271        struct key_entry *key;
272
273        for (key = hp_wmi_keymap; key->type != KE_END; key++)
274                if (key->type == KE_KEY && keycode == key->keycode)
275                        return key;
276
277        return NULL;
278}
279
280static int hp_wmi_getkeycode(struct input_dev *dev, int scancode, int *keycode)
281{
282        struct key_entry *key = hp_wmi_get_entry_by_scancode(scancode);
283
284        if (key && key->type == KE_KEY) {
285                *keycode = key->keycode;
286                return 0;
287        }
288
289        return -EINVAL;
290}
291
292static int hp_wmi_setkeycode(struct input_dev *dev, int scancode, int keycode)
293{
294        struct key_entry *key;
295        int old_keycode;
296
297        if (keycode < 0 || keycode > KEY_MAX)
298                return -EINVAL;
299
300        key = hp_wmi_get_entry_by_scancode(scancode);
301        if (key && key->type == KE_KEY) {
302                old_keycode = key->keycode;
303                key->keycode = keycode;
304                set_bit(keycode, dev->keybit);
305                if (!hp_wmi_get_entry_by_keycode(old_keycode))
306                        clear_bit(old_keycode, dev->keybit);
307                return 0;
308        }
309
310        return -EINVAL;
311}
312
313static void hp_wmi_notify(u32 value, void *context)
314{
315        struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
316        static struct key_entry *key;
317        union acpi_object *obj;
318
319        wmi_get_event_data(value, &response);
320
321        obj = (union acpi_object *)response.pointer;
322
323        if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == 8) {
324                int eventcode = *((u8 *) obj->buffer.pointer);
325                if (eventcode == 0x4)
326                        eventcode = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
327                                                         0);
328                key = hp_wmi_get_entry_by_scancode(eventcode);
329                if (key) {
330                        switch (key->type) {
331                        case KE_KEY:
332                                input_report_key(hp_wmi_input_dev,
333                                                 key->keycode, 1);
334                                input_sync(hp_wmi_input_dev);
335                                input_report_key(hp_wmi_input_dev,
336                                                 key->keycode, 0);
337                                input_sync(hp_wmi_input_dev);
338                                break;
339                        case KE_SW:
340                                input_report_switch(hp_wmi_input_dev,
341                                                    key->keycode,
342                                                    hp_wmi_dock_state());
343                                input_sync(hp_wmi_input_dev);
344                                break;
345                        }
346                } else if (eventcode == 0x5) {
347                        if (wifi_rfkill)
348                                rfkill_force_state(wifi_rfkill,
349                                                   hp_wmi_wifi_state());
350                        if (bluetooth_rfkill)
351                                rfkill_force_state(bluetooth_rfkill,
352                                                   hp_wmi_bluetooth_state());
353                        if (wwan_rfkill)
354                                rfkill_force_state(wwan_rfkill,
355                                                   hp_wmi_wwan_state());
356                } else
357                        printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n",
358                               eventcode);
359        } else
360                printk(KERN_INFO "HP WMI: Unknown response received\n");
361}
362
363static int __init hp_wmi_input_setup(void)
364{
365        struct key_entry *key;
366        int err;
367
368        hp_wmi_input_dev = input_allocate_device();
369
370        hp_wmi_input_dev->name = "HP WMI hotkeys";
371        hp_wmi_input_dev->phys = "wmi/input0";
372        hp_wmi_input_dev->id.bustype = BUS_HOST;
373        hp_wmi_input_dev->getkeycode = hp_wmi_getkeycode;
374        hp_wmi_input_dev->setkeycode = hp_wmi_setkeycode;
375
376        for (key = hp_wmi_keymap; key->type != KE_END; key++) {
377                switch (key->type) {
378                case KE_KEY:
379                        set_bit(EV_KEY, hp_wmi_input_dev->evbit);
380                        set_bit(key->keycode, hp_wmi_input_dev->keybit);
381                        break;
382                case KE_SW:
383                        set_bit(EV_SW, hp_wmi_input_dev->evbit);
384                        set_bit(key->keycode, hp_wmi_input_dev->swbit);
385                        break;
386                }
387        }
388
389        err = input_register_device(hp_wmi_input_dev);
390
391        if (err) {
392                input_free_device(hp_wmi_input_dev);
393                return err;
394        }
395
396        return 0;
397}
398
399static void cleanup_sysfs(struct platform_device *device)
400{
401        device_remove_file(&device->dev, &dev_attr_display);
402        device_remove_file(&device->dev, &dev_attr_hddtemp);
403        device_remove_file(&device->dev, &dev_attr_als);
404        device_remove_file(&device->dev, &dev_attr_dock);
405}
406
407static int __init hp_wmi_bios_setup(struct platform_device *device)
408{
409        int err;
410        int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
411
412        err = device_create_file(&device->dev, &dev_attr_display);
413        if (err)
414                goto add_sysfs_error;
415        err = device_create_file(&device->dev, &dev_attr_hddtemp);
416        if (err)
417                goto add_sysfs_error;
418        err = device_create_file(&device->dev, &dev_attr_als);
419        if (err)
420                goto add_sysfs_error;
421        err = device_create_file(&device->dev, &dev_attr_dock);
422        if (err)
423                goto add_sysfs_error;
424
425        if (wireless & 0x1) {
426                wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN);
427                wifi_rfkill->name = "hp-wifi";
428                wifi_rfkill->state = hp_wmi_wifi_state();
429                wifi_rfkill->toggle_radio = hp_wmi_wifi_set;
430                wifi_rfkill->user_claim_unsupported = 1;
431                rfkill_register(wifi_rfkill);
432        }
433
434        if (wireless & 0x2) {
435                bluetooth_rfkill = rfkill_allocate(&device->dev,
436                                                   RFKILL_TYPE_BLUETOOTH);
437                bluetooth_rfkill->name = "hp-bluetooth";
438                bluetooth_rfkill->state = hp_wmi_bluetooth_state();
439                bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set;
440                bluetooth_rfkill->user_claim_unsupported = 1;
441                rfkill_register(bluetooth_rfkill);
442        }
443
444        if (wireless & 0x4) {
445                wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN);
446                wwan_rfkill->name = "hp-wwan";
447                wwan_rfkill->state = hp_wmi_wwan_state();
448                wwan_rfkill->toggle_radio = hp_wmi_wwan_set;
449                wwan_rfkill->user_claim_unsupported = 1;
450                rfkill_register(wwan_rfkill);
451        }
452
453        return 0;
454add_sysfs_error:
455        cleanup_sysfs(device);
456        return err;
457}
458
459static int __exit hp_wmi_bios_remove(struct platform_device *device)
460{
461        cleanup_sysfs(device);
462
463        if (wifi_rfkill)
464                rfkill_unregister(wifi_rfkill);
465        if (bluetooth_rfkill)
466                rfkill_unregister(bluetooth_rfkill);
467        if (wwan_rfkill)
468                rfkill_unregister(wwan_rfkill);
469
470        return 0;
471}
472
473static int __init hp_wmi_init(void)
474{
475        int err;
476
477        if (wmi_has_guid(HPWMI_EVENT_GUID)) {
478                err = wmi_install_notify_handler(HPWMI_EVENT_GUID,
479                                                 hp_wmi_notify, NULL);
480                if (!err)
481                        hp_wmi_input_setup();
482        }
483
484        if (wmi_has_guid(HPWMI_BIOS_GUID)) {
485                err = platform_driver_register(&hp_wmi_driver);
486                if (err)
487                        return 0;
488                hp_wmi_platform_dev = platform_device_alloc("hp-wmi", -1);
489                if (!hp_wmi_platform_dev) {
490                        platform_driver_unregister(&hp_wmi_driver);
491                        return 0;
492                }
493                platform_device_add(hp_wmi_platform_dev);
494        }
495
496        return 0;
497}
498
499static void __exit hp_wmi_exit(void)
500{
501        if (wmi_has_guid(HPWMI_EVENT_GUID)) {
502                wmi_remove_notify_handler(HPWMI_EVENT_GUID);
503                input_unregister_device(hp_wmi_input_dev);
504        }
505        if (hp_wmi_platform_dev) {
506                platform_device_del(hp_wmi_platform_dev);
507                platform_driver_unregister(&hp_wmi_driver);
508        }
509}
510
511module_init(hp_wmi_init);
512module_exit(hp_wmi_exit);