Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.6 172 lines 4.3 kB view raw
1/* 2 * WMI hotkeys support for Dell All-In-One series 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 */ 18 19#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 20 21#include <linux/kernel.h> 22#include <linux/module.h> 23#include <linux/init.h> 24#include <linux/types.h> 25#include <linux/input.h> 26#include <linux/input/sparse-keymap.h> 27#include <acpi/acpi_drivers.h> 28#include <linux/acpi.h> 29#include <linux/string.h> 30 31MODULE_DESCRIPTION("WMI hotkeys driver for Dell All-In-One series"); 32MODULE_LICENSE("GPL"); 33 34#define EVENT_GUID1 "284A0E6B-380E-472A-921F-E52786257FB4" 35#define EVENT_GUID2 "02314822-307C-4F66-BF0E-48AEAEB26CC8" 36 37static const char *dell_wmi_aio_guids[] = { 38 EVENT_GUID1, 39 EVENT_GUID2, 40 NULL 41}; 42 43MODULE_ALIAS("wmi:"EVENT_GUID1); 44MODULE_ALIAS("wmi:"EVENT_GUID2); 45 46static const struct key_entry dell_wmi_aio_keymap[] = { 47 { KE_KEY, 0xc0, { KEY_VOLUMEUP } }, 48 { KE_KEY, 0xc1, { KEY_VOLUMEDOWN } }, 49 { KE_END, 0 } 50}; 51 52static struct input_dev *dell_wmi_aio_input_dev; 53 54static void dell_wmi_aio_notify(u32 value, void *context) 55{ 56 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 57 union acpi_object *obj; 58 acpi_status status; 59 60 status = wmi_get_event_data(value, &response); 61 if (status != AE_OK) { 62 pr_info("bad event status 0x%x\n", status); 63 return; 64 } 65 66 obj = (union acpi_object *)response.pointer; 67 if (obj) { 68 unsigned int scancode; 69 70 switch (obj->type) { 71 case ACPI_TYPE_INTEGER: 72 /* Most All-In-One correctly return integer scancode */ 73 scancode = obj->integer.value; 74 sparse_keymap_report_event(dell_wmi_aio_input_dev, 75 scancode, 1, true); 76 break; 77 case ACPI_TYPE_BUFFER: 78 /* Broken machines return the scancode in a buffer */ 79 if (obj->buffer.pointer && obj->buffer.length > 0) { 80 scancode = obj->buffer.pointer[0]; 81 sparse_keymap_report_event( 82 dell_wmi_aio_input_dev, 83 scancode, 1, true); 84 } 85 break; 86 } 87 } 88 kfree(obj); 89} 90 91static int __init dell_wmi_aio_input_setup(void) 92{ 93 int err; 94 95 dell_wmi_aio_input_dev = input_allocate_device(); 96 97 if (!dell_wmi_aio_input_dev) 98 return -ENOMEM; 99 100 dell_wmi_aio_input_dev->name = "Dell AIO WMI hotkeys"; 101 dell_wmi_aio_input_dev->phys = "wmi/input0"; 102 dell_wmi_aio_input_dev->id.bustype = BUS_HOST; 103 104 err = sparse_keymap_setup(dell_wmi_aio_input_dev, 105 dell_wmi_aio_keymap, NULL); 106 if (err) { 107 pr_err("Unable to setup input device keymap\n"); 108 goto err_free_dev; 109 } 110 err = input_register_device(dell_wmi_aio_input_dev); 111 if (err) { 112 pr_info("Unable to register input device\n"); 113 goto err_free_keymap; 114 } 115 return 0; 116 117err_free_keymap: 118 sparse_keymap_free(dell_wmi_aio_input_dev); 119err_free_dev: 120 input_free_device(dell_wmi_aio_input_dev); 121 return err; 122} 123 124static const char *dell_wmi_aio_find(void) 125{ 126 int i; 127 128 for (i = 0; dell_wmi_aio_guids[i] != NULL; i++) 129 if (wmi_has_guid(dell_wmi_aio_guids[i])) 130 return dell_wmi_aio_guids[i]; 131 132 return NULL; 133} 134 135static int __init dell_wmi_aio_init(void) 136{ 137 int err; 138 const char *guid; 139 140 guid = dell_wmi_aio_find(); 141 if (!guid) { 142 pr_warn("No known WMI GUID found\n"); 143 return -ENXIO; 144 } 145 146 err = dell_wmi_aio_input_setup(); 147 if (err) 148 return err; 149 150 err = wmi_install_notify_handler(guid, dell_wmi_aio_notify, NULL); 151 if (err) { 152 pr_err("Unable to register notify handler - %d\n", err); 153 sparse_keymap_free(dell_wmi_aio_input_dev); 154 input_unregister_device(dell_wmi_aio_input_dev); 155 return err; 156 } 157 158 return 0; 159} 160 161static void __exit dell_wmi_aio_exit(void) 162{ 163 const char *guid; 164 165 guid = dell_wmi_aio_find(); 166 wmi_remove_notify_handler(guid); 167 sparse_keymap_free(dell_wmi_aio_input_dev); 168 input_unregister_device(dell_wmi_aio_input_dev); 169} 170 171module_init(dell_wmi_aio_init); 172module_exit(dell_wmi_aio_exit);