--- linux-2.6/drivers/misc/fujitsu-laptop.c.orig 2008-12-09 15:19:19.000000000 +0000 +++ linux-2.6/drivers/misc/fujitsu-laptop.c 2008-12-12 01:20:07.000000000 +0000 @@ -3,6 +3,7 @@ /* Copyright (C) 2007,2008 Jonathan Woithe Copyright (C) 2008 Peter Gruber + Copyright (C) 2008 Tony Vroon Based on earlier work: Copyright (C) 2003 Shane Spencer Adrian Yee @@ -66,7 +67,7 @@ #include #include -#define FUJITSU_DRIVER_VERSION "0.4.3" +#define FUJITSU_DRIVER_VERSION "0.5.0" #define FUJITSU_LCD_N_LEVELS 8 @@ -83,6 +84,12 @@ #define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86 #define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87 +/* FUNC interface - command values */ +#define FUNC_RFKILL 0x1000 +#define FUNC_LEDS 0x1001 +#define FUNC_BUTTONS 0x1002 +#define FUNC_BACKLIGHT 0x1004 + /* Hotkey details */ #define KEY1_CODE 0x410 /* codes for the keys in the GIRB register */ #define KEY2_CODE 0x411 @@ -145,8 +152,7 @@ struct platform_device *pf_device; struct kfifo *fifo; spinlock_t fifo_lock; - - unsigned int irb; /* info about the pressed buttons */ + int rfkill_state; }; static struct fujitsu_hotkey_t *fujitsu_hotkey; @@ -160,6 +166,54 @@ static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data); +/* Fujitsu ACPI interface function */ + +static int call_fujex_func(int cmd, int arg0, int arg1, int arg2) +{ + acpi_status status = AE_OK; + union acpi_object params[4] = { + { .type = ACPI_TYPE_INTEGER }, + { .type = ACPI_TYPE_INTEGER }, + { .type = ACPI_TYPE_INTEGER }, + { .type = ACPI_TYPE_INTEGER } + }; + struct acpi_object_list arg_list = { 4, ¶ms[0] }; + struct acpi_buffer output; + union acpi_object out_obj; + acpi_handle handle = NULL; + + status = acpi_get_handle(fujitsu_hotkey->acpi_handle, "FUNC", &handle); + if (ACPI_FAILURE(status)) { + vdbg_printk(FUJLAPTOP_DBG_ERROR, "FUNC interface is not present\n"); + return -ENODEV; + } + + params[0].integer.value = cmd; + params[1].integer.value = arg0; + params[2].integer.value = arg1; + params[3].integer.value = arg2; + + output.length = sizeof(out_obj); + output.pointer = &out_obj; + + status = acpi_evaluate_object(handle, NULL, &arg_list, &output); + if (ACPI_FAILURE(status)) { + vdbg_printk(FUJLAPTOP_DBG_WARN, "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) call failed\n", + cmd, arg0, arg1, arg2); + return -ENODEV; + } + + if (out_obj.type != ACPI_TYPE_INTEGER) { + vdbg_printk(FUJLAPTOP_DBG_WARN, "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) did not return an integer\n", + cmd, arg0, arg1, arg2); + return -ENODEV; + } + + vdbg_printk(FUJLAPTOP_DBG_TRACE, "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n", cmd, arg0, arg1, + arg2, (int)out_obj.integer.value); + return out_obj.integer.value; +} + /* Hardware access for LCD brightness control */ static int set_lcd_level(int level) @@ -382,26 +436,6 @@ return count; } -/* Hardware access for hotkey device */ - -static int get_irb(void) -{ - unsigned long long state = 0; - acpi_status status = AE_OK; - - vdbg_printk(FUJLAPTOP_DBG_TRACE, "Get irb\n"); - - status = - acpi_evaluate_integer(fujitsu_hotkey->acpi_handle, "GIRB", NULL, - &state); - if (status < 0) - return status; - - fujitsu_hotkey->irb = state; - - return fujitsu_hotkey->irb; -} - static ssize_t ignore_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -771,7 +805,8 @@ input->id.bustype = BUS_HOST; input->id.product = 0x06; input->dev.parent = &device->dev; - input->evbit[0] = BIT(EV_KEY); + + set_bit(EV_KEY, input->evbit); set_bit(fujitsu->keycode1, input->keybit); set_bit(fujitsu->keycode2, input->keybit); set_bit(fujitsu->keycode3, input->keybit); @@ -804,9 +839,17 @@ } i = 0; /* Discard hotkey ringbuffer */ - while (get_irb() != 0 && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) ; + while (call_fujex_func(FUNC_BUTTONS,0x01,0x0,0x0) != 0 && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) ; vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i); + /* Sync RFKILL state */ + fujitsu_hotkey->rfkill_state = + call_fujex_func(FUNC_RFKILL,0x04,0x0,0x0); + + /* Suspect this is a keymap of the application panel, print it */ + vdbg_printk(FUJLAPTOP_DBG_INFO, "BTNI: [0x%x]", + call_fujex_func(FUNC_BUTTONS,0x0,0x0,0x0)); + return result; end: @@ -848,16 +891,25 @@ struct input_dev *input; int keycode, keycode_r; unsigned int irb = 1; - int i, status; + int i, status, rfkill_new; input = fujitsu_hotkey->input; - vdbg_printk(FUJLAPTOP_DBG_TRACE, "Hotkey event\n"); + rfkill_new = call_fujex_func(FUNC_RFKILL,0x04,0x0,0x0); + if (fujitsu_hotkey->rfkill_state != rfkill_new) { + vdbg_printk(FUJLAPTOP_DBG_INFO, + "radios: [%s], lid: [%s], docked: [%s]\n", + (rfkill_new & 0x20) ? "on" : "killed", + (rfkill_new & 0x100) ? "open" : "closed", + (rfkill_new & 0x200) ? "yes" : "no"); + } + + fujitsu_hotkey->rfkill_state = rfkill_new; switch (event) { case ACPI_FUJITSU_NOTIFY_CODE1: i = 0; - while ((irb = get_irb()) != 0 + while ((irb = call_fujex_func(FUNC_BUTTONS,0x01,0x0,0x0)) != 0 && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) { vdbg_printk(FUJLAPTOP_DBG_TRACE, "GIRB result [%x]\n", irb); @@ -1108,7 +1160,7 @@ MODULE_PARM_DESC(debug, "Sets debug level bit-mask"); #endif -MODULE_AUTHOR("Jonathan Woithe, Peter Gruber"); +MODULE_AUTHOR("Jonathan Woithe, Peter Gruber, Tony Vroon"); MODULE_DESCRIPTION("Fujitsu laptop extras support"); MODULE_VERSION(FUJITSU_DRIVER_VERSION); MODULE_LICENSE("GPL");