|
@@ -125,6 +125,19 @@ MODULE_PARM_DESC(minor,
|
|
|
"default is -1 (automatic)");
|
|
|
#endif
|
|
|
|
|
|
+static int kbd_backlight; /* = 1 */
|
|
|
+module_param(kbd_backlight, int, 0444);
|
|
|
+MODULE_PARM_DESC(kbd_backlight,
|
|
|
+ "set this to 0 to disable keyboard backlight, "
|
|
|
+ "1 to enable it (default: 0)");
|
|
|
+
|
|
|
+static int kbd_backlight_timeout; /* = 0 */
|
|
|
+module_param(kbd_backlight_timeout, int, 0444);
|
|
|
+MODULE_PARM_DESC(kbd_backlight_timeout,
|
|
|
+ "set this to 0 to set the default 10 seconds timeout, "
|
|
|
+ "1 for 30 seconds, 2 for 60 seconds and 3 to disable timeout "
|
|
|
+ "(default: 0)");
|
|
|
+
|
|
|
enum sony_nc_rfkill {
|
|
|
SONY_WIFI,
|
|
|
SONY_BLUETOOTH,
|
|
@@ -1309,6 +1322,161 @@ out_no_enum:
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+/* Keyboard backlight feature */
|
|
|
+#define KBDBL_HANDLER 0x137
|
|
|
+#define KBDBL_PRESENT 0xB00
|
|
|
+#define SET_MODE 0xC00
|
|
|
+#define SET_TIMEOUT 0xE00
|
|
|
+
|
|
|
+struct kbd_backlight {
|
|
|
+ int mode;
|
|
|
+ int timeout;
|
|
|
+ struct device_attribute mode_attr;
|
|
|
+ struct device_attribute timeout_attr;
|
|
|
+};
|
|
|
+
|
|
|
+struct kbd_backlight *kbdbl_handle;
|
|
|
+
|
|
|
+static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value)
|
|
|
+{
|
|
|
+ int result;
|
|
|
+
|
|
|
+ if (value > 1)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (sony_call_snc_handle(KBDBL_HANDLER,
|
|
|
+ (value << 0x10) | SET_MODE, &result))
|
|
|
+ return -EIO;
|
|
|
+
|
|
|
+ kbdbl_handle->mode = value;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t sony_nc_kbd_backlight_mode_store(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ const char *buffer, size_t count)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+ unsigned long value;
|
|
|
+
|
|
|
+ if (count > 31)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (strict_strtoul(buffer, 10, &value))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ ret = __sony_nc_kbd_backlight_mode_set(value);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t sony_nc_kbd_backlight_mode_show(struct device *dev,
|
|
|
+ struct device_attribute *attr, char *buffer)
|
|
|
+{
|
|
|
+ ssize_t count = 0;
|
|
|
+ count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->mode);
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+static int __sony_nc_kbd_backlight_timeout_set(u8 value)
|
|
|
+{
|
|
|
+ int result;
|
|
|
+
|
|
|
+ if (value > 3)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (sony_call_snc_handle(KBDBL_HANDLER,
|
|
|
+ (value << 0x10) | SET_TIMEOUT, &result))
|
|
|
+ return -EIO;
|
|
|
+
|
|
|
+ kbdbl_handle->timeout = value;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t sony_nc_kbd_backlight_timeout_store(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ const char *buffer, size_t count)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+ unsigned long value;
|
|
|
+
|
|
|
+ if (count > 31)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (strict_strtoul(buffer, 10, &value))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ ret = __sony_nc_kbd_backlight_timeout_set(value);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t sony_nc_kbd_backlight_timeout_show(struct device *dev,
|
|
|
+ struct device_attribute *attr, char *buffer)
|
|
|
+{
|
|
|
+ ssize_t count = 0;
|
|
|
+ count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->timeout);
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+static int sony_nc_kbd_backlight_setup(struct platform_device *pd)
|
|
|
+{
|
|
|
+ int result;
|
|
|
+
|
|
|
+ if (sony_call_snc_handle(0x137, KBDBL_PRESENT, &result))
|
|
|
+ return 0;
|
|
|
+ if (!(result & 0x02))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL);
|
|
|
+
|
|
|
+ sysfs_attr_init(&kbdbl_handle->mode_attr.attr);
|
|
|
+ kbdbl_handle->mode_attr.attr.name = "kbd_backlight";
|
|
|
+ kbdbl_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR;
|
|
|
+ kbdbl_handle->mode_attr.show = sony_nc_kbd_backlight_mode_show;
|
|
|
+ kbdbl_handle->mode_attr.store = sony_nc_kbd_backlight_mode_store;
|
|
|
+
|
|
|
+ sysfs_attr_init(&kbdbl_handle->timeout_attr.attr);
|
|
|
+ kbdbl_handle->timeout_attr.attr.name = "kbd_backlight_timeout";
|
|
|
+ kbdbl_handle->timeout_attr.attr.mode = S_IRUGO | S_IWUSR;
|
|
|
+ kbdbl_handle->timeout_attr.show = sony_nc_kbd_backlight_timeout_show;
|
|
|
+ kbdbl_handle->timeout_attr.store = sony_nc_kbd_backlight_timeout_store;
|
|
|
+
|
|
|
+ if (device_create_file(&pd->dev, &kbdbl_handle->mode_attr))
|
|
|
+ goto outkzalloc;
|
|
|
+
|
|
|
+ if (device_create_file(&pd->dev, &kbdbl_handle->timeout_attr))
|
|
|
+ goto outmode;
|
|
|
+
|
|
|
+ __sony_nc_kbd_backlight_mode_set(kbd_backlight);
|
|
|
+ __sony_nc_kbd_backlight_timeout_set(kbd_backlight_timeout);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+outmode:
|
|
|
+ device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
|
|
|
+outkzalloc:
|
|
|
+ kfree(kbdbl_handle);
|
|
|
+ kbdbl_handle = NULL;
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
|
|
|
+{
|
|
|
+ if (kbdbl_handle) {
|
|
|
+ device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
|
|
|
+ device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr);
|
|
|
+ kfree(kbdbl_handle);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int sony_nc_add(struct acpi_device *device)
|
|
|
{
|
|
|
acpi_status status;
|
|
@@ -1359,6 +1527,8 @@ static int sony_nc_add(struct acpi_device *device)
|
|
|
dprintk("Doing SNC setup\n");
|
|
|
if (sony_nc_handles_setup(sony_pf_device))
|
|
|
goto outpresent;
|
|
|
+ if (sony_nc_kbd_backlight_setup(sony_pf_device))
|
|
|
+ goto outsnc;
|
|
|
sony_nc_function_setup(device);
|
|
|
sony_nc_rfkill_setup(device);
|
|
|
}
|
|
@@ -1367,7 +1537,7 @@ static int sony_nc_add(struct acpi_device *device)
|
|
|
result = sony_laptop_setup_input(device);
|
|
|
if (result) {
|
|
|
pr_err(DRV_PFX "Unable to create input devices.\n");
|
|
|
- goto outsnc;
|
|
|
+ goto outkbdbacklight;
|
|
|
}
|
|
|
|
|
|
if (acpi_video_backlight_support()) {
|
|
@@ -1445,6 +1615,9 @@ static int sony_nc_add(struct acpi_device *device)
|
|
|
|
|
|
sony_laptop_remove_input();
|
|
|
|
|
|
+ outkbdbacklight:
|
|
|
+ sony_nc_kbd_backlight_cleanup(sony_pf_device);
|
|
|
+
|
|
|
outsnc:
|
|
|
sony_nc_handles_cleanup(sony_pf_device);
|
|
|
|
|
@@ -1469,6 +1642,7 @@ static int sony_nc_remove(struct acpi_device *device, int type)
|
|
|
device_remove_file(&sony_pf_device->dev, &item->devattr);
|
|
|
}
|
|
|
|
|
|
+ sony_nc_kbd_backlight_cleanup(sony_pf_device);
|
|
|
sony_nc_handles_cleanup(sony_pf_device);
|
|
|
sony_pf_remove();
|
|
|
sony_laptop_remove_input();
|