sony-laptop: new keyboard backlight handle
Add support for handle 0x0143 (Vaio SA/SB/SC, CA/CB) and rework the code to be hable to support different handles for the keyboard backlight function. [malattia@linux.it: group function specific variables in a struct] Signed-off-by: Marco Chiappero <marco@absence.it> Signed-off-by: Mattia Dongili <malattia@linux.it> Signed-off-by: Matthew Garrett <mjg@redhat.com>
This commit is contained in:
parent
88bf170646
commit
aa33924f35
1 changed files with 87 additions and 62 deletions
|
@ -141,8 +141,9 @@ MODULE_PARM_DESC(kbd_backlight_timeout,
|
|||
"(default: 0)");
|
||||
|
||||
static void sony_nc_kbd_backlight_resume(void);
|
||||
static void sony_nc_kbd_backlight_setup(struct platform_device *pd);
|
||||
static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd);
|
||||
static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
|
||||
unsigned int handle);
|
||||
static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd);
|
||||
|
||||
static int sony_nc_battery_care_setup(struct platform_device *pd,
|
||||
unsigned int handle);
|
||||
|
@ -1315,7 +1316,11 @@ static void sony_nc_function_setup(struct acpi_device *device,
|
|||
sony_nc_rfkill_setup(device);
|
||||
break;
|
||||
case 0x0137:
|
||||
sony_nc_kbd_backlight_setup(pf_device);
|
||||
case 0x0143:
|
||||
result = sony_nc_kbd_backlight_setup(pf_device, handle);
|
||||
if (result)
|
||||
pr_err("couldn't set up keyboard backlight function (%d)\n",
|
||||
result);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
|
@ -1365,6 +1370,7 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
|
|||
sony_nc_rfkill_cleanup();
|
||||
break;
|
||||
case 0x0137:
|
||||
case 0x0143:
|
||||
sony_nc_kbd_backlight_cleanup(pd);
|
||||
break;
|
||||
default:
|
||||
|
@ -1407,6 +1413,7 @@ static void sony_nc_function_resume(void)
|
|||
sony_nc_rfkill_update();
|
||||
break;
|
||||
case 0x0137:
|
||||
case 0x0143:
|
||||
sony_nc_kbd_backlight_resume();
|
||||
break;
|
||||
default:
|
||||
|
@ -1618,20 +1625,16 @@ static void sony_nc_rfkill_setup(struct acpi_device *device)
|
|||
}
|
||||
|
||||
/* Keyboard backlight feature */
|
||||
#define KBDBL_HANDLER 0x137
|
||||
#define KBDBL_PRESENT 0xB00
|
||||
#define SET_MODE 0xC00
|
||||
#define SET_STATE 0xD00
|
||||
#define SET_TIMEOUT 0xE00
|
||||
|
||||
struct kbd_backlight {
|
||||
int mode;
|
||||
int timeout;
|
||||
unsigned int handle;
|
||||
unsigned int base;
|
||||
unsigned int mode;
|
||||
unsigned int timeout;
|
||||
struct device_attribute mode_attr;
|
||||
struct device_attribute timeout_attr;
|
||||
};
|
||||
|
||||
static struct kbd_backlight *kbdbl_handle;
|
||||
static struct kbd_backlight *kbdbl_ctl;
|
||||
|
||||
static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value)
|
||||
{
|
||||
|
@ -1640,15 +1643,15 @@ static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value)
|
|||
if (value > 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (sony_call_snc_handle(KBDBL_HANDLER,
|
||||
(value << 0x10) | SET_MODE, &result))
|
||||
if (sony_call_snc_handle(kbdbl_ctl->handle,
|
||||
(value << 0x10) | (kbdbl_ctl->base), &result))
|
||||
return -EIO;
|
||||
|
||||
/* Try to turn the light on/off immediately */
|
||||
sony_call_snc_handle(KBDBL_HANDLER, (value << 0x10) | SET_STATE,
|
||||
&result);
|
||||
sony_call_snc_handle(kbdbl_ctl->handle,
|
||||
(value << 0x10) | (kbdbl_ctl->base + 0x100), &result);
|
||||
|
||||
kbdbl_handle->mode = value;
|
||||
kbdbl_ctl->mode = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1677,7 +1680,7 @@ 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);
|
||||
count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_ctl->mode);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -1688,11 +1691,11 @@ static int __sony_nc_kbd_backlight_timeout_set(u8 value)
|
|||
if (value > 3)
|
||||
return -EINVAL;
|
||||
|
||||
if (sony_call_snc_handle(KBDBL_HANDLER,
|
||||
(value << 0x10) | SET_TIMEOUT, &result))
|
||||
if (sony_call_snc_handle(kbdbl_ctl->handle, (value << 0x10) |
|
||||
(kbdbl_ctl->base + 0x200), &result))
|
||||
return -EIO;
|
||||
|
||||
kbdbl_handle->timeout = value;
|
||||
kbdbl_ctl->timeout = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1721,85 +1724,107 @@ 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);
|
||||
count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_ctl->timeout);
|
||||
return count;
|
||||
}
|
||||
|
||||
static void sony_nc_kbd_backlight_setup(struct platform_device *pd)
|
||||
static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
|
||||
unsigned int handle)
|
||||
{
|
||||
int result;
|
||||
int ret = 0;
|
||||
|
||||
if (sony_call_snc_handle(KBDBL_HANDLER, KBDBL_PRESENT, &result))
|
||||
return;
|
||||
if (!(result & 0x02))
|
||||
return;
|
||||
/* verify the kbd backlight presence, these handles are not used for
|
||||
* keyboard backlight only
|
||||
*/
|
||||
ret = sony_call_snc_handle(handle, handle == 0x0137 ? 0x0B00 : 0x0100,
|
||||
&result);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL);
|
||||
if (!kbdbl_handle)
|
||||
return;
|
||||
if ((handle == 0x0137 && !(result & 0x02)) ||
|
||||
!(result & 0x01)) {
|
||||
dprintk("no backlight keyboard found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
kbdbl_ctl = kzalloc(sizeof(*kbdbl_ctl), GFP_KERNEL);
|
||||
if (!kbdbl_ctl)
|
||||
return -ENOMEM;
|
||||
|
||||
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;
|
||||
kbdbl_ctl->handle = handle;
|
||||
if (handle == 0x0137)
|
||||
kbdbl_ctl->base = 0x0C00;
|
||||
else
|
||||
kbdbl_ctl->base = 0x4000;
|
||||
|
||||
if (device_create_file(&pd->dev, &kbdbl_handle->mode_attr))
|
||||
sysfs_attr_init(&kbdbl_ctl->mode_attr.attr);
|
||||
kbdbl_ctl->mode_attr.attr.name = "kbd_backlight";
|
||||
kbdbl_ctl->mode_attr.attr.mode = S_IRUGO | S_IWUSR;
|
||||
kbdbl_ctl->mode_attr.show = sony_nc_kbd_backlight_mode_show;
|
||||
kbdbl_ctl->mode_attr.store = sony_nc_kbd_backlight_mode_store;
|
||||
|
||||
sysfs_attr_init(&kbdbl_ctl->timeout_attr.attr);
|
||||
kbdbl_ctl->timeout_attr.attr.name = "kbd_backlight_timeout";
|
||||
kbdbl_ctl->timeout_attr.attr.mode = S_IRUGO | S_IWUSR;
|
||||
kbdbl_ctl->timeout_attr.show = sony_nc_kbd_backlight_timeout_show;
|
||||
kbdbl_ctl->timeout_attr.store = sony_nc_kbd_backlight_timeout_store;
|
||||
|
||||
ret = device_create_file(&pd->dev, &kbdbl_ctl->mode_attr);
|
||||
if (ret)
|
||||
goto outkzalloc;
|
||||
|
||||
if (device_create_file(&pd->dev, &kbdbl_handle->timeout_attr))
|
||||
ret = device_create_file(&pd->dev, &kbdbl_ctl->timeout_attr);
|
||||
if (ret)
|
||||
goto outmode;
|
||||
|
||||
__sony_nc_kbd_backlight_mode_set(kbd_backlight);
|
||||
__sony_nc_kbd_backlight_timeout_set(kbd_backlight_timeout);
|
||||
|
||||
return;
|
||||
return 0;
|
||||
|
||||
outmode:
|
||||
device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
|
||||
device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr);
|
||||
outkzalloc:
|
||||
kfree(kbdbl_handle);
|
||||
kbdbl_handle = NULL;
|
||||
return;
|
||||
kfree(kbdbl_ctl);
|
||||
kbdbl_ctl = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
|
||||
static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
|
||||
{
|
||||
if (kbdbl_handle) {
|
||||
if (kbdbl_ctl) {
|
||||
int result;
|
||||
|
||||
device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
|
||||
device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr);
|
||||
device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr);
|
||||
device_remove_file(&pd->dev, &kbdbl_ctl->timeout_attr);
|
||||
|
||||
/* restore the default hw behaviour */
|
||||
sony_call_snc_handle(KBDBL_HANDLER, 0x1000 | SET_MODE, &result);
|
||||
sony_call_snc_handle(KBDBL_HANDLER, SET_TIMEOUT, &result);
|
||||
sony_call_snc_handle(kbdbl_ctl->handle,
|
||||
kbdbl_ctl->base | 0x10000, &result);
|
||||
sony_call_snc_handle(kbdbl_ctl->handle,
|
||||
kbdbl_ctl->base + 0x200, &result);
|
||||
|
||||
kfree(kbdbl_handle);
|
||||
kfree(kbdbl_ctl);
|
||||
kbdbl_ctl = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sony_nc_kbd_backlight_resume(void)
|
||||
{
|
||||
int ignore = 0;
|
||||
|
||||
if (!kbdbl_handle)
|
||||
if (!kbdbl_ctl)
|
||||
return;
|
||||
|
||||
if (kbdbl_handle->mode == 0)
|
||||
sony_call_snc_handle(KBDBL_HANDLER, SET_MODE, &ignore);
|
||||
|
||||
if (kbdbl_handle->timeout != 0)
|
||||
sony_call_snc_handle(KBDBL_HANDLER,
|
||||
(kbdbl_handle->timeout << 0x10) | SET_TIMEOUT,
|
||||
if (kbdbl_ctl->mode == 0)
|
||||
sony_call_snc_handle(kbdbl_ctl->handle, kbdbl_ctl->base,
|
||||
&ignore);
|
||||
|
||||
if (kbdbl_ctl->timeout != 0)
|
||||
sony_call_snc_handle(kbdbl_ctl->handle,
|
||||
(kbdbl_ctl->base + 0x200) |
|
||||
(kbdbl_ctl->timeout << 0x10), &ignore);
|
||||
}
|
||||
|
||||
struct battery_care_control {
|
||||
|
|
Loading…
Reference in a new issue