summaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86/sony-laptop.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/x86/sony-laptop.c')
-rw-r--r--drivers/platform/x86/sony-laptop.c629
1 files changed, 525 insertions, 104 deletions
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 5e83370b0812..6fe8cd6e23b5 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -71,8 +71,9 @@
#endif
#define DRV_PFX "sony-laptop: "
-#define dprintk(msg...) do { \
- if (debug) printk(KERN_WARNING DRV_PFX msg); \
+#define dprintk(msg...) do { \
+ if (debug) \
+ pr_warn(DRV_PFX msg); \
} while (0)
#define SONY_LAPTOP_DRIVER_VERSION "0.6"
@@ -124,6 +125,21 @@ 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)");
+
+static void sony_nc_kbd_backlight_resume(void);
+
enum sony_nc_rfkill {
SONY_WIFI,
SONY_BLUETOOTH,
@@ -402,7 +418,7 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)
error = kfifo_alloc(&sony_laptop_input.fifo,
SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
if (error) {
- printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
+ pr_err(DRV_PFX "kfifo_alloc failed\n");
goto err_dec_users;
}
@@ -591,7 +607,7 @@ struct sony_nc_value {
int value; /* current setting */
int valid; /* Has ever been set */
int debug; /* active only in debug mode ? */
- struct device_attribute devattr; /* sysfs atribute */
+ struct device_attribute devattr; /* sysfs attribute */
};
#define SNC_HANDLE_NAMES(_name, _values...) \
@@ -686,7 +702,7 @@ static int acpi_callgetfunc(acpi_handle handle, char *name, int *result)
return 0;
}
- printk(KERN_WARNING DRV_PFX "acpi_callreadfunc failed\n");
+ pr_warn(DRV_PFX "acpi_callreadfunc failed\n");
return -1;
}
@@ -712,7 +728,7 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
if (status == AE_OK) {
if (result != NULL) {
if (out_obj.type != ACPI_TYPE_INTEGER) {
- printk(KERN_WARNING DRV_PFX "acpi_evaluate_object bad "
+ pr_warn(DRV_PFX "acpi_evaluate_object bad "
"return type\n");
return -1;
}
@@ -721,34 +737,111 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
return 0;
}
- printk(KERN_WARNING DRV_PFX "acpi_evaluate_object failed\n");
+ pr_warn(DRV_PFX "acpi_evaluate_object failed\n");
return -1;
}
-static int sony_find_snc_handle(int handle)
+struct sony_nc_handles {
+ u16 cap[0x10];
+ struct device_attribute devattr;
+};
+
+static struct sony_nc_handles *handles;
+
+static ssize_t sony_nc_handles_show(struct device *dev,
+ struct device_attribute *attr, char *buffer)
+{
+ ssize_t len = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
+ len += snprintf(buffer + len, PAGE_SIZE - len, "0x%.4x ",
+ handles->cap[i]);
+ }
+ len += snprintf(buffer + len, PAGE_SIZE - len, "\n");
+
+ return len;
+}
+
+static int sony_nc_handles_setup(struct platform_device *pd)
{
int i;
int result;
- for (i = 0x20; i < 0x30; i++) {
- acpi_callsetfunc(sony_nc_acpi_handle, "SN00", i, &result);
- if (result == handle)
- return i-0x20;
+ handles = kzalloc(sizeof(*handles), GFP_KERNEL);
+ if (!handles)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
+ if (!acpi_callsetfunc(sony_nc_acpi_handle,
+ "SN00", i + 0x20, &result)) {
+ dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n",
+ result, i);
+ handles->cap[i] = result;
+ }
+ }
+
+ if (debug) {
+ sysfs_attr_init(&handles->devattr.attr);
+ handles->devattr.attr.name = "handles";
+ handles->devattr.attr.mode = S_IRUGO;
+ handles->devattr.show = sony_nc_handles_show;
+
+ /* allow reading capabilities via sysfs */
+ if (device_create_file(&pd->dev, &handles->devattr)) {
+ kfree(handles);
+ handles = NULL;
+ return -1;
+ }
}
+ return 0;
+}
+
+static int sony_nc_handles_cleanup(struct platform_device *pd)
+{
+ if (handles) {
+ if (debug)
+ device_remove_file(&pd->dev, &handles->devattr);
+ kfree(handles);
+ handles = NULL;
+ }
+ return 0;
+}
+
+static int sony_find_snc_handle(int handle)
+{
+ int i;
+
+ /* not initialized yet, return early */
+ if (!handles)
+ return -1;
+
+ for (i = 0; i < 0x10; i++) {
+ if (handles->cap[i] == handle) {
+ dprintk("found handle 0x%.4x (offset: 0x%.2x)\n",
+ handle, i);
+ return i;
+ }
+ }
+ dprintk("handle 0x%.4x not found\n", handle);
return -1;
}
static int sony_call_snc_handle(int handle, int argument, int *result)
{
+ int ret = 0;
int offset = sony_find_snc_handle(handle);
if (offset < 0)
return -1;
- return acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument,
- result);
+ ret = acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument,
+ result);
+ dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", offset | argument,
+ *result);
+ return ret;
}
/*
@@ -841,6 +934,14 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
/*
* Backlight device
*/
+struct sony_backlight_props {
+ struct backlight_device *dev;
+ int handle;
+ u8 offset;
+ u8 maxlvl;
+};
+struct sony_backlight_props sony_bl_props;
+
static int sony_backlight_update_status(struct backlight_device *bd)
{
return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT",
@@ -857,11 +958,42 @@ static int sony_backlight_get_brightness(struct backlight_device *bd)
return value - 1;
}
-static struct backlight_device *sony_backlight_device;
+static int sony_nc_get_brightness_ng(struct backlight_device *bd)
+{
+ int result;
+ int *handle = (int *)bl_get_data(bd);
+ struct sony_backlight_props *sdev =
+ (struct sony_backlight_props *)bl_get_data(bd);
+
+ sony_call_snc_handle(sdev->handle, 0x0200, &result);
+
+ return (result & 0xff) - sdev->offset;
+}
+
+static int sony_nc_update_status_ng(struct backlight_device *bd)
+{
+ int value, result;
+ int *handle = (int *)bl_get_data(bd);
+ struct sony_backlight_props *sdev =
+ (struct sony_backlight_props *)bl_get_data(bd);
+
+ value = bd->props.brightness + sdev->offset;
+ if (sony_call_snc_handle(sdev->handle, 0x0100 | (value << 16), &result))
+ return -EIO;
+
+ return value;
+}
+
static const struct backlight_ops sony_backlight_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
.update_status = sony_backlight_update_status,
.get_brightness = sony_backlight_get_brightness,
};
+static const struct backlight_ops sony_backlight_ng_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
+ .update_status = sony_nc_update_status_ng,
+ .get_brightness = sony_nc_get_brightness_ng,
+};
/*
* New SNC-only Vaios event mapping to driver known keys
@@ -972,7 +1104,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
}
if (!key_event->data)
- printk(KERN_INFO DRV_PFX
+ pr_info(DRV_PFX
"Unknown event: 0x%x 0x%x\n",
key_handle,
ev);
@@ -996,7 +1128,7 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
struct acpi_device_info *info;
if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) {
- printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n",
+ pr_warn(DRV_PFX "method: name: %4.4s, args %X\n",
(char *)&info->name, info->param_count);
kfree(info);
@@ -1037,7 +1169,7 @@ static int sony_nc_resume(struct acpi_device *device)
ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset,
item->value, NULL);
if (ret < 0) {
- printk("%s: %d\n", __func__, ret);
+ pr_err(DRV_PFX "%s: %d\n", __func__, ret);
break;
}
}
@@ -1054,14 +1186,12 @@ static int sony_nc_resume(struct acpi_device *device)
sony_nc_function_setup(device);
}
- /* set the last requested brightness level */
- if (sony_backlight_device &&
- sony_backlight_update_status(sony_backlight_device) < 0)
- printk(KERN_WARNING DRV_PFX "unable to restore brightness level\n");
-
/* re-read rfkill state */
sony_nc_rfkill_update();
+ /* restore kbd backlight states */
+ sony_nc_kbd_backlight_resume();
+
return 0;
}
@@ -1206,12 +1336,12 @@ static void sony_nc_rfkill_setup(struct acpi_device *device)
device_enum = (union acpi_object *) buffer.pointer;
if (!device_enum) {
- pr_err("Invalid SN06 return object\n");
+ pr_err(DRV_PFX "No SN06 return object.");
goto out_no_enum;
}
if (device_enum->type != ACPI_TYPE_BUFFER) {
- pr_err("Invalid SN06 return object type 0x%.2x\n",
- device_enum->type);
+ pr_err(DRV_PFX "Invalid SN06 return object 0x%.2x\n",
+ device_enum->type);
goto out_no_enum;
}
@@ -1245,6 +1375,306 @@ out_no_enum:
return;
}
+/* 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;
+ struct device_attribute mode_attr;
+ struct device_attribute timeout_attr;
+};
+
+static 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;
+
+ /* Try to turn the light on/off immediately */
+ sony_call_snc_handle(KBDBL_HANDLER, (value << 0x10) | SET_STATE,
+ &result);
+
+ 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(KBDBL_HANDLER, KBDBL_PRESENT, &result))
+ return 0;
+ if (!(result & 0x02))
+ return 0;
+
+ kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL);
+ if (!kbdbl_handle)
+ return -ENOMEM;
+
+ 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) {
+ int result;
+
+ device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
+ device_remove_file(&pd->dev, &kbdbl_handle->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);
+
+ kfree(kbdbl_handle);
+ }
+ return 0;
+}
+
+static void sony_nc_kbd_backlight_resume(void)
+{
+ int ignore = 0;
+
+ if (!kbdbl_handle)
+ 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,
+ &ignore);
+}
+
+static void sony_nc_backlight_ng_read_limits(int handle,
+ struct sony_backlight_props *props)
+{
+ int offset;
+ acpi_status status;
+ u8 brlvl, i;
+ u8 min = 0xff, max = 0x00;
+ struct acpi_object_list params;
+ union acpi_object in_obj;
+ union acpi_object *lvl_enum;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+
+ props->handle = handle;
+ props->offset = 0;
+ props->maxlvl = 0xff;
+
+ offset = sony_find_snc_handle(handle);
+ if (offset < 0)
+ return;
+
+ /* try to read the boundaries from ACPI tables, if we fail the above
+ * defaults should be reasonable
+ */
+ params.count = 1;
+ params.pointer = &in_obj;
+ in_obj.type = ACPI_TYPE_INTEGER;
+ in_obj.integer.value = offset;
+ status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", &params,
+ &buffer);
+ if (ACPI_FAILURE(status))
+ return;
+
+ lvl_enum = (union acpi_object *) buffer.pointer;
+ if (!lvl_enum) {
+ pr_err("No SN06 return object.");
+ return;
+ }
+ if (lvl_enum->type != ACPI_TYPE_BUFFER) {
+ pr_err("Invalid SN06 return object 0x%.2x\n",
+ lvl_enum->type);
+ goto out_invalid;
+ }
+
+ /* the buffer lists brightness levels available, brightness levels are
+ * from 0 to 8 in the array, other values are used by ALS control.
+ */
+ for (i = 0; i < 9 && i < lvl_enum->buffer.length; i++) {
+
+ brlvl = *(lvl_enum->buffer.pointer + i);
+ dprintk("Brightness level: %d\n", brlvl);
+
+ if (!brlvl)
+ break;
+
+ if (brlvl > max)
+ max = brlvl;
+ if (brlvl < min)
+ min = brlvl;
+ }
+ props->offset = min;
+ props->maxlvl = max;
+ dprintk("Brightness levels: min=%d max=%d\n", props->offset,
+ props->maxlvl);
+
+out_invalid:
+ kfree(buffer.pointer);
+ return;
+}
+
+static void sony_nc_backlight_setup(void)
+{
+ acpi_handle unused;
+ int max_brightness = 0;
+ const struct backlight_ops *ops = NULL;
+ struct backlight_properties props;
+
+ if (sony_find_snc_handle(0x12f) != -1) {
+ ops = &sony_backlight_ng_ops;
+ sony_nc_backlight_ng_read_limits(0x12f, &sony_bl_props);
+ max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
+
+ } else if (sony_find_snc_handle(0x137) != -1) {
+ ops = &sony_backlight_ng_ops;
+ sony_nc_backlight_ng_read_limits(0x137, &sony_bl_props);
+ max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
+
+ } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
+ &unused))) {
+ ops = &sony_backlight_ops;
+ max_brightness = SONY_MAX_BRIGHTNESS - 1;
+
+ } else
+ return;
+
+ memset(&props, 0, sizeof(struct backlight_properties));
+ props.type = BACKLIGHT_PLATFORM;
+ props.max_brightness = max_brightness;
+ sony_bl_props.dev = backlight_device_register("sony", NULL,
+ &sony_bl_props,
+ ops, &props);
+
+ if (IS_ERR(sony_bl_props.dev)) {
+ pr_warn(DRV_PFX "unable to register backlight device\n");
+ sony_bl_props.dev = NULL;
+ } else
+ sony_bl_props.dev->props.brightness =
+ ops->get_brightness(sony_bl_props.dev);
+}
+
+static void sony_nc_backlight_cleanup(void)
+{
+ if (sony_bl_props.dev)
+ backlight_device_unregister(sony_bl_props.dev);
+}
+
static int sony_nc_add(struct acpi_device *device)
{
acpi_status status;
@@ -1252,8 +1682,8 @@ static int sony_nc_add(struct acpi_device *device)
acpi_handle handle;
struct sony_nc_value *item;
- printk(KERN_INFO DRV_PFX "%s v%s.\n",
- SONY_NC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
+ pr_info(DRV_PFX "%s v%s.\n", SONY_NC_DRIVER_NAME,
+ SONY_LAPTOP_DRIVER_VERSION);
sony_nc_acpi_device = device;
strcpy(acpi_device_class(device), "sony/hotkey");
@@ -1269,13 +1699,18 @@ static int sony_nc_add(struct acpi_device *device)
goto outwalk;
}
+ result = sony_pf_add();
+ if (result)
+ goto outpresent;
+
if (debug) {
- status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle,
- 1, sony_walk_callback, NULL, NULL, NULL);
+ status = acpi_walk_namespace(ACPI_TYPE_METHOD,
+ sony_nc_acpi_handle, 1, sony_walk_callback,
+ NULL, NULL, NULL);
if (ACPI_FAILURE(status)) {
- printk(KERN_WARNING DRV_PFX "unable to walk acpi resources\n");
+ pr_warn(DRV_PFX "unable to walk acpi resources\n");
result = -ENODEV;
- goto outwalk;
+ goto outpresent;
}
}
@@ -1288,6 +1723,12 @@ static int sony_nc_add(struct acpi_device *device)
if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00",
&handle))) {
dprintk("Doing SNC setup\n");
+ result = sony_nc_handles_setup(sony_pf_device);
+ if (result)
+ goto outpresent;
+ result = sony_nc_kbd_backlight_setup(sony_pf_device);
+ if (result)
+ goto outsnc;
sony_nc_function_setup(device);
sony_nc_rfkill_setup(device);
}
@@ -1295,39 +1736,17 @@ static int sony_nc_add(struct acpi_device *device)
/* setup input devices and helper fifo */
result = sony_laptop_setup_input(device);
if (result) {
- printk(KERN_ERR DRV_PFX
- "Unable to create input devices.\n");
- goto outwalk;
+ pr_err(DRV_PFX "Unable to create input devices.\n");
+ goto outkbdbacklight;
}
if (acpi_video_backlight_support()) {
- printk(KERN_INFO DRV_PFX "brightness ignored, must be "
+ pr_info(DRV_PFX "brightness ignored, must be "
"controlled by ACPI video driver\n");
- } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
- &handle))) {
- struct backlight_properties props;
- memset(&props, 0, sizeof(struct backlight_properties));
- props.max_brightness = SONY_MAX_BRIGHTNESS - 1;
- sony_backlight_device = backlight_device_register("sony", NULL,
- NULL,
- &sony_backlight_ops,
- &props);
-
- if (IS_ERR(sony_backlight_device)) {
- printk(KERN_WARNING DRV_PFX "unable to register backlight device\n");
- sony_backlight_device = NULL;
- } else {
- sony_backlight_device->props.brightness =
- sony_backlight_get_brightness
- (sony_backlight_device);
- }
-
+ } else {
+ sony_nc_backlight_setup();
}
- result = sony_pf_add();
- if (result)
- goto outbacklight;
-
/* create sony_pf sysfs attributes related to the SNC device */
for (item = sony_nc_values; item->name; ++item) {
@@ -1373,14 +1792,19 @@ static int sony_nc_add(struct acpi_device *device)
for (item = sony_nc_values; item->name; ++item) {
device_remove_file(&sony_pf_device->dev, &item->devattr);
}
- sony_pf_remove();
-
- outbacklight:
- if (sony_backlight_device)
- backlight_device_unregister(sony_backlight_device);
+ sony_nc_backlight_cleanup();
sony_laptop_remove_input();
+ outkbdbacklight:
+ sony_nc_kbd_backlight_cleanup(sony_pf_device);
+
+ outsnc:
+ sony_nc_handles_cleanup(sony_pf_device);
+
+ outpresent:
+ sony_pf_remove();
+
outwalk:
sony_nc_rfkill_cleanup();
return result;
@@ -1390,8 +1814,7 @@ static int sony_nc_remove(struct acpi_device *device, int type)
{
struct sony_nc_value *item;
- if (sony_backlight_device)
- backlight_device_unregister(sony_backlight_device);
+ sony_nc_backlight_cleanup();
sony_nc_acpi_device = NULL;
@@ -1399,6 +1822,8 @@ 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();
sony_nc_rfkill_cleanup();
@@ -1437,7 +1862,6 @@ static struct acpi_driver sony_nc_driver = {
#define SONYPI_DEVICE_TYPE1 0x00000001
#define SONYPI_DEVICE_TYPE2 0x00000002
#define SONYPI_DEVICE_TYPE3 0x00000004
-#define SONYPI_DEVICE_TYPE4 0x00000008
#define SONYPI_TYPE1_OFFSET 0x04
#define SONYPI_TYPE2_OFFSET 0x12
@@ -1583,8 +2007,8 @@ static struct sonypi_event sonypi_blueev[] = {
/* The set of possible wireless events */
static struct sonypi_event sonypi_wlessev[] = {
- { 0x59, SONYPI_EVENT_WIRELESS_ON },
- { 0x5a, SONYPI_EVENT_WIRELESS_OFF },
+ { 0x59, SONYPI_EVENT_IGNORE },
+ { 0x5a, SONYPI_EVENT_IGNORE },
{ 0, 0 }
};
@@ -1841,7 +2265,7 @@ out:
if (pcidev)
pci_dev_put(pcidev);
- printk(KERN_INFO DRV_PFX "detected Type%d model\n",
+ pr_info(DRV_PFX "detected Type%d model\n",
dev->model == SONYPI_DEVICE_TYPE1 ? 1 :
dev->model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
}
@@ -1889,7 +2313,7 @@ static int __sony_pic_camera_ready(void)
static int __sony_pic_camera_off(void)
{
if (!camera) {
- printk(KERN_WARNING DRV_PFX "camera control not enabled\n");
+ pr_warn(DRV_PFX "camera control not enabled\n");
return -ENODEV;
}
@@ -1909,7 +2333,7 @@ static int __sony_pic_camera_on(void)
int i, j, x;
if (!camera) {
- printk(KERN_WARNING DRV_PFX "camera control not enabled\n");
+ pr_warn(DRV_PFX "camera control not enabled\n");
return -ENODEV;
}
@@ -1932,7 +2356,7 @@ static int __sony_pic_camera_on(void)
}
if (j == 0) {
- printk(KERN_WARNING DRV_PFX "failed to power on camera\n");
+ pr_warn(DRV_PFX "failed to power on camera\n");
return -ENODEV;
}
@@ -1988,7 +2412,7 @@ int sony_pic_camera_command(int command, u8 value)
ITERATIONS_SHORT);
break;
default:
- printk(KERN_ERR DRV_PFX "sony_pic_camera_command invalid: %d\n",
+ pr_err(DRV_PFX "sony_pic_camera_command invalid: %d\n",
command);
break;
}
@@ -2246,7 +2670,7 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd,
mutex_lock(&spic_dev.lock);
switch (cmd) {
case SONYPI_IOCGBRT:
- if (sony_backlight_device == NULL) {
+ if (sony_bl_props.dev == NULL) {
ret = -EIO;
break;
}
@@ -2259,7 +2683,7 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd,
ret = -EFAULT;
break;
case SONYPI_IOCSBRT:
- if (sony_backlight_device == NULL) {
+ if (sony_bl_props.dev == NULL) {
ret = -EIO;
break;
}
@@ -2273,8 +2697,8 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd,
break;
}
/* sync the backlight device status */
- sony_backlight_device->props.brightness =
- sony_backlight_get_brightness(sony_backlight_device);
+ sony_bl_props.dev->props.brightness =
+ sony_backlight_get_brightness(sony_bl_props.dev);
break;
case SONYPI_IOCGBAT1CAP:
if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
@@ -2395,7 +2819,7 @@ static int sonypi_compat_init(void)
error =
kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
if (error) {
- printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
+ pr_err(DRV_PFX "kfifo_alloc failed\n");
return error;
}
@@ -2405,11 +2829,11 @@ static int sonypi_compat_init(void)
sonypi_misc_device.minor = minor;
error = misc_register(&sonypi_misc_device);
if (error) {
- printk(KERN_ERR DRV_PFX "misc_register failed\n");
+ pr_err(DRV_PFX "misc_register failed\n");
goto err_free_kfifo;
}
if (minor == -1)
- printk(KERN_INFO DRV_PFX "device allocated minor is %d\n",
+ pr_info(DRV_PFX "device allocated minor is %d\n",
sonypi_misc_device.minor);
return 0;
@@ -2469,8 +2893,7 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
}
for (i = 0; i < p->interrupt_count; i++) {
if (!p->interrupts[i]) {
- printk(KERN_WARNING DRV_PFX
- "Invalid IRQ %d\n",
+ pr_warn(DRV_PFX "Invalid IRQ %d\n",
p->interrupts[i]);
continue;
}
@@ -2509,7 +2932,7 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
ioport->io2.address_length);
}
else {
- printk(KERN_ERR DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n");
+ pr_err(DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n");
return AE_ERROR;
}
return AE_OK;
@@ -2537,7 +2960,7 @@ static int sony_pic_possible_resources(struct acpi_device *device)
dprintk("Evaluating _STA\n");
result = acpi_bus_get_status(device);
if (result) {
- printk(KERN_WARNING DRV_PFX "Unable to read status\n");
+ pr_warn(DRV_PFX "Unable to read status\n");
goto end;
}
@@ -2553,8 +2976,7 @@ static int sony_pic_possible_resources(struct acpi_device *device)
status = acpi_walk_resources(device->handle, METHOD_NAME__PRS,
sony_pic_read_possible_resource, &spic_dev);
if (ACPI_FAILURE(status)) {
- printk(KERN_WARNING DRV_PFX
- "Failure evaluating %s\n",
+ pr_warn(DRV_PFX "Failure evaluating %s\n",
METHOD_NAME__PRS);
result = -ENODEV;
}
@@ -2668,7 +3090,7 @@ static int sony_pic_enable(struct acpi_device *device,
/* check for total failure */
if (ACPI_FAILURE(status)) {
- printk(KERN_ERR DRV_PFX "Error evaluating _SRS\n");
+ pr_err(DRV_PFX "Error evaluating _SRS\n");
result = -ENODEV;
goto end;
}
@@ -2724,6 +3146,9 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id)
if (ev == dev->event_types[i].events[j].data) {
device_event =
dev->event_types[i].events[j].event;
+ /* some events may require ignoring */
+ if (!device_event)
+ return IRQ_HANDLED;
goto found;
}
}
@@ -2743,7 +3168,6 @@ found:
sony_laptop_report_input_event(device_event);
acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event);
sonypi_compat_report_event(device_event);
-
return IRQ_HANDLED;
}
@@ -2758,7 +3182,7 @@ static int sony_pic_remove(struct acpi_device *device, int type)
struct sony_pic_irq *irq, *tmp_irq;
if (sony_pic_disable(device)) {
- printk(KERN_ERR DRV_PFX "Couldn't disable device.\n");
+ pr_err(DRV_PFX "Couldn't disable device.\n");
return -ENXIO;
}
@@ -2798,8 +3222,8 @@ static int sony_pic_add(struct acpi_device *device)
struct sony_pic_ioport *io, *tmp_io;
struct sony_pic_irq *irq, *tmp_irq;
- printk(KERN_INFO DRV_PFX "%s v%s.\n",
- SONY_PIC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
+ pr_info(DRV_PFX "%s v%s.\n", SONY_PIC_DRIVER_NAME,
+ SONY_LAPTOP_DRIVER_VERSION);
spic_dev.acpi_dev = device;
strcpy(acpi_device_class(device), "sony/hotkey");
@@ -2809,16 +3233,14 @@ static int sony_pic_add(struct acpi_device *device)
/* read _PRS resources */
result = sony_pic_possible_resources(device);
if (result) {
- printk(KERN_ERR DRV_PFX
- "Unable to read possible resources.\n");
+ pr_err(DRV_PFX "Unable to read possible resources.\n");
goto err_free_resources;
}
/* setup input devices and helper fifo */
result = sony_laptop_setup_input(device);
if (result) {
- printk(KERN_ERR DRV_PFX
- "Unable to create input devices.\n");
+ pr_err(DRV_PFX "Unable to create input devices.\n");
goto err_free_resources;
}
@@ -2828,7 +3250,7 @@ static int sony_pic_add(struct acpi_device *device)
/* request io port */
list_for_each_entry_reverse(io, &spic_dev.ioports, list) {
if (request_region(io->io1.minimum, io->io1.address_length,
- "Sony Programable I/O Device")) {
+ "Sony Programmable I/O Device")) {
dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n",
io->io1.minimum, io->io1.maximum,
io->io1.address_length);
@@ -2836,7 +3258,7 @@ static int sony_pic_add(struct acpi_device *device)
if (io->io2.minimum) {
if (request_region(io->io2.minimum,
io->io2.address_length,
- "Sony Programable I/O Device")) {
+ "Sony Programmable I/O Device")) {
dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n",
io->io2.minimum, io->io2.maximum,
io->io2.address_length);
@@ -2859,7 +3281,7 @@ static int sony_pic_add(struct acpi_device *device)
}
}
if (!spic_dev.cur_ioport) {
- printk(KERN_ERR DRV_PFX "Failed to request_region.\n");
+ pr_err(DRV_PFX "Failed to request_region.\n");
result = -ENODEV;
goto err_remove_compat;
}
@@ -2879,7 +3301,7 @@ static int sony_pic_add(struct acpi_device *device)
}
}
if (!spic_dev.cur_irq) {
- printk(KERN_ERR DRV_PFX "Failed to request_irq.\n");
+ pr_err(DRV_PFX "Failed to request_irq.\n");
result = -ENODEV;
goto err_release_region;
}
@@ -2887,7 +3309,7 @@ static int sony_pic_add(struct acpi_device *device)
/* set resource status _SRS */
result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
if (result) {
- printk(KERN_ERR DRV_PFX "Couldn't enable device.\n");
+ pr_err(DRV_PFX "Couldn't enable device.\n");
goto err_free_irq;
}
@@ -2996,8 +3418,7 @@ static int __init sony_laptop_init(void)
if (!no_spic && dmi_check_system(sonypi_dmi_table)) {
result = acpi_bus_register_driver(&sony_pic_driver);
if (result) {
- printk(KERN_ERR DRV_PFX
- "Unable to register SPIC driver.");
+ pr_err(DRV_PFX "Unable to register SPIC driver.");
goto out;
}
spic_drv_registered = 1;
@@ -3005,7 +3426,7 @@ static int __init sony_laptop_init(void)
result = acpi_bus_register_driver(&sony_nc_driver);
if (result) {
- printk(KERN_ERR DRV_PFX "Unable to register SNC driver.");
+ pr_err(DRV_PFX "Unable to register SNC driver.");
goto out_unregister_pic;
}