~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise

« back to all changes in this revision

Viewing changes to drivers/platform/x86/hp-wmi.c

  • Committer: Bazaar Package Importer
  • Author(s): Paolo Pisati
  • Date: 2011-06-29 15:23:51 UTC
  • mfrom: (26.1.1 natty-proposed)
  • Revision ID: james.westby@ubuntu.com-20110629152351-xs96tm303d95rpbk
Tags: 3.0.0-1200.2
* Rebased against 3.0.0-6.7
* BSP from TI based on 3.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 * HP WMI hotkeys
3
3
 *
4
4
 * Copyright (C) 2008 Red Hat <mjg@redhat.com>
 
5
 * Copyright (C) 2010, 2011 Anssi Hannula <anssi.hannula@iki.fi>
5
6
 *
6
7
 * Portions based on wistron_btns.c:
7
8
 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
23
24
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24
25
 */
25
26
 
 
27
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
28
 
26
29
#include <linux/kernel.h>
27
30
#include <linux/module.h>
28
31
#include <linux/init.h>
51
54
#define HPWMI_HARDWARE_QUERY 0x4
52
55
#define HPWMI_WIRELESS_QUERY 0x5
53
56
#define HPWMI_HOTKEY_QUERY 0xc
54
 
 
55
 
#define PREFIX "HP WMI: "
56
 
#define UNIMP "Unimplemented "
 
57
#define HPWMI_WIRELESS2_QUERY 0x1b
57
58
 
58
59
enum hp_wmi_radio {
59
60
        HPWMI_WIFI = 0,
86
87
struct bios_return {
87
88
        u32 sigpass;
88
89
        u32 return_code;
89
 
        u32 value;
 
90
};
 
91
 
 
92
enum hp_return_value {
 
93
        HPWMI_RET_WRONG_SIGNATURE       = 0x02,
 
94
        HPWMI_RET_UNKNOWN_COMMAND       = 0x03,
 
95
        HPWMI_RET_UNKNOWN_CMDTYPE       = 0x04,
 
96
        HPWMI_RET_INVALID_PARAMETERS    = 0x05,
 
97
};
 
98
 
 
99
enum hp_wireless2_bits {
 
100
        HPWMI_POWER_STATE       = 0x01,
 
101
        HPWMI_POWER_SOFT        = 0x02,
 
102
        HPWMI_POWER_BIOS        = 0x04,
 
103
        HPWMI_POWER_HARD        = 0x08,
 
104
};
 
105
 
 
106
#define IS_HWBLOCKED(x) ((x & (HPWMI_POWER_BIOS | HPWMI_POWER_HARD)) \
 
107
                         != (HPWMI_POWER_BIOS | HPWMI_POWER_HARD))
 
108
#define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT)
 
109
 
 
110
struct bios_rfkill2_device_state {
 
111
        u8 radio_type;
 
112
        u8 bus_type;
 
113
        u16 vendor_id;
 
114
        u16 product_id;
 
115
        u16 subsys_vendor_id;
 
116
        u16 subsys_product_id;
 
117
        u8 rfkill_id;
 
118
        u8 power;
 
119
        u8 unknown[4];
 
120
};
 
121
 
 
122
/* 7 devices fit into the 128 byte buffer */
 
123
#define HPWMI_MAX_RFKILL2_DEVICES       7
 
124
 
 
125
struct bios_rfkill2_state {
 
126
        u8 unknown[7];
 
127
        u8 count;
 
128
        u8 pad[8];
 
129
        struct bios_rfkill2_device_state device[HPWMI_MAX_RFKILL2_DEVICES];
90
130
};
91
131
 
92
132
static const struct key_entry hp_wmi_keymap[] = {
108
148
static struct rfkill *bluetooth_rfkill;
109
149
static struct rfkill *wwan_rfkill;
110
150
 
 
151
struct rfkill2_device {
 
152
        u8 id;
 
153
        int num;
 
154
        struct rfkill *rfkill;
 
155
};
 
156
 
 
157
static int rfkill2_count;
 
158
static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES];
 
159
 
111
160
static const struct dev_pm_ops hp_wmi_pm_ops = {
112
161
        .resume  = hp_wmi_resume_handler,
113
162
        .restore  = hp_wmi_resume_handler,
129
178
 * query:       The commandtype -> What should be queried
130
179
 * write:       The command -> 0 read, 1 write, 3 ODM specific
131
180
 * buffer:      Buffer used as input and/or output
132
 
 * buffersize:  Size of buffer
 
181
 * insize:      Size of input buffer
 
182
 * outsize:     Size of output buffer
133
183
 *
134
184
 * returns zero on success
135
185
 *         an HP WMI query specific error code (which is positive)
140
190
 *       size. E.g. Battery info query (0x7) is defined to have 1 byte input
141
191
 *       and 128 byte output. The caller would do:
142
192
 *       buffer = kzalloc(128, GFP_KERNEL);
143
 
 *       ret = hp_wmi_perform_query(0x7, 0, buffer, 128)
 
193
 *       ret = hp_wmi_perform_query(0x7, 0, buffer, 1, 128)
144
194
 */
145
 
static int hp_wmi_perform_query(int query, int write, u32 *buffer,
146
 
                                int buffersize)
 
195
static int hp_wmi_perform_query(int query, int write, void *buffer,
 
196
                                int insize, int outsize)
147
197
{
148
 
        struct bios_return bios_return;
149
 
        acpi_status status;
 
198
        struct bios_return *bios_return;
 
199
        int actual_outsize;
150
200
        union acpi_object *obj;
151
201
        struct bios_args args = {
152
202
                .signature = 0x55434553,
153
203
                .command = write ? 0x2 : 0x1,
154
204
                .commandtype = query,
155
 
                .datasize = buffersize,
156
 
                .data = *buffer,
 
205
                .datasize = insize,
 
206
                .data = 0,
157
207
        };
158
208
        struct acpi_buffer input = { sizeof(struct bios_args), &args };
159
209
        struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
160
 
 
161
 
        status = wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output);
 
210
        u32 rc;
 
211
 
 
212
        if (WARN_ON(insize > sizeof(args.data)))
 
213
                return -EINVAL;
 
214
        memcpy(&args.data, buffer, insize);
 
215
 
 
216
        wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output);
162
217
 
163
218
        obj = output.pointer;
164
219
 
169
224
                return -EINVAL;
170
225
        }
171
226
 
172
 
        bios_return = *((struct bios_return *)obj->buffer.pointer);
173
 
 
174
 
        memcpy(buffer, &bios_return.value, sizeof(bios_return.value));
175
 
 
 
227
        bios_return = (struct bios_return *)obj->buffer.pointer;
 
228
        rc = bios_return->return_code;
 
229
 
 
230
        if (rc) {
 
231
                if (rc != HPWMI_RET_UNKNOWN_CMDTYPE)
 
232
                        pr_warn("query 0x%x returned error 0x%x\n", query, rc);
 
233
                kfree(obj);
 
234
                return rc;
 
235
        }
 
236
 
 
237
        if (!outsize) {
 
238
                /* ignore output data */
 
239
                kfree(obj);
 
240
                return 0;
 
241
        }
 
242
 
 
243
        actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return)));
 
244
        memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize);
 
245
        memset(buffer + actual_outsize, 0, outsize - actual_outsize);
176
246
        kfree(obj);
177
247
        return 0;
178
248
}
181
251
{
182
252
        int state = 0;
183
253
        int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state,
184
 
                                       sizeof(state));
 
254
                                       sizeof(state), sizeof(state));
185
255
        if (ret)
186
256
                return -EINVAL;
187
257
        return state;
191
261
{
192
262
        int state = 0;
193
263
        int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state,
194
 
                                       sizeof(state));
 
264
                                       sizeof(state), sizeof(state));
195
265
        if (ret)
196
266
                return -EINVAL;
197
267
        return state;
201
271
{
202
272
        int state = 0;
203
273
        int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state,
204
 
                                       sizeof(state));
 
274
                                       sizeof(state), sizeof(state));
205
275
        if (ret)
206
276
                return -EINVAL;
207
277
        return state;
211
281
{
212
282
        int state = 0;
213
283
        int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state,
214
 
                                       sizeof(state));
 
284
                                       sizeof(state), sizeof(state));
215
285
 
216
286
        if (ret)
217
287
                return -EINVAL;
223
293
{
224
294
        int state = 0;
225
295
        int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state,
226
 
                                       sizeof(state));
 
296
                                       sizeof(state), sizeof(state));
227
297
        if (ret)
228
298
                return ret;
229
299
 
237
307
        int ret;
238
308
 
239
309
        ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1,
240
 
                                   &query, sizeof(query));
 
310
                                   &query, sizeof(query), 0);
241
311
        if (ret)
242
312
                return -EINVAL;
243
313
        return 0;
252
322
        int wireless = 0;
253
323
        int mask;
254
324
        hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
255
 
                             &wireless, sizeof(wireless));
 
325
                             &wireless, sizeof(wireless),
 
326
                             sizeof(wireless));
256
327
        /* TBD: Pass error */
257
328
 
258
329
        mask = 0x200 << (r * 8);
268
339
        int wireless = 0;
269
340
        int mask;
270
341
        hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
271
 
                             &wireless, sizeof(wireless));
 
342
                             &wireless, sizeof(wireless),
 
343
                             sizeof(wireless));
272
344
        /* TBD: Pass error */
273
345
 
274
346
        mask = 0x800 << (r * 8);
279
351
                return true;
280
352
}
281
353
 
 
354
static int hp_wmi_rfkill2_set_block(void *data, bool blocked)
 
355
{
 
356
        int rfkill_id = (int)(long)data;
 
357
        char buffer[4] = { 0x01, 0x00, rfkill_id, !blocked };
 
358
 
 
359
        if (hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 1,
 
360
                                   buffer, sizeof(buffer), 0))
 
361
                return -EINVAL;
 
362
        return 0;
 
363
}
 
364
 
 
365
static const struct rfkill_ops hp_wmi_rfkill2_ops = {
 
366
        .set_block = hp_wmi_rfkill2_set_block,
 
367
};
 
368
 
 
369
static int hp_wmi_rfkill2_refresh(void)
 
370
{
 
371
        int err, i;
 
372
        struct bios_rfkill2_state state;
 
373
 
 
374
        err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state,
 
375
                                   0, sizeof(state));
 
376
        if (err)
 
377
                return err;
 
378
 
 
379
        for (i = 0; i < rfkill2_count; i++) {
 
380
                int num = rfkill2[i].num;
 
381
                struct bios_rfkill2_device_state *devstate;
 
382
                devstate = &state.device[num];
 
383
 
 
384
                if (num >= state.count ||
 
385
                    devstate->rfkill_id != rfkill2[i].id) {
 
386
                        pr_warn("power configuration of the wireless devices unexpectedly changed\n");
 
387
                        continue;
 
388
                }
 
389
 
 
390
                rfkill_set_states(rfkill2[i].rfkill,
 
391
                                  IS_SWBLOCKED(devstate->power),
 
392
                                  IS_HWBLOCKED(devstate->power));
 
393
        }
 
394
 
 
395
        return 0;
 
396
}
 
397
 
282
398
static ssize_t show_display(struct device *dev, struct device_attribute *attr,
283
399
                            char *buf)
284
400
{
329
445
{
330
446
        u32 tmp = simple_strtoul(buf, NULL, 10);
331
447
        int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp,
332
 
                                       sizeof(tmp));
 
448
                                       sizeof(tmp), sizeof(tmp));
333
449
        if (ret)
334
450
                return -EINVAL;
335
451
 
353
469
 
354
470
        status = wmi_get_event_data(value, &response);
355
471
        if (status != AE_OK) {
356
 
                printk(KERN_INFO PREFIX "bad event status 0x%x\n", status);
 
472
                pr_info("bad event status 0x%x\n", status);
357
473
                return;
358
474
        }
359
475
 
362
478
        if (!obj)
363
479
                return;
364
480
        if (obj->type != ACPI_TYPE_BUFFER) {
365
 
                printk(KERN_INFO "hp-wmi: Unknown response received %d\n",
366
 
                       obj->type);
 
481
                pr_info("Unknown response received %d\n", obj->type);
367
482
                kfree(obj);
368
483
                return;
369
484
        }
380
495
                event_id = *location;
381
496
                event_data = *(location + 2);
382
497
        } else {
383
 
                printk(KERN_INFO "hp-wmi: Unknown buffer length %d\n",
384
 
                       obj->buffer.length);
 
498
                pr_info("Unknown buffer length %d\n", obj->buffer.length);
385
499
                kfree(obj);
386
500
                return;
387
501
        }
402
516
        case HPWMI_BEZEL_BUTTON:
403
517
                ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
404
518
                                           &key_code,
 
519
                                           sizeof(key_code),
405
520
                                           sizeof(key_code));
406
521
                if (ret)
407
522
                        break;
408
523
 
409
524
                if (!sparse_keymap_report_event(hp_wmi_input_dev,
410
525
                                                key_code, 1, true))
411
 
                        printk(KERN_INFO PREFIX "Unknown key code - 0x%x\n",
412
 
                               key_code);
 
526
                        pr_info("Unknown key code - 0x%x\n", key_code);
413
527
                break;
414
528
        case HPWMI_WIRELESS:
 
529
                if (rfkill2_count) {
 
530
                        hp_wmi_rfkill2_refresh();
 
531
                        break;
 
532
                }
 
533
 
415
534
                if (wifi_rfkill)
416
535
                        rfkill_set_states(wifi_rfkill,
417
536
                                          hp_wmi_get_sw_state(HPWMI_WIFI),
426
545
                                          hp_wmi_get_hw_state(HPWMI_WWAN));
427
546
                break;
428
547
        case HPWMI_CPU_BATTERY_THROTTLE:
429
 
                printk(KERN_INFO PREFIX UNIMP "CPU throttle because of 3 Cell"
430
 
                       " battery event detected\n");
 
548
                pr_info("Unimplemented CPU throttle because of 3 Cell battery event detected\n");
431
549
                break;
432
550
        case HPWMI_LOCK_SWITCH:
433
551
                break;
434
552
        default:
435
 
                printk(KERN_INFO PREFIX "Unknown event_id - %d - 0x%x\n",
436
 
                       event_id, event_data);
 
553
                pr_info("Unknown event_id - %d - 0x%x\n", event_id, event_data);
437
554
                break;
438
555
        }
439
556
}
502
619
        device_remove_file(&device->dev, &dev_attr_tablet);
503
620
}
504
621
 
505
 
static int __devinit hp_wmi_bios_setup(struct platform_device *device)
 
622
static int __devinit hp_wmi_rfkill_setup(struct platform_device *device)
506
623
{
507
624
        int err;
508
625
        int wireless = 0;
509
626
 
510
627
        err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless,
511
 
                                   sizeof(wireless));
 
628
                                   sizeof(wireless), sizeof(wireless));
512
629
        if (err)
513
630
                return err;
514
631
 
515
 
        err = device_create_file(&device->dev, &dev_attr_display);
516
 
        if (err)
517
 
                goto add_sysfs_error;
518
 
        err = device_create_file(&device->dev, &dev_attr_hddtemp);
519
 
        if (err)
520
 
                goto add_sysfs_error;
521
 
        err = device_create_file(&device->dev, &dev_attr_als);
522
 
        if (err)
523
 
                goto add_sysfs_error;
524
 
        err = device_create_file(&device->dev, &dev_attr_dock);
525
 
        if (err)
526
 
                goto add_sysfs_error;
527
 
        err = device_create_file(&device->dev, &dev_attr_tablet);
528
 
        if (err)
529
 
                goto add_sysfs_error;
530
 
 
531
632
        if (wireless & 0x1) {
532
633
                wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
533
634
                                           RFKILL_TYPE_WLAN,
573
674
        return 0;
574
675
register_wwan_err:
575
676
        rfkill_destroy(wwan_rfkill);
 
677
        wwan_rfkill = NULL;
576
678
        if (bluetooth_rfkill)
577
679
                rfkill_unregister(bluetooth_rfkill);
578
680
register_bluetooth_error:
579
681
        rfkill_destroy(bluetooth_rfkill);
 
682
        bluetooth_rfkill = NULL;
580
683
        if (wifi_rfkill)
581
684
                rfkill_unregister(wifi_rfkill);
582
685
register_wifi_error:
583
686
        rfkill_destroy(wifi_rfkill);
 
687
        wifi_rfkill = NULL;
 
688
        return err;
 
689
}
 
690
 
 
691
static int __devinit hp_wmi_rfkill2_setup(struct platform_device *device)
 
692
{
 
693
        int err, i;
 
694
        struct bios_rfkill2_state state;
 
695
        err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state,
 
696
                                   0, sizeof(state));
 
697
        if (err)
 
698
                return err;
 
699
 
 
700
        if (state.count > HPWMI_MAX_RFKILL2_DEVICES) {
 
701
                pr_warn("unable to parse 0x1b query output\n");
 
702
                return -EINVAL;
 
703
        }
 
704
 
 
705
        for (i = 0; i < state.count; i++) {
 
706
                struct rfkill *rfkill;
 
707
                enum rfkill_type type;
 
708
                char *name;
 
709
                switch (state.device[i].radio_type) {
 
710
                case HPWMI_WIFI:
 
711
                        type = RFKILL_TYPE_WLAN;
 
712
                        name = "hp-wifi";
 
713
                        break;
 
714
                case HPWMI_BLUETOOTH:
 
715
                        type = RFKILL_TYPE_BLUETOOTH;
 
716
                        name = "hp-bluetooth";
 
717
                        break;
 
718
                case HPWMI_WWAN:
 
719
                        type = RFKILL_TYPE_WWAN;
 
720
                        name = "hp-wwan";
 
721
                        break;
 
722
                default:
 
723
                        pr_warn("unknown device type 0x%x\n",
 
724
                                state.device[i].radio_type);
 
725
                        continue;
 
726
                }
 
727
 
 
728
                if (!state.device[i].vendor_id) {
 
729
                        pr_warn("zero device %d while %d reported\n",
 
730
                                i, state.count);
 
731
                        continue;
 
732
                }
 
733
 
 
734
                rfkill = rfkill_alloc(name, &device->dev, type,
 
735
                                      &hp_wmi_rfkill2_ops, (void *)(long)i);
 
736
                if (!rfkill) {
 
737
                        err = -ENOMEM;
 
738
                        goto fail;
 
739
                }
 
740
 
 
741
                rfkill2[rfkill2_count].id = state.device[i].rfkill_id;
 
742
                rfkill2[rfkill2_count].num = i;
 
743
                rfkill2[rfkill2_count].rfkill = rfkill;
 
744
 
 
745
                rfkill_init_sw_state(rfkill,
 
746
                                     IS_SWBLOCKED(state.device[i].power));
 
747
                rfkill_set_hw_state(rfkill,
 
748
                                    IS_HWBLOCKED(state.device[i].power));
 
749
 
 
750
                if (!(state.device[i].power & HPWMI_POWER_BIOS))
 
751
                        pr_info("device %s blocked by BIOS\n", name);
 
752
 
 
753
                err = rfkill_register(rfkill);
 
754
                if (err) {
 
755
                        rfkill_destroy(rfkill);
 
756
                        goto fail;
 
757
                }
 
758
 
 
759
                rfkill2_count++;
 
760
        }
 
761
 
 
762
        return 0;
 
763
fail:
 
764
        for (; rfkill2_count > 0; rfkill2_count--) {
 
765
                rfkill_unregister(rfkill2[rfkill2_count - 1].rfkill);
 
766
                rfkill_destroy(rfkill2[rfkill2_count - 1].rfkill);
 
767
        }
 
768
        return err;
 
769
}
 
770
 
 
771
static int __devinit hp_wmi_bios_setup(struct platform_device *device)
 
772
{
 
773
        int err;
 
774
 
 
775
        /* clear detected rfkill devices */
 
776
        wifi_rfkill = NULL;
 
777
        bluetooth_rfkill = NULL;
 
778
        wwan_rfkill = NULL;
 
779
        rfkill2_count = 0;
 
780
 
 
781
        if (hp_wmi_rfkill_setup(device))
 
782
                hp_wmi_rfkill2_setup(device);
 
783
 
 
784
        err = device_create_file(&device->dev, &dev_attr_display);
 
785
        if (err)
 
786
                goto add_sysfs_error;
 
787
        err = device_create_file(&device->dev, &dev_attr_hddtemp);
 
788
        if (err)
 
789
                goto add_sysfs_error;
 
790
        err = device_create_file(&device->dev, &dev_attr_als);
 
791
        if (err)
 
792
                goto add_sysfs_error;
 
793
        err = device_create_file(&device->dev, &dev_attr_dock);
 
794
        if (err)
 
795
                goto add_sysfs_error;
 
796
        err = device_create_file(&device->dev, &dev_attr_tablet);
 
797
        if (err)
 
798
                goto add_sysfs_error;
 
799
        return 0;
 
800
 
584
801
add_sysfs_error:
585
802
        cleanup_sysfs(device);
586
803
        return err;
588
805
 
589
806
static int __exit hp_wmi_bios_remove(struct platform_device *device)
590
807
{
 
808
        int i;
591
809
        cleanup_sysfs(device);
592
810
 
 
811
        for (i = 0; i < rfkill2_count; i++) {
 
812
                rfkill_unregister(rfkill2[i].rfkill);
 
813
                rfkill_destroy(rfkill2[i].rfkill);
 
814
        }
 
815
 
593
816
        if (wifi_rfkill) {
594
817
                rfkill_unregister(wifi_rfkill);
595
818
                rfkill_destroy(wifi_rfkill);
622
845
                input_sync(hp_wmi_input_dev);
623
846
        }
624
847
 
 
848
        if (rfkill2_count)
 
849
                hp_wmi_rfkill2_refresh();
 
850
 
625
851
        if (wifi_rfkill)
626
852
                rfkill_set_states(wifi_rfkill,
627
853
                                  hp_wmi_get_sw_state(HPWMI_WIFI),