sony-laptop: generalise ACPI calls into SNC functions

All calls into the SNC device methods have zero or one arguments and
return an integer or a buffer (some functions go as far as returning an
integer _or_ a buffer depending on the input parameter...).
This allows simplifying a couple of code paths and prepares the field
for other users of functions returning buffers.

Signed-off-by: Mattia Dongili <malattia@linux.it>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
This commit is contained in:
Mattia Dongili 2012-05-19 22:35:46 +09:00 committed by Matthew Garrett
parent 3398241b05
commit ebcef1b0e4
1 changed files with 133 additions and 142 deletions

View File

@ -691,59 +691,92 @@ static struct acpi_device *sony_nc_acpi_device = NULL;
/* /*
* acpi_evaluate_object wrappers * acpi_evaluate_object wrappers
* all useful calls into SNC methods take one or zero parameters and return
* integers or arrays.
*/ */
static int acpi_callgetfunc(acpi_handle handle, char *name, int *result) static union acpi_object *__call_snc_method(acpi_handle handle, char *method,
u64 *value)
{ {
struct acpi_buffer output; union acpi_object *result = NULL;
union acpi_object out_obj; struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
acpi_status status; acpi_status status;
output.length = sizeof(out_obj); if (value) {
output.pointer = &out_obj; struct acpi_object_list params;
union acpi_object in;
in.type = ACPI_TYPE_INTEGER;
in.integer.value = *value;
params.count = 1;
params.pointer = &in;
status = acpi_evaluate_object(handle, method, &params, &output);
} else
status = acpi_evaluate_object(handle, method, NULL, &output);
status = acpi_evaluate_object(handle, name, NULL, &output); if (ACPI_FAILURE(status)) {
if ((status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER)) { pr_err("Failed to evaluate [%s]\n", method);
*result = out_obj.integer.value; return NULL;
return 0;
} }
pr_warn("acpi_callreadfunc failed\n"); result = (union acpi_object *) output.pointer;
if (!result)
dprintk("No return object [%s]\n", method);
return -1; return result;
} }
static int acpi_callsetfunc(acpi_handle handle, char *name, int value, static int sony_nc_int_call(acpi_handle handle, char *name, int *value,
int *result) int *result)
{ {
struct acpi_object_list params; union acpi_object *object = NULL;
union acpi_object in_obj; if (value) {
struct acpi_buffer output; u64 v = *value;
union acpi_object out_obj; object = __call_snc_method(handle, name, &v);
acpi_status status; } else
object = __call_snc_method(handle, name, NULL);
params.count = 1; if (!object)
params.pointer = &in_obj; return -EINVAL;
in_obj.type = ACPI_TYPE_INTEGER;
in_obj.integer.value = value;
output.length = sizeof(out_obj); if (object->type != ACPI_TYPE_INTEGER) {
output.pointer = &out_obj; pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n",
ACPI_TYPE_INTEGER, object->type);
status = acpi_evaluate_object(handle, name, &params, &output); kfree(object);
if (status == AE_OK) { return -EINVAL;
if (result != NULL) {
if (out_obj.type != ACPI_TYPE_INTEGER) {
pr_warn("acpi_evaluate_object bad return type\n");
return -1;
}
*result = out_obj.integer.value;
}
return 0;
} }
pr_warn("acpi_evaluate_object failed\n"); if (result)
*result = object->integer.value;
return -1; kfree(object);
return 0;
}
#define MIN(a, b) (a > b ? b : a)
static int sony_nc_buffer_call(acpi_handle handle, char *name, u64 *value,
void *buffer, size_t buflen)
{
size_t len = len;
union acpi_object *object = __call_snc_method(handle, name, value);
if (!object)
return -EINVAL;
if (object->type == ACPI_TYPE_BUFFER)
len = MIN(buflen, object->buffer.length);
else if (object->type == ACPI_TYPE_INTEGER)
len = MIN(buflen, sizeof(object->integer.value));
else {
pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n",
ACPI_TYPE_BUFFER, object->type);
kfree(object);
return -EINVAL;
}
memcpy(buffer, object->buffer.pointer, len);
kfree(object);
return 0;
} }
struct sony_nc_handles { struct sony_nc_handles {
@ -770,16 +803,17 @@ static ssize_t sony_nc_handles_show(struct device *dev,
static int sony_nc_handles_setup(struct platform_device *pd) static int sony_nc_handles_setup(struct platform_device *pd)
{ {
int i; int i, r, result, arg;
int result;
handles = kzalloc(sizeof(*handles), GFP_KERNEL); handles = kzalloc(sizeof(*handles), GFP_KERNEL);
if (!handles) if (!handles)
return -ENOMEM; return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
if (!acpi_callsetfunc(sony_nc_acpi_handle, arg = i + 0x20;
"SN00", i + 0x20, &result)) { r = sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg,
&result);
if (!r) {
dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n", dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n",
result, i); result, i);
handles->cap[i] = result; handles->cap[i] = result;
@ -835,16 +869,15 @@ static int sony_find_snc_handle(int handle)
static int sony_call_snc_handle(int handle, int argument, int *result) static int sony_call_snc_handle(int handle, int argument, int *result)
{ {
int ret = 0; int arg, ret = 0;
int offset = sony_find_snc_handle(handle); int offset = sony_find_snc_handle(handle);
if (offset < 0) if (offset < 0)
return -1; return -1;
ret = acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument, arg = offset | argument;
result); ret = sony_nc_int_call(sony_nc_acpi_handle, "SN07", &arg, result);
dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", offset | argument, dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", arg, *result);
*result);
return ret; return ret;
} }
@ -889,14 +922,16 @@ static int boolean_validate(const int direction, const int value)
static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr, static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr,
char *buffer) char *buffer)
{ {
int value; int value, ret = 0;
struct sony_nc_value *item = struct sony_nc_value *item =
container_of(attr, struct sony_nc_value, devattr); container_of(attr, struct sony_nc_value, devattr);
if (!*item->acpiget) if (!*item->acpiget)
return -EIO; return -EIO;
if (acpi_callgetfunc(sony_nc_acpi_handle, *item->acpiget, &value) < 0) ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiget, NULL,
&value);
if (ret < 0)
return -EIO; return -EIO;
if (item->validate) if (item->validate)
@ -909,7 +944,7 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
const char *buffer, size_t count) const char *buffer, size_t count)
{ {
int value; int value, ret = 0;
struct sony_nc_value *item = struct sony_nc_value *item =
container_of(attr, struct sony_nc_value, devattr); container_of(attr, struct sony_nc_value, devattr);
@ -927,8 +962,11 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
if (value < 0) if (value < 0)
return value; return value;
if (acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, value, NULL) < 0) ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset, &value,
NULL);
if (ret < 0)
return -EIO; return -EIO;
item->value = value; item->value = value;
item->valid = 1; item->valid = 1;
return count; return count;
@ -948,15 +986,15 @@ struct sony_backlight_props sony_bl_props;
static int sony_backlight_update_status(struct backlight_device *bd) static int sony_backlight_update_status(struct backlight_device *bd)
{ {
return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", int arg = bd->props.brightness + 1;
bd->props.brightness + 1, NULL); return sony_nc_int_call(sony_nc_acpi_handle, "SBRT", &arg, NULL);
} }
static int sony_backlight_get_brightness(struct backlight_device *bd) static int sony_backlight_get_brightness(struct backlight_device *bd)
{ {
int value; int value;
if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) if (sony_nc_int_call(sony_nc_acpi_handle, "GBRT", NULL, &value))
return 0; return 0;
/* brightness levels are 1-based, while backlight ones are 0-based */ /* brightness levels are 1-based, while backlight ones are 0-based */
return value - 1; return value - 1;
@ -1142,10 +1180,11 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
*/ */
static int sony_nc_function_setup(struct acpi_device *device) static int sony_nc_function_setup(struct acpi_device *device)
{ {
int result; int result, arg;
/* Enable all events */ /* Enable all events */
acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0xffff, &result); arg = 0xffff;
sony_nc_int_call(sony_nc_acpi_handle, "SN02", &arg, &result);
/* Setup hotkeys */ /* Setup hotkeys */
sony_call_snc_handle(0x0100, 0, &result); sony_call_snc_handle(0x0100, 0, &result);
@ -1166,8 +1205,8 @@ static int sony_nc_resume(struct acpi_device *device)
if (!item->valid) if (!item->valid)
continue; continue;
ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset,
item->value, NULL); &item->value, NULL);
if (ret < 0) { if (ret < 0) {
pr_err("%s: %d\n", __func__, ret); pr_err("%s: %d\n", __func__, ret);
break; break;
@ -1176,7 +1215,8 @@ static int sony_nc_resume(struct acpi_device *device)
if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON", if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON",
&handle))) { &handle))) {
if (acpi_callsetfunc(sony_nc_acpi_handle, "ECON", 1, NULL)) int arg = 1;
if (sony_nc_int_call(sony_nc_acpi_handle, "ECON", &arg, NULL))
dprintk("ECON Method failed\n"); dprintk("ECON Method failed\n");
} }
@ -1314,13 +1354,9 @@ static void sony_nc_rfkill_update(void)
static void sony_nc_rfkill_setup(struct acpi_device *device) static void sony_nc_rfkill_setup(struct acpi_device *device)
{ {
int offset; u64 offset;
u8 dev_code, i; int i;
acpi_status status; unsigned char buffer[32] = { 0 };
struct acpi_object_list params;
union acpi_object in_obj;
union acpi_object *device_enum;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
offset = sony_find_snc_handle(0x124); offset = sony_find_snc_handle(0x124);
if (offset == -1) { if (offset == -1) {
@ -1333,59 +1369,34 @@ static void sony_nc_rfkill_setup(struct acpi_device *device)
sony_rfkill_handle = 0x124; sony_rfkill_handle = 0x124;
dprintk("Found rkfill handle: 0x%.4x\n", sony_rfkill_handle); dprintk("Found rkfill handle: 0x%.4x\n", sony_rfkill_handle);
/* need to read the whole buffer returned by the acpi call to SN06 i = sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &offset, buffer,
* here otherwise we may miss some features 32);
*/ if (i < 0)
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)) {
dprintk("Radio device enumeration failed\n");
return; return;
}
device_enum = (union acpi_object *) buffer.pointer;
if (!device_enum) {
pr_err("No SN06 return object.");
return;
}
if (device_enum->type != ACPI_TYPE_BUFFER) {
pr_err("Invalid SN06 return object 0x%.2x\n",
device_enum->type);
goto out_no_enum;
}
/* the buffer is filled with magic numbers describing the devices /* the buffer is filled with magic numbers describing the devices
* available, 0xff terminates the enumeration * available, 0xff terminates the enumeration
*/ */
for (i = 0; i < device_enum->buffer.length; i++) { for (i = 0; i < ARRAY_SIZE(buffer); i++) {
dev_code = *(device_enum->buffer.pointer + i); if (buffer[i] == 0xff)
if (dev_code == 0xff)
break; break;
dprintk("Radio devices, looking at 0x%.2x\n", dev_code); dprintk("Radio devices, looking at 0x%.2x\n", buffer[i]);
if (dev_code == 0 && !sony_rfkill_devices[SONY_WIFI]) if (buffer[i] == 0 && !sony_rfkill_devices[SONY_WIFI])
sony_nc_setup_rfkill(device, SONY_WIFI); sony_nc_setup_rfkill(device, SONY_WIFI);
if (dev_code == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH]) if (buffer[i] == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH])
sony_nc_setup_rfkill(device, SONY_BLUETOOTH); sony_nc_setup_rfkill(device, SONY_BLUETOOTH);
if ((0xf0 & dev_code) == 0x20 && if ((0xf0 & buffer[i]) == 0x20 &&
!sony_rfkill_devices[SONY_WWAN]) !sony_rfkill_devices[SONY_WWAN])
sony_nc_setup_rfkill(device, SONY_WWAN); sony_nc_setup_rfkill(device, SONY_WWAN);
if (dev_code == 0x30 && !sony_rfkill_devices[SONY_WIMAX]) if (buffer[i] == 0x30 && !sony_rfkill_devices[SONY_WIMAX])
sony_nc_setup_rfkill(device, SONY_WIMAX); sony_nc_setup_rfkill(device, SONY_WIMAX);
} }
out_no_enum:
kfree(buffer.pointer);
return;
} }
/* Keyboard backlight feature */ /* Keyboard backlight feature */
@ -1576,14 +1587,10 @@ static void sony_nc_kbd_backlight_resume(void)
static void sony_nc_backlight_ng_read_limits(int handle, static void sony_nc_backlight_ng_read_limits(int handle,
struct sony_backlight_props *props) struct sony_backlight_props *props)
{ {
int offset; u64 offset;
acpi_status status; int i;
u8 brlvl, i;
u8 min = 0xff, max = 0x00; u8 min = 0xff, max = 0x00;
struct acpi_object_list params; unsigned char buffer[32] = { 0 };
union acpi_object in_obj;
union acpi_object *lvl_enum;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
props->handle = handle; props->handle = handle;
props->offset = 0; props->offset = 0;
@ -1596,50 +1603,31 @@ static void sony_nc_backlight_ng_read_limits(int handle,
/* try to read the boundaries from ACPI tables, if we fail the above /* try to read the boundaries from ACPI tables, if we fail the above
* defaults should be reasonable * defaults should be reasonable
*/ */
params.count = 1; i = sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &offset, buffer,
params.pointer = &in_obj; 32);
in_obj.type = ACPI_TYPE_INTEGER; if (i < 0)
in_obj.integer.value = offset;
status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", &params,
&buffer);
if (ACPI_FAILURE(status))
return; 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 /* the buffer lists brightness levels available, brightness levels are
* from 0 to 8 in the array, other values are used by ALS control. * from position 0 to 8 in the array, other values are used by ALS
* control.
*/ */
for (i = 0; i < 9 && i < lvl_enum->buffer.length; i++) { for (i = 0; i < 9 && i < ARRAY_SIZE(buffer); i++) {
brlvl = *(lvl_enum->buffer.pointer + i); dprintk("Brightness level: %d\n", buffer[i]);
dprintk("Brightness level: %d\n", brlvl);
if (!brlvl) if (!buffer[i])
break; break;
if (brlvl > max) if (buffer[i] > max)
max = brlvl; max = buffer[i];
if (brlvl < min) if (buffer[i] < min)
min = brlvl; min = buffer[i];
} }
props->offset = min; props->offset = min;
props->maxlvl = max; props->maxlvl = max;
dprintk("Brightness levels: min=%d max=%d\n", props->offset, dprintk("Brightness levels: min=%d max=%d\n", props->offset,
props->maxlvl); props->maxlvl);
out_invalid:
kfree(buffer.pointer);
return;
} }
static void sony_nc_backlight_setup(void) static void sony_nc_backlight_setup(void)
@ -1728,7 +1716,8 @@ static int sony_nc_add(struct acpi_device *device)
if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON", if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON",
&handle))) { &handle))) {
if (acpi_callsetfunc(sony_nc_acpi_handle, "ECON", 1, NULL)) int arg = 1;
if (sony_nc_int_call(sony_nc_acpi_handle, "ECON", &arg, NULL))
dprintk("ECON Method failed\n"); dprintk("ECON Method failed\n");
} }
@ -2684,7 +2673,8 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd,
ret = -EIO; ret = -EIO;
break; break;
} }
if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) { if (sony_nc_int_call(sony_nc_acpi_handle, "GBRT", NULL,
&value)) {
ret = -EIO; ret = -EIO;
break; break;
} }
@ -2701,8 +2691,9 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd,
ret = -EFAULT; ret = -EFAULT;
break; break;
} }
if (acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", value = (val8 >> 5) + 1;
(val8 >> 5) + 1, NULL)) { if (sony_nc_int_call(sony_nc_acpi_handle, "SBRT", &value,
NULL)) {
ret = -EIO; ret = -EIO;
break; break;
} }