diff options
| -rw-r--r-- | drivers/staging/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/staging/Makefile | 1 | ||||
| -rw-r--r-- | drivers/staging/pcc-acpi/Kconfig | 11 | ||||
| -rw-r--r-- | drivers/staging/pcc-acpi/Makefile | 1 | ||||
| -rw-r--r-- | drivers/staging/pcc-acpi/TODO | 7 | ||||
| -rw-r--r-- | drivers/staging/pcc-acpi/pcc-acpi.c | 1111 |
6 files changed, 0 insertions, 1133 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index c4eff44c9f27..e1654f59eb70 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig | |||
| @@ -43,8 +43,6 @@ source "drivers/staging/echo/Kconfig" | |||
| 43 | 43 | ||
| 44 | source "drivers/staging/at76_usb/Kconfig" | 44 | source "drivers/staging/at76_usb/Kconfig" |
| 45 | 45 | ||
| 46 | source "drivers/staging/pcc-acpi/Kconfig" | ||
| 47 | |||
| 48 | source "drivers/staging/poch/Kconfig" | 46 | source "drivers/staging/poch/Kconfig" |
| 49 | 47 | ||
| 50 | endif # STAGING | 48 | endif # STAGING |
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 7cb8701d96d4..71c4d53760b8 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile | |||
| @@ -13,5 +13,4 @@ obj-$(CONFIG_W35UND) += winbond/ | |||
| 13 | obj-$(CONFIG_PRISM2_USB) += wlan-ng/ | 13 | obj-$(CONFIG_PRISM2_USB) += wlan-ng/ |
| 14 | obj-$(CONFIG_ECHO) += echo/ | 14 | obj-$(CONFIG_ECHO) += echo/ |
| 15 | obj-$(CONFIG_USB_ATMEL) += at76_usb/ | 15 | obj-$(CONFIG_USB_ATMEL) += at76_usb/ |
| 16 | obj-$(CONFIG_PCC_ACPI) += pcc-acpi/ | ||
| 17 | obj-$(CONFIG_POCH) += poch/ | 16 | obj-$(CONFIG_POCH) += poch/ |
diff --git a/drivers/staging/pcc-acpi/Kconfig b/drivers/staging/pcc-acpi/Kconfig deleted file mode 100644 index 6720d4086baf..000000000000 --- a/drivers/staging/pcc-acpi/Kconfig +++ /dev/null | |||
| @@ -1,11 +0,0 @@ | |||
| 1 | config PCC_ACPI | ||
| 2 | tristate "Panasonic ACPI Hotkey support" | ||
| 3 | depends on ACPI | ||
| 4 | default n | ||
| 5 | ---help--- | ||
| 6 | This driver provides support for Panasonic hotkeys through the | ||
| 7 | ACPI interface. This works for the Panasonic R1 (N variant), | ||
| 8 | R2, R3, T2, W2, and Y2 laptops. | ||
| 9 | |||
| 10 | To compile this driver as a module, choose M here. The module | ||
| 11 | will be called pcc-acpi. | ||
diff --git a/drivers/staging/pcc-acpi/Makefile b/drivers/staging/pcc-acpi/Makefile deleted file mode 100644 index f93b29edf61e..000000000000 --- a/drivers/staging/pcc-acpi/Makefile +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | obj-$(CONFIG_PCC_ACPI) += pcc-acpi.o | ||
diff --git a/drivers/staging/pcc-acpi/TODO b/drivers/staging/pcc-acpi/TODO deleted file mode 100644 index fab240982286..000000000000 --- a/drivers/staging/pcc-acpi/TODO +++ /dev/null | |||
| @@ -1,7 +0,0 @@ | |||
| 1 | TODO: | ||
| 2 | - Lindent fixes | ||
| 3 | - checkpatch.pl fixes | ||
| 4 | - verify that the acpi interface is correct | ||
| 5 | - remove /proc dependancy if needed (not sure yet.) | ||
| 6 | |||
| 7 | Please send any patches for this driver to Greg Kroah-Hartman <greg@kroah.com> | ||
diff --git a/drivers/staging/pcc-acpi/pcc-acpi.c b/drivers/staging/pcc-acpi/pcc-acpi.c deleted file mode 100644 index 3b34a3e4885a..000000000000 --- a/drivers/staging/pcc-acpi/pcc-acpi.c +++ /dev/null | |||
| @@ -1,1111 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Panasonic HotKey and lcd brightness control Extra driver | ||
| 3 | * (C) 2004 Hiroshi Miura <miura@da-cha.org> | ||
| 4 | * (C) 2004 NTT DATA Intellilink Co. http://www.intellilink.co.jp/ | ||
| 5 | * (C) YOKOTA Hiroshi <yokota (at) netlab. is. tsukuba. ac. jp> | ||
| 6 | * (C) 2004 David Bronaugh <dbronaugh> | ||
| 7 | * | ||
| 8 | * derived from toshiba_acpi.c, Copyright (C) 2002-2004 John Belmonte | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * publicshed by the Free Software Foundation. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this program; if not, write to the Free Software | ||
| 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 22 | * | ||
| 23 | *--------------------------------------------------------------------------- | ||
| 24 | * | ||
| 25 | * ChangeLog: | ||
| 26 | * | ||
| 27 | * Nov.04, 2006 Hiroshi Miura <miura@da-cha.org> | ||
| 28 | * -v0.9 remove warning about section reference. | ||
| 29 | * remove acpi_os_free | ||
| 30 | * add /proc/acpi/pcc/brightness interface to | ||
| 31 | * allow HAL to access. | ||
| 32 | * merge dbronaugh's enhancement | ||
| 33 | * Aug.17, 2004 David Bronaugh (dbronaugh) | ||
| 34 | * - Added screen brightness setting interface | ||
| 35 | * Thanks to the FreeBSD crew | ||
| 36 | * (acpi_panasonic.c authors) | ||
| 37 | * for the ideas I needed to accomplish it | ||
| 38 | * | ||
| 39 | * May.29, 2006 Hiroshi Miura <miura@da-cha.org> | ||
| 40 | * -v0.8.4 follow to change keyinput structure | ||
| 41 | * thanks Fabian Yamaguchi <fabs@cs.tu-berlin.de>, | ||
| 42 | * Jacob Bower <jacob.bower@ic.ac.uk> and | ||
| 43 | * Hiroshi Yokota for providing solutions. | ||
| 44 | * | ||
| 45 | * Oct.02, 2004 Hiroshi Miura <miura@da-cha.org> | ||
| 46 | * -v0.8.2 merge code of YOKOTA Hiroshi | ||
| 47 | * <yokota@netlab.is.tsukuba.ac.jp>. | ||
| 48 | * Add sticky key mode interface. | ||
| 49 | * Refactoring acpi_pcc_generete_keyinput(). | ||
| 50 | * | ||
| 51 | * Sep.15, 2004 Hiroshi Miura <miura@da-cha.org> | ||
| 52 | * -v0.8 Generate key input event on input subsystem. | ||
| 53 | * This is based on yet another driver | ||
| 54 | * written by Ryuta Nakanishi. | ||
| 55 | * | ||
| 56 | * Sep.10, 2004 Hiroshi Miura <miura@da-cha.org> | ||
| 57 | * -v0.7 Change proc interface functions using seq_file | ||
| 58 | * facility as same as other ACPI drivers. | ||
| 59 | * | ||
| 60 | * Aug.28, 2004 Hiroshi Miura <miura@da-cha.org> | ||
| 61 | * -v0.6.4 Fix a silly error with status checking | ||
| 62 | * | ||
| 63 | * Aug.25, 2004 Hiroshi Miura <miura@da-cha.org> | ||
| 64 | * -v0.6.3 replace read_acpi_int by standard | ||
| 65 | * function acpi_evaluate_integer | ||
| 66 | * some clean up and make smart copyright notice. | ||
| 67 | * fix return value of pcc_acpi_get_key() | ||
| 68 | * fix checking return value of acpi_bus_register_driver() | ||
| 69 | * | ||
| 70 | * Aug.22, 2004 David Bronaugh <dbronaugh@linuxboxen.org> | ||
| 71 | * -v0.6.2 Add check on ACPI data (num_sifr) | ||
| 72 | * Coding style cleanups, better error messages/handling | ||
| 73 | * Fixed an off-by-one error in memory allocation | ||
| 74 | * | ||
| 75 | * Aug.21, 2004 David Bronaugh <dbronaugh@linuxboxen.org> | ||
| 76 | * -v0.6.1 Fix a silly error with status checking | ||
| 77 | * | ||
| 78 | * Aug.20, 2004 David Bronaugh <dbronaugh@linuxboxen.org> | ||
| 79 | * - v0.6 Correct brightness controls to reflect reality | ||
| 80 | * based on information gleaned by Hiroshi Miura | ||
| 81 | * and discussions with Hiroshi Miura | ||
| 82 | * | ||
| 83 | * Aug.10, 2004 Hiroshi Miura <miura@da-cha.org> | ||
| 84 | * - v0.5 support LCD brightness control | ||
| 85 | * based on the disclosed information by MEI. | ||
| 86 | * | ||
| 87 | * Jul.25, 2004 Hiroshi Miura <miura@da-cha.org> | ||
| 88 | * - v0.4 first post version | ||
| 89 | * add function to retrive SIFR | ||
| 90 | * | ||
| 91 | * Jul.24, 2004 Hiroshi Miura <miura@da-cha.org> | ||
| 92 | * - v0.3 get proper status of hotkey | ||
| 93 | * | ||
| 94 | * Jul.22, 2004 Hiroshi Miura <miura@da-cha.org> | ||
| 95 | * - v0.2 add HotKey handler | ||
| 96 | * | ||
| 97 | * Jul.17, 2004 Hiroshi Miura <miura@da-cha.org> | ||
| 98 | * - v0.1 start from toshiba_acpi driver written by John Belmonte | ||
| 99 | * | ||
| 100 | */ | ||
| 101 | |||
| 102 | #define ACPI_PCC_VERSION "0.9+hy" | ||
| 103 | |||
| 104 | #include <linux/kernel.h> | ||
| 105 | #include <linux/module.h> | ||
| 106 | #include <linux/types.h> | ||
| 107 | #include <linux/ctype.h> | ||
| 108 | #include <linux/init.h> | ||
| 109 | #include <linux/input.h> | ||
| 110 | #include <linux/proc_fs.h> | ||
| 111 | #include <linux/seq_file.h> | ||
| 112 | #include <linux/slab.h> | ||
| 113 | #include <linux/uaccess.h> | ||
| 114 | #include <acpi/acpi_bus.h> | ||
| 115 | #include <acpi/acpi_drivers.h> | ||
| 116 | |||
| 117 | |||
| 118 | /************************************************************************* | ||
| 119 | * "seq" file template definition. | ||
| 120 | */ | ||
| 121 | /* "seq" initializer */ | ||
| 122 | #define SEQ_OPEN_FS(_open_func_name_, _show_func_name_) \ | ||
| 123 | static int _open_func_name_(struct inode *inode, struct file *file) \ | ||
| 124 | { \ | ||
| 125 | return single_open(file, _show_func_name_, PDE(inode)->data); \ | ||
| 126 | } | ||
| 127 | |||
| 128 | /*------------------------------------------------------------------------- | ||
| 129 | * "seq" fops template for read-only files. | ||
| 130 | */ | ||
| 131 | #define SEQ_FILEOPS_R(_open_func_name_) \ | ||
| 132 | { \ | ||
| 133 | .open = _open_func_name_, \ | ||
| 134 | .read = seq_read, \ | ||
| 135 | .llseek = seq_lseek, \ | ||
| 136 | .release = single_release, \ | ||
| 137 | } | ||
| 138 | |||
| 139 | /*------------------------------------------------------------------------ | ||
| 140 | * "seq" fops template for read-write files. | ||
| 141 | */ | ||
| 142 | #define SEQ_FILEOPS_RW(_open_func_name_, _write_func_name_) \ | ||
| 143 | { \ | ||
| 144 | .open = _open_func_name_ , \ | ||
| 145 | .read = seq_read, \ | ||
| 146 | .write = _write_func_name_, \ | ||
| 147 | .llseek = seq_lseek, \ | ||
| 148 | .release = single_release, \ | ||
| 149 | } | ||
| 150 | |||
| 151 | /* | ||
| 152 | * "seq" file template definition ended. | ||
| 153 | *************************************************************************** | ||
| 154 | */ | ||
| 155 | #ifndef ACPI_HOTKEY_COMPONENT | ||
| 156 | #define ACPI_HOTKEY_COMPONENT 0x10000000 | ||
| 157 | #endif | ||
| 158 | |||
| 159 | #define _COMPONENT ACPI_HOTKEY_COMPONENT | ||
| 160 | ACPI_MODULE_NAME("pcc_acpi"); | ||
| 161 | |||
| 162 | MODULE_AUTHOR("Hiroshi Miura, Hiroshi Yokota"); | ||
| 163 | MODULE_DESCRIPTION("ACPI HotKey driver for Panasonic Let's Note laptops"); | ||
| 164 | MODULE_LICENSE("GPL"); | ||
| 165 | |||
| 166 | #define LOGPREFIX "pcc_acpi: " | ||
| 167 | |||
| 168 | /**************************************************** | ||
| 169 | * Define ACPI PATHs | ||
| 170 | ****************************************************/ | ||
| 171 | /* Lets note hotkeys */ | ||
| 172 | #define METHOD_HKEY_QUERY "HINF" | ||
| 173 | #define METHOD_HKEY_SQTY "SQTY" | ||
| 174 | #define METHOD_HKEY_SINF "SINF" | ||
| 175 | #define METHOD_HKEY_SSET "SSET" | ||
| 176 | #define HKEY_NOTIFY 0x80 | ||
| 177 | |||
| 178 | /* for brightness control */ | ||
| 179 | #define LCD_MAX_BRIGHTNESS 255 | ||
| 180 | /* This may be magical -- beware */ | ||
| 181 | #define LCD_BRIGHTNESS_INCREMENT 17 | ||
| 182 | /* Registers of SINF */ | ||
| 183 | #define SINF_LCD_BRIGHTNESS 4 | ||
| 184 | |||
| 185 | /******************************************************************* | ||
| 186 | * | ||
| 187 | * definitions for /proc/ interface | ||
| 188 | * | ||
| 189 | *******************************************************************/ | ||
| 190 | #define ACPI_PCC_DRIVER_NAME "pcc_acpi" | ||
| 191 | #define ACPI_PCC_DEVICE_NAME "PCCExtra" | ||
| 192 | #define ACPI_PCC_CLASS "pcc" | ||
| 193 | #define PROC_PCC ACPI_PCC_CLASS | ||
| 194 | |||
| 195 | #define ACPI_PCC_INPUT_PHYS "panasonic/hkey0" | ||
| 196 | |||
| 197 | /* This is transitional definition */ | ||
| 198 | #ifndef KEY_BATT | ||
| 199 | # define KEY_BATT 227 | ||
| 200 | #endif | ||
| 201 | |||
| 202 | #define PROC_STR_MAX_LEN 8 | ||
| 203 | |||
| 204 | #define BUS_PCC_HOTKEY BUS_I8042 /*0x1a*/ /* FIXME: BUS_I8042? */ | ||
| 205 | |||
| 206 | /* Fn+F4/F5 confricts with Shift+F1/F2 */ | ||
| 207 | /* This hack avoids key number confrict */ | ||
| 208 | #define PCC_KEYINPUT_MODE (0) | ||
| 209 | |||
| 210 | /* LCD_TYPEs: 0 = Normal, 1 = Semi-transparent | ||
| 211 | ENV_STATEs: Normal temp=0x01, High temp=0x81, N/A=0x00 | ||
| 212 | */ | ||
| 213 | enum SINF_BITS { SINF_NUM_BATTERIES = 0, | ||
| 214 | SINF_LCD_TYPE, | ||
| 215 | SINF_AC_MAX_BRIGHT, | ||
| 216 | SINF_AC_MIN_BRIGHT, | ||
| 217 | SINF_AC_CUR_BRIGHT, | ||
| 218 | /* 4 = R1 only handle SINF_AC_CUR_BRIGHT | ||
| 219 | * as SINF_CUR_BRIGHT and don't know AC state */ | ||
| 220 | SINF_DC_MAX_BRIGHT, | ||
| 221 | SINF_DC_MIN_BRIGHT, | ||
| 222 | SINF_DC_CUR_BRIGHT, | ||
| 223 | SINF_MUTE, | ||
| 224 | SINF_RESERVED, | ||
| 225 | SINF_ENV_STATE, /* 10 */ | ||
| 226 | SINF_STICKY_KEY = 0x80, | ||
| 227 | }; | ||
| 228 | |||
| 229 | static struct acpi_device_id pcc_device_ids[] = { | ||
| 230 | {"MAT0012", 0}, | ||
| 231 | {"MAT0013", 0}, | ||
| 232 | {"MAT0018", 0}, | ||
| 233 | {"MAT0019", 0}, | ||
| 234 | {"", 0}, | ||
| 235 | }; | ||
| 236 | MODULE_DEVICE_TABLE(acpi, pcc_device_ids); | ||
| 237 | |||
| 238 | |||
| 239 | static int __devinit acpi_pcc_hotkey_add(struct acpi_device *device); | ||
| 240 | static int __devexit acpi_pcc_hotkey_remove(struct acpi_device *device, | ||
| 241 | int type); | ||
| 242 | static int acpi_pcc_hotkey_resume(struct acpi_device *device); | ||
| 243 | |||
| 244 | |||
| 245 | static struct acpi_driver acpi_pcc_driver = { | ||
| 246 | .name = ACPI_PCC_DRIVER_NAME, | ||
| 247 | .class = ACPI_PCC_CLASS, | ||
| 248 | .ids = pcc_device_ids, | ||
| 249 | .ops = { | ||
| 250 | .add = acpi_pcc_hotkey_add, | ||
| 251 | .remove = __devexit_p(acpi_pcc_hotkey_remove), | ||
| 252 | #ifdef CONFIG_PM | ||
| 253 | /*.suspend = acpi_pcc_hotkey_suspend,*/ | ||
| 254 | .resume = acpi_pcc_hotkey_resume, | ||
| 255 | #endif | ||
| 256 | }, | ||
| 257 | }; | ||
| 258 | |||
| 259 | struct acpi_hotkey { | ||
| 260 | acpi_handle handle; | ||
| 261 | struct acpi_device *device; | ||
| 262 | struct proc_dir_entry *proc_dir_entry; | ||
| 263 | unsigned long num_sifr; | ||
| 264 | unsigned long status; | ||
| 265 | struct input_dev *input_dev; | ||
| 266 | int sticky_mode; | ||
| 267 | }; | ||
| 268 | |||
| 269 | struct pcc_keyinput { | ||
| 270 | struct acpi_hotkey *hotkey; | ||
| 271 | int key_mode; | ||
| 272 | }; | ||
| 273 | |||
| 274 | /* ************************************************************************* | ||
| 275 | Hotkey driver core | ||
| 276 | ************************************************************************* */ | ||
| 277 | /* ------------------------------------------------------------------------- | ||
| 278 | method access functions | ||
| 279 | ------------------------------------------------------------------------- */ | ||
| 280 | static int acpi_pcc_write_sset(struct acpi_hotkey *hotkey, int func, int val) | ||
| 281 | { | ||
| 282 | union acpi_object in_objs[] = { | ||
| 283 | { .integer.type = ACPI_TYPE_INTEGER, | ||
| 284 | .integer.value = func, }, | ||
| 285 | { .integer.type = ACPI_TYPE_INTEGER, | ||
| 286 | .integer.value = val, }, | ||
| 287 | }; | ||
| 288 | struct acpi_object_list params = { | ||
| 289 | .count = ARRAY_SIZE(in_objs), | ||
| 290 | .pointer = in_objs, | ||
| 291 | }; | ||
| 292 | acpi_status status; | ||
| 293 | |||
| 294 | ACPI_FUNCTION_TRACE("acpi_pcc_write_sset"); | ||
| 295 | |||
| 296 | status = acpi_evaluate_object(hotkey->handle, METHOD_HKEY_SSET, | ||
| 297 | ¶ms, NULL); | ||
| 298 | |||
| 299 | return_VALUE(status == AE_OK ? AE_OK : AE_ERROR); | ||
| 300 | } | ||
| 301 | |||
| 302 | static inline int acpi_pcc_get_sqty(struct acpi_device *device) | ||
| 303 | { | ||
| 304 | unsigned long s; | ||
| 305 | acpi_status status; | ||
| 306 | |||
| 307 | ACPI_FUNCTION_TRACE("acpi_pcc_get_sqty"); | ||
| 308 | |||
| 309 | status = acpi_evaluate_integer(device->handle, METHOD_HKEY_SQTY, | ||
| 310 | NULL, &s); | ||
| 311 | if (ACPI_SUCCESS(status)) { | ||
| 312 | return_VALUE(s); | ||
| 313 | } else { | ||
| 314 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
| 315 | "evaluation error HKEY.SQTY\n")); | ||
| 316 | return_VALUE(-EINVAL); | ||
| 317 | } | ||
| 318 | } | ||
| 319 | |||
| 320 | static int acpi_pcc_retrieve_biosdata(struct acpi_hotkey *hotkey, u32 *sinf) | ||
| 321 | { | ||
| 322 | acpi_status status; | ||
| 323 | struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; | ||
| 324 | union acpi_object *hkey = NULL; | ||
| 325 | int i; | ||
| 326 | |||
| 327 | ACPI_FUNCTION_TRACE("acpi_pcc_retrieve_biosdata"); | ||
| 328 | |||
| 329 | status = acpi_evaluate_object(hotkey->handle, METHOD_HKEY_SINF, 0, | ||
| 330 | &buffer); | ||
| 331 | if (ACPI_FAILURE(status)) { | ||
| 332 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
| 333 | "evaluation error HKEY.SINF\n")); | ||
| 334 | status = AE_ERROR; | ||
| 335 | return_VALUE(status); | ||
| 336 | } | ||
| 337 | |||
| 338 | hkey = buffer.pointer; | ||
| 339 | if (!hkey || (hkey->type != ACPI_TYPE_PACKAGE)) { | ||
| 340 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid HKEY.SINF\n")); | ||
| 341 | goto free_buffer; | ||
| 342 | } | ||
| 343 | |||
| 344 | if (hotkey->num_sifr < hkey->package.count) { | ||
| 345 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
| 346 | "SQTY reports bad SINF length\n")); | ||
| 347 | status = AE_ERROR; | ||
| 348 | goto free_buffer; | ||
| 349 | } | ||
| 350 | |||
| 351 | for (i = 0; i < hkey->package.count; i++) { | ||
| 352 | union acpi_object *element = &(hkey->package.elements[i]); | ||
| 353 | if (likely(element->type == ACPI_TYPE_INTEGER)) { | ||
| 354 | sinf[i] = element->integer.value; | ||
| 355 | } else { | ||
| 356 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
| 357 | "Invalid HKEY.SINF data\n")); | ||
| 358 | status = AE_ERROR; | ||
| 359 | break; | ||
| 360 | } | ||
| 361 | } | ||
| 362 | sinf[hkey->package.count] = -1; | ||
| 363 | |||
| 364 | free_buffer: | ||
| 365 | kfree(buffer.pointer); | ||
| 366 | return_VALUE(status == AE_OK ? AE_OK : AE_ERROR); | ||
| 367 | } | ||
| 368 | |||
| 369 | static int acpi_pcc_read_sinf_field(struct seq_file *seq, int field) | ||
| 370 | { | ||
| 371 | struct acpi_hotkey *hotkey = (struct acpi_hotkey *) seq->private; | ||
| 372 | u32 sinf[hotkey->num_sifr + 1]; | ||
| 373 | |||
| 374 | ACPI_FUNCTION_TRACE("acpi_pcc_read_sinf_field"); | ||
| 375 | |||
| 376 | if (ACPI_SUCCESS(acpi_pcc_retrieve_biosdata(hotkey, sinf))) | ||
| 377 | seq_printf(seq, "%u\n", sinf[field]); | ||
| 378 | else | ||
| 379 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
| 380 | "Couldn't retrieve BIOS data\n")); | ||
| 381 | |||
| 382 | return_VALUE(AE_OK); | ||
| 383 | } | ||
| 384 | |||
| 385 | /* ------------------------------------------------------------------------- | ||
| 386 | user interface functions | ||
| 387 | ------------------------------------------------------------------------- */ | ||
| 388 | /* read methods */ | ||
| 389 | /* Sinf read methods */ | ||
| 390 | #define PCC_SINF_READ_F(_name_, FUNC) \ | ||
| 391 | static int _name_(struct seq_file *seq, void *offset) \ | ||
| 392 | { \ | ||
| 393 | return_VALUE(ACPI_SUCCESS(acpi_pcc_read_sinf_field(seq, \ | ||
| 394 | (FUNC))) \ | ||
| 395 | ? 0 : -EINVAL); \ | ||
| 396 | } | ||
| 397 | |||
| 398 | PCC_SINF_READ_F(acpi_pcc_numbatteries_show, SINF_NUM_BATTERIES); | ||
| 399 | PCC_SINF_READ_F(acpi_pcc_lcdtype_show, SINF_LCD_TYPE); | ||
| 400 | PCC_SINF_READ_F(acpi_pcc_ac_brightness_max_show, SINF_AC_MAX_BRIGHT); | ||
| 401 | PCC_SINF_READ_F(acpi_pcc_ac_brightness_min_show, SINF_AC_MIN_BRIGHT); | ||
| 402 | PCC_SINF_READ_F(acpi_pcc_ac_brightness_show, SINF_AC_CUR_BRIGHT); | ||
| 403 | PCC_SINF_READ_F(acpi_pcc_dc_brightness_max_show, SINF_DC_MAX_BRIGHT); | ||
| 404 | PCC_SINF_READ_F(acpi_pcc_dc_brightness_min_show, SINF_DC_MIN_BRIGHT); | ||
| 405 | PCC_SINF_READ_F(acpi_pcc_dc_brightness_show, SINF_DC_CUR_BRIGHT); | ||
| 406 | PCC_SINF_READ_F(acpi_pcc_brightness_show, SINF_AC_CUR_BRIGHT); | ||
| 407 | PCC_SINF_READ_F(acpi_pcc_mute_show, SINF_MUTE); | ||
| 408 | |||
| 409 | static int acpi_pcc_sticky_key_show(struct seq_file *seq, void *offset) | ||
| 410 | { | ||
| 411 | struct acpi_hotkey *hotkey = seq->private; | ||
| 412 | |||
| 413 | ACPI_FUNCTION_TRACE("acpi_pcc_sticky_key_show"); | ||
| 414 | |||
| 415 | if (!hotkey || !hotkey->device) | ||
| 416 | return_VALUE(-EINVAL); | ||
| 417 | |||
| 418 | seq_printf(seq, "%d\n", hotkey->sticky_mode); | ||
| 419 | |||
| 420 | return_VALUE(0); | ||
| 421 | } | ||
| 422 | |||
| 423 | static int acpi_pcc_keyinput_show(struct seq_file *seq, void *offset) | ||
| 424 | { | ||
| 425 | struct acpi_hotkey *hotkey = seq->private; | ||
| 426 | struct input_dev *hotk_input_dev = hotkey->input_dev; | ||
| 427 | struct pcc_keyinput *keyinput = input_get_drvdata(hotk_input_dev); | ||
| 428 | |||
| 429 | ACPI_FUNCTION_TRACE("acpi_pcc_keyinput_show"); | ||
| 430 | |||
| 431 | seq_printf(seq, "%d\n", keyinput->key_mode); | ||
| 432 | |||
| 433 | return_VALUE(0); | ||
| 434 | } | ||
| 435 | |||
| 436 | static int acpi_pcc_version_show(struct seq_file *seq, void *offset) | ||
| 437 | { | ||
| 438 | struct acpi_hotkey *hotkey = seq->private; | ||
| 439 | |||
| 440 | ACPI_FUNCTION_TRACE("acpi_pcc_version_show"); | ||
| 441 | |||
| 442 | if (!hotkey || !hotkey->device) | ||
| 443 | return_VALUE(-EINVAL); | ||
| 444 | |||
| 445 | seq_printf(seq, "%s version %s\n", ACPI_PCC_DRIVER_NAME, | ||
| 446 | ACPI_PCC_VERSION); | ||
| 447 | seq_printf(seq, "%li functions\n", hotkey->num_sifr); | ||
| 448 | |||
| 449 | return_VALUE(0); | ||
| 450 | } | ||
| 451 | |||
| 452 | /* write methods */ | ||
| 453 | static ssize_t acpi_pcc_write_single_flag(struct file *file, | ||
| 454 | const char __user *buffer, | ||
| 455 | size_t count, | ||
| 456 | int sinf_func) | ||
| 457 | { | ||
| 458 | struct seq_file *seq = file->private_data; | ||
| 459 | struct acpi_hotkey *hotkey = seq->private; | ||
| 460 | char write_string[PROC_STR_MAX_LEN]; | ||
| 461 | u32 val; | ||
| 462 | |||
| 463 | ACPI_FUNCTION_TRACE("acpi_pcc_write_single_flag"); | ||
| 464 | |||
| 465 | if (!hotkey || (count > sizeof(write_string) - 1)) | ||
| 466 | return_VALUE(-EINVAL); | ||
| 467 | |||
| 468 | if (copy_from_user(write_string, buffer, count)) | ||
| 469 | return_VALUE(-EFAULT); | ||
| 470 | |||
| 471 | write_string[count] = '\0'; | ||
| 472 | |||
| 473 | if ((sscanf(write_string, "%3i", &val) == 1) && | ||
| 474 | (val == 0 || val == 1)) | ||
| 475 | acpi_pcc_write_sset(hotkey, sinf_func, val); | ||
| 476 | |||
| 477 | return_VALUE(count); | ||
| 478 | } | ||
| 479 | |||
| 480 | static unsigned long acpi_pcc_write_brightness(struct file *file, | ||
| 481 | const char __user *buffer, | ||
| 482 | size_t count, | ||
| 483 | int min_index, int max_index, | ||
| 484 | int cur_index) | ||
| 485 | { | ||
| 486 | struct seq_file *seq = (struct seq_file *)file->private_data; | ||
| 487 | struct acpi_hotkey *hotkey = (struct acpi_hotkey *)seq->private; | ||
| 488 | char write_string[PROC_STR_MAX_LEN]; | ||
| 489 | u32 bright; | ||
| 490 | u32 sinf[hotkey->num_sifr + 1]; | ||
| 491 | |||
| 492 | ACPI_FUNCTION_TRACE("acpi_pcc_write_brightness"); | ||
| 493 | |||
| 494 | if (!hotkey || (count > sizeof(write_string) - 1)) | ||
| 495 | return_VALUE(-EINVAL); | ||
| 496 | |||
| 497 | if (copy_from_user(write_string, buffer, count)) | ||
| 498 | return_VALUE(-EFAULT); | ||
| 499 | |||
| 500 | write_string[count] = '\0'; | ||
| 501 | |||
| 502 | if (ACPI_FAILURE(acpi_pcc_retrieve_biosdata(hotkey, sinf))) { | ||
| 503 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
| 504 | "Couldn't retrieve BIOS data\n")); | ||
| 505 | goto end; | ||
| 506 | } | ||
| 507 | |||
| 508 | if ((sscanf(write_string, "%4i", &bright) == 1) && | ||
| 509 | (bright >= sinf[min_index]) && | ||
| 510 | (bright <= sinf[max_index])) | ||
| 511 | acpi_pcc_write_sset(hotkey, cur_index, bright); | ||
| 512 | |||
| 513 | end: | ||
| 514 | return_VALUE(count); | ||
| 515 | } | ||
| 516 | |||
| 517 | static ssize_t acpi_pcc_write_ac_brightness(struct file *file, | ||
| 518 | const char __user *buffer, | ||
| 519 | size_t count, loff_t *ppos) | ||
| 520 | { | ||
| 521 | return_VALUE(acpi_pcc_write_brightness(file, buffer, count, | ||
| 522 | SINF_AC_MIN_BRIGHT, | ||
| 523 | SINF_AC_MAX_BRIGHT, | ||
| 524 | SINF_AC_CUR_BRIGHT)); | ||
| 525 | } | ||
| 526 | |||
| 527 | static ssize_t acpi_pcc_write_dc_brightness(struct file *file, | ||
| 528 | const char __user *buffer, | ||
| 529 | size_t count, loff_t *ppos) | ||
| 530 | { | ||
| 531 | return_VALUE(acpi_pcc_write_brightness(file, buffer, count, | ||
| 532 | SINF_DC_MIN_BRIGHT, | ||
| 533 | SINF_DC_MAX_BRIGHT, | ||
| 534 | SINF_DC_CUR_BRIGHT)); | ||
| 535 | } | ||
| 536 | |||
| 537 | static ssize_t acpi_pcc_write_no_brightness(struct file *file, | ||
| 538 | const char __user *buffer, | ||
| 539 | size_t count, loff_t *ppos) | ||
| 540 | { | ||
| 541 | return acpi_pcc_write_brightness(file, buffer, count, | ||
| 542 | SINF_AC_MIN_BRIGHT, | ||
| 543 | SINF_AC_MAX_BRIGHT, | ||
| 544 | SINF_AC_CUR_BRIGHT); | ||
| 545 | } | ||
| 546 | |||
| 547 | static ssize_t acpi_pcc_write_mute(struct file *file, | ||
| 548 | const char __user *buffer, | ||
| 549 | size_t count, loff_t *ppos) | ||
| 550 | { | ||
| 551 | return_VALUE(acpi_pcc_write_single_flag(file, buffer, count, | ||
| 552 | SINF_MUTE)); | ||
| 553 | } | ||
| 554 | |||
| 555 | static ssize_t acpi_pcc_write_sticky_key(struct file *file, | ||
| 556 | const char __user *buffer, | ||
| 557 | size_t count, loff_t *ppos) | ||
| 558 | { | ||
| 559 | struct seq_file *seq = (struct seq_file *)file->private_data; | ||
| 560 | struct acpi_hotkey *hotkey = (struct acpi_hotkey *)seq->private; | ||
| 561 | char write_string[PROC_STR_MAX_LEN]; | ||
| 562 | int mode; | ||
| 563 | |||
| 564 | ACPI_FUNCTION_TRACE("acpi_pcc_write_sticky_key"); | ||
| 565 | |||
| 566 | if (!hotkey || (count > sizeof(write_string) - 1)) | ||
| 567 | return_VALUE(-EINVAL); | ||
| 568 | |||
| 569 | if (copy_from_user(write_string, buffer, count)) | ||
| 570 | return_VALUE(-EFAULT); | ||
| 571 | |||
| 572 | write_string[count] = '\0'; | ||
| 573 | |||
| 574 | if ((sscanf(write_string, "%3i", &mode) == 1) && | ||
| 575 | (mode == 0 || mode == 1)) { | ||
| 576 | acpi_pcc_write_sset(hotkey, SINF_STICKY_KEY, mode); | ||
| 577 | hotkey->sticky_mode = mode; | ||
| 578 | } | ||
| 579 | |||
| 580 | return_VALUE(count); | ||
| 581 | } | ||
| 582 | |||
| 583 | static ssize_t acpi_pcc_write_keyinput(struct file *file, | ||
| 584 | const char __user *buffer, | ||
| 585 | size_t count, loff_t *ppos) | ||
| 586 | { | ||
| 587 | struct seq_file *seq = (struct seq_file *)file->private_data; | ||
| 588 | struct acpi_hotkey *hotkey = (struct acpi_hotkey *)seq->private; | ||
| 589 | struct pcc_keyinput *keyinput; | ||
| 590 | char write_string[PROC_STR_MAX_LEN]; | ||
| 591 | int key_mode; | ||
| 592 | |||
| 593 | ACPI_FUNCTION_TRACE("acpi_pcc_write_keyinput"); | ||
| 594 | |||
| 595 | if (!hotkey || (count > (sizeof(write_string) - 1))) | ||
| 596 | return_VALUE(-EINVAL); | ||
| 597 | |||
| 598 | if (copy_from_user(write_string, buffer, count)) | ||
| 599 | return_VALUE(-EFAULT); | ||
| 600 | |||
| 601 | write_string[count] = '\0'; | ||
| 602 | |||
| 603 | if ((sscanf(write_string, "%4i", &key_mode) == 1) && | ||
| 604 | (key_mode == 0 || key_mode == 1)) { | ||
| 605 | keyinput = input_get_drvdata(hotkey->input_dev); | ||
| 606 | keyinput->key_mode = key_mode; | ||
| 607 | } | ||
| 608 | |||
| 609 | return_VALUE(count); | ||
| 610 | } | ||
| 611 | |||
| 612 | /* ------------------------------------------------------------------------- | ||
| 613 | hotkey driver | ||
| 614 | ------------------------------------------------------------------------- */ | ||
| 615 | static void acpi_pcc_generete_keyinput(struct acpi_hotkey *hotkey) | ||
| 616 | { | ||
| 617 | struct input_dev *hotk_input_dev = hotkey->input_dev; | ||
| 618 | struct pcc_keyinput *keyinput = input_get_drvdata(hotk_input_dev); | ||
| 619 | int hinf = hotkey->status; | ||
| 620 | int key_code, hkey_num; | ||
| 621 | const int key_map[] = { | ||
| 622 | /* 0 */ -1, | ||
| 623 | /* 1 */ KEY_BRIGHTNESSDOWN, | ||
| 624 | /* 2 */ KEY_BRIGHTNESSUP, | ||
| 625 | /* 3 */ -1, /* vga/lcd switch event is not occur on | ||
| 626 | hotkey driver. */ | ||
| 627 | /* 4 */ KEY_MUTE, | ||
| 628 | /* 5 */ KEY_VOLUMEDOWN, | ||
| 629 | /* 6 */ KEY_VOLUMEUP, | ||
| 630 | /* 7 */ KEY_SLEEP, | ||
| 631 | /* 8 */ -1, /* Change CPU boost: do nothing */ | ||
| 632 | /* 9 */ KEY_BATT, | ||
| 633 | /* 10 */ KEY_SUSPEND, | ||
| 634 | }; | ||
| 635 | |||
| 636 | ACPI_FUNCTION_TRACE("acpi_pcc_generete_keyinput"); | ||
| 637 | |||
| 638 | if (keyinput->key_mode == 0) | ||
| 639 | return_VOID; | ||
| 640 | |||
| 641 | hkey_num = hinf & 0xf; | ||
| 642 | |||
| 643 | if ((0 > hkey_num) || | ||
| 644 | (hkey_num > ARRAY_SIZE(key_map))) { | ||
| 645 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
| 646 | "hotkey number out of range: %d\n", | ||
| 647 | hkey_num)); | ||
| 648 | return_VOID; | ||
| 649 | } | ||
| 650 | |||
| 651 | key_code = key_map[hkey_num]; | ||
| 652 | |||
| 653 | if (key_code != -1) { | ||
| 654 | int pushed = (hinf & 0x80) ? TRUE : FALSE; | ||
| 655 | |||
| 656 | input_report_key(hotk_input_dev, key_code, pushed); | ||
| 657 | input_sync(hotk_input_dev); | ||
| 658 | } | ||
| 659 | } | ||
| 660 | |||
| 661 | static int acpi_pcc_hotkey_get_key(struct acpi_hotkey *hotkey) | ||
| 662 | { | ||
| 663 | unsigned long result; | ||
| 664 | acpi_status status = AE_OK; | ||
| 665 | |||
| 666 | ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_get_key"); | ||
| 667 | |||
| 668 | status = acpi_evaluate_integer(hotkey->handle, METHOD_HKEY_QUERY, | ||
| 669 | NULL, &result); | ||
| 670 | if (likely(ACPI_SUCCESS(status))) | ||
| 671 | hotkey->status = result; | ||
| 672 | else | ||
| 673 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
| 674 | "error getting hotkey status\n")); | ||
| 675 | |||
| 676 | return_VALUE(status == AE_OK); | ||
| 677 | } | ||
| 678 | |||
| 679 | void acpi_pcc_hotkey_notify(acpi_handle handle, u32 event, void *data) | ||
| 680 | { | ||
| 681 | struct acpi_hotkey *hotkey = (struct acpi_hotkey *) data; | ||
| 682 | |||
| 683 | ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_notify"); | ||
| 684 | |||
| 685 | switch (event) { | ||
| 686 | case HKEY_NOTIFY: | ||
| 687 | if (acpi_pcc_hotkey_get_key(hotkey)) { | ||
| 688 | /* generate event like '"pcc HKEY 00000080 00000084"' | ||
| 689 | * when Fn+F4 pressed */ | ||
| 690 | acpi_bus_generate_proc_event(hotkey->device, event, | ||
| 691 | hotkey->status); | ||
| 692 | } | ||
| 693 | acpi_pcc_generete_keyinput(hotkey); | ||
| 694 | break; | ||
| 695 | default: | ||
| 696 | /* nothing to do */ | ||
| 697 | break; | ||
| 698 | } | ||
| 699 | return_VOID; | ||
| 700 | } | ||
| 701 | |||
| 702 | /* ************************************************************************* | ||
| 703 | FS Interface (/proc) | ||
| 704 | ************************************************************************* */ | ||
| 705 | /* oepn proc file fs*/ | ||
| 706 | SEQ_OPEN_FS(acpi_pcc_dc_brightness_open_fs, acpi_pcc_dc_brightness_show); | ||
| 707 | SEQ_OPEN_FS(acpi_pcc_numbatteries_open_fs, acpi_pcc_numbatteries_show); | ||
| 708 | SEQ_OPEN_FS(acpi_pcc_lcdtype_open_fs, acpi_pcc_lcdtype_show); | ||
| 709 | SEQ_OPEN_FS(acpi_pcc_ac_brightness_max_open_fs, | ||
| 710 | acpi_pcc_ac_brightness_max_show); | ||
| 711 | SEQ_OPEN_FS(acpi_pcc_ac_brightness_min_open_fs, | ||
| 712 | acpi_pcc_ac_brightness_min_show); | ||
| 713 | SEQ_OPEN_FS(acpi_pcc_ac_brightness_open_fs, acpi_pcc_ac_brightness_show); | ||
| 714 | SEQ_OPEN_FS(acpi_pcc_dc_brightness_max_open_fs, | ||
| 715 | acpi_pcc_dc_brightness_max_show); | ||
| 716 | SEQ_OPEN_FS(acpi_pcc_dc_brightness_min_open_fs, | ||
| 717 | acpi_pcc_dc_brightness_min_show); | ||
| 718 | SEQ_OPEN_FS(acpi_pcc_brightness_open_fs, acpi_pcc_brightness_show); | ||
| 719 | SEQ_OPEN_FS(acpi_pcc_mute_open_fs, acpi_pcc_mute_show); | ||
| 720 | SEQ_OPEN_FS(acpi_pcc_version_open_fs, acpi_pcc_version_show); | ||
| 721 | SEQ_OPEN_FS(acpi_pcc_keyinput_open_fs, acpi_pcc_keyinput_show); | ||
| 722 | SEQ_OPEN_FS(acpi_pcc_sticky_key_open_fs, acpi_pcc_sticky_key_show); | ||
| 723 | |||
| 724 | static struct file_operations acpi_pcc_numbatteries_fops = | ||
| 725 | SEQ_FILEOPS_R(acpi_pcc_numbatteries_open_fs); | ||
| 726 | static struct file_operations acpi_pcc_lcdtype_fops = | ||
| 727 | SEQ_FILEOPS_R(acpi_pcc_lcdtype_open_fs); | ||
| 728 | static struct file_operations acpi_pcc_mute_fops = | ||
| 729 | SEQ_FILEOPS_RW(acpi_pcc_mute_open_fs, acpi_pcc_write_mute); | ||
| 730 | static struct file_operations acpi_pcc_ac_brightness_fops = | ||
| 731 | SEQ_FILEOPS_RW(acpi_pcc_ac_brightness_open_fs, | ||
| 732 | acpi_pcc_write_ac_brightness); | ||
| 733 | static struct file_operations acpi_pcc_ac_brightness_max_fops = | ||
| 734 | SEQ_FILEOPS_R(acpi_pcc_ac_brightness_max_open_fs); | ||
| 735 | static struct file_operations acpi_pcc_ac_brightness_min_fops = | ||
| 736 | SEQ_FILEOPS_R(acpi_pcc_ac_brightness_min_open_fs); | ||
| 737 | static struct file_operations acpi_pcc_dc_brightness_fops = | ||
| 738 | SEQ_FILEOPS_RW(acpi_pcc_dc_brightness_open_fs, | ||
| 739 | acpi_pcc_write_dc_brightness); | ||
| 740 | static struct file_operations acpi_pcc_dc_brightness_max_fops = | ||
| 741 | SEQ_FILEOPS_R(acpi_pcc_dc_brightness_max_open_fs); | ||
| 742 | static struct file_operations acpi_pcc_dc_brightness_min_fops = | ||
| 743 | SEQ_FILEOPS_R(acpi_pcc_dc_brightness_min_open_fs); | ||
| 744 | static struct file_operations acpi_pcc_brightness_fops = | ||
| 745 | SEQ_FILEOPS_RW(acpi_pcc_brightness_open_fs, | ||
| 746 | acpi_pcc_write_no_brightness); | ||
| 747 | static struct file_operations acpi_pcc_sticky_key_fops = | ||
| 748 | SEQ_FILEOPS_RW(acpi_pcc_sticky_key_open_fs, acpi_pcc_write_sticky_key); | ||
| 749 | static struct file_operations acpi_pcc_keyinput_fops = | ||
| 750 | SEQ_FILEOPS_RW(acpi_pcc_keyinput_open_fs, acpi_pcc_write_keyinput); | ||
| 751 | static struct file_operations acpi_pcc_version_fops = | ||
| 752 | SEQ_FILEOPS_R(acpi_pcc_version_open_fs); | ||
| 753 | |||
| 754 | struct proc_item { | ||
| 755 | const char *name; | ||
| 756 | struct file_operations *fops; | ||
| 757 | mode_t flag; | ||
| 758 | }; | ||
| 759 | |||
| 760 | /* Note: These functions map *exactly* to the SINF/SSET functions */ | ||
| 761 | struct proc_item acpi_pcc_proc_items_sifr[] = { | ||
| 762 | { "num_batteries", &acpi_pcc_numbatteries_fops, S_IRUGO }, | ||
| 763 | { "lcd_type", &acpi_pcc_lcdtype_fops, S_IRUGO }, | ||
| 764 | { "ac_brightness_max", &acpi_pcc_ac_brightness_max_fops, S_IRUGO }, | ||
| 765 | { "ac_brightness_min", &acpi_pcc_ac_brightness_min_fops, S_IRUGO }, | ||
| 766 | { "ac_brightness", &acpi_pcc_ac_brightness_fops, | ||
| 767 | S_IFREG | S_IRUGO | S_IWUSR }, | ||
| 768 | { "dc_brightness_max", &acpi_pcc_dc_brightness_max_fops, S_IRUGO }, | ||
| 769 | { "dc_brightness_min", &acpi_pcc_dc_brightness_min_fops, S_IRUGO }, | ||
| 770 | { "dc_brightness", &acpi_pcc_dc_brightness_fops, | ||
| 771 | S_IFREG | S_IRUGO | S_IWUSR }, | ||
| 772 | { "brightness", &acpi_pcc_brightness_fops, S_IFREG | S_IRUGO | S_IWUSR}, | ||
| 773 | { "mute", &acpi_pcc_mute_fops, S_IFREG | S_IRUGO | S_IWUSR }, | ||
| 774 | { NULL, NULL, 0 }, | ||
| 775 | }; | ||
| 776 | |||
| 777 | struct proc_item acpi_pcc_proc_items[] = { | ||
| 778 | { "sticky_key", &acpi_pcc_sticky_key_fops, S_IFREG | S_IRUGO | S_IWUSR}, | ||
| 779 | { "keyinput", &acpi_pcc_keyinput_fops, S_IFREG | S_IRUGO | S_IWUSR }, | ||
| 780 | { "version", &acpi_pcc_version_fops, S_IRUGO }, | ||
| 781 | { NULL, NULL, 0 }, | ||
| 782 | }; | ||
| 783 | |||
| 784 | static int __devinit acpi_pcc_add_device(struct acpi_device *device, | ||
| 785 | struct proc_item *proc_items, | ||
| 786 | int num) | ||
| 787 | { | ||
| 788 | struct acpi_hotkey *hotkey = acpi_driver_data(device); | ||
| 789 | struct proc_dir_entry *proc; | ||
| 790 | struct proc_item *item; | ||
| 791 | int i; | ||
| 792 | |||
| 793 | for (item = proc_items, i = 0; item->name && i < num; ++item, ++i) { | ||
| 794 | proc = create_proc_entry(item->name, item->flag, | ||
| 795 | hotkey->proc_dir_entry); | ||
| 796 | if (likely(proc)) { | ||
| 797 | proc->proc_fops = item->fops; | ||
| 798 | proc->data = hotkey; | ||
| 799 | proc->owner = THIS_MODULE; | ||
| 800 | } else { | ||
| 801 | while (i-- > 0) { | ||
| 802 | item--; | ||
| 803 | remove_proc_entry(item->name, | ||
| 804 | hotkey->proc_dir_entry); | ||
| 805 | } | ||
| 806 | return_VALUE(-ENODEV); | ||
| 807 | } | ||
| 808 | } | ||
| 809 | return_VALUE(0); | ||
| 810 | } | ||
| 811 | |||
| 812 | static int __devinit acpi_pcc_proc_init(struct acpi_device *device) | ||
| 813 | { | ||
| 814 | struct proc_dir_entry *acpi_pcc_dir; | ||
| 815 | struct acpi_hotkey *hotkey = acpi_driver_data(device); | ||
| 816 | acpi_status status; | ||
| 817 | |||
| 818 | ACPI_FUNCTION_TRACE("acpi_pcc_proc_init"); | ||
| 819 | |||
| 820 | acpi_pcc_dir = proc_mkdir(PROC_PCC, acpi_root_dir); | ||
| 821 | |||
| 822 | if (unlikely(!acpi_pcc_dir)) { | ||
| 823 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
| 824 | "Couldn't create dir in /proc\n")); | ||
| 825 | return_VALUE(-ENODEV); | ||
| 826 | } | ||
| 827 | |||
| 828 | acpi_pcc_dir->owner = THIS_MODULE; | ||
| 829 | hotkey->proc_dir_entry = acpi_pcc_dir; | ||
| 830 | |||
| 831 | status = acpi_pcc_add_device(device, acpi_pcc_proc_items_sifr, | ||
| 832 | hotkey->num_sifr); | ||
| 833 | status |= acpi_pcc_add_device(device, acpi_pcc_proc_items, | ||
| 834 | ARRAY_SIZE(acpi_pcc_proc_items)); | ||
| 835 | if (unlikely(status)) { | ||
| 836 | remove_proc_entry(PROC_PCC, acpi_root_dir); | ||
| 837 | hotkey->proc_dir_entry = NULL; | ||
| 838 | return_VALUE(-ENODEV); | ||
| 839 | } | ||
| 840 | |||
| 841 | return_VALUE(status); | ||
| 842 | } | ||
| 843 | |||
| 844 | static void __devexit acpi_pcc_remove_device(struct acpi_device *device, | ||
| 845 | struct proc_item *proc_items, | ||
| 846 | int num) | ||
| 847 | { | ||
| 848 | struct acpi_hotkey *hotkey = acpi_driver_data(device); | ||
| 849 | struct proc_item *item; | ||
| 850 | int i; | ||
| 851 | |||
| 852 | for (item = proc_items, i = 0; | ||
| 853 | item->name != NULL && i < num; | ||
| 854 | ++item, ++i) { | ||
| 855 | remove_proc_entry(item->name, hotkey->proc_dir_entry); | ||
| 856 | } | ||
| 857 | |||
| 858 | return_VOID; | ||
| 859 | } | ||
| 860 | |||
| 861 | /* ************************************************************************* | ||
| 862 | Power Management | ||
| 863 | ************************************************************************* */ | ||
| 864 | #ifdef CONFIG_PM | ||
| 865 | static int acpi_pcc_hotkey_resume(struct acpi_device *device) | ||
| 866 | { | ||
| 867 | struct acpi_hotkey *hotkey = acpi_driver_data(device); | ||
| 868 | acpi_status status = AE_OK; | ||
| 869 | |||
| 870 | ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_resume"); | ||
| 871 | |||
| 872 | if (device == NULL || hotkey == NULL) | ||
| 873 | return_VALUE(-EINVAL); | ||
| 874 | |||
| 875 | if (hotkey->num_sifr != 0) { | ||
| 876 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Sticky mode restore: %d\n", | ||
| 877 | hotkey->sticky_mode)); | ||
| 878 | |||
| 879 | status = acpi_pcc_write_sset(hotkey, SINF_STICKY_KEY, | ||
| 880 | hotkey->sticky_mode); | ||
| 881 | } | ||
| 882 | if (status != AE_OK) | ||
| 883 | return_VALUE(-EINVAL); | ||
| 884 | |||
| 885 | return_VALUE(0); | ||
| 886 | } | ||
| 887 | #endif | ||
| 888 | |||
| 889 | /* ************************************************************************* | ||
| 890 | Module init/remove | ||
| 891 | ************************************************************************* */ | ||
| 892 | /* ------------------------------------------------------------------------- | ||
| 893 | input | ||
| 894 | ------------------------------------------------------------------------- */ | ||
| 895 | static int __devinit acpi_pcc_init_input(struct acpi_hotkey *hotkey) | ||
| 896 | { | ||
| 897 | struct input_dev *hotk_input_dev; | ||
| 898 | struct pcc_keyinput *pcc_keyinput; | ||
| 899 | int error; | ||
| 900 | |||
| 901 | ACPI_FUNCTION_TRACE("acpi_pcc_init_input"); | ||
| 902 | |||
| 903 | hotk_input_dev = input_allocate_device(); | ||
| 904 | if (hotk_input_dev == NULL) { | ||
| 905 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
| 906 | "Couldn't allocate input device for hotkey")); | ||
| 907 | goto err_input; | ||
| 908 | } | ||
| 909 | |||
| 910 | pcc_keyinput = kcalloc(1, sizeof(struct pcc_keyinput), GFP_KERNEL); | ||
| 911 | |||
| 912 | if (pcc_keyinput == NULL) { | ||
| 913 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
| 914 | "Couldn't allocate mem for private data")); | ||
| 915 | goto err_pcc; | ||
| 916 | } | ||
| 917 | |||
| 918 | hotk_input_dev->evbit[0] = BIT(EV_KEY); | ||
| 919 | |||
| 920 | set_bit(KEY_BRIGHTNESSDOWN, hotk_input_dev->keybit); | ||
| 921 | set_bit(KEY_BRIGHTNESSUP, hotk_input_dev->keybit); | ||
| 922 | set_bit(KEY_MUTE, hotk_input_dev->keybit); | ||
| 923 | set_bit(KEY_VOLUMEDOWN, hotk_input_dev->keybit); | ||
| 924 | set_bit(KEY_VOLUMEUP, hotk_input_dev->keybit); | ||
| 925 | set_bit(KEY_SLEEP, hotk_input_dev->keybit); | ||
| 926 | set_bit(KEY_BATT, hotk_input_dev->keybit); | ||
| 927 | set_bit(KEY_SUSPEND, hotk_input_dev->keybit); | ||
| 928 | |||
| 929 | hotk_input_dev->name = ACPI_PCC_DRIVER_NAME; | ||
| 930 | hotk_input_dev->phys = ACPI_PCC_INPUT_PHYS; | ||
| 931 | hotk_input_dev->id.bustype = BUS_PCC_HOTKEY; | ||
| 932 | hotk_input_dev->id.vendor = 0x0001; | ||
| 933 | hotk_input_dev->id.product = 0x0001; | ||
| 934 | hotk_input_dev->id.version = 0x0100; | ||
| 935 | |||
| 936 | pcc_keyinput->key_mode = PCC_KEYINPUT_MODE; | ||
| 937 | pcc_keyinput->hotkey = hotkey; | ||
| 938 | |||
| 939 | input_set_drvdata(hotk_input_dev, pcc_keyinput); | ||
| 940 | |||
| 941 | hotkey->input_dev = hotk_input_dev; | ||
| 942 | |||
| 943 | error = input_register_device(hotk_input_dev); | ||
| 944 | |||
| 945 | if (error) | ||
| 946 | goto err_pcc; | ||
| 947 | |||
| 948 | return_VALUE(0); | ||
| 949 | |||
| 950 | err_pcc: | ||
| 951 | input_unregister_device(hotk_input_dev); | ||
| 952 | err_input: | ||
| 953 | return_VALUE(-ENOMEM); | ||
| 954 | } | ||
| 955 | |||
| 956 | static void __devexit acpi_pcc_remove_input(struct acpi_hotkey *hotkey) | ||
| 957 | { | ||
| 958 | struct input_dev *hotk_input_dev; | ||
| 959 | struct pcc_keyinput *pcc_keyinput; | ||
| 960 | |||
| 961 | ACPI_FUNCTION_TRACE("acpi_pcc_remove_input"); | ||
| 962 | |||
| 963 | if (hotkey == NULL) { | ||
| 964 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Can't free memory")); | ||
| 965 | return_VOID; | ||
| 966 | } | ||
| 967 | |||
| 968 | hotk_input_dev = hotkey->input_dev; | ||
| 969 | pcc_keyinput = input_get_drvdata(hotk_input_dev); | ||
| 970 | |||
| 971 | input_unregister_device(hotk_input_dev); | ||
| 972 | |||
| 973 | kfree(pcc_keyinput); | ||
| 974 | } | ||
| 975 | |||
| 976 | /* ------------------------------------------------------------------------- | ||
| 977 | ACPI | ||
| 978 | ------------------------------------------------------------------------- */ | ||
| 979 | static int __devinit acpi_pcc_hotkey_add(struct acpi_device *device) | ||
| 980 | { | ||
| 981 | acpi_status status = AE_OK; | ||
| 982 | struct acpi_hotkey *hotkey = NULL; | ||
| 983 | int sifr_status, num_sifr, result; | ||
| 984 | |||
| 985 | ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_add"); | ||
| 986 | |||
| 987 | if (device == NULL) | ||
| 988 | return_VALUE(-EINVAL); | ||
| 989 | |||
| 990 | sifr_status = acpi_pcc_get_sqty(device); | ||
| 991 | |||
| 992 | if (sifr_status > 255) { | ||
| 993 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "num_sifr too large")); | ||
| 994 | return_VALUE(-ENODEV); | ||
| 995 | } | ||
| 996 | |||
| 997 | if (sifr_status < 0) { | ||
| 998 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "not support SQTY")); | ||
| 999 | num_sifr = 0; | ||
| 1000 | } else { | ||
| 1001 | num_sifr = sifr_status; | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | hotkey = kcalloc(1, sizeof(struct acpi_hotkey), GFP_KERNEL); | ||
| 1005 | if (hotkey == NULL) { | ||
| 1006 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
| 1007 | "Couldn't allocate mem for hotkey")); | ||
| 1008 | return_VALUE(-ENOMEM); | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | hotkey->device = device; | ||
| 1012 | hotkey->handle = device->handle; | ||
| 1013 | hotkey->num_sifr = num_sifr; | ||
| 1014 | device->driver_data = hotkey; | ||
| 1015 | strcpy(acpi_device_name(device), ACPI_PCC_DEVICE_NAME); | ||
| 1016 | strcpy(acpi_device_class(device), ACPI_PCC_CLASS); | ||
| 1017 | |||
| 1018 | status = acpi_install_notify_handler(hotkey->handle, | ||
| 1019 | ACPI_DEVICE_NOTIFY, | ||
| 1020 | acpi_pcc_hotkey_notify, | ||
| 1021 | hotkey); | ||
| 1022 | |||
| 1023 | if (ACPI_FAILURE(status)) { | ||
| 1024 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
| 1025 | "Error installing notify handler\n")); | ||
| 1026 | kfree(hotkey); | ||
| 1027 | return_VALUE(-ENODEV); | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | result = acpi_pcc_init_input(hotkey); | ||
| 1031 | if (result != 0) { | ||
| 1032 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
| 1033 | "Error installing keyinput handler\n")); | ||
| 1034 | kfree(hotkey); | ||
| 1035 | return_VALUE(result); | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | return_VALUE(acpi_pcc_proc_init(device)); | ||
| 1039 | } | ||
| 1040 | |||
| 1041 | static int __devexit acpi_pcc_hotkey_remove(struct acpi_device *device, | ||
| 1042 | int type) | ||
| 1043 | { | ||
| 1044 | acpi_status status = AE_OK; | ||
| 1045 | struct acpi_hotkey *hotkey = acpi_driver_data(device); | ||
| 1046 | |||
| 1047 | ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_remove"); | ||
| 1048 | |||
| 1049 | if (!device || !hotkey) | ||
| 1050 | return_VALUE(-EINVAL); | ||
| 1051 | |||
| 1052 | if (hotkey->proc_dir_entry) { | ||
| 1053 | acpi_pcc_remove_device(device, acpi_pcc_proc_items_sifr, | ||
| 1054 | hotkey->num_sifr); | ||
| 1055 | acpi_pcc_remove_device(device, acpi_pcc_proc_items, | ||
| 1056 | ARRAY_SIZE(acpi_pcc_proc_items)); | ||
| 1057 | remove_proc_entry(PROC_PCC, acpi_root_dir); | ||
| 1058 | } | ||
| 1059 | |||
| 1060 | status = acpi_remove_notify_handler(hotkey->handle, | ||
| 1061 | ACPI_DEVICE_NOTIFY, acpi_pcc_hotkey_notify); | ||
| 1062 | |||
| 1063 | if (ACPI_FAILURE(status)) { | ||
| 1064 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
| 1065 | "Error removing notify handler\n")); | ||
| 1066 | } | ||
| 1067 | |||
| 1068 | acpi_pcc_remove_input(hotkey); | ||
| 1069 | kfree(hotkey); | ||
| 1070 | return_VALUE(status == AE_OK); | ||
| 1071 | } | ||
| 1072 | |||
| 1073 | /* ********************************************************************* | ||
| 1074 | Module entry point | ||
| 1075 | ********************************************************************* */ | ||
| 1076 | static int __init acpi_pcc_init(void) | ||
| 1077 | { | ||
| 1078 | int result; | ||
| 1079 | |||
| 1080 | ACPI_FUNCTION_TRACE("acpi_pcc_init"); | ||
| 1081 | |||
| 1082 | printk(KERN_INFO LOGPREFIX "loading...\n"); | ||
| 1083 | |||
| 1084 | if (acpi_disabled) { | ||
| 1085 | printk(KERN_INFO LOGPREFIX "ACPI disabled.\n"); | ||
| 1086 | return_VALUE(-ENODEV); | ||
| 1087 | } | ||
| 1088 | |||
| 1089 | result = acpi_bus_register_driver(&acpi_pcc_driver); | ||
| 1090 | if (result < 0) { | ||
| 1091 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
| 1092 | "Error registering hotkey driver\n")); | ||
| 1093 | return_VALUE(-ENODEV); | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | return_VALUE(result); | ||
| 1097 | } | ||
| 1098 | |||
| 1099 | static void __exit acpi_pcc_exit(void) | ||
| 1100 | { | ||
| 1101 | ACPI_FUNCTION_TRACE("acpi_pcc_exit"); | ||
| 1102 | |||
| 1103 | printk(KERN_INFO LOGPREFIX "unloading...\n"); | ||
| 1104 | |||
| 1105 | acpi_bus_unregister_driver(&acpi_pcc_driver); | ||
| 1106 | |||
| 1107 | return_VOID; | ||
| 1108 | } | ||
| 1109 | |||
| 1110 | module_init(acpi_pcc_init); | ||
| 1111 | module_exit(acpi_pcc_exit); | ||
