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-rc9 2773 lines 73 kB view raw
1/* 2 * ACPI Sony Notebook Control Driver (SNC and SPIC) 3 * 4 * Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net> 5 * Copyright (C) 2007 Mattia Dongili <malattia@linux.it> 6 * 7 * Parts of this driver inspired from asus_acpi.c and ibm_acpi.c 8 * which are copyrighted by their respective authors. 9 * 10 * The SNY6001 driver part is based on the sonypi driver which includes 11 * material from: 12 * 13 * Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net> 14 * 15 * Copyright (C) 2005 Narayanan R S <nars@kadamba.org> 16 * 17 * Copyright (C) 2001-2002 Alcôve <www.alcove.com> 18 * 19 * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au> 20 * 21 * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp> 22 * 23 * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp> 24 * 25 * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com> 26 * 27 * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras. 28 * 29 * This program is free software; you can redistribute it and/or modify 30 * it under the terms of the GNU General Public License as published by 31 * the Free Software Foundation; either version 2 of the License, or 32 * (at your option) any later version. 33 * 34 * This program is distributed in the hope that it will be useful, 35 * but WITHOUT ANY WARRANTY; without even the implied warranty of 36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 37 * GNU General Public License for more details. 38 * 39 * You should have received a copy of the GNU General Public License 40 * along with this program; if not, write to the Free Software 41 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 42 * 43 */ 44 45#include <linux/kernel.h> 46#include <linux/module.h> 47#include <linux/moduleparam.h> 48#include <linux/init.h> 49#include <linux/types.h> 50#include <linux/backlight.h> 51#include <linux/platform_device.h> 52#include <linux/err.h> 53#include <linux/dmi.h> 54#include <linux/pci.h> 55#include <linux/interrupt.h> 56#include <linux/delay.h> 57#include <linux/input.h> 58#include <linux/kfifo.h> 59#include <linux/workqueue.h> 60#include <linux/acpi.h> 61#include <acpi/acpi_drivers.h> 62#include <acpi/acpi_bus.h> 63#include <asm/uaccess.h> 64#include <linux/sonypi.h> 65#include <linux/sony-laptop.h> 66#ifdef CONFIG_SONYPI_COMPAT 67#include <linux/poll.h> 68#include <linux/miscdevice.h> 69#endif 70 71#define DRV_PFX "sony-laptop: " 72#define dprintk(msg...) do { \ 73 if (debug) printk(KERN_WARNING DRV_PFX msg); \ 74} while (0) 75 76#define SONY_LAPTOP_DRIVER_VERSION "0.6" 77 78#define SONY_NC_CLASS "sony-nc" 79#define SONY_NC_HID "SNY5001" 80#define SONY_NC_DRIVER_NAME "Sony Notebook Control Driver" 81 82#define SONY_PIC_CLASS "sony-pic" 83#define SONY_PIC_HID "SNY6001" 84#define SONY_PIC_DRIVER_NAME "Sony Programmable IO Control Driver" 85 86MODULE_AUTHOR("Stelian Pop, Mattia Dongili"); 87MODULE_DESCRIPTION("Sony laptop extras driver (SPIC and SNC ACPI device)"); 88MODULE_LICENSE("GPL"); 89MODULE_VERSION(SONY_LAPTOP_DRIVER_VERSION); 90 91static int debug; 92module_param(debug, int, 0); 93MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help " 94 "the development of this driver"); 95 96static int no_spic; /* = 0 */ 97module_param(no_spic, int, 0444); 98MODULE_PARM_DESC(no_spic, 99 "set this if you don't want to enable the SPIC device"); 100 101static int compat; /* = 0 */ 102module_param(compat, int, 0444); 103MODULE_PARM_DESC(compat, 104 "set this if you want to enable backward compatibility mode"); 105 106static unsigned long mask = 0xffffffff; 107module_param(mask, ulong, 0644); 108MODULE_PARM_DESC(mask, 109 "set this to the mask of event you want to enable (see doc)"); 110 111static int camera; /* = 0 */ 112module_param(camera, int, 0444); 113MODULE_PARM_DESC(camera, 114 "set this to 1 to enable Motion Eye camera controls " 115 "(only use it if you have a C1VE or C1VN model)"); 116 117#ifdef CONFIG_SONYPI_COMPAT 118static int minor = -1; 119module_param(minor, int, 0); 120MODULE_PARM_DESC(minor, 121 "minor number of the misc device for the SPIC compatibility code, " 122 "default is -1 (automatic)"); 123#endif 124 125/*********** Input Devices ***********/ 126 127#define SONY_LAPTOP_BUF_SIZE 128 128struct sony_laptop_input_s { 129 atomic_t users; 130 struct input_dev *jog_dev; 131 struct input_dev *key_dev; 132 struct kfifo *fifo; 133 spinlock_t fifo_lock; 134 struct workqueue_struct *wq; 135}; 136static struct sony_laptop_input_s sony_laptop_input = { 137 .users = ATOMIC_INIT(0), 138}; 139 140struct sony_laptop_keypress { 141 struct input_dev *dev; 142 int key; 143}; 144 145/* Correspondance table between sonypi events 146 * and input layer indexes in the keymap 147 */ 148static int sony_laptop_input_index[] = { 149 -1, /* 0 no event */ 150 -1, /* 1 SONYPI_EVENT_JOGDIAL_DOWN */ 151 -1, /* 2 SONYPI_EVENT_JOGDIAL_UP */ 152 -1, /* 3 SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */ 153 -1, /* 4 SONYPI_EVENT_JOGDIAL_UP_PRESSED */ 154 -1, /* 5 SONYPI_EVENT_JOGDIAL_PRESSED */ 155 -1, /* 6 SONYPI_EVENT_JOGDIAL_RELEASED */ 156 0, /* 7 SONYPI_EVENT_CAPTURE_PRESSED */ 157 1, /* 8 SONYPI_EVENT_CAPTURE_RELEASED */ 158 2, /* 9 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */ 159 3, /* 10 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */ 160 4, /* 11 SONYPI_EVENT_FNKEY_ESC */ 161 5, /* 12 SONYPI_EVENT_FNKEY_F1 */ 162 6, /* 13 SONYPI_EVENT_FNKEY_F2 */ 163 7, /* 14 SONYPI_EVENT_FNKEY_F3 */ 164 8, /* 15 SONYPI_EVENT_FNKEY_F4 */ 165 9, /* 16 SONYPI_EVENT_FNKEY_F5 */ 166 10, /* 17 SONYPI_EVENT_FNKEY_F6 */ 167 11, /* 18 SONYPI_EVENT_FNKEY_F7 */ 168 12, /* 19 SONYPI_EVENT_FNKEY_F8 */ 169 13, /* 20 SONYPI_EVENT_FNKEY_F9 */ 170 14, /* 21 SONYPI_EVENT_FNKEY_F10 */ 171 15, /* 22 SONYPI_EVENT_FNKEY_F11 */ 172 16, /* 23 SONYPI_EVENT_FNKEY_F12 */ 173 17, /* 24 SONYPI_EVENT_FNKEY_1 */ 174 18, /* 25 SONYPI_EVENT_FNKEY_2 */ 175 19, /* 26 SONYPI_EVENT_FNKEY_D */ 176 20, /* 27 SONYPI_EVENT_FNKEY_E */ 177 21, /* 28 SONYPI_EVENT_FNKEY_F */ 178 22, /* 29 SONYPI_EVENT_FNKEY_S */ 179 23, /* 30 SONYPI_EVENT_FNKEY_B */ 180 24, /* 31 SONYPI_EVENT_BLUETOOTH_PRESSED */ 181 25, /* 32 SONYPI_EVENT_PKEY_P1 */ 182 26, /* 33 SONYPI_EVENT_PKEY_P2 */ 183 27, /* 34 SONYPI_EVENT_PKEY_P3 */ 184 28, /* 35 SONYPI_EVENT_BACK_PRESSED */ 185 -1, /* 36 SONYPI_EVENT_LID_CLOSED */ 186 -1, /* 37 SONYPI_EVENT_LID_OPENED */ 187 29, /* 38 SONYPI_EVENT_BLUETOOTH_ON */ 188 30, /* 39 SONYPI_EVENT_BLUETOOTH_OFF */ 189 31, /* 40 SONYPI_EVENT_HELP_PRESSED */ 190 32, /* 41 SONYPI_EVENT_FNKEY_ONLY */ 191 33, /* 42 SONYPI_EVENT_JOGDIAL_FAST_DOWN */ 192 34, /* 43 SONYPI_EVENT_JOGDIAL_FAST_UP */ 193 35, /* 44 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */ 194 36, /* 45 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */ 195 37, /* 46 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */ 196 38, /* 47 SONYPI_EVENT_JOGDIAL_VFAST_UP */ 197 39, /* 48 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */ 198 40, /* 49 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */ 199 41, /* 50 SONYPI_EVENT_ZOOM_PRESSED */ 200 42, /* 51 SONYPI_EVENT_THUMBPHRASE_PRESSED */ 201 43, /* 52 SONYPI_EVENT_MEYE_FACE */ 202 44, /* 53 SONYPI_EVENT_MEYE_OPPOSITE */ 203 45, /* 54 SONYPI_EVENT_MEMORYSTICK_INSERT */ 204 46, /* 55 SONYPI_EVENT_MEMORYSTICK_EJECT */ 205 -1, /* 56 SONYPI_EVENT_ANYBUTTON_RELEASED */ 206 -1, /* 57 SONYPI_EVENT_BATTERY_INSERT */ 207 -1, /* 58 SONYPI_EVENT_BATTERY_REMOVE */ 208 -1, /* 59 SONYPI_EVENT_FNKEY_RELEASED */ 209 47, /* 60 SONYPI_EVENT_WIRELESS_ON */ 210 48, /* 61 SONYPI_EVENT_WIRELESS_OFF */ 211 49, /* 62 SONYPI_EVENT_ZOOM_IN_PRESSED */ 212 50, /* 63 SONYPI_EVENT_ZOOM_OUT_PRESSED */ 213}; 214 215static int sony_laptop_input_keycode_map[] = { 216 KEY_CAMERA, /* 0 SONYPI_EVENT_CAPTURE_PRESSED */ 217 KEY_RESERVED, /* 1 SONYPI_EVENT_CAPTURE_RELEASED */ 218 KEY_RESERVED, /* 2 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */ 219 KEY_RESERVED, /* 3 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */ 220 KEY_FN_ESC, /* 4 SONYPI_EVENT_FNKEY_ESC */ 221 KEY_FN_F1, /* 5 SONYPI_EVENT_FNKEY_F1 */ 222 KEY_FN_F2, /* 6 SONYPI_EVENT_FNKEY_F2 */ 223 KEY_FN_F3, /* 7 SONYPI_EVENT_FNKEY_F3 */ 224 KEY_FN_F4, /* 8 SONYPI_EVENT_FNKEY_F4 */ 225 KEY_FN_F5, /* 9 SONYPI_EVENT_FNKEY_F5 */ 226 KEY_FN_F6, /* 10 SONYPI_EVENT_FNKEY_F6 */ 227 KEY_FN_F7, /* 11 SONYPI_EVENT_FNKEY_F7 */ 228 KEY_FN_F8, /* 12 SONYPI_EVENT_FNKEY_F8 */ 229 KEY_FN_F9, /* 13 SONYPI_EVENT_FNKEY_F9 */ 230 KEY_FN_F10, /* 14 SONYPI_EVENT_FNKEY_F10 */ 231 KEY_FN_F11, /* 15 SONYPI_EVENT_FNKEY_F11 */ 232 KEY_FN_F12, /* 16 SONYPI_EVENT_FNKEY_F12 */ 233 KEY_FN_F1, /* 17 SONYPI_EVENT_FNKEY_1 */ 234 KEY_FN_F2, /* 18 SONYPI_EVENT_FNKEY_2 */ 235 KEY_FN_D, /* 19 SONYPI_EVENT_FNKEY_D */ 236 KEY_FN_E, /* 20 SONYPI_EVENT_FNKEY_E */ 237 KEY_FN_F, /* 21 SONYPI_EVENT_FNKEY_F */ 238 KEY_FN_S, /* 22 SONYPI_EVENT_FNKEY_S */ 239 KEY_FN_B, /* 23 SONYPI_EVENT_FNKEY_B */ 240 KEY_BLUETOOTH, /* 24 SONYPI_EVENT_BLUETOOTH_PRESSED */ 241 KEY_PROG1, /* 25 SONYPI_EVENT_PKEY_P1 */ 242 KEY_PROG2, /* 26 SONYPI_EVENT_PKEY_P2 */ 243 KEY_PROG3, /* 27 SONYPI_EVENT_PKEY_P3 */ 244 KEY_BACK, /* 28 SONYPI_EVENT_BACK_PRESSED */ 245 KEY_BLUETOOTH, /* 29 SONYPI_EVENT_BLUETOOTH_ON */ 246 KEY_BLUETOOTH, /* 30 SONYPI_EVENT_BLUETOOTH_OFF */ 247 KEY_HELP, /* 31 SONYPI_EVENT_HELP_PRESSED */ 248 KEY_FN, /* 32 SONYPI_EVENT_FNKEY_ONLY */ 249 KEY_RESERVED, /* 33 SONYPI_EVENT_JOGDIAL_FAST_DOWN */ 250 KEY_RESERVED, /* 34 SONYPI_EVENT_JOGDIAL_FAST_UP */ 251 KEY_RESERVED, /* 35 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */ 252 KEY_RESERVED, /* 36 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */ 253 KEY_RESERVED, /* 37 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */ 254 KEY_RESERVED, /* 38 SONYPI_EVENT_JOGDIAL_VFAST_UP */ 255 KEY_RESERVED, /* 39 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */ 256 KEY_RESERVED, /* 40 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */ 257 KEY_ZOOM, /* 41 SONYPI_EVENT_ZOOM_PRESSED */ 258 BTN_THUMB, /* 42 SONYPI_EVENT_THUMBPHRASE_PRESSED */ 259 KEY_RESERVED, /* 43 SONYPI_EVENT_MEYE_FACE */ 260 KEY_RESERVED, /* 44 SONYPI_EVENT_MEYE_OPPOSITE */ 261 KEY_RESERVED, /* 45 SONYPI_EVENT_MEMORYSTICK_INSERT */ 262 KEY_RESERVED, /* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */ 263 KEY_WLAN, /* 47 SONYPI_EVENT_WIRELESS_ON */ 264 KEY_WLAN, /* 48 SONYPI_EVENT_WIRELESS_OFF */ 265 KEY_ZOOMIN, /* 49 SONYPI_EVENT_ZOOM_IN_PRESSED */ 266 KEY_ZOOMOUT /* 50 SONYPI_EVENT_ZOOM_OUT_PRESSED */ 267}; 268 269/* release buttons after a short delay if pressed */ 270static void do_sony_laptop_release_key(struct work_struct *work) 271{ 272 struct sony_laptop_keypress kp; 273 274 while (kfifo_get(sony_laptop_input.fifo, (unsigned char *)&kp, 275 sizeof(kp)) == sizeof(kp)) { 276 msleep(10); 277 input_report_key(kp.dev, kp.key, 0); 278 input_sync(kp.dev); 279 } 280} 281static DECLARE_WORK(sony_laptop_release_key_work, 282 do_sony_laptop_release_key); 283 284/* forward event to the input subsystem */ 285static void sony_laptop_report_input_event(u8 event) 286{ 287 struct input_dev *jog_dev = sony_laptop_input.jog_dev; 288 struct input_dev *key_dev = sony_laptop_input.key_dev; 289 struct sony_laptop_keypress kp = { NULL }; 290 291 if (event == SONYPI_EVENT_FNKEY_RELEASED) { 292 /* Nothing, not all VAIOs generate this event */ 293 return; 294 } 295 296 /* report events */ 297 switch (event) { 298 /* jog_dev events */ 299 case SONYPI_EVENT_JOGDIAL_UP: 300 case SONYPI_EVENT_JOGDIAL_UP_PRESSED: 301 input_report_rel(jog_dev, REL_WHEEL, 1); 302 input_sync(jog_dev); 303 return; 304 305 case SONYPI_EVENT_JOGDIAL_DOWN: 306 case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED: 307 input_report_rel(jog_dev, REL_WHEEL, -1); 308 input_sync(jog_dev); 309 return; 310 311 /* key_dev events */ 312 case SONYPI_EVENT_JOGDIAL_PRESSED: 313 kp.key = BTN_MIDDLE; 314 kp.dev = jog_dev; 315 break; 316 317 default: 318 if (event >= ARRAY_SIZE(sony_laptop_input_index)) { 319 dprintk("sony_laptop_report_input_event, event not known: %d\n", event); 320 break; 321 } 322 if (sony_laptop_input_index[event] != -1) { 323 kp.key = sony_laptop_input_keycode_map[sony_laptop_input_index[event]]; 324 if (kp.key != KEY_UNKNOWN) 325 kp.dev = key_dev; 326 } 327 break; 328 } 329 330 if (kp.dev) { 331 input_report_key(kp.dev, kp.key, 1); 332 /* we emit the scancode so we can always remap the key */ 333 input_event(kp.dev, EV_MSC, MSC_SCAN, event); 334 input_sync(kp.dev); 335 kfifo_put(sony_laptop_input.fifo, 336 (unsigned char *)&kp, sizeof(kp)); 337 338 if (!work_pending(&sony_laptop_release_key_work)) 339 queue_work(sony_laptop_input.wq, 340 &sony_laptop_release_key_work); 341 } else 342 dprintk("unknown input event %.2x\n", event); 343} 344 345static int sony_laptop_setup_input(struct acpi_device *acpi_device) 346{ 347 struct input_dev *jog_dev; 348 struct input_dev *key_dev; 349 int i; 350 int error; 351 352 /* don't run again if already initialized */ 353 if (atomic_add_return(1, &sony_laptop_input.users) > 1) 354 return 0; 355 356 /* kfifo */ 357 spin_lock_init(&sony_laptop_input.fifo_lock); 358 sony_laptop_input.fifo = 359 kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL, 360 &sony_laptop_input.fifo_lock); 361 if (IS_ERR(sony_laptop_input.fifo)) { 362 printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); 363 error = PTR_ERR(sony_laptop_input.fifo); 364 goto err_dec_users; 365 } 366 367 /* init workqueue */ 368 sony_laptop_input.wq = create_singlethread_workqueue("sony-laptop"); 369 if (!sony_laptop_input.wq) { 370 printk(KERN_ERR DRV_PFX 371 "Unabe to create workqueue.\n"); 372 error = -ENXIO; 373 goto err_free_kfifo; 374 } 375 376 /* input keys */ 377 key_dev = input_allocate_device(); 378 if (!key_dev) { 379 error = -ENOMEM; 380 goto err_destroy_wq; 381 } 382 383 key_dev->name = "Sony Vaio Keys"; 384 key_dev->id.bustype = BUS_ISA; 385 key_dev->id.vendor = PCI_VENDOR_ID_SONY; 386 key_dev->dev.parent = &acpi_device->dev; 387 388 /* Initialize the Input Drivers: special keys */ 389 set_bit(EV_KEY, key_dev->evbit); 390 set_bit(EV_MSC, key_dev->evbit); 391 set_bit(MSC_SCAN, key_dev->mscbit); 392 key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]); 393 key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map); 394 key_dev->keycode = &sony_laptop_input_keycode_map; 395 for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++) { 396 if (sony_laptop_input_keycode_map[i] != KEY_RESERVED) { 397 set_bit(sony_laptop_input_keycode_map[i], 398 key_dev->keybit); 399 } 400 } 401 402 error = input_register_device(key_dev); 403 if (error) 404 goto err_free_keydev; 405 406 sony_laptop_input.key_dev = key_dev; 407 408 /* jogdial */ 409 jog_dev = input_allocate_device(); 410 if (!jog_dev) { 411 error = -ENOMEM; 412 goto err_unregister_keydev; 413 } 414 415 jog_dev->name = "Sony Vaio Jogdial"; 416 jog_dev->id.bustype = BUS_ISA; 417 jog_dev->id.vendor = PCI_VENDOR_ID_SONY; 418 key_dev->dev.parent = &acpi_device->dev; 419 420 jog_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); 421 jog_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_MIDDLE); 422 jog_dev->relbit[0] = BIT_MASK(REL_WHEEL); 423 424 error = input_register_device(jog_dev); 425 if (error) 426 goto err_free_jogdev; 427 428 sony_laptop_input.jog_dev = jog_dev; 429 430 return 0; 431 432err_free_jogdev: 433 input_free_device(jog_dev); 434 435err_unregister_keydev: 436 input_unregister_device(key_dev); 437 /* to avoid kref underflow below at input_free_device */ 438 key_dev = NULL; 439 440err_free_keydev: 441 input_free_device(key_dev); 442 443err_destroy_wq: 444 destroy_workqueue(sony_laptop_input.wq); 445 446err_free_kfifo: 447 kfifo_free(sony_laptop_input.fifo); 448 449err_dec_users: 450 atomic_dec(&sony_laptop_input.users); 451 return error; 452} 453 454static void sony_laptop_remove_input(void) 455{ 456 /* cleanup only after the last user has gone */ 457 if (!atomic_dec_and_test(&sony_laptop_input.users)) 458 return; 459 460 /* flush workqueue first */ 461 flush_workqueue(sony_laptop_input.wq); 462 463 /* destroy input devs */ 464 input_unregister_device(sony_laptop_input.key_dev); 465 sony_laptop_input.key_dev = NULL; 466 467 if (sony_laptop_input.jog_dev) { 468 input_unregister_device(sony_laptop_input.jog_dev); 469 sony_laptop_input.jog_dev = NULL; 470 } 471 472 destroy_workqueue(sony_laptop_input.wq); 473 kfifo_free(sony_laptop_input.fifo); 474} 475 476/*********** Platform Device ***********/ 477 478static atomic_t sony_pf_users = ATOMIC_INIT(0); 479static struct platform_driver sony_pf_driver = { 480 .driver = { 481 .name = "sony-laptop", 482 .owner = THIS_MODULE, 483 } 484}; 485static struct platform_device *sony_pf_device; 486 487static int sony_pf_add(void) 488{ 489 int ret = 0; 490 491 /* don't run again if already initialized */ 492 if (atomic_add_return(1, &sony_pf_users) > 1) 493 return 0; 494 495 ret = platform_driver_register(&sony_pf_driver); 496 if (ret) 497 goto out; 498 499 sony_pf_device = platform_device_alloc("sony-laptop", -1); 500 if (!sony_pf_device) { 501 ret = -ENOMEM; 502 goto out_platform_registered; 503 } 504 505 ret = platform_device_add(sony_pf_device); 506 if (ret) 507 goto out_platform_alloced; 508 509 return 0; 510 511 out_platform_alloced: 512 platform_device_put(sony_pf_device); 513 sony_pf_device = NULL; 514 out_platform_registered: 515 platform_driver_unregister(&sony_pf_driver); 516 out: 517 atomic_dec(&sony_pf_users); 518 return ret; 519} 520 521static void sony_pf_remove(void) 522{ 523 /* deregister only after the last user has gone */ 524 if (!atomic_dec_and_test(&sony_pf_users)) 525 return; 526 527 platform_device_del(sony_pf_device); 528 platform_device_put(sony_pf_device); 529 platform_driver_unregister(&sony_pf_driver); 530} 531 532/*********** SNC (SNY5001) Device ***********/ 533 534/* the device uses 1-based values, while the backlight subsystem uses 535 0-based values */ 536#define SONY_MAX_BRIGHTNESS 8 537 538#define SNC_VALIDATE_IN 0 539#define SNC_VALIDATE_OUT 1 540 541static ssize_t sony_nc_sysfs_show(struct device *, struct device_attribute *, 542 char *); 543static ssize_t sony_nc_sysfs_store(struct device *, struct device_attribute *, 544 const char *, size_t); 545static int boolean_validate(const int, const int); 546static int brightness_default_validate(const int, const int); 547 548struct sony_nc_value { 549 char *name; /* name of the entry */ 550 char **acpiget; /* names of the ACPI get function */ 551 char **acpiset; /* names of the ACPI set function */ 552 int (*validate)(const int, const int); /* input/output validation */ 553 int value; /* current setting */ 554 int valid; /* Has ever been set */ 555 int debug; /* active only in debug mode ? */ 556 struct device_attribute devattr; /* sysfs atribute */ 557}; 558 559#define SNC_HANDLE_NAMES(_name, _values...) \ 560 static char *snc_##_name[] = { _values, NULL } 561 562#define SNC_HANDLE(_name, _getters, _setters, _validate, _debug) \ 563 { \ 564 .name = __stringify(_name), \ 565 .acpiget = _getters, \ 566 .acpiset = _setters, \ 567 .validate = _validate, \ 568 .debug = _debug, \ 569 .devattr = __ATTR(_name, 0, sony_nc_sysfs_show, sony_nc_sysfs_store), \ 570 } 571 572#define SNC_HANDLE_NULL { .name = NULL } 573 574SNC_HANDLE_NAMES(fnkey_get, "GHKE"); 575 576SNC_HANDLE_NAMES(brightness_def_get, "GPBR"); 577SNC_HANDLE_NAMES(brightness_def_set, "SPBR"); 578 579SNC_HANDLE_NAMES(cdpower_get, "GCDP"); 580SNC_HANDLE_NAMES(cdpower_set, "SCDP", "CDPW"); 581 582SNC_HANDLE_NAMES(audiopower_get, "GAZP"); 583SNC_HANDLE_NAMES(audiopower_set, "AZPW"); 584 585SNC_HANDLE_NAMES(lanpower_get, "GLNP"); 586SNC_HANDLE_NAMES(lanpower_set, "LNPW"); 587 588SNC_HANDLE_NAMES(lidstate_get, "GLID"); 589 590SNC_HANDLE_NAMES(indicatorlamp_get, "GILS"); 591SNC_HANDLE_NAMES(indicatorlamp_set, "SILS"); 592 593SNC_HANDLE_NAMES(gainbass_get, "GMGB"); 594SNC_HANDLE_NAMES(gainbass_set, "CMGB"); 595 596SNC_HANDLE_NAMES(PID_get, "GPID"); 597 598SNC_HANDLE_NAMES(CTR_get, "GCTR"); 599SNC_HANDLE_NAMES(CTR_set, "SCTR"); 600 601SNC_HANDLE_NAMES(PCR_get, "GPCR"); 602SNC_HANDLE_NAMES(PCR_set, "SPCR"); 603 604SNC_HANDLE_NAMES(CMI_get, "GCMI"); 605SNC_HANDLE_NAMES(CMI_set, "SCMI"); 606 607static struct sony_nc_value sony_nc_values[] = { 608 SNC_HANDLE(brightness_default, snc_brightness_def_get, 609 snc_brightness_def_set, brightness_default_validate, 0), 610 SNC_HANDLE(fnkey, snc_fnkey_get, NULL, NULL, 0), 611 SNC_HANDLE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0), 612 SNC_HANDLE(audiopower, snc_audiopower_get, snc_audiopower_set, 613 boolean_validate, 0), 614 SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set, 615 boolean_validate, 1), 616 SNC_HANDLE(lidstate, snc_lidstate_get, NULL, 617 boolean_validate, 0), 618 SNC_HANDLE(indicatorlamp, snc_indicatorlamp_get, snc_indicatorlamp_set, 619 boolean_validate, 0), 620 SNC_HANDLE(gainbass, snc_gainbass_get, snc_gainbass_set, 621 boolean_validate, 0), 622 /* unknown methods */ 623 SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1), 624 SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1), 625 SNC_HANDLE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1), 626 SNC_HANDLE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1), 627 SNC_HANDLE_NULL 628}; 629 630static acpi_handle sony_nc_acpi_handle; 631static struct acpi_device *sony_nc_acpi_device = NULL; 632 633/* 634 * acpi_evaluate_object wrappers 635 */ 636static int acpi_callgetfunc(acpi_handle handle, char *name, int *result) 637{ 638 struct acpi_buffer output; 639 union acpi_object out_obj; 640 acpi_status status; 641 642 output.length = sizeof(out_obj); 643 output.pointer = &out_obj; 644 645 status = acpi_evaluate_object(handle, name, NULL, &output); 646 if ((status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER)) { 647 *result = out_obj.integer.value; 648 return 0; 649 } 650 651 printk(KERN_WARNING DRV_PFX "acpi_callreadfunc failed\n"); 652 653 return -1; 654} 655 656static int acpi_callsetfunc(acpi_handle handle, char *name, int value, 657 int *result) 658{ 659 struct acpi_object_list params; 660 union acpi_object in_obj; 661 struct acpi_buffer output; 662 union acpi_object out_obj; 663 acpi_status status; 664 665 params.count = 1; 666 params.pointer = &in_obj; 667 in_obj.type = ACPI_TYPE_INTEGER; 668 in_obj.integer.value = value; 669 670 output.length = sizeof(out_obj); 671 output.pointer = &out_obj; 672 673 status = acpi_evaluate_object(handle, name, &params, &output); 674 if (status == AE_OK) { 675 if (result != NULL) { 676 if (out_obj.type != ACPI_TYPE_INTEGER) { 677 printk(KERN_WARNING DRV_PFX "acpi_evaluate_object bad " 678 "return type\n"); 679 return -1; 680 } 681 *result = out_obj.integer.value; 682 } 683 return 0; 684 } 685 686 printk(KERN_WARNING DRV_PFX "acpi_evaluate_object failed\n"); 687 688 return -1; 689} 690 691/* 692 * sony_nc_values input/output validate functions 693 */ 694 695/* brightness_default_validate: 696 * 697 * manipulate input output values to keep consistency with the 698 * backlight framework for which brightness values are 0-based. 699 */ 700static int brightness_default_validate(const int direction, const int value) 701{ 702 switch (direction) { 703 case SNC_VALIDATE_OUT: 704 return value - 1; 705 case SNC_VALIDATE_IN: 706 if (value >= 0 && value < SONY_MAX_BRIGHTNESS) 707 return value + 1; 708 } 709 return -EINVAL; 710} 711 712/* boolean_validate: 713 * 714 * on input validate boolean values 0/1, on output just pass the 715 * received value. 716 */ 717static int boolean_validate(const int direction, const int value) 718{ 719 if (direction == SNC_VALIDATE_IN) { 720 if (value != 0 && value != 1) 721 return -EINVAL; 722 } 723 return value; 724} 725 726/* 727 * Sysfs show/store common to all sony_nc_values 728 */ 729static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr, 730 char *buffer) 731{ 732 int value; 733 struct sony_nc_value *item = 734 container_of(attr, struct sony_nc_value, devattr); 735 736 if (!*item->acpiget) 737 return -EIO; 738 739 if (acpi_callgetfunc(sony_nc_acpi_handle, *item->acpiget, &value) < 0) 740 return -EIO; 741 742 if (item->validate) 743 value = item->validate(SNC_VALIDATE_OUT, value); 744 745 return snprintf(buffer, PAGE_SIZE, "%d\n", value); 746} 747 748static ssize_t sony_nc_sysfs_store(struct device *dev, 749 struct device_attribute *attr, 750 const char *buffer, size_t count) 751{ 752 int value; 753 struct sony_nc_value *item = 754 container_of(attr, struct sony_nc_value, devattr); 755 756 if (!item->acpiset) 757 return -EIO; 758 759 if (count > 31) 760 return -EINVAL; 761 762 value = simple_strtoul(buffer, NULL, 10); 763 764 if (item->validate) 765 value = item->validate(SNC_VALIDATE_IN, value); 766 767 if (value < 0) 768 return value; 769 770 if (acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, value, NULL) < 0) 771 return -EIO; 772 item->value = value; 773 item->valid = 1; 774 return count; 775} 776 777 778/* 779 * Backlight device 780 */ 781static int sony_backlight_update_status(struct backlight_device *bd) 782{ 783 return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", 784 bd->props.brightness + 1, NULL); 785} 786 787static int sony_backlight_get_brightness(struct backlight_device *bd) 788{ 789 int value; 790 791 if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) 792 return 0; 793 /* brightness levels are 1-based, while backlight ones are 0-based */ 794 return value - 1; 795} 796 797static struct backlight_device *sony_backlight_device; 798static struct backlight_ops sony_backlight_ops = { 799 .update_status = sony_backlight_update_status, 800 .get_brightness = sony_backlight_get_brightness, 801}; 802 803/* 804 * New SNC-only Vaios event mapping to driver known keys 805 */ 806struct sony_nc_event { 807 u8 data; 808 u8 event; 809}; 810 811static struct sony_nc_event *sony_nc_events; 812 813/* Vaio C* --maybe also FE*, N* and AR* ?-- special init sequence 814 * for Fn keys 815 */ 816static int sony_nc_C_enable(const struct dmi_system_id *id) 817{ 818 int result = 0; 819 820 printk(KERN_NOTICE DRV_PFX "detected %s\n", id->ident); 821 822 sony_nc_events = id->driver_data; 823 824 if (acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x4, &result) < 0 825 || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x2, &result) < 0 826 || acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x10, &result) < 0 827 || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x0, &result) < 0 828 || acpi_callsetfunc(sony_nc_acpi_handle, "SN03", 0x2, &result) < 0 829 || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x101, &result) < 0) { 830 printk(KERN_WARNING DRV_PFX "failed to initialize SNC, some " 831 "functionalities may be missing\n"); 832 return 1; 833 } 834 return 0; 835} 836 837static struct sony_nc_event sony_C_events[] = { 838 { 0x81, SONYPI_EVENT_FNKEY_F1 }, 839 { 0x01, SONYPI_EVENT_FNKEY_RELEASED }, 840 { 0x85, SONYPI_EVENT_FNKEY_F5 }, 841 { 0x05, SONYPI_EVENT_FNKEY_RELEASED }, 842 { 0x86, SONYPI_EVENT_FNKEY_F6 }, 843 { 0x06, SONYPI_EVENT_FNKEY_RELEASED }, 844 { 0x87, SONYPI_EVENT_FNKEY_F7 }, 845 { 0x07, SONYPI_EVENT_FNKEY_RELEASED }, 846 { 0x8A, SONYPI_EVENT_FNKEY_F10 }, 847 { 0x0A, SONYPI_EVENT_FNKEY_RELEASED }, 848 { 0x8C, SONYPI_EVENT_FNKEY_F12 }, 849 { 0x0C, SONYPI_EVENT_FNKEY_RELEASED }, 850 { 0, 0 }, 851}; 852 853/* SNC-only model map */ 854static const struct dmi_system_id sony_nc_ids[] = { 855 { 856 .ident = "Sony Vaio FE Series", 857 .callback = sony_nc_C_enable, 858 .driver_data = sony_C_events, 859 .matches = { 860 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 861 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FE"), 862 }, 863 }, 864 { 865 .ident = "Sony Vaio FZ Series", 866 .callback = sony_nc_C_enable, 867 .driver_data = sony_C_events, 868 .matches = { 869 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 870 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ"), 871 }, 872 }, 873 { 874 .ident = "Sony Vaio C Series", 875 .callback = sony_nc_C_enable, 876 .driver_data = sony_C_events, 877 .matches = { 878 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 879 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"), 880 }, 881 }, 882 { 883 .ident = "Sony Vaio N Series", 884 .callback = sony_nc_C_enable, 885 .driver_data = sony_C_events, 886 .matches = { 887 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 888 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-N"), 889 }, 890 }, 891 { } 892}; 893 894/* 895 * ACPI callbacks 896 */ 897static void sony_acpi_notify(acpi_handle handle, u32 event, void *data) 898{ 899 struct sony_nc_event *evmap; 900 u32 ev = event; 901 int result; 902 903 if (ev == 0x92) { 904 /* read the key pressed from EC.GECR 905 * A call to SN07 with 0x0202 will do it as well respecting 906 * the current protocol on different OSes 907 * 908 * Note: the path for GECR may be 909 * \_SB.PCI0.LPCB.EC (C, FE, AR, N and friends) 910 * \_SB.PCI0.PIB.EC0 (VGN-FR notifications are sent directly, no GECR) 911 * 912 * TODO: we may want to do the same for the older GHKE -need 913 * dmi list- so this snippet may become one more callback. 914 */ 915 if (acpi_callsetfunc(handle, "SN07", 0x0202, &result) < 0) 916 dprintk("sony_acpi_notify, unable to decode event 0x%.2x\n", ev); 917 else 918 ev = result & 0xFF; 919 } 920 921 if (sony_nc_events) 922 for (evmap = sony_nc_events; evmap->event; evmap++) { 923 if (evmap->data == ev) { 924 ev = evmap->event; 925 break; 926 } 927 } 928 929 dprintk("sony_acpi_notify, event: 0x%.2x\n", ev); 930 sony_laptop_report_input_event(ev); 931 acpi_bus_generate_proc_event(sony_nc_acpi_device, 1, ev); 932} 933 934static acpi_status sony_walk_callback(acpi_handle handle, u32 level, 935 void *context, void **return_value) 936{ 937 struct acpi_namespace_node *node; 938 union acpi_operand_object *operand; 939 940 node = (struct acpi_namespace_node *)handle; 941 operand = (union acpi_operand_object *)node->object; 942 943 printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", node->name.ascii, 944 (u32) operand->method.param_count); 945 946 return AE_OK; 947} 948 949/* 950 * ACPI device 951 */ 952static int sony_nc_resume(struct acpi_device *device) 953{ 954 struct sony_nc_value *item; 955 956 for (item = sony_nc_values; item->name; item++) { 957 int ret; 958 959 if (!item->valid) 960 continue; 961 ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, 962 item->value, NULL); 963 if (ret < 0) { 964 printk("%s: %d\n", __func__, ret); 965 break; 966 } 967 } 968 969 /* set the last requested brightness level */ 970 if (sony_backlight_device && 971 !sony_backlight_update_status(sony_backlight_device)) 972 printk(KERN_WARNING DRV_PFX "unable to restore brightness level"); 973 974 /* re-initialize models with specific requirements */ 975 dmi_check_system(sony_nc_ids); 976 977 return 0; 978} 979 980static int sony_nc_add(struct acpi_device *device) 981{ 982 acpi_status status; 983 int result = 0; 984 acpi_handle handle; 985 struct sony_nc_value *item; 986 987 printk(KERN_INFO DRV_PFX "%s v%s.\n", 988 SONY_NC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION); 989 990 sony_nc_acpi_device = device; 991 strcpy(acpi_device_class(device), "sony/hotkey"); 992 993 sony_nc_acpi_handle = device->handle; 994 995 /* read device status */ 996 result = acpi_bus_get_status(device); 997 /* bail IFF the above call was successful and the device is not present */ 998 if (!result && !device->status.present) { 999 dprintk("Device not present\n"); 1000 result = -ENODEV; 1001 goto outwalk; 1002 } 1003 1004 if (debug) { 1005 status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle, 1006 1, sony_walk_callback, NULL, NULL); 1007 if (ACPI_FAILURE(status)) { 1008 printk(KERN_WARNING DRV_PFX "unable to walk acpi resources\n"); 1009 result = -ENODEV; 1010 goto outwalk; 1011 } 1012 } 1013 1014 /* try to _INI the device if such method exists (ACPI spec 3.0-6.5.1 1015 * should be respected as we already checked for the device presence above */ 1016 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, METHOD_NAME__INI, &handle))) { 1017 dprintk("Invoking _INI\n"); 1018 if (ACPI_FAILURE(acpi_evaluate_object(sony_nc_acpi_handle, METHOD_NAME__INI, 1019 NULL, NULL))) 1020 dprintk("_INI Method failed\n"); 1021 } 1022 1023 /* setup input devices and helper fifo */ 1024 result = sony_laptop_setup_input(device); 1025 if (result) { 1026 printk(KERN_ERR DRV_PFX 1027 "Unabe to create input devices.\n"); 1028 goto outwalk; 1029 } 1030 1031 status = acpi_install_notify_handler(sony_nc_acpi_handle, 1032 ACPI_DEVICE_NOTIFY, 1033 sony_acpi_notify, NULL); 1034 if (ACPI_FAILURE(status)) { 1035 printk(KERN_WARNING DRV_PFX "unable to install notify handler (%u)\n", status); 1036 result = -ENODEV; 1037 goto outinput; 1038 } 1039 1040 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", &handle))) { 1041 sony_backlight_device = backlight_device_register("sony", NULL, 1042 NULL, 1043 &sony_backlight_ops); 1044 1045 if (IS_ERR(sony_backlight_device)) { 1046 printk(KERN_WARNING DRV_PFX "unable to register backlight device\n"); 1047 sony_backlight_device = NULL; 1048 } else { 1049 sony_backlight_device->props.brightness = 1050 sony_backlight_get_brightness 1051 (sony_backlight_device); 1052 sony_backlight_device->props.max_brightness = 1053 SONY_MAX_BRIGHTNESS - 1; 1054 } 1055 1056 } 1057 1058 /* initialize models with specific requirements */ 1059 dmi_check_system(sony_nc_ids); 1060 1061 result = sony_pf_add(); 1062 if (result) 1063 goto outbacklight; 1064 1065 /* create sony_pf sysfs attributes related to the SNC device */ 1066 for (item = sony_nc_values; item->name; ++item) { 1067 1068 if (!debug && item->debug) 1069 continue; 1070 1071 /* find the available acpiget as described in the DSDT */ 1072 for (; item->acpiget && *item->acpiget; ++item->acpiget) { 1073 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, 1074 *item->acpiget, 1075 &handle))) { 1076 dprintk("Found %s getter: %s\n", 1077 item->name, *item->acpiget); 1078 item->devattr.attr.mode |= S_IRUGO; 1079 break; 1080 } 1081 } 1082 1083 /* find the available acpiset as described in the DSDT */ 1084 for (; item->acpiset && *item->acpiset; ++item->acpiset) { 1085 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, 1086 *item->acpiset, 1087 &handle))) { 1088 dprintk("Found %s setter: %s\n", 1089 item->name, *item->acpiset); 1090 item->devattr.attr.mode |= S_IWUSR; 1091 break; 1092 } 1093 } 1094 1095 if (item->devattr.attr.mode != 0) { 1096 result = 1097 device_create_file(&sony_pf_device->dev, 1098 &item->devattr); 1099 if (result) 1100 goto out_sysfs; 1101 } 1102 } 1103 1104 return 0; 1105 1106 out_sysfs: 1107 for (item = sony_nc_values; item->name; ++item) { 1108 device_remove_file(&sony_pf_device->dev, &item->devattr); 1109 } 1110 sony_pf_remove(); 1111 1112 outbacklight: 1113 if (sony_backlight_device) 1114 backlight_device_unregister(sony_backlight_device); 1115 1116 status = acpi_remove_notify_handler(sony_nc_acpi_handle, 1117 ACPI_DEVICE_NOTIFY, 1118 sony_acpi_notify); 1119 if (ACPI_FAILURE(status)) 1120 printk(KERN_WARNING DRV_PFX "unable to remove notify handler\n"); 1121 1122 outinput: 1123 sony_laptop_remove_input(); 1124 1125 outwalk: 1126 return result; 1127} 1128 1129static int sony_nc_remove(struct acpi_device *device, int type) 1130{ 1131 acpi_status status; 1132 struct sony_nc_value *item; 1133 1134 if (sony_backlight_device) 1135 backlight_device_unregister(sony_backlight_device); 1136 1137 sony_nc_acpi_device = NULL; 1138 1139 status = acpi_remove_notify_handler(sony_nc_acpi_handle, 1140 ACPI_DEVICE_NOTIFY, 1141 sony_acpi_notify); 1142 if (ACPI_FAILURE(status)) 1143 printk(KERN_WARNING DRV_PFX "unable to remove notify handler\n"); 1144 1145 for (item = sony_nc_values; item->name; ++item) { 1146 device_remove_file(&sony_pf_device->dev, &item->devattr); 1147 } 1148 1149 sony_pf_remove(); 1150 sony_laptop_remove_input(); 1151 dprintk(SONY_NC_DRIVER_NAME " removed.\n"); 1152 1153 return 0; 1154} 1155 1156static const struct acpi_device_id sony_device_ids[] = { 1157 {SONY_NC_HID, 0}, 1158 {SONY_PIC_HID, 0}, 1159 {"", 0}, 1160}; 1161MODULE_DEVICE_TABLE(acpi, sony_device_ids); 1162 1163static const struct acpi_device_id sony_nc_device_ids[] = { 1164 {SONY_NC_HID, 0}, 1165 {"", 0}, 1166}; 1167 1168static struct acpi_driver sony_nc_driver = { 1169 .name = SONY_NC_DRIVER_NAME, 1170 .class = SONY_NC_CLASS, 1171 .ids = sony_nc_device_ids, 1172 .owner = THIS_MODULE, 1173 .ops = { 1174 .add = sony_nc_add, 1175 .remove = sony_nc_remove, 1176 .resume = sony_nc_resume, 1177 }, 1178}; 1179 1180/*********** SPIC (SNY6001) Device ***********/ 1181 1182#define SONYPI_DEVICE_TYPE1 0x00000001 1183#define SONYPI_DEVICE_TYPE2 0x00000002 1184#define SONYPI_DEVICE_TYPE3 0x00000004 1185#define SONYPI_DEVICE_TYPE4 0x00000008 1186 1187#define SONYPI_TYPE1_OFFSET 0x04 1188#define SONYPI_TYPE2_OFFSET 0x12 1189#define SONYPI_TYPE3_OFFSET 0x12 1190#define SONYPI_TYPE4_OFFSET 0x12 1191 1192struct sony_pic_ioport { 1193 struct acpi_resource_io io1; 1194 struct acpi_resource_io io2; 1195 struct list_head list; 1196}; 1197 1198struct sony_pic_irq { 1199 struct acpi_resource_irq irq; 1200 struct list_head list; 1201}; 1202 1203struct sonypi_eventtypes { 1204 u8 data; 1205 unsigned long mask; 1206 struct sonypi_event *events; 1207}; 1208 1209struct device_ctrl { 1210 int model; 1211 int (*handle_irq)(const u8, const u8); 1212 u16 evport_offset; 1213 u8 has_camera; 1214 u8 has_bluetooth; 1215 u8 has_wwan; 1216 struct sonypi_eventtypes *event_types; 1217}; 1218 1219struct sony_pic_dev { 1220 struct device_ctrl *control; 1221 struct acpi_device *acpi_dev; 1222 struct sony_pic_irq *cur_irq; 1223 struct sony_pic_ioport *cur_ioport; 1224 struct list_head interrupts; 1225 struct list_head ioports; 1226 struct mutex lock; 1227 u8 camera_power; 1228 u8 bluetooth_power; 1229 u8 wwan_power; 1230}; 1231 1232static struct sony_pic_dev spic_dev = { 1233 .interrupts = LIST_HEAD_INIT(spic_dev.interrupts), 1234 .ioports = LIST_HEAD_INIT(spic_dev.ioports), 1235}; 1236 1237/* Event masks */ 1238#define SONYPI_JOGGER_MASK 0x00000001 1239#define SONYPI_CAPTURE_MASK 0x00000002 1240#define SONYPI_FNKEY_MASK 0x00000004 1241#define SONYPI_BLUETOOTH_MASK 0x00000008 1242#define SONYPI_PKEY_MASK 0x00000010 1243#define SONYPI_BACK_MASK 0x00000020 1244#define SONYPI_HELP_MASK 0x00000040 1245#define SONYPI_LID_MASK 0x00000080 1246#define SONYPI_ZOOM_MASK 0x00000100 1247#define SONYPI_THUMBPHRASE_MASK 0x00000200 1248#define SONYPI_MEYE_MASK 0x00000400 1249#define SONYPI_MEMORYSTICK_MASK 0x00000800 1250#define SONYPI_BATTERY_MASK 0x00001000 1251#define SONYPI_WIRELESS_MASK 0x00002000 1252 1253struct sonypi_event { 1254 u8 data; 1255 u8 event; 1256}; 1257 1258/* The set of possible button release events */ 1259static struct sonypi_event sonypi_releaseev[] = { 1260 { 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED }, 1261 { 0, 0 } 1262}; 1263 1264/* The set of possible jogger events */ 1265static struct sonypi_event sonypi_joggerev[] = { 1266 { 0x1f, SONYPI_EVENT_JOGDIAL_UP }, 1267 { 0x01, SONYPI_EVENT_JOGDIAL_DOWN }, 1268 { 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED }, 1269 { 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED }, 1270 { 0x1e, SONYPI_EVENT_JOGDIAL_FAST_UP }, 1271 { 0x02, SONYPI_EVENT_JOGDIAL_FAST_DOWN }, 1272 { 0x5e, SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED }, 1273 { 0x42, SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED }, 1274 { 0x1d, SONYPI_EVENT_JOGDIAL_VFAST_UP }, 1275 { 0x03, SONYPI_EVENT_JOGDIAL_VFAST_DOWN }, 1276 { 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED }, 1277 { 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED }, 1278 { 0x40, SONYPI_EVENT_JOGDIAL_PRESSED }, 1279 { 0, 0 } 1280}; 1281 1282/* The set of possible capture button events */ 1283static struct sonypi_event sonypi_captureev[] = { 1284 { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED }, 1285 { 0x07, SONYPI_EVENT_CAPTURE_PRESSED }, 1286 { 0x40, SONYPI_EVENT_CAPTURE_PRESSED }, 1287 { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED }, 1288 { 0, 0 } 1289}; 1290 1291/* The set of possible fnkeys events */ 1292static struct sonypi_event sonypi_fnkeyev[] = { 1293 { 0x10, SONYPI_EVENT_FNKEY_ESC }, 1294 { 0x11, SONYPI_EVENT_FNKEY_F1 }, 1295 { 0x12, SONYPI_EVENT_FNKEY_F2 }, 1296 { 0x13, SONYPI_EVENT_FNKEY_F3 }, 1297 { 0x14, SONYPI_EVENT_FNKEY_F4 }, 1298 { 0x15, SONYPI_EVENT_FNKEY_F5 }, 1299 { 0x16, SONYPI_EVENT_FNKEY_F6 }, 1300 { 0x17, SONYPI_EVENT_FNKEY_F7 }, 1301 { 0x18, SONYPI_EVENT_FNKEY_F8 }, 1302 { 0x19, SONYPI_EVENT_FNKEY_F9 }, 1303 { 0x1a, SONYPI_EVENT_FNKEY_F10 }, 1304 { 0x1b, SONYPI_EVENT_FNKEY_F11 }, 1305 { 0x1c, SONYPI_EVENT_FNKEY_F12 }, 1306 { 0x1f, SONYPI_EVENT_FNKEY_RELEASED }, 1307 { 0x21, SONYPI_EVENT_FNKEY_1 }, 1308 { 0x22, SONYPI_EVENT_FNKEY_2 }, 1309 { 0x31, SONYPI_EVENT_FNKEY_D }, 1310 { 0x32, SONYPI_EVENT_FNKEY_E }, 1311 { 0x33, SONYPI_EVENT_FNKEY_F }, 1312 { 0x34, SONYPI_EVENT_FNKEY_S }, 1313 { 0x35, SONYPI_EVENT_FNKEY_B }, 1314 { 0x36, SONYPI_EVENT_FNKEY_ONLY }, 1315 { 0, 0 } 1316}; 1317 1318/* The set of possible program key events */ 1319static struct sonypi_event sonypi_pkeyev[] = { 1320 { 0x01, SONYPI_EVENT_PKEY_P1 }, 1321 { 0x02, SONYPI_EVENT_PKEY_P2 }, 1322 { 0x04, SONYPI_EVENT_PKEY_P3 }, 1323 { 0, 0 } 1324}; 1325 1326/* The set of possible bluetooth events */ 1327static struct sonypi_event sonypi_blueev[] = { 1328 { 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED }, 1329 { 0x59, SONYPI_EVENT_BLUETOOTH_ON }, 1330 { 0x5a, SONYPI_EVENT_BLUETOOTH_OFF }, 1331 { 0, 0 } 1332}; 1333 1334/* The set of possible wireless events */ 1335static struct sonypi_event sonypi_wlessev[] = { 1336 { 0x59, SONYPI_EVENT_WIRELESS_ON }, 1337 { 0x5a, SONYPI_EVENT_WIRELESS_OFF }, 1338 { 0, 0 } 1339}; 1340 1341/* The set of possible back button events */ 1342static struct sonypi_event sonypi_backev[] = { 1343 { 0x20, SONYPI_EVENT_BACK_PRESSED }, 1344 { 0, 0 } 1345}; 1346 1347/* The set of possible help button events */ 1348static struct sonypi_event sonypi_helpev[] = { 1349 { 0x3b, SONYPI_EVENT_HELP_PRESSED }, 1350 { 0, 0 } 1351}; 1352 1353 1354/* The set of possible lid events */ 1355static struct sonypi_event sonypi_lidev[] = { 1356 { 0x51, SONYPI_EVENT_LID_CLOSED }, 1357 { 0x50, SONYPI_EVENT_LID_OPENED }, 1358 { 0, 0 } 1359}; 1360 1361/* The set of possible zoom events */ 1362static struct sonypi_event sonypi_zoomev[] = { 1363 { 0x39, SONYPI_EVENT_ZOOM_PRESSED }, 1364 { 0x10, SONYPI_EVENT_ZOOM_IN_PRESSED }, 1365 { 0x20, SONYPI_EVENT_ZOOM_OUT_PRESSED }, 1366 { 0, 0 } 1367}; 1368 1369/* The set of possible thumbphrase events */ 1370static struct sonypi_event sonypi_thumbphraseev[] = { 1371 { 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED }, 1372 { 0, 0 } 1373}; 1374 1375/* The set of possible motioneye camera events */ 1376static struct sonypi_event sonypi_meyeev[] = { 1377 { 0x00, SONYPI_EVENT_MEYE_FACE }, 1378 { 0x01, SONYPI_EVENT_MEYE_OPPOSITE }, 1379 { 0, 0 } 1380}; 1381 1382/* The set of possible memorystick events */ 1383static struct sonypi_event sonypi_memorystickev[] = { 1384 { 0x53, SONYPI_EVENT_MEMORYSTICK_INSERT }, 1385 { 0x54, SONYPI_EVENT_MEMORYSTICK_EJECT }, 1386 { 0, 0 } 1387}; 1388 1389/* The set of possible battery events */ 1390static struct sonypi_event sonypi_batteryev[] = { 1391 { 0x20, SONYPI_EVENT_BATTERY_INSERT }, 1392 { 0x30, SONYPI_EVENT_BATTERY_REMOVE }, 1393 { 0, 0 } 1394}; 1395 1396static struct sonypi_eventtypes type1_events[] = { 1397 { 0, 0xffffffff, sonypi_releaseev }, 1398 { 0x70, SONYPI_MEYE_MASK, sonypi_meyeev }, 1399 { 0x30, SONYPI_LID_MASK, sonypi_lidev }, 1400 { 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev }, 1401 { 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev }, 1402 { 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, 1403 { 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, 1404 { 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev }, 1405 { 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, 1406 { 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev }, 1407 { 0 }, 1408}; 1409static struct sonypi_eventtypes type2_events[] = { 1410 { 0, 0xffffffff, sonypi_releaseev }, 1411 { 0x38, SONYPI_LID_MASK, sonypi_lidev }, 1412 { 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev }, 1413 { 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev }, 1414 { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, 1415 { 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, 1416 { 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev }, 1417 { 0x11, SONYPI_BACK_MASK, sonypi_backev }, 1418 { 0x21, SONYPI_HELP_MASK, sonypi_helpev }, 1419 { 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev }, 1420 { 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev }, 1421 { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, 1422 { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, 1423 { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, 1424 { 0 }, 1425}; 1426static struct sonypi_eventtypes type3_events[] = { 1427 { 0, 0xffffffff, sonypi_releaseev }, 1428 { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, 1429 { 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev }, 1430 { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, 1431 { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, 1432 { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, 1433 { 0 }, 1434}; 1435static struct sonypi_eventtypes type4_events[] = { 1436 { 0, 0xffffffff, sonypi_releaseev }, 1437 { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, 1438 { 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev }, 1439 { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, 1440 { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, 1441 { 0x05, SONYPI_PKEY_MASK, sonypi_pkeyev }, 1442 { 0x05, SONYPI_ZOOM_MASK, sonypi_zoomev }, 1443 { 0x05, SONYPI_CAPTURE_MASK, sonypi_captureev }, 1444 { 0 }, 1445}; 1446 1447/* low level spic calls */ 1448#define ITERATIONS_LONG 10000 1449#define ITERATIONS_SHORT 10 1450#define wait_on_command(command, iterations) { \ 1451 unsigned int n = iterations; \ 1452 while (--n && (command)) \ 1453 udelay(1); \ 1454 if (!n) \ 1455 dprintk("command failed at %s : %s (line %d)\n", \ 1456 __FILE__, __func__, __LINE__); \ 1457} 1458 1459static u8 sony_pic_call1(u8 dev) 1460{ 1461 u8 v1, v2; 1462 1463 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, 1464 ITERATIONS_LONG); 1465 outb(dev, spic_dev.cur_ioport->io1.minimum + 4); 1466 v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4); 1467 v2 = inb_p(spic_dev.cur_ioport->io1.minimum); 1468 dprintk("sony_pic_call1(0x%.2x): 0x%.4x\n", dev, (v2 << 8) | v1); 1469 return v2; 1470} 1471 1472static u8 sony_pic_call2(u8 dev, u8 fn) 1473{ 1474 u8 v1; 1475 1476 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, 1477 ITERATIONS_LONG); 1478 outb(dev, spic_dev.cur_ioport->io1.minimum + 4); 1479 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, 1480 ITERATIONS_LONG); 1481 outb(fn, spic_dev.cur_ioport->io1.minimum); 1482 v1 = inb_p(spic_dev.cur_ioport->io1.minimum); 1483 dprintk("sony_pic_call2(0x%.2x - 0x%.2x): 0x%.4x\n", dev, fn, v1); 1484 return v1; 1485} 1486 1487static u8 sony_pic_call3(u8 dev, u8 fn, u8 v) 1488{ 1489 u8 v1; 1490 1491 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); 1492 outb(dev, spic_dev.cur_ioport->io1.minimum + 4); 1493 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); 1494 outb(fn, spic_dev.cur_ioport->io1.minimum); 1495 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); 1496 outb(v, spic_dev.cur_ioport->io1.minimum); 1497 v1 = inb_p(spic_dev.cur_ioport->io1.minimum); 1498 dprintk("sony_pic_call3(0x%.2x - 0x%.2x - 0x%.2x): 0x%.4x\n", 1499 dev, fn, v, v1); 1500 return v1; 1501} 1502 1503/* 1504 * minidrivers for SPIC models 1505 */ 1506static int type4_handle_irq(const u8 data_mask, const u8 ev) 1507{ 1508 /* 1509 * 0x31 could mean we have to take some extra action and wait for 1510 * the next irq for some Type4 models, it will generate a new 1511 * irq and we can read new data from the device: 1512 * - 0x5c and 0x5f requires 0xA0 1513 * - 0x61 requires 0xB3 1514 */ 1515 if (data_mask == 0x31) { 1516 if (ev == 0x5c || ev == 0x5f) 1517 sony_pic_call1(0xA0); 1518 else if (ev == 0x61) 1519 sony_pic_call1(0xB3); 1520 return 0; 1521 } 1522 return 1; 1523} 1524 1525static struct device_ctrl spic_types[] = { 1526 { 1527 .model = SONYPI_DEVICE_TYPE1, 1528 .handle_irq = NULL, 1529 .evport_offset = SONYPI_TYPE1_OFFSET, 1530 .event_types = type1_events, 1531 }, 1532 { 1533 .model = SONYPI_DEVICE_TYPE2, 1534 .handle_irq = NULL, 1535 .evport_offset = SONYPI_TYPE2_OFFSET, 1536 .event_types = type2_events, 1537 }, 1538 { 1539 .model = SONYPI_DEVICE_TYPE3, 1540 .handle_irq = NULL, 1541 .evport_offset = SONYPI_TYPE3_OFFSET, 1542 .event_types = type3_events, 1543 }, 1544 { 1545 .model = SONYPI_DEVICE_TYPE4, 1546 .handle_irq = type4_handle_irq, 1547 .evport_offset = SONYPI_TYPE4_OFFSET, 1548 .event_types = type4_events, 1549 }, 1550}; 1551 1552static void sony_pic_detect_device_type(struct sony_pic_dev *dev) 1553{ 1554 struct pci_dev *pcidev; 1555 1556 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, 1557 PCI_DEVICE_ID_INTEL_82371AB_3, NULL); 1558 if (pcidev) { 1559 dev->control = &spic_types[0]; 1560 goto out; 1561 } 1562 1563 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, 1564 PCI_DEVICE_ID_INTEL_ICH6_1, NULL); 1565 if (pcidev) { 1566 dev->control = &spic_types[2]; 1567 goto out; 1568 } 1569 1570 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, 1571 PCI_DEVICE_ID_INTEL_ICH7_1, NULL); 1572 if (pcidev) { 1573 dev->control = &spic_types[3]; 1574 goto out; 1575 } 1576 1577 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, 1578 PCI_DEVICE_ID_INTEL_ICH8_4, NULL); 1579 if (pcidev) { 1580 dev->control = &spic_types[3]; 1581 goto out; 1582 } 1583 1584 /* default */ 1585 dev->control = &spic_types[1]; 1586 1587out: 1588 if (pcidev) 1589 pci_dev_put(pcidev); 1590 1591 printk(KERN_INFO DRV_PFX "detected Type%d model\n", 1592 dev->control->model == SONYPI_DEVICE_TYPE1 ? 1 : 1593 dev->control->model == SONYPI_DEVICE_TYPE2 ? 2 : 1594 dev->control->model == SONYPI_DEVICE_TYPE3 ? 3 : 4); 1595} 1596 1597/* camera tests and poweron/poweroff */ 1598#define SONYPI_CAMERA_PICTURE 5 1599#define SONYPI_CAMERA_CONTROL 0x10 1600 1601#define SONYPI_CAMERA_BRIGHTNESS 0 1602#define SONYPI_CAMERA_CONTRAST 1 1603#define SONYPI_CAMERA_HUE 2 1604#define SONYPI_CAMERA_COLOR 3 1605#define SONYPI_CAMERA_SHARPNESS 4 1606 1607#define SONYPI_CAMERA_EXPOSURE_MASK 0xC 1608#define SONYPI_CAMERA_WHITE_BALANCE_MASK 0x3 1609#define SONYPI_CAMERA_PICTURE_MODE_MASK 0x30 1610#define SONYPI_CAMERA_MUTE_MASK 0x40 1611 1612/* the rest don't need a loop until not 0xff */ 1613#define SONYPI_CAMERA_AGC 6 1614#define SONYPI_CAMERA_AGC_MASK 0x30 1615#define SONYPI_CAMERA_SHUTTER_MASK 0x7 1616 1617#define SONYPI_CAMERA_SHUTDOWN_REQUEST 7 1618#define SONYPI_CAMERA_CONTROL 0x10 1619 1620#define SONYPI_CAMERA_STATUS 7 1621#define SONYPI_CAMERA_STATUS_READY 0x2 1622#define SONYPI_CAMERA_STATUS_POSITION 0x4 1623 1624#define SONYPI_DIRECTION_BACKWARDS 0x4 1625 1626#define SONYPI_CAMERA_REVISION 8 1627#define SONYPI_CAMERA_ROMVERSION 9 1628 1629static int __sony_pic_camera_ready(void) 1630{ 1631 u8 v; 1632 1633 v = sony_pic_call2(0x8f, SONYPI_CAMERA_STATUS); 1634 return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY)); 1635} 1636 1637static int __sony_pic_camera_off(void) 1638{ 1639 if (!camera) { 1640 printk(KERN_WARNING DRV_PFX "camera control not enabled\n"); 1641 return -ENODEV; 1642 } 1643 1644 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, 1645 SONYPI_CAMERA_MUTE_MASK), 1646 ITERATIONS_SHORT); 1647 1648 if (spic_dev.camera_power) { 1649 sony_pic_call2(0x91, 0); 1650 spic_dev.camera_power = 0; 1651 } 1652 return 0; 1653} 1654 1655static int __sony_pic_camera_on(void) 1656{ 1657 int i, j, x; 1658 1659 if (!camera) { 1660 printk(KERN_WARNING DRV_PFX "camera control not enabled\n"); 1661 return -ENODEV; 1662 } 1663 1664 if (spic_dev.camera_power) 1665 return 0; 1666 1667 for (j = 5; j > 0; j--) { 1668 1669 for (x = 0; x < 100 && sony_pic_call2(0x91, 0x1); x++) 1670 msleep(10); 1671 sony_pic_call1(0x93); 1672 1673 for (i = 400; i > 0; i--) { 1674 if (__sony_pic_camera_ready()) 1675 break; 1676 msleep(10); 1677 } 1678 if (i) 1679 break; 1680 } 1681 1682 if (j == 0) { 1683 printk(KERN_WARNING DRV_PFX "failed to power on camera\n"); 1684 return -ENODEV; 1685 } 1686 1687 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTROL, 1688 0x5a), 1689 ITERATIONS_SHORT); 1690 1691 spic_dev.camera_power = 1; 1692 return 0; 1693} 1694 1695/* External camera command (exported to the motion eye v4l driver) */ 1696int sony_pic_camera_command(int command, u8 value) 1697{ 1698 if (!camera) 1699 return -EIO; 1700 1701 mutex_lock(&spic_dev.lock); 1702 1703 switch (command) { 1704 case SONY_PIC_COMMAND_SETCAMERA: 1705 if (value) 1706 __sony_pic_camera_on(); 1707 else 1708 __sony_pic_camera_off(); 1709 break; 1710 case SONY_PIC_COMMAND_SETCAMERABRIGHTNESS: 1711 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_BRIGHTNESS, value), 1712 ITERATIONS_SHORT); 1713 break; 1714 case SONY_PIC_COMMAND_SETCAMERACONTRAST: 1715 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTRAST, value), 1716 ITERATIONS_SHORT); 1717 break; 1718 case SONY_PIC_COMMAND_SETCAMERAHUE: 1719 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_HUE, value), 1720 ITERATIONS_SHORT); 1721 break; 1722 case SONY_PIC_COMMAND_SETCAMERACOLOR: 1723 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_COLOR, value), 1724 ITERATIONS_SHORT); 1725 break; 1726 case SONY_PIC_COMMAND_SETCAMERASHARPNESS: 1727 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_SHARPNESS, value), 1728 ITERATIONS_SHORT); 1729 break; 1730 case SONY_PIC_COMMAND_SETCAMERAPICTURE: 1731 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, value), 1732 ITERATIONS_SHORT); 1733 break; 1734 case SONY_PIC_COMMAND_SETCAMERAAGC: 1735 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_AGC, value), 1736 ITERATIONS_SHORT); 1737 break; 1738 default: 1739 printk(KERN_ERR DRV_PFX "sony_pic_camera_command invalid: %d\n", 1740 command); 1741 break; 1742 } 1743 mutex_unlock(&spic_dev.lock); 1744 return 0; 1745} 1746EXPORT_SYMBOL(sony_pic_camera_command); 1747 1748/* gprs/edge modem (SZ460N and SZ210P), thanks to Joshua Wise */ 1749static void sony_pic_set_wwanpower(u8 state) 1750{ 1751 state = !!state; 1752 mutex_lock(&spic_dev.lock); 1753 if (spic_dev.wwan_power == state) { 1754 mutex_unlock(&spic_dev.lock); 1755 return; 1756 } 1757 sony_pic_call2(0xB0, state); 1758 spic_dev.wwan_power = state; 1759 mutex_unlock(&spic_dev.lock); 1760} 1761 1762static ssize_t sony_pic_wwanpower_store(struct device *dev, 1763 struct device_attribute *attr, 1764 const char *buffer, size_t count) 1765{ 1766 unsigned long value; 1767 if (count > 31) 1768 return -EINVAL; 1769 1770 value = simple_strtoul(buffer, NULL, 10); 1771 sony_pic_set_wwanpower(value); 1772 1773 return count; 1774} 1775 1776static ssize_t sony_pic_wwanpower_show(struct device *dev, 1777 struct device_attribute *attr, char *buffer) 1778{ 1779 ssize_t count; 1780 mutex_lock(&spic_dev.lock); 1781 count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.wwan_power); 1782 mutex_unlock(&spic_dev.lock); 1783 return count; 1784} 1785 1786/* bluetooth subsystem power state */ 1787static void __sony_pic_set_bluetoothpower(u8 state) 1788{ 1789 state = !!state; 1790 if (spic_dev.bluetooth_power == state) 1791 return; 1792 sony_pic_call2(0x96, state); 1793 sony_pic_call1(0x82); 1794 spic_dev.bluetooth_power = state; 1795} 1796 1797static ssize_t sony_pic_bluetoothpower_store(struct device *dev, 1798 struct device_attribute *attr, 1799 const char *buffer, size_t count) 1800{ 1801 unsigned long value; 1802 if (count > 31) 1803 return -EINVAL; 1804 1805 value = simple_strtoul(buffer, NULL, 10); 1806 mutex_lock(&spic_dev.lock); 1807 __sony_pic_set_bluetoothpower(value); 1808 mutex_unlock(&spic_dev.lock); 1809 1810 return count; 1811} 1812 1813static ssize_t sony_pic_bluetoothpower_show(struct device *dev, 1814 struct device_attribute *attr, char *buffer) 1815{ 1816 ssize_t count = 0; 1817 mutex_lock(&spic_dev.lock); 1818 count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.bluetooth_power); 1819 mutex_unlock(&spic_dev.lock); 1820 return count; 1821} 1822 1823/* fan speed */ 1824/* FAN0 information (reverse engineered from ACPI tables) */ 1825#define SONY_PIC_FAN0_STATUS 0x93 1826static int sony_pic_set_fanspeed(unsigned long value) 1827{ 1828 return ec_write(SONY_PIC_FAN0_STATUS, value); 1829} 1830 1831static int sony_pic_get_fanspeed(u8 *value) 1832{ 1833 return ec_read(SONY_PIC_FAN0_STATUS, value); 1834} 1835 1836static ssize_t sony_pic_fanspeed_store(struct device *dev, 1837 struct device_attribute *attr, 1838 const char *buffer, size_t count) 1839{ 1840 unsigned long value; 1841 if (count > 31) 1842 return -EINVAL; 1843 1844 value = simple_strtoul(buffer, NULL, 10); 1845 if (sony_pic_set_fanspeed(value)) 1846 return -EIO; 1847 1848 return count; 1849} 1850 1851static ssize_t sony_pic_fanspeed_show(struct device *dev, 1852 struct device_attribute *attr, char *buffer) 1853{ 1854 u8 value = 0; 1855 if (sony_pic_get_fanspeed(&value)) 1856 return -EIO; 1857 1858 return snprintf(buffer, PAGE_SIZE, "%d\n", value); 1859} 1860 1861#define SPIC_ATTR(_name, _mode) \ 1862struct device_attribute spic_attr_##_name = __ATTR(_name, \ 1863 _mode, sony_pic_## _name ##_show, \ 1864 sony_pic_## _name ##_store) 1865 1866static SPIC_ATTR(bluetoothpower, 0644); 1867static SPIC_ATTR(wwanpower, 0644); 1868static SPIC_ATTR(fanspeed, 0644); 1869 1870static struct attribute *spic_attributes[] = { 1871 &spic_attr_bluetoothpower.attr, 1872 &spic_attr_wwanpower.attr, 1873 &spic_attr_fanspeed.attr, 1874 NULL 1875}; 1876 1877static struct attribute_group spic_attribute_group = { 1878 .attrs = spic_attributes 1879}; 1880 1881/******** SONYPI compatibility **********/ 1882#ifdef CONFIG_SONYPI_COMPAT 1883 1884/* battery / brightness / temperature addresses */ 1885#define SONYPI_BAT_FLAGS 0x81 1886#define SONYPI_LCD_LIGHT 0x96 1887#define SONYPI_BAT1_PCTRM 0xa0 1888#define SONYPI_BAT1_LEFT 0xa2 1889#define SONYPI_BAT1_MAXRT 0xa4 1890#define SONYPI_BAT2_PCTRM 0xa8 1891#define SONYPI_BAT2_LEFT 0xaa 1892#define SONYPI_BAT2_MAXRT 0xac 1893#define SONYPI_BAT1_MAXTK 0xb0 1894#define SONYPI_BAT1_FULL 0xb2 1895#define SONYPI_BAT2_MAXTK 0xb8 1896#define SONYPI_BAT2_FULL 0xba 1897#define SONYPI_TEMP_STATUS 0xC1 1898 1899struct sonypi_compat_s { 1900 struct fasync_struct *fifo_async; 1901 struct kfifo *fifo; 1902 spinlock_t fifo_lock; 1903 wait_queue_head_t fifo_proc_list; 1904 atomic_t open_count; 1905}; 1906static struct sonypi_compat_s sonypi_compat = { 1907 .open_count = ATOMIC_INIT(0), 1908}; 1909 1910static int sonypi_misc_fasync(int fd, struct file *filp, int on) 1911{ 1912 int retval; 1913 1914 retval = fasync_helper(fd, filp, on, &sonypi_compat.fifo_async); 1915 if (retval < 0) 1916 return retval; 1917 return 0; 1918} 1919 1920static int sonypi_misc_release(struct inode *inode, struct file *file) 1921{ 1922 sonypi_misc_fasync(-1, file, 0); 1923 atomic_dec(&sonypi_compat.open_count); 1924 return 0; 1925} 1926 1927static int sonypi_misc_open(struct inode *inode, struct file *file) 1928{ 1929 /* Flush input queue on first open */ 1930 if (atomic_inc_return(&sonypi_compat.open_count) == 1) 1931 kfifo_reset(sonypi_compat.fifo); 1932 return 0; 1933} 1934 1935static ssize_t sonypi_misc_read(struct file *file, char __user *buf, 1936 size_t count, loff_t *pos) 1937{ 1938 ssize_t ret; 1939 unsigned char c; 1940 1941 if ((kfifo_len(sonypi_compat.fifo) == 0) && 1942 (file->f_flags & O_NONBLOCK)) 1943 return -EAGAIN; 1944 1945 ret = wait_event_interruptible(sonypi_compat.fifo_proc_list, 1946 kfifo_len(sonypi_compat.fifo) != 0); 1947 if (ret) 1948 return ret; 1949 1950 while (ret < count && 1951 (kfifo_get(sonypi_compat.fifo, &c, sizeof(c)) == sizeof(c))) { 1952 if (put_user(c, buf++)) 1953 return -EFAULT; 1954 ret++; 1955 } 1956 1957 if (ret > 0) { 1958 struct inode *inode = file->f_path.dentry->d_inode; 1959 inode->i_atime = current_fs_time(inode->i_sb); 1960 } 1961 1962 return ret; 1963} 1964 1965static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait) 1966{ 1967 poll_wait(file, &sonypi_compat.fifo_proc_list, wait); 1968 if (kfifo_len(sonypi_compat.fifo)) 1969 return POLLIN | POLLRDNORM; 1970 return 0; 1971} 1972 1973static int ec_read16(u8 addr, u16 *value) 1974{ 1975 u8 val_lb, val_hb; 1976 if (ec_read(addr, &val_lb)) 1977 return -1; 1978 if (ec_read(addr + 1, &val_hb)) 1979 return -1; 1980 *value = val_lb | (val_hb << 8); 1981 return 0; 1982} 1983 1984static int sonypi_misc_ioctl(struct inode *ip, struct file *fp, 1985 unsigned int cmd, unsigned long arg) 1986{ 1987 int ret = 0; 1988 void __user *argp = (void __user *)arg; 1989 u8 val8; 1990 u16 val16; 1991 int value; 1992 1993 mutex_lock(&spic_dev.lock); 1994 switch (cmd) { 1995 case SONYPI_IOCGBRT: 1996 if (sony_backlight_device == NULL) { 1997 ret = -EIO; 1998 break; 1999 } 2000 if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) { 2001 ret = -EIO; 2002 break; 2003 } 2004 val8 = ((value & 0xff) - 1) << 5; 2005 if (copy_to_user(argp, &val8, sizeof(val8))) 2006 ret = -EFAULT; 2007 break; 2008 case SONYPI_IOCSBRT: 2009 if (sony_backlight_device == NULL) { 2010 ret = -EIO; 2011 break; 2012 } 2013 if (copy_from_user(&val8, argp, sizeof(val8))) { 2014 ret = -EFAULT; 2015 break; 2016 } 2017 if (acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", 2018 (val8 >> 5) + 1, NULL)) { 2019 ret = -EIO; 2020 break; 2021 } 2022 /* sync the backlight device status */ 2023 sony_backlight_device->props.brightness = 2024 sony_backlight_get_brightness(sony_backlight_device); 2025 break; 2026 case SONYPI_IOCGBAT1CAP: 2027 if (ec_read16(SONYPI_BAT1_FULL, &val16)) { 2028 ret = -EIO; 2029 break; 2030 } 2031 if (copy_to_user(argp, &val16, sizeof(val16))) 2032 ret = -EFAULT; 2033 break; 2034 case SONYPI_IOCGBAT1REM: 2035 if (ec_read16(SONYPI_BAT1_LEFT, &val16)) { 2036 ret = -EIO; 2037 break; 2038 } 2039 if (copy_to_user(argp, &val16, sizeof(val16))) 2040 ret = -EFAULT; 2041 break; 2042 case SONYPI_IOCGBAT2CAP: 2043 if (ec_read16(SONYPI_BAT2_FULL, &val16)) { 2044 ret = -EIO; 2045 break; 2046 } 2047 if (copy_to_user(argp, &val16, sizeof(val16))) 2048 ret = -EFAULT; 2049 break; 2050 case SONYPI_IOCGBAT2REM: 2051 if (ec_read16(SONYPI_BAT2_LEFT, &val16)) { 2052 ret = -EIO; 2053 break; 2054 } 2055 if (copy_to_user(argp, &val16, sizeof(val16))) 2056 ret = -EFAULT; 2057 break; 2058 case SONYPI_IOCGBATFLAGS: 2059 if (ec_read(SONYPI_BAT_FLAGS, &val8)) { 2060 ret = -EIO; 2061 break; 2062 } 2063 val8 &= 0x07; 2064 if (copy_to_user(argp, &val8, sizeof(val8))) 2065 ret = -EFAULT; 2066 break; 2067 case SONYPI_IOCGBLUE: 2068 val8 = spic_dev.bluetooth_power; 2069 if (copy_to_user(argp, &val8, sizeof(val8))) 2070 ret = -EFAULT; 2071 break; 2072 case SONYPI_IOCSBLUE: 2073 if (copy_from_user(&val8, argp, sizeof(val8))) { 2074 ret = -EFAULT; 2075 break; 2076 } 2077 __sony_pic_set_bluetoothpower(val8); 2078 break; 2079 /* FAN Controls */ 2080 case SONYPI_IOCGFAN: 2081 if (sony_pic_get_fanspeed(&val8)) { 2082 ret = -EIO; 2083 break; 2084 } 2085 if (copy_to_user(argp, &val8, sizeof(val8))) 2086 ret = -EFAULT; 2087 break; 2088 case SONYPI_IOCSFAN: 2089 if (copy_from_user(&val8, argp, sizeof(val8))) { 2090 ret = -EFAULT; 2091 break; 2092 } 2093 if (sony_pic_set_fanspeed(val8)) 2094 ret = -EIO; 2095 break; 2096 /* GET Temperature (useful under APM) */ 2097 case SONYPI_IOCGTEMP: 2098 if (ec_read(SONYPI_TEMP_STATUS, &val8)) { 2099 ret = -EIO; 2100 break; 2101 } 2102 if (copy_to_user(argp, &val8, sizeof(val8))) 2103 ret = -EFAULT; 2104 break; 2105 default: 2106 ret = -EINVAL; 2107 } 2108 mutex_unlock(&spic_dev.lock); 2109 return ret; 2110} 2111 2112static const struct file_operations sonypi_misc_fops = { 2113 .owner = THIS_MODULE, 2114 .read = sonypi_misc_read, 2115 .poll = sonypi_misc_poll, 2116 .open = sonypi_misc_open, 2117 .release = sonypi_misc_release, 2118 .fasync = sonypi_misc_fasync, 2119 .ioctl = sonypi_misc_ioctl, 2120}; 2121 2122static struct miscdevice sonypi_misc_device = { 2123 .minor = MISC_DYNAMIC_MINOR, 2124 .name = "sonypi", 2125 .fops = &sonypi_misc_fops, 2126}; 2127 2128static void sonypi_compat_report_event(u8 event) 2129{ 2130 kfifo_put(sonypi_compat.fifo, (unsigned char *)&event, sizeof(event)); 2131 kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN); 2132 wake_up_interruptible(&sonypi_compat.fifo_proc_list); 2133} 2134 2135static int sonypi_compat_init(void) 2136{ 2137 int error; 2138 2139 spin_lock_init(&sonypi_compat.fifo_lock); 2140 sonypi_compat.fifo = kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL, 2141 &sonypi_compat.fifo_lock); 2142 if (IS_ERR(sonypi_compat.fifo)) { 2143 printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); 2144 return PTR_ERR(sonypi_compat.fifo); 2145 } 2146 2147 init_waitqueue_head(&sonypi_compat.fifo_proc_list); 2148 2149 if (minor != -1) 2150 sonypi_misc_device.minor = minor; 2151 error = misc_register(&sonypi_misc_device); 2152 if (error) { 2153 printk(KERN_ERR DRV_PFX "misc_register failed\n"); 2154 goto err_free_kfifo; 2155 } 2156 if (minor == -1) 2157 printk(KERN_INFO DRV_PFX "device allocated minor is %d\n", 2158 sonypi_misc_device.minor); 2159 2160 return 0; 2161 2162err_free_kfifo: 2163 kfifo_free(sonypi_compat.fifo); 2164 return error; 2165} 2166 2167static void sonypi_compat_exit(void) 2168{ 2169 misc_deregister(&sonypi_misc_device); 2170 kfifo_free(sonypi_compat.fifo); 2171} 2172#else 2173static int sonypi_compat_init(void) { return 0; } 2174static void sonypi_compat_exit(void) { } 2175static void sonypi_compat_report_event(u8 event) { } 2176#endif /* CONFIG_SONYPI_COMPAT */ 2177 2178/* 2179 * ACPI callbacks 2180 */ 2181static acpi_status 2182sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) 2183{ 2184 u32 i; 2185 struct sony_pic_dev *dev = (struct sony_pic_dev *)context; 2186 2187 switch (resource->type) { 2188 case ACPI_RESOURCE_TYPE_START_DEPENDENT: 2189 { 2190 /* start IO enumeration */ 2191 struct sony_pic_ioport *ioport = kzalloc(sizeof(*ioport), GFP_KERNEL); 2192 if (!ioport) 2193 return AE_ERROR; 2194 2195 list_add(&ioport->list, &dev->ioports); 2196 return AE_OK; 2197 } 2198 2199 case ACPI_RESOURCE_TYPE_END_DEPENDENT: 2200 /* end IO enumeration */ 2201 return AE_OK; 2202 2203 case ACPI_RESOURCE_TYPE_IRQ: 2204 { 2205 struct acpi_resource_irq *p = &resource->data.irq; 2206 struct sony_pic_irq *interrupt = NULL; 2207 if (!p || !p->interrupt_count) { 2208 /* 2209 * IRQ descriptors may have no IRQ# bits set, 2210 * particularly those those w/ _STA disabled 2211 */ 2212 dprintk("Blank IRQ resource\n"); 2213 return AE_OK; 2214 } 2215 for (i = 0; i < p->interrupt_count; i++) { 2216 if (!p->interrupts[i]) { 2217 printk(KERN_WARNING DRV_PFX 2218 "Invalid IRQ %d\n", 2219 p->interrupts[i]); 2220 continue; 2221 } 2222 interrupt = kzalloc(sizeof(*interrupt), 2223 GFP_KERNEL); 2224 if (!interrupt) 2225 return AE_ERROR; 2226 2227 list_add(&interrupt->list, &dev->interrupts); 2228 interrupt->irq.triggering = p->triggering; 2229 interrupt->irq.polarity = p->polarity; 2230 interrupt->irq.sharable = p->sharable; 2231 interrupt->irq.interrupt_count = 1; 2232 interrupt->irq.interrupts[0] = p->interrupts[i]; 2233 } 2234 return AE_OK; 2235 } 2236 case ACPI_RESOURCE_TYPE_IO: 2237 { 2238 struct acpi_resource_io *io = &resource->data.io; 2239 struct sony_pic_ioport *ioport = 2240 list_first_entry(&dev->ioports, struct sony_pic_ioport, list); 2241 if (!io) { 2242 dprintk("Blank IO resource\n"); 2243 return AE_OK; 2244 } 2245 2246 if (!ioport->io1.minimum) { 2247 memcpy(&ioport->io1, io, sizeof(*io)); 2248 dprintk("IO1 at 0x%.4x (0x%.2x)\n", ioport->io1.minimum, 2249 ioport->io1.address_length); 2250 } 2251 else if (!ioport->io2.minimum) { 2252 memcpy(&ioport->io2, io, sizeof(*io)); 2253 dprintk("IO2 at 0x%.4x (0x%.2x)\n", ioport->io2.minimum, 2254 ioport->io2.address_length); 2255 } 2256 else { 2257 printk(KERN_ERR DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n"); 2258 return AE_ERROR; 2259 } 2260 return AE_OK; 2261 } 2262 default: 2263 dprintk("Resource %d isn't an IRQ nor an IO port\n", 2264 resource->type); 2265 2266 case ACPI_RESOURCE_TYPE_END_TAG: 2267 return AE_OK; 2268 } 2269 return AE_CTRL_TERMINATE; 2270} 2271 2272static int sony_pic_possible_resources(struct acpi_device *device) 2273{ 2274 int result = 0; 2275 acpi_status status = AE_OK; 2276 2277 if (!device) 2278 return -EINVAL; 2279 2280 /* get device status */ 2281 /* see acpi_pci_link_get_current acpi_pci_link_get_possible */ 2282 dprintk("Evaluating _STA\n"); 2283 result = acpi_bus_get_status(device); 2284 if (result) { 2285 printk(KERN_WARNING DRV_PFX "Unable to read status\n"); 2286 goto end; 2287 } 2288 2289 if (!device->status.enabled) 2290 dprintk("Device disabled\n"); 2291 else 2292 dprintk("Device enabled\n"); 2293 2294 /* 2295 * Query and parse 'method' 2296 */ 2297 dprintk("Evaluating %s\n", METHOD_NAME__PRS); 2298 status = acpi_walk_resources(device->handle, METHOD_NAME__PRS, 2299 sony_pic_read_possible_resource, &spic_dev); 2300 if (ACPI_FAILURE(status)) { 2301 printk(KERN_WARNING DRV_PFX 2302 "Failure evaluating %s\n", 2303 METHOD_NAME__PRS); 2304 result = -ENODEV; 2305 } 2306end: 2307 return result; 2308} 2309 2310/* 2311 * Disable the spic device by calling its _DIS method 2312 */ 2313static int sony_pic_disable(struct acpi_device *device) 2314{ 2315 if (ACPI_FAILURE(acpi_evaluate_object(device->handle, 2316 "_DIS", NULL, NULL))) 2317 return -ENXIO; 2318 2319 dprintk("Device disabled\n"); 2320 return 0; 2321} 2322 2323 2324/* 2325 * Based on drivers/acpi/pci_link.c:acpi_pci_link_set 2326 * 2327 * Call _SRS to set current resources 2328 */ 2329static int sony_pic_enable(struct acpi_device *device, 2330 struct sony_pic_ioport *ioport, struct sony_pic_irq *irq) 2331{ 2332 acpi_status status; 2333 int result = 0; 2334 /* Type 1 resource layout is: 2335 * IO 2336 * IO 2337 * IRQNoFlags 2338 * End 2339 * 2340 * Type 2 and 3 resource layout is: 2341 * IO 2342 * IRQNoFlags 2343 * End 2344 */ 2345 struct { 2346 struct acpi_resource res1; 2347 struct acpi_resource res2; 2348 struct acpi_resource res3; 2349 struct acpi_resource res4; 2350 } *resource; 2351 struct acpi_buffer buffer = { 0, NULL }; 2352 2353 if (!ioport || !irq) 2354 return -EINVAL; 2355 2356 /* init acpi_buffer */ 2357 resource = kzalloc(sizeof(*resource) + 1, GFP_KERNEL); 2358 if (!resource) 2359 return -ENOMEM; 2360 2361 buffer.length = sizeof(*resource) + 1; 2362 buffer.pointer = resource; 2363 2364 /* setup Type 1 resources */ 2365 if (spic_dev.control->model == SONYPI_DEVICE_TYPE1) { 2366 2367 /* setup io resources */ 2368 resource->res1.type = ACPI_RESOURCE_TYPE_IO; 2369 resource->res1.length = sizeof(struct acpi_resource); 2370 memcpy(&resource->res1.data.io, &ioport->io1, 2371 sizeof(struct acpi_resource_io)); 2372 2373 resource->res2.type = ACPI_RESOURCE_TYPE_IO; 2374 resource->res2.length = sizeof(struct acpi_resource); 2375 memcpy(&resource->res2.data.io, &ioport->io2, 2376 sizeof(struct acpi_resource_io)); 2377 2378 /* setup irq resource */ 2379 resource->res3.type = ACPI_RESOURCE_TYPE_IRQ; 2380 resource->res3.length = sizeof(struct acpi_resource); 2381 memcpy(&resource->res3.data.irq, &irq->irq, 2382 sizeof(struct acpi_resource_irq)); 2383 /* we requested a shared irq */ 2384 resource->res3.data.irq.sharable = ACPI_SHARED; 2385 2386 resource->res4.type = ACPI_RESOURCE_TYPE_END_TAG; 2387 2388 } 2389 /* setup Type 2/3 resources */ 2390 else { 2391 /* setup io resource */ 2392 resource->res1.type = ACPI_RESOURCE_TYPE_IO; 2393 resource->res1.length = sizeof(struct acpi_resource); 2394 memcpy(&resource->res1.data.io, &ioport->io1, 2395 sizeof(struct acpi_resource_io)); 2396 2397 /* setup irq resource */ 2398 resource->res2.type = ACPI_RESOURCE_TYPE_IRQ; 2399 resource->res2.length = sizeof(struct acpi_resource); 2400 memcpy(&resource->res2.data.irq, &irq->irq, 2401 sizeof(struct acpi_resource_irq)); 2402 /* we requested a shared irq */ 2403 resource->res2.data.irq.sharable = ACPI_SHARED; 2404 2405 resource->res3.type = ACPI_RESOURCE_TYPE_END_TAG; 2406 } 2407 2408 /* Attempt to set the resource */ 2409 dprintk("Evaluating _SRS\n"); 2410 status = acpi_set_current_resources(device->handle, &buffer); 2411 2412 /* check for total failure */ 2413 if (ACPI_FAILURE(status)) { 2414 printk(KERN_ERR DRV_PFX "Error evaluating _SRS\n"); 2415 result = -ENODEV; 2416 goto end; 2417 } 2418 2419 /* Necessary device initializations calls (from sonypi) */ 2420 sony_pic_call1(0x82); 2421 sony_pic_call2(0x81, 0xff); 2422 sony_pic_call1(compat ? 0x92 : 0x82); 2423 2424end: 2425 kfree(resource); 2426 return result; 2427} 2428 2429/***************** 2430 * 2431 * ISR: some event is available 2432 * 2433 *****************/ 2434static irqreturn_t sony_pic_irq(int irq, void *dev_id) 2435{ 2436 int i, j; 2437 u8 ev = 0; 2438 u8 data_mask = 0; 2439 u8 device_event = 0; 2440 2441 struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id; 2442 2443 ev = inb_p(dev->cur_ioport->io1.minimum); 2444 if (dev->cur_ioport->io2.minimum) 2445 data_mask = inb_p(dev->cur_ioport->io2.minimum); 2446 else 2447 data_mask = inb_p(dev->cur_ioport->io1.minimum + 2448 dev->control->evport_offset); 2449 2450 dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n", 2451 ev, data_mask, dev->cur_ioport->io1.minimum, 2452 dev->control->evport_offset); 2453 2454 if (ev == 0x00 || ev == 0xff) 2455 return IRQ_HANDLED; 2456 2457 for (i = 0; dev->control->event_types[i].mask; i++) { 2458 2459 if ((data_mask & dev->control->event_types[i].data) != 2460 dev->control->event_types[i].data) 2461 continue; 2462 2463 if (!(mask & dev->control->event_types[i].mask)) 2464 continue; 2465 2466 for (j = 0; dev->control->event_types[i].events[j].event; j++) { 2467 if (ev == dev->control->event_types[i].events[j].data) { 2468 device_event = 2469 dev->control-> 2470 event_types[i].events[j].event; 2471 goto found; 2472 } 2473 } 2474 } 2475 /* Still not able to decode the event try to pass 2476 * it over to the minidriver 2477 */ 2478 if (dev->control->handle_irq && 2479 dev->control->handle_irq(data_mask, ev) == 0) 2480 return IRQ_HANDLED; 2481 2482 dprintk("unknown event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n", 2483 ev, data_mask, dev->cur_ioport->io1.minimum, 2484 dev->control->evport_offset); 2485 return IRQ_HANDLED; 2486 2487found: 2488 sony_laptop_report_input_event(device_event); 2489 acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event); 2490 sonypi_compat_report_event(device_event); 2491 2492 return IRQ_HANDLED; 2493} 2494 2495/***************** 2496 * 2497 * ACPI driver 2498 * 2499 *****************/ 2500static int sony_pic_remove(struct acpi_device *device, int type) 2501{ 2502 struct sony_pic_ioport *io, *tmp_io; 2503 struct sony_pic_irq *irq, *tmp_irq; 2504 2505 if (sony_pic_disable(device)) { 2506 printk(KERN_ERR DRV_PFX "Couldn't disable device.\n"); 2507 return -ENXIO; 2508 } 2509 2510 free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev); 2511 release_region(spic_dev.cur_ioport->io1.minimum, 2512 spic_dev.cur_ioport->io1.address_length); 2513 if (spic_dev.cur_ioport->io2.minimum) 2514 release_region(spic_dev.cur_ioport->io2.minimum, 2515 spic_dev.cur_ioport->io2.address_length); 2516 2517 sonypi_compat_exit(); 2518 2519 sony_laptop_remove_input(); 2520 2521 /* pf attrs */ 2522 sysfs_remove_group(&sony_pf_device->dev.kobj, &spic_attribute_group); 2523 sony_pf_remove(); 2524 2525 list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) { 2526 list_del(&io->list); 2527 kfree(io); 2528 } 2529 list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) { 2530 list_del(&irq->list); 2531 kfree(irq); 2532 } 2533 spic_dev.cur_ioport = NULL; 2534 spic_dev.cur_irq = NULL; 2535 2536 dprintk(SONY_PIC_DRIVER_NAME " removed.\n"); 2537 return 0; 2538} 2539 2540static int sony_pic_add(struct acpi_device *device) 2541{ 2542 int result; 2543 struct sony_pic_ioport *io, *tmp_io; 2544 struct sony_pic_irq *irq, *tmp_irq; 2545 2546 printk(KERN_INFO DRV_PFX "%s v%s.\n", 2547 SONY_PIC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION); 2548 2549 spic_dev.acpi_dev = device; 2550 strcpy(acpi_device_class(device), "sony/hotkey"); 2551 sony_pic_detect_device_type(&spic_dev); 2552 mutex_init(&spic_dev.lock); 2553 2554 /* read _PRS resources */ 2555 result = sony_pic_possible_resources(device); 2556 if (result) { 2557 printk(KERN_ERR DRV_PFX 2558 "Unabe to read possible resources.\n"); 2559 goto err_free_resources; 2560 } 2561 2562 /* setup input devices and helper fifo */ 2563 result = sony_laptop_setup_input(device); 2564 if (result) { 2565 printk(KERN_ERR DRV_PFX 2566 "Unabe to create input devices.\n"); 2567 goto err_free_resources; 2568 } 2569 2570 if (sonypi_compat_init()) 2571 goto err_remove_input; 2572 2573 /* request io port */ 2574 list_for_each_entry_reverse(io, &spic_dev.ioports, list) { 2575 if (request_region(io->io1.minimum, io->io1.address_length, 2576 "Sony Programable I/O Device")) { 2577 dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n", 2578 io->io1.minimum, io->io1.maximum, 2579 io->io1.address_length); 2580 /* Type 1 have 2 ioports */ 2581 if (io->io2.minimum) { 2582 if (request_region(io->io2.minimum, 2583 io->io2.address_length, 2584 "Sony Programable I/O Device")) { 2585 dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n", 2586 io->io2.minimum, io->io2.maximum, 2587 io->io2.address_length); 2588 spic_dev.cur_ioport = io; 2589 break; 2590 } 2591 else { 2592 dprintk("Unable to get I/O port2: " 2593 "0x%.4x (0x%.4x) + 0x%.2x\n", 2594 io->io2.minimum, io->io2.maximum, 2595 io->io2.address_length); 2596 release_region(io->io1.minimum, 2597 io->io1.address_length); 2598 } 2599 } 2600 else { 2601 spic_dev.cur_ioport = io; 2602 break; 2603 } 2604 } 2605 } 2606 if (!spic_dev.cur_ioport) { 2607 printk(KERN_ERR DRV_PFX "Failed to request_region.\n"); 2608 result = -ENODEV; 2609 goto err_remove_compat; 2610 } 2611 2612 /* request IRQ */ 2613 list_for_each_entry_reverse(irq, &spic_dev.interrupts, list) { 2614 if (!request_irq(irq->irq.interrupts[0], sony_pic_irq, 2615 IRQF_SHARED, "sony-laptop", &spic_dev)) { 2616 dprintk("IRQ: %d - triggering: %d - " 2617 "polarity: %d - shr: %d\n", 2618 irq->irq.interrupts[0], 2619 irq->irq.triggering, 2620 irq->irq.polarity, 2621 irq->irq.sharable); 2622 spic_dev.cur_irq = irq; 2623 break; 2624 } 2625 } 2626 if (!spic_dev.cur_irq) { 2627 printk(KERN_ERR DRV_PFX "Failed to request_irq.\n"); 2628 result = -ENODEV; 2629 goto err_release_region; 2630 } 2631 2632 /* set resource status _SRS */ 2633 result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq); 2634 if (result) { 2635 printk(KERN_ERR DRV_PFX "Couldn't enable device.\n"); 2636 goto err_free_irq; 2637 } 2638 2639 spic_dev.bluetooth_power = -1; 2640 /* create device attributes */ 2641 result = sony_pf_add(); 2642 if (result) 2643 goto err_disable_device; 2644 2645 result = sysfs_create_group(&sony_pf_device->dev.kobj, &spic_attribute_group); 2646 if (result) 2647 goto err_remove_pf; 2648 2649 return 0; 2650 2651err_remove_pf: 2652 sony_pf_remove(); 2653 2654err_disable_device: 2655 sony_pic_disable(device); 2656 2657err_free_irq: 2658 free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev); 2659 2660err_release_region: 2661 release_region(spic_dev.cur_ioport->io1.minimum, 2662 spic_dev.cur_ioport->io1.address_length); 2663 if (spic_dev.cur_ioport->io2.minimum) 2664 release_region(spic_dev.cur_ioport->io2.minimum, 2665 spic_dev.cur_ioport->io2.address_length); 2666 2667err_remove_compat: 2668 sonypi_compat_exit(); 2669 2670err_remove_input: 2671 sony_laptop_remove_input(); 2672 2673err_free_resources: 2674 list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) { 2675 list_del(&io->list); 2676 kfree(io); 2677 } 2678 list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) { 2679 list_del(&irq->list); 2680 kfree(irq); 2681 } 2682 spic_dev.cur_ioport = NULL; 2683 spic_dev.cur_irq = NULL; 2684 2685 return result; 2686} 2687 2688static int sony_pic_suspend(struct acpi_device *device, pm_message_t state) 2689{ 2690 if (sony_pic_disable(device)) 2691 return -ENXIO; 2692 return 0; 2693} 2694 2695static int sony_pic_resume(struct acpi_device *device) 2696{ 2697 sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq); 2698 return 0; 2699} 2700 2701static const struct acpi_device_id sony_pic_device_ids[] = { 2702 {SONY_PIC_HID, 0}, 2703 {"", 0}, 2704}; 2705 2706static struct acpi_driver sony_pic_driver = { 2707 .name = SONY_PIC_DRIVER_NAME, 2708 .class = SONY_PIC_CLASS, 2709 .ids = sony_pic_device_ids, 2710 .owner = THIS_MODULE, 2711 .ops = { 2712 .add = sony_pic_add, 2713 .remove = sony_pic_remove, 2714 .suspend = sony_pic_suspend, 2715 .resume = sony_pic_resume, 2716 }, 2717}; 2718 2719static struct dmi_system_id __initdata sonypi_dmi_table[] = { 2720 { 2721 .ident = "Sony Vaio", 2722 .matches = { 2723 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 2724 DMI_MATCH(DMI_PRODUCT_NAME, "PCG-"), 2725 }, 2726 }, 2727 { 2728 .ident = "Sony Vaio", 2729 .matches = { 2730 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 2731 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"), 2732 }, 2733 }, 2734 { } 2735}; 2736 2737static int __init sony_laptop_init(void) 2738{ 2739 int result; 2740 2741 if (!no_spic && dmi_check_system(sonypi_dmi_table)) { 2742 result = acpi_bus_register_driver(&sony_pic_driver); 2743 if (result) { 2744 printk(KERN_ERR DRV_PFX 2745 "Unable to register SPIC driver."); 2746 goto out; 2747 } 2748 } 2749 2750 result = acpi_bus_register_driver(&sony_nc_driver); 2751 if (result) { 2752 printk(KERN_ERR DRV_PFX "Unable to register SNC driver."); 2753 goto out_unregister_pic; 2754 } 2755 2756 return 0; 2757 2758out_unregister_pic: 2759 if (!no_spic) 2760 acpi_bus_unregister_driver(&sony_pic_driver); 2761out: 2762 return result; 2763} 2764 2765static void __exit sony_laptop_exit(void) 2766{ 2767 acpi_bus_unregister_driver(&sony_nc_driver); 2768 if (!no_spic) 2769 acpi_bus_unregister_driver(&sony_pic_driver); 2770} 2771 2772module_init(sony_laptop_init); 2773module_exit(sony_laptop_exit);