aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorMattia Dongili <malattia@linux.it>2011-02-18 21:52:31 -0500
committerMatthew Garrett <mjg@redhat.com>2011-03-28 06:05:26 -0400
commitbf155714013e59c299e378055d60a4adf92e79db (patch)
treedb171b36a88ad86419e76d43424ddd8b0984c3fc /drivers/platform
parent2a4f0c81adcd1f812a63bc9106be2fd26f437730 (diff)
sony-laptop: implement keyboard backlight support
Recent Vaios have the opportunity to control the keyboard backlight via ACPI calls to the SNC device. Introduce two module parameters to control how keyboard backlight should be set at module loading (default to on and with 10 seconds timeout). Tested-by: Marco Chiappero <marco@absence.it> Signed-off-by: Mattia Dongili <malattia@linux.it> Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/sony-laptop.c176
1 files changed, 175 insertions, 1 deletions
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 516dd22bbb26..326a4600fad1 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -125,6 +125,19 @@ MODULE_PARM_DESC(minor,
125 "default is -1 (automatic)"); 125 "default is -1 (automatic)");
126#endif 126#endif
127 127
128static int kbd_backlight; /* = 1 */
129module_param(kbd_backlight, int, 0444);
130MODULE_PARM_DESC(kbd_backlight,
131 "set this to 0 to disable keyboard backlight, "
132 "1 to enable it (default: 0)");
133
134static int kbd_backlight_timeout; /* = 0 */
135module_param(kbd_backlight_timeout, int, 0444);
136MODULE_PARM_DESC(kbd_backlight_timeout,
137 "set this to 0 to set the default 10 seconds timeout, "
138 "1 for 30 seconds, 2 for 60 seconds and 3 to disable timeout "
139 "(default: 0)");
140
128enum sony_nc_rfkill { 141enum sony_nc_rfkill {
129 SONY_WIFI, 142 SONY_WIFI,
130 SONY_BLUETOOTH, 143 SONY_BLUETOOTH,
@@ -1309,6 +1322,161 @@ out_no_enum:
1309 return; 1322 return;
1310} 1323}
1311 1324
1325/* Keyboard backlight feature */
1326#define KBDBL_HANDLER 0x137
1327#define KBDBL_PRESENT 0xB00
1328#define SET_MODE 0xC00
1329#define SET_TIMEOUT 0xE00
1330
1331struct kbd_backlight {
1332 int mode;
1333 int timeout;
1334 struct device_attribute mode_attr;
1335 struct device_attribute timeout_attr;
1336};
1337
1338struct kbd_backlight *kbdbl_handle;
1339
1340static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value)
1341{
1342 int result;
1343
1344 if (value > 1)
1345 return -EINVAL;
1346
1347 if (sony_call_snc_handle(KBDBL_HANDLER,
1348 (value << 0x10) | SET_MODE, &result))
1349 return -EIO;
1350
1351 kbdbl_handle->mode = value;
1352
1353 return 0;
1354}
1355
1356static ssize_t sony_nc_kbd_backlight_mode_store(struct device *dev,
1357 struct device_attribute *attr,
1358 const char *buffer, size_t count)
1359{
1360 int ret = 0;
1361 unsigned long value;
1362
1363 if (count > 31)
1364 return -EINVAL;
1365
1366 if (strict_strtoul(buffer, 10, &value))
1367 return -EINVAL;
1368
1369 ret = __sony_nc_kbd_backlight_mode_set(value);
1370 if (ret < 0)
1371 return ret;
1372
1373 return count;
1374}
1375
1376static ssize_t sony_nc_kbd_backlight_mode_show(struct device *dev,
1377 struct device_attribute *attr, char *buffer)
1378{
1379 ssize_t count = 0;
1380 count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->mode);
1381 return count;
1382}
1383
1384static int __sony_nc_kbd_backlight_timeout_set(u8 value)
1385{
1386 int result;
1387
1388 if (value > 3)
1389 return -EINVAL;
1390
1391 if (sony_call_snc_handle(KBDBL_HANDLER,
1392 (value << 0x10) | SET_TIMEOUT, &result))
1393 return -EIO;
1394
1395 kbdbl_handle->timeout = value;
1396
1397 return 0;
1398}
1399
1400static ssize_t sony_nc_kbd_backlight_timeout_store(struct device *dev,
1401 struct device_attribute *attr,
1402 const char *buffer, size_t count)
1403{
1404 int ret = 0;
1405 unsigned long value;
1406
1407 if (count > 31)
1408 return -EINVAL;
1409
1410 if (strict_strtoul(buffer, 10, &value))
1411 return -EINVAL;
1412
1413 ret = __sony_nc_kbd_backlight_timeout_set(value);
1414 if (ret < 0)
1415 return ret;
1416
1417 return count;
1418}
1419
1420static ssize_t sony_nc_kbd_backlight_timeout_show(struct device *dev,
1421 struct device_attribute *attr, char *buffer)
1422{
1423 ssize_t count = 0;
1424 count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->timeout);
1425 return count;
1426}
1427
1428static int sony_nc_kbd_backlight_setup(struct platform_device *pd)
1429{
1430 int result;
1431
1432 if (sony_call_snc_handle(0x137, KBDBL_PRESENT, &result))
1433 return 0;
1434 if (!(result & 0x02))
1435 return 0;
1436
1437 kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL);
1438
1439 sysfs_attr_init(&kbdbl_handle->mode_attr.attr);
1440 kbdbl_handle->mode_attr.attr.name = "kbd_backlight";
1441 kbdbl_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR;
1442 kbdbl_handle->mode_attr.show = sony_nc_kbd_backlight_mode_show;
1443 kbdbl_handle->mode_attr.store = sony_nc_kbd_backlight_mode_store;
1444
1445 sysfs_attr_init(&kbdbl_handle->timeout_attr.attr);
1446 kbdbl_handle->timeout_attr.attr.name = "kbd_backlight_timeout";
1447 kbdbl_handle->timeout_attr.attr.mode = S_IRUGO | S_IWUSR;
1448 kbdbl_handle->timeout_attr.show = sony_nc_kbd_backlight_timeout_show;
1449 kbdbl_handle->timeout_attr.store = sony_nc_kbd_backlight_timeout_store;
1450
1451 if (device_create_file(&pd->dev, &kbdbl_handle->mode_attr))
1452 goto outkzalloc;
1453
1454 if (device_create_file(&pd->dev, &kbdbl_handle->timeout_attr))
1455 goto outmode;
1456
1457 __sony_nc_kbd_backlight_mode_set(kbd_backlight);
1458 __sony_nc_kbd_backlight_timeout_set(kbd_backlight_timeout);
1459
1460 return 0;
1461
1462outmode:
1463 device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
1464outkzalloc:
1465 kfree(kbdbl_handle);
1466 kbdbl_handle = NULL;
1467 return -1;
1468}
1469
1470static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
1471{
1472 if (kbdbl_handle) {
1473 device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
1474 device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr);
1475 kfree(kbdbl_handle);
1476 }
1477 return 0;
1478}
1479
1312static int sony_nc_add(struct acpi_device *device) 1480static int sony_nc_add(struct acpi_device *device)
1313{ 1481{
1314 acpi_status status; 1482 acpi_status status;
@@ -1359,6 +1527,8 @@ static int sony_nc_add(struct acpi_device *device)
1359 dprintk("Doing SNC setup\n"); 1527 dprintk("Doing SNC setup\n");
1360 if (sony_nc_handles_setup(sony_pf_device)) 1528 if (sony_nc_handles_setup(sony_pf_device))
1361 goto outpresent; 1529 goto outpresent;
1530 if (sony_nc_kbd_backlight_setup(sony_pf_device))
1531 goto outsnc;
1362 sony_nc_function_setup(device); 1532 sony_nc_function_setup(device);
1363 sony_nc_rfkill_setup(device); 1533 sony_nc_rfkill_setup(device);
1364 } 1534 }
@@ -1367,7 +1537,7 @@ static int sony_nc_add(struct acpi_device *device)
1367 result = sony_laptop_setup_input(device); 1537 result = sony_laptop_setup_input(device);
1368 if (result) { 1538 if (result) {
1369 pr_err(DRV_PFX "Unable to create input devices.\n"); 1539 pr_err(DRV_PFX "Unable to create input devices.\n");
1370 goto outsnc; 1540 goto outkbdbacklight;
1371 } 1541 }
1372 1542
1373 if (acpi_video_backlight_support()) { 1543 if (acpi_video_backlight_support()) {
@@ -1445,6 +1615,9 @@ static int sony_nc_add(struct acpi_device *device)
1445 1615
1446 sony_laptop_remove_input(); 1616 sony_laptop_remove_input();
1447 1617
1618 outkbdbacklight:
1619 sony_nc_kbd_backlight_cleanup(sony_pf_device);
1620
1448 outsnc: 1621 outsnc:
1449 sony_nc_handles_cleanup(sony_pf_device); 1622 sony_nc_handles_cleanup(sony_pf_device);
1450 1623
@@ -1469,6 +1642,7 @@ static int sony_nc_remove(struct acpi_device *device, int type)
1469 device_remove_file(&sony_pf_device->dev, &item->devattr); 1642 device_remove_file(&sony_pf_device->dev, &item->devattr);
1470 } 1643 }
1471 1644
1645 sony_nc_kbd_backlight_cleanup(sony_pf_device);
1472 sony_nc_handles_cleanup(sony_pf_device); 1646 sony_nc_handles_cleanup(sony_pf_device);
1473 sony_pf_remove(); 1647 sony_pf_remove();
1474 sony_laptop_remove_input(); 1648 sony_laptop_remove_input();