19caeb532SHerton Ronaldo Krzesinski /* 29caeb532SHerton Ronaldo Krzesinski * ACPI driver for Topstar notebooks (hotkeys support only) 39caeb532SHerton Ronaldo Krzesinski * 49caeb532SHerton Ronaldo Krzesinski * Copyright (c) 2009 Herton Ronaldo Krzesinski <herton@mandriva.com.br> 59caeb532SHerton Ronaldo Krzesinski * 69caeb532SHerton Ronaldo Krzesinski * Implementation inspired by existing x86 platform drivers, in special 79caeb532SHerton Ronaldo Krzesinski * asus/eepc/fujitsu-laptop, thanks to their authors 89caeb532SHerton Ronaldo Krzesinski * 99caeb532SHerton Ronaldo Krzesinski * This program is free software; you can redistribute it and/or modify 109caeb532SHerton Ronaldo Krzesinski * it under the terms of the GNU General Public License version 2 as 119caeb532SHerton Ronaldo Krzesinski * published by the Free Software Foundation. 129caeb532SHerton Ronaldo Krzesinski */ 139caeb532SHerton Ronaldo Krzesinski 149caeb532SHerton Ronaldo Krzesinski #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 159caeb532SHerton Ronaldo Krzesinski 169caeb532SHerton Ronaldo Krzesinski #include <linux/kernel.h> 179caeb532SHerton Ronaldo Krzesinski #include <linux/module.h> 189caeb532SHerton Ronaldo Krzesinski #include <linux/init.h> 195a0e3ad6STejun Heo #include <linux/slab.h> 209caeb532SHerton Ronaldo Krzesinski #include <linux/acpi.h> 219caeb532SHerton Ronaldo Krzesinski #include <linux/input.h> 2297490f1cSDmitry Torokhov #include <linux/input/sparse-keymap.h> 239caeb532SHerton Ronaldo Krzesinski 249caeb532SHerton Ronaldo Krzesinski #define ACPI_TOPSTAR_CLASS "topstar" 259caeb532SHerton Ronaldo Krzesinski 269caeb532SHerton Ronaldo Krzesinski struct topstar_hkey { 279caeb532SHerton Ronaldo Krzesinski struct input_dev *inputdev; 289caeb532SHerton Ronaldo Krzesinski }; 299caeb532SHerton Ronaldo Krzesinski 3097490f1cSDmitry Torokhov static const struct key_entry topstar_keymap[] = { 3197490f1cSDmitry Torokhov { KE_KEY, 0x80, { KEY_BRIGHTNESSUP } }, 3297490f1cSDmitry Torokhov { KE_KEY, 0x81, { KEY_BRIGHTNESSDOWN } }, 3397490f1cSDmitry Torokhov { KE_KEY, 0x83, { KEY_VOLUMEUP } }, 3497490f1cSDmitry Torokhov { KE_KEY, 0x84, { KEY_VOLUMEDOWN } }, 3597490f1cSDmitry Torokhov { KE_KEY, 0x85, { KEY_MUTE } }, 3697490f1cSDmitry Torokhov { KE_KEY, 0x86, { KEY_SWITCHVIDEOMODE } }, 3797490f1cSDmitry Torokhov { KE_KEY, 0x87, { KEY_F13 } }, /* touchpad enable/disable key */ 3897490f1cSDmitry Torokhov { KE_KEY, 0x88, { KEY_WLAN } }, 3997490f1cSDmitry Torokhov { KE_KEY, 0x8a, { KEY_WWW } }, 4097490f1cSDmitry Torokhov { KE_KEY, 0x8b, { KEY_MAIL } }, 4197490f1cSDmitry Torokhov { KE_KEY, 0x8c, { KEY_MEDIA } }, 4297490f1cSDmitry Torokhov 4397490f1cSDmitry Torokhov /* Known non hotkey events don't handled or that we don't care yet */ 44bd038080SManuel Lauss { KE_IGNORE, 0x82, }, /* backlight event */ 4597490f1cSDmitry Torokhov { KE_IGNORE, 0x8e, }, 4697490f1cSDmitry Torokhov { KE_IGNORE, 0x8f, }, 4797490f1cSDmitry Torokhov { KE_IGNORE, 0x90, }, 4897490f1cSDmitry Torokhov 4997490f1cSDmitry Torokhov /* 5097490f1cSDmitry Torokhov * 'G key' generate two event codes, convert to only 5197490f1cSDmitry Torokhov * one event/key code for now, consider replacing by 5297490f1cSDmitry Torokhov * a switch (3G switch - SW_3G?) 5397490f1cSDmitry Torokhov */ 5497490f1cSDmitry Torokhov { KE_KEY, 0x96, { KEY_F14 } }, 5597490f1cSDmitry Torokhov { KE_KEY, 0x97, { KEY_F14 } }, 5697490f1cSDmitry Torokhov 5797490f1cSDmitry Torokhov { KE_END, 0 } 589caeb532SHerton Ronaldo Krzesinski }; 599caeb532SHerton Ronaldo Krzesinski 609caeb532SHerton Ronaldo Krzesinski static void acpi_topstar_notify(struct acpi_device *device, u32 event) 619caeb532SHerton Ronaldo Krzesinski { 629caeb532SHerton Ronaldo Krzesinski static bool dup_evnt[2]; 639caeb532SHerton Ronaldo Krzesinski bool *dup; 649caeb532SHerton Ronaldo Krzesinski struct topstar_hkey *hkey = acpi_driver_data(device); 659caeb532SHerton Ronaldo Krzesinski 669caeb532SHerton Ronaldo Krzesinski /* 0x83 and 0x84 key events comes duplicated... */ 679caeb532SHerton Ronaldo Krzesinski if (event == 0x83 || event == 0x84) { 689caeb532SHerton Ronaldo Krzesinski dup = &dup_evnt[event - 0x83]; 699caeb532SHerton Ronaldo Krzesinski if (*dup) { 709caeb532SHerton Ronaldo Krzesinski *dup = false; 719caeb532SHerton Ronaldo Krzesinski return; 729caeb532SHerton Ronaldo Krzesinski } 739caeb532SHerton Ronaldo Krzesinski *dup = true; 749caeb532SHerton Ronaldo Krzesinski } 759caeb532SHerton Ronaldo Krzesinski 7697490f1cSDmitry Torokhov if (!sparse_keymap_report_event(hkey->inputdev, event, 1, true)) 779caeb532SHerton Ronaldo Krzesinski pr_info("unknown event = 0x%02x\n", event); 789caeb532SHerton Ronaldo Krzesinski } 799caeb532SHerton Ronaldo Krzesinski 809caeb532SHerton Ronaldo Krzesinski static int acpi_topstar_fncx_switch(struct acpi_device *device, bool state) 819caeb532SHerton Ronaldo Krzesinski { 829caeb532SHerton Ronaldo Krzesinski acpi_status status; 839caeb532SHerton Ronaldo Krzesinski 84a7f6451fSZhang Rui status = acpi_execute_simple_method(device->handle, "FNCX", 85a7f6451fSZhang Rui state ? 0x86 : 0x87); 869caeb532SHerton Ronaldo Krzesinski if (ACPI_FAILURE(status)) { 879caeb532SHerton Ronaldo Krzesinski pr_err("Unable to switch FNCX notifications\n"); 889caeb532SHerton Ronaldo Krzesinski return -ENODEV; 899caeb532SHerton Ronaldo Krzesinski } 909caeb532SHerton Ronaldo Krzesinski 919caeb532SHerton Ronaldo Krzesinski return 0; 929caeb532SHerton Ronaldo Krzesinski } 939caeb532SHerton Ronaldo Krzesinski 949caeb532SHerton Ronaldo Krzesinski static int acpi_topstar_init_hkey(struct topstar_hkey *hkey) 959caeb532SHerton Ronaldo Krzesinski { 9697490f1cSDmitry Torokhov struct input_dev *input; 9797490f1cSDmitry Torokhov int error; 989caeb532SHerton Ronaldo Krzesinski 9997490f1cSDmitry Torokhov input = input_allocate_device(); 100b222cca6SJoe Perches if (!input) 10197490f1cSDmitry Torokhov return -ENOMEM; 1029caeb532SHerton Ronaldo Krzesinski 10397490f1cSDmitry Torokhov input->name = "Topstar Laptop extra buttons"; 10497490f1cSDmitry Torokhov input->phys = "topstar/input0"; 10597490f1cSDmitry Torokhov input->id.bustype = BUS_HOST; 10697490f1cSDmitry Torokhov 10797490f1cSDmitry Torokhov error = sparse_keymap_setup(input, topstar_keymap, NULL); 10897490f1cSDmitry Torokhov if (error) { 10997490f1cSDmitry Torokhov pr_err("Unable to setup input device keymap\n"); 11097490f1cSDmitry Torokhov goto err_free_dev; 11197490f1cSDmitry Torokhov } 11297490f1cSDmitry Torokhov 11397490f1cSDmitry Torokhov error = input_register_device(input); 11497490f1cSDmitry Torokhov if (error) { 11597490f1cSDmitry Torokhov pr_err("Unable to register input device\n"); 1163f2e1a32SMichał Kępień goto err_free_dev; 11797490f1cSDmitry Torokhov } 11897490f1cSDmitry Torokhov 11997490f1cSDmitry Torokhov hkey->inputdev = input; 1209caeb532SHerton Ronaldo Krzesinski return 0; 12197490f1cSDmitry Torokhov 12297490f1cSDmitry Torokhov err_free_dev: 12397490f1cSDmitry Torokhov input_free_device(input); 12497490f1cSDmitry Torokhov return error; 1259caeb532SHerton Ronaldo Krzesinski } 1269caeb532SHerton Ronaldo Krzesinski 1279caeb532SHerton Ronaldo Krzesinski static int acpi_topstar_add(struct acpi_device *device) 1289caeb532SHerton Ronaldo Krzesinski { 1299caeb532SHerton Ronaldo Krzesinski struct topstar_hkey *tps_hkey; 1309caeb532SHerton Ronaldo Krzesinski 1319caeb532SHerton Ronaldo Krzesinski tps_hkey = kzalloc(sizeof(struct topstar_hkey), GFP_KERNEL); 1329caeb532SHerton Ronaldo Krzesinski if (!tps_hkey) 1339caeb532SHerton Ronaldo Krzesinski return -ENOMEM; 1349caeb532SHerton Ronaldo Krzesinski 1359caeb532SHerton Ronaldo Krzesinski strcpy(acpi_device_name(device), "Topstar TPSACPI"); 1369caeb532SHerton Ronaldo Krzesinski strcpy(acpi_device_class(device), ACPI_TOPSTAR_CLASS); 1379caeb532SHerton Ronaldo Krzesinski 1389caeb532SHerton Ronaldo Krzesinski if (acpi_topstar_fncx_switch(device, true)) 1399caeb532SHerton Ronaldo Krzesinski goto add_err; 1409caeb532SHerton Ronaldo Krzesinski 1419caeb532SHerton Ronaldo Krzesinski if (acpi_topstar_init_hkey(tps_hkey)) 1429caeb532SHerton Ronaldo Krzesinski goto add_err; 1439caeb532SHerton Ronaldo Krzesinski 1449caeb532SHerton Ronaldo Krzesinski device->driver_data = tps_hkey; 1459caeb532SHerton Ronaldo Krzesinski return 0; 1469caeb532SHerton Ronaldo Krzesinski 1479caeb532SHerton Ronaldo Krzesinski add_err: 1489caeb532SHerton Ronaldo Krzesinski kfree(tps_hkey); 1499caeb532SHerton Ronaldo Krzesinski return -ENODEV; 1509caeb532SHerton Ronaldo Krzesinski } 1519caeb532SHerton Ronaldo Krzesinski 15251fac838SRafael J. Wysocki static int acpi_topstar_remove(struct acpi_device *device) 1539caeb532SHerton Ronaldo Krzesinski { 1549caeb532SHerton Ronaldo Krzesinski struct topstar_hkey *tps_hkey = acpi_driver_data(device); 1559caeb532SHerton Ronaldo Krzesinski 1569caeb532SHerton Ronaldo Krzesinski acpi_topstar_fncx_switch(device, false); 1579caeb532SHerton Ronaldo Krzesinski 1589caeb532SHerton Ronaldo Krzesinski input_unregister_device(tps_hkey->inputdev); 1599caeb532SHerton Ronaldo Krzesinski kfree(tps_hkey); 1609caeb532SHerton Ronaldo Krzesinski 1619caeb532SHerton Ronaldo Krzesinski return 0; 1629caeb532SHerton Ronaldo Krzesinski } 1639caeb532SHerton Ronaldo Krzesinski 1649caeb532SHerton Ronaldo Krzesinski static const struct acpi_device_id topstar_device_ids[] = { 1659caeb532SHerton Ronaldo Krzesinski { "TPSACPI01", 0 }, 1669caeb532SHerton Ronaldo Krzesinski { "", 0 }, 1679caeb532SHerton Ronaldo Krzesinski }; 1689caeb532SHerton Ronaldo Krzesinski MODULE_DEVICE_TABLE(acpi, topstar_device_ids); 1699caeb532SHerton Ronaldo Krzesinski 1709caeb532SHerton Ronaldo Krzesinski static struct acpi_driver acpi_topstar_driver = { 1719caeb532SHerton Ronaldo Krzesinski .name = "Topstar laptop ACPI driver", 1729caeb532SHerton Ronaldo Krzesinski .class = ACPI_TOPSTAR_CLASS, 1739caeb532SHerton Ronaldo Krzesinski .ids = topstar_device_ids, 1749caeb532SHerton Ronaldo Krzesinski .ops = { 1759caeb532SHerton Ronaldo Krzesinski .add = acpi_topstar_add, 1769caeb532SHerton Ronaldo Krzesinski .remove = acpi_topstar_remove, 1779caeb532SHerton Ronaldo Krzesinski .notify = acpi_topstar_notify, 1789caeb532SHerton Ronaldo Krzesinski }, 1799caeb532SHerton Ronaldo Krzesinski }; 18015165594SMika Westerberg module_acpi_driver(acpi_topstar_driver); 1819caeb532SHerton Ronaldo Krzesinski 1829caeb532SHerton Ronaldo Krzesinski MODULE_AUTHOR("Herton Ronaldo Krzesinski"); 1839caeb532SHerton Ronaldo Krzesinski MODULE_DESCRIPTION("Topstar Laptop ACPI Extras driver"); 1849caeb532SHerton Ronaldo Krzesinski MODULE_LICENSE("GPL"); 185