diff options
| author | Marco Chiappero <marco@absence.it> | 2012-05-19 09:36:00 -0400 |
|---|---|---|
| committer | Matthew Garrett <mjg@redhat.com> | 2012-05-31 14:35:06 -0400 |
| commit | 2b8791c4ff88f774dde98f12f652d5c2bdd2925d (patch) | |
| tree | bc728e98a6dc2e95dc12b3a04971d1a08dbaa549 | |
| parent | 2e52631127ceae2508ca5ae6b0870c024f966299 (diff) | |
sony-laptop: add touchpad enable/disable function
This setting is stored in the EC and available across reboots.
[malattia@linux.it: group function specific variables in a struct, use
kstrtoul]
Signed-off-by: Marco Chiappero <marco@absence.it>
Signed-off-by: Mattia Dongili <malattia@linux.it>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
| -rw-r--r-- | drivers/platform/x86/sony-laptop.c | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 5902bb5a9e78..210d4ae547c2 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c | |||
| @@ -159,6 +159,10 @@ static void sony_nc_lid_resume_cleanup(struct platform_device *pd); | |||
| 159 | static int sony_nc_highspeed_charging_setup(struct platform_device *pd); | 159 | static int sony_nc_highspeed_charging_setup(struct platform_device *pd); |
| 160 | static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd); | 160 | static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd); |
| 161 | 161 | ||
| 162 | static int sony_nc_touchpad_setup(struct platform_device *pd, | ||
| 163 | unsigned int handle); | ||
| 164 | static void sony_nc_touchpad_cleanup(struct platform_device *pd); | ||
| 165 | |||
| 162 | enum sony_nc_rfkill { | 166 | enum sony_nc_rfkill { |
| 163 | SONY_WIFI, | 167 | SONY_WIFI, |
| 164 | SONY_BLUETOOTH, | 168 | SONY_BLUETOOTH, |
| @@ -1290,6 +1294,14 @@ static void sony_nc_function_setup(struct acpi_device *device, | |||
| 1290 | /* setup hotkeys */ | 1294 | /* setup hotkeys */ |
| 1291 | sony_call_snc_handle(handle, 0x100, &result); | 1295 | sony_call_snc_handle(handle, 0x100, &result); |
| 1292 | break; | 1296 | break; |
| 1297 | case 0x0105: | ||
| 1298 | case 0x0148: | ||
| 1299 | /* touchpad enable/disable */ | ||
| 1300 | result = sony_nc_touchpad_setup(pf_device, handle); | ||
| 1301 | if (result) | ||
| 1302 | pr_err("couldn't set up touchpad control function (%d)\n", | ||
| 1303 | result); | ||
| 1304 | break; | ||
| 1293 | case 0x0115: | 1305 | case 0x0115: |
| 1294 | case 0x0136: | 1306 | case 0x0136: |
| 1295 | case 0x013f: | 1307 | case 0x013f: |
| @@ -1359,6 +1371,10 @@ static void sony_nc_function_cleanup(struct platform_device *pd) | |||
| 1359 | continue; | 1371 | continue; |
| 1360 | 1372 | ||
| 1361 | switch (handle) { | 1373 | switch (handle) { |
| 1374 | case 0x0105: | ||
| 1375 | case 0x0148: | ||
| 1376 | sony_nc_touchpad_cleanup(pd); | ||
| 1377 | break; | ||
| 1362 | case 0x0115: | 1378 | case 0x0115: |
| 1363 | case 0x0136: | 1379 | case 0x0136: |
| 1364 | case 0x013f: | 1380 | case 0x013f: |
| @@ -2376,6 +2392,81 @@ static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd) | |||
| 2376 | } | 2392 | } |
| 2377 | } | 2393 | } |
| 2378 | 2394 | ||
| 2395 | /* Touchpad enable/disable */ | ||
| 2396 | struct touchpad_control { | ||
| 2397 | struct device_attribute attr; | ||
| 2398 | int handle; | ||
| 2399 | }; | ||
| 2400 | static struct touchpad_control *tp_ctl; | ||
| 2401 | |||
| 2402 | static ssize_t sony_nc_touchpad_store(struct device *dev, | ||
| 2403 | struct device_attribute *attr, const char *buffer, size_t count) | ||
| 2404 | { | ||
| 2405 | unsigned int result; | ||
| 2406 | unsigned long value; | ||
| 2407 | |||
| 2408 | if (count > 31) | ||
| 2409 | return -EINVAL; | ||
| 2410 | |||
| 2411 | if (kstrtoul(buffer, 10, &value) || value > 1) | ||
| 2412 | return -EINVAL; | ||
| 2413 | |||
| 2414 | /* sysfs: 0 disabled, 1 enabled | ||
| 2415 | * EC: 0 enabled, 1 disabled | ||
| 2416 | */ | ||
| 2417 | if (sony_call_snc_handle(tp_ctl->handle, | ||
| 2418 | (!value << 0x10) | 0x100, &result)) | ||
| 2419 | return -EIO; | ||
| 2420 | |||
| 2421 | return count; | ||
| 2422 | } | ||
| 2423 | |||
| 2424 | static ssize_t sony_nc_touchpad_show(struct device *dev, | ||
| 2425 | struct device_attribute *attr, char *buffer) | ||
| 2426 | { | ||
| 2427 | unsigned int result; | ||
| 2428 | |||
| 2429 | if (sony_call_snc_handle(tp_ctl->handle, 0x000, &result)) | ||
| 2430 | return -EINVAL; | ||
| 2431 | |||
| 2432 | return snprintf(buffer, PAGE_SIZE, "%d\n", !(result & 0x01)); | ||
| 2433 | } | ||
| 2434 | |||
| 2435 | static int sony_nc_touchpad_setup(struct platform_device *pd, | ||
| 2436 | unsigned int handle) | ||
| 2437 | { | ||
| 2438 | int ret = 0; | ||
| 2439 | |||
| 2440 | tp_ctl = kzalloc(sizeof(struct touchpad_control), GFP_KERNEL); | ||
| 2441 | if (!tp_ctl) | ||
| 2442 | return -ENOMEM; | ||
| 2443 | |||
| 2444 | tp_ctl->handle = handle; | ||
| 2445 | |||
| 2446 | sysfs_attr_init(&tp_ctl->attr.attr); | ||
| 2447 | tp_ctl->attr.attr.name = "touchpad"; | ||
| 2448 | tp_ctl->attr.attr.mode = S_IRUGO | S_IWUSR; | ||
| 2449 | tp_ctl->attr.show = sony_nc_touchpad_show; | ||
| 2450 | tp_ctl->attr.store = sony_nc_touchpad_store; | ||
| 2451 | |||
| 2452 | ret = device_create_file(&pd->dev, &tp_ctl->attr); | ||
| 2453 | if (ret) { | ||
| 2454 | kfree(tp_ctl); | ||
| 2455 | tp_ctl = NULL; | ||
| 2456 | } | ||
| 2457 | |||
| 2458 | return ret; | ||
| 2459 | } | ||
| 2460 | |||
| 2461 | static void sony_nc_touchpad_cleanup(struct platform_device *pd) | ||
| 2462 | { | ||
| 2463 | if (tp_ctl) { | ||
| 2464 | device_remove_file(&pd->dev, &tp_ctl->attr); | ||
| 2465 | kfree(tp_ctl); | ||
| 2466 | tp_ctl = NULL; | ||
| 2467 | } | ||
| 2468 | } | ||
| 2469 | |||
| 2379 | static void sony_nc_backlight_ng_read_limits(int handle, | 2470 | static void sony_nc_backlight_ng_read_limits(int handle, |
| 2380 | struct sony_backlight_props *props) | 2471 | struct sony_backlight_props *props) |
| 2381 | { | 2472 | { |
