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 v2.6.26-rc2 290 lines 7.0 kB view raw
1/* 2 * HP Compaq TC1100 Tablet WMI Extras Driver 3 * 4 * Copyright (C) 2007 Carlos Corbacho <carlos@strangeworlds.co.uk> 5 * Copyright (C) 2004 Jamey Hicks <jamey.hicks@hp.com> 6 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> 7 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> 8 * 9 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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 (at 14 * your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, but 17 * WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 * General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License along 22 * with this program; if not, write to the Free Software Foundation, Inc., 23 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 24 * 25 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 26 */ 27 28#include <linux/kernel.h> 29#include <linux/module.h> 30#include <linux/init.h> 31#include <linux/types.h> 32#include <acpi/acpi.h> 33#include <acpi/actypes.h> 34#include <acpi/acpi_bus.h> 35#include <acpi/acpi_drivers.h> 36#include <linux/platform_device.h> 37 38#define GUID "C364AC71-36DB-495A-8494-B439D472A505" 39 40#define TC1100_INSTANCE_WIRELESS 1 41#define TC1100_INSTANCE_JOGDIAL 2 42 43#define TC1100_LOGPREFIX "tc1100-wmi: " 44#define TC1100_INFO KERN_INFO TC1100_LOGPREFIX 45 46MODULE_AUTHOR("Jamey Hicks, Carlos Corbacho"); 47MODULE_DESCRIPTION("HP Compaq TC1100 Tablet WMI Extras"); 48MODULE_LICENSE("GPL"); 49MODULE_ALIAS("wmi:C364AC71-36DB-495A-8494-B439D472A505"); 50 51static int tc1100_probe(struct platform_device *device); 52static int tc1100_remove(struct platform_device *device); 53static int tc1100_suspend(struct platform_device *device, pm_message_t state); 54static int tc1100_resume(struct platform_device *device); 55 56static struct platform_driver tc1100_driver = { 57 .driver = { 58 .name = "tc1100-wmi", 59 .owner = THIS_MODULE, 60 }, 61 .probe = tc1100_probe, 62 .remove = tc1100_remove, 63 .suspend = tc1100_suspend, 64 .resume = tc1100_resume, 65}; 66 67static struct platform_device *tc1100_device; 68 69struct tc1100_data { 70 u32 wireless; 71 u32 jogdial; 72}; 73 74static struct tc1100_data suspend_data; 75 76/* -------------------------------------------------------------------------- 77 Device Management 78 -------------------------------------------------------------------------- */ 79 80static int get_state(u32 *out, u8 instance) 81{ 82 u32 tmp; 83 acpi_status status; 84 struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL }; 85 union acpi_object *obj; 86 87 if (!out) 88 return -EINVAL; 89 90 if (instance > 2) 91 return -ENODEV; 92 93 status = wmi_query_block(GUID, instance, &result); 94 if (ACPI_FAILURE(status)) 95 return -ENODEV; 96 97 obj = (union acpi_object *) result.pointer; 98 if (obj && obj->type == ACPI_TYPE_BUFFER && 99 obj->buffer.length == sizeof(u32)) { 100 tmp = *((u32 *) obj->buffer.pointer); 101 } else { 102 tmp = 0; 103 } 104 105 if (result.length > 0 && result.pointer) 106 kfree(result.pointer); 107 108 switch (instance) { 109 case TC1100_INSTANCE_WIRELESS: 110 *out = (tmp == 3) ? 1 : 0; 111 return 0; 112 case TC1100_INSTANCE_JOGDIAL: 113 *out = (tmp == 1) ? 1 : 0; 114 return 0; 115 default: 116 return -ENODEV; 117 } 118} 119 120static int set_state(u32 *in, u8 instance) 121{ 122 u32 value; 123 acpi_status status; 124 struct acpi_buffer input; 125 126 if (!in) 127 return -EINVAL; 128 129 if (instance > 2) 130 return -ENODEV; 131 132 switch (instance) { 133 case TC1100_INSTANCE_WIRELESS: 134 value = (*in) ? 1 : 2; 135 break; 136 case TC1100_INSTANCE_JOGDIAL: 137 value = (*in) ? 0 : 1; 138 break; 139 default: 140 return -ENODEV; 141 } 142 143 input.length = sizeof(u32); 144 input.pointer = &value; 145 146 status = wmi_set_block(GUID, instance, &input); 147 if (ACPI_FAILURE(status)) 148 return -ENODEV; 149 150 return 0; 151} 152 153/* -------------------------------------------------------------------------- 154 FS Interface (/sys) 155 -------------------------------------------------------------------------- */ 156 157/* 158 * Read/ write bool sysfs macro 159 */ 160#define show_set_bool(value, instance) \ 161static ssize_t \ 162show_bool_##value(struct device *dev, struct device_attribute *attr, \ 163 char *buf) \ 164{ \ 165 u32 result; \ 166 acpi_status status = get_state(&result, instance); \ 167 if (ACPI_SUCCESS(status)) \ 168 return sprintf(buf, "%d\n", result); \ 169 return sprintf(buf, "Read error\n"); \ 170} \ 171\ 172static ssize_t \ 173set_bool_##value(struct device *dev, struct device_attribute *attr, \ 174 const char *buf, size_t count) \ 175{ \ 176 u32 tmp = simple_strtoul(buf, NULL, 10); \ 177 acpi_status status = set_state(&tmp, instance); \ 178 if (ACPI_FAILURE(status)) \ 179 return -EINVAL; \ 180 return count; \ 181} \ 182static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \ 183 show_bool_##value, set_bool_##value); 184 185show_set_bool(wireless, TC1100_INSTANCE_WIRELESS); 186show_set_bool(jogdial, TC1100_INSTANCE_JOGDIAL); 187 188static void remove_fs(void) 189{ 190 device_remove_file(&tc1100_device->dev, &dev_attr_wireless); 191 device_remove_file(&tc1100_device->dev, &dev_attr_jogdial); 192} 193 194static int add_fs(void) 195{ 196 int ret; 197 198 ret = device_create_file(&tc1100_device->dev, &dev_attr_wireless); 199 if (ret) 200 goto add_sysfs_error; 201 202 ret = device_create_file(&tc1100_device->dev, &dev_attr_jogdial); 203 if (ret) 204 goto add_sysfs_error; 205 206 return ret; 207 208add_sysfs_error: 209 remove_fs(); 210 return ret; 211} 212 213/* -------------------------------------------------------------------------- 214 Driver Model 215 -------------------------------------------------------------------------- */ 216 217static int tc1100_probe(struct platform_device *device) 218{ 219 int result = 0; 220 221 result = add_fs(); 222 return result; 223} 224 225 226static int tc1100_remove(struct platform_device *device) 227{ 228 remove_fs(); 229 return 0; 230} 231 232static int tc1100_suspend(struct platform_device *dev, pm_message_t state) 233{ 234 int ret; 235 236 ret = get_state(&suspend_data.wireless, TC1100_INSTANCE_WIRELESS); 237 if (ret) 238 return ret; 239 240 ret = get_state(&suspend_data.jogdial, TC1100_INSTANCE_JOGDIAL); 241 if (ret) 242 return ret; 243 244 return ret; 245} 246 247static int tc1100_resume(struct platform_device *dev) 248{ 249 int ret; 250 251 ret = set_state(&suspend_data.wireless, TC1100_INSTANCE_WIRELESS); 252 if (ret) 253 return ret; 254 255 ret = set_state(&suspend_data.jogdial, TC1100_INSTANCE_JOGDIAL); 256 if (ret) 257 return ret; 258 259 return ret; 260} 261 262static int __init tc1100_init(void) 263{ 264 int result = 0; 265 266 if (!wmi_has_guid(GUID)) 267 return -ENODEV; 268 269 result = platform_driver_register(&tc1100_driver); 270 if (result) 271 return result; 272 273 tc1100_device = platform_device_alloc("tc1100-wmi", -1); 274 platform_device_add(tc1100_device); 275 276 printk(TC1100_INFO "HP Compaq TC1100 Tablet WMI Extras loaded\n"); 277 278 return result; 279} 280 281static void __exit tc1100_exit(void) 282{ 283 platform_device_del(tc1100_device); 284 platform_driver_unregister(&tc1100_driver); 285 286 printk(TC1100_INFO "HP Compaq TC1100 Tablet WMI Extras unloaded\n"); 287} 288 289module_init(tc1100_init); 290module_exit(tc1100_exit);